@unterberg/nivel 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +115 -0
- package/bin/nivel.mjs +3 -0
- package/dist/{chunk-73NPVCDQ.js → chunk-D7IAGT53.js} +56 -26
- package/dist/chunk-D7IAGT53.js.map +1 -0
- package/dist/chunk-DNCQR5NH.js +231 -0
- package/dist/chunk-DNCQR5NH.js.map +1 -0
- package/dist/{chunk-3JJ6TYWL.js → chunk-FARXFRHG.js} +120 -83
- package/dist/chunk-FARXFRHG.js.map +1 -0
- package/dist/chunk-K5ZYRA3G.js +198 -0
- package/dist/chunk-K5ZYRA3G.js.map +1 -0
- package/dist/{chunk-4WTEOEV2.js → chunk-L6ZVB6XH.js} +3 -3
- package/dist/chunk-L6ZVB6XH.js.map +1 -0
- package/dist/{chunk-FLO5CJZH.js → chunk-PYYPYIBD.js} +10 -3
- package/dist/chunk-PYYPYIBD.js.map +1 -0
- package/dist/{chunk-45CLUNJW.js → chunk-Q7JU4J6A.js} +69 -33
- package/dist/chunk-Q7JU4J6A.js.map +1 -0
- package/dist/chunk-UDOIFPCZ.js +1538 -0
- package/dist/chunk-UDOIFPCZ.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +78 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +4 -8
- package/dist/client.js +4 -4
- package/dist/index.d.ts +8 -12
- package/dist/index.js +4 -8
- package/dist/{code-blocks.d.ts → mdx/code-blocks.d.ts} +3 -1
- package/dist/{code-blocks.js → mdx/code-blocks.js} +5 -3
- package/dist/mdx.js +4 -4
- package/dist/mdx.js.map +1 -1
- package/dist/runtime/client.d.ts +1 -1
- package/dist/runtime/client.js +4 -4
- package/dist/runtime/node.d.ts +23 -0
- package/dist/runtime/node.js +24 -0
- package/dist/{types-mvLNHHrf.d.ts → types-j0kEkMA4.d.ts} +47 -24
- package/dist/{config.js → vike.js} +9 -8
- package/dist/vike.js.map +1 -0
- package/package.json +25 -16
- package/tailwind-sources.css +1 -0
- package/assets/nivel/decorators/pattern-light.png +0 -0
- package/assets/nivel/decorators/pattern.png +0 -0
- package/dist/chunk-3JJ6TYWL.js.map +0 -1
- package/dist/chunk-45CLUNJW.js.map +0 -1
- package/dist/chunk-4WTEOEV2.js.map +0 -1
- package/dist/chunk-62MBEYU7.js +0 -1091
- package/dist/chunk-62MBEYU7.js.map +0 -1
- package/dist/chunk-73NPVCDQ.js.map +0 -1
- package/dist/chunk-FLO5CJZH.js.map +0 -1
- package/dist/chunk-PHHK2BAF.js +0 -350
- package/dist/chunk-PHHK2BAF.js.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/runtime/index.d.ts +0 -15
- package/dist/runtime/index.js +0 -18
- /package/dist/{code-blocks.js.map → mdx/code-blocks.js.map} +0 -0
- /package/dist/runtime/{index.js.map → node.js.map} +0 -0
- /package/dist/{config.d.ts → vike.d.ts} +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# nivel engine
|
|
2
|
+
|
|
3
|
+
docs builder proof of concept for generating vike-based documentation sites with a single docs graph as the source of truth.
|
|
4
|
+
|
|
5
|
+
monorepo structure:
|
|
6
|
+
|
|
7
|
+
- `packages/engine`: the reusable `@unterberg/nivel` package
|
|
8
|
+
- `packages/consumer-test`: the reference consumer used to exercise the engine against real docs content, currently based on the [Telefunc docs](https://telefunc.com)
|
|
9
|
+
|
|
10
|
+
## Alpha Status
|
|
11
|
+
|
|
12
|
+
This project is an early proof of concept and should be expected to have rough edges. The main goal is to validate the core engine ideas and architecture, not to provide a polished general-purpose doc builder right now. Some specific things to keep in mind:
|
|
13
|
+
|
|
14
|
+
- Expect breaking changes.
|
|
15
|
+
- The public API is not stable yet. (blackbox)
|
|
16
|
+
- The supported stack fixed currently to Vike + Vite + React.
|
|
17
|
+
- `basePath` is currently fixed to `/docs`.
|
|
18
|
+
- The consumer app in this repo is still the main integration example.
|
|
19
|
+
|
|
20
|
+
If you need a polished general-purpose docpress replacement today, this is not that yet.
|
|
21
|
+
|
|
22
|
+
## What It Does
|
|
23
|
+
|
|
24
|
+
The engine currently owns the core docs runtime:
|
|
25
|
+
|
|
26
|
+
- docs graph validation and resolution
|
|
27
|
+
- generated Vike routes from MDX content
|
|
28
|
+
- shared docs layout pieces such as navbar, sidebar, table of contents, pagination, and meta head wiring
|
|
29
|
+
- MDX setup with built-in docs components and code-block transforms
|
|
30
|
+
- asset handling for engine-owned fonts and shared static assets
|
|
31
|
+
|
|
32
|
+
The intended split is:
|
|
33
|
+
|
|
34
|
+
- the engine owns behavior, runtime wiring, and reusable UI primitives
|
|
35
|
+
- the consumer owns docs content, `docs/docs.graph.ts`, `pages/+docs.ts`, and brand/theme assets
|
|
36
|
+
|
|
37
|
+
## Minimal Shape
|
|
38
|
+
|
|
39
|
+
At the moment, a consumer looks roughly like this:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
// pages/+docs.ts
|
|
43
|
+
import { defineDocsConfig } from '@unterberg/nivel'
|
|
44
|
+
import { docsGraph } from '../docs/docs.graph'
|
|
45
|
+
|
|
46
|
+
export default defineDocsConfig({
|
|
47
|
+
siteTitle: 'My Docs',
|
|
48
|
+
basePath: '/docs',
|
|
49
|
+
graph: docsGraph,
|
|
50
|
+
algolia: {
|
|
51
|
+
appId: 'YOUR_APP_ID',
|
|
52
|
+
apiKey: 'YOUR_SEARCH_ONLY_API_KEY',
|
|
53
|
+
indexName: 'YOUR_INDEX_NAME',
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
// docs/docs.graph.ts
|
|
60
|
+
import { defineDocsGraph } from '@unterberg/nivel'
|
|
61
|
+
|
|
62
|
+
export const docsGraph = defineDocsGraph({
|
|
63
|
+
items: [
|
|
64
|
+
{
|
|
65
|
+
kind: 'section',
|
|
66
|
+
id: 'docs',
|
|
67
|
+
title: 'Documentation',
|
|
68
|
+
items: [
|
|
69
|
+
{
|
|
70
|
+
kind: 'page',
|
|
71
|
+
id: 'quickStart',
|
|
72
|
+
title: 'Quick Start',
|
|
73
|
+
slug: 'quick-start',
|
|
74
|
+
source: 'content/quick-start/content.mdx',
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
})
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Then the consumer wires:
|
|
83
|
+
|
|
84
|
+
- `@unterberg/nivel/vike` into Vike config
|
|
85
|
+
- `MetaHead` in global `+Head`
|
|
86
|
+
- `AppLayout` in global `+Layout`
|
|
87
|
+
- `nivel prepare` before dev/build/typecheck
|
|
88
|
+
- `@import '@unterberg/nivel/tailwind-sources.css'` in the consumer Tailwind entry
|
|
89
|
+
|
|
90
|
+
Algolia search is optional. When configured, `apiKey` must be a search-only public key because requests are made from the browser.
|
|
91
|
+
|
|
92
|
+
## Current Limitations
|
|
93
|
+
|
|
94
|
+
- The package is still alpha and should be expected to change.
|
|
95
|
+
- The supported stack is currently narrow: Vike + Vite + React.
|
|
96
|
+
- `basePath` is currently fixed to `/docs`.
|
|
97
|
+
- The package is still validated mainly through one real consumer, not a broad set of independent adopters.
|
|
98
|
+
- The setup and examples are still catching up with the implementation, so the integration story is not fully polished yet.
|
|
99
|
+
|
|
100
|
+
## Future Plans
|
|
101
|
+
|
|
102
|
+
- Continue hardening the engine/consumer split so docs behavior stays in `@unterberg/nivel` and the consumer remains thin.
|
|
103
|
+
- Improve the package-level docs and examples so setup is easier to understand without reading the consumer app in detail.
|
|
104
|
+
- Reduce hard-coded assumptions where it makes sense, starting with the areas that currently make the engine feel too tied to its first consumer.
|
|
105
|
+
|
|
106
|
+
## Commands
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
pnpm install
|
|
110
|
+
pnpm dev
|
|
111
|
+
pnpm build
|
|
112
|
+
pnpm typecheck
|
|
113
|
+
pnpm format
|
|
114
|
+
pnpm knip
|
|
115
|
+
```
|
package/bin/nivel.mjs
ADDED
|
@@ -2,9 +2,9 @@ import {
|
|
|
2
2
|
nivelAssetUrl,
|
|
3
3
|
resolvePublicAssetUrl,
|
|
4
4
|
withSiteBaseUrl
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-PYYPYIBD.js";
|
|
6
6
|
|
|
7
|
-
// src/
|
|
7
|
+
// src/docs/resolveDocsConfig.ts
|
|
8
8
|
var normalizeBasePath = (value) => {
|
|
9
9
|
const normalized = value.trim().replace(/^\/+|\/+$/g, "");
|
|
10
10
|
return `/${normalized}`;
|
|
@@ -31,13 +31,19 @@ var normalizeSourcePath = (value) => {
|
|
|
31
31
|
}
|
|
32
32
|
return normalizedSegments.join("/");
|
|
33
33
|
};
|
|
34
|
-
var getSectionHref = (items) => {
|
|
34
|
+
var getSectionHref = (items, visibleOnly = false) => {
|
|
35
35
|
for (const item of items) {
|
|
36
36
|
if (item.kind === "page") {
|
|
37
|
+
if (visibleOnly && !item.showInNav) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
37
40
|
return item.href;
|
|
38
41
|
}
|
|
39
42
|
if (item.kind === "group") {
|
|
40
|
-
|
|
43
|
+
if (visibleOnly && !item.showInNav) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const href = getSectionHref(item.items, visibleOnly);
|
|
41
47
|
if (href) {
|
|
42
48
|
return href;
|
|
43
49
|
}
|
|
@@ -45,6 +51,13 @@ var getSectionHref = (items) => {
|
|
|
45
51
|
}
|
|
46
52
|
return null;
|
|
47
53
|
};
|
|
54
|
+
var resolveNavigationHref = (value, fieldName) => {
|
|
55
|
+
const normalized = value.trim();
|
|
56
|
+
if (!normalized) {
|
|
57
|
+
throw new Error(`Docs ${fieldName} must be a non-empty string.`);
|
|
58
|
+
}
|
|
59
|
+
return normalizePathname(normalized);
|
|
60
|
+
};
|
|
48
61
|
var resolveThemeConfig = (theme) => {
|
|
49
62
|
return {
|
|
50
63
|
light: theme?.light ?? "consumer-light",
|
|
@@ -105,6 +118,30 @@ var resolvePartnersConfig = (partners) => {
|
|
|
105
118
|
gold: (partners?.gold ?? []).map(resolvePartner)
|
|
106
119
|
};
|
|
107
120
|
};
|
|
121
|
+
var requireTrimmedString = (value, fieldName) => {
|
|
122
|
+
const normalized = value.trim();
|
|
123
|
+
if (!normalized) {
|
|
124
|
+
throw new Error(`Docs algolia config "${fieldName}" must be a non-empty string.`);
|
|
125
|
+
}
|
|
126
|
+
return normalized;
|
|
127
|
+
};
|
|
128
|
+
var resolveAlgoliaConfig = (algolia) => {
|
|
129
|
+
if (!algolia) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
appId: requireTrimmedString(algolia.appId, "appId"),
|
|
134
|
+
apiKey: requireTrimmedString(algolia.apiKey, "apiKey"),
|
|
135
|
+
indexName: requireTrimmedString(algolia.indexName, "indexName"),
|
|
136
|
+
fields: {
|
|
137
|
+
href: algolia.fields?.href?.trim() || "href",
|
|
138
|
+
title: algolia.fields?.title?.trim() || "title",
|
|
139
|
+
excerpt: algolia.fields?.excerpt?.trim() || "excerpt",
|
|
140
|
+
sectionTitle: algolia.fields?.sectionTitle?.trim() || "sectionTitle"
|
|
141
|
+
},
|
|
142
|
+
searchParams: algolia.searchParams ?? {}
|
|
143
|
+
};
|
|
144
|
+
};
|
|
108
145
|
var normalizeAliases = (aliases, slug) => {
|
|
109
146
|
const normalizedAliases = /* @__PURE__ */ new Set();
|
|
110
147
|
for (const alias of aliases ?? []) {
|
|
@@ -125,7 +162,6 @@ var resolveDocsConfig = (config) => {
|
|
|
125
162
|
const pageAliases = /* @__PURE__ */ new Set();
|
|
126
163
|
const groupIds = /* @__PURE__ */ new Set();
|
|
127
164
|
const sectionIds = /* @__PURE__ */ new Set();
|
|
128
|
-
const dividerIds = /* @__PURE__ */ new Set();
|
|
129
165
|
const pages = [];
|
|
130
166
|
const navbarItems = [];
|
|
131
167
|
const resolveSidebarNodes = (nodes, sectionId) => {
|
|
@@ -139,22 +175,12 @@ var resolveDocsConfig = (config) => {
|
|
|
139
175
|
kind: "group",
|
|
140
176
|
id: node.id,
|
|
141
177
|
title: node.title,
|
|
178
|
+
href: node.href ? resolveNavigationHref(node.href, `group "${node.id}" href`) : void 0,
|
|
179
|
+
showInNav: node.showInNav ?? true,
|
|
142
180
|
collapsible: node.collapsible,
|
|
143
181
|
items: resolveSidebarNodes(node.items, sectionId)
|
|
144
182
|
};
|
|
145
183
|
}
|
|
146
|
-
if (node.kind === "divider") {
|
|
147
|
-
const divider = node;
|
|
148
|
-
if (dividerIds.has(divider.id)) {
|
|
149
|
-
throw new Error(`Duplicate docs divider id "${divider.id}".`);
|
|
150
|
-
}
|
|
151
|
-
dividerIds.add(divider.id);
|
|
152
|
-
return {
|
|
153
|
-
kind: "divider",
|
|
154
|
-
id: divider.id,
|
|
155
|
-
title: divider.title
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
184
|
if (node.kind !== "page") {
|
|
159
185
|
throw new Error(`Invalid docs sidebar node: ${JSON.stringify(node)}`);
|
|
160
186
|
}
|
|
@@ -198,7 +224,8 @@ var resolveDocsConfig = (config) => {
|
|
|
198
224
|
id: pageNode.id,
|
|
199
225
|
title: pageNode.title,
|
|
200
226
|
navTitle: pageNode.navTitle ?? pageNode.title,
|
|
201
|
-
href
|
|
227
|
+
href,
|
|
228
|
+
showInNav: pageNode.showInNav ?? true
|
|
202
229
|
};
|
|
203
230
|
});
|
|
204
231
|
};
|
|
@@ -211,7 +238,8 @@ var resolveDocsConfig = (config) => {
|
|
|
211
238
|
}
|
|
212
239
|
sectionIds.add(section.id);
|
|
213
240
|
const items = resolveSidebarNodes(section.items, section.id);
|
|
214
|
-
const
|
|
241
|
+
const firstVisibleHref = getSectionHref(items, true);
|
|
242
|
+
const href = section.href ? resolveNavigationHref(section.href, `section "${section.id}" href`) : firstVisibleHref ?? getSectionHref(items);
|
|
215
243
|
if (!href) {
|
|
216
244
|
throw new Error(`Docs section "${section.id}" must contain at least one page.`);
|
|
217
245
|
}
|
|
@@ -241,6 +269,7 @@ var resolveDocsConfig = (config) => {
|
|
|
241
269
|
brand: resolveBrandConfig(config.brand, config.siteTitle),
|
|
242
270
|
head: resolveHeadConfig(config.head),
|
|
243
271
|
partners: resolvePartnersConfig(config.partners),
|
|
272
|
+
algolia: resolveAlgoliaConfig(config.algolia),
|
|
244
273
|
pages,
|
|
245
274
|
sections,
|
|
246
275
|
navbarItems
|
|
@@ -254,7 +283,8 @@ var getResolvedPageById = (config, pageId) => {
|
|
|
254
283
|
return page;
|
|
255
284
|
};
|
|
256
285
|
var getResolvedSectionById = (config, sectionId) => {
|
|
257
|
-
|
|
286
|
+
const sections = config.sections ?? config.sidebarSections ?? [];
|
|
287
|
+
return sections.find((section) => section.id === sectionId) ?? null;
|
|
258
288
|
};
|
|
259
289
|
var getResolvedPageByPathname = (config, pathname) => {
|
|
260
290
|
const normalizedPathname = normalizePathname(pathname);
|
|
@@ -280,7 +310,7 @@ var isSamePagePathname = (page, pathname) => {
|
|
|
280
310
|
return page.aliasHrefs.some((aliasHref) => normalizePathname(aliasHref) === normalizedPathname);
|
|
281
311
|
};
|
|
282
312
|
|
|
283
|
-
// src/
|
|
313
|
+
// src/docs/docHeadings.ts
|
|
284
314
|
var normalizeWhitespace = (value) => value.replace(/\s+/g, " ").trim();
|
|
285
315
|
var slugifyHeading = (value) => {
|
|
286
316
|
const normalized = normalizeWhitespace(value).normalize("NFKD").toLowerCase().replace(/['"]/g, "").replace(/[^\p{Letter}\p{Number}\s-]/gu, " ").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -340,14 +370,14 @@ var extractDocHeadings = (source, minDepth = 2, maxDepth = 3) => {
|
|
|
340
370
|
var normalizeHeadingTitle = (value) => normalizeWhitespace(value);
|
|
341
371
|
|
|
342
372
|
export {
|
|
373
|
+
createHeadingSlugger,
|
|
374
|
+
extractDocHeadings,
|
|
375
|
+
normalizeHeadingTitle,
|
|
343
376
|
resolveDocsConfig,
|
|
344
377
|
getResolvedPageById,
|
|
345
378
|
getResolvedSectionById,
|
|
346
379
|
getResolvedPageByPathname,
|
|
347
380
|
getActiveSectionByPathname,
|
|
348
|
-
isSamePagePathname
|
|
349
|
-
createHeadingSlugger,
|
|
350
|
-
extractDocHeadings,
|
|
351
|
-
normalizeHeadingTitle
|
|
381
|
+
isSamePagePathname
|
|
352
382
|
};
|
|
353
|
-
//# sourceMappingURL=chunk-
|
|
383
|
+
//# sourceMappingURL=chunk-D7IAGT53.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/docs/resolveDocsConfig.ts","../src/docs/docHeadings.ts"],"sourcesContent":["import { nivelAssetUrl, resolvePublicAssetUrl, withSiteBaseUrl } from '../shared/assets.js'\nimport type {\n DocsAlgoliaConfig,\n DocsBrandConfig,\n DocsConfig,\n DocsFooterConfig,\n DocsHeadConfig,\n DocsPartnerConfig,\n DocsPageNode,\n DocsSectionNode,\n DocsSidebarNode,\n ResolvedDocsAlgoliaConfig,\n ResolvedDocsBrandConfig,\n ResolvedDocsConfig,\n ResolvedDocsPartnerConfig,\n ResolvedDocsPage,\n ResolvedDocsPartnersConfig,\n ResolvedDocsSection,\n ResolvedNavbarItem,\n ResolvedSidebarNode,\n ThemePreference,\n} from './types.js'\n\nconst normalizeBasePath = (value: string) => {\n const normalized = value.trim().replace(/^\\/+|\\/+$/g, '')\n return `/${normalized}` as '/docs'\n}\n\nconst normalizeSlug = (value: string) => value.replace(/^\\/+|\\/+$/g, '')\n\nconst joinHref = (basePath: '/docs', slug: string) => `${basePath}/${normalizeSlug(slug)}/`\n\nconst normalizePathname = (value: string) => {\n const pathname = value.split('?')[0]?.split('#')[0] ?? value\n const normalized = pathname.trim().replace(/\\/+$/g, '')\n return normalized === '' ? '/' : `${normalized}/`.replace(/\\/+/g, '/')\n}\n\nconst normalizeSourcePath = (value: string) => {\n const segments = value.replaceAll('\\\\', '/').split('/')\n const normalizedSegments: string[] = []\n\n for (const segment of segments) {\n if (segment === '' || segment === '.') {\n continue\n }\n\n if (segment === '..') {\n normalizedSegments.pop()\n continue\n }\n\n normalizedSegments.push(segment)\n }\n\n return normalizedSegments.join('/')\n}\n\nconst getSectionHref = (items: ResolvedSidebarNode[], visibleOnly = false): string | null => {\n for (const item of items) {\n if (item.kind === 'page') {\n if (visibleOnly && !item.showInNav) {\n continue\n }\n\n return item.href\n }\n\n if (item.kind === 'group') {\n if (visibleOnly && !item.showInNav) {\n continue\n }\n\n const href = getSectionHref(item.items, visibleOnly)\n if (href) {\n return href\n }\n }\n }\n\n return null\n}\n\nconst resolveNavigationHref = (value: string, fieldName: string) => {\n const normalized = value.trim()\n\n if (!normalized) {\n throw new Error(`Docs ${fieldName} must be a non-empty string.`)\n }\n\n return normalizePathname(normalized)\n}\n\nconst resolveThemeConfig = (theme: DocsConfig['theme']) => {\n return {\n light: theme?.light ?? 'consumer-light',\n dark: theme?.dark ?? 'consumer-dark',\n defaultPreference: (theme?.defaultPreference ?? 'light') as ThemePreference,\n }\n}\n\nconst resolveFooterConfig = (footer: DocsFooterConfig | undefined) => {\n return {\n pagination: footer?.pagination ?? false,\n }\n}\n\nconst resolveBrandConfig = (brand: DocsBrandConfig | undefined, siteTitle: string): ResolvedDocsBrandConfig => {\n const text = brand?.text ?? siteTitle\n\n return {\n text,\n href: withSiteBaseUrl(brand?.href ?? '/'),\n logoLight: resolvePublicAssetUrl(brand?.logoLight),\n logoDark: resolvePublicAssetUrl(brand?.logoDark),\n logoAlt: brand?.logoAlt ?? `${text} logo`,\n }\n}\n\nconst resolveHeadConfig = (head: DocsHeadConfig | undefined) => {\n const fontPreset = head?.fontPreset ?? 'inter'\n const defaultFontStylesheetHref = fontPreset === 'inter' ? nivelAssetUrl('fonts/fonts-inter.css') : undefined\n const defaultFontPreloadHrefs =\n fontPreset === 'inter'\n ? [\n nivelAssetUrl('fonts/inter-v20-latin-regular.woff2'),\n nivelAssetUrl('fonts/inter-v20-latin-600.woff2'),\n nivelAssetUrl('fonts/inter-v20-latin-800.woff2'),\n ]\n : []\n\n return {\n faviconSvg: resolvePublicAssetUrl(head?.faviconSvg),\n faviconIco: resolvePublicAssetUrl(head?.faviconIco),\n appleTouchIcon: resolvePublicAssetUrl(head?.appleTouchIcon),\n fontPreset,\n fontStylesheetHref: head?.fontStylesheetHref ?? defaultFontStylesheetHref,\n fontPreloadHrefs: head?.fontPreloadHrefs ?? defaultFontPreloadHrefs,\n }\n}\n\nconst resolvePartnerAssetUrl = (value: string | undefined) => {\n if (!value) {\n return undefined\n }\n\n return resolvePublicAssetUrl(value)\n}\n\nconst resolvePartner = (partner: DocsPartnerConfig): ResolvedDocsPartnerConfig => {\n return {\n name: partner.name,\n href: withSiteBaseUrl(partner.href),\n logoLight: resolvePartnerAssetUrl(partner.logoLight) ?? partner.logoLight,\n logoDark: resolvePartnerAssetUrl(partner.logoDark),\n logoAlt: partner.logoAlt ?? `${partner.name} logo`,\n }\n}\n\nconst resolvePartnersConfig = (partners: DocsConfig['partners']): ResolvedDocsPartnersConfig => {\n return {\n primary: (partners?.primary ?? []).map(resolvePartner),\n gold: (partners?.gold ?? []).map(resolvePartner),\n }\n}\n\nconst requireTrimmedString = (value: string, fieldName: string) => {\n const normalized = value.trim()\n\n if (!normalized) {\n throw new Error(`Docs algolia config \"${fieldName}\" must be a non-empty string.`)\n }\n\n return normalized\n}\n\nconst resolveAlgoliaConfig = (algolia: DocsAlgoliaConfig | undefined): ResolvedDocsAlgoliaConfig | null => {\n if (!algolia) {\n return null\n }\n\n return {\n appId: requireTrimmedString(algolia.appId, 'appId'),\n apiKey: requireTrimmedString(algolia.apiKey, 'apiKey'),\n indexName: requireTrimmedString(algolia.indexName, 'indexName'),\n fields: {\n href: algolia.fields?.href?.trim() || 'href',\n title: algolia.fields?.title?.trim() || 'title',\n excerpt: algolia.fields?.excerpt?.trim() || 'excerpt',\n sectionTitle: algolia.fields?.sectionTitle?.trim() || 'sectionTitle',\n },\n searchParams: algolia.searchParams ?? {},\n }\n}\n\nconst normalizeAliases = (aliases: string[] | undefined, slug: string) => {\n const normalizedAliases = new Set<string>()\n\n for (const alias of aliases ?? []) {\n const normalizedAlias = normalizeSlug(alias)\n if (!normalizedAlias || normalizedAlias === slug) {\n continue\n }\n\n normalizedAliases.add(normalizedAlias)\n }\n\n return [...normalizedAliases]\n}\n\nexport const resolveDocsConfig = (config: DocsConfig): ResolvedDocsConfig => {\n if (normalizeBasePath(config.basePath) !== '/docs') {\n throw new Error(`nivel currently requires basePath to be \"/docs\". Received ${JSON.stringify(config.basePath)}.`)\n }\n\n const pageIds = new Set<string>()\n const pageSlugs = new Set<string>()\n const pageAliases = new Set<string>()\n const groupIds = new Set<string>()\n const sectionIds = new Set<string>()\n const pages: ResolvedDocsPage[] = []\n const navbarItems: ResolvedNavbarItem[] = []\n\n const resolveSidebarNodes = (nodes: DocsSidebarNode[], sectionId: string): ResolvedSidebarNode[] => {\n return nodes.map((node) => {\n if (node.kind === 'group') {\n if (groupIds.has(node.id)) {\n throw new Error(`Duplicate docs group id \"${node.id}\".`)\n }\n\n groupIds.add(node.id)\n\n return {\n kind: 'group',\n id: node.id,\n title: node.title,\n href: node.href ? resolveNavigationHref(node.href, `group \"${node.id}\" href`) : undefined,\n showInNav: node.showInNav ?? true,\n collapsible: node.collapsible,\n items: resolveSidebarNodes(node.items, sectionId),\n }\n }\n\n if (node.kind !== 'page') {\n throw new Error(`Invalid docs sidebar node: ${JSON.stringify(node)}`)\n }\n\n const pageNode = node as DocsPageNode\n const slug = normalizeSlug(pageNode.slug)\n const aliases = normalizeAliases(pageNode.aliases, slug)\n\n if (!slug) {\n throw new Error(`Docs page \"${pageNode.id}\" must define a non-empty slug.`)\n }\n\n if (pageIds.has(pageNode.id)) {\n throw new Error(`Duplicate docs page id \"${pageNode.id}\".`)\n }\n\n if (pageSlugs.has(slug)) {\n throw new Error(`Duplicate docs page slug \"${slug}\".`)\n }\n\n for (const alias of aliases) {\n if (pageSlugs.has(alias) || pageAliases.has(alias)) {\n throw new Error(`Duplicate docs page alias \"${alias}\".`)\n }\n }\n\n pageIds.add(pageNode.id)\n pageSlugs.add(slug)\n for (const alias of aliases) {\n pageAliases.add(alias)\n }\n\n const href = joinHref('/docs', slug)\n const page: ResolvedDocsPage = {\n ...pageNode,\n slug,\n aliases,\n href,\n aliasHrefs: aliases.map((alias) => joinHref('/docs', alias)),\n tableOfContents: pageNode.tableOfContents ?? true,\n sectionId,\n documentTitle: `${pageNode.title} | ${config.siteTitle}`,\n source: normalizeSourcePath(pageNode.source),\n }\n pages.push(page)\n\n return {\n kind: 'page',\n id: pageNode.id,\n title: pageNode.title,\n navTitle: pageNode.navTitle ?? pageNode.title,\n href,\n showInNav: pageNode.showInNav ?? true,\n }\n })\n }\n\n const sections: ResolvedDocsSection[] = config.graph.items.map((section: DocsSectionNode) => {\n if (section.kind !== 'section') {\n throw new Error(`Top-level docs graph items must be sections. Received ${JSON.stringify(section)}`)\n }\n\n if (sectionIds.has(section.id)) {\n throw new Error(`Duplicate docs section id \"${section.id}\".`)\n }\n\n sectionIds.add(section.id)\n\n const items = resolveSidebarNodes(section.items, section.id)\n const firstVisibleHref = getSectionHref(items, true)\n const href = section.href\n ? resolveNavigationHref(section.href, `section \"${section.id}\" href`)\n : (firstVisibleHref ?? getSectionHref(items))\n\n if (!href) {\n throw new Error(`Docs section \"${section.id}\" must contain at least one page.`)\n }\n\n const resolvedSection: ResolvedDocsSection = {\n id: section.id,\n title: section.title,\n navTitle: section.navTitle ?? section.title,\n href,\n items,\n }\n\n navbarItems.push({\n id: section.id,\n title: resolvedSection.navTitle,\n href: resolvedSection.href,\n })\n\n return resolvedSection\n })\n\n if (pages.length === 0) {\n throw new Error('Docs graph must contain at least one page.')\n }\n\n return {\n siteTitle: config.siteTitle,\n siteDescription: config.siteDescription ?? null,\n basePath: '/docs',\n theme: resolveThemeConfig(config.theme),\n footer: resolveFooterConfig(config.footer),\n brand: resolveBrandConfig(config.brand, config.siteTitle),\n head: resolveHeadConfig(config.head),\n partners: resolvePartnersConfig(config.partners),\n algolia: resolveAlgoliaConfig(config.algolia),\n pages,\n sections,\n navbarItems,\n }\n}\n\nexport const getResolvedPageById = (config: { pages: ResolvedDocsPage[] }, pageId: string) => {\n const page = config.pages.find((candidate) => candidate.id === pageId)\n if (!page) {\n throw new Error(`Unknown docs page id \"${pageId}\".`)\n }\n return page\n}\n\nexport const getResolvedSectionById = (\n config: { sections?: ResolvedDocsSection[]; sidebarSections?: ResolvedDocsSection[] },\n sectionId: string,\n) => {\n const sections = config.sections ?? config.sidebarSections ?? []\n return sections.find((section) => section.id === sectionId) ?? null\n}\n\nexport const getResolvedPageByPathname = (config: { pages: ResolvedDocsPage[] }, pathname: string) => {\n const normalizedPathname = normalizePathname(pathname)\n\n return (\n config.pages.find((page) => {\n if (normalizePathname(page.href) === normalizedPathname) {\n return true\n }\n\n return page.aliasHrefs.some((aliasHref) => normalizePathname(aliasHref) === normalizedPathname)\n }) ?? null\n )\n}\n\nexport const getActiveSectionByPathname = (\n config: { pages: ResolvedDocsPage[]; sections?: ResolvedDocsSection[]; sidebarSections?: ResolvedDocsSection[] },\n pathname: string,\n) => {\n const activePage = getResolvedPageByPathname(config, pathname)\n\n if (!activePage) {\n return null\n }\n\n return getResolvedSectionById(config, activePage.sectionId)\n}\n\nexport const isSamePagePathname = (page: Pick<ResolvedDocsPage, 'href' | 'aliasHrefs'>, pathname: string) => {\n const normalizedPathname = normalizePathname(pathname)\n\n if (normalizePathname(page.href) === normalizedPathname) {\n return true\n }\n\n return page.aliasHrefs.some((aliasHref) => normalizePathname(aliasHref) === normalizedPathname)\n}\n","import type { DocHeading } from './types.js'\n\nconst normalizeWhitespace = (value: string) => value.replace(/\\s+/g, ' ').trim()\n\nconst slugifyHeading = (value: string) => {\n const normalized = normalizeWhitespace(value)\n .normalize('NFKD')\n .toLowerCase()\n .replace(/['\"]/g, '')\n .replace(/[^\\p{Letter}\\p{Number}\\s-]/gu, ' ')\n .replace(/\\s+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-+|-+$/g, '')\n\n return normalized || 'section'\n}\n\nexport const createHeadingSlugger = () => {\n const slugCounts = new Map<string, number>()\n\n return (value: string) => {\n const baseSlug = slugifyHeading(value)\n const count = slugCounts.get(baseSlug) ?? 0\n slugCounts.set(baseSlug, count + 1)\n\n return count === 0 ? baseSlug : `${baseSlug}-${count}`\n }\n}\n\nconst stripInlineMarkdown = (value: string) => {\n return normalizeWhitespace(\n value\n .replace(/!\\[([^\\]]*)\\]\\([^)]+\\)/g, '$1')\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, '$1')\n .replace(/`([^`]+)`/g, '$1')\n .replace(/<[^>]+>/g, ' ')\n .replace(/\\\\([\\\\`*_[\\]{}()#+\\-.!])/g, '$1')\n .replace(/[*_~]/g, '')\n .replace(/\\{[^}]+\\}/g, ' '),\n )\n}\n\nconst getFenceMarker = (line: string) => {\n const match = line.match(/^\\s{0,3}(`{3,}|~{3,})/)\n return match?.[1]?.[0] ?? null\n}\n\nexport const extractDocHeadings = (source: string, minDepth = 2, maxDepth = 3): DocHeading[] => {\n const slugify = createHeadingSlugger()\n const headings: DocHeading[] = []\n let activeFenceMarker: string | null = null\n\n for (const line of source.split('\\n')) {\n const fenceMarker = getFenceMarker(line)\n\n if (activeFenceMarker) {\n if (fenceMarker === activeFenceMarker) {\n activeFenceMarker = null\n }\n continue\n }\n\n if (fenceMarker) {\n activeFenceMarker = fenceMarker\n continue\n }\n\n const match = line.match(/^\\s{0,3}(#{1,6})\\s+(.*?)(?:\\s+#+\\s*)?$/)\n if (!match) {\n continue\n }\n\n const depth = match[1].length\n const title = stripInlineMarkdown(match[2] ?? '')\n if (!title || depth < minDepth || depth > maxDepth) {\n continue\n }\n\n headings.push({\n depth,\n id: slugify(title),\n title,\n })\n }\n\n return headings\n}\n\nexport const normalizeHeadingTitle = (value: string) => normalizeWhitespace(value)\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import {
|
|
2
|
+
extractDocHeadings,
|
|
3
|
+
getResolvedPageById,
|
|
4
|
+
resolveDocsConfig
|
|
5
|
+
} from "./chunk-D7IAGT53.js";
|
|
6
|
+
|
|
7
|
+
// src/runtime/node/codegen.ts
|
|
8
|
+
import fs from "fs";
|
|
9
|
+
import path from "path";
|
|
10
|
+
var GENERATED_DIRNAME = "(nivel-generated)";
|
|
11
|
+
var writeFileIfChanged = (filePath, source) => {
|
|
12
|
+
const current = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf8") : null;
|
|
13
|
+
if (current === source) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
17
|
+
fs.writeFileSync(filePath, source);
|
|
18
|
+
};
|
|
19
|
+
var toPosix = (value) => value.split(path.sep).join(path.posix.sep);
|
|
20
|
+
var getRelativeImportPath = (fromDirectory, toFile) => {
|
|
21
|
+
const relativePath = toPosix(path.relative(fromDirectory, toFile));
|
|
22
|
+
if (relativePath.startsWith(".")) {
|
|
23
|
+
return relativePath;
|
|
24
|
+
}
|
|
25
|
+
return `./${relativePath}`;
|
|
26
|
+
};
|
|
27
|
+
var serializeData = (data) => JSON.stringify(data, null, 2);
|
|
28
|
+
var collectFiles = (directoryPath) => {
|
|
29
|
+
if (!fs.existsSync(directoryPath)) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
const entries = fs.readdirSync(directoryPath, { withFileTypes: true });
|
|
33
|
+
return entries.flatMap((entry) => {
|
|
34
|
+
const entryPath = path.join(directoryPath, entry.name);
|
|
35
|
+
return entry.isDirectory() ? collectFiles(entryPath) : [entryPath];
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
var removeEmptyDirectories = (directoryPath, rootPath) => {
|
|
39
|
+
if (!fs.existsSync(directoryPath)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
for (const entry of fs.readdirSync(directoryPath, { withFileTypes: true })) {
|
|
43
|
+
if (!entry.isDirectory()) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
removeEmptyDirectories(path.join(directoryPath, entry.name), rootPath);
|
|
47
|
+
}
|
|
48
|
+
if (directoryPath === rootPath) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (fs.readdirSync(directoryPath).length === 0) {
|
|
52
|
+
fs.rmdirSync(directoryPath);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
var getGeneratedPageSource = (contentImportPath) => {
|
|
56
|
+
return [
|
|
57
|
+
"import { DocsPage } from '@unterberg/nivel/client'",
|
|
58
|
+
`import Content from ${JSON.stringify(contentImportPath)}`,
|
|
59
|
+
"",
|
|
60
|
+
"const Page = () => {",
|
|
61
|
+
" return <DocsPage Content={Content} />",
|
|
62
|
+
"}",
|
|
63
|
+
"",
|
|
64
|
+
"export default Page",
|
|
65
|
+
""
|
|
66
|
+
].join("\n");
|
|
67
|
+
};
|
|
68
|
+
var getGeneratedDataSource = (data) => {
|
|
69
|
+
return [
|
|
70
|
+
"import type { DocPageData } from '@unterberg/nivel'",
|
|
71
|
+
"",
|
|
72
|
+
`const data: DocPageData = ${serializeData(data)}`,
|
|
73
|
+
"",
|
|
74
|
+
"const pageData = () => {",
|
|
75
|
+
" return data",
|
|
76
|
+
"}",
|
|
77
|
+
"",
|
|
78
|
+
"export default pageData",
|
|
79
|
+
""
|
|
80
|
+
].join("\n");
|
|
81
|
+
};
|
|
82
|
+
var getGeneratedGlobalContextSource = (data) => {
|
|
83
|
+
return [
|
|
84
|
+
"import type { DocsGlobalContextData } from '@unterberg/nivel'",
|
|
85
|
+
"",
|
|
86
|
+
`const docsGlobalContextData: DocsGlobalContextData = ${serializeData(data)}`,
|
|
87
|
+
"",
|
|
88
|
+
"export { docsGlobalContextData }",
|
|
89
|
+
""
|
|
90
|
+
].join("\n");
|
|
91
|
+
};
|
|
92
|
+
var getRouteString = (href) => {
|
|
93
|
+
if (href === "/") {
|
|
94
|
+
return href;
|
|
95
|
+
}
|
|
96
|
+
return href.replace(/\/+$/g, "");
|
|
97
|
+
};
|
|
98
|
+
var getGeneratedRouteSource = (href) => {
|
|
99
|
+
return [`export default ${JSON.stringify(getRouteString(href))}`, ""].join("\n");
|
|
100
|
+
};
|
|
101
|
+
var getGeneratedTextExport = (value) => {
|
|
102
|
+
return [`export default ${JSON.stringify(value)}`, ""].join("\n");
|
|
103
|
+
};
|
|
104
|
+
var toDocPageLinkData = (page) => {
|
|
105
|
+
if (!page) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
id: page.id,
|
|
110
|
+
title: page.title,
|
|
111
|
+
href: page.href,
|
|
112
|
+
documentTitle: page.documentTitle
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
var getGeneratedPagesRoot = (rootDir) => path.join(rootDir, "pages", GENERATED_DIRNAME);
|
|
116
|
+
var syncGeneratedDocsPages = (options) => {
|
|
117
|
+
const { rootDir, docsConfig } = options;
|
|
118
|
+
const resolved = resolveDocsConfig(docsConfig);
|
|
119
|
+
const generatedPagesRoot = getGeneratedPagesRoot(rootDir);
|
|
120
|
+
const docsRoot = path.join(rootDir, "docs");
|
|
121
|
+
const expectedFiles = /* @__PURE__ */ new Set();
|
|
122
|
+
const globalContextFilePath = path.join(generatedPagesRoot, "_docsGlobalContext.ts");
|
|
123
|
+
fs.mkdirSync(generatedPagesRoot, { recursive: true });
|
|
124
|
+
const globalContextData = {
|
|
125
|
+
siteTitle: resolved.siteTitle,
|
|
126
|
+
basePath: resolved.basePath,
|
|
127
|
+
theme: resolved.theme,
|
|
128
|
+
footer: resolved.footer,
|
|
129
|
+
brand: resolved.brand,
|
|
130
|
+
head: resolved.head,
|
|
131
|
+
partners: resolved.partners,
|
|
132
|
+
algolia: resolved.algolia,
|
|
133
|
+
pages: resolved.pages,
|
|
134
|
+
navbarItems: resolved.navbarItems,
|
|
135
|
+
sidebarSections: resolved.sections
|
|
136
|
+
};
|
|
137
|
+
writeFileIfChanged(globalContextFilePath, getGeneratedGlobalContextSource(globalContextData));
|
|
138
|
+
expectedFiles.add(globalContextFilePath);
|
|
139
|
+
for (const [pageIndex, page] of resolved.pages.entries()) {
|
|
140
|
+
const contentFilePath = path.join(docsRoot, page.source);
|
|
141
|
+
if (!fs.existsSync(contentFilePath)) {
|
|
142
|
+
throw new Error(`Docs page "${page.id}" points to missing source file: ${contentFilePath}`);
|
|
143
|
+
}
|
|
144
|
+
const pageSource = fs.readFileSync(contentFilePath, "utf8");
|
|
145
|
+
const data = {
|
|
146
|
+
page: getResolvedPageById(resolved, page.id),
|
|
147
|
+
headings: extractDocHeadings(pageSource),
|
|
148
|
+
previousPage: toDocPageLinkData(resolved.pages[pageIndex - 1]),
|
|
149
|
+
nextPage: toDocPageLinkData(resolved.pages[pageIndex + 1])
|
|
150
|
+
};
|
|
151
|
+
for (const routeHref of [page.href, ...page.aliasHrefs]) {
|
|
152
|
+
const routeSlug = routeHref.replace(/^\/docs\//, "").replace(/\/+$/g, "");
|
|
153
|
+
const pageDir = path.join(generatedPagesRoot, ...routeSlug.split("/"));
|
|
154
|
+
const contentImportPath = getRelativeImportPath(pageDir, contentFilePath);
|
|
155
|
+
const pageFilePath = path.join(pageDir, "+Page.tsx");
|
|
156
|
+
const dataFilePath = path.join(pageDir, "+data.ts");
|
|
157
|
+
const routeFilePath = path.join(pageDir, "+route.ts");
|
|
158
|
+
const titleFilePath = path.join(pageDir, "+title.ts");
|
|
159
|
+
writeFileIfChanged(pageFilePath, getGeneratedPageSource(contentImportPath));
|
|
160
|
+
writeFileIfChanged(dataFilePath, getGeneratedDataSource(data));
|
|
161
|
+
writeFileIfChanged(routeFilePath, getGeneratedRouteSource(routeHref));
|
|
162
|
+
writeFileIfChanged(titleFilePath, getGeneratedTextExport(page.documentTitle));
|
|
163
|
+
expectedFiles.add(pageFilePath);
|
|
164
|
+
expectedFiles.add(dataFilePath);
|
|
165
|
+
expectedFiles.add(routeFilePath);
|
|
166
|
+
expectedFiles.add(titleFilePath);
|
|
167
|
+
if (page.description) {
|
|
168
|
+
const descriptionFilePath = path.join(pageDir, "+description.ts");
|
|
169
|
+
writeFileIfChanged(descriptionFilePath, getGeneratedTextExport(page.description));
|
|
170
|
+
expectedFiles.add(descriptionFilePath);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
for (const filePath of collectFiles(generatedPagesRoot)) {
|
|
175
|
+
if (expectedFiles.has(filePath)) {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
fs.rmSync(filePath, { force: true });
|
|
179
|
+
}
|
|
180
|
+
removeEmptyDirectories(generatedPagesRoot, generatedPagesRoot);
|
|
181
|
+
};
|
|
182
|
+
var isDocsSourcePath = (filePath, rootDir) => {
|
|
183
|
+
const normalized = toPosix(filePath);
|
|
184
|
+
const docsRoot = toPosix(path.join(rootDir, "docs"));
|
|
185
|
+
const docsConfigPath = toPosix(path.join(rootDir, "pages", "+docs.ts"));
|
|
186
|
+
const generatedRoot = toPosix(getGeneratedPagesRoot(rootDir));
|
|
187
|
+
if (normalized.startsWith(generatedRoot)) {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
return normalized === docsConfigPath || normalized.startsWith(`${docsRoot}/`);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// src/runtime/node/loadDocsConfig.ts
|
|
194
|
+
import path2 from "path";
|
|
195
|
+
import { pathToFileURL } from "url";
|
|
196
|
+
import { register } from "tsx/esm/api";
|
|
197
|
+
var getDocsConfigModulePath = (rootDir) => {
|
|
198
|
+
return path2.join(rootDir, "pages", "+docs.ts");
|
|
199
|
+
};
|
|
200
|
+
var getDocsConfigFromLoadedModule = (loaded, modulePath) => {
|
|
201
|
+
const docsConfig = loaded.default;
|
|
202
|
+
if (!docsConfig) {
|
|
203
|
+
throw new Error(`Expected default export from ${modulePath}`);
|
|
204
|
+
}
|
|
205
|
+
return docsConfig;
|
|
206
|
+
};
|
|
207
|
+
var loadDocsConfig = async (options) => {
|
|
208
|
+
const modulePath = getDocsConfigModulePath(options.rootDir);
|
|
209
|
+
const loaded = await options.loadModule(modulePath);
|
|
210
|
+
return getDocsConfigFromLoadedModule(loaded, modulePath);
|
|
211
|
+
};
|
|
212
|
+
var loadDocsConfigWithVite = async (rootDir) => {
|
|
213
|
+
const unregister = register();
|
|
214
|
+
const modulePath = getDocsConfigModulePath(rootDir);
|
|
215
|
+
const moduleUrl = pathToFileURL(modulePath).href;
|
|
216
|
+
try {
|
|
217
|
+
const loaded = await import(moduleUrl);
|
|
218
|
+
return getDocsConfigFromLoadedModule(loaded, modulePath);
|
|
219
|
+
} finally {
|
|
220
|
+
await unregister();
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
export {
|
|
225
|
+
getGeneratedPagesRoot,
|
|
226
|
+
syncGeneratedDocsPages,
|
|
227
|
+
isDocsSourcePath,
|
|
228
|
+
loadDocsConfig,
|
|
229
|
+
loadDocsConfigWithVite
|
|
230
|
+
};
|
|
231
|
+
//# sourceMappingURL=chunk-DNCQR5NH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/node/codegen.ts","../src/runtime/node/loadDocsConfig.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport type { DocPageData, DocPageLinkData, DocsConfig, DocsGlobalContextData } from '../../docs/types.js'\nimport { extractDocHeadings } from '../../docs/docHeadings.js'\nimport { getResolvedPageById, resolveDocsConfig } from '../../docs/resolveDocsConfig.js'\n\nconst GENERATED_DIRNAME = '(nivel-generated)'\n\nconst writeFileIfChanged = (filePath: string, source: string) => {\n const current = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : null\n if (current === source) {\n return\n }\n\n fs.mkdirSync(path.dirname(filePath), { recursive: true })\n fs.writeFileSync(filePath, source)\n}\n\nconst toPosix = (value: string) => value.split(path.sep).join(path.posix.sep)\n\nconst getRelativeImportPath = (fromDirectory: string, toFile: string) => {\n const relativePath = toPosix(path.relative(fromDirectory, toFile))\n if (relativePath.startsWith('.')) {\n return relativePath\n }\n return `./${relativePath}`\n}\n\nconst serializeData = (data: DocPageData | DocsGlobalContextData) => JSON.stringify(data, null, 2)\n\nconst collectFiles = (directoryPath: string): string[] => {\n if (!fs.existsSync(directoryPath)) {\n return []\n }\n\n const entries = fs.readdirSync(directoryPath, { withFileTypes: true })\n\n return entries.flatMap((entry) => {\n const entryPath = path.join(directoryPath, entry.name)\n return entry.isDirectory() ? collectFiles(entryPath) : [entryPath]\n })\n}\n\nconst removeEmptyDirectories = (directoryPath: string, rootPath: string) => {\n if (!fs.existsSync(directoryPath)) {\n return\n }\n\n for (const entry of fs.readdirSync(directoryPath, { withFileTypes: true })) {\n if (!entry.isDirectory()) {\n continue\n }\n\n removeEmptyDirectories(path.join(directoryPath, entry.name), rootPath)\n }\n\n if (directoryPath === rootPath) {\n return\n }\n\n if (fs.readdirSync(directoryPath).length === 0) {\n fs.rmdirSync(directoryPath)\n }\n}\n\nconst getGeneratedPageSource = (contentImportPath: string) => {\n return [\n \"import { DocsPage } from '@unterberg/nivel/client'\",\n `import Content from ${JSON.stringify(contentImportPath)}`,\n '',\n 'const Page = () => {',\n ' return <DocsPage Content={Content} />',\n '}',\n '',\n 'export default Page',\n '',\n ].join('\\n')\n}\n\nconst getGeneratedDataSource = (data: DocPageData) => {\n return [\n \"import type { DocPageData } from '@unterberg/nivel'\",\n '',\n `const data: DocPageData = ${serializeData(data)}`,\n '',\n 'const pageData = () => {',\n ' return data',\n '}',\n '',\n 'export default pageData',\n '',\n ].join('\\n')\n}\n\nconst getGeneratedGlobalContextSource = (data: DocsGlobalContextData) => {\n return [\n \"import type { DocsGlobalContextData } from '@unterberg/nivel'\",\n '',\n `const docsGlobalContextData: DocsGlobalContextData = ${serializeData(data)}`,\n '',\n 'export { docsGlobalContextData }',\n '',\n ].join('\\n')\n}\n\nconst getRouteString = (href: string) => {\n if (href === '/') {\n return href\n }\n\n return href.replace(/\\/+$/g, '')\n}\n\nconst getGeneratedRouteSource = (href: string) => {\n return [`export default ${JSON.stringify(getRouteString(href))}`, ''].join('\\n')\n}\n\nconst getGeneratedTextExport = (value: string) => {\n return [`export default ${JSON.stringify(value)}`, ''].join('\\n')\n}\n\nconst toDocPageLinkData = (\n page:\n | {\n id: string\n title: string\n href: string\n documentTitle: string\n }\n | undefined,\n): DocPageLinkData | null => {\n if (!page) {\n return null\n }\n\n return {\n id: page.id,\n title: page.title,\n href: page.href,\n documentTitle: page.documentTitle,\n }\n}\n\nexport const getGeneratedPagesRoot = (rootDir: string) => path.join(rootDir, 'pages', GENERATED_DIRNAME)\n\nexport const syncGeneratedDocsPages = (options: { rootDir: string; docsConfig: DocsConfig }) => {\n const { rootDir, docsConfig } = options\n const resolved = resolveDocsConfig(docsConfig)\n const generatedPagesRoot = getGeneratedPagesRoot(rootDir)\n const docsRoot = path.join(rootDir, 'docs')\n const expectedFiles = new Set<string>()\n const globalContextFilePath = path.join(generatedPagesRoot, '_docsGlobalContext.ts')\n\n fs.mkdirSync(generatedPagesRoot, { recursive: true })\n\n const globalContextData: DocsGlobalContextData = {\n siteTitle: resolved.siteTitle,\n basePath: resolved.basePath,\n theme: resolved.theme,\n footer: resolved.footer,\n brand: resolved.brand,\n head: resolved.head,\n partners: resolved.partners,\n algolia: resolved.algolia,\n pages: resolved.pages,\n navbarItems: resolved.navbarItems,\n sidebarSections: resolved.sections,\n }\n\n writeFileIfChanged(globalContextFilePath, getGeneratedGlobalContextSource(globalContextData))\n expectedFiles.add(globalContextFilePath)\n\n for (const [pageIndex, page] of resolved.pages.entries()) {\n const contentFilePath = path.join(docsRoot, page.source)\n\n if (!fs.existsSync(contentFilePath)) {\n throw new Error(`Docs page \"${page.id}\" points to missing source file: ${contentFilePath}`)\n }\n\n const pageSource = fs.readFileSync(contentFilePath, 'utf8')\n const data: DocPageData = {\n page: getResolvedPageById(resolved, page.id),\n headings: extractDocHeadings(pageSource),\n previousPage: toDocPageLinkData(resolved.pages[pageIndex - 1]),\n nextPage: toDocPageLinkData(resolved.pages[pageIndex + 1]),\n }\n\n for (const routeHref of [page.href, ...page.aliasHrefs]) {\n const routeSlug = routeHref.replace(/^\\/docs\\//, '').replace(/\\/+$/g, '')\n const pageDir = path.join(generatedPagesRoot, ...routeSlug.split('/'))\n const contentImportPath = getRelativeImportPath(pageDir, contentFilePath)\n\n const pageFilePath = path.join(pageDir, '+Page.tsx')\n const dataFilePath = path.join(pageDir, '+data.ts')\n const routeFilePath = path.join(pageDir, '+route.ts')\n const titleFilePath = path.join(pageDir, '+title.ts')\n\n writeFileIfChanged(pageFilePath, getGeneratedPageSource(contentImportPath))\n writeFileIfChanged(dataFilePath, getGeneratedDataSource(data))\n writeFileIfChanged(routeFilePath, getGeneratedRouteSource(routeHref))\n writeFileIfChanged(titleFilePath, getGeneratedTextExport(page.documentTitle))\n\n expectedFiles.add(pageFilePath)\n expectedFiles.add(dataFilePath)\n expectedFiles.add(routeFilePath)\n expectedFiles.add(titleFilePath)\n\n if (page.description) {\n const descriptionFilePath = path.join(pageDir, '+description.ts')\n writeFileIfChanged(descriptionFilePath, getGeneratedTextExport(page.description))\n expectedFiles.add(descriptionFilePath)\n }\n }\n }\n\n for (const filePath of collectFiles(generatedPagesRoot)) {\n if (expectedFiles.has(filePath)) {\n continue\n }\n\n fs.rmSync(filePath, { force: true })\n }\n\n removeEmptyDirectories(generatedPagesRoot, generatedPagesRoot)\n}\n\nexport const isDocsSourcePath = (filePath: string, rootDir: string) => {\n const normalized = toPosix(filePath)\n const docsRoot = toPosix(path.join(rootDir, 'docs'))\n const docsConfigPath = toPosix(path.join(rootDir, 'pages', '+docs.ts'))\n const generatedRoot = toPosix(getGeneratedPagesRoot(rootDir))\n\n if (normalized.startsWith(generatedRoot)) {\n return false\n }\n\n return normalized === docsConfigPath || normalized.startsWith(`${docsRoot}/`)\n}\n","import path from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport { register } from 'tsx/esm/api'\nimport type { DocsConfig } from '../../docs/types.js'\n\nconst getDocsConfigModulePath = (rootDir: string) => {\n return path.join(rootDir, 'pages', '+docs.ts')\n}\n\nconst getDocsConfigFromLoadedModule = (loaded: unknown, modulePath: string) => {\n const docsConfig = (loaded as { default?: DocsConfig }).default\n\n if (!docsConfig) {\n throw new Error(`Expected default export from ${modulePath}`)\n }\n\n return docsConfig\n}\n\nexport const loadDocsConfig = async (options: {\n rootDir: string\n loadModule: (modulePath: string) => Promise<unknown>\n}) => {\n const modulePath = getDocsConfigModulePath(options.rootDir)\n const loaded = await options.loadModule(modulePath)\n return getDocsConfigFromLoadedModule(loaded, modulePath)\n}\n\nexport const loadDocsConfigWithVite = async (rootDir: string) => {\n const unregister = register()\n const modulePath = getDocsConfigModulePath(rootDir)\n const moduleUrl = pathToFileURL(modulePath).href\n\n try {\n const loaded = await import(moduleUrl)\n return getDocsConfigFromLoadedModule(loaded, modulePath)\n } finally {\n await unregister()\n }\n}\n"],"mappings":"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","names":["path"]}
|