@deot/docs-playground 1.1.4 → 1.1.5

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.
@@ -1,7 +1,4 @@
1
- const require_scss = require("./scss-B8OFbz1k.cjs");
2
- const require_files = require("./files-BsAOZiPN.cjs");
3
- const require_script = require("./script-BiCcpu3G.cjs");
4
- const require_local_sandbox = require("./local-sandbox-0ojvBQPO.cjs");
1
+ const require_css = require("./css-DpqJBQ5c.cjs");
5
2
  let sass = require("sass");
6
3
  //#region packages/playground/src/core/runtime/local/compile/scss.ts
7
4
  /**
@@ -21,7 +18,7 @@ var toScssFiles = (files) => {
21
18
  };
22
19
  var compileLocalScss = (source, filename, files, lang) => {
23
20
  try {
24
- return require_scss.compileScssSource(source, filename.replace(/^\/+/u, ""), compiler, toScssFiles(files), lang);
21
+ return require_css.compileScssSource(source, filename.replace(/^\/+/u, ""), compiler, toScssFiles(files), lang);
25
22
  } catch (error) {
26
23
  /* istanbul ignore next -- Sass 失败时 message 总是字符串 */
27
24
  const message = error instanceof Error ? error.message : String(error);
@@ -188,7 +185,7 @@ var transformJson = (parsed, filename) => {
188
185
  return lines.join("\n");
189
186
  };
190
187
  var compileOne = async (filename, code, files) => {
191
- const ext = require_files.getExtension(filename);
188
+ const ext = require_css.getExtension(filename);
192
189
  const errors = [];
193
190
  if (ext === ".vue") {
194
191
  if (/lang\s*=\s*["']jsx["']/iu.test(code) || /lang\s*=\s*["']tsx["']/iu.test(code)) {
@@ -204,7 +201,7 @@ var compileOne = async (filename, code, files) => {
204
201
  errors.push(...result.errors);
205
202
  return {
206
203
  filename,
207
- js: require_script.transformScript(result.js, filename, { typescript: true }),
204
+ js: require_css.transformScript(result.js, filename, { typescript: true }),
208
205
  css: result.css,
209
206
  errors
210
207
  };
@@ -216,7 +213,7 @@ var compileOne = async (filename, code, files) => {
216
213
  errors
217
214
  };
218
215
  if (ext === ".scss" || ext === ".sass") try {
219
- const { css, exports: styleExports } = require_scss.extractScssExports(compileLocalScss(code, filename, files), filename);
216
+ const { css, exports: styleExports } = require_css.extractScssExports(compileLocalScss(code, filename, files), filename);
220
217
  return {
221
218
  filename,
222
219
  js: `exports.__esModule = true; exports.default = ${JSON.stringify(styleExports)};\n//# sourceURL=playground://${filename}`,
@@ -251,7 +248,7 @@ var compileOne = async (filename, code, files) => {
251
248
  if (ext === ".js" || ext === ".ts" || ext === ".jsx" || ext === ".tsx") try {
252
249
  return {
253
250
  filename,
254
- js: require_script.transformScript(code, filename, {
251
+ js: require_css.transformScript(code, filename, {
255
252
  typescript: ext === ".ts" || ext === ".tsx",
256
253
  jsx: ext === ".jsx" || ext === ".tsx"
257
254
  }),
@@ -286,7 +283,7 @@ var compilePlayground = async (files, entryOrOptions) => {
286
283
  const errors = [];
287
284
  let entry;
288
285
  try {
289
- entry = require_files.resolveEntry(files, options.entry);
286
+ entry = require_css.resolveEntry(files, options.entry);
290
287
  } catch (error) {
291
288
  return {
292
289
  entry: "",
@@ -295,8 +292,8 @@ var compilePlayground = async (files, entryOrOptions) => {
295
292
  errors: [messageOf(error)]
296
293
  };
297
294
  }
298
- const fileIndex = require_files.createFileIndex(files);
299
- const reachable = require_files.collectReachableFilenames(files, entry);
295
+ const fileIndex = require_css.createFileIndex(files);
296
+ const reachable = require_css.collectReachableFilenames(files, entry);
300
297
  const modules = {};
301
298
  const cssChunks = [];
302
299
  for (const filename of reachable) {
@@ -309,9 +306,9 @@ var compilePlayground = async (files, entryOrOptions) => {
309
306
  js: compiled.js,
310
307
  css: compiled.css
311
308
  };
312
- cssChunks.push(...require_local_sandbox.collectCss([compiled.css]));
309
+ cssChunks.push(...require_css.collectCss([compiled.css]));
313
310
  }
314
- const normalizedEntry = require_files.normalizeVirtualPath(entry);
311
+ const normalizedEntry = require_css.normalizeVirtualPath(entry);
315
312
  /* istanbul ignore if -- 可达编译总会留下入口模块 */
316
313
  if (!modules[normalizedEntry]) errors.push(`[Playground] 入口编译结果缺失: ${normalizedEntry}`);
317
314
  return {
@@ -1,7 +1,4 @@
1
- import { d as resolveEntry, n as collectReachableFilenames, o as getExtension, r as createFileIndex, u as normalizeVirtualPath } from "./files-BqucFldk.js";
2
- import { n as compileScssSource, r as extractScssExports } from "./scss-DIh6971q.js";
3
- import { n as transformScript } from "./script-DjUf9uWK.js";
4
- import { n as collectCss } from "./local-sandbox-DvcgaBOa.js";
1
+ import { a as transformScript, c as createFileIndex, h as resolveEntry, m as normalizeVirtualPath, s as collectReachableFilenames, t as collectCss, u as getExtension, v as compileScssSource, y as extractScssExports } from "./css-DleINdoA.js";
5
2
  import { compileString } from "sass";
6
3
  //#region packages/playground/src/core/runtime/local/compile/scss.ts
7
4
  /**
@@ -0,0 +1,580 @@
1
+ import { watch } from "vue";
2
+ import { transform } from "sucrase";
3
+ import * as VueCompiler from "@vue/compiler-sfc/dist/compiler-sfc.esm-browser.js";
4
+ //#region packages/playground/src/constants.ts
5
+ var DEFAULT_ENTRY = "App.vue";
6
+ /** 预览样式和默认 import map 共用的 npm CDN 前缀。 */
7
+ var DEFAULT_CDN_URL = "https://cdn.jsdelivr.net/npm";
8
+ var NEW_SFC_CODE = `<script setup lang="ts"><\/script>\n\n<template>\n <div>\n <slot />\n <\/div>\n<\/template>\n`;
9
+ //#endregion
10
+ //#region packages/playground/src/cdn.ts
11
+ var PREVIEW_STYLE_ASSETS = [
12
+ "@deot/style/dist/index.normalize-only.css",
13
+ "@deot/vc-components/dist/index.style.css",
14
+ "@deot/style/dist/index.css"
15
+ ];
16
+ var BUILTIN_IMPORT_ASSETS = {
17
+ "@deot/vc": "@deot/vc/dist/index.js",
18
+ "@deot/vc-shared": "@deot/vc-shared/dist/index.js",
19
+ "@deot/vc-hooks": "@deot/vc-hooks/dist/index.js",
20
+ "@deot/vc-locale": "@deot/vc-locale/dist/index.js",
21
+ "@deot/vc-components": "@deot/vc-components/dist/index.js",
22
+ "@deot/helper-resize": "@deot/helper-resize/dist/index.js",
23
+ "@deot/helper-utils": "@deot/helper-utils/dist/index.js",
24
+ "@deot/helper-cache": "@deot/helper-cache/dist/index.js",
25
+ "@deot/helper-fp": "@deot/helper-fp/dist/index.js",
26
+ "@deot/helper-dom": "@deot/helper-dom/dist/index.js",
27
+ "@deot/helper-wheel": "@deot/helper-wheel/dist/index.js",
28
+ "@deot/helper-validator": "@deot/helper-validator/dist/index.js",
29
+ "@deot/helper-load": "@deot/helper-load/dist/index.js",
30
+ "@deot/helper-scheduler": "@deot/helper-scheduler/dist/index.js",
31
+ "@deot/helper-emitter": "@deot/helper-emitter/dist/index.js",
32
+ "@deot/helper-is": "@deot/helper-is/dist/index.js",
33
+ "@deot/helper-device": "@deot/helper-device/dist/index.js",
34
+ "@deot/helper-route": "@deot/helper-route/dist/index.js",
35
+ "@deot/helper-unicode": "@deot/helper-unicode/dist/index.js",
36
+ "@deot/helper": "@deot/helper/dist/index.js",
37
+ "normalize-wheel": "normalize-wheel-es/dist/index.mjs",
38
+ "photoswipe": "photoswipe/dist/photoswipe.esm.js",
39
+ "photoswipe/lightbox": "photoswipe/dist/photoswipe-lightbox.esm.js",
40
+ "vue": "vue/dist/vue.runtime.esm-browser.js",
41
+ "vue/server-renderer": "vue/dist/server-renderer.esm-browser.js"
42
+ };
43
+ var normalizeCdnURL = (cdnURL = DEFAULT_CDN_URL) => {
44
+ return cdnURL.trim().replace(/\/+$/u, "") || "https://cdn.jsdelivr.net/npm";
45
+ };
46
+ var cdnJoin = (origin, asset) => `${origin}/${asset.replace(/^\/+/u, "")}`;
47
+ var jsdelivrEsmURL = (asset) => cdnJoin(DEFAULT_CDN_URL, asset);
48
+ var SASS_CDN_URL = jsdelivrEsmURL("sass/+esm");
49
+ var cdnAsset = (cdnURL, asset) => cdnJoin(normalizeCdnURL(cdnURL), asset);
50
+ var createBuiltinImports = (cdnURL = DEFAULT_CDN_URL) => ({
51
+ ...Object.fromEntries(Object.entries(BUILTIN_IMPORT_ASSETS).map(([specifier, asset]) => [specifier, cdnAsset(cdnURL, asset)])),
52
+ "lodash-es": jsdelivrEsmURL("lodash-es/+esm")
53
+ });
54
+ var createBuiltinStyles = (cdnURL = DEFAULT_CDN_URL) => Object.fromEntries(PREVIEW_STYLE_ASSETS.map((asset) => [asset, cdnAsset(cdnURL, asset)]));
55
+ var resolveNpmImport = (specifier) => /^https?:\/\//.test(specifier) ? specifier : jsdelivrEsmURL(`${specifier}/+esm`);
56
+ //#endregion
57
+ //#region packages/playground/src/core/scss.ts
58
+ var SCHEME = "docs-playground";
59
+ var STYLE_EXTS = [".scss", ".sass"];
60
+ var VUE_SCSS_STYLE_RE = /<style\b[^>]*\blang\s*=\s*(['"]?)s[ac]ss\1/i;
61
+ var LANG_ATTR_RE = /\s*lang\s*=\s*(['"]?)s[ac]ss\1/i;
62
+ var SCSS_ERROR_MARK = "[playground-sass]";
63
+ var INJECT_START = "/* docs-playground-scss-start */";
64
+ var INJECT_END = "/* docs-playground-scss-end */";
65
+ var boundStores = /* @__PURE__ */ new WeakSet();
66
+ var wrappedCompilers = /* @__PURE__ */ new WeakSet();
67
+ var loadedSass;
68
+ var loadPromise;
69
+ var fileCode = (value) => typeof value === "string" ? value : value.code;
70
+ var playgroundPath = (url) => decodeURIComponent(url.pathname.replace(/^\/+/u, ""));
71
+ var toPlaygroundUrl = (filename) => new URL(`${SCHEME}:///${filename.replace(/^\/+/u, "")}`);
72
+ var basename$1 = (path) => path.split("/").pop() || path;
73
+ var scssSyntax = (filename, lang) => lang === "sass" || /\.sass$/i.test(filename) ? "indented" : "scss";
74
+ var errorText = (item) => item instanceof Error ? item.message : String(item);
75
+ var isScssFile = (filename) => /\.s[ac]ss$/i.test(filename);
76
+ var vueSourceNeedsScss = (source) => VUE_SCSS_STYLE_RE.test(source);
77
+ var resolveSassModule = async (url) => {
78
+ const mod = await import(
79
+ /* @vite-ignore */
80
+ url
81
+ );
82
+ const sass = typeof mod.compileString === "function" ? mod : mod.default;
83
+ if (typeof sass?.compileString !== "function") throw new Error(`Sass module at ${url} does not export compileString`);
84
+ return sass;
85
+ };
86
+ var loadSass = () => {
87
+ loadPromise ??= (() => resolveSassModule(SASS_CDN_URL))().then((sass) => {
88
+ loadedSass = sass;
89
+ return sass;
90
+ });
91
+ return loadPromise;
92
+ };
93
+ var isScssPartial = (filename) => isScssFile(filename) && basename$1(filename).startsWith("_");
94
+ var filesNeedScss = (files) => Object.entries(files).some(([filename, value]) => isScssFile(filename) || /\.vue$/i.test(filename) && vueSourceNeedsScss(fileCode(value)));
95
+ var whenSassReady = (files, run) => {
96
+ if (!filesNeedScss(files) || loadedSass) run();
97
+ else loadSass().then(run);
98
+ };
99
+ var toPlaygroundFileMap = (files) => Object.fromEntries(Object.entries(files).map(([filename, value]) => [filename, fileCode(value)]));
100
+ var formatScssError = (filename, message) => `${SCSS_ERROR_MARK} ${filename}: ${message}`;
101
+ var scssFail = (filename, error) => formatScssError(filename, errorText(error));
102
+ var withUnderscore = (path) => {
103
+ const base = basename$1(path);
104
+ if (base.startsWith("_")) return path;
105
+ return `${path.slice(0, -base.length)}_${base}`;
106
+ };
107
+ var matchFileKey = (files, path) => [
108
+ path,
109
+ path.startsWith("src/") ? path : `src/${path}`,
110
+ path.replace(/^src\//u, "")
111
+ ].find((key) => files[key] !== void 0);
112
+ var stylesheetCandidates = (requestPath) => {
113
+ if (isScssFile(requestPath)) return [requestPath, withUnderscore(requestPath)];
114
+ return STYLE_EXTS.flatMap((ext) => [
115
+ `${requestPath}${ext}`,
116
+ withUnderscore(`${requestPath}${ext}`),
117
+ `${requestPath}/index${ext}`,
118
+ withUnderscore(`${requestPath}/index${ext}`)
119
+ ]);
120
+ };
121
+ var resolvePlaygroundStylesheet = (files, requestPath) => {
122
+ const found = [...new Set(stylesheetCandidates(requestPath).map((path) => matchFileKey(files, path)).filter((key) => Boolean(key)))];
123
+ if (found.length > 1) throw new Error(`Ambiguous Sass import "${requestPath}": ${found.join(", ")}`);
124
+ return found[0] ?? null;
125
+ };
126
+ var createPlaygroundImporter = (getFiles) => ({
127
+ canonicalize(url, context) {
128
+ if (/^[a-zA-Z][\w+.-]*:/u.test(url) && !url.startsWith(`${SCHEME}:`)) return null;
129
+ try {
130
+ const resolved = resolvePlaygroundStylesheet(getFiles(), playgroundPath(new URL(url, context.containingUrl ?? toPlaygroundUrl(""))));
131
+ return resolved ? toPlaygroundUrl(resolved) : null;
132
+ } catch {
133
+ return null;
134
+ }
135
+ },
136
+ load(canonicalUrl) {
137
+ const files = getFiles();
138
+ const key = playgroundPath(canonicalUrl);
139
+ return files[key] === void 0 ? null : {
140
+ contents: files[key],
141
+ syntax: scssSyntax(key)
142
+ };
143
+ }
144
+ });
145
+ var compileScssSource = (source, filename, sass, files, lang) => {
146
+ const importer = createPlaygroundImporter(() => files);
147
+ return sass.compileString(source, {
148
+ syntax: scssSyntax(filename, lang),
149
+ url: toPlaygroundUrl(filename),
150
+ importer,
151
+ importers: [importer]
152
+ }).css;
153
+ };
154
+ var rewriteVueSfcStyles = (source, filename, parse, sass, files) => {
155
+ const scssStyles = parse(source, { filename }).descriptor.styles.filter((style) => style.lang === "scss" || style.lang === "sass");
156
+ if (!scssStyles.length) return {
157
+ code: source,
158
+ errors: []
159
+ };
160
+ const errors = [];
161
+ let code = source;
162
+ for (const style of [...scssStyles].sort((left, right) => right.loc.start.offset - left.loc.start.offset)) {
163
+ const before = code.slice(0, style.loc.start.offset);
164
+ const after = code.slice(style.loc.end.offset);
165
+ const openStart = before.lastIndexOf("<style");
166
+ if (openStart < 0) {
167
+ errors.push(formatScssError(filename, "unable to locate <style> opening tag"));
168
+ continue;
169
+ }
170
+ try {
171
+ const css = compileScssSource(style.content, filename, sass, files, style.lang);
172
+ code = `${before.slice(0, openStart)}${before.slice(openStart).replace(LANG_ATTR_RE, "")}${css}${after}`;
173
+ } catch (error) {
174
+ errors.push(scssFail(filename, error));
175
+ }
176
+ }
177
+ return {
178
+ code,
179
+ errors
180
+ };
181
+ };
182
+ var appendParseErrors = (result, errors) => errors.length ? {
183
+ ...result,
184
+ errors: [...result.errors, ...errors.map((item) => new Error(item))]
185
+ } : result;
186
+ var wrapCompiler = (compiler, getFiles) => {
187
+ if (wrappedCompilers.has(compiler)) return compiler;
188
+ const originalParse = compiler.parse.bind(compiler);
189
+ const wrapped = { ...compiler };
190
+ wrapped.parse = ((source, options) => {
191
+ const filename = options?.filename || "anonymous.vue";
192
+ if (!vueSourceNeedsScss(source)) return originalParse(source, options);
193
+ const rewritten = loadedSass ? rewriteVueSfcStyles(source, filename, originalParse, loadedSass, getFiles()) : {
194
+ code: source,
195
+ errors: [formatScssError(filename, "compiler is not loaded")]
196
+ };
197
+ return appendParseErrors(originalParse(rewritten.errors.length ? source : rewritten.code, options), rewritten.errors);
198
+ });
199
+ wrappedCompilers.add(wrapped);
200
+ return wrapped;
201
+ };
202
+ var withInjectedCss = (css, extra) => {
203
+ const start = css.indexOf(INJECT_START);
204
+ const end = start < 0 ? -1 : css.indexOf(INJECT_END, start);
205
+ const base = (start < 0 ? css : `${css.slice(0, start)}${end >= 0 ? css.slice(end + 30) : ""}`).trimEnd();
206
+ if (!extra.trim()) return base;
207
+ const block = `${INJECT_START}\n${extra.trim()}\n${INJECT_END}`;
208
+ return base ? `${base}\n${block}` : block;
209
+ };
210
+ var isStandaloneScssError = (item) => {
211
+ const text = errorText(item);
212
+ return text.startsWith(SCSS_ERROR_MARK) && /\.s[ac]ss:/i.test(text);
213
+ };
214
+ var syncScssErrors = (store, scssErrors) => {
215
+ const next = [...scssErrors, ...store.errors.filter((item) => !isStandaloneScssError(item))];
216
+ if (next.map(String).join("\0") === store.errors.map(String).join("\0")) return;
217
+ store.errors = next;
218
+ };
219
+ var extractScssExports = (css, filename) => {
220
+ const exports = {};
221
+ if (/\.module\.(?:scss|sass)$/.test(filename)) css = css.replace(/:export\s*\{([^}]*)\}/g, (_block, declarations) => {
222
+ for (const declaration of declarations.split(";")) {
223
+ const colon = declaration.indexOf(":");
224
+ if (colon >= 0) exports[declaration.slice(0, colon).trim()] = declaration.slice(colon + 1).trim();
225
+ }
226
+ return "";
227
+ });
228
+ return {
229
+ css,
230
+ exports
231
+ };
232
+ };
233
+ var applyStandaloneScss = (store, sass = loadedSass) => {
234
+ if (!sass) return [];
235
+ const fileMap = toPlaygroundFileMap(store.files);
236
+ const errors = [];
237
+ const injected = [];
238
+ for (const [filename, file] of Object.entries(store.files)) {
239
+ if (!isScssFile(filename) || !file.compiled) continue;
240
+ try {
241
+ const { css, exports } = extractScssExports(compileScssSource(file.code, filename, sass, fileMap), filename);
242
+ file.compiled.css = css;
243
+ file.compiled.js = file.compiled.ssr = `export default ${JSON.stringify(exports)};\n`;
244
+ if (!isScssPartial(filename) && css.trim()) injected.push(css);
245
+ } catch (error) {
246
+ errors.push(scssFail(filename, error));
247
+ }
248
+ }
249
+ const main = store.files[store.mainFile];
250
+ if (main?.compiled) {
251
+ const next = withInjectedCss(main.compiled.css || "", injected.join("\n"));
252
+ if (next !== (main.compiled.css || "")) main.compiled.css = next;
253
+ }
254
+ syncScssErrors(store, errors);
255
+ return errors;
256
+ };
257
+ var bindPlaygroundScss = (store) => {
258
+ if (boundStores.has(store)) return;
259
+ boundStores.add(store);
260
+ const getFiles = () => toPlaygroundFileMap(store.files);
261
+ const installCompiler = () => {
262
+ if (typeof store.compiler?.parse === "function") store.compiler = wrapCompiler(store.compiler, getFiles);
263
+ };
264
+ installCompiler();
265
+ watch(() => store.compiler, installCompiler);
266
+ watch(() => [
267
+ store.mainFile,
268
+ store.files[store.mainFile]?.compiled?.css,
269
+ store.errors.map(String).join("\0"),
270
+ Object.entries(store.files).filter(([filename]) => isScssFile(filename)).map(([filename, file]) => `${filename}:${file.code}`).join("\n")
271
+ ].join("\0"), () => {
272
+ if (loadedSass) applyStandaloneScss(store);
273
+ });
274
+ const originalSetFiles = store.setFiles.bind(store);
275
+ store.setFiles = async (newFiles, mainFile) => {
276
+ if (filesNeedScss(newFiles) && !loadedSass) await loadSass();
277
+ return originalSetFiles(newFiles, mainFile);
278
+ };
279
+ };
280
+ //#endregion
281
+ //#region packages/playground/src/core/runtime/local/compile/types.ts
282
+ var IGNORED_FILENAMES = /* @__PURE__ */ new Set(["import-map.json", "tsconfig.json"]);
283
+ //#endregion
284
+ //#region packages/playground/src/core/runtime/local/compile/files.ts
285
+ /**
286
+ * 统一成以 `/` 开头的 POSIX 绝对虚拟路径。
287
+ * `App.vue` 与 `/App.vue` 是同一文件,和 iframe 预览使用的 files 键一致。
288
+ * @param filename Playground files 的键或相对路径。
289
+ * @returns 以 `/` 开头的虚拟路径。
290
+ */
291
+ var normalizeVirtualPath = (filename) => {
292
+ const raw = String(filename || "").replace(/\\/gu, "/").trim();
293
+ if (!raw) return "/";
294
+ const parts = (raw.startsWith("/") ? raw : `/${raw}`).split("/");
295
+ const stack = [];
296
+ for (const part of parts) {
297
+ if (!part || part === ".") continue;
298
+ if (part === "..") {
299
+ if (stack.length) stack.pop();
300
+ continue;
301
+ }
302
+ stack.push(part);
303
+ }
304
+ return `/${stack.join("/")}`;
305
+ };
306
+ var dirname = (filename) => {
307
+ const path = normalizeVirtualPath(filename);
308
+ const index = path.lastIndexOf("/");
309
+ if (index <= 0) return "/";
310
+ return path.slice(0, index) || "/";
311
+ };
312
+ var basename = (filename) => {
313
+ const path = normalizeVirtualPath(filename);
314
+ const index = path.lastIndexOf("/");
315
+ return index === -1 ? path : path.slice(index + 1);
316
+ };
317
+ var joinVirtualPath = (baseDir, relative) => {
318
+ const rel = String(relative || "").replace(/\\/gu, "/");
319
+ if (rel.startsWith("/")) return normalizeVirtualPath(rel);
320
+ const base = normalizeVirtualPath(baseDir);
321
+ return normalizeVirtualPath(`${base === "/" ? "" : base}/${rel}`);
322
+ };
323
+ var getExtension = (filename) => {
324
+ const name = basename(filename);
325
+ const index = name.lastIndexOf(".");
326
+ if (index <= 0) return "";
327
+ return name.slice(index).toLowerCase();
328
+ };
329
+ var isIgnoredFilename = (filename) => IGNORED_FILENAMES.has(basename(filename));
330
+ var createFileIndex = (files) => {
331
+ const index = /* @__PURE__ */ new Map();
332
+ Object.entries(files || {}).forEach(([filename, code]) => {
333
+ const normalized = normalizeVirtualPath(filename);
334
+ if (isIgnoredFilename(normalized)) return;
335
+ index.set(normalized, code);
336
+ });
337
+ return index;
338
+ };
339
+ var resolveEntry = (files, entry) => {
340
+ const index = createFileIndex(files);
341
+ if (!index.size) throw new Error("[Playground] files 为空,无法确定入口");
342
+ if (entry) {
343
+ const normalized = normalizeVirtualPath(entry);
344
+ if (isIgnoredFilename(normalized)) throw new Error(`[Playground] entry 不能是 ${basename(normalized)}`);
345
+ if (!index.has(normalized)) throw new Error(`[Playground] entry 不在 files 中: ${entry}`);
346
+ return normalized;
347
+ }
348
+ for (const key of Object.keys(files || {})) {
349
+ const normalized = normalizeVirtualPath(key);
350
+ if (!isIgnoredFilename(normalized) && index.has(normalized)) return normalized;
351
+ }
352
+ /* istanbul ignore next -- 忽略文件已在前面排除,正常 files 不会走到这里 */
353
+ throw new Error("[Playground] files 中没有可用的入口文件");
354
+ };
355
+ var CANDIDATE_EXTENSIONS = [
356
+ ".vue",
357
+ ".ts",
358
+ ".js",
359
+ ".tsx",
360
+ ".jsx",
361
+ ".json",
362
+ ".css",
363
+ ".scss",
364
+ ".sass"
365
+ ];
366
+ /**
367
+ * 相对 / 无扩展名解析,行为对齐 Vite:精确路径、补扩展名、`/index.*`。
368
+ * @param fromFilename 发起导入的文件。
369
+ * @param specifier 相对或绝对虚拟路径。
370
+ * @param fileIndex 虚拟路径到 files 键的索引。
371
+ * @returns 解析后的 files 键;找不到时返回 null。
372
+ */
373
+ var resolveModulePath = (fromFilename, specifier, fileIndex) => {
374
+ if (!specifier || !(specifier === "." || specifier === ".." || specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith("/"))) return null;
375
+ const target = joinVirtualPath(dirname(fromFilename), specifier);
376
+ if (fileIndex.has(target)) return target;
377
+ for (const ext of CANDIDATE_EXTENSIONS) {
378
+ const withExt = `${target}${ext}`;
379
+ if (fileIndex.has(withExt)) return withExt;
380
+ }
381
+ for (const ext of CANDIDATE_EXTENSIONS) {
382
+ const asIndex = `${target}/index${ext}`;
383
+ if (fileIndex.has(asIndex)) return asIndex;
384
+ }
385
+ return null;
386
+ };
387
+ var getCommonRoot = (filenames) => {
388
+ const normalized = filenames.map(normalizeVirtualPath);
389
+ if (!normalized.length) return "/";
390
+ const split = normalized.map((path) => path.split("/").filter(Boolean));
391
+ const first = split[0];
392
+ let depth = first.length;
393
+ for (let i = 1; i < split.length; i += 1) {
394
+ let common = 0;
395
+ while (common < depth && common < split[i].length && first[common] === split[i][common]) common += 1;
396
+ depth = common;
397
+ }
398
+ if (!depth) return "/";
399
+ const maybeFile = `/${first.slice(0, depth).join("/")}`;
400
+ if (normalized.some((path) => path === maybeFile)) return dirname(maybeFile);
401
+ return maybeFile;
402
+ };
403
+ var isInsideRoot = (filename, root) => {
404
+ const path = normalizeVirtualPath(filename);
405
+ const base = normalizeVirtualPath(root);
406
+ if (base === "/") return true;
407
+ return path === base || path.startsWith(`${base}/`);
408
+ };
409
+ /**
410
+ * 静态 import / export-from / import() 的模块说明符。
411
+ * @param code 源码文本。
412
+ * @returns 按出现顺序收集到的说明符。
413
+ */
414
+ var listImportSpecifiers = (code) => {
415
+ const result = [];
416
+ const source = String(code || "");
417
+ for (const match of source.matchAll(/(?:\bfrom\s+|import\s*\(\s*|import\s+)['"]([^'"]+)['"]/gu)) if (match[1]) result.push(match[1]);
418
+ return result;
419
+ };
420
+ var isRelativeSpecifier = (id) => id === "." || id === ".." || id.startsWith("./") || id.startsWith("../") || id.startsWith("/");
421
+ /**
422
+ * 从入口出发只编译静态 import 能走到的文件。
423
+ * @param files 当前 Playground 文件表。
424
+ * @param entry 入口文件名。
425
+ * @returns 可达文件名,入口在最前。
426
+ */
427
+ var collectReachableFilenames = (files, entry) => {
428
+ const index = createFileIndex(files);
429
+ const ordered = [];
430
+ const seen = /* @__PURE__ */ new Set();
431
+ const visit = (filename) => {
432
+ const key = normalizeVirtualPath(filename);
433
+ if (seen.has(key) || !index.has(key)) return;
434
+ seen.add(key);
435
+ ordered.push(key);
436
+ listImportSpecifiers(index.get(key) || "").forEach((specifier) => {
437
+ const resolved = resolveModulePath(key, specifier, index);
438
+ if (resolved) visit(resolved);
439
+ });
440
+ };
441
+ visit(entry);
442
+ return ordered;
443
+ };
444
+ var collectBareSpecifiers = (files, filenames) => {
445
+ const index = createFileIndex(files);
446
+ const result = [];
447
+ const seen = /* @__PURE__ */ new Set();
448
+ filenames.forEach((filename) => {
449
+ listImportSpecifiers(index.get(normalizeVirtualPath(filename)) || "").forEach((specifier) => {
450
+ if (!specifier || isRelativeSpecifier(specifier) || seen.has(specifier) || /\.(?:css|scss|sass)(?:[?#]|$)/.test(specifier)) return;
451
+ seen.add(specifier);
452
+ result.push(specifier);
453
+ });
454
+ });
455
+ return result;
456
+ };
457
+ //#endregion
458
+ //#region packages/playground/src/core/runtime/local/compile/script.ts
459
+ var { babelParse, walkIdentifiers, MagicString } = VueCompiler;
460
+ var rewriteJsxAttributes = (code) => {
461
+ const replacements = [];
462
+ for (const match of code.matchAll(/\b([\w-]+:[\w-]+)\s*=\s*\{/g)) {
463
+ let depth = 1;
464
+ let quote = "";
465
+ const start = match.index + match[0].length;
466
+ let end = start;
467
+ for (; end < code.length; end += 1) {
468
+ const character = code[end];
469
+ if (quote) {
470
+ if (character === "\\") end += 1;
471
+ else if (character === quote) quote = "";
472
+ } else if ("\"'`".includes(character)) quote = character;
473
+ else if (character === "{") depth += 1;
474
+ else if (character === "}" && --depth === 0) break;
475
+ }
476
+ replacements.push({
477
+ start: match.index,
478
+ end: end + 1,
479
+ text: `{...{${JSON.stringify(match[1])}: ${code.slice(start, end)}}}`
480
+ });
481
+ }
482
+ for (const item of replacements.reverse()) code = code.slice(0, item.start) + item.text + code.slice(item.end);
483
+ return code;
484
+ };
485
+ var removeImportedTypeExports = (code) => {
486
+ const types = /* @__PURE__ */ new Set();
487
+ for (const match of code.matchAll(/\bimport\s+type\s*\{([^}]+)\}\s*from\s*['"][^'"]+['"]/g)) for (const item of match[1].split(",")) types.add(item.trim().split(/\s+as\s+/).pop());
488
+ return code.replace(/\bexport\s*\{([^}]+)\}(?!\s*from)/g, (_statement, names) => `export {${names.split(",").filter((item) => !types.has(item.trim().split(/\s+as\s+/)[0])).join(",")}}`);
489
+ };
490
+ /**
491
+ * files 里的 `import.meta.env` 没有 Vite 注入,接到开发态占位对象上。
492
+ * @param code 源码文本。
493
+ * @param filename 当前虚拟文件名。
494
+ * @returns 替换 `import.meta` 之后的源码。
495
+ */
496
+ var rewriteImportMeta = (code, filename) => {
497
+ if (!code.includes("process") && !code.includes("import.meta")) return code;
498
+ const source = new MagicString(code);
499
+ let hasMeta = false;
500
+ walkIdentifiers(babelParse(code, { sourceType: "module" }), (id, parent, parents) => {
501
+ if (id.name === "import" && parent?.type === "MetaProperty") {
502
+ source.overwrite(parent.start, parent.end, "import_meta");
503
+ hasMeta = true;
504
+ }
505
+ const outer = parents[parents.length - 2];
506
+ if (id.name === "process" && parent?.type === "MemberExpression" && parent.object === id && !parent.computed && parent.property.type === "Identifier" && parent.property.name === "env" && outer?.type === "MemberExpression" && outer.object === parent && !outer.computed && outer.property.type === "Identifier" && outer.property.name === "NODE_ENV") source.overwrite(outer.start, outer.end, JSON.stringify("development"));
507
+ }, true);
508
+ if (!hasMeta) return source.toString();
509
+ const meta = {
510
+ url: `playground://${filename}`,
511
+ env: {
512
+ MODE: "development",
513
+ DEV: true,
514
+ PROD: false,
515
+ SSR: false
516
+ }
517
+ };
518
+ return `var import_meta = ${JSON.stringify(meta)};\n${source}`;
519
+ };
520
+ /**
521
+ * 将 TS / ESM 转成可被 `new Function('require','module','exports', code)` 执行的 CJS。
522
+ * @param code 源码文本。
523
+ * @param filename 当前虚拟文件名,用来判断是否按 TypeScript 转换。
524
+ * @param options 转换选项。
525
+ * @param options.typescript 是否启用 TypeScript 转换。
526
+ * @param options.jsx 是否转换 Vue JSX。
527
+ * @param options.esm 是否保留 ESM 导入导出供 iframe 使用。
528
+ * @returns 可执行的 CJS 文本。
529
+ */
530
+ var transformScript = (code, filename, options = {}) => {
531
+ const transforms = options.esm ? [] : ["imports"];
532
+ const wantTs = options.typescript === true || options.typescript !== false && (filename.endsWith(".ts") || filename.endsWith(".tsx"));
533
+ if (wantTs) transforms.unshift("typescript");
534
+ if (options.jsx) transforms.unshift("jsx");
535
+ try {
536
+ const script = wantTs ? removeImportedTypeExports(code) : code;
537
+ const source = options.jsx ? `import { h as __docs_h, Fragment as __docs_Fragment } from 'vue';\n${rewriteJsxAttributes(script)}` : script;
538
+ return `${rewriteImportMeta(transform(source, {
539
+ transforms,
540
+ disableESTransforms: true,
541
+ production: true,
542
+ jsxRuntime: "classic",
543
+ jsxPragma: "__docs_h",
544
+ jsxFragmentPragma: "__docs_Fragment",
545
+ filePath: filename
546
+ }).code, filename)}\n//# sourceURL=playground://${filename}`;
547
+ } catch (error) {
548
+ const message = error instanceof Error ? error.message : String(error);
549
+ throw new Error(`[Playground] 脚本转换失败 ${filename}: ${message}`, { cause: error });
550
+ }
551
+ };
552
+ //#endregion
553
+ //#region packages/playground/src/core/runtime/local/compile/css.ts
554
+ var collectCss = (chunks) => {
555
+ const result = [];
556
+ chunks.forEach((chunk) => {
557
+ const css = String(chunk || "").trim();
558
+ if (css) result.push(css);
559
+ });
560
+ return result;
561
+ };
562
+ var injectStyle = (id, cssList) => {
563
+ /* istanbul ignore if -- 仅浏览器注入样式 */
564
+ if (typeof document === "undefined") return null;
565
+ document.querySelector(`style[data-playground-id="${id}"]`)?.remove();
566
+ const css = cssList.filter(Boolean).join("\n");
567
+ if (!css) return null;
568
+ const style = document.createElement("style");
569
+ style.setAttribute("data-playground-id", id);
570
+ style.textContent = css;
571
+ document.head.appendChild(style);
572
+ return style;
573
+ };
574
+ var removeStyle = (id) => {
575
+ /* istanbul ignore if -- 仅浏览器注入样式 */
576
+ if (typeof document === "undefined") return;
577
+ document.querySelector(`style[data-playground-id="${id}"]`)?.remove();
578
+ };
579
+ //#endregion
580
+ export { normalizeCdnURL as C, NEW_SFC_CODE as D, DEFAULT_ENTRY as E, createBuiltinStyles as S, DEFAULT_CDN_URL as T, bindPlaygroundScss as _, transformScript as a, whenSassReady as b, createFileIndex as c, isIgnoredFilename as d, isInsideRoot as f, resolveModulePath as g, resolveEntry as h, rewriteImportMeta as i, getCommonRoot as l, normalizeVirtualPath as m, injectStyle as n, collectBareSpecifiers as o, isRelativeSpecifier as p, removeStyle as r, collectReachableFilenames as s, collectCss as t, getExtension as u, compileScssSource as v, resolveNpmImport as w, createBuiltinImports as x, extractScssExports as y };