@vizejs/vite-plugin-musea 0.263.0 → 0.267.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.
- package/dist/cli/index.mjs +8 -0
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.d.mts +7 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +180 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/cli/index.mjs
CHANGED
|
@@ -82,6 +82,9 @@ async function parseArtFile(filePath) {
|
|
|
82
82
|
function hasCiBlockingVrtResult(summary) {
|
|
83
83
|
return summary.failed > 0 || summary.skipped > 0;
|
|
84
84
|
}
|
|
85
|
+
function isArtFileInput(filePath) {
|
|
86
|
+
return filePath.endsWith(".art.vue");
|
|
87
|
+
}
|
|
85
88
|
async function runVrt(options, artFiles) {
|
|
86
89
|
const totalVariants = artFiles.reduce((sum, art) => sum + art.variants.filter((v) => !v.skipVrt).length, 0);
|
|
87
90
|
console.log(` Testing ${totalVariants} variant(s) across ${artFiles.length} art file(s)\n`);
|
|
@@ -210,6 +213,11 @@ async function runGenerate(options) {
|
|
|
210
213
|
process.exit(1);
|
|
211
214
|
}
|
|
212
215
|
const componentPath = path.resolve(options.componentPath);
|
|
216
|
+
if (isArtFileInput(componentPath)) {
|
|
217
|
+
console.error(" Error: musea-vrt generate expects a source .vue component, not a .art.vue file.");
|
|
218
|
+
console.error(" Pass the component file that the art file should wrap.\n");
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
213
221
|
try {
|
|
214
222
|
await fs.promises.access(componentPath);
|
|
215
223
|
} catch {
|
package/dist/cli/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/cli/utils.ts","../../src/cli/commands.ts","../../src/cli/index.ts"],"sourcesContent":["/**\n * CLI utility functions for art file scanning and parsing.\n *\n * Extracted from cli.ts to keep file sizes manageable.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nimport type { ArtFileInfo } from \"../types/index.js\";\n\n/** Recursively scan a directory for .art.vue files. */\nexport async function scanArtFiles(root: string): Promise<string[]> {\n const files: string[] = [];\n\n async function scan(dir: string): Promise<void> {\n let entries: fs.Dirent[];\n try {\n entries = await fs.promises.readdir(dir, { withFileTypes: true });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EACCES\") {\n return;\n }\n throw error;\n }\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n // Skip node_modules and dist\n if (entry.name === \"node_modules\" || entry.name === \"dist\") {\n continue;\n }\n\n if (entry.isDirectory()) {\n await scan(fullPath);\n } else if (entry.isFile() && entry.name.endsWith(\".art.vue\")) {\n files.push(fullPath);\n }\n }\n }\n\n await scan(root);\n return files;\n}\n\n/** Parse a single .art.vue file into an ArtFileInfo structure. */\nexport async function parseArtFile(filePath: string): Promise<ArtFileInfo | null> {\n try {\n const source = await fs.promises.readFile(filePath, \"utf-8\");\n\n // Simple parsing - in production, use @vizejs/native\n const titleMatch = source.match(/<art[^>]*\\stitle=[\"']([^\"']+)[\"']/);\n const componentMatch = source.match(/<art[^>]*\\scomponent=[\"']([^\"']+)[\"']/);\n const categoryMatch = source.match(/<art[^>]*\\scategory=[\"']([^\"']+)[\"']/);\n\n const variants: ArtFileInfo[\"variants\"] = [];\n const variantRegex = /<variant\\s+([^>]*)>([\\s\\S]*?)<\\/variant>/g;\n let match;\n\n while ((match = variantRegex.exec(source)) !== null) {\n const attrs = match[1];\n const template = match[2].trim();\n\n const nameMatch = attrs.match(/name=[\"']([^\"']+)[\"']/);\n const isDefault = /\\bdefault\\b/.test(attrs);\n const skipVrt = /\\bskip-vrt\\b/.test(attrs);\n\n if (nameMatch) {\n variants.push({\n name: nameMatch[1],\n template,\n isDefault,\n skipVrt,\n });\n }\n }\n\n return {\n path: filePath,\n metadata: {\n title: titleMatch?.[1] || path.basename(filePath, \".art.vue\"),\n component: componentMatch?.[1],\n category: categoryMatch?.[1],\n tags: [],\n status: \"ready\",\n },\n variants,\n hasScriptSetup: /<script\\s+setup/.test(source),\n hasScript: /<script(?!\\s+setup)/.test(source),\n styleCount: (source.match(/<style/g) || []).length,\n };\n } catch (error) {\n console.error(`Failed to parse ${filePath}:`, error);\n return null;\n }\n}\n","/**\n * CLI command handlers for the Musea VRT tool.\n *\n * Extracted from cli.ts to keep file sizes manageable.\n * Contains the runVrt, runApprove, runClean, and runGenerate command implementations.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nimport { MuseaVrtRunner, generateVrtReport, generateVrtJsonReport } from \"../vrt.js\";\nimport type { VrtSummary } from \"../vrt.js\";\nimport type { ArtFileInfo, VrtOptions } from \"../types/index.js\";\n\nimport type { CliOptions } from \"./index.js\";\n\nexport function hasCiBlockingVrtResult(summary: VrtSummary): boolean {\n return summary.failed > 0 || summary.skipped > 0;\n}\n\nexport async function runVrt(options: CliOptions, artFiles: ArtFileInfo[]): Promise<void> {\n const totalVariants = artFiles.reduce(\n (sum, art) => sum + art.variants.filter((v) => !v.skipVrt).length,\n 0,\n );\n\n console.log(` Testing ${totalVariants} variant(s) across ${artFiles.length} art file(s)\\n`);\n\n // Initialize VRT runner\n const vrtOptions: VrtOptions = {\n snapshotDir: path.join(options.output, \"snapshots\"),\n threshold: options.threshold,\n };\n\n const runner = new MuseaVrtRunner({\n ...vrtOptions,\n ci: options.ci ? { failOnDiff: true, jsonReport: options.json } : undefined,\n });\n\n try {\n console.log(\" Launching browser...\");\n await runner.init();\n\n console.log(\" Running visual regression tests...\\n\");\n\n // Run tests\n const results = await runner.runAllTests(artFiles, options.baseUrl);\n const summary = runner.getSummary(results);\n\n // Print results\n console.log(\" Results:\");\n console.log(\" ---------\");\n console.log(` Passed: ${summary.passed}`);\n console.log(` Failed: ${summary.failed}`);\n console.log(` New: ${summary.new}`);\n console.log(` Skipped: ${summary.skipped}`);\n console.log(` Total: ${summary.total}`);\n console.log(` Duration: ${(summary.duration / 1000).toFixed(2)}s\\n`);\n\n // Run a11y audits if requested\n if (options.a11y) {\n console.log(\" Running accessibility audits...\\n\");\n try {\n const { MuseaA11yRunner } = await import(\"../a11y/index.js\");\n const a11yRunner = new MuseaA11yRunner();\n const a11yResults = await a11yRunner.runAudits(artFiles, options.baseUrl, runner);\n const a11ySummary = a11yRunner.getSummary(a11yResults);\n\n console.log(\" A11y Results:\");\n console.log(\" -------------\");\n console.log(` Components: ${a11ySummary.totalComponents}`);\n console.log(` Variants: ${a11ySummary.totalVariants}`);\n console.log(` Violations: ${a11ySummary.totalViolations}`);\n console.log(` Critical: ${a11ySummary.criticalCount}`);\n console.log(` Serious: ${a11ySummary.seriousCount}\\n`);\n\n // Generate a11y report\n const reportDir = options.output;\n await fs.promises.mkdir(reportDir, { recursive: true });\n\n if (options.json) {\n const a11yJson = a11yRunner.generateJsonReport(a11yResults);\n const a11yPath = path.join(reportDir, \"a11y-report.json\");\n await fs.promises.writeFile(a11yPath, a11yJson);\n console.log(` A11y JSON report: ${a11yPath}\\n`);\n } else {\n const a11yHtml = a11yRunner.generateHtmlReport(a11yResults);\n const a11yPath = path.join(reportDir, \"a11y-report.html\");\n await fs.promises.writeFile(a11yPath, a11yHtml);\n console.log(` A11y HTML report: ${a11yPath}\\n`);\n }\n\n // CI mode - exit with error on critical/serious violations\n if (options.ci && (a11ySummary.criticalCount > 0 || a11ySummary.seriousCount > 0)) {\n console.log(\" CI mode: Accessibility violations found\\n\");\n process.exit(1);\n }\n } catch (e) {\n console.warn(\" A11y audits skipped:\", e instanceof Error ? e.message : String(e));\n console.warn(\" Make sure axe-core is installed: npm install axe-core\\n\");\n }\n }\n\n // Update baselines if requested\n if (options.update) {\n console.log(\" Updating baselines...\");\n const updated = await runner.updateBaselines(results);\n console.log(` Updated ${updated} baseline(s)\\n`);\n }\n\n // Generate VRT report\n const reportDir = options.output;\n await fs.promises.mkdir(reportDir, { recursive: true });\n\n if (options.json) {\n const jsonReport = generateVrtJsonReport(results, summary);\n const jsonPath = path.join(reportDir, \"vrt-report.json\");\n await fs.promises.writeFile(jsonPath, jsonReport);\n console.log(` JSON report: ${jsonPath}\\n`);\n } else {\n const htmlReport = generateVrtReport(results, summary);\n const htmlPath = path.join(reportDir, \"vrt-report.html\");\n await fs.promises.writeFile(htmlPath, htmlReport);\n console.log(` HTML report: ${htmlPath}\\n`);\n }\n\n // CI mode - exit with error if visual diffs or capture/runtime errors occurred.\n if (options.ci && hasCiBlockingVrtResult(summary)) {\n console.log(\" CI mode: Exiting with error due to failures\\n\");\n process.exit(1);\n }\n } finally {\n await runner.close();\n }\n}\n\nexport async function runApprove(options: CliOptions, artFiles: ArtFileInfo[]): Promise<void> {\n const vrtOptions: VrtOptions = {\n snapshotDir: path.join(options.output, \"snapshots\"),\n threshold: options.threshold,\n };\n\n const runner = new MuseaVrtRunner(vrtOptions);\n\n try {\n console.log(\" Launching browser...\");\n await runner.init();\n\n console.log(\" Running tests to find diffs...\\n\");\n\n const results = await runner.runAllTests(artFiles, options.baseUrl);\n const failed = results.filter((r) => !r.passed && !r.error);\n\n if (failed.length === 0) {\n console.log(\" No failed tests to approve.\\n\");\n return;\n }\n\n const pattern = options.pattern;\n if (pattern) {\n console.log(` Approving snapshots matching: ${pattern}\\n`);\n } else {\n console.log(` Approving all ${failed.length} failed snapshot(s)...\\n`);\n }\n\n const approved = await runner.approveResults(results, pattern);\n console.log(` Approved ${approved} snapshot(s)\\n`);\n } finally {\n await runner.close();\n }\n}\n\nexport async function runClean(options: CliOptions, artFiles: ArtFileInfo[]): Promise<void> {\n const vrtOptions: VrtOptions = {\n snapshotDir: path.join(options.output, \"snapshots\"),\n threshold: options.threshold,\n };\n\n const runner = new MuseaVrtRunner(vrtOptions);\n\n console.log(\" Scanning for orphaned snapshots...\\n\");\n\n const cleaned = await runner.cleanOrphans(artFiles);\n\n if (cleaned === 0) {\n console.log(\" No orphaned snapshots found.\\n\");\n } else {\n console.log(`\\n Cleaned ${cleaned} orphaned snapshot(s)\\n`);\n }\n}\n\nexport async function runGenerate(options: CliOptions): Promise<void> {\n if (!options.componentPath) {\n console.error(\" Error: Missing component path.\");\n console.error(\" Usage: musea-vrt generate <component.vue>\\n\");\n process.exit(1);\n }\n\n const componentPath = path.resolve(options.componentPath);\n\n // Check file exists\n try {\n await fs.promises.access(componentPath);\n } catch {\n console.error(` Error: File not found: ${componentPath}\\n`);\n process.exit(1);\n }\n\n console.log(` Generating art file for: ${path.relative(process.cwd(), componentPath)}\\n`);\n\n try {\n const { writeArtFile } = await import(\"../autogen/index.js\");\n const outputPath = await writeArtFile(componentPath);\n const relOutput = path.relative(process.cwd(), outputPath);\n\n console.log(` Generated: ${relOutput}\\n`);\n } catch (e) {\n console.error(\" Generation failed:\", e instanceof Error ? e.message : String(e));\n process.exit(1);\n }\n}\n","#!/usr/bin/env node\n/**\n * Musea CLI\n *\n * Usage:\n * musea-vrt [command] [options]\n *\n * Commands:\n * (default) Run VRT tests\n * approve [pat] Approve failed snapshots (optionally filtered by pattern)\n * clean Remove orphaned snapshots\n *\n * Options:\n * -u, --update Update baseline snapshots\n * -c, --config Path to vite config (default: vite.config.ts)\n * -o, --output Output directory for reports (default: .vize)\n * -t, --threshold Diff threshold percentage (default: 0.1)\n * --json Output JSON report instead of HTML\n * --ci CI mode - exit with non-zero code on failures\n * --a11y Run accessibility audits alongside VRT\n * -h, --help Show help\n */\n\nimport type { ArtFileInfo } from \"../types/index.js\";\nimport { scanArtFiles, parseArtFile } from \"./utils.js\";\nimport { runVrt, runApprove, runClean, runGenerate } from \"./commands.js\";\n\ntype Command = \"run\" | \"approve\" | \"clean\" | \"generate\";\n\nexport interface CliOptions {\n command: Command;\n update: boolean;\n config: string;\n output: string;\n threshold: number;\n json: boolean;\n ci: boolean;\n a11y: boolean;\n help: boolean;\n baseUrl: string;\n pattern?: string;\n componentPath?: string;\n}\n\nfunction parseArgs(args: string[]): CliOptions {\n const options: CliOptions = {\n command: \"run\",\n update: false,\n config: \"vite.config.ts\",\n output: \".vize\",\n threshold: 0.1,\n json: false,\n ci: false,\n a11y: false,\n help: false,\n baseUrl: \"http://localhost:5173\",\n };\n\n let i = 0;\n\n // Check for subcommand as first arg\n if (args.length > 0 && !args[0].startsWith(\"-\")) {\n const sub = args[0];\n if (sub === \"approve\") {\n options.command = \"approve\";\n i = 1;\n // Optional pattern argument after approve\n if (args.length > 1 && !args[1].startsWith(\"-\")) {\n options.pattern = args[1];\n i = 2;\n }\n } else if (sub === \"clean\") {\n options.command = \"clean\";\n i = 1;\n } else if (sub === \"generate\") {\n options.command = \"generate\";\n i = 1;\n // Required component path argument\n if (args.length > 1 && !args[1].startsWith(\"-\")) {\n options.componentPath = args[1];\n i = 2;\n }\n }\n }\n\n for (; i < args.length; i++) {\n const arg = args[i];\n switch (arg) {\n case \"-u\":\n case \"--update\":\n options.update = true;\n break;\n case \"-c\":\n case \"--config\":\n options.config = args[++i] || \"vite.config.ts\";\n break;\n case \"-o\":\n case \"--output\":\n options.output = args[++i] || \".vize\";\n break;\n case \"-t\":\n case \"--threshold\":\n options.threshold = parseFloat(args[++i]) || 0.1;\n break;\n case \"--json\":\n options.json = true;\n break;\n case \"--ci\":\n options.ci = true;\n break;\n case \"--a11y\":\n options.a11y = true;\n break;\n case \"-b\":\n case \"--base-url\":\n options.baseUrl = args[++i] || \"http://localhost:5173\";\n break;\n case \"-h\":\n case \"--help\":\n options.help = true;\n break;\n }\n }\n\n return options;\n}\n\nfunction printHelp(): void {\n console.log(`\nMusea VRT - Visual Regression Testing for Component Gallery\n\nUsage:\n musea-vrt [command] [options]\n\nCommands:\n (default) Run VRT tests\n approve [pattern] Approve failed snapshots and update baselines\n Optional pattern filters which snapshots to approve\n clean Remove orphaned snapshots (no matching art/variant)\n generate <component> Auto-generate .art.vue from a Vue component\n\nOptions:\n -u, --update Update baseline snapshots with current screenshots\n -c, --config <path> Path to vite config file (default: vite.config.ts)\n -o, --output <dir> Output directory for reports (default: .vize)\n -t, --threshold <n> Diff threshold percentage (default: 0.1)\n -b, --base-url <url> Base URL for dev server (default: http://localhost:5173)\n --json Output JSON report instead of HTML\n --ci CI mode - exit with non-zero code on failures\n --a11y Run accessibility audits alongside VRT\n -h, --help Show this help message\n\nExamples:\n # Run VRT tests\n musea-vrt\n\n # Update baseline snapshots\n musea-vrt -u\n\n # Run with custom threshold\n musea-vrt -t 0.5\n\n # CI mode with JSON output\n musea-vrt --ci --json\n\n # Run with accessibility audits\n musea-vrt --a11y\n\n # Approve all failed snapshots\n musea-vrt approve\n\n # Approve specific snapshots by pattern\n musea-vrt approve \"Button/*\"\n\n # Clean orphaned snapshots\n musea-vrt clean\n\n # Auto-generate .art.vue from component\n musea-vrt generate src/components/Button.vue\n\n # Custom base URL\n musea-vrt -b http://localhost:3000\n`);\n}\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n const options = parseArgs(args);\n\n if (options.help) {\n printHelp();\n process.exit(0);\n }\n\n const cwd = process.cwd();\n\n console.log(\"\\n Musea VRT\");\n console.log(\" =========\\n\");\n\n // Handle generate command early (doesn't need art file scanning)\n if (options.command === \"generate\") {\n try {\n await runGenerate(options);\n } catch (error) {\n console.error(\"\\n Error:\", error);\n process.exit(1);\n }\n return;\n }\n\n // Scan for art files\n console.log(\" Scanning for art files...\");\n const artFilePaths = await scanArtFiles(cwd);\n\n if (artFilePaths.length === 0) {\n console.log(\" No art files found.\\n\");\n process.exit(0);\n }\n\n console.log(` Found ${artFilePaths.length} art file(s)\\n`);\n\n // Parse art files\n const artFiles: ArtFileInfo[] = [];\n for (const filePath of artFilePaths) {\n const art = await parseArtFile(filePath);\n if (art) {\n artFiles.push(art);\n }\n }\n\n try {\n switch (options.command) {\n case \"run\":\n await runVrt(options, artFiles);\n break;\n case \"approve\":\n await runApprove(options, artFiles);\n break;\n case \"clean\":\n await runClean(options, artFiles);\n break;\n case \"generate\":\n // Handled above before art file scanning\n break;\n }\n } catch (error) {\n console.error(\"\\n Error:\", error);\n process.exit(1);\n }\n}\n\nmain().catch((error) => {\n console.error(\"Fatal error:\", error);\n process.exit(1);\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/cli/utils.ts","../../src/cli/commands.ts","../../src/cli/index.ts"],"sourcesContent":["/**\n * CLI utility functions for art file scanning and parsing.\n *\n * Extracted from cli.ts to keep file sizes manageable.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nimport type { ArtFileInfo } from \"../types/index.js\";\n\n/** Recursively scan a directory for .art.vue files. */\nexport async function scanArtFiles(root: string): Promise<string[]> {\n const files: string[] = [];\n\n async function scan(dir: string): Promise<void> {\n let entries: fs.Dirent[];\n try {\n entries = await fs.promises.readdir(dir, { withFileTypes: true });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EACCES\") {\n return;\n }\n throw error;\n }\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n // Skip node_modules and dist\n if (entry.name === \"node_modules\" || entry.name === \"dist\") {\n continue;\n }\n\n if (entry.isDirectory()) {\n await scan(fullPath);\n } else if (entry.isFile() && entry.name.endsWith(\".art.vue\")) {\n files.push(fullPath);\n }\n }\n }\n\n await scan(root);\n return files;\n}\n\n/** Parse a single .art.vue file into an ArtFileInfo structure. */\nexport async function parseArtFile(filePath: string): Promise<ArtFileInfo | null> {\n try {\n const source = await fs.promises.readFile(filePath, \"utf-8\");\n\n // Simple parsing - in production, use @vizejs/native\n const titleMatch = source.match(/<art[^>]*\\stitle=[\"']([^\"']+)[\"']/);\n const componentMatch = source.match(/<art[^>]*\\scomponent=[\"']([^\"']+)[\"']/);\n const categoryMatch = source.match(/<art[^>]*\\scategory=[\"']([^\"']+)[\"']/);\n\n const variants: ArtFileInfo[\"variants\"] = [];\n const variantRegex = /<variant\\s+([^>]*)>([\\s\\S]*?)<\\/variant>/g;\n let match;\n\n while ((match = variantRegex.exec(source)) !== null) {\n const attrs = match[1];\n const template = match[2].trim();\n\n const nameMatch = attrs.match(/name=[\"']([^\"']+)[\"']/);\n const isDefault = /\\bdefault\\b/.test(attrs);\n const skipVrt = /\\bskip-vrt\\b/.test(attrs);\n\n if (nameMatch) {\n variants.push({\n name: nameMatch[1],\n template,\n isDefault,\n skipVrt,\n });\n }\n }\n\n return {\n path: filePath,\n metadata: {\n title: titleMatch?.[1] || path.basename(filePath, \".art.vue\"),\n component: componentMatch?.[1],\n category: categoryMatch?.[1],\n tags: [],\n status: \"ready\",\n },\n variants,\n hasScriptSetup: /<script\\s+setup/.test(source),\n hasScript: /<script(?!\\s+setup)/.test(source),\n styleCount: (source.match(/<style/g) || []).length,\n };\n } catch (error) {\n console.error(`Failed to parse ${filePath}:`, error);\n return null;\n }\n}\n","/**\n * CLI command handlers for the Musea VRT tool.\n *\n * Extracted from cli.ts to keep file sizes manageable.\n * Contains the runVrt, runApprove, runClean, and runGenerate command implementations.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nimport { MuseaVrtRunner, generateVrtReport, generateVrtJsonReport } from \"../vrt.js\";\nimport type { VrtSummary } from \"../vrt.js\";\nimport type { ArtFileInfo, VrtOptions } from \"../types/index.js\";\n\nimport type { CliOptions } from \"./index.js\";\n\nexport function hasCiBlockingVrtResult(summary: VrtSummary): boolean {\n return summary.failed > 0 || summary.skipped > 0;\n}\n\nexport function isArtFileInput(filePath: string): boolean {\n return filePath.endsWith(\".art.vue\");\n}\n\nexport async function runVrt(options: CliOptions, artFiles: ArtFileInfo[]): Promise<void> {\n const totalVariants = artFiles.reduce(\n (sum, art) => sum + art.variants.filter((v) => !v.skipVrt).length,\n 0,\n );\n\n console.log(` Testing ${totalVariants} variant(s) across ${artFiles.length} art file(s)\\n`);\n\n // Initialize VRT runner\n const vrtOptions: VrtOptions = {\n snapshotDir: path.join(options.output, \"snapshots\"),\n threshold: options.threshold,\n };\n\n const runner = new MuseaVrtRunner({\n ...vrtOptions,\n ci: options.ci ? { failOnDiff: true, jsonReport: options.json } : undefined,\n });\n\n try {\n console.log(\" Launching browser...\");\n await runner.init();\n\n console.log(\" Running visual regression tests...\\n\");\n\n // Run tests\n const results = await runner.runAllTests(artFiles, options.baseUrl);\n const summary = runner.getSummary(results);\n\n // Print results\n console.log(\" Results:\");\n console.log(\" ---------\");\n console.log(` Passed: ${summary.passed}`);\n console.log(` Failed: ${summary.failed}`);\n console.log(` New: ${summary.new}`);\n console.log(` Skipped: ${summary.skipped}`);\n console.log(` Total: ${summary.total}`);\n console.log(` Duration: ${(summary.duration / 1000).toFixed(2)}s\\n`);\n\n // Run a11y audits if requested\n if (options.a11y) {\n console.log(\" Running accessibility audits...\\n\");\n try {\n const { MuseaA11yRunner } = await import(\"../a11y/index.js\");\n const a11yRunner = new MuseaA11yRunner();\n const a11yResults = await a11yRunner.runAudits(artFiles, options.baseUrl, runner);\n const a11ySummary = a11yRunner.getSummary(a11yResults);\n\n console.log(\" A11y Results:\");\n console.log(\" -------------\");\n console.log(` Components: ${a11ySummary.totalComponents}`);\n console.log(` Variants: ${a11ySummary.totalVariants}`);\n console.log(` Violations: ${a11ySummary.totalViolations}`);\n console.log(` Critical: ${a11ySummary.criticalCount}`);\n console.log(` Serious: ${a11ySummary.seriousCount}\\n`);\n\n // Generate a11y report\n const reportDir = options.output;\n await fs.promises.mkdir(reportDir, { recursive: true });\n\n if (options.json) {\n const a11yJson = a11yRunner.generateJsonReport(a11yResults);\n const a11yPath = path.join(reportDir, \"a11y-report.json\");\n await fs.promises.writeFile(a11yPath, a11yJson);\n console.log(` A11y JSON report: ${a11yPath}\\n`);\n } else {\n const a11yHtml = a11yRunner.generateHtmlReport(a11yResults);\n const a11yPath = path.join(reportDir, \"a11y-report.html\");\n await fs.promises.writeFile(a11yPath, a11yHtml);\n console.log(` A11y HTML report: ${a11yPath}\\n`);\n }\n\n // CI mode - exit with error on critical/serious violations\n if (options.ci && (a11ySummary.criticalCount > 0 || a11ySummary.seriousCount > 0)) {\n console.log(\" CI mode: Accessibility violations found\\n\");\n process.exit(1);\n }\n } catch (e) {\n console.warn(\" A11y audits skipped:\", e instanceof Error ? e.message : String(e));\n console.warn(\" Make sure axe-core is installed: npm install axe-core\\n\");\n }\n }\n\n // Update baselines if requested\n if (options.update) {\n console.log(\" Updating baselines...\");\n const updated = await runner.updateBaselines(results);\n console.log(` Updated ${updated} baseline(s)\\n`);\n }\n\n // Generate VRT report\n const reportDir = options.output;\n await fs.promises.mkdir(reportDir, { recursive: true });\n\n if (options.json) {\n const jsonReport = generateVrtJsonReport(results, summary);\n const jsonPath = path.join(reportDir, \"vrt-report.json\");\n await fs.promises.writeFile(jsonPath, jsonReport);\n console.log(` JSON report: ${jsonPath}\\n`);\n } else {\n const htmlReport = generateVrtReport(results, summary);\n const htmlPath = path.join(reportDir, \"vrt-report.html\");\n await fs.promises.writeFile(htmlPath, htmlReport);\n console.log(` HTML report: ${htmlPath}\\n`);\n }\n\n // CI mode - exit with error if visual diffs or capture/runtime errors occurred.\n if (options.ci && hasCiBlockingVrtResult(summary)) {\n console.log(\" CI mode: Exiting with error due to failures\\n\");\n process.exit(1);\n }\n } finally {\n await runner.close();\n }\n}\n\nexport async function runApprove(options: CliOptions, artFiles: ArtFileInfo[]): Promise<void> {\n const vrtOptions: VrtOptions = {\n snapshotDir: path.join(options.output, \"snapshots\"),\n threshold: options.threshold,\n };\n\n const runner = new MuseaVrtRunner(vrtOptions);\n\n try {\n console.log(\" Launching browser...\");\n await runner.init();\n\n console.log(\" Running tests to find diffs...\\n\");\n\n const results = await runner.runAllTests(artFiles, options.baseUrl);\n const failed = results.filter((r) => !r.passed && !r.error);\n\n if (failed.length === 0) {\n console.log(\" No failed tests to approve.\\n\");\n return;\n }\n\n const pattern = options.pattern;\n if (pattern) {\n console.log(` Approving snapshots matching: ${pattern}\\n`);\n } else {\n console.log(` Approving all ${failed.length} failed snapshot(s)...\\n`);\n }\n\n const approved = await runner.approveResults(results, pattern);\n console.log(` Approved ${approved} snapshot(s)\\n`);\n } finally {\n await runner.close();\n }\n}\n\nexport async function runClean(options: CliOptions, artFiles: ArtFileInfo[]): Promise<void> {\n const vrtOptions: VrtOptions = {\n snapshotDir: path.join(options.output, \"snapshots\"),\n threshold: options.threshold,\n };\n\n const runner = new MuseaVrtRunner(vrtOptions);\n\n console.log(\" Scanning for orphaned snapshots...\\n\");\n\n const cleaned = await runner.cleanOrphans(artFiles);\n\n if (cleaned === 0) {\n console.log(\" No orphaned snapshots found.\\n\");\n } else {\n console.log(`\\n Cleaned ${cleaned} orphaned snapshot(s)\\n`);\n }\n}\n\nexport async function runGenerate(options: CliOptions): Promise<void> {\n if (!options.componentPath) {\n console.error(\" Error: Missing component path.\");\n console.error(\" Usage: musea-vrt generate <component.vue>\\n\");\n process.exit(1);\n }\n\n const componentPath = path.resolve(options.componentPath);\n if (isArtFileInput(componentPath)) {\n console.error(\n \" Error: musea-vrt generate expects a source .vue component, not a .art.vue file.\",\n );\n console.error(\" Pass the component file that the art file should wrap.\\n\");\n process.exit(1);\n }\n\n // Check file exists\n try {\n await fs.promises.access(componentPath);\n } catch {\n console.error(` Error: File not found: ${componentPath}\\n`);\n process.exit(1);\n }\n\n console.log(` Generating art file for: ${path.relative(process.cwd(), componentPath)}\\n`);\n\n try {\n const { writeArtFile } = await import(\"../autogen/index.js\");\n const outputPath = await writeArtFile(componentPath);\n const relOutput = path.relative(process.cwd(), outputPath);\n\n console.log(` Generated: ${relOutput}\\n`);\n } catch (e) {\n console.error(\" Generation failed:\", e instanceof Error ? e.message : String(e));\n process.exit(1);\n }\n}\n","#!/usr/bin/env node\n/**\n * Musea CLI\n *\n * Usage:\n * musea-vrt [command] [options]\n *\n * Commands:\n * (default) Run VRT tests\n * approve [pat] Approve failed snapshots (optionally filtered by pattern)\n * clean Remove orphaned snapshots\n *\n * Options:\n * -u, --update Update baseline snapshots\n * -c, --config Path to vite config (default: vite.config.ts)\n * -o, --output Output directory for reports (default: .vize)\n * -t, --threshold Diff threshold percentage (default: 0.1)\n * --json Output JSON report instead of HTML\n * --ci CI mode - exit with non-zero code on failures\n * --a11y Run accessibility audits alongside VRT\n * -h, --help Show help\n */\n\nimport type { ArtFileInfo } from \"../types/index.js\";\nimport { scanArtFiles, parseArtFile } from \"./utils.js\";\nimport { runVrt, runApprove, runClean, runGenerate } from \"./commands.js\";\n\ntype Command = \"run\" | \"approve\" | \"clean\" | \"generate\";\n\nexport interface CliOptions {\n command: Command;\n update: boolean;\n config: string;\n output: string;\n threshold: number;\n json: boolean;\n ci: boolean;\n a11y: boolean;\n help: boolean;\n baseUrl: string;\n pattern?: string;\n componentPath?: string;\n}\n\nfunction parseArgs(args: string[]): CliOptions {\n const options: CliOptions = {\n command: \"run\",\n update: false,\n config: \"vite.config.ts\",\n output: \".vize\",\n threshold: 0.1,\n json: false,\n ci: false,\n a11y: false,\n help: false,\n baseUrl: \"http://localhost:5173\",\n };\n\n let i = 0;\n\n // Check for subcommand as first arg\n if (args.length > 0 && !args[0].startsWith(\"-\")) {\n const sub = args[0];\n if (sub === \"approve\") {\n options.command = \"approve\";\n i = 1;\n // Optional pattern argument after approve\n if (args.length > 1 && !args[1].startsWith(\"-\")) {\n options.pattern = args[1];\n i = 2;\n }\n } else if (sub === \"clean\") {\n options.command = \"clean\";\n i = 1;\n } else if (sub === \"generate\") {\n options.command = \"generate\";\n i = 1;\n // Required component path argument\n if (args.length > 1 && !args[1].startsWith(\"-\")) {\n options.componentPath = args[1];\n i = 2;\n }\n }\n }\n\n for (; i < args.length; i++) {\n const arg = args[i];\n switch (arg) {\n case \"-u\":\n case \"--update\":\n options.update = true;\n break;\n case \"-c\":\n case \"--config\":\n options.config = args[++i] || \"vite.config.ts\";\n break;\n case \"-o\":\n case \"--output\":\n options.output = args[++i] || \".vize\";\n break;\n case \"-t\":\n case \"--threshold\":\n options.threshold = parseFloat(args[++i]) || 0.1;\n break;\n case \"--json\":\n options.json = true;\n break;\n case \"--ci\":\n options.ci = true;\n break;\n case \"--a11y\":\n options.a11y = true;\n break;\n case \"-b\":\n case \"--base-url\":\n options.baseUrl = args[++i] || \"http://localhost:5173\";\n break;\n case \"-h\":\n case \"--help\":\n options.help = true;\n break;\n }\n }\n\n return options;\n}\n\nfunction printHelp(): void {\n console.log(`\nMusea VRT - Visual Regression Testing for Component Gallery\n\nUsage:\n musea-vrt [command] [options]\n\nCommands:\n (default) Run VRT tests\n approve [pattern] Approve failed snapshots and update baselines\n Optional pattern filters which snapshots to approve\n clean Remove orphaned snapshots (no matching art/variant)\n generate <component> Auto-generate .art.vue from a Vue component\n\nOptions:\n -u, --update Update baseline snapshots with current screenshots\n -c, --config <path> Path to vite config file (default: vite.config.ts)\n -o, --output <dir> Output directory for reports (default: .vize)\n -t, --threshold <n> Diff threshold percentage (default: 0.1)\n -b, --base-url <url> Base URL for dev server (default: http://localhost:5173)\n --json Output JSON report instead of HTML\n --ci CI mode - exit with non-zero code on failures\n --a11y Run accessibility audits alongside VRT\n -h, --help Show this help message\n\nExamples:\n # Run VRT tests\n musea-vrt\n\n # Update baseline snapshots\n musea-vrt -u\n\n # Run with custom threshold\n musea-vrt -t 0.5\n\n # CI mode with JSON output\n musea-vrt --ci --json\n\n # Run with accessibility audits\n musea-vrt --a11y\n\n # Approve all failed snapshots\n musea-vrt approve\n\n # Approve specific snapshots by pattern\n musea-vrt approve \"Button/*\"\n\n # Clean orphaned snapshots\n musea-vrt clean\n\n # Auto-generate .art.vue from component\n musea-vrt generate src/components/Button.vue\n\n # Custom base URL\n musea-vrt -b http://localhost:3000\n`);\n}\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n const options = parseArgs(args);\n\n if (options.help) {\n printHelp();\n process.exit(0);\n }\n\n const cwd = process.cwd();\n\n console.log(\"\\n Musea VRT\");\n console.log(\" =========\\n\");\n\n // Handle generate command early (doesn't need art file scanning)\n if (options.command === \"generate\") {\n try {\n await runGenerate(options);\n } catch (error) {\n console.error(\"\\n Error:\", error);\n process.exit(1);\n }\n return;\n }\n\n // Scan for art files\n console.log(\" Scanning for art files...\");\n const artFilePaths = await scanArtFiles(cwd);\n\n if (artFilePaths.length === 0) {\n console.log(\" No art files found.\\n\");\n process.exit(0);\n }\n\n console.log(` Found ${artFilePaths.length} art file(s)\\n`);\n\n // Parse art files\n const artFiles: ArtFileInfo[] = [];\n for (const filePath of artFilePaths) {\n const art = await parseArtFile(filePath);\n if (art) {\n artFiles.push(art);\n }\n }\n\n try {\n switch (options.command) {\n case \"run\":\n await runVrt(options, artFiles);\n break;\n case \"approve\":\n await runApprove(options, artFiles);\n break;\n case \"clean\":\n await runClean(options, artFiles);\n break;\n case \"generate\":\n // Handled above before art file scanning\n break;\n }\n } catch (error) {\n console.error(\"\\n Error:\", error);\n process.exit(1);\n }\n}\n\nmain().catch((error) => {\n console.error(\"Fatal error:\", error);\n process.exit(1);\n});\n"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -4,6 +4,7 @@ import { AutogenOptions, AutogenOutput, GeneratedVariant, PropDefinition, genera
|
|
|
4
4
|
import { Plugin } from "vite";
|
|
5
5
|
|
|
6
6
|
//#region src/types/plugin.d.ts
|
|
7
|
+
type MuseaVueVersion = 0.11 | 1 | 2 | "2.7" | 3 | "legacy";
|
|
7
8
|
/**
|
|
8
9
|
* Theme color definitions for Musea gallery UI.
|
|
9
10
|
* All properties are optional — unspecified colors inherit from the `base` built-in theme.
|
|
@@ -125,6 +126,12 @@ interface MuseaOptions {
|
|
|
125
126
|
* @example 'musea.preview.ts'
|
|
126
127
|
*/
|
|
127
128
|
previewSetup?: string;
|
|
129
|
+
/**
|
|
130
|
+
* Host Vue version for preview runtime compatibility checks.
|
|
131
|
+
* Legacy Vue static builds currently fail fast with an actionable diagnostic.
|
|
132
|
+
* @default 3
|
|
133
|
+
*/
|
|
134
|
+
vueVersion?: MuseaVueVersion;
|
|
128
135
|
}
|
|
129
136
|
//#endregion
|
|
130
137
|
//#region src/plugin/index.d.ts
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/plugin.ts","../src/plugin/index.ts","../src/tokens/parser.ts","../src/tokens/usage.ts","../src/tokens/resolver.ts","../src/tokens/generator.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/plugin.ts","../src/plugin/index.ts","../src/tokens/parser.ts","../src/tokens/usage.ts","../src/tokens/resolver.ts","../src/tokens/generator.ts"],"mappings":";;;;;;KAEY,eAAA;;;;;UAMK,gBAAA;EACf,SAAA;EACA,WAAA;EACA,UAAA;EACA,UAAA;EACA,MAAA;EACA,WAAA;EACA,cAAA;EACA,YAAA;EACA,IAAA;EACA,aAAA;EACA,SAAA;EACA,MAAA;EACA,YAAA;EACA,OAAA;EACA,KAAA;EACA,IAAA;EACA,OAAA;EACA,MAAA;AAAA;;;;UAMe,UAAA;EARf;EAUA,IAAA;EARA;EAUA,IAAA;EAVM;EAYN,MAAA,EAAQ,gBAAA;AAAA;;;;UAMO,YAAA;EANf;;;;EAWA,OAAA;EAL2B;;;;EAW3B,OAAA;EAyFa;;;;EAnFb,QAAA;EAAA;;;;EAMA,eAAA;EAmBM;;;;EAbN,eAAA;EA0CmD;;;;;;EAlCnD,SAAA;;;;EAKA,GAAA,GAAM,UAAA;EC3Ca;;;;;EDkDnB,UAAA;EClDuD;;;;;AC/BzD;;;;;EF6FE,WAAA;EE1FA;;;;;;;;EFoGA,KAAA,iCAAsC,UAAA,GAAa,UAAA;EE1FvB;;;;;;;;EFoG5B,UAAA;EElGQ;;;;;;AAOV;;;;EFuGE,YAAA;EEtGY;;;;;EF6GZ,UAAA,GAAa,eAAA;AAAA;;;iBCrGC,KAAA,CAAM,OAAA,GAAS,YAAA,GAAoB,MAAA;;;;;;;;;ADzCnD;;UEUiB,WAAA;EACf,KAAA;EACA,IAAA;EACA,WAAA;EACA,UAAA,GAAa,MAAA;EACb,KAAA;EACA,UAAA;EACA,cAAA;AAAA;;;;UAMe,aAAA;EACf,IAAA;EACA,MAAA,EAAQ,MAAA,SAAe,WAAA;EACvB,aAAA,GAAgB,aAAA;AAAA;;;;UAMD,qBAAA;EACf,UAAA,EAAY,aAAA;EACZ,QAAA;IACE,IAAA;IACA,OAAA;IACA,WAAA;EAAA;AAAA;;;;UAOa,qBAAA;EFVf;;;EEcA,UAAA;EFZwB;AAM1B;;;EEYE,YAAA;EF2DsC;;;;EErDtC,SAAA;EFbA;;;EEkBA,UAAA,GAAa,cAAA;AAAA;;;;KAMH,cAAA,IAAkB,KAAA,EAAO,WAAA,EAAa,IAAA,eAAmB,WAAA;;;;iBAK/C,WAAA,CAAY,UAAA,WAAqB,OAAA,CAAQ,aAAA;;;;;;iBCtC/C,cAAA,CACd,QAAA,EAAU,GAAA;EAAc,IAAA;EAAc,QAAA;IAAY,KAAA;IAAe,QAAA;EAAA;AAAA,IACjE,QAAA,EAAU,MAAA,SAAe,WAAA,IACxB,aAAA;;;;;;UCtBc,eAAA;EACf,IAAA;EACA,WAAA;EACA,QAAA;AAAA;;;;UAMe,eAAA;EACf,OAAA;EACA,QAAA;EACA,WAAA;EACA,OAAA,EAAS,eAAA;AAAA;;;;KAMC,aAAA,GAAgB,MAAA,SAAe,eAAA;;;;iBAqB3B,aAAA,CAAc,UAAA,EAAY,aAAA,KAAkB,MAAA,SAAe,WAAA;;;AJ7B3E;iBIoCgB,iBAAA,CACd,UAAA,EAAY,aAAA,IACZ,SAAA,EAAW,MAAA,SAAe,WAAA;;;;;;iBC/BZ,kBAAA,CAAmB,UAAA,EAAY,aAAA;AL/B/C;;;AAAA,iBK+JgB,sBAAA,CAAuB,UAAA,EAAY,aAAA;;;;;iBAQ7B,sBAAA,CACpB,MAAA,EAAQ,qBAAA,GACP,OAAA,CAAQ,qBAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -3,12 +3,148 @@ import { i as MuseaVrtRunner, n as generateVrtJsonReport, r as generateVrtReport
|
|
|
3
3
|
import { t as MuseaA11yRunner } from "./a11y-62l8G1tr.mjs";
|
|
4
4
|
import { n as writeArtFile, t as generateArtFile } from "./autogen-B7_TO0n5.mjs";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
|
-
import { transformWithEsbuild } from "vite";
|
|
7
6
|
import fs from "node:fs";
|
|
8
7
|
import path from "node:path";
|
|
9
8
|
import { fileURLToPath } from "node:url";
|
|
10
9
|
import crypto from "node:crypto";
|
|
11
10
|
import { VIZE_CONFIG_FILE_ENV, loadConfig, vizeConfigStore } from "@vizejs/vite-plugin";
|
|
11
|
+
import * as vite from "vite";
|
|
12
|
+
//#region src/with-defaults.ts
|
|
13
|
+
/**
|
|
14
|
+
* Parsing helpers for extracting prop defaults from a Vue SFC `<script setup>`
|
|
15
|
+
* block. Defaults are read only from `withDefaults(defineProps(...), { ... })`
|
|
16
|
+
* so unrelated local identifiers are never treated as prop defaults.
|
|
17
|
+
*/
|
|
18
|
+
function extractWithDefaults(scriptContent) {
|
|
19
|
+
const defaults = /* @__PURE__ */ new Map();
|
|
20
|
+
let searchIndex = 0;
|
|
21
|
+
while (searchIndex < scriptContent.length) {
|
|
22
|
+
const calleeIndex = scriptContent.indexOf("withDefaults", searchIndex);
|
|
23
|
+
if (calleeIndex === -1) break;
|
|
24
|
+
searchIndex = calleeIndex + 12;
|
|
25
|
+
if (!isIdentifierBoundary(scriptContent[calleeIndex - 1])) continue;
|
|
26
|
+
if (!isIdentifierBoundary(scriptContent[searchIndex])) continue;
|
|
27
|
+
const parenIndex = skipWhitespace(scriptContent, searchIndex);
|
|
28
|
+
if (scriptContent[parenIndex] !== "(") continue;
|
|
29
|
+
const endParen = findMatching(scriptContent, parenIndex, "(", ")");
|
|
30
|
+
if (endParen === -1) continue;
|
|
31
|
+
const defaultsArg = splitTopLevel(scriptContent.slice(parenIndex + 1, endParen))[1]?.trim();
|
|
32
|
+
if (!defaultsArg?.startsWith("{")) continue;
|
|
33
|
+
const objectStart = scriptContent.indexOf(defaultsArg, parenIndex + 1);
|
|
34
|
+
const objectEnd = findMatching(scriptContent, objectStart, "{", "}");
|
|
35
|
+
if (objectEnd === -1) continue;
|
|
36
|
+
for (const [name, value] of objectProperties(scriptContent.slice(objectStart + 1, objectEnd))) defaults.set(name, value);
|
|
37
|
+
}
|
|
38
|
+
return defaults;
|
|
39
|
+
}
|
|
40
|
+
function objectProperties(objectBody) {
|
|
41
|
+
const properties = [];
|
|
42
|
+
for (const item of splitTopLevel(objectBody)) {
|
|
43
|
+
const colonIndex = topLevelColon(item);
|
|
44
|
+
if (colonIndex === -1) continue;
|
|
45
|
+
const rawKey = item.slice(0, colonIndex).trim();
|
|
46
|
+
const key = rawKey.match(/^[$A-Z_a-z][$\w]*$/)?.[0] ?? rawKey.match(/^["']([^"']+)["']$/)?.[1];
|
|
47
|
+
if (!key) continue;
|
|
48
|
+
const value = item.slice(colonIndex + 1).trim();
|
|
49
|
+
if (value) properties.push([key, value]);
|
|
50
|
+
}
|
|
51
|
+
return properties;
|
|
52
|
+
}
|
|
53
|
+
function splitTopLevel(source) {
|
|
54
|
+
const parts = [];
|
|
55
|
+
let start = 0;
|
|
56
|
+
let round = 0;
|
|
57
|
+
let curly = 0;
|
|
58
|
+
let square = 0;
|
|
59
|
+
let quote = null;
|
|
60
|
+
let escaped = false;
|
|
61
|
+
for (let index = 0; index < source.length; index++) {
|
|
62
|
+
const char = source[index];
|
|
63
|
+
if (quote) {
|
|
64
|
+
if (escaped) escaped = false;
|
|
65
|
+
else if (char === "\\") escaped = true;
|
|
66
|
+
else if (char === quote) quote = null;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (char === "\"" || char === "'" || char === "`") {
|
|
70
|
+
quote = char;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (char === "(") round++;
|
|
74
|
+
else if (char === ")") round--;
|
|
75
|
+
else if (char === "{") curly++;
|
|
76
|
+
else if (char === "}") curly--;
|
|
77
|
+
else if (char === "[") square++;
|
|
78
|
+
else if (char === "]") square--;
|
|
79
|
+
else if (char === "," && round === 0 && curly === 0 && square === 0) {
|
|
80
|
+
parts.push(source.slice(start, index).trim());
|
|
81
|
+
start = index + 1;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const tail = source.slice(start).trim();
|
|
85
|
+
if (tail) parts.push(tail);
|
|
86
|
+
return parts;
|
|
87
|
+
}
|
|
88
|
+
function topLevelColon(source) {
|
|
89
|
+
let round = 0;
|
|
90
|
+
let curly = 0;
|
|
91
|
+
let square = 0;
|
|
92
|
+
let quote = null;
|
|
93
|
+
let escaped = false;
|
|
94
|
+
for (let index = 0; index < source.length; index++) {
|
|
95
|
+
const char = source[index];
|
|
96
|
+
if (quote) {
|
|
97
|
+
if (escaped) escaped = false;
|
|
98
|
+
else if (char === "\\") escaped = true;
|
|
99
|
+
else if (char === quote) quote = null;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (char === "\"" || char === "'" || char === "`") {
|
|
103
|
+
quote = char;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (char === "(") round++;
|
|
107
|
+
else if (char === ")") round--;
|
|
108
|
+
else if (char === "{") curly++;
|
|
109
|
+
else if (char === "}") curly--;
|
|
110
|
+
else if (char === "[") square++;
|
|
111
|
+
else if (char === "]") square--;
|
|
112
|
+
else if (char === ":" && round === 0 && curly === 0 && square === 0) return index;
|
|
113
|
+
}
|
|
114
|
+
return -1;
|
|
115
|
+
}
|
|
116
|
+
function findMatching(source, start, open, close) {
|
|
117
|
+
let depth = 0;
|
|
118
|
+
let quote = null;
|
|
119
|
+
let escaped = false;
|
|
120
|
+
for (let index = start; index < source.length; index++) {
|
|
121
|
+
const char = source[index];
|
|
122
|
+
if (quote) {
|
|
123
|
+
if (escaped) escaped = false;
|
|
124
|
+
else if (char === "\\") escaped = true;
|
|
125
|
+
else if (char === quote) quote = null;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (char === "\"" || char === "'" || char === "`") {
|
|
129
|
+
quote = char;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (char === open) depth++;
|
|
133
|
+
if (char === close) {
|
|
134
|
+
depth--;
|
|
135
|
+
if (depth === 0) return index;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return -1;
|
|
139
|
+
}
|
|
140
|
+
function skipWhitespace(source, index) {
|
|
141
|
+
while (index < source.length && /\s/.test(source[index])) index++;
|
|
142
|
+
return index;
|
|
143
|
+
}
|
|
144
|
+
function isIdentifierBoundary(char) {
|
|
145
|
+
return char === void 0 || !/[$\w]/.test(char);
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
12
148
|
//#region src/native-loader.ts
|
|
13
149
|
/**
|
|
14
150
|
* Native binding loader for @vizejs/native.
|
|
@@ -46,6 +182,7 @@ function analyzeSfcFallback(source, _options) {
|
|
|
46
182
|
const propsMatch = scriptContent.match(/defineProps\s*<\s*\{([\s\S]*?)\}>\s*\(/);
|
|
47
183
|
const propsMatch2 = scriptContent.match(/defineProps\s*<\s*\{([\s\S]*?)\}>/);
|
|
48
184
|
const propsBody = propsMatch?.[1] || propsMatch2?.[1];
|
|
185
|
+
const withDefaults = extractWithDefaults(scriptContent);
|
|
49
186
|
if (propsBody) {
|
|
50
187
|
const lines = propsBody.split("\n");
|
|
51
188
|
let i = 0;
|
|
@@ -60,9 +197,7 @@ function analyzeSfcFallback(source, _options) {
|
|
|
60
197
|
const name = propMatch[1];
|
|
61
198
|
const optional = !!propMatch[2];
|
|
62
199
|
let type = propMatch[3].replace(/;$/, "").trim();
|
|
63
|
-
const
|
|
64
|
-
const defaultMatch = scriptContent.match(defaultPattern);
|
|
65
|
-
const defaultValue = defaultMatch ? defaultMatch[1].trim() : void 0;
|
|
200
|
+
const defaultValue = withDefaults.get(name);
|
|
66
201
|
props.push({
|
|
67
202
|
name,
|
|
68
203
|
type,
|
|
@@ -3450,6 +3585,43 @@ async function processMuseaArtFile(filePath, ctx) {
|
|
|
3450
3585
|
}
|
|
3451
3586
|
}
|
|
3452
3587
|
//#endregion
|
|
3588
|
+
//#region src/plugin/virtual-transform.ts
|
|
3589
|
+
function createMuseaVirtualTransformer(viteApi) {
|
|
3590
|
+
return async (code, id, sourcemap) => {
|
|
3591
|
+
if (typeof viteApi.transformWithOxc === "function") return viteApi.transformWithOxc(code, id, {
|
|
3592
|
+
lang: "ts",
|
|
3593
|
+
sourcemap,
|
|
3594
|
+
target: "esnext"
|
|
3595
|
+
});
|
|
3596
|
+
if (typeof viteApi.transformWithEsbuild === "function") return viteApi.transformWithEsbuild(code, id, {
|
|
3597
|
+
loader: "ts",
|
|
3598
|
+
format: "esm",
|
|
3599
|
+
sourcemap,
|
|
3600
|
+
target: "esnext"
|
|
3601
|
+
});
|
|
3602
|
+
throw new Error("Installed Vite does not expose transformWithOxc or transformWithEsbuild");
|
|
3603
|
+
};
|
|
3604
|
+
}
|
|
3605
|
+
const transformMuseaVirtualModule = createMuseaVirtualTransformer(vite);
|
|
3606
|
+
//#endregion
|
|
3607
|
+
//#region src/plugin/static-preview.ts
|
|
3608
|
+
function resolveStaticPreviewVueVersion(configured, plugins) {
|
|
3609
|
+
if (configured !== void 0) return configured;
|
|
3610
|
+
if (hasLegacyVueSfcCompilerPlugin(plugins)) return 2;
|
|
3611
|
+
return 3;
|
|
3612
|
+
}
|
|
3613
|
+
function assertStaticPreviewRuntimeSupported(vueVersion, staticBuildEnabled) {
|
|
3614
|
+
if (!staticBuildEnabled) return;
|
|
3615
|
+
if (vueVersion === 3 || vueVersion === void 0) return;
|
|
3616
|
+
throw new Error("[musea] Static Musea builds currently require the Vue 3 preview runtime. Vue 2/Nuxt 2 projects should use the dev gallery or run Nuxt static generation with @vizejs/nuxt until a Vue 2 static preview runtime is available.");
|
|
3617
|
+
}
|
|
3618
|
+
function hasLegacyVueSfcCompilerPlugin(plugins) {
|
|
3619
|
+
return plugins.some((plugin) => {
|
|
3620
|
+
const name = plugin.name ?? "";
|
|
3621
|
+
return name === "vite:vue2" || name.includes("plugin-vue2") || name.includes("vue2");
|
|
3622
|
+
});
|
|
3623
|
+
}
|
|
3624
|
+
//#endregion
|
|
3453
3625
|
//#region src/plugin/index.ts
|
|
3454
3626
|
function musea(options = {}) {
|
|
3455
3627
|
let include = options.include ?? ["**/*.art.vue"];
|
|
@@ -3463,6 +3635,7 @@ function musea(options = {}) {
|
|
|
3463
3635
|
const themeConfig = buildThemeConfig(options.theme);
|
|
3464
3636
|
const previewCss = options.previewCss ?? [];
|
|
3465
3637
|
const previewSetup = options.previewSetup;
|
|
3638
|
+
let vueVersion = options.vueVersion;
|
|
3466
3639
|
const devSessionToken = createDevSessionToken();
|
|
3467
3640
|
let config;
|
|
3468
3641
|
let server = null;
|
|
@@ -3512,6 +3685,7 @@ function musea(options = {}) {
|
|
|
3512
3685
|
if (options.storybookCompat === void 0 && mc.storybookCompat !== void 0) storybookCompat = mc.storybookCompat;
|
|
3513
3686
|
if (options.inlineArt === void 0 && mc.inlineArt !== void 0) inlineArt = mc.inlineArt;
|
|
3514
3687
|
}
|
|
3688
|
+
vueVersion = resolveStaticPreviewVueVersion(vueVersion, resolvedConfig.plugins);
|
|
3515
3689
|
virtualState.basePath = basePath;
|
|
3516
3690
|
resolvedPreviewCss = previewCss.map((cssPath) => path.isAbsolute(cssPath) ? cssPath : path.resolve(resolvedConfig.root, cssPath));
|
|
3517
3691
|
if (previewSetup) resolvedPreviewSetup = path.isAbsolute(previewSetup) ? previewSetup : path.resolve(resolvedConfig.root, previewSetup);
|
|
@@ -3597,6 +3771,7 @@ function musea(options = {}) {
|
|
|
3597
3771
|
},
|
|
3598
3772
|
async buildStart() {
|
|
3599
3773
|
console.log(`[musea] config.root: ${config.root}, include: ${JSON.stringify(include)}`);
|
|
3774
|
+
assertStaticPreviewRuntimeSupported(vueVersion, staticBuildEnabled);
|
|
3600
3775
|
if (storybookCompat && staticBuildEnabled) await assertNoUnsupportedStorybookTsxInputs(config.root, include, exclude);
|
|
3601
3776
|
const files = await scanArtFiles(config.root, include, exclude, inlineArt);
|
|
3602
3777
|
console.log(`[musea] Found ${files.length} art files`);
|
|
@@ -3629,12 +3804,7 @@ function musea(options = {}) {
|
|
|
3629
3804
|
if (!id.includes("?musea-virtual")) return null;
|
|
3630
3805
|
if (!id.includes("musea-art:") && !id.includes("\0musea:")) return null;
|
|
3631
3806
|
const safeId = id.replaceAll("\0", "").replace(/[^\w./-]+/g, "_").replace(/_+/g, "_");
|
|
3632
|
-
return
|
|
3633
|
-
loader: "ts",
|
|
3634
|
-
format: "esm",
|
|
3635
|
-
sourcemap: config.command === "serve",
|
|
3636
|
-
target: "esnext"
|
|
3637
|
-
});
|
|
3807
|
+
return transformMuseaVirtualModule(code, path.join(config.root, `.musea-${safeId}.ts`), config.command === "serve");
|
|
3638
3808
|
},
|
|
3639
3809
|
handleHotUpdate: createHandleHotUpdate(virtualState)
|
|
3640
3810
|
};
|