@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.
- package/LICENSE.txt +31 -0
- package/dist/angular-demo-plugin/angular-demo-plugin.d.ts +17 -0
- package/dist/angular-demo-plugin/angular-demo-plugin.d.ts.map +1 -0
- package/dist/angular-demo-plugin/index.d.ts +2 -0
- package/dist/angular-demo-plugin/index.d.ts.map +1 -0
- package/dist/angular-demo-plugin/virtual.d.ts +5 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +6347 -0
- package/dist/cli.js.map +7 -0
- package/dist/docs-plugin/docs-plugin.d.ts +15 -0
- package/dist/docs-plugin/docs-plugin.d.ts.map +1 -0
- package/dist/docs-plugin/index.d.ts +6 -0
- package/dist/docs-plugin/index.d.ts.map +1 -0
- package/dist/docs-plugin/internal/config-loader.d.ts +23 -0
- package/dist/docs-plugin/internal/config-loader.d.ts.map +1 -0
- package/dist/docs-plugin/internal/config-schema.d.ts +46 -0
- package/dist/docs-plugin/internal/config-schema.d.ts.map +1 -0
- package/dist/docs-plugin/internal/index.d.ts +8 -0
- package/dist/docs-plugin/internal/index.d.ts.map +1 -0
- package/dist/docs-plugin/internal/search-indexer.d.ts +46 -0
- package/dist/docs-plugin/internal/search-indexer.d.ts.map +1 -0
- package/dist/docs-plugin/internal/services/doc-props/doc-props-indexer.d.ts +28 -0
- package/dist/docs-plugin/internal/services/doc-props/doc-props-indexer.d.ts.map +1 -0
- package/dist/docs-plugin/internal/services/doc-props/index.d.ts +2 -0
- package/dist/docs-plugin/internal/services/doc-props/index.d.ts.map +1 -0
- package/dist/docs-plugin/internal/services/index.d.ts +4 -0
- package/dist/docs-plugin/internal/services/index.d.ts.map +1 -0
- package/dist/docs-plugin/internal/services/markdown/index.d.ts +6 -0
- package/dist/docs-plugin/internal/services/markdown/index.d.ts.map +1 -0
- package/dist/docs-plugin/internal/services/markdown/markdown-file-reader.d.ts +28 -0
- package/dist/docs-plugin/internal/services/markdown/markdown-file-reader.d.ts.map +1 -0
- package/dist/docs-plugin/internal/services/markdown/markdown-indexer.d.ts +27 -0
- package/dist/docs-plugin/internal/services/markdown/markdown-indexer.d.ts.map +1 -0
- package/dist/docs-plugin/internal/services/markdown/markdown.types.d.ts +10 -0
- package/dist/docs-plugin/internal/services/markdown/markdown.types.d.ts.map +1 -0
- package/dist/docs-plugin/internal/services/markdown/remark-remove-code-blocks.d.ts +3 -0
- package/dist/docs-plugin/internal/services/markdown/remark-remove-code-blocks.d.ts.map +1 -0
- package/dist/docs-plugin/internal/services/markdown/remark-remove-jsx.d.ts +3 -0
- package/dist/docs-plugin/internal/services/markdown/remark-remove-jsx.d.ts.map +1 -0
- package/dist/docs-plugin/internal/services/nav-builder/get-route-meta.d.ts +6 -0
- package/dist/docs-plugin/internal/services/nav-builder/get-route-meta.d.ts.map +1 -0
- package/dist/docs-plugin/internal/services/nav-builder/index.d.ts +4 -0
- package/dist/docs-plugin/internal/services/nav-builder/index.d.ts.map +1 -0
- package/dist/docs-plugin/internal/services/nav-builder/nav-builder.d.ts +56 -0
- package/dist/docs-plugin/internal/services/nav-builder/nav-builder.d.ts.map +1 -0
- package/dist/docs-plugin/internal/services/nav-builder/page-map.d.ts +7 -0
- package/dist/docs-plugin/internal/services/nav-builder/page-map.d.ts.map +1 -0
- package/dist/docs-plugin/internal/transform-route-meta-array.d.ts +3 -0
- package/dist/docs-plugin/internal/transform-route-meta-array.d.ts.map +1 -0
- package/dist/docs-plugin/internal/utils.d.ts +17 -0
- package/dist/docs-plugin/internal/utils.d.ts.map +1 -0
- package/dist/docs-plugin/internal/zod.d.ts +9 -0
- package/dist/docs-plugin/internal/zod.d.ts.map +1 -0
- package/dist/docs-plugin/mdx-plugins.d.ts +38 -0
- package/dist/docs-plugin/mdx-plugins.d.ts.map +1 -0
- package/dist/docs-plugin/rehype/index.d.ts +3 -0
- package/dist/docs-plugin/rehype/index.d.ts.map +1 -0
- package/dist/docs-plugin/rehype/rehype-sectionize.d.ts +11 -0
- package/dist/docs-plugin/rehype/rehype-sectionize.d.ts.map +1 -0
- package/dist/docs-plugin/rehype/rehype-slug.d.ts +16 -0
- package/dist/docs-plugin/rehype/rehype-slug.d.ts.map +1 -0
- package/dist/docs-plugin/remark/index.d.ts +5 -0
- package/dist/docs-plugin/remark/index.d.ts.map +1 -0
- package/dist/docs-plugin/remark/remark-alerts.d.ts +13 -0
- package/dist/docs-plugin/remark/remark-alerts.d.ts.map +1 -0
- package/dist/docs-plugin/remark/remark-code-tabs.d.ts +7 -0
- package/dist/docs-plugin/remark/remark-code-tabs.d.ts.map +1 -0
- package/dist/docs-plugin/remark/remark-self-link-headings.d.ts +11 -0
- package/dist/docs-plugin/remark/remark-self-link-headings.d.ts.map +1 -0
- package/dist/docs-plugin/remark/remark-spoilers.d.ts +31 -0
- package/dist/docs-plugin/remark/remark-spoilers.d.ts.map +1 -0
- package/dist/docs-plugin/tests/markdown-indexer.spec.d.ts +2 -0
- package/dist/docs-plugin/tests/markdown-indexer.spec.d.ts.map +1 -0
- package/dist/docs-plugin/tests/remark-slug.spec.d.ts +2 -0
- package/dist/docs-plugin/tests/remark-slug.spec.d.ts.map +1 -0
- package/dist/docs-plugin/tests/remix-flat-routes.spec.d.ts +2 -0
- package/dist/docs-plugin/tests/remix-flat-routes.spec.d.ts.map +1 -0
- package/dist/docs-plugin/tests/remix.spec.d.ts +2 -0
- package/dist/docs-plugin/tests/remix.spec.d.ts.map +1 -0
- package/dist/docs-plugin/tests/utils.d.ts +3 -0
- package/dist/docs-plugin/tests/utils.d.ts.map +1 -0
- package/dist/docs-plugin/tests/vite-generouted.spec.d.ts +2 -0
- package/dist/docs-plugin/tests/vite-generouted.spec.d.ts.map +1 -0
- package/dist/docs-plugin/types.d.ts +172 -0
- package/dist/docs-plugin/types.d.ts.map +1 -0
- package/dist/docs-plugin/virtual.d.ts +5 -0
- package/dist/exports.d.ts +7 -0
- package/dist/exports.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4632 -0
- package/dist/index.js.map +7 -0
- package/dist/open-web-ui-knowledge/common.d.ts +43 -0
- package/dist/open-web-ui-knowledge/common.d.ts.map +1 -0
- package/dist/open-web-ui-knowledge/download-knowledge.d.ts +2 -0
- package/dist/open-web-ui-knowledge/download-knowledge.d.ts.map +1 -0
- package/dist/open-web-ui-knowledge/generate-knowledge.d.ts +4 -0
- package/dist/open-web-ui-knowledge/generate-knowledge.d.ts.map +1 -0
- package/dist/open-web-ui-knowledge/load-config-from-env.d.ts +3 -0
- package/dist/open-web-ui-knowledge/load-config-from-env.d.ts.map +1 -0
- package/dist/open-web-ui-knowledge/types.d.ts +54 -0
- package/dist/open-web-ui-knowledge/types.d.ts.map +1 -0
- package/dist/open-web-ui-knowledge/upload-knowledge.d.ts +2 -0
- package/dist/open-web-ui-knowledge/upload-knowledge.d.ts.map +1 -0
- package/dist/react-demo-plugin/demo-plugin-constants.d.ts +9 -0
- package/dist/react-demo-plugin/demo-plugin-constants.d.ts.map +1 -0
- package/dist/react-demo-plugin/demo-plugin-types.d.ts +37 -0
- package/dist/react-demo-plugin/demo-plugin-types.d.ts.map +1 -0
- package/dist/react-demo-plugin/demo-plugin-utils.d.ts +53 -0
- package/dist/react-demo-plugin/demo-plugin-utils.d.ts.map +1 -0
- package/dist/react-demo-plugin/generate-lazy-demo-map.d.ts +21 -0
- package/dist/react-demo-plugin/generate-lazy-demo-map.d.ts.map +1 -0
- package/dist/react-demo-plugin/index.d.ts +6 -0
- package/dist/react-demo-plugin/index.d.ts.map +1 -0
- package/dist/react-demo-plugin/react-demo-plugin.d.ts +4 -0
- package/dist/react-demo-plugin/react-demo-plugin.d.ts.map +1 -0
- package/dist/react-demo-plugin/virtual.d.ts +17 -0
- package/dist/tsbuildinfo +1 -0
- package/lib/cli.js +6 -0
- 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(/</g, "<").replace(/>/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(/</g, "<").replace(/>/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
|