blume 0.3.0 → 0.4.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 +747 -471
- package/dist/cli/index.js.map +45 -38
- package/dist/types/core/schema.d.ts +289 -278
- package/dist/types/migrate/mintlify/assets.d.ts +8 -0
- package/docs/01-quickstart.mdx +5 -16
- package/docs/02-deployment.mdx +21 -54
- package/docs/advanced/api-reference.mdx +10 -37
- package/docs/advanced/blog.mdx +9 -25
- package/docs/advanced/changelog.mdx +10 -33
- package/docs/advanced/custom-pages.mdx +21 -78
- package/docs/configuration/ai.mdx +42 -103
- package/docs/configuration/analytics.mdx +20 -38
- package/docs/configuration/customization.mdx +40 -73
- package/docs/configuration/export.mdx +9 -34
- package/docs/configuration/index.mdx +67 -87
- package/docs/configuration/search.mdx +17 -54
- package/docs/configuration/seo.mdx +17 -48
- package/docs/configuration/theming.mdx +20 -42
- package/docs/content/components.mdx +42 -101
- package/docs/content/i18n.mdx +21 -72
- package/docs/content/index.mdx +18 -48
- package/docs/content/islands.mdx +25 -52
- package/docs/content/meta.mdx +23 -50
- package/docs/content/navigation.mdx +23 -62
- package/docs/content/sources.mdx +20 -83
- package/docs/content/syntax.mdx +37 -105
- package/docs/index.mdx +11 -40
- package/docs/reference/cli.mdx +18 -29
- package/docs/reference/frontmatter.mdx +2 -5
- package/package.json +1 -1
- package/src/astro/integration.ts +26 -3
- package/src/astro/islands.ts +6 -2
- package/src/astro/markdown-negotiation.ts +17 -3
- package/src/astro/pages.ts +6 -1
- package/src/astro/static-assets.ts +117 -0
- package/src/astro/templates.ts +48 -26
- package/src/cli/args.ts +23 -0
- package/src/cli/commands/build.ts +23 -0
- package/src/cli/commands/dev.ts +11 -2
- package/src/cli/commands/doctor.ts +10 -1
- package/src/cli/commands/eject.ts +3 -1
- package/src/cli/commands/init.ts +21 -1
- package/src/cli/commands/preview.ts +2 -1
- package/src/cli/commands/validate.ts +12 -1
- package/src/cli/dev-lock.ts +84 -0
- package/src/cli/log.ts +11 -0
- package/src/components/BlumePage.astro +2 -0
- package/src/components/content/YouTube.astro +35 -0
- package/src/components/content/youtube.ts +46 -0
- package/src/components/islands/ask-ai.tsx +14 -14
- package/src/components/props.ts +3 -0
- package/src/core/assets.ts +31 -0
- package/src/core/bridge.ts +10 -0
- package/src/core/builtin-tags.ts +1 -0
- package/src/core/diagnostics.ts +6 -1
- package/src/core/gitignore.ts +30 -0
- package/src/core/links.ts +60 -19
- package/src/core/schema.ts +7 -0
- package/src/core/sources/mdx-remote.ts +54 -8
- package/src/core/sources/normalize.ts +6 -1
- package/src/core/sources/notion.ts +49 -5
- package/src/core/sources/sanity.ts +5 -1
- package/src/deploy/rss.ts +1 -8
- package/src/deploy/sitemap.ts +20 -1
- package/src/deploy/xml.ts +8 -0
- package/src/markdown/directives.ts +15 -7
- package/src/markdown/package-commands.ts +26 -4
- package/src/migrate/fumadocs/content.ts +14 -1
- package/src/migrate/fumadocs/groups.ts +7 -0
- package/src/migrate/fumadocs/index.ts +5 -2
- package/src/migrate/mintlify/assets.ts +46 -0
- package/src/migrate/mintlify/index.ts +53 -45
- package/src/migrate/shared.ts +12 -27
- package/src/og/card.ts +14 -2
- package/src/registry/eject.ts +13 -3
- package/src/registry/registry.ts +6 -0
- package/src/registry/rewrite-imports.ts +31 -19
- package/src/search/documents.ts +23 -5
- package/src/search/sync/algolia.ts +5 -1
- package/src/search/sync/typesense.ts +24 -16
- package/src/theme/palette.ts +26 -7
package/dist/cli/index.js
CHANGED
|
@@ -209,6 +209,12 @@ var CONTENT_COMPONENTS = [
|
|
|
209
209
|
file: "Prompt.astro",
|
|
210
210
|
name: "prompt",
|
|
211
211
|
tag: "Prompt"
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
description: "A responsive, privacy-friendly YouTube embed.",
|
|
215
|
+
file: "YouTube.astro",
|
|
216
|
+
name: "youtube",
|
|
217
|
+
tag: "YouTube"
|
|
212
218
|
}
|
|
213
219
|
];
|
|
214
220
|
var registry = [
|
|
@@ -254,18 +260,22 @@ var findItem = (name) => registry.find((item) => item.name === name);
|
|
|
254
260
|
|
|
255
261
|
// src/registry/rewrite-imports.ts
|
|
256
262
|
import { dirname as dirname2, relative, resolve } from "pathe";
|
|
257
|
-
var
|
|
258
|
-
var
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}
|
|
263
|
+
var FROM_IMPORT = /(?<prefix>^[ \t]*(?:import|export)\b[^;]*?\bfrom[ \t]*)(?<quote>["'])(?<spec>\.[^"']*)\k<quote>/gmu;
|
|
264
|
+
var SIDE_EFFECT_IMPORT = /(?<prefix>^[ \t]*import[ \t]+)(?<quote>["'])(?<spec>\.[^"']*)\k<quote>/gmu;
|
|
265
|
+
var rewriteImports = (content, sourceFile, srcRoot) => {
|
|
266
|
+
const rewrite = (match, prefix, quote, spec) => {
|
|
267
|
+
const resolved = resolve(dirname2(sourceFile), spec);
|
|
268
|
+
if (resolved === sourceFile) {
|
|
269
|
+
return match;
|
|
270
|
+
}
|
|
271
|
+
const rel = relative(srcRoot, resolved);
|
|
272
|
+
if (rel.startsWith("..")) {
|
|
273
|
+
return match;
|
|
274
|
+
}
|
|
275
|
+
return `${prefix}${quote}blume/${rel}${quote}`;
|
|
276
|
+
};
|
|
277
|
+
return content.replaceAll(FROM_IMPORT, rewrite).replaceAll(SIDE_EFFECT_IMPORT, rewrite);
|
|
278
|
+
};
|
|
269
279
|
|
|
270
280
|
// src/cli/log.ts
|
|
271
281
|
import { consola } from "consola";
|
|
@@ -326,7 +336,7 @@ var locatePath = (source, path) => {
|
|
|
326
336
|
if (typeof segment !== "string") {
|
|
327
337
|
continue;
|
|
328
338
|
}
|
|
329
|
-
const matcher = new RegExp(
|
|
339
|
+
const matcher = new RegExp(`(?<![\\w$])${escapeRegExp(segment)}\\s*[:=]`, "gu");
|
|
330
340
|
matcher.lastIndex = cursor;
|
|
331
341
|
const match = matcher.exec(source);
|
|
332
342
|
if (!match) {
|
|
@@ -408,6 +418,9 @@ var countBySeverity = (diagnostics) => {
|
|
|
408
418
|
|
|
409
419
|
// src/cli/log.ts
|
|
410
420
|
var logger = consola.withTag("blume");
|
|
421
|
+
var flushStdout = () => new Promise((resolve2) => {
|
|
422
|
+
process.stdout.write("", () => resolve2());
|
|
423
|
+
});
|
|
411
424
|
var reportDiagnosticsJson = (diagnostics, root) => {
|
|
412
425
|
const enriched = diagnostics.map((diagnostic) => {
|
|
413
426
|
const withDocs = enrichDiagnostic(diagnostic);
|
|
@@ -500,11 +513,11 @@ Next steps:
|
|
|
500
513
|
});
|
|
501
514
|
|
|
502
515
|
// src/cli/commands/build.ts
|
|
503
|
-
import { existsSync as
|
|
516
|
+
import { existsSync as existsSync16 } from "node:fs";
|
|
504
517
|
import { readdir, stat, writeFile as writeFile6 } from "node:fs/promises";
|
|
505
518
|
import { build } from "astro";
|
|
506
519
|
import { defineCommand as defineCommand2 } from "citty";
|
|
507
|
-
import { join as
|
|
520
|
+
import { join as join26 } from "pathe";
|
|
508
521
|
|
|
509
522
|
// src/core/frontmatter.ts
|
|
510
523
|
import baseMatter from "gray-matter";
|
|
@@ -699,14 +712,24 @@ var buildRobots = (project) => {
|
|
|
699
712
|
`;
|
|
700
713
|
};
|
|
701
714
|
|
|
715
|
+
// src/deploy/xml.ts
|
|
716
|
+
var escapeXml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
717
|
+
|
|
702
718
|
// src/deploy/sitemap.ts
|
|
719
|
+
var lastmodTag = (value) => {
|
|
720
|
+
if (!value) {
|
|
721
|
+
return "";
|
|
722
|
+
}
|
|
723
|
+
const date = new Date(value);
|
|
724
|
+
return Number.isNaN(date.getTime()) ? "" : `<lastmod>${date.toISOString().slice(0, 10)}</lastmod>`;
|
|
725
|
+
};
|
|
703
726
|
var buildSitemap = (project) => {
|
|
704
727
|
const { site } = project.config.deployment;
|
|
705
728
|
if (!(site && project.config.seo.sitemap)) {
|
|
706
729
|
return null;
|
|
707
730
|
}
|
|
708
731
|
const base = site.replace(/\/$/u, "");
|
|
709
|
-
const urls = project.graph.pages.filter((page) => !(page.meta.draft || page.meta.sidebar.hidden || page.meta.seo.noindex)).map((page) => ` <url><loc>${base}${page.route}</loc
|
|
732
|
+
const urls = project.graph.pages.filter((page) => !(page.meta.draft || page.meta.sidebar.hidden || page.meta.seo.noindex)).map((page) => ` <url><loc>${escapeXml(encodeURI(`${base}${page.route}`))}</loc>${lastmodTag(page.lastModified)}</url>`).toSorted();
|
|
710
733
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
711
734
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
712
735
|
${urls.join(`
|
|
@@ -2580,7 +2603,19 @@ var LINK = /\[(?<text>[^\]]*)\]\([^)]*\)/gu;
|
|
|
2580
2603
|
var HEADING_MARK = /^#{1,6}\s+/gmu;
|
|
2581
2604
|
var MARKDOWN_PUNCT = /[*_~>]+/gu;
|
|
2582
2605
|
var WHITESPACE = /\s+/gu;
|
|
2583
|
-
var toPlainText = (markdown) =>
|
|
2606
|
+
var toPlainText = (markdown) => {
|
|
2607
|
+
const withoutBlocks = markdown.replaceAll(CODE_FENCE, " ").replaceAll(IMAGE, " ").replaceAll(LINK, "$<text>");
|
|
2608
|
+
const pieces = [];
|
|
2609
|
+
let cursor = 0;
|
|
2610
|
+
for (const match of withoutBlocks.matchAll(INLINE_CODE)) {
|
|
2611
|
+
const start = match.index ?? 0;
|
|
2612
|
+
pieces.push(withoutBlocks.slice(cursor, start).replaceAll(HTML_OR_JSX, " "));
|
|
2613
|
+
pieces.push(match.groups?.code ?? "");
|
|
2614
|
+
cursor = start + match[0].length;
|
|
2615
|
+
}
|
|
2616
|
+
pieces.push(withoutBlocks.slice(cursor).replaceAll(HTML_OR_JSX, " "));
|
|
2617
|
+
return pieces.join("").replaceAll(HEADING_MARK, "").replaceAll(MARKDOWN_PUNCT, " ").replaceAll(WHITESPACE, " ").trim();
|
|
2618
|
+
};
|
|
2584
2619
|
var buildCrumbIndex = (sidebar) => {
|
|
2585
2620
|
const index = new Map;
|
|
2586
2621
|
const walk = (nodes, trail) => {
|
|
@@ -2654,7 +2689,7 @@ var syncAlgolia = async (records, config) => {
|
|
|
2654
2689
|
}
|
|
2655
2690
|
const { algoliasearch } = await import("algoliasearch");
|
|
2656
2691
|
const client = algoliasearch(config.appId, adminKey);
|
|
2657
|
-
await client.
|
|
2692
|
+
await client.replaceAllObjects({
|
|
2658
2693
|
indexName: config.indexName,
|
|
2659
2694
|
objects: records.map((record) => ({ ...record, objectID: record._id }))
|
|
2660
2695
|
});
|
|
@@ -2706,20 +2741,21 @@ var syncTypesense = async (records, config) => {
|
|
|
2706
2741
|
}
|
|
2707
2742
|
]
|
|
2708
2743
|
});
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
await
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
name:
|
|
2721
|
-
|
|
2722
|
-
|
|
2744
|
+
const collection = client.collections(config.collection);
|
|
2745
|
+
const exists = await collection.retrieve().then(() => true).catch(() => false);
|
|
2746
|
+
if (exists) {
|
|
2747
|
+
await collection.delete();
|
|
2748
|
+
}
|
|
2749
|
+
await client.collections().create({
|
|
2750
|
+
fields: [
|
|
2751
|
+
{ name: "title", type: "string" },
|
|
2752
|
+
{ name: "description", optional: true, type: "string" },
|
|
2753
|
+
{ name: "content", type: "string" },
|
|
2754
|
+
{ name: "url", type: "string" },
|
|
2755
|
+
{ facet: true, name: "tag", optional: true, type: "string" }
|
|
2756
|
+
],
|
|
2757
|
+
name: config.collection
|
|
2758
|
+
});
|
|
2723
2759
|
const documents = records.map((record) => ({
|
|
2724
2760
|
content: record.content,
|
|
2725
2761
|
description: record.description,
|
|
@@ -2753,8 +2789,58 @@ var syncSearchProvider = async (project, reporter) => {
|
|
|
2753
2789
|
}
|
|
2754
2790
|
};
|
|
2755
2791
|
|
|
2792
|
+
// src/cli/dev-lock.ts
|
|
2793
|
+
import {
|
|
2794
|
+
existsSync as existsSync3,
|
|
2795
|
+
mkdirSync,
|
|
2796
|
+
readFileSync as readFileSync2,
|
|
2797
|
+
rmSync,
|
|
2798
|
+
writeFileSync
|
|
2799
|
+
} from "node:fs";
|
|
2800
|
+
import { join as join6 } from "pathe";
|
|
2801
|
+
var lockPath = (outDir) => join6(outDir, "dev.lock");
|
|
2802
|
+
var isDevLocked = (outDir) => {
|
|
2803
|
+
const path = lockPath(outDir);
|
|
2804
|
+
if (!existsSync3(path)) {
|
|
2805
|
+
return false;
|
|
2806
|
+
}
|
|
2807
|
+
const pid = Number.parseInt(readFileSync2(path, "utf-8").trim(), 10);
|
|
2808
|
+
if (!(Number.isInteger(pid) && pid > 0)) {
|
|
2809
|
+
return false;
|
|
2810
|
+
}
|
|
2811
|
+
try {
|
|
2812
|
+
process.kill(pid, 0);
|
|
2813
|
+
return true;
|
|
2814
|
+
} catch {
|
|
2815
|
+
return false;
|
|
2816
|
+
}
|
|
2817
|
+
};
|
|
2818
|
+
var acquireDevLock = (outDir) => {
|
|
2819
|
+
const path = lockPath(outDir);
|
|
2820
|
+
mkdirSync(outDir, { recursive: true });
|
|
2821
|
+
writeFileSync(path, String(process.pid));
|
|
2822
|
+
let released = false;
|
|
2823
|
+
return () => {
|
|
2824
|
+
if (released) {
|
|
2825
|
+
return;
|
|
2826
|
+
}
|
|
2827
|
+
released = true;
|
|
2828
|
+
try {
|
|
2829
|
+
if (existsSync3(path) && readFileSync2(path, "utf-8").trim() === String(process.pid)) {
|
|
2830
|
+
rmSync(path, { force: true });
|
|
2831
|
+
}
|
|
2832
|
+
} catch {}
|
|
2833
|
+
};
|
|
2834
|
+
};
|
|
2835
|
+
var refuseIfDevRunning = (root, action) => {
|
|
2836
|
+
if (isDevLocked(join6(root, ".blume"))) {
|
|
2837
|
+
logger.error(`A \`blume dev\` server is running against .blume; ${action} would corrupt it. Stop the dev server first.`);
|
|
2838
|
+
process.exit(1);
|
|
2839
|
+
}
|
|
2840
|
+
};
|
|
2841
|
+
|
|
2756
2842
|
// src/astro/generate.ts
|
|
2757
|
-
import { existsSync as
|
|
2843
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, realpathSync } from "node:fs";
|
|
2758
2844
|
import {
|
|
2759
2845
|
lstat,
|
|
2760
2846
|
mkdir as mkdir2,
|
|
@@ -2766,7 +2852,7 @@ import {
|
|
|
2766
2852
|
} from "node:fs/promises";
|
|
2767
2853
|
import { createRequire as createRequire4 } from "node:module";
|
|
2768
2854
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
2769
|
-
import { basename as basename2, dirname as dirname7, join as
|
|
2855
|
+
import { basename as basename2, dirname as dirname7, join as join13, normalize, relative as relative6 } from "pathe";
|
|
2770
2856
|
import { glob as glob4 } from "tinyglobby";
|
|
2771
2857
|
|
|
2772
2858
|
// src/ai/ask-data.ts
|
|
@@ -2971,7 +3057,8 @@ var BUILTIN_MDX_TAGS = new Set([
|
|
|
2971
3057
|
"Tooltip",
|
|
2972
3058
|
"Tree",
|
|
2973
3059
|
"TypeTable",
|
|
2974
|
-
"Visibility"
|
|
3060
|
+
"Visibility",
|
|
3061
|
+
"YouTube"
|
|
2975
3062
|
]);
|
|
2976
3063
|
|
|
2977
3064
|
// src/core/component-diagnostics.ts
|
|
@@ -3000,7 +3087,7 @@ var validateUsedComponents = (pages, extraTags, registryNames) => {
|
|
|
3000
3087
|
};
|
|
3001
3088
|
|
|
3002
3089
|
// src/core/component-overrides.ts
|
|
3003
|
-
import { existsSync as
|
|
3090
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
3004
3091
|
import { dirname as dirname4, extname, isAbsolute, resolve as resolve2 } from "pathe";
|
|
3005
3092
|
import ts from "typescript";
|
|
3006
3093
|
var GROUPS = ["mdx", "layout", "islands"];
|
|
@@ -3089,7 +3176,7 @@ var findDefaultExportObject = (sourceFile) => {
|
|
|
3089
3176
|
var probeExtension = (base) => {
|
|
3090
3177
|
for (const extension of COMPONENT_EXTS) {
|
|
3091
3178
|
const candidate = `${base}.${extension}`;
|
|
3092
|
-
if (
|
|
3179
|
+
if (existsSync4(candidate)) {
|
|
3093
3180
|
return candidate;
|
|
3094
3181
|
}
|
|
3095
3182
|
}
|
|
@@ -3621,10 +3708,10 @@ var validateNavStructure = (navigation, pages) => [
|
|
|
3621
3708
|
];
|
|
3622
3709
|
|
|
3623
3710
|
// src/core/tsconfig-aliases.ts
|
|
3624
|
-
import { existsSync as
|
|
3711
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, statSync } from "node:fs";
|
|
3625
3712
|
import { createRequire as createRequire2 } from "node:module";
|
|
3626
3713
|
import { pathToFileURL } from "node:url";
|
|
3627
|
-
import { dirname as dirname5, isAbsolute as isAbsolute2, join as
|
|
3714
|
+
import { dirname as dirname5, isAbsolute as isAbsolute2, join as join7, resolve as resolve3 } from "pathe";
|
|
3628
3715
|
var stripJsonComments = (text) => {
|
|
3629
3716
|
let out = "";
|
|
3630
3717
|
let inString = false;
|
|
@@ -3687,7 +3774,7 @@ var resolveExtends = (spec, fromDir) => {
|
|
|
3687
3774
|
return candidates.find(isFile) ?? null;
|
|
3688
3775
|
}
|
|
3689
3776
|
try {
|
|
3690
|
-
const require_ = createRequire2(pathToFileURL(
|
|
3777
|
+
const require_ = createRequire2(pathToFileURL(join7(fromDir, "_.js")).href);
|
|
3691
3778
|
for (const sub of [`${spec}/tsconfig.json`, spec]) {
|
|
3692
3779
|
try {
|
|
3693
3780
|
return require_.resolve(sub);
|
|
@@ -3697,11 +3784,11 @@ var resolveExtends = (spec, fromDir) => {
|
|
|
3697
3784
|
return null;
|
|
3698
3785
|
};
|
|
3699
3786
|
var loadPaths = (file, seen) => {
|
|
3700
|
-
if (seen.has(file) || !
|
|
3787
|
+
if (seen.has(file) || !existsSync5(file)) {
|
|
3701
3788
|
return null;
|
|
3702
3789
|
}
|
|
3703
3790
|
seen.add(file);
|
|
3704
|
-
const json = parseJsonc(
|
|
3791
|
+
const json = parseJsonc(readFileSync3(file, "utf-8"));
|
|
3705
3792
|
if (!json) {
|
|
3706
3793
|
return null;
|
|
3707
3794
|
}
|
|
@@ -3739,7 +3826,7 @@ var toAlias = (key, value, baseDir) => {
|
|
|
3739
3826
|
return { find, replacement: resolve3(baseDir, target) };
|
|
3740
3827
|
};
|
|
3741
3828
|
var resolveTsconfigAliases = (root) => {
|
|
3742
|
-
const entry = ["tsconfig.json", "jsconfig.json"].map((name) =>
|
|
3829
|
+
const entry = ["tsconfig.json", "jsconfig.json"].map((name) => join7(root, name)).find((file) => existsSync5(file));
|
|
3743
3830
|
if (!entry) {
|
|
3744
3831
|
return {};
|
|
3745
3832
|
}
|
|
@@ -3798,7 +3885,6 @@ var buildRssFeeds = (project) => {
|
|
|
3798
3885
|
}
|
|
3799
3886
|
return feeds;
|
|
3800
3887
|
};
|
|
3801
|
-
var escapeXml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
3802
3888
|
var renderItem = (item) => {
|
|
3803
3889
|
const parts = [
|
|
3804
3890
|
` <title>${escapeXml(item.title)}</title>`,
|
|
@@ -3838,11 +3924,18 @@ ${items}
|
|
|
3838
3924
|
|
|
3839
3925
|
// src/openapi/scalar.ts
|
|
3840
3926
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
3841
|
-
import { isAbsolute as isAbsolute3, join as
|
|
3927
|
+
import { isAbsolute as isAbsolute3, join as join10 } from "pathe";
|
|
3842
3928
|
|
|
3843
3929
|
// src/astro/templates.ts
|
|
3844
|
-
import { existsSync as
|
|
3845
|
-
import { dirname as dirname6, join as
|
|
3930
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4 } from "node:fs";
|
|
3931
|
+
import { dirname as dirname6, join as join9 } from "pathe";
|
|
3932
|
+
|
|
3933
|
+
// src/core/assets.ts
|
|
3934
|
+
import { join as join8 } from "pathe";
|
|
3935
|
+
var resolveAssetMounts = (root, assets) => assets.map((entry) => {
|
|
3936
|
+
const rel = entry.replace(/^[./]+/u, "").replaceAll(/\.\.\/?/gu, "").replace(/\/+$/u, "");
|
|
3937
|
+
return { dir: join8(root, rel), url: `/${rel}` };
|
|
3938
|
+
});
|
|
3846
3939
|
|
|
3847
3940
|
// src/theme/fonts.ts
|
|
3848
3941
|
var FALLBACKS = {
|
|
@@ -4000,17 +4093,17 @@ var WORKSPACE_MARKERS = [
|
|
|
4000
4093
|
"yarn.lock"
|
|
4001
4094
|
];
|
|
4002
4095
|
var hasWorkspacesField = (pkgPath) => {
|
|
4003
|
-
if (!
|
|
4096
|
+
if (!existsSync6(pkgPath)) {
|
|
4004
4097
|
return false;
|
|
4005
4098
|
}
|
|
4006
4099
|
try {
|
|
4007
|
-
const pkg = JSON.parse(
|
|
4100
|
+
const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
|
|
4008
4101
|
return pkg.workspaces !== undefined;
|
|
4009
4102
|
} catch {
|
|
4010
4103
|
return false;
|
|
4011
4104
|
}
|
|
4012
4105
|
};
|
|
4013
|
-
var hasWorkspaceMarker = (dir) => hasWorkspacesField(
|
|
4106
|
+
var hasWorkspaceMarker = (dir) => hasWorkspacesField(join9(dir, "package.json")) || WORKSPACE_MARKERS.some((marker) => existsSync6(join9(dir, marker)));
|
|
4014
4107
|
var findWorkspaceRoot = (start) => {
|
|
4015
4108
|
let dir = start;
|
|
4016
4109
|
for (;; ) {
|
|
@@ -4144,7 +4237,8 @@ var astroConfigTemplate = (options) => {
|
|
|
4144
4237
|
if (needsSvelte) {
|
|
4145
4238
|
integrations.push("svelte()");
|
|
4146
4239
|
}
|
|
4147
|
-
|
|
4240
|
+
const assets = resolveAssetMounts(context.root, config.content.assets);
|
|
4241
|
+
integrations.push(`blumeIntegration(${JSON.stringify({ assets, base: deployment.base, contentRoutes, pages })})`);
|
|
4148
4242
|
return `// Generated by Blume. Do not edit; this file is recreated on each run.
|
|
4149
4243
|
${defineConfigImport}
|
|
4150
4244
|
import mdx from "@astrojs/mdx";
|
|
@@ -4200,7 +4294,7 @@ export default defineConfig({
|
|
|
4200
4294
|
});
|
|
4201
4295
|
`;
|
|
4202
4296
|
};
|
|
4203
|
-
var stagedContentDir = (outDir) =>
|
|
4297
|
+
var stagedContentDir = (outDir) => join9(outDir, "content");
|
|
4204
4298
|
var contentConfigTemplate = (options) => {
|
|
4205
4299
|
const { context, config } = options;
|
|
4206
4300
|
const stagedBase = options.stagedBase ?? stagedContentDir(context.outDir);
|
|
@@ -4257,31 +4351,44 @@ const provider = createOpenAICompatible({
|
|
|
4257
4351
|
modelExpr = `provider(${JSON.stringify(backend.model)})`;
|
|
4258
4352
|
}
|
|
4259
4353
|
if (grounded) {
|
|
4260
|
-
imports.push('import { createAskContext } from "blume/ai/ask-context.ts";', 'import askData from "
|
|
4354
|
+
imports.push('import { createAskContext } from "blume/ai/ask-context.ts";', 'import askData from "../../generated/ask-data.json";');
|
|
4261
4355
|
setup += `
|
|
4262
4356
|
const ground = createAskContext(askData);
|
|
4263
4357
|
`;
|
|
4264
4358
|
}
|
|
4265
|
-
const
|
|
4266
|
-
const
|
|
4267
|
-
|
|
4268
|
-
(
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
messages,
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
}
|
|
4277
|
-
const
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4359
|
+
const validate = ` const body = await request.json().catch(() => null);
|
|
4360
|
+
const messages = body?.messages;
|
|
4361
|
+
if (
|
|
4362
|
+
!Array.isArray(messages) ||
|
|
4363
|
+
messages.length === 0 ||
|
|
4364
|
+
messages.length > 40 ||
|
|
4365
|
+
JSON.stringify(messages).length > 24_000
|
|
4366
|
+
) {
|
|
4367
|
+
return new Response("Invalid request: send 1-40 messages.", {
|
|
4368
|
+
status: 400,
|
|
4369
|
+
});
|
|
4370
|
+
}`;
|
|
4371
|
+
const stream = grounded ? ` const system =
|
|
4372
|
+
(await ground(messages, body.page)) ??
|
|
4373
|
+
"You are a helpful documentation assistant. Answer using the project's documentation.";
|
|
4374
|
+
const result = streamText({
|
|
4375
|
+
model: ${modelExpr},
|
|
4376
|
+
system,
|
|
4377
|
+
messages,
|
|
4378
|
+
});` : ` const result = streamText({
|
|
4379
|
+
model: ${modelExpr},
|
|
4380
|
+
system:
|
|
4381
|
+
"You are a helpful documentation assistant. Answer using the project's documentation.",
|
|
4382
|
+
messages,
|
|
4383
|
+
});`;
|
|
4384
|
+
const handler = `export const POST: APIRoute = async ({ request }) => {
|
|
4385
|
+
${validate}
|
|
4386
|
+
try {
|
|
4387
|
+
${stream}
|
|
4388
|
+
return result.toTextStreamResponse();
|
|
4389
|
+
} catch {
|
|
4390
|
+
return new Response("Failed to generate a response.", { status: 500 });
|
|
4391
|
+
}
|
|
4285
4392
|
};`;
|
|
4286
4393
|
return `// Generated by Blume. Do not edit.
|
|
4287
4394
|
${imports.join(`
|
|
@@ -4605,6 +4712,7 @@ import TreeFile from "blume/components/content/TreeFile.astro";
|
|
|
4605
4712
|
import TreeFolder from "blume/components/content/TreeFolder.astro";
|
|
4606
4713
|
import TypeTable from "blume/components/content/TypeTable.astro";
|
|
4607
4714
|
import Visibility from "blume/components/content/Visibility.astro";
|
|
4715
|
+
import YouTube from "blume/components/content/YouTube.astro";
|
|
4608
4716
|
import Icon from "blume/components/Icon.astro";
|
|
4609
4717
|
${mathImport}import { mdxComponents as userMdx, layoutOverrides } from "../generated/components.ts";
|
|
4610
4718
|
import { islandComponents } from "../generated/islands.ts";
|
|
@@ -4650,6 +4758,7 @@ const components = {
|
|
|
4650
4758
|
Tree,
|
|
4651
4759
|
TypeTable,
|
|
4652
4760
|
Visibility,
|
|
4761
|
+
YouTube,
|
|
4653
4762
|
${mathEntry}...islandComponents,
|
|
4654
4763
|
...userMdx,
|
|
4655
4764
|
};
|
|
@@ -5061,8 +5170,9 @@ var runtimeTsconfigTemplate = () => `${JSON.stringify({
|
|
|
5061
5170
|
`;
|
|
5062
5171
|
|
|
5063
5172
|
// src/theme/palette.ts
|
|
5173
|
+
var FALLBACK_ACCENT = "oklch(0.62 0.16 250)";
|
|
5064
5174
|
var ACCENTS = {
|
|
5065
|
-
blue:
|
|
5175
|
+
blue: FALLBACK_ACCENT,
|
|
5066
5176
|
green: "oklch(0.6 0.16 150)",
|
|
5067
5177
|
orange: "oklch(0.68 0.17 50)",
|
|
5068
5178
|
pink: "oklch(0.65 0.2 350)",
|
|
@@ -5070,6 +5180,9 @@ var ACCENTS = {
|
|
|
5070
5180
|
red: "oklch(0.58 0.22 25)",
|
|
5071
5181
|
teal: "oklch(0.6 0.12 195)"
|
|
5072
5182
|
};
|
|
5183
|
+
var CSS_COLOR = /^[\w\s#%.,()/+-]+$/u;
|
|
5184
|
+
var safeColor = (value, fallback) => CSS_COLOR.test(value.trim()) ? value.trim() : fallback;
|
|
5185
|
+
var safeColorOrNull = (value) => value && CSS_COLOR.test(value.trim()) ? value.trim() : null;
|
|
5073
5186
|
var RADII = {
|
|
5074
5187
|
lg: "0.75rem",
|
|
5075
5188
|
md: "0.5rem",
|
|
@@ -5104,7 +5217,7 @@ var themeRootCss = (theme, options) => [
|
|
|
5104
5217
|
` --blume-accent: ${options.accent};`,
|
|
5105
5218
|
...cssToken("--blume-action", options.action),
|
|
5106
5219
|
...cssToken("--blume-action-foreground", options.action ? "oklch(1 0 0)" : null),
|
|
5107
|
-
...cssToken("--blume-background", theme.background),
|
|
5220
|
+
...cssToken("--blume-background", safeColorOrNull(theme.background)),
|
|
5108
5221
|
...cssToken("--blume-background-image", theme.backgroundImage ? backgroundImageCss(theme.backgroundImage) : null),
|
|
5109
5222
|
options.backgroundDecoration.trimEnd(),
|
|
5110
5223
|
` --blume-radius: ${options.radius};`
|
|
@@ -5113,7 +5226,7 @@ var themeRootCss = (theme, options) => [
|
|
|
5113
5226
|
var themeDarkCss = (theme, accentDark) => {
|
|
5114
5227
|
const tokens = [
|
|
5115
5228
|
...cssToken("--blume-accent", accentDark),
|
|
5116
|
-
...cssToken("--blume-background", theme.backgroundDark),
|
|
5229
|
+
...cssToken("--blume-background", safeColorOrNull(theme.backgroundDark)),
|
|
5117
5230
|
...cssToken("--blume-background-image", theme.backgroundImageDark ? backgroundImageCss(theme.backgroundImageDark) : null)
|
|
5118
5231
|
];
|
|
5119
5232
|
if (tokens.length === 0) {
|
|
@@ -5125,12 +5238,12 @@ ${tokens.join(`
|
|
|
5125
5238
|
}
|
|
5126
5239
|
`;
|
|
5127
5240
|
};
|
|
5128
|
-
var resolveAccent = (theme) => ACCENTS[theme.accent] ?? theme.accent;
|
|
5241
|
+
var resolveAccent = (theme) => ACCENTS[theme.accent] ?? safeColor(theme.accent, FALLBACK_ACCENT);
|
|
5129
5242
|
var resolveRadius = (theme) => RADII[theme.radius];
|
|
5130
5243
|
var buildThemeCss = (theme) => {
|
|
5131
|
-
const accent = ACCENTS[theme.accent] ?? theme.accent;
|
|
5132
|
-
const accentDark = theme.accentDark ? ACCENTS[theme.accentDark] ?? theme.accentDark : null;
|
|
5133
|
-
const action = theme.action ? ACCENTS[theme.action] ?? theme.action : null;
|
|
5244
|
+
const accent = ACCENTS[theme.accent] ?? safeColor(theme.accent, FALLBACK_ACCENT);
|
|
5245
|
+
const accentDark = theme.accentDark ? ACCENTS[theme.accentDark] ?? safeColor(theme.accentDark, FALLBACK_ACCENT) : null;
|
|
5246
|
+
const action = theme.action ? ACCENTS[theme.action] ?? safeColor(theme.action, FALLBACK_ACCENT) : null;
|
|
5134
5247
|
const backgroundDecoration = backgroundDecorationCss(theme.backgroundDecoration);
|
|
5135
5248
|
const radius = RADII[theme.radius];
|
|
5136
5249
|
const root = themeRootCss(theme, {
|
|
@@ -5224,7 +5337,7 @@ var specConfiguration = async (spec, root) => {
|
|
|
5224
5337
|
if (URL_SPEC.test(spec)) {
|
|
5225
5338
|
return { config: { url: spec } };
|
|
5226
5339
|
}
|
|
5227
|
-
const absolute = isAbsolute3(spec) ? spec :
|
|
5340
|
+
const absolute = isAbsolute3(spec) ? spec : join10(root, spec);
|
|
5228
5341
|
try {
|
|
5229
5342
|
return { config: { content: await readFile4(absolute, "utf-8") } };
|
|
5230
5343
|
} catch {
|
|
@@ -5897,7 +6010,7 @@ ${options.userTheme}
|
|
|
5897
6010
|
`;
|
|
5898
6011
|
|
|
5899
6012
|
// src/theme/twoslash.ts
|
|
5900
|
-
import { readFileSync as
|
|
6013
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
5901
6014
|
import { createRequire as createRequire3 } from "node:module";
|
|
5902
6015
|
var require2 = createRequire3(import.meta.url);
|
|
5903
6016
|
var OVERRIDES = `
|
|
@@ -5959,7 +6072,7 @@ var OVERRIDES = `
|
|
|
5959
6072
|
`;
|
|
5960
6073
|
var twoslashCss = () => {
|
|
5961
6074
|
const file = require2.resolve("@shikijs/twoslash/style-rich.css");
|
|
5962
|
-
return `${
|
|
6075
|
+
return `${readFileSync5(file, "utf-8")}
|
|
5963
6076
|
${OVERRIDES}`;
|
|
5964
6077
|
};
|
|
5965
6078
|
|
|
@@ -6062,12 +6175,12 @@ export const layoutOverrides = { ...(overrides.layout ?? {})${layoutEntries.leng
|
|
|
6062
6175
|
|
|
6063
6176
|
// src/astro/examples.ts
|
|
6064
6177
|
import { readFile as readFile6 } from "node:fs/promises";
|
|
6065
|
-
import { join as
|
|
6178
|
+
import { join as join12, relative as relative4 } from "pathe";
|
|
6066
6179
|
import { glob as glob2 } from "tinyglobby";
|
|
6067
6180
|
|
|
6068
6181
|
// src/astro/islands.ts
|
|
6069
6182
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
6070
|
-
import { basename, join as
|
|
6183
|
+
import { basename, join as join11 } from "pathe";
|
|
6071
6184
|
import { glob } from "tinyglobby";
|
|
6072
6185
|
var DEFAULT_CLIENT = "visible";
|
|
6073
6186
|
var VALID_MODES = new Set([
|
|
@@ -6096,7 +6209,7 @@ var readClientMode = (source, file, warnings) => {
|
|
|
6096
6209
|
return mode;
|
|
6097
6210
|
};
|
|
6098
6211
|
var discoverIslands = async (root) => {
|
|
6099
|
-
const dir =
|
|
6212
|
+
const dir = join11(root, "islands");
|
|
6100
6213
|
const matches = await glob(["**/*.{jsx,svelte,tsx,vue}"], {
|
|
6101
6214
|
absolute: true,
|
|
6102
6215
|
cwd: dir,
|
|
@@ -6115,8 +6228,8 @@ var discoverIslands = async (root) => {
|
|
|
6115
6228
|
continue;
|
|
6116
6229
|
}
|
|
6117
6230
|
const name = base.replace(ISLAND_FILE, "");
|
|
6118
|
-
if (!/^[A-Z]
|
|
6119
|
-
warnings.push(`Island "${file}" must have a PascalCase filename to be used in MDX (e.g. Counter.tsx → <Counter />); skipping it.`);
|
|
6231
|
+
if (!/^[A-Z][A-Za-z0-9_]*$/u.test(name)) {
|
|
6232
|
+
warnings.push(`Island "${file}" must have a PascalCase identifier filename to be used in MDX (letters, digits, and underscores only, e.g. Counter.tsx → <Counter />); skipping it.`);
|
|
6120
6233
|
continue;
|
|
6121
6234
|
}
|
|
6122
6235
|
const existing = seen.get(name);
|
|
@@ -6159,7 +6272,7 @@ var splitGlobBase = (pattern) => {
|
|
|
6159
6272
|
};
|
|
6160
6273
|
var discoverExamples = async (root, pattern = "examples") => {
|
|
6161
6274
|
const { base, rest } = GLOB_MAGIC.test(pattern) ? splitGlobBase(pattern) : { base: pattern, rest: DEFAULT_EXAMPLE_GLOB };
|
|
6162
|
-
const dir =
|
|
6275
|
+
const dir = join12(root, base);
|
|
6163
6276
|
const matches = await glob2([rest], {
|
|
6164
6277
|
absolute: true,
|
|
6165
6278
|
cwd: dir,
|
|
@@ -6209,7 +6322,10 @@ var discoverPages = async (pagesRoot) => {
|
|
|
6209
6322
|
return files.map((file) => {
|
|
6210
6323
|
const rel = relative5(pagesRoot, file);
|
|
6211
6324
|
const withoutExt = rel.slice(0, rel.length - extname2(rel).length);
|
|
6212
|
-
const parts = withoutExt.split("/")
|
|
6325
|
+
const parts = withoutExt.split("/");
|
|
6326
|
+
if (parts.at(-1) === "index") {
|
|
6327
|
+
parts.pop();
|
|
6328
|
+
}
|
|
6213
6329
|
const pattern = parts.length === 0 ? "/" : `/${parts.join("/")}`;
|
|
6214
6330
|
return { entrypoint: file, pattern };
|
|
6215
6331
|
});
|
|
@@ -6237,10 +6353,10 @@ var customOgRoutes = (pages, siteTitle) => {
|
|
|
6237
6353
|
};
|
|
6238
6354
|
|
|
6239
6355
|
// src/astro/generate.ts
|
|
6240
|
-
var BLUME_SRC =
|
|
6356
|
+
var BLUME_SRC = join13(packageRoot(), "src");
|
|
6241
6357
|
var canResolveFrom = (fromDir, spec) => {
|
|
6242
6358
|
try {
|
|
6243
|
-
createRequire4(pathToFileURL2(
|
|
6359
|
+
createRequire4(pathToFileURL2(join13(fromDir, "_.js")).href).resolve(spec);
|
|
6244
6360
|
return true;
|
|
6245
6361
|
} catch {
|
|
6246
6362
|
return false;
|
|
@@ -6248,15 +6364,15 @@ var canResolveFrom = (fromDir, spec) => {
|
|
|
6248
6364
|
};
|
|
6249
6365
|
var resolvedAstroPath = (fromDir) => {
|
|
6250
6366
|
try {
|
|
6251
|
-
const pkg = createRequire4(pathToFileURL2(
|
|
6367
|
+
const pkg = createRequire4(pathToFileURL2(join13(fromDir, "_.js")).href).resolve("astro/package.json");
|
|
6252
6368
|
return realpathSync(pkg);
|
|
6253
6369
|
} catch {
|
|
6254
6370
|
return null;
|
|
6255
6371
|
}
|
|
6256
6372
|
};
|
|
6257
6373
|
var blumeDepsDir = (pkgDir = packageRoot()) => {
|
|
6258
|
-
const candidates = [
|
|
6259
|
-
return candidates.find((dir) =>
|
|
6374
|
+
const candidates = [join13(pkgDir, "node_modules"), dirname7(pkgDir)];
|
|
6375
|
+
return candidates.find((dir) => existsSync7(join13(dir, "astro"))) ?? null;
|
|
6260
6376
|
};
|
|
6261
6377
|
var linkDepsJunction = async (link, depsDir) => {
|
|
6262
6378
|
const existing = await lstat(link).catch(() => null);
|
|
@@ -6274,7 +6390,7 @@ var readPkgVersion = (pkgJsonPath) => {
|
|
|
6274
6390
|
return null;
|
|
6275
6391
|
}
|
|
6276
6392
|
try {
|
|
6277
|
-
return JSON.parse(
|
|
6393
|
+
return JSON.parse(readFileSync6(pkgJsonPath, "utf-8")).version ?? null;
|
|
6278
6394
|
} catch {
|
|
6279
6395
|
return null;
|
|
6280
6396
|
}
|
|
@@ -6296,8 +6412,8 @@ var ensureDepsLink = async (outDir, pkgDir = packageRoot()) => {
|
|
|
6296
6412
|
if (blumeAstro && outDirAstro === blumeAstro) {
|
|
6297
6413
|
return null;
|
|
6298
6414
|
}
|
|
6299
|
-
if (
|
|
6300
|
-
await linkDepsJunction(
|
|
6415
|
+
if (existsSync7(join13(depsDir, "@astrojs", "mdx"))) {
|
|
6416
|
+
await linkDepsJunction(join13(outDir, "node_modules"), depsDir);
|
|
6301
6417
|
return null;
|
|
6302
6418
|
}
|
|
6303
6419
|
return astroConflictWarning(blumeAstro, outDirAstro);
|
|
@@ -6376,11 +6492,11 @@ var writeStagedContent = async (out, staged) => {
|
|
|
6376
6492
|
const contentDir = stagedContentDir(out);
|
|
6377
6493
|
const written = new Set;
|
|
6378
6494
|
await Promise.all([...staged].map(async ([entryId, text]) => {
|
|
6379
|
-
const path =
|
|
6495
|
+
const path = join13(contentDir, entryId);
|
|
6380
6496
|
written.add(normalize(path));
|
|
6381
6497
|
await writeIfChanged(path, text);
|
|
6382
6498
|
}));
|
|
6383
|
-
if (
|
|
6499
|
+
if (existsSync7(contentDir)) {
|
|
6384
6500
|
await pruneOrphans(contentDir, written);
|
|
6385
6501
|
}
|
|
6386
6502
|
};
|
|
@@ -6397,11 +6513,11 @@ var resolveLogo = (project) => {
|
|
|
6397
6513
|
if (light && light === dark && light.toLowerCase().endsWith(".svg")) {
|
|
6398
6514
|
const rel = light.replace(/^\//u, "");
|
|
6399
6515
|
const file = [
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
].find((path) =>
|
|
6516
|
+
join13(project.context.root, "public", rel),
|
|
6517
|
+
join13(project.context.root, rel)
|
|
6518
|
+
].find((path) => existsSync7(path));
|
|
6403
6519
|
if (file) {
|
|
6404
|
-
return { alt, href, svg:
|
|
6520
|
+
return { alt, href, svg: readFileSync6(file, "utf-8") };
|
|
6405
6521
|
}
|
|
6406
6522
|
}
|
|
6407
6523
|
return { alt, dark, href, light };
|
|
@@ -6425,9 +6541,9 @@ var faviconType = (name) => {
|
|
|
6425
6541
|
const ext = name.split(".").pop()?.toLowerCase();
|
|
6426
6542
|
return ext ? FAVICON_TYPES[ext] : undefined;
|
|
6427
6543
|
};
|
|
6428
|
-
var inlineDataUri = (file, type) => `data:${type};base64,${
|
|
6544
|
+
var inlineDataUri = (file, type) => `data:${type};base64,${readFileSync6(file).toString("base64")}`;
|
|
6429
6545
|
var defaultFavicon = () => ({
|
|
6430
|
-
href: inlineDataUri(
|
|
6546
|
+
href: inlineDataUri(join13(BLUME_SRC, "assets", "icon.png"), "image/png"),
|
|
6431
6547
|
type: "image/png"
|
|
6432
6548
|
});
|
|
6433
6549
|
var APPLE_ICON_CANDIDATES = [
|
|
@@ -6439,13 +6555,13 @@ var APPLE_ICON_CANDIDATES = [
|
|
|
6439
6555
|
var resolveIconFile = (project, candidates) => {
|
|
6440
6556
|
const { root } = project.context;
|
|
6441
6557
|
for (const name of candidates) {
|
|
6442
|
-
if (
|
|
6558
|
+
if (existsSync7(join13(root, "public", name))) {
|
|
6443
6559
|
return { href: `/${name}`, type: faviconType(name) };
|
|
6444
6560
|
}
|
|
6445
6561
|
}
|
|
6446
6562
|
for (const name of candidates) {
|
|
6447
|
-
const file =
|
|
6448
|
-
if (
|
|
6563
|
+
const file = join13(root, name);
|
|
6564
|
+
if (existsSync7(file)) {
|
|
6449
6565
|
const type = faviconType(name);
|
|
6450
6566
|
return { href: inlineDataUri(file, type ?? "image/x-icon"), type };
|
|
6451
6567
|
}
|
|
@@ -6573,7 +6689,7 @@ var buildRuntimeData = (project) => {
|
|
|
6573
6689
|
var planMcp = (project, srcDir) => {
|
|
6574
6690
|
const { config } = project;
|
|
6575
6691
|
const { route } = config.mcp;
|
|
6576
|
-
const dir =
|
|
6692
|
+
const dir = join13(srcDir, "blume-mcp");
|
|
6577
6693
|
const base = {
|
|
6578
6694
|
dir,
|
|
6579
6695
|
discoveryPages: [],
|
|
@@ -6597,11 +6713,11 @@ var planMcp = (project, srcDir) => {
|
|
|
6597
6713
|
...base,
|
|
6598
6714
|
discoveryPages: [
|
|
6599
6715
|
{
|
|
6600
|
-
entrypoint:
|
|
6716
|
+
entrypoint: join13(dir, "discovery.ts"),
|
|
6601
6717
|
pattern: "/.well-known/mcp.json"
|
|
6602
6718
|
},
|
|
6603
6719
|
{
|
|
6604
|
-
entrypoint:
|
|
6720
|
+
entrypoint: join13(dir, "server-card.ts"),
|
|
6605
6721
|
pattern: "/.well-known/mcp/server-card.json"
|
|
6606
6722
|
}
|
|
6607
6723
|
],
|
|
@@ -6620,11 +6736,11 @@ var writeMcpFiles = async (project, plan, write) => {
|
|
|
6620
6736
|
version: data.version
|
|
6621
6737
|
};
|
|
6622
6738
|
await Promise.all([
|
|
6623
|
-
write(
|
|
6739
|
+
write(join13(plan.srcDir, "generated", "mcp-data.json"), `${JSON.stringify(data)}
|
|
6624
6740
|
`),
|
|
6625
|
-
write(
|
|
6626
|
-
write(
|
|
6627
|
-
write(
|
|
6741
|
+
write(join13(plan.srcDir, "pages", mcpPageFile(plan.route)), mcpEndpointTemplate(plan.route)),
|
|
6742
|
+
write(join13(plan.dir, "discovery.ts"), staticJsonEndpointTemplate(buildMcpDiscovery(discoveryInput))),
|
|
6743
|
+
write(join13(plan.dir, "server-card.ts"), staticJsonEndpointTemplate(buildMcpServerCard(discoveryInput)))
|
|
6628
6744
|
]);
|
|
6629
6745
|
};
|
|
6630
6746
|
var writeAskFiles = async (project, srcDir, write) => {
|
|
@@ -6634,16 +6750,16 @@ var writeAskFiles = async (project, srcDir, write) => {
|
|
|
6634
6750
|
}
|
|
6635
6751
|
const grounded = ask.provider !== "inkeep";
|
|
6636
6752
|
if (grounded) {
|
|
6637
|
-
await write(
|
|
6753
|
+
await write(join13(srcDir, "generated", "ask-data.json"), `${JSON.stringify(await buildAskData(project))}
|
|
6638
6754
|
`);
|
|
6639
6755
|
}
|
|
6640
|
-
await write(
|
|
6756
|
+
await write(join13(srcDir, "pages", "api", "ask.ts"), askEndpointTemplate(resolveAskBackend(ask), grounded));
|
|
6641
6757
|
};
|
|
6642
6758
|
var writeNotFoundPage = async (write, srcDir, pages, contentPages) => {
|
|
6643
6759
|
if (routeIsTaken(pages, contentPages, "/404")) {
|
|
6644
6760
|
return;
|
|
6645
6761
|
}
|
|
6646
|
-
await write(
|
|
6762
|
+
await write(join13(srcDir, "pages", "404.astro"), notFoundPageTemplate());
|
|
6647
6763
|
};
|
|
6648
6764
|
var shouldGenerateChangelog = (project) => {
|
|
6649
6765
|
const hasChangelog = project.graph.pages.some((page) => page.contentType === "changelog" && !(page.meta.draft || page.meta.sidebar.hidden));
|
|
@@ -6662,11 +6778,11 @@ var buildComponentSlots = async (componentsFile) => {
|
|
|
6662
6778
|
var generateRuntime = async (project) => {
|
|
6663
6779
|
const { context, config } = project;
|
|
6664
6780
|
const out = context.outDir;
|
|
6665
|
-
const srcDir =
|
|
6666
|
-
const dataPath =
|
|
6667
|
-
const themePath =
|
|
6668
|
-
const searchClientPath =
|
|
6669
|
-
const examplesPath =
|
|
6781
|
+
const srcDir = join13(out, "src");
|
|
6782
|
+
const dataPath = join13(srcDir, "generated", "data.json");
|
|
6783
|
+
const themePath = join13(srcDir, "generated", "app.css");
|
|
6784
|
+
const searchClientPath = join13(srcDir, "generated", "search-client.ts");
|
|
6785
|
+
const examplesPath = join13(srcDir, "generated", "examples.ts");
|
|
6670
6786
|
const written = new Set;
|
|
6671
6787
|
const write = (path, content) => {
|
|
6672
6788
|
written.add(normalize(path));
|
|
@@ -6702,7 +6818,7 @@ var generateRuntime = async (project) => {
|
|
|
6702
6818
|
const staged = collectStaged(project);
|
|
6703
6819
|
const hasStaged = staged.size > 0;
|
|
6704
6820
|
const structural = await Promise.all([
|
|
6705
|
-
write(
|
|
6821
|
+
write(join13(out, "astro.config.mjs"), astroConfigTemplate({
|
|
6706
6822
|
aliases: resolveTsconfigAliases(context.root),
|
|
6707
6823
|
config,
|
|
6708
6824
|
contentRoutes: project.manifest.routes.map((route) => route.path),
|
|
@@ -6716,20 +6832,20 @@ var generateRuntime = async (project) => {
|
|
|
6716
6832
|
searchClientPath,
|
|
6717
6833
|
themePath
|
|
6718
6834
|
})),
|
|
6719
|
-
write(
|
|
6720
|
-
write(
|
|
6721
|
-
write(
|
|
6722
|
-
write(
|
|
6723
|
-
write(
|
|
6835
|
+
write(join13(out, "package.json"), runtimePackageTemplate(runtimeDependencies({ config, needsReact, needsSvelte, needsVue }))),
|
|
6836
|
+
write(join13(out, "tsconfig.json"), runtimeTsconfigTemplate()),
|
|
6837
|
+
write(join13(srcDir, "env.d.ts"), envTemplate()),
|
|
6838
|
+
write(join13(srcDir, "content.config.ts"), contentConfigTemplate({ config, context, staged: hasStaged })),
|
|
6839
|
+
write(join13(srcDir, "pages", "[...slug].astro"), catchAllPageTemplate({
|
|
6724
6840
|
askEnabled,
|
|
6725
6841
|
exportEpub,
|
|
6726
6842
|
exportPdf,
|
|
6727
6843
|
mathEnabled: config.markdown.math,
|
|
6728
6844
|
needsReact
|
|
6729
6845
|
})),
|
|
6730
|
-
write(
|
|
6731
|
-
write(
|
|
6732
|
-
write(
|
|
6846
|
+
write(join13(srcDir, "generated", "components.ts"), slotPlan.module),
|
|
6847
|
+
write(join13(srcDir, "generated", "islands.ts"), islandMapTemplate(islandDiscovery.islands)),
|
|
6848
|
+
write(join13(srcDir, "generated", "examples.ts"), exampleMapTemplate(exampleDiscovery.examples)),
|
|
6733
6849
|
write(themePath, tailwindEntryTemplate({
|
|
6734
6850
|
configTokens: `${buildThemeCss(config.theme)}${buildFontsCss(config.theme.fonts)}`,
|
|
6735
6851
|
sources: [
|
|
@@ -6740,16 +6856,16 @@ var generateRuntime = async (project) => {
|
|
|
6740
6856
|
userTheme
|
|
6741
6857
|
}))
|
|
6742
6858
|
]);
|
|
6743
|
-
await Promise.all(islandDiscovery.islands.map((island) => write(
|
|
6744
|
-
await Promise.all(slotPlan.wrappers.map((wrapper) => write(
|
|
6745
|
-
await Promise.all(exampleDiscovery.examples.map((example) => write(
|
|
6859
|
+
await Promise.all(islandDiscovery.islands.map((island) => write(join13(srcDir, "generated", "islands", `${island.name}.astro`), islandWrapperTemplate(island))));
|
|
6860
|
+
await Promise.all(slotPlan.wrappers.map((wrapper) => write(join13(srcDir, "generated", "component-slots", `${wrapper.name}.astro`), wrapper.content)));
|
|
6861
|
+
await Promise.all(exampleDiscovery.examples.map((example) => write(join13(srcDir, "generated", "examples", `${exampleSlug(example.path)}.astro`), exampleWrapperTemplate(example))));
|
|
6746
6862
|
await writeAskFiles(project, srcDir, write);
|
|
6747
6863
|
await writeMcpFiles(project, mcp, write);
|
|
6748
6864
|
if (config.seo.og.enabled) {
|
|
6749
|
-
await write(
|
|
6865
|
+
await write(join13(srcDir, "pages", "og", "[...slug].png.ts"), ogEndpointTemplate(ogRoutes));
|
|
6750
6866
|
}
|
|
6751
6867
|
if (shouldGenerateChangelog(project)) {
|
|
6752
|
-
await write(
|
|
6868
|
+
await write(join13(srcDir, "pages", "changelog.astro"), changelogIndexTemplate({
|
|
6753
6869
|
askEnabled,
|
|
6754
6870
|
exportEpub,
|
|
6755
6871
|
exportPdf,
|
|
@@ -6761,27 +6877,27 @@ var generateRuntime = async (project) => {
|
|
|
6761
6877
|
await write(searchClientPath, searchClientTemplate(config));
|
|
6762
6878
|
if (servesStaticIndex(config.search.provider)) {
|
|
6763
6879
|
const documents = await buildSearchDocuments(project);
|
|
6764
|
-
await write(
|
|
6880
|
+
await write(join13(srcDir, "generated", "search.json"), `${JSON.stringify(documents)}
|
|
6765
6881
|
`);
|
|
6766
|
-
await write(
|
|
6882
|
+
await write(join13(srcDir, "pages", "blume-search.json.ts"), searchEndpointTemplate());
|
|
6767
6883
|
}
|
|
6768
6884
|
if (config.search.provider === "mixedbread") {
|
|
6769
|
-
await write(
|
|
6885
|
+
await write(join13(srcDir, "pages", "api", "search.ts"), mixedbreadSearchEndpointTemplate(config.search.mixedbread?.storeId ?? ""));
|
|
6770
6886
|
}
|
|
6771
6887
|
const rawMarkdown = await buildRawMarkdown(project);
|
|
6772
6888
|
await Promise.all([
|
|
6773
|
-
write(
|
|
6889
|
+
write(join13(srcDir, "generated", "raw-markdown.json"), `${JSON.stringify(rawMarkdown)}
|
|
6774
6890
|
`),
|
|
6775
|
-
write(
|
|
6776
|
-
write(
|
|
6891
|
+
write(join13(srcDir, "pages", "[...slug].md.ts"), rawMarkdownEndpointTemplate()),
|
|
6892
|
+
write(join13(srcDir, "pages", "[...slug].mdx.ts"), rawMarkdownEndpointTemplate())
|
|
6777
6893
|
]);
|
|
6778
6894
|
const feeds = buildRssFeeds(project);
|
|
6779
6895
|
if (feeds.length > 0) {
|
|
6780
6896
|
const feedXml = Object.fromEntries(feeds.map((feed) => [feed.type, renderRssFeed(feed)]));
|
|
6781
6897
|
await Promise.all([
|
|
6782
|
-
write(
|
|
6898
|
+
write(join13(srcDir, "generated", "rss.json"), `${JSON.stringify(feedXml)}
|
|
6783
6899
|
`),
|
|
6784
|
-
write(
|
|
6900
|
+
write(join13(srcDir, "pages", "[section]", "rss.xml.ts"), rssEndpointTemplate())
|
|
6785
6901
|
]);
|
|
6786
6902
|
}
|
|
6787
6903
|
const warnings = [
|
|
@@ -6818,10 +6934,10 @@ var generateRuntime = async (project) => {
|
|
|
6818
6934
|
root: context.root
|
|
6819
6935
|
});
|
|
6820
6936
|
warnings.push(...references.warnings);
|
|
6821
|
-
await Promise.all(references.files.map((file) => write(
|
|
6937
|
+
await Promise.all(references.files.map((file) => write(join13(srcDir, "pages", file.pagePath), file.content)));
|
|
6822
6938
|
}
|
|
6823
|
-
await write(
|
|
6824
|
-
await write(
|
|
6939
|
+
await write(join13(srcDir, "generated", "data.json"), buildRuntimeData(project));
|
|
6940
|
+
await write(join13(out, "blume.manifest.json"), `${JSON.stringify(project.manifest, null, 2)}
|
|
6825
6941
|
`);
|
|
6826
6942
|
await writeStagedContent(out, staged);
|
|
6827
6943
|
await pruneOrphans(srcDir, written);
|
|
@@ -6829,12 +6945,44 @@ var generateRuntime = async (project) => {
|
|
|
6829
6945
|
};
|
|
6830
6946
|
|
|
6831
6947
|
// src/core/config.ts
|
|
6832
|
-
import { existsSync as
|
|
6948
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7 } from "node:fs";
|
|
6833
6949
|
|
|
6834
6950
|
// src/core/bridge.ts
|
|
6835
|
-
import { existsSync as
|
|
6951
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
6836
6952
|
import { readFile as readFile9 } from "node:fs/promises";
|
|
6837
|
-
import { join as
|
|
6953
|
+
import { join as join14 } from "pathe";
|
|
6954
|
+
|
|
6955
|
+
// src/migrate/mintlify/assets.ts
|
|
6956
|
+
var assetRefs = (config) => {
|
|
6957
|
+
const refs = ["/images"];
|
|
6958
|
+
const logo = config.logo;
|
|
6959
|
+
if (typeof logo === "string") {
|
|
6960
|
+
refs.push(logo);
|
|
6961
|
+
} else if (logo) {
|
|
6962
|
+
refs.push(logo.light, logo.dark);
|
|
6963
|
+
}
|
|
6964
|
+
const favicon = config.favicon;
|
|
6965
|
+
if (typeof favicon === "string") {
|
|
6966
|
+
refs.push(favicon);
|
|
6967
|
+
} else if (favicon) {
|
|
6968
|
+
refs.push(favicon.light, favicon.dark);
|
|
6969
|
+
}
|
|
6970
|
+
refs.push(config.theme?.backgroundImage, config.theme?.backgroundImageDark);
|
|
6971
|
+
return refs;
|
|
6972
|
+
};
|
|
6973
|
+
var assetSegments = (config) => {
|
|
6974
|
+
const segments = new Set;
|
|
6975
|
+
for (const ref of assetRefs(config)) {
|
|
6976
|
+
if (typeof ref !== "string" || !ref.startsWith("/")) {
|
|
6977
|
+
continue;
|
|
6978
|
+
}
|
|
6979
|
+
const [segment] = ref.replace(/^\/+/u, "").split("/");
|
|
6980
|
+
if (segment) {
|
|
6981
|
+
segments.add(segment);
|
|
6982
|
+
}
|
|
6983
|
+
}
|
|
6984
|
+
return [...segments];
|
|
6985
|
+
};
|
|
6838
6986
|
|
|
6839
6987
|
// src/migrate/mintlify/config.ts
|
|
6840
6988
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
@@ -7503,7 +7651,7 @@ var mintlifyI18n = (spec) => {
|
|
|
7503
7651
|
// src/core/bridge.ts
|
|
7504
7652
|
var MINTLIFY_CONFIG_FILES = ["docs.json", "mint.json"];
|
|
7505
7653
|
var detectMintlifyBridge = async (root) => {
|
|
7506
|
-
const configFile = MINTLIFY_CONFIG_FILES.map((name) =>
|
|
7654
|
+
const configFile = MINTLIFY_CONFIG_FILES.map((name) => join14(root, name)).find((candidate) => existsSync8(candidate));
|
|
7507
7655
|
if (!configFile) {
|
|
7508
7656
|
return null;
|
|
7509
7657
|
}
|
|
@@ -7519,11 +7667,13 @@ var detectMintlifyBridge = async (root) => {
|
|
|
7519
7667
|
const variables = config.variables ?? {};
|
|
7520
7668
|
const root_ = config.content?.root ?? ".";
|
|
7521
7669
|
const exclude = config.content?.exclude ?? [];
|
|
7670
|
+
const assets = assetSegments(config).filter((segment) => segment !== "public" && existsSync8(join14(root, segment)));
|
|
7522
7671
|
return {
|
|
7523
7672
|
configFile,
|
|
7524
7673
|
raw: {
|
|
7525
7674
|
...config,
|
|
7526
7675
|
content: {
|
|
7676
|
+
assets,
|
|
7527
7677
|
exclude,
|
|
7528
7678
|
root: root_,
|
|
7529
7679
|
sources: [
|
|
@@ -7592,8 +7742,8 @@ var createModuleLoader = () => {
|
|
|
7592
7742
|
};
|
|
7593
7743
|
|
|
7594
7744
|
// src/core/project.ts
|
|
7595
|
-
import { existsSync as
|
|
7596
|
-
import { isAbsolute as isAbsolute4, join as
|
|
7745
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
7746
|
+
import { isAbsolute as isAbsolute4, join as join15, resolve as resolve5 } from "pathe";
|
|
7597
7747
|
var CONFIG_FILENAMES = [
|
|
7598
7748
|
"blume.config.ts",
|
|
7599
7749
|
"blume.config.mjs",
|
|
@@ -7603,8 +7753,8 @@ var THEME_FILENAMES = ["theme.css"];
|
|
|
7603
7753
|
var COMPONENTS_FILENAMES = ["components.tsx", "components.ts"];
|
|
7604
7754
|
var firstExisting = (root, names) => {
|
|
7605
7755
|
for (const name of names) {
|
|
7606
|
-
const candidate =
|
|
7607
|
-
if (
|
|
7756
|
+
const candidate = join15(root, name);
|
|
7757
|
+
if (existsSync9(candidate)) {
|
|
7608
7758
|
return candidate;
|
|
7609
7759
|
}
|
|
7610
7760
|
}
|
|
@@ -7613,14 +7763,14 @@ var firstExisting = (root, names) => {
|
|
|
7613
7763
|
var findConfigFile = (root) => firstExisting(root, CONFIG_FILENAMES);
|
|
7614
7764
|
var resolveProjectContext = (root, config) => {
|
|
7615
7765
|
const absoluteRoot = resolve5(root);
|
|
7616
|
-
const contentRoot = isAbsolute4(config.content.root) ? config.content.root :
|
|
7617
|
-
const pagesPath =
|
|
7618
|
-
const pagesRoot =
|
|
7766
|
+
const contentRoot = isAbsolute4(config.content.root) ? config.content.root : join15(absoluteRoot, config.content.root);
|
|
7767
|
+
const pagesPath = join15(absoluteRoot, config.content.pages);
|
|
7768
|
+
const pagesRoot = existsSync9(pagesPath) ? pagesPath : null;
|
|
7619
7769
|
return {
|
|
7620
7770
|
componentsFile: firstExisting(absoluteRoot, COMPONENTS_FILENAMES),
|
|
7621
7771
|
configFile: findConfigFile(absoluteRoot),
|
|
7622
7772
|
contentRoot,
|
|
7623
|
-
outDir:
|
|
7773
|
+
outDir: join15(absoluteRoot, ".blume"),
|
|
7624
7774
|
pagesRoot,
|
|
7625
7775
|
root: absoluteRoot,
|
|
7626
7776
|
themeFile: firstExisting(absoluteRoot, THEME_FILENAMES)
|
|
@@ -7810,6 +7960,7 @@ var contentSourceSchema = z2.discriminatedUnion("type", [
|
|
|
7810
7960
|
customSourceSchema
|
|
7811
7961
|
]);
|
|
7812
7962
|
var contentConfigSchema = z2.object({
|
|
7963
|
+
assets: z2.array(z2.string()).default([]),
|
|
7813
7964
|
defaultType: z2.string().default("doc"),
|
|
7814
7965
|
exclude: z2.array(z2.string()).default(["**/_*", "**/.*"]),
|
|
7815
7966
|
include: z2.array(z2.string()).default(["**/*.{md,mdx}"]),
|
|
@@ -8180,7 +8331,7 @@ var loadConfig = async (root, options = {}) => {
|
|
|
8180
8331
|
const sourceFile = bridge?.configFile ?? configFile;
|
|
8181
8332
|
const parsed = blumeConfigSchema.safeParse(raw ?? {});
|
|
8182
8333
|
if (!parsed.success) {
|
|
8183
|
-
const source = sourceFile &&
|
|
8334
|
+
const source = sourceFile && existsSync10(sourceFile) ? readFileSync7(sourceFile, "utf-8") : undefined;
|
|
8184
8335
|
const diagnostics = diagnosticsFromZod(parsed.error, {
|
|
8185
8336
|
code: "BLUME_CONFIG_INVALID",
|
|
8186
8337
|
file: sourceFile ?? undefined,
|
|
@@ -8657,7 +8808,7 @@ var discoverFolderMeta = async (contentRoot) => {
|
|
|
8657
8808
|
};
|
|
8658
8809
|
|
|
8659
8810
|
// src/core/sources/normalize.ts
|
|
8660
|
-
import { existsSync as
|
|
8811
|
+
import { existsSync as existsSync11, readFileSync as readFileSync8 } from "node:fs";
|
|
8661
8812
|
import GithubSlugger from "github-slugger";
|
|
8662
8813
|
import { extname as extname4 } from "pathe";
|
|
8663
8814
|
var NUMERIC_PREFIX2 = /^\d+[-_.]/u;
|
|
@@ -8731,8 +8882,9 @@ var extractLinks = (body) => {
|
|
|
8731
8882
|
if (target === undefined || match.index === undefined) {
|
|
8732
8883
|
continue;
|
|
8733
8884
|
}
|
|
8885
|
+
const targetOffset = match.index + match[0].indexOf("](") + "](".length;
|
|
8734
8886
|
links.push({
|
|
8735
|
-
column:
|
|
8887
|
+
column: targetOffset + 1,
|
|
8736
8888
|
line: lineNumber,
|
|
8737
8889
|
target
|
|
8738
8890
|
});
|
|
@@ -8782,7 +8934,7 @@ var normalizeEntry2 = (entry, ctx) => {
|
|
|
8782
8934
|
const ext = format === "mdx" ? ".mdx" : ".md";
|
|
8783
8935
|
const result = pageMetaSchema.safeParse(entry.data);
|
|
8784
8936
|
if (!result.success) {
|
|
8785
|
-
const source = entry.raw ?? (entry.sourcePath &&
|
|
8937
|
+
const source = entry.raw ?? (entry.sourcePath && existsSync11(entry.sourcePath) ? readFileSync8(entry.sourcePath, "utf-8") : undefined);
|
|
8786
8938
|
return {
|
|
8787
8939
|
diagnostics: diagnosticsFromZod(result.error, {
|
|
8788
8940
|
code: "BLUME_FRONTMATTER_INVALID",
|
|
@@ -8831,15 +8983,15 @@ var normalizeEntry2 = (entry, ctx) => {
|
|
|
8831
8983
|
};
|
|
8832
8984
|
|
|
8833
8985
|
// src/core/sources/resolve.ts
|
|
8834
|
-
import { join as
|
|
8986
|
+
import { join as join24 } from "pathe";
|
|
8835
8987
|
|
|
8836
8988
|
// src/core/sources/filesystem.ts
|
|
8837
|
-
import { existsSync as
|
|
8989
|
+
import { existsSync as existsSync12, watch as fsWatch } from "node:fs";
|
|
8838
8990
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
8839
|
-
import { extname as extname5, isAbsolute as isAbsolute5, join as
|
|
8991
|
+
import { extname as extname5, isAbsolute as isAbsolute5, join as join16, relative as relative10, resolve as resolve6 } from "pathe";
|
|
8840
8992
|
import { glob as glob6 } from "tinyglobby";
|
|
8841
8993
|
var filesystemSource = (options) => {
|
|
8842
|
-
const contentRoot = isAbsolute5(options.root) ? options.root :
|
|
8994
|
+
const contentRoot = isAbsolute5(options.root) ? options.root : join16(resolve6(options.projectRoot), options.root);
|
|
8843
8995
|
const load2 = async () => {
|
|
8844
8996
|
const files = await glob6(options.include, {
|
|
8845
8997
|
absolute: true,
|
|
@@ -8863,7 +9015,7 @@ var filesystemSource = (options) => {
|
|
|
8863
9015
|
return { diagnostics: [], entries };
|
|
8864
9016
|
};
|
|
8865
9017
|
const validate = () => {
|
|
8866
|
-
if (!
|
|
9018
|
+
if (!existsSync12(contentRoot)) {
|
|
8867
9019
|
throw new BlumeError({
|
|
8868
9020
|
code: options.missingCode ?? "BLUME_CONTENT_ROOT_MISSING",
|
|
8869
9021
|
file: contentRoot,
|
|
@@ -8874,7 +9026,7 @@ var filesystemSource = (options) => {
|
|
|
8874
9026
|
}
|
|
8875
9027
|
};
|
|
8876
9028
|
const watch = (onChange) => {
|
|
8877
|
-
if (!
|
|
9029
|
+
if (!existsSync12(contentRoot)) {
|
|
8878
9030
|
return () => {};
|
|
8879
9031
|
}
|
|
8880
9032
|
const watcher = fsWatch(contentRoot, { recursive: true }, onChange);
|
|
@@ -8885,7 +9037,7 @@ var filesystemSource = (options) => {
|
|
|
8885
9037
|
load: load2,
|
|
8886
9038
|
name: options.name,
|
|
8887
9039
|
prefix: options.prefix,
|
|
8888
|
-
read: (ref) => readFile10(
|
|
9040
|
+
read: (ref) => readFile10(join16(contentRoot, ref), "utf-8"),
|
|
8889
9041
|
staged: false,
|
|
8890
9042
|
validate,
|
|
8891
9043
|
watch
|
|
@@ -8894,7 +9046,7 @@ var filesystemSource = (options) => {
|
|
|
8894
9046
|
|
|
8895
9047
|
// src/core/sources/cache.ts
|
|
8896
9048
|
import { mkdir as mkdir3, readFile as readFile11, writeFile as writeFile3 } from "node:fs/promises";
|
|
8897
|
-
import { join as
|
|
9049
|
+
import { join as join17 } from "pathe";
|
|
8898
9050
|
var hashText = (text) => {
|
|
8899
9051
|
let hash = 5381;
|
|
8900
9052
|
for (let i = 0;i < text.length; i += 1) {
|
|
@@ -8921,7 +9073,7 @@ var pollingWatch = (load2, intervalSeconds) => (onChange) => {
|
|
|
8921
9073
|
return () => clearInterval(timer);
|
|
8922
9074
|
};
|
|
8923
9075
|
var snapshotCache = (cacheDir) => {
|
|
8924
|
-
const file =
|
|
9076
|
+
const file = join17(cacheDir, "entries.json");
|
|
8925
9077
|
return {
|
|
8926
9078
|
read: async () => {
|
|
8927
9079
|
try {
|
|
@@ -9135,11 +9287,12 @@ var enumerateGithub = async (github, include, doFetch) => {
|
|
|
9135
9287
|
}
|
|
9136
9288
|
const body = await res.json();
|
|
9137
9289
|
const prefix = base ? `${base}/` : "";
|
|
9138
|
-
|
|
9290
|
+
const refs = (body.tree ?? []).filter((node) => node.type === "blob" && node.path.startsWith(prefix)).map((node) => node.path.slice(prefix.length)).filter((rel) => matchesInclude(rel, include)).map((rel) => ({
|
|
9139
9291
|
editUrl: `https://github.com/${owner}/${repo}/edit/${ref}/${prefix}${rel}`,
|
|
9140
9292
|
fetchUrl: `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${prefix}${rel}`,
|
|
9141
9293
|
ref: rel
|
|
9142
9294
|
}));
|
|
9295
|
+
return { refs, truncated: body.truncated === true };
|
|
9143
9296
|
};
|
|
9144
9297
|
var mdxRemoteSource = (options, ctx) => {
|
|
9145
9298
|
const doFetch = options.fetchImpl ?? globalThis.fetch;
|
|
@@ -9151,11 +9304,12 @@ var mdxRemoteSource = (options, ctx) => {
|
|
|
9151
9304
|
}
|
|
9152
9305
|
if (options.files && options.url) {
|
|
9153
9306
|
const base = options.url.replace(/\/$/u, "");
|
|
9154
|
-
|
|
9307
|
+
const refs = options.files.filter((ref) => matchesInclude(ref, options.include)).map((ref) => ({
|
|
9155
9308
|
editUrl: `${base}/${ref}`,
|
|
9156
9309
|
fetchUrl: `${base}/${ref}`,
|
|
9157
9310
|
ref
|
|
9158
9311
|
}));
|
|
9312
|
+
return { refs, truncated: false };
|
|
9159
9313
|
}
|
|
9160
9314
|
throw new BlumeError({
|
|
9161
9315
|
code: "BLUME_SOURCE_MISCONFIGURED",
|
|
@@ -9181,12 +9335,40 @@ var mdxRemoteSource = (options, ctx) => {
|
|
|
9181
9335
|
};
|
|
9182
9336
|
};
|
|
9183
9337
|
const load2 = async () => {
|
|
9338
|
+
const skipped = [];
|
|
9184
9339
|
const result = await loadWithCache(options.name, cache, async () => {
|
|
9185
|
-
const refs = await enumerate();
|
|
9186
|
-
|
|
9340
|
+
const { refs, truncated } = await enumerate();
|
|
9341
|
+
if (truncated) {
|
|
9342
|
+
skipped.push({
|
|
9343
|
+
code: "BLUME_SOURCE_TRUNCATED",
|
|
9344
|
+
message: `Source "${options.name}" hit GitHub's tree listing limit; some files were not enumerated. Narrow the source path or split the repo.`,
|
|
9345
|
+
severity: "warning"
|
|
9346
|
+
});
|
|
9347
|
+
}
|
|
9348
|
+
const settled = await Promise.all(refs.map(async (ref) => {
|
|
9349
|
+
try {
|
|
9350
|
+
return await fetchEntry(ref);
|
|
9351
|
+
} catch (error) {
|
|
9352
|
+
skipped.push({
|
|
9353
|
+
code: "BLUME_SOURCE_FETCH_FAILED",
|
|
9354
|
+
message: `Source "${options.name}" skipped "${ref.ref}" (${error.message}); the rest were imported.`,
|
|
9355
|
+
severity: "warning"
|
|
9356
|
+
});
|
|
9357
|
+
return null;
|
|
9358
|
+
}
|
|
9359
|
+
}));
|
|
9360
|
+
const entries = settled.filter((entry) => entry !== null);
|
|
9361
|
+
if (refs.length > 0 && entries.length === 0) {
|
|
9362
|
+
skipped.length = 0;
|
|
9363
|
+
throw new Error(`all ${refs.length} remote file(s) failed to fetch`);
|
|
9364
|
+
}
|
|
9365
|
+
return entries;
|
|
9187
9366
|
}, ctx.refresh ?? true);
|
|
9188
9367
|
snapshot = new Map(result.entries.map((entry) => [entry.ref, entry]));
|
|
9189
|
-
return
|
|
9368
|
+
return {
|
|
9369
|
+
...result,
|
|
9370
|
+
diagnostics: [...result.diagnostics, ...skipped]
|
|
9371
|
+
};
|
|
9190
9372
|
};
|
|
9191
9373
|
const read = async (ref) => {
|
|
9192
9374
|
const cached3 = snapshot.get(ref);
|
|
@@ -9208,21 +9390,25 @@ var mdxRemoteSource = (options, ctx) => {
|
|
|
9208
9390
|
};
|
|
9209
9391
|
|
|
9210
9392
|
// src/core/sources/mintlify.ts
|
|
9211
|
-
import { existsSync as
|
|
9393
|
+
import { existsSync as existsSync14, watch as fsWatch2 } from "node:fs";
|
|
9212
9394
|
import { readFile as readFile13 } from "node:fs/promises";
|
|
9213
|
-
import { isAbsolute as
|
|
9395
|
+
import { isAbsolute as isAbsolute7, join as join20, relative as relative14, resolve as resolve8 } from "pathe";
|
|
9214
9396
|
import { glob as glob7 } from "tinyglobby";
|
|
9215
9397
|
|
|
9216
9398
|
// src/migrate/shared.ts
|
|
9217
|
-
import { existsSync as
|
|
9399
|
+
import { existsSync as existsSync13 } from "node:fs";
|
|
9218
9400
|
import { readFile as readFile12, writeFile as writeFile4 } from "node:fs/promises";
|
|
9219
|
-
import { join as
|
|
9401
|
+
import { isAbsolute as isAbsolute6, join as join18, relative as relative11 } from "pathe";
|
|
9402
|
+
var isInsideRoot2 = (root, candidate) => {
|
|
9403
|
+
const rel = relative11(root, candidate);
|
|
9404
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute6(rel);
|
|
9405
|
+
};
|
|
9220
9406
|
var writeBlumeConfig = async (root, config) => {
|
|
9221
9407
|
const body = `import { defineConfig } from "blume";
|
|
9222
9408
|
|
|
9223
9409
|
export default defineConfig(${JSON.stringify(config, null, 2)});
|
|
9224
9410
|
`;
|
|
9225
|
-
await writeFile4(
|
|
9411
|
+
await writeFile4(join18(root, "blume.config.ts"), body, "utf-8");
|
|
9226
9412
|
};
|
|
9227
9413
|
var BLUME_SCRIPTS = {
|
|
9228
9414
|
build: "blume build",
|
|
@@ -9230,8 +9416,8 @@ var BLUME_SCRIPTS = {
|
|
|
9230
9416
|
start: "blume preview"
|
|
9231
9417
|
};
|
|
9232
9418
|
var rewriteFrameworkScripts = async (root, cli, remove) => {
|
|
9233
|
-
const pkgPath =
|
|
9234
|
-
if (!
|
|
9419
|
+
const pkgPath = join18(root, "package.json");
|
|
9420
|
+
if (!existsSync13(pkgPath)) {
|
|
9235
9421
|
return false;
|
|
9236
9422
|
}
|
|
9237
9423
|
let pkg;
|
|
@@ -9264,25 +9450,7 @@ var rewriteFrameworkScripts = async (root, cli, remove) => {
|
|
|
9264
9450
|
}
|
|
9265
9451
|
return changed;
|
|
9266
9452
|
};
|
|
9267
|
-
var
|
|
9268
|
-
var ensureGitignore = async (root, entries) => {
|
|
9269
|
-
const path = join16(root, ".gitignore");
|
|
9270
|
-
const existing = existsSync12(path) ? await readFile12(path, "utf-8") : "";
|
|
9271
|
-
const present = new Set(existing.split(`
|
|
9272
|
-
`).map(gitignoreKey).filter(Boolean));
|
|
9273
|
-
const added = entries.filter((entry) => !present.has(gitignoreKey(entry)));
|
|
9274
|
-
if (added.length === 0) {
|
|
9275
|
-
return [];
|
|
9276
|
-
}
|
|
9277
|
-
const gap = existing.length > 0 && !existing.endsWith(`
|
|
9278
|
-
`) ? `
|
|
9279
|
-
` : "";
|
|
9280
|
-
await writeFile4(path, `${existing}${gap}${added.join(`
|
|
9281
|
-
`)}
|
|
9282
|
-
`, "utf-8");
|
|
9283
|
-
return added;
|
|
9284
|
-
};
|
|
9285
|
-
var leftoverFiles = (root, candidates) => candidates.filter((candidate) => existsSync12(join16(root, candidate)));
|
|
9453
|
+
var leftoverFiles = (root, candidates) => candidates.filter((candidate) => existsSync13(join18(root, candidate)));
|
|
9286
9454
|
var attribute = (attrs, name) => {
|
|
9287
9455
|
const match = attrs.match(new RegExp(`\\b${name}=(?:"(?<dq>[^"]*)"|'(?<sq>[^']*)')`, "u"));
|
|
9288
9456
|
return match?.groups?.dq ?? match?.groups?.sq;
|
|
@@ -9679,7 +9847,7 @@ var isLiteralObject = (value) => typeof value === "object" && value !== null &&
|
|
|
9679
9847
|
var asLiteralArray = (value) => Array.isArray(value) ? value : undefined;
|
|
9680
9848
|
|
|
9681
9849
|
// src/migrate/mintlify/content.ts
|
|
9682
|
-
import { dirname as dirname10, join as
|
|
9850
|
+
import { dirname as dirname10, join as join19, relative as relative12 } from "pathe";
|
|
9683
9851
|
var CALLOUT_DIRECTIVES = {
|
|
9684
9852
|
Check: "success",
|
|
9685
9853
|
Danger: "danger",
|
|
@@ -9715,9 +9883,9 @@ var rewriteSnippetImports = (source, options) => {
|
|
|
9715
9883
|
if (/\.mdx?$/u.test(importSource)) {
|
|
9716
9884
|
return "";
|
|
9717
9885
|
}
|
|
9718
|
-
const target =
|
|
9886
|
+
const target = join19(options.root, importSource.replace(/^\/+/u, ""));
|
|
9719
9887
|
components.push(importSource.replace(/^\/+/u, ""));
|
|
9720
|
-
let rel =
|
|
9888
|
+
let rel = relative12(dirname10(options.filePath), target);
|
|
9721
9889
|
if (!rel.startsWith(".")) {
|
|
9722
9890
|
rel = `./${rel}`;
|
|
9723
9891
|
}
|
|
@@ -9907,7 +10075,7 @@ var rewriteMintlifySvgIconProps = (source) => {
|
|
|
9907
10075
|
|
|
9908
10076
|
// src/migrate/mintlify/snippets.ts
|
|
9909
10077
|
import { readFile as readFileFromDisk } from "node:fs/promises";
|
|
9910
|
-
import { dirname as dirname11, relative as
|
|
10078
|
+
import { dirname as dirname11, relative as relative13, resolve as resolve7 } from "pathe";
|
|
9911
10079
|
var MARKDOWN_SNIPPET_IMPORT = /^import\s+(?<name>[$A-Z_a-z][$\w]*)\s+from\s+["'](?<source>[^"']+\.mdx?)["'];?\s*$/gmu;
|
|
9912
10080
|
var NAMED_SNIPPET_IMPORT = /^import\s+\{(?<names>[^}]+)\}\s+from\s+["'](?<source>[^"']+\.mdx?)["'];?\s*$/gmu;
|
|
9913
10081
|
var EXPORTED_STRING_CONST = /^export\s+const\s+(?<name>[$A-Z_a-z][$\w]*)\s*=\s*(?:"(?<double>(?:\\.|[^"\\])*)"|'(?<single>(?:\\.|[^'\\])*)'|`(?<template>(?:\\.|[^`\\])*)`)\s*;?\s*$/gmu;
|
|
@@ -9916,15 +10084,15 @@ var PLACEHOLDER = /\{(?<name>[$A-Z_a-z][$\w]*)\}/gu;
|
|
|
9916
10084
|
var GLOBAL_VARIABLE = /\{\{\s*(?<name>[A-Za-z0-9-]+)\s*\}\}/gu;
|
|
9917
10085
|
var FRONTMATTER_BLOCK = /^---\r?\n[\s\S]*?\r?\n---\r?\n?/u;
|
|
9918
10086
|
var USER_EXPORT = /^(?:export\s+)?(?:const|let|var)\s+user\s*=|^import\s+\{\s*user\s*\}/mu;
|
|
9919
|
-
var
|
|
9920
|
-
const rel =
|
|
10087
|
+
var isInsideRoot3 = (root, candidate) => {
|
|
10088
|
+
const rel = relative13(root, candidate);
|
|
9921
10089
|
return rel === "" || !rel.startsWith("..") && !rel.startsWith("/");
|
|
9922
10090
|
};
|
|
9923
10091
|
var escapeRegExp2 = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
9924
10092
|
var snippetSelfClosingTagPattern = (name) => new RegExp(`<${escapeRegExp2(name)}(?<attrs>[^>]*?)\\s*/>`, "gu");
|
|
9925
10093
|
var snippetPairedTagPattern = (name) => new RegExp(`<${escapeRegExp2(name)}(?<attrs>[^>]*?)>[\\s\\S]*?</${escapeRegExp2(name)}>`, "gu");
|
|
9926
10094
|
var rootRelativePath = (root, file) => {
|
|
9927
|
-
const rel =
|
|
10095
|
+
const rel = relative13(root, file);
|
|
9928
10096
|
return rel ? `/${rel}` : "/";
|
|
9929
10097
|
};
|
|
9930
10098
|
var snippetCycleMessage = (root, file, trail) => {
|
|
@@ -9934,7 +10102,7 @@ var snippetCycleMessage = (root, file, trail) => {
|
|
|
9934
10102
|
};
|
|
9935
10103
|
var resolveSnippetPath = (options) => {
|
|
9936
10104
|
const target = options.source.startsWith("/") ? resolve7(options.root, options.source.slice(1)) : resolve7(dirname11(options.filePath), options.source);
|
|
9937
|
-
return
|
|
10105
|
+
return isInsideRoot3(options.root, target) ? target : null;
|
|
9938
10106
|
};
|
|
9939
10107
|
var collectImports2 = (source) => [...source.matchAll(MARKDOWN_SNIPPET_IMPORT)].flatMap((match) => {
|
|
9940
10108
|
const name = match.groups?.name;
|
|
@@ -10127,7 +10295,7 @@ var MINTLIFY_SOURCE_IGNORES = [
|
|
|
10127
10295
|
"snippets/**"
|
|
10128
10296
|
];
|
|
10129
10297
|
var mintlifySource = (options) => {
|
|
10130
|
-
const contentRoot =
|
|
10298
|
+
const contentRoot = isAbsolute7(options.root) ? options.root : join20(resolve8(options.projectRoot), options.root);
|
|
10131
10299
|
const ignore = [...new Set([...options.exclude, ...MINTLIFY_SOURCE_IGNORES])];
|
|
10132
10300
|
const transform = (raw, file) => transformMintlifyContent(raw, {
|
|
10133
10301
|
filePath: file,
|
|
@@ -10153,7 +10321,7 @@ var mintlifySource = (options) => {
|
|
|
10153
10321
|
body: { format: "mdx", text: parsed.content },
|
|
10154
10322
|
data: parsed.data,
|
|
10155
10323
|
raw: result.content,
|
|
10156
|
-
ref:
|
|
10324
|
+
ref: relative14(contentRoot, file),
|
|
10157
10325
|
sourcePath: file
|
|
10158
10326
|
};
|
|
10159
10327
|
}));
|
|
@@ -10167,7 +10335,7 @@ var mintlifySource = (options) => {
|
|
|
10167
10335
|
return { diagnostics, entries };
|
|
10168
10336
|
};
|
|
10169
10337
|
const validate = () => {
|
|
10170
|
-
if (!
|
|
10338
|
+
if (!existsSync14(contentRoot)) {
|
|
10171
10339
|
throw new BlumeError({
|
|
10172
10340
|
code: "BLUME_CONTENT_ROOT_MISSING",
|
|
10173
10341
|
file: contentRoot,
|
|
@@ -10179,11 +10347,11 @@ var mintlifySource = (options) => {
|
|
|
10179
10347
|
};
|
|
10180
10348
|
const watch = (onChange) => {
|
|
10181
10349
|
const disposers = [];
|
|
10182
|
-
if (
|
|
10350
|
+
if (existsSync14(contentRoot)) {
|
|
10183
10351
|
const watcher = fsWatch2(contentRoot, { recursive: true }, onChange);
|
|
10184
10352
|
disposers.push(() => watcher.close());
|
|
10185
10353
|
}
|
|
10186
|
-
if (options.configFile &&
|
|
10354
|
+
if (options.configFile && existsSync14(options.configFile)) {
|
|
10187
10355
|
const watcher = fsWatch2(options.configFile, onChange);
|
|
10188
10356
|
disposers.push(() => watcher.close());
|
|
10189
10357
|
}
|
|
@@ -10194,7 +10362,7 @@ var mintlifySource = (options) => {
|
|
|
10194
10362
|
};
|
|
10195
10363
|
};
|
|
10196
10364
|
const read = async (ref) => {
|
|
10197
|
-
const file =
|
|
10365
|
+
const file = join20(contentRoot, ref);
|
|
10198
10366
|
const result = await transform(await readFile13(file, "utf-8"), file);
|
|
10199
10367
|
return result.content;
|
|
10200
10368
|
};
|
|
@@ -10211,11 +10379,12 @@ var mintlifySource = (options) => {
|
|
|
10211
10379
|
};
|
|
10212
10380
|
|
|
10213
10381
|
// src/core/sources/notion.ts
|
|
10214
|
-
import {
|
|
10382
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
10383
|
+
import { join as join22 } from "pathe";
|
|
10215
10384
|
|
|
10216
10385
|
// src/core/sources/assets.ts
|
|
10217
10386
|
import { mkdir as mkdir4, writeFile as writeFile5 } from "node:fs/promises";
|
|
10218
|
-
import { extname as extname6, join as
|
|
10387
|
+
import { extname as extname6, join as join21 } from "pathe";
|
|
10219
10388
|
var MD_IMAGE = /!\[(?<alt>[^\]]*)\]\((?<url>[^)\s]+)\)/gu;
|
|
10220
10389
|
var REMOTE = /^https?:\/\//u;
|
|
10221
10390
|
var SAFE_EXT = /^\.[a-z0-9]+$/iu;
|
|
@@ -10244,7 +10413,7 @@ var materializeAssets = async (markdown, ctx) => {
|
|
|
10244
10413
|
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
10245
10414
|
const file = `${hashText(url)}${extFor(url)}`;
|
|
10246
10415
|
await mkdir4(ctx.assetsDir, { recursive: true });
|
|
10247
|
-
await writeFile5(
|
|
10416
|
+
await writeFile5(join21(ctx.assetsDir, file), bytes);
|
|
10248
10417
|
rewrites.set(url, `${ctx.assetsBaseUrl}/${file}`);
|
|
10249
10418
|
} catch (error) {
|
|
10250
10419
|
diagnostics.push({
|
|
@@ -10279,6 +10448,28 @@ var richToMarkdown = (rich = []) => rich.map((node) => {
|
|
|
10279
10448
|
return node.href ? `[${text}](${node.href})` : text;
|
|
10280
10449
|
}).join("");
|
|
10281
10450
|
var blockField = (block) => block[block.type]?.rich_text ?? [];
|
|
10451
|
+
var RATE_LIMITED = 429;
|
|
10452
|
+
var MAX_RETRIES = 4;
|
|
10453
|
+
var BASE_DELAY_MS = 500;
|
|
10454
|
+
var SECOND_MS = 1000;
|
|
10455
|
+
var withNotionRetry = async (call) => {
|
|
10456
|
+
let lastError;
|
|
10457
|
+
for (let attempt = 0;attempt <= MAX_RETRIES; attempt += 1) {
|
|
10458
|
+
try {
|
|
10459
|
+
return await call();
|
|
10460
|
+
} catch (error) {
|
|
10461
|
+
lastError = error;
|
|
10462
|
+
const { status } = error;
|
|
10463
|
+
if (status !== RATE_LIMITED || attempt === MAX_RETRIES) {
|
|
10464
|
+
throw error;
|
|
10465
|
+
}
|
|
10466
|
+
const retryAfter = Number(error.headers?.["retry-after"]);
|
|
10467
|
+
const wait = retryAfter > 0 ? retryAfter * SECOND_MS : BASE_DELAY_MS * 2 ** attempt;
|
|
10468
|
+
await sleep(wait);
|
|
10469
|
+
}
|
|
10470
|
+
}
|
|
10471
|
+
throw lastError instanceof Error ? lastError : new Error("Notion request failed after retries.");
|
|
10472
|
+
};
|
|
10282
10473
|
var collectAll = async (page, cursor, acc = []) => {
|
|
10283
10474
|
const res = await page(cursor);
|
|
10284
10475
|
const all = [...acc, ...res.results];
|
|
@@ -10338,8 +10529,8 @@ ${text}
|
|
|
10338
10529
|
};
|
|
10339
10530
|
var notionSource = (options, ctx) => {
|
|
10340
10531
|
const props = options.properties ?? {};
|
|
10341
|
-
const cache = snapshotCache(ctx?.cacheDir ??
|
|
10342
|
-
const assetsDir = ctx?.assetsDir ??
|
|
10532
|
+
const cache = snapshotCache(ctx?.cacheDir ?? join22(".blume", "cache", options.name));
|
|
10533
|
+
const assetsDir = ctx?.assetsDir ?? join22(".blume", "public", "blume-assets", options.name);
|
|
10343
10534
|
const assetsBaseUrl = ctx?.assetsBaseUrl ?? `/blume-assets/${options.name}`;
|
|
10344
10535
|
let snapshot = new Map;
|
|
10345
10536
|
const resolveClient = async () => {
|
|
@@ -10358,7 +10549,7 @@ var notionSource = (options, ctx) => {
|
|
|
10358
10549
|
}
|
|
10359
10550
|
return new Client({ auth: options.token ?? process.env.NOTION_TOKEN });
|
|
10360
10551
|
};
|
|
10361
|
-
const childrenOf = (client, blockId) => collectAll((cursor) => client.blocks.children.list({ block_id: blockId, start_cursor: cursor }));
|
|
10552
|
+
const childrenOf = (client, blockId) => collectAll((cursor) => withNotionRetry(() => client.blocks.children.list({ block_id: blockId, start_cursor: cursor })));
|
|
10362
10553
|
const renderContainer = async (client, block, render) => {
|
|
10363
10554
|
const children = async (target) => {
|
|
10364
10555
|
if (!target.has_children) {
|
|
@@ -10472,10 +10663,10 @@ ${rendered.join(`
|
|
|
10472
10663
|
const assetDiagnostics = [];
|
|
10473
10664
|
const result = await loadWithCache(options.name, cache, async () => {
|
|
10474
10665
|
const client = await resolveClient();
|
|
10475
|
-
const pages = await collectAll((cursor) => client.databases.query({
|
|
10666
|
+
const pages = await collectAll((cursor) => withNotionRetry(() => client.databases.query({
|
|
10476
10667
|
database_id: options.database,
|
|
10477
10668
|
start_cursor: cursor
|
|
10478
|
-
}));
|
|
10669
|
+
})));
|
|
10479
10670
|
const built = await Promise.all(pages.map((page) => toEntry(client, page)));
|
|
10480
10671
|
for (const item of built) {
|
|
10481
10672
|
assetDiagnostics.push(...item.diagnostics);
|
|
@@ -10507,7 +10698,7 @@ ${rendered.join(`
|
|
|
10507
10698
|
};
|
|
10508
10699
|
|
|
10509
10700
|
// src/core/sources/sanity.ts
|
|
10510
|
-
import { join as
|
|
10701
|
+
import { join as join23 } from "pathe";
|
|
10511
10702
|
|
|
10512
10703
|
// src/core/sources/portable-text.ts
|
|
10513
10704
|
var HEADING_STYLES = {
|
|
@@ -10646,11 +10837,11 @@ var resolveClient = async (options, preview) => {
|
|
|
10646
10837
|
};
|
|
10647
10838
|
var sanitySource = (options, ctx) => {
|
|
10648
10839
|
const fields = options.fields ?? {};
|
|
10649
|
-
const cache = snapshotCache(ctx?.cacheDir ??
|
|
10840
|
+
const cache = snapshotCache(ctx?.cacheDir ?? join23(".blume", "cache", options.name));
|
|
10650
10841
|
let snapshot = new Map;
|
|
10651
10842
|
const toEntry = (doc) => {
|
|
10652
10843
|
const slugValue = asString2(getPath(doc, fields.slug ?? "slug.current")) ?? asString2(doc._id) ?? "untitled";
|
|
10653
|
-
const slug = slugify2(slugValue) || "untitled";
|
|
10844
|
+
const slug = slugify2(slugValue) || slugify2(asString2(doc._id) ?? "") || "untitled";
|
|
10654
10845
|
const data = {};
|
|
10655
10846
|
const title = asString2(getPath(doc, fields.title ?? "title"));
|
|
10656
10847
|
const description = asString2(getPath(doc, fields.description ?? "description"));
|
|
@@ -10721,8 +10912,8 @@ var uniqueNamer = () => {
|
|
|
10721
10912
|
};
|
|
10722
10913
|
var sourceContext = (context, name, runtime) => ({
|
|
10723
10914
|
assetsBaseUrl: `/blume-assets/${name}`,
|
|
10724
|
-
assetsDir:
|
|
10725
|
-
cacheDir:
|
|
10915
|
+
assetsDir: join24(context.outDir, "public", "blume-assets", name),
|
|
10916
|
+
cacheDir: join24(context.outDir, "cache", name),
|
|
10726
10917
|
mode: runtime.mode,
|
|
10727
10918
|
preview: runtime.preview,
|
|
10728
10919
|
projectRoot: context.root,
|
|
@@ -10916,8 +11107,8 @@ var scanProject = async (root, options = {}) => {
|
|
|
10916
11107
|
};
|
|
10917
11108
|
|
|
10918
11109
|
// src/cli/env.ts
|
|
10919
|
-
import { existsSync as
|
|
10920
|
-
import { dirname as dirname12, join as
|
|
11110
|
+
import { existsSync as existsSync15, readFileSync as readFileSync9 } from "node:fs";
|
|
11111
|
+
import { dirname as dirname12, join as join25, resolve as resolve9 } from "pathe";
|
|
10921
11112
|
var ENV_LINE = /^\s*(?:export\s+)?(?<key>[A-Za-z_][A-Za-z0-9_]*)\s*=\s*(?<value>.*?)\s*$/u;
|
|
10922
11113
|
var DOUBLE_QUOTED2 = /^"(?<body>[\s\S]*)"$/u;
|
|
10923
11114
|
var SINGLE_QUOTED = /^'(?<body>[\s\S]*)'$/u;
|
|
@@ -10955,8 +11146,8 @@ var applyEnv = (parsed) => {
|
|
|
10955
11146
|
};
|
|
10956
11147
|
var loadFile = (path) => {
|
|
10957
11148
|
try {
|
|
10958
|
-
if (
|
|
10959
|
-
applyEnv(parseEnv(
|
|
11149
|
+
if (existsSync15(path)) {
|
|
11150
|
+
applyEnv(parseEnv(readFileSync9(path, "utf-8")));
|
|
10960
11151
|
}
|
|
10961
11152
|
} catch {}
|
|
10962
11153
|
};
|
|
@@ -10964,10 +11155,10 @@ var loadEnvFiles = (startDir) => {
|
|
|
10964
11155
|
let dir = resolve9(startDir);
|
|
10965
11156
|
let done = false;
|
|
10966
11157
|
while (!done) {
|
|
10967
|
-
loadFile(
|
|
10968
|
-
loadFile(
|
|
11158
|
+
loadFile(join25(dir, ".env.local"));
|
|
11159
|
+
loadFile(join25(dir, ".env"));
|
|
10969
11160
|
const parent = dirname12(dir);
|
|
10970
|
-
done =
|
|
11161
|
+
done = existsSync15(join25(dir, ".git")) || parent === dir;
|
|
10971
11162
|
dir = parent;
|
|
10972
11163
|
}
|
|
10973
11164
|
};
|
|
@@ -11082,29 +11273,38 @@ var prepareProject = async (options) => {
|
|
|
11082
11273
|
|
|
11083
11274
|
// src/cli/commands/build.ts
|
|
11084
11275
|
var ADAPTERS = ["vercel", "node", "netlify", "cloudflare"];
|
|
11276
|
+
var validateBudgetFlags = (args) => {
|
|
11277
|
+
for (const flag of ["budget-js", "budget-css"]) {
|
|
11278
|
+
const value = args[flag];
|
|
11279
|
+
if (value !== undefined && !(Number(value) > 0)) {
|
|
11280
|
+
logger.error(`Invalid --${flag} "${value}" (expected a positive number of kB).`);
|
|
11281
|
+
process.exit(1);
|
|
11282
|
+
}
|
|
11283
|
+
}
|
|
11284
|
+
};
|
|
11085
11285
|
var emitRedirectFiles = async (config, distDir) => {
|
|
11086
11286
|
const { redirects } = config;
|
|
11087
11287
|
if (redirects.length === 0 || config.deployment.output !== "static") {
|
|
11088
11288
|
return;
|
|
11089
11289
|
}
|
|
11090
|
-
await writeFile6(
|
|
11290
|
+
await writeFile6(join26(distDir, "blume-redirects.json"), buildRedirectManifest(redirects), "utf-8");
|
|
11091
11291
|
const platformFiles = [
|
|
11092
11292
|
{ content: buildNetlifyRedirects(redirects), name: "_redirects" },
|
|
11093
11293
|
{ content: buildVercelConfig(redirects), name: "vercel.json" }
|
|
11094
11294
|
];
|
|
11095
|
-
await Promise.all(platformFiles.map((file) =>
|
|
11295
|
+
await Promise.all(platformFiles.map((file) => existsSync16(join26(distDir, file.name)) ? Promise.resolve() : writeFile6(join26(distDir, file.name), file.content, "utf-8")));
|
|
11096
11296
|
logger.success(`Emitted redirect files for ${redirects.length} redirect(s)`);
|
|
11097
11297
|
};
|
|
11098
11298
|
var formatBytes = (bytes) => bytes < 1024 ? `${bytes} B` : `${(bytes / 1024).toFixed(bytes < 1024 * 100 ? 1 : 0)} kB`;
|
|
11099
11299
|
var astroAssets = async (distDir, ext) => {
|
|
11100
|
-
const astroDir =
|
|
11101
|
-
if (!
|
|
11300
|
+
const astroDir = join26(distDir, "_astro");
|
|
11301
|
+
if (!existsSync16(astroDir)) {
|
|
11102
11302
|
return [];
|
|
11103
11303
|
}
|
|
11104
11304
|
const entries = await readdir(astroDir);
|
|
11105
11305
|
const files = entries.filter((name) => name.endsWith(`.${ext}`));
|
|
11106
11306
|
const sized = await Promise.all(files.map(async (name) => {
|
|
11107
|
-
const info = await stat(
|
|
11307
|
+
const info = await stat(join26(astroDir, name));
|
|
11108
11308
|
return { name, size: info.size };
|
|
11109
11309
|
}));
|
|
11110
11310
|
return sized.toSorted((a, b) => b.size - a.size);
|
|
@@ -11184,6 +11384,7 @@ var buildCommand = defineCommand2({
|
|
|
11184
11384
|
},
|
|
11185
11385
|
async run({ args }) {
|
|
11186
11386
|
const root = process.cwd();
|
|
11387
|
+
refuseIfDevRunning(root, "building");
|
|
11187
11388
|
if (args.output && args.output !== "static" && args.output !== "server") {
|
|
11188
11389
|
logger.error(`Invalid --output "${args.output}" (use static | server).`);
|
|
11189
11390
|
process.exit(1);
|
|
@@ -11192,6 +11393,7 @@ var buildCommand = defineCommand2({
|
|
|
11192
11393
|
logger.error(`Invalid --adapter "${args.adapter}" (use ${ADAPTERS.join(" | ")}).`);
|
|
11193
11394
|
process.exit(1);
|
|
11194
11395
|
}
|
|
11396
|
+
validateBudgetFlags(args);
|
|
11195
11397
|
const project = await prepareProject({
|
|
11196
11398
|
mode: "build",
|
|
11197
11399
|
overrides: {
|
|
@@ -11208,7 +11410,7 @@ var buildCommand = defineCommand2({
|
|
|
11208
11410
|
logLevel: "info",
|
|
11209
11411
|
root: project.context.outDir
|
|
11210
11412
|
});
|
|
11211
|
-
const distDir =
|
|
11413
|
+
const distDir = join26(root, "dist");
|
|
11212
11414
|
if (project.config.search.provider === "pagefind") {
|
|
11213
11415
|
logger.start("Building search index");
|
|
11214
11416
|
const indexed = await buildSearchIndex(distDir);
|
|
@@ -11222,19 +11424,19 @@ var buildCommand = defineCommand2({
|
|
|
11222
11424
|
if (project.config.ai.llmsTxt) {
|
|
11223
11425
|
const { index, full } = await buildLlmsFiles(project);
|
|
11224
11426
|
await Promise.all([
|
|
11225
|
-
writeFile6(
|
|
11226
|
-
writeFile6(
|
|
11427
|
+
writeFile6(join26(distDir, "llms.txt"), index, "utf-8"),
|
|
11428
|
+
writeFile6(join26(distDir, "llms-full.txt"), full, "utf-8")
|
|
11227
11429
|
]);
|
|
11228
11430
|
logger.success("Generated llms.txt and llms-full.txt");
|
|
11229
11431
|
}
|
|
11230
11432
|
const sitemap = buildSitemap(project);
|
|
11231
|
-
if (sitemap && !
|
|
11232
|
-
await writeFile6(
|
|
11433
|
+
if (sitemap && !existsSync16(join26(distDir, "sitemap.xml"))) {
|
|
11434
|
+
await writeFile6(join26(distDir, "sitemap.xml"), sitemap, "utf-8");
|
|
11233
11435
|
logger.success("Generated sitemap.xml");
|
|
11234
11436
|
}
|
|
11235
11437
|
const robots = buildRobots(project);
|
|
11236
|
-
if (robots && !
|
|
11237
|
-
await writeFile6(
|
|
11438
|
+
if (robots && !existsSync16(join26(distDir, "robots.txt"))) {
|
|
11439
|
+
await writeFile6(join26(distDir, "robots.txt"), robots, "utf-8");
|
|
11238
11440
|
logger.success("Generated robots.txt");
|
|
11239
11441
|
}
|
|
11240
11442
|
await emitRedirectFiles(project.config, distDir);
|
|
@@ -11263,11 +11465,11 @@ var buildCommand = defineCommand2({
|
|
|
11263
11465
|
});
|
|
11264
11466
|
|
|
11265
11467
|
// src/cli/commands/check.ts
|
|
11266
|
-
import { existsSync as
|
|
11468
|
+
import { existsSync as existsSync17 } from "node:fs";
|
|
11267
11469
|
import { check } from "@astrojs/check";
|
|
11268
11470
|
import { sync } from "astro";
|
|
11269
11471
|
import { defineCommand as defineCommand3 } from "citty";
|
|
11270
|
-
import { join as
|
|
11472
|
+
import { join as join27 } from "pathe";
|
|
11271
11473
|
var checkCommand = defineCommand3({
|
|
11272
11474
|
args: {
|
|
11273
11475
|
preview: {
|
|
@@ -11293,13 +11495,13 @@ var checkCommand = defineCommand3({
|
|
|
11293
11495
|
});
|
|
11294
11496
|
const { outDir } = project.context;
|
|
11295
11497
|
await sync({ logLevel: "warn", root: outDir });
|
|
11296
|
-
const tsconfig =
|
|
11498
|
+
const tsconfig = join27(root, "tsconfig.json");
|
|
11297
11499
|
logger.start(`Type-checking ${project.graph.pages.length} page(s)`);
|
|
11298
11500
|
const failed = await check({
|
|
11299
11501
|
minimumFailingSeverity: "error",
|
|
11300
11502
|
minimumSeverity: "hint",
|
|
11301
11503
|
root: outDir,
|
|
11302
|
-
tsconfig:
|
|
11504
|
+
tsconfig: existsSync17(tsconfig) ? tsconfig : undefined,
|
|
11303
11505
|
watch: false
|
|
11304
11506
|
});
|
|
11305
11507
|
if (failed) {
|
|
@@ -11315,6 +11517,9 @@ import { watch } from "node:fs";
|
|
|
11315
11517
|
import { dev } from "astro";
|
|
11316
11518
|
import { defineCommand as defineCommand4 } from "citty";
|
|
11317
11519
|
|
|
11520
|
+
// src/astro/static-assets.ts
|
|
11521
|
+
import { extname as extname7, join as join28, relative as relative15, resolve as resolve10, sep } from "pathe";
|
|
11522
|
+
|
|
11318
11523
|
// src/astro/integration.ts
|
|
11319
11524
|
var overlayServer = null;
|
|
11320
11525
|
var overlayChannel = () => overlayServer?.ws ?? overlayServer?.hot;
|
|
@@ -11348,6 +11553,20 @@ ${body}`,
|
|
|
11348
11553
|
});
|
|
11349
11554
|
};
|
|
11350
11555
|
|
|
11556
|
+
// src/cli/args.ts
|
|
11557
|
+
var MAX_PORT = 65535;
|
|
11558
|
+
var parsePort = (value) => {
|
|
11559
|
+
if (value === undefined) {
|
|
11560
|
+
return;
|
|
11561
|
+
}
|
|
11562
|
+
const port = Number(value);
|
|
11563
|
+
if (!(Number.isInteger(port) && port >= 1 && port <= MAX_PORT)) {
|
|
11564
|
+
logger.error(`Invalid --port "${value}" (expected an integer 1-${MAX_PORT}).`);
|
|
11565
|
+
process.exit(1);
|
|
11566
|
+
}
|
|
11567
|
+
return port;
|
|
11568
|
+
};
|
|
11569
|
+
|
|
11351
11570
|
// src/cli/commands/dev.ts
|
|
11352
11571
|
var devCommand = defineCommand4({
|
|
11353
11572
|
args: {
|
|
@@ -11376,7 +11595,8 @@ var devCommand = defineCommand4({
|
|
|
11376
11595
|
const root = process.cwd();
|
|
11377
11596
|
const preview = args.preview ?? false;
|
|
11378
11597
|
const overrides = args["content-dir"] ? { contentRoot: args["content-dir"] } : undefined;
|
|
11379
|
-
const
|
|
11598
|
+
const explicitPort = parsePort(args.port);
|
|
11599
|
+
const port = explicitPort ?? 4321;
|
|
11380
11600
|
const devServerUrl = `http://localhost:${port}`;
|
|
11381
11601
|
const project = await prepareProject({
|
|
11382
11602
|
devServerUrl,
|
|
@@ -11389,13 +11609,15 @@ var devCommand = defineCommand4({
|
|
|
11389
11609
|
if (project.bridge) {
|
|
11390
11610
|
logger.info('Detected docs.json — running in Mintlify bridge mode (no migration). Run "blume migrate mintlify" to convert permanently.');
|
|
11391
11611
|
}
|
|
11612
|
+
const releaseLock = acquireDevLock(project.context.outDir);
|
|
11613
|
+
process.on("exit", releaseLock);
|
|
11392
11614
|
const server = await dev({
|
|
11393
11615
|
logLevel: args.debug ? "debug" : "info",
|
|
11394
11616
|
root: project.context.outDir,
|
|
11395
11617
|
server: {
|
|
11396
11618
|
host: args.host ?? false,
|
|
11397
11619
|
open: args.open ?? false,
|
|
11398
|
-
port:
|
|
11620
|
+
port: explicitPort
|
|
11399
11621
|
}
|
|
11400
11622
|
});
|
|
11401
11623
|
showBlumeErrorOverlay(project.diagnostics);
|
|
@@ -11436,6 +11658,7 @@ var devCommand = defineCommand4({
|
|
|
11436
11658
|
for (const dispose of disposers) {
|
|
11437
11659
|
dispose();
|
|
11438
11660
|
}
|
|
11661
|
+
releaseLock();
|
|
11439
11662
|
await server.stop();
|
|
11440
11663
|
process.exit(0);
|
|
11441
11664
|
};
|
|
@@ -11505,6 +11728,7 @@ var doctorCommand = defineCommand5({
|
|
|
11505
11728
|
}
|
|
11506
11729
|
if (args.json) {
|
|
11507
11730
|
if (reportDiagnosticsJson(diagnostics, root)) {
|
|
11731
|
+
await flushStdout();
|
|
11508
11732
|
process.exit(1);
|
|
11509
11733
|
}
|
|
11510
11734
|
return;
|
|
@@ -11522,12 +11746,12 @@ var doctorCommand = defineCommand5({
|
|
|
11522
11746
|
// src/cli/commands/eject.ts
|
|
11523
11747
|
import { readFile as readFile15, writeFile as writeFile8 } from "node:fs/promises";
|
|
11524
11748
|
import { defineCommand as defineCommand6 } from "citty";
|
|
11525
|
-
import { join as
|
|
11749
|
+
import { join as join30, relative as relative17 } from "pathe";
|
|
11526
11750
|
|
|
11527
11751
|
// src/registry/eject.ts
|
|
11528
|
-
import { existsSync as
|
|
11752
|
+
import { existsSync as existsSync18 } from "node:fs";
|
|
11529
11753
|
import { cp, mkdir as mkdir5, readFile as readFile14, rm as rm2, writeFile as writeFile7 } from "node:fs/promises";
|
|
11530
|
-
import { join as
|
|
11754
|
+
import { join as join29, relative as relative16 } from "pathe";
|
|
11531
11755
|
var POSIX = (path) => path.split("\\").join("/");
|
|
11532
11756
|
var askFiles = async (project, srcDir, genDir) => {
|
|
11533
11757
|
const { ask } = project.config.ai;
|
|
@@ -11538,14 +11762,14 @@ var askFiles = async (project, srcDir, genDir) => {
|
|
|
11538
11762
|
const files = [
|
|
11539
11763
|
{
|
|
11540
11764
|
content: askEndpointTemplate(resolveAskBackend(ask), grounded),
|
|
11541
|
-
path:
|
|
11765
|
+
path: join29(srcDir, "pages", "api", "ask.ts")
|
|
11542
11766
|
}
|
|
11543
11767
|
];
|
|
11544
11768
|
if (grounded) {
|
|
11545
11769
|
files.push({
|
|
11546
11770
|
content: `${JSON.stringify(await buildAskData(project))}
|
|
11547
11771
|
`,
|
|
11548
|
-
path:
|
|
11772
|
+
path: join29(genDir, "ask-data.json")
|
|
11549
11773
|
});
|
|
11550
11774
|
}
|
|
11551
11775
|
return files;
|
|
@@ -11553,8 +11777,8 @@ var askFiles = async (project, srcDir, genDir) => {
|
|
|
11553
11777
|
var eject = async (root) => {
|
|
11554
11778
|
const project = await scanProject(root, { mode: "build" });
|
|
11555
11779
|
const { context, config } = project;
|
|
11556
|
-
const srcDir =
|
|
11557
|
-
const genDir =
|
|
11780
|
+
const srcDir = join29(root, "src");
|
|
11781
|
+
const genDir = join29(srcDir, "generated");
|
|
11558
11782
|
const askEnabled = config.ai.ask?.enabled ?? false;
|
|
11559
11783
|
const exportPdf = config.export.pdf;
|
|
11560
11784
|
const exportEpub = config.export.epub;
|
|
@@ -11575,13 +11799,13 @@ var eject = async (root) => {
|
|
|
11575
11799
|
const needsSvelte = frameworks.has("svelte");
|
|
11576
11800
|
const relContext = {
|
|
11577
11801
|
...context,
|
|
11578
|
-
contentRoot: POSIX(
|
|
11802
|
+
contentRoot: POSIX(relative16(root, context.contentRoot)),
|
|
11579
11803
|
outDir: ".",
|
|
11580
11804
|
root: "."
|
|
11581
11805
|
};
|
|
11582
|
-
const componentsImport = context.componentsFile ? `../../${POSIX(
|
|
11806
|
+
const componentsImport = context.componentsFile ? `../../${POSIX(relative16(root, context.componentsFile))}` : null;
|
|
11583
11807
|
const relPages = pages.map((page) => ({
|
|
11584
|
-
entrypoint: POSIX(
|
|
11808
|
+
entrypoint: POSIX(relative16(root, page.entrypoint)),
|
|
11585
11809
|
pattern: page.pattern
|
|
11586
11810
|
}));
|
|
11587
11811
|
const staged = collectStaged(project);
|
|
@@ -11602,13 +11826,14 @@ var eject = async (root) => {
|
|
|
11602
11826
|
searchClientPath: "./src/generated/search-client.ts",
|
|
11603
11827
|
themePath: "./src/generated/app.css"
|
|
11604
11828
|
}),
|
|
11605
|
-
path:
|
|
11829
|
+
path: join29(root, "astro.config.mjs")
|
|
11606
11830
|
},
|
|
11607
11831
|
{
|
|
11608
11832
|
content: runtimeTsconfigTemplate(),
|
|
11609
|
-
path:
|
|
11833
|
+
path: join29(root, "tsconfig.json"),
|
|
11834
|
+
skipIfExists: true
|
|
11610
11835
|
},
|
|
11611
|
-
{ content: envTemplate(), path:
|
|
11836
|
+
{ content: envTemplate(), path: join29(srcDir, "env.d.ts") },
|
|
11612
11837
|
{
|
|
11613
11838
|
content: contentConfigTemplate({
|
|
11614
11839
|
config,
|
|
@@ -11616,7 +11841,7 @@ var eject = async (root) => {
|
|
|
11616
11841
|
staged: hasStaged,
|
|
11617
11842
|
stagedBase: stagedDir
|
|
11618
11843
|
}),
|
|
11619
|
-
path:
|
|
11844
|
+
path: join29(srcDir, "content.config.ts")
|
|
11620
11845
|
},
|
|
11621
11846
|
{
|
|
11622
11847
|
content: catchAllPageTemplate({
|
|
@@ -11626,19 +11851,19 @@ var eject = async (root) => {
|
|
|
11626
11851
|
mathEnabled: config.markdown.math,
|
|
11627
11852
|
needsReact
|
|
11628
11853
|
}),
|
|
11629
|
-
path:
|
|
11854
|
+
path: join29(srcDir, "pages", "[...slug].astro")
|
|
11630
11855
|
},
|
|
11631
11856
|
{
|
|
11632
11857
|
content: planComponentSlots(componentsImport, null).module,
|
|
11633
|
-
path:
|
|
11858
|
+
path: join29(genDir, "components.ts")
|
|
11634
11859
|
},
|
|
11635
11860
|
{
|
|
11636
11861
|
content: islandMapTemplate(islands.islands),
|
|
11637
|
-
path:
|
|
11862
|
+
path: join29(genDir, "islands.ts")
|
|
11638
11863
|
},
|
|
11639
11864
|
{
|
|
11640
11865
|
content: exampleMapTemplate(examples.examples),
|
|
11641
|
-
path:
|
|
11866
|
+
path: join29(genDir, "examples.ts")
|
|
11642
11867
|
},
|
|
11643
11868
|
{
|
|
11644
11869
|
content: tailwindEntryTemplate({
|
|
@@ -11650,21 +11875,21 @@ var eject = async (root) => {
|
|
|
11650
11875
|
twoslashCss: twoslashCss(),
|
|
11651
11876
|
userTheme
|
|
11652
11877
|
}),
|
|
11653
|
-
path:
|
|
11878
|
+
path: join29(genDir, "app.css")
|
|
11654
11879
|
},
|
|
11655
|
-
{ content: buildRuntimeData(project), path:
|
|
11880
|
+
{ content: buildRuntimeData(project), path: join29(genDir, "data.json") },
|
|
11656
11881
|
{
|
|
11657
11882
|
content: `${JSON.stringify(rawMarkdown)}
|
|
11658
11883
|
`,
|
|
11659
|
-
path:
|
|
11884
|
+
path: join29(genDir, "raw-markdown.json")
|
|
11660
11885
|
},
|
|
11661
11886
|
{
|
|
11662
11887
|
content: rawMarkdownEndpointTemplate(),
|
|
11663
|
-
path:
|
|
11888
|
+
path: join29(srcDir, "pages", "[...slug].md.ts")
|
|
11664
11889
|
},
|
|
11665
11890
|
{
|
|
11666
11891
|
content: rawMarkdownEndpointTemplate(),
|
|
11667
|
-
path:
|
|
11892
|
+
path: join29(srcDir, "pages", "[...slug].mdx.ts")
|
|
11668
11893
|
}
|
|
11669
11894
|
];
|
|
11670
11895
|
if (askEnabled) {
|
|
@@ -11673,34 +11898,34 @@ var eject = async (root) => {
|
|
|
11673
11898
|
if (config.seo.og.enabled) {
|
|
11674
11899
|
files.push({
|
|
11675
11900
|
content: ogEndpointTemplate(customOgRoutes(pages, config.title)),
|
|
11676
|
-
path:
|
|
11901
|
+
path: join29(srcDir, "pages", "og", "[...slug].png.ts")
|
|
11677
11902
|
});
|
|
11678
11903
|
}
|
|
11679
11904
|
if (!routeIsTaken(pages, project.graph.pages, "/404")) {
|
|
11680
11905
|
files.push({
|
|
11681
11906
|
content: notFoundPageTemplate(),
|
|
11682
|
-
path:
|
|
11907
|
+
path: join29(srcDir, "pages", "404.astro")
|
|
11683
11908
|
});
|
|
11684
11909
|
}
|
|
11685
11910
|
files.push({
|
|
11686
11911
|
content: searchClientTemplate(config),
|
|
11687
|
-
path:
|
|
11912
|
+
path: join29(genDir, "search-client.ts")
|
|
11688
11913
|
});
|
|
11689
11914
|
if (servesStaticIndex(config.search.provider)) {
|
|
11690
11915
|
const documents = await buildSearchDocuments(project);
|
|
11691
11916
|
files.push({
|
|
11692
11917
|
content: `${JSON.stringify(documents)}
|
|
11693
11918
|
`,
|
|
11694
|
-
path:
|
|
11919
|
+
path: join29(genDir, "search.json")
|
|
11695
11920
|
}, {
|
|
11696
11921
|
content: searchEndpointTemplate(),
|
|
11697
|
-
path:
|
|
11922
|
+
path: join29(srcDir, "pages", "blume-search.json.ts")
|
|
11698
11923
|
});
|
|
11699
11924
|
}
|
|
11700
11925
|
if (config.search.provider === "mixedbread") {
|
|
11701
11926
|
files.push({
|
|
11702
11927
|
content: mixedbreadSearchEndpointTemplate(config.search.mixedbread?.storeId ?? ""),
|
|
11703
|
-
path:
|
|
11928
|
+
path: join29(srcDir, "pages", "api", "search.ts")
|
|
11704
11929
|
});
|
|
11705
11930
|
}
|
|
11706
11931
|
const feeds = buildRssFeeds(project);
|
|
@@ -11709,10 +11934,10 @@ var eject = async (root) => {
|
|
|
11709
11934
|
files.push({
|
|
11710
11935
|
content: `${JSON.stringify(feedXml)}
|
|
11711
11936
|
`,
|
|
11712
|
-
path:
|
|
11937
|
+
path: join29(genDir, "rss.json")
|
|
11713
11938
|
}, {
|
|
11714
11939
|
content: rssEndpointTemplate(),
|
|
11715
|
-
path:
|
|
11940
|
+
path: join29(srcDir, "pages", "[section]", "rss.xml.ts")
|
|
11716
11941
|
});
|
|
11717
11942
|
}
|
|
11718
11943
|
if (hasReferences(config)) {
|
|
@@ -11724,37 +11949,38 @@ var eject = async (root) => {
|
|
|
11724
11949
|
for (const file of references.files) {
|
|
11725
11950
|
files.push({
|
|
11726
11951
|
content: file.content,
|
|
11727
|
-
path:
|
|
11952
|
+
path: join29(srcDir, "pages", file.pagePath)
|
|
11728
11953
|
});
|
|
11729
11954
|
}
|
|
11730
11955
|
}
|
|
11731
11956
|
files.push(...islands.islands.map((island) => ({
|
|
11732
11957
|
content: islandWrapperTemplate(island),
|
|
11733
|
-
path:
|
|
11958
|
+
path: join29(genDir, "islands", `${island.name}.astro`)
|
|
11734
11959
|
})), ...examples.examples.map((example) => ({
|
|
11735
11960
|
content: exampleWrapperTemplate(example),
|
|
11736
|
-
path:
|
|
11961
|
+
path: join29(genDir, "examples", `${exampleSlug(example.path)}.astro`)
|
|
11737
11962
|
})));
|
|
11738
11963
|
for (const [entryId, content] of staged) {
|
|
11739
|
-
files.push({ content, path:
|
|
11964
|
+
files.push({ content, path: join29(root, stagedDir, entryId) });
|
|
11740
11965
|
}
|
|
11741
|
-
|
|
11742
|
-
|
|
11966
|
+
const written = files.filter((file) => !(file.skipIfExists && existsSync18(file.path)));
|
|
11967
|
+
await Promise.all(written.map(async (file) => {
|
|
11968
|
+
await mkdir5(join29(file.path, ".."), { recursive: true });
|
|
11743
11969
|
await writeFile7(file.path, file.content, "utf-8");
|
|
11744
11970
|
}));
|
|
11745
|
-
const assetsSrc =
|
|
11746
|
-
if (
|
|
11747
|
-
await cp(assetsSrc,
|
|
11971
|
+
const assetsSrc = join29(context.outDir, "public", "blume-assets");
|
|
11972
|
+
if (existsSync18(assetsSrc)) {
|
|
11973
|
+
await cp(assetsSrc, join29(root, "public", "blume-assets"), {
|
|
11748
11974
|
recursive: true
|
|
11749
11975
|
});
|
|
11750
11976
|
}
|
|
11751
11977
|
await rm2(context.outDir, { force: true, recursive: true });
|
|
11752
|
-
return
|
|
11978
|
+
return written.map((file) => file.path);
|
|
11753
11979
|
};
|
|
11754
11980
|
|
|
11755
11981
|
// src/cli/commands/eject.ts
|
|
11756
11982
|
var updatePackageScripts = async (root) => {
|
|
11757
|
-
const pkgPath =
|
|
11983
|
+
const pkgPath = join30(root, "package.json");
|
|
11758
11984
|
let pkg;
|
|
11759
11985
|
try {
|
|
11760
11986
|
pkg = JSON.parse(await readFile15(pkgPath, "utf-8"));
|
|
@@ -11781,8 +12007,9 @@ var ejectCommand = defineCommand6({
|
|
|
11781
12007
|
},
|
|
11782
12008
|
async run({ args }) {
|
|
11783
12009
|
const root = process.cwd();
|
|
12010
|
+
refuseIfDevRunning(root, "ejecting");
|
|
11784
12011
|
if (!args.yes) {
|
|
11785
|
-
logger.warn("Eject is one-way: it writes astro.config.mjs and
|
|
12012
|
+
logger.warn("Eject is one-way: it writes astro.config.mjs, src/, and (if absent) tsconfig.json, rewrites your package.json scripts, and removes .blume. An existing tsconfig.json is left untouched.");
|
|
11786
12013
|
logger.info("Re-run with --yes to proceed.");
|
|
11787
12014
|
return;
|
|
11788
12015
|
}
|
|
@@ -11790,7 +12017,7 @@ var ejectCommand = defineCommand6({
|
|
|
11790
12017
|
await updatePackageScripts(root);
|
|
11791
12018
|
logger.success(`Ejected ${files.length} file(s):`);
|
|
11792
12019
|
for (const file of files) {
|
|
11793
|
-
process.stdout.write(` ${
|
|
12020
|
+
process.stdout.write(` ${relative17(root, file)}
|
|
11794
12021
|
`);
|
|
11795
12022
|
}
|
|
11796
12023
|
logger.box(`Your project is now a standalone Astro app.
|
|
@@ -11803,10 +12030,35 @@ The blume package remains importable.`);
|
|
|
11803
12030
|
});
|
|
11804
12031
|
|
|
11805
12032
|
// src/cli/commands/init.ts
|
|
11806
|
-
import { existsSync as
|
|
11807
|
-
import { mkdir as mkdir6, writeFile as
|
|
12033
|
+
import { existsSync as existsSync20 } from "node:fs";
|
|
12034
|
+
import { mkdir as mkdir6, writeFile as writeFile10 } from "node:fs/promises";
|
|
11808
12035
|
import { defineCommand as defineCommand7 } from "citty";
|
|
11809
|
-
import { basename as basename4, dirname as dirname13, join as
|
|
12036
|
+
import { basename as basename4, dirname as dirname13, isAbsolute as isAbsolute8, join as join32, relative as relative18 } from "pathe";
|
|
12037
|
+
|
|
12038
|
+
// src/core/gitignore.ts
|
|
12039
|
+
import { existsSync as existsSync19 } from "node:fs";
|
|
12040
|
+
import { readFile as readFile16, writeFile as writeFile9 } from "node:fs/promises";
|
|
12041
|
+
import { join as join31 } from "pathe";
|
|
12042
|
+
var gitignoreKey = (line) => line.trim().replace(/\/+$/u, "");
|
|
12043
|
+
var ensureGitignore = async (root, entries) => {
|
|
12044
|
+
const path = join31(root, ".gitignore");
|
|
12045
|
+
const existing = existsSync19(path) ? await readFile16(path, "utf-8") : "";
|
|
12046
|
+
const present = new Set(existing.split(`
|
|
12047
|
+
`).map(gitignoreKey).filter(Boolean));
|
|
12048
|
+
const added = entries.filter((entry) => !present.has(gitignoreKey(entry)));
|
|
12049
|
+
if (added.length === 0) {
|
|
12050
|
+
return [];
|
|
12051
|
+
}
|
|
12052
|
+
const gap = existing.length > 0 && !existing.endsWith(`
|
|
12053
|
+
`) ? `
|
|
12054
|
+
` : "";
|
|
12055
|
+
await writeFile9(path, `${existing}${gap}${added.join(`
|
|
12056
|
+
`)}
|
|
12057
|
+
`, "utf-8");
|
|
12058
|
+
return added;
|
|
12059
|
+
};
|
|
12060
|
+
|
|
12061
|
+
// src/cli/commands/init.ts
|
|
11810
12062
|
var toPackageName = (raw) => raw.toLowerCase().replaceAll(/[^a-z0-9._-]+/gu, "-").replaceAll(/^[-_.]+|[-_.]+$/gu, "") || "docs";
|
|
11811
12063
|
var packageTemplate = (name, version) => `{
|
|
11812
12064
|
"name": ${JSON.stringify(name)},
|
|
@@ -11854,7 +12106,7 @@ var STARTERS = {
|
|
|
11854
12106
|
files: (dir) => [
|
|
11855
12107
|
{
|
|
11856
12108
|
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:
|
|
12109
|
+
path: join32(dir, "index.mdx")
|
|
11858
12110
|
}
|
|
11859
12111
|
]
|
|
11860
12112
|
},
|
|
@@ -11869,7 +12121,7 @@ var STARTERS = {
|
|
|
11869
12121
|
files: (dir) => [
|
|
11870
12122
|
{
|
|
11871
12123
|
content: page("Introduction", "Welcome to your new Blume docs.", "# Introduction\n\nWrite your docs here, and log releases under `changelog/`."),
|
|
11872
|
-
path:
|
|
12124
|
+
path: join32(dir, "index.mdx")
|
|
11873
12125
|
},
|
|
11874
12126
|
{
|
|
11875
12127
|
content: `---
|
|
@@ -11880,7 +12132,7 @@ date: 2026-01-01
|
|
|
11880
12132
|
|
|
11881
12133
|
The first release. Edit \`${dir}/changelog/v1-0-0.mdx\` or add new entries beside it.
|
|
11882
12134
|
`,
|
|
11883
|
-
path:
|
|
12135
|
+
path: join32(dir, "changelog", "v1-0-0.mdx")
|
|
11884
12136
|
}
|
|
11885
12137
|
]
|
|
11886
12138
|
},
|
|
@@ -11893,7 +12145,7 @@ The first release. Edit \`${dir}/changelog/v1-0-0.mdx\` or add new entries besid
|
|
|
11893
12145
|
Welcome to **Blume** — markdown-first docs powered by Astro and Vite.
|
|
11894
12146
|
|
|
11895
12147
|
Edit \`${dir}/index.mdx\` to get started, then run \`blume dev\`.`),
|
|
11896
|
-
path:
|
|
12148
|
+
path: join32(dir, "index.mdx")
|
|
11897
12149
|
}
|
|
11898
12150
|
]
|
|
11899
12151
|
},
|
|
@@ -11904,11 +12156,11 @@ Edit \`${dir}/index.mdx\` to get started, then run \`blume dev\`.`),
|
|
|
11904
12156
|
content: page("Introduction", "Get started with the SDK.", `# Introduction
|
|
11905
12157
|
|
|
11906
12158
|
Install the SDK and make your first call. See [Installation](/installation).`),
|
|
11907
|
-
path:
|
|
12159
|
+
path: join32(dir, "index.mdx")
|
|
11908
12160
|
},
|
|
11909
12161
|
{
|
|
11910
12162
|
content: page("Installation", "Install the SDK.", "# Installation\n\n```package-install\nyour-sdk\n```"),
|
|
11911
|
-
path:
|
|
12163
|
+
path: join32(dir, "installation.mdx")
|
|
11912
12164
|
}
|
|
11913
12165
|
]
|
|
11914
12166
|
}
|
|
@@ -11918,12 +12170,12 @@ var commandsFor = (pm) => ({
|
|
|
11918
12170
|
install: `${pm} install`
|
|
11919
12171
|
});
|
|
11920
12172
|
var writeFileSafe = async (path, content) => {
|
|
11921
|
-
if (
|
|
12173
|
+
if (existsSync20(path)) {
|
|
11922
12174
|
logger.info(`Skipped existing ${path}`);
|
|
11923
12175
|
return false;
|
|
11924
12176
|
}
|
|
11925
12177
|
await mkdir6(dirname13(path), { recursive: true });
|
|
11926
|
-
await
|
|
12178
|
+
await writeFile10(path, content, "utf-8");
|
|
11927
12179
|
logger.success(`Created ${path}`);
|
|
11928
12180
|
return true;
|
|
11929
12181
|
};
|
|
@@ -11955,6 +12207,10 @@ var initCommand = defineCommand7({
|
|
|
11955
12207
|
async run({ args }) {
|
|
11956
12208
|
const root = process.cwd();
|
|
11957
12209
|
const contentDir = args["content-dir"] ?? "docs";
|
|
12210
|
+
if (isAbsolute8(contentDir) || relative18(root, join32(root, contentDir)).startsWith("..")) {
|
|
12211
|
+
logger.error(`Invalid --content-dir "${contentDir}" (must be a path inside the project).`);
|
|
12212
|
+
process.exit(1);
|
|
12213
|
+
}
|
|
11958
12214
|
const template = args.template ?? "docs";
|
|
11959
12215
|
if (!TEMPLATES.includes(template)) {
|
|
11960
12216
|
logger.error(`Unknown template "${args.template}" (use ${TEMPLATES.join(" | ")}).`);
|
|
@@ -11966,9 +12222,13 @@ var initCommand = defineCommand7({
|
|
|
11966
12222
|
process.exit(1);
|
|
11967
12223
|
}
|
|
11968
12224
|
const starter = STARTERS[template];
|
|
11969
|
-
const createdPackage = await writeFileSafe(
|
|
11970
|
-
await writeFileSafe(
|
|
11971
|
-
await Promise.all(starter.files(contentDir).map((file) => writeFileSafe(
|
|
12225
|
+
const createdPackage = await writeFileSafe(join32(root, "package.json"), packageTemplate(toPackageName(basename4(root)), getBlumeVersion()));
|
|
12226
|
+
await writeFileSafe(join32(root, "blume.config.ts"), starter.config);
|
|
12227
|
+
await Promise.all(starter.files(contentDir).map((file) => writeFileSafe(join32(root, file.path), file.content)));
|
|
12228
|
+
const ignored = await ensureGitignore(root, [".blume/", "dist/"]);
|
|
12229
|
+
if (ignored.length > 0) {
|
|
12230
|
+
logger.success(`Added ${ignored.join(", ")} to .gitignore`);
|
|
12231
|
+
}
|
|
11972
12232
|
const commands = commandsFor(pm);
|
|
11973
12233
|
if (args.eject) {
|
|
11974
12234
|
try {
|
|
@@ -12005,15 +12265,15 @@ var initCommand = defineCommand7({
|
|
|
12005
12265
|
import { defineCommand as defineCommand8 } from "citty";
|
|
12006
12266
|
|
|
12007
12267
|
// src/migrate/fumadocs/index.ts
|
|
12008
|
-
import { existsSync as
|
|
12009
|
-
import { mkdir as mkdir8, readFile as
|
|
12010
|
-
import { dirname as dirname16, join as
|
|
12268
|
+
import { existsSync as existsSync24 } from "node:fs";
|
|
12269
|
+
import { mkdir as mkdir8, readFile as readFile18, rename as rename3, rm as rm3, writeFile as writeFile12 } from "node:fs/promises";
|
|
12270
|
+
import { dirname as dirname16, join as join35, relative as relative19 } from "pathe";
|
|
12011
12271
|
import { glob as glob8 } from "tinyglobby";
|
|
12012
12272
|
|
|
12013
12273
|
// src/migrate/fumadocs/config.ts
|
|
12014
|
-
import { existsSync as
|
|
12015
|
-
import { readFile as
|
|
12016
|
-
import { basename as basename5, dirname as dirname14, join as
|
|
12274
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
12275
|
+
import { readFile as readFile17 } from "node:fs/promises";
|
|
12276
|
+
import { basename as basename5, dirname as dirname14, join as join33 } from "pathe";
|
|
12017
12277
|
var SOURCE_FILES = [
|
|
12018
12278
|
"lib/source.ts",
|
|
12019
12279
|
"app/source.ts",
|
|
@@ -12043,7 +12303,7 @@ var GENERIC_NAMES = new Set([
|
|
|
12043
12303
|
var gitRepoRoot = (start) => {
|
|
12044
12304
|
let dir = start;
|
|
12045
12305
|
for (;; ) {
|
|
12046
|
-
if (
|
|
12306
|
+
if (existsSync21(join33(dir, ".git"))) {
|
|
12047
12307
|
return dir;
|
|
12048
12308
|
}
|
|
12049
12309
|
const parent = dirname14(dir);
|
|
@@ -12055,12 +12315,12 @@ var gitRepoRoot = (start) => {
|
|
|
12055
12315
|
};
|
|
12056
12316
|
var bareName = (name) => name.includes("/") ? name.slice(name.lastIndexOf("/") + 1) : name;
|
|
12057
12317
|
var readTitle = async (root) => {
|
|
12058
|
-
const packageJson =
|
|
12059
|
-
if (!
|
|
12318
|
+
const packageJson = join33(root, "package.json");
|
|
12319
|
+
if (!existsSync21(packageJson)) {
|
|
12060
12320
|
return "Documentation";
|
|
12061
12321
|
}
|
|
12062
12322
|
try {
|
|
12063
|
-
const parsed = JSON.parse(await
|
|
12323
|
+
const parsed = JSON.parse(await readFile17(packageJson, "utf-8"));
|
|
12064
12324
|
const { name } = parsed;
|
|
12065
12325
|
if (typeof name !== "string" || !name.trim()) {
|
|
12066
12326
|
return "Documentation";
|
|
@@ -12081,11 +12341,11 @@ var readTitle = async (root) => {
|
|
|
12081
12341
|
};
|
|
12082
12342
|
var scrapeBaseUrl = async (root) => {
|
|
12083
12343
|
for (const candidate of SOURCE_FILES) {
|
|
12084
|
-
const file =
|
|
12085
|
-
if (!
|
|
12344
|
+
const file = join33(root, candidate);
|
|
12345
|
+
if (!existsSync21(file)) {
|
|
12086
12346
|
continue;
|
|
12087
12347
|
}
|
|
12088
|
-
const base = BASE_URL.exec(await
|
|
12348
|
+
const base = BASE_URL.exec(await readFile17(file, "utf-8"))?.groups?.base;
|
|
12089
12349
|
if (base) {
|
|
12090
12350
|
return base;
|
|
12091
12351
|
}
|
|
@@ -12114,9 +12374,9 @@ var loadFumadocsConfig = async (root) => {
|
|
|
12114
12374
|
};
|
|
12115
12375
|
|
|
12116
12376
|
// src/migrate/fumadocs/content.ts
|
|
12117
|
-
import { existsSync as
|
|
12377
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
12118
12378
|
import { readFile as readFileFromDisk2 } from "node:fs/promises";
|
|
12119
|
-
import { dirname as dirname15, resolve as
|
|
12379
|
+
import { dirname as dirname15, resolve as resolve11 } from "pathe";
|
|
12120
12380
|
var FUMADOCS_IMPORT = /^import\s+[\s\S]*?\s+from\s+["']fumadocs-(?:ui|core|mdx)(?:\/[^"']*)?["'];?[ \t]*\n?/gmu;
|
|
12121
12381
|
var stripFumadocsImports = (source) => {
|
|
12122
12382
|
const stripped = source.replace(FUMADOCS_IMPORT, "");
|
|
@@ -12317,12 +12577,16 @@ var inlineFumadocsIncludes = async (source, options) => {
|
|
|
12317
12577
|
if (!rawPath) {
|
|
12318
12578
|
continue;
|
|
12319
12579
|
}
|
|
12320
|
-
const target =
|
|
12580
|
+
const target = resolve11(dirname15(options.filePath), rawPath);
|
|
12581
|
+
if (!isInsideRoot2(options.root, target)) {
|
|
12582
|
+
warnings.push(`<include> target "${rawPath}" is outside the docs tree — left as-is.`);
|
|
12583
|
+
continue;
|
|
12584
|
+
}
|
|
12321
12585
|
if (seen.has(target)) {
|
|
12322
12586
|
warnings.push(`Circular <include> "${rawPath}" — left as-is.`);
|
|
12323
12587
|
continue;
|
|
12324
12588
|
}
|
|
12325
|
-
if (!
|
|
12589
|
+
if (!existsSync22(target)) {
|
|
12326
12590
|
warnings.push(`<include> target "${rawPath}" not found — left as-is.`);
|
|
12327
12591
|
continue;
|
|
12328
12592
|
}
|
|
@@ -12354,9 +12618,9 @@ var normalizeFumadocsPageMeta = (value) => {
|
|
|
12354
12618
|
};
|
|
12355
12619
|
|
|
12356
12620
|
// src/migrate/fumadocs/groups.ts
|
|
12357
|
-
import { existsSync as
|
|
12358
|
-
import { mkdir as mkdir7, rename as rename2, writeFile as
|
|
12359
|
-
import { basename as basename6, join as
|
|
12621
|
+
import { existsSync as existsSync23, statSync as statSync2 } from "node:fs";
|
|
12622
|
+
import { mkdir as mkdir7, rename as rename2, writeFile as writeFile11 } from "node:fs/promises";
|
|
12623
|
+
import { basename as basename6, join as join34 } from "pathe";
|
|
12360
12624
|
|
|
12361
12625
|
// src/migrate/fumadocs/meta.ts
|
|
12362
12626
|
var SEPARATOR = /^---(?<label>.*)---$/u;
|
|
@@ -12501,13 +12765,16 @@ var isDirectory = (path) => {
|
|
|
12501
12765
|
}
|
|
12502
12766
|
};
|
|
12503
12767
|
var resolveEntry = (docsDir, name) => {
|
|
12768
|
+
if (!isInsideRoot2(docsDir, join34(docsDir, name))) {
|
|
12769
|
+
return null;
|
|
12770
|
+
}
|
|
12504
12771
|
for (const ext of PAGE_EXTS) {
|
|
12505
|
-
const file =
|
|
12506
|
-
if (
|
|
12772
|
+
const file = join34(docsDir, `${name}${ext}`);
|
|
12773
|
+
if (existsSync23(file)) {
|
|
12507
12774
|
return { kind: "file", path: file };
|
|
12508
12775
|
}
|
|
12509
12776
|
}
|
|
12510
|
-
const folder =
|
|
12777
|
+
const folder = join34(docsDir, name);
|
|
12511
12778
|
return isDirectory(folder) ? { kind: "folder", path: folder } : null;
|
|
12512
12779
|
};
|
|
12513
12780
|
var humanize2 = (name) => name.split(WORD_SPLIT3).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
@@ -12542,8 +12809,8 @@ var moveItemIntoGroup = async (item, docsDir, groupDir, label, warnings) => {
|
|
|
12542
12809
|
warnings.push(`Sidebar entry "${item.name}" in section "${label}" matched no page or folder; skipped.`);
|
|
12543
12810
|
return null;
|
|
12544
12811
|
}
|
|
12545
|
-
const dest =
|
|
12546
|
-
if (
|
|
12812
|
+
const dest = join34(groupDir, basename6(resolved.path));
|
|
12813
|
+
if (existsSync23(dest)) {
|
|
12547
12814
|
warnings.push(`Skipped moving "${item.name}" into section "${label}" (target already exists).`);
|
|
12548
12815
|
return null;
|
|
12549
12816
|
}
|
|
@@ -12570,7 +12837,7 @@ var reshapeSection = async (section, docsDir, order, warnings) => {
|
|
|
12570
12837
|
}
|
|
12571
12838
|
return;
|
|
12572
12839
|
}
|
|
12573
|
-
const groupDir =
|
|
12840
|
+
const groupDir = join34(docsDir, `(${section.label})`);
|
|
12574
12841
|
const sectionKeys = [];
|
|
12575
12842
|
for (const item of section.items) {
|
|
12576
12843
|
const key = await moveItemIntoGroup(item, docsDir, groupDir, section.label, warnings);
|
|
@@ -12583,7 +12850,7 @@ var reshapeSection = async (section, docsDir, order, warnings) => {
|
|
|
12583
12850
|
}
|
|
12584
12851
|
order.push(section.label);
|
|
12585
12852
|
if (sectionKeys.length > 1) {
|
|
12586
|
-
await
|
|
12853
|
+
await writeFile11(join34(groupDir, "meta.ts"), renderMetaModule({ pages: sectionKeys }), "utf-8");
|
|
12587
12854
|
}
|
|
12588
12855
|
};
|
|
12589
12856
|
var reshapeFumadocsGroups = async (structure, docsDir) => {
|
|
@@ -12615,9 +12882,9 @@ var FUMADOCS_LEFTOVERS = [
|
|
|
12615
12882
|
"app"
|
|
12616
12883
|
];
|
|
12617
12884
|
var movePage = async (abs, base, root) => {
|
|
12618
|
-
const rel =
|
|
12619
|
-
const dest =
|
|
12620
|
-
if (
|
|
12885
|
+
const rel = relative19(base, abs);
|
|
12886
|
+
const dest = join35(root, "docs", rel);
|
|
12887
|
+
if (existsSync24(dest)) {
|
|
12621
12888
|
return {
|
|
12622
12889
|
includeWarnings: [],
|
|
12623
12890
|
moved: 0,
|
|
@@ -12626,8 +12893,11 @@ var movePage = async (abs, base, root) => {
|
|
|
12626
12893
|
unsupported: []
|
|
12627
12894
|
};
|
|
12628
12895
|
}
|
|
12629
|
-
const raw = await
|
|
12630
|
-
const included = await inlineFumadocsIncludes(raw, {
|
|
12896
|
+
const raw = await readFile18(abs, "utf-8");
|
|
12897
|
+
const included = await inlineFumadocsIncludes(raw, {
|
|
12898
|
+
filePath: abs,
|
|
12899
|
+
root: base
|
|
12900
|
+
});
|
|
12631
12901
|
let text = stripFumadocsImports(included.content);
|
|
12632
12902
|
text = rewriteFumadocsCallouts(text);
|
|
12633
12903
|
text = rewriteFumadocsContainers(text);
|
|
@@ -12637,7 +12907,7 @@ var movePage = async (abs, base, root) => {
|
|
|
12637
12907
|
const { data, removed } = normalizeFumadocsPageMeta(parsed.data);
|
|
12638
12908
|
const content = Object.keys(data).length > 0 ? frontmatter_default.stringify(parsed.content, data) : parsed.content;
|
|
12639
12909
|
await mkdir8(dirname16(dest), { recursive: true });
|
|
12640
|
-
await
|
|
12910
|
+
await writeFile12(dest, content, "utf-8");
|
|
12641
12911
|
await rm3(abs, { force: true });
|
|
12642
12912
|
return {
|
|
12643
12913
|
includeWarnings: included.warnings,
|
|
@@ -12651,22 +12921,22 @@ var writeMeta = async (dest, meta, rel, warnings) => {
|
|
|
12651
12921
|
if (Object.keys(meta).length === 0) {
|
|
12652
12922
|
return warnings;
|
|
12653
12923
|
}
|
|
12654
|
-
if (
|
|
12924
|
+
if (existsSync24(dest)) {
|
|
12655
12925
|
return [...warnings, `Skipped ${rel} (target already exists)`];
|
|
12656
12926
|
}
|
|
12657
12927
|
await mkdir8(dirname16(dest), { recursive: true });
|
|
12658
|
-
await
|
|
12928
|
+
await writeFile12(dest, renderMetaModule(meta), "utf-8");
|
|
12659
12929
|
return warnings;
|
|
12660
12930
|
};
|
|
12661
12931
|
var convertMeta = async (abs, base, root) => {
|
|
12662
|
-
const rel =
|
|
12663
|
-
const raw = await
|
|
12932
|
+
const rel = relative19(base, abs);
|
|
12933
|
+
const raw = await readFile18(abs, "utf-8");
|
|
12664
12934
|
let parsed;
|
|
12665
12935
|
try {
|
|
12666
12936
|
parsed = JSON.parse(raw);
|
|
12667
12937
|
} catch {
|
|
12668
|
-
const dest2 =
|
|
12669
|
-
if (
|
|
12938
|
+
const dest2 = join35(root, "docs", rel);
|
|
12939
|
+
if (existsSync24(dest2)) {
|
|
12670
12940
|
return [`Skipped ${rel} (target already exists)`];
|
|
12671
12941
|
}
|
|
12672
12942
|
await mkdir8(dirname16(dest2), { recursive: true });
|
|
@@ -12676,10 +12946,10 @@ var convertMeta = async (abs, base, root) => {
|
|
|
12676
12946
|
];
|
|
12677
12947
|
}
|
|
12678
12948
|
const dir = dirname16(rel) === "." ? "" : dirname16(rel);
|
|
12679
|
-
const docsDir =
|
|
12680
|
-
const dest =
|
|
12949
|
+
const docsDir = join35(root, "docs", dir);
|
|
12950
|
+
const dest = join35(docsDir, "meta.ts");
|
|
12681
12951
|
const structure = parseFumadocsPages(parsed.pages);
|
|
12682
|
-
if (structure.hasSections && !
|
|
12952
|
+
if (structure.hasSections && !existsSync24(dest)) {
|
|
12683
12953
|
const self = translateFumadocsSelfMeta(parsed);
|
|
12684
12954
|
const reshape = await reshapeFumadocsGroups(structure, docsDir);
|
|
12685
12955
|
const meta2 = { ...self.meta };
|
|
@@ -12726,8 +12996,8 @@ var summarizePages = (results) => {
|
|
|
12726
12996
|
};
|
|
12727
12997
|
};
|
|
12728
12998
|
var cleanupSourceDirs = async (root) => {
|
|
12729
|
-
const docs =
|
|
12730
|
-
if (
|
|
12999
|
+
const docs = join35(root, "content", "docs");
|
|
13000
|
+
if (existsSync24(docs)) {
|
|
12731
13001
|
const remaining = await glob8(["**/*"], { cwd: docs, dot: true });
|
|
12732
13002
|
if (remaining.length > 0) {
|
|
12733
13003
|
return [
|
|
@@ -12736,8 +13006,8 @@ var cleanupSourceDirs = async (root) => {
|
|
|
12736
13006
|
}
|
|
12737
13007
|
await rm3(docs, { force: true, recursive: true });
|
|
12738
13008
|
}
|
|
12739
|
-
const content =
|
|
12740
|
-
if (
|
|
13009
|
+
const content = join35(root, "content");
|
|
13010
|
+
if (existsSync24(content)) {
|
|
12741
13011
|
const remaining = await glob8(["**/*"], { cwd: content, dot: true });
|
|
12742
13012
|
if (remaining.length === 0) {
|
|
12743
13013
|
await rm3(content, { force: true, recursive: true });
|
|
@@ -12747,8 +13017,8 @@ var cleanupSourceDirs = async (root) => {
|
|
|
12747
13017
|
};
|
|
12748
13018
|
var migrateFumadocsProject = async (root) => {
|
|
12749
13019
|
const { config, warnings: configWarnings } = await loadFumadocsConfig(root);
|
|
12750
|
-
const base =
|
|
12751
|
-
if (!
|
|
13020
|
+
const base = join35(root, SOURCE_DIR);
|
|
13021
|
+
if (!existsSync24(base)) {
|
|
12752
13022
|
await writeBlumeConfig(root, config);
|
|
12753
13023
|
return {
|
|
12754
13024
|
moved: 0,
|
|
@@ -12806,9 +13076,9 @@ var migrateFumadocsProject = async (root) => {
|
|
|
12806
13076
|
};
|
|
12807
13077
|
|
|
12808
13078
|
// src/migrate/mintlify/index.ts
|
|
12809
|
-
import { existsSync as
|
|
12810
|
-
import { mkdir as mkdir9, readFile as
|
|
12811
|
-
import { dirname as dirname17, join as
|
|
13079
|
+
import { existsSync as existsSync25 } from "node:fs";
|
|
13080
|
+
import { mkdir as mkdir9, readFile as readFile19, rename as rename4, rm as rm4, stat as stat2, writeFile as writeFile13 } from "node:fs/promises";
|
|
13081
|
+
import { dirname as dirname17, join as join36 } from "pathe";
|
|
12812
13082
|
import { glob as glob9 } from "tinyglobby";
|
|
12813
13083
|
var prune = (value) => {
|
|
12814
13084
|
if (Array.isArray(value)) {
|
|
@@ -12838,38 +13108,48 @@ var writeBlumeConfig2 = async (root, config) => {
|
|
|
12838
13108
|
|
|
12839
13109
|
export default defineConfig(${JSON.stringify(prune(config), null, 2)});
|
|
12840
13110
|
`;
|
|
12841
|
-
await
|
|
13111
|
+
await writeFile13(join36(root, "blume.config.ts"), body, "utf-8");
|
|
12842
13112
|
};
|
|
12843
|
-
var relocateAssets = async (root,
|
|
12844
|
-
const
|
|
12845
|
-
for (const ref of refs) {
|
|
12846
|
-
if (typeof ref !== "string" || !ref.startsWith("/")) {
|
|
12847
|
-
continue;
|
|
12848
|
-
}
|
|
12849
|
-
const [segment] = ref.replace(/^\/+/u, "").split("/");
|
|
12850
|
-
if (segment) {
|
|
12851
|
-
segments.add(segment);
|
|
12852
|
-
}
|
|
12853
|
-
}
|
|
13113
|
+
var relocateAssets = async (root, segments) => {
|
|
13114
|
+
const served = [];
|
|
12854
13115
|
const moved = [];
|
|
12855
13116
|
for (const segment of segments) {
|
|
12856
|
-
const source =
|
|
12857
|
-
if (!
|
|
13117
|
+
const source = join36(root, segment);
|
|
13118
|
+
if (!existsSync25(source) || segment === "public") {
|
|
12858
13119
|
continue;
|
|
12859
13120
|
}
|
|
12860
|
-
const
|
|
12861
|
-
if (
|
|
13121
|
+
const stats = await stat2(source);
|
|
13122
|
+
if (stats.isDirectory()) {
|
|
13123
|
+
served.push(segment);
|
|
12862
13124
|
continue;
|
|
12863
13125
|
}
|
|
12864
|
-
|
|
13126
|
+
const dest = join36(root, "public", segment);
|
|
13127
|
+
if (existsSync25(dest)) {
|
|
13128
|
+
continue;
|
|
13129
|
+
}
|
|
13130
|
+
await mkdir9(join36(root, "public"), { recursive: true });
|
|
12865
13131
|
await rename4(source, dest);
|
|
12866
13132
|
moved.push(segment);
|
|
12867
13133
|
}
|
|
12868
|
-
return moved;
|
|
13134
|
+
return { moved, served };
|
|
13135
|
+
};
|
|
13136
|
+
var applyRelocatedAssets = (config, assets, warnings) => {
|
|
13137
|
+
if (assets.served.length > 0) {
|
|
13138
|
+
config.content = {
|
|
13139
|
+
...config.content,
|
|
13140
|
+
assets: [
|
|
13141
|
+
...new Set([...config.content?.assets ?? [], ...assets.served])
|
|
13142
|
+
]
|
|
13143
|
+
};
|
|
13144
|
+
warnings.push(`Kept asset dir(s) in place, served via content.assets: ${assets.served.join(", ")}.`);
|
|
13145
|
+
}
|
|
13146
|
+
if (assets.moved.length > 0) {
|
|
13147
|
+
warnings.push(`Moved assets into public/: ${assets.moved.join(", ")}.`);
|
|
13148
|
+
}
|
|
12869
13149
|
};
|
|
12870
13150
|
var cleanupSnippets = async (root, kept, warnings) => {
|
|
12871
|
-
const dir =
|
|
12872
|
-
if (!
|
|
13151
|
+
const dir = join36(root, "snippets");
|
|
13152
|
+
if (!existsSync25(dir)) {
|
|
12873
13153
|
return;
|
|
12874
13154
|
}
|
|
12875
13155
|
const markdown = await glob9(["**/*.{md,mdx}"], { absolute: true, cwd: dir });
|
|
@@ -12887,30 +13167,13 @@ var cleanupSnippets = async (root, kept, warnings) => {
|
|
|
12887
13167
|
warnings.push(`Rewrote ${kept.size} component snippet import(s) to relative paths; verify they resolve.`);
|
|
12888
13168
|
}
|
|
12889
13169
|
};
|
|
12890
|
-
var assetRefs = (config) => {
|
|
12891
|
-
const refs = ["/images"];
|
|
12892
|
-
const logo = config.logo;
|
|
12893
|
-
if (typeof logo === "string") {
|
|
12894
|
-
refs.push(logo);
|
|
12895
|
-
} else if (logo) {
|
|
12896
|
-
refs.push(logo.light, logo.dark);
|
|
12897
|
-
}
|
|
12898
|
-
const favicon = config.favicon;
|
|
12899
|
-
if (typeof favicon === "string") {
|
|
12900
|
-
refs.push(favicon);
|
|
12901
|
-
} else if (favicon) {
|
|
12902
|
-
refs.push(favicon.light, favicon.dark);
|
|
12903
|
-
}
|
|
12904
|
-
refs.push(config.theme?.backgroundImage, config.theme?.backgroundImageDark);
|
|
12905
|
-
return refs;
|
|
12906
|
-
};
|
|
12907
13170
|
var migrateMintlifyProject = async (root) => {
|
|
12908
13171
|
const warnings = [];
|
|
12909
|
-
const configFile =
|
|
13172
|
+
const configFile = existsSync25(join36(root, "docs.json")) ? join36(root, "docs.json") : join36(root, "mint.json");
|
|
12910
13173
|
let config;
|
|
12911
|
-
if (
|
|
13174
|
+
if (existsSync25(configFile)) {
|
|
12912
13175
|
config = await loadMintlifyConfig(root, configFile);
|
|
12913
|
-
const spec = JSON.parse(await
|
|
13176
|
+
const spec = JSON.parse(await readFile19(configFile, "utf-8"));
|
|
12914
13177
|
const i18n = mintlifyI18n(spec);
|
|
12915
13178
|
if (i18n) {
|
|
12916
13179
|
config.i18n = i18n;
|
|
@@ -12941,7 +13204,7 @@ var migrateMintlifyProject = async (root) => {
|
|
|
12941
13204
|
const unsupported = new Set;
|
|
12942
13205
|
const keptComponents = new Set;
|
|
12943
13206
|
for (const file of files) {
|
|
12944
|
-
const raw = await
|
|
13207
|
+
const raw = await readFile19(file, "utf-8");
|
|
12945
13208
|
const result = await transformMintlifyContent(raw, {
|
|
12946
13209
|
filePath: file,
|
|
12947
13210
|
root,
|
|
@@ -12949,7 +13212,7 @@ var migrateMintlifyProject = async (root) => {
|
|
|
12949
13212
|
});
|
|
12950
13213
|
if (result.content !== raw) {
|
|
12951
13214
|
await mkdir9(dirname17(file), { recursive: true });
|
|
12952
|
-
await
|
|
13215
|
+
await writeFile13(file, result.content, "utf-8");
|
|
12953
13216
|
}
|
|
12954
13217
|
for (const key of result.removed) {
|
|
12955
13218
|
removedKeys.add(key);
|
|
@@ -12962,18 +13225,16 @@ var migrateMintlifyProject = async (root) => {
|
|
|
12962
13225
|
}
|
|
12963
13226
|
moved += 1;
|
|
12964
13227
|
}
|
|
12965
|
-
const
|
|
13228
|
+
const assets = await relocateAssets(root, assetSegments(config));
|
|
12966
13229
|
await cleanupSnippets(root, keptComponents, warnings);
|
|
12967
13230
|
if (config.content?.exclude) {
|
|
12968
13231
|
config.content.exclude = [...new Set(config.content.exclude)];
|
|
12969
13232
|
}
|
|
13233
|
+
applyRelocatedAssets(config, assets, warnings);
|
|
12970
13234
|
await writeBlumeConfig2(root, config);
|
|
12971
13235
|
if (Object.keys(variables).length > 0) {
|
|
12972
13236
|
warnings.push(`Inlined ${Object.keys(variables).length} docs.json variable(s) into content; Blume has no runtime variable substitution.`);
|
|
12973
13237
|
}
|
|
12974
|
-
if (movedAssets.length > 0) {
|
|
12975
|
-
warnings.push(`Moved assets into public/: ${movedAssets.join(", ")}.`);
|
|
12976
|
-
}
|
|
12977
13238
|
if (removedKeys.size > 0) {
|
|
12978
13239
|
warnings.push(`Dropped unsupported page frontmatter keys: ${[...removedKeys].join(", ")}.`);
|
|
12979
13240
|
}
|
|
@@ -12985,9 +13246,9 @@ var migrateMintlifyProject = async (root) => {
|
|
|
12985
13246
|
};
|
|
12986
13247
|
|
|
12987
13248
|
// src/migrate/nextra/index.ts
|
|
12988
|
-
import { existsSync as
|
|
12989
|
-
import { mkdir as mkdir10, readFile as
|
|
12990
|
-
import { basename as basename7, dirname as dirname18, extname as
|
|
13249
|
+
import { existsSync as existsSync26 } from "node:fs";
|
|
13250
|
+
import { mkdir as mkdir10, readFile as readFile20, rename as rename5, rm as rm5, writeFile as writeFile14 } from "node:fs/promises";
|
|
13251
|
+
import { basename as basename7, dirname as dirname18, extname as extname8, join as join37, relative as relative20 } from "pathe";
|
|
12991
13252
|
import { glob as glob10 } from "tinyglobby";
|
|
12992
13253
|
|
|
12993
13254
|
// src/migrate/nextra/content.ts
|
|
@@ -13222,7 +13483,7 @@ var indexFolders = (base, pageFiles, metaFiles) => {
|
|
|
13222
13483
|
}
|
|
13223
13484
|
};
|
|
13224
13485
|
for (const abs of pageFiles) {
|
|
13225
|
-
const rel =
|
|
13486
|
+
const rel = relative20(base, abs);
|
|
13226
13487
|
const dir = normalizeDir(dirname18(rel));
|
|
13227
13488
|
const slug = basename7(rel).replace(/\.mdx?$/u, "");
|
|
13228
13489
|
const folder = pagesByDir.get(dir) ?? new Map;
|
|
@@ -13231,7 +13492,7 @@ var indexFolders = (base, pageFiles, metaFiles) => {
|
|
|
13231
13492
|
registerDir(dir);
|
|
13232
13493
|
}
|
|
13233
13494
|
for (const abs of metaFiles) {
|
|
13234
|
-
registerDir(normalizeDir(dirname18(
|
|
13495
|
+
registerDir(normalizeDir(dirname18(relative20(base, abs))));
|
|
13235
13496
|
}
|
|
13236
13497
|
const childDirs = new Map;
|
|
13237
13498
|
for (const dir of allDirs) {
|
|
@@ -13269,7 +13530,7 @@ var planMetas = (metas, index) => {
|
|
|
13269
13530
|
plan.metaByDir.set(dir, conversion.folderMeta);
|
|
13270
13531
|
plan.consumedMetas.push(meta.abs);
|
|
13271
13532
|
for (const [slug, title] of Object.entries(conversion.folderTitles)) {
|
|
13272
|
-
plan.folderTitleByDir.set(normalizeDir(
|
|
13533
|
+
plan.folderTitleByDir.set(normalizeDir(join37(dir, slug)), title);
|
|
13273
13534
|
}
|
|
13274
13535
|
for (const [slug, label] of Object.entries(conversion.pageLabels)) {
|
|
13275
13536
|
const pageAbs = index.pagesByDir.get(dir)?.get(slug);
|
|
@@ -13293,19 +13554,19 @@ var planMetas = (metas, index) => {
|
|
|
13293
13554
|
return plan;
|
|
13294
13555
|
};
|
|
13295
13556
|
var movePage2 = async (abs, options) => {
|
|
13296
|
-
const rel =
|
|
13297
|
-
const dest =
|
|
13298
|
-
if (
|
|
13557
|
+
const rel = relative20(options.base, abs);
|
|
13558
|
+
const dest = join37(options.root, "docs", rel);
|
|
13559
|
+
if (existsSync26(dest)) {
|
|
13299
13560
|
return { moved: 0, removed: [], skipped: rel, unsupported: [] };
|
|
13300
13561
|
}
|
|
13301
|
-
const raw = await
|
|
13562
|
+
const raw = await readFile20(abs, "utf-8");
|
|
13302
13563
|
const text = rewriteNextraCallouts(stripNextraImports(raw));
|
|
13303
13564
|
const unsupported = unsupportedNextraComponents(text);
|
|
13304
13565
|
const parsed = frontmatter_default(text);
|
|
13305
13566
|
const { data, removed } = normalizeNextraPageMeta(parsed.data, options.overrides.get(abs) ?? {});
|
|
13306
13567
|
const content = Object.keys(data).length > 0 ? frontmatter_default.stringify(parsed.content, data) : parsed.content;
|
|
13307
13568
|
await mkdir10(dirname18(dest), { recursive: true });
|
|
13308
|
-
await
|
|
13569
|
+
await writeFile14(dest, content, "utf-8");
|
|
13309
13570
|
await rm5(abs, { force: true });
|
|
13310
13571
|
return { moved: 1, removed, skipped: null, unsupported };
|
|
13311
13572
|
};
|
|
@@ -13347,9 +13608,9 @@ var writeFolderMetas = async (root, plan) => {
|
|
|
13347
13608
|
if (Object.keys(finalMeta).length === 0) {
|
|
13348
13609
|
return;
|
|
13349
13610
|
}
|
|
13350
|
-
const dest =
|
|
13611
|
+
const dest = join37(root, "docs", dir, "meta.ts");
|
|
13351
13612
|
await mkdir10(dirname18(dest), { recursive: true });
|
|
13352
|
-
await
|
|
13613
|
+
await writeFile14(dest, `import { defineMeta } from "blume";
|
|
13353
13614
|
|
|
13354
13615
|
export default defineMeta(${JSON.stringify(finalMeta, null, 2)});
|
|
13355
13616
|
`, "utf-8");
|
|
@@ -13358,8 +13619,8 @@ export default defineMeta(${JSON.stringify(finalMeta, null, 2)});
|
|
|
13358
13619
|
var relocateUnparseableMetas = async (root, metas) => {
|
|
13359
13620
|
const warnings = [];
|
|
13360
13621
|
await Promise.all(metas.map(async ({ abs, rel }) => {
|
|
13361
|
-
const dest =
|
|
13362
|
-
if (
|
|
13622
|
+
const dest = join37(root, "docs", rel);
|
|
13623
|
+
if (existsSync26(dest)) {
|
|
13363
13624
|
warnings.push(`Skipped ${rel} (target already exists)`);
|
|
13364
13625
|
return;
|
|
13365
13626
|
}
|
|
@@ -13371,7 +13632,7 @@ var relocateUnparseableMetas = async (root, metas) => {
|
|
|
13371
13632
|
};
|
|
13372
13633
|
var buildConfig = (tabs) => tabs.length > 0 ? { navigation: { tabs }, title: "Documentation" } : { title: "Documentation" };
|
|
13373
13634
|
var migrateNextraProject = async (root) => {
|
|
13374
|
-
const sourceDir = SOURCE_DIRS.find((dir) =>
|
|
13635
|
+
const sourceDir = SOURCE_DIRS.find((dir) => existsSync26(join37(root, dir)));
|
|
13375
13636
|
if (!sourceDir) {
|
|
13376
13637
|
await writeBlumeConfig(root, { title: "Documentation" });
|
|
13377
13638
|
return {
|
|
@@ -13381,7 +13642,7 @@ var migrateNextraProject = async (root) => {
|
|
|
13381
13642
|
]
|
|
13382
13643
|
};
|
|
13383
13644
|
}
|
|
13384
|
-
const base =
|
|
13645
|
+
const base = join37(root, sourceDir);
|
|
13385
13646
|
const pageFiles = await glob10([PAGE_GLOB2], {
|
|
13386
13647
|
absolute: true,
|
|
13387
13648
|
cwd: base,
|
|
@@ -13395,9 +13656,9 @@ var migrateNextraProject = async (root) => {
|
|
|
13395
13656
|
const index = indexFolders(base, pageFiles, metaFiles);
|
|
13396
13657
|
const metas = await Promise.all(metaFiles.map(async (abs) => ({
|
|
13397
13658
|
abs,
|
|
13398
|
-
ext:
|
|
13399
|
-
raw: await
|
|
13400
|
-
rel:
|
|
13659
|
+
ext: extname8(abs),
|
|
13660
|
+
raw: await readFile20(abs, "utf-8"),
|
|
13661
|
+
rel: relative20(base, abs)
|
|
13401
13662
|
})));
|
|
13402
13663
|
const plan = planMetas(metas, index);
|
|
13403
13664
|
const moves = await Promise.all(pageFiles.map((abs) => movePage2(abs, { base, overrides: plan.pageOverrides, root })));
|
|
@@ -13422,15 +13683,15 @@ var migrateNextraProject = async (root) => {
|
|
|
13422
13683
|
};
|
|
13423
13684
|
|
|
13424
13685
|
// src/migrate/starlight/index.ts
|
|
13425
|
-
import { existsSync as
|
|
13426
|
-
import { readFile as
|
|
13427
|
-
import { join as
|
|
13686
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
13687
|
+
import { readFile as readFile22, writeFile as writeFile15 } from "node:fs/promises";
|
|
13688
|
+
import { join as join39 } from "pathe";
|
|
13428
13689
|
import { glob as glob11 } from "tinyglobby";
|
|
13429
13690
|
|
|
13430
13691
|
// src/migrate/starlight/config.ts
|
|
13431
|
-
import { existsSync as
|
|
13432
|
-
import { readFile as
|
|
13433
|
-
import { join as
|
|
13692
|
+
import { existsSync as existsSync27 } from "node:fs";
|
|
13693
|
+
import { readFile as readFile21 } from "node:fs/promises";
|
|
13694
|
+
import { join as join38 } from "pathe";
|
|
13434
13695
|
var CONFIG_FILES = [
|
|
13435
13696
|
"astro.config.mjs",
|
|
13436
13697
|
"astro.config.mts",
|
|
@@ -13461,7 +13722,7 @@ var extractStarlightOptions = (source) => {
|
|
|
13461
13722
|
return isLiteralObject(parsed) ? parsed : "unparseable";
|
|
13462
13723
|
};
|
|
13463
13724
|
var loadStarlightConfig = async (root) => {
|
|
13464
|
-
const file = CONFIG_FILES.map((name) =>
|
|
13725
|
+
const file = CONFIG_FILES.map((name) => join38(root, name)).find((path) => existsSync27(path));
|
|
13465
13726
|
if (!file) {
|
|
13466
13727
|
return {
|
|
13467
13728
|
options: {},
|
|
@@ -13470,7 +13731,7 @@ var loadStarlightConfig = async (root) => {
|
|
|
13470
13731
|
]
|
|
13471
13732
|
};
|
|
13472
13733
|
}
|
|
13473
|
-
const source = await
|
|
13734
|
+
const source = await readFile21(file, "utf-8");
|
|
13474
13735
|
const result = extractStarlightOptions(source);
|
|
13475
13736
|
if (result === "missing") {
|
|
13476
13737
|
return {
|
|
@@ -13868,7 +14129,7 @@ var starlightI18n = (options) => {
|
|
|
13868
14129
|
// src/migrate/starlight/index.ts
|
|
13869
14130
|
var CONTENT_DIR = "src/content/docs";
|
|
13870
14131
|
var transformPage = async (file) => {
|
|
13871
|
-
const raw = await
|
|
14132
|
+
const raw = await readFile22(file, "utf-8");
|
|
13872
14133
|
let text = stripStarlightImports(raw);
|
|
13873
14134
|
text = rewriteStarlightAsides(text);
|
|
13874
14135
|
text = rewriteStarlightComponents(text);
|
|
@@ -13878,7 +14139,7 @@ var transformPage = async (file) => {
|
|
|
13878
14139
|
const { data, removed } = normalizeStarlightPageMeta(parsed.data);
|
|
13879
14140
|
const content = Object.keys(data).length > 0 ? frontmatter_default.stringify(parsed.content, data) : parsed.content;
|
|
13880
14141
|
if (content !== raw) {
|
|
13881
|
-
await
|
|
14142
|
+
await writeFile15(file, content, "utf-8");
|
|
13882
14143
|
}
|
|
13883
14144
|
return { aliased, removed, unsupported };
|
|
13884
14145
|
};
|
|
@@ -13890,8 +14151,8 @@ var migrateStarlightProject = async (root) => {
|
|
|
13890
14151
|
config.i18n = i18n;
|
|
13891
14152
|
warnings.push(`Mapped ${i18n.locales.length} locale(s) to i18n (default: ${i18n.defaultLocale}); review the locale labels.`);
|
|
13892
14153
|
}
|
|
13893
|
-
const base =
|
|
13894
|
-
if (!
|
|
14154
|
+
const base = join39(root, CONTENT_DIR);
|
|
14155
|
+
if (!existsSync28(base)) {
|
|
13895
14156
|
await writeBlumeConfig(root, config);
|
|
13896
14157
|
return {
|
|
13897
14158
|
moved: 0,
|
|
@@ -13979,10 +14240,10 @@ var migrateCommand = defineCommand8({
|
|
|
13979
14240
|
});
|
|
13980
14241
|
|
|
13981
14242
|
// src/cli/commands/preview.ts
|
|
13982
|
-
import { existsSync as
|
|
14243
|
+
import { existsSync as existsSync29 } from "node:fs";
|
|
13983
14244
|
import { preview } from "astro";
|
|
13984
14245
|
import { defineCommand as defineCommand9 } from "citty";
|
|
13985
|
-
import { join as
|
|
14246
|
+
import { join as join40 } from "pathe";
|
|
13986
14247
|
var previewCommand = defineCommand9({
|
|
13987
14248
|
args: {
|
|
13988
14249
|
host: { description: "Network host to bind.", type: "string" },
|
|
@@ -13996,7 +14257,7 @@ var previewCommand = defineCommand9({
|
|
|
13996
14257
|
const root = process.cwd();
|
|
13997
14258
|
const { config } = await loadConfig(root);
|
|
13998
14259
|
const context = resolveProjectContext(root, config);
|
|
13999
|
-
if (!
|
|
14260
|
+
if (!existsSync29(join40(context.outDir, "astro.config.mjs"))) {
|
|
14000
14261
|
logger.error("No build found. Run `blume build` first.");
|
|
14001
14262
|
process.exit(1);
|
|
14002
14263
|
}
|
|
@@ -14005,7 +14266,7 @@ var previewCommand = defineCommand9({
|
|
|
14005
14266
|
root: context.outDir,
|
|
14006
14267
|
server: {
|
|
14007
14268
|
host: args.host ?? false,
|
|
14008
|
-
port:
|
|
14269
|
+
port: parsePort(args.port)
|
|
14009
14270
|
}
|
|
14010
14271
|
});
|
|
14011
14272
|
}
|
|
@@ -14014,7 +14275,7 @@ var previewCommand = defineCommand9({
|
|
|
14014
14275
|
// src/cli/commands/sync.ts
|
|
14015
14276
|
import { rm as rm6 } from "node:fs/promises";
|
|
14016
14277
|
import { defineCommand as defineCommand10 } from "citty";
|
|
14017
|
-
import { join as
|
|
14278
|
+
import { join as join41 } from "pathe";
|
|
14018
14279
|
var syncCommand = defineCommand10({
|
|
14019
14280
|
args: {
|
|
14020
14281
|
force: {
|
|
@@ -14036,7 +14297,7 @@ var syncCommand = defineCommand10({
|
|
|
14036
14297
|
if (args.force) {
|
|
14037
14298
|
const { config } = await loadConfig(root);
|
|
14038
14299
|
const context = resolveProjectContext(root, config);
|
|
14039
|
-
await rm6(
|
|
14300
|
+
await rm6(join41(context.outDir, "cache"), { force: true, recursive: true });
|
|
14040
14301
|
logger.info("Cleared source cache.");
|
|
14041
14302
|
}
|
|
14042
14303
|
await prepareProject({
|
|
@@ -14051,13 +14312,13 @@ var syncCommand = defineCommand10({
|
|
|
14051
14312
|
});
|
|
14052
14313
|
|
|
14053
14314
|
// src/cli/commands/validate.ts
|
|
14054
|
-
import { existsSync as
|
|
14315
|
+
import { existsSync as existsSync31 } from "node:fs";
|
|
14055
14316
|
import { defineCommand as defineCommand11 } from "citty";
|
|
14056
|
-
import { join as
|
|
14317
|
+
import { join as join43 } from "pathe";
|
|
14057
14318
|
|
|
14058
14319
|
// src/core/links.ts
|
|
14059
|
-
import { existsSync as
|
|
14060
|
-
import { join as
|
|
14320
|
+
import { existsSync as existsSync30 } from "node:fs";
|
|
14321
|
+
import { basename as basename8, join as join42 } from "pathe";
|
|
14061
14322
|
var HTTP = /^https?:\/\//iu;
|
|
14062
14323
|
var PROTOCOL_RELATIVE = /^\/\//u;
|
|
14063
14324
|
var SCHEME = /^[a-z][a-z0-9+.-]*:/iu;
|
|
@@ -14069,9 +14330,21 @@ var STATUS_NOT_FOUND = 404;
|
|
|
14069
14330
|
var STATUS_GONE = 410;
|
|
14070
14331
|
var STATUS_METHOD_NOT_ALLOWED = 405;
|
|
14071
14332
|
var STATUS_NOT_IMPLEMENTED = 501;
|
|
14072
|
-
var
|
|
14333
|
+
var assetIsPresent = (resolved, ctx) => {
|
|
14334
|
+
if (ctx.publicDir && existsSync30(join42(ctx.publicDir, resolved))) {
|
|
14335
|
+
return true;
|
|
14336
|
+
}
|
|
14337
|
+
return ctx.assetMounts.some((mount) => (resolved === mount.url || resolved.startsWith(`${mount.url}/`)) && existsSync30(join42(mount.dir, resolved.slice(mount.url.length))));
|
|
14338
|
+
};
|
|
14339
|
+
var isIndexPage = (page2) => {
|
|
14340
|
+
const ref = page2.source?.ref ?? page2.sourcePath ?? "";
|
|
14341
|
+
return /^index\.(?:md|mdx)$/iu.test(basename8(ref));
|
|
14342
|
+
};
|
|
14343
|
+
var resolveRelative = (pageRoute, target, isIndex) => {
|
|
14073
14344
|
const segments = pageRoute.split("/").filter(Boolean);
|
|
14074
|
-
|
|
14345
|
+
if (!isIndex) {
|
|
14346
|
+
segments.pop();
|
|
14347
|
+
}
|
|
14075
14348
|
for (const part of target.split("/")) {
|
|
14076
14349
|
if (part === "" || part === ".") {
|
|
14077
14350
|
continue;
|
|
@@ -14113,13 +14386,20 @@ var checkAnchor = (route, fragment, site, ctx) => {
|
|
|
14113
14386
|
};
|
|
14114
14387
|
};
|
|
14115
14388
|
var checkPathLink = (resolved, fragment, target, site, ctx) => {
|
|
14389
|
+
const route = toRoute(resolved);
|
|
14390
|
+
if (ctx.routes.has(route)) {
|
|
14391
|
+
return fragment ? checkAnchor(route, fragment, site, ctx) : null;
|
|
14392
|
+
}
|
|
14393
|
+
if (ctx.redirects.has(route)) {
|
|
14394
|
+
return null;
|
|
14395
|
+
}
|
|
14116
14396
|
if (FILE_EXT.test(resolved) && !DOC_EXT.test(resolved)) {
|
|
14117
|
-
if (ctx
|
|
14118
|
-
return "asset-unchecked";
|
|
14119
|
-
}
|
|
14120
|
-
if (existsSync28(join38(ctx.publicDir, resolved))) {
|
|
14397
|
+
if (assetIsPresent(resolved, ctx)) {
|
|
14121
14398
|
return null;
|
|
14122
14399
|
}
|
|
14400
|
+
if (ctx.publicDir === null && ctx.assetMounts.length === 0) {
|
|
14401
|
+
return "asset-unchecked";
|
|
14402
|
+
}
|
|
14123
14403
|
return {
|
|
14124
14404
|
...site,
|
|
14125
14405
|
code: "BLUME_BROKEN_ASSET",
|
|
@@ -14128,13 +14408,6 @@ var checkPathLink = (resolved, fragment, target, site, ctx) => {
|
|
|
14128
14408
|
suggestion: `Add the file at public${resolved} or fix the link.`
|
|
14129
14409
|
};
|
|
14130
14410
|
}
|
|
14131
|
-
const route = toRoute(resolved);
|
|
14132
|
-
if (ctx.routes.has(route)) {
|
|
14133
|
-
return fragment ? checkAnchor(route, fragment, site, ctx) : null;
|
|
14134
|
-
}
|
|
14135
|
-
if (ctx.redirects.has(route)) {
|
|
14136
|
-
return null;
|
|
14137
|
-
}
|
|
14138
14411
|
return {
|
|
14139
14412
|
...site,
|
|
14140
14413
|
code: "BLUME_BROKEN_LINK",
|
|
@@ -14243,12 +14516,13 @@ var classifyLink = (page2, link, ctx, onExternal) => {
|
|
|
14243
14516
|
if (rawPath === "") {
|
|
14244
14517
|
return fragment ? checkAnchor(page2.route, fragment, site, ctx) : null;
|
|
14245
14518
|
}
|
|
14246
|
-
const resolved = rawPath.startsWith("/") ? rawPath : resolveRelative(page2.route, rawPath);
|
|
14519
|
+
const resolved = rawPath.startsWith("/") ? rawPath : resolveRelative(page2.route, rawPath, isIndexPage(page2));
|
|
14247
14520
|
return checkPathLink(resolved, fragment, target, site, ctx);
|
|
14248
14521
|
};
|
|
14249
14522
|
var validateLinks = async (graph, options) => {
|
|
14250
14523
|
const ctx = {
|
|
14251
14524
|
anchors: buildAnchorIndex(graph.pages),
|
|
14525
|
+
assetMounts: options.assetMounts ?? [],
|
|
14252
14526
|
publicDir: options.publicDir,
|
|
14253
14527
|
redirects: new Set((options.redirects ?? []).map((redirect) => toRoute(redirect.from))),
|
|
14254
14528
|
routes: new Set(graph.routes.keys())
|
|
@@ -14305,10 +14579,11 @@ var validateCommand = defineCommand11({
|
|
|
14305
14579
|
try {
|
|
14306
14580
|
const project = await scanProject(root, { mode: "build" });
|
|
14307
14581
|
diagnostics.push(...project.diagnostics);
|
|
14308
|
-
const publicDir =
|
|
14582
|
+
const publicDir = join43(root, "public");
|
|
14309
14583
|
diagnostics.push(...await validateLinks(project.graph, {
|
|
14584
|
+
assetMounts: resolveAssetMounts(root, project.config.content.assets),
|
|
14310
14585
|
checkExternal: Boolean(args.external),
|
|
14311
|
-
publicDir:
|
|
14586
|
+
publicDir: existsSync31(publicDir) ? publicDir : null,
|
|
14312
14587
|
redirects: project.config.redirects
|
|
14313
14588
|
}));
|
|
14314
14589
|
} catch (error) {
|
|
@@ -14322,6 +14597,7 @@ var validateCommand = defineCommand11({
|
|
|
14322
14597
|
if (args.json) {
|
|
14323
14598
|
const hadErrors2 = reportDiagnosticsJson(diagnostics, root);
|
|
14324
14599
|
if (hadErrors2 || Boolean(args.strict) && diagnostics.length > 0) {
|
|
14600
|
+
await flushStdout();
|
|
14325
14601
|
process.exit(1);
|
|
14326
14602
|
}
|
|
14327
14603
|
return;
|
|
@@ -14368,5 +14644,5 @@ process.on("unhandledRejection", (error) => {
|
|
|
14368
14644
|
});
|
|
14369
14645
|
runMain(main);
|
|
14370
14646
|
|
|
14371
|
-
//# debugId=
|
|
14647
|
+
//# debugId=114B8B7438537BD664756E2164756E21
|
|
14372
14648
|
//# sourceMappingURL=index.js.map
|