blume 0.1.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +2123 -555
- package/dist/cli/index.js.map +39 -25
- package/dist/types/core/data.d.ts +16 -0
- package/dist/types/core/define-components.d.ts +9 -2
- package/dist/types/core/diagnostics.d.ts +5 -0
- package/dist/types/core/schema.d.ts +136 -508
- package/dist/types/core/types.d.ts +2 -2
- package/docs/02-deployment.mdx +21 -2
- package/docs/advanced/changelog.mdx +28 -1
- package/docs/advanced/custom-pages.mdx +63 -2
- package/docs/configuration/ai.mdx +20 -3
- package/docs/configuration/customization.mdx +103 -5
- package/docs/configuration/index.mdx +25 -11
- package/docs/configuration/search.mdx +13 -1
- package/docs/configuration/seo.mdx +5 -0
- package/docs/configuration/theming.mdx +51 -0
- package/docs/content/components.mdx +18 -0
- package/docs/content/islands.mdx +73 -0
- package/docs/content/navigation.mdx +25 -0
- package/docs/content/sources.mdx +43 -0
- package/docs/content/syntax.mdx +1 -1
- package/docs/index.mdx +3 -12
- package/docs/reference/cli.mdx +49 -1
- package/docs/reference/frontmatter.mdx +9 -1
- package/package.json +3 -1
- package/src/ai/ask-context.ts +131 -0
- package/src/ai/ask-data.ts +25 -0
- package/src/astro/component-slots.ts +165 -0
- package/src/astro/generate.ts +162 -26
- package/src/astro/integration.ts +59 -0
- package/src/astro/pages.ts +5 -12
- package/src/astro/templates.ts +102 -45
- package/src/blume-modules.d.ts +25 -0
- package/src/cli/commands/build.ts +186 -1
- package/src/cli/commands/check.ts +62 -0
- package/src/cli/commands/dev.ts +21 -1
- package/src/cli/commands/doctor.ts +23 -6
- package/src/cli/commands/init.ts +163 -15
- package/src/cli/commands/validate.ts +16 -2
- package/src/cli/env.ts +84 -0
- package/src/cli/index.ts +20 -0
- package/src/cli/internal-error.ts +63 -0
- package/src/cli/log.ts +30 -1
- package/src/cli/prepare.ts +22 -3
- package/src/cli/required-secrets.ts +44 -0
- package/src/components/BlumePage.astro +107 -0
- package/src/components/content/CodeBlock.astro +7 -2
- package/src/components/index.ts +3 -3
- package/src/components/islands/ask-ai.tsx +15 -1
- package/src/components/islands/hooks.ts +188 -0
- package/src/components/layout/Empty.astro +6 -0
- package/src/components/layout/Header.astro +24 -39
- package/src/components/layout/Logo.astro +50 -0
- package/src/components/layout/NavSelector.astro +75 -0
- package/src/components/layout/PageLayout.astro +38 -2
- package/src/components/layout/RootLayout.astro +70 -4
- package/src/components/layout/hydration-hint.ts +30 -0
- package/src/components/layout/overrides.ts +6 -4
- package/src/components/props.ts +68 -0
- package/src/core/builtin-tags.ts +39 -0
- package/src/core/component-diagnostics.ts +44 -0
- package/src/core/component-overrides.ts +478 -0
- package/src/core/config.ts +8 -0
- package/src/core/data.ts +14 -0
- package/src/core/define-components.ts +9 -2
- package/src/core/diagnostics.ts +90 -1
- package/src/core/graph.ts +7 -0
- package/src/core/nav-diagnostics.ts +205 -0
- package/src/core/project-graph.ts +40 -1
- package/src/core/schema.ts +54 -96
- package/src/core/sources/github-releases.ts +200 -0
- package/src/core/sources/normalize.ts +51 -0
- package/src/core/sources/resolve.ts +16 -0
- package/src/core/types.ts +2 -2
- package/src/deploy/redirects.ts +43 -0
- package/src/markdown/index.ts +24 -0
- package/src/migrate/mintlify/config.ts +1 -176
- package/src/migrate/starlight/config.ts +0 -4
- package/src/og/card.ts +163 -38
- package/src/registry/eject.ts +39 -9
- package/src/registry/registry.ts +166 -0
- package/src/runtime/index.ts +61 -0
- package/src/vite-env.d.ts +14 -0
- package/docs/changelog/v0-1-0.mdx +0 -12
- package/docs/changelog/v0-2-0.mdx +0 -16
package/dist/cli/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
4
4
|
|
|
5
5
|
// src/cli/index.ts
|
|
6
|
-
import { defineCommand as
|
|
6
|
+
import { defineCommand as defineCommand12, runMain } from "citty";
|
|
7
7
|
|
|
8
8
|
// src/core/version.ts
|
|
9
9
|
import { readFileSync } from "node:fs";
|
|
@@ -72,6 +72,145 @@ var layoutComponent = (config) => {
|
|
|
72
72
|
]
|
|
73
73
|
};
|
|
74
74
|
};
|
|
75
|
+
var contentComponent = (config) => {
|
|
76
|
+
const target = `components/blume/${config.file}`;
|
|
77
|
+
return {
|
|
78
|
+
description: config.description,
|
|
79
|
+
files: [
|
|
80
|
+
{
|
|
81
|
+
rewrite: true,
|
|
82
|
+
source: `components/content/${config.file}`,
|
|
83
|
+
target
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
name: config.name,
|
|
87
|
+
postInstall: [
|
|
88
|
+
"Register it in components.ts:",
|
|
89
|
+
' import { defineComponents } from "blume";',
|
|
90
|
+
` import ${config.tag} from "./${target}";`,
|
|
91
|
+
"",
|
|
92
|
+
` export default defineComponents({ mdx: { ${config.tag} } });`,
|
|
93
|
+
"",
|
|
94
|
+
"It imports the rest from `blume/*`, so it matches the built-in until you edit it."
|
|
95
|
+
]
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
var CONTENT_COMPONENTS = [
|
|
99
|
+
{
|
|
100
|
+
description: "Aside for notes, tips, and warnings.",
|
|
101
|
+
file: "Callout.astro",
|
|
102
|
+
name: "callout",
|
|
103
|
+
tag: "Callout"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
description: "A linkable card with icon, title, and body.",
|
|
107
|
+
file: "Card.astro",
|
|
108
|
+
name: "card",
|
|
109
|
+
tag: "Card"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
description: "A responsive grid of cards.",
|
|
113
|
+
file: "CardGroup.astro",
|
|
114
|
+
name: "card-group",
|
|
115
|
+
tag: "CardGroup"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
description: "Tabbed code blocks for multiple languages.",
|
|
119
|
+
file: "CodeGroup.astro",
|
|
120
|
+
name: "code-group",
|
|
121
|
+
tag: "CodeGroup"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
description: "A small status/label badge.",
|
|
125
|
+
file: "Badge.astro",
|
|
126
|
+
name: "badge",
|
|
127
|
+
tag: "Badge"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
description: "A numbered list of steps.",
|
|
131
|
+
file: "Steps.astro",
|
|
132
|
+
name: "steps",
|
|
133
|
+
tag: "Steps"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
description: "A single step within Steps.",
|
|
137
|
+
file: "Step.astro",
|
|
138
|
+
name: "step",
|
|
139
|
+
tag: "Step"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
description: "A tabbed content panel.",
|
|
143
|
+
file: "Tabs.astro",
|
|
144
|
+
name: "tabs",
|
|
145
|
+
tag: "Tabs"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
description: "A single tab within Tabs.",
|
|
149
|
+
file: "Tab.astro",
|
|
150
|
+
name: "tab",
|
|
151
|
+
tag: "Tab"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
description: "A collapsible accordion group.",
|
|
155
|
+
file: "Accordion.astro",
|
|
156
|
+
name: "accordion",
|
|
157
|
+
tag: "Accordion"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
description: "A single item within an Accordion.",
|
|
161
|
+
file: "AccordionItem.astro",
|
|
162
|
+
name: "accordion-item",
|
|
163
|
+
tag: "AccordionItem"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
description: "A multi-column layout.",
|
|
167
|
+
file: "Columns.astro",
|
|
168
|
+
name: "columns",
|
|
169
|
+
tag: "Columns"
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
description: "A single column within Columns.",
|
|
173
|
+
file: "Column.astro",
|
|
174
|
+
name: "column",
|
|
175
|
+
tag: "Column"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
description: "A bordered frame around an image or embed.",
|
|
179
|
+
file: "Frame.astro",
|
|
180
|
+
name: "frame",
|
|
181
|
+
tag: "Frame"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
description: "An inline expand/collapse disclosure.",
|
|
185
|
+
file: "Expandable.astro",
|
|
186
|
+
name: "expandable",
|
|
187
|
+
tag: "Expandable"
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
description: "A titled content panel.",
|
|
191
|
+
file: "Panel.astro",
|
|
192
|
+
name: "panel",
|
|
193
|
+
tag: "Panel"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
description: "A hover tooltip.",
|
|
197
|
+
file: "Tooltip.astro",
|
|
198
|
+
name: "tooltip",
|
|
199
|
+
tag: "Tooltip"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
description: "A compact linkable tile.",
|
|
203
|
+
file: "Tile.astro",
|
|
204
|
+
name: "tile",
|
|
205
|
+
tag: "Tile"
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
description: "A styled prompt / terminal block.",
|
|
209
|
+
file: "Prompt.astro",
|
|
210
|
+
name: "prompt",
|
|
211
|
+
tag: "Prompt"
|
|
212
|
+
}
|
|
213
|
+
];
|
|
75
214
|
var registry = [
|
|
76
215
|
layoutComponent({
|
|
77
216
|
description: "The top navigation bar (logo, search, nav links).",
|
|
@@ -102,7 +241,14 @@ var registry = [
|
|
|
102
241
|
file: "Pagination.astro",
|
|
103
242
|
name: "pagination",
|
|
104
243
|
slot: "Pagination"
|
|
105
|
-
})
|
|
244
|
+
}),
|
|
245
|
+
layoutComponent({
|
|
246
|
+
description: 'The "Was this page helpful?" feedback rating.',
|
|
247
|
+
file: "PageFeedback.astro",
|
|
248
|
+
name: "feedback",
|
|
249
|
+
slot: "Feedback"
|
|
250
|
+
}),
|
|
251
|
+
...CONTENT_COMPONENTS.map(contentComponent)
|
|
106
252
|
];
|
|
107
253
|
var findItem = (name) => registry.find((item) => item.name === name);
|
|
108
254
|
|
|
@@ -123,6 +269,7 @@ var rewriteImports = (content, sourceFile, srcRoot) => content.replaceAll(RELATI
|
|
|
123
269
|
|
|
124
270
|
// src/cli/log.ts
|
|
125
271
|
import { consola } from "consola";
|
|
272
|
+
import { relative as relative3 } from "pathe";
|
|
126
273
|
|
|
127
274
|
// src/core/diagnostics.ts
|
|
128
275
|
import { relative as relative2 } from "pathe";
|
|
@@ -135,12 +282,77 @@ class BlumeError extends Error {
|
|
|
135
282
|
this.diagnostic = diagnostic;
|
|
136
283
|
}
|
|
137
284
|
}
|
|
285
|
+
var DOCS_BASE = "https://useblume.dev";
|
|
286
|
+
var DOCS_PATHS = {
|
|
287
|
+
BLUME_ADAPTER_REQUIRED: "/docs/deployment",
|
|
288
|
+
BLUME_ASSETS_UNCHECKED: "/docs/reference/cli",
|
|
289
|
+
BLUME_ASSET_FETCH_FAILED: "/docs/content/sources",
|
|
290
|
+
BLUME_BROKEN_ANCHOR: "/docs/reference/cli",
|
|
291
|
+
BLUME_BROKEN_ASSET: "/docs/reference/cli",
|
|
292
|
+
BLUME_BROKEN_LINK: "/docs/reference/cli",
|
|
293
|
+
BLUME_CONFIG_INVALID: "/docs/configuration",
|
|
294
|
+
BLUME_CONFIG_LOAD_FAILED: "/docs/configuration",
|
|
295
|
+
BLUME_CONTENT_ROOT_MISSING: "/docs/content/sources",
|
|
296
|
+
BLUME_DEAD_LINK: "/docs/reference/cli",
|
|
297
|
+
BLUME_DUPLICATE_ROUTE: "/docs/content/navigation",
|
|
298
|
+
BLUME_FRONTMATTER_INVALID: "/docs/reference/frontmatter",
|
|
299
|
+
BLUME_META_INVALID: "/docs/content/meta",
|
|
300
|
+
BLUME_META_LOAD_FAILED: "/docs/content/meta",
|
|
301
|
+
BLUME_MISSING_SECRET: "/docs/deployment",
|
|
302
|
+
BLUME_NAV_DUPLICATE_LABEL: "/docs/content/navigation",
|
|
303
|
+
BLUME_NAV_HIDDEN_IN_SIDEBAR: "/docs/content/navigation",
|
|
304
|
+
BLUME_NAV_MISSING_PAGE: "/docs/content/navigation",
|
|
305
|
+
BLUME_NODE_VERSION: "/docs/quickstart",
|
|
306
|
+
BLUME_SERVER_FEATURE_REQUIRED: "/docs/deployment",
|
|
307
|
+
BLUME_SOURCE_FETCH_FAILED: "/docs/content/sources",
|
|
308
|
+
BLUME_SOURCE_MISCONFIGURED: "/docs/content/sources",
|
|
309
|
+
BLUME_SOURCE_OFFLINE: "/docs/content/sources",
|
|
310
|
+
BLUME_SOURCE_SDK_MISSING: "/docs/content/sources",
|
|
311
|
+
BLUME_SOURCE_UNAVAILABLE: "/docs/content/sources",
|
|
312
|
+
BLUME_UNKNOWN_COMPONENT: "/docs/configuration/customization",
|
|
313
|
+
BLUME_UNKNOWN_ICON: "/docs/content/navigation"
|
|
314
|
+
};
|
|
315
|
+
var resolveDocsUrl = (code) => {
|
|
316
|
+
const path = DOCS_PATHS[code];
|
|
317
|
+
return path ? `${DOCS_BASE}${path}` : undefined;
|
|
318
|
+
};
|
|
319
|
+
var enrichDiagnostic = (diagnostic) => diagnostic.docsUrl ? diagnostic : { ...diagnostic, docsUrl: resolveDocsUrl(diagnostic.code) };
|
|
320
|
+
var REGEXP_SPECIAL = /[$()*+.?[\\\]^{|}]/gu;
|
|
321
|
+
var escapeRegExp = (value) => value.replaceAll(REGEXP_SPECIAL, String.raw`\$&`);
|
|
322
|
+
var locatePath = (source, path) => {
|
|
323
|
+
let cursor = 0;
|
|
324
|
+
let found = -1;
|
|
325
|
+
for (const segment of path) {
|
|
326
|
+
if (typeof segment !== "string") {
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
const matcher = new RegExp(`${escapeRegExp(segment)}\\s*[:=]`, "gu");
|
|
330
|
+
matcher.lastIndex = cursor;
|
|
331
|
+
const match = matcher.exec(source);
|
|
332
|
+
if (!match) {
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
found = match.index;
|
|
336
|
+
cursor = matcher.lastIndex;
|
|
337
|
+
}
|
|
338
|
+
if (found < 0) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
const before = source.slice(0, found);
|
|
342
|
+
const lastNewline = before.lastIndexOf(`
|
|
343
|
+
`);
|
|
344
|
+
return { column: found - lastNewline, line: before.split(`
|
|
345
|
+
`).length };
|
|
346
|
+
};
|
|
138
347
|
var diagnosticsFromZod = (error, options) => error.issues.map((issue) => {
|
|
139
348
|
const schemaPath = issue.path.join(".");
|
|
140
349
|
const received = "received" in issue ? ` (received: ${JSON.stringify(issue.received)})` : "";
|
|
350
|
+
const position = options.source ? locatePath(options.source, issue.path) : undefined;
|
|
141
351
|
return {
|
|
142
352
|
code: options.code,
|
|
353
|
+
column: position?.column,
|
|
143
354
|
file: options.file,
|
|
355
|
+
line: position?.line,
|
|
144
356
|
message: schemaPath ? `${schemaPath}: ${issue.message}${received}` : `${issue.message}${received}`,
|
|
145
357
|
schemaPath: schemaPath || undefined,
|
|
146
358
|
severity: "error"
|
|
@@ -196,12 +408,21 @@ var countBySeverity = (diagnostics) => {
|
|
|
196
408
|
|
|
197
409
|
// src/cli/log.ts
|
|
198
410
|
var logger = consola.withTag("blume");
|
|
411
|
+
var reportDiagnosticsJson = (diagnostics, root) => {
|
|
412
|
+
const enriched = diagnostics.map((diagnostic) => {
|
|
413
|
+
const withDocs = enrichDiagnostic(diagnostic);
|
|
414
|
+
return withDocs.file && root ? { ...withDocs, file: relative3(root, withDocs.file) } : withDocs;
|
|
415
|
+
});
|
|
416
|
+
process.stdout.write(`${JSON.stringify({ diagnostics: enriched, summary: countBySeverity(diagnostics) }, null, 2)}
|
|
417
|
+
`);
|
|
418
|
+
return hasErrors(diagnostics);
|
|
419
|
+
};
|
|
199
420
|
var reportDiagnostics = (diagnostics, root) => {
|
|
200
421
|
if (diagnostics.length === 0) {
|
|
201
422
|
return false;
|
|
202
423
|
}
|
|
203
424
|
for (const diagnostic of diagnostics) {
|
|
204
|
-
process.stderr.write(`${formatDiagnostic(diagnostic, root)}
|
|
425
|
+
process.stderr.write(`${formatDiagnostic(enrichDiagnostic(diagnostic), root)}
|
|
205
426
|
`);
|
|
206
427
|
}
|
|
207
428
|
const counts = countBySeverity(diagnostics);
|
|
@@ -279,11 +500,11 @@ Next steps:
|
|
|
279
500
|
});
|
|
280
501
|
|
|
281
502
|
// src/cli/commands/build.ts
|
|
282
|
-
import { existsSync as
|
|
283
|
-
import { writeFile as writeFile6 } from "node:fs/promises";
|
|
503
|
+
import { existsSync as existsSync15 } from "node:fs";
|
|
504
|
+
import { readdir, stat, writeFile as writeFile6 } from "node:fs/promises";
|
|
284
505
|
import { build } from "astro";
|
|
285
506
|
import { defineCommand as defineCommand2 } from "citty";
|
|
286
|
-
import { join as
|
|
507
|
+
import { join as join24 } from "pathe";
|
|
287
508
|
|
|
288
509
|
// src/core/frontmatter.ts
|
|
289
510
|
import baseMatter from "gray-matter";
|
|
@@ -443,6 +664,25 @@ var serverFeatures = (config) => {
|
|
|
443
664
|
return features;
|
|
444
665
|
};
|
|
445
666
|
|
|
667
|
+
// src/deploy/redirects.ts
|
|
668
|
+
var buildNetlifyRedirects = (redirects) => `${redirects.map((redirect) => `${redirect.from} ${redirect.to} ${redirect.status}`).join(`
|
|
669
|
+
`)}
|
|
670
|
+
`;
|
|
671
|
+
var buildVercelConfig = (redirects) => `${JSON.stringify({
|
|
672
|
+
redirects: redirects.map((redirect) => ({
|
|
673
|
+
destination: redirect.to,
|
|
674
|
+
permanent: redirect.status === 301 || redirect.status === 308,
|
|
675
|
+
source: redirect.from
|
|
676
|
+
}))
|
|
677
|
+
}, null, 2)}
|
|
678
|
+
`;
|
|
679
|
+
var buildRedirectManifest = (redirects) => `${JSON.stringify(redirects.map((redirect) => ({
|
|
680
|
+
from: redirect.from,
|
|
681
|
+
status: redirect.status,
|
|
682
|
+
to: redirect.to
|
|
683
|
+
})), null, 2)}
|
|
684
|
+
`;
|
|
685
|
+
|
|
446
686
|
// src/deploy/robots.ts
|
|
447
687
|
var buildRobots = (project) => {
|
|
448
688
|
const { config } = project;
|
|
@@ -2514,7 +2754,7 @@ var syncSearchProvider = async (project, reporter) => {
|
|
|
2514
2754
|
};
|
|
2515
2755
|
|
|
2516
2756
|
// src/astro/generate.ts
|
|
2517
|
-
import { existsSync as
|
|
2757
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5, realpathSync } from "node:fs";
|
|
2518
2758
|
import {
|
|
2519
2759
|
lstat,
|
|
2520
2760
|
mkdir as mkdir2,
|
|
@@ -2526,9 +2766,26 @@ import {
|
|
|
2526
2766
|
} from "node:fs/promises";
|
|
2527
2767
|
import { createRequire as createRequire4 } from "node:module";
|
|
2528
2768
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
2529
|
-
import { basename as basename2, dirname as
|
|
2769
|
+
import { basename as basename2, dirname as dirname7, join as join11, normalize, relative as relative6 } from "pathe";
|
|
2530
2770
|
import { glob as glob4 } from "tinyglobby";
|
|
2531
2771
|
|
|
2772
|
+
// src/ai/ask-data.ts
|
|
2773
|
+
var buildAskData = async (project) => {
|
|
2774
|
+
const documents = await buildSearchDocuments(project, {
|
|
2775
|
+
includeWhenDisabled: true
|
|
2776
|
+
});
|
|
2777
|
+
return {
|
|
2778
|
+
documents: documents.map((doc) => ({
|
|
2779
|
+
content: doc.content,
|
|
2780
|
+
description: doc.description,
|
|
2781
|
+
locale: doc.locale,
|
|
2782
|
+
route: doc.route,
|
|
2783
|
+
title: doc.title
|
|
2784
|
+
})),
|
|
2785
|
+
site: project.config.deployment.site ?? null
|
|
2786
|
+
};
|
|
2787
|
+
};
|
|
2788
|
+
|
|
2532
2789
|
// src/ai/ask.ts
|
|
2533
2790
|
var ASK_PRESETS = {
|
|
2534
2791
|
inkeep: {
|
|
@@ -2682,6 +2939,323 @@ var buildMcpServerCard = (input) => ({
|
|
|
2682
2939
|
version: input.version
|
|
2683
2940
|
});
|
|
2684
2941
|
|
|
2942
|
+
// src/core/builtin-tags.ts
|
|
2943
|
+
var BUILTIN_MDX_TAGS = new Set([
|
|
2944
|
+
"Accordion",
|
|
2945
|
+
"AccordionItem",
|
|
2946
|
+
"AutoTypeTable",
|
|
2947
|
+
"Badge",
|
|
2948
|
+
"Callout",
|
|
2949
|
+
"Card",
|
|
2950
|
+
"CardGroup",
|
|
2951
|
+
"CodeBlock",
|
|
2952
|
+
"CodeGroup",
|
|
2953
|
+
"Color",
|
|
2954
|
+
"Column",
|
|
2955
|
+
"Columns",
|
|
2956
|
+
"Component",
|
|
2957
|
+
"Diff",
|
|
2958
|
+
"Expandable",
|
|
2959
|
+
"FileTree",
|
|
2960
|
+
"Frame",
|
|
2961
|
+
"GithubInfo",
|
|
2962
|
+
"Icon",
|
|
2963
|
+
"Math",
|
|
2964
|
+
"Panel",
|
|
2965
|
+
"Prompt",
|
|
2966
|
+
"Step",
|
|
2967
|
+
"Steps",
|
|
2968
|
+
"Tab",
|
|
2969
|
+
"Tabs",
|
|
2970
|
+
"Tile",
|
|
2971
|
+
"Tooltip",
|
|
2972
|
+
"Tree",
|
|
2973
|
+
"TypeTable",
|
|
2974
|
+
"Visibility"
|
|
2975
|
+
]);
|
|
2976
|
+
|
|
2977
|
+
// src/core/component-diagnostics.ts
|
|
2978
|
+
var toKebab = (tag) => tag.replaceAll(/(?<lower>[a-z0-9])(?<upper>[A-Z])/gu, "$<lower>-$<upper>").toLowerCase();
|
|
2979
|
+
var validateUsedComponents = (pages, extraTags, registryNames) => {
|
|
2980
|
+
const diagnostics = [];
|
|
2981
|
+
const seen = new Set;
|
|
2982
|
+
for (const page of pages) {
|
|
2983
|
+
for (const tag of page.componentsUsed ?? []) {
|
|
2984
|
+
if (BUILTIN_MDX_TAGS.has(tag) || extraTags.has(tag) || seen.has(tag)) {
|
|
2985
|
+
continue;
|
|
2986
|
+
}
|
|
2987
|
+
seen.add(tag);
|
|
2988
|
+
const name = toKebab(tag);
|
|
2989
|
+
const suggestion = registryNames.has(name) ? `Run \`blume add ${name}\` to install it, or register <${tag}> in components.ts (mdx).` : `Register <${tag}> in components.ts (mdx), or add an islands/${tag}.tsx component.`;
|
|
2990
|
+
diagnostics.push({
|
|
2991
|
+
code: "BLUME_UNKNOWN_COMPONENT",
|
|
2992
|
+
file: page.sourcePath ?? page.id,
|
|
2993
|
+
message: `<${tag}> is used in ${page.route} but isn't a known component.`,
|
|
2994
|
+
severity: "warning",
|
|
2995
|
+
suggestion
|
|
2996
|
+
});
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
return diagnostics;
|
|
3000
|
+
};
|
|
3001
|
+
|
|
3002
|
+
// src/core/component-overrides.ts
|
|
3003
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
3004
|
+
import { dirname as dirname4, extname, isAbsolute, resolve as resolve2 } from "pathe";
|
|
3005
|
+
import ts from "typescript";
|
|
3006
|
+
var GROUPS = ["mdx", "layout", "islands"];
|
|
3007
|
+
var FRAMEWORK_BY_EXT = {
|
|
3008
|
+
jsx: "react",
|
|
3009
|
+
svelte: "svelte",
|
|
3010
|
+
tsx: "react",
|
|
3011
|
+
vue: "vue"
|
|
3012
|
+
};
|
|
3013
|
+
var FRAMEWORK_LABEL = {
|
|
3014
|
+
react: "React",
|
|
3015
|
+
svelte: "Svelte",
|
|
3016
|
+
vue: "Vue"
|
|
3017
|
+
};
|
|
3018
|
+
var COMPONENT_EXTS = [
|
|
3019
|
+
"astro",
|
|
3020
|
+
"tsx",
|
|
3021
|
+
"ts",
|
|
3022
|
+
"jsx",
|
|
3023
|
+
"js",
|
|
3024
|
+
"mjs",
|
|
3025
|
+
"vue",
|
|
3026
|
+
"svelte"
|
|
3027
|
+
];
|
|
3028
|
+
var HYDRATION_MODES = new Set([
|
|
3029
|
+
"idle",
|
|
3030
|
+
"load",
|
|
3031
|
+
"media",
|
|
3032
|
+
"only",
|
|
3033
|
+
"visible"
|
|
3034
|
+
]);
|
|
3035
|
+
var emptyAnalysis = () => ({
|
|
3036
|
+
islands: [],
|
|
3037
|
+
layout: [],
|
|
3038
|
+
mdx: [],
|
|
3039
|
+
warnings: []
|
|
3040
|
+
});
|
|
3041
|
+
var propName = (name) => ts.isIdentifier(name) || ts.isStringLiteral(name) ? name.text : undefined;
|
|
3042
|
+
var collectImports = (sourceFile) => {
|
|
3043
|
+
const map = new Map;
|
|
3044
|
+
for (const statement of sourceFile.statements) {
|
|
3045
|
+
if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
3046
|
+
continue;
|
|
3047
|
+
}
|
|
3048
|
+
const specifier = statement.moduleSpecifier.text;
|
|
3049
|
+
const clause = statement.importClause;
|
|
3050
|
+
if (!clause) {
|
|
3051
|
+
continue;
|
|
3052
|
+
}
|
|
3053
|
+
if (clause.name) {
|
|
3054
|
+
map.set(clause.name.text, { imported: "default", specifier });
|
|
3055
|
+
}
|
|
3056
|
+
const named = clause.namedBindings;
|
|
3057
|
+
if (named && ts.isNamedImports(named)) {
|
|
3058
|
+
for (const element of named.elements) {
|
|
3059
|
+
map.set(element.name.text, {
|
|
3060
|
+
imported: (element.propertyName ?? element.name).text,
|
|
3061
|
+
specifier
|
|
3062
|
+
});
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
return map;
|
|
3067
|
+
};
|
|
3068
|
+
var unwrapObject = (expression) => {
|
|
3069
|
+
if (ts.isObjectLiteralExpression(expression)) {
|
|
3070
|
+
return expression;
|
|
3071
|
+
}
|
|
3072
|
+
if (ts.isCallExpression(expression)) {
|
|
3073
|
+
const [arg] = expression.arguments;
|
|
3074
|
+
return arg && ts.isObjectLiteralExpression(arg) ? arg : undefined;
|
|
3075
|
+
}
|
|
3076
|
+
if (ts.isAsExpression(expression) || ts.isParenthesizedExpression(expression)) {
|
|
3077
|
+
return unwrapObject(expression.expression);
|
|
3078
|
+
}
|
|
3079
|
+
return;
|
|
3080
|
+
};
|
|
3081
|
+
var findDefaultExportObject = (sourceFile) => {
|
|
3082
|
+
for (const statement of sourceFile.statements) {
|
|
3083
|
+
if (ts.isExportAssignment(statement) && !statement.isExportEquals) {
|
|
3084
|
+
return unwrapObject(statement.expression);
|
|
3085
|
+
}
|
|
3086
|
+
}
|
|
3087
|
+
return;
|
|
3088
|
+
};
|
|
3089
|
+
var probeExtension = (base) => {
|
|
3090
|
+
for (const extension of COMPONENT_EXTS) {
|
|
3091
|
+
const candidate = `${base}.${extension}`;
|
|
3092
|
+
if (existsSync3(candidate)) {
|
|
3093
|
+
return candidate;
|
|
3094
|
+
}
|
|
3095
|
+
}
|
|
3096
|
+
return null;
|
|
3097
|
+
};
|
|
3098
|
+
var toImport = (specifier, imported, dir) => {
|
|
3099
|
+
const relative4 = specifier.startsWith(".") || isAbsolute(specifier);
|
|
3100
|
+
let path = specifier;
|
|
3101
|
+
let extension = extname(specifier).slice(1).toLowerCase();
|
|
3102
|
+
if (relative4) {
|
|
3103
|
+
const absolute = isAbsolute(specifier) ? specifier : resolve2(dir, specifier);
|
|
3104
|
+
if (extension) {
|
|
3105
|
+
path = absolute;
|
|
3106
|
+
} else {
|
|
3107
|
+
const probed = probeExtension(absolute);
|
|
3108
|
+
path = probed ?? absolute;
|
|
3109
|
+
extension = probed ? extname(probed).slice(1).toLowerCase() : "";
|
|
3110
|
+
}
|
|
3111
|
+
}
|
|
3112
|
+
return {
|
|
3113
|
+
framework: FRAMEWORK_BY_EXT[extension] ?? null,
|
|
3114
|
+
name: imported,
|
|
3115
|
+
path
|
|
3116
|
+
};
|
|
3117
|
+
};
|
|
3118
|
+
var resolveIdentifier = (name, imports, dir) => {
|
|
3119
|
+
const binding = imports.get(name);
|
|
3120
|
+
return binding ? toImport(binding.specifier, binding.imported, dir) : null;
|
|
3121
|
+
};
|
|
3122
|
+
var readDescriptor = (object, imports, dir) => {
|
|
3123
|
+
const descriptor = { hadComponent: false, source: null };
|
|
3124
|
+
for (const property of object.properties) {
|
|
3125
|
+
if (ts.isShorthandPropertyAssignment(property)) {
|
|
3126
|
+
if (property.name.text === "component") {
|
|
3127
|
+
descriptor.hadComponent = true;
|
|
3128
|
+
descriptor.source = resolveIdentifier(property.name.text, imports, dir);
|
|
3129
|
+
}
|
|
3130
|
+
continue;
|
|
3131
|
+
}
|
|
3132
|
+
if (!ts.isPropertyAssignment(property)) {
|
|
3133
|
+
continue;
|
|
3134
|
+
}
|
|
3135
|
+
const name = propName(property.name);
|
|
3136
|
+
const init = property.initializer;
|
|
3137
|
+
if (name === "component") {
|
|
3138
|
+
descriptor.hadComponent = true;
|
|
3139
|
+
if (ts.isStringLiteral(init)) {
|
|
3140
|
+
descriptor.source = toImport(init.text, "default", dir);
|
|
3141
|
+
} else if (ts.isIdentifier(init)) {
|
|
3142
|
+
descriptor.source = resolveIdentifier(init.text, imports, dir);
|
|
3143
|
+
}
|
|
3144
|
+
} else if (name === "client" && ts.isStringLiteral(init) && HYDRATION_MODES.has(init.text)) {
|
|
3145
|
+
descriptor.client = init.text;
|
|
3146
|
+
} else if (name === "media" && ts.isStringLiteral(init)) {
|
|
3147
|
+
descriptor.media = init.text;
|
|
3148
|
+
}
|
|
3149
|
+
}
|
|
3150
|
+
return descriptor;
|
|
3151
|
+
};
|
|
3152
|
+
var finalize = (key, group, descriptor, label, identifier, warnings) => {
|
|
3153
|
+
const { client, media, source } = descriptor;
|
|
3154
|
+
if (group === "islands") {
|
|
3155
|
+
if (!source) {
|
|
3156
|
+
warnings.push(`Island override "${key}" couldn't be resolved to a file. Reference it by an imported component or a path string with an extension.`);
|
|
3157
|
+
return null;
|
|
3158
|
+
}
|
|
3159
|
+
if (!source.framework) {
|
|
3160
|
+
warnings.push(`Island override "${key}" (${label}) is not a React, Vue, or Svelte component; only framework components can be islands.`);
|
|
3161
|
+
return null;
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
if (client === "media" && !media) {
|
|
3165
|
+
warnings.push(`Override "${key}" uses client: "media" but no \`media\` query was given; it will hydrate as if \`client: "load"\`.`);
|
|
3166
|
+
}
|
|
3167
|
+
if (client === "only" && source && !source.framework) {
|
|
3168
|
+
warnings.push(`Override "${key}" uses client: "only" but its framework couldn't be inferred; reference a .tsx/.jsx/.vue/.svelte file.`);
|
|
3169
|
+
}
|
|
3170
|
+
if (client && !source) {
|
|
3171
|
+
warnings.push(`Override "${key}" declares client: "${client}" but its component couldn't be resolved to a file, so it can't hydrate. Reference it by an imported component or a path string.`);
|
|
3172
|
+
return { identifier, key, source: null };
|
|
3173
|
+
}
|
|
3174
|
+
if (!client && source?.framework) {
|
|
3175
|
+
warnings.push(`Override "${key}" points to a ${FRAMEWORK_LABEL[source.framework]} component (${label}) but has no hydration mode, so it renders as static HTML with no interactivity. Add one, e.g. \`${key}: { component: ${JSON.stringify(label)}, client: "load" }\`.`);
|
|
3176
|
+
}
|
|
3177
|
+
return {
|
|
3178
|
+
identifier,
|
|
3179
|
+
key,
|
|
3180
|
+
...client ? { client } : {},
|
|
3181
|
+
...media ? { media } : {},
|
|
3182
|
+
source
|
|
3183
|
+
};
|
|
3184
|
+
};
|
|
3185
|
+
var normalizeEntry = (entry, group, imports, dir, warnings) => {
|
|
3186
|
+
const defaultClient = group === "islands" ? "visible" : undefined;
|
|
3187
|
+
if (ts.isShorthandPropertyAssignment(entry)) {
|
|
3188
|
+
const name = entry.name.text;
|
|
3189
|
+
return finalize(name, group, {
|
|
3190
|
+
client: defaultClient,
|
|
3191
|
+
hadComponent: true,
|
|
3192
|
+
source: resolveIdentifier(name, imports, dir)
|
|
3193
|
+
}, name, true, warnings);
|
|
3194
|
+
}
|
|
3195
|
+
if (!ts.isPropertyAssignment(entry)) {
|
|
3196
|
+
return null;
|
|
3197
|
+
}
|
|
3198
|
+
const key = propName(entry.name);
|
|
3199
|
+
if (!key) {
|
|
3200
|
+
return null;
|
|
3201
|
+
}
|
|
3202
|
+
const value = entry.initializer;
|
|
3203
|
+
if (ts.isIdentifier(value)) {
|
|
3204
|
+
return finalize(key, group, {
|
|
3205
|
+
client: defaultClient,
|
|
3206
|
+
hadComponent: true,
|
|
3207
|
+
source: resolveIdentifier(value.text, imports, dir)
|
|
3208
|
+
}, value.text, true, warnings);
|
|
3209
|
+
}
|
|
3210
|
+
if (ts.isStringLiteral(value)) {
|
|
3211
|
+
return finalize(key, group, {
|
|
3212
|
+
client: defaultClient,
|
|
3213
|
+
hadComponent: true,
|
|
3214
|
+
source: toImport(value.text, "default", dir)
|
|
3215
|
+
}, value.text, false, warnings);
|
|
3216
|
+
}
|
|
3217
|
+
if (ts.isObjectLiteralExpression(value)) {
|
|
3218
|
+
const descriptor = readDescriptor(value, imports, dir);
|
|
3219
|
+
if (!descriptor.hadComponent) {
|
|
3220
|
+
warnings.push(`Override "${key}" is an object without a \`component\` field; expected \`{ component, client }\`.`);
|
|
3221
|
+
return null;
|
|
3222
|
+
}
|
|
3223
|
+
if (!descriptor.source) {
|
|
3224
|
+
warnings.push(`Override "${key}"'s \`component\` couldn't be resolved to a file. Reference an imported component or a path string with an extension.`);
|
|
3225
|
+
return null;
|
|
3226
|
+
}
|
|
3227
|
+
return finalize(key, group, { ...descriptor, client: descriptor.client ?? defaultClient }, key, false, warnings);
|
|
3228
|
+
}
|
|
3229
|
+
return { identifier: false, key, source: null };
|
|
3230
|
+
};
|
|
3231
|
+
var analyzeComponentOverrides = (source, filePath) => {
|
|
3232
|
+
const result = emptyAnalysis();
|
|
3233
|
+
const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, filePath.endsWith("tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
|
|
3234
|
+
const object = findDefaultExportObject(sourceFile);
|
|
3235
|
+
if (!object) {
|
|
3236
|
+
return result;
|
|
3237
|
+
}
|
|
3238
|
+
const imports = collectImports(sourceFile);
|
|
3239
|
+
const dir = dirname4(filePath);
|
|
3240
|
+
for (const property of object.properties) {
|
|
3241
|
+
if (!ts.isPropertyAssignment(property)) {
|
|
3242
|
+
continue;
|
|
3243
|
+
}
|
|
3244
|
+
const name = propName(property.name);
|
|
3245
|
+
if (!(name && GROUPS.includes(name)) || !ts.isObjectLiteralExpression(property.initializer)) {
|
|
3246
|
+
continue;
|
|
3247
|
+
}
|
|
3248
|
+
const group = name;
|
|
3249
|
+
for (const entry of property.initializer.properties) {
|
|
3250
|
+
const normalized = normalizeEntry(entry, group, imports, dir, result.warnings);
|
|
3251
|
+
if (normalized) {
|
|
3252
|
+
result[group].push(normalized);
|
|
3253
|
+
}
|
|
3254
|
+
}
|
|
3255
|
+
}
|
|
3256
|
+
return result;
|
|
3257
|
+
};
|
|
3258
|
+
|
|
2685
3259
|
// src/core/i18n-ui.ts
|
|
2686
3260
|
import { z } from "zod";
|
|
2687
3261
|
var uiStringsObject = z.object({
|
|
@@ -2773,11 +3347,284 @@ var resolveUIStrings = (locale, options) => {
|
|
|
2773
3347
|
return dict;
|
|
2774
3348
|
};
|
|
2775
3349
|
|
|
3350
|
+
// src/theme/icons.ts
|
|
3351
|
+
var icons = {
|
|
3352
|
+
"arrow-left": '<path d="m12 19-7-7 7-7"/><path d="M19 12H5"/>',
|
|
3353
|
+
"arrow-right": '<path d="M5 12h14"/><path d="m12 5 7 7-7 7"/>',
|
|
3354
|
+
"arrow-up": '<path d="m5 12 7-7 7 7"/><path d="M12 19V5"/>',
|
|
3355
|
+
"arrow-up-right": '<path d="M7 7h10v10"/><path d="M7 17 17 7"/>',
|
|
3356
|
+
"badge-alert": '<path d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.78 4.78 4 4 0 0 1-6.74 0 4 4 0 0 1-4.78-4.78 4 4 0 0 1 0-6.75Z"/><path d="M12 8v4"/><path d="M12 16h.01"/>',
|
|
3357
|
+
ban: '<circle cx="12" cy="12" r="10"/><path d="m4.93 4.93 14.14 14.14"/>',
|
|
3358
|
+
"book-open": '<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>',
|
|
3359
|
+
"book-open-cover": '<path d="M12 7v14"/><path d="M3 18a2 2 0 0 1 2-2h7V5H5a2 2 0 0 0-2 2Z"/><path d="M21 18a2 2 0 0 0-2-2h-7V5h7a2 2 0 0 1 2 2Z"/>',
|
|
3360
|
+
"brand-x": '<path d="m4 4 11.7 16H20L8.3 4Z"/><path d="M4 20 20 4"/>',
|
|
3361
|
+
check: '<path d="M20 6 9 17l-5-5"/>',
|
|
3362
|
+
"chevron-down": '<path d="m6 9 6 6 6-6"/>',
|
|
3363
|
+
"chevron-right": '<path d="m9 18 6-6-6-6"/>',
|
|
3364
|
+
"circle-check": '<circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/>',
|
|
3365
|
+
"circle-x": '<circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/>',
|
|
3366
|
+
clock: '<circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/>',
|
|
3367
|
+
copy: '<rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>',
|
|
3368
|
+
download: '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10 5 5 5-5"/><path d="M12 15V3"/>',
|
|
3369
|
+
"external-link": '<path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>',
|
|
3370
|
+
file: '<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/>',
|
|
3371
|
+
flag: '<path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><path d="M4 22V15"/>',
|
|
3372
|
+
folder: '<path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"/>',
|
|
3373
|
+
gear: '<path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915"/><circle cx="12" cy="12" r="3"/>',
|
|
3374
|
+
github: '<path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.4 5.4 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.3-.8 2.1-.36.16-.78.24-1.2.24-1.4 0-2.4-.7-3-2-.3-.6-.8-.9-1.2-.9-.4 0-.8.2-.8.5 0 .5.7.8 1 1.2.7 1.5 2 2.4 4 2.4.43 0 .84-.04 1.2-.13V22"/>',
|
|
3375
|
+
globe: '<circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/>',
|
|
3376
|
+
info: '<circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/>',
|
|
3377
|
+
js: '<path d="M8 8v7a2 2 0 1 1-4 0"/><path d="M16 15a2 2 0 1 0 2-2 2 2 0 1 1 2-2"/><path d="M20 8v.01"/>',
|
|
3378
|
+
key: '<path d="M21 2 11.4 11.6"/><circle cx="7.5" cy="16.5" r="5.5"/><path d="m15 7 2 2"/><path d="m12 10 2 2"/>',
|
|
3379
|
+
leaf: '<path d="M11 20A7 7 0 0 1 9.8 6.1C15.5 5 17 4.48 19 2c1 2 2 4.18 2 8 0 5.5-4.78 10-10 10Z"/><path d="M2 21c0-3 1.85-5.36 5.08-6C9.5 14.52 12 13 13 12"/>',
|
|
3380
|
+
lightbulb: '<path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"/><path d="M9 18h6"/><path d="M10 22h4"/>',
|
|
3381
|
+
link: '<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>',
|
|
3382
|
+
linkedin: '<path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-4 0v7h-4v-7a6 6 0 0 1 6-6z"/><rect width="4" height="12" x="2" y="9"/><circle cx="4" cy="4" r="2"/>',
|
|
3383
|
+
lock: '<rect width="18" height="11" x="3" y="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>',
|
|
3384
|
+
menu: '<line x1="4" x2="20" y1="12" y2="12"/><line x1="4" x2="20" y1="6" y2="6"/><line x1="4" x2="20" y1="18" y2="18"/>',
|
|
3385
|
+
"message-circle": '<path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z"/>',
|
|
3386
|
+
moon: '<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/>',
|
|
3387
|
+
"panel-left": '<rect width="18" height="18" x="3" y="3" rx="2"/><path d="M9 3v18"/>',
|
|
3388
|
+
"panel-left-close": '<rect width="18" height="18" x="3" y="3" rx="2"/><path d="M9 3v18"/><path d="m16 15-3-3 3-3"/>',
|
|
3389
|
+
"panel-right": '<rect width="18" height="18" x="3" y="3" rx="2"/><path d="M15 3v18"/>',
|
|
3390
|
+
"panel-right-close": '<rect width="18" height="18" x="3" y="3" rx="2"/><path d="M15 3v18"/><path d="m8 9 3 3-3 3"/>',
|
|
3391
|
+
paperclip: '<path d="m16 6-8.41 8.41a2 2 0 0 0 2.83 2.83L18.83 8.83a4 4 0 0 0-5.66-5.66L4.76 11.59a6 6 0 0 0 8.49 8.49L21.66 11.66"/>',
|
|
3392
|
+
"puzzle-piece": '<path d="M15.39 4.39a2.1 2.1 0 0 0-2.97 0L12 4.82l-.42-.43a2.1 2.1 0 1 0-2.97 2.97l.43.42L7.6 9.22H4.75A1.75 1.75 0 0 0 3 10.97v8.28C3 20.22 3.78 21 4.75 21h8.28c.97 0 1.75-.78 1.75-1.75V16.4l1.44-1.44.42.43a2.1 2.1 0 1 0 2.97-2.97l-.43-.42.43-.42a2.1 2.1 0 1 0-2.97-2.97l-.42.43-1.44-1.44.61-.61a2.1 2.1 0 0 0 0-2.97Z"/>',
|
|
3393
|
+
python: '<path d="M12 2h4a4 4 0 0 1 4 4v3H8a4 4 0 0 0-4 4v1"/><path d="M12 22H8a4 4 0 0 1-4-4v-3h12a4 4 0 0 0 4-4v-1"/><path d="M9 6h.01"/><path d="M15 18h.01"/>',
|
|
3394
|
+
rocket: '<path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"/><path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"/><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0"/><path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/>',
|
|
3395
|
+
rss: '<path d="M4 11a9 9 0 0 1 9 9"/><path d="M4 4a16 16 0 0 1 16 16"/><circle cx="5" cy="19" r="1"/>',
|
|
3396
|
+
search: '<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>',
|
|
3397
|
+
sparkles: '<path d="m12 3-1.9 5.8a2 2 0 0 1-1.3 1.3L3 12l5.8 1.9a2 2 0 0 1 1.3 1.3L12 21l1.9-5.8a2 2 0 0 1 1.3-1.3L21 12l-5.8-1.9a2 2 0 0 1-1.3-1.3Z"/><path d="M5 3v4"/><path d="M3 5h4"/><path d="M19 17v4"/><path d="M17 19h4"/>',
|
|
3398
|
+
star: '<path d="m12 2 3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01Z"/>',
|
|
3399
|
+
sun: '<circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/>',
|
|
3400
|
+
"text-align-start": '<path d="M4 6h16"/><path d="M4 10h10"/><path d="M4 14h16"/><path d="M4 18h10"/>',
|
|
3401
|
+
"thumbs-down": '<path d="M17 14V2"/><path d="M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z"/>',
|
|
3402
|
+
"thumbs-up": '<path d="M7 10v12"/><path d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z"/>',
|
|
3403
|
+
"triangle-alert": '<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/>',
|
|
3404
|
+
x: '<path d="M18 6 6 18"/><path d="m6 6 12 12"/>'
|
|
3405
|
+
};
|
|
3406
|
+
var iconAliases = {
|
|
3407
|
+
"alien-8bit": "sparkles",
|
|
3408
|
+
"arrow-up-right-from-square": "external-link",
|
|
3409
|
+
"book-open-reader": "book-open",
|
|
3410
|
+
"circle-info": "info",
|
|
3411
|
+
close: "x",
|
|
3412
|
+
"external-link-alt": "external-link",
|
|
3413
|
+
"fa-github": "github",
|
|
3414
|
+
"fa-linkedin": "linkedin",
|
|
3415
|
+
"fa-x-twitter": "brand-x",
|
|
3416
|
+
"file-lines": "file",
|
|
3417
|
+
javascript: "js",
|
|
3418
|
+
"panel-left-open": "panel-left",
|
|
3419
|
+
"panel-right-open": "panel-right",
|
|
3420
|
+
times: "x",
|
|
3421
|
+
"x-twitter": "brand-x"
|
|
3422
|
+
};
|
|
3423
|
+
var libraryPrefixes = [
|
|
3424
|
+
"fa-brands",
|
|
3425
|
+
"fa-duotone",
|
|
3426
|
+
"fa-light",
|
|
3427
|
+
"fa-regular",
|
|
3428
|
+
"fa-sharp-solid",
|
|
3429
|
+
"fa-solid",
|
|
3430
|
+
"fa-thin",
|
|
3431
|
+
"fa",
|
|
3432
|
+
"fab",
|
|
3433
|
+
"fad",
|
|
3434
|
+
"fal",
|
|
3435
|
+
"far",
|
|
3436
|
+
"fas",
|
|
3437
|
+
"fat",
|
|
3438
|
+
"lucide",
|
|
3439
|
+
"tabler",
|
|
3440
|
+
"ti"
|
|
3441
|
+
];
|
|
3442
|
+
var normalizedIconName = (name) => name.trim().toLowerCase().replaceAll(/[\s_]+/gu, "-");
|
|
3443
|
+
var isString = (value) => typeof value === "string";
|
|
3444
|
+
var withoutLibraryPrefix = (name) => {
|
|
3445
|
+
let normalized = normalizedIconName(name).replaceAll(/^icon-/gu, "");
|
|
3446
|
+
let changed = true;
|
|
3447
|
+
while (changed) {
|
|
3448
|
+
changed = false;
|
|
3449
|
+
for (const prefix of libraryPrefixes) {
|
|
3450
|
+
if (normalized.startsWith(`${prefix}-`)) {
|
|
3451
|
+
normalized = normalized.slice(prefix.length + 1);
|
|
3452
|
+
changed = true;
|
|
3453
|
+
}
|
|
3454
|
+
if (normalized.startsWith(`${prefix}:`)) {
|
|
3455
|
+
normalized = normalized.slice(prefix.length + 1);
|
|
3456
|
+
changed = true;
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
return normalized;
|
|
3461
|
+
};
|
|
3462
|
+
var resolveIcon = (name, iconType) => {
|
|
3463
|
+
const normalized = normalizedIconName(name);
|
|
3464
|
+
const stripped = withoutLibraryPrefix(name);
|
|
3465
|
+
const type = iconType ? normalizedIconName(iconType) : null;
|
|
3466
|
+
const candidates = [
|
|
3467
|
+
normalized,
|
|
3468
|
+
stripped,
|
|
3469
|
+
type ? `${type}-${stripped}` : null,
|
|
3470
|
+
iconAliases[normalized],
|
|
3471
|
+
iconAliases[stripped]
|
|
3472
|
+
].filter(isString);
|
|
3473
|
+
for (const candidate of candidates) {
|
|
3474
|
+
const markup = icons[candidate];
|
|
3475
|
+
if (markup) {
|
|
3476
|
+
return { markup, name: candidate };
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3479
|
+
return null;
|
|
3480
|
+
};
|
|
3481
|
+
var hasIcon = (name, iconType) => resolveIcon(name, iconType) !== null;
|
|
3482
|
+
|
|
3483
|
+
// src/core/nav-diagnostics.ts
|
|
3484
|
+
var IMAGE_ICON = /^(?:https?:\/\/|data:image\/|\/|\.{1,2}\/)|\.(?:avif|gif|jpe?g|png|svg|webp)$/iu;
|
|
3485
|
+
var isAssetIcon = (value) => value.startsWith("<") || IMAGE_ICON.test(value);
|
|
3486
|
+
var flattenNodes = (nodes) => nodes.flatMap((node) => node.kind === "group" ? [node, ...flattenNodes(node.children)] : [node]);
|
|
3487
|
+
var collectIcons = (navigation) => {
|
|
3488
|
+
const icons2 = [];
|
|
3489
|
+
const push = (icon, where) => {
|
|
3490
|
+
if (icon) {
|
|
3491
|
+
icons2.push({ icon, where });
|
|
3492
|
+
}
|
|
3493
|
+
};
|
|
3494
|
+
for (const tab of navigation.tabs) {
|
|
3495
|
+
push(tab.icon, `tab "${tab.label}"`);
|
|
3496
|
+
for (const item of tab.items ?? []) {
|
|
3497
|
+
push(item.icon, `tab item "${item.label}"`);
|
|
3498
|
+
}
|
|
3499
|
+
}
|
|
3500
|
+
for (const selector of navigation.selectors) {
|
|
3501
|
+
for (const item of selector.items) {
|
|
3502
|
+
push(item.icon, `selector "${item.label}"`);
|
|
3503
|
+
}
|
|
3504
|
+
}
|
|
3505
|
+
const sidebars = [
|
|
3506
|
+
navigation.sidebar,
|
|
3507
|
+
...navigation.sidebarVariants.map((variant) => variant.sidebar)
|
|
3508
|
+
];
|
|
3509
|
+
for (const sidebar of sidebars) {
|
|
3510
|
+
for (const node of flattenNodes(sidebar)) {
|
|
3511
|
+
push(node.icon, `"${node.label}"`);
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
return icons2;
|
|
3515
|
+
};
|
|
3516
|
+
var validateNavIcons = (navigation) => {
|
|
3517
|
+
const seen = new Set;
|
|
3518
|
+
const diagnostics = [];
|
|
3519
|
+
for (const { icon, where } of collectIcons(navigation)) {
|
|
3520
|
+
if (isAssetIcon(icon) || hasIcon(icon) || seen.has(icon)) {
|
|
3521
|
+
continue;
|
|
3522
|
+
}
|
|
3523
|
+
seen.add(icon);
|
|
3524
|
+
diagnostics.push({
|
|
3525
|
+
code: "BLUME_UNKNOWN_ICON",
|
|
3526
|
+
message: `Unknown icon "${icon}" (${where}) — it isn't in Blume's icon set.`,
|
|
3527
|
+
severity: "warning",
|
|
3528
|
+
suggestion: "Use a built-in icon name, an image path/URL, or inline SVG markup."
|
|
3529
|
+
});
|
|
3530
|
+
}
|
|
3531
|
+
return diagnostics;
|
|
3532
|
+
};
|
|
3533
|
+
var resolvesToPages = (routes, path) => routes.has(path) || [...routes].some((route) => route.startsWith(`${path}/`));
|
|
3534
|
+
var validateNavTargets = (navigation, routes) => {
|
|
3535
|
+
const targets = [
|
|
3536
|
+
...navigation.tabs.map((tab) => ({ label: tab.label, path: tab.path })),
|
|
3537
|
+
...navigation.selectors.flatMap((selector) => selector.items.map((item) => ({ label: item.label, path: item.path })))
|
|
3538
|
+
];
|
|
3539
|
+
const diagnostics = [];
|
|
3540
|
+
const seen = new Set;
|
|
3541
|
+
for (const { label, path } of targets) {
|
|
3542
|
+
if (!path.startsWith("/") || path.startsWith("/#") || seen.has(path)) {
|
|
3543
|
+
continue;
|
|
3544
|
+
}
|
|
3545
|
+
if (!resolvesToPages(routes, path.split("#")[0] ?? path)) {
|
|
3546
|
+
seen.add(path);
|
|
3547
|
+
diagnostics.push({
|
|
3548
|
+
code: "BLUME_NAV_MISSING_PAGE",
|
|
3549
|
+
message: `Navigation entry "${label}" points to ${path}, but no page matches it.`,
|
|
3550
|
+
severity: "warning",
|
|
3551
|
+
suggestion: "Fix the path, or add a page at that route."
|
|
3552
|
+
});
|
|
3553
|
+
}
|
|
3554
|
+
}
|
|
3555
|
+
return diagnostics;
|
|
3556
|
+
};
|
|
3557
|
+
var duplicateLabelDiagnostics = (navigation) => {
|
|
3558
|
+
const diagnostics = [];
|
|
3559
|
+
const checkLevel = (nodes, where) => {
|
|
3560
|
+
const counts = new Map;
|
|
3561
|
+
for (const node of nodes) {
|
|
3562
|
+
counts.set(node.label, (counts.get(node.label) ?? 0) + 1);
|
|
3563
|
+
}
|
|
3564
|
+
for (const [label, count] of counts) {
|
|
3565
|
+
if (count > 1) {
|
|
3566
|
+
diagnostics.push({
|
|
3567
|
+
code: "BLUME_NAV_DUPLICATE_LABEL",
|
|
3568
|
+
message: `Duplicate sidebar label "${label}" appears ${count} times ${where}.`,
|
|
3569
|
+
severity: "warning",
|
|
3570
|
+
suggestion: "Give the entries distinct titles."
|
|
3571
|
+
});
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3574
|
+
for (const node of nodes) {
|
|
3575
|
+
if (node.kind === "group") {
|
|
3576
|
+
checkLevel(node.children, `under "${node.label}"`);
|
|
3577
|
+
}
|
|
3578
|
+
}
|
|
3579
|
+
};
|
|
3580
|
+
const sidebars = [
|
|
3581
|
+
{ nodes: navigation.sidebar, where: "at the top level" },
|
|
3582
|
+
...navigation.sidebarVariants.map((variant) => ({
|
|
3583
|
+
nodes: variant.sidebar,
|
|
3584
|
+
where: `in the "${variant.path}" section`
|
|
3585
|
+
}))
|
|
3586
|
+
];
|
|
3587
|
+
for (const { nodes, where } of sidebars) {
|
|
3588
|
+
checkLevel(nodes, where);
|
|
3589
|
+
}
|
|
3590
|
+
return diagnostics;
|
|
3591
|
+
};
|
|
3592
|
+
var hiddenInSidebarDiagnostics = (navigation, pages) => {
|
|
3593
|
+
const hidden = new Set(pages.filter((page) => page.meta.sidebar.hidden).map((page) => page.id));
|
|
3594
|
+
if (hidden.size === 0) {
|
|
3595
|
+
return [];
|
|
3596
|
+
}
|
|
3597
|
+
const sidebars = [
|
|
3598
|
+
navigation.sidebar,
|
|
3599
|
+
...navigation.sidebarVariants.map((variant) => variant.sidebar)
|
|
3600
|
+
];
|
|
3601
|
+
const diagnostics = [];
|
|
3602
|
+
const seen = new Set;
|
|
3603
|
+
for (const sidebar of sidebars) {
|
|
3604
|
+
for (const node of flattenNodes(sidebar)) {
|
|
3605
|
+
if (node.kind === "page" && hidden.has(node.pageId) && !seen.has(node.pageId)) {
|
|
3606
|
+
seen.add(node.pageId);
|
|
3607
|
+
diagnostics.push({
|
|
3608
|
+
code: "BLUME_NAV_HIDDEN_IN_SIDEBAR",
|
|
3609
|
+
message: `Page "${node.label}" is marked hidden but appears in the sidebar (and its pagination).`,
|
|
3610
|
+
severity: "warning",
|
|
3611
|
+
suggestion: "Remove it from the navigation config, or unset sidebar.hidden."
|
|
3612
|
+
});
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3615
|
+
}
|
|
3616
|
+
return diagnostics;
|
|
3617
|
+
};
|
|
3618
|
+
var validateNavStructure = (navigation, pages) => [
|
|
3619
|
+
...duplicateLabelDiagnostics(navigation),
|
|
3620
|
+
...hiddenInSidebarDiagnostics(navigation, pages)
|
|
3621
|
+
];
|
|
3622
|
+
|
|
2776
3623
|
// src/core/tsconfig-aliases.ts
|
|
2777
|
-
import { existsSync as
|
|
3624
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, statSync } from "node:fs";
|
|
2778
3625
|
import { createRequire as createRequire2 } from "node:module";
|
|
2779
3626
|
import { pathToFileURL } from "node:url";
|
|
2780
|
-
import { dirname as
|
|
3627
|
+
import { dirname as dirname5, isAbsolute as isAbsolute2, join as join6, resolve as resolve3 } from "pathe";
|
|
2781
3628
|
var stripJsonComments = (text) => {
|
|
2782
3629
|
let out = "";
|
|
2783
3630
|
let inString = false;
|
|
@@ -2831,11 +3678,11 @@ var isFile = (path) => {
|
|
|
2831
3678
|
}
|
|
2832
3679
|
};
|
|
2833
3680
|
var resolveExtends = (spec, fromDir) => {
|
|
2834
|
-
if (spec.startsWith(".") ||
|
|
2835
|
-
const candidates = spec.endsWith(".json") ? [
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
3681
|
+
if (spec.startsWith(".") || isAbsolute2(spec)) {
|
|
3682
|
+
const candidates = spec.endsWith(".json") ? [resolve3(fromDir, spec)] : [
|
|
3683
|
+
resolve3(fromDir, `${spec}.json`),
|
|
3684
|
+
resolve3(fromDir, spec, "tsconfig.json"),
|
|
3685
|
+
resolve3(fromDir, spec)
|
|
2839
3686
|
];
|
|
2840
3687
|
return candidates.find(isFile) ?? null;
|
|
2841
3688
|
}
|
|
@@ -2850,7 +3697,7 @@ var resolveExtends = (spec, fromDir) => {
|
|
|
2850
3697
|
return null;
|
|
2851
3698
|
};
|
|
2852
3699
|
var loadPaths = (file, seen) => {
|
|
2853
|
-
if (seen.has(file) || !
|
|
3700
|
+
if (seen.has(file) || !existsSync4(file)) {
|
|
2854
3701
|
return null;
|
|
2855
3702
|
}
|
|
2856
3703
|
seen.add(file);
|
|
@@ -2862,7 +3709,7 @@ var loadPaths = (file, seen) => {
|
|
|
2862
3709
|
if (options.paths && typeof options.paths === "object") {
|
|
2863
3710
|
const baseUrl = typeof options.baseUrl === "string" ? options.baseUrl : ".";
|
|
2864
3711
|
return {
|
|
2865
|
-
baseDir:
|
|
3712
|
+
baseDir: resolve3(dirname5(file), baseUrl),
|
|
2866
3713
|
paths: options.paths
|
|
2867
3714
|
};
|
|
2868
3715
|
}
|
|
@@ -2871,7 +3718,7 @@ var loadPaths = (file, seen) => {
|
|
|
2871
3718
|
if (typeof base !== "string") {
|
|
2872
3719
|
continue;
|
|
2873
3720
|
}
|
|
2874
|
-
const resolved = resolveExtends(base,
|
|
3721
|
+
const resolved = resolveExtends(base, dirname5(file));
|
|
2875
3722
|
const found = resolved ? loadPaths(resolved, seen) : null;
|
|
2876
3723
|
if (found) {
|
|
2877
3724
|
return found;
|
|
@@ -2889,10 +3736,10 @@ var toAlias = (key, value, baseDir) => {
|
|
|
2889
3736
|
if (find === "" || find === "*") {
|
|
2890
3737
|
return null;
|
|
2891
3738
|
}
|
|
2892
|
-
return { find, replacement:
|
|
3739
|
+
return { find, replacement: resolve3(baseDir, target) };
|
|
2893
3740
|
};
|
|
2894
3741
|
var resolveTsconfigAliases = (root) => {
|
|
2895
|
-
const entry = ["tsconfig.json", "jsconfig.json"].map((name) => join6(root, name)).find((file) =>
|
|
3742
|
+
const entry = ["tsconfig.json", "jsconfig.json"].map((name) => join6(root, name)).find((file) => existsSync4(file));
|
|
2896
3743
|
if (!entry) {
|
|
2897
3744
|
return {};
|
|
2898
3745
|
}
|
|
@@ -2991,11 +3838,11 @@ ${items}
|
|
|
2991
3838
|
|
|
2992
3839
|
// src/openapi/scalar.ts
|
|
2993
3840
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
2994
|
-
import { isAbsolute as
|
|
3841
|
+
import { isAbsolute as isAbsolute3, join as join8 } from "pathe";
|
|
2995
3842
|
|
|
2996
3843
|
// src/astro/templates.ts
|
|
2997
|
-
import { existsSync as
|
|
2998
|
-
import { dirname as
|
|
3844
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
|
|
3845
|
+
import { dirname as dirname6, join as join7 } from "pathe";
|
|
2999
3846
|
|
|
3000
3847
|
// src/theme/fonts.ts
|
|
3001
3848
|
var FALLBACKS = {
|
|
@@ -3153,7 +4000,7 @@ var WORKSPACE_MARKERS = [
|
|
|
3153
4000
|
"yarn.lock"
|
|
3154
4001
|
];
|
|
3155
4002
|
var hasWorkspacesField = (pkgPath) => {
|
|
3156
|
-
if (!
|
|
4003
|
+
if (!existsSync5(pkgPath)) {
|
|
3157
4004
|
return false;
|
|
3158
4005
|
}
|
|
3159
4006
|
try {
|
|
@@ -3163,14 +4010,14 @@ var hasWorkspacesField = (pkgPath) => {
|
|
|
3163
4010
|
return false;
|
|
3164
4011
|
}
|
|
3165
4012
|
};
|
|
3166
|
-
var hasWorkspaceMarker = (dir) => hasWorkspacesField(join7(dir, "package.json")) || WORKSPACE_MARKERS.some((marker) =>
|
|
4013
|
+
var hasWorkspaceMarker = (dir) => hasWorkspacesField(join7(dir, "package.json")) || WORKSPACE_MARKERS.some((marker) => existsSync5(join7(dir, marker)));
|
|
3167
4014
|
var findWorkspaceRoot = (start) => {
|
|
3168
4015
|
let dir = start;
|
|
3169
4016
|
for (;; ) {
|
|
3170
4017
|
if (hasWorkspaceMarker(dir)) {
|
|
3171
4018
|
return dir;
|
|
3172
4019
|
}
|
|
3173
|
-
const parent =
|
|
4020
|
+
const parent = dirname6(dir);
|
|
3174
4021
|
if (parent === dir) {
|
|
3175
4022
|
return start;
|
|
3176
4023
|
}
|
|
@@ -3385,7 +4232,7 @@ ${stagedBlock}
|
|
|
3385
4232
|
export const collections = { docs${options.staged ? ", staged" : ""} };
|
|
3386
4233
|
`;
|
|
3387
4234
|
};
|
|
3388
|
-
var askEndpointTemplate = (backend) => {
|
|
4235
|
+
var askEndpointTemplate = (backend, grounded) => {
|
|
3389
4236
|
const imports = [
|
|
3390
4237
|
'import type { APIRoute } from "astro";',
|
|
3391
4238
|
'import { streamText } from "ai";'
|
|
@@ -3409,13 +4256,24 @@ const provider = createOpenAICompatible({
|
|
|
3409
4256
|
`;
|
|
3410
4257
|
modelExpr = `provider(${JSON.stringify(backend.model)})`;
|
|
3411
4258
|
}
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
`
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
export const POST: APIRoute = async ({ request }) => {
|
|
4259
|
+
if (grounded) {
|
|
4260
|
+
imports.push('import { createAskContext } from "blume/ai/ask-context.ts";', 'import askData from "../generated/ask-data.json";');
|
|
4261
|
+
setup += `
|
|
4262
|
+
const ground = createAskContext(askData);
|
|
4263
|
+
`;
|
|
4264
|
+
}
|
|
4265
|
+
const handler = grounded ? `export const POST: APIRoute = async ({ request }) => {
|
|
4266
|
+
const { messages, page } = await request.json();
|
|
4267
|
+
const system =
|
|
4268
|
+
(await ground(messages, page)) ??
|
|
4269
|
+
"You are a helpful documentation assistant. Answer using the project's documentation.";
|
|
4270
|
+
const result = streamText({
|
|
4271
|
+
model: ${modelExpr},
|
|
4272
|
+
system,
|
|
4273
|
+
messages,
|
|
4274
|
+
});
|
|
4275
|
+
return result.toTextStreamResponse();
|
|
4276
|
+
};` : `export const POST: APIRoute = async ({ request }) => {
|
|
3419
4277
|
const { messages } = await request.json();
|
|
3420
4278
|
const result = streamText({
|
|
3421
4279
|
model: ${modelExpr},
|
|
@@ -3424,7 +4282,14 @@ export const POST: APIRoute = async ({ request }) => {
|
|
|
3424
4282
|
messages,
|
|
3425
4283
|
});
|
|
3426
4284
|
return result.toTextStreamResponse();
|
|
3427
|
-
}
|
|
4285
|
+
};`;
|
|
4286
|
+
return `// Generated by Blume. Do not edit.
|
|
4287
|
+
${imports.join(`
|
|
4288
|
+
`)}
|
|
4289
|
+
|
|
4290
|
+
export const prerender = false;
|
|
4291
|
+
${setup}
|
|
4292
|
+
${handler}
|
|
3428
4293
|
`;
|
|
3429
4294
|
};
|
|
3430
4295
|
var searchEndpointTemplate = () => `// Generated by Blume. Do not edit.
|
|
@@ -3611,31 +4476,47 @@ const customRoutes = ${JSON.stringify(customRoutes)};
|
|
|
3611
4476
|
export function getStaticPaths() {
|
|
3612
4477
|
const seen = new Set();
|
|
3613
4478
|
const paths = [];
|
|
3614
|
-
const add = (slug, title
|
|
4479
|
+
const add = (slug, title) => {
|
|
3615
4480
|
if (seen.has(slug)) {
|
|
3616
4481
|
return;
|
|
3617
4482
|
}
|
|
3618
4483
|
seen.add(slug);
|
|
3619
|
-
paths.push({ params: { slug }, props: {
|
|
4484
|
+
paths.push({ params: { slug }, props: { title } });
|
|
3620
4485
|
};
|
|
3621
4486
|
// A custom page wins over a content route sharing its path, so add it first.
|
|
3622
4487
|
for (const route of customRoutes) {
|
|
3623
|
-
add(route.slug, route.title
|
|
4488
|
+
add(route.slug, route.title);
|
|
3624
4489
|
}
|
|
3625
4490
|
for (const route of data.routes) {
|
|
3626
|
-
add(
|
|
3627
|
-
route.path === "/" ? "index" : route.path.slice(1),
|
|
3628
|
-
route.title,
|
|
3629
|
-
data.config.title
|
|
3630
|
-
);
|
|
4491
|
+
add(route.path === "/" ? "index" : route.path.slice(1), route.title);
|
|
3631
4492
|
}
|
|
3632
4493
|
return paths;
|
|
3633
4494
|
}
|
|
3634
4495
|
|
|
4496
|
+
// Footer branding shared by every card, derived once from the resolved config.
|
|
4497
|
+
// The repo slug reuses the header link URL; the host comes from the site URL.
|
|
4498
|
+
const repoSlug = data.config.repoUrl
|
|
4499
|
+
? data.config.repoUrl.split("github.com/")[1]
|
|
4500
|
+
: undefined;
|
|
4501
|
+
const siteHost = (() => {
|
|
4502
|
+
if (!data.config.site) {
|
|
4503
|
+
return undefined;
|
|
4504
|
+
}
|
|
4505
|
+
try {
|
|
4506
|
+
return new URL(data.config.site).host;
|
|
4507
|
+
} catch {
|
|
4508
|
+
return undefined;
|
|
4509
|
+
}
|
|
4510
|
+
})();
|
|
4511
|
+
|
|
3635
4512
|
export async function GET({ props }) {
|
|
3636
4513
|
const png = await renderOgImage({
|
|
3637
4514
|
accent: data.config.theme.accent,
|
|
3638
|
-
|
|
4515
|
+
brand: data.config.title,
|
|
4516
|
+
description: data.config.description,
|
|
4517
|
+
logo: data.config.logo?.svg,
|
|
4518
|
+
repo: repoSlug,
|
|
4519
|
+
site: siteHost,
|
|
3639
4520
|
title: props.title,
|
|
3640
4521
|
});
|
|
3641
4522
|
return new Response(png, {
|
|
@@ -3683,10 +4564,13 @@ var catchAllPageTemplate = (options) => {
|
|
|
3683
4564
|
` : "";
|
|
3684
4565
|
const mathEntry = options.mathEnabled ? `Math,
|
|
3685
4566
|
` : "";
|
|
4567
|
+
const clientData = options.needsReact ? `
|
|
4568
|
+
clientData={{ config: data.config, navigation, page: { route, title: seo.title ?? title } }}` : "";
|
|
3686
4569
|
return `---
|
|
3687
4570
|
// Generated by Blume. Do not edit.
|
|
3688
4571
|
import { getEntry, render } from "astro:content";
|
|
3689
4572
|
import RootLayout from "blume/components/layout/RootLayout.astro";
|
|
4573
|
+
import { resolveSlot } from "blume/components/layout/overrides.ts";
|
|
3690
4574
|
${askImport}
|
|
3691
4575
|
import Accordion from "blume/components/content/Accordion.astro";
|
|
3692
4576
|
import AccordionItem from "blume/components/content/AccordionItem.astro";
|
|
@@ -3862,11 +4746,15 @@ const localeSwitch = i18n
|
|
|
3862
4746
|
};
|
|
3863
4747
|
})
|
|
3864
4748
|
: [];
|
|
4749
|
+
|
|
4750
|
+
// The whole page shell is overridable via \`layout.Layout\`; it receives the same
|
|
4751
|
+
// props as the built-in RootLayout, plus the \`layout\` map for its inner slots.
|
|
4752
|
+
const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
3865
4753
|
---
|
|
3866
4754
|
|
|
3867
|
-
<
|
|
4755
|
+
<LayoutComponent
|
|
3868
4756
|
site={{ title: data.config.title, description: data.config.description }}
|
|
3869
|
-
layout={layoutOverrides}
|
|
4757
|
+
layout={layoutOverrides}${clientData}
|
|
3870
4758
|
logo={data.config.logo}
|
|
3871
4759
|
mcp={data.config.mcp}
|
|
3872
4760
|
favicon={data.config.favicon}
|
|
@@ -3885,6 +4773,7 @@ const localeSwitch = i18n
|
|
|
3885
4773
|
localeSwitch={localeSwitch}
|
|
3886
4774
|
page={{ title: seo.title ?? title, description: seo.description ?? frontmatter.description, route }}
|
|
3887
4775
|
headings={headings}
|
|
4776
|
+
toc={data.config.toc}
|
|
3888
4777
|
themeMode={data.config.theme.mode}
|
|
3889
4778
|
fontCssVars={data.fontCssVars}
|
|
3890
4779
|
searchEnabled={data.config.search.enabled}
|
|
@@ -3907,7 +4796,7 @@ const localeSwitch = i18n
|
|
|
3907
4796
|
<h1>{title}</h1>
|
|
3908
4797
|
{frontmatter.description && <p class="text-lg text-muted-foreground">{frontmatter.description}</p>}
|
|
3909
4798
|
<Content components={components} />
|
|
3910
|
-
</
|
|
4799
|
+
</LayoutComponent>
|
|
3911
4800
|
`;
|
|
3912
4801
|
};
|
|
3913
4802
|
var changelogIndexTemplate = (options) => {
|
|
@@ -3915,11 +4804,16 @@ var changelogIndexTemplate = (options) => {
|
|
|
3915
4804
|
` : "";
|
|
3916
4805
|
const askSlot = options.askEnabled ? `
|
|
3917
4806
|
<AskAI slot="ask" />` : "";
|
|
4807
|
+
const clientData = options.needsReact ? `
|
|
4808
|
+
clientData={{ config: data.config, navigation: data.navigation, page: { route: "/changelog", title: data.config.title + " changelog" } }}` : "";
|
|
4809
|
+
const stagedSpread = options.staged ? `
|
|
4810
|
+
...(await getCollection("staged")),` : "";
|
|
3918
4811
|
return `---
|
|
3919
4812
|
// Generated by Blume. Do not edit.
|
|
3920
4813
|
import { getCollection, render } from "astro:content";
|
|
3921
4814
|
import RootLayout from "blume/components/layout/RootLayout.astro";
|
|
3922
4815
|
import Update from "blume/components/content/Update.astro";
|
|
4816
|
+
import { resolveSlot } from "blume/components/layout/overrides.ts";
|
|
3923
4817
|
import { layoutOverrides } from "../generated/components.ts";
|
|
3924
4818
|
${askImport}import data from "../generated/data.json";
|
|
3925
4819
|
|
|
@@ -3953,7 +4847,9 @@ const slugify = (text) =>
|
|
|
3953
4847
|
text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") ||
|
|
3954
4848
|
"update";
|
|
3955
4849
|
|
|
3956
|
-
const changelogEntries =
|
|
4850
|
+
const changelogEntries = [
|
|
4851
|
+
...(await getCollection("docs")),${stagedSpread}
|
|
4852
|
+
]
|
|
3957
4853
|
.filter(
|
|
3958
4854
|
(entry) =>
|
|
3959
4855
|
entry.data.type === "changelog" &&
|
|
@@ -3989,11 +4885,13 @@ const headings = items.map((item) => ({
|
|
|
3989
4885
|
|
|
3990
4886
|
const base = data.config.site ? data.config.site.replace(/\\/$/, "") : null;
|
|
3991
4887
|
const canonical = base ? base + "/changelog" : null;
|
|
4888
|
+
|
|
4889
|
+
const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
3992
4890
|
---
|
|
3993
4891
|
|
|
3994
|
-
<
|
|
4892
|
+
<LayoutComponent
|
|
3995
4893
|
site={{ title: data.config.title, description: data.config.description }}
|
|
3996
|
-
layout={layoutOverrides}
|
|
4894
|
+
layout={layoutOverrides}${clientData}
|
|
3997
4895
|
logo={data.config.logo}
|
|
3998
4896
|
mcp={data.config.mcp}
|
|
3999
4897
|
favicon={data.config.favicon}
|
|
@@ -4009,6 +4907,7 @@ const canonical = base ? base + "/changelog" : null;
|
|
|
4009
4907
|
route: "/changelog",
|
|
4010
4908
|
}}
|
|
4011
4909
|
headings={headings}
|
|
4910
|
+
toc={data.config.toc}
|
|
4012
4911
|
themeMode={data.config.theme.mode}
|
|
4013
4912
|
fontCssVars={data.fontCssVars}
|
|
4014
4913
|
searchEnabled={data.config.search.enabled}
|
|
@@ -4037,7 +4936,7 @@ const canonical = base ? base + "/changelog" : null;
|
|
|
4037
4936
|
</div>
|
|
4038
4937
|
)
|
|
4039
4938
|
}
|
|
4040
|
-
</
|
|
4939
|
+
</LayoutComponent>
|
|
4041
4940
|
`;
|
|
4042
4941
|
};
|
|
4043
4942
|
var notFoundPageTemplate = () => `---
|
|
@@ -4078,19 +4977,6 @@ const nf = data.ui.notFound;
|
|
|
4078
4977
|
</div>
|
|
4079
4978
|
</PageLayout>
|
|
4080
4979
|
`;
|
|
4081
|
-
var userComponentsTemplate = (componentsFile) => {
|
|
4082
|
-
if (!componentsFile) {
|
|
4083
|
-
return `// Generated by Blume. Do not edit.
|
|
4084
|
-
export const mdxComponents = {};
|
|
4085
|
-
export const layoutOverrides = {};
|
|
4086
|
-
`;
|
|
4087
|
-
}
|
|
4088
|
-
return `// Generated by Blume. Do not edit.
|
|
4089
|
-
import overrides from ${JSON.stringify(componentsFile)};
|
|
4090
|
-
export const mdxComponents = overrides.mdx ?? {};
|
|
4091
|
-
export const layoutOverrides = overrides.layout ?? {};
|
|
4092
|
-
`;
|
|
4093
|
-
};
|
|
4094
4980
|
var islandDirective = (spec) => spec.client === "only" ? `client:only="${spec.framework}"` : `client:${spec.client}`;
|
|
4095
4981
|
var islandWrapperTemplate = (spec) => `---
|
|
4096
4982
|
// Generated by Blume. Do not edit.
|
|
@@ -4152,6 +5038,12 @@ declare module "blume:data" {
|
|
|
4152
5038
|
const data: import("blume").BlumeData;
|
|
4153
5039
|
export default data;
|
|
4154
5040
|
}
|
|
5041
|
+
|
|
5042
|
+
declare module "blume:search-client" {
|
|
5043
|
+
export const createSearch: () =>
|
|
5044
|
+
| import("blume/components/layout/search/types.ts").SearchFn
|
|
5045
|
+
| Promise<import("blume/components/layout/search/types.ts").SearchFn>;
|
|
5046
|
+
}
|
|
4155
5047
|
`;
|
|
4156
5048
|
var runtimePackageTemplate = (dependencies = []) => `${JSON.stringify({
|
|
4157
5049
|
dependencies: Object.fromEntries([...dependencies].toSorted().map((name) => [name, "*"])),
|
|
@@ -4332,7 +5224,7 @@ var specConfiguration = async (spec, root) => {
|
|
|
4332
5224
|
if (URL_SPEC.test(spec)) {
|
|
4333
5225
|
return { config: { url: spec } };
|
|
4334
5226
|
}
|
|
4335
|
-
const absolute =
|
|
5227
|
+
const absolute = isAbsolute3(spec) ? spec : join8(root, spec);
|
|
4336
5228
|
try {
|
|
4337
5229
|
return { config: { content: await readFile4(absolute, "utf-8") } };
|
|
4338
5230
|
} catch {
|
|
@@ -5071,9 +5963,106 @@ var twoslashCss = () => {
|
|
|
5071
5963
|
${OVERRIDES}`;
|
|
5072
5964
|
};
|
|
5073
5965
|
|
|
5966
|
+
// src/astro/component-slots.ts
|
|
5967
|
+
var EMPTY_MODULE = `// Generated by Blume. Do not edit.
|
|
5968
|
+
export const mdxComponents = {};
|
|
5969
|
+
export const layoutOverrides = {};
|
|
5970
|
+
`;
|
|
5971
|
+
var directiveFor = (override) => {
|
|
5972
|
+
const framework = override.source?.framework;
|
|
5973
|
+
switch (override.client) {
|
|
5974
|
+
case "idle": {
|
|
5975
|
+
return "client:idle";
|
|
5976
|
+
}
|
|
5977
|
+
case "visible": {
|
|
5978
|
+
return "client:visible";
|
|
5979
|
+
}
|
|
5980
|
+
case "media": {
|
|
5981
|
+
return override.media ? `client:media="${override.media}"` : "client:load";
|
|
5982
|
+
}
|
|
5983
|
+
case "only": {
|
|
5984
|
+
return framework ? `client:only="${framework}"` : "client:load";
|
|
5985
|
+
}
|
|
5986
|
+
default: {
|
|
5987
|
+
return "client:load";
|
|
5988
|
+
}
|
|
5989
|
+
}
|
|
5990
|
+
};
|
|
5991
|
+
var importClause = (variable, name, path) => name === "default" ? `import ${variable} from ${JSON.stringify(path)};` : `import { ${name} as ${variable} } from ${JSON.stringify(path)};`;
|
|
5992
|
+
var wrapperContent = (override) => {
|
|
5993
|
+
const { name, path } = override.source;
|
|
5994
|
+
const clause = name === "default" ? `import Component from ${JSON.stringify(path)};` : `import { ${name} as Component } from ${JSON.stringify(path)};`;
|
|
5995
|
+
return `---
|
|
5996
|
+
// Generated by Blume. Do not edit.
|
|
5997
|
+
${clause}
|
|
5998
|
+
---
|
|
5999
|
+
<Component ${directiveFor(override)} {...Astro.props}><slot /></Component>
|
|
6000
|
+
`;
|
|
6001
|
+
};
|
|
6002
|
+
var sanitize = (value) => value.replaceAll(/[^A-Za-z0-9]/gu, "_");
|
|
6003
|
+
var planComponentSlots = (componentsFile, analysis) => {
|
|
6004
|
+
const frameworks = new Set;
|
|
6005
|
+
if (!componentsFile) {
|
|
6006
|
+
return { frameworks, module: EMPTY_MODULE, wrappers: [] };
|
|
6007
|
+
}
|
|
6008
|
+
if (!analysis) {
|
|
6009
|
+
return {
|
|
6010
|
+
frameworks,
|
|
6011
|
+
module: `// Generated by Blume. Do not edit.
|
|
6012
|
+
import overrides from ${JSON.stringify(componentsFile)};
|
|
6013
|
+
export const mdxComponents = overrides.mdx ?? {};
|
|
6014
|
+
export const layoutOverrides = overrides.layout ?? {};
|
|
6015
|
+
`,
|
|
6016
|
+
wrappers: []
|
|
6017
|
+
};
|
|
6018
|
+
}
|
|
6019
|
+
const wrappers = [];
|
|
6020
|
+
const importLines = [];
|
|
6021
|
+
const mdxEntries = [];
|
|
6022
|
+
const layoutEntries = [];
|
|
6023
|
+
let counter = 0;
|
|
6024
|
+
const mdxOverrides = [...analysis.mdx, ...analysis.islands];
|
|
6025
|
+
const plan = (override, group, entries) => {
|
|
6026
|
+
const { source } = override;
|
|
6027
|
+
if (source?.framework) {
|
|
6028
|
+
frameworks.add(source.framework);
|
|
6029
|
+
}
|
|
6030
|
+
if (override.identifier && !override.client) {
|
|
6031
|
+
return;
|
|
6032
|
+
}
|
|
6033
|
+
if (!source) {
|
|
6034
|
+
return;
|
|
6035
|
+
}
|
|
6036
|
+
const variable = `__blumeSlot${counter}`;
|
|
6037
|
+
counter += 1;
|
|
6038
|
+
if (override.client) {
|
|
6039
|
+
const name = `${group}-${sanitize(override.key)}`;
|
|
6040
|
+
wrappers.push({ content: wrapperContent(override), name });
|
|
6041
|
+
importLines.push(importClause(variable, "default", `./component-slots/${name}.astro`));
|
|
6042
|
+
} else {
|
|
6043
|
+
importLines.push(importClause(variable, source.name, source.path));
|
|
6044
|
+
}
|
|
6045
|
+
entries.push(`${JSON.stringify(override.key)}: ${variable}`);
|
|
6046
|
+
};
|
|
6047
|
+
for (const override of mdxOverrides) {
|
|
6048
|
+
plan(override, "mdx", mdxEntries);
|
|
6049
|
+
}
|
|
6050
|
+
for (const override of analysis.layout) {
|
|
6051
|
+
plan(override, "layout", layoutEntries);
|
|
6052
|
+
}
|
|
6053
|
+
const moduleSource = `// Generated by Blume. Do not edit.
|
|
6054
|
+
import overrides from ${JSON.stringify(componentsFile)};
|
|
6055
|
+
${importLines.join(`
|
|
6056
|
+
`)}${importLines.length ? `
|
|
6057
|
+
` : ""}export const mdxComponents = { ...(overrides.mdx ?? {})${mdxEntries.length ? `, ${mdxEntries.join(", ")}` : ""} };
|
|
6058
|
+
export const layoutOverrides = { ...(overrides.layout ?? {})${layoutEntries.length ? `, ${layoutEntries.join(", ")}` : ""} };
|
|
6059
|
+
`;
|
|
6060
|
+
return { frameworks, module: moduleSource, wrappers };
|
|
6061
|
+
};
|
|
6062
|
+
|
|
5074
6063
|
// src/astro/examples.ts
|
|
5075
6064
|
import { readFile as readFile6 } from "node:fs/promises";
|
|
5076
|
-
import { join as join10, relative as
|
|
6065
|
+
import { join as join10, relative as relative4 } from "pathe";
|
|
5077
6066
|
import { glob as glob2 } from "tinyglobby";
|
|
5078
6067
|
|
|
5079
6068
|
// src/astro/islands.ts
|
|
@@ -5087,7 +6076,7 @@ var VALID_MODES = new Set([
|
|
|
5087
6076
|
"only",
|
|
5088
6077
|
"visible"
|
|
5089
6078
|
]);
|
|
5090
|
-
var
|
|
6079
|
+
var FRAMEWORK_BY_EXT2 = {
|
|
5091
6080
|
jsx: "react",
|
|
5092
6081
|
svelte: "svelte",
|
|
5093
6082
|
tsx: "react",
|
|
@@ -5121,7 +6110,7 @@ var discoverIslands = async (root) => {
|
|
|
5121
6110
|
for (const [index, file] of files.entries()) {
|
|
5122
6111
|
const base = basename(file);
|
|
5123
6112
|
const ext = base.match(ISLAND_FILE)?.groups?.ext;
|
|
5124
|
-
const framework = ext ?
|
|
6113
|
+
const framework = ext ? FRAMEWORK_BY_EXT2[ext] : undefined;
|
|
5125
6114
|
if (!framework) {
|
|
5126
6115
|
continue;
|
|
5127
6116
|
}
|
|
@@ -5147,7 +6136,7 @@ var discoverIslands = async (root) => {
|
|
|
5147
6136
|
};
|
|
5148
6137
|
|
|
5149
6138
|
// src/astro/examples.ts
|
|
5150
|
-
var
|
|
6139
|
+
var FRAMEWORK_BY_EXT3 = {
|
|
5151
6140
|
astro: "astro",
|
|
5152
6141
|
jsx: "react",
|
|
5153
6142
|
svelte: "svelte",
|
|
@@ -5183,11 +6172,11 @@ var discoverExamples = async (root, pattern = "examples") => {
|
|
|
5183
6172
|
const seen = new Map;
|
|
5184
6173
|
for (const [index, file] of files.entries()) {
|
|
5185
6174
|
const ext = file.match(EXAMPLE_FILE)?.groups?.ext;
|
|
5186
|
-
const framework = ext ?
|
|
6175
|
+
const framework = ext ? FRAMEWORK_BY_EXT3[ext] : undefined;
|
|
5187
6176
|
if (!(ext && framework)) {
|
|
5188
6177
|
continue;
|
|
5189
6178
|
}
|
|
5190
|
-
const path =
|
|
6179
|
+
const path = relative4(dir, file).slice(0, -(ext.length + 1));
|
|
5191
6180
|
const existing = seen.get(path);
|
|
5192
6181
|
if (existing) {
|
|
5193
6182
|
warnings.push(`Two examples both resolve to "${path}" ("${existing}" and "${file}"); ignoring the second. Give them distinct paths.`);
|
|
@@ -5208,7 +6197,7 @@ var discoverExamples = async (root, pattern = "examples") => {
|
|
|
5208
6197
|
};
|
|
5209
6198
|
|
|
5210
6199
|
// src/astro/pages.ts
|
|
5211
|
-
import { extname, relative as
|
|
6200
|
+
import { extname as extname2, relative as relative5 } from "pathe";
|
|
5212
6201
|
import { glob as glob3 } from "tinyglobby";
|
|
5213
6202
|
var discoverPages = async (pagesRoot) => {
|
|
5214
6203
|
const files = await glob3(["**/*.astro"], {
|
|
@@ -5218,8 +6207,8 @@ var discoverPages = async (pagesRoot) => {
|
|
|
5218
6207
|
});
|
|
5219
6208
|
files.sort();
|
|
5220
6209
|
return files.map((file) => {
|
|
5221
|
-
const rel =
|
|
5222
|
-
const withoutExt = rel.slice(0, rel.length -
|
|
6210
|
+
const rel = relative5(pagesRoot, file);
|
|
6211
|
+
const withoutExt = rel.slice(0, rel.length - extname2(rel).length);
|
|
5223
6212
|
const parts = withoutExt.split("/").filter((part) => part !== "index");
|
|
5224
6213
|
const pattern = parts.length === 0 ? "/" : `/${parts.join("/")}`;
|
|
5225
6214
|
return { entrypoint: file, pattern };
|
|
@@ -5228,7 +6217,7 @@ var discoverPages = async (pagesRoot) => {
|
|
|
5228
6217
|
var routeIsTaken = (pages, contentPages, route) => pages.some((page) => page.pattern === route) || contentPages.some((page) => page.route === route);
|
|
5229
6218
|
var PRIVATE_SEGMENT = /^[._]/u;
|
|
5230
6219
|
var humanizeSegment = (segment) => segment.split(/[-_]/u).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
5231
|
-
var customOgRoutes = (pages, siteTitle
|
|
6220
|
+
var customOgRoutes = (pages, siteTitle) => {
|
|
5232
6221
|
const seen = new Set;
|
|
5233
6222
|
const routes = [];
|
|
5234
6223
|
for (const { pattern } of pages) {
|
|
@@ -5242,7 +6231,7 @@ var customOgRoutes = (pages, siteTitle, siteDescription) => {
|
|
|
5242
6231
|
}
|
|
5243
6232
|
seen.add(slug);
|
|
5244
6233
|
const last = segments.at(-1);
|
|
5245
|
-
routes.push(
|
|
6234
|
+
routes.push({ slug, title: last ? humanizeSegment(last) : siteTitle });
|
|
5246
6235
|
}
|
|
5247
6236
|
return routes;
|
|
5248
6237
|
};
|
|
@@ -5266,8 +6255,8 @@ var resolvedAstroPath = (fromDir) => {
|
|
|
5266
6255
|
}
|
|
5267
6256
|
};
|
|
5268
6257
|
var blumeDepsDir = (pkgDir = packageRoot()) => {
|
|
5269
|
-
const candidates = [join11(pkgDir, "node_modules"),
|
|
5270
|
-
return candidates.find((dir) =>
|
|
6258
|
+
const candidates = [join11(pkgDir, "node_modules"), dirname7(pkgDir)];
|
|
6259
|
+
return candidates.find((dir) => existsSync6(join11(dir, "astro"))) ?? null;
|
|
5271
6260
|
};
|
|
5272
6261
|
var linkDepsJunction = async (link, depsDir) => {
|
|
5273
6262
|
const existing = await lstat(link).catch(() => null);
|
|
@@ -5277,7 +6266,7 @@ var linkDepsJunction = async (link, depsDir) => {
|
|
|
5277
6266
|
}
|
|
5278
6267
|
await rm(link, { force: true });
|
|
5279
6268
|
}
|
|
5280
|
-
await mkdir2(
|
|
6269
|
+
await mkdir2(dirname7(link), { recursive: true });
|
|
5281
6270
|
await symlink(depsDir, link, "junction");
|
|
5282
6271
|
};
|
|
5283
6272
|
var readPkgVersion = (pkgJsonPath) => {
|
|
@@ -5307,7 +6296,7 @@ var ensureDepsLink = async (outDir, pkgDir = packageRoot()) => {
|
|
|
5307
6296
|
if (blumeAstro && outDirAstro === blumeAstro) {
|
|
5308
6297
|
return null;
|
|
5309
6298
|
}
|
|
5310
|
-
if (
|
|
6299
|
+
if (existsSync6(join11(depsDir, "@astrojs", "mdx"))) {
|
|
5311
6300
|
await linkDepsJunction(join11(outDir, "node_modules"), depsDir);
|
|
5312
6301
|
return null;
|
|
5313
6302
|
}
|
|
@@ -5355,7 +6344,7 @@ var writeIfChanged = async (path, content) => {
|
|
|
5355
6344
|
if (existing === content) {
|
|
5356
6345
|
return false;
|
|
5357
6346
|
}
|
|
5358
|
-
await mkdir2(
|
|
6347
|
+
await mkdir2(dirname7(path), { recursive: true });
|
|
5359
6348
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
5360
6349
|
await writeFile2(tmp, content, "utf-8");
|
|
5361
6350
|
try {
|
|
@@ -5391,7 +6380,7 @@ var writeStagedContent = async (out, staged) => {
|
|
|
5391
6380
|
written.add(normalize(path));
|
|
5392
6381
|
await writeIfChanged(path, text);
|
|
5393
6382
|
}));
|
|
5394
|
-
if (
|
|
6383
|
+
if (existsSync6(contentDir)) {
|
|
5395
6384
|
await pruneOrphans(contentDir, written);
|
|
5396
6385
|
}
|
|
5397
6386
|
};
|
|
@@ -5410,7 +6399,7 @@ var resolveLogo = (project) => {
|
|
|
5410
6399
|
const file = [
|
|
5411
6400
|
join11(project.context.root, "public", rel),
|
|
5412
6401
|
join11(project.context.root, rel)
|
|
5413
|
-
].find((path) =>
|
|
6402
|
+
].find((path) => existsSync6(path));
|
|
5414
6403
|
if (file) {
|
|
5415
6404
|
return { alt, href, svg: readFileSync5(file, "utf-8") };
|
|
5416
6405
|
}
|
|
@@ -5450,13 +6439,13 @@ var APPLE_ICON_CANDIDATES = [
|
|
|
5450
6439
|
var resolveIconFile = (project, candidates) => {
|
|
5451
6440
|
const { root } = project.context;
|
|
5452
6441
|
for (const name of candidates) {
|
|
5453
|
-
if (
|
|
6442
|
+
if (existsSync6(join11(root, "public", name))) {
|
|
5454
6443
|
return { href: `/${name}`, type: faviconType(name) };
|
|
5455
6444
|
}
|
|
5456
6445
|
}
|
|
5457
6446
|
for (const name of candidates) {
|
|
5458
6447
|
const file = join11(root, name);
|
|
5459
|
-
if (
|
|
6448
|
+
if (existsSync6(file)) {
|
|
5460
6449
|
const type = faviconType(name);
|
|
5461
6450
|
return { href: inlineDataUri(file, type ?? "image/x-icon"), type };
|
|
5462
6451
|
}
|
|
@@ -5489,7 +6478,7 @@ var buildRuntimeData = (project) => {
|
|
|
5489
6478
|
if (!(editBase && sourcePath)) {
|
|
5490
6479
|
return null;
|
|
5491
6480
|
}
|
|
5492
|
-
const rel =
|
|
6481
|
+
const rel = relative6(context.root, sourcePath).split("\\").join("/");
|
|
5493
6482
|
return `${editBase}/${github?.dir ? `${github.dir}/${rel}` : rel}`;
|
|
5494
6483
|
};
|
|
5495
6484
|
const { i18n } = config;
|
|
@@ -5550,7 +6539,8 @@ var buildRuntimeData = (project) => {
|
|
|
5550
6539
|
site: config.deployment.site ?? null,
|
|
5551
6540
|
structuredData: config.seo.structuredData,
|
|
5552
6541
|
theme: config.theme,
|
|
5553
|
-
title: config.title
|
|
6542
|
+
title: config.title,
|
|
6543
|
+
toc: config.toc
|
|
5554
6544
|
},
|
|
5555
6545
|
feeds: buildRssFeeds(project).map((feed) => ({
|
|
5556
6546
|
href: feed.path,
|
|
@@ -5637,12 +6627,38 @@ var writeMcpFiles = async (project, plan, write) => {
|
|
|
5637
6627
|
write(join11(plan.dir, "server-card.ts"), staticJsonEndpointTemplate(buildMcpServerCard(discoveryInput)))
|
|
5638
6628
|
]);
|
|
5639
6629
|
};
|
|
6630
|
+
var writeAskFiles = async (project, srcDir, write) => {
|
|
6631
|
+
const { ask } = project.config.ai;
|
|
6632
|
+
if (!ask?.enabled) {
|
|
6633
|
+
return;
|
|
6634
|
+
}
|
|
6635
|
+
const grounded = ask.provider !== "inkeep";
|
|
6636
|
+
if (grounded) {
|
|
6637
|
+
await write(join11(srcDir, "generated", "ask-data.json"), `${JSON.stringify(await buildAskData(project))}
|
|
6638
|
+
`);
|
|
6639
|
+
}
|
|
6640
|
+
await write(join11(srcDir, "pages", "api", "ask.ts"), askEndpointTemplate(resolveAskBackend(ask), grounded));
|
|
6641
|
+
};
|
|
5640
6642
|
var writeNotFoundPage = async (write, srcDir, pages, contentPages) => {
|
|
5641
6643
|
if (routeIsTaken(pages, contentPages, "/404")) {
|
|
5642
6644
|
return;
|
|
5643
6645
|
}
|
|
5644
6646
|
await write(join11(srcDir, "pages", "404.astro"), notFoundPageTemplate());
|
|
5645
6647
|
};
|
|
6648
|
+
var shouldGenerateChangelog = (project) => {
|
|
6649
|
+
const hasChangelog = project.graph.pages.some((page) => page.contentType === "changelog" && !(page.meta.draft || page.meta.sidebar.hidden));
|
|
6650
|
+
const hasChangelogSource = (project.config.content.sources ?? []).some((source) => source.type === "github-releases");
|
|
6651
|
+
const changelogRouteTaken = project.graph.pages.some((page) => page.route === "/changelog");
|
|
6652
|
+
return (hasChangelog || hasChangelogSource) && !changelogRouteTaken;
|
|
6653
|
+
};
|
|
6654
|
+
var buildComponentSlots = async (componentsFile) => {
|
|
6655
|
+
const analysis = componentsFile ? analyzeComponentOverrides(await readFile7(componentsFile, "utf-8"), componentsFile) : null;
|
|
6656
|
+
return {
|
|
6657
|
+
plan: planComponentSlots(componentsFile, analysis),
|
|
6658
|
+
tags: analysis ? [...analysis.mdx, ...analysis.islands].map((entry) => entry.key) : [],
|
|
6659
|
+
warnings: analysis ? analysis.warnings : []
|
|
6660
|
+
};
|
|
6661
|
+
};
|
|
5646
6662
|
var generateRuntime = async (project) => {
|
|
5647
6663
|
const { context, config } = project;
|
|
5648
6664
|
const out = context.outDir;
|
|
@@ -5667,14 +6683,20 @@ var generateRuntime = async (project) => {
|
|
|
5667
6683
|
discoverIslands(context.root),
|
|
5668
6684
|
discoverExamples(context.root, config.examples)
|
|
5669
6685
|
]);
|
|
6686
|
+
const {
|
|
6687
|
+
plan: slotPlan,
|
|
6688
|
+
tags: overrideTags,
|
|
6689
|
+
warnings: overrideWarnings
|
|
6690
|
+
} = await buildComponentSlots(context.componentsFile);
|
|
5670
6691
|
const frameworks = new Set([
|
|
5671
6692
|
...islandDiscovery.islands.map((island) => island.framework),
|
|
5672
|
-
...exampleDiscovery.examples.map((example) => example.framework)
|
|
6693
|
+
...exampleDiscovery.examples.map((example) => example.framework),
|
|
6694
|
+
...slotPlan.frameworks
|
|
5673
6695
|
]);
|
|
5674
6696
|
const needsReact = detectedReact || askEnabled || frameworks.has("react");
|
|
5675
6697
|
const needsVue = frameworks.has("vue");
|
|
5676
6698
|
const needsSvelte = frameworks.has("svelte");
|
|
5677
|
-
const ogRoutes = customOgRoutes(pages, config.title
|
|
6699
|
+
const ogRoutes = customOgRoutes(pages, config.title);
|
|
5678
6700
|
const mcp = planMcp(project, srcDir);
|
|
5679
6701
|
pages.push(...mcp.discoveryPages);
|
|
5680
6702
|
const staged = collectStaged(project);
|
|
@@ -5702,9 +6724,10 @@ var generateRuntime = async (project) => {
|
|
|
5702
6724
|
askEnabled,
|
|
5703
6725
|
exportEpub,
|
|
5704
6726
|
exportPdf,
|
|
5705
|
-
mathEnabled: config.markdown.math
|
|
6727
|
+
mathEnabled: config.markdown.math,
|
|
6728
|
+
needsReact
|
|
5706
6729
|
})),
|
|
5707
|
-
write(join11(srcDir, "generated", "components.ts"),
|
|
6730
|
+
write(join11(srcDir, "generated", "components.ts"), slotPlan.module),
|
|
5708
6731
|
write(join11(srcDir, "generated", "islands.ts"), islandMapTemplate(islandDiscovery.islands)),
|
|
5709
6732
|
write(join11(srcDir, "generated", "examples.ts"), exampleMapTemplate(exampleDiscovery.examples)),
|
|
5710
6733
|
write(themePath, tailwindEntryTemplate({
|
|
@@ -5718,18 +6741,21 @@ var generateRuntime = async (project) => {
|
|
|
5718
6741
|
}))
|
|
5719
6742
|
]);
|
|
5720
6743
|
await Promise.all(islandDiscovery.islands.map((island) => write(join11(srcDir, "generated", "islands", `${island.name}.astro`), islandWrapperTemplate(island))));
|
|
6744
|
+
await Promise.all(slotPlan.wrappers.map((wrapper) => write(join11(srcDir, "generated", "component-slots", `${wrapper.name}.astro`), wrapper.content)));
|
|
5721
6745
|
await Promise.all(exampleDiscovery.examples.map((example) => write(join11(srcDir, "generated", "examples", `${exampleSlug(example.path)}.astro`), exampleWrapperTemplate(example))));
|
|
5722
|
-
|
|
5723
|
-
await write(join11(srcDir, "pages", "api", "ask.ts"), askEndpointTemplate(resolveAskBackend(config.ai.ask)));
|
|
5724
|
-
}
|
|
6746
|
+
await writeAskFiles(project, srcDir, write);
|
|
5725
6747
|
await writeMcpFiles(project, mcp, write);
|
|
5726
6748
|
if (config.seo.og.enabled) {
|
|
5727
6749
|
await write(join11(srcDir, "pages", "og", "[...slug].png.ts"), ogEndpointTemplate(ogRoutes));
|
|
5728
6750
|
}
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
6751
|
+
if (shouldGenerateChangelog(project)) {
|
|
6752
|
+
await write(join11(srcDir, "pages", "changelog.astro"), changelogIndexTemplate({
|
|
6753
|
+
askEnabled,
|
|
6754
|
+
exportEpub,
|
|
6755
|
+
exportPdf,
|
|
6756
|
+
needsReact,
|
|
6757
|
+
staged: hasStaged
|
|
6758
|
+
}));
|
|
5733
6759
|
}
|
|
5734
6760
|
await writeNotFoundPage(write, srcDir, pages, project.graph.pages);
|
|
5735
6761
|
await write(searchClientPath, searchClientTemplate(config));
|
|
@@ -5762,8 +6788,23 @@ var generateRuntime = async (project) => {
|
|
|
5762
6788
|
...depsLinkWarning ? [depsLinkWarning] : [],
|
|
5763
6789
|
...mcp.warnings,
|
|
5764
6790
|
...islandDiscovery.warnings,
|
|
5765
|
-
...exampleDiscovery.warnings
|
|
6791
|
+
...exampleDiscovery.warnings,
|
|
6792
|
+
...overrideWarnings
|
|
5766
6793
|
];
|
|
6794
|
+
const navTargetRoutes = new Set([
|
|
6795
|
+
...project.graph.routes.keys(),
|
|
6796
|
+
...pages.map((page) => page.pattern),
|
|
6797
|
+
...referenceTabs(config).map((tab) => tab.path)
|
|
6798
|
+
]);
|
|
6799
|
+
if (shouldGenerateChangelog(project)) {
|
|
6800
|
+
navTargetRoutes.add("/changelog");
|
|
6801
|
+
}
|
|
6802
|
+
warnings.push(...validateNavTargets(project.graph.navigation, navTargetRoutes).map((diagnostic) => diagnostic.suggestion ? `${diagnostic.message} ${diagnostic.suggestion}` : diagnostic.message));
|
|
6803
|
+
const knownComponentTags = new Set([
|
|
6804
|
+
...islandDiscovery.islands.map((island) => island.name),
|
|
6805
|
+
...overrideTags
|
|
6806
|
+
]);
|
|
6807
|
+
warnings.push(...validateUsedComponents(project.graph.pages, knownComponentTags, new Set(registry.map((item) => item.name))).map((diagnostic) => diagnostic.suggestion ? `${diagnostic.message} ${diagnostic.suggestion}` : diagnostic.message));
|
|
5767
6808
|
for (const dep of searchProviderMeta(config.search.provider).runtimeDeps) {
|
|
5768
6809
|
if (!(canResolveFrom(context.root, dep) || canResolveFrom(packageRoot(), dep))) {
|
|
5769
6810
|
warnings.push(`Search provider "${config.search.provider}" needs "${dep}", which isn't installed. Run \`npm install ${dep}\` (or your package manager's equivalent).`);
|
|
@@ -5787,14 +6828,17 @@ var generateRuntime = async (project) => {
|
|
|
5787
6828
|
return { structuralChange: structural.some(Boolean), warnings };
|
|
5788
6829
|
};
|
|
5789
6830
|
|
|
6831
|
+
// src/core/config.ts
|
|
6832
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6 } from "node:fs";
|
|
6833
|
+
|
|
5790
6834
|
// src/core/bridge.ts
|
|
5791
|
-
import { existsSync as
|
|
6835
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
5792
6836
|
import { readFile as readFile9 } from "node:fs/promises";
|
|
5793
6837
|
import { join as join12 } from "pathe";
|
|
5794
6838
|
|
|
5795
6839
|
// src/migrate/mintlify/config.ts
|
|
5796
6840
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
5797
|
-
import { dirname as
|
|
6841
|
+
import { dirname as dirname8, relative as relative7, resolve as resolve4 } from "pathe";
|
|
5798
6842
|
var MINTLIFY_DEFAULT_IGNORES = [
|
|
5799
6843
|
"**/_*",
|
|
5800
6844
|
"**/.*",
|
|
@@ -5830,7 +6874,7 @@ var asDirectoryMode = (value) => value === "accordion" || value === "card" || va
|
|
|
5830
6874
|
var withoutUndefined = (value) => Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined));
|
|
5831
6875
|
var hasOwn = (object, key) => Object.hasOwn(object, key);
|
|
5832
6876
|
var isInsideRoot = (root, candidate) => {
|
|
5833
|
-
const rel =
|
|
6877
|
+
const rel = relative7(root, candidate);
|
|
5834
6878
|
return rel === "" || !rel.startsWith("..") && !rel.startsWith("/");
|
|
5835
6879
|
};
|
|
5836
6880
|
var readJsonFile = async (file) => {
|
|
@@ -5855,7 +6899,7 @@ var resolveRefs = async (value, options) => {
|
|
|
5855
6899
|
}
|
|
5856
6900
|
const ref = asString(object.$ref);
|
|
5857
6901
|
if (ref) {
|
|
5858
|
-
const refFile =
|
|
6902
|
+
const refFile = resolve4(dirname8(options.file), ref);
|
|
5859
6903
|
if (!isInsideRoot(options.root, refFile)) {
|
|
5860
6904
|
throw new BlumeError({
|
|
5861
6905
|
code: "BLUME_MINTLIFY_REF_OUTSIDE_ROOT",
|
|
@@ -6209,53 +7253,9 @@ var mintlifySelectors = (spec) => {
|
|
|
6209
7253
|
}
|
|
6210
7254
|
].filter((selector) => selector.items.length > 0);
|
|
6211
7255
|
};
|
|
6212
|
-
var navbarTypeLabel = (type) => {
|
|
6213
|
-
if (type === "github") {
|
|
6214
|
-
return "GitHub";
|
|
6215
|
-
}
|
|
6216
|
-
if (type === "discord") {
|
|
6217
|
-
return "Discord";
|
|
6218
|
-
}
|
|
6219
|
-
return;
|
|
6220
|
-
};
|
|
6221
|
-
var navbarLinkType = (type) => type === "github" || type === "discord" ? type : undefined;
|
|
6222
|
-
var navbarPrimaryType = (type) => type === "github" || type === "discord" ? type : "button";
|
|
6223
|
-
var mintlifyNavbar = (value) => {
|
|
6224
|
-
const object = asObject(value);
|
|
6225
|
-
if (!object) {
|
|
6226
|
-
return { links: [] };
|
|
6227
|
-
}
|
|
6228
|
-
const links = asArray(object.links).flatMap((item) => {
|
|
6229
|
-
const itemObject = asObject(item);
|
|
6230
|
-
const href = itemObject ? asString(itemObject.href) : undefined;
|
|
6231
|
-
const type = itemObject ? asString(itemObject.type) : undefined;
|
|
6232
|
-
const label = itemObject ? asString(itemObject.label) ?? navbarTypeLabel(type) : undefined;
|
|
6233
|
-
if (!itemObject || !href || !label) {
|
|
6234
|
-
return [];
|
|
6235
|
-
}
|
|
6236
|
-
return [
|
|
6237
|
-
withoutUndefined({
|
|
6238
|
-
href,
|
|
6239
|
-
icon: asString(itemObject.icon),
|
|
6240
|
-
label,
|
|
6241
|
-
type: navbarLinkType(type)
|
|
6242
|
-
})
|
|
6243
|
-
];
|
|
6244
|
-
});
|
|
6245
|
-
const primaryObject = asObject(object.primary);
|
|
6246
|
-
const primaryHref = primaryObject ? asString(primaryObject.href) : undefined;
|
|
6247
|
-
const primaryType = primaryObject ? asString(primaryObject.type) ?? "button" : undefined;
|
|
6248
|
-
const primaryLabel = primaryObject ? asString(primaryObject.label) ?? navbarTypeLabel(primaryType) : undefined;
|
|
6249
|
-
const primary = primaryObject && primaryHref && primaryLabel ? withoutUndefined({
|
|
6250
|
-
href: primaryHref,
|
|
6251
|
-
label: primaryLabel,
|
|
6252
|
-
type: navbarPrimaryType(primaryType)
|
|
6253
|
-
}) : undefined;
|
|
6254
|
-
return withoutUndefined({ links, primary });
|
|
6255
|
-
};
|
|
6256
7256
|
var mintignorePatterns = async (root) => {
|
|
6257
7257
|
try {
|
|
6258
|
-
const raw = await readFile8(
|
|
7258
|
+
const raw = await readFile8(resolve4(root, ".mintignore"), "utf-8");
|
|
6259
7259
|
return raw.split(`
|
|
6260
7260
|
`).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).filter((line) => !line.startsWith("!")).map((line) => line.endsWith("/") ? `${line}**` : line);
|
|
6261
7261
|
} catch {
|
|
@@ -6274,61 +7274,6 @@ var mintlifyRedirects = (spec) => asArray(spec.redirects).flatMap((redirect) =>
|
|
|
6274
7274
|
}
|
|
6275
7275
|
return [{ from, to }];
|
|
6276
7276
|
});
|
|
6277
|
-
var mintlifyContextual = (value) => {
|
|
6278
|
-
const object = asObject(value);
|
|
6279
|
-
if (!object) {
|
|
6280
|
-
return { options: [] };
|
|
6281
|
-
}
|
|
6282
|
-
const display = object.display === "toc" ? "toc" : "header";
|
|
6283
|
-
const options = [];
|
|
6284
|
-
for (const option of asArray(object.options)) {
|
|
6285
|
-
if (typeof option === "string") {
|
|
6286
|
-
options.push(option);
|
|
6287
|
-
continue;
|
|
6288
|
-
}
|
|
6289
|
-
const optionObject = asObject(option);
|
|
6290
|
-
const title = optionObject ? asString(optionObject.title) : undefined;
|
|
6291
|
-
if (!optionObject || !title) {
|
|
6292
|
-
continue;
|
|
6293
|
-
}
|
|
6294
|
-
options.push(withoutUndefined({
|
|
6295
|
-
description: asString(optionObject.description),
|
|
6296
|
-
href: asString(optionObject.href),
|
|
6297
|
-
icon: asString(optionObject.icon),
|
|
6298
|
-
title
|
|
6299
|
-
}));
|
|
6300
|
-
}
|
|
6301
|
-
return { display, options };
|
|
6302
|
-
};
|
|
6303
|
-
var mintlifyFooter = (value) => {
|
|
6304
|
-
const object = asObject(value);
|
|
6305
|
-
const socials = asObject(object?.socials);
|
|
6306
|
-
const links = asArray(object?.links).flatMap((group) => {
|
|
6307
|
-
const groupObject = asObject(group);
|
|
6308
|
-
const items = asArray(groupObject?.items).flatMap((item) => {
|
|
6309
|
-
const itemObject = asObject(item);
|
|
6310
|
-
const label = itemObject ? asString(itemObject.label) : undefined;
|
|
6311
|
-
const href = itemObject ? asString(itemObject.href) : undefined;
|
|
6312
|
-
return label && href ? [{ href, label }] : [];
|
|
6313
|
-
});
|
|
6314
|
-
if (!groupObject || items.length === 0) {
|
|
6315
|
-
return [];
|
|
6316
|
-
}
|
|
6317
|
-
return [
|
|
6318
|
-
withoutUndefined({
|
|
6319
|
-
header: asString(groupObject.header),
|
|
6320
|
-
items
|
|
6321
|
-
})
|
|
6322
|
-
];
|
|
6323
|
-
}).slice(0, 4);
|
|
6324
|
-
return {
|
|
6325
|
-
links,
|
|
6326
|
-
socials: socials ? Object.fromEntries(Object.entries(socials).flatMap(([label, href]) => {
|
|
6327
|
-
const hrefValue = asString(href);
|
|
6328
|
-
return hrefValue ? [[label, hrefValue]] : [];
|
|
6329
|
-
})) : {}
|
|
6330
|
-
};
|
|
6331
|
-
};
|
|
6332
7277
|
var mintlifyLogo = (value) => {
|
|
6333
7278
|
if (typeof value === "string") {
|
|
6334
7279
|
return value;
|
|
@@ -6393,16 +7338,12 @@ var mintlifyChromeVariants = (spec) => {
|
|
|
6393
7338
|
return [];
|
|
6394
7339
|
}
|
|
6395
7340
|
const banner = hasOwn(object, "banner") ? mintlifyBanner(object.banner) : undefined;
|
|
6396
|
-
|
|
6397
|
-
const navbar = hasOwn(object, "navbar") ? mintlifyNavbar(object.navbar) : undefined;
|
|
6398
|
-
if (!banner && !footer && !navbar) {
|
|
7341
|
+
if (!banner) {
|
|
6399
7342
|
return [];
|
|
6400
7343
|
}
|
|
6401
7344
|
return [
|
|
6402
7345
|
withoutUndefined({
|
|
6403
7346
|
banner,
|
|
6404
|
-
footer,
|
|
6405
|
-
navbar,
|
|
6406
7347
|
path
|
|
6407
7348
|
})
|
|
6408
7349
|
];
|
|
@@ -6454,13 +7395,6 @@ var mintlifyMarkdown = (value, styling) => {
|
|
|
6454
7395
|
schema: object?.schema === false ? false : undefined
|
|
6455
7396
|
});
|
|
6456
7397
|
};
|
|
6457
|
-
var mintlifyStyling = (value) => {
|
|
6458
|
-
const object = asObject(value);
|
|
6459
|
-
const eyebrows = asString(object?.eyebrows);
|
|
6460
|
-
return withoutUndefined({
|
|
6461
|
-
eyebrows: eyebrows === "breadcrumbs" || eyebrows === "section" ? eyebrows : undefined
|
|
6462
|
-
});
|
|
6463
|
-
};
|
|
6464
7398
|
var mintlifySeo = (value) => {
|
|
6465
7399
|
const object = asObject(value);
|
|
6466
7400
|
const metatags = asObject(object?.metatags);
|
|
@@ -6471,16 +7405,9 @@ var mintlifySeo = (value) => {
|
|
|
6471
7405
|
})) : {}
|
|
6472
7406
|
};
|
|
6473
7407
|
};
|
|
6474
|
-
var mintlifyIcons = (value) => {
|
|
6475
|
-
const object = asObject(value);
|
|
6476
|
-
const library = object?.library;
|
|
6477
|
-
return withoutUndefined({
|
|
6478
|
-
library: library === "fontawesome" || library === "lucide" || library === "tabler" ? library : undefined
|
|
6479
|
-
});
|
|
6480
|
-
};
|
|
6481
7408
|
var loadMintlifyConfig = async (root, file) => {
|
|
6482
|
-
const projectRoot =
|
|
6483
|
-
const configFile =
|
|
7409
|
+
const projectRoot = resolve4(root);
|
|
7410
|
+
const configFile = resolve4(file);
|
|
6484
7411
|
const spec = asObject(await resolveRefs(await readJsonFile(configFile), {
|
|
6485
7412
|
file: configFile,
|
|
6486
7413
|
root: projectRoot,
|
|
@@ -6511,14 +7438,10 @@ var loadMintlifyConfig = async (root, file) => {
|
|
|
6511
7438
|
],
|
|
6512
7439
|
root: "."
|
|
6513
7440
|
},
|
|
6514
|
-
contextual: mintlifyContextual(spec.contextual),
|
|
6515
7441
|
description: asString(spec.description),
|
|
6516
7442
|
favicon: mintlifyFavicon(spec.favicon),
|
|
6517
|
-
footer: mintlifyFooter(spec.footer),
|
|
6518
|
-
icons: mintlifyIcons(spec.icons),
|
|
6519
7443
|
logo: mintlifyLogo(spec.logo),
|
|
6520
7444
|
markdown: mintlifyMarkdown(spec.markdown, styling),
|
|
6521
|
-
navbar: mintlifyNavbar(spec.navbar),
|
|
6522
7445
|
navigation: {
|
|
6523
7446
|
chromeVariants: mintlifyChromeVariants(spec),
|
|
6524
7447
|
selectors: mintlifySelectors(spec),
|
|
@@ -6534,7 +7457,6 @@ var loadMintlifyConfig = async (root, file) => {
|
|
|
6534
7457
|
prompt: asString(search.prompt)
|
|
6535
7458
|
},
|
|
6536
7459
|
seo: mintlifySeo(seo),
|
|
6537
|
-
styling: mintlifyStyling(styling),
|
|
6538
7460
|
theme: {
|
|
6539
7461
|
accent: asString(colors.primary) ?? "blue",
|
|
6540
7462
|
accentDark: asString(colors.light),
|
|
@@ -6581,7 +7503,7 @@ var mintlifyI18n = (spec) => {
|
|
|
6581
7503
|
// src/core/bridge.ts
|
|
6582
7504
|
var MINTLIFY_CONFIG_FILES = ["docs.json", "mint.json"];
|
|
6583
7505
|
var detectMintlifyBridge = async (root) => {
|
|
6584
|
-
const configFile = MINTLIFY_CONFIG_FILES.map((name) => join12(root, name)).find((candidate) =>
|
|
7506
|
+
const configFile = MINTLIFY_CONFIG_FILES.map((name) => join12(root, name)).find((candidate) => existsSync7(candidate));
|
|
6585
7507
|
if (!configFile) {
|
|
6586
7508
|
return null;
|
|
6587
7509
|
}
|
|
@@ -6670,8 +7592,8 @@ var createModuleLoader = () => {
|
|
|
6670
7592
|
};
|
|
6671
7593
|
|
|
6672
7594
|
// src/core/project.ts
|
|
6673
|
-
import { existsSync as
|
|
6674
|
-
import { isAbsolute as
|
|
7595
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
7596
|
+
import { isAbsolute as isAbsolute4, join as join13, resolve as resolve5 } from "pathe";
|
|
6675
7597
|
var CONFIG_FILENAMES = [
|
|
6676
7598
|
"blume.config.ts",
|
|
6677
7599
|
"blume.config.mjs",
|
|
@@ -6682,7 +7604,7 @@ var COMPONENTS_FILENAMES = ["components.tsx", "components.ts"];
|
|
|
6682
7604
|
var firstExisting = (root, names) => {
|
|
6683
7605
|
for (const name of names) {
|
|
6684
7606
|
const candidate = join13(root, name);
|
|
6685
|
-
if (
|
|
7607
|
+
if (existsSync8(candidate)) {
|
|
6686
7608
|
return candidate;
|
|
6687
7609
|
}
|
|
6688
7610
|
}
|
|
@@ -6690,10 +7612,10 @@ var firstExisting = (root, names) => {
|
|
|
6690
7612
|
};
|
|
6691
7613
|
var findConfigFile = (root) => firstExisting(root, CONFIG_FILENAMES);
|
|
6692
7614
|
var resolveProjectContext = (root, config) => {
|
|
6693
|
-
const absoluteRoot =
|
|
6694
|
-
const contentRoot =
|
|
7615
|
+
const absoluteRoot = resolve5(root);
|
|
7616
|
+
const contentRoot = isAbsolute4(config.content.root) ? config.content.root : join13(absoluteRoot, config.content.root);
|
|
6695
7617
|
const pagesPath = join13(absoluteRoot, config.content.pages);
|
|
6696
|
-
const pagesRoot =
|
|
7618
|
+
const pagesRoot = existsSync8(pagesPath) ? pagesPath : null;
|
|
6697
7619
|
return {
|
|
6698
7620
|
componentsFile: firstExisting(absoluteRoot, COMPONENTS_FILENAMES),
|
|
6699
7621
|
configFile: findConfigFile(absoluteRoot),
|
|
@@ -6855,6 +7777,16 @@ var notionSourceSchema = z2.object({
|
|
|
6855
7777
|
publishedValue: z2.string().optional(),
|
|
6856
7778
|
type: z2.literal("notion")
|
|
6857
7779
|
});
|
|
7780
|
+
var githubReleasesSourceSchema = z2.object({
|
|
7781
|
+
drafts: z2.boolean().optional(),
|
|
7782
|
+
limit: z2.number().positive().optional(),
|
|
7783
|
+
owner: z2.string(),
|
|
7784
|
+
pollInterval: z2.number().positive().optional(),
|
|
7785
|
+
prefix: z2.string().optional(),
|
|
7786
|
+
prereleases: z2.boolean().optional(),
|
|
7787
|
+
repo: z2.string(),
|
|
7788
|
+
type: z2.literal("github-releases")
|
|
7789
|
+
}).strict();
|
|
6858
7790
|
var mintlifySourceSchema = z2.object({
|
|
6859
7791
|
configFile: z2.string().optional(),
|
|
6860
7792
|
exclude: z2.array(z2.string()).default([]),
|
|
@@ -6871,6 +7803,7 @@ var customSourceSchema = z2.object({
|
|
|
6871
7803
|
var contentSourceSchema = z2.discriminatedUnion("type", [
|
|
6872
7804
|
filesystemSourceSchema,
|
|
6873
7805
|
mdxRemoteSourceSchema,
|
|
7806
|
+
githubReleasesSourceSchema,
|
|
6874
7807
|
sanitySourceSchema,
|
|
6875
7808
|
notionSourceSchema,
|
|
6876
7809
|
mintlifySourceSchema,
|
|
@@ -6927,26 +7860,6 @@ var sidebarVariantSchema = z2.object({
|
|
|
6927
7860
|
items: z2.array(sidebarItemSchema).default([]),
|
|
6928
7861
|
path: z2.string()
|
|
6929
7862
|
}).strict();
|
|
6930
|
-
var navbarLinkTypeSchema = z2.enum(["github", "discord"]);
|
|
6931
|
-
var navbarLinkSchema = z2.object({
|
|
6932
|
-
href: z2.string(),
|
|
6933
|
-
icon: iconName.optional(),
|
|
6934
|
-
label: z2.string().optional(),
|
|
6935
|
-
type: navbarLinkTypeSchema.optional()
|
|
6936
|
-
}).strict().refine((value) => value.label !== undefined || value.type !== undefined, {
|
|
6937
|
-
message: "Navbar links require either label or type."
|
|
6938
|
-
});
|
|
6939
|
-
var navbarPrimarySchema = z2.object({
|
|
6940
|
-
href: z2.string(),
|
|
6941
|
-
label: z2.string().optional(),
|
|
6942
|
-
type: z2.enum(["button", "github", "discord"]).default("button")
|
|
6943
|
-
}).strict().refine((value) => value.label !== undefined || value.type !== "button", {
|
|
6944
|
-
message: "Navbar primary button links require a label."
|
|
6945
|
-
});
|
|
6946
|
-
var navbarConfigSchema = z2.object({
|
|
6947
|
-
links: z2.array(navbarLinkSchema).default([]),
|
|
6948
|
-
primary: navbarPrimarySchema.optional()
|
|
6949
|
-
}).strict();
|
|
6950
7863
|
var variablesConfigSchema = z2.record(z2.string().regex(/^[A-Za-z0-9-]+$/u), z2.string()).default({});
|
|
6951
7864
|
var fontSlug = z2.string().refine(isFontSlug, (value) => ({
|
|
6952
7865
|
message: `Unknown font "${value}". Supported fonts: ${FONT_SLUGS.join(", ")}.`
|
|
@@ -6970,9 +7883,6 @@ var themeConfigSchema = z2.object({
|
|
|
6970
7883
|
radius: z2.enum(["none", "sm", "md", "lg"]).default("md"),
|
|
6971
7884
|
strict: z2.boolean().default(false)
|
|
6972
7885
|
}).strict();
|
|
6973
|
-
var iconsConfigSchema = z2.object({
|
|
6974
|
-
library: z2.enum(["fontawesome", "lucide", "tabler"]).default("lucide")
|
|
6975
|
-
}).strict();
|
|
6976
7886
|
var algoliaSearchSchema = z2.object({
|
|
6977
7887
|
appId: z2.string(),
|
|
6978
7888
|
indexName: z2.string(),
|
|
@@ -7054,33 +7964,8 @@ var aiConfigSchema = z2.object({
|
|
|
7054
7964
|
}).optional(),
|
|
7055
7965
|
llmsTxt: z2.boolean().default(false)
|
|
7056
7966
|
}).strict();
|
|
7057
|
-
var contextualOptionSchema = z2.union([
|
|
7058
|
-
z2.string(),
|
|
7059
|
-
z2.object({
|
|
7060
|
-
description: z2.string().optional(),
|
|
7061
|
-
href: z2.string().optional(),
|
|
7062
|
-
icon: iconName.optional(),
|
|
7063
|
-
title: z2.string()
|
|
7064
|
-
}).passthrough()
|
|
7065
|
-
]);
|
|
7066
|
-
var contextualConfigSchema = z2.object({
|
|
7067
|
-
display: z2.enum(["header", "toc"]).default("header"),
|
|
7068
|
-
options: z2.array(contextualOptionSchema).default([])
|
|
7069
|
-
}).strict();
|
|
7070
|
-
var footerConfigSchema = z2.object({
|
|
7071
|
-
links: z2.array(z2.object({
|
|
7072
|
-
header: z2.string().optional(),
|
|
7073
|
-
items: z2.array(z2.object({
|
|
7074
|
-
href: z2.string(),
|
|
7075
|
-
label: z2.string()
|
|
7076
|
-
}).strict()).default([])
|
|
7077
|
-
}).strict()).max(4).default([]),
|
|
7078
|
-
socials: z2.record(z2.string(), z2.string()).default({})
|
|
7079
|
-
}).strict();
|
|
7080
7967
|
var chromeVariantSchema = z2.object({
|
|
7081
7968
|
banner: bannerConfigSchema.optional(),
|
|
7082
|
-
footer: footerConfigSchema.optional(),
|
|
7083
|
-
navbar: navbarConfigSchema.optional(),
|
|
7084
7969
|
path: z2.string()
|
|
7085
7970
|
}).strict();
|
|
7086
7971
|
var navigationConfigSchema = z2.object({
|
|
@@ -7205,9 +8090,6 @@ var markdownConfigSchema = z2.object({
|
|
|
7205
8090
|
imageZoom: z2.boolean().default(true),
|
|
7206
8091
|
math: z2.boolean().default(false)
|
|
7207
8092
|
}).strict();
|
|
7208
|
-
var stylingConfigSchema = z2.object({
|
|
7209
|
-
eyebrows: z2.enum(["breadcrumbs", "section"]).default("section")
|
|
7210
|
-
}).strict();
|
|
7211
8093
|
var openapiSourceSchema = z2.object({
|
|
7212
8094
|
label: z2.string().optional(),
|
|
7213
8095
|
route: z2.string().optional(),
|
|
@@ -7227,36 +8109,48 @@ var asyncapiConfigSchema = z2.object({
|
|
|
7227
8109
|
spec: z2.string().optional(),
|
|
7228
8110
|
theme: z2.string().optional()
|
|
7229
8111
|
}).strict();
|
|
8112
|
+
var tocConfigSchema = z2.union([
|
|
8113
|
+
z2.boolean(),
|
|
8114
|
+
z2.object({
|
|
8115
|
+
maxHeadingLevel: z2.number().int().min(1).max(6).optional(),
|
|
8116
|
+
minHeadingLevel: z2.number().int().min(1).max(6).optional()
|
|
8117
|
+
}).strict()
|
|
8118
|
+
]).default(true).transform((value) => {
|
|
8119
|
+
if (typeof value === "boolean") {
|
|
8120
|
+
return { enabled: value, maxLevel: 3, minLevel: 2 };
|
|
8121
|
+
}
|
|
8122
|
+
return {
|
|
8123
|
+
enabled: true,
|
|
8124
|
+
maxLevel: value.maxHeadingLevel ?? 3,
|
|
8125
|
+
minLevel: value.minHeadingLevel ?? 2
|
|
8126
|
+
};
|
|
8127
|
+
});
|
|
7230
8128
|
var blumeConfigSchema = z2.object({
|
|
7231
8129
|
ai: aiConfigSchema.default({}),
|
|
7232
8130
|
analytics: analyticsConfigSchema.optional(),
|
|
7233
8131
|
asyncapi: asyncapiConfigSchema.default({}),
|
|
7234
8132
|
banner: bannerConfigSchema.optional(),
|
|
7235
8133
|
content: contentConfigSchema.default({}),
|
|
7236
|
-
contextual: contextualConfigSchema.default({}),
|
|
7237
8134
|
deployment: deploymentConfigSchema.default({}),
|
|
7238
8135
|
description: z2.string().optional(),
|
|
7239
8136
|
examples: z2.string().default("examples"),
|
|
7240
8137
|
export: exportConfigSchema.default(false),
|
|
7241
8138
|
favicon: faviconConfigSchema.optional(),
|
|
7242
8139
|
feedback: z2.boolean().default(true),
|
|
7243
|
-
footer: footerConfigSchema.default({}),
|
|
7244
8140
|
github: githubConfigSchema.optional(),
|
|
7245
8141
|
i18n: i18nConfigSchema.optional(),
|
|
7246
|
-
icons: iconsConfigSchema.default({}),
|
|
7247
8142
|
lastModified: lastModifiedConfigSchema.default(false),
|
|
7248
8143
|
logo: logoConfigSchema.optional(),
|
|
7249
8144
|
markdown: markdownConfigSchema.default({}),
|
|
7250
8145
|
mcp: mcpConfigSchema.default({}),
|
|
7251
|
-
navbar: navbarConfigSchema.default({}),
|
|
7252
8146
|
navigation: navigationConfigSchema.default({}),
|
|
7253
8147
|
openapi: openapiConfigSchema.default({}),
|
|
7254
8148
|
redirects: z2.array(redirectSchema).default([]),
|
|
7255
8149
|
search: searchConfigSchema.default({}),
|
|
7256
8150
|
seo: seoConfigSchema.default({}),
|
|
7257
|
-
styling: stylingConfigSchema.default({}),
|
|
7258
8151
|
theme: themeConfigSchema.default({}),
|
|
7259
8152
|
title: z2.string().default("Documentation"),
|
|
8153
|
+
toc: tocConfigSchema,
|
|
7260
8154
|
variables: variablesConfigSchema
|
|
7261
8155
|
}).strict();
|
|
7262
8156
|
|
|
@@ -7286,9 +8180,11 @@ var loadConfig = async (root, options = {}) => {
|
|
|
7286
8180
|
const sourceFile = bridge?.configFile ?? configFile;
|
|
7287
8181
|
const parsed = blumeConfigSchema.safeParse(raw ?? {});
|
|
7288
8182
|
if (!parsed.success) {
|
|
8183
|
+
const source = sourceFile && existsSync9(sourceFile) ? readFileSync6(sourceFile, "utf-8") : undefined;
|
|
7289
8184
|
const diagnostics = diagnosticsFromZod(parsed.error, {
|
|
7290
8185
|
code: "BLUME_CONFIG_INVALID",
|
|
7291
|
-
file: sourceFile ?? undefined
|
|
8186
|
+
file: sourceFile ?? undefined,
|
|
8187
|
+
source
|
|
7292
8188
|
});
|
|
7293
8189
|
throw new BlumeError(diagnostics[0] ?? {
|
|
7294
8190
|
code: "BLUME_CONFIG_INVALID",
|
|
@@ -7313,7 +8209,7 @@ var loadConfig = async (root, options = {}) => {
|
|
|
7313
8209
|
};
|
|
7314
8210
|
|
|
7315
8211
|
// src/core/navigation.ts
|
|
7316
|
-
import { extname as
|
|
8212
|
+
import { extname as extname3 } from "pathe";
|
|
7317
8213
|
var NUMERIC_PREFIX = /^(?<order>\d+)[-_.]/u;
|
|
7318
8214
|
var GROUP_FOLDER = /^\((?<label>.+)\)$/u;
|
|
7319
8215
|
var WORD_SPLIT = /[-_]/u;
|
|
@@ -7350,7 +8246,7 @@ var pageOrder = (page, filename) => {
|
|
|
7350
8246
|
if (page.meta.sidebar.order !== undefined) {
|
|
7351
8247
|
return page.meta.sidebar.order;
|
|
7352
8248
|
}
|
|
7353
|
-
if (filename.replace(
|
|
8249
|
+
if (filename.replace(extname3(filename), "") === "index") {
|
|
7354
8250
|
return Number.NEGATIVE_INFINITY;
|
|
7355
8251
|
}
|
|
7356
8252
|
return numericOrder(filename);
|
|
@@ -7442,7 +8338,7 @@ var buildFileSystemSidebar = (pages, folderMeta, sharedMeta, metaPrefix) => {
|
|
|
7442
8338
|
deprecated: page.meta.deprecated || undefined,
|
|
7443
8339
|
description: page.description,
|
|
7444
8340
|
icon: page.meta.sidebar.icon,
|
|
7445
|
-
key: segmentKey(filename.replace(
|
|
8341
|
+
key: segmentKey(filename.replace(extname3(filename), "")),
|
|
7446
8342
|
kind: "page",
|
|
7447
8343
|
label: page.meta.sidebar.label ?? page.title,
|
|
7448
8344
|
order: pageOrder(page, filename),
|
|
@@ -7641,6 +8537,8 @@ var buildContentGraph = (pages, options) => {
|
|
|
7641
8537
|
tabs: options.navigation.tabs
|
|
7642
8538
|
});
|
|
7643
8539
|
}
|
|
8540
|
+
diagnostics.push(...validateNavIcons(navigation));
|
|
8541
|
+
diagnostics.push(...validateNavStructure(navigation, pages));
|
|
7644
8542
|
return {
|
|
7645
8543
|
diagnostics,
|
|
7646
8544
|
navigation,
|
|
@@ -7652,7 +8550,7 @@ var buildContentGraph = (pages, options) => {
|
|
|
7652
8550
|
|
|
7653
8551
|
// src/core/last-modified.ts
|
|
7654
8552
|
import { execFileSync } from "node:child_process";
|
|
7655
|
-
import { relative as
|
|
8553
|
+
import { relative as relative8 } from "pathe";
|
|
7656
8554
|
var resolveLastModifiedConfig = (value) => {
|
|
7657
8555
|
if (value === false) {
|
|
7658
8556
|
return { enabled: false, source: "git" };
|
|
@@ -7692,7 +8590,7 @@ var gitLastModifiedTimes = (root, contentRoot, sourcePaths) => {
|
|
|
7692
8590
|
const byRepoPath = parseGitLog(output);
|
|
7693
8591
|
const result = new Map;
|
|
7694
8592
|
for (const sourcePath of sourcePaths) {
|
|
7695
|
-
const iso = byRepoPath.get(
|
|
8593
|
+
const iso = byRepoPath.get(relative8(gitRoot, sourcePath));
|
|
7696
8594
|
if (iso) {
|
|
7697
8595
|
result.set(sourcePath, iso);
|
|
7698
8596
|
}
|
|
@@ -7704,7 +8602,7 @@ var gitLastModifiedTimes = (root, contentRoot, sourcePaths) => {
|
|
|
7704
8602
|
};
|
|
7705
8603
|
|
|
7706
8604
|
// src/core/meta.ts
|
|
7707
|
-
import { basename as basename3, dirname as
|
|
8605
|
+
import { basename as basename3, dirname as dirname9, relative as relative9 } from "pathe";
|
|
7708
8606
|
import { glob as glob5 } from "tinyglobby";
|
|
7709
8607
|
var META_FILES = [
|
|
7710
8608
|
"**/meta.ts",
|
|
@@ -7734,7 +8632,7 @@ var discoverFolderMeta = async (contentRoot) => {
|
|
|
7734
8632
|
const shared = new Map;
|
|
7735
8633
|
const diagnostics = [];
|
|
7736
8634
|
for (const entry of loaded) {
|
|
7737
|
-
const dir =
|
|
8635
|
+
const dir = relative9(contentRoot, dirname9(entry.file));
|
|
7738
8636
|
if (!entry.ok) {
|
|
7739
8637
|
diagnostics.push({
|
|
7740
8638
|
code: "BLUME_META_LOAD_FAILED",
|
|
@@ -7759,8 +8657,9 @@ var discoverFolderMeta = async (contentRoot) => {
|
|
|
7759
8657
|
};
|
|
7760
8658
|
|
|
7761
8659
|
// src/core/sources/normalize.ts
|
|
8660
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7 } from "node:fs";
|
|
7762
8661
|
import GithubSlugger from "github-slugger";
|
|
7763
|
-
import { extname as
|
|
8662
|
+
import { extname as extname4 } from "pathe";
|
|
7764
8663
|
var NUMERIC_PREFIX2 = /^\d+[-_.]/u;
|
|
7765
8664
|
var GROUP_FOLDER2 = /^\((?<label>.+)\)$/u;
|
|
7766
8665
|
var WORD_SPLIT2 = /[-_]/u;
|
|
@@ -7769,7 +8668,7 @@ var groupLabel = (segment) => segment.match(GROUP_FOLDER2)?.groups?.label ?? nul
|
|
|
7769
8668
|
var slugify2 = (text) => text.toLowerCase().trim().replaceAll(/[^\w\s-]/gu, "").replaceAll(/[\s_]+/gu, "-").replaceAll(/-+/gu, "-").replaceAll(/^-|-$/gu, "");
|
|
7770
8669
|
var titleCase = (value) => value.split(WORD_SPLIT2).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
7771
8670
|
var mapRoute = (relativePath) => {
|
|
7772
|
-
const withoutExt = relativePath.slice(0, relativePath.length -
|
|
8671
|
+
const withoutExt = relativePath.slice(0, relativePath.length - extname4(relativePath).length);
|
|
7773
8672
|
const rawParts = withoutExt.split("/");
|
|
7774
8673
|
const segments = [];
|
|
7775
8674
|
const groups = [];
|
|
@@ -7841,6 +8740,31 @@ var extractLinks = (body) => {
|
|
|
7841
8740
|
}
|
|
7842
8741
|
return links;
|
|
7843
8742
|
};
|
|
8743
|
+
var INLINE_CODE2 = /`[^`]*`/gu;
|
|
8744
|
+
var DOUBLE_QUOTED = /"[^"]*"/gu;
|
|
8745
|
+
var JSX_OPEN = /<(?<tag>[A-Z][A-Za-z0-9]*)/gu;
|
|
8746
|
+
var extractComponentTags = (body) => {
|
|
8747
|
+
const tags = new Set;
|
|
8748
|
+
let inFence = false;
|
|
8749
|
+
for (const line of body.split(`
|
|
8750
|
+
`)) {
|
|
8751
|
+
if (CODE_FENCE2.test(line.trimStart())) {
|
|
8752
|
+
inFence = !inFence;
|
|
8753
|
+
continue;
|
|
8754
|
+
}
|
|
8755
|
+
if (inFence) {
|
|
8756
|
+
continue;
|
|
8757
|
+
}
|
|
8758
|
+
const clean = line.replaceAll(INLINE_CODE2, "").replaceAll(DOUBLE_QUOTED, "");
|
|
8759
|
+
for (const match of clean.matchAll(JSX_OPEN)) {
|
|
8760
|
+
const tag = match.groups?.tag;
|
|
8761
|
+
if (tag) {
|
|
8762
|
+
tags.add(tag);
|
|
8763
|
+
}
|
|
8764
|
+
}
|
|
8765
|
+
}
|
|
8766
|
+
return [...tags];
|
|
8767
|
+
};
|
|
7844
8768
|
var deriveTitle = (meta, headings, id2) => {
|
|
7845
8769
|
if (meta.title) {
|
|
7846
8770
|
return meta.title;
|
|
@@ -7850,18 +8774,20 @@ var deriveTitle = (meta, headings, id2) => {
|
|
|
7850
8774
|
return firstHeading.text;
|
|
7851
8775
|
}
|
|
7852
8776
|
const base = id2.split("/").pop() ?? id2;
|
|
7853
|
-
return titleCase(stripNumericPrefix(base.replace(
|
|
8777
|
+
return titleCase(stripNumericPrefix(base.replace(extname4(base), "")));
|
|
7854
8778
|
};
|
|
7855
8779
|
var withPrefix = (prefix, path) => prefix ? `${prefix}/${path}` : path;
|
|
7856
|
-
var
|
|
8780
|
+
var normalizeEntry2 = (entry, ctx) => {
|
|
7857
8781
|
const { format } = entry.body;
|
|
7858
8782
|
const ext = format === "mdx" ? ".mdx" : ".md";
|
|
7859
8783
|
const result = pageMetaSchema.safeParse(entry.data);
|
|
7860
8784
|
if (!result.success) {
|
|
8785
|
+
const source = entry.raw ?? (entry.sourcePath && existsSync10(entry.sourcePath) ? readFileSync7(entry.sourcePath, "utf-8") : undefined);
|
|
7861
8786
|
return {
|
|
7862
8787
|
diagnostics: diagnosticsFromZod(result.error, {
|
|
7863
8788
|
code: "BLUME_FRONTMATTER_INVALID",
|
|
7864
|
-
file: entry.sourcePath ?? `${ctx.source.name}:${entry.ref}
|
|
8789
|
+
file: entry.sourcePath ?? `${ctx.source.name}:${entry.ref}`,
|
|
8790
|
+
source
|
|
7865
8791
|
}),
|
|
7866
8792
|
pages: []
|
|
7867
8793
|
};
|
|
@@ -7877,6 +8803,7 @@ var normalizeEntry = (entry, ctx) => {
|
|
|
7877
8803
|
const base = {
|
|
7878
8804
|
body: staged ? { format, text: entry.raw ?? entry.body.text } : undefined,
|
|
7879
8805
|
collection: staged ? "staged" : undefined,
|
|
8806
|
+
componentsUsed: format === "mdx" ? extractComponentTags(entry.body.text) : undefined,
|
|
7880
8807
|
contentType: meta.type ?? ctx.defaultType,
|
|
7881
8808
|
description: meta.description,
|
|
7882
8809
|
editUrl: entry.editUrl,
|
|
@@ -7907,12 +8834,12 @@ var normalizeEntry = (entry, ctx) => {
|
|
|
7907
8834
|
import { join as join22 } from "pathe";
|
|
7908
8835
|
|
|
7909
8836
|
// src/core/sources/filesystem.ts
|
|
7910
|
-
import { existsSync as
|
|
8837
|
+
import { existsSync as existsSync11, watch as fsWatch } from "node:fs";
|
|
7911
8838
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
7912
|
-
import { extname as
|
|
8839
|
+
import { extname as extname5, isAbsolute as isAbsolute5, join as join14, relative as relative10, resolve as resolve6 } from "pathe";
|
|
7913
8840
|
import { glob as glob6 } from "tinyglobby";
|
|
7914
8841
|
var filesystemSource = (options) => {
|
|
7915
|
-
const contentRoot =
|
|
8842
|
+
const contentRoot = isAbsolute5(options.root) ? options.root : join14(resolve6(options.projectRoot), options.root);
|
|
7916
8843
|
const load2 = async () => {
|
|
7917
8844
|
const files = await glob6(options.include, {
|
|
7918
8845
|
absolute: true,
|
|
@@ -7923,20 +8850,20 @@ var filesystemSource = (options) => {
|
|
|
7923
8850
|
files.sort();
|
|
7924
8851
|
const entries = await Promise.all(files.map(async (file) => {
|
|
7925
8852
|
const source = await readFile10(file, "utf-8");
|
|
7926
|
-
const ext =
|
|
8853
|
+
const ext = extname5(file).toLowerCase();
|
|
7927
8854
|
const format = ext === ".mdx" ? "mdx" : "md";
|
|
7928
8855
|
const parsed = frontmatter_default(source);
|
|
7929
8856
|
return {
|
|
7930
8857
|
body: { format, text: parsed.content },
|
|
7931
8858
|
data: parsed.data,
|
|
7932
|
-
ref:
|
|
8859
|
+
ref: relative10(contentRoot, file),
|
|
7933
8860
|
sourcePath: file
|
|
7934
8861
|
};
|
|
7935
8862
|
}));
|
|
7936
8863
|
return { diagnostics: [], entries };
|
|
7937
8864
|
};
|
|
7938
8865
|
const validate = () => {
|
|
7939
|
-
if (!
|
|
8866
|
+
if (!existsSync11(contentRoot)) {
|
|
7940
8867
|
throw new BlumeError({
|
|
7941
8868
|
code: options.missingCode ?? "BLUME_CONTENT_ROOT_MISSING",
|
|
7942
8869
|
file: contentRoot,
|
|
@@ -7947,7 +8874,7 @@ var filesystemSource = (options) => {
|
|
|
7947
8874
|
}
|
|
7948
8875
|
};
|
|
7949
8876
|
const watch = (onChange) => {
|
|
7950
|
-
if (!
|
|
8877
|
+
if (!existsSync11(contentRoot)) {
|
|
7951
8878
|
return () => {};
|
|
7952
8879
|
}
|
|
7953
8880
|
const watcher = fsWatch(contentRoot, { recursive: true }, onChange);
|
|
@@ -8041,6 +8968,118 @@ var loadWithCache = async (name, cache, fetchEntries, refresh = true) => {
|
|
|
8041
8968
|
}
|
|
8042
8969
|
};
|
|
8043
8970
|
|
|
8971
|
+
// src/core/sources/github-releases.ts
|
|
8972
|
+
var DEFAULT_BASE_URL = "https://api.github.com";
|
|
8973
|
+
var DEFAULT_LIMIT = 100;
|
|
8974
|
+
var PER_PAGE = 100;
|
|
8975
|
+
var LEADING_V = /^v/iu;
|
|
8976
|
+
var NON_SLUG2 = /[^a-z0-9]+/gu;
|
|
8977
|
+
var EDGE_DASHES = /^-+|-+$/gu;
|
|
8978
|
+
var slugifyTag = (tag) => tag.toLowerCase().replaceAll(NON_SLUG2, "-").replaceAll(EDGE_DASHES, "");
|
|
8979
|
+
var githubHeaders = () => {
|
|
8980
|
+
const headers = new Headers({ Accept: "application/vnd.github+json" });
|
|
8981
|
+
const token = process.env.GITHUB_TOKEN;
|
|
8982
|
+
if (token) {
|
|
8983
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
8984
|
+
}
|
|
8985
|
+
return headers;
|
|
8986
|
+
};
|
|
8987
|
+
var releaseToEntry = (release) => {
|
|
8988
|
+
const version = release.tag_name.replace(LEADING_V, "");
|
|
8989
|
+
const title = release.name?.trim() || release.tag_name;
|
|
8990
|
+
const date = release.published_at ?? release.created_at;
|
|
8991
|
+
const category = release.prerelease ? "Prerelease" : "Release";
|
|
8992
|
+
const body = (release.body ?? "").replaceAll(`\r
|
|
8993
|
+
`, `
|
|
8994
|
+
`).trim();
|
|
8995
|
+
const data = {
|
|
8996
|
+
changelog: { category, version },
|
|
8997
|
+
date,
|
|
8998
|
+
title,
|
|
8999
|
+
type: "changelog"
|
|
9000
|
+
};
|
|
9001
|
+
const raw = frontmatter_default.stringify(`${body}
|
|
9002
|
+
`, data);
|
|
9003
|
+
const ref = `${slugifyTag(release.tag_name) || `release-${release.id}`}.md`;
|
|
9004
|
+
return {
|
|
9005
|
+
body: { format: "md", text: body },
|
|
9006
|
+
data,
|
|
9007
|
+
editUrl: release.html_url,
|
|
9008
|
+
hash: hashText(raw),
|
|
9009
|
+
lastModified: date,
|
|
9010
|
+
raw,
|
|
9011
|
+
ref
|
|
9012
|
+
};
|
|
9013
|
+
};
|
|
9014
|
+
var githubReleasesSource = (options, ctx) => {
|
|
9015
|
+
const doFetch = options.fetchImpl ?? globalThis.fetch;
|
|
9016
|
+
const base = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/u, "");
|
|
9017
|
+
const max = options.limit ?? DEFAULT_LIMIT;
|
|
9018
|
+
const cache = snapshotCache(ctx.cacheDir);
|
|
9019
|
+
let snapshot = new Map;
|
|
9020
|
+
const include = (release) => (options.drafts || !release.draft) && (options.prereleases || !release.prerelease);
|
|
9021
|
+
const fetchPage = async (page) => {
|
|
9022
|
+
const url = `${base}/repos/${options.owner}/${options.repo}/releases?per_page=${PER_PAGE}&page=${page}`;
|
|
9023
|
+
const res = await doFetch(url, { headers: githubHeaders() });
|
|
9024
|
+
if (!res.ok) {
|
|
9025
|
+
throw new Error(`${url} -> ${res.status}`);
|
|
9026
|
+
}
|
|
9027
|
+
return await res.json();
|
|
9028
|
+
};
|
|
9029
|
+
const fetchReleases = async () => {
|
|
9030
|
+
const collected = [];
|
|
9031
|
+
let page = 1;
|
|
9032
|
+
while (collected.length < max) {
|
|
9033
|
+
const batch = await fetchPage(page);
|
|
9034
|
+
collected.push(...batch.filter(include));
|
|
9035
|
+
if (batch.length < PER_PAGE) {
|
|
9036
|
+
break;
|
|
9037
|
+
}
|
|
9038
|
+
page += 1;
|
|
9039
|
+
}
|
|
9040
|
+
return collected.slice(0, max);
|
|
9041
|
+
};
|
|
9042
|
+
const load2 = async () => {
|
|
9043
|
+
try {
|
|
9044
|
+
const result = await loadWithCache(options.name, cache, async () => {
|
|
9045
|
+
const releases = await fetchReleases();
|
|
9046
|
+
return releases.map(releaseToEntry);
|
|
9047
|
+
}, ctx.refresh ?? true);
|
|
9048
|
+
snapshot = new Map(result.entries.map((entry) => [entry.ref, entry]));
|
|
9049
|
+
return result;
|
|
9050
|
+
} catch (error) {
|
|
9051
|
+
snapshot = new Map;
|
|
9052
|
+
return {
|
|
9053
|
+
diagnostics: [
|
|
9054
|
+
{
|
|
9055
|
+
code: "BLUME_SOURCE_UNAVAILABLE",
|
|
9056
|
+
message: `Source "${options.name}" could not fetch GitHub releases (${error.message}); the changelog will be empty. Set GITHUB_TOKEN to include it (required for a private repository).`,
|
|
9057
|
+
severity: "warning"
|
|
9058
|
+
}
|
|
9059
|
+
],
|
|
9060
|
+
entries: []
|
|
9061
|
+
};
|
|
9062
|
+
}
|
|
9063
|
+
};
|
|
9064
|
+
const read = async (ref) => {
|
|
9065
|
+
const cached3 = snapshot.get(ref);
|
|
9066
|
+
if (cached3) {
|
|
9067
|
+
return cached3.raw ?? cached3.body.text;
|
|
9068
|
+
}
|
|
9069
|
+
const all = await cache.read();
|
|
9070
|
+
const entry = all.find((e) => e.ref === ref);
|
|
9071
|
+
return entry?.raw ?? entry?.body.text ?? "";
|
|
9072
|
+
};
|
|
9073
|
+
return {
|
|
9074
|
+
load: load2,
|
|
9075
|
+
name: options.name,
|
|
9076
|
+
prefix: options.prefix,
|
|
9077
|
+
read,
|
|
9078
|
+
staged: true,
|
|
9079
|
+
watch: options.pollInterval ? pollingWatch(load2, options.pollInterval) : undefined
|
|
9080
|
+
};
|
|
9081
|
+
};
|
|
9082
|
+
|
|
8044
9083
|
// src/core/sources/mdx-remote.ts
|
|
8045
9084
|
var REGEX_SPECIAL = /[.*+?^${}()|[\]\\]/u;
|
|
8046
9085
|
var escapeChar = (char) => REGEX_SPECIAL.test(char) ? `\\${char}` : char;
|
|
@@ -8082,7 +9121,7 @@ var globToRegExp = (pattern) => {
|
|
|
8082
9121
|
return new RegExp(`^${source}$`, "u");
|
|
8083
9122
|
};
|
|
8084
9123
|
var matchesInclude = (ref, patterns) => patterns.some((pattern) => globToRegExp(pattern).test(ref));
|
|
8085
|
-
var
|
|
9124
|
+
var githubHeaders2 = () => {
|
|
8086
9125
|
const token = process.env.GITHUB_TOKEN;
|
|
8087
9126
|
return token ? { authorization: `Bearer ${token}` } : {};
|
|
8088
9127
|
};
|
|
@@ -8090,7 +9129,7 @@ var enumerateGithub = async (github, include, doFetch) => {
|
|
|
8090
9129
|
const { owner, repo, ref } = github;
|
|
8091
9130
|
const base = github.path.replaceAll(/^\/|\/$/gu, "");
|
|
8092
9131
|
const treeUrl = `https://api.github.com/repos/${owner}/${repo}/git/trees/${ref}?recursive=1`;
|
|
8093
|
-
const res = await doFetch(treeUrl, { headers:
|
|
9132
|
+
const res = await doFetch(treeUrl, { headers: githubHeaders2() });
|
|
8094
9133
|
if (!res.ok) {
|
|
8095
9134
|
throw new Error(`${treeUrl} -> ${res.status}`);
|
|
8096
9135
|
}
|
|
@@ -8125,7 +9164,7 @@ var mdxRemoteSource = (options, ctx) => {
|
|
|
8125
9164
|
});
|
|
8126
9165
|
};
|
|
8127
9166
|
const fetchEntry = async (item) => {
|
|
8128
|
-
const res = await doFetch(item.fetchUrl, { headers:
|
|
9167
|
+
const res = await doFetch(item.fetchUrl, { headers: githubHeaders2() });
|
|
8129
9168
|
if (!res.ok) {
|
|
8130
9169
|
throw new Error(`${item.fetchUrl} -> ${res.status}`);
|
|
8131
9170
|
}
|
|
@@ -8169,13 +9208,13 @@ var mdxRemoteSource = (options, ctx) => {
|
|
|
8169
9208
|
};
|
|
8170
9209
|
|
|
8171
9210
|
// src/core/sources/mintlify.ts
|
|
8172
|
-
import { existsSync as
|
|
9211
|
+
import { existsSync as existsSync13, watch as fsWatch2 } from "node:fs";
|
|
8173
9212
|
import { readFile as readFile13 } from "node:fs/promises";
|
|
8174
|
-
import { isAbsolute as
|
|
9213
|
+
import { isAbsolute as isAbsolute6, join as join18, relative as relative13, resolve as resolve8 } from "pathe";
|
|
8175
9214
|
import { glob as glob7 } from "tinyglobby";
|
|
8176
9215
|
|
|
8177
9216
|
// src/migrate/shared.ts
|
|
8178
|
-
import { existsSync as
|
|
9217
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
8179
9218
|
import { readFile as readFile12, writeFile as writeFile4 } from "node:fs/promises";
|
|
8180
9219
|
import { join as join16 } from "pathe";
|
|
8181
9220
|
var writeBlumeConfig = async (root, config) => {
|
|
@@ -8192,7 +9231,7 @@ var BLUME_SCRIPTS = {
|
|
|
8192
9231
|
};
|
|
8193
9232
|
var rewriteFrameworkScripts = async (root, cli, remove) => {
|
|
8194
9233
|
const pkgPath = join16(root, "package.json");
|
|
8195
|
-
if (!
|
|
9234
|
+
if (!existsSync12(pkgPath)) {
|
|
8196
9235
|
return false;
|
|
8197
9236
|
}
|
|
8198
9237
|
let pkg;
|
|
@@ -8228,7 +9267,7 @@ var rewriteFrameworkScripts = async (root, cli, remove) => {
|
|
|
8228
9267
|
var gitignoreKey = (line) => line.trim().replace(/\/+$/u, "");
|
|
8229
9268
|
var ensureGitignore = async (root, entries) => {
|
|
8230
9269
|
const path = join16(root, ".gitignore");
|
|
8231
|
-
const existing =
|
|
9270
|
+
const existing = existsSync12(path) ? await readFile12(path, "utf-8") : "";
|
|
8232
9271
|
const present = new Set(existing.split(`
|
|
8233
9272
|
`).map(gitignoreKey).filter(Boolean));
|
|
8234
9273
|
const added = entries.filter((entry) => !present.has(gitignoreKey(entry)));
|
|
@@ -8243,7 +9282,7 @@ var ensureGitignore = async (root, entries) => {
|
|
|
8243
9282
|
`, "utf-8");
|
|
8244
9283
|
return added;
|
|
8245
9284
|
};
|
|
8246
|
-
var leftoverFiles = (root, candidates) => candidates.filter((candidate) =>
|
|
9285
|
+
var leftoverFiles = (root, candidates) => candidates.filter((candidate) => existsSync12(join16(root, candidate)));
|
|
8247
9286
|
var attribute = (attrs, name) => {
|
|
8248
9287
|
const match = attrs.match(new RegExp(`\\b${name}=(?:"(?<dq>[^"]*)"|'(?<sq>[^']*)')`, "u"));
|
|
8249
9288
|
return match?.groups?.dq ?? match?.groups?.sq;
|
|
@@ -8286,7 +9325,7 @@ var findOpenTagEnd = (source, from) => {
|
|
|
8286
9325
|
}
|
|
8287
9326
|
return -1;
|
|
8288
9327
|
};
|
|
8289
|
-
var
|
|
9328
|
+
var directiveFor2 = (tag, attrs, options) => {
|
|
8290
9329
|
if (tag in options.tagDirectives) {
|
|
8291
9330
|
return options.tagDirectives[tag];
|
|
8292
9331
|
}
|
|
@@ -8316,7 +9355,7 @@ var rewriteCallouts = (source, options) => {
|
|
|
8316
9355
|
continue;
|
|
8317
9356
|
}
|
|
8318
9357
|
const attrs = source.slice(start + tag.length + 1, openEnd);
|
|
8319
|
-
const directive =
|
|
9358
|
+
const directive = directiveFor2(tag, attrs, options);
|
|
8320
9359
|
const closeTag = `</${tag}>`;
|
|
8321
9360
|
const selfClosing = attrs.trimEnd().endsWith("/");
|
|
8322
9361
|
const closeIndex = selfClosing ? openEnd : source.indexOf(closeTag, openEnd + 1);
|
|
@@ -8640,7 +9679,7 @@ var isLiteralObject = (value) => typeof value === "object" && value !== null &&
|
|
|
8640
9679
|
var asLiteralArray = (value) => Array.isArray(value) ? value : undefined;
|
|
8641
9680
|
|
|
8642
9681
|
// src/migrate/mintlify/content.ts
|
|
8643
|
-
import { dirname as
|
|
9682
|
+
import { dirname as dirname10, join as join17, relative as relative11 } from "pathe";
|
|
8644
9683
|
var CALLOUT_DIRECTIVES = {
|
|
8645
9684
|
Check: "success",
|
|
8646
9685
|
Danger: "danger",
|
|
@@ -8678,7 +9717,7 @@ var rewriteSnippetImports = (source, options) => {
|
|
|
8678
9717
|
}
|
|
8679
9718
|
const target = join17(options.root, importSource.replace(/^\/+/u, ""));
|
|
8680
9719
|
components.push(importSource.replace(/^\/+/u, ""));
|
|
8681
|
-
let rel =
|
|
9720
|
+
let rel = relative11(dirname10(options.filePath), target);
|
|
8682
9721
|
if (!rel.startsWith(".")) {
|
|
8683
9722
|
rel = `./${rel}`;
|
|
8684
9723
|
}
|
|
@@ -8868,7 +9907,7 @@ var rewriteMintlifySvgIconProps = (source) => {
|
|
|
8868
9907
|
|
|
8869
9908
|
// src/migrate/mintlify/snippets.ts
|
|
8870
9909
|
import { readFile as readFileFromDisk } from "node:fs/promises";
|
|
8871
|
-
import { dirname as
|
|
9910
|
+
import { dirname as dirname11, relative as relative12, resolve as resolve7 } from "pathe";
|
|
8872
9911
|
var MARKDOWN_SNIPPET_IMPORT = /^import\s+(?<name>[$A-Z_a-z][$\w]*)\s+from\s+["'](?<source>[^"']+\.mdx?)["'];?\s*$/gmu;
|
|
8873
9912
|
var NAMED_SNIPPET_IMPORT = /^import\s+\{(?<names>[^}]+)\}\s+from\s+["'](?<source>[^"']+\.mdx?)["'];?\s*$/gmu;
|
|
8874
9913
|
var EXPORTED_STRING_CONST = /^export\s+const\s+(?<name>[$A-Z_a-z][$\w]*)\s*=\s*(?:"(?<double>(?:\\.|[^"\\])*)"|'(?<single>(?:\\.|[^'\\])*)'|`(?<template>(?:\\.|[^`\\])*)`)\s*;?\s*$/gmu;
|
|
@@ -8878,14 +9917,14 @@ var GLOBAL_VARIABLE = /\{\{\s*(?<name>[A-Za-z0-9-]+)\s*\}\}/gu;
|
|
|
8878
9917
|
var FRONTMATTER_BLOCK = /^---\r?\n[\s\S]*?\r?\n---\r?\n?/u;
|
|
8879
9918
|
var USER_EXPORT = /^(?:export\s+)?(?:const|let|var)\s+user\s*=|^import\s+\{\s*user\s*\}/mu;
|
|
8880
9919
|
var isInsideRoot2 = (root, candidate) => {
|
|
8881
|
-
const rel =
|
|
9920
|
+
const rel = relative12(root, candidate);
|
|
8882
9921
|
return rel === "" || !rel.startsWith("..") && !rel.startsWith("/");
|
|
8883
9922
|
};
|
|
8884
|
-
var
|
|
8885
|
-
var snippetSelfClosingTagPattern = (name) => new RegExp(`<${
|
|
8886
|
-
var snippetPairedTagPattern = (name) => new RegExp(`<${
|
|
9923
|
+
var escapeRegExp2 = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
9924
|
+
var snippetSelfClosingTagPattern = (name) => new RegExp(`<${escapeRegExp2(name)}(?<attrs>[^>]*?)\\s*/>`, "gu");
|
|
9925
|
+
var snippetPairedTagPattern = (name) => new RegExp(`<${escapeRegExp2(name)}(?<attrs>[^>]*?)>[\\s\\S]*?</${escapeRegExp2(name)}>`, "gu");
|
|
8887
9926
|
var rootRelativePath = (root, file) => {
|
|
8888
|
-
const rel =
|
|
9927
|
+
const rel = relative12(root, file);
|
|
8889
9928
|
return rel ? `/${rel}` : "/";
|
|
8890
9929
|
};
|
|
8891
9930
|
var snippetCycleMessage = (root, file, trail) => {
|
|
@@ -8894,10 +9933,10 @@ var snippetCycleMessage = (root, file, trail) => {
|
|
|
8894
9933
|
return `Circular Mintlify snippet import detected: ${cycle}`;
|
|
8895
9934
|
};
|
|
8896
9935
|
var resolveSnippetPath = (options) => {
|
|
8897
|
-
const target = options.source.startsWith("/") ?
|
|
9936
|
+
const target = options.source.startsWith("/") ? resolve7(options.root, options.source.slice(1)) : resolve7(dirname11(options.filePath), options.source);
|
|
8898
9937
|
return isInsideRoot2(options.root, target) ? target : null;
|
|
8899
9938
|
};
|
|
8900
|
-
var
|
|
9939
|
+
var collectImports2 = (source) => [...source.matchAll(MARKDOWN_SNIPPET_IMPORT)].flatMap((match) => {
|
|
8901
9940
|
const name = match.groups?.name;
|
|
8902
9941
|
const importSource = match.groups?.source;
|
|
8903
9942
|
if (!(name && importSource)) {
|
|
@@ -8945,7 +9984,7 @@ var interpolateProps = (source, props) => source.replaceAll(PLACEHOLDER, (value,
|
|
|
8945
9984
|
var stripImport = (source, importText) => source.replace(importText, "").replaceAll(/\n{3,}/gu, `
|
|
8946
9985
|
|
|
8947
9986
|
`);
|
|
8948
|
-
var replacePlaceholder = (source, name, value) => source.replaceAll(new RegExp(`\\{${
|
|
9987
|
+
var replacePlaceholder = (source, name, value) => source.replaceAll(new RegExp(`\\{${escapeRegExp2(name)}\\}`, "gu"), value);
|
|
8949
9988
|
var inlineSnippetTags = (options) => {
|
|
8950
9989
|
const inline = (_value, attrs) => interpolateProps(options.snippet, parseAttributes(attrs));
|
|
8951
9990
|
return options.source.replaceAll(snippetSelfClosingTagPattern(options.name), inline).replaceAll(snippetPairedTagPattern(options.name), inline);
|
|
@@ -8989,7 +10028,7 @@ var rewriteMintlifyMarkdownSnippets = async (source, options) => {
|
|
|
8989
10028
|
});
|
|
8990
10029
|
return next === current ? current : stripImport(next, snippetImport.importText);
|
|
8991
10030
|
};
|
|
8992
|
-
const imports =
|
|
10031
|
+
const imports = collectImports2(source);
|
|
8993
10032
|
const inlineAt = async (index, current) => {
|
|
8994
10033
|
const snippetImport = imports[index];
|
|
8995
10034
|
if (!snippetImport) {
|
|
@@ -9088,11 +10127,11 @@ var MINTLIFY_SOURCE_IGNORES = [
|
|
|
9088
10127
|
"snippets/**"
|
|
9089
10128
|
];
|
|
9090
10129
|
var mintlifySource = (options) => {
|
|
9091
|
-
const contentRoot =
|
|
10130
|
+
const contentRoot = isAbsolute6(options.root) ? options.root : join18(resolve8(options.projectRoot), options.root);
|
|
9092
10131
|
const ignore = [...new Set([...options.exclude, ...MINTLIFY_SOURCE_IGNORES])];
|
|
9093
10132
|
const transform = (raw, file) => transformMintlifyContent(raw, {
|
|
9094
10133
|
filePath: file,
|
|
9095
|
-
root:
|
|
10134
|
+
root: resolve8(options.projectRoot),
|
|
9096
10135
|
variables: options.variables
|
|
9097
10136
|
});
|
|
9098
10137
|
const load2 = async () => {
|
|
@@ -9114,7 +10153,7 @@ var mintlifySource = (options) => {
|
|
|
9114
10153
|
body: { format: "mdx", text: parsed.content },
|
|
9115
10154
|
data: parsed.data,
|
|
9116
10155
|
raw: result.content,
|
|
9117
|
-
ref:
|
|
10156
|
+
ref: relative13(contentRoot, file),
|
|
9118
10157
|
sourcePath: file
|
|
9119
10158
|
};
|
|
9120
10159
|
}));
|
|
@@ -9128,7 +10167,7 @@ var mintlifySource = (options) => {
|
|
|
9128
10167
|
return { diagnostics, entries };
|
|
9129
10168
|
};
|
|
9130
10169
|
const validate = () => {
|
|
9131
|
-
if (!
|
|
10170
|
+
if (!existsSync13(contentRoot)) {
|
|
9132
10171
|
throw new BlumeError({
|
|
9133
10172
|
code: "BLUME_CONTENT_ROOT_MISSING",
|
|
9134
10173
|
file: contentRoot,
|
|
@@ -9140,11 +10179,11 @@ var mintlifySource = (options) => {
|
|
|
9140
10179
|
};
|
|
9141
10180
|
const watch = (onChange) => {
|
|
9142
10181
|
const disposers = [];
|
|
9143
|
-
if (
|
|
10182
|
+
if (existsSync13(contentRoot)) {
|
|
9144
10183
|
const watcher = fsWatch2(contentRoot, { recursive: true }, onChange);
|
|
9145
10184
|
disposers.push(() => watcher.close());
|
|
9146
10185
|
}
|
|
9147
|
-
if (options.configFile &&
|
|
10186
|
+
if (options.configFile && existsSync13(options.configFile)) {
|
|
9148
10187
|
const watcher = fsWatch2(options.configFile, onChange);
|
|
9149
10188
|
disposers.push(() => watcher.close());
|
|
9150
10189
|
}
|
|
@@ -9176,13 +10215,13 @@ import { join as join20 } from "pathe";
|
|
|
9176
10215
|
|
|
9177
10216
|
// src/core/sources/assets.ts
|
|
9178
10217
|
import { mkdir as mkdir4, writeFile as writeFile5 } from "node:fs/promises";
|
|
9179
|
-
import { extname as
|
|
10218
|
+
import { extname as extname6, join as join19 } from "pathe";
|
|
9180
10219
|
var MD_IMAGE = /!\[(?<alt>[^\]]*)\]\((?<url>[^)\s]+)\)/gu;
|
|
9181
10220
|
var REMOTE = /^https?:\/\//u;
|
|
9182
10221
|
var SAFE_EXT = /^\.[a-z0-9]+$/iu;
|
|
9183
10222
|
var extFor = (url) => {
|
|
9184
10223
|
const clean = url.split("?")[0] ?? url;
|
|
9185
|
-
const ext =
|
|
10224
|
+
const ext = extname6(clean);
|
|
9186
10225
|
return SAFE_EXT.test(ext) ? ext.toLowerCase() : ".png";
|
|
9187
10226
|
};
|
|
9188
10227
|
var materializeAssets = async (markdown, ctx) => {
|
|
@@ -9733,8 +10772,20 @@ var buildSource = (def, name, context, runtime) => {
|
|
|
9733
10772
|
name,
|
|
9734
10773
|
pollInterval: def.pollInterval,
|
|
9735
10774
|
prefix: def.prefix,
|
|
9736
|
-
properties: def.properties,
|
|
9737
|
-
publishedValue: def.publishedValue
|
|
10775
|
+
properties: def.properties,
|
|
10776
|
+
publishedValue: def.publishedValue
|
|
10777
|
+
}, sourceContext(context, name, runtime));
|
|
10778
|
+
}
|
|
10779
|
+
if (def.type === "github-releases") {
|
|
10780
|
+
return githubReleasesSource({
|
|
10781
|
+
drafts: def.drafts,
|
|
10782
|
+
limit: def.limit,
|
|
10783
|
+
name,
|
|
10784
|
+
owner: def.owner,
|
|
10785
|
+
pollInterval: def.pollInterval,
|
|
10786
|
+
prefix: def.prefix,
|
|
10787
|
+
prereleases: def.prereleases,
|
|
10788
|
+
repo: def.repo
|
|
9738
10789
|
}, sourceContext(context, name, runtime));
|
|
9739
10790
|
}
|
|
9740
10791
|
return mdxRemoteSource({
|
|
@@ -9771,12 +10822,32 @@ var resolveSources = (config, context, runtime) => {
|
|
|
9771
10822
|
};
|
|
9772
10823
|
|
|
9773
10824
|
// src/core/project-graph.ts
|
|
10825
|
+
var applyConfigOverrides = (config, overrides) => {
|
|
10826
|
+
if (!overrides) {
|
|
10827
|
+
return config;
|
|
10828
|
+
}
|
|
10829
|
+
return {
|
|
10830
|
+
...config,
|
|
10831
|
+
content: {
|
|
10832
|
+
...config.content,
|
|
10833
|
+
root: overrides.contentRoot ?? config.content.root
|
|
10834
|
+
},
|
|
10835
|
+
deployment: {
|
|
10836
|
+
...config.deployment,
|
|
10837
|
+
adapter: overrides.adapter ?? config.deployment.adapter,
|
|
10838
|
+
base: overrides.base ?? config.deployment.base,
|
|
10839
|
+
output: overrides.output ?? config.deployment.output
|
|
10840
|
+
}
|
|
10841
|
+
};
|
|
10842
|
+
};
|
|
9774
10843
|
var scanProject = async (root, options = {}) => {
|
|
9775
10844
|
const mode = options.mode ?? "dev";
|
|
9776
10845
|
const preview = options.preview ?? false;
|
|
9777
|
-
const
|
|
10846
|
+
const configResult = await loadConfig(root, {
|
|
9778
10847
|
devServerUrl: options.devServerUrl
|
|
9779
10848
|
});
|
|
10849
|
+
const { bridge } = configResult;
|
|
10850
|
+
const config = applyConfigOverrides(configResult.config, options.overrides);
|
|
9780
10851
|
const context = resolveProjectContext(root, config);
|
|
9781
10852
|
const sources = resolveSources(config, context, {
|
|
9782
10853
|
mode,
|
|
@@ -9795,7 +10866,7 @@ var scanProject = async (root, options = {}) => {
|
|
|
9795
10866
|
for (const { source, entries, diagnostics } of loaded) {
|
|
9796
10867
|
contentDiagnostics.push(...diagnostics);
|
|
9797
10868
|
for (const entry of entries) {
|
|
9798
|
-
const normalized =
|
|
10869
|
+
const normalized = normalizeEntry2(entry, {
|
|
9799
10870
|
defaultType: config.content.defaultType,
|
|
9800
10871
|
i18n: config.i18n,
|
|
9801
10872
|
source: {
|
|
@@ -9844,22 +10915,140 @@ var scanProject = async (root, options = {}) => {
|
|
|
9844
10915
|
};
|
|
9845
10916
|
};
|
|
9846
10917
|
|
|
10918
|
+
// src/cli/env.ts
|
|
10919
|
+
import { existsSync as existsSync14, readFileSync as readFileSync8 } from "node:fs";
|
|
10920
|
+
import { dirname as dirname12, join as join23, resolve as resolve9 } from "pathe";
|
|
10921
|
+
var ENV_LINE = /^\s*(?:export\s+)?(?<key>[A-Za-z_][A-Za-z0-9_]*)\s*=\s*(?<value>.*?)\s*$/u;
|
|
10922
|
+
var DOUBLE_QUOTED2 = /^"(?<body>[\s\S]*)"$/u;
|
|
10923
|
+
var SINGLE_QUOTED = /^'(?<body>[\s\S]*)'$/u;
|
|
10924
|
+
var unquote = (raw) => {
|
|
10925
|
+
const double = raw.match(DOUBLE_QUOTED2)?.groups?.body;
|
|
10926
|
+
if (double !== undefined) {
|
|
10927
|
+
return double.replaceAll("\\n", `
|
|
10928
|
+
`).replaceAll("\\t", "\t").replaceAll("\\\"", '"').replaceAll("\\\\", "\\");
|
|
10929
|
+
}
|
|
10930
|
+
const single = raw.match(SINGLE_QUOTED)?.groups?.body;
|
|
10931
|
+
if (single !== undefined) {
|
|
10932
|
+
return single;
|
|
10933
|
+
}
|
|
10934
|
+
return raw;
|
|
10935
|
+
};
|
|
10936
|
+
var parseEnv = (content) => {
|
|
10937
|
+
const env = {};
|
|
10938
|
+
for (const line of content.split(/\r?\n/u)) {
|
|
10939
|
+
if (line.trim() === "" || line.trimStart().startsWith("#")) {
|
|
10940
|
+
continue;
|
|
10941
|
+
}
|
|
10942
|
+
const groups = line.match(ENV_LINE)?.groups;
|
|
10943
|
+
if (groups?.key !== undefined && groups.value !== undefined) {
|
|
10944
|
+
env[groups.key] = unquote(groups.value);
|
|
10945
|
+
}
|
|
10946
|
+
}
|
|
10947
|
+
return env;
|
|
10948
|
+
};
|
|
10949
|
+
var applyEnv = (parsed) => {
|
|
10950
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
10951
|
+
if (!(key in process.env)) {
|
|
10952
|
+
process.env[key] = value;
|
|
10953
|
+
}
|
|
10954
|
+
}
|
|
10955
|
+
};
|
|
10956
|
+
var loadFile = (path) => {
|
|
10957
|
+
try {
|
|
10958
|
+
if (existsSync14(path)) {
|
|
10959
|
+
applyEnv(parseEnv(readFileSync8(path, "utf-8")));
|
|
10960
|
+
}
|
|
10961
|
+
} catch {}
|
|
10962
|
+
};
|
|
10963
|
+
var loadEnvFiles = (startDir) => {
|
|
10964
|
+
let dir = resolve9(startDir);
|
|
10965
|
+
let done = false;
|
|
10966
|
+
while (!done) {
|
|
10967
|
+
loadFile(join23(dir, ".env.local"));
|
|
10968
|
+
loadFile(join23(dir, ".env"));
|
|
10969
|
+
const parent = dirname12(dir);
|
|
10970
|
+
done = existsSync14(join23(dir, ".git")) || parent === dir;
|
|
10971
|
+
dir = parent;
|
|
10972
|
+
}
|
|
10973
|
+
};
|
|
10974
|
+
|
|
10975
|
+
// src/cli/internal-error.ts
|
|
10976
|
+
var ESC2 = String.fromCodePoint(27);
|
|
10977
|
+
var DIM = `${ESC2}[2m`;
|
|
10978
|
+
var RED = `${ESC2}[31m`;
|
|
10979
|
+
var BOLD = `${ESC2}[1m`;
|
|
10980
|
+
var RESET = `${ESC2}[0m`;
|
|
10981
|
+
var ISSUES_URL = "https://github.com/haydenbleasel/blume/issues";
|
|
10982
|
+
var BLUME_FRAME = /(?<abs>\/[^\s()]*\/\.blume\/[^\s()]*)/gu;
|
|
10983
|
+
var remapBlumeStack = (stack) => stack.replaceAll(BLUME_FRAME, (match) => {
|
|
10984
|
+
const marker = match.indexOf("/.blume/");
|
|
10985
|
+
return `${match.slice(marker + 1)} (generated)`;
|
|
10986
|
+
});
|
|
10987
|
+
var reportInternalError = (error) => {
|
|
10988
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
10989
|
+
const lines = [
|
|
10990
|
+
`${RED}${BOLD}BLUME_INTERNAL${RESET} An unexpected error occurred.`,
|
|
10991
|
+
` ${err.message}`
|
|
10992
|
+
];
|
|
10993
|
+
const stack = remapBlumeStack(err.stack ?? "").split(`
|
|
10994
|
+
`).slice(1, 5).map((line) => line.trim()).filter(Boolean);
|
|
10995
|
+
if (stack.length > 0) {
|
|
10996
|
+
lines.push("", `${DIM}${stack.join(`
|
|
10997
|
+
`)}${RESET}`);
|
|
10998
|
+
}
|
|
10999
|
+
lines.push("", "This is likely a bug in Blume. Please report it with the details below:", ` ${DIM}Blume: ${getBlumeVersion()}`, ` Node: ${process.version}`, ` Platform: ${process.platform} ${process.arch}${RESET}`, ` ${ISSUES_URL}`);
|
|
11000
|
+
process.stderr.write(`${lines.join(`
|
|
11001
|
+
`)}
|
|
11002
|
+
`);
|
|
11003
|
+
};
|
|
11004
|
+
|
|
11005
|
+
// src/cli/required-secrets.ts
|
|
11006
|
+
var checkRequiredSecrets = (config) => {
|
|
11007
|
+
const diagnostics = [];
|
|
11008
|
+
const requireSecret = (feature, env, note) => {
|
|
11009
|
+
if (process.env[env]) {
|
|
11010
|
+
return;
|
|
11011
|
+
}
|
|
11012
|
+
diagnostics.push({
|
|
11013
|
+
code: "BLUME_MISSING_SECRET",
|
|
11014
|
+
message: `${feature} is enabled but ${env} is not set${note ? ` (${note})` : ""}.`,
|
|
11015
|
+
severity: "warning",
|
|
11016
|
+
suggestion: `Set ${env} in .env.local for local dev, or in your host's environment for production.`
|
|
11017
|
+
});
|
|
11018
|
+
};
|
|
11019
|
+
if (config.ai.ask?.enabled) {
|
|
11020
|
+
const backend = resolveAskBackend(config.ai.ask);
|
|
11021
|
+
if (backend.kind === "gateway") {
|
|
11022
|
+
requireSecret("Ask AI (AI Gateway)", "AI_GATEWAY_API_KEY", "on Vercel the gateway can also authenticate via OIDC");
|
|
11023
|
+
} else {
|
|
11024
|
+
requireSecret("Ask AI", backend.apiKeyEnv);
|
|
11025
|
+
}
|
|
11026
|
+
}
|
|
11027
|
+
if (config.search.provider === "mixedbread") {
|
|
11028
|
+
requireSecret("Mixedbread search", "MIXEDBREAD_API_KEY");
|
|
11029
|
+
}
|
|
11030
|
+
return diagnostics;
|
|
11031
|
+
};
|
|
11032
|
+
|
|
9847
11033
|
// src/cli/prepare.ts
|
|
9848
11034
|
var prepareProject = async (options) => {
|
|
11035
|
+
loadEnvFiles(options.root);
|
|
9849
11036
|
let project;
|
|
9850
11037
|
try {
|
|
9851
11038
|
project = await scanProject(options.root, {
|
|
9852
11039
|
devServerUrl: options.devServerUrl,
|
|
9853
11040
|
mode: options.mode,
|
|
11041
|
+
overrides: options.overrides,
|
|
9854
11042
|
preview: options.preview,
|
|
9855
11043
|
refresh: options.refresh
|
|
9856
11044
|
});
|
|
9857
11045
|
} catch (error) {
|
|
9858
11046
|
if (error instanceof BlumeError) {
|
|
9859
11047
|
reportDiagnostics([error.diagnostic], options.root);
|
|
9860
|
-
|
|
11048
|
+
} else {
|
|
11049
|
+
reportInternalError(error);
|
|
9861
11050
|
}
|
|
9862
|
-
|
|
11051
|
+
process.exit(1);
|
|
9863
11052
|
}
|
|
9864
11053
|
if (options.mode === "build" && project.config.deployment.output === "static") {
|
|
9865
11054
|
const features = serverFeatures(project.config);
|
|
@@ -9887,12 +11076,102 @@ var prepareProject = async (options) => {
|
|
|
9887
11076
|
for (const warning of warnings) {
|
|
9888
11077
|
logger.warn(warning);
|
|
9889
11078
|
}
|
|
11079
|
+
reportDiagnostics(checkRequiredSecrets(project.config), options.root);
|
|
9890
11080
|
return project;
|
|
9891
11081
|
};
|
|
9892
11082
|
|
|
9893
11083
|
// src/cli/commands/build.ts
|
|
11084
|
+
var ADAPTERS = ["vercel", "node", "netlify", "cloudflare"];
|
|
11085
|
+
var emitRedirectFiles = async (config, distDir) => {
|
|
11086
|
+
const { redirects } = config;
|
|
11087
|
+
if (redirects.length === 0 || config.deployment.output !== "static") {
|
|
11088
|
+
return;
|
|
11089
|
+
}
|
|
11090
|
+
await writeFile6(join24(distDir, "blume-redirects.json"), buildRedirectManifest(redirects), "utf-8");
|
|
11091
|
+
const platformFiles = [
|
|
11092
|
+
{ content: buildNetlifyRedirects(redirects), name: "_redirects" },
|
|
11093
|
+
{ content: buildVercelConfig(redirects), name: "vercel.json" }
|
|
11094
|
+
];
|
|
11095
|
+
await Promise.all(platformFiles.map((file) => existsSync15(join24(distDir, file.name)) ? Promise.resolve() : writeFile6(join24(distDir, file.name), file.content, "utf-8")));
|
|
11096
|
+
logger.success(`Emitted redirect files for ${redirects.length} redirect(s)`);
|
|
11097
|
+
};
|
|
11098
|
+
var formatBytes = (bytes) => bytes < 1024 ? `${bytes} B` : `${(bytes / 1024).toFixed(bytes < 1024 * 100 ? 1 : 0)} kB`;
|
|
11099
|
+
var astroAssets = async (distDir, ext) => {
|
|
11100
|
+
const astroDir = join24(distDir, "_astro");
|
|
11101
|
+
if (!existsSync15(astroDir)) {
|
|
11102
|
+
return [];
|
|
11103
|
+
}
|
|
11104
|
+
const entries = await readdir(astroDir);
|
|
11105
|
+
const files = entries.filter((name) => name.endsWith(`.${ext}`));
|
|
11106
|
+
const sized = await Promise.all(files.map(async (name) => {
|
|
11107
|
+
const info = await stat(join24(astroDir, name));
|
|
11108
|
+
return { name, size: info.size };
|
|
11109
|
+
}));
|
|
11110
|
+
return sized.toSorted((a, b) => b.size - a.size);
|
|
11111
|
+
};
|
|
11112
|
+
var totalSize = (assets) => assets.reduce((sum, asset) => sum + asset.size, 0);
|
|
11113
|
+
var reportBundleSizes = async (distDir) => {
|
|
11114
|
+
const sized = await astroAssets(distDir, "js");
|
|
11115
|
+
if (sized.length === 0) {
|
|
11116
|
+
logger.info("No client JavaScript emitted — the site ships zero JS.");
|
|
11117
|
+
return;
|
|
11118
|
+
}
|
|
11119
|
+
const rows = sized.slice(0, 15).map((file) => ` ${formatBytes(file.size).padStart(8)} ${file.name}`);
|
|
11120
|
+
logger.box([
|
|
11121
|
+
`Client JavaScript — ${sized.length} file(s), ${formatBytes(totalSize(sized))} total`,
|
|
11122
|
+
"",
|
|
11123
|
+
...rows,
|
|
11124
|
+
sized.length > 15 ? ` … and ${sized.length - 15} more` : null
|
|
11125
|
+
].filter((line) => line !== null).join(`
|
|
11126
|
+
`));
|
|
11127
|
+
};
|
|
11128
|
+
var enforceBudget = async (distDir, args) => {
|
|
11129
|
+
const checks = [
|
|
11130
|
+
...args["budget-js"] ? [{ ext: "js", limitKb: Number(args["budget-js"]), name: "JavaScript" }] : [],
|
|
11131
|
+
...args["budget-css"] ? [{ ext: "css", limitKb: Number(args["budget-css"]), name: "CSS" }] : []
|
|
11132
|
+
];
|
|
11133
|
+
if (checks.length === 0) {
|
|
11134
|
+
return "skip";
|
|
11135
|
+
}
|
|
11136
|
+
let passed = true;
|
|
11137
|
+
for (const check of checks) {
|
|
11138
|
+
const total = totalSize(await astroAssets(distDir, check.ext));
|
|
11139
|
+
const limit = check.limitKb * 1024;
|
|
11140
|
+
if (total > limit) {
|
|
11141
|
+
passed = false;
|
|
11142
|
+
logger.error(`${check.name} budget exceeded: ${formatBytes(total)} > ${check.limitKb} kB`);
|
|
11143
|
+
} else {
|
|
11144
|
+
logger.success(`${check.name} budget: ${formatBytes(total)} / ${check.limitKb} kB`);
|
|
11145
|
+
}
|
|
11146
|
+
}
|
|
11147
|
+
return passed ? "pass" : "fail";
|
|
11148
|
+
};
|
|
9894
11149
|
var buildCommand = defineCommand2({
|
|
9895
11150
|
args: {
|
|
11151
|
+
adapter: {
|
|
11152
|
+
description: "Server adapter: vercel | node | netlify | cloudflare.",
|
|
11153
|
+
type: "string"
|
|
11154
|
+
},
|
|
11155
|
+
analyze: {
|
|
11156
|
+
description: "Report client JavaScript bundle sizes after the build.",
|
|
11157
|
+
type: "boolean"
|
|
11158
|
+
},
|
|
11159
|
+
base: {
|
|
11160
|
+
description: "Base path the site is served under (e.g. /docs).",
|
|
11161
|
+
type: "string"
|
|
11162
|
+
},
|
|
11163
|
+
"budget-css": {
|
|
11164
|
+
description: "Fail if total client CSS exceeds this many kB.",
|
|
11165
|
+
type: "string"
|
|
11166
|
+
},
|
|
11167
|
+
"budget-js": {
|
|
11168
|
+
description: "Fail if total client JavaScript exceeds this many kB.",
|
|
11169
|
+
type: "string"
|
|
11170
|
+
},
|
|
11171
|
+
output: {
|
|
11172
|
+
description: "Output mode: static | server.",
|
|
11173
|
+
type: "string"
|
|
11174
|
+
},
|
|
9896
11175
|
preview: {
|
|
9897
11176
|
description: "Include drafts and unpublished CMS content.",
|
|
9898
11177
|
type: "boolean"
|
|
@@ -9905,8 +11184,21 @@ var buildCommand = defineCommand2({
|
|
|
9905
11184
|
},
|
|
9906
11185
|
async run({ args }) {
|
|
9907
11186
|
const root = process.cwd();
|
|
11187
|
+
if (args.output && args.output !== "static" && args.output !== "server") {
|
|
11188
|
+
logger.error(`Invalid --output "${args.output}" (use static | server).`);
|
|
11189
|
+
process.exit(1);
|
|
11190
|
+
}
|
|
11191
|
+
if (args.adapter && !ADAPTERS.includes(args.adapter)) {
|
|
11192
|
+
logger.error(`Invalid --adapter "${args.adapter}" (use ${ADAPTERS.join(" | ")}).`);
|
|
11193
|
+
process.exit(1);
|
|
11194
|
+
}
|
|
9908
11195
|
const project = await prepareProject({
|
|
9909
11196
|
mode: "build",
|
|
11197
|
+
overrides: {
|
|
11198
|
+
adapter: args.adapter,
|
|
11199
|
+
base: args.base,
|
|
11200
|
+
output: args.output
|
|
11201
|
+
},
|
|
9910
11202
|
preview: args.preview,
|
|
9911
11203
|
root,
|
|
9912
11204
|
strict: args.strict
|
|
@@ -9916,7 +11208,7 @@ var buildCommand = defineCommand2({
|
|
|
9916
11208
|
logLevel: "info",
|
|
9917
11209
|
root: project.context.outDir
|
|
9918
11210
|
});
|
|
9919
|
-
const distDir =
|
|
11211
|
+
const distDir = join24(root, "dist");
|
|
9920
11212
|
if (project.config.search.provider === "pagefind") {
|
|
9921
11213
|
logger.start("Building search index");
|
|
9922
11214
|
const indexed = await buildSearchIndex(distDir);
|
|
@@ -9930,21 +11222,22 @@ var buildCommand = defineCommand2({
|
|
|
9930
11222
|
if (project.config.ai.llmsTxt) {
|
|
9931
11223
|
const { index, full } = await buildLlmsFiles(project);
|
|
9932
11224
|
await Promise.all([
|
|
9933
|
-
writeFile6(
|
|
9934
|
-
writeFile6(
|
|
11225
|
+
writeFile6(join24(distDir, "llms.txt"), index, "utf-8"),
|
|
11226
|
+
writeFile6(join24(distDir, "llms-full.txt"), full, "utf-8")
|
|
9935
11227
|
]);
|
|
9936
11228
|
logger.success("Generated llms.txt and llms-full.txt");
|
|
9937
11229
|
}
|
|
9938
11230
|
const sitemap = buildSitemap(project);
|
|
9939
|
-
if (sitemap && !
|
|
9940
|
-
await writeFile6(
|
|
11231
|
+
if (sitemap && !existsSync15(join24(distDir, "sitemap.xml"))) {
|
|
11232
|
+
await writeFile6(join24(distDir, "sitemap.xml"), sitemap, "utf-8");
|
|
9941
11233
|
logger.success("Generated sitemap.xml");
|
|
9942
11234
|
}
|
|
9943
11235
|
const robots = buildRobots(project);
|
|
9944
|
-
if (robots && !
|
|
9945
|
-
await writeFile6(
|
|
11236
|
+
if (robots && !existsSync15(join24(distDir, "robots.txt"))) {
|
|
11237
|
+
await writeFile6(join24(distDir, "robots.txt"), robots, "utf-8");
|
|
9946
11238
|
logger.success("Generated robots.txt");
|
|
9947
11239
|
}
|
|
11240
|
+
await emitRedirectFiles(project.config, distDir);
|
|
9948
11241
|
const { config } = project;
|
|
9949
11242
|
const features = serverFeatures(config);
|
|
9950
11243
|
logger.box([
|
|
@@ -9959,16 +11252,113 @@ var buildCommand = defineCommand2({
|
|
|
9959
11252
|
`Server features ${features.length > 0 ? features.join(", ") : "none"}`
|
|
9960
11253
|
].join(`
|
|
9961
11254
|
`));
|
|
11255
|
+
if (args.analyze) {
|
|
11256
|
+
await reportBundleSizes(distDir);
|
|
11257
|
+
}
|
|
11258
|
+
if (await enforceBudget(distDir, args) === "fail") {
|
|
11259
|
+
process.exit(1);
|
|
11260
|
+
}
|
|
9962
11261
|
logger.success(`Built to ${distDir}`);
|
|
9963
11262
|
}
|
|
9964
11263
|
});
|
|
9965
11264
|
|
|
11265
|
+
// src/cli/commands/check.ts
|
|
11266
|
+
import { existsSync as existsSync16 } from "node:fs";
|
|
11267
|
+
import { check } from "@astrojs/check";
|
|
11268
|
+
import { sync } from "astro";
|
|
11269
|
+
import { defineCommand as defineCommand3 } from "citty";
|
|
11270
|
+
import { join as join25 } from "pathe";
|
|
11271
|
+
var checkCommand = defineCommand3({
|
|
11272
|
+
args: {
|
|
11273
|
+
preview: {
|
|
11274
|
+
description: "Include drafts and unpublished CMS content.",
|
|
11275
|
+
type: "boolean"
|
|
11276
|
+
},
|
|
11277
|
+
strict: {
|
|
11278
|
+
description: "Fail on content diagnostics as well as type errors.",
|
|
11279
|
+
type: "boolean"
|
|
11280
|
+
}
|
|
11281
|
+
},
|
|
11282
|
+
meta: {
|
|
11283
|
+
description: "Type-check the docs site with astro check.",
|
|
11284
|
+
name: "check"
|
|
11285
|
+
},
|
|
11286
|
+
async run({ args }) {
|
|
11287
|
+
const root = process.cwd();
|
|
11288
|
+
const project = await prepareProject({
|
|
11289
|
+
mode: "build",
|
|
11290
|
+
preview: args.preview,
|
|
11291
|
+
root,
|
|
11292
|
+
strict: args.strict
|
|
11293
|
+
});
|
|
11294
|
+
const { outDir } = project.context;
|
|
11295
|
+
await sync({ logLevel: "warn", root: outDir });
|
|
11296
|
+
const tsconfig = join25(root, "tsconfig.json");
|
|
11297
|
+
logger.start(`Type-checking ${project.graph.pages.length} page(s)`);
|
|
11298
|
+
const failed = await check({
|
|
11299
|
+
minimumFailingSeverity: "error",
|
|
11300
|
+
minimumSeverity: "hint",
|
|
11301
|
+
root: outDir,
|
|
11302
|
+
tsconfig: existsSync16(tsconfig) ? tsconfig : undefined,
|
|
11303
|
+
watch: false
|
|
11304
|
+
});
|
|
11305
|
+
if (failed) {
|
|
11306
|
+
logger.error("Type check failed.");
|
|
11307
|
+
process.exit(1);
|
|
11308
|
+
}
|
|
11309
|
+
logger.success("No type errors.");
|
|
11310
|
+
}
|
|
11311
|
+
});
|
|
11312
|
+
|
|
9966
11313
|
// src/cli/commands/dev.ts
|
|
9967
11314
|
import { watch } from "node:fs";
|
|
9968
11315
|
import { dev } from "astro";
|
|
9969
|
-
import { defineCommand as
|
|
9970
|
-
|
|
11316
|
+
import { defineCommand as defineCommand4 } from "citty";
|
|
11317
|
+
|
|
11318
|
+
// src/astro/integration.ts
|
|
11319
|
+
var overlayServer = null;
|
|
11320
|
+
var overlayChannel = () => overlayServer?.ws ?? overlayServer?.hot;
|
|
11321
|
+
var showBlumeErrorOverlay = (diagnostics) => {
|
|
11322
|
+
const errors = diagnostics.filter((diagnostic) => diagnostic.severity === "error").map(enrichDiagnostic);
|
|
11323
|
+
const channel = overlayChannel();
|
|
11324
|
+
if (errors.length === 0 || !channel) {
|
|
11325
|
+
return;
|
|
11326
|
+
}
|
|
11327
|
+
const body = errors.map((diagnostic) => {
|
|
11328
|
+
const where = diagnostic.file ? `
|
|
11329
|
+
at ${diagnostic.file}${diagnostic.line ? `:${diagnostic.line}` : ""}` : "";
|
|
11330
|
+
const fix = diagnostic.suggestion ? `
|
|
11331
|
+
fix: ${diagnostic.suggestion}` : "";
|
|
11332
|
+
const docs = diagnostic.docsUrl ? `
|
|
11333
|
+
docs: ${diagnostic.docsUrl}` : "";
|
|
11334
|
+
return `[${diagnostic.code}] ${diagnostic.message}${where}${fix}${docs}`;
|
|
11335
|
+
}).join(`
|
|
11336
|
+
|
|
11337
|
+
`);
|
|
11338
|
+
channel.send({
|
|
11339
|
+
err: {
|
|
11340
|
+
id: errors[0]?.file,
|
|
11341
|
+
message: `Blume found ${errors.length} error(s):
|
|
11342
|
+
|
|
11343
|
+
${body}`,
|
|
11344
|
+
plugin: "blume",
|
|
11345
|
+
stack: ""
|
|
11346
|
+
},
|
|
11347
|
+
type: "error"
|
|
11348
|
+
});
|
|
11349
|
+
};
|
|
11350
|
+
|
|
11351
|
+
// src/cli/commands/dev.ts
|
|
11352
|
+
var devCommand = defineCommand4({
|
|
9971
11353
|
args: {
|
|
11354
|
+
"content-dir": {
|
|
11355
|
+
description: "Content folder to scan, overriding config (content.root).",
|
|
11356
|
+
type: "string"
|
|
11357
|
+
},
|
|
11358
|
+
debug: {
|
|
11359
|
+
description: "Verbose Astro/Vite logging for troubleshooting.",
|
|
11360
|
+
type: "boolean"
|
|
11361
|
+
},
|
|
9972
11362
|
host: { description: "Network host to bind.", type: "string" },
|
|
9973
11363
|
open: { description: "Open the browser on start.", type: "boolean" },
|
|
9974
11364
|
port: { description: "Port to listen on.", type: "string" },
|
|
@@ -9985,11 +11375,13 @@ var devCommand = defineCommand3({
|
|
|
9985
11375
|
async run({ args }) {
|
|
9986
11376
|
const root = process.cwd();
|
|
9987
11377
|
const preview = args.preview ?? false;
|
|
11378
|
+
const overrides = args["content-dir"] ? { contentRoot: args["content-dir"] } : undefined;
|
|
9988
11379
|
const port = args.port ? Number(args.port) : 4321;
|
|
9989
11380
|
const devServerUrl = `http://localhost:${port}`;
|
|
9990
11381
|
const project = await prepareProject({
|
|
9991
11382
|
devServerUrl,
|
|
9992
11383
|
mode: "dev",
|
|
11384
|
+
overrides,
|
|
9993
11385
|
preview,
|
|
9994
11386
|
root,
|
|
9995
11387
|
strict: args.strict
|
|
@@ -9998,7 +11390,7 @@ var devCommand = defineCommand3({
|
|
|
9998
11390
|
logger.info('Detected docs.json — running in Mintlify bridge mode (no migration). Run "blume migrate mintlify" to convert permanently.');
|
|
9999
11391
|
}
|
|
10000
11392
|
const server = await dev({
|
|
10001
|
-
logLevel: "info",
|
|
11393
|
+
logLevel: args.debug ? "debug" : "info",
|
|
10002
11394
|
root: project.context.outDir,
|
|
10003
11395
|
server: {
|
|
10004
11396
|
host: args.host ?? false,
|
|
@@ -10006,6 +11398,7 @@ var devCommand = defineCommand3({
|
|
|
10006
11398
|
port: args.port ? Number(args.port) : undefined
|
|
10007
11399
|
}
|
|
10008
11400
|
});
|
|
11401
|
+
showBlumeErrorOverlay(project.diagnostics);
|
|
10009
11402
|
let timer = null;
|
|
10010
11403
|
const regenerate = () => {
|
|
10011
11404
|
if (timer) {
|
|
@@ -10016,9 +11409,11 @@ var devCommand = defineCommand3({
|
|
|
10016
11409
|
const next = await scanProject(root, {
|
|
10017
11410
|
devServerUrl,
|
|
10018
11411
|
mode: "dev",
|
|
11412
|
+
overrides,
|
|
10019
11413
|
preview
|
|
10020
11414
|
});
|
|
10021
11415
|
await generateRuntime(next);
|
|
11416
|
+
showBlumeErrorOverlay(next.diagnostics);
|
|
10022
11417
|
} catch (error) {
|
|
10023
11418
|
logger.error(`Regeneration failed: ${error.message}`);
|
|
10024
11419
|
}
|
|
@@ -10050,14 +11445,20 @@ var devCommand = defineCommand3({
|
|
|
10050
11445
|
});
|
|
10051
11446
|
|
|
10052
11447
|
// src/cli/commands/doctor.ts
|
|
10053
|
-
import { defineCommand as
|
|
11448
|
+
import { defineCommand as defineCommand5 } from "citty";
|
|
10054
11449
|
var MIN_NODE_MAJOR = 20;
|
|
10055
|
-
var doctorCommand =
|
|
11450
|
+
var doctorCommand = defineCommand5({
|
|
11451
|
+
args: {
|
|
11452
|
+
json: {
|
|
11453
|
+
description: "Emit diagnostics as JSON on stdout (for CI/editors).",
|
|
11454
|
+
type: "boolean"
|
|
11455
|
+
}
|
|
11456
|
+
},
|
|
10056
11457
|
meta: {
|
|
10057
11458
|
description: "Diagnose common configuration and content problems.",
|
|
10058
11459
|
name: "doctor"
|
|
10059
11460
|
},
|
|
10060
|
-
async run() {
|
|
11461
|
+
async run({ args }) {
|
|
10061
11462
|
const root = process.cwd();
|
|
10062
11463
|
const diagnostics = [];
|
|
10063
11464
|
const nodeMajor = Number.parseInt(process.versions.node.split(".")[0] ?? "0", 10);
|
|
@@ -10089,16 +11490,25 @@ var doctorCommand = defineCommand4({
|
|
|
10089
11490
|
suggestion: 'Set deployment.adapter (e.g. "vercel").'
|
|
10090
11491
|
});
|
|
10091
11492
|
}
|
|
10092
|
-
|
|
10093
|
-
|
|
10094
|
-
|
|
11493
|
+
if (!args.json) {
|
|
11494
|
+
logger.info(`Pages: ${project.graph.pages.length}`);
|
|
11495
|
+
logger.info(`Output: ${config.deployment.output}`);
|
|
11496
|
+
logger.info(`Search: ${config.search.provider}`);
|
|
11497
|
+
}
|
|
10095
11498
|
} catch (error) {
|
|
10096
11499
|
if (error instanceof BlumeError) {
|
|
10097
11500
|
diagnostics.push(error.diagnostic);
|
|
10098
11501
|
} else {
|
|
10099
|
-
|
|
11502
|
+
reportInternalError(error);
|
|
11503
|
+
process.exit(1);
|
|
10100
11504
|
}
|
|
10101
11505
|
}
|
|
11506
|
+
if (args.json) {
|
|
11507
|
+
if (reportDiagnosticsJson(diagnostics, root)) {
|
|
11508
|
+
process.exit(1);
|
|
11509
|
+
}
|
|
11510
|
+
return;
|
|
11511
|
+
}
|
|
10102
11512
|
const hadErrors = reportDiagnostics(diagnostics, root);
|
|
10103
11513
|
if (diagnostics.length === 0) {
|
|
10104
11514
|
logger.success("No problems found.");
|
|
@@ -10111,19 +11521,40 @@ var doctorCommand = defineCommand4({
|
|
|
10111
11521
|
|
|
10112
11522
|
// src/cli/commands/eject.ts
|
|
10113
11523
|
import { readFile as readFile15, writeFile as writeFile8 } from "node:fs/promises";
|
|
10114
|
-
import { defineCommand as
|
|
10115
|
-
import { join as
|
|
11524
|
+
import { defineCommand as defineCommand6 } from "citty";
|
|
11525
|
+
import { join as join27, relative as relative15 } from "pathe";
|
|
10116
11526
|
|
|
10117
11527
|
// src/registry/eject.ts
|
|
10118
|
-
import { existsSync as
|
|
11528
|
+
import { existsSync as existsSync17 } from "node:fs";
|
|
10119
11529
|
import { cp, mkdir as mkdir5, readFile as readFile14, rm as rm2, writeFile as writeFile7 } from "node:fs/promises";
|
|
10120
|
-
import { join as
|
|
11530
|
+
import { join as join26, relative as relative14 } from "pathe";
|
|
10121
11531
|
var POSIX = (path) => path.split("\\").join("/");
|
|
11532
|
+
var askFiles = async (project, srcDir, genDir) => {
|
|
11533
|
+
const { ask } = project.config.ai;
|
|
11534
|
+
if (!ask?.enabled) {
|
|
11535
|
+
return [];
|
|
11536
|
+
}
|
|
11537
|
+
const grounded = ask.provider !== "inkeep";
|
|
11538
|
+
const files = [
|
|
11539
|
+
{
|
|
11540
|
+
content: askEndpointTemplate(resolveAskBackend(ask), grounded),
|
|
11541
|
+
path: join26(srcDir, "pages", "api", "ask.ts")
|
|
11542
|
+
}
|
|
11543
|
+
];
|
|
11544
|
+
if (grounded) {
|
|
11545
|
+
files.push({
|
|
11546
|
+
content: `${JSON.stringify(await buildAskData(project))}
|
|
11547
|
+
`,
|
|
11548
|
+
path: join26(genDir, "ask-data.json")
|
|
11549
|
+
});
|
|
11550
|
+
}
|
|
11551
|
+
return files;
|
|
11552
|
+
};
|
|
10122
11553
|
var eject = async (root) => {
|
|
10123
11554
|
const project = await scanProject(root, { mode: "build" });
|
|
10124
11555
|
const { context, config } = project;
|
|
10125
|
-
const srcDir =
|
|
10126
|
-
const genDir =
|
|
11556
|
+
const srcDir = join26(root, "src");
|
|
11557
|
+
const genDir = join26(srcDir, "generated");
|
|
10127
11558
|
const askEnabled = config.ai.ask?.enabled ?? false;
|
|
10128
11559
|
const exportPdf = config.export.pdf;
|
|
10129
11560
|
const exportEpub = config.export.epub;
|
|
@@ -10144,13 +11575,13 @@ var eject = async (root) => {
|
|
|
10144
11575
|
const needsSvelte = frameworks.has("svelte");
|
|
10145
11576
|
const relContext = {
|
|
10146
11577
|
...context,
|
|
10147
|
-
contentRoot: POSIX(
|
|
11578
|
+
contentRoot: POSIX(relative14(root, context.contentRoot)),
|
|
10148
11579
|
outDir: ".",
|
|
10149
11580
|
root: "."
|
|
10150
11581
|
};
|
|
10151
|
-
const componentsImport = context.componentsFile ? `../../${POSIX(
|
|
11582
|
+
const componentsImport = context.componentsFile ? `../../${POSIX(relative14(root, context.componentsFile))}` : null;
|
|
10152
11583
|
const relPages = pages.map((page) => ({
|
|
10153
|
-
entrypoint: POSIX(
|
|
11584
|
+
entrypoint: POSIX(relative14(root, page.entrypoint)),
|
|
10154
11585
|
pattern: page.pattern
|
|
10155
11586
|
}));
|
|
10156
11587
|
const staged = collectStaged(project);
|
|
@@ -10171,13 +11602,13 @@ var eject = async (root) => {
|
|
|
10171
11602
|
searchClientPath: "./src/generated/search-client.ts",
|
|
10172
11603
|
themePath: "./src/generated/app.css"
|
|
10173
11604
|
}),
|
|
10174
|
-
path:
|
|
11605
|
+
path: join26(root, "astro.config.mjs")
|
|
10175
11606
|
},
|
|
10176
11607
|
{
|
|
10177
11608
|
content: runtimeTsconfigTemplate(),
|
|
10178
|
-
path:
|
|
11609
|
+
path: join26(root, "tsconfig.json")
|
|
10179
11610
|
},
|
|
10180
|
-
{ content: envTemplate(), path:
|
|
11611
|
+
{ content: envTemplate(), path: join26(srcDir, "env.d.ts") },
|
|
10181
11612
|
{
|
|
10182
11613
|
content: contentConfigTemplate({
|
|
10183
11614
|
config,
|
|
@@ -10185,28 +11616,29 @@ var eject = async (root) => {
|
|
|
10185
11616
|
staged: hasStaged,
|
|
10186
11617
|
stagedBase: stagedDir
|
|
10187
11618
|
}),
|
|
10188
|
-
path:
|
|
11619
|
+
path: join26(srcDir, "content.config.ts")
|
|
10189
11620
|
},
|
|
10190
11621
|
{
|
|
10191
11622
|
content: catchAllPageTemplate({
|
|
10192
11623
|
askEnabled,
|
|
10193
11624
|
exportEpub,
|
|
10194
11625
|
exportPdf,
|
|
10195
|
-
mathEnabled: config.markdown.math
|
|
11626
|
+
mathEnabled: config.markdown.math,
|
|
11627
|
+
needsReact
|
|
10196
11628
|
}),
|
|
10197
|
-
path:
|
|
11629
|
+
path: join26(srcDir, "pages", "[...slug].astro")
|
|
10198
11630
|
},
|
|
10199
11631
|
{
|
|
10200
|
-
content:
|
|
10201
|
-
path:
|
|
11632
|
+
content: planComponentSlots(componentsImport, null).module,
|
|
11633
|
+
path: join26(genDir, "components.ts")
|
|
10202
11634
|
},
|
|
10203
11635
|
{
|
|
10204
11636
|
content: islandMapTemplate(islands.islands),
|
|
10205
|
-
path:
|
|
11637
|
+
path: join26(genDir, "islands.ts")
|
|
10206
11638
|
},
|
|
10207
11639
|
{
|
|
10208
11640
|
content: exampleMapTemplate(examples.examples),
|
|
10209
|
-
path:
|
|
11641
|
+
path: join26(genDir, "examples.ts")
|
|
10210
11642
|
},
|
|
10211
11643
|
{
|
|
10212
11644
|
content: tailwindEntryTemplate({
|
|
@@ -10218,60 +11650,57 @@ var eject = async (root) => {
|
|
|
10218
11650
|
twoslashCss: twoslashCss(),
|
|
10219
11651
|
userTheme
|
|
10220
11652
|
}),
|
|
10221
|
-
path:
|
|
11653
|
+
path: join26(genDir, "app.css")
|
|
10222
11654
|
},
|
|
10223
|
-
{ content: buildRuntimeData(project), path:
|
|
11655
|
+
{ content: buildRuntimeData(project), path: join26(genDir, "data.json") },
|
|
10224
11656
|
{
|
|
10225
11657
|
content: `${JSON.stringify(rawMarkdown)}
|
|
10226
11658
|
`,
|
|
10227
|
-
path:
|
|
11659
|
+
path: join26(genDir, "raw-markdown.json")
|
|
10228
11660
|
},
|
|
10229
11661
|
{
|
|
10230
11662
|
content: rawMarkdownEndpointTemplate(),
|
|
10231
|
-
path:
|
|
11663
|
+
path: join26(srcDir, "pages", "[...slug].md.ts")
|
|
10232
11664
|
},
|
|
10233
11665
|
{
|
|
10234
11666
|
content: rawMarkdownEndpointTemplate(),
|
|
10235
|
-
path:
|
|
11667
|
+
path: join26(srcDir, "pages", "[...slug].mdx.ts")
|
|
10236
11668
|
}
|
|
10237
11669
|
];
|
|
10238
11670
|
if (askEnabled) {
|
|
10239
|
-
files.push(
|
|
10240
|
-
content: askEndpointTemplate(resolveAskBackend(config.ai.ask)),
|
|
10241
|
-
path: join24(srcDir, "pages", "api", "ask.ts")
|
|
10242
|
-
});
|
|
11671
|
+
files.push(...await askFiles(project, srcDir, genDir));
|
|
10243
11672
|
}
|
|
10244
11673
|
if (config.seo.og.enabled) {
|
|
10245
11674
|
files.push({
|
|
10246
|
-
content: ogEndpointTemplate(customOgRoutes(pages, config.title
|
|
10247
|
-
path:
|
|
11675
|
+
content: ogEndpointTemplate(customOgRoutes(pages, config.title)),
|
|
11676
|
+
path: join26(srcDir, "pages", "og", "[...slug].png.ts")
|
|
10248
11677
|
});
|
|
10249
11678
|
}
|
|
10250
11679
|
if (!routeIsTaken(pages, project.graph.pages, "/404")) {
|
|
10251
11680
|
files.push({
|
|
10252
11681
|
content: notFoundPageTemplate(),
|
|
10253
|
-
path:
|
|
11682
|
+
path: join26(srcDir, "pages", "404.astro")
|
|
10254
11683
|
});
|
|
10255
11684
|
}
|
|
10256
11685
|
files.push({
|
|
10257
11686
|
content: searchClientTemplate(config),
|
|
10258
|
-
path:
|
|
11687
|
+
path: join26(genDir, "search-client.ts")
|
|
10259
11688
|
});
|
|
10260
11689
|
if (servesStaticIndex(config.search.provider)) {
|
|
10261
11690
|
const documents = await buildSearchDocuments(project);
|
|
10262
11691
|
files.push({
|
|
10263
11692
|
content: `${JSON.stringify(documents)}
|
|
10264
11693
|
`,
|
|
10265
|
-
path:
|
|
11694
|
+
path: join26(genDir, "search.json")
|
|
10266
11695
|
}, {
|
|
10267
11696
|
content: searchEndpointTemplate(),
|
|
10268
|
-
path:
|
|
11697
|
+
path: join26(srcDir, "pages", "blume-search.json.ts")
|
|
10269
11698
|
});
|
|
10270
11699
|
}
|
|
10271
11700
|
if (config.search.provider === "mixedbread") {
|
|
10272
11701
|
files.push({
|
|
10273
11702
|
content: mixedbreadSearchEndpointTemplate(config.search.mixedbread?.storeId ?? ""),
|
|
10274
|
-
path:
|
|
11703
|
+
path: join26(srcDir, "pages", "api", "search.ts")
|
|
10275
11704
|
});
|
|
10276
11705
|
}
|
|
10277
11706
|
const feeds = buildRssFeeds(project);
|
|
@@ -10280,10 +11709,10 @@ var eject = async (root) => {
|
|
|
10280
11709
|
files.push({
|
|
10281
11710
|
content: `${JSON.stringify(feedXml)}
|
|
10282
11711
|
`,
|
|
10283
|
-
path:
|
|
11712
|
+
path: join26(genDir, "rss.json")
|
|
10284
11713
|
}, {
|
|
10285
11714
|
content: rssEndpointTemplate(),
|
|
10286
|
-
path:
|
|
11715
|
+
path: join26(srcDir, "pages", "[section]", "rss.xml.ts")
|
|
10287
11716
|
});
|
|
10288
11717
|
}
|
|
10289
11718
|
if (hasReferences(config)) {
|
|
@@ -10295,27 +11724,27 @@ var eject = async (root) => {
|
|
|
10295
11724
|
for (const file of references.files) {
|
|
10296
11725
|
files.push({
|
|
10297
11726
|
content: file.content,
|
|
10298
|
-
path:
|
|
11727
|
+
path: join26(srcDir, "pages", file.pagePath)
|
|
10299
11728
|
});
|
|
10300
11729
|
}
|
|
10301
11730
|
}
|
|
10302
11731
|
files.push(...islands.islands.map((island) => ({
|
|
10303
11732
|
content: islandWrapperTemplate(island),
|
|
10304
|
-
path:
|
|
11733
|
+
path: join26(genDir, "islands", `${island.name}.astro`)
|
|
10305
11734
|
})), ...examples.examples.map((example) => ({
|
|
10306
11735
|
content: exampleWrapperTemplate(example),
|
|
10307
|
-
path:
|
|
11736
|
+
path: join26(genDir, "examples", `${exampleSlug(example.path)}.astro`)
|
|
10308
11737
|
})));
|
|
10309
11738
|
for (const [entryId, content] of staged) {
|
|
10310
|
-
files.push({ content, path:
|
|
11739
|
+
files.push({ content, path: join26(root, stagedDir, entryId) });
|
|
10311
11740
|
}
|
|
10312
11741
|
await Promise.all(files.map(async (file) => {
|
|
10313
|
-
await mkdir5(
|
|
11742
|
+
await mkdir5(join26(file.path, ".."), { recursive: true });
|
|
10314
11743
|
await writeFile7(file.path, file.content, "utf-8");
|
|
10315
11744
|
}));
|
|
10316
|
-
const assetsSrc =
|
|
10317
|
-
if (
|
|
10318
|
-
await cp(assetsSrc,
|
|
11745
|
+
const assetsSrc = join26(context.outDir, "public", "blume-assets");
|
|
11746
|
+
if (existsSync17(assetsSrc)) {
|
|
11747
|
+
await cp(assetsSrc, join26(root, "public", "blume-assets"), {
|
|
10319
11748
|
recursive: true
|
|
10320
11749
|
});
|
|
10321
11750
|
}
|
|
@@ -10325,7 +11754,7 @@ var eject = async (root) => {
|
|
|
10325
11754
|
|
|
10326
11755
|
// src/cli/commands/eject.ts
|
|
10327
11756
|
var updatePackageScripts = async (root) => {
|
|
10328
|
-
const pkgPath =
|
|
11757
|
+
const pkgPath = join27(root, "package.json");
|
|
10329
11758
|
let pkg;
|
|
10330
11759
|
try {
|
|
10331
11760
|
pkg = JSON.parse(await readFile15(pkgPath, "utf-8"));
|
|
@@ -10342,7 +11771,7 @@ var updatePackageScripts = async (root) => {
|
|
|
10342
11771
|
await writeFile8(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
10343
11772
|
`, "utf-8");
|
|
10344
11773
|
};
|
|
10345
|
-
var ejectCommand =
|
|
11774
|
+
var ejectCommand = defineCommand6({
|
|
10346
11775
|
args: {
|
|
10347
11776
|
yes: { description: "Skip the confirmation prompt.", type: "boolean" }
|
|
10348
11777
|
},
|
|
@@ -10361,7 +11790,7 @@ var ejectCommand = defineCommand5({
|
|
|
10361
11790
|
await updatePackageScripts(root);
|
|
10362
11791
|
logger.success(`Ejected ${files.length} file(s):`);
|
|
10363
11792
|
for (const file of files) {
|
|
10364
|
-
process.stdout.write(` ${
|
|
11793
|
+
process.stdout.write(` ${relative15(root, file)}
|
|
10365
11794
|
`);
|
|
10366
11795
|
}
|
|
10367
11796
|
logger.box(`Your project is now a standalone Astro app.
|
|
@@ -10374,10 +11803,10 @@ The blume package remains importable.`);
|
|
|
10374
11803
|
});
|
|
10375
11804
|
|
|
10376
11805
|
// src/cli/commands/init.ts
|
|
10377
|
-
import { existsSync as
|
|
11806
|
+
import { existsSync as existsSync18 } from "node:fs";
|
|
10378
11807
|
import { mkdir as mkdir6, writeFile as writeFile9 } from "node:fs/promises";
|
|
10379
|
-
import { defineCommand as
|
|
10380
|
-
import { basename as basename4, dirname as
|
|
11808
|
+
import { defineCommand as defineCommand7 } from "citty";
|
|
11809
|
+
import { basename as basename4, dirname as dirname13, join as join28 } from "pathe";
|
|
10381
11810
|
var toPackageName = (raw) => raw.toLowerCase().replaceAll(/[^a-z0-9._-]+/gu, "-").replaceAll(/^[-_.]+|[-_.]+$/gu, "") || "docs";
|
|
10382
11811
|
var packageTemplate = (name, version) => `{
|
|
10383
11812
|
"name": ${JSON.stringify(name)},
|
|
@@ -10393,41 +11822,130 @@ var packageTemplate = (name, version) => `{
|
|
|
10393
11822
|
}
|
|
10394
11823
|
}
|
|
10395
11824
|
`;
|
|
10396
|
-
var
|
|
11825
|
+
var TEMPLATES = ["docs", "api", "sdk", "changelog"];
|
|
11826
|
+
var PACKAGE_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
|
|
11827
|
+
var configFor = (extra) => `import { defineConfig } from "blume";
|
|
10397
11828
|
|
|
10398
11829
|
export default defineConfig({
|
|
10399
11830
|
title: "My Docs",
|
|
10400
|
-
description: "Documentation powered by Blume."
|
|
11831
|
+
description: "Documentation powered by Blume.",${extra}
|
|
10401
11832
|
});
|
|
10402
11833
|
`;
|
|
10403
|
-
var
|
|
10404
|
-
title:
|
|
10405
|
-
description:
|
|
11834
|
+
var page = (title, description, body) => `---
|
|
11835
|
+
title: ${title}
|
|
11836
|
+
description: ${description}
|
|
11837
|
+
---
|
|
11838
|
+
|
|
11839
|
+
${body}
|
|
11840
|
+
`;
|
|
11841
|
+
var STARTERS = {
|
|
11842
|
+
api: {
|
|
11843
|
+
config: configFor(`
|
|
11844
|
+
openapi: {
|
|
11845
|
+
enabled: true,
|
|
11846
|
+
route: "/api",
|
|
11847
|
+
sources: [
|
|
11848
|
+
{
|
|
11849
|
+
label: "Petstore",
|
|
11850
|
+
spec: "https://petstore3.swagger.io/api/v3/openapi.json",
|
|
11851
|
+
},
|
|
11852
|
+
],
|
|
11853
|
+
},`),
|
|
11854
|
+
files: (dir) => [
|
|
11855
|
+
{
|
|
11856
|
+
content: page("API Reference", "Explore the API.", "# API Reference\n\nYour OpenAPI spec renders at [`/api`](/api). Point `openapi.sources` at your own spec in `blume.config.ts`."),
|
|
11857
|
+
path: join28(dir, "index.mdx")
|
|
11858
|
+
}
|
|
11859
|
+
]
|
|
11860
|
+
},
|
|
11861
|
+
changelog: {
|
|
11862
|
+
config: configFor(`
|
|
11863
|
+
navigation: {
|
|
11864
|
+
tabs: [
|
|
11865
|
+
{ label: "Docs", path: "/" },
|
|
11866
|
+
{ label: "Changelog", path: "/changelog" },
|
|
11867
|
+
],
|
|
11868
|
+
},`),
|
|
11869
|
+
files: (dir) => [
|
|
11870
|
+
{
|
|
11871
|
+
content: page("Introduction", "Welcome to your new Blume docs.", "# Introduction\n\nWrite your docs here, and log releases under `changelog/`."),
|
|
11872
|
+
path: join28(dir, "index.mdx")
|
|
11873
|
+
},
|
|
11874
|
+
{
|
|
11875
|
+
content: `---
|
|
11876
|
+
title: v1.0.0
|
|
11877
|
+
type: changelog
|
|
11878
|
+
date: 2026-01-01
|
|
10406
11879
|
---
|
|
10407
11880
|
|
|
10408
|
-
|
|
11881
|
+
The first release. Edit \`${dir}/changelog/v1-0-0.mdx\` or add new entries beside it.
|
|
11882
|
+
`,
|
|
11883
|
+
path: join28(dir, "changelog", "v1-0-0.mdx")
|
|
11884
|
+
}
|
|
11885
|
+
]
|
|
11886
|
+
},
|
|
11887
|
+
docs: {
|
|
11888
|
+
config: configFor(""),
|
|
11889
|
+
files: (dir) => [
|
|
11890
|
+
{
|
|
11891
|
+
content: page("Introduction", "Welcome to your new Blume docs.", `# Introduction
|
|
10409
11892
|
|
|
10410
11893
|
Welcome to **Blume** — markdown-first docs powered by Astro and Vite.
|
|
10411
11894
|
|
|
10412
|
-
Edit
|
|
10413
|
-
|
|
11895
|
+
Edit \`${dir}/index.mdx\` to get started, then run \`blume dev\`.`),
|
|
11896
|
+
path: join28(dir, "index.mdx")
|
|
11897
|
+
}
|
|
11898
|
+
]
|
|
11899
|
+
},
|
|
11900
|
+
sdk: {
|
|
11901
|
+
config: configFor(""),
|
|
11902
|
+
files: (dir) => [
|
|
11903
|
+
{
|
|
11904
|
+
content: page("Introduction", "Get started with the SDK.", `# Introduction
|
|
11905
|
+
|
|
11906
|
+
Install the SDK and make your first call. See [Installation](/installation).`),
|
|
11907
|
+
path: join28(dir, "index.mdx")
|
|
11908
|
+
},
|
|
11909
|
+
{
|
|
11910
|
+
content: page("Installation", "Install the SDK.", "# Installation\n\n```package-install\nyour-sdk\n```"),
|
|
11911
|
+
path: join28(dir, "installation.mdx")
|
|
11912
|
+
}
|
|
11913
|
+
]
|
|
11914
|
+
}
|
|
11915
|
+
};
|
|
11916
|
+
var commandsFor = (pm) => ({
|
|
11917
|
+
dev: pm === "npm" ? "npm run dev" : `${pm} dev`,
|
|
11918
|
+
install: `${pm} install`
|
|
11919
|
+
});
|
|
10414
11920
|
var writeFileSafe = async (path, content) => {
|
|
10415
|
-
if (
|
|
11921
|
+
if (existsSync18(path)) {
|
|
10416
11922
|
logger.info(`Skipped existing ${path}`);
|
|
10417
11923
|
return false;
|
|
10418
11924
|
}
|
|
10419
|
-
await mkdir6(
|
|
11925
|
+
await mkdir6(dirname13(path), { recursive: true });
|
|
10420
11926
|
await writeFile9(path, content, "utf-8");
|
|
10421
11927
|
logger.success(`Created ${path}`);
|
|
10422
11928
|
return true;
|
|
10423
11929
|
};
|
|
10424
|
-
var initCommand =
|
|
11930
|
+
var initCommand = defineCommand7({
|
|
10425
11931
|
args: {
|
|
10426
11932
|
"content-dir": {
|
|
10427
11933
|
default: "docs",
|
|
10428
11934
|
description: "Content directory.",
|
|
10429
11935
|
type: "string"
|
|
10430
11936
|
},
|
|
11937
|
+
eject: {
|
|
11938
|
+
description: "Eject to a standalone Astro project after scaffolding.",
|
|
11939
|
+
type: "boolean"
|
|
11940
|
+
},
|
|
11941
|
+
"package-manager": {
|
|
11942
|
+
description: "Package manager for the next-steps hint (npm|pnpm|yarn|bun).",
|
|
11943
|
+
type: "string"
|
|
11944
|
+
},
|
|
11945
|
+
template: {
|
|
11946
|
+
description: "Starter template: docs | api | sdk | changelog.",
|
|
11947
|
+
type: "string"
|
|
11948
|
+
},
|
|
10431
11949
|
yes: { description: "Skip prompts.", type: "boolean" }
|
|
10432
11950
|
},
|
|
10433
11951
|
meta: {
|
|
@@ -10437,34 +11955,65 @@ var initCommand = defineCommand6({
|
|
|
10437
11955
|
async run({ args }) {
|
|
10438
11956
|
const root = process.cwd();
|
|
10439
11957
|
const contentDir = args["content-dir"] ?? "docs";
|
|
10440
|
-
const
|
|
10441
|
-
|
|
10442
|
-
|
|
11958
|
+
const template = args.template ?? "docs";
|
|
11959
|
+
if (!TEMPLATES.includes(template)) {
|
|
11960
|
+
logger.error(`Unknown template "${args.template}" (use ${TEMPLATES.join(" | ")}).`);
|
|
11961
|
+
process.exit(1);
|
|
11962
|
+
}
|
|
11963
|
+
const pm = args["package-manager"] ?? "npm";
|
|
11964
|
+
if (!PACKAGE_MANAGERS.includes(pm)) {
|
|
11965
|
+
logger.error(`Unknown package manager "${args["package-manager"]}" (use ${PACKAGE_MANAGERS.join(" | ")}).`);
|
|
11966
|
+
process.exit(1);
|
|
11967
|
+
}
|
|
11968
|
+
const starter = STARTERS[template];
|
|
11969
|
+
const createdPackage = await writeFileSafe(join28(root, "package.json"), packageTemplate(toPackageName(basename4(root)), getBlumeVersion()));
|
|
11970
|
+
await writeFileSafe(join28(root, "blume.config.ts"), starter.config);
|
|
11971
|
+
await Promise.all(starter.files(contentDir).map((file) => writeFileSafe(join28(root, file.path), file.content)));
|
|
11972
|
+
const commands = commandsFor(pm);
|
|
11973
|
+
if (args.eject) {
|
|
11974
|
+
try {
|
|
11975
|
+
await eject(root);
|
|
11976
|
+
logger.success("Ejected to a standalone Astro project.");
|
|
11977
|
+
logger.box(`Next steps:
|
|
11978
|
+
|
|
11979
|
+
${commands.install}
|
|
11980
|
+
npx astro dev
|
|
11981
|
+
`);
|
|
11982
|
+
} catch (error) {
|
|
11983
|
+
logger.warn(`Scaffolded, but eject failed: ${error.message}`);
|
|
11984
|
+
logger.box(`Next steps:
|
|
11985
|
+
|
|
11986
|
+
${commands.install}
|
|
11987
|
+
blume eject --yes
|
|
11988
|
+
`);
|
|
11989
|
+
}
|
|
11990
|
+
return;
|
|
11991
|
+
}
|
|
10443
11992
|
const nextSteps = createdPackage ? `Next steps:
|
|
10444
11993
|
|
|
10445
|
-
|
|
10446
|
-
|
|
11994
|
+
${commands.install}
|
|
11995
|
+
${commands.dev}
|
|
10447
11996
|
` : `Next steps:
|
|
10448
11997
|
|
|
10449
|
-
|
|
11998
|
+
${commands.dev}
|
|
10450
11999
|
`;
|
|
10451
12000
|
logger.box(nextSteps);
|
|
10452
12001
|
}
|
|
10453
12002
|
});
|
|
10454
12003
|
|
|
10455
12004
|
// src/cli/commands/migrate.ts
|
|
10456
|
-
import { defineCommand as
|
|
12005
|
+
import { defineCommand as defineCommand8 } from "citty";
|
|
10457
12006
|
|
|
10458
12007
|
// src/migrate/fumadocs/index.ts
|
|
10459
|
-
import { existsSync as
|
|
12008
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
10460
12009
|
import { mkdir as mkdir8, readFile as readFile17, rename as rename3, rm as rm3, writeFile as writeFile11 } from "node:fs/promises";
|
|
10461
|
-
import { dirname as
|
|
12010
|
+
import { dirname as dirname16, join as join31, relative as relative16 } from "pathe";
|
|
10462
12011
|
import { glob as glob8 } from "tinyglobby";
|
|
10463
12012
|
|
|
10464
12013
|
// src/migrate/fumadocs/config.ts
|
|
10465
|
-
import { existsSync as
|
|
12014
|
+
import { existsSync as existsSync19 } from "node:fs";
|
|
10466
12015
|
import { readFile as readFile16 } from "node:fs/promises";
|
|
10467
|
-
import { basename as basename5, dirname as
|
|
12016
|
+
import { basename as basename5, dirname as dirname14, join as join29 } from "pathe";
|
|
10468
12017
|
var SOURCE_FILES = [
|
|
10469
12018
|
"lib/source.ts",
|
|
10470
12019
|
"app/source.ts",
|
|
@@ -10494,10 +12043,10 @@ var GENERIC_NAMES = new Set([
|
|
|
10494
12043
|
var gitRepoRoot = (start) => {
|
|
10495
12044
|
let dir = start;
|
|
10496
12045
|
for (;; ) {
|
|
10497
|
-
if (
|
|
12046
|
+
if (existsSync19(join29(dir, ".git"))) {
|
|
10498
12047
|
return dir;
|
|
10499
12048
|
}
|
|
10500
|
-
const parent =
|
|
12049
|
+
const parent = dirname14(dir);
|
|
10501
12050
|
if (parent === dir) {
|
|
10502
12051
|
return null;
|
|
10503
12052
|
}
|
|
@@ -10506,8 +12055,8 @@ var gitRepoRoot = (start) => {
|
|
|
10506
12055
|
};
|
|
10507
12056
|
var bareName = (name) => name.includes("/") ? name.slice(name.lastIndexOf("/") + 1) : name;
|
|
10508
12057
|
var readTitle = async (root) => {
|
|
10509
|
-
const packageJson =
|
|
10510
|
-
if (!
|
|
12058
|
+
const packageJson = join29(root, "package.json");
|
|
12059
|
+
if (!existsSync19(packageJson)) {
|
|
10511
12060
|
return "Documentation";
|
|
10512
12061
|
}
|
|
10513
12062
|
try {
|
|
@@ -10532,8 +12081,8 @@ var readTitle = async (root) => {
|
|
|
10532
12081
|
};
|
|
10533
12082
|
var scrapeBaseUrl = async (root) => {
|
|
10534
12083
|
for (const candidate of SOURCE_FILES) {
|
|
10535
|
-
const file =
|
|
10536
|
-
if (!
|
|
12084
|
+
const file = join29(root, candidate);
|
|
12085
|
+
if (!existsSync19(file)) {
|
|
10537
12086
|
continue;
|
|
10538
12087
|
}
|
|
10539
12088
|
const base = BASE_URL.exec(await readFile16(file, "utf-8"))?.groups?.base;
|
|
@@ -10565,9 +12114,9 @@ var loadFumadocsConfig = async (root) => {
|
|
|
10565
12114
|
};
|
|
10566
12115
|
|
|
10567
12116
|
// src/migrate/fumadocs/content.ts
|
|
10568
|
-
import { existsSync as
|
|
12117
|
+
import { existsSync as existsSync20 } from "node:fs";
|
|
10569
12118
|
import { readFile as readFileFromDisk2 } from "node:fs/promises";
|
|
10570
|
-
import { dirname as
|
|
12119
|
+
import { dirname as dirname15, resolve as resolve10 } from "pathe";
|
|
10571
12120
|
var FUMADOCS_IMPORT = /^import\s+[\s\S]*?\s+from\s+["']fumadocs-(?:ui|core|mdx)(?:\/[^"']*)?["'];?[ \t]*\n?/gmu;
|
|
10572
12121
|
var stripFumadocsImports = (source) => {
|
|
10573
12122
|
const stripped = source.replace(FUMADOCS_IMPORT, "");
|
|
@@ -10768,12 +12317,12 @@ var inlineFumadocsIncludes = async (source, options) => {
|
|
|
10768
12317
|
if (!rawPath) {
|
|
10769
12318
|
continue;
|
|
10770
12319
|
}
|
|
10771
|
-
const target =
|
|
12320
|
+
const target = resolve10(dirname15(options.filePath), rawPath);
|
|
10772
12321
|
if (seen.has(target)) {
|
|
10773
12322
|
warnings.push(`Circular <include> "${rawPath}" — left as-is.`);
|
|
10774
12323
|
continue;
|
|
10775
12324
|
}
|
|
10776
|
-
if (!
|
|
12325
|
+
if (!existsSync20(target)) {
|
|
10777
12326
|
warnings.push(`<include> target "${rawPath}" not found — left as-is.`);
|
|
10778
12327
|
continue;
|
|
10779
12328
|
}
|
|
@@ -10805,9 +12354,9 @@ var normalizeFumadocsPageMeta = (value) => {
|
|
|
10805
12354
|
};
|
|
10806
12355
|
|
|
10807
12356
|
// src/migrate/fumadocs/groups.ts
|
|
10808
|
-
import { existsSync as
|
|
12357
|
+
import { existsSync as existsSync21, statSync as statSync2 } from "node:fs";
|
|
10809
12358
|
import { mkdir as mkdir7, rename as rename2, writeFile as writeFile10 } from "node:fs/promises";
|
|
10810
|
-
import { basename as basename6, join as
|
|
12359
|
+
import { basename as basename6, join as join30 } from "pathe";
|
|
10811
12360
|
|
|
10812
12361
|
// src/migrate/fumadocs/meta.ts
|
|
10813
12362
|
var SEPARATOR = /^---(?<label>.*)---$/u;
|
|
@@ -10953,12 +12502,12 @@ var isDirectory = (path) => {
|
|
|
10953
12502
|
};
|
|
10954
12503
|
var resolveEntry = (docsDir, name) => {
|
|
10955
12504
|
for (const ext of PAGE_EXTS) {
|
|
10956
|
-
const file =
|
|
10957
|
-
if (
|
|
12505
|
+
const file = join30(docsDir, `${name}${ext}`);
|
|
12506
|
+
if (existsSync21(file)) {
|
|
10958
12507
|
return { kind: "file", path: file };
|
|
10959
12508
|
}
|
|
10960
12509
|
}
|
|
10961
|
-
const folder =
|
|
12510
|
+
const folder = join30(docsDir, name);
|
|
10962
12511
|
return isDirectory(folder) ? { kind: "folder", path: folder } : null;
|
|
10963
12512
|
};
|
|
10964
12513
|
var humanize2 = (name) => name.split(WORD_SPLIT3).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
@@ -10993,8 +12542,8 @@ var moveItemIntoGroup = async (item, docsDir, groupDir, label, warnings) => {
|
|
|
10993
12542
|
warnings.push(`Sidebar entry "${item.name}" in section "${label}" matched no page or folder; skipped.`);
|
|
10994
12543
|
return null;
|
|
10995
12544
|
}
|
|
10996
|
-
const dest =
|
|
10997
|
-
if (
|
|
12545
|
+
const dest = join30(groupDir, basename6(resolved.path));
|
|
12546
|
+
if (existsSync21(dest)) {
|
|
10998
12547
|
warnings.push(`Skipped moving "${item.name}" into section "${label}" (target already exists).`);
|
|
10999
12548
|
return null;
|
|
11000
12549
|
}
|
|
@@ -11021,7 +12570,7 @@ var reshapeSection = async (section, docsDir, order, warnings) => {
|
|
|
11021
12570
|
}
|
|
11022
12571
|
return;
|
|
11023
12572
|
}
|
|
11024
|
-
const groupDir =
|
|
12573
|
+
const groupDir = join30(docsDir, `(${section.label})`);
|
|
11025
12574
|
const sectionKeys = [];
|
|
11026
12575
|
for (const item of section.items) {
|
|
11027
12576
|
const key = await moveItemIntoGroup(item, docsDir, groupDir, section.label, warnings);
|
|
@@ -11034,7 +12583,7 @@ var reshapeSection = async (section, docsDir, order, warnings) => {
|
|
|
11034
12583
|
}
|
|
11035
12584
|
order.push(section.label);
|
|
11036
12585
|
if (sectionKeys.length > 1) {
|
|
11037
|
-
await writeFile10(
|
|
12586
|
+
await writeFile10(join30(groupDir, "meta.ts"), renderMetaModule({ pages: sectionKeys }), "utf-8");
|
|
11038
12587
|
}
|
|
11039
12588
|
};
|
|
11040
12589
|
var reshapeFumadocsGroups = async (structure, docsDir) => {
|
|
@@ -11066,9 +12615,9 @@ var FUMADOCS_LEFTOVERS = [
|
|
|
11066
12615
|
"app"
|
|
11067
12616
|
];
|
|
11068
12617
|
var movePage = async (abs, base, root) => {
|
|
11069
|
-
const rel =
|
|
11070
|
-
const dest =
|
|
11071
|
-
if (
|
|
12618
|
+
const rel = relative16(base, abs);
|
|
12619
|
+
const dest = join31(root, "docs", rel);
|
|
12620
|
+
if (existsSync22(dest)) {
|
|
11072
12621
|
return {
|
|
11073
12622
|
includeWarnings: [],
|
|
11074
12623
|
moved: 0,
|
|
@@ -11087,7 +12636,7 @@ var movePage = async (abs, base, root) => {
|
|
|
11087
12636
|
const parsed = frontmatter_default(text);
|
|
11088
12637
|
const { data, removed } = normalizeFumadocsPageMeta(parsed.data);
|
|
11089
12638
|
const content = Object.keys(data).length > 0 ? frontmatter_default.stringify(parsed.content, data) : parsed.content;
|
|
11090
|
-
await mkdir8(
|
|
12639
|
+
await mkdir8(dirname16(dest), { recursive: true });
|
|
11091
12640
|
await writeFile11(dest, content, "utf-8");
|
|
11092
12641
|
await rm3(abs, { force: true });
|
|
11093
12642
|
return {
|
|
@@ -11102,35 +12651,35 @@ var writeMeta = async (dest, meta, rel, warnings) => {
|
|
|
11102
12651
|
if (Object.keys(meta).length === 0) {
|
|
11103
12652
|
return warnings;
|
|
11104
12653
|
}
|
|
11105
|
-
if (
|
|
12654
|
+
if (existsSync22(dest)) {
|
|
11106
12655
|
return [...warnings, `Skipped ${rel} (target already exists)`];
|
|
11107
12656
|
}
|
|
11108
|
-
await mkdir8(
|
|
12657
|
+
await mkdir8(dirname16(dest), { recursive: true });
|
|
11109
12658
|
await writeFile11(dest, renderMetaModule(meta), "utf-8");
|
|
11110
12659
|
return warnings;
|
|
11111
12660
|
};
|
|
11112
12661
|
var convertMeta = async (abs, base, root) => {
|
|
11113
|
-
const rel =
|
|
12662
|
+
const rel = relative16(base, abs);
|
|
11114
12663
|
const raw = await readFile17(abs, "utf-8");
|
|
11115
12664
|
let parsed;
|
|
11116
12665
|
try {
|
|
11117
12666
|
parsed = JSON.parse(raw);
|
|
11118
12667
|
} catch {
|
|
11119
|
-
const dest2 =
|
|
11120
|
-
if (
|
|
12668
|
+
const dest2 = join31(root, "docs", rel);
|
|
12669
|
+
if (existsSync22(dest2)) {
|
|
11121
12670
|
return [`Skipped ${rel} (target already exists)`];
|
|
11122
12671
|
}
|
|
11123
|
-
await mkdir8(
|
|
12672
|
+
await mkdir8(dirname16(dest2), { recursive: true });
|
|
11124
12673
|
await rename3(abs, dest2);
|
|
11125
12674
|
return [
|
|
11126
12675
|
`Could not parse ${rel}; moved as-is — convert it to meta.ts by hand.`
|
|
11127
12676
|
];
|
|
11128
12677
|
}
|
|
11129
|
-
const dir =
|
|
11130
|
-
const docsDir =
|
|
11131
|
-
const dest =
|
|
12678
|
+
const dir = dirname16(rel) === "." ? "" : dirname16(rel);
|
|
12679
|
+
const docsDir = join31(root, "docs", dir);
|
|
12680
|
+
const dest = join31(docsDir, "meta.ts");
|
|
11132
12681
|
const structure = parseFumadocsPages(parsed.pages);
|
|
11133
|
-
if (structure.hasSections && !
|
|
12682
|
+
if (structure.hasSections && !existsSync22(dest)) {
|
|
11134
12683
|
const self = translateFumadocsSelfMeta(parsed);
|
|
11135
12684
|
const reshape = await reshapeFumadocsGroups(structure, docsDir);
|
|
11136
12685
|
const meta2 = { ...self.meta };
|
|
@@ -11177,8 +12726,8 @@ var summarizePages = (results) => {
|
|
|
11177
12726
|
};
|
|
11178
12727
|
};
|
|
11179
12728
|
var cleanupSourceDirs = async (root) => {
|
|
11180
|
-
const docs =
|
|
11181
|
-
if (
|
|
12729
|
+
const docs = join31(root, "content", "docs");
|
|
12730
|
+
if (existsSync22(docs)) {
|
|
11182
12731
|
const remaining = await glob8(["**/*"], { cwd: docs, dot: true });
|
|
11183
12732
|
if (remaining.length > 0) {
|
|
11184
12733
|
return [
|
|
@@ -11187,8 +12736,8 @@ var cleanupSourceDirs = async (root) => {
|
|
|
11187
12736
|
}
|
|
11188
12737
|
await rm3(docs, { force: true, recursive: true });
|
|
11189
12738
|
}
|
|
11190
|
-
const content =
|
|
11191
|
-
if (
|
|
12739
|
+
const content = join31(root, "content");
|
|
12740
|
+
if (existsSync22(content)) {
|
|
11192
12741
|
const remaining = await glob8(["**/*"], { cwd: content, dot: true });
|
|
11193
12742
|
if (remaining.length === 0) {
|
|
11194
12743
|
await rm3(content, { force: true, recursive: true });
|
|
@@ -11198,8 +12747,8 @@ var cleanupSourceDirs = async (root) => {
|
|
|
11198
12747
|
};
|
|
11199
12748
|
var migrateFumadocsProject = async (root) => {
|
|
11200
12749
|
const { config, warnings: configWarnings } = await loadFumadocsConfig(root);
|
|
11201
|
-
const base =
|
|
11202
|
-
if (!
|
|
12750
|
+
const base = join31(root, SOURCE_DIR);
|
|
12751
|
+
if (!existsSync22(base)) {
|
|
11203
12752
|
await writeBlumeConfig(root, config);
|
|
11204
12753
|
return {
|
|
11205
12754
|
moved: 0,
|
|
@@ -11257,9 +12806,9 @@ var migrateFumadocsProject = async (root) => {
|
|
|
11257
12806
|
};
|
|
11258
12807
|
|
|
11259
12808
|
// src/migrate/mintlify/index.ts
|
|
11260
|
-
import { existsSync as
|
|
12809
|
+
import { existsSync as existsSync23 } from "node:fs";
|
|
11261
12810
|
import { mkdir as mkdir9, readFile as readFile18, rename as rename4, rm as rm4, writeFile as writeFile12 } from "node:fs/promises";
|
|
11262
|
-
import { dirname as
|
|
12811
|
+
import { dirname as dirname17, join as join32 } from "pathe";
|
|
11263
12812
|
import { glob as glob9 } from "tinyglobby";
|
|
11264
12813
|
var prune = (value) => {
|
|
11265
12814
|
if (Array.isArray(value)) {
|
|
@@ -11289,7 +12838,7 @@ var writeBlumeConfig2 = async (root, config) => {
|
|
|
11289
12838
|
|
|
11290
12839
|
export default defineConfig(${JSON.stringify(prune(config), null, 2)});
|
|
11291
12840
|
`;
|
|
11292
|
-
await writeFile12(
|
|
12841
|
+
await writeFile12(join32(root, "blume.config.ts"), body, "utf-8");
|
|
11293
12842
|
};
|
|
11294
12843
|
var relocateAssets = async (root, refs) => {
|
|
11295
12844
|
const segments = new Set;
|
|
@@ -11304,23 +12853,23 @@ var relocateAssets = async (root, refs) => {
|
|
|
11304
12853
|
}
|
|
11305
12854
|
const moved = [];
|
|
11306
12855
|
for (const segment of segments) {
|
|
11307
|
-
const source =
|
|
11308
|
-
if (!
|
|
12856
|
+
const source = join32(root, segment);
|
|
12857
|
+
if (!existsSync23(source) || segment === "public") {
|
|
11309
12858
|
continue;
|
|
11310
12859
|
}
|
|
11311
|
-
const dest =
|
|
11312
|
-
if (
|
|
12860
|
+
const dest = join32(root, "public", segment);
|
|
12861
|
+
if (existsSync23(dest)) {
|
|
11313
12862
|
continue;
|
|
11314
12863
|
}
|
|
11315
|
-
await mkdir9(
|
|
12864
|
+
await mkdir9(join32(root, "public"), { recursive: true });
|
|
11316
12865
|
await rename4(source, dest);
|
|
11317
12866
|
moved.push(segment);
|
|
11318
12867
|
}
|
|
11319
12868
|
return moved;
|
|
11320
12869
|
};
|
|
11321
12870
|
var cleanupSnippets = async (root, kept, warnings) => {
|
|
11322
|
-
const dir =
|
|
11323
|
-
if (!
|
|
12871
|
+
const dir = join32(root, "snippets");
|
|
12872
|
+
if (!existsSync23(dir)) {
|
|
11324
12873
|
return;
|
|
11325
12874
|
}
|
|
11326
12875
|
const markdown = await glob9(["**/*.{md,mdx}"], { absolute: true, cwd: dir });
|
|
@@ -11357,9 +12906,9 @@ var assetRefs = (config) => {
|
|
|
11357
12906
|
};
|
|
11358
12907
|
var migrateMintlifyProject = async (root) => {
|
|
11359
12908
|
const warnings = [];
|
|
11360
|
-
const configFile =
|
|
12909
|
+
const configFile = existsSync23(join32(root, "docs.json")) ? join32(root, "docs.json") : join32(root, "mint.json");
|
|
11361
12910
|
let config;
|
|
11362
|
-
if (
|
|
12911
|
+
if (existsSync23(configFile)) {
|
|
11363
12912
|
config = await loadMintlifyConfig(root, configFile);
|
|
11364
12913
|
const spec = JSON.parse(await readFile18(configFile, "utf-8"));
|
|
11365
12914
|
const i18n = mintlifyI18n(spec);
|
|
@@ -11399,7 +12948,7 @@ var migrateMintlifyProject = async (root) => {
|
|
|
11399
12948
|
variables
|
|
11400
12949
|
});
|
|
11401
12950
|
if (result.content !== raw) {
|
|
11402
|
-
await mkdir9(
|
|
12951
|
+
await mkdir9(dirname17(file), { recursive: true });
|
|
11403
12952
|
await writeFile12(file, result.content, "utf-8");
|
|
11404
12953
|
}
|
|
11405
12954
|
for (const key of result.removed) {
|
|
@@ -11436,9 +12985,9 @@ var migrateMintlifyProject = async (root) => {
|
|
|
11436
12985
|
};
|
|
11437
12986
|
|
|
11438
12987
|
// src/migrate/nextra/index.ts
|
|
11439
|
-
import { existsSync as
|
|
12988
|
+
import { existsSync as existsSync24 } from "node:fs";
|
|
11440
12989
|
import { mkdir as mkdir10, readFile as readFile19, rename as rename5, rm as rm5, writeFile as writeFile13 } from "node:fs/promises";
|
|
11441
|
-
import { basename as basename7, dirname as
|
|
12990
|
+
import { basename as basename7, dirname as dirname18, extname as extname7, join as join33, relative as relative17 } from "pathe";
|
|
11442
12991
|
import { glob as glob10 } from "tinyglobby";
|
|
11443
12992
|
|
|
11444
12993
|
// src/migrate/nextra/content.ts
|
|
@@ -11668,13 +13217,13 @@ var indexFolders = (base, pageFiles, metaFiles) => {
|
|
|
11668
13217
|
let current = normalizeDir(dir);
|
|
11669
13218
|
allDirs.add(current);
|
|
11670
13219
|
while (current !== "") {
|
|
11671
|
-
current = normalizeDir(
|
|
13220
|
+
current = normalizeDir(dirname18(current));
|
|
11672
13221
|
allDirs.add(current);
|
|
11673
13222
|
}
|
|
11674
13223
|
};
|
|
11675
13224
|
for (const abs of pageFiles) {
|
|
11676
|
-
const rel =
|
|
11677
|
-
const dir = normalizeDir(
|
|
13225
|
+
const rel = relative17(base, abs);
|
|
13226
|
+
const dir = normalizeDir(dirname18(rel));
|
|
11678
13227
|
const slug = basename7(rel).replace(/\.mdx?$/u, "");
|
|
11679
13228
|
const folder = pagesByDir.get(dir) ?? new Map;
|
|
11680
13229
|
folder.set(slug, abs);
|
|
@@ -11682,14 +13231,14 @@ var indexFolders = (base, pageFiles, metaFiles) => {
|
|
|
11682
13231
|
registerDir(dir);
|
|
11683
13232
|
}
|
|
11684
13233
|
for (const abs of metaFiles) {
|
|
11685
|
-
registerDir(normalizeDir(
|
|
13234
|
+
registerDir(normalizeDir(dirname18(relative17(base, abs))));
|
|
11686
13235
|
}
|
|
11687
13236
|
const childDirs = new Map;
|
|
11688
13237
|
for (const dir of allDirs) {
|
|
11689
13238
|
if (dir === "") {
|
|
11690
13239
|
continue;
|
|
11691
13240
|
}
|
|
11692
|
-
const parent = normalizeDir(
|
|
13241
|
+
const parent = normalizeDir(dirname18(dir));
|
|
11693
13242
|
const children = childDirs.get(parent) ?? new Set;
|
|
11694
13243
|
children.add(basename7(dir));
|
|
11695
13244
|
childDirs.set(parent, children);
|
|
@@ -11707,7 +13256,7 @@ var planMetas = (metas, index) => {
|
|
|
11707
13256
|
warnings: []
|
|
11708
13257
|
};
|
|
11709
13258
|
for (const meta of metas) {
|
|
11710
|
-
const dir = normalizeDir(
|
|
13259
|
+
const dir = normalizeDir(dirname18(meta.rel));
|
|
11711
13260
|
const entries = parseNextraMeta(meta.raw, meta.ext);
|
|
11712
13261
|
if (!entries) {
|
|
11713
13262
|
plan.unparseableMetas.push({ abs: meta.abs, rel: meta.rel });
|
|
@@ -11720,7 +13269,7 @@ var planMetas = (metas, index) => {
|
|
|
11720
13269
|
plan.metaByDir.set(dir, conversion.folderMeta);
|
|
11721
13270
|
plan.consumedMetas.push(meta.abs);
|
|
11722
13271
|
for (const [slug, title] of Object.entries(conversion.folderTitles)) {
|
|
11723
|
-
plan.folderTitleByDir.set(normalizeDir(
|
|
13272
|
+
plan.folderTitleByDir.set(normalizeDir(join33(dir, slug)), title);
|
|
11724
13273
|
}
|
|
11725
13274
|
for (const [slug, label] of Object.entries(conversion.pageLabels)) {
|
|
11726
13275
|
const pageAbs = index.pagesByDir.get(dir)?.get(slug);
|
|
@@ -11744,9 +13293,9 @@ var planMetas = (metas, index) => {
|
|
|
11744
13293
|
return plan;
|
|
11745
13294
|
};
|
|
11746
13295
|
var movePage2 = async (abs, options) => {
|
|
11747
|
-
const rel =
|
|
11748
|
-
const dest =
|
|
11749
|
-
if (
|
|
13296
|
+
const rel = relative17(options.base, abs);
|
|
13297
|
+
const dest = join33(options.root, "docs", rel);
|
|
13298
|
+
if (existsSync24(dest)) {
|
|
11750
13299
|
return { moved: 0, removed: [], skipped: rel, unsupported: [] };
|
|
11751
13300
|
}
|
|
11752
13301
|
const raw = await readFile19(abs, "utf-8");
|
|
@@ -11755,7 +13304,7 @@ var movePage2 = async (abs, options) => {
|
|
|
11755
13304
|
const parsed = frontmatter_default(text);
|
|
11756
13305
|
const { data, removed } = normalizeNextraPageMeta(parsed.data, options.overrides.get(abs) ?? {});
|
|
11757
13306
|
const content = Object.keys(data).length > 0 ? frontmatter_default.stringify(parsed.content, data) : parsed.content;
|
|
11758
|
-
await mkdir10(
|
|
13307
|
+
await mkdir10(dirname18(dest), { recursive: true });
|
|
11759
13308
|
await writeFile13(dest, content, "utf-8");
|
|
11760
13309
|
await rm5(abs, { force: true });
|
|
11761
13310
|
return { moved: 1, removed, skipped: null, unsupported };
|
|
@@ -11798,8 +13347,8 @@ var writeFolderMetas = async (root, plan) => {
|
|
|
11798
13347
|
if (Object.keys(finalMeta).length === 0) {
|
|
11799
13348
|
return;
|
|
11800
13349
|
}
|
|
11801
|
-
const dest =
|
|
11802
|
-
await mkdir10(
|
|
13350
|
+
const dest = join33(root, "docs", dir, "meta.ts");
|
|
13351
|
+
await mkdir10(dirname18(dest), { recursive: true });
|
|
11803
13352
|
await writeFile13(dest, `import { defineMeta } from "blume";
|
|
11804
13353
|
|
|
11805
13354
|
export default defineMeta(${JSON.stringify(finalMeta, null, 2)});
|
|
@@ -11809,12 +13358,12 @@ export default defineMeta(${JSON.stringify(finalMeta, null, 2)});
|
|
|
11809
13358
|
var relocateUnparseableMetas = async (root, metas) => {
|
|
11810
13359
|
const warnings = [];
|
|
11811
13360
|
await Promise.all(metas.map(async ({ abs, rel }) => {
|
|
11812
|
-
const dest =
|
|
11813
|
-
if (
|
|
13361
|
+
const dest = join33(root, "docs", rel);
|
|
13362
|
+
if (existsSync24(dest)) {
|
|
11814
13363
|
warnings.push(`Skipped ${rel} (target already exists)`);
|
|
11815
13364
|
return;
|
|
11816
13365
|
}
|
|
11817
|
-
await mkdir10(
|
|
13366
|
+
await mkdir10(dirname18(dest), { recursive: true });
|
|
11818
13367
|
await rename5(abs, dest);
|
|
11819
13368
|
warnings.push(`Could not parse ${rel}; moved as-is — convert it to meta.ts by hand.`);
|
|
11820
13369
|
}));
|
|
@@ -11822,7 +13371,7 @@ var relocateUnparseableMetas = async (root, metas) => {
|
|
|
11822
13371
|
};
|
|
11823
13372
|
var buildConfig = (tabs) => tabs.length > 0 ? { navigation: { tabs }, title: "Documentation" } : { title: "Documentation" };
|
|
11824
13373
|
var migrateNextraProject = async (root) => {
|
|
11825
|
-
const sourceDir = SOURCE_DIRS.find((dir) =>
|
|
13374
|
+
const sourceDir = SOURCE_DIRS.find((dir) => existsSync24(join33(root, dir)));
|
|
11826
13375
|
if (!sourceDir) {
|
|
11827
13376
|
await writeBlumeConfig(root, { title: "Documentation" });
|
|
11828
13377
|
return {
|
|
@@ -11832,7 +13381,7 @@ var migrateNextraProject = async (root) => {
|
|
|
11832
13381
|
]
|
|
11833
13382
|
};
|
|
11834
13383
|
}
|
|
11835
|
-
const base =
|
|
13384
|
+
const base = join33(root, sourceDir);
|
|
11836
13385
|
const pageFiles = await glob10([PAGE_GLOB2], {
|
|
11837
13386
|
absolute: true,
|
|
11838
13387
|
cwd: base,
|
|
@@ -11846,9 +13395,9 @@ var migrateNextraProject = async (root) => {
|
|
|
11846
13395
|
const index = indexFolders(base, pageFiles, metaFiles);
|
|
11847
13396
|
const metas = await Promise.all(metaFiles.map(async (abs) => ({
|
|
11848
13397
|
abs,
|
|
11849
|
-
ext:
|
|
13398
|
+
ext: extname7(abs),
|
|
11850
13399
|
raw: await readFile19(abs, "utf-8"),
|
|
11851
|
-
rel:
|
|
13400
|
+
rel: relative17(base, abs)
|
|
11852
13401
|
})));
|
|
11853
13402
|
const plan = planMetas(metas, index);
|
|
11854
13403
|
const moves = await Promise.all(pageFiles.map((abs) => movePage2(abs, { base, overrides: plan.pageOverrides, root })));
|
|
@@ -11873,15 +13422,15 @@ var migrateNextraProject = async (root) => {
|
|
|
11873
13422
|
};
|
|
11874
13423
|
|
|
11875
13424
|
// src/migrate/starlight/index.ts
|
|
11876
|
-
import { existsSync as
|
|
13425
|
+
import { existsSync as existsSync26 } from "node:fs";
|
|
11877
13426
|
import { readFile as readFile21, writeFile as writeFile14 } from "node:fs/promises";
|
|
11878
|
-
import { join as
|
|
13427
|
+
import { join as join35 } from "pathe";
|
|
11879
13428
|
import { glob as glob11 } from "tinyglobby";
|
|
11880
13429
|
|
|
11881
13430
|
// src/migrate/starlight/config.ts
|
|
11882
|
-
import { existsSync as
|
|
13431
|
+
import { existsSync as existsSync25 } from "node:fs";
|
|
11883
13432
|
import { readFile as readFile20 } from "node:fs/promises";
|
|
11884
|
-
import { join as
|
|
13433
|
+
import { join as join34 } from "pathe";
|
|
11885
13434
|
var CONFIG_FILES = [
|
|
11886
13435
|
"astro.config.mjs",
|
|
11887
13436
|
"astro.config.mts",
|
|
@@ -11912,7 +13461,7 @@ var extractStarlightOptions = (source) => {
|
|
|
11912
13461
|
return isLiteralObject(parsed) ? parsed : "unparseable";
|
|
11913
13462
|
};
|
|
11914
13463
|
var loadStarlightConfig = async (root) => {
|
|
11915
|
-
const file = CONFIG_FILES.map((name) =>
|
|
13464
|
+
const file = CONFIG_FILES.map((name) => join34(root, name)).find((path) => existsSync25(path));
|
|
11916
13465
|
if (!file) {
|
|
11917
13466
|
return {
|
|
11918
13467
|
options: {},
|
|
@@ -12155,9 +13704,6 @@ var mapStarlightConfig = (options, warnings) => {
|
|
|
12155
13704
|
}
|
|
12156
13705
|
}
|
|
12157
13706
|
const social = mapSocial(options.social);
|
|
12158
|
-
if (Object.keys(social.socials).length > 0) {
|
|
12159
|
-
config.footer = { socials: social.socials };
|
|
12160
|
-
}
|
|
12161
13707
|
const github = mapEditLink(options.editLink) ?? social.github;
|
|
12162
13708
|
if (github) {
|
|
12163
13709
|
config.github = github;
|
|
@@ -12344,8 +13890,8 @@ var migrateStarlightProject = async (root) => {
|
|
|
12344
13890
|
config.i18n = i18n;
|
|
12345
13891
|
warnings.push(`Mapped ${i18n.locales.length} locale(s) to i18n (default: ${i18n.defaultLocale}); review the locale labels.`);
|
|
12346
13892
|
}
|
|
12347
|
-
const base =
|
|
12348
|
-
if (!
|
|
13893
|
+
const base = join35(root, CONTENT_DIR);
|
|
13894
|
+
if (!existsSync26(base)) {
|
|
12349
13895
|
await writeBlumeConfig(root, config);
|
|
12350
13896
|
return {
|
|
12351
13897
|
moved: 0,
|
|
@@ -12399,7 +13945,7 @@ var migrators = {
|
|
|
12399
13945
|
};
|
|
12400
13946
|
|
|
12401
13947
|
// src/cli/commands/migrate.ts
|
|
12402
|
-
var makeMigrateCommand = (source) =>
|
|
13948
|
+
var makeMigrateCommand = (source) => defineCommand8({
|
|
12403
13949
|
meta: {
|
|
12404
13950
|
description: `Migrate a ${source} project to Blume.`,
|
|
12405
13951
|
name: source
|
|
@@ -12419,7 +13965,7 @@ var makeMigrateCommand = (source) => defineCommand7({
|
|
|
12419
13965
|
logger.box("Review blume.config.ts and run `blume dev`.");
|
|
12420
13966
|
}
|
|
12421
13967
|
});
|
|
12422
|
-
var migrateCommand =
|
|
13968
|
+
var migrateCommand = defineCommand8({
|
|
12423
13969
|
meta: {
|
|
12424
13970
|
description: "Migrate from another docs tool to Blume.",
|
|
12425
13971
|
name: "migrate"
|
|
@@ -12433,11 +13979,11 @@ var migrateCommand = defineCommand7({
|
|
|
12433
13979
|
});
|
|
12434
13980
|
|
|
12435
13981
|
// src/cli/commands/preview.ts
|
|
12436
|
-
import { existsSync as
|
|
13982
|
+
import { existsSync as existsSync27 } from "node:fs";
|
|
12437
13983
|
import { preview } from "astro";
|
|
12438
|
-
import { defineCommand as
|
|
12439
|
-
import { join as
|
|
12440
|
-
var previewCommand =
|
|
13984
|
+
import { defineCommand as defineCommand9 } from "citty";
|
|
13985
|
+
import { join as join36 } from "pathe";
|
|
13986
|
+
var previewCommand = defineCommand9({
|
|
12441
13987
|
args: {
|
|
12442
13988
|
host: { description: "Network host to bind.", type: "string" },
|
|
12443
13989
|
port: { description: "Port to listen on.", type: "string" }
|
|
@@ -12450,7 +13996,7 @@ var previewCommand = defineCommand8({
|
|
|
12450
13996
|
const root = process.cwd();
|
|
12451
13997
|
const { config } = await loadConfig(root);
|
|
12452
13998
|
const context = resolveProjectContext(root, config);
|
|
12453
|
-
if (!
|
|
13999
|
+
if (!existsSync27(join36(context.outDir, "astro.config.mjs"))) {
|
|
12454
14000
|
logger.error("No build found. Run `blume build` first.");
|
|
12455
14001
|
process.exit(1);
|
|
12456
14002
|
}
|
|
@@ -12467,9 +14013,9 @@ var previewCommand = defineCommand8({
|
|
|
12467
14013
|
|
|
12468
14014
|
// src/cli/commands/sync.ts
|
|
12469
14015
|
import { rm as rm6 } from "node:fs/promises";
|
|
12470
|
-
import { defineCommand as
|
|
12471
|
-
import { join as
|
|
12472
|
-
var syncCommand =
|
|
14016
|
+
import { defineCommand as defineCommand10 } from "citty";
|
|
14017
|
+
import { join as join37 } from "pathe";
|
|
14018
|
+
var syncCommand = defineCommand10({
|
|
12473
14019
|
args: {
|
|
12474
14020
|
force: {
|
|
12475
14021
|
description: "Clear the source cache before refetching.",
|
|
@@ -12490,7 +14036,7 @@ var syncCommand = defineCommand9({
|
|
|
12490
14036
|
if (args.force) {
|
|
12491
14037
|
const { config } = await loadConfig(root);
|
|
12492
14038
|
const context = resolveProjectContext(root, config);
|
|
12493
|
-
await rm6(
|
|
14039
|
+
await rm6(join37(context.outDir, "cache"), { force: true, recursive: true });
|
|
12494
14040
|
logger.info("Cleared source cache.");
|
|
12495
14041
|
}
|
|
12496
14042
|
await prepareProject({
|
|
@@ -12505,13 +14051,13 @@ var syncCommand = defineCommand9({
|
|
|
12505
14051
|
});
|
|
12506
14052
|
|
|
12507
14053
|
// src/cli/commands/validate.ts
|
|
12508
|
-
import { existsSync as
|
|
12509
|
-
import { defineCommand as
|
|
12510
|
-
import { join as
|
|
14054
|
+
import { existsSync as existsSync29 } from "node:fs";
|
|
14055
|
+
import { defineCommand as defineCommand11 } from "citty";
|
|
14056
|
+
import { join as join39 } from "pathe";
|
|
12511
14057
|
|
|
12512
14058
|
// src/core/links.ts
|
|
12513
|
-
import { existsSync as
|
|
12514
|
-
import { join as
|
|
14059
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
14060
|
+
import { join as join38 } from "pathe";
|
|
12515
14061
|
var HTTP = /^https?:\/\//iu;
|
|
12516
14062
|
var PROTOCOL_RELATIVE = /^\/\//u;
|
|
12517
14063
|
var SCHEME = /^[a-z][a-z0-9+.-]*:/iu;
|
|
@@ -12550,8 +14096,8 @@ var toRoute = (path) => {
|
|
|
12550
14096
|
};
|
|
12551
14097
|
var buildAnchorIndex = (pages) => {
|
|
12552
14098
|
const anchors = new Map;
|
|
12553
|
-
for (const
|
|
12554
|
-
anchors.set(
|
|
14099
|
+
for (const page2 of pages) {
|
|
14100
|
+
anchors.set(page2.route, new Set(page2.headings.map((heading) => heading.slug)));
|
|
12555
14101
|
}
|
|
12556
14102
|
return anchors;
|
|
12557
14103
|
};
|
|
@@ -12571,7 +14117,7 @@ var checkPathLink = (resolved, fragment, target, site, ctx) => {
|
|
|
12571
14117
|
if (ctx.publicDir === null) {
|
|
12572
14118
|
return "asset-unchecked";
|
|
12573
14119
|
}
|
|
12574
|
-
if (
|
|
14120
|
+
if (existsSync28(join38(ctx.publicDir, resolved))) {
|
|
12575
14121
|
return null;
|
|
12576
14122
|
}
|
|
12577
14123
|
return {
|
|
@@ -12670,11 +14216,11 @@ var checkExternalLinks = async (refs) => {
|
|
|
12670
14216
|
}
|
|
12671
14217
|
return diagnostics;
|
|
12672
14218
|
};
|
|
12673
|
-
var classifyLink = (
|
|
14219
|
+
var classifyLink = (page2, link, ctx, onExternal) => {
|
|
12674
14220
|
const { target } = link;
|
|
12675
14221
|
const site = {
|
|
12676
14222
|
column: link.column,
|
|
12677
|
-
file:
|
|
14223
|
+
file: page2.sourcePath ?? page2.id,
|
|
12678
14224
|
line: link.line
|
|
12679
14225
|
};
|
|
12680
14226
|
if (HTTP.test(target) || PROTOCOL_RELATIVE.test(target)) {
|
|
@@ -12695,9 +14241,9 @@ var classifyLink = (page, link, ctx, onExternal) => {
|
|
|
12695
14241
|
rawPath = rawPath.slice(0, queryIndex);
|
|
12696
14242
|
}
|
|
12697
14243
|
if (rawPath === "") {
|
|
12698
|
-
return fragment ? checkAnchor(
|
|
14244
|
+
return fragment ? checkAnchor(page2.route, fragment, site, ctx) : null;
|
|
12699
14245
|
}
|
|
12700
|
-
const resolved = rawPath.startsWith("/") ? rawPath : resolveRelative(
|
|
14246
|
+
const resolved = rawPath.startsWith("/") ? rawPath : resolveRelative(page2.route, rawPath);
|
|
12701
14247
|
return checkPathLink(resolved, fragment, target, site, ctx);
|
|
12702
14248
|
};
|
|
12703
14249
|
var validateLinks = async (graph, options) => {
|
|
@@ -12710,9 +14256,9 @@ var validateLinks = async (graph, options) => {
|
|
|
12710
14256
|
const diagnostics = [];
|
|
12711
14257
|
const external = [];
|
|
12712
14258
|
let uncheckedAssets = 0;
|
|
12713
|
-
for (const
|
|
12714
|
-
for (const link of
|
|
12715
|
-
const result = classifyLink(
|
|
14259
|
+
for (const page2 of graph.pages) {
|
|
14260
|
+
for (const link of page2.links) {
|
|
14261
|
+
const result = classifyLink(page2, link, ctx, (ref) => external.push(ref));
|
|
12716
14262
|
if (result === "asset-unchecked") {
|
|
12717
14263
|
uncheckedAssets += 1;
|
|
12718
14264
|
} else if (result) {
|
|
@@ -12734,12 +14280,16 @@ var validateLinks = async (graph, options) => {
|
|
|
12734
14280
|
};
|
|
12735
14281
|
|
|
12736
14282
|
// src/cli/commands/validate.ts
|
|
12737
|
-
var validateCommand =
|
|
14283
|
+
var validateCommand = defineCommand11({
|
|
12738
14284
|
args: {
|
|
12739
14285
|
external: {
|
|
12740
14286
|
description: "Check external (HTTP) links over the network.",
|
|
12741
14287
|
type: "boolean"
|
|
12742
14288
|
},
|
|
14289
|
+
json: {
|
|
14290
|
+
description: "Emit diagnostics as JSON on stdout (for CI/editors).",
|
|
14291
|
+
type: "boolean"
|
|
14292
|
+
},
|
|
12743
14293
|
strict: {
|
|
12744
14294
|
description: "Treat warnings as errors.",
|
|
12745
14295
|
type: "boolean"
|
|
@@ -12755,18 +14305,26 @@ var validateCommand = defineCommand10({
|
|
|
12755
14305
|
try {
|
|
12756
14306
|
const project = await scanProject(root, { mode: "build" });
|
|
12757
14307
|
diagnostics.push(...project.diagnostics);
|
|
12758
|
-
const publicDir =
|
|
14308
|
+
const publicDir = join39(root, "public");
|
|
12759
14309
|
diagnostics.push(...await validateLinks(project.graph, {
|
|
12760
14310
|
checkExternal: Boolean(args.external),
|
|
12761
|
-
publicDir:
|
|
14311
|
+
publicDir: existsSync29(publicDir) ? publicDir : null,
|
|
12762
14312
|
redirects: project.config.redirects
|
|
12763
14313
|
}));
|
|
12764
14314
|
} catch (error) {
|
|
12765
14315
|
if (error instanceof BlumeError) {
|
|
12766
14316
|
diagnostics.push(error.diagnostic);
|
|
12767
14317
|
} else {
|
|
12768
|
-
|
|
14318
|
+
reportInternalError(error);
|
|
14319
|
+
process.exit(1);
|
|
14320
|
+
}
|
|
14321
|
+
}
|
|
14322
|
+
if (args.json) {
|
|
14323
|
+
const hadErrors2 = reportDiagnosticsJson(diagnostics, root);
|
|
14324
|
+
if (hadErrors2 || Boolean(args.strict) && diagnostics.length > 0) {
|
|
14325
|
+
process.exit(1);
|
|
12769
14326
|
}
|
|
14327
|
+
return;
|
|
12770
14328
|
}
|
|
12771
14329
|
const hadErrors = reportDiagnostics(diagnostics, root);
|
|
12772
14330
|
if (diagnostics.length === 0) {
|
|
@@ -12779,7 +14337,7 @@ var validateCommand = defineCommand10({
|
|
|
12779
14337
|
});
|
|
12780
14338
|
|
|
12781
14339
|
// src/cli/index.ts
|
|
12782
|
-
var main =
|
|
14340
|
+
var main = defineCommand12({
|
|
12783
14341
|
meta: {
|
|
12784
14342
|
description: "Markdown-first documentation powered by Astro and Vite.",
|
|
12785
14343
|
name: "blume",
|
|
@@ -12788,6 +14346,7 @@ var main = defineCommand11({
|
|
|
12788
14346
|
subCommands: {
|
|
12789
14347
|
add: addCommand,
|
|
12790
14348
|
build: buildCommand,
|
|
14349
|
+
check: checkCommand,
|
|
12791
14350
|
dev: devCommand,
|
|
12792
14351
|
doctor: doctorCommand,
|
|
12793
14352
|
eject: ejectCommand,
|
|
@@ -12798,7 +14357,16 @@ var main = defineCommand11({
|
|
|
12798
14357
|
validate: validateCommand
|
|
12799
14358
|
}
|
|
12800
14359
|
});
|
|
14360
|
+
loadEnvFiles(process.cwd());
|
|
14361
|
+
process.on("uncaughtException", (error) => {
|
|
14362
|
+
reportInternalError(error);
|
|
14363
|
+
process.exit(1);
|
|
14364
|
+
});
|
|
14365
|
+
process.on("unhandledRejection", (error) => {
|
|
14366
|
+
reportInternalError(error);
|
|
14367
|
+
process.exit(1);
|
|
14368
|
+
});
|
|
12801
14369
|
runMain(main);
|
|
12802
14370
|
|
|
12803
|
-
//# debugId=
|
|
14371
|
+
//# debugId=8EA79E97DE44177D64756E2164756E21
|
|
12804
14372
|
//# sourceMappingURL=index.js.map
|