@tenphi/cookbook 0.17.0 → 0.18.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/dist/cli.js +39 -9
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/content.d.ts +3 -0
- package/dist/content.js +3 -0
- package/dist/eslint-plugin.d.ts +2 -2
- package/dist/eslint-plugin.js +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/docs/ai-agents.md +15 -4
- package/docs/authoring.mdx +42 -8
- package/docs/cli.md +43 -1
- package/docs/configuration.md +77 -15
- package/docs/content-sources.md +26 -0
- package/docs/customization-rules.md +8 -0
- package/docs/deployment.md +20 -3
- package/docs/examples.md +5 -2
- package/docs/getting-started.md +9 -6
- package/docs/index.md +21 -10
- package/docs/migration.md +98 -5
- package/docs/plugins.md +120 -0
- package/docs/publishing.md +153 -0
- package/docs/quality-checks.md +71 -0
- package/docs/recipes.md +116 -0
- package/docs/theme-and-components.md +481 -70
- package/docs/troubleshooting.md +89 -0
- package/package.json +7 -3
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { resolveDocsTheme } from "@tenphi/starlight";
|
|
3
|
-
import { createDocsGraph, formatDiagnostics, materializePackage, normalizeDocsConfig, readDocsLock, reconcileDocsLock, resolveDocsProject, writeDocsLock } from "@tenphi/docs";
|
|
3
|
+
import { createDocsGraph, formatDiagnostics, materializePackage, normalizeDocsConfig, readDocsLock, reconcileDocsLock, resolveDocsProject, validateBuiltDocs, validateProjectAssets, writeDocsLock } from "@tenphi/docs";
|
|
4
4
|
import { cp, mkdir } from "node:fs/promises";
|
|
5
5
|
import { dirname, resolve } from "node:path";
|
|
6
6
|
import { parseArgs } from "node:util";
|
|
@@ -16,6 +16,9 @@ try {
|
|
|
16
16
|
},
|
|
17
17
|
root: { type: "string" },
|
|
18
18
|
config: { type: "string" },
|
|
19
|
+
out: { type: "string" },
|
|
20
|
+
url: { type: "string" },
|
|
21
|
+
"public-dir": { type: "string" },
|
|
19
22
|
"dry-run": {
|
|
20
23
|
type: "boolean",
|
|
21
24
|
default: false
|
|
@@ -31,14 +34,35 @@ try {
|
|
|
31
34
|
if (values.help || positionals.length === 0) printHelp();
|
|
32
35
|
else {
|
|
33
36
|
const command = positionals[0];
|
|
34
|
-
if (
|
|
35
|
-
|
|
37
|
+
if (![
|
|
38
|
+
"doctor",
|
|
39
|
+
"update",
|
|
40
|
+
"check-build"
|
|
41
|
+
].includes(command)) throw new Error(`Unknown command: ${command ?? ""}.`);
|
|
42
|
+
if (command !== "update" && (positionals.length > 1 || values["dry-run"])) throw new Error(`${command} does not accept package selectors or --dry-run.`);
|
|
43
|
+
if (command !== "check-build" && (values.out || values.url)) throw new Error("--out and --url are only supported by check-build.");
|
|
44
|
+
if (values["public-dir"] && command !== "doctor") throw new Error("--public-dir is only supported by doctor.");
|
|
36
45
|
const project = await resolveDocsProject({
|
|
37
46
|
root: resolve(values.root ?? process.cwd()),
|
|
38
47
|
...values.config ? { configFile: values.config } : {}
|
|
39
48
|
});
|
|
40
|
-
if (command === "doctor") await doctor(project, values.json);
|
|
41
|
-
else
|
|
49
|
+
if (command === "doctor") await doctor(project, values.json, values["public-dir"] ? resolve(values.root ?? process.cwd(), values["public-dir"]) : resolve(values.root ?? process.cwd(), "public"));
|
|
50
|
+
else if (command === "check-build") {
|
|
51
|
+
const graph = await createDocsGraph(project);
|
|
52
|
+
const report = await validateBuiltDocs({
|
|
53
|
+
directory: resolve(values.root ?? process.cwd(), values.out ?? "dist"),
|
|
54
|
+
graph,
|
|
55
|
+
...values.url ? { deployedUrl: values.url } : {}
|
|
56
|
+
});
|
|
57
|
+
report.diagnostics.unshift(...graph.diagnostics);
|
|
58
|
+
report.ok = !report.diagnostics.some((d) => d.severity === "error");
|
|
59
|
+
if (values.json) console.log(JSON.stringify(report, null, 2));
|
|
60
|
+
else {
|
|
61
|
+
if (report.diagnostics.length) console.log(formatDiagnostics(report.diagnostics));
|
|
62
|
+
console.log(`${report.ok ? "Passed" : "Failed"} ${report.scope} checks: ${report.pages} pages, ${report.assets} assets${report.checkedUrls ? `, ${report.checkedUrls} deployed URLs` : ""}.`);
|
|
63
|
+
}
|
|
64
|
+
if (!report.ok) process.exitCode = 1;
|
|
65
|
+
} else await update(project, positionals.slice(1), values.json, values["dry-run"]);
|
|
42
66
|
}
|
|
43
67
|
} catch (error) {
|
|
44
68
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -56,19 +80,25 @@ try {
|
|
|
56
80
|
else console.error(formatDiagnostics(diagnostics));
|
|
57
81
|
process.exitCode = 1;
|
|
58
82
|
}
|
|
59
|
-
async function doctor(project, json) {
|
|
83
|
+
async function doctor(project, json, publicDirectory) {
|
|
60
84
|
const theme = resolveDocsTheme(project.config.theme);
|
|
61
85
|
const graph = await createDocsGraph(project);
|
|
62
|
-
const diagnostics = [
|
|
86
|
+
const diagnostics = [
|
|
87
|
+
...graph.diagnostics,
|
|
88
|
+
...theme.diagnostics,
|
|
89
|
+
...await validateProjectAssets(project, graph, publicDirectory)
|
|
90
|
+
];
|
|
63
91
|
const hasErrors = diagnostics.some((diagnostic) => diagnostic.severity === "error");
|
|
64
92
|
if (json) console.log(JSON.stringify({
|
|
65
93
|
ok: !hasErrors,
|
|
94
|
+
scope: "preflight",
|
|
95
|
+
buildVerified: false,
|
|
66
96
|
pages: graph.entries.length,
|
|
67
97
|
assets: graph.assets.length,
|
|
68
98
|
diagnostics
|
|
69
99
|
}, null, 2));
|
|
70
100
|
else if (diagnostics.length > 0) console.log(formatDiagnostics(diagnostics));
|
|
71
|
-
else console.log(`
|
|
101
|
+
else console.log(`Preflight passed: ${graph.entries.length} pages, ${graph.assets.length} content assets. MDX compilation, remote fonts, and deployment are not checked. Run astro build and cookbook check-build.`);
|
|
72
102
|
if (hasErrors) process.exitCode = 1;
|
|
73
103
|
}
|
|
74
104
|
async function update(project, packages, json, dryRun) {
|
|
@@ -111,7 +141,7 @@ async function update(project, packages, json, dryRun) {
|
|
|
111
141
|
}
|
|
112
142
|
}
|
|
113
143
|
function printHelp() {
|
|
114
|
-
console.log(`Usage: cookbook <command> [options]\n\nCommands:\n doctor
|
|
144
|
+
console.log(`Usage: cookbook <command> [options]\n\nCommands:\n doctor Check configuration, content graph, theme, and local files\n check-build Inspect production output and optionally deployed URLs\n update [packages] Reconcile configured package sources and their lock\n\nOptions:\n --root <directory>\n --config <path>\n --public-dir <directory> Local public assets for doctor (default: public)\n --out <directory> Built output (default: dist)\n --url <base-url> Also check a deployed site\n --dry-run Preview an update without writing files\n --json\n -h, --help`);
|
|
115
145
|
process.exit(0);
|
|
116
146
|
}
|
|
117
147
|
//#endregion
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["import { cp, mkdir } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\nimport {\n createDocsGraph,\n formatDiagnostics,\n materializePackage,\n normalizeDocsConfig,\n readDocsLock,\n reconcileDocsLock,\n resolveDocsProject,\n writeDocsLock,\n type DocsDiagnostic,\n type DocsProject,\n} from \"@tenphi/docs\";\nimport { resolveDocsTheme } from \"@tenphi/starlight\";\n\nlet jsonOutput = process.argv.slice(2).includes(\"--json\");\n\ntry {\n const { positionals, values } = parseArgs({\n allowPositionals: true,\n options: {\n json: { type: \"boolean\", default: false },\n root: { type: \"string\" },\n config: { type: \"string\" },\n \"dry-run\": { type: \"boolean\", default: false },\n help: { type: \"boolean\", short: \"h\", default: false },\n },\n });\n jsonOutput = values.json;\n if (values.help || positionals.length === 0) {\n printHelp();\n } else {\n const command = positionals[0];\n if (command !== \"doctor\" && command !== \"update\") {\n throw new Error(`Unknown command: ${command ?? \"\"}.`);\n }\n if (command === \"doctor\" && (positionals.length > 1 || values[\"dry-run\"])) {\n throw new Error(\"doctor does not accept package selectors or --dry-run.\");\n }\n const project = await resolveDocsProject({\n root: resolve(values.root ?? process.cwd()),\n ...(values.config ? { configFile: values.config } : {}),\n });\n if (command === \"doctor\") await doctor(project, values.json);\n else\n await update(\n project,\n positionals.slice(1),\n values.json,\n values[\"dry-run\"],\n );\n }\n} catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const diagnostics: DocsDiagnostic[] =\n error && typeof error === \"object\" && \"diagnostics\" in error\n ? (error.diagnostics as DocsDiagnostic[])\n : [{ code: \"COOKBOOK_CLI_ERROR\", severity: \"error\", message }];\n if (jsonOutput) {\n console.log(\n JSON.stringify({ ok: false, pages: 0, assets: 0, diagnostics }, null, 2),\n );\n } else {\n console.error(formatDiagnostics(diagnostics));\n }\n process.exitCode = 1;\n}\n\nasync function doctor(project: DocsProject, json: boolean): Promise<void> {\n const theme = resolveDocsTheme(project.config.theme);\n const graph = await createDocsGraph(project);\n const diagnostics = [...graph.diagnostics, ...theme.diagnostics];\n const hasErrors = diagnostics.some(\n (diagnostic) => diagnostic.severity === \"error\",\n );\n if (json) {\n console.log(\n JSON.stringify(\n {\n ok: !hasErrors,\n pages: graph.entries.length,\n assets: graph.assets.length,\n diagnostics,\n },\n null,\n 2,\n ),\n );\n } else if (diagnostics.length > 0) {\n console.log(formatDiagnostics(diagnostics));\n } else {\n console.log(\n `Cookbook is healthy: ${graph.entries.length} pages, ${graph.assets.length} assets.`,\n );\n }\n if (hasErrors) process.exitCode = 1;\n}\n\nasync function update(\n project: DocsProject,\n packages: string[],\n json: boolean,\n dryRun: boolean,\n): Promise<void> {\n const existing = await readDocsLock(project.root);\n const next = await reconcileDocsLock(project.config, existing, { packages });\n const changes = next.sources.map((source) => ({\n requested: source.requested,\n from:\n existing?.sources.find(\n (current) => current.requested === source.requested,\n )?.resolved ?? null,\n to: source.resolved,\n }));\n const removed =\n existing?.sources\n .filter(\n (source) =>\n !next.sources.some(\n (current) => current.requested === source.requested,\n ),\n )\n .map((source) => source.requested) ?? [];\n if (!dryRun) {\n const build = normalizeDocsConfig(project.config).build;\n for (const source of next.sources) {\n if (!source.vendored) continue;\n const current = existing?.sources.find(\n (entry) => entry.requested === source.requested,\n );\n if (\n current?.vendored === source.vendored &&\n current.integrity === source.integrity\n )\n continue;\n const { vendored, ...remote } = source;\n const artifact = await materializePackage(remote, build, project.root);\n const destination = resolve(project.root, vendored);\n await mkdir(dirname(destination), { recursive: true });\n await cp(artifact, destination, { recursive: true });\n }\n await writeDocsLock(project.root, next);\n }\n if (json) {\n console.log(\n JSON.stringify(\n {\n ok: true,\n pages: 0,\n assets: 0,\n diagnostics: [],\n dryRun,\n changes,\n removed,\n lock: next,\n },\n null,\n 2,\n ),\n );\n } else {\n for (const change of changes)\n console.log(\n `${change.requested}: ${change.from ?? \"(new)\"} -> ${change.to}`,\n );\n for (const source of removed) console.log(`Removed ${source}`);\n console.log(\n dryRun\n ? \"Dry run: cookbook.lock.json is unchanged.\"\n : \"Updated cookbook.lock.json.\",\n );\n }\n}\n\nfunction printHelp(): never {\n console.log(\n `Usage: cookbook <command> [options]\\n\\nCommands:\\n doctor Validate content, configuration, and theme\\n update [packages] Reconcile configured package sources and their lock\\n\\nOptions:\\n --root <directory>\\n --config <path>\\n --dry-run Preview an update without writing files\\n --json\\n -h, --help`,\n );\n process.exit(0);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["import { cp, mkdir } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\nimport {\n createDocsGraph,\n formatDiagnostics,\n materializePackage,\n normalizeDocsConfig,\n readDocsLock,\n reconcileDocsLock,\n resolveDocsProject,\n writeDocsLock,\n validateProjectAssets,\n validateBuiltDocs,\n type DocsDiagnostic,\n type DocsProject,\n} from \"@tenphi/docs\";\nimport { resolveDocsTheme } from \"@tenphi/starlight\";\n\nlet jsonOutput = process.argv.slice(2).includes(\"--json\");\n\ntry {\n const { positionals, values } = parseArgs({\n allowPositionals: true,\n options: {\n json: { type: \"boolean\", default: false },\n root: { type: \"string\" },\n config: { type: \"string\" },\n out: { type: \"string\" },\n url: { type: \"string\" },\n \"public-dir\": { type: \"string\" },\n \"dry-run\": { type: \"boolean\", default: false },\n help: { type: \"boolean\", short: \"h\", default: false },\n },\n });\n jsonOutput = values.json;\n if (values.help || positionals.length === 0) {\n printHelp();\n } else {\n const command = positionals[0];\n if (![\"doctor\", \"update\", \"check-build\"].includes(command!)) {\n throw new Error(`Unknown command: ${command ?? \"\"}.`);\n }\n if (command !== \"update\" && (positionals.length > 1 || values[\"dry-run\"])) {\n throw new Error(\n `${command} does not accept package selectors or --dry-run.`,\n );\n }\n if (command !== \"check-build\" && (values.out || values.url))\n throw new Error(\"--out and --url are only supported by check-build.\");\n if (values[\"public-dir\"] && command !== \"doctor\")\n throw new Error(\"--public-dir is only supported by doctor.\");\n const project = await resolveDocsProject({\n root: resolve(values.root ?? process.cwd()),\n ...(values.config ? { configFile: values.config } : {}),\n });\n if (command === \"doctor\")\n await doctor(\n project,\n values.json,\n values[\"public-dir\"]\n ? resolve(values.root ?? process.cwd(), values[\"public-dir\"])\n : resolve(values.root ?? process.cwd(), \"public\"),\n );\n else if (command === \"check-build\") {\n const graph = await createDocsGraph(project);\n const report = await validateBuiltDocs({\n directory: resolve(values.root ?? process.cwd(), values.out ?? \"dist\"),\n graph,\n ...(values.url ? { deployedUrl: values.url } : {}),\n });\n report.diagnostics.unshift(...graph.diagnostics);\n report.ok = !report.diagnostics.some((d) => d.severity === \"error\");\n if (values.json) console.log(JSON.stringify(report, null, 2));\n else {\n if (report.diagnostics.length)\n console.log(formatDiagnostics(report.diagnostics));\n console.log(\n `${report.ok ? \"Passed\" : \"Failed\"} ${report.scope} checks: ${report.pages} pages, ${report.assets} assets${report.checkedUrls ? `, ${report.checkedUrls} deployed URLs` : \"\"}.`,\n );\n }\n if (!report.ok) process.exitCode = 1;\n } else\n await update(\n project,\n positionals.slice(1),\n values.json,\n values[\"dry-run\"],\n );\n }\n} catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const diagnostics: DocsDiagnostic[] =\n error && typeof error === \"object\" && \"diagnostics\" in error\n ? (error.diagnostics as DocsDiagnostic[])\n : [{ code: \"COOKBOOK_CLI_ERROR\", severity: \"error\", message }];\n if (jsonOutput) {\n console.log(\n JSON.stringify({ ok: false, pages: 0, assets: 0, diagnostics }, null, 2),\n );\n } else {\n console.error(formatDiagnostics(diagnostics));\n }\n process.exitCode = 1;\n}\n\nasync function doctor(\n project: DocsProject,\n json: boolean,\n publicDirectory?: string,\n): Promise<void> {\n const theme = resolveDocsTheme(project.config.theme);\n const graph = await createDocsGraph(project);\n const diagnostics = [\n ...graph.diagnostics,\n ...theme.diagnostics,\n ...(await validateProjectAssets(project, graph, publicDirectory)),\n ];\n const hasErrors = diagnostics.some(\n (diagnostic) => diagnostic.severity === \"error\",\n );\n if (json) {\n console.log(\n JSON.stringify(\n {\n ok: !hasErrors,\n scope: \"preflight\",\n buildVerified: false,\n pages: graph.entries.length,\n assets: graph.assets.length,\n diagnostics,\n },\n null,\n 2,\n ),\n );\n } else if (diagnostics.length > 0) {\n console.log(formatDiagnostics(diagnostics));\n } else {\n console.log(\n `Preflight passed: ${graph.entries.length} pages, ${graph.assets.length} content assets. MDX compilation, remote fonts, and deployment are not checked. Run astro build and cookbook check-build.`,\n );\n }\n if (hasErrors) process.exitCode = 1;\n}\n\nasync function update(\n project: DocsProject,\n packages: string[],\n json: boolean,\n dryRun: boolean,\n): Promise<void> {\n const existing = await readDocsLock(project.root);\n const next = await reconcileDocsLock(project.config, existing, { packages });\n const changes = next.sources.map((source) => ({\n requested: source.requested,\n from:\n existing?.sources.find(\n (current) => current.requested === source.requested,\n )?.resolved ?? null,\n to: source.resolved,\n }));\n const removed =\n existing?.sources\n .filter(\n (source) =>\n !next.sources.some(\n (current) => current.requested === source.requested,\n ),\n )\n .map((source) => source.requested) ?? [];\n if (!dryRun) {\n const build = normalizeDocsConfig(project.config).build;\n for (const source of next.sources) {\n if (!source.vendored) continue;\n const current = existing?.sources.find(\n (entry) => entry.requested === source.requested,\n );\n if (\n current?.vendored === source.vendored &&\n current.integrity === source.integrity\n )\n continue;\n const { vendored, ...remote } = source;\n const artifact = await materializePackage(remote, build, project.root);\n const destination = resolve(project.root, vendored);\n await mkdir(dirname(destination), { recursive: true });\n await cp(artifact, destination, { recursive: true });\n }\n await writeDocsLock(project.root, next);\n }\n if (json) {\n console.log(\n JSON.stringify(\n {\n ok: true,\n pages: 0,\n assets: 0,\n diagnostics: [],\n dryRun,\n changes,\n removed,\n lock: next,\n },\n null,\n 2,\n ),\n );\n } else {\n for (const change of changes)\n console.log(\n `${change.requested}: ${change.from ?? \"(new)\"} -> ${change.to}`,\n );\n for (const source of removed) console.log(`Removed ${source}`);\n console.log(\n dryRun\n ? \"Dry run: cookbook.lock.json is unchanged.\"\n : \"Updated cookbook.lock.json.\",\n );\n }\n}\n\nfunction printHelp(): never {\n console.log(\n `Usage: cookbook <command> [options]\\n\\nCommands:\\n doctor Check configuration, content graph, theme, and local files\\n check-build Inspect production output and optionally deployed URLs\\n update [packages] Reconcile configured package sources and their lock\\n\\nOptions:\\n --root <directory>\\n --config <path>\\n --public-dir <directory> Local public assets for doctor (default: public)\\n --out <directory> Built output (default: dist)\\n --url <base-url> Also check a deployed site\\n --dry-run Preview an update without writing files\\n --json\\n -h, --help`,\n );\n process.exit(0);\n}\n"],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
|
|
2
|
-
import { COOKBOOK_COMPONENT_NAMES, COOKBOOK_COMPONENT_SUB_ELEMENTS, ComponentStylesConfig, DocsConfig, DocsSource, ThemeConfig, ThemeFont, ThemeFontFile, ThemeFonts, defineDocsConfig, mergeDocsConfig } from "@tenphi/docs/config";
|
|
3
|
-
export { COOKBOOK_COMPONENT_NAMES, COOKBOOK_COMPONENT_SUB_ELEMENTS, type ComponentStylesConfig, type DocsConfig, type DocsSource, type ThemeConfig, type ThemeFont, type ThemeFontFile, type ThemeFonts, defineDocsConfig, mergeDocsConfig };
|
|
2
|
+
import { BreadcrumbItem, COOKBOOK_COMPONENT_NAMES, COOKBOOK_COMPONENT_SUB_ELEMENTS, ComponentStylesConfig, DocsConfig, DocsSource, FontLoadingConfig, PageSeoConfig, SiteLogoConfig, SiteSeoConfig, SocialImage, TableOfContentsConfig, ThemeConfig, ThemeFont, ThemeFontFile, ThemeFonts, defineDocsConfig, mergeDocsConfig } from "@tenphi/docs/config";
|
|
3
|
+
export { type BreadcrumbItem, COOKBOOK_COMPONENT_NAMES, COOKBOOK_COMPONENT_SUB_ELEMENTS, type ComponentStylesConfig, type DocsConfig, type DocsSource, type FontLoadingConfig, type PageSeoConfig, type SiteLogoConfig, type SiteSeoConfig, type SocialImage, type TableOfContentsConfig, type ThemeConfig, type ThemeFont, type ThemeFontFile, type ThemeFonts, defineDocsConfig, mergeDocsConfig };
|
package/dist/content.js
ADDED
package/dist/eslint-plugin.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
|
|
2
|
-
import eslint_plugin_default, { ResolvedConfig, StyleFunctionConfig, TastyValidationConfig, recommended, strict, validationConfig } from "@tenphi/starlight/eslint-plugin";
|
|
3
|
-
export { type ResolvedConfig, type StyleFunctionConfig, type TastyValidationConfig, eslint_plugin_default as default, recommended, strict, validationConfig };
|
|
2
|
+
import eslint_plugin_default, { ResolvedConfig, StyleFunctionConfig, TastyValidationConfig, createValidationConfig, recommended, strict, validationConfig } from "@tenphi/starlight/eslint-plugin";
|
|
3
|
+
export { type ResolvedConfig, type StyleFunctionConfig, type TastyValidationConfig, createValidationConfig, eslint_plugin_default as default, recommended, strict, validationConfig };
|
package/dist/eslint-plugin.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import eslint_plugin_default, { recommended, strict, validationConfig } from "@tenphi/starlight/eslint-plugin";
|
|
3
|
-
export { eslint_plugin_default as default, recommended, strict, validationConfig };
|
|
2
|
+
import eslint_plugin_default, { createValidationConfig, recommended, strict, validationConfig } from "@tenphi/starlight/eslint-plugin";
|
|
3
|
+
export { createValidationConfig, eslint_plugin_default as default, recommended, strict, validationConfig };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
|
|
2
2
|
import starlight_default, { CookbookOptions, DEFAULT_THEME_TOKENS, DEFAULT_TYPOGRAPHY_PRESETS } from "@tenphi/starlight";
|
|
3
|
-
import { BrandConfig, BrandDeclaration, BuildConfig, COOKBOOK_COMPONENT_NAMES, COOKBOOK_COMPONENT_SUB_ELEMENTS, ComponentStyleConfig, ComponentStyles, ComponentStylesConfig, ComponentsConfig, ContentConfig, CookbookComponentName, CookbookComponentStyles, CookbookComponentSubElementName, DocsAsset, DocsConfig, DocsDiagnostic, DocsEntry, DocsFrontmatter, DocsGraph, DocsRoute, DocsSource, EditLinkConfig, HeadConfig, LocaleConfig, MarkdownConfig, NavigationConfig, NavigationItem, NavigationPlacement, NavigationTab, SearchConfig, SiteConfig, SiteIconConfig, SiteVersion, ThemeConfig, ThemeFont, ThemeFontFile, ThemeFonts, ThemePaletteColor, ThemePaletteConfig, ThemeTokenValue, ThemeTokens, TypographyPreset, TypographyPresets, defineDocsConfig, mergeDocsConfig } from "@tenphi/docs";
|
|
4
|
-
export { type BrandConfig, type BrandDeclaration, type BuildConfig, COOKBOOK_COMPONENT_NAMES, COOKBOOK_COMPONENT_SUB_ELEMENTS, type ComponentStyleConfig, type ComponentStyles, type ComponentStylesConfig, type ComponentsConfig, type ContentConfig, type CookbookComponentName, type CookbookComponentStyles, type CookbookComponentSubElementName, type CookbookOptions, DEFAULT_THEME_TOKENS, DEFAULT_TYPOGRAPHY_PRESETS, type DocsAsset, type DocsConfig, type DocsDiagnostic, type DocsEntry, type DocsFrontmatter, type DocsGraph, type DocsRoute, type DocsSource, type EditLinkConfig, type HeadConfig, type LocaleConfig, type MarkdownConfig, type NavigationConfig, type NavigationItem, type NavigationPlacement, type NavigationTab, type SearchConfig, type SiteConfig, type SiteIconConfig, type SiteVersion, type ThemeConfig, type ThemeFont, type ThemeFontFile, type ThemeFonts, type ThemePaletteColor, type ThemePaletteConfig, type ThemeTokenValue, type ThemeTokens, type TypographyPreset, type TypographyPresets, starlight_default as default, defineDocsConfig, mergeDocsConfig };
|
|
3
|
+
import { BrandConfig, BrandDeclaration, BreadcrumbItem, BuildConfig, COOKBOOK_COMPONENT_NAMES, COOKBOOK_COMPONENT_SUB_ELEMENTS, COOKBOOK_PALETTE_NAMES, ComponentStyleConfig, ComponentStyles, ComponentStylesConfig, ComponentsConfig, ContentConfig, CookbookComponentName, CookbookComponentStyles, CookbookComponentSubElementName, DocsAsset, DocsConfig, DocsDiagnostic, DocsEntry, DocsFrontmatter, DocsGraph, DocsRoute, DocsSource, EditLinkConfig, FontLoadingConfig, HeadConfig, LocaleConfig, MarkdownConfig, NavigationConfig, NavigationItem, NavigationPlacement, NavigationTab, PageSeoConfig, SearchConfig, SiteConfig, SiteIconConfig, SiteLogoConfig, SiteSeoConfig, SiteVersion, SocialImage, TableOfContentsConfig, ThemeConfig, ThemeFont, ThemeFontFile, ThemeFonts, ThemePaletteColor, ThemePaletteConfig, ThemeTokenValue, ThemeTokens, TypographyPreset, TypographyPresets, defineDocsConfig, mergeDocsConfig } from "@tenphi/docs";
|
|
4
|
+
export { type BrandConfig, type BrandDeclaration, type BreadcrumbItem, type BuildConfig, COOKBOOK_COMPONENT_NAMES, COOKBOOK_COMPONENT_SUB_ELEMENTS, COOKBOOK_PALETTE_NAMES, type ComponentStyleConfig, type ComponentStyles, type ComponentStylesConfig, type ComponentsConfig, type ContentConfig, type CookbookComponentName, type CookbookComponentStyles, type CookbookComponentSubElementName, type CookbookOptions, DEFAULT_THEME_TOKENS, DEFAULT_TYPOGRAPHY_PRESETS, type DocsAsset, type DocsConfig, type DocsDiagnostic, type DocsEntry, type DocsFrontmatter, type DocsGraph, type DocsRoute, type DocsSource, type EditLinkConfig, type FontLoadingConfig, type HeadConfig, type LocaleConfig, type MarkdownConfig, type NavigationConfig, type NavigationItem, type NavigationPlacement, type NavigationTab, type PageSeoConfig, type SearchConfig, type SiteConfig, type SiteIconConfig, type SiteLogoConfig, type SiteSeoConfig, type SiteVersion, type SocialImage, type TableOfContentsConfig, type ThemeConfig, type ThemeFont, type ThemeFontFile, type ThemeFonts, type ThemePaletteColor, type ThemePaletteConfig, type ThemeTokenValue, type ThemeTokens, type TypographyPreset, type TypographyPresets, starlight_default as default, defineDocsConfig, mergeDocsConfig };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import starlight_default, { DEFAULT_THEME_TOKENS, DEFAULT_TYPOGRAPHY_PRESETS } from "@tenphi/starlight";
|
|
3
|
-
import { COOKBOOK_COMPONENT_NAMES, COOKBOOK_COMPONENT_SUB_ELEMENTS, defineDocsConfig, mergeDocsConfig } from "@tenphi/docs";
|
|
4
|
-
export { COOKBOOK_COMPONENT_NAMES, COOKBOOK_COMPONENT_SUB_ELEMENTS, DEFAULT_THEME_TOKENS, DEFAULT_TYPOGRAPHY_PRESETS, starlight_default as default, defineDocsConfig, mergeDocsConfig };
|
|
3
|
+
import { COOKBOOK_COMPONENT_NAMES, COOKBOOK_COMPONENT_SUB_ELEMENTS, COOKBOOK_PALETTE_NAMES, defineDocsConfig, mergeDocsConfig } from "@tenphi/docs";
|
|
4
|
+
export { COOKBOOK_COMPONENT_NAMES, COOKBOOK_COMPONENT_SUB_ELEMENTS, COOKBOOK_PALETTE_NAMES, DEFAULT_THEME_TOKENS, DEFAULT_TYPOGRAPHY_PRESETS, starlight_default as default, defineDocsConfig, mergeDocsConfig };
|
package/docs/ai-agents.md
CHANGED
|
@@ -14,15 +14,14 @@ concrete task, for example:
|
|
|
14
14
|
> Create a Cookbook site for this repository in `docs-site/`. Use the existing
|
|
15
15
|
> README and `docs/` pages as sources. Set the public site URL to
|
|
16
16
|
> `https://docs.example.com`, add a getting started page if one is missing,
|
|
17
|
-
> and run the
|
|
17
|
+
> and run the complete validation command.
|
|
18
18
|
|
|
19
19
|
From the repository root, the agent can run:
|
|
20
20
|
|
|
21
21
|
```sh
|
|
22
22
|
npm create @tenphi/cookbook@latest docs-site -- --source . --site https://docs.example.com --yes
|
|
23
23
|
cd docs-site
|
|
24
|
-
npm run
|
|
25
|
-
npm run build
|
|
24
|
+
npm run validate
|
|
26
25
|
```
|
|
27
26
|
|
|
28
27
|
For a new project without existing documentation, omit `--source .`. To document
|
|
@@ -53,9 +52,21 @@ The HTML pages remain the primary source of information. Their text, headings,
|
|
|
53
52
|
links, and page metadata are present in the static response, so an agent can
|
|
54
53
|
read them without running client JavaScript. Write descriptive headings and
|
|
55
54
|
link text, keep instructions current, and verify the production output with
|
|
56
|
-
`npm run
|
|
55
|
+
`npm run validate` and `npm run preview`.
|
|
57
56
|
|
|
58
57
|
Google's [AI Search guidance](https://developers.google.com/search/docs/fundamentals/ai-optimization-guide)
|
|
59
58
|
prioritizes ordinary crawlability and useful content. It says `llms.txt` is
|
|
60
59
|
not used by Google Search; Cookbook provides it for other agents that use the
|
|
61
60
|
[llms.txt proposal](https://llmstxt.org/).
|
|
61
|
+
|
|
62
|
+
## Read a published page
|
|
63
|
+
|
|
64
|
+
Follow the page’s `rel="alternate" type="text/markdown"` link or its **Download Markdown**
|
|
65
|
+
control for a clean reading representation with canonical/source/language/version
|
|
66
|
+
metadata. Use the HTML for interactive component output omitted from Markdown.
|
|
67
|
+
See [Publishing metadata](./publishing.md) for discovery and indexing controls.
|
|
68
|
+
|
|
69
|
+
For maintenance, follow the [upgrade guide](./migration.md), then check the
|
|
70
|
+
[deployed output](./deployment.md#validate-the-published-result). The
|
|
71
|
+
[recipes](./recipes.md) provide complete starting configurations;
|
|
72
|
+
[troubleshooting](./troubleshooting.md) explains common failures.
|
package/docs/authoring.mdx
CHANGED
|
@@ -51,8 +51,9 @@ and contrast modes.
|
|
|
51
51
|
## Code groups
|
|
52
52
|
|
|
53
53
|
Pass labeled source strings to create an accessible tabbed code group. `language`
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
selects the Shiki grammar (defaults to plain text). Groups share semantic syntax
|
|
55
|
+
colors, configured grammars/transformers, and copy controls with Markdown fences.
|
|
56
|
+
Each panel retains keyboard-accessible tabs and readable fallback content.
|
|
56
57
|
|
|
57
58
|
```mdx
|
|
58
59
|
<CodeGroup
|
|
@@ -74,13 +75,46 @@ text. Ordinary fenced Markdown provides syntax highlighting.
|
|
|
74
75
|
|
|
75
76
|
## Other components
|
|
76
77
|
|
|
77
|
-
| Component | Props and behavior
|
|
78
|
-
| --------- |
|
|
79
|
-
| `Card` | Optional `title` and `href`; renders an article or link with slot content
|
|
80
|
-
| `Steps` | Ordered list container; supply `li` elements
|
|
81
|
-
| `Logo` | Optional `label`, `decorative`, and `class`; renders the Cookbook mark
|
|
82
|
-
| `Preview` | Required `title`; optional `html`, `css`, and `javascript`; isolates examples in
|
|
78
|
+
| Component | Props and behavior |
|
|
79
|
+
| --------- | --------------------------------------------------------------------------------------------------- |
|
|
80
|
+
| `Card` | Optional `title` and `href`; renders an article or link with slot content |
|
|
81
|
+
| `Steps` | Ordered list container; supply `li` elements |
|
|
82
|
+
| `Logo` | Optional `label`, `decorative`, and `class`; renders the Cookbook mark |
|
|
83
|
+
| `Preview` | Required `title`; optional `html`, `css`, and `javascript`; isolates examples in a sandboxed iframe |
|
|
83
84
|
|
|
84
85
|
The public package exports each component's props type, such as `TabProps`,
|
|
85
86
|
`CalloutProps`, and `CodeGroupProps`. Styles and all named sub-elements are
|
|
86
87
|
listed in [Theme and components](./theme-and-components.md#style-customization).
|
|
88
|
+
|
|
89
|
+
## On-page navigation
|
|
90
|
+
|
|
91
|
+
Desktop pages show a table of contents. Opt into a compact disclosure below the
|
|
92
|
+
header on smaller screens, globally in `docs.config.ts`:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
tableOfContents: { mobile: true, minHeadingLevel: 2, maxHeadingLevel: 3 }
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The same frontmatter field can change heading levels or set `mobile: false` on
|
|
99
|
+
one page. `tableOfContents: false` disables both versions. Selecting a mobile
|
|
100
|
+
contents link closes the disclosure and moves keyboard focus to the heading.
|
|
101
|
+
Customize `theme.styles.MobileTableOfContents` and `TableOfContentsLayout`.
|
|
102
|
+
|
|
103
|
+
## Hero images
|
|
104
|
+
|
|
105
|
+
Use a relative local image in frontmatter. Cookbook reads its intrinsic dimensions
|
|
106
|
+
and reserves the correct aspect ratio as the layout responds to screen width:
|
|
107
|
+
|
|
108
|
+
```yaml
|
|
109
|
+
hero:
|
|
110
|
+
tagline: Build something useful.
|
|
111
|
+
image:
|
|
112
|
+
file: ./assets/hero.png
|
|
113
|
+
alt: A preview of the documentation
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Use `light` and `dark` instead of `file` for appearance variants; both must have
|
|
117
|
+
the same aspect ratio. Remote or public-path images require explicit `width` and
|
|
118
|
+
`height`. Hero images load eagerly with high fetch priority; use ordinary Markdown
|
|
119
|
+
images for content farther down the page. `theme.styles.Hero.Visual` controls
|
|
120
|
+
responsive sizing without changing the intrinsic dimensions.
|
package/docs/cli.md
CHANGED
|
@@ -20,19 +20,61 @@ npx @tenphi/cookbook doctor --config ./config/manual.ts --json
|
|
|
20
20
|
|
|
21
21
|
Doctor checks the content graph, configuration, semantic theme, links, assets,
|
|
22
22
|
navigation, and redirects without starting Astro. It exits non-zero for errors.
|
|
23
|
-
It
|
|
23
|
+
It validates configured local font files, logo/favicon sources, public social
|
|
24
|
+
images, and component override paths. `--public-dir ./static` supports a custom
|
|
25
|
+
Astro public directory; the default is `public/` in the app directory.
|
|
26
|
+
|
|
27
|
+
Doctor reports **preflight** health. It does not compile MDX or components,
|
|
28
|
+
download Google fonts, check image decoding, inspect Astro plugins, or verify
|
|
29
|
+
the emitted site. These checks happen during the build and output validation.
|
|
24
30
|
|
|
25
31
|
JSON results use a stable envelope, including configuration failures:
|
|
26
32
|
|
|
27
33
|
```json
|
|
28
34
|
{
|
|
29
35
|
"ok": true,
|
|
36
|
+
"scope": "preflight",
|
|
37
|
+
"buildVerified": false,
|
|
30
38
|
"pages": 8,
|
|
31
39
|
"assets": 3,
|
|
32
40
|
"diagnostics": []
|
|
33
41
|
}
|
|
34
42
|
```
|
|
35
43
|
|
|
44
|
+
## Check the built site and deployment
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
npm run validate
|
|
48
|
+
npx @tenphi/cookbook check-build --out dist --json
|
|
49
|
+
npx @tenphi/cookbook check-build --out dist --url https://docs.example.com/manual/
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
New projects include `validate`, which runs `cookbook doctor && astro build &&
|
|
53
|
+
cookbook check-build`. Existing projects can add that script to `package.json`.
|
|
54
|
+
Use the same environment variables and configuration for building and checking.
|
|
55
|
+
`--out` is relative to the selected app directory, even when `docs.config.ts`
|
|
56
|
+
points at a different content root.
|
|
57
|
+
|
|
58
|
+
`check-build` reads actual HTML and CSS plus Cookbook's publishing manifest. It
|
|
59
|
+
checks local page/asset URLs, heading fragments, referenced fonts, social images,
|
|
60
|
+
canonical and indexing metadata, sitemap coverage, and discovery files. Direct
|
|
61
|
+
links to drafts are valid; drafts must still be built and carry `noindex`.
|
|
62
|
+
External links and remote font availability are outside this local check.
|
|
63
|
+
|
|
64
|
+
With `--url`, it also fetches the built pages and referenced local assets from
|
|
65
|
+
that deployment, checks status codes, rejects HTML fallbacks for assets, and
|
|
66
|
+
compares page title/canonical/indexing metadata. Include the deployed path prefix;
|
|
67
|
+
it may differ from the production prefix in the build. Production canonicals can
|
|
68
|
+
remain unchanged on a preview host. An unexpected `X-Robots-Tag: noindex` on an
|
|
69
|
+
indexable page is reported. Network failures exit non-zero; rerun after the host
|
|
70
|
+
has finished deploying.
|
|
71
|
+
|
|
72
|
+
JSON adds `scope` (`built-output` or `deployment`) and `checkedUrls`. A missing
|
|
73
|
+
production site URL is a warning: configure `site.url` or Astro's `site` before
|
|
74
|
+
relying on canonical or sitemap checks. Warnings do not fail the command.
|
|
75
|
+
This checks output and hosting; browser accessibility and interaction testing
|
|
76
|
+
remain separate steps.
|
|
77
|
+
|
|
36
78
|
## Update package content
|
|
37
79
|
|
|
38
80
|
```sh
|
package/docs/configuration.md
CHANGED
|
@@ -20,6 +20,10 @@ export default defineDocsConfig({
|
|
|
20
20
|
Cookbook validates the configuration when it loads. Unknown top-level and
|
|
21
21
|
section keys are errors.
|
|
22
22
|
|
|
23
|
+
Start with a complete [configuration recipe](./recipes.md) for common tasks.
|
|
24
|
+
This page documents the available options; [working examples](./examples.md)
|
|
25
|
+
covers repository layouts and shared presets.
|
|
26
|
+
|
|
23
27
|
## Project resolution and presets
|
|
24
28
|
|
|
25
29
|
`cookbook()` and CLI commands discover the same `docs.config.ts`. Set `root`
|
|
@@ -92,10 +96,19 @@ content: {
|
|
|
92
96
|
},
|
|
93
97
|
```
|
|
94
98
|
|
|
95
|
-
Each `routeBase` must have a page, and version roots must be distinct. A
|
|
99
|
+
Each `routeBase` must have a home page (a localized home also qualifies), and version roots must be distinct. A
|
|
96
100
|
single-version site can continue using `site.version` for a simple label.
|
|
97
101
|
|
|
98
|
-
### Site
|
|
102
|
+
### Site logo
|
|
103
|
+
|
|
104
|
+
`site.logo` accepts a local image path, `false` to hide the mark, or an object
|
|
105
|
+
with `src` (one image) or `light` and `dark` (appearance variants). Optional
|
|
106
|
+
`alt`, `decorative`, `href`, `width`, and `height` control accessible text,
|
|
107
|
+
destination, and intrinsic sizing. It applies to the header and mobile drawer.
|
|
108
|
+
See the [shared logo guide](./theme-and-components.md#a-shared-site-logo).
|
|
109
|
+
The logo and favicon are independent.
|
|
110
|
+
|
|
111
|
+
## Site icons
|
|
99
112
|
|
|
100
113
|
Cookbook ships its book mark as the default favicon. Set `site.favicon` to a
|
|
101
114
|
local SVG, PNG, JPEG, WebP, AVIF, or GIF when the documentation should use the
|
|
@@ -204,6 +217,14 @@ renderer frontmatter. Use `content.frontmatter: "reject"` to reject unrelated
|
|
|
204
217
|
fields. Other supported fields include `aliases`, `template`, `hero`, `editUrl`,
|
|
205
218
|
`lastUpdated`, `prev`, `next`, `head`, `draft`, and `slug`.
|
|
206
219
|
|
|
220
|
+
### Draft pages
|
|
221
|
+
|
|
222
|
+
Set `draft: true` to publish a page for review at its normal URL. Drafts remain
|
|
223
|
+
available in development and production, and authored links to them are valid.
|
|
224
|
+
They are excluded from automatic navigation, pagination, search, sitemaps, and
|
|
225
|
+
`llms.txt`, and receive `noindex` metadata. Removing `draft` makes the page
|
|
226
|
+
discoverable on the next build. A draft URL is public; this is not access control.
|
|
227
|
+
|
|
207
228
|
## Languages
|
|
208
229
|
|
|
209
230
|
Expose Starlight's multilingual routing and language picker directly:
|
|
@@ -218,10 +239,17 @@ defaultLocale: "root",
|
|
|
218
239
|
```
|
|
219
240
|
|
|
220
241
|
Locale keys other than `root` are URL prefixes. A source routed to `/fr/guide`
|
|
221
|
-
is the French counterpart of `/guide
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
242
|
+
is the French counterpart of `/guide`. Navigation and pagination include the
|
|
243
|
+
current locale's published routes. Locale prefixes are added once, after the
|
|
244
|
+
site's deployment base.
|
|
245
|
+
|
|
246
|
+
Cookbook does not create duplicate fallback pages. When the language picker
|
|
247
|
+
cannot find a translation, it links to the equivalent page in `defaultLocale`,
|
|
248
|
+
then an existing locale home or default-language home. The picker labels
|
|
249
|
+
cross-language fallbacks. Locales with no usable target are omitted. Header home
|
|
250
|
+
links use the same policy, so a missing `/fr/` never creates a broken home link.
|
|
251
|
+
Alternate-language metadata lists only existing published translations. Drafts
|
|
252
|
+
remain directly accessible but are excluded from locale discovery.
|
|
225
253
|
|
|
226
254
|
## Content
|
|
227
255
|
|
|
@@ -350,13 +378,19 @@ theme: {
|
|
|
350
378
|
surface: { tone: 98, saturation: 0.05 },
|
|
351
379
|
text: {
|
|
352
380
|
base: "surface",
|
|
353
|
-
tone:
|
|
381
|
+
tone: 0,
|
|
382
|
+
saturation: 0,
|
|
383
|
+
contrast: { wcag: [7, 10] }
|
|
384
|
+
},
|
|
385
|
+
heading: {
|
|
386
|
+
base: "surface",
|
|
387
|
+
tone: [4, 0],
|
|
354
388
|
saturation: 0,
|
|
355
389
|
contrast: { wcag: [7, 10] }
|
|
356
390
|
},
|
|
357
391
|
textSoft: {
|
|
358
392
|
base: "surface",
|
|
359
|
-
tone:
|
|
393
|
+
tone: [25, 10],
|
|
360
394
|
saturation: 0.05,
|
|
361
395
|
contrast: { wcag: [4.5, 7] }
|
|
362
396
|
}
|
|
@@ -404,8 +438,11 @@ flows. The default layout is capped at `87.5rem` (1400px), matching the
|
|
|
404
438
|
Tasty site, with a `58rem` reading column and a `17.5rem` sidebar. `brand.from`
|
|
405
439
|
supplies the color seed. `palette` supplies semantic Glaze declarations that
|
|
406
440
|
inherit its hue and saturation unless a role supplies its own `from`. `tone` and
|
|
407
|
-
a saturation factor set the surface
|
|
408
|
-
|
|
441
|
+
a saturation factor set the surface. Reading text uses absolute tones: body
|
|
442
|
+
text starts at 0, and headings at 4. Glaze applies normal-mode tone boundaries
|
|
443
|
+
and adapts the values for dark mode; `base` and `contrast` provide minimum
|
|
444
|
+
contrast safeguards. `palette.heading` follows an explicit `palette.text`
|
|
445
|
+
declaration unless customized separately. Glaze resolves light, dark, and both
|
|
409
446
|
high-contrast modes independently. Literal color shorthand and structured
|
|
410
447
|
brand hue/saturation/tone remain supported. A requested APCA floor below 45 requires the explicit
|
|
411
448
|
`unsafeContrast: true` escape hatch. Learn more in
|
|
@@ -456,11 +493,9 @@ export default defineConfig({
|
|
|
456
493
|
});
|
|
457
494
|
```
|
|
458
495
|
|
|
459
|
-
Cookbook
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
Cookbook-owned components or change routes can conflict with the content graph.
|
|
463
|
-
Use `theme.styles` for visual changes.
|
|
496
|
+
Cookbook preserves custom metadata for route middleware and supports custom schemas.
|
|
497
|
+
See the [plugin compatibility guide](./plugins.md) for the tested ecosystem matrix,
|
|
498
|
+
content query API, Tasty adapters, and collection/style limitations.
|
|
464
499
|
|
|
465
500
|
Cookbook renders fenced `mermaid` blocks as responsive, theme-aware SVG during
|
|
466
501
|
the static build. Flowcharts, state, sequence, class, and entity-relationship
|
|
@@ -585,3 +620,30 @@ contrast modes. Adjust blur and other header styling via `theme.styles.HeaderFra
|
|
|
585
620
|
`theme.palette.overlay` controls the fixed underlay color, defaulting to black at
|
|
586
621
|
50% opacity in every scheme. The mobile drawer uses the Glaze shadow token and
|
|
587
622
|
a 120ms slide transition; customize these through `theme.styles.Sidebar`.
|
|
623
|
+
|
|
624
|
+
### Translate Cookbook controls
|
|
625
|
+
|
|
626
|
+
Cookbook includes English and French interface messages. Other languages use
|
|
627
|
+
English for missing Cookbook messages while Starlight supplies its own built-in
|
|
628
|
+
translations. Override messages by language code; regional codes fall back to the
|
|
629
|
+
base language and then English:
|
|
630
|
+
|
|
631
|
+
```ts
|
|
632
|
+
translations: {
|
|
633
|
+
de: {
|
|
634
|
+
appearance: "Darstellung",
|
|
635
|
+
closeNavigation: "Navigation schließen",
|
|
636
|
+
"navigation.Guide": "Anleitung",
|
|
637
|
+
},
|
|
638
|
+
},
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
`navigation.<configured label>` translates named tabs and navigation groups.
|
|
642
|
+
Automatically generated links use the title from the translated page.
|
|
643
|
+
Cookbook message keys are `appearance`, `colorScheme`, `contrast`,
|
|
644
|
+
`normalContrast`, `highContrast`, `auto`, `closeNavigation`, `primary`, `sections`,
|
|
645
|
+
`chooseSection`, `headerLinks`, `more`, `closeMore`, `moreLinks`, `versions`,
|
|
646
|
+
`documentationVersion`, `documentationVersions`, `version`, `home`,
|
|
647
|
+
`generatedWith`, `viewSource`, `copyCode`, `codeCopied`, `codeCopyError`,
|
|
648
|
+
`copyHeading`, `linkCopied`, `linkCopyError`, `notFound`, `notFoundDescription`,
|
|
649
|
+
and `fallback`. Preserve `{heading}` in the `copyHeading` message.
|
package/docs/content-sources.md
CHANGED
|
@@ -120,6 +120,32 @@ into one local document before the build. Cookbook checks the spec size against
|
|
|
120
120
|
`build.maxAssetBytes` and reports invalid or duplicate operation routes.
|
|
121
121
|
Generated pages are static references; they do not make requests to the API.
|
|
122
122
|
|
|
123
|
+
### Supported OpenAPI details
|
|
124
|
+
|
|
125
|
+
Cookbook renders the core OpenAPI 3.0/3.1 operation model:
|
|
126
|
+
|
|
127
|
+
- Operation parameters replace path parameters with the same **name and location**.
|
|
128
|
+
The same name in `query` and `path` remains two parameters.
|
|
129
|
+
- Parameters and request/response media types render singular `example` values
|
|
130
|
+
(including `false`, `0`, and `null`) and named `examples`. Local Example Object
|
|
131
|
+
references resolve to their summaries, descriptions, and values. HTTP(S)
|
|
132
|
+
`externalValue` examples are linked and never fetched by the build.
|
|
133
|
+
- Operations inherit document `security`. An explicit array replaces it;
|
|
134
|
+
`security: []` declares anonymous access. Empty objects allow an anonymous
|
|
135
|
+
alternative. Schemes within an object are required together; array entries
|
|
136
|
+
are alternatives. Scheme details and required scopes appear on each page.
|
|
137
|
+
- Local JSON Pointer references support escaped names and reference chains.
|
|
138
|
+
Reference-only cycles and unknown security schemes produce diagnostics.
|
|
139
|
+
Recursive schema definitions remain visible as JSON references.
|
|
140
|
+
|
|
141
|
+
These follow the [OpenAPI parameter and security rules](https://spec.openapis.org/oas/v3.1.1.html#operation-object).
|
|
142
|
+
Cookbook is not a complete OpenAPI validator or an interactive API client.
|
|
143
|
+
Callbacks, webhooks, link execution, OAuth login flows, multipart editors,
|
|
144
|
+
request serialization, and interactive schema expansion are not implemented.
|
|
145
|
+
Schema JSON is displayed as authored; externally split specs must be bundled
|
|
146
|
+
first. Use an OpenAPI validator alongside `cookbook doctor` for specification
|
|
147
|
+
validation beyond the rendered feature set.
|
|
148
|
+
|
|
123
149
|
## npm package sources
|
|
124
150
|
|
|
125
151
|
Package sources read documentation from the actual npm artifact:
|
|
@@ -48,6 +48,14 @@ export default defineDocsConfig({
|
|
|
48
48
|
});
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
## Keep styling on the server
|
|
52
|
+
|
|
53
|
+
Tasty and Glaze run during build/server rendering. The browser receives extracted
|
|
54
|
+
CSS; never initialize their configuration or ship their runtime in client scripts
|
|
55
|
+
or hydrated islands. Use server-rendered styled components with small client
|
|
56
|
+
scripts for behavior. Cookbook rejects browser imports of its styling API,
|
|
57
|
+
Tasty, and Glaze, including transitive dependencies.
|
|
58
|
+
|
|
51
59
|
## Write styles through Cookbook
|
|
52
60
|
|
|
53
61
|
Import `defineComponent`, `tasty`, `useGlobalStyles`, `resolveComponentStyles`,
|
package/docs/deployment.md
CHANGED
|
@@ -12,12 +12,13 @@ plain file server.
|
|
|
12
12
|
## Build locally
|
|
13
13
|
|
|
14
14
|
```sh
|
|
15
|
-
npm run
|
|
15
|
+
npm run validate
|
|
16
16
|
npm run preview
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
New projects include `validate`: preflight, production build, then built-output
|
|
20
|
+
checks. Existing projects can add this script using the [upgrade guide](./migration.md).
|
|
21
|
+
Run [`cookbook doctor`](./cli.md#validate-with-doctor) for a focused preflight.
|
|
21
22
|
|
|
22
23
|
## GitHub Pages
|
|
23
24
|
|
|
@@ -93,3 +94,19 @@ to the sitemap. Host these files with the rest of `dist/`; custom files in
|
|
|
93
94
|
|
|
94
95
|
Check the deployed HTML, `sitemap-index.xml`, and `llms.txt` through their public
|
|
95
96
|
URLs. See [AI agents](./ai-agents.md) for the setup and reading workflow.
|
|
97
|
+
|
|
98
|
+
For title templates, social images, preview noindex, older-version policies,
|
|
99
|
+
breadcrumbs, and copy-page downloads, see [Publishing metadata](./publishing.md).
|
|
100
|
+
|
|
101
|
+
## Validate the published result
|
|
102
|
+
|
|
103
|
+
New projects include `npm run validate` for preflight, build, and output checks.
|
|
104
|
+
After the host finishes deploying, run:
|
|
105
|
+
|
|
106
|
+
```sh
|
|
107
|
+
npx @tenphi/cookbook check-build --url https://docs.example.com/manual/
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Use your actual deployment URL, including any base path, and the same local
|
|
111
|
+
`dist/` output that was deployed. See [CLI checks](./cli.md#check-the-built-site-and-deployment)
|
|
112
|
+
for the exact coverage, warnings, JSON output, and custom output directories.
|
package/docs/examples.md
CHANGED
|
@@ -19,7 +19,7 @@ export default defineConfig({ integrations: [cookbook()] });
|
|
|
19
19
|
Put this in `docs.config.ts` at the repository root. README/docs discovery is
|
|
20
20
|
automatic; add `content.sources` only when you need different routes or files.
|
|
21
21
|
|
|
22
|
-
```ts
|
|
22
|
+
```ts cookbook-verify=minimal
|
|
23
23
|
import { defineDocsConfig } from "@tenphi/cookbook/config";
|
|
24
24
|
|
|
25
25
|
export default defineDocsConfig({ site: { title: "My library" } });
|
|
@@ -75,7 +75,7 @@ is the npm public registry. Keep credentials out of committed configuration.
|
|
|
75
75
|
|
|
76
76
|
A preset is an ordinary exported `DocsConfig` object:
|
|
77
77
|
|
|
78
|
-
```ts
|
|
78
|
+
```ts cookbook-verify=shared-theme
|
|
79
79
|
import { defineDocsConfig, mergeDocsConfig } from "@tenphi/cookbook/config";
|
|
80
80
|
|
|
81
81
|
const company = defineDocsConfig({
|
|
@@ -99,3 +99,6 @@ Objects merge recursively, arrays replace, and inputs are not mutated. Tasty
|
|
|
99
99
|
styles preserve their default values when adding conditional overrides. A preset
|
|
100
100
|
can live in a shared workspace package. Component overrides remain partial Tasty
|
|
101
101
|
objects and merge into Cookbook's complete base styles inside the renderer.
|
|
102
|
+
|
|
103
|
+
For complete branding, font, locale, and preview configurations, see
|
|
104
|
+
[configuration recipes](./recipes.md).
|