@eqtylab/docs 0.3.0

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.
Files changed (94) hide show
  1. package/README.md +201 -0
  2. package/dist/chunk-55J6XMHW.js +3 -0
  3. package/dist/chunk-55J6XMHW.js.map +1 -0
  4. package/dist/chunk-ATIOPYKE.js +102 -0
  5. package/dist/chunk-ATIOPYKE.js.map +1 -0
  6. package/dist/chunk-GSSSQTEV.js +51 -0
  7. package/dist/chunk-GSSSQTEV.js.map +1 -0
  8. package/dist/chunk-IWKZQ4CW.js +68 -0
  9. package/dist/chunk-IWKZQ4CW.js.map +1 -0
  10. package/dist/chunk-K7PJRTK3.js +113 -0
  11. package/dist/chunk-K7PJRTK3.js.map +1 -0
  12. package/dist/chunk-VJN3HXKM.js +59 -0
  13. package/dist/chunk-VJN3HXKM.js.map +1 -0
  14. package/dist/chunk-ZZ45WAVR.js +20 -0
  15. package/dist/chunk-ZZ45WAVR.js.map +1 -0
  16. package/dist/config.d.ts +78 -0
  17. package/dist/config.js +3 -0
  18. package/dist/config.js.map +1 -0
  19. package/dist/dev.d.ts +6 -0
  20. package/dist/dev.js +84 -0
  21. package/dist/dev.js.map +1 -0
  22. package/dist/env.d.ts +17 -0
  23. package/dist/env.js +3 -0
  24. package/dist/env.js.map +1 -0
  25. package/dist/index.d.ts +12 -0
  26. package/dist/index.js +421 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/internal/assert-mdx-only.d.ts +1 -0
  29. package/dist/internal/microlighter-grammars.d.ts +3 -0
  30. package/dist/internal/pagefind.d.ts +2 -0
  31. package/dist/internal/rehype-base-url.d.ts +5 -0
  32. package/dist/internal/rehype-base-url.js +3 -0
  33. package/dist/internal/rehype-base-url.js.map +1 -0
  34. package/dist/internal/rehype-code-fence.d.ts +1 -0
  35. package/dist/internal/rehype-prose-scope.d.ts +1 -0
  36. package/dist/internal/rehype-table-columns.d.ts +1 -0
  37. package/dist/internal/scan-consumer-pages.d.ts +7 -0
  38. package/dist/internal/virtual-config.d.ts +3 -0
  39. package/dist/loaders.d.ts +20 -0
  40. package/dist/loaders.js +85 -0
  41. package/dist/loaders.js.map +1 -0
  42. package/dist/nav.d.ts +57 -0
  43. package/dist/nav.js +222 -0
  44. package/dist/nav.js.map +1 -0
  45. package/dist/paths.d.ts +28 -0
  46. package/dist/paths.js +3 -0
  47. package/dist/paths.js.map +1 -0
  48. package/dist/runtime/chrome/GlobalSearch.module.css +26 -0
  49. package/dist/runtime/chrome/GlobalSearch.tsx +422 -0
  50. package/dist/runtime/chrome/Header.astro +105 -0
  51. package/dist/runtime/chrome/LinkIcon.astro +35 -0
  52. package/dist/runtime/chrome/NavDrawer.astro +60 -0
  53. package/dist/runtime/chrome/NavTree.astro +112 -0
  54. package/dist/runtime/chrome/NotFoundBody.tsx +12 -0
  55. package/dist/runtime/chrome/PageFooter.astro +80 -0
  56. package/dist/runtime/chrome/Prose.astro +169 -0
  57. package/dist/runtime/chrome/Sidebar.astro +21 -0
  58. package/dist/runtime/chrome/TableOfContents.astro +86 -0
  59. package/dist/runtime/chrome/ThemeToggle.tsx +85 -0
  60. package/dist/runtime/chrome/TocElbow.astro +30 -0
  61. package/dist/runtime/chrome/TocList.astro +43 -0
  62. package/dist/runtime/components/AlertBridge.astro +16 -0
  63. package/dist/runtime/components/CodeFence.astro +38 -0
  64. package/dist/runtime/components/CodeFenceBridge.astro +20 -0
  65. package/dist/runtime/components/Link.astro +21 -0
  66. package/dist/runtime/components/TableBridge.astro +18 -0
  67. package/dist/runtime/components/index.ts +2 -0
  68. package/dist/runtime/layouts/DocsPage.astro +50 -0
  69. package/dist/runtime/layouts/DocsShell.astro +92 -0
  70. package/dist/runtime/lib/mdx-components.ts +43 -0
  71. package/dist/runtime/lib/nav-data.ts +74 -0
  72. package/dist/runtime/lib/summary.ts +57 -0
  73. package/dist/runtime/lib/theme.ts +84 -0
  74. package/dist/runtime/routes/docs-md.ts +33 -0
  75. package/dist/runtime/routes/docs.astro +92 -0
  76. package/dist/runtime/routes/llms-txt.ts +38 -0
  77. package/dist/runtime/routes/not-found.astro +16 -0
  78. package/dist/runtime/scripts/eq-copy.ts +27 -0
  79. package/dist/runtime/scripts/eq-highlight.ts +24 -0
  80. package/dist/runtime/scripts/eq-nav-drawer.ts +31 -0
  81. package/dist/runtime/scripts/eq-nav-group.ts +52 -0
  82. package/dist/runtime/scripts/eq-toc.ts +166 -0
  83. package/dist/runtime/styles/chrome.css +30 -0
  84. package/dist/runtime/styles/docs.css +21 -0
  85. package/dist/runtime/styles/prose.css +102 -0
  86. package/dist/runtime/styles/theme.css +2 -0
  87. package/dist/runtime/styles/utilities.css +38 -0
  88. package/dist/schema.d.ts +110 -0
  89. package/dist/schema.js +3 -0
  90. package/dist/schema.js.map +1 -0
  91. package/dist/types.d.ts +60 -0
  92. package/dist/types.js +3 -0
  93. package/dist/types.js.map +1 -0
  94. package/package.json +127 -0
package/README.md ADDED
@@ -0,0 +1,201 @@
1
+ # @eqtylab/docs
2
+
3
+ An Astro documentation framework built on the [Equality](https://equality.eqtylab.io) design system.
4
+ One package to build every EQTY docs site — component library, product docs, and API reference —
5
+ with folder-driven navigation and versioned deploys.
6
+
7
+ ## Quick start
8
+
9
+ ```bash
10
+ pnpm add @eqtylab/docs @eqtylab/equality astro react react-dom
11
+ ```
12
+
13
+ ```js
14
+ // astro.config.mjs
15
+ import docs from '@eqtylab/docs';
16
+ import { defineConfig } from 'astro/config';
17
+
18
+ export default defineConfig({
19
+ site: 'https://docs.example.com',
20
+ base: process.env.DOCS_BASE ?? '/',
21
+ integrations: [docs({ title: 'My Docs' })],
22
+ });
23
+ ```
24
+
25
+ ```ts
26
+ // src/content.config.ts — required; Astro cannot inject collections
27
+ import { docsCollections } from '@eqtylab/docs/loaders';
28
+
29
+ export const collections = docsCollections();
30
+ ```
31
+
32
+ Then write MDX under `src/content/docs/`. That's the whole setup: the integration injects the
33
+ page routes, a Markdown twin per page, `/llms.txt`, and a 404. Search is built separately, at the
34
+ end of `astro build`; see [Search needs a build](#search-needs-a-build).
35
+
36
+ Content is **MDX-only**. Component overrides apply exclusively to MDX, so a `.md` page would
37
+ render its tables, code fences and callouts differently from every other page. A `.md` file in
38
+ the content tree fails the build rather than going silently missing — renaming it is usually the
39
+ only change needed, since MDX is a superset of Markdown.
40
+
41
+ ## Navigation comes from folders
42
+
43
+ Ordering lives in one optional `_group.yaml` per directory — there is deliberately **no
44
+ `sidebar.order` frontmatter** to hand-maintain.
45
+
46
+ ```yaml
47
+ # src/content/docs/getting-started/_group.yaml
48
+ label: Getting Started
49
+ order: [installation, usage, themes] # filesystem names, not titles
50
+ collapsed: false
51
+ ```
52
+
53
+ - Children listed in `order` come first, in that order.
54
+ - Everything unlisted appends alphabetically by sidebar label (`sort: filename` or `manual` to change that).
55
+ - `index.mdx` in a folder becomes that folder's own landing page.
56
+ - A typo in `order` produces a build **warning naming the file and the token** rather than silently
57
+ reordering, and the schema is `.strict()` so an unknown key fails the build.
58
+
59
+ ## Two conventions worth knowing
60
+
61
+ **No Tailwind utility classes in this package's markup.** All styling goes through `@apply` in a
62
+ co-located `*.module.css` with a `@reference` header, mirroring `packages/ui`. This is not a style
63
+ preference: Tailwind v4's source detection skips `node_modules`, so utilities written literally in
64
+ shipped markup would silently produce nothing in a consumer's build. `@apply` has no such
65
+ dependency. `pnpm run check:no-utilities` enforces it and runs as part of `build`.
66
+
67
+ **Route-level MDX components override page-level ones.** `@astrojs/mdx` builds the map as
68
+ `{ Fragment, ...fileComponents, ...props.components }`, so the route's `<Content components={…} />`
69
+ wins over a page's own `export const components`. The route map is therefore kept to element
70
+ overrides (`a`, `pre`); everything richer is an explicit import from `@eqtylab/docs/components`, so
71
+ per-page overrides stay possible.
72
+
73
+ ## Code blocks
74
+
75
+ Fenced code renders through Equality's `CodeBlock`, server-side, so docs match product surfaces with
76
+ **no client React**. The highlighter paints through the CSS Custom Highlight API rather than by
77
+ wrapping tokens in markup, so the server-rendered DOM is the final DOM, the palette resolves through
78
+ the normal cascade, and a static render gets correct light _and_ dark colours for free.
79
+
80
+ Two small scripts do what would otherwise need hydration: `runtime/scripts/eq-copy.ts` for the copy
81
+ button, and `runtime/scripts/eq-highlight.ts` to start the highlight pass. Fence tags are passed
82
+ through as authored — the highlighter owns language resolution, including its alias table (`ts`,
83
+ `jsx`, `sh`, `yml` and the rest), and renders plain rather than guessing at a tag it does not know.
84
+
85
+ Set `code: { highlighter: 'shiki' }` to use Astro's Shiki instead: wider language coverage, line
86
+ highlighting and `meta` support, at the cost of a different look from the product.
87
+
88
+ ## Everything renders through Equality
89
+
90
+ The framework contributes layout, navigation and prose typography. Everything that renders
91
+ _content_ is an Equality component, server-rendered with no client React, so docs and
92
+ product surfaces cannot drift:
93
+
94
+ | Authored as | Renders as |
95
+ | --------------- | --------------------------------------------------------------------------------------- |
96
+ | Code fences | `CodeBlock` |
97
+ | Markdown tables | `TableContainer` / `TableHeader` / `TableBody` / `TableRow` / `TableHead` / `TableCell` |
98
+ | `<Alert>` | `Alert`, as an `aside` |
99
+ | Links | base-aware `a` override |
100
+
101
+ **Authors write Equality's own components, with no imports.** The route-level component map
102
+ supplies named components as well as element overrides, so this works in any page with
103
+ nothing at the top of the file — there is no docs-specific component vocabulary to learn:
104
+
105
+ ```mdx
106
+ ---
107
+ title: My page
108
+ ---
109
+
110
+ <Alert variant="warning" title="Heads up">
111
+ Body content, with real block elements.
112
+ </Alert>
113
+ ```
114
+
115
+ The only thing the framework adds is a default: `as="aside"`. Alert's default `div` carries
116
+ `role="alert"`, an assertive live region — right for a message responding to something the
117
+ user did, wrong for a standing note in a document. Importing `Alert` from
118
+ `@eqtylab/equality` explicitly opts out and gives you the raw component, because a
119
+ file-level import wins over the component map.
120
+
121
+ One detail worth knowing: **tables need a column count.** `TableContainer` is a CSS grid
122
+ whose parts all use `subgrid`, so it needs an explicit track list or the table collapses
123
+ to one column. Markdown has no syntax for that, so `rehypeTableColumns` derives the count
124
+ from the first row at build time.
125
+
126
+ This is also why content is MDX-only — these overrides are the mechanism, and Astro's
127
+ plain-Markdown pipeline has no component substitution at all.
128
+
129
+ ## Search needs a build
130
+
131
+ Search is full-text, over the built HTML, via [Pagefind](https://pagefind.app). The integration
132
+ runs it in `astro:build:done` and writes the index to `dist/pagefind/`.
133
+
134
+ **One `astro build` makes search work in `astro dev` too.** Dev serves `dist/pagefind/` off disk,
135
+ so results describe the last build; rebuild while dev runs and the next search picks it up. Until
136
+ that first build the palette says search needs one.
137
+
138
+ What gets indexed is set by the markup, not by config:
139
+
140
+ | Attribute | Where | Effect |
141
+ | ---------------------- | -------------------------------- | ------------------------------------- |
142
+ | `data-pagefind-body` | the `<article>` | Bounds the index to page content |
143
+ | `data-pagefind-ignore` | header, sidebar, TOC, action row | Keeps chrome out of every result |
144
+ | `data-pagefind-meta` | the `<h1>` and the `<article>` | Carries `title` and the `group` label |
145
+
146
+ The `group` value is the section's `label` from `_group.yaml`, so search headings and the sidebar
147
+ cannot drift apart.
148
+
149
+ The control itself is a command palette in the header, opened by click, `⌘K` or `/`. Fill the
150
+ header's `search` slot to replace it, or set `search.provider: 'none'` to drop it entirely.
151
+
152
+ ## Versioned deploys
153
+
154
+ `base` must be literal in Astro's config at build time, so it is threaded by environment variable:
155
+
156
+ | Variable | Meaning |
157
+ | ------------------- | -------------------------------------------------------------------------- |
158
+ | `DOCS_BASE` | Astro's `base` — `/`, `/v3.1/`, `/repo/v3.1/` |
159
+ | `DOCS_VERSION_ROOT` | Directory holding all version directories (tracked separately from `base`) |
160
+ | `DOCS_VERSION` | This build's version id, e.g. `3.1` |
161
+ | `DOCS_IS_LATEST` | `true` for the canonical build served at root |
162
+
163
+ Every internal URL flows through `@eqtylab/docs/paths`, and authored markdown links are rewritten by
164
+ a rehype plugin — Astro does not do this itself, so without it every root-relative link in content
165
+ would 404 in a sub-path build.
166
+
167
+ ## Development
168
+
169
+ ```bash
170
+ pnpm build # guard + node bundle + runtime copy + declarations
171
+ pnpm test # nav ordering, prev/next, breadcrumbs, TOC
172
+ ```
173
+
174
+ `src/*.ts` is bundled for Node (it is loaded when Astro reads your config). `src/runtime/**` ships
175
+ as **source** and is compiled by the consumer's Astro — `.astro` files cannot be bundled. The copy is
176
+ verbatim, which is what keeps dev source-linking byte-equivalent to the published package.
177
+
178
+ ### The dev surface
179
+
180
+ `packages/demo` — the Equality docs site — is the first-class consumer, so the framework is
181
+ developed against the same site that ships. Run `pnpm dev` from the repo root: this package's
182
+ `dev` keeps `dist/runtime` in sync while the demo serves on port 4321.
183
+
184
+ The sync is what makes edits to `src/runtime/**` hot-reload. Astro resolves injected route
185
+ entrypoints through the real exports map, so `dist/runtime` — not `src/runtime` — is what Vite
186
+ actually serves. Changes to `src/*.ts` are a different matter: they are bundled by tsup and read
187
+ by Astro at config time, so they need `pnpm build:node` and a dev-server restart.
188
+
189
+ To exercise a versioned sub-path build:
190
+
191
+ ```bash
192
+ DOCS_BASE=/v0.0/ pnpm --filter demo build
193
+ ```
194
+
195
+ Then confirm nothing 404s when `packages/demo/dist` is served at `/v0.0/`.
196
+
197
+ ### Fixtures
198
+
199
+ `tests/fixtures/basic` is a separate, deliberately minimal consumer used for assertions — it
200
+ contains a misspelled `_group.yaml` key on purpose, which is why it is kept apart from the demo
201
+ rather than doubling as the dev surface.
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=chunk-55J6XMHW.js.map
3
+ //# sourceMappingURL=chunk-55J6XMHW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-55J6XMHW.js"}
@@ -0,0 +1,102 @@
1
+ import { z } from 'astro/zod';
2
+
3
+ // src/config.ts
4
+ var headerLink = z.object({
5
+ label: z.string(),
6
+ href: z.string(),
7
+ /**
8
+ * A Lucide name like `BookOpen`, or a path to an SVG in `public/` like
9
+ * `/github.svg`. An SVG must be white: light mode inverts it.
10
+ */
11
+ icon: z.string().optional(),
12
+ external: z.boolean().optional()
13
+ });
14
+ var docsConfigSchema = z.object({
15
+ /** Site name, shown in the header and used as the `<title>` suffix. */
16
+ title: z.string(),
17
+ description: z.string().optional(),
18
+ /** Path to a favicon, relative to `public/`. Base is applied automatically. */
19
+ favicon: z.string().default("/favicon.svg"),
20
+ /**
21
+ * The header mark. Without one the header falls back to `title` as text. Either
22
+ * way a constant "Docs" label follows it, and `title` heads the sidebar.
23
+ */
24
+ logo: z.object({
25
+ src: z.string(),
26
+ /** Name the company: the brand link reads as this plus "Docs". */
27
+ alt: z.string().default("")
28
+ }).optional(),
29
+ /** Content directory, relative to `src/`. */
30
+ contentDir: z.string().default("content/docs"),
31
+ /** Mount docs under a sub-path, e.g. 'docs' for /docs/*. Empty means the site root. */
32
+ pathPrefix: z.string().default(""),
33
+ sidebar: z.object({
34
+ /** Default collapse state for groups with no explicit `collapsed`. */
35
+ collapsed: z.boolean().default(false),
36
+ /** Default append order for children absent from a group's `order`. */
37
+ sort: z.enum(["alpha", "filename", "manual"]).default("alpha"),
38
+ /** Extra top-level nodes, appended after folder-derived ones. */
39
+ extra: z.array(z.any()).default([])
40
+ }).prefault({}),
41
+ header: z.object({
42
+ links: z.array(headerLink).default([]),
43
+ showThemeToggle: z.boolean().default(true)
44
+ }).prefault({}),
45
+ footer: z.object({
46
+ /** Base URL for "Edit this page"; the content path is appended. */
47
+ editUrl: z.string().optional(),
48
+ showPrevNext: z.boolean().default(true),
49
+ text: z.string().optional()
50
+ }).prefault({}),
51
+ tableOfContents: z.union([
52
+ z.object({
53
+ minLevel: z.number().int().min(1).max(6).default(2),
54
+ maxLevel: z.number().int().min(1).max(6).default(3)
55
+ }),
56
+ z.literal(false)
57
+ ]).prefault({}),
58
+ code: z.object({
59
+ /** 'codeblock' renders fences through Equality's CodeBlock; 'shiki' uses Astro's Shiki. */
60
+ highlighter: z.enum(["codeblock", "shiki"]).default("codeblock"),
61
+ /** Shiki themes; only consulted when `highlighter` is 'shiki'. */
62
+ themes: z.object({ light: z.string(), dark: z.string() }).default({ light: "github-light", dark: "github-dark" }),
63
+ wrap: z.boolean().default(false),
64
+ langs: z.array(z.string()).default([])
65
+ }).prefault({}),
66
+ search: z.object({
67
+ /** 'pagefind' indexes the built HTML. Dev serves that index, so it needs one build. */
68
+ provider: z.enum(["pagefind", "none"]).default("pagefind")
69
+ }).prefault({}),
70
+ routing: z.object({
71
+ /** Inject the catch-all docs route. Disable to own routing entirely. */
72
+ injectPages: z.boolean().default(true),
73
+ /** Emit a `.md` twin per page plus `/llms.txt`. */
74
+ markdownTwins: z.boolean().default(true),
75
+ notFound: z.boolean().default(true)
76
+ }).prefault({}),
77
+ theme: z.object({
78
+ /** 'global' puts tokens on <html>; 'scoped' wraps in a ThemeProvider. */
79
+ mode: z.enum(["global", "scoped"]).default("global"),
80
+ /** Persist the reader's choice to localStorage. */
81
+ persist: z.boolean().default(true)
82
+ }).prefault({}),
83
+ /** Install @astrojs/mdx, @astrojs/react and Tailwind when absent. */
84
+ autoIntegrations: z.boolean().default(true),
85
+ /** Versioning. Left permissive here; the versioning workstream owns the shape. */
86
+ versions: z.any().optional(),
87
+ /** Generated-section plugins (OpenAPI reference, changelogs, ...). */
88
+ plugins: z.array(z.any()).default([])
89
+ });
90
+ function resolveConfig(user) {
91
+ const result = docsConfigSchema.safeParse(user);
92
+ if (!result.success) {
93
+ const issues = result.error.issues.map((i) => ` - ${i.path.join(".") || "(root)"}: ${i.message}`).join("\n");
94
+ throw new Error(`[@eqtylab/docs] Invalid configuration:
95
+ ${issues}`);
96
+ }
97
+ return result.data;
98
+ }
99
+
100
+ export { docsConfigSchema, resolveConfig };
101
+ //# sourceMappingURL=chunk-ATIOPYKE.js.map
102
+ //# sourceMappingURL=chunk-ATIOPYKE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts"],"names":[],"mappings":"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","file":"chunk-ATIOPYKE.js","sourcesContent":["/** Integration options: the whole consumer-facing configuration surface. */\nimport { z } from 'astro/zod';\n\nconst headerLink = z.object({\n label: z.string(),\n href: z.string(),\n /**\n * A Lucide name like `BookOpen`, or a path to an SVG in `public/` like\n * `/github.svg`. An SVG must be white: light mode inverts it.\n */\n icon: z.string().optional(),\n external: z.boolean().optional(),\n});\n\nexport const docsConfigSchema = z.object({\n /** Site name, shown in the header and used as the `<title>` suffix. */\n title: z.string(),\n description: z.string().optional(),\n /** Path to a favicon, relative to `public/`. Base is applied automatically. */\n favicon: z.string().default('/favicon.svg'),\n\n /**\n * The header mark. Without one the header falls back to `title` as text. Either\n * way a constant \"Docs\" label follows it, and `title` heads the sidebar.\n */\n logo: z\n .object({\n src: z.string(),\n /** Name the company: the brand link reads as this plus \"Docs\". */\n alt: z.string().default(''),\n })\n .optional(),\n\n /** Content directory, relative to `src/`. */\n contentDir: z.string().default('content/docs'),\n\n /** Mount docs under a sub-path, e.g. 'docs' for /docs/*. Empty means the site root. */\n pathPrefix: z.string().default(''),\n\n sidebar: z\n .object({\n /** Default collapse state for groups with no explicit `collapsed`. */\n collapsed: z.boolean().default(false),\n /** Default append order for children absent from a group's `order`. */\n sort: z.enum(['alpha', 'filename', 'manual']).default('alpha'),\n /** Extra top-level nodes, appended after folder-derived ones. */\n extra: z.array(z.any()).default([]),\n })\n .prefault({}),\n\n header: z\n .object({\n links: z.array(headerLink).default([]),\n showThemeToggle: z.boolean().default(true),\n })\n .prefault({}),\n\n footer: z\n .object({\n /** Base URL for \"Edit this page\"; the content path is appended. */\n editUrl: z.string().optional(),\n showPrevNext: z.boolean().default(true),\n text: z.string().optional(),\n })\n .prefault({}),\n\n tableOfContents: z\n .union([\n z.object({\n minLevel: z.number().int().min(1).max(6).default(2),\n maxLevel: z.number().int().min(1).max(6).default(3),\n }),\n z.literal(false),\n ])\n .prefault({}),\n\n code: z\n .object({\n /** 'codeblock' renders fences through Equality's CodeBlock; 'shiki' uses Astro's Shiki. */\n highlighter: z.enum(['codeblock', 'shiki']).default('codeblock'),\n /** Shiki themes; only consulted when `highlighter` is 'shiki'. */\n themes: z\n .object({ light: z.string(), dark: z.string() })\n .default({ light: 'github-light', dark: 'github-dark' }),\n wrap: z.boolean().default(false),\n langs: z.array(z.string()).default([]),\n })\n .prefault({}),\n\n search: z\n .object({\n /** 'pagefind' indexes the built HTML. Dev serves that index, so it needs one build. */\n provider: z.enum(['pagefind', 'none']).default('pagefind'),\n })\n .prefault({}),\n\n routing: z\n .object({\n /** Inject the catch-all docs route. Disable to own routing entirely. */\n injectPages: z.boolean().default(true),\n /** Emit a `.md` twin per page plus `/llms.txt`. */\n markdownTwins: z.boolean().default(true),\n notFound: z.boolean().default(true),\n })\n .prefault({}),\n\n theme: z\n .object({\n /** 'global' puts tokens on <html>; 'scoped' wraps in a ThemeProvider. */\n mode: z.enum(['global', 'scoped']).default('global'),\n /** Persist the reader's choice to localStorage. */\n persist: z.boolean().default(true),\n })\n .prefault({}),\n\n /** Install @astrojs/mdx, @astrojs/react and Tailwind when absent. */\n autoIntegrations: z.boolean().default(true),\n\n /** Versioning. Left permissive here; the versioning workstream owns the shape. */\n versions: z.any().optional(),\n\n /** Generated-section plugins (OpenAPI reference, changelogs, ...). */\n plugins: z.array(z.any()).default([]),\n});\n\nexport type DocsUserConfig = z.input<typeof docsConfigSchema>;\nexport type DocsConfig = z.output<typeof docsConfigSchema>;\n\nexport function resolveConfig(user: DocsUserConfig): DocsConfig {\n const result = docsConfigSchema.safeParse(user);\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => ` - ${i.path.join('.') || '(root)'}: ${i.message}`)\n .join('\\n');\n throw new Error(`[@eqtylab/docs] Invalid configuration:\\n${issues}`);\n }\n return result.data;\n}\n"]}
@@ -0,0 +1,51 @@
1
+ import { visit } from 'unist-util-visit';
2
+
3
+ // src/internal/rehype-base-url.ts
4
+ var URL_ATTRS = ["href", "src", "poster"];
5
+ var SRCSET_ATTRS = ["srcSet", "srcset"];
6
+ function shouldRewrite(value, base) {
7
+ if (!value.startsWith("/")) return false;
8
+ if (value.startsWith("//")) return false;
9
+ if (base !== "/" && (value === base.replace(/\/$/, "") || value.startsWith(base))) return false;
10
+ return true;
11
+ }
12
+ function rewrite(value, base) {
13
+ return shouldRewrite(value, base) ? base.replace(/\/$/, "") + value : value;
14
+ }
15
+ function rewriteSrcset(value, base) {
16
+ return value.split(",").map((candidate) => {
17
+ const trimmed = candidate.trim();
18
+ if (!trimmed) return candidate;
19
+ const [url, ...descriptors] = trimmed.split(/\s+/);
20
+ return [rewrite(url, base), ...descriptors].join(" ");
21
+ }).join(", ");
22
+ }
23
+ function rehypeBaseUrl(options) {
24
+ const base = options.base || "/";
25
+ return function transformer(tree) {
26
+ if (base === "/") return;
27
+ visit(tree, "element", (node) => {
28
+ const props = node.properties;
29
+ if (!props) return;
30
+ for (const attr of URL_ATTRS) {
31
+ const value = props[attr];
32
+ if (typeof value === "string") props[attr] = rewrite(value, base);
33
+ }
34
+ for (const attr of SRCSET_ATTRS) {
35
+ const value = props[attr];
36
+ if (typeof value === "string") props[attr] = rewriteSrcset(value, base);
37
+ }
38
+ });
39
+ };
40
+ }
41
+ function rewriteHtmlBase(html, base) {
42
+ if (!base || base === "/") return html;
43
+ return html.replace(
44
+ /\b(href|src)=("|')(\/(?!\/)[^"']*)\2/g,
45
+ (_match, attr, quote, url) => `${attr}=${quote}${rewrite(url, base)}${quote}`
46
+ );
47
+ }
48
+
49
+ export { rehypeBaseUrl, rewriteHtmlBase };
50
+ //# sourceMappingURL=chunk-GSSSQTEV.js.map
51
+ //# sourceMappingURL=chunk-GSSSQTEV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internal/rehype-base-url.ts"],"names":[],"mappings":";;;AAQA,IAAM,SAAA,GAAY,CAAC,MAAA,EAAQ,KAAA,EAAO,QAAQ,CAAA;AAC1C,IAAM,YAAA,GAAe,CAAC,QAAA,EAAU,QAAQ,CAAA;AAExC,SAAS,aAAA,CAAc,OAAe,IAAA,EAAuB;AAC3D,EAAA,IAAI,CAAC,KAAA,CAAM,UAAA,CAAW,GAAG,GAAG,OAAO,KAAA;AACnC,EAAA,IAAI,KAAA,CAAM,UAAA,CAAW,IAAI,CAAA,EAAG,OAAO,KAAA;AACnC,EAAA,IAAI,IAAA,KAAS,GAAA,KAAQ,KAAA,KAAU,IAAA,CAAK,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA,IAAK,KAAA,CAAM,UAAA,CAAW,IAAI,CAAA,CAAA,EAAI,OAAO,KAAA;AAC1F,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,OAAA,CAAQ,OAAe,IAAA,EAAsB;AACpD,EAAA,OAAO,aAAA,CAAc,OAAO,IAAI,CAAA,GAAI,KAAK,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA,GAAI,KAAA,GAAQ,KAAA;AACxE;AAEA,SAAS,aAAA,CAAc,OAAe,IAAA,EAAsB;AAC1D,EAAA,OAAO,MACJ,KAAA,CAAM,GAAG,CAAA,CACT,GAAA,CAAI,CAAC,SAAA,KAAc;AAClB,IAAA,MAAM,OAAA,GAAU,UAAU,IAAA,EAAK;AAC/B,IAAA,IAAI,CAAC,SAAS,OAAO,SAAA;AACrB,IAAA,MAAM,CAAC,GAAA,EAAK,GAAG,WAAW,CAAA,GAAI,OAAA,CAAQ,MAAM,KAAK,CAAA;AACjD,IAAA,OAAO,CAAC,QAAQ,GAAA,EAAe,IAAI,GAAG,GAAG,WAAW,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAAA,EAChE,CAAC,CAAA,CACA,IAAA,CAAK,IAAI,CAAA;AACd;AAEO,SAAS,cAAc,OAAA,EAA2B;AACvD,EAAA,MAAM,IAAA,GAAO,QAAQ,IAAA,IAAQ,GAAA;AAE7B,EAAA,OAAO,SAAS,YAAY,IAAA,EAAe;AACzC,IAAA,IAAI,SAAS,GAAA,EAAK;AAElB,IAAA,KAAA,CAAM,IAAA,EAAe,SAAA,EAAW,CAAC,IAAA,KAAsB;AACrD,MAAA,MAAM,QAAQ,IAAA,CAAK,UAAA;AACnB,MAAA,IAAI,CAAC,KAAA,EAAO;AAEZ,MAAA,KAAA,MAAW,QAAQ,SAAA,EAAW;AAC5B,QAAA,MAAM,KAAA,GAAQ,MAAM,IAAI,CAAA;AACxB,QAAA,IAAI,OAAO,UAAU,QAAA,EAAU,KAAA,CAAM,IAAI,CAAA,GAAI,OAAA,CAAQ,OAAO,IAAI,CAAA;AAAA,MAClE;AAEA,MAAA,KAAA,MAAW,QAAQ,YAAA,EAAc;AAC/B,QAAA,MAAM,KAAA,GAAQ,MAAM,IAAI,CAAA;AACxB,QAAA,IAAI,OAAO,UAAU,QAAA,EAAU,KAAA,CAAM,IAAI,CAAA,GAAI,aAAA,CAAc,OAAO,IAAI,CAAA;AAAA,MACxE;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAA;AACF;AAGO,SAAS,eAAA,CAAgB,MAAc,IAAA,EAAsB;AAClE,EAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,KAAS,GAAA,EAAK,OAAO,IAAA;AAClC,EAAA,OAAO,IAAA,CAAK,OAAA;AAAA,IACV,uCAAA;AAAA,IACA,CAAC,MAAA,EAAQ,IAAA,EAAc,KAAA,EAAe,QACpC,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,KAAK,GAAG,OAAA,CAAQ,GAAA,EAAK,IAAI,CAAC,GAAG,KAAK,CAAA;AAAA,GACjD;AACF","file":"chunk-GSSSQTEV.js","sourcesContent":["/** Prefixes root-relative URLs with Astro's `base`, which Astro does not do for authored markdown links. */\nimport { visit } from 'unist-util-visit';\n\ninterface ElementNode {\n type: string;\n properties?: Record<string, unknown>;\n}\n\nconst URL_ATTRS = ['href', 'src', 'poster'];\nconst SRCSET_ATTRS = ['srcSet', 'srcset'];\n\nfunction shouldRewrite(value: string, base: string): boolean {\n if (!value.startsWith('/')) return false;\n if (value.startsWith('//')) return false; // protocol-relative\n if (base !== '/' && (value === base.replace(/\\/$/, '') || value.startsWith(base))) return false;\n return true;\n}\n\nfunction rewrite(value: string, base: string): string {\n return shouldRewrite(value, base) ? base.replace(/\\/$/, '') + value : value;\n}\n\nfunction rewriteSrcset(value: string, base: string): string {\n return value\n .split(',')\n .map((candidate) => {\n const trimmed = candidate.trim();\n if (!trimmed) return candidate;\n const [url, ...descriptors] = trimmed.split(/\\s+/);\n return [rewrite(url as string, base), ...descriptors].join(' ');\n })\n .join(', ');\n}\n\nexport function rehypeBaseUrl(options: { base: string }) {\n const base = options.base || '/';\n\n return function transformer(tree: unknown) {\n if (base === '/') return;\n\n visit(tree as never, 'element', (node: ElementNode) => {\n const props = node.properties;\n if (!props) return;\n\n for (const attr of URL_ATTRS) {\n const value = props[attr];\n if (typeof value === 'string') props[attr] = rewrite(value, base);\n }\n\n for (const attr of SRCSET_ATTRS) {\n const value = props[attr];\n if (typeof value === 'string') props[attr] = rewriteSrcset(value, base);\n }\n });\n };\n}\n\n/** Same, for authored HTML strings in frontmatter. */\nexport function rewriteHtmlBase(html: string, base: string): string {\n if (!base || base === '/') return html;\n return html.replace(\n /\\b(href|src)=(\"|')(\\/(?!\\/)[^\"']*)\\2/g,\n (_match, attr: string, quote: string, url: string) =>\n `${attr}=${quote}${rewrite(url, base)}${quote}`\n );\n}\n"]}
@@ -0,0 +1,68 @@
1
+ import { z } from 'astro/zod';
2
+
3
+ // src/schema.ts
4
+ var badgeSchema = () => z.object({
5
+ text: z.string(),
6
+ variant: z.enum(["primary", "secondary", "neutral", "success", "warning", "danger"]).default("neutral")
7
+ });
8
+ var deprecatedSchema = () => z.union([
9
+ z.boolean(),
10
+ z.object({
11
+ message: z.string().optional(),
12
+ replacedBy: z.string().optional()
13
+ })
14
+ ]);
15
+ var tocSchema = () => z.object({
16
+ minLevel: z.number().int().min(1).max(6).default(2),
17
+ maxLevel: z.number().int().min(1).max(6).default(3)
18
+ });
19
+ function docsSchema() {
20
+ return z.object({
21
+ title: z.string(),
22
+ description: z.string().optional(),
23
+ /** Overrides `title` in the sidebar only. */
24
+ navLabel: z.string().optional(),
25
+ /** Lucide icon name. */
26
+ icon: z.string().optional(),
27
+ badge: badgeSchema().optional(),
28
+ /** Omit from the sidebar. The page still builds and is still reachable. */
29
+ hidden: z.boolean().default(false),
30
+ /** Excluded from builds entirely, but visible in `astro dev`. */
31
+ draft: z.boolean().default(false),
32
+ deprecated: deprecatedSchema().default(false),
33
+ /** 'doc' gets sidebar + TOC; 'splash' is full-bleed with neither. */
34
+ template: z.enum(["doc", "splash"]).default("doc"),
35
+ tableOfContents: z.union([tocSchema(), z.literal(false)]).optional(),
36
+ /** Opt out of the markdown twin and the search index for this page. */
37
+ noIndex: z.boolean().default(false),
38
+ prev: z.union([z.boolean(), z.string()]).optional(),
39
+ next: z.union([z.boolean(), z.string()]).optional()
40
+ });
41
+ }
42
+ var groupLinkSchema = () => z.object({
43
+ label: z.string(),
44
+ href: z.string(),
45
+ /** Inferred from the href when omitted. */
46
+ external: z.boolean().optional(),
47
+ icon: z.string().optional(),
48
+ badge: badgeSchema().optional(),
49
+ attrs: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])).default({})
50
+ });
51
+ function groupSchema() {
52
+ return z.object({
53
+ label: z.string().optional(),
54
+ icon: z.string().optional(),
55
+ /** Immediate-child filesystem names (not titles), in display order. */
56
+ order: z.array(z.string()).default([]),
57
+ /** Children absent from `order`: alpha by label (default), by filename, or manual (dropped from the sidebar). */
58
+ sort: z.enum(["alpha", "filename", "manual"]).optional(),
59
+ collapsed: z.boolean().optional(),
60
+ hidden: z.boolean().default(false),
61
+ badge: badgeSchema().optional(),
62
+ links: z.array(groupLinkSchema()).default([])
63
+ }).strict();
64
+ }
65
+
66
+ export { badgeSchema, docsSchema, groupLinkSchema, groupSchema };
67
+ //# sourceMappingURL=chunk-IWKZQ4CW.js.map
68
+ //# sourceMappingURL=chunk-IWKZQ4CW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/schema.ts"],"names":[],"mappings":"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","file":"chunk-IWKZQ4CW.js","sourcesContent":["/** `z` must come from `astro/zod`: a different zod instance breaks Astro's collection validation. */\nimport { z } from 'astro/zod';\n\nexport const badgeSchema = () =>\n z.object({\n text: z.string(),\n variant: z\n .enum(['primary', 'secondary', 'neutral', 'success', 'warning', 'danger'])\n .default('neutral'),\n });\n\nconst deprecatedSchema = () =>\n z.union([\n z.boolean(),\n z.object({\n message: z.string().optional(),\n replacedBy: z.string().optional(),\n }),\n ]);\n\nconst tocSchema = () =>\n z.object({\n minLevel: z.number().int().min(1).max(6).default(2),\n maxLevel: z.number().int().min(1).max(6).default(3),\n });\n\n/** Page frontmatter. Ordering lives in `_group.yaml`, not here. */\nexport function docsSchema() {\n return z.object({\n title: z.string(),\n description: z.string().optional(),\n /** Overrides `title` in the sidebar only. */\n navLabel: z.string().optional(),\n /** Lucide icon name. */\n icon: z.string().optional(),\n badge: badgeSchema().optional(),\n /** Omit from the sidebar. The page still builds and is still reachable. */\n hidden: z.boolean().default(false),\n /** Excluded from builds entirely, but visible in `astro dev`. */\n draft: z.boolean().default(false),\n deprecated: deprecatedSchema().default(false),\n /** 'doc' gets sidebar + TOC; 'splash' is full-bleed with neither. */\n template: z.enum(['doc', 'splash']).default('doc'),\n tableOfContents: z.union([tocSchema(), z.literal(false)]).optional(),\n /** Opt out of the markdown twin and the search index for this page. */\n noIndex: z.boolean().default(false),\n prev: z.union([z.boolean(), z.string()]).optional(),\n next: z.union([z.boolean(), z.string()]).optional(),\n });\n}\n\nexport const groupLinkSchema = () =>\n z.object({\n label: z.string(),\n href: z.string(),\n /** Inferred from the href when omitted. */\n external: z.boolean().optional(),\n icon: z.string().optional(),\n badge: badgeSchema().optional(),\n attrs: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])).default({}),\n });\n\n/** `_group.yaml`. `.strict()` is load-bearing: a typo in an ordering file must fail, not be ignored. */\nexport function groupSchema() {\n return z\n .object({\n label: z.string().optional(),\n icon: z.string().optional(),\n /** Immediate-child filesystem names (not titles), in display order. */\n order: z.array(z.string()).default([]),\n /** Children absent from `order`: alpha by label (default), by filename, or manual (dropped from the sidebar). */\n sort: z.enum(['alpha', 'filename', 'manual']).optional(),\n collapsed: z.boolean().optional(),\n hidden: z.boolean().default(false),\n badge: badgeSchema().optional(),\n links: z.array(groupLinkSchema()).default([]),\n })\n .strict();\n}\n\nexport type DocsFrontmatter = z.infer<ReturnType<typeof docsSchema>>;\nexport type GroupFrontmatter = z.infer<ReturnType<typeof groupSchema>>;\n"]}
@@ -0,0 +1,113 @@
1
+ import { z } from 'astro/zod';
2
+
3
+ // src/config.ts
4
+ var headerLink = z.object({
5
+ label: z.string(),
6
+ href: z.string(),
7
+ /**
8
+ * A Lucide name like `BookOpen`, or a path to an SVG in `public/` like
9
+ * `/github.svg`. An SVG must be white: light mode inverts it.
10
+ */
11
+ icon: z.string().optional(),
12
+ external: z.boolean().optional()
13
+ });
14
+ var docsConfigSchema = z.object({
15
+ /** Site name, shown in the header and used as the `<title>` suffix. */
16
+ title: z.string(),
17
+ description: z.string().optional(),
18
+ /** Path to a favicon, relative to `public/`. Base is applied automatically. */
19
+ favicon: z.string().default("/favicon.svg"),
20
+ /**
21
+ * The header mark. Without one the header falls back to `title` as text. Either
22
+ * way a constant "Docs" label follows it, and `title` heads the sidebar.
23
+ */
24
+ logo: z.object({
25
+ src: z.string(),
26
+ /** Name the company: the brand link reads as this plus "Docs". */
27
+ alt: z.string().default("")
28
+ }).optional(),
29
+ /** Content directory, relative to `src/`. */
30
+ contentDir: z.string().default("content/docs"),
31
+ /** Mount docs under a sub-path, e.g. 'docs' for /docs/*. Empty means the site root. */
32
+ pathPrefix: z.string().default(""),
33
+ sidebar: z.object({
34
+ /** Default collapse state for groups with no explicit `collapsed`. */
35
+ collapsed: z.boolean().default(false),
36
+ /** Default append order for children absent from a group's `order`. */
37
+ sort: z.enum(["alpha", "filename", "manual"]).default("alpha"),
38
+ /** Extra top-level nodes, appended after folder-derived ones. */
39
+ extra: z.array(z.any()).default([])
40
+ }).prefault({}),
41
+ header: z.object({
42
+ links: z.array(headerLink).default([]),
43
+ showThemeToggle: z.boolean().default(true)
44
+ }).prefault({}),
45
+ footer: z.object({
46
+ /** Base URL for "Edit this page"; the content path is appended. */
47
+ editUrl: z.string().optional(),
48
+ showPrevNext: z.boolean().default(true),
49
+ text: z.string().optional()
50
+ }).prefault({}),
51
+ tableOfContents: z.union([
52
+ z.object({
53
+ minLevel: z.number().int().min(1).max(6).default(2),
54
+ maxLevel: z.number().int().min(1).max(6).default(3)
55
+ }),
56
+ z.literal(false)
57
+ ]).prefault({}),
58
+ code: z.object({
59
+ /** 'codeblock' renders fences through Equality's CodeBlock; 'shiki' uses Astro's Shiki. */
60
+ highlighter: z.enum(["codeblock", "shiki"]).default("codeblock"),
61
+ /** Shiki themes; only consulted when `highlighter` is 'shiki'. */
62
+ themes: z.object({ light: z.string(), dark: z.string() }).default({ light: "github-light", dark: "github-dark" }),
63
+ wrap: z.boolean().default(false),
64
+ langs: z.array(z.string()).default([])
65
+ }).prefault({}),
66
+ search: z.object({
67
+ /** 'pagefind' indexes the built HTML. Dev serves that index, so it needs one build. */
68
+ provider: z.enum(["pagefind", "none"]).default("pagefind")
69
+ }).prefault({}),
70
+ routing: z.object({
71
+ /** Inject the catch-all docs route. Disable to own routing entirely. */
72
+ injectPages: z.boolean().default(true),
73
+ /** Emit a `.md` twin per page plus `/llms.txt`. */
74
+ markdownTwins: z.boolean().default(true),
75
+ notFound: z.boolean().default(true)
76
+ }).prefault({}),
77
+ theme: z.object({
78
+ /** 'global' puts tokens on <html>; 'scoped' wraps in a ThemeProvider. */
79
+ mode: z.enum(["global", "scoped"]).default("global"),
80
+ /** Persist the reader's choice to localStorage. */
81
+ persist: z.boolean().default(true)
82
+ }).prefault({}),
83
+ /**
84
+ * Stylesheets loaded on every docs page. A project-relative path ('./src/styles/site.css')
85
+ * or a package specifier. Resolved against the project root, so dev and build agree.
86
+ */
87
+ customCss: z.array(z.string()).default([]),
88
+ /**
89
+ * Client modules loaded on every docs page. Bundled rather than served as-is, so they may
90
+ * import from node_modules - which is what a script mutating rendered text needs, since it
91
+ * has to call Equality's `scheduleHighlight` afterwards to repaint code blocks.
92
+ */
93
+ clientScripts: z.array(z.string()).default([]),
94
+ /** Install @astrojs/mdx, @astrojs/react and Tailwind when absent. */
95
+ autoIntegrations: z.boolean().default(true),
96
+ /** Versioning. Left permissive here; the versioning workstream owns the shape. */
97
+ versions: z.any().optional(),
98
+ /** Generated-section plugins (OpenAPI reference, changelogs, ...). */
99
+ plugins: z.array(z.any()).default([])
100
+ });
101
+ function resolveConfig(user) {
102
+ const result = docsConfigSchema.safeParse(user);
103
+ if (!result.success) {
104
+ const issues = result.error.issues.map((i) => ` - ${i.path.join(".") || "(root)"}: ${i.message}`).join("\n");
105
+ throw new Error(`[@eqtylab/docs] Invalid configuration:
106
+ ${issues}`);
107
+ }
108
+ return result.data;
109
+ }
110
+
111
+ export { docsConfigSchema, resolveConfig };
112
+ //# sourceMappingURL=chunk-K7PJRTK3.js.map
113
+ //# sourceMappingURL=chunk-K7PJRTK3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts"],"names":[],"mappings":"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","file":"chunk-K7PJRTK3.js","sourcesContent":["/** Integration options: the whole consumer-facing configuration surface. */\nimport { z } from 'astro/zod';\n\nconst headerLink = z.object({\n label: z.string(),\n href: z.string(),\n /**\n * A Lucide name like `BookOpen`, or a path to an SVG in `public/` like\n * `/github.svg`. An SVG must be white: light mode inverts it.\n */\n icon: z.string().optional(),\n external: z.boolean().optional(),\n});\n\nexport const docsConfigSchema = z.object({\n /** Site name, shown in the header and used as the `<title>` suffix. */\n title: z.string(),\n description: z.string().optional(),\n /** Path to a favicon, relative to `public/`. Base is applied automatically. */\n favicon: z.string().default('/favicon.svg'),\n\n /**\n * The header mark. Without one the header falls back to `title` as text. Either\n * way a constant \"Docs\" label follows it, and `title` heads the sidebar.\n */\n logo: z\n .object({\n src: z.string(),\n /** Name the company: the brand link reads as this plus \"Docs\". */\n alt: z.string().default(''),\n })\n .optional(),\n\n /** Content directory, relative to `src/`. */\n contentDir: z.string().default('content/docs'),\n\n /** Mount docs under a sub-path, e.g. 'docs' for /docs/*. Empty means the site root. */\n pathPrefix: z.string().default(''),\n\n sidebar: z\n .object({\n /** Default collapse state for groups with no explicit `collapsed`. */\n collapsed: z.boolean().default(false),\n /** Default append order for children absent from a group's `order`. */\n sort: z.enum(['alpha', 'filename', 'manual']).default('alpha'),\n /** Extra top-level nodes, appended after folder-derived ones. */\n extra: z.array(z.any()).default([]),\n })\n .prefault({}),\n\n header: z\n .object({\n links: z.array(headerLink).default([]),\n showThemeToggle: z.boolean().default(true),\n })\n .prefault({}),\n\n footer: z\n .object({\n /** Base URL for \"Edit this page\"; the content path is appended. */\n editUrl: z.string().optional(),\n showPrevNext: z.boolean().default(true),\n text: z.string().optional(),\n })\n .prefault({}),\n\n tableOfContents: z\n .union([\n z.object({\n minLevel: z.number().int().min(1).max(6).default(2),\n maxLevel: z.number().int().min(1).max(6).default(3),\n }),\n z.literal(false),\n ])\n .prefault({}),\n\n code: z\n .object({\n /** 'codeblock' renders fences through Equality's CodeBlock; 'shiki' uses Astro's Shiki. */\n highlighter: z.enum(['codeblock', 'shiki']).default('codeblock'),\n /** Shiki themes; only consulted when `highlighter` is 'shiki'. */\n themes: z\n .object({ light: z.string(), dark: z.string() })\n .default({ light: 'github-light', dark: 'github-dark' }),\n wrap: z.boolean().default(false),\n langs: z.array(z.string()).default([]),\n })\n .prefault({}),\n\n search: z\n .object({\n /** 'pagefind' indexes the built HTML. Dev serves that index, so it needs one build. */\n provider: z.enum(['pagefind', 'none']).default('pagefind'),\n })\n .prefault({}),\n\n routing: z\n .object({\n /** Inject the catch-all docs route. Disable to own routing entirely. */\n injectPages: z.boolean().default(true),\n /** Emit a `.md` twin per page plus `/llms.txt`. */\n markdownTwins: z.boolean().default(true),\n notFound: z.boolean().default(true),\n })\n .prefault({}),\n\n theme: z\n .object({\n /** 'global' puts tokens on <html>; 'scoped' wraps in a ThemeProvider. */\n mode: z.enum(['global', 'scoped']).default('global'),\n /** Persist the reader's choice to localStorage. */\n persist: z.boolean().default(true),\n })\n .prefault({}),\n\n /**\n * Stylesheets loaded on every docs page. A project-relative path ('./src/styles/site.css')\n * or a package specifier. Resolved against the project root, so dev and build agree.\n */\n customCss: z.array(z.string()).default([]),\n\n /**\n * Client modules loaded on every docs page. Bundled rather than served as-is, so they may\n * import from node_modules - which is what a script mutating rendered text needs, since it\n * has to call Equality's `scheduleHighlight` afterwards to repaint code blocks.\n */\n clientScripts: z.array(z.string()).default([]),\n\n /** Install @astrojs/mdx, @astrojs/react and Tailwind when absent. */\n autoIntegrations: z.boolean().default(true),\n\n /** Versioning. Left permissive here; the versioning workstream owns the shape. */\n versions: z.any().optional(),\n\n /** Generated-section plugins (OpenAPI reference, changelogs, ...). */\n plugins: z.array(z.any()).default([]),\n});\n\nexport type DocsUserConfig = z.input<typeof docsConfigSchema>;\nexport type DocsConfig = z.output<typeof docsConfigSchema>;\n\nexport function resolveConfig(user: DocsUserConfig): DocsConfig {\n const result = docsConfigSchema.safeParse(user);\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => ` - ${i.path.join('.') || '(root)'}: ${i.message}`)\n .join('\\n');\n throw new Error(`[@eqtylab/docs] Invalid configuration:\\n${issues}`);\n }\n return result.data;\n}\n"]}