Skip to content

Commit 8ab10b5

Browse files
Merge pull request #70 from IntersectMBO/feat/add-blueprint
feat/add blueprint
2 parents 45697b9 + b8d4be0 commit 8ab10b5

File tree

382 files changed

+4977
-390
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

382 files changed

+4977
-390
lines changed

.changeset/free-schools-sing.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@evolution-sdk/evolution": patch
3+
---
4+
5+
add blueprint module
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
'use client'
2+
3+
import { useState } from 'react'
4+
import { Blueprint } from "@evolution-sdk/evolution"
5+
import { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock'
6+
7+
const { PlutusBlueprint, generateTypeScript, createCodegenConfig } = Blueprint
8+
9+
export function BlueprintCodegen() {
10+
const [blueprintJson, setBlueprintJson] = useState("")
11+
const [generatedCode, setGeneratedCode] = useState<string>("")
12+
const [error, setError] = useState<string | null>(null)
13+
const [optionStyle, setOptionStyle] = useState<'NullOr' | 'UndefinedOr' | 'Union'>('UndefinedOr')
14+
const [moduleStrategy, setModuleStrategy] = useState<'flat' | 'namespaced'>('namespaced')
15+
const [forceVariant, setForceVariant] = useState(true)
16+
17+
const generateTypes = async () => {
18+
setError(null)
19+
setGeneratedCode("")
20+
21+
try {
22+
const cleanJson = blueprintJson.trim()
23+
24+
if (!cleanJson) {
25+
setError('Please enter a Plutus Blueprint JSON')
26+
return
27+
}
28+
29+
// Parse the JSON
30+
const plutusJson = JSON.parse(cleanJson)
31+
32+
// Create config
33+
const config = createCodegenConfig({
34+
optionStyle,
35+
moduleStrategy,
36+
forceVariant,
37+
useSuspend: false,
38+
useRelativeRefs: true,
39+
emptyConstructorStyle: "Literal",
40+
})
41+
42+
// Generate TypeScript code
43+
const code = generateTypeScript(plutusJson, config)
44+
45+
setGeneratedCode(code)
46+
} catch (err) {
47+
console.error('Generation error:', err)
48+
setError(err instanceof Error ? err.message : 'Failed to generate types from blueprint')
49+
}
50+
}
51+
52+
const downloadCode = () => {
53+
if (!generatedCode) return
54+
55+
const blob = new Blob([generatedCode], { type: 'text/typescript' })
56+
const url = URL.createObjectURL(blob)
57+
const a = document.createElement('a')
58+
a.href = url
59+
a.download = 'generated-types.ts'
60+
document.body.appendChild(a)
61+
a.click()
62+
document.body.removeChild(a)
63+
URL.revokeObjectURL(url)
64+
}
65+
66+
const copyToClipboard = async () => {
67+
if (!generatedCode) return
68+
69+
try {
70+
await navigator.clipboard.writeText(generatedCode)
71+
} catch (err) {
72+
console.error('Failed to copy:', err)
73+
}
74+
}
75+
76+
return (
77+
<div className="max-w-6xl mx-auto space-y-6">
78+
<div className="rounded-lg border bg-card text-card-foreground shadow-sm">
79+
<div className="p-6 space-y-6">
80+
<div className="flex items-center justify-between">
81+
<div className="space-y-1">
82+
<h3 className="text-2xl font-semibold tracking-tight">Blueprint Input</h3>
83+
<p className="text-sm text-muted-foreground">Paste your plutus.json blueprint</p>
84+
</div>
85+
</div>
86+
87+
<div className="space-y-4">
88+
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
89+
<div className="space-y-2">
90+
<label htmlFor="option-style" className="text-sm font-medium leading-none">
91+
Option Style
92+
</label>
93+
<select
94+
id="option-style"
95+
value={optionStyle}
96+
onChange={(e) => setOptionStyle(e.target.value as any)}
97+
className="flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
98+
>
99+
<option value="UndefinedOr">UndefinedOr</option>
100+
<option value="NullOr">NullOr</option>
101+
<option value="Union">Union</option>
102+
</select>
103+
</div>
104+
105+
<div className="space-y-2">
106+
<label htmlFor="module-strategy" className="text-sm font-medium leading-none">
107+
Module Strategy
108+
</label>
109+
<select
110+
id="module-strategy"
111+
value={moduleStrategy}
112+
onChange={(e) => setModuleStrategy(e.target.value as any)}
113+
className="flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
114+
>
115+
<option value="namespaced">Namespaced</option>
116+
<option value="flat">Flat</option>
117+
</select>
118+
</div>
119+
120+
<div className="space-y-2">
121+
<label htmlFor="force-variant" className="text-sm font-medium leading-none">
122+
Force Variant
123+
</label>
124+
<div className="flex items-center h-10">
125+
<input
126+
id="force-variant"
127+
type="checkbox"
128+
checked={forceVariant}
129+
onChange={(e) => setForceVariant(e.target.checked)}
130+
className="h-4 w-4 rounded border-input"
131+
/>
132+
<label htmlFor="force-variant" className="ml-2 text-sm text-muted-foreground">
133+
Use Variant for all unions
134+
</label>
135+
</div>
136+
</div>
137+
</div>
138+
139+
<div className="space-y-2">
140+
<label htmlFor="blueprint-json" className="text-sm font-medium leading-none">
141+
Blueprint JSON
142+
</label>
143+
<textarea
144+
id="blueprint-json"
145+
value={blueprintJson}
146+
onChange={(e) => setBlueprintJson(e.target.value)}
147+
placeholder="Paste your plutus.json content here..."
148+
className="flex min-h-[200px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm font-mono resize-y focus:outline-none focus:ring-2 focus:ring-ring"
149+
/>
150+
</div>
151+
152+
<button
153+
onClick={generateTypes}
154+
className="sm:w-auto w-full inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-6 py-2 bg-zinc-700 text-white hover:bg-zinc-600 active:bg-zinc-500 transition-all cursor-pointer shadow-sm hover:shadow"
155+
>
156+
Generate Types
157+
</button>
158+
</div>
159+
</div>
160+
</div>
161+
162+
{error && (
163+
<div className="rounded-lg border bg-card text-card-foreground shadow-sm">
164+
<div className="p-6">
165+
<div className="flex gap-3">
166+
<svg className="h-5 w-5 text-destructive shrink-0 mt-0.5" viewBox="0 0 20 20" fill="currentColor">
167+
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
168+
</svg>
169+
<div className="flex-1 min-w-0 space-y-2">
170+
<p className="text-sm font-medium text-destructive">Error generating types</p>
171+
<pre className="text-xs text-muted-foreground whitespace-pre-wrap break-words overflow-wrap-anywhere font-mono">{error}</pre>
172+
</div>
173+
</div>
174+
</div>
175+
</div>
176+
)}
177+
178+
{generatedCode && (
179+
<div className="rounded-lg border bg-card text-card-foreground shadow-sm">
180+
<div className="p-6 space-y-3">
181+
<div className="flex items-center justify-between">
182+
<h4 className="text-sm font-semibold">Generated TypeScript</h4>
183+
<div className="flex gap-2">
184+
<button
185+
onClick={copyToClipboard}
186+
className="inline-flex items-center justify-center rounded-md text-sm font-medium h-8 px-3 py-1 bg-zinc-700 text-white hover:bg-zinc-600 active:bg-zinc-500 transition-all cursor-pointer shadow-sm"
187+
>
188+
Copy
189+
</button>
190+
<button
191+
onClick={downloadCode}
192+
className="inline-flex items-center justify-center rounded-md text-sm font-medium h-8 px-3 py-1 bg-zinc-700 text-white hover:bg-zinc-600 active:bg-zinc-500 transition-all cursor-pointer shadow-sm"
193+
>
194+
Download
195+
</button>
196+
</div>
197+
</div>
198+
<div className="max-h-[600px] overflow-y-auto">
199+
<DynamicCodeBlock lang="ts" code={generatedCode} />
200+
</div>
201+
</div>
202+
</div>
203+
)}
204+
205+
<div className="pt-4 border-t border-border/50">
206+
<p className="text-xs text-center text-muted-foreground">
207+
Questions or feedback? <a href="https://github.com/IntersectMBO/evolution-sdk/issues" target="_blank" rel="noopener noreferrer" className="text-primary hover:underline">Start a discussion on GitHub</a>
208+
</p>
209+
</div>
210+
</div>
211+
)
212+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { BlueprintCodegen } from "./blueprint-codegen"
2+
import type { Metadata } from 'next'
3+
4+
export const metadata: Metadata = {
5+
title: 'Blueprint Codegen | Evolution SDK',
6+
description: 'Generate TypeScript types from Plutus Blueprint (plutus.json)',
7+
}
8+
9+
export default function BlueprintCodegenPage() {
10+
return (
11+
<div className="container mx-auto px-4 py-8 max-w-6xl">
12+
<div className="mb-8">
13+
<h1 className="text-4xl font-bold mb-4">Blueprint Type Generator</h1>
14+
<p className="text-muted-foreground text-lg">
15+
Generate TypeScript TSchema definitions from your Plutus Blueprint (plutus.json). Paste your blueprint JSON below to generate type-safe TypeScript code.
16+
</p>
17+
</div>
18+
<BlueprintCodegen />
19+
</div>
20+
)
21+
}

docs/content/docs/index.mdx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ import { Card, Cards } from 'fumadocs-ui/components/card'
2727
description="Decode CBOR transaction hex into readable JSON format"
2828
href="/tools/tx-decoder"
2929
/>
30+
<Card
31+
title="Blueprint Codegen"
32+
description="Generate TypeScript types from Plutus Blueprint JSON"
33+
href="/tools/blueprint-codegen"
34+
/>
3035
<Card
3136
title="Examples"
3237
description="Explore real-world examples and common patterns"

0 commit comments

Comments
 (0)