@eqtylab/docs 0.3.0 → 0.3.2

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/LICENSE ADDED
@@ -0,0 +1,190 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to the Licensor for inclusion in the Work by the copyright
52
+ owner or by an individual or Legal Entity authorized to submit on behalf
53
+ of the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ Copyright 2025 EQTY Lab
179
+
180
+ Licensed under the Apache License, Version 2.0 (the "License");
181
+ you may not use this file except in compliance with the License.
182
+ You may obtain a copy of the License at
183
+
184
+ http://www.apache.org/licenses/LICENSE-2.0
185
+
186
+ Unless required by applicable law or agreed to in writing, software
187
+ distributed under the License is distributed on an "AS IS" BASIS,
188
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
189
+ See the License for the specific language governing permissions and
190
+ limitations under the License.
package/README.md CHANGED
@@ -56,13 +56,24 @@ collapsed: false
56
56
  - A typo in `order` produces a build **warning naming the file and the token** rather than silently
57
57
  reordering, and the schema is `.strict()` so an unknown key fails the build.
58
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`.
59
+ ## Three conventions worth knowing
60
+
61
+ **Styling is inline Tailwind, and one `@source` line is what makes it work.** The chrome is styled
62
+ with utility classes written in the markup. That only compiles because `runtime/styles/docs.css`
63
+ names this package's own files in an explicit `@source`: Tailwind v4's automatic source detection
64
+ skips `node_modules`, which is exactly where this markup sits in a consumer's build. Drop that line
65
+ and every utility here produces nothing, with no error anywhere. `pnpm run check:source` enforces
66
+ that the glob still covers all shipped markup, and runs as part of `build`. Recipes used by more
67
+ than one component are `@utility` definitions in `runtime/styles/utilities.css`; a co-located
68
+ `*.module.css` is the escape hatch for rules that cannot live on an element, which today means
69
+ only `GlobalSearch.module.css`.
70
+
71
+ **Overruling an Equality component takes `!`.** `packages/ui` ships unlayered CSS, Tailwind
72
+ utilities live in `@layer utilities`, and an unlayered declaration beats a layered one whatever its
73
+ specificity. So where this markup has to overrule a value an Equality class already sets on the
74
+ same element — `CodeBlock`'s `max-height`, `CommandList`'s — the utility carries `!`. Properties
75
+ Equality leaves alone need nothing. Getting this wrong fails silently: the class is in the HTML and
76
+ the rule is in the bundle, it just loses.
66
77
 
67
78
  **Route-level MDX components override page-level ones.** `@astrojs/mdx` builds the map as
68
79
  `{ Fragment, ...fileComponents, ...props.components }`, so the route's `<Content components={…} />`
@@ -96,6 +107,7 @@ product surfaces cannot drift:
96
107
  | Code fences | `CodeBlock` |
97
108
  | Markdown tables | `TableContainer` / `TableHeader` / `TableBody` / `TableRow` / `TableHead` / `TableCell` |
98
109
  | `<Alert>` | `Alert`, as an `aside` |
110
+ | `<Tabs>` | `Tabs`, server-rendered |
99
111
  | Links | base-aware `a` override |
100
112
 
101
113
  **Authors write Equality's own components, with no imports.** The route-level component map
@@ -123,15 +135,45 @@ whose parts all use `subgrid`, so it needs an explicit track list or the table c
123
135
  to one column. Markdown has no syntax for that, so `rehypeTableColumns` derives the count
124
136
  from the first row at build time.
125
137
 
138
+ Tabs are authored the same way, with no imports:
139
+
140
+ ```mdx
141
+ <Tabs syncKey="platform">
142
+ <TabItem label="Linux">Anything, including fences and tables.</TabItem>
143
+ <TabItem label="macOS">
144
+ Sets sharing a `syncKey` switch together, and the choice is remembered.
145
+ </TabItem>
146
+ </Tabs>
147
+ ```
148
+
126
149
  This is also why content is MDX-only — these overrides are the mechanism, and Astro's
127
150
  plain-Markdown pipeline has no component substitution at all.
128
151
 
129
- ## Search needs a build
152
+ ## Bringing your own CSS and scripts
153
+
154
+ `customCss` and `clientScripts` attach a consumer's own assets to every docs page:
155
+
156
+ ```js
157
+ docs({
158
+ title: 'My Docs',
159
+ customCss: ['./src/styles/site.css'],
160
+ clientScripts: ['./src/scripts/glossary.ts'],
161
+ });
162
+ ```
163
+
164
+ Both resolve project-relative paths against the project root, so they mean the same thing in
165
+ dev and in a build. `clientScripts` entries are **bundled** rather than served as-is, which is
166
+ what a script that rewrites rendered text needs: it has to import `scheduleHighlight` from
167
+ `@eqtylab/equality` and call it afterwards, or the code blocks it touched lose their
168
+ highlighting. (`CodeBlock` paints through the CSS Custom Highlight API over `Range`s into those
169
+ very text nodes.) A plain `<script src>` in `public/` cannot import anything.
170
+
171
+ ## Building the Search Index
130
172
 
131
- Search is full-text, over the built HTML, via [Pagefind](https://pagefind.app). The integration
173
+ Full-text search uses the built HTML, via [Pagefind](https://pagefind.app). The integration
132
174
  runs it in `astro:build:done` and writes the index to `dist/pagefind/`.
133
175
 
134
- **One `astro build` makes search work in `astro dev` too.** Dev serves `dist/pagefind/` off disk,
176
+ RUn `pnpm run build` to make search work in `pnpm run dev`. Dev serves `dist/pagefind/` off disk,
135
177
  so results describe the last build; rebuild while dev runs and the next search picks it up. Until
136
178
  that first build the palette says search needs one.
137
179
 
package/dist/config.js CHANGED
@@ -1,3 +1,3 @@
1
- export { docsConfigSchema, resolveConfig } from './chunk-ATIOPYKE.js';
1
+ export { docsConfigSchema, resolveConfig } from './chunk-K7PJRTK3.js';
2
2
  //# sourceMappingURL=config.js.map
3
3
  //# sourceMappingURL=config.js.map
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import './chunk-55J6XMHW.js';
2
2
  import { rehypeBaseUrl } from './chunk-GSSSQTEV.js';
3
- import { resolveConfig } from './chunk-ATIOPYKE.js';
4
- export { resolveConfig } from './chunk-ATIOPYKE.js';
3
+ import { resolveConfig } from './chunk-K7PJRTK3.js';
4
+ export { resolveConfig } from './chunk-K7PJRTK3.js';
5
5
  import { resolveDocsEnv } from './chunk-ZZ45WAVR.js';
6
6
  export { resolveDocsEnv } from './chunk-ZZ45WAVR.js';
7
7
  export { badgeSchema, docsSchema, groupSchema } from './chunk-IWKZQ4CW.js';
8
- import path3 from 'path';
9
8
  import { fileURLToPath } from 'url';
9
+ import path3 from 'path';
10
10
  import { globSync } from 'tinyglobby';
11
11
  import fs, { readdirSync, readFileSync } from 'fs';
12
12
  import { createRequire } from 'module';
@@ -176,10 +176,14 @@ function isComponent(node) {
176
176
  const name = node.name;
177
177
  return typeof name === "string" && (/^[A-Z]/.test(name) || name.includes("."));
178
178
  }
179
+ var CONTAINERS = /* @__PURE__ */ new Set(["Tabs", "TabItem"]);
180
+ function isContainer(node) {
181
+ return typeof node.name === "string" && CONTAINERS.has(node.name);
182
+ }
179
183
  function rehypeProseScope() {
180
184
  return function transformer(tree) {
181
185
  visit(tree, (node) => {
182
- if (isComponent(node)) return SKIP;
186
+ if (isComponent(node)) return isContainer(node) ? void 0 : SKIP;
183
187
  if (node.type === "element") {
184
188
  node.properties = { ...node.properties, dataEqMd: "" };
185
189
  return void 0;
@@ -309,7 +313,7 @@ function docs(options = {}) {
309
313
  name: "@eqtylab/docs",
310
314
  hooks: {
311
315
  async "astro:config:setup"(params) {
312
- const { config, injectRoute, updateConfig, addWatchFile, logger, command } = params;
316
+ const { config, injectRoute, injectScript, updateConfig, addWatchFile, logger, command } = params;
313
317
  assertMdxOnly(new URL(`./${cfg.contentDir}/`, config.srcDir));
314
318
  const consumer = scanConsumerPages(config.srcDir);
315
319
  for (const route of plannedRoutes(cfg)) {
@@ -376,6 +380,13 @@ function docs(options = {}) {
376
380
  rehypeTableColumns,
377
381
  ...cfg.code.highlighter === "codeblock" ? [rehypeCodeFence] : []
378
382
  ];
383
+ const resolveAsset = (spec) => spec.startsWith(".") ? fileURLToPath(new URL(spec, config.root)) : spec;
384
+ for (const href of cfg.customCss) {
385
+ injectScript("page-ssr", `import ${JSON.stringify(resolveAsset(href))};`);
386
+ }
387
+ for (const src of cfg.clientScripts) {
388
+ injectScript("page", `import ${JSON.stringify(resolveAsset(src))};`);
389
+ }
379
390
  updateConfig({
380
391
  integrations: added,
381
392
  vite: { plugins: vitePlugins },
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/assert-mdx-only.ts","../src/internal/microlighter-grammars.ts","../src/internal/pagefind.ts","../src/internal/rehype-code-fence.ts","../src/internal/rehype-prose-scope.ts","../src/internal/rehype-table-columns.ts","../src/internal/scan-consumer-pages.ts","../src/internal/virtual-config.ts","../src/index.ts"],"names":["path","fileURLToPath","visit","globSync"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Only MDX supports the component overrides and the loader globs `.mdx` only,\n * so a stray `.md` would be silently absent from the site. Fail loudly instead.\n */\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { globSync } from 'tinyglobby';\n\nexport function assertMdxOnly(contentDir: URL): void {\n const dir = fileURLToPath(contentDir);\n\n let strays: string[] = [];\n try {\n strays = globSync(['**/*.md'], { cwd: dir, absolute: false });\n } catch {\n return;\n }\n if (strays.length === 0) return;\n\n const list = strays\n .sort()\n .map((file) => ` - ${file} -> ${file.replace(/\\.md$/i, '.mdx')}`)\n .join('\\n');\n\n throw new Error(\n `[@eqtylab/docs] Found ${strays.length} Markdown file${strays.length > 1 ? 's' : ''} in ` +\n `${path.relative(process.cwd(), dir) || dir}:\\n${list}\\n\\n` +\n `Docs content must be .mdx. Only MDX supports the component overrides that render\\n` +\n `tables, code fences and callouts through Equality, so a .md page would look\\n` +\n `different from every other page. Renaming is usually the only change needed --\\n` +\n `MDX is a superset of Markdown.`\n );\n}\n","/**\n * Emits microlighter's grammar modules beside the chunks that ask for them.\n * CodeBlock loads grammars with `import('./grammars/' + language)`, which no\n * bundler can expand; without this the build succeeds and code renders unhighlighted.\n */\nimport { readdirSync, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\nimport type { AstroIntegrationLogger } from 'astro';\nimport type { Plugin } from 'vite';\n\n/** Residue of the dynamic import in the emitted chunk. */\nconst GRAMMAR_IMPORT = 'grammars/${';\n\n/** Two hops from the consumer: microlighter is a dependency of @eqtylab/equality, which is only a peer here. */\nfunction findGrammarDir(projectRoot: URL): string {\n const requireFromProject = createRequire(new URL('package.json', projectRoot));\n const equalityEntry = requireFromProject.resolve('@eqtylab/equality');\n const requireFromEquality = createRequire(equalityEntry);\n return path.resolve(path.dirname(requireFromEquality.resolve('microlighter')), 'grammars');\n}\n\nexport function microlighterGrammarsPlugin(\n projectRoot: URL,\n logger: AstroIntegrationLogger\n): Plugin {\n return {\n name: 'eqty-docs:microlighter-grammars',\n apply: 'build',\n generateBundle(_options, bundle) {\n const directories = new Set(\n Object.values(bundle)\n .filter((output) => output.type === 'chunk' && output.code.includes(GRAMMAR_IMPORT))\n .map((output) => path.posix.dirname(output.fileName))\n );\n if (directories.size === 0) return;\n\n let grammarDir: string;\n let grammars: string[];\n try {\n grammarDir = findGrammarDir(projectRoot);\n grammars = readdirSync(grammarDir).filter((file) => file.endsWith('.js'));\n } catch (error) {\n // Warn rather than fail the build over highlighting.\n logger.warn(\n 'Code blocks ask for microlighter grammars, but they could not be resolved. ' +\n 'Fenced code will render unhighlighted. Check that @eqtylab/equality is ' +\n `installed in this project.\\n ${String(error)}`\n );\n return;\n }\n\n for (const directory of directories) {\n for (const grammar of grammars) {\n this.emitFile({\n type: 'asset',\n fileName:\n directory === '.' ? `grammars/${grammar}` : `${directory}/grammars/${grammar}`,\n source: readFileSync(path.resolve(grammarDir, grammar), 'utf8'),\n });\n }\n }\n },\n };\n}\n","/**\n * Not `astro-pagefind`: it ships TypeScript, and Node will not compile that under\n * node_modules when this integration reaches it from its own bundle.\n *\n * The build writes the index; dev serves that same index off disk, so it always\n * describes the last build.\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { AstroIntegration } from 'astro';\n\nconst INDEX_DIR = 'pagefind';\n\n/** Everything else Pagefind fetches is read as bytes, so the type never reaches a parser. */\nconst MIME: Record<string, string> = {\n '.js': 'text/javascript',\n '.css': 'text/css',\n '.json': 'application/json',\n '.wasm': 'application/wasm',\n};\n\n/** Pagefind collects errors per step and carries on; any of them means no usable index. */\nfunction failOn(\n errors: string[],\n logger: { error: (message: string) => void },\n what: string\n): void {\n if (!errors.length) return;\n errors.forEach((error) => logger.error(error));\n throw new Error(`[@eqtylab/docs] Pagefind could not ${what}.`);\n}\n\nfunction indexRequest(url: string | undefined, base: string): string | null {\n if (!url) return null;\n const pathname = decodeURIComponent(url.split(/[?#]/)[0]);\n const prefix = `${base.replace(/\\/+$/, '')}/${INDEX_DIR}/`;\n return pathname.startsWith(prefix) ? pathname.slice(prefix.length) : null;\n}\n\nexport function pagefindIntegration(): AstroIntegration {\n let indexDir = '';\n\n return {\n name: '@eqtylab/docs/pagefind',\n hooks: {\n 'astro:config:setup'({ config, logger }) {\n indexDir = path.join(fileURLToPath(config.outDir), INDEX_DIR);\n\n if (config.output === 'server') {\n logger.warn(\n 'Output \"server\" emits no static HTML, so there is nothing for Pagefind to index.'\n );\n }\n },\n\n /** Runs ahead of Vite's static middleware and Astro's handler; move it and `/pagefind/*` 404s. */\n 'astro:server:setup'({ server, logger }) {\n const base = server.config.base ?? '/';\n\n logger.info(\n fs.existsSync(indexDir)\n ? 'serving the search index from the last build; rebuild to pick up edits'\n : 'no search index yet — run `astro build` once to search in dev'\n );\n\n server.middlewares.use((req, res, next) => {\n const requested = indexRequest(req.url, base);\n if (requested === null) return next();\n\n const file = path.join(indexDir, requested);\n // The prefix check is what stops `..` climbing out of the index directory.\n if (!file.startsWith(indexDir + path.sep) || !fs.existsSync(file)) return next();\n\n res.setHeader('Content-Type', MIME[path.extname(file)] ?? 'application/octet-stream');\n // The next build rewrites these in place, and a cached fragment would outlive it.\n res.setHeader('Cache-Control', 'no-store');\n fs.createReadStream(file).pipe(res);\n });\n },\n\n /** The last hook of the build, and the first moment every page exists on disk to read. */\n async 'astro:build:done'({ dir, logger }) {\n const outDir = fileURLToPath(dir);\n const { createIndex } = await import('pagefind');\n\n const { index, errors } = await createIndex();\n failOn(errors, logger, 'create an index');\n if (!index) throw new Error('[@eqtylab/docs] Pagefind returned no index.');\n\n const { page_count, errors: addErrors } = await index.addDirectory({ path: outDir });\n failOn(addErrors, logger, 'index the built output');\n\n const { outputPath, errors: writeErrors } = await index.writeFiles({\n outputPath: path.join(outDir, INDEX_DIR),\n });\n failOn(writeErrors, logger, 'write the index');\n\n logger.info(`indexed ${page_count} pages to ${outputPath}`);\n },\n },\n };\n}\n","/**\n * Lifts each fence's source, language and title onto its `<pre>`. Do not recover\n * the source from the rendered slot: `Astro.slots.render()` escapes in dev but not in build.\n */\nimport { visit } from 'unist-util-visit';\n\ninterface Node {\n type: string;\n tagName?: string;\n value?: string;\n properties?: Record<string, unknown>;\n children?: Node[];\n data?: { meta?: string };\n}\n\nfunction textOf(node: Node): string {\n if (node.type === 'text') return node.value ?? '';\n return (node.children ?? []).map(textOf).join('');\n}\n\nfunction classNames(props: Record<string, unknown> | undefined): string[] {\n const raw = props?.className ?? props?.class;\n if (Array.isArray(raw)) return raw.map(String);\n if (typeof raw === 'string') return raw.split(/\\s+/);\n return [];\n}\n\n/** ```ts title=\"button.tsx\" -> \"button.tsx\" */\nfunction titleFromMeta(meta: string | undefined): string | undefined {\n const match = meta?.match(/(?:^|\\s)title=(?:\"([^\"]*)\"|'([^']*)'|(\\S+))/);\n return match ? (match[1] ?? match[2] ?? match[3]) : undefined;\n}\n\nexport function rehypeCodeFence() {\n return function transformer(tree: unknown) {\n visit(tree as never, 'element', (node: Node) => {\n if (node.tagName !== 'pre') return;\n\n const code = (node.children ?? []).find(\n (child) => child.type === 'element' && child.tagName === 'code'\n );\n if (!code) return;\n\n const language = classNames(code.properties)\n .find((name) => name.startsWith('language-'))\n ?.slice('language-'.length);\n\n const title = titleFromMeta(code.data?.meta);\n\n node.properties = {\n ...node.properties,\n dataCode: textOf(code).replace(/\\n$/, ''),\n ...(language ? { dataLanguage: language } : {}),\n ...(title ? { dataTitle: title } : {}),\n };\n });\n };\n}\n","/**\n * Marks the content a page authored as markdown or as plain HTML, so\n * `prose.css` can typeset it without reaching inside a component.\n *\n * MDX parses a component's children as markdown whenever they sit on their own\n * lines, so `<Badge icon=\"Shield\">\\n Primary\\n</Badge>` renders a `<p>` inside\n * the badge — and prettier puts them there. Authoring discipline cannot fix it;\n * the boundary has to be drawn here. Everything below a capitalised JSX tag is\n * that component's business, `<div>` and friends are the page's own.\n */\nimport { SKIP, visit } from 'unist-util-visit';\n\nconst MARKER = 'data-eq-md';\n\ninterface Attribute {\n type: string;\n name?: string | null;\n}\n\ninterface Node {\n type: string;\n name?: string | null;\n properties?: Record<string, unknown>;\n attributes?: Attribute[];\n}\n\n/** Capitalised or dotted JSX names are components; `div`, `span` and friends are not. */\nfunction isComponent(node: Node): boolean {\n if (node.type !== 'mdxJsxFlowElement' && node.type !== 'mdxJsxTextElement') return false;\n const name = node.name;\n return typeof name === 'string' && (/^[A-Z]/.test(name) || name.includes('.'));\n}\n\nexport function rehypeProseScope() {\n return function transformer(tree: unknown) {\n visit(tree as never, (node: Node) => {\n if (isComponent(node)) return SKIP;\n\n if (node.type === 'element') {\n node.properties = { ...node.properties, dataEqMd: '' };\n return undefined;\n }\n\n // Authored HTML. A JSX fragment has no name and nothing to mark.\n if ((node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') && node.name) {\n const attributes = node.attributes ?? [];\n if (!attributes.some((a) => a.type === 'mdxJsxAttribute' && a.name === MARKER)) {\n attributes.push({ type: 'mdxJsxAttribute', name: MARKER, value: '' } as Attribute);\n }\n node.attributes = attributes;\n }\n\n return undefined;\n });\n };\n}\n","/**\n * Annotates each markdown table with its column count. Equality's `TableContainer`\n * is a CSS grid and collapses to one column without an explicit track list.\n */\nimport { visit } from 'unist-util-visit';\n\ninterface ElementNode {\n type: string;\n tagName?: string;\n properties?: Record<string, unknown>;\n children?: ElementNode[];\n}\n\n/** First `tr` in document order, searching thead before tbody. */\nfunction firstRow(table: ElementNode): ElementNode | undefined {\n let found: ElementNode | undefined;\n visit(table as never, 'element', (node: ElementNode) => {\n if (found) return false;\n if (node.tagName === 'tr') {\n found = node;\n return false;\n }\n return undefined;\n });\n return found;\n}\n\nfunction countCells(row: ElementNode): number {\n return (row.children ?? []).reduce((total, child) => {\n if (child.type !== 'element') return total;\n if (child.tagName !== 'th' && child.tagName !== 'td') return total;\n const span = Number(child.properties?.colSpan ?? child.properties?.colspan ?? 1);\n return total + (Number.isFinite(span) && span > 0 ? span : 1);\n }, 0);\n}\n\nexport function rehypeTableColumns() {\n return function transformer(tree: unknown) {\n visit(tree as never, 'element', (node: ElementNode) => {\n if (node.tagName !== 'table') return;\n const row = firstRow(node);\n const count = row ? countCells(row) : 0;\n if (count <= 0) return;\n node.properties = { ...node.properties, dataColumnCount: String(count) };\n });\n };\n}\n","/**\n * Routes the consumer's own `src/pages` already claim. Astro does NOT de-duplicate\n * injected routes against file-based ones: a path claimed by both is emitted\n * twice and the winner is write order, so yielding has to be explicit here.\n */\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { globSync } from 'tinyglobby';\n\nconst PAGE_EXTENSIONS = ['astro', 'md', 'mdx', 'html', 'ts', 'js'];\n\nexport interface ConsumerPages {\n /** Concrete route paths the consumer's pages generate, normalised without trailing slash. */\n ownedPaths: string[];\n /** Route patterns claimed by consumer pages, e.g. '/[...slug]' or '/404'. */\n claimedPatterns: Set<string>;\n}\n\n/** `index.astro` -> '', `a/b.astro` -> '/a/b', `[...slug].astro` -> '/[...slug]' */\nfunction toRoutePath(relative: string): string {\n const withoutExt = relative.replace(/\\.[^./]+$/, '');\n const segments = withoutExt.split(path.sep).join('/').split('/').filter(Boolean);\n if (segments.at(-1) === 'index') segments.pop();\n return '/' + segments.join('/');\n}\n\nexport function scanConsumerPages(srcDir: URL): ConsumerPages {\n const pagesDir = fileURLToPath(new URL('./pages/', srcDir));\n\n let files: string[] = [];\n try {\n files = globSync([`**/*.{${PAGE_EXTENSIONS.join(',')}}`], {\n cwd: pagesDir,\n absolute: false,\n });\n } catch {\n // No src/pages: a docs-only site.\n return { ownedPaths: [], claimedPatterns: new Set() };\n }\n\n const ownedPaths: string[] = [];\n const claimedPatterns = new Set<string>();\n\n for (const file of files) {\n // Astro ignores files and directories prefixed with `_`.\n if (file.split(path.sep).some((segment) => segment.startsWith('_'))) continue;\n\n const routePath = toRoutePath(file);\n claimedPatterns.add(routePath === '' ? '/' : routePath);\n\n if (!/[[\\]]/.test(file)) {\n ownedPaths.push(routePath.replace(/\\/+$/, '') || '/');\n }\n }\n\n return { ownedPaths, claimedPatterns };\n}\n","/** Serves the resolved config to runtime components, which ship from node_modules and cannot reach the consumer's project by path. */\nimport type { Plugin } from 'vite';\n\nconst MODULE_ID = 'virtual:eqty-docs/config';\nconst RESOLVED_ID = '\\0' + MODULE_ID;\n\nexport function virtualConfigPlugin(getPayload: () => Record<string, unknown>): Plugin {\n return {\n name: 'eqty-docs:virtual-config',\n resolveId(id) {\n return id === MODULE_ID ? RESOLVED_ID : null;\n },\n load(id) {\n if (id !== RESOLVED_ID) return null;\n return `export default ${JSON.stringify(getPayload())};`;\n },\n };\n}\n","import type { AstroIntegration } from 'astro';\n\nimport { resolveConfig, type DocsConfig, type DocsUserConfig } from './config.ts';\nimport { resolveDocsEnv, type DocsEnv } from './env.ts';\nimport { assertMdxOnly } from './internal/assert-mdx-only.ts';\nimport { microlighterGrammarsPlugin } from './internal/microlighter-grammars.ts';\nimport { pagefindIntegration } from './internal/pagefind.ts';\nimport { rehypeBaseUrl } from './internal/rehype-base-url.ts';\nimport { rehypeCodeFence } from './internal/rehype-code-fence.ts';\nimport { rehypeProseScope } from './internal/rehype-prose-scope.ts';\nimport { rehypeTableColumns } from './internal/rehype-table-columns.ts';\nimport { scanConsumerPages } from './internal/scan-consumer-pages.ts';\nimport { virtualConfigPlugin } from './internal/virtual-config.ts';\n\nexport { resolveConfig, type DocsConfig, type DocsUserConfig } from './config.ts';\nexport { resolveDocsEnv, type DocsEnv } from './env.ts';\n// Do not re-export the loaders: this entry runs in Node when astro.config loads,\n// and they import `astro:content`, which only exists in the Vite graph.\nexport { docsSchema, groupSchema, badgeSchema } from './schema.ts';\nexport * from './types.ts';\n\nexport interface DocsIntegrationOptions extends DocsUserConfig {\n /** Build environment for versioned deploys. Defaults to `resolveDocsEnv()`. */\n env?: Partial<DocsEnv>;\n}\n\n/** Route patterns the integration would like to own, paired with their entrypoints. */\nfunction plannedRoutes(cfg: DocsConfig) {\n const prefix = cfg.pathPrefix ? `/${cfg.pathPrefix.replace(/^\\/|\\/$/g, '')}` : '';\n const routes: Array<{ pattern: string; entrypoint: string; enabled: boolean }> = [\n {\n pattern: `${prefix}/[...slug]`,\n entrypoint: '@eqtylab/docs/routes/docs.astro',\n enabled: cfg.routing.injectPages,\n },\n {\n pattern: `${prefix}/[...slug].md`,\n entrypoint: '@eqtylab/docs/routes/docs-md.ts',\n enabled: cfg.routing.markdownTwins,\n },\n {\n pattern: '/llms.txt',\n entrypoint: '@eqtylab/docs/routes/llms-txt.ts',\n enabled: cfg.routing.markdownTwins,\n },\n {\n pattern: '/404',\n entrypoint: '@eqtylab/docs/routes/not-found.astro',\n enabled: cfg.routing.notFound,\n },\n ];\n return routes.filter((r) => r.enabled);\n}\n\nexport default function docs(\n options: DocsIntegrationOptions = {} as DocsIntegrationOptions\n): AstroIntegration {\n const { env: envOverrides, ...userConfig } = options;\n const cfg = resolveConfig(userConfig);\n const env = resolveDocsEnv(envOverrides);\n\n let payload: Record<string, unknown> = {};\n\n return {\n name: '@eqtylab/docs',\n hooks: {\n async 'astro:config:setup'(params) {\n const { config, injectRoute, updateConfig, addWatchFile, logger, command } = params;\n\n assertMdxOnly(new URL(`./${cfg.contentDir}/`, config.srcDir));\n\n const consumer = scanConsumerPages(config.srcDir);\n\n for (const route of plannedRoutes(cfg)) {\n if (consumer.claimedPatterns.has(route.pattern)) {\n logger.info(\n `yielding ${route.pattern} to your own src/pages file (docs route not injected)`\n );\n continue;\n }\n injectRoute({ pattern: route.pattern, entrypoint: route.entrypoint, prerender: true });\n }\n\n payload = {\n ...cfg,\n env,\n // Read by the catch-all's getStaticPaths so no path is emitted twice.\n ownedByConsumer: consumer.ownedPaths,\n };\n\n // So `_group.yaml` edits reload in dev.\n if (command === 'dev') {\n addWatchFile(new URL(`./${cfg.contentDir}/`, config.srcDir));\n }\n\n const integrationNames = new Set(config.integrations.map((i) => i.name));\n const added: AstroIntegration[] = [];\n\n if (cfg.autoIntegrations) {\n if (!integrationNames.has('@astrojs/mdx')) {\n const { default: mdx } = await import('@astrojs/mdx');\n added.push(mdx());\n }\n if (!integrationNames.has('@astrojs/react')) {\n const { default: react } = await import('@astrojs/react');\n added.push(react());\n }\n if (cfg.search.provider === 'pagefind' && !integrationNames.has('pagefind')) {\n added.push(pagefindIntegration());\n }\n }\n\n const vitePlugins: unknown[] = [virtualConfigPlugin(() => payload)];\n\n // Shiki tokenises at build time and needs no grammars emitted.\n if (cfg.code.highlighter === 'codeblock') {\n vitePlugins.push(microlighterGrammarsPlugin(config.root, logger));\n }\n\n if (cfg.autoIntegrations) {\n // Cast first: `.flat(Infinity)` over Vite's recursive PluginOption hits TS2589.\n const existing = (config.vite?.plugins ?? []) as unknown[];\n const hasTailwind = existing\n .flat(Infinity as 1)\n .some(\n (p) =>\n typeof (p as { name?: string })?.name === 'string' &&\n (p as { name: string }).name.includes('tailwind')\n );\n if (!hasTailwind) {\n const { default: tailwindcss } = await import('@tailwindcss/vite');\n vitePlugins.push(tailwindcss());\n }\n }\n\n // Typed loosely on purpose: inlining this hits \"type instantiation is excessively deep\".\n const markdown: Record<string, unknown> =\n cfg.code.highlighter === 'codeblock'\n ? {\n // Shiki must be off so the `pre` override receives raw source.\n syntaxHighlight: false,\n }\n : {\n shikiConfig: {\n themes: cfg.code.themes,\n defaultColor: false,\n wrap: cfg.code.wrap,\n ...(cfg.code.langs.length ? { langs: cfg.code.langs } : {}),\n },\n };\n\n // Astro does not apply `base` to authored markdown links. MDX inherits these via extendMarkdownConfig.\n markdown.rehypePlugins = [\n [rehypeBaseUrl, { base: config.base }],\n rehypeProseScope,\n rehypeTableColumns,\n ...(cfg.code.highlighter === 'codeblock' ? [rehypeCodeFence] : []),\n ];\n\n updateConfig({\n integrations: added,\n vite: { plugins: vitePlugins as never },\n markdown,\n } as never);\n },\n\n 'astro:config:done'({ injectTypes }) {\n injectTypes({\n filename: 'types.d.ts',\n content: [\n `declare module 'virtual:eqty-docs/config' {`,\n ` const config: import('@eqtylab/docs').DocsConfig & {`,\n ` env: import('@eqtylab/docs').DocsEnv;`,\n ` ownedByConsumer: string[];`,\n ` };`,\n ` export default config;`,\n `}`,\n '',\n ].join('\\n'),\n });\n },\n\n 'astro:routes:resolved'({ routes, logger }) {\n // Catches collisions the filesystem scan cannot see.\n const seen = new Map<string, string>();\n for (const route of routes as Array<{ pattern: string; entrypoint: string }>) {\n const previous = seen.get(route.pattern);\n if (previous && previous !== route.entrypoint) {\n logger.warn(\n `Route ${route.pattern} is claimed twice:\\n ${previous}\\n ${route.entrypoint}\\n` +\n `One of them will be overwritten in the static build.`\n );\n }\n seen.set(route.pattern, route.entrypoint);\n }\n },\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/assert-mdx-only.ts","../src/internal/microlighter-grammars.ts","../src/internal/pagefind.ts","../src/internal/rehype-code-fence.ts","../src/internal/rehype-prose-scope.ts","../src/internal/rehype-table-columns.ts","../src/internal/scan-consumer-pages.ts","../src/internal/virtual-config.ts","../src/index.ts"],"names":["path","fileURLToPath","visit","globSync"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Only MDX supports the component overrides and the loader globs `.mdx` only,\n * so a stray `.md` would be silently absent from the site. Fail loudly instead.\n */\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { globSync } from 'tinyglobby';\n\nexport function assertMdxOnly(contentDir: URL): void {\n const dir = fileURLToPath(contentDir);\n\n let strays: string[] = [];\n try {\n strays = globSync(['**/*.md'], { cwd: dir, absolute: false });\n } catch {\n return;\n }\n if (strays.length === 0) return;\n\n const list = strays\n .sort()\n .map((file) => ` - ${file} -> ${file.replace(/\\.md$/i, '.mdx')}`)\n .join('\\n');\n\n throw new Error(\n `[@eqtylab/docs] Found ${strays.length} Markdown file${strays.length > 1 ? 's' : ''} in ` +\n `${path.relative(process.cwd(), dir) || dir}:\\n${list}\\n\\n` +\n `Docs content must be .mdx. Only MDX supports the component overrides that render\\n` +\n `tables, code fences and callouts through Equality, so a .md page would look\\n` +\n `different from every other page. Renaming is usually the only change needed --\\n` +\n `MDX is a superset of Markdown.`\n );\n}\n","/**\n * Emits microlighter's grammar modules beside the chunks that ask for them.\n * CodeBlock loads grammars with `import('./grammars/' + language)`, which no\n * bundler can expand; without this the build succeeds and code renders unhighlighted.\n */\nimport { readdirSync, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\nimport type { AstroIntegrationLogger } from 'astro';\nimport type { Plugin } from 'vite';\n\n/** Residue of the dynamic import in the emitted chunk. */\nconst GRAMMAR_IMPORT = 'grammars/${';\n\n/** Two hops from the consumer: microlighter is a dependency of @eqtylab/equality, which is only a peer here. */\nfunction findGrammarDir(projectRoot: URL): string {\n const requireFromProject = createRequire(new URL('package.json', projectRoot));\n const equalityEntry = requireFromProject.resolve('@eqtylab/equality');\n const requireFromEquality = createRequire(equalityEntry);\n return path.resolve(path.dirname(requireFromEquality.resolve('microlighter')), 'grammars');\n}\n\nexport function microlighterGrammarsPlugin(\n projectRoot: URL,\n logger: AstroIntegrationLogger\n): Plugin {\n return {\n name: 'eqty-docs:microlighter-grammars',\n apply: 'build',\n generateBundle(_options, bundle) {\n const directories = new Set(\n Object.values(bundle)\n .filter((output) => output.type === 'chunk' && output.code.includes(GRAMMAR_IMPORT))\n .map((output) => path.posix.dirname(output.fileName))\n );\n if (directories.size === 0) return;\n\n let grammarDir: string;\n let grammars: string[];\n try {\n grammarDir = findGrammarDir(projectRoot);\n grammars = readdirSync(grammarDir).filter((file) => file.endsWith('.js'));\n } catch (error) {\n // Warn rather than fail the build over highlighting.\n logger.warn(\n 'Code blocks ask for microlighter grammars, but they could not be resolved. ' +\n 'Fenced code will render unhighlighted. Check that @eqtylab/equality is ' +\n `installed in this project.\\n ${String(error)}`\n );\n return;\n }\n\n for (const directory of directories) {\n for (const grammar of grammars) {\n this.emitFile({\n type: 'asset',\n fileName:\n directory === '.' ? `grammars/${grammar}` : `${directory}/grammars/${grammar}`,\n source: readFileSync(path.resolve(grammarDir, grammar), 'utf8'),\n });\n }\n }\n },\n };\n}\n","/**\n * Not `astro-pagefind`: it ships TypeScript, and Node will not compile that under\n * node_modules when this integration reaches it from its own bundle.\n *\n * The build writes the index; dev serves that same index off disk, so it always\n * describes the last build.\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { AstroIntegration } from 'astro';\n\nconst INDEX_DIR = 'pagefind';\n\n/** Everything else Pagefind fetches is read as bytes, so the type never reaches a parser. */\nconst MIME: Record<string, string> = {\n '.js': 'text/javascript',\n '.css': 'text/css',\n '.json': 'application/json',\n '.wasm': 'application/wasm',\n};\n\n/** Pagefind collects errors per step and carries on; any of them means no usable index. */\nfunction failOn(\n errors: string[],\n logger: { error: (message: string) => void },\n what: string\n): void {\n if (!errors.length) return;\n errors.forEach((error) => logger.error(error));\n throw new Error(`[@eqtylab/docs] Pagefind could not ${what}.`);\n}\n\nfunction indexRequest(url: string | undefined, base: string): string | null {\n if (!url) return null;\n const pathname = decodeURIComponent(url.split(/[?#]/)[0]);\n const prefix = `${base.replace(/\\/+$/, '')}/${INDEX_DIR}/`;\n return pathname.startsWith(prefix) ? pathname.slice(prefix.length) : null;\n}\n\nexport function pagefindIntegration(): AstroIntegration {\n let indexDir = '';\n\n return {\n name: '@eqtylab/docs/pagefind',\n hooks: {\n 'astro:config:setup'({ config, logger }) {\n indexDir = path.join(fileURLToPath(config.outDir), INDEX_DIR);\n\n if (config.output === 'server') {\n logger.warn(\n 'Output \"server\" emits no static HTML, so there is nothing for Pagefind to index.'\n );\n }\n },\n\n /** Runs ahead of Vite's static middleware and Astro's handler; move it and `/pagefind/*` 404s. */\n 'astro:server:setup'({ server, logger }) {\n const base = server.config.base ?? '/';\n\n logger.info(\n fs.existsSync(indexDir)\n ? 'serving the search index from the last build; rebuild to pick up edits'\n : 'no search index yet — run `astro build` once to search in dev'\n );\n\n server.middlewares.use((req, res, next) => {\n const requested = indexRequest(req.url, base);\n if (requested === null) return next();\n\n const file = path.join(indexDir, requested);\n // The prefix check is what stops `..` climbing out of the index directory.\n if (!file.startsWith(indexDir + path.sep) || !fs.existsSync(file)) return next();\n\n res.setHeader('Content-Type', MIME[path.extname(file)] ?? 'application/octet-stream');\n // The next build rewrites these in place, and a cached fragment would outlive it.\n res.setHeader('Cache-Control', 'no-store');\n fs.createReadStream(file).pipe(res);\n });\n },\n\n /** The last hook of the build, and the first moment every page exists on disk to read. */\n async 'astro:build:done'({ dir, logger }) {\n const outDir = fileURLToPath(dir);\n const { createIndex } = await import('pagefind');\n\n const { index, errors } = await createIndex();\n failOn(errors, logger, 'create an index');\n if (!index) throw new Error('[@eqtylab/docs] Pagefind returned no index.');\n\n const { page_count, errors: addErrors } = await index.addDirectory({ path: outDir });\n failOn(addErrors, logger, 'index the built output');\n\n const { outputPath, errors: writeErrors } = await index.writeFiles({\n outputPath: path.join(outDir, INDEX_DIR),\n });\n failOn(writeErrors, logger, 'write the index');\n\n logger.info(`indexed ${page_count} pages to ${outputPath}`);\n },\n },\n };\n}\n","/**\n * Lifts each fence's source, language and title onto its `<pre>`. Do not recover\n * the source from the rendered slot: `Astro.slots.render()` escapes in dev but not in build.\n */\nimport { visit } from 'unist-util-visit';\n\ninterface Node {\n type: string;\n tagName?: string;\n value?: string;\n properties?: Record<string, unknown>;\n children?: Node[];\n data?: { meta?: string };\n}\n\nfunction textOf(node: Node): string {\n if (node.type === 'text') return node.value ?? '';\n return (node.children ?? []).map(textOf).join('');\n}\n\nfunction classNames(props: Record<string, unknown> | undefined): string[] {\n const raw = props?.className ?? props?.class;\n if (Array.isArray(raw)) return raw.map(String);\n if (typeof raw === 'string') return raw.split(/\\s+/);\n return [];\n}\n\n/** ```ts title=\"button.tsx\" -> \"button.tsx\" */\nfunction titleFromMeta(meta: string | undefined): string | undefined {\n const match = meta?.match(/(?:^|\\s)title=(?:\"([^\"]*)\"|'([^']*)'|(\\S+))/);\n return match ? (match[1] ?? match[2] ?? match[3]) : undefined;\n}\n\nexport function rehypeCodeFence() {\n return function transformer(tree: unknown) {\n visit(tree as never, 'element', (node: Node) => {\n if (node.tagName !== 'pre') return;\n\n const code = (node.children ?? []).find(\n (child) => child.type === 'element' && child.tagName === 'code'\n );\n if (!code) return;\n\n const language = classNames(code.properties)\n .find((name) => name.startsWith('language-'))\n ?.slice('language-'.length);\n\n const title = titleFromMeta(code.data?.meta);\n\n node.properties = {\n ...node.properties,\n dataCode: textOf(code).replace(/\\n$/, ''),\n ...(language ? { dataLanguage: language } : {}),\n ...(title ? { dataTitle: title } : {}),\n };\n });\n };\n}\n","/**\n * Marks the content a page authored as markdown or as plain HTML, so\n * `prose.css` can typeset it without reaching inside a component.\n *\n * MDX parses a component's children as markdown whenever they sit on their own\n * lines, so `<Badge icon=\"Shield\">\\n Primary\\n</Badge>` renders a `<p>` inside\n * the badge — and prettier puts them there. Authoring discipline cannot fix it;\n * the boundary has to be drawn here. Everything below a capitalised JSX tag is\n * that component's business, `<div>` and friends are the page's own.\n */\nimport { SKIP, visit } from 'unist-util-visit';\n\nconst MARKER = 'data-eq-md';\n\ninterface Attribute {\n type: string;\n name?: string | null;\n}\n\ninterface Node {\n type: string;\n name?: string | null;\n properties?: Record<string, unknown>;\n attributes?: Attribute[];\n}\n\n/** Capitalised or dotted JSX names are components; `div`, `span` and friends are not. */\nfunction isComponent(node: Node): boolean {\n if (node.type !== 'mdxJsxFlowElement' && node.type !== 'mdxJsxTextElement') return false;\n const name = node.name;\n return typeof name === 'string' && (/^[A-Z]/.test(name) || name.includes('.'));\n}\n\n/**\n * Structural components that hold the page's own prose rather than content of their own.\n * Without this a heading or list inside a `<TabItem>` would render untypeset.\n */\nconst CONTAINERS = new Set(['Tabs', 'TabItem']);\n\nfunction isContainer(node: Node): boolean {\n return typeof node.name === 'string' && CONTAINERS.has(node.name);\n}\n\nexport function rehypeProseScope() {\n return function transformer(tree: unknown) {\n visit(tree as never, (node: Node) => {\n // A container's children are the page's own markup, so traversal continues into them.\n // The component tag itself is never page markup and never takes the marker.\n if (isComponent(node)) return isContainer(node) ? undefined : SKIP;\n\n if (node.type === 'element') {\n node.properties = { ...node.properties, dataEqMd: '' };\n return undefined;\n }\n\n // Authored HTML. A JSX fragment has no name and nothing to mark.\n if ((node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') && node.name) {\n const attributes = node.attributes ?? [];\n if (!attributes.some((a) => a.type === 'mdxJsxAttribute' && a.name === MARKER)) {\n attributes.push({ type: 'mdxJsxAttribute', name: MARKER, value: '' } as Attribute);\n }\n node.attributes = attributes;\n }\n\n return undefined;\n });\n };\n}\n","/**\n * Annotates each markdown table with its column count. Equality's `TableContainer`\n * is a CSS grid and collapses to one column without an explicit track list.\n */\nimport { visit } from 'unist-util-visit';\n\ninterface ElementNode {\n type: string;\n tagName?: string;\n properties?: Record<string, unknown>;\n children?: ElementNode[];\n}\n\n/** First `tr` in document order, searching thead before tbody. */\nfunction firstRow(table: ElementNode): ElementNode | undefined {\n let found: ElementNode | undefined;\n visit(table as never, 'element', (node: ElementNode) => {\n if (found) return false;\n if (node.tagName === 'tr') {\n found = node;\n return false;\n }\n return undefined;\n });\n return found;\n}\n\nfunction countCells(row: ElementNode): number {\n return (row.children ?? []).reduce((total, child) => {\n if (child.type !== 'element') return total;\n if (child.tagName !== 'th' && child.tagName !== 'td') return total;\n const span = Number(child.properties?.colSpan ?? child.properties?.colspan ?? 1);\n return total + (Number.isFinite(span) && span > 0 ? span : 1);\n }, 0);\n}\n\nexport function rehypeTableColumns() {\n return function transformer(tree: unknown) {\n visit(tree as never, 'element', (node: ElementNode) => {\n if (node.tagName !== 'table') return;\n const row = firstRow(node);\n const count = row ? countCells(row) : 0;\n if (count <= 0) return;\n node.properties = { ...node.properties, dataColumnCount: String(count) };\n });\n };\n}\n","/**\n * Routes the consumer's own `src/pages` already claim. Astro does NOT de-duplicate\n * injected routes against file-based ones: a path claimed by both is emitted\n * twice and the winner is write order, so yielding has to be explicit here.\n */\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { globSync } from 'tinyglobby';\n\nconst PAGE_EXTENSIONS = ['astro', 'md', 'mdx', 'html', 'ts', 'js'];\n\nexport interface ConsumerPages {\n /** Concrete route paths the consumer's pages generate, normalised without trailing slash. */\n ownedPaths: string[];\n /** Route patterns claimed by consumer pages, e.g. '/[...slug]' or '/404'. */\n claimedPatterns: Set<string>;\n}\n\n/** `index.astro` -> '', `a/b.astro` -> '/a/b', `[...slug].astro` -> '/[...slug]' */\nfunction toRoutePath(relative: string): string {\n const withoutExt = relative.replace(/\\.[^./]+$/, '');\n const segments = withoutExt.split(path.sep).join('/').split('/').filter(Boolean);\n if (segments.at(-1) === 'index') segments.pop();\n return '/' + segments.join('/');\n}\n\nexport function scanConsumerPages(srcDir: URL): ConsumerPages {\n const pagesDir = fileURLToPath(new URL('./pages/', srcDir));\n\n let files: string[] = [];\n try {\n files = globSync([`**/*.{${PAGE_EXTENSIONS.join(',')}}`], {\n cwd: pagesDir,\n absolute: false,\n });\n } catch {\n // No src/pages: a docs-only site.\n return { ownedPaths: [], claimedPatterns: new Set() };\n }\n\n const ownedPaths: string[] = [];\n const claimedPatterns = new Set<string>();\n\n for (const file of files) {\n // Astro ignores files and directories prefixed with `_`.\n if (file.split(path.sep).some((segment) => segment.startsWith('_'))) continue;\n\n const routePath = toRoutePath(file);\n claimedPatterns.add(routePath === '' ? '/' : routePath);\n\n if (!/[[\\]]/.test(file)) {\n ownedPaths.push(routePath.replace(/\\/+$/, '') || '/');\n }\n }\n\n return { ownedPaths, claimedPatterns };\n}\n","/** Serves the resolved config to runtime components, which ship from node_modules and cannot reach the consumer's project by path. */\nimport type { Plugin } from 'vite';\n\nconst MODULE_ID = 'virtual:eqty-docs/config';\nconst RESOLVED_ID = '\\0' + MODULE_ID;\n\nexport function virtualConfigPlugin(getPayload: () => Record<string, unknown>): Plugin {\n return {\n name: 'eqty-docs:virtual-config',\n resolveId(id) {\n return id === MODULE_ID ? RESOLVED_ID : null;\n },\n load(id) {\n if (id !== RESOLVED_ID) return null;\n return `export default ${JSON.stringify(getPayload())};`;\n },\n };\n}\n","import { fileURLToPath } from 'node:url';\nimport type { AstroIntegration } from 'astro';\n\nimport { resolveConfig, type DocsConfig, type DocsUserConfig } from './config.ts';\nimport { resolveDocsEnv, type DocsEnv } from './env.ts';\nimport { assertMdxOnly } from './internal/assert-mdx-only.ts';\nimport { microlighterGrammarsPlugin } from './internal/microlighter-grammars.ts';\nimport { pagefindIntegration } from './internal/pagefind.ts';\nimport { rehypeBaseUrl } from './internal/rehype-base-url.ts';\nimport { rehypeCodeFence } from './internal/rehype-code-fence.ts';\nimport { rehypeProseScope } from './internal/rehype-prose-scope.ts';\nimport { rehypeTableColumns } from './internal/rehype-table-columns.ts';\nimport { scanConsumerPages } from './internal/scan-consumer-pages.ts';\nimport { virtualConfigPlugin } from './internal/virtual-config.ts';\n\nexport { resolveConfig, type DocsConfig, type DocsUserConfig } from './config.ts';\nexport { resolveDocsEnv, type DocsEnv } from './env.ts';\n// Do not re-export the loaders: this entry runs in Node when astro.config loads,\n// and they import `astro:content`, which only exists in the Vite graph.\nexport { docsSchema, groupSchema, badgeSchema } from './schema.ts';\nexport * from './types.ts';\n\nexport interface DocsIntegrationOptions extends DocsUserConfig {\n /** Build environment for versioned deploys. Defaults to `resolveDocsEnv()`. */\n env?: Partial<DocsEnv>;\n}\n\n/** Route patterns the integration would like to own, paired with their entrypoints. */\nfunction plannedRoutes(cfg: DocsConfig) {\n const prefix = cfg.pathPrefix ? `/${cfg.pathPrefix.replace(/^\\/|\\/$/g, '')}` : '';\n const routes: Array<{ pattern: string; entrypoint: string; enabled: boolean }> = [\n {\n pattern: `${prefix}/[...slug]`,\n entrypoint: '@eqtylab/docs/routes/docs.astro',\n enabled: cfg.routing.injectPages,\n },\n {\n pattern: `${prefix}/[...slug].md`,\n entrypoint: '@eqtylab/docs/routes/docs-md.ts',\n enabled: cfg.routing.markdownTwins,\n },\n {\n pattern: '/llms.txt',\n entrypoint: '@eqtylab/docs/routes/llms-txt.ts',\n enabled: cfg.routing.markdownTwins,\n },\n {\n pattern: '/404',\n entrypoint: '@eqtylab/docs/routes/not-found.astro',\n enabled: cfg.routing.notFound,\n },\n ];\n return routes.filter((r) => r.enabled);\n}\n\nexport default function docs(\n options: DocsIntegrationOptions = {} as DocsIntegrationOptions\n): AstroIntegration {\n const { env: envOverrides, ...userConfig } = options;\n const cfg = resolveConfig(userConfig);\n const env = resolveDocsEnv(envOverrides);\n\n let payload: Record<string, unknown> = {};\n\n return {\n name: '@eqtylab/docs',\n hooks: {\n async 'astro:config:setup'(params) {\n const { config, injectRoute, injectScript, updateConfig, addWatchFile, logger, command } =\n params;\n\n assertMdxOnly(new URL(`./${cfg.contentDir}/`, config.srcDir));\n\n const consumer = scanConsumerPages(config.srcDir);\n\n for (const route of plannedRoutes(cfg)) {\n if (consumer.claimedPatterns.has(route.pattern)) {\n logger.info(\n `yielding ${route.pattern} to your own src/pages file (docs route not injected)`\n );\n continue;\n }\n injectRoute({ pattern: route.pattern, entrypoint: route.entrypoint, prerender: true });\n }\n\n payload = {\n ...cfg,\n env,\n // Read by the catch-all's getStaticPaths so no path is emitted twice.\n ownedByConsumer: consumer.ownedPaths,\n };\n\n // So `_group.yaml` edits reload in dev.\n if (command === 'dev') {\n addWatchFile(new URL(`./${cfg.contentDir}/`, config.srcDir));\n }\n\n const integrationNames = new Set(config.integrations.map((i) => i.name));\n const added: AstroIntegration[] = [];\n\n if (cfg.autoIntegrations) {\n if (!integrationNames.has('@astrojs/mdx')) {\n const { default: mdx } = await import('@astrojs/mdx');\n added.push(mdx());\n }\n if (!integrationNames.has('@astrojs/react')) {\n const { default: react } = await import('@astrojs/react');\n added.push(react());\n }\n if (cfg.search.provider === 'pagefind' && !integrationNames.has('pagefind')) {\n added.push(pagefindIntegration());\n }\n }\n\n const vitePlugins: unknown[] = [virtualConfigPlugin(() => payload)];\n\n // Shiki tokenises at build time and needs no grammars emitted.\n if (cfg.code.highlighter === 'codeblock') {\n vitePlugins.push(microlighterGrammarsPlugin(config.root, logger));\n }\n\n if (cfg.autoIntegrations) {\n // Cast first: `.flat(Infinity)` over Vite's recursive PluginOption hits TS2589.\n const existing = (config.vite?.plugins ?? []) as unknown[];\n const hasTailwind = existing\n .flat(Infinity as 1)\n .some(\n (p) =>\n typeof (p as { name?: string })?.name === 'string' &&\n (p as { name: string }).name.includes('tailwind')\n );\n if (!hasTailwind) {\n const { default: tailwindcss } = await import('@tailwindcss/vite');\n vitePlugins.push(tailwindcss());\n }\n }\n\n // Typed loosely on purpose: inlining this hits \"type instantiation is excessively deep\".\n const markdown: Record<string, unknown> =\n cfg.code.highlighter === 'codeblock'\n ? {\n // Shiki must be off so the `pre` override receives raw source.\n syntaxHighlight: false,\n }\n : {\n shikiConfig: {\n themes: cfg.code.themes,\n defaultColor: false,\n wrap: cfg.code.wrap,\n ...(cfg.code.langs.length ? { langs: cfg.code.langs } : {}),\n },\n };\n\n // Astro does not apply `base` to authored markdown links. MDX inherits these via extendMarkdownConfig.\n markdown.rehypePlugins = [\n [rehypeBaseUrl, { base: config.base }],\n rehypeProseScope,\n rehypeTableColumns,\n ...(cfg.code.highlighter === 'codeblock' ? [rehypeCodeFence] : []),\n ];\n\n // Resolve against the project root first, or a './...' path means different things\n // in dev and in a build.\n const resolveAsset = (spec: string) =>\n spec.startsWith('.') ? fileURLToPath(new URL(spec, config.root)) : spec;\n\n for (const href of cfg.customCss) {\n injectScript('page-ssr', `import ${JSON.stringify(resolveAsset(href))};`);\n }\n for (const src of cfg.clientScripts) {\n injectScript('page', `import ${JSON.stringify(resolveAsset(src))};`);\n }\n\n updateConfig({\n integrations: added,\n vite: { plugins: vitePlugins as never },\n markdown,\n } as never);\n },\n\n 'astro:config:done'({ injectTypes }) {\n injectTypes({\n filename: 'types.d.ts',\n content: [\n `declare module 'virtual:eqty-docs/config' {`,\n ` const config: import('@eqtylab/docs').DocsConfig & {`,\n ` env: import('@eqtylab/docs').DocsEnv;`,\n ` ownedByConsumer: string[];`,\n ` };`,\n ` export default config;`,\n `}`,\n '',\n ].join('\\n'),\n });\n },\n\n 'astro:routes:resolved'({ routes, logger }) {\n // Catches collisions the filesystem scan cannot see.\n const seen = new Map<string, string>();\n for (const route of routes as Array<{ pattern: string; entrypoint: string }>) {\n const previous = seen.get(route.pattern);\n if (previous && previous !== route.entrypoint) {\n logger.warn(\n `Route ${route.pattern} is claimed twice:\\n ${previous}\\n ${route.entrypoint}\\n` +\n `One of them will be overwritten in the static build.`\n );\n }\n seen.set(route.pattern, route.entrypoint);\n }\n },\n },\n };\n}\n"]}
@@ -0,0 +1,16 @@
1
+ ---
2
+ /**
3
+ * One panel of a `<Tabs>` set. Emits nothing but a marked section: `Tabs.astro` recovers the
4
+ * label from it and re-emits the body, because Astro hands a framework component its children
5
+ * as opaque pre-rendered HTML and nothing inside React could read this `label`.
6
+ */
7
+ interface Props {
8
+ label: string;
9
+ /** Lucide icon name. */
10
+ icon?: string;
11
+ }
12
+
13
+ const { label, icon } = Astro.props;
14
+ ---
15
+
16
+ <section data-eq-tab-panel data-label={label} data-icon={icon}><slot /></section>
@@ -0,0 +1,121 @@
1
+ ---
2
+ /**
3
+ * `<Tabs><TabItem label="…">` for MDX, on top of Equality's `Tabs`.
4
+ *
5
+ * Labels are recovered from the rendered slot because Astro hands a framework component its
6
+ * children as opaque pre-rendered HTML - nothing inside React can read a `<TabItem>`'s
7
+ * `label`. Matching is on `data-eq-tab-panel`, this package's own marker, never on
8
+ * `data-label` alone, so authored content cannot be mistaken for a panel.
9
+ */
10
+ import GithubSlugger from 'github-slugger';
11
+
12
+ import TabsBridge from './TabsBridge.tsx';
13
+
14
+ interface Props {
15
+ /** Tab sets sharing a key switch together, and the reader's choice is remembered. */
16
+ syncKey?: string;
17
+ }
18
+
19
+ const { syncKey } = Astro.props;
20
+
21
+ const slotHtml = await Astro.slots.render('default');
22
+
23
+ if (/\bdata-eq-tabs\b/.test(slotHtml)) {
24
+ throw new Error('[@eqtylab/docs] Nested <Tabs> are not supported.');
25
+ }
26
+
27
+ interface Panel {
28
+ label: string;
29
+ icon?: string;
30
+ html: string;
31
+ }
32
+
33
+ const OPEN = /<section\b([^>]*)>/gi;
34
+ const SECTION = /<(\/?)section\b[^>]*>/gi;
35
+
36
+ const NAMED: Record<string, string> = {
37
+ amp: '&',
38
+ lt: '<',
39
+ gt: '>',
40
+ quot: '"',
41
+ apos: "'",
42
+ };
43
+
44
+ /**
45
+ * Attribute values arrive escaped, and a label like "BIOS & Host Config" is ordinary. One
46
+ * pass, not chained replaces: decoding named then numeric would turn a literal `&amp;#38;`
47
+ * into a bare `&`.
48
+ */
49
+ function decode(value: string): string {
50
+ return value.replace(
51
+ /&(?:#(\d+)|#x([0-9a-f]+)|(amp|lt|gt|quot|apos));/gi,
52
+ (match: string, dec?: string, hex?: string, name?: string) => {
53
+ if (dec) return String.fromCodePoint(Number(dec));
54
+ if (hex) return String.fromCodePoint(parseInt(hex, 16));
55
+ return (name && NAMED[name.toLowerCase()]) || match;
56
+ }
57
+ );
58
+ }
59
+
60
+ function attribute(attrs: string, name: string): string | undefined {
61
+ const match = new RegExp(`\\b${name}="([^"]*)"`, 'i').exec(attrs);
62
+ return match ? decode(match[1] as string) : undefined;
63
+ }
64
+
65
+ /** Depth-counted, so a panel may contain sections of its own. */
66
+ function closeAt(source: string, from: number): number {
67
+ SECTION.lastIndex = from;
68
+ let depth = 1;
69
+ let match: RegExpExecArray | null;
70
+ while ((match = SECTION.exec(source))) {
71
+ depth += match[1] ? -1 : 1;
72
+ if (depth === 0) return match.index;
73
+ }
74
+ return -1;
75
+ }
76
+
77
+ function readPanels(source: string): Panel[] {
78
+ const found: Panel[] = [];
79
+ OPEN.lastIndex = 0;
80
+ let match: RegExpExecArray | null;
81
+ while ((match = OPEN.exec(source))) {
82
+ const attrs = match[1] ?? '';
83
+ if (!/\bdata-eq-tab-panel\b/.test(attrs)) continue;
84
+ const bodyStart = OPEN.lastIndex;
85
+ const bodyEnd = closeAt(source, bodyStart);
86
+ if (bodyEnd < 0) break;
87
+ found.push({
88
+ label: attribute(attrs, 'data-label') ?? '',
89
+ icon: attribute(attrs, 'data-icon'),
90
+ html: source.slice(bodyStart, bodyEnd),
91
+ });
92
+ OPEN.lastIndex = bodyEnd;
93
+ }
94
+ return found;
95
+ }
96
+
97
+ const panels = readPanels(slotHtml);
98
+
99
+ if (panels.length === 0) {
100
+ throw new Error('[@eqtylab/docs] <Tabs> needs at least one <TabItem label="…"> child.');
101
+ }
102
+
103
+ const slugger = new GithubSlugger();
104
+ const items = panels.map((panel) => ({
105
+ label: panel.label,
106
+ value: slugger.slug(panel.label || 'tab'),
107
+ icon: panel.icon,
108
+ html: panel.html,
109
+ }));
110
+
111
+ // Equality requires an id, but `staticRender` never renders the motion layoutId that uses it.
112
+ const id = `eq-tabs-${items[0]?.value}`;
113
+ ---
114
+
115
+ <div class="mb-4" data-eq-tabs data-sync-key={syncKey}>
116
+ <TabsBridge id={id} items={items} />
117
+ </div>
118
+
119
+ <script>
120
+ import '@eqtylab/docs/scripts/eq-tabs.ts';
121
+ </script>
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Equality's `Tabs`, server-rendered with no client React.
3
+ *
4
+ * This exists as a React component, rather than as markup in `Tabs.astro`, because the whole
5
+ * Radix tree has to render inside one root: its context does not survive an Astro component
6
+ * boundary, which is why `TableBridge` can get away with a plain `<slot />` and this cannot.
7
+ */
8
+ import { Tabs } from '@eqtylab/equality';
9
+
10
+ export interface TabsBridgeItem {
11
+ label: string;
12
+ value: string;
13
+ icon?: string;
14
+ /** Panel body, already rendered by `Astro.slots.render`. */
15
+ html: string;
16
+ }
17
+
18
+ interface Props {
19
+ id: string;
20
+ items: TabsBridgeItem[];
21
+ }
22
+
23
+ export default function TabsBridge({ id, items }: Props) {
24
+ return (
25
+ <Tabs
26
+ id={id}
27
+ /* Mounts every panel and puts the indicator in every trigger, so `eq-tabs.ts` can
28
+ switch tabs by flipping `data-state` with no React on the page. */
29
+ staticRender
30
+ items={items.map(({ label, value, icon, html }) => ({
31
+ label,
32
+ value,
33
+ icon,
34
+ /* `eq-tabs.ts` pairs synced sets by label; reading it off the trigger's text would
35
+ break as soon as a tab carries an icon or a suffix. */
36
+ triggerProps: { 'data-eq-tab-label': label },
37
+ content: <div dangerouslySetInnerHTML={{ __html: html }} />,
38
+ }))}
39
+ />
40
+ );
41
+ }
@@ -1,2 +1,4 @@
1
1
  /** Public components for MDX authors. `.astro` only: a React component here pulls React into every page. */
2
2
  export { default as Link } from './Link.astro';
3
+ export { default as TabItem } from './TabItem.astro';
4
+ export { default as Tabs } from './Tabs.astro';
@@ -16,7 +16,9 @@ import CONFIG from 'virtual:eqty-docs/config';
16
16
  import AlertBridge from '../components/AlertBridge.astro';
17
17
  import CodeFenceBridge from '../components/CodeFenceBridge.astro';
18
18
  import Link from '../components/Link.astro';
19
+ import TabItem from '../components/TabItem.astro';
19
20
  import TableBridge from '../components/TableBridge.astro';
21
+ import Tabs from '../components/Tabs.astro';
20
22
 
21
23
  const base: Record<string, unknown> = {
22
24
  a: Link,
@@ -24,6 +26,10 @@ const base: Record<string, unknown> = {
24
26
  // An explicit import of Alert from @eqtylab/equality still wins.
25
27
  Alert: AlertBridge,
26
28
 
29
+ // Equality's Tabs, server-rendered. A file-level import still wins, as with Alert.
30
+ Tabs,
31
+ TabItem,
32
+
27
33
  // All hook-free, so they render statically with no client directive.
28
34
  table: TableBridge,
29
35
  thead: TableHeader,
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Tab switching for server-rendered `<Tabs>`. Equality renders them with `staticRender`, so
3
+ * every panel is already in the DOM and selecting one is a `data-state` flip - there is no
4
+ * React on the page to do it. One delegated listener, so it survives view transitions.
5
+ */
6
+ const STORAGE_PREFIX = 'eqty-docs-tabs:';
7
+
8
+ function setOf(node: Element | null): HTMLElement | null {
9
+ return node?.closest<HTMLElement>('[data-eq-tabs]') ?? null;
10
+ }
11
+
12
+ function triggersIn(set: HTMLElement): HTMLElement[] {
13
+ return Array.from(set.querySelectorAll<HTMLElement>('[role="tab"]'));
14
+ }
15
+
16
+ function panelFor(trigger: HTMLElement): HTMLElement | null {
17
+ const id = trigger.getAttribute('aria-controls');
18
+ return id ? document.getElementById(id) : null;
19
+ }
20
+
21
+ function select(set: HTMLElement, chosen: HTMLElement, focus = false): void {
22
+ for (const trigger of triggersIn(set)) {
23
+ const active = trigger === chosen;
24
+ const state = active ? 'active' : 'inactive';
25
+ trigger.setAttribute('aria-selected', String(active));
26
+ trigger.setAttribute('data-state', state);
27
+ // Roving tabindex: the strip is one tab stop, arrows move within it.
28
+ trigger.tabIndex = active ? 0 : -1;
29
+ panelFor(trigger)?.setAttribute('data-state', state);
30
+ }
31
+ if (focus) chosen.focus();
32
+ }
33
+
34
+ function labelOf(trigger: HTMLElement): string {
35
+ return trigger.dataset.eqTabLabel ?? '';
36
+ }
37
+
38
+ function read(key: string): string | null {
39
+ try {
40
+ return window.localStorage.getItem(STORAGE_PREFIX + key);
41
+ } catch {
42
+ return null;
43
+ }
44
+ }
45
+
46
+ function write(key: string, label: string): void {
47
+ try {
48
+ window.localStorage.setItem(STORAGE_PREFIX + key, label);
49
+ } catch {
50
+ // Storage denied; syncing still works for this page view.
51
+ }
52
+ }
53
+
54
+ /** Every other set sharing the key follows. A set without that label is left alone. */
55
+ function sync(key: string, label: string, origin: HTMLElement | null): void {
56
+ for (const set of document.querySelectorAll<HTMLElement>('[data-eq-tabs][data-sync-key]')) {
57
+ if (set === origin || set.dataset.syncKey !== key) continue;
58
+ const match = triggersIn(set).find((trigger) => labelOf(trigger) === label);
59
+ if (match) select(set, match);
60
+ }
61
+ }
62
+
63
+ function activate(set: HTMLElement, trigger: HTMLElement, focus = false): void {
64
+ select(set, trigger, focus);
65
+ const key = set.dataset.syncKey;
66
+ if (!key) return;
67
+ const label = labelOf(trigger);
68
+ write(key, label);
69
+ sync(key, label, set);
70
+ }
71
+
72
+ document.addEventListener('click', (event) => {
73
+ const trigger = (event.target as Element | null)?.closest<HTMLElement>('[role="tab"]');
74
+ const set = setOf(trigger ?? null);
75
+ if (!trigger || !set) return;
76
+ event.preventDefault();
77
+ activate(set, trigger);
78
+ });
79
+
80
+ const MOVES: Record<string, number> = { ArrowRight: 1, ArrowLeft: -1 };
81
+
82
+ document.addEventListener('keydown', (event) => {
83
+ const trigger = (event.target as Element | null)?.closest<HTMLElement>('[role="tab"]');
84
+ const set = setOf(trigger ?? null);
85
+ if (!trigger || !set) return;
86
+
87
+ const triggers = triggersIn(set);
88
+ const from = triggers.indexOf(trigger);
89
+ if (from < 0) return;
90
+
91
+ let to: number;
92
+ if (event.key in MOVES) {
93
+ to = (from + (MOVES[event.key] as number) + triggers.length) % triggers.length;
94
+ } else if (event.key === 'Home') {
95
+ to = 0;
96
+ } else if (event.key === 'End') {
97
+ to = triggers.length - 1;
98
+ } else {
99
+ return;
100
+ }
101
+
102
+ event.preventDefault();
103
+ activate(set, triggers[to] as HTMLElement, true);
104
+ });
105
+
106
+ // Restore remembered choices. Runs after first paint, so a non-default choice visibly settles.
107
+ for (const set of document.querySelectorAll<HTMLElement>('[data-eq-tabs][data-sync-key]')) {
108
+ const key = set.dataset.syncKey;
109
+ if (!key) continue;
110
+ const stored = read(key);
111
+ if (!stored) continue;
112
+ const match = triggersIn(set).find((trigger) => labelOf(trigger) === stored);
113
+ if (match) select(set, match);
114
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@eqtylab/docs",
3
3
  "description": "Astro documentation framework built on the Equality design system",
4
- "version": "0.3.0",
4
+ "version": "0.3.2",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://equality.eqtylab.io/",
7
7
  "repository": {
@@ -106,7 +106,7 @@
106
106
  },
107
107
  "peerDependencies": {
108
108
  "@astrojs/mdx": "^5.0.2",
109
- "@astrojs/react": "^5.0.1",
109
+ "@astrojs/react": "^5.0.1 || ^6.0.0",
110
110
  "@eqtylab/equality": ">=3.2.6 <5",
111
111
  "astro": "^6.0.0",
112
112
  "react": "^18.2.0 || ^19.0.0",
@@ -1,102 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config.ts"],"names":[],"mappings":";;;AAGA,IAAM,UAAA,GAAa,EAAE,MAAA,CAAO;AAAA,EAC1B,KAAA,EAAO,EAAE,MAAA,EAAO;AAAA,EAChB,IAAA,EAAM,EAAE,MAAA,EAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAKf,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC1B,QAAA,EAAU,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAA;AACxB,CAAC,CAAA;AAEM,IAAM,gBAAA,GAAmB,EAAE,MAAA,CAAO;AAAA;AAAA,EAEvC,KAAA,EAAO,EAAE,MAAA,EAAO;AAAA,EAChB,WAAA,EAAa,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA;AAAA,EAEjC,OAAA,EAAS,CAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,cAAc,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM1C,IAAA,EAAM,EACH,MAAA,CAAO;AAAA,IACN,GAAA,EAAK,EAAE,MAAA,EAAO;AAAA;AAAA,IAEd,GAAA,EAAK,CAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,EAAE;AAAA,GAC3B,EACA,QAAA,EAAS;AAAA;AAAA,EAGZ,UAAA,EAAY,CAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,cAAc,CAAA;AAAA;AAAA,EAG7C,UAAA,EAAY,CAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,EAAE,CAAA;AAAA,EAEjC,OAAA,EAAS,EACN,MAAA,CAAO;AAAA;AAAA,IAEN,SAAA,EAAW,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,KAAK,CAAA;AAAA;AAAA,IAEpC,IAAA,EAAM,CAAA,CAAE,IAAA,CAAK,CAAC,OAAA,EAAS,YAAY,QAAQ,CAAC,CAAA,CAAE,OAAA,CAAQ,OAAO,CAAA;AAAA;AAAA,IAE7D,KAAA,EAAO,EAAE,KAAA,CAAM,CAAA,CAAE,KAAK,CAAA,CAAE,OAAA,CAAQ,EAAE;AAAA,GACnC,CAAA,CACA,QAAA,CAAS,EAAE,CAAA;AAAA,EAEd,MAAA,EAAQ,EACL,MAAA,CAAO;AAAA,IACN,OAAO,CAAA,CAAE,KAAA,CAAM,UAAU,CAAA,CAAE,OAAA,CAAQ,EAAE,CAAA;AAAA,IACrC,eAAA,EAAiB,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,IAAI;AAAA,GAC1C,CAAA,CACA,QAAA,CAAS,EAAE,CAAA;AAAA,EAEd,MAAA,EAAQ,EACL,MAAA,CAAO;AAAA;AAAA,IAEN,OAAA,EAAS,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IAC7B,YAAA,EAAc,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,IAAI,CAAA;AAAA,IACtC,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS,GAC3B,CAAA,CACA,QAAA,CAAS,EAAE,CAAA;AAAA,EAEd,eAAA,EAAiB,EACd,KAAA,CAAM;AAAA,IACL,EAAE,MAAA,CAAO;AAAA,MACP,QAAA,EAAU,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,QAAQ,CAAC,CAAA;AAAA,MAClD,QAAA,EAAU,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,QAAQ,CAAC;AAAA,KACnD,CAAA;AAAA,IACD,CAAA,CAAE,QAAQ,KAAK;AAAA,GAChB,CAAA,CACA,QAAA,CAAS,EAAE,CAAA;AAAA,EAEd,IAAA,EAAM,EACH,MAAA,CAAO;AAAA;AAAA,IAEN,WAAA,EAAa,EAAE,IAAA,CAAK,CAAC,aAAa,OAAO,CAAC,CAAA,CAAE,OAAA,CAAQ,WAAW,CAAA;AAAA;AAAA,IAE/D,MAAA,EAAQ,EACL,MAAA,CAAO,EAAE,OAAO,CAAA,CAAE,MAAA,IAAU,IAAA,EAAM,CAAA,CAAE,QAAO,EAAG,EAC9C,OAAA,CAAQ,EAAE,OAAO,cAAA,EAAgB,IAAA,EAAM,eAAe,CAAA;AAAA,IACzD,IAAA,EAAM,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,KAAK,CAAA;AAAA,IAC/B,KAAA,EAAO,EAAE,KAAA,CAAM,CAAA,CAAE,QAAQ,CAAA,CAAE,OAAA,CAAQ,EAAE;AAAA,GACtC,CAAA,CACA,QAAA,CAAS,EAAE,CAAA;AAAA,EAEd,MAAA,EAAQ,EACL,MAAA,CAAO;AAAA;AAAA,IAEN,QAAA,EAAU,EAAE,IAAA,CAAK,CAAC,YAAY,MAAM,CAAC,CAAA,CAAE,OAAA,CAAQ,UAAU;AAAA,GAC1D,CAAA,CACA,QAAA,CAAS,EAAE,CAAA;AAAA,EAEd,OAAA,EAAS,EACN,MAAA,CAAO;AAAA;AAAA,IAEN,WAAA,EAAa,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,IAAI,CAAA;AAAA;AAAA,IAErC,aAAA,EAAe,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,IAAI,CAAA;AAAA,IACvC,QAAA,EAAU,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,IAAI;AAAA,GACnC,CAAA,CACA,QAAA,CAAS,EAAE,CAAA;AAAA,EAEd,KAAA,EAAO,EACJ,MAAA,CAAO;AAAA;AAAA,IAEN,IAAA,EAAM,EAAE,IAAA,CAAK,CAAC,UAAU,QAAQ,CAAC,CAAA,CAAE,OAAA,CAAQ,QAAQ,CAAA;AAAA;AAAA,IAEnD,OAAA,EAAS,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,IAAI;AAAA,GAClC,CAAA,CACA,QAAA,CAAS,EAAE,CAAA;AAAA;AAAA,EAGd,gBAAA,EAAkB,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,IAAI,CAAA;AAAA;AAAA,EAG1C,QAAA,EAAU,CAAA,CAAE,GAAA,EAAI,CAAE,QAAA,EAAS;AAAA;AAAA,EAG3B,OAAA,EAAS,EAAE,KAAA,CAAM,CAAA,CAAE,KAAK,CAAA,CAAE,OAAA,CAAQ,EAAE;AACtC,CAAC;AAKM,SAAS,cAAc,IAAA,EAAkC;AAC9D,EAAA,MAAM,MAAA,GAAS,gBAAA,CAAiB,SAAA,CAAU,IAAI,CAAA;AAC9C,EAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,IAAA,MAAM,MAAA,GAAS,OAAO,KAAA,CAAM,MAAA,CACzB,IAAI,CAAC,CAAA,KAAM,OAAO,CAAA,CAAE,IAAA,CAAK,KAAK,GAAG,CAAA,IAAK,QAAQ,CAAA,EAAA,EAAK,CAAA,CAAE,OAAO,CAAA,CAAE,CAAA,CAC9D,KAAK,IAAI,CAAA;AACZ,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA;AAAA,EAA2C,MAAM,CAAA,CAAE,CAAA;AAAA,EACrE;AACA,EAAA,OAAO,MAAA,CAAO,IAAA;AAChB","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"]}