@clarify-labs/cli 0.10.0 → 0.10.2
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/output/cli.cjs +14 -9
- package/output/cli.cjs.map +1 -1
- package/output/cli.js +14 -9
- package/output/cli.js.map +1 -1
- package/output/core/engine/phases.d.ts +5 -5
- package/output/core/plugin/hooks.d.ts +2 -2
- package/output/core/runtime/ssg.d.ts +1 -1
- package/output/core/runtime/virtual-modules.d.ts +1 -0
- package/output/{engine-3f5Tpa-6.js → engine-CSSL_gGd.js} +502 -338
- package/output/engine-CSSL_gGd.js.map +1 -0
- package/output/{engine-I04EZzjg.cjs → engine-qafLfnXQ.cjs} +504 -337
- package/output/engine-qafLfnXQ.cjs.map +1 -0
- package/output/index.cjs +1 -1
- package/output/index.d.ts +1 -1
- package/output/index.js +1 -1
- package/output/parsers/markdown/mdx.d.ts +4 -4
- package/output/parsers/routes/routes.d.ts +2 -1
- package/output/parsers/routes/routes.test-utils.d.ts +18 -1
- package/output/plugins/openapi/parser.d.ts +1 -0
- package/output/plugins/openapi/virtual-modules.d.ts +4 -3
- package/output/plugins/source-links/source-links.d.ts +2 -2
- package/output/types.d.ts +108 -44
- package/package.json +6 -3
- package/output/engine-3f5Tpa-6.js.map +0 -1
- package/output/engine-I04EZzjg.cjs.map +0 -1
|
@@ -2,13 +2,16 @@ import { dirname, extname, isAbsolute, join, relative, resolve } from "node:path
|
|
|
2
2
|
import mdxPlugin from "@mdx-js/rollup";
|
|
3
3
|
import tailwindcss from "@tailwindcss/vite";
|
|
4
4
|
import react from "@vitejs/plugin-react";
|
|
5
|
+
import rehypeRaw from "rehype-raw";
|
|
5
6
|
import { compile } from "@mdx-js/mdx";
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
7
|
+
import rehypeShiki from "@shikijs/rehype";
|
|
8
|
+
import rehypeSlug from "rehype-slug";
|
|
9
|
+
import { createCssVariablesTheme } from "shiki";
|
|
9
10
|
import { visit } from "unist-util-visit";
|
|
10
|
-
import { markdownRemarkPlugins, themeBootstrapScript, themePresets } from "@clarify-labs/renderer";
|
|
11
|
+
import { markdownRemarkPlugins, parseCodeMeta, themeBootstrapScript, themePresets } from "@clarify-labs/renderer";
|
|
11
12
|
import { readFile, readdir, stat } from "node:fs/promises";
|
|
13
|
+
import GithubSlugger, { slug } from "github-slugger";
|
|
14
|
+
import { toString } from "mdast-util-to-string";
|
|
12
15
|
import { remark } from "remark";
|
|
13
16
|
import matter from "gray-matter";
|
|
14
17
|
import { createReadStream, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
@@ -19,38 +22,11 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
19
22
|
import SwaggerParser from "@apidevtools/swagger-parser";
|
|
20
23
|
import { tmpdir } from "node:os";
|
|
21
24
|
import { createRequire } from "node:module";
|
|
22
|
-
//#region source/parsers/markdown/utils.ts
|
|
23
|
-
function escapeHtml(text) {
|
|
24
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
25
|
-
}
|
|
26
|
-
//#endregion
|
|
27
25
|
//#region source/parsers/markdown/mdx.ts
|
|
28
26
|
function getLanguage(className) {
|
|
29
27
|
return (Array.isArray(className) ? className : typeof className === "string" ? className.split(/\s+/) : []).find((item) => typeof item === "string" && item.startsWith("language-"))?.replace(/^language-/, "") || "txt";
|
|
30
28
|
}
|
|
31
|
-
function getTextContent(node) {
|
|
32
|
-
if (!node) return "";
|
|
33
|
-
if (typeof node.value === "string") return node.value;
|
|
34
|
-
return node.children?.map(getTextContent).join("") ?? "";
|
|
35
|
-
}
|
|
36
|
-
function renderPlainCode(code) {
|
|
37
|
-
return code.split("\n").map((line) => `<span>${escapeHtml(line)}</span>`).join("\n");
|
|
38
|
-
}
|
|
39
|
-
function isBundledLanguage(language) {
|
|
40
|
-
return language in bundledLanguages;
|
|
41
|
-
}
|
|
42
|
-
var highlighter;
|
|
43
29
|
var cssVariablesTheme = createCssVariablesTheme();
|
|
44
|
-
async function getHighlighter() {
|
|
45
|
-
highlighter = highlighter ?? await createHighlighter({
|
|
46
|
-
themes: [cssVariablesTheme],
|
|
47
|
-
langs: []
|
|
48
|
-
});
|
|
49
|
-
return highlighter;
|
|
50
|
-
}
|
|
51
|
-
function renderHighlightedCode(html) {
|
|
52
|
-
return (/<code[^>]*>([\s\S]*?)<\/code>/.exec(html)?.[1] ?? html).split("\n").map((line) => line.trimStart().startsWith("<span") ? line : `<span>${line}</span>`).join("\n");
|
|
53
|
-
}
|
|
54
30
|
function rehypeParseCodeBlocks() {
|
|
55
31
|
return (tree) => {
|
|
56
32
|
visit(tree, "element", (node, _nodeIndex, parentNode) => {
|
|
@@ -68,61 +44,18 @@ function rehypeParseCodeBlocks() {
|
|
|
68
44
|
});
|
|
69
45
|
};
|
|
70
46
|
}
|
|
71
|
-
function rehypeShiki() {
|
|
72
|
-
return async (tree) => {
|
|
73
|
-
const shikiHighlighter = await getHighlighter();
|
|
74
|
-
const languages = /* @__PURE__ */ new Set();
|
|
75
|
-
visit(tree, "element", (node) => {
|
|
76
|
-
if (node.tagName !== "pre") return;
|
|
77
|
-
const codeNode = node.children?.[0];
|
|
78
|
-
if (codeNode?.tagName !== "code") return;
|
|
79
|
-
const language = typeof node.properties?.language === "string" ? node.properties.language : getLanguage(codeNode.properties?.className);
|
|
80
|
-
if (language && language !== "txt" && isBundledLanguage(language)) languages.add(language);
|
|
81
|
-
});
|
|
82
|
-
if (languages.size > 0) await shikiHighlighter.loadLanguage(...languages);
|
|
83
|
-
visit(tree, "element", (node) => {
|
|
84
|
-
if (node.tagName !== "pre") return;
|
|
85
|
-
const codeNode = node.children?.[0];
|
|
86
|
-
if (codeNode?.tagName !== "code") return;
|
|
87
|
-
node.properties = node.properties ?? {};
|
|
88
|
-
codeNode.properties = codeNode.properties ?? {};
|
|
89
|
-
const code = getTextContent(codeNode);
|
|
90
|
-
const language = typeof node.properties.language === "string" ? node.properties.language : getLanguage(codeNode.properties.className);
|
|
91
|
-
node.properties.code = code;
|
|
92
|
-
codeNode.properties.code = code;
|
|
93
|
-
codeNode.properties.language = language;
|
|
94
|
-
let highlighted = renderPlainCode(code);
|
|
95
|
-
if (language && language !== "txt") try {
|
|
96
|
-
highlighted = renderHighlightedCode(shikiHighlighter.codeToHtml(code, {
|
|
97
|
-
lang: language,
|
|
98
|
-
theme: cssVariablesTheme
|
|
99
|
-
}));
|
|
100
|
-
} catch {
|
|
101
|
-
highlighted = renderPlainCode(code);
|
|
102
|
-
}
|
|
103
|
-
codeNode.children = [{
|
|
104
|
-
type: "text",
|
|
105
|
-
value: highlighted
|
|
106
|
-
}];
|
|
107
|
-
});
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
function rehypeSlugSections() {
|
|
111
|
-
return (tree) => {
|
|
112
|
-
const slugger = new GithubSlugger();
|
|
113
|
-
visit(tree, "element", (node) => {
|
|
114
|
-
if (node.tagName !== "h2" && node.tagName !== "h3") return;
|
|
115
|
-
node.properties = node.properties ?? {};
|
|
116
|
-
if (node.properties.id) return;
|
|
117
|
-
node.properties.id = slugger.slug(toString(node));
|
|
118
|
-
});
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
47
|
var remarkPlugins = markdownRemarkPlugins;
|
|
122
48
|
var rehypePlugins = [
|
|
123
|
-
|
|
49
|
+
rehypeSlug,
|
|
124
50
|
rehypeParseCodeBlocks,
|
|
125
|
-
rehypeShiki
|
|
51
|
+
[rehypeShiki, {
|
|
52
|
+
theme: cssVariablesTheme,
|
|
53
|
+
langs: [],
|
|
54
|
+
lazy: true,
|
|
55
|
+
addLanguageClass: true,
|
|
56
|
+
fallbackLanguage: "text",
|
|
57
|
+
parseMetaString: parseCodeMeta
|
|
58
|
+
}]
|
|
126
59
|
];
|
|
127
60
|
function formatMdxDiagnostic(error) {
|
|
128
61
|
if (error instanceof Error) return error.message;
|
|
@@ -134,7 +67,8 @@ function formatMdxDiagnostic(error) {
|
|
|
134
67
|
*
|
|
135
68
|
* `rehypePlugins` includes `rehypeShiki`, which loads grammar/WASM assets and
|
|
136
69
|
* is expensive. The real highlighting happens at Vite build time via the
|
|
137
|
-
* `@mdx-js/rollup`
|
|
70
|
+
* `@mdx-js/rollup` plugins (see `createMarkdownPlugin` and `createMdxPlugin`
|
|
71
|
+
* in `core/adapters.ts`), which
|
|
138
72
|
* runs the full remark + rehype pipeline. Re-running it here, during route
|
|
139
73
|
* discovery (Phase 3), would compile every `.mdx` file twice and invoke Shiki
|
|
140
74
|
* once per file per `engine.refresh()` — see ARCHITECTURE.md §2.2 which states
|
|
@@ -283,6 +217,11 @@ function kebabToTitle(str) {
|
|
|
283
217
|
function parseMdxTree(content) {
|
|
284
218
|
return remark.parse(content);
|
|
285
219
|
}
|
|
220
|
+
async function compileRouteDiagnostic(content, filePath, baseDir) {
|
|
221
|
+
if (extname(filePath).toLowerCase() !== ".mdx") return void 0;
|
|
222
|
+
const result = await compileMdxContent(content, filePath, baseDir);
|
|
223
|
+
return result.ok ? void 0 : result.diagnostic;
|
|
224
|
+
}
|
|
286
225
|
/** 从内容中提取第一个 H1 标题 */
|
|
287
226
|
function extractH1(content) {
|
|
288
227
|
const tree = parseMdxTree(content);
|
|
@@ -308,12 +247,12 @@ function extractMdxSections(content) {
|
|
|
308
247
|
return sections;
|
|
309
248
|
}
|
|
310
249
|
function navigationSections(sections) {
|
|
311
|
-
return sections.map((
|
|
312
|
-
id:
|
|
313
|
-
title:
|
|
314
|
-
level:
|
|
315
|
-
badge:
|
|
316
|
-
tags:
|
|
250
|
+
return sections.map((section) => ({
|
|
251
|
+
id: section.id,
|
|
252
|
+
title: section.title,
|
|
253
|
+
level: section.level,
|
|
254
|
+
badge: section.badge,
|
|
255
|
+
tags: section.tags
|
|
317
256
|
}));
|
|
318
257
|
}
|
|
319
258
|
function normalizePath(path) {
|
|
@@ -377,7 +316,7 @@ async function findContentRoutes(dir, base = dir, options = {}) {
|
|
|
377
316
|
frontmatter,
|
|
378
317
|
content
|
|
379
318
|
};
|
|
380
|
-
const
|
|
319
|
+
const diagnostic = await compileRouteDiagnostic(page.content, fullPath, base);
|
|
381
320
|
let title = typeof page.frontmatter.title === "string" ? page.frontmatter.title : "";
|
|
382
321
|
if (!title) {
|
|
383
322
|
const lastPart = pathParts[pathParts.length - 1] ?? "";
|
|
@@ -385,17 +324,21 @@ async function findContentRoutes(dir, base = dir, options = {}) {
|
|
|
385
324
|
}
|
|
386
325
|
routes.push({
|
|
387
326
|
kind: "mdx",
|
|
388
|
-
title,
|
|
389
327
|
path: cleanPath,
|
|
390
328
|
basePath: cleanPath,
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
329
|
+
meta: {
|
|
330
|
+
title,
|
|
331
|
+
description: typeof page.frontmatter.description === "string" ? page.frontmatter.description : void 0,
|
|
332
|
+
keywords: frontmatterKeywords(page.frontmatter),
|
|
333
|
+
sections: extractMdxSections(page.content)
|
|
334
|
+
},
|
|
335
|
+
module: { virtualModuleId: "virtual:clarify-page/" + relativePath.replace(/\.mdx?$/, "").replace(/\/+/g, "/") },
|
|
336
|
+
source: {
|
|
337
|
+
filePath: fullPath,
|
|
338
|
+
frontmatter: page.frontmatter,
|
|
339
|
+
content: page.content
|
|
340
|
+
},
|
|
341
|
+
diagnostic
|
|
399
342
|
});
|
|
400
343
|
}
|
|
401
344
|
}
|
|
@@ -454,7 +397,7 @@ async function findLocalizedContentRoutes(contentRoot, i18n, options = {}) {
|
|
|
454
397
|
path: localizedRoutePath(basePath, locale.code, i18n),
|
|
455
398
|
basePath,
|
|
456
399
|
locale: locale.code,
|
|
457
|
-
virtualModuleId: virtualModuleIdForLocalizedRoute(contentRoot, route.filePath)
|
|
400
|
+
module: { virtualModuleId: virtualModuleIdForLocalizedRoute(contentRoot, route.source.filePath) }
|
|
458
401
|
});
|
|
459
402
|
}
|
|
460
403
|
}
|
|
@@ -490,12 +433,12 @@ function buildNavigation(routes) {
|
|
|
490
433
|
if (!node) {
|
|
491
434
|
node = {
|
|
492
435
|
path: pathSoFar,
|
|
493
|
-
title: i === parts.length - 1 ? route.title : kebabToTitle(parts[i]),
|
|
436
|
+
title: i === parts.length - 1 ? route.meta.title : kebabToTitle(parts[i]),
|
|
494
437
|
children: []
|
|
495
438
|
};
|
|
496
439
|
current.push(node);
|
|
497
440
|
}
|
|
498
|
-
if (i === parts.length - 1 && route.sections) node.sections = navigationSections(route.sections);
|
|
441
|
+
if (i === parts.length - 1 && route.meta.sections) node.sections = navigationSections(route.meta.sections);
|
|
499
442
|
if (i < parts.length - 1) {
|
|
500
443
|
node.children = node.children ?? [];
|
|
501
444
|
current = node.children;
|
|
@@ -504,17 +447,22 @@ function buildNavigation(routes) {
|
|
|
504
447
|
}
|
|
505
448
|
return root;
|
|
506
449
|
}
|
|
507
|
-
function
|
|
508
|
-
if (typeof item === "string") return {
|
|
450
|
+
function routeIntentFromPagesItem(item) {
|
|
451
|
+
if (typeof item === "string") return {
|
|
452
|
+
kind: "page",
|
|
453
|
+
ref: item
|
|
454
|
+
};
|
|
509
455
|
if ("openapi" in item) return {
|
|
510
|
-
|
|
511
|
-
|
|
456
|
+
kind: "openapi",
|
|
457
|
+
ref: item.openapi,
|
|
458
|
+
tagFilter: item.filter?.tags,
|
|
512
459
|
path: item.path,
|
|
513
460
|
title: item.title,
|
|
514
461
|
icon: item.icon
|
|
515
462
|
};
|
|
516
463
|
return {
|
|
517
|
-
|
|
464
|
+
kind: "page",
|
|
465
|
+
ref: item.page,
|
|
518
466
|
path: item.path,
|
|
519
467
|
redirect: item.redirect,
|
|
520
468
|
title: item.title,
|
|
@@ -529,25 +477,28 @@ function firstNavigationPath(nodes) {
|
|
|
529
477
|
}
|
|
530
478
|
return "/";
|
|
531
479
|
}
|
|
532
|
-
function
|
|
533
|
-
const
|
|
480
|
+
function collectExplicitPagePathIntents(tabs) {
|
|
481
|
+
const intents = [];
|
|
534
482
|
for (const tab of tabs ?? []) {
|
|
535
483
|
if (!tab.pages || tab.pages === "FileTree") continue;
|
|
536
|
-
for (const group of tab.pages) for (const item of group.pages) if (typeof item !== "string" && "page" in item && item.path)
|
|
537
|
-
|
|
538
|
-
path
|
|
539
|
-
|
|
484
|
+
for (const group of tab.pages) for (const item of group.pages) if (typeof item !== "string" && "page" in item && item.path) {
|
|
485
|
+
const intent = routeIntentFromPagesItem(item);
|
|
486
|
+
if (intent.kind === "page" && intent.path) intents.push({
|
|
487
|
+
...intent,
|
|
488
|
+
path: intent.path
|
|
489
|
+
});
|
|
490
|
+
}
|
|
540
491
|
}
|
|
541
|
-
return
|
|
492
|
+
return intents;
|
|
542
493
|
}
|
|
543
494
|
function applyConfiguredPageRoutePaths(routes, tabs, i18n) {
|
|
544
|
-
const
|
|
545
|
-
if (!
|
|
495
|
+
const pageIntents = collectExplicitPagePathIntents(tabs);
|
|
496
|
+
if (!pageIntents.length) return routes;
|
|
546
497
|
const additions = [];
|
|
547
498
|
const existingKeys = new Set(routes.map((route) => `${route.locale ?? ""}:${route.basePath ?? route.path}`));
|
|
548
|
-
for (const
|
|
549
|
-
const sourceBasePath = routePathFromRef(
|
|
550
|
-
const targetBasePath = routePathFromRef(
|
|
499
|
+
for (const intent of pageIntents) {
|
|
500
|
+
const sourceBasePath = routePathFromRef(intent.ref);
|
|
501
|
+
const targetBasePath = routePathFromRef(intent.ref, intent.path);
|
|
551
502
|
if (sourceBasePath === targetBasePath) continue;
|
|
552
503
|
for (const route of routes) {
|
|
553
504
|
if (route.kind !== "mdx" || (route.basePath ?? route.path) !== sourceBasePath) continue;
|
|
@@ -571,40 +522,42 @@ function buildNavigationFromPagesConfig(routes, config) {
|
|
|
571
522
|
return buildNavigationFromConfig(routes, config);
|
|
572
523
|
}
|
|
573
524
|
function buildNavigationFromTabsConfig(routes, tabs) {
|
|
574
|
-
return {
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
525
|
+
return {
|
|
526
|
+
kind: "tabbed",
|
|
527
|
+
tabs: tabs.map((tab) => {
|
|
528
|
+
const children = buildNavigationFromPagesConfig(routes, tab.pages);
|
|
529
|
+
return {
|
|
530
|
+
type: "tab",
|
|
531
|
+
path: firstNavigationPath(children),
|
|
532
|
+
title: resolveLocalizedText(tab.tab, "", "") ?? "",
|
|
533
|
+
icon: tab.icon,
|
|
534
|
+
children
|
|
535
|
+
};
|
|
536
|
+
})
|
|
537
|
+
};
|
|
584
538
|
}
|
|
585
539
|
function buildNavigationFromConfig(routes, config) {
|
|
586
540
|
const routeMap = new Map(routes.map((r) => [r.path, r]));
|
|
587
541
|
return config.map((group) => {
|
|
588
542
|
const children = group.pages.map((item) => {
|
|
589
|
-
const
|
|
590
|
-
if (
|
|
591
|
-
const path = openAPIPagePathFromRef(
|
|
543
|
+
const intent = routeIntentFromPagesItem(item);
|
|
544
|
+
if (intent.kind === "openapi") {
|
|
545
|
+
const path = openAPIPagePathFromRef(intent.ref, intent.tagFilter, intent.path);
|
|
592
546
|
const route = routeMap.get(path);
|
|
593
547
|
return {
|
|
594
548
|
path,
|
|
595
|
-
title: resolveLocalizedText(title, "", "") ?? route?.title ?? kebabToTitle(path.split("/").pop() ??
|
|
596
|
-
icon,
|
|
597
|
-
sections: route?.sections ? navigationSections(route.sections) : void 0
|
|
549
|
+
title: resolveLocalizedText(intent.title, "", "") ?? route?.meta.title ?? kebabToTitle(path.split("/").pop() ?? intent.ref),
|
|
550
|
+
icon: intent.icon,
|
|
551
|
+
sections: route?.meta.sections ? navigationSections(route.meta.sections) : void 0
|
|
598
552
|
};
|
|
599
553
|
}
|
|
600
|
-
const
|
|
601
|
-
const path = routePathFromRef(ref, explicitPath);
|
|
554
|
+
const path = routePathFromRef(intent.ref, intent.path);
|
|
602
555
|
const route = routeMap.get(path);
|
|
603
556
|
return {
|
|
604
|
-
path: redirect ? normalizePath(redirect) : path,
|
|
605
|
-
title: resolveLocalizedText(title, "", "") ?? route?.title ?? kebabToTitle(path.split("/").pop() ?? ref),
|
|
606
|
-
icon,
|
|
607
|
-
sections: route?.sections ? navigationSections(route.sections) : void 0
|
|
557
|
+
path: intent.redirect ? normalizePath(intent.redirect) : path,
|
|
558
|
+
title: resolveLocalizedText(intent.title, "", "") ?? route?.meta.title ?? kebabToTitle(path.split("/").pop() ?? intent.ref),
|
|
559
|
+
icon: intent.icon,
|
|
560
|
+
sections: route?.meta.sections ? navigationSections(route.meta.sections) : void 0
|
|
608
561
|
};
|
|
609
562
|
});
|
|
610
563
|
return {
|
|
@@ -630,16 +583,15 @@ function buildLocalizedNavigationForLocale(routes, config, locale, i18n) {
|
|
|
630
583
|
const routeMap = new Map(routes.map((route) => [route.basePath ?? route.path, route]));
|
|
631
584
|
return config.map((group) => {
|
|
632
585
|
const children = group.pages.map((item) => {
|
|
633
|
-
const
|
|
634
|
-
const
|
|
635
|
-
const basePath = openapiRef ? openAPIPagePathFromRef(openapiRef, openapiTagFilter, explicitPath) : routePathFromRef(ref, explicitPath);
|
|
586
|
+
const intent = routeIntentFromPagesItem(item);
|
|
587
|
+
const basePath = intent.kind === "openapi" ? openAPIPagePathFromRef(intent.ref, intent.tagFilter, intent.path) : routePathFromRef(intent.ref, intent.path);
|
|
636
588
|
const route = routeMap.get(basePath);
|
|
637
589
|
const path = route?.path ?? localizedRoutePath(basePath, locale, i18n);
|
|
638
590
|
return {
|
|
639
|
-
path: (redirect ? localizedRoutePath(routePathFromRef(redirect), locale, i18n) : void 0) ?? path,
|
|
640
|
-
title: resolveLocalizedText(title, locale, i18n.defaultLocale) ?? route?.title ?? kebabToTitle(basePath.split("/").pop() ?? ref),
|
|
641
|
-
icon,
|
|
642
|
-
sections: route?.sections ? navigationSections(route.sections) : void 0
|
|
591
|
+
path: (intent.kind === "page" && intent.redirect ? localizedRoutePath(routePathFromRef(intent.redirect), locale, i18n) : void 0) ?? path,
|
|
592
|
+
title: resolveLocalizedText(intent.title, locale, i18n.defaultLocale) ?? route?.meta.title ?? kebabToTitle(basePath.split("/").pop() ?? intent.ref),
|
|
593
|
+
icon: intent.icon,
|
|
594
|
+
sections: route?.meta.sections ? navigationSections(route.meta.sections) : void 0
|
|
643
595
|
};
|
|
644
596
|
});
|
|
645
597
|
return {
|
|
@@ -652,10 +604,10 @@ function buildLocalizedNavigationForLocale(routes, config, locale, i18n) {
|
|
|
652
604
|
}
|
|
653
605
|
function buildLocalizedNavigationFromTabsConfig(routes, tabs, i18n) {
|
|
654
606
|
if (!i18n) return void 0;
|
|
655
|
-
const
|
|
607
|
+
const locales = {};
|
|
656
608
|
for (const locale of i18n.locales) {
|
|
657
609
|
const localeRoutes = routes.filter((route) => route.locale === locale.code);
|
|
658
|
-
|
|
610
|
+
locales[locale.code] = { tabs: tabs.map((tab) => {
|
|
659
611
|
const children = buildLocalizedNavigationForLocale(localeRoutes, tab.pages, locale.code, i18n);
|
|
660
612
|
return {
|
|
661
613
|
type: "tab",
|
|
@@ -666,17 +618,20 @@ function buildLocalizedNavigationFromTabsConfig(routes, tabs, i18n) {
|
|
|
666
618
|
};
|
|
667
619
|
}) };
|
|
668
620
|
}
|
|
669
|
-
return
|
|
621
|
+
return {
|
|
622
|
+
kind: "localized-tabbed",
|
|
623
|
+
locales
|
|
624
|
+
};
|
|
670
625
|
}
|
|
671
626
|
/** Serialize a ContentRoute into the minimal shape exposed to tooling. */
|
|
672
627
|
function toDevRouteEntry(route) {
|
|
673
628
|
return {
|
|
674
629
|
path: route.path,
|
|
675
|
-
filePath: route.filePath,
|
|
630
|
+
filePath: route.source.filePath,
|
|
676
631
|
locale: route.locale,
|
|
677
632
|
basePath: route.basePath,
|
|
678
633
|
kind: route.kind,
|
|
679
|
-
title: route.title
|
|
634
|
+
title: route.meta.title
|
|
680
635
|
};
|
|
681
636
|
}
|
|
682
637
|
/**
|
|
@@ -690,7 +645,7 @@ function toDevRouteEntry(route) {
|
|
|
690
645
|
* or the first match.
|
|
691
646
|
*/
|
|
692
647
|
function resolveRouteForFile(filePath, routes, defaultLocale) {
|
|
693
|
-
const matches = routes.filter((r) => r.filePath === filePath);
|
|
648
|
+
const matches = routes.filter((r) => r.source.filePath === filePath);
|
|
694
649
|
if (matches.length === 0) return void 0;
|
|
695
650
|
if (matches.length === 1) return matches[0];
|
|
696
651
|
const fileLocale = inferLocaleFromPath(filePath);
|
|
@@ -1115,6 +1070,7 @@ var VIRTUAL_CONFIG = "virtual:clarify/config";
|
|
|
1115
1070
|
var VIRTUAL_ROUTES = "virtual:clarify/routes";
|
|
1116
1071
|
var VIRTUAL_SERVER_ROUTES = "virtual:clarify/routes/server";
|
|
1117
1072
|
var VIRTUAL_OPENAPI = "virtual:clarify/openapi";
|
|
1073
|
+
var VIRTUAL_OPENAPI_SERVER = "virtual:clarify/openapi/server";
|
|
1118
1074
|
var VIRTUAL_SLOTS = "virtual:clarify/slots";
|
|
1119
1075
|
var VIRTUAL_SLOT = "virtual:clarify/slot";
|
|
1120
1076
|
var VIRTUAL_CLIENT_ENTRY = "virtual:clarify/entry-client";
|
|
@@ -1135,6 +1091,7 @@ var FIXED_VIRTUAL_IDS = [
|
|
|
1135
1091
|
VIRTUAL_ROUTES,
|
|
1136
1092
|
VIRTUAL_SERVER_ROUTES,
|
|
1137
1093
|
VIRTUAL_OPENAPI,
|
|
1094
|
+
VIRTUAL_OPENAPI_SERVER,
|
|
1138
1095
|
VIRTUAL_SLOTS,
|
|
1139
1096
|
VIRTUAL_SLOT
|
|
1140
1097
|
];
|
|
@@ -1151,8 +1108,8 @@ function resolveVirtualModuleId(id, modules, routes) {
|
|
|
1151
1108
|
for (const virtualId of FIXED_VIRTUAL_IDS) if (id === virtualId || id === resolveVirtualId(virtualId)) return resolveVirtualId(virtualId);
|
|
1152
1109
|
const moduleId = stripVirtualPrefix(id);
|
|
1153
1110
|
if (modules.has(moduleId)) return resolveVirtualId(moduleId);
|
|
1154
|
-
const route = routes.find((route) => route.virtualModuleId === id || route.virtualModuleId === moduleId);
|
|
1155
|
-
if (route) return resolveVirtualId(route.virtualModuleId);
|
|
1111
|
+
const route = routes.find((route) => route.module.virtualModuleId === id || route.module.virtualModuleId === moduleId);
|
|
1112
|
+
if (route) return resolveVirtualId(route.module.virtualModuleId);
|
|
1156
1113
|
return null;
|
|
1157
1114
|
}
|
|
1158
1115
|
function generateConfigModule(projectConfig, buildOptions, version) {
|
|
@@ -1166,38 +1123,38 @@ function generateConfigModule(projectConfig, buildOptions, version) {
|
|
|
1166
1123
|
function moduleSpecifier(value) {
|
|
1167
1124
|
return JSON.stringify(value);
|
|
1168
1125
|
}
|
|
1169
|
-
function
|
|
1170
|
-
const
|
|
1126
|
+
function routeToRuntimeManifestEntry(route, component, mode) {
|
|
1127
|
+
const entry = {
|
|
1171
1128
|
path: route.path,
|
|
1172
|
-
title: route.title,
|
|
1129
|
+
title: route.meta.title,
|
|
1173
1130
|
component,
|
|
1174
1131
|
kind: route.kind
|
|
1175
1132
|
};
|
|
1176
|
-
if (mode === "client")
|
|
1177
|
-
if (route.basePath)
|
|
1178
|
-
if (route.locale)
|
|
1179
|
-
if (route.isFallback)
|
|
1180
|
-
if (route.isBareAlias)
|
|
1181
|
-
if (route.alternates)
|
|
1182
|
-
if (route.description)
|
|
1183
|
-
if (route.keywords?.length)
|
|
1184
|
-
if (route.contentArtifactUrl)
|
|
1185
|
-
if (route.
|
|
1186
|
-
if (route.sections?.length)
|
|
1187
|
-
id:
|
|
1188
|
-
title:
|
|
1189
|
-
level:
|
|
1190
|
-
badge:
|
|
1191
|
-
tags:
|
|
1133
|
+
if (mode === "client") entry.lazy = true;
|
|
1134
|
+
if (route.basePath) entry.basePath = route.basePath;
|
|
1135
|
+
if (route.locale) entry.locale = route.locale;
|
|
1136
|
+
if (route.isFallback) entry.isFallback = true;
|
|
1137
|
+
if (route.isBareAlias) entry.isBareAlias = true;
|
|
1138
|
+
if (route.alternates) entry.alternates = route.alternates;
|
|
1139
|
+
if (route.meta.description) entry.description = route.meta.description;
|
|
1140
|
+
if (route.meta.keywords?.length) entry.keywords = route.meta.keywords;
|
|
1141
|
+
if (route.artifacts?.contentArtifactUrl) entry.contentArtifactUrl = route.artifacts.contentArtifactUrl;
|
|
1142
|
+
if (route.source?.sourceEditUrl) entry.sourceEditUrl = route.source.sourceEditUrl;
|
|
1143
|
+
if (route.meta.sections?.length) entry.sections = route.meta.sections.map((section) => ({
|
|
1144
|
+
id: section.id,
|
|
1145
|
+
title: section.title,
|
|
1146
|
+
level: section.level,
|
|
1147
|
+
badge: section.badge,
|
|
1148
|
+
tags: section.tags
|
|
1192
1149
|
}));
|
|
1193
|
-
return
|
|
1150
|
+
return entry;
|
|
1194
1151
|
}
|
|
1195
1152
|
function generateRoutesModule(routes, navigation, mode = "client") {
|
|
1196
|
-
return `${mode === "server" ? routes.map((r, i) => `import Page${i} from ${moduleSpecifier(r.virtualModuleId)};`).join("\n") : `import { createContentDiagnosticComponent } from '@clarify-labs/renderer';`}\n\nexport const routes = [\n${routes.map((r, i) => {
|
|
1197
|
-
const component = mode === "server" ? `Page${i}` : `() => import(${moduleSpecifier(r.virtualModuleId)}).catch((error) => Promise.resolve({ default: createContentDiagnosticComponent({ kind: 'route-load', title: 'This page could not be loaded', message: error instanceof Error ? error.message : String(error), details: error instanceof Error ? error.stack : undefined }) }))`;
|
|
1153
|
+
return `${mode === "server" ? routes.map((r, i) => `import Page${i} from ${moduleSpecifier(r.module.virtualModuleId)};`).join("\n") : `import { createContentDiagnosticComponent } from '@clarify-labs/renderer';`}\n\nexport const routes = [\n${routes.map((r, i) => {
|
|
1154
|
+
const component = mode === "server" ? `Page${i}` : `() => import(${moduleSpecifier(r.module.virtualModuleId)}).catch((error) => Promise.resolve({ default: createContentDiagnosticComponent({ kind: 'route-load', title: 'This page could not be loaded', message: error instanceof Error ? error.message : String(error), details: error instanceof Error ? error.stack : undefined }) }))`;
|
|
1198
1155
|
const placeholder = `__COMPONENT_${i}__`;
|
|
1199
|
-
const
|
|
1200
|
-
return ` ${JSON.stringify(
|
|
1156
|
+
const manifestEntry = routeToRuntimeManifestEntry(r, placeholder, mode);
|
|
1157
|
+
return ` ${JSON.stringify(manifestEntry, null, 0).replace(`"${placeholder}"`, component).replace(/"([A-Za-z_$][\w$]*)":/g, "$1: ")}`;
|
|
1201
1158
|
}).join(",\n")}\n];\n\nexport const navigation = ${JSON.stringify(navigation, null, 2)};\n`;
|
|
1202
1159
|
}
|
|
1203
1160
|
function createClientEntryModule(options = {}) {
|
|
@@ -1206,9 +1163,15 @@ import '@clarify-labs/renderer/style.css';
|
|
|
1206
1163
|
import { render } from '@clarify-labs/renderer/client';
|
|
1207
1164
|
import { routes, navigation } from '${VIRTUAL_ROUTES}';
|
|
1208
1165
|
import { config } from '${VIRTUAL_CONFIG}';
|
|
1209
|
-
import {
|
|
1166
|
+
import { openApiSpecs } from '${VIRTUAL_OPENAPI}';
|
|
1210
1167
|
import { runtimeSlots } from '${VIRTUAL_SLOTS}';
|
|
1211
|
-
|
|
1168
|
+
const renderOptions = { config, routes, navigation, openApiSpecs, runtimeSlots, themeEditor: ${JSON.stringify(options.themeEditor ?? false)} };
|
|
1169
|
+
render(renderOptions);
|
|
1170
|
+
if (import.meta.hot) {
|
|
1171
|
+
import.meta.hot.accept('${VIRTUAL_ROUTES}', (mod) => {
|
|
1172
|
+
render({ ...renderOptions, routes: mod.routes, navigation: mod.navigation });
|
|
1173
|
+
});
|
|
1174
|
+
}`;
|
|
1212
1175
|
}
|
|
1213
1176
|
/**
|
|
1214
1177
|
* Collect every plugin's `slots` declarations into a single runtime registry
|
|
@@ -1237,7 +1200,7 @@ function createRuntimeSlotsModule(plugins = [], root = process.cwd()) {
|
|
|
1237
1200
|
}
|
|
1238
1201
|
if (!slot.component.startsWith("/")) throw new Error(`[clarify] Plugin "${plugin}" slot "${slot.name}" has an invalid component path "${slot.component}". Component paths must start with "/" to reference the project root.`);
|
|
1239
1202
|
const componentPath = root + slot.component;
|
|
1240
|
-
const entry = `{ plugin: ${JSON.stringify(plugin)},
|
|
1203
|
+
const entry = `{ plugin: ${JSON.stringify(plugin)}, loadComponent: () => import(${moduleSpecifier(componentPath)}) }`;
|
|
1241
1204
|
const list = grouped.get(slot.name) ?? [];
|
|
1242
1205
|
list.push(entry);
|
|
1243
1206
|
grouped.set(slot.name, list);
|
|
@@ -1266,18 +1229,34 @@ function buildVirtualModules(args) {
|
|
|
1266
1229
|
modules.set(VIRTUAL_ROUTES, generateRoutesModule(args.routes, args.navigation, "client"));
|
|
1267
1230
|
modules.set(VIRTUAL_SERVER_ROUTES, generateRoutesModule(args.routes, args.navigation, "server"));
|
|
1268
1231
|
modules.set(VIRTUAL_SLOTS, createRuntimeSlotsModule(allPlugins, args.generateOptions.projectRoot));
|
|
1269
|
-
modules.set(VIRTUAL_OPENAPI, "export const
|
|
1232
|
+
modules.set(VIRTUAL_OPENAPI, "export const openApiSpecs = {};");
|
|
1270
1233
|
modules.set(VIRTUAL_SLOT, "export { useSlot } from '@clarify-labs/renderer';\n");
|
|
1271
1234
|
modules.set(VIRTUAL_CLIENT_ENTRY, clientEntryModule);
|
|
1272
1235
|
modules.set(RESOLVED_CLIENT_ENTRY, clientEntryModule);
|
|
1273
1236
|
for (const route of args.routes) {
|
|
1274
|
-
const moduleContent = route.diagnostic ? generateMdxErrorModule(route.diagnostic) : `export { default } from ${moduleSpecifier(route.filePath)};`;
|
|
1275
|
-
modules.set(route.virtualModuleId, moduleContent);
|
|
1237
|
+
const moduleContent = route.diagnostic ? generateMdxErrorModule(route.diagnostic) : `export { default } from ${moduleSpecifier(route.source.filePath)};`;
|
|
1238
|
+
modules.set(route.module.virtualModuleId, moduleContent);
|
|
1276
1239
|
}
|
|
1277
1240
|
return modules;
|
|
1278
1241
|
}
|
|
1279
1242
|
//#endregion
|
|
1280
1243
|
//#region source/core/adapters.ts
|
|
1244
|
+
function routeStructure(route) {
|
|
1245
|
+
const { content: _content, ...source } = route.source;
|
|
1246
|
+
return {
|
|
1247
|
+
...route,
|
|
1248
|
+
source
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
function createDevStructureSnapshot(routes, navigation) {
|
|
1252
|
+
return {
|
|
1253
|
+
routes: JSON.stringify(routes.map(routeStructure)),
|
|
1254
|
+
navigation: JSON.stringify(navigation)
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
function hasDevStructureChanged(before, after) {
|
|
1258
|
+
return before.routes !== after.routes || before.navigation !== after.navigation;
|
|
1259
|
+
}
|
|
1281
1260
|
function invalidateVirtualModules(engine, server) {
|
|
1282
1261
|
for (const id of engine.modules.keys()) {
|
|
1283
1262
|
const moduleNode = server.moduleGraph.getModuleById(resolveVirtualId(id));
|
|
@@ -1285,20 +1264,22 @@ function invalidateVirtualModules(engine, server) {
|
|
|
1285
1264
|
}
|
|
1286
1265
|
}
|
|
1287
1266
|
async function refreshDevServer(engine, server) {
|
|
1267
|
+
const before = createDevStructureSnapshot(engine.routes, engine.navigation);
|
|
1288
1268
|
await engine.refresh();
|
|
1289
1269
|
invalidateVirtualModules(engine, server);
|
|
1270
|
+
return hasDevStructureChanged(before, createDevStructureSnapshot(engine.routes, engine.navigation));
|
|
1290
1271
|
}
|
|
1291
|
-
function
|
|
1272
|
+
function createNormalizedContentPlugin(engine) {
|
|
1292
1273
|
return {
|
|
1293
|
-
name: "clarify:normalized-
|
|
1274
|
+
name: "clarify:normalized-content",
|
|
1294
1275
|
enforce: "pre",
|
|
1295
1276
|
transform(_code, id) {
|
|
1296
1277
|
if (!/\.mdx?(?:\?|$)/.test(id)) return null;
|
|
1297
1278
|
const filePath = id.replace(/\?.*$/, "");
|
|
1298
|
-
const route = engine.routes.find((route) => route.kind === "mdx" && route.filePath === filePath);
|
|
1299
|
-
if (!route || route.content === void 0) return null;
|
|
1279
|
+
const route = engine.routes.find((route) => route.kind === "mdx" && route.source.filePath === filePath);
|
|
1280
|
+
if (!route || route.source.content === void 0) return null;
|
|
1300
1281
|
return {
|
|
1301
|
-
code: route.content,
|
|
1282
|
+
code: route.source.content,
|
|
1302
1283
|
map: null
|
|
1303
1284
|
};
|
|
1304
1285
|
}
|
|
@@ -1306,14 +1287,26 @@ function createNormalizedMdxContentPlugin(engine) {
|
|
|
1306
1287
|
}
|
|
1307
1288
|
function createMdxPlugin() {
|
|
1308
1289
|
return mdxPlugin({
|
|
1309
|
-
include: ["**/*.
|
|
1290
|
+
include: ["**/*.mdx"],
|
|
1291
|
+
format: "mdx",
|
|
1310
1292
|
jsxImportSource: "react",
|
|
1311
1293
|
providerImportSource: "@clarify-labs/renderer",
|
|
1312
1294
|
remarkPlugins,
|
|
1313
1295
|
rehypePlugins
|
|
1314
1296
|
});
|
|
1315
1297
|
}
|
|
1316
|
-
function
|
|
1298
|
+
function createMarkdownPlugin() {
|
|
1299
|
+
return mdxPlugin({
|
|
1300
|
+
include: ["**/*.md"],
|
|
1301
|
+
format: "md",
|
|
1302
|
+
jsxImportSource: "react",
|
|
1303
|
+
providerImportSource: "@clarify-labs/renderer",
|
|
1304
|
+
remarkPlugins,
|
|
1305
|
+
remarkRehypeOptions: { allowDangerousHtml: true },
|
|
1306
|
+
rehypePlugins: [rehypeRaw, ...rehypePlugins]
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
function createClarifyViteCorePlugin(engine, normalizedContentPlugin, markdown, mdx) {
|
|
1317
1310
|
let viteConfig;
|
|
1318
1311
|
return {
|
|
1319
1312
|
name: "clarify:core",
|
|
@@ -1352,8 +1345,13 @@ function createClarifyViteCorePlugin(engine, normalizedMdxContentPlugin, mdx) {
|
|
|
1352
1345
|
}
|
|
1353
1346
|
const relativeContentFile = relative(engine.contentRoot, changedFile);
|
|
1354
1347
|
if (!(relativeContentFile && !relativeContentFile.startsWith("..") && !isAbsolute(relativeContentFile)) || !engine.hasContentRouteForFile(changedFile)) return;
|
|
1355
|
-
await refreshDevServer(engine, ctx.server)
|
|
1356
|
-
|
|
1348
|
+
if (await refreshDevServer(engine, ctx.server)) {
|
|
1349
|
+
const routesModule = ctx.server.moduleGraph.getModuleById(resolveVirtualId(VIRTUAL_ROUTES));
|
|
1350
|
+
if (routesModule) return [...ctx.modules, routesModule];
|
|
1351
|
+
ctx.server.ws.send({ type: "full-reload" });
|
|
1352
|
+
return [];
|
|
1353
|
+
}
|
|
1354
|
+
return ctx.modules;
|
|
1357
1355
|
},
|
|
1358
1356
|
resolveId(id) {
|
|
1359
1357
|
return resolveVirtualModuleId(id, engine.modules, engine.routes);
|
|
@@ -1364,18 +1362,6 @@ function createClarifyViteCorePlugin(engine, normalizedMdxContentPlugin, mdx) {
|
|
|
1364
1362
|
async configureServer(server) {
|
|
1365
1363
|
server.watcher.add(engine.contentRoot);
|
|
1366
1364
|
if (engine.configFilePath) server.watcher.add(engine.configFilePath);
|
|
1367
|
-
let reloadQueued = false;
|
|
1368
|
-
const invalidateAndReload = () => {
|
|
1369
|
-
if (reloadQueued) return;
|
|
1370
|
-
reloadQueued = true;
|
|
1371
|
-
queueMicrotask(() => {
|
|
1372
|
-
reloadQueued = false;
|
|
1373
|
-
invalidateVirtualModules(engine, server);
|
|
1374
|
-
server.ws.send({ type: "full-reload" });
|
|
1375
|
-
});
|
|
1376
|
-
};
|
|
1377
|
-
engine.ctx.onRoutesChange(invalidateAndReload);
|
|
1378
|
-
engine.ctx.onNavigationChange(invalidateAndReload);
|
|
1379
1365
|
server.middlewares.use((req, res, next) => {
|
|
1380
1366
|
if (req.url === "/dev/query-preview-route" && req.method === "POST") return handleDevRouteRequest(req, res, engine.routes, engine.runtimeContext());
|
|
1381
1367
|
if (req.url === "/dev/project-info" && (req.method === "GET" || req.method === "HEAD")) return handleProjectInfoRequest(req, res, engine.runtimeContext());
|
|
@@ -1385,7 +1371,7 @@ function createClarifyViteCorePlugin(engine, normalizedMdxContentPlugin, mdx) {
|
|
|
1385
1371
|
const changedFile = isAbsolute(filePath) ? filePath : join(engine.root, filePath);
|
|
1386
1372
|
const relativeContentFile = relative(engine.contentRoot, changedFile);
|
|
1387
1373
|
if (!(relativeContentFile && !relativeContentFile.startsWith("..") && !isAbsolute(relativeContentFile))) return;
|
|
1388
|
-
await refreshDevServer(engine, server);
|
|
1374
|
+
if (await refreshDevServer(engine, server)) server.ws.send({ type: "full-reload" });
|
|
1389
1375
|
};
|
|
1390
1376
|
server.watcher.on("add", handleContentTreeChange);
|
|
1391
1377
|
server.watcher.on("unlink", handleContentTreeChange);
|
|
@@ -1422,7 +1408,8 @@ function createClarifyViteCorePlugin(engine, normalizedMdxContentPlugin, mdx) {
|
|
|
1422
1408
|
outputDirectory: viteConfig.build.outDir,
|
|
1423
1409
|
ssrPlugins: [
|
|
1424
1410
|
engine.createSSGVirtualPlugin(),
|
|
1425
|
-
|
|
1411
|
+
normalizedContentPlugin,
|
|
1412
|
+
markdown,
|
|
1426
1413
|
mdx
|
|
1427
1414
|
]
|
|
1428
1415
|
});
|
|
@@ -1439,20 +1426,22 @@ function createClarifyViteCorePlugin(engine, normalizedMdxContentPlugin, mdx) {
|
|
|
1439
1426
|
* site itself - it only bridges Vite lifecycle hooks to the engine.
|
|
1440
1427
|
*/
|
|
1441
1428
|
function createViteAdapter(engine) {
|
|
1442
|
-
const
|
|
1429
|
+
const normalizedContentPlugin = createNormalizedContentPlugin(engine);
|
|
1430
|
+
const markdown = createMarkdownPlugin();
|
|
1443
1431
|
const mdx = createMdxPlugin();
|
|
1444
1432
|
const tailwind = tailwindcss();
|
|
1445
1433
|
return [
|
|
1446
1434
|
...react(),
|
|
1447
1435
|
...Array.isArray(tailwind) ? tailwind : [tailwind],
|
|
1448
|
-
|
|
1449
|
-
createClarifyViteCorePlugin(engine,
|
|
1436
|
+
normalizedContentPlugin,
|
|
1437
|
+
createClarifyViteCorePlugin(engine, normalizedContentPlugin, markdown, mdx),
|
|
1438
|
+
markdown,
|
|
1450
1439
|
mdx
|
|
1451
1440
|
];
|
|
1452
1441
|
}
|
|
1453
1442
|
var cliPackageVersion = {
|
|
1454
1443
|
name: "@clarify-labs/cli",
|
|
1455
|
-
version: "0.10.
|
|
1444
|
+
version: "0.10.2",
|
|
1456
1445
|
license: "AGPL-3.0-only",
|
|
1457
1446
|
type: "module",
|
|
1458
1447
|
repository: {
|
|
@@ -1493,6 +1482,7 @@ var cliPackageVersion = {
|
|
|
1493
1482
|
"@clarify-labs/templates": "workspace:*",
|
|
1494
1483
|
"@mdx-js/mdx": "^3.1.1",
|
|
1495
1484
|
"@mdx-js/rollup": "^3.1.1",
|
|
1485
|
+
"@shikijs/rehype": "^4.3.0",
|
|
1496
1486
|
"@tailwindcss/vite": "^4.3.2",
|
|
1497
1487
|
"@vitejs/plugin-react": "^6.0.3",
|
|
1498
1488
|
"cac": "^7.0.0",
|
|
@@ -1507,6 +1497,8 @@ var cliPackageVersion = {
|
|
|
1507
1497
|
"react-router": "^7.0.0",
|
|
1508
1498
|
"react-router-dom": "^7.0.0",
|
|
1509
1499
|
"react-zoom-pan-pinch": "^4.0.3",
|
|
1500
|
+
"rehype-raw": "^7.0.0",
|
|
1501
|
+
"rehype-slug": "^6.0.0",
|
|
1510
1502
|
"remark": "^15.0.1",
|
|
1511
1503
|
"remark-gfm": "^4.0.1",
|
|
1512
1504
|
"shiki": "4.3.0",
|
|
@@ -1558,11 +1550,14 @@ function routeToOpenAPIArtifactUrl(routePath) {
|
|
|
1558
1550
|
return `${routePath === "/" ? "/index" : routePath.replace(/\/$/, "")}.openapi.json`;
|
|
1559
1551
|
}
|
|
1560
1552
|
function attachContentArtifactUrls(routes) {
|
|
1561
|
-
for (const route of routes) route.
|
|
1553
|
+
for (const route of routes) route.artifacts = {
|
|
1554
|
+
...route.artifacts,
|
|
1555
|
+
contentArtifactUrl: route.kind === "openapi" ? routeToOpenAPIArtifactUrl(route.path) : routeToMarkdownArtifactUrl(route.path)
|
|
1556
|
+
};
|
|
1562
1557
|
}
|
|
1563
1558
|
function readRouteContent(route) {
|
|
1564
|
-
if (route.content !== void 0) return route.content;
|
|
1565
|
-
throw new Error(`Route content is missing from route context: ${route.filePath}`);
|
|
1559
|
+
if (route.source.content !== void 0) return route.source.content;
|
|
1560
|
+
throw new Error(`Route content is missing from route context: ${route.source.filePath}`);
|
|
1566
1561
|
}
|
|
1567
1562
|
function readRouteArtifactContent(route) {
|
|
1568
1563
|
const content = readRouteContent(route);
|
|
@@ -1572,16 +1567,17 @@ function isLlmsTxtRoute(route) {
|
|
|
1572
1567
|
return !route.path.split("/").includes("404");
|
|
1573
1568
|
}
|
|
1574
1569
|
function llmsTxtDescription(route) {
|
|
1575
|
-
if (route.description) return route.description;
|
|
1576
|
-
const sections = route.sections?.filter((section) => section.level === 2).slice(0, 3).map((section) => section.title);
|
|
1570
|
+
if (route.meta.description) return route.meta.description;
|
|
1571
|
+
const sections = route.meta.sections?.filter((section) => section.level === 2).slice(0, 3).map((section) => section.title);
|
|
1577
1572
|
if (sections?.length) return `Covers ${sections.join(", ")}.`;
|
|
1578
|
-
if (route.keywords?.length) return `Related topics: ${route.keywords.join(", ")}.`;
|
|
1573
|
+
if (route.meta.keywords?.length) return `Related topics: ${route.meta.keywords.join(", ")}.`;
|
|
1579
1574
|
if (route.kind === "openapi") return "OpenAPI artifact for machine-readable API reference data.";
|
|
1580
1575
|
}
|
|
1581
1576
|
function llmsTxtListItem(route, basePath) {
|
|
1582
|
-
|
|
1577
|
+
const contentArtifactUrl = route.artifacts?.contentArtifactUrl;
|
|
1578
|
+
if (!contentArtifactUrl) return void 0;
|
|
1583
1579
|
const description = llmsTxtDescription(route);
|
|
1584
|
-
return description ? `- [${route.title}](${basePath}${
|
|
1580
|
+
return description ? `- [${route.meta.title}](${basePath}${contentArtifactUrl}): ${description}` : `- [${route.meta.title}](${basePath}${contentArtifactUrl})`;
|
|
1585
1581
|
}
|
|
1586
1582
|
function llmsTxtLocaleLabel(locale, projectConfig) {
|
|
1587
1583
|
return projectConfig.i18n?.locales.find((item) => item.code === locale)?.label ?? locale;
|
|
@@ -1598,7 +1594,7 @@ function groupLlmsTxtRoutesByLocale(routes, projectConfig) {
|
|
|
1598
1594
|
const routesBySource = /* @__PURE__ */ new Map();
|
|
1599
1595
|
const defaultLocale = projectConfig.i18n?.defaultLocale;
|
|
1600
1596
|
for (const route of routes) {
|
|
1601
|
-
const sourceKey = `${route.locale ?? defaultLocale ?? "default"}:${route.basePath ?? route.contentArtifactUrl ?? route.path}`;
|
|
1597
|
+
const sourceKey = `${route.locale ?? defaultLocale ?? "default"}:${route.basePath ?? route.artifacts?.contentArtifactUrl ?? route.path}`;
|
|
1602
1598
|
const previousRoute = routesBySource.get(sourceKey);
|
|
1603
1599
|
if (!previousRoute || previousRoute.locale && !route.locale) routesBySource.set(sourceKey, route);
|
|
1604
1600
|
}
|
|
@@ -1667,9 +1663,9 @@ function serveContentArtifacts(req, res, projectConfig, routes) {
|
|
|
1667
1663
|
}
|
|
1668
1664
|
if (contentPath.endsWith(".openapi.yaml")) {
|
|
1669
1665
|
const jsonPath = contentPath.replace(/\.yaml$/, ".json");
|
|
1670
|
-
const route = routes.find((
|
|
1671
|
-
if (route?.kind === "openapi" && route.content) {
|
|
1672
|
-
const spec = JSON.parse(route.content);
|
|
1666
|
+
const route = routes.find((route) => route.artifacts?.contentArtifactUrl === jsonPath);
|
|
1667
|
+
if (route?.kind === "openapi" && route.source.content) {
|
|
1668
|
+
const spec = JSON.parse(route.source.content);
|
|
1673
1669
|
res.statusCode = 200;
|
|
1674
1670
|
res.setHeader("Content-Type", "text/yaml; charset=utf-8");
|
|
1675
1671
|
res.end(stringify(spec, { lineWidth: 0 }), "utf8");
|
|
@@ -1677,7 +1673,7 @@ function serveContentArtifacts(req, res, projectConfig, routes) {
|
|
|
1677
1673
|
}
|
|
1678
1674
|
return false;
|
|
1679
1675
|
}
|
|
1680
|
-
const route = routes.find((route) => route.contentArtifactUrl === contentPath);
|
|
1676
|
+
const route = routes.find((route) => route.artifacts?.contentArtifactUrl === contentPath);
|
|
1681
1677
|
if (!route) return false;
|
|
1682
1678
|
res.statusCode = 200;
|
|
1683
1679
|
res.setHeader("Content-Type", resolveContentArtifactType(route));
|
|
@@ -1703,14 +1699,15 @@ function createContentArtifactsPlugin() {
|
|
|
1703
1699
|
"build:assets": (ctx) => {
|
|
1704
1700
|
const assets = [];
|
|
1705
1701
|
for (const route of ctx.routes) {
|
|
1706
|
-
|
|
1702
|
+
const contentArtifactUrl = route.artifacts?.contentArtifactUrl;
|
|
1703
|
+
if (!contentArtifactUrl) continue;
|
|
1707
1704
|
assets.push({
|
|
1708
|
-
fileName:
|
|
1705
|
+
fileName: contentArtifactUrl.replace(/^\//, ""),
|
|
1709
1706
|
source: readRouteArtifactContent(route)
|
|
1710
1707
|
});
|
|
1711
|
-
if (route.kind === "openapi" && route.content) {
|
|
1712
|
-
const yamlFileName =
|
|
1713
|
-
const spec = JSON.parse(route.content);
|
|
1708
|
+
if (route.kind === "openapi" && route.source.content) {
|
|
1709
|
+
const yamlFileName = contentArtifactUrl.replace(/\.json$/, ".yaml");
|
|
1710
|
+
const spec = JSON.parse(route.source.content);
|
|
1714
1711
|
assets.push({
|
|
1715
1712
|
fileName: yamlFileName.replace(/^\//, ""),
|
|
1716
1713
|
source: stringify(spec, { lineWidth: 0 })
|
|
@@ -1796,6 +1793,7 @@ var OPENAPI_HTTP_METHODS = [
|
|
|
1796
1793
|
"patch",
|
|
1797
1794
|
"trace"
|
|
1798
1795
|
];
|
|
1796
|
+
var CLARIFY_OPENAPI_SECTION_ID_EXTENSION = "x-clarify-section-id";
|
|
1799
1797
|
function errorMessage(error) {
|
|
1800
1798
|
return error instanceof Error ? error.message : String(error);
|
|
1801
1799
|
}
|
|
@@ -1822,10 +1820,10 @@ function findOpenAPIRoutes(dir, base = dir) {
|
|
|
1822
1820
|
routes.push({
|
|
1823
1821
|
path: cleanPath,
|
|
1824
1822
|
basePath: cleanPath,
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1823
|
+
kind: "openapi",
|
|
1824
|
+
meta: { title: kebabToTitle(cleanPath.split("/").pop() ?? "API") },
|
|
1825
|
+
module: { virtualModuleId: virtualModuleIdFromRef(ref) },
|
|
1826
|
+
source: { filePath: fullPath }
|
|
1829
1827
|
});
|
|
1830
1828
|
}
|
|
1831
1829
|
return routes;
|
|
@@ -1834,36 +1832,80 @@ function operationMatchesTags(operationTags, filterTags) {
|
|
|
1834
1832
|
if (!filterTags?.length) return true;
|
|
1835
1833
|
return operationTags?.some((tag) => filterTags.includes(tag)) ?? false;
|
|
1836
1834
|
}
|
|
1835
|
+
function filterPathItemsByTags(items, tags) {
|
|
1836
|
+
const filteredItems = {};
|
|
1837
|
+
for (const path of Object.keys(items)) {
|
|
1838
|
+
const pathItem = items[path];
|
|
1839
|
+
if (!pathItem) continue;
|
|
1840
|
+
if (OPENAPI_HTTP_METHODS.map((method) => pathItem[method]).some((op) => op && typeof op === "object" && operationMatchesTags(op.tags, tags))) filteredItems[path] = pathItem;
|
|
1841
|
+
}
|
|
1842
|
+
return filteredItems;
|
|
1843
|
+
}
|
|
1844
|
+
function createOperationSectionId(operation, method, path, kind) {
|
|
1845
|
+
return (typeof operation.operationId === "string" ? operation.operationId.trim() : "") || slug(`${kind === "webhook" ? "webhook " : ""}${method.toLowerCase()} ${path}`);
|
|
1846
|
+
}
|
|
1847
|
+
function operationSectionId(operation) {
|
|
1848
|
+
const sectionId = operation[CLARIFY_OPENAPI_SECTION_ID_EXTENSION];
|
|
1849
|
+
return typeof sectionId === "string" ? sectionId : "";
|
|
1850
|
+
}
|
|
1851
|
+
function normalizeOpenAPISpecSectionIds(spec) {
|
|
1852
|
+
const items = [...Object.entries(spec.paths ?? {}).map(([path, pathItem]) => ({
|
|
1853
|
+
path,
|
|
1854
|
+
pathItem,
|
|
1855
|
+
kind: "path"
|
|
1856
|
+
})), ...Object.entries(spec.webhooks ?? {}).map(([path, pathItem]) => ({
|
|
1857
|
+
path,
|
|
1858
|
+
pathItem,
|
|
1859
|
+
kind: "webhook"
|
|
1860
|
+
}))];
|
|
1861
|
+
for (const { path, pathItem, kind } of items) {
|
|
1862
|
+
if (!pathItem || typeof pathItem !== "object") continue;
|
|
1863
|
+
const operations = pathItem;
|
|
1864
|
+
for (const method of OPENAPI_HTTP_METHODS) {
|
|
1865
|
+
const op = operations[method];
|
|
1866
|
+
if (!op || typeof op !== "object") continue;
|
|
1867
|
+
op[CLARIFY_OPENAPI_SECTION_ID_EXTENSION] = createOperationSectionId(op, method, path, kind);
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
return spec;
|
|
1871
|
+
}
|
|
1837
1872
|
/** Filter an OpenAPI spec to only include paths that have at least one operation matching the given tags. */
|
|
1838
1873
|
function filterSpecByTags(spec, tags) {
|
|
1839
|
-
const filteredPaths = {};
|
|
1840
1874
|
const paths = spec.paths ?? {};
|
|
1841
|
-
|
|
1842
|
-
const pathItem = paths[path];
|
|
1843
|
-
if (!pathItem) continue;
|
|
1844
|
-
if (Object.values(pathItem).some((op) => op && typeof op === "object" && operationMatchesTags(op.tags, tags))) filteredPaths[path] = pathItem;
|
|
1845
|
-
}
|
|
1875
|
+
const webhooks = spec.webhooks ?? {};
|
|
1846
1876
|
return {
|
|
1847
1877
|
...spec,
|
|
1848
|
-
paths:
|
|
1878
|
+
paths: filterPathItemsByTags(paths, tags),
|
|
1879
|
+
webhooks: filterPathItemsByTags(webhooks, tags)
|
|
1849
1880
|
};
|
|
1850
1881
|
}
|
|
1851
1882
|
/** Extract endpoint operations from an OpenAPI spec as page sections. */
|
|
1852
1883
|
function extractOpenAPISections(spec, filterTags) {
|
|
1884
|
+
normalizeOpenAPISpecSectionIds(spec);
|
|
1853
1885
|
const sections = [];
|
|
1854
|
-
const
|
|
1855
|
-
|
|
1886
|
+
const items = [...Object.entries(spec.paths ?? {}).map(([path, pathItem]) => ({
|
|
1887
|
+
path,
|
|
1888
|
+
pathItem,
|
|
1889
|
+
kind: "path"
|
|
1890
|
+
})), ...Object.entries(spec.webhooks ?? {}).map(([path, pathItem]) => ({
|
|
1891
|
+
path,
|
|
1892
|
+
pathItem,
|
|
1893
|
+
kind: "webhook"
|
|
1894
|
+
}))];
|
|
1895
|
+
for (const { path, pathItem, kind } of items) {
|
|
1856
1896
|
if (!pathItem) continue;
|
|
1897
|
+
const operations = pathItem;
|
|
1857
1898
|
for (const method of OPENAPI_HTTP_METHODS) {
|
|
1858
|
-
const op =
|
|
1859
|
-
|
|
1860
|
-
|
|
1899
|
+
const op = operations[method];
|
|
1900
|
+
const tags = Array.isArray(op?.tags) ? op.tags : void 0;
|
|
1901
|
+
if (!op || !operationMatchesTags(tags, filterTags)) continue;
|
|
1902
|
+
const title = typeof op.summary === "string" ? op.summary : `${method.toUpperCase()} ${path}`;
|
|
1861
1903
|
sections.push({
|
|
1862
|
-
id:
|
|
1904
|
+
id: operationSectionId(op),
|
|
1863
1905
|
title,
|
|
1864
1906
|
level: 2,
|
|
1865
|
-
badge: method.toUpperCase(),
|
|
1866
|
-
tags
|
|
1907
|
+
badge: kind === "webhook" ? "WEBHOOK" : method.toUpperCase(),
|
|
1908
|
+
tags
|
|
1867
1909
|
});
|
|
1868
1910
|
}
|
|
1869
1911
|
}
|
|
@@ -1905,12 +1947,16 @@ async function readOpenAPISpec(filePath, contentProcessor) {
|
|
|
1905
1947
|
//#endregion
|
|
1906
1948
|
//#region source/plugins/openapi/virtual-modules.ts
|
|
1907
1949
|
var openApiRegistryModuleId = VIRTUAL_OPENAPI;
|
|
1950
|
+
var openApiServerRegistryModuleId = VIRTUAL_OPENAPI_SERVER;
|
|
1908
1951
|
var OPENAPI_SPEC_PREFIX = "virtual:clarify/openapi-spec/";
|
|
1909
1952
|
function specVirtualModuleId(specKey) {
|
|
1910
1953
|
return `${OPENAPI_SPEC_PREFIX}${specKey}`;
|
|
1911
1954
|
}
|
|
1912
|
-
function generateOpenAPIRegistryModule(
|
|
1913
|
-
return `export const
|
|
1955
|
+
function generateOpenAPIRegistryModule(openApiSpecs) {
|
|
1956
|
+
return `export const openApiSpecs = {\n${Object.entries(openApiSpecs).map(([key, moduleId]) => ` ${JSON.stringify(key)}: () => import(${JSON.stringify(moduleId)}),`).join("\n")}\n};`;
|
|
1957
|
+
}
|
|
1958
|
+
function generateOpenAPIServerRegistryModule(openApiSpecs) {
|
|
1959
|
+
return `export const openApiSpecs = ${JSON.stringify(openApiSpecs)};`;
|
|
1914
1960
|
}
|
|
1915
1961
|
/** Generate a virtual module that exports a single spec as default. */
|
|
1916
1962
|
function generateOpenAPISpecModule(spec) {
|
|
@@ -1918,13 +1964,11 @@ function generateOpenAPISpecModule(spec) {
|
|
|
1918
1964
|
}
|
|
1919
1965
|
function generateOpenAPIPageModule(opts) {
|
|
1920
1966
|
return `import { createOpenApiRouteComponent } from '@clarify-labs/renderer';
|
|
1967
|
+
import spec from ${JSON.stringify(opts.specModuleId)};
|
|
1921
1968
|
|
|
1922
|
-
export const routeData =
|
|
1923
|
-
spec: opts.spec,
|
|
1924
|
-
tagFilter: opts.tagFilter
|
|
1925
|
-
})};
|
|
1969
|
+
export const routeData = {};
|
|
1926
1970
|
|
|
1927
|
-
export default createOpenApiRouteComponent(routeData);
|
|
1971
|
+
export default createOpenApiRouteComponent({ ...routeData, spec });
|
|
1928
1972
|
`;
|
|
1929
1973
|
}
|
|
1930
1974
|
function generateOpenAPIErrorModule(diagnostic) {
|
|
@@ -1943,115 +1987,212 @@ export default createContentDiagnosticComponent(contentDiagnostic);
|
|
|
1943
1987
|
}
|
|
1944
1988
|
//#endregion
|
|
1945
1989
|
//#region source/plugins/openapi/index.ts
|
|
1946
|
-
function
|
|
1947
|
-
const
|
|
1990
|
+
function collectOpenAPIPageIntents(config) {
|
|
1991
|
+
const intents = [];
|
|
1948
1992
|
function visitPages(pages) {
|
|
1949
1993
|
if (!pages || pages === "FileTree") return;
|
|
1950
|
-
for (const group of pages) for (const item of group.pages)
|
|
1994
|
+
for (const group of pages) for (const item of group.pages) {
|
|
1995
|
+
const intent = routeIntentFromPagesItem(item);
|
|
1996
|
+
if (intent.kind === "openapi" && (intent.path || intent.tagFilter?.length)) intents.push(intent);
|
|
1997
|
+
}
|
|
1951
1998
|
}
|
|
1952
1999
|
for (const tab of config.tabs ?? []) visitPages(tab.pages);
|
|
1953
|
-
return
|
|
2000
|
+
return intents;
|
|
1954
2001
|
}
|
|
1955
2002
|
function virtualModuleIdFromPath(path) {
|
|
1956
2003
|
return `virtual:clarify-page/${path.replace(/^\/+/, "") || "index"}`;
|
|
1957
2004
|
}
|
|
2005
|
+
function cloneOpenAPIRoute(route, overrides = {}) {
|
|
2006
|
+
return {
|
|
2007
|
+
...route,
|
|
2008
|
+
meta: {
|
|
2009
|
+
...route.meta,
|
|
2010
|
+
sections: route.meta.sections ? [...route.meta.sections] : void 0
|
|
2011
|
+
},
|
|
2012
|
+
module: { ...route.module },
|
|
2013
|
+
source: { ...route.source },
|
|
2014
|
+
openapi: route.openapi ? {
|
|
2015
|
+
...route.openapi,
|
|
2016
|
+
tagFilter: route.openapi.tagFilter ? [...route.openapi.tagFilter] : void 0
|
|
2017
|
+
} : void 0,
|
|
2018
|
+
alternates: route.alternates ? { ...route.alternates } : void 0,
|
|
2019
|
+
...overrides
|
|
2020
|
+
};
|
|
2021
|
+
}
|
|
2022
|
+
function findOpenAPIRoutesForContentRoot(contentRoot, i18n) {
|
|
2023
|
+
if (!i18n) return findOpenAPIRoutes(contentRoot);
|
|
2024
|
+
const localizedRoutes = [];
|
|
2025
|
+
for (const locale of i18n.locales) {
|
|
2026
|
+
const localeRoot = join(contentRoot, locale.code);
|
|
2027
|
+
for (const route of findOpenAPIRoutes(localeRoot, localeRoot)) {
|
|
2028
|
+
const basePath = route.basePath ?? route.path;
|
|
2029
|
+
const path = localizedRoutePath(basePath, locale.code, i18n);
|
|
2030
|
+
localizedRoutes.push({
|
|
2031
|
+
...route,
|
|
2032
|
+
path,
|
|
2033
|
+
basePath,
|
|
2034
|
+
locale: locale.code,
|
|
2035
|
+
module: { virtualModuleId: virtualModuleIdFromPath(path) }
|
|
2036
|
+
});
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
if (i18n.missing === "fallback") {
|
|
2040
|
+
const routeByLocaleAndBase = new Map(localizedRoutes.map((route) => [`${route.locale ?? ""}:${route.basePath ?? route.path}`, route]));
|
|
2041
|
+
const defaultRoutes = localizedRoutes.filter((route) => route.locale === i18n.defaultLocale);
|
|
2042
|
+
for (const sourceRoute of defaultRoutes) {
|
|
2043
|
+
const basePath = sourceRoute.basePath ?? sourceRoute.path;
|
|
2044
|
+
for (const locale of i18n.locales) {
|
|
2045
|
+
const key = `${locale.code}:${basePath}`;
|
|
2046
|
+
if (routeByLocaleAndBase.has(key)) continue;
|
|
2047
|
+
const path = localizedRoutePath(basePath, locale.code, i18n);
|
|
2048
|
+
localizedRoutes.push(cloneOpenAPIRoute(sourceRoute, {
|
|
2049
|
+
path,
|
|
2050
|
+
locale: locale.code,
|
|
2051
|
+
module: { virtualModuleId: virtualModuleIdFromPath(path) },
|
|
2052
|
+
isFallback: true
|
|
2053
|
+
}));
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
return localizedRoutes;
|
|
2058
|
+
}
|
|
1958
2059
|
function createConfiguredOpenAPIRoutes(routes, config) {
|
|
1959
|
-
const
|
|
1960
|
-
if (!
|
|
2060
|
+
const openAPIIntents = collectOpenAPIPageIntents(config);
|
|
2061
|
+
if (!openAPIIntents.length) return routes;
|
|
1961
2062
|
const additions = [];
|
|
1962
2063
|
const existingKeys = new Set(routes.map((route) => `${route.locale ?? ""}:${route.basePath ?? route.path}`));
|
|
1963
|
-
for (const
|
|
1964
|
-
const tagFilter =
|
|
1965
|
-
const sourceBasePath = openAPIPagePathFromRef(
|
|
1966
|
-
const targetBasePath = openAPIPagePathFromRef(
|
|
2064
|
+
for (const intent of openAPIIntents) {
|
|
2065
|
+
const tagFilter = intent.tagFilter?.filter(Boolean);
|
|
2066
|
+
const sourceBasePath = openAPIPagePathFromRef(intent.ref);
|
|
2067
|
+
const targetBasePath = openAPIPagePathFromRef(intent.ref, tagFilter, intent.path);
|
|
1967
2068
|
if (sourceBasePath === targetBasePath && !tagFilter?.length) continue;
|
|
1968
2069
|
for (const route of routes) {
|
|
1969
2070
|
if (route.kind !== "openapi" || (route.basePath ?? route.path) !== sourceBasePath) continue;
|
|
1970
2071
|
const key = `${route.locale ?? ""}:${targetBasePath}`;
|
|
1971
2072
|
if (existingKeys.has(key)) continue;
|
|
1972
2073
|
existingKeys.add(key);
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
path
|
|
2074
|
+
const path = route.locale && config.i18n ? localizedRoutePath(targetBasePath, route.locale, config.i18n) : targetBasePath;
|
|
2075
|
+
additions.push(cloneOpenAPIRoute(route, {
|
|
2076
|
+
path,
|
|
1976
2077
|
basePath: targetBasePath,
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
2078
|
+
module: { virtualModuleId: virtualModuleIdFromPath(path) },
|
|
2079
|
+
openapi: {
|
|
2080
|
+
...route.openapi,
|
|
2081
|
+
tagFilter: tagFilter?.length ? tagFilter : void 0
|
|
2082
|
+
}
|
|
2083
|
+
}));
|
|
1981
2084
|
}
|
|
1982
2085
|
}
|
|
1983
2086
|
const nextRoutes = [...routes, ...additions];
|
|
1984
|
-
|
|
2087
|
+
if (!config.i18n) return nextRoutes;
|
|
2088
|
+
const routesWithAlternates = nextRoutes.map((route) => withAlternates(route, nextRoutes, config.i18n));
|
|
2089
|
+
const bareAliases = [];
|
|
2090
|
+
const seenBare = new Set(routesWithAlternates.map((route) => route.path));
|
|
2091
|
+
for (const route of routesWithAlternates) {
|
|
2092
|
+
if (route.locale !== config.i18n.defaultLocale) continue;
|
|
2093
|
+
const basePath = route.basePath ?? route.path;
|
|
2094
|
+
if (basePath === route.path || seenBare.has(basePath)) continue;
|
|
2095
|
+
seenBare.add(basePath);
|
|
2096
|
+
bareAliases.push(cloneOpenAPIRoute(route, {
|
|
2097
|
+
path: basePath,
|
|
2098
|
+
module: { virtualModuleId: virtualModuleIdFromPath(basePath) },
|
|
2099
|
+
isBareAlias: true
|
|
2100
|
+
}));
|
|
2101
|
+
}
|
|
2102
|
+
return [...routesWithAlternates, ...bareAliases];
|
|
1985
2103
|
}
|
|
1986
|
-
/** Derive a stable, deduplicated
|
|
1987
|
-
function
|
|
2104
|
+
/** Derive a stable, deduplicated id from an absolute spec file path. */
|
|
2105
|
+
function sourceSpecIdFromPath(filePath, projectRoot) {
|
|
1988
2106
|
return relative(projectRoot, filePath).replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
1989
2107
|
}
|
|
2108
|
+
function routeSpecModuleIdFromSourceSpecId(sourceSpecId, tagFilter) {
|
|
2109
|
+
if (!tagFilter?.length) return sourceSpecId;
|
|
2110
|
+
return `${sourceSpecId}_tags_${tagFilter.map((tag) => tag.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "") || "tag").join("_")}`;
|
|
2111
|
+
}
|
|
2112
|
+
function openAPIRegistryKeys(route) {
|
|
2113
|
+
const keys = /* @__PURE__ */ new Set();
|
|
2114
|
+
const path = (route.path || "/").replace(/^\//, "");
|
|
2115
|
+
const base = (route.basePath ?? route.path).replace(/^\//, "");
|
|
2116
|
+
if (route.locale) keys.add(`virtual:clarify-page/${route.locale}/${base}`);
|
|
2117
|
+
if (path) keys.add(`virtual:clarify-page/${path}`);
|
|
2118
|
+
else keys.add("virtual:clarify-page/index");
|
|
2119
|
+
if (!route.locale && base) keys.add(`virtual:clarify-page/${base}`);
|
|
2120
|
+
return [...keys];
|
|
2121
|
+
}
|
|
1990
2122
|
function createOpenAPIPlugin() {
|
|
1991
|
-
/** specs keyed by
|
|
2123
|
+
/** specs keyed by sourceSpecId (deduplicated per source file). */
|
|
1992
2124
|
const specs = /* @__PURE__ */ new Map();
|
|
2125
|
+
const specModules = /* @__PURE__ */ new Map();
|
|
1993
2126
|
return {
|
|
1994
2127
|
name: "clarify:openapi",
|
|
1995
2128
|
hooks: {
|
|
1996
|
-
"routes:discover": (input) => ({
|
|
2129
|
+
"routes:discover": (input, ctx) => ({
|
|
1997
2130
|
...input,
|
|
1998
|
-
routes: [...input.routes, ...
|
|
2131
|
+
routes: [...input.routes, ...findOpenAPIRoutesForContentRoot(input.contentRoot, ctx.projectConfig.i18n)]
|
|
1999
2132
|
}),
|
|
2000
2133
|
"routes:discovered": async (routes, ctx) => {
|
|
2001
2134
|
specs.clear();
|
|
2135
|
+
specModules.clear();
|
|
2002
2136
|
const nextRoutes = createConfiguredOpenAPIRoutes(routes, ctx.projectConfig);
|
|
2003
2137
|
const specByFilePath = /* @__PURE__ */ new Map();
|
|
2004
2138
|
for (const route of nextRoutes.filter((route) => route.kind === "openapi")) {
|
|
2005
|
-
const specFromCache = specByFilePath.get(route.filePath);
|
|
2139
|
+
const specFromCache = specByFilePath.get(route.source.filePath);
|
|
2006
2140
|
const processor = createProjectContentProcessor(ctx.plugins, ctx);
|
|
2007
2141
|
const result = specFromCache ? {
|
|
2008
2142
|
ok: true,
|
|
2009
2143
|
spec: specFromCache
|
|
2010
|
-
} : await readOpenAPISpec(route.filePath, processor);
|
|
2144
|
+
} : await readOpenAPISpec(route.source.filePath, processor);
|
|
2011
2145
|
if (!result.ok) {
|
|
2012
2146
|
route.diagnostic = result.diagnostic;
|
|
2013
|
-
route.title = route.title || "OpenAPI parse error";
|
|
2014
|
-
route.sections = [];
|
|
2147
|
+
route.meta.title = route.meta.title || "OpenAPI parse error";
|
|
2148
|
+
route.meta.sections = [];
|
|
2015
2149
|
continue;
|
|
2016
2150
|
}
|
|
2017
|
-
const spec = result.spec;
|
|
2018
|
-
specByFilePath.set(route.filePath, spec);
|
|
2019
|
-
const
|
|
2020
|
-
route.
|
|
2021
|
-
|
|
2151
|
+
const spec = normalizeOpenAPISpecSectionIds(result.spec);
|
|
2152
|
+
specByFilePath.set(route.source.filePath, spec);
|
|
2153
|
+
const sourceSpecId = sourceSpecIdFromPath(route.source.filePath, ctx.generateOptions.projectRoot);
|
|
2154
|
+
route.openapi = {
|
|
2155
|
+
...route.openapi,
|
|
2156
|
+
sourceSpecId
|
|
2157
|
+
};
|
|
2158
|
+
specs.set(sourceSpecId, {
|
|
2022
2159
|
spec,
|
|
2023
|
-
filePath: route.filePath
|
|
2160
|
+
filePath: route.source.filePath
|
|
2024
2161
|
});
|
|
2025
|
-
route.title = spec.info?.title ?? route.title;
|
|
2026
|
-
route.description = spec.info?.description ?? route.description;
|
|
2027
|
-
route.sections = extractOpenAPISections(spec, route.
|
|
2028
|
-
const pageSpec = route.
|
|
2029
|
-
|
|
2162
|
+
route.meta.title = spec.info?.title ?? route.meta.title;
|
|
2163
|
+
route.meta.description = spec.info?.description ?? route.meta.description;
|
|
2164
|
+
route.meta.sections = extractOpenAPISections(spec, route.openapi?.tagFilter);
|
|
2165
|
+
const pageSpec = route.openapi?.tagFilter?.length ? filterSpecByTags(spec, route.openapi.tagFilter) : spec;
|
|
2166
|
+
const routeSpecModuleId = routeSpecModuleIdFromSourceSpecId(sourceSpecId, route.openapi?.tagFilter);
|
|
2167
|
+
route.openapi.routeSpecModuleId = routeSpecModuleId;
|
|
2168
|
+
specModules.set(routeSpecModuleId, pageSpec);
|
|
2169
|
+
route.source.content = JSON.stringify(pageSpec);
|
|
2030
2170
|
}
|
|
2031
2171
|
return nextRoutes;
|
|
2032
2172
|
},
|
|
2033
2173
|
"modules:before": (modules, ctx) => {
|
|
2034
2174
|
const registryEntries = {};
|
|
2175
|
+
const serverRegistryEntries = {};
|
|
2035
2176
|
for (const route of ctx.routes) {
|
|
2036
|
-
if (route.kind !== "openapi" || !route.
|
|
2037
|
-
const
|
|
2177
|
+
if (route.kind !== "openapi" || !route.openapi?.sourceSpecId) continue;
|
|
2178
|
+
const routeSpecModuleId = route.openapi.routeSpecModuleId ?? route.openapi.sourceSpecId;
|
|
2179
|
+
const spec = specModules.get(routeSpecModuleId) ?? specs.get(route.openapi.sourceSpecId)?.spec;
|
|
2038
2180
|
if (!spec) continue;
|
|
2039
|
-
const
|
|
2040
|
-
|
|
2041
|
-
|
|
2181
|
+
for (const registryKey of openAPIRegistryKeys(route)) {
|
|
2182
|
+
registryEntries[registryKey] = specVirtualModuleId(routeSpecModuleId);
|
|
2183
|
+
serverRegistryEntries[registryKey] = spec;
|
|
2184
|
+
}
|
|
2042
2185
|
}
|
|
2043
2186
|
modules.set(openApiRegistryModuleId, generateOpenAPIRegistryModule(registryEntries));
|
|
2044
|
-
|
|
2187
|
+
modules.set(openApiServerRegistryModuleId, generateOpenAPIServerRegistryModule(serverRegistryEntries));
|
|
2188
|
+
for (const [routeSpecModuleId, spec] of specModules) modules.set(specVirtualModuleId(routeSpecModuleId), generateOpenAPISpecModule(spec));
|
|
2045
2189
|
for (const route of ctx.routes) {
|
|
2046
2190
|
if (route.kind !== "openapi") continue;
|
|
2047
|
-
if (route.diagnostic) modules.set(route.virtualModuleId, generateOpenAPIErrorModule(route.diagnostic));
|
|
2048
|
-
else if (route.
|
|
2049
|
-
const
|
|
2050
|
-
if (!
|
|
2051
|
-
modules.set(route.virtualModuleId, generateOpenAPIPageModule({
|
|
2052
|
-
spec: entry.spec,
|
|
2053
|
-
tagFilter: route.openapiTagFilter
|
|
2054
|
-
}));
|
|
2191
|
+
if (route.diagnostic) modules.set(route.module.virtualModuleId, generateOpenAPIErrorModule(route.diagnostic));
|
|
2192
|
+
else if (route.openapi?.sourceSpecId) {
|
|
2193
|
+
const routeSpecModuleId = route.openapi.routeSpecModuleId ?? route.openapi.sourceSpecId;
|
|
2194
|
+
if (!specModules.has(routeSpecModuleId)) continue;
|
|
2195
|
+
modules.set(route.module.virtualModuleId, generateOpenAPIPageModule({ specModuleId: specVirtualModuleId(routeSpecModuleId) }));
|
|
2055
2196
|
}
|
|
2056
2197
|
}
|
|
2057
2198
|
return modules;
|
|
@@ -2119,11 +2260,11 @@ async function generatePagefindIndex(options, pagefind) {
|
|
|
2119
2260
|
}
|
|
2120
2261
|
function routeSearchContent(route) {
|
|
2121
2262
|
return [
|
|
2122
|
-
route.title,
|
|
2123
|
-
route.description,
|
|
2124
|
-
route.keywords?.join(" "),
|
|
2125
|
-
route.sections?.map((section) => section.title).join(" "),
|
|
2126
|
-
route.content
|
|
2263
|
+
route.meta.title,
|
|
2264
|
+
route.meta.description,
|
|
2265
|
+
route.meta.keywords?.join(" "),
|
|
2266
|
+
route.meta.sections?.map((section) => section.title).join(" "),
|
|
2267
|
+
route.source.content
|
|
2127
2268
|
].filter(Boolean).join("\n\n");
|
|
2128
2269
|
}
|
|
2129
2270
|
async function generateDevSearchIndex(ctx, root, pagefind) {
|
|
@@ -2145,7 +2286,7 @@ async function generateDevSearchIndex(ctx, root, pagefind) {
|
|
|
2145
2286
|
url: route.path,
|
|
2146
2287
|
content,
|
|
2147
2288
|
language: toPagefindLanguage(route.locale ?? ctx.projectConfig.i18n?.defaultLocale),
|
|
2148
|
-
meta: { title: route.title }
|
|
2289
|
+
meta: { title: route.meta.title }
|
|
2149
2290
|
});
|
|
2150
2291
|
assertNoPagefindErrors(`addCustomRecord ${route.path}`, result.errors);
|
|
2151
2292
|
pageCount += 1;
|
|
@@ -2302,15 +2443,18 @@ function normalizeRepositoryUrl(repository) {
|
|
|
2302
2443
|
function encodePath(path) {
|
|
2303
2444
|
return path.split("/").filter(Boolean).map((segment) => encodeURIComponent(segment)).join("/");
|
|
2304
2445
|
}
|
|
2305
|
-
function
|
|
2446
|
+
function createSourceEditUrl(filePath, contentRoot, source) {
|
|
2306
2447
|
const repository = normalizeRepositoryUrl(source.repository);
|
|
2307
2448
|
const branch = source.branch ?? "main";
|
|
2308
2449
|
const sourcePath = [source.directory ? trimSlashes(source.directory) : "", relative(contentRoot, filePath).replaceAll("\\", "/")].filter(Boolean).join("/");
|
|
2309
2450
|
return `${repository}/edit/${encodeURIComponent(branch)}/${encodePath(sourcePath)}`;
|
|
2310
2451
|
}
|
|
2311
|
-
function
|
|
2452
|
+
function attachSourceEditUrls(routes, contentRoot, source) {
|
|
2312
2453
|
if (!source) return;
|
|
2313
|
-
for (const route of routes) route.
|
|
2454
|
+
for (const route of routes) route.source = {
|
|
2455
|
+
...route.source,
|
|
2456
|
+
sourceEditUrl: createSourceEditUrl(route.source.filePath, contentRoot, source)
|
|
2457
|
+
};
|
|
2314
2458
|
}
|
|
2315
2459
|
//#endregion
|
|
2316
2460
|
//#region source/plugins/source-links/index.ts
|
|
@@ -2318,7 +2462,7 @@ function createSourceLinksPlugin() {
|
|
|
2318
2462
|
return {
|
|
2319
2463
|
name: "clarify:source-links",
|
|
2320
2464
|
hooks: { "routes:discovered": (routes, ctx) => {
|
|
2321
|
-
|
|
2465
|
+
attachSourceEditUrls(routes, join(ctx.generateOptions.projectRoot, ctx.generateOptions.rootDirectory), ctx.projectConfig.source);
|
|
2322
2466
|
return routes;
|
|
2323
2467
|
} }
|
|
2324
2468
|
};
|
|
@@ -2475,9 +2619,9 @@ var CLARIFY_ENV_TEMPLATE = `// This file is generated by Clarify. Do not edit it
|
|
|
2475
2619
|
// plugin and slot code, so the TypeScript language service can resolve them.
|
|
2476
2620
|
|
|
2477
2621
|
declare module 'virtual:clarify/slot' {
|
|
2478
|
-
import type {
|
|
2622
|
+
import type { UISlotContext } from '@clarify-labs/cli'
|
|
2479
2623
|
|
|
2480
|
-
export function useSlot():
|
|
2624
|
+
export function useSlot(): UISlotContext
|
|
2481
2625
|
}
|
|
2482
2626
|
`;
|
|
2483
2627
|
function generateClarifyEnvDts(_plugins) {
|
|
@@ -2499,6 +2643,11 @@ function writeClarifyEnvDts(projectRoot, plugins) {
|
|
|
2499
2643
|
writeFileSync(filePath, next, "utf-8");
|
|
2500
2644
|
}
|
|
2501
2645
|
//#endregion
|
|
2646
|
+
//#region source/parsers/markdown/utils.ts
|
|
2647
|
+
function escapeHtml(text) {
|
|
2648
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2649
|
+
}
|
|
2650
|
+
//#endregion
|
|
2502
2651
|
//#region source/core/runtime/html-template.ts
|
|
2503
2652
|
/**
|
|
2504
2653
|
* HTML template manipulation helpers used during SSG.
|
|
@@ -2515,7 +2664,7 @@ function resolveProjectConfigFromContext(contextOrConfig) {
|
|
|
2515
2664
|
}
|
|
2516
2665
|
function routeTitle(contextOrConfig, route) {
|
|
2517
2666
|
const projectConfig = resolveProjectConfigFromContext(contextOrConfig);
|
|
2518
|
-
const title = route?.title
|
|
2667
|
+
const title = route?.meta.title.trim();
|
|
2519
2668
|
if (!title || title === projectConfig.title) return projectConfig.title;
|
|
2520
2669
|
return `${title} - ${projectConfig.title}`;
|
|
2521
2670
|
}
|
|
@@ -2563,8 +2712,8 @@ function injectSSRIntoTemplate(template, appHtml, contextOrConfig, route) {
|
|
|
2563
2712
|
const projectConfig = resolveProjectConfigFromContext(contextOrConfig);
|
|
2564
2713
|
let html = injectHtmlLocaleAttributes(template, contextOrConfig, route);
|
|
2565
2714
|
html = html.replace(/<title>.*?<\/title>/, `<title>${escapeHtml(routeTitle(contextOrConfig, route))}</title>`);
|
|
2566
|
-
html = setNamedMeta(html, "description", route?.description ?? projectConfig.description);
|
|
2567
|
-
html = setNamedMeta(html, "keywords", route?.keywords?.join(", "));
|
|
2715
|
+
html = setNamedMeta(html, "description", route?.meta.description ?? projectConfig.description);
|
|
2716
|
+
html = setNamedMeta(html, "keywords", route?.meta.keywords?.join(", "));
|
|
2568
2717
|
html = injectCanonicalUrl(html, contextOrConfig, route);
|
|
2569
2718
|
const dataPagefindIgnore = route?.isBareAlias ? " data-pagefind-ignore" : "";
|
|
2570
2719
|
html = html.replace(/<div id="root">([\s\S]*?)<\/div>/, `<div id="root"${dataPagefindIgnore}>${appHtml}</div>`);
|
|
@@ -2673,7 +2822,7 @@ function routeOutputFiles(outputDirectory, route) {
|
|
|
2673
2822
|
var SSR_ENTRY_CODE = `import { renderToHTML } from '@clarify-labs/renderer/server';
|
|
2674
2823
|
import { routes, navigation } from 'virtual:clarify/routes/server';
|
|
2675
2824
|
import { config } from 'virtual:clarify/config';
|
|
2676
|
-
import {
|
|
2825
|
+
import { openApiSpecs } from 'virtual:clarify/openapi/server';
|
|
2677
2826
|
import { runtimeSlots } from 'virtual:clarify/slots';
|
|
2678
2827
|
|
|
2679
2828
|
export async function render(url) {
|
|
@@ -2681,10 +2830,10 @@ export async function render(url) {
|
|
|
2681
2830
|
// them synchronously (renderToString has no Suspense support).
|
|
2682
2831
|
const entries = Object.values(runtimeSlots).flat()
|
|
2683
2832
|
await Promise.all(entries.map(async (entry) => {
|
|
2684
|
-
const mod = await entry.
|
|
2833
|
+
const mod = await entry.loadComponent()
|
|
2685
2834
|
entry._resolved = mod.default
|
|
2686
2835
|
}))
|
|
2687
|
-
return renderToHTML({ config, routes, navigation,
|
|
2836
|
+
return renderToHTML({ config, routes, navigation, openApiSpecs, runtimeSlots, url, themeEditor: config.theme.editor });
|
|
2688
2837
|
}`;
|
|
2689
2838
|
function createTempEntryFile(content) {
|
|
2690
2839
|
const entryPath = join(createClarifyTempDir("ssr"), "entry-server.ts");
|
|
@@ -2771,7 +2920,10 @@ var ClarifyContext = class {
|
|
|
2771
2920
|
this.generateOptions = init.generateOptions;
|
|
2772
2921
|
this.version = init.version;
|
|
2773
2922
|
this.currentRoutes = init.routes ?? [];
|
|
2774
|
-
this.currentNavigation = init.navigation ??
|
|
2923
|
+
this.currentNavigation = init.navigation ?? {
|
|
2924
|
+
kind: "flat",
|
|
2925
|
+
nodes: []
|
|
2926
|
+
};
|
|
2775
2927
|
this.currentPlugins = init.plugins ?? [];
|
|
2776
2928
|
}
|
|
2777
2929
|
get routes() {
|
|
@@ -2893,7 +3045,10 @@ var ClarifyEngine = class {
|
|
|
2893
3045
|
generateOptions: placeholderOptions,
|
|
2894
3046
|
version: cliPackageVersion,
|
|
2895
3047
|
routes: [],
|
|
2896
|
-
navigation:
|
|
3048
|
+
navigation: {
|
|
3049
|
+
kind: "flat",
|
|
3050
|
+
nodes: []
|
|
3051
|
+
},
|
|
2897
3052
|
plugins: []
|
|
2898
3053
|
});
|
|
2899
3054
|
}
|
|
@@ -2996,9 +3151,9 @@ var ClarifyEngine = class {
|
|
|
2996
3151
|
routes = await runPhase(plugins, "content:process", this.ctx, async () => {
|
|
2997
3152
|
const pages = routes.map((route) => ({
|
|
2998
3153
|
path: route.path,
|
|
2999
|
-
filePath: route.filePath,
|
|
3000
|
-
frontmatter: route.frontmatter ?? {},
|
|
3001
|
-
content: route.content ?? ""
|
|
3154
|
+
filePath: route.source.filePath,
|
|
3155
|
+
frontmatter: route.source.frontmatter ?? {},
|
|
3156
|
+
content: route.source.content ?? ""
|
|
3002
3157
|
}));
|
|
3003
3158
|
const resolvedPages = await runHooks(plugins, "pages:resolved", pages, this.ctx);
|
|
3004
3159
|
const pageByPath = new Map(resolvedPages.map((p) => [p.path, p]));
|
|
@@ -3007,13 +3162,22 @@ var ClarifyEngine = class {
|
|
|
3007
3162
|
if (!page) return route;
|
|
3008
3163
|
return {
|
|
3009
3164
|
...route,
|
|
3010
|
-
|
|
3011
|
-
|
|
3165
|
+
source: {
|
|
3166
|
+
...route.source,
|
|
3167
|
+
frontmatter: page.frontmatter,
|
|
3168
|
+
content: page.content
|
|
3169
|
+
}
|
|
3012
3170
|
};
|
|
3013
3171
|
});
|
|
3014
3172
|
});
|
|
3015
3173
|
routes = applyConfiguredPageRoutePaths(routes, tabs, i18n);
|
|
3016
|
-
const navigation = tabs ? i18n ? buildLocalizedNavigationFromTabsConfig(routes, tabs, i18n) ?? {
|
|
3174
|
+
const navigation = tabs ? i18n ? buildLocalizedNavigationFromTabsConfig(routes, tabs, i18n) ?? {
|
|
3175
|
+
kind: "localized-tabbed",
|
|
3176
|
+
locales: {}
|
|
3177
|
+
} : buildNavigationFromTabsConfig(routes, tabs) : {
|
|
3178
|
+
kind: "flat",
|
|
3179
|
+
nodes: buildNavigation(routes)
|
|
3180
|
+
};
|
|
3017
3181
|
const resolved = await runHooks(plugins, "routes:resolved", {
|
|
3018
3182
|
routes,
|
|
3019
3183
|
navigation
|
|
@@ -3047,7 +3211,7 @@ var ClarifyEngine = class {
|
|
|
3047
3211
|
writeClarifyEnvDts(this.root, this.plugins);
|
|
3048
3212
|
}
|
|
3049
3213
|
hasContentRouteForFile(filePath) {
|
|
3050
|
-
return this.routes.some((route) => route.filePath === filePath);
|
|
3214
|
+
return this.routes.some((route) => route.source.filePath === filePath);
|
|
3051
3215
|
}
|
|
3052
3216
|
async collectBuildAssets() {
|
|
3053
3217
|
if (!this.buildEnabled) return [];
|
|
@@ -3140,4 +3304,4 @@ function createClarifyEngine(options = {}) {
|
|
|
3140
3304
|
//#endregion
|
|
3141
3305
|
export { cliPackageVersion as a, defineConfig as c, createClarifyTempDir as i, createClarifyEngine as n, cliPackageVersionWithCaret as o, createClarifyRuntimeAliases as r, createViteAdapter as s, ClarifyEngine as t };
|
|
3142
3306
|
|
|
3143
|
-
//# sourceMappingURL=engine-
|
|
3307
|
+
//# sourceMappingURL=engine-CSSL_gGd.js.map
|