@deckspec/cli 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +114 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/commands/approve.d.ts +2 -0
  6. package/dist/commands/approve.d.ts.map +1 -0
  7. package/dist/commands/approve.js +56 -0
  8. package/dist/commands/approve.js.map +1 -0
  9. package/dist/commands/dev.d.ts +2 -0
  10. package/dist/commands/dev.d.ts.map +1 -0
  11. package/dist/commands/dev.js +331 -0
  12. package/dist/commands/dev.js.map +1 -0
  13. package/dist/commands/init.d.ts +5 -0
  14. package/dist/commands/init.d.ts.map +1 -0
  15. package/dist/commands/init.js +257 -0
  16. package/dist/commands/init.js.map +1 -0
  17. package/dist/commands/lock.d.ts +2 -0
  18. package/dist/commands/lock.d.ts.map +1 -0
  19. package/dist/commands/lock.js +155 -0
  20. package/dist/commands/lock.js.map +1 -0
  21. package/dist/commands/patterns.d.ts +6 -0
  22. package/dist/commands/patterns.d.ts.map +1 -0
  23. package/dist/commands/patterns.js +97 -0
  24. package/dist/commands/patterns.js.map +1 -0
  25. package/dist/commands/render.d.ts +6 -0
  26. package/dist/commands/render.d.ts.map +1 -0
  27. package/dist/commands/render.js +41 -0
  28. package/dist/commands/render.js.map +1 -0
  29. package/dist/commands/validate.d.ts +6 -0
  30. package/dist/commands/validate.d.ts.map +1 -0
  31. package/dist/commands/validate.js +37 -0
  32. package/dist/commands/validate.js.map +1 -0
  33. package/dist/index.d.ts +5 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +5 -0
  36. package/dist/index.js.map +1 -0
  37. package/package.json +8 -4
  38. package/src/cli.ts +7 -0
  39. package/src/commands/init.ts +284 -0
  40. package/tsconfig.json +0 -14
@@ -0,0 +1,257 @@
1
+ import { resolve, join, dirname, relative } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { mkdir, readdir, copyFile, writeFile, stat, } from "node:fs/promises";
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ const __dirname = dirname(__filename);
6
+ /** Directories to skip when copying a theme. */
7
+ const SKIP_DIRS = new Set(["dist", "node_modules", ".turbo"]);
8
+ /**
9
+ * Recursively copy a directory, skipping entries in SKIP_DIRS.
10
+ */
11
+ async function copyDirRecursive(src, dest) {
12
+ await mkdir(dest, { recursive: true });
13
+ const entries = await readdir(src, { withFileTypes: true });
14
+ for (const entry of entries) {
15
+ const srcPath = join(src, entry.name);
16
+ const destPath = join(dest, entry.name);
17
+ if (entry.isDirectory()) {
18
+ if (SKIP_DIRS.has(entry.name))
19
+ continue;
20
+ await copyDirRecursive(srcPath, destPath);
21
+ }
22
+ else {
23
+ await copyFile(srcPath, destPath);
24
+ }
25
+ }
26
+ }
27
+ /**
28
+ * List pattern directory names under a theme's patterns/ folder.
29
+ * Excludes _lib and index.ts; returns only directories.
30
+ */
31
+ async function listPatternNames(patternsDir) {
32
+ let entries;
33
+ try {
34
+ entries = await readdir(patternsDir, { withFileTypes: true });
35
+ }
36
+ catch {
37
+ return [];
38
+ }
39
+ return entries
40
+ .filter((e) => e.isDirectory() && !e.name.startsWith("_"))
41
+ .map((e) => e.name)
42
+ .sort();
43
+ }
44
+ /**
45
+ * Resolve the monorepo root from the CLI package location.
46
+ * Walks up from packages/cli/src/commands/ (or dist/) to find themes/.
47
+ */
48
+ function resolveMonorepoRoot() {
49
+ // In dev: packages/cli/src/commands/init.ts → up 4
50
+ // In dist: packages/cli/dist/commands/init.js → up 4
51
+ let dir = __dirname;
52
+ for (let i = 0; i < 6; i++) {
53
+ const candidate = join(dir, "themes");
54
+ // Synchronous existence check via try/catch is avoided;
55
+ // we just go up 4 levels from commands/ which should land at monorepo root.
56
+ dir = dirname(dir);
57
+ }
58
+ // __dirname is packages/cli/dist/commands or packages/cli/src/commands
59
+ // Go up 4 levels: commands → dist/src → cli → packages → root
60
+ return resolve(__dirname, "..", "..", "..", "..");
61
+ }
62
+ function generateSampleDeck(theme) {
63
+ return `meta:
64
+ title: "My Presentation"
65
+ theme: ${theme}
66
+ state: active
67
+ slides:
68
+ - file: title-center
69
+ vars:
70
+ title: "Welcome"
71
+ subtitle: "A presentation built with DeckSpec"
72
+
73
+ - file: feature-metrics
74
+ vars:
75
+ headline: "Key Numbers"
76
+ metrics:
77
+ - label: "Slides"
78
+ value: "3"
79
+ - label: "Patterns"
80
+ value: "17+"
81
+ - label: "Build Steps"
82
+ value: "0"
83
+
84
+ - file: three-pillars
85
+ vars:
86
+ label: "How It Works"
87
+ heading: "Three Simple Steps"
88
+ pillars:
89
+ - title: "Write"
90
+ value: "YAML"
91
+ description: "Define your content in a simple, structured format."
92
+ - title: "Validate"
93
+ value: "Zod"
94
+ description: "Schemas catch mistakes before you ever see the output."
95
+ - title: "Render"
96
+ value: "HTML"
97
+ description: "Patterns produce standalone HTML — no dependencies."
98
+ `;
99
+ }
100
+ function generatePackageJson() {
101
+ return JSON.stringify({
102
+ private: true,
103
+ type: "module",
104
+ dependencies: {
105
+ "@deckspec/cli": "^0.1.0",
106
+ },
107
+ }, null, 2) + "\n";
108
+ }
109
+ function generateGitignore() {
110
+ return `node_modules/
111
+ dist/
112
+ output/
113
+ tmp/
114
+ *.tsbuildinfo
115
+ `;
116
+ }
117
+ function generateClaudeMd(theme, patterns) {
118
+ const patternList = patterns.map((p) => `- \`${p}\``).join("\n");
119
+ return `# DeckSpec Project
120
+
121
+ Programmable presentations. YAML で書く。Zod で守る。React で描く。
122
+
123
+ ## YAML DSL Spec
124
+
125
+ A deck is defined by a single \`deck.yaml\` file:
126
+
127
+ \`\`\`yaml
128
+ meta:
129
+ title: "Presentation Title"
130
+ theme: ${theme}
131
+ state: active # active | archived
132
+ slides:
133
+ - file: pattern-name # pattern from themes/${theme}/patterns/
134
+ vars:
135
+ key: "value" # content injected into the pattern
136
+ \`\`\`
137
+
138
+ ### Slide Fields
139
+
140
+ | Field | Required | Description |
141
+ |-------|----------|-------------|
142
+ | \`file\` | yes | Pattern name (resolved from theme) or relative path |
143
+ | \`vars\` | yes | Content variables — validated by the pattern's Zod schema |
144
+ | \`state\` | no | \`generated\` (default) / \`approved\` / \`locked\` |
145
+
146
+ ## Available Patterns (theme: ${theme})
147
+
148
+ ${patternList}
149
+
150
+ Each pattern lives in \`themes/${theme}/patterns/<name>/index.tsx\` and exports:
151
+ - \`export const schema\` — Zod schema defining accepted \`vars\`
152
+ - \`export default Component\` — React component for SSR
153
+
154
+ Check each pattern's \`examples.yaml\` (if present) for usage examples.
155
+
156
+ ## Commands
157
+
158
+ \`\`\`bash
159
+ npx deckspec validate decks/sample/deck.yaml # Validate YAML against Zod schemas
160
+ npx deckspec render decks/sample/deck.yaml -o out # Render to standalone HTML
161
+ npx deckspec dev # Live preview at http://localhost:3002
162
+ npx deckspec patterns # List all patterns with schemas
163
+ \`\`\`
164
+
165
+ ## Creating a New Slide
166
+
167
+ 1. Pick a pattern from the list above
168
+ 2. Add a slide entry to \`deck.yaml\` with \`file:\` and \`vars:\`
169
+ 3. Run \`npx deckspec validate\` to check your YAML
170
+ 4. Run \`npx deckspec dev\` to preview
171
+
172
+ ## Creating a Deck-Local Pattern
173
+
174
+ If no existing pattern fits, create a custom one:
175
+
176
+ 1. Create \`decks/<deck>/patterns/<name>/index.tsx\`
177
+ 2. Export \`schema\` (Zod) and \`default\` (React component)
178
+ 3. Reference it in \`deck.yaml\` with \`file: <name>\`
179
+ 4. Deck-local patterns are compiled on-the-fly with esbuild — no build step needed
180
+
181
+ ## Theme Design Reference
182
+
183
+ See \`themes/${theme}/design.md\` for the theme's design principles, color palette, and typography rules.
184
+ `;
185
+ }
186
+ /**
187
+ * deckspec init [dir] --theme <name>
188
+ */
189
+ export async function initCommand(args) {
190
+ // Parse arguments
191
+ let targetDir = ".";
192
+ let themeName = "noir-display";
193
+ const themeIdx = args.indexOf("--theme");
194
+ if (themeIdx !== -1) {
195
+ const val = args[themeIdx + 1];
196
+ if (!val) {
197
+ console.error("Error: --theme requires a value.");
198
+ process.exit(1);
199
+ }
200
+ themeName = val;
201
+ }
202
+ // First positional arg (not a flag) is the target directory
203
+ for (const arg of args) {
204
+ if (arg === "--theme")
205
+ break;
206
+ if (!arg.startsWith("-")) {
207
+ targetDir = arg;
208
+ break;
209
+ }
210
+ }
211
+ const root = resolve(targetDir);
212
+ const monorepoRoot = resolveMonorepoRoot();
213
+ const themeSrc = join(monorepoRoot, "themes", themeName);
214
+ // Verify theme exists
215
+ try {
216
+ const s = await stat(themeSrc);
217
+ if (!s.isDirectory())
218
+ throw new Error();
219
+ }
220
+ catch {
221
+ console.error(`Error: Theme "${themeName}" not found at ${themeSrc}`);
222
+ process.exit(1);
223
+ }
224
+ console.log(`Initializing DeckSpec project in ${root}`);
225
+ console.log(` Theme: ${themeName}`);
226
+ // 1. Copy theme
227
+ const themeDest = join(root, "themes", themeName);
228
+ console.log(` Copying theme to themes/${themeName}/`);
229
+ await copyDirRecursive(themeSrc, themeDest);
230
+ // 2. Create sample deck
231
+ const deckDir = join(root, "decks", "sample");
232
+ await mkdir(deckDir, { recursive: true });
233
+ const deckPath = join(deckDir, "deck.yaml");
234
+ await writeFile(deckPath, generateSampleDeck(themeName));
235
+ console.log(" Created decks/sample/deck.yaml");
236
+ // 3. Create package.json
237
+ const pkgPath = join(root, "package.json");
238
+ await writeFile(pkgPath, generatePackageJson());
239
+ console.log(" Created package.json");
240
+ // 4. Create CLAUDE.md
241
+ const patterns = await listPatternNames(join(themeDest, "patterns"));
242
+ const claudePath = join(root, "CLAUDE.md");
243
+ await writeFile(claudePath, generateClaudeMd(themeName, patterns));
244
+ console.log(" Created CLAUDE.md");
245
+ // 5. Create .gitignore
246
+ const gitignorePath = join(root, ".gitignore");
247
+ await writeFile(gitignorePath, generateGitignore());
248
+ console.log(" Created .gitignore");
249
+ console.log("");
250
+ console.log("Done! Next steps:");
251
+ console.log("");
252
+ console.log(` cd ${relative(process.cwd(), root) || "."}`);
253
+ console.log(" npm install");
254
+ console.log(" npx deckspec dev");
255
+ console.log("");
256
+ }
257
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function lockCommand(filePath: string, extraArgs: string[]): Promise<void>;
2
+ //# sourceMappingURL=lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../src/commands/lock.ts"],"names":[],"mappings":"AA0IA,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,IAAI,CAAC,CAqDf"}
@@ -0,0 +1,155 @@
1
+ import { writeFile, mkdir } from "node:fs/promises";
2
+ import { resolve, dirname, join } from "node:path";
3
+ import { loadDeckFile, lockSlide } from "@deckspec/dsl";
4
+ import { renderSlide, extractThemeName, resolveThemePatternsDir, resolveThemePatternsSrcDir } from "@deckspec/renderer";
5
+ /**
6
+ * Extracts text nodes from HTML as variable candidates.
7
+ * Returns a map of variable names to their values.
8
+ */
9
+ function extractVarsFromHtml(html) {
10
+ const vars = {};
11
+ // Extract <h1> → title
12
+ const h1Match = /<h1[^>]*>(.*?)<\/h1>/i.exec(html);
13
+ if (h1Match) {
14
+ vars.title = h1Match[1].replace(/<[^>]*>/g, "").trim();
15
+ }
16
+ // Extract <h2> → headline
17
+ const h2Match = /<h2[^>]*>(.*?)<\/h2>/i.exec(html);
18
+ if (h2Match) {
19
+ vars.headline = h2Match[1].replace(/<[^>]*>/g, "").trim();
20
+ }
21
+ // Extract first <p> → subtitle or body
22
+ const pMatch = /<p[^>]*>(.*?)<\/p>/i.exec(html);
23
+ if (pMatch) {
24
+ const text = pMatch[1].replace(/<[^>]*>/g, "").trim();
25
+ if (vars.title && !vars.headline) {
26
+ vars.subtitle = text;
27
+ }
28
+ else {
29
+ vars.body = text;
30
+ }
31
+ }
32
+ return vars;
33
+ }
34
+ /**
35
+ * Generates a .tsx pattern file from HTML content and extracted vars.
36
+ */
37
+ function generatePatternTsx(name, html, vars) {
38
+ const componentName = name
39
+ .split("-")
40
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
41
+ .join("");
42
+ const schemaFields = Object.entries(vars)
43
+ .map(([key, value]) => {
44
+ const maxLen = Math.max(value.length * 2, 60);
45
+ return ` ${key}: z.string().min(1).max(${maxLen}).describe("${key}"),`;
46
+ })
47
+ .join("\n");
48
+ // Replace literal values with JSX expressions in the HTML
49
+ let jsxBody = html.trim();
50
+ for (const [key, value] of Object.entries(vars)) {
51
+ // Escape special regex characters in value
52
+ const escaped = value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
53
+ jsxBody = jsxBody.replace(new RegExp(`>${escaped}<`, "g"), `>{${key}}<`);
54
+ }
55
+ // Convert HTML attributes to JSX
56
+ jsxBody = jsxBody.replace(/class="/g, 'className="');
57
+ jsxBody = jsxBody.replace(/style="([^"]*)"/g, (_match, styleStr) => {
58
+ const props = styleStr
59
+ .split(";")
60
+ .filter(Boolean)
61
+ .map((prop) => {
62
+ const [k, v] = prop.split(":").map((s) => s.trim());
63
+ const camelKey = k.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
64
+ // Try to convert numeric values
65
+ const numVal = parseFloat(v);
66
+ if (!isNaN(numVal) && v.endsWith("px")) {
67
+ return `${camelKey}: ${numVal}`;
68
+ }
69
+ return `${camelKey}: "${v}"`;
70
+ })
71
+ .join(", ");
72
+ return `style={{ ${props} }}`;
73
+ });
74
+ const propsDestructure = Object.keys(vars).join(", ");
75
+ return `import { z } from "zod";
76
+
77
+ export const schema = z.object({
78
+ ${schemaFields}
79
+ });
80
+
81
+ type Props = z.infer<typeof schema>;
82
+
83
+ export default function ${componentName}({ ${propsDestructure} }: Props) {
84
+ return (
85
+ ${jsxBody}
86
+ );
87
+ }
88
+ `;
89
+ }
90
+ function parseOptions(args) {
91
+ let slideIndex;
92
+ let patternName;
93
+ for (let i = 0; i < args.length; i++) {
94
+ const arg = args[i];
95
+ if (arg === "--slide" && args[i + 1]) {
96
+ slideIndex = parseInt(args[i + 1], 10);
97
+ if (Number.isNaN(slideIndex) || slideIndex < 0) {
98
+ throw new Error(`Invalid slide index: "${args[i + 1]}"`);
99
+ }
100
+ i++;
101
+ }
102
+ else if (arg === "--name" && args[i + 1]) {
103
+ patternName = args[i + 1];
104
+ i++;
105
+ }
106
+ }
107
+ if (slideIndex === undefined) {
108
+ throw new Error("Missing --slide <index>");
109
+ }
110
+ if (!patternName) {
111
+ throw new Error("Missing --name <pattern-name>");
112
+ }
113
+ return { slideIndex, patternName };
114
+ }
115
+ export async function lockCommand(filePath, extraArgs) {
116
+ const options = parseOptions(extraArgs);
117
+ const absPath = resolve(filePath);
118
+ const basePath = dirname(absPath);
119
+ const raw = await loadDeckFile(absPath);
120
+ const themeName = extractThemeName(raw);
121
+ const patternsDir = resolveThemePatternsDir(themeName);
122
+ const patternsSrcDir = resolveThemePatternsSrcDir(themeName);
123
+ const deck = raw;
124
+ if (options.slideIndex < 0 || options.slideIndex >= deck.slides.length) {
125
+ console.error(`Error: Slide index ${options.slideIndex} out of range (0–${deck.slides.length - 1})`);
126
+ process.exit(1);
127
+ }
128
+ const slide = deck.slides[options.slideIndex];
129
+ const currentState = slide.state ?? "generated";
130
+ if (currentState !== "approved") {
131
+ console.error(`Error: Slide ${options.slideIndex} is "${currentState}". Only "approved" slides can be locked.`);
132
+ process.exit(1);
133
+ }
134
+ // Render the slide to get its HTML
135
+ const slideHtml = await renderSlide(slide, { basePath, patternsDir, patternsSrcDir });
136
+ // Extract variables from the HTML
137
+ const vars = extractVarsFromHtml(slideHtml);
138
+ if (Object.keys(vars).length === 0) {
139
+ console.error("Warning: No text variables could be extracted from the slide.");
140
+ console.error("The pattern will be generated without variables.");
141
+ }
142
+ // Generate the .tsx pattern
143
+ const tsxContent = generatePatternTsx(options.patternName, slideHtml, vars);
144
+ // Write the pattern file to source directory
145
+ const patternDir = join(patternsSrcDir, options.patternName);
146
+ await mkdir(patternDir, { recursive: true });
147
+ const patternPath = join(patternDir, "index.tsx");
148
+ await writeFile(patternPath, tsxContent, "utf-8");
149
+ console.log(`\u2713 Generated pattern: ${patternPath}`);
150
+ // Update the deck YAML: rewrite the slide entry
151
+ await lockSlide(absPath, options.slideIndex, options.patternName, vars);
152
+ console.log(`\u2713 Locked slide ${options.slideIndex} → pattern "${options.patternName}"`);
153
+ console.log(`\nRebuild patterns to use: pnpm build`);
154
+ }
155
+ //# sourceMappingURL=lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/commands/lock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Lists available patterns with their schema definitions.
3
+ * --examples flag shows example vars from examples.yaml.
4
+ */
5
+ export declare function patternsCommand(args: string[]): Promise<void>;
6
+ //# sourceMappingURL=patterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../src/commands/patterns.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAyFnE"}
@@ -0,0 +1,97 @@
1
+ import { readdir, readFile, stat } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { resolveThemePatternsDir, resolveThemePatternsSrcDir } from "@deckspec/renderer";
4
+ import yaml from "js-yaml";
5
+ /**
6
+ * Lists available patterns with their schema definitions.
7
+ * --examples flag shows example vars from examples.yaml.
8
+ */
9
+ export async function patternsCommand(args) {
10
+ let themeName = "noir-display";
11
+ let showExamples = false;
12
+ for (let i = 0; i < args.length; i++) {
13
+ if (args[i] === "--theme" && args[i + 1]) {
14
+ themeName = args[i + 1];
15
+ i++;
16
+ }
17
+ if (args[i] === "--examples") {
18
+ showExamples = true;
19
+ }
20
+ }
21
+ const patternsDir = resolveThemePatternsDir(themeName);
22
+ const patternsSrcDir = resolveThemePatternsSrcDir(themeName);
23
+ let entries;
24
+ try {
25
+ entries = await readdir(patternsDir);
26
+ }
27
+ catch {
28
+ console.log(`No patterns found for theme "${themeName}".`);
29
+ return;
30
+ }
31
+ // Filter to directories that look like pattern names
32
+ const patternNames = [];
33
+ for (const name of entries) {
34
+ if (name.startsWith(".") || name.startsWith("_") || name === "node_modules" || name === "dist")
35
+ continue;
36
+ try {
37
+ const s = await stat(join(patternsDir, name));
38
+ if (s.isDirectory())
39
+ patternNames.push(name);
40
+ }
41
+ catch {
42
+ // skip
43
+ }
44
+ }
45
+ if (patternNames.length === 0) {
46
+ console.log(`No patterns found for theme "${themeName}".`);
47
+ return;
48
+ }
49
+ patternNames.sort();
50
+ console.log(`Available patterns (theme: ${themeName}):\n`);
51
+ for (const name of patternNames) {
52
+ const indexPath = join(patternsDir, name, "index.js");
53
+ try {
54
+ const mod = await import(indexPath);
55
+ // Check for examples.yaml
56
+ let hasExamples = false;
57
+ let examples = [];
58
+ try {
59
+ const examplesPath = join(patternsSrcDir, name, "examples.yaml");
60
+ const examplesContent = await readFile(examplesPath, "utf-8");
61
+ examples = yaml.load(examplesContent);
62
+ hasExamples = true;
63
+ }
64
+ catch {
65
+ // no examples
66
+ }
67
+ if (mod.schema) {
68
+ const shape = mod.schema.shape;
69
+ const fields = Object.entries(shape)
70
+ .map(([key, val]) => {
71
+ const desc = val.description ?? "";
72
+ const optional = val.isOptional?.() ? "?" : "";
73
+ return ` ${key}${optional}: ${desc}`;
74
+ })
75
+ .join("\n");
76
+ const badge = hasExamples ? " [examples]" : "";
77
+ console.log(` ${name}:${badge}`);
78
+ console.log(fields);
79
+ }
80
+ else {
81
+ console.log(` ${name}: (no schema)`);
82
+ }
83
+ // Show examples if requested
84
+ if (showExamples && examples.length > 0) {
85
+ console.log(` --- examples ---`);
86
+ for (const ex of examples) {
87
+ console.log(` "${ex.name}"${ex.description ? ` — ${ex.description}` : ""}`);
88
+ }
89
+ }
90
+ }
91
+ catch {
92
+ console.log(` ${name}: (not compiled — run pnpm build)`);
93
+ }
94
+ console.log();
95
+ }
96
+ }
97
+ //# sourceMappingURL=patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../src/commands/patterns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Renders a deck YAML file to standalone HTML.
3
+ * Validates the deck first, then renders via @deckspec/renderer.
4
+ */
5
+ export declare function renderCommand(filePath: string, outputPath: string): Promise<void>;
6
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/commands/render.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAoCf"}
@@ -0,0 +1,41 @@
1
+ import { writeFile } from "node:fs/promises";
2
+ import { resolve, dirname } from "node:path";
3
+ import { loadDeckFile, validateDeck } from "@deckspec/dsl";
4
+ import { renderDeck, loadThemeCSS, extractThemeName, resolveThemePatternsDir, resolveThemePatternsSrcDir, compileTsxCached } from "@deckspec/renderer";
5
+ /**
6
+ * Renders a deck YAML file to standalone HTML.
7
+ * Validates the deck first, then renders via @deckspec/renderer.
8
+ */
9
+ export async function renderCommand(filePath, outputPath) {
10
+ const raw = await loadDeckFile(filePath);
11
+ const basePath = dirname(resolve(filePath));
12
+ const themeName = extractThemeName(raw);
13
+ const patternsDir = resolveThemePatternsDir(themeName);
14
+ // Validate first
15
+ const result = await validateDeck(raw, { basePath, patternsDir, compileTsx: compileTsxCached });
16
+ if (result.deckError) {
17
+ console.error("\u2717 Deck structure is invalid:");
18
+ for (const issue of result.deckError.issues) {
19
+ console.error(` ${issue.path.join(".")}: ${issue.message}`);
20
+ }
21
+ process.exit(1);
22
+ }
23
+ if (!result.valid) {
24
+ console.error("\u2717 Validation failed. Fix errors before rendering:");
25
+ for (const slideResult of result.results) {
26
+ if (!slideResult.valid) {
27
+ for (const issue of slideResult.errors.issues) {
28
+ console.error(` slides[${slideResult.index}]: ${issue.message}`);
29
+ }
30
+ }
31
+ }
32
+ process.exit(1);
33
+ }
34
+ const deck = raw;
35
+ const themeCSS = await loadThemeCSS(deck.meta.theme);
36
+ const patternsSrcDir = resolveThemePatternsSrcDir(themeName);
37
+ const html = await renderDeck(deck, themeCSS, { basePath, patternsDir, patternsSrcDir });
38
+ await writeFile(outputPath, html, "utf-8");
39
+ console.log(`\u2713 Rendered ${result.results.length} slide(s) to ${outputPath}`);
40
+ }
41
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/commands/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE3D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,0BAA0B,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEvJ;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAAgB,EAChB,UAAkB;IAElB,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,WAAW,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC;IAEvD,iBAAiB;IACjB,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAEhG,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACrB,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACnD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YAC5C,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAC;QACxE,KAAK,MAAM,WAAW,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACzC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;gBACvB,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,MAAO,CAAC,MAAM,EAAE,CAAC;oBAC/C,OAAO,CAAC,KAAK,CAAC,YAAY,WAAW,CAAC,KAAK,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;gBACpE,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,GAAW,CAAC;IACzB,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrD,MAAM,cAAc,GAAG,0BAA0B,CAAC,SAAS,CAAC,CAAC;IAC7D,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC,CAAC;IAEzF,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,mBAAmB,MAAM,CAAC,OAAO,CAAC,MAAM,gBAAgB,UAAU,EAAE,CAAC,CAAC;AACpF,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Validates a deck YAML file.
3
+ * Prints per-slide results to stdout and exits with code 1 if any errors.
4
+ */
5
+ export declare function validateCommand(filePath: string): Promise<void>;
6
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgCrE"}