@unterberg/nivel 0.2.42 → 0.2.46

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.
@@ -1,1353 +0,0 @@
1
- import {
2
- extractDocHeadings,
3
- getDocsIconMapKey
4
- } from "./chunk-AT4O3RRN.js";
5
- import {
6
- nivelAssetUrl,
7
- resolvePublicAssetUrl,
8
- withSiteBaseUrl
9
- } from "./chunk-PYYPYIBD.js";
10
-
11
- // src/docs/icons.ts
12
- import * as lucideIcons from "lucide-react";
13
- var excludedLucideExports = /* @__PURE__ */ new Set(["createLucideIcon", "Icon", "icons", "LucideProvider", "useLucideContext"]);
14
- var isLucideIconExport = (value) => {
15
- if (typeof value !== "object" || value === null) {
16
- return false;
17
- }
18
- return "$$typeof" in value && "render" in value;
19
- };
20
- var docsIconNames = Object.freeze(
21
- Object.entries(lucideIcons).filter(([name, value]) => !excludedLucideExports.has(name) && isLucideIconExport(value)).map(([name]) => name).sort()
22
- );
23
- var docsIconNameSet = new Set(docsIconNames);
24
- var isDocsIconName = (value) => {
25
- return docsIconNameSet.has(value);
26
- };
27
- var assertDocsIconName = (value, context) => {
28
- if (isDocsIconName(value)) {
29
- return;
30
- }
31
- throw new Error(
32
- `${context} must be a valid lucide-react icon export. Received "${value}". See https://lucide.dev/icons/`
33
- );
34
- };
35
-
36
- // src/docs/resolveDocsConfig.ts
37
- var isExternalHref = (value) => {
38
- return /^(?:[a-z]+:)?\/\//i.test(value) || value.startsWith("mailto:") || value.startsWith("tel:");
39
- };
40
- var normalizeBasePath = (value) => {
41
- const normalized = value.trim();
42
- if (!normalized) {
43
- throw new Error("Docs basePath must be a non-empty absolute path.");
44
- }
45
- if (!normalized.startsWith("/") || normalized.startsWith("//")) {
46
- throw new Error(`Docs basePath must start with "/". Received ${JSON.stringify(value)}.`);
47
- }
48
- if (normalized.includes("?") || normalized.includes("#")) {
49
- throw new Error(`Docs basePath cannot include query strings or hashes. Received ${JSON.stringify(value)}.`);
50
- }
51
- const collapsed = normalized.replace(/\/+/g, "/").replace(/\/+$/g, "");
52
- return collapsed === "" ? "/" : collapsed;
53
- };
54
- var normalizeContentDir = (value) => {
55
- const normalized = (value ?? "docs").trim();
56
- if (!normalized) {
57
- throw new Error("Docs contentDir must be a non-empty project-relative path.");
58
- }
59
- if (normalized.startsWith("/") || normalized.startsWith("\\")) {
60
- throw new Error(`Docs contentDir must be project-relative. Received ${JSON.stringify(value)}.`);
61
- }
62
- if (/^[a-zA-Z]:[\\/]/.test(normalized)) {
63
- throw new Error(`Docs contentDir must be project-relative. Received ${JSON.stringify(value)}.`);
64
- }
65
- const segments = normalized.replaceAll("\\", "/").split("/");
66
- const resolvedSegments = [];
67
- for (const segment of segments) {
68
- if (segment === "" || segment === ".") {
69
- continue;
70
- }
71
- if (segment === "..") {
72
- throw new Error(`Docs contentDir cannot escape the project root. Received ${JSON.stringify(value)}.`);
73
- }
74
- resolvedSegments.push(segment);
75
- }
76
- if (resolvedSegments.length === 0) {
77
- throw new Error(`Docs contentDir must contain at least one path segment. Received ${JSON.stringify(value)}.`);
78
- }
79
- return resolvedSegments.join("/");
80
- };
81
- var normalizeSlug = (value) => value.replace(/^\/+|\/+$/g, "");
82
- var joinDocsHref = (basePath, slug) => {
83
- const normalizedBasePath = normalizeBasePath(basePath);
84
- const normalizedSlug = normalizeSlug(slug);
85
- if (!normalizedSlug) {
86
- return normalizedBasePath === "/" ? "/" : `${normalizedBasePath}/`;
87
- }
88
- return normalizedBasePath === "/" ? `/${normalizedSlug}/` : `${normalizedBasePath}/${normalizedSlug}/`;
89
- };
90
- var normalizePathname = (value) => {
91
- const pathname = value.split("?")[0]?.split("#")[0] ?? value;
92
- const normalized = pathname.trim().replace(/\/+$/g, "");
93
- return normalized === "" ? "/" : `${normalized}/`.replace(/\/+/g, "/");
94
- };
95
- var resolveDocsHref = (basePath, href) => {
96
- const normalized = href.trim();
97
- if (!normalized || normalized.startsWith("#") || isExternalHref(normalized)) {
98
- return null;
99
- }
100
- const pathname = normalized.split("?")[0]?.split("#")[0] ?? normalized;
101
- if (!pathname) {
102
- return null;
103
- }
104
- if (pathname.startsWith("/")) {
105
- const normalizedPathname = normalizePathname(pathname);
106
- const normalizedBasePath = normalizeBasePath(basePath);
107
- if (normalizedBasePath === "/") {
108
- return normalizedPathname;
109
- }
110
- return normalizedPathname === `${normalizedBasePath}/` || normalizedPathname.startsWith(`${normalizedBasePath}/`) ? normalizedPathname : null;
111
- }
112
- if (pathname.startsWith("./") || pathname.startsWith("../")) {
113
- return null;
114
- }
115
- return joinDocsHref(basePath, pathname);
116
- };
117
- var normalizeSourcePath = (value) => {
118
- const segments = value.replaceAll("\\", "/").split("/");
119
- const normalizedSegments = [];
120
- for (const segment of segments) {
121
- if (segment === "" || segment === ".") {
122
- continue;
123
- }
124
- if (segment === "..") {
125
- normalizedSegments.pop();
126
- continue;
127
- }
128
- normalizedSegments.push(segment);
129
- }
130
- return normalizedSegments.join("/");
131
- };
132
- var getSectionHref = (items, visibleOnly = false) => {
133
- for (const item of items) {
134
- if (item.kind === "page") {
135
- if (visibleOnly && !item.showInNav) {
136
- continue;
137
- }
138
- return item.href;
139
- }
140
- if (item.kind === "group") {
141
- if (visibleOnly && !item.showInNav) {
142
- continue;
143
- }
144
- const href = getSectionHref(item.items, visibleOnly);
145
- if (href) {
146
- return href;
147
- }
148
- }
149
- }
150
- return null;
151
- };
152
- var resolveNavigationHref = (value, fieldName, basePath) => {
153
- const normalized = value.trim();
154
- if (!normalized) {
155
- throw new Error(`Docs ${fieldName} must be a non-empty string.`);
156
- }
157
- if (normalized.startsWith("#") || isExternalHref(normalized)) {
158
- return normalized;
159
- }
160
- if (!normalized.startsWith("/")) {
161
- return joinDocsHref(basePath, normalized);
162
- }
163
- return normalizePathname(normalized);
164
- };
165
- var resolveThemeConfig = (theme) => {
166
- return {
167
- light: theme?.light ?? "consumer-light",
168
- dark: theme?.dark ?? "consumer-dark",
169
- defaultPreference: theme?.defaultPreference ?? "light"
170
- };
171
- };
172
- var resolveFooterConfig = (footer) => {
173
- return {
174
- pagination: footer?.pagination ?? false
175
- };
176
- };
177
- var resolveRobotsConfig = (robots) => {
178
- return robots ?? true;
179
- };
180
- var resolveCustomFontsConfig = (customFonts) => {
181
- return customFonts ?? true;
182
- };
183
- var resolveBrandConfig = (brand, siteTitle) => {
184
- const text = brand?.text ?? siteTitle;
185
- return {
186
- text,
187
- href: withSiteBaseUrl(brand?.href ?? "/"),
188
- logoLight: resolvePublicAssetUrl(brand?.logoLight),
189
- logoDark: resolvePublicAssetUrl(brand?.logoDark),
190
- logoAlt: brand?.logoAlt ?? `${text} logo`
191
- };
192
- };
193
- var resolveHeadConfig = (head, customFonts) => {
194
- const fontPreset = customFonts ? head?.fontPreset ?? "inter" : "none";
195
- const defaultFontStylesheetHref = fontPreset === "inter" ? nivelAssetUrl("fonts/fonts-inter.css") : void 0;
196
- const defaultFontPreloadHrefs = fontPreset === "inter" ? [
197
- nivelAssetUrl("fonts/inter-v20-latin-regular.woff2"),
198
- nivelAssetUrl("fonts/inter-v20-latin-600.woff2"),
199
- nivelAssetUrl("fonts/inter-v20-latin-800.woff2")
200
- ] : [];
201
- return {
202
- customFonts,
203
- faviconSvg: resolvePublicAssetUrl(head?.faviconSvg),
204
- faviconIco: resolvePublicAssetUrl(head?.faviconIco),
205
- appleTouchIcon: resolvePublicAssetUrl(head?.appleTouchIcon),
206
- fontPreset,
207
- fontStylesheetHref: head?.fontStylesheetHref ?? defaultFontStylesheetHref,
208
- fontPreloadHrefs: head?.fontPreloadHrefs ?? defaultFontPreloadHrefs
209
- };
210
- };
211
- var resolvePartnerAssetUrl = (value) => {
212
- if (!value) {
213
- return void 0;
214
- }
215
- return resolvePublicAssetUrl(value);
216
- };
217
- var resolvePartner = (partner) => {
218
- return {
219
- name: partner.name,
220
- href: withSiteBaseUrl(partner.href),
221
- logoLight: resolvePartnerAssetUrl(partner.logoLight) ?? partner.logoLight,
222
- logoDark: resolvePartnerAssetUrl(partner.logoDark),
223
- logoAlt: partner.logoAlt ?? `${partner.name} logo`
224
- };
225
- };
226
- var resolveSocialConfig = (social) => {
227
- return {
228
- ...social
229
- };
230
- };
231
- var resolvePartnersConfig = (partners) => {
232
- return {
233
- primary: (partners?.primary ?? []).map(resolvePartner),
234
- gold: (partners?.gold ?? []).map(resolvePartner)
235
- };
236
- };
237
- var requireTrimmedString = (value, fieldName) => {
238
- const normalized = value.trim();
239
- if (!normalized) {
240
- throw new Error(`Docs algolia config "${fieldName}" must be a non-empty string.`);
241
- }
242
- return normalized;
243
- };
244
- var resolveAlgoliaConfig = (algolia) => {
245
- if (!algolia) {
246
- return null;
247
- }
248
- return {
249
- appId: requireTrimmedString(algolia.appId, "appId"),
250
- apiKey: requireTrimmedString(algolia.apiKey, "apiKey"),
251
- indexName: requireTrimmedString(algolia.indexName, "indexName"),
252
- fields: {
253
- href: algolia.fields?.href?.trim() || "href",
254
- title: algolia.fields?.title?.trim() || "title",
255
- excerpt: algolia.fields?.excerpt?.trim() || "excerpt",
256
- sectionTitle: algolia.fields?.sectionTitle?.trim() || "sectionTitle"
257
- },
258
- searchParams: algolia.searchParams ?? {}
259
- };
260
- };
261
- var normalizeAliases = (aliases, slug) => {
262
- const normalizedAliases = /* @__PURE__ */ new Set();
263
- for (const alias of aliases ?? []) {
264
- const normalizedAlias = normalizeSlug(alias);
265
- if (!normalizedAlias || normalizedAlias === slug) {
266
- continue;
267
- }
268
- normalizedAliases.add(normalizedAlias);
269
- }
270
- return [...normalizedAliases];
271
- };
272
- var resolveDocsConfig = (config) => {
273
- const normalizedBasePath = normalizeBasePath(config.basePath);
274
- const normalizedContentDir = normalizeContentDir(config.contentDir);
275
- const customFonts = resolveCustomFontsConfig(config.customFonts);
276
- const pageIds = /* @__PURE__ */ new Set();
277
- const pageSlugs = /* @__PURE__ */ new Set();
278
- const pageAliases = /* @__PURE__ */ new Set();
279
- const groupIds = /* @__PURE__ */ new Set();
280
- const sectionIds = /* @__PURE__ */ new Set();
281
- const pages = [];
282
- const navbarItems = [];
283
- const resolveSidebarNodes = (nodes, sectionId) => {
284
- return nodes.map((node) => {
285
- if (node.kind === "group") {
286
- if (groupIds.has(node.id)) {
287
- throw new Error(`Duplicate docs group id "${node.id}".`);
288
- }
289
- if (node.icon) {
290
- assertDocsIconName(node.icon, `Docs group "${node.id}" icon`);
291
- }
292
- groupIds.add(node.id);
293
- return {
294
- kind: "group",
295
- id: node.id,
296
- title: node.title,
297
- href: node.href ? resolveNavigationHref(node.href, `group "${node.id}" href`, normalizedBasePath) : void 0,
298
- showInNav: node.showInNav ?? true,
299
- collapsible: node.collapsible,
300
- items: resolveSidebarNodes(node.items, sectionId),
301
- icon: node.icon
302
- };
303
- }
304
- if (node.kind !== "page") {
305
- throw new Error(`Invalid docs sidebar node: ${JSON.stringify(node)}`);
306
- }
307
- const pageNode = node;
308
- const slug = normalizeSlug(pageNode.slug);
309
- const aliases = normalizeAliases(pageNode.aliases, slug);
310
- if (pageNode.icon) {
311
- assertDocsIconName(pageNode.icon, `Docs page "${pageNode.id}" icon`);
312
- }
313
- if (!slug) {
314
- throw new Error(`Docs page "${pageNode.id}" must define a non-empty slug.`);
315
- }
316
- if (pageIds.has(pageNode.id)) {
317
- throw new Error(`Duplicate docs page id "${pageNode.id}".`);
318
- }
319
- if (pageSlugs.has(slug)) {
320
- throw new Error(`Duplicate docs page slug "${slug}".`);
321
- }
322
- for (const alias of aliases) {
323
- if (pageSlugs.has(alias) || pageAliases.has(alias)) {
324
- throw new Error(`Duplicate docs page alias "${alias}".`);
325
- }
326
- }
327
- pageIds.add(pageNode.id);
328
- pageSlugs.add(slug);
329
- for (const alias of aliases) {
330
- pageAliases.add(alias);
331
- }
332
- const href = joinDocsHref(normalizedBasePath, slug);
333
- const page = {
334
- ...pageNode,
335
- slug,
336
- aliases,
337
- href,
338
- aliasHrefs: aliases.map((alias) => joinDocsHref(normalizedBasePath, alias)),
339
- tableOfContents: pageNode.tableOfContents ?? true,
340
- sectionId,
341
- documentTitle: `${pageNode.title} | ${config.siteTitle}`,
342
- source: normalizeSourcePath(pageNode.source)
343
- };
344
- pages.push(page);
345
- return {
346
- kind: "page",
347
- id: pageNode.id,
348
- title: pageNode.title,
349
- navTitle: pageNode.navTitle ?? pageNode.title,
350
- href,
351
- showInNav: pageNode.showInNav ?? true,
352
- icon: pageNode.icon
353
- };
354
- });
355
- };
356
- const sections = config.graph.items.map((section) => {
357
- if (section.kind !== "section") {
358
- throw new Error(`Top-level docs graph items must be sections. Received ${JSON.stringify(section)}`);
359
- }
360
- if (sectionIds.has(section.id)) {
361
- throw new Error(`Duplicate docs section id "${section.id}".`);
362
- }
363
- if (section.icon) {
364
- assertDocsIconName(section.icon, `Docs section "${section.id}" icon`);
365
- }
366
- sectionIds.add(section.id);
367
- const items = resolveSidebarNodes(section.items, section.id);
368
- const firstVisibleHref = getSectionHref(items, true);
369
- const href = section.href ? resolveNavigationHref(section.href, `section "${section.id}" href`, normalizedBasePath) : firstVisibleHref ?? getSectionHref(items);
370
- if (!href) {
371
- throw new Error(`Docs section "${section.id}" must contain at least one page.`);
372
- }
373
- const resolvedSection = {
374
- id: section.id,
375
- title: section.title,
376
- navTitle: section.navTitle ?? section.title,
377
- href,
378
- items,
379
- icon: section.icon
380
- };
381
- navbarItems.push({
382
- id: section.id,
383
- title: resolvedSection.navTitle,
384
- href: resolvedSection.href
385
- });
386
- return resolvedSection;
387
- });
388
- if (pages.length === 0) {
389
- throw new Error("Docs graph must contain at least one page.");
390
- }
391
- return {
392
- siteTitle: config.siteTitle,
393
- siteDescription: config.siteDescription ?? null,
394
- robots: resolveRobotsConfig(config.robots),
395
- customFonts,
396
- basePath: normalizedBasePath,
397
- contentDir: normalizedContentDir,
398
- theme: resolveThemeConfig(config.theme),
399
- footer: resolveFooterConfig(config.footer),
400
- brand: resolveBrandConfig(config.brand, config.siteTitle),
401
- head: resolveHeadConfig(config.head, customFonts),
402
- partners: resolvePartnersConfig(config.partners),
403
- social: resolveSocialConfig(config.social),
404
- algolia: resolveAlgoliaConfig(config.algolia),
405
- pages,
406
- sections,
407
- navbarItems
408
- };
409
- };
410
- var getResolvedPageById = (config, pageId) => {
411
- const page = config.pages.find((candidate) => candidate.id === pageId);
412
- if (!page) {
413
- throw new Error(`Unknown docs page id "${pageId}".`);
414
- }
415
- return page;
416
- };
417
-
418
- // src/runtime/node/codegen.ts
419
- import fs from "fs";
420
- import path from "path";
421
- import * as lucideIcons2 from "lucide-react";
422
- var GENERATED_DIRNAME = "(nivel-generated)";
423
- var lucideIconNodeByName = /* @__PURE__ */ new Map();
424
- var writeFileIfChanged = (filePath, source) => {
425
- const current = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf8") : null;
426
- if (current === source) {
427
- return;
428
- }
429
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
430
- fs.writeFileSync(filePath, source);
431
- };
432
- var toPosix = (value) => value.split(path.sep).join(path.posix.sep);
433
- var getRelativeImportPath = (fromDirectory, toFile) => {
434
- const relativePath = toPosix(path.relative(fromDirectory, toFile));
435
- if (relativePath.startsWith(".")) {
436
- return relativePath;
437
- }
438
- return `./${relativePath}`;
439
- };
440
- var serializeData = (data) => JSON.stringify(data, null, 2);
441
- var collectFiles = (directoryPath) => {
442
- if (!fs.existsSync(directoryPath)) {
443
- return [];
444
- }
445
- const entries = fs.readdirSync(directoryPath, { withFileTypes: true });
446
- return entries.flatMap((entry) => {
447
- const entryPath = path.join(directoryPath, entry.name);
448
- return entry.isDirectory() ? collectFiles(entryPath) : [entryPath];
449
- });
450
- };
451
- var removeEmptyDirectories = (directoryPath, rootPath) => {
452
- if (!fs.existsSync(directoryPath)) {
453
- return;
454
- }
455
- for (const entry of fs.readdirSync(directoryPath, { withFileTypes: true })) {
456
- if (!entry.isDirectory()) {
457
- continue;
458
- }
459
- removeEmptyDirectories(path.join(directoryPath, entry.name), rootPath);
460
- }
461
- if (directoryPath === rootPath) {
462
- return;
463
- }
464
- if (fs.readdirSync(directoryPath).length === 0) {
465
- fs.rmdirSync(directoryPath);
466
- }
467
- };
468
- var getGeneratedPageSource = (contentImportPath) => {
469
- return [
470
- "import { DocsPage } from '@unterberg/nivel/client'",
471
- `import Content from ${JSON.stringify(contentImportPath)}`,
472
- "",
473
- "const Page = () => {",
474
- " return <DocsPage Content={Content} />",
475
- "}",
476
- "",
477
- "export default Page",
478
- ""
479
- ].join("\n");
480
- };
481
- var getGeneratedLayoutSource = () => {
482
- return [
483
- "import { DocsRouteLayout } from '@unterberg/nivel/client'",
484
- "import type { ReactNode } from 'react'",
485
- "",
486
- "const Layout = ({ children }: { children: ReactNode }) => {",
487
- " return <DocsRouteLayout>{children}</DocsRouteLayout>",
488
- "}",
489
- "",
490
- "export default Layout",
491
- ""
492
- ].join("\n");
493
- };
494
- var getGeneratedDataSource = (data) => {
495
- return [
496
- "import type { DocPageData } from '@unterberg/nivel'",
497
- "",
498
- `const data: DocPageData = ${serializeData(data)}`,
499
- "",
500
- "const pageData = () => {",
501
- " return data",
502
- "}",
503
- "",
504
- "export default pageData",
505
- ""
506
- ].join("\n");
507
- };
508
- var getSidebarIconEntries = (nodes) => {
509
- return nodes.flatMap((node) => {
510
- const iconEntries = node.icon ? [{ iconKey: getDocsIconMapKey(node.kind, node.id), iconName: node.icon }] : [];
511
- if (node.kind === "group") {
512
- return [...iconEntries, ...getSidebarIconEntries(node.items)];
513
- }
514
- return iconEntries;
515
- });
516
- };
517
- var getGeneratedIconMapSource = (entries) => {
518
- if (entries.length === 0) {
519
- return "{}";
520
- }
521
- return ["{", ...entries.map(({ iconKey, iconName }) => ` ${JSON.stringify(iconKey)}: ${iconName},`), "}"].join("\n");
522
- };
523
- var getDocsIconNode = (iconName) => {
524
- const cachedIconNode = lucideIconNodeByName.get(iconName);
525
- if (cachedIconNode) {
526
- return cachedIconNode;
527
- }
528
- const iconComponent = lucideIcons2[iconName];
529
- if (!iconComponent || typeof iconComponent !== "object" || !("render" in iconComponent)) {
530
- throw new Error(`Unable to resolve lucide-react export for docs icon "${iconName}".`);
531
- }
532
- const iconElement = iconComponent.render({}, null);
533
- const iconNode = iconElement.props?.iconNode;
534
- if (!iconNode) {
535
- throw new Error(`Unable to read lucide-react icon node for docs icon "${iconName}".`);
536
- }
537
- lucideIconNodeByName.set(iconName, iconNode);
538
- return iconNode;
539
- };
540
- var getGeneratedIconDefinitionsSource = (iconNames) => {
541
- if (iconNames.length === 0) {
542
- return [];
543
- }
544
- const definitions = iconNames.flatMap((iconName) => {
545
- return [`const ${iconName} = createDocsIcon(${JSON.stringify(getDocsIconNode(iconName))})`, ""];
546
- });
547
- return [
548
- "import { createElement, forwardRef, type SVGProps } from 'react'",
549
- "",
550
- "type DocsGeneratedIconProps = SVGProps<SVGSVGElement> & {",
551
- " size?: string | number",
552
- " absoluteStrokeWidth?: boolean",
553
- "}",
554
- "",
555
- "type DocsGeneratedIconNode = [tagName: string, attrs: Record<string, string>][]",
556
- "",
557
- "const docsGeneratedIconSvgAttrs = {",
558
- " xmlns: 'http://www.w3.org/2000/svg',",
559
- " fill: 'none',",
560
- " viewBox: '0 0 24 24',",
561
- " stroke: 'currentColor',",
562
- " strokeWidth: 2,",
563
- " strokeLinecap: 'round',",
564
- " strokeLinejoin: 'round',",
565
- "} as const",
566
- "",
567
- "const createDocsIcon = (iconNode: DocsGeneratedIconNode) => {",
568
- " return forwardRef<SVGSVGElement, DocsGeneratedIconProps>(",
569
- ' ({ color = "currentColor", size = 24, strokeWidth = 2, absoluteStrokeWidth, children, ...props }, ref) => {',
570
- " const resolvedSize = typeof size === 'number' ? size : Number(size)",
571
- " const resolvedStrokeWidth =",
572
- " absoluteStrokeWidth && Number.isFinite(resolvedSize) && resolvedSize > 0",
573
- " ? (Number(strokeWidth) * 24) / resolvedSize",
574
- " : strokeWidth",
575
- "",
576
- " return createElement(",
577
- " 'svg',",
578
- " {",
579
- " ...docsGeneratedIconSvgAttrs,",
580
- " ...props,",
581
- " ref,",
582
- " width: size,",
583
- " height: size,",
584
- " stroke: color,",
585
- " strokeWidth: resolvedStrokeWidth,",
586
- " },",
587
- " ...iconNode.map(([tagName, attrs]) => createElement(tagName, attrs)),",
588
- " children,",
589
- " )",
590
- " },",
591
- " )",
592
- "}",
593
- "",
594
- ...definitions
595
- ];
596
- };
597
- var getGeneratedGlobalContextSource = (data) => {
598
- const iconEntries = data.sidebarSections.flatMap((section) => {
599
- const sectionIconEntries = section.icon ? [{ iconKey: getDocsIconMapKey("section", section.id), iconName: section.icon }] : [];
600
- return [...sectionIconEntries, ...getSidebarIconEntries(section.items)];
601
- });
602
- const iconImports = [...new Set(iconEntries.map(({ iconName }) => iconName))].sort();
603
- return [
604
- "import type { DocsGlobalContextData, DocsGlobalContextSerializableData, DocsIconMap } from '@unterberg/nivel'",
605
- ...getGeneratedIconDefinitionsSource(iconImports),
606
- "",
607
- `const docsGlobalContextSerializableData: DocsGlobalContextSerializableData = ${serializeData(data)}`,
608
- "",
609
- `const docsIconMap: DocsIconMap = ${getGeneratedIconMapSource(iconEntries)}`,
610
- "",
611
- "const docsGlobalContextData: DocsGlobalContextData = {",
612
- " ...docsGlobalContextSerializableData,",
613
- " docsIconMap,",
614
- "}",
615
- "",
616
- "export { docsGlobalContextData }",
617
- ""
618
- ].join("\n");
619
- };
620
- var getRouteString = (href) => {
621
- if (href === "/") {
622
- return href;
623
- }
624
- return href.replace(/\/+$/g, "");
625
- };
626
- var getGeneratedRouteSource = (href) => {
627
- return [`export default ${JSON.stringify(getRouteString(href))}`, ""].join("\n");
628
- };
629
- var getGeneratedTextExport = (value) => {
630
- return [`export default ${JSON.stringify(value)}`, ""].join("\n");
631
- };
632
- var toDocPageLinkData = (page) => {
633
- if (!page) {
634
- return null;
635
- }
636
- return {
637
- id: page.id,
638
- title: page.title,
639
- href: page.href,
640
- documentTitle: page.documentTitle
641
- };
642
- };
643
- var getGeneratedPagesRoot = (rootDir) => path.join(rootDir, "pages", GENERATED_DIRNAME);
644
- var getDocsConfigPath = (rootDir) => path.join(rootDir, "pages", "+docs.ts");
645
- var getDocsGraphPath = (rootDir) => path.join(rootDir, "docs", "docs.graph.ts");
646
- var getDocsSourcePaths = (options) => {
647
- const resolved = resolveDocsConfig(options.docsConfig);
648
- return {
649
- contentRootPath: path.join(options.rootDir, resolved.contentDir),
650
- docsConfigPath: getDocsConfigPath(options.rootDir),
651
- docsGraphPath: getDocsGraphPath(options.rootDir),
652
- generatedRootPath: getGeneratedPagesRoot(options.rootDir)
653
- };
654
- };
655
- var isDocsSourcePath = (filePath, docsSourcePaths) => {
656
- const normalized = toPosix(filePath);
657
- if (isGeneratedDocsPath(filePath, docsSourcePaths)) {
658
- return false;
659
- }
660
- const docsConfigPath = toPosix(docsSourcePaths.docsConfigPath);
661
- const docsGraphPath = toPosix(docsSourcePaths.docsGraphPath);
662
- const contentRootPath = toPosix(docsSourcePaths.contentRootPath);
663
- return normalized === docsConfigPath || normalized === docsGraphPath || normalized === contentRootPath || normalized.startsWith(`${contentRootPath}/`);
664
- };
665
- var isGeneratedDocsPath = (filePath, docsSourcePaths) => {
666
- const normalized = toPosix(filePath);
667
- const generatedRootPath = toPosix(docsSourcePaths.generatedRootPath);
668
- return normalized.startsWith(generatedRootPath);
669
- };
670
- var syncGeneratedDocsPages = (options) => {
671
- const { rootDir, docsConfig } = options;
672
- const resolved = resolveDocsConfig(docsConfig);
673
- const generatedPagesRoot = getGeneratedPagesRoot(rootDir);
674
- const docsContentRoot = path.join(rootDir, resolved.contentDir);
675
- const expectedFiles = /* @__PURE__ */ new Set();
676
- const globalContextFilePath = path.join(generatedPagesRoot, "_docsGlobalContext.ts");
677
- const layoutFilePath = path.join(generatedPagesRoot, "+Layout.tsx");
678
- fs.mkdirSync(generatedPagesRoot, { recursive: true });
679
- const globalContextData = {
680
- siteTitle: resolved.siteTitle,
681
- robots: resolved.robots,
682
- basePath: resolved.basePath,
683
- theme: resolved.theme,
684
- footer: resolved.footer,
685
- brand: resolved.brand,
686
- head: resolved.head,
687
- partners: resolved.partners,
688
- social: resolved.social,
689
- algolia: resolved.algolia,
690
- pages: resolved.pages,
691
- navbarItems: resolved.navbarItems,
692
- sidebarSections: resolved.sections
693
- };
694
- writeFileIfChanged(globalContextFilePath, getGeneratedGlobalContextSource(globalContextData));
695
- writeFileIfChanged(layoutFilePath, getGeneratedLayoutSource());
696
- expectedFiles.add(globalContextFilePath);
697
- expectedFiles.add(layoutFilePath);
698
- for (const [pageIndex, page] of resolved.pages.entries()) {
699
- const contentFilePath = path.join(docsContentRoot, page.source);
700
- if (!fs.existsSync(contentFilePath)) {
701
- throw new Error(`Docs page "${page.id}" points to missing source file: ${contentFilePath}`);
702
- }
703
- const pageSource = fs.readFileSync(contentFilePath, "utf8");
704
- const data = {
705
- page: getResolvedPageById(resolved, page.id),
706
- headings: extractDocHeadings(pageSource),
707
- previousPage: toDocPageLinkData(resolved.pages[pageIndex - 1]),
708
- nextPage: toDocPageLinkData(resolved.pages[pageIndex + 1])
709
- };
710
- const routeTargets = [
711
- { routeHref: page.href, routePath: page.slug },
712
- ...page.aliases.map((routePath, index) => ({
713
- routeHref: page.aliasHrefs[index],
714
- routePath
715
- }))
716
- ];
717
- for (const { routeHref, routePath } of routeTargets) {
718
- const pageDir = path.join(generatedPagesRoot, ...routePath.split("/"));
719
- const contentImportPath = getRelativeImportPath(pageDir, contentFilePath);
720
- const pageFilePath = path.join(pageDir, "+Page.tsx");
721
- const dataFilePath = path.join(pageDir, "+data.ts");
722
- const routeFilePath = path.join(pageDir, "+route.ts");
723
- const titleFilePath = path.join(pageDir, "+title.ts");
724
- writeFileIfChanged(pageFilePath, getGeneratedPageSource(contentImportPath));
725
- writeFileIfChanged(dataFilePath, getGeneratedDataSource(data));
726
- writeFileIfChanged(routeFilePath, getGeneratedRouteSource(routeHref));
727
- writeFileIfChanged(titleFilePath, getGeneratedTextExport(page.documentTitle));
728
- expectedFiles.add(pageFilePath);
729
- expectedFiles.add(dataFilePath);
730
- expectedFiles.add(routeFilePath);
731
- expectedFiles.add(titleFilePath);
732
- if (page.description) {
733
- const descriptionFilePath = path.join(pageDir, "+description.ts");
734
- writeFileIfChanged(descriptionFilePath, getGeneratedTextExport(page.description));
735
- expectedFiles.add(descriptionFilePath);
736
- }
737
- }
738
- }
739
- for (const filePath of collectFiles(generatedPagesRoot)) {
740
- if (expectedFiles.has(filePath)) {
741
- continue;
742
- }
743
- fs.rmSync(filePath, { force: true });
744
- }
745
- removeEmptyDirectories(generatedPagesRoot, generatedPagesRoot);
746
- };
747
-
748
- // src/runtime/node/loadDocsConfig.ts
749
- import path2 from "path";
750
- var getDocsConfigModulePath = (rootDir) => {
751
- return path2.join(rootDir, "pages", "+docs.ts");
752
- };
753
- var getDocsConfigFromLoadedModule = (loaded, modulePath) => {
754
- const docsConfig = loaded.default;
755
- if (!docsConfig) {
756
- throw new Error(`Expected default export from ${modulePath}`);
757
- }
758
- return docsConfig;
759
- };
760
- var loadDocsConfig = async (options) => {
761
- const modulePath = getDocsConfigModulePath(options.rootDir);
762
- const loaded = await options.loadModule(modulePath);
763
- return getDocsConfigFromLoadedModule(loaded, modulePath);
764
- };
765
-
766
- // src/runtime/node/scaffold.ts
767
- import fs2 from "fs";
768
- import path3 from "path";
769
- var MANAGED_SCRIPT_NAMES = ["generate:docs", "predev", "prebuild", "pretypecheck"];
770
- var REQUIRED_DEPENDENCIES = ["@unterberg/nivel", "react", "react-dom", "vike", "vike-react"];
771
- var REQUIRED_DEV_DEPENDENCIES = ["vite", "typescript", "@types/react", "@types/react-dom"];
772
- var getConsumerViteConfigFilename = (packageJson) => {
773
- return packageJson.type === "module" ? "vite.config.ts" : "vite.config.mts";
774
- };
775
- var getViteConfigTemplate = () => {
776
- return [
777
- "import { nivelTailwindVite } from '@unterberg/nivel/tailwind'",
778
- "import vike from 'vike/plugin'",
779
- "",
780
- "process.env.VIKE_CRAWL ??= JSON.stringify({ git: false })",
781
- "",
782
- "const base = (() => {",
783
- " const normalized = process.env.PAGES_BASE_PATH?.trim().replace(/^\\/+|\\/+$/g, '') ?? ''",
784
- " return normalized ? `/${normalized}/` : '/'",
785
- "})()",
786
- "",
787
- "export default {",
788
- " base,",
789
- " plugins: [nivelTailwindVite(), vike()],",
790
- "}",
791
- ""
792
- ].join("\n");
793
- };
794
- var getDocsConfigTemplate = () => {
795
- return [
796
- "import type { DocsConfig } from '@unterberg/nivel'",
797
- "import { docsGraph } from '../docs/docs.graph'",
798
- "",
799
- "const docsConfig = {",
800
- " graph: docsGraph,",
801
- " siteTitle: 'My Docs',",
802
- " siteDescription: 'Documentation site powered by @unterberg/nivel.',",
803
- " // Add siteUrl to enable automatic sitemap.xml and robots.txt generation.",
804
- " // siteUrl: 'https://docs.example.com',",
805
- " // Set robots to false to emit noindex/nofollow and a disallow-all robots.txt.",
806
- " // robots: false,",
807
- " // Set customFonts to false if you want to fully own font loading in consumer CSS.",
808
- " // customFonts: false,",
809
- " basePath: '/docs',",
810
- "} satisfies DocsConfig",
811
- "",
812
- "export default docsConfig",
813
- ""
814
- ].join("\n");
815
- };
816
- var getDocsGraphTemplate = () => {
817
- return [
818
- "import type { DocsGraph } from '@unterberg/nivel'",
819
- "",
820
- "export const docsGraph = {",
821
- " items: [",
822
- " {",
823
- " kind: 'section',",
824
- " id: 'docs',",
825
- " title: 'Docs',",
826
- " items: [",
827
- " {",
828
- " kind: 'page',",
829
- " id: 'gettingStarted',",
830
- " title: 'Getting Started',",
831
- " slug: 'getting-started',",
832
- " source: 'content/getting-started/content.mdx',",
833
- " description: 'Getting started with @unterberg/nivel.',",
834
- " },",
835
- " ],",
836
- " },",
837
- " ],",
838
- "} satisfies DocsGraph",
839
- ""
840
- ].join("\n");
841
- };
842
- var getGettingStartedTemplate = () => {
843
- return [
844
- "This page is scaffolded by `nivel init` and wired through `docs/docs.graph.ts`.",
845
- "",
846
- "## Next steps",
847
- "",
848
- "- Update `pages/+docs.ts` with your site metadata.",
849
- "- Expand `docs/docs.graph.ts` with your docs structure.",
850
- "- Replace this page with your real getting-started guide.",
851
- ""
852
- ].join("\n");
853
- };
854
- var getLandingPageTemplate = () => {
855
- return [
856
- "import { Link, LayoutComponent } from '@unterberg/nivel'",
857
- "",
858
- "<LayoutComponent>",
859
- "# Welcome",
860
- "",
861
- "This starter page is scaffolded by `nivel init` so the app can boot before you build a custom landing page.",
862
- "",
863
- '<Link href="/docs/getting-started/">Read the getting started guide</Link>',
864
- "</LayoutComponent>"
865
- ].join("\n");
866
- };
867
- var getConfigTemplate = () => {
868
- return [
869
- "import { createNivelVikeConfig } from '@unterberg/nivel/vike'",
870
- "import docsConfig from './+docs'",
871
- "",
872
- "const config = {",
873
- " ...createNivelVikeConfig(docsConfig),",
874
- "",
875
- " // User-facing Vike levers stay visible in +config.ts.",
876
- " prerender: true,",
877
- " // ssr: true,",
878
- " // prefetchStaticAssets: 'viewport',",
879
- "}",
880
- "",
881
- "export default config",
882
- ""
883
- ].join("\n");
884
- };
885
- var getHeadTemplate = () => {
886
- return [
887
- "import { MetaHead } from '@unterberg/nivel/client'",
888
- "",
889
- "export const Head = () => {",
890
- " return <MetaHead />",
891
- "}",
892
- ""
893
- ].join("\n");
894
- };
895
- var getLayoutTemplate = () => {
896
- return [
897
- "import { AppLayout } from '@unterberg/nivel/client'",
898
- "import type { ReactNode } from 'react'",
899
- "",
900
- "const Layout = ({ children }: { children: ReactNode }) => {",
901
- " return <AppLayout>{children}</AppLayout>",
902
- "}",
903
- "",
904
- "export default Layout",
905
- ""
906
- ].join("\n");
907
- };
908
- var getGlobalContextTemplate = () => {
909
- return [
910
- "import { docsGlobalContextData } from './(nivel-generated)/_docsGlobalContext'",
911
- "",
912
- "export const onCreateGlobalContext = (globalContext: { docs?: typeof docsGlobalContextData }) => {",
913
- " globalContext.docs = docsGlobalContextData",
914
- "}",
915
- ""
916
- ].join("\n");
917
- };
918
- var getWrapperTemplate = () => {
919
- return [
920
- "import type { ReactNode } from 'react'",
921
- "import '../styles/global.css'",
922
- "",
923
- "const Wrapper = ({ children }: { children: ReactNode }) => {",
924
- " return <>{children}</>",
925
- "}",
926
- "",
927
- "export default Wrapper",
928
- ""
929
- ].join("\n");
930
- };
931
- var getGlobalStyleTemplate = () => {
932
- return [
933
- "@import '@unterberg/nivel/tailwind.css';",
934
- "@import './theme.css';",
935
- "",
936
- "@source '../pages';",
937
- "@source '../docs';",
938
- "",
939
- "@layer base {",
940
- " html,",
941
- " body {",
942
- " @apply bg-base-100 text-base-content font-sans antialiased md:subpixel-antialiased;",
943
- " }",
944
- "",
945
- " .prose-container {",
946
- " @apply prose prose-neutral max-w-none dark:prose-invert;",
947
- " @apply prose-a:text-primary;",
948
- " @apply prose-pre:bg-base-200!;",
949
- " @apply prose-code:rounded!;",
950
- " @apply prose-code:bg-primary/5!;",
951
- " @apply prose-code:border-primary/15!;",
952
- " @apply prose-code:dark:bg-primary/10!;",
953
- " @apply prose-code:dark:border-primary/20!;",
954
- " @apply prose-p:leading-[180%];",
955
- " @apply prose-li:leading-[180%];",
956
- " @apply prose-p:after:content-none;",
957
- " @apply prose-p:before:content-none;",
958
- " @apply prose-blockquote:not-italic;",
959
- " @apply prose-blockquote:bg-base-200;",
960
- " @apply prose-blockquote:py-2;",
961
- " }",
962
- "",
963
- " .prose-container :where(p, li, blockquote, td, th, a) {",
964
- " overflow-wrap: anywhere;",
965
- " word-break: break-word;",
966
- " }",
967
- "}",
968
- ""
969
- ].join("\n");
970
- };
971
- var getThemeTemplate = () => {
972
- return [
973
- "@custom-variant dark (&:where(",
974
- " [data-theme='consumer-dark'],",
975
- " [data-theme='consumer-dark'] *",
976
- " ));",
977
- "",
978
- "@plugin '@unterberg/nivel/daisyui-theme' {",
979
- " name: 'consumer-light';",
980
- " default: true;",
981
- " prefersdark: false;",
982
- " color-scheme: 'light';",
983
- " --color-base-100: #f6f6f4;",
984
- " --color-base-200: #ffffff;",
985
- " --color-base-300: #ecebe7;",
986
- " --color-base-content: #171717;",
987
- " --color-primary: #0f766e;",
988
- " --color-primary-content: #f8fafc;",
989
- " --color-secondary: #d97706;",
990
- " --color-secondary-content: #111827;",
991
- " --color-accent: #1d4ed8;",
992
- " --color-accent-content: #f8fafc;",
993
- " --color-neutral: #171717;",
994
- " --color-neutral-content: #f8fafc;",
995
- " --color-info: #2563eb;",
996
- " --color-info-content: #eff6ff;",
997
- " --color-success: #15803d;",
998
- " --color-success-content: #f0fdf4;",
999
- " --color-warning: #d97706;",
1000
- " --color-warning-content: #fff7ed;",
1001
- " --color-error: #dc2626;",
1002
- " --color-error-content: #fef2f2;",
1003
- " --radius-selector: 0.25rem;",
1004
- " --radius-field: 0.5rem;",
1005
- " --radius-box: 1rem;",
1006
- " --size-selector: 0.25rem;",
1007
- " --size-field: 0.25rem;",
1008
- " --border: 1px;",
1009
- " --depth: 0;",
1010
- " --noise: 0;",
1011
- "}",
1012
- "",
1013
- "@plugin '@unterberg/nivel/daisyui-theme' {",
1014
- " name: 'consumer-dark';",
1015
- " default: false;",
1016
- " prefersdark: false;",
1017
- " color-scheme: 'dark';",
1018
- " --color-base-100: #151515;",
1019
- " --color-base-200: #1e1e1e;",
1020
- " --color-base-300: #2a2a2a;",
1021
- " --color-base-content: #ededed;",
1022
- " --color-primary: #2dd4bf;",
1023
- " --color-primary-content: #042f2e;",
1024
- " --color-secondary: #f59e0b;",
1025
- " --color-secondary-content: #1c1917;",
1026
- " --color-accent: #60a5fa;",
1027
- " --color-accent-content: #172554;",
1028
- " --color-neutral: #ededed;",
1029
- " --color-neutral-content: #171717;",
1030
- " --color-info: #60a5fa;",
1031
- " --color-info-content: #172554;",
1032
- " --color-success: #4ade80;",
1033
- " --color-success-content: #052e16;",
1034
- " --color-warning: #fbbf24;",
1035
- " --color-warning-content: #451a03;",
1036
- " --color-error: #f87171;",
1037
- " --color-error-content: #450a0a;",
1038
- " --radius-selector: 0.25rem;",
1039
- " --radius-field: 0.5rem;",
1040
- " --radius-box: 1rem;",
1041
- " --size-selector: 0.25rem;",
1042
- " --size-field: 0.25rem;",
1043
- " --border: 1px;",
1044
- " --depth: 0;",
1045
- " --noise: 0;",
1046
- "}",
1047
- "",
1048
- "@theme inline {",
1049
- " --color-base-muted: color-mix(",
1050
- " in oklab,",
1051
- " var(--color-base-content) 65%,",
1052
- " transparent",
1053
- " );",
1054
- " --color-base-muted-medium: color-mix(",
1055
- " in oklab,",
1056
- " var(--color-base-content) 40%,",
1057
- " transparent",
1058
- " );",
1059
- " --color-base-muted-light: color-mix(",
1060
- " in oklab,",
1061
- " var(--color-base-content) 12%,",
1062
- " transparent",
1063
- " );",
1064
- " --color-base-muted-superlight: color-mix(",
1065
- " in oklab,",
1066
- " var(--color-base-content) 5%,",
1067
- " transparent",
1068
- " );",
1069
- " --color-primary-muted: color-mix(",
1070
- " in oklab,",
1071
- " var(--color-primary) 80%,",
1072
- " transparent",
1073
- " );",
1074
- " --color-primary-muted-medium: color-mix(",
1075
- " in oklab,",
1076
- " var(--color-primary) 50%,",
1077
- " transparent",
1078
- " );",
1079
- " --color-primary-muted-light: color-mix(",
1080
- " in oklab,",
1081
- " var(--color-primary) 20%,",
1082
- " transparent",
1083
- " );",
1084
- " --color-primary-muted-superlight: color-mix(",
1085
- " in oklab,",
1086
- " var(--color-primary) 5%,",
1087
- " transparent",
1088
- " );",
1089
- " --nivel-mermaid-node-fill: var(--color-primary-muted-superlight);",
1090
- " --nivel-mermaid-node-stroke: var(--color-primary-muted-medium);",
1091
- " --nivel-mermaid-node-stroke-width: 1px;",
1092
- " --nivel-mermaid-node-text: var(--color-base-content);",
1093
- " --nivel-mermaid-edge-label-fill: var(--color-base-100);",
1094
- " --nivel-mermaid-edge-label-text: var(--color-base-content);",
1095
- " --nivel-mermaid-line-color: var(--color-primary-muted);",
1096
- " --nivel-mermaid-line-width: 1.5px;",
1097
- " --nivel-mermaid-cluster-fill: var(--color-base-100);",
1098
- " --nivel-mermaid-cluster-stroke: var(--color-primary-muted-light);",
1099
- " --nivel-mermaid-cluster-stroke-width: 1px;",
1100
- " --font-sans: 'Inter', 'Helvetica Neue', sans-serif;",
1101
- " --font-mono:",
1102
- " 'Monaco', 'SF Mono', SF Mono, SF Mono Regular, Consolas, 'Liberation Mono',",
1103
- " Menlo, Courier, monospace;",
1104
- "}",
1105
- ""
1106
- ].join("\n");
1107
- };
1108
- var getGlobalTypesTemplate = () => {
1109
- return [
1110
- "declare module '*.mdx' {",
1111
- " import type { ComponentType } from 'react'",
1112
- "",
1113
- " const MdxComponent: ComponentType",
1114
- " export default MdxComponent",
1115
- "}",
1116
- "",
1117
- "declare module '*.css'",
1118
- "",
1119
- "declare global {",
1120
- " namespace Vike {",
1121
- " interface GlobalContext {",
1122
- " docs: import('@unterberg/nivel').DocsGlobalContextData",
1123
- " }",
1124
- " }",
1125
- "}",
1126
- ""
1127
- ].join("\n");
1128
- };
1129
- var getManagedFileEntries = (packageJson) => {
1130
- return [
1131
- [getConsumerViteConfigFilename(packageJson), getViteConfigTemplate()],
1132
- ["pages/+docs.ts", getDocsConfigTemplate()],
1133
- ["docs/docs.graph.ts", getDocsGraphTemplate()],
1134
- ["docs/content/getting-started/content.mdx", getGettingStartedTemplate()],
1135
- ["pages/index/+Page.mdx", getLandingPageTemplate()],
1136
- ["pages/+config.ts", getConfigTemplate()],
1137
- ["pages/+Head.tsx", getHeadTemplate()],
1138
- ["pages/+Layout.tsx", getLayoutTemplate()],
1139
- ["pages/+onCreateGlobalContext.ts", getGlobalContextTemplate()],
1140
- ["pages/+Wrapper.tsx", getWrapperTemplate()],
1141
- ["styles/global.css", getGlobalStyleTemplate()],
1142
- ["styles/theme.css", getThemeTemplate()],
1143
- ["global.d.ts", getGlobalTypesTemplate()]
1144
- ];
1145
- };
1146
- var readFileIfExists = (filePath) => {
1147
- if (!fs2.existsSync(filePath)) {
1148
- return null;
1149
- }
1150
- return fs2.readFileSync(filePath, "utf8");
1151
- };
1152
- var getConfigPathToWrite = (rootDir, packageJson) => {
1153
- const expectedFilename = getConsumerViteConfigFilename(packageJson);
1154
- const expectedPath = path3.join(rootDir, expectedFilename);
1155
- const alternateFilename = expectedFilename === "vite.config.ts" ? "vite.config.mts" : "vite.config.ts";
1156
- const alternatePath = path3.join(rootDir, alternateFilename);
1157
- if (fs2.existsSync(expectedPath)) {
1158
- return expectedFilename;
1159
- }
1160
- if (fs2.existsSync(alternatePath)) {
1161
- return alternateFilename;
1162
- }
1163
- return expectedFilename;
1164
- };
1165
- var getScaffoldVisibilitySummary = (packageJson) => {
1166
- return `Scaffolded ${getConsumerViteConfigFilename(packageJson)} and local Tailwind starter files remain visible and editable in the consumer.`;
1167
- };
1168
- var getManagedFileEntriesForConsumer = (rootDir, packageJson) => {
1169
- return getManagedFileEntries(packageJson).map(([relativeFilePath, source]) => {
1170
- if (relativeFilePath !== getConsumerViteConfigFilename(packageJson)) {
1171
- return [relativeFilePath, source];
1172
- }
1173
- return [getConfigPathToWrite(rootDir, packageJson), source];
1174
- });
1175
- };
1176
- var getTailwindBootstrapWarnings = (rootDir) => {
1177
- const warnings = [];
1178
- const wrapperPath = path3.join(rootDir, "pages", "+Wrapper.tsx");
1179
- const globalCssPath = path3.join(rootDir, "styles", "global.css");
1180
- const themeCssPath = path3.join(rootDir, "styles", "theme.css");
1181
- const packageJsonPath = path3.join(rootDir, "package.json");
1182
- const viteConfigMtsPath = path3.join(rootDir, "vite.config.mts");
1183
- const viteConfigTsPath = path3.join(rootDir, "vite.config.ts");
1184
- const packageJsonSource = readFileIfExists(packageJsonPath);
1185
- const packageJson = packageJsonSource ? JSON.parse(packageJsonSource) : null;
1186
- const expectedViteConfigFilename = getConsumerViteConfigFilename(packageJson ?? {});
1187
- const viteConfigPath = fs2.existsSync(viteConfigMtsPath) ? viteConfigMtsPath : viteConfigTsPath;
1188
- const viteConfigSource = readFileIfExists(viteConfigPath);
1189
- if (!viteConfigSource?.includes("@unterberg/nivel/tailwind") || !viteConfigSource.includes("nivelTailwindVite()")) {
1190
- warnings.push(
1191
- `${expectedViteConfigFilename} should use @unterberg/nivel/tailwind and call nivelTailwindVite() for the engine-owned Tailwind integration.`
1192
- );
1193
- }
1194
- if (viteConfigPath === viteConfigTsPath && packageJson?.type !== "module") {
1195
- warnings.push(
1196
- 'vite.config.ts is loaded through CommonJS in packages without "type": "module". Rename it to vite.config.mts to avoid ESM-only dependency errors.'
1197
- );
1198
- }
1199
- if (packageJson?.type === "module" && fs2.existsSync(viteConfigMtsPath) && !fs2.existsSync(viteConfigTsPath)) {
1200
- warnings.push('vite.config.mts is unnecessary in packages with "type": "module". Rename it to vite.config.ts.');
1201
- }
1202
- if (fs2.existsSync(viteConfigMtsPath) && fs2.existsSync(viteConfigTsPath)) {
1203
- warnings.push(
1204
- "Both vite.config.mts and vite.config.ts exist. Keep only the expected config file for the package module type."
1205
- );
1206
- }
1207
- const wrapperSource = readFileIfExists(wrapperPath);
1208
- if (!wrapperSource?.includes("../styles/global.css")) {
1209
- warnings.push("pages/+Wrapper.tsx should import ../styles/global.css.");
1210
- }
1211
- const globalCssSource = readFileIfExists(globalCssPath);
1212
- if (!globalCssSource?.includes("@unterberg/nivel/tailwind.css") || !globalCssSource.includes("@import './theme.css';") || !globalCssSource.includes("@source '../pages';") || !globalCssSource.includes("@source '../docs';")) {
1213
- warnings.push(
1214
- "styles/global.css should import @unterberg/nivel/tailwind.css, import ./theme.css, and declare @source '../pages' plus @source '../docs'."
1215
- );
1216
- }
1217
- if (!fs2.existsSync(themeCssPath)) {
1218
- warnings.push("styles/theme.css is missing; define local daisyUI themes there.");
1219
- }
1220
- return warnings;
1221
- };
1222
- var getGenerateDocsRunner = (packageJson) => {
1223
- const packageManager = packageJson.packageManager?.trim() ?? "";
1224
- if (packageManager.startsWith("pnpm@")) {
1225
- return "pnpm generate:docs";
1226
- }
1227
- if (packageManager.startsWith("npm@")) {
1228
- return "npm run generate:docs";
1229
- }
1230
- return "npm run generate:docs";
1231
- };
1232
- var getManagedScripts = (packageJson) => {
1233
- const generateDocsRunner = getGenerateDocsRunner(packageJson);
1234
- return {
1235
- "generate:docs": "nivel prepare",
1236
- predev: generateDocsRunner,
1237
- prebuild: generateDocsRunner,
1238
- pretypecheck: generateDocsRunner
1239
- };
1240
- };
1241
- var writeFile = (filePath, source) => {
1242
- fs2.mkdirSync(path3.dirname(filePath), { recursive: true });
1243
- fs2.writeFileSync(filePath, source);
1244
- };
1245
- var writeManagedFile = (rootDir, relativeFilePath, source, force, result) => {
1246
- const filePath = path3.join(rootDir, relativeFilePath);
1247
- const exists = fs2.existsSync(filePath);
1248
- if (exists && !force) {
1249
- result.skippedFiles.push(relativeFilePath);
1250
- return;
1251
- }
1252
- writeFile(filePath, source);
1253
- if (exists) {
1254
- result.overwrittenFiles.push(relativeFilePath);
1255
- return;
1256
- }
1257
- result.createdFiles.push(relativeFilePath);
1258
- };
1259
- var readPackageJson = (rootDir) => {
1260
- const packageJsonPath = path3.join(rootDir, "package.json");
1261
- if (!fs2.existsSync(packageJsonPath)) {
1262
- throw new Error(`Expected package.json in ${rootDir}`);
1263
- }
1264
- return {
1265
- packageJson: JSON.parse(fs2.readFileSync(packageJsonPath, "utf8")),
1266
- packageJsonPath
1267
- };
1268
- };
1269
- var patchPackageScripts = (packageJson, packageJsonPath, result) => {
1270
- const scripts = { ...packageJson.scripts ?? {} };
1271
- const managedScripts = getManagedScripts(packageJson);
1272
- for (const scriptName of MANAGED_SCRIPT_NAMES) {
1273
- if (scripts[scriptName] === managedScripts[scriptName]) {
1274
- continue;
1275
- }
1276
- scripts[scriptName] = managedScripts[scriptName];
1277
- result.updatedScripts.push(scriptName);
1278
- }
1279
- const nextPackageJson = {
1280
- ...packageJson,
1281
- scripts
1282
- };
1283
- fs2.writeFileSync(packageJsonPath, `${JSON.stringify(nextPackageJson, null, 2)}
1284
- `);
1285
- };
1286
- var getMissingDependencies = (packageJson) => {
1287
- const installed = /* @__PURE__ */ new Set([
1288
- ...Object.keys(packageJson.dependencies ?? {}),
1289
- ...Object.keys(packageJson.devDependencies ?? {})
1290
- ]);
1291
- return [...REQUIRED_DEPENDENCIES, ...REQUIRED_DEV_DEPENDENCIES].filter((packageName) => !installed.has(packageName));
1292
- };
1293
- var getInitSummary = (result) => {
1294
- const lines = ["Initialized nivel consumer scaffolding."];
1295
- if (result.createdFiles.length > 0) {
1296
- lines.push(`Created files: ${result.createdFiles.join(", ")}`);
1297
- }
1298
- if (result.overwrittenFiles.length > 0) {
1299
- lines.push(`Overwritten files: ${result.overwrittenFiles.join(", ")}`);
1300
- }
1301
- if (result.skippedFiles.length > 0) {
1302
- lines.push(`Skipped existing files: ${result.skippedFiles.join(", ")}`);
1303
- }
1304
- if (result.updatedScripts.length > 0) {
1305
- lines.push(`Updated package.json scripts: ${result.updatedScripts.join(", ")}`);
1306
- }
1307
- lines.push(getScaffoldVisibilitySummary(result.packageJson));
1308
- if (result.missingDependencies.length > 0) {
1309
- lines.push(`Missing dependencies: ${result.missingDependencies.join(", ")}`);
1310
- } else if (!result.allDependenciesPresent) {
1311
- lines.push("Dependency validation completed with warnings.");
1312
- } else {
1313
- lines.push("All required dependencies are already present.");
1314
- }
1315
- return `${lines.join("\n")}
1316
- `;
1317
- };
1318
- var initConsumer = (options) => {
1319
- const result = {
1320
- allDependenciesPresent: true,
1321
- createdFiles: [],
1322
- missingDependencies: [],
1323
- overwrittenFiles: [],
1324
- skippedFiles: [],
1325
- updatedScripts: [],
1326
- packageJson: {}
1327
- };
1328
- const { packageJson, packageJsonPath } = readPackageJson(options.rootDir);
1329
- result.packageJson = packageJson;
1330
- for (const [relativeFilePath, source] of getManagedFileEntriesForConsumer(options.rootDir, packageJson)) {
1331
- writeManagedFile(options.rootDir, relativeFilePath, source, options.force, result);
1332
- }
1333
- patchPackageScripts(packageJson, packageJsonPath, result);
1334
- result.missingDependencies = getMissingDependencies(packageJson);
1335
- result.allDependenciesPresent = result.missingDependencies.length === 0;
1336
- return result;
1337
- };
1338
-
1339
- export {
1340
- resolveDocsHref,
1341
- resolveDocsConfig,
1342
- getResolvedPageById,
1343
- getGeneratedPagesRoot,
1344
- getDocsSourcePaths,
1345
- isDocsSourcePath,
1346
- isGeneratedDocsPath,
1347
- syncGeneratedDocsPages,
1348
- loadDocsConfig,
1349
- getTailwindBootstrapWarnings,
1350
- getInitSummary,
1351
- initConsumer
1352
- };
1353
- //# sourceMappingURL=chunk-OVP4OFUG.js.map