@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,83 @@
|
|
|
1
|
+
import { readFileSync, readdirSync } from "node:fs";
|
|
2
|
+
import { join, relative, resolve } from "node:path";
|
|
3
|
+
import matter from "gray-matter";
|
|
4
|
+
import { stripImportsAndJsx, stripMarkdown } from "./strip.js";
|
|
5
|
+
function collectMdFiles(dir) {
|
|
6
|
+
const results = [];
|
|
7
|
+
function walk(currentDir, baseDir) {
|
|
8
|
+
let entries;
|
|
9
|
+
try {
|
|
10
|
+
entries = readdirSync(currentDir, { withFileTypes: true });
|
|
11
|
+
} catch {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
for (const entry of entries) {
|
|
15
|
+
const fullPath = join(currentDir, entry.name);
|
|
16
|
+
if (entry.isDirectory()) {
|
|
17
|
+
walk(fullPath, baseDir);
|
|
18
|
+
} else if (/\.mdx?$/.test(entry.name) && !entry.name.startsWith("_")) {
|
|
19
|
+
const rel = relative(baseDir, fullPath).replace(/\.mdx?$/, "").replace(/\/index$/, "");
|
|
20
|
+
results.push({ filePath: fullPath, slug: rel });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
walk(dir, dir);
|
|
25
|
+
return results;
|
|
26
|
+
}
|
|
27
|
+
function slugToUrl(slug, locale, base, siteUrl) {
|
|
28
|
+
const trimmedBase = base.replace(/\/$/, "");
|
|
29
|
+
const path = locale ? `${trimmedBase}/${locale}/docs/${slug}` : `${trimmedBase}/docs/${slug}`;
|
|
30
|
+
if (siteUrl) {
|
|
31
|
+
return `${siteUrl.replace(/\/$/, "")}${path}`;
|
|
32
|
+
}
|
|
33
|
+
return path;
|
|
34
|
+
}
|
|
35
|
+
function isExcluded(data) {
|
|
36
|
+
return Boolean(data.search_exclude || data.draft || data.unlisted);
|
|
37
|
+
}
|
|
38
|
+
function parseMarkdownFile(filePath) {
|
|
39
|
+
try {
|
|
40
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
41
|
+
const parsed = matter(raw);
|
|
42
|
+
return { data: parsed.data, content: parsed.content };
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function loadDocEntries(options) {
|
|
48
|
+
const { contentDir, locale, base, siteUrl } = options;
|
|
49
|
+
const absDir = resolve(contentDir);
|
|
50
|
+
const files = collectMdFiles(absDir);
|
|
51
|
+
const entries = [];
|
|
52
|
+
for (const { filePath, slug } of files) {
|
|
53
|
+
const parsed = parseMarkdownFile(filePath);
|
|
54
|
+
if (!parsed) continue;
|
|
55
|
+
const { data, content } = parsed;
|
|
56
|
+
if (isExcluded(data)) continue;
|
|
57
|
+
let description = data.description ?? "";
|
|
58
|
+
if (!description) {
|
|
59
|
+
const stripped = stripMarkdown(content);
|
|
60
|
+
description = stripped.split("\n").find((l) => l.trim().length > 0) ?? "";
|
|
61
|
+
}
|
|
62
|
+
entries.push({
|
|
63
|
+
title: data.title ?? slug,
|
|
64
|
+
description,
|
|
65
|
+
url: slugToUrl(slug, locale, base, siteUrl),
|
|
66
|
+
content: stripImportsAndJsx(content),
|
|
67
|
+
sidebarPosition: data.sidebar_position
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
entries.sort((a, b) => {
|
|
71
|
+
const posA = a.sidebarPosition ?? Number.MAX_SAFE_INTEGER;
|
|
72
|
+
const posB = b.sidebarPosition ?? Number.MAX_SAFE_INTEGER;
|
|
73
|
+
return posA - posB;
|
|
74
|
+
});
|
|
75
|
+
return entries;
|
|
76
|
+
}
|
|
77
|
+
export {
|
|
78
|
+
collectMdFiles,
|
|
79
|
+
isExcluded,
|
|
80
|
+
loadDocEntries,
|
|
81
|
+
parseMarkdownFile,
|
|
82
|
+
slugToUrl
|
|
83
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown / JSX text-stripping helpers.
|
|
3
|
+
*
|
|
4
|
+
* The two functions below match the legacy Astro emitter's behaviour
|
|
5
|
+
* byte-for-byte. Any change here is a behaviour change and must be
|
|
6
|
+
* reflected in the byte-equality fixture corpus.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Strip imports, exports, and HTML/JSX tags from MDX/MD content while
|
|
10
|
+
* keeping the prose layout (headings, lists, blockquotes) intact for
|
|
11
|
+
* LLM consumption. Used by `llms-full.txt`.
|
|
12
|
+
*/
|
|
13
|
+
declare function stripImportsAndJsx(content: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Strip markdown formatting and produce plain prose. Used to derive a
|
|
16
|
+
* fallback `description` from the body when frontmatter doesn't carry
|
|
17
|
+
* one. The regex sequence matches the legacy `stripMarkdown` helper in
|
|
18
|
+
* `src/utils/content-files.ts` — keep them in sync.
|
|
19
|
+
*/
|
|
20
|
+
declare function stripMarkdown(md: string): string;
|
|
21
|
+
|
|
22
|
+
export { stripImportsAndJsx, stripMarkdown };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
function stripImportsAndJsx(content) {
|
|
2
|
+
return content.replace(/^import\s+.*$/gm, "").replace(/^export\s+.*$/gm, "").replace(/<\/?[a-zA-Z][a-zA-Z0-9]*[^>]*>/g, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
3
|
+
}
|
|
4
|
+
function stripMarkdown(md) {
|
|
5
|
+
return md.replace(/```[\s\S]*?```/g, "").replace(/`[^`]+`/g, "").replace(/<[^>]+>/g, "").replace(/^#{1,6}\s+/gm, "").replace(/\*{1,3}([^*]+)\*{1,3}/g, "$1").replace(/_{1,3}([^_]+)_{1,3}/g, "$1").replace(/!\[[^\]]*\]\([^)]+\)/g, "").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/^>\s+/gm, "").replace(/^[-*_]{3,}\s*$/gm, "").replace(/^[\s]*[-*+]\s+/gm, "").replace(/^[\s]*\d+\.\s+/gm, "").replace(/^import\s+.*$/gm, "").replace(/^export\s+.*$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
6
|
+
}
|
|
7
|
+
export {
|
|
8
|
+
stripImportsAndJsx,
|
|
9
|
+
stripMarkdown
|
|
10
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for the framework-agnostic llms-txt build emitter.
|
|
3
|
+
*
|
|
4
|
+
* The shapes here are deliberately decoupled from `astro:content` and
|
|
5
|
+
* Astro's `AstroIntegration` API so the emitter can run on top of any
|
|
6
|
+
* pipeline that exposes a `dist/` output directory and a list of
|
|
7
|
+
* markdown content roots — Astro today, zfb tomorrow, plain Node tooling
|
|
8
|
+
* in a unit test, etc.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Frontmatter fields the loader reads off of each MDX/MD file. Callers
|
|
12
|
+
* are free to extend this; unrecognised fields are ignored.
|
|
13
|
+
*/
|
|
14
|
+
interface LlmsTxtFrontmatter {
|
|
15
|
+
title?: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
sidebar_position?: number;
|
|
18
|
+
draft?: boolean;
|
|
19
|
+
unlisted?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* `true` when the page is excluded from search and llms.txt indexing.
|
|
22
|
+
* Mirrors the `search_exclude` flag used by the existing project.
|
|
23
|
+
*/
|
|
24
|
+
search_exclude?: boolean;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* One entry in the generated llms.txt / llms-full.txt files. Pure data,
|
|
29
|
+
* already sorted, already stripped — generators (`generateLlmsTxt`,
|
|
30
|
+
* `generateLlmsFullTxt`) consume this without further processing.
|
|
31
|
+
*/
|
|
32
|
+
interface LlmsDocEntry {
|
|
33
|
+
/** Page title (frontmatter `title`, with the slug as a fallback). */
|
|
34
|
+
title: string;
|
|
35
|
+
/**
|
|
36
|
+
* Short description used as the bullet's right-hand side in
|
|
37
|
+
* `llms.txt`. Falls back to the first non-blank prose line of the
|
|
38
|
+
* stripped body when `frontmatter.description` is absent.
|
|
39
|
+
*/
|
|
40
|
+
description: string;
|
|
41
|
+
/**
|
|
42
|
+
* Public URL for the page. Absolute when `siteUrl` is supplied to the
|
|
43
|
+
* loader, otherwise a path-only URL beginning with `base`.
|
|
44
|
+
*/
|
|
45
|
+
url: string;
|
|
46
|
+
/**
|
|
47
|
+
* Body content with imports/exports/JSX tags removed. Used verbatim
|
|
48
|
+
* inside `llms-full.txt`.
|
|
49
|
+
*/
|
|
50
|
+
content: string;
|
|
51
|
+
/** `frontmatter.sidebar_position`, undefined when not declared. */
|
|
52
|
+
sidebarPosition: number | undefined;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Site-level metadata threaded through the generators. Matches the
|
|
56
|
+
* `siteName` / `siteDescription` fields on the legacy settings object
|
|
57
|
+
* one-for-one so callers can pass `settings` straight through.
|
|
58
|
+
*/
|
|
59
|
+
interface LlmsTxtSiteMeta {
|
|
60
|
+
siteName: string;
|
|
61
|
+
siteDescription: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* One locale's content directory + URL prefix. The default locale is
|
|
65
|
+
* represented separately on {@link LlmsTxtEmitOptions}; this type
|
|
66
|
+
* describes the *additional* locales (e.g. `ja`).
|
|
67
|
+
*/
|
|
68
|
+
interface LlmsTxtLocaleConfig {
|
|
69
|
+
/** Locale code used as both the URL segment and the output subfolder. */
|
|
70
|
+
code: string;
|
|
71
|
+
/** Absolute or cwd-relative path to the locale's content root. */
|
|
72
|
+
dir: string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Options for {@link loadDocEntries} — one content directory at a time.
|
|
76
|
+
*/
|
|
77
|
+
interface LlmsTxtLoadOptions {
|
|
78
|
+
/** Absolute or cwd-relative path to the markdown content root. */
|
|
79
|
+
contentDir: string;
|
|
80
|
+
/**
|
|
81
|
+
* Locale segment for the generated URLs. Pass `null` to omit the
|
|
82
|
+
* locale segment (the default locale).
|
|
83
|
+
*/
|
|
84
|
+
locale: string | null;
|
|
85
|
+
/**
|
|
86
|
+
* URL base, with or without a trailing slash. The loader strips the
|
|
87
|
+
* trailing slash before joining.
|
|
88
|
+
*/
|
|
89
|
+
base: string;
|
|
90
|
+
/**
|
|
91
|
+
* Optional absolute site URL. When set, the loader produces fully
|
|
92
|
+
* qualified URLs by prefixing the base+path with `siteUrl`. When
|
|
93
|
+
* empty, URLs are returned path-only (matching the legacy emitter's
|
|
94
|
+
* behaviour for projects that omit `siteUrl`).
|
|
95
|
+
*/
|
|
96
|
+
siteUrl?: string;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Top-level options for {@link emitLlmsTxt}. Mirrors the inputs the
|
|
100
|
+
* legacy Astro emitter pulled implicitly off of the project's `settings`
|
|
101
|
+
* module so that a one-line registration in `zfb.config.ts` (or a
|
|
102
|
+
* `b4-build` hook in Astro) can wire the same behaviour.
|
|
103
|
+
*/
|
|
104
|
+
interface LlmsTxtEmitOptions extends LlmsTxtSiteMeta {
|
|
105
|
+
/** Absolute output directory — typically `dist/`. */
|
|
106
|
+
outDir: string;
|
|
107
|
+
/** URL base used when materialising per-page links. */
|
|
108
|
+
base: string;
|
|
109
|
+
/** Optional absolute site URL; see {@link LlmsTxtLoadOptions}. */
|
|
110
|
+
siteUrl?: string;
|
|
111
|
+
/**
|
|
112
|
+
* Default-locale content directory. Emitted at `outDir/llms.txt` and
|
|
113
|
+
* `outDir/llms-full.txt`.
|
|
114
|
+
*/
|
|
115
|
+
defaultLocaleDir: string;
|
|
116
|
+
/**
|
|
117
|
+
* Additional locales. Each one emits to
|
|
118
|
+
* `outDir/<code>/llms.txt` and `outDir/<code>/llms-full.txt`.
|
|
119
|
+
*/
|
|
120
|
+
locales?: LlmsTxtLocaleConfig[];
|
|
121
|
+
/**
|
|
122
|
+
* Optional logger. Defaults to a no-op so unit tests stay quiet; the
|
|
123
|
+
* Astro adapter can wire `astro:build:done`'s `logger` through, and
|
|
124
|
+
* a future zfb plugin can pipe its own.
|
|
125
|
+
*/
|
|
126
|
+
logger?: LlmsTxtLogger;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Minimal logger interface — a structural subset of both Astro's
|
|
130
|
+
* `logger` and `console`. Only `info` is used today; the wider shape is
|
|
131
|
+
* provided so the option can hold either object without type acrobatics.
|
|
132
|
+
*/
|
|
133
|
+
interface LlmsTxtLogger {
|
|
134
|
+
info: (msg: string) => void;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Result returned by {@link emitLlmsTxt}. Useful for tests and for
|
|
138
|
+
* callers that want to log / further process the emitted set.
|
|
139
|
+
*/
|
|
140
|
+
interface LlmsTxtEmitResult {
|
|
141
|
+
/** Absolute paths of every file written, in emit order. */
|
|
142
|
+
written: string[];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export type { LlmsDocEntry, LlmsTxtEmitOptions, LlmsTxtEmitResult, LlmsTxtFrontmatter, LlmsTxtLoadOptions, LlmsTxtLocaleConfig, LlmsTxtLogger, LlmsTxtSiteMeta };
|
|
File without changes
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { SearchIndexConfig, SearchIndexEntry } from './types.js';
|
|
2
|
+
|
|
3
|
+
interface SearchIndexBuildResult {
|
|
4
|
+
/** Absolute path of the JSON file that was written. */
|
|
5
|
+
jsonPath: string;
|
|
6
|
+
/** Number of entries serialised. */
|
|
7
|
+
entryCount: number;
|
|
8
|
+
/** The raw entries — exposed so callers can pipe the same data into a Worker bundle if needed. */
|
|
9
|
+
entries: SearchIndexEntry[];
|
|
10
|
+
}
|
|
11
|
+
interface SearchIndexBuildOptions extends SearchIndexConfig {
|
|
12
|
+
/** Absolute path of the build output directory (e.g. zfb's `outDir`). */
|
|
13
|
+
outDir: string;
|
|
14
|
+
/** Optional logger; defaults to a no-op so builds stay quiet by default. */
|
|
15
|
+
logger?: {
|
|
16
|
+
info: (msg: string) => void;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Walk the configured content directories, build the flat search index,
|
|
21
|
+
* and write `search-index.json` to `outDir`. Returns the entries so
|
|
22
|
+
* callers (e.g. a downstream `search-worker` bundler) can reuse the
|
|
23
|
+
* same data without re-walking the filesystem.
|
|
24
|
+
*
|
|
25
|
+
* Schema is byte-identical to today's Astro integration — see
|
|
26
|
+
* `types.ts` for the locked-in shape.
|
|
27
|
+
*/
|
|
28
|
+
declare function emitSearchIndex(options: SearchIndexBuildOptions): SearchIndexBuildResult;
|
|
29
|
+
|
|
30
|
+
export { type SearchIndexBuildOptions, type SearchIndexBuildResult, emitSearchIndex };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { collectSearchEntries } from "./collect.js";
|
|
4
|
+
function emitSearchIndex(options) {
|
|
5
|
+
const { outDir, logger, ...config } = options;
|
|
6
|
+
const entries = collectSearchEntries(config);
|
|
7
|
+
mkdirSync(outDir, { recursive: true });
|
|
8
|
+
const jsonPath = join(outDir, "search-index.json");
|
|
9
|
+
writeFileSync(jsonPath, JSON.stringify(entries));
|
|
10
|
+
logger?.info(`Generated search index with ${entries.length} entries`);
|
|
11
|
+
return { jsonPath, entryCount: entries.length, entries };
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
emitSearchIndex
|
|
15
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SearchIndexConfig, SearchIndexEntry } from './types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Collect every search-index entry across the default locale plus all
|
|
5
|
+
* configured non-default locales. The traversal order matches today's
|
|
6
|
+
* Astro integration: default locale first, then locales in the iteration
|
|
7
|
+
* order of the `locales` map. Downstream consumers should not rely on
|
|
8
|
+
* order beyond that, but keep it stable for diff-friendly builds.
|
|
9
|
+
*/
|
|
10
|
+
declare function collectSearchEntries(config: SearchIndexConfig): SearchIndexEntry[];
|
|
11
|
+
|
|
12
|
+
export { collectSearchEntries };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import {
|
|
3
|
+
collectMdFiles,
|
|
4
|
+
isExcluded,
|
|
5
|
+
parseMarkdownFile,
|
|
6
|
+
slugToUrl,
|
|
7
|
+
stripMarkdown
|
|
8
|
+
} from "./content-files.js";
|
|
9
|
+
import {
|
|
10
|
+
MAX_BODY_LENGTH
|
|
11
|
+
} from "./types.js";
|
|
12
|
+
function truncateBody(text) {
|
|
13
|
+
return text.length > MAX_BODY_LENGTH ? text.substring(0, MAX_BODY_LENGTH) : text;
|
|
14
|
+
}
|
|
15
|
+
function buildEntries(contentDir, locale, base) {
|
|
16
|
+
const absDir = resolve(contentDir);
|
|
17
|
+
const files = collectMdFiles(absDir);
|
|
18
|
+
const entries = [];
|
|
19
|
+
for (const { filePath, slug } of files) {
|
|
20
|
+
const parsed = parseMarkdownFile(filePath);
|
|
21
|
+
if (!parsed) continue;
|
|
22
|
+
const { data, content } = parsed;
|
|
23
|
+
if (isExcluded(data)) continue;
|
|
24
|
+
const id = locale ? `${locale}/${slug}` : slug;
|
|
25
|
+
entries.push({
|
|
26
|
+
id,
|
|
27
|
+
title: data.title ?? slug,
|
|
28
|
+
body: truncateBody(stripMarkdown(content)),
|
|
29
|
+
url: slugToUrl(slug, locale, base),
|
|
30
|
+
description: data.description ?? ""
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return entries;
|
|
34
|
+
}
|
|
35
|
+
function collectSearchEntries(config) {
|
|
36
|
+
const base = config.base ?? "";
|
|
37
|
+
const entries = [];
|
|
38
|
+
entries.push(...buildEntries(config.docsDir, null, base));
|
|
39
|
+
if (config.locales) {
|
|
40
|
+
for (const [code, locale] of Object.entries(config.locales)) {
|
|
41
|
+
entries.push(...buildEntries(locale.dir, code, base));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return entries;
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
collectSearchEntries
|
|
48
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip markdown formatting to plain text. Conservative-by-design — the
|
|
3
|
+
* regex pipeline is identical to today's Astro integration so search
|
|
4
|
+
* excerpts stay byte-equal across the cutover. Do not add new rules
|
|
5
|
+
* without also updating the byte-equality fixtures (topic-plugin-audit).
|
|
6
|
+
*/
|
|
7
|
+
declare function stripMarkdown(md: string): string;
|
|
8
|
+
/** Walk a directory recursively and collect all `.md`/`.mdx` files. */
|
|
9
|
+
declare function collectMdFiles(dir: string): Array<{
|
|
10
|
+
filePath: string;
|
|
11
|
+
slug: string;
|
|
12
|
+
}>;
|
|
13
|
+
/** Compute the site-relative URL for a slug + locale, honouring `base`. */
|
|
14
|
+
declare function slugToUrl(slug: string, locale: string | null, base: string): string;
|
|
15
|
+
/** Frontmatter fields the integration cares about. Extra keys pass through. */
|
|
16
|
+
interface DocFrontmatter {
|
|
17
|
+
title?: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
draft?: boolean;
|
|
20
|
+
unlisted?: boolean;
|
|
21
|
+
search_exclude?: boolean;
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
}
|
|
24
|
+
/** Parse a markdown file. Returns null when the file cannot be read. */
|
|
25
|
+
declare function parseMarkdownFile(filePath: string): {
|
|
26
|
+
data: DocFrontmatter;
|
|
27
|
+
content: string;
|
|
28
|
+
} | null;
|
|
29
|
+
/** A page is excluded from indexing when explicitly opted out, drafted, or unlisted. */
|
|
30
|
+
declare function isExcluded(data: DocFrontmatter): boolean;
|
|
31
|
+
|
|
32
|
+
export { type DocFrontmatter, collectMdFiles, isExcluded, parseMarkdownFile, slugToUrl, stripMarkdown };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readFileSync, readdirSync } from "node:fs";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
import matter from "gray-matter";
|
|
4
|
+
function stripMarkdown(md) {
|
|
5
|
+
return md.replace(/```[\s\S]*?```/g, "").replace(/`[^`]+`/g, "").replace(/<[^>]+>/g, "").replace(/^#{1,6}\s+/gm, "").replace(/\*{1,3}([^*]+)\*{1,3}/g, "$1").replace(/_{1,3}([^_]+)_{1,3}/g, "$1").replace(/!\[[^\]]*\]\([^)]+\)/g, "").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/^>\s+/gm, "").replace(/^[-*_]{3,}\s*$/gm, "").replace(/^[\s]*[-*+]\s+/gm, "").replace(/^[\s]*\d+\.\s+/gm, "").replace(/^import\s+.*$/gm, "").replace(/^export\s+.*$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
6
|
+
}
|
|
7
|
+
function collectMdFiles(dir) {
|
|
8
|
+
const results = [];
|
|
9
|
+
function walk(currentDir, baseDir) {
|
|
10
|
+
let entries;
|
|
11
|
+
try {
|
|
12
|
+
entries = readdirSync(currentDir, { withFileTypes: true });
|
|
13
|
+
} catch {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
for (const entry of entries) {
|
|
17
|
+
const fullPath = join(currentDir, entry.name);
|
|
18
|
+
if (entry.isDirectory()) {
|
|
19
|
+
walk(fullPath, baseDir);
|
|
20
|
+
} else if (/\.mdx?$/.test(entry.name) && !entry.name.startsWith("_")) {
|
|
21
|
+
const rel = relative(baseDir, fullPath).replace(/\.mdx?$/, "").replace(/\/index$/, "");
|
|
22
|
+
results.push({ filePath: fullPath, slug: rel });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
walk(dir, dir);
|
|
27
|
+
return results;
|
|
28
|
+
}
|
|
29
|
+
function slugToUrl(slug, locale, base) {
|
|
30
|
+
const normalizedBase = base.replace(/\/$/, "");
|
|
31
|
+
return locale ? `${normalizedBase}/${locale}/docs/${slug}` : `${normalizedBase}/docs/${slug}`;
|
|
32
|
+
}
|
|
33
|
+
function parseMarkdownFile(filePath) {
|
|
34
|
+
try {
|
|
35
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
36
|
+
return matter(raw);
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function isExcluded(data) {
|
|
42
|
+
return !!(data.search_exclude || data.draft || data.unlisted);
|
|
43
|
+
}
|
|
44
|
+
export {
|
|
45
|
+
collectMdFiles,
|
|
46
|
+
isExcluded,
|
|
47
|
+
parseMarkdownFile,
|
|
48
|
+
slugToUrl,
|
|
49
|
+
stripMarkdown
|
|
50
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import { SearchIndexConfig } from './types.js';
|
|
3
|
+
|
|
4
|
+
type SearchIndexNextFn = (err?: unknown) => void;
|
|
5
|
+
type SearchIndexMiddleware = (req: IncomingMessage, res: ServerResponse, next: SearchIndexNextFn) => void;
|
|
6
|
+
/**
|
|
7
|
+
* Build a dev-server middleware that responds to GET requests for
|
|
8
|
+
* `/search-index.json` (or any URL ending in that suffix, mirroring the
|
|
9
|
+
* tolerant matcher in the Astro integration so a `base` prefix at the
|
|
10
|
+
* dev server does not break the route). Every request rebuilds the
|
|
11
|
+
* index from disk — that matches the Astro behaviour and keeps content
|
|
12
|
+
* edits visible without a dev-server restart.
|
|
13
|
+
*/
|
|
14
|
+
declare function createSearchIndexDevMiddleware(config: SearchIndexConfig): SearchIndexMiddleware;
|
|
15
|
+
|
|
16
|
+
export { type SearchIndexMiddleware, type SearchIndexNextFn, createSearchIndexDevMiddleware };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { collectSearchEntries } from "./collect.js";
|
|
2
|
+
import {
|
|
3
|
+
SEARCH_INDEX_ROUTE
|
|
4
|
+
} from "./types.js";
|
|
5
|
+
function createSearchIndexDevMiddleware(config) {
|
|
6
|
+
return (req, res, next) => {
|
|
7
|
+
const url = req.url ?? "";
|
|
8
|
+
const matches = url === SEARCH_INDEX_ROUTE || url.endsWith(SEARCH_INDEX_ROUTE);
|
|
9
|
+
if (!matches) {
|
|
10
|
+
next();
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const entries = collectSearchEntries(config);
|
|
15
|
+
res.setHeader("Content-Type", "application/json");
|
|
16
|
+
res.end(JSON.stringify(entries));
|
|
17
|
+
} catch (err) {
|
|
18
|
+
res.statusCode = 500;
|
|
19
|
+
res.setHeader("Content-Type", "application/json");
|
|
20
|
+
res.end(
|
|
21
|
+
JSON.stringify({
|
|
22
|
+
error: err instanceof Error ? err.message : "Internal error"
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
createSearchIndexDevMiddleware
|
|
30
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { SearchIndexBuildOptions, SearchIndexBuildResult, emitSearchIndex } from './build-emitter.js';
|
|
2
|
+
export { collectSearchEntries } from './collect.js';
|
|
3
|
+
export { SearchIndexMiddleware, SearchIndexNextFn, createSearchIndexDevMiddleware } from './dev-middleware.js';
|
|
4
|
+
export { MAX_BODY_LENGTH, SEARCH_INDEX_ROUTE, SearchIndexConfig, SearchIndexEntry, SearchIndexLocaleConfig } from './types.js';
|
|
5
|
+
import 'node:http';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { emitSearchIndex } from "./build-emitter.js";
|
|
2
|
+
import { collectSearchEntries } from "./collect.js";
|
|
3
|
+
import { createSearchIndexDevMiddleware } from "./dev-middleware.js";
|
|
4
|
+
import {
|
|
5
|
+
MAX_BODY_LENGTH,
|
|
6
|
+
SEARCH_INDEX_ROUTE
|
|
7
|
+
} from "./types.js";
|
|
8
|
+
export {
|
|
9
|
+
MAX_BODY_LENGTH,
|
|
10
|
+
SEARCH_INDEX_ROUTE,
|
|
11
|
+
collectSearchEntries,
|
|
12
|
+
createSearchIndexDevMiddleware,
|
|
13
|
+
emitSearchIndex
|
|
14
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One page in the search index. The shape mirrors today's Astro
|
|
3
|
+
* integration output verbatim — keep it byte-identical so downstream
|
|
4
|
+
* consumers (search.astro client island and packages/search-worker via
|
|
5
|
+
* MiniSearch) keep working unchanged after the zfb cutover.
|
|
6
|
+
*/
|
|
7
|
+
interface SearchIndexEntry {
|
|
8
|
+
/** Stable identifier — `slug` for the default locale, `${locale}/${slug}` otherwise. */
|
|
9
|
+
id: string;
|
|
10
|
+
/** Frontmatter title, falling back to the slug when missing. */
|
|
11
|
+
title: string;
|
|
12
|
+
/** Plain-text body excerpt, capped at MAX_BODY_LENGTH characters. */
|
|
13
|
+
body: string;
|
|
14
|
+
/** Site-relative URL (respecting `base`). */
|
|
15
|
+
url: string;
|
|
16
|
+
/** Frontmatter description, or the empty string when absent. */
|
|
17
|
+
description: string;
|
|
18
|
+
}
|
|
19
|
+
/** A locale entry that mirrors the Astro `settings.locales` shape we already have. */
|
|
20
|
+
interface SearchIndexLocaleConfig {
|
|
21
|
+
/** Absolute or project-relative directory holding this locale's MDX content. */
|
|
22
|
+
dir: string;
|
|
23
|
+
}
|
|
24
|
+
/** Build-time configuration for collecting search entries. */
|
|
25
|
+
interface SearchIndexConfig {
|
|
26
|
+
/** Default-locale content directory (e.g. `src/content/docs`). */
|
|
27
|
+
docsDir: string;
|
|
28
|
+
/** Optional non-default locales, keyed by locale code (e.g. `{ ja: { dir: "src/content/docs-ja" } }`). */
|
|
29
|
+
locales?: Record<string, SearchIndexLocaleConfig>;
|
|
30
|
+
/** Site base path (e.g. `""`, `"/docs"`); trailing slash is normalised away. */
|
|
31
|
+
base?: string;
|
|
32
|
+
}
|
|
33
|
+
/** Maximum body text stored per entry (display excerpt cap). */
|
|
34
|
+
declare const MAX_BODY_LENGTH = 300;
|
|
35
|
+
/** Public route the dev middleware and build emitter agree on. */
|
|
36
|
+
declare const SEARCH_INDEX_ROUTE = "/search-index.json";
|
|
37
|
+
|
|
38
|
+
export { MAX_BODY_LENGTH, SEARCH_INDEX_ROUTE, type SearchIndexConfig, type SearchIndexEntry, type SearchIndexLocaleConfig };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { VNode } from 'preact';
|
|
2
|
+
|
|
3
|
+
/** @jsxRuntime automatic */
|
|
4
|
+
/** @jsxImportSource preact */
|
|
5
|
+
|
|
6
|
+
interface DocMetainfoProps {
|
|
7
|
+
/**
|
|
8
|
+
* Pre-formatted creation date string (e.g. `"Jan 1, 2024"`).
|
|
9
|
+
* The legacy `doc-metainfo.astro` called `formatDate(gitInfo.createdAt,
|
|
10
|
+
* locale)` inline; v2 delegates that computation to the caller.
|
|
11
|
+
* Omit (or pass `null`) to suppress the "created" row.
|
|
12
|
+
*/
|
|
13
|
+
createdAt?: string | null;
|
|
14
|
+
/**
|
|
15
|
+
* Pre-formatted last-updated date string. Suppressed when equal to
|
|
16
|
+
* `createdAt` (matching the original template's guard
|
|
17
|
+
* `updatedAt !== createdAt`), or when null / omitted.
|
|
18
|
+
*/
|
|
19
|
+
updatedAt?: string | null;
|
|
20
|
+
/**
|
|
21
|
+
* Git author name (or any attribution string). Omit to suppress.
|
|
22
|
+
*/
|
|
23
|
+
author?: string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Label for the "created" entry. Defaults to `"Created"`. Pass the
|
|
26
|
+
* i18n-resolved string (`t("doc.created", locale)`) from upstream.
|
|
27
|
+
*/
|
|
28
|
+
createdLabel?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Label for the "updated" entry. Defaults to `"Updated"`.
|
|
31
|
+
*/
|
|
32
|
+
updatedLabel?: string;
|
|
33
|
+
}
|
|
34
|
+
declare const DEFAULT_CREATED_LABEL = "Created";
|
|
35
|
+
declare const DEFAULT_UPDATED_LABEL = "Updated";
|
|
36
|
+
/**
|
|
37
|
+
* Document meta-information strip (created date, updated date, author)
|
|
38
|
+
* — JSX port of `src/components/doc-metainfo.astro`.
|
|
39
|
+
*
|
|
40
|
+
* The legacy component owned three responsibilities: reading
|
|
41
|
+
* `settings.docMetainfo`, calling `getGitInfo(filePath)`, and
|
|
42
|
+
* presentation. v2 keeps only presentation; the caller resolves git
|
|
43
|
+
* info and date formatting upstream.
|
|
44
|
+
*
|
|
45
|
+
* Returns `null` when no displayable field is provided, mirroring the
|
|
46
|
+
* original `hasInfo && (...)` guard.
|
|
47
|
+
*/
|
|
48
|
+
declare function DocMetainfo(props: DocMetainfoProps): VNode | null;
|
|
49
|
+
|
|
50
|
+
export { DEFAULT_CREATED_LABEL, DEFAULT_UPDATED_LABEL, DocMetainfo, type DocMetainfoProps };
|