fix: исправить доступность артефактов документации
- добавлены HTML-подсказки для обнаружения llms.txt агентами - обновлена карточка скачивания спецификации и архива - добавлен раздел с порядком чтения спецификации - исправлена генерация ссылок для single-file, Markdown и ZIP - обновлены сгенерированные README.md и ARCHITECTURE.md
This commit is contained in:
69
generate.ts
69
generate.ts
@@ -65,6 +65,35 @@ function fileRelToMdUrl(file: string): string {
|
||||
return `${DOC_ROUTE_PREFIX}/${file}`;
|
||||
}
|
||||
|
||||
const ARCHITECTURE_LINK_RE = /\]\((\/architecture(?:\/[^)\s#]*)?)(#[^)\s]*)?\)/g;
|
||||
|
||||
function architectureRouteToFileRel(route: string): string {
|
||||
if (route.replace(/\/$/, "") === "/architecture") return "architecture/index.md";
|
||||
return linkToFileRel(route);
|
||||
}
|
||||
|
||||
function transformArchitectureLinks(
|
||||
content: string,
|
||||
toHref: (route: string, hash: string) => string,
|
||||
): string {
|
||||
return content.replace(ARCHITECTURE_LINK_RE, (_match, route: string, hash = "") => {
|
||||
return `](${toHref(route, hash)})`;
|
||||
});
|
||||
}
|
||||
|
||||
function transformArchiveLinks(content: string): string {
|
||||
return transformArchitectureLinks(content, (route, hash) => {
|
||||
const fileName = path.basename(architectureRouteToFileRel(route));
|
||||
return `./${fileName}${hash}`;
|
||||
});
|
||||
}
|
||||
|
||||
function transformSiteMarkdownLinks(content: string): string {
|
||||
return transformArchitectureLinks(content, (route, hash) => {
|
||||
return `${fileRelToMdUrl(architectureRouteToFileRel(route))}${hash}`;
|
||||
});
|
||||
}
|
||||
|
||||
function getAllFiles(): string[] {
|
||||
return SIDEBAR.flatMap((g) => g.items.map((item) => linkToFileRel(item.link)));
|
||||
}
|
||||
@@ -75,6 +104,38 @@ const stripFrontmatter = (content: string) =>
|
||||
const stripRulesLink = (content: string) =>
|
||||
content.replace(/<!-- rules-link -->[\s\S]*?<!-- \/rules-link -->\n*/g, "");
|
||||
|
||||
function slugifyHeading(heading: string): string {
|
||||
return heading
|
||||
.trim()
|
||||
.replace(/[`*_~[\]()]/g, "")
|
||||
.toLowerCase()
|
||||
.replace(/[^\p{L}\p{N}\s-]/gu, "")
|
||||
.trim()
|
||||
.replace(/\s+/g, "-");
|
||||
}
|
||||
|
||||
function fileRelToSingleFileAnchor(file: string): string {
|
||||
const filePath = path.join(SRC_DIR, file);
|
||||
if (!fs.existsSync(filePath)) return slugifyHeading(path.basename(file, ".md"));
|
||||
|
||||
const raw = stripFrontmatter(fs.readFileSync(filePath, "utf8"));
|
||||
const title = raw.match(/^#\s+(.+)$/m)?.[1];
|
||||
return slugifyHeading(title ?? path.basename(file, ".md"));
|
||||
}
|
||||
|
||||
function transformSingleFileLinks(content: string): string {
|
||||
return transformArchitectureLinks(content, (route, hash) => {
|
||||
if (hash) return hash;
|
||||
return `#${fileRelToSingleFileAnchor(architectureRouteToFileRel(route))}`;
|
||||
});
|
||||
}
|
||||
|
||||
function transformReadmeLinks(content: string): string {
|
||||
return transformArchitectureLinks(content, (route, hash) => {
|
||||
return `docs/${architectureRouteToFileRel(route)}${hash}`;
|
||||
});
|
||||
}
|
||||
|
||||
const shiftHeadings = (content: string) => {
|
||||
const lines = content.split("\n");
|
||||
let inCodeBlock = false;
|
||||
@@ -100,7 +161,8 @@ const buildArchitectureMarkdown = (routePrefix: string) => {
|
||||
if (!content) continue;
|
||||
|
||||
const route = routePrefix + fileRelToRoute(file).replace(DOC_ROUTE_PREFIX, "");
|
||||
const processed = file.endsWith("index.md") ? content : shiftHeadings(content);
|
||||
const shifted = file.endsWith("index.md") ? content : shiftHeadings(content);
|
||||
const processed = transformSingleFileLinks(shifted);
|
||||
parts.push(`<!-- ${route} -->\n${processed}`);
|
||||
}
|
||||
|
||||
@@ -151,9 +213,10 @@ function copyMarkdownFiles() {
|
||||
const src = path.join(SRC_DIR, file);
|
||||
if (!fs.existsSync(src)) continue;
|
||||
|
||||
const content = transformSiteMarkdownLinks(fs.readFileSync(src, "utf8"));
|
||||
const dest = path.join(DOCS_PUBLIC_DIR, file);
|
||||
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
||||
fs.copyFileSync(src, dest);
|
||||
fs.writeFileSync(dest, content, "utf8");
|
||||
copied++;
|
||||
}
|
||||
|
||||
@@ -179,6 +242,7 @@ function buildZip() {
|
||||
if (!fs.existsSync(src)) continue;
|
||||
let content = fs.readFileSync(src, "utf8");
|
||||
content = stripRulesLink(stripFrontmatter(content)).trim();
|
||||
content = transformArchiveLinks(content);
|
||||
const destName = path.basename(file);
|
||||
fs.writeFileSync(path.join(tmpDir, destName), content, "utf8");
|
||||
}
|
||||
@@ -205,6 +269,7 @@ function buildReadme() {
|
||||
|
||||
let content = stripFrontmatter(fs.readFileSync(indexPath, "utf8"));
|
||||
content = content.replace(/<!-- rules-link -->[\s\S]*?<!-- \/rules-link -->\n*/g, "");
|
||||
content = transformReadmeLinks(content);
|
||||
fs.writeFileSync("./README.md", content, "utf8");
|
||||
console.log("README.md создан");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user