@vizejs/vite-plugin-musea 0.391.0 → 0.404.9
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/a11y/index.d.mts +2 -2
- package/dist/a11y/index.mjs +2 -2
- package/dist/{a11y-Cht-W4kd.mjs → a11y-Ci9EEv6F.mjs} +43 -23
- package/dist/a11y-Ci9EEv6F.mjs.map +1 -0
- package/dist/cli/index.d.mts +6 -22
- package/dist/cli/index.d.mts.map +1 -1
- package/dist/cli/index.mjs +92 -16
- package/dist/cli/index.mjs.map +1 -1
- package/dist/{gallery-CKU5e84r.mjs → gallery-DnAsudTG.mjs} +2 -2
- package/dist/{gallery-CKU5e84r.mjs.map → gallery-DnAsudTG.mjs.map} +1 -1
- package/dist/{index-75q-ZCzF.d.mts → index-X16io2wM.d.mts} +26 -7
- package/dist/index-X16io2wM.d.mts.map +1 -0
- package/dist/index.d.mts +5 -253
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +11 -8
- package/dist/index.mjs.map +1 -1
- package/dist/{art-processing-U_FYqvAE.mjs → options-CGA4BetG.mjs} +41 -3
- package/dist/options-CGA4BetG.mjs.map +1 -0
- package/dist/plugin-_rDO6Wej.d.mts +259 -0
- package/dist/plugin-_rDO6Wej.d.mts.map +1 -0
- package/dist/{template-BXWLfxIQ.mjs → template-B_y7_OsF.mjs} +2 -2
- package/dist/{template-BXWLfxIQ.mjs.map → template-B_y7_OsF.mjs.map} +1 -1
- package/dist/{vrt-D454uyH6.d.mts → vrt-DC8PNsYN.d.mts} +3 -84
- package/dist/vrt-DC8PNsYN.d.mts.map +1 -0
- package/dist/vrt-DJ_qLgan.d.mts +84 -0
- package/dist/vrt-DJ_qLgan.d.mts.map +1 -0
- package/dist/{vrt-DgVSWKGl.mjs → vrt-DYTmYF1X.mjs} +2 -1
- package/dist/vrt-DYTmYF1X.mjs.map +1 -0
- package/dist/vrt.d.mts +1 -1
- package/dist/vrt.mjs +1 -1
- package/package.json +4 -4
- package/dist/a11y-Cht-W4kd.mjs.map +0 -1
- package/dist/art-processing-U_FYqvAE.mjs.map +0 -1
- package/dist/index-75q-ZCzF.d.mts.map +0 -1
- package/dist/vrt-D454uyH6.d.mts.map +0 -1
- package/dist/vrt-DgVSWKGl.mjs.map +0 -1
package/dist/a11y/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { A11ySummary, MuseaA11yRunner, computeA11ySummary, generateA11yHtmlReport, generateA11yJsonReport };
|
|
1
|
+
import { a as generateA11yHtmlReport, i as computeA11ySummary, n as MuseaA11yRunner, o as generateA11yJsonReport, r as resolveAxeSource, t as A11ySummary } from "../index-X16io2wM.mjs";
|
|
2
|
+
export { A11ySummary, MuseaA11yRunner, computeA11ySummary, generateA11yHtmlReport, generateA11yJsonReport, resolveAxeSource };
|
package/dist/a11y/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { MuseaA11yRunner, computeA11ySummary, generateA11yHtmlReport, generateA11yJsonReport };
|
|
1
|
+
import { a as generateA11yJsonReport, i as generateA11yHtmlReport, n as resolveAxeSource, r as computeA11ySummary, t as MuseaA11yRunner } from "../a11y-Ci9EEv6F.mjs";
|
|
2
|
+
export { MuseaA11yRunner, computeA11ySummary, generateA11yHtmlReport, generateA11yJsonReport, resolveAxeSource };
|
|
@@ -9,6 +9,7 @@ function computeA11ySummary(results) {
|
|
|
9
9
|
return {
|
|
10
10
|
totalComponents: components.size,
|
|
11
11
|
totalVariants: results.length,
|
|
12
|
+
erroredVariants: results.filter((r) => r.error !== void 0).length,
|
|
12
13
|
totalViolations: allViolations.length,
|
|
13
14
|
criticalCount: allViolations.filter((v) => v.impact === "critical").length,
|
|
14
15
|
seriousCount: allViolations.filter((v) => v.impact === "serious").length,
|
|
@@ -36,6 +37,16 @@ function generateA11yHtmlReport(results, summary) {
|
|
|
36
37
|
default: return "#7b8494";
|
|
37
38
|
}
|
|
38
39
|
};
|
|
40
|
+
const errorItems = results.filter((r) => r.error !== void 0).map((r) => `
|
|
41
|
+
<div class="result">
|
|
42
|
+
<div class="result-header">
|
|
43
|
+
<div class="result-info">
|
|
44
|
+
<span class="result-name">${escapeHtml(path.basename(r.artPath, ".art.vue"))} / ${escapeHtml(r.variantName)}</span>
|
|
45
|
+
<span class="result-count">audit did not run</span>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<p style="padding:0.75rem 1rem;color:#f87171"><code>${escapeHtml(r.error ?? "")}</code></p>
|
|
49
|
+
</div>`).join("");
|
|
39
50
|
const resultItems = results.filter((r) => r.violations.length > 0).map((r) => {
|
|
40
51
|
const artName = path.basename(r.artPath, ".art.vue");
|
|
41
52
|
const violationRows = r.violations.map((v) => `
|
|
@@ -129,8 +140,9 @@ function generateA11yHtmlReport(results, summary) {
|
|
|
129
140
|
<div class="stat serious"><div class="stat-value">${summary.seriousCount}</div><div class="stat-label">Serious</div></div>
|
|
130
141
|
<div class="stat moderate"><div class="stat-value">${summary.moderateCount}</div><div class="stat-label">Moderate</div></div>
|
|
131
142
|
<div class="stat minor"><div class="stat-value">${summary.minorCount}</div><div class="stat-label">Minor</div></div>
|
|
143
|
+
<div class="stat critical"><div class="stat-value">${summary.erroredVariants}</div><div class="stat-label">Not audited</div></div>
|
|
132
144
|
</div>
|
|
133
|
-
${summary.totalViolations === 0 ? `<div class="all-clear"><div class="all-clear-text">No accessibility violations found across ${summary.totalVariants} variant(s)</div></div>` : `<div class="results">${resultItems}</div>`}
|
|
145
|
+
${summary.totalViolations === 0 && summary.erroredVariants === 0 ? `<div class="all-clear"><div class="all-clear-text">No accessibility violations found across ${summary.totalVariants} variant(s)</div></div>` : `<div class="results">${errorItems}${resultItems}</div>`}
|
|
134
146
|
</main>
|
|
135
147
|
</body>
|
|
136
148
|
</html>`;
|
|
@@ -148,7 +160,8 @@ function generateA11yJsonReport(results) {
|
|
|
148
160
|
variant: r.variantName,
|
|
149
161
|
violations: r.violations,
|
|
150
162
|
passes: r.passes,
|
|
151
|
-
incomplete: r.incomplete
|
|
163
|
+
incomplete: r.incomplete,
|
|
164
|
+
...r.error === void 0 ? {} : { error: r.error }
|
|
152
165
|
}))
|
|
153
166
|
}, null, 2);
|
|
154
167
|
}
|
|
@@ -158,6 +171,28 @@ function escapeHtml(str) {
|
|
|
158
171
|
//#endregion
|
|
159
172
|
//#region src/a11y/index.ts
|
|
160
173
|
/**
|
|
174
|
+
* Read axe-core's injectable browser bundle.
|
|
175
|
+
*
|
|
176
|
+
* axe-core ships CommonJS (`"main": "axe.js"`, no `exports` map), so under
|
|
177
|
+
* ESM its exports arrive on the namespace's `default` and `source` is not
|
|
178
|
+
* interop-detected as a named export: `(await import("axe-core")).source`
|
|
179
|
+
* is `undefined`. Injecting that injects nothing, leaves `window.axe`
|
|
180
|
+
* undefined, and the audit dies later as `Cannot read properties of
|
|
181
|
+
* undefined (reading 'run')` — a failure that points at the wrong line. So
|
|
182
|
+
* read both shapes and fail here, where the cause is still legible.
|
|
183
|
+
*/
|
|
184
|
+
async function resolveAxeSource() {
|
|
185
|
+
let namespace;
|
|
186
|
+
try {
|
|
187
|
+
namespace = await import("axe-core");
|
|
188
|
+
} catch (cause) {
|
|
189
|
+
throw new Error("axe-core is not installed. Install it as a peer dependency: npm install axe-core", { cause });
|
|
190
|
+
}
|
|
191
|
+
const source = namespace.source ?? namespace.default?.source;
|
|
192
|
+
if (typeof source !== "string" || source.length === 0) throw new Error("axe-core is installed but exposes no `source` bundle to inject. Expected a non-empty string on either the module namespace or its default export; check that the installed axe-core version is >= 4.");
|
|
193
|
+
return source;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
161
196
|
* A11y runner using axe-core via Playwright.
|
|
162
197
|
*/
|
|
163
198
|
var MuseaA11yRunner = class {
|
|
@@ -211,15 +246,10 @@ var MuseaA11yRunner = class {
|
|
|
211
246
|
results.push({
|
|
212
247
|
artPath: art.path,
|
|
213
248
|
variantName: variant.name,
|
|
214
|
-
violations: [
|
|
215
|
-
id: "audit-error",
|
|
216
|
-
impact: "critical",
|
|
217
|
-
description: `Audit failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
218
|
-
helpUrl: "",
|
|
219
|
-
nodes: 0
|
|
220
|
-
}],
|
|
249
|
+
violations: [],
|
|
221
250
|
passes: 0,
|
|
222
|
-
incomplete: 0
|
|
251
|
+
incomplete: 0,
|
|
252
|
+
error: error instanceof Error ? error.message : String(error)
|
|
223
253
|
});
|
|
224
254
|
} finally {
|
|
225
255
|
if (context) await context.context.close();
|
|
@@ -231,7 +261,7 @@ var MuseaA11yRunner = class {
|
|
|
231
261
|
* Audit a single page using axe-core.
|
|
232
262
|
*/
|
|
233
263
|
async auditPage(page, artPath, variantName) {
|
|
234
|
-
const axeSource = await
|
|
264
|
+
const axeSource = await resolveAxeSource();
|
|
235
265
|
await page.evaluate(axeSource);
|
|
236
266
|
const runOptions = this.buildAxeOptions();
|
|
237
267
|
const axeResult = await page.evaluate((opts) => {
|
|
@@ -270,16 +300,6 @@ var MuseaA11yRunner = class {
|
|
|
270
300
|
return generateA11yJsonReport(results);
|
|
271
301
|
}
|
|
272
302
|
/**
|
|
273
|
-
* Get axe-core source code for injection.
|
|
274
|
-
*/
|
|
275
|
-
async getAxeSource() {
|
|
276
|
-
try {
|
|
277
|
-
return (await import("axe-core")).source;
|
|
278
|
-
} catch {
|
|
279
|
-
throw new Error("axe-core is not installed. Install it as a peer dependency: npm install axe-core");
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
303
|
* Build axe-core run options from configuration.
|
|
284
304
|
*/
|
|
285
305
|
buildAxeOptions() {
|
|
@@ -313,6 +333,6 @@ var MuseaA11yRunner = class {
|
|
|
313
333
|
}
|
|
314
334
|
};
|
|
315
335
|
//#endregion
|
|
316
|
-
export { generateA11yJsonReport as i,
|
|
336
|
+
export { generateA11yJsonReport as a, generateA11yHtmlReport as i, resolveAxeSource as n, computeA11ySummary as r, MuseaA11yRunner as t };
|
|
317
337
|
|
|
318
|
-
//# sourceMappingURL=a11y-
|
|
338
|
+
//# sourceMappingURL=a11y-Ci9EEv6F.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a11y-Ci9EEv6F.mjs","names":[],"sources":["../src/a11y/report.ts","../src/a11y/index.ts"],"sourcesContent":["/**\n * A11y report generation for Musea.\n *\n * Generates HTML and JSON reports from accessibility audit results,\n * plus summary statistics computation.\n */\n\nimport type { A11yResult } from \"../types/index.js\";\nimport type { A11ySummary } from \"./index.js\";\nimport path from \"node:path\";\n\n/**\n * Compute a11y summary statistics from results.\n */\nexport function computeA11ySummary(results: A11yResult[]): A11ySummary {\n const components = new Set(results.map((r) => r.artPath));\n const allViolations = results.flatMap((r) => r.violations);\n\n return {\n totalComponents: components.size,\n totalVariants: results.length,\n erroredVariants: results.filter((r) => r.error !== undefined).length,\n totalViolations: allViolations.length,\n criticalCount: allViolations.filter((v) => v.impact === \"critical\").length,\n seriousCount: allViolations.filter((v) => v.impact === \"serious\").length,\n moderateCount: allViolations.filter((v) => v.impact === \"moderate\").length,\n minorCount: allViolations.filter((v) => v.impact === \"minor\").length,\n };\n}\n\n/**\n * Generate HTML report from a11y results.\n */\nexport function generateA11yHtmlReport(results: A11yResult[], summary: A11ySummary): string {\n const timestamp = new Date().toLocaleString(\"ja-JP\", {\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n\n const impactColor = (impact: string): string => {\n switch (impact) {\n case \"critical\":\n return \"#f87171\";\n case \"serious\":\n return \"#fb923c\";\n case \"moderate\":\n return \"#fbbf24\";\n case \"minor\":\n return \"#60a5fa\";\n default:\n return \"#7b8494\";\n }\n };\n\n const errorItems = results\n .filter((r) => r.error !== undefined)\n .map(\n (r) => `\n <div class=\"result\">\n <div class=\"result-header\">\n <div class=\"result-info\">\n <span class=\"result-name\">${escapeHtml(path.basename(r.artPath, \".art.vue\"))} / ${escapeHtml(r.variantName)}</span>\n <span class=\"result-count\">audit did not run</span>\n </div>\n </div>\n <p style=\"padding:0.75rem 1rem;color:#f87171\"><code>${escapeHtml(r.error ?? \"\")}</code></p>\n </div>`,\n )\n .join(\"\");\n\n const resultItems = results\n .filter((r) => r.violations.length > 0)\n .map((r) => {\n const artName = path.basename(r.artPath, \".art.vue\");\n const violationRows = r.violations\n .map(\n (v) => `\n <tr>\n <td><span style=\"color:${impactColor(v.impact)};font-weight:600;text-transform:uppercase;font-size:0.6875rem\">${escapeHtml(v.impact)}</span></td>\n <td><code>${escapeHtml(v.id)}</code></td>\n <td>${escapeHtml(v.description)}</td>\n <td>${v.nodes}</td>\n <td>${v.helpUrl ? `<a href=\"${escapeHtml(v.helpUrl)}\" target=\"_blank\" style=\"color:#60a5fa\">docs</a>` : \"\"}</td>\n </tr>`,\n )\n .join(\"\");\n\n return `\n <div class=\"result\">\n <div class=\"result-header\">\n <div class=\"result-info\">\n <span class=\"result-name\">${escapeHtml(artName)} / ${escapeHtml(r.variantName)}</span>\n <span class=\"result-count\">${r.violations.length} violation(s)</span>\n </div>\n </div>\n <table class=\"violations-table\">\n <thead><tr><th>Impact</th><th>Rule</th><th>Description</th><th>Nodes</th><th>Help</th></tr></thead>\n <tbody>${violationRows}</tbody>\n </table>\n </div>`;\n })\n .join(\"\");\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>A11y Report - Musea</title>\n <style>\n :root {\n --musea-bg-primary: #0d0d0d;\n --musea-bg-secondary: #1a1815;\n --musea-bg-tertiary: #252220;\n --musea-accent: #a34828;\n --musea-text: #e6e9f0;\n --musea-text-muted: #7b8494;\n --musea-border: #3a3530;\n }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body {\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;\n background: var(--musea-bg-primary);\n color: var(--musea-text);\n min-height: 100vh;\n line-height: 1.5;\n }\n .header {\n background: var(--musea-bg-secondary);\n border-bottom: 1px solid var(--musea-border);\n padding: 1rem 2rem;\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n .logo { font-size: 1.25rem; font-weight: 700; color: var(--musea-accent); }\n .header-meta { color: var(--musea-text-muted); font-size: 0.8125rem; }\n .main { max-width: 1200px; margin: 0 auto; padding: 2rem; }\n .summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 1rem; margin-bottom: 2rem; }\n .stat { background: var(--musea-bg-secondary); border: 1px solid var(--musea-border); border-radius: 8px; padding: 1rem; text-align: center; }\n .stat-value { font-size: 1.75rem; font-weight: 700; font-variant-numeric: tabular-nums; }\n .stat-label { color: var(--musea-text-muted); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.08em; }\n .stat.critical .stat-value { color: #f87171; }\n .stat.serious .stat-value { color: #fb923c; }\n .stat.moderate .stat-value { color: #fbbf24; }\n .stat.minor .stat-value { color: #60a5fa; }\n .stat.total .stat-value { color: var(--musea-text); }\n .results { display: flex; flex-direction: column; gap: 1rem; }\n .result { background: var(--musea-bg-secondary); border: 1px solid var(--musea-border); border-radius: 8px; overflow: hidden; }\n .result-header { padding: 1rem; background: var(--musea-bg-tertiary); display: flex; justify-content: space-between; align-items: center; }\n .result-name { font-weight: 600; }\n .result-count { color: var(--musea-text-muted); font-size: 0.8125rem; }\n .violations-table { width: 100%; border-collapse: collapse; font-size: 0.8125rem; }\n .violations-table th { padding: 0.75rem 1rem; text-align: left; color: var(--musea-text-muted); font-weight: 500; font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.08em; border-bottom: 1px solid var(--musea-border); }\n .violations-table td { padding: 0.75rem 1rem; border-bottom: 1px solid var(--musea-border); }\n .violations-table code { background: var(--musea-bg-tertiary); padding: 0.125rem 0.375rem; border-radius: 3px; font-size: 0.75rem; }\n .all-clear { background: rgba(74, 222, 128, 0.1); border: 1px solid rgba(74, 222, 128, 0.2); border-radius: 8px; padding: 2rem; text-align: center; }\n .all-clear-text { color: #4ade80; font-weight: 600; }\n </style>\n</head>\n<body>\n <header class=\"header\">\n <div><span class=\"logo\">Musea</span> <span style=\"color:var(--musea-text-muted);font-size:0.875rem;margin-left:1rem\">Accessibility Report</span></div>\n <div class=\"header-meta\">${timestamp}</div>\n </header>\n <main class=\"main\">\n <div class=\"summary\">\n <div class=\"stat total\"><div class=\"stat-value\">${summary.totalViolations}</div><div class=\"stat-label\">Violations</div></div>\n <div class=\"stat critical\"><div class=\"stat-value\">${summary.criticalCount}</div><div class=\"stat-label\">Critical</div></div>\n <div class=\"stat serious\"><div class=\"stat-value\">${summary.seriousCount}</div><div class=\"stat-label\">Serious</div></div>\n <div class=\"stat moderate\"><div class=\"stat-value\">${summary.moderateCount}</div><div class=\"stat-label\">Moderate</div></div>\n <div class=\"stat minor\"><div class=\"stat-value\">${summary.minorCount}</div><div class=\"stat-label\">Minor</div></div>\n <div class=\"stat critical\"><div class=\"stat-value\">${summary.erroredVariants}</div><div class=\"stat-label\">Not audited</div></div>\n </div>\n ${\n summary.totalViolations === 0 && summary.erroredVariants === 0\n ? `<div class=\"all-clear\"><div class=\"all-clear-text\">No accessibility violations found across ${summary.totalVariants} variant(s)</div></div>`\n : `<div class=\"results\">${errorItems}${resultItems}</div>`\n }\n </main>\n</body>\n</html>`;\n}\n\n/**\n * Generate JSON report for CI integration.\n */\nexport function generateA11yJsonReport(results: A11yResult[]): string {\n const summary = computeA11ySummary(results);\n return JSON.stringify(\n {\n timestamp: new Date().toISOString(),\n summary,\n results: results.map((r) => ({\n art: path.basename(r.artPath, \".art.vue\"),\n variant: r.variantName,\n violations: r.violations,\n passes: r.passes,\n incomplete: r.incomplete,\n ...(r.error === undefined ? {} : { error: r.error }),\n })),\n },\n null,\n 2,\n );\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n","/**\n * Accessibility (a11y) testing module for Musea.\n * Uses axe-core for automated accessibility auditing via Playwright.\n */\n\nimport type { Page } from \"playwright\";\nimport type {\n ArtFileInfo,\n A11yResult,\n A11yViolation,\n A11yOptions,\n ViewportConfig,\n} from \"../types/index.js\";\nimport type { MuseaVrtRunner } from \"../vrt.js\";\n\nimport { computeA11ySummary, generateA11yHtmlReport, generateA11yJsonReport } from \"./report.js\";\n\n// Re-export report functions so consumers importing from a11y.js still work\nexport { computeA11ySummary, generateA11yHtmlReport, generateA11yJsonReport } from \"./report.js\";\n\n/**\n * A11y audit summary.\n */\nexport interface A11ySummary {\n totalComponents: number;\n totalVariants: number;\n /** Variants whose audit could not run at all; see `A11yResult.error`. */\n erroredVariants: number;\n totalViolations: number;\n criticalCount: number;\n seriousCount: number;\n moderateCount: number;\n minorCount: number;\n}\n\n/**\n * axe-core result shape (subset).\n */\ninterface AxeResult {\n violations: Array<{\n id: string;\n impact: string;\n description: string;\n helpUrl: string;\n nodes: Array<unknown>;\n }>;\n passes: Array<unknown>;\n incomplete: Array<unknown>;\n}\n\n/**\n * Read axe-core's injectable browser bundle.\n *\n * axe-core ships CommonJS (`\"main\": \"axe.js\"`, no `exports` map), so under\n * ESM its exports arrive on the namespace's `default` and `source` is not\n * interop-detected as a named export: `(await import(\"axe-core\")).source`\n * is `undefined`. Injecting that injects nothing, leaves `window.axe`\n * undefined, and the audit dies later as `Cannot read properties of\n * undefined (reading 'run')` — a failure that points at the wrong line. So\n * read both shapes and fail here, where the cause is still legible.\n */\nexport async function resolveAxeSource(): Promise<string> {\n let namespace: { source?: unknown; default?: { source?: unknown } };\n try {\n namespace = await import(\"axe-core\");\n } catch (cause) {\n throw new Error(\n \"axe-core is not installed. Install it as a peer dependency: npm install axe-core\",\n { cause },\n );\n }\n\n const source = namespace.source ?? namespace.default?.source;\n if (typeof source !== \"string\" || source.length === 0) {\n throw new Error(\n \"axe-core is installed but exposes no `source` bundle to inject. \" +\n \"Expected a non-empty string on either the module namespace or its \" +\n \"default export; check that the installed axe-core version is >= 4.\",\n );\n }\n return source;\n}\n\n/**\n * A11y runner using axe-core via Playwright.\n */\nexport class MuseaA11yRunner {\n private options: Required<A11yOptions>;\n\n constructor(options: A11yOptions = {}) {\n this.options = {\n enabled: options.enabled ?? true,\n includeRules: options.includeRules ?? [],\n excludeRules: options.excludeRules ?? [],\n level: options.level ?? \"AA\",\n };\n }\n\n /**\n * Run a11y audits on all art file variants.\n * Reuses VRT runner's browser if available.\n */\n async runAudits(\n artFiles: ArtFileInfo[],\n baseUrl: string,\n vrtRunner?: MuseaVrtRunner,\n ): Promise<A11yResult[]> {\n const results: A11yResult[] = [];\n const defaultViewport: ViewportConfig = { width: 1280, height: 720, name: \"desktop\" };\n\n for (const art of artFiles) {\n for (const variant of art.variants) {\n if (variant.skipVrt) continue;\n\n let page: Page | null = null;\n let context: { page: Page; context: { close(): Promise<void> } } | null = null;\n\n try {\n if (vrtRunner) {\n context = await vrtRunner.createPage(defaultViewport);\n page = context.page;\n } else {\n // Standalone mode: launch own browser\n const { chromium } = await import(\"playwright\");\n const browser = await chromium.launch({ headless: true });\n const ctx = await browser.newContext({\n viewport: { width: defaultViewport.width, height: defaultViewport.height },\n });\n page = await ctx.newPage();\n context = { page, context: ctx };\n }\n\n const variantUrl = this.buildVariantUrl(baseUrl, art.path, variant.name);\n await page.goto(variantUrl, { waitUntil: \"networkidle\" });\n await page.waitForSelector(\".musea-variant\", { timeout: 10000 });\n await page.waitForTimeout(200);\n\n const result = await this.auditPage(page, art.path, variant.name);\n results.push(result);\n } catch (error) {\n results.push({\n artPath: art.path,\n variantName: variant.name,\n violations: [],\n passes: 0,\n incomplete: 0,\n error: error instanceof Error ? error.message : String(error),\n });\n } finally {\n if (context) {\n await context.context.close();\n }\n }\n }\n }\n\n return results;\n }\n\n /**\n * Audit a single page using axe-core.\n */\n async auditPage(page: Page, artPath: string, variantName: string): Promise<A11yResult> {\n // Inject axe-core into the page\n const axeSource = await resolveAxeSource();\n await page.evaluate(axeSource);\n\n // Build axe-core run options\n const runOptions = this.buildAxeOptions();\n\n // Run axe-core\n const axeResult = (await page.evaluate((opts) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (window as any).axe.run(document, opts);\n }, runOptions)) as AxeResult;\n\n // Map to our result format\n const violations: A11yViolation[] = axeResult.violations.map((v) => ({\n id: v.id,\n impact: v.impact as A11yViolation[\"impact\"],\n description: v.description,\n helpUrl: v.helpUrl,\n nodes: v.nodes.length,\n }));\n\n return {\n artPath,\n variantName,\n violations,\n passes: axeResult.passes.length,\n incomplete: axeResult.incomplete.length,\n };\n }\n\n /**\n * Get summary statistics from results.\n */\n getSummary(results: A11yResult[]): A11ySummary {\n return computeA11ySummary(results);\n }\n\n /**\n * Generate HTML report.\n */\n generateHtmlReport(results: A11yResult[]): string {\n const summary = this.getSummary(results);\n return generateA11yHtmlReport(results, summary);\n }\n\n /**\n * Generate JSON report for CI integration.\n */\n generateJsonReport(results: A11yResult[]): string {\n return generateA11yJsonReport(results);\n }\n\n /**\n * Build axe-core run options from configuration.\n */\n private buildAxeOptions(): Record<string, unknown> {\n const runOnly: Record<string, unknown> = {};\n\n // Set WCAG level\n const tags: string[] = [];\n switch (this.options.level) {\n case \"A\":\n tags.push(\"wcag2a\", \"wcag21a\");\n break;\n case \"AA\":\n tags.push(\"wcag2a\", \"wcag2aa\", \"wcag21a\", \"wcag21aa\", \"wcag22aa\");\n break;\n case \"AAA\":\n tags.push(\"wcag2a\", \"wcag2aa\", \"wcag2aaa\", \"wcag21a\", \"wcag21aa\", \"wcag22aa\");\n break;\n }\n\n if (tags.length > 0) {\n runOnly.type = \"tag\";\n runOnly.values = tags;\n }\n\n const rules: Record<string, { enabled: boolean }> = {};\n\n for (const ruleId of this.options.includeRules) {\n rules[ruleId] = { enabled: true };\n }\n for (const ruleId of this.options.excludeRules) {\n rules[ruleId] = { enabled: false };\n }\n\n return {\n ...(Object.keys(runOnly).length > 0 ? { runOnly } : {}),\n ...(Object.keys(rules).length > 0 ? { rules } : {}),\n };\n }\n\n private buildVariantUrl(baseUrl: string, artPath: string, variantName: string): string {\n const encodedPath = encodeURIComponent(artPath);\n const encodedVariant = encodeURIComponent(variantName);\n return `${baseUrl}/__musea__/preview?art=${encodedPath}&variant=${encodedVariant}`;\n }\n}\n"],"mappings":"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"}
|
package/dist/cli/index.d.mts
CHANGED
|
@@ -1,25 +1,6 @@
|
|
|
1
|
+
import { i as MuseaVrtOptions } from "../plugin-_rDO6Wej.mjs";
|
|
2
|
+
|
|
1
3
|
//#region src/cli/index.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Musea CLI
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* musea-vrt [command] [options]
|
|
7
|
-
*
|
|
8
|
-
* Commands:
|
|
9
|
-
* (default) Run VRT tests
|
|
10
|
-
* approve [pat] Approve failed snapshots (optionally filtered by pattern)
|
|
11
|
-
* clean Remove orphaned snapshots
|
|
12
|
-
*
|
|
13
|
-
* Options:
|
|
14
|
-
* -u, --update Update baseline snapshots
|
|
15
|
-
* -c, --config Path to vite config (default: vite.config.ts)
|
|
16
|
-
* -o, --output Output directory for reports (default: .vize)
|
|
17
|
-
* -t, --threshold Diff threshold percentage (default: 0.1)
|
|
18
|
-
* --json Output JSON report instead of HTML
|
|
19
|
-
* --ci CI mode - exit with non-zero code on failures
|
|
20
|
-
* --a11y Run accessibility audits alongside VRT
|
|
21
|
-
* -h, --help Show help
|
|
22
|
-
*/
|
|
23
4
|
type Command = "run" | "approve" | "clean" | "generate";
|
|
24
5
|
interface CliOptions {
|
|
25
6
|
command: Command;
|
|
@@ -27,6 +8,7 @@ interface CliOptions {
|
|
|
27
8
|
config: string;
|
|
28
9
|
output: string;
|
|
29
10
|
threshold: number;
|
|
11
|
+
thresholdProvided: boolean;
|
|
30
12
|
json: boolean;
|
|
31
13
|
ci: boolean;
|
|
32
14
|
a11y: boolean;
|
|
@@ -34,7 +16,9 @@ interface CliOptions {
|
|
|
34
16
|
baseUrl: string;
|
|
35
17
|
pattern?: string;
|
|
36
18
|
componentPath?: string;
|
|
19
|
+
vrt?: MuseaVrtOptions;
|
|
37
20
|
}
|
|
21
|
+
declare function parseArgs(args: string[]): CliOptions;
|
|
38
22
|
//#endregion
|
|
39
|
-
export { CliOptions };
|
|
23
|
+
export { CliOptions, parseArgs };
|
|
40
24
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/cli/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/cli/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/cli/index.ts"],"mappings":";;;KA+BK,OAAA;AAAA,UAEY,UAAA;EACf,OAAA,EAAS,OAAA;EACT,MAAA;EACA,MAAA;EACA,MAAA;EACA,SAAA;EACA,iBAAA;EACA,IAAA;EACA,EAAA;EACA,IAAA;EACA,IAAA;EACA,OAAA;EACA,OAAA;EACA,aAAA;EACA,GAAA,GAAM,eAAe;AAAA;AAAA,iBAGP,SAAA,CAAU,IAAA,aAAiB,UAAU"}
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { i as MuseaVrtRunner, n as generateVrtJsonReport, r as generateVrtReport } from "../vrt-
|
|
2
|
+
import { n as readMuseaOptions, r as processMuseaArtFile } from "../options-CGA4BetG.mjs";
|
|
3
|
+
import { i as MuseaVrtRunner, n as generateVrtJsonReport, r as generateVrtReport } from "../vrt-DYTmYF1X.mjs";
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { loadConfigFromFile } from "vite";
|
|
6
8
|
//#region src/cli/utils.ts
|
|
7
9
|
/**
|
|
8
10
|
* CLI utility functions for art file scanning and parsing.
|
|
@@ -51,12 +53,19 @@ function hasCiBlockingVrtResult(summary) {
|
|
|
51
53
|
function isArtFileInput(filePath) {
|
|
52
54
|
return filePath.endsWith(".art.vue");
|
|
53
55
|
}
|
|
56
|
+
function createVrtOptions(options) {
|
|
57
|
+
const configured = options.vrt ?? {};
|
|
58
|
+
return {
|
|
59
|
+
...configured,
|
|
60
|
+
snapshotDir: path.join(options.output, "snapshots"),
|
|
61
|
+
threshold: options.thresholdProvided ? options.threshold : configured.threshold ?? options.threshold
|
|
62
|
+
};
|
|
63
|
+
}
|
|
54
64
|
async function runVrt(options, artFiles) {
|
|
55
65
|
const totalVariants = artFiles.reduce((sum, art) => sum + art.variants.filter((v) => !v.skipVrt).length, 0);
|
|
56
66
|
console.log(` Testing ${totalVariants} variant(s) across ${artFiles.length} art file(s)\n`);
|
|
57
67
|
const runner = new MuseaVrtRunner({
|
|
58
|
-
|
|
59
|
-
threshold: options.threshold,
|
|
68
|
+
...createVrtOptions(options),
|
|
60
69
|
ci: options.ci ? {
|
|
61
70
|
failOnDiff: true,
|
|
62
71
|
jsonReport: options.json
|
|
@@ -89,7 +98,8 @@ async function runVrt(options, artFiles) {
|
|
|
89
98
|
console.log(` Variants: ${a11ySummary.totalVariants}`);
|
|
90
99
|
console.log(` Violations: ${a11ySummary.totalViolations}`);
|
|
91
100
|
console.log(` Critical: ${a11ySummary.criticalCount}`);
|
|
92
|
-
console.log(` Serious: ${a11ySummary.seriousCount}
|
|
101
|
+
console.log(` Serious: ${a11ySummary.seriousCount}`);
|
|
102
|
+
console.log(` Not audited: ${a11ySummary.erroredVariants}\n`);
|
|
93
103
|
const reportDir = options.output;
|
|
94
104
|
await fs.promises.mkdir(reportDir, { recursive: true });
|
|
95
105
|
if (options.json) {
|
|
@@ -103,6 +113,10 @@ async function runVrt(options, artFiles) {
|
|
|
103
113
|
await fs.promises.writeFile(a11yPath, a11yHtml);
|
|
104
114
|
console.log(` A11y HTML report: ${a11yPath}\n`);
|
|
105
115
|
}
|
|
116
|
+
if (options.ci && a11ySummary.erroredVariants > 0) {
|
|
117
|
+
console.log(` CI mode: ${a11ySummary.erroredVariants} variant(s) could not be audited\n`);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
106
120
|
if (options.ci && (a11ySummary.criticalCount > 0 || a11ySummary.seriousCount > 0)) {
|
|
107
121
|
console.log(" CI mode: Accessibility violations found\n");
|
|
108
122
|
process.exit(1);
|
|
@@ -139,10 +153,7 @@ async function runVrt(options, artFiles) {
|
|
|
139
153
|
}
|
|
140
154
|
}
|
|
141
155
|
async function runApprove(options, artFiles) {
|
|
142
|
-
const runner = new MuseaVrtRunner(
|
|
143
|
-
snapshotDir: path.join(options.output, "snapshots"),
|
|
144
|
-
threshold: options.threshold
|
|
145
|
-
});
|
|
156
|
+
const runner = new MuseaVrtRunner(createVrtOptions(options));
|
|
146
157
|
try {
|
|
147
158
|
console.log(" Launching browser...");
|
|
148
159
|
await runner.init();
|
|
@@ -163,10 +174,7 @@ async function runApprove(options, artFiles) {
|
|
|
163
174
|
}
|
|
164
175
|
}
|
|
165
176
|
async function runClean(options, artFiles) {
|
|
166
|
-
const runner = new MuseaVrtRunner(
|
|
167
|
-
snapshotDir: path.join(options.output, "snapshots"),
|
|
168
|
-
threshold: options.threshold
|
|
169
|
-
});
|
|
177
|
+
const runner = new MuseaVrtRunner(createVrtOptions(options));
|
|
170
178
|
console.log(" Scanning for orphaned snapshots...\n");
|
|
171
179
|
const cleaned = await runner.cleanOrphans(artFiles);
|
|
172
180
|
if (cleaned === 0) console.log(" No orphaned snapshots found.\n");
|
|
@@ -202,7 +210,64 @@ async function runGenerate(options) {
|
|
|
202
210
|
}
|
|
203
211
|
}
|
|
204
212
|
//#endregion
|
|
213
|
+
//#region src/cli/config.ts
|
|
214
|
+
async function loadMuseaVrtOptions(configPath, cwd = process.cwd()) {
|
|
215
|
+
const resolvedConfigPath = path.isAbsolute(configPath) ? configPath : path.resolve(cwd, configPath);
|
|
216
|
+
if (!await fileExists(resolvedConfigPath)) return void 0;
|
|
217
|
+
const loaded = await loadConfigFromFile({
|
|
218
|
+
command: "serve",
|
|
219
|
+
mode: "development",
|
|
220
|
+
isPreview: false,
|
|
221
|
+
isSsrBuild: false
|
|
222
|
+
}, resolvedConfigPath);
|
|
223
|
+
if (!loaded) return void 0;
|
|
224
|
+
const plugins = [];
|
|
225
|
+
await collectPlugins(loaded.config.plugins, plugins);
|
|
226
|
+
for (const plugin of plugins) {
|
|
227
|
+
const options = readMuseaOptions(plugin);
|
|
228
|
+
if (options?.vrt) return options.vrt;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async function collectPlugins(input, plugins) {
|
|
232
|
+
const resolved = await input;
|
|
233
|
+
if (!resolved) return;
|
|
234
|
+
if (Array.isArray(resolved)) {
|
|
235
|
+
for (const item of resolved) await collectPlugins(item, plugins);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
plugins.push(resolved);
|
|
239
|
+
}
|
|
240
|
+
async function fileExists(filePath) {
|
|
241
|
+
try {
|
|
242
|
+
await fs.promises.access(filePath);
|
|
243
|
+
return true;
|
|
244
|
+
} catch {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
//#endregion
|
|
205
249
|
//#region src/cli/index.ts
|
|
250
|
+
/**
|
|
251
|
+
* Musea CLI
|
|
252
|
+
*
|
|
253
|
+
* Usage:
|
|
254
|
+
* musea-vrt [command] [options]
|
|
255
|
+
*
|
|
256
|
+
* Commands:
|
|
257
|
+
* (default) Run VRT tests
|
|
258
|
+
* approve [pat] Approve failed snapshots (optionally filtered by pattern)
|
|
259
|
+
* clean Remove orphaned snapshots
|
|
260
|
+
*
|
|
261
|
+
* Options:
|
|
262
|
+
* -u, --update Update baseline snapshots
|
|
263
|
+
* -c, --config Path to vite config (default: vite.config.ts)
|
|
264
|
+
* -o, --output Output directory for reports (default: .vize)
|
|
265
|
+
* -t, --threshold Diff threshold percentage (default: 0.1)
|
|
266
|
+
* --json Output JSON report instead of HTML
|
|
267
|
+
* --ci CI mode - exit with non-zero code on failures
|
|
268
|
+
* --a11y Run accessibility audits alongside VRT
|
|
269
|
+
* -h, --help Show help
|
|
270
|
+
*/
|
|
206
271
|
function parseArgs(args) {
|
|
207
272
|
const options = {
|
|
208
273
|
command: "run",
|
|
@@ -210,6 +275,7 @@ function parseArgs(args) {
|
|
|
210
275
|
config: "vite.config.ts",
|
|
211
276
|
output: ".vize",
|
|
212
277
|
threshold: .1,
|
|
278
|
+
thresholdProvided: false,
|
|
213
279
|
json: false,
|
|
214
280
|
ci: false,
|
|
215
281
|
a11y: false,
|
|
@@ -253,7 +319,8 @@ function parseArgs(args) {
|
|
|
253
319
|
break;
|
|
254
320
|
case "-t":
|
|
255
321
|
case "--threshold":
|
|
256
|
-
options.threshold =
|
|
322
|
+
options.threshold = parseThreshold(args[++i]);
|
|
323
|
+
options.thresholdProvided = true;
|
|
257
324
|
break;
|
|
258
325
|
case "--json":
|
|
259
326
|
options.json = true;
|
|
@@ -275,6 +342,10 @@ function parseArgs(args) {
|
|
|
275
342
|
}
|
|
276
343
|
return options;
|
|
277
344
|
}
|
|
345
|
+
function parseThreshold(value) {
|
|
346
|
+
const threshold = Number.parseFloat(value ?? "");
|
|
347
|
+
return Number.isFinite(threshold) ? threshold : .1;
|
|
348
|
+
}
|
|
278
349
|
function printHelp() {
|
|
279
350
|
console.log(`
|
|
280
351
|
Musea VRT - Visual Regression Testing for Component Gallery
|
|
@@ -350,6 +421,7 @@ async function main() {
|
|
|
350
421
|
}
|
|
351
422
|
return;
|
|
352
423
|
}
|
|
424
|
+
options.vrt = await loadMuseaVrtOptions(options.config, cwd);
|
|
353
425
|
console.log(" Scanning for art files...");
|
|
354
426
|
const artFilePaths = await scanArtFiles(cwd);
|
|
355
427
|
if (artFilePaths.length === 0) {
|
|
@@ -380,11 +452,15 @@ async function main() {
|
|
|
380
452
|
process.exit(1);
|
|
381
453
|
}
|
|
382
454
|
}
|
|
383
|
-
main().catch((error) => {
|
|
455
|
+
if (isDirectRun()) main().catch((error) => {
|
|
384
456
|
console.error("Fatal error:", error);
|
|
385
457
|
process.exit(1);
|
|
386
458
|
});
|
|
459
|
+
function isDirectRun() {
|
|
460
|
+
const entrypoint = process.argv[1];
|
|
461
|
+
return entrypoint ? fileURLToPath(import.meta.url) === path.resolve(entrypoint) : false;
|
|
462
|
+
}
|
|
387
463
|
//#endregion
|
|
388
|
-
export {};
|
|
464
|
+
export { parseArgs };
|
|
389
465
|
|
|
390
466
|
//# sourceMappingURL=index.mjs.map
|
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 { processMuseaArtFile } from \"../plugin/art-processing.js\";\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 return processMuseaArtFile(filePath, {\n root: path.dirname(filePath),\n command: \"serve\",\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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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/cli/utils.ts","../../src/cli/commands.ts","../../src/cli/config.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 { processMuseaArtFile } from \"../plugin/art-processing.js\";\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 return processMuseaArtFile(filePath, {\n root: path.dirname(filePath),\n command: \"serve\",\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 { ExtendedVrtOptions, VrtSummary } from \"../vrt.js\";\nimport type { ArtFileInfo } 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 function createVrtOptions(options: CliOptions): ExtendedVrtOptions {\n const configured = options.vrt ?? {};\n return {\n ...configured,\n snapshotDir: path.join(options.output, \"snapshots\"),\n threshold: options.thresholdProvided\n ? options.threshold\n : (configured.threshold ?? options.threshold),\n };\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 const runner = new MuseaVrtRunner({\n ...createVrtOptions(options),\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 console.log(` Not audited: ${a11ySummary.erroredVariants}\\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. A variant\n // whose audit never ran fails too, but under its own message: it is\n // not an accessibility finding, and reporting it as one sends people\n // looking for a component defect that does not exist.\n if (options.ci && a11ySummary.erroredVariants > 0) {\n console.log(\n ` CI mode: ${a11ySummary.erroredVariants} variant(s) could not be audited\\n`,\n );\n process.exit(1);\n }\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 runner = new MuseaVrtRunner(createVrtOptions(options));\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 runner = new MuseaVrtRunner(createVrtOptions(options));\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","import fs from \"node:fs\";\nimport path from \"node:path\";\n\nimport { loadConfigFromFile, type PluginOption } from \"vite\";\n\nimport type { MuseaVrtOptions } from \"../types/index.js\";\nimport { readMuseaOptions } from \"../plugin/options.js\";\n\nexport async function loadMuseaVrtOptions(\n configPath: string,\n cwd = process.cwd(),\n): Promise<MuseaVrtOptions | undefined> {\n const resolvedConfigPath = path.isAbsolute(configPath)\n ? configPath\n : path.resolve(cwd, configPath);\n if (!(await fileExists(resolvedConfigPath))) return undefined;\n\n const loaded = await loadConfigFromFile(\n {\n command: \"serve\",\n mode: \"development\",\n isPreview: false,\n isSsrBuild: false,\n },\n resolvedConfigPath,\n );\n if (!loaded) return undefined;\n\n const plugins: unknown[] = [];\n await collectPlugins(loaded.config.plugins, plugins);\n\n for (const plugin of plugins) {\n const options = readMuseaOptions(plugin);\n if (options?.vrt) return options.vrt;\n }\n return undefined;\n}\n\nasync function collectPlugins(\n input: PluginOption | Promise<PluginOption> | undefined,\n plugins: unknown[],\n) {\n const resolved = await input;\n if (!resolved) return;\n\n if (Array.isArray(resolved)) {\n for (const item of resolved) {\n await collectPlugins(item, plugins);\n }\n return;\n }\n\n plugins.push(resolved);\n}\n\nasync function fileExists(filePath: string): Promise<boolean> {\n try {\n await fs.promises.access(filePath);\n return true;\n } catch {\n return false;\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 path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { ArtFileInfo } from \"../types/index.js\";\nimport { scanArtFiles, parseArtFile } from \"./utils.js\";\nimport { runVrt, runApprove, runClean, runGenerate } from \"./commands.js\";\nimport { loadMuseaVrtOptions } from \"./config.js\";\nimport type { MuseaVrtOptions } from \"../types/index.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 thresholdProvided: boolean;\n json: boolean;\n ci: boolean;\n a11y: boolean;\n help: boolean;\n baseUrl: string;\n pattern?: string;\n componentPath?: string;\n vrt?: MuseaVrtOptions;\n}\n\nexport function 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 thresholdProvided: false,\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 = parseThreshold(args[++i]);\n options.thresholdProvided = true;\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 parseThreshold(value: string | undefined): number {\n const threshold = Number.parseFloat(value ?? \"\");\n return Number.isFinite(threshold) ? threshold : 0.1;\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 options.vrt = await loadMuseaVrtOptions(options.config, cwd);\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\nif (isDirectRun()) {\n main().catch((error) => {\n console.error(\"Fatal error:\", error);\n process.exit(1);\n });\n}\n\nfunction isDirectRun(): boolean {\n const entrypoint = process.argv[1];\n return entrypoint ? fileURLToPath(import.meta.url) === path.resolve(entrypoint) : false;\n}\n"],"mappings":";;;;;;;;;;;;;;AAaA,eAAsB,aAAa,MAAiC;CAClE,MAAM,QAAkB,CAAC;CAEzB,eAAe,KAAK,KAA4B;EAC9C,IAAI;EACJ,IAAI;GACF,UAAU,MAAM,GAAG,SAAS,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;EAClE,SAAS,OAAO;GACd,IAAK,MAAgC,SAAS,UAC5C;GAEF,MAAM;EACR;EAEA,KAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,WAAW,KAAK,KAAK,KAAK,MAAM,IAAI;GAG1C,IAAI,MAAM,SAAS,kBAAkB,MAAM,SAAS,QAClD;GAGF,IAAI,MAAM,YAAY,GACpB,MAAM,KAAK,QAAQ;QACd,IAAI,MAAM,OAAO,KAAK,MAAM,KAAK,SAAS,UAAU,GACzD,MAAM,KAAK,QAAQ;EAEvB;CACF;CAEA,MAAM,KAAK,IAAI;CACf,OAAO;AACT;;AAGA,eAAsB,aAAa,UAA+C;CAChF,OAAO,oBAAoB,UAAU;EACnC,MAAM,KAAK,QAAQ,QAAQ;EAC3B,SAAS;CACX,CAAC;AACH;;;;;;;;;ACrCA,SAAgB,uBAAuB,SAA8B;CACnE,OAAO,QAAQ,SAAS,KAAK,QAAQ,UAAU;AACjD;AAEA,SAAgB,eAAe,UAA2B;CACxD,OAAO,SAAS,SAAS,UAAU;AACrC;AAEA,SAAgB,iBAAiB,SAAyC;CACxE,MAAM,aAAa,QAAQ,OAAO,CAAC;CACnC,OAAO;EACL,GAAG;EACH,aAAa,KAAK,KAAK,QAAQ,QAAQ,WAAW;EAClD,WAAW,QAAQ,oBACf,QAAQ,YACP,WAAW,aAAa,QAAQ;CACvC;AACF;AAEA,eAAsB,OAAO,SAAqB,UAAwC;CACxF,MAAM,gBAAgB,SAAS,QAC5B,KAAK,QAAQ,MAAM,IAAI,SAAS,QAAQ,MAAM,CAAC,EAAE,OAAO,EAAE,QAC3D,CACF;CAEA,QAAQ,IAAI,aAAa,cAAc,qBAAqB,SAAS,OAAO,eAAe;CAE3F,MAAM,SAAS,IAAI,eAAe;EAChC,GAAG,iBAAiB,OAAO;EAC3B,IAAI,QAAQ,KAAK;GAAE,YAAY;GAAM,YAAY,QAAQ;EAAK,IAAI,KAAA;CACpE,CAAC;CAED,IAAI;EACF,QAAQ,IAAI,wBAAwB;EACpC,MAAM,OAAO,KAAK;EAElB,QAAQ,IAAI,wCAAwC;EAGpD,MAAM,UAAU,MAAM,OAAO,YAAY,UAAU,QAAQ,OAAO;EAClE,MAAM,UAAU,OAAO,WAAW,OAAO;EAGzC,QAAQ,IAAI,YAAY;EACxB,QAAQ,IAAI,aAAa;EACzB,QAAQ,IAAI,gBAAgB,QAAQ,QAAQ;EAC5C,QAAQ,IAAI,gBAAgB,QAAQ,QAAQ;EAC5C,QAAQ,IAAI,gBAAgB,QAAQ,KAAK;EACzC,QAAQ,IAAI,gBAAgB,QAAQ,SAAS;EAC7C,QAAQ,IAAI,gBAAgB,QAAQ,OAAO;EAC3C,QAAQ,IAAI,kBAAkB,QAAQ,WAAW,KAAM,QAAQ,CAAC,EAAE,IAAI;EAGtE,IAAI,QAAQ,MAAM;GAChB,QAAQ,IAAI,qCAAqC;GACjD,IAAI;IACF,MAAM,EAAE,oBAAoB,MAAM,OAAO;IACzC,MAAM,aAAa,IAAI,gBAAgB;IACvC,MAAM,cAAc,MAAM,WAAW,UAAU,UAAU,QAAQ,SAAS,MAAM;IAChF,MAAM,cAAc,WAAW,WAAW,WAAW;IAErD,QAAQ,IAAI,iBAAiB;IAC7B,QAAQ,IAAI,iBAAiB;IAC7B,QAAQ,IAAI,mBAAmB,YAAY,iBAAiB;IAC5D,QAAQ,IAAI,mBAAmB,YAAY,eAAe;IAC1D,QAAQ,IAAI,mBAAmB,YAAY,iBAAiB;IAC5D,QAAQ,IAAI,mBAAmB,YAAY,eAAe;IAC1D,QAAQ,IAAI,mBAAmB,YAAY,cAAc;IACzD,QAAQ,IAAI,oBAAoB,YAAY,gBAAgB,GAAG;IAG/D,MAAM,YAAY,QAAQ;IAC1B,MAAM,GAAG,SAAS,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;IAEtD,IAAI,QAAQ,MAAM;KAChB,MAAM,WAAW,WAAW,mBAAmB,WAAW;KAC1D,MAAM,WAAW,KAAK,KAAK,WAAW,kBAAkB;KACxD,MAAM,GAAG,SAAS,UAAU,UAAU,QAAQ;KAC9C,QAAQ,IAAI,uBAAuB,SAAS,GAAG;IACjD,OAAO;KACL,MAAM,WAAW,WAAW,mBAAmB,WAAW;KAC1D,MAAM,WAAW,KAAK,KAAK,WAAW,kBAAkB;KACxD,MAAM,GAAG,SAAS,UAAU,UAAU,QAAQ;KAC9C,QAAQ,IAAI,uBAAuB,SAAS,GAAG;IACjD;IAMA,IAAI,QAAQ,MAAM,YAAY,kBAAkB,GAAG;KACjD,QAAQ,IACN,cAAc,YAAY,gBAAgB,mCAC5C;KACA,QAAQ,KAAK,CAAC;IAChB;IACA,IAAI,QAAQ,OAAO,YAAY,gBAAgB,KAAK,YAAY,eAAe,IAAI;KACjF,QAAQ,IAAI,6CAA6C;KACzD,QAAQ,KAAK,CAAC;IAChB;GACF,SAAS,GAAG;IACV,QAAQ,KAAK,0BAA0B,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;IACjF,QAAQ,KAAK,2DAA2D;GAC1E;EACF;EAGA,IAAI,QAAQ,QAAQ;GAClB,QAAQ,IAAI,yBAAyB;GACrC,MAAM,UAAU,MAAM,OAAO,gBAAgB,OAAO;GACpD,QAAQ,IAAI,aAAa,QAAQ,eAAe;EAClD;EAGA,MAAM,YAAY,QAAQ;EAC1B,MAAM,GAAG,SAAS,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;EAEtD,IAAI,QAAQ,MAAM;GAChB,MAAM,aAAa,sBAAsB,SAAS,OAAO;GACzD,MAAM,WAAW,KAAK,KAAK,WAAW,iBAAiB;GACvD,MAAM,GAAG,SAAS,UAAU,UAAU,UAAU;GAChD,QAAQ,IAAI,kBAAkB,SAAS,GAAG;EAC5C,OAAO;GACL,MAAM,aAAa,kBAAkB,SAAS,OAAO;GACrD,MAAM,WAAW,KAAK,KAAK,WAAW,iBAAiB;GACvD,MAAM,GAAG,SAAS,UAAU,UAAU,UAAU;GAChD,QAAQ,IAAI,kBAAkB,SAAS,GAAG;EAC5C;EAGA,IAAI,QAAQ,MAAM,uBAAuB,OAAO,GAAG;GACjD,QAAQ,IAAI,iDAAiD;GAC7D,QAAQ,KAAK,CAAC;EAChB;CACF,UAAU;EACR,MAAM,OAAO,MAAM;CACrB;AACF;AAEA,eAAsB,WAAW,SAAqB,UAAwC;CAC5F,MAAM,SAAS,IAAI,eAAe,iBAAiB,OAAO,CAAC;CAE3D,IAAI;EACF,QAAQ,IAAI,wBAAwB;EACpC,MAAM,OAAO,KAAK;EAElB,QAAQ,IAAI,oCAAoC;EAEhD,MAAM,UAAU,MAAM,OAAO,YAAY,UAAU,QAAQ,OAAO;EAClE,MAAM,SAAS,QAAQ,QAAQ,MAAM,CAAC,EAAE,UAAU,CAAC,EAAE,KAAK;EAE1D,IAAI,OAAO,WAAW,GAAG;GACvB,QAAQ,IAAI,iCAAiC;GAC7C;EACF;EAEA,MAAM,UAAU,QAAQ;EACxB,IAAI,SACF,QAAQ,IAAI,mCAAmC,QAAQ,GAAG;OAE1D,QAAQ,IAAI,mBAAmB,OAAO,OAAO,yBAAyB;EAGxE,MAAM,WAAW,MAAM,OAAO,eAAe,SAAS,OAAO;EAC7D,QAAQ,IAAI,cAAc,SAAS,eAAe;CACpD,UAAU;EACR,MAAM,OAAO,MAAM;CACrB;AACF;AAEA,eAAsB,SAAS,SAAqB,UAAwC;CAC1F,MAAM,SAAS,IAAI,eAAe,iBAAiB,OAAO,CAAC;CAE3D,QAAQ,IAAI,wCAAwC;CAEpD,MAAM,UAAU,MAAM,OAAO,aAAa,QAAQ;CAElD,IAAI,YAAY,GACd,QAAQ,IAAI,kCAAkC;MAE9C,QAAQ,IAAI,eAAe,QAAQ,wBAAwB;AAE/D;AAEA,eAAsB,YAAY,SAAoC;CACpE,IAAI,CAAC,QAAQ,eAAe;EAC1B,QAAQ,MAAM,kCAAkC;EAChD,QAAQ,MAAM,+CAA+C;EAC7D,QAAQ,KAAK,CAAC;CAChB;CAEA,MAAM,gBAAgB,KAAK,QAAQ,QAAQ,aAAa;CACxD,IAAI,eAAe,aAAa,GAAG;EACjC,QAAQ,MACN,mFACF;EACA,QAAQ,MAAM,4DAA4D;EAC1E,QAAQ,KAAK,CAAC;CAChB;CAGA,IAAI;EACF,MAAM,GAAG,SAAS,OAAO,aAAa;CACxC,QAAQ;EACN,QAAQ,MAAM,4BAA4B,cAAc,GAAG;EAC3D,QAAQ,KAAK,CAAC;CAChB;CAEA,QAAQ,IAAI,8BAA8B,KAAK,SAAS,QAAQ,IAAI,GAAG,aAAa,EAAE,GAAG;CAEzF,IAAI;EACF,MAAM,EAAE,iBAAiB,MAAM,OAAO;EACtC,MAAM,aAAa,MAAM,aAAa,aAAa;EACnD,MAAM,YAAY,KAAK,SAAS,QAAQ,IAAI,GAAG,UAAU;EAEzD,QAAQ,IAAI,gBAAgB,UAAU,GAAG;CAC3C,SAAS,GAAG;EACV,QAAQ,MAAM,wBAAwB,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;EAChF,QAAQ,KAAK,CAAC;CAChB;AACF;;;ACpOA,eAAsB,oBACpB,YACA,MAAM,QAAQ,IAAI,GACoB;CACtC,MAAM,qBAAqB,KAAK,WAAW,UAAU,IACjD,aACA,KAAK,QAAQ,KAAK,UAAU;CAChC,IAAI,CAAE,MAAM,WAAW,kBAAkB,GAAI,OAAO,KAAA;CAEpD,MAAM,SAAS,MAAM,mBACnB;EACE,SAAS;EACT,MAAM;EACN,WAAW;EACX,YAAY;CACd,GACA,kBACF;CACA,IAAI,CAAC,QAAQ,OAAO,KAAA;CAEpB,MAAM,UAAqB,CAAC;CAC5B,MAAM,eAAe,OAAO,OAAO,SAAS,OAAO;CAEnD,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,UAAU,iBAAiB,MAAM;EACvC,IAAI,SAAS,KAAK,OAAO,QAAQ;CACnC;AAEF;AAEA,eAAe,eACb,OACA,SACA;CACA,MAAM,WAAW,MAAM;CACvB,IAAI,CAAC,UAAU;CAEf,IAAI,MAAM,QAAQ,QAAQ,GAAG;EAC3B,KAAK,MAAM,QAAQ,UACjB,MAAM,eAAe,MAAM,OAAO;EAEpC;CACF;CAEA,QAAQ,KAAK,QAAQ;AACvB;AAEA,eAAe,WAAW,UAAoC;CAC5D,IAAI;EACF,MAAM,GAAG,SAAS,OAAO,QAAQ;EACjC,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;;;;;;;;;;;;;;;;;;;;;;;;ACZA,SAAgB,UAAU,MAA4B;CACpD,MAAM,UAAsB;EAC1B,SAAS;EACT,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,WAAW;EACX,mBAAmB;EACnB,MAAM;EACN,IAAI;EACJ,MAAM;EACN,MAAM;EACN,SAAS;CACX;CAEA,IAAI,IAAI;CAGR,IAAI,KAAK,SAAS,KAAK,CAAC,KAAK,GAAG,WAAW,GAAG,GAAG;EAC/C,MAAM,MAAM,KAAK;EACjB,IAAI,QAAQ,WAAW;GACrB,QAAQ,UAAU;GAClB,IAAI;GAEJ,IAAI,KAAK,SAAS,KAAK,CAAC,KAAK,GAAG,WAAW,GAAG,GAAG;IAC/C,QAAQ,UAAU,KAAK;IACvB,IAAI;GACN;EACF,OAAO,IAAI,QAAQ,SAAS;GAC1B,QAAQ,UAAU;GAClB,IAAI;EACN,OAAO,IAAI,QAAQ,YAAY;GAC7B,QAAQ,UAAU;GAClB,IAAI;GAEJ,IAAI,KAAK,SAAS,KAAK,CAAC,KAAK,GAAG,WAAW,GAAG,GAAG;IAC/C,QAAQ,gBAAgB,KAAK;IAC7B,IAAI;GACN;EACF;CACF;CAEA,OAAO,IAAI,KAAK,QAAQ,KAEtB,QADY,KAAK,IACjB;EACE,KAAK;EACL,KAAK;GACH,QAAQ,SAAS;GACjB;EACF,KAAK;EACL,KAAK;GACH,QAAQ,SAAS,KAAK,EAAE,MAAM;GAC9B;EACF,KAAK;EACL,KAAK;GACH,QAAQ,SAAS,KAAK,EAAE,MAAM;GAC9B;EACF,KAAK;EACL,KAAK;GACH,QAAQ,YAAY,eAAe,KAAK,EAAE,EAAE;GAC5C,QAAQ,oBAAoB;GAC5B;EACF,KAAK;GACH,QAAQ,OAAO;GACf;EACF,KAAK;GACH,QAAQ,KAAK;GACb;EACF,KAAK;GACH,QAAQ,OAAO;GACf;EACF,KAAK;EACL,KAAK;GACH,QAAQ,UAAU,KAAK,EAAE,MAAM;GAC/B;EACF,KAAK;EACL,KAAK;GACH,QAAQ,OAAO;GACf;CACJ;CAGF,OAAO;AACT;AAEA,SAAS,eAAe,OAAmC;CACzD,MAAM,YAAY,OAAO,WAAW,SAAS,EAAE;CAC/C,OAAO,OAAO,SAAS,SAAS,IAAI,YAAY;AAClD;AAEA,SAAS,YAAkB;CACzB,QAAQ,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsDb;AACD;AAEA,eAAe,OAAsB;CAEnC,MAAM,UAAU,UADH,QAAQ,KAAK,MAAM,CACH,CAAC;CAE9B,IAAI,QAAQ,MAAM;EAChB,UAAU;EACV,QAAQ,KAAK,CAAC;CAChB;CAEA,MAAM,MAAM,QAAQ,IAAI;CAExB,QAAQ,IAAI,eAAe;CAC3B,QAAQ,IAAI,eAAe;CAG3B,IAAI,QAAQ,YAAY,YAAY;EAClC,IAAI;GACF,MAAM,YAAY,OAAO;EAC3B,SAAS,OAAO;GACd,QAAQ,MAAM,cAAc,KAAK;GACjC,QAAQ,KAAK,CAAC;EAChB;EACA;CACF;CAEA,QAAQ,MAAM,MAAM,oBAAoB,QAAQ,QAAQ,GAAG;CAG3D,QAAQ,IAAI,6BAA6B;CACzC,MAAM,eAAe,MAAM,aAAa,GAAG;CAE3C,IAAI,aAAa,WAAW,GAAG;EAC7B,QAAQ,IAAI,yBAAyB;EACrC,QAAQ,KAAK,CAAC;CAChB;CAEA,QAAQ,IAAI,WAAW,aAAa,OAAO,eAAe;CAG1D,MAAM,WAA0B,CAAC;CACjC,KAAK,MAAM,YAAY,cAAc;EACnC,MAAM,MAAM,MAAM,aAAa,QAAQ;EACvC,IAAI,KACF,SAAS,KAAK,GAAG;CAErB;CAEA,IAAI;EACF,QAAQ,QAAQ,SAAhB;GACE,KAAK;IACH,MAAM,OAAO,SAAS,QAAQ;IAC9B;GACF,KAAK;IACH,MAAM,WAAW,SAAS,QAAQ;IAClC;GACF,KAAK;IACH,MAAM,SAAS,SAAS,QAAQ;IAChC;GACF,KAAK,YAEH;EACJ;CACF,SAAS,OAAO;EACd,QAAQ,MAAM,cAAc,KAAK;EACjC,QAAQ,KAAK,CAAC;CAChB;AACF;AAEA,IAAI,YAAY,GACd,KAAK,EAAE,OAAO,UAAU;CACtB,QAAQ,MAAM,gBAAgB,KAAK;CACnC,QAAQ,KAAK,CAAC;AAChB,CAAC;AAGH,SAAS,cAAuB;CAC9B,MAAM,aAAa,QAAQ,KAAK;CAChC,OAAO,aAAa,cAAc,OAAO,KAAK,GAAG,MAAM,KAAK,QAAQ,UAAU,IAAI;AACpF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as generateGalleryGlobalsScript, n as generateGalleryScript, t as generateGalleryBody } from "./template-
|
|
1
|
+
import { a as generateGalleryGlobalsScript, n as generateGalleryScript, t as generateGalleryBody } from "./template-B_y7_OsF.mjs";
|
|
2
2
|
//#region src/gallery/styles-base.css?inline
|
|
3
3
|
var styles_base_default = ":root {\n --musea-bg-primary: #e6e2d6;\n --musea-bg-secondary: #ddd9cd;\n --musea-bg-tertiary: #d4d0c4;\n --musea-bg-elevated: #e6e2d6;\n --musea-accent: #121212;\n --musea-accent-hover: #2a2a2a;\n --musea-accent-subtle: #12121214;\n --musea-text: #121212;\n --musea-text-secondary: #3a3a3a;\n --musea-text-muted: #6b6b6b;\n --musea-border: #c8c4b8;\n --musea-border-subtle: #d4d0c4;\n --musea-success: #16a34a;\n --musea-shadow: 0 4px 24px #00000014;\n --musea-radius-sm: 4px;\n --musea-radius-md: 6px;\n --musea-radius-lg: 8px;\n --musea-transition: .15s ease;\n}\n\n* {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\nbody {\n background: var(--musea-bg-primary);\n color: var(--musea-text);\n -webkit-font-smoothing: antialiased;\n min-height: 100vh;\n font-family: Helvetica Neue, Helvetica, Arial, sans-serif;\n line-height: 1.5;\n}\n";
|
|
4
4
|
//#endregion
|
|
@@ -58,4 +58,4 @@ function generateGalleryHtml(basePath, devSessionToken, themeConfig, tokenPrevie
|
|
|
58
58
|
//#endregion
|
|
59
59
|
export { generateGalleryHtml };
|
|
60
60
|
|
|
61
|
-
//# sourceMappingURL=gallery-
|
|
61
|
+
//# sourceMappingURL=gallery-DnAsudTG.mjs.map
|