From 4b29e175bcef29037dc88505c11466e8a0710301 Mon Sep 17 00:00:00 2001 From: "S.Gromov" Date: Mon, 11 May 2026 21:26:55 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=81=D1=81=D1=8B=D0=BB=D0=BA=D0=B8=20mar?= =?UTF-8?q?kdown-=D0=B0=D1=80=D1=82=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - исправлена генерация ссылок для architecture и examples - сохранена структура папок в архиве slm-design.zip - обновлён сгенерированный ARCHITECTURE.md --- docs/architecture/monorepo.md | 2 +- generate.ts | 60 ++++++++++++++--------------------- public/ARCHITECTURE.md | 16 +++++----- 3 files changed, 32 insertions(+), 46 deletions(-) diff --git a/docs/architecture/monorepo.md b/docs/architecture/monorepo.md index 803ee9e..0078180 100644 --- a/docs/architecture/monorepo.md +++ b/docs/architecture/monorepo.md @@ -1,6 +1,6 @@ --- title: Монорепозитории -description: "Правила применения SLM Design для frontend-проектов, находящихся в монорепозитории" +description: Правила применения SLM Design для frontend-проектов, находящихся в монорепозитории --- # Монорепозитории diff --git a/generate.ts b/generate.ts index eb559fb..37283a3 100644 --- a/generate.ts +++ b/generate.ts @@ -65,32 +65,37 @@ function fileRelToMdUrl(file: string): string { return `${DOC_ROUTE_PREFIX}/${file}`; } -const ARCHITECTURE_LINK_RE = /\]\((\/architecture(?:\/[^)\s#]*)?)(#[^)\s]*)?\)/g; +const DOC_LINK_RE = /\]\((\/(?:architecture|examples)(?:\/[^)\s#]*)?)(#[^)\s]*)?\)/g; -function architectureRouteToFileRel(route: string): string { +function docRouteToFileRel(route: string): string { if (route.replace(/\/$/, "") === "/architecture") return "architecture/index.md"; + if (route.replace(/\/$/, "") === "/examples") return "examples/index.md"; return linkToFileRel(route); } -function transformArchitectureLinks( +function transformDocLinks( content: string, toHref: (route: string, hash: string) => string, ): string { - return content.replace(ARCHITECTURE_LINK_RE, (_match, route: string, hash = "") => { + return content.replace(DOC_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 formatRelativeMarkdownPath(fromFile: string, toFile: string): string { + const relative = path.relative(path.dirname(fromFile), toFile).split(path.sep).join("/"); + return relative.startsWith(".") ? relative : `./${relative}`; +} + +function transformArchiveLinks(content: string, fromFile: string): string { + return transformDocLinks(content, (route, hash) => { + return `${formatRelativeMarkdownPath(fromFile, docRouteToFileRel(route))}${hash}`; }); } function transformSiteMarkdownLinks(content: string): string { - return transformArchitectureLinks(content, (route, hash) => { - return `${fileRelToMdUrl(architectureRouteToFileRel(route))}${hash}`; + return transformDocLinks(content, (route, hash) => { + return `${fileRelToMdUrl(docRouteToFileRel(route))}${hash}`; }); } @@ -104,35 +109,15 @@ const stripFrontmatter = (content: string) => const stripRulesLink = (content: string) => content.replace(/[\s\S]*?\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))}`; + return transformDocLinks(content, (route, hash) => { + return `${fileRelToMdUrl(docRouteToFileRel(route))}${hash}`; }); } function transformReadmeLinks(content: string): string { - return transformArchitectureLinks(content, (route, hash) => { - return `docs/${architectureRouteToFileRel(route)}${hash}`; + return transformDocLinks(content, (route, hash) => { + return `docs/${docRouteToFileRel(route)}${hash}`; }); } @@ -242,9 +227,10 @@ 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"); + content = transformArchiveLinks(content, file); + const dest = path.join(tmpDir, file); + fs.mkdirSync(path.dirname(dest), { recursive: true }); + fs.writeFileSync(dest, content, "utf8"); } const pkg = JSON.parse(fs.readFileSync("./package.json", "utf8")); diff --git a/public/ARCHITECTURE.md b/public/ARCHITECTURE.md index 87c49a3..9c12364 100644 --- a/public/ARCHITECTURE.md +++ b/public/ARCHITECTURE.md @@ -10,10 +10,10 @@ Scoped Layered Module Design — модульная архитектура фр Спецификация SLM Design состоит из нескольких связанных разделов. Этот обзор даёт общий контекст, а детальные правила описаны дальше: -- [Слои](#слои) — уровни организации `src/`, направление зависимостей и зона ответственности каждого слоя. -- [Модули](#модули) — границы ответственности, публичный API, типы модулей и отличие модуля от компонента. -- [Сегменты](#сегменты) — внутренние папки модуля (`ui/`, `parts/`, `hooks/`, `types/` и другие) и правила размещения файлов. -- [Монорепозитории](#монорепозитории) — применение SLM в `apps/` и `packages/`, правила выноса общих слоёв и ограничения для business. +- [Слои](/docs/architecture/layers.md) — уровни организации `src/`, направление зависимостей и зона ответственности каждого слоя. +- [Модули](/docs/architecture/modules.md) — границы ответственности, публичный API, типы модулей и отличие модуля от компонента. +- [Сегменты](/docs/architecture/segments.md) — внутренние папки модуля (`ui/`, `parts/`, `hooks/`, `types/` и другие) и правила размещения файлов. +- [Монорепозитории](/docs/architecture/monorepo.md) — применение SLM в `apps/` и `packages/`, правила выноса общих слоёв и ограничения для business. Рекомендуемый порядок чтения: обзор → слои → модули → сегменты → монорепозитории. @@ -513,7 +513,7 @@ backend-api/ └── index.ts # публичный API ``` -Подробное описание сегментов — в разделе [Сегменты](#сегменты). +Подробное описание сегментов — в разделе [Сегменты](/docs/architecture/segments.md). ### Публичный API @@ -558,9 +558,9 @@ Business-модуль всегда экспортирует фабрику. Фа #### Примеры -Пример реализации фабрики в React см. в [Создание фабрики](/examples/react/factory). +Пример реализации фабрики в React см. в [Создание фабрики](/docs/examples/react/factory.md). -Пример композиции фабрик в React screen-модуле см. в [Композиция фабрик](/examples/react/factory-composition). +Пример композиции фабрик в React screen-модуле см. в [Композиция фабрик](/docs/examples/react/factory-composition.md). ### Жизненный цикл @@ -614,7 +614,7 @@ Business-модуль всегда экспортирует фабрику. Фа - Не получает данные самостоятельно, не выбирает источник данных и не композирует данные. - Не содержит бизнес-логику или сценарную логику. -Если UI-сущности нужно что-то за пределами этих ограничений, она должна быть оформлена как модуль. Полная граница описана в разделе [Компонент](#компонент). +Если UI-сущности нужно что-то за пределами этих ограничений, она должна быть оформлена как модуль. Полная граница описана в разделе [Компонент](/docs/architecture/modules.md#компонент). Корневой файл модуля в `ui/` не размещается. Он лежит в корне модуля: `{module-name}.tsx`.