blume 0.2.0 → 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 +1921 -560
- package/dist/cli/index.js.map +36 -24
- 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 +26 -502
- package/dist/types/core/types.d.ts +2 -2
- package/docs/02-deployment.mdx +21 -2
- package/docs/advanced/custom-pages.mdx +63 -1
- package/docs/configuration/ai.mdx +20 -3
- package/docs/configuration/customization.mdx +103 -5
- package/docs/configuration/index.mdx +13 -0
- package/docs/configuration/seo.mdx +5 -0
- package/docs/content/islands.mdx +73 -0
- package/docs/content/navigation.mdx +25 -0
- package/docs/index.mdx +3 -12
- package/docs/reference/cli.mdx +42 -0
- 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 +132 -13
- package/src/astro/integration.ts +59 -0
- package/src/astro/pages.ts +5 -12
- package/src/astro/templates.ts +92 -44
- 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/index.ts +15 -0
- package/src/cli/internal-error.ts +63 -0
- package/src/cli/log.ts +30 -1
- package/src/cli/prepare.ts +17 -3
- package/src/cli/required-secrets.ts +44 -0
- package/src/components/BlumePage.astro +107 -0
- 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 +28 -96
- package/src/core/sources/normalize.ts +51 -0
- package/src/core/types.ts +2 -2
- package/src/deploy/redirects.ts +43 -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/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,8 +500,8 @@ 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
507
|
import { join as join24 } from "pathe";
|
|
@@ -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,6 +4804,8 @@ 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" } }}` : "";
|
|
3918
4809
|
const stagedSpread = options.staged ? `
|
|
3919
4810
|
...(await getCollection("staged")),` : "";
|
|
3920
4811
|
return `---
|
|
@@ -3922,6 +4813,7 @@ var changelogIndexTemplate = (options) => {
|
|
|
3922
4813
|
import { getCollection, render } from "astro:content";
|
|
3923
4814
|
import RootLayout from "blume/components/layout/RootLayout.astro";
|
|
3924
4815
|
import Update from "blume/components/content/Update.astro";
|
|
4816
|
+
import { resolveSlot } from "blume/components/layout/overrides.ts";
|
|
3925
4817
|
import { layoutOverrides } from "../generated/components.ts";
|
|
3926
4818
|
${askImport}import data from "../generated/data.json";
|
|
3927
4819
|
|
|
@@ -3993,11 +4885,13 @@ const headings = items.map((item) => ({
|
|
|
3993
4885
|
|
|
3994
4886
|
const base = data.config.site ? data.config.site.replace(/\\/$/, "") : null;
|
|
3995
4887
|
const canonical = base ? base + "/changelog" : null;
|
|
4888
|
+
|
|
4889
|
+
const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
3996
4890
|
---
|
|
3997
4891
|
|
|
3998
|
-
<
|
|
4892
|
+
<LayoutComponent
|
|
3999
4893
|
site={{ title: data.config.title, description: data.config.description }}
|
|
4000
|
-
layout={layoutOverrides}
|
|
4894
|
+
layout={layoutOverrides}${clientData}
|
|
4001
4895
|
logo={data.config.logo}
|
|
4002
4896
|
mcp={data.config.mcp}
|
|
4003
4897
|
favicon={data.config.favicon}
|
|
@@ -4013,6 +4907,7 @@ const canonical = base ? base + "/changelog" : null;
|
|
|
4013
4907
|
route: "/changelog",
|
|
4014
4908
|
}}
|
|
4015
4909
|
headings={headings}
|
|
4910
|
+
toc={data.config.toc}
|
|
4016
4911
|
themeMode={data.config.theme.mode}
|
|
4017
4912
|
fontCssVars={data.fontCssVars}
|
|
4018
4913
|
searchEnabled={data.config.search.enabled}
|
|
@@ -4041,7 +4936,7 @@ const canonical = base ? base + "/changelog" : null;
|
|
|
4041
4936
|
</div>
|
|
4042
4937
|
)
|
|
4043
4938
|
}
|
|
4044
|
-
</
|
|
4939
|
+
</LayoutComponent>
|
|
4045
4940
|
`;
|
|
4046
4941
|
};
|
|
4047
4942
|
var notFoundPageTemplate = () => `---
|
|
@@ -4082,19 +4977,6 @@ const nf = data.ui.notFound;
|
|
|
4082
4977
|
</div>
|
|
4083
4978
|
</PageLayout>
|
|
4084
4979
|
`;
|
|
4085
|
-
var userComponentsTemplate = (componentsFile) => {
|
|
4086
|
-
if (!componentsFile) {
|
|
4087
|
-
return `// Generated by Blume. Do not edit.
|
|
4088
|
-
export const mdxComponents = {};
|
|
4089
|
-
export const layoutOverrides = {};
|
|
4090
|
-
`;
|
|
4091
|
-
}
|
|
4092
|
-
return `// Generated by Blume. Do not edit.
|
|
4093
|
-
import overrides from ${JSON.stringify(componentsFile)};
|
|
4094
|
-
export const mdxComponents = overrides.mdx ?? {};
|
|
4095
|
-
export const layoutOverrides = overrides.layout ?? {};
|
|
4096
|
-
`;
|
|
4097
|
-
};
|
|
4098
4980
|
var islandDirective = (spec) => spec.client === "only" ? `client:only="${spec.framework}"` : `client:${spec.client}`;
|
|
4099
4981
|
var islandWrapperTemplate = (spec) => `---
|
|
4100
4982
|
// Generated by Blume. Do not edit.
|
|
@@ -4156,6 +5038,12 @@ declare module "blume:data" {
|
|
|
4156
5038
|
const data: import("blume").BlumeData;
|
|
4157
5039
|
export default data;
|
|
4158
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
|
+
}
|
|
4159
5047
|
`;
|
|
4160
5048
|
var runtimePackageTemplate = (dependencies = []) => `${JSON.stringify({
|
|
4161
5049
|
dependencies: Object.fromEntries([...dependencies].toSorted().map((name) => [name, "*"])),
|
|
@@ -4336,7 +5224,7 @@ var specConfiguration = async (spec, root) => {
|
|
|
4336
5224
|
if (URL_SPEC.test(spec)) {
|
|
4337
5225
|
return { config: { url: spec } };
|
|
4338
5226
|
}
|
|
4339
|
-
const absolute =
|
|
5227
|
+
const absolute = isAbsolute3(spec) ? spec : join8(root, spec);
|
|
4340
5228
|
try {
|
|
4341
5229
|
return { config: { content: await readFile4(absolute, "utf-8") } };
|
|
4342
5230
|
} catch {
|
|
@@ -5075,9 +5963,106 @@ var twoslashCss = () => {
|
|
|
5075
5963
|
${OVERRIDES}`;
|
|
5076
5964
|
};
|
|
5077
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
|
+
|
|
5078
6063
|
// src/astro/examples.ts
|
|
5079
6064
|
import { readFile as readFile6 } from "node:fs/promises";
|
|
5080
|
-
import { join as join10, relative as
|
|
6065
|
+
import { join as join10, relative as relative4 } from "pathe";
|
|
5081
6066
|
import { glob as glob2 } from "tinyglobby";
|
|
5082
6067
|
|
|
5083
6068
|
// src/astro/islands.ts
|
|
@@ -5091,7 +6076,7 @@ var VALID_MODES = new Set([
|
|
|
5091
6076
|
"only",
|
|
5092
6077
|
"visible"
|
|
5093
6078
|
]);
|
|
5094
|
-
var
|
|
6079
|
+
var FRAMEWORK_BY_EXT2 = {
|
|
5095
6080
|
jsx: "react",
|
|
5096
6081
|
svelte: "svelte",
|
|
5097
6082
|
tsx: "react",
|
|
@@ -5125,7 +6110,7 @@ var discoverIslands = async (root) => {
|
|
|
5125
6110
|
for (const [index, file] of files.entries()) {
|
|
5126
6111
|
const base = basename(file);
|
|
5127
6112
|
const ext = base.match(ISLAND_FILE)?.groups?.ext;
|
|
5128
|
-
const framework = ext ?
|
|
6113
|
+
const framework = ext ? FRAMEWORK_BY_EXT2[ext] : undefined;
|
|
5129
6114
|
if (!framework) {
|
|
5130
6115
|
continue;
|
|
5131
6116
|
}
|
|
@@ -5151,7 +6136,7 @@ var discoverIslands = async (root) => {
|
|
|
5151
6136
|
};
|
|
5152
6137
|
|
|
5153
6138
|
// src/astro/examples.ts
|
|
5154
|
-
var
|
|
6139
|
+
var FRAMEWORK_BY_EXT3 = {
|
|
5155
6140
|
astro: "astro",
|
|
5156
6141
|
jsx: "react",
|
|
5157
6142
|
svelte: "svelte",
|
|
@@ -5187,11 +6172,11 @@ var discoverExamples = async (root, pattern = "examples") => {
|
|
|
5187
6172
|
const seen = new Map;
|
|
5188
6173
|
for (const [index, file] of files.entries()) {
|
|
5189
6174
|
const ext = file.match(EXAMPLE_FILE)?.groups?.ext;
|
|
5190
|
-
const framework = ext ?
|
|
6175
|
+
const framework = ext ? FRAMEWORK_BY_EXT3[ext] : undefined;
|
|
5191
6176
|
if (!(ext && framework)) {
|
|
5192
6177
|
continue;
|
|
5193
6178
|
}
|
|
5194
|
-
const path =
|
|
6179
|
+
const path = relative4(dir, file).slice(0, -(ext.length + 1));
|
|
5195
6180
|
const existing = seen.get(path);
|
|
5196
6181
|
if (existing) {
|
|
5197
6182
|
warnings.push(`Two examples both resolve to "${path}" ("${existing}" and "${file}"); ignoring the second. Give them distinct paths.`);
|
|
@@ -5212,7 +6197,7 @@ var discoverExamples = async (root, pattern = "examples") => {
|
|
|
5212
6197
|
};
|
|
5213
6198
|
|
|
5214
6199
|
// src/astro/pages.ts
|
|
5215
|
-
import { extname, relative as
|
|
6200
|
+
import { extname as extname2, relative as relative5 } from "pathe";
|
|
5216
6201
|
import { glob as glob3 } from "tinyglobby";
|
|
5217
6202
|
var discoverPages = async (pagesRoot) => {
|
|
5218
6203
|
const files = await glob3(["**/*.astro"], {
|
|
@@ -5222,8 +6207,8 @@ var discoverPages = async (pagesRoot) => {
|
|
|
5222
6207
|
});
|
|
5223
6208
|
files.sort();
|
|
5224
6209
|
return files.map((file) => {
|
|
5225
|
-
const rel =
|
|
5226
|
-
const withoutExt = rel.slice(0, rel.length -
|
|
6210
|
+
const rel = relative5(pagesRoot, file);
|
|
6211
|
+
const withoutExt = rel.slice(0, rel.length - extname2(rel).length);
|
|
5227
6212
|
const parts = withoutExt.split("/").filter((part) => part !== "index");
|
|
5228
6213
|
const pattern = parts.length === 0 ? "/" : `/${parts.join("/")}`;
|
|
5229
6214
|
return { entrypoint: file, pattern };
|
|
@@ -5232,7 +6217,7 @@ var discoverPages = async (pagesRoot) => {
|
|
|
5232
6217
|
var routeIsTaken = (pages, contentPages, route) => pages.some((page) => page.pattern === route) || contentPages.some((page) => page.route === route);
|
|
5233
6218
|
var PRIVATE_SEGMENT = /^[._]/u;
|
|
5234
6219
|
var humanizeSegment = (segment) => segment.split(/[-_]/u).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
5235
|
-
var customOgRoutes = (pages, siteTitle
|
|
6220
|
+
var customOgRoutes = (pages, siteTitle) => {
|
|
5236
6221
|
const seen = new Set;
|
|
5237
6222
|
const routes = [];
|
|
5238
6223
|
for (const { pattern } of pages) {
|
|
@@ -5246,7 +6231,7 @@ var customOgRoutes = (pages, siteTitle, siteDescription) => {
|
|
|
5246
6231
|
}
|
|
5247
6232
|
seen.add(slug);
|
|
5248
6233
|
const last = segments.at(-1);
|
|
5249
|
-
routes.push(
|
|
6234
|
+
routes.push({ slug, title: last ? humanizeSegment(last) : siteTitle });
|
|
5250
6235
|
}
|
|
5251
6236
|
return routes;
|
|
5252
6237
|
};
|
|
@@ -5270,8 +6255,8 @@ var resolvedAstroPath = (fromDir) => {
|
|
|
5270
6255
|
}
|
|
5271
6256
|
};
|
|
5272
6257
|
var blumeDepsDir = (pkgDir = packageRoot()) => {
|
|
5273
|
-
const candidates = [join11(pkgDir, "node_modules"),
|
|
5274
|
-
return candidates.find((dir) =>
|
|
6258
|
+
const candidates = [join11(pkgDir, "node_modules"), dirname7(pkgDir)];
|
|
6259
|
+
return candidates.find((dir) => existsSync6(join11(dir, "astro"))) ?? null;
|
|
5275
6260
|
};
|
|
5276
6261
|
var linkDepsJunction = async (link, depsDir) => {
|
|
5277
6262
|
const existing = await lstat(link).catch(() => null);
|
|
@@ -5281,7 +6266,7 @@ var linkDepsJunction = async (link, depsDir) => {
|
|
|
5281
6266
|
}
|
|
5282
6267
|
await rm(link, { force: true });
|
|
5283
6268
|
}
|
|
5284
|
-
await mkdir2(
|
|
6269
|
+
await mkdir2(dirname7(link), { recursive: true });
|
|
5285
6270
|
await symlink(depsDir, link, "junction");
|
|
5286
6271
|
};
|
|
5287
6272
|
var readPkgVersion = (pkgJsonPath) => {
|
|
@@ -5311,7 +6296,7 @@ var ensureDepsLink = async (outDir, pkgDir = packageRoot()) => {
|
|
|
5311
6296
|
if (blumeAstro && outDirAstro === blumeAstro) {
|
|
5312
6297
|
return null;
|
|
5313
6298
|
}
|
|
5314
|
-
if (
|
|
6299
|
+
if (existsSync6(join11(depsDir, "@astrojs", "mdx"))) {
|
|
5315
6300
|
await linkDepsJunction(join11(outDir, "node_modules"), depsDir);
|
|
5316
6301
|
return null;
|
|
5317
6302
|
}
|
|
@@ -5359,7 +6344,7 @@ var writeIfChanged = async (path, content) => {
|
|
|
5359
6344
|
if (existing === content) {
|
|
5360
6345
|
return false;
|
|
5361
6346
|
}
|
|
5362
|
-
await mkdir2(
|
|
6347
|
+
await mkdir2(dirname7(path), { recursive: true });
|
|
5363
6348
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
5364
6349
|
await writeFile2(tmp, content, "utf-8");
|
|
5365
6350
|
try {
|
|
@@ -5395,7 +6380,7 @@ var writeStagedContent = async (out, staged) => {
|
|
|
5395
6380
|
written.add(normalize(path));
|
|
5396
6381
|
await writeIfChanged(path, text);
|
|
5397
6382
|
}));
|
|
5398
|
-
if (
|
|
6383
|
+
if (existsSync6(contentDir)) {
|
|
5399
6384
|
await pruneOrphans(contentDir, written);
|
|
5400
6385
|
}
|
|
5401
6386
|
};
|
|
@@ -5414,7 +6399,7 @@ var resolveLogo = (project) => {
|
|
|
5414
6399
|
const file = [
|
|
5415
6400
|
join11(project.context.root, "public", rel),
|
|
5416
6401
|
join11(project.context.root, rel)
|
|
5417
|
-
].find((path) =>
|
|
6402
|
+
].find((path) => existsSync6(path));
|
|
5418
6403
|
if (file) {
|
|
5419
6404
|
return { alt, href, svg: readFileSync5(file, "utf-8") };
|
|
5420
6405
|
}
|
|
@@ -5454,13 +6439,13 @@ var APPLE_ICON_CANDIDATES = [
|
|
|
5454
6439
|
var resolveIconFile = (project, candidates) => {
|
|
5455
6440
|
const { root } = project.context;
|
|
5456
6441
|
for (const name of candidates) {
|
|
5457
|
-
if (
|
|
6442
|
+
if (existsSync6(join11(root, "public", name))) {
|
|
5458
6443
|
return { href: `/${name}`, type: faviconType(name) };
|
|
5459
6444
|
}
|
|
5460
6445
|
}
|
|
5461
6446
|
for (const name of candidates) {
|
|
5462
6447
|
const file = join11(root, name);
|
|
5463
|
-
if (
|
|
6448
|
+
if (existsSync6(file)) {
|
|
5464
6449
|
const type = faviconType(name);
|
|
5465
6450
|
return { href: inlineDataUri(file, type ?? "image/x-icon"), type };
|
|
5466
6451
|
}
|
|
@@ -5493,7 +6478,7 @@ var buildRuntimeData = (project) => {
|
|
|
5493
6478
|
if (!(editBase && sourcePath)) {
|
|
5494
6479
|
return null;
|
|
5495
6480
|
}
|
|
5496
|
-
const rel =
|
|
6481
|
+
const rel = relative6(context.root, sourcePath).split("\\").join("/");
|
|
5497
6482
|
return `${editBase}/${github?.dir ? `${github.dir}/${rel}` : rel}`;
|
|
5498
6483
|
};
|
|
5499
6484
|
const { i18n } = config;
|
|
@@ -5554,7 +6539,8 @@ var buildRuntimeData = (project) => {
|
|
|
5554
6539
|
site: config.deployment.site ?? null,
|
|
5555
6540
|
structuredData: config.seo.structuredData,
|
|
5556
6541
|
theme: config.theme,
|
|
5557
|
-
title: config.title
|
|
6542
|
+
title: config.title,
|
|
6543
|
+
toc: config.toc
|
|
5558
6544
|
},
|
|
5559
6545
|
feeds: buildRssFeeds(project).map((feed) => ({
|
|
5560
6546
|
href: feed.path,
|
|
@@ -5641,6 +6627,18 @@ var writeMcpFiles = async (project, plan, write) => {
|
|
|
5641
6627
|
write(join11(plan.dir, "server-card.ts"), staticJsonEndpointTemplate(buildMcpServerCard(discoveryInput)))
|
|
5642
6628
|
]);
|
|
5643
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
|
+
};
|
|
5644
6642
|
var writeNotFoundPage = async (write, srcDir, pages, contentPages) => {
|
|
5645
6643
|
if (routeIsTaken(pages, contentPages, "/404")) {
|
|
5646
6644
|
return;
|
|
@@ -5653,6 +6651,14 @@ var shouldGenerateChangelog = (project) => {
|
|
|
5653
6651
|
const changelogRouteTaken = project.graph.pages.some((page) => page.route === "/changelog");
|
|
5654
6652
|
return (hasChangelog || hasChangelogSource) && !changelogRouteTaken;
|
|
5655
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
|
+
};
|
|
5656
6662
|
var generateRuntime = async (project) => {
|
|
5657
6663
|
const { context, config } = project;
|
|
5658
6664
|
const out = context.outDir;
|
|
@@ -5677,14 +6683,20 @@ var generateRuntime = async (project) => {
|
|
|
5677
6683
|
discoverIslands(context.root),
|
|
5678
6684
|
discoverExamples(context.root, config.examples)
|
|
5679
6685
|
]);
|
|
6686
|
+
const {
|
|
6687
|
+
plan: slotPlan,
|
|
6688
|
+
tags: overrideTags,
|
|
6689
|
+
warnings: overrideWarnings
|
|
6690
|
+
} = await buildComponentSlots(context.componentsFile);
|
|
5680
6691
|
const frameworks = new Set([
|
|
5681
6692
|
...islandDiscovery.islands.map((island) => island.framework),
|
|
5682
|
-
...exampleDiscovery.examples.map((example) => example.framework)
|
|
6693
|
+
...exampleDiscovery.examples.map((example) => example.framework),
|
|
6694
|
+
...slotPlan.frameworks
|
|
5683
6695
|
]);
|
|
5684
6696
|
const needsReact = detectedReact || askEnabled || frameworks.has("react");
|
|
5685
6697
|
const needsVue = frameworks.has("vue");
|
|
5686
6698
|
const needsSvelte = frameworks.has("svelte");
|
|
5687
|
-
const ogRoutes = customOgRoutes(pages, config.title
|
|
6699
|
+
const ogRoutes = customOgRoutes(pages, config.title);
|
|
5688
6700
|
const mcp = planMcp(project, srcDir);
|
|
5689
6701
|
pages.push(...mcp.discoveryPages);
|
|
5690
6702
|
const staged = collectStaged(project);
|
|
@@ -5712,9 +6724,10 @@ var generateRuntime = async (project) => {
|
|
|
5712
6724
|
askEnabled,
|
|
5713
6725
|
exportEpub,
|
|
5714
6726
|
exportPdf,
|
|
5715
|
-
mathEnabled: config.markdown.math
|
|
6727
|
+
mathEnabled: config.markdown.math,
|
|
6728
|
+
needsReact
|
|
5716
6729
|
})),
|
|
5717
|
-
write(join11(srcDir, "generated", "components.ts"),
|
|
6730
|
+
write(join11(srcDir, "generated", "components.ts"), slotPlan.module),
|
|
5718
6731
|
write(join11(srcDir, "generated", "islands.ts"), islandMapTemplate(islandDiscovery.islands)),
|
|
5719
6732
|
write(join11(srcDir, "generated", "examples.ts"), exampleMapTemplate(exampleDiscovery.examples)),
|
|
5720
6733
|
write(themePath, tailwindEntryTemplate({
|
|
@@ -5728,10 +6741,9 @@ var generateRuntime = async (project) => {
|
|
|
5728
6741
|
}))
|
|
5729
6742
|
]);
|
|
5730
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)));
|
|
5731
6745
|
await Promise.all(exampleDiscovery.examples.map((example) => write(join11(srcDir, "generated", "examples", `${exampleSlug(example.path)}.astro`), exampleWrapperTemplate(example))));
|
|
5732
|
-
|
|
5733
|
-
await write(join11(srcDir, "pages", "api", "ask.ts"), askEndpointTemplate(resolveAskBackend(config.ai.ask)));
|
|
5734
|
-
}
|
|
6746
|
+
await writeAskFiles(project, srcDir, write);
|
|
5735
6747
|
await writeMcpFiles(project, mcp, write);
|
|
5736
6748
|
if (config.seo.og.enabled) {
|
|
5737
6749
|
await write(join11(srcDir, "pages", "og", "[...slug].png.ts"), ogEndpointTemplate(ogRoutes));
|
|
@@ -5741,6 +6753,7 @@ var generateRuntime = async (project) => {
|
|
|
5741
6753
|
askEnabled,
|
|
5742
6754
|
exportEpub,
|
|
5743
6755
|
exportPdf,
|
|
6756
|
+
needsReact,
|
|
5744
6757
|
staged: hasStaged
|
|
5745
6758
|
}));
|
|
5746
6759
|
}
|
|
@@ -5775,8 +6788,23 @@ var generateRuntime = async (project) => {
|
|
|
5775
6788
|
...depsLinkWarning ? [depsLinkWarning] : [],
|
|
5776
6789
|
...mcp.warnings,
|
|
5777
6790
|
...islandDiscovery.warnings,
|
|
5778
|
-
...exampleDiscovery.warnings
|
|
6791
|
+
...exampleDiscovery.warnings,
|
|
6792
|
+
...overrideWarnings
|
|
5779
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));
|
|
5780
6808
|
for (const dep of searchProviderMeta(config.search.provider).runtimeDeps) {
|
|
5781
6809
|
if (!(canResolveFrom(context.root, dep) || canResolveFrom(packageRoot(), dep))) {
|
|
5782
6810
|
warnings.push(`Search provider "${config.search.provider}" needs "${dep}", which isn't installed. Run \`npm install ${dep}\` (or your package manager's equivalent).`);
|
|
@@ -5800,14 +6828,17 @@ var generateRuntime = async (project) => {
|
|
|
5800
6828
|
return { structuralChange: structural.some(Boolean), warnings };
|
|
5801
6829
|
};
|
|
5802
6830
|
|
|
6831
|
+
// src/core/config.ts
|
|
6832
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6 } from "node:fs";
|
|
6833
|
+
|
|
5803
6834
|
// src/core/bridge.ts
|
|
5804
|
-
import { existsSync as
|
|
6835
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
5805
6836
|
import { readFile as readFile9 } from "node:fs/promises";
|
|
5806
6837
|
import { join as join12 } from "pathe";
|
|
5807
6838
|
|
|
5808
6839
|
// src/migrate/mintlify/config.ts
|
|
5809
6840
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
5810
|
-
import { dirname as
|
|
6841
|
+
import { dirname as dirname8, relative as relative7, resolve as resolve4 } from "pathe";
|
|
5811
6842
|
var MINTLIFY_DEFAULT_IGNORES = [
|
|
5812
6843
|
"**/_*",
|
|
5813
6844
|
"**/.*",
|
|
@@ -5843,7 +6874,7 @@ var asDirectoryMode = (value) => value === "accordion" || value === "card" || va
|
|
|
5843
6874
|
var withoutUndefined = (value) => Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined));
|
|
5844
6875
|
var hasOwn = (object, key) => Object.hasOwn(object, key);
|
|
5845
6876
|
var isInsideRoot = (root, candidate) => {
|
|
5846
|
-
const rel =
|
|
6877
|
+
const rel = relative7(root, candidate);
|
|
5847
6878
|
return rel === "" || !rel.startsWith("..") && !rel.startsWith("/");
|
|
5848
6879
|
};
|
|
5849
6880
|
var readJsonFile = async (file) => {
|
|
@@ -5868,7 +6899,7 @@ var resolveRefs = async (value, options) => {
|
|
|
5868
6899
|
}
|
|
5869
6900
|
const ref = asString(object.$ref);
|
|
5870
6901
|
if (ref) {
|
|
5871
|
-
const refFile =
|
|
6902
|
+
const refFile = resolve4(dirname8(options.file), ref);
|
|
5872
6903
|
if (!isInsideRoot(options.root, refFile)) {
|
|
5873
6904
|
throw new BlumeError({
|
|
5874
6905
|
code: "BLUME_MINTLIFY_REF_OUTSIDE_ROOT",
|
|
@@ -6222,53 +7253,9 @@ var mintlifySelectors = (spec) => {
|
|
|
6222
7253
|
}
|
|
6223
7254
|
].filter((selector) => selector.items.length > 0);
|
|
6224
7255
|
};
|
|
6225
|
-
var navbarTypeLabel = (type) => {
|
|
6226
|
-
if (type === "github") {
|
|
6227
|
-
return "GitHub";
|
|
6228
|
-
}
|
|
6229
|
-
if (type === "discord") {
|
|
6230
|
-
return "Discord";
|
|
6231
|
-
}
|
|
6232
|
-
return;
|
|
6233
|
-
};
|
|
6234
|
-
var navbarLinkType = (type) => type === "github" || type === "discord" ? type : undefined;
|
|
6235
|
-
var navbarPrimaryType = (type) => type === "github" || type === "discord" ? type : "button";
|
|
6236
|
-
var mintlifyNavbar = (value) => {
|
|
6237
|
-
const object = asObject(value);
|
|
6238
|
-
if (!object) {
|
|
6239
|
-
return { links: [] };
|
|
6240
|
-
}
|
|
6241
|
-
const links = asArray(object.links).flatMap((item) => {
|
|
6242
|
-
const itemObject = asObject(item);
|
|
6243
|
-
const href = itemObject ? asString(itemObject.href) : undefined;
|
|
6244
|
-
const type = itemObject ? asString(itemObject.type) : undefined;
|
|
6245
|
-
const label = itemObject ? asString(itemObject.label) ?? navbarTypeLabel(type) : undefined;
|
|
6246
|
-
if (!itemObject || !href || !label) {
|
|
6247
|
-
return [];
|
|
6248
|
-
}
|
|
6249
|
-
return [
|
|
6250
|
-
withoutUndefined({
|
|
6251
|
-
href,
|
|
6252
|
-
icon: asString(itemObject.icon),
|
|
6253
|
-
label,
|
|
6254
|
-
type: navbarLinkType(type)
|
|
6255
|
-
})
|
|
6256
|
-
];
|
|
6257
|
-
});
|
|
6258
|
-
const primaryObject = asObject(object.primary);
|
|
6259
|
-
const primaryHref = primaryObject ? asString(primaryObject.href) : undefined;
|
|
6260
|
-
const primaryType = primaryObject ? asString(primaryObject.type) ?? "button" : undefined;
|
|
6261
|
-
const primaryLabel = primaryObject ? asString(primaryObject.label) ?? navbarTypeLabel(primaryType) : undefined;
|
|
6262
|
-
const primary = primaryObject && primaryHref && primaryLabel ? withoutUndefined({
|
|
6263
|
-
href: primaryHref,
|
|
6264
|
-
label: primaryLabel,
|
|
6265
|
-
type: navbarPrimaryType(primaryType)
|
|
6266
|
-
}) : undefined;
|
|
6267
|
-
return withoutUndefined({ links, primary });
|
|
6268
|
-
};
|
|
6269
7256
|
var mintignorePatterns = async (root) => {
|
|
6270
7257
|
try {
|
|
6271
|
-
const raw = await readFile8(
|
|
7258
|
+
const raw = await readFile8(resolve4(root, ".mintignore"), "utf-8");
|
|
6272
7259
|
return raw.split(`
|
|
6273
7260
|
`).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).filter((line) => !line.startsWith("!")).map((line) => line.endsWith("/") ? `${line}**` : line);
|
|
6274
7261
|
} catch {
|
|
@@ -6287,61 +7274,6 @@ var mintlifyRedirects = (spec) => asArray(spec.redirects).flatMap((redirect) =>
|
|
|
6287
7274
|
}
|
|
6288
7275
|
return [{ from, to }];
|
|
6289
7276
|
});
|
|
6290
|
-
var mintlifyContextual = (value) => {
|
|
6291
|
-
const object = asObject(value);
|
|
6292
|
-
if (!object) {
|
|
6293
|
-
return { options: [] };
|
|
6294
|
-
}
|
|
6295
|
-
const display = object.display === "toc" ? "toc" : "header";
|
|
6296
|
-
const options = [];
|
|
6297
|
-
for (const option of asArray(object.options)) {
|
|
6298
|
-
if (typeof option === "string") {
|
|
6299
|
-
options.push(option);
|
|
6300
|
-
continue;
|
|
6301
|
-
}
|
|
6302
|
-
const optionObject = asObject(option);
|
|
6303
|
-
const title = optionObject ? asString(optionObject.title) : undefined;
|
|
6304
|
-
if (!optionObject || !title) {
|
|
6305
|
-
continue;
|
|
6306
|
-
}
|
|
6307
|
-
options.push(withoutUndefined({
|
|
6308
|
-
description: asString(optionObject.description),
|
|
6309
|
-
href: asString(optionObject.href),
|
|
6310
|
-
icon: asString(optionObject.icon),
|
|
6311
|
-
title
|
|
6312
|
-
}));
|
|
6313
|
-
}
|
|
6314
|
-
return { display, options };
|
|
6315
|
-
};
|
|
6316
|
-
var mintlifyFooter = (value) => {
|
|
6317
|
-
const object = asObject(value);
|
|
6318
|
-
const socials = asObject(object?.socials);
|
|
6319
|
-
const links = asArray(object?.links).flatMap((group) => {
|
|
6320
|
-
const groupObject = asObject(group);
|
|
6321
|
-
const items = asArray(groupObject?.items).flatMap((item) => {
|
|
6322
|
-
const itemObject = asObject(item);
|
|
6323
|
-
const label = itemObject ? asString(itemObject.label) : undefined;
|
|
6324
|
-
const href = itemObject ? asString(itemObject.href) : undefined;
|
|
6325
|
-
return label && href ? [{ href, label }] : [];
|
|
6326
|
-
});
|
|
6327
|
-
if (!groupObject || items.length === 0) {
|
|
6328
|
-
return [];
|
|
6329
|
-
}
|
|
6330
|
-
return [
|
|
6331
|
-
withoutUndefined({
|
|
6332
|
-
header: asString(groupObject.header),
|
|
6333
|
-
items
|
|
6334
|
-
})
|
|
6335
|
-
];
|
|
6336
|
-
}).slice(0, 4);
|
|
6337
|
-
return {
|
|
6338
|
-
links,
|
|
6339
|
-
socials: socials ? Object.fromEntries(Object.entries(socials).flatMap(([label, href]) => {
|
|
6340
|
-
const hrefValue = asString(href);
|
|
6341
|
-
return hrefValue ? [[label, hrefValue]] : [];
|
|
6342
|
-
})) : {}
|
|
6343
|
-
};
|
|
6344
|
-
};
|
|
6345
7277
|
var mintlifyLogo = (value) => {
|
|
6346
7278
|
if (typeof value === "string") {
|
|
6347
7279
|
return value;
|
|
@@ -6406,16 +7338,12 @@ var mintlifyChromeVariants = (spec) => {
|
|
|
6406
7338
|
return [];
|
|
6407
7339
|
}
|
|
6408
7340
|
const banner = hasOwn(object, "banner") ? mintlifyBanner(object.banner) : undefined;
|
|
6409
|
-
|
|
6410
|
-
const navbar = hasOwn(object, "navbar") ? mintlifyNavbar(object.navbar) : undefined;
|
|
6411
|
-
if (!banner && !footer && !navbar) {
|
|
7341
|
+
if (!banner) {
|
|
6412
7342
|
return [];
|
|
6413
7343
|
}
|
|
6414
7344
|
return [
|
|
6415
7345
|
withoutUndefined({
|
|
6416
7346
|
banner,
|
|
6417
|
-
footer,
|
|
6418
|
-
navbar,
|
|
6419
7347
|
path
|
|
6420
7348
|
})
|
|
6421
7349
|
];
|
|
@@ -6467,13 +7395,6 @@ var mintlifyMarkdown = (value, styling) => {
|
|
|
6467
7395
|
schema: object?.schema === false ? false : undefined
|
|
6468
7396
|
});
|
|
6469
7397
|
};
|
|
6470
|
-
var mintlifyStyling = (value) => {
|
|
6471
|
-
const object = asObject(value);
|
|
6472
|
-
const eyebrows = asString(object?.eyebrows);
|
|
6473
|
-
return withoutUndefined({
|
|
6474
|
-
eyebrows: eyebrows === "breadcrumbs" || eyebrows === "section" ? eyebrows : undefined
|
|
6475
|
-
});
|
|
6476
|
-
};
|
|
6477
7398
|
var mintlifySeo = (value) => {
|
|
6478
7399
|
const object = asObject(value);
|
|
6479
7400
|
const metatags = asObject(object?.metatags);
|
|
@@ -6484,16 +7405,9 @@ var mintlifySeo = (value) => {
|
|
|
6484
7405
|
})) : {}
|
|
6485
7406
|
};
|
|
6486
7407
|
};
|
|
6487
|
-
var mintlifyIcons = (value) => {
|
|
6488
|
-
const object = asObject(value);
|
|
6489
|
-
const library = object?.library;
|
|
6490
|
-
return withoutUndefined({
|
|
6491
|
-
library: library === "fontawesome" || library === "lucide" || library === "tabler" ? library : undefined
|
|
6492
|
-
});
|
|
6493
|
-
};
|
|
6494
7408
|
var loadMintlifyConfig = async (root, file) => {
|
|
6495
|
-
const projectRoot =
|
|
6496
|
-
const configFile =
|
|
7409
|
+
const projectRoot = resolve4(root);
|
|
7410
|
+
const configFile = resolve4(file);
|
|
6497
7411
|
const spec = asObject(await resolveRefs(await readJsonFile(configFile), {
|
|
6498
7412
|
file: configFile,
|
|
6499
7413
|
root: projectRoot,
|
|
@@ -6524,14 +7438,10 @@ var loadMintlifyConfig = async (root, file) => {
|
|
|
6524
7438
|
],
|
|
6525
7439
|
root: "."
|
|
6526
7440
|
},
|
|
6527
|
-
contextual: mintlifyContextual(spec.contextual),
|
|
6528
7441
|
description: asString(spec.description),
|
|
6529
7442
|
favicon: mintlifyFavicon(spec.favicon),
|
|
6530
|
-
footer: mintlifyFooter(spec.footer),
|
|
6531
|
-
icons: mintlifyIcons(spec.icons),
|
|
6532
7443
|
logo: mintlifyLogo(spec.logo),
|
|
6533
7444
|
markdown: mintlifyMarkdown(spec.markdown, styling),
|
|
6534
|
-
navbar: mintlifyNavbar(spec.navbar),
|
|
6535
7445
|
navigation: {
|
|
6536
7446
|
chromeVariants: mintlifyChromeVariants(spec),
|
|
6537
7447
|
selectors: mintlifySelectors(spec),
|
|
@@ -6547,7 +7457,6 @@ var loadMintlifyConfig = async (root, file) => {
|
|
|
6547
7457
|
prompt: asString(search.prompt)
|
|
6548
7458
|
},
|
|
6549
7459
|
seo: mintlifySeo(seo),
|
|
6550
|
-
styling: mintlifyStyling(styling),
|
|
6551
7460
|
theme: {
|
|
6552
7461
|
accent: asString(colors.primary) ?? "blue",
|
|
6553
7462
|
accentDark: asString(colors.light),
|
|
@@ -6594,7 +7503,7 @@ var mintlifyI18n = (spec) => {
|
|
|
6594
7503
|
// src/core/bridge.ts
|
|
6595
7504
|
var MINTLIFY_CONFIG_FILES = ["docs.json", "mint.json"];
|
|
6596
7505
|
var detectMintlifyBridge = async (root) => {
|
|
6597
|
-
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));
|
|
6598
7507
|
if (!configFile) {
|
|
6599
7508
|
return null;
|
|
6600
7509
|
}
|
|
@@ -6683,8 +7592,8 @@ var createModuleLoader = () => {
|
|
|
6683
7592
|
};
|
|
6684
7593
|
|
|
6685
7594
|
// src/core/project.ts
|
|
6686
|
-
import { existsSync as
|
|
6687
|
-
import { isAbsolute as
|
|
7595
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
7596
|
+
import { isAbsolute as isAbsolute4, join as join13, resolve as resolve5 } from "pathe";
|
|
6688
7597
|
var CONFIG_FILENAMES = [
|
|
6689
7598
|
"blume.config.ts",
|
|
6690
7599
|
"blume.config.mjs",
|
|
@@ -6695,7 +7604,7 @@ var COMPONENTS_FILENAMES = ["components.tsx", "components.ts"];
|
|
|
6695
7604
|
var firstExisting = (root, names) => {
|
|
6696
7605
|
for (const name of names) {
|
|
6697
7606
|
const candidate = join13(root, name);
|
|
6698
|
-
if (
|
|
7607
|
+
if (existsSync8(candidate)) {
|
|
6699
7608
|
return candidate;
|
|
6700
7609
|
}
|
|
6701
7610
|
}
|
|
@@ -6703,10 +7612,10 @@ var firstExisting = (root, names) => {
|
|
|
6703
7612
|
};
|
|
6704
7613
|
var findConfigFile = (root) => firstExisting(root, CONFIG_FILENAMES);
|
|
6705
7614
|
var resolveProjectContext = (root, config) => {
|
|
6706
|
-
const absoluteRoot =
|
|
6707
|
-
const contentRoot =
|
|
7615
|
+
const absoluteRoot = resolve5(root);
|
|
7616
|
+
const contentRoot = isAbsolute4(config.content.root) ? config.content.root : join13(absoluteRoot, config.content.root);
|
|
6708
7617
|
const pagesPath = join13(absoluteRoot, config.content.pages);
|
|
6709
|
-
const pagesRoot =
|
|
7618
|
+
const pagesRoot = existsSync8(pagesPath) ? pagesPath : null;
|
|
6710
7619
|
return {
|
|
6711
7620
|
componentsFile: firstExisting(absoluteRoot, COMPONENTS_FILENAMES),
|
|
6712
7621
|
configFile: findConfigFile(absoluteRoot),
|
|
@@ -6951,26 +7860,6 @@ var sidebarVariantSchema = z2.object({
|
|
|
6951
7860
|
items: z2.array(sidebarItemSchema).default([]),
|
|
6952
7861
|
path: z2.string()
|
|
6953
7862
|
}).strict();
|
|
6954
|
-
var navbarLinkTypeSchema = z2.enum(["github", "discord"]);
|
|
6955
|
-
var navbarLinkSchema = z2.object({
|
|
6956
|
-
href: z2.string(),
|
|
6957
|
-
icon: iconName.optional(),
|
|
6958
|
-
label: z2.string().optional(),
|
|
6959
|
-
type: navbarLinkTypeSchema.optional()
|
|
6960
|
-
}).strict().refine((value) => value.label !== undefined || value.type !== undefined, {
|
|
6961
|
-
message: "Navbar links require either label or type."
|
|
6962
|
-
});
|
|
6963
|
-
var navbarPrimarySchema = z2.object({
|
|
6964
|
-
href: z2.string(),
|
|
6965
|
-
label: z2.string().optional(),
|
|
6966
|
-
type: z2.enum(["button", "github", "discord"]).default("button")
|
|
6967
|
-
}).strict().refine((value) => value.label !== undefined || value.type !== "button", {
|
|
6968
|
-
message: "Navbar primary button links require a label."
|
|
6969
|
-
});
|
|
6970
|
-
var navbarConfigSchema = z2.object({
|
|
6971
|
-
links: z2.array(navbarLinkSchema).default([]),
|
|
6972
|
-
primary: navbarPrimarySchema.optional()
|
|
6973
|
-
}).strict();
|
|
6974
7863
|
var variablesConfigSchema = z2.record(z2.string().regex(/^[A-Za-z0-9-]+$/u), z2.string()).default({});
|
|
6975
7864
|
var fontSlug = z2.string().refine(isFontSlug, (value) => ({
|
|
6976
7865
|
message: `Unknown font "${value}". Supported fonts: ${FONT_SLUGS.join(", ")}.`
|
|
@@ -6994,9 +7883,6 @@ var themeConfigSchema = z2.object({
|
|
|
6994
7883
|
radius: z2.enum(["none", "sm", "md", "lg"]).default("md"),
|
|
6995
7884
|
strict: z2.boolean().default(false)
|
|
6996
7885
|
}).strict();
|
|
6997
|
-
var iconsConfigSchema = z2.object({
|
|
6998
|
-
library: z2.enum(["fontawesome", "lucide", "tabler"]).default("lucide")
|
|
6999
|
-
}).strict();
|
|
7000
7886
|
var algoliaSearchSchema = z2.object({
|
|
7001
7887
|
appId: z2.string(),
|
|
7002
7888
|
indexName: z2.string(),
|
|
@@ -7078,33 +7964,8 @@ var aiConfigSchema = z2.object({
|
|
|
7078
7964
|
}).optional(),
|
|
7079
7965
|
llmsTxt: z2.boolean().default(false)
|
|
7080
7966
|
}).strict();
|
|
7081
|
-
var contextualOptionSchema = z2.union([
|
|
7082
|
-
z2.string(),
|
|
7083
|
-
z2.object({
|
|
7084
|
-
description: z2.string().optional(),
|
|
7085
|
-
href: z2.string().optional(),
|
|
7086
|
-
icon: iconName.optional(),
|
|
7087
|
-
title: z2.string()
|
|
7088
|
-
}).passthrough()
|
|
7089
|
-
]);
|
|
7090
|
-
var contextualConfigSchema = z2.object({
|
|
7091
|
-
display: z2.enum(["header", "toc"]).default("header"),
|
|
7092
|
-
options: z2.array(contextualOptionSchema).default([])
|
|
7093
|
-
}).strict();
|
|
7094
|
-
var footerConfigSchema = z2.object({
|
|
7095
|
-
links: z2.array(z2.object({
|
|
7096
|
-
header: z2.string().optional(),
|
|
7097
|
-
items: z2.array(z2.object({
|
|
7098
|
-
href: z2.string(),
|
|
7099
|
-
label: z2.string()
|
|
7100
|
-
}).strict()).default([])
|
|
7101
|
-
}).strict()).max(4).default([]),
|
|
7102
|
-
socials: z2.record(z2.string(), z2.string()).default({})
|
|
7103
|
-
}).strict();
|
|
7104
7967
|
var chromeVariantSchema = z2.object({
|
|
7105
7968
|
banner: bannerConfigSchema.optional(),
|
|
7106
|
-
footer: footerConfigSchema.optional(),
|
|
7107
|
-
navbar: navbarConfigSchema.optional(),
|
|
7108
7969
|
path: z2.string()
|
|
7109
7970
|
}).strict();
|
|
7110
7971
|
var navigationConfigSchema = z2.object({
|
|
@@ -7229,9 +8090,6 @@ var markdownConfigSchema = z2.object({
|
|
|
7229
8090
|
imageZoom: z2.boolean().default(true),
|
|
7230
8091
|
math: z2.boolean().default(false)
|
|
7231
8092
|
}).strict();
|
|
7232
|
-
var stylingConfigSchema = z2.object({
|
|
7233
|
-
eyebrows: z2.enum(["breadcrumbs", "section"]).default("section")
|
|
7234
|
-
}).strict();
|
|
7235
8093
|
var openapiSourceSchema = z2.object({
|
|
7236
8094
|
label: z2.string().optional(),
|
|
7237
8095
|
route: z2.string().optional(),
|
|
@@ -7251,36 +8109,48 @@ var asyncapiConfigSchema = z2.object({
|
|
|
7251
8109
|
spec: z2.string().optional(),
|
|
7252
8110
|
theme: z2.string().optional()
|
|
7253
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
|
+
});
|
|
7254
8128
|
var blumeConfigSchema = z2.object({
|
|
7255
8129
|
ai: aiConfigSchema.default({}),
|
|
7256
8130
|
analytics: analyticsConfigSchema.optional(),
|
|
7257
8131
|
asyncapi: asyncapiConfigSchema.default({}),
|
|
7258
8132
|
banner: bannerConfigSchema.optional(),
|
|
7259
8133
|
content: contentConfigSchema.default({}),
|
|
7260
|
-
contextual: contextualConfigSchema.default({}),
|
|
7261
8134
|
deployment: deploymentConfigSchema.default({}),
|
|
7262
8135
|
description: z2.string().optional(),
|
|
7263
8136
|
examples: z2.string().default("examples"),
|
|
7264
8137
|
export: exportConfigSchema.default(false),
|
|
7265
8138
|
favicon: faviconConfigSchema.optional(),
|
|
7266
8139
|
feedback: z2.boolean().default(true),
|
|
7267
|
-
footer: footerConfigSchema.default({}),
|
|
7268
8140
|
github: githubConfigSchema.optional(),
|
|
7269
8141
|
i18n: i18nConfigSchema.optional(),
|
|
7270
|
-
icons: iconsConfigSchema.default({}),
|
|
7271
8142
|
lastModified: lastModifiedConfigSchema.default(false),
|
|
7272
8143
|
logo: logoConfigSchema.optional(),
|
|
7273
8144
|
markdown: markdownConfigSchema.default({}),
|
|
7274
8145
|
mcp: mcpConfigSchema.default({}),
|
|
7275
|
-
navbar: navbarConfigSchema.default({}),
|
|
7276
8146
|
navigation: navigationConfigSchema.default({}),
|
|
7277
8147
|
openapi: openapiConfigSchema.default({}),
|
|
7278
8148
|
redirects: z2.array(redirectSchema).default([]),
|
|
7279
8149
|
search: searchConfigSchema.default({}),
|
|
7280
8150
|
seo: seoConfigSchema.default({}),
|
|
7281
|
-
styling: stylingConfigSchema.default({}),
|
|
7282
8151
|
theme: themeConfigSchema.default({}),
|
|
7283
8152
|
title: z2.string().default("Documentation"),
|
|
8153
|
+
toc: tocConfigSchema,
|
|
7284
8154
|
variables: variablesConfigSchema
|
|
7285
8155
|
}).strict();
|
|
7286
8156
|
|
|
@@ -7310,9 +8180,11 @@ var loadConfig = async (root, options = {}) => {
|
|
|
7310
8180
|
const sourceFile = bridge?.configFile ?? configFile;
|
|
7311
8181
|
const parsed = blumeConfigSchema.safeParse(raw ?? {});
|
|
7312
8182
|
if (!parsed.success) {
|
|
8183
|
+
const source = sourceFile && existsSync9(sourceFile) ? readFileSync6(sourceFile, "utf-8") : undefined;
|
|
7313
8184
|
const diagnostics = diagnosticsFromZod(parsed.error, {
|
|
7314
8185
|
code: "BLUME_CONFIG_INVALID",
|
|
7315
|
-
file: sourceFile ?? undefined
|
|
8186
|
+
file: sourceFile ?? undefined,
|
|
8187
|
+
source
|
|
7316
8188
|
});
|
|
7317
8189
|
throw new BlumeError(diagnostics[0] ?? {
|
|
7318
8190
|
code: "BLUME_CONFIG_INVALID",
|
|
@@ -7337,7 +8209,7 @@ var loadConfig = async (root, options = {}) => {
|
|
|
7337
8209
|
};
|
|
7338
8210
|
|
|
7339
8211
|
// src/core/navigation.ts
|
|
7340
|
-
import { extname as
|
|
8212
|
+
import { extname as extname3 } from "pathe";
|
|
7341
8213
|
var NUMERIC_PREFIX = /^(?<order>\d+)[-_.]/u;
|
|
7342
8214
|
var GROUP_FOLDER = /^\((?<label>.+)\)$/u;
|
|
7343
8215
|
var WORD_SPLIT = /[-_]/u;
|
|
@@ -7374,7 +8246,7 @@ var pageOrder = (page, filename) => {
|
|
|
7374
8246
|
if (page.meta.sidebar.order !== undefined) {
|
|
7375
8247
|
return page.meta.sidebar.order;
|
|
7376
8248
|
}
|
|
7377
|
-
if (filename.replace(
|
|
8249
|
+
if (filename.replace(extname3(filename), "") === "index") {
|
|
7378
8250
|
return Number.NEGATIVE_INFINITY;
|
|
7379
8251
|
}
|
|
7380
8252
|
return numericOrder(filename);
|
|
@@ -7466,7 +8338,7 @@ var buildFileSystemSidebar = (pages, folderMeta, sharedMeta, metaPrefix) => {
|
|
|
7466
8338
|
deprecated: page.meta.deprecated || undefined,
|
|
7467
8339
|
description: page.description,
|
|
7468
8340
|
icon: page.meta.sidebar.icon,
|
|
7469
|
-
key: segmentKey(filename.replace(
|
|
8341
|
+
key: segmentKey(filename.replace(extname3(filename), "")),
|
|
7470
8342
|
kind: "page",
|
|
7471
8343
|
label: page.meta.sidebar.label ?? page.title,
|
|
7472
8344
|
order: pageOrder(page, filename),
|
|
@@ -7665,6 +8537,8 @@ var buildContentGraph = (pages, options) => {
|
|
|
7665
8537
|
tabs: options.navigation.tabs
|
|
7666
8538
|
});
|
|
7667
8539
|
}
|
|
8540
|
+
diagnostics.push(...validateNavIcons(navigation));
|
|
8541
|
+
diagnostics.push(...validateNavStructure(navigation, pages));
|
|
7668
8542
|
return {
|
|
7669
8543
|
diagnostics,
|
|
7670
8544
|
navigation,
|
|
@@ -7676,7 +8550,7 @@ var buildContentGraph = (pages, options) => {
|
|
|
7676
8550
|
|
|
7677
8551
|
// src/core/last-modified.ts
|
|
7678
8552
|
import { execFileSync } from "node:child_process";
|
|
7679
|
-
import { relative as
|
|
8553
|
+
import { relative as relative8 } from "pathe";
|
|
7680
8554
|
var resolveLastModifiedConfig = (value) => {
|
|
7681
8555
|
if (value === false) {
|
|
7682
8556
|
return { enabled: false, source: "git" };
|
|
@@ -7716,7 +8590,7 @@ var gitLastModifiedTimes = (root, contentRoot, sourcePaths) => {
|
|
|
7716
8590
|
const byRepoPath = parseGitLog(output);
|
|
7717
8591
|
const result = new Map;
|
|
7718
8592
|
for (const sourcePath of sourcePaths) {
|
|
7719
|
-
const iso = byRepoPath.get(
|
|
8593
|
+
const iso = byRepoPath.get(relative8(gitRoot, sourcePath));
|
|
7720
8594
|
if (iso) {
|
|
7721
8595
|
result.set(sourcePath, iso);
|
|
7722
8596
|
}
|
|
@@ -7728,7 +8602,7 @@ var gitLastModifiedTimes = (root, contentRoot, sourcePaths) => {
|
|
|
7728
8602
|
};
|
|
7729
8603
|
|
|
7730
8604
|
// src/core/meta.ts
|
|
7731
|
-
import { basename as basename3, dirname as
|
|
8605
|
+
import { basename as basename3, dirname as dirname9, relative as relative9 } from "pathe";
|
|
7732
8606
|
import { glob as glob5 } from "tinyglobby";
|
|
7733
8607
|
var META_FILES = [
|
|
7734
8608
|
"**/meta.ts",
|
|
@@ -7758,7 +8632,7 @@ var discoverFolderMeta = async (contentRoot) => {
|
|
|
7758
8632
|
const shared = new Map;
|
|
7759
8633
|
const diagnostics = [];
|
|
7760
8634
|
for (const entry of loaded) {
|
|
7761
|
-
const dir =
|
|
8635
|
+
const dir = relative9(contentRoot, dirname9(entry.file));
|
|
7762
8636
|
if (!entry.ok) {
|
|
7763
8637
|
diagnostics.push({
|
|
7764
8638
|
code: "BLUME_META_LOAD_FAILED",
|
|
@@ -7783,8 +8657,9 @@ var discoverFolderMeta = async (contentRoot) => {
|
|
|
7783
8657
|
};
|
|
7784
8658
|
|
|
7785
8659
|
// src/core/sources/normalize.ts
|
|
8660
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7 } from "node:fs";
|
|
7786
8661
|
import GithubSlugger from "github-slugger";
|
|
7787
|
-
import { extname as
|
|
8662
|
+
import { extname as extname4 } from "pathe";
|
|
7788
8663
|
var NUMERIC_PREFIX2 = /^\d+[-_.]/u;
|
|
7789
8664
|
var GROUP_FOLDER2 = /^\((?<label>.+)\)$/u;
|
|
7790
8665
|
var WORD_SPLIT2 = /[-_]/u;
|
|
@@ -7793,7 +8668,7 @@ var groupLabel = (segment) => segment.match(GROUP_FOLDER2)?.groups?.label ?? nul
|
|
|
7793
8668
|
var slugify2 = (text) => text.toLowerCase().trim().replaceAll(/[^\w\s-]/gu, "").replaceAll(/[\s_]+/gu, "-").replaceAll(/-+/gu, "-").replaceAll(/^-|-$/gu, "");
|
|
7794
8669
|
var titleCase = (value) => value.split(WORD_SPLIT2).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
7795
8670
|
var mapRoute = (relativePath) => {
|
|
7796
|
-
const withoutExt = relativePath.slice(0, relativePath.length -
|
|
8671
|
+
const withoutExt = relativePath.slice(0, relativePath.length - extname4(relativePath).length);
|
|
7797
8672
|
const rawParts = withoutExt.split("/");
|
|
7798
8673
|
const segments = [];
|
|
7799
8674
|
const groups = [];
|
|
@@ -7840,10 +8715,39 @@ var MD_LINK = /\[[^\]]*\]\((?<target>[^)\s]+)(?:\s+"[^"]*")?\)/gu;
|
|
|
7840
8715
|
var extractLinks = (body) => {
|
|
7841
8716
|
const links = [];
|
|
7842
8717
|
let inFence = false;
|
|
7843
|
-
let lineNumber = 0;
|
|
8718
|
+
let lineNumber = 0;
|
|
8719
|
+
for (const line of body.split(`
|
|
8720
|
+
`)) {
|
|
8721
|
+
lineNumber += 1;
|
|
8722
|
+
if (CODE_FENCE2.test(line.trimStart())) {
|
|
8723
|
+
inFence = !inFence;
|
|
8724
|
+
continue;
|
|
8725
|
+
}
|
|
8726
|
+
if (inFence) {
|
|
8727
|
+
continue;
|
|
8728
|
+
}
|
|
8729
|
+
for (const match of line.matchAll(MD_LINK)) {
|
|
8730
|
+
const target = match.groups?.target;
|
|
8731
|
+
if (target === undefined || match.index === undefined) {
|
|
8732
|
+
continue;
|
|
8733
|
+
}
|
|
8734
|
+
links.push({
|
|
8735
|
+
column: line.indexOf(target, match.index) + 1,
|
|
8736
|
+
line: lineNumber,
|
|
8737
|
+
target
|
|
8738
|
+
});
|
|
8739
|
+
}
|
|
8740
|
+
}
|
|
8741
|
+
return links;
|
|
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;
|
|
7844
8749
|
for (const line of body.split(`
|
|
7845
8750
|
`)) {
|
|
7846
|
-
lineNumber += 1;
|
|
7847
8751
|
if (CODE_FENCE2.test(line.trimStart())) {
|
|
7848
8752
|
inFence = !inFence;
|
|
7849
8753
|
continue;
|
|
@@ -7851,19 +8755,15 @@ var extractLinks = (body) => {
|
|
|
7851
8755
|
if (inFence) {
|
|
7852
8756
|
continue;
|
|
7853
8757
|
}
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
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);
|
|
7858
8763
|
}
|
|
7859
|
-
links.push({
|
|
7860
|
-
column: line.indexOf(target, match.index) + 1,
|
|
7861
|
-
line: lineNumber,
|
|
7862
|
-
target
|
|
7863
|
-
});
|
|
7864
8764
|
}
|
|
7865
8765
|
}
|
|
7866
|
-
return
|
|
8766
|
+
return [...tags];
|
|
7867
8767
|
};
|
|
7868
8768
|
var deriveTitle = (meta, headings, id2) => {
|
|
7869
8769
|
if (meta.title) {
|
|
@@ -7874,18 +8774,20 @@ var deriveTitle = (meta, headings, id2) => {
|
|
|
7874
8774
|
return firstHeading.text;
|
|
7875
8775
|
}
|
|
7876
8776
|
const base = id2.split("/").pop() ?? id2;
|
|
7877
|
-
return titleCase(stripNumericPrefix(base.replace(
|
|
8777
|
+
return titleCase(stripNumericPrefix(base.replace(extname4(base), "")));
|
|
7878
8778
|
};
|
|
7879
8779
|
var withPrefix = (prefix, path) => prefix ? `${prefix}/${path}` : path;
|
|
7880
|
-
var
|
|
8780
|
+
var normalizeEntry2 = (entry, ctx) => {
|
|
7881
8781
|
const { format } = entry.body;
|
|
7882
8782
|
const ext = format === "mdx" ? ".mdx" : ".md";
|
|
7883
8783
|
const result = pageMetaSchema.safeParse(entry.data);
|
|
7884
8784
|
if (!result.success) {
|
|
8785
|
+
const source = entry.raw ?? (entry.sourcePath && existsSync10(entry.sourcePath) ? readFileSync7(entry.sourcePath, "utf-8") : undefined);
|
|
7885
8786
|
return {
|
|
7886
8787
|
diagnostics: diagnosticsFromZod(result.error, {
|
|
7887
8788
|
code: "BLUME_FRONTMATTER_INVALID",
|
|
7888
|
-
file: entry.sourcePath ?? `${ctx.source.name}:${entry.ref}
|
|
8789
|
+
file: entry.sourcePath ?? `${ctx.source.name}:${entry.ref}`,
|
|
8790
|
+
source
|
|
7889
8791
|
}),
|
|
7890
8792
|
pages: []
|
|
7891
8793
|
};
|
|
@@ -7901,6 +8803,7 @@ var normalizeEntry = (entry, ctx) => {
|
|
|
7901
8803
|
const base = {
|
|
7902
8804
|
body: staged ? { format, text: entry.raw ?? entry.body.text } : undefined,
|
|
7903
8805
|
collection: staged ? "staged" : undefined,
|
|
8806
|
+
componentsUsed: format === "mdx" ? extractComponentTags(entry.body.text) : undefined,
|
|
7904
8807
|
contentType: meta.type ?? ctx.defaultType,
|
|
7905
8808
|
description: meta.description,
|
|
7906
8809
|
editUrl: entry.editUrl,
|
|
@@ -7931,12 +8834,12 @@ var normalizeEntry = (entry, ctx) => {
|
|
|
7931
8834
|
import { join as join22 } from "pathe";
|
|
7932
8835
|
|
|
7933
8836
|
// src/core/sources/filesystem.ts
|
|
7934
|
-
import { existsSync as
|
|
8837
|
+
import { existsSync as existsSync11, watch as fsWatch } from "node:fs";
|
|
7935
8838
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
7936
|
-
import { extname as
|
|
8839
|
+
import { extname as extname5, isAbsolute as isAbsolute5, join as join14, relative as relative10, resolve as resolve6 } from "pathe";
|
|
7937
8840
|
import { glob as glob6 } from "tinyglobby";
|
|
7938
8841
|
var filesystemSource = (options) => {
|
|
7939
|
-
const contentRoot =
|
|
8842
|
+
const contentRoot = isAbsolute5(options.root) ? options.root : join14(resolve6(options.projectRoot), options.root);
|
|
7940
8843
|
const load2 = async () => {
|
|
7941
8844
|
const files = await glob6(options.include, {
|
|
7942
8845
|
absolute: true,
|
|
@@ -7947,20 +8850,20 @@ var filesystemSource = (options) => {
|
|
|
7947
8850
|
files.sort();
|
|
7948
8851
|
const entries = await Promise.all(files.map(async (file) => {
|
|
7949
8852
|
const source = await readFile10(file, "utf-8");
|
|
7950
|
-
const ext =
|
|
8853
|
+
const ext = extname5(file).toLowerCase();
|
|
7951
8854
|
const format = ext === ".mdx" ? "mdx" : "md";
|
|
7952
8855
|
const parsed = frontmatter_default(source);
|
|
7953
8856
|
return {
|
|
7954
8857
|
body: { format, text: parsed.content },
|
|
7955
8858
|
data: parsed.data,
|
|
7956
|
-
ref:
|
|
8859
|
+
ref: relative10(contentRoot, file),
|
|
7957
8860
|
sourcePath: file
|
|
7958
8861
|
};
|
|
7959
8862
|
}));
|
|
7960
8863
|
return { diagnostics: [], entries };
|
|
7961
8864
|
};
|
|
7962
8865
|
const validate = () => {
|
|
7963
|
-
if (!
|
|
8866
|
+
if (!existsSync11(contentRoot)) {
|
|
7964
8867
|
throw new BlumeError({
|
|
7965
8868
|
code: options.missingCode ?? "BLUME_CONTENT_ROOT_MISSING",
|
|
7966
8869
|
file: contentRoot,
|
|
@@ -7971,7 +8874,7 @@ var filesystemSource = (options) => {
|
|
|
7971
8874
|
}
|
|
7972
8875
|
};
|
|
7973
8876
|
const watch = (onChange) => {
|
|
7974
|
-
if (!
|
|
8877
|
+
if (!existsSync11(contentRoot)) {
|
|
7975
8878
|
return () => {};
|
|
7976
8879
|
}
|
|
7977
8880
|
const watcher = fsWatch(contentRoot, { recursive: true }, onChange);
|
|
@@ -8305,13 +9208,13 @@ var mdxRemoteSource = (options, ctx) => {
|
|
|
8305
9208
|
};
|
|
8306
9209
|
|
|
8307
9210
|
// src/core/sources/mintlify.ts
|
|
8308
|
-
import { existsSync as
|
|
9211
|
+
import { existsSync as existsSync13, watch as fsWatch2 } from "node:fs";
|
|
8309
9212
|
import { readFile as readFile13 } from "node:fs/promises";
|
|
8310
|
-
import { isAbsolute as
|
|
9213
|
+
import { isAbsolute as isAbsolute6, join as join18, relative as relative13, resolve as resolve8 } from "pathe";
|
|
8311
9214
|
import { glob as glob7 } from "tinyglobby";
|
|
8312
9215
|
|
|
8313
9216
|
// src/migrate/shared.ts
|
|
8314
|
-
import { existsSync as
|
|
9217
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
8315
9218
|
import { readFile as readFile12, writeFile as writeFile4 } from "node:fs/promises";
|
|
8316
9219
|
import { join as join16 } from "pathe";
|
|
8317
9220
|
var writeBlumeConfig = async (root, config) => {
|
|
@@ -8328,7 +9231,7 @@ var BLUME_SCRIPTS = {
|
|
|
8328
9231
|
};
|
|
8329
9232
|
var rewriteFrameworkScripts = async (root, cli, remove) => {
|
|
8330
9233
|
const pkgPath = join16(root, "package.json");
|
|
8331
|
-
if (!
|
|
9234
|
+
if (!existsSync12(pkgPath)) {
|
|
8332
9235
|
return false;
|
|
8333
9236
|
}
|
|
8334
9237
|
let pkg;
|
|
@@ -8364,7 +9267,7 @@ var rewriteFrameworkScripts = async (root, cli, remove) => {
|
|
|
8364
9267
|
var gitignoreKey = (line) => line.trim().replace(/\/+$/u, "");
|
|
8365
9268
|
var ensureGitignore = async (root, entries) => {
|
|
8366
9269
|
const path = join16(root, ".gitignore");
|
|
8367
|
-
const existing =
|
|
9270
|
+
const existing = existsSync12(path) ? await readFile12(path, "utf-8") : "";
|
|
8368
9271
|
const present = new Set(existing.split(`
|
|
8369
9272
|
`).map(gitignoreKey).filter(Boolean));
|
|
8370
9273
|
const added = entries.filter((entry) => !present.has(gitignoreKey(entry)));
|
|
@@ -8379,7 +9282,7 @@ var ensureGitignore = async (root, entries) => {
|
|
|
8379
9282
|
`, "utf-8");
|
|
8380
9283
|
return added;
|
|
8381
9284
|
};
|
|
8382
|
-
var leftoverFiles = (root, candidates) => candidates.filter((candidate) =>
|
|
9285
|
+
var leftoverFiles = (root, candidates) => candidates.filter((candidate) => existsSync12(join16(root, candidate)));
|
|
8383
9286
|
var attribute = (attrs, name) => {
|
|
8384
9287
|
const match = attrs.match(new RegExp(`\\b${name}=(?:"(?<dq>[^"]*)"|'(?<sq>[^']*)')`, "u"));
|
|
8385
9288
|
return match?.groups?.dq ?? match?.groups?.sq;
|
|
@@ -8422,7 +9325,7 @@ var findOpenTagEnd = (source, from) => {
|
|
|
8422
9325
|
}
|
|
8423
9326
|
return -1;
|
|
8424
9327
|
};
|
|
8425
|
-
var
|
|
9328
|
+
var directiveFor2 = (tag, attrs, options) => {
|
|
8426
9329
|
if (tag in options.tagDirectives) {
|
|
8427
9330
|
return options.tagDirectives[tag];
|
|
8428
9331
|
}
|
|
@@ -8452,7 +9355,7 @@ var rewriteCallouts = (source, options) => {
|
|
|
8452
9355
|
continue;
|
|
8453
9356
|
}
|
|
8454
9357
|
const attrs = source.slice(start + tag.length + 1, openEnd);
|
|
8455
|
-
const directive =
|
|
9358
|
+
const directive = directiveFor2(tag, attrs, options);
|
|
8456
9359
|
const closeTag = `</${tag}>`;
|
|
8457
9360
|
const selfClosing = attrs.trimEnd().endsWith("/");
|
|
8458
9361
|
const closeIndex = selfClosing ? openEnd : source.indexOf(closeTag, openEnd + 1);
|
|
@@ -8776,7 +9679,7 @@ var isLiteralObject = (value) => typeof value === "object" && value !== null &&
|
|
|
8776
9679
|
var asLiteralArray = (value) => Array.isArray(value) ? value : undefined;
|
|
8777
9680
|
|
|
8778
9681
|
// src/migrate/mintlify/content.ts
|
|
8779
|
-
import { dirname as
|
|
9682
|
+
import { dirname as dirname10, join as join17, relative as relative11 } from "pathe";
|
|
8780
9683
|
var CALLOUT_DIRECTIVES = {
|
|
8781
9684
|
Check: "success",
|
|
8782
9685
|
Danger: "danger",
|
|
@@ -8814,7 +9717,7 @@ var rewriteSnippetImports = (source, options) => {
|
|
|
8814
9717
|
}
|
|
8815
9718
|
const target = join17(options.root, importSource.replace(/^\/+/u, ""));
|
|
8816
9719
|
components.push(importSource.replace(/^\/+/u, ""));
|
|
8817
|
-
let rel =
|
|
9720
|
+
let rel = relative11(dirname10(options.filePath), target);
|
|
8818
9721
|
if (!rel.startsWith(".")) {
|
|
8819
9722
|
rel = `./${rel}`;
|
|
8820
9723
|
}
|
|
@@ -9004,7 +9907,7 @@ var rewriteMintlifySvgIconProps = (source) => {
|
|
|
9004
9907
|
|
|
9005
9908
|
// src/migrate/mintlify/snippets.ts
|
|
9006
9909
|
import { readFile as readFileFromDisk } from "node:fs/promises";
|
|
9007
|
-
import { dirname as
|
|
9910
|
+
import { dirname as dirname11, relative as relative12, resolve as resolve7 } from "pathe";
|
|
9008
9911
|
var MARKDOWN_SNIPPET_IMPORT = /^import\s+(?<name>[$A-Z_a-z][$\w]*)\s+from\s+["'](?<source>[^"']+\.mdx?)["'];?\s*$/gmu;
|
|
9009
9912
|
var NAMED_SNIPPET_IMPORT = /^import\s+\{(?<names>[^}]+)\}\s+from\s+["'](?<source>[^"']+\.mdx?)["'];?\s*$/gmu;
|
|
9010
9913
|
var EXPORTED_STRING_CONST = /^export\s+const\s+(?<name>[$A-Z_a-z][$\w]*)\s*=\s*(?:"(?<double>(?:\\.|[^"\\])*)"|'(?<single>(?:\\.|[^'\\])*)'|`(?<template>(?:\\.|[^`\\])*)`)\s*;?\s*$/gmu;
|
|
@@ -9014,14 +9917,14 @@ var GLOBAL_VARIABLE = /\{\{\s*(?<name>[A-Za-z0-9-]+)\s*\}\}/gu;
|
|
|
9014
9917
|
var FRONTMATTER_BLOCK = /^---\r?\n[\s\S]*?\r?\n---\r?\n?/u;
|
|
9015
9918
|
var USER_EXPORT = /^(?:export\s+)?(?:const|let|var)\s+user\s*=|^import\s+\{\s*user\s*\}/mu;
|
|
9016
9919
|
var isInsideRoot2 = (root, candidate) => {
|
|
9017
|
-
const rel =
|
|
9920
|
+
const rel = relative12(root, candidate);
|
|
9018
9921
|
return rel === "" || !rel.startsWith("..") && !rel.startsWith("/");
|
|
9019
9922
|
};
|
|
9020
|
-
var
|
|
9021
|
-
var snippetSelfClosingTagPattern = (name) => new RegExp(`<${
|
|
9022
|
-
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");
|
|
9023
9926
|
var rootRelativePath = (root, file) => {
|
|
9024
|
-
const rel =
|
|
9927
|
+
const rel = relative12(root, file);
|
|
9025
9928
|
return rel ? `/${rel}` : "/";
|
|
9026
9929
|
};
|
|
9027
9930
|
var snippetCycleMessage = (root, file, trail) => {
|
|
@@ -9030,10 +9933,10 @@ var snippetCycleMessage = (root, file, trail) => {
|
|
|
9030
9933
|
return `Circular Mintlify snippet import detected: ${cycle}`;
|
|
9031
9934
|
};
|
|
9032
9935
|
var resolveSnippetPath = (options) => {
|
|
9033
|
-
const target = options.source.startsWith("/") ?
|
|
9936
|
+
const target = options.source.startsWith("/") ? resolve7(options.root, options.source.slice(1)) : resolve7(dirname11(options.filePath), options.source);
|
|
9034
9937
|
return isInsideRoot2(options.root, target) ? target : null;
|
|
9035
9938
|
};
|
|
9036
|
-
var
|
|
9939
|
+
var collectImports2 = (source) => [...source.matchAll(MARKDOWN_SNIPPET_IMPORT)].flatMap((match) => {
|
|
9037
9940
|
const name = match.groups?.name;
|
|
9038
9941
|
const importSource = match.groups?.source;
|
|
9039
9942
|
if (!(name && importSource)) {
|
|
@@ -9081,7 +9984,7 @@ var interpolateProps = (source, props) => source.replaceAll(PLACEHOLDER, (value,
|
|
|
9081
9984
|
var stripImport = (source, importText) => source.replace(importText, "").replaceAll(/\n{3,}/gu, `
|
|
9082
9985
|
|
|
9083
9986
|
`);
|
|
9084
|
-
var replacePlaceholder = (source, name, value) => source.replaceAll(new RegExp(`\\{${
|
|
9987
|
+
var replacePlaceholder = (source, name, value) => source.replaceAll(new RegExp(`\\{${escapeRegExp2(name)}\\}`, "gu"), value);
|
|
9085
9988
|
var inlineSnippetTags = (options) => {
|
|
9086
9989
|
const inline = (_value, attrs) => interpolateProps(options.snippet, parseAttributes(attrs));
|
|
9087
9990
|
return options.source.replaceAll(snippetSelfClosingTagPattern(options.name), inline).replaceAll(snippetPairedTagPattern(options.name), inline);
|
|
@@ -9125,7 +10028,7 @@ var rewriteMintlifyMarkdownSnippets = async (source, options) => {
|
|
|
9125
10028
|
});
|
|
9126
10029
|
return next === current ? current : stripImport(next, snippetImport.importText);
|
|
9127
10030
|
};
|
|
9128
|
-
const imports =
|
|
10031
|
+
const imports = collectImports2(source);
|
|
9129
10032
|
const inlineAt = async (index, current) => {
|
|
9130
10033
|
const snippetImport = imports[index];
|
|
9131
10034
|
if (!snippetImport) {
|
|
@@ -9224,11 +10127,11 @@ var MINTLIFY_SOURCE_IGNORES = [
|
|
|
9224
10127
|
"snippets/**"
|
|
9225
10128
|
];
|
|
9226
10129
|
var mintlifySource = (options) => {
|
|
9227
|
-
const contentRoot =
|
|
10130
|
+
const contentRoot = isAbsolute6(options.root) ? options.root : join18(resolve8(options.projectRoot), options.root);
|
|
9228
10131
|
const ignore = [...new Set([...options.exclude, ...MINTLIFY_SOURCE_IGNORES])];
|
|
9229
10132
|
const transform = (raw, file) => transformMintlifyContent(raw, {
|
|
9230
10133
|
filePath: file,
|
|
9231
|
-
root:
|
|
10134
|
+
root: resolve8(options.projectRoot),
|
|
9232
10135
|
variables: options.variables
|
|
9233
10136
|
});
|
|
9234
10137
|
const load2 = async () => {
|
|
@@ -9250,7 +10153,7 @@ var mintlifySource = (options) => {
|
|
|
9250
10153
|
body: { format: "mdx", text: parsed.content },
|
|
9251
10154
|
data: parsed.data,
|
|
9252
10155
|
raw: result.content,
|
|
9253
|
-
ref:
|
|
10156
|
+
ref: relative13(contentRoot, file),
|
|
9254
10157
|
sourcePath: file
|
|
9255
10158
|
};
|
|
9256
10159
|
}));
|
|
@@ -9264,7 +10167,7 @@ var mintlifySource = (options) => {
|
|
|
9264
10167
|
return { diagnostics, entries };
|
|
9265
10168
|
};
|
|
9266
10169
|
const validate = () => {
|
|
9267
|
-
if (!
|
|
10170
|
+
if (!existsSync13(contentRoot)) {
|
|
9268
10171
|
throw new BlumeError({
|
|
9269
10172
|
code: "BLUME_CONTENT_ROOT_MISSING",
|
|
9270
10173
|
file: contentRoot,
|
|
@@ -9276,11 +10179,11 @@ var mintlifySource = (options) => {
|
|
|
9276
10179
|
};
|
|
9277
10180
|
const watch = (onChange) => {
|
|
9278
10181
|
const disposers = [];
|
|
9279
|
-
if (
|
|
10182
|
+
if (existsSync13(contentRoot)) {
|
|
9280
10183
|
const watcher = fsWatch2(contentRoot, { recursive: true }, onChange);
|
|
9281
10184
|
disposers.push(() => watcher.close());
|
|
9282
10185
|
}
|
|
9283
|
-
if (options.configFile &&
|
|
10186
|
+
if (options.configFile && existsSync13(options.configFile)) {
|
|
9284
10187
|
const watcher = fsWatch2(options.configFile, onChange);
|
|
9285
10188
|
disposers.push(() => watcher.close());
|
|
9286
10189
|
}
|
|
@@ -9312,13 +10215,13 @@ import { join as join20 } from "pathe";
|
|
|
9312
10215
|
|
|
9313
10216
|
// src/core/sources/assets.ts
|
|
9314
10217
|
import { mkdir as mkdir4, writeFile as writeFile5 } from "node:fs/promises";
|
|
9315
|
-
import { extname as
|
|
10218
|
+
import { extname as extname6, join as join19 } from "pathe";
|
|
9316
10219
|
var MD_IMAGE = /!\[(?<alt>[^\]]*)\]\((?<url>[^)\s]+)\)/gu;
|
|
9317
10220
|
var REMOTE = /^https?:\/\//u;
|
|
9318
10221
|
var SAFE_EXT = /^\.[a-z0-9]+$/iu;
|
|
9319
10222
|
var extFor = (url) => {
|
|
9320
10223
|
const clean = url.split("?")[0] ?? url;
|
|
9321
|
-
const ext =
|
|
10224
|
+
const ext = extname6(clean);
|
|
9322
10225
|
return SAFE_EXT.test(ext) ? ext.toLowerCase() : ".png";
|
|
9323
10226
|
};
|
|
9324
10227
|
var materializeAssets = async (markdown, ctx) => {
|
|
@@ -9919,12 +10822,32 @@ var resolveSources = (config, context, runtime) => {
|
|
|
9919
10822
|
};
|
|
9920
10823
|
|
|
9921
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
|
+
};
|
|
9922
10843
|
var scanProject = async (root, options = {}) => {
|
|
9923
10844
|
const mode = options.mode ?? "dev";
|
|
9924
10845
|
const preview = options.preview ?? false;
|
|
9925
|
-
const
|
|
10846
|
+
const configResult = await loadConfig(root, {
|
|
9926
10847
|
devServerUrl: options.devServerUrl
|
|
9927
10848
|
});
|
|
10849
|
+
const { bridge } = configResult;
|
|
10850
|
+
const config = applyConfigOverrides(configResult.config, options.overrides);
|
|
9928
10851
|
const context = resolveProjectContext(root, config);
|
|
9929
10852
|
const sources = resolveSources(config, context, {
|
|
9930
10853
|
mode,
|
|
@@ -9943,7 +10866,7 @@ var scanProject = async (root, options = {}) => {
|
|
|
9943
10866
|
for (const { source, entries, diagnostics } of loaded) {
|
|
9944
10867
|
contentDiagnostics.push(...diagnostics);
|
|
9945
10868
|
for (const entry of entries) {
|
|
9946
|
-
const normalized =
|
|
10869
|
+
const normalized = normalizeEntry2(entry, {
|
|
9947
10870
|
defaultType: config.content.defaultType,
|
|
9948
10871
|
i18n: config.i18n,
|
|
9949
10872
|
source: {
|
|
@@ -9993,13 +10916,13 @@ var scanProject = async (root, options = {}) => {
|
|
|
9993
10916
|
};
|
|
9994
10917
|
|
|
9995
10918
|
// src/cli/env.ts
|
|
9996
|
-
import { existsSync as
|
|
9997
|
-
import { dirname as
|
|
10919
|
+
import { existsSync as existsSync14, readFileSync as readFileSync8 } from "node:fs";
|
|
10920
|
+
import { dirname as dirname12, join as join23, resolve as resolve9 } from "pathe";
|
|
9998
10921
|
var ENV_LINE = /^\s*(?:export\s+)?(?<key>[A-Za-z_][A-Za-z0-9_]*)\s*=\s*(?<value>.*?)\s*$/u;
|
|
9999
|
-
var
|
|
10922
|
+
var DOUBLE_QUOTED2 = /^"(?<body>[\s\S]*)"$/u;
|
|
10000
10923
|
var SINGLE_QUOTED = /^'(?<body>[\s\S]*)'$/u;
|
|
10001
10924
|
var unquote = (raw) => {
|
|
10002
|
-
const double = raw.match(
|
|
10925
|
+
const double = raw.match(DOUBLE_QUOTED2)?.groups?.body;
|
|
10003
10926
|
if (double !== undefined) {
|
|
10004
10927
|
return double.replaceAll("\\n", `
|
|
10005
10928
|
`).replaceAll("\\t", "\t").replaceAll("\\\"", '"').replaceAll("\\\\", "\\");
|
|
@@ -10032,23 +10955,81 @@ var applyEnv = (parsed) => {
|
|
|
10032
10955
|
};
|
|
10033
10956
|
var loadFile = (path) => {
|
|
10034
10957
|
try {
|
|
10035
|
-
if (
|
|
10036
|
-
applyEnv(parseEnv(
|
|
10958
|
+
if (existsSync14(path)) {
|
|
10959
|
+
applyEnv(parseEnv(readFileSync8(path, "utf-8")));
|
|
10037
10960
|
}
|
|
10038
10961
|
} catch {}
|
|
10039
10962
|
};
|
|
10040
10963
|
var loadEnvFiles = (startDir) => {
|
|
10041
|
-
let dir =
|
|
10964
|
+
let dir = resolve9(startDir);
|
|
10042
10965
|
let done = false;
|
|
10043
10966
|
while (!done) {
|
|
10044
10967
|
loadFile(join23(dir, ".env.local"));
|
|
10045
10968
|
loadFile(join23(dir, ".env"));
|
|
10046
|
-
const parent =
|
|
10047
|
-
done =
|
|
10969
|
+
const parent = dirname12(dir);
|
|
10970
|
+
done = existsSync14(join23(dir, ".git")) || parent === dir;
|
|
10048
10971
|
dir = parent;
|
|
10049
10972
|
}
|
|
10050
10973
|
};
|
|
10051
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
|
+
|
|
10052
11033
|
// src/cli/prepare.ts
|
|
10053
11034
|
var prepareProject = async (options) => {
|
|
10054
11035
|
loadEnvFiles(options.root);
|
|
@@ -10057,15 +11038,17 @@ var prepareProject = async (options) => {
|
|
|
10057
11038
|
project = await scanProject(options.root, {
|
|
10058
11039
|
devServerUrl: options.devServerUrl,
|
|
10059
11040
|
mode: options.mode,
|
|
11041
|
+
overrides: options.overrides,
|
|
10060
11042
|
preview: options.preview,
|
|
10061
11043
|
refresh: options.refresh
|
|
10062
11044
|
});
|
|
10063
11045
|
} catch (error) {
|
|
10064
11046
|
if (error instanceof BlumeError) {
|
|
10065
11047
|
reportDiagnostics([error.diagnostic], options.root);
|
|
10066
|
-
|
|
11048
|
+
} else {
|
|
11049
|
+
reportInternalError(error);
|
|
10067
11050
|
}
|
|
10068
|
-
|
|
11051
|
+
process.exit(1);
|
|
10069
11052
|
}
|
|
10070
11053
|
if (options.mode === "build" && project.config.deployment.output === "static") {
|
|
10071
11054
|
const features = serverFeatures(project.config);
|
|
@@ -10093,12 +11076,102 @@ var prepareProject = async (options) => {
|
|
|
10093
11076
|
for (const warning of warnings) {
|
|
10094
11077
|
logger.warn(warning);
|
|
10095
11078
|
}
|
|
11079
|
+
reportDiagnostics(checkRequiredSecrets(project.config), options.root);
|
|
10096
11080
|
return project;
|
|
10097
11081
|
};
|
|
10098
11082
|
|
|
10099
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
|
+
};
|
|
10100
11149
|
var buildCommand = defineCommand2({
|
|
10101
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
|
+
},
|
|
10102
11175
|
preview: {
|
|
10103
11176
|
description: "Include drafts and unpublished CMS content.",
|
|
10104
11177
|
type: "boolean"
|
|
@@ -10111,8 +11184,21 @@ var buildCommand = defineCommand2({
|
|
|
10111
11184
|
},
|
|
10112
11185
|
async run({ args }) {
|
|
10113
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
|
+
}
|
|
10114
11195
|
const project = await prepareProject({
|
|
10115
11196
|
mode: "build",
|
|
11197
|
+
overrides: {
|
|
11198
|
+
adapter: args.adapter,
|
|
11199
|
+
base: args.base,
|
|
11200
|
+
output: args.output
|
|
11201
|
+
},
|
|
10116
11202
|
preview: args.preview,
|
|
10117
11203
|
root,
|
|
10118
11204
|
strict: args.strict
|
|
@@ -10142,15 +11228,16 @@ var buildCommand = defineCommand2({
|
|
|
10142
11228
|
logger.success("Generated llms.txt and llms-full.txt");
|
|
10143
11229
|
}
|
|
10144
11230
|
const sitemap = buildSitemap(project);
|
|
10145
|
-
if (sitemap && !
|
|
11231
|
+
if (sitemap && !existsSync15(join24(distDir, "sitemap.xml"))) {
|
|
10146
11232
|
await writeFile6(join24(distDir, "sitemap.xml"), sitemap, "utf-8");
|
|
10147
11233
|
logger.success("Generated sitemap.xml");
|
|
10148
11234
|
}
|
|
10149
11235
|
const robots = buildRobots(project);
|
|
10150
|
-
if (robots && !
|
|
11236
|
+
if (robots && !existsSync15(join24(distDir, "robots.txt"))) {
|
|
10151
11237
|
await writeFile6(join24(distDir, "robots.txt"), robots, "utf-8");
|
|
10152
11238
|
logger.success("Generated robots.txt");
|
|
10153
11239
|
}
|
|
11240
|
+
await emitRedirectFiles(project.config, distDir);
|
|
10154
11241
|
const { config } = project;
|
|
10155
11242
|
const features = serverFeatures(config);
|
|
10156
11243
|
logger.box([
|
|
@@ -10165,16 +11252,113 @@ var buildCommand = defineCommand2({
|
|
|
10165
11252
|
`Server features ${features.length > 0 ? features.join(", ") : "none"}`
|
|
10166
11253
|
].join(`
|
|
10167
11254
|
`));
|
|
11255
|
+
if (args.analyze) {
|
|
11256
|
+
await reportBundleSizes(distDir);
|
|
11257
|
+
}
|
|
11258
|
+
if (await enforceBudget(distDir, args) === "fail") {
|
|
11259
|
+
process.exit(1);
|
|
11260
|
+
}
|
|
10168
11261
|
logger.success(`Built to ${distDir}`);
|
|
10169
11262
|
}
|
|
10170
11263
|
});
|
|
10171
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
|
+
|
|
10172
11313
|
// src/cli/commands/dev.ts
|
|
10173
11314
|
import { watch } from "node:fs";
|
|
10174
11315
|
import { dev } from "astro";
|
|
10175
|
-
import { defineCommand as
|
|
10176
|
-
|
|
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({
|
|
10177
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
|
+
},
|
|
10178
11362
|
host: { description: "Network host to bind.", type: "string" },
|
|
10179
11363
|
open: { description: "Open the browser on start.", type: "boolean" },
|
|
10180
11364
|
port: { description: "Port to listen on.", type: "string" },
|
|
@@ -10191,11 +11375,13 @@ var devCommand = defineCommand3({
|
|
|
10191
11375
|
async run({ args }) {
|
|
10192
11376
|
const root = process.cwd();
|
|
10193
11377
|
const preview = args.preview ?? false;
|
|
11378
|
+
const overrides = args["content-dir"] ? { contentRoot: args["content-dir"] } : undefined;
|
|
10194
11379
|
const port = args.port ? Number(args.port) : 4321;
|
|
10195
11380
|
const devServerUrl = `http://localhost:${port}`;
|
|
10196
11381
|
const project = await prepareProject({
|
|
10197
11382
|
devServerUrl,
|
|
10198
11383
|
mode: "dev",
|
|
11384
|
+
overrides,
|
|
10199
11385
|
preview,
|
|
10200
11386
|
root,
|
|
10201
11387
|
strict: args.strict
|
|
@@ -10204,7 +11390,7 @@ var devCommand = defineCommand3({
|
|
|
10204
11390
|
logger.info('Detected docs.json — running in Mintlify bridge mode (no migration). Run "blume migrate mintlify" to convert permanently.');
|
|
10205
11391
|
}
|
|
10206
11392
|
const server = await dev({
|
|
10207
|
-
logLevel: "info",
|
|
11393
|
+
logLevel: args.debug ? "debug" : "info",
|
|
10208
11394
|
root: project.context.outDir,
|
|
10209
11395
|
server: {
|
|
10210
11396
|
host: args.host ?? false,
|
|
@@ -10212,6 +11398,7 @@ var devCommand = defineCommand3({
|
|
|
10212
11398
|
port: args.port ? Number(args.port) : undefined
|
|
10213
11399
|
}
|
|
10214
11400
|
});
|
|
11401
|
+
showBlumeErrorOverlay(project.diagnostics);
|
|
10215
11402
|
let timer = null;
|
|
10216
11403
|
const regenerate = () => {
|
|
10217
11404
|
if (timer) {
|
|
@@ -10222,9 +11409,11 @@ var devCommand = defineCommand3({
|
|
|
10222
11409
|
const next = await scanProject(root, {
|
|
10223
11410
|
devServerUrl,
|
|
10224
11411
|
mode: "dev",
|
|
11412
|
+
overrides,
|
|
10225
11413
|
preview
|
|
10226
11414
|
});
|
|
10227
11415
|
await generateRuntime(next);
|
|
11416
|
+
showBlumeErrorOverlay(next.diagnostics);
|
|
10228
11417
|
} catch (error) {
|
|
10229
11418
|
logger.error(`Regeneration failed: ${error.message}`);
|
|
10230
11419
|
}
|
|
@@ -10256,14 +11445,20 @@ var devCommand = defineCommand3({
|
|
|
10256
11445
|
});
|
|
10257
11446
|
|
|
10258
11447
|
// src/cli/commands/doctor.ts
|
|
10259
|
-
import { defineCommand as
|
|
11448
|
+
import { defineCommand as defineCommand5 } from "citty";
|
|
10260
11449
|
var MIN_NODE_MAJOR = 20;
|
|
10261
|
-
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
|
+
},
|
|
10262
11457
|
meta: {
|
|
10263
11458
|
description: "Diagnose common configuration and content problems.",
|
|
10264
11459
|
name: "doctor"
|
|
10265
11460
|
},
|
|
10266
|
-
async run() {
|
|
11461
|
+
async run({ args }) {
|
|
10267
11462
|
const root = process.cwd();
|
|
10268
11463
|
const diagnostics = [];
|
|
10269
11464
|
const nodeMajor = Number.parseInt(process.versions.node.split(".")[0] ?? "0", 10);
|
|
@@ -10295,15 +11490,24 @@ var doctorCommand = defineCommand4({
|
|
|
10295
11490
|
suggestion: 'Set deployment.adapter (e.g. "vercel").'
|
|
10296
11491
|
});
|
|
10297
11492
|
}
|
|
10298
|
-
|
|
10299
|
-
|
|
10300
|
-
|
|
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
|
+
}
|
|
10301
11498
|
} catch (error) {
|
|
10302
11499
|
if (error instanceof BlumeError) {
|
|
10303
11500
|
diagnostics.push(error.diagnostic);
|
|
10304
11501
|
} else {
|
|
10305
|
-
|
|
11502
|
+
reportInternalError(error);
|
|
11503
|
+
process.exit(1);
|
|
11504
|
+
}
|
|
11505
|
+
}
|
|
11506
|
+
if (args.json) {
|
|
11507
|
+
if (reportDiagnosticsJson(diagnostics, root)) {
|
|
11508
|
+
process.exit(1);
|
|
10306
11509
|
}
|
|
11510
|
+
return;
|
|
10307
11511
|
}
|
|
10308
11512
|
const hadErrors = reportDiagnostics(diagnostics, root);
|
|
10309
11513
|
if (diagnostics.length === 0) {
|
|
@@ -10317,19 +11521,40 @@ var doctorCommand = defineCommand4({
|
|
|
10317
11521
|
|
|
10318
11522
|
// src/cli/commands/eject.ts
|
|
10319
11523
|
import { readFile as readFile15, writeFile as writeFile8 } from "node:fs/promises";
|
|
10320
|
-
import { defineCommand as
|
|
10321
|
-
import { join as
|
|
11524
|
+
import { defineCommand as defineCommand6 } from "citty";
|
|
11525
|
+
import { join as join27, relative as relative15 } from "pathe";
|
|
10322
11526
|
|
|
10323
11527
|
// src/registry/eject.ts
|
|
10324
|
-
import { existsSync as
|
|
11528
|
+
import { existsSync as existsSync17 } from "node:fs";
|
|
10325
11529
|
import { cp, mkdir as mkdir5, readFile as readFile14, rm as rm2, writeFile as writeFile7 } from "node:fs/promises";
|
|
10326
|
-
import { join as
|
|
11530
|
+
import { join as join26, relative as relative14 } from "pathe";
|
|
10327
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
|
+
};
|
|
10328
11553
|
var eject = async (root) => {
|
|
10329
11554
|
const project = await scanProject(root, { mode: "build" });
|
|
10330
11555
|
const { context, config } = project;
|
|
10331
|
-
const srcDir =
|
|
10332
|
-
const genDir =
|
|
11556
|
+
const srcDir = join26(root, "src");
|
|
11557
|
+
const genDir = join26(srcDir, "generated");
|
|
10333
11558
|
const askEnabled = config.ai.ask?.enabled ?? false;
|
|
10334
11559
|
const exportPdf = config.export.pdf;
|
|
10335
11560
|
const exportEpub = config.export.epub;
|
|
@@ -10350,13 +11575,13 @@ var eject = async (root) => {
|
|
|
10350
11575
|
const needsSvelte = frameworks.has("svelte");
|
|
10351
11576
|
const relContext = {
|
|
10352
11577
|
...context,
|
|
10353
|
-
contentRoot: POSIX(
|
|
11578
|
+
contentRoot: POSIX(relative14(root, context.contentRoot)),
|
|
10354
11579
|
outDir: ".",
|
|
10355
11580
|
root: "."
|
|
10356
11581
|
};
|
|
10357
|
-
const componentsImport = context.componentsFile ? `../../${POSIX(
|
|
11582
|
+
const componentsImport = context.componentsFile ? `../../${POSIX(relative14(root, context.componentsFile))}` : null;
|
|
10358
11583
|
const relPages = pages.map((page) => ({
|
|
10359
|
-
entrypoint: POSIX(
|
|
11584
|
+
entrypoint: POSIX(relative14(root, page.entrypoint)),
|
|
10360
11585
|
pattern: page.pattern
|
|
10361
11586
|
}));
|
|
10362
11587
|
const staged = collectStaged(project);
|
|
@@ -10377,13 +11602,13 @@ var eject = async (root) => {
|
|
|
10377
11602
|
searchClientPath: "./src/generated/search-client.ts",
|
|
10378
11603
|
themePath: "./src/generated/app.css"
|
|
10379
11604
|
}),
|
|
10380
|
-
path:
|
|
11605
|
+
path: join26(root, "astro.config.mjs")
|
|
10381
11606
|
},
|
|
10382
11607
|
{
|
|
10383
11608
|
content: runtimeTsconfigTemplate(),
|
|
10384
|
-
path:
|
|
11609
|
+
path: join26(root, "tsconfig.json")
|
|
10385
11610
|
},
|
|
10386
|
-
{ content: envTemplate(), path:
|
|
11611
|
+
{ content: envTemplate(), path: join26(srcDir, "env.d.ts") },
|
|
10387
11612
|
{
|
|
10388
11613
|
content: contentConfigTemplate({
|
|
10389
11614
|
config,
|
|
@@ -10391,28 +11616,29 @@ var eject = async (root) => {
|
|
|
10391
11616
|
staged: hasStaged,
|
|
10392
11617
|
stagedBase: stagedDir
|
|
10393
11618
|
}),
|
|
10394
|
-
path:
|
|
11619
|
+
path: join26(srcDir, "content.config.ts")
|
|
10395
11620
|
},
|
|
10396
11621
|
{
|
|
10397
11622
|
content: catchAllPageTemplate({
|
|
10398
11623
|
askEnabled,
|
|
10399
11624
|
exportEpub,
|
|
10400
11625
|
exportPdf,
|
|
10401
|
-
mathEnabled: config.markdown.math
|
|
11626
|
+
mathEnabled: config.markdown.math,
|
|
11627
|
+
needsReact
|
|
10402
11628
|
}),
|
|
10403
|
-
path:
|
|
11629
|
+
path: join26(srcDir, "pages", "[...slug].astro")
|
|
10404
11630
|
},
|
|
10405
11631
|
{
|
|
10406
|
-
content:
|
|
10407
|
-
path:
|
|
11632
|
+
content: planComponentSlots(componentsImport, null).module,
|
|
11633
|
+
path: join26(genDir, "components.ts")
|
|
10408
11634
|
},
|
|
10409
11635
|
{
|
|
10410
11636
|
content: islandMapTemplate(islands.islands),
|
|
10411
|
-
path:
|
|
11637
|
+
path: join26(genDir, "islands.ts")
|
|
10412
11638
|
},
|
|
10413
11639
|
{
|
|
10414
11640
|
content: exampleMapTemplate(examples.examples),
|
|
10415
|
-
path:
|
|
11641
|
+
path: join26(genDir, "examples.ts")
|
|
10416
11642
|
},
|
|
10417
11643
|
{
|
|
10418
11644
|
content: tailwindEntryTemplate({
|
|
@@ -10424,60 +11650,57 @@ var eject = async (root) => {
|
|
|
10424
11650
|
twoslashCss: twoslashCss(),
|
|
10425
11651
|
userTheme
|
|
10426
11652
|
}),
|
|
10427
|
-
path:
|
|
11653
|
+
path: join26(genDir, "app.css")
|
|
10428
11654
|
},
|
|
10429
|
-
{ content: buildRuntimeData(project), path:
|
|
11655
|
+
{ content: buildRuntimeData(project), path: join26(genDir, "data.json") },
|
|
10430
11656
|
{
|
|
10431
11657
|
content: `${JSON.stringify(rawMarkdown)}
|
|
10432
11658
|
`,
|
|
10433
|
-
path:
|
|
11659
|
+
path: join26(genDir, "raw-markdown.json")
|
|
10434
11660
|
},
|
|
10435
11661
|
{
|
|
10436
11662
|
content: rawMarkdownEndpointTemplate(),
|
|
10437
|
-
path:
|
|
11663
|
+
path: join26(srcDir, "pages", "[...slug].md.ts")
|
|
10438
11664
|
},
|
|
10439
11665
|
{
|
|
10440
11666
|
content: rawMarkdownEndpointTemplate(),
|
|
10441
|
-
path:
|
|
11667
|
+
path: join26(srcDir, "pages", "[...slug].mdx.ts")
|
|
10442
11668
|
}
|
|
10443
11669
|
];
|
|
10444
11670
|
if (askEnabled) {
|
|
10445
|
-
files.push(
|
|
10446
|
-
content: askEndpointTemplate(resolveAskBackend(config.ai.ask)),
|
|
10447
|
-
path: join25(srcDir, "pages", "api", "ask.ts")
|
|
10448
|
-
});
|
|
11671
|
+
files.push(...await askFiles(project, srcDir, genDir));
|
|
10449
11672
|
}
|
|
10450
11673
|
if (config.seo.og.enabled) {
|
|
10451
11674
|
files.push({
|
|
10452
|
-
content: ogEndpointTemplate(customOgRoutes(pages, config.title
|
|
10453
|
-
path:
|
|
11675
|
+
content: ogEndpointTemplate(customOgRoutes(pages, config.title)),
|
|
11676
|
+
path: join26(srcDir, "pages", "og", "[...slug].png.ts")
|
|
10454
11677
|
});
|
|
10455
11678
|
}
|
|
10456
11679
|
if (!routeIsTaken(pages, project.graph.pages, "/404")) {
|
|
10457
11680
|
files.push({
|
|
10458
11681
|
content: notFoundPageTemplate(),
|
|
10459
|
-
path:
|
|
11682
|
+
path: join26(srcDir, "pages", "404.astro")
|
|
10460
11683
|
});
|
|
10461
11684
|
}
|
|
10462
11685
|
files.push({
|
|
10463
11686
|
content: searchClientTemplate(config),
|
|
10464
|
-
path:
|
|
11687
|
+
path: join26(genDir, "search-client.ts")
|
|
10465
11688
|
});
|
|
10466
11689
|
if (servesStaticIndex(config.search.provider)) {
|
|
10467
11690
|
const documents = await buildSearchDocuments(project);
|
|
10468
11691
|
files.push({
|
|
10469
11692
|
content: `${JSON.stringify(documents)}
|
|
10470
11693
|
`,
|
|
10471
|
-
path:
|
|
11694
|
+
path: join26(genDir, "search.json")
|
|
10472
11695
|
}, {
|
|
10473
11696
|
content: searchEndpointTemplate(),
|
|
10474
|
-
path:
|
|
11697
|
+
path: join26(srcDir, "pages", "blume-search.json.ts")
|
|
10475
11698
|
});
|
|
10476
11699
|
}
|
|
10477
11700
|
if (config.search.provider === "mixedbread") {
|
|
10478
11701
|
files.push({
|
|
10479
11702
|
content: mixedbreadSearchEndpointTemplate(config.search.mixedbread?.storeId ?? ""),
|
|
10480
|
-
path:
|
|
11703
|
+
path: join26(srcDir, "pages", "api", "search.ts")
|
|
10481
11704
|
});
|
|
10482
11705
|
}
|
|
10483
11706
|
const feeds = buildRssFeeds(project);
|
|
@@ -10486,10 +11709,10 @@ var eject = async (root) => {
|
|
|
10486
11709
|
files.push({
|
|
10487
11710
|
content: `${JSON.stringify(feedXml)}
|
|
10488
11711
|
`,
|
|
10489
|
-
path:
|
|
11712
|
+
path: join26(genDir, "rss.json")
|
|
10490
11713
|
}, {
|
|
10491
11714
|
content: rssEndpointTemplate(),
|
|
10492
|
-
path:
|
|
11715
|
+
path: join26(srcDir, "pages", "[section]", "rss.xml.ts")
|
|
10493
11716
|
});
|
|
10494
11717
|
}
|
|
10495
11718
|
if (hasReferences(config)) {
|
|
@@ -10501,27 +11724,27 @@ var eject = async (root) => {
|
|
|
10501
11724
|
for (const file of references.files) {
|
|
10502
11725
|
files.push({
|
|
10503
11726
|
content: file.content,
|
|
10504
|
-
path:
|
|
11727
|
+
path: join26(srcDir, "pages", file.pagePath)
|
|
10505
11728
|
});
|
|
10506
11729
|
}
|
|
10507
11730
|
}
|
|
10508
11731
|
files.push(...islands.islands.map((island) => ({
|
|
10509
11732
|
content: islandWrapperTemplate(island),
|
|
10510
|
-
path:
|
|
11733
|
+
path: join26(genDir, "islands", `${island.name}.astro`)
|
|
10511
11734
|
})), ...examples.examples.map((example) => ({
|
|
10512
11735
|
content: exampleWrapperTemplate(example),
|
|
10513
|
-
path:
|
|
11736
|
+
path: join26(genDir, "examples", `${exampleSlug(example.path)}.astro`)
|
|
10514
11737
|
})));
|
|
10515
11738
|
for (const [entryId, content] of staged) {
|
|
10516
|
-
files.push({ content, path:
|
|
11739
|
+
files.push({ content, path: join26(root, stagedDir, entryId) });
|
|
10517
11740
|
}
|
|
10518
11741
|
await Promise.all(files.map(async (file) => {
|
|
10519
|
-
await mkdir5(
|
|
11742
|
+
await mkdir5(join26(file.path, ".."), { recursive: true });
|
|
10520
11743
|
await writeFile7(file.path, file.content, "utf-8");
|
|
10521
11744
|
}));
|
|
10522
|
-
const assetsSrc =
|
|
10523
|
-
if (
|
|
10524
|
-
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"), {
|
|
10525
11748
|
recursive: true
|
|
10526
11749
|
});
|
|
10527
11750
|
}
|
|
@@ -10531,7 +11754,7 @@ var eject = async (root) => {
|
|
|
10531
11754
|
|
|
10532
11755
|
// src/cli/commands/eject.ts
|
|
10533
11756
|
var updatePackageScripts = async (root) => {
|
|
10534
|
-
const pkgPath =
|
|
11757
|
+
const pkgPath = join27(root, "package.json");
|
|
10535
11758
|
let pkg;
|
|
10536
11759
|
try {
|
|
10537
11760
|
pkg = JSON.parse(await readFile15(pkgPath, "utf-8"));
|
|
@@ -10548,7 +11771,7 @@ var updatePackageScripts = async (root) => {
|
|
|
10548
11771
|
await writeFile8(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
10549
11772
|
`, "utf-8");
|
|
10550
11773
|
};
|
|
10551
|
-
var ejectCommand =
|
|
11774
|
+
var ejectCommand = defineCommand6({
|
|
10552
11775
|
args: {
|
|
10553
11776
|
yes: { description: "Skip the confirmation prompt.", type: "boolean" }
|
|
10554
11777
|
},
|
|
@@ -10567,7 +11790,7 @@ var ejectCommand = defineCommand5({
|
|
|
10567
11790
|
await updatePackageScripts(root);
|
|
10568
11791
|
logger.success(`Ejected ${files.length} file(s):`);
|
|
10569
11792
|
for (const file of files) {
|
|
10570
|
-
process.stdout.write(` ${
|
|
11793
|
+
process.stdout.write(` ${relative15(root, file)}
|
|
10571
11794
|
`);
|
|
10572
11795
|
}
|
|
10573
11796
|
logger.box(`Your project is now a standalone Astro app.
|
|
@@ -10580,10 +11803,10 @@ The blume package remains importable.`);
|
|
|
10580
11803
|
});
|
|
10581
11804
|
|
|
10582
11805
|
// src/cli/commands/init.ts
|
|
10583
|
-
import { existsSync as
|
|
11806
|
+
import { existsSync as existsSync18 } from "node:fs";
|
|
10584
11807
|
import { mkdir as mkdir6, writeFile as writeFile9 } from "node:fs/promises";
|
|
10585
|
-
import { defineCommand as
|
|
10586
|
-
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";
|
|
10587
11810
|
var toPackageName = (raw) => raw.toLowerCase().replaceAll(/[^a-z0-9._-]+/gu, "-").replaceAll(/^[-_.]+|[-_.]+$/gu, "") || "docs";
|
|
10588
11811
|
var packageTemplate = (name, version) => `{
|
|
10589
11812
|
"name": ${JSON.stringify(name)},
|
|
@@ -10599,41 +11822,130 @@ var packageTemplate = (name, version) => `{
|
|
|
10599
11822
|
}
|
|
10600
11823
|
}
|
|
10601
11824
|
`;
|
|
10602
|
-
var
|
|
11825
|
+
var TEMPLATES = ["docs", "api", "sdk", "changelog"];
|
|
11826
|
+
var PACKAGE_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
|
|
11827
|
+
var configFor = (extra) => `import { defineConfig } from "blume";
|
|
10603
11828
|
|
|
10604
11829
|
export default defineConfig({
|
|
10605
11830
|
title: "My Docs",
|
|
10606
|
-
description: "Documentation powered by Blume."
|
|
11831
|
+
description: "Documentation powered by Blume.",${extra}
|
|
10607
11832
|
});
|
|
10608
11833
|
`;
|
|
10609
|
-
var
|
|
10610
|
-
title:
|
|
10611
|
-
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
|
|
10612
11879
|
---
|
|
10613
11880
|
|
|
10614
|
-
|
|
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
|
|
10615
11892
|
|
|
10616
11893
|
Welcome to **Blume** — markdown-first docs powered by Astro and Vite.
|
|
10617
11894
|
|
|
10618
|
-
Edit
|
|
10619
|
-
|
|
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
|
+
});
|
|
10620
11920
|
var writeFileSafe = async (path, content) => {
|
|
10621
|
-
if (
|
|
11921
|
+
if (existsSync18(path)) {
|
|
10622
11922
|
logger.info(`Skipped existing ${path}`);
|
|
10623
11923
|
return false;
|
|
10624
11924
|
}
|
|
10625
|
-
await mkdir6(
|
|
11925
|
+
await mkdir6(dirname13(path), { recursive: true });
|
|
10626
11926
|
await writeFile9(path, content, "utf-8");
|
|
10627
11927
|
logger.success(`Created ${path}`);
|
|
10628
11928
|
return true;
|
|
10629
11929
|
};
|
|
10630
|
-
var initCommand =
|
|
11930
|
+
var initCommand = defineCommand7({
|
|
10631
11931
|
args: {
|
|
10632
11932
|
"content-dir": {
|
|
10633
11933
|
default: "docs",
|
|
10634
11934
|
description: "Content directory.",
|
|
10635
11935
|
type: "string"
|
|
10636
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
|
+
},
|
|
10637
11949
|
yes: { description: "Skip prompts.", type: "boolean" }
|
|
10638
11950
|
},
|
|
10639
11951
|
meta: {
|
|
@@ -10643,34 +11955,65 @@ var initCommand = defineCommand6({
|
|
|
10643
11955
|
async run({ args }) {
|
|
10644
11956
|
const root = process.cwd();
|
|
10645
11957
|
const contentDir = args["content-dir"] ?? "docs";
|
|
10646
|
-
const
|
|
10647
|
-
|
|
10648
|
-
|
|
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
|
+
}
|
|
10649
11992
|
const nextSteps = createdPackage ? `Next steps:
|
|
10650
11993
|
|
|
10651
|
-
|
|
10652
|
-
|
|
11994
|
+
${commands.install}
|
|
11995
|
+
${commands.dev}
|
|
10653
11996
|
` : `Next steps:
|
|
10654
11997
|
|
|
10655
|
-
|
|
11998
|
+
${commands.dev}
|
|
10656
11999
|
`;
|
|
10657
12000
|
logger.box(nextSteps);
|
|
10658
12001
|
}
|
|
10659
12002
|
});
|
|
10660
12003
|
|
|
10661
12004
|
// src/cli/commands/migrate.ts
|
|
10662
|
-
import { defineCommand as
|
|
12005
|
+
import { defineCommand as defineCommand8 } from "citty";
|
|
10663
12006
|
|
|
10664
12007
|
// src/migrate/fumadocs/index.ts
|
|
10665
|
-
import { existsSync as
|
|
12008
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
10666
12009
|
import { mkdir as mkdir8, readFile as readFile17, rename as rename3, rm as rm3, writeFile as writeFile11 } from "node:fs/promises";
|
|
10667
|
-
import { dirname as
|
|
12010
|
+
import { dirname as dirname16, join as join31, relative as relative16 } from "pathe";
|
|
10668
12011
|
import { glob as glob8 } from "tinyglobby";
|
|
10669
12012
|
|
|
10670
12013
|
// src/migrate/fumadocs/config.ts
|
|
10671
|
-
import { existsSync as
|
|
12014
|
+
import { existsSync as existsSync19 } from "node:fs";
|
|
10672
12015
|
import { readFile as readFile16 } from "node:fs/promises";
|
|
10673
|
-
import { basename as basename5, dirname as
|
|
12016
|
+
import { basename as basename5, dirname as dirname14, join as join29 } from "pathe";
|
|
10674
12017
|
var SOURCE_FILES = [
|
|
10675
12018
|
"lib/source.ts",
|
|
10676
12019
|
"app/source.ts",
|
|
@@ -10700,10 +12043,10 @@ var GENERIC_NAMES = new Set([
|
|
|
10700
12043
|
var gitRepoRoot = (start) => {
|
|
10701
12044
|
let dir = start;
|
|
10702
12045
|
for (;; ) {
|
|
10703
|
-
if (
|
|
12046
|
+
if (existsSync19(join29(dir, ".git"))) {
|
|
10704
12047
|
return dir;
|
|
10705
12048
|
}
|
|
10706
|
-
const parent =
|
|
12049
|
+
const parent = dirname14(dir);
|
|
10707
12050
|
if (parent === dir) {
|
|
10708
12051
|
return null;
|
|
10709
12052
|
}
|
|
@@ -10712,8 +12055,8 @@ var gitRepoRoot = (start) => {
|
|
|
10712
12055
|
};
|
|
10713
12056
|
var bareName = (name) => name.includes("/") ? name.slice(name.lastIndexOf("/") + 1) : name;
|
|
10714
12057
|
var readTitle = async (root) => {
|
|
10715
|
-
const packageJson =
|
|
10716
|
-
if (!
|
|
12058
|
+
const packageJson = join29(root, "package.json");
|
|
12059
|
+
if (!existsSync19(packageJson)) {
|
|
10717
12060
|
return "Documentation";
|
|
10718
12061
|
}
|
|
10719
12062
|
try {
|
|
@@ -10738,8 +12081,8 @@ var readTitle = async (root) => {
|
|
|
10738
12081
|
};
|
|
10739
12082
|
var scrapeBaseUrl = async (root) => {
|
|
10740
12083
|
for (const candidate of SOURCE_FILES) {
|
|
10741
|
-
const file =
|
|
10742
|
-
if (!
|
|
12084
|
+
const file = join29(root, candidate);
|
|
12085
|
+
if (!existsSync19(file)) {
|
|
10743
12086
|
continue;
|
|
10744
12087
|
}
|
|
10745
12088
|
const base = BASE_URL.exec(await readFile16(file, "utf-8"))?.groups?.base;
|
|
@@ -10771,9 +12114,9 @@ var loadFumadocsConfig = async (root) => {
|
|
|
10771
12114
|
};
|
|
10772
12115
|
|
|
10773
12116
|
// src/migrate/fumadocs/content.ts
|
|
10774
|
-
import { existsSync as
|
|
12117
|
+
import { existsSync as existsSync20 } from "node:fs";
|
|
10775
12118
|
import { readFile as readFileFromDisk2 } from "node:fs/promises";
|
|
10776
|
-
import { dirname as
|
|
12119
|
+
import { dirname as dirname15, resolve as resolve10 } from "pathe";
|
|
10777
12120
|
var FUMADOCS_IMPORT = /^import\s+[\s\S]*?\s+from\s+["']fumadocs-(?:ui|core|mdx)(?:\/[^"']*)?["'];?[ \t]*\n?/gmu;
|
|
10778
12121
|
var stripFumadocsImports = (source) => {
|
|
10779
12122
|
const stripped = source.replace(FUMADOCS_IMPORT, "");
|
|
@@ -10974,12 +12317,12 @@ var inlineFumadocsIncludes = async (source, options) => {
|
|
|
10974
12317
|
if (!rawPath) {
|
|
10975
12318
|
continue;
|
|
10976
12319
|
}
|
|
10977
|
-
const target =
|
|
12320
|
+
const target = resolve10(dirname15(options.filePath), rawPath);
|
|
10978
12321
|
if (seen.has(target)) {
|
|
10979
12322
|
warnings.push(`Circular <include> "${rawPath}" — left as-is.`);
|
|
10980
12323
|
continue;
|
|
10981
12324
|
}
|
|
10982
|
-
if (!
|
|
12325
|
+
if (!existsSync20(target)) {
|
|
10983
12326
|
warnings.push(`<include> target "${rawPath}" not found — left as-is.`);
|
|
10984
12327
|
continue;
|
|
10985
12328
|
}
|
|
@@ -11011,9 +12354,9 @@ var normalizeFumadocsPageMeta = (value) => {
|
|
|
11011
12354
|
};
|
|
11012
12355
|
|
|
11013
12356
|
// src/migrate/fumadocs/groups.ts
|
|
11014
|
-
import { existsSync as
|
|
12357
|
+
import { existsSync as existsSync21, statSync as statSync2 } from "node:fs";
|
|
11015
12358
|
import { mkdir as mkdir7, rename as rename2, writeFile as writeFile10 } from "node:fs/promises";
|
|
11016
|
-
import { basename as basename6, join as
|
|
12359
|
+
import { basename as basename6, join as join30 } from "pathe";
|
|
11017
12360
|
|
|
11018
12361
|
// src/migrate/fumadocs/meta.ts
|
|
11019
12362
|
var SEPARATOR = /^---(?<label>.*)---$/u;
|
|
@@ -11159,12 +12502,12 @@ var isDirectory = (path) => {
|
|
|
11159
12502
|
};
|
|
11160
12503
|
var resolveEntry = (docsDir, name) => {
|
|
11161
12504
|
for (const ext of PAGE_EXTS) {
|
|
11162
|
-
const file =
|
|
11163
|
-
if (
|
|
12505
|
+
const file = join30(docsDir, `${name}${ext}`);
|
|
12506
|
+
if (existsSync21(file)) {
|
|
11164
12507
|
return { kind: "file", path: file };
|
|
11165
12508
|
}
|
|
11166
12509
|
}
|
|
11167
|
-
const folder =
|
|
12510
|
+
const folder = join30(docsDir, name);
|
|
11168
12511
|
return isDirectory(folder) ? { kind: "folder", path: folder } : null;
|
|
11169
12512
|
};
|
|
11170
12513
|
var humanize2 = (name) => name.split(WORD_SPLIT3).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
@@ -11199,8 +12542,8 @@ var moveItemIntoGroup = async (item, docsDir, groupDir, label, warnings) => {
|
|
|
11199
12542
|
warnings.push(`Sidebar entry "${item.name}" in section "${label}" matched no page or folder; skipped.`);
|
|
11200
12543
|
return null;
|
|
11201
12544
|
}
|
|
11202
|
-
const dest =
|
|
11203
|
-
if (
|
|
12545
|
+
const dest = join30(groupDir, basename6(resolved.path));
|
|
12546
|
+
if (existsSync21(dest)) {
|
|
11204
12547
|
warnings.push(`Skipped moving "${item.name}" into section "${label}" (target already exists).`);
|
|
11205
12548
|
return null;
|
|
11206
12549
|
}
|
|
@@ -11227,7 +12570,7 @@ var reshapeSection = async (section, docsDir, order, warnings) => {
|
|
|
11227
12570
|
}
|
|
11228
12571
|
return;
|
|
11229
12572
|
}
|
|
11230
|
-
const groupDir =
|
|
12573
|
+
const groupDir = join30(docsDir, `(${section.label})`);
|
|
11231
12574
|
const sectionKeys = [];
|
|
11232
12575
|
for (const item of section.items) {
|
|
11233
12576
|
const key = await moveItemIntoGroup(item, docsDir, groupDir, section.label, warnings);
|
|
@@ -11240,7 +12583,7 @@ var reshapeSection = async (section, docsDir, order, warnings) => {
|
|
|
11240
12583
|
}
|
|
11241
12584
|
order.push(section.label);
|
|
11242
12585
|
if (sectionKeys.length > 1) {
|
|
11243
|
-
await writeFile10(
|
|
12586
|
+
await writeFile10(join30(groupDir, "meta.ts"), renderMetaModule({ pages: sectionKeys }), "utf-8");
|
|
11244
12587
|
}
|
|
11245
12588
|
};
|
|
11246
12589
|
var reshapeFumadocsGroups = async (structure, docsDir) => {
|
|
@@ -11272,9 +12615,9 @@ var FUMADOCS_LEFTOVERS = [
|
|
|
11272
12615
|
"app"
|
|
11273
12616
|
];
|
|
11274
12617
|
var movePage = async (abs, base, root) => {
|
|
11275
|
-
const rel =
|
|
11276
|
-
const dest =
|
|
11277
|
-
if (
|
|
12618
|
+
const rel = relative16(base, abs);
|
|
12619
|
+
const dest = join31(root, "docs", rel);
|
|
12620
|
+
if (existsSync22(dest)) {
|
|
11278
12621
|
return {
|
|
11279
12622
|
includeWarnings: [],
|
|
11280
12623
|
moved: 0,
|
|
@@ -11293,7 +12636,7 @@ var movePage = async (abs, base, root) => {
|
|
|
11293
12636
|
const parsed = frontmatter_default(text);
|
|
11294
12637
|
const { data, removed } = normalizeFumadocsPageMeta(parsed.data);
|
|
11295
12638
|
const content = Object.keys(data).length > 0 ? frontmatter_default.stringify(parsed.content, data) : parsed.content;
|
|
11296
|
-
await mkdir8(
|
|
12639
|
+
await mkdir8(dirname16(dest), { recursive: true });
|
|
11297
12640
|
await writeFile11(dest, content, "utf-8");
|
|
11298
12641
|
await rm3(abs, { force: true });
|
|
11299
12642
|
return {
|
|
@@ -11308,35 +12651,35 @@ var writeMeta = async (dest, meta, rel, warnings) => {
|
|
|
11308
12651
|
if (Object.keys(meta).length === 0) {
|
|
11309
12652
|
return warnings;
|
|
11310
12653
|
}
|
|
11311
|
-
if (
|
|
12654
|
+
if (existsSync22(dest)) {
|
|
11312
12655
|
return [...warnings, `Skipped ${rel} (target already exists)`];
|
|
11313
12656
|
}
|
|
11314
|
-
await mkdir8(
|
|
12657
|
+
await mkdir8(dirname16(dest), { recursive: true });
|
|
11315
12658
|
await writeFile11(dest, renderMetaModule(meta), "utf-8");
|
|
11316
12659
|
return warnings;
|
|
11317
12660
|
};
|
|
11318
12661
|
var convertMeta = async (abs, base, root) => {
|
|
11319
|
-
const rel =
|
|
12662
|
+
const rel = relative16(base, abs);
|
|
11320
12663
|
const raw = await readFile17(abs, "utf-8");
|
|
11321
12664
|
let parsed;
|
|
11322
12665
|
try {
|
|
11323
12666
|
parsed = JSON.parse(raw);
|
|
11324
12667
|
} catch {
|
|
11325
|
-
const dest2 =
|
|
11326
|
-
if (
|
|
12668
|
+
const dest2 = join31(root, "docs", rel);
|
|
12669
|
+
if (existsSync22(dest2)) {
|
|
11327
12670
|
return [`Skipped ${rel} (target already exists)`];
|
|
11328
12671
|
}
|
|
11329
|
-
await mkdir8(
|
|
12672
|
+
await mkdir8(dirname16(dest2), { recursive: true });
|
|
11330
12673
|
await rename3(abs, dest2);
|
|
11331
12674
|
return [
|
|
11332
12675
|
`Could not parse ${rel}; moved as-is — convert it to meta.ts by hand.`
|
|
11333
12676
|
];
|
|
11334
12677
|
}
|
|
11335
|
-
const dir =
|
|
11336
|
-
const docsDir =
|
|
11337
|
-
const dest =
|
|
12678
|
+
const dir = dirname16(rel) === "." ? "" : dirname16(rel);
|
|
12679
|
+
const docsDir = join31(root, "docs", dir);
|
|
12680
|
+
const dest = join31(docsDir, "meta.ts");
|
|
11338
12681
|
const structure = parseFumadocsPages(parsed.pages);
|
|
11339
|
-
if (structure.hasSections && !
|
|
12682
|
+
if (structure.hasSections && !existsSync22(dest)) {
|
|
11340
12683
|
const self = translateFumadocsSelfMeta(parsed);
|
|
11341
12684
|
const reshape = await reshapeFumadocsGroups(structure, docsDir);
|
|
11342
12685
|
const meta2 = { ...self.meta };
|
|
@@ -11383,8 +12726,8 @@ var summarizePages = (results) => {
|
|
|
11383
12726
|
};
|
|
11384
12727
|
};
|
|
11385
12728
|
var cleanupSourceDirs = async (root) => {
|
|
11386
|
-
const docs =
|
|
11387
|
-
if (
|
|
12729
|
+
const docs = join31(root, "content", "docs");
|
|
12730
|
+
if (existsSync22(docs)) {
|
|
11388
12731
|
const remaining = await glob8(["**/*"], { cwd: docs, dot: true });
|
|
11389
12732
|
if (remaining.length > 0) {
|
|
11390
12733
|
return [
|
|
@@ -11393,8 +12736,8 @@ var cleanupSourceDirs = async (root) => {
|
|
|
11393
12736
|
}
|
|
11394
12737
|
await rm3(docs, { force: true, recursive: true });
|
|
11395
12738
|
}
|
|
11396
|
-
const content =
|
|
11397
|
-
if (
|
|
12739
|
+
const content = join31(root, "content");
|
|
12740
|
+
if (existsSync22(content)) {
|
|
11398
12741
|
const remaining = await glob8(["**/*"], { cwd: content, dot: true });
|
|
11399
12742
|
if (remaining.length === 0) {
|
|
11400
12743
|
await rm3(content, { force: true, recursive: true });
|
|
@@ -11404,8 +12747,8 @@ var cleanupSourceDirs = async (root) => {
|
|
|
11404
12747
|
};
|
|
11405
12748
|
var migrateFumadocsProject = async (root) => {
|
|
11406
12749
|
const { config, warnings: configWarnings } = await loadFumadocsConfig(root);
|
|
11407
|
-
const base =
|
|
11408
|
-
if (!
|
|
12750
|
+
const base = join31(root, SOURCE_DIR);
|
|
12751
|
+
if (!existsSync22(base)) {
|
|
11409
12752
|
await writeBlumeConfig(root, config);
|
|
11410
12753
|
return {
|
|
11411
12754
|
moved: 0,
|
|
@@ -11463,9 +12806,9 @@ var migrateFumadocsProject = async (root) => {
|
|
|
11463
12806
|
};
|
|
11464
12807
|
|
|
11465
12808
|
// src/migrate/mintlify/index.ts
|
|
11466
|
-
import { existsSync as
|
|
12809
|
+
import { existsSync as existsSync23 } from "node:fs";
|
|
11467
12810
|
import { mkdir as mkdir9, readFile as readFile18, rename as rename4, rm as rm4, writeFile as writeFile12 } from "node:fs/promises";
|
|
11468
|
-
import { dirname as
|
|
12811
|
+
import { dirname as dirname17, join as join32 } from "pathe";
|
|
11469
12812
|
import { glob as glob9 } from "tinyglobby";
|
|
11470
12813
|
var prune = (value) => {
|
|
11471
12814
|
if (Array.isArray(value)) {
|
|
@@ -11495,7 +12838,7 @@ var writeBlumeConfig2 = async (root, config) => {
|
|
|
11495
12838
|
|
|
11496
12839
|
export default defineConfig(${JSON.stringify(prune(config), null, 2)});
|
|
11497
12840
|
`;
|
|
11498
|
-
await writeFile12(
|
|
12841
|
+
await writeFile12(join32(root, "blume.config.ts"), body, "utf-8");
|
|
11499
12842
|
};
|
|
11500
12843
|
var relocateAssets = async (root, refs) => {
|
|
11501
12844
|
const segments = new Set;
|
|
@@ -11510,23 +12853,23 @@ var relocateAssets = async (root, refs) => {
|
|
|
11510
12853
|
}
|
|
11511
12854
|
const moved = [];
|
|
11512
12855
|
for (const segment of segments) {
|
|
11513
|
-
const source =
|
|
11514
|
-
if (!
|
|
12856
|
+
const source = join32(root, segment);
|
|
12857
|
+
if (!existsSync23(source) || segment === "public") {
|
|
11515
12858
|
continue;
|
|
11516
12859
|
}
|
|
11517
|
-
const dest =
|
|
11518
|
-
if (
|
|
12860
|
+
const dest = join32(root, "public", segment);
|
|
12861
|
+
if (existsSync23(dest)) {
|
|
11519
12862
|
continue;
|
|
11520
12863
|
}
|
|
11521
|
-
await mkdir9(
|
|
12864
|
+
await mkdir9(join32(root, "public"), { recursive: true });
|
|
11522
12865
|
await rename4(source, dest);
|
|
11523
12866
|
moved.push(segment);
|
|
11524
12867
|
}
|
|
11525
12868
|
return moved;
|
|
11526
12869
|
};
|
|
11527
12870
|
var cleanupSnippets = async (root, kept, warnings) => {
|
|
11528
|
-
const dir =
|
|
11529
|
-
if (!
|
|
12871
|
+
const dir = join32(root, "snippets");
|
|
12872
|
+
if (!existsSync23(dir)) {
|
|
11530
12873
|
return;
|
|
11531
12874
|
}
|
|
11532
12875
|
const markdown = await glob9(["**/*.{md,mdx}"], { absolute: true, cwd: dir });
|
|
@@ -11563,9 +12906,9 @@ var assetRefs = (config) => {
|
|
|
11563
12906
|
};
|
|
11564
12907
|
var migrateMintlifyProject = async (root) => {
|
|
11565
12908
|
const warnings = [];
|
|
11566
|
-
const configFile =
|
|
12909
|
+
const configFile = existsSync23(join32(root, "docs.json")) ? join32(root, "docs.json") : join32(root, "mint.json");
|
|
11567
12910
|
let config;
|
|
11568
|
-
if (
|
|
12911
|
+
if (existsSync23(configFile)) {
|
|
11569
12912
|
config = await loadMintlifyConfig(root, configFile);
|
|
11570
12913
|
const spec = JSON.parse(await readFile18(configFile, "utf-8"));
|
|
11571
12914
|
const i18n = mintlifyI18n(spec);
|
|
@@ -11605,7 +12948,7 @@ var migrateMintlifyProject = async (root) => {
|
|
|
11605
12948
|
variables
|
|
11606
12949
|
});
|
|
11607
12950
|
if (result.content !== raw) {
|
|
11608
|
-
await mkdir9(
|
|
12951
|
+
await mkdir9(dirname17(file), { recursive: true });
|
|
11609
12952
|
await writeFile12(file, result.content, "utf-8");
|
|
11610
12953
|
}
|
|
11611
12954
|
for (const key of result.removed) {
|
|
@@ -11642,9 +12985,9 @@ var migrateMintlifyProject = async (root) => {
|
|
|
11642
12985
|
};
|
|
11643
12986
|
|
|
11644
12987
|
// src/migrate/nextra/index.ts
|
|
11645
|
-
import { existsSync as
|
|
12988
|
+
import { existsSync as existsSync24 } from "node:fs";
|
|
11646
12989
|
import { mkdir as mkdir10, readFile as readFile19, rename as rename5, rm as rm5, writeFile as writeFile13 } from "node:fs/promises";
|
|
11647
|
-
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";
|
|
11648
12991
|
import { glob as glob10 } from "tinyglobby";
|
|
11649
12992
|
|
|
11650
12993
|
// src/migrate/nextra/content.ts
|
|
@@ -11874,13 +13217,13 @@ var indexFolders = (base, pageFiles, metaFiles) => {
|
|
|
11874
13217
|
let current = normalizeDir(dir);
|
|
11875
13218
|
allDirs.add(current);
|
|
11876
13219
|
while (current !== "") {
|
|
11877
|
-
current = normalizeDir(
|
|
13220
|
+
current = normalizeDir(dirname18(current));
|
|
11878
13221
|
allDirs.add(current);
|
|
11879
13222
|
}
|
|
11880
13223
|
};
|
|
11881
13224
|
for (const abs of pageFiles) {
|
|
11882
|
-
const rel =
|
|
11883
|
-
const dir = normalizeDir(
|
|
13225
|
+
const rel = relative17(base, abs);
|
|
13226
|
+
const dir = normalizeDir(dirname18(rel));
|
|
11884
13227
|
const slug = basename7(rel).replace(/\.mdx?$/u, "");
|
|
11885
13228
|
const folder = pagesByDir.get(dir) ?? new Map;
|
|
11886
13229
|
folder.set(slug, abs);
|
|
@@ -11888,14 +13231,14 @@ var indexFolders = (base, pageFiles, metaFiles) => {
|
|
|
11888
13231
|
registerDir(dir);
|
|
11889
13232
|
}
|
|
11890
13233
|
for (const abs of metaFiles) {
|
|
11891
|
-
registerDir(normalizeDir(
|
|
13234
|
+
registerDir(normalizeDir(dirname18(relative17(base, abs))));
|
|
11892
13235
|
}
|
|
11893
13236
|
const childDirs = new Map;
|
|
11894
13237
|
for (const dir of allDirs) {
|
|
11895
13238
|
if (dir === "") {
|
|
11896
13239
|
continue;
|
|
11897
13240
|
}
|
|
11898
|
-
const parent = normalizeDir(
|
|
13241
|
+
const parent = normalizeDir(dirname18(dir));
|
|
11899
13242
|
const children = childDirs.get(parent) ?? new Set;
|
|
11900
13243
|
children.add(basename7(dir));
|
|
11901
13244
|
childDirs.set(parent, children);
|
|
@@ -11913,7 +13256,7 @@ var planMetas = (metas, index) => {
|
|
|
11913
13256
|
warnings: []
|
|
11914
13257
|
};
|
|
11915
13258
|
for (const meta of metas) {
|
|
11916
|
-
const dir = normalizeDir(
|
|
13259
|
+
const dir = normalizeDir(dirname18(meta.rel));
|
|
11917
13260
|
const entries = parseNextraMeta(meta.raw, meta.ext);
|
|
11918
13261
|
if (!entries) {
|
|
11919
13262
|
plan.unparseableMetas.push({ abs: meta.abs, rel: meta.rel });
|
|
@@ -11926,7 +13269,7 @@ var planMetas = (metas, index) => {
|
|
|
11926
13269
|
plan.metaByDir.set(dir, conversion.folderMeta);
|
|
11927
13270
|
plan.consumedMetas.push(meta.abs);
|
|
11928
13271
|
for (const [slug, title] of Object.entries(conversion.folderTitles)) {
|
|
11929
|
-
plan.folderTitleByDir.set(normalizeDir(
|
|
13272
|
+
plan.folderTitleByDir.set(normalizeDir(join33(dir, slug)), title);
|
|
11930
13273
|
}
|
|
11931
13274
|
for (const [slug, label] of Object.entries(conversion.pageLabels)) {
|
|
11932
13275
|
const pageAbs = index.pagesByDir.get(dir)?.get(slug);
|
|
@@ -11950,9 +13293,9 @@ var planMetas = (metas, index) => {
|
|
|
11950
13293
|
return plan;
|
|
11951
13294
|
};
|
|
11952
13295
|
var movePage2 = async (abs, options) => {
|
|
11953
|
-
const rel =
|
|
11954
|
-
const dest =
|
|
11955
|
-
if (
|
|
13296
|
+
const rel = relative17(options.base, abs);
|
|
13297
|
+
const dest = join33(options.root, "docs", rel);
|
|
13298
|
+
if (existsSync24(dest)) {
|
|
11956
13299
|
return { moved: 0, removed: [], skipped: rel, unsupported: [] };
|
|
11957
13300
|
}
|
|
11958
13301
|
const raw = await readFile19(abs, "utf-8");
|
|
@@ -11961,7 +13304,7 @@ var movePage2 = async (abs, options) => {
|
|
|
11961
13304
|
const parsed = frontmatter_default(text);
|
|
11962
13305
|
const { data, removed } = normalizeNextraPageMeta(parsed.data, options.overrides.get(abs) ?? {});
|
|
11963
13306
|
const content = Object.keys(data).length > 0 ? frontmatter_default.stringify(parsed.content, data) : parsed.content;
|
|
11964
|
-
await mkdir10(
|
|
13307
|
+
await mkdir10(dirname18(dest), { recursive: true });
|
|
11965
13308
|
await writeFile13(dest, content, "utf-8");
|
|
11966
13309
|
await rm5(abs, { force: true });
|
|
11967
13310
|
return { moved: 1, removed, skipped: null, unsupported };
|
|
@@ -12004,8 +13347,8 @@ var writeFolderMetas = async (root, plan) => {
|
|
|
12004
13347
|
if (Object.keys(finalMeta).length === 0) {
|
|
12005
13348
|
return;
|
|
12006
13349
|
}
|
|
12007
|
-
const dest =
|
|
12008
|
-
await mkdir10(
|
|
13350
|
+
const dest = join33(root, "docs", dir, "meta.ts");
|
|
13351
|
+
await mkdir10(dirname18(dest), { recursive: true });
|
|
12009
13352
|
await writeFile13(dest, `import { defineMeta } from "blume";
|
|
12010
13353
|
|
|
12011
13354
|
export default defineMeta(${JSON.stringify(finalMeta, null, 2)});
|
|
@@ -12015,12 +13358,12 @@ export default defineMeta(${JSON.stringify(finalMeta, null, 2)});
|
|
|
12015
13358
|
var relocateUnparseableMetas = async (root, metas) => {
|
|
12016
13359
|
const warnings = [];
|
|
12017
13360
|
await Promise.all(metas.map(async ({ abs, rel }) => {
|
|
12018
|
-
const dest =
|
|
12019
|
-
if (
|
|
13361
|
+
const dest = join33(root, "docs", rel);
|
|
13362
|
+
if (existsSync24(dest)) {
|
|
12020
13363
|
warnings.push(`Skipped ${rel} (target already exists)`);
|
|
12021
13364
|
return;
|
|
12022
13365
|
}
|
|
12023
|
-
await mkdir10(
|
|
13366
|
+
await mkdir10(dirname18(dest), { recursive: true });
|
|
12024
13367
|
await rename5(abs, dest);
|
|
12025
13368
|
warnings.push(`Could not parse ${rel}; moved as-is — convert it to meta.ts by hand.`);
|
|
12026
13369
|
}));
|
|
@@ -12028,7 +13371,7 @@ var relocateUnparseableMetas = async (root, metas) => {
|
|
|
12028
13371
|
};
|
|
12029
13372
|
var buildConfig = (tabs) => tabs.length > 0 ? { navigation: { tabs }, title: "Documentation" } : { title: "Documentation" };
|
|
12030
13373
|
var migrateNextraProject = async (root) => {
|
|
12031
|
-
const sourceDir = SOURCE_DIRS.find((dir) =>
|
|
13374
|
+
const sourceDir = SOURCE_DIRS.find((dir) => existsSync24(join33(root, dir)));
|
|
12032
13375
|
if (!sourceDir) {
|
|
12033
13376
|
await writeBlumeConfig(root, { title: "Documentation" });
|
|
12034
13377
|
return {
|
|
@@ -12038,7 +13381,7 @@ var migrateNextraProject = async (root) => {
|
|
|
12038
13381
|
]
|
|
12039
13382
|
};
|
|
12040
13383
|
}
|
|
12041
|
-
const base =
|
|
13384
|
+
const base = join33(root, sourceDir);
|
|
12042
13385
|
const pageFiles = await glob10([PAGE_GLOB2], {
|
|
12043
13386
|
absolute: true,
|
|
12044
13387
|
cwd: base,
|
|
@@ -12052,9 +13395,9 @@ var migrateNextraProject = async (root) => {
|
|
|
12052
13395
|
const index = indexFolders(base, pageFiles, metaFiles);
|
|
12053
13396
|
const metas = await Promise.all(metaFiles.map(async (abs) => ({
|
|
12054
13397
|
abs,
|
|
12055
|
-
ext:
|
|
13398
|
+
ext: extname7(abs),
|
|
12056
13399
|
raw: await readFile19(abs, "utf-8"),
|
|
12057
|
-
rel:
|
|
13400
|
+
rel: relative17(base, abs)
|
|
12058
13401
|
})));
|
|
12059
13402
|
const plan = planMetas(metas, index);
|
|
12060
13403
|
const moves = await Promise.all(pageFiles.map((abs) => movePage2(abs, { base, overrides: plan.pageOverrides, root })));
|
|
@@ -12079,15 +13422,15 @@ var migrateNextraProject = async (root) => {
|
|
|
12079
13422
|
};
|
|
12080
13423
|
|
|
12081
13424
|
// src/migrate/starlight/index.ts
|
|
12082
|
-
import { existsSync as
|
|
13425
|
+
import { existsSync as existsSync26 } from "node:fs";
|
|
12083
13426
|
import { readFile as readFile21, writeFile as writeFile14 } from "node:fs/promises";
|
|
12084
|
-
import { join as
|
|
13427
|
+
import { join as join35 } from "pathe";
|
|
12085
13428
|
import { glob as glob11 } from "tinyglobby";
|
|
12086
13429
|
|
|
12087
13430
|
// src/migrate/starlight/config.ts
|
|
12088
|
-
import { existsSync as
|
|
13431
|
+
import { existsSync as existsSync25 } from "node:fs";
|
|
12089
13432
|
import { readFile as readFile20 } from "node:fs/promises";
|
|
12090
|
-
import { join as
|
|
13433
|
+
import { join as join34 } from "pathe";
|
|
12091
13434
|
var CONFIG_FILES = [
|
|
12092
13435
|
"astro.config.mjs",
|
|
12093
13436
|
"astro.config.mts",
|
|
@@ -12118,7 +13461,7 @@ var extractStarlightOptions = (source) => {
|
|
|
12118
13461
|
return isLiteralObject(parsed) ? parsed : "unparseable";
|
|
12119
13462
|
};
|
|
12120
13463
|
var loadStarlightConfig = async (root) => {
|
|
12121
|
-
const file = CONFIG_FILES.map((name) =>
|
|
13464
|
+
const file = CONFIG_FILES.map((name) => join34(root, name)).find((path) => existsSync25(path));
|
|
12122
13465
|
if (!file) {
|
|
12123
13466
|
return {
|
|
12124
13467
|
options: {},
|
|
@@ -12361,9 +13704,6 @@ var mapStarlightConfig = (options, warnings) => {
|
|
|
12361
13704
|
}
|
|
12362
13705
|
}
|
|
12363
13706
|
const social = mapSocial(options.social);
|
|
12364
|
-
if (Object.keys(social.socials).length > 0) {
|
|
12365
|
-
config.footer = { socials: social.socials };
|
|
12366
|
-
}
|
|
12367
13707
|
const github = mapEditLink(options.editLink) ?? social.github;
|
|
12368
13708
|
if (github) {
|
|
12369
13709
|
config.github = github;
|
|
@@ -12550,8 +13890,8 @@ var migrateStarlightProject = async (root) => {
|
|
|
12550
13890
|
config.i18n = i18n;
|
|
12551
13891
|
warnings.push(`Mapped ${i18n.locales.length} locale(s) to i18n (default: ${i18n.defaultLocale}); review the locale labels.`);
|
|
12552
13892
|
}
|
|
12553
|
-
const base =
|
|
12554
|
-
if (!
|
|
13893
|
+
const base = join35(root, CONTENT_DIR);
|
|
13894
|
+
if (!existsSync26(base)) {
|
|
12555
13895
|
await writeBlumeConfig(root, config);
|
|
12556
13896
|
return {
|
|
12557
13897
|
moved: 0,
|
|
@@ -12605,7 +13945,7 @@ var migrators = {
|
|
|
12605
13945
|
};
|
|
12606
13946
|
|
|
12607
13947
|
// src/cli/commands/migrate.ts
|
|
12608
|
-
var makeMigrateCommand = (source) =>
|
|
13948
|
+
var makeMigrateCommand = (source) => defineCommand8({
|
|
12609
13949
|
meta: {
|
|
12610
13950
|
description: `Migrate a ${source} project to Blume.`,
|
|
12611
13951
|
name: source
|
|
@@ -12625,7 +13965,7 @@ var makeMigrateCommand = (source) => defineCommand7({
|
|
|
12625
13965
|
logger.box("Review blume.config.ts and run `blume dev`.");
|
|
12626
13966
|
}
|
|
12627
13967
|
});
|
|
12628
|
-
var migrateCommand =
|
|
13968
|
+
var migrateCommand = defineCommand8({
|
|
12629
13969
|
meta: {
|
|
12630
13970
|
description: "Migrate from another docs tool to Blume.",
|
|
12631
13971
|
name: "migrate"
|
|
@@ -12639,11 +13979,11 @@ var migrateCommand = defineCommand7({
|
|
|
12639
13979
|
});
|
|
12640
13980
|
|
|
12641
13981
|
// src/cli/commands/preview.ts
|
|
12642
|
-
import { existsSync as
|
|
13982
|
+
import { existsSync as existsSync27 } from "node:fs";
|
|
12643
13983
|
import { preview } from "astro";
|
|
12644
|
-
import { defineCommand as
|
|
12645
|
-
import { join as
|
|
12646
|
-
var previewCommand =
|
|
13984
|
+
import { defineCommand as defineCommand9 } from "citty";
|
|
13985
|
+
import { join as join36 } from "pathe";
|
|
13986
|
+
var previewCommand = defineCommand9({
|
|
12647
13987
|
args: {
|
|
12648
13988
|
host: { description: "Network host to bind.", type: "string" },
|
|
12649
13989
|
port: { description: "Port to listen on.", type: "string" }
|
|
@@ -12656,7 +13996,7 @@ var previewCommand = defineCommand8({
|
|
|
12656
13996
|
const root = process.cwd();
|
|
12657
13997
|
const { config } = await loadConfig(root);
|
|
12658
13998
|
const context = resolveProjectContext(root, config);
|
|
12659
|
-
if (!
|
|
13999
|
+
if (!existsSync27(join36(context.outDir, "astro.config.mjs"))) {
|
|
12660
14000
|
logger.error("No build found. Run `blume build` first.");
|
|
12661
14001
|
process.exit(1);
|
|
12662
14002
|
}
|
|
@@ -12673,9 +14013,9 @@ var previewCommand = defineCommand8({
|
|
|
12673
14013
|
|
|
12674
14014
|
// src/cli/commands/sync.ts
|
|
12675
14015
|
import { rm as rm6 } from "node:fs/promises";
|
|
12676
|
-
import { defineCommand as
|
|
12677
|
-
import { join as
|
|
12678
|
-
var syncCommand =
|
|
14016
|
+
import { defineCommand as defineCommand10 } from "citty";
|
|
14017
|
+
import { join as join37 } from "pathe";
|
|
14018
|
+
var syncCommand = defineCommand10({
|
|
12679
14019
|
args: {
|
|
12680
14020
|
force: {
|
|
12681
14021
|
description: "Clear the source cache before refetching.",
|
|
@@ -12696,7 +14036,7 @@ var syncCommand = defineCommand9({
|
|
|
12696
14036
|
if (args.force) {
|
|
12697
14037
|
const { config } = await loadConfig(root);
|
|
12698
14038
|
const context = resolveProjectContext(root, config);
|
|
12699
|
-
await rm6(
|
|
14039
|
+
await rm6(join37(context.outDir, "cache"), { force: true, recursive: true });
|
|
12700
14040
|
logger.info("Cleared source cache.");
|
|
12701
14041
|
}
|
|
12702
14042
|
await prepareProject({
|
|
@@ -12711,13 +14051,13 @@ var syncCommand = defineCommand9({
|
|
|
12711
14051
|
});
|
|
12712
14052
|
|
|
12713
14053
|
// src/cli/commands/validate.ts
|
|
12714
|
-
import { existsSync as
|
|
12715
|
-
import { defineCommand as
|
|
12716
|
-
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";
|
|
12717
14057
|
|
|
12718
14058
|
// src/core/links.ts
|
|
12719
|
-
import { existsSync as
|
|
12720
|
-
import { join as
|
|
14059
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
14060
|
+
import { join as join38 } from "pathe";
|
|
12721
14061
|
var HTTP = /^https?:\/\//iu;
|
|
12722
14062
|
var PROTOCOL_RELATIVE = /^\/\//u;
|
|
12723
14063
|
var SCHEME = /^[a-z][a-z0-9+.-]*:/iu;
|
|
@@ -12756,8 +14096,8 @@ var toRoute = (path) => {
|
|
|
12756
14096
|
};
|
|
12757
14097
|
var buildAnchorIndex = (pages) => {
|
|
12758
14098
|
const anchors = new Map;
|
|
12759
|
-
for (const
|
|
12760
|
-
anchors.set(
|
|
14099
|
+
for (const page2 of pages) {
|
|
14100
|
+
anchors.set(page2.route, new Set(page2.headings.map((heading) => heading.slug)));
|
|
12761
14101
|
}
|
|
12762
14102
|
return anchors;
|
|
12763
14103
|
};
|
|
@@ -12777,7 +14117,7 @@ var checkPathLink = (resolved, fragment, target, site, ctx) => {
|
|
|
12777
14117
|
if (ctx.publicDir === null) {
|
|
12778
14118
|
return "asset-unchecked";
|
|
12779
14119
|
}
|
|
12780
|
-
if (
|
|
14120
|
+
if (existsSync28(join38(ctx.publicDir, resolved))) {
|
|
12781
14121
|
return null;
|
|
12782
14122
|
}
|
|
12783
14123
|
return {
|
|
@@ -12876,11 +14216,11 @@ var checkExternalLinks = async (refs) => {
|
|
|
12876
14216
|
}
|
|
12877
14217
|
return diagnostics;
|
|
12878
14218
|
};
|
|
12879
|
-
var classifyLink = (
|
|
14219
|
+
var classifyLink = (page2, link, ctx, onExternal) => {
|
|
12880
14220
|
const { target } = link;
|
|
12881
14221
|
const site = {
|
|
12882
14222
|
column: link.column,
|
|
12883
|
-
file:
|
|
14223
|
+
file: page2.sourcePath ?? page2.id,
|
|
12884
14224
|
line: link.line
|
|
12885
14225
|
};
|
|
12886
14226
|
if (HTTP.test(target) || PROTOCOL_RELATIVE.test(target)) {
|
|
@@ -12901,9 +14241,9 @@ var classifyLink = (page, link, ctx, onExternal) => {
|
|
|
12901
14241
|
rawPath = rawPath.slice(0, queryIndex);
|
|
12902
14242
|
}
|
|
12903
14243
|
if (rawPath === "") {
|
|
12904
|
-
return fragment ? checkAnchor(
|
|
14244
|
+
return fragment ? checkAnchor(page2.route, fragment, site, ctx) : null;
|
|
12905
14245
|
}
|
|
12906
|
-
const resolved = rawPath.startsWith("/") ? rawPath : resolveRelative(
|
|
14246
|
+
const resolved = rawPath.startsWith("/") ? rawPath : resolveRelative(page2.route, rawPath);
|
|
12907
14247
|
return checkPathLink(resolved, fragment, target, site, ctx);
|
|
12908
14248
|
};
|
|
12909
14249
|
var validateLinks = async (graph, options) => {
|
|
@@ -12916,9 +14256,9 @@ var validateLinks = async (graph, options) => {
|
|
|
12916
14256
|
const diagnostics = [];
|
|
12917
14257
|
const external = [];
|
|
12918
14258
|
let uncheckedAssets = 0;
|
|
12919
|
-
for (const
|
|
12920
|
-
for (const link of
|
|
12921
|
-
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));
|
|
12922
14262
|
if (result === "asset-unchecked") {
|
|
12923
14263
|
uncheckedAssets += 1;
|
|
12924
14264
|
} else if (result) {
|
|
@@ -12940,12 +14280,16 @@ var validateLinks = async (graph, options) => {
|
|
|
12940
14280
|
};
|
|
12941
14281
|
|
|
12942
14282
|
// src/cli/commands/validate.ts
|
|
12943
|
-
var validateCommand =
|
|
14283
|
+
var validateCommand = defineCommand11({
|
|
12944
14284
|
args: {
|
|
12945
14285
|
external: {
|
|
12946
14286
|
description: "Check external (HTTP) links over the network.",
|
|
12947
14287
|
type: "boolean"
|
|
12948
14288
|
},
|
|
14289
|
+
json: {
|
|
14290
|
+
description: "Emit diagnostics as JSON on stdout (for CI/editors).",
|
|
14291
|
+
type: "boolean"
|
|
14292
|
+
},
|
|
12949
14293
|
strict: {
|
|
12950
14294
|
description: "Treat warnings as errors.",
|
|
12951
14295
|
type: "boolean"
|
|
@@ -12961,18 +14305,26 @@ var validateCommand = defineCommand10({
|
|
|
12961
14305
|
try {
|
|
12962
14306
|
const project = await scanProject(root, { mode: "build" });
|
|
12963
14307
|
diagnostics.push(...project.diagnostics);
|
|
12964
|
-
const publicDir =
|
|
14308
|
+
const publicDir = join39(root, "public");
|
|
12965
14309
|
diagnostics.push(...await validateLinks(project.graph, {
|
|
12966
14310
|
checkExternal: Boolean(args.external),
|
|
12967
|
-
publicDir:
|
|
14311
|
+
publicDir: existsSync29(publicDir) ? publicDir : null,
|
|
12968
14312
|
redirects: project.config.redirects
|
|
12969
14313
|
}));
|
|
12970
14314
|
} catch (error) {
|
|
12971
14315
|
if (error instanceof BlumeError) {
|
|
12972
14316
|
diagnostics.push(error.diagnostic);
|
|
12973
14317
|
} else {
|
|
12974
|
-
|
|
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);
|
|
12975
14326
|
}
|
|
14327
|
+
return;
|
|
12976
14328
|
}
|
|
12977
14329
|
const hadErrors = reportDiagnostics(diagnostics, root);
|
|
12978
14330
|
if (diagnostics.length === 0) {
|
|
@@ -12985,7 +14337,7 @@ var validateCommand = defineCommand10({
|
|
|
12985
14337
|
});
|
|
12986
14338
|
|
|
12987
14339
|
// src/cli/index.ts
|
|
12988
|
-
var main =
|
|
14340
|
+
var main = defineCommand12({
|
|
12989
14341
|
meta: {
|
|
12990
14342
|
description: "Markdown-first documentation powered by Astro and Vite.",
|
|
12991
14343
|
name: "blume",
|
|
@@ -12994,6 +14346,7 @@ var main = defineCommand11({
|
|
|
12994
14346
|
subCommands: {
|
|
12995
14347
|
add: addCommand,
|
|
12996
14348
|
build: buildCommand,
|
|
14349
|
+
check: checkCommand,
|
|
12997
14350
|
dev: devCommand,
|
|
12998
14351
|
doctor: doctorCommand,
|
|
12999
14352
|
eject: ejectCommand,
|
|
@@ -13005,7 +14358,15 @@ var main = defineCommand11({
|
|
|
13005
14358
|
}
|
|
13006
14359
|
});
|
|
13007
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
|
+
});
|
|
13008
14369
|
runMain(main);
|
|
13009
14370
|
|
|
13010
|
-
//# debugId=
|
|
14371
|
+
//# debugId=8EA79E97DE44177D64756E2164756E21
|
|
13011
14372
|
//# sourceMappingURL=index.js.map
|