@vizejs/vite-plugin-musea 0.250.0 → 0.263.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/autogen/index.d.mts.map +1 -1
- package/dist/autogen/index.mjs +1 -1
- package/dist/{autogen-Blm3Qy_O.mjs → autogen-B7_TO0n5.mjs} +63 -20
- package/dist/autogen-B7_TO0n5.mjs.map +1 -0
- package/dist/cli/index.mjs +7 -1
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.d.mts +11 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +587 -457
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/dist/autogen-Blm3Qy_O.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { c as createDevSessionToken, d as resolveInside, f as resolveInsideAny, h as validateDevApiRequest, i as generateGalleryScript, l as decodeUrlComponent, m as serializeScriptValue, n as generateGalleryModule, o as HttpError, p as resolveUrlPathInside, r as generateGalleryBody, s as collectRequestBody, u as parseJsonBody } from "./gallery-DIBlUrB6.mjs";
|
|
2
2
|
import { i as MuseaVrtRunner, n as generateVrtJsonReport, r as generateVrtReport } from "./vrt-Cv1PK1EF.mjs";
|
|
3
3
|
import { t as MuseaA11yRunner } from "./a11y-62l8G1tr.mjs";
|
|
4
|
-
import { n as writeArtFile, t as generateArtFile } from "./autogen-
|
|
4
|
+
import { n as writeArtFile, t as generateArtFile } from "./autogen-B7_TO0n5.mjs";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { transformWithEsbuild } from "vite";
|
|
7
7
|
import fs from "node:fs";
|
|
8
8
|
import path from "node:path";
|
|
9
|
-
import { vizeConfigStore } from "@vizejs/vite-plugin";
|
|
10
|
-
import crypto from "node:crypto";
|
|
11
9
|
import { fileURLToPath } from "node:url";
|
|
10
|
+
import crypto from "node:crypto";
|
|
11
|
+
import { VIZE_CONFIG_FILE_ENV, loadConfig, vizeConfigStore } from "@vizejs/vite-plugin";
|
|
12
12
|
//#region src/native-loader.ts
|
|
13
13
|
/**
|
|
14
14
|
* Native binding loader for @vizejs/native.
|
|
@@ -92,15 +92,6 @@ function analyzeSfcFallback(source, _options) {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
//#endregion
|
|
95
|
-
//#region src/component-source.ts
|
|
96
|
-
function allowedSourceRoots(root, scanRoots = []) {
|
|
97
|
-
return [...new Set([root, ...scanRoots].map((sourceRoot) => path.resolve(sourceRoot)))];
|
|
98
|
-
}
|
|
99
|
-
function resolveComponentSourcePath(art, artPath, sourceRoots) {
|
|
100
|
-
const componentPath = art.isInline && art.componentPath ? art.componentPath : art.metadata.component ? path.isAbsolute(art.metadata.component) ? art.metadata.component : path.resolve(path.dirname(artPath), art.metadata.component) : null;
|
|
101
|
-
return componentPath ? resolveInsideAny(sourceRoots, componentPath, "component path") : null;
|
|
102
|
-
}
|
|
103
|
-
//#endregion
|
|
104
95
|
//#region src/utils.ts
|
|
105
96
|
/**
|
|
106
97
|
* Shared utility functions for the Musea Vite plugin.
|
|
@@ -182,7 +173,7 @@ async function generateStorybookFiles(artFiles, root, outDir) {
|
|
|
182
173
|
const source = await fs.promises.readFile(filePath, "utf-8");
|
|
183
174
|
const csf = binding.artToCsf(source, { filename: filePath });
|
|
184
175
|
const outputPath = path.join(outputDir, csf.filename);
|
|
185
|
-
const code = rewriteStorybookComponentImport(csf.code, art, filePath, outputPath);
|
|
176
|
+
const code = rewriteStorybookScriptImports(rewriteStorybookComponentImport(csf.code, art, filePath, outputPath), filePath, outputPath);
|
|
186
177
|
await fs.promises.writeFile(outputPath, code, "utf-8");
|
|
187
178
|
console.log(`[musea] Generated: ${path.relative(root, outputPath)}`);
|
|
188
179
|
} catch (e) {
|
|
@@ -200,369 +191,50 @@ function rewriteStorybookComponentImport(code, art, artPath, outputPath) {
|
|
|
200
191
|
function isBareImport(source) {
|
|
201
192
|
return !source.startsWith(".") && !path.isAbsolute(source);
|
|
202
193
|
}
|
|
203
|
-
function toPascalCase(str) {
|
|
204
|
-
const pascal = str.normalize("NFKD").replace(/[^\p{L}\p{N}]+/gu, " ").trim().split(/\s+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
205
|
-
if (!pascal) return "Variant";
|
|
206
|
-
return /^[\p{L}_$]/u.test(pascal) ? pascal : `Variant${pascal}`;
|
|
207
|
-
}
|
|
208
|
-
function escapeHtml(str) {
|
|
209
|
-
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
210
|
-
}
|
|
211
194
|
/**
|
|
212
|
-
*
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (!theme) return void 0;
|
|
216
|
-
if (typeof theme === "string") return { default: theme };
|
|
217
|
-
const themes = Array.isArray(theme) ? theme : [theme];
|
|
218
|
-
const custom = {};
|
|
219
|
-
for (const t of themes) custom[t.name] = {
|
|
220
|
-
base: t.base,
|
|
221
|
-
colors: t.colors
|
|
222
|
-
};
|
|
223
|
-
return {
|
|
224
|
-
default: themes[0].name,
|
|
225
|
-
custom
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
//#endregion
|
|
229
|
-
//#region src/art-module.ts
|
|
230
|
-
/**
|
|
231
|
-
* Art module generation for Musea.
|
|
195
|
+
* Rewrite relative import specifiers in the generated Storybook CSF file so that
|
|
196
|
+
* imports lifted verbatim from the art file's `<script setup>` resolve against
|
|
197
|
+
* the generated file's location instead of the original art file's directory.
|
|
232
198
|
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*/
|
|
236
|
-
/**
|
|
237
|
-
* Extract the content of the first <script setup> block from a Vue SFC source.
|
|
238
|
-
*/
|
|
239
|
-
function extractScriptSetupContent(source) {
|
|
240
|
-
return source.match(/<script\s+[^>]*setup[^>]*>([\s\S]*?)<\/script>/)?.[1]?.trim();
|
|
241
|
-
}
|
|
242
|
-
function extractScriptSetupIsolated(source) {
|
|
243
|
-
const match = source.match(/<script\s+([^>]*)\bsetup\b([^>]*)>/);
|
|
244
|
-
if (!match) return true;
|
|
245
|
-
const isolate = `${match[1] ?? ""} ${match[2] ?? ""}`.match(/\bisolate\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/);
|
|
246
|
-
return (isolate?.[1] ?? isolate?.[2] ?? isolate?.[3]) !== "false";
|
|
247
|
-
}
|
|
248
|
-
function resolveRelativeSpecifier(specifier, artDir) {
|
|
249
|
-
if (!specifier.startsWith(".")) return specifier;
|
|
250
|
-
return path.resolve(artDir, specifier);
|
|
251
|
-
}
|
|
252
|
-
function rewriteRelativeImportStatement(statement, artDir) {
|
|
253
|
-
return statement.replace(/\bfrom\s+(['"])([^'"]+)\1/g, (_match, quote, specifier) => `from ${quote}${resolveRelativeSpecifier(specifier, artDir)}${quote}`).replace(/^(\s*import\s+)(['"])([^'"]+)\2(\s*;?\s*)$/s, (_match, prefix, quote, specifier, suffix) => `${prefix}${quote}${resolveRelativeSpecifier(specifier, artDir)}${quote}${suffix}`);
|
|
254
|
-
}
|
|
255
|
-
function escapeTemplateLiteral(str) {
|
|
256
|
-
return str.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$");
|
|
257
|
-
}
|
|
258
|
-
function countCharBalance(source, openChar, closeChar) {
|
|
259
|
-
let balance = 0;
|
|
260
|
-
for (const char of source) if (char === openChar) balance++;
|
|
261
|
-
else if (char === closeChar) balance--;
|
|
262
|
-
return balance;
|
|
263
|
-
}
|
|
264
|
-
function isCompleteImportStatement(statement) {
|
|
265
|
-
const trimmed = statement.trim();
|
|
266
|
-
if (!trimmed.startsWith("import ")) return false;
|
|
267
|
-
if (countCharBalance(statement, "{", "}") > 0) return false;
|
|
268
|
-
return /^import\s+[\s\S]+?\s+from\s+['"][^'"]+['"]\s*;?$/s.test(trimmed) || /^import\s+['"][^'"]+['"]\s*;?$/s.test(trimmed);
|
|
269
|
-
}
|
|
270
|
-
function splitTopLevelCommaList(source) {
|
|
271
|
-
const parts = [];
|
|
272
|
-
let current = "";
|
|
273
|
-
let braceDepth = 0;
|
|
274
|
-
let bracketDepth = 0;
|
|
275
|
-
let parenDepth = 0;
|
|
276
|
-
for (const char of source) {
|
|
277
|
-
if (char === "," && braceDepth === 0 && bracketDepth === 0 && parenDepth === 0) {
|
|
278
|
-
const trimmed = current.trim();
|
|
279
|
-
if (trimmed) parts.push(trimmed);
|
|
280
|
-
current = "";
|
|
281
|
-
continue;
|
|
282
|
-
}
|
|
283
|
-
current += char;
|
|
284
|
-
if (char === "{") braceDepth++;
|
|
285
|
-
else if (char === "}") braceDepth--;
|
|
286
|
-
else if (char === "[") bracketDepth++;
|
|
287
|
-
else if (char === "]") bracketDepth--;
|
|
288
|
-
else if (char === "(") parenDepth++;
|
|
289
|
-
else if (char === ")") parenDepth--;
|
|
290
|
-
}
|
|
291
|
-
const trimmed = current.trim();
|
|
292
|
-
if (trimmed) parts.push(trimmed);
|
|
293
|
-
return parts;
|
|
294
|
-
}
|
|
295
|
-
function collectImportedNames(statement, returnNames) {
|
|
296
|
-
const fromMatch = statement.replace(/\s+/g, " ").trim().replace(/;$/, "").match(/^import\s+(type\s+)?(.+?)\s+from\s+['"][^'"]+['"]$/);
|
|
297
|
-
if (!fromMatch) return;
|
|
298
|
-
if (fromMatch[1]) return;
|
|
299
|
-
const specifierParts = splitTopLevelCommaList(fromMatch[2].trim());
|
|
300
|
-
const defaultOrNamespace = specifierParts[0]?.trim() ?? "";
|
|
301
|
-
const trailing = specifierParts.slice(1).join(", ").trim();
|
|
302
|
-
if (defaultOrNamespace && !defaultOrNamespace.startsWith("{")) {
|
|
303
|
-
const namespaceMatch = defaultOrNamespace.match(/^\*\s+as\s+([A-Za-z_$][\w$]*)$/);
|
|
304
|
-
if (namespaceMatch) returnNames.add(namespaceMatch[1]);
|
|
305
|
-
else if (!defaultOrNamespace.startsWith("type ")) returnNames.add(defaultOrNamespace);
|
|
306
|
-
}
|
|
307
|
-
const namedBlock = defaultOrNamespace.startsWith("{") ? defaultOrNamespace : trailing.startsWith("{") ? trailing : "";
|
|
308
|
-
if (!namedBlock) return;
|
|
309
|
-
const namedContent = namedBlock.slice(1, -1);
|
|
310
|
-
for (const part of splitTopLevelCommaList(namedContent)) {
|
|
311
|
-
const trimmed = part.trim();
|
|
312
|
-
if (!trimmed || trimmed.startsWith("type ")) continue;
|
|
313
|
-
const alias = trimmed.split(/\s+as\s+/).pop()?.trim();
|
|
314
|
-
if (alias) returnNames.add(alias);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
function importDeclaresName(statement, name) {
|
|
318
|
-
const names = /* @__PURE__ */ new Set();
|
|
319
|
-
collectImportedNames(statement, names);
|
|
320
|
-
return names.has(name);
|
|
321
|
-
}
|
|
322
|
-
function collectObjectDestructuredNames(statement, returnNames) {
|
|
323
|
-
const match = statement.match(/^(?:export\s+)?(?:const|let|var)\s+\{([\s\S]*?)\}\s*=/);
|
|
324
|
-
if (!match) return;
|
|
325
|
-
for (const part of splitTopLevelCommaList(match[1])) {
|
|
326
|
-
let name = part.trim();
|
|
327
|
-
if (!name) continue;
|
|
328
|
-
if (name.startsWith("...")) name = name.slice(3).trim();
|
|
329
|
-
else if (name.includes(":")) name = name.split(":").pop().trim();
|
|
330
|
-
else if (name.includes("=")) name = name.split("=")[0].trim();
|
|
331
|
-
if (name.includes("=")) name = name.split("=")[0].trim();
|
|
332
|
-
if (/^[A-Za-z_$][\w$]*$/.test(name)) returnNames.add(name);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
function collectArrayDestructuredNames(statement, returnNames) {
|
|
336
|
-
const match = statement.match(/^(?:export\s+)?(?:const|let|var)\s+\[([\s\S]*?)\]\s*=/);
|
|
337
|
-
if (!match) return;
|
|
338
|
-
for (const part of splitTopLevelCommaList(match[1])) {
|
|
339
|
-
let name = part.trim();
|
|
340
|
-
if (!name) continue;
|
|
341
|
-
if (name.startsWith("...")) name = name.slice(3).trim();
|
|
342
|
-
if (name.includes("=")) name = name.split("=")[0].trim();
|
|
343
|
-
if (/^[A-Za-z_$][\w$]*$/.test(name)) returnNames.add(name);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
function collectTopLevelReturnNames(setupBody, returnNames) {
|
|
347
|
-
let braceDepth = 0;
|
|
348
|
-
for (let i = 0; i < setupBody.length; i++) {
|
|
349
|
-
const line = setupBody[i];
|
|
350
|
-
const trimmed = line.trim();
|
|
351
|
-
if (braceDepth === 0) {
|
|
352
|
-
if (/^(?:export\s+)?(?:const|let|var)\s+\{/.test(trimmed)) {
|
|
353
|
-
const statementLines = [line];
|
|
354
|
-
let balance = countCharBalance(line, "{", "}") + countCharBalance(line, "[", "]") + countCharBalance(line, "(", ")");
|
|
355
|
-
while (balance > 0 && i + 1 < setupBody.length) {
|
|
356
|
-
i++;
|
|
357
|
-
statementLines.push(setupBody[i]);
|
|
358
|
-
balance += countCharBalance(setupBody[i], "{", "}") + countCharBalance(setupBody[i], "[", "]") + countCharBalance(setupBody[i], "(", ")");
|
|
359
|
-
}
|
|
360
|
-
collectObjectDestructuredNames(statementLines.join("\n"), returnNames);
|
|
361
|
-
continue;
|
|
362
|
-
}
|
|
363
|
-
if (/^(?:export\s+)?(?:const|let|var)\s+\[/.test(trimmed)) {
|
|
364
|
-
const statementLines = [line];
|
|
365
|
-
let balance = countCharBalance(line, "{", "}") + countCharBalance(line, "[", "]") + countCharBalance(line, "(", ")");
|
|
366
|
-
while (balance > 0 && i + 1 < setupBody.length) {
|
|
367
|
-
i++;
|
|
368
|
-
statementLines.push(setupBody[i]);
|
|
369
|
-
balance += countCharBalance(setupBody[i], "{", "}") + countCharBalance(setupBody[i], "[", "]") + countCharBalance(setupBody[i], "(", ")");
|
|
370
|
-
}
|
|
371
|
-
collectArrayDestructuredNames(statementLines.join("\n"), returnNames);
|
|
372
|
-
continue;
|
|
373
|
-
}
|
|
374
|
-
const constMatch = trimmed.match(/^(?:export\s+)?(?:const|let|var)\s+([A-Za-z_$][\w$]*)/);
|
|
375
|
-
if (constMatch) returnNames.add(constMatch[1]);
|
|
376
|
-
const functionMatch = trimmed.match(/^(?:export\s+)?(?:async\s+)?function\s+([A-Za-z_$][\w$]*)\s*\(/);
|
|
377
|
-
if (functionMatch) returnNames.add(functionMatch[1]);
|
|
378
|
-
const classMatch = trimmed.match(/^(?:export\s+)?class\s+([A-Za-z_$][\w$]*)\b/);
|
|
379
|
-
if (classMatch) returnNames.add(classMatch[1]);
|
|
380
|
-
}
|
|
381
|
-
braceDepth += countCharBalance(line, "{", "}");
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
/**
|
|
385
|
-
* Parse script setup content into imports and setup body.
|
|
386
|
-
* Returns the import lines, setup body lines, and all identifiers to expose.
|
|
199
|
+
* The `__museaComponent` import is already rebased by
|
|
200
|
+
* `rewriteStorybookComponentImport` and is skipped here.
|
|
387
201
|
*/
|
|
388
|
-
function
|
|
389
|
-
const
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
defineArtBalance += countCharBalance(line, "(", ")");
|
|
400
|
-
continue;
|
|
401
|
-
}
|
|
402
|
-
if (currentImport) {
|
|
403
|
-
currentImport.push(line);
|
|
404
|
-
const statement = currentImport.join("\n");
|
|
405
|
-
if (isCompleteImportStatement(statement)) {
|
|
406
|
-
imports.push(statement);
|
|
407
|
-
collectImportedNames(statement, returnNames);
|
|
408
|
-
currentImport = null;
|
|
409
|
-
}
|
|
410
|
-
continue;
|
|
411
|
-
}
|
|
412
|
-
if (trimmed.startsWith("import ")) {
|
|
413
|
-
currentImport = [line];
|
|
414
|
-
const statement = currentImport.join("\n");
|
|
415
|
-
if (isCompleteImportStatement(statement)) {
|
|
416
|
-
imports.push(statement);
|
|
417
|
-
collectImportedNames(statement, returnNames);
|
|
418
|
-
currentImport = null;
|
|
419
|
-
}
|
|
420
|
-
continue;
|
|
421
|
-
}
|
|
422
|
-
if (isDefineArtLine(trimmed)) {
|
|
423
|
-
defineArtBalance = Math.max(0, countCharBalance(line, "(", ")"));
|
|
424
|
-
continue;
|
|
425
|
-
}
|
|
426
|
-
setupBody.push(line);
|
|
427
|
-
}
|
|
428
|
-
if (currentImport) {
|
|
429
|
-
const statement = currentImport.join("\n");
|
|
430
|
-
imports.push(statement);
|
|
431
|
-
collectImportedNames(statement, returnNames);
|
|
432
|
-
}
|
|
433
|
-
collectTopLevelReturnNames(setupBody, returnNames);
|
|
434
|
-
returnNames.delete("type");
|
|
435
|
-
if (defineArtComponent.name) returnNames.delete(defineArtComponent.name);
|
|
436
|
-
return {
|
|
437
|
-
imports,
|
|
438
|
-
setupBody,
|
|
439
|
-
returnNames: [...returnNames],
|
|
440
|
-
defineArtComponentName: defineArtComponent.name,
|
|
441
|
-
defineArtComponentSource: defineArtComponent.source
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
function extractDefineArtComponent(content) {
|
|
445
|
-
const sourceMatch = content.match(/\bdefineArt\s*\(\s*(['"])([^'"]+)\1/);
|
|
446
|
-
if (sourceMatch) return {
|
|
447
|
-
name: componentNameFromSource(sourceMatch[2]),
|
|
448
|
-
source: sourceMatch[2]
|
|
449
|
-
};
|
|
450
|
-
return { name: content.match(/\bdefineArt\s*\(\s*([A-Za-z_$][\w$]*)/)?.[1] };
|
|
451
|
-
}
|
|
452
|
-
function componentNameFromSource(source) {
|
|
453
|
-
const withoutQuery = source.split(/[?#]/, 1)[0] || source;
|
|
454
|
-
const filename = path.basename(withoutQuery);
|
|
455
|
-
const extension = path.extname(filename);
|
|
456
|
-
const name = toPascalCase(extension ? filename.slice(0, -extension.length) : filename);
|
|
457
|
-
return name === "Variant" ? "MuseaComponent" : name;
|
|
202
|
+
function rewriteStorybookScriptImports(code, artPath, outputPath) {
|
|
203
|
+
const artDir = path.dirname(artPath);
|
|
204
|
+
const outDir = path.dirname(outputPath);
|
|
205
|
+
return code.replace(/(import\s+(?:[\s\S]*?)\s+from\s+)(['"])([^'"]+)\2(\s*;?)/g, (match, head, quote, specifier, tail) => {
|
|
206
|
+
if (!specifier.startsWith(".")) return match;
|
|
207
|
+
if (/\b__museaComponent\b/.test(head)) return match;
|
|
208
|
+
const resolved = path.resolve(artDir, specifier);
|
|
209
|
+
let rebased = normalizeGlobPath(path.relative(outDir, resolved));
|
|
210
|
+
if (!rebased.startsWith(".")) rebased = `./${rebased}`;
|
|
211
|
+
return `${head}${quote}${rebased}${quote}${tail}`;
|
|
212
|
+
});
|
|
458
213
|
}
|
|
459
|
-
function
|
|
460
|
-
|
|
214
|
+
function toPascalCase(str) {
|
|
215
|
+
const pascal = str.normalize("NFKD").replace(/[^\p{L}\p{N}]+/gu, " ").trim().split(/\s+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
216
|
+
if (!pascal) return "Variant";
|
|
217
|
+
return /^[\p{L}_$]/u.test(pascal) ? pascal : `Variant${pascal}`;
|
|
461
218
|
}
|
|
462
|
-
function
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
if (
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
};
|
|
482
|
-
componentImportPath = options.root ? resolveComponentSourcePath(sourceArt, filePath, allowedSourceRoots(options.root, options.scanRoots ?? [])) ?? void 0 : path.isAbsolute(componentSource) ? componentSource : path.resolve(path.dirname(filePath), componentSource);
|
|
483
|
-
}
|
|
484
|
-
componentTagName = defineArtComponentName ?? (art.metadata.component ? componentNameFromSource(art.metadata.component) : "MuseaComponent");
|
|
485
|
-
componentBindingName = componentTagName;
|
|
486
|
-
}
|
|
487
|
-
let code = `
|
|
488
|
-
// Auto-generated module for: ${path.basename(filePath)}
|
|
489
|
-
import { defineComponent, h } from 'vue';
|
|
490
|
-
`;
|
|
491
|
-
if (scriptSetup) {
|
|
492
|
-
const artDir = path.dirname(filePath);
|
|
493
|
-
for (const imp of scriptSetup.imports) {
|
|
494
|
-
const resolved = rewriteRelativeImportStatement(imp, artDir);
|
|
495
|
-
code += `${resolved}\n`;
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
if (componentImportPath && componentTagName) {
|
|
499
|
-
if (!scriptSetup?.imports.some((imp) => importDeclaresName(imp, componentBindingName))) code += `import ${componentBindingName} from ${JSON.stringify(componentImportPath)};\n`;
|
|
500
|
-
code += `export const __component__ = ${componentBindingName};\n`;
|
|
501
|
-
}
|
|
502
|
-
code += `
|
|
503
|
-
export const metadata = ${JSON.stringify(art.metadata)};
|
|
504
|
-
export const variants = ${JSON.stringify(art.variants)};
|
|
505
|
-
export const __styles__ = ${JSON.stringify(art.styleBlocks ?? [])};
|
|
506
|
-
`;
|
|
507
|
-
const hasSetupBody = scriptSetup?.setupBody.some((line) => line.trim().length > 0) ?? false;
|
|
508
|
-
const hasSetup = !!scriptSetup && (hasSetupBody || scriptSetup.returnNames.length > 0);
|
|
509
|
-
const setupReturn = `{ ${scriptSetup?.returnNames.join(", ") ?? ""} }`;
|
|
510
|
-
const isolatedSetup = art.scriptSetupIsolated !== false;
|
|
511
|
-
if (scriptSetup && hasSetup && !isolatedSetup) code += `
|
|
512
|
-
const __museaSharedSetup = (() => {
|
|
513
|
-
${scriptSetup.setupBody.map((l) => ` ${l}`).join("\n")}
|
|
514
|
-
return ${setupReturn};
|
|
515
|
-
})();
|
|
516
|
-
`;
|
|
517
|
-
for (const variant of art.variants) {
|
|
518
|
-
const variantComponentName = toPascalCase(variant.name);
|
|
519
|
-
let template = variant.template;
|
|
520
|
-
if (componentTagName) template = template.replace(/<Self/g, `<${componentTagName}`).replace(/<\/Self>/g, `</${componentTagName}>`);
|
|
521
|
-
const escapedTemplate = escapeTemplateLiteral(template);
|
|
522
|
-
const fullTemplate = `<div data-variant="${escapeTemplateLiteral(escapeHtml(variant.name))}">${escapedTemplate}</div>`;
|
|
523
|
-
const componentNames = /* @__PURE__ */ new Map();
|
|
524
|
-
if (componentTagName) componentNames.set(componentTagName, componentBindingName);
|
|
525
|
-
if (scriptSetup) {
|
|
526
|
-
for (const name of scriptSetup.returnNames) if (/^[A-Z]/.test(name)) componentNames.set(name, name);
|
|
527
|
-
}
|
|
528
|
-
const components = componentNames.size > 0 ? ` components: { ${[...componentNames].map(([name, value]) => `${JSON.stringify(name)}: ${value}`).join(", ")} },\n` : "";
|
|
529
|
-
if (scriptSetup && hasSetup && isolatedSetup) code += `
|
|
530
|
-
export const ${variantComponentName} = defineComponent({
|
|
531
|
-
name: '${variantComponentName}',
|
|
532
|
-
${components} setup() {
|
|
533
|
-
${scriptSetup.setupBody.map((l) => ` ${l}`).join("\n")}
|
|
534
|
-
return ${setupReturn};
|
|
535
|
-
},
|
|
536
|
-
template: \`${fullTemplate}\`,
|
|
537
|
-
});
|
|
538
|
-
`;
|
|
539
|
-
else if (scriptSetup && hasSetup) code += `
|
|
540
|
-
export const ${variantComponentName} = defineComponent({
|
|
541
|
-
name: '${variantComponentName}',
|
|
542
|
-
${components} setup() {
|
|
543
|
-
return __museaSharedSetup;
|
|
544
|
-
},
|
|
545
|
-
template: \`${fullTemplate}\`,
|
|
546
|
-
});
|
|
547
|
-
`;
|
|
548
|
-
else if (componentTagName) code += `
|
|
549
|
-
export const ${variantComponentName} = {
|
|
550
|
-
name: '${variantComponentName}',
|
|
551
|
-
${components} template: \`${fullTemplate}\`,
|
|
552
|
-
};
|
|
553
|
-
`;
|
|
554
|
-
else code += `
|
|
555
|
-
export const ${variantComponentName} = {
|
|
556
|
-
name: '${variantComponentName}',
|
|
557
|
-
template: \`${fullTemplate}\`,
|
|
558
|
-
};
|
|
559
|
-
`;
|
|
560
|
-
}
|
|
561
|
-
const defaultVariant = art.variants.find((v) => v.isDefault) || art.variants[0];
|
|
562
|
-
if (defaultVariant) code += `
|
|
563
|
-
export default ${toPascalCase(defaultVariant.name)};
|
|
564
|
-
`;
|
|
565
|
-
return code;
|
|
219
|
+
function escapeHtml(str) {
|
|
220
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Build the theme config object from plugin options for runtime injection.
|
|
224
|
+
*/
|
|
225
|
+
function buildThemeConfig(theme) {
|
|
226
|
+
if (!theme) return void 0;
|
|
227
|
+
if (typeof theme === "string") return { default: theme };
|
|
228
|
+
const themes = Array.isArray(theme) ? theme : [theme];
|
|
229
|
+
const custom = {};
|
|
230
|
+
for (const t of themes) custom[t.name] = {
|
|
231
|
+
base: t.base,
|
|
232
|
+
colors: t.colors
|
|
233
|
+
};
|
|
234
|
+
return {
|
|
235
|
+
default: themes[0].name,
|
|
236
|
+
custom
|
|
237
|
+
};
|
|
566
238
|
}
|
|
567
239
|
//#endregion
|
|
568
240
|
//#region src/preview/addons.ts
|
|
@@ -1181,53 +853,401 @@ function ensureArtStyles(styles) {
|
|
|
1181
853
|
document.head.appendChild(tag);
|
|
1182
854
|
}
|
|
1183
855
|
}
|
|
1184
|
-
|
|
1185
|
-
function renderError(title, error) {
|
|
1186
|
-
container.textContent = '';
|
|
1187
|
-
const root = document.createElement('div');
|
|
1188
|
-
root.className = 'musea-error';
|
|
1189
|
-
|
|
1190
|
-
const titleEl = document.createElement('div');
|
|
1191
|
-
titleEl.className = 'musea-error-title';
|
|
1192
|
-
titleEl.textContent = title;
|
|
1193
|
-
root.appendChild(titleEl);
|
|
1194
|
-
|
|
1195
|
-
const messageEl = document.createElement('div');
|
|
1196
|
-
messageEl.textContent = error instanceof Error ? error.message : String(error);
|
|
1197
|
-
root.appendChild(messageEl);
|
|
1198
|
-
|
|
1199
|
-
container.appendChild(root);
|
|
856
|
+
|
|
857
|
+
function renderError(title, error) {
|
|
858
|
+
container.textContent = '';
|
|
859
|
+
const root = document.createElement('div');
|
|
860
|
+
root.className = 'musea-error';
|
|
861
|
+
|
|
862
|
+
const titleEl = document.createElement('div');
|
|
863
|
+
titleEl.className = 'musea-error-title';
|
|
864
|
+
titleEl.textContent = title;
|
|
865
|
+
root.appendChild(titleEl);
|
|
866
|
+
|
|
867
|
+
const messageEl = document.createElement('div');
|
|
868
|
+
messageEl.textContent = error instanceof Error ? error.message : String(error);
|
|
869
|
+
root.appendChild(messageEl);
|
|
870
|
+
|
|
871
|
+
container.appendChild(root);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
async function mount() {
|
|
875
|
+
try {
|
|
876
|
+
const VariantComponent = artModule[${variantComponentNameLiteral}];
|
|
877
|
+
if (!VariantComponent) {
|
|
878
|
+
throw new Error('Variant component ' + ${variantComponentNameLiteral} + ' not found');
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
const WrappedComponent = {
|
|
882
|
+
render() {
|
|
883
|
+
return h(VariantComponent, propsOverride);
|
|
884
|
+
}
|
|
885
|
+
};
|
|
886
|
+
|
|
887
|
+
const app = createApp(WrappedComponent);
|
|
888
|
+
ensureArtStyles(artModule.__styles__);
|
|
889
|
+
${setupCall}
|
|
890
|
+
container.innerHTML = '';
|
|
891
|
+
container.className = 'musea-variant';
|
|
892
|
+
app.mount(container);
|
|
893
|
+
console.log('[musea-preview] Mounted variant with props override:', ${variantNameLiteral});
|
|
894
|
+
__museaInitAddons(container, ${variantNameLiteral}, ${actionEvents});
|
|
895
|
+
} catch (error) {
|
|
896
|
+
console.error('[musea-preview] Failed to mount:', error);
|
|
897
|
+
renderError('Failed to render', error);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
mount();
|
|
902
|
+
`;
|
|
903
|
+
}
|
|
904
|
+
//#endregion
|
|
905
|
+
//#region src/component-source.ts
|
|
906
|
+
function allowedSourceRoots(root, scanRoots = []) {
|
|
907
|
+
return [...new Set([root, ...scanRoots].map((sourceRoot) => path.resolve(sourceRoot)))];
|
|
908
|
+
}
|
|
909
|
+
function resolveComponentSourcePath(art, artPath, sourceRoots) {
|
|
910
|
+
const componentPath = art.isInline && art.componentPath ? art.componentPath : art.metadata.component ? path.isAbsolute(art.metadata.component) ? art.metadata.component : path.resolve(path.dirname(artPath), art.metadata.component) : null;
|
|
911
|
+
return componentPath ? resolveInsideAny(sourceRoots, componentPath, "component path") : null;
|
|
912
|
+
}
|
|
913
|
+
//#endregion
|
|
914
|
+
//#region src/art-module.ts
|
|
915
|
+
/**
|
|
916
|
+
* Art module generation for Musea.
|
|
917
|
+
*
|
|
918
|
+
* Generates the virtual ES modules that represent parsed `.art.vue` files,
|
|
919
|
+
* including variant component definitions and script setup handling.
|
|
920
|
+
*/
|
|
921
|
+
/**
|
|
922
|
+
* Extract the content of the first <script setup> block from a Vue SFC source.
|
|
923
|
+
*/
|
|
924
|
+
function extractScriptSetupContent(source) {
|
|
925
|
+
return source.match(/<script\s+[^>]*setup[^>]*>([\s\S]*?)<\/script>/)?.[1]?.trim();
|
|
926
|
+
}
|
|
927
|
+
function extractScriptSetupIsolated(source) {
|
|
928
|
+
const match = source.match(/<script\s+([^>]*)\bsetup\b([^>]*)>/);
|
|
929
|
+
if (!match) return true;
|
|
930
|
+
const isolate = `${match[1] ?? ""} ${match[2] ?? ""}`.match(/\bisolate\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/);
|
|
931
|
+
return (isolate?.[1] ?? isolate?.[2] ?? isolate?.[3]) !== "false";
|
|
932
|
+
}
|
|
933
|
+
function resolveRelativeSpecifier(specifier, artDir) {
|
|
934
|
+
if (!specifier.startsWith(".")) return specifier;
|
|
935
|
+
return path.resolve(artDir, specifier);
|
|
936
|
+
}
|
|
937
|
+
function rewriteRelativeImportStatement(statement, artDir) {
|
|
938
|
+
return statement.replace(/\bfrom\s+(['"])([^'"]+)\1/g, (_match, quote, specifier) => `from ${quote}${resolveRelativeSpecifier(specifier, artDir)}${quote}`).replace(/^(\s*import\s+)(['"])([^'"]+)\2(\s*;?\s*)$/s, (_match, prefix, quote, specifier, suffix) => `${prefix}${quote}${resolveRelativeSpecifier(specifier, artDir)}${quote}${suffix}`);
|
|
939
|
+
}
|
|
940
|
+
function escapeTemplateLiteral(str) {
|
|
941
|
+
return str.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$");
|
|
942
|
+
}
|
|
943
|
+
function countCharBalance(source, openChar, closeChar) {
|
|
944
|
+
let balance = 0;
|
|
945
|
+
for (const char of source) if (char === openChar) balance++;
|
|
946
|
+
else if (char === closeChar) balance--;
|
|
947
|
+
return balance;
|
|
948
|
+
}
|
|
949
|
+
function isCompleteImportStatement(statement) {
|
|
950
|
+
const trimmed = statement.trim();
|
|
951
|
+
if (!trimmed.startsWith("import ")) return false;
|
|
952
|
+
if (countCharBalance(statement, "{", "}") > 0) return false;
|
|
953
|
+
return /^import\s+[\s\S]+?\s+from\s+['"][^'"]+['"]\s*;?$/s.test(trimmed) || /^import\s+['"][^'"]+['"]\s*;?$/s.test(trimmed);
|
|
954
|
+
}
|
|
955
|
+
function splitTopLevelCommaList(source) {
|
|
956
|
+
const parts = [];
|
|
957
|
+
let current = "";
|
|
958
|
+
let braceDepth = 0;
|
|
959
|
+
let bracketDepth = 0;
|
|
960
|
+
let parenDepth = 0;
|
|
961
|
+
for (const char of source) {
|
|
962
|
+
if (char === "," && braceDepth === 0 && bracketDepth === 0 && parenDepth === 0) {
|
|
963
|
+
const trimmed = current.trim();
|
|
964
|
+
if (trimmed) parts.push(trimmed);
|
|
965
|
+
current = "";
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
current += char;
|
|
969
|
+
if (char === "{") braceDepth++;
|
|
970
|
+
else if (char === "}") braceDepth--;
|
|
971
|
+
else if (char === "[") bracketDepth++;
|
|
972
|
+
else if (char === "]") bracketDepth--;
|
|
973
|
+
else if (char === "(") parenDepth++;
|
|
974
|
+
else if (char === ")") parenDepth--;
|
|
975
|
+
}
|
|
976
|
+
const trimmed = current.trim();
|
|
977
|
+
if (trimmed) parts.push(trimmed);
|
|
978
|
+
return parts;
|
|
979
|
+
}
|
|
980
|
+
function collectImportedNames(statement, returnNames) {
|
|
981
|
+
const fromMatch = statement.replace(/\s+/g, " ").trim().replace(/;$/, "").match(/^import\s+(type\s+)?(.+?)\s+from\s+['"][^'"]+['"]$/);
|
|
982
|
+
if (!fromMatch) return;
|
|
983
|
+
if (fromMatch[1]) return;
|
|
984
|
+
const specifierParts = splitTopLevelCommaList(fromMatch[2].trim());
|
|
985
|
+
const defaultOrNamespace = specifierParts[0]?.trim() ?? "";
|
|
986
|
+
const trailing = specifierParts.slice(1).join(", ").trim();
|
|
987
|
+
if (defaultOrNamespace && !defaultOrNamespace.startsWith("{")) {
|
|
988
|
+
const namespaceMatch = defaultOrNamespace.match(/^\*\s+as\s+([A-Za-z_$][\w$]*)$/);
|
|
989
|
+
if (namespaceMatch) returnNames.add(namespaceMatch[1]);
|
|
990
|
+
else if (!defaultOrNamespace.startsWith("type ")) returnNames.add(defaultOrNamespace);
|
|
991
|
+
}
|
|
992
|
+
const namedBlock = defaultOrNamespace.startsWith("{") ? defaultOrNamespace : trailing.startsWith("{") ? trailing : "";
|
|
993
|
+
if (!namedBlock) return;
|
|
994
|
+
const namedContent = namedBlock.slice(1, -1);
|
|
995
|
+
for (const part of splitTopLevelCommaList(namedContent)) {
|
|
996
|
+
const trimmed = part.trim();
|
|
997
|
+
if (!trimmed || trimmed.startsWith("type ")) continue;
|
|
998
|
+
const alias = trimmed.split(/\s+as\s+/).pop()?.trim();
|
|
999
|
+
if (alias) returnNames.add(alias);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
function importDeclaresName(statement, name) {
|
|
1003
|
+
const names = /* @__PURE__ */ new Set();
|
|
1004
|
+
collectImportedNames(statement, names);
|
|
1005
|
+
return names.has(name);
|
|
1006
|
+
}
|
|
1007
|
+
function collectObjectDestructuredNames(statement, returnNames) {
|
|
1008
|
+
const match = statement.match(/^(?:export\s+)?(?:const|let|var)\s+\{([\s\S]*?)\}\s*=/);
|
|
1009
|
+
if (!match) return;
|
|
1010
|
+
for (const part of splitTopLevelCommaList(match[1])) {
|
|
1011
|
+
let name = part.trim();
|
|
1012
|
+
if (!name) continue;
|
|
1013
|
+
if (name.startsWith("...")) name = name.slice(3).trim();
|
|
1014
|
+
else if (name.includes(":")) name = name.split(":").pop().trim();
|
|
1015
|
+
else if (name.includes("=")) name = name.split("=")[0].trim();
|
|
1016
|
+
if (name.includes("=")) name = name.split("=")[0].trim();
|
|
1017
|
+
if (/^[A-Za-z_$][\w$]*$/.test(name)) returnNames.add(name);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
function collectArrayDestructuredNames(statement, returnNames) {
|
|
1021
|
+
const match = statement.match(/^(?:export\s+)?(?:const|let|var)\s+\[([\s\S]*?)\]\s*=/);
|
|
1022
|
+
if (!match) return;
|
|
1023
|
+
for (const part of splitTopLevelCommaList(match[1])) {
|
|
1024
|
+
let name = part.trim();
|
|
1025
|
+
if (!name) continue;
|
|
1026
|
+
if (name.startsWith("...")) name = name.slice(3).trim();
|
|
1027
|
+
if (name.includes("=")) name = name.split("=")[0].trim();
|
|
1028
|
+
if (/^[A-Za-z_$][\w$]*$/.test(name)) returnNames.add(name);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
function collectTopLevelReturnNames(setupBody, returnNames) {
|
|
1032
|
+
let braceDepth = 0;
|
|
1033
|
+
for (let i = 0; i < setupBody.length; i++) {
|
|
1034
|
+
const line = setupBody[i];
|
|
1035
|
+
const trimmed = line.trim();
|
|
1036
|
+
if (braceDepth === 0) {
|
|
1037
|
+
if (/^(?:export\s+)?(?:const|let|var)\s+\{/.test(trimmed)) {
|
|
1038
|
+
const statementLines = [line];
|
|
1039
|
+
let balance = countCharBalance(line, "{", "}") + countCharBalance(line, "[", "]") + countCharBalance(line, "(", ")");
|
|
1040
|
+
while (balance > 0 && i + 1 < setupBody.length) {
|
|
1041
|
+
i++;
|
|
1042
|
+
statementLines.push(setupBody[i]);
|
|
1043
|
+
balance += countCharBalance(setupBody[i], "{", "}") + countCharBalance(setupBody[i], "[", "]") + countCharBalance(setupBody[i], "(", ")");
|
|
1044
|
+
}
|
|
1045
|
+
collectObjectDestructuredNames(statementLines.join("\n"), returnNames);
|
|
1046
|
+
continue;
|
|
1047
|
+
}
|
|
1048
|
+
if (/^(?:export\s+)?(?:const|let|var)\s+\[/.test(trimmed)) {
|
|
1049
|
+
const statementLines = [line];
|
|
1050
|
+
let balance = countCharBalance(line, "{", "}") + countCharBalance(line, "[", "]") + countCharBalance(line, "(", ")");
|
|
1051
|
+
while (balance > 0 && i + 1 < setupBody.length) {
|
|
1052
|
+
i++;
|
|
1053
|
+
statementLines.push(setupBody[i]);
|
|
1054
|
+
balance += countCharBalance(setupBody[i], "{", "}") + countCharBalance(setupBody[i], "[", "]") + countCharBalance(setupBody[i], "(", ")");
|
|
1055
|
+
}
|
|
1056
|
+
collectArrayDestructuredNames(statementLines.join("\n"), returnNames);
|
|
1057
|
+
continue;
|
|
1058
|
+
}
|
|
1059
|
+
const constMatch = trimmed.match(/^(?:export\s+)?(?:const|let|var)\s+([A-Za-z_$][\w$]*)/);
|
|
1060
|
+
if (constMatch) returnNames.add(constMatch[1]);
|
|
1061
|
+
const functionMatch = trimmed.match(/^(?:export\s+)?(?:async\s+)?function\s+([A-Za-z_$][\w$]*)\s*\(/);
|
|
1062
|
+
if (functionMatch) returnNames.add(functionMatch[1]);
|
|
1063
|
+
const classMatch = trimmed.match(/^(?:export\s+)?class\s+([A-Za-z_$][\w$]*)\b/);
|
|
1064
|
+
if (classMatch) returnNames.add(classMatch[1]);
|
|
1065
|
+
}
|
|
1066
|
+
braceDepth += countCharBalance(line, "{", "}");
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
/**
|
|
1070
|
+
* Parse script setup content into imports and setup body.
|
|
1071
|
+
* Returns the import lines, setup body lines, and all identifiers to expose.
|
|
1072
|
+
*/
|
|
1073
|
+
function parseScriptSetupForArt(content) {
|
|
1074
|
+
const lines = content.split("\n");
|
|
1075
|
+
const imports = [];
|
|
1076
|
+
const setupBody = [];
|
|
1077
|
+
const returnNames = /* @__PURE__ */ new Set();
|
|
1078
|
+
let currentImport = null;
|
|
1079
|
+
const defineArtComponent = extractDefineArtComponent(content);
|
|
1080
|
+
let defineArtBalance = 0;
|
|
1081
|
+
for (const line of lines) {
|
|
1082
|
+
const trimmed = line.trim();
|
|
1083
|
+
if (defineArtBalance > 0) {
|
|
1084
|
+
defineArtBalance += countCharBalance(line, "(", ")");
|
|
1085
|
+
continue;
|
|
1086
|
+
}
|
|
1087
|
+
if (currentImport) {
|
|
1088
|
+
currentImport.push(line);
|
|
1089
|
+
const statement = currentImport.join("\n");
|
|
1090
|
+
if (isCompleteImportStatement(statement)) {
|
|
1091
|
+
imports.push(statement);
|
|
1092
|
+
collectImportedNames(statement, returnNames);
|
|
1093
|
+
currentImport = null;
|
|
1094
|
+
}
|
|
1095
|
+
continue;
|
|
1096
|
+
}
|
|
1097
|
+
if (trimmed.startsWith("import ")) {
|
|
1098
|
+
currentImport = [line];
|
|
1099
|
+
const statement = currentImport.join("\n");
|
|
1100
|
+
if (isCompleteImportStatement(statement)) {
|
|
1101
|
+
imports.push(statement);
|
|
1102
|
+
collectImportedNames(statement, returnNames);
|
|
1103
|
+
currentImport = null;
|
|
1104
|
+
}
|
|
1105
|
+
continue;
|
|
1106
|
+
}
|
|
1107
|
+
if (isDefineArtLine(trimmed)) {
|
|
1108
|
+
defineArtBalance = Math.max(0, countCharBalance(line, "(", ")"));
|
|
1109
|
+
continue;
|
|
1110
|
+
}
|
|
1111
|
+
setupBody.push(line);
|
|
1112
|
+
}
|
|
1113
|
+
if (currentImport) {
|
|
1114
|
+
const statement = currentImport.join("\n");
|
|
1115
|
+
imports.push(statement);
|
|
1116
|
+
collectImportedNames(statement, returnNames);
|
|
1117
|
+
}
|
|
1118
|
+
collectTopLevelReturnNames(setupBody, returnNames);
|
|
1119
|
+
returnNames.delete("type");
|
|
1120
|
+
if (defineArtComponent.name) returnNames.delete(defineArtComponent.name);
|
|
1121
|
+
return {
|
|
1122
|
+
imports,
|
|
1123
|
+
setupBody,
|
|
1124
|
+
returnNames: [...returnNames],
|
|
1125
|
+
defineArtComponentName: defineArtComponent.name,
|
|
1126
|
+
defineArtComponentSource: defineArtComponent.source
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
function extractDefineArtComponent(content) {
|
|
1130
|
+
const sourceMatch = content.match(/\bdefineArt\s*\(\s*(['"])([^'"]+)\1/);
|
|
1131
|
+
if (sourceMatch) return {
|
|
1132
|
+
name: componentNameFromSource(sourceMatch[2]),
|
|
1133
|
+
source: sourceMatch[2]
|
|
1134
|
+
};
|
|
1135
|
+
return { name: content.match(/\bdefineArt\s*\(\s*([A-Za-z_$][\w$]*)/)?.[1] };
|
|
1200
1136
|
}
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
const WrappedComponent = {
|
|
1210
|
-
render() {
|
|
1211
|
-
return h(VariantComponent, propsOverride);
|
|
1212
|
-
}
|
|
1213
|
-
};
|
|
1214
|
-
|
|
1215
|
-
const app = createApp(WrappedComponent);
|
|
1216
|
-
ensureArtStyles(artModule.__styles__);
|
|
1217
|
-
${setupCall}
|
|
1218
|
-
container.innerHTML = '';
|
|
1219
|
-
container.className = 'musea-variant';
|
|
1220
|
-
app.mount(container);
|
|
1221
|
-
console.log('[musea-preview] Mounted variant with props override:', ${variantNameLiteral});
|
|
1222
|
-
__museaInitAddons(container, ${variantNameLiteral}, ${actionEvents});
|
|
1223
|
-
} catch (error) {
|
|
1224
|
-
console.error('[musea-preview] Failed to mount:', error);
|
|
1225
|
-
renderError('Failed to render', error);
|
|
1226
|
-
}
|
|
1137
|
+
function componentNameFromSource(source) {
|
|
1138
|
+
const withoutQuery = source.split(/[?#]/, 1)[0] || source;
|
|
1139
|
+
const filename = path.basename(withoutQuery);
|
|
1140
|
+
const extension = path.extname(filename);
|
|
1141
|
+
const name = toPascalCase(extension ? filename.slice(0, -extension.length) : filename);
|
|
1142
|
+
return name === "Variant" ? "MuseaComponent" : name;
|
|
1227
1143
|
}
|
|
1228
|
-
|
|
1229
|
-
|
|
1144
|
+
function isDefineArtLine(trimmed) {
|
|
1145
|
+
return /\bdefineArt\s*\(/.test(trimmed);
|
|
1146
|
+
}
|
|
1147
|
+
function generateArtModule(art, filePath, options = {}) {
|
|
1148
|
+
let componentImportPath;
|
|
1149
|
+
let componentTagName;
|
|
1150
|
+
let componentBindingName = "__MuseaComponent";
|
|
1151
|
+
const scriptSetup = art.scriptSetupContent ? parseScriptSetupForArt(art.scriptSetupContent) : null;
|
|
1152
|
+
const defineArtComponentName = scriptSetup?.defineArtComponentName;
|
|
1153
|
+
const defineArtComponentSource = scriptSetup?.defineArtComponentSource;
|
|
1154
|
+
if (art.isInline && art.componentPath) {
|
|
1155
|
+
componentImportPath = options.root ? resolveComponentSourcePath(art, filePath, allowedSourceRoots(options.root, options.scanRoots ?? [])) ?? void 0 : art.componentPath;
|
|
1156
|
+
componentTagName = "MuseaComponent";
|
|
1157
|
+
} else if (defineArtComponentSource || art.metadata.component) {
|
|
1158
|
+
const componentSource = defineArtComponentSource ?? art.metadata.component;
|
|
1159
|
+
if (componentSource) {
|
|
1160
|
+
const sourceArt = componentSource === art.metadata.component ? art : {
|
|
1161
|
+
...art,
|
|
1162
|
+
metadata: {
|
|
1163
|
+
...art.metadata,
|
|
1164
|
+
component: componentSource
|
|
1165
|
+
}
|
|
1166
|
+
};
|
|
1167
|
+
componentImportPath = options.root ? resolveComponentSourcePath(sourceArt, filePath, allowedSourceRoots(options.root, options.scanRoots ?? [])) ?? void 0 : path.isAbsolute(componentSource) ? componentSource : path.resolve(path.dirname(filePath), componentSource);
|
|
1168
|
+
}
|
|
1169
|
+
componentTagName = defineArtComponentName ?? (art.metadata.component ? componentNameFromSource(art.metadata.component) : "MuseaComponent");
|
|
1170
|
+
componentBindingName = componentTagName;
|
|
1171
|
+
}
|
|
1172
|
+
let code = `
|
|
1173
|
+
// Auto-generated module for: ${path.basename(filePath)}
|
|
1174
|
+
import { defineComponent, h } from 'vue';
|
|
1175
|
+
`;
|
|
1176
|
+
if (scriptSetup) {
|
|
1177
|
+
const artDir = path.dirname(filePath);
|
|
1178
|
+
for (const imp of scriptSetup.imports) {
|
|
1179
|
+
const resolved = rewriteRelativeImportStatement(imp, artDir);
|
|
1180
|
+
code += `${resolved}\n`;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
if (componentImportPath && componentTagName) {
|
|
1184
|
+
if (!scriptSetup?.imports.some((imp) => importDeclaresName(imp, componentBindingName))) code += `import ${componentBindingName} from ${JSON.stringify(componentImportPath)};\n`;
|
|
1185
|
+
code += `export const __component__ = ${componentBindingName};\n`;
|
|
1186
|
+
}
|
|
1187
|
+
code += `
|
|
1188
|
+
export const metadata = ${JSON.stringify(art.metadata)};
|
|
1189
|
+
export const variants = ${JSON.stringify(art.variants)};
|
|
1190
|
+
export const __styles__ = ${JSON.stringify(art.styleBlocks ?? [])};
|
|
1191
|
+
`;
|
|
1192
|
+
const hasSetupBody = scriptSetup?.setupBody.some((line) => line.trim().length > 0) ?? false;
|
|
1193
|
+
const hasSetup = !!scriptSetup && (hasSetupBody || scriptSetup.returnNames.length > 0);
|
|
1194
|
+
const setupReturn = `{ ${scriptSetup?.returnNames.join(", ") ?? ""} }`;
|
|
1195
|
+
const isolatedSetup = art.scriptSetupIsolated !== false;
|
|
1196
|
+
if (scriptSetup && hasSetup && !isolatedSetup) code += `
|
|
1197
|
+
const __museaSharedSetup = (() => {
|
|
1198
|
+
${scriptSetup.setupBody.map((l) => ` ${l}`).join("\n")}
|
|
1199
|
+
return ${setupReturn};
|
|
1200
|
+
})();
|
|
1201
|
+
`;
|
|
1202
|
+
for (const variant of art.variants) {
|
|
1203
|
+
const variantComponentName = toPascalCase(variant.name);
|
|
1204
|
+
let template = variant.template;
|
|
1205
|
+
if (componentTagName) template = template.replace(/<Self/g, `<${componentTagName}`).replace(/<\/Self>/g, `</${componentTagName}>`);
|
|
1206
|
+
const escapedTemplate = escapeTemplateLiteral(template);
|
|
1207
|
+
const fullTemplate = `<div data-variant="${escapeTemplateLiteral(escapeHtml(variant.name))}">${escapedTemplate}</div>`;
|
|
1208
|
+
const componentNames = /* @__PURE__ */ new Map();
|
|
1209
|
+
if (componentTagName) componentNames.set(componentTagName, componentBindingName);
|
|
1210
|
+
if (scriptSetup) {
|
|
1211
|
+
for (const name of scriptSetup.returnNames) if (/^[A-Z]/.test(name)) componentNames.set(name, name);
|
|
1212
|
+
}
|
|
1213
|
+
const components = componentNames.size > 0 ? ` components: { ${[...componentNames].map(([name, value]) => `${JSON.stringify(name)}: ${value}`).join(", ")} },\n` : "";
|
|
1214
|
+
if (scriptSetup && hasSetup && isolatedSetup) code += `
|
|
1215
|
+
export const ${variantComponentName} = defineComponent({
|
|
1216
|
+
name: '${variantComponentName}',
|
|
1217
|
+
${components} setup() {
|
|
1218
|
+
${scriptSetup.setupBody.map((l) => ` ${l}`).join("\n")}
|
|
1219
|
+
return ${setupReturn};
|
|
1220
|
+
},
|
|
1221
|
+
template: \`${fullTemplate}\`,
|
|
1222
|
+
});
|
|
1223
|
+
`;
|
|
1224
|
+
else if (scriptSetup && hasSetup) code += `
|
|
1225
|
+
export const ${variantComponentName} = defineComponent({
|
|
1226
|
+
name: '${variantComponentName}',
|
|
1227
|
+
${components} setup() {
|
|
1228
|
+
return __museaSharedSetup;
|
|
1229
|
+
},
|
|
1230
|
+
template: \`${fullTemplate}\`,
|
|
1231
|
+
});
|
|
1232
|
+
`;
|
|
1233
|
+
else if (componentTagName) code += `
|
|
1234
|
+
export const ${variantComponentName} = {
|
|
1235
|
+
name: '${variantComponentName}',
|
|
1236
|
+
${components} template: \`${fullTemplate}\`,
|
|
1237
|
+
};
|
|
1238
|
+
`;
|
|
1239
|
+
else code += `
|
|
1240
|
+
export const ${variantComponentName} = {
|
|
1241
|
+
name: '${variantComponentName}',
|
|
1242
|
+
template: \`${fullTemplate}\`,
|
|
1243
|
+
};
|
|
1244
|
+
`;
|
|
1245
|
+
}
|
|
1246
|
+
const defaultVariant = art.variants.find((v) => v.isDefault) || art.variants[0];
|
|
1247
|
+
if (defaultVariant) code += `
|
|
1248
|
+
export default ${toPascalCase(defaultVariant.name)};
|
|
1230
1249
|
`;
|
|
1250
|
+
return code;
|
|
1231
1251
|
}
|
|
1232
1252
|
//#endregion
|
|
1233
1253
|
//#region src/server-middleware.ts
|
|
@@ -2121,7 +2141,9 @@ async function processStyleDictionary(config) {
|
|
|
2121
2141
|
//#endregion
|
|
2122
2142
|
//#region src/api-tokens.ts
|
|
2123
2143
|
function resolveTokensPath(ctx) {
|
|
2124
|
-
|
|
2144
|
+
const allowedRoots = [ctx.config.root, ...ctx.scanRoots];
|
|
2145
|
+
if (ctx.projectRoot) allowedRoots.push(ctx.projectRoot);
|
|
2146
|
+
return resolveInsideAny(allowedRoots, ctx.tokensPath, "tokensPath");
|
|
2125
2147
|
}
|
|
2126
2148
|
function sendTokenMutationError(e, sendError) {
|
|
2127
2149
|
if (e instanceof HttpError) {
|
|
@@ -2922,6 +2944,55 @@ function resolveVueRuntimeCompiler() {
|
|
|
2922
2944
|
}
|
|
2923
2945
|
}
|
|
2924
2946
|
//#endregion
|
|
2947
|
+
//#region src/plugin/storybook-inputs.ts
|
|
2948
|
+
function isStorybookTsxInput(filePath) {
|
|
2949
|
+
return /\.(?:stories|story)\.tsx$/i.test(filePath);
|
|
2950
|
+
}
|
|
2951
|
+
async function scanStorybookTsxInputs(root, include, exclude) {
|
|
2952
|
+
const files = /* @__PURE__ */ new Set();
|
|
2953
|
+
const visitedDirs = /* @__PURE__ */ new Set();
|
|
2954
|
+
async function scan(dir) {
|
|
2955
|
+
const resolvedDir = path.resolve(dir);
|
|
2956
|
+
if (visitedDirs.has(resolvedDir)) return;
|
|
2957
|
+
visitedDirs.add(resolvedDir);
|
|
2958
|
+
let entries;
|
|
2959
|
+
try {
|
|
2960
|
+
entries = await fs.promises.readdir(resolvedDir, { withFileTypes: true });
|
|
2961
|
+
} catch {
|
|
2962
|
+
return;
|
|
2963
|
+
}
|
|
2964
|
+
for (const entry of entries) {
|
|
2965
|
+
const fullPath = path.join(resolvedDir, entry.name);
|
|
2966
|
+
if (isExcluded(fullPath, entry.name, exclude, root)) continue;
|
|
2967
|
+
if (entry.isDirectory()) await scan(fullPath);
|
|
2968
|
+
else if (entry.isFile() && isStorybookTsxInput(entry.name) && shouldProcess(fullPath, include, exclude, root)) files.add(fullPath);
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2971
|
+
for (const scanRoot of resolveScanRoots(root, include)) await scan(scanRoot);
|
|
2972
|
+
return [...files].sort();
|
|
2973
|
+
}
|
|
2974
|
+
async function assertNoUnsupportedStorybookTsxInputs(root, include, exclude) {
|
|
2975
|
+
const files = await scanStorybookTsxInputs(root, include, exclude);
|
|
2976
|
+
if (files.length > 0) throw new Error(formatUnsupportedStorybookTsxInputError(root, files));
|
|
2977
|
+
}
|
|
2978
|
+
function formatUnsupportedStorybookTsxInputError(root, files) {
|
|
2979
|
+
return [
|
|
2980
|
+
"[musea] Storybook TSX files matched by include are not supported as Musea art inputs yet.",
|
|
2981
|
+
"Remove *.stories.tsx from musea.include or migrate those stories to .art.vue files.",
|
|
2982
|
+
"Matched files:",
|
|
2983
|
+
`${files.slice(0, 5).map((file) => ` - ${relativePath(root, file)}`).join("\n")}${files.length > 5 ? `\n ... and ${files.length - 5} more` : ""}`
|
|
2984
|
+
].join("\n");
|
|
2985
|
+
}
|
|
2986
|
+
function isExcluded(filePath, name, exclude, root) {
|
|
2987
|
+
return exclude.some((pattern) => matchesPathPattern(filePath, pattern, root) || matchGlob(name, pattern));
|
|
2988
|
+
}
|
|
2989
|
+
function matchesPathPattern(filePath, pattern, root) {
|
|
2990
|
+
return matchGlob(path.isAbsolute(pattern) ? path.resolve(filePath) : path.relative(root, filePath), pattern);
|
|
2991
|
+
}
|
|
2992
|
+
function relativePath(root, filePath) {
|
|
2993
|
+
return path.relative(root, filePath).split(path.sep).join("/");
|
|
2994
|
+
}
|
|
2995
|
+
//#endregion
|
|
2925
2996
|
//#region src/static-data.ts
|
|
2926
2997
|
function staticPreviewId(artPath, variantName) {
|
|
2927
2998
|
return crypto.createHash("sha256").update(artPath).update("\0").update(variantName).digest("hex").slice(0, 20);
|
|
@@ -2980,6 +3051,7 @@ function createApiContext(ctx) {
|
|
|
2980
3051
|
artFiles: ctx.artFiles,
|
|
2981
3052
|
scanRoots: ctx.scanRoots,
|
|
2982
3053
|
tokensPath: ctx.tokensPath,
|
|
3054
|
+
projectRoot: ctx.projectRoot,
|
|
2983
3055
|
basePath: ctx.basePath,
|
|
2984
3056
|
resolvedPreviewCss: ctx.resolvedPreviewCss,
|
|
2985
3057
|
resolvedPreviewSetup: ctx.resolvedPreviewSetup,
|
|
@@ -3267,7 +3339,27 @@ function relativeUrl(fromDir, toFile) {
|
|
|
3267
3339
|
return relative.startsWith(".") ? relative : `./${relative}`;
|
|
3268
3340
|
}
|
|
3269
3341
|
//#endregion
|
|
3270
|
-
//#region src/plugin/
|
|
3342
|
+
//#region src/plugin/config.ts
|
|
3343
|
+
async function resolveMuseaSharedConfig(resolvedConfig) {
|
|
3344
|
+
const sharedConfig = vizeConfigStore.get(resolvedConfig.root);
|
|
3345
|
+
if (sharedConfig) return sharedConfig;
|
|
3346
|
+
const configFile = process.env[VIZE_CONFIG_FILE_ENV];
|
|
3347
|
+
if (!configFile) return null;
|
|
3348
|
+
try {
|
|
3349
|
+
return await loadConfig(resolvedConfig.root, {
|
|
3350
|
+
configFile,
|
|
3351
|
+
env: {
|
|
3352
|
+
mode: resolvedConfig.mode,
|
|
3353
|
+
command: resolvedConfig.command === "build" ? "build" : "serve",
|
|
3354
|
+
isSsrBuild: !!resolvedConfig.build?.ssr
|
|
3355
|
+
}
|
|
3356
|
+
});
|
|
3357
|
+
} catch (error) {
|
|
3358
|
+
throw new Error(`[musea] Failed to load Vize config from ${configFile}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
//#endregion
|
|
3362
|
+
//#region src/plugin/art-processing.ts
|
|
3271
3363
|
function extractArtTagAttributes(source) {
|
|
3272
3364
|
const artTagMatch = source.match(/<art\b([\s\S]*?)>/i);
|
|
3273
3365
|
if (!artTagMatch) return {};
|
|
@@ -3303,6 +3395,62 @@ function extractStyleBlocks(source) {
|
|
|
3303
3395
|
}
|
|
3304
3396
|
return styles;
|
|
3305
3397
|
}
|
|
3398
|
+
function formatArtProcessingError(root, filePath, error) {
|
|
3399
|
+
const detail = error instanceof Error ? error.message || error.name : error == null ? "unknown error" : stringifyUnknown(error);
|
|
3400
|
+
return `[musea] Failed to process ${path.relative(root, filePath) || filePath}: ${detail}`;
|
|
3401
|
+
}
|
|
3402
|
+
function stringifyUnknown(value) {
|
|
3403
|
+
if (typeof value === "string") return value;
|
|
3404
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return value.toString();
|
|
3405
|
+
try {
|
|
3406
|
+
return JSON.stringify(value) ?? "unknown error";
|
|
3407
|
+
} catch {
|
|
3408
|
+
return "unknown error";
|
|
3409
|
+
}
|
|
3410
|
+
}
|
|
3411
|
+
async function processMuseaArtFile(filePath, ctx) {
|
|
3412
|
+
try {
|
|
3413
|
+
const source = await fs.promises.readFile(filePath, "utf-8");
|
|
3414
|
+
const parsed = loadNative().parseArt(source, { filename: filePath });
|
|
3415
|
+
const customMetadata = extractCustomArtMetadata(source);
|
|
3416
|
+
if (!parsed.variants || parsed.variants.length === 0) return null;
|
|
3417
|
+
const isInline = !filePath.endsWith(".art.vue");
|
|
3418
|
+
return {
|
|
3419
|
+
path: filePath,
|
|
3420
|
+
metadata: {
|
|
3421
|
+
title: parsed.metadata.title || (isInline ? path.basename(filePath, ".vue") : ""),
|
|
3422
|
+
description: parsed.metadata.description,
|
|
3423
|
+
component: isInline ? void 0 : parsed.metadata.component,
|
|
3424
|
+
category: parsed.metadata.category,
|
|
3425
|
+
tags: parsed.metadata.tags,
|
|
3426
|
+
status: parsed.metadata.status,
|
|
3427
|
+
order: parsed.metadata.order,
|
|
3428
|
+
actionEvents: customMetadata.actionEvents ?? parsed.metadata.actionEvents
|
|
3429
|
+
},
|
|
3430
|
+
variants: parsed.variants.map((v) => ({
|
|
3431
|
+
name: v.name,
|
|
3432
|
+
template: v.template,
|
|
3433
|
+
isDefault: v.isDefault,
|
|
3434
|
+
skipVrt: v.skipVrt
|
|
3435
|
+
})),
|
|
3436
|
+
hasScriptSetup: isInline ? false : parsed.hasScriptSetup,
|
|
3437
|
+
scriptSetupContent: !isInline && parsed.hasScriptSetup ? extractScriptSetupContent(source) : void 0,
|
|
3438
|
+
scriptSetupIsolated: !isInline && parsed.hasScriptSetup ? extractScriptSetupIsolated(source) : true,
|
|
3439
|
+
hasScript: parsed.hasScript,
|
|
3440
|
+
styleCount: parsed.styleCount,
|
|
3441
|
+
styleBlocks: isInline ? [] : extractStyleBlocks(source),
|
|
3442
|
+
isInline,
|
|
3443
|
+
componentPath: isInline ? filePath : void 0
|
|
3444
|
+
};
|
|
3445
|
+
} catch (error) {
|
|
3446
|
+
const message = formatArtProcessingError(ctx.root, filePath, error);
|
|
3447
|
+
if (ctx.command === "build") throw new Error(message);
|
|
3448
|
+
(ctx.onError ?? console.error)(message);
|
|
3449
|
+
return null;
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
3452
|
+
//#endregion
|
|
3453
|
+
//#region src/plugin/index.ts
|
|
3306
3454
|
function musea(options = {}) {
|
|
3307
3455
|
let include = options.include ?? ["**/*.art.vue"];
|
|
3308
3456
|
let exclude = options.exclude ?? ["node_modules/**", "dist/**"];
|
|
@@ -3311,6 +3459,7 @@ function musea(options = {}) {
|
|
|
3311
3459
|
const storybookOutDir = options.storybookOutDir ?? ".storybook/stories";
|
|
3312
3460
|
let inlineArt = options.inlineArt ?? false;
|
|
3313
3461
|
const tokensPath = options.tokensPath;
|
|
3462
|
+
const projectRootOption = options.projectRoot;
|
|
3314
3463
|
const themeConfig = buildThemeConfig(options.theme);
|
|
3315
3464
|
const previewCss = options.previewCss ?? [];
|
|
3316
3465
|
const previewSetup = options.previewSetup;
|
|
@@ -3352,9 +3501,9 @@ function musea(options = {}) {
|
|
|
3352
3501
|
};
|
|
3353
3502
|
},
|
|
3354
3503
|
options: applyMuseaStaticBuildInput,
|
|
3355
|
-
configResolved(resolvedConfig) {
|
|
3504
|
+
async configResolved(resolvedConfig) {
|
|
3356
3505
|
config = resolvedConfig;
|
|
3357
|
-
const vizeConfig =
|
|
3506
|
+
const vizeConfig = await resolveMuseaSharedConfig(resolvedConfig);
|
|
3358
3507
|
if (vizeConfig?.musea) {
|
|
3359
3508
|
const mc = vizeConfig.musea;
|
|
3360
3509
|
if (!options.include && mc.include) include = mc.include;
|
|
@@ -3386,6 +3535,7 @@ function musea(options = {}) {
|
|
|
3386
3535
|
artFiles,
|
|
3387
3536
|
scanRoots,
|
|
3388
3537
|
tokensPath,
|
|
3538
|
+
projectRoot: resolveProjectRoot(projectRootOption, config.root),
|
|
3389
3539
|
basePath,
|
|
3390
3540
|
resolvedPreviewCss,
|
|
3391
3541
|
resolvedPreviewSetup,
|
|
@@ -3433,7 +3583,12 @@ function musea(options = {}) {
|
|
|
3433
3583
|
if (address && typeof address === "object") {
|
|
3434
3584
|
const protocol = devServer.config.server.https ? "https" : "http";
|
|
3435
3585
|
const rawHost = address.address;
|
|
3436
|
-
const url = `${protocol}://${
|
|
3586
|
+
const url = `${protocol}://${[
|
|
3587
|
+
"::",
|
|
3588
|
+
"::1",
|
|
3589
|
+
"0.0.0.0",
|
|
3590
|
+
"127.0.0.1"
|
|
3591
|
+
].includes(rawHost) ? "localhost" : rawHost}:${address.port}${basePath}`;
|
|
3437
3592
|
console.log();
|
|
3438
3593
|
console.log(` \x1b[36m➜\x1b[0m \x1b[1mMusea Gallery:\x1b[0m \x1b[36m${url}\x1b[0m`);
|
|
3439
3594
|
}
|
|
@@ -3442,6 +3597,7 @@ function musea(options = {}) {
|
|
|
3442
3597
|
},
|
|
3443
3598
|
async buildStart() {
|
|
3444
3599
|
console.log(`[musea] config.root: ${config.root}, include: ${JSON.stringify(include)}`);
|
|
3600
|
+
if (storybookCompat && staticBuildEnabled) await assertNoUnsupportedStorybookTsxInputs(config.root, include, exclude);
|
|
3445
3601
|
const files = await scanArtFiles(config.root, include, exclude, inlineArt);
|
|
3446
3602
|
console.log(`[musea] Found ${files.length} art files`);
|
|
3447
3603
|
if (server) watchMuseaArtFiles(server.watcher, files);
|
|
@@ -3461,6 +3617,7 @@ function musea(options = {}) {
|
|
|
3461
3617
|
artFiles,
|
|
3462
3618
|
scanRoots,
|
|
3463
3619
|
tokensPath,
|
|
3620
|
+
projectRoot: resolveProjectRoot(projectRootOption, config.root),
|
|
3464
3621
|
basePath,
|
|
3465
3622
|
resolvedPreviewCss,
|
|
3466
3623
|
resolvedPreviewSetup,
|
|
@@ -3482,46 +3639,19 @@ function musea(options = {}) {
|
|
|
3482
3639
|
handleHotUpdate: createHandleHotUpdate(virtualState)
|
|
3483
3640
|
};
|
|
3484
3641
|
async function processArtFile(filePath) {
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
const isInline = !filePath.endsWith(".art.vue");
|
|
3491
|
-
const info = {
|
|
3492
|
-
path: filePath,
|
|
3493
|
-
metadata: {
|
|
3494
|
-
title: parsed.metadata.title || (isInline ? path.basename(filePath, ".vue") : ""),
|
|
3495
|
-
description: parsed.metadata.description,
|
|
3496
|
-
component: isInline ? void 0 : parsed.metadata.component,
|
|
3497
|
-
category: parsed.metadata.category,
|
|
3498
|
-
tags: parsed.metadata.tags,
|
|
3499
|
-
status: parsed.metadata.status,
|
|
3500
|
-
order: parsed.metadata.order,
|
|
3501
|
-
actionEvents: customMetadata.actionEvents ?? parsed.metadata.actionEvents
|
|
3502
|
-
},
|
|
3503
|
-
variants: parsed.variants.map((v) => ({
|
|
3504
|
-
name: v.name,
|
|
3505
|
-
template: v.template,
|
|
3506
|
-
isDefault: v.isDefault,
|
|
3507
|
-
skipVrt: v.skipVrt
|
|
3508
|
-
})),
|
|
3509
|
-
hasScriptSetup: isInline ? false : parsed.hasScriptSetup,
|
|
3510
|
-
scriptSetupContent: !isInline && parsed.hasScriptSetup ? extractScriptSetupContent(source) : void 0,
|
|
3511
|
-
scriptSetupIsolated: !isInline && parsed.hasScriptSetup ? extractScriptSetupIsolated(source) : true,
|
|
3512
|
-
hasScript: parsed.hasScript,
|
|
3513
|
-
styleCount: parsed.styleCount,
|
|
3514
|
-
styleBlocks: isInline ? [] : extractStyleBlocks(source),
|
|
3515
|
-
isInline,
|
|
3516
|
-
componentPath: isInline ? filePath : void 0
|
|
3517
|
-
};
|
|
3518
|
-
artFiles.set(filePath, info);
|
|
3519
|
-
} catch (e) {
|
|
3520
|
-
console.error(`[musea] Failed to process ${filePath}:`, e);
|
|
3521
|
-
}
|
|
3642
|
+
const info = await processMuseaArtFile(filePath, {
|
|
3643
|
+
root: config.root,
|
|
3644
|
+
command: config.command
|
|
3645
|
+
});
|
|
3646
|
+
if (info) artFiles.set(filePath, info);
|
|
3522
3647
|
}
|
|
3523
3648
|
return [mainPlugin];
|
|
3524
3649
|
}
|
|
3650
|
+
function resolveProjectRoot(projectRoot, viteRoot) {
|
|
3651
|
+
if (!projectRoot) return void 0;
|
|
3652
|
+
const absolute = path.isAbsolute(projectRoot) ? projectRoot : path.resolve(viteRoot, projectRoot);
|
|
3653
|
+
return absolute === path.resolve(viteRoot) ? void 0 : absolute;
|
|
3654
|
+
}
|
|
3525
3655
|
//#endregion
|
|
3526
3656
|
//#region src/index.ts
|
|
3527
3657
|
var src_default = musea;
|