@clarify-labs/cli 0.10.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +196 -201
- package/output/core/config/config.d.ts +2 -1
- package/output/core/config/options.d.ts +0 -8
- package/output/core/config/user-config.d.ts +4 -3
- package/output/core/engine/engine.d.ts +1 -0
- package/output/core/project/project-info.d.ts +3 -3
- package/output/core/runtime/ssg.d.ts +1 -1
- package/output/core/runtime/virtual-modules.d.ts +2 -2
- package/output/{engine-qafLfnXQ.cjs → engine-BfkoyVNo.cjs} +353 -236
- package/output/engine-BfkoyVNo.cjs.map +1 -0
- package/output/{engine-CSSL_gGd.js → engine-DfF5RJjC.js} +353 -236
- package/output/engine-DfF5RJjC.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 +8 -0
- package/output/parsers/routes/routes.d.ts +7 -7
- package/output/parsers/routes/routes.test-utils.d.ts +2 -2
- package/output/plugins/openapi/parser.d.ts +1 -1
- package/output/plugins/openapi/virtual-modules.d.ts +1 -2
- package/output/plugins/source-links/source-links.d.ts +3 -3
- package/output/types.d.ts +67 -42
- package/package.json +3 -3
- package/output/engine-CSSL_gGd.js.map +0 -1
- package/output/engine-qafLfnXQ.cjs.map +0 -1
|
@@ -22,6 +22,24 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
22
22
|
import SwaggerParser from "@apidevtools/swagger-parser";
|
|
23
23
|
import { tmpdir } from "node:os";
|
|
24
24
|
import { createRequire } from "node:module";
|
|
25
|
+
//#region source/parsers/content/diagnostic.ts
|
|
26
|
+
function displayPath(filePath, projectRoot) {
|
|
27
|
+
if (!filePath) return void 0;
|
|
28
|
+
if (!projectRoot) return filePath.replace(/^[A-Za-z]:\//, "").replace(/^\/+/, "");
|
|
29
|
+
const normalized = relative(projectRoot, filePath);
|
|
30
|
+
return normalized && !normalized.startsWith("..") && !isAbsolute(normalized) ? normalized : filePath.replace(/^[A-Za-z]:\//, "").replace(/^\/+/, "");
|
|
31
|
+
}
|
|
32
|
+
function createContentDiagnostic(options) {
|
|
33
|
+
const { error } = options;
|
|
34
|
+
return {
|
|
35
|
+
kind: options.kind,
|
|
36
|
+
title: options.title,
|
|
37
|
+
message: options.message,
|
|
38
|
+
filePath: displayPath(options.filePath, options.projectRoot),
|
|
39
|
+
details: error instanceof Error ? options.includeStack ? error.stack ?? error.message : error.message : String(error)
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
25
43
|
//#region source/parsers/markdown/mdx.ts
|
|
26
44
|
function getLanguage(className) {
|
|
27
45
|
return (Array.isArray(className) ? className : typeof className === "string" ? className.split(/\s+/) : []).find((item) => typeof item === "string" && item.startsWith("language-"))?.replace(/^language-/, "") || "txt";
|
|
@@ -57,9 +75,18 @@ var rehypePlugins = [
|
|
|
57
75
|
parseMetaString: parseCodeMeta
|
|
58
76
|
}]
|
|
59
77
|
];
|
|
60
|
-
function
|
|
61
|
-
|
|
62
|
-
|
|
78
|
+
function createContentCompileDiagnostic(options) {
|
|
79
|
+
const { format, phase, error, filePath, projectRoot } = options;
|
|
80
|
+
const label = format === "mdx" ? "MDX" : "Markdown";
|
|
81
|
+
return createContentDiagnostic({
|
|
82
|
+
kind: format,
|
|
83
|
+
title: `${label} ${phase} error`,
|
|
84
|
+
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.`,
|
|
85
|
+
error,
|
|
86
|
+
filePath,
|
|
87
|
+
projectRoot,
|
|
88
|
+
includeStack: phase === "compilation"
|
|
89
|
+
});
|
|
63
90
|
}
|
|
64
91
|
/**
|
|
65
92
|
* Validate MDX content for diagnostics WITHOUT running the build-time rehype
|
|
@@ -90,13 +117,13 @@ async function compileMdxContent(content, filePath, projectRoot) {
|
|
|
90
117
|
} catch (error) {
|
|
91
118
|
return {
|
|
92
119
|
ok: false,
|
|
93
|
-
diagnostic: {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
filePath
|
|
98
|
-
|
|
99
|
-
}
|
|
120
|
+
diagnostic: createContentCompileDiagnostic({
|
|
121
|
+
format: "mdx",
|
|
122
|
+
phase: "syntax",
|
|
123
|
+
error,
|
|
124
|
+
filePath,
|
|
125
|
+
projectRoot
|
|
126
|
+
})
|
|
100
127
|
};
|
|
101
128
|
}
|
|
102
129
|
}
|
|
@@ -352,10 +379,10 @@ function frontmatterKeywords(frontmatter) {
|
|
|
352
379
|
const keywords = Array.isArray(value) ? value.filter((item) => typeof item === "string") : typeof value === "string" ? value.split(",").map((keyword) => keyword.trim()).filter(Boolean) : [];
|
|
353
380
|
return keywords.length > 0 ? keywords : void 0;
|
|
354
381
|
}
|
|
355
|
-
function withAlternates(route, routes,
|
|
382
|
+
function withAlternates(route, routes, locales) {
|
|
356
383
|
const basePath = route.basePath ?? route.path;
|
|
357
384
|
const routeByLocaleAndBase = new Map(routes.filter((r) => !r.locale || r.path === `/${r.locale}` || r.path.startsWith(`/${r.locale}/`)).map((r) => [`${r.locale ?? ""}:${r.basePath ?? r.path}`, r]));
|
|
358
|
-
const alternates = Object.fromEntries(
|
|
385
|
+
const alternates = Object.fromEntries(locales.locales.flatMap((locale) => {
|
|
359
386
|
const alternate = routeByLocaleAndBase.get(`${locale.code}:${basePath}`);
|
|
360
387
|
return alternate ? [[locale.code, alternate.path]] : [];
|
|
361
388
|
}));
|
|
@@ -368,11 +395,11 @@ function withAlternates(route, routes, i18n) {
|
|
|
368
395
|
* 为默认语言的 locale-prefixed 路由生成无前缀的"裸路径别名",方便不带语言
|
|
369
396
|
* 前缀的 URL 也能访问。标记 `isBareAlias` 以便搜索索引生成时过滤重复索引。
|
|
370
397
|
*/
|
|
371
|
-
function generateBareAliases(routes,
|
|
398
|
+
function generateBareAliases(routes, locales) {
|
|
372
399
|
const bareRoutes = [];
|
|
373
400
|
const seenBare = new Set(routes.map((r) => r.path));
|
|
374
401
|
for (const route of routes) {
|
|
375
|
-
if (route.locale !==
|
|
402
|
+
if (route.locale !== locales.default) continue;
|
|
376
403
|
const bp = route.basePath ?? route.path;
|
|
377
404
|
if (bp === route.path || seenBare.has(bp)) continue;
|
|
378
405
|
seenBare.add(bp);
|
|
@@ -384,42 +411,42 @@ function generateBareAliases(routes, i18n) {
|
|
|
384
411
|
}
|
|
385
412
|
return bareRoutes;
|
|
386
413
|
}
|
|
387
|
-
async function findLocalizedContentRoutes(contentRoot,
|
|
388
|
-
if (!
|
|
414
|
+
async function findLocalizedContentRoutes(contentRoot, locales, options = {}) {
|
|
415
|
+
if (!locales) return findContentRoutes(contentRoot, contentRoot, options);
|
|
389
416
|
const localizedRoutes = [];
|
|
390
|
-
for (const locale of
|
|
417
|
+
for (const locale of locales.locales) {
|
|
391
418
|
const localeRoot = join(contentRoot, locale.code);
|
|
392
419
|
const discovered = await findContentRoutes(localeRoot, localeRoot, options);
|
|
393
420
|
for (const route of discovered) {
|
|
394
421
|
const basePath = route.basePath ?? route.path;
|
|
395
422
|
localizedRoutes.push({
|
|
396
423
|
...route,
|
|
397
|
-
path: localizedRoutePath(basePath, locale.code,
|
|
424
|
+
path: localizedRoutePath(basePath, locale.code, locales),
|
|
398
425
|
basePath,
|
|
399
426
|
locale: locale.code,
|
|
400
427
|
module: { virtualModuleId: virtualModuleIdForLocalizedRoute(contentRoot, route.source.filePath) }
|
|
401
428
|
});
|
|
402
429
|
}
|
|
403
430
|
}
|
|
404
|
-
if (
|
|
431
|
+
if (locales.missing === "fallback") {
|
|
405
432
|
const routeByLocaleAndBase = new Map(localizedRoutes.map((route) => [`${route.locale ?? ""}:${route.basePath ?? route.path}`, route]));
|
|
406
|
-
const defaultRoutes = localizedRoutes.filter((route) => route.locale ===
|
|
433
|
+
const defaultRoutes = localizedRoutes.filter((route) => route.locale === locales.default);
|
|
407
434
|
for (const sourceRoute of defaultRoutes) {
|
|
408
435
|
const basePath = sourceRoute.basePath ?? sourceRoute.path;
|
|
409
|
-
for (const locale of
|
|
436
|
+
for (const locale of locales.locales) {
|
|
410
437
|
const key = `${locale.code}:${basePath}`;
|
|
411
438
|
if (routeByLocaleAndBase.has(key)) continue;
|
|
412
439
|
localizedRoutes.push({
|
|
413
440
|
...sourceRoute,
|
|
414
|
-
path: localizedRoutePath(basePath, locale.code,
|
|
441
|
+
path: localizedRoutePath(basePath, locale.code, locales),
|
|
415
442
|
locale: locale.code,
|
|
416
443
|
isFallback: true
|
|
417
444
|
});
|
|
418
445
|
}
|
|
419
446
|
}
|
|
420
447
|
}
|
|
421
|
-
const routesWithAlternates = localizedRoutes.map((route) => withAlternates(route, localizedRoutes,
|
|
422
|
-
return [...routesWithAlternates, ...generateBareAliases(routesWithAlternates,
|
|
448
|
+
const routesWithAlternates = localizedRoutes.map((route) => withAlternates(route, localizedRoutes, locales));
|
|
449
|
+
return [...routesWithAlternates, ...generateBareAliases(routesWithAlternates, locales)];
|
|
423
450
|
}
|
|
424
451
|
function buildNavigation(routes) {
|
|
425
452
|
const root = [];
|
|
@@ -452,6 +479,7 @@ function routeIntentFromPagesItem(item) {
|
|
|
452
479
|
kind: "page",
|
|
453
480
|
ref: item
|
|
454
481
|
};
|
|
482
|
+
if ("group" in item) throw new Error("Navigation groups do not resolve to route intents");
|
|
455
483
|
if ("openapi" in item) return {
|
|
456
484
|
kind: "openapi",
|
|
457
485
|
ref: item.openapi,
|
|
@@ -479,19 +507,23 @@ function firstNavigationPath(nodes) {
|
|
|
479
507
|
}
|
|
480
508
|
function collectExplicitPagePathIntents(tabs) {
|
|
481
509
|
const intents = [];
|
|
482
|
-
|
|
483
|
-
if (
|
|
484
|
-
|
|
510
|
+
const collectItems = (items) => {
|
|
511
|
+
for (const item of items) if (typeof item !== "string" && "group" in item) collectItems(item.pages);
|
|
512
|
+
else if (typeof item !== "string" && "page" in item && item.path) {
|
|
485
513
|
const intent = routeIntentFromPagesItem(item);
|
|
486
514
|
if (intent.kind === "page" && intent.path) intents.push({
|
|
487
515
|
...intent,
|
|
488
516
|
path: intent.path
|
|
489
517
|
});
|
|
490
518
|
}
|
|
519
|
+
};
|
|
520
|
+
for (const tab of tabs ?? []) {
|
|
521
|
+
if (!tab.pages || tab.pages === "FileTree") continue;
|
|
522
|
+
for (const group of tab.pages) collectItems(group.pages);
|
|
491
523
|
}
|
|
492
524
|
return intents;
|
|
493
525
|
}
|
|
494
|
-
function applyConfiguredPageRoutePaths(routes, tabs,
|
|
526
|
+
function applyConfiguredPageRoutePaths(routes, tabs, locales) {
|
|
495
527
|
const pageIntents = collectExplicitPagePathIntents(tabs);
|
|
496
528
|
if (!pageIntents.length) return routes;
|
|
497
529
|
const additions = [];
|
|
@@ -507,15 +539,15 @@ function applyConfiguredPageRoutePaths(routes, tabs, i18n) {
|
|
|
507
539
|
existingKeys.add(key);
|
|
508
540
|
additions.push({
|
|
509
541
|
...route,
|
|
510
|
-
path: route.locale &&
|
|
542
|
+
path: route.locale && locales ? localizedRoutePath(targetBasePath, route.locale, locales) : targetBasePath,
|
|
511
543
|
basePath: targetBasePath
|
|
512
544
|
});
|
|
513
545
|
}
|
|
514
546
|
}
|
|
515
547
|
const nextRoutes = [...routes, ...additions];
|
|
516
|
-
const routesWithAlternates =
|
|
517
|
-
if (!
|
|
518
|
-
return [...routesWithAlternates, ...generateBareAliases(routesWithAlternates,
|
|
548
|
+
const routesWithAlternates = locales ? nextRoutes.map((route) => withAlternates(route, nextRoutes, locales)) : nextRoutes;
|
|
549
|
+
if (!locales) return routesWithAlternates;
|
|
550
|
+
return [...routesWithAlternates, ...generateBareAliases(routesWithAlternates, locales)];
|
|
519
551
|
}
|
|
520
552
|
function buildNavigationFromPagesConfig(routes, config) {
|
|
521
553
|
if (!config || config === "FileTree") return buildNavigation(routes);
|
|
@@ -538,28 +570,38 @@ function buildNavigationFromTabsConfig(routes, tabs) {
|
|
|
538
570
|
}
|
|
539
571
|
function buildNavigationFromConfig(routes, config) {
|
|
540
572
|
const routeMap = new Map(routes.map((r) => [r.path, r]));
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
const path = routePathFromRef(intent.ref, intent.path);
|
|
573
|
+
const buildItem = (item) => {
|
|
574
|
+
if (typeof item !== "string" && "group" in item) {
|
|
575
|
+
const children = item.pages.map(buildItem);
|
|
576
|
+
return {
|
|
577
|
+
path: firstNavigationPath(children),
|
|
578
|
+
title: resolveLocalizedText(item.group, "", "") ?? "",
|
|
579
|
+
icon: item.icon,
|
|
580
|
+
children
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
const intent = routeIntentFromPagesItem(item);
|
|
584
|
+
if (intent.kind === "openapi") {
|
|
585
|
+
const path = openAPIPagePathFromRef(intent.ref, intent.tagFilter, intent.path);
|
|
555
586
|
const route = routeMap.get(path);
|
|
556
587
|
return {
|
|
557
|
-
path
|
|
588
|
+
path,
|
|
558
589
|
title: resolveLocalizedText(intent.title, "", "") ?? route?.meta.title ?? kebabToTitle(path.split("/").pop() ?? intent.ref),
|
|
559
590
|
icon: intent.icon,
|
|
560
591
|
sections: route?.meta.sections ? navigationSections(route.meta.sections) : void 0
|
|
561
592
|
};
|
|
562
|
-
}
|
|
593
|
+
}
|
|
594
|
+
const path = routePathFromRef(intent.ref, intent.path);
|
|
595
|
+
const route = routeMap.get(path);
|
|
596
|
+
return {
|
|
597
|
+
path: intent.redirect ? normalizePath(intent.redirect) : path,
|
|
598
|
+
title: resolveLocalizedText(intent.title, "", "") ?? route?.meta.title ?? kebabToTitle(path.split("/").pop() ?? intent.ref),
|
|
599
|
+
icon: intent.icon,
|
|
600
|
+
sections: route?.meta.sections ? navigationSections(route.meta.sections) : void 0
|
|
601
|
+
};
|
|
602
|
+
};
|
|
603
|
+
return config.map((group) => {
|
|
604
|
+
const children = group.pages.map(buildItem);
|
|
563
605
|
return {
|
|
564
606
|
path: children[0]?.path ?? "/",
|
|
565
607
|
title: resolveLocalizedText(group.group, "", "") ?? "",
|
|
@@ -568,51 +610,61 @@ function buildNavigationFromConfig(routes, config) {
|
|
|
568
610
|
};
|
|
569
611
|
});
|
|
570
612
|
}
|
|
571
|
-
function localizeNavigationPaths(nodes, locale,
|
|
613
|
+
function localizeNavigationPaths(nodes, locale, locales) {
|
|
572
614
|
return nodes.map((node) => ({
|
|
573
615
|
...node,
|
|
574
|
-
path: localizedRoutePath(node.path, locale,
|
|
575
|
-
children: node.children ? localizeNavigationPaths(node.children, locale,
|
|
616
|
+
path: localizedRoutePath(node.path, locale, locales),
|
|
617
|
+
children: node.children ? localizeNavigationPaths(node.children, locale, locales) : void 0
|
|
576
618
|
}));
|
|
577
619
|
}
|
|
578
|
-
function buildLocalizedNavigationForLocale(routes, config, locale,
|
|
620
|
+
function buildLocalizedNavigationForLocale(routes, config, locale, locales) {
|
|
579
621
|
if (!config || config === "FileTree") return localizeNavigationPaths(buildNavigation(routes.map((route) => ({
|
|
580
622
|
...route,
|
|
581
623
|
path: route.basePath ?? route.path
|
|
582
|
-
}))), locale,
|
|
624
|
+
}))), locale, locales);
|
|
583
625
|
const routeMap = new Map(routes.map((route) => [route.basePath ?? route.path, route]));
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
const
|
|
587
|
-
const basePath = intent.kind === "openapi" ? openAPIPagePathFromRef(intent.ref, intent.tagFilter, intent.path) : routePathFromRef(intent.ref, intent.path);
|
|
588
|
-
const route = routeMap.get(basePath);
|
|
589
|
-
const path = route?.path ?? localizedRoutePath(basePath, locale, i18n);
|
|
626
|
+
const buildItem = (item) => {
|
|
627
|
+
if (typeof item !== "string" && "group" in item) {
|
|
628
|
+
const children = item.pages.map(buildItem);
|
|
590
629
|
return {
|
|
591
|
-
path: (
|
|
592
|
-
title: resolveLocalizedText(
|
|
593
|
-
icon:
|
|
594
|
-
|
|
630
|
+
path: firstNavigationPath(children),
|
|
631
|
+
title: resolveLocalizedText(item.group, locale, locales.default) ?? "",
|
|
632
|
+
icon: item.icon,
|
|
633
|
+
children
|
|
595
634
|
};
|
|
596
|
-
}
|
|
635
|
+
}
|
|
636
|
+
const intent = routeIntentFromPagesItem(item);
|
|
637
|
+
const basePath = intent.kind === "openapi" ? openAPIPagePathFromRef(intent.ref, intent.tagFilter, intent.path) : routePathFromRef(intent.ref, intent.path);
|
|
638
|
+
const route = routeMap.get(basePath);
|
|
639
|
+
const path = route?.path ?? localizedRoutePath(basePath, locale, locales);
|
|
640
|
+
return {
|
|
641
|
+
path: (intent.kind === "page" && intent.redirect ? localizedRoutePath(routePathFromRef(intent.redirect), locale, locales) : void 0) ?? path,
|
|
642
|
+
title: resolveLocalizedText(intent.title, locale, locales.default) ?? route?.meta.title ?? kebabToTitle(basePath.split("/").pop() ?? intent.ref),
|
|
643
|
+
icon: intent.icon,
|
|
644
|
+
sections: route?.meta.sections ? navigationSections(route.meta.sections) : void 0
|
|
645
|
+
};
|
|
646
|
+
};
|
|
647
|
+
return config.map((group) => {
|
|
648
|
+
const children = group.pages.map(buildItem);
|
|
597
649
|
return {
|
|
598
|
-
path: children[0]?.path ?? localizedRoutePath("/", locale,
|
|
599
|
-
title: resolveLocalizedText(group.group, locale,
|
|
650
|
+
path: children[0]?.path ?? localizedRoutePath("/", locale, locales),
|
|
651
|
+
title: resolveLocalizedText(group.group, locale, locales.default) ?? "",
|
|
600
652
|
icon: group.icon,
|
|
601
653
|
children
|
|
602
654
|
};
|
|
603
655
|
});
|
|
604
656
|
}
|
|
605
|
-
function buildLocalizedNavigationFromTabsConfig(routes, tabs,
|
|
606
|
-
if (!
|
|
657
|
+
function buildLocalizedNavigationFromTabsConfig(routes, tabs, localesConfig) {
|
|
658
|
+
if (!localesConfig) return void 0;
|
|
607
659
|
const locales = {};
|
|
608
|
-
for (const locale of
|
|
660
|
+
for (const locale of localesConfig.locales) {
|
|
609
661
|
const localeRoutes = routes.filter((route) => route.locale === locale.code);
|
|
610
662
|
locales[locale.code] = { tabs: tabs.map((tab) => {
|
|
611
|
-
const children = buildLocalizedNavigationForLocale(localeRoutes, tab.pages, locale.code,
|
|
663
|
+
const children = buildLocalizedNavigationForLocale(localeRoutes, tab.pages, locale.code, localesConfig);
|
|
612
664
|
return {
|
|
613
665
|
type: "tab",
|
|
614
666
|
path: firstNavigationPath(children),
|
|
615
|
-
title: resolveLocalizedText(tab.tab, locale.code,
|
|
667
|
+
title: resolveLocalizedText(tab.tab, locale.code, localesConfig.default) ?? "",
|
|
616
668
|
icon: tab.icon,
|
|
617
669
|
children
|
|
618
670
|
};
|
|
@@ -679,7 +731,7 @@ function inferRouteForFile(filePath, contentRoot, defaultLocale) {
|
|
|
679
731
|
const localeSegmentIndex = fileLocale ? segments.indexOf(fileLocale) : -1;
|
|
680
732
|
const basePath = basePathFromRef(localeSegmentIndex >= 0 ? segments.slice(localeSegmentIndex + 1).join("/") : ref);
|
|
681
733
|
const path = fileLocale && defaultLocale ? localizedRoutePath(basePath, fileLocale, {
|
|
682
|
-
defaultLocale,
|
|
734
|
+
default: defaultLocale,
|
|
683
735
|
missing: "fallback",
|
|
684
736
|
locales: []
|
|
685
737
|
}) : basePath;
|
|
@@ -732,12 +784,12 @@ async function handleDevRouteRequest(req, res, routes, context) {
|
|
|
732
784
|
}
|
|
733
785
|
const file = typeof body === "object" && body !== null ? body.file : void 0;
|
|
734
786
|
if (typeof file === "string" && file.length > 0) {
|
|
735
|
-
const route = resolveRouteForFile(file, routes, context.projectConfig.
|
|
787
|
+
const route = resolveRouteForFile(file, routes, context.projectConfig.locales?.default);
|
|
736
788
|
if (route) {
|
|
737
789
|
res.end(JSON.stringify(toDevRouteEntry(route)));
|
|
738
790
|
return;
|
|
739
791
|
}
|
|
740
|
-
const inferred = inferRouteForFile(file, context.contentRoot, context.projectConfig.
|
|
792
|
+
const inferred = inferRouteForFile(file, context.contentRoot, context.projectConfig.locales?.default);
|
|
741
793
|
res.end(JSON.stringify(inferred));
|
|
742
794
|
return;
|
|
743
795
|
}
|
|
@@ -763,8 +815,7 @@ function resolveThemeConfig(theme = {}) {
|
|
|
763
815
|
layout: {
|
|
764
816
|
...presetTheme.layout,
|
|
765
817
|
...theme.layout
|
|
766
|
-
}
|
|
767
|
-
editor: theme.editor ?? presetTheme.editor
|
|
818
|
+
}
|
|
768
819
|
};
|
|
769
820
|
}
|
|
770
821
|
//#endregion
|
|
@@ -772,26 +823,26 @@ function resolveThemeConfig(theme = {}) {
|
|
|
772
823
|
var clarifyLogoConfigSchema = z.union([z.string(), z.object({
|
|
773
824
|
light: z.string().optional(),
|
|
774
825
|
dark: z.string().optional()
|
|
775
|
-
})]);
|
|
826
|
+
}).strict()]);
|
|
776
827
|
var clarifyFaviconConfigSchema = z.union([z.string(), z.object({
|
|
777
828
|
light: z.string().optional(),
|
|
778
829
|
dark: z.string().optional()
|
|
779
|
-
})]);
|
|
830
|
+
}).strict()]);
|
|
780
831
|
var clarifyLocalizedTextSchema = z.union([z.string(), z.record(z.string(), z.string())]);
|
|
781
832
|
var clarifyLocaleConfigSchema = z.object({
|
|
782
833
|
code: z.string(),
|
|
783
834
|
label: z.string(),
|
|
784
835
|
dir: z.union([z.literal("ltr"), z.literal("rtl")]).optional()
|
|
785
|
-
});
|
|
786
|
-
var
|
|
787
|
-
|
|
836
|
+
}).strict();
|
|
837
|
+
var clarifyLocalesConfigSchema = z.object({
|
|
838
|
+
default: z.string().optional(),
|
|
788
839
|
missing: z.union([
|
|
789
840
|
z.literal("fallback"),
|
|
790
841
|
z.literal("404"),
|
|
791
842
|
z.literal("hide")
|
|
792
843
|
]).optional(),
|
|
793
844
|
locales: z.array(clarifyLocaleConfigSchema).min(1)
|
|
794
|
-
}).superRefine((config, ctx) => {
|
|
845
|
+
}).strict().superRefine((config, ctx) => {
|
|
795
846
|
const localeCodes = /* @__PURE__ */ new Set();
|
|
796
847
|
for (const [index, locale] of config.locales.entries()) {
|
|
797
848
|
if (localeCodes.has(locale.code)) ctx.addIssue({
|
|
@@ -805,17 +856,17 @@ var clarifyI18nConfigSchema = z.object({
|
|
|
805
856
|
});
|
|
806
857
|
localeCodes.add(locale.code);
|
|
807
858
|
}
|
|
808
|
-
if (config.
|
|
859
|
+
if (config.default && !localeCodes.has(config.default)) ctx.addIssue({
|
|
809
860
|
code: z.ZodIssueCode.custom,
|
|
810
|
-
message: "
|
|
811
|
-
path: ["
|
|
861
|
+
message: "default must be one of locales.locales",
|
|
862
|
+
path: ["default"]
|
|
812
863
|
});
|
|
813
864
|
});
|
|
814
865
|
var clarifyNavbarLinkSchema = z.object({
|
|
815
866
|
label: clarifyLocalizedTextSchema,
|
|
816
867
|
href: z.string(),
|
|
817
868
|
external: z.boolean().optional()
|
|
818
|
-
});
|
|
869
|
+
}).strict();
|
|
819
870
|
var clarifyBannerConfigOptionsSchema = z.object({
|
|
820
871
|
content: clarifyLocalizedTextSchema,
|
|
821
872
|
dismissible: z.boolean().optional(),
|
|
@@ -833,45 +884,46 @@ var clarifyVariableValueSchema = z.lazy(() => z.union([
|
|
|
833
884
|
z.record(z.string(), clarifyVariableValueSchema)
|
|
834
885
|
]));
|
|
835
886
|
var clarifyVariablesConfigSchema = z.record(z.string(), clarifyVariableValueSchema);
|
|
836
|
-
var
|
|
837
|
-
|
|
887
|
+
var clarifyRepositoryConfigSchema = z.object({
|
|
888
|
+
url: z.string().optional(),
|
|
838
889
|
branch: z.string().optional(),
|
|
839
890
|
directory: z.string().optional()
|
|
840
|
-
});
|
|
841
|
-
var clarifyPagesItemSchema = z.union([
|
|
891
|
+
}).strict();
|
|
892
|
+
var clarifyPagesItemSchema = z.lazy(() => z.union([
|
|
842
893
|
z.string(),
|
|
894
|
+
clarifyPagesGroupSchema,
|
|
843
895
|
z.object({
|
|
844
896
|
page: z.string(),
|
|
845
897
|
path: z.string().optional(),
|
|
846
898
|
title: clarifyLocalizedTextSchema.optional(),
|
|
847
899
|
icon: z.string().optional(),
|
|
848
900
|
redirect: z.string().optional()
|
|
849
|
-
}),
|
|
901
|
+
}).strict(),
|
|
850
902
|
z.object({
|
|
851
903
|
openapi: z.string(),
|
|
852
904
|
path: z.string().optional(),
|
|
853
905
|
icon: z.string().optional(),
|
|
854
906
|
title: clarifyLocalizedTextSchema.optional(),
|
|
855
|
-
filter: z.object({ tags: z.array(z.string()).optional() }).optional()
|
|
856
|
-
})
|
|
857
|
-
]);
|
|
858
|
-
var clarifyPagesGroupSchema = z.object({
|
|
907
|
+
filter: z.object({ tags: z.array(z.string()).optional() }).strict().optional()
|
|
908
|
+
}).strict()
|
|
909
|
+
]));
|
|
910
|
+
var clarifyPagesGroupSchema = z.lazy(() => z.object({
|
|
859
911
|
group: clarifyLocalizedTextSchema,
|
|
860
912
|
icon: z.string().optional(),
|
|
861
913
|
pages: z.array(clarifyPagesItemSchema)
|
|
862
|
-
});
|
|
914
|
+
}).strict());
|
|
863
915
|
var clarifyPagesConfigSchema = z.union([z.array(clarifyPagesGroupSchema), z.literal("FileTree")]);
|
|
864
916
|
var clarifyTabItemSchema = z.object({
|
|
865
917
|
tab: clarifyLocalizedTextSchema,
|
|
866
918
|
icon: z.string().optional(),
|
|
867
919
|
pages: clarifyPagesConfigSchema.optional()
|
|
868
|
-
});
|
|
920
|
+
}).strict();
|
|
869
921
|
var clarifyTabsConfigSchema = z.array(clarifyTabItemSchema);
|
|
870
922
|
var clarifyThemePresetSchema = z.enum(["default", "base"]);
|
|
871
923
|
var clarifyThemeModeColorValueSchema = z.object({
|
|
872
924
|
light: z.string().optional(),
|
|
873
925
|
dark: z.string().optional()
|
|
874
|
-
});
|
|
926
|
+
}).strict();
|
|
875
927
|
var clarifyThemeColorValueSchema = z.union([z.string(), clarifyThemeModeColorValueSchema]);
|
|
876
928
|
var clarifyThemeColorTokensConfigSchema = z.object({
|
|
877
929
|
primary: clarifyThemeColorValueSchema.optional(),
|
|
@@ -882,42 +934,65 @@ var clarifyThemeColorTokensConfigSchema = z.object({
|
|
|
882
934
|
muted: clarifyThemeColorValueSchema.optional(),
|
|
883
935
|
border: clarifyThemeColorValueSchema.optional(),
|
|
884
936
|
codeBackground: clarifyThemeColorValueSchema.optional()
|
|
885
|
-
});
|
|
937
|
+
}).strict();
|
|
886
938
|
var clarifyThemeRadiusTokensConfigSchema = z.object({
|
|
887
939
|
sm: z.string().optional(),
|
|
888
940
|
md: z.string().optional(),
|
|
889
941
|
lg: z.string().optional(),
|
|
890
942
|
xl: z.string().optional()
|
|
891
|
-
});
|
|
943
|
+
}).strict();
|
|
892
944
|
var clarifyThemeTokensConfigSchema = z.object({
|
|
893
945
|
colors: clarifyThemeColorTokensConfigSchema.optional(),
|
|
894
946
|
radius: clarifyThemeRadiusTokensConfigSchema.optional()
|
|
895
|
-
});
|
|
896
|
-
var clarifyThemeLayoutConfigSchema = z.object({ maxWidth: z.string().optional() });
|
|
947
|
+
}).strict();
|
|
948
|
+
var clarifyThemeLayoutConfigSchema = z.object({ maxWidth: z.string().optional() }).strict();
|
|
897
949
|
var clarifyThemeConfigSchema = z.object({
|
|
898
950
|
preset: clarifyThemePresetSchema.optional(),
|
|
899
951
|
tokens: clarifyThemeTokensConfigSchema.optional(),
|
|
900
|
-
layout: clarifyThemeLayoutConfigSchema.optional()
|
|
901
|
-
|
|
902
|
-
|
|
952
|
+
layout: clarifyThemeLayoutConfigSchema.optional()
|
|
953
|
+
}).strict();
|
|
954
|
+
function featureSchema(shape, defaults) {
|
|
955
|
+
const objectSchema = z.object({
|
|
956
|
+
enabled: z.boolean().default(true),
|
|
957
|
+
...shape
|
|
958
|
+
}).strict().default({
|
|
959
|
+
enabled: true,
|
|
960
|
+
...defaults
|
|
961
|
+
});
|
|
962
|
+
return z.union([z.boolean(), objectSchema]).default({
|
|
963
|
+
enabled: true,
|
|
964
|
+
...defaults
|
|
965
|
+
}).transform((value) => typeof value === "boolean" ? {
|
|
966
|
+
enabled: value,
|
|
967
|
+
...defaults
|
|
968
|
+
} : value);
|
|
969
|
+
}
|
|
970
|
+
var clarifyFeaturesConfigSchema = z.object({
|
|
971
|
+
search: featureSchema({ provider: z.literal("pagefind").default("pagefind") }, { provider: "pagefind" }),
|
|
972
|
+
repository: featureSchema(clarifyRepositoryConfigSchema.shape, {}),
|
|
973
|
+
themeEditor: featureSchema({}, {}),
|
|
974
|
+
openapi: featureSchema({ playground: z.boolean().default(true) }, { playground: true })
|
|
975
|
+
}).strict();
|
|
903
976
|
var clarifyProjectConfigSchema = z.object({
|
|
904
977
|
title: z.string().optional(),
|
|
905
978
|
description: z.string().optional(),
|
|
906
979
|
siteUrl: z.string().optional(),
|
|
907
|
-
|
|
980
|
+
routePrefix: z.string().default("/"),
|
|
981
|
+
assetPrefix: z.string().optional(),
|
|
908
982
|
logo: clarifyLogoConfigSchema.optional(),
|
|
909
983
|
homeUrl: z.string().optional(),
|
|
910
984
|
favicon: clarifyFaviconConfigSchema.optional(),
|
|
911
985
|
theme: clarifyThemeConfigSchema.optional(),
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
986
|
+
navigation: z.object({
|
|
987
|
+
links: z.array(clarifyNavbarLinkSchema).optional(),
|
|
988
|
+
tabs: clarifyTabsConfigSchema.optional()
|
|
989
|
+
}).strict().optional(),
|
|
915
990
|
banner: clarifyBannerConfigOptionsSchema.optional(),
|
|
916
991
|
footer: clarifyFooterConfigSchema.optional(),
|
|
992
|
+
locales: clarifyLocalesConfigSchema.optional(),
|
|
917
993
|
variables: clarifyVariablesConfigSchema.optional(),
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
});
|
|
994
|
+
features: clarifyFeaturesConfigSchema.optional()
|
|
995
|
+
}).strict();
|
|
921
996
|
//#endregion
|
|
922
997
|
//#region source/core/config/config.ts
|
|
923
998
|
function formatIssuePath(path) {
|
|
@@ -939,17 +1014,20 @@ function validateProjectConfig(value) {
|
|
|
939
1014
|
if (!result.success) throw new Error(formatProjectConfigError(result.error));
|
|
940
1015
|
return result.data;
|
|
941
1016
|
}
|
|
942
|
-
function
|
|
943
|
-
if (!
|
|
944
|
-
const firstLocale =
|
|
945
|
-
const defaultLocale =
|
|
1017
|
+
function resolveLocalesConfig(locales) {
|
|
1018
|
+
if (!locales) return void 0;
|
|
1019
|
+
const firstLocale = locales.locales[0]?.code;
|
|
1020
|
+
const defaultLocale = locales.default ?? firstLocale;
|
|
946
1021
|
if (!defaultLocale) return void 0;
|
|
947
1022
|
return {
|
|
948
|
-
defaultLocale,
|
|
949
|
-
missing:
|
|
950
|
-
locales:
|
|
1023
|
+
default: defaultLocale,
|
|
1024
|
+
missing: locales.missing ?? "fallback",
|
|
1025
|
+
locales: locales.locales
|
|
951
1026
|
};
|
|
952
1027
|
}
|
|
1028
|
+
function resolveFeaturesConfig(features = {}) {
|
|
1029
|
+
return clarifyFeaturesConfigSchema.parse(features);
|
|
1030
|
+
}
|
|
953
1031
|
function resolveRoutePrefix(routePrefix) {
|
|
954
1032
|
const trimmed = routePrefix?.trim();
|
|
955
1033
|
if (!trimmed || trimmed === "/") return "/";
|
|
@@ -970,26 +1048,24 @@ function resolveProjectConfig(config = {}) {
|
|
|
970
1048
|
title: config.title ?? "Clarify Docs",
|
|
971
1049
|
description: config.description ?? "",
|
|
972
1050
|
siteUrl: config.siteUrl,
|
|
973
|
-
|
|
1051
|
+
routePrefix,
|
|
1052
|
+
assetPrefix: resolveAssetPrefix(config.assetPrefix, routePrefix),
|
|
974
1053
|
logo: config.logo,
|
|
975
1054
|
homeUrl: config.homeUrl,
|
|
976
1055
|
favicon: config.favicon,
|
|
977
|
-
routePrefix,
|
|
978
|
-
assetPrefix: resolveAssetPrefix(config.assetPrefix, routePrefix),
|
|
979
1056
|
theme: resolveThemeConfig(config.theme),
|
|
980
|
-
|
|
1057
|
+
navigation: config.navigation,
|
|
981
1058
|
banner: config.banner,
|
|
982
1059
|
footer: config.footer,
|
|
1060
|
+
locales: resolveLocalesConfig(config.locales),
|
|
983
1061
|
variables: config.variables ?? {},
|
|
984
|
-
|
|
985
|
-
tabs: config.tabs
|
|
1062
|
+
features: resolveFeaturesConfig(config.features)
|
|
986
1063
|
};
|
|
987
1064
|
}
|
|
988
1065
|
//#endregion
|
|
989
1066
|
//#region source/core/config/user-config.ts
|
|
990
1067
|
function defineConfig(config) {
|
|
991
|
-
|
|
992
|
-
return config;
|
|
1068
|
+
return validateClarifyConfig(config);
|
|
993
1069
|
}
|
|
994
1070
|
/**
|
|
995
1071
|
* Config filenames Clarify CLI looks for at the project root, in resolution
|
|
@@ -1013,18 +1089,23 @@ function assertConfigObject(config, configFile) {
|
|
|
1013
1089
|
}
|
|
1014
1090
|
function loadJsonConfig(configFile) {
|
|
1015
1091
|
const config = assertConfigObject(JSON.parse(readFileSync(configFile, "utf-8")), configFile);
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1092
|
+
if ("plugins" in config) throw new Error("[clarify] clarify.json does not support plugins; use clarify.ts or clarify.js");
|
|
1093
|
+
return validateClarifyConfig(config);
|
|
1094
|
+
}
|
|
1095
|
+
function validateClarifyConfig(config) {
|
|
1096
|
+
const { plugins, ...projectConfigInput } = config;
|
|
1097
|
+
if (plugins !== void 0 && !Array.isArray(plugins)) throw new Error("[clarify] config field \"plugins\" is invalid: Expected an array");
|
|
1098
|
+
const projectConfig = validateProjectConfig(projectConfigInput);
|
|
1099
|
+
return plugins ? {
|
|
1019
1100
|
...projectConfig,
|
|
1020
|
-
|
|
1021
|
-
};
|
|
1101
|
+
plugins
|
|
1102
|
+
} : projectConfig;
|
|
1022
1103
|
}
|
|
1023
1104
|
async function loadClarifyConfig(root, env) {
|
|
1024
1105
|
const configFile = findClarifyConfigFile(root);
|
|
1025
1106
|
if (!configFile) return {};
|
|
1026
1107
|
if (configFile.endsWith(".json")) return loadJsonConfig(configFile);
|
|
1027
|
-
return assertConfigObject((await loadConfigFromFile(env, configFile, root, "silent"))?.config, configFile);
|
|
1108
|
+
return validateClarifyConfig(assertConfigObject((await loadConfigFromFile(env, configFile, root, "silent"))?.config, configFile));
|
|
1028
1109
|
}
|
|
1029
1110
|
/**
|
|
1030
1111
|
* File extensions Clarify treats as content files. Kept in sync with the
|
|
@@ -1050,9 +1131,9 @@ function buildProjectInfo(context) {
|
|
|
1050
1131
|
contentRoot: (contentRoot.startsWith(projectRoot) ? contentRoot.slice(projectRoot.length).replace(/^[/\\]+/, "") : contentRoot) || "source",
|
|
1051
1132
|
projectRoot
|
|
1052
1133
|
};
|
|
1053
|
-
if (projectConfig.
|
|
1054
|
-
|
|
1055
|
-
locales: projectConfig.
|
|
1134
|
+
if (projectConfig.locales) response.locales = {
|
|
1135
|
+
default: projectConfig.locales.default,
|
|
1136
|
+
locales: projectConfig.locales.locales.map((l) => l.code)
|
|
1056
1137
|
};
|
|
1057
1138
|
return response;
|
|
1058
1139
|
}
|
|
@@ -1112,10 +1193,23 @@ function resolveVirtualModuleId(id, modules, routes) {
|
|
|
1112
1193
|
if (route) return resolveVirtualId(route.module.virtualModuleId);
|
|
1113
1194
|
return null;
|
|
1114
1195
|
}
|
|
1115
|
-
function generateConfigModule(projectConfig,
|
|
1196
|
+
function generateConfigModule(projectConfig, version) {
|
|
1116
1197
|
const runtimeConfig = {
|
|
1117
|
-
|
|
1118
|
-
|
|
1198
|
+
title: projectConfig.title,
|
|
1199
|
+
description: projectConfig.description,
|
|
1200
|
+
siteUrl: projectConfig.siteUrl,
|
|
1201
|
+
routePrefix: projectConfig.routePrefix,
|
|
1202
|
+
assetPrefix: projectConfig.assetPrefix,
|
|
1203
|
+
logo: projectConfig.logo,
|
|
1204
|
+
homeUrl: projectConfig.homeUrl,
|
|
1205
|
+
favicon: projectConfig.favicon,
|
|
1206
|
+
theme: projectConfig.theme,
|
|
1207
|
+
navigation: projectConfig.navigation,
|
|
1208
|
+
banner: projectConfig.banner,
|
|
1209
|
+
footer: projectConfig.footer,
|
|
1210
|
+
locales: projectConfig.locales,
|
|
1211
|
+
variables: projectConfig.variables,
|
|
1212
|
+
features: projectConfig.features
|
|
1119
1213
|
};
|
|
1120
1214
|
if (version) runtimeConfig.version = version;
|
|
1121
1215
|
return `export const config = ${JSON.stringify(runtimeConfig)};`;
|
|
@@ -1207,16 +1301,10 @@ function createRuntimeSlotsModule(plugins = [], root = process.cwd()) {
|
|
|
1207
1301
|
}
|
|
1208
1302
|
return `export const runtimeSlots = {\n${[...grouped.entries()].map(([name, list]) => ` ${JSON.stringify(name)}: [\n ${list.join(",\n ")}\n ]`).join(",\n")}\n};\n`;
|
|
1209
1303
|
}
|
|
1210
|
-
function
|
|
1304
|
+
function generateContentDiagnosticModule(diagnostic) {
|
|
1211
1305
|
return `import { createContentDiagnosticComponent } from '@clarify-labs/renderer';
|
|
1212
1306
|
|
|
1213
|
-
export const contentDiagnostic = ${JSON.stringify(
|
|
1214
|
-
kind: diagnostic.kind ?? "mdx",
|
|
1215
|
-
title: diagnostic.title,
|
|
1216
|
-
message: diagnostic.message,
|
|
1217
|
-
filePath: diagnostic.filePath,
|
|
1218
|
-
details: diagnostic.details
|
|
1219
|
-
})};
|
|
1307
|
+
export const contentDiagnostic = ${JSON.stringify(diagnostic)};
|
|
1220
1308
|
|
|
1221
1309
|
export default createContentDiagnosticComponent(contentDiagnostic);
|
|
1222
1310
|
`;
|
|
@@ -1225,7 +1313,7 @@ function buildVirtualModules(args) {
|
|
|
1225
1313
|
const modules = /* @__PURE__ */ new Map();
|
|
1226
1314
|
const clientEntryModule = createClientEntryModule({ themeEditor: args.themeEditor });
|
|
1227
1315
|
const allPlugins = [...args.plugins ?? []];
|
|
1228
|
-
modules.set(VIRTUAL_CONFIG, generateConfigModule(args.projectConfig, args.
|
|
1316
|
+
modules.set(VIRTUAL_CONFIG, generateConfigModule(args.projectConfig, args.version));
|
|
1229
1317
|
modules.set(VIRTUAL_ROUTES, generateRoutesModule(args.routes, args.navigation, "client"));
|
|
1230
1318
|
modules.set(VIRTUAL_SERVER_ROUTES, generateRoutesModule(args.routes, args.navigation, "server"));
|
|
1231
1319
|
modules.set(VIRTUAL_SLOTS, createRuntimeSlotsModule(allPlugins, args.generateOptions.projectRoot));
|
|
@@ -1234,7 +1322,7 @@ function buildVirtualModules(args) {
|
|
|
1234
1322
|
modules.set(VIRTUAL_CLIENT_ENTRY, clientEntryModule);
|
|
1235
1323
|
modules.set(RESOLVED_CLIENT_ENTRY, clientEntryModule);
|
|
1236
1324
|
for (const route of args.routes) {
|
|
1237
|
-
const moduleContent = route.diagnostic ?
|
|
1325
|
+
const moduleContent = route.diagnostic ? generateContentDiagnosticModule(route.diagnostic) : `export { default } from ${moduleSpecifier(route.source.filePath)};`;
|
|
1238
1326
|
modules.set(route.module.virtualModuleId, moduleContent);
|
|
1239
1327
|
}
|
|
1240
1328
|
return modules;
|
|
@@ -1285,26 +1373,42 @@ function createNormalizedContentPlugin(engine) {
|
|
|
1285
1373
|
}
|
|
1286
1374
|
};
|
|
1287
1375
|
}
|
|
1288
|
-
function
|
|
1289
|
-
return
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1376
|
+
function createContentCompileTransform(transform, format, projectRoot, errorPolicy = () => "diagnostic") {
|
|
1377
|
+
return async function contentCompileTransform(code, id) {
|
|
1378
|
+
try {
|
|
1379
|
+
return await transform.call(this, code, id);
|
|
1380
|
+
} catch (error) {
|
|
1381
|
+
if (errorPolicy() === "throw") throw error;
|
|
1382
|
+
return {
|
|
1383
|
+
code: generateContentDiagnosticModule(createContentCompileDiagnostic({
|
|
1384
|
+
format,
|
|
1385
|
+
phase: "compilation",
|
|
1386
|
+
error,
|
|
1387
|
+
filePath: id.replace(/\?.*$/, ""),
|
|
1388
|
+
projectRoot
|
|
1389
|
+
})),
|
|
1390
|
+
map: null
|
|
1391
|
+
};
|
|
1392
|
+
}
|
|
1393
|
+
};
|
|
1297
1394
|
}
|
|
1298
|
-
function
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1395
|
+
function createContentCompilerPlugin(format, projectRoot, errorPolicy) {
|
|
1396
|
+
const markdown = format === "markdown";
|
|
1397
|
+
const plugin = mdxPlugin({
|
|
1398
|
+
include: [markdown ? "**/*.md" : "**/*.mdx"],
|
|
1399
|
+
format: markdown ? "md" : "mdx",
|
|
1302
1400
|
jsxImportSource: "react",
|
|
1303
1401
|
providerImportSource: "@clarify-labs/renderer",
|
|
1304
1402
|
remarkPlugins,
|
|
1305
|
-
remarkRehypeOptions: { allowDangerousHtml: true },
|
|
1306
|
-
rehypePlugins: [rehypeRaw, ...rehypePlugins]
|
|
1403
|
+
...markdown ? { remarkRehypeOptions: { allowDangerousHtml: true } } : {},
|
|
1404
|
+
rehypePlugins: markdown ? [rehypeRaw, ...rehypePlugins] : rehypePlugins
|
|
1307
1405
|
});
|
|
1406
|
+
const transform = typeof plugin.transform === "function" ? plugin.transform : plugin.transform?.handler;
|
|
1407
|
+
if (!transform) return plugin;
|
|
1408
|
+
return {
|
|
1409
|
+
...plugin,
|
|
1410
|
+
transform: createContentCompileTransform(transform, format, projectRoot, errorPolicy)
|
|
1411
|
+
};
|
|
1308
1412
|
}
|
|
1309
1413
|
function createClarifyViteCorePlugin(engine, normalizedContentPlugin, markdown, mdx) {
|
|
1310
1414
|
let viteConfig;
|
|
@@ -1426,13 +1530,22 @@ function createClarifyViteCorePlugin(engine, normalizedContentPlugin, markdown,
|
|
|
1426
1530
|
* site itself - it only bridges Vite lifecycle hooks to the engine.
|
|
1427
1531
|
*/
|
|
1428
1532
|
function createViteAdapter(engine) {
|
|
1533
|
+
let contentCompileErrorPolicy = "diagnostic";
|
|
1534
|
+
const errorPolicy = () => contentCompileErrorPolicy;
|
|
1429
1535
|
const normalizedContentPlugin = createNormalizedContentPlugin(engine);
|
|
1430
|
-
const markdown =
|
|
1431
|
-
const mdx =
|
|
1536
|
+
const markdown = createContentCompilerPlugin("markdown", engine.root, errorPolicy);
|
|
1537
|
+
const mdx = createContentCompilerPlugin("mdx", engine.root, errorPolicy);
|
|
1538
|
+
const compilePolicyPlugin = {
|
|
1539
|
+
name: "clarify:content-compile-policy",
|
|
1540
|
+
configResolved(config) {
|
|
1541
|
+
contentCompileErrorPolicy = config.command === "build" ? "throw" : "diagnostic";
|
|
1542
|
+
}
|
|
1543
|
+
};
|
|
1432
1544
|
const tailwind = tailwindcss();
|
|
1433
1545
|
return [
|
|
1434
1546
|
...react(),
|
|
1435
1547
|
...Array.isArray(tailwind) ? tailwind : [tailwind],
|
|
1548
|
+
compilePolicyPlugin,
|
|
1436
1549
|
normalizedContentPlugin,
|
|
1437
1550
|
createClarifyViteCorePlugin(engine, normalizedContentPlugin, markdown, mdx),
|
|
1438
1551
|
markdown,
|
|
@@ -1441,7 +1554,7 @@ function createViteAdapter(engine) {
|
|
|
1441
1554
|
}
|
|
1442
1555
|
var cliPackageVersion = {
|
|
1443
1556
|
name: "@clarify-labs/cli",
|
|
1444
|
-
version: "0.
|
|
1557
|
+
version: "0.11.0",
|
|
1445
1558
|
license: "AGPL-3.0-only",
|
|
1446
1559
|
type: "module",
|
|
1447
1560
|
repository: {
|
|
@@ -1521,8 +1634,7 @@ function resolveBuildOptions(options = {}) {
|
|
|
1521
1634
|
return {
|
|
1522
1635
|
projectRoot: options.projectRoot ?? process.cwd(),
|
|
1523
1636
|
rootDirectory: options.rootDirectory ?? "source",
|
|
1524
|
-
outputDirectory: options.outputDirectory
|
|
1525
|
-
ssg: { failOnError: options.ssg?.failOnError ?? true }
|
|
1637
|
+
outputDirectory: options.outputDirectory
|
|
1526
1638
|
};
|
|
1527
1639
|
}
|
|
1528
1640
|
//#endregion
|
|
@@ -1580,7 +1692,7 @@ function llmsTxtListItem(route, basePath) {
|
|
|
1580
1692
|
return description ? `- [${route.meta.title}](${basePath}${contentArtifactUrl}): ${description}` : `- [${route.meta.title}](${basePath}${contentArtifactUrl})`;
|
|
1581
1693
|
}
|
|
1582
1694
|
function llmsTxtLocaleLabel(locale, projectConfig) {
|
|
1583
|
-
return projectConfig.
|
|
1695
|
+
return projectConfig.locales?.locales.find((item) => item.code === locale)?.label ?? locale;
|
|
1584
1696
|
}
|
|
1585
1697
|
function groupRoutesByLocale(routes) {
|
|
1586
1698
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -1592,7 +1704,7 @@ function groupRoutesByLocale(routes) {
|
|
|
1592
1704
|
}
|
|
1593
1705
|
function groupLlmsTxtRoutesByLocale(routes, projectConfig) {
|
|
1594
1706
|
const routesBySource = /* @__PURE__ */ new Map();
|
|
1595
|
-
const defaultLocale = projectConfig.
|
|
1707
|
+
const defaultLocale = projectConfig.locales?.default;
|
|
1596
1708
|
for (const route of routes) {
|
|
1597
1709
|
const sourceKey = `${route.locale ?? defaultLocale ?? "default"}:${route.basePath ?? route.artifacts?.contentArtifactUrl ?? route.path}`;
|
|
1598
1710
|
const previousRoute = routesBySource.get(sourceKey);
|
|
@@ -1794,9 +1906,6 @@ var OPENAPI_HTTP_METHODS = [
|
|
|
1794
1906
|
"trace"
|
|
1795
1907
|
];
|
|
1796
1908
|
var CLARIFY_OPENAPI_SECTION_ID_EXTENSION = "x-clarify-section-id";
|
|
1797
|
-
function errorMessage(error) {
|
|
1798
|
-
return error instanceof Error ? error.message : String(error);
|
|
1799
|
-
}
|
|
1800
1909
|
function isSameOpenAPIFile(url, filePath) {
|
|
1801
1910
|
try {
|
|
1802
1911
|
return resolve(fileURLToPath(url)) === resolve(filePath);
|
|
@@ -1911,7 +2020,7 @@ function extractOpenAPISections(spec, filterTags) {
|
|
|
1911
2020
|
}
|
|
1912
2021
|
return sections;
|
|
1913
2022
|
}
|
|
1914
|
-
async function readOpenAPISpec(filePath, contentProcessor) {
|
|
2023
|
+
async function readOpenAPISpec(filePath, contentProcessor, projectRoot) {
|
|
1915
2024
|
try {
|
|
1916
2025
|
if (!contentProcessor) return {
|
|
1917
2026
|
ok: true,
|
|
@@ -1934,13 +2043,14 @@ async function readOpenAPISpec(filePath, contentProcessor) {
|
|
|
1934
2043
|
} catch (error) {
|
|
1935
2044
|
return {
|
|
1936
2045
|
ok: false,
|
|
1937
|
-
diagnostic: {
|
|
2046
|
+
diagnostic: createContentDiagnostic({
|
|
1938
2047
|
kind: "openapi",
|
|
1939
2048
|
title: "OpenAPI spec parse failed",
|
|
1940
|
-
message:
|
|
2049
|
+
message: "Clarify could not parse this OpenAPI specification.",
|
|
2050
|
+
error,
|
|
1941
2051
|
filePath,
|
|
1942
|
-
|
|
1943
|
-
}
|
|
2052
|
+
projectRoot
|
|
2053
|
+
})
|
|
1944
2054
|
};
|
|
1945
2055
|
}
|
|
1946
2056
|
}
|
|
@@ -1971,32 +2081,25 @@ export const routeData = {};
|
|
|
1971
2081
|
export default createOpenApiRouteComponent({ ...routeData, spec });
|
|
1972
2082
|
`;
|
|
1973
2083
|
}
|
|
1974
|
-
function generateOpenAPIErrorModule(diagnostic) {
|
|
1975
|
-
return `import { createContentDiagnosticComponent } from '@clarify-labs/renderer';
|
|
1976
|
-
|
|
1977
|
-
export const contentDiagnostic = ${JSON.stringify({
|
|
1978
|
-
kind: diagnostic.kind ?? "openapi",
|
|
1979
|
-
title: diagnostic.title,
|
|
1980
|
-
message: diagnostic.message,
|
|
1981
|
-
filePath: diagnostic.filePath,
|
|
1982
|
-
details: diagnostic.details
|
|
1983
|
-
})};
|
|
1984
|
-
|
|
1985
|
-
export default createContentDiagnosticComponent(contentDiagnostic);
|
|
1986
|
-
`;
|
|
1987
|
-
}
|
|
1988
2084
|
//#endregion
|
|
1989
2085
|
//#region source/plugins/openapi/index.ts
|
|
1990
2086
|
function collectOpenAPIPageIntents(config) {
|
|
1991
2087
|
const intents = [];
|
|
1992
|
-
function
|
|
1993
|
-
|
|
1994
|
-
|
|
2088
|
+
function visitItems(items) {
|
|
2089
|
+
for (const item of items) {
|
|
2090
|
+
if (typeof item !== "string" && "group" in item) {
|
|
2091
|
+
visitItems(item.pages);
|
|
2092
|
+
continue;
|
|
2093
|
+
}
|
|
1995
2094
|
const intent = routeIntentFromPagesItem(item);
|
|
1996
2095
|
if (intent.kind === "openapi" && (intent.path || intent.tagFilter?.length)) intents.push(intent);
|
|
1997
2096
|
}
|
|
1998
2097
|
}
|
|
1999
|
-
|
|
2098
|
+
function visitPages(pages) {
|
|
2099
|
+
if (!pages || pages === "FileTree") return;
|
|
2100
|
+
for (const group of pages) visitItems(group.pages);
|
|
2101
|
+
}
|
|
2102
|
+
for (const tab of config.navigation?.tabs ?? []) visitPages(tab.pages);
|
|
2000
2103
|
return intents;
|
|
2001
2104
|
}
|
|
2002
2105
|
function virtualModuleIdFromPath(path) {
|
|
@@ -2019,14 +2122,14 @@ function cloneOpenAPIRoute(route, overrides = {}) {
|
|
|
2019
2122
|
...overrides
|
|
2020
2123
|
};
|
|
2021
2124
|
}
|
|
2022
|
-
function findOpenAPIRoutesForContentRoot(contentRoot,
|
|
2023
|
-
if (!
|
|
2125
|
+
function findOpenAPIRoutesForContentRoot(contentRoot, locales) {
|
|
2126
|
+
if (!locales) return findOpenAPIRoutes(contentRoot);
|
|
2024
2127
|
const localizedRoutes = [];
|
|
2025
|
-
for (const locale of
|
|
2128
|
+
for (const locale of locales.locales) {
|
|
2026
2129
|
const localeRoot = join(contentRoot, locale.code);
|
|
2027
2130
|
for (const route of findOpenAPIRoutes(localeRoot, localeRoot)) {
|
|
2028
2131
|
const basePath = route.basePath ?? route.path;
|
|
2029
|
-
const path = localizedRoutePath(basePath, locale.code,
|
|
2132
|
+
const path = localizedRoutePath(basePath, locale.code, locales);
|
|
2030
2133
|
localizedRoutes.push({
|
|
2031
2134
|
...route,
|
|
2032
2135
|
path,
|
|
@@ -2036,15 +2139,15 @@ function findOpenAPIRoutesForContentRoot(contentRoot, i18n) {
|
|
|
2036
2139
|
});
|
|
2037
2140
|
}
|
|
2038
2141
|
}
|
|
2039
|
-
if (
|
|
2142
|
+
if (locales.missing === "fallback") {
|
|
2040
2143
|
const routeByLocaleAndBase = new Map(localizedRoutes.map((route) => [`${route.locale ?? ""}:${route.basePath ?? route.path}`, route]));
|
|
2041
|
-
const defaultRoutes = localizedRoutes.filter((route) => route.locale ===
|
|
2144
|
+
const defaultRoutes = localizedRoutes.filter((route) => route.locale === locales.default);
|
|
2042
2145
|
for (const sourceRoute of defaultRoutes) {
|
|
2043
2146
|
const basePath = sourceRoute.basePath ?? sourceRoute.path;
|
|
2044
|
-
for (const locale of
|
|
2147
|
+
for (const locale of locales.locales) {
|
|
2045
2148
|
const key = `${locale.code}:${basePath}`;
|
|
2046
2149
|
if (routeByLocaleAndBase.has(key)) continue;
|
|
2047
|
-
const path = localizedRoutePath(basePath, locale.code,
|
|
2150
|
+
const path = localizedRoutePath(basePath, locale.code, locales);
|
|
2048
2151
|
localizedRoutes.push(cloneOpenAPIRoute(sourceRoute, {
|
|
2049
2152
|
path,
|
|
2050
2153
|
locale: locale.code,
|
|
@@ -2071,7 +2174,7 @@ function createConfiguredOpenAPIRoutes(routes, config) {
|
|
|
2071
2174
|
const key = `${route.locale ?? ""}:${targetBasePath}`;
|
|
2072
2175
|
if (existingKeys.has(key)) continue;
|
|
2073
2176
|
existingKeys.add(key);
|
|
2074
|
-
const path = route.locale && config.
|
|
2177
|
+
const path = route.locale && config.locales ? localizedRoutePath(targetBasePath, route.locale, config.locales) : targetBasePath;
|
|
2075
2178
|
additions.push(cloneOpenAPIRoute(route, {
|
|
2076
2179
|
path,
|
|
2077
2180
|
basePath: targetBasePath,
|
|
@@ -2084,12 +2187,12 @@ function createConfiguredOpenAPIRoutes(routes, config) {
|
|
|
2084
2187
|
}
|
|
2085
2188
|
}
|
|
2086
2189
|
const nextRoutes = [...routes, ...additions];
|
|
2087
|
-
if (!config.
|
|
2088
|
-
const routesWithAlternates = nextRoutes.map((route) => withAlternates(route, nextRoutes, config.
|
|
2190
|
+
if (!config.locales) return nextRoutes;
|
|
2191
|
+
const routesWithAlternates = nextRoutes.map((route) => withAlternates(route, nextRoutes, config.locales));
|
|
2089
2192
|
const bareAliases = [];
|
|
2090
2193
|
const seenBare = new Set(routesWithAlternates.map((route) => route.path));
|
|
2091
2194
|
for (const route of routesWithAlternates) {
|
|
2092
|
-
if (route.locale !== config.
|
|
2195
|
+
if (route.locale !== config.locales.default) continue;
|
|
2093
2196
|
const basePath = route.basePath ?? route.path;
|
|
2094
2197
|
if (basePath === route.path || seenBare.has(basePath)) continue;
|
|
2095
2198
|
seenBare.add(basePath);
|
|
@@ -2128,7 +2231,7 @@ function createOpenAPIPlugin() {
|
|
|
2128
2231
|
hooks: {
|
|
2129
2232
|
"routes:discover": (input, ctx) => ({
|
|
2130
2233
|
...input,
|
|
2131
|
-
routes: [...input.routes, ...findOpenAPIRoutesForContentRoot(input.contentRoot, ctx.projectConfig.
|
|
2234
|
+
routes: [...input.routes, ...findOpenAPIRoutesForContentRoot(input.contentRoot, ctx.projectConfig.locales)]
|
|
2132
2235
|
}),
|
|
2133
2236
|
"routes:discovered": async (routes, ctx) => {
|
|
2134
2237
|
specs.clear();
|
|
@@ -2141,7 +2244,7 @@ function createOpenAPIPlugin() {
|
|
|
2141
2244
|
const result = specFromCache ? {
|
|
2142
2245
|
ok: true,
|
|
2143
2246
|
spec: specFromCache
|
|
2144
|
-
} : await readOpenAPISpec(route.source.filePath, processor);
|
|
2247
|
+
} : await readOpenAPISpec(route.source.filePath, processor, ctx.generateOptions.projectRoot);
|
|
2145
2248
|
if (!result.ok) {
|
|
2146
2249
|
route.diagnostic = result.diagnostic;
|
|
2147
2250
|
route.meta.title = route.meta.title || "OpenAPI parse error";
|
|
@@ -2188,7 +2291,7 @@ function createOpenAPIPlugin() {
|
|
|
2188
2291
|
for (const [routeSpecModuleId, spec] of specModules) modules.set(specVirtualModuleId(routeSpecModuleId), generateOpenAPISpecModule(spec));
|
|
2189
2292
|
for (const route of ctx.routes) {
|
|
2190
2293
|
if (route.kind !== "openapi") continue;
|
|
2191
|
-
if (route.diagnostic) modules.set(route.module.virtualModuleId,
|
|
2294
|
+
if (route.diagnostic) modules.set(route.module.virtualModuleId, generateContentDiagnosticModule(route.diagnostic));
|
|
2192
2295
|
else if (route.openapi?.sourceSpecId) {
|
|
2193
2296
|
const routeSpecModuleId = route.openapi.routeSpecModuleId ?? route.openapi.sourceSpecId;
|
|
2194
2297
|
if (!specModules.has(routeSpecModuleId)) continue;
|
|
@@ -2285,7 +2388,7 @@ async function generateDevSearchIndex(ctx, root, pagefind) {
|
|
|
2285
2388
|
const result = await index.addCustomRecord({
|
|
2286
2389
|
url: route.path,
|
|
2287
2390
|
content,
|
|
2288
|
-
language: toPagefindLanguage(route.locale ?? ctx.projectConfig.
|
|
2391
|
+
language: toPagefindLanguage(route.locale ?? ctx.projectConfig.locales?.default),
|
|
2289
2392
|
meta: { title: route.meta.title }
|
|
2290
2393
|
});
|
|
2291
2394
|
assertNoPagefindErrors(`addCustomRecord ${route.path}`, result.errors);
|
|
@@ -2328,6 +2431,7 @@ function createSearchIndexPlugin() {
|
|
|
2328
2431
|
name: "clarify:search-index",
|
|
2329
2432
|
hooks: {
|
|
2330
2433
|
async "dev:configureServer"(server, ctx) {
|
|
2434
|
+
if (!ctx.projectConfig.features.search.enabled) return;
|
|
2331
2435
|
const pagefind = await import("pagefind");
|
|
2332
2436
|
let currentRoot;
|
|
2333
2437
|
const staleRoots = /* @__PURE__ */ new Set();
|
|
@@ -2367,6 +2471,7 @@ function createSearchIndexPlugin() {
|
|
|
2367
2471
|
});
|
|
2368
2472
|
},
|
|
2369
2473
|
async "build:done"(ctx) {
|
|
2474
|
+
if (!ctx.projectConfig.features.search.enabled) return;
|
|
2370
2475
|
const outputDirectory = ctx.generateOptions.outputDirectory;
|
|
2371
2476
|
if (!outputDirectory) return;
|
|
2372
2477
|
const pageCount = await generatePagefindIndex({ outputRoot: resolve(ctx.generateOptions.projectRoot, outputDirectory) });
|
|
@@ -2419,16 +2524,18 @@ function createSeoPlugin() {
|
|
|
2419
2524
|
return {
|
|
2420
2525
|
name: "clarify:seo",
|
|
2421
2526
|
hooks: { "build:assets"(ctx) {
|
|
2527
|
+
const assets = [];
|
|
2422
2528
|
const sitemap = createSitemapXml(ctx.routes, ctx.projectConfig);
|
|
2423
2529
|
const robots = createRobotsTxt(ctx.projectConfig);
|
|
2424
|
-
if (
|
|
2425
|
-
return [{
|
|
2530
|
+
if (sitemap) assets.push({
|
|
2426
2531
|
fileName: "sitemap.xml",
|
|
2427
2532
|
source: sitemap
|
|
2428
|
-
}
|
|
2533
|
+
});
|
|
2534
|
+
if (robots) assets.push({
|
|
2429
2535
|
fileName: "robots.txt",
|
|
2430
2536
|
source: robots
|
|
2431
|
-
}
|
|
2537
|
+
});
|
|
2538
|
+
return assets;
|
|
2432
2539
|
} }
|
|
2433
2540
|
};
|
|
2434
2541
|
}
|
|
@@ -2444,7 +2551,8 @@ function encodePath(path) {
|
|
|
2444
2551
|
return path.split("/").filter(Boolean).map((segment) => encodeURIComponent(segment)).join("/");
|
|
2445
2552
|
}
|
|
2446
2553
|
function createSourceEditUrl(filePath, contentRoot, source) {
|
|
2447
|
-
|
|
2554
|
+
if (!source.url) return "";
|
|
2555
|
+
const repository = normalizeRepositoryUrl(source.url);
|
|
2448
2556
|
const branch = source.branch ?? "main";
|
|
2449
2557
|
const sourcePath = [source.directory ? trimSlashes(source.directory) : "", relative(contentRoot, filePath).replaceAll("\\", "/")].filter(Boolean).join("/");
|
|
2450
2558
|
return `${repository}/edit/${encodeURIComponent(branch)}/${encodePath(sourcePath)}`;
|
|
@@ -2462,7 +2570,8 @@ function createSourceLinksPlugin() {
|
|
|
2462
2570
|
return {
|
|
2463
2571
|
name: "clarify:source-links",
|
|
2464
2572
|
hooks: { "routes:discovered": (routes, ctx) => {
|
|
2465
|
-
|
|
2573
|
+
if (!ctx.projectConfig.features.repository.enabled) return routes;
|
|
2574
|
+
attachSourceEditUrls(routes, join(ctx.generateOptions.projectRoot, ctx.generateOptions.rootDirectory), ctx.projectConfig.features.repository);
|
|
2466
2575
|
return routes;
|
|
2467
2576
|
} }
|
|
2468
2577
|
};
|
|
@@ -2577,18 +2686,18 @@ async function resolveProjectContext(options = {}, env = {
|
|
|
2577
2686
|
}) {
|
|
2578
2687
|
const projectRoot = resolve(options.projectRoot ?? process.cwd());
|
|
2579
2688
|
const initialBuildOptions = resolveBuildOptions(options);
|
|
2580
|
-
const contentRoot = join(projectRoot, initialBuildOptions.rootDirectory);
|
|
2581
2689
|
const configFilePath = findClarifyConfigFile(projectRoot);
|
|
2582
2690
|
const config = configFilePath && existsSync(configFilePath) ? await loadClarifyConfig(projectRoot, env) : {};
|
|
2583
2691
|
const mergedOptions = {
|
|
2584
2692
|
...config,
|
|
2585
2693
|
...options,
|
|
2586
2694
|
projectRoot,
|
|
2587
|
-
rootDirectory: initialBuildOptions.rootDirectory,
|
|
2588
|
-
outputDirectory: initialBuildOptions.outputDirectory
|
|
2695
|
+
rootDirectory: options.rootDirectory ?? initialBuildOptions.rootDirectory,
|
|
2696
|
+
outputDirectory: options.outputDirectory ?? initialBuildOptions.outputDirectory
|
|
2589
2697
|
};
|
|
2590
2698
|
const resolvedProjectConfig = resolveProjectConfig(mergedOptions);
|
|
2591
2699
|
const resolvedBuildOptions = resolveBuildOptions(mergedOptions);
|
|
2700
|
+
const contentRoot = join(projectRoot, resolvedBuildOptions.rootDirectory);
|
|
2592
2701
|
return {
|
|
2593
2702
|
projectRoot,
|
|
2594
2703
|
contentRoot,
|
|
@@ -2678,9 +2787,9 @@ function canonicalUrl(contextOrConfig, route) {
|
|
|
2678
2787
|
/** Inject `lang` (and optional `dir`) onto the `<html>` tag for the route locale. */
|
|
2679
2788
|
function injectHtmlLocaleAttributes(html, contextOrConfig, route) {
|
|
2680
2789
|
const projectConfig = resolveProjectConfigFromContext(contextOrConfig);
|
|
2681
|
-
const localeCode = route?.locale ?? projectConfig.
|
|
2790
|
+
const localeCode = route?.locale ?? projectConfig.locales?.default;
|
|
2682
2791
|
if (!localeCode) return html;
|
|
2683
|
-
const dir = (projectConfig.
|
|
2792
|
+
const dir = (projectConfig.locales?.locales.find((locale) => locale.code === localeCode))?.dir;
|
|
2684
2793
|
return html.replace(/<html\b([^>]*)>/i, (_match, attributes) => {
|
|
2685
2794
|
let nextAttributes = attributes.replace(/\s+lang=("[^"]*"|'[^']*'|[^\s>]*)/i, "").replace(/\s+dir=("[^"]*"|'[^']*'|[^\s>]*)/i, "");
|
|
2686
2795
|
nextAttributes = `${nextAttributes} lang="${escapeHtml(localeCode)}"`;
|
|
@@ -2858,7 +2967,7 @@ async function buildSSRBundle(root, ssrEntry, ssrOutDir, plugins) {
|
|
|
2858
2967
|
}
|
|
2859
2968
|
});
|
|
2860
2969
|
}
|
|
2861
|
-
async function renderSSGRoutes(routes, contextOrConfig, outputDirectory, ssrBundlePath
|
|
2970
|
+
async function renderSSGRoutes(routes, contextOrConfig, outputDirectory, ssrBundlePath) {
|
|
2862
2971
|
const { render } = await import(pathToFileURL(ssrBundlePath).href);
|
|
2863
2972
|
const template = readIndexHtml(outputDirectory);
|
|
2864
2973
|
if (!template) throw new Error(`[clarify] index.html not found in outputDirectory "${outputDirectory}". Make sure Vite build produces it.`);
|
|
@@ -2870,7 +2979,7 @@ async function renderSSGRoutes(routes, contextOrConfig, outputDirectory, ssrBund
|
|
|
2870
2979
|
}
|
|
2871
2980
|
} catch (err) {
|
|
2872
2981
|
console.error(`[clarify] Failed to render route "${route.path}":`, err);
|
|
2873
|
-
|
|
2982
|
+
throw err;
|
|
2874
2983
|
}
|
|
2875
2984
|
}
|
|
2876
2985
|
//#endregion
|
|
@@ -2947,10 +3056,10 @@ var ClarifyContext = class {
|
|
|
2947
3056
|
this.currentPlugins = plugins;
|
|
2948
3057
|
}
|
|
2949
3058
|
get isI18n() {
|
|
2950
|
-
return Boolean(this.projectConfig.
|
|
3059
|
+
return Boolean(this.projectConfig.locales);
|
|
2951
3060
|
}
|
|
2952
3061
|
get defaultLocale() {
|
|
2953
|
-
return this.projectConfig.
|
|
3062
|
+
return this.projectConfig.locales?.default;
|
|
2954
3063
|
}
|
|
2955
3064
|
get(key) {
|
|
2956
3065
|
return this.values.get(key);
|
|
@@ -3020,6 +3129,12 @@ function loadVirtualModule(id, modules) {
|
|
|
3020
3129
|
const bareId = stripVirtualPrefix(id);
|
|
3021
3130
|
return modules.get(bareId) ?? modules.get(id) ?? null;
|
|
3022
3131
|
}
|
|
3132
|
+
function assertNoContentDiagnostics(routes) {
|
|
3133
|
+
const failures = routes.filter((route) => route.diagnostic);
|
|
3134
|
+
if (failures.length === 0) return;
|
|
3135
|
+
const summary = failures.map((route) => `- ${route.path}: ${route.diagnostic?.title ?? "Content error"}${route.diagnostic?.filePath ? ` (${route.diagnostic.filePath})` : ""}`).join("\n");
|
|
3136
|
+
throw new Error(`[clarify] Content diagnostics prevented the build:\n${summary}`);
|
|
3137
|
+
}
|
|
3023
3138
|
var ClarifyEngine = class {
|
|
3024
3139
|
options;
|
|
3025
3140
|
root;
|
|
@@ -3138,10 +3253,10 @@ var ClarifyEngine = class {
|
|
|
3138
3253
|
async discoverSite() {
|
|
3139
3254
|
const plugins = this.ctx.plugins;
|
|
3140
3255
|
const contentRoot = this.ctx.contentRoot;
|
|
3141
|
-
const {
|
|
3256
|
+
const { locales, navigation: navigationConfig } = this.ctx.projectConfig;
|
|
3142
3257
|
let routes = await runPhase(plugins, "site:discover", this.ctx, async () => {
|
|
3143
3258
|
const options = { contentProcessor: createProjectContentProcessor(plugins, this.ctx) };
|
|
3144
|
-
const discovered =
|
|
3259
|
+
const discovered = locales ? await findLocalizedContentRoutes(contentRoot, locales, options) : await findContentRoutes(contentRoot, contentRoot, options);
|
|
3145
3260
|
const result = await runHooks(plugins, "routes:discover", {
|
|
3146
3261
|
contentRoot,
|
|
3147
3262
|
routes: discovered
|
|
@@ -3170,8 +3285,9 @@ var ClarifyEngine = class {
|
|
|
3170
3285
|
};
|
|
3171
3286
|
});
|
|
3172
3287
|
});
|
|
3173
|
-
|
|
3174
|
-
|
|
3288
|
+
const tabs = navigationConfig?.tabs;
|
|
3289
|
+
routes = applyConfiguredPageRoutePaths(routes, tabs, locales);
|
|
3290
|
+
const navigation = tabs ? locales ? buildLocalizedNavigationFromTabsConfig(routes, tabs, locales) ?? {
|
|
3175
3291
|
kind: "localized-tabbed",
|
|
3176
3292
|
locales: {}
|
|
3177
3293
|
} : buildNavigationFromTabsConfig(routes, tabs) : {
|
|
@@ -3201,7 +3317,7 @@ var ClarifyEngine = class {
|
|
|
3201
3317
|
routes: this.routes,
|
|
3202
3318
|
navigation: this.navigation,
|
|
3203
3319
|
plugins: this.plugins,
|
|
3204
|
-
themeEditor: this.runtime.command === "serve" || this.runtime.themeEditor === true || this.projectConfig.
|
|
3320
|
+
themeEditor: this.runtime.command === "serve" || this.runtime.themeEditor === true || this.projectConfig.features.themeEditor.enabled,
|
|
3205
3321
|
version: this.ctx.version
|
|
3206
3322
|
});
|
|
3207
3323
|
this.virtualModules = await runHooks(this.plugins, "modules:before", this.virtualModules, this.ctx);
|
|
@@ -3244,6 +3360,7 @@ var ClarifyEngine = class {
|
|
|
3244
3360
|
await runPhase(this.plugins, "ssg", this.ctx, async () => {
|
|
3245
3361
|
if (process.env.SKIP_CLARIFY_SSG) return;
|
|
3246
3362
|
if (!await runInterceptHooks(this.plugins, "ssg:shouldRun", this.ctx)) return;
|
|
3363
|
+
assertNoContentDiagnostics(this.routes);
|
|
3247
3364
|
const outputDir = this.runtime.outputDirectory ?? this.generateOptions.outputDirectory;
|
|
3248
3365
|
if (!outputDir) throw new Error("[clarify] outputDirectory is required before SSG runs");
|
|
3249
3366
|
const ssrOutputDir = join(outputDir, ".ssr");
|
|
@@ -3257,10 +3374,10 @@ var ClarifyEngine = class {
|
|
|
3257
3374
|
plugins: this.runtime.ssrPlugins ?? []
|
|
3258
3375
|
});
|
|
3259
3376
|
const ssrBundlePath = join(ssrOutputDir, "entry-server.js");
|
|
3260
|
-
await renderSSGRoutes(this.routes, this.runtimeContext(), outputDir, ssrBundlePath
|
|
3377
|
+
await renderSSGRoutes(this.routes, this.runtimeContext(), outputDir, ssrBundlePath);
|
|
3261
3378
|
} catch (err) {
|
|
3262
3379
|
console.error("[clarify] SSG failed:", err);
|
|
3263
|
-
|
|
3380
|
+
throw err;
|
|
3264
3381
|
} finally {
|
|
3265
3382
|
if (tempEntryPath) try {
|
|
3266
3383
|
rmSync(tempEntryPath, { force: true });
|
|
@@ -3304,4 +3421,4 @@ function createClarifyEngine(options = {}) {
|
|
|
3304
3421
|
//#endregion
|
|
3305
3422
|
export { cliPackageVersion as a, defineConfig as c, createClarifyTempDir as i, createClarifyEngine as n, cliPackageVersionWithCaret as o, createClarifyRuntimeAliases as r, createViteAdapter as s, ClarifyEngine as t };
|
|
3306
3423
|
|
|
3307
|
-
//# sourceMappingURL=engine-
|
|
3424
|
+
//# sourceMappingURL=engine-DfF5RJjC.js.map
|