@qualcomm-ui/mdx-vite 1.0.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.
Files changed (121) hide show
  1. package/LICENSE.txt +31 -0
  2. package/dist/angular-demo-plugin/angular-demo-plugin.d.ts +17 -0
  3. package/dist/angular-demo-plugin/angular-demo-plugin.d.ts.map +1 -0
  4. package/dist/angular-demo-plugin/index.d.ts +2 -0
  5. package/dist/angular-demo-plugin/index.d.ts.map +1 -0
  6. package/dist/angular-demo-plugin/virtual.d.ts +5 -0
  7. package/dist/cli.d.ts +2 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +6347 -0
  10. package/dist/cli.js.map +7 -0
  11. package/dist/docs-plugin/docs-plugin.d.ts +15 -0
  12. package/dist/docs-plugin/docs-plugin.d.ts.map +1 -0
  13. package/dist/docs-plugin/index.d.ts +6 -0
  14. package/dist/docs-plugin/index.d.ts.map +1 -0
  15. package/dist/docs-plugin/internal/config-loader.d.ts +23 -0
  16. package/dist/docs-plugin/internal/config-loader.d.ts.map +1 -0
  17. package/dist/docs-plugin/internal/config-schema.d.ts +46 -0
  18. package/dist/docs-plugin/internal/config-schema.d.ts.map +1 -0
  19. package/dist/docs-plugin/internal/index.d.ts +8 -0
  20. package/dist/docs-plugin/internal/index.d.ts.map +1 -0
  21. package/dist/docs-plugin/internal/search-indexer.d.ts +46 -0
  22. package/dist/docs-plugin/internal/search-indexer.d.ts.map +1 -0
  23. package/dist/docs-plugin/internal/services/doc-props/doc-props-indexer.d.ts +28 -0
  24. package/dist/docs-plugin/internal/services/doc-props/doc-props-indexer.d.ts.map +1 -0
  25. package/dist/docs-plugin/internal/services/doc-props/index.d.ts +2 -0
  26. package/dist/docs-plugin/internal/services/doc-props/index.d.ts.map +1 -0
  27. package/dist/docs-plugin/internal/services/index.d.ts +4 -0
  28. package/dist/docs-plugin/internal/services/index.d.ts.map +1 -0
  29. package/dist/docs-plugin/internal/services/markdown/index.d.ts +6 -0
  30. package/dist/docs-plugin/internal/services/markdown/index.d.ts.map +1 -0
  31. package/dist/docs-plugin/internal/services/markdown/markdown-file-reader.d.ts +28 -0
  32. package/dist/docs-plugin/internal/services/markdown/markdown-file-reader.d.ts.map +1 -0
  33. package/dist/docs-plugin/internal/services/markdown/markdown-indexer.d.ts +27 -0
  34. package/dist/docs-plugin/internal/services/markdown/markdown-indexer.d.ts.map +1 -0
  35. package/dist/docs-plugin/internal/services/markdown/markdown.types.d.ts +10 -0
  36. package/dist/docs-plugin/internal/services/markdown/markdown.types.d.ts.map +1 -0
  37. package/dist/docs-plugin/internal/services/markdown/remark-remove-code-blocks.d.ts +3 -0
  38. package/dist/docs-plugin/internal/services/markdown/remark-remove-code-blocks.d.ts.map +1 -0
  39. package/dist/docs-plugin/internal/services/markdown/remark-remove-jsx.d.ts +3 -0
  40. package/dist/docs-plugin/internal/services/markdown/remark-remove-jsx.d.ts.map +1 -0
  41. package/dist/docs-plugin/internal/services/nav-builder/get-route-meta.d.ts +6 -0
  42. package/dist/docs-plugin/internal/services/nav-builder/get-route-meta.d.ts.map +1 -0
  43. package/dist/docs-plugin/internal/services/nav-builder/index.d.ts +4 -0
  44. package/dist/docs-plugin/internal/services/nav-builder/index.d.ts.map +1 -0
  45. package/dist/docs-plugin/internal/services/nav-builder/nav-builder.d.ts +56 -0
  46. package/dist/docs-plugin/internal/services/nav-builder/nav-builder.d.ts.map +1 -0
  47. package/dist/docs-plugin/internal/services/nav-builder/page-map.d.ts +7 -0
  48. package/dist/docs-plugin/internal/services/nav-builder/page-map.d.ts.map +1 -0
  49. package/dist/docs-plugin/internal/transform-route-meta-array.d.ts +3 -0
  50. package/dist/docs-plugin/internal/transform-route-meta-array.d.ts.map +1 -0
  51. package/dist/docs-plugin/internal/utils.d.ts +17 -0
  52. package/dist/docs-plugin/internal/utils.d.ts.map +1 -0
  53. package/dist/docs-plugin/internal/zod.d.ts +9 -0
  54. package/dist/docs-plugin/internal/zod.d.ts.map +1 -0
  55. package/dist/docs-plugin/mdx-plugins.d.ts +38 -0
  56. package/dist/docs-plugin/mdx-plugins.d.ts.map +1 -0
  57. package/dist/docs-plugin/rehype/index.d.ts +3 -0
  58. package/dist/docs-plugin/rehype/index.d.ts.map +1 -0
  59. package/dist/docs-plugin/rehype/rehype-sectionize.d.ts +11 -0
  60. package/dist/docs-plugin/rehype/rehype-sectionize.d.ts.map +1 -0
  61. package/dist/docs-plugin/rehype/rehype-slug.d.ts +16 -0
  62. package/dist/docs-plugin/rehype/rehype-slug.d.ts.map +1 -0
  63. package/dist/docs-plugin/remark/index.d.ts +5 -0
  64. package/dist/docs-plugin/remark/index.d.ts.map +1 -0
  65. package/dist/docs-plugin/remark/remark-alerts.d.ts +13 -0
  66. package/dist/docs-plugin/remark/remark-alerts.d.ts.map +1 -0
  67. package/dist/docs-plugin/remark/remark-code-tabs.d.ts +7 -0
  68. package/dist/docs-plugin/remark/remark-code-tabs.d.ts.map +1 -0
  69. package/dist/docs-plugin/remark/remark-self-link-headings.d.ts +11 -0
  70. package/dist/docs-plugin/remark/remark-self-link-headings.d.ts.map +1 -0
  71. package/dist/docs-plugin/remark/remark-spoilers.d.ts +31 -0
  72. package/dist/docs-plugin/remark/remark-spoilers.d.ts.map +1 -0
  73. package/dist/docs-plugin/tests/markdown-indexer.spec.d.ts +2 -0
  74. package/dist/docs-plugin/tests/markdown-indexer.spec.d.ts.map +1 -0
  75. package/dist/docs-plugin/tests/remark-slug.spec.d.ts +2 -0
  76. package/dist/docs-plugin/tests/remark-slug.spec.d.ts.map +1 -0
  77. package/dist/docs-plugin/tests/remix-flat-routes.spec.d.ts +2 -0
  78. package/dist/docs-plugin/tests/remix-flat-routes.spec.d.ts.map +1 -0
  79. package/dist/docs-plugin/tests/remix.spec.d.ts +2 -0
  80. package/dist/docs-plugin/tests/remix.spec.d.ts.map +1 -0
  81. package/dist/docs-plugin/tests/utils.d.ts +3 -0
  82. package/dist/docs-plugin/tests/utils.d.ts.map +1 -0
  83. package/dist/docs-plugin/tests/vite-generouted.spec.d.ts +2 -0
  84. package/dist/docs-plugin/tests/vite-generouted.spec.d.ts.map +1 -0
  85. package/dist/docs-plugin/types.d.ts +172 -0
  86. package/dist/docs-plugin/types.d.ts.map +1 -0
  87. package/dist/docs-plugin/virtual.d.ts +5 -0
  88. package/dist/exports.d.ts +7 -0
  89. package/dist/exports.d.ts.map +1 -0
  90. package/dist/index.d.ts +5 -0
  91. package/dist/index.d.ts.map +1 -0
  92. package/dist/index.js +4632 -0
  93. package/dist/index.js.map +7 -0
  94. package/dist/open-web-ui-knowledge/common.d.ts +43 -0
  95. package/dist/open-web-ui-knowledge/common.d.ts.map +1 -0
  96. package/dist/open-web-ui-knowledge/download-knowledge.d.ts +2 -0
  97. package/dist/open-web-ui-knowledge/download-knowledge.d.ts.map +1 -0
  98. package/dist/open-web-ui-knowledge/generate-knowledge.d.ts +4 -0
  99. package/dist/open-web-ui-knowledge/generate-knowledge.d.ts.map +1 -0
  100. package/dist/open-web-ui-knowledge/load-config-from-env.d.ts +3 -0
  101. package/dist/open-web-ui-knowledge/load-config-from-env.d.ts.map +1 -0
  102. package/dist/open-web-ui-knowledge/types.d.ts +54 -0
  103. package/dist/open-web-ui-knowledge/types.d.ts.map +1 -0
  104. package/dist/open-web-ui-knowledge/upload-knowledge.d.ts +2 -0
  105. package/dist/open-web-ui-knowledge/upload-knowledge.d.ts.map +1 -0
  106. package/dist/react-demo-plugin/demo-plugin-constants.d.ts +9 -0
  107. package/dist/react-demo-plugin/demo-plugin-constants.d.ts.map +1 -0
  108. package/dist/react-demo-plugin/demo-plugin-types.d.ts +37 -0
  109. package/dist/react-demo-plugin/demo-plugin-types.d.ts.map +1 -0
  110. package/dist/react-demo-plugin/demo-plugin-utils.d.ts +53 -0
  111. package/dist/react-demo-plugin/demo-plugin-utils.d.ts.map +1 -0
  112. package/dist/react-demo-plugin/generate-lazy-demo-map.d.ts +21 -0
  113. package/dist/react-demo-plugin/generate-lazy-demo-map.d.ts.map +1 -0
  114. package/dist/react-demo-plugin/index.d.ts +6 -0
  115. package/dist/react-demo-plugin/index.d.ts.map +1 -0
  116. package/dist/react-demo-plugin/react-demo-plugin.d.ts +4 -0
  117. package/dist/react-demo-plugin/react-demo-plugin.d.ts.map +1 -0
  118. package/dist/react-demo-plugin/virtual.d.ts +17 -0
  119. package/dist/tsbuildinfo +1 -0
  120. package/lib/cli.js +6 -0
  121. package/package.json +84 -0
package/dist/index.js ADDED
@@ -0,0 +1,4632 @@
1
+ import {createRequire} from "node:module";const require=createRequire(import.meta.url);
2
+
3
+ // src/angular-demo-plugin/angular-demo-plugin.ts
4
+ import { transformerRenderIndentGuides } from "@shikijs/transformers";
5
+ import chalk from "chalk";
6
+ import { watch } from "chokidar";
7
+ import { glob } from "glob";
8
+ import { existsSync } from "node:fs";
9
+ import { readFile, stat } from "node:fs/promises";
10
+ import { basename, dirname, join, relative, resolve } from "node:path";
11
+ import {
12
+ createHighlighter
13
+ } from "shiki";
14
+ import * as ts from "typescript";
15
+ import {
16
+ quiCustomDarkTheme
17
+ } from "@qualcomm-ui/mdx-common";
18
+ var VIRTUAL_MODULE_ID = "\0virtual:angular-demo-registry";
19
+ var VIRTUAL_MODULE_PREFIX = "virtual:angular-demo-registry/";
20
+ var LOG_PREFIX = "[angular-demo]";
21
+ var hasWatcherInitialized = false;
22
+ function logDev(...args) {
23
+ if (!hasWatcherInitialized) {
24
+ return;
25
+ }
26
+ console.log(...args);
27
+ }
28
+ var demoDimensionsCache = {};
29
+ var highlighter = null;
30
+ var initCount = 0;
31
+ var demoRegistry = /* @__PURE__ */ new Map();
32
+ var hotUpdateDemoIds = [];
33
+ function angularDemoPlugin({
34
+ demoPattern = "src/routes/**/demos/*.ts",
35
+ initialHtml,
36
+ routesDir = "src/routes",
37
+ theme = {
38
+ dark: quiCustomDarkTheme,
39
+ light: "github-light-high-contrast"
40
+ }
41
+ } = {}) {
42
+ let watcher = null;
43
+ let devServer = null;
44
+ return {
45
+ async buildEnd() {
46
+ if (watcher) {
47
+ await watcher.close();
48
+ watcher = null;
49
+ hasWatcherInitialized = false;
50
+ }
51
+ },
52
+ async buildStart() {
53
+ if (initCount === 0) {
54
+ initCount++;
55
+ return;
56
+ }
57
+ if (!highlighter) {
58
+ try {
59
+ highlighter = await createHighlighter({
60
+ langs: ["angular-ts", "angular-html"],
61
+ themes: [theme.dark, theme.light]
62
+ });
63
+ logDev(`${chalk.blue.bold(LOG_PREFIX)} Shiki highlighter initialized`);
64
+ } catch (error) {
65
+ console.warn(
66
+ `${chalk.blue.bold(LOG_PREFIX)} Failed to initialize highlighter:`,
67
+ error
68
+ );
69
+ }
70
+ }
71
+ logDev(`${chalk.blue.bold(LOG_PREFIX)} Initializing Angular demo scanner`);
72
+ await collectAngularDemos();
73
+ if (process.env.NODE_ENV === "development") {
74
+ if (!hasWatcherInitialized) {
75
+ hasWatcherInitialized = true;
76
+ await setupAngularWatcher();
77
+ } else {
78
+ logDev(
79
+ `${chalk.blue.bold(LOG_PREFIX)} Watcher already initialized by another instance`
80
+ );
81
+ }
82
+ }
83
+ },
84
+ configureServer(server) {
85
+ devServer = server;
86
+ let dimensionUpdateTimeout = null;
87
+ server.ws.on(
88
+ "custom:store-demo-dimensions",
89
+ (data) => {
90
+ const demoId = data.demoId;
91
+ demoDimensionsCache[demoId] = data.dimensions;
92
+ if (dimensionUpdateTimeout) {
93
+ clearTimeout(dimensionUpdateTimeout);
94
+ }
95
+ dimensionUpdateTimeout = setTimeout(() => {
96
+ const module = server.moduleGraph.getModuleById(VIRTUAL_MODULE_ID);
97
+ if (module) {
98
+ server.moduleGraph.invalidateModule(module);
99
+ }
100
+ }, 50);
101
+ }
102
+ );
103
+ server.ws.on("custom:reset-demo-dimensions", () => {
104
+ demoDimensionsCache = {};
105
+ const module = server.moduleGraph.getModuleById(VIRTUAL_MODULE_ID);
106
+ if (module) {
107
+ server.moduleGraph.invalidateModule(module);
108
+ server.reloadModule(module);
109
+ }
110
+ });
111
+ },
112
+ async handleHotUpdate({ file, server }) {
113
+ if (!isAngularDemoFile(file)) {
114
+ if (isCssAsset2(file)) {
115
+ return server.moduleGraph.getModulesByFile(file)?.values()?.toArray();
116
+ } else if (file.endsWith("main.js")) {
117
+ const ids = [...hotUpdateDemoIds];
118
+ server.ws.send({
119
+ data: {
120
+ demoInfo: ids.reduce(
121
+ (acc, current) => {
122
+ acc[current] = demoRegistry.get(current);
123
+ return acc;
124
+ },
125
+ {}
126
+ )
127
+ },
128
+ event: "demo-bundle-updated",
129
+ type: "custom"
130
+ });
131
+ }
132
+ return [];
133
+ }
134
+ logDev(
135
+ `${chalk.blue.bold(LOG_PREFIX)} Processing Angular demo change: ${chalk.cyan(file)}`
136
+ );
137
+ const code = await readFile(file, "utf-8");
138
+ const demoInfo = await parseAngularDemo(file, code);
139
+ if (!demoInfo) {
140
+ const affectedDemos = await scanDemosForFileImport(file);
141
+ if (affectedDemos.length > 0) {
142
+ hotUpdateDemoIds = [];
143
+ const mainModule2 = server.moduleGraph.getModuleById(VIRTUAL_MODULE_ID);
144
+ if (mainModule2) {
145
+ server.moduleGraph.invalidateModule(mainModule2);
146
+ await server.reloadModule(mainModule2);
147
+ }
148
+ for (const demo of affectedDemos) {
149
+ hotUpdateDemoIds.push(demo.id);
150
+ }
151
+ const pageIds = new Set(affectedDemos.map((demo) => demo.pageId));
152
+ for (const pageId of pageIds) {
153
+ const pageModuleId2 = `\0${VIRTUAL_MODULE_PREFIX}${pageId}`;
154
+ const pageModule2 = server.moduleGraph.getModuleById(pageModuleId2);
155
+ if (pageModule2) {
156
+ server.moduleGraph.invalidateModule(pageModule2);
157
+ await server.reloadModule(pageModule2);
158
+ }
159
+ }
160
+ }
161
+ server.ws.send({
162
+ data: {
163
+ ids: [...hotUpdateDemoIds]
164
+ },
165
+ event: "demo-bundle-updating",
166
+ type: "custom"
167
+ });
168
+ return;
169
+ }
170
+ delete demoDimensionsCache[demoInfo.id];
171
+ demoRegistry.set(demoInfo.id, demoInfo);
172
+ hotUpdateDemoIds = [demoInfo.id];
173
+ server.ws.send({
174
+ data: {
175
+ ids: [...hotUpdateDemoIds]
176
+ },
177
+ event: "demo-bundle-updating",
178
+ type: "custom"
179
+ });
180
+ const mainModule = server.moduleGraph.getModuleById(VIRTUAL_MODULE_ID);
181
+ if (mainModule) {
182
+ server.moduleGraph.invalidateModule(mainModule);
183
+ await server.reloadModule(mainModule);
184
+ }
185
+ const pageModuleId = `\0${VIRTUAL_MODULE_PREFIX}${demoInfo.pageId}`;
186
+ const pageModule = server.moduleGraph.getModuleById(pageModuleId);
187
+ if (pageModule) {
188
+ server.moduleGraph.invalidateModule(pageModule);
189
+ await server.reloadModule(pageModule);
190
+ }
191
+ const demoModule = server.moduleGraph.getModuleById(file);
192
+ if (demoModule) {
193
+ server.moduleGraph.invalidateModule(demoModule);
194
+ }
195
+ return [];
196
+ },
197
+ async load(id) {
198
+ if (id === VIRTUAL_MODULE_ID) {
199
+ return generateRegistryModule();
200
+ }
201
+ if (id.startsWith(`\0${VIRTUAL_MODULE_PREFIX}`)) {
202
+ const pageId = id.slice(`\0${VIRTUAL_MODULE_PREFIX}`.length);
203
+ return generatePageRegistryModule(pageId);
204
+ }
205
+ },
206
+ name: "angular-demo-plugin",
207
+ resolveId(id) {
208
+ if (id === "virtual:angular-demo-registry") {
209
+ return VIRTUAL_MODULE_ID;
210
+ }
211
+ if (id.startsWith(VIRTUAL_MODULE_PREFIX)) {
212
+ const pageId = id.slice(VIRTUAL_MODULE_PREFIX.length);
213
+ return `\0${VIRTUAL_MODULE_PREFIX}${pageId}`;
214
+ }
215
+ },
216
+ writeBundle() {
217
+ console.log(
218
+ `${chalk.blue.bold(LOG_PREFIX)} Successfully integrated ${chalk.green(demoRegistry.size)} component demos`
219
+ );
220
+ }
221
+ };
222
+ async function collectAngularDemos() {
223
+ if (demoRegistry.size) {
224
+ logDev(
225
+ `${chalk.magenta.bold(LOG_PREFIX)} Using cached ${chalk.cyanBright.bold(demoRegistry.size)} demos`
226
+ );
227
+ return;
228
+ }
229
+ const demoFiles = await glob(demoPattern);
230
+ demoRegistry.clear();
231
+ for (const filePath of demoFiles) {
232
+ const code = await readFile(filePath, "utf-8");
233
+ const demoInfo = await parseAngularDemo(filePath, code);
234
+ if (demoInfo) {
235
+ demoRegistry.set(demoInfo.id, demoInfo);
236
+ }
237
+ }
238
+ }
239
+ async function scanDemosForFileImport(file) {
240
+ const affectedDemos = [];
241
+ for (const [demoId, demo] of demoRegistry.entries()) {
242
+ if (demo.sourceCode.find((entry) => entry.filePath === file)) {
243
+ logDev(
244
+ `${chalk.blue.bold(LOG_PREFIX)} Re-parsing demo ${chalk.cyan(demoId)} due to imported file change: ${chalk.yellow(file)}`
245
+ );
246
+ const code = await readFile(demo.filePath, "utf-8");
247
+ const updatedDemo = await parseAngularDemo(demo.filePath, code);
248
+ if (updatedDemo) {
249
+ delete demoDimensionsCache[updatedDemo.id];
250
+ demoRegistry.set(updatedDemo.id, updatedDemo);
251
+ affectedDemos.push(updatedDemo);
252
+ hotUpdateDemoIds.push(updatedDemo.id);
253
+ }
254
+ }
255
+ }
256
+ return affectedDemos;
257
+ }
258
+ async function highlightCode(code, language = "angular-ts") {
259
+ if (!highlighter) {
260
+ return code;
261
+ }
262
+ try {
263
+ return highlighter.codeToHtml(code, {
264
+ defaultColor: "light-dark()",
265
+ lang: language,
266
+ themes: {
267
+ dark: theme.dark,
268
+ light: theme.light
269
+ },
270
+ transformers: [transformerRenderIndentGuides()]
271
+ });
272
+ } catch (error) {
273
+ console.warn(
274
+ `${chalk.blue.bold(LOG_PREFIX)} Failed to highlight code with ${language} language:`,
275
+ error
276
+ );
277
+ return code;
278
+ }
279
+ }
280
+ function extractAngularPreviewsAndCleanSource(code) {
281
+ const lines = code.split("\n");
282
+ const previewBlocks = [];
283
+ const cleanedLines = [];
284
+ let inPreview = false;
285
+ let currentBlock = [];
286
+ let startLine = -1;
287
+ let currentContext = "typescript";
288
+ let inTemplate = false;
289
+ let templateDepth = 0;
290
+ let omitNextLine = false;
291
+ for (let i = 0; i < lines.length; i++) {
292
+ const line = lines[i];
293
+ const trimmedLine = line.trim();
294
+ if (/template\s*:\s*[`"']/.test(line)) {
295
+ inTemplate = true;
296
+ templateDepth = 0;
297
+ }
298
+ if (inTemplate && line.includes("`")) {
299
+ const backticks = (line.match(/`/g) || []).length;
300
+ templateDepth += backticks;
301
+ if (templateDepth % 2 === 0 && backticks > 0) {
302
+ inTemplate = false;
303
+ }
304
+ }
305
+ if (inTemplate && /['"]\s*[,}]/.test(line)) {
306
+ inTemplate = false;
307
+ }
308
+ if (omitNextLine) {
309
+ omitNextLine = false;
310
+ continue;
311
+ }
312
+ if (isOmitNextLine(trimmedLine)) {
313
+ omitNextLine = true;
314
+ continue;
315
+ }
316
+ if (isPreviewLine(trimmedLine)) {
317
+ if (inPreview) {
318
+ const normalizedContent = normalizeIndentation2(currentBlock);
319
+ previewBlocks.push({
320
+ content: normalizedContent,
321
+ context: currentContext,
322
+ endLine: i - 1,
323
+ startLine
324
+ });
325
+ currentBlock = [];
326
+ inPreview = false;
327
+ } else {
328
+ inPreview = true;
329
+ startLine = i + 1;
330
+ currentContext = inTemplate ? "template" : "typescript";
331
+ }
332
+ } else {
333
+ cleanedLines.push(line);
334
+ if (inPreview) {
335
+ currentBlock.push(line);
336
+ }
337
+ }
338
+ }
339
+ function normalizeIndentation2(lines2) {
340
+ if (lines2.length === 0) {
341
+ return "";
342
+ }
343
+ const nonEmptyLines = lines2.filter((line) => line.trim().length > 0);
344
+ if (nonEmptyLines.length === 0) {
345
+ return lines2.join("\n");
346
+ }
347
+ let minIndent = Infinity;
348
+ for (const line of nonEmptyLines) {
349
+ const match = line.match(/^(\s*)/);
350
+ const indent = match ? match[1].length : 0;
351
+ minIndent = Math.min(minIndent, indent);
352
+ }
353
+ const normalizedLines = lines2.map((line) => {
354
+ if (line.trim().length === 0) {
355
+ return line;
356
+ }
357
+ return line.slice(minIndent);
358
+ });
359
+ return normalizedLines.join("\n");
360
+ }
361
+ const formattedPreview = previewBlocks.length ? previewBlocks.map((block) => block.content).join("\n") : "";
362
+ return {
363
+ formattedPreview,
364
+ previewBlocks,
365
+ sourceWithoutPreviews: cleanedLines.join("\n")
366
+ };
367
+ }
368
+ function isPreviewLine(trimmedLine) {
369
+ return trimmedLine === "// preview" || /^\/\*\s*preview\s*\*\/$/.test(trimmedLine) || /^<!--\s*preview\s*-->$/.test(trimmedLine);
370
+ }
371
+ async function extractRelativeImports(filePath) {
372
+ try {
373
+ let visit8 = function(node) {
374
+ if (ts.isImportDeclaration(node)) {
375
+ const moduleSpecifier = node.moduleSpecifier;
376
+ if (ts.isStringLiteral(moduleSpecifier)) {
377
+ const source = moduleSpecifier.text;
378
+ if (isRelativeImport2(source)) {
379
+ const resolvedPath = resolveRelativeImport2(source, filePath);
380
+ relativeImports.push({ resolvedPath, source });
381
+ } else if (!isNodeBuiltin2(source)) {
382
+ const pathAliases = loadTsConfigPaths2(filePath);
383
+ if (isPathAliasImport(source, pathAliases)) {
384
+ const resolvedPath = resolvePathAlias(source, pathAliases);
385
+ if (resolvedPath) {
386
+ relativeImports.push({ resolvedPath, source });
387
+ }
388
+ }
389
+ }
390
+ }
391
+ }
392
+ ts.forEachChild(node, visit8);
393
+ };
394
+ var visit7 = visit8;
395
+ const content = await readFile(filePath, "utf-8");
396
+ const sourceFile = ts.createSourceFile(
397
+ filePath,
398
+ content,
399
+ ts.ScriptTarget.Latest,
400
+ true,
401
+ ts.ScriptKind.TS
402
+ );
403
+ const relativeImports = [];
404
+ visit8(sourceFile);
405
+ return relativeImports;
406
+ } catch (error) {
407
+ logDev(
408
+ `${chalk.blue.bold(LOG_PREFIX)} ${chalk.yellowBright("Failed to extract imports from")} ${chalk.cyan(filePath)}:`,
409
+ error
410
+ );
411
+ return [];
412
+ }
413
+ }
414
+ async function collectAllImports(filePath, visited = /* @__PURE__ */ new Set()) {
415
+ if (visited.has(filePath)) {
416
+ return [];
417
+ }
418
+ visited.add(filePath);
419
+ const directImports = await extractRelativeImports(filePath);
420
+ for (const { resolvedPath } of directImports) {
421
+ await collectAllImports(resolvedPath, visited);
422
+ }
423
+ return Array.from(visited).slice(1);
424
+ }
425
+ function stripImports(code, fileName) {
426
+ try {
427
+ let visit8 = function(node) {
428
+ if (ts.isImportDeclaration(node)) {
429
+ importRanges.push({
430
+ end: node.getEnd(),
431
+ start: node.getFullStart()
432
+ });
433
+ }
434
+ ts.forEachChild(node, visit8);
435
+ };
436
+ var visit7 = visit8;
437
+ const sourceFile = ts.createSourceFile(
438
+ fileName,
439
+ code,
440
+ ts.ScriptTarget.Latest,
441
+ true,
442
+ ts.ScriptKind.TS
443
+ );
444
+ const importRanges = [];
445
+ visit8(sourceFile);
446
+ const imports = importRanges.map((range) => {
447
+ let endPos = range.end;
448
+ if (code[endPos] === "\n") {
449
+ endPos++;
450
+ }
451
+ return code.slice(range.start, endPos).trim();
452
+ });
453
+ importRanges.sort((a, b) => b.start - a.start);
454
+ let strippedCode = code;
455
+ for (const range of importRanges) {
456
+ let endPos = range.end;
457
+ if (strippedCode[endPos] === "\n") {
458
+ endPos++;
459
+ }
460
+ strippedCode = strippedCode.slice(0, range.start) + strippedCode.slice(endPos);
461
+ }
462
+ strippedCode = strippedCode.trim();
463
+ return {
464
+ imports,
465
+ strippedCode: strippedCode.replace(/^\n+/, "")
466
+ };
467
+ } catch (error) {
468
+ logDev(
469
+ `${chalk.blue.bold(LOG_PREFIX)} ${chalk.redBright("Failed to strip imports from")} ${chalk.cyan(fileName)}:`,
470
+ error
471
+ );
472
+ return {
473
+ imports: [],
474
+ strippedCode: code
475
+ };
476
+ }
477
+ }
478
+ async function parseAngularDemo(filePath, code) {
479
+ try {
480
+ let visit8 = function(node) {
481
+ if (ts.isImportDeclaration(node)) {
482
+ imports.push(node.getFullText(sourceFile).trim());
483
+ }
484
+ if (ts.isClassDeclaration(node)) {
485
+ const decorators = node.modifiers?.filter(ts.isDecorator);
486
+ const componentDecorator = decorators?.find((decorator) => {
487
+ if (ts.isCallExpression(decorator.expression)) {
488
+ const expression = decorator.expression.expression;
489
+ return ts.isIdentifier(expression) && expression.text === "Component";
490
+ }
491
+ return false;
492
+ });
493
+ if (componentDecorator && node.name) {
494
+ componentClass = node.name.text;
495
+ if (ts.isCallExpression(componentDecorator.expression) && componentDecorator.expression.arguments[0] && ts.isObjectLiteralExpression(
496
+ componentDecorator.expression.arguments[0]
497
+ )) {
498
+ const properties = componentDecorator.expression.arguments[0].properties;
499
+ const selectorProp = properties.find(
500
+ (prop) => ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === "selector"
501
+ );
502
+ if (selectorProp && ts.isStringLiteral(selectorProp.initializer)) {
503
+ selector = selectorProp.initializer.text;
504
+ }
505
+ const templateUrlProp = properties.find(
506
+ (prop) => ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === "templateUrl"
507
+ );
508
+ if (templateUrlProp) {
509
+ if (ts.isStringLiteral(templateUrlProp.initializer)) {
510
+ templateUrl = templateUrlProp.initializer.text;
511
+ } else if (ts.isNoSubstitutionTemplateLiteral(
512
+ templateUrlProp.initializer
513
+ )) {
514
+ templateUrl = templateUrlProp.initializer.text;
515
+ }
516
+ }
517
+ const standaloneProp = properties.find(
518
+ (prop) => ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === "standalone"
519
+ );
520
+ if (standaloneProp) {
521
+ if (standaloneProp.initializer.kind === ts.SyntaxKind.FalseKeyword) {
522
+ isStandalone = false;
523
+ }
524
+ }
525
+ }
526
+ }
527
+ }
528
+ if (ts.isExportAssignment(node) && !node.isExportEquals) {
529
+ hasDefaultExport = true;
530
+ }
531
+ ts.forEachChild(node, visit8);
532
+ };
533
+ var visit7 = visit8;
534
+ const { formattedPreview, sourceWithoutPreviews } = extractAngularPreviewsAndCleanSource(code);
535
+ const sourceFile = ts.createSourceFile(
536
+ filePath,
537
+ sourceWithoutPreviews,
538
+ ts.ScriptTarget.Latest,
539
+ true,
540
+ ts.ScriptKind.TS
541
+ );
542
+ let componentClass = "";
543
+ let selector = "";
544
+ let isStandalone = true;
545
+ let templateUrl = null;
546
+ const imports = [];
547
+ let hasDefaultExport = false;
548
+ visit8(sourceFile);
549
+ if (!componentClass || !selector) {
550
+ return null;
551
+ }
552
+ const demoId = componentClass;
553
+ const pageId = extractPageId2(filePath, routesDir);
554
+ const importPath = relative(process.cwd(), filePath).replace(/\\/g, "/");
555
+ const fileName = basename(filePath);
556
+ const { strippedCode: codeWithoutImports } = stripImports(code, filePath);
557
+ const highlightedFull = await highlightCode(code, "angular-ts");
558
+ const { highlightedPreview, highlightedWithoutPreview } = extractHighlightedVariants(highlightedFull);
559
+ const sourceCode = [
560
+ {
561
+ fileName,
562
+ filePath,
563
+ highlighted: {
564
+ full: highlightedWithoutPreview,
565
+ preview: highlightedPreview
566
+ },
567
+ raw: {
568
+ full: sourceWithoutPreviews,
569
+ preview: formattedPreview || "",
570
+ withoutImports: codeWithoutImports
571
+ }
572
+ }
573
+ ];
574
+ if (templateUrl) {
575
+ const templatePath = resolveTemplateFile(templateUrl, filePath);
576
+ if (existsSync(templatePath)) {
577
+ try {
578
+ const templateCode = await readFile(templatePath, "utf-8");
579
+ const {
580
+ formattedPreview: templatePreview,
581
+ sourceWithoutPreviews: templateWithoutPreviews
582
+ } = extractAngularPreviewsAndCleanSource(templateCode);
583
+ const highlightedTemplate = await highlightCode(
584
+ templateCode,
585
+ "angular-html"
586
+ );
587
+ const {
588
+ highlightedPreview: highlightedTemplatePreview,
589
+ highlightedWithoutPreview: highlightedTemplateWithoutPreview
590
+ } = extractHighlightedVariants(highlightedTemplate);
591
+ sourceCode.push({
592
+ fileName: basename(templatePath),
593
+ highlighted: {
594
+ full: highlightedTemplateWithoutPreview,
595
+ preview: highlightedTemplatePreview
596
+ },
597
+ raw: {
598
+ full: templateWithoutPreviews,
599
+ preview: templatePreview || "",
600
+ withoutImports: templateCode
601
+ }
602
+ });
603
+ } catch (error) {
604
+ console.log(
605
+ `${chalk.blue.bold(LOG_PREFIX)} ${chalk.redBright("Failed to read template file:")} ${chalk.cyan(templatePath)}`,
606
+ error
607
+ );
608
+ }
609
+ }
610
+ }
611
+ const relativeImports = await collectAllImports(filePath);
612
+ for (const resolvedPath of relativeImports) {
613
+ try {
614
+ const importedCode = await readFile(resolvedPath, "utf-8");
615
+ const { strippedCode: importedCodeWithoutImports } = stripImports(
616
+ importedCode,
617
+ resolvedPath
618
+ );
619
+ const { sourceWithoutPreviews: importedSourceWithoutSnippets } = extractAngularPreviewsAndCleanSource(importedCode);
620
+ const importedFileName = basename(resolvedPath);
621
+ const highlightedImportedSource = await highlightCode(
622
+ importedSourceWithoutSnippets,
623
+ "angular-ts"
624
+ );
625
+ sourceCode.push({
626
+ fileName: importedFileName,
627
+ highlighted: {
628
+ full: highlightedImportedSource,
629
+ preview: ""
630
+ },
631
+ raw: {
632
+ full: importedSourceWithoutSnippets,
633
+ preview: "",
634
+ withoutImports: importedCodeWithoutImports
635
+ }
636
+ });
637
+ } catch (error) {
638
+ logDev(
639
+ `${chalk.blue.bold(LOG_PREFIX)} ${chalk.yellowBright("Failed to process relative import:")} ${chalk.cyan(resolvedPath)}`
640
+ );
641
+ }
642
+ }
643
+ return {
644
+ componentClass,
645
+ filePath: importPath.startsWith(".") ? importPath : `./${importPath}`,
646
+ hasDefaultExport,
647
+ id: demoId,
648
+ imports,
649
+ initialHtml: initialHtml?.[demoId] || void 0,
650
+ isStandalone,
651
+ lastModified: Date.now(),
652
+ pageId,
653
+ selector,
654
+ sourceCode
655
+ };
656
+ } catch (error) {
657
+ console.error(
658
+ `${chalk.blue.bold(LOG_PREFIX)} Failed to parse Angular demo ${filePath}:`,
659
+ error
660
+ );
661
+ return null;
662
+ }
663
+ }
664
+ function extractHighlightedVariants(highlightedHtml) {
665
+ const preMatch = highlightedHtml.match(/^<pre[^>]*><code>/)?.[0] || "";
666
+ const postMatch = highlightedHtml.match(/<\/code><\/pre>$/)?.[0] || "";
667
+ const content = highlightedHtml.slice(preMatch.length, -postMatch.length);
668
+ const lines = content.split("\n");
669
+ const previewLines = [];
670
+ const withoutPreviewLines = [];
671
+ let inPreview = false;
672
+ let omitNextLine = false;
673
+ for (const line of lines) {
674
+ const textContent = line.replace(/<[^>]*>/g, "").replace(/&#x3C;/g, "<").replace(/&#x3E;/g, ">").trim();
675
+ if (omitNextLine) {
676
+ omitNextLine = false;
677
+ continue;
678
+ }
679
+ if (textContent === "// qui-docs::omit-next-line") {
680
+ omitNextLine = true;
681
+ continue;
682
+ }
683
+ if (textContent === "// preview" || textContent === "/* preview */" || textContent === "<!-- preview -->") {
684
+ inPreview = !inPreview;
685
+ continue;
686
+ }
687
+ if (inPreview) {
688
+ previewLines.push(line);
689
+ }
690
+ withoutPreviewLines.push(line);
691
+ }
692
+ const normalizedPreviewLines = normalizeIndentation(previewLines);
693
+ const highlightedPreview = normalizedPreviewLines.length > 0 ? `${preMatch}${normalizedPreviewLines.join("\n")}${postMatch}` : "";
694
+ const highlightedWithoutPreview = `${preMatch}${withoutPreviewLines.join("\n")}${postMatch}`;
695
+ return { highlightedPreview, highlightedWithoutPreview };
696
+ }
697
+ function normalizeIndentation(lines) {
698
+ if (lines.length === 0) {
699
+ return [];
700
+ }
701
+ const nonEmptyLines = lines.filter(
702
+ (line) => line.replace(/<[^>]*>/g, "").trim().length > 0
703
+ );
704
+ if (nonEmptyLines.length === 0) {
705
+ return lines;
706
+ }
707
+ let minIndent = Infinity;
708
+ for (const line of nonEmptyLines) {
709
+ const matches = line.match(/<span class="indent">/g);
710
+ if (matches) {
711
+ minIndent = Math.min(minIndent, matches.length);
712
+ } else {
713
+ minIndent = 0;
714
+ break;
715
+ }
716
+ }
717
+ if (minIndent === 0 || minIndent === Infinity) {
718
+ return lines;
719
+ }
720
+ return lines.map((line) => {
721
+ let result = line;
722
+ for (let i = 0; i < minIndent; i++) {
723
+ result = result.replace(/<span class="indent">(\s*)<\/span>/, "");
724
+ }
725
+ return result;
726
+ });
727
+ }
728
+ function generateRegistryModule() {
729
+ const demos = Array.from(demoRegistry.values());
730
+ return `// Auto-generated Angular demo registry
731
+ export const ANGULAR_DEMOS = {
732
+ ${demos.map(
733
+ (demo) => ` "${demo.id}": ${JSON.stringify(
734
+ {
735
+ componentClass: demo.componentClass,
736
+ dimensions: demoDimensionsCache[demo.id],
737
+ filePath: demo.filePath,
738
+ hasDefaultExport: demo.hasDefaultExport,
739
+ id: demo.id,
740
+ imports: demo.imports,
741
+ initialHtml: demo.initialHtml,
742
+ isStandalone: demo.isStandalone,
743
+ lastModified: demo.lastModified,
744
+ pageId: demo.pageId,
745
+ selector: demo.selector,
746
+ sourceCode: demo.sourceCode
747
+ },
748
+ null,
749
+ 4
750
+ )}`
751
+ ).join(",\n")}
752
+ }
753
+
754
+ export function isAngularDemo(demoId) {
755
+ return demoId in ANGULAR_DEMOS
756
+ }
757
+
758
+ export function getAngularDemoInfo(demoId) {
759
+ return ANGULAR_DEMOS[demoId] || null
760
+ }
761
+
762
+ export function getAllAngularDemos() {
763
+ return Object.values(ANGULAR_DEMOS)
764
+ }
765
+
766
+ export const availableAngularDemos = Object.keys(ANGULAR_DEMOS)
767
+
768
+ if (import.meta.hot) {
769
+ import.meta.hot.accept(() => {
770
+ console.log('[angular-demo-registry] Registry updated via HMR')
771
+ })
772
+
773
+ if (typeof window !== 'undefined') {
774
+ import.meta.hot.on('angular-demo-update', (data) => {
775
+ console.log('[angular-demo-registry] Demo updated:', data.demoId)
776
+ })
777
+ }
778
+ }`;
779
+ }
780
+ function generatePageRegistryModule(pageId) {
781
+ const pageDemos = Array.from(demoRegistry.values()).filter(
782
+ (demo) => demo.pageId === pageId
783
+ );
784
+ if (pageDemos.length === 0) {
785
+ return `export function getAngularDemoInfo() { return null }
786
+ export const ANGULAR_DEMOS = {}`;
787
+ }
788
+ return `// Auto-generated Angular demo registry for ${pageId}
789
+ export const ANGULAR_DEMOS = {
790
+ ${pageDemos.map(
791
+ (demo) => ` "${demo.id}": ${JSON.stringify(
792
+ {
793
+ componentClass: demo.componentClass,
794
+ dimensions: demoDimensionsCache[demo.id],
795
+ filePath: demo.filePath,
796
+ hasDefaultExport: demo.hasDefaultExport,
797
+ id: demo.id,
798
+ imports: demo.imports,
799
+ initialHtml: demo.initialHtml,
800
+ isStandalone: demo.isStandalone,
801
+ lastModified: demo.lastModified,
802
+ pageId: demo.pageId,
803
+ selector: demo.selector,
804
+ sourceCode: demo.sourceCode
805
+ },
806
+ null,
807
+ 4
808
+ )}`
809
+ ).join(",\n")}
810
+ }
811
+
812
+ export function getAngularDemoInfo(demoId) {
813
+ return ANGULAR_DEMOS[demoId] || null
814
+ }
815
+
816
+ if (import.meta.hot) {
817
+ import.meta.hot.accept(() => {
818
+ console.log('[angular-demo-registry/${pageId}] Registry updated')
819
+ })
820
+ }`;
821
+ }
822
+ function extractPageId2(filePath, routesDir2) {
823
+ const relativePath = relative(routesDir2, filePath);
824
+ const pathParts = relativePath.split("/");
825
+ const demoIndex = pathParts.findIndex((part) => part.includes("demos"));
826
+ if (demoIndex === -1) {
827
+ return pathParts.at(-2) || pathParts.join("/");
828
+ }
829
+ return pathParts.slice(0, demoIndex).join("/");
830
+ }
831
+ function isAngularDemoFile(filePath) {
832
+ return filePath.includes("/demos/") && (filePath.endsWith(".ts") || filePath.endsWith("html"));
833
+ }
834
+ function isCssAsset2(filePath) {
835
+ return filePath.endsWith(".css");
836
+ }
837
+ function isRelativeImport2(source) {
838
+ return source.startsWith("./") || source.startsWith("../");
839
+ }
840
+ function isNodeBuiltin2(source) {
841
+ const NODE_BUILTINS2 = [
842
+ "assert",
843
+ "buffer",
844
+ "child_process",
845
+ "cluster",
846
+ "crypto",
847
+ "dgram",
848
+ "dns",
849
+ "domain",
850
+ "events",
851
+ "fs",
852
+ "http",
853
+ "https",
854
+ "net",
855
+ "os",
856
+ "path",
857
+ "punycode",
858
+ "querystring",
859
+ "readline",
860
+ "stream",
861
+ "string_decoder",
862
+ "timers",
863
+ "tls",
864
+ "tty",
865
+ "url",
866
+ "util",
867
+ "v8",
868
+ "vm",
869
+ "zlib"
870
+ ];
871
+ return source.startsWith("node:") || NODE_BUILTINS2.includes(source);
872
+ }
873
+ function resolveRelativeImport2(source, fromFile) {
874
+ const fromDir = dirname(fromFile);
875
+ const resolved = resolve(fromDir, source);
876
+ const extensions = [".ts", ".tsx", ".js", ".jsx"];
877
+ for (const ext of extensions) {
878
+ const withExt = resolved + ext;
879
+ if (existsSync(withExt)) {
880
+ return withExt;
881
+ }
882
+ }
883
+ for (const ext of extensions) {
884
+ const indexFile = join(resolved, `index${ext}`);
885
+ if (existsSync(indexFile)) {
886
+ return indexFile;
887
+ }
888
+ }
889
+ return resolved;
890
+ }
891
+ function loadTsConfigPaths2(fromFile) {
892
+ let currentDir = dirname(fromFile);
893
+ const pathAliases = [];
894
+ while (currentDir !== dirname(currentDir)) {
895
+ const tsconfigPath = join(currentDir, "tsconfig.json");
896
+ if (existsSync(tsconfigPath)) {
897
+ try {
898
+ const configContent = ts.sys.readFile(tsconfigPath);
899
+ if (!configContent) {
900
+ currentDir = dirname(currentDir);
901
+ continue;
902
+ }
903
+ const parseResult = ts.parseConfigFileTextToJson(
904
+ tsconfigPath,
905
+ configContent
906
+ );
907
+ if (parseResult.error) {
908
+ currentDir = dirname(currentDir);
909
+ continue;
910
+ }
911
+ const paths = parseResult.config?.compilerOptions?.paths;
912
+ const baseUrl = parseResult.config?.compilerOptions?.baseUrl || "./";
913
+ const resolvedBaseUrl = resolve(currentDir, baseUrl);
914
+ if (paths) {
915
+ for (const [alias, targets] of Object.entries(paths)) {
916
+ if (Array.isArray(targets) && targets.length > 0) {
917
+ const target = targets[0];
918
+ const pattern = new RegExp(
919
+ `^${alias.replace("*", "(.*)").replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\(\\*\\)", "(.*)")}$`
920
+ );
921
+ const replacement = resolve(
922
+ resolvedBaseUrl,
923
+ target.replace("*", "$1")
924
+ );
925
+ pathAliases.push({ pattern, replacement });
926
+ }
927
+ }
928
+ }
929
+ const extendsPath = parseResult.config?.extends;
930
+ if (extendsPath) {
931
+ const resolvedExtends = resolve(currentDir, extendsPath);
932
+ const extendedAliases = loadTsConfigPathsFromFile(resolvedExtends);
933
+ pathAliases.push(...extendedAliases);
934
+ }
935
+ return pathAliases;
936
+ } catch (error) {
937
+ currentDir = dirname(currentDir);
938
+ continue;
939
+ }
940
+ }
941
+ currentDir = dirname(currentDir);
942
+ }
943
+ return pathAliases;
944
+ }
945
+ async function setupAngularWatcher() {
946
+ watcher = watch(routesDir, {
947
+ ignoreInitial: true,
948
+ persistent: true
949
+ });
950
+ watcher.on("ready", () => {
951
+ logDev(
952
+ `${chalk.blue.bold(LOG_PREFIX)} Registered ${chalk.green(demoRegistry.size)} demo files. Watching for file changes...`
953
+ );
954
+ });
955
+ watcher.on("add", async (filePath) => {
956
+ const fileStats = await stat(filePath);
957
+ if (fileStats.size === 0) {
958
+ return;
959
+ }
960
+ if (isAngularDemoFile(filePath)) {
961
+ logDev(
962
+ `${chalk.blue.bold(LOG_PREFIX)} New Angular demo: ${chalk.green(filePath)}`
963
+ );
964
+ await handleAngularDemoUpdate(filePath);
965
+ triggerRegistryUpdate();
966
+ }
967
+ });
968
+ watcher.on("unlink", (filePath) => {
969
+ if (isAngularDemoFile(filePath)) {
970
+ const demoEntry = Array.from(demoRegistry.entries()).find(
971
+ ([, info]) => info.filePath === filePath
972
+ );
973
+ if (demoEntry) {
974
+ const [demoId] = demoEntry;
975
+ demoRegistry.delete(demoId);
976
+ logDev(
977
+ `${chalk.blue.bold(LOG_PREFIX)} Removed demo: ${chalk.red(demoId)}`
978
+ );
979
+ triggerRegistryUpdate();
980
+ }
981
+ }
982
+ });
983
+ }
984
+ async function handleAngularDemoUpdate(filePath) {
985
+ const code = await readFile(filePath, "utf-8");
986
+ const demoInfo = await parseAngularDemo(filePath, code);
987
+ if (demoInfo) {
988
+ demoRegistry.set(demoInfo.id, demoInfo);
989
+ }
990
+ }
991
+ function triggerRegistryUpdate() {
992
+ if (devServer) {
993
+ const mainModule = devServer.moduleGraph.getModuleById(VIRTUAL_MODULE_ID);
994
+ if (mainModule) {
995
+ devServer.moduleGraph.invalidateModule(mainModule);
996
+ mainModule.lastHMRTimestamp = Date.now();
997
+ devServer.reloadModule(mainModule);
998
+ }
999
+ const pageIds = new Set(
1000
+ Array.from(demoRegistry.values()).map((demo) => demo.pageId)
1001
+ );
1002
+ for (const pageId of pageIds) {
1003
+ const pageModuleId = `\0${VIRTUAL_MODULE_PREFIX}${pageId}`;
1004
+ const pageModule = devServer.moduleGraph.getModuleById(pageModuleId);
1005
+ if (pageModule) {
1006
+ devServer.moduleGraph.invalidateModule(pageModule);
1007
+ pageModule.lastHMRTimestamp = Date.now();
1008
+ devServer.reloadModule(pageModule);
1009
+ }
1010
+ }
1011
+ }
1012
+ }
1013
+ }
1014
+ function loadTsConfigPathsFromFile(tsconfigPath) {
1015
+ const pathAliases = [];
1016
+ const configDir = dirname(tsconfigPath);
1017
+ try {
1018
+ const configContent = ts.sys.readFile(tsconfigPath);
1019
+ if (!configContent) {
1020
+ return pathAliases;
1021
+ }
1022
+ const parseResult = ts.parseConfigFileTextToJson(
1023
+ tsconfigPath,
1024
+ configContent
1025
+ );
1026
+ if (parseResult.error) {
1027
+ return pathAliases;
1028
+ }
1029
+ const paths = parseResult.config?.compilerOptions?.paths;
1030
+ const baseUrl = parseResult.config?.compilerOptions?.baseUrl || "./";
1031
+ const resolvedBaseUrl = resolve(configDir, baseUrl);
1032
+ if (paths) {
1033
+ for (const [alias, targets] of Object.entries(paths)) {
1034
+ if (Array.isArray(targets) && targets.length > 0) {
1035
+ const target = targets[0];
1036
+ const pattern = new RegExp(
1037
+ `^${alias.replace("*", "(.*)").replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\(\\*\\)", "(.*)")}$`
1038
+ );
1039
+ const replacement = resolve(
1040
+ resolvedBaseUrl,
1041
+ target.replace("*", "$1")
1042
+ );
1043
+ pathAliases.push({ pattern, replacement });
1044
+ }
1045
+ }
1046
+ }
1047
+ const extendsPath = parseResult.config?.extends;
1048
+ if (extendsPath) {
1049
+ let resolvedExtends = resolve(configDir, extendsPath);
1050
+ if (!resolvedExtends.endsWith(".json")) {
1051
+ resolvedExtends += ".json";
1052
+ }
1053
+ if (existsSync(resolvedExtends)) {
1054
+ const extendedAliases = loadTsConfigPathsFromFile(resolvedExtends);
1055
+ pathAliases.push(...extendedAliases);
1056
+ }
1057
+ }
1058
+ } catch (error) {
1059
+ return pathAliases;
1060
+ }
1061
+ return pathAliases;
1062
+ }
1063
+ function isPathAliasImport(source, pathAliases) {
1064
+ return pathAliases.some((alias) => alias.pattern.test(source));
1065
+ }
1066
+ function resolvePathAlias(source, pathAliases) {
1067
+ for (const alias of pathAliases) {
1068
+ if (alias.pattern.test(source)) {
1069
+ const resolvedPath = source.replace(alias.pattern, alias.replacement);
1070
+ const extensions = [".ts", ".tsx", ".js", ".jsx"];
1071
+ for (const ext of extensions) {
1072
+ const withExt = resolvedPath + ext;
1073
+ if (existsSync(withExt)) {
1074
+ return withExt;
1075
+ }
1076
+ }
1077
+ for (const ext of extensions) {
1078
+ const indexFile = join(resolvedPath, `index${ext}`);
1079
+ if (existsSync(indexFile)) {
1080
+ return indexFile;
1081
+ }
1082
+ }
1083
+ return resolvedPath;
1084
+ }
1085
+ }
1086
+ return null;
1087
+ }
1088
+ function resolveTemplateFile(templateUrl, fromFile) {
1089
+ const fromDir = dirname(fromFile);
1090
+ const resolved = resolve(fromDir, templateUrl);
1091
+ if (existsSync(resolved)) {
1092
+ return resolved;
1093
+ }
1094
+ if (!resolved.endsWith(".html")) {
1095
+ const withHtml = `${resolved}.html`;
1096
+ if (existsSync(withHtml)) {
1097
+ return withHtml;
1098
+ }
1099
+ }
1100
+ return resolved;
1101
+ }
1102
+ function isOmitNextLine(trimmedLine) {
1103
+ return trimmedLine === "// qui-docs::omit-next-line";
1104
+ }
1105
+
1106
+ // src/docs-plugin/docs-plugin.ts
1107
+ import chalk4 from "chalk";
1108
+ import chokidar from "chokidar";
1109
+ import { glob as glob2 } from "glob";
1110
+ import { readFileSync as readFileSync2 } from "node:fs";
1111
+ import { resolve as resolve2 } from "node:path";
1112
+ import prettyMilliseconds from "pretty-ms";
1113
+
1114
+ // src/docs-plugin/internal/config-loader.ts
1115
+ import { cosmiconfigSync } from "cosmiconfig";
1116
+
1117
+ // src/docs-plugin/internal/config-schema.ts
1118
+ import { z as z2 } from "zod";
1119
+
1120
+ // src/docs-plugin/internal/zod.ts
1121
+ import { z } from "zod";
1122
+ function implement() {
1123
+ return {
1124
+ with: (schema) => z.object(schema)
1125
+ };
1126
+ }
1127
+
1128
+ // src/docs-plugin/internal/config-schema.ts
1129
+ var navMetaSchema = implement().with({
1130
+ id: z2.never().optional(),
1131
+ sectionTitle: z2.string().optional(),
1132
+ separator: z2.boolean().optional()
1133
+ });
1134
+ var routeMetaSchema = implement().with({
1135
+ children: z2.array(z2.lazy(() => routeMetaSchema)).optional(),
1136
+ expanded: z2.boolean().optional(),
1137
+ group: z2.string().optional(),
1138
+ groupOrder: z2.string().array().optional(),
1139
+ hidden: z2.boolean().optional(),
1140
+ hideBreadcrumbs: z2.boolean().optional(),
1141
+ hideFromSearch: z2.boolean().optional(),
1142
+ hidePageLinks: z2.boolean().optional(),
1143
+ hideSideNav: z2.boolean().optional(),
1144
+ hideToc: z2.boolean().optional(),
1145
+ id: z2.string(),
1146
+ ignoreRouteMetaOrder: z2.boolean().optional(),
1147
+ restricted: z2.boolean().optional(),
1148
+ sectionTitle: z2.never().optional(),
1149
+ separator: z2.never().optional(),
1150
+ sideNavTitle: z2.string().optional(),
1151
+ title: z2.string().optional()
1152
+ });
1153
+ var typeDocPropsSchema = implement().with({
1154
+ includeInSearchIndex: z2.boolean().optional()
1155
+ });
1156
+ var configSchema = implement().with({
1157
+ appDirectory: z2.string().optional(),
1158
+ disableCache: z2.boolean().optional(),
1159
+ headings: z2.array(
1160
+ z2.union([
1161
+ z2.literal("h1"),
1162
+ z2.literal("h2"),
1163
+ z2.literal("h3"),
1164
+ z2.literal("h4"),
1165
+ z2.literal("h5"),
1166
+ z2.literal("h6")
1167
+ ])
1168
+ ).optional(),
1169
+ hotUpdateIgnore: z2.instanceof(RegExp).optional(),
1170
+ navConfig: z2.array(z2.union([routeMetaSchema, navMetaSchema])).optional(),
1171
+ pageDirectory: z2.string().optional(),
1172
+ routingStrategy: z2.union([
1173
+ z2.literal("vite-generouted"),
1174
+ z2.function(z2.tuple([z2.string()]), z2.array(z2.string()))
1175
+ ]).optional(),
1176
+ typeDocProps: z2.string().optional(),
1177
+ typeDocPropsOptions: typeDocPropsSchema.optional()
1178
+ });
1179
+
1180
+ // src/docs-plugin/internal/utils.ts
1181
+ import { z as z3 } from "zod";
1182
+ function defined(value) {
1183
+ return typeof value !== "undefined" && value !== null;
1184
+ }
1185
+ var frontmatterSchema = implement().with({
1186
+ categories: z3.string().array().optional(),
1187
+ group: z3.string().optional(),
1188
+ hidden: z3.boolean().optional(),
1189
+ hideBreadcrumbs: z3.boolean().optional(),
1190
+ hideFromSearch: z3.boolean().optional(),
1191
+ hidePageLinks: z3.boolean().optional(),
1192
+ hideSideNav: z3.boolean().optional(),
1193
+ hideToc: z3.boolean().optional(),
1194
+ id: z3.string().optional(),
1195
+ restricted: z3.boolean().optional(),
1196
+ sideNavTitle: z3.string().optional(),
1197
+ title: z3.string()
1198
+ });
1199
+ function fixPath(str) {
1200
+ return str.replaceAll("\\", "/");
1201
+ }
1202
+ function removeTrailingSlash(str) {
1203
+ return str.endsWith("/") ? str.substring(0, str.length - 1) : str;
1204
+ }
1205
+
1206
+ // src/docs-plugin/internal/config-loader.ts
1207
+ var ConfigLoader = class {
1208
+ options;
1209
+ constructor(options) {
1210
+ this.options = options;
1211
+ return this;
1212
+ }
1213
+ getCosmiconfig() {
1214
+ const explorer = cosmiconfigSync("qui-docs");
1215
+ const result = this.options.configFile ? explorer.load(this.options.configFile) : explorer.search();
1216
+ if (!result) {
1217
+ throw new Error(
1218
+ "Config file not found. Please consult the docs at https://docs.qui.qualcomm.com/guide/page-setup#config"
1219
+ );
1220
+ }
1221
+ return result;
1222
+ }
1223
+ resolveConfigFromCosmiconfig(config) {
1224
+ const parsed = configSchema.safeParse(config.config);
1225
+ if (!parsed.success) {
1226
+ console.dir(parsed.error.issues, { depth: 10 });
1227
+ throw new Error("Failed to parse config file.");
1228
+ }
1229
+ const conf = parsed.data;
1230
+ return {
1231
+ ...conf,
1232
+ appDirectory: conf.appDirectory || "app",
1233
+ filePath: config.filepath,
1234
+ pageDirectory: conf.pageDirectory ? removeTrailingSlash(conf.pageDirectory) : "routes"
1235
+ };
1236
+ }
1237
+ loadConfig() {
1238
+ const config = this.getCosmiconfig();
1239
+ return this.resolveConfigFromCosmiconfig(config);
1240
+ }
1241
+ };
1242
+
1243
+ // src/docs-plugin/internal/search-indexer.ts
1244
+ import chalk3 from "chalk";
1245
+
1246
+ // src/docs-plugin/internal/services/doc-props/doc-props-indexer.ts
1247
+ import remarkMdx from "remark-mdx";
1248
+ import remarkParse from "remark-parse";
1249
+ import remarkStringify from "remark-stringify";
1250
+ import { unified } from "unified";
1251
+ import { visit } from "unist-util-visit";
1252
+ import {
1253
+ UniqueIdService
1254
+ } from "@qualcomm-ui/mdx-common";
1255
+ function extractPickPropsRecord(node) {
1256
+ if (node.name !== "unionWithPick" || !node.value || typeof node.value === "string") {
1257
+ return null;
1258
+ }
1259
+ const estree = node.value.data?.estree;
1260
+ if (!estree?.body?.[0] || estree.body[0].type !== "ExpressionStatement") {
1261
+ return null;
1262
+ }
1263
+ const expression = estree.body[0].expression;
1264
+ if (expression.type !== "ObjectExpression") {
1265
+ return null;
1266
+ }
1267
+ const result = {};
1268
+ for (const property of expression.properties) {
1269
+ if (property.type !== "Property" || property.key.type !== "Identifier") {
1270
+ continue;
1271
+ }
1272
+ if (property.value.type !== "ArrayExpression") {
1273
+ continue;
1274
+ }
1275
+ const key = property.key.name;
1276
+ const values = [];
1277
+ for (const element of property.value.elements) {
1278
+ if (element?.type === "Literal" && typeof element.value === "string") {
1279
+ values.push(element.value);
1280
+ }
1281
+ }
1282
+ result[key] = values;
1283
+ }
1284
+ return result;
1285
+ }
1286
+ var targetMdxElements = [
1287
+ "TypeDocProps",
1288
+ "TypeDocAttributes",
1289
+ "TypeDocAngularAttributes"
1290
+ ];
1291
+ var DocPropsIndexer = class {
1292
+ docPropsEntries = [];
1293
+ idService = new UniqueIdService();
1294
+ props;
1295
+ pageDocProps = {};
1296
+ constructor(props) {
1297
+ this.props = props;
1298
+ }
1299
+ reset() {
1300
+ this.idService.reset();
1301
+ this.docPropsEntries = [];
1302
+ }
1303
+ extractNamesFromAttribute(attr) {
1304
+ if (!attr.value) {
1305
+ return [];
1306
+ }
1307
+ if (typeof attr.value === "string") {
1308
+ return [attr.value];
1309
+ }
1310
+ if (attr.value.type === "mdxJsxAttributeValueExpression") {
1311
+ const estree = attr.value.data?.estree;
1312
+ if (!estree?.body?.[0] || estree.body[0].type !== "ExpressionStatement") {
1313
+ return [];
1314
+ }
1315
+ const expression = estree.body[0].expression;
1316
+ if (expression.type === "ArrayExpression") {
1317
+ const names = [];
1318
+ for (const element of expression.elements) {
1319
+ if (element?.type === "Literal" && typeof element.value === "string") {
1320
+ names.push(element.value);
1321
+ }
1322
+ }
1323
+ return names;
1324
+ }
1325
+ if (expression.type === "Literal" && typeof expression.value === "string") {
1326
+ return [expression.value];
1327
+ }
1328
+ }
1329
+ return [];
1330
+ }
1331
+ /**
1332
+ * Finds all JSX `<TypeDocProps />` nodes on the current page and adds their names
1333
+ * to an array. Once all nodes have been collected, we process them into
1334
+ * `PageSection` entries for the search index.
1335
+ */
1336
+ getTypeDocPropsNodes = () => {
1337
+ return (tree, _file, done) => {
1338
+ visit(tree, "mdxJsxFlowElement", (node) => {
1339
+ if (node && "name" in node && targetMdxElements.includes(node.name)) {
1340
+ const nameAttr = node.attributes?.find(
1341
+ (attr) => attr.name === "name"
1342
+ );
1343
+ const omitFromAttr = node.attributes?.find(
1344
+ (attr) => attr.name === "omitFrom"
1345
+ );
1346
+ const omitFrom = omitFromAttr ? this.extractNamesFromAttribute(omitFromAttr) : void 0;
1347
+ if (nameAttr) {
1348
+ const names = this.extractNamesFromAttribute(nameAttr);
1349
+ for (const name of names) {
1350
+ this.docPropsEntries.push({ name, omitFrom });
1351
+ if (name.endsWith("Props")) {
1352
+ this.docPropsEntries.push({ name: name.slice(0, -5), omitFrom });
1353
+ }
1354
+ }
1355
+ }
1356
+ const unionWithPickAttr = node.attributes?.find(
1357
+ (attr) => attr.name === "unionWithPick"
1358
+ );
1359
+ if (unionWithPickAttr) {
1360
+ try {
1361
+ const unionWithPick = extractPickPropsRecord(unionWithPickAttr);
1362
+ if (unionWithPick) {
1363
+ this.docPropsEntries.push(
1364
+ ...Object.keys(unionWithPick).map((entry) => ({
1365
+ name: entry,
1366
+ omitFrom
1367
+ }))
1368
+ );
1369
+ }
1370
+ } catch (e) {
1371
+ }
1372
+ }
1373
+ }
1374
+ });
1375
+ done();
1376
+ };
1377
+ };
1378
+ build(fileContents, toc) {
1379
+ unified().use(remarkMdx).use(this.getTypeDocPropsNodes).use(remarkParse).use(remarkStringify).processSync(fileContents);
1380
+ if (!this.docPropsEntries.length) {
1381
+ return null;
1382
+ }
1383
+ for (const item of toc) {
1384
+ this.idService.add(item.id);
1385
+ }
1386
+ return this.docPropsEntries.map((entry) => {
1387
+ const propTypes = this.props[entry.name];
1388
+ if (!propTypes) {
1389
+ return [];
1390
+ }
1391
+ const omittedProps = new Set(
1392
+ (entry.omitFrom ?? []).map((entry2) => {
1393
+ const propTypes2 = this.props[entry2];
1394
+ if (!propTypes2) {
1395
+ return [];
1396
+ }
1397
+ return [
1398
+ propTypes2.props,
1399
+ propTypes2.input,
1400
+ propTypes2.output,
1401
+ propTypes2.publicMethods
1402
+ ].reduce((acc, current) => {
1403
+ if (current) {
1404
+ acc.push(...current.map((prop) => prop.name));
1405
+ }
1406
+ return acc;
1407
+ }, []);
1408
+ }).flat(1).filter(Boolean)
1409
+ );
1410
+ const sections = [];
1411
+ const assembleProps = (propsInput) => {
1412
+ if (!propsInput) {
1413
+ return void 0;
1414
+ }
1415
+ const props = [];
1416
+ for (const prop of propsInput) {
1417
+ if (omittedProps.has(prop.name)) {
1418
+ continue;
1419
+ }
1420
+ const id = this.idService.add(prop.name);
1421
+ props.push({ ...prop, id });
1422
+ sections.push(this.assembleProp(prop, id));
1423
+ }
1424
+ return props;
1425
+ };
1426
+ this.pageDocProps[entry.name] = {
1427
+ ...this.props[entry.name],
1428
+ input: assembleProps(propTypes.input),
1429
+ output: assembleProps(propTypes.output),
1430
+ props: assembleProps(propTypes.props),
1431
+ publicMethods: assembleProps(propTypes.publicMethods)
1432
+ };
1433
+ return sections;
1434
+ }).flat();
1435
+ }
1436
+ getDocProps() {
1437
+ return this.docPropsEntries.reduce((acc, entry) => {
1438
+ const propTypes = this.pageDocProps[entry.name];
1439
+ if (propTypes) {
1440
+ acc[entry.name] = propTypes;
1441
+ }
1442
+ return acc;
1443
+ }, {});
1444
+ }
1445
+ assembleProp(prop, id) {
1446
+ const name = prop.name;
1447
+ const heading2 = {
1448
+ headingLevel: 4,
1449
+ id,
1450
+ tagName: "a",
1451
+ textContent: name
1452
+ };
1453
+ const comment = prop.comment;
1454
+ if (!comment) {
1455
+ return { content: [], heading: heading2 };
1456
+ }
1457
+ const content = {
1458
+ tagName: "p",
1459
+ text: [
1460
+ comment.summary.map((entry) => entry.text.replaceAll("\n", " ")).join("")
1461
+ ]
1462
+ };
1463
+ return { content: [content], heading: heading2 };
1464
+ }
1465
+ };
1466
+
1467
+ // src/docs-plugin/internal/services/markdown/markdown-file-reader.ts
1468
+ import chalk2 from "chalk";
1469
+ import { createHash } from "node:crypto";
1470
+ import { readFileSync } from "node:fs";
1471
+ import remarkFrontmatter from "remark-frontmatter";
1472
+ import remarkParse2 from "remark-parse";
1473
+ import remarkParseFrontmatter from "remark-parse-frontmatter";
1474
+ import remarkStringify2 from "remark-stringify";
1475
+ import { unified as unified2 } from "unified";
1476
+ var MarkdownFileReader = class {
1477
+ constructor(enabled) {
1478
+ this.enabled = enabled;
1479
+ }
1480
+ cachedFileCount = 0;
1481
+ logWarnings = true;
1482
+ mdxCache = {};
1483
+ hash(input) {
1484
+ return createHash("md5").update(input).digest("hex");
1485
+ }
1486
+ reset() {
1487
+ this.cachedFileCount = 0;
1488
+ }
1489
+ checkCache(filepath, fileContents) {
1490
+ if (!this.enabled) {
1491
+ return;
1492
+ }
1493
+ const fileMd5 = this.hash(fileContents);
1494
+ const cached = this.mdxCache[filepath];
1495
+ if (cached?.md5 !== fileMd5) {
1496
+ return;
1497
+ }
1498
+ this.cachedFileCount++;
1499
+ return {
1500
+ frontmatter: cached.frontmatter,
1501
+ page: cached.page,
1502
+ pageDocProps: cached.pageDocProps,
1503
+ pageDocPropSections: cached.pageDocPropSections
1504
+ };
1505
+ }
1506
+ readFile(filepath) {
1507
+ const fileContents = readFileSync(filepath, "utf-8");
1508
+ const cached = this.checkCache(filepath, fileContents);
1509
+ let file;
1510
+ if (cached?.frontmatter) {
1511
+ file = { data: { frontmatter: cached.frontmatter } };
1512
+ } else {
1513
+ const yamlSection = fileContents.substring(
1514
+ 0,
1515
+ fileContents.indexOf("\n---") + 4
1516
+ );
1517
+ file = unified2().use(remarkParse2).use(remarkFrontmatter, ["yaml"]).use(remarkParseFrontmatter).use(remarkStringify2).processSync(yamlSection);
1518
+ }
1519
+ const frontmatter = file.data.frontmatter ?? { title: "" };
1520
+ if (!frontmatter.title) {
1521
+ const lines = fileContents.split("\n");
1522
+ const fallbackTitle = lines.find((line) => line.startsWith("# "));
1523
+ if (fallbackTitle) {
1524
+ frontmatter.title = fallbackTitle.substring(2).trim();
1525
+ }
1526
+ }
1527
+ if (!frontmatter.title && this.logWarnings) {
1528
+ console.debug(chalk2.red.bold("Missing title:"), filepath);
1529
+ }
1530
+ const parsedFrontmatter = frontmatterSchema.safeParse(frontmatter);
1531
+ if (!parsedFrontmatter.success) {
1532
+ console.debug(
1533
+ `${chalk2.redBright.bold("Invalid frontmatter detected for file")}: ${filepath}
1534
+ `
1535
+ );
1536
+ console.debug(chalk2.redBright.bold("Please check the following fields:"));
1537
+ parsedFrontmatter.error.issues.map((issue) => {
1538
+ console.debug(`- ${issue.path.join(".")}`);
1539
+ });
1540
+ }
1541
+ return { cached, fileContents, frontmatter };
1542
+ }
1543
+ updateCache(filepath, fileContents, cacheData) {
1544
+ if (this.enabled) {
1545
+ this.mdxCache[filepath] = { ...cacheData, md5: this.hash(fileContents) };
1546
+ }
1547
+ }
1548
+ };
1549
+
1550
+ // src/docs-plugin/internal/services/markdown/markdown-indexer.ts
1551
+ import { fromHtml } from "hast-util-from-html";
1552
+ import { toText } from "hast-util-to-text";
1553
+ import { clone, size } from "lodash-es";
1554
+ import rehypeParse from "rehype-parse";
1555
+ import rehypeStringify from "rehype-stringify";
1556
+ import remarkGfm from "remark-gfm";
1557
+ import remarkMdx2 from "remark-mdx";
1558
+ import remarkParse3 from "remark-parse";
1559
+ import remarkRehype from "remark-rehype";
1560
+ import { unified as unified3 } from "unified";
1561
+
1562
+ // src/docs-plugin/rehype/rehype-slug.ts
1563
+ import { headingRank } from "hast-util-heading-rank";
1564
+ import { toString } from "hast-util-to-string";
1565
+ import { visit as visit2 } from "unist-util-visit";
1566
+ var emptyOptions = {};
1567
+ var rehypeSlug = (options) => {
1568
+ const settings = options || emptyOptions;
1569
+ const prefix = settings.prefix || "";
1570
+ const allowedHeadings = new Set(
1571
+ settings.allowedHeadings || ["h2", "h3", "h4"]
1572
+ );
1573
+ const seenIds = /* @__PURE__ */ new Map();
1574
+ function createSlug(text) {
1575
+ const cleaned = text.replace(/[<>]/g, "").replace(/[^\w\s-]/g, "").trim();
1576
+ let slug;
1577
+ if (cleaned.includes(" ")) {
1578
+ slug = cleaned.toLowerCase().replace(/\s+/g, "-").replace(/^-+|-+$/g, "");
1579
+ } else if ((cleaned.match(/[A-Z]/g) || []).length >= 2) {
1580
+ slug = cleaned.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").toLowerCase();
1581
+ } else {
1582
+ slug = cleaned.toLowerCase();
1583
+ }
1584
+ const count = seenIds.get(slug) || 0;
1585
+ seenIds.set(slug, count + 1);
1586
+ return count > 0 ? `${slug}-${count}` : slug;
1587
+ }
1588
+ return (tree) => {
1589
+ seenIds.clear();
1590
+ visit2(tree, "element", function(node) {
1591
+ if (headingRank(node) && !node.properties.id && allowedHeadings.has(node.tagName)) {
1592
+ node.properties.id = prefix + createSlug(toString(node));
1593
+ }
1594
+ });
1595
+ };
1596
+ };
1597
+
1598
+ // src/docs-plugin/remark/remark-alerts.ts
1599
+ import { visit as visit3 } from "unist-util-visit";
1600
+ var alertLegacyRegex = /^\[!(NOTE|TIP|SUCCESS|WARNING|CAUTION)(\/.*)?\]/i;
1601
+ var remarkAlerts = () => {
1602
+ return (tree) => {
1603
+ visit3(tree, "blockquote", (node) => {
1604
+ let alertType = "";
1605
+ let title = "";
1606
+ let isNext = true;
1607
+ const child = node.children.map((item) => {
1608
+ if (isNext && item.type === "paragraph") {
1609
+ const firstNode = item.children[0];
1610
+ const text = firstNode.type === "text" ? firstNode.value : "";
1611
+ const reg = alertLegacyRegex;
1612
+ const match = text.match(reg);
1613
+ if (match) {
1614
+ isNext = false;
1615
+ alertType = match[1].toLocaleLowerCase();
1616
+ title = match[2] || alertType.toLocaleUpperCase();
1617
+ if (text.includes("\n")) {
1618
+ item.children[0] = {
1619
+ type: "text",
1620
+ value: text.replace(reg, "").replace(/^\n+/, "")
1621
+ };
1622
+ }
1623
+ if (!text.includes("\n")) {
1624
+ const itemChild = [];
1625
+ item.children.forEach((item2, idx) => {
1626
+ if (idx === 0) {
1627
+ return;
1628
+ }
1629
+ if (idx === 1 && item2.type === "break") {
1630
+ return;
1631
+ }
1632
+ itemChild.push(item2);
1633
+ });
1634
+ item.children = [...itemChild];
1635
+ }
1636
+ }
1637
+ }
1638
+ return item;
1639
+ });
1640
+ title = title.replace(/^\//, "");
1641
+ if (!!alertType) {
1642
+ node.data = {
1643
+ hName: "div",
1644
+ hProperties: {
1645
+ class: `qui-notification__root`,
1646
+ "data-emphasis": alertToEmphasis[alertType] || "neutral",
1647
+ "data-orientation": "vertical",
1648
+ dir: "auto"
1649
+ }
1650
+ };
1651
+ node.children = [
1652
+ {
1653
+ children: [getAlertIcon(alertType)],
1654
+ data: {
1655
+ hProperties: {
1656
+ class: "qui-notification__icon",
1657
+ "data-part": "status-icon",
1658
+ "data-scope": "inline-notification"
1659
+ }
1660
+ },
1661
+ type: "paragraph"
1662
+ },
1663
+ {
1664
+ children: [
1665
+ {
1666
+ type: "text",
1667
+ value: title
1668
+ }
1669
+ ],
1670
+ data: {
1671
+ hProperties: {
1672
+ class: "qui-notification__label",
1673
+ dir: "auto"
1674
+ }
1675
+ },
1676
+ type: "paragraph"
1677
+ },
1678
+ {
1679
+ children: child,
1680
+ data: {
1681
+ hName: "div",
1682
+ hProperties: {
1683
+ class: `qui-notification__description`,
1684
+ dir: "auto"
1685
+ }
1686
+ },
1687
+ type: "blockquote"
1688
+ }
1689
+ ];
1690
+ }
1691
+ });
1692
+ };
1693
+ };
1694
+ function getAlertIcon(type) {
1695
+ const svgChildren = svgData[type] ?? [];
1696
+ return {
1697
+ children: svgChildren,
1698
+ data: {
1699
+ hName: "svg",
1700
+ hProperties: {
1701
+ ariaHidden: "true",
1702
+ class: "lucide",
1703
+ fill: "transparent",
1704
+ height: "20",
1705
+ stroke: "currentColor",
1706
+ strokeLinecap: "round",
1707
+ strokeLinejoin: "round",
1708
+ strokeWidth: "2",
1709
+ viewBox: "0 0 24 24",
1710
+ width: "20"
1711
+ }
1712
+ },
1713
+ type: "emphasis"
1714
+ };
1715
+ }
1716
+ var svgData = {
1717
+ caution: [
1718
+ {
1719
+ children: [],
1720
+ data: {
1721
+ hName: "polygon",
1722
+ hProperties: {
1723
+ points: "7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86 7.86 2"
1724
+ }
1725
+ },
1726
+ type: "emphasis"
1727
+ },
1728
+ {
1729
+ children: [],
1730
+ data: {
1731
+ hName: "line",
1732
+ hProperties: {
1733
+ x1: "12",
1734
+ x2: "12",
1735
+ y1: "8",
1736
+ y2: "12"
1737
+ }
1738
+ },
1739
+ type: "emphasis"
1740
+ },
1741
+ {
1742
+ children: [],
1743
+ data: {
1744
+ hName: "line",
1745
+ hProperties: {
1746
+ x1: "12",
1747
+ x2: "12.01",
1748
+ y1: "16",
1749
+ y2: "16"
1750
+ }
1751
+ },
1752
+ type: "emphasis"
1753
+ }
1754
+ ],
1755
+ note: [
1756
+ {
1757
+ children: [],
1758
+ data: {
1759
+ hName: "circle",
1760
+ hProperties: {
1761
+ cx: "12",
1762
+ cy: "12",
1763
+ r: "10"
1764
+ }
1765
+ },
1766
+ type: "emphasis"
1767
+ },
1768
+ {
1769
+ children: [],
1770
+ data: {
1771
+ hName: "path",
1772
+ hProperties: {
1773
+ d: "M12 16v-4"
1774
+ }
1775
+ },
1776
+ type: "emphasis"
1777
+ },
1778
+ {
1779
+ children: [],
1780
+ data: {
1781
+ hName: "path",
1782
+ hProperties: {
1783
+ d: "M12 8h.01"
1784
+ }
1785
+ },
1786
+ type: "emphasis"
1787
+ }
1788
+ ],
1789
+ success: [
1790
+ {
1791
+ children: [],
1792
+ data: {
1793
+ hName: "path",
1794
+ hProperties: {
1795
+ d: "M20 6 9 17l-5-5"
1796
+ }
1797
+ },
1798
+ type: "emphasis"
1799
+ }
1800
+ ],
1801
+ tip: [
1802
+ {
1803
+ children: [],
1804
+ data: {
1805
+ hName: "path",
1806
+ hProperties: {
1807
+ d: "M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"
1808
+ }
1809
+ },
1810
+ type: "emphasis"
1811
+ },
1812
+ {
1813
+ children: [],
1814
+ data: {
1815
+ hName: "path",
1816
+ hProperties: {
1817
+ d: "M9 18h6"
1818
+ }
1819
+ },
1820
+ type: "emphasis"
1821
+ },
1822
+ {
1823
+ children: [],
1824
+ data: {
1825
+ hName: "path",
1826
+ hProperties: {
1827
+ d: "M10 22h4"
1828
+ }
1829
+ },
1830
+ type: "emphasis"
1831
+ }
1832
+ ],
1833
+ warning: [
1834
+ {
1835
+ children: [],
1836
+ data: {
1837
+ hName: "path",
1838
+ hProperties: {
1839
+ d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"
1840
+ }
1841
+ },
1842
+ type: "emphasis"
1843
+ },
1844
+ {
1845
+ children: [],
1846
+ data: {
1847
+ hName: "path",
1848
+ hProperties: {
1849
+ d: "M12 9v4"
1850
+ }
1851
+ },
1852
+ type: "emphasis"
1853
+ },
1854
+ {
1855
+ children: [],
1856
+ data: {
1857
+ hName: "path",
1858
+ hProperties: {
1859
+ d: "M12 17h.01"
1860
+ }
1861
+ },
1862
+ type: "emphasis"
1863
+ }
1864
+ ]
1865
+ };
1866
+ var alertToEmphasis = {
1867
+ caution: "danger",
1868
+ note: "neutral",
1869
+ success: "success",
1870
+ tip: "info",
1871
+ warning: "warning"
1872
+ };
1873
+
1874
+ // src/docs-plugin/internal/services/markdown/remark-remove-code-blocks.ts
1875
+ import { remove } from "unist-util-remove";
1876
+ var remarkRemoveMermaidCodeBlocks = () => {
1877
+ return (tree, _file, done) => {
1878
+ remove(tree, (node) => node.type === "code" && node.lang === "mermaid");
1879
+ done();
1880
+ };
1881
+ };
1882
+
1883
+ // src/docs-plugin/internal/services/markdown/remark-remove-jsx.ts
1884
+ import { remove as remove2 } from "unist-util-remove";
1885
+ var remarkRemoveJsx = () => {
1886
+ return (tree, _file, done) => {
1887
+ remove2(tree, "mdxjsEsm");
1888
+ remove2(tree, "mdxJsxFlowElement");
1889
+ done();
1890
+ };
1891
+ };
1892
+
1893
+ // src/docs-plugin/internal/services/markdown/markdown-indexer.ts
1894
+ var MarkdownIndexer = class {
1895
+ sections = [];
1896
+ currentSection;
1897
+ headingLevels;
1898
+ reset() {
1899
+ this.sections = [];
1900
+ this._toc = [];
1901
+ this.resetSection();
1902
+ }
1903
+ resetSection() {
1904
+ this.currentSection = {
1905
+ content: [],
1906
+ heading: null
1907
+ };
1908
+ }
1909
+ get toc() {
1910
+ return this._toc;
1911
+ }
1912
+ _toc = [];
1913
+ constructor(headingLevels) {
1914
+ this.resetSection();
1915
+ this.headingLevels = headingLevels;
1916
+ }
1917
+ appendTocItem(heading2) {
1918
+ this._toc.push(heading2);
1919
+ }
1920
+ warn(...data) {
1921
+ if (process.env.DEBUG) {
1922
+ console.warn(...data);
1923
+ }
1924
+ console.warn(...data);
1925
+ }
1926
+ isHeading(element) {
1927
+ return this.headingLevels.has(element.tagName);
1928
+ }
1929
+ isRootHeading(element) {
1930
+ return element.tagName === "h1";
1931
+ }
1932
+ /**
1933
+ * Parses a heading Element node into the indexed heading data structure.
1934
+ */
1935
+ parseHeading(headingElement) {
1936
+ const id = headingElement.properties.id;
1937
+ const text = toText(headingElement);
1938
+ return {
1939
+ headingLevel: parseInt(headingElement.tagName.charAt(1)),
1940
+ id: id ? `${id}` : "",
1941
+ tagName: headingElement.tagName,
1942
+ textContent: text
1943
+ };
1944
+ }
1945
+ parseElementNode(element) {
1946
+ const isRootHeading = this.isRootHeading(element);
1947
+ if (this.isHeading(element) || isRootHeading) {
1948
+ const currentSection = this.currentSection;
1949
+ if (currentSection.heading) {
1950
+ this.sections.push(clone(this.currentSection));
1951
+ this.resetSection();
1952
+ }
1953
+ const heading2 = this.parseHeading(element);
1954
+ if (!isRootHeading) {
1955
+ this.appendTocItem(heading2);
1956
+ }
1957
+ this.currentSection.heading = heading2;
1958
+ return;
1959
+ }
1960
+ const text = toText(element, { whitespace: "pre-wrap" }).replaceAll("\n", " ").split(" ").filter(size);
1961
+ if (text.length) {
1962
+ this.currentSection.content.push({
1963
+ tagName: element.tagName,
1964
+ text
1965
+ });
1966
+ }
1967
+ }
1968
+ parseMarkdown(fileContents, frontmatter) {
1969
+ const file = unified3().use(remarkMdx2).use(remarkRemoveJsx).use(remarkRemoveMermaidCodeBlocks).use(remarkParse3).use(remarkGfm).use(remarkAlerts).use(remarkRehype).use(rehypeStringify).processSync(fileContents);
1970
+ let contents = file.toString();
1971
+ contents = contents.substring(contents.indexOf("<h1>"));
1972
+ for (const [key, value] of Object.entries(frontmatter)) {
1973
+ if (typeof value === "string" || typeof value === "number") {
1974
+ contents = contents.replaceAll(`frontmatter.${key}`, `${value}`);
1975
+ }
1976
+ }
1977
+ const htmlAst = unified3().data("settings", { fragment: true }).use(rehypeParse).use(rehypeStringify).use(rehypeSlug).processSync(contents);
1978
+ contents = htmlAst.toString();
1979
+ return this.build(contents);
1980
+ }
1981
+ build(html) {
1982
+ const tree = fromHtml(html, { fragment: true });
1983
+ for (const child of tree.children) {
1984
+ if (child.type === "element") {
1985
+ this.parseElementNode(child);
1986
+ }
1987
+ }
1988
+ if (this.currentSection.heading?.textContent) {
1989
+ this.sections.push(clone(this.currentSection));
1990
+ }
1991
+ return {
1992
+ sections: this.sections,
1993
+ toc: this.toc
1994
+ };
1995
+ }
1996
+ };
1997
+
1998
+ // src/docs-plugin/internal/services/nav-builder/get-route-meta.ts
1999
+ function getRouteMeta(pathSegments, metaJson) {
2000
+ const routeMeta = metaJson[pathSegments[0]];
2001
+ if (!routeMeta) {
2002
+ return void 0;
2003
+ }
2004
+ if (pathSegments.length === 1) {
2005
+ return routeMeta;
2006
+ }
2007
+ return pathSegments.slice(1).reduce((acc, segment) => {
2008
+ return acc?.children?.[segment];
2009
+ }, routeMeta);
2010
+ }
2011
+
2012
+ // src/docs-plugin/internal/services/nav-builder/nav-builder.ts
2013
+ import { capitalCase } from "change-case";
2014
+ import { sortBy } from "lodash-es";
2015
+ import { v4 as uuidv4 } from "uuid";
2016
+ var NavBuilder = class {
2017
+ initialRoutes = [];
2018
+ flatNavItems = [];
2019
+ get navItems() {
2020
+ return this._navItems;
2021
+ }
2022
+ _navItems = [];
2023
+ metaJson;
2024
+ navMeta;
2025
+ constructor(metaJson, navMeta) {
2026
+ this.navMeta = navMeta;
2027
+ this.metaJson = metaJson;
2028
+ }
2029
+ add(pageSection, pageFrontmatter, routeMeta) {
2030
+ this.initialRoutes.push({ pageFrontmatter, pageSection, routeMeta });
2031
+ }
2032
+ reset() {
2033
+ this.initialRoutes = [];
2034
+ this.flatNavItems = [];
2035
+ this._navItems = [];
2036
+ }
2037
+ /**
2038
+ * Sorts nav items. Nav items with an order defined take precedence over nav items
2039
+ * without an order. Nav items with the same order are sorted alphabetically by
2040
+ * title.
2041
+ */
2042
+ navItemSort(a, b, groupOrder) {
2043
+ if (a.depth !== b.depth) {
2044
+ return a.depth - b.depth;
2045
+ }
2046
+ if (a.order && !b.order) {
2047
+ return -1;
2048
+ }
2049
+ if (!a.order && b.order) {
2050
+ return 1;
2051
+ } else if (a.order && b.order && a.order !== b.order) {
2052
+ return a.order - b.order;
2053
+ }
2054
+ if (groupOrder && a.group && b.group) {
2055
+ const aIndex = a.group ? groupOrder.indexOf(a.group) : -1;
2056
+ const bIndex = b.group ? groupOrder.indexOf(b.group) : -1;
2057
+ if (aIndex === bIndex) {
2058
+ } else if (aIndex !== -1 && bIndex !== -1) {
2059
+ return aIndex - bIndex;
2060
+ } else if (aIndex !== -1) {
2061
+ return -1;
2062
+ } else if (bIndex !== -1) {
2063
+ return 1;
2064
+ }
2065
+ }
2066
+ if (a.group !== b.group) {
2067
+ if (!a.group && b.group) {
2068
+ return -1;
2069
+ }
2070
+ if (a.group && !b.group) {
2071
+ return 1;
2072
+ }
2073
+ if (a.group && b.group) {
2074
+ return a.group.localeCompare(b.group);
2075
+ }
2076
+ }
2077
+ return a.title.localeCompare(b.title);
2078
+ }
2079
+ resolveSideNavTitle(frontmatter, routeMeta, fallback) {
2080
+ return (defined(routeMeta.sideNavTitle) ? routeMeta.sideNavTitle || "" : frontmatter.sideNavTitle || "") || fallback;
2081
+ }
2082
+ /**
2083
+ * Builds a flat list of nav items from the MDX pages and _meta.json. If a page
2084
+ * does not exist, it is not added to the side nav (even if it has an entry in
2085
+ * _meta.json).
2086
+ */
2087
+ buildNavItem({
2088
+ pageFrontmatter,
2089
+ pageSection: { pathname, pathSegments, title },
2090
+ routeMeta: routeMetaParam
2091
+ }) {
2092
+ const id = pageFrontmatter?.id || "";
2093
+ if (!pathSegments.length && pathname === "/") {
2094
+ const routeMeta = routeMetaParam || getRouteMeta(id ? [id] : [], this.metaJson);
2095
+ if (!routeMeta) {
2096
+ return;
2097
+ }
2098
+ this.flatNavItems.push({
2099
+ depth: 1,
2100
+ expanded: routeMeta?.expanded || false,
2101
+ id: `/`,
2102
+ order: routeMeta?.order,
2103
+ pathname,
2104
+ pathSegments: [],
2105
+ title: this.resolveSideNavTitle(
2106
+ pageFrontmatter,
2107
+ routeMeta,
2108
+ routeMeta?.title || title
2109
+ )
2110
+ });
2111
+ }
2112
+ pathSegments.forEach((segment, index) => {
2113
+ const depth = index + 1;
2114
+ const navItem = this.flatNavItems.find(
2115
+ (item) => pathSegments.slice(0, depth).every((value, i) => value === item.pathSegments[i])
2116
+ );
2117
+ if (!navItem) {
2118
+ const isPage = index === pathSegments.length - 1;
2119
+ const adjustedSegments = pathSegments.slice(0, depth);
2120
+ const routeMeta = getRouteMeta(
2121
+ isPage ? pathSegments : adjustedSegments,
2122
+ this.metaJson
2123
+ ) ?? {};
2124
+ this.flatNavItems.push({
2125
+ depth,
2126
+ expanded: routeMeta?.expanded || false,
2127
+ group: isPage ? routeMeta.group || pageFrontmatter.group : routeMeta.group,
2128
+ id: `/${adjustedSegments.join("/")}`,
2129
+ items: [],
2130
+ order: routeMeta?.order,
2131
+ pathname: isPage ? pathname : void 0,
2132
+ pathSegments: adjustedSegments,
2133
+ title: this.resolveSideNavTitle(
2134
+ pageFrontmatter,
2135
+ routeMeta,
2136
+ routeMeta?.title ? routeMeta.title : isPage ? title : capitalCase(segment)
2137
+ )
2138
+ });
2139
+ }
2140
+ });
2141
+ }
2142
+ /**
2143
+ * Iterates through a nav item's path segments and ensures that all of its parent
2144
+ * elements exist in the recursive structure.
2145
+ */
2146
+ ensureParent(navItem) {
2147
+ const segments = navItem.pathSegments;
2148
+ let items = this.navItems;
2149
+ let item;
2150
+ let prevItem = void 0;
2151
+ for (let i = 0; i < segments.length - 1; i++) {
2152
+ const segment = segments[i];
2153
+ item = items?.find((entry) => entry.pathSegments[i] === segment);
2154
+ if (item) {
2155
+ items = item.items ?? [];
2156
+ prevItem = item;
2157
+ continue;
2158
+ }
2159
+ if (prevItem) {
2160
+ const pathSegments = segments.slice(0, i + 1);
2161
+ const routeMeta = getRouteMeta(pathSegments, this.metaJson);
2162
+ items = [];
2163
+ const base = {
2164
+ depth: pathSegments.length,
2165
+ id: `/routes/${pathSegments.join("/")}`,
2166
+ items,
2167
+ pathSegments,
2168
+ title: segment
2169
+ };
2170
+ const newItem = routeMeta ? {
2171
+ ...base,
2172
+ expanded: routeMeta.expanded,
2173
+ order: routeMeta.order,
2174
+ restricted: routeMeta.restricted,
2175
+ title: routeMeta.title ?? segment
2176
+ } : base;
2177
+ prevItem.items = prevItem.items ? [...prevItem.items, newItem] : [newItem];
2178
+ }
2179
+ prevItem = item;
2180
+ }
2181
+ }
2182
+ /**
2183
+ * Deeply inserts a nav item into the array, iterating through parent routes
2184
+ * (based on the pathSegments) and adding them if they don't exist.
2185
+ *
2186
+ * For example, given a leaf node 4 path segments deep, this function will create
2187
+ * all parent nav items as nested children of the top-most nav item.
2188
+ */
2189
+ nestedInsert(item, pathSegments, items) {
2190
+ const segment = pathSegments[0];
2191
+ const parentItem = items.find(
2192
+ (parent) => parent.pathSegments[parent.pathSegments.length - 1] === segment
2193
+ );
2194
+ if (parentItem) {
2195
+ this.nestedInsert(item, pathSegments.slice(1), parentItem.items ?? []);
2196
+ } else if (pathSegments.length === 1) {
2197
+ items.push(item);
2198
+ }
2199
+ }
2200
+ buildNestedNavItems() {
2201
+ for (let i = 0; i < this.flatNavItems.length; i++) {
2202
+ const navItem = this.flatNavItems[i];
2203
+ if (navItem.depth === 1) {
2204
+ this.navItems.push(navItem);
2205
+ continue;
2206
+ }
2207
+ this.ensureParent(navItem);
2208
+ this.nestedInsert(navItem, navItem.pathSegments, this.navItems);
2209
+ }
2210
+ }
2211
+ sortNestedNavItems(items, groupOrder) {
2212
+ items.sort((a, b) => this.navItemSort(a, b, groupOrder));
2213
+ items.forEach((item) => {
2214
+ if (item.items?.length) {
2215
+ const meta = getRouteMeta(item.pathSegments, this.metaJson);
2216
+ this.sortNestedNavItems(item.items, meta?.groupOrder);
2217
+ }
2218
+ });
2219
+ }
2220
+ /**
2221
+ * To be called after every mdx page route has been added through the {@link add}
2222
+ * function.
2223
+ */
2224
+ build() {
2225
+ sortBy(
2226
+ this.initialRoutes,
2227
+ (item) => item.pageSection.pathSegments.length
2228
+ ).map((r) => this.buildNavItem(r));
2229
+ this.buildNestedNavItems();
2230
+ const rootMeta = getRouteMeta([], this.metaJson);
2231
+ this.sortNestedNavItems(this.navItems, rootMeta?.groupOrder);
2232
+ if (this.navMeta) {
2233
+ Object.entries(this.navMeta).forEach(([index, value]) => {
2234
+ this._navItems.splice(parseInt(index), 0, {
2235
+ depth: 1,
2236
+ id: uuidv4(),
2237
+ pathSegments: [],
2238
+ sectionTitle: value.sectionTitle,
2239
+ separator: value.separator,
2240
+ title: ""
2241
+ });
2242
+ });
2243
+ }
2244
+ this._navItems = this.groupNavItems(this.navItems);
2245
+ this._navItems = this.buildSearchMeta(this.navItems, []);
2246
+ return this.navItems;
2247
+ }
2248
+ groupNavItems(items) {
2249
+ const result = [];
2250
+ const seenGroups = /* @__PURE__ */ new Set();
2251
+ for (const item of items) {
2252
+ if (item.group && !seenGroups.has(item.group)) {
2253
+ seenGroups.add(item.group);
2254
+ result.push({
2255
+ depth: item.depth,
2256
+ group: item.group,
2257
+ id: uuidv4(),
2258
+ pathSegments: [],
2259
+ sectionTitle: item.group,
2260
+ title: ""
2261
+ });
2262
+ }
2263
+ result.push({
2264
+ ...item,
2265
+ items: item.items ? this.groupNavItems(item.items) : void 0
2266
+ });
2267
+ }
2268
+ return result;
2269
+ }
2270
+ /**
2271
+ * Walks over the tree and builds search metadata using the nearest sectionTitle.
2272
+ */
2273
+ buildSearchMeta(items, meta) {
2274
+ let sectionTitle = "";
2275
+ const results = [];
2276
+ for (const ogItem of items) {
2277
+ const item = { ...ogItem };
2278
+ if (item.sectionTitle) {
2279
+ sectionTitle = item.sectionTitle;
2280
+ } else if (item.separator) {
2281
+ sectionTitle = "";
2282
+ }
2283
+ if (!item.separator) {
2284
+ const currentMeta = sectionTitle ? [...meta, sectionTitle] : [...meta];
2285
+ const nextMeta = [...item.searchMeta || [], ...currentMeta];
2286
+ if (nextMeta.length) {
2287
+ item.searchMeta = [...nextMeta];
2288
+ }
2289
+ if (item.items) {
2290
+ item.items = this.buildSearchMeta(item.items, currentMeta);
2291
+ }
2292
+ }
2293
+ results.push(item);
2294
+ }
2295
+ return results;
2296
+ }
2297
+ };
2298
+
2299
+ // src/docs-plugin/internal/services/nav-builder/page-map.ts
2300
+ import { capitalCase as capitalCase2 } from "change-case";
2301
+ import { join as join2 } from "node:path";
2302
+ function getPathnameFromPathSegments(segments) {
2303
+ return `/${segments.join("/")}`;
2304
+ }
2305
+ function getCategoriesFromPathSegments(segments, metaJson, frontmatterTitle) {
2306
+ return segments.reduce((acc, segment, index) => {
2307
+ const pathSegments = segments.slice(0, index + 1);
2308
+ if (index === segments.length - 1) {
2309
+ acc.push(frontmatterTitle);
2310
+ return acc;
2311
+ }
2312
+ const meta = getRouteMeta(pathSegments, metaJson);
2313
+ if (meta?.title) {
2314
+ acc.push(meta.title);
2315
+ } else {
2316
+ acc.push(pathSegmentToCategory(segment));
2317
+ }
2318
+ return acc;
2319
+ }, []);
2320
+ }
2321
+ function pathSegmentToCategory(segment) {
2322
+ return segment.split("-").map(
2323
+ (segment2) => /\b(a|an|and|but|or|in|on|at)\b/.test(segment2) ? segment2 : capitalCase2(segment2)
2324
+ ).join(" ");
2325
+ }
2326
+ function getGeneroutedPathSegments(filePath) {
2327
+ const extension = filePath.endsWith("mdx") ? "mdx" : "tsx";
2328
+ const segments = filePath.substring(0, filePath.lastIndexOf(`.${extension}`)).split("/");
2329
+ if (segments[segments.length - 1] === "index") {
2330
+ return segments.slice(0, segments.length - 1);
2331
+ }
2332
+ return segments;
2333
+ }
2334
+ var pathSeparatorRegex = /[\/\\.]/;
2335
+ function isPathSeparator(char) {
2336
+ return pathSeparatorRegex.test(char);
2337
+ }
2338
+ var indexRouteRegex = /((^|[.]|[+]\/)(index|_index))(\/[^\/]+)?$|(\/_?index\/)/;
2339
+ function getRemixFlatRoutesSegments(name, index, paramPrefixChar = "$") {
2340
+ let routeSegments = [];
2341
+ let i = 0;
2342
+ let routeSegment = "";
2343
+ let state2 = "START";
2344
+ let subState = "NORMAL";
2345
+ let hasPlus = false;
2346
+ if (name.endsWith("_layout")) {
2347
+ return [];
2348
+ }
2349
+ if (/\+\/_\./.test(name)) {
2350
+ name = name.replace(/\+\/_\./g, "_+/");
2351
+ }
2352
+ if (/\+\//.test(name)) {
2353
+ name = name.replace(/\+\//g, ".");
2354
+ hasPlus = true;
2355
+ }
2356
+ const hasFolder = /\//.test(name);
2357
+ if ((hasPlus && hasFolder || !hasPlus) && !(name.endsWith(".route") || name.endsWith(".index"))) {
2358
+ const last = name.lastIndexOf("/");
2359
+ if (last >= 0) {
2360
+ name = name.substring(0, last);
2361
+ }
2362
+ }
2363
+ const pushRouteSegment = (routeSegment2) => {
2364
+ if (routeSegment2) {
2365
+ routeSegments.push(routeSegment2);
2366
+ }
2367
+ };
2368
+ while (i < name.length) {
2369
+ const char = name[i];
2370
+ switch (state2) {
2371
+ case "START":
2372
+ if (routeSegment.includes(paramPrefixChar) && !(routeSegment.startsWith(paramPrefixChar) || routeSegment.startsWith(`(${paramPrefixChar}`))) {
2373
+ throw new Error(
2374
+ `Route params must start with prefix char ${paramPrefixChar}: ${routeSegment}`
2375
+ );
2376
+ }
2377
+ if (routeSegment.includes("(") && !routeSegment.startsWith("(") && !routeSegment.endsWith(")")) {
2378
+ throw new Error(
2379
+ `Optional routes must start and end with parentheses: ${routeSegment}`
2380
+ );
2381
+ }
2382
+ pushRouteSegment(routeSegment);
2383
+ routeSegment = "";
2384
+ state2 = "PATH";
2385
+ continue;
2386
+ // restart without advancing index
2387
+ case "PATH":
2388
+ if (isPathSeparator(char) && subState === "NORMAL") {
2389
+ state2 = "START";
2390
+ break;
2391
+ } else if (char === "[") {
2392
+ subState = "ESCAPE";
2393
+ break;
2394
+ } else if (char === "]") {
2395
+ subState = "NORMAL";
2396
+ break;
2397
+ }
2398
+ routeSegment += char;
2399
+ break;
2400
+ }
2401
+ i++;
2402
+ }
2403
+ pushRouteSegment(routeSegment);
2404
+ if (routeSegments.at(-1) === "route" || routeSegments.at(-1) === "index" || routeSegments.at(-1) === "_index" || routeSegments.at(-1) === "_route") {
2405
+ routeSegments = routeSegments.slice(0, -1);
2406
+ }
2407
+ if (!index && hasPlus && routeSegments.at(-1)?.startsWith("_")) {
2408
+ routeSegments = routeSegments.slice(0, -1);
2409
+ }
2410
+ return routeSegments;
2411
+ }
2412
+ function getRemixHybridRoutesPathSegments(filePath) {
2413
+ const routeWithoutExtension = filePath.substring(0, filePath.lastIndexOf("."));
2414
+ return getRemixFlatRoutesSegments(
2415
+ routeWithoutExtension,
2416
+ indexRouteRegex.test(routeWithoutExtension)
2417
+ );
2418
+ }
2419
+ function getPathSegmentsFromFileName(filePath, pageDirectory, strategy) {
2420
+ const filePathWithoutPageDirectory = filePath.substring(
2421
+ filePath.indexOf(pageDirectory) + pageDirectory.length + 1
2422
+ );
2423
+ if (typeof strategy === "function") {
2424
+ return strategy(filePathWithoutPageDirectory);
2425
+ }
2426
+ switch (strategy) {
2427
+ case "vite-generouted":
2428
+ return getGeneroutedPathSegments(filePathWithoutPageDirectory);
2429
+ default:
2430
+ return getRemixHybridRoutesPathSegments(filePathWithoutPageDirectory);
2431
+ }
2432
+ }
2433
+ function filterFileGlob(fileGlob, ext, srcDir, router) {
2434
+ if (typeof router === "string" && router === "vite-generouted") {
2435
+ const restrictedPattern = /(\(.*\))|(\[.*\])/;
2436
+ const relativeGlobs = fileGlob.map((file) => file.replace(srcDir, ""));
2437
+ return relativeGlobs.filter(
2438
+ (file) => file.endsWith(`.${ext}`) && !file.includes("/_") && !file.includes("/+")
2439
+ ).map(
2440
+ (file) => file.split("/").filter((segment) => !restrictedPattern.test(segment)).join("/")
2441
+ ).map((file) => join2(srcDir, file));
2442
+ }
2443
+ return fileGlob.filter((file) => file.endsWith(ext) && !file.includes("$"));
2444
+ }
2445
+
2446
+ // src/docs-plugin/internal/transform-route-meta-array.ts
2447
+ function transformRouteMetaArray(meta, routeMetaNav) {
2448
+ let ignoringOrder = 0;
2449
+ return meta.reduce((acc, item, index) => {
2450
+ if (!("id" in item)) {
2451
+ if ("separator" in item || "sectionTitle" in item) {
2452
+ routeMetaNav[index - ignoringOrder] = item;
2453
+ }
2454
+ return acc;
2455
+ }
2456
+ const current = item;
2457
+ if (current.ignoreRouteMetaOrder || current.hidden) {
2458
+ ignoringOrder++;
2459
+ }
2460
+ acc[current.id] = {
2461
+ children: current.children ? transformRouteMetaArray(current.children, routeMetaNav) : void 0,
2462
+ expanded: current.expanded,
2463
+ group: current.group,
2464
+ groupOrder: current.groupOrder,
2465
+ hidden: current.hidden,
2466
+ hideBreadcrumbs: current.hideBreadcrumbs,
2467
+ hideFromSearch: current.hideFromSearch,
2468
+ hidePageLinks: current.hidePageLinks,
2469
+ hideSideNav: current.hideSideNav,
2470
+ hideToc: current.hideToc,
2471
+ order: current.ignoreRouteMetaOrder ? void 0 : index + 1,
2472
+ restricted: current.restricted,
2473
+ title: current.title
2474
+ };
2475
+ return acc;
2476
+ }, {});
2477
+ }
2478
+
2479
+ // src/docs-plugin/internal/search-indexer.ts
2480
+ var SearchIndexer = class {
2481
+ constructor(config, logWarnings = true, addons = {}) {
2482
+ this.config = config;
2483
+ this.logWarnings = logWarnings;
2484
+ this.allowedHeadings = new Set(
2485
+ Array.from(config?.headings || ["h2", "h3", "h4"])
2486
+ );
2487
+ this.metaJson = transformRouteMetaArray(
2488
+ this.config.navConfig ?? [],
2489
+ this.routeMetaNav
2490
+ );
2491
+ this.markdownIndexer = addons.markdownIndexer || new MarkdownIndexer(this.allowedHeadings);
2492
+ this.navBuilder = addons.navBuilder || new NavBuilder(this.metaJson, this.routeMetaNav);
2493
+ this.docPropsIndexer = addons.docPropsIndexer || new DocPropsIndexer(this.config.typeDocProps ?? {});
2494
+ this.fileCache = addons.fileCache || new MarkdownFileReader(
2495
+ process.env.NODE_ENV === "development" && !this.config.disableCache
2496
+ );
2497
+ }
2498
+ docPropsIndexer;
2499
+ markdownIndexer;
2500
+ navBuilder;
2501
+ fileCache;
2502
+ allowedHeadings;
2503
+ metaJson;
2504
+ routeMetaNav = {};
2505
+ get cachedFileCount() {
2506
+ return this.fileCache.cachedFileCount;
2507
+ }
2508
+ get pageDocProps() {
2509
+ return this._pageDocProps;
2510
+ }
2511
+ _pageDocProps = {};
2512
+ get mdxFileCount() {
2513
+ return this._mdxFileCount;
2514
+ }
2515
+ _mdxFileCount = 0;
2516
+ get navItems() {
2517
+ return this.navBuilder.navItems;
2518
+ }
2519
+ get pageMap() {
2520
+ return this._pageMap;
2521
+ }
2522
+ _pageMap = {};
2523
+ get searchIndex() {
2524
+ return this._searchIndex;
2525
+ }
2526
+ _searchIndex = [];
2527
+ reset() {
2528
+ this.fileCache.reset();
2529
+ this._pageMap = {};
2530
+ this._searchIndex = [];
2531
+ }
2532
+ /**
2533
+ * Resolves a page's properties from the combined frontmatter and RouteMeta.
2534
+ * RouteMeta properties take precedence.
2535
+ */
2536
+ getPageEntry(filepath, frontmatter) {
2537
+ const pagePath = filepath.replace(this.config.srcDir, "");
2538
+ const pathSegments = getPathSegmentsFromFileName(
2539
+ pagePath,
2540
+ this.config.pageDirectory,
2541
+ this.config.routingStrategy
2542
+ );
2543
+ const pathname = getPathnameFromPathSegments(pathSegments);
2544
+ const routeMeta = getRouteMeta(
2545
+ pathSegments.length === 0 ? frontmatter.id ? [frontmatter.id] : ["_index"] : pathSegments,
2546
+ this.metaJson
2547
+ ) ?? {};
2548
+ return {
2549
+ categories: frontmatter.categories ?? getCategoriesFromPathSegments(
2550
+ pathSegments,
2551
+ this.metaJson,
2552
+ routeMeta?.title || frontmatter.title || ""
2553
+ ),
2554
+ hidden: defined(routeMeta.hidden) ? routeMeta.hidden : frontmatter.hidden,
2555
+ hideBreadcrumbs: defined(routeMeta.hideBreadcrumbs) ? routeMeta.hideBreadcrumbs : frontmatter.hideBreadcrumbs,
2556
+ hideFromSearch: defined(routeMeta.hideFromSearch) ? routeMeta.hideFromSearch : frontmatter.hideFromSearch,
2557
+ hidePageLinks: defined(routeMeta.hidePageLinks) ? routeMeta.hidePageLinks : frontmatter.hidePageLinks,
2558
+ hideSideNav: defined(routeMeta.hideSideNav) ? routeMeta.hideSideNav : frontmatter.hideSideNav,
2559
+ hideToc: defined(routeMeta.hideToc) ? routeMeta.hideToc : frontmatter.hideToc,
2560
+ id: pagePath,
2561
+ pathname,
2562
+ pathSegments,
2563
+ restricted: defined(routeMeta.restricted) ? routeMeta.restricted : frontmatter.restricted,
2564
+ title: defined(routeMeta.title) ? routeMeta.title || "" : frontmatter.title || ""
2565
+ };
2566
+ }
2567
+ /**
2568
+ * Parses an MDX file to extract the site data for the nav items, doc props,
2569
+ * breadcrumbs, and search index.
2570
+ */
2571
+ compileMdxFile(filepath) {
2572
+ const { cached, fileContents, frontmatter } = this.fileCache.readFile(filepath);
2573
+ this.docPropsIndexer.reset();
2574
+ this.markdownIndexer.reset();
2575
+ const defaultSection = this.getPageEntry(filepath, frontmatter);
2576
+ if (!defaultSection.categories.length && defaultSection.title) {
2577
+ defaultSection.categories = [defaultSection.title];
2578
+ }
2579
+ if (!defaultSection.hidden) {
2580
+ this.navBuilder.add(defaultSection, frontmatter);
2581
+ }
2582
+ this._pageMap[defaultSection.pathname] = defaultSection;
2583
+ let indexedPage;
2584
+ try {
2585
+ indexedPage = cached?.page ? cached.page : this.markdownIndexer.parseMarkdown(fileContents, frontmatter);
2586
+ } catch (error) {
2587
+ console.debug(
2588
+ `${chalk3.yellowBright.bold(
2589
+ "Failed to parse mdx page content."
2590
+ )} ${chalk3.blueBright.bold(filepath)}`
2591
+ );
2592
+ return [defaultSection];
2593
+ }
2594
+ const { sections, toc } = indexedPage;
2595
+ if (toc.length) {
2596
+ this._pageMap[defaultSection.pathname].toc = toc;
2597
+ }
2598
+ let docPropSections = [];
2599
+ let docProps = {};
2600
+ if (this.config.typeDocProps) {
2601
+ docPropSections = cached?.pageDocPropSections || (this.docPropsIndexer.build(fileContents, toc) ?? []);
2602
+ docProps = cached?.pageDocProps || this.docPropsIndexer.getDocProps();
2603
+ }
2604
+ if (docPropSections.length) {
2605
+ this._pageDocProps[defaultSection.pathname] = docProps;
2606
+ }
2607
+ this.fileCache.updateCache(filepath, fileContents, {
2608
+ frontmatter,
2609
+ page: indexedPage,
2610
+ pageDocProps: docProps,
2611
+ pageDocPropSections: docPropSections
2612
+ });
2613
+ if (frontmatter.hideFromSearch) {
2614
+ return [defaultSection];
2615
+ }
2616
+ if (!sections.length && !docPropSections.length) {
2617
+ return [defaultSection];
2618
+ }
2619
+ const sectionReturn = [
2620
+ ...this.formatSections(sections, defaultSection, false)
2621
+ ];
2622
+ if (this.config.typeDocPropsOptions?.includeInSearchIndex) {
2623
+ sectionReturn.push(
2624
+ ...this.formatSections(docPropSections, defaultSection, true)
2625
+ );
2626
+ }
2627
+ return sectionReturn;
2628
+ }
2629
+ formatSections(sections, { toc: _toc, ...defaultSection }, isDocProp) {
2630
+ return sections.map((section, index) => {
2631
+ const content = section.content.map((c) => c.text.join(" ")).join(" ");
2632
+ return {
2633
+ ...defaultSection,
2634
+ content: content || void 0,
2635
+ heading: section.heading?.textContent ?? defaultSection.title,
2636
+ headingLevel: section.heading?.headingLevel,
2637
+ href: section.heading && (this.allowedHeadings.has(section.heading.tagName) || isDocProp) ? `${defaultSection.pathname}#${section.heading.id}` : defaultSection.pathname,
2638
+ id: `${defaultSection.id}-${index}${isDocProp ? "-prop" : ""}`,
2639
+ isDocProp: isDocProp || void 0
2640
+ };
2641
+ });
2642
+ }
2643
+ compileTsxFile(filepath) {
2644
+ const entry = this.getPageEntry(filepath, {});
2645
+ const routeMeta = getRouteMeta(
2646
+ entry.pathSegments.length === 0 ? ["_index"] : entry.pathSegments,
2647
+ this.metaJson
2648
+ );
2649
+ if (!routeMeta) {
2650
+ return null;
2651
+ }
2652
+ if (!entry.hidden) {
2653
+ this.navBuilder.add(entry, {}, routeMeta);
2654
+ }
2655
+ this._pageMap[entry.pathname] = entry;
2656
+ return entry;
2657
+ }
2658
+ buildIndex(inputFileGlob, logWarnings = true) {
2659
+ this.logWarnings = logWarnings;
2660
+ this.fileCache.logWarnings = logWarnings;
2661
+ const fileGlob = inputFileGlob.map(fixPath);
2662
+ this.navBuilder.reset();
2663
+ this.reset();
2664
+ const mdxFileGlob = filterFileGlob(
2665
+ fileGlob,
2666
+ "mdx",
2667
+ this.config.srcDir,
2668
+ this.config.routingStrategy
2669
+ );
2670
+ this._mdxFileCount = mdxFileGlob.length;
2671
+ const mdxIndex = mdxFileGlob.map((file) => this.compileMdxFile(file)).flat();
2672
+ filterFileGlob(
2673
+ fileGlob,
2674
+ "tsx",
2675
+ this.config.srcDir,
2676
+ this.config.routingStrategy
2677
+ ).map((file) => this.compileTsxFile(file));
2678
+ this._searchIndex.push(...mdxIndex.filter((entry) => !entry.hideFromSearch));
2679
+ this.navBuilder.build();
2680
+ }
2681
+ };
2682
+
2683
+ // src/docs-plugin/docs-plugin.ts
2684
+ var isDev = process.env.NODE_ENV === "development";
2685
+ var PluginState = class {
2686
+ buildCount = 0;
2687
+ configFilePath = "";
2688
+ docPropsFilePath = "";
2689
+ indexer;
2690
+ configLoader = null;
2691
+ routesDir;
2692
+ servers = [];
2693
+ timeout = void 0;
2694
+ watching = false;
2695
+ resolvedVirtualModuleId;
2696
+ virtualModuleId = "@qualcomm-ui/mdx-vite-plugin";
2697
+ cwd;
2698
+ constructor() {
2699
+ this.resolvedVirtualModuleId = `\0${this.virtualModuleId}`;
2700
+ }
2701
+ init(cwd) {
2702
+ this.cwd = cwd;
2703
+ }
2704
+ get docPropsDirectory() {
2705
+ if (!this.docPropsFilePath) {
2706
+ return "";
2707
+ }
2708
+ return this.docPropsFilePath.substring(
2709
+ 0,
2710
+ this.docPropsFilePath.lastIndexOf("/")
2711
+ );
2712
+ }
2713
+ resolveDocProps() {
2714
+ if (!this.docPropsFilePath) {
2715
+ return {};
2716
+ }
2717
+ try {
2718
+ return JSON.parse(readFileSync2(this.docPropsFilePath, "utf-8"))?.props;
2719
+ } catch (e) {
2720
+ console.debug(
2721
+ "Invalid doc props file. Unable to parse JSON. Please check the file"
2722
+ );
2723
+ return {};
2724
+ }
2725
+ }
2726
+ createIndexer(config) {
2727
+ this.configFilePath = config.filePath;
2728
+ this.docPropsFilePath = config.typeDocProps ? fixPath(resolve2(this.cwd, config.typeDocProps)) : "";
2729
+ this.routesDir = fixPath(resolve2(config.appDirectory, config.pageDirectory));
2730
+ this.indexer = new SearchIndexer({
2731
+ ...config,
2732
+ srcDir: fixPath(resolve2(this.cwd, config.appDirectory)),
2733
+ typeDocProps: this.resolveDocProps()
2734
+ });
2735
+ }
2736
+ buildIndex(shouldLog) {
2737
+ const files = glob2.sync(
2738
+ [`${this.routesDir}/**/*.mdx`, `${this.routesDir}/**/*.tsx`],
2739
+ {
2740
+ absolute: true,
2741
+ cwd: this.cwd
2742
+ }
2743
+ );
2744
+ if (!files.length) {
2745
+ return;
2746
+ }
2747
+ const startTime = Date.now();
2748
+ this.indexer.buildIndex(files, shouldLog);
2749
+ if (isDev && shouldLog) {
2750
+ console.debug(
2751
+ `${chalk4.magenta.bold(`@qualcomm-ui/mdx-vite/docs-plugin:`)} Compiled search index in: ${chalk4.blueBright.bold(prettyMilliseconds(Date.now() - startTime))}${state.indexer.cachedFileCount ? chalk4.greenBright.bold(` (${state.indexer.cachedFileCount}/${state.indexer.mdxFileCount} files cached)`) : ""}`
2752
+ );
2753
+ }
2754
+ }
2755
+ /**
2756
+ * When the user edits MDX content or modifies the plugin config, we re-index the
2757
+ * site. This function handles module invalidation so that virtual file imports
2758
+ * are refreshed as expected by the consumer's dev server.
2759
+ */
2760
+ sendUpdate() {
2761
+ for (const server of this.servers) {
2762
+ const virtualModule = server.moduleGraph.getModuleById(
2763
+ this.resolvedVirtualModuleId
2764
+ );
2765
+ if (virtualModule) {
2766
+ server.moduleGraph.invalidateModule(virtualModule);
2767
+ server.reloadModule(virtualModule);
2768
+ }
2769
+ }
2770
+ }
2771
+ handleChange(callback) {
2772
+ clearTimeout(this.timeout);
2773
+ this.timeout = setTimeout(() => {
2774
+ this.buildIndex(true);
2775
+ this.sendUpdate();
2776
+ callback?.();
2777
+ }, 300);
2778
+ }
2779
+ initWatchers(configFile) {
2780
+ if (this.watching) {
2781
+ return;
2782
+ }
2783
+ this.initConfigWatcher(configFile);
2784
+ this.watching = true;
2785
+ }
2786
+ initConfigWatcher(configFile) {
2787
+ const paths = [this.configFilePath];
2788
+ if (this.docPropsFilePath) {
2789
+ paths.push(this.docPropsFilePath);
2790
+ }
2791
+ chokidar.watch(paths, {
2792
+ cwd: this.cwd
2793
+ }).on("change", () => {
2794
+ console.debug(`qui-docs config changed, reloading plugin`);
2795
+ this.configLoader = new ConfigLoader({ configFile });
2796
+ const resolvedConfig = this.configLoader.loadConfig();
2797
+ this.configFilePath = resolvedConfig.filePath;
2798
+ this.createIndexer(resolvedConfig);
2799
+ this.handleChange();
2800
+ });
2801
+ }
2802
+ };
2803
+ var state = new PluginState();
2804
+ function quiDocsPlugin(opts) {
2805
+ state.init(fixPath(opts?.cwd ?? process.cwd()));
2806
+ const configLoader = new ConfigLoader(opts || {});
2807
+ const config = configLoader.loadConfig();
2808
+ state.createIndexer(config);
2809
+ return {
2810
+ buildStart: async () => {
2811
+ state.buildIndex(state.buildCount > 0);
2812
+ state.buildCount++;
2813
+ },
2814
+ configureServer: (server) => {
2815
+ if (!isDev) {
2816
+ return;
2817
+ }
2818
+ state.initWatchers(opts?.configFile);
2819
+ server.watcher.on("add", (path) => {
2820
+ if (path.endsWith(".mdx")) {
2821
+ state.handleChange(() => {
2822
+ server.ws.send({ type: "full-reload" });
2823
+ });
2824
+ }
2825
+ });
2826
+ server.watcher.on("unlink", (path) => {
2827
+ if (path.endsWith(".mdx")) {
2828
+ state.handleChange(() => {
2829
+ server.ws.send({ type: "full-reload" });
2830
+ });
2831
+ }
2832
+ });
2833
+ state.servers.push(server);
2834
+ },
2835
+ handleHotUpdate: async ({ file: updateFile }) => {
2836
+ const file = fixPath(updateFile);
2837
+ if ((!config.hotUpdateIgnore || !config.hotUpdateIgnore.test(file)) && // ignore watched files. We watch for these separately.
2838
+ file !== state.configFilePath) {
2839
+ if (state.docPropsDirectory && file.startsWith(state.docPropsFilePath)) {
2840
+ return [];
2841
+ }
2842
+ state.handleChange();
2843
+ }
2844
+ return [];
2845
+ },
2846
+ load: (id) => {
2847
+ if (id === state.resolvedVirtualModuleId) {
2848
+ return `export const siteData = ${JSON.stringify({ navItems: state.indexer.navItems, pageDocProps: state.indexer.pageDocProps, pageMap: state.indexer.pageMap, searchIndex: state.indexer.searchIndex })}`;
2849
+ }
2850
+ return void 0;
2851
+ },
2852
+ name: "qui-mdx-vite-plugin",
2853
+ resolveId: (id) => {
2854
+ if (id === state.virtualModuleId) {
2855
+ return state.resolvedVirtualModuleId;
2856
+ }
2857
+ return void 0;
2858
+ }
2859
+ };
2860
+ }
2861
+
2862
+ // src/docs-plugin/mdx-plugins.ts
2863
+ import rehypeShiki from "@shikijs/rehype";
2864
+ import { quiCustomDarkTheme as quiCustomDarkTheme2 } from "@qualcomm-ui/mdx-common";
2865
+
2866
+ // src/exports.ts
2867
+ import rehypeMdxCodeProps from "rehype-mdx-code-props";
2868
+ import remarkFrontmatter2 from "remark-frontmatter";
2869
+ import remarkGfm2 from "remark-gfm";
2870
+ import remarkMdxFrontmatter from "remark-mdx-frontmatter";
2871
+
2872
+ // src/docs-plugin/rehype/rehype-sectionize.ts
2873
+ import { heading } from "hast-util-heading";
2874
+ import { headingRank as headingRank2 } from "hast-util-heading-rank";
2875
+ var defaultOptions = {
2876
+ enableRootSection: false,
2877
+ idPropertyName: "ariaLabelledby",
2878
+ properties: {},
2879
+ rankPropertyName: "dataHeadingRank"
2880
+ };
2881
+ var wrappingRank = (rootContent, rankPropertyName) => {
2882
+ if (rootContent == null || rankPropertyName == null || !("properties" in rootContent)) {
2883
+ throw new Error("rootContent and rankPropertyName must have value");
2884
+ }
2885
+ const rank = rootContent.properties?.[rankPropertyName];
2886
+ if (typeof rank !== "number") {
2887
+ throw new Error(`rankPropertyName(${rankPropertyName}) must be number`);
2888
+ }
2889
+ return rank;
2890
+ };
2891
+ var createElement = (rank, options, children = []) => {
2892
+ const { idPropertyName, properties, rankPropertyName } = options;
2893
+ if (properties != null && rankPropertyName != null && rankPropertyName in properties) {
2894
+ throw new Error(
2895
+ `rankPropertyName(${rankPropertyName}) dataHeadingRank must exist`
2896
+ );
2897
+ }
2898
+ const id = children.at(0)?.properties?.id;
2899
+ const element = {
2900
+ children,
2901
+ properties: {
2902
+ className: ["heading"],
2903
+ ...rankPropertyName ? { [rankPropertyName]: rank } : {},
2904
+ ...idPropertyName && typeof id === "string" ? { [idPropertyName]: id } : {},
2905
+ ...properties ? properties : {}
2906
+ },
2907
+ tagName: "section",
2908
+ type: "element"
2909
+ };
2910
+ return element;
2911
+ };
2912
+ var rehypeSectionize = (options = defaultOptions) => {
2913
+ const { enableRootSection, ...rest } = {
2914
+ enableRootSection: options.enableRootSection ?? defaultOptions.enableRootSection,
2915
+ idPropertyName: options.idPropertyName ?? defaultOptions.idPropertyName,
2916
+ properties: options.properties ?? defaultOptions.properties,
2917
+ rankPropertyName: options.rankPropertyName ?? defaultOptions.rankPropertyName
2918
+ };
2919
+ return (root) => {
2920
+ const rootWrapper = createElement(0, rest);
2921
+ const wrapperStack = [];
2922
+ wrapperStack.push(rootWrapper);
2923
+ const lastStackItem = () => {
2924
+ const last = wrapperStack.at(-1);
2925
+ if (last == null || last.type !== "element") {
2926
+ throw new Error("lastStackItem must be Element");
2927
+ }
2928
+ return wrapperStack.at(-1);
2929
+ };
2930
+ for (const rootContent of root.children) {
2931
+ if (heading(rootContent)) {
2932
+ const rank = headingRank2(rootContent);
2933
+ if (rank == null) {
2934
+ throw new Error("heading or headingRank is not working");
2935
+ }
2936
+ if (rank > wrappingRank(lastStackItem(), rest.rankPropertyName)) {
2937
+ const childWrapper = createElement(rank, rest, [rootContent]);
2938
+ lastStackItem().children.push(childWrapper);
2939
+ wrapperStack.push(childWrapper);
2940
+ } else if (rank <= wrappingRank(lastStackItem(), rest.rankPropertyName)) {
2941
+ while (rank <= wrappingRank(lastStackItem(), rest.rankPropertyName)) {
2942
+ wrapperStack.pop();
2943
+ }
2944
+ const siblingWrapper = createElement(rank, rest, [rootContent]);
2945
+ lastStackItem().children.push(siblingWrapper);
2946
+ wrapperStack.push(siblingWrapper);
2947
+ }
2948
+ } else {
2949
+ if (rootContent.type === "doctype") {
2950
+ throw new Error("must be used in a fragment");
2951
+ }
2952
+ lastStackItem().children.push(rootContent);
2953
+ }
2954
+ }
2955
+ return {
2956
+ ...root,
2957
+ children: enableRootSection ? [rootWrapper] : rootWrapper.children
2958
+ };
2959
+ };
2960
+ };
2961
+
2962
+ // src/docs-plugin/remark/remark-code-tabs.ts
2963
+ import { visit as visit4 } from "unist-util-visit";
2964
+ function parseTabAttributes(meta) {
2965
+ if (!meta) {
2966
+ return { label: null, remainingMeta: "", tabsGroup: null };
2967
+ }
2968
+ const tabsMatch = meta.match(/tabs=["']([^"']+)["']|tabs=(\S+)/);
2969
+ const labelMatch = meta.match(/label=["']([^"']+)["']|label=(\S+)/);
2970
+ const tabsGroup = tabsMatch ? tabsMatch[1] || tabsMatch[2] : null;
2971
+ const label = labelMatch ? labelMatch[1] || labelMatch[2] : null;
2972
+ const remainingMeta = meta.replace(/\s*tabs=["']([^"']+)["']/g, "").replace(/\s*tabs=(\S+)/g, "").replace(/\s*label=["']([^"']+)["']/g, "").replace(/\s*label=(\S+)/g, "").trim();
2973
+ return { label, remainingMeta, tabsGroup };
2974
+ }
2975
+ function findConsecutiveTabs(startIndex, parent, targetTabsGroup) {
2976
+ const tabs = [];
2977
+ let currentIndex = startIndex;
2978
+ while (currentIndex < parent.children.length) {
2979
+ const currentNode = parent.children[currentIndex];
2980
+ if (!currentNode || currentNode.type !== "code") {
2981
+ break;
2982
+ }
2983
+ const codeNode = currentNode;
2984
+ if (!codeNode.meta) {
2985
+ break;
2986
+ }
2987
+ const { label, remainingMeta, tabsGroup } = parseTabAttributes(codeNode.meta);
2988
+ if (!tabsGroup || !label || tabsGroup !== targetTabsGroup) {
2989
+ break;
2990
+ }
2991
+ codeNode.meta = remainingMeta || void 0;
2992
+ tabs.push({
2993
+ index: currentIndex,
2994
+ label,
2995
+ meta: remainingMeta || void 0,
2996
+ tabsGroup
2997
+ });
2998
+ if (remainingMeta && remainingMeta.includes("end")) {
2999
+ break;
3000
+ }
3001
+ currentIndex++;
3002
+ }
3003
+ return tabs;
3004
+ }
3005
+ function renderTabs(tabs, parent) {
3006
+ const tabsContainer = {
3007
+ attributes: [],
3008
+ children: [],
3009
+ name: "CodeTabs",
3010
+ type: "mdxJsxFlowElement"
3011
+ };
3012
+ tabs.forEach((tab) => {
3013
+ const codeNode = parent.children[tab.index];
3014
+ const tabAttributes = [
3015
+ {
3016
+ name: "label",
3017
+ type: "mdxJsxAttribute",
3018
+ value: tab.label
3019
+ }
3020
+ ];
3021
+ if (tab.meta) {
3022
+ tabAttributes.push({
3023
+ name: "meta",
3024
+ type: "mdxJsxAttribute",
3025
+ value: tab.meta
3026
+ });
3027
+ }
3028
+ const tabElement = {
3029
+ attributes: tabAttributes,
3030
+ children: [
3031
+ {
3032
+ lang: codeNode.lang,
3033
+ meta: codeNode.meta,
3034
+ // This is now clean
3035
+ type: "code",
3036
+ value: codeNode.value
3037
+ }
3038
+ ],
3039
+ name: "CodeTab",
3040
+ type: "mdxJsxFlowElement"
3041
+ };
3042
+ tabsContainer.children.push(tabElement);
3043
+ });
3044
+ return [tabsContainer];
3045
+ }
3046
+ var remarkCodeTabs = () => {
3047
+ return (tree) => {
3048
+ const transformations = [];
3049
+ visit4(
3050
+ tree,
3051
+ "code",
3052
+ (node, index, parent) => {
3053
+ if (!node.meta || !parent || index === void 0) {
3054
+ return;
3055
+ }
3056
+ const { label, tabsGroup } = parseTabAttributes(node.meta);
3057
+ if (!tabsGroup || !label) {
3058
+ return;
3059
+ }
3060
+ const alreadyProcessed = transformations.some(
3061
+ (t) => t.parent === parent && index >= t.startIndex && index < t.endIndex
3062
+ );
3063
+ if (alreadyProcessed) {
3064
+ return;
3065
+ }
3066
+ const tabs = findConsecutiveTabs(index, parent, tabsGroup);
3067
+ if (tabs.length > 1) {
3068
+ const startIndex = tabs[0].index;
3069
+ const endIndex = tabs[tabs.length - 1].index + 1;
3070
+ const newChildren = renderTabs(tabs, parent);
3071
+ transformations.push({
3072
+ endIndex,
3073
+ parent,
3074
+ replacement: newChildren,
3075
+ startIndex
3076
+ });
3077
+ }
3078
+ }
3079
+ );
3080
+ transformations.sort((a, b) => b.startIndex - a.startIndex).forEach((transformation) => {
3081
+ transformation.parent.children.splice(
3082
+ transformation.startIndex,
3083
+ transformation.endIndex - transformation.startIndex,
3084
+ ...transformation.replacement
3085
+ );
3086
+ });
3087
+ };
3088
+ };
3089
+
3090
+ // src/docs-plugin/remark/remark-self-link-headings.ts
3091
+ import { toString as toString2 } from "mdast-util-to-string";
3092
+ import { visit as visit5 } from "unist-util-visit";
3093
+ var emptyOptions2 = {};
3094
+ function remarkSelfLinkHeadings(baseUrl = "", options) {
3095
+ if (!baseUrl) {
3096
+ return () => {
3097
+ };
3098
+ }
3099
+ return () => {
3100
+ const settings = options || emptyOptions2;
3101
+ const prefix = settings.prefix || "";
3102
+ const allowedLevels = new Set(settings.allowedLevels || [2, 3, 4]);
3103
+ const seenIds = /* @__PURE__ */ new Map();
3104
+ function createSlug(text) {
3105
+ const cleaned = text.replace(/[<>]/g, "").replace(/[^\w\s-]/g, "").trim();
3106
+ let slug;
3107
+ if (cleaned.includes(" ")) {
3108
+ slug = cleaned.toLowerCase().replace(/\s+/g, "-").replace(/^-+|-+$/g, "");
3109
+ } else if ((cleaned.match(/[A-Z]/g) || []).length >= 2) {
3110
+ slug = cleaned.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").toLowerCase();
3111
+ } else {
3112
+ slug = cleaned.toLowerCase();
3113
+ }
3114
+ const count = seenIds.get(slug) || 0;
3115
+ seenIds.set(slug, count + 1);
3116
+ return count > 0 ? `${slug}-${count}` : slug;
3117
+ }
3118
+ return (tree) => {
3119
+ seenIds.clear();
3120
+ visit5(tree, "heading", (node) => {
3121
+ if (allowedLevels.has(node.depth)) {
3122
+ const text = toString2(node);
3123
+ const slug = prefix + createSlug(text);
3124
+ const linkNode = {
3125
+ children: node.children,
3126
+ type: "link",
3127
+ url: `${baseUrl}#${slug}`
3128
+ };
3129
+ node.children = [linkNode];
3130
+ }
3131
+ });
3132
+ };
3133
+ };
3134
+ }
3135
+
3136
+ // src/docs-plugin/remark/remark-spoilers.ts
3137
+ import { visit as visit6 } from "unist-util-visit";
3138
+ var remarkSpoilers = (options = {}) => {
3139
+ const {
3140
+ defaultSummary = "Open spoiler",
3141
+ detailsClassName = [],
3142
+ summaryClassName = []
3143
+ } = options;
3144
+ return (tree) => {
3145
+ visit6(tree, "paragraph", (node, index, parent) => {
3146
+ if (!parent || index === void 0) {
3147
+ return;
3148
+ }
3149
+ const firstChild = node.children[0];
3150
+ if (firstChild?.type !== "text") {
3151
+ return;
3152
+ }
3153
+ const match = firstChild.value.match(/^:::\s*spoiler\s*(.*)$/);
3154
+ if (!match) {
3155
+ return;
3156
+ }
3157
+ const summary = match[1].trim() || defaultSummary;
3158
+ let endIndex = index + 1;
3159
+ const contentNodes = [];
3160
+ while (endIndex < parent.children.length) {
3161
+ const child = parent.children[endIndex];
3162
+ if (child.type === "paragraph") {
3163
+ const firstText = child.children[0];
3164
+ if (firstText?.type === "text" && firstText.value.trim() === ":::") {
3165
+ break;
3166
+ }
3167
+ }
3168
+ contentNodes.push(child);
3169
+ endIndex++;
3170
+ }
3171
+ if (endIndex >= parent.children.length) {
3172
+ return;
3173
+ }
3174
+ const summaryNode = {
3175
+ attributes: summaryClassName.length ? [
3176
+ {
3177
+ name: "className",
3178
+ type: "mdxJsxAttribute",
3179
+ value: summaryClassName.join(" ")
3180
+ }
3181
+ ] : [],
3182
+ children: [
3183
+ {
3184
+ children: [{ type: "text", value: summary }],
3185
+ type: "paragraph"
3186
+ }
3187
+ ],
3188
+ name: "SpoilerSummary",
3189
+ type: "mdxJsxFlowElement"
3190
+ };
3191
+ const contentNode = {
3192
+ attributes: [],
3193
+ children: contentNodes,
3194
+ name: "SpoilerContent",
3195
+ type: "mdxJsxFlowElement"
3196
+ };
3197
+ const detailsNode = {
3198
+ attributes: detailsClassName.length ? [
3199
+ {
3200
+ name: "className",
3201
+ type: "mdxJsxAttribute",
3202
+ value: detailsClassName.join(" ")
3203
+ }
3204
+ ] : [],
3205
+ children: [summaryNode, contentNode],
3206
+ name: "SpoilerRoot",
3207
+ type: "mdxJsxFlowElement"
3208
+ };
3209
+ parent.children.splice(index, endIndex - index + 1, detailsNode);
3210
+ });
3211
+ };
3212
+ };
3213
+
3214
+ // src/docs-plugin/mdx-plugins.ts
3215
+ var quiRehypePlugins = [rehypeSectionize, rehypeSlug];
3216
+ function getRehypePlugins(options = {}) {
3217
+ const config = new ConfigLoader(options).loadConfig();
3218
+ return [
3219
+ rehypeMdxCodeProps,
3220
+ [
3221
+ rehypeSlug,
3222
+ { allowedHeadings: config.headings }
3223
+ ],
3224
+ rehypeSectionize,
3225
+ [
3226
+ rehypeShiki,
3227
+ {
3228
+ defaultColor: "light-dark()",
3229
+ themes: {
3230
+ dark: quiCustomDarkTheme2,
3231
+ light: "github-light-high-contrast"
3232
+ },
3233
+ ...options.rehypeShikiOptions
3234
+ }
3235
+ ]
3236
+ ];
3237
+ }
3238
+ var quiRemarkPlugins = [remarkAlerts, remarkCodeTabs];
3239
+ function getRemarkPlugins() {
3240
+ return [
3241
+ remarkFrontmatter2,
3242
+ remarkMdxFrontmatter,
3243
+ remarkGfm2,
3244
+ remarkAlerts,
3245
+ remarkCodeTabs,
3246
+ remarkSpoilers
3247
+ ];
3248
+ }
3249
+
3250
+ // src/react-demo-plugin/demo-plugin-constants.ts
3251
+ var VIRTUAL_MODULE_IDS = {
3252
+ AUTO: "\0virtual:qui-demo-scope/auto",
3253
+ CONFIG: "\0virtual:qui-demo-scope/config",
3254
+ PAGE_PREFIX: "\0virtual:qui-demo-scope/page:"
3255
+ };
3256
+ var LOG_PREFIX2 = "@qualcomm-ui/mdx-vite/react-demo-plugin:";
3257
+ var REACT_IMPORTS = [
3258
+ "useState",
3259
+ "useEffect",
3260
+ "useMemo",
3261
+ "useCallback",
3262
+ "useRef",
3263
+ "useContext",
3264
+ "createContext",
3265
+ "forwardRef",
3266
+ "memo",
3267
+ "lazy",
3268
+ "Suspense",
3269
+ "Fragment"
3270
+ ];
3271
+ var NODE_BUILTINS = [
3272
+ "fs",
3273
+ "path",
3274
+ "url",
3275
+ "util",
3276
+ "os",
3277
+ "crypto",
3278
+ "events",
3279
+ "stream",
3280
+ "buffer"
3281
+ ];
3282
+
3283
+ // src/react-demo-plugin/demo-plugin-utils.ts
3284
+ import chalk5 from "chalk";
3285
+ import { createHash as createHash2 } from "node:crypto";
3286
+ import { existsSync as existsSync2, readFileSync as readFileSync3 } from "node:fs";
3287
+ import { readFile as readFile2 } from "node:fs/promises";
3288
+ import { dirname as dirname2, join as join3, relative as relative2, resolve as resolve3, sep } from "node:path";
3289
+ import * as ts2 from "typescript";
3290
+ import { pascalCase } from "@qualcomm-ui/utils/change-case";
3291
+ function createDemoName(filePath) {
3292
+ const separatorChar = filePath.includes("/") ? "/" : "\\";
3293
+ const fileName = filePath.substring(
3294
+ filePath.lastIndexOf(separatorChar),
3295
+ filePath.lastIndexOf(".")
3296
+ );
3297
+ if (!fileName) {
3298
+ throw new Error(`Failed to create demo name for ${filePath}`);
3299
+ }
3300
+ return pascalCase(fileName);
3301
+ }
3302
+ async function extractFileImports(filePath) {
3303
+ try {
3304
+ const content = await readFile2(filePath, "utf-8");
3305
+ return extractImports(content, filePath);
3306
+ } catch (error) {
3307
+ console.log(
3308
+ `${chalk5.magenta.bold(LOG_PREFIX2)} ${chalk5.yellowBright("Failed to parse")} ${chalk5.blueBright.bold(filePath)}:`,
3309
+ error
3310
+ );
3311
+ return null;
3312
+ }
3313
+ }
3314
+ function mergeImports(importMap, imports) {
3315
+ for (const { source, specifiers } of imports) {
3316
+ if (isNodeBuiltin(source)) {
3317
+ continue;
3318
+ }
3319
+ let sourceSpecifiers = importMap.get(source);
3320
+ if (!sourceSpecifiers) {
3321
+ sourceSpecifiers = /* @__PURE__ */ new Set();
3322
+ importMap.set(source, sourceSpecifiers);
3323
+ }
3324
+ for (const spec of specifiers) {
3325
+ sourceSpecifiers.add(spec);
3326
+ }
3327
+ }
3328
+ }
3329
+ function extractImports(code, fileName) {
3330
+ const sourceFile = ts2.createSourceFile(
3331
+ fileName,
3332
+ code,
3333
+ ts2.ScriptTarget.Latest,
3334
+ true,
3335
+ getScriptKind(fileName)
3336
+ );
3337
+ const thirdPartyImports = [];
3338
+ const relativeImports = [];
3339
+ function visit7(node) {
3340
+ if (ts2.isImportDeclaration(node)) {
3341
+ const importSpec = parseImportDeclaration(node, fileName);
3342
+ if (importSpec) {
3343
+ if (importSpec.type === "relative") {
3344
+ relativeImports.push(importSpec);
3345
+ } else {
3346
+ thirdPartyImports.push(importSpec);
3347
+ }
3348
+ }
3349
+ }
3350
+ ts2.forEachChild(node, visit7);
3351
+ }
3352
+ visit7(sourceFile);
3353
+ return { relativeImports, thirdPartyImports };
3354
+ }
3355
+ function getScriptKind(fileName) {
3356
+ return fileName.endsWith(".tsx") || fileName.endsWith(".jsx") ? ts2.ScriptKind.TSX : ts2.ScriptKind.TS;
3357
+ }
3358
+ function parseImportDeclaration(node, fileName) {
3359
+ const moduleSpecifier = node.moduleSpecifier;
3360
+ if (!ts2.isStringLiteral(moduleSpecifier)) {
3361
+ return null;
3362
+ }
3363
+ const source = moduleSpecifier.text;
3364
+ if (node.importClause?.isTypeOnly) {
3365
+ return null;
3366
+ }
3367
+ const specifiers = extractSpecifiers(node.importClause);
3368
+ if (specifiers.length === 0) {
3369
+ return null;
3370
+ }
3371
+ if (isRelativeImport(source)) {
3372
+ const resolvedPath = resolveRelativeImport(source, fileName);
3373
+ return {
3374
+ resolvedPath,
3375
+ source,
3376
+ specifiers,
3377
+ type: "relative"
3378
+ };
3379
+ }
3380
+ if (isNodeBuiltin(source)) {
3381
+ return null;
3382
+ }
3383
+ const pathAliases = loadTsConfigPaths(fileName);
3384
+ if (isPathAliasImport2(source, pathAliases)) {
3385
+ const resolvedPath = resolvePathAlias2(source, pathAliases);
3386
+ if (resolvedPath) {
3387
+ return {
3388
+ resolvedPath,
3389
+ source,
3390
+ specifiers,
3391
+ type: "relative"
3392
+ };
3393
+ }
3394
+ }
3395
+ return {
3396
+ source,
3397
+ specifiers,
3398
+ type: "thirdParty"
3399
+ };
3400
+ }
3401
+ function extractSpecifiers(importClause) {
3402
+ if (!importClause) {
3403
+ return [];
3404
+ }
3405
+ const specifiers = [];
3406
+ if (importClause.name) {
3407
+ specifiers.push({ imported: "default", local: "default" });
3408
+ }
3409
+ if (importClause.namedBindings) {
3410
+ if (ts2.isNamespaceImport(importClause.namedBindings)) {
3411
+ specifiers.push({ imported: "*", local: "*" });
3412
+ } else if (ts2.isNamedImports(importClause.namedBindings)) {
3413
+ importClause.namedBindings.elements.forEach((element) => {
3414
+ if (!element.isTypeOnly) {
3415
+ const imported = element.propertyName ? element.propertyName.text : element.name.text;
3416
+ const local = element.name.text;
3417
+ specifiers.push({ imported, local });
3418
+ }
3419
+ });
3420
+ }
3421
+ }
3422
+ return specifiers;
3423
+ }
3424
+ function resolveRelativeImport(source, fromFile) {
3425
+ const fromDir = dirname2(fromFile);
3426
+ const resolved = resolve3(fromDir, source);
3427
+ const extensions = [".ts", ".tsx", ".js", ".jsx"];
3428
+ for (const ext of extensions) {
3429
+ const withExt = resolved + ext;
3430
+ if (existsSync2(withExt)) {
3431
+ return withExt;
3432
+ }
3433
+ }
3434
+ for (const ext of extensions) {
3435
+ const indexFile = join3(resolved, `index${ext}`);
3436
+ if (existsSync2(indexFile)) {
3437
+ return indexFile;
3438
+ }
3439
+ }
3440
+ return resolved;
3441
+ }
3442
+ async function extractAllImports(files) {
3443
+ const importMap = /* @__PURE__ */ new Map();
3444
+ const relativeImports = [];
3445
+ for (const filePath of files) {
3446
+ const result = await extractFileImports(filePath);
3447
+ if (result) {
3448
+ mergeImports(importMap, result.thirdPartyImports);
3449
+ relativeImports.push(...result.relativeImports);
3450
+ }
3451
+ }
3452
+ return { importMap, relativeImports };
3453
+ }
3454
+ function isRelativeImport(source) {
3455
+ return source.startsWith("./") || source.startsWith("../");
3456
+ }
3457
+ function isNodeBuiltin(source) {
3458
+ return source.startsWith("node:") || NODE_BUILTINS.includes(source);
3459
+ }
3460
+ function loadTsConfigPaths(fromFile) {
3461
+ let currentDir = dirname2(fromFile);
3462
+ const pathAliases = [];
3463
+ while (currentDir !== dirname2(currentDir)) {
3464
+ const tsconfigPath = join3(currentDir, "tsconfig.json");
3465
+ if (existsSync2(tsconfigPath)) {
3466
+ try {
3467
+ const configContent = ts2.sys.readFile(tsconfigPath);
3468
+ if (!configContent) {
3469
+ currentDir = dirname2(currentDir);
3470
+ continue;
3471
+ }
3472
+ const parseResult = ts2.parseConfigFileTextToJson(
3473
+ tsconfigPath,
3474
+ configContent
3475
+ );
3476
+ if (parseResult.error) {
3477
+ currentDir = dirname2(currentDir);
3478
+ continue;
3479
+ }
3480
+ const paths = parseResult.config?.compilerOptions?.paths;
3481
+ const baseUrl = parseResult.config?.compilerOptions?.baseUrl || "./";
3482
+ const resolvedBaseUrl = resolve3(currentDir, baseUrl);
3483
+ if (paths) {
3484
+ for (const [alias, targets] of Object.entries(paths)) {
3485
+ if (Array.isArray(targets) && targets.length > 0) {
3486
+ const target = targets[0];
3487
+ const pattern = new RegExp(
3488
+ `^${alias.replace("*", "(.*)").replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\(\\*\\)", "(.*)")}$`
3489
+ );
3490
+ const replacement = resolve3(
3491
+ resolvedBaseUrl,
3492
+ target.replace("*", "$1")
3493
+ );
3494
+ pathAliases.push({ pattern, replacement });
3495
+ }
3496
+ }
3497
+ }
3498
+ const extendsPath = parseResult.config?.extends;
3499
+ if (extendsPath) {
3500
+ const resolvedExtends = resolve3(currentDir, extendsPath);
3501
+ const extendedAliases = loadTsConfigPathsFromFile2(resolvedExtends);
3502
+ pathAliases.push(...extendedAliases);
3503
+ }
3504
+ return pathAliases;
3505
+ } catch (error) {
3506
+ currentDir = dirname2(currentDir);
3507
+ continue;
3508
+ }
3509
+ }
3510
+ currentDir = dirname2(currentDir);
3511
+ }
3512
+ return pathAliases;
3513
+ }
3514
+ function loadTsConfigPathsFromFile2(tsconfigPath) {
3515
+ const pathAliases = [];
3516
+ const configDir = dirname2(tsconfigPath);
3517
+ try {
3518
+ const configContent = ts2.sys.readFile(tsconfigPath);
3519
+ if (!configContent) {
3520
+ return pathAliases;
3521
+ }
3522
+ const parseResult = ts2.parseConfigFileTextToJson(
3523
+ tsconfigPath,
3524
+ configContent
3525
+ );
3526
+ if (parseResult.error) {
3527
+ return pathAliases;
3528
+ }
3529
+ const paths = parseResult.config?.compilerOptions?.paths;
3530
+ const baseUrl = parseResult.config?.compilerOptions?.baseUrl || "./";
3531
+ const resolvedBaseUrl = resolve3(configDir, baseUrl);
3532
+ if (paths) {
3533
+ for (const [alias, targets] of Object.entries(paths)) {
3534
+ if (Array.isArray(targets) && targets.length > 0) {
3535
+ const target = targets[0];
3536
+ const pattern = new RegExp(
3537
+ `^${alias.replace("*", "(.*)").replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\(\\*\\)", "(.*)")}$`
3538
+ );
3539
+ const replacement = resolve3(
3540
+ resolvedBaseUrl,
3541
+ target.replace("*", "$1")
3542
+ );
3543
+ pathAliases.push({ pattern, replacement });
3544
+ }
3545
+ }
3546
+ }
3547
+ const extendsPath = parseResult.config?.extends;
3548
+ if (extendsPath) {
3549
+ let resolvedExtends = resolve3(configDir, extendsPath);
3550
+ if (!resolvedExtends.endsWith(".json")) {
3551
+ resolvedExtends += ".json";
3552
+ }
3553
+ if (existsSync2(resolvedExtends)) {
3554
+ const extendedAliases = loadTsConfigPathsFromFile2(resolvedExtends);
3555
+ pathAliases.push(...extendedAliases);
3556
+ }
3557
+ }
3558
+ } catch (error) {
3559
+ return pathAliases;
3560
+ }
3561
+ return pathAliases;
3562
+ }
3563
+ function isPathAliasImport2(source, pathAliases) {
3564
+ return pathAliases.some((alias) => alias.pattern.test(source));
3565
+ }
3566
+ function resolvePathAlias2(source, pathAliases) {
3567
+ for (const alias of pathAliases) {
3568
+ if (alias.pattern.test(source)) {
3569
+ const resolvedPath = source.replace(alias.pattern, alias.replacement);
3570
+ const extensions = [".ts", ".tsx", ".js", ".jsx"];
3571
+ for (const ext of extensions) {
3572
+ const withExt = resolvedPath + ext;
3573
+ if (existsSync2(withExt)) {
3574
+ return withExt;
3575
+ }
3576
+ }
3577
+ for (const ext of extensions) {
3578
+ const indexFile = join3(resolvedPath, `index${ext}`);
3579
+ if (existsSync2(indexFile)) {
3580
+ return indexFile;
3581
+ }
3582
+ }
3583
+ return resolvedPath;
3584
+ }
3585
+ }
3586
+ return null;
3587
+ }
3588
+ function sanitizeSourceName(source) {
3589
+ return source.replace(/@/g, "at_").replace(/\//g, "_").replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
3590
+ }
3591
+ function sanitizeIdentifier(str) {
3592
+ return str.replace(/[^a-zA-Z0-9]/g, "_");
3593
+ }
3594
+ function createUniqueModuleName(source) {
3595
+ const hash = createHash2("sha256").update(source).digest("hex").substring(0, 8);
3596
+ const baseName = source.split("/").pop()?.replace(/[^a-zA-Z0-9]/g, "_")?.replace(/^_+|_+$/g, "")?.replace(/^(\d)/, "_$1") || "module";
3597
+ return `mod_${baseName}_${hash}`;
3598
+ }
3599
+ function addReactImports(imports, scopeEntries) {
3600
+ imports.push(`import React from "react"`);
3601
+ imports.push(`import {
3602
+ ${REACT_IMPORTS.join(", ")}
3603
+ } from "react"`);
3604
+ scopeEntries.push("React", ...REACT_IMPORTS);
3605
+ }
3606
+ function addThirdPartyImports(importMap, imports, scopeEntries) {
3607
+ const sortedImports = Array.from(importMap.entries()).sort(
3608
+ ([a], [b]) => a.localeCompare(b)
3609
+ );
3610
+ const usedNames = /* @__PURE__ */ new Set(["React", ...REACT_IMPORTS]);
3611
+ for (const [source, specifiers] of sortedImports) {
3612
+ const moduleName = createUniqueModuleName(source);
3613
+ imports.push(`import * as ${moduleName} from "${source}"`);
3614
+ addModuleToScope(source, specifiers, moduleName, scopeEntries, usedNames);
3615
+ }
3616
+ }
3617
+ function addThirdPartyImportsNamespaced(importMap, imports, scopeEntries, demoName) {
3618
+ const sortedImports = Array.from(importMap.entries()).sort(
3619
+ ([a], [b]) => a.localeCompare(b)
3620
+ );
3621
+ const usedNames = /* @__PURE__ */ new Set(["React", ...REACT_IMPORTS]);
3622
+ for (const [source, specifiers] of sortedImports) {
3623
+ const moduleName = `${sanitizeIdentifier(demoName)}_${createUniqueModuleName(source)}`;
3624
+ imports.push(`import * as ${moduleName} from "${source}"`);
3625
+ addModuleToScope(source, specifiers, moduleName, scopeEntries, usedNames);
3626
+ }
3627
+ }
3628
+ function addRelativeImportsNamespaced(relativeImports, imports, scopeEntries, demoName) {
3629
+ const processedPaths = /* @__PURE__ */ new Set();
3630
+ for (const { resolvedPath, specifiers } of relativeImports) {
3631
+ if (processedPaths.has(resolvedPath)) {
3632
+ continue;
3633
+ }
3634
+ processedPaths.add(resolvedPath);
3635
+ const moduleName = `${sanitizeIdentifier(demoName)}_${createUniqueModuleName(resolvedPath)}`;
3636
+ imports.push(`import * as ${moduleName} from "${resolvedPath}"`);
3637
+ for (const { imported, local } of specifiers) {
3638
+ if (imported === "default") {
3639
+ scopeEntries.push(`${local}: ${moduleName}.default`);
3640
+ } else if (imported === "*") {
3641
+ scopeEntries.push(`...${moduleName}`);
3642
+ } else {
3643
+ scopeEntries.push(`${local}: ${moduleName}.${imported}`);
3644
+ }
3645
+ }
3646
+ }
3647
+ }
3648
+ function addModuleToScope(source, specifiers, moduleName, scopeEntries, usedNames) {
3649
+ const specArray = Array.from(specifiers);
3650
+ const hasDefault = specArray.some((spec) => spec.imported === "default");
3651
+ const hasNamespace = specArray.some((spec) => spec.imported === "*");
3652
+ const namedImports = specArray.filter(
3653
+ (spec) => spec.imported !== "default" && spec.imported !== "*"
3654
+ );
3655
+ if (hasNamespace) {
3656
+ scopeEntries.push(`...${moduleName}`);
3657
+ return;
3658
+ }
3659
+ const sanitizedSource = sanitizeSourceName(source);
3660
+ if (hasDefault) {
3661
+ scopeEntries.push(`"${sanitizedSource}__default": ${moduleName}.default`);
3662
+ }
3663
+ for (const { imported, local } of namedImports) {
3664
+ const sanitizedKey = `${sanitizedSource}__${imported}`;
3665
+ scopeEntries.push(`"${sanitizedKey}": ${moduleName}.${imported}`);
3666
+ if (!usedNames.has(local)) {
3667
+ scopeEntries.push(`${local}: ${moduleName}.${imported}`);
3668
+ usedNames.add(local);
3669
+ }
3670
+ }
3671
+ }
3672
+ function extractPageId(filePath, routesDir) {
3673
+ const relativePath = relative2(routesDir, filePath);
3674
+ const pathParts = relativePath.split(sep);
3675
+ if (pathParts.includes("demos")) {
3676
+ const demosIndex = pathParts.indexOf("demos");
3677
+ return pathParts.slice(0, demosIndex).join(sep);
3678
+ }
3679
+ return dirname2(relativePath);
3680
+ }
3681
+ function isCssAsset(filePath) {
3682
+ return filePath.endsWith(".css");
3683
+ }
3684
+ function isDemoFile(filePath) {
3685
+ try {
3686
+ return filePath.includes("/demos/") && filePath.endsWith(".tsx") && // could also be in a comment, probably need to use TS parser
3687
+ readFileSync3(filePath, "utf-8").includes("export default");
3688
+ } catch (error) {
3689
+ return false;
3690
+ }
3691
+ }
3692
+ function createEmptyScopeModule() {
3693
+ return "export const createDemoScope = () => ({})";
3694
+ }
3695
+
3696
+ // src/react-demo-plugin/react-demo-plugin.ts
3697
+ import { transformerRenderIndentGuides as transformerRenderIndentGuides2 } from "@shikijs/transformers";
3698
+ import chalk6 from "chalk";
3699
+ import { watch as watch2 } from "chokidar";
3700
+ import { glob as glob3 } from "glob";
3701
+ import { readFile as readFile3 } from "node:fs/promises";
3702
+ import { basename as basename2, resolve as resolve4 } from "node:path";
3703
+ import { createHighlighter as createHighlighter2 } from "shiki";
3704
+ import * as ts3 from "typescript";
3705
+ import { quiCustomDarkTheme as quiCustomDarkTheme3 } from "@qualcomm-ui/mdx-common";
3706
+ import { dedent } from "@qualcomm-ui/utils/dedent";
3707
+ import { debounce } from "@qualcomm-ui/utils/functions";
3708
+ var isDev2 = process.env.NODE_ENV === "development";
3709
+ var highlighter2 = null;
3710
+ var initCount2 = 0;
3711
+ var hmrState = {
3712
+ windowScrollY: 0
3713
+ };
3714
+ var demoRegistry2 = /* @__PURE__ */ new Map();
3715
+ var pageScopes = /* @__PURE__ */ new Map();
3716
+ var pageFiles = /* @__PURE__ */ new Map();
3717
+ var relativeImportDependents = /* @__PURE__ */ new Map();
3718
+ var hasWatcherInitialized2 = false;
3719
+ function logDev2(...args) {
3720
+ if (!hasWatcherInitialized2) {
3721
+ return;
3722
+ }
3723
+ console.log(...args);
3724
+ }
3725
+ function reactDemoPlugin({
3726
+ demoPattern = "src/routes/**/demos/*.tsx",
3727
+ lazyLoadDevModules = true,
3728
+ routesDir = "src/routes",
3729
+ theme = {
3730
+ dark: quiCustomDarkTheme3,
3731
+ light: "github-light-high-contrast"
3732
+ },
3733
+ transformers = [],
3734
+ transformLine
3735
+ } = {}) {
3736
+ let watcher = null;
3737
+ return {
3738
+ async buildEnd() {
3739
+ if (watcher) {
3740
+ await watcher.close();
3741
+ watcher = null;
3742
+ hasWatcherInitialized2 = false;
3743
+ }
3744
+ },
3745
+ async buildStart() {
3746
+ if (initCount2 === 0) {
3747
+ initCount2++;
3748
+ return;
3749
+ }
3750
+ if (!highlighter2) {
3751
+ try {
3752
+ highlighter2 = await createHighlighter2({
3753
+ langs: ["tsx", "typescript"],
3754
+ themes: [theme.dark, theme.light]
3755
+ });
3756
+ console.log(
3757
+ `${chalk6.magenta.bold(LOG_PREFIX2)} Shiki highlighter initialized`
3758
+ );
3759
+ } catch (error) {
3760
+ console.warn(
3761
+ `${chalk6.magenta.bold(LOG_PREFIX2)} Failed to initialize highlighter:`,
3762
+ error
3763
+ );
3764
+ }
3765
+ }
3766
+ try {
3767
+ await collectReactDemos();
3768
+ if (isDev2 && !hasWatcherInitialized2) {
3769
+ hasWatcherInitialized2 = true;
3770
+ await setupFileWatcher();
3771
+ } else if (isDev2) {
3772
+ logDev2(
3773
+ `${chalk6.magenta.bold(LOG_PREFIX2)} skipping watch: watcher already initialized by another instance`
3774
+ );
3775
+ }
3776
+ } catch (error) {
3777
+ if (watcher) {
3778
+ await watcher.close();
3779
+ watcher = null;
3780
+ hasWatcherInitialized2 = false;
3781
+ }
3782
+ throw error;
3783
+ }
3784
+ },
3785
+ configureServer(server) {
3786
+ const debouncedRestore = debounce((data) => {
3787
+ hmrState.windowScrollY = data.scrollY;
3788
+ }, 100);
3789
+ server.ws.on("custom:store-scroll-position", debouncedRestore);
3790
+ server.ws.on("custom:request-scroll-position", () => {
3791
+ server.ws.send({
3792
+ data: hmrState.windowScrollY,
3793
+ event: "custom:restore-scroll-position",
3794
+ type: "custom"
3795
+ });
3796
+ });
3797
+ },
3798
+ async handleHotUpdate({ file, server }) {
3799
+ if (isCssAsset(file)) {
3800
+ return server.moduleGraph.getModulesByFile(file)?.values()?.toArray();
3801
+ }
3802
+ if (!lazyLoadDevModules) {
3803
+ let shouldUpdate = false;
3804
+ if (isDemoFile(file)) {
3805
+ await handleFileAdditionOrUpdate(file, false);
3806
+ shouldUpdate = true;
3807
+ }
3808
+ const normalizedFile = resolve4(file);
3809
+ const dependents = relativeImportDependents.get(normalizedFile);
3810
+ if (dependents) {
3811
+ shouldUpdate = true;
3812
+ }
3813
+ if (shouldUpdate) {
3814
+ const autoModule = server.moduleGraph.getModuleById(
3815
+ VIRTUAL_MODULE_IDS.AUTO
3816
+ );
3817
+ if (autoModule) {
3818
+ server.moduleGraph.invalidateModule(autoModule);
3819
+ await server.reloadModule(autoModule);
3820
+ }
3821
+ return [];
3822
+ }
3823
+ }
3824
+ if (isDemoFile(file)) {
3825
+ logDev2(
3826
+ `${chalk6.magenta.bold(LOG_PREFIX2)} Processing change: ${chalk6.blueBright.bold(file)}`
3827
+ );
3828
+ const pageId = extractPageId(file, routesDir);
3829
+ const demoName = createDemoName(file);
3830
+ const wasNew = !demoRegistry2.has(demoName);
3831
+ await handleFileAdditionOrUpdate(file, false);
3832
+ const pageModule = server.moduleGraph.getModuleById(
3833
+ `${VIRTUAL_MODULE_IDS.PAGE_PREFIX}${pageId}`
3834
+ );
3835
+ if (pageModule) {
3836
+ console.debug(
3837
+ "invalidating:",
3838
+ `virtual:qui-demo-scope/page:${pageId}`
3839
+ );
3840
+ server.moduleGraph.invalidateModule(pageModule);
3841
+ await server.reloadModule(pageModule);
3842
+ }
3843
+ if (wasNew) {
3844
+ const autoModule = server.moduleGraph.getModuleById(
3845
+ VIRTUAL_MODULE_IDS.AUTO
3846
+ );
3847
+ if (autoModule) {
3848
+ server.moduleGraph.invalidateModule(autoModule);
3849
+ await server.reloadModule(autoModule);
3850
+ }
3851
+ }
3852
+ server.ws.send({
3853
+ data: demoRegistry2.get(createDemoName(file)),
3854
+ event: "qui-demo-update",
3855
+ type: "custom"
3856
+ });
3857
+ } else {
3858
+ const normalizedFile = resolve4(file);
3859
+ const dependents = relativeImportDependents.get(normalizedFile);
3860
+ if (dependents) {
3861
+ for (const demoName of dependents) {
3862
+ server.ws.send({
3863
+ data: { demoName },
3864
+ event: "react-demo-updating",
3865
+ type: "custom"
3866
+ });
3867
+ }
3868
+ }
3869
+ }
3870
+ return [];
3871
+ },
3872
+ async load(id) {
3873
+ if (id === VIRTUAL_MODULE_IDS.AUTO) {
3874
+ return generateAutoScopeModule();
3875
+ }
3876
+ if (id.startsWith(VIRTUAL_MODULE_IDS.PAGE_PREFIX)) {
3877
+ const pageId = id.replace(VIRTUAL_MODULE_IDS.PAGE_PREFIX, "");
3878
+ return pageScopes.get(pageId) || createEmptyScopeModule();
3879
+ }
3880
+ if (id === VIRTUAL_MODULE_IDS.CONFIG) {
3881
+ return generateConfigModule();
3882
+ }
3883
+ },
3884
+ name: "auto-demo-scope",
3885
+ resolveId(id) {
3886
+ if (id === "virtual:qui-demo-scope/auto") {
3887
+ return VIRTUAL_MODULE_IDS.AUTO;
3888
+ }
3889
+ if (id.startsWith("virtual:qui-demo-scope/page:")) {
3890
+ return `\0${id}`;
3891
+ }
3892
+ if (id === "virtual:qui-demo-scope/config") {
3893
+ return VIRTUAL_MODULE_IDS.CONFIG;
3894
+ }
3895
+ },
3896
+ writeBundle() {
3897
+ console.log(
3898
+ `${chalk6.blue.bold(LOG_PREFIX2)} Successfully integrated ${chalk6.green(demoRegistry2.size)} component demos`
3899
+ );
3900
+ }
3901
+ };
3902
+ async function setupFileWatcher() {
3903
+ watcher = watch2(routesDir, {
3904
+ ignoreInitial: true,
3905
+ persistent: true
3906
+ });
3907
+ watcher.on("ready", () => {
3908
+ logDev2(
3909
+ `${chalk6.blue.bold(LOG_PREFIX2)} Registered ${chalk6.green(demoRegistry2.size)} demo files. Watching for file changes...`
3910
+ );
3911
+ });
3912
+ watcher.on("addDir", (dirPath) => {
3913
+ if (dirPath.endsWith("/demos")) {
3914
+ logDev2(
3915
+ `${chalk6.magenta.bold(LOG_PREFIX2)} ${chalk6.greenBright("New demo directory detected:")} ${chalk6.blueBright.bold(dirPath)}`
3916
+ );
3917
+ }
3918
+ });
3919
+ watcher.on("unlink", async (filePath) => {
3920
+ if (isDemoFile(filePath)) {
3921
+ logDev2(
3922
+ `${chalk6.magenta.bold(LOG_PREFIX2)} ${chalk6.redBright("Demo file deleted:")} ${chalk6.blueBright.bold(filePath)}`
3923
+ );
3924
+ await handleFileDeletion(filePath);
3925
+ }
3926
+ });
3927
+ watcher.on("add", async (filePath) => {
3928
+ if (isDemoFile(filePath)) {
3929
+ logDev2(
3930
+ `${chalk6.magenta.bold(LOG_PREFIX2)} ${chalk6.greenBright("Demo file added:")} ${chalk6.blueBright.bold(filePath)}`
3931
+ );
3932
+ await handleFileAdditionOrUpdate(filePath, true).catch(() => {
3933
+ console.debug("failed to add file", filePath);
3934
+ });
3935
+ }
3936
+ });
3937
+ }
3938
+ async function handleFileAdditionOrUpdate(filePath, isAdd) {
3939
+ const pageId = extractPageId(filePath, routesDir);
3940
+ const demoName = createDemoName(filePath);
3941
+ const existingFiles = pageFiles.get(pageId) ?? [];
3942
+ if (!existingFiles.includes(filePath)) {
3943
+ existingFiles.push(filePath);
3944
+ pageFiles.set(pageId, existingFiles);
3945
+ }
3946
+ const fileData = await extractFileData(filePath);
3947
+ if (fileData) {
3948
+ demoRegistry2.set(demoName, {
3949
+ ...fileData,
3950
+ demoName,
3951
+ pageId
3952
+ });
3953
+ const fileImports = await extractFileImports(filePath);
3954
+ if (fileImports) {
3955
+ for (const relativeImport of fileImports.relativeImports) {
3956
+ const dependents = relativeImportDependents.get(relativeImport.resolvedPath) ?? /* @__PURE__ */ new Set();
3957
+ dependents.add(demoName);
3958
+ relativeImportDependents.set(relativeImport.resolvedPath, dependents);
3959
+ }
3960
+ }
3961
+ }
3962
+ const previousScope = pageScopes.get(pageId);
3963
+ const allPageFiles = pageFiles.get(pageId);
3964
+ const scope = await generateScopeForPage(pageId, allPageFiles);
3965
+ pageScopes.set(pageId, scope);
3966
+ logDev2(
3967
+ `${chalk6.magenta.bold(LOG_PREFIX2)} ${chalk6.greenBright(isAdd ? "Added demo:" : "Updated demo:")} ${chalk6.greenBright.bold(demoName)}`
3968
+ );
3969
+ return previousScope !== scope;
3970
+ }
3971
+ async function handleFileDeletion(deletedFile) {
3972
+ const demoName = createDemoName(deletedFile);
3973
+ const pageId = extractPageId(deletedFile, routesDir);
3974
+ demoRegistry2.delete(demoName);
3975
+ for (const [importPath, dependents] of relativeImportDependents.entries()) {
3976
+ dependents.delete(demoName);
3977
+ if (dependents.size === 0) {
3978
+ relativeImportDependents.delete(importPath);
3979
+ }
3980
+ }
3981
+ const files = pageFiles.get(pageId);
3982
+ if (files) {
3983
+ const updatedFiles = files.filter((f) => f !== deletedFile);
3984
+ if (updatedFiles.length === 0) {
3985
+ pageFiles.delete(pageId);
3986
+ pageScopes.delete(pageId);
3987
+ logDev2(
3988
+ `${chalk6.magenta.bold(LOG_PREFIX2)} ${chalk6.redBright("Removed empty page:")} ${chalk6.blueBright.bold(pageId)}`
3989
+ );
3990
+ } else {
3991
+ pageFiles.set(pageId, updatedFiles);
3992
+ const scope = await generateScopeForPage(pageId, updatedFiles);
3993
+ pageScopes.set(pageId, scope);
3994
+ }
3995
+ }
3996
+ logDev2(
3997
+ `${chalk6.magenta.bold(LOG_PREFIX2)} ${chalk6.redBright("Cleaned up deleted file:")} ${chalk6.blueBright.bold(deletedFile)}`
3998
+ );
3999
+ }
4000
+ function isPreviewLine(trimmedLine) {
4001
+ return trimmedLine === "// preview" || /^\{\s*\/\*\s*preview\s*\*\/\s*\}$/.test(trimmedLine);
4002
+ }
4003
+ function extractPreviewsAndCleanSource(code) {
4004
+ const lines = code.split("\n");
4005
+ const previewBlocks = [];
4006
+ const cleanedLines = [];
4007
+ let inPreview = false;
4008
+ let currentBlock = [];
4009
+ for (const line of lines) {
4010
+ const trimmedLine = line.trim();
4011
+ if (isPreviewLine(trimmedLine)) {
4012
+ if (inPreview) {
4013
+ previewBlocks.push(currentBlock.join("\n"));
4014
+ currentBlock = [];
4015
+ inPreview = false;
4016
+ } else {
4017
+ inPreview = true;
4018
+ }
4019
+ continue;
4020
+ }
4021
+ cleanedLines.push(line);
4022
+ if (inPreview) {
4023
+ currentBlock.push(line);
4024
+ }
4025
+ }
4026
+ const joined = previewBlocks.join("\n");
4027
+ const split = joined.split("\n");
4028
+ if (!split.at(-1)?.trim()) {
4029
+ split.pop();
4030
+ }
4031
+ return {
4032
+ formattedPreview: dedent(split.join("\n")).trim(),
4033
+ sourceWithoutSnippetComments: cleanedLines.join("\n")
4034
+ };
4035
+ }
4036
+ async function highlightCode(code) {
4037
+ if (!highlighter2) {
4038
+ return code;
4039
+ }
4040
+ try {
4041
+ return highlighter2.codeToHtml(code, {
4042
+ defaultColor: "light-dark()",
4043
+ lang: "tsx",
4044
+ themes: {
4045
+ dark: theme.dark,
4046
+ light: theme.light
4047
+ },
4048
+ transformers: [transformerRenderIndentGuides2(), ...transformers]
4049
+ });
4050
+ } catch (error) {
4051
+ console.warn(
4052
+ `${chalk6.magenta.bold(LOG_PREFIX2)} Failed to highlight code:`,
4053
+ error
4054
+ );
4055
+ return code;
4056
+ }
4057
+ }
4058
+ async function collectReactDemos() {
4059
+ if (demoRegistry2.size && pageScopes.size && pageFiles.size) {
4060
+ logDev2(
4061
+ `${chalk6.magenta.bold(LOG_PREFIX2)} Using cached ${chalk6.cyanBright.bold(demoRegistry2.size)} demos`
4062
+ );
4063
+ return;
4064
+ }
4065
+ const demoFiles = (await glob3(demoPattern)).filter(isDemoFile);
4066
+ for (const filePath of demoFiles) {
4067
+ const pageId = extractPageId(filePath, routesDir);
4068
+ const existingFiles = pageFiles.get(pageId) ?? [];
4069
+ existingFiles.push(filePath);
4070
+ pageFiles.set(pageId, existingFiles);
4071
+ const fileData = await extractFileData(filePath);
4072
+ if (fileData) {
4073
+ const demoName = createDemoName(filePath);
4074
+ demoRegistry2.set(demoName, {
4075
+ ...fileData,
4076
+ pageId
4077
+ });
4078
+ }
4079
+ const fileImports = await extractFileImports(filePath);
4080
+ if (fileImports) {
4081
+ for (const relativeImport of fileImports.relativeImports) {
4082
+ const demoName = createDemoName(filePath);
4083
+ const dependents = relativeImportDependents.get(relativeImport.resolvedPath) ?? /* @__PURE__ */ new Set();
4084
+ dependents.add(demoName);
4085
+ relativeImportDependents.set(relativeImport.resolvedPath, dependents);
4086
+ }
4087
+ }
4088
+ }
4089
+ for (const [pageId, files] of pageFiles.entries()) {
4090
+ const scope = await generateScopeForPage(pageId, files);
4091
+ pageScopes.set(pageId, scope);
4092
+ }
4093
+ }
4094
+ async function generateScopeForPage(pageId, files) {
4095
+ const demosData = [];
4096
+ const allThirdPartyImports = /* @__PURE__ */ new Map();
4097
+ const allRelativeImports = [];
4098
+ const demoImportData = /* @__PURE__ */ new Map();
4099
+ for (const file of files) {
4100
+ const demoName = createDemoName(file);
4101
+ const demo = demoRegistry2.get(demoName);
4102
+ if (!demo) {
4103
+ continue;
4104
+ }
4105
+ demosData.push({
4106
+ demoName,
4107
+ fileName: demo.fileName,
4108
+ imports: demo.imports,
4109
+ pageId: demo.pageId,
4110
+ sourceCode: demo.sourceCode
4111
+ });
4112
+ const { importMap, relativeImports } = await extractAllImports([file]);
4113
+ demoImportData.set(demoName, {
4114
+ relative: relativeImports.map((r) => ({
4115
+ resolvedPath: r.resolvedPath,
4116
+ specifiers: r.specifiers
4117
+ })),
4118
+ thirdParty: Array.from(importMap.entries()).map(([source, specs]) => ({
4119
+ source,
4120
+ specifiers: Array.from(specs)
4121
+ }))
4122
+ });
4123
+ for (const [source, specifiers] of importMap) {
4124
+ if (!allThirdPartyImports.has(source)) {
4125
+ allThirdPartyImports.set(source, /* @__PURE__ */ new Set());
4126
+ }
4127
+ for (const spec of specifiers) {
4128
+ allThirdPartyImports.get(source).add(spec);
4129
+ }
4130
+ }
4131
+ for (const relImport of relativeImports) {
4132
+ if (!allRelativeImports.some(
4133
+ (r) => r.resolvedPath === relImport.resolvedPath
4134
+ )) {
4135
+ allRelativeImports.push(relImport);
4136
+ }
4137
+ }
4138
+ }
4139
+ const pageImports = [];
4140
+ const reactScopeEntries = [];
4141
+ addReactImports(pageImports, reactScopeEntries);
4142
+ const moduleNames = /* @__PURE__ */ new Map();
4143
+ const moduleRegistryEntries = [];
4144
+ for (const [source] of Array.from(allThirdPartyImports.entries()).sort(
4145
+ ([a], [b]) => a.localeCompare(b)
4146
+ )) {
4147
+ const moduleName = createUniqueModuleName(source);
4148
+ moduleNames.set(source, moduleName);
4149
+ pageImports.push(`import * as ${moduleName} from "${source}"`);
4150
+ moduleRegistryEntries.push(` "${source}": ${moduleName}`);
4151
+ }
4152
+ for (const { resolvedPath } of allRelativeImports) {
4153
+ const moduleName = createUniqueModuleName(resolvedPath);
4154
+ moduleNames.set(resolvedPath, moduleName);
4155
+ pageImports.push(`import * as ${moduleName} from "${resolvedPath}"`);
4156
+ moduleRegistryEntries.push(` "${resolvedPath}": ${moduleName}`);
4157
+ }
4158
+ const demosJson = JSON.stringify(demosData);
4159
+ const demoImportDataJson = JSON.stringify(
4160
+ Array.from(demoImportData.entries())
4161
+ );
4162
+ const reactScopeEntriesCode = reactScopeEntries.map((e) => ` ${e}`).join(",\n");
4163
+ return `// Auto-generated page scope for ${pageId}
4164
+ ${pageImports.join("\n")}
4165
+
4166
+ const modules = {
4167
+ ${moduleRegistryEntries.join(",\n")}
4168
+ }
4169
+
4170
+ const demosData = ${demosJson}
4171
+ const demoImportData = new Map(${demoImportDataJson})
4172
+
4173
+ const reactScope = {
4174
+ ${reactScopeEntriesCode}
4175
+ }
4176
+
4177
+ const scopeCache = new Map()
4178
+
4179
+ function createScope(demoName) {
4180
+ if (scopeCache.has(demoName)) {
4181
+ return scopeCache.get(demoName)
4182
+ }
4183
+
4184
+ const imports = demoImportData.get(demoName)
4185
+ if (!imports) return {}
4186
+
4187
+ const scope = {...reactScope}
4188
+
4189
+ for (const {source, specifiers} of imports.thirdParty) {
4190
+ const mod = modules[source]
4191
+ if (!mod) continue
4192
+
4193
+ for (const {imported, local} of specifiers) {
4194
+ if (imported === 'default') {
4195
+ scope[local] = mod.default
4196
+ } else if (imported === '*') {
4197
+ Object.assign(scope, mod)
4198
+ } else {
4199
+ scope[local] = mod[imported]
4200
+ }
4201
+ }
4202
+ }
4203
+
4204
+ for (const {resolvedPath, specifiers} of imports.relative) {
4205
+ const mod = modules[resolvedPath]
4206
+ if (!mod) continue
4207
+
4208
+ for (const {imported, local} of specifiers) {
4209
+ if (imported === 'default') {
4210
+ scope[local] = mod.default
4211
+ } else if (imported === '*') {
4212
+ Object.assign(scope, mod)
4213
+ } else {
4214
+ scope[local] = mod[imported]
4215
+ }
4216
+ }
4217
+ }
4218
+
4219
+ scopeCache.set(demoName, scope)
4220
+ return scope
4221
+ }
4222
+
4223
+ export function getDemo(demoName) {
4224
+ const demo = demosData.find(d => d.demoName === demoName)
4225
+ if (!demo) return null
4226
+ return {
4227
+ ...demo,
4228
+ scope: createScope(demoName)
4229
+ }
4230
+ }
4231
+
4232
+ export function getDemos() {
4233
+ return demosData.map(demo => ({
4234
+ ...demo,
4235
+ scope: createScope(demo.demoName)
4236
+ }))
4237
+ }
4238
+ `;
4239
+ }
4240
+ async function generateAutoScopeModule() {
4241
+ if (isDev2 && lazyLoadDevModules) {
4242
+ return [
4243
+ "// Auto-generated demo scope resolver (DEV MODE - Lazy by Page)",
4244
+ generateLazyPageLoaders(),
4245
+ generateDemoToPageMap(),
4246
+ generateDevGetDemo()
4247
+ ].join("\n\n");
4248
+ }
4249
+ const registryCode = generateDemoRegistry(demoRegistry2);
4250
+ return [
4251
+ "// Auto-generated demo scope resolver (PROD MODE)",
4252
+ generatePageImports(),
4253
+ generateScopeMap(),
4254
+ registryCode,
4255
+ generateExportedFunctions()
4256
+ ].join("\n\n");
4257
+ }
4258
+ function generateConfigModule() {
4259
+ return dedent`
4260
+ export function getReactDemoConfig() {
4261
+ return {lazyLoadDevModules: ${lazyLoadDevModules}}
4262
+ }
4263
+ `;
4264
+ }
4265
+ function generateLazyPageLoaders() {
4266
+ const pageIds = Array.from(pageFiles.keys()).sort();
4267
+ if (pageIds.length === 0) {
4268
+ return "export const lazyDemoLoader = {}";
4269
+ }
4270
+ const entries = pageIds.map((pageId) => {
4271
+ return ` "${pageId}": () => import("virtual:qui-demo-scope/page:${pageId}")`;
4272
+ }).join(",\n");
4273
+ return `export const lazyDemoLoader = {
4274
+ ${entries}
4275
+ }`;
4276
+ }
4277
+ function generateDemoToPageMap() {
4278
+ const entries = Array.from(demoRegistry2.entries()).map(([demoName, { pageId }]) => {
4279
+ return ` "${demoName}": "${pageId}"`;
4280
+ }).join(",\n");
4281
+ return `const demoToPageMap = {
4282
+ ${entries}
4283
+ }`;
4284
+ }
4285
+ function generateDevGetDemo() {
4286
+ return dedent`
4287
+ export async function getDemo(demoName) {
4288
+ const pageId = demoToPageMap[demoName]
4289
+ if (!pageId) {
4290
+ return {
4291
+ fileName: "",
4292
+ imports: [],
4293
+ errorMessage: \`Demo "\${demoName}" not found.\`,
4294
+ scope: {},
4295
+ pageId: "",
4296
+ sourceCode: [],
4297
+ }
4298
+ }
4299
+
4300
+ const loader = lazyDemoLoader[pageId]
4301
+ if (!loader) {
4302
+ return {
4303
+ fileName: "",
4304
+ imports: [],
4305
+ errorMessage: \`Page "\${pageId}" not found.\`,
4306
+ scope: {},
4307
+ pageId: "",
4308
+ sourceCode: [],
4309
+ }
4310
+ }
4311
+
4312
+ const pageModule = await loader()
4313
+ const demo = pageModule.getDemo(demoName)
4314
+
4315
+ return demo || {
4316
+ fileName: "",
4317
+ imports: [],
4318
+ errorMessage: \`Demo "\${demoName}" not found in page.\`,
4319
+ scope: {},
4320
+ pageId: "",
4321
+ sourceCode: [],
4322
+ }
4323
+ }
4324
+ `;
4325
+ }
4326
+ function extractHighlightedVariants(highlightedHtml) {
4327
+ const preMatch = highlightedHtml.match(/^<pre[^>]*><code>/)?.[0] || "";
4328
+ const postMatch = highlightedHtml.match(/<\/code><\/pre>$/)?.[0] || "";
4329
+ const content = highlightedHtml.slice(preMatch.length, -postMatch.length);
4330
+ const lines = content.split("\n");
4331
+ const previewLines = [];
4332
+ const withoutPreviewLines = [];
4333
+ let inPreview = false;
4334
+ for (const line of lines) {
4335
+ const textContent = line.replace(/<[^>]*>/g, "").replace(/&#x3C;/g, "<").replace(/&#x3E;/g, ">").trim();
4336
+ if (textContent === "// preview" || textContent === "{/* preview */}") {
4337
+ inPreview = !inPreview;
4338
+ continue;
4339
+ }
4340
+ if (inPreview) {
4341
+ previewLines.push(line);
4342
+ }
4343
+ withoutPreviewLines.push(line);
4344
+ }
4345
+ const normalizedPreviewLines = normalizeIndentation(previewLines);
4346
+ const highlightedPreview = normalizedPreviewLines.length > 0 ? `${preMatch}${normalizedPreviewLines.join("\n")}${postMatch}` : "";
4347
+ const highlightedWithoutPreview = `${preMatch}${withoutPreviewLines.join("\n")}${postMatch}`;
4348
+ return { highlightedPreview, highlightedWithoutPreview };
4349
+ }
4350
+ function normalizeIndentation(lines) {
4351
+ if (lines.length === 0) {
4352
+ return [];
4353
+ }
4354
+ const nonEmptyLines = lines.filter(
4355
+ (line) => line.replace(/<[^>]*>/g, "").trim().length > 0
4356
+ );
4357
+ if (nonEmptyLines.length === 0) {
4358
+ return lines;
4359
+ }
4360
+ let minIndent = Infinity;
4361
+ for (const line of nonEmptyLines) {
4362
+ const matches = line.match(/<span class="indent">/g);
4363
+ if (matches) {
4364
+ minIndent = Math.min(minIndent, matches.length);
4365
+ } else {
4366
+ minIndent = 0;
4367
+ break;
4368
+ }
4369
+ }
4370
+ if (minIndent === 0 || minIndent === Infinity) {
4371
+ return lines;
4372
+ }
4373
+ return lines.map((line) => {
4374
+ let result = line;
4375
+ for (let i = 0; i < minIndent; i++) {
4376
+ result = result.replace(/<span class="indent">(\s*)<\/span>/, "");
4377
+ }
4378
+ return result;
4379
+ });
4380
+ }
4381
+ function transformLines(code) {
4382
+ if (!transformLine) {
4383
+ return code;
4384
+ }
4385
+ const result = [];
4386
+ for (const line of code.split("\n")) {
4387
+ if (line.trim()) {
4388
+ const transformed = transformLine(line);
4389
+ if (transformed) {
4390
+ result.push(transformed);
4391
+ }
4392
+ } else {
4393
+ result.push(line);
4394
+ }
4395
+ }
4396
+ return result.join("\n");
4397
+ }
4398
+ async function extractFileData(filePath) {
4399
+ try {
4400
+ const code = await readFile3(filePath, "utf-8").then(transformLines);
4401
+ const { imports, strippedCode: codeWithoutImports } = stripImports(
4402
+ code,
4403
+ filePath
4404
+ );
4405
+ const fileName = basename2(filePath);
4406
+ const { formattedPreview, sourceWithoutSnippetComments } = extractPreviewsAndCleanSource(code);
4407
+ const highlightedFull = await highlightCode(code);
4408
+ const { highlightedPreview, highlightedWithoutPreview } = extractHighlightedVariants(highlightedFull);
4409
+ const sourceCode = [
4410
+ {
4411
+ fileName,
4412
+ highlighted: {
4413
+ full: highlightedWithoutPreview,
4414
+ preview: highlightedPreview
4415
+ },
4416
+ raw: {
4417
+ full: sourceWithoutSnippetComments,
4418
+ preview: formattedPreview,
4419
+ withoutImports: codeWithoutImports
4420
+ }
4421
+ }
4422
+ ];
4423
+ const fileImports = await extractFileImports(filePath);
4424
+ if (fileImports) {
4425
+ for (const relativeImport of fileImports.relativeImports) {
4426
+ try {
4427
+ const importedCode = await readFile3(
4428
+ relativeImport.resolvedPath,
4429
+ "utf-8"
4430
+ ).then(transformLines);
4431
+ const { strippedCode: importedCodeWithoutImports } = stripImports(
4432
+ importedCode,
4433
+ relativeImport.resolvedPath
4434
+ );
4435
+ const {
4436
+ sourceWithoutSnippetComments: importedSourceWithoutSnippets
4437
+ } = extractPreviewsAndCleanSource(importedCode);
4438
+ const importedFileName = basename2(relativeImport.resolvedPath);
4439
+ const highlightedImportedSource = await highlightCode(
4440
+ importedSourceWithoutSnippets
4441
+ );
4442
+ sourceCode.push({
4443
+ fileName: importedFileName,
4444
+ highlighted: {
4445
+ full: highlightedImportedSource,
4446
+ preview: ""
4447
+ },
4448
+ raw: {
4449
+ full: importedSourceWithoutSnippets,
4450
+ preview: "",
4451
+ withoutImports: importedCodeWithoutImports
4452
+ }
4453
+ });
4454
+ } catch (error) {
4455
+ logDev2(
4456
+ `${chalk6.magenta.bold(LOG_PREFIX2)} ${chalk6.yellowBright("Failed to process relative import:")} ${chalk6.blueBright.bold(relativeImport.resolvedPath)}`
4457
+ );
4458
+ }
4459
+ }
4460
+ }
4461
+ return {
4462
+ demoName: createDemoName(filePath),
4463
+ fileName,
4464
+ imports,
4465
+ sourceCode
4466
+ };
4467
+ } catch (e) {
4468
+ logDev2(
4469
+ `${chalk6.magenta.bold(LOG_PREFIX2)} ${chalk6.yellowBright("Failed to parse")} ${chalk6.blueBright.bold(filePath)}. ${chalk6.yellowBright("Removing from registry")}`
4470
+ );
4471
+ return null;
4472
+ }
4473
+ }
4474
+ function stripImports(code, fileName) {
4475
+ try {
4476
+ let visit8 = function(node) {
4477
+ if (ts3.isImportDeclaration(node)) {
4478
+ importRanges.push({
4479
+ end: node.getEnd(),
4480
+ start: node.getFullStart()
4481
+ });
4482
+ }
4483
+ ts3.forEachChild(node, visit8);
4484
+ };
4485
+ var visit7 = visit8;
4486
+ const sourceFile = ts3.createSourceFile(
4487
+ fileName,
4488
+ code,
4489
+ ts3.ScriptTarget.Latest,
4490
+ true,
4491
+ getScriptKind(fileName)
4492
+ );
4493
+ const importRanges = [];
4494
+ visit8(sourceFile);
4495
+ const imports = importRanges.map((range) => {
4496
+ let endPos = range.end;
4497
+ if (code[endPos] === "\n") {
4498
+ endPos++;
4499
+ }
4500
+ return code.slice(range.start, endPos).trim();
4501
+ });
4502
+ importRanges.sort((a, b) => b.start - a.start);
4503
+ let strippedCode = code;
4504
+ for (const range of importRanges) {
4505
+ let endPos = range.end;
4506
+ if (strippedCode[endPos] === "\n") {
4507
+ endPos++;
4508
+ }
4509
+ strippedCode = strippedCode.slice(0, range.start) + strippedCode.slice(endPos);
4510
+ }
4511
+ strippedCode = strippedCode.trim();
4512
+ return {
4513
+ imports,
4514
+ strippedCode: strippedCode.replace(/^\n+/, "")
4515
+ };
4516
+ } catch (error) {
4517
+ logDev2(
4518
+ `${chalk6.magenta.bold(LOG_PREFIX2)} ${chalk6.redBright("Failed to strip imports from")} ${chalk6.blueBright.bold(fileName)}:`,
4519
+ error
4520
+ );
4521
+ return {
4522
+ imports: [],
4523
+ strippedCode: code
4524
+ };
4525
+ }
4526
+ }
4527
+ function generatePageImports() {
4528
+ const pageIds = Array.from(pageScopes.keys());
4529
+ return pageIds.map((pageId) => {
4530
+ const safeName = sanitizeIdentifier(pageId);
4531
+ return `import * as page_${safeName} from "virtual:qui-demo-scope/page:${pageId}"`;
4532
+ }).join("\n");
4533
+ }
4534
+ function generateScopeMap() {
4535
+ const pageIds = Array.from(pageScopes.keys());
4536
+ if (pageIds.length === 0) {
4537
+ return "const pageModules = {}";
4538
+ }
4539
+ const entries = pageIds.map((pageId) => {
4540
+ const safeName = sanitizeIdentifier(pageId);
4541
+ return ` "${pageId}": page_${safeName}`;
4542
+ }).join(",\n");
4543
+ return `const pageModules = {
4544
+ ${entries}
4545
+ }`;
4546
+ }
4547
+ function generateDemoRegistry(registry) {
4548
+ const entries = Array.from(registry.entries()).map(([demoName, { fileName, imports, pageId, sourceCode }]) => {
4549
+ return ` ["${demoName}", { fileName: "${fileName}", imports: ${JSON.stringify(imports)}, pageId: "${pageId}", sourceCode: ${JSON.stringify(sourceCode)}, demoName: "${demoName}" }]`;
4550
+ }).join(",\n");
4551
+ return `const demoRegistry = new Map([
4552
+ ${entries}
4553
+ ])`;
4554
+ }
4555
+ function generateExportedFunctions() {
4556
+ return dedent`
4557
+ export function getDemo(demoName) {
4558
+ const demo = demoRegistry.get(demoName)
4559
+ if (!demo) {
4560
+ return {
4561
+ fileName: "",
4562
+ imports: [],
4563
+ errorMessage: \`Demo "\${demoName}" not found.\`,
4564
+ scope: {},
4565
+ pageId: "",
4566
+ sourceCode: [],
4567
+ }
4568
+ }
4569
+
4570
+ const pageModule = pageModules[demo.pageId]
4571
+ if (!pageModule) {
4572
+ return {
4573
+ fileName: "",
4574
+ imports: [],
4575
+ errorMessage: \`Page module not found.\`,
4576
+ scope: {},
4577
+ pageId: demo.pageId,
4578
+ sourceCode: [],
4579
+ }
4580
+ }
4581
+
4582
+ return pageModule.getDemo(demoName) || {
4583
+ fileName: demo.fileName,
4584
+ imports: demo.imports,
4585
+ scope: {},
4586
+ pageId: demo.pageId,
4587
+ sourceCode: demo.sourceCode,
4588
+ }
4589
+ }
4590
+ `;
4591
+ }
4592
+ }
4593
+ export {
4594
+ LOG_PREFIX2 as LOG_PREFIX,
4595
+ NODE_BUILTINS,
4596
+ REACT_IMPORTS,
4597
+ VIRTUAL_MODULE_IDS,
4598
+ addReactImports,
4599
+ addRelativeImportsNamespaced,
4600
+ addThirdPartyImports,
4601
+ addThirdPartyImportsNamespaced,
4602
+ angularDemoPlugin,
4603
+ createDemoName,
4604
+ createEmptyScopeModule,
4605
+ createUniqueModuleName,
4606
+ extractAllImports,
4607
+ extractFileImports,
4608
+ extractPageId,
4609
+ getAlertIcon,
4610
+ getRehypePlugins,
4611
+ getRemarkPlugins,
4612
+ getScriptKind,
4613
+ isCssAsset,
4614
+ isDemoFile,
4615
+ quiDocsPlugin,
4616
+ quiRehypePlugins,
4617
+ quiRemarkPlugins,
4618
+ reactDemoPlugin,
4619
+ rehypeMdxCodeProps,
4620
+ rehypeSectionize,
4621
+ rehypeSlug,
4622
+ remarkAlerts,
4623
+ remarkCodeTabs,
4624
+ remarkFrontmatter2 as remarkFrontmatter,
4625
+ remarkGfm2 as remarkGfm,
4626
+ remarkMdxFrontmatter,
4627
+ remarkSelfLinkHeadings,
4628
+ remarkSpoilers,
4629
+ sanitizeIdentifier,
4630
+ sanitizeSourceName
4631
+ };
4632
+ //# sourceMappingURL=index.js.map