blume 1.1.3 → 1.1.4

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.
Files changed (37) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/cli/index.js +189 -88
  3. package/dist/cli/index.js.map +22 -22
  4. package/dist/types/core/data.d.ts +2 -0
  5. package/package.json +1 -1
  6. package/src/ai/mcp/server.ts +29 -6
  7. package/src/astro/generate.ts +94 -46
  8. package/src/astro/templates.ts +59 -15
  9. package/src/audit/checks/duplicates.ts +15 -6
  10. package/src/audit/checks/indexability.ts +11 -2
  11. package/src/audit/checks/network.ts +22 -8
  12. package/src/audit/checks/sitemap.ts +42 -16
  13. package/src/audit/redirects.ts +12 -1
  14. package/src/audit/run.ts +13 -3
  15. package/src/audit/url.ts +21 -2
  16. package/src/cli/commands/audit.ts +21 -6
  17. package/src/cli/commands/dev.ts +19 -2
  18. package/src/components/content/Frame.astro +4 -1
  19. package/src/components/content/Prompt.astro +4 -1
  20. package/src/components/content/Tooltip.astro +4 -1
  21. package/src/components/content/Update.astro +45 -0
  22. package/src/components/islands/ask-ai.tsx +19 -2
  23. package/src/components/islands/hooks.ts +38 -11
  24. package/src/components/layout/RootLayout.astro +13 -2
  25. package/src/components/layout/Search.astro +5 -1
  26. package/src/components/layout/head-scripts.ts +22 -5
  27. package/src/core/data.ts +2 -0
  28. package/src/core/deployment-env.ts +7 -2
  29. package/src/core/graph.ts +7 -1
  30. package/src/core/i18n.ts +10 -2
  31. package/src/core/navigation.ts +7 -3
  32. package/src/core/sources/normalize.ts +69 -8
  33. package/src/core/sources/notion.ts +4 -2
  34. package/src/core/sources/sanity.ts +5 -3
  35. package/src/markdown/code-title.ts +7 -1
  36. package/src/openapi/model.ts +31 -2
  37. package/src/openapi/render-mdx.ts +12 -7
package/dist/cli/index.js CHANGED
@@ -1581,6 +1581,13 @@ var normalizePath = (path) => {
1581
1581
  const trimmed = path.replace(/\/+$/u, "");
1582
1582
  return trimmed === "" ? "/" : trimmed;
1583
1583
  };
1584
+ var decodePath = (path) => {
1585
+ try {
1586
+ return decodeURI(path);
1587
+ } catch {
1588
+ return path;
1589
+ }
1590
+ };
1584
1591
  var siteOrigin = (site) => {
1585
1592
  if (!site) {
1586
1593
  return null;
@@ -1611,7 +1618,7 @@ var resolveHref = (pageUrl, href, origin, deployBase = "") => {
1611
1618
  return {
1612
1619
  hash: parsed.hash.slice(1),
1613
1620
  kind: "self-origin",
1614
- path: normalizePath(stripBasePath(deployBase, parsed.pathname))
1621
+ path: normalizePath(stripBasePath(deployBase, decodePath(parsed.pathname)))
1615
1622
  };
1616
1623
  }
1617
1624
  return { kind: "external", url: parsed.toString() };
@@ -1626,7 +1633,7 @@ var resolveHref = (pageUrl, href, origin, deployBase = "") => {
1626
1633
  return {
1627
1634
  hash: resolved.hash.slice(1),
1628
1635
  kind: "internal",
1629
- path: normalizePath(stripBasePath(deployBase, resolved.pathname))
1636
+ path: normalizePath(stripBasePath(deployBase, decodePath(resolved.pathname)))
1630
1637
  };
1631
1638
  };
1632
1639
 
@@ -1825,17 +1832,20 @@ var contentChecks = {
1825
1832
  };
1826
1833
 
1827
1834
  // src/audit/checks/duplicates.ts
1828
- var isNonCanonical = (page) => {
1835
+ var isNonCanonical = (page, deployBase) => {
1829
1836
  if (!page.canonical) {
1830
1837
  return false;
1831
1838
  }
1832
1839
  try {
1833
- return new URL(page.canonical).pathname.replace(/\/$/u, "") !== page.url.replace(/\/$/u, "");
1840
+ return stripBasePath(deployBase, decodePath(new URL(page.canonical).pathname)).replace(/\/$/u, "") !== page.url.replace(/\/$/u, "");
1834
1841
  } catch {
1835
1842
  return false;
1836
1843
  }
1837
1844
  };
1838
- var comparable = (context) => context.pages.filter((page) => page.indexable && !page.route?.fallback && !isNonCanonical(page));
1845
+ var comparable = (context) => {
1846
+ const deployBase = normalizeBasePath(context.project.config.deployment.base);
1847
+ return context.pages.filter((page) => page.indexable && !page.route?.fallback && !isNonCanonical(page, deployBase));
1848
+ };
1839
1849
  var reportGroups = (context, pages, id, key, describe, frontmatterKey) => {
1840
1850
  const groups = new Map;
1841
1851
  for (const page of pages) {
@@ -2009,12 +2019,12 @@ var PLATFORMS = [
2009
2019
  {
2010
2020
  adapter: "vercel",
2011
2021
  detect: (env) => Boolean(env.VERCEL),
2012
- site: (env) => toUrl(env.VERCEL_PROJECT_PRODUCTION_URL ?? env.VERCEL_URL)
2022
+ site: (env) => toUrl(env.VERCEL_PROJECT_PRODUCTION_URL) ?? toUrl(env.VERCEL_URL)
2013
2023
  },
2014
2024
  {
2015
2025
  adapter: "netlify",
2016
2026
  detect: (env) => Boolean(env.NETLIFY),
2017
- site: (env) => toUrl(env.URL ?? env.DEPLOY_PRIME_URL ?? env.DEPLOY_URL)
2027
+ site: (env) => toUrl(env.URL) ?? toUrl(env.DEPLOY_PRIME_URL) ?? toUrl(env.DEPLOY_URL)
2018
2028
  },
2019
2029
  {
2020
2030
  adapter: "cloudflare",
@@ -2073,7 +2083,7 @@ var canonicalChecks = (context, page) => {
2073
2083
  }
2074
2084
  return found;
2075
2085
  }
2076
- const target = normalizePath(canonical.pathname);
2086
+ const target = normalizePath(stripBasePath(normalizeBasePath(context.project.config.deployment.base), decodePath(canonical.pathname)));
2077
2087
  if (target === normalizePath(page.url)) {
2078
2088
  return found;
2079
2089
  }
@@ -2401,7 +2411,7 @@ var probeAll = async (urls, options = {}) => {
2401
2411
  var CLIENT_ERROR = 400;
2402
2412
  var SERVER_ERROR = 500;
2403
2413
  var SLOW_MS = 1500;
2404
- var liveUrl = (origin, page) => new URL(page.url, origin).toString();
2414
+ var liveUrl = (origin, page, deployBase) => new URL(`${deployBase}${page.url}`, origin).toString();
2405
2415
  var badResponse = (context, page, result) => {
2406
2416
  const site = pageSite(context, page);
2407
2417
  if (result.timedOut) {
@@ -2445,12 +2455,13 @@ var networkChecks = {
2445
2455
  return [];
2446
2456
  }
2447
2457
  const found = [];
2448
- const targets = context.pages.map((page) => liveUrl(origin, page));
2449
- const robotsUrl = new URL("/robots.txt", origin).toString();
2450
- const sitemapUrl = new URL("/sitemap.xml", origin).toString();
2458
+ const deployBase = normalizeBasePath(context.project.config.deployment.base);
2459
+ const targets = context.pages.map((page) => liveUrl(origin, page, deployBase));
2460
+ const robotsUrl = new URL(`${deployBase}/robots.txt`, origin).toString();
2461
+ const sitemapUrl = new URL(`${deployBase}/sitemap.xml`, origin).toString();
2451
2462
  const results = await probeAll([...targets, robotsUrl, sitemapUrl]);
2452
2463
  for (const page of context.pages) {
2453
- const result = results.get(liveUrl(origin, page));
2464
+ const result = results.get(liveUrl(origin, page, deployBase));
2454
2465
  if (!result) {
2455
2466
  continue;
2456
2467
  }
@@ -2717,23 +2728,23 @@ var MAX_SITEMAP_BYTES = 50 * 1024 * 1024;
2717
2728
  var MAX_SITEMAP_URLS = 50000;
2718
2729
  var LASTMOD_SLACK_MS = 24 * 60 * 60 * 1000;
2719
2730
  var ERROR_ROUTES2 = new Set(["/404", "/500"]);
2720
- var sitemapPaths = (context) => {
2731
+ var sitemapPaths = (context, deployBase) => {
2721
2732
  const paths = new Map;
2722
2733
  for (const loc of context.sitemap?.urls ?? []) {
2723
2734
  try {
2724
- paths.set(normalizePath(new URL(loc).pathname), loc);
2735
+ paths.set(normalizePath(stripBasePath(deployBase, decodePath(new URL(loc).pathname))), loc);
2725
2736
  } catch {}
2726
2737
  }
2727
2738
  return paths;
2728
2739
  };
2729
- var canonicalPath = (canonical) => {
2740
+ var canonicalPath = (canonical, deployBase) => {
2730
2741
  try {
2731
- return normalizePath(new URL(canonical).pathname);
2742
+ return normalizePath(stripBasePath(deployBase, decodePath(new URL(canonical).pathname)));
2732
2743
  } catch {
2733
2744
  return null;
2734
2745
  }
2735
2746
  };
2736
- var checkListedUrl = (context, loc, origin, file) => {
2747
+ var checkListedUrl = (context, loc, origin, file, deployBase) => {
2737
2748
  let parsed;
2738
2749
  try {
2739
2750
  parsed = new URL(loc);
@@ -2747,7 +2758,7 @@ var checkListedUrl = (context, loc, origin, file) => {
2747
2758
  finding("BLUME_AUDIT_SITEMAP_OUT_OF_SCOPE", { file, url: loc }, `sitemap.xml lists ${loc}, which is on another origin.`)
2748
2759
  ];
2749
2760
  }
2750
- const path = normalizePath(stripBasePath(normalizeBasePath(context.project.config.deployment.base), parsed.pathname));
2761
+ const path = normalizePath(stripBasePath(deployBase, decodePath(parsed.pathname)));
2751
2762
  const page = context.byUrl.get(path);
2752
2763
  if (!page) {
2753
2764
  const redirect = context.redirects.find((entry) => normalizePath(entry.from) === path);
@@ -2759,7 +2770,7 @@ var checkListedUrl = (context, loc, origin, file) => {
2759
2770
  if (!page.indexable) {
2760
2771
  found.push(finding("BLUME_AUDIT_NOINDEX_IN_SITEMAP", pageSite(context, page, ["noindex"]), `${path} is in the sitemap but declares robots "${page.robots}".`));
2761
2772
  }
2762
- const canonical = page.canonical && canonicalPath(page.canonical);
2773
+ const canonical = page.canonical && canonicalPath(page.canonical, deployBase);
2763
2774
  if (canonical && canonical !== path) {
2764
2775
  found.push(finding("BLUME_AUDIT_NON_CANONICAL_IN_SITEMAP", pageSite(context, page, ["seo", "canonical"]), `${path} is in the sitemap but canonicalizes to ${canonical}.`));
2765
2776
  }
@@ -2795,9 +2806,10 @@ var sitemapChecks = {
2795
2806
  }
2796
2807
  }
2797
2808
  const origin = siteOrigin(site);
2798
- const listed = sitemapPaths(context);
2809
+ const deployBase = normalizeBasePath(context.project.config.deployment.base);
2810
+ const listed = sitemapPaths(context, deployBase);
2799
2811
  for (const loc of sitemap.urls) {
2800
- found.push(...checkListedUrl(context, loc, origin, sitemap.file));
2812
+ found.push(...checkListedUrl(context, loc, origin, sitemap.file, deployBase));
2801
2813
  }
2802
2814
  for (const page of context.pages) {
2803
2815
  if (!page.indexable || ERROR_ROUTES2.has(page.url) || listed.has(normalizePath(page.url))) {
@@ -3468,6 +3480,13 @@ var astroOutDir = (context) => context.distDir ?? `${context.root}/dist`;
3468
3480
  var adapterRoot = (context) => dirname5(astroOutDir(context));
3469
3481
  var REACT_EXCLUDE = String.raw`exclude: [/\/node_modules\/\.vite\//]`;
3470
3482
  var reactIntegration = (compilerPath) => compilerPath ? `react({ babel: { plugins: [[${JSON.stringify(compilerPath)}, { target: "19" }]] }, ${REACT_EXCLUDE} })` : `react({ ${REACT_EXCLUDE} })`;
3483
+ var devWatchOption = (outDir, contentWatchesRuntimeDir) => contentWatchesRuntimeDir ? `
3484
+ // Astro's cache dir sits inside the docs collection, whose watcher would
3485
+ // otherwise churn (and can loop) on Astro's own writes. Trade-off: .md
3486
+ // body edits need a dev-server restart in this layout.
3487
+ watch: {
3488
+ ignored: ${JSON.stringify([join8(outDir, ".astro", "**")])},
3489
+ },` : "";
3471
3490
  var astroConfigTemplate = (options) => {
3472
3491
  const { context, config, needsReact, pages, dataPath, themePath } = options;
3473
3492
  const {
@@ -3554,6 +3573,7 @@ var astroConfigTemplate = (options) => {
3554
3573
  integrations.push("svelte()");
3555
3574
  }
3556
3575
  integrations.push(`blumeIntegration(${JSON.stringify({ base: deployment.base, contentRoutes, pages })})`);
3576
+ const watchOption = devWatchOption(context.outDir, options.contentWatchesRuntimeDir);
3557
3577
  return `// Generated by Blume. Do not edit; this file is recreated on each run.
3558
3578
  ${defineConfigImport}
3559
3579
  import mdx from "@astrojs/mdx";
@@ -3628,22 +3648,17 @@ export default defineConfig({
3628
3648
  server: {
3629
3649
  fs: {
3630
3650
  allow: ${JSON.stringify(fsAllow)},
3631
- },
3632
- // Keep the file watcher out of Astro's own cache dir. In a migrated
3633
- // (root-rooted) project the docs collection is rooted at the project dir,
3634
- // so its glob-loader watcher would otherwise fire on every write Astro
3635
- // makes under .blume/.astro (data-store.json, content module manifests,
3636
- // self-hosted fonts) -- pure noise the loader logs as "No entry type
3637
- // found". Vite appends this to its default ignores.
3638
- watch: {
3639
- ignored: ${JSON.stringify([join8(context.outDir, ".astro", "**")])},
3640
- },
3651
+ },${watchOption}
3641
3652
  },
3642
3653
  },
3643
3654
  });
3644
3655
  `;
3645
3656
  };
3646
3657
  var stagedContentDir = (outDir) => join8(outDir, "content");
3658
+ var runtimeDirWithin = (base, outDir) => {
3659
+ const rel = relative5(base, outDir);
3660
+ return rel && !rel.startsWith("..") && !isAbsolute(rel) ? rel : null;
3661
+ };
3647
3662
  var astroGlobBase = (base) => isAbsolute(base) ? pathToFileURL(base).href : base;
3648
3663
  var contentConfigTemplate = (options) => {
3649
3664
  const { context, config } = options;
@@ -3651,8 +3666,8 @@ var contentConfigTemplate = (options) => {
3651
3666
  const collectionBase = options.collection?.base ?? context.contentRoot;
3652
3667
  const includeGlobs = options.collection?.include ?? config.content.include;
3653
3668
  const excludeGlobs = options.collection?.exclude ?? config.content.exclude;
3654
- const outDirRel = relative5(collectionBase, context.outDir);
3655
- const outDirIgnore = outDirRel && !outDirRel.startsWith("..") && !isAbsolute(outDirRel) ? [`!${outDirRel}/**`] : [];
3669
+ const outDirRel = runtimeDirWithin(collectionBase, context.outDir);
3670
+ const outDirIgnore = outDirRel ? [`!${outDirRel}/**`] : [];
3656
3671
  const filesystem = options.filesystem ?? true;
3657
3672
  const docsPattern = filesystem ? [
3658
3673
  ...includeGlobs,
@@ -5125,6 +5140,10 @@ var crawlStaticDir = async (options) => {
5125
5140
  };
5126
5141
 
5127
5142
  // src/audit/redirects.ts
5143
+ var pathOnly = (value) => {
5144
+ const cut = value.search(/[?#]/u);
5145
+ return cut === -1 ? value : value.slice(0, cut);
5146
+ };
5128
5147
  var resolveRedirects = (redirects, pageUrls) => {
5129
5148
  const byFrom = new Map;
5130
5149
  for (const redirect of redirects) {
@@ -5140,7 +5159,7 @@ var resolveRedirects = (redirects, pageUrls) => {
5140
5159
  chain.push(current);
5141
5160
  break;
5142
5161
  }
5143
- const next = normalizePath(current);
5162
+ const next = normalizePath(pathOnly(current));
5144
5163
  if (seen.has(next)) {
5145
5164
  chain.push(next);
5146
5165
  return {
@@ -5222,8 +5241,9 @@ var matches = (id, terms) => {
5222
5241
  var runAudit = async (options) => {
5223
5242
  const { project } = options;
5224
5243
  const staticDir = deployStaticDir(project.config, project.context);
5244
+ const basePath = normalizeBasePath(project.config.basePath);
5225
5245
  const crawl = await crawlStaticDir({
5226
- basePath: normalizeBasePath(project.config.basePath),
5246
+ basePath,
5227
5247
  manifest: project.manifest,
5228
5248
  staticDir
5229
5249
  });
@@ -5240,7 +5260,11 @@ var runAudit = async (options) => {
5240
5260
  origin,
5241
5261
  pages: crawl.pages,
5242
5262
  project,
5243
- redirects: resolveRedirects(project.config.redirects, new Set([...byUrl.keys(), ...crawl.files.keys()].map((path) => normalizePath(path)))),
5263
+ redirects: resolveRedirects(project.config.redirects.map((redirect) => ({
5264
+ ...redirect,
5265
+ from: withBasePath(basePath, redirect.from),
5266
+ to: withBasePath(basePath, redirect.to)
5267
+ })), new Set([...byUrl.keys(), ...crawl.files.keys()].map((path) => normalizePath(path)))),
5244
5268
  robots: crawl.robots,
5245
5269
  sitemap: crawl.sitemap,
5246
5270
  sources: await readSources(crawl.pages),
@@ -8191,9 +8215,10 @@ var detectLocale = (parts, i18n) => {
8191
8215
  var localePlacement = (rel, ext, i18n) => {
8192
8216
  const base = rel.slice(0, rel.length - ext.length);
8193
8217
  if (base.endsWith(".$")) {
8218
+ const shared = `${base.slice(0, -2)}${ext}`;
8194
8219
  return {
8195
8220
  locales: i18n.locales.map((locale2) => locale2.code),
8196
- navPath: `${base.slice(0, -2)}${ext}`
8221
+ navPath: i18n.parser === "dir" ? detectLocale(shared.split("/"), i18n).rest.join("/") : shared
8197
8222
  };
8198
8223
  }
8199
8224
  if (i18n.parser === "dot") {
@@ -8673,7 +8698,8 @@ var normalizeRef = (ref) => {
8673
8698
  return "/";
8674
8699
  }
8675
8700
  const withSlash = ref.startsWith("/") ? ref : `/${ref}`;
8676
- const trimmed = withSlash.endsWith("/index") ? withSlash.slice(0, -"/index".length) : withSlash;
8701
+ const noTrailing = withSlash.replace(/\/+$/u, "");
8702
+ const trimmed = noTrailing.endsWith("/index") ? noTrailing.slice(0, -"/index".length) : noTrailing;
8677
8703
  return trimmed === "" ? "/" : trimmed;
8678
8704
  };
8679
8705
  var routeForRef = (ref, byRoute, basePath) => {
@@ -8880,7 +8906,10 @@ var buildLocaleNavigation = (code, pages, fallback, fallbackByKey, options, i18n
8880
8906
  basePath: options.basePath ?? "",
8881
8907
  diagnostics,
8882
8908
  display: options.navigation.sidebar.display,
8883
- featured: options.navigation.featured,
8909
+ featured: options.navigation.featured?.map((link) => ({
8910
+ ...link,
8911
+ href: localizePath(link.href)
8912
+ })),
8884
8913
  folderMeta: options.folderMeta,
8885
8914
  localizedRoot: localizeRoute("/", code, i18n),
8886
8915
  metaPrefix: i18n.parser === "dir" && code !== i18n.defaultLocale ? code : "",
@@ -9176,6 +9205,7 @@ var WORD_SPLIT2 = /[-_]/u;
9176
9205
  var stripNumericPrefix = (segment) => segment.replace(NUMERIC_PREFIX2, "");
9177
9206
  var groupLabel = (segment) => segment.match(GROUP_FOLDER2)?.groups?.label ?? null;
9178
9207
  var slugify2 = (text) => text.toLowerCase().trim().replaceAll(/[^\w\s-]/gu, "").replaceAll(/[\s_]+/gu, "-").replaceAll(/-+/gu, "-").replaceAll(/^-|-$/gu, "");
9208
+ var slugifyPath = (text) => text.split("/").map(slugify2).filter(Boolean).join("/");
9179
9209
  var titleCase = (value) => value.split(WORD_SPLIT2).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
9180
9210
  var addRouteSegment = (part, segments, groups) => {
9181
9211
  if (part === "") {
@@ -9205,11 +9235,18 @@ var mapRoute = (relativePath) => {
9205
9235
  };
9206
9236
  var CODE_FENCE = /^(?<delimiter>```|~~~)/u;
9207
9237
  var nextFenceState = (line, fence) => {
9208
- const delimiter = line.trimStart().match(CODE_FENCE)?.groups?.delimiter;
9238
+ const trimmed = line.trimStart();
9239
+ const delimiter = trimmed.match(CODE_FENCE)?.groups?.delimiter;
9209
9240
  if (delimiter === undefined) {
9210
9241
  return fence;
9211
9242
  }
9212
9243
  if (fence === null) {
9244
+ if (delimiter === "```") {
9245
+ const run = trimmed.match(/^`+/u)?.[0].length ?? 0;
9246
+ if (trimmed.slice(run).includes("`")) {
9247
+ return fence;
9248
+ }
9249
+ }
9213
9250
  return delimiter;
9214
9251
  }
9215
9252
  return fence === delimiter ? null : fence;
@@ -9227,6 +9264,9 @@ var linesWithoutFrontMatter = (body) => {
9227
9264
  if (!/^-{3}\s*$/u.test(lines[0] ?? "")) {
9228
9265
  return lines;
9229
9266
  }
9267
+ if ((lines[1] ?? "").trim() === "") {
9268
+ return lines;
9269
+ }
9230
9270
  const close = lines.findIndex((line, index) => index > 0 && FRONT_MATTER_CLOSE.test(line));
9231
9271
  return close === -1 ? lines : lines.slice(close + 1);
9232
9272
  };
@@ -9306,8 +9346,10 @@ var extractHeadings = (body) => {
9306
9346
  }
9307
9347
  return headings;
9308
9348
  };
9309
- var MD_LINK = /\[[^\]]*\]\((?<target>[^)\s]+)(?:\s+"[^"]*")?\)/gu;
9349
+ var MD_LINK = /\[(?<label>(?:[^[\]]|\[[^\]]*\])*)\]\((?<target>(?:[^()\s]|\([^()\s]*\))+)(?<title>\s+"[^"]*")?\)/gu;
9350
+ var MD_IMAGE = /!\[[^\]]*\]\((?<target>(?:[^()\s]|\([^()\s]*\))+)(?<title>\s+"[^"]*")?\)/gu;
9310
9351
  var INLINE_CODE = /`[^`]*`/gu;
9352
+ var targetOffsetIn = (matched, target, title) => matched.length - 1 - (title?.length ?? 0) - target.length;
9311
9353
  var scanLinkLine = (line, lineNumber, fence, links) => {
9312
9354
  const next = nextFenceState(line, fence);
9313
9355
  if (fence !== null || next !== null) {
@@ -9319,12 +9361,24 @@ var scanLinkLine = (line, lineNumber, fence, links) => {
9319
9361
  if (target === undefined || match.index === undefined) {
9320
9362
  continue;
9321
9363
  }
9322
- const targetOffset = match.index + match[0].indexOf("](") + "](".length;
9364
+ const targetOffset = targetOffsetIn(match[0], target, match.groups?.title);
9323
9365
  links.push({
9324
- column: targetOffset + 1,
9366
+ column: match.index + targetOffset + 1,
9325
9367
  line: lineNumber,
9326
9368
  target
9327
9369
  });
9370
+ const label = match[0].slice(0, targetOffset - "](".length);
9371
+ for (const image of label.matchAll(MD_IMAGE)) {
9372
+ const imageTarget = image.groups?.target;
9373
+ if (imageTarget === undefined || image.index === undefined) {
9374
+ continue;
9375
+ }
9376
+ links.push({
9377
+ column: match.index + image.index + targetOffsetIn(image[0], imageTarget, image.groups?.title) + 1,
9378
+ line: lineNumber,
9379
+ target: imageTarget
9380
+ });
9381
+ }
9328
9382
  }
9329
9383
  return next;
9330
9384
  };
@@ -9598,6 +9652,24 @@ var operationKey = (method, path, operationId) => {
9598
9652
  return fromId || slugify3(`${method}-${path}`);
9599
9653
  };
9600
9654
  var isOperation = (value) => typeof value === "object" && value !== null;
9655
+ var tagSlugger = () => {
9656
+ const assigned = new Map;
9657
+ const taken = new Set;
9658
+ return (name) => {
9659
+ const existing = assigned.get(name);
9660
+ if (existing) {
9661
+ return existing;
9662
+ }
9663
+ const base = slugify3(name) || "operations";
9664
+ let slug = base;
9665
+ for (let suffix = 2;taken.has(slug); suffix += 1) {
9666
+ slug = `${base}-${suffix}`;
9667
+ }
9668
+ taken.add(slug);
9669
+ assigned.set(name, slug);
9670
+ return slug;
9671
+ };
9672
+ };
9601
9673
  var extractOperations = (document, baseRoute) => {
9602
9674
  const operations = [];
9603
9675
  const tagOrder = [];
@@ -9605,6 +9677,7 @@ var extractOperations = (document, baseRoute) => {
9605
9677
  const tagMeta = new Map((document.tags ?? []).map((tag) => [tag.name, tag.description ?? ""]));
9606
9678
  const seen = new Set;
9607
9679
  const warnings = [];
9680
+ const slugForTag = tagSlugger();
9608
9681
  for (const [path, rawItem] of Object.entries(document.paths ?? {})) {
9609
9682
  const item = rawItem;
9610
9683
  if (!item) {
@@ -9620,7 +9693,7 @@ var extractOperations = (document, baseRoute) => {
9620
9693
  continue;
9621
9694
  }
9622
9695
  const tag = operation.tags?.[0] ?? UNTAGGED;
9623
- const tagSlug = slugify3(tag) || "operations";
9696
+ const tagSlug = slugForTag(tag);
9624
9697
  if (!tagsSeen.has(tag)) {
9625
9698
  tagsSeen.add(tag);
9626
9699
  tagOrder.push(tag);
@@ -9647,7 +9720,7 @@ var extractOperations = (document, baseRoute) => {
9647
9720
  const tags = tagOrder.map((name) => ({
9648
9721
  description: tagMeta.get(name) ?? "",
9649
9722
  name,
9650
- slug: slugify3(name) || "operations"
9723
+ slug: slugForTag(name)
9651
9724
  }));
9652
9725
  return { operations, tags, warnings };
9653
9726
  };
@@ -9797,15 +9870,14 @@ var parseSpec = async (spec, root, options = {}) => {
9797
9870
  };
9798
9871
 
9799
9872
  // src/openapi/render-mdx.ts
9800
- var MDX_UNSAFE = /[<>{}]/gu;
9873
+ var MDX_UNSAFE = /[<{}]/gu;
9801
9874
  var ENTITIES = {
9802
9875
  "<": "&lt;",
9803
- ">": "&gt;",
9804
9876
  "{": "&#123;",
9805
9877
  "}": "&#125;"
9806
9878
  };
9807
9879
  var MDX_ESM_KEYWORD = /^(?<keyword>import|export)\b/gmu;
9808
- var BACKTICK_CODE = /(?<bt>`+)[\s\S]*?\k<bt>/gu;
9880
+ var BACKTICK_CODE = /(?<!`)(?<bt>`+)(?!`)[\s\S]*?(?<!`)\k<bt>(?!`)/gu;
9809
9881
  var escapeProse = (text) => text.replace(MDX_UNSAFE, (char) => ENTITIES[char] ?? char).replace(MDX_ESM_KEYWORD, (keyword) => `&#${keyword.codePointAt(0)};${keyword.slice(1)}`);
9810
9882
  var mdxSafe = (text) => {
9811
9883
  let out = "";
@@ -10417,7 +10489,7 @@ import { join as join15 } from "pathe";
10417
10489
  // src/core/sources/assets.ts
10418
10490
  import { mkdir as mkdir5, writeFile as writeFile5 } from "node:fs/promises";
10419
10491
  import { extname as extname4, join as join14 } from "pathe";
10420
- var MD_IMAGE = /!\[(?<alt>[^\]]*)\]\((?<url>[^)\s]+)\)/gu;
10492
+ var MD_IMAGE2 = /!\[(?<alt>[^\]]*)\]\((?<url>[^)\s]+)\)/gu;
10421
10493
  var REMOTE = /^https?:\/\//u;
10422
10494
  var SAFE_EXT = /^\.[a-z0-9]+$/iu;
10423
10495
  var CODE_FENCE_BLOCK = /^(?<fence>`{3,}|~{3,})[^\n]*\n[\s\S]*?^\k<fence>[^\n]*(?=\n|$)/gmu;
@@ -10436,7 +10508,7 @@ var materializeAssets = async (markdown, ctx) => {
10436
10508
  return `\x00blume-fence-${fences.length - 1}\x00`;
10437
10509
  });
10438
10510
  const urls = new Set;
10439
- for (const match of masked.matchAll(MD_IMAGE)) {
10511
+ for (const match of masked.matchAll(MD_IMAGE2)) {
10440
10512
  const url = match.groups?.url;
10441
10513
  if (url && REMOTE.test(url)) {
10442
10514
  urls.add(url);
@@ -10462,7 +10534,7 @@ var materializeAssets = async (markdown, ctx) => {
10462
10534
  });
10463
10535
  }
10464
10536
  }));
10465
- const rewritten = masked.replaceAll(MD_IMAGE, (match, alt, url) => {
10537
+ const rewritten = masked.replaceAll(MD_IMAGE2, (match, alt, url) => {
10466
10538
  const local = rewrites.get(url);
10467
10539
  return local ? `![${alt}](${local})` : match;
10468
10540
  }).replaceAll(FENCE_TOKEN, (token, index) => fences[Number(index)] ?? token);
@@ -10697,7 +10769,7 @@ ${nested}`;
10697
10769
  data.sidebar = { order };
10698
10770
  }
10699
10771
  const slugProp = richToMarkdown(page.properties[props.slug ?? "Slug"]?.rich_text);
10700
- const slug = slugify2(slugProp || title) || page.id;
10772
+ const slug = slugifyPath(slugProp || title) || page.id;
10701
10773
  return { data, slug };
10702
10774
  };
10703
10775
  const toEntry2 = async (client, page) => {
@@ -10904,7 +10976,7 @@ var sanitySource = (options, ctx) => {
10904
10976
  let snapshot = new Map;
10905
10977
  const toEntry2 = (doc) => {
10906
10978
  const slugValue = asString(getPath(doc, fields.slug ?? "slug.current")) ?? asString(doc._id) ?? "untitled";
10907
- const slug = slugify2(slugValue) || slugify2(asString(doc._id) ?? "") || "untitled";
10979
+ const slug = slugifyPath(slugValue) || slugify2(asString(doc._id) ?? "") || "untitled";
10908
10980
  const data = {};
10909
10981
  const title = asString(getPath(doc, fields.title ?? "title"));
10910
10982
  const description = asString(getPath(doc, fields.description ?? "description"));
@@ -11264,6 +11336,16 @@ var shouldFail = (result, gate) => {
11264
11336
  const failing = failingSeverities(gate);
11265
11337
  return result.diagnostics.some((d) => failing.has(d.severity));
11266
11338
  };
11339
+ var launchAgentCode = async (bin, prompt) => {
11340
+ try {
11341
+ return await launchAgent(bin, prompt);
11342
+ } catch (error) {
11343
+ if (error?.code !== "ENOENT") {
11344
+ throw error;
11345
+ }
11346
+ return WINDOWS_COMMAND_NOT_FOUND;
11347
+ }
11348
+ };
11267
11349
  var auditCommand = defineCommand2({
11268
11350
  args: {
11269
11351
  claude: {
@@ -11369,12 +11451,7 @@ var auditCommand = defineCommand2({
11369
11451
  process.stderr.write(` Handing ${count} finding${count === 1 ? "" : "s"} to ${cli.name}…
11370
11452
 
11371
11453
  `);
11372
- let code;
11373
- try {
11374
- code = await launchAgent(cli.bin, fixPrompt(report));
11375
- } catch {
11376
- code = WINDOWS_COMMAND_NOT_FOUND;
11377
- }
11454
+ const code = await launchAgentCode(cli.bin, fixPrompt(report));
11378
11455
  if (code === WINDOWS_COMMAND_NOT_FOUND) {
11379
11456
  logger.error(`${cli.name} (\`${cli.bin}\`) was not found on PATH. Install it with \`${cli.install}\`.`);
11380
11457
  process.exit(1);
@@ -12577,6 +12654,7 @@ import {
12577
12654
  lstat,
12578
12655
  mkdir as mkdir6,
12579
12656
  readFile as readFile14,
12657
+ readlink,
12580
12658
  realpath,
12581
12659
  rename,
12582
12660
  rm as rm2,
@@ -12585,7 +12663,7 @@ import {
12585
12663
  } from "node:fs/promises";
12586
12664
  import { createRequire as createRequire5 } from "node:module";
12587
12665
  import { pathToFileURL as pathToFileURL3 } from "node:url";
12588
- import { basename as basename3, dirname as dirname9, join as join26, normalize as normalize3, relative as relative13 } from "pathe";
12666
+ import { basename as basename3, dirname as dirname9, join as join26, normalize as normalize3, relative as relative13, resolve as resolve7 } from "pathe";
12589
12667
  import { glob as glob7 } from "tinyglobby";
12590
12668
 
12591
12669
  // src/ai/ask-data.ts
@@ -14485,12 +14563,12 @@ var canResolveFrom = (fromDir, spec) => {
14485
14563
  return false;
14486
14564
  }
14487
14565
  };
14488
- var resolveReactCompiler = (config, needsReact) => {
14566
+ var resolveReactCompiler = (config, needsReact, pkgDir = packageRoot()) => {
14489
14567
  if (!(needsReact && config.react.compiler)) {
14490
14568
  return null;
14491
14569
  }
14492
14570
  try {
14493
- return createRequire5(pathToFileURL3(join26(packageRoot(), "_.js")).href).resolve("babel-plugin-react-compiler");
14571
+ return createRequire5(pathToFileURL3(join26(pkgDir, "_.js")).href).resolve("babel-plugin-react-compiler");
14494
14572
  } catch {
14495
14573
  return null;
14496
14574
  }
@@ -14543,6 +14621,11 @@ var linkDepsJunction = async (link, depsDir) => {
14543
14621
  if (!existing.isSymbolicLink()) {
14544
14622
  return;
14545
14623
  }
14624
+ try {
14625
+ if (resolve7(dirname9(link), await readlink(link)) === resolve7(depsDir)) {
14626
+ return;
14627
+ }
14628
+ } catch {}
14546
14629
  await rm2(link, { force: true });
14547
14630
  }
14548
14631
  await mkdir6(dirname9(link), { recursive: true });
@@ -14634,6 +14717,15 @@ var deploymentAdapterWarnings = (deployment, root) => {
14634
14717
  }
14635
14718
  return [];
14636
14719
  };
14720
+ var searchProviderWarnings = (provider, root, pkgDir = packageRoot()) => {
14721
+ const warnings = [];
14722
+ for (const dep of searchProviderMeta(provider).runtimeDeps) {
14723
+ if (!(canResolveFrom(root, dep) || canResolveFrom(pkgDir, dep))) {
14724
+ warnings.push(`Search provider "${provider}" needs "${dep}", which isn't installed. Run \`npm install ${dep}\` (or your package manager's equivalent).`);
14725
+ }
14726
+ }
14727
+ return warnings;
14728
+ };
14637
14729
  var examplesCssFile = (root, config) => config.examples.css ? join26(root, config.examples.css) : null;
14638
14730
  var writeExamplesPreview = async (options) => {
14639
14731
  const { config, hasExamples, root, srcDir, write } = options;
@@ -14896,6 +14988,7 @@ var buildRuntimeData = (project) => {
14896
14988
  basePath: config.basePath,
14897
14989
  codeThemes: config.markdown.codeBlocks.theme,
14898
14990
  codeWrap: config.markdown.code.wrap,
14991
+ dateFormat: config.dateFormat,
14899
14992
  description: config.description,
14900
14993
  favicon: resolveFavicon(project),
14901
14994
  feedback: config.feedback,
@@ -15038,6 +15131,7 @@ var writeNotFoundPage = async (write, srcDir, pages, contentPages) => {
15038
15131
  }
15039
15132
  await write(join26(srcDir, "pages", "404.astro"), notFoundPageTemplate());
15040
15133
  };
15134
+ var diagnosticWarning = (diagnostic) => diagnostic.suggestion ? `${diagnostic.message} ${diagnostic.suggestion}` : diagnostic.message;
15041
15135
  var buildComponentSlots = async (componentsFile) => {
15042
15136
  const analysis = componentsFile ? analyzeComponentOverrides(await readFile14(componentsFile, "utf-8"), componentsFile) : null;
15043
15137
  return {
@@ -15046,6 +15140,7 @@ var buildComponentSlots = async (componentsFile) => {
15046
15140
  warnings: analysis ? analysis.warnings : []
15047
15141
  };
15048
15142
  };
15143
+ var contentWatchesRuntimeDir = (hasFilesystemSource, collectionBase, context) => hasFilesystemSource && runtimeDirWithin(collectionBase, context.outDir) !== null;
15049
15144
  var generateRuntime = async (project) => {
15050
15145
  const { context, config } = project;
15051
15146
  const out = context.outDir;
@@ -15106,6 +15201,7 @@ var generateRuntime = async (project) => {
15106
15201
  pages.push(...mcp.discoveryPages);
15107
15202
  const hasStaged = staged.size > 0;
15108
15203
  const hasFilesystemSource = project.sources.some((source) => !source.staged);
15204
+ const docsCollection = resolveDocsCollection(config, context);
15109
15205
  const [structural] = await Promise.all([
15110
15206
  Promise.all([
15111
15207
  write(join26(out, "astro.config.mjs"), astroConfigTemplate({
@@ -15113,6 +15209,7 @@ var generateRuntime = async (project) => {
15113
15209
  askPath,
15114
15210
  config,
15115
15211
  contentRoutes: project.manifest.routes.map((route) => route.path),
15212
+ contentWatchesRuntimeDir: contentWatchesRuntimeDir(hasFilesystemSource, docsCollection.base, context),
15116
15213
  context,
15117
15214
  dataPath,
15118
15215
  examplesPath,
@@ -15130,7 +15227,7 @@ var generateRuntime = async (project) => {
15130
15227
  write(join26(out, "tsconfig.json"), runtimeTsconfigTemplate()),
15131
15228
  write(join26(srcDir, "env.d.ts"), envTemplate()),
15132
15229
  write(join26(srcDir, "content.config.ts"), contentConfigTemplate({
15133
- collection: resolveDocsCollection(config, context),
15230
+ collection: docsCollection,
15134
15231
  config,
15135
15232
  context,
15136
15233
  filesystem: hasFilesystemSource,
@@ -15234,18 +15331,12 @@ var generateRuntime = async (project) => {
15234
15331
  warnings.push(...[
15235
15332
  ...validateNavTargets(project.graph.navigation, navTargetRoutes),
15236
15333
  ...validateSearchPopularIcons(config.search.popular)
15237
- ].map((diagnostic) => diagnostic.suggestion ? `${diagnostic.message} ${diagnostic.suggestion}` : diagnostic.message));
15334
+ ].map(diagnosticWarning));
15238
15335
  const knownComponentTags = new Set([
15239
15336
  ...islandDiscovery.islands.map((island) => island.name),
15240
15337
  ...overrideTags
15241
15338
  ]);
15242
- warnings.push(...validateUsedComponents(project.graph.pages, knownComponentTags, new Set(registry.map((item) => item.name))).map((diagnostic) => diagnostic.suggestion ? `${diagnostic.message} ${diagnostic.suggestion}` : diagnostic.message));
15243
- for (const dep of searchProviderMeta(config.search.provider).runtimeDeps) {
15244
- if (!(canResolveFrom(context.root, dep) || canResolveFrom(packageRoot(), dep))) {
15245
- warnings.push(`Search provider "${config.search.provider}" needs "${dep}", which isn't installed. Run \`npm install ${dep}\` (or your package manager's equivalent).`);
15246
- }
15247
- }
15248
- warnings.push(...deploymentAdapterWarnings(config.deployment, context.root), ...islandFrameworkWarnings(frameworks, context.root));
15339
+ warnings.push(...validateUsedComponents(project.graph.pages, knownComponentTags, new Set(registry.map((item) => item.name))).map(diagnosticWarning), ...searchProviderWarnings(config.search.provider, context.root), ...deploymentAdapterWarnings(config.deployment, context.root), ...islandFrameworkWarnings(frameworks, context.root));
15249
15340
  if (hasScalarReferences(config)) {
15250
15341
  const references = await buildReferenceFiles({
15251
15342
  config,
@@ -15270,7 +15361,7 @@ var generateRuntime = async (project) => {
15270
15361
 
15271
15362
  // src/cli/env.ts
15272
15363
  import { existsSync as existsSync15, readFileSync as readFileSync10 } from "node:fs";
15273
- import { dirname as dirname10, join as join27, resolve as resolve7 } from "pathe";
15364
+ import { dirname as dirname10, join as join27, resolve as resolve8 } from "pathe";
15274
15365
  var ENV_LINE = /^\s*(?:export\s+)?(?<key>[A-Za-z_][A-Za-z0-9_]*)\s*=\s*(?<value>.*?)\s*$/u;
15275
15366
  var DOUBLE_QUOTED2 = /^"(?<body>[\s\S]*)"$/u;
15276
15367
  var SINGLE_QUOTED = /^'(?<body>[\s\S]*)'$/u;
@@ -15322,7 +15413,7 @@ var loadFile = (path) => {
15322
15413
  } catch {}
15323
15414
  };
15324
15415
  var loadEnvFiles = (startDir) => {
15325
- let dir = resolve7(startDir);
15416
+ let dir = resolve8(startDir);
15326
15417
  let done = false;
15327
15418
  while (!done) {
15328
15419
  loadFile(join27(dir, ".env.local"));
@@ -15764,6 +15855,7 @@ var checkCommand = defineCommand4({
15764
15855
  import { watch } from "node:fs";
15765
15856
  import { dev } from "astro";
15766
15857
  import { defineCommand as defineCommand5 } from "citty";
15858
+ import { basename as basename4, dirname as dirname11 } from "pathe";
15767
15859
 
15768
15860
  // src/astro/integration.ts
15769
15861
  var overlayServer = null;
@@ -15942,17 +16034,26 @@ var devCommand = defineCommand5({
15942
16034
  if (boundPort !== port) {
15943
16035
  runRegenerate();
15944
16036
  }
16037
+ const dirTargets = [project.context.pagesRoot].filter((target) => target !== null);
15945
16038
  const fileTargets = [
15946
- project.context.pagesRoot,
15947
16039
  project.context.configFile,
15948
16040
  project.context.themeFile,
15949
16041
  project.context.componentsFile
15950
16042
  ].filter((target) => target !== null);
15951
16043
  const disposers = [
15952
16044
  ...project.sources.map((source) => source.watch?.(regenerate)),
15953
- ...fileTargets.map((target) => {
16045
+ ...dirTargets.map((target) => {
15954
16046
  const watcher = watch(target, { recursive: true }, regenerate);
15955
16047
  return () => watcher.close();
16048
+ }),
16049
+ ...fileTargets.map((target) => {
16050
+ const name = basename4(target);
16051
+ const watcher = watch(dirname11(target), (_event, filename) => {
16052
+ if (!filename || filename === name) {
16053
+ regenerate();
16054
+ }
16055
+ });
16056
+ return () => watcher.close();
15956
16057
  })
15957
16058
  ].filter((dispose) => dispose !== undefined);
15958
16059
  const shutdown = async () => {
@@ -16473,7 +16574,7 @@ var updatePackageScripts = async (root) => {
16473
16574
  // src/cli/init/scaffold.ts
16474
16575
  import { existsSync as existsSync19 } from "node:fs";
16475
16576
  import { mkdir as mkdir8, writeFile as writeFile11 } from "node:fs/promises";
16476
- import { basename as basename4, dirname as dirname11, isAbsolute as isAbsolute9, join as join33, relative as relative15 } from "pathe";
16577
+ import { basename as basename5, dirname as dirname12, isAbsolute as isAbsolute9, join as join33, relative as relative15 } from "pathe";
16477
16578
 
16478
16579
  // src/core/package-json.ts
16479
16580
  var toPackageName = (raw) => raw.toLowerCase().replaceAll(/[^a-z0-9._-]+/gu, "-").replaceAll(/^[-_.]+|[-_.]+$/gu, "") || "docs";
@@ -16683,7 +16784,7 @@ var extraDepsFor = (sources) => ({
16683
16784
  var buildPlan = (root, answers) => {
16684
16785
  const files = [
16685
16786
  {
16686
- content: blumePackageJson(toPackageName(basename4(root)), extraDepsFor(answers.sources)),
16787
+ content: blumePackageJson(toPackageName(basename5(root)), extraDepsFor(answers.sources)),
16687
16788
  path: join33(root, "package.json")
16688
16789
  },
16689
16790
  { content: buildConfig(answers), path: join33(root, "blume.config.ts") }
@@ -16698,14 +16799,14 @@ var writeFileSafe = async (file, log) => {
16698
16799
  log.info(`Skipped existing ${file.path}`);
16699
16800
  return false;
16700
16801
  }
16701
- await mkdir8(dirname11(file.path), { recursive: true });
16802
+ await mkdir8(dirname12(file.path), { recursive: true });
16702
16803
  await writeFile11(file.path, file.content, "utf-8");
16703
16804
  log.success(`Created ${file.path}`);
16704
16805
  return true;
16705
16806
  };
16706
16807
  var applyPlan = async (files, log) => {
16707
16808
  const created = await Promise.all(files.map((file) => writeFileSafe(file, log)));
16708
- const createdPackage = files.some((file, index) => created[index] && basename4(file.path) === "package.json");
16809
+ const createdPackage = files.some((file, index) => created[index] && basename5(file.path) === "package.json");
16709
16810
  return { createdPackage };
16710
16811
  };
16711
16812
  var envVarsFor = (sources) => [
@@ -16792,10 +16893,10 @@ The blume package remains importable.`);
16792
16893
  // src/cli/commands/init.ts
16793
16894
  import * as clack from "@clack/prompts";
16794
16895
  import { defineCommand as defineCommand8 } from "citty";
16795
- import { resolve as resolve9 } from "pathe";
16896
+ import { resolve as resolve10 } from "pathe";
16796
16897
 
16797
16898
  // src/cli/init/questions.ts
16798
- import { basename as basename5, resolve as resolve8 } from "pathe";
16899
+ import { basename as basename6, resolve as resolve9 } from "pathe";
16799
16900
  var cancelled = (value) => typeof value === "symbol";
16800
16901
  var collectAnswers = async (prompter, flags, defaults) => {
16801
16902
  const directory = flags.directory ?? await prompter.text({
@@ -16806,9 +16907,9 @@ var collectAnswers = async (prompter, flags, defaults) => {
16806
16907
  if (cancelled(directory)) {
16807
16908
  return null;
16808
16909
  }
16809
- const root = resolve8(defaults.cwd, directory);
16910
+ const root = resolve9(defaults.cwd, directory);
16810
16911
  const title = await prompter.text({
16811
- initialValue: titleize(basename5(root)),
16912
+ initialValue: titleize(basename6(root)),
16812
16913
  message: "What's your docs site called?",
16813
16914
  validate: (value) => value?.trim() ? undefined : "Give your docs site a name."
16814
16915
  });
@@ -16975,7 +17076,7 @@ var initCommand = defineCommand8({
16975
17076
  title: "My Docs"
16976
17077
  };
16977
17078
  }
16978
- const root = resolve9(cwd, answers.directory);
17079
+ const root = resolve10(cwd, answers.directory);
16979
17080
  if (validateContentDir(root, answers.contentDir) !== undefined) {
16980
17081
  logger.error(`Invalid --content-dir "${answers.contentDir}" (must be a path inside the project).`);
16981
17082
  process.exit(1);
@@ -17082,7 +17183,7 @@ import { join as join37 } from "pathe";
17082
17183
 
17083
17184
  // src/core/links.ts
17084
17185
  import { existsSync as existsSync21 } from "node:fs";
17085
- import { basename as basename6, join as join36 } from "pathe";
17186
+ import { basename as basename7, join as join36 } from "pathe";
17086
17187
  var HTTP = /^https?:\/\//iu;
17087
17188
  var PROTOCOL_RELATIVE = /^\/\//u;
17088
17189
  var SCHEME = /^[a-z][a-z0-9+.-]*:/iu;
@@ -17097,7 +17198,7 @@ var DOC_EXT = /\.(?:md|mdx)$/iu;
17097
17198
  var FILE_EXT = /\.[a-z0-9]+$/iu;
17098
17199
  var assetIsPresent = (resolved, ctx) => ctx.publicDir !== null && existsSync21(join36(ctx.publicDir, resolved));
17099
17200
  var NUMERIC_PREFIX3 = /^\d+[-_.]/u;
17100
- var isIndexPage = (page2) => /^index\.(?:md|mdx)$/iu.test(basename6(page2.navPath).replace(NUMERIC_PREFIX3, ""));
17201
+ var isIndexPage = (page2) => /^index\.(?:md|mdx)$/iu.test(basename7(page2.navPath).replace(NUMERIC_PREFIX3, ""));
17101
17202
  var applyRelativePart = (segments, part) => {
17102
17203
  if (part === "" || part === ".") {
17103
17204
  return;
@@ -17373,5 +17474,5 @@ process.on("unhandledRejection", (error) => {
17373
17474
  });
17374
17475
  runMain(main);
17375
17476
 
17376
- //# debugId=74F150F28E9B859A64756E2164756E21
17477
+ //# debugId=5D342B2E16EE6E0464756E2164756E21
17377
17478
  //# sourceMappingURL=index.js.map