Files
docs/projects/_shared/lib/prepare-docs.ts
S.Gromov bdb99ade62
All checks were successful
CI/CD Pipeline / build (push) Successful in 39s
CI/CD Pipeline / docker (push) Successful in 1m30s
CI/CD Pipeline / deploy (push) Successful in 8s
refactor: перенести сборку в проекты
- перенесены каноны и VitePress-конфиги в projects/<slug>

- добавлены корневой и проектные build.ts для сборки артефактов

- добавлены shared-библиотеки сборки в projects/_shared/lib

- обновлены CI, Dockerfile, package.json, gitignore и README

- удалена сборка frontend-агента
2026-05-22 19:07:10 +03:00

113 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import fs from 'node:fs';
import path from 'node:path';
import { pathToFileURL } from 'node:url';
type Page = {
source: string;
target: string;
};
type RouteRewrite = {
from: string;
to: string;
};
type DocsConfig = {
mounts: Page[];
routeRewrites?: RouteRewrite[];
};
type ProjectConfig = {
slug: string;
docsDir: string;
};
const MD_LINK_RE = /\]\((?!#|[a-z][a-z0-9+.-]*:|\/\/)([^)\s]+)(#[^)]*)?\)/gi;
function normalizePath(value: string) {
return value.split(path.sep).join('/').replace(/^\.\//, '');
}
function formatRelativeMarkdownPath(fromTarget: string, toTarget: string) {
const relative = path.relative(path.dirname(fromTarget), toTarget).split(path.sep).join('/');
return relative.startsWith('.') ? relative : `./${relative}`;
}
async function loadDocsConfig(configPath: string) {
return (await import(`${pathToFileURL(configPath).href}?t=${Date.now()}`)) as DocsConfig;
}
export async function prepareDocs(projectDir: string, config: ProjectConfig) {
const docsDir = path.join(projectDir, config.docsDir);
const contentDir = path.join(docsDir, 'content');
const docsConfig = await loadDocsConfig(path.join(docsDir, 'docs.config.ts'));
const targetBySource = new Map(
docsConfig.mounts.map((page) => [normalizePath(path.resolve(projectDir, page.source)), normalizePath(page.target)]),
);
const routeRewrites = [...(docsConfig.routeRewrites ?? [])].sort((a, b) => b.from.length - a.from.length);
function applyRouteRewrites(route: string) {
for (const rewrite of routeRewrites) {
if (route === rewrite.from || route.startsWith(`${rewrite.from}/`) || route.startsWith(`${rewrite.from}#`)) {
return `${rewrite.to}${route.slice(rewrite.from.length)}`;
}
}
return undefined;
}
function formatDocsRoute(route: string) {
const rewritten = applyRouteRewrites(route);
if (rewritten) return rewritten;
if (route === '/docs') return '/';
if (route.startsWith('/docs/')) return route.slice('/docs'.length);
return undefined;
}
function formatRelativeRoute(hrefPath: string, sourceDir: string) {
const sourcePath = normalizePath(path.relative(projectDir, path.resolve(sourceDir, hrefPath)));
if (sourcePath.startsWith('canons/')) return formatDocsRoute(`/docs/${sourcePath.slice('canons/'.length)}`);
return undefined;
}
function transformMarkdownLinks(content: string, page: Page) {
const sourceDir = path.dirname(path.resolve(projectDir, page.source));
return content.replace(MD_LINK_RE, (match, href: string, hash = '') => {
const [hrefPath, query = ''] = href.split('?');
const queryPart = query ? `?${query}` : '';
if (hrefPath.startsWith('/')) {
const route = formatDocsRoute(hrefPath) ?? applyRouteRewrites(hrefPath);
return route ? `](${route}${queryPart}${hash})` : match;
}
if (!hrefPath.endsWith('.md')) {
const route = formatRelativeRoute(hrefPath, sourceDir);
return route ? `](${route}${queryPart}${hash})` : match;
}
const target = targetBySource.get(normalizePath(path.resolve(sourceDir, hrefPath)));
if (!target) return match;
return `](${formatRelativeMarkdownPath(page.target, `${target}${queryPart}`)}${hash})`;
});
}
fs.rmSync(contentDir, { recursive: true, force: true });
fs.mkdirSync(contentDir, { recursive: true });
for (const page of docsConfig.mounts) {
const sourcePath = path.resolve(projectDir, page.source);
const targetPath = path.join(contentDir, page.target);
if (!fs.existsSync(sourcePath)) throw new Error(`Не найден канон: ${sourcePath}`);
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
fs.writeFileSync(targetPath, transformMarkdownLinks(fs.readFileSync(sourcePath, 'utf8'), page), 'utf8');
console.log(`${page.target} -> ${path.relative(projectDir, sourcePath)}`);
}
console.log(`Подготовлен VitePress content для ${config.slug}: ${docsConfig.mounts.length} страниц`);
}