diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 3d99881..35ba398 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -20,22 +20,7 @@ jobs: - name: Установка зависимостей run: npm ci - - name: Сборка документации SLM Design - run: npm run docs:build:slm-design - - - name: Сборка документации NextJS Style Guide - run: npm run docs:build:nextjs-style-guide - - - name: Сборка документации Figma Adaptive Standards - run: npm run docs:build:figma-adaptive-standards - - - name: Генерация корневых артефактов - run: npm run site:generate - - - name: Сборка агентов - run: npm run agents:build - - - name: Сборка лендинга + - name: Сборка артефактов проекта run: npm run build docker: diff --git a/.gitignore b/.gitignore index 9b65dac..e92a8dc 100644 --- a/.gitignore +++ b/.gitignore @@ -13,14 +13,13 @@ dist-ssr *.local # Generated docs -docs/*/content/ -docs/*/.vitepress/cache/ +projects/*/docs/content/ +projects/*/docs/.vitepress/cache/ public/llms.txt public/slm-design/ public/nextjs-style-guide/ public/figma-adaptive-standards/ public/template-sync-strategy/ -public/agents/ # Editor directories and files .vscode/* diff --git a/Dockerfile b/Dockerfile index 76cd199..8bc2b2d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ COPY package*.json ./ RUN npm ci COPY . . -RUN npm run docs:build:slm-design && npm run docs:build:nextjs-style-guide && npm run docs:build:figma-adaptive-standards && npm run docs:build:template-sync-strategy && npm run agents:build && npm run build +RUN npm run build FROM caddy:2-alpine diff --git a/README.md b/README.md index 59d5cc2..54adceb 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ - VitePress-сборка для `Template Sync Strategy`. - Корневой `llms.txt` как карта всех документаций. - Собственные `llms.txt` и `llms-full.txt` внутри каждой документации. +- ZIP-архивы Markdown-контента для каждой документации. - Docker/Caddy-конфигурация для публикации статической сборки. - Gitea CI/CD для ветки `master`. @@ -27,15 +28,16 @@ ## Структура ```text -canons/ исходные материалы и черновики -docs/slm-design/ VitePress-сайт SLM Design -docs/nextjs-style-guide/ VitePress-сайт NextJS Style Guide -docs/figma-adaptive-standards/ VitePress-сайт Figma Adaptive Standards -docs/template-sync-strategy/ VitePress-сайт Template Sync Strategy -scripts/docs/ подготовка контента для документаций -scripts/site/ генерация корневых артефактов сайта -src/ React-лендинг -public/ статические файлы и сгенерированные документации +build.ts сборка всего репозитория +projects//build.ts сборка конкретного проекта +projects//canons/ исходные Markdown-материалы проекта +projects//docs/ VitePress-конфигурация проекта +projects//scripts/ уникальные вспомогательные скрипты проекта +projects/_shared/lib/ общие библиотечные функции сборки +projects/_shared/docs/ общая VitePress-тема +src/ React-лендинг +public/ статические файлы и сгенерированные документации +dist/ итоговая статическая сборка ``` ## Команды @@ -46,25 +48,39 @@ npm run dev ``` ```bash -npm run docs:build:slm-design -npm run docs:build:nextjs-style-guide -npm run docs:build:figma-adaptive-standards -npm run docs:build:template-sync-strategy -npm run site:generate npm run build ``` Основные скрипты: - `npm run dev` — запускает Vite dev server. -- `npm run docs:build:slm-design` — подготавливает и собирает VitePress-документацию SLM Design. -- `npm run docs:build:nextjs-style-guide` — подготавливает и собирает VitePress-документацию NextJS Style Guide. -- `npm run docs:build:figma-adaptive-standards` — подготавливает и собирает VitePress-документацию Figma Adaptive Standards. -- `npm run docs:build:template-sync-strategy` — подготавливает и собирает VitePress-документацию Template Sync Strategy. -- `npm run site:generate` — генерирует корневой `public/llms.txt` из `src/config/docs.config.ts` и хардкод-секций. -- `npm run build` — генерирует корневые артефакты и собирает лендинг. +- `npm run build` — одной командой собирает проектные документации, ZIP-архивы, корневой `llms.txt`, агентов и лендинг. +- `npm run build:slm-design` — собирает только проект `SLM Design`. +- `npm run build:nextjs-style-guide` — собирает только проект `NextJS Style Guide`. +- `npm run build:figma-adaptive-standards` — собирает только проект `Figma Adaptive Standards`. +- `npm run build:template-sync-strategy` — собирает только проект `Template Sync Strategy`. +- `npm run app:build` — собирает React/Vite-лендинг без проектных артефактов. - `npm run lint` — запускает ESLint. +## Проекты + +Каждая документация живёт в собственной папке `projects/` и сама владеет исходниками, конфигами и сборкой. + +```text +projects/slm-design/ + build.ts + project.config.ts + canons/ + docs/ + docs.config.ts + .vitepress/ + scripts/ +``` + +Общая команда `npm run build` запускает корневой `build.ts`. Он последовательно вызывает `projects//build.ts`, затем собирает общие артефакты репозитория. + +Если скрипт является библиотечной функцией сборки, он лежит в `projects/_shared/lib`. Если скрипт уникален для проекта, он лежит в `projects//scripts`. + ## LLM-артефакты Корневой файл: @@ -86,6 +102,10 @@ npm run build /figma-adaptive-standards/llms-full.txt /template-sync-strategy/llms.txt /template-sync-strategy/llms-full.txt +/slm-design/slm-design.zip +/nextjs-style-guide/nextjs-style-guide.zip +/figma-adaptive-standards/figma-adaptive-standards.zip +/template-sync-strategy/template-sync-strategy.zip ``` Корневой `llms-full.txt` намеренно не создаётся. Полные bundles остаются внутри конкретных документаций. @@ -114,10 +134,6 @@ docker build -t all-docs:test . Docker-сборка выполняет: ```bash -npm run docs:build:slm-design -npm run docs:build:nextjs-style-guide -npm run docs:build:figma-adaptive-standards -npm run docs:build:template-sync-strategy npm run build ``` diff --git a/agents/frontend-architect/source/AGENT.md b/agents/frontend-architect/source/AGENT.md deleted file mode 100644 index fd1f5ed..0000000 --- a/agents/frontend-architect/source/AGENT.md +++ /dev/null @@ -1,88 +0,0 @@ -# Frontend Architect - -## Роль - -Ты frontend-архитектор проекта. К тебе обращаются, когда нужно понять, как правильно спроектировать frontend-часть задачи: где создать код, какие модули затронуть, как разделить ответственность, как связать части приложения и не сломать архитектурные границы. - -В этом проекте архитектурным стандартом является SLM Design. Используй его как рабочую модель для всех решений: слой, модуль, сегмент, публичный API, направление зависимостей, business factory и композиция. - -## Граница ответственности - -- По умолчанию не пиши production-код. -- Не реализуй фичи как frontend-разработчик без явного запроса пользователя. -- Проектируй реализацию задачи: какие слои, модули, сегменты, public API и factory нужны. -- Точно указывай, где создавать или изменять файлы: слой, модуль, сегмент, назначение файла. -- Объясняй, почему код должен жить именно там, а не в другом месте. -- Проводь архитектурное ревью существующего или предлагаемого кода. -- Переходи к правкам кода только если пользователь явно попросил внести изменения. - -## Архитектурная основа - -Единственная архитектура проекта — SLM Design. Все frontend-решения принимай только в терминах SLM: слой, модуль, сегмент, публичный API, направление зависимостей, business factory. - -Не вводи альтернативные архитектурные модели и не объясняй решения через них. - -## Рабочий процесс - -1. Пойми пользовательскую задачу как frontend-изменение: экран, фича, домен, UI-блок, сервис, состояние, данные или инфраструктура. -2. Найди существующую структуру проекта, если решение зависит от текущего кода. -3. Определи слой SLM, где должна жить основная ответственность. -4. Определи модуль или модули, которые нужно создать или изменить. -5. Определи сегменты и конкретные файлы внутри модулей. -6. Определи публичные API, допустимые импорты и runtime-зависимости. -7. Если решение спорное, открой relevant reference и принимай решение по нему. -8. Сформулируй итог: как реализовать задачу по SLM, куда что положить, какие границы не нарушать. -9. Если пользователь попросил код, сначала зафиксируй архитектурное решение, потом выполняй минимальные правки. - -## Инварианты SLM - -- Импорты между модулями идут только через публичный API. -- Deep imports во внутренние сегменты чужого модуля запрещены. -- Зависимости идут по направлению SLM-слоёв. -- Runtime-связи между business-доменами идут через factory. -- `import type` не считается runtime-зависимостью. -- Доменные типы не выносятся в `shared`. -- `shared` не знает о продукте и доменах. -- `ui` не содержит бизнес-логику, сценарную логику и обращения к API. - -## Архитектурные развилки - -При спорных решениях не пересказывай правила из памяти. Открой нужный reference и прими решение по нему. - -- Слой и направление зависимостей → `references/slm-layers.md`. -- Модуль, компонент, публичный API, factory → `references/slm-modules.md`. -- Размещение файлов внутри модуля → `references/slm-segments.md`. -- Monorepo и `packages/*` → `references/slm-monorepo.md`. -- Business factory → `references/slm-react-factory.md`. -- Композиция business factories → `references/slm-react-factory-composition.md`. -- Композиция через Provider → `references/slm-react-composition-provider.md`. - -## Что проектировать - -- Новый экран: определить `screens/{name}`, локальные `parts/`, нужные business/widget/ui зависимости. -- Новый UI-блок: решить, это локальный `parts/`, `widgets`, `business/{domain}/parts` или `ui`. -- Новая фича: определить доменную принадлежность, business-модуль, factory API и точку композиции. -- Новый business-домен: определить factory, types, hooks/services/mappers/ui и public API. -- Новый сервис: определить, это `infra` или локальная часть модуля. -- Общая утилита: проверить, действительно ли это `shared`, а не локальный `lib/` модуля. -- Monorepo-вынос: проверить, допустим ли `packages/ui`, `packages/infra` или `packages/shared`. - -## Формат ответа - -Если пользователь просит архитектурное решение, отвечай коротко: - -```text -Решение: ... -Почему: ... -Куда: ... -Что создать/изменить: ... -Зависимости: ... -Ограничения: ... -Reference: ... -``` - -Если пользователь просит ревью, сначала перечисли нарушения и риски, затем предложи SLM-совместимое исправление. - -## Поведение при конфликте - -Если запрос пользователя требует нарушить SLM, не делай это молча. Коротко объясни конфликт и предложи SLM-совместимый вариант. Если правил недостаточно для решения, задай один уточняющий вопрос. diff --git a/agents/frontend-architect/source/manifest.json b/agents/frontend-architect/source/manifest.json deleted file mode 100644 index 4685795..0000000 --- a/agents/frontend-architect/source/manifest.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "frontend-architect", - "title": "Frontend Architect", - "version": "0.1.0", - "description": "Frontend-архитектор для работы по SLM Design.", - "entry": "AGENT.md", - "references": [ - "references/slm-overview.md", - "references/slm-layers.md", - "references/slm-modules.md", - "references/slm-segments.md", - "references/slm-monorepo.md", - "references/slm-react-factory.md", - "references/slm-react-factory-composition.md", - "references/slm-react-composition-provider.md" - ] -} diff --git a/agents/frontend-architect/source/references.json b/agents/frontend-architect/source/references.json deleted file mode 100644 index 5150f0b..0000000 --- a/agents/frontend-architect/source/references.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "references": [ - { - "source": "canons/slm-design/architecture/index.md", - "target": "references/slm-overview.md" - }, - { - "source": "canons/slm-design/architecture/layers.md", - "target": "references/slm-layers.md" - }, - { - "source": "canons/slm-design/architecture/modules.md", - "target": "references/slm-modules.md" - }, - { - "source": "canons/slm-design/architecture/segments.md", - "target": "references/slm-segments.md" - }, - { - "source": "canons/slm-design/architecture/monorepo.md", - "target": "references/slm-monorepo.md" - }, - { - "source": "canons/slm-design/examples/react/factory.md", - "target": "references/slm-react-factory.md" - }, - { - "source": "canons/slm-design/examples/react/factory-composition.md", - "target": "references/slm-react-factory-composition.md" - }, - { - "source": "canons/slm-design/examples/react/composition-provider.md", - "target": "references/slm-react-composition-provider.md" - } - ] -} diff --git a/build.ts b/build.ts new file mode 100644 index 0000000..be20d0f --- /dev/null +++ b/build.ts @@ -0,0 +1,9 @@ +import { generateRootLlms } from './projects/_shared/lib/root-llms'; +import { run } from './projects/_shared/lib/run'; + +run('npm', ['run', 'build:slm-design']); +run('npm', ['run', 'build:nextjs-style-guide']); +run('npm', ['run', 'build:figma-adaptive-standards']); +run('npm', ['run', 'build:template-sync-strategy']); +generateRootLlms(); +run('npm', ['run', 'app:build']); diff --git a/docs/figma-adaptive-standards/.vitepress/theme/index.ts b/docs/figma-adaptive-standards/.vitepress/theme/index.ts deleted file mode 100644 index e0013e9..0000000 --- a/docs/figma-adaptive-standards/.vitepress/theme/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from '../../../shared/vitepress/theme'; diff --git a/docs/nextjs-style-guide/.vitepress/theme/index.ts b/docs/nextjs-style-guide/.vitepress/theme/index.ts deleted file mode 100644 index e0013e9..0000000 --- a/docs/nextjs-style-guide/.vitepress/theme/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from '../../../shared/vitepress/theme'; diff --git a/docs/slm-design/.vitepress/theme/index.ts b/docs/slm-design/.vitepress/theme/index.ts deleted file mode 100644 index e0013e9..0000000 --- a/docs/slm-design/.vitepress/theme/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from '../../../shared/vitepress/theme'; diff --git a/docs/template-sync-strategy/.vitepress/theme/index.ts b/docs/template-sync-strategy/.vitepress/theme/index.ts deleted file mode 100644 index e0013e9..0000000 --- a/docs/template-sync-strategy/.vitepress/theme/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from '../../../shared/vitepress/theme'; diff --git a/eslint.config.js b/eslint.config.js index 34e6109..db09e20 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -8,8 +8,8 @@ import { defineConfig, globalIgnores } from 'eslint/config' export default defineConfig([ globalIgnores([ 'dist', - 'docs/*/content', - 'docs/*/.vitepress/cache', + 'projects/*/docs/content', + 'projects/*/docs/.vitepress/cache', 'public', ]), { diff --git a/package.json b/package.json index 3d35900..c41b567 100644 --- a/package.json +++ b/package.json @@ -5,18 +5,12 @@ "type": "module", "scripts": { "dev": "vite", - "build": "npm run site:generate && tsc -b && vite build", - "docs:prepare:slm-design": "tsx scripts/docs/prepare.ts slm-design", - "docs:build:slm-design": "npm run docs:prepare:slm-design && vitepress build docs/slm-design", - "docs:prepare:nextjs-style-guide": "tsx scripts/docs/prepare.ts nextjs-style-guide", - "docs:build:nextjs-style-guide": "npm run docs:prepare:nextjs-style-guide && vitepress build docs/nextjs-style-guide", - "docs:prepare:figma-adaptive-standards": "tsx scripts/docs/prepare.ts figma-adaptive-standards", - "docs:build:figma-adaptive-standards": "npm run docs:prepare:figma-adaptive-standards && vitepress build docs/figma-adaptive-standards", - "docs:prepare:template-sync-strategy": "tsx scripts/docs/prepare.ts template-sync-strategy", - "docs:build:template-sync-strategy": "npm run docs:prepare:template-sync-strategy && vitepress build docs/template-sync-strategy", - "site:generate": "tsx scripts/site/generate-artifacts.ts", - "agent:build:frontend-architect": "tsx agents/frontend-architect/scripts/build.ts", - "agents:build": "npm run agent:build:frontend-architect", + "build": "tsx build.ts", + "app:build": "tsc -b && vite build", + "build:slm-design": "tsx projects/slm-design/build.ts", + "build:nextjs-style-guide": "tsx projects/nextjs-style-guide/build.ts", + "build:figma-adaptive-standards": "tsx projects/figma-adaptive-standards/build.ts", + "build:template-sync-strategy": "tsx projects/template-sync-strategy/build.ts", "lint": "eslint .", "preview": "vite preview" }, diff --git a/docs/shared/vitepress/HomeLink.vue b/projects/_shared/docs/vitepress/HomeLink.vue similarity index 100% rename from docs/shared/vitepress/HomeLink.vue rename to projects/_shared/docs/vitepress/HomeLink.vue diff --git a/docs/shared/vitepress/theme.ts b/projects/_shared/docs/vitepress/theme.ts similarity index 100% rename from docs/shared/vitepress/theme.ts rename to projects/_shared/docs/vitepress/theme.ts diff --git a/docs/shared/vitepress/themeHead.ts b/projects/_shared/docs/vitepress/themeHead.ts similarity index 100% rename from docs/shared/vitepress/themeHead.ts rename to projects/_shared/docs/vitepress/themeHead.ts diff --git a/projects/_shared/lib/prepare-docs.ts b/projects/_shared/lib/prepare-docs.ts new file mode 100644 index 0000000..54e5b61 --- /dev/null +++ b/projects/_shared/lib/prepare-docs.ts @@ -0,0 +1,112 @@ +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} страниц`); +} diff --git a/projects/_shared/lib/root-llms.ts b/projects/_shared/lib/root-llms.ts new file mode 100644 index 0000000..472426d --- /dev/null +++ b/projects/_shared/lib/root-llms.ts @@ -0,0 +1,51 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +import { docs } from '../../../src/config/docs.config'; + +const siteTitle = 'Документация'; +const siteDescription = 'Единое пространство для идей, черновиков и первых версий документаций, которые ещё формируются и постепенно становятся самостоятельными материалами.'; + +function formatMarkdownLink(label: string, href: string, description: string) { + return `- [${label}](${href}): ${description}`; +} + +function findDocLink(doc: (typeof docs)[number], label: string) { + return doc.links.find((link) => link.label === label); +} + +export function generateRootLlms(rootDir = process.cwd()) { + const publicDir = path.join(rootDir, 'public'); + const llmsPath = path.join(publicDir, 'llms.txt'); + const content = [ + `# ${siteTitle}`, + '', + `> ${siteDescription}`, + '', + 'Этот файл является корневой картой документаций. Для работы с конкретным направлением используйте его собственный `llms.txt`.', + '', + '## Documentation', + '', + ...docs + .map((doc) => { + const link = findDocLink(doc, 'llms.txt'); + return link ? formatMarkdownLink(doc.title, link.href, doc.description) : undefined; + }) + .filter(Boolean), + '', + '## Optional', + '', + ...docs + .map((doc) => { + const link = findDocLink(doc, 'llms-full.txt'); + return link ? formatMarkdownLink(`${doc.title} full`, link.href, `Полный bundle документации: ${doc.label.toLowerCase()}.`) : undefined; + }) + .filter(Boolean), + '', + ].join('\n'); + + fs.mkdirSync(publicDir, { recursive: true }); + fs.writeFileSync(llmsPath, content, 'utf8'); + + console.log(`Сгенерирован ${path.relative(rootDir, llmsPath)}`); +} diff --git a/projects/_shared/lib/run.ts b/projects/_shared/lib/run.ts new file mode 100644 index 0000000..afc0896 --- /dev/null +++ b/projects/_shared/lib/run.ts @@ -0,0 +1,12 @@ +import { spawnSync } from 'node:child_process'; + +export function run(command: string, args: string[], cwd = process.cwd()) { + const result = spawnSync(command, args, { + cwd, + stdio: 'inherit', + shell: process.platform === 'win32', + }); + + if (result.error) throw result.error; + if (result.status !== 0) throw new Error(`Command failed: ${[command, ...args].join(' ')}`); +} diff --git a/agents/frontend-architect/scripts/build.ts b/projects/_shared/lib/zip.ts similarity index 57% rename from agents/frontend-architect/scripts/build.ts rename to projects/_shared/lib/zip.ts index 58ed5b2..53a2f66 100644 --- a/agents/frontend-architect/scripts/build.ts +++ b/projects/_shared/lib/zip.ts @@ -1,53 +1,24 @@ import fs from 'node:fs'; import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -type ReferenceConfig = { - references: Array<{ - source: string; - target: string; - }>; -}; type ZipEntry = { name: string; content: Buffer; }; -const scriptDir = path.dirname(fileURLToPath(import.meta.url)); -const agentDir = path.resolve(scriptDir, '..'); -const rootDir = path.resolve(agentDir, '../..'); -const sourceDir = path.join(agentDir, 'source'); -const tempDir = path.join(agentDir, '.tmp'); -const packageName = 'frontend-architect'; -const packageDir = path.join(tempDir, packageName); -const publicAgentsDir = path.join(rootDir, 'public', 'agents'); -const zipPath = path.join(publicAgentsDir, `${packageName}.zip`); - -function readJson(filePath: string): T { - return JSON.parse(fs.readFileSync(filePath, 'utf8')) as T; -} - -function copyFile(sourcePath: string, targetPath: string) { - fs.mkdirSync(path.dirname(targetPath), { recursive: true }); - fs.copyFileSync(sourcePath, targetPath); -} - -function collectFiles(dir: string, baseDir = dir): ZipEntry[] { +function collectFiles(dir: string, baseDir = dir, archiveRoot = path.basename(dir)): ZipEntry[] { return fs .readdirSync(dir, { withFileTypes: true }) .flatMap((entry) => { const entryPath = path.join(dir, entry.name); - if (entry.isDirectory()) { - return collectFiles(entryPath, baseDir); - } + if (entry.isDirectory()) return collectFiles(entryPath, baseDir, archiveRoot); const relativePath = path.relative(baseDir, entryPath).split(path.sep).join('/'); return [ { - name: `${packageName}/${relativePath}`, + name: `${archiveRoot}/${relativePath}`, content: fs.readFileSync(entryPath), }, ]; @@ -120,7 +91,7 @@ function createZip(entries: ZipEntry[]) { localParts.push(localHeader, entry.content); - const centralHeader = Buffer.concat([ + centralParts.push(Buffer.concat([ writeUInt32(0x02014b50), writeUInt16(20), writeUInt16(20), @@ -139,9 +110,8 @@ function createZip(entries: ZipEntry[]) { writeUInt32(0), writeUInt32(offset), fileName, - ]); + ])); - centralParts.push(centralHeader); offset += localHeader.length + size; } @@ -160,30 +130,7 @@ function createZip(entries: ZipEntry[]) { return Buffer.concat([...localParts, centralDirectory, endOfCentralDirectory]); } -function buildAgent() { - const referencesConfig = readJson(path.join(sourceDir, 'references.json')); - - fs.rmSync(tempDir, { recursive: true, force: true }); - fs.mkdirSync(packageDir, { recursive: true }); - - copyFile(path.join(sourceDir, 'AGENT.md'), path.join(packageDir, 'AGENT.md')); - copyFile(path.join(sourceDir, 'manifest.json'), path.join(packageDir, 'manifest.json')); - - for (const reference of referencesConfig.references) { - const sourcePath = path.join(rootDir, reference.source); - - if (!fs.existsSync(sourcePath)) { - throw new Error(`Reference not found: ${reference.source}`); - } - - copyFile(sourcePath, path.join(packageDir, reference.target)); - } - - fs.mkdirSync(publicAgentsDir, { recursive: true }); - fs.writeFileSync(zipPath, createZip(collectFiles(packageDir))); - fs.rmSync(tempDir, { recursive: true, force: true }); - - console.log(`Built ${path.relative(rootDir, zipPath)}`); +export function writeZipFromDirectory(sourceDir: string, zipPath: string, archiveRoot = path.basename(sourceDir)) { + fs.mkdirSync(path.dirname(zipPath), { recursive: true }); + fs.writeFileSync(zipPath, createZip(collectFiles(sourceDir, sourceDir, archiveRoot))); } - -buildAgent(); diff --git a/projects/figma-adaptive-standards/build.ts b/projects/figma-adaptive-standards/build.ts new file mode 100644 index 0000000..145ac87 --- /dev/null +++ b/projects/figma-adaptive-standards/build.ts @@ -0,0 +1,20 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { prepareDocs } from '../_shared/lib/prepare-docs'; +import { run } from '../_shared/lib/run'; +import { writeZipFromDirectory } from '../_shared/lib/zip'; +import config from './project.config'; + +const projectDir = path.dirname(fileURLToPath(import.meta.url)); +const rootDir = path.resolve(projectDir, '../..'); +const docsDir = path.join(projectDir, config.docsDir); + +await prepareDocs(projectDir, config); +run('npx', ['vitepress', 'build', docsDir], rootDir); + +if (config.archive) { + const zipPath = path.join(rootDir, 'public', config.slug, `${config.slug}.zip`); + writeZipFromDirectory(path.join(docsDir, 'content'), zipPath, config.slug); + console.log(`Собран ${path.relative(rootDir, zipPath)}`); +} diff --git a/canons/figma/adaptive-layout-requirements.checklist.md b/projects/figma-adaptive-standards/canons/adaptive-layout-requirements.checklist.md similarity index 100% rename from canons/figma/adaptive-layout-requirements.checklist.md rename to projects/figma-adaptive-standards/canons/adaptive-layout-requirements.checklist.md diff --git a/canons/figma/adaptive-layout-requirements.full.md b/projects/figma-adaptive-standards/canons/adaptive-layout-requirements.full.md similarity index 100% rename from canons/figma/adaptive-layout-requirements.full.md rename to projects/figma-adaptive-standards/canons/adaptive-layout-requirements.full.md diff --git a/canons/figma/adaptive-layout-requirements.short.md b/projects/figma-adaptive-standards/canons/adaptive-layout-requirements.short.md similarity index 100% rename from canons/figma/adaptive-layout-requirements.short.md rename to projects/figma-adaptive-standards/canons/adaptive-layout-requirements.short.md diff --git a/canons/figma/index.md b/projects/figma-adaptive-standards/canons/index.md similarity index 100% rename from canons/figma/index.md rename to projects/figma-adaptive-standards/canons/index.md diff --git a/docs/figma-adaptive-standards/.vitepress/config.ts b/projects/figma-adaptive-standards/docs/.vitepress/config.ts similarity index 87% rename from docs/figma-adaptive-standards/.vitepress/config.ts rename to projects/figma-adaptive-standards/docs/.vitepress/config.ts index 1075be6..fd1ce4c 100644 --- a/docs/figma-adaptive-standards/.vitepress/config.ts +++ b/projects/figma-adaptive-standards/docs/.vitepress/config.ts @@ -1,7 +1,7 @@ import { defineConfig } from 'vitepress'; import taskLists from 'markdown-it-task-lists'; import llmstxt from 'vitepress-plugin-llms'; -import { themeSyncHead } from '../../shared/vitepress/themeHead'; +import { themeSyncHead } from '../../../_shared/docs/vitepress/themeHead'; import { sidebar, site } from '../docs.config'; export default defineConfig({ diff --git a/projects/figma-adaptive-standards/docs/.vitepress/theme/index.ts b/projects/figma-adaptive-standards/docs/.vitepress/theme/index.ts new file mode 100644 index 0000000..94e709e --- /dev/null +++ b/projects/figma-adaptive-standards/docs/.vitepress/theme/index.ts @@ -0,0 +1 @@ +export { default } from '../../../../_shared/docs/vitepress/theme'; diff --git a/docs/figma-adaptive-standards/docs.config.ts b/projects/figma-adaptive-standards/docs/docs.config.ts similarity index 67% rename from docs/figma-adaptive-standards/docs.config.ts rename to projects/figma-adaptive-standards/docs/docs.config.ts index 5eacdd2..44686ae 100644 --- a/docs/figma-adaptive-standards/docs.config.ts +++ b/projects/figma-adaptive-standards/docs/docs.config.ts @@ -2,22 +2,22 @@ export const site = { title: 'Figma Adaptive Standards', description: 'Стандарты подготовки адаптивных макетов в Figma', base: '/figma-adaptive-standards/', - outDir: '../../public/figma-adaptive-standards', + outDir: '../../../public/figma-adaptive-standards', }; /** * Карта монтирования исходных канонов в VitePress-документацию. * * `source` указывает на markdown-файл внутри `canons/`. - * `target` задаёт путь, по которому этот файл попадёт в `docs/figma-adaptive-standards/content/` + * `target` задаёт путь, по которому этот файл попадёт в `docs/content/` * и станет страницей итоговой документации. */ export const mounts = [ - { target: 'index.md', source: 'figma/index.md' }, - { target: 'overview.md', source: 'figma/index.md' }, - { target: 'adaptive-layout-requirements/short.md', source: 'figma/adaptive-layout-requirements.short.md' }, - { target: 'adaptive-layout-requirements/full.md', source: 'figma/adaptive-layout-requirements.full.md' }, - { target: 'adaptive-layout-requirements/checklist.md', source: 'figma/adaptive-layout-requirements.checklist.md' }, + { target: 'index.md', source: 'canons/index.md' }, + { target: 'overview.md', source: 'canons/index.md' }, + { target: 'adaptive-layout-requirements/short.md', source: 'canons/adaptive-layout-requirements.short.md' }, + { target: 'adaptive-layout-requirements/full.md', source: 'canons/adaptive-layout-requirements.full.md' }, + { target: 'adaptive-layout-requirements/checklist.md', source: 'canons/adaptive-layout-requirements.checklist.md' }, ]; export const sidebar = [ diff --git a/projects/figma-adaptive-standards/project.config.ts b/projects/figma-adaptive-standards/project.config.ts new file mode 100644 index 0000000..6c22783 --- /dev/null +++ b/projects/figma-adaptive-standards/project.config.ts @@ -0,0 +1,5 @@ +export default { + slug: 'figma-adaptive-standards', + docsDir: 'docs', + archive: true, +} as const; diff --git a/canons/style-guide/applied/stores.md b/projects/figma-adaptive-standards/scripts/.gitkeep similarity index 100% rename from canons/style-guide/applied/stores.md rename to projects/figma-adaptive-standards/scripts/.gitkeep diff --git a/projects/nextjs-style-guide/build.ts b/projects/nextjs-style-guide/build.ts new file mode 100644 index 0000000..145ac87 --- /dev/null +++ b/projects/nextjs-style-guide/build.ts @@ -0,0 +1,20 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { prepareDocs } from '../_shared/lib/prepare-docs'; +import { run } from '../_shared/lib/run'; +import { writeZipFromDirectory } from '../_shared/lib/zip'; +import config from './project.config'; + +const projectDir = path.dirname(fileURLToPath(import.meta.url)); +const rootDir = path.resolve(projectDir, '../..'); +const docsDir = path.join(projectDir, config.docsDir); + +await prepareDocs(projectDir, config); +run('npx', ['vitepress', 'build', docsDir], rootDir); + +if (config.archive) { + const zipPath = path.join(rootDir, 'public', config.slug, `${config.slug}.zip`); + writeZipFromDirectory(path.join(docsDir, 'content'), zipPath, config.slug); + console.log(`Собран ${path.relative(rootDir, zipPath)}`); +} diff --git a/canons/style-guide/DEVELOP.md b/projects/nextjs-style-guide/canons/DEVELOP.md similarity index 100% rename from canons/style-guide/DEVELOP.md rename to projects/nextjs-style-guide/canons/DEVELOP.md diff --git a/canons/style-guide/MAP.md b/projects/nextjs-style-guide/canons/MAP.md similarity index 100% rename from canons/style-guide/MAP.md rename to projects/nextjs-style-guide/canons/MAP.md diff --git a/canons/style-guide/applied/aliases.md b/projects/nextjs-style-guide/canons/applied/aliases.md similarity index 100% rename from canons/style-guide/applied/aliases.md rename to projects/nextjs-style-guide/canons/applied/aliases.md diff --git a/canons/style-guide/applied/biome.md b/projects/nextjs-style-guide/canons/applied/biome.md similarity index 100% rename from canons/style-guide/applied/biome.md rename to projects/nextjs-style-guide/canons/applied/biome.md diff --git a/canons/style-guide/applied/component.md b/projects/nextjs-style-guide/canons/applied/component.md similarity index 100% rename from canons/style-guide/applied/component.md rename to projects/nextjs-style-guide/canons/applied/component.md diff --git a/canons/style-guide/applied/creating-project/from-template.md b/projects/nextjs-style-guide/canons/applied/creating-project/from-template.md similarity index 100% rename from canons/style-guide/applied/creating-project/from-template.md rename to projects/nextjs-style-guide/canons/applied/creating-project/from-template.md diff --git a/canons/style-guide/applied/creating-project/manual.md b/projects/nextjs-style-guide/canons/applied/creating-project/manual.md similarity index 100% rename from canons/style-guide/applied/creating-project/manual.md rename to projects/nextjs-style-guide/canons/applied/creating-project/manual.md diff --git a/canons/style-guide/applied/creating-project/nextjs.md b/projects/nextjs-style-guide/canons/applied/creating-project/nextjs.md similarity index 100% rename from canons/style-guide/applied/creating-project/nextjs.md rename to projects/nextjs-style-guide/canons/applied/creating-project/nextjs.md diff --git a/canons/style-guide/applied/data-fetch/business-composition.md b/projects/nextjs-style-guide/canons/applied/data-fetch/business-composition.md similarity index 100% rename from canons/style-guide/applied/data-fetch/business-composition.md rename to projects/nextjs-style-guide/canons/applied/data-fetch/business-composition.md diff --git a/canons/style-guide/applied/data-fetch/client-get-hook.md b/projects/nextjs-style-guide/canons/applied/data-fetch/client-get-hook.md similarity index 100% rename from canons/style-guide/applied/data-fetch/client-get-hook.md rename to projects/nextjs-style-guide/canons/applied/data-fetch/client-get-hook.md diff --git a/canons/style-guide/applied/data-fetch/client-hooks-initial-data.md b/projects/nextjs-style-guide/canons/applied/data-fetch/client-hooks-initial-data.md similarity index 100% rename from canons/style-guide/applied/data-fetch/client-hooks-initial-data.md rename to projects/nextjs-style-guide/canons/applied/data-fetch/client-hooks-initial-data.md diff --git a/canons/style-guide/applied/data-fetch/index.md b/projects/nextjs-style-guide/canons/applied/data-fetch/index.md similarity index 100% rename from canons/style-guide/applied/data-fetch/index.md rename to projects/nextjs-style-guide/canons/applied/data-fetch/index.md diff --git a/canons/style-guide/applied/data-fetch/parallel-server-requests.md b/projects/nextjs-style-guide/canons/applied/data-fetch/parallel-server-requests.md similarity index 100% rename from canons/style-guide/applied/data-fetch/parallel-server-requests.md rename to projects/nextjs-style-guide/canons/applied/data-fetch/parallel-server-requests.md diff --git a/canons/style-guide/applied/data-fetch/pass-promise-down.md b/projects/nextjs-style-guide/canons/applied/data-fetch/pass-promise-down.md similarity index 100% rename from canons/style-guide/applied/data-fetch/pass-promise-down.md rename to projects/nextjs-style-guide/canons/applied/data-fetch/pass-promise-down.md diff --git a/canons/style-guide/applied/data-fetch/server-await.md b/projects/nextjs-style-guide/canons/applied/data-fetch/server-await.md similarity index 100% rename from canons/style-guide/applied/data-fetch/server-await.md rename to projects/nextjs-style-guide/canons/applied/data-fetch/server-await.md diff --git a/canons/style-guide/applied/fonts.md b/projects/nextjs-style-guide/canons/applied/fonts.md similarity index 100% rename from canons/style-guide/applied/fonts.md rename to projects/nextjs-style-guide/canons/applied/fonts.md diff --git a/canons/style-guide/applied/images.md b/projects/nextjs-style-guide/canons/applied/images.md similarity index 100% rename from canons/style-guide/applied/images.md rename to projects/nextjs-style-guide/canons/applied/images.md diff --git a/canons/style-guide/applied/localization.md b/projects/nextjs-style-guide/canons/applied/localization.md similarity index 100% rename from canons/style-guide/applied/localization.md rename to projects/nextjs-style-guide/canons/applied/localization.md diff --git a/canons/style-guide/applied/module.md b/projects/nextjs-style-guide/canons/applied/module.md similarity index 100% rename from canons/style-guide/applied/module.md rename to projects/nextjs-style-guide/canons/applied/module.md diff --git a/canons/style-guide/applied/page-level.md b/projects/nextjs-style-guide/canons/applied/page-level.md similarity index 100% rename from canons/style-guide/applied/page-level.md rename to projects/nextjs-style-guide/canons/applied/page-level.md diff --git a/canons/style-guide/applied/postcss.md b/projects/nextjs-style-guide/canons/applied/postcss.md similarity index 100% rename from canons/style-guide/applied/postcss.md rename to projects/nextjs-style-guide/canons/applied/postcss.md diff --git a/canons/style-guide/applied/project-structure.md b/projects/nextjs-style-guide/canons/applied/project-structure.md similarity index 100% rename from canons/style-guide/applied/project-structure.md rename to projects/nextjs-style-guide/canons/applied/project-structure.md diff --git a/canons/style-guide/applied/rest-client/index.md b/projects/nextjs-style-guide/canons/applied/rest-client/index.md similarity index 100% rename from canons/style-guide/applied/rest-client/index.md rename to projects/nextjs-style-guide/canons/applied/rest-client/index.md diff --git a/canons/style-guide/applied/rest-client/setup/auto.md b/projects/nextjs-style-guide/canons/applied/rest-client/setup/auto.md similarity index 100% rename from canons/style-guide/applied/rest-client/setup/auto.md rename to projects/nextjs-style-guide/canons/applied/rest-client/setup/auto.md diff --git a/canons/style-guide/applied/rest-client/setup/hooks.md b/projects/nextjs-style-guide/canons/applied/rest-client/setup/hooks.md similarity index 100% rename from canons/style-guide/applied/rest-client/setup/hooks.md rename to projects/nextjs-style-guide/canons/applied/rest-client/setup/hooks.md diff --git a/canons/style-guide/applied/rest-client/setup/index.md b/projects/nextjs-style-guide/canons/applied/rest-client/setup/index.md similarity index 100% rename from canons/style-guide/applied/rest-client/setup/index.md rename to projects/nextjs-style-guide/canons/applied/rest-client/setup/index.md diff --git a/canons/style-guide/applied/rest-client/setup/manual.md b/projects/nextjs-style-guide/canons/applied/rest-client/setup/manual.md similarity index 100% rename from canons/style-guide/applied/rest-client/setup/manual.md rename to projects/nextjs-style-guide/canons/applied/rest-client/setup/manual.md diff --git a/canons/style-guide/applied/rest-client/usage.md b/projects/nextjs-style-guide/canons/applied/rest-client/usage.md similarity index 100% rename from canons/style-guide/applied/rest-client/usage.md rename to projects/nextjs-style-guide/canons/applied/rest-client/usage.md diff --git a/projects/nextjs-style-guide/canons/applied/stores.md b/projects/nextjs-style-guide/canons/applied/stores.md new file mode 100644 index 0000000..e69de29 diff --git a/canons/style-guide/applied/styles/styles-setup.md b/projects/nextjs-style-guide/canons/applied/styles/styles-setup.md similarity index 100% rename from canons/style-guide/applied/styles/styles-setup.md rename to projects/nextjs-style-guide/canons/applied/styles/styles-setup.md diff --git a/canons/style-guide/applied/styles/styles-usage.md b/projects/nextjs-style-guide/canons/applied/styles/styles-usage.md similarity index 100% rename from canons/style-guide/applied/styles/styles-usage.md rename to projects/nextjs-style-guide/canons/applied/styles/styles-usage.md diff --git a/canons/style-guide/applied/svg-sprites/svg-sprites-intro.md b/projects/nextjs-style-guide/canons/applied/svg-sprites/svg-sprites-intro.md similarity index 100% rename from canons/style-guide/applied/svg-sprites/svg-sprites-intro.md rename to projects/nextjs-style-guide/canons/applied/svg-sprites/svg-sprites-intro.md diff --git a/canons/style-guide/applied/svg-sprites/svg-sprites-setup.md b/projects/nextjs-style-guide/canons/applied/svg-sprites/svg-sprites-setup.md similarity index 100% rename from canons/style-guide/applied/svg-sprites/svg-sprites-setup.md rename to projects/nextjs-style-guide/canons/applied/svg-sprites/svg-sprites-setup.md diff --git a/canons/style-guide/applied/svg-sprites/svg-sprites-usage.md b/projects/nextjs-style-guide/canons/applied/svg-sprites/svg-sprites-usage.md similarity index 100% rename from canons/style-guide/applied/svg-sprites/svg-sprites-usage.md rename to projects/nextjs-style-guide/canons/applied/svg-sprites/svg-sprites-usage.md diff --git a/canons/style-guide/applied/templates/templates-create.md b/projects/nextjs-style-guide/canons/applied/templates/templates-create.md similarity index 100% rename from canons/style-guide/applied/templates/templates-create.md rename to projects/nextjs-style-guide/canons/applied/templates/templates-create.md diff --git a/canons/style-guide/applied/templates/templates-intro.md b/projects/nextjs-style-guide/canons/applied/templates/templates-intro.md similarity index 100% rename from canons/style-guide/applied/templates/templates-intro.md rename to projects/nextjs-style-guide/canons/applied/templates/templates-intro.md diff --git a/canons/style-guide/applied/templates/templates-setup.md b/projects/nextjs-style-guide/canons/applied/templates/templates-setup.md similarity index 100% rename from canons/style-guide/applied/templates/templates-setup.md rename to projects/nextjs-style-guide/canons/applied/templates/templates-setup.md diff --git a/canons/style-guide/applied/templates/templates-usage.md b/projects/nextjs-style-guide/canons/applied/templates/templates-usage.md similarity index 100% rename from canons/style-guide/applied/templates/templates-usage.md rename to projects/nextjs-style-guide/canons/applied/templates/templates-usage.md diff --git a/canons/style-guide/applied/vscode.md b/projects/nextjs-style-guide/canons/applied/vscode.md similarity index 100% rename from canons/style-guide/applied/vscode.md rename to projects/nextjs-style-guide/canons/applied/vscode.md diff --git a/canons/style-guide/basics/code-style.md b/projects/nextjs-style-guide/canons/basics/code-style.md similarity index 100% rename from canons/style-guide/basics/code-style.md rename to projects/nextjs-style-guide/canons/basics/code-style.md diff --git a/canons/style-guide/basics/documentation.md b/projects/nextjs-style-guide/canons/basics/documentation.md similarity index 100% rename from canons/style-guide/basics/documentation.md rename to projects/nextjs-style-guide/canons/basics/documentation.md diff --git a/canons/style-guide/basics/naming.md b/projects/nextjs-style-guide/canons/basics/naming.md similarity index 100% rename from canons/style-guide/basics/naming.md rename to projects/nextjs-style-guide/canons/basics/naming.md diff --git a/canons/style-guide/basics/tech-stack.md b/projects/nextjs-style-guide/canons/basics/tech-stack.md similarity index 100% rename from canons/style-guide/basics/tech-stack.md rename to projects/nextjs-style-guide/canons/basics/tech-stack.md diff --git a/canons/style-guide/basics/typing.md b/projects/nextjs-style-guide/canons/basics/typing.md similarity index 100% rename from canons/style-guide/basics/typing.md rename to projects/nextjs-style-guide/canons/basics/typing.md diff --git a/canons/style-guide/index.md b/projects/nextjs-style-guide/canons/index.md similarity index 95% rename from canons/style-guide/index.md rename to projects/nextjs-style-guide/canons/index.md index d870c54..c33208d 100644 --- a/canons/style-guide/index.md +++ b/projects/nextjs-style-guide/canons/index.md @@ -16,7 +16,7 @@ description: Практический стайлгайд для разработ **Для проекта:** -- [nextjs-style-guide.zip](/nextjs-style-guide.zip) — Набор Markdown-файлов для распаковки в `./ai/nextjs-style-guide/` или другую папку проекта. +- [nextjs-style-guide.zip](/nextjs-style-guide/nextjs-style-guide.zip) — Набор Markdown-файлов для распаковки в `./ai/nextjs-style-guide/` или другую папку проекта. ## Структура документации diff --git a/canons/style-guide/workflow.md b/projects/nextjs-style-guide/canons/workflow.md similarity index 100% rename from canons/style-guide/workflow.md rename to projects/nextjs-style-guide/canons/workflow.md diff --git a/docs/template-sync-strategy/.vitepress/config.ts b/projects/nextjs-style-guide/docs/.vitepress/config.ts similarity index 82% rename from docs/template-sync-strategy/.vitepress/config.ts rename to projects/nextjs-style-guide/docs/.vitepress/config.ts index 1075be6..05d5f05 100644 --- a/docs/template-sync-strategy/.vitepress/config.ts +++ b/projects/nextjs-style-guide/docs/.vitepress/config.ts @@ -1,7 +1,7 @@ import { defineConfig } from 'vitepress'; import taskLists from 'markdown-it-task-lists'; import llmstxt from 'vitepress-plugin-llms'; -import { themeSyncHead } from '../../shared/vitepress/themeHead'; +import { themeSyncHead } from '../../../_shared/docs/vitepress/themeHead'; import { sidebar, site } from '../docs.config'; export default defineConfig({ @@ -11,6 +11,7 @@ export default defineConfig({ outDir: site.outDir, srcDir: 'content', cleanUrls: true, + ignoreDeadLinks: [/^\/slm-design\//], head: [...themeSyncHead], vite: { plugins: [llmstxt()], diff --git a/projects/nextjs-style-guide/docs/.vitepress/theme/index.ts b/projects/nextjs-style-guide/docs/.vitepress/theme/index.ts new file mode 100644 index 0000000..94e709e --- /dev/null +++ b/projects/nextjs-style-guide/docs/.vitepress/theme/index.ts @@ -0,0 +1 @@ +export { default } from '../../../../_shared/docs/vitepress/theme'; diff --git a/docs/nextjs-style-guide/docs.config.ts b/projects/nextjs-style-guide/docs/docs.config.ts similarity index 58% rename from docs/nextjs-style-guide/docs.config.ts rename to projects/nextjs-style-guide/docs/docs.config.ts index 8f12bea..4015695 100644 --- a/docs/nextjs-style-guide/docs.config.ts +++ b/projects/nextjs-style-guide/docs/docs.config.ts @@ -2,71 +2,71 @@ export const site = { title: 'NextJS Style Guide', description: 'Практический стайлгайд для разработки frontend-приложений на Next.js и TypeScript', base: '/nextjs-style-guide/', - outDir: '../../public/nextjs-style-guide', + outDir: '../../../public/nextjs-style-guide', }; /** * Карта монтирования исходных канонов в VitePress-документацию. * - * SLM-разделы берутся только из корневого `canons/slm-design/`, чтобы - * NextJS-гайд не содержал собственных дублей архитектурного канона. + * SLM-разделы берутся из проекта `slm-design`, чтобы NextJS-гайд не содержал + * собственных дублей архитектурного канона. */ export const mounts = [ - { target: 'index.md', source: 'style-guide/index.md' }, - { target: 'workflow.md', source: 'style-guide/workflow.md' }, + { target: 'index.md', source: 'canons/index.md' }, + { target: 'workflow.md', source: 'canons/workflow.md' }, - { target: 'slm-design/architecture/index.md', source: 'slm-design/architecture/index.md' }, - { target: 'slm-design/architecture/layers.md', source: 'slm-design/architecture/layers.md' }, - { target: 'slm-design/architecture/modules.md', source: 'slm-design/architecture/modules.md' }, - { target: 'slm-design/architecture/segments.md', source: 'slm-design/architecture/segments.md' }, - { target: 'slm-design/architecture/monorepo.md', source: 'slm-design/architecture/monorepo.md' }, - { target: 'slm-design/examples/react/factory.md', source: 'slm-design/examples/react/factory.md' }, - { target: 'slm-design/examples/react/factory-composition.md', source: 'slm-design/examples/react/factory-composition.md' }, - { target: 'slm-design/examples/react/composition-provider.md', source: 'slm-design/examples/react/composition-provider.md' }, + { target: 'slm-design/architecture/index.md', source: '../slm-design/canons/architecture/index.md' }, + { target: 'slm-design/architecture/layers.md', source: '../slm-design/canons/architecture/layers.md' }, + { target: 'slm-design/architecture/modules.md', source: '../slm-design/canons/architecture/modules.md' }, + { target: 'slm-design/architecture/segments.md', source: '../slm-design/canons/architecture/segments.md' }, + { target: 'slm-design/architecture/monorepo.md', source: '../slm-design/canons/architecture/monorepo.md' }, + { target: 'slm-design/examples/react/factory.md', source: '../slm-design/canons/examples/react/factory.md' }, + { target: 'slm-design/examples/react/factory-composition.md', source: '../slm-design/canons/examples/react/factory-composition.md' }, + { target: 'slm-design/examples/react/composition-provider.md', source: '../slm-design/canons/examples/react/composition-provider.md' }, - { target: 'basics/tech-stack.md', source: 'style-guide/basics/tech-stack.md' }, - { target: 'basics/naming.md', source: 'style-guide/basics/naming.md' }, - { target: 'basics/code-style.md', source: 'style-guide/basics/code-style.md' }, - { target: 'basics/documentation.md', source: 'style-guide/basics/documentation.md' }, - { target: 'basics/typing.md', source: 'style-guide/basics/typing.md' }, + { target: 'basics/tech-stack.md', source: 'canons/basics/tech-stack.md' }, + { target: 'basics/naming.md', source: 'canons/basics/naming.md' }, + { target: 'basics/code-style.md', source: 'canons/basics/code-style.md' }, + { target: 'basics/documentation.md', source: 'canons/basics/documentation.md' }, + { target: 'basics/typing.md', source: 'canons/basics/typing.md' }, - { target: 'applied/creating-project/from-template.md', source: 'style-guide/applied/creating-project/from-template.md' }, - { target: 'applied/creating-project/manual.md', source: 'style-guide/applied/creating-project/manual.md' }, - { target: 'applied/creating-project/nextjs.md', source: 'style-guide/applied/creating-project/nextjs.md' }, - { target: 'applied/project-structure.md', source: 'style-guide/applied/project-structure.md' }, - { target: 'applied/page-level.md', source: 'style-guide/applied/page-level.md' }, - { target: 'applied/component.md', source: 'style-guide/applied/component.md' }, - { target: 'applied/module.md', source: 'style-guide/applied/module.md' }, - { target: 'applied/rest-client/index.md', source: 'style-guide/applied/rest-client/index.md' }, - { target: 'applied/rest-client/setup/index.md', source: 'style-guide/applied/rest-client/setup/index.md' }, - { target: 'applied/rest-client/setup/auto.md', source: 'style-guide/applied/rest-client/setup/auto.md' }, - { target: 'applied/rest-client/setup/manual.md', source: 'style-guide/applied/rest-client/setup/manual.md' }, - { target: 'applied/rest-client/setup/hooks.md', source: 'style-guide/applied/rest-client/setup/hooks.md' }, - { target: 'applied/rest-client/usage.md', source: 'style-guide/applied/rest-client/usage.md' }, - { target: 'applied/data-fetch/index.md', source: 'style-guide/applied/data-fetch/index.md' }, - { target: 'applied/data-fetch/server-await.md', source: 'style-guide/applied/data-fetch/server-await.md' }, - { target: 'applied/data-fetch/parallel-server-requests.md', source: 'style-guide/applied/data-fetch/parallel-server-requests.md' }, - { target: 'applied/data-fetch/pass-promise-down.md', source: 'style-guide/applied/data-fetch/pass-promise-down.md' }, - { target: 'applied/data-fetch/client-hooks-initial-data.md', source: 'style-guide/applied/data-fetch/client-hooks-initial-data.md' }, - { target: 'applied/data-fetch/client-get-hook.md', source: 'style-guide/applied/data-fetch/client-get-hook.md' }, - { target: 'applied/data-fetch/business-composition.md', source: 'style-guide/applied/data-fetch/business-composition.md' }, - { target: 'applied/styles/styles-setup.md', source: 'style-guide/applied/styles/styles-setup.md' }, - { target: 'applied/styles/styles-usage.md', source: 'style-guide/applied/styles/styles-usage.md' }, - { target: 'applied/svg-sprites/svg-sprites-intro.md', source: 'style-guide/applied/svg-sprites/svg-sprites-intro.md' }, - { target: 'applied/svg-sprites/svg-sprites-setup.md', source: 'style-guide/applied/svg-sprites/svg-sprites-setup.md' }, - { target: 'applied/svg-sprites/svg-sprites-usage.md', source: 'style-guide/applied/svg-sprites/svg-sprites-usage.md' }, - { target: 'applied/images.md', source: 'style-guide/applied/images.md' }, - { target: 'applied/fonts.md', source: 'style-guide/applied/fonts.md' }, - { target: 'applied/aliases.md', source: 'style-guide/applied/aliases.md' }, - { target: 'applied/templates/templates-intro.md', source: 'style-guide/applied/templates/templates-intro.md' }, - { target: 'applied/templates/templates-setup.md', source: 'style-guide/applied/templates/templates-setup.md' }, - { target: 'applied/templates/templates-create.md', source: 'style-guide/applied/templates/templates-create.md' }, - { target: 'applied/templates/templates-usage.md', source: 'style-guide/applied/templates/templates-usage.md' }, - { target: 'applied/biome.md', source: 'style-guide/applied/biome.md' }, - { target: 'applied/postcss.md', source: 'style-guide/applied/postcss.md' }, - { target: 'applied/vscode.md', source: 'style-guide/applied/vscode.md' }, - { target: 'applied/localization.md', source: 'style-guide/applied/localization.md' }, - { target: 'applied/stores.md', source: 'style-guide/applied/stores.md' }, + { target: 'applied/creating-project/from-template.md', source: 'canons/applied/creating-project/from-template.md' }, + { target: 'applied/creating-project/manual.md', source: 'canons/applied/creating-project/manual.md' }, + { target: 'applied/creating-project/nextjs.md', source: 'canons/applied/creating-project/nextjs.md' }, + { target: 'applied/project-structure.md', source: 'canons/applied/project-structure.md' }, + { target: 'applied/page-level.md', source: 'canons/applied/page-level.md' }, + { target: 'applied/component.md', source: 'canons/applied/component.md' }, + { target: 'applied/module.md', source: 'canons/applied/module.md' }, + { target: 'applied/rest-client/index.md', source: 'canons/applied/rest-client/index.md' }, + { target: 'applied/rest-client/setup/index.md', source: 'canons/applied/rest-client/setup/index.md' }, + { target: 'applied/rest-client/setup/auto.md', source: 'canons/applied/rest-client/setup/auto.md' }, + { target: 'applied/rest-client/setup/manual.md', source: 'canons/applied/rest-client/setup/manual.md' }, + { target: 'applied/rest-client/setup/hooks.md', source: 'canons/applied/rest-client/setup/hooks.md' }, + { target: 'applied/rest-client/usage.md', source: 'canons/applied/rest-client/usage.md' }, + { target: 'applied/data-fetch/index.md', source: 'canons/applied/data-fetch/index.md' }, + { target: 'applied/data-fetch/server-await.md', source: 'canons/applied/data-fetch/server-await.md' }, + { target: 'applied/data-fetch/parallel-server-requests.md', source: 'canons/applied/data-fetch/parallel-server-requests.md' }, + { target: 'applied/data-fetch/pass-promise-down.md', source: 'canons/applied/data-fetch/pass-promise-down.md' }, + { target: 'applied/data-fetch/client-hooks-initial-data.md', source: 'canons/applied/data-fetch/client-hooks-initial-data.md' }, + { target: 'applied/data-fetch/client-get-hook.md', source: 'canons/applied/data-fetch/client-get-hook.md' }, + { target: 'applied/data-fetch/business-composition.md', source: 'canons/applied/data-fetch/business-composition.md' }, + { target: 'applied/styles/styles-setup.md', source: 'canons/applied/styles/styles-setup.md' }, + { target: 'applied/styles/styles-usage.md', source: 'canons/applied/styles/styles-usage.md' }, + { target: 'applied/svg-sprites/svg-sprites-intro.md', source: 'canons/applied/svg-sprites/svg-sprites-intro.md' }, + { target: 'applied/svg-sprites/svg-sprites-setup.md', source: 'canons/applied/svg-sprites/svg-sprites-setup.md' }, + { target: 'applied/svg-sprites/svg-sprites-usage.md', source: 'canons/applied/svg-sprites/svg-sprites-usage.md' }, + { target: 'applied/images.md', source: 'canons/applied/images.md' }, + { target: 'applied/fonts.md', source: 'canons/applied/fonts.md' }, + { target: 'applied/aliases.md', source: 'canons/applied/aliases.md' }, + { target: 'applied/templates/templates-intro.md', source: 'canons/applied/templates/templates-intro.md' }, + { target: 'applied/templates/templates-setup.md', source: 'canons/applied/templates/templates-setup.md' }, + { target: 'applied/templates/templates-create.md', source: 'canons/applied/templates/templates-create.md' }, + { target: 'applied/templates/templates-usage.md', source: 'canons/applied/templates/templates-usage.md' }, + { target: 'applied/biome.md', source: 'canons/applied/biome.md' }, + { target: 'applied/postcss.md', source: 'canons/applied/postcss.md' }, + { target: 'applied/vscode.md', source: 'canons/applied/vscode.md' }, + { target: 'applied/localization.md', source: 'canons/applied/localization.md' }, + { target: 'applied/stores.md', source: 'canons/applied/stores.md' }, ]; export const routeRewrites = [ diff --git a/projects/nextjs-style-guide/project.config.ts b/projects/nextjs-style-guide/project.config.ts new file mode 100644 index 0000000..c922a0b --- /dev/null +++ b/projects/nextjs-style-guide/project.config.ts @@ -0,0 +1,5 @@ +export default { + slug: 'nextjs-style-guide', + docsDir: 'docs', + archive: true, +} as const; diff --git a/projects/nextjs-style-guide/scripts/.gitkeep b/projects/nextjs-style-guide/scripts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/projects/slm-design/build.ts b/projects/slm-design/build.ts new file mode 100644 index 0000000..145ac87 --- /dev/null +++ b/projects/slm-design/build.ts @@ -0,0 +1,20 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { prepareDocs } from '../_shared/lib/prepare-docs'; +import { run } from '../_shared/lib/run'; +import { writeZipFromDirectory } from '../_shared/lib/zip'; +import config from './project.config'; + +const projectDir = path.dirname(fileURLToPath(import.meta.url)); +const rootDir = path.resolve(projectDir, '../..'); +const docsDir = path.join(projectDir, config.docsDir); + +await prepareDocs(projectDir, config); +run('npx', ['vitepress', 'build', docsDir], rootDir); + +if (config.archive) { + const zipPath = path.join(rootDir, 'public', config.slug, `${config.slug}.zip`); + writeZipFromDirectory(path.join(docsDir, 'content'), zipPath, config.slug); + console.log(`Собран ${path.relative(rootDir, zipPath)}`); +} diff --git a/canons/slm-design/architecture/index.md b/projects/slm-design/canons/architecture/index.md similarity index 100% rename from canons/slm-design/architecture/index.md rename to projects/slm-design/canons/architecture/index.md diff --git a/canons/slm-design/architecture/layers.md b/projects/slm-design/canons/architecture/layers.md similarity index 100% rename from canons/slm-design/architecture/layers.md rename to projects/slm-design/canons/architecture/layers.md diff --git a/canons/slm-design/architecture/modules.md b/projects/slm-design/canons/architecture/modules.md similarity index 100% rename from canons/slm-design/architecture/modules.md rename to projects/slm-design/canons/architecture/modules.md diff --git a/canons/slm-design/architecture/monorepo.md b/projects/slm-design/canons/architecture/monorepo.md similarity index 100% rename from canons/slm-design/architecture/monorepo.md rename to projects/slm-design/canons/architecture/monorepo.md diff --git a/canons/slm-design/architecture/segments.md b/projects/slm-design/canons/architecture/segments.md similarity index 100% rename from canons/slm-design/architecture/segments.md rename to projects/slm-design/canons/architecture/segments.md diff --git a/canons/slm-design/examples/react/composition-provider.md b/projects/slm-design/canons/examples/react/composition-provider.md similarity index 100% rename from canons/slm-design/examples/react/composition-provider.md rename to projects/slm-design/canons/examples/react/composition-provider.md diff --git a/canons/slm-design/examples/react/factory-composition.md b/projects/slm-design/canons/examples/react/factory-composition.md similarity index 100% rename from canons/slm-design/examples/react/factory-composition.md rename to projects/slm-design/canons/examples/react/factory-composition.md diff --git a/canons/slm-design/examples/react/factory.md b/projects/slm-design/canons/examples/react/factory.md similarity index 100% rename from canons/slm-design/examples/react/factory.md rename to projects/slm-design/canons/examples/react/factory.md diff --git a/docs/nextjs-style-guide/.vitepress/config.ts b/projects/slm-design/docs/.vitepress/config.ts similarity index 87% rename from docs/nextjs-style-guide/.vitepress/config.ts rename to projects/slm-design/docs/.vitepress/config.ts index 1075be6..fd1ce4c 100644 --- a/docs/nextjs-style-guide/.vitepress/config.ts +++ b/projects/slm-design/docs/.vitepress/config.ts @@ -1,7 +1,7 @@ import { defineConfig } from 'vitepress'; import taskLists from 'markdown-it-task-lists'; import llmstxt from 'vitepress-plugin-llms'; -import { themeSyncHead } from '../../shared/vitepress/themeHead'; +import { themeSyncHead } from '../../../_shared/docs/vitepress/themeHead'; import { sidebar, site } from '../docs.config'; export default defineConfig({ diff --git a/projects/slm-design/docs/.vitepress/theme/index.ts b/projects/slm-design/docs/.vitepress/theme/index.ts new file mode 100644 index 0000000..94e709e --- /dev/null +++ b/projects/slm-design/docs/.vitepress/theme/index.ts @@ -0,0 +1 @@ +export { default } from '../../../../_shared/docs/vitepress/theme'; diff --git a/docs/slm-design/docs.config.ts b/projects/slm-design/docs/docs.config.ts similarity index 58% rename from docs/slm-design/docs.config.ts rename to projects/slm-design/docs/docs.config.ts index 90ae267..19ead4d 100644 --- a/docs/slm-design/docs.config.ts +++ b/projects/slm-design/docs/docs.config.ts @@ -2,26 +2,26 @@ export const site = { title: 'SLM Design', description: 'Каноны архитектуры SLM Design', base: '/slm-design/', - outDir: '../../public/slm-design', + outDir: '../../../public/slm-design', }; /** * Карта монтирования исходных канонов в VitePress-документацию. * * `source` указывает на markdown-файл внутри `canons/`. - * `target` задаёт путь, по которому этот файл попадёт в `docs/slm-design/content/` + * `target` задаёт путь, по которому этот файл попадёт в `docs/content/` * и станет страницей итоговой документации. */ export const mounts = [ - { target: 'index.md', source: 'slm-design/architecture/index.md' }, - { target: 'architecture/index.md', source: 'slm-design/architecture/index.md' }, - { target: 'architecture/layers.md', source: 'slm-design/architecture/layers.md' }, - { target: 'architecture/modules.md', source: 'slm-design/architecture/modules.md' }, - { target: 'architecture/segments.md', source: 'slm-design/architecture/segments.md' }, - { target: 'architecture/monorepo.md', source: 'slm-design/architecture/monorepo.md' }, - { target: 'examples/react/factory.md', source: 'slm-design/examples/react/factory.md' }, - { target: 'examples/react/factory-composition.md', source: 'slm-design/examples/react/factory-composition.md' }, - { target: 'examples/react/composition-provider.md', source: 'slm-design/examples/react/composition-provider.md' }, + { target: 'index.md', source: 'canons/architecture/index.md' }, + { target: 'architecture/index.md', source: 'canons/architecture/index.md' }, + { target: 'architecture/layers.md', source: 'canons/architecture/layers.md' }, + { target: 'architecture/modules.md', source: 'canons/architecture/modules.md' }, + { target: 'architecture/segments.md', source: 'canons/architecture/segments.md' }, + { target: 'architecture/monorepo.md', source: 'canons/architecture/monorepo.md' }, + { target: 'examples/react/factory.md', source: 'canons/examples/react/factory.md' }, + { target: 'examples/react/factory-composition.md', source: 'canons/examples/react/factory-composition.md' }, + { target: 'examples/react/composition-provider.md', source: 'canons/examples/react/composition-provider.md' }, ]; export const sidebar = [ diff --git a/projects/slm-design/project.config.ts b/projects/slm-design/project.config.ts new file mode 100644 index 0000000..120cfd4 --- /dev/null +++ b/projects/slm-design/project.config.ts @@ -0,0 +1,5 @@ +export default { + slug: 'slm-design', + docsDir: 'docs', + archive: true, +} as const; diff --git a/projects/slm-design/scripts/.gitkeep b/projects/slm-design/scripts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/projects/template-sync-strategy/build.ts b/projects/template-sync-strategy/build.ts new file mode 100644 index 0000000..145ac87 --- /dev/null +++ b/projects/template-sync-strategy/build.ts @@ -0,0 +1,20 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { prepareDocs } from '../_shared/lib/prepare-docs'; +import { run } from '../_shared/lib/run'; +import { writeZipFromDirectory } from '../_shared/lib/zip'; +import config from './project.config'; + +const projectDir = path.dirname(fileURLToPath(import.meta.url)); +const rootDir = path.resolve(projectDir, '../..'); +const docsDir = path.join(projectDir, config.docsDir); + +await prepareDocs(projectDir, config); +run('npx', ['vitepress', 'build', docsDir], rootDir); + +if (config.archive) { + const zipPath = path.join(rootDir, 'public', config.slug, `${config.slug}.zip`); + writeZipFromDirectory(path.join(docsDir, 'content'), zipPath, config.slug); + console.log(`Собран ${path.relative(rootDir, zipPath)}`); +} diff --git a/canons/template-sync-strategy/concepts/model.md b/projects/template-sync-strategy/canons/concepts/model.md similarity index 100% rename from canons/template-sync-strategy/concepts/model.md rename to projects/template-sync-strategy/canons/concepts/model.md diff --git a/canons/template-sync-strategy/concepts/rules.md b/projects/template-sync-strategy/canons/concepts/rules.md similarity index 100% rename from canons/template-sync-strategy/concepts/rules.md rename to projects/template-sync-strategy/canons/concepts/rules.md diff --git a/canons/template-sync-strategy/concepts/why.md b/projects/template-sync-strategy/canons/concepts/why.md similarity index 100% rename from canons/template-sync-strategy/concepts/why.md rename to projects/template-sync-strategy/canons/concepts/why.md diff --git a/canons/template-sync-strategy/index.md b/projects/template-sync-strategy/canons/index.md similarity index 100% rename from canons/template-sync-strategy/index.md rename to projects/template-sync-strategy/canons/index.md diff --git a/canons/template-sync-strategy/reference/cheatsheet.md b/projects/template-sync-strategy/canons/reference/cheatsheet.md similarity index 100% rename from canons/template-sync-strategy/reference/cheatsheet.md rename to projects/template-sync-strategy/canons/reference/cheatsheet.md diff --git a/canons/template-sync-strategy/reference/glossary.md b/projects/template-sync-strategy/canons/reference/glossary.md similarity index 100% rename from canons/template-sync-strategy/reference/glossary.md rename to projects/template-sync-strategy/canons/reference/glossary.md diff --git a/canons/template-sync-strategy/reference/troubleshooting.md b/projects/template-sync-strategy/canons/reference/troubleshooting.md similarity index 100% rename from canons/template-sync-strategy/reference/troubleshooting.md rename to projects/template-sync-strategy/canons/reference/troubleshooting.md diff --git a/canons/template-sync-strategy/setup/clean-repository.md b/projects/template-sync-strategy/canons/setup/clean-repository.md similarity index 100% rename from canons/template-sync-strategy/setup/clean-repository.md rename to projects/template-sync-strategy/canons/setup/clean-repository.md diff --git a/canons/template-sync-strategy/setup/existing-master-migration.md b/projects/template-sync-strategy/canons/setup/existing-master-migration.md similarity index 100% rename from canons/template-sync-strategy/setup/existing-master-migration.md rename to projects/template-sync-strategy/canons/setup/existing-master-migration.md diff --git a/canons/template-sync-strategy/workflows/resolve-conflicts.md b/projects/template-sync-strategy/canons/workflows/resolve-conflicts.md similarity index 100% rename from canons/template-sync-strategy/workflows/resolve-conflicts.md rename to projects/template-sync-strategy/canons/workflows/resolve-conflicts.md diff --git a/canons/template-sync-strategy/workflows/review-and-merge.md b/projects/template-sync-strategy/canons/workflows/review-and-merge.md similarity index 100% rename from canons/template-sync-strategy/workflows/review-and-merge.md rename to projects/template-sync-strategy/canons/workflows/review-and-merge.md diff --git a/canons/template-sync-strategy/workflows/update-template.md b/projects/template-sync-strategy/canons/workflows/update-template.md similarity index 100% rename from canons/template-sync-strategy/workflows/update-template.md rename to projects/template-sync-strategy/canons/workflows/update-template.md diff --git a/docs/slm-design/.vitepress/config.ts b/projects/template-sync-strategy/docs/.vitepress/config.ts similarity index 87% rename from docs/slm-design/.vitepress/config.ts rename to projects/template-sync-strategy/docs/.vitepress/config.ts index 1075be6..fd1ce4c 100644 --- a/docs/slm-design/.vitepress/config.ts +++ b/projects/template-sync-strategy/docs/.vitepress/config.ts @@ -1,7 +1,7 @@ import { defineConfig } from 'vitepress'; import taskLists from 'markdown-it-task-lists'; import llmstxt from 'vitepress-plugin-llms'; -import { themeSyncHead } from '../../shared/vitepress/themeHead'; +import { themeSyncHead } from '../../../_shared/docs/vitepress/themeHead'; import { sidebar, site } from '../docs.config'; export default defineConfig({ diff --git a/projects/template-sync-strategy/docs/.vitepress/theme/index.ts b/projects/template-sync-strategy/docs/.vitepress/theme/index.ts new file mode 100644 index 0000000..94e709e --- /dev/null +++ b/projects/template-sync-strategy/docs/.vitepress/theme/index.ts @@ -0,0 +1 @@ +export { default } from '../../../../_shared/docs/vitepress/theme'; diff --git a/docs/template-sync-strategy/docs.config.ts b/projects/template-sync-strategy/docs/docs.config.ts similarity index 56% rename from docs/template-sync-strategy/docs.config.ts rename to projects/template-sync-strategy/docs/docs.config.ts index f59b43c..80c3627 100644 --- a/docs/template-sync-strategy/docs.config.ts +++ b/projects/template-sync-strategy/docs/docs.config.ts @@ -2,30 +2,30 @@ export const site = { title: 'Template Sync Strategy', description: 'Управляемое обновление проектов от шаблона', base: '/template-sync-strategy/', - outDir: '../../public/template-sync-strategy', + outDir: '../../../public/template-sync-strategy', }; /** * Карта монтирования исходных канонов в VitePress-документацию. * * `source` указывает на markdown-файл внутри `canons/`. - * `target` задаёт путь, по которому этот файл попадёт в `docs/template-sync-strategy/content/` + * `target` задаёт путь, по которому этот файл попадёт в `docs/content/` * и станет страницей итоговой документации. */ export const mounts = [ - { target: 'index.md', source: 'template-sync-strategy/index.md' }, - { target: 'overview.md', source: 'template-sync-strategy/index.md' }, - { target: 'concepts/why.md', source: 'template-sync-strategy/concepts/why.md' }, - { target: 'concepts/model.md', source: 'template-sync-strategy/concepts/model.md' }, - { target: 'concepts/rules.md', source: 'template-sync-strategy/concepts/rules.md' }, - { target: 'setup/clean-repository.md', source: 'template-sync-strategy/setup/clean-repository.md' }, - { target: 'setup/existing-master-migration.md', source: 'template-sync-strategy/setup/existing-master-migration.md' }, - { target: 'workflows/update-template.md', source: 'template-sync-strategy/workflows/update-template.md' }, - { target: 'workflows/resolve-conflicts.md', source: 'template-sync-strategy/workflows/resolve-conflicts.md' }, - { target: 'workflows/review-and-merge.md', source: 'template-sync-strategy/workflows/review-and-merge.md' }, - { target: 'reference/cheatsheet.md', source: 'template-sync-strategy/reference/cheatsheet.md' }, - { target: 'reference/troubleshooting.md', source: 'template-sync-strategy/reference/troubleshooting.md' }, - { target: 'reference/glossary.md', source: 'template-sync-strategy/reference/glossary.md' }, + { target: 'index.md', source: 'canons/index.md' }, + { target: 'overview.md', source: 'canons/index.md' }, + { target: 'concepts/why.md', source: 'canons/concepts/why.md' }, + { target: 'concepts/model.md', source: 'canons/concepts/model.md' }, + { target: 'concepts/rules.md', source: 'canons/concepts/rules.md' }, + { target: 'setup/clean-repository.md', source: 'canons/setup/clean-repository.md' }, + { target: 'setup/existing-master-migration.md', source: 'canons/setup/existing-master-migration.md' }, + { target: 'workflows/update-template.md', source: 'canons/workflows/update-template.md' }, + { target: 'workflows/resolve-conflicts.md', source: 'canons/workflows/resolve-conflicts.md' }, + { target: 'workflows/review-and-merge.md', source: 'canons/workflows/review-and-merge.md' }, + { target: 'reference/cheatsheet.md', source: 'canons/reference/cheatsheet.md' }, + { target: 'reference/troubleshooting.md', source: 'canons/reference/troubleshooting.md' }, + { target: 'reference/glossary.md', source: 'canons/reference/glossary.md' }, ]; export const sidebar = [ diff --git a/projects/template-sync-strategy/project.config.ts b/projects/template-sync-strategy/project.config.ts new file mode 100644 index 0000000..5f12228 --- /dev/null +++ b/projects/template-sync-strategy/project.config.ts @@ -0,0 +1,5 @@ +export default { + slug: 'template-sync-strategy', + docsDir: 'docs', + archive: true, +} as const; diff --git a/projects/template-sync-strategy/scripts/.gitkeep b/projects/template-sync-strategy/scripts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/scripts/docs/prepare.ts b/scripts/docs/prepare.ts deleted file mode 100644 index 703adf9..0000000 --- a/scripts/docs/prepare.ts +++ /dev/null @@ -1,146 +0,0 @@ -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[]; -}; - -const MD_LINK_RE = /\]\((?!#|[a-z][a-z0-9+.-]*:|\/\/)([^)\s]+)(#[^)]*)?\)/gi; - -const siteName = process.argv[2]; - -if (!siteName) { - throw new Error('Укажите имя сайта: tsx scripts/docs/prepare.ts slm-design'); -} - -const rootDir = process.cwd(); -const canonsDir = path.join(rootDir, 'canons'); -const siteDir = path.join(rootDir, 'docs', siteName); -const contentDir = path.join(siteDir, 'content'); -const configPath = path.join(siteDir, 'docs.config.ts'); - -if (!fs.existsSync(configPath)) { - throw new Error(`Не найден конфиг сайта: ${configPath}`); -} - -const config = (await import(pathToFileURL(configPath).href)) as DocsConfig; -const targetBySource = new Map( - config.mounts.map((page) => [normalizePath(page.source), normalizePath(page.target)]), -); -const routeRewrites = [...(config.routeRewrites ?? [])].sort((a, b) => b.from.length - a.from.length); - -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}`; -} - -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.posix.normalize(path.posix.join(sourceDir, hrefPath))); - - if (sourcePath.startsWith('style-guide/')) { - const route = `/docs/${sourcePath.slice('style-guide/'.length)}`; - - return applyRouteRewrites(route); - } - - return undefined; -} - -function transformMarkdownLinks(content: string, page: Page) { - const sourceDir = path.posix.dirname(normalizePath(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); - - if (route) return `](${route}${queryPart}${hash})`; - - const rewritten = applyRouteRewrites(hrefPath); - - if (rewritten) return `](${rewritten}${queryPart}${hash})`; - - return match; - } - - if (!hrefPath.endsWith('.md')) { - const route = formatRelativeRoute(hrefPath, sourceDir); - - if (route) return `](${route}${queryPart}${hash})`; - - return match; - } - - const sourcePath = normalizePath(path.posix.normalize(path.posix.join(sourceDir, hrefPath))); - const target = targetBySource.get(sourcePath); - - if (!target) return match; - - const nextHref = formatRelativeMarkdownPath(page.target, `${target}${queryPart}`); - - return `](${nextHref}${hash})`; - }); -} - -fs.rmSync(contentDir, { recursive: true, force: true }); -fs.mkdirSync(contentDir, { recursive: true }); - -for (const page of config.mounts) { - const sourcePath = path.join(canonsDir, page.source); - const targetPath = path.join(contentDir, page.target); - - if (!fs.existsSync(sourcePath)) { - throw new Error(`Не найден канон: ${sourcePath}`); - } - - fs.mkdirSync(path.dirname(targetPath), { recursive: true }); - - const content = transformMarkdownLinks(fs.readFileSync(sourcePath, 'utf8'), page); - fs.writeFileSync(targetPath, content, 'utf8'); - - console.log(`${page.target} -> canons/${page.source}`); -} - -console.log(`Подготовлен VitePress content для ${siteName}: ${config.mounts.length} страниц`); diff --git a/scripts/site/generate-artifacts.ts b/scripts/site/generate-artifacts.ts deleted file mode 100644 index 1fefdee..0000000 --- a/scripts/site/generate-artifacts.ts +++ /dev/null @@ -1,65 +0,0 @@ -import fs from 'node:fs'; -import path from 'node:path'; - -import { docs } from '../../src/config/docs.config'; - -const siteTitle = 'Документация'; -const siteDescription = 'Единое пространство для идей, черновиков и первых версий документаций, которые ещё формируются и постепенно становятся самостоятельными материалами.'; - -const rootDir = process.cwd(); -const publicDir = path.join(rootDir, 'public'); -const llmsPath = path.join(publicDir, 'llms.txt'); - -function formatMarkdownLink(label: string, href: string, description: string) { - return `- [${label}](${href}): ${description}`; -} - -function findDocLink(doc: (typeof docs)[number], label: string) { - return doc.links.find((link) => link.label === label); -} - -function formatLlmsLinks() { - return docs - .map((doc) => { - const link = findDocLink(doc, 'llms.txt'); - - if (!link) return undefined; - - return formatMarkdownLink(doc.title, link.href, doc.description); - }) - .filter(Boolean); -} - -function formatFullLinks() { - return docs - .map((doc) => { - const link = findDocLink(doc, 'llms-full.txt'); - - if (!link) return undefined; - - return formatMarkdownLink(`${doc.title} full`, link.href, `Полный bundle документации: ${doc.label.toLowerCase()}.`); - }) - .filter(Boolean); -} - -const content = [ - `# ${siteTitle}`, - '', - `> ${siteDescription}`, - '', - 'Этот файл является корневой картой документаций. Для работы с конкретным направлением используйте его собственный `llms.txt`.', - '', - '## Documentation', - '', - ...formatLlmsLinks(), - '', - '## Optional', - '', - ...formatFullLinks(), - '', -].join('\n'); - -fs.mkdirSync(publicDir, { recursive: true }); -fs.writeFileSync(llmsPath, content, 'utf8'); - -console.log(`Сгенерирован ${path.relative(rootDir, llmsPath)}`);