@vizejs/vite-plugin-musea 0.243.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 +610 -448
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- 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.
|
|
@@ -178,16 +169,48 @@ async function generateStorybookFiles(artFiles, root, outDir) {
|
|
|
178
169
|
const binding = loadNative();
|
|
179
170
|
const outputDir = path.resolve(root, outDir);
|
|
180
171
|
await fs.promises.mkdir(outputDir, { recursive: true });
|
|
181
|
-
for (const [filePath,
|
|
172
|
+
for (const [filePath, art] of artFiles) try {
|
|
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
|
-
|
|
176
|
+
const code = rewriteStorybookScriptImports(rewriteStorybookComponentImport(csf.code, art, filePath, outputPath), filePath, outputPath);
|
|
177
|
+
await fs.promises.writeFile(outputPath, code, "utf-8");
|
|
186
178
|
console.log(`[musea] Generated: ${path.relative(root, outputPath)}`);
|
|
187
179
|
} catch (e) {
|
|
188
180
|
console.error(`[musea] Failed to generate CSF for ${filePath}:`, e);
|
|
189
181
|
}
|
|
190
182
|
}
|
|
183
|
+
function rewriteStorybookComponentImport(code, art, artPath, outputPath) {
|
|
184
|
+
const component = art.isInline && art.componentPath ? art.componentPath : art.metadata.component;
|
|
185
|
+
if (!component || isBareImport(component)) return code;
|
|
186
|
+
const resolvedComponent = path.isAbsolute(component) ? component : path.resolve(path.dirname(artPath), component);
|
|
187
|
+
let relativeComponent = normalizeGlobPath(path.relative(path.dirname(outputPath), resolvedComponent));
|
|
188
|
+
if (!relativeComponent.startsWith(".")) relativeComponent = `./${relativeComponent}`;
|
|
189
|
+
return code.replace(/import\s+(__museaComponent)\s+from\s+(['"])([^'"]+)\2;/, `import $1 from $2${relativeComponent}$2;`);
|
|
190
|
+
}
|
|
191
|
+
function isBareImport(source) {
|
|
192
|
+
return !source.startsWith(".") && !path.isAbsolute(source);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
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.
|
|
198
|
+
*
|
|
199
|
+
* The `__museaComponent` import is already rebased by
|
|
200
|
+
* `rewriteStorybookComponentImport` and is skipped here.
|
|
201
|
+
*/
|
|
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
|
+
});
|
|
213
|
+
}
|
|
191
214
|
function toPascalCase(str) {
|
|
192
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("");
|
|
193
216
|
if (!pascal) return "Variant";
|
|
@@ -211,346 +234,7 @@ function buildThemeConfig(theme) {
|
|
|
211
234
|
return {
|
|
212
235
|
default: themes[0].name,
|
|
213
236
|
custom
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
//#endregion
|
|
217
|
-
//#region src/art-module.ts
|
|
218
|
-
/**
|
|
219
|
-
* Art module generation for Musea.
|
|
220
|
-
*
|
|
221
|
-
* Generates the virtual ES modules that represent parsed `.art.vue` files,
|
|
222
|
-
* including variant component definitions and script setup handling.
|
|
223
|
-
*/
|
|
224
|
-
/**
|
|
225
|
-
* Extract the content of the first <script setup> block from a Vue SFC source.
|
|
226
|
-
*/
|
|
227
|
-
function extractScriptSetupContent(source) {
|
|
228
|
-
return source.match(/<script\s+[^>]*setup[^>]*>([\s\S]*?)<\/script>/)?.[1]?.trim();
|
|
229
|
-
}
|
|
230
|
-
function extractScriptSetupIsolated(source) {
|
|
231
|
-
const match = source.match(/<script\s+([^>]*)\bsetup\b([^>]*)>/);
|
|
232
|
-
if (!match) return true;
|
|
233
|
-
const isolate = `${match[1] ?? ""} ${match[2] ?? ""}`.match(/\bisolate\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/);
|
|
234
|
-
return (isolate?.[1] ?? isolate?.[2] ?? isolate?.[3]) !== "false";
|
|
235
|
-
}
|
|
236
|
-
function resolveRelativeSpecifier(specifier, artDir) {
|
|
237
|
-
if (!specifier.startsWith(".")) return specifier;
|
|
238
|
-
return path.resolve(artDir, specifier);
|
|
239
|
-
}
|
|
240
|
-
function rewriteRelativeImportStatement(statement, artDir) {
|
|
241
|
-
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}`);
|
|
242
|
-
}
|
|
243
|
-
function escapeTemplateLiteral(str) {
|
|
244
|
-
return str.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$");
|
|
245
|
-
}
|
|
246
|
-
function countCharBalance(source, openChar, closeChar) {
|
|
247
|
-
let balance = 0;
|
|
248
|
-
for (const char of source) if (char === openChar) balance++;
|
|
249
|
-
else if (char === closeChar) balance--;
|
|
250
|
-
return balance;
|
|
251
|
-
}
|
|
252
|
-
function isCompleteImportStatement(statement) {
|
|
253
|
-
const trimmed = statement.trim();
|
|
254
|
-
if (!trimmed.startsWith("import ")) return false;
|
|
255
|
-
if (countCharBalance(statement, "{", "}") > 0) return false;
|
|
256
|
-
return /^import\s+[\s\S]+?\s+from\s+['"][^'"]+['"]\s*;?$/s.test(trimmed) || /^import\s+['"][^'"]+['"]\s*;?$/s.test(trimmed);
|
|
257
|
-
}
|
|
258
|
-
function splitTopLevelCommaList(source) {
|
|
259
|
-
const parts = [];
|
|
260
|
-
let current = "";
|
|
261
|
-
let braceDepth = 0;
|
|
262
|
-
let bracketDepth = 0;
|
|
263
|
-
let parenDepth = 0;
|
|
264
|
-
for (const char of source) {
|
|
265
|
-
if (char === "," && braceDepth === 0 && bracketDepth === 0 && parenDepth === 0) {
|
|
266
|
-
const trimmed = current.trim();
|
|
267
|
-
if (trimmed) parts.push(trimmed);
|
|
268
|
-
current = "";
|
|
269
|
-
continue;
|
|
270
|
-
}
|
|
271
|
-
current += char;
|
|
272
|
-
if (char === "{") braceDepth++;
|
|
273
|
-
else if (char === "}") braceDepth--;
|
|
274
|
-
else if (char === "[") bracketDepth++;
|
|
275
|
-
else if (char === "]") bracketDepth--;
|
|
276
|
-
else if (char === "(") parenDepth++;
|
|
277
|
-
else if (char === ")") parenDepth--;
|
|
278
|
-
}
|
|
279
|
-
const trimmed = current.trim();
|
|
280
|
-
if (trimmed) parts.push(trimmed);
|
|
281
|
-
return parts;
|
|
282
|
-
}
|
|
283
|
-
function collectImportedNames(statement, returnNames) {
|
|
284
|
-
const fromMatch = statement.replace(/\s+/g, " ").trim().replace(/;$/, "").match(/^import\s+(type\s+)?(.+?)\s+from\s+['"][^'"]+['"]$/);
|
|
285
|
-
if (!fromMatch) return;
|
|
286
|
-
if (fromMatch[1]) return;
|
|
287
|
-
const specifierParts = splitTopLevelCommaList(fromMatch[2].trim());
|
|
288
|
-
const defaultOrNamespace = specifierParts[0]?.trim() ?? "";
|
|
289
|
-
const trailing = specifierParts.slice(1).join(", ").trim();
|
|
290
|
-
if (defaultOrNamespace && !defaultOrNamespace.startsWith("{")) {
|
|
291
|
-
const namespaceMatch = defaultOrNamespace.match(/^\*\s+as\s+([A-Za-z_$][\w$]*)$/);
|
|
292
|
-
if (namespaceMatch) returnNames.add(namespaceMatch[1]);
|
|
293
|
-
else if (!defaultOrNamespace.startsWith("type ")) returnNames.add(defaultOrNamespace);
|
|
294
|
-
}
|
|
295
|
-
const namedBlock = defaultOrNamespace.startsWith("{") ? defaultOrNamespace : trailing.startsWith("{") ? trailing : "";
|
|
296
|
-
if (!namedBlock) return;
|
|
297
|
-
const namedContent = namedBlock.slice(1, -1);
|
|
298
|
-
for (const part of splitTopLevelCommaList(namedContent)) {
|
|
299
|
-
const trimmed = part.trim();
|
|
300
|
-
if (!trimmed || trimmed.startsWith("type ")) continue;
|
|
301
|
-
const alias = trimmed.split(/\s+as\s+/).pop()?.trim();
|
|
302
|
-
if (alias) returnNames.add(alias);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
function importDeclaresName(statement, name) {
|
|
306
|
-
const names = /* @__PURE__ */ new Set();
|
|
307
|
-
collectImportedNames(statement, names);
|
|
308
|
-
return names.has(name);
|
|
309
|
-
}
|
|
310
|
-
function collectObjectDestructuredNames(statement, returnNames) {
|
|
311
|
-
const match = statement.match(/^(?:export\s+)?(?:const|let|var)\s+\{([\s\S]*?)\}\s*=/);
|
|
312
|
-
if (!match) return;
|
|
313
|
-
for (const part of splitTopLevelCommaList(match[1])) {
|
|
314
|
-
let name = part.trim();
|
|
315
|
-
if (!name) continue;
|
|
316
|
-
if (name.startsWith("...")) name = name.slice(3).trim();
|
|
317
|
-
else if (name.includes(":")) name = name.split(":").pop().trim();
|
|
318
|
-
else if (name.includes("=")) name = name.split("=")[0].trim();
|
|
319
|
-
if (name.includes("=")) name = name.split("=")[0].trim();
|
|
320
|
-
if (/^[A-Za-z_$][\w$]*$/.test(name)) returnNames.add(name);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
function collectArrayDestructuredNames(statement, returnNames) {
|
|
324
|
-
const match = statement.match(/^(?:export\s+)?(?:const|let|var)\s+\[([\s\S]*?)\]\s*=/);
|
|
325
|
-
if (!match) return;
|
|
326
|
-
for (const part of splitTopLevelCommaList(match[1])) {
|
|
327
|
-
let name = part.trim();
|
|
328
|
-
if (!name) continue;
|
|
329
|
-
if (name.startsWith("...")) name = name.slice(3).trim();
|
|
330
|
-
if (name.includes("=")) name = name.split("=")[0].trim();
|
|
331
|
-
if (/^[A-Za-z_$][\w$]*$/.test(name)) returnNames.add(name);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
function collectTopLevelReturnNames(setupBody, returnNames) {
|
|
335
|
-
let braceDepth = 0;
|
|
336
|
-
for (let i = 0; i < setupBody.length; i++) {
|
|
337
|
-
const line = setupBody[i];
|
|
338
|
-
const trimmed = line.trim();
|
|
339
|
-
if (braceDepth === 0) {
|
|
340
|
-
if (/^(?:export\s+)?(?:const|let|var)\s+\{/.test(trimmed)) {
|
|
341
|
-
const statementLines = [line];
|
|
342
|
-
let balance = countCharBalance(line, "{", "}") + countCharBalance(line, "[", "]") + countCharBalance(line, "(", ")");
|
|
343
|
-
while (balance > 0 && i + 1 < setupBody.length) {
|
|
344
|
-
i++;
|
|
345
|
-
statementLines.push(setupBody[i]);
|
|
346
|
-
balance += countCharBalance(setupBody[i], "{", "}") + countCharBalance(setupBody[i], "[", "]") + countCharBalance(setupBody[i], "(", ")");
|
|
347
|
-
}
|
|
348
|
-
collectObjectDestructuredNames(statementLines.join("\n"), returnNames);
|
|
349
|
-
continue;
|
|
350
|
-
}
|
|
351
|
-
if (/^(?:export\s+)?(?:const|let|var)\s+\[/.test(trimmed)) {
|
|
352
|
-
const statementLines = [line];
|
|
353
|
-
let balance = countCharBalance(line, "{", "}") + countCharBalance(line, "[", "]") + countCharBalance(line, "(", ")");
|
|
354
|
-
while (balance > 0 && i + 1 < setupBody.length) {
|
|
355
|
-
i++;
|
|
356
|
-
statementLines.push(setupBody[i]);
|
|
357
|
-
balance += countCharBalance(setupBody[i], "{", "}") + countCharBalance(setupBody[i], "[", "]") + countCharBalance(setupBody[i], "(", ")");
|
|
358
|
-
}
|
|
359
|
-
collectArrayDestructuredNames(statementLines.join("\n"), returnNames);
|
|
360
|
-
continue;
|
|
361
|
-
}
|
|
362
|
-
const constMatch = trimmed.match(/^(?:export\s+)?(?:const|let|var)\s+([A-Za-z_$][\w$]*)/);
|
|
363
|
-
if (constMatch) returnNames.add(constMatch[1]);
|
|
364
|
-
const functionMatch = trimmed.match(/^(?:export\s+)?(?:async\s+)?function\s+([A-Za-z_$][\w$]*)\s*\(/);
|
|
365
|
-
if (functionMatch) returnNames.add(functionMatch[1]);
|
|
366
|
-
const classMatch = trimmed.match(/^(?:export\s+)?class\s+([A-Za-z_$][\w$]*)\b/);
|
|
367
|
-
if (classMatch) returnNames.add(classMatch[1]);
|
|
368
|
-
}
|
|
369
|
-
braceDepth += countCharBalance(line, "{", "}");
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
/**
|
|
373
|
-
* Parse script setup content into imports and setup body.
|
|
374
|
-
* Returns the import lines, setup body lines, and all identifiers to expose.
|
|
375
|
-
*/
|
|
376
|
-
function parseScriptSetupForArt(content) {
|
|
377
|
-
const lines = content.split("\n");
|
|
378
|
-
const imports = [];
|
|
379
|
-
const setupBody = [];
|
|
380
|
-
const returnNames = /* @__PURE__ */ new Set();
|
|
381
|
-
let currentImport = null;
|
|
382
|
-
const defineArtComponent = extractDefineArtComponent(content);
|
|
383
|
-
let defineArtBalance = 0;
|
|
384
|
-
for (const line of lines) {
|
|
385
|
-
const trimmed = line.trim();
|
|
386
|
-
if (defineArtBalance > 0) {
|
|
387
|
-
defineArtBalance += countCharBalance(line, "(", ")");
|
|
388
|
-
continue;
|
|
389
|
-
}
|
|
390
|
-
if (currentImport) {
|
|
391
|
-
currentImport.push(line);
|
|
392
|
-
const statement = currentImport.join("\n");
|
|
393
|
-
if (isCompleteImportStatement(statement)) {
|
|
394
|
-
imports.push(statement);
|
|
395
|
-
collectImportedNames(statement, returnNames);
|
|
396
|
-
currentImport = null;
|
|
397
|
-
}
|
|
398
|
-
continue;
|
|
399
|
-
}
|
|
400
|
-
if (trimmed.startsWith("import ")) {
|
|
401
|
-
currentImport = [line];
|
|
402
|
-
const statement = currentImport.join("\n");
|
|
403
|
-
if (isCompleteImportStatement(statement)) {
|
|
404
|
-
imports.push(statement);
|
|
405
|
-
collectImportedNames(statement, returnNames);
|
|
406
|
-
currentImport = null;
|
|
407
|
-
}
|
|
408
|
-
continue;
|
|
409
|
-
}
|
|
410
|
-
if (isDefineArtLine(trimmed)) {
|
|
411
|
-
defineArtBalance = Math.max(0, countCharBalance(line, "(", ")"));
|
|
412
|
-
continue;
|
|
413
|
-
}
|
|
414
|
-
setupBody.push(line);
|
|
415
|
-
}
|
|
416
|
-
if (currentImport) {
|
|
417
|
-
const statement = currentImport.join("\n");
|
|
418
|
-
imports.push(statement);
|
|
419
|
-
collectImportedNames(statement, returnNames);
|
|
420
|
-
}
|
|
421
|
-
collectTopLevelReturnNames(setupBody, returnNames);
|
|
422
|
-
returnNames.delete("type");
|
|
423
|
-
if (defineArtComponent.name) returnNames.delete(defineArtComponent.name);
|
|
424
|
-
return {
|
|
425
|
-
imports,
|
|
426
|
-
setupBody,
|
|
427
|
-
returnNames: [...returnNames],
|
|
428
|
-
defineArtComponentName: defineArtComponent.name,
|
|
429
|
-
defineArtComponentSource: defineArtComponent.source
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
function extractDefineArtComponent(content) {
|
|
433
|
-
const sourceMatch = content.match(/\bdefineArt\s*\(\s*(['"])([^'"]+)\1/);
|
|
434
|
-
if (sourceMatch) return {
|
|
435
|
-
name: componentNameFromSource(sourceMatch[2]),
|
|
436
|
-
source: sourceMatch[2]
|
|
437
|
-
};
|
|
438
|
-
return { name: content.match(/\bdefineArt\s*\(\s*([A-Za-z_$][\w$]*)/)?.[1] };
|
|
439
|
-
}
|
|
440
|
-
function componentNameFromSource(source) {
|
|
441
|
-
const withoutQuery = source.split(/[?#]/, 1)[0] || source;
|
|
442
|
-
const filename = path.basename(withoutQuery);
|
|
443
|
-
const extension = path.extname(filename);
|
|
444
|
-
const name = toPascalCase(extension ? filename.slice(0, -extension.length) : filename);
|
|
445
|
-
return name === "Variant" ? "MuseaComponent" : name;
|
|
446
|
-
}
|
|
447
|
-
function isDefineArtLine(trimmed) {
|
|
448
|
-
return /\bdefineArt\s*\(/.test(trimmed);
|
|
449
|
-
}
|
|
450
|
-
function generateArtModule(art, filePath, options = {}) {
|
|
451
|
-
let componentImportPath;
|
|
452
|
-
let componentTagName;
|
|
453
|
-
let componentBindingName = "__MuseaComponent";
|
|
454
|
-
const scriptSetup = art.scriptSetupContent ? parseScriptSetupForArt(art.scriptSetupContent) : null;
|
|
455
|
-
const defineArtComponentName = scriptSetup?.defineArtComponentName;
|
|
456
|
-
const defineArtComponentSource = scriptSetup?.defineArtComponentSource;
|
|
457
|
-
if (art.isInline && art.componentPath) {
|
|
458
|
-
componentImportPath = options.root ? resolveComponentSourcePath(art, filePath, allowedSourceRoots(options.root, options.scanRoots ?? [])) ?? void 0 : art.componentPath;
|
|
459
|
-
componentTagName = "MuseaComponent";
|
|
460
|
-
} else if (defineArtComponentSource || art.metadata.component) {
|
|
461
|
-
const componentSource = defineArtComponentSource ?? art.metadata.component;
|
|
462
|
-
if (componentSource) {
|
|
463
|
-
const sourceArt = componentSource === art.metadata.component ? art : {
|
|
464
|
-
...art,
|
|
465
|
-
metadata: {
|
|
466
|
-
...art.metadata,
|
|
467
|
-
component: componentSource
|
|
468
|
-
}
|
|
469
|
-
};
|
|
470
|
-
componentImportPath = options.root ? resolveComponentSourcePath(sourceArt, filePath, allowedSourceRoots(options.root, options.scanRoots ?? [])) ?? void 0 : path.isAbsolute(componentSource) ? componentSource : path.resolve(path.dirname(filePath), componentSource);
|
|
471
|
-
}
|
|
472
|
-
componentTagName = defineArtComponentName ?? (art.metadata.component ? componentNameFromSource(art.metadata.component) : "MuseaComponent");
|
|
473
|
-
componentBindingName = componentTagName;
|
|
474
|
-
}
|
|
475
|
-
let code = `
|
|
476
|
-
// Auto-generated module for: ${path.basename(filePath)}
|
|
477
|
-
import { defineComponent, h } from 'vue';
|
|
478
|
-
`;
|
|
479
|
-
if (scriptSetup) {
|
|
480
|
-
const artDir = path.dirname(filePath);
|
|
481
|
-
for (const imp of scriptSetup.imports) {
|
|
482
|
-
const resolved = rewriteRelativeImportStatement(imp, artDir);
|
|
483
|
-
code += `${resolved}\n`;
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
if (componentImportPath && componentTagName) {
|
|
487
|
-
if (!scriptSetup?.imports.some((imp) => importDeclaresName(imp, componentBindingName))) code += `import ${componentBindingName} from ${JSON.stringify(componentImportPath)};\n`;
|
|
488
|
-
code += `export const __component__ = ${componentBindingName};\n`;
|
|
489
|
-
}
|
|
490
|
-
code += `
|
|
491
|
-
export const metadata = ${JSON.stringify(art.metadata)};
|
|
492
|
-
export const variants = ${JSON.stringify(art.variants)};
|
|
493
|
-
export const __styles__ = ${JSON.stringify(art.styleBlocks ?? [])};
|
|
494
|
-
`;
|
|
495
|
-
const hasSetupBody = scriptSetup?.setupBody.some((line) => line.trim().length > 0) ?? false;
|
|
496
|
-
const hasSetup = !!scriptSetup && (hasSetupBody || scriptSetup.returnNames.length > 0);
|
|
497
|
-
const setupReturn = `{ ${scriptSetup?.returnNames.join(", ") ?? ""} }`;
|
|
498
|
-
const isolatedSetup = art.scriptSetupIsolated !== false;
|
|
499
|
-
if (scriptSetup && hasSetup && !isolatedSetup) code += `
|
|
500
|
-
const __museaSharedSetup = (() => {
|
|
501
|
-
${scriptSetup.setupBody.map((l) => ` ${l}`).join("\n")}
|
|
502
|
-
return ${setupReturn};
|
|
503
|
-
})();
|
|
504
|
-
`;
|
|
505
|
-
for (const variant of art.variants) {
|
|
506
|
-
const variantComponentName = toPascalCase(variant.name);
|
|
507
|
-
let template = variant.template;
|
|
508
|
-
if (componentTagName) template = template.replace(/<Self/g, `<${componentTagName}`).replace(/<\/Self>/g, `</${componentTagName}>`);
|
|
509
|
-
const escapedTemplate = escapeTemplateLiteral(template);
|
|
510
|
-
const fullTemplate = `<div data-variant="${escapeTemplateLiteral(escapeHtml(variant.name))}">${escapedTemplate}</div>`;
|
|
511
|
-
const componentNames = /* @__PURE__ */ new Map();
|
|
512
|
-
if (componentTagName) componentNames.set(componentTagName, componentBindingName);
|
|
513
|
-
if (scriptSetup) {
|
|
514
|
-
for (const name of scriptSetup.returnNames) if (/^[A-Z]/.test(name)) componentNames.set(name, name);
|
|
515
|
-
}
|
|
516
|
-
const components = componentNames.size > 0 ? ` components: { ${[...componentNames].map(([name, value]) => `${JSON.stringify(name)}: ${value}`).join(", ")} },\n` : "";
|
|
517
|
-
if (scriptSetup && hasSetup && isolatedSetup) code += `
|
|
518
|
-
export const ${variantComponentName} = defineComponent({
|
|
519
|
-
name: '${variantComponentName}',
|
|
520
|
-
${components} setup() {
|
|
521
|
-
${scriptSetup.setupBody.map((l) => ` ${l}`).join("\n")}
|
|
522
|
-
return ${setupReturn};
|
|
523
|
-
},
|
|
524
|
-
template: \`${fullTemplate}\`,
|
|
525
|
-
});
|
|
526
|
-
`;
|
|
527
|
-
else if (scriptSetup && hasSetup) code += `
|
|
528
|
-
export const ${variantComponentName} = defineComponent({
|
|
529
|
-
name: '${variantComponentName}',
|
|
530
|
-
${components} setup() {
|
|
531
|
-
return __museaSharedSetup;
|
|
532
|
-
},
|
|
533
|
-
template: \`${fullTemplate}\`,
|
|
534
|
-
});
|
|
535
|
-
`;
|
|
536
|
-
else if (componentTagName) code += `
|
|
537
|
-
export const ${variantComponentName} = {
|
|
538
|
-
name: '${variantComponentName}',
|
|
539
|
-
${components} template: \`${fullTemplate}\`,
|
|
540
|
-
};
|
|
541
|
-
`;
|
|
542
|
-
else code += `
|
|
543
|
-
export const ${variantComponentName} = {
|
|
544
|
-
name: '${variantComponentName}',
|
|
545
|
-
template: \`${fullTemplate}\`,
|
|
546
|
-
};
|
|
547
|
-
`;
|
|
548
|
-
}
|
|
549
|
-
const defaultVariant = art.variants.find((v) => v.isDefault) || art.variants[0];
|
|
550
|
-
if (defaultVariant) code += `
|
|
551
|
-
export default ${toPascalCase(defaultVariant.name)};
|
|
552
|
-
`;
|
|
553
|
-
return code;
|
|
237
|
+
};
|
|
554
238
|
}
|
|
555
239
|
//#endregion
|
|
556
240
|
//#region src/preview/addons.ts
|
|
@@ -1169,53 +853,401 @@ function ensureArtStyles(styles) {
|
|
|
1169
853
|
document.head.appendChild(tag);
|
|
1170
854
|
}
|
|
1171
855
|
}
|
|
1172
|
-
|
|
1173
|
-
function renderError(title, error) {
|
|
1174
|
-
container.textContent = '';
|
|
1175
|
-
const root = document.createElement('div');
|
|
1176
|
-
root.className = 'musea-error';
|
|
1177
|
-
|
|
1178
|
-
const titleEl = document.createElement('div');
|
|
1179
|
-
titleEl.className = 'musea-error-title';
|
|
1180
|
-
titleEl.textContent = title;
|
|
1181
|
-
root.appendChild(titleEl);
|
|
1182
|
-
|
|
1183
|
-
const messageEl = document.createElement('div');
|
|
1184
|
-
messageEl.textContent = error instanceof Error ? error.message : String(error);
|
|
1185
|
-
root.appendChild(messageEl);
|
|
1186
|
-
|
|
1187
|
-
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] };
|
|
1188
1136
|
}
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
const WrappedComponent = {
|
|
1198
|
-
render() {
|
|
1199
|
-
return h(VariantComponent, propsOverride);
|
|
1200
|
-
}
|
|
1201
|
-
};
|
|
1202
|
-
|
|
1203
|
-
const app = createApp(WrappedComponent);
|
|
1204
|
-
ensureArtStyles(artModule.__styles__);
|
|
1205
|
-
${setupCall}
|
|
1206
|
-
container.innerHTML = '';
|
|
1207
|
-
container.className = 'musea-variant';
|
|
1208
|
-
app.mount(container);
|
|
1209
|
-
console.log('[musea-preview] Mounted variant with props override:', ${variantNameLiteral});
|
|
1210
|
-
__museaInitAddons(container, ${variantNameLiteral}, ${actionEvents});
|
|
1211
|
-
} catch (error) {
|
|
1212
|
-
console.error('[musea-preview] Failed to mount:', error);
|
|
1213
|
-
renderError('Failed to render', error);
|
|
1214
|
-
}
|
|
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;
|
|
1215
1143
|
}
|
|
1216
|
-
|
|
1217
|
-
|
|
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)};
|
|
1218
1249
|
`;
|
|
1250
|
+
return code;
|
|
1219
1251
|
}
|
|
1220
1252
|
//#endregion
|
|
1221
1253
|
//#region src/server-middleware.ts
|
|
@@ -2109,7 +2141,9 @@ async function processStyleDictionary(config) {
|
|
|
2109
2141
|
//#endregion
|
|
2110
2142
|
//#region src/api-tokens.ts
|
|
2111
2143
|
function resolveTokensPath(ctx) {
|
|
2112
|
-
|
|
2144
|
+
const allowedRoots = [ctx.config.root, ...ctx.scanRoots];
|
|
2145
|
+
if (ctx.projectRoot) allowedRoots.push(ctx.projectRoot);
|
|
2146
|
+
return resolveInsideAny(allowedRoots, ctx.tokensPath, "tokensPath");
|
|
2113
2147
|
}
|
|
2114
2148
|
function sendTokenMutationError(e, sendError) {
|
|
2115
2149
|
if (e instanceof HttpError) {
|
|
@@ -2894,6 +2928,71 @@ function watchMuseaArtFiles(watcher, files) {
|
|
|
2894
2928
|
watcher.add(targets);
|
|
2895
2929
|
}
|
|
2896
2930
|
//#endregion
|
|
2931
|
+
//#region src/plugin/vue-alias.ts
|
|
2932
|
+
const require = createRequire(import.meta.url);
|
|
2933
|
+
function createVueRuntimeCompilerAlias() {
|
|
2934
|
+
return {
|
|
2935
|
+
find: /^vue$/,
|
|
2936
|
+
replacement: resolveVueRuntimeCompiler()
|
|
2937
|
+
};
|
|
2938
|
+
}
|
|
2939
|
+
function resolveVueRuntimeCompiler() {
|
|
2940
|
+
try {
|
|
2941
|
+
return require.resolve("vue/dist/vue.esm-bundler.js");
|
|
2942
|
+
} catch {
|
|
2943
|
+
return "vue/dist/vue.esm-bundler.js";
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
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
|
|
2897
2996
|
//#region src/static-data.ts
|
|
2898
2997
|
function staticPreviewId(artPath, variantName) {
|
|
2899
2998
|
return crypto.createHash("sha256").update(artPath).update("\0").update(variantName).digest("hex").slice(0, 20);
|
|
@@ -2952,6 +3051,7 @@ function createApiContext(ctx) {
|
|
|
2952
3051
|
artFiles: ctx.artFiles,
|
|
2953
3052
|
scanRoots: ctx.scanRoots,
|
|
2954
3053
|
tokensPath: ctx.tokensPath,
|
|
3054
|
+
projectRoot: ctx.projectRoot,
|
|
2955
3055
|
basePath: ctx.basePath,
|
|
2956
3056
|
resolvedPreviewCss: ctx.resolvedPreviewCss,
|
|
2957
3057
|
resolvedPreviewSetup: ctx.resolvedPreviewSetup,
|
|
@@ -3032,6 +3132,9 @@ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
|
3032
3132
|
function isMuseaStaticBuild() {
|
|
3033
3133
|
return process.env[MUSEA_STATIC_BUILD_ENV] === "1";
|
|
3034
3134
|
}
|
|
3135
|
+
function shouldEnableMuseaStaticBuild(command) {
|
|
3136
|
+
return isMuseaStaticBuild() || command === "build";
|
|
3137
|
+
}
|
|
3035
3138
|
function museaStaticBuildInput(input) {
|
|
3036
3139
|
const entries = {};
|
|
3037
3140
|
if (typeof input === "string") entries[STATIC_USER_INPUT_NAME] = input;
|
|
@@ -3047,6 +3150,9 @@ function applyMuseaStaticBuildInput(options) {
|
|
|
3047
3150
|
options.input = museaStaticBuildInput(options.input);
|
|
3048
3151
|
return null;
|
|
3049
3152
|
}
|
|
3153
|
+
function museaStaticBuildConfig(input) {
|
|
3154
|
+
return { build: { rollupOptions: { input: museaStaticBuildInput(input) } } };
|
|
3155
|
+
}
|
|
3050
3156
|
function resolveStaticRuntimeId(id) {
|
|
3051
3157
|
return id === "virtual:musea-static-runtime" ? RESOLVED_STATIC_RUNTIME : null;
|
|
3052
3158
|
}
|
|
@@ -3233,15 +3339,27 @@ function relativeUrl(fromDir, toFile) {
|
|
|
3233
3339
|
return relative.startsWith(".") ? relative : `./${relative}`;
|
|
3234
3340
|
}
|
|
3235
3341
|
//#endregion
|
|
3236
|
-
//#region src/plugin/
|
|
3237
|
-
|
|
3238
|
-
|
|
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;
|
|
3239
3348
|
try {
|
|
3240
|
-
return
|
|
3241
|
-
|
|
3242
|
-
|
|
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 });
|
|
3243
3359
|
}
|
|
3244
3360
|
}
|
|
3361
|
+
//#endregion
|
|
3362
|
+
//#region src/plugin/art-processing.ts
|
|
3245
3363
|
function extractArtTagAttributes(source) {
|
|
3246
3364
|
const artTagMatch = source.match(/<art\b([\s\S]*?)>/i);
|
|
3247
3365
|
if (!artTagMatch) return {};
|
|
@@ -3277,6 +3395,62 @@ function extractStyleBlocks(source) {
|
|
|
3277
3395
|
}
|
|
3278
3396
|
return styles;
|
|
3279
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
|
|
3280
3454
|
function musea(options = {}) {
|
|
3281
3455
|
let include = options.include ?? ["**/*.art.vue"];
|
|
3282
3456
|
let exclude = options.exclude ?? ["node_modules/**", "dist/**"];
|
|
@@ -3285,6 +3459,7 @@ function musea(options = {}) {
|
|
|
3285
3459
|
const storybookOutDir = options.storybookOutDir ?? ".storybook/stories";
|
|
3286
3460
|
let inlineArt = options.inlineArt ?? false;
|
|
3287
3461
|
const tokensPath = options.tokensPath;
|
|
3462
|
+
const projectRootOption = options.projectRoot;
|
|
3288
3463
|
const themeConfig = buildThemeConfig(options.theme);
|
|
3289
3464
|
const previewCss = options.previewCss ?? [];
|
|
3290
3465
|
const previewSetup = options.previewSetup;
|
|
@@ -3295,6 +3470,7 @@ function musea(options = {}) {
|
|
|
3295
3470
|
let resolvedPreviewCss = [];
|
|
3296
3471
|
let resolvedPreviewSetup = null;
|
|
3297
3472
|
let scanRoots = [];
|
|
3473
|
+
let staticBuildEnabled = isMuseaStaticBuild();
|
|
3298
3474
|
const virtualState = {
|
|
3299
3475
|
basePath,
|
|
3300
3476
|
get inlineArt() {
|
|
@@ -3316,13 +3492,18 @@ function musea(options = {}) {
|
|
|
3316
3492
|
apply(_config, env) {
|
|
3317
3493
|
return shouldApplyMuseaPlugin(env);
|
|
3318
3494
|
},
|
|
3319
|
-
config() {
|
|
3320
|
-
|
|
3495
|
+
config(userConfig, env) {
|
|
3496
|
+
staticBuildEnabled = shouldEnableMuseaStaticBuild(env.command);
|
|
3497
|
+
const staticBuildConfig = staticBuildEnabled ? museaStaticBuildConfig(userConfig.build?.rollupOptions?.input) : {};
|
|
3498
|
+
return {
|
|
3499
|
+
resolve: { alias: [createVueRuntimeCompilerAlias()] },
|
|
3500
|
+
...staticBuildConfig
|
|
3501
|
+
};
|
|
3321
3502
|
},
|
|
3322
3503
|
options: applyMuseaStaticBuildInput,
|
|
3323
|
-
configResolved(resolvedConfig) {
|
|
3504
|
+
async configResolved(resolvedConfig) {
|
|
3324
3505
|
config = resolvedConfig;
|
|
3325
|
-
const vizeConfig =
|
|
3506
|
+
const vizeConfig = await resolveMuseaSharedConfig(resolvedConfig);
|
|
3326
3507
|
if (vizeConfig?.musea) {
|
|
3327
3508
|
const mc = vizeConfig.musea;
|
|
3328
3509
|
if (!options.include && mc.include) include = mc.include;
|
|
@@ -3354,6 +3535,7 @@ function musea(options = {}) {
|
|
|
3354
3535
|
artFiles,
|
|
3355
3536
|
scanRoots,
|
|
3356
3537
|
tokensPath,
|
|
3538
|
+
projectRoot: resolveProjectRoot(projectRootOption, config.root),
|
|
3357
3539
|
basePath,
|
|
3358
3540
|
resolvedPreviewCss,
|
|
3359
3541
|
resolvedPreviewSetup,
|
|
@@ -3401,7 +3583,12 @@ function musea(options = {}) {
|
|
|
3401
3583
|
if (address && typeof address === "object") {
|
|
3402
3584
|
const protocol = devServer.config.server.https ? "https" : "http";
|
|
3403
3585
|
const rawHost = address.address;
|
|
3404
|
-
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}`;
|
|
3405
3592
|
console.log();
|
|
3406
3593
|
console.log(` \x1b[36m➜\x1b[0m \x1b[1mMusea Gallery:\x1b[0m \x1b[36m${url}\x1b[0m`);
|
|
3407
3594
|
}
|
|
@@ -3410,6 +3597,7 @@ function musea(options = {}) {
|
|
|
3410
3597
|
},
|
|
3411
3598
|
async buildStart() {
|
|
3412
3599
|
console.log(`[musea] config.root: ${config.root}, include: ${JSON.stringify(include)}`);
|
|
3600
|
+
if (storybookCompat && staticBuildEnabled) await assertNoUnsupportedStorybookTsxInputs(config.root, include, exclude);
|
|
3413
3601
|
const files = await scanArtFiles(config.root, include, exclude, inlineArt);
|
|
3414
3602
|
console.log(`[musea] Found ${files.length} art files`);
|
|
3415
3603
|
if (server) watchMuseaArtFiles(server.watcher, files);
|
|
@@ -3423,12 +3611,13 @@ function musea(options = {}) {
|
|
|
3423
3611
|
return loadStaticRuntimeModule(id, artFiles) ?? virtualLoad(id);
|
|
3424
3612
|
},
|
|
3425
3613
|
async generateBundle(_options, bundle) {
|
|
3426
|
-
if (!
|
|
3614
|
+
if (!staticBuildEnabled) return;
|
|
3427
3615
|
await emitStaticGallery((asset) => void this.emitFile(asset), bundle, {
|
|
3428
3616
|
config,
|
|
3429
3617
|
artFiles,
|
|
3430
3618
|
scanRoots,
|
|
3431
3619
|
tokensPath,
|
|
3620
|
+
projectRoot: resolveProjectRoot(projectRootOption, config.root),
|
|
3432
3621
|
basePath,
|
|
3433
3622
|
resolvedPreviewCss,
|
|
3434
3623
|
resolvedPreviewSetup,
|
|
@@ -3450,46 +3639,19 @@ function musea(options = {}) {
|
|
|
3450
3639
|
handleHotUpdate: createHandleHotUpdate(virtualState)
|
|
3451
3640
|
};
|
|
3452
3641
|
async function processArtFile(filePath) {
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
const isInline = !filePath.endsWith(".art.vue");
|
|
3459
|
-
const info = {
|
|
3460
|
-
path: filePath,
|
|
3461
|
-
metadata: {
|
|
3462
|
-
title: parsed.metadata.title || (isInline ? path.basename(filePath, ".vue") : ""),
|
|
3463
|
-
description: parsed.metadata.description,
|
|
3464
|
-
component: isInline ? void 0 : parsed.metadata.component,
|
|
3465
|
-
category: parsed.metadata.category,
|
|
3466
|
-
tags: parsed.metadata.tags,
|
|
3467
|
-
status: parsed.metadata.status,
|
|
3468
|
-
order: parsed.metadata.order,
|
|
3469
|
-
actionEvents: customMetadata.actionEvents ?? parsed.metadata.actionEvents
|
|
3470
|
-
},
|
|
3471
|
-
variants: parsed.variants.map((v) => ({
|
|
3472
|
-
name: v.name,
|
|
3473
|
-
template: v.template,
|
|
3474
|
-
isDefault: v.isDefault,
|
|
3475
|
-
skipVrt: v.skipVrt
|
|
3476
|
-
})),
|
|
3477
|
-
hasScriptSetup: isInline ? false : parsed.hasScriptSetup,
|
|
3478
|
-
scriptSetupContent: !isInline && parsed.hasScriptSetup ? extractScriptSetupContent(source) : void 0,
|
|
3479
|
-
scriptSetupIsolated: !isInline && parsed.hasScriptSetup ? extractScriptSetupIsolated(source) : true,
|
|
3480
|
-
hasScript: parsed.hasScript,
|
|
3481
|
-
styleCount: parsed.styleCount,
|
|
3482
|
-
styleBlocks: isInline ? [] : extractStyleBlocks(source),
|
|
3483
|
-
isInline,
|
|
3484
|
-
componentPath: isInline ? filePath : void 0
|
|
3485
|
-
};
|
|
3486
|
-
artFiles.set(filePath, info);
|
|
3487
|
-
} catch (e) {
|
|
3488
|
-
console.error(`[musea] Failed to process ${filePath}:`, e);
|
|
3489
|
-
}
|
|
3642
|
+
const info = await processMuseaArtFile(filePath, {
|
|
3643
|
+
root: config.root,
|
|
3644
|
+
command: config.command
|
|
3645
|
+
});
|
|
3646
|
+
if (info) artFiles.set(filePath, info);
|
|
3490
3647
|
}
|
|
3491
3648
|
return [mainPlugin];
|
|
3492
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
|
+
}
|
|
3493
3655
|
//#endregion
|
|
3494
3656
|
//#region src/index.ts
|
|
3495
3657
|
var src_default = musea;
|