@tenphi/docs 0.16.0 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/config/index.d.ts +3 -3
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -1
- package/dist/config/schema.json +261 -10
- package/dist/{config-CmoSqvii.js → config-CW0iIYp8.js} +178 -10
- package/dist/config-CW0iIYp8.js.map +1 -0
- package/dist/content/index.d.ts +1 -1
- package/dist/content/index.js +1 -1
- package/dist/{content-Btz1o52C.js → content-CrWnRfN7.js} +221 -7
- package/dist/content-CrWnRfN7.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/markdown/index.d.ts +1 -1
- package/dist/{types-CH6E2v-J.d.ts → types-CY8WfBmM.d.ts} +66 -19
- package/dist/{types-CH6E2v-J.d.ts.map → types-CY8WfBmM.d.ts.map} +1 -1
- package/package.json +2 -2
- package/dist/config-CmoSqvii.js.map +0 -1
- package/dist/content-Btz1o52C.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-CW0iIYp8.js","names":[],"sources":["../src/types.ts","../src/config/index.ts"],"sourcesContent":["import type { Styles, StylesWithoutSelectors } from \"@tenphi/tasty/core\";\nimport type {\n GlazeColorInput,\n GlazeColorValue,\n RegularColorDef,\n} from \"@tenphi/glaze\";\nimport type { Root } from \"mdast\";\n\nexport type DiagnosticSeverity = \"warning\" | \"error\";\n\nexport interface DocsDiagnostic {\n code: string;\n severity: DiagnosticSeverity;\n message: string;\n file?: string;\n line?: number;\n column?: number;\n hint?: string;\n related?: Array<{ file: string; line?: number; message: string }>;\n}\n\nexport interface SiteConfig {\n title?: string;\n /** Version of the documented package, rendered beside the site title. */\n version?: string;\n /** Selectable documentation versions and their route roots. */\n versions?: SiteVersion[];\n description?: string;\n url?: string;\n repository?: string;\n /** Header buttons, collapsed into a More menu on mobile. */\n headerLinks?: HeaderLink[];\n /** Source artwork used to generate browser, touch, and installable-app icons. */\n favicon?: string | SiteIconConfig;\n}\n\nexport interface SiteVersion {\n label: string;\n routeBase: string;\n}\n\nexport interface HeaderLink {\n label: string;\n /** HTTP(S) URL, root-relative route (prefixed with the site base), or fragment. */\n link: string;\n /** Desktop button variant; mobile More menus use uniform navigation links. */\n variant?: \"default\" | \"primary\";\n newTab?: boolean;\n}\n\nexport interface SiteIconConfig {\n /** Local SVG, PNG, JPEG, WebP, AVIF, or GIF path, relative to the project root. */\n source: string;\n /** Opaque background for touch and maskable icons. */\n background?: string;\n}\n\n/** A language exposed by Starlight's locale picker and routing. */\nexport interface LocaleConfig {\n label: string;\n /** BCP-47 language tag. Defaults to the locale key. */\n lang?: string;\n dir?: \"ltr\" | \"rtl\";\n}\n\nexport interface EditLinkConfig {\n /** Base URL joined with each page's repository-relative source path. */\n baseUrl: string;\n}\n\n/** A custom HTML element rendered in the document head. */\nexport interface HeadConfig {\n tag: string;\n attrs?: Record<string, string | boolean | undefined>;\n content?: string;\n}\n\nexport interface NavigationPlacement {\n label?: string;\n order?: number;\n group?: string;\n}\n\nexport type DocsSource = {\n /** Stable name for cross-source links and repeated mounts. */\n id?: string;\n routeBase?: string;\n} & (\n | {\n file: string;\n root?: string;\n route?: string;\n title?: string;\n description?: string;\n navigation?: false | NavigationPlacement;\n }\n | {\n glob: string | string[];\n root?: string;\n base?: string;\n routeBase?: string;\n exclude?: string[];\n navigation?: \"auto\" | false;\n }\n | {\n package: string;\n registry?: string;\n include?: string[];\n exclude?: string[];\n index?: string;\n routeBase?: string;\n trust?: \"markdown\" | \"mdx\";\n }\n | {\n /** Local OpenAPI 3.x JSON or YAML document. */\n openapi: string;\n root?: string;\n routeBase?: string;\n }\n);\n\nexport interface ContentConfig {\n sources?: DocsSource[];\n allowOutsideRoot?: boolean;\n /** Rewrite absolute links into the current repository to matching Cookbook routes. */\n localizeRepositoryLinks?: boolean;\n /** Keep unrelated metadata without exposing it as renderer frontmatter. */\n frontmatter?: \"preserve\" | \"reject\";\n}\n\nexport type NavigationItem =\n | string\n | { label: string; link?: string; items: NavigationItem[] }\n | { label: string; link?: string; autogenerate: { directory: string } }\n | { label: string; link: string };\n\nexport interface NavigationTab {\n label: string;\n link: string;\n /** Sidebar tree shown while this tab is active. */\n items?: NavigationItem[];\n}\n\nexport interface NavigationConfig {\n items?: NavigationItem[];\n /** Optional primary navigation rendered as a compact row below the header. */\n tabs?: NavigationTab[];\n}\n\nexport type BrandDeclaration = Pick<GlazeColorInput, \"hue\" | \"saturation\"> & {\n /** Single tone for the brand seed; contrast targets adapt it per mode. */\n tone: number;\n contrast?: { apca: number | [number, number] };\n unsafeContrast?: boolean;\n};\n\nexport type BrandConfig =\n | GlazeColorValue\n | {\n from: GlazeColorValue;\n contrast?: { apca: number | [number, number] };\n unsafeContrast?: boolean;\n }\n | BrandDeclaration;\n\nexport type ThemeTokenValue = string | number;\n\n/**\n * Tasty design tokens. `$name` is emitted as `--name`; existing `--name`\n * custom-property keys remain supported for compatibility.\n */\nexport interface ThemeTokens {\n $gap?: ThemeTokenValue;\n $radius?: ThemeTokenValue;\n \"$card-radius\"?: ThemeTokenValue;\n \"$border-width\"?: ThemeTokenValue;\n \"$outline-width\"?: ThemeTokenValue;\n \"$outline-offset\"?: ThemeTokenValue;\n \"$layout-width\"?: ThemeTokenValue;\n \"$content-width\"?: ThemeTokenValue;\n \"$sidebar-width\"?: ThemeTokenValue;\n \"$control-height\"?: ThemeTokenValue;\n [name: `$${string}`]: ThemeTokenValue | undefined;\n [customProperty: `--${string}`]: ThemeTokenValue | undefined;\n}\n\nexport interface TypographyPreset {\n fontFamily?: string;\n fontSize?: ThemeTokenValue;\n lineHeight?: ThemeTokenValue;\n letterSpacing?: ThemeTokenValue;\n fontWeight?: ThemeTokenValue;\n boldFontWeight?: ThemeTokenValue;\n iconSize?: ThemeTokenValue;\n textTransform?: ThemeTokenValue;\n fontStyle?: ThemeTokenValue;\n}\n\n/** Built-in presets can be overridden and additional Tasty presets may be added. */\nexport interface TypographyPresets {\n body?: TypographyPreset;\n heading?: TypographyPreset;\n h1?: TypographyPreset;\n h2?: TypographyPreset;\n h3?: TypographyPreset;\n h4?: TypographyPreset;\n h5?: TypographyPreset;\n h6?: TypographyPreset;\n navigation?: TypographyPreset;\n small?: TypographyPreset;\n code?: TypographyPreset;\n [name: string]: TypographyPreset | undefined;\n}\n\n/** A font file served from the site's `public/` directory. */\nexport interface ThemeFontFile {\n /** Root-relative public URL, for example `/fonts/brand.woff2`. */\n src: string;\n /** A single weight or a variable-font range such as `\"100 900\"`. */\n weight?: number | `${number} ${number}`;\n style?: \"normal\" | \"italic\";\n}\n\n/** A Google Fonts family or a set of files hosted by the site. */\nexport type ThemeFont =\n | string\n | { google: string; weights?: number[] }\n | { family: string; files: ThemeFontFile[] };\n\nexport interface ThemeFonts {\n body?: ThemeFont;\n heading?: ThemeFont;\n code?: ThemeFont;\n}\n\n/** A Glaze declaration, or a literal color retained as a convenient seed shorthand. */\nexport type ThemePaletteColor = GlazeColorValue | RegularColorDef;\n\n/** Semantic palette declarations resolved for every appearance mode. */\nexport interface ThemePaletteConfig {\n info?: ThemePaletteColor;\n success?: ThemePaletteColor;\n warning?: ThemePaletteColor;\n danger?: ThemePaletteColor;\n /** Light-scheme page surface; dark and high-contrast values adapt. */\n surface?: ThemePaletteColor;\n /** Translucent header surface; defaults to the page surface declaration. */\n header?: ThemePaletteColor;\n /** Fixed underlay; defaults to black at 50% opacity in every scheme. */\n overlay?: ThemePaletteColor;\n /** Primary reading text, resolved against `surface`. */\n text?: ThemePaletteColor;\n /** Heading text; follows an explicit `text` declaration unless configured. */\n heading?: ThemePaletteColor;\n /** Secondary reading text, resolved against `surface`. */\n textSoft?: ThemePaletteColor;\n}\n\n/** Cookbook UI surfaces whose default Tasty styles can be customized. */\nexport const COOKBOOK_COMPONENT_NAMES = [\n \"Card\",\n \"Callout\",\n \"CodeGroup\",\n \"Tab\",\n \"Footer\",\n \"Hero\",\n \"PageFrame\",\n \"HeaderFrame\",\n \"HeaderLinks\",\n \"Heading\",\n \"Layout\",\n \"SearchButton\",\n \"TableOfContentsLayout\",\n \"LanguageSelect\",\n \"Logo\",\n \"MarkdownCodeBlock\",\n \"MarkdownHeading\",\n \"MarkdownInlineCode\",\n \"MarkdownTable\",\n \"Mermaid\",\n \"MobileMenuFooter\",\n \"MobileMenuToggle\",\n \"MobileNavigationTabs\",\n \"MobileTableOfContents\",\n \"PackageVersion\",\n \"VersionSwitcher\",\n \"Preview\",\n \"Sidebar\",\n \"SocialIcons\",\n \"Steps\",\n \"Tabs\",\n \"TableOfContents\",\n \"ThemeSelect\",\n \"TopNavigation\",\n \"StarlightHeader\",\n] as const;\n\nexport type CookbookComponentName = (typeof COOKBOOK_COMPONENT_NAMES)[number];\n\n/** Named Tasty sub-elements available on each configurable Cookbook surface. */\nexport const COOKBOOK_COMPONENT_SUB_ELEMENTS = {\n PageFrame: [\"MainFrame\", \"SidebarFrame\", \"Columns\"],\n HeaderFrame: [],\n Heading: [\n \"Level1\",\n \"Level2\",\n \"Level3\",\n \"Level4\",\n \"Level5\",\n \"Level6\",\n \"PageTitle\",\n ],\n HeaderLinks: [\n \"Desktop\",\n \"Link\",\n \"HoverLink\",\n \"PrimaryLink\",\n \"HoverPrimaryLink\",\n \"Trigger\",\n \"HoverTrigger\",\n \"Panel\",\n \"PanelNavigation\",\n \"PanelLink\",\n \"FirstPanelLink\",\n \"Close\",\n \"HoverClose\",\n ],\n Layout: [\"LockedPage\"],\n SearchButton: [\"Label\", \"Shortcut\", \"Hover\", \"Active\", \"NativeIcon\", \"Icon\"],\n TableOfContentsLayout: [\"Content\"],\n Card: [\"Heading2\", \"Heading3\", \"Paragraph\"],\n Callout: [\"Title\", \"Body\", \"Tip\", \"Caution\", \"Danger\"],\n CodeGroup: [\"Caption\", \"Pre\", \"Code\"],\n Tab: [\"Heading\", \"Hidden\", \"HiddenHeading\"],\n Footer: [\n \"Meta\",\n \"LoneMetaItem\",\n \"MetaLink\",\n \"HoverMetaLink\",\n \"Credit\",\n \"CreditLink\",\n \"HoverCreditLink\",\n ],\n Hero: [\n \"Visual\",\n \"Stack\",\n \"Copy\",\n \"Title\",\n \"Tagline\",\n \"Actions\",\n \"Action\",\n \"HoverAction\",\n \"PrimaryAction\",\n \"SecondaryAction\",\n \"MinimalAction\",\n \"ActionIcon\",\n ],\n LanguageSelect: [\n \"Label\",\n \"HoverLabel\",\n \"LabelIcon\",\n \"Select\",\n \"Caret\",\n \"Option\",\n ],\n Logo: [\"Svg\", \"Mark\"],\n MarkdownCodeBlock: [\n \"Pre\",\n \"CopyButton\",\n \"HoverCopyButton\",\n \"CopiedButton\",\n \"CopyIcon\",\n \"CopiedIcon\",\n ],\n MarkdownHeading: [\n \"Heading\",\n \"Heading1\",\n \"Heading2\",\n \"Heading3\",\n \"Heading4\",\n \"Heading5\",\n \"Heading6\",\n \"Link\",\n \"RevealedLink\",\n \"HoverLink\",\n \"LinkIcon\",\n \"CopiedLink\",\n \"CopiedLinkIcon\",\n \"CopiedIcon\",\n ],\n MarkdownTable: [\"Table\", \"Cell\", \"LastBodyRowCell\", \"HeaderCell\"],\n MarkdownInlineCode: [],\n Mermaid: [\"Diagram\", \"Text\", \"MonoText\"],\n MobileMenuFooter: [\"Social\"],\n MobileMenuToggle: [\n \"Control\",\n \"Icon\",\n \"Section\",\n \"Page\",\n \"HoverControl\",\n \"ActiveControl\",\n ],\n MobileNavigationTabs: [\n \"Trigger\",\n \"Marker\",\n \"Caret\",\n \"ExpandedCaret\",\n \"Label\",\n \"List\",\n \"Item\",\n \"Link\",\n \"HoverLink\",\n \"CurrentLink\",\n ],\n MobileTableOfContents: [\n \"Item\",\n \"Link\",\n \"LinkLabel\",\n \"HoverLink\",\n \"CurrentLink\",\n \"CurrentIndicator\",\n ],\n PackageVersion: [],\n VersionSwitcher: [\"Trigger\", \"Panel\", \"OpenPanel\", \"Link\", \"CurrentLink\"],\n Preview: [\"Caption\", \"Stage\", \"Frame\", \"Code\", \"Summary\", \"Pre\"],\n Sidebar: [\n \"Backdrop\",\n \"OpenBackdrop\",\n \"MobileHeading\",\n \"HomeLink\",\n \"HomeLogo\",\n \"HomeLabel\",\n \"Close\",\n \"HoverClose\",\n \"CloseIcon\",\n \"CurrentLink\",\n \"OpenPane\",\n \"Content\",\n \"Tree\",\n \"List\",\n \"Item\",\n \"TopLevelSpacing\",\n \"GroupSpacing\",\n \"NestedItem\",\n \"SectionHeading\",\n \"Control\",\n \"Summary\",\n \"GroupLabel\",\n \"GroupLabelText\",\n \"Link\",\n \"LinkLabel\",\n \"InteractiveControl\",\n \"SummaryMarker\",\n \"Caret\",\n \"ExpandedCaret\",\n \"LinkedSummary\",\n \"GroupLink\",\n \"LinkedSectionHeading\",\n \"SectionLink\",\n \"Badge\",\n \"TopLevelLink\",\n ],\n Steps: [\"Item\", \"Marker\"],\n SocialIcons: [\"Link\", \"HoverLink\", \"Icon\"],\n Tabs: [\"List\", \"Button\", \"SelectedButton\", \"FocusedButton\"],\n TableOfContents: [\n \"Heading\",\n \"List\",\n \"Item\",\n \"Link\",\n \"LinkLabel\",\n \"HoverLink\",\n \"CurrentLink\",\n ],\n ThemeSelect: [\n \"Trigger\",\n \"HoverTrigger\",\n \"ActiveTrigger\",\n \"Icon\",\n \"Panel\",\n \"OpenPanel\",\n \"Section\",\n \"SectionSpacing\",\n \"SectionLabel\",\n \"Option\",\n \"HoverOption\",\n \"CheckedOption\",\n \"FocusedOption\",\n \"Input\",\n \"OptionIcon\",\n \"Checkmark\",\n \"SelectedCheckmark\",\n ],\n TopNavigation: [\n \"Scrollbar\",\n \"Link\",\n \"HoverLink\",\n \"CurrentLink\",\n \"ActiveIndicator\",\n ],\n StarlightHeader: [\n \"Primary\",\n \"TitleAndSearch\",\n \"Title\",\n \"LogoLink\",\n \"Logo\",\n \"SiteTitle\",\n \"Search\",\n \"SearchElement\",\n \"Tools\",\n \"ToolItem\",\n \"Social\",\n \"MobileTheme\",\n ],\n} as const satisfies Record<CookbookComponentName, readonly string[]>;\n\nexport type CookbookComponentSubElementName<\n Name extends CookbookComponentName,\n> = (typeof COOKBOOK_COMPONENT_SUB_ELEMENTS)[Name][number];\n\n/** A serializable partial Tasty style object, merged into the base internally. */\nexport type ComponentStyles = StylesWithoutSelectors & {\n $?: string;\n mode?: never;\n recipe?: string;\n [token: `$${string}`]: Styles[string];\n [color: `#${string}`]: Styles[string];\n [state: `@${string}`]: Styles[string];\n};\n\n/** Style properties supplied by the user to override Cookbook defaults. */\nexport type ComponentStyleConfig = ComponentStyles;\n\n/** A component override with typed suggestions for its named sub-elements. */\nexport type CookbookComponentStyles<Name extends CookbookComponentName> =\n ComponentStyles &\n Partial<Record<CookbookComponentSubElementName<Name>, ComponentStyles>>;\n\nexport type ComponentStylesConfig = {\n [Name in CookbookComponentName]?: CookbookComponentStyles<Name>;\n};\n\nexport interface ThemeConfig {\n brand?: BrandConfig;\n palette?: ThemePaletteConfig;\n fonts?: ThemeFonts;\n states?: Record<string, string>;\n tokens?: ThemeTokens;\n presets?: TypographyPresets;\n /** Tasty UI styles, keyed by Cookbook component or bridge name. */\n styles?: ComponentStylesConfig;\n /** Explicit registration and overrides for user-authored components. */\n customStyles?: Record<string, Styles>;\n contrastLevel?: number | \"auto\";\n}\n\nexport interface MarkdownConfig {\n stripLeadingBadges?: boolean;\n /** Raw HTML policy for trusted Markdown. Untrusted package Markdown is always sanitized. */\n rawHtml?: \"allow\" | \"sanitize\" | \"strip\" | \"reject\";\n}\n\nexport interface SearchConfig {\n enabled?: boolean;\n}\n\nexport interface ComponentsConfig {\n /** Astro component paths keyed by Starlight component name. `Footer` also accepts `false`. */\n overrides?: Record<string, string | false>;\n}\n\nexport interface BuildConfig {\n strict?: boolean;\n ci?: boolean;\n cacheDir?: string;\n maxArtifactBytes?: number;\n maxUnpackedBytes?: number;\n maxFiles?: number;\n maxPathDepth?: number;\n maxAssetBytes?: number;\n}\n\nexport interface DocsConfig {\n /** Content and lock directory, relative to docs.config.ts (or the inline root). */\n root?: string;\n /** Old public routes mapped to current document routes. */\n redirects?: Record<string, string>;\n site?: SiteConfig;\n head?: HeadConfig[];\n /** Enable source-aware “Edit page” links. */\n editLink?: EditLinkConfig;\n /** Show the most recent Git commit date for each local page. */\n lastUpdated?: boolean;\n /** Languages keyed by their URL segment, or `root` for `/`. */\n locales?: Record<string, LocaleConfig>;\n /** Locale key used for fallback content. */\n defaultLocale?: string;\n content?: ContentConfig;\n navigation?: NavigationConfig | NavigationItem[];\n theme?: ThemeConfig;\n markdown?: MarkdownConfig;\n search?: SearchConfig;\n components?: ComponentsConfig;\n build?: BuildConfig;\n}\n\nexport interface NormalizedDocsConfig {\n redirects: Record<string, string>;\n site: SiteConfig;\n head: HeadConfig[];\n editLink?: EditLinkConfig;\n lastUpdated: boolean;\n locales?: Record<string, LocaleConfig>;\n defaultLocale?: string;\n content: Required<\n Pick<ContentConfig, \"allowOutsideRoot\" | \"localizeRepositoryLinks\">\n > &\n ContentConfig;\n navigation: NavigationConfig;\n theme: ThemeConfig & { brand: BrandConfig };\n markdown: Required<Pick<MarkdownConfig, \"stripLeadingBadges\" | \"rawHtml\">> &\n MarkdownConfig;\n search: Required<SearchConfig>;\n components: ComponentsConfig;\n build: Required<BuildConfig> & { base: string };\n}\n\nexport interface DocsFrontmatter {\n aliases?: string[];\n title?: string;\n description?: string;\n slug?: string;\n draft?: boolean;\n sidebar?: false | { label?: string; order?: number; group?: string };\n tableOfContents?:\n false | { minHeadingLevel?: number; maxHeadingLevel?: number };\n editUrl?: false | string;\n /** Starlight page layout. */\n template?: \"doc\" | \"splash\";\n hero?: {\n title?: string;\n tagline?: string;\n image?:\n | { html: string }\n | { file: string; alt?: string }\n | { dark: string; light: string; alt?: string };\n actions?: Array<{\n text: string;\n link: string;\n variant?: \"primary\" | \"secondary\" | \"minimal\";\n }>;\n };\n lastUpdated?: boolean | Date;\n prev?: false | string | { link?: string; label?: string };\n next?: false | string | { link?: string; label?: string };\n banner?: { content: string };\n pagefind?: boolean;\n head?: Array<Record<string, unknown>>;\n}\n\nexport interface DocsHeading {\n depth: number;\n text: string;\n slug: string;\n line?: number;\n}\n\nexport interface DocsReference {\n original: string;\n resolved?: string;\n targetSource?: string;\n fragment?: string;\n line?: number;\n}\n\nexport interface DocsAsset extends DocsReference {\n sourcePath?: string;\n publicPath?: string;\n hash?: string;\n bytes?: number;\n}\n\nexport interface DocsEntry {\n id: string;\n sourceId: string;\n routeBase: string;\n metadata: Record<string, unknown>;\n sourcePath: string;\n absolutePath: string;\n sourceRoot: string;\n route: string;\n title: string;\n description?: string;\n frontmatter: DocsFrontmatter;\n headings: DocsHeading[];\n body: string;\n transformedBody: string;\n ast: Root;\n links: DocsReference[];\n assets: DocsAsset[];\n trust: \"markdown\" | \"mdx\";\n package?: { requested: string; resolved: string };\n}\n\nexport interface DocsRoute {\n route: string;\n entryId: string;\n sourcePath: string;\n title: string;\n sidebar?: false | NavigationPlacement;\n}\n\nexport interface DocsGraph {\n redirects: Record<string, string>;\n root: string;\n config: NormalizedDocsConfig;\n entries: DocsEntry[];\n routes: DocsRoute[];\n assets: DocsAsset[];\n diagnostics: DocsDiagnostic[];\n entryByRoute(route: string): DocsEntry | undefined;\n entryBySource(sourcePath: string, sourceId?: string): DocsEntry | undefined;\n}\n\nexport interface PackageLockSource {\n requested: string;\n resolved: string;\n registry: string;\n integrity: string;\n vendored?: string;\n}\n\nexport interface CookbookLock {\n schemaVersion: 1;\n sources: PackageLockSource[];\n}\n\nexport interface PackageManifest {\n name: string;\n version: string;\n description?: string;\n homepage?: string;\n repository?: string | { type?: string; url?: string; directory?: string };\n cookbook?: {\n index?: string;\n include?: string[];\n exclude?: string[];\n theme?: { brand?: BrandConfig };\n };\n _integrity?: string;\n _resolved?: string;\n}\n\nexport interface PackageDiscovery {\n root: string;\n manifest: PackageManifest;\n home?: string;\n pages: string[];\n assets: string[];\n}\n\nexport interface CreateDocsGraphOptions {\n root?: string;\n config?: DocsConfig;\n lock?: CookbookLock;\n /** Public URL base used when rewriting routes and assets. */\n base?: string;\n}\n","import { glaze, type RegularColorDef } from \"@tenphi/glaze\";\nimport { mergeStyles, type Styles } from \"@tenphi/tasty/core\";\nimport {\n COOKBOOK_COMPONENT_NAMES,\n COOKBOOK_COMPONENT_SUB_ELEMENTS,\n} from \"../types.js\";\nimport type {\n BrandDeclaration,\n DocsConfig,\n DocsDiagnostic,\n NormalizedDocsConfig,\n ThemePaletteColor,\n} from \"../types.js\";\n\nconst DEFAULT_BRAND = \"okhsl(266 68% 48%)\";\nconst HEAD_KEYS = new Set([\"tag\", \"attrs\", \"content\"]);\nconst SITE_ICON_KEYS = new Set([\"source\", \"background\"]);\nconst COLOR_DECLARATION_KEYS = new Set([\n \"from\",\n \"tone\",\n \"saturation\",\n \"hue\",\n \"darkHue\",\n \"darkSaturation\",\n \"base\",\n \"contrast\",\n \"mode\",\n \"autoFlip\",\n \"opacity\",\n \"pastel\",\n \"role\",\n \"inherit\",\n]);\nconst ROOT_KEYS = new Set([\n \"root\",\n \"redirects\",\n \"site\",\n \"head\",\n \"editLink\",\n \"lastUpdated\",\n \"locales\",\n \"defaultLocale\",\n \"content\",\n \"navigation\",\n \"theme\",\n \"markdown\",\n \"search\",\n \"components\",\n \"build\",\n]);\n\nconst OBJECT_KEYS: Record<string, Set<string>> = {\n site: new Set([\n \"title\",\n \"version\",\n \"versions\",\n \"description\",\n \"url\",\n \"repository\",\n \"favicon\",\n \"headerLinks\",\n ]),\n content: new Set([\n \"sources\",\n \"allowOutsideRoot\",\n \"localizeRepositoryLinks\",\n \"frontmatter\",\n ]),\n markdown: new Set([\"stripLeadingBadges\", \"rawHtml\"]),\n search: new Set([\"enabled\"]),\n components: new Set([\"overrides\"]),\n theme: new Set([\n \"brand\",\n \"palette\",\n \"fonts\",\n \"states\",\n \"tokens\",\n \"presets\",\n \"styles\",\n \"customStyles\",\n \"contrastLevel\",\n ]),\n build: new Set([\n \"strict\",\n \"ci\",\n \"cacheDir\",\n \"maxArtifactBytes\",\n \"maxUnpackedBytes\",\n \"maxFiles\",\n \"maxPathDepth\",\n \"maxAssetBytes\",\n ]),\n};\n\nexport class DocsConfigError extends Error {\n readonly diagnostics: DocsDiagnostic[];\n\n constructor(diagnostics: DocsDiagnostic[]) {\n super(diagnostics.map((diagnostic) => diagnostic.message).join(\"\\n\"));\n this.name = \"DocsConfigError\";\n this.diagnostics = diagnostics;\n }\n}\n\nexport function validateConfig(config: DocsConfig): DocsDiagnostic[] {\n const diagnostics: DocsDiagnostic[] = [];\n if (config === null || typeof config !== \"object\" || Array.isArray(config)) {\n invalid(diagnostics, \"Documentation configuration must be an object.\");\n return diagnostics;\n }\n if (config.root !== undefined && typeof config.root !== \"string\") {\n invalid(diagnostics, \"root must be a directory path.\");\n }\n for (const key of Object.keys(config)) {\n if (!ROOT_KEYS.has(key)) unknown(diagnostics, key);\n }\n for (const [section, keys] of Object.entries(OBJECT_KEYS)) {\n const value = config[section as keyof DocsConfig];\n if (value === undefined) continue;\n if (!isRecord(value)) {\n invalid(diagnostics, `${section} must be an object.`);\n continue;\n }\n for (const key of Object.keys(value)) {\n if (!keys.has(key)) unknown(diagnostics, `${section}.${key}`);\n }\n }\n\n if (isRecord(config.site) && config.site.versions !== undefined) {\n if (\n !Array.isArray(config.site.versions) ||\n config.site.versions.length < 2\n ) {\n invalid(diagnostics, \"site.versions must contain at least two versions.\");\n } else {\n const bases = new Set<string>();\n for (const [index, version] of config.site.versions.entries()) {\n const path = `site.versions[${index}]`;\n if (!isRecord(version)) {\n invalid(diagnostics, `${path} must be an object.`);\n continue;\n }\n for (const key of Object.keys(version)) {\n if (key !== \"label\" && key !== \"routeBase\")\n unknown(diagnostics, `${path}.${key}`);\n }\n if (typeof version.label !== \"string\" || !version.label.trim())\n invalid(diagnostics, `${path}.label must be a non-empty string.`);\n const base = version.routeBase;\n if (\n typeof base !== \"string\" ||\n !base.startsWith(\"/\") ||\n (base !== \"/\" && base.endsWith(\"/\")) ||\n base.includes(\"//\") ||\n /[?#\\\\\\s]/.test(base) ||\n base.split(\"/\").some((segment) => segment === \".\" || segment === \"..\")\n ) {\n invalid(\n diagnostics,\n `${path}.routeBase must be a root-relative route without a trailing slash.`,\n );\n } else if (bases.has(base)) {\n invalid(diagnostics, `${path}.routeBase duplicates ${base}.`);\n } else {\n bases.add(base);\n }\n }\n }\n }\n\n if (isRecord(config.site) && config.site.headerLinks !== undefined) {\n if (!Array.isArray(config.site.headerLinks)) {\n invalid(diagnostics, \"site.headerLinks must be an array.\");\n } else {\n config.site.headerLinks.forEach((item, index) => {\n const path = `site.headerLinks[${index}]`;\n if (!isRecord(item)) {\n invalid(diagnostics, `${path} must be an object.`);\n return;\n }\n for (const key of Object.keys(item)) {\n if (![\"label\", \"link\", \"variant\", \"newTab\"].includes(key))\n unknown(diagnostics, `${path}.${key}`);\n }\n if (typeof item.label !== \"string\" || !item.label.trim())\n invalid(diagnostics, `${path}.label must be a non-empty string.`);\n if (\n typeof item.link !== \"string\" ||\n /[\\\\\\s]/.test(item.link) ||\n !(/^(?:\\/(?!\\/)|#)/.test(item.link) || isHttpUrl(item.link))\n )\n invalid(\n diagnostics,\n `${path}.link must be an HTTP(S) URL, root-relative route, or fragment.`,\n );\n if (\n item.variant !== undefined &&\n ![\"default\", \"primary\"].includes(item.variant as string)\n )\n invalid(\n diagnostics,\n `${path}.variant must be \"default\" or \"primary\".`,\n );\n if (item.newTab !== undefined && typeof item.newTab !== \"boolean\")\n invalid(diagnostics, `${path}.newTab must be a boolean.`);\n });\n }\n }\n\n if (config.navigation !== undefined && !Array.isArray(config.navigation)) {\n if (!isRecord(config.navigation)) {\n invalid(diagnostics, \"navigation must be an array or object.\");\n } else {\n for (const key of Object.keys(config.navigation)) {\n if (!new Set([\"items\", \"tabs\"]).has(key)) {\n unknown(diagnostics, `navigation.${key}`);\n }\n }\n if (\n config.navigation.items !== undefined &&\n !Array.isArray(config.navigation.items)\n ) {\n invalid(diagnostics, \"navigation.items must be an array.\");\n }\n if (\n config.navigation.tabs !== undefined &&\n !Array.isArray(config.navigation.tabs)\n ) {\n invalid(diagnostics, \"navigation.tabs must be an array.\");\n }\n }\n }\n if (Array.isArray(config.navigation)) {\n validateNavigationItems(config.navigation, \"navigation\", diagnostics);\n } else if (isRecord(config.navigation)) {\n if (Array.isArray(config.navigation.items)) {\n validateNavigationItems(\n config.navigation.items,\n \"navigation.items\",\n diagnostics,\n );\n }\n if (Array.isArray(config.navigation.tabs)) {\n for (const [index, tab] of config.navigation.tabs.entries()) {\n const path = `navigation.tabs[${index}]`;\n if (\n !isRecord(tab) ||\n typeof tab.label !== \"string\" ||\n typeof tab.link !== \"string\"\n ) {\n invalid(diagnostics, `${path} must have a label and link.`);\n } else if (tab.items !== undefined) {\n validateNavigationItems(tab.items, `${path}.items`, diagnostics);\n }\n }\n }\n }\n\n if (\n config.redirects !== undefined &&\n (!isRecord(config.redirects) ||\n Object.values(config.redirects).some(\n (value) => typeof value !== \"string\",\n ))\n )\n invalid(diagnostics, \"redirects must map old routes to document routes.\");\n const head = config.head;\n if (head !== undefined && !Array.isArray(head)) {\n invalid(diagnostics, \"head must be an array.\");\n } else {\n for (const [index, entry] of (head ?? []).entries()) {\n if (!isRecord(entry)) {\n invalid(diagnostics, `head[${index}] must be an object.`);\n continue;\n }\n for (const key of Object.keys(entry)) {\n if (!HEAD_KEYS.has(key)) {\n unknown(diagnostics, `head[${index}].${key}`);\n }\n }\n if (typeof entry.tag !== \"string\") {\n invalid(diagnostics, `head[${index}].tag must be a string.`);\n }\n if (entry.attrs !== undefined && !isRecord(entry.attrs)) {\n invalid(diagnostics, `head[${index}].attrs must be an object.`);\n } else {\n for (const [name, value] of Object.entries(entry.attrs ?? {})) {\n if (\n value !== undefined &&\n typeof value !== \"string\" &&\n typeof value !== \"boolean\"\n ) {\n invalid(\n diagnostics,\n `head[${index}].attrs.${name} must be a string or boolean.`,\n );\n }\n }\n }\n if (entry.content !== undefined && typeof entry.content !== \"string\") {\n invalid(diagnostics, `head[${index}].content must be a string.`);\n }\n }\n }\n\n const favicon = config.site?.favicon;\n if (favicon !== undefined) {\n if (typeof favicon === \"string\") {\n if (favicon.trim() === \"\") {\n invalid(diagnostics, \"site.favicon must be a non-empty local path.\");\n }\n } else if (!isRecord(favicon)) {\n invalid(\n diagnostics,\n \"site.favicon must be a local path or an object with a source path.\",\n );\n } else {\n for (const key of Object.keys(favicon)) {\n if (!SITE_ICON_KEYS.has(key)) {\n unknown(diagnostics, `site.favicon.${key}`);\n }\n }\n if (typeof favicon.source !== \"string\" || favicon.source.trim() === \"\") {\n invalid(diagnostics, \"site.favicon.source must be a non-empty string.\");\n }\n if (\n favicon.background !== undefined &&\n (typeof favicon.background !== \"string\" ||\n favicon.background.trim() === \"\")\n ) {\n invalid(\n diagnostics,\n \"site.favicon.background must be a non-empty color string.\",\n );\n }\n }\n }\n for (const field of [\"url\", \"repository\"] as const) {\n const value = config.site?.[field];\n if (value === undefined) continue;\n if (typeof value !== \"string\" || !isHttpUrl(value)) {\n invalid(diagnostics, `site.${field} must be an absolute HTTP(S) URL.`);\n }\n }\n\n if (\n config.editLink !== undefined &&\n (!isRecord(config.editLink) || typeof config.editLink.baseUrl !== \"string\")\n ) {\n invalid(diagnostics, \"editLink must contain a string baseUrl.\");\n } else if (config.editLink !== undefined) {\n for (const key of Object.keys(config.editLink)) {\n if (key !== \"baseUrl\") unknown(diagnostics, `editLink.${key}`);\n }\n try {\n new URL(config.editLink.baseUrl);\n } catch {\n invalid(diagnostics, \"editLink.baseUrl must be an absolute URL.\");\n }\n }\n if (\n config.lastUpdated !== undefined &&\n typeof config.lastUpdated !== \"boolean\"\n ) {\n invalid(diagnostics, \"lastUpdated must be a boolean.\");\n }\n if (config.locales !== undefined && !isRecord(config.locales)) {\n invalid(diagnostics, \"locales must be an object.\");\n } else {\n for (const [key, locale] of Object.entries(config.locales ?? {})) {\n if (!isRecord(locale) || typeof locale.label !== \"string\") {\n invalid(diagnostics, `locales.${key} must contain a string label.`);\n continue;\n }\n for (const property of Object.keys(locale)) {\n if (![\"label\", \"lang\", \"dir\"].includes(property)) {\n unknown(diagnostics, `locales.${key}.${property}`);\n }\n }\n if (locale.lang !== undefined && typeof locale.lang !== \"string\") {\n invalid(diagnostics, `locales.${key}.lang must be a string.`);\n }\n if (\n locale.dir !== undefined &&\n locale.dir !== \"ltr\" &&\n locale.dir !== \"rtl\"\n ) {\n invalid(diagnostics, `locales.${key}.dir must be \"ltr\" or \"rtl\".`);\n }\n }\n }\n if (\n config.defaultLocale !== undefined &&\n typeof config.defaultLocale !== \"string\"\n ) {\n invalid(diagnostics, \"defaultLocale must be a string.\");\n } else if (\n config.defaultLocale !== undefined &&\n (config.locales === undefined || !(config.defaultLocale in config.locales))\n ) {\n invalid(\n diagnostics,\n `defaultLocale must match a key in locales; received \"${config.defaultLocale}\".`,\n );\n }\n\n if (\n config.content?.allowOutsideRoot !== undefined &&\n typeof config.content.allowOutsideRoot !== \"boolean\"\n ) {\n invalid(diagnostics, \"content.allowOutsideRoot must be a boolean.\");\n }\n if (\n config.content?.localizeRepositoryLinks !== undefined &&\n typeof config.content.localizeRepositoryLinks !== \"boolean\"\n ) {\n invalid(diagnostics, \"content.localizeRepositoryLinks must be a boolean.\");\n }\n const configuredSources = config.content?.sources;\n if (configuredSources !== undefined && !Array.isArray(configuredSources)) {\n invalid(diagnostics, \"content.sources must be an array.\");\n }\n const sources = Array.isArray(configuredSources) ? configuredSources : [];\n for (const [index, source] of sources.entries()) {\n if (!isRecord(source)) {\n invalid(diagnostics, `content.sources[${index}] must be an object.`);\n continue;\n }\n const sourceRecord = source as unknown as Record<string, unknown>;\n const variants = [\"file\", \"glob\", \"package\", \"openapi\"].filter(\n (key) => key in source,\n );\n if (variants.length !== 1) {\n diagnostics.push({\n code: \"DOCS_CONFIG_INVALID\",\n severity: \"error\",\n message: `content.sources[${index}] must select exactly one of file, glob, package, or openapi.`,\n });\n continue;\n }\n const variant = variants[0] as \"file\" | \"glob\" | \"package\" | \"openapi\";\n const allowed = {\n file: new Set([\n \"id\",\n \"root\",\n \"routeBase\",\n \"file\",\n \"route\",\n \"title\",\n \"description\",\n \"navigation\",\n ]),\n glob: new Set([\n \"id\",\n \"root\",\n \"glob\",\n \"base\",\n \"routeBase\",\n \"exclude\",\n \"navigation\",\n ]),\n package: new Set([\n \"id\",\n \"package\",\n \"registry\",\n \"include\",\n \"exclude\",\n \"index\",\n \"routeBase\",\n \"trust\",\n ]),\n openapi: new Set([\"id\", \"root\", \"routeBase\", \"openapi\"]),\n }[variant];\n for (const key of Object.keys(source)) {\n if (!allowed.has(key))\n unknown(diagnostics, `content.sources[${index}].${key}`);\n }\n for (const field of [\n \"id\",\n \"root\",\n \"route\",\n \"routeBase\",\n \"base\",\n \"index\",\n \"title\",\n \"description\",\n \"registry\",\n ]) {\n if (\n sourceRecord[field] !== undefined &&\n typeof sourceRecord[field] !== \"string\"\n )\n invalid(\n diagnostics,\n `content.sources[${index}].${field} must be a string.`,\n );\n }\n if (\n typeof sourceRecord.id === \"string\" &&\n !/^[a-zA-Z0-9_-]+$/.test(sourceRecord.id)\n )\n invalid(\n diagnostics,\n `content.sources[${index}].id must contain only letters, numbers, underscores, and hyphens.`,\n );\n if (\n sourceRecord.trust !== undefined &&\n ![\"markdown\", \"mdx\"].includes(String(sourceRecord.trust))\n )\n invalid(\n diagnostics,\n `content.sources[${index}].trust must be \"markdown\" or \"mdx\".`,\n );\n if (\n typeof sourceRecord.registry === \"string\" &&\n !isHttpUrl(sourceRecord.registry)\n )\n invalid(\n diagnostics,\n `content.sources[${index}].registry must be an absolute HTTP(S) URL.`,\n );\n const selector = sourceRecord[variant];\n if (\n variant === \"glob\"\n ? typeof selector !== \"string\" &&\n (!Array.isArray(selector) ||\n selector.some((value) => typeof value !== \"string\"))\n : typeof selector !== \"string\" || selector.trim() === \"\"\n ) {\n invalid(\n diagnostics,\n `content.sources[${index}].${variant} must be ${variant === \"glob\" ? \"a string or string array\" : \"a non-empty string\"}.`,\n );\n }\n for (const list of [\"include\", \"exclude\"] as const) {\n const value = sourceRecord[list];\n if (\n value !== undefined &&\n (!Array.isArray(value) ||\n value.some((entry) => typeof entry !== \"string\"))\n ) {\n invalid(\n diagnostics,\n `content.sources[${index}].${list} must be a string array.`,\n );\n }\n }\n }\n\n if (\n config.markdown?.stripLeadingBadges !== undefined &&\n typeof config.markdown.stripLeadingBadges !== \"boolean\"\n ) {\n invalid(diagnostics, \"markdown.stripLeadingBadges must be a boolean.\");\n }\n if (\n config.markdown?.rawHtml !== undefined &&\n ![\"allow\", \"sanitize\", \"strip\", \"reject\"].includes(config.markdown.rawHtml)\n ) {\n invalid(\n diagnostics,\n 'markdown.rawHtml must be \"allow\", \"sanitize\", \"strip\", or \"reject\".',\n );\n }\n if (\n config.search?.enabled !== undefined &&\n typeof config.search.enabled !== \"boolean\"\n ) {\n invalid(diagnostics, \"search.enabled must be a boolean.\");\n }\n for (const key of [\"strict\", \"ci\"] as const) {\n const value = config.build?.[key];\n if (value !== undefined && typeof value !== \"boolean\") {\n invalid(diagnostics, `build.${key} must be a boolean.`);\n }\n }\n for (const key of [\n \"maxArtifactBytes\",\n \"maxUnpackedBytes\",\n \"maxFiles\",\n \"maxPathDepth\",\n \"maxAssetBytes\",\n ] as const) {\n const value = config.build?.[key];\n if (value !== undefined && (!Number.isSafeInteger(value) || value <= 0)) {\n invalid(diagnostics, `build.${key} must be a positive integer.`);\n }\n }\n\n const brand = config.theme?.brand;\n if (\n typeof brand === \"object\" &&\n brand !== null &&\n \"contrast\" in brand &&\n !brand.unsafeContrast\n ) {\n const target = brand.contrast?.apca;\n const normal = Array.isArray(target) ? target[0] : target;\n if (typeof normal === \"number\" && normal < 45) {\n diagnostics.push({\n code: \"DOCS_CONFIG_INVALID\",\n severity: \"error\",\n message:\n \"theme.brand.contrast.apca cannot be below 45 without unsafeContrast.\",\n hint: \"Remove the override, use 45 or higher, or explicitly set unsafeContrast: true.\",\n });\n }\n }\n\n if (\n config.content?.frontmatter !== undefined &&\n ![\"preserve\", \"reject\"].includes(config.content.frontmatter)\n )\n invalid(diagnostics, 'content.frontmatter must be \"preserve\" or \"reject\".');\n for (const field of [\n \"styles\",\n \"customStyles\",\n \"palette\",\n \"fonts\",\n \"tokens\",\n \"states\",\n \"presets\",\n ] as const) {\n if (config.theme?.[field] !== undefined && !isRecord(config.theme[field]))\n invalid(diagnostics, `theme.${field} must be an object.`);\n }\n if (isRecord(config.theme?.fonts)) {\n for (const [role, font] of Object.entries(config.theme.fonts)) {\n const path = `theme.fonts.${role}`;\n if (![\"body\", \"heading\", \"code\"].includes(role)) {\n unknown(diagnostics, path);\n continue;\n }\n if (font === undefined) continue;\n if (typeof font === \"string\") {\n if (!validFontFamily(font))\n invalid(diagnostics, `${path} must name a Google Fonts family.`);\n continue;\n }\n if (!isRecord(font)) {\n invalid(\n diagnostics,\n `${path} must be a Google Fonts name or font definition.`,\n );\n continue;\n }\n if (\"google\" in font) {\n for (const key of Object.keys(font))\n if (![\"google\", \"weights\"].includes(key))\n unknown(diagnostics, `${path}.${key}`);\n if (!validFontFamily(font.google))\n invalid(\n diagnostics,\n `${path}.google must name a Google Fonts family.`,\n );\n if (\n font.weights !== undefined &&\n (!Array.isArray(font.weights) ||\n font.weights.length === 0 ||\n font.weights.some(\n (weight) =>\n !Number.isInteger(weight) || weight < 1 || weight > 1000,\n ))\n )\n invalid(\n diagnostics,\n `${path}.weights must be a non-empty array of font weights from 1 to 1000.`,\n );\n } else {\n for (const key of Object.keys(font))\n if (![\"family\", \"files\"].includes(key))\n unknown(diagnostics, `${path}.${key}`);\n if (!validFontFamily(font.family))\n invalid(diagnostics, `${path}.family must be a font family name.`);\n if (!Array.isArray(font.files) || font.files.length === 0) {\n invalid(\n diagnostics,\n `${path}.files must contain at least one font file.`,\n );\n continue;\n }\n font.files.forEach((file, index) => {\n const filePath = `${path}.files[${index}]`;\n if (!isRecord(file)) {\n invalid(diagnostics, `${filePath} must be an object.`);\n return;\n }\n for (const key of Object.keys(file))\n if (![\"src\", \"weight\", \"style\"].includes(key))\n unknown(diagnostics, `${filePath}.${key}`);\n if (\n typeof file.src !== \"string\" ||\n !/^\\/(?!\\/)[^\\s\"'()\\\\?#]+\\.(?:woff2?|ttf|otf)$/.test(file.src) ||\n file.src\n .split(\"/\")\n .some((segment) => segment === \".\" || segment === \"..\")\n )\n invalid(\n diagnostics,\n `${filePath}.src must be a root-relative .woff2, .woff, .ttf, or .otf public path.`,\n );\n if (\n file.weight !== undefined &&\n !(\n typeof file.weight === \"number\" &&\n Number.isInteger(file.weight) &&\n file.weight >= 1 &&\n file.weight <= 1000\n ) &&\n !(\n typeof file.weight === \"string\" &&\n /^(?:[1-9]\\d{0,2}|1000) (?:[1-9]\\d{0,2}|1000)$/.test(\n file.weight,\n ) &&\n Number(file.weight.split(\" \")[0]) <\n Number(file.weight.split(\" \")[1])\n )\n )\n invalid(\n diagnostics,\n `${filePath}.weight must be a weight from 1 to 1000 or an ascending range.`,\n );\n if (\n file.style !== undefined &&\n ![\"normal\", \"italic\"].includes(file.style as string)\n )\n invalid(diagnostics, `${filePath}.style must be normal or italic.`);\n });\n }\n }\n }\n for (const [name, entry] of Object.entries(config.theme?.styles ?? {})) {\n if (!(COOKBOOK_COMPONENT_NAMES as readonly string[]).includes(name)) {\n unknown(\n diagnostics,\n `theme.styles.${name}; register custom components under theme.customStyles`,\n );\n continue;\n }\n if (!isRecord(entry))\n invalid(\n diagnostics,\n `theme.styles.${name} must be a Tasty style object.`,\n );\n else {\n if (\"mode\" in entry)\n invalid(\n diagnostics,\n `theme.styles.${name} must contain only Tasty properties, without a mode wrapper.`,\n );\n const elements: readonly string[] =\n COOKBOOK_COMPONENT_SUB_ELEMENTS[\n name as keyof typeof COOKBOOK_COMPONENT_SUB_ELEMENTS\n ];\n for (const key of Object.keys(entry)) {\n if (/^[A-Z]/.test(key) && !elements.includes(key))\n unknown(diagnostics, `theme.styles.${name}.${key}`);\n }\n }\n }\n for (const [name, entry] of Object.entries(\n config.theme?.customStyles ?? {},\n )) {\n if ((COOKBOOK_COMPONENT_NAMES as readonly string[]).includes(name))\n invalid(\n diagnostics,\n `Use theme.styles.${name} for a built-in component.`,\n );\n if (\n !/^[A-Za-z][A-Za-z0-9_-]*$/.test(name) ||\n !isRecord(entry) ||\n \"mode\" in entry\n )\n invalid(\n diagnostics,\n `theme.customStyles.${name} must be a named partial Tasty style object.`,\n );\n }\n for (const [name, value] of Object.entries(config.theme?.palette ?? {})) {\n if (\n ![\n \"surface\",\n \"header\",\n \"overlay\",\n \"text\",\n \"heading\",\n \"textSoft\",\n \"info\",\n \"success\",\n \"warning\",\n \"danger\",\n ].includes(name)\n )\n unknown(diagnostics, `theme.palette.${name}`);\n validatePaletteColor(name, value, diagnostics);\n }\n if (brand !== undefined) {\n try {\n if (isBrandDeclaration(brand)) {\n glaze\n .color({\n hue: brand.hue,\n saturation: brand.saturation,\n tone: brand.tone,\n })\n .resolve();\n } else {\n glaze\n .color({\n from:\n typeof brand === \"object\" && brand !== null && \"from\" in brand\n ? brand.from\n : brand,\n })\n .resolve();\n }\n } catch (error) {\n invalid(\n diagnostics,\n `theme.brand: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n const contrast = config.theme?.contrastLevel;\n if (\n contrast !== undefined &&\n contrast !== \"auto\" &&\n (typeof contrast !== \"number\" ||\n !Number.isFinite(contrast) ||\n contrast < 0 ||\n contrast > 100)\n )\n invalid(\n diagnostics,\n 'theme.contrastLevel must be \"auto\" or a number from 0 to 100.',\n );\n\n const componentOverrides = config.components?.overrides;\n if (componentOverrides !== undefined && !isRecord(componentOverrides)) {\n invalid(diagnostics, \"components.overrides must be an object.\");\n } else {\n for (const [name, override] of Object.entries(componentOverrides ?? {})) {\n if (typeof override === \"string\") continue;\n if (name === \"Footer\" && override === false) continue;\n invalid(\n diagnostics,\n `components.overrides.${name} must be an Astro component path${name === \"Footer\" ? \" or false\" : \"\"}.`,\n );\n }\n }\n return diagnostics;\n}\n\nfunction validatePaletteColor(\n name: string,\n value: ThemePaletteColor,\n diagnostics: DocsDiagnostic[],\n): void {\n try {\n if (!isPaletteDeclaration(value)) {\n glaze.color({ from: value }).resolve();\n return;\n }\n for (const key of Object.keys(value)) {\n if (!COLOR_DECLARATION_KEYS.has(key))\n unknown(diagnostics, `theme.palette.${name}.${key}`);\n }\n const colorName = name === \"textSoft\" ? \"text-soft\" : name;\n const theme = glaze(266, 68);\n theme.colors({\n surface: { tone: 98 },\n \"surface-2\": { base: \"surface\", tone: \"-2\" },\n \"accent-surface\": { tone: 48 },\n text: { base: \"surface\", contrast: { apca: 75 } },\n heading: { base: \"surface\", tone: 4 },\n \"text-soft\": { base: \"surface\", contrast: { apca: 60 } },\n [colorName]: { tone: colorName === \"surface\" ? 98 : 50, ...value },\n });\n theme.resolve();\n } catch (error) {\n invalid(\n diagnostics,\n `theme.palette.${name}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\nfunction isPaletteDeclaration(\n value: ThemePaletteColor,\n): value is RegularColorDef {\n return (\n typeof value === \"object\" &&\n value !== null &&\n !(\"h\" in value || \"r\" in value || \"c\" in value)\n );\n}\n\nfunction isBrandDeclaration(value: unknown): value is BrandDeclaration {\n return (\n isRecord(value) &&\n \"hue\" in value &&\n \"saturation\" in value &&\n \"tone\" in value\n );\n}\n\nfunction unknown(diagnostics: DocsDiagnostic[], path: string): void {\n diagnostics.push({\n code: \"DOCS_CONFIG_UNKNOWN_KEY\",\n severity: \"error\",\n message: `Unknown configuration key \"${path}\".`,\n });\n}\n\nfunction invalid(diagnostics: DocsDiagnostic[], message: string): void {\n diagnostics.push({\n code: \"DOCS_CONFIG_INVALID\",\n severity: \"error\",\n message,\n });\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction validFontFamily(value: unknown): value is string {\n return (\n typeof value === \"string\" &&\n value.length <= 100 &&\n /^[\\p{L}\\p{N} ._-]+$/u.test(value) &&\n value.trim() === value &&\n value.length > 0\n );\n}\n\nfunction isHttpUrl(value: string): boolean {\n try {\n return [\"http:\", \"https:\"].includes(new URL(value).protocol);\n } catch {\n return false;\n }\n}\n\nfunction validateNavigationItems(\n items: unknown,\n path: string,\n diagnostics: DocsDiagnostic[],\n): void {\n if (!Array.isArray(items)) {\n invalid(diagnostics, `${path} must be an array.`);\n return;\n }\n for (const [index, item] of items.entries()) {\n const itemPath = `${path}[${index}]`;\n if (typeof item === \"string\") continue;\n if (!isRecord(item) || typeof item.label !== \"string\") {\n invalid(\n diagnostics,\n `${itemPath} must be a route or a labeled navigation item.`,\n );\n continue;\n }\n const group = \"items\" in item || \"autogenerate\" in item;\n if (\n group &&\n item.link !== undefined &&\n (typeof item.link !== \"string\" ||\n !/^\\/(?!\\/)[^?#\\\\\\s]*$/.test(item.link) ||\n item.link.includes(\"//\") ||\n item.link\n .split(\"/\")\n .some((segment) => segment === \".\" || segment === \"..\"))\n ) {\n invalid(\n diagnostics,\n `${itemPath}.link must be a root-relative page route without a query or fragment.`,\n );\n }\n if (\"items\" in item) {\n validateNavigationItems(item.items, `${itemPath}.items`, diagnostics);\n } else if (\"autogenerate\" in item) {\n if (\n !isRecord(item.autogenerate) ||\n typeof item.autogenerate.directory !== \"string\"\n ) {\n invalid(\n diagnostics,\n `${itemPath}.autogenerate.directory must be a directory path.`,\n );\n }\n } else if (typeof item.link !== \"string\") {\n invalid(diagnostics, `${itemPath}.link must be a URL or route.`);\n }\n }\n}\n\nexport function normalizeDocsConfig(\n config: DocsConfig = {},\n): NormalizedDocsConfig {\n const diagnostics = validateConfig(config);\n if (diagnostics.length > 0) throw new DocsConfigError(diagnostics);\n const navigation = Array.isArray(config.navigation)\n ? { items: config.navigation }\n : (config.navigation ?? {});\n\n return {\n redirects: { ...config.redirects },\n site: { ...config.site },\n head: [...(config.head ?? [])],\n ...(config.editLink ? { editLink: { ...config.editLink } } : {}),\n lastUpdated: config.lastUpdated ?? false,\n ...(config.locales ? { locales: { ...config.locales } } : {}),\n ...(config.defaultLocale ? { defaultLocale: config.defaultLocale } : {}),\n content: {\n allowOutsideRoot: false,\n localizeRepositoryLinks: false,\n ...config.content,\n },\n navigation,\n theme: { ...config.theme, brand: config.theme?.brand ?? DEFAULT_BRAND },\n markdown: {\n stripLeadingBadges: true,\n rawHtml: \"sanitize\",\n ...config.markdown,\n },\n search: { enabled: true, ...config.search },\n components: { ...config.components },\n build: {\n strict: true,\n ci: process.env.CI === \"true\",\n base: \"/\",\n cacheDir: \"\",\n maxArtifactBytes: 25 * 1024 * 1024,\n maxUnpackedBytes: 100 * 1024 * 1024,\n maxFiles: 10_000,\n maxPathDepth: 24,\n maxAssetBytes: 20 * 1024 * 1024,\n ...config.build,\n },\n };\n}\n\nexport function defineDocsConfig(config: DocsConfig): DocsConfig {\n const diagnostics = validateConfig(config);\n if (diagnostics.length > 0) throw new DocsConfigError(diagnostics);\n return config;\n}\n\n/** Compose presets. Color roles and fonts replace, other objects merge, and styles use Tasty semantics. */\nexport function mergeDocsConfig(...configs: DocsConfig[]): DocsConfig {\n const merge = (\n base: Record<string, unknown>,\n next: Record<string, unknown>,\n ) => {\n const result = { ...base };\n for (const [key, value] of Object.entries(next)) {\n if (value === undefined) continue;\n result[key] = isRecord(value)\n ? merge(isRecord(result[key]) ? result[key] : {}, value)\n : Array.isArray(value)\n ? [...value]\n : value;\n }\n return result;\n };\n return defineDocsConfig(\n configs.reduce<DocsConfig>((base, next) => {\n const diagnostics = validateConfig(next);\n if (diagnostics.length) throw new DocsConfigError(diagnostics);\n const result = merge(\n base as Record<string, unknown>,\n next as Record<string, unknown>,\n ) as DocsConfig;\n // A color declaration is one value. Merging its fields could retain an\n // obsolete `from` seed when a consumer switches to tone relationships.\n if (next.theme?.brand !== undefined)\n result.theme!.brand = next.theme.brand;\n if (next.theme?.palette)\n result.theme!.palette = {\n ...base.theme?.palette,\n ...Object.fromEntries(\n Object.entries(next.theme.palette).filter(\n ([, color]) => color !== undefined,\n ),\n ),\n };\n // Font definitions are alternatives, so a consumer can switch from a\n // Google family to local files (or back) in a layered configuration.\n if (next.theme?.fonts)\n result.theme!.fonts = {\n ...base.theme?.fonts,\n ...Object.fromEntries(\n Object.entries(next.theme.fonts).filter(\n ([, font]) => font !== undefined,\n ),\n ),\n };\n for (const field of [\"styles\", \"customStyles\"] as const) {\n if (!next.theme?.[field]) continue;\n const styles = { ...base.theme?.[field] } as Record<string, Styles>;\n for (const [name, configured] of Object.entries(next.theme[field])) {\n styles[name] = mergeStyles(styles[name] ?? {}, configured);\n }\n result.theme![field] = styles;\n }\n return result;\n }, {}),\n );\n}\n\nexport { COOKBOOK_COMPONENT_NAMES, COOKBOOK_COMPONENT_SUB_ELEMENTS };\n\nexport type {\n BrandConfig,\n BrandDeclaration,\n BuildConfig,\n ComponentStyleConfig,\n ComponentStyles,\n ComponentStylesConfig,\n CookbookComponentName,\n ComponentsConfig,\n ContentConfig,\n DocsConfig,\n DocsSource,\n EditLinkConfig,\n HeadConfig,\n LocaleConfig,\n MarkdownConfig,\n NavigationConfig,\n NavigationItem,\n NavigationPlacement,\n NavigationTab,\n NormalizedDocsConfig,\n SearchConfig,\n SiteConfig,\n HeaderLink,\n SiteIconConfig,\n ThemeConfig,\n ThemeFont,\n ThemeFontFile,\n ThemeFonts,\n ThemePaletteColor,\n ThemePaletteConfig,\n ThemeTokens,\n ThemeTokenValue,\n TypographyPreset,\n TypographyPresets,\n} from \"../types.js\";\n"],"mappings":";;;;AAmQA,MAAa,2BAA2B;CACtC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAKA,MAAa,kCAAkC;CAC7C,WAAW;EAAC;EAAa;EAAgB;CAAS;CAClD,aAAa,CAAC;CACd,SAAS;EACP;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,aAAa;EACX;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,QAAQ,CAAC,YAAY;CACrB,cAAc;EAAC;EAAS;EAAY;EAAS;EAAU;EAAc;CAAM;CAC3E,uBAAuB,CAAC,SAAS;CACjC,MAAM;EAAC;EAAY;EAAY;CAAW;CAC1C,SAAS;EAAC;EAAS;EAAQ;EAAO;EAAW;CAAQ;CACrD,WAAW;EAAC;EAAW;EAAO;CAAM;CACpC,KAAK;EAAC;EAAW;EAAU;CAAe;CAC1C,QAAQ;EACN;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,MAAM;EACJ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,gBAAgB;EACd;EACA;EACA;EACA;EACA;EACA;CACF;CACA,MAAM,CAAC,OAAO,MAAM;CACpB,mBAAmB;EACjB;EACA;EACA;EACA;EACA;EACA;CACF;CACA,iBAAiB;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,eAAe;EAAC;EAAS;EAAQ;EAAmB;CAAY;CAChE,oBAAoB,CAAC;CACrB,SAAS;EAAC;EAAW;EAAQ;CAAU;CACvC,kBAAkB,CAAC,QAAQ;CAC3B,kBAAkB;EAChB;EACA;EACA;EACA;EACA;EACA;CACF;CACA,sBAAsB;EACpB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,uBAAuB;EACrB;EACA;EACA;EACA;EACA;EACA;CACF;CACA,gBAAgB,CAAC;CACjB,iBAAiB;EAAC;EAAW;EAAS;EAAa;EAAQ;CAAa;CACxE,SAAS;EAAC;EAAW;EAAS;EAAS;EAAQ;EAAW;CAAK;CAC/D,SAAS;EACP;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,OAAO,CAAC,QAAQ,QAAQ;CACxB,aAAa;EAAC;EAAQ;EAAa;CAAM;CACzC,MAAM;EAAC;EAAQ;EAAU;EAAkB;CAAe;CAC1D,iBAAiB;EACf;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,aAAa;EACX;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,eAAe;EACb;EACA;EACA;EACA;EACA;CACF;CACA,iBAAiB;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;;ACpfA,MAAM,gBAAgB;AACtB,MAAM,4BAAY,IAAI,IAAI;CAAC;CAAO;CAAS;AAAS,CAAC;AACrD,MAAM,iCAAiB,IAAI,IAAI,CAAC,UAAU,YAAY,CAAC;AACvD,MAAM,yCAAyB,IAAI,IAAI;CACrC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AACD,MAAM,4BAAY,IAAI,IAAI;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,cAA2C;CAC/C,sBAAM,IAAI,IAAI;EACZ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CACD,yBAAS,IAAI,IAAI;EACf;EACA;EACA;EACA;CACF,CAAC;CACD,0BAAU,IAAI,IAAI,CAAC,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"}
|
package/dist/content/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { S as DocsGraph, T as DocsRoute, _ as DocsAsset, b as DocsEntry, h as CreateDocsGraphOptions, v as DocsConfig } from "../types-CY8WfBmM.js";
|
|
2
2
|
//#region src/content/index.d.ts
|
|
3
3
|
interface DocsLoaderContext {
|
|
4
4
|
store: {
|
package/dist/content/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createDocsLoader } from "../content-
|
|
1
|
+
import { t as createDocsLoader } from "../content-CrWnRfN7.js";
|
|
2
2
|
export { createDocsLoader };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as normalizeDocsConfig } from "./config-
|
|
1
|
+
import { i as normalizeDocsConfig } from "./config-CW0iIYp8.js";
|
|
2
2
|
import { cloneAst, parseMarkdown, removeRenderedTitle, serializeMarkdown, stripLeadingBadgeBlock } from "./markdown/index.js";
|
|
3
3
|
import { lstat, mkdir, mkdtemp, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
4
4
|
import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
@@ -68,6 +68,192 @@ async function sanitizeMarkup(html, rewrite) {
|
|
|
68
68
|
return result;
|
|
69
69
|
}
|
|
70
70
|
//#endregion
|
|
71
|
+
//#region src/graph/openapi.ts
|
|
72
|
+
const METHODS = [
|
|
73
|
+
"get",
|
|
74
|
+
"post",
|
|
75
|
+
"put",
|
|
76
|
+
"patch",
|
|
77
|
+
"delete",
|
|
78
|
+
"head",
|
|
79
|
+
"options",
|
|
80
|
+
"trace"
|
|
81
|
+
];
|
|
82
|
+
/** Turn a local OpenAPI 3 document into static, searchable Markdown pages. */
|
|
83
|
+
function openApiPages(source, routeBase, text) {
|
|
84
|
+
let document;
|
|
85
|
+
try {
|
|
86
|
+
document = source.endsWith(".json") ? JSON.parse(text) : parse(text, { uniqueKeys: true });
|
|
87
|
+
} catch (error) {
|
|
88
|
+
throw new Error(`Invalid OpenAPI document ${source}: ${String(error)}`);
|
|
89
|
+
}
|
|
90
|
+
if (!record(document) || typeof document.openapi !== "string" || !document.openapi.startsWith("3.")) throw new Error(`OpenAPI source ${source} must use OpenAPI 3.x.`);
|
|
91
|
+
if (!record(document.info) || typeof document.info.title !== "string" || !record(document.paths)) throw new Error(`OpenAPI source ${source} needs info.title and paths.`);
|
|
92
|
+
assertLocalReferences(document, document, source);
|
|
93
|
+
const title = document.info.title;
|
|
94
|
+
const description = string(document.info.description);
|
|
95
|
+
const operations = [];
|
|
96
|
+
const routes = /* @__PURE__ */ new Set([routeBase]);
|
|
97
|
+
for (const [path, rawItem] of Object.entries(document.paths)) {
|
|
98
|
+
const item = resolveReference(rawItem, document);
|
|
99
|
+
if (!path.startsWith("/") || !record(item)) throw new Error(`Invalid OpenAPI path ${path} in ${source}.`);
|
|
100
|
+
for (const method of METHODS) {
|
|
101
|
+
const operation = item[method];
|
|
102
|
+
if (operation === void 0) continue;
|
|
103
|
+
if (!record(operation)) throw new Error(`Invalid ${method.toUpperCase()} ${path} in ${source}.`);
|
|
104
|
+
const slug = slugify(string(operation.operationId) ?? `${method}-${path}`);
|
|
105
|
+
if (!slug) throw new Error(`Cannot generate a route for ${method.toUpperCase()} ${path} in ${source}.`);
|
|
106
|
+
const route = `${routeBase === "/" ? "" : routeBase}/${slug}`;
|
|
107
|
+
if (routes.has(route)) throw new Error(`Duplicate OpenAPI operation route ${route} in ${source}. Give operations distinct operationId values.`);
|
|
108
|
+
routes.add(route);
|
|
109
|
+
operations.push({
|
|
110
|
+
method,
|
|
111
|
+
path,
|
|
112
|
+
operation,
|
|
113
|
+
route,
|
|
114
|
+
title: string(operation.summary) ?? `${method.toUpperCase()} ${path}`
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const overview = [`# ${escapeText(title)}`, ""];
|
|
119
|
+
if (description) overview.push(description, "");
|
|
120
|
+
if (typeof document.info.version === "string") overview.push(`**API version:** ${escapeText(document.info.version)}`, "");
|
|
121
|
+
if (Array.isArray(document.servers) && document.servers.length) {
|
|
122
|
+
overview.push("## Servers", "");
|
|
123
|
+
for (const server of document.servers) if (record(server) && typeof server.url === "string") overview.push(`- \`${escapeCode(server.url)}\`${string(server.description) ? ` — ${escapeText(server.description)}` : ""}`);
|
|
124
|
+
overview.push("");
|
|
125
|
+
}
|
|
126
|
+
overview.push("## Operations", "");
|
|
127
|
+
for (const operation of operations) overview.push(`- [${escapeText(operation.method.toUpperCase())} ${escapeText(operation.path)} — ${escapeText(operation.title)}](${operation.route})`);
|
|
128
|
+
if (!operations.length) overview.push("No operations are defined.");
|
|
129
|
+
overview.push("");
|
|
130
|
+
const schemas = record(document.components) && record(document.components.schemas) ? document.components.schemas : void 0;
|
|
131
|
+
if (schemas && Object.keys(schemas).length) {
|
|
132
|
+
overview.push("## Schemas", "");
|
|
133
|
+
for (const [name, schema] of Object.entries(schemas)) overview.push(`### ${escapeText(name)}`, "", jsonBlock(schema), "");
|
|
134
|
+
}
|
|
135
|
+
const pages = [{
|
|
136
|
+
route: routeBase,
|
|
137
|
+
sourcePath: `${source}#overview.md`,
|
|
138
|
+
title,
|
|
139
|
+
...description ? { description } : {},
|
|
140
|
+
body: overview.join("\n")
|
|
141
|
+
}];
|
|
142
|
+
for (const { method, path, operation, route, title: operationTitle } of operations) {
|
|
143
|
+
const body = [
|
|
144
|
+
`# ${escapeText(operationTitle)}`,
|
|
145
|
+
"",
|
|
146
|
+
`**${method.toUpperCase()}** \`${escapeCode(path)}\``,
|
|
147
|
+
"",
|
|
148
|
+
`[All operations](${routeBase})`,
|
|
149
|
+
""
|
|
150
|
+
];
|
|
151
|
+
if (string(operation.description)) body.push(operation.description, "");
|
|
152
|
+
if (Array.isArray(operation.tags) && operation.tags.length) body.push(`**Tags:** ${operation.tags.filter((tag) => typeof tag === "string").map(escapeText).join(", ")}`, "");
|
|
153
|
+
const pathItem = resolveReference(document.paths[path], document);
|
|
154
|
+
const parameters = [...Array.isArray(pathItem.parameters) ? pathItem.parameters : [], ...Array.isArray(operation.parameters) ? operation.parameters : []];
|
|
155
|
+
if (parameters.length) {
|
|
156
|
+
body.push("## Parameters", "", "| Name | In | Required | Description |", "| --- | --- | --- | --- |");
|
|
157
|
+
for (const parameter of parameters) {
|
|
158
|
+
const item = resolveReference(parameter, document);
|
|
159
|
+
if (!record(item)) continue;
|
|
160
|
+
const schema = record(item.schema) ? ` (${schemaLabel(item.schema)})` : "";
|
|
161
|
+
body.push(`| ${tableCell(string(item.name) ?? "—")} | ${tableCell(string(item.in) ?? "—")} | ${item.required === true ? "Yes" : "No"} | ${tableCell(`${string(item.description) ?? ""}${schema}`)} |`);
|
|
162
|
+
}
|
|
163
|
+
body.push("");
|
|
164
|
+
}
|
|
165
|
+
if (operation.requestBody !== void 0) {
|
|
166
|
+
const request = resolveReference(operation.requestBody, document);
|
|
167
|
+
if (record(request)) {
|
|
168
|
+
body.push("## Request body", "");
|
|
169
|
+
if (string(request.description)) body.push(request.description, "");
|
|
170
|
+
body.push(`**Required:** ${request.required === true ? "Yes" : "No"}`, "");
|
|
171
|
+
renderContent(body, request.content);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (record(operation.responses)) {
|
|
175
|
+
body.push("## Responses", "");
|
|
176
|
+
for (const [status, value] of Object.entries(operation.responses)) {
|
|
177
|
+
const response = resolveReference(value, document);
|
|
178
|
+
if (!record(response)) continue;
|
|
179
|
+
body.push(`### ${escapeText(status)}${string(response.description) ? ` — ${escapeText(response.description)}` : ""}`, "");
|
|
180
|
+
renderContent(body, response.content);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
pages.push({
|
|
184
|
+
route,
|
|
185
|
+
sourcePath: `${source}#${route.slice(routeBase.length + 1)}.md`,
|
|
186
|
+
title: operationTitle,
|
|
187
|
+
...string(operation.description) ? { description: operation.description } : {},
|
|
188
|
+
body: body.join("\n")
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return pages;
|
|
192
|
+
}
|
|
193
|
+
function renderContent(lines, content) {
|
|
194
|
+
if (!record(content)) return;
|
|
195
|
+
for (const [mediaType, media] of Object.entries(content)) {
|
|
196
|
+
lines.push(`#### ${escapeText(mediaType)}`, "");
|
|
197
|
+
if (record(media) && media.schema !== void 0) lines.push(jsonBlock(media.schema), "");
|
|
198
|
+
if (record(media) && record(media.examples)) for (const [name, example] of Object.entries(media.examples)) {
|
|
199
|
+
const value = record(example) && "value" in example ? example.value : example;
|
|
200
|
+
lines.push(`**Example: ${escapeText(name)}**`, "", jsonBlock(value), "");
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function assertLocalReferences(value, document, source, seen = /* @__PURE__ */ new Set()) {
|
|
205
|
+
if (typeof value !== "object" || value === null || seen.has(value)) return;
|
|
206
|
+
seen.add(value);
|
|
207
|
+
if (Array.isArray(value)) for (const item of value) assertLocalReferences(item, document, source, seen);
|
|
208
|
+
else for (const [key, item] of Object.entries(value)) {
|
|
209
|
+
if (key === "$ref" && (typeof item !== "string" || !item.startsWith("#/"))) throw new Error(`OpenAPI source ${source} has an external or invalid $ref; bundle references into the document first.`);
|
|
210
|
+
if (key === "$ref" && typeof item === "string" && lookupReference(item, document) === void 0) throw new Error(`OpenAPI source ${source} has an unresolved reference: ${item}.`);
|
|
211
|
+
assertLocalReferences(item, document, source, seen);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function resolveReference(value, document) {
|
|
215
|
+
const visited = /* @__PURE__ */ new Set();
|
|
216
|
+
while (record(value) && typeof value.$ref === "string") {
|
|
217
|
+
const ref = value.$ref;
|
|
218
|
+
if (visited.has(ref)) throw new Error(`Circular OpenAPI reference: ${ref}.`);
|
|
219
|
+
visited.add(ref);
|
|
220
|
+
value = lookupReference(ref, document);
|
|
221
|
+
if (value === void 0) throw new Error(`Unresolved OpenAPI reference: ${ref}.`);
|
|
222
|
+
}
|
|
223
|
+
return value;
|
|
224
|
+
}
|
|
225
|
+
function lookupReference(ref, document) {
|
|
226
|
+
return ref.slice(2).split("/").reduce((current, part) => record(current) ? current[part.replace(/~1/g, "/").replace(/~0/g, "~")] : void 0, document);
|
|
227
|
+
}
|
|
228
|
+
function record(value) {
|
|
229
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
230
|
+
}
|
|
231
|
+
function string(value) {
|
|
232
|
+
return typeof value === "string" && value.length ? value : void 0;
|
|
233
|
+
}
|
|
234
|
+
function slugify(value) {
|
|
235
|
+
return value.normalize("NFKD").replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
236
|
+
}
|
|
237
|
+
function escapeText(value) {
|
|
238
|
+
return value.replace(/[\\`*_\[\]<>|]/g, "\\$&").replace(/\r?\n/g, " ");
|
|
239
|
+
}
|
|
240
|
+
function escapeCode(value) {
|
|
241
|
+
return value.replace(/`/g, "\\`").replace(/\r?\n/g, " ");
|
|
242
|
+
}
|
|
243
|
+
function tableCell(value) {
|
|
244
|
+
return escapeText(value);
|
|
245
|
+
}
|
|
246
|
+
function schemaLabel(schema) {
|
|
247
|
+
return typeof schema.$ref === "string" ? schema.$ref.split("/").at(-1) ?? "schema" : string(schema.type) ?? "schema";
|
|
248
|
+
}
|
|
249
|
+
function jsonBlock(value) {
|
|
250
|
+
const body = JSON.stringify(value, null, 2);
|
|
251
|
+
let longest = 0;
|
|
252
|
+
for (const [run] of body.matchAll(/`+/g)) longest = Math.max(longest, run.length);
|
|
253
|
+
const fence = "`".repeat(Math.max(3, longest + 1));
|
|
254
|
+
return `${fence}json\n${body}\n${fence}`;
|
|
255
|
+
}
|
|
256
|
+
//#endregion
|
|
71
257
|
//#region src/npm/index.ts
|
|
72
258
|
const DEFAULT_REGISTRY = "https://registry.npmjs.org/";
|
|
73
259
|
const LOCK_FILE = "cookbook.lock.json";
|
|
@@ -362,8 +548,10 @@ async function createDocsGraph(options = {}) {
|
|
|
362
548
|
continue;
|
|
363
549
|
}
|
|
364
550
|
routeMap.set(entry.route, entry);
|
|
365
|
-
|
|
366
|
-
|
|
551
|
+
if (source.generatedBody === void 0) {
|
|
552
|
+
const absolute = normalizeFs(entry.absolutePath);
|
|
553
|
+
absoluteMap.set(absolute, [...absoluteMap.get(absolute) ?? [], entry]);
|
|
554
|
+
}
|
|
367
555
|
sourceMap.set(entry.sourcePath, [...sourceMap.get(entry.sourcePath) ?? [], entry]);
|
|
368
556
|
sourceMap.set(entry.id, [entry]);
|
|
369
557
|
if (source.repository) repositoryMap.set(entry.id, source.repository);
|
|
@@ -388,6 +576,11 @@ async function createDocsGraph(options = {}) {
|
|
|
388
576
|
}], routeMap, diagnostics);
|
|
389
577
|
validateNavigation(tab.items ?? [], routeMap, diagnostics);
|
|
390
578
|
}
|
|
579
|
+
for (const version of config.site.versions ?? []) if (!routeMap.has(version.routeBase)) diagnostics.push({
|
|
580
|
+
code: "DOCS_VERSION_ROOT_MISSING",
|
|
581
|
+
severity: "error",
|
|
582
|
+
message: `Version ${version.label} needs a page at ${version.routeBase}.`
|
|
583
|
+
});
|
|
391
584
|
entries.sort((left, right) => left.route.localeCompare(right.route));
|
|
392
585
|
return {
|
|
393
586
|
redirects,
|
|
@@ -469,14 +662,14 @@ async function collectSources(root, config, lock, diagnostics) {
|
|
|
469
662
|
message: `Source did not match any files: ${sourceLabel(declaration)}.`
|
|
470
663
|
});
|
|
471
664
|
for (const source of found) {
|
|
472
|
-
const identity = `${sourceId}:${normalizeFs(source.absolutePath)}`;
|
|
665
|
+
const identity = `${sourceId}:${normalizeFs(source.absolutePath)}:${source.generatedBody === void 0 ? "" : source.route}`;
|
|
473
666
|
if (identities.has(identity)) continue;
|
|
474
667
|
identities.add(identity);
|
|
475
668
|
results.push(source);
|
|
476
669
|
}
|
|
477
670
|
} catch (error) {
|
|
478
671
|
diagnostics.push({
|
|
479
|
-
code: error instanceof OutsideRootError ? "DOCS_SOURCE_OUTSIDE_ROOT" : "DOCS_SOURCE_NOT_FOUND",
|
|
672
|
+
code: error instanceof OutsideRootError ? "DOCS_SOURCE_OUTSIDE_ROOT" : "openapi" in declaration ? "DOCS_OPENAPI_INVALID" : "DOCS_SOURCE_NOT_FOUND",
|
|
480
673
|
severity: "error",
|
|
481
674
|
message: errorMessage(error)
|
|
482
675
|
});
|
|
@@ -497,6 +690,26 @@ async function conventionSources(root) {
|
|
|
497
690
|
return sources;
|
|
498
691
|
}
|
|
499
692
|
async function collectDeclaration(root, declaration, config, lock, sourceId) {
|
|
693
|
+
if ("openapi" in declaration) {
|
|
694
|
+
const sourceRoot = resolve(root, declaration.root ?? ".");
|
|
695
|
+
const absolutePath = resolveSourcePath(sourceRoot, declaration.openapi, config.content.allowOutsideRoot);
|
|
696
|
+
if (!await isFile(absolutePath)) return [];
|
|
697
|
+
if ((await stat(absolutePath)).size > config.build.maxAssetBytes) throw new Error(`OpenAPI source ${declaration.openapi} exceeds ${config.build.maxAssetBytes} bytes.`);
|
|
698
|
+
const routeBase = normalizeRoute(declaration.routeBase ?? "/api");
|
|
699
|
+
return openApiPages(toPosix(relative(sourceRoot, absolutePath)), routeBase, await readFile(absolutePath, "utf8")).map((page) => ({
|
|
700
|
+
sourceId,
|
|
701
|
+
routeBase,
|
|
702
|
+
absolutePath,
|
|
703
|
+
sourcePath: page.sourcePath,
|
|
704
|
+
sourceRoot,
|
|
705
|
+
editPath: toPosix(relative(inside(root, absolutePath) ? root : sourceRoot, absolutePath)),
|
|
706
|
+
route: page.route,
|
|
707
|
+
title: page.title,
|
|
708
|
+
...page.description ? { description: page.description } : {},
|
|
709
|
+
generatedBody: page.body,
|
|
710
|
+
trust: "markdown"
|
|
711
|
+
}));
|
|
712
|
+
}
|
|
500
713
|
if ("package" in declaration) {
|
|
501
714
|
const packageLock = lockForSource(lock, declaration.package);
|
|
502
715
|
if (declaration.registry && packageLock.registry !== declaration.registry) throw new Error(`Registry changed for ${declaration.package}. Run "cookbook update".`);
|
|
@@ -587,7 +800,7 @@ async function readEntry(source, config, diagnostics) {
|
|
|
587
800
|
});
|
|
588
801
|
return;
|
|
589
802
|
}
|
|
590
|
-
const original = await readFile(source.absolutePath, "utf8");
|
|
803
|
+
const original = source.generatedBody ?? await readFile(source.absolutePath, "utf8");
|
|
591
804
|
let parsedMatter;
|
|
592
805
|
try {
|
|
593
806
|
parsedMatter = parseFrontmatter(original);
|
|
@@ -1110,6 +1323,7 @@ function safeDecode(value) {
|
|
|
1110
1323
|
function sourceLabel(source) {
|
|
1111
1324
|
if ("file" in source) return source.file;
|
|
1112
1325
|
if ("glob" in source) return Array.isArray(source.glob) ? source.glob.join(", ") : source.glob;
|
|
1326
|
+
if ("openapi" in source) return source.openapi;
|
|
1113
1327
|
return source.package;
|
|
1114
1328
|
}
|
|
1115
1329
|
function normalizeFs(path) {
|
|
@@ -1337,4 +1551,4 @@ function toLoaderEntry(entry) {
|
|
|
1337
1551
|
//#endregion
|
|
1338
1552
|
export { resolvePackageLock as _, validateDocs as a, routeForPath as c, discoverPackage as d, lockForSource as f, reconcileDocsLock as g, readDocsLock as h, formatDiagnostics as i, assertSafePackagePath as l, packageNameFromSpecifier as m, DocsValidationError as n, createDocsGraph as o, materializePackage as p, assertValidDocs as r, normalizeRoute as s, createDocsLoader as t, defaultLock as u, validateLock as v, writeDocsLock as y };
|
|
1339
1553
|
|
|
1340
|
-
//# sourceMappingURL=content-
|
|
1554
|
+
//# sourceMappingURL=content-CrWnRfN7.js.map
|