@clarify-labs/cli 0.9.3 → 0.9.4
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 +11 -84
- package/output/cli.cjs.map +1 -1
- package/output/cli.js +9 -82
- package/output/cli.js.map +1 -1
- package/output/core/dev-routes.d.ts +2 -2
- package/output/core/project-context.d.ts +16 -0
- package/output/core/project-info.d.ts +3 -3
- package/output/core/site.d.ts +2 -2
- package/output/core/ssg.d.ts +3 -3
- package/output/core/startup.d.ts +8 -0
- package/output/core/virtual-modules.d.ts +6 -4
- package/output/index.cjs +1 -1
- package/output/index.js +1 -1
- package/output/parsers/mdx.d.ts +7 -0
- package/output/{plugin-BUFe4vEb.cjs → plugin-Etn8ZfYN.cjs} +328 -113
- package/output/plugin-Etn8ZfYN.cjs.map +1 -0
- package/output/{plugin-poS3N83A.js → plugin-Z3fYTMcb.js} +313 -110
- package/output/plugin-Z3fYTMcb.js.map +1 -0
- package/output/plugins/openapi/virtual-modules.d.ts +1 -4
- package/output/types.d.ts +8 -2
- package/package.json +4 -4
- package/output/plugin-BUFe4vEb.cjs.map +0 -1
- package/output/plugin-poS3N83A.js.map +0 -1
|
@@ -3,6 +3,7 @@ import { dirname, extname, isAbsolute, join, relative, resolve } from "node:path
|
|
|
3
3
|
import mdxPlugin from "@mdx-js/rollup";
|
|
4
4
|
import tailwindcss from "@tailwindcss/vite";
|
|
5
5
|
import react from "@vitejs/plugin-react";
|
|
6
|
+
import { compile } from "@mdx-js/mdx";
|
|
6
7
|
import GithubSlugger, { slug } from "github-slugger";
|
|
7
8
|
import { toString } from "mdast-util-to-string";
|
|
8
9
|
import shiki from "shiki";
|
|
@@ -17,6 +18,80 @@ import { tmpdir } from "node:os";
|
|
|
17
18
|
import { z } from "zod";
|
|
18
19
|
import { build, loadConfigFromFile } from "vite";
|
|
19
20
|
import { createRequire } from "node:module";
|
|
21
|
+
var cliPackageVersion = {
|
|
22
|
+
name: "@clarify-labs/cli",
|
|
23
|
+
version: "0.9.4",
|
|
24
|
+
license: "AGPL-3.0-only",
|
|
25
|
+
type: "module",
|
|
26
|
+
repository: {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/taicode-labs/clarify",
|
|
29
|
+
"directory": "packages/cli"
|
|
30
|
+
},
|
|
31
|
+
main: "output/index.cjs",
|
|
32
|
+
module: "output/index.js",
|
|
33
|
+
types: "output/index.d.ts",
|
|
34
|
+
bin: { "clarify": "bin/clarify.js" },
|
|
35
|
+
exports: {
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./output/index.d.ts",
|
|
38
|
+
"import": "./output/index.js",
|
|
39
|
+
"require": "./output/index.cjs",
|
|
40
|
+
"default": "./output/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./package.json": "./package.json"
|
|
43
|
+
},
|
|
44
|
+
files: [
|
|
45
|
+
"LICENSE",
|
|
46
|
+
"bin",
|
|
47
|
+
"output"
|
|
48
|
+
],
|
|
49
|
+
scripts: {
|
|
50
|
+
"dev": "vite build --watch",
|
|
51
|
+
"build": "vite build",
|
|
52
|
+
"lint": "eslint source/",
|
|
53
|
+
"lint:fix": "eslint source/ --fix",
|
|
54
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
55
|
+
"test": "vitest run",
|
|
56
|
+
"test:watch": "vitest"
|
|
57
|
+
},
|
|
58
|
+
dependencies: {
|
|
59
|
+
"@apidevtools/swagger-parser": "^12.1.0",
|
|
60
|
+
"@clarify-labs/renderer": "workspace:*",
|
|
61
|
+
"@clarify-labs/templates": "workspace:*",
|
|
62
|
+
"@mdx-js/mdx": "^3.1.1",
|
|
63
|
+
"@mdx-js/rollup": "^3.1.1",
|
|
64
|
+
"@tailwindcss/vite": "^4.1.11",
|
|
65
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
66
|
+
"cac": "^7.0.0",
|
|
67
|
+
"github-slugger": "^2.0.0",
|
|
68
|
+
"gray-matter": "^4.0.3",
|
|
69
|
+
"mdast-util-to-string": "^4.0.0",
|
|
70
|
+
"mermaid": "^11.4.0",
|
|
71
|
+
"openapi-types": "^12.1.3",
|
|
72
|
+
"pagefind": "^1.5.2",
|
|
73
|
+
"react": "^19.1.0",
|
|
74
|
+
"react-dom": "^19.1.0",
|
|
75
|
+
"react-router": "^7.0.0",
|
|
76
|
+
"react-router-dom": "^7.0.0",
|
|
77
|
+
"react-zoom-pan-pinch": "^4.0.3",
|
|
78
|
+
"remark": "^15.0.1",
|
|
79
|
+
"remark-gfm": "^4.0.1",
|
|
80
|
+
"shiki": "0.14.7",
|
|
81
|
+
"unist-util-visit": "^5.1.0",
|
|
82
|
+
"vite": "^8.0.15",
|
|
83
|
+
"yaml": "^2.9.0",
|
|
84
|
+
"zod": "^4.4.3"
|
|
85
|
+
},
|
|
86
|
+
devDependencies: {
|
|
87
|
+
"@types/react": "^19.1.8",
|
|
88
|
+
"typescript": "^5.8.3",
|
|
89
|
+
"vite-plugin-dts": "^4.5.4",
|
|
90
|
+
"vitest": "^4.1.9"
|
|
91
|
+
}
|
|
92
|
+
}.version ?? "0.0.0";
|
|
93
|
+
var cliPackageVersionWithCaret = `^${cliPackageVersion}`;
|
|
94
|
+
//#endregion
|
|
20
95
|
//#region source/core/utils.ts
|
|
21
96
|
function escapeHtml(text) {
|
|
22
97
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -105,6 +180,32 @@ var rehypePlugins = [
|
|
|
105
180
|
rehypeParseCodeBlocks,
|
|
106
181
|
rehypeShiki
|
|
107
182
|
];
|
|
183
|
+
function formatMdxDiagnostic(error) {
|
|
184
|
+
if (error instanceof Error) return error.message;
|
|
185
|
+
return String(error);
|
|
186
|
+
}
|
|
187
|
+
async function compileMdxContent(content, filePath, projectRoot) {
|
|
188
|
+
try {
|
|
189
|
+
await compile(content, {
|
|
190
|
+
jsx: true,
|
|
191
|
+
providerImportSource: "@clarify-labs/renderer",
|
|
192
|
+
remarkPlugins,
|
|
193
|
+
rehypePlugins
|
|
194
|
+
});
|
|
195
|
+
return { ok: true };
|
|
196
|
+
} catch (error) {
|
|
197
|
+
return {
|
|
198
|
+
ok: false,
|
|
199
|
+
diagnostic: {
|
|
200
|
+
kind: "mdx",
|
|
201
|
+
title: "MDX syntax error",
|
|
202
|
+
message: "This page could not be compiled. Fix the MDX syntax or component usage above, then reload the route.",
|
|
203
|
+
filePath: filePath && projectRoot ? filePath.replace(projectRoot + "/", "").replace(/^\/+/, "") : filePath ? filePath.replace(/^[A-Za-z]:\//, "").replace(/^\/+/, "") : void 0,
|
|
204
|
+
details: formatMdxDiagnostic(error)
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
108
209
|
//#endregion
|
|
109
210
|
//#region source/plugins/content-artifacts/artifacts.ts
|
|
110
211
|
var UTF8_SIGNATURE = "";
|
|
@@ -553,23 +654,25 @@ async function findContentRoutes(dir, base = dir, options = {}) {
|
|
|
553
654
|
const cleanPath = ("/" + pathParts.map((p) => p === "index" ? "" : p).filter(Boolean).join("/")).replace(/\/+/g, "/").replace(/\/$/, "") || "/";
|
|
554
655
|
const source = readFileSync(fullPath, "utf-8");
|
|
555
656
|
const { frontmatter, content } = await (options.contentProcessor ?? createContentProcessor()).processMdx(source, fullPath);
|
|
657
|
+
const mdxResult = await compileMdxContent(content, fullPath, base);
|
|
556
658
|
let title = typeof frontmatter.title === "string" ? frontmatter.title : "";
|
|
557
659
|
if (!title) {
|
|
558
660
|
const lastPart = pathParts[pathParts.length - 1] ?? "";
|
|
559
661
|
title = kebabToTitle(lastPart === "index" ? pathParts.length >= 2 ? pathParts[pathParts.length - 2] : extractH1(content) : lastPart) || "Untitled";
|
|
560
662
|
}
|
|
561
663
|
routes.push({
|
|
664
|
+
kind: "mdx",
|
|
665
|
+
title,
|
|
562
666
|
path: cleanPath,
|
|
563
667
|
basePath: cleanPath,
|
|
564
668
|
filePath: fullPath,
|
|
565
669
|
virtualModuleId: "virtual:clarify-page/" + relativePath.replace(/\.mdx?$/, "").replace(/\/+/g, "/"),
|
|
566
|
-
title,
|
|
567
670
|
description: typeof frontmatter.description === "string" ? frontmatter.description : void 0,
|
|
568
671
|
keywords: frontmatterKeywords(frontmatter),
|
|
569
|
-
kind: "mdx",
|
|
570
672
|
frontmatter,
|
|
571
673
|
content,
|
|
572
|
-
sections: extractMdxSections(content)
|
|
674
|
+
sections: extractMdxSections(content),
|
|
675
|
+
diagnostic: mdxResult.ok ? void 0 : mdxResult.diagnostic
|
|
573
676
|
});
|
|
574
677
|
}
|
|
575
678
|
}
|
|
@@ -903,10 +1006,11 @@ async function readOpenAPISpec(filePath, contentProcessor) {
|
|
|
903
1006
|
return {
|
|
904
1007
|
ok: false,
|
|
905
1008
|
diagnostic: {
|
|
1009
|
+
kind: "openapi",
|
|
906
1010
|
title: "OpenAPI spec parse failed",
|
|
907
1011
|
message: `Clarify could not parse ${filePath}.`,
|
|
908
1012
|
filePath,
|
|
909
|
-
|
|
1013
|
+
details: errorMessage(error)
|
|
910
1014
|
}
|
|
911
1015
|
};
|
|
912
1016
|
}
|
|
@@ -927,17 +1031,19 @@ function resolveVirtualId(id) {
|
|
|
927
1031
|
function stripVirtualPrefix(id) {
|
|
928
1032
|
return id.startsWith("\0") ? id.slice(1) : id;
|
|
929
1033
|
}
|
|
930
|
-
function generateConfigModule(projectConfig, buildOptions) {
|
|
931
|
-
|
|
1034
|
+
function generateConfigModule(projectConfig, buildOptions, version) {
|
|
1035
|
+
const runtimeConfig = {
|
|
932
1036
|
...projectConfig,
|
|
933
1037
|
...buildOptions
|
|
934
|
-
}
|
|
1038
|
+
};
|
|
1039
|
+
if (version) runtimeConfig.version = version;
|
|
1040
|
+
return `export const config = ${JSON.stringify(runtimeConfig)};`;
|
|
935
1041
|
}
|
|
936
1042
|
function moduleSpecifier(value) {
|
|
937
1043
|
return JSON.stringify(value);
|
|
938
1044
|
}
|
|
939
1045
|
function generateRoutesModule(routes, resolvedNavigation, projectConfig, mode = "client") {
|
|
940
|
-
const imports = mode === "server" ? routes.map((r, i) => `import Page${i} from ${moduleSpecifier(r.virtualModuleId)};`).join("\n") :
|
|
1046
|
+
const imports = mode === "server" ? routes.map((r, i) => `import Page${i} from ${moduleSpecifier(r.virtualModuleId)};`).join("\n") : `import { createContentDiagnosticComponent } from '@clarify-labs/renderer';`;
|
|
941
1047
|
const routesArray = routes.map((r, i) => {
|
|
942
1048
|
const sections = r.sections && r.sections.length > 0 ? `, sections: ${JSON.stringify(r.sections.map((s) => ({
|
|
943
1049
|
id: s.id,
|
|
@@ -955,7 +1061,7 @@ function generateRoutesModule(routes, resolvedNavigation, projectConfig, mode =
|
|
|
955
1061
|
const description = r.description ? `, description: ${JSON.stringify(r.description)}` : "";
|
|
956
1062
|
const keywords = r.keywords && r.keywords.length > 0 ? `, keywords: ${JSON.stringify(r.keywords)}` : "";
|
|
957
1063
|
const sourceUrl = r.sourceUrl ? `, sourceUrl: ${JSON.stringify(r.sourceUrl)}` : "";
|
|
958
|
-
const component = mode === "server" ? `Page${i}` : `() => import(${moduleSpecifier(r.virtualModuleId)})`;
|
|
1064
|
+
const component = mode === "server" ? `Page${i}` : `() => import(${moduleSpecifier(r.virtualModuleId)}).catch((error) => Promise.resolve({ default: createContentDiagnosticComponent({ kind: 'route-load', title: 'This page could not be loaded', message: error instanceof Error ? error.message : String(error), details: error instanceof Error ? error.stack : undefined }) }))`;
|
|
959
1065
|
const lazy = mode === "client" ? ", lazy: true" : "";
|
|
960
1066
|
return ` { path: ${JSON.stringify(r.path)}, title: ${JSON.stringify(r.title)}, component: ${component}${lazy}, kind: ${JSON.stringify(r.kind)}${basePath}${locale}${isFallback}${isBareAlias}${alternates}${description}${keywords}${sections}${contentArtifactUrl}${sourceUrl} }`;
|
|
961
1067
|
}).join(",\n");
|
|
@@ -1014,11 +1120,25 @@ function createRuntimeSlotsModule(plugins = [], root = process.cwd()) {
|
|
|
1014
1120
|
function createSlotModule() {
|
|
1015
1121
|
return `export { useSlot } from '@clarify-labs/renderer';\n`;
|
|
1016
1122
|
}
|
|
1123
|
+
function generateMdxErrorModule(diagnostic) {
|
|
1124
|
+
return `import { createContentDiagnosticComponent } from '@clarify-labs/renderer';
|
|
1125
|
+
|
|
1126
|
+
export const contentDiagnostic = ${JSON.stringify({
|
|
1127
|
+
kind: diagnostic.kind ?? "mdx",
|
|
1128
|
+
title: diagnostic.title,
|
|
1129
|
+
message: diagnostic.message,
|
|
1130
|
+
filePath: diagnostic.filePath,
|
|
1131
|
+
details: diagnostic.details
|
|
1132
|
+
})};
|
|
1133
|
+
|
|
1134
|
+
export default createContentDiagnosticComponent(contentDiagnostic);
|
|
1135
|
+
`;
|
|
1136
|
+
}
|
|
1017
1137
|
function buildVirtualModules(args) {
|
|
1018
1138
|
const modules = /* @__PURE__ */ new Map();
|
|
1019
1139
|
const clientEntryModule = createClientEntryModule({ themeEditor: args.themeEditor });
|
|
1020
1140
|
const allPlugins = [...args.plugins ?? []];
|
|
1021
|
-
modules.set(VIRTUAL_CONFIG, generateConfigModule(args.projectConfig, args.generateOptions));
|
|
1141
|
+
modules.set(VIRTUAL_CONFIG, generateConfigModule(args.projectConfig, args.generateOptions, args.version));
|
|
1022
1142
|
modules.set(VIRTUAL_ROUTES, generateRoutesModule(args.routes, args.navigation, args.projectConfig, "client"));
|
|
1023
1143
|
modules.set(VIRTUAL_SERVER_ROUTES, generateRoutesModule(args.routes, args.navigation, args.projectConfig, "server"));
|
|
1024
1144
|
modules.set(VIRTUAL_SLOTS, createRuntimeSlotsModule(allPlugins, args.generateOptions.projectRoot));
|
|
@@ -1026,7 +1146,10 @@ function buildVirtualModules(args) {
|
|
|
1026
1146
|
modules.set(VIRTUAL_SLOT, createSlotModule());
|
|
1027
1147
|
modules.set(VIRTUAL_CLIENT_ENTRY, clientEntryModule);
|
|
1028
1148
|
modules.set(RESOLVED_CLIENT_ENTRY, clientEntryModule);
|
|
1029
|
-
for (const route of args.routes)
|
|
1149
|
+
for (const route of args.routes) {
|
|
1150
|
+
const moduleContent = route.diagnostic ? generateMdxErrorModule(route.diagnostic) : `export { default } from ${moduleSpecifier(route.filePath)};`;
|
|
1151
|
+
modules.set(route.virtualModuleId, moduleContent);
|
|
1152
|
+
}
|
|
1030
1153
|
return modules;
|
|
1031
1154
|
}
|
|
1032
1155
|
function generateOpenApiModule() {
|
|
@@ -1047,53 +1170,29 @@ function generateOpenAPISpecModule(spec) {
|
|
|
1047
1170
|
return `export default ${JSON.stringify(spec)};`;
|
|
1048
1171
|
}
|
|
1049
1172
|
function generateOpenAPIPageModule(opts) {
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
` return loadPromise;`,
|
|
1060
|
-
`}`,
|
|
1061
|
-
`export default function OpenApiRoutePage() {`,
|
|
1062
|
-
` const specs = useOpenApis();`,
|
|
1063
|
-
` const serverSpec = specs[SPEC_KEY];`,
|
|
1064
|
-
` const [spec, setSpec] = useState(serverSpec || null);`,
|
|
1065
|
-
` const mountedRef = useRef(false);`,
|
|
1066
|
-
` useEffect(function() {`,
|
|
1067
|
-
` if (mountedRef.current) return;`,
|
|
1068
|
-
` mountedRef.current = true;`,
|
|
1069
|
-
` if (spec) return;`,
|
|
1070
|
-
` loadSpec().then(setSpec);`,
|
|
1071
|
-
` }, []);`,
|
|
1072
|
-
` if (!spec) return null;`,
|
|
1073
|
-
` return createElement(OpenApiDocument, { spec: spec, tagFilter: TAG_FILTER });`,
|
|
1074
|
-
`}`
|
|
1075
|
-
].join("\n");
|
|
1173
|
+
return `import { createOpenApiRouteComponent } from '@clarify-labs/renderer';
|
|
1174
|
+
|
|
1175
|
+
export const routeData = ${JSON.stringify({
|
|
1176
|
+
spec: opts.spec,
|
|
1177
|
+
tagFilter: opts.tagFilter
|
|
1178
|
+
})};
|
|
1179
|
+
|
|
1180
|
+
export default createOpenApiRouteComponent(routeData);
|
|
1181
|
+
`;
|
|
1076
1182
|
}
|
|
1077
1183
|
function generateOpenAPIErrorModule(diagnostic) {
|
|
1078
|
-
return `import {
|
|
1079
|
-
|
|
1080
|
-
export
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
diagnostic.cause ? createElement('div', { className: 'not-prose mt-4 rounded-lg border border-red-200 bg-red-50 p-4 text-sm text-red-800 dark:border-red-500/30 dark:bg-red-500/10 dark:text-red-200' },
|
|
1091
|
-
createElement('div', { className: 'mb-1 font-semibold' }, 'Why it happened'),
|
|
1092
|
-
createElement('pre', { className: 'whitespace-pre-wrap break-words text-xs' }, diagnostic.cause)
|
|
1093
|
-
) : null
|
|
1094
|
-
)
|
|
1095
|
-
);
|
|
1096
|
-
}`;
|
|
1184
|
+
return `import { createContentDiagnosticComponent } from '@clarify-labs/renderer';
|
|
1185
|
+
|
|
1186
|
+
export const contentDiagnostic = ${JSON.stringify({
|
|
1187
|
+
kind: diagnostic.kind ?? "openapi",
|
|
1188
|
+
title: diagnostic.title,
|
|
1189
|
+
message: diagnostic.message,
|
|
1190
|
+
filePath: diagnostic.filePath,
|
|
1191
|
+
details: diagnostic.details
|
|
1192
|
+
})};
|
|
1193
|
+
|
|
1194
|
+
export default createContentDiagnosticComponent(contentDiagnostic);
|
|
1195
|
+
`;
|
|
1097
1196
|
}
|
|
1098
1197
|
//#endregion
|
|
1099
1198
|
//#region source/plugins/openapi/index.ts
|
|
@@ -1199,11 +1298,10 @@ function createOpenAPIPlugin() {
|
|
|
1199
1298
|
if (route.kind !== "openapi") continue;
|
|
1200
1299
|
if (route.diagnostic) modules.set(route.virtualModuleId, generateOpenAPIErrorModule(route.diagnostic));
|
|
1201
1300
|
else if (route.specFileKey) {
|
|
1202
|
-
const
|
|
1203
|
-
|
|
1301
|
+
const entry = specs.get(route.specFileKey);
|
|
1302
|
+
if (!entry) continue;
|
|
1204
1303
|
modules.set(route.virtualModuleId, generateOpenAPIPageModule({
|
|
1205
|
-
|
|
1206
|
-
specRegistryKey,
|
|
1304
|
+
spec: entry.spec,
|
|
1207
1305
|
tagFilter: route.openapiTagFilter
|
|
1208
1306
|
}));
|
|
1209
1307
|
}
|
|
@@ -1871,7 +1969,7 @@ function readJsonBody(req) {
|
|
|
1871
1969
|
* Handle a request to the dev route endpoint. Pure function — does not touch
|
|
1872
1970
|
* the network directly, only reads the request body and writes to `res`.
|
|
1873
1971
|
*/
|
|
1874
|
-
async function handleDevRouteRequest(req, res, routes,
|
|
1972
|
+
async function handleDevRouteRequest(req, res, routes, context) {
|
|
1875
1973
|
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
1876
1974
|
let body;
|
|
1877
1975
|
try {
|
|
@@ -1883,12 +1981,12 @@ async function handleDevRouteRequest(req, res, routes, projectConfig, contentRoo
|
|
|
1883
1981
|
}
|
|
1884
1982
|
const file = typeof body === "object" && body !== null ? body.file : void 0;
|
|
1885
1983
|
if (typeof file === "string" && file.length > 0) {
|
|
1886
|
-
const route = resolveRouteForFile(file, routes, projectConfig.i18n?.defaultLocale);
|
|
1984
|
+
const route = resolveRouteForFile(file, routes, context.projectConfig.i18n?.defaultLocale);
|
|
1887
1985
|
if (route) {
|
|
1888
1986
|
res.end(JSON.stringify(toDevRouteEntry(route)));
|
|
1889
1987
|
return;
|
|
1890
1988
|
}
|
|
1891
|
-
const inferred = inferRouteForFile(file, contentRoot, projectConfig.i18n?.defaultLocale);
|
|
1989
|
+
const inferred = inferRouteForFile(file, context.contentRoot, context.projectConfig.i18n?.defaultLocale);
|
|
1892
1990
|
res.end(JSON.stringify(inferred));
|
|
1893
1991
|
return;
|
|
1894
1992
|
}
|
|
@@ -1911,18 +2009,6 @@ declare module 'virtual:clarify/slot' {
|
|
|
1911
2009
|
|
|
1912
2010
|
export function useSlot(): SlotContext
|
|
1913
2011
|
}
|
|
1914
|
-
|
|
1915
|
-
declare module 'virtual:clarify/slots' {
|
|
1916
|
-
import type { ComponentType } from 'react'
|
|
1917
|
-
|
|
1918
|
-
export type RuntimeSlotEntry = {
|
|
1919
|
-
plugin: string
|
|
1920
|
-
/** Lazy import factory — yields the default-exported React component. */
|
|
1921
|
-
component: () => Promise<{ default: ComponentType }>
|
|
1922
|
-
}
|
|
1923
|
-
|
|
1924
|
-
export const runtimeSlots: Record<string, RuntimeSlotEntry[]>
|
|
1925
|
-
}
|
|
1926
2012
|
`;
|
|
1927
2013
|
function generateClarifyEnvDts(_plugins) {
|
|
1928
2014
|
return CLARIFY_ENV_TEMPLATE;
|
|
@@ -1993,6 +2079,48 @@ async function loadClarifyConfig(root, env) {
|
|
|
1993
2079
|
if (configFile.endsWith(".json")) return loadJsonConfig(configFile);
|
|
1994
2080
|
return assertConfigObject((await loadConfigFromFile(env, configFile, root, "silent"))?.config, configFile);
|
|
1995
2081
|
}
|
|
2082
|
+
//#endregion
|
|
2083
|
+
//#region source/core/project-context.ts
|
|
2084
|
+
async function resolveProjectContext(options = {}, env = {
|
|
2085
|
+
command: "build",
|
|
2086
|
+
mode: "production"
|
|
2087
|
+
}) {
|
|
2088
|
+
const projectRoot = resolve(options.projectRoot ?? process.cwd());
|
|
2089
|
+
const initialBuildOptions = resolveBuildOptions(options);
|
|
2090
|
+
const contentRoot = join(projectRoot, initialBuildOptions.rootDirectory);
|
|
2091
|
+
const configFilePath = findClarifyConfigFile(projectRoot);
|
|
2092
|
+
const config = configFilePath && existsSync(configFilePath) ? await loadClarifyConfig(projectRoot, env) : {};
|
|
2093
|
+
const mergedOptions = {
|
|
2094
|
+
...config,
|
|
2095
|
+
...options,
|
|
2096
|
+
projectRoot,
|
|
2097
|
+
rootDirectory: initialBuildOptions.rootDirectory,
|
|
2098
|
+
outputDirectory: initialBuildOptions.outputDirectory
|
|
2099
|
+
};
|
|
2100
|
+
const resolvedProjectConfig = resolveProjectConfig(mergedOptions);
|
|
2101
|
+
const resolvedBuildOptions = resolveBuildOptions(mergedOptions);
|
|
2102
|
+
const projectContext = {
|
|
2103
|
+
projectRoot,
|
|
2104
|
+
contentRoot,
|
|
2105
|
+
version: cliPackageVersion,
|
|
2106
|
+
projectConfig: resolvedProjectConfig,
|
|
2107
|
+
generateOptions: resolvedBuildOptions
|
|
2108
|
+
};
|
|
2109
|
+
return {
|
|
2110
|
+
projectRoot,
|
|
2111
|
+
contentRoot,
|
|
2112
|
+
configFilePath,
|
|
2113
|
+
projectConfig: resolvedProjectConfig,
|
|
2114
|
+
buildOptions: resolvedBuildOptions,
|
|
2115
|
+
config,
|
|
2116
|
+
hookContext: {
|
|
2117
|
+
...projectContext,
|
|
2118
|
+
routes: [],
|
|
2119
|
+
navigation: []
|
|
2120
|
+
},
|
|
2121
|
+
projectContext
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
1996
2124
|
/**
|
|
1997
2125
|
* File extensions Clarify treats as content files. Kept in sync with the
|
|
1998
2126
|
* patterns used by route discovery in `parsers/routes.ts` and the OpenAPI
|
|
@@ -2009,7 +2137,8 @@ var CONTENT_FILE_EXTENSIONS = [
|
|
|
2009
2137
|
/**
|
|
2010
2138
|
* Build the project-info response payload from the resolved plugin state.
|
|
2011
2139
|
*/
|
|
2012
|
-
function buildProjectInfo(
|
|
2140
|
+
function buildProjectInfo(context) {
|
|
2141
|
+
const { projectRoot, contentRoot, projectConfig } = context;
|
|
2013
2142
|
const response = {
|
|
2014
2143
|
configFilenames: CONFIG_FILENAMES,
|
|
2015
2144
|
contentFileExtensions: CONTENT_FILE_EXTENSIONS,
|
|
@@ -2026,9 +2155,9 @@ function buildProjectInfo(projectRoot, contentRoot, projectConfig) {
|
|
|
2026
2155
|
* Handle a request to the project-info endpoint. Responds to any method
|
|
2027
2156
|
* (GET is typical) with the JSON payload — there is no request body to parse.
|
|
2028
2157
|
*/
|
|
2029
|
-
function handleProjectInfoRequest(_req, res,
|
|
2158
|
+
function handleProjectInfoRequest(_req, res, context) {
|
|
2030
2159
|
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
2031
|
-
res.end(JSON.stringify(buildProjectInfo(
|
|
2160
|
+
res.end(JSON.stringify(buildProjectInfo(context)));
|
|
2032
2161
|
}
|
|
2033
2162
|
//#endregion
|
|
2034
2163
|
//#region source/core/site.ts
|
|
@@ -2091,16 +2220,18 @@ async function discoverRoutes(root, contentRoot, plugins, ctx) {
|
|
|
2091
2220
|
return [...routesWithAlternates, ...bareRoutes];
|
|
2092
2221
|
}
|
|
2093
2222
|
async function resolveClarifySite(options = {}, resolveOptions = {}) {
|
|
2094
|
-
const
|
|
2095
|
-
const
|
|
2096
|
-
const
|
|
2097
|
-
const
|
|
2223
|
+
const context = await resolveProjectContext(options);
|
|
2224
|
+
const root = context.projectRoot;
|
|
2225
|
+
const projectConfig = context.projectConfig;
|
|
2226
|
+
const generateOptions = context.buildOptions;
|
|
2227
|
+
const contentRoot = context.contentRoot;
|
|
2098
2228
|
const plugins = [...createBuiltinPlugins({ htmlShell: resolveOptions.includeHtmlShellPlugin }), ...options.plugins ?? []];
|
|
2099
2229
|
const ctx = {
|
|
2230
|
+
...context.hookContext,
|
|
2231
|
+
projectRoot: root,
|
|
2232
|
+
contentRoot,
|
|
2100
2233
|
projectConfig,
|
|
2101
|
-
generateOptions
|
|
2102
|
-
routes: [],
|
|
2103
|
-
navigation: []
|
|
2234
|
+
generateOptions
|
|
2104
2235
|
};
|
|
2105
2236
|
setProjectContentProcessor(ctx, createProjectContentProcessor(plugins, ctx));
|
|
2106
2237
|
let routes = await discoverRoutes(root, contentRoot, plugins, ctx);
|
|
@@ -2198,7 +2329,11 @@ function readIndexHtml(outputDirectory) {
|
|
|
2198
2329
|
return;
|
|
2199
2330
|
}
|
|
2200
2331
|
}
|
|
2201
|
-
function
|
|
2332
|
+
function resolveProjectConfigFromContext(contextOrConfig) {
|
|
2333
|
+
return "projectConfig" in contextOrConfig ? contextOrConfig.projectConfig : contextOrConfig;
|
|
2334
|
+
}
|
|
2335
|
+
function injectHtmlLocaleAttributes(html, contextOrConfig, route) {
|
|
2336
|
+
const projectConfig = resolveProjectConfigFromContext(contextOrConfig);
|
|
2202
2337
|
const localeCode = route?.locale ?? projectConfig.i18n?.defaultLocale;
|
|
2203
2338
|
if (!localeCode) return html;
|
|
2204
2339
|
const dir = (projectConfig.i18n?.locales.find((locale) => locale.code === localeCode))?.dir;
|
|
@@ -2209,7 +2344,8 @@ function injectHtmlLocaleAttributes(html, projectConfig, route) {
|
|
|
2209
2344
|
return `<html${nextAttributes}>`;
|
|
2210
2345
|
});
|
|
2211
2346
|
}
|
|
2212
|
-
function routeTitle(
|
|
2347
|
+
function routeTitle(contextOrConfig, route) {
|
|
2348
|
+
const projectConfig = resolveProjectConfigFromContext(contextOrConfig);
|
|
2213
2349
|
const title = route?.title?.trim();
|
|
2214
2350
|
if (!title || title === projectConfig.title) return projectConfig.title;
|
|
2215
2351
|
return `${title} - ${projectConfig.title}`;
|
|
@@ -2221,24 +2357,26 @@ function setNamedMeta(html, name, content) {
|
|
|
2221
2357
|
if (metaPattern.test(html)) return html.replace(metaPattern, meta);
|
|
2222
2358
|
return html.replace("</head>", ` ${meta}\n </head>`);
|
|
2223
2359
|
}
|
|
2224
|
-
function canonicalUrl(
|
|
2360
|
+
function canonicalUrl(contextOrConfig, route) {
|
|
2361
|
+
const projectConfig = resolveProjectConfigFromContext(contextOrConfig);
|
|
2225
2362
|
if (!projectConfig.siteUrl || !route.alternates || !route.locale) return void 0;
|
|
2226
2363
|
const prefixedPath = route.alternates[route.locale];
|
|
2227
2364
|
if (!prefixedPath || prefixedPath === route.path) return void 0;
|
|
2228
2365
|
return `${projectConfig.siteUrl.replace(/\/+$/, "")}${!projectConfig.routePrefix || projectConfig.routePrefix === "/" ? "" : `/${projectConfig.routePrefix.replace(/^\/+|\/+$/g, "")}`}${prefixedPath}`;
|
|
2229
2366
|
}
|
|
2230
|
-
function injectCanonicalUrl(html,
|
|
2231
|
-
const url = route ? canonicalUrl(
|
|
2367
|
+
function injectCanonicalUrl(html, contextOrConfig, route) {
|
|
2368
|
+
const url = route ? canonicalUrl(contextOrConfig, route) : void 0;
|
|
2232
2369
|
html = html.replace(/<link\b[^>]*\brel=["']canonical["'][^>]*\/?>\n?/gi, "");
|
|
2233
2370
|
if (!url) return html;
|
|
2234
2371
|
return html.replace("</head>", ` <link rel="canonical" href="${escapeHtml(url)}" />\n </head>`);
|
|
2235
2372
|
}
|
|
2236
|
-
function injectSSRIntoTemplate(template, appHtml,
|
|
2237
|
-
|
|
2238
|
-
html =
|
|
2373
|
+
function injectSSRIntoTemplate(template, appHtml, contextOrConfig, route) {
|
|
2374
|
+
const projectConfig = resolveProjectConfigFromContext(contextOrConfig);
|
|
2375
|
+
let html = injectHtmlLocaleAttributes(template, contextOrConfig, route);
|
|
2376
|
+
html = html.replace(/<title>.*?<\/title>/, `<title>${escapeHtml(routeTitle(contextOrConfig, route))}</title>`);
|
|
2239
2377
|
html = setNamedMeta(html, "description", route?.description ?? projectConfig.description);
|
|
2240
2378
|
html = setNamedMeta(html, "keywords", route?.keywords?.join(", "));
|
|
2241
|
-
html = injectCanonicalUrl(html,
|
|
2379
|
+
html = injectCanonicalUrl(html, contextOrConfig, route);
|
|
2242
2380
|
const dataPagefindIgnore = route?.isBareAlias ? " data-pagefind-ignore" : "";
|
|
2243
2381
|
html = html.replace(/<div id="root">([\s\S]*?)<\/div>/, `<div id="root"${dataPagefindIgnore}>${appHtml}</div>`);
|
|
2244
2382
|
return html;
|
|
@@ -2290,12 +2428,12 @@ async function buildSSRBundle(root, ssrEntry, ssrOutDir, plugins) {
|
|
|
2290
2428
|
}
|
|
2291
2429
|
});
|
|
2292
2430
|
}
|
|
2293
|
-
async function renderSSGRoutes(routes,
|
|
2431
|
+
async function renderSSGRoutes(routes, contextOrConfig, outputDirectory, ssrBundlePath, failOnError = true) {
|
|
2294
2432
|
const { render } = await import(pathToFileURL(ssrBundlePath).href);
|
|
2295
2433
|
const template = readIndexHtml(outputDirectory);
|
|
2296
2434
|
if (!template) throw new Error(`[clarify] index.html not found in outputDirectory "${outputDirectory}". Make sure Vite build produces it.`);
|
|
2297
2435
|
for (const route of routes) try {
|
|
2298
|
-
const finalHtml = injectSSRIntoTemplate(template, await render(route.path),
|
|
2436
|
+
const finalHtml = injectSSRIntoTemplate(template, await render(route.path), contextOrConfig, route);
|
|
2299
2437
|
for (const outFile of routeOutputFiles(outputDirectory, route)) {
|
|
2300
2438
|
mkdirSync(dirname(outFile), { recursive: true });
|
|
2301
2439
|
writeFileSync(outFile, finalHtml, "utf-8");
|
|
@@ -2306,6 +2444,33 @@ async function renderSSGRoutes(routes, projectConfig, outputDirectory, ssrBundle
|
|
|
2306
2444
|
}
|
|
2307
2445
|
}
|
|
2308
2446
|
//#endregion
|
|
2447
|
+
//#region source/core/startup.ts
|
|
2448
|
+
function contentDirectoryLabel(projectRoot, contentRoot) {
|
|
2449
|
+
const relativePath = relative(projectRoot, contentRoot);
|
|
2450
|
+
return relativePath && relativePath !== "." ? relativePath : "source";
|
|
2451
|
+
}
|
|
2452
|
+
function contentFileExampleLabel(projectRoot, contentRoot) {
|
|
2453
|
+
const label = contentDirectoryLabel(projectRoot, contentRoot);
|
|
2454
|
+
return label === "." ? "index.mdx" : `${label}/index.mdx`;
|
|
2455
|
+
}
|
|
2456
|
+
function getStartupHints(options) {
|
|
2457
|
+
const hints = [];
|
|
2458
|
+
if (!options.contentDirExists) {
|
|
2459
|
+
const label = contentDirectoryLabel(options.projectRoot, options.contentRoot);
|
|
2460
|
+
hints.push(`Content directory "${label}" was not found. Create it or pass --content <dir> to point Clarify at a different directory.`);
|
|
2461
|
+
} else if (!options.hasRoutes) {
|
|
2462
|
+
const example = contentFileExampleLabel(options.projectRoot, options.contentRoot);
|
|
2463
|
+
hints.push(`No content pages were found yet. Add ${example} to get started.`);
|
|
2464
|
+
}
|
|
2465
|
+
return hints;
|
|
2466
|
+
}
|
|
2467
|
+
function logStartupHints(options) {
|
|
2468
|
+
const hints = getStartupHints(options);
|
|
2469
|
+
if (hints.length === 0) return;
|
|
2470
|
+
const message = hints.map((hint) => `[clarify] ${hint}`).join("\n");
|
|
2471
|
+
console.warn(message);
|
|
2472
|
+
}
|
|
2473
|
+
//#endregion
|
|
2309
2474
|
//#region source/core/plugin.ts
|
|
2310
2475
|
function loadVirtualModule(id, modules) {
|
|
2311
2476
|
const bareId = stripVirtualPrefix(id);
|
|
@@ -2315,13 +2480,23 @@ function clarifyPlugin(options = {}) {
|
|
|
2315
2480
|
const root = resolve(options.projectRoot ?? process.cwd());
|
|
2316
2481
|
let projectConfig = resolveProjectConfig(options);
|
|
2317
2482
|
let generateOptions = resolveBuildOptions(options);
|
|
2318
|
-
|
|
2483
|
+
let contentRoot = join(root, generateOptions.rootDirectory);
|
|
2484
|
+
let runtimeContext = {
|
|
2485
|
+
projectRoot: root,
|
|
2486
|
+
contentRoot,
|
|
2487
|
+
projectConfig,
|
|
2488
|
+
generateOptions,
|
|
2489
|
+
version: cliPackageVersion
|
|
2490
|
+
};
|
|
2319
2491
|
const configFilePath = findClarifyConfigFile(root);
|
|
2320
2492
|
let routes = [];
|
|
2321
2493
|
let clarifyPlugins = [...createBuiltinPlugins(), ...options.plugins ?? []];
|
|
2322
2494
|
const ctx = {
|
|
2495
|
+
projectRoot: root,
|
|
2496
|
+
contentRoot,
|
|
2323
2497
|
projectConfig,
|
|
2324
2498
|
generateOptions,
|
|
2499
|
+
version: cliPackageVersion,
|
|
2325
2500
|
routes,
|
|
2326
2501
|
navigation: []
|
|
2327
2502
|
};
|
|
@@ -2332,11 +2507,22 @@ function clarifyPlugin(options = {}) {
|
|
|
2332
2507
|
const site = await resolveClarifySite(overrides ?? options);
|
|
2333
2508
|
projectConfig = site.projectConfig;
|
|
2334
2509
|
generateOptions = site.generateOptions;
|
|
2510
|
+
contentRoot = join(root, generateOptions.rootDirectory);
|
|
2511
|
+
runtimeContext = {
|
|
2512
|
+
projectRoot: root,
|
|
2513
|
+
contentRoot,
|
|
2514
|
+
projectConfig,
|
|
2515
|
+
generateOptions,
|
|
2516
|
+
version: cliPackageVersion
|
|
2517
|
+
};
|
|
2335
2518
|
routes = site.routes;
|
|
2336
2519
|
resolvedNavigation = site.navigation;
|
|
2337
2520
|
clarifyPlugins = site.plugins;
|
|
2521
|
+
ctx.projectRoot = root;
|
|
2522
|
+
ctx.contentRoot = contentRoot;
|
|
2338
2523
|
ctx.projectConfig = projectConfig;
|
|
2339
2524
|
ctx.generateOptions = generateOptions;
|
|
2525
|
+
ctx.version = cliPackageVersion;
|
|
2340
2526
|
ctx.routes = routes;
|
|
2341
2527
|
ctx.navigation = resolvedNavigation;
|
|
2342
2528
|
}
|
|
@@ -2347,7 +2533,8 @@ function clarifyPlugin(options = {}) {
|
|
|
2347
2533
|
routes,
|
|
2348
2534
|
navigation: resolvedNavigation,
|
|
2349
2535
|
plugins: clarifyPlugins,
|
|
2350
|
-
themeEditor: viteConfig.command === "serve" || projectConfig.theme.editor
|
|
2536
|
+
themeEditor: viteConfig.command === "serve" || projectConfig.theme.editor,
|
|
2537
|
+
version: ctx.version
|
|
2351
2538
|
});
|
|
2352
2539
|
virtualModules = await runHooks(clarifyPlugins, "modules:before", virtualModules, ctx);
|
|
2353
2540
|
}
|
|
@@ -2395,6 +2582,12 @@ function clarifyPlugin(options = {}) {
|
|
|
2395
2582
|
name: "clarify:core",
|
|
2396
2583
|
async config() {
|
|
2397
2584
|
await resolveRoutesAndSpecs();
|
|
2585
|
+
logStartupHints({
|
|
2586
|
+
projectRoot: root,
|
|
2587
|
+
contentRoot,
|
|
2588
|
+
contentDirExists: existsSync(contentRoot),
|
|
2589
|
+
hasRoutes: routes.length > 0
|
|
2590
|
+
});
|
|
2398
2591
|
return {
|
|
2399
2592
|
base: projectConfig.assetPrefix,
|
|
2400
2593
|
build: {
|
|
@@ -2414,14 +2607,23 @@ function clarifyPlugin(options = {}) {
|
|
|
2414
2607
|
async handleHotUpdate(ctx) {
|
|
2415
2608
|
const changedFile = isAbsolute(ctx.file) ? ctx.file : join(root, ctx.file);
|
|
2416
2609
|
if (configFilePath && changedFile === configFilePath) {
|
|
2417
|
-
await
|
|
2418
|
-
...
|
|
2419
|
-
|
|
2420
|
-
mode: viteConfig.mode
|
|
2421
|
-
}),
|
|
2422
|
-
projectRoot: options.projectRoot,
|
|
2610
|
+
const newContext = await resolveProjectContext({
|
|
2611
|
+
...options,
|
|
2612
|
+
projectRoot: root,
|
|
2423
2613
|
rootDirectory: options.rootDirectory,
|
|
2424
2614
|
outputDirectory: options.outputDirectory
|
|
2615
|
+
}, {
|
|
2616
|
+
command: "serve",
|
|
2617
|
+
mode: viteConfig.mode
|
|
2618
|
+
});
|
|
2619
|
+
projectConfig = newContext.projectConfig;
|
|
2620
|
+
generateOptions = newContext.buildOptions;
|
|
2621
|
+
contentRoot = newContext.contentRoot;
|
|
2622
|
+
await resolveRoutesAndSpecs({
|
|
2623
|
+
...newContext.config,
|
|
2624
|
+
projectRoot: newContext.projectRoot,
|
|
2625
|
+
rootDirectory: newContext.buildOptions.rootDirectory,
|
|
2626
|
+
outputDirectory: newContext.buildOptions.outputDirectory
|
|
2425
2627
|
});
|
|
2426
2628
|
await rebuildVirtualModules();
|
|
2427
2629
|
invalidateVirtualModules(ctx.server);
|
|
@@ -2454,12 +2656,13 @@ function clarifyPlugin(options = {}) {
|
|
|
2454
2656
|
server.watcher.add(contentRoot);
|
|
2455
2657
|
if (configFilePath) server.watcher.add(configFilePath);
|
|
2456
2658
|
server.middlewares.use((req, res, next) => {
|
|
2457
|
-
if (req.url === "/dev/query-preview-route" && req.method === "POST") return handleDevRouteRequest(req, res, routes,
|
|
2458
|
-
if (req.url === "/dev/project-info" && (req.method === "GET" || req.method === "HEAD")) return handleProjectInfoRequest(req, res,
|
|
2659
|
+
if (req.url === "/dev/query-preview-route" && req.method === "POST") return handleDevRouteRequest(req, res, routes, runtimeContext);
|
|
2660
|
+
if (req.url === "/dev/project-info" && (req.method === "GET" || req.method === "HEAD")) return handleProjectInfoRequest(req, res, runtimeContext);
|
|
2459
2661
|
next();
|
|
2460
2662
|
});
|
|
2461
2663
|
const handleContentTreeChange = async (filePath) => {
|
|
2462
|
-
const
|
|
2664
|
+
const changedFile = isAbsolute(filePath) ? filePath : join(root, filePath);
|
|
2665
|
+
const relativeContentFile = relative(contentRoot, changedFile);
|
|
2463
2666
|
if (!(relativeContentFile && !relativeContentFile.startsWith("..") && !isAbsolute(relativeContentFile))) return;
|
|
2464
2667
|
await refreshDevServer(server);
|
|
2465
2668
|
};
|
|
@@ -2523,7 +2726,7 @@ function clarifyPlugin(options = {}) {
|
|
|
2523
2726
|
mdx
|
|
2524
2727
|
]);
|
|
2525
2728
|
const ssrBundlePath = join(ssrOutputDir, "entry-server.js");
|
|
2526
|
-
await renderSSGRoutes(routes,
|
|
2729
|
+
await renderSSGRoutes(routes, runtimeContext, outputDir, ssrBundlePath, generateOptions.ssg.failOnError);
|
|
2527
2730
|
} catch (err) {
|
|
2528
2731
|
console.error("[clarify] SSG failed:", err);
|
|
2529
2732
|
if (generateOptions.ssg.failOnError) throw err;
|
|
@@ -2539,6 +2742,6 @@ function clarifyPlugin(options = {}) {
|
|
|
2539
2742
|
].flat().filter(Boolean);
|
|
2540
2743
|
}
|
|
2541
2744
|
//#endregion
|
|
2542
|
-
export {
|
|
2745
|
+
export { defineConfig as a, cliPackageVersionWithCaret as c, resolveProjectContext as i, createClarifyRuntimeAliases as n, createClarifyTempDir as o, resolveClarifySite as r, cliPackageVersion as s, clarifyPlugin as t };
|
|
2543
2746
|
|
|
2544
|
-
//# sourceMappingURL=plugin-
|
|
2747
|
+
//# sourceMappingURL=plugin-Z3fYTMcb.js.map
|