blume 1.4.3 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/cli/index.js +1621 -576
- package/dist/cli/index.js.map +109 -104
- package/dist/types/ai/component-markdown.d.ts +14 -4
- package/dist/types/core/config-input.d.ts +79 -27
- package/dist/types/core/config.d.ts +2 -1
- package/dist/types/core/data.d.ts +16 -1
- 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/docs/advanced/api-reference.mdx +8 -6
- package/docs/configuration/search.mdx +2 -0
- package/docs/configuration/seo.mdx +1 -1
- 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 +1 -0
- 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 +54 -29
- package/src/astro/integration.ts +13 -2
- package/src/astro/islands.ts +16 -9
- package/src/astro/templates.ts +152 -33
- 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/Header.astro +25 -1
- package/src/components/layout/NavSelector.astro +11 -2
- package/src/components/layout/NavTree.astro +4 -2
- package/src/components/layout/RootLayout.astro +18 -0
- 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 +88 -27
- package/src/core/config.ts +20 -7
- package/src/core/content.ts +3 -1
- package/src/core/data.ts +16 -1
- 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/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 +15 -3
- package/src/core/schema.ts +213 -67
- 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 +11 -4
- 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 +30 -11
- 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/fonts.ts +8 -4
- 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);
|
|
@@ -3626,9 +3650,9 @@ var ADAPTER_IMPORTS = {
|
|
|
3626
3650
|
node: "@astrojs/node",
|
|
3627
3651
|
vercel: "@astrojs/vercel"
|
|
3628
3652
|
};
|
|
3629
|
-
var ADAPTER_OPTIONS =
|
|
3630
|
-
node
|
|
3631
|
-
|
|
3653
|
+
var ADAPTER_OPTIONS = new Map([
|
|
3654
|
+
["node", '{ mode: "standalone" }']
|
|
3655
|
+
]);
|
|
3632
3656
|
var WRANGLER_CONFIG_FILES = [
|
|
3633
3657
|
"wrangler.jsonc",
|
|
3634
3658
|
"wrangler.json",
|
|
@@ -3790,7 +3814,7 @@ var astroConfigTemplate = (options) => {
|
|
|
3790
3814
|
if (deployment.adapter === "cloudflare") {
|
|
3791
3815
|
return resolveCloudflareAdapterArgs(context);
|
|
3792
3816
|
}
|
|
3793
|
-
return ADAPTER_OPTIONS
|
|
3817
|
+
return ADAPTER_OPTIONS.get(deployment.adapter) ?? "";
|
|
3794
3818
|
})();
|
|
3795
3819
|
const adapterExpr = deployment.adapter === "vercel" ? `withAdapterRoot(adapter(${adapterArgs}), ${JSON.stringify(adapterRoot(context))})` : `adapter(${adapterArgs})`;
|
|
3796
3820
|
const adapterOption = server && deployment.adapter ? `
|
|
@@ -3817,13 +3841,21 @@ var astroConfigTemplate = (options) => {
|
|
|
3817
3841
|
])))},` : "";
|
|
3818
3842
|
const fontEntries = buildFontEntries(config.theme.fonts);
|
|
3819
3843
|
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
|
-
|
|
3844
|
+
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) => {
|
|
3845
|
+
const face = {};
|
|
3846
|
+
if (variant.weight !== undefined) {
|
|
3847
|
+
face.weight = variant.weight;
|
|
3848
|
+
}
|
|
3849
|
+
if (variant.style !== undefined) {
|
|
3850
|
+
face.style = variant.style;
|
|
3851
|
+
}
|
|
3852
|
+
return {
|
|
3853
|
+
...face,
|
|
3854
|
+
src: [
|
|
3855
|
+
isAbsolute(variant.src) ? variant.src : join8(context.root, variant.src)
|
|
3856
|
+
]
|
|
3857
|
+
};
|
|
3858
|
+
}))} } }` : `{ 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
3859
|
const defineConfigImport = astroConfigImportLine({
|
|
3828
3860
|
hasFonts: fontEntries.length > 0,
|
|
3829
3861
|
hasSession: sessionOption.length > 0
|
|
@@ -4638,11 +4670,13 @@ export function getStaticPaths() {
|
|
|
4638
4670
|
locale: route.locale,
|
|
4639
4671
|
route: route.path,
|
|
4640
4672
|
title: route.title,
|
|
4673
|
+
version: route.version,
|
|
4674
|
+
versionAlternates: route.versionAlternates,
|
|
4641
4675
|
},
|
|
4642
4676
|
}));
|
|
4643
4677
|
}
|
|
4644
4678
|
|
|
4645
|
-
const { entryId, collection, route, title, indexable, editUrl, lastModified, locale, alternates, fallback } = Astro.props;
|
|
4679
|
+
const { entryId, collection, route, title, indexable, editUrl, lastModified, locale, alternates, fallback, version, versionAlternates } = Astro.props;
|
|
4646
4680
|
const entry = await getEntry(collection as CollectionKey, entryId);
|
|
4647
4681
|
if (!entry) {
|
|
4648
4682
|
return new Response(null, { status: 404 });
|
|
@@ -4674,9 +4708,6 @@ const ogGenerated = !seo.image && Boolean(ogPath);
|
|
|
4674
4708
|
const x = { ...data.config.x, ...(seo.x?.creator ? { creator: seo.x.creator } : {}) };
|
|
4675
4709
|
|
|
4676
4710
|
const basedRoute = withBase(route);
|
|
4677
|
-
const canonical =
|
|
4678
|
-
seo.canonical ??
|
|
4679
|
-
(base ? \`\${base}\${basedRoute === "/" ? "" : encodeURI(basedRoute)}\` : null);
|
|
4680
4711
|
|
|
4681
4712
|
// Locale resolution. With i18n on, pick the active locale's nav + dictionary,
|
|
4682
4713
|
// build hreflang alternates, and derive the language-switcher targets.
|
|
@@ -4697,7 +4728,20 @@ const stripLocale = (path: string, codeArg: string) => {
|
|
|
4697
4728
|
return prefix && path.startsWith(prefix) ? path.slice(prefix.length) || "/" : path;
|
|
4698
4729
|
};
|
|
4699
4730
|
|
|
4700
|
-
|
|
4731
|
+
// Version resolution. An archived page renders its snapshot's navigation tree,
|
|
4732
|
+
// points its canonical at the latest equivalent (unless configured otherwise),
|
|
4733
|
+
// and shows the old-version notice.
|
|
4734
|
+
const versionsConfig = data.config.versions;
|
|
4735
|
+
const archived = versionsConfig && version
|
|
4736
|
+
? (versionsConfig.archived.find((v) => v.id === version) ?? null)
|
|
4737
|
+
: null;
|
|
4738
|
+
const latestVersionAlt = (versionAlternates ?? []).find((alt) => alt.version === "");
|
|
4739
|
+
|
|
4740
|
+
const navigation = version
|
|
4741
|
+
? (data.navigationByVersion[version]?.[i18n ? locale : ""] ?? data.navigation)
|
|
4742
|
+
: i18n
|
|
4743
|
+
? (data.navigationByLocale[locale] ?? data.navigation)
|
|
4744
|
+
: data.navigation;
|
|
4701
4745
|
const ui = i18n ? (data.uiByLocale[locale] ?? data.ui) : data.ui;
|
|
4702
4746
|
const localeMeta = i18n ? i18n.locales.find((l) => l.code === locale) : null;
|
|
4703
4747
|
const dir = localeMeta?.dir ?? "ltr";
|
|
@@ -4714,6 +4758,19 @@ const absolute = (path: string) => {
|
|
|
4714
4758
|
return base + (p === "/" ? "" : p);
|
|
4715
4759
|
};
|
|
4716
4760
|
|
|
4761
|
+
// An archived page defaults its canonical to the same page in the latest docs
|
|
4762
|
+
// when that page still exists — search engines treat the live page as
|
|
4763
|
+
// authoritative without deindexing version-only content. A page's own
|
|
4764
|
+
// \`seo.canonical\` always wins, and \`canonical: "self"\` keeps the default.
|
|
4765
|
+
const canonical =
|
|
4766
|
+
seo.canonical ??
|
|
4767
|
+
(archived && archived.canonical === "latest" && latestVersionAlt && base
|
|
4768
|
+
? absolute(latestVersionAlt.path)
|
|
4769
|
+
: base
|
|
4770
|
+
? \`\${base}\${basedRoute === "/" ? "" : encodeURI(basedRoute)}\`
|
|
4771
|
+
: null);
|
|
4772
|
+
const effectiveNoindex = Boolean(seo.noindex) || (archived?.noindex ?? false);
|
|
4773
|
+
|
|
4717
4774
|
const localeAlternates =
|
|
4718
4775
|
i18n && base
|
|
4719
4776
|
? (alternates ?? []).map((alt) => ({ hreflang: alt.locale, href: absolute(alt.path) }))
|
|
@@ -4736,6 +4793,72 @@ const localeSwitch = i18n
|
|
|
4736
4793
|
})
|
|
4737
4794
|
: [];
|
|
4738
4795
|
|
|
4796
|
+
// Version switcher + old-version notice. The switcher auto-populates from the
|
|
4797
|
+
// versions config as a \`kind: "version"\` selector; a user-declared version
|
|
4798
|
+
// selector in \`navigation.selectors\` suppresses it (theirs renders instead).
|
|
4799
|
+
// Fallback version roots compose like real routes — \`{basePath}/{locale?}/{id}\`
|
|
4800
|
+
// (manifest \`versionAlternates\` paths arrive with the base already applied).
|
|
4801
|
+
const versionRootFor = (id: string) => {
|
|
4802
|
+
const logical = id ? \`/\${id}\` : "/";
|
|
4803
|
+
const localized = i18n ? localizeRoute(logical, locale) : logical;
|
|
4804
|
+
const mount = data.config.basePath;
|
|
4805
|
+
if (!mount) {
|
|
4806
|
+
return localized;
|
|
4807
|
+
}
|
|
4808
|
+
return localized === "/" ? mount : \`\${mount}\${localized}\`;
|
|
4809
|
+
};
|
|
4810
|
+
const samePageSwitch = versionsConfig
|
|
4811
|
+
? versionsConfig.switcher.redirect === "same-page"
|
|
4812
|
+
: true;
|
|
4813
|
+
const userHasVersionSelector = navigation.selectors.some(
|
|
4814
|
+
(selector) => selector.kind === "version"
|
|
4815
|
+
);
|
|
4816
|
+
const versionSelector =
|
|
4817
|
+
versionsConfig && !userHasVersionSelector
|
|
4818
|
+
? {
|
|
4819
|
+
items: [
|
|
4820
|
+
{
|
|
4821
|
+
id: "",
|
|
4822
|
+
label: versionsConfig.current.label,
|
|
4823
|
+
tag: versionsConfig.current.badge,
|
|
4824
|
+
},
|
|
4825
|
+
...versionsConfig.archived.map((v) => ({
|
|
4826
|
+
id: v.id,
|
|
4827
|
+
label: v.label ?? v.id,
|
|
4828
|
+
tag: undefined,
|
|
4829
|
+
})),
|
|
4830
|
+
].map((entry) => {
|
|
4831
|
+
const alt = (versionAlternates ?? []).find(
|
|
4832
|
+
(a) => a.version === entry.id
|
|
4833
|
+
);
|
|
4834
|
+
return {
|
|
4835
|
+
label: entry.label,
|
|
4836
|
+
path: samePageSwitch && alt ? alt.path : versionRootFor(entry.id),
|
|
4837
|
+
...(entry.tag ? { tag: entry.tag } : {}),
|
|
4838
|
+
};
|
|
4839
|
+
}),
|
|
4840
|
+
kind: "version" as const,
|
|
4841
|
+
label: ui.versions.switcher,
|
|
4842
|
+
}
|
|
4843
|
+
: null;
|
|
4844
|
+
|
|
4845
|
+
const versionNotice =
|
|
4846
|
+
archived && archived.banner !== false
|
|
4847
|
+
? {
|
|
4848
|
+
latestHref: latestVersionAlt
|
|
4849
|
+
? latestVersionAlt.path
|
|
4850
|
+
: versionRootFor(""),
|
|
4851
|
+
latestLabel: ui.versions.latest,
|
|
4852
|
+
message:
|
|
4853
|
+
typeof archived.banner === "string"
|
|
4854
|
+
? archived.banner
|
|
4855
|
+
: ui.versions.notice.replace(
|
|
4856
|
+
"{version}",
|
|
4857
|
+
archived.label ?? archived.id
|
|
4858
|
+
),
|
|
4859
|
+
}
|
|
4860
|
+
: null;
|
|
4861
|
+
|
|
4739
4862
|
// The whole page shell is overridable via \`layout.Layout\`; it receives the same
|
|
4740
4863
|
// props as the built-in RootLayout, plus the \`layout\` map for its inner slots.
|
|
4741
4864
|
const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
@@ -4760,6 +4883,9 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
|
4760
4883
|
localeAlternates={localeAlternates}
|
|
4761
4884
|
xDefault={xDefault}
|
|
4762
4885
|
localeSwitch={localeSwitch}
|
|
4886
|
+
versionSelector={versionSelector}
|
|
4887
|
+
versionNotice={versionNotice}
|
|
4888
|
+
searchVersion={versionsConfig ? version : null}
|
|
4763
4889
|
page={{ title: seo.title ?? title, description: seo.description ?? frontmatter.description, route }}
|
|
4764
4890
|
headings={headings}
|
|
4765
4891
|
toc={data.config.toc}
|
|
@@ -4782,7 +4908,7 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
|
4782
4908
|
pageType={frontmatter.type}
|
|
4783
4909
|
published={frontmatter.date ?? frontmatter.changelog?.date ?? null}
|
|
4784
4910
|
lastModified={lastModified}
|
|
4785
|
-
noindex={
|
|
4911
|
+
noindex={effectiveNoindex}
|
|
4786
4912
|
structuredDataEnabled={data.config.structuredData}
|
|
4787
4913
|
>
|
|
4788
4914
|
<h1>{title}</h1>
|
|
@@ -5467,6 +5593,9 @@ var sitemapParser = new XMLParser({
|
|
|
5467
5593
|
parseTagValue: false,
|
|
5468
5594
|
removeNSPrefix: true
|
|
5469
5595
|
});
|
|
5596
|
+
var isUrlsetElement = (value) => typeof value === "object" && value !== null;
|
|
5597
|
+
var isUrlEntry = (value) => typeof value === "object" && value !== null;
|
|
5598
|
+
var isText = (value) => typeof value === "string";
|
|
5470
5599
|
var parseSitemap = (file, xml, bytes) => {
|
|
5471
5600
|
const doc = { bytes, file, lastmod: new Map, urls: [] };
|
|
5472
5601
|
let parsed;
|
|
@@ -5480,19 +5609,19 @@ var parseSitemap = (file, xml, bytes) => {
|
|
|
5480
5609
|
doc.error = Object.hasOwn(parsed, "sitemapindex") ? "sitemap is an index, not a urlset" : "no <urlset> element";
|
|
5481
5610
|
return doc;
|
|
5482
5611
|
}
|
|
5483
|
-
const urlset = parsed
|
|
5484
|
-
const entries =
|
|
5612
|
+
const { urlset } = parsed;
|
|
5613
|
+
const entries = isUrlsetElement(urlset) ? [urlset.url].flat() : [];
|
|
5485
5614
|
for (const entry of entries) {
|
|
5486
|
-
if (
|
|
5615
|
+
if (!isUrlEntry(entry)) {
|
|
5487
5616
|
continue;
|
|
5488
5617
|
}
|
|
5489
5618
|
const { loc, lastmod } = entry;
|
|
5490
|
-
const locText =
|
|
5619
|
+
const locText = isText(loc) ? loc.trim() : "";
|
|
5491
5620
|
if (!locText) {
|
|
5492
5621
|
continue;
|
|
5493
5622
|
}
|
|
5494
5623
|
doc.urls.push(locText);
|
|
5495
|
-
if (
|
|
5624
|
+
if (isText(lastmod) && lastmod.trim() !== "") {
|
|
5496
5625
|
doc.lastmod?.set(locText, lastmod.trim());
|
|
5497
5626
|
}
|
|
5498
5627
|
}
|
|
@@ -5740,6 +5869,7 @@ import { relative as relative10 } from "pathe";
|
|
|
5740
5869
|
|
|
5741
5870
|
// src/core/config.ts
|
|
5742
5871
|
import { existsSync as existsSync6, readFileSync as readFileSync3 } from "node:fs";
|
|
5872
|
+
import { z as z3 } from "zod";
|
|
5743
5873
|
|
|
5744
5874
|
// src/core/load-module.ts
|
|
5745
5875
|
import { createJiti } from "jiti";
|
|
@@ -5795,8 +5925,9 @@ var resolveProjectContext = (root, config, options) => {
|
|
|
5795
5925
|
import { z as z2 } from "zod";
|
|
5796
5926
|
|
|
5797
5927
|
// src/seo/x-handle.ts
|
|
5928
|
+
var isString = (value) => typeof value === "string";
|
|
5798
5929
|
var normalizeXHandle = (value) => {
|
|
5799
|
-
if (
|
|
5930
|
+
if (!isString(value)) {
|
|
5800
5931
|
return;
|
|
5801
5932
|
}
|
|
5802
5933
|
const handle = value.trim().replace(/^@+/u, "");
|
|
@@ -9377,6 +9508,7 @@ var uiStringsObject = z.object({
|
|
|
9377
9508
|
search: z.object({
|
|
9378
9509
|
all: z.string().default("All"),
|
|
9379
9510
|
allLanguages: z.string().default("All languages"),
|
|
9511
|
+
allVersions: z.string().default("All versions"),
|
|
9380
9512
|
askAi: z.string().default("Ask AI"),
|
|
9381
9513
|
askAiHint: z.string().default("Get an instant answer from AI"),
|
|
9382
9514
|
button: z.string().default("Search"),
|
|
@@ -9393,6 +9525,11 @@ var uiStringsObject = z.object({
|
|
|
9393
9525
|
}).prefault({}),
|
|
9394
9526
|
toc: z.object({
|
|
9395
9527
|
title: z.string().default("On this page")
|
|
9528
|
+
}).prefault({}),
|
|
9529
|
+
versions: z.object({
|
|
9530
|
+
latest: z.string().default("Go to latest"),
|
|
9531
|
+
notice: z.string().default("You're viewing documentation for {version}. It may be out of date."),
|
|
9532
|
+
switcher: z.string().default("Version")
|
|
9396
9533
|
}).prefault({})
|
|
9397
9534
|
});
|
|
9398
9535
|
var uiStringsSchema = uiStringsObject.prefault({});
|
|
@@ -9433,12 +9570,16 @@ var resolveUIStrings = (locale, options) => {
|
|
|
9433
9570
|
var isStandardSchema = (value) => typeof value === "object" && value !== null && typeof value["~standard"]?.validate === "function";
|
|
9434
9571
|
|
|
9435
9572
|
// src/core/schema.ts
|
|
9573
|
+
var isString2 = (value) => typeof value === "string";
|
|
9574
|
+
var isBoolean = (value) => typeof value === "boolean";
|
|
9436
9575
|
var iconName = z2.string().min(1);
|
|
9437
9576
|
var DEFAULT_CONTENT_GLOB = "**/*.{md,mdx}";
|
|
9438
9577
|
var hydrationMode = z2.enum(["load", "idle", "visible", "media", "only"]);
|
|
9439
9578
|
var dateSchema = z2.union([z2.string(), z2.date()]).transform((value) => value instanceof Date ? value.toISOString() : value);
|
|
9579
|
+
var sidebarDisplaySchema = z2.enum(["flat", "group", "page"]);
|
|
9440
9580
|
var sidebarMetaSchema = z2.strictObject({
|
|
9441
9581
|
badge: z2.string().optional(),
|
|
9582
|
+
display: sidebarDisplaySchema.optional(),
|
|
9442
9583
|
hidden: z2.boolean().default(false),
|
|
9443
9584
|
icon: iconName.optional(),
|
|
9444
9585
|
label: z2.string().optional(),
|
|
@@ -9495,11 +9636,12 @@ var pageMetaBaseSchema = z2.strictObject({
|
|
|
9495
9636
|
type: z2.string().optional()
|
|
9496
9637
|
});
|
|
9497
9638
|
var pageMetaSchema = pageMetaBaseSchema;
|
|
9639
|
+
var BUILT_IN_PAGE_META_KEYS = new Set(pageMetaBaseSchema.keyof().options);
|
|
9498
9640
|
var customKeySchemaRecord = (where) => z2.record(z2.string(), z2.custom(isStandardSchema, {
|
|
9499
9641
|
message: "Expected a Standard Schema (e.g. a Zod schema — any Zod version works)."
|
|
9500
9642
|
})).default({}).superRefine((value, ctx) => {
|
|
9501
9643
|
for (const key of Object.keys(value)) {
|
|
9502
|
-
if (
|
|
9644
|
+
if (BUILT_IN_PAGE_META_KEYS.has(key)) {
|
|
9503
9645
|
ctx.addIssue({
|
|
9504
9646
|
code: z2.ZodIssueCode.custom,
|
|
9505
9647
|
message: `"${key}" is a built-in frontmatter field and cannot be redeclared via ${where}.`,
|
|
@@ -9508,9 +9650,9 @@ var customKeySchemaRecord = (where) => z2.record(z2.string(), z2.custom(isStanda
|
|
|
9508
9650
|
}
|
|
9509
9651
|
}
|
|
9510
9652
|
});
|
|
9511
|
-
var sidebarDisplaySchema = z2.enum(["flat", "group", "page"]);
|
|
9512
9653
|
var folderMetaSchema = z2.strictObject({
|
|
9513
9654
|
collapsed: z2.boolean().optional(),
|
|
9655
|
+
display: sidebarDisplaySchema.optional(),
|
|
9514
9656
|
icon: iconName.optional(),
|
|
9515
9657
|
order: z2.number().optional(),
|
|
9516
9658
|
pages: z2.array(z2.string()).optional(),
|
|
@@ -9604,7 +9746,7 @@ var githubReleasesSourceSchema = z2.strictObject({
|
|
|
9604
9746
|
type: z2.literal("github-releases")
|
|
9605
9747
|
});
|
|
9606
9748
|
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)" }),
|
|
9749
|
+
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
9750
|
type: z2.literal("custom")
|
|
9609
9751
|
});
|
|
9610
9752
|
var contentSourceSchema = z2.discriminatedUnion("type", [
|
|
@@ -9695,7 +9837,7 @@ var localFontSchema = z2.strictObject({
|
|
|
9695
9837
|
variants: z2.array(localFontVariantSchema).nonempty()
|
|
9696
9838
|
});
|
|
9697
9839
|
var fontValueSchema = z2.union([z2.string(), remoteFontSchema, localFontSchema]).superRefine((value, ctx) => {
|
|
9698
|
-
if (
|
|
9840
|
+
if (isString2(value) && !isFontSlug(value)) {
|
|
9699
9841
|
ctx.addIssue({
|
|
9700
9842
|
code: z2.ZodIssueCode.custom,
|
|
9701
9843
|
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,12 +9850,12 @@ var perModeValueSchema = z2.union([
|
|
|
9708
9850
|
dark: z2.string().optional(),
|
|
9709
9851
|
light: z2.string().optional()
|
|
9710
9852
|
})
|
|
9711
|
-
]).optional().transform((value) =>
|
|
9853
|
+
]).optional().transform((value) => isString2(value) ? { dark: value, light: value } : value);
|
|
9712
9854
|
var themeConfigSchema = z2.strictObject({
|
|
9713
9855
|
accent: z2.union([
|
|
9714
9856
|
z2.string(),
|
|
9715
9857
|
z2.strictObject({ dark: z2.string(), light: z2.string() })
|
|
9716
|
-
]).default("blue").transform((value) =>
|
|
9858
|
+
]).default("blue").transform((value) => isString2(value) ? { dark: value, light: value } : value),
|
|
9717
9859
|
action: z2.string().optional(),
|
|
9718
9860
|
background: perModeValueSchema,
|
|
9719
9861
|
backgroundImage: perModeValueSchema,
|
|
@@ -9796,7 +9938,7 @@ var askAiProviders = [
|
|
|
9796
9938
|
];
|
|
9797
9939
|
var PRIVATE_JWK_PARAMS = ["d", "p", "q", "dp", "dq", "qi", "oth", "k"];
|
|
9798
9940
|
var publicJwkSchema = z2.record(z2.string(), z2.unknown()).superRefine((jwk, ctx) => {
|
|
9799
|
-
if (
|
|
9941
|
+
if (!isString2(jwk.kty) || jwk.kty.length === 0) {
|
|
9800
9942
|
ctx.addIssue({
|
|
9801
9943
|
code: z2.ZodIssueCode.custom,
|
|
9802
9944
|
message: 'A JWK must declare its key type ("kty").'
|
|
@@ -9857,7 +9999,7 @@ var aiConfigSchema = z2.strictObject({
|
|
|
9857
9999
|
enabled: z2.boolean().default(true),
|
|
9858
10000
|
openapi: z2.boolean().default(true)
|
|
9859
10001
|
})
|
|
9860
|
-
]).default(true).transform((value) =>
|
|
10002
|
+
]).default(true).transform((value) => isBoolean(value) ? { enabled: value, openapi: true } : value),
|
|
9861
10003
|
markdownComponents: z2.record(z2.string(), z2.custom((value) => typeof value === "function", {
|
|
9862
10004
|
message: "Expected a serializer function."
|
|
9863
10005
|
})).default({}),
|
|
@@ -9892,7 +10034,7 @@ var exportConfigSchema = z2.union([
|
|
|
9892
10034
|
epub: z2.boolean().default(false),
|
|
9893
10035
|
pdf: z2.boolean().default(false)
|
|
9894
10036
|
})
|
|
9895
|
-
]).transform((value) =>
|
|
10037
|
+
]).transform((value) => isBoolean(value) ? { epub: value, pdf: value } : value);
|
|
9896
10038
|
var localeSchema = z2.strictObject({
|
|
9897
10039
|
code: z2.string().min(1),
|
|
9898
10040
|
dir: z2.enum(["ltr", "rtl"]).default("ltr"),
|
|
@@ -9923,6 +10065,36 @@ var i18nConfigSchema = z2.strictObject({
|
|
|
9923
10065
|
});
|
|
9924
10066
|
}
|
|
9925
10067
|
});
|
|
10068
|
+
var VERSION_ID = /^[A-Za-z][\w.-]*$/u;
|
|
10069
|
+
var archivedVersionSchema = z2.strictObject({
|
|
10070
|
+
banner: z2.union([z2.boolean(), z2.string()]).default(true),
|
|
10071
|
+
canonical: z2.enum(["latest", "self"]).default("latest"),
|
|
10072
|
+
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.'),
|
|
10073
|
+
label: z2.string().optional(),
|
|
10074
|
+
noindex: z2.boolean().default(false)
|
|
10075
|
+
});
|
|
10076
|
+
var versionsConfigSchema = z2.strictObject({
|
|
10077
|
+
archived: z2.array(archivedVersionSchema).default([]),
|
|
10078
|
+
current: z2.strictObject({
|
|
10079
|
+
badge: z2.string().optional(),
|
|
10080
|
+
label: z2.string()
|
|
10081
|
+
}),
|
|
10082
|
+
switcher: z2.strictObject({
|
|
10083
|
+
redirect: z2.enum(["same-page", "root"]).default("same-page")
|
|
10084
|
+
}).prefault({})
|
|
10085
|
+
}).superRefine((value, ctx) => {
|
|
10086
|
+
const seen = new Set;
|
|
10087
|
+
for (const [position, version] of value.archived.entries()) {
|
|
10088
|
+
if (seen.has(version.id)) {
|
|
10089
|
+
ctx.addIssue({
|
|
10090
|
+
code: z2.ZodIssueCode.custom,
|
|
10091
|
+
message: `versions.archived declares "${version.id}" more than once.`,
|
|
10092
|
+
path: ["archived", position, "id"]
|
|
10093
|
+
});
|
|
10094
|
+
}
|
|
10095
|
+
seen.add(version.id);
|
|
10096
|
+
}
|
|
10097
|
+
});
|
|
9926
10098
|
var analyticsScriptSchema = z2.strictObject({
|
|
9927
10099
|
attributes: z2.record(z2.string(), z2.string()).optional(),
|
|
9928
10100
|
content: z2.string().optional(),
|
|
@@ -10036,18 +10208,18 @@ var githubConfigSchema = z2.strictObject({
|
|
|
10036
10208
|
owner: z2.string(),
|
|
10037
10209
|
repo: z2.string()
|
|
10038
10210
|
});
|
|
10211
|
+
var isThemeObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10039
10212
|
var codeThemeSchema = z2.custom((value) => {
|
|
10040
|
-
if (
|
|
10213
|
+
if (isString2(value)) {
|
|
10041
10214
|
return true;
|
|
10042
10215
|
}
|
|
10043
|
-
if (
|
|
10216
|
+
if (!isThemeObject(value)) {
|
|
10044
10217
|
return false;
|
|
10045
10218
|
}
|
|
10046
|
-
const
|
|
10047
|
-
const
|
|
10048
|
-
const
|
|
10049
|
-
const
|
|
10050
|
-
const hasContent = theme.settings !== undefined || theme.tokenColors !== undefined || theme.colors !== undefined;
|
|
10219
|
+
const settingsValid = value.settings === undefined || Array.isArray(value.settings);
|
|
10220
|
+
const tokenColorsValid = value.tokenColors === undefined || Array.isArray(value.tokenColors);
|
|
10221
|
+
const colorsValid = value.colors === undefined || isThemeObject(value.colors);
|
|
10222
|
+
const hasContent = value.settings !== undefined || value.tokenColors !== undefined || value.colors !== undefined;
|
|
10051
10223
|
return settingsValid && tokenColorsValid && colorsValid && hasContent;
|
|
10052
10224
|
}, "Expected a Shiki theme name or custom theme object");
|
|
10053
10225
|
var codeBlockThemeSchema = z2.strictObject({
|
|
@@ -10063,7 +10235,7 @@ var examplesConfigSchema = z2.union([
|
|
|
10063
10235
|
css: z2.string().optional(),
|
|
10064
10236
|
source: z2.string().default("examples")
|
|
10065
10237
|
})
|
|
10066
|
-
]).transform((value) =>
|
|
10238
|
+
]).transform((value) => isString2(value) ? { source: value } : value);
|
|
10067
10239
|
var lastModifiedConfigSchema = z2.union([
|
|
10068
10240
|
z2.boolean(),
|
|
10069
10241
|
z2.strictObject({ type: z2.enum(["git", "frontmatter"]).default("git") })
|
|
@@ -10103,24 +10275,24 @@ var openapiSourceSchema = z2.strictObject({
|
|
|
10103
10275
|
spec: z2.string()
|
|
10104
10276
|
});
|
|
10105
10277
|
var scalarConfigSchema = z2.record(z2.string(), z2.unknown()).optional();
|
|
10106
|
-
var
|
|
10107
|
-
codeSamples: z2.array(z2.string()).default(
|
|
10278
|
+
var referenceConfigSchema = (defaults) => z2.strictObject({
|
|
10279
|
+
codeSamples: z2.array(z2.string()).default(defaults.codeSamples),
|
|
10108
10280
|
enabled: z2.boolean().default(false),
|
|
10109
10281
|
expandSchemas: z2.boolean().default(false),
|
|
10110
10282
|
renderer: z2.enum(["blume", "scalar"]).default("blume"),
|
|
10111
|
-
route: z2.string().default(
|
|
10283
|
+
route: z2.string().default(defaults.route),
|
|
10112
10284
|
scalar: scalarConfigSchema,
|
|
10113
10285
|
sources: z2.array(openapiSourceSchema).default([]),
|
|
10114
10286
|
spec: z2.string().optional(),
|
|
10115
10287
|
theme: z2.string().optional()
|
|
10116
10288
|
});
|
|
10117
|
-
var
|
|
10118
|
-
|
|
10119
|
-
route:
|
|
10120
|
-
|
|
10121
|
-
|
|
10122
|
-
|
|
10123
|
-
|
|
10289
|
+
var openapiConfigSchema = referenceConfigSchema({
|
|
10290
|
+
codeSamples: ["curl", "js", "python"],
|
|
10291
|
+
route: "/reference"
|
|
10292
|
+
});
|
|
10293
|
+
var asyncapiConfigSchema = referenceConfigSchema({
|
|
10294
|
+
codeSamples: [],
|
|
10295
|
+
route: "/events"
|
|
10124
10296
|
});
|
|
10125
10297
|
var frontmatterConfigSchema = z2.strictObject({
|
|
10126
10298
|
extend: customKeySchemaRecord("frontmatter.extend")
|
|
@@ -10132,7 +10304,7 @@ var tocConfigSchema = z2.union([
|
|
|
10132
10304
|
minHeadingLevel: z2.number().int().min(1).max(6).optional()
|
|
10133
10305
|
})
|
|
10134
10306
|
]).default(true).transform((value) => {
|
|
10135
|
-
if (
|
|
10307
|
+
if (isBoolean(value)) {
|
|
10136
10308
|
return { enabled: value, maxLevel: 3, minLevel: 2 };
|
|
10137
10309
|
}
|
|
10138
10310
|
return {
|
|
@@ -10172,8 +10344,21 @@ var blumeConfigSchema = z2.strictObject({
|
|
|
10172
10344
|
seo: seoConfigSchema.prefault({}),
|
|
10173
10345
|
theme: themeConfigSchema.prefault({}),
|
|
10174
10346
|
title: z2.string().default("Documentation"),
|
|
10175
|
-
toc: tocConfigSchema
|
|
10347
|
+
toc: tocConfigSchema,
|
|
10348
|
+
versions: versionsConfigSchema.optional()
|
|
10176
10349
|
}).superRefine((config, ctx) => {
|
|
10350
|
+
if (config.versions && config.i18n) {
|
|
10351
|
+
const localeCodes = new Set(config.i18n.locales.map((locale) => locale.code.toLowerCase()));
|
|
10352
|
+
for (const [position, version] of config.versions.archived.entries()) {
|
|
10353
|
+
if (localeCodes.has(version.id.toLowerCase())) {
|
|
10354
|
+
ctx.addIssue({
|
|
10355
|
+
code: z2.ZodIssueCode.custom,
|
|
10356
|
+
message: `Version id "${version.id}" is also a configured locale code — rename the version (e.g. "v${version.id}").`,
|
|
10357
|
+
path: ["versions", "archived", position, "id"]
|
|
10358
|
+
});
|
|
10359
|
+
}
|
|
10360
|
+
}
|
|
10361
|
+
}
|
|
10177
10362
|
for (const [typeName, typeConfig] of Object.entries(config.content.types)) {
|
|
10178
10363
|
for (const key of Object.keys(typeConfig.frontmatter)) {
|
|
10179
10364
|
if (Object.hasOwn(config.frontmatter.extend, key)) {
|
|
@@ -10198,9 +10383,12 @@ var blumeConfigSchema = z2.strictObject({
|
|
|
10198
10383
|
|
|
10199
10384
|
// src/core/config.ts
|
|
10200
10385
|
var importConfigModule = createModuleLoader();
|
|
10386
|
+
var themeFontsProbeSchema = z3.looseObject({
|
|
10387
|
+
theme: z3.looseObject({ fonts: z3.unknown() }).optional()
|
|
10388
|
+
});
|
|
10201
10389
|
var loadConfig = async (root, options = {}) => {
|
|
10202
10390
|
const configFile = findConfigFile(root);
|
|
10203
|
-
let raw
|
|
10391
|
+
let raw;
|
|
10204
10392
|
if (configFile) {
|
|
10205
10393
|
try {
|
|
10206
10394
|
raw = await importConfigModule(configFile);
|
|
@@ -10213,7 +10401,8 @@ var loadConfig = async (root, options = {}) => {
|
|
|
10213
10401
|
});
|
|
10214
10402
|
}
|
|
10215
10403
|
}
|
|
10216
|
-
const
|
|
10404
|
+
const probe2 = themeFontsProbeSchema.safeParse(raw);
|
|
10405
|
+
const themeFontsConfigured = probe2.success && probe2.data.theme?.fonts !== undefined;
|
|
10217
10406
|
const parsed = blumeConfigSchema.safeParse(raw ?? {});
|
|
10218
10407
|
if (!parsed.success) {
|
|
10219
10408
|
const source = configFile && existsSync6(configFile) ? readFileSync3(configFile, "utf-8") : undefined;
|
|
@@ -10320,12 +10509,14 @@ var localeTargetPath = (rel, ext, locale, i18n) => {
|
|
|
10320
10509
|
}
|
|
10321
10510
|
return `${locale}/${rel}`;
|
|
10322
10511
|
};
|
|
10323
|
-
var i18nDiagnostics = (pages, i18n) => {
|
|
10512
|
+
var i18nDiagnostics = (pages, i18n, versions) => {
|
|
10324
10513
|
const configured = new Set(i18n.locales.map((locale) => locale.code.toLowerCase()));
|
|
10514
|
+
const versionDirs = new Set(versions?.archived.map((version) => version.id));
|
|
10325
10515
|
const seen = new Set;
|
|
10326
10516
|
const diagnostics = [];
|
|
10327
10517
|
for (const page of pages) {
|
|
10328
|
-
const
|
|
10518
|
+
const parts = page.source.ref.split("/");
|
|
10519
|
+
const first = (parts[0] && versionDirs.has(parts[0]) ? parts[1] : parts[0])?.toLowerCase();
|
|
10329
10520
|
if (first && !seen.has(first) && KNOWN_LOCALES.has(first) && !configured.has(first)) {
|
|
10330
10521
|
seen.add(first);
|
|
10331
10522
|
diagnostics.push({
|
|
@@ -10381,7 +10572,7 @@ var resolveIcon = (name) => {
|
|
|
10381
10572
|
var hasIcon = (name) => resolveIcon(name) !== null;
|
|
10382
10573
|
|
|
10383
10574
|
// src/core/nav-diagnostics.ts
|
|
10384
|
-
var
|
|
10575
|
+
var ICON_FORMAT_HINT = "Use a built-in icon name, an image path/URL, or inline SVG markup.";
|
|
10385
10576
|
var flattenNodes = (nodes) => nodes.flatMap((node) => node.kind === "group" ? [node, ...flattenNodes(node.children)] : [node]);
|
|
10386
10577
|
var collectIcons = (navigation) => {
|
|
10387
10578
|
const icons = [];
|
|
@@ -10430,10 +10621,10 @@ var unknownIconDiagnostics = (icons, suggestion) => {
|
|
|
10430
10621
|
}
|
|
10431
10622
|
return diagnostics;
|
|
10432
10623
|
};
|
|
10433
|
-
var validateNavIcons = (navigation) => unknownIconDiagnostics(collectIcons(navigation),
|
|
10624
|
+
var validateNavIcons = (navigation) => unknownIconDiagnostics(collectIcons(navigation), ICON_FORMAT_HINT);
|
|
10434
10625
|
var validateSearchPopularIcons = (popular) => {
|
|
10435
10626
|
const icons = popular.flatMap((link) => link.icon ? [{ icon: link.icon, where: `popular link "${link.label}"` }] : []);
|
|
10436
|
-
return unknownIconDiagnostics(icons,
|
|
10627
|
+
return unknownIconDiagnostics(icons, ICON_FORMAT_HINT);
|
|
10437
10628
|
};
|
|
10438
10629
|
var resolvesToPages = (routes, path) => routes.has(path) || [...routes].some((route) => route.startsWith(`${path}/`));
|
|
10439
10630
|
var validateNavTargets = (navigation, routes) => {
|
|
@@ -10537,6 +10728,8 @@ var segmentKey = (raw) => {
|
|
|
10537
10728
|
return (group ?? raw).replace(NUMERIC_PREFIX, "");
|
|
10538
10729
|
};
|
|
10539
10730
|
var isIndexStem = (stem) => stem.replace(NUMERIC_PREFIX, "") === "index";
|
|
10731
|
+
var stemOf = (filename) => filename.replace(extname(filename), "");
|
|
10732
|
+
var navStem = (navPath) => stemOf(navPath.split("/").at(-1) ?? navPath);
|
|
10540
10733
|
var createGroup = (key, path, label, order) => ({
|
|
10541
10734
|
children: [],
|
|
10542
10735
|
index: new Map,
|
|
@@ -10561,7 +10754,7 @@ var pageOrder = (page, filename) => {
|
|
|
10561
10754
|
if (page.meta.sidebar.order !== undefined) {
|
|
10562
10755
|
return { order: page.meta.sidebar.order, orderIsAuthored: true };
|
|
10563
10756
|
}
|
|
10564
|
-
if (isIndexStem(
|
|
10757
|
+
if (isIndexStem(stemOf(filename))) {
|
|
10565
10758
|
return { order: Number.NEGATIVE_INFINITY, orderIsAuthored: false };
|
|
10566
10759
|
}
|
|
10567
10760
|
if (page.contentType === "changelog") {
|
|
@@ -10583,8 +10776,9 @@ var metaKey = (path, metaPrefix) => {
|
|
|
10583
10776
|
}
|
|
10584
10777
|
return path ? `${metaPrefix}/${path}` : metaPrefix;
|
|
10585
10778
|
};
|
|
10586
|
-
var applyFolderMeta = (group, folderMeta, sharedMeta, metaPrefix) => {
|
|
10587
|
-
const meta = folderMeta.get(metaKey(group.path, metaPrefix)) ?? sharedMeta.get(group.path);
|
|
10779
|
+
var applyFolderMeta = (group, folderMeta, sharedMeta, metaPrefix, sharedMetaPrefix, indexDisplay) => {
|
|
10780
|
+
const meta = folderMeta.get(metaKey(group.path, metaPrefix)) ?? sharedMeta.get(metaKey(group.path, sharedMetaPrefix));
|
|
10781
|
+
group.display = indexDisplay.get(group.path) ?? meta?.display;
|
|
10588
10782
|
if (meta) {
|
|
10589
10783
|
group.label = meta.title ?? group.label;
|
|
10590
10784
|
group.icon = meta.icon ?? group.icon;
|
|
@@ -10605,15 +10799,15 @@ var applyFolderMeta = (group, folderMeta, sharedMeta, metaPrefix) => {
|
|
|
10605
10799
|
}
|
|
10606
10800
|
for (const child of group.children) {
|
|
10607
10801
|
if (child.kind === "group") {
|
|
10608
|
-
applyFolderMeta(child, folderMeta, sharedMeta, metaPrefix);
|
|
10802
|
+
applyFolderMeta(child, folderMeta, sharedMeta, metaPrefix, sharedMetaPrefix, indexDisplay);
|
|
10609
10803
|
}
|
|
10610
10804
|
}
|
|
10611
10805
|
};
|
|
10612
|
-
var indexTitleMismatchDiagnostic = (page, folderPath, folderMeta, sharedMeta, metaPrefix) => {
|
|
10806
|
+
var indexTitleMismatchDiagnostic = (page, folderPath, folderMeta, sharedMeta, metaPrefix, sharedMetaPrefix) => {
|
|
10613
10807
|
if (!page.meta.title || page.fallback || folderPath === "") {
|
|
10614
10808
|
return;
|
|
10615
10809
|
}
|
|
10616
|
-
const meta = folderMeta.get(metaKey(folderPath, metaPrefix)) ?? sharedMeta.get(folderPath);
|
|
10810
|
+
const meta = folderMeta.get(metaKey(folderPath, metaPrefix)) ?? sharedMeta.get(metaKey(folderPath, sharedMetaPrefix));
|
|
10617
10811
|
if (!meta?.title || meta.title === page.title) {
|
|
10618
10812
|
return;
|
|
10619
10813
|
}
|
|
@@ -10625,6 +10819,46 @@ var indexTitleMismatchDiagnostic = (page, folderPath, folderMeta, sharedMeta, me
|
|
|
10625
10819
|
suggestion: `Update the page's frontmatter title to match ("${meta.title}"), or leave it if the divergence is intentional.`
|
|
10626
10820
|
};
|
|
10627
10821
|
};
|
|
10822
|
+
var sidebarDisplayIgnoredDiagnostics = (pages, explicitSidebar) => {
|
|
10823
|
+
const diagnostics = [];
|
|
10824
|
+
for (const page of pages) {
|
|
10825
|
+
if (!page.meta.sidebar.display) {
|
|
10826
|
+
continue;
|
|
10827
|
+
}
|
|
10828
|
+
const isIndex = isIndexStem(navStem(page.navPath));
|
|
10829
|
+
if (explicitSidebar) {
|
|
10830
|
+
diagnostics.push({
|
|
10831
|
+
code: "BLUME_SIDEBAR_DISPLAY_IGNORED",
|
|
10832
|
+
file: page.sourcePath ?? page.id,
|
|
10833
|
+
message: `"${page.navPath}" sets sidebar.display, but the explicit navigation.sidebar config owns each group's display mode — the value is ignored.`,
|
|
10834
|
+
severity: "warning",
|
|
10835
|
+
suggestion: "Set display on the matching group in navigation.sidebar, or remove the frontmatter key."
|
|
10836
|
+
});
|
|
10837
|
+
continue;
|
|
10838
|
+
}
|
|
10839
|
+
if (isIndex && !page.navPath.includes("/")) {
|
|
10840
|
+
diagnostics.push({
|
|
10841
|
+
code: "BLUME_SIDEBAR_DISPLAY_IGNORED",
|
|
10842
|
+
file: page.sourcePath ?? page.id,
|
|
10843
|
+
message: `"${page.navPath}" sets sidebar.display, but the content root is not a sidebar group — the value is ignored.`,
|
|
10844
|
+
severity: "warning",
|
|
10845
|
+
suggestion: "Set navigation.sidebar.display in blume.config to change the sidebar-wide mode."
|
|
10846
|
+
});
|
|
10847
|
+
continue;
|
|
10848
|
+
}
|
|
10849
|
+
if (isIndex) {
|
|
10850
|
+
continue;
|
|
10851
|
+
}
|
|
10852
|
+
diagnostics.push({
|
|
10853
|
+
code: "BLUME_SIDEBAR_DISPLAY_IGNORED",
|
|
10854
|
+
file: page.sourcePath ?? page.id,
|
|
10855
|
+
message: `"${page.navPath}" sets sidebar.display, but only a folder's index page can set its group's display mode — the value is ignored.`,
|
|
10856
|
+
severity: "warning",
|
|
10857
|
+
suggestion: "Move display to the folder's index page frontmatter, or set it in the folder's meta.ts."
|
|
10858
|
+
});
|
|
10859
|
+
}
|
|
10860
|
+
return diagnostics;
|
|
10861
|
+
};
|
|
10628
10862
|
var isAuthoredOrder = (node) => node.kind === "group" || node.orderIsAuthored;
|
|
10629
10863
|
var duplicateOrderDiagnostics = (nodes) => {
|
|
10630
10864
|
const byOrder = new Map;
|
|
@@ -10671,25 +10905,25 @@ var sortNodes = (nodes, diagnostics) => {
|
|
|
10671
10905
|
}
|
|
10672
10906
|
}
|
|
10673
10907
|
};
|
|
10674
|
-
var hoistPages = (nodes,
|
|
10675
|
-
const pages = nodes.filter((node) => node.kind === "page");
|
|
10908
|
+
var hoistPages = (nodes, display, hoist) => {
|
|
10676
10909
|
const groups = nodes.filter((node) => node.kind === "group");
|
|
10677
|
-
|
|
10678
|
-
|
|
10679
|
-
|
|
10680
|
-
|
|
10681
|
-
|
|
10910
|
+
if (hoist || groups.some((group) => (group.display ?? display) === "flat")) {
|
|
10911
|
+
const pages = nodes.filter((node) => node.kind === "page");
|
|
10912
|
+
nodes.splice(0, nodes.length, ...pages, ...groups);
|
|
10913
|
+
}
|
|
10914
|
+
for (const group of groups) {
|
|
10915
|
+
hoistPages(group.children, display, false);
|
|
10682
10916
|
}
|
|
10683
10917
|
};
|
|
10684
|
-
var hoistTabSections = (nodes, tabPaths,
|
|
10918
|
+
var hoistTabSections = (nodes, tabPaths, display) => {
|
|
10685
10919
|
for (const node of nodes) {
|
|
10686
10920
|
if (node.kind !== "group") {
|
|
10687
10921
|
continue;
|
|
10688
10922
|
}
|
|
10689
10923
|
if (node.routePath !== undefined && tabPaths.has(node.routePath)) {
|
|
10690
|
-
hoistPages(node.children,
|
|
10924
|
+
hoistPages(node.children, display, true);
|
|
10691
10925
|
}
|
|
10692
|
-
hoistTabSections(node.children, tabPaths,
|
|
10926
|
+
hoistTabSections(node.children, tabPaths, display);
|
|
10693
10927
|
}
|
|
10694
10928
|
};
|
|
10695
10929
|
var toNavNode = (node, display) => {
|
|
@@ -10708,25 +10942,29 @@ var toNavNode = (node, display) => {
|
|
|
10708
10942
|
return {
|
|
10709
10943
|
children: node.children.map((child) => toNavNode(child, display)),
|
|
10710
10944
|
collapsed: node.collapsed,
|
|
10711
|
-
display,
|
|
10945
|
+
display: node.display ?? display,
|
|
10712
10946
|
icon: node.icon,
|
|
10713
10947
|
kind: "group",
|
|
10714
10948
|
label: node.label,
|
|
10715
10949
|
path: node.routePath
|
|
10716
10950
|
};
|
|
10717
10951
|
};
|
|
10718
|
-
var buildFileSystemSidebar = (pages, folderMeta, sharedMeta, metaPrefix, display, tabPaths, diagnostics = []) => {
|
|
10952
|
+
var buildFileSystemSidebar = (pages, folderMeta, sharedMeta, metaPrefix, sharedMetaPrefix, display, tabPaths, diagnostics = []) => {
|
|
10719
10953
|
const root = createGroup("", "", "", 0);
|
|
10954
|
+
const indexDisplay = new Map;
|
|
10720
10955
|
for (const page of pages) {
|
|
10721
10956
|
const parts = page.navPath.split("/");
|
|
10722
10957
|
const filename = parts.at(-1) ?? page.navPath;
|
|
10723
|
-
const stem =
|
|
10958
|
+
const stem = stemOf(filename);
|
|
10724
10959
|
const dirs = parts.slice(0, -1);
|
|
10725
10960
|
if (isIndexStem(stem)) {
|
|
10726
|
-
const diagnostic = indexTitleMismatchDiagnostic(page, dirs.join("/"), folderMeta, sharedMeta, metaPrefix);
|
|
10961
|
+
const diagnostic = indexTitleMismatchDiagnostic(page, dirs.join("/"), folderMeta, sharedMeta, metaPrefix, sharedMetaPrefix);
|
|
10727
10962
|
if (diagnostic) {
|
|
10728
10963
|
diagnostics.push(diagnostic);
|
|
10729
10964
|
}
|
|
10965
|
+
if (page.meta.sidebar.display && !page.fallback) {
|
|
10966
|
+
indexDisplay.set(dirs.join("/"), page.meta.sidebar.display);
|
|
10967
|
+
}
|
|
10730
10968
|
}
|
|
10731
10969
|
if (page.meta.sidebar.hidden) {
|
|
10732
10970
|
continue;
|
|
@@ -10760,10 +10998,10 @@ var buildFileSystemSidebar = (pages, folderMeta, sharedMeta, metaPrefix, display
|
|
|
10760
10998
|
route: page.route
|
|
10761
10999
|
});
|
|
10762
11000
|
}
|
|
10763
|
-
applyFolderMeta(root, folderMeta, sharedMeta, metaPrefix);
|
|
11001
|
+
applyFolderMeta(root, folderMeta, sharedMeta, metaPrefix, sharedMetaPrefix, indexDisplay);
|
|
10764
11002
|
sortNodes(root.children, diagnostics);
|
|
10765
|
-
hoistPages(root.children, display
|
|
10766
|
-
hoistTabSections(root.children, tabPaths, display
|
|
11003
|
+
hoistPages(root.children, display, true);
|
|
11004
|
+
hoistTabSections(root.children, tabPaths, display);
|
|
10767
11005
|
return root.children.map((child) => toNavNode(child, display));
|
|
10768
11006
|
};
|
|
10769
11007
|
var normalizeRef = (ref) => {
|
|
@@ -10782,8 +11020,9 @@ var routeForRef = (ref, byRoute, basePath) => {
|
|
|
10782
11020
|
const normalized = normalizeRef(ref);
|
|
10783
11021
|
return byRoute.get(normalized)?.route ?? withBasePath(basePath, normalized);
|
|
10784
11022
|
};
|
|
11023
|
+
var isPageRef = (item) => typeof item === "string";
|
|
10785
11024
|
var configItemToNode = (item, byRoute, basePath) => {
|
|
10786
|
-
if (
|
|
11025
|
+
if (isPageRef(item)) {
|
|
10787
11026
|
const page = byRoute.get(normalizeRef(item));
|
|
10788
11027
|
if (!page) {
|
|
10789
11028
|
return null;
|
|
@@ -10826,7 +11065,7 @@ var configItemToNode = (item, byRoute, basePath) => {
|
|
|
10826
11065
|
var buildConfigSidebar = (items, byRoute, display, basePath) => {
|
|
10827
11066
|
const nodes = [];
|
|
10828
11067
|
for (const item of items) {
|
|
10829
|
-
if (
|
|
11068
|
+
if (!isPageRef(item) && item.items) {
|
|
10830
11069
|
nodes.push({
|
|
10831
11070
|
badge: item.badge,
|
|
10832
11071
|
children: buildConfigSidebar(item.items, byRoute, display, basePath),
|
|
@@ -10870,29 +11109,46 @@ var withTabHrefs = (tabs, sidebar) => tabs.map((tab) => {
|
|
|
10870
11109
|
const href = tab.href ?? resolveTabHref(sidebar, tab.path);
|
|
10871
11110
|
return href === tab.path ? tab : { ...tab, href };
|
|
10872
11111
|
});
|
|
11112
|
+
var rebaseNavChrome = (basePath, options) => {
|
|
11113
|
+
const featured = options.featured ?? [];
|
|
11114
|
+
const selectors = options.selectors ?? [];
|
|
11115
|
+
const tabs = options.tabs ?? [];
|
|
11116
|
+
if (!basePath) {
|
|
11117
|
+
return { featured, selectors, tabs };
|
|
11118
|
+
}
|
|
11119
|
+
const rebasePath = (item) => ({
|
|
11120
|
+
...item,
|
|
11121
|
+
path: withBasePath(basePath, item.path)
|
|
11122
|
+
});
|
|
11123
|
+
return {
|
|
11124
|
+
featured: featured.map((link) => ({
|
|
11125
|
+
...link,
|
|
11126
|
+
href: withBasePath(basePath, link.href)
|
|
11127
|
+
})),
|
|
11128
|
+
selectors: selectors.map((selector) => ({
|
|
11129
|
+
...selector,
|
|
11130
|
+
items: selector.items.map(rebasePath)
|
|
11131
|
+
})),
|
|
11132
|
+
tabs: tabs.map((tab) => {
|
|
11133
|
+
const rebased = {
|
|
11134
|
+
...tab,
|
|
11135
|
+
items: tab.items?.map(rebasePath),
|
|
11136
|
+
path: withBasePath(basePath, tab.path)
|
|
11137
|
+
};
|
|
11138
|
+
if (tab.href) {
|
|
11139
|
+
rebased.href = withBasePath(basePath, tab.href);
|
|
11140
|
+
}
|
|
11141
|
+
return rebased;
|
|
11142
|
+
})
|
|
11143
|
+
};
|
|
11144
|
+
};
|
|
10873
11145
|
var buildNavigation = (pages, options) => {
|
|
10874
11146
|
const basePath = options.basePath ?? "";
|
|
10875
11147
|
const display = options.display ?? "flat";
|
|
10876
11148
|
const metaPrefix = options.metaPrefix ?? "";
|
|
11149
|
+
const sharedMetaPrefix = options.sharedMetaPrefix ?? "";
|
|
10877
11150
|
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 ?? [];
|
|
11151
|
+
const { featured, selectors, tabs } = rebaseNavChrome(basePath, options);
|
|
10896
11152
|
const byRoute = new Map(pages.map((page) => [
|
|
10897
11153
|
options.refByLogical ? page.translationKey : page.route,
|
|
10898
11154
|
page
|
|
@@ -10906,6 +11162,8 @@ var buildNavigation = (pages, options) => {
|
|
|
10906
11162
|
}
|
|
10907
11163
|
}
|
|
10908
11164
|
const rootTabPath = withBasePath(basePath, options.localizedRoot ?? "/");
|
|
11165
|
+
const diagnostics = options.diagnostics ?? [];
|
|
11166
|
+
diagnostics.push(...sidebarDisplayIgnoredDiagnostics(pages, Boolean(options.sidebar)));
|
|
10909
11167
|
if (options.sidebar) {
|
|
10910
11168
|
const sidebar2 = buildConfigSidebar(options.sidebar, byRoute, display, basePath);
|
|
10911
11169
|
return {
|
|
@@ -10916,7 +11174,7 @@ var buildNavigation = (pages, options) => {
|
|
|
10916
11174
|
tabs: withTabHrefs(tabs, sidebar2)
|
|
10917
11175
|
};
|
|
10918
11176
|
}
|
|
10919
|
-
const sidebar = buildFileSystemSidebar(pages, options.folderMeta, sharedFolderMeta, metaPrefix, display, new Set(tabs.flatMap((tab) => tab.path === rootTabPath ? [] : [tab.path])),
|
|
11177
|
+
const sidebar = buildFileSystemSidebar(pages, options.folderMeta, sharedFolderMeta, metaPrefix, sharedMetaPrefix, display, new Set(tabs.flatMap((tab) => tab.path === rootTabPath ? [] : [tab.path])), diagnostics);
|
|
10920
11178
|
return {
|
|
10921
11179
|
featured,
|
|
10922
11180
|
root: rootTabPath,
|
|
@@ -10926,6 +11184,44 @@ var buildNavigation = (pages, options) => {
|
|
|
10926
11184
|
};
|
|
10927
11185
|
};
|
|
10928
11186
|
|
|
11187
|
+
// src/core/versions.ts
|
|
11188
|
+
var VERSION_LIKE = /^v\d/iu;
|
|
11189
|
+
var detectVersion = (parts, versions) => {
|
|
11190
|
+
const [first] = parts;
|
|
11191
|
+
if (first && versions.archived.some((version) => version.id === first)) {
|
|
11192
|
+
return { rest: parts.slice(1), version: first };
|
|
11193
|
+
}
|
|
11194
|
+
return { rest: parts, version: "" };
|
|
11195
|
+
};
|
|
11196
|
+
var detectVersionRef = (ref, versions) => {
|
|
11197
|
+
const { version, rest } = detectVersion(ref.split("/"), versions);
|
|
11198
|
+
return { rest: rest.join("/"), version };
|
|
11199
|
+
};
|
|
11200
|
+
var versionizeRoute = (logicalRoute, version) => {
|
|
11201
|
+
if (!version) {
|
|
11202
|
+
return logicalRoute;
|
|
11203
|
+
}
|
|
11204
|
+
return logicalRoute === "/" ? `/${version}` : `/${version}${logicalRoute}`;
|
|
11205
|
+
};
|
|
11206
|
+
var versionsDiagnostics = (pages, versions) => {
|
|
11207
|
+
const configured = new Set(versions.archived.map((version) => version.id));
|
|
11208
|
+
const seen = new Set;
|
|
11209
|
+
const diagnostics = [];
|
|
11210
|
+
for (const page of pages) {
|
|
11211
|
+
const [first] = page.source.ref.split("/");
|
|
11212
|
+
if (first && !seen.has(first) && VERSION_LIKE.test(first) && !configured.has(first)) {
|
|
11213
|
+
seen.add(first);
|
|
11214
|
+
diagnostics.push({
|
|
11215
|
+
code: "BLUME_VERSIONS_UNCONFIGURED_VERSION",
|
|
11216
|
+
message: `Folder "${first}/" looks like a version, but "${first}" is not in versions.archived — its pages are treated as current-version content at /${first}/….`,
|
|
11217
|
+
severity: "warning",
|
|
11218
|
+
suggestion: `Add { id: "${first}" } to versions.archived, or rename the folder if it isn't a snapshot.`
|
|
11219
|
+
});
|
|
11220
|
+
}
|
|
11221
|
+
}
|
|
11222
|
+
return diagnostics;
|
|
11223
|
+
};
|
|
11224
|
+
|
|
10929
11225
|
// src/core/graph.ts
|
|
10930
11226
|
var collectRoutes = (pages) => {
|
|
10931
11227
|
const routes = new Map;
|
|
@@ -10964,8 +11260,9 @@ var localePagesFor = (code, real, fallback, fallbackByKey, i18n, basePath) => {
|
|
|
10964
11260
|
}
|
|
10965
11261
|
return [...real, ...filled];
|
|
10966
11262
|
};
|
|
11263
|
+
var isSingleLabel = (label) => typeof label === "string";
|
|
10967
11264
|
var resolveLabel = (label, locale, defaultLocale) => {
|
|
10968
|
-
if (
|
|
11265
|
+
if (isSingleLabel(label)) {
|
|
10969
11266
|
return label;
|
|
10970
11267
|
}
|
|
10971
11268
|
return label[locale] ?? (defaultLocale === undefined ? undefined : label[defaultLocale]) ?? Object.values(label)[0] ?? "";
|
|
@@ -10978,19 +11275,25 @@ var resolveTabLabels = (tabs, locale, defaultLocale) => (tabs ?? []).map((tab) =
|
|
|
10978
11275
|
})),
|
|
10979
11276
|
label: resolveLabel(tab.label, locale, defaultLocale)
|
|
10980
11277
|
}));
|
|
10981
|
-
var buildLocaleNavigation = (code, pages, fallback, fallbackByKey, options, i18n, diagnostics) => {
|
|
11278
|
+
var buildLocaleNavigation = (code, pages, fallback, fallbackByKey, options, i18n, diagnostics, version = "") => {
|
|
10982
11279
|
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
|
-
|
|
11280
|
+
const tabs = resolveTabLabels(options.navigation.tabs, code, i18n.defaultLocale).map((tab) => {
|
|
11281
|
+
const localized = {
|
|
11282
|
+
...tab,
|
|
11283
|
+
items: tab.items?.map((item) => ({
|
|
11284
|
+
...item,
|
|
11285
|
+
path: localizePath(item.path)
|
|
11286
|
+
})),
|
|
11287
|
+
path: localizePath(tab.path)
|
|
11288
|
+
};
|
|
11289
|
+
if (localized.href) {
|
|
11290
|
+
localized.href = localizePath(localized.href);
|
|
11291
|
+
}
|
|
11292
|
+
return localized;
|
|
11293
|
+
});
|
|
10992
11294
|
const real = pages.filter((page) => page.locale === code);
|
|
10993
11295
|
const localePages = localePagesFor(code, real, fallback, fallbackByKey, i18n, options.basePath ?? "");
|
|
11296
|
+
const localeDir = i18n.parser === "dir" && code !== i18n.defaultLocale ? code : "";
|
|
10994
11297
|
return buildNavigation(localePages, {
|
|
10995
11298
|
basePath: options.basePath ?? "",
|
|
10996
11299
|
diagnostics,
|
|
@@ -11000,16 +11303,17 @@ var buildLocaleNavigation = (code, pages, fallback, fallbackByKey, options, i18n
|
|
|
11000
11303
|
href: localizePath(link.href)
|
|
11001
11304
|
})),
|
|
11002
11305
|
folderMeta: options.folderMeta,
|
|
11003
|
-
localizedRoot: localizeRoute("/", code, i18n),
|
|
11004
|
-
metaPrefix:
|
|
11306
|
+
localizedRoot: localizeRoute(versionizeRoute("/", version), code, i18n),
|
|
11307
|
+
metaPrefix: [version, localeDir].filter(Boolean).join("/"),
|
|
11005
11308
|
refByLogical: true,
|
|
11006
11309
|
selectors: options.navigation.selectors,
|
|
11007
11310
|
sharedFolderMeta: options.sharedFolderMeta,
|
|
11008
|
-
|
|
11311
|
+
sharedMetaPrefix: version,
|
|
11312
|
+
sidebar: version ? undefined : options.navigation.sidebar.items,
|
|
11009
11313
|
tabs
|
|
11010
11314
|
});
|
|
11011
11315
|
};
|
|
11012
|
-
var buildI18nNavigation = (pages, options, i18n, diagnostics) => {
|
|
11316
|
+
var buildI18nNavigation = (pages, options, i18n, diagnostics, version = "") => {
|
|
11013
11317
|
const fallback = resolveFallbackLocale(i18n);
|
|
11014
11318
|
const fallbackByKey = new Map;
|
|
11015
11319
|
if (fallback) {
|
|
@@ -11023,7 +11327,7 @@ var buildI18nNavigation = (pages, options, i18n, diagnostics) => {
|
|
|
11023
11327
|
const seen = new Set;
|
|
11024
11328
|
for (const { code } of i18n.locales) {
|
|
11025
11329
|
const localeDiagnostics = [];
|
|
11026
|
-
navigationByLocale[code] = buildLocaleNavigation(code, pages, fallback, fallbackByKey, options, i18n, localeDiagnostics);
|
|
11330
|
+
navigationByLocale[code] = buildLocaleNavigation(code, pages, fallback, fallbackByKey, options, i18n, localeDiagnostics, version);
|
|
11027
11331
|
for (const diagnostic of localeDiagnostics) {
|
|
11028
11332
|
const key = `${diagnostic.code}
|
|
11029
11333
|
${diagnostic.file ?? ""}
|
|
@@ -11042,11 +11346,37 @@ ${diagnostic.message}`;
|
|
|
11042
11346
|
};
|
|
11043
11347
|
return { navigation, navigationByLocale };
|
|
11044
11348
|
};
|
|
11349
|
+
var buildVersionNavigation = (id2, versionPages, options, diagnostics) => {
|
|
11350
|
+
const { i18n } = options;
|
|
11351
|
+
if (i18n) {
|
|
11352
|
+
return buildI18nNavigation(versionPages, options, i18n, diagnostics, id2).navigationByLocale;
|
|
11353
|
+
}
|
|
11354
|
+
return {
|
|
11355
|
+
"": buildNavigation(versionPages, {
|
|
11356
|
+
basePath: options.basePath ?? "",
|
|
11357
|
+
diagnostics,
|
|
11358
|
+
display: options.navigation.sidebar.display,
|
|
11359
|
+
featured: options.navigation.featured,
|
|
11360
|
+
folderMeta: options.folderMeta,
|
|
11361
|
+
localizedRoot: versionizeRoute("/", id2),
|
|
11362
|
+
metaPrefix: id2,
|
|
11363
|
+
selectors: options.navigation.selectors,
|
|
11364
|
+
sharedFolderMeta: options.sharedFolderMeta,
|
|
11365
|
+
sharedMetaPrefix: id2,
|
|
11366
|
+
tabs: resolveTabLabels(options.navigation.tabs, "")
|
|
11367
|
+
})
|
|
11368
|
+
};
|
|
11369
|
+
};
|
|
11045
11370
|
var buildContentGraph = (pages, options) => {
|
|
11046
11371
|
const { diagnostics, routes } = collectRoutes(pages);
|
|
11047
11372
|
const { i18n } = options;
|
|
11048
|
-
const
|
|
11049
|
-
|
|
11373
|
+
const currentPages = options.versions ? pages.filter((page) => page.version === "") : pages;
|
|
11374
|
+
let navigationByLocale = {};
|
|
11375
|
+
let navigation;
|
|
11376
|
+
if (i18n) {
|
|
11377
|
+
({ navigation, navigationByLocale } = buildI18nNavigation(currentPages, options, i18n, diagnostics));
|
|
11378
|
+
} else {
|
|
11379
|
+
navigation = buildNavigation(currentPages, {
|
|
11050
11380
|
basePath: options.basePath ?? "",
|
|
11051
11381
|
diagnostics,
|
|
11052
11382
|
display: options.navigation.sidebar.display,
|
|
@@ -11056,14 +11386,18 @@ var buildContentGraph = (pages, options) => {
|
|
|
11056
11386
|
sharedFolderMeta: options.sharedFolderMeta,
|
|
11057
11387
|
sidebar: options.navigation.sidebar.items,
|
|
11058
11388
|
tabs: resolveTabLabels(options.navigation.tabs, "")
|
|
11059
|
-
})
|
|
11060
|
-
|
|
11061
|
-
};
|
|
11062
|
-
|
|
11389
|
+
});
|
|
11390
|
+
}
|
|
11391
|
+
const navigationByVersion = {};
|
|
11392
|
+
for (const { id: id2 } of options.versions?.archived ?? []) {
|
|
11393
|
+
navigationByVersion[id2] = buildVersionNavigation(id2, pages.filter((page) => page.version === id2), options, diagnostics);
|
|
11394
|
+
}
|
|
11395
|
+
diagnostics.push(...validateNavIcons(navigation), ...validateNavStructure(navigation, currentPages));
|
|
11063
11396
|
return {
|
|
11064
11397
|
diagnostics,
|
|
11065
11398
|
navigation,
|
|
11066
11399
|
navigationByLocale,
|
|
11400
|
+
navigationByVersion,
|
|
11067
11401
|
pages,
|
|
11068
11402
|
routes
|
|
11069
11403
|
};
|
|
@@ -11126,9 +11460,20 @@ var gitLastModifiedTimes = (root, contentRoots, sourcePaths) => {
|
|
|
11126
11460
|
};
|
|
11127
11461
|
|
|
11128
11462
|
// src/core/manifest.ts
|
|
11463
|
+
var versionAlternateKey = (versionKey, locale) => `${versionKey}\x00${locale}`;
|
|
11464
|
+
var versionAlternatesFor = (byKey, versionKey, locale) => {
|
|
11465
|
+
const key = versionAlternateKey(versionKey, locale);
|
|
11466
|
+
const existing = byKey.get(key);
|
|
11467
|
+
if (existing) {
|
|
11468
|
+
return existing;
|
|
11469
|
+
}
|
|
11470
|
+
const list2 = [];
|
|
11471
|
+
byKey.set(key, list2);
|
|
11472
|
+
return list2;
|
|
11473
|
+
};
|
|
11129
11474
|
var MANIFEST_VERSION = 1;
|
|
11130
11475
|
var contentIndexable = (page, config) => !page.meta.search.exclude && (!page.meta.sidebar.hidden || config.search.indexing.includeHiddenPages);
|
|
11131
|
-
var buildFallbackRoutes = (graph, i18n, alternatesByKey, basePath) => {
|
|
11476
|
+
var buildFallbackRoutes = (graph, i18n, alternatesByKey, basePath, versionAlternatesByKey) => {
|
|
11132
11477
|
const fallback = resolveFallbackLocale(i18n);
|
|
11133
11478
|
if (!fallback) {
|
|
11134
11479
|
return [];
|
|
@@ -11144,6 +11489,11 @@ var buildFallbackRoutes = (graph, i18n, alternatesByKey, basePath) => {
|
|
|
11144
11489
|
if (present.has(key)) {
|
|
11145
11490
|
continue;
|
|
11146
11491
|
}
|
|
11492
|
+
const path = withBasePath(basePath, localizeRoute(key, code, i18n));
|
|
11493
|
+
const versionAlternates = versionAlternatesByKey ? versionAlternatesFor(versionAlternatesByKey, source.versionKey, code) : [];
|
|
11494
|
+
if (versionAlternatesByKey) {
|
|
11495
|
+
versionAlternates.push({ path, version: source.version });
|
|
11496
|
+
}
|
|
11147
11497
|
routes.push({
|
|
11148
11498
|
alternates: alternatesByKey.get(key) ?? [],
|
|
11149
11499
|
collection: source.collection ?? "docs",
|
|
@@ -11157,10 +11507,12 @@ var buildFallbackRoutes = (graph, i18n, alternatesByKey, basePath) => {
|
|
|
11157
11507
|
indexable: false,
|
|
11158
11508
|
lastModified: source.lastModified,
|
|
11159
11509
|
locale: code,
|
|
11160
|
-
path
|
|
11510
|
+
path,
|
|
11161
11511
|
source: source.source,
|
|
11162
11512
|
sourcePath: source.sourcePath,
|
|
11163
|
-
title: source.title
|
|
11513
|
+
title: source.title,
|
|
11514
|
+
version: source.version,
|
|
11515
|
+
versionAlternates
|
|
11164
11516
|
});
|
|
11165
11517
|
}
|
|
11166
11518
|
}
|
|
@@ -11178,6 +11530,12 @@ var buildManifest = (options) => {
|
|
|
11178
11530
|
alternatesByKey.set(page.translationKey, list2);
|
|
11179
11531
|
}
|
|
11180
11532
|
}
|
|
11533
|
+
const versionAlternatesByKey = config.versions ? new Map : undefined;
|
|
11534
|
+
if (versionAlternatesByKey) {
|
|
11535
|
+
for (const page of graph.pages) {
|
|
11536
|
+
versionAlternatesFor(versionAlternatesByKey, page.versionKey, page.locale).push({ path: page.route, version: page.version });
|
|
11537
|
+
}
|
|
11538
|
+
}
|
|
11181
11539
|
const routes = graph.pages.map((page) => ({
|
|
11182
11540
|
alternates: alternatesByKey.get(page.translationKey) ?? [],
|
|
11183
11541
|
collection: page.collection ?? "docs",
|
|
@@ -11193,10 +11551,18 @@ var buildManifest = (options) => {
|
|
|
11193
11551
|
path: page.route,
|
|
11194
11552
|
source: page.source,
|
|
11195
11553
|
sourcePath: page.sourcePath,
|
|
11196
|
-
title: page.title
|
|
11554
|
+
title: page.title,
|
|
11555
|
+
version: page.version,
|
|
11556
|
+
versionAlternates: versionAlternatesByKey ? versionAlternatesFor(versionAlternatesByKey, page.versionKey, page.locale) : []
|
|
11197
11557
|
}));
|
|
11198
11558
|
if (i18n) {
|
|
11199
|
-
routes.push(...buildFallbackRoutes(graph, i18n, alternatesByKey, config.basePath));
|
|
11559
|
+
routes.push(...buildFallbackRoutes(graph, i18n, alternatesByKey, config.basePath, versionAlternatesByKey));
|
|
11560
|
+
}
|
|
11561
|
+
if (versionAlternatesByKey && config.versions) {
|
|
11562
|
+
const rank = new Map(config.versions.archived.map((version, index) => [version.id, index + 1]));
|
|
11563
|
+
for (const list2 of versionAlternatesByKey.values()) {
|
|
11564
|
+
list2.sort((a, b) => (rank.get(a.version) ?? 0) - (rank.get(b.version) ?? 0));
|
|
11565
|
+
}
|
|
11200
11566
|
}
|
|
11201
11567
|
routes.sort((a, b) => a.path.localeCompare(b.path));
|
|
11202
11568
|
return {
|
|
@@ -11220,7 +11586,8 @@ var META_FILES = [
|
|
|
11220
11586
|
"**/meta.$.js",
|
|
11221
11587
|
"**/meta.$.mjs"
|
|
11222
11588
|
];
|
|
11223
|
-
var
|
|
11589
|
+
var isMetaFactory = (mod) => typeof mod === "function";
|
|
11590
|
+
var resolveMeta = async (mod) => isMetaFactory(mod) ? await mod() : mod;
|
|
11224
11591
|
var metaKeyFor = (prefix, dir) => {
|
|
11225
11592
|
const clean = prefix ? prefix.replaceAll(/^\/+|\/+$/gu, "") : "";
|
|
11226
11593
|
if (!clean) {
|
|
@@ -11229,8 +11596,9 @@ var metaKeyFor = (prefix, dir) => {
|
|
|
11229
11596
|
return dir ? `${clean}/${dir}` : clean;
|
|
11230
11597
|
};
|
|
11231
11598
|
var discoverFolderMeta = async (sources, options = {}) => {
|
|
11232
|
-
const list2 =
|
|
11599
|
+
const list2 = Array.isArray(sources) ? sources : [{ root: sources }];
|
|
11233
11600
|
const localeDirs = new Set(options.localeDirs);
|
|
11601
|
+
const versionDirs = new Set(options.versionDirs);
|
|
11234
11602
|
const load2 = createModuleLoader();
|
|
11235
11603
|
const meta = new Map;
|
|
11236
11604
|
const shared = new Map;
|
|
@@ -11259,7 +11627,12 @@ var discoverFolderMeta = async (sources, options = {}) => {
|
|
|
11259
11627
|
for (const entry of loaded) {
|
|
11260
11628
|
const dir = relative8(source.root, dirname6(entry.file));
|
|
11261
11629
|
const [head, ...tail] = dir.split("/");
|
|
11262
|
-
const
|
|
11630
|
+
const version = head && versionDirs.has(head) ? head : "";
|
|
11631
|
+
const afterVersion = version ? tail : [head ?? "", ...tail];
|
|
11632
|
+
const [localeHead, ...localeTail] = afterVersion;
|
|
11633
|
+
const locale = localeHead && localeDirs.has(localeHead) ? localeHead : "";
|
|
11634
|
+
const rest = (locale ? localeTail : afterVersion).filter(Boolean).join("/");
|
|
11635
|
+
const key = [version, locale, metaKeyFor(source.prefix, rest)].filter(Boolean).join("/");
|
|
11263
11636
|
if (!entry.ok) {
|
|
11264
11637
|
diagnostics.push({
|
|
11265
11638
|
code: "BLUME_META_LOAD_FAILED",
|
|
@@ -11331,7 +11704,7 @@ var CODE_FENCE = /^(?<delimiter>```|~~~)/u;
|
|
|
11331
11704
|
var nextFenceState = (line, fence) => {
|
|
11332
11705
|
const trimmed = line.trimStart();
|
|
11333
11706
|
const delimiter = trimmed.match(CODE_FENCE)?.groups?.delimiter;
|
|
11334
|
-
if (delimiter
|
|
11707
|
+
if (delimiter !== "```" && delimiter !== "~~~") {
|
|
11335
11708
|
return fence;
|
|
11336
11709
|
}
|
|
11337
11710
|
if (fence === null) {
|
|
@@ -11527,13 +11900,16 @@ var deriveTitle = (meta, headings, id2) => {
|
|
|
11527
11900
|
return titleCase(stripNumericPrefix(base.replace(extname2(base), "")));
|
|
11528
11901
|
};
|
|
11529
11902
|
var trimSlashes = (value) => value.replaceAll(/^\/+|\/+$/gu, "");
|
|
11903
|
+
var isStringValue = (value) => typeof value === "string";
|
|
11530
11904
|
var withPrefix = (prefix, path) => {
|
|
11531
11905
|
const clean = prefix ? trimSlashes(prefix) : "";
|
|
11532
11906
|
return clean ? `${clean}/${path}` : path;
|
|
11533
11907
|
};
|
|
11908
|
+
var isKeyCarrier = (segment) => typeof segment === "object" && segment !== null;
|
|
11909
|
+
var isSymbolKey = (key) => typeof key === "symbol";
|
|
11534
11910
|
var segmentKey2 = (segment) => {
|
|
11535
|
-
const key =
|
|
11536
|
-
return
|
|
11911
|
+
const key = isKeyCarrier(segment) ? segment.key : segment;
|
|
11912
|
+
return isSymbolKey(key) ? String(key) : key;
|
|
11537
11913
|
};
|
|
11538
11914
|
var validateCustomKeys = (data, extend) => {
|
|
11539
11915
|
const custom = {};
|
|
@@ -11564,7 +11940,7 @@ var validateCustomKeys = (data, extend) => {
|
|
|
11564
11940
|
};
|
|
11565
11941
|
};
|
|
11566
11942
|
var parseEntryMeta = (entry, ctx) => {
|
|
11567
|
-
const entryType =
|
|
11943
|
+
const entryType = isStringValue(entry.data.type) ? entry.data.type : ctx.defaultType;
|
|
11568
11944
|
const typeExtend = ctx.typeFrontmatter?.[entryType];
|
|
11569
11945
|
const extend = ctx.frontmatterExtend || typeExtend ? { ...ctx.frontmatterExtend, ...typeExtend } : undefined;
|
|
11570
11946
|
const known = extend ? Object.fromEntries(Object.entries(entry.data).filter(([key]) => !Object.hasOwn(extend, key))) : entry.data;
|
|
@@ -11600,13 +11976,16 @@ var normalizeEntry = (entry, ctx) => {
|
|
|
11600
11976
|
if (meta.noindex) {
|
|
11601
11977
|
meta.seo.noindex = true;
|
|
11602
11978
|
}
|
|
11979
|
+
const { versions } = ctx;
|
|
11980
|
+
const { version, rest: versionlessRef } = versions ? detectVersionRef(entry.ref, versions) : { rest: entry.ref, version: "" };
|
|
11603
11981
|
const { i18n } = ctx;
|
|
11604
|
-
const { navPath: rawNavPath, locales } = i18n ? localePlacement(
|
|
11982
|
+
const { navPath: rawNavPath, locales } = i18n ? localePlacement(versionlessRef, ext, i18n) : { locales: [""], navPath: versionlessRef };
|
|
11605
11983
|
const navPath = withPrefix(ctx.source.prefix, rawNavPath);
|
|
11606
11984
|
const slugInput = meta.slug ?? entry.slug;
|
|
11607
11985
|
const slug = slugInput ? trimSlashes(slugInput) : "";
|
|
11608
11986
|
const routeInput = withPrefix(ctx.source.prefix, slug ? `${slug}${ext}` : rawNavPath);
|
|
11609
|
-
const { segments, groups, route:
|
|
11987
|
+
const { segments, groups, route: versionKey } = mapRoute(routeInput);
|
|
11988
|
+
const logicalRoute = versionizeRoute(versionKey, version);
|
|
11610
11989
|
const headings = extractHeadings(entry.body.text);
|
|
11611
11990
|
const { staged } = ctx.source;
|
|
11612
11991
|
const base = {
|
|
@@ -11630,7 +12009,9 @@ var normalizeEntry = (entry, ctx) => {
|
|
|
11630
12009
|
source: { name: ctx.source.name, ref: entry.ref },
|
|
11631
12010
|
sourcePath: entry.sourcePath,
|
|
11632
12011
|
title: deriveTitle(meta, headings, navPath),
|
|
11633
|
-
translationKey: logicalRoute
|
|
12012
|
+
translationKey: logicalRoute,
|
|
12013
|
+
version,
|
|
12014
|
+
versionKey
|
|
11634
12015
|
};
|
|
11635
12016
|
const pages = locales.map((locale) => ({
|
|
11636
12017
|
...base,
|
|
@@ -11740,6 +12121,7 @@ var operationKey = (method, path, operationId) => {
|
|
|
11740
12121
|
return fromId || slugify(`${method}-${path}`);
|
|
11741
12122
|
};
|
|
11742
12123
|
var isOperation = (value) => typeof value === "object" && value !== null;
|
|
12124
|
+
var hasTagName = (tag) => typeof tag.name === "string";
|
|
11743
12125
|
var tagSlugger = () => {
|
|
11744
12126
|
const assigned = new Map;
|
|
11745
12127
|
const taken = new Set;
|
|
@@ -11758,16 +12140,45 @@ var tagSlugger = () => {
|
|
|
11758
12140
|
return slug;
|
|
11759
12141
|
};
|
|
11760
12142
|
};
|
|
11761
|
-
var
|
|
12143
|
+
var operationCollector = (baseRoute, tagMeta) => {
|
|
11762
12144
|
const operations = [];
|
|
11763
12145
|
const tagOrder = [];
|
|
11764
12146
|
const tagsSeen = new Set;
|
|
11765
|
-
const tagMeta = new Map((document.tags ?? []).map((tag) => [tag.name, tag.description ?? ""]));
|
|
11766
12147
|
const seen = new Set;
|
|
11767
|
-
const warnings = [];
|
|
11768
12148
|
const slugForTag = tagSlugger();
|
|
11769
|
-
|
|
11770
|
-
const
|
|
12149
|
+
const add2 = (entry) => {
|
|
12150
|
+
const tagSlug = slugForTag(entry.tag);
|
|
12151
|
+
if (!tagsSeen.has(entry.tag)) {
|
|
12152
|
+
tagsSeen.add(entry.tag);
|
|
12153
|
+
tagOrder.push(entry.tag);
|
|
12154
|
+
}
|
|
12155
|
+
let { key } = entry;
|
|
12156
|
+
while (seen.has(key)) {
|
|
12157
|
+
key = `${key}-${entry.method}`;
|
|
12158
|
+
}
|
|
12159
|
+
seen.add(key);
|
|
12160
|
+
operations.push({
|
|
12161
|
+
...entry,
|
|
12162
|
+
key,
|
|
12163
|
+
route: `${baseRoute === "/" ? "" : baseRoute}/${tagSlug}/${key}`,
|
|
12164
|
+
tagSlug
|
|
12165
|
+
});
|
|
12166
|
+
};
|
|
12167
|
+
const finish = () => ({
|
|
12168
|
+
operations,
|
|
12169
|
+
tags: tagOrder.map((name) => ({
|
|
12170
|
+
description: tagMeta.get(name) ?? "",
|
|
12171
|
+
name,
|
|
12172
|
+
slug: slugForTag(name)
|
|
12173
|
+
}))
|
|
12174
|
+
});
|
|
12175
|
+
return { add: add2, finish };
|
|
12176
|
+
};
|
|
12177
|
+
var extractOperations = (document, baseRoute) => {
|
|
12178
|
+
const warnings = [];
|
|
12179
|
+
const tagMeta = new Map((document.tags ?? []).filter(hasTagName).map((tag) => [tag.name, tag.description ?? ""]));
|
|
12180
|
+
const collector = operationCollector(baseRoute, tagMeta);
|
|
12181
|
+
for (const [path, item] of Object.entries(document.paths ?? {})) {
|
|
11771
12182
|
if (!item) {
|
|
11772
12183
|
continue;
|
|
11773
12184
|
}
|
|
@@ -11780,42 +12191,171 @@ var extractOperations = (document, baseRoute) => {
|
|
|
11780
12191
|
if (!isOperation(operation)) {
|
|
11781
12192
|
continue;
|
|
11782
12193
|
}
|
|
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({
|
|
12194
|
+
collector.add({
|
|
11795
12195
|
deprecated: operation.deprecated ?? false,
|
|
11796
12196
|
description: operation.description ?? "",
|
|
11797
|
-
key,
|
|
12197
|
+
key: operationKey(method, path, operation.operationId),
|
|
11798
12198
|
method,
|
|
11799
12199
|
operationId: operation.operationId,
|
|
11800
12200
|
path,
|
|
11801
|
-
route: `${baseRoute === "/" ? "" : baseRoute}/${tagSlug}/${key}`,
|
|
11802
12201
|
summary: operation.summary ?? "",
|
|
11803
|
-
tag
|
|
11804
|
-
tagSlug
|
|
12202
|
+
tag: operation.tags?.[0] ?? UNTAGGED
|
|
11805
12203
|
});
|
|
11806
12204
|
}
|
|
11807
12205
|
}
|
|
11808
|
-
|
|
11809
|
-
|
|
11810
|
-
|
|
11811
|
-
|
|
11812
|
-
|
|
11813
|
-
|
|
12206
|
+
return { ...collector.finish(), warnings };
|
|
12207
|
+
};
|
|
12208
|
+
|
|
12209
|
+
// src/openapi/asyncapi.ts
|
|
12210
|
+
var ASYNCAPI_ACTIONS = ["send", "receive"];
|
|
12211
|
+
var unescapePointer = (token) => token.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
12212
|
+
var CHANNEL_REF = /^#\/channels\/(?<id>.+)$/u;
|
|
12213
|
+
var isString3 = (value) => typeof value === "string";
|
|
12214
|
+
var channelIdOf = (channel) => {
|
|
12215
|
+
const id2 = CHANNEL_REF.exec(channel?.$ref ?? "")?.groups?.id;
|
|
12216
|
+
return id2 === undefined ? undefined : unescapePointer(id2);
|
|
12217
|
+
};
|
|
12218
|
+
var channelAddress = (channelId, channel) => {
|
|
12219
|
+
const address = channel?.address;
|
|
12220
|
+
return isString3(address) && address !== "" ? address : channelId;
|
|
12221
|
+
};
|
|
12222
|
+
var isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12223
|
+
var COMPONENT_SECTION_REF = /^#\/components\/(?<section>channels|operations)\/(?<name>[^/]+)$/u;
|
|
12224
|
+
var inlineComponentRefs = (document) => {
|
|
12225
|
+
const maps = [
|
|
12226
|
+
[document.channels, "channels"],
|
|
12227
|
+
[document.operations, "operations"]
|
|
12228
|
+
];
|
|
12229
|
+
for (const [map, section] of maps) {
|
|
12230
|
+
if (!isObject(map)) {
|
|
12231
|
+
continue;
|
|
12232
|
+
}
|
|
12233
|
+
const table = document.components?.[section];
|
|
12234
|
+
for (const [id2, entry] of Object.entries(map)) {
|
|
12235
|
+
if (!isObject(entry) || !isString3(entry.$ref)) {
|
|
12236
|
+
continue;
|
|
12237
|
+
}
|
|
12238
|
+
const groups = COMPONENT_SECTION_REF.exec(entry.$ref)?.groups;
|
|
12239
|
+
if (groups?.section !== section) {
|
|
12240
|
+
continue;
|
|
12241
|
+
}
|
|
12242
|
+
const resolved = isObject(table) ? table[unescapePointer(groups.name ?? "")] : undefined;
|
|
12243
|
+
if (isObject(resolved) && !isString3(resolved.$ref)) {
|
|
12244
|
+
map[id2] = resolved;
|
|
12245
|
+
}
|
|
12246
|
+
}
|
|
12247
|
+
}
|
|
12248
|
+
};
|
|
12249
|
+
var TRAIT_REF = /^#\/components\/(?<section>operationTraits|messageTraits)\/(?<name>[^/]+)$/u;
|
|
12250
|
+
var applyAsyncApiTraits = (document) => {
|
|
12251
|
+
const resolveTrait = (trait) => {
|
|
12252
|
+
if (!isObject(trait)) {
|
|
12253
|
+
return;
|
|
12254
|
+
}
|
|
12255
|
+
if (!isString3(trait.$ref)) {
|
|
12256
|
+
return trait;
|
|
12257
|
+
}
|
|
12258
|
+
const groups = TRAIT_REF.exec(trait.$ref)?.groups;
|
|
12259
|
+
const section = groups?.section ? document.components?.[groups.section] : undefined;
|
|
12260
|
+
const resolved = section?.[groups?.name ?? ""];
|
|
12261
|
+
return isObject(resolved) ? resolved : undefined;
|
|
12262
|
+
};
|
|
12263
|
+
const mergeTraits = (node) => {
|
|
12264
|
+
const { traits } = node;
|
|
12265
|
+
if (!Array.isArray(traits)) {
|
|
12266
|
+
return;
|
|
12267
|
+
}
|
|
12268
|
+
delete node.traits;
|
|
12269
|
+
const merged = {};
|
|
12270
|
+
for (const trait of traits) {
|
|
12271
|
+
Object.assign(merged, resolveTrait(trait));
|
|
12272
|
+
}
|
|
12273
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
12274
|
+
if (!(key in node)) {
|
|
12275
|
+
node[key] = value;
|
|
12276
|
+
}
|
|
12277
|
+
}
|
|
12278
|
+
};
|
|
12279
|
+
for (const operation of Object.values(document.operations ?? {})) {
|
|
12280
|
+
if (isObject(operation)) {
|
|
12281
|
+
mergeTraits(operation);
|
|
12282
|
+
}
|
|
12283
|
+
}
|
|
12284
|
+
const channelMaps = [
|
|
12285
|
+
...Object.values(document.channels ?? {}),
|
|
12286
|
+
...Object.values(document.components?.channels ?? {})
|
|
12287
|
+
];
|
|
12288
|
+
const messageMaps = [
|
|
12289
|
+
...channelMaps.map((channel) => isObject(channel) ? channel.messages : undefined),
|
|
12290
|
+
document.components?.messages
|
|
12291
|
+
];
|
|
12292
|
+
for (const messages of messageMaps) {
|
|
12293
|
+
if (!isObject(messages)) {
|
|
12294
|
+
continue;
|
|
12295
|
+
}
|
|
12296
|
+
for (const message of Object.values(messages)) {
|
|
12297
|
+
if (isObject(message) && !isString3(message.$ref)) {
|
|
12298
|
+
mergeTraits(message);
|
|
12299
|
+
}
|
|
12300
|
+
}
|
|
12301
|
+
}
|
|
12302
|
+
return document;
|
|
12303
|
+
};
|
|
12304
|
+
var normalizeAsyncApiDocument = (document) => {
|
|
12305
|
+
inlineComponentRefs(document);
|
|
12306
|
+
return applyAsyncApiTraits(document);
|
|
12307
|
+
};
|
|
12308
|
+
var operationSite = (id2, operation, channels) => {
|
|
12309
|
+
const action = ASYNCAPI_ACTIONS.find((a) => a === operation.action);
|
|
12310
|
+
if (!action) {
|
|
12311
|
+
return `Operation "${id2}" declares no send/receive action; it is missing from the reference.`;
|
|
12312
|
+
}
|
|
12313
|
+
const channelId = channelIdOf(operation.channel);
|
|
12314
|
+
const channel = channelId === undefined ? undefined : channels[channelId];
|
|
12315
|
+
if (channelId === undefined || !isObject(channel) || isString3(channel.$ref)) {
|
|
12316
|
+
return `Operation "${id2}" references a channel that isn't declared under "channels"; it is missing from the reference.`;
|
|
12317
|
+
}
|
|
12318
|
+
return { action, address: channelAddress(channelId, channel), channelId };
|
|
12319
|
+
};
|
|
12320
|
+
var extractAsyncApiOperations = (document, baseRoute) => {
|
|
12321
|
+
const warnings = [];
|
|
12322
|
+
const tagMeta = new Map((document.info?.tags ?? []).filter((tag) => typeof tag?.name === "string").map((tag) => [tag.name, tag.description ?? ""]));
|
|
12323
|
+
const collector = operationCollector(baseRoute, tagMeta);
|
|
12324
|
+
const channels = document.channels ?? {};
|
|
12325
|
+
for (const [id2, operation] of Object.entries(document.operations ?? {})) {
|
|
12326
|
+
if (!isObject(operation)) {
|
|
12327
|
+
continue;
|
|
12328
|
+
}
|
|
12329
|
+
if (isString3(operation.$ref)) {
|
|
12330
|
+
warnings.push(`Operation "${id2}" is a reference that doesn't resolve to a components operation; it is missing from the reference.`);
|
|
12331
|
+
continue;
|
|
12332
|
+
}
|
|
12333
|
+
const site = operationSite(id2, operation, channels);
|
|
12334
|
+
if (isString3(site)) {
|
|
12335
|
+
warnings.push(site);
|
|
12336
|
+
continue;
|
|
12337
|
+
}
|
|
12338
|
+
const { action, address, channelId } = site;
|
|
12339
|
+
const tag = operation.tags?.find((candidate) => typeof candidate?.name === "string")?.name;
|
|
12340
|
+
collector.add({
|
|
12341
|
+
channelId,
|
|
12342
|
+
deprecated: operation.deprecated === true,
|
|
12343
|
+
description: operation.description ?? "",
|
|
12344
|
+
key: operationKey(action, address, id2),
|
|
12345
|
+
method: action,
|
|
12346
|
+
operationId: id2,
|
|
12347
|
+
path: address,
|
|
12348
|
+
summary: operation.title ?? operation.summary ?? "",
|
|
12349
|
+
tag: tag ?? address
|
|
12350
|
+
});
|
|
12351
|
+
}
|
|
12352
|
+
return { ...collector.finish(), warnings };
|
|
11814
12353
|
};
|
|
11815
12354
|
|
|
11816
12355
|
// src/openapi/parse.ts
|
|
11817
12356
|
import { mkdir as mkdir4, readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
|
|
11818
12357
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
12358
|
+
import { convert } from "@asyncapi/converter";
|
|
11819
12359
|
import { normalize as normalize2, upgrade } from "@scalar/openapi-parser";
|
|
11820
12360
|
import pRetry, { AbortError } from "p-retry";
|
|
11821
12361
|
import { isAbsolute as isAbsolute3, join as join12 } from "pathe";
|
|
@@ -11969,27 +12509,74 @@ var readSpecText = async (spec, root, options) => {
|
|
|
11969
12509
|
throw error;
|
|
11970
12510
|
}
|
|
11971
12511
|
};
|
|
12512
|
+
var isApiDocument = (value) => typeof value === "object" && value !== null;
|
|
11972
12513
|
var parseSpec = async (spec, root, options = {}) => {
|
|
11973
12514
|
const { text, warnings } = await readSpecText(spec, root, options);
|
|
11974
12515
|
const normalized = normalize2(text);
|
|
11975
12516
|
const { specification } = upgrade(normalized);
|
|
11976
|
-
if (specification
|
|
12517
|
+
if (!isApiDocument(specification)) {
|
|
11977
12518
|
throw new InvalidSpecError(`${spec} is not a valid OpenAPI document (expected a YAML or JSON object).`);
|
|
11978
12519
|
}
|
|
11979
12520
|
return { document: specification, warnings };
|
|
11980
12521
|
};
|
|
12522
|
+
var isAsyncApiDocument = (value) => typeof value === "object" && value !== null && ("asyncapi" in value) && typeof value.asyncapi === "string" && value.asyncapi !== "";
|
|
12523
|
+
var parseAsyncApiSpec = async (spec, root, options = {}) => {
|
|
12524
|
+
const { text, warnings } = await readSpecText(spec, root, options);
|
|
12525
|
+
const normalized = normalize2(text);
|
|
12526
|
+
if (!isAsyncApiDocument(normalized)) {
|
|
12527
|
+
throw new InvalidSpecError(`${spec} is not a valid AsyncAPI document (expected a YAML or JSON object with an \`asyncapi\` version field).`);
|
|
12528
|
+
}
|
|
12529
|
+
const version = normalized.asyncapi;
|
|
12530
|
+
let document = normalized;
|
|
12531
|
+
if (!version.startsWith("3.")) {
|
|
12532
|
+
const captured = [];
|
|
12533
|
+
const originalWarn = console.warn;
|
|
12534
|
+
console.warn = (...args) => {
|
|
12535
|
+
captured.push(args.map(String).join(" "));
|
|
12536
|
+
};
|
|
12537
|
+
try {
|
|
12538
|
+
document = convert(document, "3.0.0");
|
|
12539
|
+
} catch (error) {
|
|
12540
|
+
throw new InvalidSpecError(`${spec} could not be converted to AsyncAPI 3.0 (${error.message}).`);
|
|
12541
|
+
} finally {
|
|
12542
|
+
console.warn = originalWarn;
|
|
12543
|
+
}
|
|
12544
|
+
warnings.push(...captured.map((message) => `Converting ${spec} to AsyncAPI 3.0: ${message}`));
|
|
12545
|
+
}
|
|
12546
|
+
return { document: normalizeAsyncApiDocument(document), warnings };
|
|
12547
|
+
};
|
|
11981
12548
|
|
|
11982
12549
|
// src/openapi/render-mdx.ts
|
|
11983
12550
|
import { fromMarkdown as fromMarkdown2 } from "mdast-util-from-markdown";
|
|
11984
12551
|
import { toString as mdastToString } from "mdast-util-to-string";
|
|
11985
|
-
|
|
11986
|
-
|
|
11987
|
-
|
|
11988
|
-
|
|
11989
|
-
|
|
12552
|
+
import stringWidth3 from "string-width";
|
|
12553
|
+
|
|
12554
|
+
// src/core/text-width.ts
|
|
12555
|
+
import stringWidth2 from "string-width";
|
|
12556
|
+
var columnsPrefix = (text, max) => {
|
|
12557
|
+
let end = 0;
|
|
12558
|
+
let used = 0;
|
|
12559
|
+
const graphemes = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
12560
|
+
for (const { index, segment } of graphemes.segment(text)) {
|
|
12561
|
+
const width = stringWidth2(segment);
|
|
12562
|
+
if (used + width > max) {
|
|
12563
|
+
break;
|
|
12564
|
+
}
|
|
12565
|
+
used += width;
|
|
12566
|
+
end = index + segment.length;
|
|
12567
|
+
}
|
|
12568
|
+
return text.slice(0, end);
|
|
11990
12569
|
};
|
|
12570
|
+
|
|
12571
|
+
// src/openapi/render-mdx.ts
|
|
12572
|
+
var MDX_UNSAFE = /[<{}]/gu;
|
|
12573
|
+
var ENTITIES = new Map([
|
|
12574
|
+
["<", "<"],
|
|
12575
|
+
["{", "{"],
|
|
12576
|
+
["}", "}"]
|
|
12577
|
+
]);
|
|
11991
12578
|
var MDX_ESM_KEYWORD = /^(?<keyword>import|export)\b/gmu;
|
|
11992
|
-
var escapeProse = (text) => text.replace(MDX_UNSAFE, (char) => ENTITIES
|
|
12579
|
+
var escapeProse = (text) => text.replace(MDX_UNSAFE, (char) => ENTITIES.get(char) ?? char).replace(MDX_ESM_KEYWORD, (keyword) => `&#${keyword.codePointAt(0)};${keyword.slice(1)}`);
|
|
11993
12580
|
var codeSpans = (text) => {
|
|
11994
12581
|
const spans = [];
|
|
11995
12582
|
const collect = (node) => {
|
|
@@ -12022,29 +12609,28 @@ var mdxSafe = (text) => {
|
|
|
12022
12609
|
return out + escapeProse(text.slice(cursor));
|
|
12023
12610
|
};
|
|
12024
12611
|
var META_DESCRIPTION_MAX = 160;
|
|
12025
|
-
var
|
|
12612
|
+
var WHITESPACE2 = /\s+/gu;
|
|
12026
12613
|
var TRAILING_WORD = /\s+\S*$/u;
|
|
12027
12614
|
var plainProse = (markdown) => {
|
|
12028
12615
|
const tree = fromMarkdown2(markdown);
|
|
12029
12616
|
const first = tree.children.find((node) => node.type === "paragraph") ?? tree.children[0];
|
|
12030
|
-
return first ? mdastToString(first).replace(
|
|
12617
|
+
return first ? mdastToString(first).replace(WHITESPACE2, " ").trim() : "";
|
|
12031
12618
|
};
|
|
12032
12619
|
var clip = (text, max) => {
|
|
12033
12620
|
if (max <= 0) {
|
|
12034
12621
|
return "";
|
|
12035
12622
|
}
|
|
12036
|
-
if (text
|
|
12623
|
+
if (stringWidth3(text) <= max) {
|
|
12037
12624
|
return text;
|
|
12038
12625
|
}
|
|
12039
|
-
const head = text
|
|
12626
|
+
const head = columnsPrefix(text, max - 1);
|
|
12040
12627
|
const onWordBoundary = head.replace(TRAILING_WORD, "");
|
|
12041
|
-
return `${onWordBoundary
|
|
12628
|
+
return `${stringWidth3(onWordBoundary) >= max / 2 ? onWordBoundary : head}…`;
|
|
12042
12629
|
};
|
|
12043
12630
|
var apiName = (spec) => spec.title || spec.label;
|
|
12044
12631
|
var operationDescription = (spec, operation) => {
|
|
12045
|
-
const
|
|
12046
|
-
const
|
|
12047
|
-
const prose = clip(plainProse(operation.description || operation.summary), META_DESCRIPTION_MAX - suffix.length - 1);
|
|
12632
|
+
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.`;
|
|
12633
|
+
const prose = clip(plainProse(operation.description || operation.summary), META_DESCRIPTION_MAX - stringWidth3(suffix) - 1);
|
|
12048
12634
|
return clip([prose, suffix].filter(Boolean).join(" "), META_DESCRIPTION_MAX);
|
|
12049
12635
|
};
|
|
12050
12636
|
var withDescription = (description, component) => description.trim() ? `${mdxSafe(description.trim())}
|
|
@@ -12054,19 +12640,29 @@ var operationMdx = (spec, operation, reference) => {
|
|
|
12054
12640
|
const method = operation.method.toUpperCase();
|
|
12055
12641
|
const title = operation.summary || `${method} ${operation.path}`;
|
|
12056
12642
|
const description = operation.description.trim() === operation.summary.trim() ? "" : operation.description;
|
|
12057
|
-
|
|
12058
|
-
|
|
12643
|
+
const flags = {};
|
|
12644
|
+
if (reference?.includeInLlms === false) {
|
|
12645
|
+
flags.ai = { exclude: true };
|
|
12646
|
+
}
|
|
12647
|
+
if (operation.deprecated) {
|
|
12648
|
+
flags.deprecated = true;
|
|
12649
|
+
}
|
|
12650
|
+
const searchFlags = {};
|
|
12651
|
+
if (reference?.includeInSearch === false) {
|
|
12652
|
+
searchFlags.exclude = true;
|
|
12653
|
+
}
|
|
12654
|
+
const seo = {
|
|
12655
|
+
description: operationDescription(spec, operation)
|
|
12656
|
+
};
|
|
12657
|
+
if (reference?.noindex) {
|
|
12658
|
+
seo.noindex = true;
|
|
12659
|
+
}
|
|
12660
|
+
return {
|
|
12661
|
+
body: withDescription(description, `<Operation source="${spec.slug}" id="${operation.key}" />`),
|
|
12059
12662
|
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
|
-
},
|
|
12663
|
+
...flags,
|
|
12664
|
+
search: { ...searchFlags, tags: [operation.tag, method] },
|
|
12665
|
+
seo,
|
|
12070
12666
|
sidebar: { badge: method, label: operation.summary || operation.path },
|
|
12071
12667
|
title,
|
|
12072
12668
|
type: "openapi-operation"
|
|
@@ -12107,6 +12703,19 @@ var overviewMdx = (spec, reference) => {
|
|
|
12107
12703
|
|
|
12108
12704
|
`));
|
|
12109
12705
|
}
|
|
12706
|
+
const flags = {};
|
|
12707
|
+
if (reference?.includeInLlms === false) {
|
|
12708
|
+
flags.ai = { exclude: true };
|
|
12709
|
+
}
|
|
12710
|
+
if (reference?.includeInSearch === false) {
|
|
12711
|
+
flags.search = { exclude: true };
|
|
12712
|
+
}
|
|
12713
|
+
const seo = {
|
|
12714
|
+
description: clip(plainProse(spec.description), META_DESCRIPTION_MAX) || `${apiName(spec)} API reference.`
|
|
12715
|
+
};
|
|
12716
|
+
if (reference?.noindex) {
|
|
12717
|
+
seo.noindex = true;
|
|
12718
|
+
}
|
|
12110
12719
|
return {
|
|
12111
12720
|
body: [
|
|
12112
12721
|
withDescription(spec.description, `<ApiOverview source="${spec.slug}" />`),
|
|
@@ -12115,12 +12724,8 @@ var overviewMdx = (spec, reference) => {
|
|
|
12115
12724
|
|
|
12116
12725
|
`),
|
|
12117
12726
|
data: {
|
|
12118
|
-
...
|
|
12119
|
-
|
|
12120
|
-
seo: {
|
|
12121
|
-
description: clip(plainProse(spec.description), META_DESCRIPTION_MAX) || `${apiName(spec)} API reference.`,
|
|
12122
|
-
...reference?.noindex ? { noindex: true } : {}
|
|
12123
|
-
},
|
|
12727
|
+
...flags,
|
|
12728
|
+
seo,
|
|
12124
12729
|
sidebar: { label: "Overview" },
|
|
12125
12730
|
title: apiName(spec)
|
|
12126
12731
|
}
|
|
@@ -12128,14 +12733,14 @@ var overviewMdx = (spec, reference) => {
|
|
|
12128
12733
|
};
|
|
12129
12734
|
|
|
12130
12735
|
// src/openapi/source.ts
|
|
12131
|
-
var isOpenApiSource = (source) => source.kind === "openapi-source";
|
|
12736
|
+
var isOpenApiSource = (source) => ("kind" in source) && source.kind === "openapi-source";
|
|
12132
12737
|
var routeToRef = (route) => route.replace(/^\/+/u, "");
|
|
12133
12738
|
var toEntry = (rendered, ref) => {
|
|
12134
12739
|
const raw = frontmatter_default.stringify(`${rendered.body}
|
|
12135
12740
|
`, rendered.data);
|
|
12136
12741
|
return {
|
|
12137
12742
|
body: { format: "mdx", text: rendered.body },
|
|
12138
|
-
data: rendered.data,
|
|
12743
|
+
data: { ...rendered.data },
|
|
12139
12744
|
hash: hashText(raw),
|
|
12140
12745
|
raw,
|
|
12141
12746
|
ref
|
|
@@ -12154,22 +12759,43 @@ var tagFolderMeta = (spec, tags) => {
|
|
|
12154
12759
|
{ title: tag.name }
|
|
12155
12760
|
]));
|
|
12156
12761
|
};
|
|
12762
|
+
var parseReference = async (reference, ctx) => {
|
|
12763
|
+
const options = { cacheDir: ctx.cacheDir, refresh: ctx.refresh };
|
|
12764
|
+
if (reference.kind === "asyncapi") {
|
|
12765
|
+
const { document: document2, warnings: warnings2 } = await parseAsyncApiSpec(reference.spec, ctx.projectRoot, options);
|
|
12766
|
+
const extracted2 = extractAsyncApiOperations(document2, reference.route);
|
|
12767
|
+
return {
|
|
12768
|
+
document: document2,
|
|
12769
|
+
extractWarnings: extracted2.warnings,
|
|
12770
|
+
operations: extracted2.operations,
|
|
12771
|
+
tags: extracted2.tags,
|
|
12772
|
+
warnings: warnings2
|
|
12773
|
+
};
|
|
12774
|
+
}
|
|
12775
|
+
const { document, warnings } = await parseSpec(reference.spec, ctx.projectRoot, options);
|
|
12776
|
+
const extracted = extractOperations(document, reference.route);
|
|
12777
|
+
return {
|
|
12778
|
+
document,
|
|
12779
|
+
extractWarnings: extracted.warnings,
|
|
12780
|
+
operations: extracted.operations,
|
|
12781
|
+
tags: extracted.tags,
|
|
12782
|
+
warnings
|
|
12783
|
+
};
|
|
12784
|
+
};
|
|
12157
12785
|
var openApiSource = (references, ctx) => {
|
|
12158
12786
|
let parsed = {};
|
|
12159
12787
|
const loadReference = async (reference) => {
|
|
12788
|
+
const kindLabel = reference.kind === "asyncapi" ? "AsyncAPI" : "OpenAPI";
|
|
12789
|
+
const codePrefix = reference.kind === "asyncapi" ? "BLUME_ASYNCAPI" : "BLUME_OPENAPI";
|
|
12160
12790
|
try {
|
|
12161
|
-
const { document, warnings } = await
|
|
12162
|
-
const {
|
|
12163
|
-
operations,
|
|
12164
|
-
tags,
|
|
12165
|
-
warnings: extractWarnings
|
|
12166
|
-
} = extractOperations(document, reference.route);
|
|
12791
|
+
const { document, warnings, operations, tags, extractWarnings } = await parseReference(reference, ctx);
|
|
12167
12792
|
const info = document.info ?? { title: reference.label, version: "" };
|
|
12168
12793
|
const spec = {
|
|
12169
12794
|
codeSamples: reference.display.codeSamples,
|
|
12170
12795
|
description: info.description ?? "",
|
|
12171
12796
|
document,
|
|
12172
12797
|
expandSchemas: reference.display.expandSchemas,
|
|
12798
|
+
kind: reference.kind,
|
|
12173
12799
|
label: reference.label,
|
|
12174
12800
|
operations: Object.fromEntries(operations.map((operation) => [
|
|
12175
12801
|
operation.key,
|
|
@@ -12187,21 +12813,21 @@ var openApiSource = (references, ctx) => {
|
|
|
12187
12813
|
return {
|
|
12188
12814
|
diagnostics: [
|
|
12189
12815
|
...warnings.map((message) => ({
|
|
12190
|
-
code: "BLUME_OPENAPI_STALE",
|
|
12816
|
+
code: reference.kind === "asyncapi" ? "BLUME_ASYNCAPI_SPEC_WARNING" : "BLUME_OPENAPI_STALE",
|
|
12191
12817
|
message,
|
|
12192
12818
|
severity: "warning"
|
|
12193
12819
|
})),
|
|
12194
12820
|
...extractWarnings.map((message) => ({
|
|
12195
|
-
code: "BLUME_OPENAPI_REF_PATH_ITEM",
|
|
12196
|
-
message: `In
|
|
12821
|
+
code: reference.kind === "asyncapi" ? "BLUME_ASYNCAPI_SKIPPED_OPERATION" : "BLUME_OPENAPI_REF_PATH_ITEM",
|
|
12822
|
+
message: `In ${kindLabel} spec "${reference.spec}": ${message}`,
|
|
12197
12823
|
severity: "warning"
|
|
12198
12824
|
})),
|
|
12199
12825
|
...operations.length === 0 ? [
|
|
12200
12826
|
{
|
|
12201
|
-
code:
|
|
12202
|
-
message:
|
|
12827
|
+
code: `${codePrefix}_EMPTY`,
|
|
12828
|
+
message: `${kindLabel} spec "${reference.spec}" for ${reference.route} declares no operations; its API reference is empty.`,
|
|
12203
12829
|
severity: "warning",
|
|
12204
|
-
suggestion: "Check the spec points at an OpenAPI document with operations under `paths`."
|
|
12830
|
+
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
12831
|
}
|
|
12206
12832
|
] : []
|
|
12207
12833
|
],
|
|
@@ -12212,10 +12838,10 @@ var openApiSource = (references, ctx) => {
|
|
|
12212
12838
|
};
|
|
12213
12839
|
} catch (error) {
|
|
12214
12840
|
return {
|
|
12215
|
-
code:
|
|
12216
|
-
message: `Could not load
|
|
12841
|
+
code: `${codePrefix}_UNAVAILABLE`,
|
|
12842
|
+
message: `Could not load ${kindLabel} spec "${reference.spec}" for ${reference.route} (${error.message}); its reference pages were skipped.`,
|
|
12217
12843
|
severity: ctx.mode === "build" ? "error" : "warning",
|
|
12218
|
-
suggestion: error instanceof InvalidSpecError ?
|
|
12844
|
+
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
12845
|
};
|
|
12220
12846
|
}
|
|
12221
12847
|
};
|
|
@@ -12320,6 +12946,7 @@ import { fromMarkdown as fromMarkdown3 } from "mdast-util-from-markdown";
|
|
|
12320
12946
|
import { gfmFromMarkdown } from "mdast-util-gfm";
|
|
12321
12947
|
import { toString as mdastToString2 } from "mdast-util-to-string";
|
|
12322
12948
|
import { gfm } from "micromark-extension-gfm";
|
|
12949
|
+
import stringWidth4 from "string-width";
|
|
12323
12950
|
var DEFAULT_BASE_URL = "https://api.github.com";
|
|
12324
12951
|
var DEFAULT_LIMIT = 100;
|
|
12325
12952
|
var PER_PAGE = 100;
|
|
@@ -12329,35 +12956,24 @@ var EDGE_DASHES = /^-+|-+$/gu;
|
|
|
12329
12956
|
var DESCRIPTION_MAX = 160;
|
|
12330
12957
|
var DESCRIPTION_MIN = 110;
|
|
12331
12958
|
var CHANGESET_HASH = /^(?<mark>\s*(?:[-*+]|\d+[.)])\s+)[0-9a-f]{7,40}:\s+/gmu;
|
|
12332
|
-
var
|
|
12959
|
+
var WHITESPACE3 = /\s+/gu;
|
|
12333
12960
|
var TRAILING_FRAGMENT = /[\s,;:.—–-]+$/u;
|
|
12334
12961
|
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
12962
|
var releaseDescription = (body) => {
|
|
12347
12963
|
const tree = fromMarkdown3(body.replaceAll(CHANGESET_HASH, "$<mark>"), {
|
|
12348
12964
|
extensions: [gfm()],
|
|
12349
12965
|
mdastExtensions: [gfmFromMarkdown()]
|
|
12350
12966
|
});
|
|
12351
|
-
const text = tree.children.filter((node) => !NON_PROSE.has(node.type)).map((node) => mdastToString2(node, { includeHtml: false, includeImageAlt: false })).join(" ").replaceAll(
|
|
12967
|
+
const text = tree.children.filter((node) => !NON_PROSE.has(node.type)).map((node) => mdastToString2(node, { includeHtml: false, includeImageAlt: false })).join(" ").replaceAll(WHITESPACE3, " ").trim();
|
|
12352
12968
|
if (!text) {
|
|
12353
12969
|
return;
|
|
12354
12970
|
}
|
|
12355
|
-
if (text
|
|
12971
|
+
if (stringWidth4(text) <= DESCRIPTION_MAX) {
|
|
12356
12972
|
return text;
|
|
12357
12973
|
}
|
|
12358
|
-
const slice =
|
|
12974
|
+
const slice = columnsPrefix(text, DESCRIPTION_MAX - 1);
|
|
12359
12975
|
const boundary = slice.lastIndexOf(" ");
|
|
12360
|
-
const head = (boundary >= DESCRIPTION_MIN ? slice.slice(0, boundary) : slice).replace(TRAILING_FRAGMENT, "");
|
|
12976
|
+
const head = (boundary !== -1 && stringWidth4(slice.slice(0, boundary)) >= DESCRIPTION_MIN ? slice.slice(0, boundary) : slice).replace(TRAILING_FRAGMENT, "");
|
|
12361
12977
|
return `${head}…`;
|
|
12362
12978
|
};
|
|
12363
12979
|
var slugifyTag = (tag) => tag.toLowerCase().replaceAll(NON_SLUG2, "-").replaceAll(EDGE_DASHES, "");
|
|
@@ -12380,18 +12996,20 @@ var releaseToEntry = (release) => {
|
|
|
12380
12996
|
const description = releaseDescription(body);
|
|
12381
12997
|
const data = {
|
|
12382
12998
|
changelog: { category, version },
|
|
12383
|
-
date
|
|
12384
|
-
...description ? { seo: { description } } : {},
|
|
12385
|
-
title,
|
|
12386
|
-
type: "changelog"
|
|
12999
|
+
date
|
|
12387
13000
|
};
|
|
13001
|
+
if (description) {
|
|
13002
|
+
data.seo = { description };
|
|
13003
|
+
}
|
|
13004
|
+
data.title = title;
|
|
13005
|
+
data.type = "changelog";
|
|
12388
13006
|
const raw = frontmatter_default.stringify(`${body}
|
|
12389
13007
|
`, data);
|
|
12390
13008
|
const fallbackRef = `release-${release.id}`;
|
|
12391
13009
|
const ref = `${slugifyTag(release.tag_name) || fallbackRef}.md`;
|
|
12392
13010
|
return {
|
|
12393
13011
|
body: { format: "md", text: body },
|
|
12394
|
-
data,
|
|
13012
|
+
data: { ...data },
|
|
12395
13013
|
editUrl: release.html_url,
|
|
12396
13014
|
hash: hashText(raw),
|
|
12397
13015
|
lastModified: date,
|
|
@@ -12688,7 +13306,12 @@ var richToMarkdown = (rich = []) => rich.map((node) => {
|
|
|
12688
13306
|
}
|
|
12689
13307
|
return node.href ? `[${text}](${node.href})` : text;
|
|
12690
13308
|
}).join("");
|
|
12691
|
-
var
|
|
13309
|
+
var isBlockPayload = (value) => typeof value === "object";
|
|
13310
|
+
var payloadOf = (block) => {
|
|
13311
|
+
const value = block[block.type];
|
|
13312
|
+
return isBlockPayload(value) ? value : undefined;
|
|
13313
|
+
};
|
|
13314
|
+
var blockField = (block) => payloadOf(block)?.rich_text ?? [];
|
|
12692
13315
|
var RATE_LIMITED = 429;
|
|
12693
13316
|
var MAX_RETRIES = 4;
|
|
12694
13317
|
var BASE_DELAY_MS = 500;
|
|
@@ -12720,7 +13343,7 @@ var LIST_BLOCKS = new Set([
|
|
|
12720
13343
|
]);
|
|
12721
13344
|
var isListItem = (block) => block !== undefined && LIST_BLOCKS.has(block.type);
|
|
12722
13345
|
var renderLeaf = (block) => {
|
|
12723
|
-
const data = block
|
|
13346
|
+
const data = payloadOf(block) ?? {};
|
|
12724
13347
|
const text = richToMarkdown(blockField(block));
|
|
12725
13348
|
switch (block.type) {
|
|
12726
13349
|
case "paragraph": {
|
|
@@ -12756,9 +13379,8 @@ ${text}
|
|
|
12756
13379
|
\`\`\``;
|
|
12757
13380
|
}
|
|
12758
13381
|
case "image": {
|
|
12759
|
-
const
|
|
12760
|
-
|
|
12761
|
-
return url ? `` : "";
|
|
13382
|
+
const url = data.external?.url ?? data.file?.url;
|
|
13383
|
+
return url ? `` : "";
|
|
12762
13384
|
}
|
|
12763
13385
|
default: {
|
|
12764
13386
|
return null;
|
|
@@ -12878,7 +13500,7 @@ ${nested}`;
|
|
|
12878
13500
|
};
|
|
12879
13501
|
const orderOf = (page) => {
|
|
12880
13502
|
const order = page.properties[props.order ?? "Order"]?.number;
|
|
12881
|
-
return
|
|
13503
|
+
return order === null ? undefined : order;
|
|
12882
13504
|
};
|
|
12883
13505
|
const frontmatter = (page) => {
|
|
12884
13506
|
const data = {};
|
|
@@ -12965,14 +13587,14 @@ ${nested}`;
|
|
|
12965
13587
|
import { join as join16 } from "pathe";
|
|
12966
13588
|
|
|
12967
13589
|
// src/core/sources/portable-text.ts
|
|
12968
|
-
var HEADING_STYLES =
|
|
12969
|
-
h1
|
|
12970
|
-
h2
|
|
12971
|
-
h3
|
|
12972
|
-
h4
|
|
12973
|
-
h5
|
|
12974
|
-
h6
|
|
12975
|
-
|
|
13590
|
+
var HEADING_STYLES = new Map([
|
|
13591
|
+
["h1", "# "],
|
|
13592
|
+
["h2", "## "],
|
|
13593
|
+
["h3", "### "],
|
|
13594
|
+
["h4", "#### "],
|
|
13595
|
+
["h5", "##### "],
|
|
13596
|
+
["h6", "###### "]
|
|
13597
|
+
]);
|
|
12976
13598
|
var MARKDOWN_SPECIALS = /[\\`*_[\]~<]/gu;
|
|
12977
13599
|
var escapeText = (text) => text.replaceAll(MARKDOWN_SPECIALS, String.raw`\$&`);
|
|
12978
13600
|
var renderSpan = (span, defs) => {
|
|
@@ -13014,6 +13636,7 @@ var renderChildren = (block) => {
|
|
|
13014
13636
|
const defs = new Map((block.markDefs ?? []).map((def) => [def._key, def]));
|
|
13015
13637
|
return (block.children ?? []).map((span) => renderSpan(span, defs)).join("");
|
|
13016
13638
|
};
|
|
13639
|
+
var isAltText = (value) => typeof value === "string";
|
|
13017
13640
|
var renderBlock = (block, options) => {
|
|
13018
13641
|
const custom = options.serializers?.[block._type];
|
|
13019
13642
|
if (custom) {
|
|
@@ -13021,7 +13644,7 @@ var renderBlock = (block, options) => {
|
|
|
13021
13644
|
}
|
|
13022
13645
|
if (block._type === "image") {
|
|
13023
13646
|
const url = options.imageUrl?.(block);
|
|
13024
|
-
const alt =
|
|
13647
|
+
const alt = isAltText(block.alt) ? block.alt : "";
|
|
13025
13648
|
return url ? `` : "";
|
|
13026
13649
|
}
|
|
13027
13650
|
if (block._type !== "block") {
|
|
@@ -13036,7 +13659,7 @@ var renderBlock = (block, options) => {
|
|
|
13036
13659
|
if (block.style === "blockquote") {
|
|
13037
13660
|
return `> ${inline}`;
|
|
13038
13661
|
}
|
|
13039
|
-
return `${HEADING_STYLES
|
|
13662
|
+
return `${HEADING_STYLES.get(block.style ?? "normal") ?? ""}${inline}`;
|
|
13040
13663
|
};
|
|
13041
13664
|
var portableTextToMarkdown = (blocks, options = {}) => {
|
|
13042
13665
|
const lines = blocks.map((block) => renderBlock(block, options));
|
|
@@ -13059,10 +13682,11 @@ var portableTextToMarkdown = (blocks, options = {}) => {
|
|
|
13059
13682
|
|
|
13060
13683
|
// src/core/sources/sanity.ts
|
|
13061
13684
|
var IMAGE_REF = /^image-(?<id>[a-f0-9]+)-(?<dims>\d+x\d+)-(?<ext>\w+)$/u;
|
|
13685
|
+
var isTraversable = (value) => typeof value === "object" && value !== null;
|
|
13062
13686
|
var getPath = (doc, path) => {
|
|
13063
13687
|
let current = doc;
|
|
13064
13688
|
for (const key of path.split(".")) {
|
|
13065
|
-
if (current
|
|
13689
|
+
if (isTraversable(current)) {
|
|
13066
13690
|
current = current[key];
|
|
13067
13691
|
} else {
|
|
13068
13692
|
return;
|
|
@@ -13070,7 +13694,8 @@ var getPath = (doc, path) => {
|
|
|
13070
13694
|
}
|
|
13071
13695
|
return current;
|
|
13072
13696
|
};
|
|
13073
|
-
var
|
|
13697
|
+
var isStringValue2 = (value) => typeof value === "string";
|
|
13698
|
+
var asString = (value) => isStringValue2(value) ? value : undefined;
|
|
13074
13699
|
var imageUrlFromRef = (ref, projectId, dataset) => {
|
|
13075
13700
|
const match = ref.match(IMAGE_REF);
|
|
13076
13701
|
if (!match?.groups) {
|
|
@@ -13129,7 +13754,7 @@ var sanitySource = (options, ctx) => {
|
|
|
13129
13754
|
const raw = frontmatter_default.stringify(markdown, data);
|
|
13130
13755
|
return {
|
|
13131
13756
|
body: { format: "md", text: markdown },
|
|
13132
|
-
data,
|
|
13757
|
+
data: { ...data },
|
|
13133
13758
|
hash: hashText(raw),
|
|
13134
13759
|
lastModified: asString(getPath(doc, fields.lastModified ?? "_updatedAt")),
|
|
13135
13760
|
raw,
|
|
@@ -13354,7 +13979,8 @@ var normalizeLoadedEntries = (loaded, config) => {
|
|
|
13354
13979
|
prefix: source.prefix,
|
|
13355
13980
|
staged: source.staged
|
|
13356
13981
|
},
|
|
13357
|
-
typeFrontmatter
|
|
13982
|
+
typeFrontmatter,
|
|
13983
|
+
versions: config.versions
|
|
13358
13984
|
});
|
|
13359
13985
|
if (normalized.pages.length === 0 && normalized.diagnostics.length > 0) {
|
|
13360
13986
|
droppedPages += 1;
|
|
@@ -13387,7 +14013,10 @@ var scanProject = async (root, options = {}) => {
|
|
|
13387
14013
|
const localeDirs = config.i18n && config.i18n.parser === "dir" ? config.i18n.locales.flatMap((locale) => locale.code === config.i18n?.defaultLocale ? [] : [locale.code]) : undefined;
|
|
13388
14014
|
const [loaded, folderMeta] = await Promise.all([
|
|
13389
14015
|
Promise.all(sources.map(async (source) => ({ source, ...await source.load() }))),
|
|
13390
|
-
discoverFolderMeta(metaSources, {
|
|
14016
|
+
discoverFolderMeta(metaSources, {
|
|
14017
|
+
localeDirs,
|
|
14018
|
+
versionDirs: config.versions?.archived.map((version) => version.id)
|
|
14019
|
+
})
|
|
13391
14020
|
]);
|
|
13392
14021
|
const sharedFolderMeta = new Map([
|
|
13393
14022
|
...loaded.flatMap(({ folderMeta: sourceMeta }) => Object.entries(sourceMeta ?? {})),
|
|
@@ -13415,10 +14044,12 @@ var scanProject = async (root, options = {}) => {
|
|
|
13415
14044
|
folderMeta: folderMeta.meta,
|
|
13416
14045
|
i18n: config.i18n,
|
|
13417
14046
|
navigation: config.navigation,
|
|
13418
|
-
sharedFolderMeta
|
|
14047
|
+
sharedFolderMeta,
|
|
14048
|
+
versions: config.versions
|
|
13419
14049
|
});
|
|
13420
14050
|
const manifest = buildManifest({ config, context, graph });
|
|
13421
|
-
const i18nWarnings = config.i18n ? i18nDiagnostics(pages, config.i18n) : [];
|
|
14051
|
+
const i18nWarnings = config.i18n ? i18nDiagnostics(pages, config.i18n, config.versions) : [];
|
|
14052
|
+
const versionWarnings = config.versions ? versionsDiagnostics(pages, config.versions) : [];
|
|
13422
14053
|
return {
|
|
13423
14054
|
config,
|
|
13424
14055
|
context,
|
|
@@ -13427,7 +14058,8 @@ var scanProject = async (root, options = {}) => {
|
|
|
13427
14058
|
...folderMeta.diagnostics,
|
|
13428
14059
|
...entryIdDiagnostics(pages, resolveDocsCollection(config, context).base),
|
|
13429
14060
|
...graph.diagnostics,
|
|
13430
|
-
...i18nWarnings
|
|
14061
|
+
...i18nWarnings,
|
|
14062
|
+
...versionWarnings
|
|
13431
14063
|
],
|
|
13432
14064
|
droppedPages,
|
|
13433
14065
|
graph,
|
|
@@ -13547,9 +14179,10 @@ var auditCommand = defineCommand2({
|
|
|
13547
14179
|
return;
|
|
13548
14180
|
}
|
|
13549
14181
|
const root = process.cwd();
|
|
13550
|
-
const
|
|
13551
|
-
|
|
13552
|
-
|
|
14182
|
+
const gateInput = args["fail-on"] ?? (args.strict ? "warning" : "error");
|
|
14183
|
+
const gate = SEVERITIES.find((severity) => severity === gateInput);
|
|
14184
|
+
if (gate === undefined) {
|
|
14185
|
+
logger.error(`Invalid --fail-on "${gateInput}" (use ${SEVERITIES.join(" | ")}).`);
|
|
13553
14186
|
process.exit(1);
|
|
13554
14187
|
}
|
|
13555
14188
|
const agents = Object.keys(AGENTS).filter((kind) => args[kind]);
|
|
@@ -13748,12 +14381,8 @@ var buildAgentReadability = (project) => {
|
|
|
13748
14381
|
return site ? absoluteUrl(site, based) : based;
|
|
13749
14382
|
};
|
|
13750
14383
|
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
|
-
};
|
|
14384
|
+
const markdown = negotiates ? { contentNegotiation: "text/markdown", pattern: abs("/{route}.md") } : { pattern: abs("/{route}.md") };
|
|
14385
|
+
const artifacts = { markdown };
|
|
13757
14386
|
if (config.ai.llmsTxt.enabled) {
|
|
13758
14387
|
artifacts.llmsFullTxt = abs("/llms-full.txt");
|
|
13759
14388
|
artifacts.llmsTxt = abs("/llms.txt");
|
|
@@ -13934,6 +14563,8 @@ var parseYouTubeId = (input) => {
|
|
|
13934
14563
|
};
|
|
13935
14564
|
|
|
13936
14565
|
// src/ai/component-markdown.ts
|
|
14566
|
+
var isString4 = (value) => typeof value === "string";
|
|
14567
|
+
var isNumber = (value) => typeof value === "number";
|
|
13937
14568
|
var evaluateExpression = (raw, frontmatter) => {
|
|
13938
14569
|
try {
|
|
13939
14570
|
const value = new Function("frontmatter", `"use strict"; return (${raw});`)(frontmatter);
|
|
@@ -13952,7 +14583,7 @@ var readProps = (node, frontmatter) => {
|
|
|
13952
14583
|
}
|
|
13953
14584
|
if (attribute.value === null || attribute.value === undefined) {
|
|
13954
14585
|
props[attribute.name] = true;
|
|
13955
|
-
} else if (
|
|
14586
|
+
} else if (isString4(attribute.value)) {
|
|
13956
14587
|
props[attribute.name] = attribute.value;
|
|
13957
14588
|
} else {
|
|
13958
14589
|
const result = evaluateExpression(attribute.value.value, frontmatter);
|
|
@@ -14003,9 +14634,10 @@ var cellCode = (value) => {
|
|
|
14003
14634
|
const text = cellText(value);
|
|
14004
14635
|
return text && !text.includes("`") ? `\`${text}\`` : text;
|
|
14005
14636
|
};
|
|
14637
|
+
var isTypeEntryMap = (value) => typeof value === "object" && value !== null;
|
|
14006
14638
|
var typeTable = ({ children, props }) => {
|
|
14007
14639
|
const { type } = props;
|
|
14008
|
-
if (type
|
|
14640
|
+
if (!isTypeEntryMap(type)) {
|
|
14009
14641
|
return null;
|
|
14010
14642
|
}
|
|
14011
14643
|
const entries = Object.entries(type);
|
|
@@ -14013,7 +14645,7 @@ var typeTable = ({ children, props }) => {
|
|
|
14013
14645
|
const prop = cellCode(`${name}${info.required ? "" : "?"}`);
|
|
14014
14646
|
const typeCell = info.typeDescriptionLink ? `[${cellCode(info.type)}](${cellText(info.typeDescriptionLink)})` : cellCode(info.type);
|
|
14015
14647
|
const defaultCell = info.default === undefined ? "-" : cellCode(info.default);
|
|
14016
|
-
const description = cellText([info.description, info.typeDescription].filter((part) =>
|
|
14648
|
+
const description = cellText([info.description, info.typeDescription].filter((part) => isString4(part) && part !== "").join(" "));
|
|
14017
14649
|
return [prop, typeCell, defaultCell, description];
|
|
14018
14650
|
});
|
|
14019
14651
|
const table = rows.length > 0 ? markdownTable([["Prop", "Type", "Default", "Description"], ...rows], {
|
|
@@ -14024,8 +14656,8 @@ var typeTable = ({ children, props }) => {
|
|
|
14024
14656
|
`);
|
|
14025
14657
|
};
|
|
14026
14658
|
var callout = ({ children, props }) => {
|
|
14027
|
-
const type =
|
|
14028
|
-
const label =
|
|
14659
|
+
const type = isString4(props.type) ? props.type : "info";
|
|
14660
|
+
const label = isString4(props.title) && props.title !== "" ? props.title : type.charAt(0).toUpperCase() + type.slice(1);
|
|
14029
14661
|
if (!children) {
|
|
14030
14662
|
return `> **${label}**`;
|
|
14031
14663
|
}
|
|
@@ -14053,7 +14685,7 @@ var steps = ({ childComponents, children }) => {
|
|
|
14053
14685
|
return children;
|
|
14054
14686
|
}
|
|
14055
14687
|
return items.map((step, index) => {
|
|
14056
|
-
const title =
|
|
14688
|
+
const title = isString4(step.props.title) && step.props.title !== "" ? `**${step.props.title}**` : "";
|
|
14057
14689
|
const content = [title, step.children].filter(Boolean).join(`
|
|
14058
14690
|
|
|
14059
14691
|
`);
|
|
@@ -14068,7 +14700,7 @@ var tabs = ({ childComponents, children }) => {
|
|
|
14068
14700
|
return children;
|
|
14069
14701
|
}
|
|
14070
14702
|
return items.map((tab, index) => {
|
|
14071
|
-
const title =
|
|
14703
|
+
const title = isString4(tab.props.title) && tab.props.title !== "" ? tab.props.title : `Tab ${index + 1}`;
|
|
14072
14704
|
return tab.children ? `**${title}**
|
|
14073
14705
|
|
|
14074
14706
|
${tab.children}` : `**${title}**`;
|
|
@@ -14078,17 +14710,17 @@ ${tab.children}` : `**${title}**`;
|
|
|
14078
14710
|
};
|
|
14079
14711
|
var youtube = ({ props }) => {
|
|
14080
14712
|
let input = "";
|
|
14081
|
-
if (
|
|
14713
|
+
if (isString4(props.id)) {
|
|
14082
14714
|
input = props.id;
|
|
14083
|
-
} else if (
|
|
14715
|
+
} else if (isString4(props.url)) {
|
|
14084
14716
|
input = props.url;
|
|
14085
14717
|
}
|
|
14086
14718
|
const videoId = parseYouTubeId(input);
|
|
14087
14719
|
if (!videoId) {
|
|
14088
14720
|
return null;
|
|
14089
14721
|
}
|
|
14090
|
-
const start =
|
|
14091
|
-
const title =
|
|
14722
|
+
const start = isNumber(props.start) && props.start > 0 ? `&t=${Math.floor(props.start)}s` : "";
|
|
14723
|
+
const title = isString4(props.title) && props.title !== "" ? props.title : "Watch on YouTube";
|
|
14092
14724
|
return `[${title}](https://www.youtube.com/watch?v=${videoId}${start})`;
|
|
14093
14725
|
};
|
|
14094
14726
|
var fencedBlock = (lang, code) => {
|
|
@@ -14102,7 +14734,7 @@ ${fence}`;
|
|
|
14102
14734
|
};
|
|
14103
14735
|
var exampleComponentSerializers = (examples) => ({
|
|
14104
14736
|
Component: ({ props }) => {
|
|
14105
|
-
const path =
|
|
14737
|
+
const path = isString4(props.path) ? props.path : undefined;
|
|
14106
14738
|
const example = path === undefined ? undefined : examples[path];
|
|
14107
14739
|
return example ? fencedBlock(example.lang, example.source) : null;
|
|
14108
14740
|
}
|
|
@@ -14212,19 +14844,28 @@ var pageUrl = (route, site, base = "") => {
|
|
|
14212
14844
|
const path = withBasePath(base, route);
|
|
14213
14845
|
return encodeURI(site ? absoluteUrl(site, path) : path);
|
|
14214
14846
|
};
|
|
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"));
|
|
14847
|
+
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
14848
|
var indexedNavigations = (project) => {
|
|
14217
|
-
const { i18n } = project.config;
|
|
14218
|
-
|
|
14219
|
-
|
|
14220
|
-
|
|
14221
|
-
|
|
14222
|
-
|
|
14223
|
-
|
|
14224
|
-
|
|
14849
|
+
const { i18n, versions } = project.config;
|
|
14850
|
+
const current = i18n ? i18n.locales.flatMap(({ code, label }) => {
|
|
14851
|
+
const nav = project.graph.navigationByLocale[code];
|
|
14852
|
+
if (!nav) {
|
|
14853
|
+
return [];
|
|
14854
|
+
}
|
|
14855
|
+
return [
|
|
14856
|
+
{ label: code === i18n.defaultLocale ? undefined : label, nav }
|
|
14857
|
+
];
|
|
14858
|
+
}) : [{ nav: project.graph.navigation }];
|
|
14859
|
+
const archived = (versions?.archived ?? []).flatMap((version) => {
|
|
14860
|
+
const byLocale = project.graph.navigationByVersion[version.id] ?? {};
|
|
14861
|
+
const versionLabel = `${version.label ?? version.id} (archived)`;
|
|
14862
|
+
return Object.entries(byLocale).flatMap(([code, nav]) => {
|
|
14863
|
+
const locale = i18n?.locales.find((entry) => entry.code === code);
|
|
14864
|
+
const label = locale && code !== i18n?.defaultLocale ? `${locale.label} — ${versionLabel}` : versionLabel;
|
|
14865
|
+
return [{ label, nav }];
|
|
14225
14866
|
});
|
|
14226
|
-
}
|
|
14227
|
-
return [
|
|
14867
|
+
});
|
|
14868
|
+
return [...current, ...archived];
|
|
14228
14869
|
};
|
|
14229
14870
|
var buildLlmsIndex = (project) => {
|
|
14230
14871
|
const { config } = project;
|
|
@@ -14301,7 +14942,7 @@ var buildLlmsIndex = (project) => {
|
|
|
14301
14942
|
};
|
|
14302
14943
|
var buildFull = async (project) => {
|
|
14303
14944
|
const { config } = project;
|
|
14304
|
-
const pages = eligiblePages(project).toSorted((a, b) => a.route.localeCompare(b.route));
|
|
14945
|
+
const pages = eligiblePages(project, { versions: "current" }).toSorted((a, b) => a.route.localeCompare(b.route));
|
|
14305
14946
|
const components = {
|
|
14306
14947
|
...exampleComponentSerializers(project.examples ?? {}),
|
|
14307
14948
|
...config.ai.markdownComponents
|
|
@@ -14446,6 +15087,7 @@ var collectEntries = async (dir, prefix = "") => {
|
|
|
14446
15087
|
}
|
|
14447
15088
|
return entries;
|
|
14448
15089
|
};
|
|
15090
|
+
var isString5 = (value) => typeof value === "string";
|
|
14449
15091
|
var skillMeta = (raw, dirName) => {
|
|
14450
15092
|
let data;
|
|
14451
15093
|
try {
|
|
@@ -14456,8 +15098,8 @@ var skillMeta = (raw, dirName) => {
|
|
|
14456
15098
|
warning: `Skill "${dirName}" has unparsable SKILL.md frontmatter; skipped.`
|
|
14457
15099
|
};
|
|
14458
15100
|
}
|
|
14459
|
-
const name =
|
|
14460
|
-
const description =
|
|
15101
|
+
const name = isString5(data.name) ? data.name : "";
|
|
15102
|
+
const description = isString5(data.description) ? data.description : "";
|
|
14461
15103
|
if (!(name && description)) {
|
|
14462
15104
|
return {
|
|
14463
15105
|
meta: null,
|
|
@@ -14582,6 +15224,8 @@ var MAX_RULES = 100;
|
|
|
14582
15224
|
var MAX_RULE_LENGTH = 100;
|
|
14583
15225
|
var FALLBACK_RULES = ["/*", "!/_astro/*", "!/*.md", "!/*.mdx", "!/*.txt"];
|
|
14584
15226
|
var basePrefix = (base) => base && base !== "/" ? base.replace(/\/$/u, "") : "";
|
|
15227
|
+
var isJsonObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15228
|
+
var isJsonString = (value) => typeof value === "string";
|
|
14585
15229
|
var isNegativeRule = (rule) => rule.startsWith("!");
|
|
14586
15230
|
var ruleBody = (rule) => isNegativeRule(rule) ? rule.slice(1) : rule;
|
|
14587
15231
|
var buildRunWorkerFirstRules = (routePaths, base) => {
|
|
@@ -14836,15 +15480,15 @@ var injectWorkerNegotiation = (wranglerText, options) => {
|
|
|
14836
15480
|
} catch {
|
|
14837
15481
|
return null;
|
|
14838
15482
|
}
|
|
14839
|
-
if (
|
|
15483
|
+
if (!isJsonObject(config)) {
|
|
14840
15484
|
return null;
|
|
14841
15485
|
}
|
|
14842
15486
|
const { main } = config;
|
|
14843
|
-
if (
|
|
15487
|
+
if (!isJsonString(main) || main.length === 0 || main === NEGOTIATION_WORKER_FILE) {
|
|
14844
15488
|
return null;
|
|
14845
15489
|
}
|
|
14846
|
-
const assets = config
|
|
14847
|
-
if (assets
|
|
15490
|
+
const { assets } = config;
|
|
15491
|
+
if (!isJsonObject(assets) || !isJsonString(assets.binding)) {
|
|
14848
15492
|
return null;
|
|
14849
15493
|
}
|
|
14850
15494
|
const {
|
|
@@ -15059,6 +15703,16 @@ var buildSitemapFiles = (project) => {
|
|
|
15059
15703
|
}
|
|
15060
15704
|
const base = siteRoot(site);
|
|
15061
15705
|
const deployBase = normalizeBasePath(project.config.deployment.base);
|
|
15706
|
+
const { versions } = project.config;
|
|
15707
|
+
const archivedById = new Map((versions?.archived ?? []).map((version) => [version.id, version]));
|
|
15708
|
+
const currentKeys = versions ? new Set(project.graph.pages.flatMap((page) => page.version === "" ? [`${page.versionKey}\x00${page.locale}`] : [])) : null;
|
|
15709
|
+
const archivedExcluded = (page) => {
|
|
15710
|
+
if (!page.version) {
|
|
15711
|
+
return false;
|
|
15712
|
+
}
|
|
15713
|
+
const archived = archivedById.get(page.version);
|
|
15714
|
+
return Boolean(archived?.noindex || archived?.canonical === "latest" && currentKeys?.has(`${page.versionKey}\x00${page.locale}`));
|
|
15715
|
+
};
|
|
15062
15716
|
const seen = new Set;
|
|
15063
15717
|
const urls = [];
|
|
15064
15718
|
const pushUrl = (route, lastModified) => {
|
|
@@ -15070,7 +15724,7 @@ var buildSitemapFiles = (project) => {
|
|
|
15070
15724
|
urls.push(` <url><loc>${loc}</loc>${lastmodTag(lastModified)}</url>`);
|
|
15071
15725
|
};
|
|
15072
15726
|
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)) {
|
|
15727
|
+
if (page.meta.draft || page.meta.sidebar.hidden || page.meta.seo.noindex || ERROR_ROUTES3.has(page.route) || archivedExcluded(page)) {
|
|
15074
15728
|
continue;
|
|
15075
15729
|
}
|
|
15076
15730
|
pushUrl(withBasePath(deployBase, page.route), page.lastModified);
|
|
@@ -15109,6 +15763,7 @@ ${references.join(`
|
|
|
15109
15763
|
|
|
15110
15764
|
// src/deploy/vercel-negotiation.ts
|
|
15111
15765
|
var ACCEPT_MARKDOWN_HEADER_VALUE = "(.*,)?\\s*text/(x-)?markdown(\\s*[;,].*)?$";
|
|
15766
|
+
var isString6 = (value) => typeof value === "string";
|
|
15112
15767
|
var ACCEPT_MARKDOWN_CONDITION = [
|
|
15113
15768
|
{ key: "accept", type: "header", value: ACCEPT_MARKDOWN_HEADER_VALUE }
|
|
15114
15769
|
];
|
|
@@ -15163,7 +15818,7 @@ var buildNegotiationRoutes = (routePaths, homeTokens) => {
|
|
|
15163
15818
|
return { headerRoutes, rewriteRoutes };
|
|
15164
15819
|
};
|
|
15165
15820
|
var HOME_SRC = "^/$";
|
|
15166
|
-
var isNegotiationRoute = (route) => route.has?.some((condition) => condition.value === ACCEPT_MARKDOWN_HEADER_VALUE) === true || route.continue === true && route.headers?.vary === "Accept" &&
|
|
15821
|
+
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;
|
|
15167
15822
|
var injectNegotiationRoutes = (configText, routePaths, homeLinkHeader, contentTypeOverrides, homeTokens) => {
|
|
15168
15823
|
const overrideEntries = Object.entries(contentTypeOverrides ?? {});
|
|
15169
15824
|
if (routePaths.length === 0 && !homeLinkHeader && overrideEntries.length === 0) {
|
|
@@ -15220,6 +15875,7 @@ import { gfmFromMarkdown as gfmFromMarkdown2 } from "mdast-util-gfm";
|
|
|
15220
15875
|
import { gfm as gfm2 } from "micromark-extension-gfm";
|
|
15221
15876
|
|
|
15222
15877
|
// src/search/facets.ts
|
|
15878
|
+
var isFacetValue = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
15223
15879
|
var pageFacets = (page, config) => {
|
|
15224
15880
|
const declared = config.content.types[page.contentType]?.facets;
|
|
15225
15881
|
if (!declared || declared.length === 0 || !page.custom) {
|
|
@@ -15228,7 +15884,7 @@ var pageFacets = (page, config) => {
|
|
|
15228
15884
|
const facets = {};
|
|
15229
15885
|
for (const key of declared) {
|
|
15230
15886
|
const value = page.custom[key];
|
|
15231
|
-
if (
|
|
15887
|
+
if (isFacetValue(value)) {
|
|
15232
15888
|
facets[key] = String(value);
|
|
15233
15889
|
}
|
|
15234
15890
|
}
|
|
@@ -15237,7 +15893,7 @@ var pageFacets = (page, config) => {
|
|
|
15237
15893
|
|
|
15238
15894
|
// src/search/documents.ts
|
|
15239
15895
|
var HTML_OR_JSX = /<\/?[a-zA-Z][^\n<>]*>|<\/?>/gu;
|
|
15240
|
-
var
|
|
15896
|
+
var WHITESPACE4 = /\s+/gu;
|
|
15241
15897
|
var INLINE_PARENTS = new Set([
|
|
15242
15898
|
"delete",
|
|
15243
15899
|
"emphasis",
|
|
@@ -15289,7 +15945,7 @@ var toPlainText = (markdown) => {
|
|
|
15289
15945
|
});
|
|
15290
15946
|
const out = [];
|
|
15291
15947
|
collectText(tree, out);
|
|
15292
|
-
return out.join("").replaceAll(
|
|
15948
|
+
return out.join("").replaceAll(WHITESPACE4, " ").trim();
|
|
15293
15949
|
};
|
|
15294
15950
|
var buildCrumbIndex = (sidebar) => {
|
|
15295
15951
|
const index = new Map;
|
|
@@ -15323,7 +15979,11 @@ var buildCrumbIndex = (sidebar) => {
|
|
|
15323
15979
|
var buildSearchDocuments = async (project, options) => {
|
|
15324
15980
|
const pageById = new Map(project.graph.pages.map((page) => [page.id, page]));
|
|
15325
15981
|
const byLocale = Object.values(project.graph.navigationByLocale ?? {});
|
|
15326
|
-
const
|
|
15982
|
+
const byVersion = Object.values(project.graph.navigationByVersion ?? {}).flatMap((locales) => Object.values(locales)).map((nav) => nav.sidebar);
|
|
15983
|
+
const sidebars = [
|
|
15984
|
+
...byLocale.length > 0 ? byLocale.map((nav) => nav.sidebar) : [project.graph.navigation?.sidebar ?? []],
|
|
15985
|
+
...byVersion
|
|
15986
|
+
];
|
|
15327
15987
|
const crumbs = new Map;
|
|
15328
15988
|
for (const sidebar of sidebars) {
|
|
15329
15989
|
for (const [route, crumb] of buildCrumbIndex(sidebar)) {
|
|
@@ -15346,18 +16006,22 @@ var buildSearchDocuments = async (project, options) => {
|
|
|
15346
16006
|
const tags = page?.meta?.search?.tags;
|
|
15347
16007
|
const crumb = crumbs.get(route.path);
|
|
15348
16008
|
const facets = page ? pageFacets(page, project.config) : undefined;
|
|
15349
|
-
|
|
16009
|
+
const document = {
|
|
15350
16010
|
breadcrumb: crumb?.breadcrumb ?? [],
|
|
15351
16011
|
content: body,
|
|
15352
16012
|
contentType: route.contentType,
|
|
15353
16013
|
description: page?.description ?? "",
|
|
15354
|
-
...facets ? { facets } : {},
|
|
15355
16014
|
locale: route.locale,
|
|
15356
16015
|
route: route.path,
|
|
15357
16016
|
section: crumb?.section || "Docs",
|
|
15358
16017
|
tags: tags && tags.length > 0 ? tags : undefined,
|
|
15359
|
-
title: route.title
|
|
16018
|
+
title: route.title,
|
|
16019
|
+
version: route.version
|
|
15360
16020
|
};
|
|
16021
|
+
if (facets) {
|
|
16022
|
+
document.facets = facets;
|
|
16023
|
+
}
|
|
16024
|
+
return document;
|
|
15361
16025
|
}));
|
|
15362
16026
|
};
|
|
15363
16027
|
var toSearchRecords = (documents) => documents.map((doc) => ({
|
|
@@ -15367,7 +16031,8 @@ var toSearchRecords = (documents) => documents.map((doc) => ({
|
|
|
15367
16031
|
locale: doc.locale,
|
|
15368
16032
|
tag: doc.tags?.[0],
|
|
15369
16033
|
title: doc.title,
|
|
15370
|
-
url: doc.route
|
|
16034
|
+
url: doc.route,
|
|
16035
|
+
version: doc.version || "current"
|
|
15371
16036
|
}));
|
|
15372
16037
|
|
|
15373
16038
|
// src/search/sync/algolia.ts
|
|
@@ -15451,7 +16116,8 @@ var syncTypesense = async (records, config) => {
|
|
|
15451
16116
|
{ name: "content", type: "string" },
|
|
15452
16117
|
{ name: "url", type: "string" },
|
|
15453
16118
|
{ facet: true, name: "tag", optional: true, type: "string" },
|
|
15454
|
-
{ facet: true, name: "locale", optional: true, type: "string" }
|
|
16119
|
+
{ facet: true, name: "locale", optional: true, type: "string" },
|
|
16120
|
+
{ facet: true, name: "version", optional: true, type: "string" }
|
|
15455
16121
|
],
|
|
15456
16122
|
name: config.collection
|
|
15457
16123
|
});
|
|
@@ -15462,7 +16128,8 @@ var syncTypesense = async (records, config) => {
|
|
|
15462
16128
|
locale: record.locale,
|
|
15463
16129
|
tag: record.tag,
|
|
15464
16130
|
title: record.title,
|
|
15465
|
-
url: record.url
|
|
16131
|
+
url: record.url,
|
|
16132
|
+
version: record.version
|
|
15466
16133
|
}));
|
|
15467
16134
|
await client.collections(config.collection).documents().import(documents, { action: "upsert" });
|
|
15468
16135
|
};
|
|
@@ -15500,6 +16167,8 @@ import {
|
|
|
15500
16167
|
import { join as join21 } from "pathe";
|
|
15501
16168
|
var lockPath = (outDir) => join21(outDir, "dev.lock");
|
|
15502
16169
|
var isValidPid = (pid) => typeof pid === "number" && Number.isInteger(pid) && pid > 0;
|
|
16170
|
+
var isPortNumber = (port) => typeof port === "number";
|
|
16171
|
+
var isLockRecord = (data) => typeof data === "object" && data !== null;
|
|
15503
16172
|
var parseLock = (raw) => {
|
|
15504
16173
|
let data;
|
|
15505
16174
|
try {
|
|
@@ -15510,10 +16179,10 @@ var parseLock = (raw) => {
|
|
|
15510
16179
|
if (isValidPid(data)) {
|
|
15511
16180
|
return { pid: data };
|
|
15512
16181
|
}
|
|
15513
|
-
if (
|
|
16182
|
+
if (isLockRecord(data)) {
|
|
15514
16183
|
const { pid, port } = data;
|
|
15515
16184
|
if (isValidPid(pid)) {
|
|
15516
|
-
return
|
|
16185
|
+
return isPortNumber(port) ? { pid, port } : { pid };
|
|
15517
16186
|
}
|
|
15518
16187
|
}
|
|
15519
16188
|
return null;
|
|
@@ -15534,10 +16203,13 @@ var readDevLock = (outDir) => {
|
|
|
15534
16203
|
const lock = parseLock(readFileSync5(path, "utf-8"));
|
|
15535
16204
|
return lock && isProcessAlive(lock.pid) ? lock : null;
|
|
15536
16205
|
};
|
|
15537
|
-
var lockPayload = (port) =>
|
|
15538
|
-
pid: process.pid
|
|
15539
|
-
|
|
15540
|
-
|
|
16206
|
+
var lockPayload = (port) => {
|
|
16207
|
+
const info = { pid: process.pid };
|
|
16208
|
+
if (port !== undefined) {
|
|
16209
|
+
info.port = port;
|
|
16210
|
+
}
|
|
16211
|
+
return JSON.stringify(info);
|
|
16212
|
+
};
|
|
15541
16213
|
var writeLock = (outDir, port) => {
|
|
15542
16214
|
writeFileSync(lockPath(outDir), lockPayload(port));
|
|
15543
16215
|
};
|
|
@@ -15669,27 +16341,39 @@ var buildMcpData = async (project) => {
|
|
|
15669
16341
|
}
|
|
15670
16342
|
const page = pageById.get(route.id);
|
|
15671
16343
|
const facets = page ? pageFacets(page, config) : undefined;
|
|
15672
|
-
|
|
16344
|
+
const entry = {
|
|
15673
16345
|
contentType: route.contentType,
|
|
15674
16346
|
description: page?.description,
|
|
15675
|
-
...facets ? { facets } : {},
|
|
15676
16347
|
indexable: route.indexable,
|
|
15677
16348
|
lastModified: route.lastModified ?? null,
|
|
16349
|
+
locale: route.locale,
|
|
15678
16350
|
route: route.path,
|
|
15679
|
-
title: route.title
|
|
15680
|
-
|
|
16351
|
+
title: route.title,
|
|
16352
|
+
version: route.version
|
|
16353
|
+
};
|
|
16354
|
+
if (facets) {
|
|
16355
|
+
entry.facets = facets;
|
|
16356
|
+
}
|
|
16357
|
+
routes.push(entry);
|
|
15681
16358
|
}
|
|
15682
|
-
|
|
16359
|
+
const data = {
|
|
15683
16360
|
base: normalizeBasePath(config.deployment.base),
|
|
15684
16361
|
defaultLocale: config.i18n?.defaultLocale,
|
|
15685
|
-
documents: documents.map((doc) =>
|
|
15686
|
-
|
|
15687
|
-
|
|
15688
|
-
|
|
15689
|
-
|
|
15690
|
-
|
|
15691
|
-
|
|
15692
|
-
|
|
16362
|
+
documents: documents.map((doc) => {
|
|
16363
|
+
const document = {
|
|
16364
|
+
content: doc.content,
|
|
16365
|
+
contentType: doc.contentType,
|
|
16366
|
+
description: doc.description,
|
|
16367
|
+
locale: doc.locale,
|
|
16368
|
+
route: doc.route,
|
|
16369
|
+
title: doc.title,
|
|
16370
|
+
version: doc.version
|
|
16371
|
+
};
|
|
16372
|
+
if (doc.facets) {
|
|
16373
|
+
document.facets = doc.facets;
|
|
16374
|
+
}
|
|
16375
|
+
return document;
|
|
16376
|
+
}),
|
|
15693
16377
|
instructions: config.ai.mcp.instructions,
|
|
15694
16378
|
name: config.ai.mcp.name ?? config.title,
|
|
15695
16379
|
navigation: graph.navigation,
|
|
@@ -15698,6 +16382,14 @@ var buildMcpData = async (project) => {
|
|
|
15698
16382
|
site: config.deployment.site ?? null,
|
|
15699
16383
|
version: manifest.blumeVersion
|
|
15700
16384
|
};
|
|
16385
|
+
if (config.versions) {
|
|
16386
|
+
data.archivedVersions = config.versions.archived.map((version) => version.id);
|
|
16387
|
+
data.navigationByVersion = graph.navigationByVersion;
|
|
16388
|
+
}
|
|
16389
|
+
if (config.i18n) {
|
|
16390
|
+
data.navigationByLocale = graph.navigationByLocale;
|
|
16391
|
+
}
|
|
16392
|
+
return data;
|
|
15701
16393
|
};
|
|
15702
16394
|
|
|
15703
16395
|
// src/ai/mcp/tools.ts
|
|
@@ -15705,7 +16397,7 @@ var READ_ONLY = { openWorldHint: false, readOnlyHint: true };
|
|
|
15705
16397
|
var MCP_TOOLS = [
|
|
15706
16398
|
{
|
|
15707
16399
|
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`),
|
|
16400
|
+
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
16401
|
name: "search_docs",
|
|
15710
16402
|
title: "Search documentation"
|
|
15711
16403
|
},
|
|
@@ -15717,13 +16409,13 @@ var MCP_TOOLS = [
|
|
|
15717
16409
|
},
|
|
15718
16410
|
{
|
|
15719
16411
|
annotations: READ_ONLY,
|
|
15720
|
-
description:
|
|
16412
|
+
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
16413
|
name: "list_pages",
|
|
15722
16414
|
title: "List pages"
|
|
15723
16415
|
},
|
|
15724
16416
|
{
|
|
15725
16417
|
annotations: READ_ONLY,
|
|
15726
|
-
description: "Return the documentation navigation tree (header tabs and the sidebar hierarchy), reflecting how the docs are organized for readers.",
|
|
16418
|
+
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
16419
|
name: "get_navigation",
|
|
15728
16420
|
title: "Get navigation"
|
|
15729
16421
|
}
|
|
@@ -15761,12 +16453,11 @@ var reverseDnsName = (input) => {
|
|
|
15761
16453
|
var HTTP_URL2 = /^https?:\/\//u;
|
|
15762
16454
|
var buildMcpServerCard = (input) => {
|
|
15763
16455
|
const url = serverUrl(input);
|
|
15764
|
-
|
|
16456
|
+
const card = {
|
|
15765
16457
|
$schema: SERVER_CARD_SCHEMA,
|
|
15766
16458
|
capabilities: { tools: { listChanged: false } },
|
|
15767
16459
|
description: truncate(`Model Context Protocol server for the ${input.name} documentation.`),
|
|
15768
16460
|
name: reverseDnsName(input),
|
|
15769
|
-
...HTTP_URL2.test(url) ? { remotes: [{ type: "streamable-http", url }] } : {},
|
|
15770
16461
|
serverInfo: { name: input.name, version: input.version },
|
|
15771
16462
|
title: truncate(input.name),
|
|
15772
16463
|
tools: MCP_TOOLS.map((tool) => ({
|
|
@@ -15778,9 +16469,15 @@ var buildMcpServerCard = (input) => {
|
|
|
15778
16469
|
transport: "streamable-http",
|
|
15779
16470
|
transports: [{ endpoint: url, type: "streamable-http" }],
|
|
15780
16471
|
url,
|
|
15781
|
-
version: input.version
|
|
15782
|
-
...input.site ? { websiteUrl: siteRoot(input.site) } : {}
|
|
16472
|
+
version: input.version
|
|
15783
16473
|
};
|
|
16474
|
+
if (HTTP_URL2.test(url)) {
|
|
16475
|
+
card.remotes = [{ type: "streamable-http", url }];
|
|
16476
|
+
}
|
|
16477
|
+
if (input.site) {
|
|
16478
|
+
card.websiteUrl = siteRoot(input.site);
|
|
16479
|
+
}
|
|
16480
|
+
return card;
|
|
15784
16481
|
};
|
|
15785
16482
|
|
|
15786
16483
|
// src/core/builtin-tags.ts
|
|
@@ -15853,12 +16550,13 @@ import { dirname as dirname8, extname as extname7, isAbsolute as isAbsolute6, re
|
|
|
15853
16550
|
import ts from "typescript";
|
|
15854
16551
|
var GROUPS = ["mdx", "layout", "islands"];
|
|
15855
16552
|
var GROUP_SET = new Set(GROUPS);
|
|
15856
|
-
var
|
|
15857
|
-
|
|
15858
|
-
|
|
15859
|
-
|
|
15860
|
-
|
|
15861
|
-
|
|
16553
|
+
var isGroup = (name) => GROUP_SET.has(name);
|
|
16554
|
+
var FRAMEWORK_BY_EXT = new Map([
|
|
16555
|
+
["jsx", "react"],
|
|
16556
|
+
["svelte", "svelte"],
|
|
16557
|
+
["tsx", "react"],
|
|
16558
|
+
["vue", "vue"]
|
|
16559
|
+
]);
|
|
15862
16560
|
var FRAMEWORK_LABEL = {
|
|
15863
16561
|
react: "React",
|
|
15864
16562
|
svelte: "Svelte",
|
|
@@ -15881,6 +16579,7 @@ var HYDRATION_MODES = new Set([
|
|
|
15881
16579
|
"only",
|
|
15882
16580
|
"visible"
|
|
15883
16581
|
]);
|
|
16582
|
+
var isHydrationMode = (value) => HYDRATION_MODES.has(value);
|
|
15884
16583
|
var emptyAnalysis = () => ({
|
|
15885
16584
|
islands: [],
|
|
15886
16585
|
layout: [],
|
|
@@ -15962,7 +16661,7 @@ var toImport = (specifier, imported, dir) => {
|
|
|
15962
16661
|
}
|
|
15963
16662
|
}
|
|
15964
16663
|
return {
|
|
15965
|
-
framework: FRAMEWORK_BY_EXT
|
|
16664
|
+
framework: FRAMEWORK_BY_EXT.get(extension) ?? null,
|
|
15966
16665
|
name: imported,
|
|
15967
16666
|
path
|
|
15968
16667
|
};
|
|
@@ -15991,7 +16690,7 @@ var applyDescriptorProperty = (descriptor, property, imports, dir) => {
|
|
|
15991
16690
|
} else if (ts.isIdentifier(init)) {
|
|
15992
16691
|
descriptor.source = resolveIdentifier(init.text, imports, dir);
|
|
15993
16692
|
}
|
|
15994
|
-
} else if (name === "client" && ts.isStringLiteral(init) &&
|
|
16693
|
+
} else if (name === "client" && ts.isStringLiteral(init) && isHydrationMode(init.text)) {
|
|
15995
16694
|
descriptor.client = init.text;
|
|
15996
16695
|
} else if (name === "media" && ts.isStringLiteral(init)) {
|
|
15997
16696
|
descriptor.media = init.text;
|
|
@@ -16025,13 +16724,14 @@ var finalize = (key, group, descriptor, label, identifier, warnings) => {
|
|
|
16025
16724
|
if (!client && source?.framework) {
|
|
16026
16725
|
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
16726
|
}
|
|
16028
|
-
|
|
16029
|
-
|
|
16030
|
-
|
|
16031
|
-
|
|
16032
|
-
|
|
16033
|
-
|
|
16034
|
-
}
|
|
16727
|
+
const normalized = { identifier, key, source };
|
|
16728
|
+
if (client) {
|
|
16729
|
+
normalized.client = client;
|
|
16730
|
+
}
|
|
16731
|
+
if (media) {
|
|
16732
|
+
normalized.media = media;
|
|
16733
|
+
}
|
|
16734
|
+
return normalized;
|
|
16035
16735
|
};
|
|
16036
16736
|
var normalizeEntry2 = (entry, group, imports, dir, warnings) => {
|
|
16037
16737
|
const defaultClient = group === "islands" ? "visible" : undefined;
|
|
@@ -16084,14 +16784,13 @@ var collectGroupOverrides = (property, imports, dir, result) => {
|
|
|
16084
16784
|
return;
|
|
16085
16785
|
}
|
|
16086
16786
|
const name = propName(property.name);
|
|
16087
|
-
if (!(name &&
|
|
16787
|
+
if (!(name && isGroup(name)) || !ts.isObjectLiteralExpression(property.initializer)) {
|
|
16088
16788
|
return;
|
|
16089
16789
|
}
|
|
16090
|
-
const group = name;
|
|
16091
16790
|
for (const entry of property.initializer.properties) {
|
|
16092
|
-
const normalized = normalizeEntry2(entry,
|
|
16791
|
+
const normalized = normalizeEntry2(entry, name, imports, dir, result.warnings);
|
|
16093
16792
|
if (normalized) {
|
|
16094
|
-
result[
|
|
16793
|
+
result[name].push(normalized);
|
|
16095
16794
|
}
|
|
16096
16795
|
}
|
|
16097
16796
|
};
|
|
@@ -16125,9 +16824,10 @@ import { parseTsconfig } from "get-tsconfig";
|
|
|
16125
16824
|
import { dirname as dirname10, join as join22, resolve as resolve7 } from "pathe";
|
|
16126
16825
|
var CONFIG_DIR_TEMPLATE = "${configDir}";
|
|
16127
16826
|
var substituteConfigDir = (value, configDir) => value.startsWith(CONFIG_DIR_TEMPLATE) ? join22(configDir, value.slice(CONFIG_DIR_TEMPLATE.length)) : value;
|
|
16827
|
+
var isPathTarget = (target) => typeof target === "string";
|
|
16128
16828
|
var toAlias = (key, value, baseDir, configDir) => {
|
|
16129
16829
|
const first = Array.isArray(value) ? value[0] : value;
|
|
16130
|
-
if (
|
|
16830
|
+
if (!isPathTarget(first)) {
|
|
16131
16831
|
return null;
|
|
16132
16832
|
}
|
|
16133
16833
|
const find = key.endsWith("/*") ? key.slice(0, -2) : key;
|
|
@@ -16157,14 +16857,14 @@ var resolveTsconfigAliases = (root) => {
|
|
|
16157
16857
|
}
|
|
16158
16858
|
const configDir = dirname10(entry);
|
|
16159
16859
|
const baseDir = resolve7(configDir, substituteConfigDir(options?.baseUrl ?? ".", configDir));
|
|
16160
|
-
const
|
|
16860
|
+
const entries = [];
|
|
16161
16861
|
for (const [key, value] of Object.entries(paths)) {
|
|
16162
16862
|
const alias = toAlias(key, value, baseDir, configDir);
|
|
16163
16863
|
if (alias) {
|
|
16164
|
-
|
|
16864
|
+
entries.push([alias.find, alias.replacement]);
|
|
16165
16865
|
}
|
|
16166
16866
|
}
|
|
16167
|
-
return
|
|
16867
|
+
return Object.fromEntries(entries);
|
|
16168
16868
|
};
|
|
16169
16869
|
|
|
16170
16870
|
// src/og/derive.ts
|
|
@@ -16172,8 +16872,12 @@ import { existsSync as existsSync14 } from "node:fs";
|
|
|
16172
16872
|
import { isAbsolute as isAbsolute7, join as join23 } from "pathe";
|
|
16173
16873
|
var CARD_WEIGHTS = [400, 600];
|
|
16174
16874
|
var absoluteSrc = (root, src) => isAbsolute7(src) ? src : join23(root, src);
|
|
16875
|
+
var isNumericWeight = (weight) => typeof weight === "number";
|
|
16876
|
+
var isRangeWeight = (weight) => typeof weight === "string";
|
|
16877
|
+
var isFontName = (value) => typeof value === "string";
|
|
16878
|
+
var isLocalOgFont = (font) => typeof font !== "string" && ("src" in font);
|
|
16175
16879
|
var googleWeights = (weights) => {
|
|
16176
|
-
const numbers = weights.filter(
|
|
16880
|
+
const numbers = weights.filter(isNumericWeight);
|
|
16177
16881
|
const used = numbers.filter((weight) => CARD_WEIGHTS.includes(weight));
|
|
16178
16882
|
if (used.length > 0) {
|
|
16179
16883
|
return used;
|
|
@@ -16182,20 +16886,22 @@ var googleWeights = (weights) => {
|
|
|
16182
16886
|
return numbers;
|
|
16183
16887
|
}
|
|
16184
16888
|
const [first] = weights;
|
|
16185
|
-
return weights.length === 1 &&
|
|
16889
|
+
return weights.length === 1 && isRangeWeight(first) ? first : undefined;
|
|
16186
16890
|
};
|
|
16187
16891
|
var googleOgFont = (name, weights) => {
|
|
16188
16892
|
const weight = googleWeights(weights);
|
|
16189
16893
|
return weight === undefined ? { name } : { name, weight };
|
|
16190
16894
|
};
|
|
16191
|
-
var localOgFonts = (font, root) => font.variants.map((variant) =>
|
|
16192
|
-
|
|
16193
|
-
|
|
16194
|
-
|
|
16195
|
-
|
|
16196
|
-
}
|
|
16895
|
+
var localOgFonts = (font, root) => font.variants.map((variant) => {
|
|
16896
|
+
const entry = {
|
|
16897
|
+
name: font.name,
|
|
16898
|
+
src: absoluteSrc(root, variant.src)
|
|
16899
|
+
};
|
|
16900
|
+
const withWeight = isNumericWeight(variant.weight) ? { ...entry, weight: variant.weight } : entry;
|
|
16901
|
+
return variant.style === "normal" || variant.style === "italic" ? { ...withWeight, style: variant.style } : withWeight;
|
|
16902
|
+
});
|
|
16197
16903
|
var roleFonts = (value, root) => {
|
|
16198
|
-
if (
|
|
16904
|
+
if (isFontName(value)) {
|
|
16199
16905
|
if (!isFontSlug(value)) {
|
|
16200
16906
|
return null;
|
|
16201
16907
|
}
|
|
@@ -16205,14 +16911,13 @@ var roleFonts = (value, root) => {
|
|
|
16205
16911
|
if ("variants" in value) {
|
|
16206
16912
|
return localOgFonts(value, root);
|
|
16207
16913
|
}
|
|
16208
|
-
|
|
16209
|
-
if ((remote.provider ?? "google") !== "google") {
|
|
16914
|
+
if ((value.provider ?? "google") !== "google") {
|
|
16210
16915
|
return null;
|
|
16211
16916
|
}
|
|
16212
|
-
return [googleOgFont(
|
|
16917
|
+
return [googleOgFont(value.name, value.weights ?? CARD_WEIGHTS)];
|
|
16213
16918
|
};
|
|
16214
16919
|
var roleFamily = (value) => {
|
|
16215
|
-
if (
|
|
16920
|
+
if (isFontName(value)) {
|
|
16216
16921
|
return isFontSlug(value) ? GOOGLE_FONTS[value].family : null;
|
|
16217
16922
|
}
|
|
16218
16923
|
return value.name;
|
|
@@ -16242,12 +16947,13 @@ var deriveOgFonts = (fonts, root) => {
|
|
|
16242
16947
|
}
|
|
16243
16948
|
}
|
|
16244
16949
|
}
|
|
16245
|
-
|
|
16246
|
-
|
|
16247
|
-
|
|
16248
|
-
}
|
|
16950
|
+
const result = { fonts: derived };
|
|
16951
|
+
if (families.title || families.body) {
|
|
16952
|
+
result.families = families;
|
|
16953
|
+
}
|
|
16954
|
+
return result;
|
|
16249
16955
|
};
|
|
16250
|
-
var resolveOgFontSources = (fonts, root) => fonts.map((font) =>
|
|
16956
|
+
var resolveOgFontSources = (fonts, root) => fonts.map((font) => isLocalOgFont(font) ? { ...font, src: absoluteSrc(root, font.src) } : font);
|
|
16251
16957
|
var resolveOgFonts = (options, root) => {
|
|
16252
16958
|
if (options.ogFonts) {
|
|
16253
16959
|
return { fonts: resolveOgFontSources(options.ogFonts, root) };
|
|
@@ -16257,12 +16963,12 @@ var resolveOgFonts = (options, root) => {
|
|
|
16257
16963
|
var missingFontFiles = (options, root) => {
|
|
16258
16964
|
const sources = [];
|
|
16259
16965
|
for (const value of Object.values(options.themeFonts ?? {})) {
|
|
16260
|
-
if (
|
|
16966
|
+
if (!isFontName(value) && "variants" in value) {
|
|
16261
16967
|
sources.push(...value.variants.map((variant) => absoluteSrc(root, variant.src)));
|
|
16262
16968
|
}
|
|
16263
16969
|
}
|
|
16264
16970
|
for (const font of options.ogFonts) {
|
|
16265
|
-
if (
|
|
16971
|
+
if (isLocalOgFont(font)) {
|
|
16266
16972
|
sources.push(absoluteSrc(root, font.src));
|
|
16267
16973
|
}
|
|
16268
16974
|
}
|
|
@@ -16299,9 +17005,10 @@ var ACCENTS = {
|
|
|
16299
17005
|
red: "oklch(0.58 0.22 25)",
|
|
16300
17006
|
teal: "oklch(0.6 0.12 195)"
|
|
16301
17007
|
};
|
|
17008
|
+
var isAccentPreset = (value) => Object.hasOwn(ACCENTS, value);
|
|
16302
17009
|
var CSS_COLOR = /^[\w\s#%.,()/+-]+$/u;
|
|
16303
17010
|
var safeColor = (value, fallback) => CSS_COLOR.test(value.trim()) ? value.trim() : fallback;
|
|
16304
|
-
var presetOrColor = (value) =>
|
|
17011
|
+
var presetOrColor = (value) => isAccentPreset(value) ? ACCENTS[value] : safeColor(value, FALLBACK_ACCENT);
|
|
16305
17012
|
var safeColorOrNull = (value) => value && CSS_COLOR.test(value.trim()) ? value.trim() : null;
|
|
16306
17013
|
var RADII = {
|
|
16307
17014
|
lg: "0.75rem",
|
|
@@ -16457,11 +17164,16 @@ var buildReferenceFiles = async (options) => {
|
|
|
16457
17164
|
};
|
|
16458
17165
|
|
|
16459
17166
|
// src/search/popular.ts
|
|
16460
|
-
var resolveSearchPopular = (popular, basePath) => popular.map(({ href, icon, label }) =>
|
|
16461
|
-
|
|
16462
|
-
|
|
16463
|
-
|
|
16464
|
-
}
|
|
17167
|
+
var resolveSearchPopular = (popular, basePath) => popular.map(({ href, icon, label }) => {
|
|
17168
|
+
const page = {
|
|
17169
|
+
label,
|
|
17170
|
+
route: withBasePath(basePath, href)
|
|
17171
|
+
};
|
|
17172
|
+
if (icon) {
|
|
17173
|
+
page.icon = icon;
|
|
17174
|
+
}
|
|
17175
|
+
return page;
|
|
17176
|
+
});
|
|
16465
17177
|
|
|
16466
17178
|
// src/theme/entry.ts
|
|
16467
17179
|
var DARK_VARIANT = `/* Dark mode is driven by data-theme on the <html> element. */
|
|
@@ -17423,12 +18135,13 @@ var VALID_MODES = new Set([
|
|
|
17423
18135
|
"only",
|
|
17424
18136
|
"visible"
|
|
17425
18137
|
]);
|
|
17426
|
-
var
|
|
17427
|
-
|
|
17428
|
-
|
|
17429
|
-
|
|
17430
|
-
|
|
17431
|
-
|
|
18138
|
+
var isClientMode = (mode) => VALID_MODES.has(mode);
|
|
18139
|
+
var FRAMEWORK_BY_EXT2 = new Map([
|
|
18140
|
+
["jsx", "react"],
|
|
18141
|
+
["svelte", "svelte"],
|
|
18142
|
+
["tsx", "react"],
|
|
18143
|
+
["vue", "vue"]
|
|
18144
|
+
]);
|
|
17432
18145
|
var ISLAND_FILE = /\.(?<ext>jsx|svelte|tsx|vue)$/u;
|
|
17433
18146
|
var CLIENT_EXPORT = /export\s+const\s+client\s*(?::[^=]+)?=\s*["'](?<mode>\w+)["']/u;
|
|
17434
18147
|
var readClientMode = (source, file, warnings) => {
|
|
@@ -17436,7 +18149,7 @@ var readClientMode = (source, file, warnings) => {
|
|
|
17436
18149
|
if (!mode) {
|
|
17437
18150
|
return DEFAULT_CLIENT;
|
|
17438
18151
|
}
|
|
17439
|
-
if (!
|
|
18152
|
+
if (!isClientMode(mode)) {
|
|
17440
18153
|
warnings.push(`Island "${file}" declares an unknown client mode "${mode}"; defaulting to "${DEFAULT_CLIENT}". Use "load", "idle", "visible", or "only".`);
|
|
17441
18154
|
return DEFAULT_CLIENT;
|
|
17442
18155
|
}
|
|
@@ -17459,7 +18172,7 @@ var discoverIslands = async (root) => {
|
|
|
17459
18172
|
const collectIsland = (file, source) => {
|
|
17460
18173
|
const base = basename2(file);
|
|
17461
18174
|
const ext = base.match(ISLAND_FILE)?.groups?.ext;
|
|
17462
|
-
const framework = ext ? FRAMEWORK_BY_EXT2
|
|
18175
|
+
const framework = ext ? FRAMEWORK_BY_EXT2.get(ext) : undefined;
|
|
17463
18176
|
if (!framework) {
|
|
17464
18177
|
return;
|
|
17465
18178
|
}
|
|
@@ -17691,18 +18404,18 @@ var ensureDepsLink = async (outDir, pkgDir = packageRoot()) => {
|
|
|
17691
18404
|
}
|
|
17692
18405
|
return astroConflictWarning(blumeAstro, outDirHit?.pkg ?? null);
|
|
17693
18406
|
};
|
|
17694
|
-
var ISLAND_FRAMEWORK_DEPS =
|
|
17695
|
-
svelte
|
|
17696
|
-
vue
|
|
17697
|
-
|
|
17698
|
-
var DEPLOYMENT_ADAPTER_DEPS =
|
|
17699
|
-
cloudflare
|
|
17700
|
-
netlify
|
|
17701
|
-
|
|
18407
|
+
var ISLAND_FRAMEWORK_DEPS = new Map([
|
|
18408
|
+
["svelte", "@astrojs/svelte"],
|
|
18409
|
+
["vue", "@astrojs/vue"]
|
|
18410
|
+
]);
|
|
18411
|
+
var DEPLOYMENT_ADAPTER_DEPS = new Map([
|
|
18412
|
+
["cloudflare", "@astrojs/cloudflare"],
|
|
18413
|
+
["netlify", "@astrojs/netlify"]
|
|
18414
|
+
]);
|
|
17702
18415
|
var islandFrameworkWarnings = (frameworks, root) => {
|
|
17703
18416
|
const warnings = [];
|
|
17704
18417
|
for (const framework of frameworks) {
|
|
17705
|
-
const dep = ISLAND_FRAMEWORK_DEPS
|
|
18418
|
+
const dep = ISLAND_FRAMEWORK_DEPS.get(framework);
|
|
17706
18419
|
if (dep && !canResolveFrom(root, dep)) {
|
|
17707
18420
|
warnings.push(`Islands use ${framework}, which needs "${dep}". Install it (e.g. \`npm install ${dep} ${framework}\`).`);
|
|
17708
18421
|
}
|
|
@@ -17710,7 +18423,7 @@ var islandFrameworkWarnings = (frameworks, root) => {
|
|
|
17710
18423
|
return warnings;
|
|
17711
18424
|
};
|
|
17712
18425
|
var deploymentAdapterWarnings = (deployment, root) => {
|
|
17713
|
-
const dep = deployment.output === "server" && deployment.adapter ? DEPLOYMENT_ADAPTER_DEPS
|
|
18426
|
+
const dep = deployment.output === "server" && deployment.adapter ? DEPLOYMENT_ADAPTER_DEPS.get(deployment.adapter) : undefined;
|
|
17714
18427
|
if (dep && !(canResolveFrom(root, dep) || canResolveFrom(packageRoot(), dep))) {
|
|
17715
18428
|
return [
|
|
17716
18429
|
`Deployment adapter "${deployment.adapter}" needs "${dep}", which isn't installed. Run \`npm install ${dep}\` (or your package manager's equivalent).`
|
|
@@ -17862,14 +18575,15 @@ var readLogoSvg = (project, source) => {
|
|
|
17862
18575
|
].find((path) => existsSync16(path));
|
|
17863
18576
|
return file ? readFileSync8(file, "utf-8") : undefined;
|
|
17864
18577
|
};
|
|
18578
|
+
var isStringShorthand = (value) => typeof value === "string";
|
|
17865
18579
|
var resolveLogo = (project) => {
|
|
17866
18580
|
const { logo } = project.config;
|
|
17867
18581
|
if (!logo) {
|
|
17868
18582
|
return null;
|
|
17869
18583
|
}
|
|
17870
|
-
const config =
|
|
18584
|
+
const config = isStringShorthand(logo) ? { image: logo } : logo;
|
|
17871
18585
|
const { href, image: source, text } = config;
|
|
17872
|
-
const image =
|
|
18586
|
+
const image = isStringShorthand(source) ? { light: source } : source;
|
|
17873
18587
|
const light = image?.light ?? image?.dark;
|
|
17874
18588
|
const dark = image?.dark ?? image?.light;
|
|
17875
18589
|
const alt = image?.alt ?? "";
|
|
@@ -17892,16 +18606,16 @@ var FAVICON_CANDIDATES = [
|
|
|
17892
18606
|
"favicon.ico",
|
|
17893
18607
|
"icon.ico"
|
|
17894
18608
|
];
|
|
17895
|
-
var FAVICON_TYPES =
|
|
17896
|
-
ico
|
|
17897
|
-
jpeg
|
|
17898
|
-
jpg
|
|
17899
|
-
png
|
|
17900
|
-
svg
|
|
17901
|
-
|
|
18609
|
+
var FAVICON_TYPES = new Map([
|
|
18610
|
+
["ico", "image/x-icon"],
|
|
18611
|
+
["jpeg", "image/jpeg"],
|
|
18612
|
+
["jpg", "image/jpeg"],
|
|
18613
|
+
["png", "image/png"],
|
|
18614
|
+
["svg", "image/svg+xml"]
|
|
18615
|
+
]);
|
|
17902
18616
|
var faviconType = (name) => {
|
|
17903
18617
|
const ext = name.split(".").pop()?.toLowerCase();
|
|
17904
|
-
return ext ? FAVICON_TYPES
|
|
18618
|
+
return ext ? FAVICON_TYPES.get(ext) : undefined;
|
|
17905
18619
|
};
|
|
17906
18620
|
var inlineDataUri = (file, type) => `data:${type};base64,${readFileSync8(file).toString("base64")}`;
|
|
17907
18621
|
var defaultFavicon = () => ({
|
|
@@ -17937,7 +18651,7 @@ var resolveBanner = (config) => {
|
|
|
17937
18651
|
if (!banner) {
|
|
17938
18652
|
return null;
|
|
17939
18653
|
}
|
|
17940
|
-
if (
|
|
18654
|
+
if (isStringShorthand(banner)) {
|
|
17941
18655
|
return { content: banner, dismissible: false, key: banner };
|
|
17942
18656
|
}
|
|
17943
18657
|
return {
|
|
@@ -18068,6 +18782,7 @@ var buildRuntimeData = (project) => {
|
|
|
18068
18782
|
theme: config.theme,
|
|
18069
18783
|
title: config.title,
|
|
18070
18784
|
toc: config.toc,
|
|
18785
|
+
versions: config.versions ?? null,
|
|
18071
18786
|
webmcp: {
|
|
18072
18787
|
enabled: config.ai.webmcp,
|
|
18073
18788
|
llms: config.ai.llmsTxt.enabled
|
|
@@ -18081,6 +18796,13 @@ var buildRuntimeData = (project) => {
|
|
|
18081
18796
|
fontCssVars: configuredCssVars(config.theme.fonts),
|
|
18082
18797
|
navigation: withRepoUrl(graph.navigation),
|
|
18083
18798
|
navigationByLocale,
|
|
18799
|
+
navigationByVersion: Object.fromEntries(Object.entries(graph.navigationByVersion).map(([id2, byLocale]) => [
|
|
18800
|
+
id2,
|
|
18801
|
+
Object.fromEntries(Object.entries(byLocale).map(([code, nav]) => [
|
|
18802
|
+
code,
|
|
18803
|
+
withRepoUrl(nav)
|
|
18804
|
+
]))
|
|
18805
|
+
])),
|
|
18084
18806
|
routes: manifest.routes.map((route) => ({
|
|
18085
18807
|
alternates: route.alternates,
|
|
18086
18808
|
collection: route.collection,
|
|
@@ -18094,7 +18816,9 @@ var buildRuntimeData = (project) => {
|
|
|
18094
18816
|
lastModified: route.lastModified ?? null,
|
|
18095
18817
|
locale: route.locale,
|
|
18096
18818
|
path: route.path,
|
|
18097
|
-
title: route.title
|
|
18819
|
+
title: route.title,
|
|
18820
|
+
version: route.version,
|
|
18821
|
+
versionAlternates: route.versionAlternates
|
|
18098
18822
|
})),
|
|
18099
18823
|
ui: defaultUi,
|
|
18100
18824
|
uiByLocale
|
|
@@ -18530,6 +19254,7 @@ var prepareProject = async (options) => {
|
|
|
18530
19254
|
|
|
18531
19255
|
// src/cli/commands/build.ts
|
|
18532
19256
|
var ADAPTERS = ["vercel", "node", "netlify", "cloudflare"];
|
|
19257
|
+
var isAdapter = (value) => ADAPTERS.some((adapter) => adapter === value);
|
|
18533
19258
|
var BUDGET_JS = "budget-js";
|
|
18534
19259
|
var BUDGET_CSS = "budget-css";
|
|
18535
19260
|
var validateBudgetFlags = (args) => {
|
|
@@ -18626,10 +19351,13 @@ var emitVercelNegotiation = async (project, routePaths, root) => {
|
|
|
18626
19351
|
if (!existsSync18(configPath)) {
|
|
18627
19352
|
return;
|
|
18628
19353
|
}
|
|
18629
|
-
const overrides = {
|
|
18630
|
-
|
|
18631
|
-
|
|
18632
|
-
}
|
|
19354
|
+
const overrides = {};
|
|
19355
|
+
if (hasApiCatalog(config2)) {
|
|
19356
|
+
overrides[API_CATALOG_PATH.slice(1)] = API_CATALOG_TYPE;
|
|
19357
|
+
}
|
|
19358
|
+
if (config2.ai.webBotAuth.keys.length > 0) {
|
|
19359
|
+
overrides[SIGNATURES_DIRECTORY_PATH.slice(1)] = SIGNATURES_DIRECTORY_TYPE;
|
|
19360
|
+
}
|
|
18633
19361
|
const rawMarkdown = await buildRawMarkdown(project);
|
|
18634
19362
|
const home = rawMarkdown["/"];
|
|
18635
19363
|
const injected = injectNegotiationRoutes(await readFile17(configPath, "utf-8"), routePaths, buildHomeLinkHeader(config2, routePaths), overrides, home ? markdownTokenCount(agentMarkdown(home)) : undefined);
|
|
@@ -18883,7 +19611,7 @@ var buildCommand = defineCommand3({
|
|
|
18883
19611
|
logger.error(`Invalid --output "${args.output}" (use static | server).`);
|
|
18884
19612
|
process.exit(1);
|
|
18885
19613
|
}
|
|
18886
|
-
if (args.adapter && !
|
|
19614
|
+
if (args.adapter && !isAdapter(args.adapter)) {
|
|
18887
19615
|
logger.error(`Invalid --adapter "${args.adapter}" (use ${ADAPTERS.join(" | ")}).`);
|
|
18888
19616
|
process.exit(1);
|
|
18889
19617
|
}
|
|
@@ -19295,7 +20023,7 @@ var askFiles = async (project, srcDir, genDir) => {
|
|
|
19295
20023
|
const grounded = ask.provider !== "inkeep";
|
|
19296
20024
|
const files = [
|
|
19297
20025
|
{
|
|
19298
|
-
content: askEndpointTemplate(resolveAskBackend(ask), grounded),
|
|
20026
|
+
content: askEndpointTemplate(resolveAskBackend(ask), grounded, ask.instructions),
|
|
19299
20027
|
path: join33(srcDir, "pages", "api", "ask.ts")
|
|
19300
20028
|
}
|
|
19301
20029
|
];
|
|
@@ -19794,14 +20522,15 @@ var commandsFor = (pm) => ({
|
|
|
19794
20522
|
exec: { bun: "bunx", npm: "npx", pnpm: "pnpm exec", yarn: "yarn" }[pm],
|
|
19795
20523
|
install: `${pm} install`
|
|
19796
20524
|
});
|
|
20525
|
+
var isPackageManager = (value) => PACKAGE_MANAGERS.some((pm) => pm === value);
|
|
19797
20526
|
var detectPackageManager = (userAgent) => {
|
|
19798
20527
|
const name = userAgent?.split("/")[0];
|
|
19799
|
-
return name !== undefined &&
|
|
20528
|
+
return name !== undefined && isPackageManager(name) ? name : "npm";
|
|
19800
20529
|
};
|
|
19801
20530
|
var detectProjectPackageManager = async (root) => {
|
|
19802
20531
|
const detected = await detect({ cwd: root });
|
|
19803
20532
|
const name = detected?.name;
|
|
19804
|
-
return name !== undefined &&
|
|
20533
|
+
return name !== undefined && isPackageManager(name) ? name : detectPackageManager(process.env.npm_config_user_agent);
|
|
19805
20534
|
};
|
|
19806
20535
|
var validateContentDir = (root, dir) => isAbsolute9(dir) || relative16(root, join35(root, dir)).startsWith("..") ? "Must be a relative path inside the project." : undefined;
|
|
19807
20536
|
var titleize = (raw) => {
|
|
@@ -19865,10 +20594,16 @@ export default defineConfig({
|
|
|
19865
20594
|
description: "Documentation powered by Blume.",${STARTERS[answers.template].configExtra}${contentBlockFor(answers)}
|
|
19866
20595
|
});
|
|
19867
20596
|
`;
|
|
19868
|
-
var extraDepsFor = (sources) =>
|
|
19869
|
-
|
|
19870
|
-
|
|
19871
|
-
|
|
20597
|
+
var extraDepsFor = (sources) => {
|
|
20598
|
+
const deps = {};
|
|
20599
|
+
if (sources.includes("notion")) {
|
|
20600
|
+
deps["@notionhq/client"] = "^2.2.15";
|
|
20601
|
+
}
|
|
20602
|
+
if (sources.includes("sanity")) {
|
|
20603
|
+
deps["@sanity/client"] = "^7.25.0";
|
|
20604
|
+
}
|
|
20605
|
+
return deps;
|
|
20606
|
+
};
|
|
19872
20607
|
var buildPlan = (root, answers) => {
|
|
19873
20608
|
const files = [
|
|
19874
20609
|
{
|
|
@@ -20166,7 +20901,7 @@ import { join as join38 } from "pathe";
|
|
|
20166
20901
|
import { readFile as readFile20, writeFile as writeFile12 } from "node:fs/promises";
|
|
20167
20902
|
import spawn2 from "cross-spawn";
|
|
20168
20903
|
import { join as join37 } from "pathe";
|
|
20169
|
-
import { z as
|
|
20904
|
+
import { z as z4 } from "zod";
|
|
20170
20905
|
var KILL_GRACE_MS = 5000;
|
|
20171
20906
|
var MCP_TOOL_NAMES = [
|
|
20172
20907
|
"search_docs",
|
|
@@ -20292,10 +21027,10 @@ var codexArgs = (context) => {
|
|
|
20292
21027
|
return [...base, "-"];
|
|
20293
21028
|
};
|
|
20294
21029
|
var agentArgs = (kind, context) => kind === "claude" ? claudeArgs(context) : codexArgs(context);
|
|
20295
|
-
var claudeResultSchema =
|
|
20296
|
-
is_error:
|
|
20297
|
-
result:
|
|
20298
|
-
total_cost_usd:
|
|
21030
|
+
var claudeResultSchema = z4.object({
|
|
21031
|
+
is_error: z4.boolean().default(false),
|
|
21032
|
+
result: z4.string().default(""),
|
|
21033
|
+
total_cost_usd: z4.number().optional()
|
|
20299
21034
|
});
|
|
20300
21035
|
var tail = (value, max = 300) => {
|
|
20301
21036
|
const trimmed = value.trim();
|
|
@@ -20349,11 +21084,11 @@ var readAgentOutput = async (kind, result, lastMessagePath) => {
|
|
|
20349
21084
|
}
|
|
20350
21085
|
return { isError: false, text };
|
|
20351
21086
|
};
|
|
20352
|
-
var verdictSchema =
|
|
20353
|
-
missing:
|
|
20354
|
-
notes:
|
|
20355
|
-
pass:
|
|
20356
|
-
score:
|
|
21087
|
+
var verdictSchema = z4.object({
|
|
21088
|
+
missing: z4.array(z4.string()).default([]),
|
|
21089
|
+
notes: z4.string().default(""),
|
|
21090
|
+
pass: z4.boolean(),
|
|
21091
|
+
score: z4.number().min(0).max(1).optional()
|
|
20357
21092
|
});
|
|
20358
21093
|
var parseVerdict = (text) => {
|
|
20359
21094
|
const start = text.indexOf("{");
|
|
@@ -20374,26 +21109,26 @@ var parseVerdict = (text) => {
|
|
|
20374
21109
|
// src/eval/schema.ts
|
|
20375
21110
|
import { readFile as readFile21 } from "node:fs/promises";
|
|
20376
21111
|
import { load as load2 } from "js-yaml";
|
|
20377
|
-
import { z as
|
|
21112
|
+
import { z as z5 } from "zod";
|
|
20378
21113
|
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:
|
|
21114
|
+
var questionSchema = z5.strictObject({
|
|
21115
|
+
expected: z5.array(z5.string().min(1)).min(1, "expected must list at least one fact"),
|
|
21116
|
+
id: z5.string().regex(ID_PATTERN, "id must be a kebab-case slug (a-z, 0-9, dashes)"),
|
|
21117
|
+
question: z5.string().min(1),
|
|
21118
|
+
routes: z5.union([z5.string(), z5.array(z5.string())]).default([]).transform((value) => Array.isArray(value) ? value : [value]),
|
|
21119
|
+
severity: z5.enum(["error", "warning"]).default("error"),
|
|
21120
|
+
skip: z5.boolean().default(false)
|
|
20386
21121
|
});
|
|
20387
|
-
var fullSchema =
|
|
20388
|
-
questions:
|
|
20389
|
-
version:
|
|
21122
|
+
var fullSchema = z5.strictObject({
|
|
21123
|
+
questions: z5.array(questionSchema).min(1),
|
|
21124
|
+
version: z5.literal(1).default(1)
|
|
20390
21125
|
});
|
|
20391
21126
|
var evalsFileSchema = fullSchema.superRefine((value, context) => {
|
|
20392
21127
|
const seen = new Set;
|
|
20393
21128
|
for (const question of value.questions) {
|
|
20394
21129
|
if (seen.has(question.id)) {
|
|
20395
21130
|
context.addIssue({
|
|
20396
|
-
code:
|
|
21131
|
+
code: z5.ZodIssueCode.custom,
|
|
20397
21132
|
message: `duplicate question id "${question.id}"`,
|
|
20398
21133
|
path: ["questions"]
|
|
20399
21134
|
});
|
|
@@ -20986,13 +21721,13 @@ var initCommand = defineCommand9({
|
|
|
20986
21721
|
},
|
|
20987
21722
|
async run({ args }) {
|
|
20988
21723
|
const cwd = process.cwd();
|
|
20989
|
-
const template = args.template;
|
|
20990
|
-
if (template !== undefined &&
|
|
21724
|
+
const template = TEMPLATES.find((candidate) => candidate === args.template);
|
|
21725
|
+
if (args.template !== undefined && template === undefined) {
|
|
20991
21726
|
logger.error(`Unknown template "${args.template}" (use ${TEMPLATES.join(" | ")}).`);
|
|
20992
21727
|
process.exit(1);
|
|
20993
21728
|
}
|
|
20994
|
-
const pm = args["package-manager"];
|
|
20995
|
-
if (
|
|
21729
|
+
const pm = PACKAGE_MANAGERS.find((candidate) => candidate === args["package-manager"]);
|
|
21730
|
+
if (args["package-manager"] !== undefined && pm === undefined) {
|
|
20996
21731
|
logger.error(`Unknown package manager "${args["package-manager"]}" (use ${PACKAGE_MANAGERS.join(" | ")}).`);
|
|
20997
21732
|
process.exit(1);
|
|
20998
21733
|
}
|
|
@@ -21065,7 +21800,7 @@ import {
|
|
|
21065
21800
|
CallToolRequestSchema,
|
|
21066
21801
|
ListToolsRequestSchema
|
|
21067
21802
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
21068
|
-
import { z as
|
|
21803
|
+
import { z as z6 } from "zod";
|
|
21069
21804
|
|
|
21070
21805
|
// src/search/orama-index.ts
|
|
21071
21806
|
import { create, insertMultiple, search } from "@orama/orama";
|
|
@@ -21076,7 +21811,8 @@ var SCHEMA = {
|
|
|
21076
21811
|
facetTerms: "enum[]",
|
|
21077
21812
|
locale: "enum",
|
|
21078
21813
|
route: "string",
|
|
21079
|
-
title: "string"
|
|
21814
|
+
title: "string",
|
|
21815
|
+
version: "enum"
|
|
21080
21816
|
};
|
|
21081
21817
|
var toFacetTerms = (facets) => Object.entries(facets).map(([key, value]) => `${key}:${value}`);
|
|
21082
21818
|
var BOOST = { description: 2, title: 3 };
|
|
@@ -21098,12 +21834,13 @@ var addBigrams = (run, tokens) => {
|
|
|
21098
21834
|
previous = character;
|
|
21099
21835
|
}
|
|
21100
21836
|
};
|
|
21837
|
+
var hasSegmenter = (segmenter) => typeof segmenter === "function";
|
|
21101
21838
|
var segmentingTokenizer = (locale) => {
|
|
21102
21839
|
const language = locale?.toLowerCase().split(/[-_]/u)[0] ?? "";
|
|
21103
21840
|
if (!SEGMENTED_LANGUAGES.has(language)) {
|
|
21104
21841
|
return;
|
|
21105
21842
|
}
|
|
21106
|
-
if (
|
|
21843
|
+
if (!hasSegmenter(Intl.Segmenter)) {
|
|
21107
21844
|
return;
|
|
21108
21845
|
}
|
|
21109
21846
|
const segmenter = new Intl.Segmenter(language, { granularity: "word" });
|
|
@@ -21152,28 +21889,33 @@ var segmentingTokenizer = (locale) => {
|
|
|
21152
21889
|
};
|
|
21153
21890
|
var buildOramaIndex = async (documents, locale) => {
|
|
21154
21891
|
const tokenizer = segmentingTokenizer(locale);
|
|
21155
|
-
const db = create({
|
|
21156
|
-
schema: SCHEMA,
|
|
21157
|
-
...tokenizer ? { components: { tokenizer } } : {}
|
|
21158
|
-
});
|
|
21892
|
+
const db = tokenizer ? create({ components: { tokenizer }, schema: SCHEMA }) : create({ schema: SCHEMA });
|
|
21159
21893
|
await insertMultiple(db, documents.map((doc) => doc.facets ? { ...doc, facetTerms: toFacetTerms(doc.facets) } : doc));
|
|
21160
21894
|
return db;
|
|
21161
21895
|
};
|
|
21162
21896
|
var ALL_TOKENS = 0;
|
|
21163
21897
|
var queryOramaIndex = async (db, term, limit, filters) => {
|
|
21164
21898
|
const facetTerms = filters?.facets ? toFacetTerms(filters.facets) : [];
|
|
21165
|
-
const where = {
|
|
21166
|
-
|
|
21167
|
-
|
|
21168
|
-
|
|
21169
|
-
|
|
21170
|
-
|
|
21899
|
+
const where = {};
|
|
21900
|
+
if (filters?.locale) {
|
|
21901
|
+
where.locale = { eq: filters.locale };
|
|
21902
|
+
}
|
|
21903
|
+
if (filters?.version !== undefined) {
|
|
21904
|
+
where.version = { eq: filters.version };
|
|
21905
|
+
}
|
|
21906
|
+
if (filters?.contentTypes && filters.contentTypes.length > 0) {
|
|
21907
|
+
where.contentType = { in: filters.contentTypes };
|
|
21908
|
+
}
|
|
21909
|
+
if (facetTerms.length > 0) {
|
|
21910
|
+
where.facetTerms = { containsAll: facetTerms };
|
|
21911
|
+
}
|
|
21912
|
+
const unfiltered = {
|
|
21171
21913
|
boost: BOOST,
|
|
21172
21914
|
limit,
|
|
21173
21915
|
properties: ["title", "description", "content"],
|
|
21174
|
-
term
|
|
21175
|
-
...Object.keys(where).length > 0 ? { where } : {}
|
|
21916
|
+
term
|
|
21176
21917
|
};
|
|
21918
|
+
const params = Object.keys(where).length > 0 ? { ...unfiltered, where } : unfiltered;
|
|
21177
21919
|
const bigrammed = BIGRAM_LANGUAGES.has(db.tokenizer?.language ?? "");
|
|
21178
21920
|
const strict = bigrammed ? await search(db, { ...params, threshold: ALL_TOKENS }) : undefined;
|
|
21179
21921
|
const found = strict && strict.hits.length > 0 ? strict : await search(db, params);
|
|
@@ -21184,36 +21926,55 @@ var queryOramaIndex = async (db, term, limit, filters) => {
|
|
|
21184
21926
|
var DEFAULT_SEARCH_LIMIT = 8;
|
|
21185
21927
|
var MAX_SEARCH_LIMIT = 20;
|
|
21186
21928
|
var EXCERPT_LENGTH = 200;
|
|
21187
|
-
var contentTypesField =
|
|
21929
|
+
var contentTypesField = z6.preprocess((value) => {
|
|
21188
21930
|
const list2 = (Array.isArray(value) ? value : [value]).filter((entry) => typeof entry === "string");
|
|
21189
21931
|
return list2.length > 0 ? list2 : undefined;
|
|
21190
|
-
},
|
|
21191
|
-
var
|
|
21192
|
-
|
|
21932
|
+
}, 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.'));
|
|
21933
|
+
var looseFacetObject = z6.record(z6.string(), z6.unknown());
|
|
21934
|
+
var filtersField = z6.preprocess((value) => {
|
|
21935
|
+
const candidate = looseFacetObject.safeParse(value);
|
|
21936
|
+
if (!candidate.success) {
|
|
21193
21937
|
return;
|
|
21194
21938
|
}
|
|
21195
|
-
const entries = Object.entries(
|
|
21939
|
+
const entries = Object.entries(candidate.data).filter((entry) => typeof entry[1] === "string");
|
|
21196
21940
|
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
21197
|
-
},
|
|
21198
|
-
var limitField =
|
|
21199
|
-
const num =
|
|
21941
|
+
}, 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.'));
|
|
21942
|
+
var limitField = z6.preprocess((value) => {
|
|
21943
|
+
const num = Number(value);
|
|
21200
21944
|
return Number.isFinite(num) ? Math.min(Math.max(Math.trunc(num), 1), MAX_SEARCH_LIMIT) : undefined;
|
|
21201
|
-
},
|
|
21202
|
-
var textField = (description) =>
|
|
21945
|
+
}, z6.int().min(1).max(MAX_SEARCH_LIMIT).optional().describe(`Maximum hits to return (default ${DEFAULT_SEARCH_LIMIT}).`));
|
|
21946
|
+
var textField = (description) => z6.preprocess((value) => {
|
|
21947
|
+
const parsed = z6.string().safeParse(value);
|
|
21948
|
+
return parsed.success ? parsed.data : "";
|
|
21949
|
+
}, z6.string().describe(description));
|
|
21950
|
+
var optionalTextField = (description) => z6.preprocess((value) => {
|
|
21951
|
+
const parsed = z6.string().safeParse(value);
|
|
21952
|
+
const trimmed = parsed.success ? parsed.data.trim() : "";
|
|
21953
|
+
return trimmed || undefined;
|
|
21954
|
+
}, z6.string().optional().describe(description));
|
|
21955
|
+
var localeField = optionalTextField("Only include pages in this locale (e.g. `fr`). Omit for every language.");
|
|
21956
|
+
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
21957
|
var TOOL_INPUTS = {
|
|
21204
|
-
get_navigation:
|
|
21205
|
-
|
|
21958
|
+
get_navigation: z6.object({
|
|
21959
|
+
locale: optionalTextField("Locale whose navigation tree to return (defaults to the default locale)."),
|
|
21960
|
+
version: optionalTextField("Archived version id whose tree to return (defaults to the current docs).")
|
|
21961
|
+
}),
|
|
21962
|
+
get_page: z6.object({
|
|
21206
21963
|
route: textField("The page route, e.g. `/guides/install`.")
|
|
21207
21964
|
}),
|
|
21208
|
-
list_pages:
|
|
21965
|
+
list_pages: z6.object({
|
|
21209
21966
|
contentTypes: contentTypesField,
|
|
21210
|
-
filters: filtersField
|
|
21967
|
+
filters: filtersField,
|
|
21968
|
+
locale: localeField,
|
|
21969
|
+
version: versionField
|
|
21211
21970
|
}),
|
|
21212
|
-
search_docs:
|
|
21971
|
+
search_docs: z6.object({
|
|
21213
21972
|
contentTypes: contentTypesField,
|
|
21214
21973
|
filters: filtersField,
|
|
21215
21974
|
limit: limitField,
|
|
21216
|
-
|
|
21975
|
+
locale: localeField,
|
|
21976
|
+
query: textField("The search query."),
|
|
21977
|
+
version: versionField
|
|
21217
21978
|
})
|
|
21218
21979
|
};
|
|
21219
21980
|
var inputSchemaFor = (schema) => {
|
|
@@ -21221,7 +21982,7 @@ var inputSchemaFor = (schema) => {
|
|
|
21221
21982
|
$schema: _dialect,
|
|
21222
21983
|
additionalProperties: _closed,
|
|
21223
21984
|
...rest
|
|
21224
|
-
} =
|
|
21985
|
+
} = z6.toJSONSchema(schema);
|
|
21225
21986
|
return rest;
|
|
21226
21987
|
};
|
|
21227
21988
|
var TOOL_DEFINITIONS = MCP_TOOLS.map((tool) => ({
|
|
@@ -21232,6 +21993,19 @@ var TOOL_DEFINITIONS = MCP_TOOLS.map((tool) => ({
|
|
|
21232
21993
|
title: tool.title
|
|
21233
21994
|
}));
|
|
21234
21995
|
var matchesFacets = (facets, filters) => Object.entries(filters).every(([key, value]) => facets?.[key] === value);
|
|
21996
|
+
var asVersionScope = (value, data) => {
|
|
21997
|
+
if (!data.archivedVersions) {
|
|
21998
|
+
return;
|
|
21999
|
+
}
|
|
22000
|
+
if (value === "all") {
|
|
22001
|
+
return;
|
|
22002
|
+
}
|
|
22003
|
+
if (value === undefined || value === "latest" || value === "current") {
|
|
22004
|
+
return "";
|
|
22005
|
+
}
|
|
22006
|
+
return value;
|
|
22007
|
+
};
|
|
22008
|
+
var unknownVersionError = (versionId, data) => versionId && data.archivedVersions && !data.archivedVersions.includes(versionId) ? `Unknown version "${versionId}". Archived versions: ${data.archivedVersions.join(", ")}.` : null;
|
|
21235
22009
|
var normalizeRoute2 = (input, data) => {
|
|
21236
22010
|
let value = input.trim();
|
|
21237
22011
|
if (/^https?:\/\//iu.test(value)) {
|
|
@@ -21256,10 +22030,10 @@ var excerptFor = (doc) => {
|
|
|
21256
22030
|
const head = doc.content.slice(0, EXCERPT_LENGTH).trim();
|
|
21257
22031
|
return doc.content.length > EXCERPT_LENGTH ? `${head}…` : head;
|
|
21258
22032
|
};
|
|
21259
|
-
var text = (value, isError = false) =>
|
|
21260
|
-
content
|
|
21261
|
-
|
|
21262
|
-
}
|
|
22033
|
+
var text = (value, isError = false) => {
|
|
22034
|
+
const content = [{ text: value, type: "text" }];
|
|
22035
|
+
return isError ? { content, isError: true } : { content };
|
|
22036
|
+
};
|
|
21263
22037
|
var createIndexProvider = (documents, locale) => {
|
|
21264
22038
|
let dbPromise = null;
|
|
21265
22039
|
return function provideIndex() {
|
|
@@ -21268,10 +22042,8 @@ var createIndexProvider = (documents, locale) => {
|
|
|
21268
22042
|
};
|
|
21269
22043
|
};
|
|
21270
22044
|
var buildServer = (data, index) => {
|
|
21271
|
-
const
|
|
21272
|
-
|
|
21273
|
-
...data.instructions ? { instructions: data.instructions } : {}
|
|
21274
|
-
});
|
|
22045
|
+
const serverOptions = data.instructions ? { capabilities: { tools: {} }, instructions: data.instructions } : { capabilities: { tools: {} } };
|
|
22046
|
+
const server = new Server({ name: data.name, version: data.version }, serverOptions);
|
|
21275
22047
|
server.setRequestHandler(ListToolsRequestSchema, () => ({
|
|
21276
22048
|
tools: TOOL_DEFINITIONS
|
|
21277
22049
|
}));
|
|
@@ -21282,16 +22054,24 @@ var buildServer = (data, index) => {
|
|
|
21282
22054
|
const db = await index();
|
|
21283
22055
|
const hits = await queryOramaIndex(db, input.query, input.limit ?? DEFAULT_SEARCH_LIMIT, {
|
|
21284
22056
|
contentTypes: input.contentTypes,
|
|
21285
|
-
facets: input.filters
|
|
22057
|
+
facets: input.filters,
|
|
22058
|
+
locale: input.locale,
|
|
22059
|
+
version: asVersionScope(input.version, data)
|
|
22060
|
+
});
|
|
22061
|
+
const results = hits.map((doc) => {
|
|
22062
|
+
const hit = {
|
|
22063
|
+
contentType: doc.contentType,
|
|
22064
|
+
excerpt: excerptFor(doc),
|
|
22065
|
+
facets: doc.facets,
|
|
22066
|
+
route: doc.route,
|
|
22067
|
+
title: doc.title,
|
|
22068
|
+
url: urlFor(doc.route, data)
|
|
22069
|
+
};
|
|
22070
|
+
if (data.archivedVersions) {
|
|
22071
|
+
hit.version = doc.version ?? "";
|
|
22072
|
+
}
|
|
22073
|
+
return hit;
|
|
21286
22074
|
});
|
|
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
22075
|
return text(JSON.stringify(results, null, 2));
|
|
21296
22076
|
}
|
|
21297
22077
|
if (name === "get_page") {
|
|
@@ -21304,20 +22084,40 @@ var buildServer = (data, index) => {
|
|
|
21304
22084
|
return text(markdown);
|
|
21305
22085
|
}
|
|
21306
22086
|
if (name === "list_pages") {
|
|
21307
|
-
const
|
|
21308
|
-
const
|
|
21309
|
-
|
|
21310
|
-
|
|
21311
|
-
|
|
21312
|
-
|
|
21313
|
-
|
|
21314
|
-
|
|
21315
|
-
|
|
21316
|
-
|
|
21317
|
-
|
|
22087
|
+
const input = TOOL_INPUTS.list_pages.parse(args);
|
|
22088
|
+
const { contentTypes, filters, locale } = input;
|
|
22089
|
+
const versionScope = asVersionScope(input.version, data);
|
|
22090
|
+
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));
|
|
22091
|
+
return text(JSON.stringify(routes.map((route) => {
|
|
22092
|
+
const listing = {
|
|
22093
|
+
contentType: route.contentType,
|
|
22094
|
+
description: route.description,
|
|
22095
|
+
facets: route.facets,
|
|
22096
|
+
lastModified: route.lastModified,
|
|
22097
|
+
route: route.route,
|
|
22098
|
+
title: route.title,
|
|
22099
|
+
url: urlFor(route.route, data)
|
|
22100
|
+
};
|
|
22101
|
+
if (data.archivedVersions) {
|
|
22102
|
+
listing.version = route.version;
|
|
22103
|
+
}
|
|
22104
|
+
return listing;
|
|
22105
|
+
}), null, 2));
|
|
21318
22106
|
}
|
|
21319
22107
|
if (name === "get_navigation") {
|
|
21320
|
-
|
|
22108
|
+
const { locale, version: versionId } = TOOL_INPUTS.get_navigation.parse(args);
|
|
22109
|
+
const unknownVersion = unknownVersionError(versionId, data);
|
|
22110
|
+
if (unknownVersion) {
|
|
22111
|
+
return text(unknownVersion, true);
|
|
22112
|
+
}
|
|
22113
|
+
let { navigation } = data;
|
|
22114
|
+
const byLocale = versionId ? data.navigationByVersion?.[versionId] : undefined;
|
|
22115
|
+
if (byLocale) {
|
|
22116
|
+
navigation = (locale ? byLocale[locale] : undefined) ?? byLocale[data.defaultLocale ?? ""] ?? Object.values(byLocale)[0] ?? navigation;
|
|
22117
|
+
} else if (locale && data.navigationByLocale?.[locale]) {
|
|
22118
|
+
navigation = data.navigationByLocale[locale];
|
|
22119
|
+
}
|
|
22120
|
+
return text(JSON.stringify(navigation, null, 2));
|
|
21321
22121
|
}
|
|
21322
22122
|
return text(`Unknown tool: ${name}`, true);
|
|
21323
22123
|
});
|
|
@@ -21469,11 +22269,11 @@ var translateAgentArgs = (kind, lastMessagePath) => kind === "claude" ? claudeAr
|
|
|
21469
22269
|
import { createHash as createHash5 } from "node:crypto";
|
|
21470
22270
|
import { readFile as readFile23 } from "node:fs/promises";
|
|
21471
22271
|
import { join as join42 } from "pathe";
|
|
21472
|
-
import { z as
|
|
22272
|
+
import { z as z7 } from "zod";
|
|
21473
22273
|
var LEDGER_FILE = "blume.translations.json";
|
|
21474
|
-
var ledgerSchema =
|
|
21475
|
-
files:
|
|
21476
|
-
version:
|
|
22274
|
+
var ledgerSchema = z7.object({
|
|
22275
|
+
files: z7.record(z7.string(), z7.record(z7.string(), z7.string())),
|
|
22276
|
+
version: z7.literal(1)
|
|
21477
22277
|
});
|
|
21478
22278
|
var emptyLedger = () => ({
|
|
21479
22279
|
files: {},
|
|
@@ -21743,6 +22543,7 @@ import { readFile as readFile24 } from "node:fs/promises";
|
|
|
21743
22543
|
import { dirname as dirname15, join as join43, relative as relative19 } from "pathe";
|
|
21744
22544
|
import { glob as glob8 } from "tinyglobby";
|
|
21745
22545
|
var META_FILES2 = ["**/meta.ts", "**/meta.js", "**/meta.mjs"];
|
|
22546
|
+
var isFactoryModule = (value) => typeof value === "function";
|
|
21746
22547
|
var metaTargetPath = (meta, locale) => join43(meta.contentRoot, locale, meta.dir, "meta.ts");
|
|
21747
22548
|
var discoverTranslatableMeta = async (project) => {
|
|
21748
22549
|
const { i18n } = project.config;
|
|
@@ -21771,7 +22572,7 @@ var discoverTranslatableMeta = async (project) => {
|
|
|
21771
22572
|
readFile24(file, "utf-8"),
|
|
21772
22573
|
load3(file)
|
|
21773
22574
|
]);
|
|
21774
|
-
if (
|
|
22575
|
+
if (isFactoryModule(mod)) {
|
|
21775
22576
|
diagnostics.push({
|
|
21776
22577
|
code: "BLUME_TRANSLATE_META_FACTORY",
|
|
21777
22578
|
file,
|
|
@@ -21803,7 +22604,7 @@ var generateMetaModule = (meta, translatedTitle) => {
|
|
|
21803
22604
|
...meta,
|
|
21804
22605
|
title: translatedTitle
|
|
21805
22606
|
};
|
|
21806
|
-
const lines = Object.
|
|
22607
|
+
const lines = Object.entries(data).toSorted(([a], [b]) => a < b ? -1 : 1).filter(([, value]) => value !== undefined).map(([key, value]) => ` ${key}: ${JSON.stringify(value)},`);
|
|
21807
22608
|
return [
|
|
21808
22609
|
"// Generated by `blume translate` — edit the default locale's meta file",
|
|
21809
22610
|
"// and rerun the translation instead of editing this copy.",
|
|
@@ -21863,10 +22664,12 @@ var stripOuterFence = (text2) => {
|
|
|
21863
22664
|
};
|
|
21864
22665
|
var countFenceLines = (text2) => text2.split(`
|
|
21865
22666
|
`).filter((line) => FENCE_LINE.test(line)).length;
|
|
22667
|
+
var isKeyedObject = (value) => typeof value === "object" && value !== null;
|
|
22668
|
+
var isString7 = (value) => typeof value === "string";
|
|
21866
22669
|
var getPath2 = (data, path) => {
|
|
21867
22670
|
let value = data;
|
|
21868
22671
|
for (const key of path) {
|
|
21869
|
-
if (
|
|
22672
|
+
if (!isKeyedObject(value)) {
|
|
21870
22673
|
return;
|
|
21871
22674
|
}
|
|
21872
22675
|
value = value[key];
|
|
@@ -21921,7 +22724,7 @@ var validateTranslation = (sourceText, agentText) => {
|
|
|
21921
22724
|
for (const path of TRANSLATABLE_KEY_PATHS) {
|
|
21922
22725
|
const original = getPath2(source.data, path);
|
|
21923
22726
|
const translated = getPath2(parsed.data, path);
|
|
21924
|
-
if (
|
|
22727
|
+
if (isString7(original) && isString7(translated) && translated.trim() !== "") {
|
|
21925
22728
|
setPath(data, path, translated);
|
|
21926
22729
|
}
|
|
21927
22730
|
}
|
|
@@ -21941,12 +22744,12 @@ var parseMetaTitles = (agentText, expectedKeys) => {
|
|
|
21941
22744
|
parsed = undefined;
|
|
21942
22745
|
}
|
|
21943
22746
|
}
|
|
21944
|
-
const record =
|
|
22747
|
+
const record = isKeyedObject(parsed) ? parsed : {};
|
|
21945
22748
|
const titles = {};
|
|
21946
22749
|
const missing = [];
|
|
21947
22750
|
for (const key of expectedKeys) {
|
|
21948
22751
|
const value = record[key];
|
|
21949
|
-
if (
|
|
22752
|
+
if (isString7(value) && value.trim() !== "") {
|
|
21950
22753
|
titles[key] = value;
|
|
21951
22754
|
} else {
|
|
21952
22755
|
missing.push(key);
|
|
@@ -22103,7 +22906,7 @@ var translatablePages = (project, i18n) => {
|
|
|
22103
22906
|
const seen = new Set;
|
|
22104
22907
|
const universe = [];
|
|
22105
22908
|
for (const page2 of project.graph.pages) {
|
|
22106
|
-
if (page2.locale !== i18n.defaultLocale || page2.fallback || !page2.sourcePath || seen.has(page2.sourcePath)) {
|
|
22909
|
+
if (page2.locale !== i18n.defaultLocale || page2.fallback || !page2.sourcePath || seen.has(page2.sourcePath) || page2.version !== "") {
|
|
22107
22910
|
continue;
|
|
22108
22911
|
}
|
|
22109
22912
|
const ext = extname8(page2.sourcePath);
|
|
@@ -22673,8 +23476,249 @@ var validateCommand = defineCommand14({
|
|
|
22673
23476
|
}
|
|
22674
23477
|
});
|
|
22675
23478
|
|
|
23479
|
+
// src/cli/commands/version.ts
|
|
23480
|
+
import { defineCommand as defineCommand15 } from "citty";
|
|
23481
|
+
|
|
23482
|
+
// src/core/version-cut.ts
|
|
23483
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
23484
|
+
import { cp as cp3, readdir as readdir3, readFile as readFile27, rm as rm5 } from "node:fs/promises";
|
|
23485
|
+
import { join as join48, relative as relative21 } from "pathe";
|
|
23486
|
+
class CutError extends Error {
|
|
23487
|
+
constructor(message) {
|
|
23488
|
+
super(message);
|
|
23489
|
+
this.name = "CutError";
|
|
23490
|
+
}
|
|
23491
|
+
}
|
|
23492
|
+
var INLINE_CODE2 = /`[^`]*`/gu;
|
|
23493
|
+
var ROOT_LINK = /(?<prefix>\]\(|href="|src=")(?<target>\/[^\s"')]*)/gu;
|
|
23494
|
+
var buildRouteRewrites = (project, id2) => {
|
|
23495
|
+
const { basePath, i18n } = project.config;
|
|
23496
|
+
const { contentRoot: contentRoot2 } = project.context;
|
|
23497
|
+
const rewrites = new Map;
|
|
23498
|
+
for (const page2 of project.graph.pages) {
|
|
23499
|
+
const { sourcePath } = page2;
|
|
23500
|
+
if (page2.version !== "" || !sourcePath || relative21(contentRoot2, sourcePath).startsWith("..")) {
|
|
23501
|
+
continue;
|
|
23502
|
+
}
|
|
23503
|
+
const logical = versionizeRoute(page2.versionKey, id2);
|
|
23504
|
+
rewrites.set(stripBasePath(basePath, page2.route), i18n ? localizeRoute(logical, page2.locale, i18n) : logical);
|
|
23505
|
+
}
|
|
23506
|
+
return rewrites;
|
|
23507
|
+
};
|
|
23508
|
+
var rewriteLine2 = (line, rewrites) => {
|
|
23509
|
+
const masked = line.replaceAll(INLINE_CODE2, (span) => " ".repeat(span.length));
|
|
23510
|
+
let out = "";
|
|
23511
|
+
let cursor = 0;
|
|
23512
|
+
let count = 0;
|
|
23513
|
+
for (const match of masked.matchAll(ROOT_LINK)) {
|
|
23514
|
+
const target = match.groups?.target ?? "";
|
|
23515
|
+
const hash = target.search(/[#?]/u);
|
|
23516
|
+
const path = hash === -1 ? target : target.slice(0, hash);
|
|
23517
|
+
const suffix = hash === -1 ? "" : target.slice(hash);
|
|
23518
|
+
const bare = path !== "/" && path.endsWith("/") ? path.slice(0, -1) : path;
|
|
23519
|
+
const replacement = rewrites.get(bare);
|
|
23520
|
+
if (replacement === undefined) {
|
|
23521
|
+
continue;
|
|
23522
|
+
}
|
|
23523
|
+
const offset = (match.index ?? 0) + (match.groups?.prefix?.length ?? 0);
|
|
23524
|
+
out += line.slice(cursor, offset) + replacement + suffix;
|
|
23525
|
+
cursor = offset + target.length;
|
|
23526
|
+
count += 1;
|
|
23527
|
+
}
|
|
23528
|
+
return count === 0 ? line : out + line.slice(cursor);
|
|
23529
|
+
};
|
|
23530
|
+
var rewriteSnapshotLinks = (source, rewrites) => {
|
|
23531
|
+
let fence = null;
|
|
23532
|
+
let count = 0;
|
|
23533
|
+
const lines = source.split(`
|
|
23534
|
+
`).map((line) => {
|
|
23535
|
+
const next = nextFenceState(line, fence);
|
|
23536
|
+
const inFence = fence !== null || next !== null;
|
|
23537
|
+
fence = next;
|
|
23538
|
+
if (inFence) {
|
|
23539
|
+
return line;
|
|
23540
|
+
}
|
|
23541
|
+
const rewrittenLine = rewriteLine2(line, rewrites);
|
|
23542
|
+
if (rewrittenLine !== line) {
|
|
23543
|
+
count += 1;
|
|
23544
|
+
}
|
|
23545
|
+
return rewrittenLine;
|
|
23546
|
+
});
|
|
23547
|
+
return { count, text: lines.join(`
|
|
23548
|
+
`) };
|
|
23549
|
+
};
|
|
23550
|
+
var snippetFor = (id2, hasVersions) => hasVersions ? `Add to versions.archived in blume.config.ts (newest first):
|
|
23551
|
+
|
|
23552
|
+
{ id: "${id2}" },
|
|
23553
|
+
` : `Add to blume.config.ts:
|
|
23554
|
+
|
|
23555
|
+
versions: {
|
|
23556
|
+
archived: [{ id: "${id2}" }],
|
|
23557
|
+
current: { label: "…" },
|
|
23558
|
+
},
|
|
23559
|
+
`;
|
|
23560
|
+
var insertArchivedVersion = async (configPath, id2) => {
|
|
23561
|
+
let text2;
|
|
23562
|
+
try {
|
|
23563
|
+
text2 = await readFile27(configPath, "utf-8");
|
|
23564
|
+
} catch {
|
|
23565
|
+
return false;
|
|
23566
|
+
}
|
|
23567
|
+
const match = text2.match(/(?<lead>archived:\s*\[)/u);
|
|
23568
|
+
if (!match || match.index === undefined) {
|
|
23569
|
+
return false;
|
|
23570
|
+
}
|
|
23571
|
+
const insertAt = match.index + (match.groups?.lead?.length ?? 0);
|
|
23572
|
+
const lineStart = text2.lastIndexOf(`
|
|
23573
|
+
`, match.index) + 1;
|
|
23574
|
+
const indent = text2.slice(lineStart).match(/^\s*/u)?.[0] ?? "";
|
|
23575
|
+
const rest = text2.slice(insertAt);
|
|
23576
|
+
let entry;
|
|
23577
|
+
if (rest.trimStart().startsWith("]")) {
|
|
23578
|
+
entry = `{ id: "${id2}" }`;
|
|
23579
|
+
} else if (rest.startsWith(`
|
|
23580
|
+
`)) {
|
|
23581
|
+
entry = `
|
|
23582
|
+
${indent} { id: "${id2}" },`;
|
|
23583
|
+
} else {
|
|
23584
|
+
entry = `{ id: "${id2}" }, `;
|
|
23585
|
+
}
|
|
23586
|
+
await writeTextAtomic(configPath, text2.slice(0, insertAt) + entry + rest);
|
|
23587
|
+
return true;
|
|
23588
|
+
};
|
|
23589
|
+
var cutVersion = async (root, id2, options = {}) => {
|
|
23590
|
+
if (!VERSION_ID.test(id2)) {
|
|
23591
|
+
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}".`);
|
|
23592
|
+
}
|
|
23593
|
+
const project = await scanProject(root);
|
|
23594
|
+
const errors = project.diagnostics.filter((diagnostic) => diagnostic.severity === "error");
|
|
23595
|
+
if (errors.length > 0) {
|
|
23596
|
+
throw new CutError(`The project has ${errors.length} error diagnostic(s) — fix them before cutting a version (run \`blume validate\`).`);
|
|
23597
|
+
}
|
|
23598
|
+
const { contentRoot: contentRoot2 } = project.context;
|
|
23599
|
+
if (project.config.versions?.archived.some((version) => version.id === id2)) {
|
|
23600
|
+
throw new CutError(`Version "${id2}" is already registered in versions.archived.`);
|
|
23601
|
+
}
|
|
23602
|
+
const dir = join48(contentRoot2, id2);
|
|
23603
|
+
if (existsSync28(dir)) {
|
|
23604
|
+
if (!options.force) {
|
|
23605
|
+
throw new CutError(`${dir} already exists — pass --force to overwrite the snapshot.`);
|
|
23606
|
+
}
|
|
23607
|
+
await rm5(dir, { force: true, recursive: true });
|
|
23608
|
+
}
|
|
23609
|
+
const excluded = new Set([
|
|
23610
|
+
id2,
|
|
23611
|
+
"node_modules",
|
|
23612
|
+
...project.config.versions?.archived.map((version) => version.id) ?? []
|
|
23613
|
+
]);
|
|
23614
|
+
const entries = await readdir3(contentRoot2, { withFileTypes: true });
|
|
23615
|
+
let copied = 0;
|
|
23616
|
+
await Promise.all(entries.map(async (entry) => {
|
|
23617
|
+
if (excluded.has(entry.name) || entry.name.startsWith(".") || entry.isDirectory() && VERSION_LIKE.test(entry.name)) {
|
|
23618
|
+
return;
|
|
23619
|
+
}
|
|
23620
|
+
await cp3(join48(contentRoot2, entry.name), join48(dir, entry.name), {
|
|
23621
|
+
recursive: true
|
|
23622
|
+
});
|
|
23623
|
+
}));
|
|
23624
|
+
const rewrites = buildRouteRewrites(project, id2);
|
|
23625
|
+
const rewritten = [];
|
|
23626
|
+
const walk = async (current) => {
|
|
23627
|
+
const children = await readdir3(current, { withFileTypes: true });
|
|
23628
|
+
await Promise.all(children.map(async (child) => {
|
|
23629
|
+
const abs = join48(current, child.name);
|
|
23630
|
+
if (child.isDirectory()) {
|
|
23631
|
+
await walk(abs);
|
|
23632
|
+
return;
|
|
23633
|
+
}
|
|
23634
|
+
copied += 1;
|
|
23635
|
+
if (!/\.mdx?$/u.test(child.name)) {
|
|
23636
|
+
return;
|
|
23637
|
+
}
|
|
23638
|
+
const source = await readFile27(abs, "utf-8");
|
|
23639
|
+
const { text: text2, count } = rewriteSnapshotLinks(source, rewrites);
|
|
23640
|
+
if (count > 0) {
|
|
23641
|
+
await writeTextAtomic(abs, text2);
|
|
23642
|
+
rewritten.push({ count, file: relative21(dir, abs) });
|
|
23643
|
+
}
|
|
23644
|
+
}));
|
|
23645
|
+
};
|
|
23646
|
+
await walk(dir);
|
|
23647
|
+
const configPath = join48(root, "blume.config.ts");
|
|
23648
|
+
const configUpdated = project.config.versions !== undefined && await insertArchivedVersion(configPath, id2);
|
|
23649
|
+
return {
|
|
23650
|
+
configSnippet: configUpdated ? null : snippetFor(id2, project.config.versions !== undefined),
|
|
23651
|
+
configUpdated,
|
|
23652
|
+
copied,
|
|
23653
|
+
dir,
|
|
23654
|
+
rewritten
|
|
23655
|
+
};
|
|
23656
|
+
};
|
|
23657
|
+
|
|
23658
|
+
// src/cli/commands/version.ts
|
|
23659
|
+
var versionCommand = defineCommand15({
|
|
23660
|
+
args: {
|
|
23661
|
+
force: {
|
|
23662
|
+
description: "Overwrite an existing snapshot directory.",
|
|
23663
|
+
type: "boolean"
|
|
23664
|
+
},
|
|
23665
|
+
id: {
|
|
23666
|
+
description: 'Version id to cut (e.g. "v1.0").',
|
|
23667
|
+
required: false,
|
|
23668
|
+
type: "positional"
|
|
23669
|
+
}
|
|
23670
|
+
},
|
|
23671
|
+
meta: {
|
|
23672
|
+
description: "Freeze the current docs as an archived version.",
|
|
23673
|
+
name: "version"
|
|
23674
|
+
},
|
|
23675
|
+
async run({ args }) {
|
|
23676
|
+
const root = process.cwd();
|
|
23677
|
+
if (!args.id) {
|
|
23678
|
+
const { config: config2 } = await loadConfig(root);
|
|
23679
|
+
if (!config2.versions) {
|
|
23680
|
+
logger.info("Versioning is not configured. Cut the first version with `blume version <id>` (e.g. `blume version v1.0`).");
|
|
23681
|
+
return;
|
|
23682
|
+
}
|
|
23683
|
+
const { current, archived } = config2.versions;
|
|
23684
|
+
process.stdout.write(` ${current.label} (current)${current.badge ? ` — ${current.badge}` : ""}
|
|
23685
|
+
`);
|
|
23686
|
+
for (const version of archived) {
|
|
23687
|
+
process.stdout.write(` ${version.label ?? version.id} — ${version.id}/
|
|
23688
|
+
`);
|
|
23689
|
+
}
|
|
23690
|
+
return;
|
|
23691
|
+
}
|
|
23692
|
+
try {
|
|
23693
|
+
const result = await cutVersion(root, args.id, { force: args.force });
|
|
23694
|
+
logger.success(`Snapshot ${result.dir} (${result.copied} file(s) copied)`);
|
|
23695
|
+
const totalRewrites = result.rewritten.reduce((sum, entry) => sum + entry.count, 0);
|
|
23696
|
+
if (totalRewrites > 0) {
|
|
23697
|
+
logger.info(`Rewrote root-absolute links in ${result.rewritten.length} page(s) (${totalRewrites} line(s)).`);
|
|
23698
|
+
}
|
|
23699
|
+
if (result.configUpdated) {
|
|
23700
|
+
logger.success(`Added "${args.id}" to versions.archived in blume.config.ts`);
|
|
23701
|
+
} else if (result.configSnippet) {
|
|
23702
|
+
logger.info(result.configSnippet);
|
|
23703
|
+
}
|
|
23704
|
+
logger.info("Archived versions are frozen — future edits belong in the live tree. Restart `blume dev` to pick up the snapshot.");
|
|
23705
|
+
} catch (error) {
|
|
23706
|
+
if (error instanceof CutError) {
|
|
23707
|
+
logger.error(error.message);
|
|
23708
|
+
process.exit(1);
|
|
23709
|
+
}
|
|
23710
|
+
if (error instanceof BlumeError) {
|
|
23711
|
+
logger.error(error.diagnostic.message);
|
|
23712
|
+
process.exit(1);
|
|
23713
|
+
}
|
|
23714
|
+
reportInternalError(error);
|
|
23715
|
+
process.exit(1);
|
|
23716
|
+
}
|
|
23717
|
+
}
|
|
23718
|
+
});
|
|
23719
|
+
|
|
22676
23720
|
// src/cli/index.ts
|
|
22677
|
-
var main =
|
|
23721
|
+
var main = defineCommand16({
|
|
22678
23722
|
meta: {
|
|
22679
23723
|
description: "Markdown-first documentation powered by Astro and Vite.",
|
|
22680
23724
|
name: "blume",
|
|
@@ -22694,7 +23738,8 @@ var main = defineCommand15({
|
|
|
22694
23738
|
preview: previewCommand,
|
|
22695
23739
|
sync: syncCommand,
|
|
22696
23740
|
translate: translateCommand,
|
|
22697
|
-
validate: validateCommand
|
|
23741
|
+
validate: validateCommand,
|
|
23742
|
+
version: versionCommand
|
|
22698
23743
|
}
|
|
22699
23744
|
});
|
|
22700
23745
|
loadEnvFiles(process.cwd());
|
|
@@ -22708,5 +23753,5 @@ process.on("unhandledRejection", (error) => {
|
|
|
22708
23753
|
});
|
|
22709
23754
|
runMain(main);
|
|
22710
23755
|
|
|
22711
|
-
//# debugId=
|
|
23756
|
+
//# debugId=6377B095BFD3F5AE64756E2164756E21
|
|
22712
23757
|
//# sourceMappingURL=index.js.map
|