@clarify-labs/cli 0.10.1 → 0.10.3
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 +18 -32
- package/output/cli.cjs.map +1 -1
- package/output/cli.js +18 -32
- package/output/cli.js.map +1 -1
- package/output/core/adapters.d.ts +5 -0
- package/output/core/config/config-schema.d.ts +6 -110
- package/output/core/engine/engine.d.ts +1 -0
- package/output/core/runtime/virtual-modules.d.ts +1 -1
- package/output/{engine-5bdNX2Oo.cjs → engine-BDdPszs2.cjs} +212 -177
- package/output/engine-BDdPszs2.cjs.map +1 -0
- package/output/{engine-Ca_2MCj9.js → engine-CyFtr8Pz.js} +210 -178
- package/output/engine-CyFtr8Pz.js.map +1 -0
- package/output/index.cjs +1 -1
- package/output/index.js +1 -1
- package/output/parsers/content/diagnostic.d.ts +12 -0
- package/output/parsers/markdown/mdx.d.ts +12 -4
- package/output/plugins/openapi/parser.d.ts +1 -1
- package/output/plugins/openapi/virtual-modules.d.ts +1 -2
- package/output/types.d.ts +4 -9
- package/package.json +6 -3
- package/output/engine-5bdNX2Oo.cjs.map +0 -1
- package/output/engine-Ca_2MCj9.js.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,29 @@ 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/
|
|
51
|
-
function
|
|
52
|
-
|
|
56
|
+
//#region source/parsers/content/diagnostic.ts
|
|
57
|
+
function displayPath(filePath, projectRoot) {
|
|
58
|
+
if (!filePath) return void 0;
|
|
59
|
+
if (!projectRoot) return filePath.replace(/^[A-Za-z]:\//, "").replace(/^\/+/, "");
|
|
60
|
+
const normalized = (0, node_path.relative)(projectRoot, filePath);
|
|
61
|
+
return normalized && !normalized.startsWith("..") && !(0, node_path.isAbsolute)(normalized) ? normalized : filePath.replace(/^[A-Za-z]:\//, "").replace(/^\/+/, "");
|
|
62
|
+
}
|
|
63
|
+
function createContentDiagnostic(options) {
|
|
64
|
+
const { error } = options;
|
|
65
|
+
return {
|
|
66
|
+
kind: options.kind,
|
|
67
|
+
title: options.title,
|
|
68
|
+
message: options.message,
|
|
69
|
+
filePath: displayPath(options.filePath, options.projectRoot),
|
|
70
|
+
details: error instanceof Error ? options.includeStack ? error.stack ?? error.message : error.message : String(error)
|
|
71
|
+
};
|
|
53
72
|
}
|
|
54
73
|
//#endregion
|
|
55
74
|
//#region source/parsers/markdown/mdx.ts
|
|
56
75
|
function getLanguage(className) {
|
|
57
76
|
return (Array.isArray(className) ? className : typeof className === "string" ? className.split(/\s+/) : []).find((item) => typeof item === "string" && item.startsWith("language-"))?.replace(/^language-/, "") || "txt";
|
|
58
77
|
}
|
|
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 highlighterPromise;
|
|
71
78
|
var cssVariablesTheme = (0, shiki.createCssVariablesTheme)();
|
|
72
|
-
async function getHighlighter() {
|
|
73
|
-
highlighterPromise = highlighterPromise ?? (0, shiki.createHighlighter)({
|
|
74
|
-
themes: [cssVariablesTheme],
|
|
75
|
-
langs: []
|
|
76
|
-
});
|
|
77
|
-
return highlighterPromise;
|
|
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
79
|
function rehypeParseCodeBlocks() {
|
|
83
80
|
return (tree) => {
|
|
84
81
|
(0, unist_util_visit.visit)(tree, "element", (node, _nodeIndex, parentNode) => {
|
|
@@ -96,65 +93,31 @@ function rehypeParseCodeBlocks() {
|
|
|
96
93
|
});
|
|
97
94
|
};
|
|
98
95
|
}
|
|
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
96
|
var remarkPlugins = _clarify_labs_renderer.markdownRemarkPlugins;
|
|
150
97
|
var rehypePlugins = [
|
|
151
|
-
|
|
98
|
+
rehype_slug.default,
|
|
152
99
|
rehypeParseCodeBlocks,
|
|
153
|
-
|
|
100
|
+
[_shikijs_rehype.default, {
|
|
101
|
+
theme: cssVariablesTheme,
|
|
102
|
+
langs: [],
|
|
103
|
+
lazy: true,
|
|
104
|
+
addLanguageClass: true,
|
|
105
|
+
fallbackLanguage: "text",
|
|
106
|
+
parseMetaString: _clarify_labs_renderer.parseCodeMeta
|
|
107
|
+
}]
|
|
154
108
|
];
|
|
155
|
-
function
|
|
156
|
-
|
|
157
|
-
|
|
109
|
+
function createContentCompileDiagnostic(options) {
|
|
110
|
+
const { format, phase, error, filePath, projectRoot } = options;
|
|
111
|
+
const label = format === "mdx" ? "MDX" : "Markdown";
|
|
112
|
+
return createContentDiagnostic({
|
|
113
|
+
kind: format,
|
|
114
|
+
title: `${label} ${phase} error`,
|
|
115
|
+
message: phase === "syntax" ? "This page could not be compiled. Fix the MDX syntax or component usage above, then reload the route." : `This page could not be compiled. Fix the ${label} syntax or plugin error below, then reload the route.`,
|
|
116
|
+
error,
|
|
117
|
+
filePath,
|
|
118
|
+
projectRoot,
|
|
119
|
+
includeStack: phase === "compilation"
|
|
120
|
+
});
|
|
158
121
|
}
|
|
159
122
|
/**
|
|
160
123
|
* Validate MDX content for diagnostics WITHOUT running the build-time rehype
|
|
@@ -162,7 +125,8 @@ function formatMdxDiagnostic(error) {
|
|
|
162
125
|
*
|
|
163
126
|
* `rehypePlugins` includes `rehypeShiki`, which loads grammar/WASM assets and
|
|
164
127
|
* is expensive. The real highlighting happens at Vite build time via the
|
|
165
|
-
* `@mdx-js/rollup`
|
|
128
|
+
* `@mdx-js/rollup` plugins (see `createMarkdownPlugin` and `createMdxPlugin`
|
|
129
|
+
* in `core/adapters.ts`), which
|
|
166
130
|
* runs the full remark + rehype pipeline. Re-running it here, during route
|
|
167
131
|
* discovery (Phase 3), would compile every `.mdx` file twice and invoke Shiki
|
|
168
132
|
* once per file per `engine.refresh()` — see ARCHITECTURE.md §2.2 which states
|
|
@@ -184,13 +148,13 @@ async function compileMdxContent(content, filePath, projectRoot) {
|
|
|
184
148
|
} catch (error) {
|
|
185
149
|
return {
|
|
186
150
|
ok: false,
|
|
187
|
-
diagnostic: {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
filePath
|
|
192
|
-
|
|
193
|
-
}
|
|
151
|
+
diagnostic: createContentCompileDiagnostic({
|
|
152
|
+
format: "mdx",
|
|
153
|
+
phase: "syntax",
|
|
154
|
+
error,
|
|
155
|
+
filePath,
|
|
156
|
+
projectRoot
|
|
157
|
+
})
|
|
194
158
|
};
|
|
195
159
|
}
|
|
196
160
|
}
|
|
@@ -311,6 +275,11 @@ function kebabToTitle(str) {
|
|
|
311
275
|
function parseMdxTree(content) {
|
|
312
276
|
return remark.remark.parse(content);
|
|
313
277
|
}
|
|
278
|
+
async function compileRouteDiagnostic(content, filePath, baseDir) {
|
|
279
|
+
if ((0, node_path.extname)(filePath).toLowerCase() !== ".mdx") return void 0;
|
|
280
|
+
const result = await compileMdxContent(content, filePath, baseDir);
|
|
281
|
+
return result.ok ? void 0 : result.diagnostic;
|
|
282
|
+
}
|
|
314
283
|
/** 从内容中提取第一个 H1 标题 */
|
|
315
284
|
function extractH1(content) {
|
|
316
285
|
const tree = parseMdxTree(content);
|
|
@@ -405,7 +374,7 @@ async function findContentRoutes(dir, base = dir, options = {}) {
|
|
|
405
374
|
frontmatter,
|
|
406
375
|
content
|
|
407
376
|
};
|
|
408
|
-
const
|
|
377
|
+
const diagnostic = await compileRouteDiagnostic(page.content, fullPath, base);
|
|
409
378
|
let title = typeof page.frontmatter.title === "string" ? page.frontmatter.title : "";
|
|
410
379
|
if (!title) {
|
|
411
380
|
const lastPart = pathParts[pathParts.length - 1] ?? "";
|
|
@@ -427,7 +396,7 @@ async function findContentRoutes(dir, base = dir, options = {}) {
|
|
|
427
396
|
frontmatter: page.frontmatter,
|
|
428
397
|
content: page.content
|
|
429
398
|
},
|
|
430
|
-
diagnostic
|
|
399
|
+
diagnostic
|
|
431
400
|
});
|
|
432
401
|
}
|
|
433
402
|
}
|
|
@@ -541,6 +510,7 @@ function routeIntentFromPagesItem(item) {
|
|
|
541
510
|
kind: "page",
|
|
542
511
|
ref: item
|
|
543
512
|
};
|
|
513
|
+
if ("group" in item) throw new Error("Navigation groups do not resolve to route intents");
|
|
544
514
|
if ("openapi" in item) return {
|
|
545
515
|
kind: "openapi",
|
|
546
516
|
ref: item.openapi,
|
|
@@ -568,15 +538,19 @@ function firstNavigationPath(nodes) {
|
|
|
568
538
|
}
|
|
569
539
|
function collectExplicitPagePathIntents(tabs) {
|
|
570
540
|
const intents = [];
|
|
571
|
-
|
|
572
|
-
if (
|
|
573
|
-
|
|
541
|
+
const collectItems = (items) => {
|
|
542
|
+
for (const item of items) if (typeof item !== "string" && "group" in item) collectItems(item.pages);
|
|
543
|
+
else if (typeof item !== "string" && "page" in item && item.path) {
|
|
574
544
|
const intent = routeIntentFromPagesItem(item);
|
|
575
545
|
if (intent.kind === "page" && intent.path) intents.push({
|
|
576
546
|
...intent,
|
|
577
547
|
path: intent.path
|
|
578
548
|
});
|
|
579
549
|
}
|
|
550
|
+
};
|
|
551
|
+
for (const tab of tabs ?? []) {
|
|
552
|
+
if (!tab.pages || tab.pages === "FileTree") continue;
|
|
553
|
+
for (const group of tab.pages) collectItems(group.pages);
|
|
580
554
|
}
|
|
581
555
|
return intents;
|
|
582
556
|
}
|
|
@@ -627,28 +601,38 @@ function buildNavigationFromTabsConfig(routes, tabs) {
|
|
|
627
601
|
}
|
|
628
602
|
function buildNavigationFromConfig(routes, config) {
|
|
629
603
|
const routeMap = new Map(routes.map((r) => [r.path, r]));
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
const path = routePathFromRef(intent.ref, intent.path);
|
|
604
|
+
const buildItem = (item) => {
|
|
605
|
+
if (typeof item !== "string" && "group" in item) {
|
|
606
|
+
const children = item.pages.map(buildItem);
|
|
607
|
+
return {
|
|
608
|
+
path: firstNavigationPath(children),
|
|
609
|
+
title: resolveLocalizedText(item.group, "", "") ?? "",
|
|
610
|
+
icon: item.icon,
|
|
611
|
+
children
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
const intent = routeIntentFromPagesItem(item);
|
|
615
|
+
if (intent.kind === "openapi") {
|
|
616
|
+
const path = openAPIPagePathFromRef(intent.ref, intent.tagFilter, intent.path);
|
|
644
617
|
const route = routeMap.get(path);
|
|
645
618
|
return {
|
|
646
|
-
path
|
|
619
|
+
path,
|
|
647
620
|
title: resolveLocalizedText(intent.title, "", "") ?? route?.meta.title ?? kebabToTitle(path.split("/").pop() ?? intent.ref),
|
|
648
621
|
icon: intent.icon,
|
|
649
622
|
sections: route?.meta.sections ? navigationSections(route.meta.sections) : void 0
|
|
650
623
|
};
|
|
651
|
-
}
|
|
624
|
+
}
|
|
625
|
+
const path = routePathFromRef(intent.ref, intent.path);
|
|
626
|
+
const route = routeMap.get(path);
|
|
627
|
+
return {
|
|
628
|
+
path: intent.redirect ? normalizePath(intent.redirect) : path,
|
|
629
|
+
title: resolveLocalizedText(intent.title, "", "") ?? route?.meta.title ?? kebabToTitle(path.split("/").pop() ?? intent.ref),
|
|
630
|
+
icon: intent.icon,
|
|
631
|
+
sections: route?.meta.sections ? navigationSections(route.meta.sections) : void 0
|
|
632
|
+
};
|
|
633
|
+
};
|
|
634
|
+
return config.map((group) => {
|
|
635
|
+
const children = group.pages.map(buildItem);
|
|
652
636
|
return {
|
|
653
637
|
path: children[0]?.path ?? "/",
|
|
654
638
|
title: resolveLocalizedText(group.group, "", "") ?? "",
|
|
@@ -670,19 +654,29 @@ function buildLocalizedNavigationForLocale(routes, config, locale, i18n) {
|
|
|
670
654
|
path: route.basePath ?? route.path
|
|
671
655
|
}))), locale, i18n);
|
|
672
656
|
const routeMap = new Map(routes.map((route) => [route.basePath ?? route.path, route]));
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
const
|
|
676
|
-
const basePath = intent.kind === "openapi" ? openAPIPagePathFromRef(intent.ref, intent.tagFilter, intent.path) : routePathFromRef(intent.ref, intent.path);
|
|
677
|
-
const route = routeMap.get(basePath);
|
|
678
|
-
const path = route?.path ?? localizedRoutePath(basePath, locale, i18n);
|
|
657
|
+
const buildItem = (item) => {
|
|
658
|
+
if (typeof item !== "string" && "group" in item) {
|
|
659
|
+
const children = item.pages.map(buildItem);
|
|
679
660
|
return {
|
|
680
|
-
path: (
|
|
681
|
-
title: resolveLocalizedText(
|
|
682
|
-
icon:
|
|
683
|
-
|
|
661
|
+
path: firstNavigationPath(children),
|
|
662
|
+
title: resolveLocalizedText(item.group, locale, i18n.defaultLocale) ?? "",
|
|
663
|
+
icon: item.icon,
|
|
664
|
+
children
|
|
684
665
|
};
|
|
685
|
-
}
|
|
666
|
+
}
|
|
667
|
+
const intent = routeIntentFromPagesItem(item);
|
|
668
|
+
const basePath = intent.kind === "openapi" ? openAPIPagePathFromRef(intent.ref, intent.tagFilter, intent.path) : routePathFromRef(intent.ref, intent.path);
|
|
669
|
+
const route = routeMap.get(basePath);
|
|
670
|
+
const path = route?.path ?? localizedRoutePath(basePath, locale, i18n);
|
|
671
|
+
return {
|
|
672
|
+
path: (intent.kind === "page" && intent.redirect ? localizedRoutePath(routePathFromRef(intent.redirect), locale, i18n) : void 0) ?? path,
|
|
673
|
+
title: resolveLocalizedText(intent.title, locale, i18n.defaultLocale) ?? route?.meta.title ?? kebabToTitle(basePath.split("/").pop() ?? intent.ref),
|
|
674
|
+
icon: intent.icon,
|
|
675
|
+
sections: route?.meta.sections ? navigationSections(route.meta.sections) : void 0
|
|
676
|
+
};
|
|
677
|
+
};
|
|
678
|
+
return config.map((group) => {
|
|
679
|
+
const children = group.pages.map(buildItem);
|
|
686
680
|
return {
|
|
687
681
|
path: children[0]?.path ?? localizedRoutePath("/", locale, i18n),
|
|
688
682
|
title: resolveLocalizedText(group.group, locale, i18n.defaultLocale) ?? "",
|
|
@@ -927,8 +921,9 @@ var clarifySourceConfigSchema = zod.z.object({
|
|
|
927
921
|
branch: zod.z.string().optional(),
|
|
928
922
|
directory: zod.z.string().optional()
|
|
929
923
|
});
|
|
930
|
-
var clarifyPagesItemSchema = zod.z.union([
|
|
924
|
+
var clarifyPagesItemSchema = zod.z.lazy(() => zod.z.union([
|
|
931
925
|
zod.z.string(),
|
|
926
|
+
clarifyPagesGroupSchema,
|
|
932
927
|
zod.z.object({
|
|
933
928
|
page: zod.z.string(),
|
|
934
929
|
path: zod.z.string().optional(),
|
|
@@ -943,12 +938,12 @@ var clarifyPagesItemSchema = zod.z.union([
|
|
|
943
938
|
title: clarifyLocalizedTextSchema.optional(),
|
|
944
939
|
filter: zod.z.object({ tags: zod.z.array(zod.z.string()).optional() }).optional()
|
|
945
940
|
})
|
|
946
|
-
]);
|
|
947
|
-
var clarifyPagesGroupSchema = zod.z.object({
|
|
941
|
+
]));
|
|
942
|
+
var clarifyPagesGroupSchema = zod.z.lazy(() => zod.z.object({
|
|
948
943
|
group: clarifyLocalizedTextSchema,
|
|
949
944
|
icon: zod.z.string().optional(),
|
|
950
945
|
pages: zod.z.array(clarifyPagesItemSchema)
|
|
951
|
-
});
|
|
946
|
+
}));
|
|
952
947
|
var clarifyPagesConfigSchema = zod.z.union([zod.z.array(clarifyPagesGroupSchema), zod.z.literal("FileTree")]);
|
|
953
948
|
var clarifyTabItemSchema = zod.z.object({
|
|
954
949
|
tab: clarifyLocalizedTextSchema,
|
|
@@ -1296,16 +1291,10 @@ function createRuntimeSlotsModule(plugins = [], root = process.cwd()) {
|
|
|
1296
1291
|
}
|
|
1297
1292
|
return `export const runtimeSlots = {\n${[...grouped.entries()].map(([name, list]) => ` ${JSON.stringify(name)}: [\n ${list.join(",\n ")}\n ]`).join(",\n")}\n};\n`;
|
|
1298
1293
|
}
|
|
1299
|
-
function
|
|
1294
|
+
function generateContentDiagnosticModule(diagnostic) {
|
|
1300
1295
|
return `import { createContentDiagnosticComponent } from '@clarify-labs/renderer';
|
|
1301
1296
|
|
|
1302
|
-
export const contentDiagnostic = ${JSON.stringify(
|
|
1303
|
-
kind: diagnostic.kind ?? "mdx",
|
|
1304
|
-
title: diagnostic.title,
|
|
1305
|
-
message: diagnostic.message,
|
|
1306
|
-
filePath: diagnostic.filePath,
|
|
1307
|
-
details: diagnostic.details
|
|
1308
|
-
})};
|
|
1297
|
+
export const contentDiagnostic = ${JSON.stringify(diagnostic)};
|
|
1309
1298
|
|
|
1310
1299
|
export default createContentDiagnosticComponent(contentDiagnostic);
|
|
1311
1300
|
`;
|
|
@@ -1323,7 +1312,7 @@ function buildVirtualModules(args) {
|
|
|
1323
1312
|
modules.set(VIRTUAL_CLIENT_ENTRY, clientEntryModule);
|
|
1324
1313
|
modules.set(RESOLVED_CLIENT_ENTRY, clientEntryModule);
|
|
1325
1314
|
for (const route of args.routes) {
|
|
1326
|
-
const moduleContent = route.diagnostic ?
|
|
1315
|
+
const moduleContent = route.diagnostic ? generateContentDiagnosticModule(route.diagnostic) : `export { default } from ${moduleSpecifier(route.source.filePath)};`;
|
|
1327
1316
|
modules.set(route.module.virtualModuleId, moduleContent);
|
|
1328
1317
|
}
|
|
1329
1318
|
return modules;
|
|
@@ -1358,9 +1347,9 @@ async function refreshDevServer(engine, server) {
|
|
|
1358
1347
|
invalidateVirtualModules(engine, server);
|
|
1359
1348
|
return hasDevStructureChanged(before, createDevStructureSnapshot(engine.routes, engine.navigation));
|
|
1360
1349
|
}
|
|
1361
|
-
function
|
|
1350
|
+
function createNormalizedContentPlugin(engine) {
|
|
1362
1351
|
return {
|
|
1363
|
-
name: "clarify:normalized-
|
|
1352
|
+
name: "clarify:normalized-content",
|
|
1364
1353
|
enforce: "pre",
|
|
1365
1354
|
transform(_code, id) {
|
|
1366
1355
|
if (!/\.mdx?(?:\?|$)/.test(id)) return null;
|
|
@@ -1374,16 +1363,44 @@ function createNormalizedMdxContentPlugin(engine) {
|
|
|
1374
1363
|
}
|
|
1375
1364
|
};
|
|
1376
1365
|
}
|
|
1377
|
-
function
|
|
1378
|
-
return (
|
|
1379
|
-
|
|
1366
|
+
function createContentCompileTransform(transform, format, projectRoot, errorPolicy = () => "diagnostic") {
|
|
1367
|
+
return async function contentCompileTransform(code, id) {
|
|
1368
|
+
try {
|
|
1369
|
+
return await transform.call(this, code, id);
|
|
1370
|
+
} catch (error) {
|
|
1371
|
+
if (errorPolicy() === "throw") throw error;
|
|
1372
|
+
return {
|
|
1373
|
+
code: generateContentDiagnosticModule(createContentCompileDiagnostic({
|
|
1374
|
+
format,
|
|
1375
|
+
phase: "compilation",
|
|
1376
|
+
error,
|
|
1377
|
+
filePath: id.replace(/\?.*$/, ""),
|
|
1378
|
+
projectRoot
|
|
1379
|
+
})),
|
|
1380
|
+
map: null
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
function createContentCompilerPlugin(format, projectRoot, errorPolicy) {
|
|
1386
|
+
const markdown = format === "markdown";
|
|
1387
|
+
const plugin = (0, _mdx_js_rollup.default)({
|
|
1388
|
+
include: [markdown ? "**/*.md" : "**/*.mdx"],
|
|
1389
|
+
format: markdown ? "md" : "mdx",
|
|
1380
1390
|
jsxImportSource: "react",
|
|
1381
1391
|
providerImportSource: "@clarify-labs/renderer",
|
|
1382
1392
|
remarkPlugins,
|
|
1383
|
-
|
|
1393
|
+
...markdown ? { remarkRehypeOptions: { allowDangerousHtml: true } } : {},
|
|
1394
|
+
rehypePlugins: markdown ? [rehype_raw.default, ...rehypePlugins] : rehypePlugins
|
|
1384
1395
|
});
|
|
1396
|
+
const transform = typeof plugin.transform === "function" ? plugin.transform : plugin.transform?.handler;
|
|
1397
|
+
if (!transform) return plugin;
|
|
1398
|
+
return {
|
|
1399
|
+
...plugin,
|
|
1400
|
+
transform: createContentCompileTransform(transform, format, projectRoot, errorPolicy)
|
|
1401
|
+
};
|
|
1385
1402
|
}
|
|
1386
|
-
function createClarifyViteCorePlugin(engine,
|
|
1403
|
+
function createClarifyViteCorePlugin(engine, normalizedContentPlugin, markdown, mdx) {
|
|
1387
1404
|
let viteConfig;
|
|
1388
1405
|
return {
|
|
1389
1406
|
name: "clarify:core",
|
|
@@ -1485,7 +1502,8 @@ function createClarifyViteCorePlugin(engine, normalizedMdxContentPlugin, mdx) {
|
|
|
1485
1502
|
outputDirectory: viteConfig.build.outDir,
|
|
1486
1503
|
ssrPlugins: [
|
|
1487
1504
|
engine.createSSGVirtualPlugin(),
|
|
1488
|
-
|
|
1505
|
+
normalizedContentPlugin,
|
|
1506
|
+
markdown,
|
|
1489
1507
|
mdx
|
|
1490
1508
|
]
|
|
1491
1509
|
});
|
|
@@ -1502,20 +1520,31 @@ function createClarifyViteCorePlugin(engine, normalizedMdxContentPlugin, mdx) {
|
|
|
1502
1520
|
* site itself - it only bridges Vite lifecycle hooks to the engine.
|
|
1503
1521
|
*/
|
|
1504
1522
|
function createViteAdapter(engine) {
|
|
1505
|
-
|
|
1506
|
-
const
|
|
1523
|
+
let contentCompileErrorPolicy = "diagnostic";
|
|
1524
|
+
const errorPolicy = () => contentCompileErrorPolicy;
|
|
1525
|
+
const normalizedContentPlugin = createNormalizedContentPlugin(engine);
|
|
1526
|
+
const markdown = createContentCompilerPlugin("markdown", engine.root, errorPolicy);
|
|
1527
|
+
const mdx = createContentCompilerPlugin("mdx", engine.root, errorPolicy);
|
|
1528
|
+
const compilePolicyPlugin = {
|
|
1529
|
+
name: "clarify:content-compile-policy",
|
|
1530
|
+
configResolved(config) {
|
|
1531
|
+
contentCompileErrorPolicy = config.command === "build" && engine.generateOptions.ssg.failOnError ? "throw" : "diagnostic";
|
|
1532
|
+
}
|
|
1533
|
+
};
|
|
1507
1534
|
const tailwind = (0, _tailwindcss_vite.default)();
|
|
1508
1535
|
return [
|
|
1509
1536
|
...(0, _vitejs_plugin_react.default)(),
|
|
1510
1537
|
...Array.isArray(tailwind) ? tailwind : [tailwind],
|
|
1511
|
-
|
|
1512
|
-
|
|
1538
|
+
compilePolicyPlugin,
|
|
1539
|
+
normalizedContentPlugin,
|
|
1540
|
+
createClarifyViteCorePlugin(engine, normalizedContentPlugin, markdown, mdx),
|
|
1541
|
+
markdown,
|
|
1513
1542
|
mdx
|
|
1514
1543
|
];
|
|
1515
1544
|
}
|
|
1516
1545
|
var cliPackageVersion = {
|
|
1517
1546
|
name: "@clarify-labs/cli",
|
|
1518
|
-
version: "0.10.
|
|
1547
|
+
version: "0.10.3",
|
|
1519
1548
|
license: "AGPL-3.0-only",
|
|
1520
1549
|
type: "module",
|
|
1521
1550
|
repository: {
|
|
@@ -1556,6 +1585,7 @@ var cliPackageVersion = {
|
|
|
1556
1585
|
"@clarify-labs/templates": "workspace:*",
|
|
1557
1586
|
"@mdx-js/mdx": "^3.1.1",
|
|
1558
1587
|
"@mdx-js/rollup": "^3.1.1",
|
|
1588
|
+
"@shikijs/rehype": "^4.3.0",
|
|
1559
1589
|
"@tailwindcss/vite": "^4.3.2",
|
|
1560
1590
|
"@vitejs/plugin-react": "^6.0.3",
|
|
1561
1591
|
"cac": "^7.0.0",
|
|
@@ -1570,6 +1600,8 @@ var cliPackageVersion = {
|
|
|
1570
1600
|
"react-router": "^7.0.0",
|
|
1571
1601
|
"react-router-dom": "^7.0.0",
|
|
1572
1602
|
"react-zoom-pan-pinch": "^4.0.3",
|
|
1603
|
+
"rehype-raw": "^7.0.0",
|
|
1604
|
+
"rehype-slug": "^6.0.0",
|
|
1573
1605
|
"remark": "^15.0.1",
|
|
1574
1606
|
"remark-gfm": "^4.0.1",
|
|
1575
1607
|
"shiki": "4.3.0",
|
|
@@ -1865,9 +1897,6 @@ var OPENAPI_HTTP_METHODS = [
|
|
|
1865
1897
|
"trace"
|
|
1866
1898
|
];
|
|
1867
1899
|
var CLARIFY_OPENAPI_SECTION_ID_EXTENSION = "x-clarify-section-id";
|
|
1868
|
-
function errorMessage(error) {
|
|
1869
|
-
return error instanceof Error ? error.message : String(error);
|
|
1870
|
-
}
|
|
1871
1900
|
function isSameOpenAPIFile(url, filePath) {
|
|
1872
1901
|
try {
|
|
1873
1902
|
return (0, node_path.resolve)((0, node_url.fileURLToPath)(url)) === (0, node_path.resolve)(filePath);
|
|
@@ -1982,7 +2011,7 @@ function extractOpenAPISections(spec, filterTags) {
|
|
|
1982
2011
|
}
|
|
1983
2012
|
return sections;
|
|
1984
2013
|
}
|
|
1985
|
-
async function readOpenAPISpec(filePath, contentProcessor) {
|
|
2014
|
+
async function readOpenAPISpec(filePath, contentProcessor, projectRoot) {
|
|
1986
2015
|
try {
|
|
1987
2016
|
if (!contentProcessor) return {
|
|
1988
2017
|
ok: true,
|
|
@@ -2005,13 +2034,14 @@ async function readOpenAPISpec(filePath, contentProcessor) {
|
|
|
2005
2034
|
} catch (error) {
|
|
2006
2035
|
return {
|
|
2007
2036
|
ok: false,
|
|
2008
|
-
diagnostic: {
|
|
2037
|
+
diagnostic: createContentDiagnostic({
|
|
2009
2038
|
kind: "openapi",
|
|
2010
2039
|
title: "OpenAPI spec parse failed",
|
|
2011
|
-
message:
|
|
2040
|
+
message: "Clarify could not parse this OpenAPI specification.",
|
|
2041
|
+
error,
|
|
2012
2042
|
filePath,
|
|
2013
|
-
|
|
2014
|
-
}
|
|
2043
|
+
projectRoot
|
|
2044
|
+
})
|
|
2015
2045
|
};
|
|
2016
2046
|
}
|
|
2017
2047
|
}
|
|
@@ -2042,31 +2072,24 @@ export const routeData = {};
|
|
|
2042
2072
|
export default createOpenApiRouteComponent({ ...routeData, spec });
|
|
2043
2073
|
`;
|
|
2044
2074
|
}
|
|
2045
|
-
function generateOpenAPIErrorModule(diagnostic) {
|
|
2046
|
-
return `import { createContentDiagnosticComponent } from '@clarify-labs/renderer';
|
|
2047
|
-
|
|
2048
|
-
export const contentDiagnostic = ${JSON.stringify({
|
|
2049
|
-
kind: diagnostic.kind ?? "openapi",
|
|
2050
|
-
title: diagnostic.title,
|
|
2051
|
-
message: diagnostic.message,
|
|
2052
|
-
filePath: diagnostic.filePath,
|
|
2053
|
-
details: diagnostic.details
|
|
2054
|
-
})};
|
|
2055
|
-
|
|
2056
|
-
export default createContentDiagnosticComponent(contentDiagnostic);
|
|
2057
|
-
`;
|
|
2058
|
-
}
|
|
2059
2075
|
//#endregion
|
|
2060
2076
|
//#region source/plugins/openapi/index.ts
|
|
2061
2077
|
function collectOpenAPIPageIntents(config) {
|
|
2062
2078
|
const intents = [];
|
|
2063
|
-
function
|
|
2064
|
-
|
|
2065
|
-
|
|
2079
|
+
function visitItems(items) {
|
|
2080
|
+
for (const item of items) {
|
|
2081
|
+
if (typeof item !== "string" && "group" in item) {
|
|
2082
|
+
visitItems(item.pages);
|
|
2083
|
+
continue;
|
|
2084
|
+
}
|
|
2066
2085
|
const intent = routeIntentFromPagesItem(item);
|
|
2067
2086
|
if (intent.kind === "openapi" && (intent.path || intent.tagFilter?.length)) intents.push(intent);
|
|
2068
2087
|
}
|
|
2069
2088
|
}
|
|
2089
|
+
function visitPages(pages) {
|
|
2090
|
+
if (!pages || pages === "FileTree") return;
|
|
2091
|
+
for (const group of pages) visitItems(group.pages);
|
|
2092
|
+
}
|
|
2070
2093
|
for (const tab of config.tabs ?? []) visitPages(tab.pages);
|
|
2071
2094
|
return intents;
|
|
2072
2095
|
}
|
|
@@ -2212,7 +2235,7 @@ function createOpenAPIPlugin() {
|
|
|
2212
2235
|
const result = specFromCache ? {
|
|
2213
2236
|
ok: true,
|
|
2214
2237
|
spec: specFromCache
|
|
2215
|
-
} : await readOpenAPISpec(route.source.filePath, processor);
|
|
2238
|
+
} : await readOpenAPISpec(route.source.filePath, processor, ctx.generateOptions.projectRoot);
|
|
2216
2239
|
if (!result.ok) {
|
|
2217
2240
|
route.diagnostic = result.diagnostic;
|
|
2218
2241
|
route.meta.title = route.meta.title || "OpenAPI parse error";
|
|
@@ -2259,7 +2282,7 @@ function createOpenAPIPlugin() {
|
|
|
2259
2282
|
for (const [routeSpecModuleId, spec] of specModules) modules.set(specVirtualModuleId(routeSpecModuleId), generateOpenAPISpecModule(spec));
|
|
2260
2283
|
for (const route of ctx.routes) {
|
|
2261
2284
|
if (route.kind !== "openapi") continue;
|
|
2262
|
-
if (route.diagnostic) modules.set(route.module.virtualModuleId,
|
|
2285
|
+
if (route.diagnostic) modules.set(route.module.virtualModuleId, generateContentDiagnosticModule(route.diagnostic));
|
|
2263
2286
|
else if (route.openapi?.sourceSpecId) {
|
|
2264
2287
|
const routeSpecModuleId = route.openapi.routeSpecModuleId ?? route.openapi.sourceSpecId;
|
|
2265
2288
|
if (!specModules.has(routeSpecModuleId)) continue;
|
|
@@ -2714,6 +2737,11 @@ function writeClarifyEnvDts(projectRoot, plugins) {
|
|
|
2714
2737
|
(0, node_fs.writeFileSync)(filePath, next, "utf-8");
|
|
2715
2738
|
}
|
|
2716
2739
|
//#endregion
|
|
2740
|
+
//#region source/parsers/markdown/utils.ts
|
|
2741
|
+
function escapeHtml(text) {
|
|
2742
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2743
|
+
}
|
|
2744
|
+
//#endregion
|
|
2717
2745
|
//#region source/core/runtime/html-template.ts
|
|
2718
2746
|
/**
|
|
2719
2747
|
* HTML template manipulation helpers used during SSG.
|
|
@@ -3086,6 +3114,12 @@ function loadVirtualModule(id, modules) {
|
|
|
3086
3114
|
const bareId = stripVirtualPrefix(id);
|
|
3087
3115
|
return modules.get(bareId) ?? modules.get(id) ?? null;
|
|
3088
3116
|
}
|
|
3117
|
+
function assertNoContentDiagnostics(routes) {
|
|
3118
|
+
const failures = routes.filter((route) => route.diagnostic);
|
|
3119
|
+
if (failures.length === 0) return;
|
|
3120
|
+
const summary = failures.map((route) => `- ${route.path}: ${route.diagnostic?.title ?? "Content error"}${route.diagnostic?.filePath ? ` (${route.diagnostic.filePath})` : ""}`).join("\n");
|
|
3121
|
+
throw new Error(`[clarify] Content diagnostics prevented the build:\n${summary}`);
|
|
3122
|
+
}
|
|
3089
3123
|
var ClarifyEngine = class {
|
|
3090
3124
|
options;
|
|
3091
3125
|
root;
|
|
@@ -3310,6 +3344,7 @@ var ClarifyEngine = class {
|
|
|
3310
3344
|
await runPhase(this.plugins, "ssg", this.ctx, async () => {
|
|
3311
3345
|
if (process.env.SKIP_CLARIFY_SSG) return;
|
|
3312
3346
|
if (!await runInterceptHooks(this.plugins, "ssg:shouldRun", this.ctx)) return;
|
|
3347
|
+
if (this.generateOptions.ssg.failOnError) assertNoContentDiagnostics(this.routes);
|
|
3313
3348
|
const outputDir = this.runtime.outputDirectory ?? this.generateOptions.outputDirectory;
|
|
3314
3349
|
if (!outputDir) throw new Error("[clarify] outputDirectory is required before SSG runs");
|
|
3315
3350
|
const ssrOutputDir = (0, node_path.join)(outputDir, ".ssr");
|
|
@@ -3417,4 +3452,4 @@ Object.defineProperty(exports, "defineConfig", {
|
|
|
3417
3452
|
}
|
|
3418
3453
|
});
|
|
3419
3454
|
|
|
3420
|
-
//# sourceMappingURL=engine-
|
|
3455
|
+
//# sourceMappingURL=engine-BDdPszs2.cjs.map
|