Skip to content

alt-docs-registry

Единый источник правды для реестра продуктов, разделов и версий документации ALT. Одна YAML-схема products.yaml, Vite-плагин с виртуальным модулем virtual:alt-docs-registry, рантайм-composable useRegistry() и CLI alt-docs.

Пакет заменяет прежние хардкоды PRODUCT_NAMES, ALIASES, ALL_DISTROS, разбросанные по теме и 22 веткам конфига дистрибутивов. Один и тот же реестр читают билд-тайм тема, конвертер publican-docbook-to-vitepress-markdown и рантайм-компоненты навигации.

Установка

bash
pnpm add @ampernic/alt-docs-registry

Для скоупа @ampernic из Forgejo прописывается .npmrc в корне проекта:

@ampernic:registry=https://altlinux.space/api/packages/ampernic/npm/

CLI alt-docs устанавливается через bin пакета -- запускать pnpm dlx alt-docs ... или локально pnpm exec alt-docs ....

Источник -- products.yaml

Формат описан в schema.ts. Минимальный пример:

yaml
schema: 1
locales: [ru, en]
site:
  hostname: https://docs.altlinux.space
  organization:
    name: Базальт СПО
    url: https://www.basealt.ru
sections:
  - id: server
    name: { ru: "Серверные", en: "Server" }
    products: [alt-server, alt-domain]
  - id: workstation
    name: { ru: "Рабочие станции", en: "Workstation" }
    products: [alt-workstation, alt-kworkstation]
products:
  alt-workstation:
    name: { ru: "Альт Рабочая станция" }
    tagline: { ru: "Универсальная система для офиса" }
    product_link: https://www.basealt.ru/alt-workstation
    versions: ["11.2", "11.1", "11.0", "10.4"]
    branding:
      logo:
        col: branding/alt-workstation/logo-col.svg
        dark: branding/alt-workstation/logo-dark.svg
      accent: "#fa814c"
    meta:
      isPublic: true

Голова versions считается актуальной. Поле family объединяет legacy-строку (alt-domain-p10) с основной под одной карточкой. site.hostname пробрасывается в ResolvedRegistry.hostname и далее в vitepress-plugin-meta для канонических URL, а site.organization -- в узел schema.org Organization на лендинге.

Использование в конфиге VitePress

ts
// .vitepress/config.mts
import { defineConfig } from 'vitepress'
import { AltDocsRegistryPlugin, createRegistry } from '@ampernic/alt-docs-registry'
import { createSharedConfig } from '@ampernic/vitepress-theme-alt-docs/config'

const { plugin: registryPlugin, resolved } = await createRegistry({
  source: 'products.yaml',
  fallback: 'https://raw.altlinux.space/alt-docs/docs-vitepress/index/products.yaml',
  distro: 'alt-workstation',
  locale: 'ru',
  emitProductsJson: true,
  emitSprite: true,
})

const shared = createSharedConfig({
  distroName: 'alt-workstation',
  allDistros: resolved.allDistros,
  sections: resolved.sections,
  productNames: resolved.productNames,
  productLinks: resolved.productLinks,
})

export default defineConfig({
  ...shared,
  vite: {
    plugins: [registryPlugin, ...(shared.vite?.plugins ?? [])],
  },
})

createRegistry прогревает snapshot один раз и возвращает и плагин (для vite.plugins), и уже резолвнутый объект ResolvedRegistry. AltDocsRegistryPlugin можно использовать самостоятельно, если snapshot нужен только рантайму.

Использование в компонентах

ts
import { useRegistry } from '@ampernic/alt-docs-registry/composables'

const { registry, merged, refresh } = useRegistry()

// registry.value: билд-тайм snapshot из virtual:alt-docs-registry
// merged.value:   runtime cache | build; runtime побеждает
// refresh():      подтягивает свежий /products.json из корня сайта

Composable возвращает shallow-refs, чтобы обновление реестра не рендерило пол-темы. Один модульный кэш на страницу: разные компоненты, зовущие useRegistry(), видят один и тот же fetched snapshot.

CLI alt-docs

Файловые операции, без auto-commit -- git обёртка остаётся за gear-* или CI:

bash
alt-docs product add alt-orchestra \
  --section orchestra \
  --logoCol ./logo.svg \
  --logoDark ./logo-mono.svg

alt-docs version add alt-workstation 11.3 --from 11.2
alt-docs product publish --repo alt-docs/docs-vitepress --token "$ALT_DOCS_TOKEN"
alt-docs check --strict
  • product add -- добавляет запись в products.yaml, копирует логотипы в docs/public/branding/<slug>/, привязывает к секции.
  • product remove -- убирает из реестра (ветку не трогает).
  • product publish -- дёргает workflow full-rebuild.yml через Forgejo API. Требует --token или ALT_DOCS_TOKEN.
  • version add -- прописывает новую версию в products.yaml (первой в списке = актуальной) и разворачивает docs/ru/<X.Y>/ из шаблона или предыдущей версии.
  • check -- валидирует schema + факт существования файлов брендинга на диске. --strict = warnings уходят в exit-code 1.

Опции плагина

ОпцияТипПо умолчаниюОписание
sourcestring--Обязательный. Путь к products.yaml или URL https://...
fallbackstring--Резервный источник -- пробуется, если source не читается
distrostring | nullnullСлаг текущего дистрибутива. null = index-сборка, показывающая все
localeLocale'ru'Локаль, в которую резолвятся LocalizedString-поля
emitProductsJsonbooleantrueПисать <outDir>/products.json -- ест useRegistry().refresh() в рантайме
productsJsonNamestring'products.json'Имя выходного JSON
brandingRootsstring[]['docs/public', 'public']Корни, где искать branding.logo.col/dark. Порядок = приоритет
emitSpritebooleanfalseСобирать SVG-спрайт всех логотипов как <outDir>/products-sprite.svg
spriteFileNamestring'products-sprite.svg'Имя выходного спрайта

Что кладётся в ResolvedRegistry

Виртуальный модуль virtual:alt-docs-registry и products.json содержат locale-резолвнутый снимок:

ПолеОписание
hostnameКопия site.hostname из yaml
organizationКопия site.organization: издатель, которого vitepress-plugin-meta печатает как узел schema.org Organization на лендинге
allDistrosОтсортированный список слагов всех продуктов
sections{ id, name, products } -- имена уже резолвнуты в текущую локаль
productNamesslug -> localized name
productBrandingKeysslug -> ключ спрайта (учтён branding.sharedWith)
productTaglinesslug -> localized tagline
productLinksslug -> product_link (внешняя страница продукта)
productFamilyPrimaryslug -> primary slug семьи (self, если не в семье)
productFamilyMembersprimary slug -> [primary, ...secondaries]
productVersionsslug -> versions[] (позволяет primary landing показать все ветки без cross-site fetch)
currentDistroКопия опции distro
localeКопия опции locale

Нюансы

  • Парсер требует наличия schema: 1 в yaml. Дополнительные поля не ломают -- ломает только несовпадение мажорной версии.
  • parseRegistry может вернуть issues[] с severity: 'error' -- плагин в этом случае падает при configResolved, а не молча собирает битый snapshot.
  • Дистрибутив, у которого пусто versions[], не считается ошибкой -- в переключателе отображается заглушкой без версий (нужно для распорок под будущие продукты).
  • Флаг emitSprite включайте только когда тема реально пользуется путём products-sprite.svg -- иначе платите килобайтами в бандле впустую.
  • parseRegistry умеет обрабатывать неизвестные поля мягко: пишет warning, но валидирует остальное.
  • field: site при merge из YAML восстанавливается вручную -- в старых версиях парсера теряется. Сейчас чинится наверху; смотрите test/site-field.test.ts перед патчами loader'а.