@takazudo/zudo-doc 0.1.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/LICENSE +21 -0
- package/README.md +18 -0
- package/dist/body-foot-util/body-foot-util-area.d.ts +55 -0
- package/dist/body-foot-util/body-foot-util-area.js +71 -0
- package/dist/body-foot-util/edit-link.d.ts +45 -0
- package/dist/body-foot-util/edit-link.js +42 -0
- package/dist/body-foot-util/index.d.ts +3 -0
- package/dist/body-foot-util/index.js +11 -0
- package/dist/breadcrumb/breadcrumb.d.ts +57 -0
- package/dist/breadcrumb/breadcrumb.js +113 -0
- package/dist/breadcrumb/find-path.d.ts +16 -0
- package/dist/breadcrumb/find-path.js +13 -0
- package/dist/breadcrumb/index.d.ts +4 -0
- package/dist/breadcrumb/index.js +7 -0
- package/dist/breadcrumb/types.d.ts +32 -0
- package/dist/breadcrumb/types.js +0 -0
- package/dist/code-syntax/code-block-enhancer-script.d.ts +3 -0
- package/dist/code-syntax/code-block-enhancer-script.js +165 -0
- package/dist/code-syntax/code-block-enhancer.d.ts +22 -0
- package/dist/code-syntax/code-block-enhancer.js +13 -0
- package/dist/code-syntax/index.d.ts +8 -0
- package/dist/code-syntax/index.js +29 -0
- package/dist/code-syntax/mermaid-init-script.d.ts +51 -0
- package/dist/code-syntax/mermaid-init-script.js +225 -0
- package/dist/code-syntax/mermaid-init.d.ts +48 -0
- package/dist/code-syntax/mermaid-init.js +14 -0
- package/dist/code-syntax/tabs-init-script.d.ts +3 -0
- package/dist/code-syntax/tabs-init-script.js +106 -0
- package/dist/code-syntax/tabs-init.d.ts +24 -0
- package/dist/code-syntax/tabs-init.js +10 -0
- package/dist/code-syntax/tabs.d.ts +36 -0
- package/dist/code-syntax/tabs.js +62 -0
- package/dist/content/component-map.d.ts +51 -0
- package/dist/content/component-map.js +29 -0
- package/dist/content/content-blockquote.d.ts +11 -0
- package/dist/content/content-blockquote.js +14 -0
- package/dist/content/content-code.d.ts +26 -0
- package/dist/content/content-code.js +39 -0
- package/dist/content/content-link.d.ts +12 -0
- package/dist/content/content-link.js +43 -0
- package/dist/content/content-ol.d.ts +11 -0
- package/dist/content/content-ol.js +15 -0
- package/dist/content/content-paragraph.d.ts +10 -0
- package/dist/content/content-paragraph.js +7 -0
- package/dist/content/content-strong.d.ts +11 -0
- package/dist/content/content-strong.js +14 -0
- package/dist/content/content-table.d.ts +11 -0
- package/dist/content/content-table.js +14 -0
- package/dist/content/content-ul.d.ts +11 -0
- package/dist/content/content-ul.js +15 -0
- package/dist/content/heading-h2.d.ts +14 -0
- package/dist/content/heading-h2.js +18 -0
- package/dist/content/heading-h3.d.ts +14 -0
- package/dist/content/heading-h3.js +18 -0
- package/dist/content/heading-h4.d.ts +14 -0
- package/dist/content/heading-h4.js +18 -0
- package/dist/content/index.d.ts +13 -0
- package/dist/content/index.js +27 -0
- package/dist/details/details.d.ts +26 -0
- package/dist/details/details.js +10 -0
- package/dist/details/index.d.ts +2 -0
- package/dist/details/index.js +4 -0
- package/dist/doclayout/anchors.d.ts +55 -0
- package/dist/doclayout/anchors.js +42 -0
- package/dist/doclayout/doc-layout-with-defaults.d.ts +83 -0
- package/dist/doclayout/doc-layout-with-defaults.js +159 -0
- package/dist/doclayout/doc-layout.d.ts +121 -0
- package/dist/doclayout/doc-layout.js +89 -0
- package/dist/doclayout/index.d.ts +6 -0
- package/dist/doclayout/index.js +17 -0
- package/dist/footer/footer.d.ts +42 -0
- package/dist/footer/footer.js +79 -0
- package/dist/footer/index.d.ts +3 -0
- package/dist/footer/index.js +4 -0
- package/dist/footer/types.d.ts +58 -0
- package/dist/footer/types.js +0 -0
- package/dist/head/doc-head.d.ts +33 -0
- package/dist/head/doc-head.js +90 -0
- package/dist/head/index.d.ts +5 -0
- package/dist/head/index.js +8 -0
- package/dist/head/og-tags.d.ts +25 -0
- package/dist/head/og-tags.js +16 -0
- package/dist/head/twitter-card.d.ts +21 -0
- package/dist/head/twitter-card.js +14 -0
- package/dist/head/types.d.ts +83 -0
- package/dist/head/types.js +0 -0
- package/dist/header/header.d.ts +158 -0
- package/dist/header/header.js +367 -0
- package/dist/header/index.d.ts +6 -0
- package/dist/header/index.js +18 -0
- package/dist/header/nav-active.d.ts +39 -0
- package/dist/header/nav-active.js +24 -0
- package/dist/header/nav-overflow-script.d.ts +3 -0
- package/dist/header/nav-overflow-script.js +169 -0
- package/dist/header/right-items.d.ts +38 -0
- package/dist/header/right-items.js +30 -0
- package/dist/header/types.d.ts +40 -0
- package/dist/header/types.js +0 -0
- package/dist/html-preview-wrapper/dedent.d.ts +10 -0
- package/dist/html-preview-wrapper/dedent.js +16 -0
- package/dist/html-preview-wrapper/highlighted-code.d.ts +18 -0
- package/dist/html-preview-wrapper/highlighted-code.js +53 -0
- package/dist/html-preview-wrapper/html-preview-wrapper.d.ts +60 -0
- package/dist/html-preview-wrapper/html-preview-wrapper.js +36 -0
- package/dist/html-preview-wrapper/html-preview.d.ts +35 -0
- package/dist/html-preview-wrapper/html-preview.js +75 -0
- package/dist/html-preview-wrapper/index.d.ts +5 -0
- package/dist/html-preview-wrapper/index.js +12 -0
- package/dist/html-preview-wrapper/preflight.d.ts +13 -0
- package/dist/html-preview-wrapper/preflight.js +108 -0
- package/dist/html-preview-wrapper/preview-base.d.ts +29 -0
- package/dist/html-preview-wrapper/preview-base.js +127 -0
- package/dist/i18n-version/index.d.ts +5 -0
- package/dist/i18n-version/index.js +14 -0
- package/dist/i18n-version/language-switcher.d.ts +24 -0
- package/dist/i18n-version/language-switcher.js +25 -0
- package/dist/i18n-version/types.d.ts +43 -0
- package/dist/i18n-version/types.js +0 -0
- package/dist/i18n-version/version-banner.d.ts +30 -0
- package/dist/i18n-version/version-banner.js +21 -0
- package/dist/i18n-version/version-switcher.d.ts +112 -0
- package/dist/i18n-version/version-switcher.js +157 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +0 -0
- package/dist/integrations/claude-resources/escape-for-mdx.d.ts +8 -0
- package/dist/integrations/claude-resources/escape-for-mdx.js +131 -0
- package/dist/integrations/claude-resources/generate.d.ts +13 -0
- package/dist/integrations/claude-resources/generate.js +404 -0
- package/dist/integrations/claude-resources/index.d.ts +46 -0
- package/dist/integrations/claude-resources/index.js +24 -0
- package/dist/integrations/doc-history/index.d.ts +137 -0
- package/dist/integrations/doc-history/index.js +138 -0
- package/dist/integrations/doc-history/pre-build.d.ts +58 -0
- package/dist/integrations/doc-history/pre-build.js +67 -0
- package/dist/integrations/llms-txt/dev-middleware.d.ts +40 -0
- package/dist/integrations/llms-txt/dev-middleware.js +76 -0
- package/dist/integrations/llms-txt/emit.d.ts +22 -0
- package/dist/integrations/llms-txt/emit.js +55 -0
- package/dist/integrations/llms-txt/generate.d.ts +26 -0
- package/dist/integrations/llms-txt/generate.js +36 -0
- package/dist/integrations/llms-txt/index.d.ts +7 -0
- package/dist/integrations/llms-txt/index.js +27 -0
- package/dist/integrations/llms-txt/load.d.ts +51 -0
- package/dist/integrations/llms-txt/load.js +83 -0
- package/dist/integrations/llms-txt/strip.d.ts +22 -0
- package/dist/integrations/llms-txt/strip.js +10 -0
- package/dist/integrations/llms-txt/types.d.ts +145 -0
- package/dist/integrations/llms-txt/types.js +0 -0
- package/dist/integrations/search-index/build-emitter.d.ts +30 -0
- package/dist/integrations/search-index/build-emitter.js +15 -0
- package/dist/integrations/search-index/collect.d.ts +12 -0
- package/dist/integrations/search-index/collect.js +48 -0
- package/dist/integrations/search-index/content-files.d.ts +32 -0
- package/dist/integrations/search-index/content-files.js +50 -0
- package/dist/integrations/search-index/dev-middleware.d.ts +16 -0
- package/dist/integrations/search-index/dev-middleware.js +30 -0
- package/dist/integrations/search-index/index.d.ts +5 -0
- package/dist/integrations/search-index/index.js +14 -0
- package/dist/integrations/search-index/types.d.ts +38 -0
- package/dist/integrations/search-index/types.js +6 -0
- package/dist/metainfo/doc-metainfo.d.ts +50 -0
- package/dist/metainfo/doc-metainfo.js +107 -0
- package/dist/metainfo/doc-tags.d.ts +66 -0
- package/dist/metainfo/doc-tags.js +53 -0
- package/dist/metainfo/frontmatter-preview.d.ts +95 -0
- package/dist/metainfo/frontmatter-preview.js +55 -0
- package/dist/metainfo/index.d.ts +4 -0
- package/dist/metainfo/index.js +28 -0
- package/dist/nav-indexing/category-nav.d.ts +28 -0
- package/dist/nav-indexing/category-nav.js +41 -0
- package/dist/nav-indexing/category-tree-nav.d.ts +27 -0
- package/dist/nav-indexing/category-tree-nav.js +49 -0
- package/dist/nav-indexing/doc-card-grid.d.ts +38 -0
- package/dist/nav-indexing/doc-card-grid.js +40 -0
- package/dist/nav-indexing/docs-sitemap.d.ts +25 -0
- package/dist/nav-indexing/docs-sitemap.js +40 -0
- package/dist/nav-indexing/index.d.ts +10 -0
- package/dist/nav-indexing/index.js +18 -0
- package/dist/nav-indexing/nav-card-grid.d.ts +31 -0
- package/dist/nav-indexing/nav-card-grid.js +43 -0
- package/dist/nav-indexing/site-tree-nav-demo.d.ts +39 -0
- package/dist/nav-indexing/site-tree-nav-demo.js +65 -0
- package/dist/nav-indexing/tag-nav.d.ts +38 -0
- package/dist/nav-indexing/tag-nav.js +96 -0
- package/dist/nav-indexing/types.d.ts +95 -0
- package/dist/nav-indexing/types.js +0 -0
- package/dist/nav-indexing/versions-page-content.d.ts +29 -0
- package/dist/nav-indexing/versions-page-content.js +76 -0
- package/dist/page-loading/index.d.ts +2 -0
- package/dist/page-loading/index.js +10 -0
- package/dist/page-loading/page-loading-overlay.d.ts +35 -0
- package/dist/page-loading/page-loading-overlay.js +50 -0
- package/dist/sidebar/index.d.ts +3 -0
- package/dist/sidebar/index.js +4 -0
- package/dist/sidebar/sidebar.d.ts +54 -0
- package/dist/sidebar/sidebar.js +35 -0
- package/dist/sidebar/types.d.ts +71 -0
- package/dist/sidebar/types.js +0 -0
- package/dist/sidebar-resizer/index.d.ts +14 -0
- package/dist/sidebar-resizer/index.js +165 -0
- package/dist/sidebar-resizer/sidebar-resizer-init.d.ts +20 -0
- package/dist/sidebar-resizer/sidebar-resizer-init.js +119 -0
- package/dist/sidebar-tree/build-tree.d.ts +43 -0
- package/dist/sidebar-tree/build-tree.js +127 -0
- package/dist/sidebar-tree/category-meta.d.ts +19 -0
- package/dist/sidebar-tree/category-meta.js +63 -0
- package/dist/sidebar-tree/index.d.ts +3 -0
- package/dist/sidebar-tree/index.js +13 -0
- package/dist/sidebar-tree/types.d.ts +120 -0
- package/dist/sidebar-tree/types.js +0 -0
- package/dist/tab-item/index.d.ts +2 -0
- package/dist/tab-item/index.js +5 -0
- package/dist/tab-item/tab-item.d.ts +38 -0
- package/dist/tab-item/tab-item.js +25 -0
- package/dist/theme/color-scheme-provider.d.ts +32 -0
- package/dist/theme/color-scheme-provider.js +43 -0
- package/dist/theme/color-tweak-export-modal.d.ts +20 -0
- package/dist/theme/color-tweak-export-modal.js +138 -0
- package/dist/theme/design-token-serde.d.ts +136 -0
- package/dist/theme/design-token-serde.js +254 -0
- package/dist/theme/design-token-tweak-panel.d.ts +11 -0
- package/dist/theme/design-token-tweak-panel.js +10 -0
- package/dist/theme/design-token-types.d.ts +19 -0
- package/dist/theme/design-token-types.js +6 -0
- package/dist/theme/iframe-bridge.d.ts +44 -0
- package/dist/theme/iframe-bridge.js +70 -0
- package/dist/theme/index.d.ts +9 -0
- package/dist/theme/index.js +42 -0
- package/dist/theme/theme-toggle.d.ts +17 -0
- package/dist/theme/theme-toggle.js +91 -0
- package/dist/toc/cx.d.ts +16 -0
- package/dist/toc/cx.js +22 -0
- package/dist/toc/index.d.ts +5 -0
- package/dist/toc/index.js +9 -0
- package/dist/toc/mobile-toc.d.ts +46 -0
- package/dist/toc/mobile-toc.js +88 -0
- package/dist/toc/smart-break.d.ts +27 -0
- package/dist/toc/smart-break.js +36 -0
- package/dist/toc/toc-title.d.ts +10 -0
- package/dist/toc/toc-title.js +14 -0
- package/dist/toc/toc.d.ts +60 -0
- package/dist/toc/toc.js +56 -0
- package/dist/toc/types.d.ts +23 -0
- package/dist/toc/types.js +0 -0
- package/dist/toc/use-active-heading.d.ts +30 -0
- package/dist/toc/use-active-heading.js +106 -0
- package/dist/transitions/index.d.ts +1 -0
- package/dist/transitions/index.js +12 -0
- package/dist/transitions/page-events.d.ts +41 -0
- package/dist/transitions/page-events.js +20 -0
- package/dist/url-normalizer/index.d.ts +1 -0
- package/dist/url-normalizer/index.js +6 -0
- package/dist/url-normalizer/normalize.d.ts +104 -0
- package/dist/url-normalizer/normalize.js +22 -0
- package/package.json +186 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { dirname, join, resolve as resolvePath } from "node:path";
|
|
4
|
+
import {
|
|
5
|
+
runDocHistoryMetaStep
|
|
6
|
+
} from "./pre-build.js";
|
|
7
|
+
const DEFAULT_SERVER_PORT = 4322;
|
|
8
|
+
const DEFAULT_MAX_ENTRIES = 50;
|
|
9
|
+
const DOC_HISTORY_ROUTE_PREFIX = "/doc-history/";
|
|
10
|
+
const DOC_HISTORY_OUTPUT_DIRNAME = "doc-history";
|
|
11
|
+
const DOC_HISTORY_GENERATE_BIN = "doc-history-generate";
|
|
12
|
+
function docHistoryPlugin(options) {
|
|
13
|
+
return { name: "doc-history", options };
|
|
14
|
+
}
|
|
15
|
+
function createDocHistoryDevMiddleware(options, logger) {
|
|
16
|
+
const port = options.serverPort ?? DEFAULT_SERVER_PORT;
|
|
17
|
+
return (req, res, next) => {
|
|
18
|
+
const url = req.url ?? "";
|
|
19
|
+
if (!url.includes(DOC_HISTORY_ROUTE_PREFIX)) {
|
|
20
|
+
next();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const idx = url.indexOf(DOC_HISTORY_ROUTE_PREFIX);
|
|
24
|
+
const proxyPath = url.slice(idx);
|
|
25
|
+
const proxyUrl = `http://localhost:${port}${proxyPath}`;
|
|
26
|
+
fetch(proxyUrl).then(async (upstream) => {
|
|
27
|
+
res.statusCode = upstream.status;
|
|
28
|
+
res.setHeader(
|
|
29
|
+
"Content-Type",
|
|
30
|
+
upstream.headers.get("content-type") ?? "application/json"
|
|
31
|
+
);
|
|
32
|
+
const body = await upstream.text();
|
|
33
|
+
res.end(body);
|
|
34
|
+
}).catch((err) => {
|
|
35
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
36
|
+
logger?.warn(
|
|
37
|
+
`Doc history proxy failed: ${msg}. Is the doc-history server running on port ${port}?`
|
|
38
|
+
);
|
|
39
|
+
res.statusCode = 502;
|
|
40
|
+
res.setHeader("Content-Type", "application/json");
|
|
41
|
+
res.end(
|
|
42
|
+
JSON.stringify({
|
|
43
|
+
error: `Doc history server unavailable (port ${port})`
|
|
44
|
+
})
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async function runDocHistoryPostBuild(options, ctx) {
|
|
50
|
+
if (process.env.SKIP_DOC_HISTORY === "1") {
|
|
51
|
+
ctx.logger?.info("Skipping doc history generation (SKIP_DOC_HISTORY=1)");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const args = buildGenerateCliArgs(options, ctx.outDir);
|
|
55
|
+
await spawnDocHistoryGenerate(args, ctx.logger);
|
|
56
|
+
}
|
|
57
|
+
function buildGenerateCliArgs(options, outDir) {
|
|
58
|
+
const historyOut = join(outDir, DOC_HISTORY_OUTPUT_DIRNAME);
|
|
59
|
+
const args = [
|
|
60
|
+
"--content-dir",
|
|
61
|
+
options.docsDir,
|
|
62
|
+
"--out-dir",
|
|
63
|
+
historyOut
|
|
64
|
+
];
|
|
65
|
+
if (options.locales) {
|
|
66
|
+
for (const [key, locale] of Object.entries(options.locales)) {
|
|
67
|
+
args.push("--locale", `${key}:${locale.dir}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (options.maxEntries != null) {
|
|
71
|
+
args.push("--max-entries", String(options.maxEntries));
|
|
72
|
+
}
|
|
73
|
+
return args;
|
|
74
|
+
}
|
|
75
|
+
function resolveDocHistoryGenerateBin() {
|
|
76
|
+
const localRequire = createRequire(import.meta.url);
|
|
77
|
+
const pkgJsonPath = localRequire.resolve(
|
|
78
|
+
"@takazudo/zudo-doc-history-server/package.json"
|
|
79
|
+
);
|
|
80
|
+
const pkgJson = localRequire(
|
|
81
|
+
"@takazudo/zudo-doc-history-server/package.json"
|
|
82
|
+
);
|
|
83
|
+
const binEntry = typeof pkgJson.bin === "string" ? pkgJson.bin : pkgJson.bin?.[DOC_HISTORY_GENERATE_BIN];
|
|
84
|
+
if (!binEntry) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`@takazudo/zudo-doc-history-server does not declare a '${DOC_HISTORY_GENERATE_BIN}' bin entry`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
return resolvePath(dirname(pkgJsonPath), binEntry);
|
|
90
|
+
}
|
|
91
|
+
function spawnDocHistoryGenerate(args, logger) {
|
|
92
|
+
return new Promise((resolveSpawn, reject) => {
|
|
93
|
+
let cliPath;
|
|
94
|
+
try {
|
|
95
|
+
cliPath = resolveDocHistoryGenerateBin();
|
|
96
|
+
} catch (err) {
|
|
97
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
98
|
+
logger?.warn(
|
|
99
|
+
`Failed to resolve ${DOC_HISTORY_GENERATE_BIN} from @takazudo/zudo-doc-history-server: ${msg}`
|
|
100
|
+
);
|
|
101
|
+
reject(err instanceof Error ? err : new Error(msg));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const child = spawn(process.execPath, [cliPath, ...args], {
|
|
105
|
+
stdio: "inherit",
|
|
106
|
+
shell: false
|
|
107
|
+
});
|
|
108
|
+
child.on("error", (err) => {
|
|
109
|
+
logger?.warn(
|
|
110
|
+
`Failed to launch ${DOC_HISTORY_GENERATE_BIN}: ${err.message}`
|
|
111
|
+
);
|
|
112
|
+
reject(err);
|
|
113
|
+
});
|
|
114
|
+
child.on("exit", (code, signal) => {
|
|
115
|
+
if (code === 0) {
|
|
116
|
+
resolveSpawn();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const reason = code != null ? `exit code ${code}` : `signal ${signal ?? "unknown"}`;
|
|
120
|
+
reject(
|
|
121
|
+
new Error(`${DOC_HISTORY_GENERATE_BIN} failed (${reason})`)
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
export {
|
|
127
|
+
DEFAULT_MAX_ENTRIES,
|
|
128
|
+
DEFAULT_SERVER_PORT,
|
|
129
|
+
DOC_HISTORY_GENERATE_BIN,
|
|
130
|
+
DOC_HISTORY_OUTPUT_DIRNAME,
|
|
131
|
+
DOC_HISTORY_ROUTE_PREFIX,
|
|
132
|
+
buildGenerateCliArgs,
|
|
133
|
+
createDocHistoryDevMiddleware,
|
|
134
|
+
docHistoryPlugin,
|
|
135
|
+
resolveDocHistoryGenerateBin,
|
|
136
|
+
runDocHistoryMetaStep,
|
|
137
|
+
runDocHistoryPostBuild
|
|
138
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** A single non-default locale entry; mirrors `settings.locales[*]`. */
|
|
2
|
+
interface DocHistoryMetaLocaleConfig {
|
|
3
|
+
/** Absolute or project-relative directory holding this locale's MDX content. */
|
|
4
|
+
dir: string;
|
|
5
|
+
}
|
|
6
|
+
/** A versioned docs entry; mirrors `settings.versions[*]`. */
|
|
7
|
+
interface DocHistoryMetaVersionConfig {
|
|
8
|
+
/** Slug used to namespace the version (e.g. `"1.0"`). */
|
|
9
|
+
slug: string;
|
|
10
|
+
/** Default-locale content directory for this version. */
|
|
11
|
+
docsDir: string;
|
|
12
|
+
/** Optional non-default locales, keyed by locale code. */
|
|
13
|
+
locales?: Record<string, DocHistoryMetaLocaleConfig>;
|
|
14
|
+
}
|
|
15
|
+
/** Options accepted by the preBuild runner. */
|
|
16
|
+
interface RunDocHistoryMetaOptions {
|
|
17
|
+
/** Project root — directory containing `zfb.config.ts`. Resolves all relative paths. */
|
|
18
|
+
projectRoot: string;
|
|
19
|
+
/** Default-locale content directory (e.g. `"src/content/docs"`). */
|
|
20
|
+
docsDir: string;
|
|
21
|
+
/** Optional non-default locales, keyed by locale code. */
|
|
22
|
+
locales?: Record<string, DocHistoryMetaLocaleConfig>;
|
|
23
|
+
/**
|
|
24
|
+
* Optional versioned docs (e.g. legacy `1.0`). Each version produces
|
|
25
|
+
* its own default-locale collection plus per-locale variants.
|
|
26
|
+
* Currently unused by the host's emitted manifest (parity with
|
|
27
|
+
* `scripts/zfb-prebuild.mjs`) — accepted here so callers can pass
|
|
28
|
+
* versions through without ad-hoc filtering.
|
|
29
|
+
*/
|
|
30
|
+
versions?: DocHistoryMetaVersionConfig[];
|
|
31
|
+
/** Optional logger. Falls back to `console`. */
|
|
32
|
+
logger?: {
|
|
33
|
+
info(msg: string): void;
|
|
34
|
+
warn?(msg: string): void;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** A single manifest entry. */
|
|
38
|
+
interface DocHistoryMetaEntry {
|
|
39
|
+
author: string;
|
|
40
|
+
createdDate: string;
|
|
41
|
+
updatedDate: string;
|
|
42
|
+
}
|
|
43
|
+
/** Manifest shape — keyed by composedSlug. */
|
|
44
|
+
type DocHistoryMetaManifest = Record<string, DocHistoryMetaEntry>;
|
|
45
|
+
/**
|
|
46
|
+
* Emit `<projectRoot>/.zfb/doc-history-meta.json` from git history.
|
|
47
|
+
*
|
|
48
|
+
* Honours the `SKIP_DOC_HISTORY=1` env-var short-circuit (see header
|
|
49
|
+
* comment for the CI contract). Writes a byte-identical empty manifest
|
|
50
|
+
* (`{}\n`) when set; writes a sorted-key JSON document otherwise.
|
|
51
|
+
*
|
|
52
|
+
* Skips files with no git history (untracked / not yet committed) by
|
|
53
|
+
* omitting them from the manifest — the page-side wrapper treats
|
|
54
|
+
* undefined entries as "no SSR data".
|
|
55
|
+
*/
|
|
56
|
+
declare function runDocHistoryMetaStep(options: RunDocHistoryMetaOptions): Promise<void>;
|
|
57
|
+
|
|
58
|
+
export { type DocHistoryMetaEntry, type DocHistoryMetaLocaleConfig, type DocHistoryMetaManifest, type DocHistoryMetaVersionConfig, type RunDocHistoryMetaOptions, runDocHistoryMetaStep };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
collectContentFiles,
|
|
5
|
+
getFileCommits,
|
|
6
|
+
getFirstCommit,
|
|
7
|
+
getCommitInfo
|
|
8
|
+
} from "@takazudo/zudo-doc-history-server/git-history";
|
|
9
|
+
const META_OUT_RELATIVE_DIR = ".zfb";
|
|
10
|
+
const META_OUT_FILENAME = "doc-history-meta.json";
|
|
11
|
+
async function runDocHistoryMetaStep(options) {
|
|
12
|
+
const projectRoot = path.resolve(options.projectRoot);
|
|
13
|
+
const zfbDir = path.join(projectRoot, META_OUT_RELATIVE_DIR);
|
|
14
|
+
const outPath = path.join(zfbDir, META_OUT_FILENAME);
|
|
15
|
+
const logger = options.logger ?? defaultLogger;
|
|
16
|
+
if (process.env.SKIP_DOC_HISTORY === "1") {
|
|
17
|
+
logger.info(
|
|
18
|
+
"[doc-history-meta] SKIP_DOC_HISTORY=1 \u2014 emitting empty doc-history-meta.json"
|
|
19
|
+
);
|
|
20
|
+
fs.mkdirSync(zfbDir, { recursive: true });
|
|
21
|
+
fs.writeFileSync(outPath, "{}\n", "utf-8");
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const dirEntries = [
|
|
25
|
+
[null, path.resolve(projectRoot, options.docsDir)]
|
|
26
|
+
];
|
|
27
|
+
if (options.locales) {
|
|
28
|
+
for (const [code, locale] of Object.entries(options.locales)) {
|
|
29
|
+
dirEntries.push([code, path.resolve(projectRoot, locale.dir)]);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const meta = {};
|
|
33
|
+
for (const [localeKey, contentDir] of dirEntries) {
|
|
34
|
+
const files = collectContentFiles(contentDir);
|
|
35
|
+
for (const { filePath, slug } of files) {
|
|
36
|
+
const commits = getFileCommits(filePath, 1);
|
|
37
|
+
if (commits.length === 0) continue;
|
|
38
|
+
const newestInfo = getCommitInfo(commits[0], filePath);
|
|
39
|
+
const firstHash = getFirstCommit(filePath);
|
|
40
|
+
const oldestInfo = firstHash && firstHash !== commits[0] ? getCommitInfo(firstHash, filePath) : newestInfo;
|
|
41
|
+
const composedSlug = localeKey ? `${localeKey}/${slug}` : slug;
|
|
42
|
+
meta[composedSlug] = {
|
|
43
|
+
// Author comes from the FIRST (oldest) commit.
|
|
44
|
+
author: oldestInfo.author,
|
|
45
|
+
// createdDate = oldest commit; updatedDate = newest commit.
|
|
46
|
+
createdDate: oldestInfo.date,
|
|
47
|
+
updatedDate: newestInfo.date
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
fs.mkdirSync(zfbDir, { recursive: true });
|
|
52
|
+
fs.writeFileSync(outPath, JSON.stringify(meta, null, 2) + "\n", "utf-8");
|
|
53
|
+
logger.info(
|
|
54
|
+
`[doc-history-meta] wrote ${Object.keys(meta).length} entries \u2192 .zfb/doc-history-meta.json`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
const defaultLogger = {
|
|
58
|
+
info(msg) {
|
|
59
|
+
console.log(msg);
|
|
60
|
+
},
|
|
61
|
+
warn(msg) {
|
|
62
|
+
console.warn(msg);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
export {
|
|
66
|
+
runDocHistoryMetaStep
|
|
67
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import { LlmsTxtSiteMeta, LlmsTxtLocaleConfig } from './types.js';
|
|
3
|
+
|
|
4
|
+
/** Connect-style middleware signature — works as a Vite plugin middleware. */
|
|
5
|
+
type LlmsTxtNextFn = (err?: unknown) => void;
|
|
6
|
+
type LlmsTxtMiddleware = (req: IncomingMessage, res: ServerResponse, next: LlmsTxtNextFn) => void;
|
|
7
|
+
/** Minimal logger surface used by the middleware on generation failure. */
|
|
8
|
+
interface LlmsTxtMiddlewareLogger {
|
|
9
|
+
warn(msg: string): void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Build-time + dev-time options. Mirrors {@link LlmsTxtEmitOptions}
|
|
13
|
+
* minus the `outDir` field (the dev middleware never writes to disk)
|
|
14
|
+
* so callers can hand a single options object to both `emitLlmsTxt`
|
|
15
|
+
* (build) and `createLlmsTxtDevMiddleware` (dev).
|
|
16
|
+
*/
|
|
17
|
+
interface LlmsTxtDevMiddlewareOptions extends LlmsTxtSiteMeta {
|
|
18
|
+
/** URL base used when materialising per-page links. */
|
|
19
|
+
base: string;
|
|
20
|
+
/** Optional absolute site URL; see `LlmsTxtLoadOptions.siteUrl`. */
|
|
21
|
+
siteUrl?: string;
|
|
22
|
+
/** Default-locale content directory. */
|
|
23
|
+
defaultLocaleDir: string;
|
|
24
|
+
/** Additional locales (e.g. `[{ code: "ja", dir: "src/content/docs-ja" }]`). */
|
|
25
|
+
locales?: LlmsTxtLocaleConfig[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Build a dev-server middleware that responds to GET requests for
|
|
29
|
+
* `/llms.txt`, `/llms-full.txt`, `/<code>/llms.txt`, and
|
|
30
|
+
* `/<code>/llms-full.txt`. Unknown locale prefixes fall through (the
|
|
31
|
+
* chain returns 404), avoiding collisions with future routes that
|
|
32
|
+
* might share the `/<thing>/llms.txt` shape.
|
|
33
|
+
*
|
|
34
|
+
* Every request rebuilds the entries from disk — the same pattern the
|
|
35
|
+
* sibling `searchIndex` middleware uses — so authoring loops surface
|
|
36
|
+
* content edits without a dev-server restart.
|
|
37
|
+
*/
|
|
38
|
+
declare function createLlmsTxtDevMiddleware(options: LlmsTxtDevMiddlewareOptions, logger?: LlmsTxtMiddlewareLogger): LlmsTxtMiddleware;
|
|
39
|
+
|
|
40
|
+
export { type LlmsTxtDevMiddlewareOptions, type LlmsTxtMiddleware, type LlmsTxtMiddlewareLogger, type LlmsTxtNextFn, createLlmsTxtDevMiddleware };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { generateLlmsFullTxt, generateLlmsTxt } from "./generate.js";
|
|
2
|
+
import { loadDocEntries } from "./load.js";
|
|
3
|
+
const LLMS_KIND_PATTERN = /^(?:\/(.+?))?\/(llms|llms-full)\.txt$/;
|
|
4
|
+
function createLlmsTxtDevMiddleware(options, logger) {
|
|
5
|
+
const meta = {
|
|
6
|
+
siteName: options.siteName,
|
|
7
|
+
siteDescription: options.siteDescription
|
|
8
|
+
};
|
|
9
|
+
const localeCodes = new Set((options.locales ?? []).map((l) => l.code));
|
|
10
|
+
const localeDirByCode = new Map(
|
|
11
|
+
(options.locales ?? []).map((l) => [l.code, l.dir])
|
|
12
|
+
);
|
|
13
|
+
const base = options.base ?? "";
|
|
14
|
+
const siteUrl = options.siteUrl || void 0;
|
|
15
|
+
return (req, res, next) => {
|
|
16
|
+
const url = req.url ?? "";
|
|
17
|
+
const match = matchLlmsRoute(stripBase(url, base), localeCodes);
|
|
18
|
+
if (!match) {
|
|
19
|
+
next();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (req.method && req.method !== "GET" && req.method !== "HEAD") {
|
|
23
|
+
res.statusCode = 405;
|
|
24
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
25
|
+
res.end("Method Not Allowed");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const contentDir = match.locale === null ? options.defaultLocaleDir : localeDirByCode.get(match.locale);
|
|
30
|
+
if (contentDir === void 0) {
|
|
31
|
+
res.statusCode = 404;
|
|
32
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
33
|
+
res.end("Not Found");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const entries = loadDocEntries({
|
|
37
|
+
contentDir,
|
|
38
|
+
locale: match.locale,
|
|
39
|
+
base,
|
|
40
|
+
siteUrl
|
|
41
|
+
});
|
|
42
|
+
const body = match.kind === "llms" ? generateLlmsTxt(entries, meta) : generateLlmsFullTxt(entries, meta);
|
|
43
|
+
res.statusCode = 200;
|
|
44
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
45
|
+
res.end(body);
|
|
46
|
+
} catch (err) {
|
|
47
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
48
|
+
logger?.warn(`llms-txt generation failed: ${msg}`);
|
|
49
|
+
res.statusCode = 500;
|
|
50
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
51
|
+
res.end("Internal Server Error");
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function matchLlmsRoute(url, localeCodes) {
|
|
56
|
+
const pathname = url.split("?")[0];
|
|
57
|
+
const m = pathname.match(LLMS_KIND_PATTERN);
|
|
58
|
+
if (!m) return null;
|
|
59
|
+
const prefix = m[1];
|
|
60
|
+
const kind = m[2];
|
|
61
|
+
if (prefix === void 0) return { kind, locale: null };
|
|
62
|
+
if (localeCodes.has(prefix)) return { kind, locale: prefix };
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
function stripBase(url, base) {
|
|
66
|
+
if (!base || base === "/") return url;
|
|
67
|
+
const normalised = base.endsWith("/") ? base.slice(0, -1) : base;
|
|
68
|
+
if (url.startsWith(normalised + "/")) {
|
|
69
|
+
return url.slice(normalised.length);
|
|
70
|
+
}
|
|
71
|
+
if (url === normalised) return "/";
|
|
72
|
+
return url;
|
|
73
|
+
}
|
|
74
|
+
export {
|
|
75
|
+
createLlmsTxtDevMiddleware
|
|
76
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { LlmsTxtEmitOptions, LlmsTxtEmitResult } from './types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Build-time emitter that writes `llms.txt` and `llms-full.txt` for the
|
|
5
|
+
* default locale plus every additional locale.
|
|
6
|
+
*
|
|
7
|
+
* Designed as a zfb-shaped build hook: the function takes a single
|
|
8
|
+
* options object, performs synchronous fs writes, and returns the list
|
|
9
|
+
* of files it produced. Adapters wrap it for their build system —
|
|
10
|
+
* Astro's `astro:build:done`, a future zfb plugin's `onBuildDone`,
|
|
11
|
+
* a Node CLI in CI, etc.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Walk every configured content root, generate the two files per
|
|
16
|
+
* locale, and write them to `outDir` (default locale) and
|
|
17
|
+
* `outDir/<code>/` (additional locales). The output directory is
|
|
18
|
+
* created if needed; existing files are overwritten.
|
|
19
|
+
*/
|
|
20
|
+
declare function emitLlmsTxt(options: LlmsTxtEmitOptions): LlmsTxtEmitResult;
|
|
21
|
+
|
|
22
|
+
export { emitLlmsTxt };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { generateLlmsFullTxt, generateLlmsTxt } from "./generate.js";
|
|
4
|
+
import { loadDocEntries } from "./load.js";
|
|
5
|
+
function emitLlmsTxt(options) {
|
|
6
|
+
const {
|
|
7
|
+
outDir,
|
|
8
|
+
base,
|
|
9
|
+
siteUrl,
|
|
10
|
+
siteName,
|
|
11
|
+
siteDescription,
|
|
12
|
+
defaultLocaleDir,
|
|
13
|
+
locales = [],
|
|
14
|
+
logger
|
|
15
|
+
} = options;
|
|
16
|
+
const meta = { siteName, siteDescription };
|
|
17
|
+
const written = [];
|
|
18
|
+
const defaultEntries = loadDocEntries({
|
|
19
|
+
contentDir: defaultLocaleDir,
|
|
20
|
+
locale: null,
|
|
21
|
+
base,
|
|
22
|
+
siteUrl
|
|
23
|
+
});
|
|
24
|
+
mkdirSync(outDir, { recursive: true });
|
|
25
|
+
const defaultIndexPath = join(outDir, "llms.txt");
|
|
26
|
+
const defaultFullPath = join(outDir, "llms-full.txt");
|
|
27
|
+
writeFileSync(defaultIndexPath, generateLlmsTxt(defaultEntries, meta));
|
|
28
|
+
writeFileSync(defaultFullPath, generateLlmsFullTxt(defaultEntries, meta));
|
|
29
|
+
written.push(defaultIndexPath, defaultFullPath);
|
|
30
|
+
logger?.info(
|
|
31
|
+
`Generated llms.txt and llms-full.txt (${defaultEntries.length} pages)`
|
|
32
|
+
);
|
|
33
|
+
for (const { code, dir } of locales) {
|
|
34
|
+
const localeEntries = loadDocEntries({
|
|
35
|
+
contentDir: dir,
|
|
36
|
+
locale: code,
|
|
37
|
+
base,
|
|
38
|
+
siteUrl
|
|
39
|
+
});
|
|
40
|
+
const localeDir = join(outDir, code);
|
|
41
|
+
mkdirSync(localeDir, { recursive: true });
|
|
42
|
+
const indexPath = join(localeDir, "llms.txt");
|
|
43
|
+
const fullPath = join(localeDir, "llms-full.txt");
|
|
44
|
+
writeFileSync(indexPath, generateLlmsTxt(localeEntries, meta));
|
|
45
|
+
writeFileSync(fullPath, generateLlmsFullTxt(localeEntries, meta));
|
|
46
|
+
written.push(indexPath, fullPath);
|
|
47
|
+
logger?.info(
|
|
48
|
+
`Generated ${code}/llms.txt and ${code}/llms-full.txt (${localeEntries.length} pages)`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
return { written };
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
emitLlmsTxt
|
|
55
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { LlmsDocEntry, LlmsTxtSiteMeta } from './types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pure string generators for `llms.txt` and `llms-full.txt`.
|
|
5
|
+
*
|
|
6
|
+
* Both functions are intentionally pure (no fs, no logger, no globals)
|
|
7
|
+
* so they can be unit-tested with fixture entries and so a future zfb
|
|
8
|
+
* non-HTML page (`pages/llms.txt.tsx`) can call them straight from a
|
|
9
|
+
* default export without a build-time hook.
|
|
10
|
+
*
|
|
11
|
+
* Output format must remain byte-identical to the legacy Astro emitter
|
|
12
|
+
* — the file shape is part of the project's public surface.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Slim index — site header followed by a markdown bullet per page with
|
|
17
|
+
* `[title](url): description`.
|
|
18
|
+
*/
|
|
19
|
+
declare function generateLlmsTxt(entries: readonly LlmsDocEntry[], meta: LlmsTxtSiteMeta): string;
|
|
20
|
+
/**
|
|
21
|
+
* Full content concatenation — site header followed by every page's
|
|
22
|
+
* stripped body separated by `---` rules.
|
|
23
|
+
*/
|
|
24
|
+
declare function generateLlmsFullTxt(entries: readonly LlmsDocEntry[], meta: LlmsTxtSiteMeta): string;
|
|
25
|
+
|
|
26
|
+
export { generateLlmsFullTxt, generateLlmsTxt };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
function generateLlmsTxt(entries, meta) {
|
|
2
|
+
const lines = [];
|
|
3
|
+
lines.push(`# ${meta.siteName}`);
|
|
4
|
+
lines.push("");
|
|
5
|
+
lines.push(`> ${meta.siteDescription}`);
|
|
6
|
+
lines.push("");
|
|
7
|
+
lines.push("## Docs");
|
|
8
|
+
lines.push("");
|
|
9
|
+
for (const entry of entries) {
|
|
10
|
+
lines.push(`- [${entry.title}](${entry.url}): ${entry.description}`);
|
|
11
|
+
}
|
|
12
|
+
lines.push("");
|
|
13
|
+
return lines.join("\n");
|
|
14
|
+
}
|
|
15
|
+
function generateLlmsFullTxt(entries, meta) {
|
|
16
|
+
const lines = [];
|
|
17
|
+
lines.push(`# ${meta.siteName}`);
|
|
18
|
+
lines.push("");
|
|
19
|
+
lines.push(`> ${meta.siteDescription}`);
|
|
20
|
+
for (const entry of entries) {
|
|
21
|
+
lines.push("");
|
|
22
|
+
lines.push("---");
|
|
23
|
+
lines.push("");
|
|
24
|
+
lines.push(`# ${entry.title}`);
|
|
25
|
+
lines.push("");
|
|
26
|
+
lines.push(`> Source: ${entry.url}`);
|
|
27
|
+
lines.push("");
|
|
28
|
+
lines.push(entry.content);
|
|
29
|
+
}
|
|
30
|
+
lines.push("");
|
|
31
|
+
return lines.join("\n");
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
generateLlmsFullTxt,
|
|
35
|
+
generateLlmsTxt
|
|
36
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { LlmsTxtDevMiddlewareOptions, LlmsTxtMiddleware, LlmsTxtMiddlewareLogger, LlmsTxtNextFn, createLlmsTxtDevMiddleware } from './dev-middleware.js';
|
|
2
|
+
export { emitLlmsTxt } from './emit.js';
|
|
3
|
+
export { generateLlmsFullTxt, generateLlmsTxt } from './generate.js';
|
|
4
|
+
export { collectMdFiles, isExcluded, loadDocEntries, parseMarkdownFile, slugToUrl } from './load.js';
|
|
5
|
+
export { stripImportsAndJsx, stripMarkdown } from './strip.js';
|
|
6
|
+
export { LlmsDocEntry, LlmsTxtEmitOptions, LlmsTxtEmitResult, LlmsTxtFrontmatter, LlmsTxtLoadOptions, LlmsTxtLocaleConfig, LlmsTxtLogger, LlmsTxtSiteMeta } from './types.js';
|
|
7
|
+
import 'node:http';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createLlmsTxtDevMiddleware } from "./dev-middleware.js";
|
|
2
|
+
import { emitLlmsTxt } from "./emit.js";
|
|
3
|
+
import {
|
|
4
|
+
generateLlmsFullTxt,
|
|
5
|
+
generateLlmsTxt
|
|
6
|
+
} from "./generate.js";
|
|
7
|
+
import {
|
|
8
|
+
collectMdFiles,
|
|
9
|
+
isExcluded,
|
|
10
|
+
loadDocEntries,
|
|
11
|
+
parseMarkdownFile,
|
|
12
|
+
slugToUrl
|
|
13
|
+
} from "./load.js";
|
|
14
|
+
import { stripImportsAndJsx, stripMarkdown } from "./strip.js";
|
|
15
|
+
export {
|
|
16
|
+
collectMdFiles,
|
|
17
|
+
createLlmsTxtDevMiddleware,
|
|
18
|
+
emitLlmsTxt,
|
|
19
|
+
generateLlmsFullTxt,
|
|
20
|
+
generateLlmsTxt,
|
|
21
|
+
isExcluded,
|
|
22
|
+
loadDocEntries,
|
|
23
|
+
parseMarkdownFile,
|
|
24
|
+
slugToUrl,
|
|
25
|
+
stripImportsAndJsx,
|
|
26
|
+
stripMarkdown
|
|
27
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { LlmsTxtFrontmatter, LlmsTxtLoadOptions, LlmsDocEntry } from './types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Filesystem loader for llms-txt content. Walks a markdown content root,
|
|
5
|
+
* parses frontmatter via `gray-matter`, and emits sorted
|
|
6
|
+
* {@link LlmsDocEntry} records ready for the generator stage.
|
|
7
|
+
*
|
|
8
|
+
* Lives in the framework layer (no `@/...` imports) so any consumer
|
|
9
|
+
* project — Astro today, zfb tomorrow, fixture-driven unit tests in
|
|
10
|
+
* between — can drive the emitter without dragging in the legacy
|
|
11
|
+
* `src/utils/content-files.ts` module.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Walk `dir` recursively and return every `*.md` / `*.mdx` file's
|
|
16
|
+
* absolute path together with its docs-relative slug. Files (or whole
|
|
17
|
+
* directories) whose name starts with `_` are skipped, matching the
|
|
18
|
+
* Content Collections convention.
|
|
19
|
+
*/
|
|
20
|
+
declare function collectMdFiles(dir: string): Array<{
|
|
21
|
+
filePath: string;
|
|
22
|
+
slug: string;
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Compute a docs URL for a given slug + locale. Mirrors the legacy
|
|
26
|
+
* `slugToUrl(slug, locale, true)` call site exactly: when `siteUrl` is
|
|
27
|
+
* empty, the URL is path-only; when `siteUrl` is set, a fully qualified
|
|
28
|
+
* URL is produced.
|
|
29
|
+
*/
|
|
30
|
+
declare function slugToUrl(slug: string, locale: string | null, base: string, siteUrl?: string): string;
|
|
31
|
+
/** Whether a given doc should be excluded from the llms.txt index. */
|
|
32
|
+
declare function isExcluded(data: LlmsTxtFrontmatter): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Parse a markdown file into frontmatter + body. Returns `null` when
|
|
35
|
+
* the file is unreadable so callers can simply skip it.
|
|
36
|
+
*/
|
|
37
|
+
declare function parseMarkdownFile(filePath: string): {
|
|
38
|
+
data: LlmsTxtFrontmatter;
|
|
39
|
+
content: string;
|
|
40
|
+
} | null;
|
|
41
|
+
/**
|
|
42
|
+
* Build the sorted {@link LlmsDocEntry} list for a single content root.
|
|
43
|
+
* Excluded pages (draft / unlisted / search_exclude) are dropped.
|
|
44
|
+
* Entries are sorted ascending by `sidebar_position`; entries without a
|
|
45
|
+
* position go last (they share `Number.MAX_SAFE_INTEGER`, and
|
|
46
|
+
* `Array.prototype.sort` is stable in V8 so ties keep filesystem
|
|
47
|
+
* traversal order — same as the legacy emitter).
|
|
48
|
+
*/
|
|
49
|
+
declare function loadDocEntries(options: LlmsTxtLoadOptions): LlmsDocEntry[];
|
|
50
|
+
|
|
51
|
+
export { collectMdFiles, isExcluded, loadDocEntries, parseMarkdownFile, slugToUrl };
|