blume 1.4.3 → 1.5.1
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/CHANGELOG.md +32 -0
- package/README.md +16 -12
- package/dist/cli/index.js +1784 -633
- package/dist/cli/index.js.map +111 -106
- package/dist/types/ai/component-markdown.d.ts +14 -4
- package/dist/types/core/config-input.d.ts +80 -28
- package/dist/types/core/config.d.ts +2 -1
- package/dist/types/core/data.d.ts +19 -3
- package/dist/types/core/diagnostics.d.ts +5 -1
- package/dist/types/core/i18n-ui.d.ts +12 -0
- package/dist/types/core/schema.d.ts +112 -15
- package/dist/types/core/sources/types.d.ts +3 -1
- package/dist/types/core/standard-schema.d.ts +7 -3
- package/dist/types/core/types.d.ts +43 -2
- package/dist/types/core/ui-packs/index.d.ts +9 -1
- package/dist/types/openapi/references.d.ts +6 -5
- package/dist/types/seo/x-handle.d.ts +3 -2
- package/dist/types/theme/fonts.d.ts +11 -2
- package/docs/advanced/api-reference.mdx +8 -6
- package/docs/advanced/custom-pages.mdx +5 -1
- package/docs/configuration/index.mdx +1 -1
- package/docs/configuration/search.mdx +2 -0
- package/docs/configuration/seo.mdx +1 -1
- package/docs/configuration/theming.mdx +4 -2
- package/docs/content/i18n.mdx +1 -1
- package/docs/content/meta.mdx +2 -1
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +35 -1
- package/docs/content/versioning.mdx +106 -0
- package/docs/reference/cli.mdx +2 -1
- package/docs/reference/frontmatter.mdx +3 -0
- package/package.json +3 -1
- package/skills/blume-migrate/SKILL.md +2 -2
- package/skills/blume-migrate/references/docusaurus.md +1 -1
- package/skills/blume-migrate/references/fumadocs.md +1 -1
- package/skills/blume-migrate/references/mintlify.md +1 -1
- package/src/ai/agent-readability.ts +37 -10
- package/src/ai/ask-context.ts +5 -1
- package/src/ai/ask.ts +10 -1
- package/src/ai/component-markdown.ts +80 -43
- package/src/ai/llms.ts +40 -16
- package/src/ai/mcp/data.ts +48 -12
- package/src/ai/mcp/discovery.ts +28 -11
- package/src/ai/mcp/server.ts +183 -38
- package/src/ai/mcp/tools.ts +3 -3
- package/src/ai/skills.ts +32 -9
- package/src/ai/visibility.ts +2 -2
- package/src/astro/component-slots.ts +2 -0
- package/src/astro/examples.ts +6 -2
- package/src/astro/generate.ts +64 -34
- package/src/astro/integration.ts +13 -2
- package/src/astro/islands.ts +16 -9
- package/src/astro/templates.ts +181 -40
- package/src/audit/agent.ts +2 -2
- package/src/audit/checks/content.ts +26 -11
- package/src/audit/checks/dns-aid.ts +3 -0
- package/src/audit/checks/indexability.ts +24 -6
- package/src/audit/checks/llms.ts +9 -4
- package/src/audit/checks/network.ts +2 -0
- package/src/audit/checks/social.ts +18 -10
- package/src/audit/crawl.ts +37 -9
- package/src/audit/report.ts +20 -19
- package/src/audit/run.ts +5 -2
- package/src/audit/snapshot.ts +2 -4
- package/src/audit/types.ts +25 -3
- package/src/blume-modules.d.ts +5 -1
- package/src/cli/commands/audit.ts +9 -4
- package/src/cli/commands/build.ts +15 -9
- package/src/cli/commands/dev.ts +2 -0
- package/src/cli/commands/doctor.ts +2 -0
- package/src/cli/commands/eval.ts +7 -3
- package/src/cli/commands/init.ts +9 -9
- package/src/cli/commands/mcp-stdio.ts +3 -0
- package/src/cli/commands/translate.ts +14 -3
- package/src/cli/commands/version.ts +85 -0
- package/src/cli/dev-lock.ts +31 -10
- package/src/cli/eject-scripts.ts +17 -2
- package/src/cli/index.ts +2 -0
- package/src/cli/init/questions.ts +1 -1
- package/src/cli/init/scaffold.ts +22 -15
- package/src/cli/internal-error.ts +1 -0
- package/src/components/content/auto-type-table.ts +3 -0
- package/src/components/content/diff.ts +9 -5
- package/src/components/content/github-info.ts +2 -0
- package/src/components/islands/ask-ai.tsx +33 -25
- package/src/components/islands/hooks.ts +5 -1
- package/src/components/islands/webmcp.ts +49 -12
- package/src/components/layout/Fonts.astro +23 -3
- package/src/components/layout/Header.astro +25 -1
- package/src/components/layout/NavSelector.astro +11 -2
- package/src/components/layout/NavTree.astro +4 -2
- package/src/components/layout/PageLayout.astro +72 -3
- package/src/components/layout/ReferenceLayout.astro +2 -1
- package/src/components/layout/RootLayout.astro +20 -1
- package/src/components/layout/Search.astro +77 -13
- package/src/components/layout/VersionBanner.astro +39 -0
- package/src/components/layout/analytics-client.ts +8 -5
- package/src/components/layout/hydration-hint.ts +1 -1
- package/src/components/layout/nav-utils.ts +1 -4
- package/src/components/layout/overrides.ts +25 -12
- package/src/components/layout/search/algolia.ts +18 -5
- package/src/components/layout/search/endpoint.ts +3 -0
- package/src/components/layout/search/flexsearch.ts +23 -7
- package/src/components/layout/search/orama-cloud.ts +1 -1
- package/src/components/layout/search/orama.ts +4 -1
- package/src/components/layout/search/pagefind.ts +2 -0
- package/src/components/layout/search/types.ts +13 -1
- package/src/components/layout/search/typesense.ts +19 -3
- package/src/components/openapi/ApiOverview.astro +32 -6
- package/src/components/openapi/AsyncApiOperation.astro +237 -0
- package/src/components/openapi/Bindings.astro +89 -0
- package/src/components/openapi/MethodBadge.astro +3 -0
- package/src/components/openapi/Operation.astro +7 -2
- package/src/components/openapi/PanelTabs.astro +131 -0
- package/src/components/openapi/ParametersTable.astro +2 -0
- package/src/components/openapi/RequestPanel.astro +12 -119
- package/src/components/openapi/async-snippets.ts +174 -0
- package/src/components/openapi/async.ts +348 -0
- package/src/components/openapi/helpers.ts +52 -20
- package/src/components/openapi/security.ts +102 -29
- package/src/components/openapi/snippets.ts +11 -11
- package/src/core/component-overrides.ts +28 -23
- package/src/core/config-input.ts +89 -28
- package/src/core/config.ts +20 -7
- package/src/core/content.ts +3 -1
- package/src/core/data.ts +19 -3
- package/src/core/define-components.ts +5 -0
- package/src/core/diagnostics.ts +46 -38
- package/src/core/frontmatter.ts +33 -7
- package/src/core/graph.ts +137 -53
- package/src/core/i18n-ui.ts +15 -0
- package/src/core/i18n.ts +16 -8
- package/src/core/last-modified.ts +49 -0
- package/src/core/load-module.ts +1 -0
- package/src/core/manifest.ts +92 -3
- package/src/core/meta.ts +44 -14
- package/src/core/nav-diagnostics.ts +3 -3
- package/src/core/navigation.ts +247 -67
- package/src/core/project-graph.ts +26 -3
- package/src/core/schema.ts +214 -68
- package/src/core/sources/assets.ts +2 -0
- package/src/core/sources/cache.ts +6 -0
- package/src/core/sources/github-releases.ts +39 -31
- package/src/core/sources/mdx-remote.ts +4 -0
- package/src/core/sources/normalize.ts +67 -20
- package/src/core/sources/notion.ts +49 -17
- package/src/core/sources/portable-text.ts +32 -11
- package/src/core/sources/sanity.ts +68 -14
- package/src/core/sources/types.ts +4 -0
- package/src/core/sources/watch.ts +1 -1
- package/src/core/standard-schema.ts +9 -3
- package/src/core/text-width.ts +26 -0
- package/src/core/tsconfig-aliases.ts +9 -5
- package/src/core/types.ts +45 -2
- package/src/core/ui-packs/index.ts +9 -1
- package/src/core/version-cut.ts +301 -0
- package/src/core/version.ts +2 -0
- package/src/core/versions.ts +170 -0
- package/src/deploy/adapter-output.ts +5 -2
- package/src/deploy/cloudflare-negotiation.ts +25 -10
- package/src/deploy/sitemap.ts +33 -1
- package/src/deploy/vercel-negotiation.ts +45 -18
- package/src/eval/report.ts +4 -4
- package/src/eval/run.ts +2 -2
- package/src/eval/schema.ts +1 -1
- package/src/markdown/base-links.ts +6 -6
- package/src/markdown/directives.ts +7 -1
- package/src/markdown/heading-anchors.ts +17 -6
- package/src/markdown/index.ts +73 -24
- package/src/markdown/inline-code.ts +14 -2
- package/src/markdown/language-icon.ts +6 -2
- package/src/markdown/mdast.ts +18 -4
- package/src/markdown/package-commands.ts +6 -8
- package/src/markdown/table-wrap.ts +4 -1
- package/src/markdown/twoslash.ts +2 -0
- package/src/og/card.ts +33 -12
- package/src/og/derive.ts +43 -27
- package/src/openapi/asyncapi.ts +366 -0
- package/src/openapi/model.ts +126 -57
- package/src/openapi/parse.ts +97 -5
- package/src/openapi/references.ts +12 -10
- package/src/openapi/render-mdx.ts +73 -34
- package/src/openapi/scalar.ts +6 -8
- package/src/openapi/source.ts +98 -28
- package/src/registry/eject.ts +7 -2
- package/src/search/documents.ts +25 -5
- package/src/search/facets.ts +7 -5
- package/src/search/orama-index.ts +66 -20
- package/src/search/popular.ts +10 -5
- package/src/search/providers.ts +2 -2
- package/src/search/sync/index.ts +2 -0
- package/src/search/sync/typesense.ts +4 -2
- package/src/seo/jsonld.ts +24 -6
- package/src/seo/x-handle.ts +8 -3
- package/src/theme/chrome-icons.ts +7 -2
- package/src/theme/entry.ts +24 -2
- package/src/theme/fonts.ts +83 -7
- package/src/theme/icons.ts +4 -2
- package/src/theme/palette.ts +22 -14
- package/src/translate/meta.ts +15 -6
- package/src/translate/report.ts +9 -5
- package/src/translate/run.ts +10 -4
- package/src/translate/validate.ts +52 -17
- package/src/translate/work-list.ts +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
4
4
|
|
|
5
5
|
// src/cli/index.ts
|
|
6
|
-
import { defineCommand as
|
|
6
|
+
import { defineCommand as defineCommand16, runMain } from "citty";
|
|
7
7
|
|
|
8
8
|
// src/core/version.ts
|
|
9
9
|
import { readFileSync } from "node:fs";
|
|
@@ -297,7 +297,7 @@ var DOCS_DEPLOYMENT = "/docs/deployment";
|
|
|
297
297
|
var DOCS_REFERENCE_CLI = "/docs/reference/cli";
|
|
298
298
|
var DOCS_CONTENT_SOURCES = "/docs/content/sources";
|
|
299
299
|
var DOCS_CONTENT_NAVIGATION = "/docs/content/navigation";
|
|
300
|
-
var DOCS_PATHS = {
|
|
300
|
+
var DOCS_PATHS = new Map(Object.entries({
|
|
301
301
|
BLUME_ADAPTER_REQUIRED: DOCS_DEPLOYMENT,
|
|
302
302
|
BLUME_ASSETS_UNCHECKED: DOCS_REFERENCE_CLI,
|
|
303
303
|
BLUME_ASSET_FETCH_FAILED: DOCS_CONTENT_SOURCES,
|
|
@@ -320,6 +320,7 @@ var DOCS_PATHS = {
|
|
|
320
320
|
BLUME_NAV_MISSING_PAGE: DOCS_CONTENT_NAVIGATION,
|
|
321
321
|
BLUME_NODE_VERSION: "/docs/quickstart",
|
|
322
322
|
BLUME_SERVER_FEATURE_REQUIRED: DOCS_DEPLOYMENT,
|
|
323
|
+
BLUME_SIDEBAR_DISPLAY_IGNORED: DOCS_CONTENT_NAVIGATION,
|
|
323
324
|
BLUME_SOURCE_FETCH_FAILED: DOCS_CONTENT_SOURCES,
|
|
324
325
|
BLUME_SOURCE_MISCONFIGURED: DOCS_CONTENT_SOURCES,
|
|
325
326
|
BLUME_SOURCE_OFFLINE: DOCS_CONTENT_SOURCES,
|
|
@@ -327,16 +328,17 @@ var DOCS_PATHS = {
|
|
|
327
328
|
BLUME_SOURCE_UNAVAILABLE: DOCS_CONTENT_SOURCES,
|
|
328
329
|
BLUME_UNKNOWN_COMPONENT: "/docs/configuration/customization",
|
|
329
330
|
BLUME_UNKNOWN_ICON: DOCS_CONTENT_NAVIGATION
|
|
330
|
-
};
|
|
331
|
+
}));
|
|
331
332
|
var resolveDocsUrl = (code) => {
|
|
332
|
-
const path = DOCS_PATHS
|
|
333
|
+
const path = DOCS_PATHS.get(code);
|
|
333
334
|
return path ? `${DOCS_BASE}${path}` : undefined;
|
|
334
335
|
};
|
|
335
336
|
var enrichDiagnostic = (diagnostic) => diagnostic.docsUrl ? diagnostic : { ...diagnostic, docsUrl: resolveDocsUrl(diagnostic.code) };
|
|
336
337
|
var REGEXP_SPECIAL = /[$()*+.?[\\\]^{|}]/gu;
|
|
337
338
|
var escapeRegExp = (value) => value.replaceAll(REGEXP_SPECIAL, String.raw`\$&`);
|
|
339
|
+
var isKeySegment = (segment) => typeof segment === "string";
|
|
338
340
|
var stepSegment = (source, segment, cursor) => {
|
|
339
|
-
if (
|
|
341
|
+
if (!isKeySegment(segment)) {
|
|
340
342
|
return { index: -1, next: cursor, stop: false };
|
|
341
343
|
}
|
|
342
344
|
const matcher = new RegExp(`(?<![\\w$])${escapeRegExp(segment)}\\s*[:=]`, "gu");
|
|
@@ -1298,10 +1300,10 @@ var GLYPH = {
|
|
|
1298
1300
|
warning: "⚠"
|
|
1299
1301
|
};
|
|
1300
1302
|
var PREVIEW = 3;
|
|
1301
|
-
var
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1303
|
+
var TIER_FLAGS = [
|
|
1304
|
+
{ flag: "--external", tier: "external" },
|
|
1305
|
+
{ flag: "--url <origin>", tier: "network" }
|
|
1306
|
+
];
|
|
1305
1307
|
var rollup = (diagnostics) => {
|
|
1306
1308
|
const groups = new Map;
|
|
1307
1309
|
for (const diagnostic of diagnostics) {
|
|
@@ -1318,12 +1320,13 @@ var rollup = (diagnostics) => {
|
|
|
1318
1320
|
warning: 1
|
|
1319
1321
|
};
|
|
1320
1322
|
const checks = [...groups.entries()].map(([id, findings]) => {
|
|
1321
|
-
const
|
|
1323
|
+
const checkId = id;
|
|
1324
|
+
const { category, severity, title } = checkMeta(checkId);
|
|
1322
1325
|
return {
|
|
1323
1326
|
category,
|
|
1324
1327
|
count: findings.length,
|
|
1325
1328
|
findings,
|
|
1326
|
-
id,
|
|
1329
|
+
id: checkId,
|
|
1327
1330
|
severity,
|
|
1328
1331
|
title
|
|
1329
1332
|
};
|
|
@@ -1335,9 +1338,9 @@ var rollup = (diagnostics) => {
|
|
|
1335
1338
|
}
|
|
1336
1339
|
return checks.toSorted((a, b) => (worst.get(a.category) ?? 0) - (worst.get(b.category) ?? 0) || a.category.localeCompare(b.category) || order[a.severity] - order[b.severity] || b.count - a.count);
|
|
1337
1340
|
};
|
|
1338
|
-
var skippedTiers = (tiers) =>
|
|
1341
|
+
var skippedTiers = (tiers) => TIER_FLAGS.filter(({ tier }) => !tiers[tier]).map(({ flag, tier }) => {
|
|
1339
1342
|
const label = CHECKS.filter((check) => check.tier === tier).length;
|
|
1340
|
-
return ` ${colors2.dim(`⊘ ${tier.padEnd(12)} skipped — pass ${
|
|
1343
|
+
return ` ${colors2.dim(`⊘ ${tier.padEnd(12)} skipped — pass ${flag} (${label} checks)`)}`;
|
|
1341
1344
|
});
|
|
1342
1345
|
var activeChecks = (tiers) => CHECKS.filter((check) => tiers[check.tier]).length;
|
|
1343
1346
|
var auditCount = (result) => activeChecks(result.tiers) * result.pages;
|
|
@@ -1721,6 +1724,9 @@ var assetChecks = {
|
|
|
1721
1724
|
tier: "static"
|
|
1722
1725
|
};
|
|
1723
1726
|
|
|
1727
|
+
// src/audit/checks/content.ts
|
|
1728
|
+
import stringWidth from "string-width";
|
|
1729
|
+
|
|
1724
1730
|
// src/core/frontmatter.ts
|
|
1725
1731
|
import baseMatter from "gray-matter";
|
|
1726
1732
|
import { dump, load } from "js-yaml";
|
|
@@ -1746,17 +1752,21 @@ var opensWithThematicBreak = (input) => {
|
|
|
1746
1752
|
return !input.includes(`
|
|
1747
1753
|
---`, 1);
|
|
1748
1754
|
};
|
|
1749
|
-
var passthrough = (input) =>
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1755
|
+
var passthrough = (input) => {
|
|
1756
|
+
const file = {
|
|
1757
|
+
content: input,
|
|
1758
|
+
data: {},
|
|
1759
|
+
excerpt: "",
|
|
1760
|
+
isEmpty: false,
|
|
1761
|
+
language: "",
|
|
1762
|
+
matter: "",
|
|
1763
|
+
orig: input,
|
|
1764
|
+
stringify: () => input
|
|
1765
|
+
};
|
|
1766
|
+
return file;
|
|
1767
|
+
};
|
|
1768
|
+
var isStringInput = (input) => typeof input === "string";
|
|
1769
|
+
var matter = Object.assign((input, options) => isStringInput(input) && opensWithThematicBreak(input) ? passthrough(input) : baseMatter(input, withYamlEngine(options)), baseMatter, {
|
|
1760
1770
|
read: (filepath, options) => baseMatter.read(filepath, withYamlEngine(options)),
|
|
1761
1771
|
stringify: (file, data, options) => baseMatter.stringify(file, data, withYamlEngine(options))
|
|
1762
1772
|
});
|
|
@@ -1776,10 +1786,12 @@ var DEFAULT_THRESHOLDS = {
|
|
|
1776
1786
|
};
|
|
1777
1787
|
|
|
1778
1788
|
// src/audit/checks/content.ts
|
|
1789
|
+
var WHITESPACE = /\s+/gu;
|
|
1790
|
+
var isDateValue = (value) => typeof value === "string" || value instanceof Date;
|
|
1779
1791
|
var frontmatterDate = (source) => {
|
|
1780
1792
|
try {
|
|
1781
1793
|
const { date } = frontmatter_default(source).data;
|
|
1782
|
-
if (
|
|
1794
|
+
if (!isDateValue(date)) {
|
|
1783
1795
|
return null;
|
|
1784
1796
|
}
|
|
1785
1797
|
const parsed = date instanceof Date ? date : new Date(date);
|
|
@@ -1800,9 +1812,10 @@ var titleChecks = (context, page) => {
|
|
|
1800
1812
|
if (page.titles.length > 1) {
|
|
1801
1813
|
found.push(finding("BLUME_AUDIT_TITLE_MULTIPLE", pageSite(context, page), `Page has ${page.titles.length} <title> tags; search engines use only the first.`));
|
|
1802
1814
|
}
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1815
|
+
const width = stringWidth(title.replaceAll(WHITESPACE, " "));
|
|
1816
|
+
if (width > titleMax || width < titleMin) {
|
|
1817
|
+
const direction = width > titleMax ? "long" : "short";
|
|
1818
|
+
found.push(finding("BLUME_AUDIT_TITLE_LENGTH", pageSite(context, page, ["title"]), `Title renders ${width} columns wide — too ${direction} (aim for ${titleMin}–${titleMax}).`));
|
|
1806
1819
|
}
|
|
1807
1820
|
return found;
|
|
1808
1821
|
};
|
|
@@ -1821,9 +1834,10 @@ var descriptionChecks = (context, page) => {
|
|
|
1821
1834
|
if (page.descriptions.length > 1) {
|
|
1822
1835
|
found.push(finding("BLUME_AUDIT_DESCRIPTION_MULTIPLE", pageSite(context, page), `Page has ${page.descriptions.length} meta description tags.`));
|
|
1823
1836
|
}
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1837
|
+
const width = stringWidth(description.replaceAll(WHITESPACE, " "));
|
|
1838
|
+
if (width > descriptionMax || width < descriptionMin) {
|
|
1839
|
+
const direction = width > descriptionMax ? "long" : "short";
|
|
1840
|
+
found.push(finding("BLUME_AUDIT_DESCRIPTION_LENGTH", pageSite(context, page, ["description"]), `Meta description renders ${width} columns wide — too ${direction} (aim for ${descriptionMin}–${descriptionMax}).`));
|
|
1827
1841
|
}
|
|
1828
1842
|
return found;
|
|
1829
1843
|
};
|
|
@@ -2236,7 +2250,13 @@ var canonicalChecks = (context, page) => {
|
|
|
2236
2250
|
if (redirect) {
|
|
2237
2251
|
found.push(finding("BLUME_AUDIT_CANONICAL_BAD_TARGET", pageSite(context, page, ["seo", "canonical"]), `Canonical points at ${target}, which is a redirect to ${redirect.to}.`));
|
|
2238
2252
|
} else if (context.byUrl.has(target)) {
|
|
2239
|
-
|
|
2253
|
+
const version = page.route?.version;
|
|
2254
|
+
const archived = version ? context.project.config.versions?.archived.find((entry) => entry.id === version) : undefined;
|
|
2255
|
+
const latestAlternate = page.route?.versionAlternates.find((alternate) => alternate.version === "");
|
|
2256
|
+
const intentional = archived?.canonical === "latest" && latestAlternate !== undefined && normalizePath(latestAlternate.path) === target;
|
|
2257
|
+
if (!intentional) {
|
|
2258
|
+
found.push(finding("BLUME_AUDIT_CANONICAL_NOT_SELF", pageSite(context, page, ["seo", "canonical"]), `Page declares ${target} as its canonical, so it will not be indexed itself.`));
|
|
2259
|
+
}
|
|
2240
2260
|
} else {
|
|
2241
2261
|
found.push(finding("BLUME_AUDIT_CANONICAL_BAD_TARGET", pageSite(context, page, ["seo", "canonical"]), `Canonical points at ${target}, which is not a page on this site.`));
|
|
2242
2262
|
}
|
|
@@ -2407,9 +2427,10 @@ var linkChecks = {
|
|
|
2407
2427
|
};
|
|
2408
2428
|
|
|
2409
2429
|
// src/audit/checks/llms.ts
|
|
2430
|
+
var isLlmsToggleObject = (value) => typeof value === "object" && value !== null;
|
|
2410
2431
|
var llmsConfig = (context) => {
|
|
2411
2432
|
const value = context.project.config.ai?.llmsTxt;
|
|
2412
|
-
if (
|
|
2433
|
+
if (isLlmsToggleObject(value)) {
|
|
2413
2434
|
return { enabled: value.enabled, openapi: value.openapi };
|
|
2414
2435
|
}
|
|
2415
2436
|
return { enabled: value !== false, openapi: true };
|
|
@@ -2946,22 +2967,22 @@ var socialChecks = {
|
|
|
2946
2967
|
},
|
|
2947
2968
|
tier: "static"
|
|
2948
2969
|
};
|
|
2970
|
+
var isJsonLdNode = (value) => typeof value === "object" && value !== null;
|
|
2949
2971
|
var jsonLdProblems = (node) => {
|
|
2950
|
-
if (
|
|
2972
|
+
if (!isJsonLdNode(node)) {
|
|
2951
2973
|
return ["it is not an object"];
|
|
2952
2974
|
}
|
|
2953
|
-
const record = node;
|
|
2954
2975
|
const problems = [];
|
|
2955
|
-
if (!
|
|
2976
|
+
if (!node["@context"]) {
|
|
2956
2977
|
problems.push("@context");
|
|
2957
2978
|
}
|
|
2958
|
-
const graph =
|
|
2979
|
+
const graph = node["@graph"];
|
|
2959
2980
|
if (Array.isArray(graph)) {
|
|
2960
|
-
const untyped = graph.filter((entry) =>
|
|
2981
|
+
const untyped = graph.filter((entry) => !isJsonLdNode(entry) || !entry["@type"]).length;
|
|
2961
2982
|
if (untyped > 0) {
|
|
2962
2983
|
problems.push(`@type on ${untyped} of its ${graph.length} @graph nodes`);
|
|
2963
2984
|
}
|
|
2964
|
-
} else if (!
|
|
2985
|
+
} else if (!node["@type"]) {
|
|
2965
2986
|
problems.push("@type");
|
|
2966
2987
|
}
|
|
2967
2988
|
return problems;
|
|
@@ -3155,17 +3176,19 @@ var referencesFor = (kind, block, defaultLabel, renderer, display, basePath) =>
|
|
|
3155
3176
|
};
|
|
3156
3177
|
});
|
|
3157
3178
|
};
|
|
3158
|
-
var NO_DISPLAY = { codeSamples: [], expandSchemas: false };
|
|
3159
3179
|
var resolveReferences = (config) => [
|
|
3160
3180
|
...referencesFor("openapi", config.openapi, "API Reference", config.openapi.renderer, {
|
|
3161
3181
|
codeSamples: config.openapi.codeSamples,
|
|
3162
3182
|
expandSchemas: config.openapi.expandSchemas
|
|
3163
3183
|
}, config.basePath),
|
|
3164
|
-
...referencesFor("asyncapi", config.asyncapi, "Events",
|
|
3184
|
+
...referencesFor("asyncapi", config.asyncapi, "Events", config.asyncapi.renderer, {
|
|
3185
|
+
codeSamples: config.asyncapi.codeSamples,
|
|
3186
|
+
expandSchemas: config.asyncapi.expandSchemas
|
|
3187
|
+
}, config.basePath)
|
|
3165
3188
|
];
|
|
3166
3189
|
var referenceRoutes = (config) => resolveReferences(config).map((ref) => ref.renderer === "blume" ? withBasePath(config.basePath, ref.route) : ref.route);
|
|
3167
3190
|
var blumeReferenceOf = (ref, seen, usedSlugs) => {
|
|
3168
|
-
if (ref.
|
|
3191
|
+
if (ref.renderer !== "blume") {
|
|
3169
3192
|
return null;
|
|
3170
3193
|
}
|
|
3171
3194
|
const kept = seen.get(ref.route);
|
|
@@ -3279,7 +3302,7 @@ var excludeDirSegments = (patterns) => patterns.map((pattern) => /^(?<dir>[^*/]+
|
|
|
3279
3302
|
var ignoringWatchListener = (onChange, ignoreDirs = BLUME_WATCH_IGNORE_DIRS) => {
|
|
3280
3303
|
const ignore = new Set(ignoreDirs);
|
|
3281
3304
|
return (_event, filename) => {
|
|
3282
|
-
if (
|
|
3305
|
+
if (filename !== null && filename.split(/[/\\]/u).some((segment) => ignore.has(segment))) {
|
|
3283
3306
|
return;
|
|
3284
3307
|
}
|
|
3285
3308
|
onChange();
|
|
@@ -3492,8 +3515,9 @@ var slugifyFontName = (name) => name.toLowerCase().replaceAll(/[^a-z0-9]+/gu, "-
|
|
|
3492
3515
|
var fontVar = (slug) => `--blume-ff-${slug}`;
|
|
3493
3516
|
var SLOTS = ["display", "body", "mono"];
|
|
3494
3517
|
var slotCategory = (slot) => slot === "mono" ? "mono" : "sans";
|
|
3518
|
+
var isSlugValue = (value) => typeof value === "string";
|
|
3495
3519
|
var resolveFontValue = (slot, value) => {
|
|
3496
|
-
if (
|
|
3520
|
+
if (isSlugValue(value)) {
|
|
3497
3521
|
if (!isFontSlug(value)) {
|
|
3498
3522
|
return null;
|
|
3499
3523
|
}
|
|
@@ -3559,7 +3583,7 @@ var buildFontEntries = (fonts) => {
|
|
|
3559
3583
|
return [...entries.values()];
|
|
3560
3584
|
};
|
|
3561
3585
|
var slotSlug = (value) => {
|
|
3562
|
-
if (
|
|
3586
|
+
if (isSlugValue(value)) {
|
|
3563
3587
|
return isFontSlug(value) ? value : null;
|
|
3564
3588
|
}
|
|
3565
3589
|
return slugifyFontName(value.name);
|
|
@@ -3583,7 +3607,47 @@ ${lines.join(`
|
|
|
3583
3607
|
}
|
|
3584
3608
|
` : "";
|
|
3585
3609
|
};
|
|
3586
|
-
var
|
|
3610
|
+
var PRELOAD_WEIGHTS = {
|
|
3611
|
+
body: [400, 500],
|
|
3612
|
+
display: [500, 600],
|
|
3613
|
+
mono: [400]
|
|
3614
|
+
};
|
|
3615
|
+
var entryWeights = (entry) => entry.kind === "remote" ? entry.weights : entry.variants.map((variant) => variant.weight);
|
|
3616
|
+
var preloadWeightsFor = (slot, entry) => {
|
|
3617
|
+
const preferred = PRELOAD_WEIGHTS[slot];
|
|
3618
|
+
const weights = entryWeights(entry);
|
|
3619
|
+
const numeric = weights.filter((weight) => typeof weight === "number");
|
|
3620
|
+
const hits = preferred.filter((weight) => numeric.includes(weight));
|
|
3621
|
+
if (hits.length > 0) {
|
|
3622
|
+
return hits;
|
|
3623
|
+
}
|
|
3624
|
+
return numeric.length === weights.length ? numeric : preferred;
|
|
3625
|
+
};
|
|
3626
|
+
var configuredFonts = (fonts) => {
|
|
3627
|
+
if (!fonts) {
|
|
3628
|
+
return [];
|
|
3629
|
+
}
|
|
3630
|
+
const heads = new Map;
|
|
3631
|
+
for (const slot of SLOTS) {
|
|
3632
|
+
const value = fonts[slot];
|
|
3633
|
+
if (value === undefined) {
|
|
3634
|
+
continue;
|
|
3635
|
+
}
|
|
3636
|
+
const entry = resolveFontValue(slot, value);
|
|
3637
|
+
if (!entry) {
|
|
3638
|
+
continue;
|
|
3639
|
+
}
|
|
3640
|
+
const weights = heads.get(entry.cssVariable) ?? new Set;
|
|
3641
|
+
for (const weight of preloadWeightsFor(slot, entry)) {
|
|
3642
|
+
weights.add(weight);
|
|
3643
|
+
}
|
|
3644
|
+
heads.set(entry.cssVariable, weights);
|
|
3645
|
+
}
|
|
3646
|
+
return [...heads].map(([cssVariable, weights]) => ({
|
|
3647
|
+
cssVariable,
|
|
3648
|
+
preloadWeights: [...weights].toSorted((a, b) => a - b)
|
|
3649
|
+
}));
|
|
3650
|
+
};
|
|
3587
3651
|
|
|
3588
3652
|
// src/astro/templates.ts
|
|
3589
3653
|
var WORKSPACE_MARKERS = [
|
|
@@ -3626,9 +3690,9 @@ var ADAPTER_IMPORTS = {
|
|
|
3626
3690
|
node: "@astrojs/node",
|
|
3627
3691
|
vercel: "@astrojs/vercel"
|
|
3628
3692
|
};
|
|
3629
|
-
var ADAPTER_OPTIONS =
|
|
3630
|
-
node
|
|
3631
|
-
|
|
3693
|
+
var ADAPTER_OPTIONS = new Map([
|
|
3694
|
+
["node", '{ mode: "standalone" }']
|
|
3695
|
+
]);
|
|
3632
3696
|
var WRANGLER_CONFIG_FILES = [
|
|
3633
3697
|
"wrangler.jsonc",
|
|
3634
3698
|
"wrangler.json",
|
|
@@ -3790,7 +3854,7 @@ var astroConfigTemplate = (options) => {
|
|
|
3790
3854
|
if (deployment.adapter === "cloudflare") {
|
|
3791
3855
|
return resolveCloudflareAdapterArgs(context);
|
|
3792
3856
|
}
|
|
3793
|
-
return ADAPTER_OPTIONS
|
|
3857
|
+
return ADAPTER_OPTIONS.get(deployment.adapter) ?? "";
|
|
3794
3858
|
})();
|
|
3795
3859
|
const adapterExpr = deployment.adapter === "vercel" ? `withAdapterRoot(adapter(${adapterArgs}), ${JSON.stringify(adapterRoot(context))})` : `adapter(${adapterArgs})`;
|
|
3796
3860
|
const adapterOption = server && deployment.adapter ? `
|
|
@@ -3817,13 +3881,21 @@ var astroConfigTemplate = (options) => {
|
|
|
3817
3881
|
])))},` : "";
|
|
3818
3882
|
const fontEntries = buildFontEntries(config.theme.fonts);
|
|
3819
3883
|
const fontsOption = fontEntries.length ? `
|
|
3820
|
-
fonts: [${fontEntries.map((font) => font.kind === "local" ? `{ provider: fontProviders.local(), name: ${JSON.stringify(font.name)}, cssVariable: ${JSON.stringify(font.cssVariable)}, fallbacks: ${JSON.stringify(font.fallbacks)}, options: { variants: ${JSON.stringify(font.variants.map((variant) =>
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3884
|
+
fonts: [${fontEntries.map((font) => font.kind === "local" ? `{ provider: fontProviders.local(), name: ${JSON.stringify(font.name)}, cssVariable: ${JSON.stringify(font.cssVariable)}, fallbacks: ${JSON.stringify(font.fallbacks)}, options: { variants: ${JSON.stringify(font.variants.map((variant) => {
|
|
3885
|
+
const face = {};
|
|
3886
|
+
if (variant.weight !== undefined) {
|
|
3887
|
+
face.weight = variant.weight;
|
|
3888
|
+
}
|
|
3889
|
+
if (variant.style !== undefined) {
|
|
3890
|
+
face.style = variant.style;
|
|
3891
|
+
}
|
|
3892
|
+
return {
|
|
3893
|
+
...face,
|
|
3894
|
+
src: [
|
|
3895
|
+
isAbsolute(variant.src) ? variant.src : join8(context.root, variant.src)
|
|
3896
|
+
]
|
|
3897
|
+
};
|
|
3898
|
+
}))} } }` : `{ provider: fontProviders.${font.provider}(), name: ${JSON.stringify(font.name)}, cssVariable: ${JSON.stringify(font.cssVariable)}, weights: ${JSON.stringify(font.weights)}, fallbacks: ${JSON.stringify(font.fallbacks)} }`).join(", ")}],` : "";
|
|
3827
3899
|
const defineConfigImport = astroConfigImportLine({
|
|
3828
3900
|
hasFonts: fontEntries.length > 0,
|
|
3829
3901
|
hasSession: sessionOption.length > 0
|
|
@@ -3904,6 +3976,11 @@ ${userConfigSetup}export default defineConfig({
|
|
|
3904
3976
|
},
|
|
3905
3977
|
},
|
|
3906
3978
|
devToolbar: { enabled: false },
|
|
3979
|
+
// Navigations are full document loads (no client router), so the next page's
|
|
3980
|
+
// HTML is fetched on hover/viewport to hide the request latency behind the
|
|
3981
|
+
// user's intent. Pairs with the cross-document view-transition rule in the
|
|
3982
|
+
// theme sheet, which smooths the swap itself.
|
|
3983
|
+
prefetch: { prefetchAll: true },
|
|
3907
3984
|
vite: {
|
|
3908
3985
|
plugins: [tailwindcss(), prerenderDepsPlugin(), serverAppResolvePlugin()],
|
|
3909
3986
|
// Everything hydration can reach must be part of the dev dep optimizer's
|
|
@@ -4412,7 +4489,7 @@ export function GET({ props }: { props: { section: string } }) {
|
|
|
4412
4489
|
});
|
|
4413
4490
|
}
|
|
4414
4491
|
`;
|
|
4415
|
-
var ogEndpointTemplate = (customRoutes = [], og = {}) => `// Generated by Blume. Do not edit.
|
|
4492
|
+
var ogEndpointTemplate = (customRoutes = [], og = {}, includeChangelog = false) => `// Generated by Blume. Do not edit.
|
|
4416
4493
|
import { renderOgImage } from "blume/og";
|
|
4417
4494
|
import type { OgFont, OgFontFamilies } from "blume/og";
|
|
4418
4495
|
import data from "blume:data";
|
|
@@ -4447,7 +4524,10 @@ export function getStaticPaths() {
|
|
|
4447
4524
|
}
|
|
4448
4525
|
for (const route of data.routes) {
|
|
4449
4526
|
add(route.path === "/" ? "index" : route.path.slice(1), route.title);
|
|
4450
|
-
}
|
|
4527
|
+
}${includeChangelog ? `
|
|
4528
|
+
// The generated changelog index is not a content route, so it needs its own
|
|
4529
|
+
// card. Added last: a custom page or content route owning /changelog wins.
|
|
4530
|
+
add("changelog", data.ui.changelog?.title ?? "Changelog");` : ""}
|
|
4451
4531
|
return paths;
|
|
4452
4532
|
}
|
|
4453
4533
|
|
|
@@ -4638,11 +4718,13 @@ export function getStaticPaths() {
|
|
|
4638
4718
|
locale: route.locale,
|
|
4639
4719
|
route: route.path,
|
|
4640
4720
|
title: route.title,
|
|
4721
|
+
version: route.version,
|
|
4722
|
+
versionAlternates: route.versionAlternates,
|
|
4641
4723
|
},
|
|
4642
4724
|
}));
|
|
4643
4725
|
}
|
|
4644
4726
|
|
|
4645
|
-
const { entryId, collection, route, title, indexable, editUrl, lastModified, locale, alternates, fallback } = Astro.props;
|
|
4727
|
+
const { entryId, collection, route, title, indexable, editUrl, lastModified, locale, alternates, fallback, version, versionAlternates } = Astro.props;
|
|
4646
4728
|
const entry = await getEntry(collection as CollectionKey, entryId);
|
|
4647
4729
|
if (!entry) {
|
|
4648
4730
|
return new Response(null, { status: 404 });
|
|
@@ -4674,9 +4756,6 @@ const ogGenerated = !seo.image && Boolean(ogPath);
|
|
|
4674
4756
|
const x = { ...data.config.x, ...(seo.x?.creator ? { creator: seo.x.creator } : {}) };
|
|
4675
4757
|
|
|
4676
4758
|
const basedRoute = withBase(route);
|
|
4677
|
-
const canonical =
|
|
4678
|
-
seo.canonical ??
|
|
4679
|
-
(base ? \`\${base}\${basedRoute === "/" ? "" : encodeURI(basedRoute)}\` : null);
|
|
4680
4759
|
|
|
4681
4760
|
// Locale resolution. With i18n on, pick the active locale's nav + dictionary,
|
|
4682
4761
|
// build hreflang alternates, and derive the language-switcher targets.
|
|
@@ -4697,7 +4776,20 @@ const stripLocale = (path: string, codeArg: string) => {
|
|
|
4697
4776
|
return prefix && path.startsWith(prefix) ? path.slice(prefix.length) || "/" : path;
|
|
4698
4777
|
};
|
|
4699
4778
|
|
|
4700
|
-
|
|
4779
|
+
// Version resolution. An archived page renders its snapshot's navigation tree,
|
|
4780
|
+
// points its canonical at the latest equivalent (unless configured otherwise),
|
|
4781
|
+
// and shows the old-version notice.
|
|
4782
|
+
const versionsConfig = data.config.versions;
|
|
4783
|
+
const archived = versionsConfig && version
|
|
4784
|
+
? (versionsConfig.archived.find((v) => v.id === version) ?? null)
|
|
4785
|
+
: null;
|
|
4786
|
+
const latestVersionAlt = (versionAlternates ?? []).find((alt) => alt.version === "");
|
|
4787
|
+
|
|
4788
|
+
const navigation = version
|
|
4789
|
+
? (data.navigationByVersion[version]?.[i18n ? locale : ""] ?? data.navigation)
|
|
4790
|
+
: i18n
|
|
4791
|
+
? (data.navigationByLocale[locale] ?? data.navigation)
|
|
4792
|
+
: data.navigation;
|
|
4701
4793
|
const ui = i18n ? (data.uiByLocale[locale] ?? data.ui) : data.ui;
|
|
4702
4794
|
const localeMeta = i18n ? i18n.locales.find((l) => l.code === locale) : null;
|
|
4703
4795
|
const dir = localeMeta?.dir ?? "ltr";
|
|
@@ -4709,10 +4801,22 @@ const contentLocale =
|
|
|
4709
4801
|
const contentDir = i18n
|
|
4710
4802
|
? (i18n.locales.find((l) => l.code === contentLocale)?.dir ?? "ltr")
|
|
4711
4803
|
: "ltr";
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4804
|
+
// The root route keeps its trailing slash (\`https://site/\`) so canonical and
|
|
4805
|
+
// hreflang URLs byte-match the sitemap's <loc> for the home page.
|
|
4806
|
+
const absolute = (path: string) => base + withBase(path);
|
|
4807
|
+
|
|
4808
|
+
// An archived page defaults its canonical to the same page in the latest docs
|
|
4809
|
+
// when that page still exists — search engines treat the live page as
|
|
4810
|
+
// authoritative without deindexing version-only content. A page's own
|
|
4811
|
+
// \`seo.canonical\` always wins, and \`canonical: "self"\` keeps the default.
|
|
4812
|
+
const canonical =
|
|
4813
|
+
seo.canonical ??
|
|
4814
|
+
(archived && archived.canonical === "latest" && latestVersionAlt && base
|
|
4815
|
+
? absolute(latestVersionAlt.path)
|
|
4816
|
+
: base
|
|
4817
|
+
? \`\${base}\${basedRoute === "/" ? "/" : encodeURI(basedRoute)}\`
|
|
4818
|
+
: null);
|
|
4819
|
+
const effectiveNoindex = Boolean(seo.noindex) || (archived?.noindex ?? false);
|
|
4716
4820
|
|
|
4717
4821
|
const localeAlternates =
|
|
4718
4822
|
i18n && base
|
|
@@ -4736,6 +4840,72 @@ const localeSwitch = i18n
|
|
|
4736
4840
|
})
|
|
4737
4841
|
: [];
|
|
4738
4842
|
|
|
4843
|
+
// Version switcher + old-version notice. The switcher auto-populates from the
|
|
4844
|
+
// versions config as a \`kind: "version"\` selector; a user-declared version
|
|
4845
|
+
// selector in \`navigation.selectors\` suppresses it (theirs renders instead).
|
|
4846
|
+
// Fallback version roots compose like real routes — \`{basePath}/{locale?}/{id}\`
|
|
4847
|
+
// (manifest \`versionAlternates\` paths arrive with the base already applied).
|
|
4848
|
+
const versionRootFor = (id: string) => {
|
|
4849
|
+
const logical = id ? \`/\${id}\` : "/";
|
|
4850
|
+
const localized = i18n ? localizeRoute(logical, locale) : logical;
|
|
4851
|
+
const mount = data.config.basePath;
|
|
4852
|
+
if (!mount) {
|
|
4853
|
+
return localized;
|
|
4854
|
+
}
|
|
4855
|
+
return localized === "/" ? mount : \`\${mount}\${localized}\`;
|
|
4856
|
+
};
|
|
4857
|
+
const samePageSwitch = versionsConfig
|
|
4858
|
+
? versionsConfig.switcher.redirect === "same-page"
|
|
4859
|
+
: true;
|
|
4860
|
+
const userHasVersionSelector = navigation.selectors.some(
|
|
4861
|
+
(selector) => selector.kind === "version"
|
|
4862
|
+
);
|
|
4863
|
+
const versionSelector =
|
|
4864
|
+
versionsConfig && !userHasVersionSelector
|
|
4865
|
+
? {
|
|
4866
|
+
items: [
|
|
4867
|
+
{
|
|
4868
|
+
id: "",
|
|
4869
|
+
label: versionsConfig.current.label,
|
|
4870
|
+
tag: versionsConfig.current.badge,
|
|
4871
|
+
},
|
|
4872
|
+
...versionsConfig.archived.map((v) => ({
|
|
4873
|
+
id: v.id,
|
|
4874
|
+
label: v.label ?? v.id,
|
|
4875
|
+
tag: undefined,
|
|
4876
|
+
})),
|
|
4877
|
+
].map((entry) => {
|
|
4878
|
+
const alt = (versionAlternates ?? []).find(
|
|
4879
|
+
(a) => a.version === entry.id
|
|
4880
|
+
);
|
|
4881
|
+
return {
|
|
4882
|
+
label: entry.label,
|
|
4883
|
+
path: samePageSwitch && alt ? alt.path : versionRootFor(entry.id),
|
|
4884
|
+
...(entry.tag ? { tag: entry.tag } : {}),
|
|
4885
|
+
};
|
|
4886
|
+
}),
|
|
4887
|
+
kind: "version" as const,
|
|
4888
|
+
label: ui.versions.switcher,
|
|
4889
|
+
}
|
|
4890
|
+
: null;
|
|
4891
|
+
|
|
4892
|
+
const versionNotice =
|
|
4893
|
+
archived && archived.banner !== false
|
|
4894
|
+
? {
|
|
4895
|
+
latestHref: latestVersionAlt
|
|
4896
|
+
? latestVersionAlt.path
|
|
4897
|
+
: versionRootFor(""),
|
|
4898
|
+
latestLabel: ui.versions.latest,
|
|
4899
|
+
message:
|
|
4900
|
+
typeof archived.banner === "string"
|
|
4901
|
+
? archived.banner
|
|
4902
|
+
: ui.versions.notice.replace(
|
|
4903
|
+
"{version}",
|
|
4904
|
+
archived.label ?? archived.id
|
|
4905
|
+
),
|
|
4906
|
+
}
|
|
4907
|
+
: null;
|
|
4908
|
+
|
|
4739
4909
|
// The whole page shell is overridable via \`layout.Layout\`; it receives the same
|
|
4740
4910
|
// props as the built-in RootLayout, plus the \`layout\` map for its inner slots.
|
|
4741
4911
|
const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
@@ -4760,6 +4930,9 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
|
4760
4930
|
localeAlternates={localeAlternates}
|
|
4761
4931
|
xDefault={xDefault}
|
|
4762
4932
|
localeSwitch={localeSwitch}
|
|
4933
|
+
versionSelector={versionSelector}
|
|
4934
|
+
versionNotice={versionNotice}
|
|
4935
|
+
searchVersion={versionsConfig ? version : null}
|
|
4763
4936
|
page={{ title: seo.title ?? title, description: seo.description ?? frontmatter.description, route }}
|
|
4764
4937
|
headings={headings}
|
|
4765
4938
|
toc={data.config.toc}
|
|
@@ -4782,7 +4955,7 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
|
4782
4955
|
pageType={frontmatter.type}
|
|
4783
4956
|
published={frontmatter.date ?? frontmatter.changelog?.date ?? null}
|
|
4784
4957
|
lastModified={lastModified}
|
|
4785
|
-
noindex={
|
|
4958
|
+
noindex={effectiveNoindex}
|
|
4786
4959
|
structuredDataEnabled={data.config.structuredData}
|
|
4787
4960
|
>
|
|
4788
4961
|
<h1>{title}</h1>
|
|
@@ -4935,6 +5108,12 @@ const base = data.config.site ? data.config.site.replace(/\\/$/, "") : null;
|
|
|
4935
5108
|
const basedRoute = withBase("/changelog");
|
|
4936
5109
|
const canonical = base ? base + basedRoute : null;
|
|
4937
5110
|
|
|
5111
|
+
// The generated OG card for this route (the /og endpoint emits it alongside
|
|
5112
|
+
// the content-route cards), absolutized like the catch-all's so crawlers get
|
|
5113
|
+
// a full URL when the site is known.
|
|
5114
|
+
const ogPath = data.config.og.enabled ? withBase("/og/changelog.png") : null;
|
|
5115
|
+
const ogImage = ogPath && base ? base + ogPath : ogPath;
|
|
5116
|
+
|
|
4938
5117
|
// The page chrome (h1, title, description) comes from the same translatable
|
|
4939
5118
|
// \`changelog\` group as the reveal button; optional chaining tolerates a
|
|
4940
5119
|
// not-yet-regenerated data snapshot from before these keys existed.
|
|
@@ -4942,7 +5121,10 @@ const changelogTitle = data.ui.changelog?.title ?? "Changelog";
|
|
|
4942
5121
|
const changelogDescription =
|
|
4943
5122
|
data.ui.changelog?.description ??
|
|
4944
5123
|
"Product updates, new features, and fixes from every release.";
|
|
4945
|
-
|
|
5124
|
+
// The layout suffixes "- {site title}" itself, so the page title is just the
|
|
5125
|
+
// changelog's own name — prefixing the site title too would double it
|
|
5126
|
+
// ("Acme Changelog - Acme").
|
|
5127
|
+
const pageTitle = changelogTitle;
|
|
4946
5128
|
|
|
4947
5129
|
const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
4948
5130
|
---
|
|
@@ -4974,7 +5156,8 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
|
4974
5156
|
fontCssVars={data.fontCssVars}
|
|
4975
5157
|
searchEnabled={data.config.search.enabled}
|
|
4976
5158
|
indexable={true}
|
|
4977
|
-
ogImage={
|
|
5159
|
+
ogImage={ogImage}
|
|
5160
|
+
ogGenerated={Boolean(ogImage)}
|
|
4978
5161
|
x={data.config.x}
|
|
4979
5162
|
canonical={canonical}
|
|
4980
5163
|
exportPdf={${options.exportPdf}}
|
|
@@ -5467,6 +5650,9 @@ var sitemapParser = new XMLParser({
|
|
|
5467
5650
|
parseTagValue: false,
|
|
5468
5651
|
removeNSPrefix: true
|
|
5469
5652
|
});
|
|
5653
|
+
var isUrlsetElement = (value) => typeof value === "object" && value !== null;
|
|
5654
|
+
var isUrlEntry = (value) => typeof value === "object" && value !== null;
|
|
5655
|
+
var isText = (value) => typeof value === "string";
|
|
5470
5656
|
var parseSitemap = (file, xml, bytes) => {
|
|
5471
5657
|
const doc = { bytes, file, lastmod: new Map, urls: [] };
|
|
5472
5658
|
let parsed;
|
|
@@ -5480,19 +5666,19 @@ var parseSitemap = (file, xml, bytes) => {
|
|
|
5480
5666
|
doc.error = Object.hasOwn(parsed, "sitemapindex") ? "sitemap is an index, not a urlset" : "no <urlset> element";
|
|
5481
5667
|
return doc;
|
|
5482
5668
|
}
|
|
5483
|
-
const urlset = parsed
|
|
5484
|
-
const entries =
|
|
5669
|
+
const { urlset } = parsed;
|
|
5670
|
+
const entries = isUrlsetElement(urlset) ? [urlset.url].flat() : [];
|
|
5485
5671
|
for (const entry of entries) {
|
|
5486
|
-
if (
|
|
5672
|
+
if (!isUrlEntry(entry)) {
|
|
5487
5673
|
continue;
|
|
5488
5674
|
}
|
|
5489
5675
|
const { loc, lastmod } = entry;
|
|
5490
|
-
const locText =
|
|
5676
|
+
const locText = isText(loc) ? loc.trim() : "";
|
|
5491
5677
|
if (!locText) {
|
|
5492
5678
|
continue;
|
|
5493
5679
|
}
|
|
5494
5680
|
doc.urls.push(locText);
|
|
5495
|
-
if (
|
|
5681
|
+
if (isText(lastmod) && lastmod.trim() !== "") {
|
|
5496
5682
|
doc.lastmod?.set(locText, lastmod.trim());
|
|
5497
5683
|
}
|
|
5498
5684
|
}
|
|
@@ -5740,6 +5926,7 @@ import { relative as relative10 } from "pathe";
|
|
|
5740
5926
|
|
|
5741
5927
|
// src/core/config.ts
|
|
5742
5928
|
import { existsSync as existsSync6, readFileSync as readFileSync3 } from "node:fs";
|
|
5929
|
+
import { z as z3 } from "zod";
|
|
5743
5930
|
|
|
5744
5931
|
// src/core/load-module.ts
|
|
5745
5932
|
import { createJiti } from "jiti";
|
|
@@ -5795,8 +5982,9 @@ var resolveProjectContext = (root, config, options) => {
|
|
|
5795
5982
|
import { z as z2 } from "zod";
|
|
5796
5983
|
|
|
5797
5984
|
// src/seo/x-handle.ts
|
|
5985
|
+
var isString = (value) => typeof value === "string";
|
|
5798
5986
|
var normalizeXHandle = (value) => {
|
|
5799
|
-
if (
|
|
5987
|
+
if (!isString(value)) {
|
|
5800
5988
|
return;
|
|
5801
5989
|
}
|
|
5802
5990
|
const handle = value.trim().replace(/^@+/u, "");
|
|
@@ -9377,6 +9565,7 @@ var uiStringsObject = z.object({
|
|
|
9377
9565
|
search: z.object({
|
|
9378
9566
|
all: z.string().default("All"),
|
|
9379
9567
|
allLanguages: z.string().default("All languages"),
|
|
9568
|
+
allVersions: z.string().default("All versions"),
|
|
9380
9569
|
askAi: z.string().default("Ask AI"),
|
|
9381
9570
|
askAiHint: z.string().default("Get an instant answer from AI"),
|
|
9382
9571
|
button: z.string().default("Search"),
|
|
@@ -9393,6 +9582,11 @@ var uiStringsObject = z.object({
|
|
|
9393
9582
|
}).prefault({}),
|
|
9394
9583
|
toc: z.object({
|
|
9395
9584
|
title: z.string().default("On this page")
|
|
9585
|
+
}).prefault({}),
|
|
9586
|
+
versions: z.object({
|
|
9587
|
+
latest: z.string().default("Go to latest"),
|
|
9588
|
+
notice: z.string().default("You're viewing documentation for {version}. It may be out of date."),
|
|
9589
|
+
switcher: z.string().default("Version")
|
|
9396
9590
|
}).prefault({})
|
|
9397
9591
|
});
|
|
9398
9592
|
var uiStringsSchema = uiStringsObject.prefault({});
|
|
@@ -9433,12 +9627,16 @@ var resolveUIStrings = (locale, options) => {
|
|
|
9433
9627
|
var isStandardSchema = (value) => typeof value === "object" && value !== null && typeof value["~standard"]?.validate === "function";
|
|
9434
9628
|
|
|
9435
9629
|
// src/core/schema.ts
|
|
9630
|
+
var isString2 = (value) => typeof value === "string";
|
|
9631
|
+
var isBoolean = (value) => typeof value === "boolean";
|
|
9436
9632
|
var iconName = z2.string().min(1);
|
|
9437
9633
|
var DEFAULT_CONTENT_GLOB = "**/*.{md,mdx}";
|
|
9438
9634
|
var hydrationMode = z2.enum(["load", "idle", "visible", "media", "only"]);
|
|
9439
9635
|
var dateSchema = z2.union([z2.string(), z2.date()]).transform((value) => value instanceof Date ? value.toISOString() : value);
|
|
9636
|
+
var sidebarDisplaySchema = z2.enum(["flat", "group", "page"]);
|
|
9440
9637
|
var sidebarMetaSchema = z2.strictObject({
|
|
9441
9638
|
badge: z2.string().optional(),
|
|
9639
|
+
display: sidebarDisplaySchema.optional(),
|
|
9442
9640
|
hidden: z2.boolean().default(false),
|
|
9443
9641
|
icon: iconName.optional(),
|
|
9444
9642
|
label: z2.string().optional(),
|
|
@@ -9495,11 +9693,12 @@ var pageMetaBaseSchema = z2.strictObject({
|
|
|
9495
9693
|
type: z2.string().optional()
|
|
9496
9694
|
});
|
|
9497
9695
|
var pageMetaSchema = pageMetaBaseSchema;
|
|
9696
|
+
var BUILT_IN_PAGE_META_KEYS = new Set(pageMetaBaseSchema.keyof().options);
|
|
9498
9697
|
var customKeySchemaRecord = (where) => z2.record(z2.string(), z2.custom(isStandardSchema, {
|
|
9499
9698
|
message: "Expected a Standard Schema (e.g. a Zod schema — any Zod version works)."
|
|
9500
9699
|
})).default({}).superRefine((value, ctx) => {
|
|
9501
9700
|
for (const key of Object.keys(value)) {
|
|
9502
|
-
if (
|
|
9701
|
+
if (BUILT_IN_PAGE_META_KEYS.has(key)) {
|
|
9503
9702
|
ctx.addIssue({
|
|
9504
9703
|
code: z2.ZodIssueCode.custom,
|
|
9505
9704
|
message: `"${key}" is a built-in frontmatter field and cannot be redeclared via ${where}.`,
|
|
@@ -9508,9 +9707,9 @@ var customKeySchemaRecord = (where) => z2.record(z2.string(), z2.custom(isStanda
|
|
|
9508
9707
|
}
|
|
9509
9708
|
}
|
|
9510
9709
|
});
|
|
9511
|
-
var sidebarDisplaySchema = z2.enum(["flat", "group", "page"]);
|
|
9512
9710
|
var folderMetaSchema = z2.strictObject({
|
|
9513
9711
|
collapsed: z2.boolean().optional(),
|
|
9712
|
+
display: sidebarDisplaySchema.optional(),
|
|
9514
9713
|
icon: iconName.optional(),
|
|
9515
9714
|
order: z2.number().optional(),
|
|
9516
9715
|
pages: z2.array(z2.string()).optional(),
|
|
@@ -9604,7 +9803,7 @@ var githubReleasesSourceSchema = z2.strictObject({
|
|
|
9604
9803
|
type: z2.literal("github-releases")
|
|
9605
9804
|
});
|
|
9606
9805
|
var customSourceSchema = z2.object({
|
|
9607
|
-
source: z2.custom((val) => typeof val === "object" && val !== null && typeof val.load === "function" && typeof val.name === "string", { message: "custom source must be a ContentSource (with name + load)" }),
|
|
9806
|
+
source: z2.custom((val) => typeof val === "object" && val !== null && ("load" in val) && typeof val.load === "function" && ("name" in val) && typeof val.name === "string", { message: "custom source must be a ContentSource (with name + load)" }),
|
|
9608
9807
|
type: z2.literal("custom")
|
|
9609
9808
|
});
|
|
9610
9809
|
var contentSourceSchema = z2.discriminatedUnion("type", [
|
|
@@ -9695,7 +9894,7 @@ var localFontSchema = z2.strictObject({
|
|
|
9695
9894
|
variants: z2.array(localFontVariantSchema).nonempty()
|
|
9696
9895
|
});
|
|
9697
9896
|
var fontValueSchema = z2.union([z2.string(), remoteFontSchema, localFontSchema]).superRefine((value, ctx) => {
|
|
9698
|
-
if (
|
|
9897
|
+
if (isString2(value) && !isFontSlug(value)) {
|
|
9699
9898
|
ctx.addIssue({
|
|
9700
9899
|
code: z2.ZodIssueCode.custom,
|
|
9701
9900
|
message: `Unknown font "${value}". Supported fonts: ${FONT_SLUGS.join(", ")}. For any other family, use the object form: { name: "..." } (remote provider) or { name: "...", variants: [...] } (local files).`
|
|
@@ -9708,18 +9907,18 @@ var perModeValueSchema = z2.union([
|
|
|
9708
9907
|
dark: z2.string().optional(),
|
|
9709
9908
|
light: z2.string().optional()
|
|
9710
9909
|
})
|
|
9711
|
-
]).optional().transform((value) =>
|
|
9910
|
+
]).optional().transform((value) => isString2(value) ? { dark: value, light: value } : value);
|
|
9712
9911
|
var themeConfigSchema = z2.strictObject({
|
|
9713
9912
|
accent: z2.union([
|
|
9714
9913
|
z2.string(),
|
|
9715
9914
|
z2.strictObject({ dark: z2.string(), light: z2.string() })
|
|
9716
|
-
]).default("blue").transform((value) =>
|
|
9915
|
+
]).default("blue").transform((value) => isString2(value) ? { dark: value, light: value } : value),
|
|
9717
9916
|
action: z2.string().optional(),
|
|
9718
9917
|
background: perModeValueSchema,
|
|
9719
9918
|
backgroundImage: perModeValueSchema,
|
|
9720
9919
|
fonts: z2.strictObject({
|
|
9721
9920
|
body: fontValueSchema.default("inter"),
|
|
9722
|
-
display: fontValueSchema.default("inter
|
|
9921
|
+
display: fontValueSchema.default("inter"),
|
|
9723
9922
|
mono: fontValueSchema.default("ibm-plex-mono")
|
|
9724
9923
|
}).prefault({}),
|
|
9725
9924
|
layout: z2.enum(["sidebar"]).default("sidebar"),
|
|
@@ -9796,7 +9995,7 @@ var askAiProviders = [
|
|
|
9796
9995
|
];
|
|
9797
9996
|
var PRIVATE_JWK_PARAMS = ["d", "p", "q", "dp", "dq", "qi", "oth", "k"];
|
|
9798
9997
|
var publicJwkSchema = z2.record(z2.string(), z2.unknown()).superRefine((jwk, ctx) => {
|
|
9799
|
-
if (
|
|
9998
|
+
if (!isString2(jwk.kty) || jwk.kty.length === 0) {
|
|
9800
9999
|
ctx.addIssue({
|
|
9801
10000
|
code: z2.ZodIssueCode.custom,
|
|
9802
10001
|
message: 'A JWK must declare its key type ("kty").'
|
|
@@ -9857,7 +10056,7 @@ var aiConfigSchema = z2.strictObject({
|
|
|
9857
10056
|
enabled: z2.boolean().default(true),
|
|
9858
10057
|
openapi: z2.boolean().default(true)
|
|
9859
10058
|
})
|
|
9860
|
-
]).default(true).transform((value) =>
|
|
10059
|
+
]).default(true).transform((value) => isBoolean(value) ? { enabled: value, openapi: true } : value),
|
|
9861
10060
|
markdownComponents: z2.record(z2.string(), z2.custom((value) => typeof value === "function", {
|
|
9862
10061
|
message: "Expected a serializer function."
|
|
9863
10062
|
})).default({}),
|
|
@@ -9892,7 +10091,7 @@ var exportConfigSchema = z2.union([
|
|
|
9892
10091
|
epub: z2.boolean().default(false),
|
|
9893
10092
|
pdf: z2.boolean().default(false)
|
|
9894
10093
|
})
|
|
9895
|
-
]).transform((value) =>
|
|
10094
|
+
]).transform((value) => isBoolean(value) ? { epub: value, pdf: value } : value);
|
|
9896
10095
|
var localeSchema = z2.strictObject({
|
|
9897
10096
|
code: z2.string().min(1),
|
|
9898
10097
|
dir: z2.enum(["ltr", "rtl"]).default("ltr"),
|
|
@@ -9923,6 +10122,36 @@ var i18nConfigSchema = z2.strictObject({
|
|
|
9923
10122
|
});
|
|
9924
10123
|
}
|
|
9925
10124
|
});
|
|
10125
|
+
var VERSION_ID = /^[A-Za-z][\w.-]*$/u;
|
|
10126
|
+
var archivedVersionSchema = z2.strictObject({
|
|
10127
|
+
banner: z2.union([z2.boolean(), z2.string()]).default(true),
|
|
10128
|
+
canonical: z2.enum(["latest", "self"]).default("latest"),
|
|
10129
|
+
id: z2.string().regex(VERSION_ID, 'Version ids must start with a letter (e.g. "v1.0") and contain only letters, digits, dots, hyphens, and underscores.'),
|
|
10130
|
+
label: z2.string().optional(),
|
|
10131
|
+
noindex: z2.boolean().default(false)
|
|
10132
|
+
});
|
|
10133
|
+
var versionsConfigSchema = z2.strictObject({
|
|
10134
|
+
archived: z2.array(archivedVersionSchema).default([]),
|
|
10135
|
+
current: z2.strictObject({
|
|
10136
|
+
badge: z2.string().optional(),
|
|
10137
|
+
label: z2.string()
|
|
10138
|
+
}),
|
|
10139
|
+
switcher: z2.strictObject({
|
|
10140
|
+
redirect: z2.enum(["same-page", "root"]).default("same-page")
|
|
10141
|
+
}).prefault({})
|
|
10142
|
+
}).superRefine((value, ctx) => {
|
|
10143
|
+
const seen = new Set;
|
|
10144
|
+
for (const [position, version] of value.archived.entries()) {
|
|
10145
|
+
if (seen.has(version.id)) {
|
|
10146
|
+
ctx.addIssue({
|
|
10147
|
+
code: z2.ZodIssueCode.custom,
|
|
10148
|
+
message: `versions.archived declares "${version.id}" more than once.`,
|
|
10149
|
+
path: ["archived", position, "id"]
|
|
10150
|
+
});
|
|
10151
|
+
}
|
|
10152
|
+
seen.add(version.id);
|
|
10153
|
+
}
|
|
10154
|
+
});
|
|
9926
10155
|
var analyticsScriptSchema = z2.strictObject({
|
|
9927
10156
|
attributes: z2.record(z2.string(), z2.string()).optional(),
|
|
9928
10157
|
content: z2.string().optional(),
|
|
@@ -10036,18 +10265,18 @@ var githubConfigSchema = z2.strictObject({
|
|
|
10036
10265
|
owner: z2.string(),
|
|
10037
10266
|
repo: z2.string()
|
|
10038
10267
|
});
|
|
10268
|
+
var isThemeObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10039
10269
|
var codeThemeSchema = z2.custom((value) => {
|
|
10040
|
-
if (
|
|
10270
|
+
if (isString2(value)) {
|
|
10041
10271
|
return true;
|
|
10042
10272
|
}
|
|
10043
|
-
if (
|
|
10273
|
+
if (!isThemeObject(value)) {
|
|
10044
10274
|
return false;
|
|
10045
10275
|
}
|
|
10046
|
-
const
|
|
10047
|
-
const
|
|
10048
|
-
const
|
|
10049
|
-
const
|
|
10050
|
-
const hasContent = theme.settings !== undefined || theme.tokenColors !== undefined || theme.colors !== undefined;
|
|
10276
|
+
const settingsValid = value.settings === undefined || Array.isArray(value.settings);
|
|
10277
|
+
const tokenColorsValid = value.tokenColors === undefined || Array.isArray(value.tokenColors);
|
|
10278
|
+
const colorsValid = value.colors === undefined || isThemeObject(value.colors);
|
|
10279
|
+
const hasContent = value.settings !== undefined || value.tokenColors !== undefined || value.colors !== undefined;
|
|
10051
10280
|
return settingsValid && tokenColorsValid && colorsValid && hasContent;
|
|
10052
10281
|
}, "Expected a Shiki theme name or custom theme object");
|
|
10053
10282
|
var codeBlockThemeSchema = z2.strictObject({
|
|
@@ -10063,7 +10292,7 @@ var examplesConfigSchema = z2.union([
|
|
|
10063
10292
|
css: z2.string().optional(),
|
|
10064
10293
|
source: z2.string().default("examples")
|
|
10065
10294
|
})
|
|
10066
|
-
]).transform((value) =>
|
|
10295
|
+
]).transform((value) => isString2(value) ? { source: value } : value);
|
|
10067
10296
|
var lastModifiedConfigSchema = z2.union([
|
|
10068
10297
|
z2.boolean(),
|
|
10069
10298
|
z2.strictObject({ type: z2.enum(["git", "frontmatter"]).default("git") })
|
|
@@ -10103,24 +10332,24 @@ var openapiSourceSchema = z2.strictObject({
|
|
|
10103
10332
|
spec: z2.string()
|
|
10104
10333
|
});
|
|
10105
10334
|
var scalarConfigSchema = z2.record(z2.string(), z2.unknown()).optional();
|
|
10106
|
-
var
|
|
10107
|
-
codeSamples: z2.array(z2.string()).default(
|
|
10335
|
+
var referenceConfigSchema = (defaults) => z2.strictObject({
|
|
10336
|
+
codeSamples: z2.array(z2.string()).default(defaults.codeSamples),
|
|
10108
10337
|
enabled: z2.boolean().default(false),
|
|
10109
10338
|
expandSchemas: z2.boolean().default(false),
|
|
10110
10339
|
renderer: z2.enum(["blume", "scalar"]).default("blume"),
|
|
10111
|
-
route: z2.string().default(
|
|
10340
|
+
route: z2.string().default(defaults.route),
|
|
10112
10341
|
scalar: scalarConfigSchema,
|
|
10113
10342
|
sources: z2.array(openapiSourceSchema).default([]),
|
|
10114
10343
|
spec: z2.string().optional(),
|
|
10115
10344
|
theme: z2.string().optional()
|
|
10116
10345
|
});
|
|
10117
|
-
var
|
|
10118
|
-
|
|
10119
|
-
route:
|
|
10120
|
-
|
|
10121
|
-
|
|
10122
|
-
|
|
10123
|
-
|
|
10346
|
+
var openapiConfigSchema = referenceConfigSchema({
|
|
10347
|
+
codeSamples: ["curl", "js", "python"],
|
|
10348
|
+
route: "/reference"
|
|
10349
|
+
});
|
|
10350
|
+
var asyncapiConfigSchema = referenceConfigSchema({
|
|
10351
|
+
codeSamples: [],
|
|
10352
|
+
route: "/events"
|
|
10124
10353
|
});
|
|
10125
10354
|
var frontmatterConfigSchema = z2.strictObject({
|
|
10126
10355
|
extend: customKeySchemaRecord("frontmatter.extend")
|
|
@@ -10132,7 +10361,7 @@ var tocConfigSchema = z2.union([
|
|
|
10132
10361
|
minHeadingLevel: z2.number().int().min(1).max(6).optional()
|
|
10133
10362
|
})
|
|
10134
10363
|
]).default(true).transform((value) => {
|
|
10135
|
-
if (
|
|
10364
|
+
if (isBoolean(value)) {
|
|
10136
10365
|
return { enabled: value, maxLevel: 3, minLevel: 2 };
|
|
10137
10366
|
}
|
|
10138
10367
|
return {
|
|
@@ -10172,8 +10401,21 @@ var blumeConfigSchema = z2.strictObject({
|
|
|
10172
10401
|
seo: seoConfigSchema.prefault({}),
|
|
10173
10402
|
theme: themeConfigSchema.prefault({}),
|
|
10174
10403
|
title: z2.string().default("Documentation"),
|
|
10175
|
-
toc: tocConfigSchema
|
|
10404
|
+
toc: tocConfigSchema,
|
|
10405
|
+
versions: versionsConfigSchema.optional()
|
|
10176
10406
|
}).superRefine((config, ctx) => {
|
|
10407
|
+
if (config.versions && config.i18n) {
|
|
10408
|
+
const localeCodes = new Set(config.i18n.locales.map((locale) => locale.code.toLowerCase()));
|
|
10409
|
+
for (const [position, version] of config.versions.archived.entries()) {
|
|
10410
|
+
if (localeCodes.has(version.id.toLowerCase())) {
|
|
10411
|
+
ctx.addIssue({
|
|
10412
|
+
code: z2.ZodIssueCode.custom,
|
|
10413
|
+
message: `Version id "${version.id}" is also a configured locale code — rename the version (e.g. "v${version.id}").`,
|
|
10414
|
+
path: ["versions", "archived", position, "id"]
|
|
10415
|
+
});
|
|
10416
|
+
}
|
|
10417
|
+
}
|
|
10418
|
+
}
|
|
10177
10419
|
for (const [typeName, typeConfig] of Object.entries(config.content.types)) {
|
|
10178
10420
|
for (const key of Object.keys(typeConfig.frontmatter)) {
|
|
10179
10421
|
if (Object.hasOwn(config.frontmatter.extend, key)) {
|
|
@@ -10198,9 +10440,12 @@ var blumeConfigSchema = z2.strictObject({
|
|
|
10198
10440
|
|
|
10199
10441
|
// src/core/config.ts
|
|
10200
10442
|
var importConfigModule = createModuleLoader();
|
|
10443
|
+
var themeFontsProbeSchema = z3.looseObject({
|
|
10444
|
+
theme: z3.looseObject({ fonts: z3.unknown() }).optional()
|
|
10445
|
+
});
|
|
10201
10446
|
var loadConfig = async (root, options = {}) => {
|
|
10202
10447
|
const configFile = findConfigFile(root);
|
|
10203
|
-
let raw
|
|
10448
|
+
let raw;
|
|
10204
10449
|
if (configFile) {
|
|
10205
10450
|
try {
|
|
10206
10451
|
raw = await importConfigModule(configFile);
|
|
@@ -10213,7 +10458,8 @@ var loadConfig = async (root, options = {}) => {
|
|
|
10213
10458
|
});
|
|
10214
10459
|
}
|
|
10215
10460
|
}
|
|
10216
|
-
const
|
|
10461
|
+
const probe2 = themeFontsProbeSchema.safeParse(raw);
|
|
10462
|
+
const themeFontsConfigured = probe2.success && probe2.data.theme?.fonts !== undefined;
|
|
10217
10463
|
const parsed = blumeConfigSchema.safeParse(raw ?? {});
|
|
10218
10464
|
if (!parsed.success) {
|
|
10219
10465
|
const source = configFile && existsSync6(configFile) ? readFileSync3(configFile, "utf-8") : undefined;
|
|
@@ -10320,12 +10566,14 @@ var localeTargetPath = (rel, ext, locale, i18n) => {
|
|
|
10320
10566
|
}
|
|
10321
10567
|
return `${locale}/${rel}`;
|
|
10322
10568
|
};
|
|
10323
|
-
var i18nDiagnostics = (pages, i18n) => {
|
|
10569
|
+
var i18nDiagnostics = (pages, i18n, versions) => {
|
|
10324
10570
|
const configured = new Set(i18n.locales.map((locale) => locale.code.toLowerCase()));
|
|
10571
|
+
const versionDirs = new Set(versions?.archived.map((version) => version.id));
|
|
10325
10572
|
const seen = new Set;
|
|
10326
10573
|
const diagnostics = [];
|
|
10327
10574
|
for (const page of pages) {
|
|
10328
|
-
const
|
|
10575
|
+
const parts = page.source.ref.split("/");
|
|
10576
|
+
const first = (parts[0] && versionDirs.has(parts[0]) ? parts[1] : parts[0])?.toLowerCase();
|
|
10329
10577
|
if (first && !seen.has(first) && KNOWN_LOCALES.has(first) && !configured.has(first)) {
|
|
10330
10578
|
seen.add(first);
|
|
10331
10579
|
diagnostics.push({
|
|
@@ -10381,7 +10629,7 @@ var resolveIcon = (name) => {
|
|
|
10381
10629
|
var hasIcon = (name) => resolveIcon(name) !== null;
|
|
10382
10630
|
|
|
10383
10631
|
// src/core/nav-diagnostics.ts
|
|
10384
|
-
var
|
|
10632
|
+
var ICON_FORMAT_HINT = "Use a built-in icon name, an image path/URL, or inline SVG markup.";
|
|
10385
10633
|
var flattenNodes = (nodes) => nodes.flatMap((node) => node.kind === "group" ? [node, ...flattenNodes(node.children)] : [node]);
|
|
10386
10634
|
var collectIcons = (navigation) => {
|
|
10387
10635
|
const icons = [];
|
|
@@ -10430,10 +10678,10 @@ var unknownIconDiagnostics = (icons, suggestion) => {
|
|
|
10430
10678
|
}
|
|
10431
10679
|
return diagnostics;
|
|
10432
10680
|
};
|
|
10433
|
-
var validateNavIcons = (navigation) => unknownIconDiagnostics(collectIcons(navigation),
|
|
10681
|
+
var validateNavIcons = (navigation) => unknownIconDiagnostics(collectIcons(navigation), ICON_FORMAT_HINT);
|
|
10434
10682
|
var validateSearchPopularIcons = (popular) => {
|
|
10435
10683
|
const icons = popular.flatMap((link) => link.icon ? [{ icon: link.icon, where: `popular link "${link.label}"` }] : []);
|
|
10436
|
-
return unknownIconDiagnostics(icons,
|
|
10684
|
+
return unknownIconDiagnostics(icons, ICON_FORMAT_HINT);
|
|
10437
10685
|
};
|
|
10438
10686
|
var resolvesToPages = (routes, path) => routes.has(path) || [...routes].some((route) => route.startsWith(`${path}/`));
|
|
10439
10687
|
var validateNavTargets = (navigation, routes) => {
|
|
@@ -10537,6 +10785,8 @@ var segmentKey = (raw) => {
|
|
|
10537
10785
|
return (group ?? raw).replace(NUMERIC_PREFIX, "");
|
|
10538
10786
|
};
|
|
10539
10787
|
var isIndexStem = (stem) => stem.replace(NUMERIC_PREFIX, "") === "index";
|
|
10788
|
+
var stemOf = (filename) => filename.replace(extname(filename), "");
|
|
10789
|
+
var navStem = (navPath) => stemOf(navPath.split("/").at(-1) ?? navPath);
|
|
10540
10790
|
var createGroup = (key, path, label, order) => ({
|
|
10541
10791
|
children: [],
|
|
10542
10792
|
index: new Map,
|
|
@@ -10561,7 +10811,7 @@ var pageOrder = (page, filename) => {
|
|
|
10561
10811
|
if (page.meta.sidebar.order !== undefined) {
|
|
10562
10812
|
return { order: page.meta.sidebar.order, orderIsAuthored: true };
|
|
10563
10813
|
}
|
|
10564
|
-
if (isIndexStem(
|
|
10814
|
+
if (isIndexStem(stemOf(filename))) {
|
|
10565
10815
|
return { order: Number.NEGATIVE_INFINITY, orderIsAuthored: false };
|
|
10566
10816
|
}
|
|
10567
10817
|
if (page.contentType === "changelog") {
|
|
@@ -10583,8 +10833,9 @@ var metaKey = (path, metaPrefix) => {
|
|
|
10583
10833
|
}
|
|
10584
10834
|
return path ? `${metaPrefix}/${path}` : metaPrefix;
|
|
10585
10835
|
};
|
|
10586
|
-
var applyFolderMeta = (group, folderMeta, sharedMeta, metaPrefix) => {
|
|
10587
|
-
const meta = folderMeta.get(metaKey(group.path, metaPrefix)) ?? sharedMeta.get(group.path);
|
|
10836
|
+
var applyFolderMeta = (group, folderMeta, sharedMeta, metaPrefix, sharedMetaPrefix, indexDisplay) => {
|
|
10837
|
+
const meta = folderMeta.get(metaKey(group.path, metaPrefix)) ?? sharedMeta.get(metaKey(group.path, sharedMetaPrefix));
|
|
10838
|
+
group.display = indexDisplay.get(group.path) ?? meta?.display;
|
|
10588
10839
|
if (meta) {
|
|
10589
10840
|
group.label = meta.title ?? group.label;
|
|
10590
10841
|
group.icon = meta.icon ?? group.icon;
|
|
@@ -10605,15 +10856,15 @@ var applyFolderMeta = (group, folderMeta, sharedMeta, metaPrefix) => {
|
|
|
10605
10856
|
}
|
|
10606
10857
|
for (const child of group.children) {
|
|
10607
10858
|
if (child.kind === "group") {
|
|
10608
|
-
applyFolderMeta(child, folderMeta, sharedMeta, metaPrefix);
|
|
10859
|
+
applyFolderMeta(child, folderMeta, sharedMeta, metaPrefix, sharedMetaPrefix, indexDisplay);
|
|
10609
10860
|
}
|
|
10610
10861
|
}
|
|
10611
10862
|
};
|
|
10612
|
-
var indexTitleMismatchDiagnostic = (page, folderPath, folderMeta, sharedMeta, metaPrefix) => {
|
|
10863
|
+
var indexTitleMismatchDiagnostic = (page, folderPath, folderMeta, sharedMeta, metaPrefix, sharedMetaPrefix) => {
|
|
10613
10864
|
if (!page.meta.title || page.fallback || folderPath === "") {
|
|
10614
10865
|
return;
|
|
10615
10866
|
}
|
|
10616
|
-
const meta = folderMeta.get(metaKey(folderPath, metaPrefix)) ?? sharedMeta.get(folderPath);
|
|
10867
|
+
const meta = folderMeta.get(metaKey(folderPath, metaPrefix)) ?? sharedMeta.get(metaKey(folderPath, sharedMetaPrefix));
|
|
10617
10868
|
if (!meta?.title || meta.title === page.title) {
|
|
10618
10869
|
return;
|
|
10619
10870
|
}
|
|
@@ -10625,6 +10876,46 @@ var indexTitleMismatchDiagnostic = (page, folderPath, folderMeta, sharedMeta, me
|
|
|
10625
10876
|
suggestion: `Update the page's frontmatter title to match ("${meta.title}"), or leave it if the divergence is intentional.`
|
|
10626
10877
|
};
|
|
10627
10878
|
};
|
|
10879
|
+
var sidebarDisplayIgnoredDiagnostics = (pages, explicitSidebar) => {
|
|
10880
|
+
const diagnostics = [];
|
|
10881
|
+
for (const page of pages) {
|
|
10882
|
+
if (!page.meta.sidebar.display) {
|
|
10883
|
+
continue;
|
|
10884
|
+
}
|
|
10885
|
+
const isIndex = isIndexStem(navStem(page.navPath));
|
|
10886
|
+
if (explicitSidebar) {
|
|
10887
|
+
diagnostics.push({
|
|
10888
|
+
code: "BLUME_SIDEBAR_DISPLAY_IGNORED",
|
|
10889
|
+
file: page.sourcePath ?? page.id,
|
|
10890
|
+
message: `"${page.navPath}" sets sidebar.display, but the explicit navigation.sidebar config owns each group's display mode — the value is ignored.`,
|
|
10891
|
+
severity: "warning",
|
|
10892
|
+
suggestion: "Set display on the matching group in navigation.sidebar, or remove the frontmatter key."
|
|
10893
|
+
});
|
|
10894
|
+
continue;
|
|
10895
|
+
}
|
|
10896
|
+
if (isIndex && !page.navPath.includes("/")) {
|
|
10897
|
+
diagnostics.push({
|
|
10898
|
+
code: "BLUME_SIDEBAR_DISPLAY_IGNORED",
|
|
10899
|
+
file: page.sourcePath ?? page.id,
|
|
10900
|
+
message: `"${page.navPath}" sets sidebar.display, but the content root is not a sidebar group — the value is ignored.`,
|
|
10901
|
+
severity: "warning",
|
|
10902
|
+
suggestion: "Set navigation.sidebar.display in blume.config to change the sidebar-wide mode."
|
|
10903
|
+
});
|
|
10904
|
+
continue;
|
|
10905
|
+
}
|
|
10906
|
+
if (isIndex) {
|
|
10907
|
+
continue;
|
|
10908
|
+
}
|
|
10909
|
+
diagnostics.push({
|
|
10910
|
+
code: "BLUME_SIDEBAR_DISPLAY_IGNORED",
|
|
10911
|
+
file: page.sourcePath ?? page.id,
|
|
10912
|
+
message: `"${page.navPath}" sets sidebar.display, but only a folder's index page can set its group's display mode — the value is ignored.`,
|
|
10913
|
+
severity: "warning",
|
|
10914
|
+
suggestion: "Move display to the folder's index page frontmatter, or set it in the folder's meta.ts."
|
|
10915
|
+
});
|
|
10916
|
+
}
|
|
10917
|
+
return diagnostics;
|
|
10918
|
+
};
|
|
10628
10919
|
var isAuthoredOrder = (node) => node.kind === "group" || node.orderIsAuthored;
|
|
10629
10920
|
var duplicateOrderDiagnostics = (nodes) => {
|
|
10630
10921
|
const byOrder = new Map;
|
|
@@ -10671,25 +10962,25 @@ var sortNodes = (nodes, diagnostics) => {
|
|
|
10671
10962
|
}
|
|
10672
10963
|
}
|
|
10673
10964
|
};
|
|
10674
|
-
var hoistPages = (nodes,
|
|
10675
|
-
const pages = nodes.filter((node) => node.kind === "page");
|
|
10965
|
+
var hoistPages = (nodes, display, hoist) => {
|
|
10676
10966
|
const groups = nodes.filter((node) => node.kind === "group");
|
|
10677
|
-
|
|
10678
|
-
|
|
10679
|
-
|
|
10680
|
-
|
|
10681
|
-
|
|
10967
|
+
if (hoist || groups.some((group) => (group.display ?? display) === "flat")) {
|
|
10968
|
+
const pages = nodes.filter((node) => node.kind === "page");
|
|
10969
|
+
nodes.splice(0, nodes.length, ...pages, ...groups);
|
|
10970
|
+
}
|
|
10971
|
+
for (const group of groups) {
|
|
10972
|
+
hoistPages(group.children, display, false);
|
|
10682
10973
|
}
|
|
10683
10974
|
};
|
|
10684
|
-
var hoistTabSections = (nodes, tabPaths,
|
|
10975
|
+
var hoistTabSections = (nodes, tabPaths, display) => {
|
|
10685
10976
|
for (const node of nodes) {
|
|
10686
10977
|
if (node.kind !== "group") {
|
|
10687
10978
|
continue;
|
|
10688
10979
|
}
|
|
10689
10980
|
if (node.routePath !== undefined && tabPaths.has(node.routePath)) {
|
|
10690
|
-
hoistPages(node.children,
|
|
10981
|
+
hoistPages(node.children, display, true);
|
|
10691
10982
|
}
|
|
10692
|
-
hoistTabSections(node.children, tabPaths,
|
|
10983
|
+
hoistTabSections(node.children, tabPaths, display);
|
|
10693
10984
|
}
|
|
10694
10985
|
};
|
|
10695
10986
|
var toNavNode = (node, display) => {
|
|
@@ -10708,25 +10999,29 @@ var toNavNode = (node, display) => {
|
|
|
10708
10999
|
return {
|
|
10709
11000
|
children: node.children.map((child) => toNavNode(child, display)),
|
|
10710
11001
|
collapsed: node.collapsed,
|
|
10711
|
-
display,
|
|
11002
|
+
display: node.display ?? display,
|
|
10712
11003
|
icon: node.icon,
|
|
10713
11004
|
kind: "group",
|
|
10714
11005
|
label: node.label,
|
|
10715
11006
|
path: node.routePath
|
|
10716
11007
|
};
|
|
10717
11008
|
};
|
|
10718
|
-
var buildFileSystemSidebar = (pages, folderMeta, sharedMeta, metaPrefix, display, tabPaths, diagnostics = []) => {
|
|
11009
|
+
var buildFileSystemSidebar = (pages, folderMeta, sharedMeta, metaPrefix, sharedMetaPrefix, display, tabPaths, diagnostics = []) => {
|
|
10719
11010
|
const root = createGroup("", "", "", 0);
|
|
11011
|
+
const indexDisplay = new Map;
|
|
10720
11012
|
for (const page of pages) {
|
|
10721
11013
|
const parts = page.navPath.split("/");
|
|
10722
11014
|
const filename = parts.at(-1) ?? page.navPath;
|
|
10723
|
-
const stem =
|
|
11015
|
+
const stem = stemOf(filename);
|
|
10724
11016
|
const dirs = parts.slice(0, -1);
|
|
10725
11017
|
if (isIndexStem(stem)) {
|
|
10726
|
-
const diagnostic = indexTitleMismatchDiagnostic(page, dirs.join("/"), folderMeta, sharedMeta, metaPrefix);
|
|
11018
|
+
const diagnostic = indexTitleMismatchDiagnostic(page, dirs.join("/"), folderMeta, sharedMeta, metaPrefix, sharedMetaPrefix);
|
|
10727
11019
|
if (diagnostic) {
|
|
10728
11020
|
diagnostics.push(diagnostic);
|
|
10729
11021
|
}
|
|
11022
|
+
if (page.meta.sidebar.display && !page.fallback) {
|
|
11023
|
+
indexDisplay.set(dirs.join("/"), page.meta.sidebar.display);
|
|
11024
|
+
}
|
|
10730
11025
|
}
|
|
10731
11026
|
if (page.meta.sidebar.hidden) {
|
|
10732
11027
|
continue;
|
|
@@ -10760,10 +11055,10 @@ var buildFileSystemSidebar = (pages, folderMeta, sharedMeta, metaPrefix, display
|
|
|
10760
11055
|
route: page.route
|
|
10761
11056
|
});
|
|
10762
11057
|
}
|
|
10763
|
-
applyFolderMeta(root, folderMeta, sharedMeta, metaPrefix);
|
|
11058
|
+
applyFolderMeta(root, folderMeta, sharedMeta, metaPrefix, sharedMetaPrefix, indexDisplay);
|
|
10764
11059
|
sortNodes(root.children, diagnostics);
|
|
10765
|
-
hoistPages(root.children, display
|
|
10766
|
-
hoistTabSections(root.children, tabPaths, display
|
|
11060
|
+
hoistPages(root.children, display, true);
|
|
11061
|
+
hoistTabSections(root.children, tabPaths, display);
|
|
10767
11062
|
return root.children.map((child) => toNavNode(child, display));
|
|
10768
11063
|
};
|
|
10769
11064
|
var normalizeRef = (ref) => {
|
|
@@ -10782,8 +11077,9 @@ var routeForRef = (ref, byRoute, basePath) => {
|
|
|
10782
11077
|
const normalized = normalizeRef(ref);
|
|
10783
11078
|
return byRoute.get(normalized)?.route ?? withBasePath(basePath, normalized);
|
|
10784
11079
|
};
|
|
11080
|
+
var isPageRef = (item) => typeof item === "string";
|
|
10785
11081
|
var configItemToNode = (item, byRoute, basePath) => {
|
|
10786
|
-
if (
|
|
11082
|
+
if (isPageRef(item)) {
|
|
10787
11083
|
const page = byRoute.get(normalizeRef(item));
|
|
10788
11084
|
if (!page) {
|
|
10789
11085
|
return null;
|
|
@@ -10826,7 +11122,7 @@ var configItemToNode = (item, byRoute, basePath) => {
|
|
|
10826
11122
|
var buildConfigSidebar = (items, byRoute, display, basePath) => {
|
|
10827
11123
|
const nodes = [];
|
|
10828
11124
|
for (const item of items) {
|
|
10829
|
-
if (
|
|
11125
|
+
if (!isPageRef(item) && item.items) {
|
|
10830
11126
|
nodes.push({
|
|
10831
11127
|
badge: item.badge,
|
|
10832
11128
|
children: buildConfigSidebar(item.items, byRoute, display, basePath),
|
|
@@ -10870,29 +11166,46 @@ var withTabHrefs = (tabs, sidebar) => tabs.map((tab) => {
|
|
|
10870
11166
|
const href = tab.href ?? resolveTabHref(sidebar, tab.path);
|
|
10871
11167
|
return href === tab.path ? tab : { ...tab, href };
|
|
10872
11168
|
});
|
|
11169
|
+
var rebaseNavChrome = (basePath, options) => {
|
|
11170
|
+
const featured = options.featured ?? [];
|
|
11171
|
+
const selectors = options.selectors ?? [];
|
|
11172
|
+
const tabs = options.tabs ?? [];
|
|
11173
|
+
if (!basePath) {
|
|
11174
|
+
return { featured, selectors, tabs };
|
|
11175
|
+
}
|
|
11176
|
+
const rebasePath = (item) => ({
|
|
11177
|
+
...item,
|
|
11178
|
+
path: withBasePath(basePath, item.path)
|
|
11179
|
+
});
|
|
11180
|
+
return {
|
|
11181
|
+
featured: featured.map((link) => ({
|
|
11182
|
+
...link,
|
|
11183
|
+
href: withBasePath(basePath, link.href)
|
|
11184
|
+
})),
|
|
11185
|
+
selectors: selectors.map((selector) => ({
|
|
11186
|
+
...selector,
|
|
11187
|
+
items: selector.items.map(rebasePath)
|
|
11188
|
+
})),
|
|
11189
|
+
tabs: tabs.map((tab) => {
|
|
11190
|
+
const rebased = {
|
|
11191
|
+
...tab,
|
|
11192
|
+
items: tab.items?.map(rebasePath),
|
|
11193
|
+
path: withBasePath(basePath, tab.path)
|
|
11194
|
+
};
|
|
11195
|
+
if (tab.href) {
|
|
11196
|
+
rebased.href = withBasePath(basePath, tab.href);
|
|
11197
|
+
}
|
|
11198
|
+
return rebased;
|
|
11199
|
+
})
|
|
11200
|
+
};
|
|
11201
|
+
};
|
|
10873
11202
|
var buildNavigation = (pages, options) => {
|
|
10874
11203
|
const basePath = options.basePath ?? "";
|
|
10875
11204
|
const display = options.display ?? "flat";
|
|
10876
11205
|
const metaPrefix = options.metaPrefix ?? "";
|
|
11206
|
+
const sharedMetaPrefix = options.sharedMetaPrefix ?? "";
|
|
10877
11207
|
const sharedFolderMeta = options.sharedFolderMeta ?? new Map;
|
|
10878
|
-
const
|
|
10879
|
-
...item,
|
|
10880
|
-
path: withBasePath(basePath, item.path)
|
|
10881
|
-
});
|
|
10882
|
-
const featured = basePath ? (options.featured ?? []).map((link) => ({
|
|
10883
|
-
...link,
|
|
10884
|
-
href: withBasePath(basePath, link.href)
|
|
10885
|
-
})) : options.featured ?? [];
|
|
10886
|
-
const selectors = basePath ? (options.selectors ?? []).map((selector) => ({
|
|
10887
|
-
...selector,
|
|
10888
|
-
items: selector.items.map(rebasePath)
|
|
10889
|
-
})) : options.selectors ?? [];
|
|
10890
|
-
const tabs = basePath ? (options.tabs ?? []).map((tab) => ({
|
|
10891
|
-
...tab,
|
|
10892
|
-
...tab.href ? { href: withBasePath(basePath, tab.href) } : {},
|
|
10893
|
-
items: tab.items?.map(rebasePath),
|
|
10894
|
-
path: withBasePath(basePath, tab.path)
|
|
10895
|
-
})) : options.tabs ?? [];
|
|
11208
|
+
const { featured, selectors, tabs } = rebaseNavChrome(basePath, options);
|
|
10896
11209
|
const byRoute = new Map(pages.map((page) => [
|
|
10897
11210
|
options.refByLogical ? page.translationKey : page.route,
|
|
10898
11211
|
page
|
|
@@ -10906,6 +11219,8 @@ var buildNavigation = (pages, options) => {
|
|
|
10906
11219
|
}
|
|
10907
11220
|
}
|
|
10908
11221
|
const rootTabPath = withBasePath(basePath, options.localizedRoot ?? "/");
|
|
11222
|
+
const diagnostics = options.diagnostics ?? [];
|
|
11223
|
+
diagnostics.push(...sidebarDisplayIgnoredDiagnostics(pages, Boolean(options.sidebar)));
|
|
10909
11224
|
if (options.sidebar) {
|
|
10910
11225
|
const sidebar2 = buildConfigSidebar(options.sidebar, byRoute, display, basePath);
|
|
10911
11226
|
return {
|
|
@@ -10916,7 +11231,7 @@ var buildNavigation = (pages, options) => {
|
|
|
10916
11231
|
tabs: withTabHrefs(tabs, sidebar2)
|
|
10917
11232
|
};
|
|
10918
11233
|
}
|
|
10919
|
-
const sidebar = buildFileSystemSidebar(pages, options.folderMeta, sharedFolderMeta, metaPrefix, display, new Set(tabs.flatMap((tab) => tab.path === rootTabPath ? [] : [tab.path])),
|
|
11234
|
+
const sidebar = buildFileSystemSidebar(pages, options.folderMeta, sharedFolderMeta, metaPrefix, sharedMetaPrefix, display, new Set(tabs.flatMap((tab) => tab.path === rootTabPath ? [] : [tab.path])), diagnostics);
|
|
10920
11235
|
return {
|
|
10921
11236
|
featured,
|
|
10922
11237
|
root: rootTabPath,
|
|
@@ -10926,6 +11241,44 @@ var buildNavigation = (pages, options) => {
|
|
|
10926
11241
|
};
|
|
10927
11242
|
};
|
|
10928
11243
|
|
|
11244
|
+
// src/core/versions.ts
|
|
11245
|
+
var VERSION_LIKE = /^v\d/iu;
|
|
11246
|
+
var detectVersion = (parts, versions) => {
|
|
11247
|
+
const [first] = parts;
|
|
11248
|
+
if (first && versions.archived.some((version) => version.id === first)) {
|
|
11249
|
+
return { rest: parts.slice(1), version: first };
|
|
11250
|
+
}
|
|
11251
|
+
return { rest: parts, version: "" };
|
|
11252
|
+
};
|
|
11253
|
+
var detectVersionRef = (ref, versions) => {
|
|
11254
|
+
const { version, rest } = detectVersion(ref.split("/"), versions);
|
|
11255
|
+
return { rest: rest.join("/"), version };
|
|
11256
|
+
};
|
|
11257
|
+
var versionizeRoute = (logicalRoute, version) => {
|
|
11258
|
+
if (!version) {
|
|
11259
|
+
return logicalRoute;
|
|
11260
|
+
}
|
|
11261
|
+
return logicalRoute === "/" ? `/${version}` : `/${version}${logicalRoute}`;
|
|
11262
|
+
};
|
|
11263
|
+
var versionsDiagnostics = (pages, versions) => {
|
|
11264
|
+
const configured = new Set(versions.archived.map((version) => version.id));
|
|
11265
|
+
const seen = new Set;
|
|
11266
|
+
const diagnostics = [];
|
|
11267
|
+
for (const page of pages) {
|
|
11268
|
+
const [first] = page.source.ref.split("/");
|
|
11269
|
+
if (first && !seen.has(first) && VERSION_LIKE.test(first) && !configured.has(first)) {
|
|
11270
|
+
seen.add(first);
|
|
11271
|
+
diagnostics.push({
|
|
11272
|
+
code: "BLUME_VERSIONS_UNCONFIGURED_VERSION",
|
|
11273
|
+
message: `Folder "${first}/" looks like a version, but "${first}" is not in versions.archived — its pages are treated as current-version content at /${first}/….`,
|
|
11274
|
+
severity: "warning",
|
|
11275
|
+
suggestion: `Add { id: "${first}" } to versions.archived, or rename the folder if it isn't a snapshot.`
|
|
11276
|
+
});
|
|
11277
|
+
}
|
|
11278
|
+
}
|
|
11279
|
+
return diagnostics;
|
|
11280
|
+
};
|
|
11281
|
+
|
|
10929
11282
|
// src/core/graph.ts
|
|
10930
11283
|
var collectRoutes = (pages) => {
|
|
10931
11284
|
const routes = new Map;
|
|
@@ -10964,8 +11317,9 @@ var localePagesFor = (code, real, fallback, fallbackByKey, i18n, basePath) => {
|
|
|
10964
11317
|
}
|
|
10965
11318
|
return [...real, ...filled];
|
|
10966
11319
|
};
|
|
11320
|
+
var isSingleLabel = (label) => typeof label === "string";
|
|
10967
11321
|
var resolveLabel = (label, locale, defaultLocale) => {
|
|
10968
|
-
if (
|
|
11322
|
+
if (isSingleLabel(label)) {
|
|
10969
11323
|
return label;
|
|
10970
11324
|
}
|
|
10971
11325
|
return label[locale] ?? (defaultLocale === undefined ? undefined : label[defaultLocale]) ?? Object.values(label)[0] ?? "";
|
|
@@ -10978,19 +11332,25 @@ var resolveTabLabels = (tabs, locale, defaultLocale) => (tabs ?? []).map((tab) =
|
|
|
10978
11332
|
})),
|
|
10979
11333
|
label: resolveLabel(tab.label, locale, defaultLocale)
|
|
10980
11334
|
}));
|
|
10981
|
-
var buildLocaleNavigation = (code, pages, fallback, fallbackByKey, options, i18n, diagnostics) => {
|
|
11335
|
+
var buildLocaleNavigation = (code, pages, fallback, fallbackByKey, options, i18n, diagnostics, version = "") => {
|
|
10982
11336
|
const localizePath = (path) => path.startsWith("/") ? localizeRoute(path, code, i18n) : path;
|
|
10983
|
-
const tabs = resolveTabLabels(options.navigation.tabs, code, i18n.defaultLocale).map((tab) =>
|
|
10984
|
-
|
|
10985
|
-
|
|
10986
|
-
|
|
10987
|
-
|
|
10988
|
-
|
|
10989
|
-
|
|
10990
|
-
|
|
10991
|
-
|
|
11337
|
+
const tabs = resolveTabLabels(options.navigation.tabs, code, i18n.defaultLocale).map((tab) => {
|
|
11338
|
+
const localized = {
|
|
11339
|
+
...tab,
|
|
11340
|
+
items: tab.items?.map((item) => ({
|
|
11341
|
+
...item,
|
|
11342
|
+
path: localizePath(item.path)
|
|
11343
|
+
})),
|
|
11344
|
+
path: localizePath(tab.path)
|
|
11345
|
+
};
|
|
11346
|
+
if (localized.href) {
|
|
11347
|
+
localized.href = localizePath(localized.href);
|
|
11348
|
+
}
|
|
11349
|
+
return localized;
|
|
11350
|
+
});
|
|
10992
11351
|
const real = pages.filter((page) => page.locale === code);
|
|
10993
11352
|
const localePages = localePagesFor(code, real, fallback, fallbackByKey, i18n, options.basePath ?? "");
|
|
11353
|
+
const localeDir = i18n.parser === "dir" && code !== i18n.defaultLocale ? code : "";
|
|
10994
11354
|
return buildNavigation(localePages, {
|
|
10995
11355
|
basePath: options.basePath ?? "",
|
|
10996
11356
|
diagnostics,
|
|
@@ -11000,16 +11360,17 @@ var buildLocaleNavigation = (code, pages, fallback, fallbackByKey, options, i18n
|
|
|
11000
11360
|
href: localizePath(link.href)
|
|
11001
11361
|
})),
|
|
11002
11362
|
folderMeta: options.folderMeta,
|
|
11003
|
-
localizedRoot: localizeRoute("/", code, i18n),
|
|
11004
|
-
metaPrefix:
|
|
11363
|
+
localizedRoot: localizeRoute(versionizeRoute("/", version), code, i18n),
|
|
11364
|
+
metaPrefix: [version, localeDir].filter(Boolean).join("/"),
|
|
11005
11365
|
refByLogical: true,
|
|
11006
11366
|
selectors: options.navigation.selectors,
|
|
11007
11367
|
sharedFolderMeta: options.sharedFolderMeta,
|
|
11008
|
-
|
|
11368
|
+
sharedMetaPrefix: version,
|
|
11369
|
+
sidebar: version ? undefined : options.navigation.sidebar.items,
|
|
11009
11370
|
tabs
|
|
11010
11371
|
});
|
|
11011
11372
|
};
|
|
11012
|
-
var buildI18nNavigation = (pages, options, i18n, diagnostics) => {
|
|
11373
|
+
var buildI18nNavigation = (pages, options, i18n, diagnostics, version = "") => {
|
|
11013
11374
|
const fallback = resolveFallbackLocale(i18n);
|
|
11014
11375
|
const fallbackByKey = new Map;
|
|
11015
11376
|
if (fallback) {
|
|
@@ -11023,7 +11384,7 @@ var buildI18nNavigation = (pages, options, i18n, diagnostics) => {
|
|
|
11023
11384
|
const seen = new Set;
|
|
11024
11385
|
for (const { code } of i18n.locales) {
|
|
11025
11386
|
const localeDiagnostics = [];
|
|
11026
|
-
navigationByLocale[code] = buildLocaleNavigation(code, pages, fallback, fallbackByKey, options, i18n, localeDiagnostics);
|
|
11387
|
+
navigationByLocale[code] = buildLocaleNavigation(code, pages, fallback, fallbackByKey, options, i18n, localeDiagnostics, version);
|
|
11027
11388
|
for (const diagnostic of localeDiagnostics) {
|
|
11028
11389
|
const key = `${diagnostic.code}
|
|
11029
11390
|
${diagnostic.file ?? ""}
|
|
@@ -11042,11 +11403,37 @@ ${diagnostic.message}`;
|
|
|
11042
11403
|
};
|
|
11043
11404
|
return { navigation, navigationByLocale };
|
|
11044
11405
|
};
|
|
11406
|
+
var buildVersionNavigation = (id2, versionPages, options, diagnostics) => {
|
|
11407
|
+
const { i18n } = options;
|
|
11408
|
+
if (i18n) {
|
|
11409
|
+
return buildI18nNavigation(versionPages, options, i18n, diagnostics, id2).navigationByLocale;
|
|
11410
|
+
}
|
|
11411
|
+
return {
|
|
11412
|
+
"": buildNavigation(versionPages, {
|
|
11413
|
+
basePath: options.basePath ?? "",
|
|
11414
|
+
diagnostics,
|
|
11415
|
+
display: options.navigation.sidebar.display,
|
|
11416
|
+
featured: options.navigation.featured,
|
|
11417
|
+
folderMeta: options.folderMeta,
|
|
11418
|
+
localizedRoot: versionizeRoute("/", id2),
|
|
11419
|
+
metaPrefix: id2,
|
|
11420
|
+
selectors: options.navigation.selectors,
|
|
11421
|
+
sharedFolderMeta: options.sharedFolderMeta,
|
|
11422
|
+
sharedMetaPrefix: id2,
|
|
11423
|
+
tabs: resolveTabLabels(options.navigation.tabs, "")
|
|
11424
|
+
})
|
|
11425
|
+
};
|
|
11426
|
+
};
|
|
11045
11427
|
var buildContentGraph = (pages, options) => {
|
|
11046
11428
|
const { diagnostics, routes } = collectRoutes(pages);
|
|
11047
11429
|
const { i18n } = options;
|
|
11048
|
-
const
|
|
11049
|
-
|
|
11430
|
+
const currentPages = options.versions ? pages.filter((page) => page.version === "") : pages;
|
|
11431
|
+
let navigationByLocale = {};
|
|
11432
|
+
let navigation;
|
|
11433
|
+
if (i18n) {
|
|
11434
|
+
({ navigation, navigationByLocale } = buildI18nNavigation(currentPages, options, i18n, diagnostics));
|
|
11435
|
+
} else {
|
|
11436
|
+
navigation = buildNavigation(currentPages, {
|
|
11050
11437
|
basePath: options.basePath ?? "",
|
|
11051
11438
|
diagnostics,
|
|
11052
11439
|
display: options.navigation.sidebar.display,
|
|
@@ -11056,14 +11443,18 @@ var buildContentGraph = (pages, options) => {
|
|
|
11056
11443
|
sharedFolderMeta: options.sharedFolderMeta,
|
|
11057
11444
|
sidebar: options.navigation.sidebar.items,
|
|
11058
11445
|
tabs: resolveTabLabels(options.navigation.tabs, "")
|
|
11059
|
-
})
|
|
11060
|
-
|
|
11061
|
-
};
|
|
11062
|
-
|
|
11446
|
+
});
|
|
11447
|
+
}
|
|
11448
|
+
const navigationByVersion = {};
|
|
11449
|
+
for (const { id: id2 } of options.versions?.archived ?? []) {
|
|
11450
|
+
navigationByVersion[id2] = buildVersionNavigation(id2, pages.filter((page) => page.version === id2), options, diagnostics);
|
|
11451
|
+
}
|
|
11452
|
+
diagnostics.push(...validateNavIcons(navigation), ...validateNavStructure(navigation, currentPages));
|
|
11063
11453
|
return {
|
|
11064
11454
|
diagnostics,
|
|
11065
11455
|
navigation,
|
|
11066
11456
|
navigationByLocale,
|
|
11457
|
+
navigationByVersion,
|
|
11067
11458
|
pages,
|
|
11068
11459
|
routes
|
|
11069
11460
|
};
|
|
@@ -11124,11 +11515,42 @@ var gitLastModifiedTimes = (root, contentRoots, sourcePaths) => {
|
|
|
11124
11515
|
return new Map;
|
|
11125
11516
|
}
|
|
11126
11517
|
};
|
|
11518
|
+
var isShallowGitRepository = (root) => {
|
|
11519
|
+
try {
|
|
11520
|
+
return execFileSync("git", ["-C", root, "rev-parse", "--is-shallow-repository"], { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }).trim() === "true";
|
|
11521
|
+
} catch {
|
|
11522
|
+
return false;
|
|
11523
|
+
}
|
|
11524
|
+
};
|
|
11525
|
+
var lastModifiedShallowWarning = (root, undatedCount) => {
|
|
11526
|
+
if (undatedCount === 0 || !isShallowGitRepository(root)) {
|
|
11527
|
+
return [];
|
|
11528
|
+
}
|
|
11529
|
+
return [
|
|
11530
|
+
{
|
|
11531
|
+
code: "BLUME_SHALLOW_GIT_HISTORY",
|
|
11532
|
+
message: `lastModified is on, but this build runs in a shallow git clone, so ${undatedCount} page(s) have no git-derived date — their sitemap <lastmod> and "Last updated" stamps are omitted.`,
|
|
11533
|
+
severity: "warning",
|
|
11534
|
+
suggestion: "Fetch full history in CI: set the VERCEL_DEEP_CLONE=true environment variable on Vercel, or fetch-depth: 0 for actions/checkout."
|
|
11535
|
+
}
|
|
11536
|
+
];
|
|
11537
|
+
};
|
|
11127
11538
|
|
|
11128
11539
|
// src/core/manifest.ts
|
|
11540
|
+
var versionAlternateKey = (versionKey, locale) => `${versionKey}\x00${locale}`;
|
|
11541
|
+
var versionAlternatesFor = (byKey, versionKey, locale) => {
|
|
11542
|
+
const key = versionAlternateKey(versionKey, locale);
|
|
11543
|
+
const existing = byKey.get(key);
|
|
11544
|
+
if (existing) {
|
|
11545
|
+
return existing;
|
|
11546
|
+
}
|
|
11547
|
+
const list2 = [];
|
|
11548
|
+
byKey.set(key, list2);
|
|
11549
|
+
return list2;
|
|
11550
|
+
};
|
|
11129
11551
|
var MANIFEST_VERSION = 1;
|
|
11130
11552
|
var contentIndexable = (page, config) => !page.meta.search.exclude && (!page.meta.sidebar.hidden || config.search.indexing.includeHiddenPages);
|
|
11131
|
-
var buildFallbackRoutes = (graph, i18n, alternatesByKey, basePath) => {
|
|
11553
|
+
var buildFallbackRoutes = (graph, i18n, alternatesByKey, basePath, versionAlternatesByKey) => {
|
|
11132
11554
|
const fallback = resolveFallbackLocale(i18n);
|
|
11133
11555
|
if (!fallback) {
|
|
11134
11556
|
return [];
|
|
@@ -11144,6 +11566,11 @@ var buildFallbackRoutes = (graph, i18n, alternatesByKey, basePath) => {
|
|
|
11144
11566
|
if (present.has(key)) {
|
|
11145
11567
|
continue;
|
|
11146
11568
|
}
|
|
11569
|
+
const path = withBasePath(basePath, localizeRoute(key, code, i18n));
|
|
11570
|
+
const versionAlternates = versionAlternatesByKey ? versionAlternatesFor(versionAlternatesByKey, source.versionKey, code) : [];
|
|
11571
|
+
if (versionAlternatesByKey) {
|
|
11572
|
+
versionAlternates.push({ path, version: source.version });
|
|
11573
|
+
}
|
|
11147
11574
|
routes.push({
|
|
11148
11575
|
alternates: alternatesByKey.get(key) ?? [],
|
|
11149
11576
|
collection: source.collection ?? "docs",
|
|
@@ -11157,10 +11584,12 @@ var buildFallbackRoutes = (graph, i18n, alternatesByKey, basePath) => {
|
|
|
11157
11584
|
indexable: false,
|
|
11158
11585
|
lastModified: source.lastModified,
|
|
11159
11586
|
locale: code,
|
|
11160
|
-
path
|
|
11587
|
+
path,
|
|
11161
11588
|
source: source.source,
|
|
11162
11589
|
sourcePath: source.sourcePath,
|
|
11163
|
-
title: source.title
|
|
11590
|
+
title: source.title,
|
|
11591
|
+
version: source.version,
|
|
11592
|
+
versionAlternates
|
|
11164
11593
|
});
|
|
11165
11594
|
}
|
|
11166
11595
|
}
|
|
@@ -11178,6 +11607,12 @@ var buildManifest = (options) => {
|
|
|
11178
11607
|
alternatesByKey.set(page.translationKey, list2);
|
|
11179
11608
|
}
|
|
11180
11609
|
}
|
|
11610
|
+
const versionAlternatesByKey = config.versions ? new Map : undefined;
|
|
11611
|
+
if (versionAlternatesByKey) {
|
|
11612
|
+
for (const page of graph.pages) {
|
|
11613
|
+
versionAlternatesFor(versionAlternatesByKey, page.versionKey, page.locale).push({ path: page.route, version: page.version });
|
|
11614
|
+
}
|
|
11615
|
+
}
|
|
11181
11616
|
const routes = graph.pages.map((page) => ({
|
|
11182
11617
|
alternates: alternatesByKey.get(page.translationKey) ?? [],
|
|
11183
11618
|
collection: page.collection ?? "docs",
|
|
@@ -11193,10 +11628,18 @@ var buildManifest = (options) => {
|
|
|
11193
11628
|
path: page.route,
|
|
11194
11629
|
source: page.source,
|
|
11195
11630
|
sourcePath: page.sourcePath,
|
|
11196
|
-
title: page.title
|
|
11631
|
+
title: page.title,
|
|
11632
|
+
version: page.version,
|
|
11633
|
+
versionAlternates: versionAlternatesByKey ? versionAlternatesFor(versionAlternatesByKey, page.versionKey, page.locale) : []
|
|
11197
11634
|
}));
|
|
11198
11635
|
if (i18n) {
|
|
11199
|
-
routes.push(...buildFallbackRoutes(graph, i18n, alternatesByKey, config.basePath));
|
|
11636
|
+
routes.push(...buildFallbackRoutes(graph, i18n, alternatesByKey, config.basePath, versionAlternatesByKey));
|
|
11637
|
+
}
|
|
11638
|
+
if (versionAlternatesByKey && config.versions) {
|
|
11639
|
+
const rank = new Map(config.versions.archived.map((version, index) => [version.id, index + 1]));
|
|
11640
|
+
for (const list2 of versionAlternatesByKey.values()) {
|
|
11641
|
+
list2.sort((a, b) => (rank.get(a.version) ?? 0) - (rank.get(b.version) ?? 0));
|
|
11642
|
+
}
|
|
11200
11643
|
}
|
|
11201
11644
|
routes.sort((a, b) => a.path.localeCompare(b.path));
|
|
11202
11645
|
return {
|
|
@@ -11220,7 +11663,8 @@ var META_FILES = [
|
|
|
11220
11663
|
"**/meta.$.js",
|
|
11221
11664
|
"**/meta.$.mjs"
|
|
11222
11665
|
];
|
|
11223
|
-
var
|
|
11666
|
+
var isMetaFactory = (mod) => typeof mod === "function";
|
|
11667
|
+
var resolveMeta = async (mod) => isMetaFactory(mod) ? await mod() : mod;
|
|
11224
11668
|
var metaKeyFor = (prefix, dir) => {
|
|
11225
11669
|
const clean = prefix ? prefix.replaceAll(/^\/+|\/+$/gu, "") : "";
|
|
11226
11670
|
if (!clean) {
|
|
@@ -11229,8 +11673,9 @@ var metaKeyFor = (prefix, dir) => {
|
|
|
11229
11673
|
return dir ? `${clean}/${dir}` : clean;
|
|
11230
11674
|
};
|
|
11231
11675
|
var discoverFolderMeta = async (sources, options = {}) => {
|
|
11232
|
-
const list2 =
|
|
11676
|
+
const list2 = Array.isArray(sources) ? sources : [{ root: sources }];
|
|
11233
11677
|
const localeDirs = new Set(options.localeDirs);
|
|
11678
|
+
const versionDirs = new Set(options.versionDirs);
|
|
11234
11679
|
const load2 = createModuleLoader();
|
|
11235
11680
|
const meta = new Map;
|
|
11236
11681
|
const shared = new Map;
|
|
@@ -11259,7 +11704,12 @@ var discoverFolderMeta = async (sources, options = {}) => {
|
|
|
11259
11704
|
for (const entry of loaded) {
|
|
11260
11705
|
const dir = relative8(source.root, dirname6(entry.file));
|
|
11261
11706
|
const [head, ...tail] = dir.split("/");
|
|
11262
|
-
const
|
|
11707
|
+
const version = head && versionDirs.has(head) ? head : "";
|
|
11708
|
+
const afterVersion = version ? tail : [head ?? "", ...tail];
|
|
11709
|
+
const [localeHead, ...localeTail] = afterVersion;
|
|
11710
|
+
const locale = localeHead && localeDirs.has(localeHead) ? localeHead : "";
|
|
11711
|
+
const rest = (locale ? localeTail : afterVersion).filter(Boolean).join("/");
|
|
11712
|
+
const key = [version, locale, metaKeyFor(source.prefix, rest)].filter(Boolean).join("/");
|
|
11263
11713
|
if (!entry.ok) {
|
|
11264
11714
|
diagnostics.push({
|
|
11265
11715
|
code: "BLUME_META_LOAD_FAILED",
|
|
@@ -11331,7 +11781,7 @@ var CODE_FENCE = /^(?<delimiter>```|~~~)/u;
|
|
|
11331
11781
|
var nextFenceState = (line, fence) => {
|
|
11332
11782
|
const trimmed = line.trimStart();
|
|
11333
11783
|
const delimiter = trimmed.match(CODE_FENCE)?.groups?.delimiter;
|
|
11334
|
-
if (delimiter
|
|
11784
|
+
if (delimiter !== "```" && delimiter !== "~~~") {
|
|
11335
11785
|
return fence;
|
|
11336
11786
|
}
|
|
11337
11787
|
if (fence === null) {
|
|
@@ -11527,13 +11977,16 @@ var deriveTitle = (meta, headings, id2) => {
|
|
|
11527
11977
|
return titleCase(stripNumericPrefix(base.replace(extname2(base), "")));
|
|
11528
11978
|
};
|
|
11529
11979
|
var trimSlashes = (value) => value.replaceAll(/^\/+|\/+$/gu, "");
|
|
11980
|
+
var isStringValue = (value) => typeof value === "string";
|
|
11530
11981
|
var withPrefix = (prefix, path) => {
|
|
11531
11982
|
const clean = prefix ? trimSlashes(prefix) : "";
|
|
11532
11983
|
return clean ? `${clean}/${path}` : path;
|
|
11533
11984
|
};
|
|
11985
|
+
var isKeyCarrier = (segment) => typeof segment === "object" && segment !== null;
|
|
11986
|
+
var isSymbolKey = (key) => typeof key === "symbol";
|
|
11534
11987
|
var segmentKey2 = (segment) => {
|
|
11535
|
-
const key =
|
|
11536
|
-
return
|
|
11988
|
+
const key = isKeyCarrier(segment) ? segment.key : segment;
|
|
11989
|
+
return isSymbolKey(key) ? String(key) : key;
|
|
11537
11990
|
};
|
|
11538
11991
|
var validateCustomKeys = (data, extend) => {
|
|
11539
11992
|
const custom = {};
|
|
@@ -11564,7 +12017,7 @@ var validateCustomKeys = (data, extend) => {
|
|
|
11564
12017
|
};
|
|
11565
12018
|
};
|
|
11566
12019
|
var parseEntryMeta = (entry, ctx) => {
|
|
11567
|
-
const entryType =
|
|
12020
|
+
const entryType = isStringValue(entry.data.type) ? entry.data.type : ctx.defaultType;
|
|
11568
12021
|
const typeExtend = ctx.typeFrontmatter?.[entryType];
|
|
11569
12022
|
const extend = ctx.frontmatterExtend || typeExtend ? { ...ctx.frontmatterExtend, ...typeExtend } : undefined;
|
|
11570
12023
|
const known = extend ? Object.fromEntries(Object.entries(entry.data).filter(([key]) => !Object.hasOwn(extend, key))) : entry.data;
|
|
@@ -11600,13 +12053,16 @@ var normalizeEntry = (entry, ctx) => {
|
|
|
11600
12053
|
if (meta.noindex) {
|
|
11601
12054
|
meta.seo.noindex = true;
|
|
11602
12055
|
}
|
|
12056
|
+
const { versions } = ctx;
|
|
12057
|
+
const { version, rest: versionlessRef } = versions ? detectVersionRef(entry.ref, versions) : { rest: entry.ref, version: "" };
|
|
11603
12058
|
const { i18n } = ctx;
|
|
11604
|
-
const { navPath: rawNavPath, locales } = i18n ? localePlacement(
|
|
12059
|
+
const { navPath: rawNavPath, locales } = i18n ? localePlacement(versionlessRef, ext, i18n) : { locales: [""], navPath: versionlessRef };
|
|
11605
12060
|
const navPath = withPrefix(ctx.source.prefix, rawNavPath);
|
|
11606
12061
|
const slugInput = meta.slug ?? entry.slug;
|
|
11607
12062
|
const slug = slugInput ? trimSlashes(slugInput) : "";
|
|
11608
12063
|
const routeInput = withPrefix(ctx.source.prefix, slug ? `${slug}${ext}` : rawNavPath);
|
|
11609
|
-
const { segments, groups, route:
|
|
12064
|
+
const { segments, groups, route: versionKey } = mapRoute(routeInput);
|
|
12065
|
+
const logicalRoute = versionizeRoute(versionKey, version);
|
|
11610
12066
|
const headings = extractHeadings(entry.body.text);
|
|
11611
12067
|
const { staged } = ctx.source;
|
|
11612
12068
|
const base = {
|
|
@@ -11630,7 +12086,9 @@ var normalizeEntry = (entry, ctx) => {
|
|
|
11630
12086
|
source: { name: ctx.source.name, ref: entry.ref },
|
|
11631
12087
|
sourcePath: entry.sourcePath,
|
|
11632
12088
|
title: deriveTitle(meta, headings, navPath),
|
|
11633
|
-
translationKey: logicalRoute
|
|
12089
|
+
translationKey: logicalRoute,
|
|
12090
|
+
version,
|
|
12091
|
+
versionKey
|
|
11634
12092
|
};
|
|
11635
12093
|
const pages = locales.map((locale) => ({
|
|
11636
12094
|
...base,
|
|
@@ -11740,6 +12198,7 @@ var operationKey = (method, path, operationId) => {
|
|
|
11740
12198
|
return fromId || slugify(`${method}-${path}`);
|
|
11741
12199
|
};
|
|
11742
12200
|
var isOperation = (value) => typeof value === "object" && value !== null;
|
|
12201
|
+
var hasTagName = (tag) => typeof tag.name === "string";
|
|
11743
12202
|
var tagSlugger = () => {
|
|
11744
12203
|
const assigned = new Map;
|
|
11745
12204
|
const taken = new Set;
|
|
@@ -11758,16 +12217,45 @@ var tagSlugger = () => {
|
|
|
11758
12217
|
return slug;
|
|
11759
12218
|
};
|
|
11760
12219
|
};
|
|
11761
|
-
var
|
|
12220
|
+
var operationCollector = (baseRoute, tagMeta) => {
|
|
11762
12221
|
const operations = [];
|
|
11763
12222
|
const tagOrder = [];
|
|
11764
12223
|
const tagsSeen = new Set;
|
|
11765
|
-
const tagMeta = new Map((document.tags ?? []).map((tag) => [tag.name, tag.description ?? ""]));
|
|
11766
12224
|
const seen = new Set;
|
|
11767
|
-
const warnings = [];
|
|
11768
12225
|
const slugForTag = tagSlugger();
|
|
11769
|
-
|
|
11770
|
-
const
|
|
12226
|
+
const add2 = (entry) => {
|
|
12227
|
+
const tagSlug = slugForTag(entry.tag);
|
|
12228
|
+
if (!tagsSeen.has(entry.tag)) {
|
|
12229
|
+
tagsSeen.add(entry.tag);
|
|
12230
|
+
tagOrder.push(entry.tag);
|
|
12231
|
+
}
|
|
12232
|
+
let { key } = entry;
|
|
12233
|
+
while (seen.has(key)) {
|
|
12234
|
+
key = `${key}-${entry.method}`;
|
|
12235
|
+
}
|
|
12236
|
+
seen.add(key);
|
|
12237
|
+
operations.push({
|
|
12238
|
+
...entry,
|
|
12239
|
+
key,
|
|
12240
|
+
route: `${baseRoute === "/" ? "" : baseRoute}/${tagSlug}/${key}`,
|
|
12241
|
+
tagSlug
|
|
12242
|
+
});
|
|
12243
|
+
};
|
|
12244
|
+
const finish = () => ({
|
|
12245
|
+
operations,
|
|
12246
|
+
tags: tagOrder.map((name) => ({
|
|
12247
|
+
description: tagMeta.get(name) ?? "",
|
|
12248
|
+
name,
|
|
12249
|
+
slug: slugForTag(name)
|
|
12250
|
+
}))
|
|
12251
|
+
});
|
|
12252
|
+
return { add: add2, finish };
|
|
12253
|
+
};
|
|
12254
|
+
var extractOperations = (document, baseRoute) => {
|
|
12255
|
+
const warnings = [];
|
|
12256
|
+
const tagMeta = new Map((document.tags ?? []).filter(hasTagName).map((tag) => [tag.name, tag.description ?? ""]));
|
|
12257
|
+
const collector = operationCollector(baseRoute, tagMeta);
|
|
12258
|
+
for (const [path, item] of Object.entries(document.paths ?? {})) {
|
|
11771
12259
|
if (!item) {
|
|
11772
12260
|
continue;
|
|
11773
12261
|
}
|
|
@@ -11780,78 +12268,207 @@ var extractOperations = (document, baseRoute) => {
|
|
|
11780
12268
|
if (!isOperation(operation)) {
|
|
11781
12269
|
continue;
|
|
11782
12270
|
}
|
|
11783
|
-
|
|
11784
|
-
const tagSlug = slugForTag(tag);
|
|
11785
|
-
if (!tagsSeen.has(tag)) {
|
|
11786
|
-
tagsSeen.add(tag);
|
|
11787
|
-
tagOrder.push(tag);
|
|
11788
|
-
}
|
|
11789
|
-
let key = operationKey(method, path, operation.operationId);
|
|
11790
|
-
while (seen.has(key)) {
|
|
11791
|
-
key = `${key}-${method}`;
|
|
11792
|
-
}
|
|
11793
|
-
seen.add(key);
|
|
11794
|
-
operations.push({
|
|
12271
|
+
collector.add({
|
|
11795
12272
|
deprecated: operation.deprecated ?? false,
|
|
11796
12273
|
description: operation.description ?? "",
|
|
11797
|
-
key,
|
|
12274
|
+
key: operationKey(method, path, operation.operationId),
|
|
11798
12275
|
method,
|
|
11799
12276
|
operationId: operation.operationId,
|
|
11800
12277
|
path,
|
|
11801
|
-
route: `${baseRoute === "/" ? "" : baseRoute}/${tagSlug}/${key}`,
|
|
11802
12278
|
summary: operation.summary ?? "",
|
|
11803
|
-
tag
|
|
11804
|
-
tagSlug
|
|
12279
|
+
tag: operation.tags?.[0] ?? UNTAGGED
|
|
11805
12280
|
});
|
|
11806
12281
|
}
|
|
11807
12282
|
}
|
|
11808
|
-
|
|
11809
|
-
description: tagMeta.get(name) ?? "",
|
|
11810
|
-
name,
|
|
11811
|
-
slug: slugForTag(name)
|
|
11812
|
-
}));
|
|
11813
|
-
return { operations, tags, warnings };
|
|
12283
|
+
return { ...collector.finish(), warnings };
|
|
11814
12284
|
};
|
|
11815
12285
|
|
|
11816
|
-
// src/openapi/
|
|
11817
|
-
|
|
11818
|
-
|
|
11819
|
-
|
|
11820
|
-
|
|
11821
|
-
|
|
11822
|
-
|
|
11823
|
-
|
|
11824
|
-
|
|
11825
|
-
var
|
|
11826
|
-
|
|
11827
|
-
|
|
11828
|
-
|
|
11829
|
-
var
|
|
11830
|
-
var
|
|
11831
|
-
|
|
11832
|
-
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
}
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
}
|
|
12286
|
+
// src/openapi/asyncapi.ts
|
|
12287
|
+
var ASYNCAPI_ACTIONS = ["send", "receive"];
|
|
12288
|
+
var unescapePointer = (token) => token.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
12289
|
+
var CHANNEL_REF = /^#\/channels\/(?<id>.+)$/u;
|
|
12290
|
+
var isString3 = (value) => typeof value === "string";
|
|
12291
|
+
var channelIdOf = (channel) => {
|
|
12292
|
+
const id2 = CHANNEL_REF.exec(channel?.$ref ?? "")?.groups?.id;
|
|
12293
|
+
return id2 === undefined ? undefined : unescapePointer(id2);
|
|
12294
|
+
};
|
|
12295
|
+
var channelAddress = (channelId, channel) => {
|
|
12296
|
+
const address = channel?.address;
|
|
12297
|
+
return isString3(address) && address !== "" ? address : channelId;
|
|
12298
|
+
};
|
|
12299
|
+
var isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12300
|
+
var COMPONENT_SECTION_REF = /^#\/components\/(?<section>channels|operations)\/(?<name>[^/]+)$/u;
|
|
12301
|
+
var inlineComponentRefs = (document) => {
|
|
12302
|
+
const maps = [
|
|
12303
|
+
[document.channels, "channels"],
|
|
12304
|
+
[document.operations, "operations"]
|
|
12305
|
+
];
|
|
12306
|
+
for (const [map, section] of maps) {
|
|
12307
|
+
if (!isObject(map)) {
|
|
12308
|
+
continue;
|
|
12309
|
+
}
|
|
12310
|
+
const table = document.components?.[section];
|
|
12311
|
+
for (const [id2, entry] of Object.entries(map)) {
|
|
12312
|
+
if (!isObject(entry) || !isString3(entry.$ref)) {
|
|
12313
|
+
continue;
|
|
12314
|
+
}
|
|
12315
|
+
const groups = COMPONENT_SECTION_REF.exec(entry.$ref)?.groups;
|
|
12316
|
+
if (groups?.section !== section) {
|
|
12317
|
+
continue;
|
|
12318
|
+
}
|
|
12319
|
+
const resolved = isObject(table) ? table[unescapePointer(groups.name ?? "")] : undefined;
|
|
12320
|
+
if (isObject(resolved) && !isString3(resolved.$ref)) {
|
|
12321
|
+
map[id2] = resolved;
|
|
12322
|
+
}
|
|
12323
|
+
}
|
|
12324
|
+
}
|
|
12325
|
+
};
|
|
12326
|
+
var TRAIT_REF = /^#\/components\/(?<section>operationTraits|messageTraits)\/(?<name>[^/]+)$/u;
|
|
12327
|
+
var applyAsyncApiTraits = (document) => {
|
|
12328
|
+
const resolveTrait = (trait) => {
|
|
12329
|
+
if (!isObject(trait)) {
|
|
12330
|
+
return;
|
|
12331
|
+
}
|
|
12332
|
+
if (!isString3(trait.$ref)) {
|
|
12333
|
+
return trait;
|
|
12334
|
+
}
|
|
12335
|
+
const groups = TRAIT_REF.exec(trait.$ref)?.groups;
|
|
12336
|
+
const section = groups?.section ? document.components?.[groups.section] : undefined;
|
|
12337
|
+
const resolved = section?.[groups?.name ?? ""];
|
|
12338
|
+
return isObject(resolved) ? resolved : undefined;
|
|
12339
|
+
};
|
|
12340
|
+
const mergeTraits = (node) => {
|
|
12341
|
+
const { traits } = node;
|
|
12342
|
+
if (!Array.isArray(traits)) {
|
|
12343
|
+
return;
|
|
12344
|
+
}
|
|
12345
|
+
delete node.traits;
|
|
12346
|
+
const merged = {};
|
|
12347
|
+
for (const trait of traits) {
|
|
12348
|
+
Object.assign(merged, resolveTrait(trait));
|
|
12349
|
+
}
|
|
12350
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
12351
|
+
if (!(key in node)) {
|
|
12352
|
+
node[key] = value;
|
|
12353
|
+
}
|
|
12354
|
+
}
|
|
12355
|
+
};
|
|
12356
|
+
for (const operation of Object.values(document.operations ?? {})) {
|
|
12357
|
+
if (isObject(operation)) {
|
|
12358
|
+
mergeTraits(operation);
|
|
12359
|
+
}
|
|
12360
|
+
}
|
|
12361
|
+
const channelMaps = [
|
|
12362
|
+
...Object.values(document.channels ?? {}),
|
|
12363
|
+
...Object.values(document.components?.channels ?? {})
|
|
12364
|
+
];
|
|
12365
|
+
const messageMaps = [
|
|
12366
|
+
...channelMaps.map((channel) => isObject(channel) ? channel.messages : undefined),
|
|
12367
|
+
document.components?.messages
|
|
12368
|
+
];
|
|
12369
|
+
for (const messages of messageMaps) {
|
|
12370
|
+
if (!isObject(messages)) {
|
|
12371
|
+
continue;
|
|
12372
|
+
}
|
|
12373
|
+
for (const message of Object.values(messages)) {
|
|
12374
|
+
if (isObject(message) && !isString3(message.$ref)) {
|
|
12375
|
+
mergeTraits(message);
|
|
12376
|
+
}
|
|
12377
|
+
}
|
|
12378
|
+
}
|
|
12379
|
+
return document;
|
|
12380
|
+
};
|
|
12381
|
+
var normalizeAsyncApiDocument = (document) => {
|
|
12382
|
+
inlineComponentRefs(document);
|
|
12383
|
+
return applyAsyncApiTraits(document);
|
|
12384
|
+
};
|
|
12385
|
+
var operationSite = (id2, operation, channels) => {
|
|
12386
|
+
const action = ASYNCAPI_ACTIONS.find((a) => a === operation.action);
|
|
12387
|
+
if (!action) {
|
|
12388
|
+
return `Operation "${id2}" declares no send/receive action; it is missing from the reference.`;
|
|
12389
|
+
}
|
|
12390
|
+
const channelId = channelIdOf(operation.channel);
|
|
12391
|
+
const channel = channelId === undefined ? undefined : channels[channelId];
|
|
12392
|
+
if (channelId === undefined || !isObject(channel) || isString3(channel.$ref)) {
|
|
12393
|
+
return `Operation "${id2}" references a channel that isn't declared under "channels"; it is missing from the reference.`;
|
|
12394
|
+
}
|
|
12395
|
+
return { action, address: channelAddress(channelId, channel), channelId };
|
|
12396
|
+
};
|
|
12397
|
+
var extractAsyncApiOperations = (document, baseRoute) => {
|
|
12398
|
+
const warnings = [];
|
|
12399
|
+
const tagMeta = new Map((document.info?.tags ?? []).filter((tag) => typeof tag?.name === "string").map((tag) => [tag.name, tag.description ?? ""]));
|
|
12400
|
+
const collector = operationCollector(baseRoute, tagMeta);
|
|
12401
|
+
const channels = document.channels ?? {};
|
|
12402
|
+
for (const [id2, operation] of Object.entries(document.operations ?? {})) {
|
|
12403
|
+
if (!isObject(operation)) {
|
|
12404
|
+
continue;
|
|
12405
|
+
}
|
|
12406
|
+
if (isString3(operation.$ref)) {
|
|
12407
|
+
warnings.push(`Operation "${id2}" is a reference that doesn't resolve to a components operation; it is missing from the reference.`);
|
|
12408
|
+
continue;
|
|
12409
|
+
}
|
|
12410
|
+
const site = operationSite(id2, operation, channels);
|
|
12411
|
+
if (isString3(site)) {
|
|
12412
|
+
warnings.push(site);
|
|
12413
|
+
continue;
|
|
12414
|
+
}
|
|
12415
|
+
const { action, address, channelId } = site;
|
|
12416
|
+
const tag = operation.tags?.find((candidate) => typeof candidate?.name === "string")?.name;
|
|
12417
|
+
collector.add({
|
|
12418
|
+
channelId,
|
|
12419
|
+
deprecated: operation.deprecated === true,
|
|
12420
|
+
description: operation.description ?? "",
|
|
12421
|
+
key: operationKey(action, address, id2),
|
|
12422
|
+
method: action,
|
|
12423
|
+
operationId: id2,
|
|
12424
|
+
path: address,
|
|
12425
|
+
summary: operation.title ?? operation.summary ?? "",
|
|
12426
|
+
tag: tag ?? address
|
|
12427
|
+
});
|
|
12428
|
+
}
|
|
12429
|
+
return { ...collector.finish(), warnings };
|
|
12430
|
+
};
|
|
12431
|
+
|
|
12432
|
+
// src/openapi/parse.ts
|
|
12433
|
+
import { mkdir as mkdir4, readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
|
|
12434
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
12435
|
+
import { convert } from "@asyncapi/converter";
|
|
12436
|
+
import { normalize as normalize2, upgrade } from "@scalar/openapi-parser";
|
|
12437
|
+
import pRetry, { AbortError } from "p-retry";
|
|
12438
|
+
import { isAbsolute as isAbsolute3, join as join12 } from "pathe";
|
|
12439
|
+
var URL_SPEC = /^https?:\/\//u;
|
|
12440
|
+
var FETCH_TIMEOUT_MS = 15000;
|
|
12441
|
+
var MAX_ATTEMPTS = 3;
|
|
12442
|
+
var BASE_BACKOFF_MS = 500;
|
|
12443
|
+
var MAX_RETRY_WAIT_MS = 1e4;
|
|
12444
|
+
var SECOND_MS = 1000;
|
|
12445
|
+
var RETRYABLE_STATUS = new Set([408, 425, 429, 500, 502, 503, 504]);
|
|
12446
|
+
var USER_AGENT = "blume (+https://github.com/haydenbleasel/blume)";
|
|
12447
|
+
var PROXY_ENV_VARS = [
|
|
12448
|
+
"HTTP_PROXY",
|
|
12449
|
+
"http_proxy",
|
|
12450
|
+
"HTTPS_PROXY",
|
|
12451
|
+
"https_proxy",
|
|
12452
|
+
"ALL_PROXY",
|
|
12453
|
+
"all_proxy"
|
|
12454
|
+
];
|
|
12455
|
+
|
|
12456
|
+
class InvalidSpecError extends Error {
|
|
12457
|
+
constructor(message) {
|
|
12458
|
+
super(message);
|
|
12459
|
+
this.name = "InvalidSpecError";
|
|
12460
|
+
}
|
|
12461
|
+
}
|
|
12462
|
+
var proxyInstalled = false;
|
|
12463
|
+
var ensureProxyDispatcher = async () => {
|
|
12464
|
+
if (proxyInstalled || !PROXY_ENV_VARS.some((name) => process.env[name])) {
|
|
12465
|
+
return;
|
|
12466
|
+
}
|
|
12467
|
+
try {
|
|
12468
|
+
const { EnvHttpProxyAgent, setGlobalDispatcher } = await import("undici");
|
|
12469
|
+
setGlobalDispatcher(new EnvHttpProxyAgent);
|
|
12470
|
+
proxyInstalled = true;
|
|
12471
|
+
} catch {}
|
|
11855
12472
|
};
|
|
11856
12473
|
var retryAfterMs = (response) => {
|
|
11857
12474
|
const header = response.headers.get("retry-after");
|
|
@@ -11969,27 +12586,74 @@ var readSpecText = async (spec, root, options) => {
|
|
|
11969
12586
|
throw error;
|
|
11970
12587
|
}
|
|
11971
12588
|
};
|
|
12589
|
+
var isApiDocument = (value) => typeof value === "object" && value !== null;
|
|
11972
12590
|
var parseSpec = async (spec, root, options = {}) => {
|
|
11973
12591
|
const { text, warnings } = await readSpecText(spec, root, options);
|
|
11974
12592
|
const normalized = normalize2(text);
|
|
11975
12593
|
const { specification } = upgrade(normalized);
|
|
11976
|
-
if (specification
|
|
12594
|
+
if (!isApiDocument(specification)) {
|
|
11977
12595
|
throw new InvalidSpecError(`${spec} is not a valid OpenAPI document (expected a YAML or JSON object).`);
|
|
11978
12596
|
}
|
|
11979
12597
|
return { document: specification, warnings };
|
|
11980
12598
|
};
|
|
12599
|
+
var isAsyncApiDocument = (value) => typeof value === "object" && value !== null && ("asyncapi" in value) && typeof value.asyncapi === "string" && value.asyncapi !== "";
|
|
12600
|
+
var parseAsyncApiSpec = async (spec, root, options = {}) => {
|
|
12601
|
+
const { text, warnings } = await readSpecText(spec, root, options);
|
|
12602
|
+
const normalized = normalize2(text);
|
|
12603
|
+
if (!isAsyncApiDocument(normalized)) {
|
|
12604
|
+
throw new InvalidSpecError(`${spec} is not a valid AsyncAPI document (expected a YAML or JSON object with an \`asyncapi\` version field).`);
|
|
12605
|
+
}
|
|
12606
|
+
const version = normalized.asyncapi;
|
|
12607
|
+
let document = normalized;
|
|
12608
|
+
if (!version.startsWith("3.")) {
|
|
12609
|
+
const captured = [];
|
|
12610
|
+
const originalWarn = console.warn;
|
|
12611
|
+
console.warn = (...args) => {
|
|
12612
|
+
captured.push(args.map(String).join(" "));
|
|
12613
|
+
};
|
|
12614
|
+
try {
|
|
12615
|
+
document = convert(document, "3.0.0");
|
|
12616
|
+
} catch (error) {
|
|
12617
|
+
throw new InvalidSpecError(`${spec} could not be converted to AsyncAPI 3.0 (${error.message}).`);
|
|
12618
|
+
} finally {
|
|
12619
|
+
console.warn = originalWarn;
|
|
12620
|
+
}
|
|
12621
|
+
warnings.push(...captured.map((message) => `Converting ${spec} to AsyncAPI 3.0: ${message}`));
|
|
12622
|
+
}
|
|
12623
|
+
return { document: normalizeAsyncApiDocument(document), warnings };
|
|
12624
|
+
};
|
|
11981
12625
|
|
|
11982
12626
|
// src/openapi/render-mdx.ts
|
|
11983
12627
|
import { fromMarkdown as fromMarkdown2 } from "mdast-util-from-markdown";
|
|
11984
12628
|
import { toString as mdastToString } from "mdast-util-to-string";
|
|
11985
|
-
|
|
11986
|
-
|
|
11987
|
-
|
|
11988
|
-
|
|
11989
|
-
|
|
12629
|
+
import stringWidth3 from "string-width";
|
|
12630
|
+
|
|
12631
|
+
// src/core/text-width.ts
|
|
12632
|
+
import stringWidth2 from "string-width";
|
|
12633
|
+
var columnsPrefix = (text, max) => {
|
|
12634
|
+
let end = 0;
|
|
12635
|
+
let used = 0;
|
|
12636
|
+
const graphemes = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
12637
|
+
for (const { index, segment } of graphemes.segment(text)) {
|
|
12638
|
+
const width = stringWidth2(segment);
|
|
12639
|
+
if (used + width > max) {
|
|
12640
|
+
break;
|
|
12641
|
+
}
|
|
12642
|
+
used += width;
|
|
12643
|
+
end = index + segment.length;
|
|
12644
|
+
}
|
|
12645
|
+
return text.slice(0, end);
|
|
11990
12646
|
};
|
|
12647
|
+
|
|
12648
|
+
// src/openapi/render-mdx.ts
|
|
12649
|
+
var MDX_UNSAFE = /[<{}]/gu;
|
|
12650
|
+
var ENTITIES = new Map([
|
|
12651
|
+
["<", "<"],
|
|
12652
|
+
["{", "{"],
|
|
12653
|
+
["}", "}"]
|
|
12654
|
+
]);
|
|
11991
12655
|
var MDX_ESM_KEYWORD = /^(?<keyword>import|export)\b/gmu;
|
|
11992
|
-
var escapeProse = (text) => text.replace(MDX_UNSAFE, (char) => ENTITIES
|
|
12656
|
+
var escapeProse = (text) => text.replace(MDX_UNSAFE, (char) => ENTITIES.get(char) ?? char).replace(MDX_ESM_KEYWORD, (keyword) => `&#${keyword.codePointAt(0)};${keyword.slice(1)}`);
|
|
11993
12657
|
var codeSpans = (text) => {
|
|
11994
12658
|
const spans = [];
|
|
11995
12659
|
const collect = (node) => {
|
|
@@ -12022,29 +12686,28 @@ var mdxSafe = (text) => {
|
|
|
12022
12686
|
return out + escapeProse(text.slice(cursor));
|
|
12023
12687
|
};
|
|
12024
12688
|
var META_DESCRIPTION_MAX = 160;
|
|
12025
|
-
var
|
|
12689
|
+
var WHITESPACE2 = /\s+/gu;
|
|
12026
12690
|
var TRAILING_WORD = /\s+\S*$/u;
|
|
12027
12691
|
var plainProse = (markdown) => {
|
|
12028
12692
|
const tree = fromMarkdown2(markdown);
|
|
12029
12693
|
const first = tree.children.find((node) => node.type === "paragraph") ?? tree.children[0];
|
|
12030
|
-
return first ? mdastToString(first).replace(
|
|
12694
|
+
return first ? mdastToString(first).replace(WHITESPACE2, " ").trim() : "";
|
|
12031
12695
|
};
|
|
12032
12696
|
var clip = (text, max) => {
|
|
12033
12697
|
if (max <= 0) {
|
|
12034
12698
|
return "";
|
|
12035
12699
|
}
|
|
12036
|
-
if (text
|
|
12700
|
+
if (stringWidth3(text) <= max) {
|
|
12037
12701
|
return text;
|
|
12038
12702
|
}
|
|
12039
|
-
const head = text
|
|
12703
|
+
const head = columnsPrefix(text, max - 1);
|
|
12040
12704
|
const onWordBoundary = head.replace(TRAILING_WORD, "");
|
|
12041
|
-
return `${onWordBoundary
|
|
12705
|
+
return `${stringWidth3(onWordBoundary) >= max / 2 ? onWordBoundary : head}…`;
|
|
12042
12706
|
};
|
|
12043
12707
|
var apiName = (spec) => spec.title || spec.label;
|
|
12044
12708
|
var operationDescription = (spec, operation) => {
|
|
12045
|
-
const
|
|
12046
|
-
const
|
|
12047
|
-
const prose = clip(plainProse(operation.description || operation.summary), META_DESCRIPTION_MAX - suffix.length - 1);
|
|
12709
|
+
const suffix = spec.kind === "asyncapi" ? `Reference for the ${operation.method} operation on ${operation.path} in the ${apiName(spec)} API.` : `Reference for the ${operation.method.toUpperCase()} ${operation.path} endpoint in the ${apiName(spec)} API.`;
|
|
12710
|
+
const prose = clip(plainProse(operation.description || operation.summary), META_DESCRIPTION_MAX - stringWidth3(suffix) - 1);
|
|
12048
12711
|
return clip([prose, suffix].filter(Boolean).join(" "), META_DESCRIPTION_MAX);
|
|
12049
12712
|
};
|
|
12050
12713
|
var withDescription = (description, component) => description.trim() ? `${mdxSafe(description.trim())}
|
|
@@ -12054,19 +12717,29 @@ var operationMdx = (spec, operation, reference) => {
|
|
|
12054
12717
|
const method = operation.method.toUpperCase();
|
|
12055
12718
|
const title = operation.summary || `${method} ${operation.path}`;
|
|
12056
12719
|
const description = operation.description.trim() === operation.summary.trim() ? "" : operation.description;
|
|
12720
|
+
const flags = {};
|
|
12721
|
+
if (reference?.includeInLlms === false) {
|
|
12722
|
+
flags.ai = { exclude: true };
|
|
12723
|
+
}
|
|
12724
|
+
if (operation.deprecated) {
|
|
12725
|
+
flags.deprecated = true;
|
|
12726
|
+
}
|
|
12727
|
+
const searchFlags = {};
|
|
12728
|
+
if (reference?.includeInSearch === false) {
|
|
12729
|
+
searchFlags.exclude = true;
|
|
12730
|
+
}
|
|
12731
|
+
const seo = {
|
|
12732
|
+
description: operationDescription(spec, operation)
|
|
12733
|
+
};
|
|
12734
|
+
if (reference?.noindex) {
|
|
12735
|
+
seo.noindex = true;
|
|
12736
|
+
}
|
|
12057
12737
|
return {
|
|
12058
12738
|
body: withDescription(description, `<Operation source="${spec.slug}" id="${operation.key}" />`),
|
|
12059
12739
|
data: {
|
|
12060
|
-
...
|
|
12061
|
-
|
|
12062
|
-
|
|
12063
|
-
...reference?.includeInSearch === false ? { exclude: true } : {},
|
|
12064
|
-
tags: [operation.tag, method]
|
|
12065
|
-
},
|
|
12066
|
-
seo: {
|
|
12067
|
-
description: operationDescription(spec, operation),
|
|
12068
|
-
...reference?.noindex ? { noindex: true } : {}
|
|
12069
|
-
},
|
|
12740
|
+
...flags,
|
|
12741
|
+
search: { ...searchFlags, tags: [operation.tag, method] },
|
|
12742
|
+
seo,
|
|
12070
12743
|
sidebar: { badge: method, label: operation.summary || operation.path },
|
|
12071
12744
|
title,
|
|
12072
12745
|
type: "openapi-operation"
|
|
@@ -12107,6 +12780,19 @@ var overviewMdx = (spec, reference) => {
|
|
|
12107
12780
|
|
|
12108
12781
|
`));
|
|
12109
12782
|
}
|
|
12783
|
+
const flags = {};
|
|
12784
|
+
if (reference?.includeInLlms === false) {
|
|
12785
|
+
flags.ai = { exclude: true };
|
|
12786
|
+
}
|
|
12787
|
+
if (reference?.includeInSearch === false) {
|
|
12788
|
+
flags.search = { exclude: true };
|
|
12789
|
+
}
|
|
12790
|
+
const seo = {
|
|
12791
|
+
description: clip(plainProse(spec.description), META_DESCRIPTION_MAX) || `${apiName(spec)} API reference.`
|
|
12792
|
+
};
|
|
12793
|
+
if (reference?.noindex) {
|
|
12794
|
+
seo.noindex = true;
|
|
12795
|
+
}
|
|
12110
12796
|
return {
|
|
12111
12797
|
body: [
|
|
12112
12798
|
withDescription(spec.description, `<ApiOverview source="${spec.slug}" />`),
|
|
@@ -12115,12 +12801,8 @@ var overviewMdx = (spec, reference) => {
|
|
|
12115
12801
|
|
|
12116
12802
|
`),
|
|
12117
12803
|
data: {
|
|
12118
|
-
...
|
|
12119
|
-
|
|
12120
|
-
seo: {
|
|
12121
|
-
description: clip(plainProse(spec.description), META_DESCRIPTION_MAX) || `${apiName(spec)} API reference.`,
|
|
12122
|
-
...reference?.noindex ? { noindex: true } : {}
|
|
12123
|
-
},
|
|
12804
|
+
...flags,
|
|
12805
|
+
seo,
|
|
12124
12806
|
sidebar: { label: "Overview" },
|
|
12125
12807
|
title: apiName(spec)
|
|
12126
12808
|
}
|
|
@@ -12128,14 +12810,14 @@ var overviewMdx = (spec, reference) => {
|
|
|
12128
12810
|
};
|
|
12129
12811
|
|
|
12130
12812
|
// src/openapi/source.ts
|
|
12131
|
-
var isOpenApiSource = (source) => source.kind === "openapi-source";
|
|
12813
|
+
var isOpenApiSource = (source) => ("kind" in source) && source.kind === "openapi-source";
|
|
12132
12814
|
var routeToRef = (route) => route.replace(/^\/+/u, "");
|
|
12133
12815
|
var toEntry = (rendered, ref) => {
|
|
12134
12816
|
const raw = frontmatter_default.stringify(`${rendered.body}
|
|
12135
12817
|
`, rendered.data);
|
|
12136
12818
|
return {
|
|
12137
12819
|
body: { format: "mdx", text: rendered.body },
|
|
12138
|
-
data: rendered.data,
|
|
12820
|
+
data: { ...rendered.data },
|
|
12139
12821
|
hash: hashText(raw),
|
|
12140
12822
|
raw,
|
|
12141
12823
|
ref
|
|
@@ -12154,22 +12836,43 @@ var tagFolderMeta = (spec, tags) => {
|
|
|
12154
12836
|
{ title: tag.name }
|
|
12155
12837
|
]));
|
|
12156
12838
|
};
|
|
12839
|
+
var parseReference = async (reference, ctx) => {
|
|
12840
|
+
const options = { cacheDir: ctx.cacheDir, refresh: ctx.refresh };
|
|
12841
|
+
if (reference.kind === "asyncapi") {
|
|
12842
|
+
const { document: document2, warnings: warnings2 } = await parseAsyncApiSpec(reference.spec, ctx.projectRoot, options);
|
|
12843
|
+
const extracted2 = extractAsyncApiOperations(document2, reference.route);
|
|
12844
|
+
return {
|
|
12845
|
+
document: document2,
|
|
12846
|
+
extractWarnings: extracted2.warnings,
|
|
12847
|
+
operations: extracted2.operations,
|
|
12848
|
+
tags: extracted2.tags,
|
|
12849
|
+
warnings: warnings2
|
|
12850
|
+
};
|
|
12851
|
+
}
|
|
12852
|
+
const { document, warnings } = await parseSpec(reference.spec, ctx.projectRoot, options);
|
|
12853
|
+
const extracted = extractOperations(document, reference.route);
|
|
12854
|
+
return {
|
|
12855
|
+
document,
|
|
12856
|
+
extractWarnings: extracted.warnings,
|
|
12857
|
+
operations: extracted.operations,
|
|
12858
|
+
tags: extracted.tags,
|
|
12859
|
+
warnings
|
|
12860
|
+
};
|
|
12861
|
+
};
|
|
12157
12862
|
var openApiSource = (references, ctx) => {
|
|
12158
12863
|
let parsed = {};
|
|
12159
12864
|
const loadReference = async (reference) => {
|
|
12865
|
+
const kindLabel = reference.kind === "asyncapi" ? "AsyncAPI" : "OpenAPI";
|
|
12866
|
+
const codePrefix = reference.kind === "asyncapi" ? "BLUME_ASYNCAPI" : "BLUME_OPENAPI";
|
|
12160
12867
|
try {
|
|
12161
|
-
const { document, warnings } = await
|
|
12162
|
-
const {
|
|
12163
|
-
operations,
|
|
12164
|
-
tags,
|
|
12165
|
-
warnings: extractWarnings
|
|
12166
|
-
} = extractOperations(document, reference.route);
|
|
12868
|
+
const { document, warnings, operations, tags, extractWarnings } = await parseReference(reference, ctx);
|
|
12167
12869
|
const info = document.info ?? { title: reference.label, version: "" };
|
|
12168
12870
|
const spec = {
|
|
12169
12871
|
codeSamples: reference.display.codeSamples,
|
|
12170
12872
|
description: info.description ?? "",
|
|
12171
12873
|
document,
|
|
12172
12874
|
expandSchemas: reference.display.expandSchemas,
|
|
12875
|
+
kind: reference.kind,
|
|
12173
12876
|
label: reference.label,
|
|
12174
12877
|
operations: Object.fromEntries(operations.map((operation) => [
|
|
12175
12878
|
operation.key,
|
|
@@ -12187,21 +12890,21 @@ var openApiSource = (references, ctx) => {
|
|
|
12187
12890
|
return {
|
|
12188
12891
|
diagnostics: [
|
|
12189
12892
|
...warnings.map((message) => ({
|
|
12190
|
-
code: "BLUME_OPENAPI_STALE",
|
|
12893
|
+
code: reference.kind === "asyncapi" ? "BLUME_ASYNCAPI_SPEC_WARNING" : "BLUME_OPENAPI_STALE",
|
|
12191
12894
|
message,
|
|
12192
12895
|
severity: "warning"
|
|
12193
12896
|
})),
|
|
12194
12897
|
...extractWarnings.map((message) => ({
|
|
12195
|
-
code: "BLUME_OPENAPI_REF_PATH_ITEM",
|
|
12196
|
-
message: `In
|
|
12898
|
+
code: reference.kind === "asyncapi" ? "BLUME_ASYNCAPI_SKIPPED_OPERATION" : "BLUME_OPENAPI_REF_PATH_ITEM",
|
|
12899
|
+
message: `In ${kindLabel} spec "${reference.spec}": ${message}`,
|
|
12197
12900
|
severity: "warning"
|
|
12198
12901
|
})),
|
|
12199
12902
|
...operations.length === 0 ? [
|
|
12200
12903
|
{
|
|
12201
|
-
code:
|
|
12202
|
-
message:
|
|
12904
|
+
code: `${codePrefix}_EMPTY`,
|
|
12905
|
+
message: `${kindLabel} spec "${reference.spec}" for ${reference.route} declares no operations; its API reference is empty.`,
|
|
12203
12906
|
severity: "warning",
|
|
12204
|
-
suggestion: "Check the spec points at an OpenAPI document with operations under `paths`."
|
|
12907
|
+
suggestion: reference.kind === "asyncapi" ? "Check the spec points at an AsyncAPI document with `channels` and `operations`." : "Check the spec points at an OpenAPI document with operations under `paths`."
|
|
12205
12908
|
}
|
|
12206
12909
|
] : []
|
|
12207
12910
|
],
|
|
@@ -12212,10 +12915,10 @@ var openApiSource = (references, ctx) => {
|
|
|
12212
12915
|
};
|
|
12213
12916
|
} catch (error) {
|
|
12214
12917
|
return {
|
|
12215
|
-
code:
|
|
12216
|
-
message: `Could not load
|
|
12918
|
+
code: `${codePrefix}_UNAVAILABLE`,
|
|
12919
|
+
message: `Could not load ${kindLabel} spec "${reference.spec}" for ${reference.route} (${error.message}); its reference pages were skipped.`,
|
|
12217
12920
|
severity: ctx.mode === "build" ? "error" : "warning",
|
|
12218
|
-
suggestion: error instanceof InvalidSpecError ?
|
|
12921
|
+
suggestion: error instanceof InvalidSpecError ? `Point the spec at ${reference.kind === "asyncapi" ? "an AsyncAPI" : "an OpenAPI"} document (a YAML or JSON file with an object at the top level).` : "Check the spec URL/path is reachable from the build environment; behind a proxy, set HTTP(S)_PROXY."
|
|
12219
12922
|
};
|
|
12220
12923
|
}
|
|
12221
12924
|
};
|
|
@@ -12320,6 +13023,7 @@ import { fromMarkdown as fromMarkdown3 } from "mdast-util-from-markdown";
|
|
|
12320
13023
|
import { gfmFromMarkdown } from "mdast-util-gfm";
|
|
12321
13024
|
import { toString as mdastToString2 } from "mdast-util-to-string";
|
|
12322
13025
|
import { gfm } from "micromark-extension-gfm";
|
|
13026
|
+
import stringWidth4 from "string-width";
|
|
12323
13027
|
var DEFAULT_BASE_URL = "https://api.github.com";
|
|
12324
13028
|
var DEFAULT_LIMIT = 100;
|
|
12325
13029
|
var PER_PAGE = 100;
|
|
@@ -12329,35 +13033,24 @@ var EDGE_DASHES = /^-+|-+$/gu;
|
|
|
12329
13033
|
var DESCRIPTION_MAX = 160;
|
|
12330
13034
|
var DESCRIPTION_MIN = 110;
|
|
12331
13035
|
var CHANGESET_HASH = /^(?<mark>\s*(?:[-*+]|\d+[.)])\s+)[0-9a-f]{7,40}:\s+/gmu;
|
|
12332
|
-
var
|
|
13036
|
+
var WHITESPACE3 = /\s+/gu;
|
|
12333
13037
|
var TRAILING_FRAGMENT = /[\s,;:.—–-]+$/u;
|
|
12334
13038
|
var NON_PROSE = new Set(["code", "heading", "html", "thematicBreak"]);
|
|
12335
|
-
var graphemePrefix = (text, max) => {
|
|
12336
|
-
let end = 0;
|
|
12337
|
-
const graphemes = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
12338
|
-
for (const { index, segment } of graphemes.segment(text)) {
|
|
12339
|
-
if (index + segment.length > max) {
|
|
12340
|
-
break;
|
|
12341
|
-
}
|
|
12342
|
-
end = index + segment.length;
|
|
12343
|
-
}
|
|
12344
|
-
return text.slice(0, end);
|
|
12345
|
-
};
|
|
12346
13039
|
var releaseDescription = (body) => {
|
|
12347
13040
|
const tree = fromMarkdown3(body.replaceAll(CHANGESET_HASH, "$<mark>"), {
|
|
12348
13041
|
extensions: [gfm()],
|
|
12349
13042
|
mdastExtensions: [gfmFromMarkdown()]
|
|
12350
13043
|
});
|
|
12351
|
-
const text = tree.children.filter((node) => !NON_PROSE.has(node.type)).map((node) => mdastToString2(node, { includeHtml: false, includeImageAlt: false })).join(" ").replaceAll(
|
|
13044
|
+
const text = tree.children.filter((node) => !NON_PROSE.has(node.type)).map((node) => mdastToString2(node, { includeHtml: false, includeImageAlt: false })).join(" ").replaceAll(WHITESPACE3, " ").trim();
|
|
12352
13045
|
if (!text) {
|
|
12353
13046
|
return;
|
|
12354
13047
|
}
|
|
12355
|
-
if (text
|
|
13048
|
+
if (stringWidth4(text) <= DESCRIPTION_MAX) {
|
|
12356
13049
|
return text;
|
|
12357
13050
|
}
|
|
12358
|
-
const slice =
|
|
13051
|
+
const slice = columnsPrefix(text, DESCRIPTION_MAX - 1);
|
|
12359
13052
|
const boundary = slice.lastIndexOf(" ");
|
|
12360
|
-
const head = (boundary >= DESCRIPTION_MIN ? slice.slice(0, boundary) : slice).replace(TRAILING_FRAGMENT, "");
|
|
13053
|
+
const head = (boundary !== -1 && stringWidth4(slice.slice(0, boundary)) >= DESCRIPTION_MIN ? slice.slice(0, boundary) : slice).replace(TRAILING_FRAGMENT, "");
|
|
12361
13054
|
return `${head}…`;
|
|
12362
13055
|
};
|
|
12363
13056
|
var slugifyTag = (tag) => tag.toLowerCase().replaceAll(NON_SLUG2, "-").replaceAll(EDGE_DASHES, "");
|
|
@@ -12380,18 +13073,20 @@ var releaseToEntry = (release) => {
|
|
|
12380
13073
|
const description = releaseDescription(body);
|
|
12381
13074
|
const data = {
|
|
12382
13075
|
changelog: { category, version },
|
|
12383
|
-
date
|
|
12384
|
-
...description ? { seo: { description } } : {},
|
|
12385
|
-
title,
|
|
12386
|
-
type: "changelog"
|
|
13076
|
+
date
|
|
12387
13077
|
};
|
|
13078
|
+
if (description) {
|
|
13079
|
+
data.seo = { description };
|
|
13080
|
+
}
|
|
13081
|
+
data.title = title;
|
|
13082
|
+
data.type = "changelog";
|
|
12388
13083
|
const raw = frontmatter_default.stringify(`${body}
|
|
12389
13084
|
`, data);
|
|
12390
13085
|
const fallbackRef = `release-${release.id}`;
|
|
12391
13086
|
const ref = `${slugifyTag(release.tag_name) || fallbackRef}.md`;
|
|
12392
13087
|
return {
|
|
12393
13088
|
body: { format: "md", text: body },
|
|
12394
|
-
data,
|
|
13089
|
+
data: { ...data },
|
|
12395
13090
|
editUrl: release.html_url,
|
|
12396
13091
|
hash: hashText(raw),
|
|
12397
13092
|
lastModified: date,
|
|
@@ -12688,7 +13383,12 @@ var richToMarkdown = (rich = []) => rich.map((node) => {
|
|
|
12688
13383
|
}
|
|
12689
13384
|
return node.href ? `[${text}](${node.href})` : text;
|
|
12690
13385
|
}).join("");
|
|
12691
|
-
var
|
|
13386
|
+
var isBlockPayload = (value) => typeof value === "object";
|
|
13387
|
+
var payloadOf = (block) => {
|
|
13388
|
+
const value = block[block.type];
|
|
13389
|
+
return isBlockPayload(value) ? value : undefined;
|
|
13390
|
+
};
|
|
13391
|
+
var blockField = (block) => payloadOf(block)?.rich_text ?? [];
|
|
12692
13392
|
var RATE_LIMITED = 429;
|
|
12693
13393
|
var MAX_RETRIES = 4;
|
|
12694
13394
|
var BASE_DELAY_MS = 500;
|
|
@@ -12720,7 +13420,7 @@ var LIST_BLOCKS = new Set([
|
|
|
12720
13420
|
]);
|
|
12721
13421
|
var isListItem = (block) => block !== undefined && LIST_BLOCKS.has(block.type);
|
|
12722
13422
|
var renderLeaf = (block) => {
|
|
12723
|
-
const data = block
|
|
13423
|
+
const data = payloadOf(block) ?? {};
|
|
12724
13424
|
const text = richToMarkdown(blockField(block));
|
|
12725
13425
|
switch (block.type) {
|
|
12726
13426
|
case "paragraph": {
|
|
@@ -12756,9 +13456,8 @@ ${text}
|
|
|
12756
13456
|
\`\`\``;
|
|
12757
13457
|
}
|
|
12758
13458
|
case "image": {
|
|
12759
|
-
const
|
|
12760
|
-
|
|
12761
|
-
return url ? `` : "";
|
|
13459
|
+
const url = data.external?.url ?? data.file?.url;
|
|
13460
|
+
return url ? `` : "";
|
|
12762
13461
|
}
|
|
12763
13462
|
default: {
|
|
12764
13463
|
return null;
|
|
@@ -12878,7 +13577,7 @@ ${nested}`;
|
|
|
12878
13577
|
};
|
|
12879
13578
|
const orderOf = (page) => {
|
|
12880
13579
|
const order = page.properties[props.order ?? "Order"]?.number;
|
|
12881
|
-
return
|
|
13580
|
+
return order === null ? undefined : order;
|
|
12882
13581
|
};
|
|
12883
13582
|
const frontmatter = (page) => {
|
|
12884
13583
|
const data = {};
|
|
@@ -12965,14 +13664,14 @@ ${nested}`;
|
|
|
12965
13664
|
import { join as join16 } from "pathe";
|
|
12966
13665
|
|
|
12967
13666
|
// src/core/sources/portable-text.ts
|
|
12968
|
-
var HEADING_STYLES =
|
|
12969
|
-
h1
|
|
12970
|
-
h2
|
|
12971
|
-
h3
|
|
12972
|
-
h4
|
|
12973
|
-
h5
|
|
12974
|
-
h6
|
|
12975
|
-
|
|
13667
|
+
var HEADING_STYLES = new Map([
|
|
13668
|
+
["h1", "# "],
|
|
13669
|
+
["h2", "## "],
|
|
13670
|
+
["h3", "### "],
|
|
13671
|
+
["h4", "#### "],
|
|
13672
|
+
["h5", "##### "],
|
|
13673
|
+
["h6", "###### "]
|
|
13674
|
+
]);
|
|
12976
13675
|
var MARKDOWN_SPECIALS = /[\\`*_[\]~<]/gu;
|
|
12977
13676
|
var escapeText = (text) => text.replaceAll(MARKDOWN_SPECIALS, String.raw`\$&`);
|
|
12978
13677
|
var renderSpan = (span, defs) => {
|
|
@@ -13014,6 +13713,7 @@ var renderChildren = (block) => {
|
|
|
13014
13713
|
const defs = new Map((block.markDefs ?? []).map((def) => [def._key, def]));
|
|
13015
13714
|
return (block.children ?? []).map((span) => renderSpan(span, defs)).join("");
|
|
13016
13715
|
};
|
|
13716
|
+
var isAltText = (value) => typeof value === "string";
|
|
13017
13717
|
var renderBlock = (block, options) => {
|
|
13018
13718
|
const custom = options.serializers?.[block._type];
|
|
13019
13719
|
if (custom) {
|
|
@@ -13021,7 +13721,7 @@ var renderBlock = (block, options) => {
|
|
|
13021
13721
|
}
|
|
13022
13722
|
if (block._type === "image") {
|
|
13023
13723
|
const url = options.imageUrl?.(block);
|
|
13024
|
-
const alt =
|
|
13724
|
+
const alt = isAltText(block.alt) ? block.alt : "";
|
|
13025
13725
|
return url ? `` : "";
|
|
13026
13726
|
}
|
|
13027
13727
|
if (block._type !== "block") {
|
|
@@ -13036,7 +13736,7 @@ var renderBlock = (block, options) => {
|
|
|
13036
13736
|
if (block.style === "blockquote") {
|
|
13037
13737
|
return `> ${inline}`;
|
|
13038
13738
|
}
|
|
13039
|
-
return `${HEADING_STYLES
|
|
13739
|
+
return `${HEADING_STYLES.get(block.style ?? "normal") ?? ""}${inline}`;
|
|
13040
13740
|
};
|
|
13041
13741
|
var portableTextToMarkdown = (blocks, options = {}) => {
|
|
13042
13742
|
const lines = blocks.map((block) => renderBlock(block, options));
|
|
@@ -13059,10 +13759,11 @@ var portableTextToMarkdown = (blocks, options = {}) => {
|
|
|
13059
13759
|
|
|
13060
13760
|
// src/core/sources/sanity.ts
|
|
13061
13761
|
var IMAGE_REF = /^image-(?<id>[a-f0-9]+)-(?<dims>\d+x\d+)-(?<ext>\w+)$/u;
|
|
13762
|
+
var isTraversable = (value) => typeof value === "object" && value !== null;
|
|
13062
13763
|
var getPath = (doc, path) => {
|
|
13063
13764
|
let current = doc;
|
|
13064
13765
|
for (const key of path.split(".")) {
|
|
13065
|
-
if (current
|
|
13766
|
+
if (isTraversable(current)) {
|
|
13066
13767
|
current = current[key];
|
|
13067
13768
|
} else {
|
|
13068
13769
|
return;
|
|
@@ -13070,7 +13771,8 @@ var getPath = (doc, path) => {
|
|
|
13070
13771
|
}
|
|
13071
13772
|
return current;
|
|
13072
13773
|
};
|
|
13073
|
-
var
|
|
13774
|
+
var isStringValue2 = (value) => typeof value === "string";
|
|
13775
|
+
var asString = (value) => isStringValue2(value) ? value : undefined;
|
|
13074
13776
|
var imageUrlFromRef = (ref, projectId, dataset) => {
|
|
13075
13777
|
const match = ref.match(IMAGE_REF);
|
|
13076
13778
|
if (!match?.groups) {
|
|
@@ -13129,7 +13831,7 @@ var sanitySource = (options, ctx) => {
|
|
|
13129
13831
|
const raw = frontmatter_default.stringify(markdown, data);
|
|
13130
13832
|
return {
|
|
13131
13833
|
body: { format: "md", text: markdown },
|
|
13132
|
-
data,
|
|
13834
|
+
data: { ...data },
|
|
13133
13835
|
hash: hashText(raw),
|
|
13134
13836
|
lastModified: asString(getPath(doc, fields.lastModified ?? "_updatedAt")),
|
|
13135
13837
|
raw,
|
|
@@ -13354,7 +14056,8 @@ var normalizeLoadedEntries = (loaded, config) => {
|
|
|
13354
14056
|
prefix: source.prefix,
|
|
13355
14057
|
staged: source.staged
|
|
13356
14058
|
},
|
|
13357
|
-
typeFrontmatter
|
|
14059
|
+
typeFrontmatter,
|
|
14060
|
+
versions: config.versions
|
|
13358
14061
|
});
|
|
13359
14062
|
if (normalized.pages.length === 0 && normalized.diagnostics.length > 0) {
|
|
13360
14063
|
droppedPages += 1;
|
|
@@ -13387,7 +14090,10 @@ var scanProject = async (root, options = {}) => {
|
|
|
13387
14090
|
const localeDirs = config.i18n && config.i18n.parser === "dir" ? config.i18n.locales.flatMap((locale) => locale.code === config.i18n?.defaultLocale ? [] : [locale.code]) : undefined;
|
|
13388
14091
|
const [loaded, folderMeta] = await Promise.all([
|
|
13389
14092
|
Promise.all(sources.map(async (source) => ({ source, ...await source.load() }))),
|
|
13390
|
-
discoverFolderMeta(metaSources, {
|
|
14093
|
+
discoverFolderMeta(metaSources, {
|
|
14094
|
+
localeDirs,
|
|
14095
|
+
versionDirs: config.versions?.archived.map((version) => version.id)
|
|
14096
|
+
})
|
|
13391
14097
|
]);
|
|
13392
14098
|
const sharedFolderMeta = new Map([
|
|
13393
14099
|
...loaded.flatMap(({ folderMeta: sourceMeta }) => Object.entries(sourceMeta ?? {})),
|
|
@@ -13400,6 +14106,7 @@ var scanProject = async (root, options = {}) => {
|
|
|
13400
14106
|
} = normalizeLoadedEntries(loaded, config);
|
|
13401
14107
|
const pages = mode === "build" && !preview ? allPages.filter((page) => !page.meta.draft) : allPages;
|
|
13402
14108
|
const lastModified = resolveLastModifiedConfig(config.lastModified);
|
|
14109
|
+
const lastModifiedWarnings = [];
|
|
13403
14110
|
if (lastModified.enabled && lastModified.source === "git") {
|
|
13404
14111
|
const fsPaths = pages.map((page) => page.sourcePath).filter((path) => path !== undefined);
|
|
13405
14112
|
const contentRoots = sources.flatMap((source) => source.staged || !source.contentRoot ? [] : [source.contentRoot]);
|
|
@@ -13409,16 +14116,20 @@ var scanProject = async (root, options = {}) => {
|
|
|
13409
14116
|
page.lastModified = gitTimes.get(page.sourcePath);
|
|
13410
14117
|
}
|
|
13411
14118
|
}
|
|
14119
|
+
const undated = pages.filter((page) => page.sourcePath && !page.lastModified).length;
|
|
14120
|
+
lastModifiedWarnings.push(...lastModifiedShallowWarning(context.root, undated));
|
|
13412
14121
|
}
|
|
13413
14122
|
const graph = buildContentGraph(pages, {
|
|
13414
14123
|
basePath: config.basePath,
|
|
13415
14124
|
folderMeta: folderMeta.meta,
|
|
13416
14125
|
i18n: config.i18n,
|
|
13417
14126
|
navigation: config.navigation,
|
|
13418
|
-
sharedFolderMeta
|
|
14127
|
+
sharedFolderMeta,
|
|
14128
|
+
versions: config.versions
|
|
13419
14129
|
});
|
|
13420
14130
|
const manifest = buildManifest({ config, context, graph });
|
|
13421
|
-
const i18nWarnings = config.i18n ? i18nDiagnostics(pages, config.i18n) : [];
|
|
14131
|
+
const i18nWarnings = config.i18n ? i18nDiagnostics(pages, config.i18n, config.versions) : [];
|
|
14132
|
+
const versionWarnings = config.versions ? versionsDiagnostics(pages, config.versions) : [];
|
|
13422
14133
|
return {
|
|
13423
14134
|
config,
|
|
13424
14135
|
context,
|
|
@@ -13427,7 +14138,9 @@ var scanProject = async (root, options = {}) => {
|
|
|
13427
14138
|
...folderMeta.diagnostics,
|
|
13428
14139
|
...entryIdDiagnostics(pages, resolveDocsCollection(config, context).base),
|
|
13429
14140
|
...graph.diagnostics,
|
|
13430
|
-
...i18nWarnings
|
|
14141
|
+
...i18nWarnings,
|
|
14142
|
+
...versionWarnings,
|
|
14143
|
+
...lastModifiedWarnings
|
|
13431
14144
|
],
|
|
13432
14145
|
droppedPages,
|
|
13433
14146
|
graph,
|
|
@@ -13547,9 +14260,10 @@ var auditCommand = defineCommand2({
|
|
|
13547
14260
|
return;
|
|
13548
14261
|
}
|
|
13549
14262
|
const root = process.cwd();
|
|
13550
|
-
const
|
|
13551
|
-
|
|
13552
|
-
|
|
14263
|
+
const gateInput = args["fail-on"] ?? (args.strict ? "warning" : "error");
|
|
14264
|
+
const gate = SEVERITIES.find((severity) => severity === gateInput);
|
|
14265
|
+
if (gate === undefined) {
|
|
14266
|
+
logger.error(`Invalid --fail-on "${gateInput}" (use ${SEVERITIES.join(" | ")}).`);
|
|
13553
14267
|
process.exit(1);
|
|
13554
14268
|
}
|
|
13555
14269
|
const agents = Object.keys(AGENTS).filter((kind) => args[kind]);
|
|
@@ -13748,12 +14462,8 @@ var buildAgentReadability = (project) => {
|
|
|
13748
14462
|
return site ? absoluteUrl(site, based) : based;
|
|
13749
14463
|
};
|
|
13750
14464
|
const negotiates = config.deployment.output === "server" && (config.deployment.adapter === "vercel" || config.deployment.adapter === "cloudflare");
|
|
13751
|
-
const
|
|
13752
|
-
|
|
13753
|
-
...negotiates ? { contentNegotiation: "text/markdown" } : {},
|
|
13754
|
-
pattern: abs("/{route}.md")
|
|
13755
|
-
}
|
|
13756
|
-
};
|
|
14465
|
+
const markdown = negotiates ? { contentNegotiation: "text/markdown", pattern: abs("/{route}.md") } : { pattern: abs("/{route}.md") };
|
|
14466
|
+
const artifacts = { markdown };
|
|
13757
14467
|
if (config.ai.llmsTxt.enabled) {
|
|
13758
14468
|
artifacts.llmsFullTxt = abs("/llms-full.txt");
|
|
13759
14469
|
artifacts.llmsTxt = abs("/llms.txt");
|
|
@@ -13934,6 +14644,8 @@ var parseYouTubeId = (input) => {
|
|
|
13934
14644
|
};
|
|
13935
14645
|
|
|
13936
14646
|
// src/ai/component-markdown.ts
|
|
14647
|
+
var isString4 = (value) => typeof value === "string";
|
|
14648
|
+
var isNumber = (value) => typeof value === "number";
|
|
13937
14649
|
var evaluateExpression = (raw, frontmatter) => {
|
|
13938
14650
|
try {
|
|
13939
14651
|
const value = new Function("frontmatter", `"use strict"; return (${raw});`)(frontmatter);
|
|
@@ -13952,7 +14664,7 @@ var readProps = (node, frontmatter) => {
|
|
|
13952
14664
|
}
|
|
13953
14665
|
if (attribute.value === null || attribute.value === undefined) {
|
|
13954
14666
|
props[attribute.name] = true;
|
|
13955
|
-
} else if (
|
|
14667
|
+
} else if (isString4(attribute.value)) {
|
|
13956
14668
|
props[attribute.name] = attribute.value;
|
|
13957
14669
|
} else {
|
|
13958
14670
|
const result = evaluateExpression(attribute.value.value, frontmatter);
|
|
@@ -14003,9 +14715,10 @@ var cellCode = (value) => {
|
|
|
14003
14715
|
const text = cellText(value);
|
|
14004
14716
|
return text && !text.includes("`") ? `\`${text}\`` : text;
|
|
14005
14717
|
};
|
|
14718
|
+
var isTypeEntryMap = (value) => typeof value === "object" && value !== null;
|
|
14006
14719
|
var typeTable = ({ children, props }) => {
|
|
14007
14720
|
const { type } = props;
|
|
14008
|
-
if (type
|
|
14721
|
+
if (!isTypeEntryMap(type)) {
|
|
14009
14722
|
return null;
|
|
14010
14723
|
}
|
|
14011
14724
|
const entries = Object.entries(type);
|
|
@@ -14013,7 +14726,7 @@ var typeTable = ({ children, props }) => {
|
|
|
14013
14726
|
const prop = cellCode(`${name}${info.required ? "" : "?"}`);
|
|
14014
14727
|
const typeCell = info.typeDescriptionLink ? `[${cellCode(info.type)}](${cellText(info.typeDescriptionLink)})` : cellCode(info.type);
|
|
14015
14728
|
const defaultCell = info.default === undefined ? "-" : cellCode(info.default);
|
|
14016
|
-
const description = cellText([info.description, info.typeDescription].filter((part) =>
|
|
14729
|
+
const description = cellText([info.description, info.typeDescription].filter((part) => isString4(part) && part !== "").join(" "));
|
|
14017
14730
|
return [prop, typeCell, defaultCell, description];
|
|
14018
14731
|
});
|
|
14019
14732
|
const table = rows.length > 0 ? markdownTable([["Prop", "Type", "Default", "Description"], ...rows], {
|
|
@@ -14024,8 +14737,8 @@ var typeTable = ({ children, props }) => {
|
|
|
14024
14737
|
`);
|
|
14025
14738
|
};
|
|
14026
14739
|
var callout = ({ children, props }) => {
|
|
14027
|
-
const type =
|
|
14028
|
-
const label =
|
|
14740
|
+
const type = isString4(props.type) ? props.type : "info";
|
|
14741
|
+
const label = isString4(props.title) && props.title !== "" ? props.title : type.charAt(0).toUpperCase() + type.slice(1);
|
|
14029
14742
|
if (!children) {
|
|
14030
14743
|
return `> **${label}**`;
|
|
14031
14744
|
}
|
|
@@ -14053,7 +14766,7 @@ var steps = ({ childComponents, children }) => {
|
|
|
14053
14766
|
return children;
|
|
14054
14767
|
}
|
|
14055
14768
|
return items.map((step, index) => {
|
|
14056
|
-
const title =
|
|
14769
|
+
const title = isString4(step.props.title) && step.props.title !== "" ? `**${step.props.title}**` : "";
|
|
14057
14770
|
const content = [title, step.children].filter(Boolean).join(`
|
|
14058
14771
|
|
|
14059
14772
|
`);
|
|
@@ -14068,7 +14781,7 @@ var tabs = ({ childComponents, children }) => {
|
|
|
14068
14781
|
return children;
|
|
14069
14782
|
}
|
|
14070
14783
|
return items.map((tab, index) => {
|
|
14071
|
-
const title =
|
|
14784
|
+
const title = isString4(tab.props.title) && tab.props.title !== "" ? tab.props.title : `Tab ${index + 1}`;
|
|
14072
14785
|
return tab.children ? `**${title}**
|
|
14073
14786
|
|
|
14074
14787
|
${tab.children}` : `**${title}**`;
|
|
@@ -14078,17 +14791,17 @@ ${tab.children}` : `**${title}**`;
|
|
|
14078
14791
|
};
|
|
14079
14792
|
var youtube = ({ props }) => {
|
|
14080
14793
|
let input = "";
|
|
14081
|
-
if (
|
|
14794
|
+
if (isString4(props.id)) {
|
|
14082
14795
|
input = props.id;
|
|
14083
|
-
} else if (
|
|
14796
|
+
} else if (isString4(props.url)) {
|
|
14084
14797
|
input = props.url;
|
|
14085
14798
|
}
|
|
14086
14799
|
const videoId = parseYouTubeId(input);
|
|
14087
14800
|
if (!videoId) {
|
|
14088
14801
|
return null;
|
|
14089
14802
|
}
|
|
14090
|
-
const start =
|
|
14091
|
-
const title =
|
|
14803
|
+
const start = isNumber(props.start) && props.start > 0 ? `&t=${Math.floor(props.start)}s` : "";
|
|
14804
|
+
const title = isString4(props.title) && props.title !== "" ? props.title : "Watch on YouTube";
|
|
14092
14805
|
return `[${title}](https://www.youtube.com/watch?v=${videoId}${start})`;
|
|
14093
14806
|
};
|
|
14094
14807
|
var fencedBlock = (lang, code) => {
|
|
@@ -14102,7 +14815,7 @@ ${fence}`;
|
|
|
14102
14815
|
};
|
|
14103
14816
|
var exampleComponentSerializers = (examples) => ({
|
|
14104
14817
|
Component: ({ props }) => {
|
|
14105
|
-
const path =
|
|
14818
|
+
const path = isString4(props.path) ? props.path : undefined;
|
|
14106
14819
|
const example = path === undefined ? undefined : examples[path];
|
|
14107
14820
|
return example ? fencedBlock(example.lang, example.source) : null;
|
|
14108
14821
|
}
|
|
@@ -14212,19 +14925,28 @@ var pageUrl = (route, site, base = "") => {
|
|
|
14212
14925
|
const path = withBasePath(base, route);
|
|
14213
14926
|
return encodeURI(site ? absoluteUrl(site, path) : path);
|
|
14214
14927
|
};
|
|
14215
|
-
var eligiblePages = (project) => project.graph.pages.filter((page) => !(page.meta.ai.exclude || page.meta.draft || page.meta.sidebar.hidden || page.meta.seo.noindex && page.source.name !== "openapi") && (project.config.ai.llmsTxt.openapi || page.source.name !== "openapi"));
|
|
14928
|
+
var eligiblePages = (project, options = {}) => project.graph.pages.filter((page) => !(page.meta.ai.exclude || page.meta.draft || page.meta.sidebar.hidden || page.meta.seo.noindex && page.source.name !== "openapi" || options.versions === "current" && page.version !== "") && (project.config.ai.llmsTxt.openapi || page.source.name !== "openapi"));
|
|
14216
14929
|
var indexedNavigations = (project) => {
|
|
14217
|
-
const { i18n } = project.config;
|
|
14218
|
-
|
|
14219
|
-
|
|
14220
|
-
|
|
14221
|
-
|
|
14222
|
-
|
|
14223
|
-
|
|
14224
|
-
|
|
14930
|
+
const { i18n, versions } = project.config;
|
|
14931
|
+
const current = i18n ? i18n.locales.flatMap(({ code, label }) => {
|
|
14932
|
+
const nav = project.graph.navigationByLocale[code];
|
|
14933
|
+
if (!nav) {
|
|
14934
|
+
return [];
|
|
14935
|
+
}
|
|
14936
|
+
return [
|
|
14937
|
+
{ label: code === i18n.defaultLocale ? undefined : label, nav }
|
|
14938
|
+
];
|
|
14939
|
+
}) : [{ nav: project.graph.navigation }];
|
|
14940
|
+
const archived = (versions?.archived ?? []).flatMap((version) => {
|
|
14941
|
+
const byLocale = project.graph.navigationByVersion[version.id] ?? {};
|
|
14942
|
+
const versionLabel = `${version.label ?? version.id} (archived)`;
|
|
14943
|
+
return Object.entries(byLocale).flatMap(([code, nav]) => {
|
|
14944
|
+
const locale = i18n?.locales.find((entry) => entry.code === code);
|
|
14945
|
+
const label = locale && code !== i18n?.defaultLocale ? `${locale.label} — ${versionLabel}` : versionLabel;
|
|
14946
|
+
return [{ label, nav }];
|
|
14225
14947
|
});
|
|
14226
|
-
}
|
|
14227
|
-
return [
|
|
14948
|
+
});
|
|
14949
|
+
return [...current, ...archived];
|
|
14228
14950
|
};
|
|
14229
14951
|
var buildLlmsIndex = (project) => {
|
|
14230
14952
|
const { config } = project;
|
|
@@ -14301,7 +15023,7 @@ var buildLlmsIndex = (project) => {
|
|
|
14301
15023
|
};
|
|
14302
15024
|
var buildFull = async (project) => {
|
|
14303
15025
|
const { config } = project;
|
|
14304
|
-
const pages = eligiblePages(project).toSorted((a, b) => a.route.localeCompare(b.route));
|
|
15026
|
+
const pages = eligiblePages(project, { versions: "current" }).toSorted((a, b) => a.route.localeCompare(b.route));
|
|
14305
15027
|
const components = {
|
|
14306
15028
|
...exampleComponentSerializers(project.examples ?? {}),
|
|
14307
15029
|
...config.ai.markdownComponents
|
|
@@ -14446,6 +15168,7 @@ var collectEntries = async (dir, prefix = "") => {
|
|
|
14446
15168
|
}
|
|
14447
15169
|
return entries;
|
|
14448
15170
|
};
|
|
15171
|
+
var isString5 = (value) => typeof value === "string";
|
|
14449
15172
|
var skillMeta = (raw, dirName) => {
|
|
14450
15173
|
let data;
|
|
14451
15174
|
try {
|
|
@@ -14456,8 +15179,8 @@ var skillMeta = (raw, dirName) => {
|
|
|
14456
15179
|
warning: `Skill "${dirName}" has unparsable SKILL.md frontmatter; skipped.`
|
|
14457
15180
|
};
|
|
14458
15181
|
}
|
|
14459
|
-
const name =
|
|
14460
|
-
const description =
|
|
15182
|
+
const name = isString5(data.name) ? data.name : "";
|
|
15183
|
+
const description = isString5(data.description) ? data.description : "";
|
|
14461
15184
|
if (!(name && description)) {
|
|
14462
15185
|
return {
|
|
14463
15186
|
meta: null,
|
|
@@ -14582,6 +15305,8 @@ var MAX_RULES = 100;
|
|
|
14582
15305
|
var MAX_RULE_LENGTH = 100;
|
|
14583
15306
|
var FALLBACK_RULES = ["/*", "!/_astro/*", "!/*.md", "!/*.mdx", "!/*.txt"];
|
|
14584
15307
|
var basePrefix = (base) => base && base !== "/" ? base.replace(/\/$/u, "") : "";
|
|
15308
|
+
var isJsonObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15309
|
+
var isJsonString = (value) => typeof value === "string";
|
|
14585
15310
|
var isNegativeRule = (rule) => rule.startsWith("!");
|
|
14586
15311
|
var ruleBody = (rule) => isNegativeRule(rule) ? rule.slice(1) : rule;
|
|
14587
15312
|
var buildRunWorkerFirstRules = (routePaths, base) => {
|
|
@@ -14836,15 +15561,15 @@ var injectWorkerNegotiation = (wranglerText, options) => {
|
|
|
14836
15561
|
} catch {
|
|
14837
15562
|
return null;
|
|
14838
15563
|
}
|
|
14839
|
-
if (
|
|
15564
|
+
if (!isJsonObject(config)) {
|
|
14840
15565
|
return null;
|
|
14841
15566
|
}
|
|
14842
15567
|
const { main } = config;
|
|
14843
|
-
if (
|
|
15568
|
+
if (!isJsonString(main) || main.length === 0 || main === NEGOTIATION_WORKER_FILE) {
|
|
14844
15569
|
return null;
|
|
14845
15570
|
}
|
|
14846
|
-
const assets = config
|
|
14847
|
-
if (assets
|
|
15571
|
+
const { assets } = config;
|
|
15572
|
+
if (!isJsonObject(assets) || !isJsonString(assets.binding)) {
|
|
14848
15573
|
return null;
|
|
14849
15574
|
}
|
|
14850
15575
|
const {
|
|
@@ -15059,6 +15784,16 @@ var buildSitemapFiles = (project) => {
|
|
|
15059
15784
|
}
|
|
15060
15785
|
const base = siteRoot(site);
|
|
15061
15786
|
const deployBase = normalizeBasePath(project.config.deployment.base);
|
|
15787
|
+
const { versions } = project.config;
|
|
15788
|
+
const archivedById = new Map((versions?.archived ?? []).map((version) => [version.id, version]));
|
|
15789
|
+
const currentKeys = versions ? new Set(project.graph.pages.flatMap((page) => page.version === "" ? [`${page.versionKey}\x00${page.locale}`] : [])) : null;
|
|
15790
|
+
const archivedExcluded = (page) => {
|
|
15791
|
+
if (!page.version) {
|
|
15792
|
+
return false;
|
|
15793
|
+
}
|
|
15794
|
+
const archived = archivedById.get(page.version);
|
|
15795
|
+
return Boolean(archived?.noindex || archived?.canonical === "latest" && currentKeys?.has(`${page.versionKey}\x00${page.locale}`));
|
|
15796
|
+
};
|
|
15062
15797
|
const seen = new Set;
|
|
15063
15798
|
const urls = [];
|
|
15064
15799
|
const pushUrl = (route, lastModified) => {
|
|
@@ -15070,7 +15805,7 @@ var buildSitemapFiles = (project) => {
|
|
|
15070
15805
|
urls.push(` <url><loc>${loc}</loc>${lastmodTag(lastModified)}</url>`);
|
|
15071
15806
|
};
|
|
15072
15807
|
for (const page of project.graph.pages) {
|
|
15073
|
-
if (page.meta.draft || page.meta.sidebar.hidden || page.meta.seo.noindex || ERROR_ROUTES3.has(page.route)) {
|
|
15808
|
+
if (page.meta.draft || page.meta.sidebar.hidden || page.meta.seo.noindex || ERROR_ROUTES3.has(page.route) || archivedExcluded(page)) {
|
|
15074
15809
|
continue;
|
|
15075
15810
|
}
|
|
15076
15811
|
pushUrl(withBasePath(deployBase, page.route), page.lastModified);
|
|
@@ -15109,6 +15844,7 @@ ${references.join(`
|
|
|
15109
15844
|
|
|
15110
15845
|
// src/deploy/vercel-negotiation.ts
|
|
15111
15846
|
var ACCEPT_MARKDOWN_HEADER_VALUE = "(.*,)?\\s*text/(x-)?markdown(\\s*[;,].*)?$";
|
|
15847
|
+
var isString6 = (value) => typeof value === "string";
|
|
15112
15848
|
var ACCEPT_MARKDOWN_CONDITION = [
|
|
15113
15849
|
{ key: "accept", type: "header", value: ACCEPT_MARKDOWN_HEADER_VALUE }
|
|
15114
15850
|
];
|
|
@@ -15163,12 +15899,14 @@ var buildNegotiationRoutes = (routePaths, homeTokens) => {
|
|
|
15163
15899
|
return { headerRoutes, rewriteRoutes };
|
|
15164
15900
|
};
|
|
15165
15901
|
var HOME_SRC = "^/$";
|
|
15166
|
-
var
|
|
15902
|
+
var TRAILING_SLASH_REDIRECT = {
|
|
15903
|
+
headers: { Location: "/$1" },
|
|
15904
|
+
src: "^/(.+)/$",
|
|
15905
|
+
status: 308
|
|
15906
|
+
};
|
|
15907
|
+
var isNegotiationRoute = (route) => route.has?.some((condition) => condition.value === ACCEPT_MARKDOWN_HEADER_VALUE) === true || route.continue === true && route.headers?.vary === "Accept" && isString6(route.src) && Object.keys(route).length === 3 || route.continue === true && isString6(route.headers?.link) && route.src === HOME_SRC && Object.keys(route).length === 3 || route.status === TRAILING_SLASH_REDIRECT.status && route.src === TRAILING_SLASH_REDIRECT.src;
|
|
15167
15908
|
var injectNegotiationRoutes = (configText, routePaths, homeLinkHeader, contentTypeOverrides, homeTokens) => {
|
|
15168
15909
|
const overrideEntries = Object.entries(contentTypeOverrides ?? {});
|
|
15169
|
-
if (routePaths.length === 0 && !homeLinkHeader && overrideEntries.length === 0) {
|
|
15170
|
-
return null;
|
|
15171
|
-
}
|
|
15172
15910
|
let config;
|
|
15173
15911
|
try {
|
|
15174
15912
|
config = JSON.parse(configText);
|
|
@@ -15194,7 +15932,7 @@ var injectNegotiationRoutes = (configText, routePaths, homeLinkHeader, contentTy
|
|
|
15194
15932
|
src: HOME_SRC
|
|
15195
15933
|
});
|
|
15196
15934
|
}
|
|
15197
|
-
routes.splice(filesystemIndex, 0, ...headerRoutes, ...rewriteRoutes);
|
|
15935
|
+
routes.splice(filesystemIndex, 0, ...headerRoutes, ...rewriteRoutes, TRAILING_SLASH_REDIRECT);
|
|
15198
15936
|
config.routes = routes;
|
|
15199
15937
|
return `${JSON.stringify(config, null, "\t")}
|
|
15200
15938
|
`;
|
|
@@ -15220,6 +15958,7 @@ import { gfmFromMarkdown as gfmFromMarkdown2 } from "mdast-util-gfm";
|
|
|
15220
15958
|
import { gfm as gfm2 } from "micromark-extension-gfm";
|
|
15221
15959
|
|
|
15222
15960
|
// src/search/facets.ts
|
|
15961
|
+
var isFacetValue = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
15223
15962
|
var pageFacets = (page, config) => {
|
|
15224
15963
|
const declared = config.content.types[page.contentType]?.facets;
|
|
15225
15964
|
if (!declared || declared.length === 0 || !page.custom) {
|
|
@@ -15228,7 +15967,7 @@ var pageFacets = (page, config) => {
|
|
|
15228
15967
|
const facets = {};
|
|
15229
15968
|
for (const key of declared) {
|
|
15230
15969
|
const value = page.custom[key];
|
|
15231
|
-
if (
|
|
15970
|
+
if (isFacetValue(value)) {
|
|
15232
15971
|
facets[key] = String(value);
|
|
15233
15972
|
}
|
|
15234
15973
|
}
|
|
@@ -15237,7 +15976,7 @@ var pageFacets = (page, config) => {
|
|
|
15237
15976
|
|
|
15238
15977
|
// src/search/documents.ts
|
|
15239
15978
|
var HTML_OR_JSX = /<\/?[a-zA-Z][^\n<>]*>|<\/?>/gu;
|
|
15240
|
-
var
|
|
15979
|
+
var WHITESPACE4 = /\s+/gu;
|
|
15241
15980
|
var INLINE_PARENTS = new Set([
|
|
15242
15981
|
"delete",
|
|
15243
15982
|
"emphasis",
|
|
@@ -15289,7 +16028,7 @@ var toPlainText = (markdown) => {
|
|
|
15289
16028
|
});
|
|
15290
16029
|
const out = [];
|
|
15291
16030
|
collectText(tree, out);
|
|
15292
|
-
return out.join("").replaceAll(
|
|
16031
|
+
return out.join("").replaceAll(WHITESPACE4, " ").trim();
|
|
15293
16032
|
};
|
|
15294
16033
|
var buildCrumbIndex = (sidebar) => {
|
|
15295
16034
|
const index = new Map;
|
|
@@ -15323,7 +16062,11 @@ var buildCrumbIndex = (sidebar) => {
|
|
|
15323
16062
|
var buildSearchDocuments = async (project, options) => {
|
|
15324
16063
|
const pageById = new Map(project.graph.pages.map((page) => [page.id, page]));
|
|
15325
16064
|
const byLocale = Object.values(project.graph.navigationByLocale ?? {});
|
|
15326
|
-
const
|
|
16065
|
+
const byVersion = Object.values(project.graph.navigationByVersion ?? {}).flatMap((locales) => Object.values(locales)).map((nav) => nav.sidebar);
|
|
16066
|
+
const sidebars = [
|
|
16067
|
+
...byLocale.length > 0 ? byLocale.map((nav) => nav.sidebar) : [project.graph.navigation?.sidebar ?? []],
|
|
16068
|
+
...byVersion
|
|
16069
|
+
];
|
|
15327
16070
|
const crumbs = new Map;
|
|
15328
16071
|
for (const sidebar of sidebars) {
|
|
15329
16072
|
for (const [route, crumb] of buildCrumbIndex(sidebar)) {
|
|
@@ -15346,18 +16089,22 @@ var buildSearchDocuments = async (project, options) => {
|
|
|
15346
16089
|
const tags = page?.meta?.search?.tags;
|
|
15347
16090
|
const crumb = crumbs.get(route.path);
|
|
15348
16091
|
const facets = page ? pageFacets(page, project.config) : undefined;
|
|
15349
|
-
|
|
16092
|
+
const document = {
|
|
15350
16093
|
breadcrumb: crumb?.breadcrumb ?? [],
|
|
15351
16094
|
content: body,
|
|
15352
16095
|
contentType: route.contentType,
|
|
15353
16096
|
description: page?.description ?? "",
|
|
15354
|
-
...facets ? { facets } : {},
|
|
15355
16097
|
locale: route.locale,
|
|
15356
16098
|
route: route.path,
|
|
15357
16099
|
section: crumb?.section || "Docs",
|
|
15358
16100
|
tags: tags && tags.length > 0 ? tags : undefined,
|
|
15359
|
-
title: route.title
|
|
16101
|
+
title: route.title,
|
|
16102
|
+
version: route.version
|
|
15360
16103
|
};
|
|
16104
|
+
if (facets) {
|
|
16105
|
+
document.facets = facets;
|
|
16106
|
+
}
|
|
16107
|
+
return document;
|
|
15361
16108
|
}));
|
|
15362
16109
|
};
|
|
15363
16110
|
var toSearchRecords = (documents) => documents.map((doc) => ({
|
|
@@ -15367,7 +16114,8 @@ var toSearchRecords = (documents) => documents.map((doc) => ({
|
|
|
15367
16114
|
locale: doc.locale,
|
|
15368
16115
|
tag: doc.tags?.[0],
|
|
15369
16116
|
title: doc.title,
|
|
15370
|
-
url: doc.route
|
|
16117
|
+
url: doc.route,
|
|
16118
|
+
version: doc.version || "current"
|
|
15371
16119
|
}));
|
|
15372
16120
|
|
|
15373
16121
|
// src/search/sync/algolia.ts
|
|
@@ -15451,7 +16199,8 @@ var syncTypesense = async (records, config) => {
|
|
|
15451
16199
|
{ name: "content", type: "string" },
|
|
15452
16200
|
{ name: "url", type: "string" },
|
|
15453
16201
|
{ facet: true, name: "tag", optional: true, type: "string" },
|
|
15454
|
-
{ facet: true, name: "locale", optional: true, type: "string" }
|
|
16202
|
+
{ facet: true, name: "locale", optional: true, type: "string" },
|
|
16203
|
+
{ facet: true, name: "version", optional: true, type: "string" }
|
|
15455
16204
|
],
|
|
15456
16205
|
name: config.collection
|
|
15457
16206
|
});
|
|
@@ -15462,7 +16211,8 @@ var syncTypesense = async (records, config) => {
|
|
|
15462
16211
|
locale: record.locale,
|
|
15463
16212
|
tag: record.tag,
|
|
15464
16213
|
title: record.title,
|
|
15465
|
-
url: record.url
|
|
16214
|
+
url: record.url,
|
|
16215
|
+
version: record.version
|
|
15466
16216
|
}));
|
|
15467
16217
|
await client.collections(config.collection).documents().import(documents, { action: "upsert" });
|
|
15468
16218
|
};
|
|
@@ -15500,6 +16250,8 @@ import {
|
|
|
15500
16250
|
import { join as join21 } from "pathe";
|
|
15501
16251
|
var lockPath = (outDir) => join21(outDir, "dev.lock");
|
|
15502
16252
|
var isValidPid = (pid) => typeof pid === "number" && Number.isInteger(pid) && pid > 0;
|
|
16253
|
+
var isPortNumber = (port) => typeof port === "number";
|
|
16254
|
+
var isLockRecord = (data) => typeof data === "object" && data !== null;
|
|
15503
16255
|
var parseLock = (raw) => {
|
|
15504
16256
|
let data;
|
|
15505
16257
|
try {
|
|
@@ -15510,10 +16262,10 @@ var parseLock = (raw) => {
|
|
|
15510
16262
|
if (isValidPid(data)) {
|
|
15511
16263
|
return { pid: data };
|
|
15512
16264
|
}
|
|
15513
|
-
if (
|
|
16265
|
+
if (isLockRecord(data)) {
|
|
15514
16266
|
const { pid, port } = data;
|
|
15515
16267
|
if (isValidPid(pid)) {
|
|
15516
|
-
return
|
|
16268
|
+
return isPortNumber(port) ? { pid, port } : { pid };
|
|
15517
16269
|
}
|
|
15518
16270
|
}
|
|
15519
16271
|
return null;
|
|
@@ -15534,10 +16286,13 @@ var readDevLock = (outDir) => {
|
|
|
15534
16286
|
const lock = parseLock(readFileSync5(path, "utf-8"));
|
|
15535
16287
|
return lock && isProcessAlive(lock.pid) ? lock : null;
|
|
15536
16288
|
};
|
|
15537
|
-
var lockPayload = (port) =>
|
|
15538
|
-
pid: process.pid
|
|
15539
|
-
|
|
15540
|
-
|
|
16289
|
+
var lockPayload = (port) => {
|
|
16290
|
+
const info = { pid: process.pid };
|
|
16291
|
+
if (port !== undefined) {
|
|
16292
|
+
info.port = port;
|
|
16293
|
+
}
|
|
16294
|
+
return JSON.stringify(info);
|
|
16295
|
+
};
|
|
15541
16296
|
var writeLock = (outDir, port) => {
|
|
15542
16297
|
writeFileSync(lockPath(outDir), lockPayload(port));
|
|
15543
16298
|
};
|
|
@@ -15669,27 +16424,39 @@ var buildMcpData = async (project) => {
|
|
|
15669
16424
|
}
|
|
15670
16425
|
const page = pageById.get(route.id);
|
|
15671
16426
|
const facets = page ? pageFacets(page, config) : undefined;
|
|
15672
|
-
|
|
16427
|
+
const entry = {
|
|
15673
16428
|
contentType: route.contentType,
|
|
15674
16429
|
description: page?.description,
|
|
15675
|
-
...facets ? { facets } : {},
|
|
15676
16430
|
indexable: route.indexable,
|
|
15677
16431
|
lastModified: route.lastModified ?? null,
|
|
16432
|
+
locale: route.locale,
|
|
15678
16433
|
route: route.path,
|
|
15679
|
-
title: route.title
|
|
15680
|
-
|
|
16434
|
+
title: route.title,
|
|
16435
|
+
version: route.version
|
|
16436
|
+
};
|
|
16437
|
+
if (facets) {
|
|
16438
|
+
entry.facets = facets;
|
|
16439
|
+
}
|
|
16440
|
+
routes.push(entry);
|
|
15681
16441
|
}
|
|
15682
|
-
|
|
16442
|
+
const data = {
|
|
15683
16443
|
base: normalizeBasePath(config.deployment.base),
|
|
15684
16444
|
defaultLocale: config.i18n?.defaultLocale,
|
|
15685
|
-
documents: documents.map((doc) =>
|
|
15686
|
-
|
|
15687
|
-
|
|
15688
|
-
|
|
15689
|
-
|
|
15690
|
-
|
|
15691
|
-
|
|
15692
|
-
|
|
16445
|
+
documents: documents.map((doc) => {
|
|
16446
|
+
const document = {
|
|
16447
|
+
content: doc.content,
|
|
16448
|
+
contentType: doc.contentType,
|
|
16449
|
+
description: doc.description,
|
|
16450
|
+
locale: doc.locale,
|
|
16451
|
+
route: doc.route,
|
|
16452
|
+
title: doc.title,
|
|
16453
|
+
version: doc.version
|
|
16454
|
+
};
|
|
16455
|
+
if (doc.facets) {
|
|
16456
|
+
document.facets = doc.facets;
|
|
16457
|
+
}
|
|
16458
|
+
return document;
|
|
16459
|
+
}),
|
|
15693
16460
|
instructions: config.ai.mcp.instructions,
|
|
15694
16461
|
name: config.ai.mcp.name ?? config.title,
|
|
15695
16462
|
navigation: graph.navigation,
|
|
@@ -15698,6 +16465,14 @@ var buildMcpData = async (project) => {
|
|
|
15698
16465
|
site: config.deployment.site ?? null,
|
|
15699
16466
|
version: manifest.blumeVersion
|
|
15700
16467
|
};
|
|
16468
|
+
if (config.versions) {
|
|
16469
|
+
data.archivedVersions = config.versions.archived.map((version) => version.id);
|
|
16470
|
+
data.navigationByVersion = graph.navigationByVersion;
|
|
16471
|
+
}
|
|
16472
|
+
if (config.i18n) {
|
|
16473
|
+
data.navigationByLocale = graph.navigationByLocale;
|
|
16474
|
+
}
|
|
16475
|
+
return data;
|
|
15701
16476
|
};
|
|
15702
16477
|
|
|
15703
16478
|
// src/ai/mcp/tools.ts
|
|
@@ -15705,7 +16480,7 @@ var READ_ONLY = { openWorldHint: false, readOnlyHint: true };
|
|
|
15705
16480
|
var MCP_TOOLS = [
|
|
15706
16481
|
{
|
|
15707
16482
|
annotations: READ_ONLY,
|
|
15708
|
-
description: 'Full-text search across the documentation. Returns matching pages with their title, route, content type, and a short excerpt; pass `contentTypes` to search only pages of certain types (e.g. `rfc`, `changelog`),
|
|
16483
|
+
description: 'Full-text search across the documentation. Returns matching pages with their title, route, content type, and a short excerpt; pass `contentTypes` to search only pages of certain types (e.g. `rfc`, `changelog`), `filters` to require facet values the site declares per type (e.g. `{"status": "enforced"}`), and `locale` to search one language. On a versioned site results default to the current docs — pass `version` to search an archived version (e.g. `"v1.0"`) or `"all"` for every version. Use this first to discover relevant pages, then `get_page` to read one in full.',
|
|
15709
16484
|
name: "search_docs",
|
|
15710
16485
|
title: "Search documentation"
|
|
15711
16486
|
},
|
|
@@ -15717,13 +16492,13 @@ var MCP_TOOLS = [
|
|
|
15717
16492
|
},
|
|
15718
16493
|
{
|
|
15719
16494
|
annotations: READ_ONLY,
|
|
15720
|
-
description:
|
|
16495
|
+
description: 'List every documentation page with its route, title, description, content type, and any declared facet values; pass `contentTypes`, `filters`, and/or `locale` to narrow the list. On a versioned site the list defaults to the current docs — pass `version` for an archived version or `"all"`. Useful for enumerating the docs, discovering the types and facets in use, or finding a page when search is too narrow.',
|
|
15721
16496
|
name: "list_pages",
|
|
15722
16497
|
title: "List pages"
|
|
15723
16498
|
},
|
|
15724
16499
|
{
|
|
15725
16500
|
annotations: READ_ONLY,
|
|
15726
|
-
description: "Return the documentation navigation tree (header tabs and the sidebar hierarchy), reflecting how the docs are organized for readers.",
|
|
16501
|
+
description: "Return the documentation navigation tree (header tabs and the sidebar hierarchy), reflecting how the docs are organized for readers. Pass `locale` for a language's tree and, on a versioned site, `version` for an archived snapshot's tree.",
|
|
15727
16502
|
name: "get_navigation",
|
|
15728
16503
|
title: "Get navigation"
|
|
15729
16504
|
}
|
|
@@ -15761,12 +16536,11 @@ var reverseDnsName = (input) => {
|
|
|
15761
16536
|
var HTTP_URL2 = /^https?:\/\//u;
|
|
15762
16537
|
var buildMcpServerCard = (input) => {
|
|
15763
16538
|
const url = serverUrl(input);
|
|
15764
|
-
|
|
16539
|
+
const card = {
|
|
15765
16540
|
$schema: SERVER_CARD_SCHEMA,
|
|
15766
16541
|
capabilities: { tools: { listChanged: false } },
|
|
15767
16542
|
description: truncate(`Model Context Protocol server for the ${input.name} documentation.`),
|
|
15768
16543
|
name: reverseDnsName(input),
|
|
15769
|
-
...HTTP_URL2.test(url) ? { remotes: [{ type: "streamable-http", url }] } : {},
|
|
15770
16544
|
serverInfo: { name: input.name, version: input.version },
|
|
15771
16545
|
title: truncate(input.name),
|
|
15772
16546
|
tools: MCP_TOOLS.map((tool) => ({
|
|
@@ -15778,9 +16552,15 @@ var buildMcpServerCard = (input) => {
|
|
|
15778
16552
|
transport: "streamable-http",
|
|
15779
16553
|
transports: [{ endpoint: url, type: "streamable-http" }],
|
|
15780
16554
|
url,
|
|
15781
|
-
version: input.version
|
|
15782
|
-
...input.site ? { websiteUrl: siteRoot(input.site) } : {}
|
|
16555
|
+
version: input.version
|
|
15783
16556
|
};
|
|
16557
|
+
if (HTTP_URL2.test(url)) {
|
|
16558
|
+
card.remotes = [{ type: "streamable-http", url }];
|
|
16559
|
+
}
|
|
16560
|
+
if (input.site) {
|
|
16561
|
+
card.websiteUrl = siteRoot(input.site);
|
|
16562
|
+
}
|
|
16563
|
+
return card;
|
|
15784
16564
|
};
|
|
15785
16565
|
|
|
15786
16566
|
// src/core/builtin-tags.ts
|
|
@@ -15853,12 +16633,13 @@ import { dirname as dirname8, extname as extname7, isAbsolute as isAbsolute6, re
|
|
|
15853
16633
|
import ts from "typescript";
|
|
15854
16634
|
var GROUPS = ["mdx", "layout", "islands"];
|
|
15855
16635
|
var GROUP_SET = new Set(GROUPS);
|
|
15856
|
-
var
|
|
15857
|
-
|
|
15858
|
-
|
|
15859
|
-
|
|
15860
|
-
|
|
15861
|
-
|
|
16636
|
+
var isGroup = (name) => GROUP_SET.has(name);
|
|
16637
|
+
var FRAMEWORK_BY_EXT = new Map([
|
|
16638
|
+
["jsx", "react"],
|
|
16639
|
+
["svelte", "svelte"],
|
|
16640
|
+
["tsx", "react"],
|
|
16641
|
+
["vue", "vue"]
|
|
16642
|
+
]);
|
|
15862
16643
|
var FRAMEWORK_LABEL = {
|
|
15863
16644
|
react: "React",
|
|
15864
16645
|
svelte: "Svelte",
|
|
@@ -15881,6 +16662,7 @@ var HYDRATION_MODES = new Set([
|
|
|
15881
16662
|
"only",
|
|
15882
16663
|
"visible"
|
|
15883
16664
|
]);
|
|
16665
|
+
var isHydrationMode = (value) => HYDRATION_MODES.has(value);
|
|
15884
16666
|
var emptyAnalysis = () => ({
|
|
15885
16667
|
islands: [],
|
|
15886
16668
|
layout: [],
|
|
@@ -15962,7 +16744,7 @@ var toImport = (specifier, imported, dir) => {
|
|
|
15962
16744
|
}
|
|
15963
16745
|
}
|
|
15964
16746
|
return {
|
|
15965
|
-
framework: FRAMEWORK_BY_EXT
|
|
16747
|
+
framework: FRAMEWORK_BY_EXT.get(extension) ?? null,
|
|
15966
16748
|
name: imported,
|
|
15967
16749
|
path
|
|
15968
16750
|
};
|
|
@@ -15991,7 +16773,7 @@ var applyDescriptorProperty = (descriptor, property, imports, dir) => {
|
|
|
15991
16773
|
} else if (ts.isIdentifier(init)) {
|
|
15992
16774
|
descriptor.source = resolveIdentifier(init.text, imports, dir);
|
|
15993
16775
|
}
|
|
15994
|
-
} else if (name === "client" && ts.isStringLiteral(init) &&
|
|
16776
|
+
} else if (name === "client" && ts.isStringLiteral(init) && isHydrationMode(init.text)) {
|
|
15995
16777
|
descriptor.client = init.text;
|
|
15996
16778
|
} else if (name === "media" && ts.isStringLiteral(init)) {
|
|
15997
16779
|
descriptor.media = init.text;
|
|
@@ -16025,13 +16807,14 @@ var finalize = (key, group, descriptor, label, identifier, warnings) => {
|
|
|
16025
16807
|
if (!client && source?.framework) {
|
|
16026
16808
|
warnings.push(`Override "${key}" points to a ${FRAMEWORK_LABEL[source.framework]} component (${label}) but has no hydration mode, so it renders as static HTML with no interactivity. Add one, e.g. \`${key}: { component: ${JSON.stringify(label)}, client: "load" }\`.`);
|
|
16027
16809
|
}
|
|
16028
|
-
|
|
16029
|
-
|
|
16030
|
-
|
|
16031
|
-
|
|
16032
|
-
|
|
16033
|
-
|
|
16034
|
-
}
|
|
16810
|
+
const normalized = { identifier, key, source };
|
|
16811
|
+
if (client) {
|
|
16812
|
+
normalized.client = client;
|
|
16813
|
+
}
|
|
16814
|
+
if (media) {
|
|
16815
|
+
normalized.media = media;
|
|
16816
|
+
}
|
|
16817
|
+
return normalized;
|
|
16035
16818
|
};
|
|
16036
16819
|
var normalizeEntry2 = (entry, group, imports, dir, warnings) => {
|
|
16037
16820
|
const defaultClient = group === "islands" ? "visible" : undefined;
|
|
@@ -16084,14 +16867,13 @@ var collectGroupOverrides = (property, imports, dir, result) => {
|
|
|
16084
16867
|
return;
|
|
16085
16868
|
}
|
|
16086
16869
|
const name = propName(property.name);
|
|
16087
|
-
if (!(name &&
|
|
16870
|
+
if (!(name && isGroup(name)) || !ts.isObjectLiteralExpression(property.initializer)) {
|
|
16088
16871
|
return;
|
|
16089
16872
|
}
|
|
16090
|
-
const group = name;
|
|
16091
16873
|
for (const entry of property.initializer.properties) {
|
|
16092
|
-
const normalized = normalizeEntry2(entry,
|
|
16874
|
+
const normalized = normalizeEntry2(entry, name, imports, dir, result.warnings);
|
|
16093
16875
|
if (normalized) {
|
|
16094
|
-
result[
|
|
16876
|
+
result[name].push(normalized);
|
|
16095
16877
|
}
|
|
16096
16878
|
}
|
|
16097
16879
|
};
|
|
@@ -16125,9 +16907,10 @@ import { parseTsconfig } from "get-tsconfig";
|
|
|
16125
16907
|
import { dirname as dirname10, join as join22, resolve as resolve7 } from "pathe";
|
|
16126
16908
|
var CONFIG_DIR_TEMPLATE = "${configDir}";
|
|
16127
16909
|
var substituteConfigDir = (value, configDir) => value.startsWith(CONFIG_DIR_TEMPLATE) ? join22(configDir, value.slice(CONFIG_DIR_TEMPLATE.length)) : value;
|
|
16910
|
+
var isPathTarget = (target) => typeof target === "string";
|
|
16128
16911
|
var toAlias = (key, value, baseDir, configDir) => {
|
|
16129
16912
|
const first = Array.isArray(value) ? value[0] : value;
|
|
16130
|
-
if (
|
|
16913
|
+
if (!isPathTarget(first)) {
|
|
16131
16914
|
return null;
|
|
16132
16915
|
}
|
|
16133
16916
|
const find = key.endsWith("/*") ? key.slice(0, -2) : key;
|
|
@@ -16157,14 +16940,14 @@ var resolveTsconfigAliases = (root) => {
|
|
|
16157
16940
|
}
|
|
16158
16941
|
const configDir = dirname10(entry);
|
|
16159
16942
|
const baseDir = resolve7(configDir, substituteConfigDir(options?.baseUrl ?? ".", configDir));
|
|
16160
|
-
const
|
|
16943
|
+
const entries = [];
|
|
16161
16944
|
for (const [key, value] of Object.entries(paths)) {
|
|
16162
16945
|
const alias = toAlias(key, value, baseDir, configDir);
|
|
16163
16946
|
if (alias) {
|
|
16164
|
-
|
|
16947
|
+
entries.push([alias.find, alias.replacement]);
|
|
16165
16948
|
}
|
|
16166
16949
|
}
|
|
16167
|
-
return
|
|
16950
|
+
return Object.fromEntries(entries);
|
|
16168
16951
|
};
|
|
16169
16952
|
|
|
16170
16953
|
// src/og/derive.ts
|
|
@@ -16172,8 +16955,12 @@ import { existsSync as existsSync14 } from "node:fs";
|
|
|
16172
16955
|
import { isAbsolute as isAbsolute7, join as join23 } from "pathe";
|
|
16173
16956
|
var CARD_WEIGHTS = [400, 600];
|
|
16174
16957
|
var absoluteSrc = (root, src) => isAbsolute7(src) ? src : join23(root, src);
|
|
16958
|
+
var isNumericWeight = (weight) => typeof weight === "number";
|
|
16959
|
+
var isRangeWeight = (weight) => typeof weight === "string";
|
|
16960
|
+
var isFontName = (value) => typeof value === "string";
|
|
16961
|
+
var isLocalOgFont = (font) => typeof font !== "string" && ("src" in font);
|
|
16175
16962
|
var googleWeights = (weights) => {
|
|
16176
|
-
const numbers = weights.filter(
|
|
16963
|
+
const numbers = weights.filter(isNumericWeight);
|
|
16177
16964
|
const used = numbers.filter((weight) => CARD_WEIGHTS.includes(weight));
|
|
16178
16965
|
if (used.length > 0) {
|
|
16179
16966
|
return used;
|
|
@@ -16182,20 +16969,22 @@ var googleWeights = (weights) => {
|
|
|
16182
16969
|
return numbers;
|
|
16183
16970
|
}
|
|
16184
16971
|
const [first] = weights;
|
|
16185
|
-
return weights.length === 1 &&
|
|
16972
|
+
return weights.length === 1 && isRangeWeight(first) ? first : undefined;
|
|
16186
16973
|
};
|
|
16187
16974
|
var googleOgFont = (name, weights) => {
|
|
16188
16975
|
const weight = googleWeights(weights);
|
|
16189
16976
|
return weight === undefined ? { name } : { name, weight };
|
|
16190
16977
|
};
|
|
16191
|
-
var localOgFonts = (font, root) => font.variants.map((variant) =>
|
|
16192
|
-
|
|
16193
|
-
|
|
16194
|
-
|
|
16195
|
-
|
|
16196
|
-
}
|
|
16978
|
+
var localOgFonts = (font, root) => font.variants.map((variant) => {
|
|
16979
|
+
const entry = {
|
|
16980
|
+
name: font.name,
|
|
16981
|
+
src: absoluteSrc(root, variant.src)
|
|
16982
|
+
};
|
|
16983
|
+
const withWeight = isNumericWeight(variant.weight) ? { ...entry, weight: variant.weight } : entry;
|
|
16984
|
+
return variant.style === "normal" || variant.style === "italic" ? { ...withWeight, style: variant.style } : withWeight;
|
|
16985
|
+
});
|
|
16197
16986
|
var roleFonts = (value, root) => {
|
|
16198
|
-
if (
|
|
16987
|
+
if (isFontName(value)) {
|
|
16199
16988
|
if (!isFontSlug(value)) {
|
|
16200
16989
|
return null;
|
|
16201
16990
|
}
|
|
@@ -16205,14 +16994,13 @@ var roleFonts = (value, root) => {
|
|
|
16205
16994
|
if ("variants" in value) {
|
|
16206
16995
|
return localOgFonts(value, root);
|
|
16207
16996
|
}
|
|
16208
|
-
|
|
16209
|
-
if ((remote.provider ?? "google") !== "google") {
|
|
16997
|
+
if ((value.provider ?? "google") !== "google") {
|
|
16210
16998
|
return null;
|
|
16211
16999
|
}
|
|
16212
|
-
return [googleOgFont(
|
|
17000
|
+
return [googleOgFont(value.name, value.weights ?? CARD_WEIGHTS)];
|
|
16213
17001
|
};
|
|
16214
17002
|
var roleFamily = (value) => {
|
|
16215
|
-
if (
|
|
17003
|
+
if (isFontName(value)) {
|
|
16216
17004
|
return isFontSlug(value) ? GOOGLE_FONTS[value].family : null;
|
|
16217
17005
|
}
|
|
16218
17006
|
return value.name;
|
|
@@ -16242,12 +17030,13 @@ var deriveOgFonts = (fonts, root) => {
|
|
|
16242
17030
|
}
|
|
16243
17031
|
}
|
|
16244
17032
|
}
|
|
16245
|
-
|
|
16246
|
-
|
|
16247
|
-
|
|
16248
|
-
}
|
|
17033
|
+
const result = { fonts: derived };
|
|
17034
|
+
if (families.title || families.body) {
|
|
17035
|
+
result.families = families;
|
|
17036
|
+
}
|
|
17037
|
+
return result;
|
|
16249
17038
|
};
|
|
16250
|
-
var resolveOgFontSources = (fonts, root) => fonts.map((font) =>
|
|
17039
|
+
var resolveOgFontSources = (fonts, root) => fonts.map((font) => isLocalOgFont(font) ? { ...font, src: absoluteSrc(root, font.src) } : font);
|
|
16251
17040
|
var resolveOgFonts = (options, root) => {
|
|
16252
17041
|
if (options.ogFonts) {
|
|
16253
17042
|
return { fonts: resolveOgFontSources(options.ogFonts, root) };
|
|
@@ -16257,12 +17046,12 @@ var resolveOgFonts = (options, root) => {
|
|
|
16257
17046
|
var missingFontFiles = (options, root) => {
|
|
16258
17047
|
const sources = [];
|
|
16259
17048
|
for (const value of Object.values(options.themeFonts ?? {})) {
|
|
16260
|
-
if (
|
|
17049
|
+
if (!isFontName(value) && "variants" in value) {
|
|
16261
17050
|
sources.push(...value.variants.map((variant) => absoluteSrc(root, variant.src)));
|
|
16262
17051
|
}
|
|
16263
17052
|
}
|
|
16264
17053
|
for (const font of options.ogFonts) {
|
|
16265
|
-
if (
|
|
17054
|
+
if (isLocalOgFont(font)) {
|
|
16266
17055
|
sources.push(absoluteSrc(root, font.src));
|
|
16267
17056
|
}
|
|
16268
17057
|
}
|
|
@@ -16299,9 +17088,10 @@ var ACCENTS = {
|
|
|
16299
17088
|
red: "oklch(0.58 0.22 25)",
|
|
16300
17089
|
teal: "oklch(0.6 0.12 195)"
|
|
16301
17090
|
};
|
|
17091
|
+
var isAccentPreset = (value) => Object.hasOwn(ACCENTS, value);
|
|
16302
17092
|
var CSS_COLOR = /^[\w\s#%.,()/+-]+$/u;
|
|
16303
17093
|
var safeColor = (value, fallback) => CSS_COLOR.test(value.trim()) ? value.trim() : fallback;
|
|
16304
|
-
var presetOrColor = (value) =>
|
|
17094
|
+
var presetOrColor = (value) => isAccentPreset(value) ? ACCENTS[value] : safeColor(value, FALLBACK_ACCENT);
|
|
16305
17095
|
var safeColorOrNull = (value) => value && CSS_COLOR.test(value.trim()) ? value.trim() : null;
|
|
16306
17096
|
var RADII = {
|
|
16307
17097
|
lg: "0.75rem",
|
|
@@ -16457,11 +17247,16 @@ var buildReferenceFiles = async (options) => {
|
|
|
16457
17247
|
};
|
|
16458
17248
|
|
|
16459
17249
|
// src/search/popular.ts
|
|
16460
|
-
var resolveSearchPopular = (popular, basePath) => popular.map(({ href, icon, label }) =>
|
|
16461
|
-
|
|
16462
|
-
|
|
16463
|
-
|
|
16464
|
-
}
|
|
17250
|
+
var resolveSearchPopular = (popular, basePath) => popular.map(({ href, icon, label }) => {
|
|
17251
|
+
const page = {
|
|
17252
|
+
label,
|
|
17253
|
+
route: withBasePath(basePath, href)
|
|
17254
|
+
};
|
|
17255
|
+
if (icon) {
|
|
17256
|
+
page.icon = icon;
|
|
17257
|
+
}
|
|
17258
|
+
return page;
|
|
17259
|
+
});
|
|
16465
17260
|
|
|
16466
17261
|
// src/theme/entry.ts
|
|
16467
17262
|
var DARK_VARIANT = `/* Dark mode is driven by data-theme on the <html> element. */
|
|
@@ -16607,7 +17402,11 @@ ${THEME_MAPPING}
|
|
|
16607
17402
|
scroll-padding-top: 4.5rem;
|
|
16608
17403
|
text-rendering: optimizeLegibility;
|
|
16609
17404
|
}
|
|
16610
|
-
/* Headings use the display font (defaults to the body font when unset).
|
|
17405
|
+
/* Headings use the display font (defaults to the body font when unset).
|
|
17406
|
+
The tightened tracking is part of the theme, not the font: display-tuned
|
|
17407
|
+
families bake it into their metrics, but a text family promoted to
|
|
17408
|
+
headings (including the Inter default) reads loose without it. -0.05em
|
|
17409
|
+
was matched visually against Inter Tight, the previous display default. */
|
|
16611
17410
|
h1,
|
|
16612
17411
|
h2,
|
|
16613
17412
|
h3,
|
|
@@ -16615,6 +17414,7 @@ ${THEME_MAPPING}
|
|
|
16615
17414
|
h5,
|
|
16616
17415
|
h6 {
|
|
16617
17416
|
font-family: var(--font-display);
|
|
17417
|
+
letter-spacing: -0.05em;
|
|
16618
17418
|
}
|
|
16619
17419
|
:focus-visible {
|
|
16620
17420
|
outline: 2px solid var(--blume-accent);
|
|
@@ -16635,6 +17435,22 @@ ${THEME_MAPPING}
|
|
|
16635
17435
|
}
|
|
16636
17436
|
}
|
|
16637
17437
|
|
|
17438
|
+
/* Same-origin navigations are full document loads (no client router); opting
|
|
17439
|
+
into cross-document view transitions has the browser crossfade between the
|
|
17440
|
+
old and new page instead of hard-swapping, in browsers that support it.
|
|
17441
|
+
Pairs with the prefetch option in the generated Astro config. */
|
|
17442
|
+
@view-transition {
|
|
17443
|
+
navigation: auto;
|
|
17444
|
+
}
|
|
17445
|
+
|
|
17446
|
+
@media (prefers-reduced-motion: reduce) {
|
|
17447
|
+
::view-transition-group(*),
|
|
17448
|
+
::view-transition-old(*),
|
|
17449
|
+
::view-transition-new(*) {
|
|
17450
|
+
animation: none !important;
|
|
17451
|
+
}
|
|
17452
|
+
}
|
|
17453
|
+
|
|
16638
17454
|
/* Code reads left-to-right regardless of page direction; only the surrounding
|
|
16639
17455
|
chrome mirrors for RTL. Inline code is isolated so LTR identifiers don't
|
|
16640
17456
|
disturb the bidi flow of right-to-left prose. */
|
|
@@ -16670,9 +17486,10 @@ ${THEME_MAPPING}
|
|
|
16670
17486
|
line-height: 1.7;
|
|
16671
17487
|
}
|
|
16672
17488
|
|
|
17489
|
+
/* No letter-spacing here: prose headings inherit the base h1-h6 rule's
|
|
17490
|
+
display tracking, same as headings outside the prose column. */
|
|
16673
17491
|
.prose :where(h1, h2, h3, h4) {
|
|
16674
17492
|
font-weight: 500;
|
|
16675
|
-
letter-spacing: 0;
|
|
16676
17493
|
}
|
|
16677
17494
|
|
|
16678
17495
|
/* A heading can carry one long unbreakable token — an OpenAPI operation's title
|
|
@@ -17423,12 +18240,13 @@ var VALID_MODES = new Set([
|
|
|
17423
18240
|
"only",
|
|
17424
18241
|
"visible"
|
|
17425
18242
|
]);
|
|
17426
|
-
var
|
|
17427
|
-
|
|
17428
|
-
|
|
17429
|
-
|
|
17430
|
-
|
|
17431
|
-
|
|
18243
|
+
var isClientMode = (mode) => VALID_MODES.has(mode);
|
|
18244
|
+
var FRAMEWORK_BY_EXT2 = new Map([
|
|
18245
|
+
["jsx", "react"],
|
|
18246
|
+
["svelte", "svelte"],
|
|
18247
|
+
["tsx", "react"],
|
|
18248
|
+
["vue", "vue"]
|
|
18249
|
+
]);
|
|
17432
18250
|
var ISLAND_FILE = /\.(?<ext>jsx|svelte|tsx|vue)$/u;
|
|
17433
18251
|
var CLIENT_EXPORT = /export\s+const\s+client\s*(?::[^=]+)?=\s*["'](?<mode>\w+)["']/u;
|
|
17434
18252
|
var readClientMode = (source, file, warnings) => {
|
|
@@ -17436,7 +18254,7 @@ var readClientMode = (source, file, warnings) => {
|
|
|
17436
18254
|
if (!mode) {
|
|
17437
18255
|
return DEFAULT_CLIENT;
|
|
17438
18256
|
}
|
|
17439
|
-
if (!
|
|
18257
|
+
if (!isClientMode(mode)) {
|
|
17440
18258
|
warnings.push(`Island "${file}" declares an unknown client mode "${mode}"; defaulting to "${DEFAULT_CLIENT}". Use "load", "idle", "visible", or "only".`);
|
|
17441
18259
|
return DEFAULT_CLIENT;
|
|
17442
18260
|
}
|
|
@@ -17459,7 +18277,7 @@ var discoverIslands = async (root) => {
|
|
|
17459
18277
|
const collectIsland = (file, source) => {
|
|
17460
18278
|
const base = basename2(file);
|
|
17461
18279
|
const ext = base.match(ISLAND_FILE)?.groups?.ext;
|
|
17462
|
-
const framework = ext ? FRAMEWORK_BY_EXT2
|
|
18280
|
+
const framework = ext ? FRAMEWORK_BY_EXT2.get(ext) : undefined;
|
|
17463
18281
|
if (!framework) {
|
|
17464
18282
|
return;
|
|
17465
18283
|
}
|
|
@@ -17691,18 +18509,18 @@ var ensureDepsLink = async (outDir, pkgDir = packageRoot()) => {
|
|
|
17691
18509
|
}
|
|
17692
18510
|
return astroConflictWarning(blumeAstro, outDirHit?.pkg ?? null);
|
|
17693
18511
|
};
|
|
17694
|
-
var ISLAND_FRAMEWORK_DEPS =
|
|
17695
|
-
svelte
|
|
17696
|
-
vue
|
|
17697
|
-
|
|
17698
|
-
var DEPLOYMENT_ADAPTER_DEPS =
|
|
17699
|
-
cloudflare
|
|
17700
|
-
netlify
|
|
17701
|
-
|
|
18512
|
+
var ISLAND_FRAMEWORK_DEPS = new Map([
|
|
18513
|
+
["svelte", "@astrojs/svelte"],
|
|
18514
|
+
["vue", "@astrojs/vue"]
|
|
18515
|
+
]);
|
|
18516
|
+
var DEPLOYMENT_ADAPTER_DEPS = new Map([
|
|
18517
|
+
["cloudflare", "@astrojs/cloudflare"],
|
|
18518
|
+
["netlify", "@astrojs/netlify"]
|
|
18519
|
+
]);
|
|
17702
18520
|
var islandFrameworkWarnings = (frameworks, root) => {
|
|
17703
18521
|
const warnings = [];
|
|
17704
18522
|
for (const framework of frameworks) {
|
|
17705
|
-
const dep = ISLAND_FRAMEWORK_DEPS
|
|
18523
|
+
const dep = ISLAND_FRAMEWORK_DEPS.get(framework);
|
|
17706
18524
|
if (dep && !canResolveFrom(root, dep)) {
|
|
17707
18525
|
warnings.push(`Islands use ${framework}, which needs "${dep}". Install it (e.g. \`npm install ${dep} ${framework}\`).`);
|
|
17708
18526
|
}
|
|
@@ -17710,7 +18528,7 @@ var islandFrameworkWarnings = (frameworks, root) => {
|
|
|
17710
18528
|
return warnings;
|
|
17711
18529
|
};
|
|
17712
18530
|
var deploymentAdapterWarnings = (deployment, root) => {
|
|
17713
|
-
const dep = deployment.output === "server" && deployment.adapter ? DEPLOYMENT_ADAPTER_DEPS
|
|
18531
|
+
const dep = deployment.output === "server" && deployment.adapter ? DEPLOYMENT_ADAPTER_DEPS.get(deployment.adapter) : undefined;
|
|
17714
18532
|
if (dep && !(canResolveFrom(root, dep) || canResolveFrom(packageRoot(), dep))) {
|
|
17715
18533
|
return [
|
|
17716
18534
|
`Deployment adapter "${deployment.adapter}" needs "${dep}", which isn't installed. Run \`npm install ${dep}\` (or your package manager's equivalent).`
|
|
@@ -17862,14 +18680,15 @@ var readLogoSvg = (project, source) => {
|
|
|
17862
18680
|
].find((path) => existsSync16(path));
|
|
17863
18681
|
return file ? readFileSync8(file, "utf-8") : undefined;
|
|
17864
18682
|
};
|
|
18683
|
+
var isStringShorthand = (value) => typeof value === "string";
|
|
17865
18684
|
var resolveLogo = (project) => {
|
|
17866
18685
|
const { logo } = project.config;
|
|
17867
18686
|
if (!logo) {
|
|
17868
18687
|
return null;
|
|
17869
18688
|
}
|
|
17870
|
-
const config =
|
|
18689
|
+
const config = isStringShorthand(logo) ? { image: logo } : logo;
|
|
17871
18690
|
const { href, image: source, text } = config;
|
|
17872
|
-
const image =
|
|
18691
|
+
const image = isStringShorthand(source) ? { light: source } : source;
|
|
17873
18692
|
const light = image?.light ?? image?.dark;
|
|
17874
18693
|
const dark = image?.dark ?? image?.light;
|
|
17875
18694
|
const alt = image?.alt ?? "";
|
|
@@ -17892,16 +18711,16 @@ var FAVICON_CANDIDATES = [
|
|
|
17892
18711
|
"favicon.ico",
|
|
17893
18712
|
"icon.ico"
|
|
17894
18713
|
];
|
|
17895
|
-
var FAVICON_TYPES =
|
|
17896
|
-
ico
|
|
17897
|
-
jpeg
|
|
17898
|
-
jpg
|
|
17899
|
-
png
|
|
17900
|
-
svg
|
|
17901
|
-
|
|
18714
|
+
var FAVICON_TYPES = new Map([
|
|
18715
|
+
["ico", "image/x-icon"],
|
|
18716
|
+
["jpeg", "image/jpeg"],
|
|
18717
|
+
["jpg", "image/jpeg"],
|
|
18718
|
+
["png", "image/png"],
|
|
18719
|
+
["svg", "image/svg+xml"]
|
|
18720
|
+
]);
|
|
17902
18721
|
var faviconType = (name) => {
|
|
17903
18722
|
const ext = name.split(".").pop()?.toLowerCase();
|
|
17904
|
-
return ext ? FAVICON_TYPES
|
|
18723
|
+
return ext ? FAVICON_TYPES.get(ext) : undefined;
|
|
17905
18724
|
};
|
|
17906
18725
|
var inlineDataUri = (file, type) => `data:${type};base64,${readFileSync8(file).toString("base64")}`;
|
|
17907
18726
|
var defaultFavicon = () => ({
|
|
@@ -17937,7 +18756,7 @@ var resolveBanner = (config) => {
|
|
|
17937
18756
|
if (!banner) {
|
|
17938
18757
|
return null;
|
|
17939
18758
|
}
|
|
17940
|
-
if (
|
|
18759
|
+
if (isStringShorthand(banner)) {
|
|
17941
18760
|
return { content: banner, dismissible: false, key: banner };
|
|
17942
18761
|
}
|
|
17943
18762
|
return {
|
|
@@ -18068,6 +18887,7 @@ var buildRuntimeData = (project) => {
|
|
|
18068
18887
|
theme: config.theme,
|
|
18069
18888
|
title: config.title,
|
|
18070
18889
|
toc: config.toc,
|
|
18890
|
+
versions: config.versions ?? null,
|
|
18071
18891
|
webmcp: {
|
|
18072
18892
|
enabled: config.ai.webmcp,
|
|
18073
18893
|
llms: config.ai.llmsTxt.enabled
|
|
@@ -18078,9 +18898,16 @@ var buildRuntimeData = (project) => {
|
|
|
18078
18898
|
href: feed.path,
|
|
18079
18899
|
title: feed.title
|
|
18080
18900
|
})),
|
|
18081
|
-
fontCssVars:
|
|
18901
|
+
fontCssVars: configuredFonts(config.theme.fonts),
|
|
18082
18902
|
navigation: withRepoUrl(graph.navigation),
|
|
18083
18903
|
navigationByLocale,
|
|
18904
|
+
navigationByVersion: Object.fromEntries(Object.entries(graph.navigationByVersion).map(([id2, byLocale]) => [
|
|
18905
|
+
id2,
|
|
18906
|
+
Object.fromEntries(Object.entries(byLocale).map(([code, nav]) => [
|
|
18907
|
+
code,
|
|
18908
|
+
withRepoUrl(nav)
|
|
18909
|
+
]))
|
|
18910
|
+
])),
|
|
18084
18911
|
routes: manifest.routes.map((route) => ({
|
|
18085
18912
|
alternates: route.alternates,
|
|
18086
18913
|
collection: route.collection,
|
|
@@ -18094,7 +18921,9 @@ var buildRuntimeData = (project) => {
|
|
|
18094
18921
|
lastModified: route.lastModified ?? null,
|
|
18095
18922
|
locale: route.locale,
|
|
18096
18923
|
path: route.path,
|
|
18097
|
-
title: route.title
|
|
18924
|
+
title: route.title,
|
|
18925
|
+
version: route.version,
|
|
18926
|
+
versionAlternates: route.versionAlternates
|
|
18098
18927
|
})),
|
|
18099
18928
|
ui: defaultUi,
|
|
18100
18929
|
uiByLocale
|
|
@@ -18263,6 +19092,7 @@ var generateRuntime = async (project) => {
|
|
|
18263
19092
|
const needsSvelte = frameworks.has("svelte");
|
|
18264
19093
|
const reactCompilerPath = resolveReactCompiler(config, needsReact);
|
|
18265
19094
|
const ogRoutes = customOgRoutes(pages, config.title, config.seo.og.titles);
|
|
19095
|
+
const changelogIndex = hasGeneratedChangelog(project, pages);
|
|
18266
19096
|
const mcp = planMcp(project, srcDir, pages);
|
|
18267
19097
|
pages.push(...mcp.discoveryPages);
|
|
18268
19098
|
const hasStaged = staged.size > 0;
|
|
@@ -18332,9 +19162,9 @@ var generateRuntime = async (project) => {
|
|
|
18332
19162
|
writeMcpFiles(project, mcp, write)
|
|
18333
19163
|
]);
|
|
18334
19164
|
if (config.seo.og.enabled) {
|
|
18335
|
-
await write(join28(srcDir, "pages", "og", "[...slug].png.ts"), ogEndpointTemplate(ogRoutes, projectOgFonts(project)));
|
|
19165
|
+
await write(join28(srcDir, "pages", "og", "[...slug].png.ts"), ogEndpointTemplate(ogRoutes, projectOgFonts(project), changelogIndex));
|
|
18336
19166
|
}
|
|
18337
|
-
if (
|
|
19167
|
+
if (changelogIndex) {
|
|
18338
19168
|
await write(join28(srcDir, "pages", "changelog.astro"), changelogIndexTemplate({
|
|
18339
19169
|
exportEpub,
|
|
18340
19170
|
exportPdf,
|
|
@@ -18396,7 +19226,7 @@ var generateRuntime = async (project) => {
|
|
|
18396
19226
|
...pages.map((page) => page.pattern),
|
|
18397
19227
|
...referenceRoutes(config)
|
|
18398
19228
|
]);
|
|
18399
|
-
if (
|
|
19229
|
+
if (changelogIndex) {
|
|
18400
19230
|
navTargetRoutes.add("/changelog");
|
|
18401
19231
|
}
|
|
18402
19232
|
warnings.push(...[
|
|
@@ -18530,6 +19360,7 @@ var prepareProject = async (options) => {
|
|
|
18530
19360
|
|
|
18531
19361
|
// src/cli/commands/build.ts
|
|
18532
19362
|
var ADAPTERS = ["vercel", "node", "netlify", "cloudflare"];
|
|
19363
|
+
var isAdapter = (value) => ADAPTERS.some((adapter) => adapter === value);
|
|
18533
19364
|
var BUDGET_JS = "budget-js";
|
|
18534
19365
|
var BUDGET_CSS = "budget-css";
|
|
18535
19366
|
var validateBudgetFlags = (args) => {
|
|
@@ -18626,10 +19457,13 @@ var emitVercelNegotiation = async (project, routePaths, root) => {
|
|
|
18626
19457
|
if (!existsSync18(configPath)) {
|
|
18627
19458
|
return;
|
|
18628
19459
|
}
|
|
18629
|
-
const overrides = {
|
|
18630
|
-
|
|
18631
|
-
|
|
18632
|
-
}
|
|
19460
|
+
const overrides = {};
|
|
19461
|
+
if (hasApiCatalog(config2)) {
|
|
19462
|
+
overrides[API_CATALOG_PATH.slice(1)] = API_CATALOG_TYPE;
|
|
19463
|
+
}
|
|
19464
|
+
if (config2.ai.webBotAuth.keys.length > 0) {
|
|
19465
|
+
overrides[SIGNATURES_DIRECTORY_PATH.slice(1)] = SIGNATURES_DIRECTORY_TYPE;
|
|
19466
|
+
}
|
|
18633
19467
|
const rawMarkdown = await buildRawMarkdown(project);
|
|
18634
19468
|
const home = rawMarkdown["/"];
|
|
18635
19469
|
const injected = injectNegotiationRoutes(await readFile17(configPath, "utf-8"), routePaths, buildHomeLinkHeader(config2, routePaths), overrides, home ? markdownTokenCount(agentMarkdown(home)) : undefined);
|
|
@@ -18883,7 +19717,7 @@ var buildCommand = defineCommand3({
|
|
|
18883
19717
|
logger.error(`Invalid --output "${args.output}" (use static | server).`);
|
|
18884
19718
|
process.exit(1);
|
|
18885
19719
|
}
|
|
18886
|
-
if (args.adapter && !
|
|
19720
|
+
if (args.adapter && !isAdapter(args.adapter)) {
|
|
18887
19721
|
logger.error(`Invalid --adapter "${args.adapter}" (use ${ADAPTERS.join(" | ")}).`);
|
|
18888
19722
|
process.exit(1);
|
|
18889
19723
|
}
|
|
@@ -19295,7 +20129,7 @@ var askFiles = async (project, srcDir, genDir) => {
|
|
|
19295
20129
|
const grounded = ask.provider !== "inkeep";
|
|
19296
20130
|
const files = [
|
|
19297
20131
|
{
|
|
19298
|
-
content: askEndpointTemplate(resolveAskBackend(ask), grounded),
|
|
20132
|
+
content: askEndpointTemplate(resolveAskBackend(ask), grounded, ask.instructions),
|
|
19299
20133
|
path: join33(srcDir, "pages", "api", "ask.ts")
|
|
19300
20134
|
}
|
|
19301
20135
|
];
|
|
@@ -19794,14 +20628,15 @@ var commandsFor = (pm) => ({
|
|
|
19794
20628
|
exec: { bun: "bunx", npm: "npx", pnpm: "pnpm exec", yarn: "yarn" }[pm],
|
|
19795
20629
|
install: `${pm} install`
|
|
19796
20630
|
});
|
|
20631
|
+
var isPackageManager = (value) => PACKAGE_MANAGERS.some((pm) => pm === value);
|
|
19797
20632
|
var detectPackageManager = (userAgent) => {
|
|
19798
20633
|
const name = userAgent?.split("/")[0];
|
|
19799
|
-
return name !== undefined &&
|
|
20634
|
+
return name !== undefined && isPackageManager(name) ? name : "npm";
|
|
19800
20635
|
};
|
|
19801
20636
|
var detectProjectPackageManager = async (root) => {
|
|
19802
20637
|
const detected = await detect({ cwd: root });
|
|
19803
20638
|
const name = detected?.name;
|
|
19804
|
-
return name !== undefined &&
|
|
20639
|
+
return name !== undefined && isPackageManager(name) ? name : detectPackageManager(process.env.npm_config_user_agent);
|
|
19805
20640
|
};
|
|
19806
20641
|
var validateContentDir = (root, dir) => isAbsolute9(dir) || relative16(root, join35(root, dir)).startsWith("..") ? "Must be a relative path inside the project." : undefined;
|
|
19807
20642
|
var titleize = (raw) => {
|
|
@@ -19865,10 +20700,16 @@ export default defineConfig({
|
|
|
19865
20700
|
description: "Documentation powered by Blume.",${STARTERS[answers.template].configExtra}${contentBlockFor(answers)}
|
|
19866
20701
|
});
|
|
19867
20702
|
`;
|
|
19868
|
-
var extraDepsFor = (sources) =>
|
|
19869
|
-
|
|
19870
|
-
|
|
19871
|
-
|
|
20703
|
+
var extraDepsFor = (sources) => {
|
|
20704
|
+
const deps = {};
|
|
20705
|
+
if (sources.includes("notion")) {
|
|
20706
|
+
deps["@notionhq/client"] = "^2.2.15";
|
|
20707
|
+
}
|
|
20708
|
+
if (sources.includes("sanity")) {
|
|
20709
|
+
deps["@sanity/client"] = "^7.25.0";
|
|
20710
|
+
}
|
|
20711
|
+
return deps;
|
|
20712
|
+
};
|
|
19872
20713
|
var buildPlan = (root, answers) => {
|
|
19873
20714
|
const files = [
|
|
19874
20715
|
{
|
|
@@ -20166,7 +21007,7 @@ import { join as join38 } from "pathe";
|
|
|
20166
21007
|
import { readFile as readFile20, writeFile as writeFile12 } from "node:fs/promises";
|
|
20167
21008
|
import spawn2 from "cross-spawn";
|
|
20168
21009
|
import { join as join37 } from "pathe";
|
|
20169
|
-
import { z as
|
|
21010
|
+
import { z as z4 } from "zod";
|
|
20170
21011
|
var KILL_GRACE_MS = 5000;
|
|
20171
21012
|
var MCP_TOOL_NAMES = [
|
|
20172
21013
|
"search_docs",
|
|
@@ -20292,10 +21133,10 @@ var codexArgs = (context) => {
|
|
|
20292
21133
|
return [...base, "-"];
|
|
20293
21134
|
};
|
|
20294
21135
|
var agentArgs = (kind, context) => kind === "claude" ? claudeArgs(context) : codexArgs(context);
|
|
20295
|
-
var claudeResultSchema =
|
|
20296
|
-
is_error:
|
|
20297
|
-
result:
|
|
20298
|
-
total_cost_usd:
|
|
21136
|
+
var claudeResultSchema = z4.object({
|
|
21137
|
+
is_error: z4.boolean().default(false),
|
|
21138
|
+
result: z4.string().default(""),
|
|
21139
|
+
total_cost_usd: z4.number().optional()
|
|
20299
21140
|
});
|
|
20300
21141
|
var tail = (value, max = 300) => {
|
|
20301
21142
|
const trimmed = value.trim();
|
|
@@ -20349,11 +21190,11 @@ var readAgentOutput = async (kind, result, lastMessagePath) => {
|
|
|
20349
21190
|
}
|
|
20350
21191
|
return { isError: false, text };
|
|
20351
21192
|
};
|
|
20352
|
-
var verdictSchema =
|
|
20353
|
-
missing:
|
|
20354
|
-
notes:
|
|
20355
|
-
pass:
|
|
20356
|
-
score:
|
|
21193
|
+
var verdictSchema = z4.object({
|
|
21194
|
+
missing: z4.array(z4.string()).default([]),
|
|
21195
|
+
notes: z4.string().default(""),
|
|
21196
|
+
pass: z4.boolean(),
|
|
21197
|
+
score: z4.number().min(0).max(1).optional()
|
|
20357
21198
|
});
|
|
20358
21199
|
var parseVerdict = (text) => {
|
|
20359
21200
|
const start = text.indexOf("{");
|
|
@@ -20374,26 +21215,26 @@ var parseVerdict = (text) => {
|
|
|
20374
21215
|
// src/eval/schema.ts
|
|
20375
21216
|
import { readFile as readFile21 } from "node:fs/promises";
|
|
20376
21217
|
import { load as load2 } from "js-yaml";
|
|
20377
|
-
import { z as
|
|
21218
|
+
import { z as z5 } from "zod";
|
|
20378
21219
|
var ID_PATTERN = /^[a-z0-9][a-z0-9-]*$/u;
|
|
20379
|
-
var questionSchema =
|
|
20380
|
-
expected:
|
|
20381
|
-
id:
|
|
20382
|
-
question:
|
|
20383
|
-
routes:
|
|
20384
|
-
severity:
|
|
20385
|
-
skip:
|
|
21220
|
+
var questionSchema = z5.strictObject({
|
|
21221
|
+
expected: z5.array(z5.string().min(1)).min(1, "expected must list at least one fact"),
|
|
21222
|
+
id: z5.string().regex(ID_PATTERN, "id must be a kebab-case slug (a-z, 0-9, dashes)"),
|
|
21223
|
+
question: z5.string().min(1),
|
|
21224
|
+
routes: z5.union([z5.string(), z5.array(z5.string())]).default([]).transform((value) => Array.isArray(value) ? value : [value]),
|
|
21225
|
+
severity: z5.enum(["error", "warning"]).default("error"),
|
|
21226
|
+
skip: z5.boolean().default(false)
|
|
20386
21227
|
});
|
|
20387
|
-
var fullSchema =
|
|
20388
|
-
questions:
|
|
20389
|
-
version:
|
|
21228
|
+
var fullSchema = z5.strictObject({
|
|
21229
|
+
questions: z5.array(questionSchema).min(1),
|
|
21230
|
+
version: z5.literal(1).default(1)
|
|
20390
21231
|
});
|
|
20391
21232
|
var evalsFileSchema = fullSchema.superRefine((value, context) => {
|
|
20392
21233
|
const seen = new Set;
|
|
20393
21234
|
for (const question of value.questions) {
|
|
20394
21235
|
if (seen.has(question.id)) {
|
|
20395
21236
|
context.addIssue({
|
|
20396
|
-
code:
|
|
21237
|
+
code: z5.ZodIssueCode.custom,
|
|
20397
21238
|
message: `duplicate question id "${question.id}"`,
|
|
20398
21239
|
path: ["questions"]
|
|
20399
21240
|
});
|
|
@@ -20986,13 +21827,13 @@ var initCommand = defineCommand9({
|
|
|
20986
21827
|
},
|
|
20987
21828
|
async run({ args }) {
|
|
20988
21829
|
const cwd = process.cwd();
|
|
20989
|
-
const template = args.template;
|
|
20990
|
-
if (template !== undefined &&
|
|
21830
|
+
const template = TEMPLATES.find((candidate) => candidate === args.template);
|
|
21831
|
+
if (args.template !== undefined && template === undefined) {
|
|
20991
21832
|
logger.error(`Unknown template "${args.template}" (use ${TEMPLATES.join(" | ")}).`);
|
|
20992
21833
|
process.exit(1);
|
|
20993
21834
|
}
|
|
20994
|
-
const pm = args["package-manager"];
|
|
20995
|
-
if (
|
|
21835
|
+
const pm = PACKAGE_MANAGERS.find((candidate) => candidate === args["package-manager"]);
|
|
21836
|
+
if (args["package-manager"] !== undefined && pm === undefined) {
|
|
20996
21837
|
logger.error(`Unknown package manager "${args["package-manager"]}" (use ${PACKAGE_MANAGERS.join(" | ")}).`);
|
|
20997
21838
|
process.exit(1);
|
|
20998
21839
|
}
|
|
@@ -21065,7 +21906,7 @@ import {
|
|
|
21065
21906
|
CallToolRequestSchema,
|
|
21066
21907
|
ListToolsRequestSchema
|
|
21067
21908
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
21068
|
-
import { z as
|
|
21909
|
+
import { z as z6 } from "zod";
|
|
21069
21910
|
|
|
21070
21911
|
// src/search/orama-index.ts
|
|
21071
21912
|
import { create, insertMultiple, search } from "@orama/orama";
|
|
@@ -21076,7 +21917,8 @@ var SCHEMA = {
|
|
|
21076
21917
|
facetTerms: "enum[]",
|
|
21077
21918
|
locale: "enum",
|
|
21078
21919
|
route: "string",
|
|
21079
|
-
title: "string"
|
|
21920
|
+
title: "string",
|
|
21921
|
+
version: "enum"
|
|
21080
21922
|
};
|
|
21081
21923
|
var toFacetTerms = (facets) => Object.entries(facets).map(([key, value]) => `${key}:${value}`);
|
|
21082
21924
|
var BOOST = { description: 2, title: 3 };
|
|
@@ -21098,12 +21940,13 @@ var addBigrams = (run, tokens) => {
|
|
|
21098
21940
|
previous = character;
|
|
21099
21941
|
}
|
|
21100
21942
|
};
|
|
21943
|
+
var hasSegmenter = (segmenter) => typeof segmenter === "function";
|
|
21101
21944
|
var segmentingTokenizer = (locale) => {
|
|
21102
21945
|
const language = locale?.toLowerCase().split(/[-_]/u)[0] ?? "";
|
|
21103
21946
|
if (!SEGMENTED_LANGUAGES.has(language)) {
|
|
21104
21947
|
return;
|
|
21105
21948
|
}
|
|
21106
|
-
if (
|
|
21949
|
+
if (!hasSegmenter(Intl.Segmenter)) {
|
|
21107
21950
|
return;
|
|
21108
21951
|
}
|
|
21109
21952
|
const segmenter = new Intl.Segmenter(language, { granularity: "word" });
|
|
@@ -21152,28 +21995,33 @@ var segmentingTokenizer = (locale) => {
|
|
|
21152
21995
|
};
|
|
21153
21996
|
var buildOramaIndex = async (documents, locale) => {
|
|
21154
21997
|
const tokenizer = segmentingTokenizer(locale);
|
|
21155
|
-
const db = create({
|
|
21156
|
-
schema: SCHEMA,
|
|
21157
|
-
...tokenizer ? { components: { tokenizer } } : {}
|
|
21158
|
-
});
|
|
21998
|
+
const db = tokenizer ? create({ components: { tokenizer }, schema: SCHEMA }) : create({ schema: SCHEMA });
|
|
21159
21999
|
await insertMultiple(db, documents.map((doc) => doc.facets ? { ...doc, facetTerms: toFacetTerms(doc.facets) } : doc));
|
|
21160
22000
|
return db;
|
|
21161
22001
|
};
|
|
21162
22002
|
var ALL_TOKENS = 0;
|
|
21163
22003
|
var queryOramaIndex = async (db, term, limit, filters) => {
|
|
21164
22004
|
const facetTerms = filters?.facets ? toFacetTerms(filters.facets) : [];
|
|
21165
|
-
const where = {
|
|
21166
|
-
|
|
21167
|
-
|
|
21168
|
-
|
|
21169
|
-
|
|
21170
|
-
|
|
22005
|
+
const where = {};
|
|
22006
|
+
if (filters?.locale) {
|
|
22007
|
+
where.locale = { eq: filters.locale };
|
|
22008
|
+
}
|
|
22009
|
+
if (filters?.version !== undefined) {
|
|
22010
|
+
where.version = { eq: filters.version };
|
|
22011
|
+
}
|
|
22012
|
+
if (filters?.contentTypes && filters.contentTypes.length > 0) {
|
|
22013
|
+
where.contentType = { in: filters.contentTypes };
|
|
22014
|
+
}
|
|
22015
|
+
if (facetTerms.length > 0) {
|
|
22016
|
+
where.facetTerms = { containsAll: facetTerms };
|
|
22017
|
+
}
|
|
22018
|
+
const unfiltered = {
|
|
21171
22019
|
boost: BOOST,
|
|
21172
22020
|
limit,
|
|
21173
22021
|
properties: ["title", "description", "content"],
|
|
21174
|
-
term
|
|
21175
|
-
...Object.keys(where).length > 0 ? { where } : {}
|
|
22022
|
+
term
|
|
21176
22023
|
};
|
|
22024
|
+
const params = Object.keys(where).length > 0 ? { ...unfiltered, where } : unfiltered;
|
|
21177
22025
|
const bigrammed = BIGRAM_LANGUAGES.has(db.tokenizer?.language ?? "");
|
|
21178
22026
|
const strict = bigrammed ? await search(db, { ...params, threshold: ALL_TOKENS }) : undefined;
|
|
21179
22027
|
const found = strict && strict.hits.length > 0 ? strict : await search(db, params);
|
|
@@ -21184,36 +22032,55 @@ var queryOramaIndex = async (db, term, limit, filters) => {
|
|
|
21184
22032
|
var DEFAULT_SEARCH_LIMIT = 8;
|
|
21185
22033
|
var MAX_SEARCH_LIMIT = 20;
|
|
21186
22034
|
var EXCERPT_LENGTH = 200;
|
|
21187
|
-
var contentTypesField =
|
|
22035
|
+
var contentTypesField = z6.preprocess((value) => {
|
|
21188
22036
|
const list2 = (Array.isArray(value) ? value : [value]).filter((entry) => typeof entry === "string");
|
|
21189
22037
|
return list2.length > 0 ? list2 : undefined;
|
|
21190
|
-
},
|
|
21191
|
-
var
|
|
21192
|
-
|
|
22038
|
+
}, z6.array(z6.string()).optional().describe('Only include pages of these content types (frontmatter `type`, e.g. `["doc", "rfc"]`). `list_pages` shows each page\'s type. Omit to include every type.'));
|
|
22039
|
+
var looseFacetObject = z6.record(z6.string(), z6.unknown());
|
|
22040
|
+
var filtersField = z6.preprocess((value) => {
|
|
22041
|
+
const candidate = looseFacetObject.safeParse(value);
|
|
22042
|
+
if (!candidate.success) {
|
|
21193
22043
|
return;
|
|
21194
22044
|
}
|
|
21195
|
-
const entries = Object.entries(
|
|
22045
|
+
const entries = Object.entries(candidate.data).filter((entry) => typeof entry[1] === "string");
|
|
21196
22046
|
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
21197
|
-
},
|
|
21198
|
-
var limitField =
|
|
21199
|
-
const num =
|
|
22047
|
+
}, z6.record(z6.string(), z6.string()).optional().describe('Only include pages matching every facet, key → required value (e.g. `{"status": "enforced"}`). Facets are metadata the site declares per content type; `list_pages` shows each page\'s facet values. Omit for no facet filtering.'));
|
|
22048
|
+
var limitField = z6.preprocess((value) => {
|
|
22049
|
+
const num = Number(value);
|
|
21200
22050
|
return Number.isFinite(num) ? Math.min(Math.max(Math.trunc(num), 1), MAX_SEARCH_LIMIT) : undefined;
|
|
21201
|
-
},
|
|
21202
|
-
var textField = (description) =>
|
|
22051
|
+
}, z6.int().min(1).max(MAX_SEARCH_LIMIT).optional().describe(`Maximum hits to return (default ${DEFAULT_SEARCH_LIMIT}).`));
|
|
22052
|
+
var textField = (description) => z6.preprocess((value) => {
|
|
22053
|
+
const parsed = z6.string().safeParse(value);
|
|
22054
|
+
return parsed.success ? parsed.data : "";
|
|
22055
|
+
}, z6.string().describe(description));
|
|
22056
|
+
var optionalTextField = (description) => z6.preprocess((value) => {
|
|
22057
|
+
const parsed = z6.string().safeParse(value);
|
|
22058
|
+
const trimmed = parsed.success ? parsed.data.trim() : "";
|
|
22059
|
+
return trimmed || undefined;
|
|
22060
|
+
}, z6.string().optional().describe(description));
|
|
22061
|
+
var localeField = optionalTextField("Only include pages in this locale (e.g. `fr`). Omit for every language.");
|
|
22062
|
+
var versionField = optionalTextField('Docs version to scope to on a versioned site: `"latest"` (the default — current docs only), `"all"` (every version), or an archived version id (e.g. `"v1.0"`). Ignored when the site is unversioned.');
|
|
21203
22063
|
var TOOL_INPUTS = {
|
|
21204
|
-
get_navigation:
|
|
21205
|
-
|
|
22064
|
+
get_navigation: z6.object({
|
|
22065
|
+
locale: optionalTextField("Locale whose navigation tree to return (defaults to the default locale)."),
|
|
22066
|
+
version: optionalTextField("Archived version id whose tree to return (defaults to the current docs).")
|
|
22067
|
+
}),
|
|
22068
|
+
get_page: z6.object({
|
|
21206
22069
|
route: textField("The page route, e.g. `/guides/install`.")
|
|
21207
22070
|
}),
|
|
21208
|
-
list_pages:
|
|
22071
|
+
list_pages: z6.object({
|
|
21209
22072
|
contentTypes: contentTypesField,
|
|
21210
|
-
filters: filtersField
|
|
22073
|
+
filters: filtersField,
|
|
22074
|
+
locale: localeField,
|
|
22075
|
+
version: versionField
|
|
21211
22076
|
}),
|
|
21212
|
-
search_docs:
|
|
22077
|
+
search_docs: z6.object({
|
|
21213
22078
|
contentTypes: contentTypesField,
|
|
21214
22079
|
filters: filtersField,
|
|
21215
22080
|
limit: limitField,
|
|
21216
|
-
|
|
22081
|
+
locale: localeField,
|
|
22082
|
+
query: textField("The search query."),
|
|
22083
|
+
version: versionField
|
|
21217
22084
|
})
|
|
21218
22085
|
};
|
|
21219
22086
|
var inputSchemaFor = (schema) => {
|
|
@@ -21221,7 +22088,7 @@ var inputSchemaFor = (schema) => {
|
|
|
21221
22088
|
$schema: _dialect,
|
|
21222
22089
|
additionalProperties: _closed,
|
|
21223
22090
|
...rest
|
|
21224
|
-
} =
|
|
22091
|
+
} = z6.toJSONSchema(schema);
|
|
21225
22092
|
return rest;
|
|
21226
22093
|
};
|
|
21227
22094
|
var TOOL_DEFINITIONS = MCP_TOOLS.map((tool) => ({
|
|
@@ -21232,6 +22099,19 @@ var TOOL_DEFINITIONS = MCP_TOOLS.map((tool) => ({
|
|
|
21232
22099
|
title: tool.title
|
|
21233
22100
|
}));
|
|
21234
22101
|
var matchesFacets = (facets, filters) => Object.entries(filters).every(([key, value]) => facets?.[key] === value);
|
|
22102
|
+
var asVersionScope = (value, data) => {
|
|
22103
|
+
if (!data.archivedVersions) {
|
|
22104
|
+
return;
|
|
22105
|
+
}
|
|
22106
|
+
if (value === "all") {
|
|
22107
|
+
return;
|
|
22108
|
+
}
|
|
22109
|
+
if (value === undefined || value === "latest" || value === "current") {
|
|
22110
|
+
return "";
|
|
22111
|
+
}
|
|
22112
|
+
return value;
|
|
22113
|
+
};
|
|
22114
|
+
var unknownVersionError = (versionId, data) => versionId && data.archivedVersions && !data.archivedVersions.includes(versionId) ? `Unknown version "${versionId}". Archived versions: ${data.archivedVersions.join(", ")}.` : null;
|
|
21235
22115
|
var normalizeRoute2 = (input, data) => {
|
|
21236
22116
|
let value = input.trim();
|
|
21237
22117
|
if (/^https?:\/\//iu.test(value)) {
|
|
@@ -21256,10 +22136,10 @@ var excerptFor = (doc) => {
|
|
|
21256
22136
|
const head = doc.content.slice(0, EXCERPT_LENGTH).trim();
|
|
21257
22137
|
return doc.content.length > EXCERPT_LENGTH ? `${head}…` : head;
|
|
21258
22138
|
};
|
|
21259
|
-
var text = (value, isError = false) =>
|
|
21260
|
-
content
|
|
21261
|
-
|
|
21262
|
-
}
|
|
22139
|
+
var text = (value, isError = false) => {
|
|
22140
|
+
const content = [{ text: value, type: "text" }];
|
|
22141
|
+
return isError ? { content, isError: true } : { content };
|
|
22142
|
+
};
|
|
21263
22143
|
var createIndexProvider = (documents, locale) => {
|
|
21264
22144
|
let dbPromise = null;
|
|
21265
22145
|
return function provideIndex() {
|
|
@@ -21268,10 +22148,8 @@ var createIndexProvider = (documents, locale) => {
|
|
|
21268
22148
|
};
|
|
21269
22149
|
};
|
|
21270
22150
|
var buildServer = (data, index) => {
|
|
21271
|
-
const
|
|
21272
|
-
|
|
21273
|
-
...data.instructions ? { instructions: data.instructions } : {}
|
|
21274
|
-
});
|
|
22151
|
+
const serverOptions = data.instructions ? { capabilities: { tools: {} }, instructions: data.instructions } : { capabilities: { tools: {} } };
|
|
22152
|
+
const server = new Server({ name: data.name, version: data.version }, serverOptions);
|
|
21275
22153
|
server.setRequestHandler(ListToolsRequestSchema, () => ({
|
|
21276
22154
|
tools: TOOL_DEFINITIONS
|
|
21277
22155
|
}));
|
|
@@ -21282,16 +22160,24 @@ var buildServer = (data, index) => {
|
|
|
21282
22160
|
const db = await index();
|
|
21283
22161
|
const hits = await queryOramaIndex(db, input.query, input.limit ?? DEFAULT_SEARCH_LIMIT, {
|
|
21284
22162
|
contentTypes: input.contentTypes,
|
|
21285
|
-
facets: input.filters
|
|
22163
|
+
facets: input.filters,
|
|
22164
|
+
locale: input.locale,
|
|
22165
|
+
version: asVersionScope(input.version, data)
|
|
22166
|
+
});
|
|
22167
|
+
const results = hits.map((doc) => {
|
|
22168
|
+
const hit = {
|
|
22169
|
+
contentType: doc.contentType,
|
|
22170
|
+
excerpt: excerptFor(doc),
|
|
22171
|
+
facets: doc.facets,
|
|
22172
|
+
route: doc.route,
|
|
22173
|
+
title: doc.title,
|
|
22174
|
+
url: urlFor(doc.route, data)
|
|
22175
|
+
};
|
|
22176
|
+
if (data.archivedVersions) {
|
|
22177
|
+
hit.version = doc.version ?? "";
|
|
22178
|
+
}
|
|
22179
|
+
return hit;
|
|
21286
22180
|
});
|
|
21287
|
-
const results = hits.map((doc) => ({
|
|
21288
|
-
contentType: doc.contentType,
|
|
21289
|
-
excerpt: excerptFor(doc),
|
|
21290
|
-
facets: doc.facets,
|
|
21291
|
-
route: doc.route,
|
|
21292
|
-
title: doc.title,
|
|
21293
|
-
url: urlFor(doc.route, data)
|
|
21294
|
-
}));
|
|
21295
22181
|
return text(JSON.stringify(results, null, 2));
|
|
21296
22182
|
}
|
|
21297
22183
|
if (name === "get_page") {
|
|
@@ -21304,20 +22190,40 @@ var buildServer = (data, index) => {
|
|
|
21304
22190
|
return text(markdown);
|
|
21305
22191
|
}
|
|
21306
22192
|
if (name === "list_pages") {
|
|
21307
|
-
const
|
|
21308
|
-
const
|
|
21309
|
-
|
|
21310
|
-
|
|
21311
|
-
|
|
21312
|
-
|
|
21313
|
-
|
|
21314
|
-
|
|
21315
|
-
|
|
21316
|
-
|
|
21317
|
-
|
|
22193
|
+
const input = TOOL_INPUTS.list_pages.parse(args);
|
|
22194
|
+
const { contentTypes, filters, locale } = input;
|
|
22195
|
+
const versionScope = asVersionScope(input.version, data);
|
|
22196
|
+
const routes = data.routes.filter((route) => (!contentTypes || contentTypes.includes(route.contentType)) && (!filters || matchesFacets(route.facets, filters)) && (!locale || route.locale === locale) && (versionScope === undefined || route.version === versionScope));
|
|
22197
|
+
return text(JSON.stringify(routes.map((route) => {
|
|
22198
|
+
const listing = {
|
|
22199
|
+
contentType: route.contentType,
|
|
22200
|
+
description: route.description,
|
|
22201
|
+
facets: route.facets,
|
|
22202
|
+
lastModified: route.lastModified,
|
|
22203
|
+
route: route.route,
|
|
22204
|
+
title: route.title,
|
|
22205
|
+
url: urlFor(route.route, data)
|
|
22206
|
+
};
|
|
22207
|
+
if (data.archivedVersions) {
|
|
22208
|
+
listing.version = route.version;
|
|
22209
|
+
}
|
|
22210
|
+
return listing;
|
|
22211
|
+
}), null, 2));
|
|
21318
22212
|
}
|
|
21319
22213
|
if (name === "get_navigation") {
|
|
21320
|
-
|
|
22214
|
+
const { locale, version: versionId } = TOOL_INPUTS.get_navigation.parse(args);
|
|
22215
|
+
const unknownVersion = unknownVersionError(versionId, data);
|
|
22216
|
+
if (unknownVersion) {
|
|
22217
|
+
return text(unknownVersion, true);
|
|
22218
|
+
}
|
|
22219
|
+
let { navigation } = data;
|
|
22220
|
+
const byLocale = versionId ? data.navigationByVersion?.[versionId] : undefined;
|
|
22221
|
+
if (byLocale) {
|
|
22222
|
+
navigation = (locale ? byLocale[locale] : undefined) ?? byLocale[data.defaultLocale ?? ""] ?? Object.values(byLocale)[0] ?? navigation;
|
|
22223
|
+
} else if (locale && data.navigationByLocale?.[locale]) {
|
|
22224
|
+
navigation = data.navigationByLocale[locale];
|
|
22225
|
+
}
|
|
22226
|
+
return text(JSON.stringify(navigation, null, 2));
|
|
21321
22227
|
}
|
|
21322
22228
|
return text(`Unknown tool: ${name}`, true);
|
|
21323
22229
|
});
|
|
@@ -21469,11 +22375,11 @@ var translateAgentArgs = (kind, lastMessagePath) => kind === "claude" ? claudeAr
|
|
|
21469
22375
|
import { createHash as createHash5 } from "node:crypto";
|
|
21470
22376
|
import { readFile as readFile23 } from "node:fs/promises";
|
|
21471
22377
|
import { join as join42 } from "pathe";
|
|
21472
|
-
import { z as
|
|
22378
|
+
import { z as z7 } from "zod";
|
|
21473
22379
|
var LEDGER_FILE = "blume.translations.json";
|
|
21474
|
-
var ledgerSchema =
|
|
21475
|
-
files:
|
|
21476
|
-
version:
|
|
22380
|
+
var ledgerSchema = z7.object({
|
|
22381
|
+
files: z7.record(z7.string(), z7.record(z7.string(), z7.string())),
|
|
22382
|
+
version: z7.literal(1)
|
|
21477
22383
|
});
|
|
21478
22384
|
var emptyLedger = () => ({
|
|
21479
22385
|
files: {},
|
|
@@ -21743,6 +22649,7 @@ import { readFile as readFile24 } from "node:fs/promises";
|
|
|
21743
22649
|
import { dirname as dirname15, join as join43, relative as relative19 } from "pathe";
|
|
21744
22650
|
import { glob as glob8 } from "tinyglobby";
|
|
21745
22651
|
var META_FILES2 = ["**/meta.ts", "**/meta.js", "**/meta.mjs"];
|
|
22652
|
+
var isFactoryModule = (value) => typeof value === "function";
|
|
21746
22653
|
var metaTargetPath = (meta, locale) => join43(meta.contentRoot, locale, meta.dir, "meta.ts");
|
|
21747
22654
|
var discoverTranslatableMeta = async (project) => {
|
|
21748
22655
|
const { i18n } = project.config;
|
|
@@ -21771,7 +22678,7 @@ var discoverTranslatableMeta = async (project) => {
|
|
|
21771
22678
|
readFile24(file, "utf-8"),
|
|
21772
22679
|
load3(file)
|
|
21773
22680
|
]);
|
|
21774
|
-
if (
|
|
22681
|
+
if (isFactoryModule(mod)) {
|
|
21775
22682
|
diagnostics.push({
|
|
21776
22683
|
code: "BLUME_TRANSLATE_META_FACTORY",
|
|
21777
22684
|
file,
|
|
@@ -21803,7 +22710,7 @@ var generateMetaModule = (meta, translatedTitle) => {
|
|
|
21803
22710
|
...meta,
|
|
21804
22711
|
title: translatedTitle
|
|
21805
22712
|
};
|
|
21806
|
-
const lines = Object.
|
|
22713
|
+
const lines = Object.entries(data).toSorted(([a], [b]) => a < b ? -1 : 1).filter(([, value]) => value !== undefined).map(([key, value]) => ` ${key}: ${JSON.stringify(value)},`);
|
|
21807
22714
|
return [
|
|
21808
22715
|
"// Generated by `blume translate` — edit the default locale's meta file",
|
|
21809
22716
|
"// and rerun the translation instead of editing this copy.",
|
|
@@ -21863,10 +22770,12 @@ var stripOuterFence = (text2) => {
|
|
|
21863
22770
|
};
|
|
21864
22771
|
var countFenceLines = (text2) => text2.split(`
|
|
21865
22772
|
`).filter((line) => FENCE_LINE.test(line)).length;
|
|
22773
|
+
var isKeyedObject = (value) => typeof value === "object" && value !== null;
|
|
22774
|
+
var isString7 = (value) => typeof value === "string";
|
|
21866
22775
|
var getPath2 = (data, path) => {
|
|
21867
22776
|
let value = data;
|
|
21868
22777
|
for (const key of path) {
|
|
21869
|
-
if (
|
|
22778
|
+
if (!isKeyedObject(value)) {
|
|
21870
22779
|
return;
|
|
21871
22780
|
}
|
|
21872
22781
|
value = value[key];
|
|
@@ -21921,7 +22830,7 @@ var validateTranslation = (sourceText, agentText) => {
|
|
|
21921
22830
|
for (const path of TRANSLATABLE_KEY_PATHS) {
|
|
21922
22831
|
const original = getPath2(source.data, path);
|
|
21923
22832
|
const translated = getPath2(parsed.data, path);
|
|
21924
|
-
if (
|
|
22833
|
+
if (isString7(original) && isString7(translated) && translated.trim() !== "") {
|
|
21925
22834
|
setPath(data, path, translated);
|
|
21926
22835
|
}
|
|
21927
22836
|
}
|
|
@@ -21941,12 +22850,12 @@ var parseMetaTitles = (agentText, expectedKeys) => {
|
|
|
21941
22850
|
parsed = undefined;
|
|
21942
22851
|
}
|
|
21943
22852
|
}
|
|
21944
|
-
const record =
|
|
22853
|
+
const record = isKeyedObject(parsed) ? parsed : {};
|
|
21945
22854
|
const titles = {};
|
|
21946
22855
|
const missing = [];
|
|
21947
22856
|
for (const key of expectedKeys) {
|
|
21948
22857
|
const value = record[key];
|
|
21949
|
-
if (
|
|
22858
|
+
if (isString7(value) && value.trim() !== "") {
|
|
21950
22859
|
titles[key] = value;
|
|
21951
22860
|
} else {
|
|
21952
22861
|
missing.push(key);
|
|
@@ -22103,7 +23012,7 @@ var translatablePages = (project, i18n) => {
|
|
|
22103
23012
|
const seen = new Set;
|
|
22104
23013
|
const universe = [];
|
|
22105
23014
|
for (const page2 of project.graph.pages) {
|
|
22106
|
-
if (page2.locale !== i18n.defaultLocale || page2.fallback || !page2.sourcePath || seen.has(page2.sourcePath)) {
|
|
23015
|
+
if (page2.locale !== i18n.defaultLocale || page2.fallback || !page2.sourcePath || seen.has(page2.sourcePath) || page2.version !== "") {
|
|
22107
23016
|
continue;
|
|
22108
23017
|
}
|
|
22109
23018
|
const ext = extname8(page2.sourcePath);
|
|
@@ -22673,8 +23582,249 @@ var validateCommand = defineCommand14({
|
|
|
22673
23582
|
}
|
|
22674
23583
|
});
|
|
22675
23584
|
|
|
23585
|
+
// src/cli/commands/version.ts
|
|
23586
|
+
import { defineCommand as defineCommand15 } from "citty";
|
|
23587
|
+
|
|
23588
|
+
// src/core/version-cut.ts
|
|
23589
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
23590
|
+
import { cp as cp3, readdir as readdir3, readFile as readFile27, rm as rm5 } from "node:fs/promises";
|
|
23591
|
+
import { join as join48, relative as relative21 } from "pathe";
|
|
23592
|
+
class CutError extends Error {
|
|
23593
|
+
constructor(message) {
|
|
23594
|
+
super(message);
|
|
23595
|
+
this.name = "CutError";
|
|
23596
|
+
}
|
|
23597
|
+
}
|
|
23598
|
+
var INLINE_CODE2 = /`[^`]*`/gu;
|
|
23599
|
+
var ROOT_LINK = /(?<prefix>\]\(|href="|src=")(?<target>\/[^\s"')]*)/gu;
|
|
23600
|
+
var buildRouteRewrites = (project, id2) => {
|
|
23601
|
+
const { basePath, i18n } = project.config;
|
|
23602
|
+
const { contentRoot: contentRoot2 } = project.context;
|
|
23603
|
+
const rewrites = new Map;
|
|
23604
|
+
for (const page2 of project.graph.pages) {
|
|
23605
|
+
const { sourcePath } = page2;
|
|
23606
|
+
if (page2.version !== "" || !sourcePath || relative21(contentRoot2, sourcePath).startsWith("..")) {
|
|
23607
|
+
continue;
|
|
23608
|
+
}
|
|
23609
|
+
const logical = versionizeRoute(page2.versionKey, id2);
|
|
23610
|
+
rewrites.set(stripBasePath(basePath, page2.route), i18n ? localizeRoute(logical, page2.locale, i18n) : logical);
|
|
23611
|
+
}
|
|
23612
|
+
return rewrites;
|
|
23613
|
+
};
|
|
23614
|
+
var rewriteLine2 = (line, rewrites) => {
|
|
23615
|
+
const masked = line.replaceAll(INLINE_CODE2, (span) => " ".repeat(span.length));
|
|
23616
|
+
let out = "";
|
|
23617
|
+
let cursor = 0;
|
|
23618
|
+
let count = 0;
|
|
23619
|
+
for (const match of masked.matchAll(ROOT_LINK)) {
|
|
23620
|
+
const target = match.groups?.target ?? "";
|
|
23621
|
+
const hash = target.search(/[#?]/u);
|
|
23622
|
+
const path = hash === -1 ? target : target.slice(0, hash);
|
|
23623
|
+
const suffix = hash === -1 ? "" : target.slice(hash);
|
|
23624
|
+
const bare = path !== "/" && path.endsWith("/") ? path.slice(0, -1) : path;
|
|
23625
|
+
const replacement = rewrites.get(bare);
|
|
23626
|
+
if (replacement === undefined) {
|
|
23627
|
+
continue;
|
|
23628
|
+
}
|
|
23629
|
+
const offset = (match.index ?? 0) + (match.groups?.prefix?.length ?? 0);
|
|
23630
|
+
out += line.slice(cursor, offset) + replacement + suffix;
|
|
23631
|
+
cursor = offset + target.length;
|
|
23632
|
+
count += 1;
|
|
23633
|
+
}
|
|
23634
|
+
return count === 0 ? line : out + line.slice(cursor);
|
|
23635
|
+
};
|
|
23636
|
+
var rewriteSnapshotLinks = (source, rewrites) => {
|
|
23637
|
+
let fence = null;
|
|
23638
|
+
let count = 0;
|
|
23639
|
+
const lines = source.split(`
|
|
23640
|
+
`).map((line) => {
|
|
23641
|
+
const next = nextFenceState(line, fence);
|
|
23642
|
+
const inFence = fence !== null || next !== null;
|
|
23643
|
+
fence = next;
|
|
23644
|
+
if (inFence) {
|
|
23645
|
+
return line;
|
|
23646
|
+
}
|
|
23647
|
+
const rewrittenLine = rewriteLine2(line, rewrites);
|
|
23648
|
+
if (rewrittenLine !== line) {
|
|
23649
|
+
count += 1;
|
|
23650
|
+
}
|
|
23651
|
+
return rewrittenLine;
|
|
23652
|
+
});
|
|
23653
|
+
return { count, text: lines.join(`
|
|
23654
|
+
`) };
|
|
23655
|
+
};
|
|
23656
|
+
var snippetFor = (id2, hasVersions) => hasVersions ? `Add to versions.archived in blume.config.ts (newest first):
|
|
23657
|
+
|
|
23658
|
+
{ id: "${id2}" },
|
|
23659
|
+
` : `Add to blume.config.ts:
|
|
23660
|
+
|
|
23661
|
+
versions: {
|
|
23662
|
+
archived: [{ id: "${id2}" }],
|
|
23663
|
+
current: { label: "…" },
|
|
23664
|
+
},
|
|
23665
|
+
`;
|
|
23666
|
+
var insertArchivedVersion = async (configPath, id2) => {
|
|
23667
|
+
let text2;
|
|
23668
|
+
try {
|
|
23669
|
+
text2 = await readFile27(configPath, "utf-8");
|
|
23670
|
+
} catch {
|
|
23671
|
+
return false;
|
|
23672
|
+
}
|
|
23673
|
+
const match = text2.match(/(?<lead>archived:\s*\[)/u);
|
|
23674
|
+
if (!match || match.index === undefined) {
|
|
23675
|
+
return false;
|
|
23676
|
+
}
|
|
23677
|
+
const insertAt = match.index + (match.groups?.lead?.length ?? 0);
|
|
23678
|
+
const lineStart = text2.lastIndexOf(`
|
|
23679
|
+
`, match.index) + 1;
|
|
23680
|
+
const indent = text2.slice(lineStart).match(/^\s*/u)?.[0] ?? "";
|
|
23681
|
+
const rest = text2.slice(insertAt);
|
|
23682
|
+
let entry;
|
|
23683
|
+
if (rest.trimStart().startsWith("]")) {
|
|
23684
|
+
entry = `{ id: "${id2}" }`;
|
|
23685
|
+
} else if (rest.startsWith(`
|
|
23686
|
+
`)) {
|
|
23687
|
+
entry = `
|
|
23688
|
+
${indent} { id: "${id2}" },`;
|
|
23689
|
+
} else {
|
|
23690
|
+
entry = `{ id: "${id2}" }, `;
|
|
23691
|
+
}
|
|
23692
|
+
await writeTextAtomic(configPath, text2.slice(0, insertAt) + entry + rest);
|
|
23693
|
+
return true;
|
|
23694
|
+
};
|
|
23695
|
+
var cutVersion = async (root, id2, options = {}) => {
|
|
23696
|
+
if (!VERSION_ID.test(id2)) {
|
|
23697
|
+
throw new CutError(`Version ids must start with a letter (e.g. "v1.0") and contain only letters, digits, dots, hyphens, and underscores — got "${id2}".`);
|
|
23698
|
+
}
|
|
23699
|
+
const project = await scanProject(root);
|
|
23700
|
+
const errors = project.diagnostics.filter((diagnostic) => diagnostic.severity === "error");
|
|
23701
|
+
if (errors.length > 0) {
|
|
23702
|
+
throw new CutError(`The project has ${errors.length} error diagnostic(s) — fix them before cutting a version (run \`blume validate\`).`);
|
|
23703
|
+
}
|
|
23704
|
+
const { contentRoot: contentRoot2 } = project.context;
|
|
23705
|
+
if (project.config.versions?.archived.some((version) => version.id === id2)) {
|
|
23706
|
+
throw new CutError(`Version "${id2}" is already registered in versions.archived.`);
|
|
23707
|
+
}
|
|
23708
|
+
const dir = join48(contentRoot2, id2);
|
|
23709
|
+
if (existsSync28(dir)) {
|
|
23710
|
+
if (!options.force) {
|
|
23711
|
+
throw new CutError(`${dir} already exists — pass --force to overwrite the snapshot.`);
|
|
23712
|
+
}
|
|
23713
|
+
await rm5(dir, { force: true, recursive: true });
|
|
23714
|
+
}
|
|
23715
|
+
const excluded = new Set([
|
|
23716
|
+
id2,
|
|
23717
|
+
"node_modules",
|
|
23718
|
+
...project.config.versions?.archived.map((version) => version.id) ?? []
|
|
23719
|
+
]);
|
|
23720
|
+
const entries = await readdir3(contentRoot2, { withFileTypes: true });
|
|
23721
|
+
let copied = 0;
|
|
23722
|
+
await Promise.all(entries.map(async (entry) => {
|
|
23723
|
+
if (excluded.has(entry.name) || entry.name.startsWith(".") || entry.isDirectory() && VERSION_LIKE.test(entry.name)) {
|
|
23724
|
+
return;
|
|
23725
|
+
}
|
|
23726
|
+
await cp3(join48(contentRoot2, entry.name), join48(dir, entry.name), {
|
|
23727
|
+
recursive: true
|
|
23728
|
+
});
|
|
23729
|
+
}));
|
|
23730
|
+
const rewrites = buildRouteRewrites(project, id2);
|
|
23731
|
+
const rewritten = [];
|
|
23732
|
+
const walk = async (current) => {
|
|
23733
|
+
const children = await readdir3(current, { withFileTypes: true });
|
|
23734
|
+
await Promise.all(children.map(async (child) => {
|
|
23735
|
+
const abs = join48(current, child.name);
|
|
23736
|
+
if (child.isDirectory()) {
|
|
23737
|
+
await walk(abs);
|
|
23738
|
+
return;
|
|
23739
|
+
}
|
|
23740
|
+
copied += 1;
|
|
23741
|
+
if (!/\.mdx?$/u.test(child.name)) {
|
|
23742
|
+
return;
|
|
23743
|
+
}
|
|
23744
|
+
const source = await readFile27(abs, "utf-8");
|
|
23745
|
+
const { text: text2, count } = rewriteSnapshotLinks(source, rewrites);
|
|
23746
|
+
if (count > 0) {
|
|
23747
|
+
await writeTextAtomic(abs, text2);
|
|
23748
|
+
rewritten.push({ count, file: relative21(dir, abs) });
|
|
23749
|
+
}
|
|
23750
|
+
}));
|
|
23751
|
+
};
|
|
23752
|
+
await walk(dir);
|
|
23753
|
+
const configPath = join48(root, "blume.config.ts");
|
|
23754
|
+
const configUpdated = project.config.versions !== undefined && await insertArchivedVersion(configPath, id2);
|
|
23755
|
+
return {
|
|
23756
|
+
configSnippet: configUpdated ? null : snippetFor(id2, project.config.versions !== undefined),
|
|
23757
|
+
configUpdated,
|
|
23758
|
+
copied,
|
|
23759
|
+
dir,
|
|
23760
|
+
rewritten
|
|
23761
|
+
};
|
|
23762
|
+
};
|
|
23763
|
+
|
|
23764
|
+
// src/cli/commands/version.ts
|
|
23765
|
+
var versionCommand = defineCommand15({
|
|
23766
|
+
args: {
|
|
23767
|
+
force: {
|
|
23768
|
+
description: "Overwrite an existing snapshot directory.",
|
|
23769
|
+
type: "boolean"
|
|
23770
|
+
},
|
|
23771
|
+
id: {
|
|
23772
|
+
description: 'Version id to cut (e.g. "v1.0").',
|
|
23773
|
+
required: false,
|
|
23774
|
+
type: "positional"
|
|
23775
|
+
}
|
|
23776
|
+
},
|
|
23777
|
+
meta: {
|
|
23778
|
+
description: "Freeze the current docs as an archived version.",
|
|
23779
|
+
name: "version"
|
|
23780
|
+
},
|
|
23781
|
+
async run({ args }) {
|
|
23782
|
+
const root = process.cwd();
|
|
23783
|
+
if (!args.id) {
|
|
23784
|
+
const { config: config2 } = await loadConfig(root);
|
|
23785
|
+
if (!config2.versions) {
|
|
23786
|
+
logger.info("Versioning is not configured. Cut the first version with `blume version <id>` (e.g. `blume version v1.0`).");
|
|
23787
|
+
return;
|
|
23788
|
+
}
|
|
23789
|
+
const { current, archived } = config2.versions;
|
|
23790
|
+
process.stdout.write(` ${current.label} (current)${current.badge ? ` — ${current.badge}` : ""}
|
|
23791
|
+
`);
|
|
23792
|
+
for (const version of archived) {
|
|
23793
|
+
process.stdout.write(` ${version.label ?? version.id} — ${version.id}/
|
|
23794
|
+
`);
|
|
23795
|
+
}
|
|
23796
|
+
return;
|
|
23797
|
+
}
|
|
23798
|
+
try {
|
|
23799
|
+
const result = await cutVersion(root, args.id, { force: args.force });
|
|
23800
|
+
logger.success(`Snapshot ${result.dir} (${result.copied} file(s) copied)`);
|
|
23801
|
+
const totalRewrites = result.rewritten.reduce((sum, entry) => sum + entry.count, 0);
|
|
23802
|
+
if (totalRewrites > 0) {
|
|
23803
|
+
logger.info(`Rewrote root-absolute links in ${result.rewritten.length} page(s) (${totalRewrites} line(s)).`);
|
|
23804
|
+
}
|
|
23805
|
+
if (result.configUpdated) {
|
|
23806
|
+
logger.success(`Added "${args.id}" to versions.archived in blume.config.ts`);
|
|
23807
|
+
} else if (result.configSnippet) {
|
|
23808
|
+
logger.info(result.configSnippet);
|
|
23809
|
+
}
|
|
23810
|
+
logger.info("Archived versions are frozen — future edits belong in the live tree. Restart `blume dev` to pick up the snapshot.");
|
|
23811
|
+
} catch (error) {
|
|
23812
|
+
if (error instanceof CutError) {
|
|
23813
|
+
logger.error(error.message);
|
|
23814
|
+
process.exit(1);
|
|
23815
|
+
}
|
|
23816
|
+
if (error instanceof BlumeError) {
|
|
23817
|
+
logger.error(error.diagnostic.message);
|
|
23818
|
+
process.exit(1);
|
|
23819
|
+
}
|
|
23820
|
+
reportInternalError(error);
|
|
23821
|
+
process.exit(1);
|
|
23822
|
+
}
|
|
23823
|
+
}
|
|
23824
|
+
});
|
|
23825
|
+
|
|
22676
23826
|
// src/cli/index.ts
|
|
22677
|
-
var main =
|
|
23827
|
+
var main = defineCommand16({
|
|
22678
23828
|
meta: {
|
|
22679
23829
|
description: "Markdown-first documentation powered by Astro and Vite.",
|
|
22680
23830
|
name: "blume",
|
|
@@ -22694,7 +23844,8 @@ var main = defineCommand15({
|
|
|
22694
23844
|
preview: previewCommand,
|
|
22695
23845
|
sync: syncCommand,
|
|
22696
23846
|
translate: translateCommand,
|
|
22697
|
-
validate: validateCommand
|
|
23847
|
+
validate: validateCommand,
|
|
23848
|
+
version: versionCommand
|
|
22698
23849
|
}
|
|
22699
23850
|
});
|
|
22700
23851
|
loadEnvFiles(process.cwd());
|
|
@@ -22708,5 +23859,5 @@ process.on("unhandledRejection", (error) => {
|
|
|
22708
23859
|
});
|
|
22709
23860
|
runMain(main);
|
|
22710
23861
|
|
|
22711
|
-
//# debugId=
|
|
23862
|
+
//# debugId=A01DCE54DD00393164756E2164756E21
|
|
22712
23863
|
//# sourceMappingURL=index.js.map
|