@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
|
@@ -27,14 +27,20 @@ let _tailwindcss_vite = require("@tailwindcss/vite");
|
|
|
27
27
|
_tailwindcss_vite = __toESM(_tailwindcss_vite, 1);
|
|
28
28
|
let _vitejs_plugin_react = require("@vitejs/plugin-react");
|
|
29
29
|
_vitejs_plugin_react = __toESM(_vitejs_plugin_react, 1);
|
|
30
|
+
let rehype_raw = require("rehype-raw");
|
|
31
|
+
rehype_raw = __toESM(rehype_raw, 1);
|
|
30
32
|
let _mdx_js_mdx = require("@mdx-js/mdx");
|
|
31
|
-
let
|
|
32
|
-
|
|
33
|
-
let
|
|
33
|
+
let _shikijs_rehype = require("@shikijs/rehype");
|
|
34
|
+
_shikijs_rehype = __toESM(_shikijs_rehype, 1);
|
|
35
|
+
let rehype_slug = require("rehype-slug");
|
|
36
|
+
rehype_slug = __toESM(rehype_slug, 1);
|
|
34
37
|
let shiki = require("shiki");
|
|
35
38
|
let unist_util_visit = require("unist-util-visit");
|
|
36
39
|
let _clarify_labs_renderer = require("@clarify-labs/renderer");
|
|
37
40
|
let node_fs_promises = require("node:fs/promises");
|
|
41
|
+
let github_slugger = require("github-slugger");
|
|
42
|
+
github_slugger = __toESM(github_slugger, 1);
|
|
43
|
+
let mdast_util_to_string = require("mdast-util-to-string");
|
|
38
44
|
let remark = require("remark");
|
|
39
45
|
let gray_matter = require("gray-matter");
|
|
40
46
|
gray_matter = __toESM(gray_matter, 1);
|
|
@@ -47,38 +53,11 @@ let _apidevtools_swagger_parser = require("@apidevtools/swagger-parser");
|
|
|
47
53
|
_apidevtools_swagger_parser = __toESM(_apidevtools_swagger_parser, 1);
|
|
48
54
|
let node_os = require("node:os");
|
|
49
55
|
let node_module = require("node:module");
|
|
50
|
-
//#region source/parsers/markdown/utils.ts
|
|
51
|
-
function escapeHtml(text) {
|
|
52
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
53
|
-
}
|
|
54
|
-
//#endregion
|
|
55
56
|
//#region source/parsers/markdown/mdx.ts
|
|
56
57
|
function getLanguage(className) {
|
|
57
58
|
return (Array.isArray(className) ? className : typeof className === "string" ? className.split(/\s+/) : []).find((item) => typeof item === "string" && item.startsWith("language-"))?.replace(/^language-/, "") || "txt";
|
|
58
59
|
}
|
|
59
|
-
function getTextContent(node) {
|
|
60
|
-
if (!node) return "";
|
|
61
|
-
if (typeof node.value === "string") return node.value;
|
|
62
|
-
return node.children?.map(getTextContent).join("") ?? "";
|
|
63
|
-
}
|
|
64
|
-
function renderPlainCode(code) {
|
|
65
|
-
return code.split("\n").map((line) => `<span>${escapeHtml(line)}</span>`).join("\n");
|
|
66
|
-
}
|
|
67
|
-
function isBundledLanguage(language) {
|
|
68
|
-
return language in shiki.bundledLanguages;
|
|
69
|
-
}
|
|
70
|
-
var highlighter;
|
|
71
60
|
var cssVariablesTheme = (0, shiki.createCssVariablesTheme)();
|
|
72
|
-
async function getHighlighter() {
|
|
73
|
-
highlighter = highlighter ?? await (0, shiki.createHighlighter)({
|
|
74
|
-
themes: [cssVariablesTheme],
|
|
75
|
-
langs: []
|
|
76
|
-
});
|
|
77
|
-
return highlighter;
|
|
78
|
-
}
|
|
79
|
-
function renderHighlightedCode(html) {
|
|
80
|
-
return (/<code[^>]*>([\s\S]*?)<\/code>/.exec(html)?.[1] ?? html).split("\n").map((line) => line.trimStart().startsWith("<span") ? line : `<span>${line}</span>`).join("\n");
|
|
81
|
-
}
|
|
82
61
|
function rehypeParseCodeBlocks() {
|
|
83
62
|
return (tree) => {
|
|
84
63
|
(0, unist_util_visit.visit)(tree, "element", (node, _nodeIndex, parentNode) => {
|
|
@@ -96,61 +75,18 @@ function rehypeParseCodeBlocks() {
|
|
|
96
75
|
});
|
|
97
76
|
};
|
|
98
77
|
}
|
|
99
|
-
function rehypeShiki() {
|
|
100
|
-
return async (tree) => {
|
|
101
|
-
const shikiHighlighter = await getHighlighter();
|
|
102
|
-
const languages = /* @__PURE__ */ new Set();
|
|
103
|
-
(0, unist_util_visit.visit)(tree, "element", (node) => {
|
|
104
|
-
if (node.tagName !== "pre") return;
|
|
105
|
-
const codeNode = node.children?.[0];
|
|
106
|
-
if (codeNode?.tagName !== "code") return;
|
|
107
|
-
const language = typeof node.properties?.language === "string" ? node.properties.language : getLanguage(codeNode.properties?.className);
|
|
108
|
-
if (language && language !== "txt" && isBundledLanguage(language)) languages.add(language);
|
|
109
|
-
});
|
|
110
|
-
if (languages.size > 0) await shikiHighlighter.loadLanguage(...languages);
|
|
111
|
-
(0, unist_util_visit.visit)(tree, "element", (node) => {
|
|
112
|
-
if (node.tagName !== "pre") return;
|
|
113
|
-
const codeNode = node.children?.[0];
|
|
114
|
-
if (codeNode?.tagName !== "code") return;
|
|
115
|
-
node.properties = node.properties ?? {};
|
|
116
|
-
codeNode.properties = codeNode.properties ?? {};
|
|
117
|
-
const code = getTextContent(codeNode);
|
|
118
|
-
const language = typeof node.properties.language === "string" ? node.properties.language : getLanguage(codeNode.properties.className);
|
|
119
|
-
node.properties.code = code;
|
|
120
|
-
codeNode.properties.code = code;
|
|
121
|
-
codeNode.properties.language = language;
|
|
122
|
-
let highlighted = renderPlainCode(code);
|
|
123
|
-
if (language && language !== "txt") try {
|
|
124
|
-
highlighted = renderHighlightedCode(shikiHighlighter.codeToHtml(code, {
|
|
125
|
-
lang: language,
|
|
126
|
-
theme: cssVariablesTheme
|
|
127
|
-
}));
|
|
128
|
-
} catch {
|
|
129
|
-
highlighted = renderPlainCode(code);
|
|
130
|
-
}
|
|
131
|
-
codeNode.children = [{
|
|
132
|
-
type: "text",
|
|
133
|
-
value: highlighted
|
|
134
|
-
}];
|
|
135
|
-
});
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
function rehypeSlugSections() {
|
|
139
|
-
return (tree) => {
|
|
140
|
-
const slugger = new github_slugger.default();
|
|
141
|
-
(0, unist_util_visit.visit)(tree, "element", (node) => {
|
|
142
|
-
if (node.tagName !== "h2" && node.tagName !== "h3") return;
|
|
143
|
-
node.properties = node.properties ?? {};
|
|
144
|
-
if (node.properties.id) return;
|
|
145
|
-
node.properties.id = slugger.slug((0, mdast_util_to_string.toString)(node));
|
|
146
|
-
});
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
78
|
var remarkPlugins = _clarify_labs_renderer.markdownRemarkPlugins;
|
|
150
79
|
var rehypePlugins = [
|
|
151
|
-
|
|
80
|
+
rehype_slug.default,
|
|
152
81
|
rehypeParseCodeBlocks,
|
|
153
|
-
|
|
82
|
+
[_shikijs_rehype.default, {
|
|
83
|
+
theme: cssVariablesTheme,
|
|
84
|
+
langs: [],
|
|
85
|
+
lazy: true,
|
|
86
|
+
addLanguageClass: true,
|
|
87
|
+
fallbackLanguage: "text",
|
|
88
|
+
parseMetaString: _clarify_labs_renderer.parseCodeMeta
|
|
89
|
+
}]
|
|
154
90
|
];
|
|
155
91
|
function formatMdxDiagnostic(error) {
|
|
156
92
|
if (error instanceof Error) return error.message;
|
|
@@ -162,7 +98,8 @@ function formatMdxDiagnostic(error) {
|
|
|
162
98
|
*
|
|
163
99
|
* `rehypePlugins` includes `rehypeShiki`, which loads grammar/WASM assets and
|
|
164
100
|
* is expensive. The real highlighting happens at Vite build time via the
|
|
165
|
-
* `@mdx-js/rollup`
|
|
101
|
+
* `@mdx-js/rollup` plugins (see `createMarkdownPlugin` and `createMdxPlugin`
|
|
102
|
+
* in `core/adapters.ts`), which
|
|
166
103
|
* runs the full remark + rehype pipeline. Re-running it here, during route
|
|
167
104
|
* discovery (Phase 3), would compile every `.mdx` file twice and invoke Shiki
|
|
168
105
|
* once per file per `engine.refresh()` — see ARCHITECTURE.md §2.2 which states
|
|
@@ -311,6 +248,11 @@ function kebabToTitle(str) {
|
|
|
311
248
|
function parseMdxTree(content) {
|
|
312
249
|
return remark.remark.parse(content);
|
|
313
250
|
}
|
|
251
|
+
async function compileRouteDiagnostic(content, filePath, baseDir) {
|
|
252
|
+
if ((0, node_path.extname)(filePath).toLowerCase() !== ".mdx") return void 0;
|
|
253
|
+
const result = await compileMdxContent(content, filePath, baseDir);
|
|
254
|
+
return result.ok ? void 0 : result.diagnostic;
|
|
255
|
+
}
|
|
314
256
|
/** 从内容中提取第一个 H1 标题 */
|
|
315
257
|
function extractH1(content) {
|
|
316
258
|
const tree = parseMdxTree(content);
|
|
@@ -336,12 +278,12 @@ function extractMdxSections(content) {
|
|
|
336
278
|
return sections;
|
|
337
279
|
}
|
|
338
280
|
function navigationSections(sections) {
|
|
339
|
-
return sections.map((
|
|
340
|
-
id:
|
|
341
|
-
title:
|
|
342
|
-
level:
|
|
343
|
-
badge:
|
|
344
|
-
tags:
|
|
281
|
+
return sections.map((section) => ({
|
|
282
|
+
id: section.id,
|
|
283
|
+
title: section.title,
|
|
284
|
+
level: section.level,
|
|
285
|
+
badge: section.badge,
|
|
286
|
+
tags: section.tags
|
|
345
287
|
}));
|
|
346
288
|
}
|
|
347
289
|
function normalizePath(path) {
|
|
@@ -405,7 +347,7 @@ async function findContentRoutes(dir, base = dir, options = {}) {
|
|
|
405
347
|
frontmatter,
|
|
406
348
|
content
|
|
407
349
|
};
|
|
408
|
-
const
|
|
350
|
+
const diagnostic = await compileRouteDiagnostic(page.content, fullPath, base);
|
|
409
351
|
let title = typeof page.frontmatter.title === "string" ? page.frontmatter.title : "";
|
|
410
352
|
if (!title) {
|
|
411
353
|
const lastPart = pathParts[pathParts.length - 1] ?? "";
|
|
@@ -413,17 +355,21 @@ async function findContentRoutes(dir, base = dir, options = {}) {
|
|
|
413
355
|
}
|
|
414
356
|
routes.push({
|
|
415
357
|
kind: "mdx",
|
|
416
|
-
title,
|
|
417
358
|
path: cleanPath,
|
|
418
359
|
basePath: cleanPath,
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
360
|
+
meta: {
|
|
361
|
+
title,
|
|
362
|
+
description: typeof page.frontmatter.description === "string" ? page.frontmatter.description : void 0,
|
|
363
|
+
keywords: frontmatterKeywords(page.frontmatter),
|
|
364
|
+
sections: extractMdxSections(page.content)
|
|
365
|
+
},
|
|
366
|
+
module: { virtualModuleId: "virtual:clarify-page/" + relativePath.replace(/\.mdx?$/, "").replace(/\/+/g, "/") },
|
|
367
|
+
source: {
|
|
368
|
+
filePath: fullPath,
|
|
369
|
+
frontmatter: page.frontmatter,
|
|
370
|
+
content: page.content
|
|
371
|
+
},
|
|
372
|
+
diagnostic
|
|
427
373
|
});
|
|
428
374
|
}
|
|
429
375
|
}
|
|
@@ -482,7 +428,7 @@ async function findLocalizedContentRoutes(contentRoot, i18n, options = {}) {
|
|
|
482
428
|
path: localizedRoutePath(basePath, locale.code, i18n),
|
|
483
429
|
basePath,
|
|
484
430
|
locale: locale.code,
|
|
485
|
-
virtualModuleId: virtualModuleIdForLocalizedRoute(contentRoot, route.filePath)
|
|
431
|
+
module: { virtualModuleId: virtualModuleIdForLocalizedRoute(contentRoot, route.source.filePath) }
|
|
486
432
|
});
|
|
487
433
|
}
|
|
488
434
|
}
|
|
@@ -518,12 +464,12 @@ function buildNavigation(routes) {
|
|
|
518
464
|
if (!node) {
|
|
519
465
|
node = {
|
|
520
466
|
path: pathSoFar,
|
|
521
|
-
title: i === parts.length - 1 ? route.title : kebabToTitle(parts[i]),
|
|
467
|
+
title: i === parts.length - 1 ? route.meta.title : kebabToTitle(parts[i]),
|
|
522
468
|
children: []
|
|
523
469
|
};
|
|
524
470
|
current.push(node);
|
|
525
471
|
}
|
|
526
|
-
if (i === parts.length - 1 && route.sections) node.sections = navigationSections(route.sections);
|
|
472
|
+
if (i === parts.length - 1 && route.meta.sections) node.sections = navigationSections(route.meta.sections);
|
|
527
473
|
if (i < parts.length - 1) {
|
|
528
474
|
node.children = node.children ?? [];
|
|
529
475
|
current = node.children;
|
|
@@ -532,17 +478,22 @@ function buildNavigation(routes) {
|
|
|
532
478
|
}
|
|
533
479
|
return root;
|
|
534
480
|
}
|
|
535
|
-
function
|
|
536
|
-
if (typeof item === "string") return {
|
|
481
|
+
function routeIntentFromPagesItem(item) {
|
|
482
|
+
if (typeof item === "string") return {
|
|
483
|
+
kind: "page",
|
|
484
|
+
ref: item
|
|
485
|
+
};
|
|
537
486
|
if ("openapi" in item) return {
|
|
538
|
-
|
|
539
|
-
|
|
487
|
+
kind: "openapi",
|
|
488
|
+
ref: item.openapi,
|
|
489
|
+
tagFilter: item.filter?.tags,
|
|
540
490
|
path: item.path,
|
|
541
491
|
title: item.title,
|
|
542
492
|
icon: item.icon
|
|
543
493
|
};
|
|
544
494
|
return {
|
|
545
|
-
|
|
495
|
+
kind: "page",
|
|
496
|
+
ref: item.page,
|
|
546
497
|
path: item.path,
|
|
547
498
|
redirect: item.redirect,
|
|
548
499
|
title: item.title,
|
|
@@ -557,25 +508,28 @@ function firstNavigationPath(nodes) {
|
|
|
557
508
|
}
|
|
558
509
|
return "/";
|
|
559
510
|
}
|
|
560
|
-
function
|
|
561
|
-
const
|
|
511
|
+
function collectExplicitPagePathIntents(tabs) {
|
|
512
|
+
const intents = [];
|
|
562
513
|
for (const tab of tabs ?? []) {
|
|
563
514
|
if (!tab.pages || tab.pages === "FileTree") continue;
|
|
564
|
-
for (const group of tab.pages) for (const item of group.pages) if (typeof item !== "string" && "page" in item && item.path)
|
|
565
|
-
|
|
566
|
-
path
|
|
567
|
-
|
|
515
|
+
for (const group of tab.pages) for (const item of group.pages) if (typeof item !== "string" && "page" in item && item.path) {
|
|
516
|
+
const intent = routeIntentFromPagesItem(item);
|
|
517
|
+
if (intent.kind === "page" && intent.path) intents.push({
|
|
518
|
+
...intent,
|
|
519
|
+
path: intent.path
|
|
520
|
+
});
|
|
521
|
+
}
|
|
568
522
|
}
|
|
569
|
-
return
|
|
523
|
+
return intents;
|
|
570
524
|
}
|
|
571
525
|
function applyConfiguredPageRoutePaths(routes, tabs, i18n) {
|
|
572
|
-
const
|
|
573
|
-
if (!
|
|
526
|
+
const pageIntents = collectExplicitPagePathIntents(tabs);
|
|
527
|
+
if (!pageIntents.length) return routes;
|
|
574
528
|
const additions = [];
|
|
575
529
|
const existingKeys = new Set(routes.map((route) => `${route.locale ?? ""}:${route.basePath ?? route.path}`));
|
|
576
|
-
for (const
|
|
577
|
-
const sourceBasePath = routePathFromRef(
|
|
578
|
-
const targetBasePath = routePathFromRef(
|
|
530
|
+
for (const intent of pageIntents) {
|
|
531
|
+
const sourceBasePath = routePathFromRef(intent.ref);
|
|
532
|
+
const targetBasePath = routePathFromRef(intent.ref, intent.path);
|
|
579
533
|
if (sourceBasePath === targetBasePath) continue;
|
|
580
534
|
for (const route of routes) {
|
|
581
535
|
if (route.kind !== "mdx" || (route.basePath ?? route.path) !== sourceBasePath) continue;
|
|
@@ -599,40 +553,42 @@ function buildNavigationFromPagesConfig(routes, config) {
|
|
|
599
553
|
return buildNavigationFromConfig(routes, config);
|
|
600
554
|
}
|
|
601
555
|
function buildNavigationFromTabsConfig(routes, tabs) {
|
|
602
|
-
return {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
556
|
+
return {
|
|
557
|
+
kind: "tabbed",
|
|
558
|
+
tabs: tabs.map((tab) => {
|
|
559
|
+
const children = buildNavigationFromPagesConfig(routes, tab.pages);
|
|
560
|
+
return {
|
|
561
|
+
type: "tab",
|
|
562
|
+
path: firstNavigationPath(children),
|
|
563
|
+
title: resolveLocalizedText(tab.tab, "", "") ?? "",
|
|
564
|
+
icon: tab.icon,
|
|
565
|
+
children
|
|
566
|
+
};
|
|
567
|
+
})
|
|
568
|
+
};
|
|
612
569
|
}
|
|
613
570
|
function buildNavigationFromConfig(routes, config) {
|
|
614
571
|
const routeMap = new Map(routes.map((r) => [r.path, r]));
|
|
615
572
|
return config.map((group) => {
|
|
616
573
|
const children = group.pages.map((item) => {
|
|
617
|
-
const
|
|
618
|
-
if (
|
|
619
|
-
const path = openAPIPagePathFromRef(
|
|
574
|
+
const intent = routeIntentFromPagesItem(item);
|
|
575
|
+
if (intent.kind === "openapi") {
|
|
576
|
+
const path = openAPIPagePathFromRef(intent.ref, intent.tagFilter, intent.path);
|
|
620
577
|
const route = routeMap.get(path);
|
|
621
578
|
return {
|
|
622
579
|
path,
|
|
623
|
-
title: resolveLocalizedText(title, "", "") ?? route?.title ?? kebabToTitle(path.split("/").pop() ??
|
|
624
|
-
icon,
|
|
625
|
-
sections: route?.sections ? navigationSections(route.sections) : void 0
|
|
580
|
+
title: resolveLocalizedText(intent.title, "", "") ?? route?.meta.title ?? kebabToTitle(path.split("/").pop() ?? intent.ref),
|
|
581
|
+
icon: intent.icon,
|
|
582
|
+
sections: route?.meta.sections ? navigationSections(route.meta.sections) : void 0
|
|
626
583
|
};
|
|
627
584
|
}
|
|
628
|
-
const
|
|
629
|
-
const path = routePathFromRef(ref, explicitPath);
|
|
585
|
+
const path = routePathFromRef(intent.ref, intent.path);
|
|
630
586
|
const route = routeMap.get(path);
|
|
631
587
|
return {
|
|
632
|
-
path: redirect ? normalizePath(redirect) : path,
|
|
633
|
-
title: resolveLocalizedText(title, "", "") ?? route?.title ?? kebabToTitle(path.split("/").pop() ?? ref),
|
|
634
|
-
icon,
|
|
635
|
-
sections: route?.sections ? navigationSections(route.sections) : void 0
|
|
588
|
+
path: intent.redirect ? normalizePath(intent.redirect) : path,
|
|
589
|
+
title: resolveLocalizedText(intent.title, "", "") ?? route?.meta.title ?? kebabToTitle(path.split("/").pop() ?? intent.ref),
|
|
590
|
+
icon: intent.icon,
|
|
591
|
+
sections: route?.meta.sections ? navigationSections(route.meta.sections) : void 0
|
|
636
592
|
};
|
|
637
593
|
});
|
|
638
594
|
return {
|
|
@@ -658,16 +614,15 @@ function buildLocalizedNavigationForLocale(routes, config, locale, i18n) {
|
|
|
658
614
|
const routeMap = new Map(routes.map((route) => [route.basePath ?? route.path, route]));
|
|
659
615
|
return config.map((group) => {
|
|
660
616
|
const children = group.pages.map((item) => {
|
|
661
|
-
const
|
|
662
|
-
const
|
|
663
|
-
const basePath = openapiRef ? openAPIPagePathFromRef(openapiRef, openapiTagFilter, explicitPath) : routePathFromRef(ref, explicitPath);
|
|
617
|
+
const intent = routeIntentFromPagesItem(item);
|
|
618
|
+
const basePath = intent.kind === "openapi" ? openAPIPagePathFromRef(intent.ref, intent.tagFilter, intent.path) : routePathFromRef(intent.ref, intent.path);
|
|
664
619
|
const route = routeMap.get(basePath);
|
|
665
620
|
const path = route?.path ?? localizedRoutePath(basePath, locale, i18n);
|
|
666
621
|
return {
|
|
667
|
-
path: (redirect ? localizedRoutePath(routePathFromRef(redirect), locale, i18n) : void 0) ?? path,
|
|
668
|
-
title: resolveLocalizedText(title, locale, i18n.defaultLocale) ?? route?.title ?? kebabToTitle(basePath.split("/").pop() ?? ref),
|
|
669
|
-
icon,
|
|
670
|
-
sections: route?.sections ? navigationSections(route.sections) : void 0
|
|
622
|
+
path: (intent.kind === "page" && intent.redirect ? localizedRoutePath(routePathFromRef(intent.redirect), locale, i18n) : void 0) ?? path,
|
|
623
|
+
title: resolveLocalizedText(intent.title, locale, i18n.defaultLocale) ?? route?.meta.title ?? kebabToTitle(basePath.split("/").pop() ?? intent.ref),
|
|
624
|
+
icon: intent.icon,
|
|
625
|
+
sections: route?.meta.sections ? navigationSections(route.meta.sections) : void 0
|
|
671
626
|
};
|
|
672
627
|
});
|
|
673
628
|
return {
|
|
@@ -680,10 +635,10 @@ function buildLocalizedNavigationForLocale(routes, config, locale, i18n) {
|
|
|
680
635
|
}
|
|
681
636
|
function buildLocalizedNavigationFromTabsConfig(routes, tabs, i18n) {
|
|
682
637
|
if (!i18n) return void 0;
|
|
683
|
-
const
|
|
638
|
+
const locales = {};
|
|
684
639
|
for (const locale of i18n.locales) {
|
|
685
640
|
const localeRoutes = routes.filter((route) => route.locale === locale.code);
|
|
686
|
-
|
|
641
|
+
locales[locale.code] = { tabs: tabs.map((tab) => {
|
|
687
642
|
const children = buildLocalizedNavigationForLocale(localeRoutes, tab.pages, locale.code, i18n);
|
|
688
643
|
return {
|
|
689
644
|
type: "tab",
|
|
@@ -694,17 +649,20 @@ function buildLocalizedNavigationFromTabsConfig(routes, tabs, i18n) {
|
|
|
694
649
|
};
|
|
695
650
|
}) };
|
|
696
651
|
}
|
|
697
|
-
return
|
|
652
|
+
return {
|
|
653
|
+
kind: "localized-tabbed",
|
|
654
|
+
locales
|
|
655
|
+
};
|
|
698
656
|
}
|
|
699
657
|
/** Serialize a ContentRoute into the minimal shape exposed to tooling. */
|
|
700
658
|
function toDevRouteEntry(route) {
|
|
701
659
|
return {
|
|
702
660
|
path: route.path,
|
|
703
|
-
filePath: route.filePath,
|
|
661
|
+
filePath: route.source.filePath,
|
|
704
662
|
locale: route.locale,
|
|
705
663
|
basePath: route.basePath,
|
|
706
664
|
kind: route.kind,
|
|
707
|
-
title: route.title
|
|
665
|
+
title: route.meta.title
|
|
708
666
|
};
|
|
709
667
|
}
|
|
710
668
|
/**
|
|
@@ -718,7 +676,7 @@ function toDevRouteEntry(route) {
|
|
|
718
676
|
* or the first match.
|
|
719
677
|
*/
|
|
720
678
|
function resolveRouteForFile(filePath, routes, defaultLocale) {
|
|
721
|
-
const matches = routes.filter((r) => r.filePath === filePath);
|
|
679
|
+
const matches = routes.filter((r) => r.source.filePath === filePath);
|
|
722
680
|
if (matches.length === 0) return void 0;
|
|
723
681
|
if (matches.length === 1) return matches[0];
|
|
724
682
|
const fileLocale = inferLocaleFromPath(filePath);
|
|
@@ -1143,6 +1101,7 @@ var VIRTUAL_CONFIG = "virtual:clarify/config";
|
|
|
1143
1101
|
var VIRTUAL_ROUTES = "virtual:clarify/routes";
|
|
1144
1102
|
var VIRTUAL_SERVER_ROUTES = "virtual:clarify/routes/server";
|
|
1145
1103
|
var VIRTUAL_OPENAPI = "virtual:clarify/openapi";
|
|
1104
|
+
var VIRTUAL_OPENAPI_SERVER = "virtual:clarify/openapi/server";
|
|
1146
1105
|
var VIRTUAL_SLOTS = "virtual:clarify/slots";
|
|
1147
1106
|
var VIRTUAL_SLOT = "virtual:clarify/slot";
|
|
1148
1107
|
var VIRTUAL_CLIENT_ENTRY = "virtual:clarify/entry-client";
|
|
@@ -1163,6 +1122,7 @@ var FIXED_VIRTUAL_IDS = [
|
|
|
1163
1122
|
VIRTUAL_ROUTES,
|
|
1164
1123
|
VIRTUAL_SERVER_ROUTES,
|
|
1165
1124
|
VIRTUAL_OPENAPI,
|
|
1125
|
+
VIRTUAL_OPENAPI_SERVER,
|
|
1166
1126
|
VIRTUAL_SLOTS,
|
|
1167
1127
|
VIRTUAL_SLOT
|
|
1168
1128
|
];
|
|
@@ -1179,8 +1139,8 @@ function resolveVirtualModuleId(id, modules, routes) {
|
|
|
1179
1139
|
for (const virtualId of FIXED_VIRTUAL_IDS) if (id === virtualId || id === resolveVirtualId(virtualId)) return resolveVirtualId(virtualId);
|
|
1180
1140
|
const moduleId = stripVirtualPrefix(id);
|
|
1181
1141
|
if (modules.has(moduleId)) return resolveVirtualId(moduleId);
|
|
1182
|
-
const route = routes.find((route) => route.virtualModuleId === id || route.virtualModuleId === moduleId);
|
|
1183
|
-
if (route) return resolveVirtualId(route.virtualModuleId);
|
|
1142
|
+
const route = routes.find((route) => route.module.virtualModuleId === id || route.module.virtualModuleId === moduleId);
|
|
1143
|
+
if (route) return resolveVirtualId(route.module.virtualModuleId);
|
|
1184
1144
|
return null;
|
|
1185
1145
|
}
|
|
1186
1146
|
function generateConfigModule(projectConfig, buildOptions, version) {
|
|
@@ -1194,38 +1154,38 @@ function generateConfigModule(projectConfig, buildOptions, version) {
|
|
|
1194
1154
|
function moduleSpecifier(value) {
|
|
1195
1155
|
return JSON.stringify(value);
|
|
1196
1156
|
}
|
|
1197
|
-
function
|
|
1198
|
-
const
|
|
1157
|
+
function routeToRuntimeManifestEntry(route, component, mode) {
|
|
1158
|
+
const entry = {
|
|
1199
1159
|
path: route.path,
|
|
1200
|
-
title: route.title,
|
|
1160
|
+
title: route.meta.title,
|
|
1201
1161
|
component,
|
|
1202
1162
|
kind: route.kind
|
|
1203
1163
|
};
|
|
1204
|
-
if (mode === "client")
|
|
1205
|
-
if (route.basePath)
|
|
1206
|
-
if (route.locale)
|
|
1207
|
-
if (route.isFallback)
|
|
1208
|
-
if (route.isBareAlias)
|
|
1209
|
-
if (route.alternates)
|
|
1210
|
-
if (route.description)
|
|
1211
|
-
if (route.keywords?.length)
|
|
1212
|
-
if (route.contentArtifactUrl)
|
|
1213
|
-
if (route.
|
|
1214
|
-
if (route.sections?.length)
|
|
1215
|
-
id:
|
|
1216
|
-
title:
|
|
1217
|
-
level:
|
|
1218
|
-
badge:
|
|
1219
|
-
tags:
|
|
1164
|
+
if (mode === "client") entry.lazy = true;
|
|
1165
|
+
if (route.basePath) entry.basePath = route.basePath;
|
|
1166
|
+
if (route.locale) entry.locale = route.locale;
|
|
1167
|
+
if (route.isFallback) entry.isFallback = true;
|
|
1168
|
+
if (route.isBareAlias) entry.isBareAlias = true;
|
|
1169
|
+
if (route.alternates) entry.alternates = route.alternates;
|
|
1170
|
+
if (route.meta.description) entry.description = route.meta.description;
|
|
1171
|
+
if (route.meta.keywords?.length) entry.keywords = route.meta.keywords;
|
|
1172
|
+
if (route.artifacts?.contentArtifactUrl) entry.contentArtifactUrl = route.artifacts.contentArtifactUrl;
|
|
1173
|
+
if (route.source?.sourceEditUrl) entry.sourceEditUrl = route.source.sourceEditUrl;
|
|
1174
|
+
if (route.meta.sections?.length) entry.sections = route.meta.sections.map((section) => ({
|
|
1175
|
+
id: section.id,
|
|
1176
|
+
title: section.title,
|
|
1177
|
+
level: section.level,
|
|
1178
|
+
badge: section.badge,
|
|
1179
|
+
tags: section.tags
|
|
1220
1180
|
}));
|
|
1221
|
-
return
|
|
1181
|
+
return entry;
|
|
1222
1182
|
}
|
|
1223
1183
|
function generateRoutesModule(routes, navigation, mode = "client") {
|
|
1224
|
-
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) => {
|
|
1225
|
-
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 }) }))`;
|
|
1184
|
+
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) => {
|
|
1185
|
+
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 }) }))`;
|
|
1226
1186
|
const placeholder = `__COMPONENT_${i}__`;
|
|
1227
|
-
const
|
|
1228
|
-
return ` ${JSON.stringify(
|
|
1187
|
+
const manifestEntry = routeToRuntimeManifestEntry(r, placeholder, mode);
|
|
1188
|
+
return ` ${JSON.stringify(manifestEntry, null, 0).replace(`"${placeholder}"`, component).replace(/"([A-Za-z_$][\w$]*)":/g, "$1: ")}`;
|
|
1229
1189
|
}).join(",\n")}\n];\n\nexport const navigation = ${JSON.stringify(navigation, null, 2)};\n`;
|
|
1230
1190
|
}
|
|
1231
1191
|
function createClientEntryModule(options = {}) {
|
|
@@ -1234,9 +1194,15 @@ import '@clarify-labs/renderer/style.css';
|
|
|
1234
1194
|
import { render } from '@clarify-labs/renderer/client';
|
|
1235
1195
|
import { routes, navigation } from '${VIRTUAL_ROUTES}';
|
|
1236
1196
|
import { config } from '${VIRTUAL_CONFIG}';
|
|
1237
|
-
import {
|
|
1197
|
+
import { openApiSpecs } from '${VIRTUAL_OPENAPI}';
|
|
1238
1198
|
import { runtimeSlots } from '${VIRTUAL_SLOTS}';
|
|
1239
|
-
|
|
1199
|
+
const renderOptions = { config, routes, navigation, openApiSpecs, runtimeSlots, themeEditor: ${JSON.stringify(options.themeEditor ?? false)} };
|
|
1200
|
+
render(renderOptions);
|
|
1201
|
+
if (import.meta.hot) {
|
|
1202
|
+
import.meta.hot.accept('${VIRTUAL_ROUTES}', (mod) => {
|
|
1203
|
+
render({ ...renderOptions, routes: mod.routes, navigation: mod.navigation });
|
|
1204
|
+
});
|
|
1205
|
+
}`;
|
|
1240
1206
|
}
|
|
1241
1207
|
/**
|
|
1242
1208
|
* Collect every plugin's `slots` declarations into a single runtime registry
|
|
@@ -1265,7 +1231,7 @@ function createRuntimeSlotsModule(plugins = [], root = process.cwd()) {
|
|
|
1265
1231
|
}
|
|
1266
1232
|
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.`);
|
|
1267
1233
|
const componentPath = root + slot.component;
|
|
1268
|
-
const entry = `{ plugin: ${JSON.stringify(plugin)},
|
|
1234
|
+
const entry = `{ plugin: ${JSON.stringify(plugin)}, loadComponent: () => import(${moduleSpecifier(componentPath)}) }`;
|
|
1269
1235
|
const list = grouped.get(slot.name) ?? [];
|
|
1270
1236
|
list.push(entry);
|
|
1271
1237
|
grouped.set(slot.name, list);
|
|
@@ -1294,18 +1260,34 @@ function buildVirtualModules(args) {
|
|
|
1294
1260
|
modules.set(VIRTUAL_ROUTES, generateRoutesModule(args.routes, args.navigation, "client"));
|
|
1295
1261
|
modules.set(VIRTUAL_SERVER_ROUTES, generateRoutesModule(args.routes, args.navigation, "server"));
|
|
1296
1262
|
modules.set(VIRTUAL_SLOTS, createRuntimeSlotsModule(allPlugins, args.generateOptions.projectRoot));
|
|
1297
|
-
modules.set(VIRTUAL_OPENAPI, "export const
|
|
1263
|
+
modules.set(VIRTUAL_OPENAPI, "export const openApiSpecs = {};");
|
|
1298
1264
|
modules.set(VIRTUAL_SLOT, "export { useSlot } from '@clarify-labs/renderer';\n");
|
|
1299
1265
|
modules.set(VIRTUAL_CLIENT_ENTRY, clientEntryModule);
|
|
1300
1266
|
modules.set(RESOLVED_CLIENT_ENTRY, clientEntryModule);
|
|
1301
1267
|
for (const route of args.routes) {
|
|
1302
|
-
const moduleContent = route.diagnostic ? generateMdxErrorModule(route.diagnostic) : `export { default } from ${moduleSpecifier(route.filePath)};`;
|
|
1303
|
-
modules.set(route.virtualModuleId, moduleContent);
|
|
1268
|
+
const moduleContent = route.diagnostic ? generateMdxErrorModule(route.diagnostic) : `export { default } from ${moduleSpecifier(route.source.filePath)};`;
|
|
1269
|
+
modules.set(route.module.virtualModuleId, moduleContent);
|
|
1304
1270
|
}
|
|
1305
1271
|
return modules;
|
|
1306
1272
|
}
|
|
1307
1273
|
//#endregion
|
|
1308
1274
|
//#region source/core/adapters.ts
|
|
1275
|
+
function routeStructure(route) {
|
|
1276
|
+
const { content: _content, ...source } = route.source;
|
|
1277
|
+
return {
|
|
1278
|
+
...route,
|
|
1279
|
+
source
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
1282
|
+
function createDevStructureSnapshot(routes, navigation) {
|
|
1283
|
+
return {
|
|
1284
|
+
routes: JSON.stringify(routes.map(routeStructure)),
|
|
1285
|
+
navigation: JSON.stringify(navigation)
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
function hasDevStructureChanged(before, after) {
|
|
1289
|
+
return before.routes !== after.routes || before.navigation !== after.navigation;
|
|
1290
|
+
}
|
|
1309
1291
|
function invalidateVirtualModules(engine, server) {
|
|
1310
1292
|
for (const id of engine.modules.keys()) {
|
|
1311
1293
|
const moduleNode = server.moduleGraph.getModuleById(resolveVirtualId(id));
|
|
@@ -1313,20 +1295,22 @@ function invalidateVirtualModules(engine, server) {
|
|
|
1313
1295
|
}
|
|
1314
1296
|
}
|
|
1315
1297
|
async function refreshDevServer(engine, server) {
|
|
1298
|
+
const before = createDevStructureSnapshot(engine.routes, engine.navigation);
|
|
1316
1299
|
await engine.refresh();
|
|
1317
1300
|
invalidateVirtualModules(engine, server);
|
|
1301
|
+
return hasDevStructureChanged(before, createDevStructureSnapshot(engine.routes, engine.navigation));
|
|
1318
1302
|
}
|
|
1319
|
-
function
|
|
1303
|
+
function createNormalizedContentPlugin(engine) {
|
|
1320
1304
|
return {
|
|
1321
|
-
name: "clarify:normalized-
|
|
1305
|
+
name: "clarify:normalized-content",
|
|
1322
1306
|
enforce: "pre",
|
|
1323
1307
|
transform(_code, id) {
|
|
1324
1308
|
if (!/\.mdx?(?:\?|$)/.test(id)) return null;
|
|
1325
1309
|
const filePath = id.replace(/\?.*$/, "");
|
|
1326
|
-
const route = engine.routes.find((route) => route.kind === "mdx" && route.filePath === filePath);
|
|
1327
|
-
if (!route || route.content === void 0) return null;
|
|
1310
|
+
const route = engine.routes.find((route) => route.kind === "mdx" && route.source.filePath === filePath);
|
|
1311
|
+
if (!route || route.source.content === void 0) return null;
|
|
1328
1312
|
return {
|
|
1329
|
-
code: route.content,
|
|
1313
|
+
code: route.source.content,
|
|
1330
1314
|
map: null
|
|
1331
1315
|
};
|
|
1332
1316
|
}
|
|
@@ -1334,14 +1318,26 @@ function createNormalizedMdxContentPlugin(engine) {
|
|
|
1334
1318
|
}
|
|
1335
1319
|
function createMdxPlugin() {
|
|
1336
1320
|
return (0, _mdx_js_rollup.default)({
|
|
1337
|
-
include: ["**/*.
|
|
1321
|
+
include: ["**/*.mdx"],
|
|
1322
|
+
format: "mdx",
|
|
1338
1323
|
jsxImportSource: "react",
|
|
1339
1324
|
providerImportSource: "@clarify-labs/renderer",
|
|
1340
1325
|
remarkPlugins,
|
|
1341
1326
|
rehypePlugins
|
|
1342
1327
|
});
|
|
1343
1328
|
}
|
|
1344
|
-
function
|
|
1329
|
+
function createMarkdownPlugin() {
|
|
1330
|
+
return (0, _mdx_js_rollup.default)({
|
|
1331
|
+
include: ["**/*.md"],
|
|
1332
|
+
format: "md",
|
|
1333
|
+
jsxImportSource: "react",
|
|
1334
|
+
providerImportSource: "@clarify-labs/renderer",
|
|
1335
|
+
remarkPlugins,
|
|
1336
|
+
remarkRehypeOptions: { allowDangerousHtml: true },
|
|
1337
|
+
rehypePlugins: [rehype_raw.default, ...rehypePlugins]
|
|
1338
|
+
});
|
|
1339
|
+
}
|
|
1340
|
+
function createClarifyViteCorePlugin(engine, normalizedContentPlugin, markdown, mdx) {
|
|
1345
1341
|
let viteConfig;
|
|
1346
1342
|
return {
|
|
1347
1343
|
name: "clarify:core",
|
|
@@ -1380,8 +1376,13 @@ function createClarifyViteCorePlugin(engine, normalizedMdxContentPlugin, mdx) {
|
|
|
1380
1376
|
}
|
|
1381
1377
|
const relativeContentFile = (0, node_path.relative)(engine.contentRoot, changedFile);
|
|
1382
1378
|
if (!(relativeContentFile && !relativeContentFile.startsWith("..") && !(0, node_path.isAbsolute)(relativeContentFile)) || !engine.hasContentRouteForFile(changedFile)) return;
|
|
1383
|
-
await refreshDevServer(engine, ctx.server)
|
|
1384
|
-
|
|
1379
|
+
if (await refreshDevServer(engine, ctx.server)) {
|
|
1380
|
+
const routesModule = ctx.server.moduleGraph.getModuleById(resolveVirtualId(VIRTUAL_ROUTES));
|
|
1381
|
+
if (routesModule) return [...ctx.modules, routesModule];
|
|
1382
|
+
ctx.server.ws.send({ type: "full-reload" });
|
|
1383
|
+
return [];
|
|
1384
|
+
}
|
|
1385
|
+
return ctx.modules;
|
|
1385
1386
|
},
|
|
1386
1387
|
resolveId(id) {
|
|
1387
1388
|
return resolveVirtualModuleId(id, engine.modules, engine.routes);
|
|
@@ -1392,18 +1393,6 @@ function createClarifyViteCorePlugin(engine, normalizedMdxContentPlugin, mdx) {
|
|
|
1392
1393
|
async configureServer(server) {
|
|
1393
1394
|
server.watcher.add(engine.contentRoot);
|
|
1394
1395
|
if (engine.configFilePath) server.watcher.add(engine.configFilePath);
|
|
1395
|
-
let reloadQueued = false;
|
|
1396
|
-
const invalidateAndReload = () => {
|
|
1397
|
-
if (reloadQueued) return;
|
|
1398
|
-
reloadQueued = true;
|
|
1399
|
-
queueMicrotask(() => {
|
|
1400
|
-
reloadQueued = false;
|
|
1401
|
-
invalidateVirtualModules(engine, server);
|
|
1402
|
-
server.ws.send({ type: "full-reload" });
|
|
1403
|
-
});
|
|
1404
|
-
};
|
|
1405
|
-
engine.ctx.onRoutesChange(invalidateAndReload);
|
|
1406
|
-
engine.ctx.onNavigationChange(invalidateAndReload);
|
|
1407
1396
|
server.middlewares.use((req, res, next) => {
|
|
1408
1397
|
if (req.url === "/dev/query-preview-route" && req.method === "POST") return handleDevRouteRequest(req, res, engine.routes, engine.runtimeContext());
|
|
1409
1398
|
if (req.url === "/dev/project-info" && (req.method === "GET" || req.method === "HEAD")) return handleProjectInfoRequest(req, res, engine.runtimeContext());
|
|
@@ -1413,7 +1402,7 @@ function createClarifyViteCorePlugin(engine, normalizedMdxContentPlugin, mdx) {
|
|
|
1413
1402
|
const changedFile = (0, node_path.isAbsolute)(filePath) ? filePath : (0, node_path.join)(engine.root, filePath);
|
|
1414
1403
|
const relativeContentFile = (0, node_path.relative)(engine.contentRoot, changedFile);
|
|
1415
1404
|
if (!(relativeContentFile && !relativeContentFile.startsWith("..") && !(0, node_path.isAbsolute)(relativeContentFile))) return;
|
|
1416
|
-
await refreshDevServer(engine, server);
|
|
1405
|
+
if (await refreshDevServer(engine, server)) server.ws.send({ type: "full-reload" });
|
|
1417
1406
|
};
|
|
1418
1407
|
server.watcher.on("add", handleContentTreeChange);
|
|
1419
1408
|
server.watcher.on("unlink", handleContentTreeChange);
|
|
@@ -1450,7 +1439,8 @@ function createClarifyViteCorePlugin(engine, normalizedMdxContentPlugin, mdx) {
|
|
|
1450
1439
|
outputDirectory: viteConfig.build.outDir,
|
|
1451
1440
|
ssrPlugins: [
|
|
1452
1441
|
engine.createSSGVirtualPlugin(),
|
|
1453
|
-
|
|
1442
|
+
normalizedContentPlugin,
|
|
1443
|
+
markdown,
|
|
1454
1444
|
mdx
|
|
1455
1445
|
]
|
|
1456
1446
|
});
|
|
@@ -1467,20 +1457,22 @@ function createClarifyViteCorePlugin(engine, normalizedMdxContentPlugin, mdx) {
|
|
|
1467
1457
|
* site itself - it only bridges Vite lifecycle hooks to the engine.
|
|
1468
1458
|
*/
|
|
1469
1459
|
function createViteAdapter(engine) {
|
|
1470
|
-
const
|
|
1460
|
+
const normalizedContentPlugin = createNormalizedContentPlugin(engine);
|
|
1461
|
+
const markdown = createMarkdownPlugin();
|
|
1471
1462
|
const mdx = createMdxPlugin();
|
|
1472
1463
|
const tailwind = (0, _tailwindcss_vite.default)();
|
|
1473
1464
|
return [
|
|
1474
1465
|
...(0, _vitejs_plugin_react.default)(),
|
|
1475
1466
|
...Array.isArray(tailwind) ? tailwind : [tailwind],
|
|
1476
|
-
|
|
1477
|
-
createClarifyViteCorePlugin(engine,
|
|
1467
|
+
normalizedContentPlugin,
|
|
1468
|
+
createClarifyViteCorePlugin(engine, normalizedContentPlugin, markdown, mdx),
|
|
1469
|
+
markdown,
|
|
1478
1470
|
mdx
|
|
1479
1471
|
];
|
|
1480
1472
|
}
|
|
1481
1473
|
var cliPackageVersion = {
|
|
1482
1474
|
name: "@clarify-labs/cli",
|
|
1483
|
-
version: "0.10.
|
|
1475
|
+
version: "0.10.2",
|
|
1484
1476
|
license: "AGPL-3.0-only",
|
|
1485
1477
|
type: "module",
|
|
1486
1478
|
repository: {
|
|
@@ -1521,6 +1513,7 @@ var cliPackageVersion = {
|
|
|
1521
1513
|
"@clarify-labs/templates": "workspace:*",
|
|
1522
1514
|
"@mdx-js/mdx": "^3.1.1",
|
|
1523
1515
|
"@mdx-js/rollup": "^3.1.1",
|
|
1516
|
+
"@shikijs/rehype": "^4.3.0",
|
|
1524
1517
|
"@tailwindcss/vite": "^4.3.2",
|
|
1525
1518
|
"@vitejs/plugin-react": "^6.0.3",
|
|
1526
1519
|
"cac": "^7.0.0",
|
|
@@ -1535,6 +1528,8 @@ var cliPackageVersion = {
|
|
|
1535
1528
|
"react-router": "^7.0.0",
|
|
1536
1529
|
"react-router-dom": "^7.0.0",
|
|
1537
1530
|
"react-zoom-pan-pinch": "^4.0.3",
|
|
1531
|
+
"rehype-raw": "^7.0.0",
|
|
1532
|
+
"rehype-slug": "^6.0.0",
|
|
1538
1533
|
"remark": "^15.0.1",
|
|
1539
1534
|
"remark-gfm": "^4.0.1",
|
|
1540
1535
|
"shiki": "4.3.0",
|
|
@@ -1586,11 +1581,14 @@ function routeToOpenAPIArtifactUrl(routePath) {
|
|
|
1586
1581
|
return `${routePath === "/" ? "/index" : routePath.replace(/\/$/, "")}.openapi.json`;
|
|
1587
1582
|
}
|
|
1588
1583
|
function attachContentArtifactUrls(routes) {
|
|
1589
|
-
for (const route of routes) route.
|
|
1584
|
+
for (const route of routes) route.artifacts = {
|
|
1585
|
+
...route.artifacts,
|
|
1586
|
+
contentArtifactUrl: route.kind === "openapi" ? routeToOpenAPIArtifactUrl(route.path) : routeToMarkdownArtifactUrl(route.path)
|
|
1587
|
+
};
|
|
1590
1588
|
}
|
|
1591
1589
|
function readRouteContent(route) {
|
|
1592
|
-
if (route.content !== void 0) return route.content;
|
|
1593
|
-
throw new Error(`Route content is missing from route context: ${route.filePath}`);
|
|
1590
|
+
if (route.source.content !== void 0) return route.source.content;
|
|
1591
|
+
throw new Error(`Route content is missing from route context: ${route.source.filePath}`);
|
|
1594
1592
|
}
|
|
1595
1593
|
function readRouteArtifactContent(route) {
|
|
1596
1594
|
const content = readRouteContent(route);
|
|
@@ -1600,16 +1598,17 @@ function isLlmsTxtRoute(route) {
|
|
|
1600
1598
|
return !route.path.split("/").includes("404");
|
|
1601
1599
|
}
|
|
1602
1600
|
function llmsTxtDescription(route) {
|
|
1603
|
-
if (route.description) return route.description;
|
|
1604
|
-
const sections = route.sections?.filter((section) => section.level === 2).slice(0, 3).map((section) => section.title);
|
|
1601
|
+
if (route.meta.description) return route.meta.description;
|
|
1602
|
+
const sections = route.meta.sections?.filter((section) => section.level === 2).slice(0, 3).map((section) => section.title);
|
|
1605
1603
|
if (sections?.length) return `Covers ${sections.join(", ")}.`;
|
|
1606
|
-
if (route.keywords?.length) return `Related topics: ${route.keywords.join(", ")}.`;
|
|
1604
|
+
if (route.meta.keywords?.length) return `Related topics: ${route.meta.keywords.join(", ")}.`;
|
|
1607
1605
|
if (route.kind === "openapi") return "OpenAPI artifact for machine-readable API reference data.";
|
|
1608
1606
|
}
|
|
1609
1607
|
function llmsTxtListItem(route, basePath) {
|
|
1610
|
-
|
|
1608
|
+
const contentArtifactUrl = route.artifacts?.contentArtifactUrl;
|
|
1609
|
+
if (!contentArtifactUrl) return void 0;
|
|
1611
1610
|
const description = llmsTxtDescription(route);
|
|
1612
|
-
return description ? `- [${route.title}](${basePath}${
|
|
1611
|
+
return description ? `- [${route.meta.title}](${basePath}${contentArtifactUrl}): ${description}` : `- [${route.meta.title}](${basePath}${contentArtifactUrl})`;
|
|
1613
1612
|
}
|
|
1614
1613
|
function llmsTxtLocaleLabel(locale, projectConfig) {
|
|
1615
1614
|
return projectConfig.i18n?.locales.find((item) => item.code === locale)?.label ?? locale;
|
|
@@ -1626,7 +1625,7 @@ function groupLlmsTxtRoutesByLocale(routes, projectConfig) {
|
|
|
1626
1625
|
const routesBySource = /* @__PURE__ */ new Map();
|
|
1627
1626
|
const defaultLocale = projectConfig.i18n?.defaultLocale;
|
|
1628
1627
|
for (const route of routes) {
|
|
1629
|
-
const sourceKey = `${route.locale ?? defaultLocale ?? "default"}:${route.basePath ?? route.contentArtifactUrl ?? route.path}`;
|
|
1628
|
+
const sourceKey = `${route.locale ?? defaultLocale ?? "default"}:${route.basePath ?? route.artifacts?.contentArtifactUrl ?? route.path}`;
|
|
1630
1629
|
const previousRoute = routesBySource.get(sourceKey);
|
|
1631
1630
|
if (!previousRoute || previousRoute.locale && !route.locale) routesBySource.set(sourceKey, route);
|
|
1632
1631
|
}
|
|
@@ -1695,9 +1694,9 @@ function serveContentArtifacts(req, res, projectConfig, routes) {
|
|
|
1695
1694
|
}
|
|
1696
1695
|
if (contentPath.endsWith(".openapi.yaml")) {
|
|
1697
1696
|
const jsonPath = contentPath.replace(/\.yaml$/, ".json");
|
|
1698
|
-
const route = routes.find((
|
|
1699
|
-
if (route?.kind === "openapi" && route.content) {
|
|
1700
|
-
const spec = JSON.parse(route.content);
|
|
1697
|
+
const route = routes.find((route) => route.artifacts?.contentArtifactUrl === jsonPath);
|
|
1698
|
+
if (route?.kind === "openapi" && route.source.content) {
|
|
1699
|
+
const spec = JSON.parse(route.source.content);
|
|
1701
1700
|
res.statusCode = 200;
|
|
1702
1701
|
res.setHeader("Content-Type", "text/yaml; charset=utf-8");
|
|
1703
1702
|
res.end((0, yaml.stringify)(spec, { lineWidth: 0 }), "utf8");
|
|
@@ -1705,7 +1704,7 @@ function serveContentArtifacts(req, res, projectConfig, routes) {
|
|
|
1705
1704
|
}
|
|
1706
1705
|
return false;
|
|
1707
1706
|
}
|
|
1708
|
-
const route = routes.find((route) => route.contentArtifactUrl === contentPath);
|
|
1707
|
+
const route = routes.find((route) => route.artifacts?.contentArtifactUrl === contentPath);
|
|
1709
1708
|
if (!route) return false;
|
|
1710
1709
|
res.statusCode = 200;
|
|
1711
1710
|
res.setHeader("Content-Type", resolveContentArtifactType(route));
|
|
@@ -1731,14 +1730,15 @@ function createContentArtifactsPlugin() {
|
|
|
1731
1730
|
"build:assets": (ctx) => {
|
|
1732
1731
|
const assets = [];
|
|
1733
1732
|
for (const route of ctx.routes) {
|
|
1734
|
-
|
|
1733
|
+
const contentArtifactUrl = route.artifacts?.contentArtifactUrl;
|
|
1734
|
+
if (!contentArtifactUrl) continue;
|
|
1735
1735
|
assets.push({
|
|
1736
|
-
fileName:
|
|
1736
|
+
fileName: contentArtifactUrl.replace(/^\//, ""),
|
|
1737
1737
|
source: readRouteArtifactContent(route)
|
|
1738
1738
|
});
|
|
1739
|
-
if (route.kind === "openapi" && route.content) {
|
|
1740
|
-
const yamlFileName =
|
|
1741
|
-
const spec = JSON.parse(route.content);
|
|
1739
|
+
if (route.kind === "openapi" && route.source.content) {
|
|
1740
|
+
const yamlFileName = contentArtifactUrl.replace(/\.json$/, ".yaml");
|
|
1741
|
+
const spec = JSON.parse(route.source.content);
|
|
1742
1742
|
assets.push({
|
|
1743
1743
|
fileName: yamlFileName.replace(/^\//, ""),
|
|
1744
1744
|
source: (0, yaml.stringify)(spec, { lineWidth: 0 })
|
|
@@ -1824,6 +1824,7 @@ var OPENAPI_HTTP_METHODS = [
|
|
|
1824
1824
|
"patch",
|
|
1825
1825
|
"trace"
|
|
1826
1826
|
];
|
|
1827
|
+
var CLARIFY_OPENAPI_SECTION_ID_EXTENSION = "x-clarify-section-id";
|
|
1827
1828
|
function errorMessage(error) {
|
|
1828
1829
|
return error instanceof Error ? error.message : String(error);
|
|
1829
1830
|
}
|
|
@@ -1850,10 +1851,10 @@ function findOpenAPIRoutes(dir, base = dir) {
|
|
|
1850
1851
|
routes.push({
|
|
1851
1852
|
path: cleanPath,
|
|
1852
1853
|
basePath: cleanPath,
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1854
|
+
kind: "openapi",
|
|
1855
|
+
meta: { title: kebabToTitle(cleanPath.split("/").pop() ?? "API") },
|
|
1856
|
+
module: { virtualModuleId: virtualModuleIdFromRef(ref) },
|
|
1857
|
+
source: { filePath: fullPath }
|
|
1857
1858
|
});
|
|
1858
1859
|
}
|
|
1859
1860
|
return routes;
|
|
@@ -1862,36 +1863,80 @@ function operationMatchesTags(operationTags, filterTags) {
|
|
|
1862
1863
|
if (!filterTags?.length) return true;
|
|
1863
1864
|
return operationTags?.some((tag) => filterTags.includes(tag)) ?? false;
|
|
1864
1865
|
}
|
|
1866
|
+
function filterPathItemsByTags(items, tags) {
|
|
1867
|
+
const filteredItems = {};
|
|
1868
|
+
for (const path of Object.keys(items)) {
|
|
1869
|
+
const pathItem = items[path];
|
|
1870
|
+
if (!pathItem) continue;
|
|
1871
|
+
if (OPENAPI_HTTP_METHODS.map((method) => pathItem[method]).some((op) => op && typeof op === "object" && operationMatchesTags(op.tags, tags))) filteredItems[path] = pathItem;
|
|
1872
|
+
}
|
|
1873
|
+
return filteredItems;
|
|
1874
|
+
}
|
|
1875
|
+
function createOperationSectionId(operation, method, path, kind) {
|
|
1876
|
+
return (typeof operation.operationId === "string" ? operation.operationId.trim() : "") || (0, github_slugger.slug)(`${kind === "webhook" ? "webhook " : ""}${method.toLowerCase()} ${path}`);
|
|
1877
|
+
}
|
|
1878
|
+
function operationSectionId(operation) {
|
|
1879
|
+
const sectionId = operation[CLARIFY_OPENAPI_SECTION_ID_EXTENSION];
|
|
1880
|
+
return typeof sectionId === "string" ? sectionId : "";
|
|
1881
|
+
}
|
|
1882
|
+
function normalizeOpenAPISpecSectionIds(spec) {
|
|
1883
|
+
const items = [...Object.entries(spec.paths ?? {}).map(([path, pathItem]) => ({
|
|
1884
|
+
path,
|
|
1885
|
+
pathItem,
|
|
1886
|
+
kind: "path"
|
|
1887
|
+
})), ...Object.entries(spec.webhooks ?? {}).map(([path, pathItem]) => ({
|
|
1888
|
+
path,
|
|
1889
|
+
pathItem,
|
|
1890
|
+
kind: "webhook"
|
|
1891
|
+
}))];
|
|
1892
|
+
for (const { path, pathItem, kind } of items) {
|
|
1893
|
+
if (!pathItem || typeof pathItem !== "object") continue;
|
|
1894
|
+
const operations = pathItem;
|
|
1895
|
+
for (const method of OPENAPI_HTTP_METHODS) {
|
|
1896
|
+
const op = operations[method];
|
|
1897
|
+
if (!op || typeof op !== "object") continue;
|
|
1898
|
+
op[CLARIFY_OPENAPI_SECTION_ID_EXTENSION] = createOperationSectionId(op, method, path, kind);
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
return spec;
|
|
1902
|
+
}
|
|
1865
1903
|
/** Filter an OpenAPI spec to only include paths that have at least one operation matching the given tags. */
|
|
1866
1904
|
function filterSpecByTags(spec, tags) {
|
|
1867
|
-
const filteredPaths = {};
|
|
1868
1905
|
const paths = spec.paths ?? {};
|
|
1869
|
-
|
|
1870
|
-
const pathItem = paths[path];
|
|
1871
|
-
if (!pathItem) continue;
|
|
1872
|
-
if (Object.values(pathItem).some((op) => op && typeof op === "object" && operationMatchesTags(op.tags, tags))) filteredPaths[path] = pathItem;
|
|
1873
|
-
}
|
|
1906
|
+
const webhooks = spec.webhooks ?? {};
|
|
1874
1907
|
return {
|
|
1875
1908
|
...spec,
|
|
1876
|
-
paths:
|
|
1909
|
+
paths: filterPathItemsByTags(paths, tags),
|
|
1910
|
+
webhooks: filterPathItemsByTags(webhooks, tags)
|
|
1877
1911
|
};
|
|
1878
1912
|
}
|
|
1879
1913
|
/** Extract endpoint operations from an OpenAPI spec as page sections. */
|
|
1880
1914
|
function extractOpenAPISections(spec, filterTags) {
|
|
1915
|
+
normalizeOpenAPISpecSectionIds(spec);
|
|
1881
1916
|
const sections = [];
|
|
1882
|
-
const
|
|
1883
|
-
|
|
1917
|
+
const items = [...Object.entries(spec.paths ?? {}).map(([path, pathItem]) => ({
|
|
1918
|
+
path,
|
|
1919
|
+
pathItem,
|
|
1920
|
+
kind: "path"
|
|
1921
|
+
})), ...Object.entries(spec.webhooks ?? {}).map(([path, pathItem]) => ({
|
|
1922
|
+
path,
|
|
1923
|
+
pathItem,
|
|
1924
|
+
kind: "webhook"
|
|
1925
|
+
}))];
|
|
1926
|
+
for (const { path, pathItem, kind } of items) {
|
|
1884
1927
|
if (!pathItem) continue;
|
|
1928
|
+
const operations = pathItem;
|
|
1885
1929
|
for (const method of OPENAPI_HTTP_METHODS) {
|
|
1886
|
-
const op =
|
|
1887
|
-
|
|
1888
|
-
|
|
1930
|
+
const op = operations[method];
|
|
1931
|
+
const tags = Array.isArray(op?.tags) ? op.tags : void 0;
|
|
1932
|
+
if (!op || !operationMatchesTags(tags, filterTags)) continue;
|
|
1933
|
+
const title = typeof op.summary === "string" ? op.summary : `${method.toUpperCase()} ${path}`;
|
|
1889
1934
|
sections.push({
|
|
1890
|
-
id: (
|
|
1935
|
+
id: operationSectionId(op),
|
|
1891
1936
|
title,
|
|
1892
1937
|
level: 2,
|
|
1893
|
-
badge: method.toUpperCase(),
|
|
1894
|
-
tags
|
|
1938
|
+
badge: kind === "webhook" ? "WEBHOOK" : method.toUpperCase(),
|
|
1939
|
+
tags
|
|
1895
1940
|
});
|
|
1896
1941
|
}
|
|
1897
1942
|
}
|
|
@@ -1933,12 +1978,16 @@ async function readOpenAPISpec(filePath, contentProcessor) {
|
|
|
1933
1978
|
//#endregion
|
|
1934
1979
|
//#region source/plugins/openapi/virtual-modules.ts
|
|
1935
1980
|
var openApiRegistryModuleId = VIRTUAL_OPENAPI;
|
|
1981
|
+
var openApiServerRegistryModuleId = VIRTUAL_OPENAPI_SERVER;
|
|
1936
1982
|
var OPENAPI_SPEC_PREFIX = "virtual:clarify/openapi-spec/";
|
|
1937
1983
|
function specVirtualModuleId(specKey) {
|
|
1938
1984
|
return `${OPENAPI_SPEC_PREFIX}${specKey}`;
|
|
1939
1985
|
}
|
|
1940
|
-
function generateOpenAPIRegistryModule(
|
|
1941
|
-
return `export const
|
|
1986
|
+
function generateOpenAPIRegistryModule(openApiSpecs) {
|
|
1987
|
+
return `export const openApiSpecs = {\n${Object.entries(openApiSpecs).map(([key, moduleId]) => ` ${JSON.stringify(key)}: () => import(${JSON.stringify(moduleId)}),`).join("\n")}\n};`;
|
|
1988
|
+
}
|
|
1989
|
+
function generateOpenAPIServerRegistryModule(openApiSpecs) {
|
|
1990
|
+
return `export const openApiSpecs = ${JSON.stringify(openApiSpecs)};`;
|
|
1942
1991
|
}
|
|
1943
1992
|
/** Generate a virtual module that exports a single spec as default. */
|
|
1944
1993
|
function generateOpenAPISpecModule(spec) {
|
|
@@ -1946,13 +1995,11 @@ function generateOpenAPISpecModule(spec) {
|
|
|
1946
1995
|
}
|
|
1947
1996
|
function generateOpenAPIPageModule(opts) {
|
|
1948
1997
|
return `import { createOpenApiRouteComponent } from '@clarify-labs/renderer';
|
|
1998
|
+
import spec from ${JSON.stringify(opts.specModuleId)};
|
|
1949
1999
|
|
|
1950
|
-
export const routeData =
|
|
1951
|
-
spec: opts.spec,
|
|
1952
|
-
tagFilter: opts.tagFilter
|
|
1953
|
-
})};
|
|
2000
|
+
export const routeData = {};
|
|
1954
2001
|
|
|
1955
|
-
export default createOpenApiRouteComponent(routeData);
|
|
2002
|
+
export default createOpenApiRouteComponent({ ...routeData, spec });
|
|
1956
2003
|
`;
|
|
1957
2004
|
}
|
|
1958
2005
|
function generateOpenAPIErrorModule(diagnostic) {
|
|
@@ -1971,115 +2018,212 @@ export default createContentDiagnosticComponent(contentDiagnostic);
|
|
|
1971
2018
|
}
|
|
1972
2019
|
//#endregion
|
|
1973
2020
|
//#region source/plugins/openapi/index.ts
|
|
1974
|
-
function
|
|
1975
|
-
const
|
|
2021
|
+
function collectOpenAPIPageIntents(config) {
|
|
2022
|
+
const intents = [];
|
|
1976
2023
|
function visitPages(pages) {
|
|
1977
2024
|
if (!pages || pages === "FileTree") return;
|
|
1978
|
-
for (const group of pages) for (const item of group.pages)
|
|
2025
|
+
for (const group of pages) for (const item of group.pages) {
|
|
2026
|
+
const intent = routeIntentFromPagesItem(item);
|
|
2027
|
+
if (intent.kind === "openapi" && (intent.path || intent.tagFilter?.length)) intents.push(intent);
|
|
2028
|
+
}
|
|
1979
2029
|
}
|
|
1980
2030
|
for (const tab of config.tabs ?? []) visitPages(tab.pages);
|
|
1981
|
-
return
|
|
2031
|
+
return intents;
|
|
1982
2032
|
}
|
|
1983
2033
|
function virtualModuleIdFromPath(path) {
|
|
1984
2034
|
return `virtual:clarify-page/${path.replace(/^\/+/, "") || "index"}`;
|
|
1985
2035
|
}
|
|
2036
|
+
function cloneOpenAPIRoute(route, overrides = {}) {
|
|
2037
|
+
return {
|
|
2038
|
+
...route,
|
|
2039
|
+
meta: {
|
|
2040
|
+
...route.meta,
|
|
2041
|
+
sections: route.meta.sections ? [...route.meta.sections] : void 0
|
|
2042
|
+
},
|
|
2043
|
+
module: { ...route.module },
|
|
2044
|
+
source: { ...route.source },
|
|
2045
|
+
openapi: route.openapi ? {
|
|
2046
|
+
...route.openapi,
|
|
2047
|
+
tagFilter: route.openapi.tagFilter ? [...route.openapi.tagFilter] : void 0
|
|
2048
|
+
} : void 0,
|
|
2049
|
+
alternates: route.alternates ? { ...route.alternates } : void 0,
|
|
2050
|
+
...overrides
|
|
2051
|
+
};
|
|
2052
|
+
}
|
|
2053
|
+
function findOpenAPIRoutesForContentRoot(contentRoot, i18n) {
|
|
2054
|
+
if (!i18n) return findOpenAPIRoutes(contentRoot);
|
|
2055
|
+
const localizedRoutes = [];
|
|
2056
|
+
for (const locale of i18n.locales) {
|
|
2057
|
+
const localeRoot = (0, node_path.join)(contentRoot, locale.code);
|
|
2058
|
+
for (const route of findOpenAPIRoutes(localeRoot, localeRoot)) {
|
|
2059
|
+
const basePath = route.basePath ?? route.path;
|
|
2060
|
+
const path = localizedRoutePath(basePath, locale.code, i18n);
|
|
2061
|
+
localizedRoutes.push({
|
|
2062
|
+
...route,
|
|
2063
|
+
path,
|
|
2064
|
+
basePath,
|
|
2065
|
+
locale: locale.code,
|
|
2066
|
+
module: { virtualModuleId: virtualModuleIdFromPath(path) }
|
|
2067
|
+
});
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
if (i18n.missing === "fallback") {
|
|
2071
|
+
const routeByLocaleAndBase = new Map(localizedRoutes.map((route) => [`${route.locale ?? ""}:${route.basePath ?? route.path}`, route]));
|
|
2072
|
+
const defaultRoutes = localizedRoutes.filter((route) => route.locale === i18n.defaultLocale);
|
|
2073
|
+
for (const sourceRoute of defaultRoutes) {
|
|
2074
|
+
const basePath = sourceRoute.basePath ?? sourceRoute.path;
|
|
2075
|
+
for (const locale of i18n.locales) {
|
|
2076
|
+
const key = `${locale.code}:${basePath}`;
|
|
2077
|
+
if (routeByLocaleAndBase.has(key)) continue;
|
|
2078
|
+
const path = localizedRoutePath(basePath, locale.code, i18n);
|
|
2079
|
+
localizedRoutes.push(cloneOpenAPIRoute(sourceRoute, {
|
|
2080
|
+
path,
|
|
2081
|
+
locale: locale.code,
|
|
2082
|
+
module: { virtualModuleId: virtualModuleIdFromPath(path) },
|
|
2083
|
+
isFallback: true
|
|
2084
|
+
}));
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
return localizedRoutes;
|
|
2089
|
+
}
|
|
1986
2090
|
function createConfiguredOpenAPIRoutes(routes, config) {
|
|
1987
|
-
const
|
|
1988
|
-
if (!
|
|
2091
|
+
const openAPIIntents = collectOpenAPIPageIntents(config);
|
|
2092
|
+
if (!openAPIIntents.length) return routes;
|
|
1989
2093
|
const additions = [];
|
|
1990
2094
|
const existingKeys = new Set(routes.map((route) => `${route.locale ?? ""}:${route.basePath ?? route.path}`));
|
|
1991
|
-
for (const
|
|
1992
|
-
const tagFilter =
|
|
1993
|
-
const sourceBasePath = openAPIPagePathFromRef(
|
|
1994
|
-
const targetBasePath = openAPIPagePathFromRef(
|
|
2095
|
+
for (const intent of openAPIIntents) {
|
|
2096
|
+
const tagFilter = intent.tagFilter?.filter(Boolean);
|
|
2097
|
+
const sourceBasePath = openAPIPagePathFromRef(intent.ref);
|
|
2098
|
+
const targetBasePath = openAPIPagePathFromRef(intent.ref, tagFilter, intent.path);
|
|
1995
2099
|
if (sourceBasePath === targetBasePath && !tagFilter?.length) continue;
|
|
1996
2100
|
for (const route of routes) {
|
|
1997
2101
|
if (route.kind !== "openapi" || (route.basePath ?? route.path) !== sourceBasePath) continue;
|
|
1998
2102
|
const key = `${route.locale ?? ""}:${targetBasePath}`;
|
|
1999
2103
|
if (existingKeys.has(key)) continue;
|
|
2000
2104
|
existingKeys.add(key);
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
path
|
|
2105
|
+
const path = route.locale && config.i18n ? localizedRoutePath(targetBasePath, route.locale, config.i18n) : targetBasePath;
|
|
2106
|
+
additions.push(cloneOpenAPIRoute(route, {
|
|
2107
|
+
path,
|
|
2004
2108
|
basePath: targetBasePath,
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2109
|
+
module: { virtualModuleId: virtualModuleIdFromPath(path) },
|
|
2110
|
+
openapi: {
|
|
2111
|
+
...route.openapi,
|
|
2112
|
+
tagFilter: tagFilter?.length ? tagFilter : void 0
|
|
2113
|
+
}
|
|
2114
|
+
}));
|
|
2009
2115
|
}
|
|
2010
2116
|
}
|
|
2011
2117
|
const nextRoutes = [...routes, ...additions];
|
|
2012
|
-
|
|
2118
|
+
if (!config.i18n) return nextRoutes;
|
|
2119
|
+
const routesWithAlternates = nextRoutes.map((route) => withAlternates(route, nextRoutes, config.i18n));
|
|
2120
|
+
const bareAliases = [];
|
|
2121
|
+
const seenBare = new Set(routesWithAlternates.map((route) => route.path));
|
|
2122
|
+
for (const route of routesWithAlternates) {
|
|
2123
|
+
if (route.locale !== config.i18n.defaultLocale) continue;
|
|
2124
|
+
const basePath = route.basePath ?? route.path;
|
|
2125
|
+
if (basePath === route.path || seenBare.has(basePath)) continue;
|
|
2126
|
+
seenBare.add(basePath);
|
|
2127
|
+
bareAliases.push(cloneOpenAPIRoute(route, {
|
|
2128
|
+
path: basePath,
|
|
2129
|
+
module: { virtualModuleId: virtualModuleIdFromPath(basePath) },
|
|
2130
|
+
isBareAlias: true
|
|
2131
|
+
}));
|
|
2132
|
+
}
|
|
2133
|
+
return [...routesWithAlternates, ...bareAliases];
|
|
2013
2134
|
}
|
|
2014
|
-
/** Derive a stable, deduplicated
|
|
2015
|
-
function
|
|
2135
|
+
/** Derive a stable, deduplicated id from an absolute spec file path. */
|
|
2136
|
+
function sourceSpecIdFromPath(filePath, projectRoot) {
|
|
2016
2137
|
return (0, node_path.relative)(projectRoot, filePath).replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
2017
2138
|
}
|
|
2139
|
+
function routeSpecModuleIdFromSourceSpecId(sourceSpecId, tagFilter) {
|
|
2140
|
+
if (!tagFilter?.length) return sourceSpecId;
|
|
2141
|
+
return `${sourceSpecId}_tags_${tagFilter.map((tag) => tag.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "") || "tag").join("_")}`;
|
|
2142
|
+
}
|
|
2143
|
+
function openAPIRegistryKeys(route) {
|
|
2144
|
+
const keys = /* @__PURE__ */ new Set();
|
|
2145
|
+
const path = (route.path || "/").replace(/^\//, "");
|
|
2146
|
+
const base = (route.basePath ?? route.path).replace(/^\//, "");
|
|
2147
|
+
if (route.locale) keys.add(`virtual:clarify-page/${route.locale}/${base}`);
|
|
2148
|
+
if (path) keys.add(`virtual:clarify-page/${path}`);
|
|
2149
|
+
else keys.add("virtual:clarify-page/index");
|
|
2150
|
+
if (!route.locale && base) keys.add(`virtual:clarify-page/${base}`);
|
|
2151
|
+
return [...keys];
|
|
2152
|
+
}
|
|
2018
2153
|
function createOpenAPIPlugin() {
|
|
2019
|
-
/** specs keyed by
|
|
2154
|
+
/** specs keyed by sourceSpecId (deduplicated per source file). */
|
|
2020
2155
|
const specs = /* @__PURE__ */ new Map();
|
|
2156
|
+
const specModules = /* @__PURE__ */ new Map();
|
|
2021
2157
|
return {
|
|
2022
2158
|
name: "clarify:openapi",
|
|
2023
2159
|
hooks: {
|
|
2024
|
-
"routes:discover": (input) => ({
|
|
2160
|
+
"routes:discover": (input, ctx) => ({
|
|
2025
2161
|
...input,
|
|
2026
|
-
routes: [...input.routes, ...
|
|
2162
|
+
routes: [...input.routes, ...findOpenAPIRoutesForContentRoot(input.contentRoot, ctx.projectConfig.i18n)]
|
|
2027
2163
|
}),
|
|
2028
2164
|
"routes:discovered": async (routes, ctx) => {
|
|
2029
2165
|
specs.clear();
|
|
2166
|
+
specModules.clear();
|
|
2030
2167
|
const nextRoutes = createConfiguredOpenAPIRoutes(routes, ctx.projectConfig);
|
|
2031
2168
|
const specByFilePath = /* @__PURE__ */ new Map();
|
|
2032
2169
|
for (const route of nextRoutes.filter((route) => route.kind === "openapi")) {
|
|
2033
|
-
const specFromCache = specByFilePath.get(route.filePath);
|
|
2170
|
+
const specFromCache = specByFilePath.get(route.source.filePath);
|
|
2034
2171
|
const processor = createProjectContentProcessor(ctx.plugins, ctx);
|
|
2035
2172
|
const result = specFromCache ? {
|
|
2036
2173
|
ok: true,
|
|
2037
2174
|
spec: specFromCache
|
|
2038
|
-
} : await readOpenAPISpec(route.filePath, processor);
|
|
2175
|
+
} : await readOpenAPISpec(route.source.filePath, processor);
|
|
2039
2176
|
if (!result.ok) {
|
|
2040
2177
|
route.diagnostic = result.diagnostic;
|
|
2041
|
-
route.title = route.title || "OpenAPI parse error";
|
|
2042
|
-
route.sections = [];
|
|
2178
|
+
route.meta.title = route.meta.title || "OpenAPI parse error";
|
|
2179
|
+
route.meta.sections = [];
|
|
2043
2180
|
continue;
|
|
2044
2181
|
}
|
|
2045
|
-
const spec = result.spec;
|
|
2046
|
-
specByFilePath.set(route.filePath, spec);
|
|
2047
|
-
const
|
|
2048
|
-
route.
|
|
2049
|
-
|
|
2182
|
+
const spec = normalizeOpenAPISpecSectionIds(result.spec);
|
|
2183
|
+
specByFilePath.set(route.source.filePath, spec);
|
|
2184
|
+
const sourceSpecId = sourceSpecIdFromPath(route.source.filePath, ctx.generateOptions.projectRoot);
|
|
2185
|
+
route.openapi = {
|
|
2186
|
+
...route.openapi,
|
|
2187
|
+
sourceSpecId
|
|
2188
|
+
};
|
|
2189
|
+
specs.set(sourceSpecId, {
|
|
2050
2190
|
spec,
|
|
2051
|
-
filePath: route.filePath
|
|
2191
|
+
filePath: route.source.filePath
|
|
2052
2192
|
});
|
|
2053
|
-
route.title = spec.info?.title ?? route.title;
|
|
2054
|
-
route.description = spec.info?.description ?? route.description;
|
|
2055
|
-
route.sections = extractOpenAPISections(spec, route.
|
|
2056
|
-
const pageSpec = route.
|
|
2057
|
-
|
|
2193
|
+
route.meta.title = spec.info?.title ?? route.meta.title;
|
|
2194
|
+
route.meta.description = spec.info?.description ?? route.meta.description;
|
|
2195
|
+
route.meta.sections = extractOpenAPISections(spec, route.openapi?.tagFilter);
|
|
2196
|
+
const pageSpec = route.openapi?.tagFilter?.length ? filterSpecByTags(spec, route.openapi.tagFilter) : spec;
|
|
2197
|
+
const routeSpecModuleId = routeSpecModuleIdFromSourceSpecId(sourceSpecId, route.openapi?.tagFilter);
|
|
2198
|
+
route.openapi.routeSpecModuleId = routeSpecModuleId;
|
|
2199
|
+
specModules.set(routeSpecModuleId, pageSpec);
|
|
2200
|
+
route.source.content = JSON.stringify(pageSpec);
|
|
2058
2201
|
}
|
|
2059
2202
|
return nextRoutes;
|
|
2060
2203
|
},
|
|
2061
2204
|
"modules:before": (modules, ctx) => {
|
|
2062
2205
|
const registryEntries = {};
|
|
2206
|
+
const serverRegistryEntries = {};
|
|
2063
2207
|
for (const route of ctx.routes) {
|
|
2064
|
-
if (route.kind !== "openapi" || !route.
|
|
2065
|
-
const
|
|
2208
|
+
if (route.kind !== "openapi" || !route.openapi?.sourceSpecId) continue;
|
|
2209
|
+
const routeSpecModuleId = route.openapi.routeSpecModuleId ?? route.openapi.sourceSpecId;
|
|
2210
|
+
const spec = specModules.get(routeSpecModuleId) ?? specs.get(route.openapi.sourceSpecId)?.spec;
|
|
2066
2211
|
if (!spec) continue;
|
|
2067
|
-
const
|
|
2068
|
-
|
|
2069
|
-
|
|
2212
|
+
for (const registryKey of openAPIRegistryKeys(route)) {
|
|
2213
|
+
registryEntries[registryKey] = specVirtualModuleId(routeSpecModuleId);
|
|
2214
|
+
serverRegistryEntries[registryKey] = spec;
|
|
2215
|
+
}
|
|
2070
2216
|
}
|
|
2071
2217
|
modules.set(openApiRegistryModuleId, generateOpenAPIRegistryModule(registryEntries));
|
|
2072
|
-
|
|
2218
|
+
modules.set(openApiServerRegistryModuleId, generateOpenAPIServerRegistryModule(serverRegistryEntries));
|
|
2219
|
+
for (const [routeSpecModuleId, spec] of specModules) modules.set(specVirtualModuleId(routeSpecModuleId), generateOpenAPISpecModule(spec));
|
|
2073
2220
|
for (const route of ctx.routes) {
|
|
2074
2221
|
if (route.kind !== "openapi") continue;
|
|
2075
|
-
if (route.diagnostic) modules.set(route.virtualModuleId, generateOpenAPIErrorModule(route.diagnostic));
|
|
2076
|
-
else if (route.
|
|
2077
|
-
const
|
|
2078
|
-
if (!
|
|
2079
|
-
modules.set(route.virtualModuleId, generateOpenAPIPageModule({
|
|
2080
|
-
spec: entry.spec,
|
|
2081
|
-
tagFilter: route.openapiTagFilter
|
|
2082
|
-
}));
|
|
2222
|
+
if (route.diagnostic) modules.set(route.module.virtualModuleId, generateOpenAPIErrorModule(route.diagnostic));
|
|
2223
|
+
else if (route.openapi?.sourceSpecId) {
|
|
2224
|
+
const routeSpecModuleId = route.openapi.routeSpecModuleId ?? route.openapi.sourceSpecId;
|
|
2225
|
+
if (!specModules.has(routeSpecModuleId)) continue;
|
|
2226
|
+
modules.set(route.module.virtualModuleId, generateOpenAPIPageModule({ specModuleId: specVirtualModuleId(routeSpecModuleId) }));
|
|
2083
2227
|
}
|
|
2084
2228
|
}
|
|
2085
2229
|
return modules;
|
|
@@ -2147,11 +2291,11 @@ async function generatePagefindIndex(options, pagefind) {
|
|
|
2147
2291
|
}
|
|
2148
2292
|
function routeSearchContent(route) {
|
|
2149
2293
|
return [
|
|
2150
|
-
route.title,
|
|
2151
|
-
route.description,
|
|
2152
|
-
route.keywords?.join(" "),
|
|
2153
|
-
route.sections?.map((section) => section.title).join(" "),
|
|
2154
|
-
route.content
|
|
2294
|
+
route.meta.title,
|
|
2295
|
+
route.meta.description,
|
|
2296
|
+
route.meta.keywords?.join(" "),
|
|
2297
|
+
route.meta.sections?.map((section) => section.title).join(" "),
|
|
2298
|
+
route.source.content
|
|
2155
2299
|
].filter(Boolean).join("\n\n");
|
|
2156
2300
|
}
|
|
2157
2301
|
async function generateDevSearchIndex(ctx, root, pagefind) {
|
|
@@ -2173,7 +2317,7 @@ async function generateDevSearchIndex(ctx, root, pagefind) {
|
|
|
2173
2317
|
url: route.path,
|
|
2174
2318
|
content,
|
|
2175
2319
|
language: toPagefindLanguage(route.locale ?? ctx.projectConfig.i18n?.defaultLocale),
|
|
2176
|
-
meta: { title: route.title }
|
|
2320
|
+
meta: { title: route.meta.title }
|
|
2177
2321
|
});
|
|
2178
2322
|
assertNoPagefindErrors(`addCustomRecord ${route.path}`, result.errors);
|
|
2179
2323
|
pageCount += 1;
|
|
@@ -2330,15 +2474,18 @@ function normalizeRepositoryUrl(repository) {
|
|
|
2330
2474
|
function encodePath(path) {
|
|
2331
2475
|
return path.split("/").filter(Boolean).map((segment) => encodeURIComponent(segment)).join("/");
|
|
2332
2476
|
}
|
|
2333
|
-
function
|
|
2477
|
+
function createSourceEditUrl(filePath, contentRoot, source) {
|
|
2334
2478
|
const repository = normalizeRepositoryUrl(source.repository);
|
|
2335
2479
|
const branch = source.branch ?? "main";
|
|
2336
2480
|
const sourcePath = [source.directory ? trimSlashes(source.directory) : "", (0, node_path.relative)(contentRoot, filePath).replaceAll("\\", "/")].filter(Boolean).join("/");
|
|
2337
2481
|
return `${repository}/edit/${encodeURIComponent(branch)}/${encodePath(sourcePath)}`;
|
|
2338
2482
|
}
|
|
2339
|
-
function
|
|
2483
|
+
function attachSourceEditUrls(routes, contentRoot, source) {
|
|
2340
2484
|
if (!source) return;
|
|
2341
|
-
for (const route of routes) route.
|
|
2485
|
+
for (const route of routes) route.source = {
|
|
2486
|
+
...route.source,
|
|
2487
|
+
sourceEditUrl: createSourceEditUrl(route.source.filePath, contentRoot, source)
|
|
2488
|
+
};
|
|
2342
2489
|
}
|
|
2343
2490
|
//#endregion
|
|
2344
2491
|
//#region source/plugins/source-links/index.ts
|
|
@@ -2346,7 +2493,7 @@ function createSourceLinksPlugin() {
|
|
|
2346
2493
|
return {
|
|
2347
2494
|
name: "clarify:source-links",
|
|
2348
2495
|
hooks: { "routes:discovered": (routes, ctx) => {
|
|
2349
|
-
|
|
2496
|
+
attachSourceEditUrls(routes, (0, node_path.join)(ctx.generateOptions.projectRoot, ctx.generateOptions.rootDirectory), ctx.projectConfig.source);
|
|
2350
2497
|
return routes;
|
|
2351
2498
|
} }
|
|
2352
2499
|
};
|
|
@@ -2503,9 +2650,9 @@ var CLARIFY_ENV_TEMPLATE = `// This file is generated by Clarify. Do not edit it
|
|
|
2503
2650
|
// plugin and slot code, so the TypeScript language service can resolve them.
|
|
2504
2651
|
|
|
2505
2652
|
declare module 'virtual:clarify/slot' {
|
|
2506
|
-
import type {
|
|
2653
|
+
import type { UISlotContext } from '@clarify-labs/cli'
|
|
2507
2654
|
|
|
2508
|
-
export function useSlot():
|
|
2655
|
+
export function useSlot(): UISlotContext
|
|
2509
2656
|
}
|
|
2510
2657
|
`;
|
|
2511
2658
|
function generateClarifyEnvDts(_plugins) {
|
|
@@ -2527,6 +2674,11 @@ function writeClarifyEnvDts(projectRoot, plugins) {
|
|
|
2527
2674
|
(0, node_fs.writeFileSync)(filePath, next, "utf-8");
|
|
2528
2675
|
}
|
|
2529
2676
|
//#endregion
|
|
2677
|
+
//#region source/parsers/markdown/utils.ts
|
|
2678
|
+
function escapeHtml(text) {
|
|
2679
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2680
|
+
}
|
|
2681
|
+
//#endregion
|
|
2530
2682
|
//#region source/core/runtime/html-template.ts
|
|
2531
2683
|
/**
|
|
2532
2684
|
* HTML template manipulation helpers used during SSG.
|
|
@@ -2543,7 +2695,7 @@ function resolveProjectConfigFromContext(contextOrConfig) {
|
|
|
2543
2695
|
}
|
|
2544
2696
|
function routeTitle(contextOrConfig, route) {
|
|
2545
2697
|
const projectConfig = resolveProjectConfigFromContext(contextOrConfig);
|
|
2546
|
-
const title = route?.title
|
|
2698
|
+
const title = route?.meta.title.trim();
|
|
2547
2699
|
if (!title || title === projectConfig.title) return projectConfig.title;
|
|
2548
2700
|
return `${title} - ${projectConfig.title}`;
|
|
2549
2701
|
}
|
|
@@ -2591,8 +2743,8 @@ function injectSSRIntoTemplate(template, appHtml, contextOrConfig, route) {
|
|
|
2591
2743
|
const projectConfig = resolveProjectConfigFromContext(contextOrConfig);
|
|
2592
2744
|
let html = injectHtmlLocaleAttributes(template, contextOrConfig, route);
|
|
2593
2745
|
html = html.replace(/<title>.*?<\/title>/, `<title>${escapeHtml(routeTitle(contextOrConfig, route))}</title>`);
|
|
2594
|
-
html = setNamedMeta(html, "description", route?.description ?? projectConfig.description);
|
|
2595
|
-
html = setNamedMeta(html, "keywords", route?.keywords?.join(", "));
|
|
2746
|
+
html = setNamedMeta(html, "description", route?.meta.description ?? projectConfig.description);
|
|
2747
|
+
html = setNamedMeta(html, "keywords", route?.meta.keywords?.join(", "));
|
|
2596
2748
|
html = injectCanonicalUrl(html, contextOrConfig, route);
|
|
2597
2749
|
const dataPagefindIgnore = route?.isBareAlias ? " data-pagefind-ignore" : "";
|
|
2598
2750
|
html = html.replace(/<div id="root">([\s\S]*?)<\/div>/, `<div id="root"${dataPagefindIgnore}>${appHtml}</div>`);
|
|
@@ -2701,7 +2853,7 @@ function routeOutputFiles(outputDirectory, route) {
|
|
|
2701
2853
|
var SSR_ENTRY_CODE = `import { renderToHTML } from '@clarify-labs/renderer/server';
|
|
2702
2854
|
import { routes, navigation } from 'virtual:clarify/routes/server';
|
|
2703
2855
|
import { config } from 'virtual:clarify/config';
|
|
2704
|
-
import {
|
|
2856
|
+
import { openApiSpecs } from 'virtual:clarify/openapi/server';
|
|
2705
2857
|
import { runtimeSlots } from 'virtual:clarify/slots';
|
|
2706
2858
|
|
|
2707
2859
|
export async function render(url) {
|
|
@@ -2709,10 +2861,10 @@ export async function render(url) {
|
|
|
2709
2861
|
// them synchronously (renderToString has no Suspense support).
|
|
2710
2862
|
const entries = Object.values(runtimeSlots).flat()
|
|
2711
2863
|
await Promise.all(entries.map(async (entry) => {
|
|
2712
|
-
const mod = await entry.
|
|
2864
|
+
const mod = await entry.loadComponent()
|
|
2713
2865
|
entry._resolved = mod.default
|
|
2714
2866
|
}))
|
|
2715
|
-
return renderToHTML({ config, routes, navigation,
|
|
2867
|
+
return renderToHTML({ config, routes, navigation, openApiSpecs, runtimeSlots, url, themeEditor: config.theme.editor });
|
|
2716
2868
|
}`;
|
|
2717
2869
|
function createTempEntryFile(content) {
|
|
2718
2870
|
const entryPath = (0, node_path.join)(createClarifyTempDir("ssr"), "entry-server.ts");
|
|
@@ -2799,7 +2951,10 @@ var ClarifyContext = class {
|
|
|
2799
2951
|
this.generateOptions = init.generateOptions;
|
|
2800
2952
|
this.version = init.version;
|
|
2801
2953
|
this.currentRoutes = init.routes ?? [];
|
|
2802
|
-
this.currentNavigation = init.navigation ??
|
|
2954
|
+
this.currentNavigation = init.navigation ?? {
|
|
2955
|
+
kind: "flat",
|
|
2956
|
+
nodes: []
|
|
2957
|
+
};
|
|
2803
2958
|
this.currentPlugins = init.plugins ?? [];
|
|
2804
2959
|
}
|
|
2805
2960
|
get routes() {
|
|
@@ -2921,7 +3076,10 @@ var ClarifyEngine = class {
|
|
|
2921
3076
|
generateOptions: placeholderOptions,
|
|
2922
3077
|
version: cliPackageVersion,
|
|
2923
3078
|
routes: [],
|
|
2924
|
-
navigation:
|
|
3079
|
+
navigation: {
|
|
3080
|
+
kind: "flat",
|
|
3081
|
+
nodes: []
|
|
3082
|
+
},
|
|
2925
3083
|
plugins: []
|
|
2926
3084
|
});
|
|
2927
3085
|
}
|
|
@@ -3024,9 +3182,9 @@ var ClarifyEngine = class {
|
|
|
3024
3182
|
routes = await runPhase(plugins, "content:process", this.ctx, async () => {
|
|
3025
3183
|
const pages = routes.map((route) => ({
|
|
3026
3184
|
path: route.path,
|
|
3027
|
-
filePath: route.filePath,
|
|
3028
|
-
frontmatter: route.frontmatter ?? {},
|
|
3029
|
-
content: route.content ?? ""
|
|
3185
|
+
filePath: route.source.filePath,
|
|
3186
|
+
frontmatter: route.source.frontmatter ?? {},
|
|
3187
|
+
content: route.source.content ?? ""
|
|
3030
3188
|
}));
|
|
3031
3189
|
const resolvedPages = await runHooks(plugins, "pages:resolved", pages, this.ctx);
|
|
3032
3190
|
const pageByPath = new Map(resolvedPages.map((p) => [p.path, p]));
|
|
@@ -3035,13 +3193,22 @@ var ClarifyEngine = class {
|
|
|
3035
3193
|
if (!page) return route;
|
|
3036
3194
|
return {
|
|
3037
3195
|
...route,
|
|
3038
|
-
|
|
3039
|
-
|
|
3196
|
+
source: {
|
|
3197
|
+
...route.source,
|
|
3198
|
+
frontmatter: page.frontmatter,
|
|
3199
|
+
content: page.content
|
|
3200
|
+
}
|
|
3040
3201
|
};
|
|
3041
3202
|
});
|
|
3042
3203
|
});
|
|
3043
3204
|
routes = applyConfiguredPageRoutePaths(routes, tabs, i18n);
|
|
3044
|
-
const navigation = tabs ? i18n ? buildLocalizedNavigationFromTabsConfig(routes, tabs, i18n) ?? {
|
|
3205
|
+
const navigation = tabs ? i18n ? buildLocalizedNavigationFromTabsConfig(routes, tabs, i18n) ?? {
|
|
3206
|
+
kind: "localized-tabbed",
|
|
3207
|
+
locales: {}
|
|
3208
|
+
} : buildNavigationFromTabsConfig(routes, tabs) : {
|
|
3209
|
+
kind: "flat",
|
|
3210
|
+
nodes: buildNavigation(routes)
|
|
3211
|
+
};
|
|
3045
3212
|
const resolved = await runHooks(plugins, "routes:resolved", {
|
|
3046
3213
|
routes,
|
|
3047
3214
|
navigation
|
|
@@ -3075,7 +3242,7 @@ var ClarifyEngine = class {
|
|
|
3075
3242
|
writeClarifyEnvDts(this.root, this.plugins);
|
|
3076
3243
|
}
|
|
3077
3244
|
hasContentRouteForFile(filePath) {
|
|
3078
|
-
return this.routes.some((route) => route.filePath === filePath);
|
|
3245
|
+
return this.routes.some((route) => route.source.filePath === filePath);
|
|
3079
3246
|
}
|
|
3080
3247
|
async collectBuildAssets() {
|
|
3081
3248
|
if (!this.buildEnabled) return [];
|
|
@@ -3215,4 +3382,4 @@ Object.defineProperty(exports, "defineConfig", {
|
|
|
3215
3382
|
}
|
|
3216
3383
|
});
|
|
3217
3384
|
|
|
3218
|
-
//# sourceMappingURL=engine-
|
|
3385
|
+
//# sourceMappingURL=engine-qafLfnXQ.cjs.map
|