executable-stories-demo 0.1.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts","../src/index.ts"],"sourcesContent":["import * as path from \"node:path\";\n\nimport { buildDemo, initDemo, previewDemo } from \"./index\";\n\ninterface ParsedArgs {\n command?: string;\n rest: string[];\n flags: Map<string, string | boolean>;\n}\n\nasync function main(): Promise<void> {\n const parsed = parseArgs(process.argv.slice(2));\n\n switch (parsed.command) {\n case \"init\": {\n const target = parsed.rest[0] ?? \"demo-site\";\n const result = initDemo({\n targetDir: target,\n force: Boolean(parsed.flags.get(\"force\")),\n productName: getStringFlag(parsed.flags, \"product-name\"),\n });\n console.log(`Demo site initialized at ${result.targetDir}`);\n console.log(`Config created at ${result.configPath}`);\n return;\n }\n\n case \"build\": {\n const input = getStringFlag(parsed.flags, \"input\");\n const site = getStringFlag(parsed.flags, \"site\");\n\n if (!input || !site) {\n throw new Error(\"build requires --input <run.json> and --site <site-dir>\");\n }\n\n const result = await buildDemo({\n input,\n siteDir: site,\n configPath: getStringFlag(parsed.flags, \"config\"),\n allowMissingAssets: parseBooleanFlag(parsed.flags, \"allow-missing-assets\"),\n assetsBaseUrl: getStringFlag(parsed.flags, \"assets-base-url\"),\n assetsDir: getStringFlag(parsed.flags, \"assets-dir\"),\n strict: parseBooleanFlag(parsed.flags, \"strict\"),\n });\n\n console.log(`Generated ${result.pages.length} page(s)`);\n console.log(`Stories: ${path.resolve(result.storiesDir)}`);\n console.log(`Manifest: ${path.resolve(result.manifestPath)}`);\n return;\n }\n\n case \"preview\": {\n const site = getStringFlag(parsed.flags, \"site\");\n if (!site) {\n throw new Error(\"preview requires --site <site-dir>\");\n }\n\n const mode = getStringFlag(parsed.flags, \"mode\");\n if (mode && mode !== \"dev\" && mode !== \"preview\" && mode !== \"build\") {\n throw new Error(\"--mode must be one of: dev, preview, build\");\n }\n\n previewDemo({\n siteDir: site,\n mode: mode as \"dev\" | \"preview\" | \"build\" | undefined,\n });\n return;\n }\n\n case \"help\":\n case \"--help\":\n case \"-h\":\n default:\n printHelp();\n }\n}\n\nfunction parseArgs(argv: string[]): ParsedArgs {\n const [command, ...restRaw] = argv;\n const rest: string[] = [];\n const flags = new Map<string, string | boolean>();\n\n for (let i = 0; i < restRaw.length; i++) {\n const part = restRaw[i];\n\n if (!part.startsWith(\"--\")) {\n rest.push(part);\n continue;\n }\n\n const key = part.slice(2);\n const next = restRaw[i + 1];\n\n if (!next || next.startsWith(\"--\")) {\n flags.set(key, true);\n continue;\n }\n\n flags.set(key, next);\n i += 1;\n }\n\n return { command, rest, flags };\n}\n\nfunction getStringFlag(flags: Map<string, string | boolean>, key: string): string | undefined {\n const value = flags.get(key);\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction parseBooleanFlag(\n flags: Map<string, string | boolean>,\n key: string,\n): boolean | undefined {\n const value = flags.get(key);\n if (value === undefined) return undefined;\n if (typeof value === \"boolean\") return value;\n\n const normalized = value.trim().toLowerCase();\n if ([\"true\", \"1\", \"yes\", \"y\", \"on\"].includes(normalized)) return true;\n if ([\"false\", \"0\", \"no\", \"n\", \"off\"].includes(normalized)) return false;\n\n throw new Error(`--${key} expects a boolean value (true/false)`);\n}\n\nfunction printHelp(): void {\n console.log(\n `executable-stories-demo\\n\\nCommands:\\n init [dir] [--force] [--product-name <name>]\\n build --input <run.json> --site <site-dir> [--config <demo.config.json>] [--allow-missing-assets <true|false>] [--assets-base-url <url>] [--assets-dir <path>] [--strict]\\n preview --site <site-dir> [--mode dev|preview|build]`,\n );\n}\n\nmain().catch((error) => {\n const message = error instanceof Error ? error.message : String(error);\n console.error(message);\n process.exitCode = 1;\n});\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\nimport { fileURLToPath } from \"node:url\";\n\nimport {\n ReportGenerator,\n canonicalizeRun,\n copyMarkdownAssets,\n type Attachment,\n type RawRun,\n type TestCaseResult,\n type TestRunResult,\n} from \"executable-stories-formatters\";\n\nexport interface DemoCta {\n primary: string;\n url: string;\n}\n\nexport interface DemoScenarioConfig {\n order?: string[];\n}\n\nexport type DemoTemplate = \"splash\" | \"dashboard\";\n\nexport type DemoStatsMode = \"test\" | \"capability\" | \"off\";\n\nexport interface DemoStatsConfig {\n mode?: DemoStatsMode;\n}\n\nexport interface DemoFeaturedConfig {\n /** Slug of a story (e.g. \"stories/checkout/happy-path\") to feature inline on the landing page. */\n scenario?: string;\n}\n\nexport interface DemoBrandingConfig {\n /** Site-relative path or absolute URL to a logo. */\n logo?: string;\n /** Site-relative path or absolute URL to an OG/Twitter card image. */\n ogImage?: string;\n /** Site-relative path or absolute URL to a favicon. */\n favicon?: string;\n /** Optional CSS color string that overrides the active theme's --demo-accent. */\n accent?: string;\n}\n\nexport interface DemoSeoConfig {\n /** Defaults to productName. */\n title?: string;\n /** Defaults to tagline. */\n description?: string;\n /** Twitter handle including @, e.g. \"@acme\". */\n twitter?: string;\n /** Canonical URL for og:url and link rel=canonical. */\n canonical?: string;\n}\n\nexport type DemoSection =\n | { kind: \"feature-grid\"; heading?: string; items: Array<{ title: string; body: string }> }\n | { kind: \"narrative\"; heading?: string; eyebrow?: string; body: string; media?: string }\n | { kind: \"quote\"; quote: string; attribution?: string };\n\nexport interface DemoConfig {\n productName?: string;\n tagline?: string;\n theme?: string;\n template?: DemoTemplate;\n cta?: DemoCta;\n scenarios?: DemoScenarioConfig;\n stats?: DemoStatsConfig;\n featured?: DemoFeaturedConfig;\n branding?: DemoBrandingConfig;\n seo?: DemoSeoConfig;\n sections?: DemoSection[];\n}\n\nexport interface InitDemoOptions {\n targetDir?: string;\n force?: boolean;\n productName?: string;\n}\n\nexport interface InitDemoResult {\n targetDir: string;\n configPath: string;\n}\n\nexport interface BuildDemoOptions {\n input: string;\n siteDir: string;\n configPath?: string;\n allowMissingAssets?: boolean;\n assetsBaseUrl?: string;\n assetsDir?: string;\n strict?: boolean;\n}\n\nexport interface DemoPage {\n title: string;\n slug: string;\n file: string;\n}\n\nexport interface BuildDemoResult {\n pages: DemoPage[];\n manifestPath: string;\n storiesDir: string;\n}\n\nexport interface PreviewDemoOptions {\n siteDir: string;\n mode?: \"dev\" | \"preview\" | \"build\";\n}\n\ninterface ResolvedConfig {\n productName: string;\n tagline: string;\n theme: string;\n template: DemoTemplate;\n cta: DemoCta;\n scenarios: { order: string[] };\n stats: { mode: DemoStatsMode };\n featured: { scenario?: string };\n branding: DemoBrandingConfig;\n seo: DemoSeoConfig;\n sections: DemoSection[];\n}\n\nconst DEFAULT_CONFIG = {\n productName: \"Product Demo\",\n tagline: \"Executable stories turned into product walkthroughs.\",\n theme: \"default\",\n template: \"splash\" as DemoTemplate,\n cta: {\n primary: \"Get Started\",\n url: \"/\",\n },\n scenarios: {\n order: [] as string[],\n },\n // Splash audiences = customers/prospects; capability framing reads better than test counts.\n // Dashboard mode flips to \"test\" by default in loadConfig.\n stats: {\n mode: \"capability\" as DemoStatsMode,\n },\n} as const;\nconst SUPPORTED_THEMES = new Set([\n \"default\",\n \"corporate\",\n \"terminal\",\n \"minimal\",\n \"dashboard\",\n \"playful\",\n]);\nconst TEST_EXTENSIONS = [\n \".test.ts\",\n \".test.tsx\",\n \".spec.ts\",\n \".spec.tsx\",\n \".test.js\",\n \".spec.js\",\n \".story.test.ts\",\n \".story.spec.ts\",\n];\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport function initDemo(options: InitDemoOptions = {}): InitDemoResult {\n const targetDir = path.resolve(options.targetDir ?? \"./demo-site\");\n const force = options.force ?? false;\n\n if (fs.existsSync(targetDir)) {\n const entries = fs.readdirSync(targetDir);\n if (entries.length > 0 && !force) {\n throw new Error(\n `Directory \\\"${targetDir}\\\" already exists and is not empty. Use --force to overwrite.`,\n );\n }\n }\n\n const templateDir = path.resolve(\n __dirname,\n \"..\",\n \"templates\",\n \"astro-demo-starlight\",\n );\n\n if (!fs.existsSync(templateDir)) {\n throw new Error(`Template directory not found at ${templateDir}`);\n }\n\n copyDirRecursive(templateDir, targetDir);\n\n const productName = options.productName ?? toTitleCase(path.basename(targetDir));\n const config: DemoConfig = {\n productName,\n tagline: DEFAULT_CONFIG.tagline,\n theme: DEFAULT_CONFIG.theme,\n template: DEFAULT_CONFIG.template,\n cta: { ...DEFAULT_CONFIG.cta },\n scenarios: { order: [] },\n stats: { mode: DEFAULT_CONFIG.stats.mode },\n seo: {\n title: productName,\n description: DEFAULT_CONFIG.tagline,\n },\n };\n\n const configPath = path.join(targetDir, \"demo.config.json\");\n fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`, \"utf8\");\n\n return { targetDir, configPath };\n}\n\nexport async function buildDemo(options: BuildDemoOptions): Promise<BuildDemoResult> {\n const siteDir = path.resolve(options.siteDir);\n const inputPath = path.resolve(options.input);\n const configPath = path.resolve(options.configPath ?? path.join(siteDir, \"demo.config.json\"));\n const astroConfigPath = path.join(siteDir, \"astro.config.mjs\");\n\n if (!fs.existsSync(siteDir)) {\n throw new Error(\n `Demo site directory not found: ${siteDir}. Run \\\"executable-stories-demo init <dir>\\\" first.`,\n );\n }\n\n if (!fs.existsSync(astroConfigPath)) {\n throw new Error(\n `astro.config.mjs not found in ${siteDir}. This directory is not a valid demo site scaffold.`,\n );\n }\n\n if (!fs.existsSync(inputPath)) {\n throw new Error(`Input run file not found: ${inputPath}`);\n }\n\n const config = loadConfig(configPath);\n const run = loadRun(inputPath);\n\n const docsDir = path.join(siteDir, \"src\", \"content\", \"docs\");\n const storiesDir = path.join(docsDir, \"stories\");\n const strict = options.strict ?? false;\n const allowMissingAssets = strict ? false : options.allowMissingAssets ?? true;\n const assetsDir = resolveAssetsDir(siteDir, options.assetsDir);\n const assetsBaseUrl = normalizeAssetsBaseUrl(options.assetsBaseUrl);\n\n fs.mkdirSync(storiesDir, { recursive: true });\n fs.mkdirSync(assetsDir, { recursive: true });\n\n const generator = new ReportGenerator({\n formats: [\"astro\"],\n outputDir: storiesDir,\n output: {\n mode: \"colocated\",\n colocatedStyle: \"mirrored\",\n },\n astro: {\n assetsDir,\n assetsBaseUrl,\n markdown: {\n title: `${config.productName} Stories`,\n },\n },\n assetMode: \"copy\",\n allowMissingAssets,\n });\n\n const output = await generator.generate(run);\n const astroFiles = output.get(\"astro\") ?? [];\n appendAttachmentsToPages({\n astroFiles,\n run,\n storiesDir,\n assetsDir,\n assetsBaseUrl,\n allowMissingAssets,\n });\n\n const pages = toPages(astroFiles, docsDir, config.scenarios.order);\n writeLandingPage(path.join(docsDir, \"index.mdx\"), config, pages, run, docsDir, assetsBaseUrl);\n applyThemeToAstroConfig(siteDir, config.theme);\n\n const manifest = {\n generatedAt: new Date().toISOString(),\n input: toPosix(inputPath),\n config: toPosix(configPath),\n productName: config.productName,\n theme: config.theme,\n assets: {\n dir: toPosix(assetsDir),\n baseUrl: assetsBaseUrl,\n allowMissing: allowMissingAssets,\n strict,\n },\n stats: {\n scenarios: run.testCases.length,\n passed: run.testCases.filter((tc) => tc.status === \"passed\").length,\n failed: run.testCases.filter((tc) => tc.status === \"failed\").length,\n skipped: run.testCases.filter((tc) => tc.status === \"skipped\").length,\n pending: run.testCases.filter((tc) => tc.status === \"pending\").length,\n },\n pages,\n };\n\n const manifestPath = path.join(siteDir, \"demo-manifest.json\");\n fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\\n`, \"utf8\");\n\n return {\n pages,\n manifestPath,\n storiesDir,\n };\n}\n\nexport function previewDemo(options: PreviewDemoOptions): void {\n const siteDir = path.resolve(options.siteDir);\n const mode = options.mode ?? \"dev\";\n\n const command = mode === \"build\" ? \"build\" : mode === \"preview\" ? \"preview\" : \"dev\";\n const result = spawnSync(\"pnpm\", [command], {\n cwd: siteDir,\n stdio: \"inherit\",\n shell: process.platform === \"win32\",\n });\n\n if (result.status !== 0) {\n throw new Error(`pnpm ${command} failed with exit code ${result.status ?? 1}`);\n }\n}\n\nfunction loadConfig(configPath: string): ResolvedConfig {\n const userConfig = fs.existsSync(configPath)\n ? (JSON.parse(fs.readFileSync(configPath, \"utf8\")) as DemoConfig)\n : {};\n const theme = normalizeTheme(userConfig.theme);\n const template: DemoTemplate =\n userConfig.template === \"dashboard\" ? \"dashboard\" : DEFAULT_CONFIG.template;\n const statsMode: DemoStatsMode = (() => {\n const m = userConfig.stats?.mode;\n if (m === \"test\" || m === \"capability\" || m === \"off\") return m;\n // Dashboard audiences are engineering — test framing fits.\n return template === \"dashboard\" ? \"test\" : DEFAULT_CONFIG.stats.mode;\n })();\n\n return {\n productName: userConfig.productName ?? DEFAULT_CONFIG.productName,\n tagline: userConfig.tagline ?? DEFAULT_CONFIG.tagline,\n theme,\n template,\n cta: {\n primary: userConfig.cta?.primary ?? DEFAULT_CONFIG.cta.primary,\n url: userConfig.cta?.url ?? DEFAULT_CONFIG.cta.url,\n },\n scenarios: {\n order: userConfig.scenarios?.order ?? [...DEFAULT_CONFIG.scenarios.order],\n },\n stats: { mode: statsMode },\n featured: {\n scenario: userConfig.featured?.scenario,\n },\n branding: {\n logo: userConfig.branding?.logo,\n ogImage: userConfig.branding?.ogImage,\n favicon: userConfig.branding?.favicon,\n accent: userConfig.branding?.accent,\n },\n seo: {\n title: userConfig.seo?.title,\n description: userConfig.seo?.description,\n twitter: userConfig.seo?.twitter,\n canonical: userConfig.seo?.canonical,\n },\n sections: userConfig.sections ?? [],\n };\n}\n\nfunction loadRun(inputPath: string): TestRunResult {\n const payload = JSON.parse(fs.readFileSync(inputPath, \"utf8\")) as unknown;\n\n if (isRawLikePayload(payload)) {\n return canonicalizeRun(payload as RawRun);\n }\n\n return payload as TestRunResult;\n}\n\nfunction isRawLikePayload(payload: unknown): boolean {\n if (!payload || typeof payload !== \"object\") return false;\n\n const maybeCases = (payload as { testCases?: Array<{ status?: unknown }> }).testCases;\n const firstStatus = maybeCases?.[0]?.status;\n\n return firstStatus === \"pass\" || firstStatus === \"fail\" || firstStatus === \"skip\";\n}\n\nfunction appendAttachmentsToPages(args: {\n astroFiles: string[];\n run: TestRunResult;\n storiesDir: string;\n assetsDir: string;\n assetsBaseUrl: string;\n allowMissingAssets: boolean;\n}): void {\n const byPage = groupAttachmentsByPage(args.run.testCases, args.storiesDir, \"index\");\n\n for (const filePath of args.astroFiles) {\n const attachments = byPage.get(toPosix(path.resolve(filePath)));\n if (!attachments || attachments.length === 0) continue;\n\n const markdownDir = path.dirname(filePath);\n const unique = dedupeAttachments(attachments);\n const rendered = renderAttachmentSection(unique, markdownDir, args.run.projectRoot);\n if (rendered.length === 0) continue;\n\n const original = fs.readFileSync(filePath, \"utf8\");\n const appended = `${original.trimEnd()}\\n\\n${rendered}\\n`;\n\n const copied = copyMarkdownAssets({\n markdown: appended,\n markdownDir,\n assetsDir: args.assetsDir,\n assetsBaseUrl: args.assetsBaseUrl,\n allowMissing: args.allowMissingAssets,\n });\n\n fs.writeFileSync(filePath, copied.markdown, \"utf8\");\n }\n}\n\nfunction groupAttachmentsByPage(\n testCases: TestCaseResult[],\n storiesDir: string,\n outputName: string,\n): Map<string, Attachment[]> {\n const grouped = new Map<string, Attachment[]>();\n const baseDir = toPosix(path.resolve(storiesDir));\n\n for (const tc of testCases) {\n if (tc.attachments.length === 0) continue;\n\n const outputPath = computeStoryOutputPath(tc.sourceFile, baseDir, outputName);\n const existing = grouped.get(outputPath) ?? [];\n existing.push(...tc.attachments);\n grouped.set(outputPath, existing);\n }\n\n return grouped;\n}\n\nfunction computeStoryOutputPath(sourceFile: string, baseOutputDir: string, outputName: string): string {\n if (sourceFile === \"unknown\") {\n return toPosix(path.join(baseOutputDir, `${outputName}.md`));\n }\n\n const normalizedSource = toPosix(sourceFile);\n const dirOfSource = path.posix.dirname(normalizedSource);\n let baseName = path.posix.basename(normalizedSource);\n\n for (const extension of TEST_EXTENSIONS) {\n if (baseName.endsWith(extension)) {\n baseName = baseName.slice(0, -extension.length);\n break;\n }\n }\n\n const fileName = `${baseName}.${outputName}.md`;\n return toPosix(path.posix.join(baseOutputDir, dirOfSource, fileName));\n}\n\nfunction dedupeAttachments(attachments: Attachment[]): Attachment[] {\n const seen = new Set<string>();\n const deduped: Attachment[] = [];\n\n for (const attachment of attachments) {\n const key = `${attachment.name}|${attachment.mediaType}|${attachment.contentEncoding}|${attachment.body}`;\n if (seen.has(key)) continue;\n seen.add(key);\n deduped.push(attachment);\n }\n\n return deduped;\n}\n\nfunction renderAttachmentSection(\n attachments: Attachment[],\n markdownDir: string,\n projectRoot: string,\n): string {\n const lines: string[] = [\"## Media\", \"\"];\n\n for (const attachment of attachments) {\n const source = resolveAttachmentSource(attachment, markdownDir, projectRoot);\n if (!source) continue;\n\n const label = attachment.name || \"Attachment\";\n if (attachment.mediaType.startsWith(\"video/\")) {\n lines.push(`### ${label}`);\n lines.push(\"\");\n lines.push(`<video controls preload=\\\"metadata\\\" src=\\\"${source}\\\"></video>`);\n lines.push(\"\");\n continue;\n }\n\n if (attachment.mediaType.startsWith(\"image/\")) {\n lines.push(`### ${label}`);\n lines.push(\"\");\n lines.push(`![${label}](${source})`);\n lines.push(\"\");\n continue;\n }\n\n lines.push(`- [${label}](${source})`);\n }\n\n if (lines.length <= 2) return \"\";\n return lines.join(\"\\n\");\n}\n\nfunction resolveAttachmentSource(\n attachment: Attachment,\n markdownDir: string,\n projectRoot: string,\n): string | undefined {\n if (!attachment.body) return undefined;\n\n if (attachment.contentEncoding === \"BASE64\") {\n return `data:${attachment.mediaType};base64,${attachment.body}`;\n }\n\n const body = attachment.body.trim();\n if (\n body.startsWith(\"http://\") ||\n body.startsWith(\"https://\") ||\n body.startsWith(\"data:\") ||\n body.startsWith(\"#\")\n ) {\n return body;\n }\n\n if (path.isAbsolute(body) && fs.existsSync(body)) {\n return toPosix(path.relative(markdownDir, body));\n }\n\n const candidateFromProject = path.resolve(projectRoot, body);\n if (fs.existsSync(candidateFromProject)) {\n return toPosix(path.relative(markdownDir, candidateFromProject));\n }\n\n return body;\n}\n\nfunction toPages(astroFiles: string[], docsDir: string, orderedSlugs: string[]): DemoPage[] {\n const pages = astroFiles.map((absPath) => {\n const rel = toPosix(path.relative(docsDir, absPath));\n const withoutExt = rel.replace(/\\.md$/, \"\");\n const slug = withoutExt;\n const title = toTitleCase(normalizePageName(path.basename(withoutExt)));\n return {\n title,\n slug,\n file: rel,\n };\n });\n\n if (orderedSlugs.length === 0) return pages;\n\n const rank = new Map(orderedSlugs.map((slug, index) => [slug, index]));\n return [...pages].sort((a, b) => {\n const ar = rank.get(a.slug);\n const br = rank.get(b.slug);\n\n if (ar === undefined && br === undefined) return a.slug.localeCompare(b.slug);\n if (ar === undefined) return 1;\n if (br === undefined) return -1;\n return ar - br;\n });\n}\n\nfunction normalizePageName(fileBase: string): string {\n return fileBase\n .replace(/\\.story\\.index$/i, \"\")\n .replace(/\\.index$/i, \"\")\n .replace(/\\.story$/i, \"\");\n}\n\nfunction applyThemeToAstroConfig(siteDir: string, requestedTheme: string): void {\n const configPath = path.join(siteDir, \"astro.config.mjs\");\n if (!fs.existsSync(configPath)) return;\n\n const theme = normalizeTheme(requestedTheme);\n const config = fs.readFileSync(configPath, \"utf8\");\n const updated = config.replace(\n /'\\.\\/src\\/styles\\/themes\\/[^']+\\.css'/,\n `'./src/styles/themes/${theme}.css'`,\n );\n\n fs.writeFileSync(configPath, updated, \"utf8\");\n}\n\nfunction normalizeTheme(requestedTheme: string | undefined): string {\n if (!requestedTheme) return DEFAULT_CONFIG.theme;\n return SUPPORTED_THEMES.has(requestedTheme) ? requestedTheme : DEFAULT_CONFIG.theme;\n}\n\ntype PageStatus = \"passed\" | \"failed\" | \"skipped\" | \"pending\";\n\ninterface RunStats {\n total: number;\n passed: number;\n failed: number;\n skipped: number;\n}\n\nfunction computeStats(run: TestRunResult): RunStats {\n return {\n total: run.testCases.length,\n passed: run.testCases.filter((tc) => tc.status === \"passed\").length,\n failed: run.testCases.filter((tc) => tc.status === \"failed\").length,\n skipped: run.testCases.filter((tc) => tc.status === \"skipped\").length,\n };\n}\n\nfunction renderHead(config: ResolvedConfig): string[] {\n const seoTitle = config.seo.title ?? config.productName;\n const seoDesc = config.seo.description ?? config.tagline;\n const ogImage = config.branding.ogImage;\n const canonical = config.seo.canonical;\n const twitter = config.seo.twitter;\n\n const tags: Array<{ tag: string; attrs: Record<string, string> }> = [\n { tag: \"meta\", attrs: { property: \"og:type\", content: \"website\" } },\n { tag: \"meta\", attrs: { property: \"og:title\", content: seoTitle } },\n { tag: \"meta\", attrs: { property: \"og:description\", content: seoDesc } },\n { tag: \"meta\", attrs: { name: \"twitter:card\", content: ogImage ? \"summary_large_image\" : \"summary\" } },\n { tag: \"meta\", attrs: { name: \"twitter:title\", content: seoTitle } },\n { tag: \"meta\", attrs: { name: \"twitter:description\", content: seoDesc } },\n ];\n if (ogImage) {\n tags.push({ tag: \"meta\", attrs: { property: \"og:image\", content: ogImage } });\n tags.push({ tag: \"meta\", attrs: { name: \"twitter:image\", content: ogImage } });\n }\n if (canonical) {\n tags.push({ tag: \"meta\", attrs: { property: \"og:url\", content: canonical } });\n tags.push({ tag: \"link\", attrs: { rel: \"canonical\", href: canonical } });\n }\n if (twitter) {\n tags.push({ tag: \"meta\", attrs: { name: \"twitter:site\", content: twitter } });\n }\n if (config.branding.favicon) {\n tags.push({ tag: \"link\", attrs: { rel: \"icon\", href: config.branding.favicon } });\n }\n\n const lines = [\"head:\"];\n for (const { tag, attrs } of tags) {\n lines.push(` - tag: ${tag}`);\n lines.push(` attrs:`);\n for (const [k, v] of Object.entries(attrs)) {\n lines.push(` ${k}: ${yamlString(v)}`);\n }\n }\n return lines;\n}\n\nfunction renderStats(mode: DemoStatsMode, stats: RunStats): string[] {\n if (mode === \"off\") return [];\n\n if (mode === \"capability\") {\n // Customer-facing framing: total = capabilities verified, no fail count up top.\n const verified = stats.passed;\n const inProgress = stats.failed + stats.skipped;\n const items: string[] = [\n ` <ul class=\"demo-stats\" aria-label=\"Coverage summary\">`,\n ` <li class=\"demo-stat\" data-tone=\"total\"><span class=\"demo-stat__value\">${stats.total}</span><span class=\"demo-stat__label\">Scenarios</span></li>`,\n ` <li class=\"demo-stat\" data-tone=\"pass\"><span class=\"demo-stat__value\">${verified}</span><span class=\"demo-stat__label\">Verified</span></li>`,\n ];\n if (inProgress > 0) {\n items.push(\n ` <li class=\"demo-stat\" data-tone=\"pending\"><span class=\"demo-stat__value\">${inProgress}</span><span class=\"demo-stat__label\">In progress</span></li>`,\n );\n }\n items.push(` </ul>`);\n return [\"\", ...items];\n }\n\n // Test mode: original engineering dashboard.\n return [\n \"\",\n ` <ul class=\"demo-stats\" aria-label=\"Test results\">`,\n ` <li class=\"demo-stat\" data-tone=\"total\"><span class=\"demo-stat__value\">${stats.total}</span><span class=\"demo-stat__label\">Scenarios</span></li>`,\n ` <li class=\"demo-stat\" data-tone=\"pass\"><span class=\"demo-stat__value\">${stats.passed}</span><span class=\"demo-stat__label\">Passed</span></li>`,\n ` <li class=\"demo-stat\" data-tone=\"fail\"><span class=\"demo-stat__value\">${stats.failed}</span><span class=\"demo-stat__label\">Failed</span></li>`,\n ` <li class=\"demo-stat\" data-tone=\"skip\"><span class=\"demo-stat__value\">${stats.skipped}</span><span class=\"demo-stat__label\">Skipped</span></li>`,\n ` </ul>`,\n ];\n}\n\nfunction renderStoryList(\n pages: DemoPage[],\n statusBySlug: Map<string, PageStatus>,\n heading: string,\n): string[] {\n const lines: string[] = [\n \"\",\n ` <section class=\"demo-section\">`,\n ` <h2 class=\"demo-section-heading\">${escapeHtml(heading)}</h2>`,\n ];\n if (pages.length === 0) {\n lines.push(\n ` <div class=\"demo-empty\">No stories generated yet. Run <code>executable-stories-demo build</code>.</div>`,\n );\n } else {\n lines.push(` <ol class=\"demo-stories\">`);\n pages.forEach((page, index) => {\n const status = statusBySlug.get(page.slug) ?? \"pending\";\n const indexLabel = String(index + 1).padStart(2, \"0\");\n const title = escapeHtml(page.title);\n const statusLabel = escapeHtml(status);\n const href = toAstroUrl(page.slug);\n lines.push(\n ` <li><a class=\"demo-story\" data-status=\"${statusLabel}\" href=\"${href}\">` +\n `<span class=\"demo-story__index\">${indexLabel}</span>` +\n `<span class=\"demo-story__title\">${title}</span>` +\n `<span class=\"demo-story__status\">${statusLabel}</span></a></li>`,\n );\n });\n lines.push(` </ol>`);\n }\n lines.push(` </section>`);\n return lines;\n}\n\nfunction findFeaturedMedia(\n featuredSlug: string,\n pages: DemoPage[],\n run: TestRunResult,\n docsDir: string,\n assetsBaseUrl: string,\n):\n | { kind: \"video\" | \"image\"; src: string; alt: string; storyHref: string; storyTitle: string }\n | undefined {\n const target = pages.find((p) => p.slug === featuredSlug);\n if (!target) return undefined;\n\n const storiesDir = path.join(docsDir, \"stories\");\n const baseDir = toPosix(path.resolve(storiesDir));\n\n for (const tc of run.testCases) {\n const out = computeStoryOutputPath(tc.sourceFile, baseDir, \"index\");\n const rel = toPosix(path.posix.relative(toPosix(path.resolve(docsDir)), out));\n const slug = rel.replace(/\\.md$/, \"\");\n if (slug !== featuredSlug) continue;\n\n for (const att of tc.attachments) {\n const isVideo = att.mediaType.startsWith(\"video/\");\n const isImage = att.mediaType.startsWith(\"image/\");\n if (!isVideo && !isImage) continue;\n // Best-effort src: data URI for embedded, otherwise assume it lives under assetsBaseUrl\n // by name (the attachment pipeline already copies + hashes files into assetsDir).\n let src: string | undefined;\n if (att.contentEncoding === \"BASE64\") {\n src = `data:${att.mediaType};base64,${att.body}`;\n } else if (att.body) {\n const body = att.body.trim();\n if (body.startsWith(\"http\") || body.startsWith(\"data:\") || body.startsWith(\"/\")) {\n src = body;\n } else {\n src = `${assetsBaseUrl}/${path.posix.basename(body)}`;\n }\n }\n if (!src) continue;\n return {\n kind: isVideo ? \"video\" : \"image\",\n src,\n alt: att.name || target.title,\n storyHref: toAstroUrl(target.slug),\n storyTitle: target.title,\n };\n }\n }\n\n return undefined;\n}\n\nfunction renderFeatured(\n featured: NonNullable<ReturnType<typeof findFeaturedMedia>>,\n): string[] {\n const lines: string[] = [\n \"\",\n ` <section class=\"demo-featured\" aria-labelledby=\"demo-featured-title\">`,\n ` <span class=\"demo-featured__eyebrow\">Watch first</span>`,\n ` <h2 id=\"demo-featured-title\" class=\"demo-featured__title\">${escapeHtml(featured.storyTitle)}</h2>`,\n ` <div class=\"demo-featured__media\">`,\n ];\n if (featured.kind === \"video\") {\n lines.push(\n ` <video class=\"demo-featured__video\" controls preload=\"metadata\" src=\"${escapeHtml(featured.src)}\" aria-label=\"${escapeHtml(featured.alt)}\"></video>`,\n );\n } else {\n lines.push(\n ` <img class=\"demo-featured__image\" src=\"${escapeHtml(featured.src)}\" alt=\"${escapeHtml(featured.alt)}\" />`,\n );\n }\n lines.push(` </div>`);\n lines.push(\n ` <a class=\"demo-featured__link\" href=\"${escapeHtml(featured.storyHref)}\">Read the full scenario →</a>`,\n );\n lines.push(` </section>`);\n return lines;\n}\n\nfunction renderSections(sections: DemoSection[]): string[] {\n if (sections.length === 0) return [];\n const lines: string[] = [];\n\n for (const section of sections) {\n lines.push(\"\");\n if (section.kind === \"feature-grid\") {\n lines.push(` <section class=\"demo-section\">`);\n if (section.heading) {\n lines.push(` <h2 class=\"demo-section-heading\">${escapeHtml(section.heading)}</h2>`);\n }\n lines.push(` <ul class=\"demo-feature-grid\">`);\n for (const item of section.items) {\n lines.push(` <li class=\"demo-feature\">`);\n lines.push(` <h3 class=\"demo-feature__title\">${escapeHtml(item.title)}</h3>`);\n lines.push(` <p class=\"demo-feature__body\">${escapeHtml(item.body)}</p>`);\n lines.push(` </li>`);\n }\n lines.push(` </ul>`);\n lines.push(` </section>`);\n } else if (section.kind === \"narrative\") {\n lines.push(` <section class=\"demo-narrative\">`);\n lines.push(` <div class=\"demo-narrative__copy\">`);\n if (section.eyebrow) {\n lines.push(` <span class=\"demo-narrative__eyebrow\">${escapeHtml(section.eyebrow)}</span>`);\n }\n if (section.heading) {\n lines.push(` <h2 class=\"demo-narrative__heading\">${escapeHtml(section.heading)}</h2>`);\n }\n lines.push(` <p class=\"demo-narrative__body\">${escapeHtml(section.body)}</p>`);\n lines.push(` </div>`);\n if (section.media) {\n lines.push(` <div class=\"demo-narrative__media\">`);\n lines.push(` <img src=\"${escapeHtml(section.media)}\" alt=\"\" />`);\n lines.push(` </div>`);\n }\n lines.push(` </section>`);\n } else if (section.kind === \"quote\") {\n lines.push(` <figure class=\"demo-quote\">`);\n lines.push(` <blockquote class=\"demo-quote__body\">${escapeHtml(section.quote)}</blockquote>`);\n if (section.attribution) {\n lines.push(` <figcaption class=\"demo-quote__attribution\">${escapeHtml(section.attribution)}</figcaption>`);\n }\n lines.push(` </figure>`);\n }\n }\n\n return lines;\n}\n\nfunction writeLandingPage(\n indexPath: string,\n config: ResolvedConfig,\n pages: DemoPage[],\n run: TestRunResult,\n docsDir: string,\n assetsBaseUrl: string,\n): void {\n const stats = computeStats(run);\n const statusBySlug = buildStatusBySlug(run, docsDir);\n const ctaHref = config.cta.url || \"/\";\n const ctaLabel = escapeHtml(config.cta.primary);\n const productName = escapeHtml(config.productName);\n const tagline = escapeHtml(config.tagline);\n const isSplash = config.template === \"splash\";\n\n const frontmatter: string[] = [\n \"---\",\n `title: ${yamlString(config.productName)}`,\n `description: ${yamlString(config.tagline)}`,\n \"template: splash\",\n ];\n // SEO/OG meta via Starlight's frontmatter `head:` block.\n for (const line of renderHead(config)) frontmatter.push(line);\n frontmatter.push(\"---\", \"\");\n\n const accentVar = config.branding.accent\n ? ` style=\"--demo-accent-override: ${cssColorEscape(config.branding.accent)};\"`\n : \"\";\n\n const lines: string[] = [\n ...frontmatter,\n `{/* Generated by executable-stories-demo. Edit demo.config.json, not this file. */}`,\n `{/* template=${config.template} theme=${config.theme} stats=${config.stats.mode} */}`,\n \"\",\n `<div class=\"demo-landing not-content\" data-template=\"${config.template}\"${accentVar}>`,\n \"\",\n ` <section class=\"demo-hero\">`,\n ];\n\n if (config.branding.logo) {\n lines.push(\n ` <img class=\"demo-hero__logo\" src=\"${escapeHtml(config.branding.logo)}\" alt=\"${escapeHtml(config.productName + \" logo\")}\" />`,\n );\n }\n lines.push(\n ` <span class=\"demo-hero__eyebrow\">${escapeHtml(isSplash ? \"Product demo\" : \"Executable stories\")}</span>`,\n ` <h1 class=\"demo-hero__title\">${productName}</h1>`,\n ` <p class=\"demo-hero__tagline\">${tagline}</p>`,\n ` <a class=\"demo-hero__cta\" href=\"${escapeHtml(ctaHref)}\">${ctaLabel}</a>`,\n ` </section>`,\n );\n\n // Featured scenario (splash mode only — and only if config.featured.scenario resolves to a real story).\n if (isSplash && config.featured.scenario) {\n const featured = findFeaturedMedia(\n config.featured.scenario,\n pages,\n run,\n docsDir,\n assetsBaseUrl,\n );\n if (featured) lines.push(...renderFeatured(featured));\n }\n\n // Stats — capability framing in splash, test framing in dashboard, hidden if mode=off.\n for (const line of renderStats(config.stats.mode, stats)) lines.push(line);\n\n // Custom sections (splash only — dashboard stays focused on the test run).\n if (isSplash) {\n for (const line of renderSections(config.sections)) lines.push(line);\n }\n\n // Story list (always, but heading copy depends on mode).\n const storyHeading = isSplash ? \"Scenarios\" : \"Stories\";\n for (const line of renderStoryList(pages, statusBySlug, storyHeading)) {\n lines.push(line);\n }\n\n lines.push(\"\");\n lines.push(\"</div>\");\n\n fs.writeFileSync(indexPath, `${lines.join(\"\\n\")}\\n`, \"utf8\");\n}\n\n/**\n * YAML-safe scalar quote: `\"foo\"` for any value that contains characters YAML\n * would interpret. Used for frontmatter values we generate from user config.\n */\nfunction yamlString(value: string): string {\n return `\"${value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\n/** Inline CSS values get a tighter sanitisation than HTML attributes. */\nfunction cssColorEscape(value: string): string {\n // Strip anything that isn't a plausible CSS value character to neutralise\n // injection via style attributes. Keep alnum + common color punctuation.\n return value.replace(/[^a-zA-Z0-9#%(),.\\-\\s/]/g, \"\");\n}\n\nfunction buildStatusBySlug(run: TestRunResult, docsDir: string): Map<string, PageStatus> {\n const storiesDir = path.join(docsDir, \"stories\");\n const baseDir = toPosix(path.resolve(storiesDir));\n const absDocsDir = toPosix(path.resolve(docsDir));\n const result = new Map<string, PageStatus>();\n\n for (const tc of run.testCases) {\n const outputPath = computeStoryOutputPath(tc.sourceFile, baseDir, \"index\");\n const relative = toPosix(path.posix.relative(absDocsDir, outputPath));\n const slug = relative.replace(/\\.md$/, \"\");\n const current = result.get(slug);\n result.set(slug, mergePageStatus(current, tc.status as PageStatus));\n }\n\n return result;\n}\n\nfunction mergePageStatus(current: PageStatus | undefined, incoming: PageStatus): PageStatus {\n if (!current) return incoming;\n if (current === \"failed\" || incoming === \"failed\") return \"failed\";\n if (current === \"passed\" || incoming === \"passed\") return \"passed\";\n if (current === \"skipped\" && incoming === \"skipped\") return \"skipped\";\n return current;\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n}\n\n// Astro Starlight's content loader sanitizes slug segments by stripping\n// non-alphanumeric/-/_ characters and lower-casing. Mirror that so the\n// landing-page links resolve to the pages Astro actually emits.\nfunction toAstroUrl(pageSlug: string): string {\n const sanitized = pageSlug\n .split(\"/\")\n .map((segment) => segment.toLowerCase().replace(/[^a-z0-9_-]/g, \"\"))\n .filter(Boolean)\n .join(\"/\");\n return sanitized.length === 0 ? \"/\" : `/${sanitized}/`;\n}\n\nfunction copyDirRecursive(src: string, dest: string): void {\n fs.mkdirSync(dest, { recursive: true });\n const entries = fs.readdirSync(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n\n if (entry.isDirectory()) {\n copyDirRecursive(srcPath, destPath);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n\nfunction toTitleCase(value: string): string {\n return value\n .replace(/[-_]/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim()\n .replace(/\\b\\w/g, (match) => match.toUpperCase());\n}\n\nfunction toPosix(value: string): string {\n return value.split(path.sep).join(\"/\");\n}\n\nfunction normalizeAssetsBaseUrl(value: string | undefined): string {\n const base = value ?? \"/demo-assets\";\n if (!base.startsWith(\"/\")) return `/${base.replace(/\\/+$/, \"\")}`;\n return base.replace(/\\/+$/, \"\") || \"/demo-assets\";\n}\n\nfunction resolveAssetsDir(siteDir: string, value: string | undefined): string {\n if (!value) return path.join(siteDir, \"public\", \"demo-assets\");\n if (path.isAbsolute(value)) return value;\n return path.join(siteDir, value);\n}\n"],"mappings":"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","names":["path","relative"]}
@@ -0,0 +1,104 @@
1
+ interface DemoCta {
2
+ primary: string;
3
+ url: string;
4
+ }
5
+ interface DemoScenarioConfig {
6
+ order?: string[];
7
+ }
8
+ type DemoTemplate = "splash" | "dashboard";
9
+ type DemoStatsMode = "test" | "capability" | "off";
10
+ interface DemoStatsConfig {
11
+ mode?: DemoStatsMode;
12
+ }
13
+ interface DemoFeaturedConfig {
14
+ /** Slug of a story (e.g. "stories/checkout/happy-path") to feature inline on the landing page. */
15
+ scenario?: string;
16
+ }
17
+ interface DemoBrandingConfig {
18
+ /** Site-relative path or absolute URL to a logo. */
19
+ logo?: string;
20
+ /** Site-relative path or absolute URL to an OG/Twitter card image. */
21
+ ogImage?: string;
22
+ /** Site-relative path or absolute URL to a favicon. */
23
+ favicon?: string;
24
+ /** Optional CSS color string that overrides the active theme's --demo-accent. */
25
+ accent?: string;
26
+ }
27
+ interface DemoSeoConfig {
28
+ /** Defaults to productName. */
29
+ title?: string;
30
+ /** Defaults to tagline. */
31
+ description?: string;
32
+ /** Twitter handle including @, e.g. "@acme". */
33
+ twitter?: string;
34
+ /** Canonical URL for og:url and link rel=canonical. */
35
+ canonical?: string;
36
+ }
37
+ type DemoSection = {
38
+ kind: "feature-grid";
39
+ heading?: string;
40
+ items: Array<{
41
+ title: string;
42
+ body: string;
43
+ }>;
44
+ } | {
45
+ kind: "narrative";
46
+ heading?: string;
47
+ eyebrow?: string;
48
+ body: string;
49
+ media?: string;
50
+ } | {
51
+ kind: "quote";
52
+ quote: string;
53
+ attribution?: string;
54
+ };
55
+ interface DemoConfig {
56
+ productName?: string;
57
+ tagline?: string;
58
+ theme?: string;
59
+ template?: DemoTemplate;
60
+ cta?: DemoCta;
61
+ scenarios?: DemoScenarioConfig;
62
+ stats?: DemoStatsConfig;
63
+ featured?: DemoFeaturedConfig;
64
+ branding?: DemoBrandingConfig;
65
+ seo?: DemoSeoConfig;
66
+ sections?: DemoSection[];
67
+ }
68
+ interface InitDemoOptions {
69
+ targetDir?: string;
70
+ force?: boolean;
71
+ productName?: string;
72
+ }
73
+ interface InitDemoResult {
74
+ targetDir: string;
75
+ configPath: string;
76
+ }
77
+ interface BuildDemoOptions {
78
+ input: string;
79
+ siteDir: string;
80
+ configPath?: string;
81
+ allowMissingAssets?: boolean;
82
+ assetsBaseUrl?: string;
83
+ assetsDir?: string;
84
+ strict?: boolean;
85
+ }
86
+ interface DemoPage {
87
+ title: string;
88
+ slug: string;
89
+ file: string;
90
+ }
91
+ interface BuildDemoResult {
92
+ pages: DemoPage[];
93
+ manifestPath: string;
94
+ storiesDir: string;
95
+ }
96
+ interface PreviewDemoOptions {
97
+ siteDir: string;
98
+ mode?: "dev" | "preview" | "build";
99
+ }
100
+ declare function initDemo(options?: InitDemoOptions): InitDemoResult;
101
+ declare function buildDemo(options: BuildDemoOptions): Promise<BuildDemoResult>;
102
+ declare function previewDemo(options: PreviewDemoOptions): void;
103
+
104
+ export { type BuildDemoOptions, type BuildDemoResult, type DemoBrandingConfig, type DemoConfig, type DemoCta, type DemoFeaturedConfig, type DemoPage, type DemoScenarioConfig, type DemoSection, type DemoSeoConfig, type DemoStatsConfig, type DemoStatsMode, type DemoTemplate, type InitDemoOptions, type InitDemoResult, type PreviewDemoOptions, buildDemo, initDemo, previewDemo };