boltdocs 3.3.4 → 3.3.6

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 (79) hide show
  1. package/dist/{build-COgv-rkY.mjs → build-BJnL-FHG.mjs} +1 -1
  2. package/dist/{build-1CsvBIsN.cjs → build-CxT38vPv.cjs} +1 -1
  3. package/dist/client/index.cjs +80 -32
  4. package/dist/client/index.d.cts +1 -1
  5. package/dist/client/index.d.ts +1 -1
  6. package/dist/client/index.js +78 -31
  7. package/dist/client/mdx.cjs +1 -1
  8. package/dist/client/mdx.js +1 -1
  9. package/dist/client/primitives.cjs +4 -4
  10. package/dist/client/primitives.d.cts +40 -9
  11. package/dist/client/primitives.d.ts +40 -9
  12. package/dist/client/primitives.js +4 -4
  13. package/dist/config-B3_iVsbi.mjs +7 -0
  14. package/dist/{config-PLvresCv.cjs → config-BC_qhXws.cjs} +1 -1
  15. package/dist/config-BJp3lGzE.cjs +7 -0
  16. package/dist/{dev-C_9iBwmu.cjs → dev-46NiL0MC.cjs} +1 -1
  17. package/dist/{dev-UWVM3ah-.mjs → dev-C4kjO5xs.mjs} +1 -1
  18. package/dist/{docs-layout-CbZ7LDRe.js → docs-layout-D3Fmb0Wd.js} +16 -117
  19. package/dist/{docs-layout-vzfXed1Q.cjs → docs-layout-SgphExoE.cjs} +16 -123
  20. package/dist/{doctor-DMECtdK6.cjs → doctor-BqxOFRt3.cjs} +1 -1
  21. package/dist/{doctor-i8Qmd8DJ.mjs → doctor-Cv5lXnay.mjs} +1 -1
  22. package/dist/{doctor-FuFY1jBz.cjs → doctor-TS3JGNEU.cjs} +1 -1
  23. package/dist/{image-B-NDSDuY.js → image-BAiDReNd.js} +1 -1
  24. package/dist/{image-Hnaa2bJd.cjs → image-Bkx85rsq.cjs} +1 -1
  25. package/dist/{index-Cg3TmXIZ.d.ts → index-B1Mx0dHl.d.ts} +30 -6
  26. package/dist/{index-CSiMUBhC.d.cts → index-DLaHgD-i.d.cts} +30 -6
  27. package/dist/{link-vZjmD-es.cjs → link-hLWOsx0x.cjs} +59 -28
  28. package/dist/{link-CgdI6O2o.js → link-q1qHNGK_.js} +54 -29
  29. package/dist/{mdx-BRT71V5Q.js → mdx-CJGWzBGy.js} +2 -2
  30. package/dist/{mdx-D0Absdq5.cjs → mdx-Qi0DmaY8.cjs} +2 -2
  31. package/dist/node/cli-entry.cjs +1 -1
  32. package/dist/node/cli-entry.mjs +1 -1
  33. package/dist/node/highlight.d.cts +2 -2
  34. package/dist/node/highlight.d.mts +2 -2
  35. package/dist/node/index.cjs +1 -1
  36. package/dist/node/index.d.cts +7 -4
  37. package/dist/node/index.d.mts +7 -4
  38. package/dist/node/index.mjs +1 -1
  39. package/dist/node/mdx/shiki-adapter.cjs +1 -1
  40. package/dist/node/mdx/shiki-adapter.d.cts +7 -2
  41. package/dist/node/mdx/shiki-adapter.d.mts +7 -2
  42. package/dist/node/mdx/shiki-adapter.mjs +1 -1
  43. package/dist/node-7Cfw6nMr.cjs +23 -0
  44. package/dist/node-CT2E84nY.mjs +23 -0
  45. package/dist/{package-Cwma8oO7.cjs → package-Bah2tHjK.cjs} +1 -1
  46. package/dist/{package-CKC-4LtU.mjs → package-D6bf68FR.mjs} +1 -1
  47. package/dist/plugin-AgNI3ktz.cjs +69 -0
  48. package/dist/plugin-BAv_pYLt.mjs +69 -0
  49. package/dist/{plugin-context-BxF88sW4.cjs → plugin-context-BZs5lvDu.cjs} +3 -3
  50. package/dist/{plugin-context-BKK-nfOd.mjs → plugin-context-b5qVVQSU.mjs} +2 -2
  51. package/dist/{plugin-lifecycle-BjMclfc3.cjs → plugin-lifecycle-s89gzTlh.cjs} +1 -1
  52. package/dist/{registry-BbB6NqSv.d.cts → registry-B8pt41zj.d.cts} +1 -1
  53. package/dist/{registry-sJqDv0kE.d.mts → registry-BrrH2X9c.d.mts} +1 -1
  54. package/dist/routes-CzhKOw67.cjs +6 -0
  55. package/dist/{routes-C3_w9fLX.cjs → routes-Dq_2EUIB.cjs} +1 -1
  56. package/dist/routes-Dw6g0bfF.mjs +6 -0
  57. package/dist/search-dialog-BYZS9aeO.cjs +747 -0
  58. package/dist/{search-dialog-x_qHU8ty.cjs → search-dialog-CguKVtUu.cjs} +145 -5
  59. package/dist/{search-dialog-MmwxFMmE.js → search-dialog-DQwod5Xc.js} +1 -1
  60. package/dist/search-dialog-DzObE-Ar.js +717 -0
  61. package/dist/{search-dialog-DmirOMPg.cjs → search-dialog-QgKRRbsI.cjs} +1 -1
  62. package/dist/{search-dialog-BqkzDTq2.js → search-dialog-mYnqU4v7.js} +134 -6
  63. package/dist/{types-Db6zToZH.d.mts → types-74i_xUe2.d.mts} +1 -1
  64. package/dist/{types-o7iZ2BAR.d.cts → types-X_Pwk8Cg.d.cts} +1 -1
  65. package/dist/virtual-modules-C3S3Nz8r.cjs +40 -0
  66. package/dist/virtual-modules-CaxqrFd6.mjs +40 -0
  67. package/package.json +4 -3
  68. package/dist/config-CrsQJHQz.cjs +0 -7
  69. package/dist/config-DC0nMMk7.mjs +0 -7
  70. package/dist/node-C3HctGaH.cjs +0 -23
  71. package/dist/node-CUiheODn.mjs +0 -23
  72. package/dist/plugin-BX6TXR8x.cjs +0 -69
  73. package/dist/plugin-C8UMIA-4.mjs +0 -69
  74. package/dist/routes-C0kb4ue6.cjs +0 -6
  75. package/dist/routes-C4wrLWwu.mjs +0 -6
  76. package/dist/search-dialog-D3jtaw6w.cjs +0 -525
  77. package/dist/search-dialog-DRiXejws.js +0 -501
  78. package/dist/virtual-modules-XBiJoTsp.mjs +0 -39
  79. package/dist/virtual-modules-hndVivLR.cjs +0 -39
@@ -4,7 +4,8 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  const require_router = require('./router-C3kygdRK.cjs');
7
- const require_link = require('./link-vZjmD-es.cjs');
7
+ const require_link = require('./link-hLWOsx0x.cjs');
8
+ const require_search_dialog = require('./search-dialog-CguKVtUu.cjs');
8
9
  let react = require("react");
9
10
  let react_jsx_runtime = require("react/jsx-runtime");
10
11
  let react_aria_components = require("react-aria-components");
@@ -254,9 +255,9 @@ function Tabs({ children, className = "", ...props }) {
254
255
  children
255
256
  });
256
257
  }
257
- function TabsList({ children, className = "" }) {
258
+ function TabsList({ children, className, role }) {
258
259
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
259
- role: "tablist",
260
+ role: role === null ? void 0 : role ?? "tablist",
260
261
  className: require_link.cn("relative flex flex-row items-center overflow-x-auto", className),
261
262
  children
262
263
  });
@@ -572,112 +573,6 @@ function useSidebar(routes) {
572
573
  };
573
574
  }
574
575
 
575
- //#endregion
576
- //#region src/client/hooks/use-search-highlight.ts
577
- /**
578
- * Hook to highlight search terms based on the 'hl' query parameter.
579
- */
580
- function useSearchHighlight(containerSelector = ".boltdocs-page") {
581
- const { search } = require_router.useLocation();
582
- const query = new URLSearchParams(search).get("hl");
583
- (0, react.useEffect)(() => {
584
- if (!query) {
585
- clearHighlights(containerSelector);
586
- return;
587
- }
588
- const container = document.querySelector(containerSelector);
589
- if (!container) return;
590
- let rafId;
591
- const observer = new MutationObserver((mutations) => {
592
- if (mutations.some((m) => {
593
- const addedNodes = Array.from(m.addedNodes);
594
- const removedNodes = Array.from(m.removedNodes);
595
- return addedNodes.some((n) => !(n instanceof HTMLElement && n.hasAttribute("data-search-highlight"))) || removedNodes.some((n) => !(n instanceof HTMLElement && n.hasAttribute("data-search-highlight")));
596
- })) run();
597
- });
598
- function run() {
599
- cancelAnimationFrame(rafId);
600
- rafId = requestAnimationFrame(() => {
601
- observer.disconnect();
602
- clearHighlights(containerSelector);
603
- const terms = query.split(/\s+/).map((t) => t.trim()).filter((t) => t.length >= 2);
604
- if (terms.length > 0) highlightTerms(container, terms);
605
- observer.observe(container, {
606
- childList: true,
607
- subtree: true
608
- });
609
- });
610
- }
611
- run();
612
- return () => {
613
- cancelAnimationFrame(rafId);
614
- observer.disconnect();
615
- clearHighlights(containerSelector);
616
- };
617
- }, [query, containerSelector]);
618
- }
619
- function clearHighlights(selector) {
620
- document.querySelectorAll(`${selector} mark[data-search-highlight]`).forEach((mark) => {
621
- try {
622
- const parent = mark.parentNode;
623
- if (parent && parent.contains(mark)) {
624
- const text = mark.textContent || "";
625
- parent.replaceChild(document.createTextNode(text), mark);
626
- }
627
- } catch (e) {}
628
- });
629
- }
630
- function highlightTerms(container, terms) {
631
- const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT, { acceptNode: (node) => {
632
- const parent = node.parentElement;
633
- if (parent && (parent.tagName === "SCRIPT" || parent.tagName === "STYLE" || parent.tagName === "MARK" || parent.closest("pre") || parent.closest("code"))) return NodeFilter.FILTER_REJECT;
634
- return NodeFilter.FILTER_ACCEPT;
635
- } });
636
- const nodes = [];
637
- let node = walker.nextNode();
638
- while (node) {
639
- nodes.push(node);
640
- node = walker.nextNode();
641
- }
642
- const accentMap = {
643
- a: "[aáàäâã]",
644
- e: "[eéèëê]",
645
- i: "[iíìïî]",
646
- o: "[oóòöôõ]",
647
- u: "[uúùüû]",
648
- n: "[nñ]",
649
- c: "[cç]"
650
- };
651
- const prepareRegex = (term) => {
652
- let pattern = term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
653
- pattern = pattern.split("").map((char) => {
654
- return accentMap[char.toLowerCase()] || char;
655
- }).join("");
656
- return pattern;
657
- };
658
- const combinedPattern = terms.map(prepareRegex).join("|");
659
- const regex = new RegExp(`(${combinedPattern})`, "gi");
660
- const matchRegexes = terms.map((term) => {
661
- const p = prepareRegex(term);
662
- return new RegExp(`^${p}$`, "i");
663
- });
664
- nodes.forEach((textNode) => {
665
- const text = textNode.textContent;
666
- if (text && regex.test(text)) {
667
- const fragment = document.createDocumentFragment();
668
- text.split(regex).forEach((part) => {
669
- if (matchRegexes.some((rx) => rx.test(part))) {
670
- const mark = document.createElement("mark");
671
- mark.textContent = part;
672
- mark.setAttribute("data-search-highlight", "true");
673
- fragment.appendChild(mark);
674
- } else if (part) fragment.appendChild(document.createTextNode(part));
675
- });
676
- if (textNode.parentNode) textNode.parentNode.replaceChild(fragment, textNode);
677
- }
678
- });
679
- }
680
-
681
576
  //#endregion
682
577
  //#region src/client/components/primitives/helpers/observer.ts
683
578
  function getItemId(url) {
@@ -841,9 +736,10 @@ function AnchorProvider({ toc, single = false, observerOptions, children }) {
841
736
  children
842
737
  });
843
738
  }
844
- function OnThisPage({ children, className }) {
739
+ function OnThisPage({ children, className, label = "On this page" }) {
845
740
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("nav", {
846
741
  "data-otp-root": true,
742
+ "aria-label": label,
847
743
  className,
848
744
  children
849
745
  });
@@ -938,7 +834,7 @@ function OnThisPageIndicator({ style, className }) {
938
834
  const items = useItems();
939
835
  (0, react.useEffect)(() => {
940
836
  if (items.length === 0) return;
941
- const parent = containerRef.current?.parentElement;
837
+ const parent = containerRef.current?.offsetParent;
942
838
  if (!parent) return;
943
839
  const activeLinks = parent.querySelectorAll("a[data-active=\"true\"]");
944
840
  if (activeLinks.length > 0) {
@@ -963,6 +859,7 @@ function OnThisPageIndicator({ style, className }) {
963
859
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
964
860
  ref: containerRef,
965
861
  "data-otp-indicator": true,
862
+ "aria-hidden": "true",
966
863
  className: require_link.cn("absolute", className),
967
864
  style: {
968
865
  transition: "transform 180ms cubic-bezier(0.2, 0.8, 0.2, 1), height 180ms cubic-bezier(0.2, 0.8, 0.2, 1), opacity 150ms",
@@ -976,9 +873,9 @@ function OnThisPageIndicator({ style, className }) {
976
873
  function OnThisPageItems({ headings = [], className, itemClassName, linkClassName, indicatorClassName }) {
977
874
  const activeIds = useActiveAnchors();
978
875
  if (headings.length === 0) return null;
979
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(OnThisPageList, {
876
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(OnThisPageIndicator, { className: indicatorClassName }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OnThisPageList, {
980
877
  className,
981
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(OnThisPageIndicator, { className: indicatorClassName }), headings.map((h) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OnThisPageItem, {
878
+ children: headings.map((h) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OnThisPageItem, {
982
879
  level: h.level,
983
880
  className: itemClassName,
984
881
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OnThisPageLink, {
@@ -987,8 +884,8 @@ function OnThisPageItems({ headings = [], className, itemClassName, linkClassNam
987
884
  className: linkClassName,
988
885
  children: h.text
989
886
  })
990
- }, h.id))]
991
- });
887
+ }, h.id))
888
+ })] });
992
889
  }
993
890
  /**
994
891
  * High-level automated Table of Contents tree
@@ -1035,6 +932,7 @@ OnThisPage.Tree = OnThisPageTree;
1035
932
  //#region src/client/components/primitives/page-nav.tsx
1036
933
  function PageNav({ children, className }) {
1037
934
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("nav", {
935
+ "aria-label": "Pagination",
1038
936
  className: require_link.cn("grid sm:grid-cols-2 gap-4", className),
1039
937
  children
1040
938
  });
@@ -1134,7 +1032,7 @@ function SidebarHeader({ children, className }) {
1134
1032
  * The scroll container doubles as the semantic `<nav>` landmark. State and
1135
1033
  * scroll-position handling live here; all visuals belong to the theme.
1136
1034
  */
1137
- function SidebarContent({ children, className }) {
1035
+ function SidebarContent({ children, className, label = "Docs navigation" }) {
1138
1036
  const scrollRef = (0, react.useRef)(null);
1139
1037
  (0, react.useLayoutEffect)(() => {
1140
1038
  if (scrollRef.current) scrollRef.current.scrollTop = sidebarScrollPos;
@@ -1151,6 +1049,7 @@ function SidebarContent({ children, className }) {
1151
1049
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("nav", {
1152
1050
  ref: scrollRef,
1153
1051
  "data-sidebar-content": true,
1052
+ "aria-label": label,
1154
1053
  className,
1155
1054
  children
1156
1055
  });
@@ -1400,7 +1299,7 @@ const Sidebar = Object.assign(SidebarRoot, {
1400
1299
  * It doesn't render anything visible.
1401
1300
  */
1402
1301
  function SearchHighlight() {
1403
- useSearchHighlight(".boltdocs-page");
1302
+ require_search_dialog.useSearchHighlight(".boltdocs-page");
1404
1303
  return null;
1405
1304
  }
1406
1305
 
@@ -1625,12 +1524,6 @@ Object.defineProperty(exports, 'useItems', {
1625
1524
  return useItems;
1626
1525
  }
1627
1526
  });
1628
- Object.defineProperty(exports, 'useSearchHighlight', {
1629
- enumerable: true,
1630
- get: function () {
1631
- return useSearchHighlight;
1632
- }
1633
- });
1634
1527
  Object.defineProperty(exports, 'useSidebar', {
1635
1528
  enumerable: true,
1636
1529
  get: function () {
@@ -3,4 +3,4 @@
3
3
  * Copyright (c) 2026 Jesus Alcala
4
4
  * Licensed under the MIT License.
5
5
  */
6
- const e=require(`./chunk-D1Md3oWO.cjs`),t=require(`./utils-ej6_SjIZ.cjs`),n=require(`./pages-external-DPiPFxxP.cjs`),r=require(`./config-CrsQJHQz.cjs`),i=require(`./update-check-DFQZyoSU.cjs`);let a=require(`node:path`);a=e.r(a);let o=require(`node:fs`);o=e.r(o);let s=require(`@bdocs/dui`),c=require(`fdir`),l=require(`picomatch`);l=e.r(l);let u=require(`fastest-levenshtein`);const d={$schema:`https://boltdocs.vercel.app/schemas/doctor-config.schema.json`,checks:{metadata:{enabled:!0,titleMin:10,titleMax:60,descriptionMin:50,required:[`title`,`description`],optional:[],validateDates:!1},links:{internal:!0,external:!1,timeout:1e4,concurrency:10,ignore:[]},i18n:{enabled:!0},performance:{enabled:!0,budgets:{maxJSBundleSize:`200kb`,maxCSSBundleSize:`30kb`,maxPageHTMLSize:`80kb`,maxImagesKB:500,maxBuildTime:3e4,maxFontCount:3}}},fix:{confirmChanges:!1,backupFiles:!1,backupPath:`.boltdocs/backups`},reporting:{format:`pretty`,outputFile:`.boltdocs/reports/doctor.json`,failOnError:!1,maxWarnings:-1},severity:{missingTranslation:`warning`,brokenLink:`high`,brokenAnchor:`warning`,largeFile:`warning`,orphanedPage:`low`,duplicateTitle:`low`,shortMetadata:`low`,missingMetadata:`warning`,malformedFrontmatter:`high`,invalidFrontmatter:`high`,budgetExceeded:`warning`},exclude:[]};function f(e,t){if(e==null)return t;if(typeof e==`number`)return e;let n=e.toLowerCase().match(/^(\d+(?:\.\d+)?)\s*(b|kb|mb|gb)?$/);if(!n)return t;let r=Number.parseFloat(n[1]),i=n[2]||`b`;return Math.round(r*({b:1,kb:1024,mb:1024*1024,gb:1024*1024*1024}[i]||1))}function p(e,t,n){return e.doctorConfig.severity[t]||n}async function m(e,t){o.default.existsSync(t)||o.default.mkdirSync(t,{recursive:!0});let n=a.default.basename(e),r=new Date().toISOString().replace(/[:.]/g,`-`),i=a.default.join(t,`${n}.${r}.bak`);o.default.copyFileSync(e,i)}const h=new Map;function g(e){let n=h.get(e);if(n)return n;let r=(async()=>{let n=await t.d(e,!1);return{raw:n.raw,data:n.data,content:n.content}})();return h.set(e,r),r}const _=new Map;function v(e){if(_.has(e))return _.get(e);let t=!1;try{t=o.default.existsSync(e)&&o.default.statSync(e).isFile()}catch{t=!1}return _.set(e,t),t}async function y(e){let t=a.default.resolve(e,`doctor.json`);if(o.default.existsSync(t))try{let e=JSON.parse(o.default.readFileSync(t,`utf-8`));return{...d,...e,checks:{...d.checks,...e.checks,metadata:{...d.checks.metadata,...e.checks?.metadata},links:{...d.checks.links,...e.checks?.links},i18n:{...d.checks.i18n,...e.checks?.i18n},performance:{...d.checks.performance,...e.checks?.performance,budgets:{...d.checks.performance?.budgets,...e.checks?.performance?.budgets}}},fix:{...d.fix,...e.fix},reporting:{...d.reporting,...e.reporting},severity:{...d.severity,...e.severity},exclude:[...d.exclude,...e.exclude||[]]}}catch(e){(0,s.warn)(`Failed to parse doctor.json: ${e}`)}return d}async function b(e,r=process.cwd(),i,s){let l=a.default.resolve(r,`.boltdocs`,`generated`);o.default.existsSync(l)||o.default.mkdirSync(l,{recursive:!0});let u=s;u||=await new c.fdir().withFullPaths().filter(e=>e.endsWith(`.md`)||e.endsWith(`.mdx`)).crawl(e).withPromise();let d=i?.base||`/`,f=[];for(let n=0;n<u.length;n+=100){let r=u.slice(n,n+100),i=await Promise.all(r.map(async n=>{let r=a.default.isAbsolute(n)?n:a.default.resolve(e,n),i=a.default.relative(e,r),{data:o}=await g(r),s;return s=o.permalink?String(o.permalink).startsWith(`/`)?String(o.permalink):`/${o.permalink}`:t.a(i),d===`/`?s:(d.endsWith(`/`)?d:d+`/`)+(s.startsWith(`/`)?s.substring(1):s)}));f.push(...i)}f.includes(d)||f.push(d);let p=n.n(e,i);for(let e of p)f.includes(e)||f.push(e);let m={routes:Array.from(new Set(f)).sort(),timestamp:Date.now()};return o.default.writeFileSync(a.default.resolve(l,`link-tree.json`),JSON.stringify(m,null,2)),m}function x(e,t){if(e===t)return 1;if(!e||!t)return 0;let n=e.split(`/`).filter(Boolean),r=t.split(`/`).filter(Boolean),i=n[n.length-1]||``,a=r[r.length-1]||``;if(i===a){let e=0;for(let t of n)r.includes(t)&&e++;return e>=2?.99:.9}if(i.length>3&&a.length>3&&(a.startsWith(i)||i.startsWith(a))&&Math.min(i.length,a.length)/Math.max(i.length,a.length)>.5)return .88;let o=1-(0,u.distance)(i,a)/Math.max(i.length,a.length);return o>.8?o*.95:1-(0,u.distance)(e,t)/Math.max(e.length,t.length)}const S=new Map;function C(e,t){if(S.has(e))return S.get(e);let n=e.length,r=``,i=0;for(let a of t){if(a===e)continue;let t=a.length,o=Math.max(n,t);if(o===0)continue;let s=1-Math.abs(n-t)/o;if(s<=.8&&s<=i)continue;let c=x(e,a);c>i&&(i=c,r=a)}let a={bestMatch:r,similarity:i};return S.set(e,a),a}function w(e,t,n){let r=/```[\s\S]*?```/g,i=/`[^`\n]*`/g,a=0,o=[],s=t=>{e=e.replace(t,e=>(o.push(e),`__BD_CODE_MASK_${a++}__`))};return s(r),s(i),e.split(t).join(n).replace(/__BD_CODE_MASK_(\d+)__/g,(e,t)=>o[Number(t)]??``)}async function T(e){let n=[];if(!e.doctorConfig.checks.metadata.enabled)return n;let{titleMin:r,titleMax:i,descriptionMin:o}=e.doctorConfig.checks.metadata,s=new Map;for(let c of e.files){let l=t.u(a.default.relative(e.docsDir,c));try{let{raw:a,data:u}=await g(c);if(a.trim().startsWith(`---`)&&a.split(`---`).length>=3&&Object.keys(u).length===0){let t=p(e,`malformedFrontmatter`,`high`);t!==`off`&&n.push({file:l,level:t,message:`Malformed frontmatter (YAML parsing failed).`,suggestion:`Check your YAML syntax for indentation or unquoted special characters.`})}let d=t.g.safeParse(u);if(!d.success){let t=p(e,`invalidFrontmatter`,`high`);if(t!==`off`)for(let e of d.error.issues)n.push({file:l,level:t,message:`Invalid frontmatter field "${e.path.join(`.`)}": ${e.message}`,suggestion:`Ensure the field follows the correct type.`})}let f=Array.from(new Set([`title`,...e.doctorConfig.checks.metadata.required]));for(let t of f)if(u[t]===void 0){let r=p(e,`missingMetadata`,`warning`);r!==`off`&&n.push({file:l,level:r,message:`Missing required frontmatter field: "${t}".`,suggestion:`Add the "${t}" field to your frontmatter.`})}if(e.doctorConfig.checks.metadata.validateDates){let t=[`date`,`lastUpdated`,...e.doctorConfig.checks.metadata.optional.filter(e=>e.toLowerCase().includes(`date`))];for(let r of t)if(u[r]&&Number.isNaN(Date.parse(String(u[r])))){let t=p(e,`invalidFrontmatter`,`high`);t!==`off`&&n.push({file:l,level:t,message:`Invalid date format in field "${r}": "${u[r]}".`,suggestion:`Use a valid ISO date format (e.g., YYYY-MM-DD).`})}}if(u.title){let t=String(u.title);if(t.length<r){let i=p(e,`shortMetadata`,`low`);i!==`off`&&n.push({file:l,level:i,message:`Title is too short (${t.length} chars).`,suggestion:`Titles should be at least ${r} characters for better SEO.`})}else if(t.length>i){let r=p(e,`shortMetadata`,`low`);r!==`off`&&n.push({file:l,level:r,message:`Title is too long (${t.length} chars).`,suggestion:`Titles should be under ${i} characters.`})}let a=s.get(t)||[];a.push(l),s.set(t,a)}if(u.description&&String(u.description).length<o){let t=p(e,`shortMetadata`,`low`);t!==`off`&&n.push({file:l,level:t,message:`Description is very short.`,suggestion:`Descriptions should ideally be at least ${o} characters.`})}}catch(t){if(t instanceof Error){let r=p(e,`malformedFrontmatter`,`high`);r!==`off`&&n.push({file:l,level:r,message:`Malformed frontmatter (YAML error): ${t.message}`,suggestion:`Check your YAML syntax for indentation or unquoted special characters.`})}}}for(let[t,r]of s.entries())if(r.length>1){let i=p(e,`duplicateTitle`,`low`);if(i!==`off`)for(let e of r)n.push({file:e,level:i,message:`Duplicate title found: "${t}"`,suggestion:`Ensure each page has a unique title. Also used in: ${r.filter(t=>t!==e).join(`, `)}`})}return n}const E=/(?:\[([^\]]*)\]\(([^)\s]+)(?:\s+["'][^"']*["'])?\))|(?:href=["']([^"']+)["'])|(?:<Link\s+[^>]*?to=["'](\/[^"']+)["'])/g,D=[``,`.md`,`.mdx`,`/index.md`,`/index.mdx`];function O(e){let t=[],n=e=>{t.includes(e)||t.push(e)};n(e),e.endsWith(`/`)?n(e.slice(0,-1)):n(e+`/`);let r=e.replace(/\.(md|mdx)$/i,``);r!==e&&(n(r),n(r+`/`));let i=e.replace(/\/index\.(md|mdx)$/i,``);return i!==e&&(n(i),n(i+`/`)),n(e.endsWith(`/`)?e+`index`:e+`/index`),e.endsWith(`/index`)&&n(e.replace(/\/index$/,``)),t}async function k(e){let n=[],{internal:r,external:i,ignore:c,timeout:l,concurrency:u}=e.doctorConfig.checks.links;if(!r&&!i&&!e.options.checkExternal)return n;let d=new Set,f=5e5;for(let s of e.files){let l=t.u(a.default.relative(e.docsDir,s)),{content:u}=await g(s),m=[...(u.length>f?u.slice(0,f):u).replace(/<!--[\s\S]*?-->/g,``).replace(/```[\s\S]*?```/g,``).replace(/`[^`\n]*`/g,``).matchAll(E)];for(let t of m){let u=t[2]||t[3]||t[4],f=!!t[2],m=!!t[4];if(!u||c.some(e=>u.includes(e)))continue;if(/^(https?:|mailto:|tel:|data:|javascript:|blob:|ftp:)/i.test(u)){(i||e.options.checkExternal)&&d.add({url:u,file:s});continue}if(u.startsWith(`//`)){(i||e.options.checkExternal)&&d.add({url:u,file:s});continue}if(!r||u.startsWith(`#`))continue;let g;try{g=decodeURIComponent(u.split(`#`)[0].split(`?`)[0])}catch{g=u.split(`#`)[0].split(`?`)[0]}if(!g)continue;let _=!1,y=!1,b=``;if(g.startsWith(`/`)){let t=O(g);for(let n of t)if(e.routeIndex.has(n)||e.routeIndexWithSlash.has(n)||e.routeIndexWithoutSlash.has(n)){_=!0;break}if(!_&&e.basePrefix)for(let n of t){let t=e.basePrefix+(n.startsWith(`/`)?n:`/`+n);if(t!==n&&(e.routeIndex.has(t)||e.routeIndexWithSlash.has(t))){y=!0,b=t;break}}if(!_&&!y){let t=g.replace(/^\/+/,``),n=a.default.join(e.docsDir,t);_=D.some(e=>v(n+e))}}else{let e=a.default.resolve(a.default.dirname(s),g);_=D.some(t=>v(e+t))}if(!_){let{bestMatch:t,similarity:r}=C(g,e.linkTree.routes);y&&(t=b,r=1);let i=r>.6||y,a=r>.75&&t!==g||y,c=p(e,`brokenLink`,`high`);c!==`off`&&n.push({file:l,level:c,message:`Broken internal link: "${u}"`,suggestion:i?`Did you mean "${t}"?`:`Ensure the target exists or check for typos.`,fix:a?async()=>{let e=u.includes(`#`)?`#`+u.split(`#`)[1]:``,n=f?`(${u})`:m?`to="${u}"`:`href="${u}"`,r=f?`(${t}${e})`:m?`to="${t}${e}"`:`href="${t}${e}"`,i=w(o.default.readFileSync(s,`utf-8`),n,r);o.default.writeFileSync(s,i),h.delete(s)}:void 0})}}}if(d.size>0){(0,s.info)(s.colors.gray(`Verifying ${d.size} external links...`));let r=new Map;for(let e of d)r.has(e.url)||r.set(e.url,[]),r.get(e.url).push(e.file);let i=async e=>{try{let t=new AbortController,n=setTimeout(()=>t.abort(),l),r=await fetch(e,{method:`HEAD`,signal:t.signal,headers:{"User-Agent":`boltdocs-doctor/1.0`}});return clearTimeout(n),!r.ok&&r.status!==404?{url:e,ok:(await fetch(e,{method:`GET`,signal:t.signal,headers:{"User-Agent":`boltdocs-doctor/1.0`}})).ok}:{url:e,ok:r.ok}}catch(t){return{url:e,ok:!1,error:t instanceof Error?t.message:String(t)}}},o=Array.from(r.keys()),c=[];for(let e=0;e<o.length;e+=u){let t=o.slice(e,e+u),n=await Promise.allSettled(t.map(i));c.push(...n.map(e=>e.status===`fulfilled`?e.value:{url:`unknown`,ok:!1,error:String(e.reason)}))}for(let i of c)if(!i.ok){let o=p(e,`brokenLink`,`warning`);if(o!==`off`){let s=r.get(i.url)||[];for(let r of s)n.push({file:t.u(a.default.relative(e.docsDir,r)),level:o,message:`Broken external link: "${i.url}"`,suggestion:`Verify the URL or update it if it's permanently down. Error: ${i.error||`Status >= 400`}`})}}}return n}async function A(e){let n=[];if(!e.doctorConfig.checks.i18n.enabled||!e.config.i18n)return n;let{defaultLocale:r,locales:i}=e.config.i18n,s=Object.keys(i),c=s.filter(e=>e!==r);if(c.length===0)return n;let l=a.default.resolve(e.docsDir),u=a.default.join(l,r),d=o.default.existsSync(u)&&o.default.statSync(u).isDirectory(),f=e=>{let t=a.default.resolve(e);if(t!==l&&!t.startsWith(l+a.default.sep))throw Error(`Refusing to write outside docs dir: ${t}`);return t};for(let i of e.files){let m=t.u(a.default.relative(e.docsDir,i)),h=m.split(`/`),g=h[0],_,y;if(s.includes(g)&&g!==r?(_=g,y=h.slice(1).join(`/`)):g===r&&d?(_=r,y=h.slice(1).join(`/`)):(_=r,y=m),y)if(_===r)for(let t of c){let r=a.default.join(l,t,y);if(!v(r)){let s=p(e,`missingTranslation`,`warning`);s!==`off`&&n.push({file:m,level:s,message:`Missing translation for locale "${t}"`,suggestion:`Create a version at "${t}/${y}".`,fix:async()=>{let e=f(r),t=a.default.dirname(e);o.default.existsSync(t)||o.default.mkdirSync(t,{recursive:!0}),o.default.copyFileSync(i,e)}})}}else{let t=a.default.join(l,y),s=d?a.default.join(u,y):``;if(!(v(t)||s!==``&&v(s))){let t=p(e,`missingTranslation`,`low`);t!==`off`&&n.push({file:m,level:t,message:`Orphaned translation (source missing in "${r}")`,suggestion:`Remove this file or create the source at "${r}/${y}".`,fix:async()=>{o.default.unlinkSync(f(i))}})}}}return n}async function j(e){let t=[];if(!e.config.theme?.sidebar)return t;let n=new Set,r=e.config.theme.sidebar;for(let[i,a]of Object.entries(r))for(let r of a){if(!r.text){let n=p(e,`invalidFrontmatter`,`warning`);n!==`off`&&t.push({file:`boltdocs.config.ts`,level:n,message:`Sidebar item in group "${i}" is missing a label.`,suggestion:`Add a "text" property to the sidebar item.`})}if(r.link&&(n.add(r.link),!e.routeIndex.has(r.link))){let{bestMatch:n,similarity:i}=C(r.link,e.linkTree.routes),a=i>.6,o=p(e,`brokenLink`,`high`);o!==`off`&&t.push({file:`boltdocs.config.ts`,level:o,message:`Broken sidebar link: "${r.link}"`,suggestion:a?`Did you mean "${n}"?`:`Ensure the route exists and is correctly formatted.`})}}for(let r of e.linkTree.routes)if(!(r===`/`||r===``)&&!n.has(r)){let n=p(e,`orphanedPage`,`low`);n!==`off`&&t.push({file:`Sidebar`,level:n,message:`Orphaned page found: "${r}" is not linked in the sidebar.`,suggestion:`Consider adding it to the sidebar for better discoverability.`})}return t}async function M(e){let t=[],n=e.doctorConfig.checks.performance;if(!n?.enabled)return t;let r=a.default.resolve(e.root,`.boltdocs`,`reports`,`performance.json`);if(!o.default.existsSync(r))return t.push({file:`(build)`,level:p(e,`budgetExceeded`,`warning`)??`warning`,message:"Performance metrics not found. Run `boltdocs build` first."}),t;let i;try{i=JSON.parse(o.default.readFileSync(r,`utf-8`))}catch{return t.push({file:`(build)`,level:p(e,`budgetExceeded`,`warning`)??`warning`,message:`Failed to parse performance metrics file.`}),t}let s=n.budgets,c=p(e,`budgetExceeded`,`warning`),l=f(s?.maxJSBundleSize,1/0),u=f(s?.maxCSSBundleSize,1/0),d=f(s?.maxPageHTMLSize,1/0),m=s?.maxImagesKB??1/0,h=s?.maxBuildTime??1/0,g=s?.maxFontCount??1/0;if(l!==1/0&&i.totalJSBundleSize>l){let e=(i.totalJSBundleSize/1024).toFixed(0),n=(l/1024).toFixed(0);t.push({file:`(build)`,level:c,message:`JS bundle size exceeds budget: ${e}kb > ${n}kb`,suggestion:`Code-split large dependencies or lazy-load route components.`})}if(u!==1/0&&i.totalCSSBundleSize>u){let e=(i.totalCSSBundleSize/1024).toFixed(0),n=(u/1024).toFixed(0);t.push({file:`(build)`,level:c,message:`CSS bundle size exceeds budget: ${e}kb > ${n}kb`,suggestion:`Remove unused styles or split CSS by route.`})}if(d!==1/0){for(let e of i.pages)if(e.htmlSize>d){let n=(e.htmlSize/1024).toFixed(0),r=(d/1024).toFixed(0);t.push({file:e.route,level:c,message:`Page HTML size exceeds budget: ${n}kb > ${r}kb`,suggestion:`Reduce the amount of inline content or split into sub-pages.`})}}let _=m*1024;if(m!==1/0&&i.totalImagesSize>_){let e=(i.totalImagesSize/1024).toFixed(0);t.push({file:`(build)`,level:c,message:`Image assets exceed budget: ${e}kb > ${m}kb`,suggestion:`Optimize images with lossy compression or use next-gen formats (webp/avif).`})}if(h!==1/0&&i.buildTime>h){let e=(i.buildTime/1e3).toFixed(1),n=(h/1e3).toFixed(1);t.push({file:`(build)`,level:c,message:`Build time exceeds budget: ${e}s > ${n}s`,suggestion:"Check for large unoptimized assets or increase `concurrency` in SSG options."})}return g!==1/0&&i.fontCount>g&&t.push({file:`(build)`,level:c,message:`Font files exceed budget: ${i.fontCount} > ${g}`,suggestion:`Reduce the number of font families or use variable fonts.`}),t}async function N(e){let t=a.default.resolve(e,`doctor.json`);if(o.default.existsSync(t)){(0,s.warn)(`"doctor.json" already exists at ${e}.`);return}try{o.default.writeFileSync(t,JSON.stringify(d,null,2)),(0,s.success)(`Created "doctor.json" with default configuration.`)}catch(e){(0,s.error)(`Failed to create "doctor.json": ${e}`)}}async function P(e=process.cwd(),t={}){if(t.init){await N(e);return}i.t();try{let n=await y(e),{format:u}=n.reporting,d=performance.now(),f=await r.t(`docs`,e),p=a.default.resolve(e,`docs`);if(o.default.existsSync(p)||(u===`pretty`&&(0,s.error)(`Docs dir not found at ${p}`),process.exit(1)),u===`pretty`){let t=i.n?` ${i.i(`v${i.n}`)}`:``;console.log(`\n ${s.colors.bold(`⚡`)} ${i.s(`boltdocs`)}${t} ${s.colors.dim(`—`)} ${s.colors.bold(`doctor`)} ${s.colors.dim(`· documentation health check`)}\n`),console.log(` ${s.colors.dim(`Docs dir ${p}`)}\n ${s.colors.dim(`Reports ${e}/.boltdocs/reports/`)}\n`)}u===`pretty`&&(0,s.info)(s.colors.dim(`🔍 Discovering files and routes...`));let h=(0,l.default)(n.exclude||[]),g=await new c.fdir().withFullPaths().filter(e=>{if(!(e.endsWith(`.md`)||e.endsWith(`.mdx`)))return!1;let t=a.default.relative(p,e).replace(/\\/g,`/`),n=t.split(`/`).some(e=>e.startsWith(`_`)&&e!==`_index.md`&&e!==`_index.mdx`);return!h(t)&&!n}).crawl(p).withPromise();for(let e of g)_.set(e,!0);let v=await b(p,e,f,g),x=f.base||`/`,S=x===`/`?``:x.endsWith(`/`)?x.slice(0,-1):x,C=new Set(v.routes),w=new Set(v.routes.map(e=>e.endsWith(`/`)?e:e+`/`)),E=new Set(v.routes.map(e=>e.endsWith(`/`)?e.slice(0,-1):e));u===`pretty`&&(0,s.info)(s.colors.dim(`🧪 Running diagnostic checks in parallel...`));let D={root:e,docsDir:p,config:f,doctorConfig:n,linkTree:v,files:g,options:t,routeIndex:C,routeIndexWithSlash:w,routeIndexWithoutSlash:E,basePrefix:S};u===`pretty`&&(0,s.info)(s.colors.dim(`🧪 Running diagnostic checks in parallel...`));let O=[T(D),k(D),A(D),j(D)];t.budget&&O.push(M(D));let[N,P,F,I,...L]=await Promise.all(O),R=t.budget?L[0]??[]:[],z=[...N,...P,...F,...I,...R];if(u===`pretty`){let e=e=>e>0?s.colors.red(`${e} issue${e===1?``:`s`}`):s.colors.green(`OK`),n=[{label:`Metadata checks ${e(N.length)}`,done:N.length===0},{label:`Link checks ${e(P.length)}`,done:P.length===0},{label:`i18n checks ${e(F.length)}`,done:F.length===0},{label:`Sidebar checks ${e(I.length)}`,done:I.length===0}];t.budget&&n.push({label:`Performance budget ${e(R.length)}`,done:R.length===0}),console.log(`\n${(0,s.tasks)(n)}\n`)}let B=0;if(t.fix){for(let e of z)if(e.fix){if(D.doctorConfig.fix.confirmChanges&&!await(0,s.confirm)(`Fix issue in "${e.file}": ${e.message}?`))continue;if(D.doctorConfig.fix.backupFiles){let t=a.default.resolve(D.docsDir,e.file);o.default.existsSync(t)&&await m(t,a.default.resolve(D.root,D.doctorConfig.fix.backupPath))}await e.fix(),B++}}let V=((performance.now()-d)/1e3).toFixed(2),H=z.filter(e=>e.level===`high`).length,U=z.filter(e=>e.level===`warning`).length,W=z.filter(e=>e.level===`low`).length,G={summary:{total:z.length,high:H,warning:U,low:W,fixed:B,duration:V},issues:z.map(e=>({...e,fix:void 0}))};if(n.reporting.outputFile){let t=a.default.resolve(e,n.reporting.outputFile);o.default.existsSync(a.default.dirname(t))||o.default.mkdirSync(a.default.dirname(t),{recursive:!0}),o.default.writeFileSync(t,JSON.stringify(G,null,2))}if(u===`json`)console.log(JSON.stringify(G,null,2));else if(u===`pretty`){let e=z.reduce((e,t)=>(e[t.file]||(e[t.file]=[]),e[t.file].push(t),e),{});if(z.length>0){console.log((0,s.section)({title:`Issues`,colors:{title:i.r}}));for(let[n,r]of Object.entries(e)){let e=r.some(e=>e.level===`high`)?`high`:r.some(e=>e.level===`warning`)?`warning`:`low`,a=e.toUpperCase(),o=e===`high`?(0,s.badge)({label:a,status:`error`}):e===`warning`?(0,s.badge)({label:a,status:`warning`}):(0,s.badge)({label:a,colors:{text:`#ffffff`,bg:i.r}});console.log(`\n ${o} ${s.colors.bold(n)}`);for(let e of r){let n=e.level===`high`?`✖`:e.level===`warning`?`⚠`:`ℹ`,r=e.level===`high`?s.colors.red:e.level===`warning`?s.colors.yellow:e=>(0,s.colorize)(e,i.r,`fg`);console.log(` ${r(n)} ${e.message}`),e.suggestion&&console.log(` ${s.colors.dim(`💡 ${e.suggestion}`)}`),t.fix&&e.fix&&console.log(` ${s.colors.green(`✅ Fixed automatically`)}`)}}console.log(``)}z.length===0?(console.log(` ${s.colors.green.bold(`✨ Everything looks perfect!`)} ${s.colors.dim(`— your documentation is in great shape.`)}`),console.log(` ${s.colors.dim(`Scanned ${g.length} file${g.length===1?``:`s`} in ${V}s`)}`)):(console.log(`\n${(0,s.section)({title:`Summary`,colors:{title:i.r}})}`),H>0&&console.log(` ${(0,s.badge)({label:String(H),status:`error`})} ${s.colors.bold(`high`)}`),U>0&&console.log(` ${(0,s.badge)({label:String(U),status:`warning`})} ${s.colors.bold(`warning`)}${U===1?``:`s`}`),W>0&&console.log(` ${(0,s.badge)({label:String(W),colors:{text:`#ffffff`,bg:i.r}})} ${s.colors.bold(`low`)}`),console.log(` ${s.colors.dim(`Scanned ${g.length} file${g.length===1?``:`s`} in ${V}s`)}`),B>0&&(0,s.success)(`Successfully fixed ${B} issues automatically!`),H>0?(0,s.error)(`Please fix the critical errors before building for production.`):(0,s.success)(`No critical issues found. You are ready to go!`))}n.reporting.failOnError&&H>0&&process.exit(1),n.reporting.maxWarnings!==-1&&U>n.reporting.maxWarnings&&(u===`pretty`&&(0,s.error)(`Failed: Too many warnings (${U} > ${n.reporting.maxWarnings})`),process.exit(1))}catch(e){(0,s.error)(`Doctor failed: ${e}`),process.exit(1)}}Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return N}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return M}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return A}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return P}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return d}});
6
+ const e=require(`./chunk-D1Md3oWO.cjs`),t=require(`./utils-ej6_SjIZ.cjs`),n=require(`./pages-external-DPiPFxxP.cjs`),r=require(`./config-BJp3lGzE.cjs`),i=require(`./update-check-DFQZyoSU.cjs`);let a=require(`node:path`);a=e.r(a);let o=require(`node:fs`);o=e.r(o);let s=require(`@bdocs/dui`),c=require(`fdir`),l=require(`picomatch`);l=e.r(l);let u=require(`fastest-levenshtein`);const d={$schema:`https://boltdocs.vercel.app/schemas/doctor-config.schema.json`,checks:{metadata:{enabled:!0,titleMin:10,titleMax:60,descriptionMin:50,required:[`title`,`description`],optional:[],validateDates:!1},links:{internal:!0,external:!1,timeout:1e4,concurrency:10,ignore:[]},i18n:{enabled:!0},performance:{enabled:!0,budgets:{maxJSBundleSize:`200kb`,maxCSSBundleSize:`30kb`,maxPageHTMLSize:`80kb`,maxImagesKB:500,maxBuildTime:3e4,maxFontCount:3}}},fix:{confirmChanges:!1,backupFiles:!1,backupPath:`.boltdocs/backups`},reporting:{format:`pretty`,outputFile:`.boltdocs/reports/doctor.json`,failOnError:!1,maxWarnings:-1},severity:{missingTranslation:`warning`,brokenLink:`high`,brokenAnchor:`warning`,largeFile:`warning`,orphanedPage:`low`,duplicateTitle:`low`,shortMetadata:`low`,missingMetadata:`warning`,malformedFrontmatter:`high`,invalidFrontmatter:`high`,budgetExceeded:`warning`},exclude:[]};function f(e,t){if(e==null)return t;if(typeof e==`number`)return e;let n=e.toLowerCase().match(/^(\d+(?:\.\d+)?)\s*(b|kb|mb|gb)?$/);if(!n)return t;let r=Number.parseFloat(n[1]),i=n[2]||`b`;return Math.round(r*({b:1,kb:1024,mb:1024*1024,gb:1024*1024*1024}[i]||1))}function p(e,t,n){return e.doctorConfig.severity[t]||n}async function m(e,t){o.default.existsSync(t)||o.default.mkdirSync(t,{recursive:!0});let n=a.default.basename(e),r=new Date().toISOString().replace(/[:.]/g,`-`),i=a.default.join(t,`${n}.${r}.bak`);o.default.copyFileSync(e,i)}const h=new Map;function g(e){let n=h.get(e);if(n)return n;let r=(async()=>{let n=await t.d(e,!1);return{raw:n.raw,data:n.data,content:n.content}})();return h.set(e,r),r}const _=new Map;function v(e){if(_.has(e))return _.get(e);let t=!1;try{t=o.default.existsSync(e)&&o.default.statSync(e).isFile()}catch{t=!1}return _.set(e,t),t}async function y(e){let t=a.default.resolve(e,`doctor.json`);if(o.default.existsSync(t))try{let e=JSON.parse(o.default.readFileSync(t,`utf-8`));return{...d,...e,checks:{...d.checks,...e.checks,metadata:{...d.checks.metadata,...e.checks?.metadata},links:{...d.checks.links,...e.checks?.links},i18n:{...d.checks.i18n,...e.checks?.i18n},performance:{...d.checks.performance,...e.checks?.performance,budgets:{...d.checks.performance?.budgets,...e.checks?.performance?.budgets}}},fix:{...d.fix,...e.fix},reporting:{...d.reporting,...e.reporting},severity:{...d.severity,...e.severity},exclude:[...d.exclude,...e.exclude||[]]}}catch(e){(0,s.warn)(`Failed to parse doctor.json: ${e}`)}return d}async function b(e,r=process.cwd(),i,s){let l=a.default.resolve(r,`.boltdocs`,`generated`);o.default.existsSync(l)||o.default.mkdirSync(l,{recursive:!0});let u=s;u||=await new c.fdir().withFullPaths().filter(e=>e.endsWith(`.md`)||e.endsWith(`.mdx`)).crawl(e).withPromise();let d=i?.base||`/`,f=[];for(let n=0;n<u.length;n+=100){let r=u.slice(n,n+100),i=await Promise.all(r.map(async n=>{let r=a.default.isAbsolute(n)?n:a.default.resolve(e,n),i=a.default.relative(e,r),{data:o}=await g(r),s;return s=o.permalink?String(o.permalink).startsWith(`/`)?String(o.permalink):`/${o.permalink}`:t.a(i),d===`/`?s:(d.endsWith(`/`)?d:d+`/`)+(s.startsWith(`/`)?s.substring(1):s)}));f.push(...i)}f.includes(d)||f.push(d);let p=n.n(e,i);for(let e of p)f.includes(e)||f.push(e);let m={routes:Array.from(new Set(f)).sort(),timestamp:Date.now()};return o.default.writeFileSync(a.default.resolve(l,`link-tree.json`),JSON.stringify(m,null,2)),m}function x(e,t){if(e===t)return 1;if(!e||!t)return 0;let n=e.split(`/`).filter(Boolean),r=t.split(`/`).filter(Boolean),i=n[n.length-1]||``,a=r[r.length-1]||``;if(i===a){let e=0;for(let t of n)r.includes(t)&&e++;return e>=2?.99:.9}if(i.length>3&&a.length>3&&(a.startsWith(i)||i.startsWith(a))&&Math.min(i.length,a.length)/Math.max(i.length,a.length)>.5)return .88;let o=1-(0,u.distance)(i,a)/Math.max(i.length,a.length);return o>.8?o*.95:1-(0,u.distance)(e,t)/Math.max(e.length,t.length)}const S=new Map;function C(e,t){if(S.has(e))return S.get(e);let n=e.length,r=``,i=0;for(let a of t){if(a===e)continue;let t=a.length,o=Math.max(n,t);if(o===0)continue;let s=1-Math.abs(n-t)/o;if(s<=.8&&s<=i)continue;let c=x(e,a);c>i&&(i=c,r=a)}let a={bestMatch:r,similarity:i};return S.set(e,a),a}function w(e,t,n){let r=/```[\s\S]*?```/g,i=/`[^`\n]*`/g,a=0,o=[],s=t=>{e=e.replace(t,e=>(o.push(e),`__BD_CODE_MASK_${a++}__`))};return s(r),s(i),e.split(t).join(n).replace(/__BD_CODE_MASK_(\d+)__/g,(e,t)=>o[Number(t)]??``)}async function T(e){let n=[];if(!e.doctorConfig.checks.metadata.enabled)return n;let{titleMin:r,titleMax:i,descriptionMin:o}=e.doctorConfig.checks.metadata,s=new Map;for(let c of e.files){let l=t.u(a.default.relative(e.docsDir,c));try{let{raw:a,data:u}=await g(c);if(a.trim().startsWith(`---`)&&a.split(`---`).length>=3&&Object.keys(u).length===0){let t=p(e,`malformedFrontmatter`,`high`);t!==`off`&&n.push({file:l,level:t,message:`Malformed frontmatter (YAML parsing failed).`,suggestion:`Check your YAML syntax for indentation or unquoted special characters.`})}let d=t.g.safeParse(u);if(!d.success){let t=p(e,`invalidFrontmatter`,`high`);if(t!==`off`)for(let e of d.error.issues)n.push({file:l,level:t,message:`Invalid frontmatter field "${e.path.join(`.`)}": ${e.message}`,suggestion:`Ensure the field follows the correct type.`})}let f=Array.from(new Set([`title`,...e.doctorConfig.checks.metadata.required]));for(let t of f)if(u[t]===void 0){let r=p(e,`missingMetadata`,`warning`);r!==`off`&&n.push({file:l,level:r,message:`Missing required frontmatter field: "${t}".`,suggestion:`Add the "${t}" field to your frontmatter.`})}if(e.doctorConfig.checks.metadata.validateDates){let t=[`date`,`lastUpdated`,...e.doctorConfig.checks.metadata.optional.filter(e=>e.toLowerCase().includes(`date`))];for(let r of t)if(u[r]&&Number.isNaN(Date.parse(String(u[r])))){let t=p(e,`invalidFrontmatter`,`high`);t!==`off`&&n.push({file:l,level:t,message:`Invalid date format in field "${r}": "${u[r]}".`,suggestion:`Use a valid ISO date format (e.g., YYYY-MM-DD).`})}}if(u.title){let t=String(u.title);if(t.length<r){let i=p(e,`shortMetadata`,`low`);i!==`off`&&n.push({file:l,level:i,message:`Title is too short (${t.length} chars).`,suggestion:`Titles should be at least ${r} characters for better SEO.`})}else if(t.length>i){let r=p(e,`shortMetadata`,`low`);r!==`off`&&n.push({file:l,level:r,message:`Title is too long (${t.length} chars).`,suggestion:`Titles should be under ${i} characters.`})}let a=s.get(t)||[];a.push(l),s.set(t,a)}if(u.description&&String(u.description).length<o){let t=p(e,`shortMetadata`,`low`);t!==`off`&&n.push({file:l,level:t,message:`Description is very short.`,suggestion:`Descriptions should ideally be at least ${o} characters.`})}}catch(t){if(t instanceof Error){let r=p(e,`malformedFrontmatter`,`high`);r!==`off`&&n.push({file:l,level:r,message:`Malformed frontmatter (YAML error): ${t.message}`,suggestion:`Check your YAML syntax for indentation or unquoted special characters.`})}}}for(let[t,r]of s.entries())if(r.length>1){let i=p(e,`duplicateTitle`,`low`);if(i!==`off`)for(let e of r)n.push({file:e,level:i,message:`Duplicate title found: "${t}"`,suggestion:`Ensure each page has a unique title. Also used in: ${r.filter(t=>t!==e).join(`, `)}`})}return n}const E=/(?:\[([^\]]*)\]\(([^)\s]+)(?:\s+["'][^"']*["'])?\))|(?:href=["']([^"']+)["'])|(?:<Link\s+[^>]*?to=["'](\/[^"']+)["'])/g,D=[``,`.md`,`.mdx`,`/index.md`,`/index.mdx`];function O(e){let t=[],n=e=>{t.includes(e)||t.push(e)};n(e),e.endsWith(`/`)?n(e.slice(0,-1)):n(e+`/`);let r=e.replace(/\.(md|mdx)$/i,``);r!==e&&(n(r),n(r+`/`));let i=e.replace(/\/index\.(md|mdx)$/i,``);return i!==e&&(n(i),n(i+`/`)),n(e.endsWith(`/`)?e+`index`:e+`/index`),e.endsWith(`/index`)&&n(e.replace(/\/index$/,``)),t}async function k(e){let n=[],{internal:r,external:i,ignore:c,timeout:l,concurrency:u}=e.doctorConfig.checks.links;if(!r&&!i&&!e.options.checkExternal)return n;let d=new Set,f=5e5;for(let s of e.files){let l=t.u(a.default.relative(e.docsDir,s)),{content:u}=await g(s),m=[...(u.length>f?u.slice(0,f):u).replace(/<!--[\s\S]*?-->/g,``).replace(/```[\s\S]*?```/g,``).replace(/`[^`\n]*`/g,``).matchAll(E)];for(let t of m){let u=t[2]||t[3]||t[4],f=!!t[2],m=!!t[4];if(!u||c.some(e=>u.includes(e)))continue;if(/^(https?:|mailto:|tel:|data:|javascript:|blob:|ftp:)/i.test(u)){(i||e.options.checkExternal)&&d.add({url:u,file:s});continue}if(u.startsWith(`//`)){(i||e.options.checkExternal)&&d.add({url:u,file:s});continue}if(!r||u.startsWith(`#`))continue;let g;try{g=decodeURIComponent(u.split(`#`)[0].split(`?`)[0])}catch{g=u.split(`#`)[0].split(`?`)[0]}if(!g)continue;let _=!1,y=!1,b=``;if(g.startsWith(`/`)){let t=O(g);for(let n of t)if(e.routeIndex.has(n)||e.routeIndexWithSlash.has(n)||e.routeIndexWithoutSlash.has(n)){_=!0;break}if(!_&&e.basePrefix)for(let n of t){let t=e.basePrefix+(n.startsWith(`/`)?n:`/`+n);if(t!==n&&(e.routeIndex.has(t)||e.routeIndexWithSlash.has(t))){y=!0,b=t;break}}if(!_&&!y){let t=g.replace(/^\/+/,``),n=a.default.join(e.docsDir,t);_=D.some(e=>v(n+e))}}else{let e=a.default.resolve(a.default.dirname(s),g);_=D.some(t=>v(e+t))}if(!_){let{bestMatch:t,similarity:r}=C(g,e.linkTree.routes);y&&(t=b,r=1);let i=r>.6||y,a=r>.75&&t!==g||y,c=p(e,`brokenLink`,`high`);c!==`off`&&n.push({file:l,level:c,message:`Broken internal link: "${u}"`,suggestion:i?`Did you mean "${t}"?`:`Ensure the target exists or check for typos.`,fix:a?async()=>{let e=u.includes(`#`)?`#`+u.split(`#`)[1]:``,n=f?`(${u})`:m?`to="${u}"`:`href="${u}"`,r=f?`(${t}${e})`:m?`to="${t}${e}"`:`href="${t}${e}"`,i=w(o.default.readFileSync(s,`utf-8`),n,r);o.default.writeFileSync(s,i),h.delete(s)}:void 0})}}}if(d.size>0){(0,s.info)(s.colors.gray(`Verifying ${d.size} external links...`));let r=new Map;for(let e of d)r.has(e.url)||r.set(e.url,[]),r.get(e.url).push(e.file);let i=async e=>{try{let t=new AbortController,n=setTimeout(()=>t.abort(),l),r=await fetch(e,{method:`HEAD`,signal:t.signal,headers:{"User-Agent":`boltdocs-doctor/1.0`}});return clearTimeout(n),!r.ok&&r.status!==404?{url:e,ok:(await fetch(e,{method:`GET`,signal:t.signal,headers:{"User-Agent":`boltdocs-doctor/1.0`}})).ok}:{url:e,ok:r.ok}}catch(t){return{url:e,ok:!1,error:t instanceof Error?t.message:String(t)}}},o=Array.from(r.keys()),c=[];for(let e=0;e<o.length;e+=u){let t=o.slice(e,e+u),n=await Promise.allSettled(t.map(i));c.push(...n.map(e=>e.status===`fulfilled`?e.value:{url:`unknown`,ok:!1,error:String(e.reason)}))}for(let i of c)if(!i.ok){let o=p(e,`brokenLink`,`warning`);if(o!==`off`){let s=r.get(i.url)||[];for(let r of s)n.push({file:t.u(a.default.relative(e.docsDir,r)),level:o,message:`Broken external link: "${i.url}"`,suggestion:`Verify the URL or update it if it's permanently down. Error: ${i.error||`Status >= 400`}`})}}}return n}async function A(e){let n=[];if(!e.doctorConfig.checks.i18n.enabled||!e.config.i18n)return n;let{defaultLocale:r,locales:i}=e.config.i18n,s=Object.keys(i),c=s.filter(e=>e!==r);if(c.length===0)return n;let l=a.default.resolve(e.docsDir),u=a.default.join(l,r),d=o.default.existsSync(u)&&o.default.statSync(u).isDirectory(),f=e=>{let t=a.default.resolve(e);if(t!==l&&!t.startsWith(l+a.default.sep))throw Error(`Refusing to write outside docs dir: ${t}`);return t};for(let i of e.files){let m=t.u(a.default.relative(e.docsDir,i)),h=m.split(`/`),g=h[0],_,y;if(s.includes(g)&&g!==r?(_=g,y=h.slice(1).join(`/`)):g===r&&d?(_=r,y=h.slice(1).join(`/`)):(_=r,y=m),y)if(_===r)for(let t of c){let r=a.default.join(l,t,y);if(!v(r)){let s=p(e,`missingTranslation`,`warning`);s!==`off`&&n.push({file:m,level:s,message:`Missing translation for locale "${t}"`,suggestion:`Create a version at "${t}/${y}".`,fix:async()=>{let e=f(r),t=a.default.dirname(e);o.default.existsSync(t)||o.default.mkdirSync(t,{recursive:!0}),o.default.copyFileSync(i,e)}})}}else{let t=a.default.join(l,y),s=d?a.default.join(u,y):``;if(!(v(t)||s!==``&&v(s))){let t=p(e,`missingTranslation`,`low`);t!==`off`&&n.push({file:m,level:t,message:`Orphaned translation (source missing in "${r}")`,suggestion:`Remove this file or create the source at "${r}/${y}".`,fix:async()=>{o.default.unlinkSync(f(i))}})}}}return n}async function j(e){let t=[];if(!e.config.theme?.sidebar)return t;let n=new Set,r=e.config.theme.sidebar;for(let[i,a]of Object.entries(r))for(let r of a){if(!r.text){let n=p(e,`invalidFrontmatter`,`warning`);n!==`off`&&t.push({file:`boltdocs.config.ts`,level:n,message:`Sidebar item in group "${i}" is missing a label.`,suggestion:`Add a "text" property to the sidebar item.`})}if(r.link&&(n.add(r.link),!e.routeIndex.has(r.link))){let{bestMatch:n,similarity:i}=C(r.link,e.linkTree.routes),a=i>.6,o=p(e,`brokenLink`,`high`);o!==`off`&&t.push({file:`boltdocs.config.ts`,level:o,message:`Broken sidebar link: "${r.link}"`,suggestion:a?`Did you mean "${n}"?`:`Ensure the route exists and is correctly formatted.`})}}for(let r of e.linkTree.routes)if(!(r===`/`||r===``)&&!n.has(r)){let n=p(e,`orphanedPage`,`low`);n!==`off`&&t.push({file:`Sidebar`,level:n,message:`Orphaned page found: "${r}" is not linked in the sidebar.`,suggestion:`Consider adding it to the sidebar for better discoverability.`})}return t}async function M(e){let t=[],n=e.doctorConfig.checks.performance;if(!n?.enabled)return t;let r=a.default.resolve(e.root,`.boltdocs`,`reports`,`performance.json`);if(!o.default.existsSync(r))return t.push({file:`(build)`,level:p(e,`budgetExceeded`,`warning`)??`warning`,message:"Performance metrics not found. Run `boltdocs build` first."}),t;let i;try{i=JSON.parse(o.default.readFileSync(r,`utf-8`))}catch{return t.push({file:`(build)`,level:p(e,`budgetExceeded`,`warning`)??`warning`,message:`Failed to parse performance metrics file.`}),t}let s=n.budgets,c=p(e,`budgetExceeded`,`warning`),l=f(s?.maxJSBundleSize,1/0),u=f(s?.maxCSSBundleSize,1/0),d=f(s?.maxPageHTMLSize,1/0),m=s?.maxImagesKB??1/0,h=s?.maxBuildTime??1/0,g=s?.maxFontCount??1/0;if(l!==1/0&&i.totalJSBundleSize>l){let e=(i.totalJSBundleSize/1024).toFixed(0),n=(l/1024).toFixed(0);t.push({file:`(build)`,level:c,message:`JS bundle size exceeds budget: ${e}kb > ${n}kb`,suggestion:`Code-split large dependencies or lazy-load route components.`})}if(u!==1/0&&i.totalCSSBundleSize>u){let e=(i.totalCSSBundleSize/1024).toFixed(0),n=(u/1024).toFixed(0);t.push({file:`(build)`,level:c,message:`CSS bundle size exceeds budget: ${e}kb > ${n}kb`,suggestion:`Remove unused styles or split CSS by route.`})}if(d!==1/0){for(let e of i.pages)if(e.htmlSize>d){let n=(e.htmlSize/1024).toFixed(0),r=(d/1024).toFixed(0);t.push({file:e.route,level:c,message:`Page HTML size exceeds budget: ${n}kb > ${r}kb`,suggestion:`Reduce the amount of inline content or split into sub-pages.`})}}let _=m*1024;if(m!==1/0&&i.totalImagesSize>_){let e=(i.totalImagesSize/1024).toFixed(0);t.push({file:`(build)`,level:c,message:`Image assets exceed budget: ${e}kb > ${m}kb`,suggestion:`Optimize images with lossy compression or use next-gen formats (webp/avif).`})}if(h!==1/0&&i.buildTime>h){let e=(i.buildTime/1e3).toFixed(1),n=(h/1e3).toFixed(1);t.push({file:`(build)`,level:c,message:`Build time exceeds budget: ${e}s > ${n}s`,suggestion:"Check for large unoptimized assets or increase `concurrency` in SSG options."})}return g!==1/0&&i.fontCount>g&&t.push({file:`(build)`,level:c,message:`Font files exceed budget: ${i.fontCount} > ${g}`,suggestion:`Reduce the number of font families or use variable fonts.`}),t}async function N(e){let t=a.default.resolve(e,`doctor.json`);if(o.default.existsSync(t)){(0,s.warn)(`"doctor.json" already exists at ${e}.`);return}try{o.default.writeFileSync(t,JSON.stringify(d,null,2)),(0,s.success)(`Created "doctor.json" with default configuration.`)}catch(e){(0,s.error)(`Failed to create "doctor.json": ${e}`)}}async function P(e=process.cwd(),t={}){if(t.init){await N(e);return}i.t();try{let n=await y(e),{format:u}=n.reporting,d=performance.now(),f=await r.t(`docs`,e),p=a.default.resolve(e,`docs`);if(o.default.existsSync(p)||(u===`pretty`&&(0,s.error)(`Docs dir not found at ${p}`),process.exit(1)),u===`pretty`){let t=i.n?` ${i.i(`v${i.n}`)}`:``;console.log(`\n ${s.colors.bold(`⚡`)} ${i.s(`boltdocs`)}${t} ${s.colors.dim(`—`)} ${s.colors.bold(`doctor`)} ${s.colors.dim(`· documentation health check`)}\n`),console.log(` ${s.colors.dim(`Docs dir ${p}`)}\n ${s.colors.dim(`Reports ${e}/.boltdocs/reports/`)}\n`)}u===`pretty`&&(0,s.info)(s.colors.dim(`🔍 Discovering files and routes...`));let h=(0,l.default)(n.exclude||[]),g=await new c.fdir().withFullPaths().filter(e=>{if(!(e.endsWith(`.md`)||e.endsWith(`.mdx`)))return!1;let t=a.default.relative(p,e).replace(/\\/g,`/`),n=t.split(`/`).some(e=>e.startsWith(`_`)&&e!==`_index.md`&&e!==`_index.mdx`);return!h(t)&&!n}).crawl(p).withPromise();for(let e of g)_.set(e,!0);let v=await b(p,e,f,g),x=f.base||`/`,S=x===`/`?``:x.endsWith(`/`)?x.slice(0,-1):x,C=new Set(v.routes),w=new Set(v.routes.map(e=>e.endsWith(`/`)?e:e+`/`)),E=new Set(v.routes.map(e=>e.endsWith(`/`)?e.slice(0,-1):e));u===`pretty`&&(0,s.info)(s.colors.dim(`🧪 Running diagnostic checks in parallel...`));let D={root:e,docsDir:p,config:f,doctorConfig:n,linkTree:v,files:g,options:t,routeIndex:C,routeIndexWithSlash:w,routeIndexWithoutSlash:E,basePrefix:S};u===`pretty`&&(0,s.info)(s.colors.dim(`🧪 Running diagnostic checks in parallel...`));let O=[T(D),k(D),A(D),j(D)];t.budget&&O.push(M(D));let[N,P,F,I,...L]=await Promise.all(O),R=t.budget?L[0]??[]:[],z=[...N,...P,...F,...I,...R];if(u===`pretty`){let e=e=>e>0?s.colors.red(`${e} issue${e===1?``:`s`}`):s.colors.green(`OK`),n=[{label:`Metadata checks ${e(N.length)}`,done:N.length===0},{label:`Link checks ${e(P.length)}`,done:P.length===0},{label:`i18n checks ${e(F.length)}`,done:F.length===0},{label:`Sidebar checks ${e(I.length)}`,done:I.length===0}];t.budget&&n.push({label:`Performance budget ${e(R.length)}`,done:R.length===0}),console.log(`\n${(0,s.tasks)(n)}\n`)}let B=0;if(t.fix){for(let e of z)if(e.fix){if(D.doctorConfig.fix.confirmChanges&&!await(0,s.confirm)(`Fix issue in "${e.file}": ${e.message}?`))continue;if(D.doctorConfig.fix.backupFiles){let t=a.default.resolve(D.docsDir,e.file);o.default.existsSync(t)&&await m(t,a.default.resolve(D.root,D.doctorConfig.fix.backupPath))}await e.fix(),B++}}let V=((performance.now()-d)/1e3).toFixed(2),H=z.filter(e=>e.level===`high`).length,U=z.filter(e=>e.level===`warning`).length,W=z.filter(e=>e.level===`low`).length,G={summary:{total:z.length,high:H,warning:U,low:W,fixed:B,duration:V},issues:z.map(e=>({...e,fix:void 0}))};if(n.reporting.outputFile){let t=a.default.resolve(e,n.reporting.outputFile);o.default.existsSync(a.default.dirname(t))||o.default.mkdirSync(a.default.dirname(t),{recursive:!0}),o.default.writeFileSync(t,JSON.stringify(G,null,2))}if(u===`json`)console.log(JSON.stringify(G,null,2));else if(u===`pretty`){let e=z.reduce((e,t)=>(e[t.file]||(e[t.file]=[]),e[t.file].push(t),e),{});if(z.length>0){console.log((0,s.section)({title:`Issues`,colors:{title:i.r}}));for(let[n,r]of Object.entries(e)){let e=r.some(e=>e.level===`high`)?`high`:r.some(e=>e.level===`warning`)?`warning`:`low`,a=e.toUpperCase(),o=e===`high`?(0,s.badge)({label:a,status:`error`}):e===`warning`?(0,s.badge)({label:a,status:`warning`}):(0,s.badge)({label:a,colors:{text:`#ffffff`,bg:i.r}});console.log(`\n ${o} ${s.colors.bold(n)}`);for(let e of r){let n=e.level===`high`?`✖`:e.level===`warning`?`⚠`:`ℹ`,r=e.level===`high`?s.colors.red:e.level===`warning`?s.colors.yellow:e=>(0,s.colorize)(e,i.r,`fg`);console.log(` ${r(n)} ${e.message}`),e.suggestion&&console.log(` ${s.colors.dim(`💡 ${e.suggestion}`)}`),t.fix&&e.fix&&console.log(` ${s.colors.green(`✅ Fixed automatically`)}`)}}console.log(``)}z.length===0?(console.log(` ${s.colors.green.bold(`✨ Everything looks perfect!`)} ${s.colors.dim(`— your documentation is in great shape.`)}`),console.log(` ${s.colors.dim(`Scanned ${g.length} file${g.length===1?``:`s`} in ${V}s`)}`)):(console.log(`\n${(0,s.section)({title:`Summary`,colors:{title:i.r}})}`),H>0&&console.log(` ${(0,s.badge)({label:String(H),status:`error`})} ${s.colors.bold(`high`)}`),U>0&&console.log(` ${(0,s.badge)({label:String(U),status:`warning`})} ${s.colors.bold(`warning`)}${U===1?``:`s`}`),W>0&&console.log(` ${(0,s.badge)({label:String(W),colors:{text:`#ffffff`,bg:i.r}})} ${s.colors.bold(`low`)}`),console.log(` ${s.colors.dim(`Scanned ${g.length} file${g.length===1?``:`s`} in ${V}s`)}`),B>0&&(0,s.success)(`Successfully fixed ${B} issues automatically!`),H>0?(0,s.error)(`Please fix the critical errors before building for production.`):(0,s.success)(`No critical issues found. You are ready to go!`))}n.reporting.failOnError&&H>0&&process.exit(1),n.reporting.maxWarnings!==-1&&U>n.reporting.maxWarnings&&(u===`pretty`&&(0,s.error)(`Failed: Too many warnings (${U} > ${n.reporting.maxWarnings})`),process.exit(1))}catch(e){(0,s.error)(`Doctor failed: ${e}`),process.exit(1)}}Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return N}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return M}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return A}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return P}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return d}});
@@ -3,4 +3,4 @@
3
3
  * Copyright (c) 2026 Jesus Alcala
4
4
  * Licensed under the MIT License.
5
5
  */
6
- import{t as e}from"./chunk-BFSpntXv.mjs";import{a as t,d as n,g as r,u as i}from"./utils-8lzafE49.mjs";import{n as a}from"./pages-external-BBw8ObVK.mjs";import{n as o}from"./config-DC0nMMk7.mjs";import{i as s,n as c,r as l,s as u,t as d}from"./update-check-BXD1atVv.mjs";import f from"node:path";import p from"node:fs";import{badge as m,colorize as h,colors as g,confirm as _,error as v,info as y,section as b,success as x,tasks as ee,warn as S}from"@bdocs/dui";import{fdir as C}from"fdir";import te from"picomatch";import{distance as w}from"fastest-levenshtein";const T={$schema:`https://boltdocs.vercel.app/schemas/doctor-config.schema.json`,checks:{metadata:{enabled:!0,titleMin:10,titleMax:60,descriptionMin:50,required:[`title`,`description`],optional:[],validateDates:!1},links:{internal:!0,external:!1,timeout:1e4,concurrency:10,ignore:[]},i18n:{enabled:!0},performance:{enabled:!0,budgets:{maxJSBundleSize:`200kb`,maxCSSBundleSize:`30kb`,maxPageHTMLSize:`80kb`,maxImagesKB:500,maxBuildTime:3e4,maxFontCount:3}}},fix:{confirmChanges:!1,backupFiles:!1,backupPath:`.boltdocs/backups`},reporting:{format:`pretty`,outputFile:`.boltdocs/reports/doctor.json`,failOnError:!1,maxWarnings:-1},severity:{missingTranslation:`warning`,brokenLink:`high`,brokenAnchor:`warning`,largeFile:`warning`,orphanedPage:`low`,duplicateTitle:`low`,shortMetadata:`low`,missingMetadata:`warning`,malformedFrontmatter:`high`,invalidFrontmatter:`high`,budgetExceeded:`warning`},exclude:[]};function E(e,t){if(e==null)return t;if(typeof e==`number`)return e;let n=e.toLowerCase().match(/^(\d+(?:\.\d+)?)\s*(b|kb|mb|gb)?$/);if(!n)return t;let r=Number.parseFloat(n[1]),i=n[2]||`b`;return Math.round(r*({b:1,kb:1024,mb:1024*1024,gb:1024*1024*1024}[i]||1))}function D(e,t,n){return e.doctorConfig.severity[t]||n}async function ne(e,t){p.existsSync(t)||p.mkdirSync(t,{recursive:!0});let n=f.basename(e),r=new Date().toISOString().replace(/[:.]/g,`-`),i=f.join(t,`${n}.${r}.bak`);p.copyFileSync(e,i)}const O=new Map;function k(e){let t=O.get(e);if(t)return t;let r=(async()=>{let t=await n(e,!1);return{raw:t.raw,data:t.data,content:t.content}})();return O.set(e,r),r}const A=new Map;function j(e){if(A.has(e))return A.get(e);let t=!1;try{t=p.existsSync(e)&&p.statSync(e).isFile()}catch{t=!1}return A.set(e,t),t}async function M(e){let t=f.resolve(e,`doctor.json`);if(p.existsSync(t))try{let e=JSON.parse(p.readFileSync(t,`utf-8`));return{...T,...e,checks:{...T.checks,...e.checks,metadata:{...T.checks.metadata,...e.checks?.metadata},links:{...T.checks.links,...e.checks?.links},i18n:{...T.checks.i18n,...e.checks?.i18n},performance:{...T.checks.performance,...e.checks?.performance,budgets:{...T.checks.performance?.budgets,...e.checks?.performance?.budgets}}},fix:{...T.fix,...e.fix},reporting:{...T.reporting,...e.reporting},severity:{...T.severity,...e.severity},exclude:[...T.exclude,...e.exclude||[]]}}catch(e){S(`Failed to parse doctor.json: ${e}`)}return T}async function N(e,n=process.cwd(),r,i){let o=f.resolve(n,`.boltdocs`,`generated`);p.existsSync(o)||p.mkdirSync(o,{recursive:!0});let s=i;s||=await new C().withFullPaths().filter(e=>e.endsWith(`.md`)||e.endsWith(`.mdx`)).crawl(e).withPromise();let c=r?.base||`/`,l=[];for(let n=0;n<s.length;n+=100){let r=s.slice(n,n+100),i=await Promise.all(r.map(async n=>{let r=f.isAbsolute(n)?n:f.resolve(e,n),i=f.relative(e,r),{data:a}=await k(r),o;return o=a.permalink?String(a.permalink).startsWith(`/`)?String(a.permalink):`/${a.permalink}`:t(i),c===`/`?o:(c.endsWith(`/`)?c:c+`/`)+(o.startsWith(`/`)?o.substring(1):o)}));l.push(...i)}l.includes(c)||l.push(c);let u=a(e,r);for(let e of u)l.includes(e)||l.push(e);let d={routes:Array.from(new Set(l)).sort(),timestamp:Date.now()};return p.writeFileSync(f.resolve(o,`link-tree.json`),JSON.stringify(d,null,2)),d}function P(e,t){if(e===t)return 1;if(!e||!t)return 0;let n=e.split(`/`).filter(Boolean),r=t.split(`/`).filter(Boolean),i=n[n.length-1]||``,a=r[r.length-1]||``;if(i===a){let e=0;for(let t of n)r.includes(t)&&e++;return e>=2?.99:.9}if(i.length>3&&a.length>3&&(a.startsWith(i)||i.startsWith(a))&&Math.min(i.length,a.length)/Math.max(i.length,a.length)>.5)return .88;let o=1-w(i,a)/Math.max(i.length,a.length);return o>.8?o*.95:1-w(e,t)/Math.max(e.length,t.length)}const F=new Map;function I(e,t){if(F.has(e))return F.get(e);let n=e.length,r=``,i=0;for(let a of t){if(a===e)continue;let t=a.length,o=Math.max(n,t);if(o===0)continue;let s=1-Math.abs(n-t)/o;if(s<=.8&&s<=i)continue;let c=P(e,a);c>i&&(i=c,r=a)}let a={bestMatch:r,similarity:i};return F.set(e,a),a}function L(e,t,n){let r=/```[\s\S]*?```/g,i=/`[^`\n]*`/g,a=0,o=[],s=t=>{e=e.replace(t,e=>(o.push(e),`__BD_CODE_MASK_${a++}__`))};return s(r),s(i),e.split(t).join(n).replace(/__BD_CODE_MASK_(\d+)__/g,(e,t)=>o[Number(t)]??``)}async function R(e){let t=[];if(!e.doctorConfig.checks.metadata.enabled)return t;let{titleMin:n,titleMax:a,descriptionMin:o}=e.doctorConfig.checks.metadata,s=new Map;for(let c of e.files){let l=i(f.relative(e.docsDir,c));try{let{raw:i,data:u}=await k(c);if(i.trim().startsWith(`---`)&&i.split(`---`).length>=3&&Object.keys(u).length===0){let n=D(e,`malformedFrontmatter`,`high`);n!==`off`&&t.push({file:l,level:n,message:`Malformed frontmatter (YAML parsing failed).`,suggestion:`Check your YAML syntax for indentation or unquoted special characters.`})}let d=r.safeParse(u);if(!d.success){let n=D(e,`invalidFrontmatter`,`high`);if(n!==`off`)for(let e of d.error.issues)t.push({file:l,level:n,message:`Invalid frontmatter field "${e.path.join(`.`)}": ${e.message}`,suggestion:`Ensure the field follows the correct type.`})}let f=Array.from(new Set([`title`,...e.doctorConfig.checks.metadata.required]));for(let n of f)if(u[n]===void 0){let r=D(e,`missingMetadata`,`warning`);r!==`off`&&t.push({file:l,level:r,message:`Missing required frontmatter field: "${n}".`,suggestion:`Add the "${n}" field to your frontmatter.`})}if(e.doctorConfig.checks.metadata.validateDates){let n=[`date`,`lastUpdated`,...e.doctorConfig.checks.metadata.optional.filter(e=>e.toLowerCase().includes(`date`))];for(let r of n)if(u[r]&&Number.isNaN(Date.parse(String(u[r])))){let n=D(e,`invalidFrontmatter`,`high`);n!==`off`&&t.push({file:l,level:n,message:`Invalid date format in field "${r}": "${u[r]}".`,suggestion:`Use a valid ISO date format (e.g., YYYY-MM-DD).`})}}if(u.title){let r=String(u.title);if(r.length<n){let i=D(e,`shortMetadata`,`low`);i!==`off`&&t.push({file:l,level:i,message:`Title is too short (${r.length} chars).`,suggestion:`Titles should be at least ${n} characters for better SEO.`})}else if(r.length>a){let n=D(e,`shortMetadata`,`low`);n!==`off`&&t.push({file:l,level:n,message:`Title is too long (${r.length} chars).`,suggestion:`Titles should be under ${a} characters.`})}let i=s.get(r)||[];i.push(l),s.set(r,i)}if(u.description&&String(u.description).length<o){let n=D(e,`shortMetadata`,`low`);n!==`off`&&t.push({file:l,level:n,message:`Description is very short.`,suggestion:`Descriptions should ideally be at least ${o} characters.`})}}catch(n){if(n instanceof Error){let r=D(e,`malformedFrontmatter`,`high`);r!==`off`&&t.push({file:l,level:r,message:`Malformed frontmatter (YAML error): ${n.message}`,suggestion:`Check your YAML syntax for indentation or unquoted special characters.`})}}}for(let[n,r]of s.entries())if(r.length>1){let i=D(e,`duplicateTitle`,`low`);if(i!==`off`)for(let e of r)t.push({file:e,level:i,message:`Duplicate title found: "${n}"`,suggestion:`Ensure each page has a unique title. Also used in: ${r.filter(t=>t!==e).join(`, `)}`})}return t}const z=/(?:\[([^\]]*)\]\(([^)\s]+)(?:\s+["'][^"']*["'])?\))|(?:href=["']([^"']+)["'])|(?:<Link\s+[^>]*?to=["'](\/[^"']+)["'])/g,B=[``,`.md`,`.mdx`,`/index.md`,`/index.mdx`];function V(e){let t=[],n=e=>{t.includes(e)||t.push(e)};n(e),e.endsWith(`/`)?n(e.slice(0,-1)):n(e+`/`);let r=e.replace(/\.(md|mdx)$/i,``);r!==e&&(n(r),n(r+`/`));let i=e.replace(/\/index\.(md|mdx)$/i,``);return i!==e&&(n(i),n(i+`/`)),n(e.endsWith(`/`)?e+`index`:e+`/index`),e.endsWith(`/index`)&&n(e.replace(/\/index$/,``)),t}async function H(e){let t=[],{internal:n,external:r,ignore:a,timeout:o,concurrency:s}=e.doctorConfig.checks.links;if(!n&&!r&&!e.options.checkExternal)return t;let c=new Set,l=5e5;for(let o of e.files){let s=i(f.relative(e.docsDir,o)),{content:u}=await k(o),d=[...(u.length>l?u.slice(0,l):u).replace(/<!--[\s\S]*?-->/g,``).replace(/```[\s\S]*?```/g,``).replace(/`[^`\n]*`/g,``).matchAll(z)];for(let i of d){let l=i[2]||i[3]||i[4],u=!!i[2],d=!!i[4];if(!l||a.some(e=>l.includes(e)))continue;if(/^(https?:|mailto:|tel:|data:|javascript:|blob:|ftp:)/i.test(l)){(r||e.options.checkExternal)&&c.add({url:l,file:o});continue}if(l.startsWith(`//`)){(r||e.options.checkExternal)&&c.add({url:l,file:o});continue}if(!n||l.startsWith(`#`))continue;let m;try{m=decodeURIComponent(l.split(`#`)[0].split(`?`)[0])}catch{m=l.split(`#`)[0].split(`?`)[0]}if(!m)continue;let h=!1,g=!1,_=``;if(m.startsWith(`/`)){let t=V(m);for(let n of t)if(e.routeIndex.has(n)||e.routeIndexWithSlash.has(n)||e.routeIndexWithoutSlash.has(n)){h=!0;break}if(!h&&e.basePrefix)for(let n of t){let t=e.basePrefix+(n.startsWith(`/`)?n:`/`+n);if(t!==n&&(e.routeIndex.has(t)||e.routeIndexWithSlash.has(t))){g=!0,_=t;break}}if(!h&&!g){let t=m.replace(/^\/+/,``),n=f.join(e.docsDir,t);h=B.some(e=>j(n+e))}}else{let e=f.resolve(f.dirname(o),m);h=B.some(t=>j(e+t))}if(!h){let{bestMatch:n,similarity:r}=I(m,e.linkTree.routes);g&&(n=_,r=1);let i=r>.6||g,a=r>.75&&n!==m||g,c=D(e,`brokenLink`,`high`);c!==`off`&&t.push({file:s,level:c,message:`Broken internal link: "${l}"`,suggestion:i?`Did you mean "${n}"?`:`Ensure the target exists or check for typos.`,fix:a?async()=>{let e=l.includes(`#`)?`#`+l.split(`#`)[1]:``,t=u?`(${l})`:d?`to="${l}"`:`href="${l}"`,r=u?`(${n}${e})`:d?`to="${n}${e}"`:`href="${n}${e}"`,i=L(p.readFileSync(o,`utf-8`),t,r);p.writeFileSync(o,i),O.delete(o)}:void 0})}}}if(c.size>0){y(g.gray(`Verifying ${c.size} external links...`));let n=new Map;for(let e of c)n.has(e.url)||n.set(e.url,[]),n.get(e.url).push(e.file);let r=async e=>{try{let t=new AbortController,n=setTimeout(()=>t.abort(),o),r=await fetch(e,{method:`HEAD`,signal:t.signal,headers:{"User-Agent":`boltdocs-doctor/1.0`}});return clearTimeout(n),!r.ok&&r.status!==404?{url:e,ok:(await fetch(e,{method:`GET`,signal:t.signal,headers:{"User-Agent":`boltdocs-doctor/1.0`}})).ok}:{url:e,ok:r.ok}}catch(t){return{url:e,ok:!1,error:t instanceof Error?t.message:String(t)}}},a=Array.from(n.keys()),l=[];for(let e=0;e<a.length;e+=s){let t=a.slice(e,e+s),n=await Promise.allSettled(t.map(r));l.push(...n.map(e=>e.status===`fulfilled`?e.value:{url:`unknown`,ok:!1,error:String(e.reason)}))}for(let r of l)if(!r.ok){let a=D(e,`brokenLink`,`warning`);if(a!==`off`){let o=n.get(r.url)||[];for(let n of o)t.push({file:i(f.relative(e.docsDir,n)),level:a,message:`Broken external link: "${r.url}"`,suggestion:`Verify the URL or update it if it's permanently down. Error: ${r.error||`Status >= 400`}`})}}}return t}async function U(e){let t=[];if(!e.doctorConfig.checks.i18n.enabled||!e.config.i18n)return t;let{defaultLocale:n,locales:r}=e.config.i18n,a=Object.keys(r),o=a.filter(e=>e!==n);if(o.length===0)return t;let s=f.resolve(e.docsDir),c=f.join(s,n),l=p.existsSync(c)&&p.statSync(c).isDirectory(),u=e=>{let t=f.resolve(e);if(t!==s&&!t.startsWith(s+f.sep))throw Error(`Refusing to write outside docs dir: ${t}`);return t};for(let r of e.files){let d=i(f.relative(e.docsDir,r)),m=d.split(`/`),h=m[0],g,_;if(a.includes(h)&&h!==n?(g=h,_=m.slice(1).join(`/`)):h===n&&l?(g=n,_=m.slice(1).join(`/`)):(g=n,_=d),_)if(g===n)for(let n of o){let i=f.join(s,n,_);if(!j(i)){let a=D(e,`missingTranslation`,`warning`);a!==`off`&&t.push({file:d,level:a,message:`Missing translation for locale "${n}"`,suggestion:`Create a version at "${n}/${_}".`,fix:async()=>{let e=u(i),t=f.dirname(e);p.existsSync(t)||p.mkdirSync(t,{recursive:!0}),p.copyFileSync(r,e)}})}}else{let i=f.join(s,_),a=l?f.join(c,_):``;if(!(j(i)||a!==``&&j(a))){let i=D(e,`missingTranslation`,`low`);i!==`off`&&t.push({file:d,level:i,message:`Orphaned translation (source missing in "${n}")`,suggestion:`Remove this file or create the source at "${n}/${_}".`,fix:async()=>{p.unlinkSync(u(r))}})}}}return t}async function W(e){let t=[];if(!e.config.theme?.sidebar)return t;let n=new Set,r=e.config.theme.sidebar;for(let[i,a]of Object.entries(r))for(let r of a){if(!r.text){let n=D(e,`invalidFrontmatter`,`warning`);n!==`off`&&t.push({file:`boltdocs.config.ts`,level:n,message:`Sidebar item in group "${i}" is missing a label.`,suggestion:`Add a "text" property to the sidebar item.`})}if(r.link&&(n.add(r.link),!e.routeIndex.has(r.link))){let{bestMatch:n,similarity:i}=I(r.link,e.linkTree.routes),a=i>.6,o=D(e,`brokenLink`,`high`);o!==`off`&&t.push({file:`boltdocs.config.ts`,level:o,message:`Broken sidebar link: "${r.link}"`,suggestion:a?`Did you mean "${n}"?`:`Ensure the route exists and is correctly formatted.`})}}for(let r of e.linkTree.routes)if(!(r===`/`||r===``)&&!n.has(r)){let n=D(e,`orphanedPage`,`low`);n!==`off`&&t.push({file:`Sidebar`,level:n,message:`Orphaned page found: "${r}" is not linked in the sidebar.`,suggestion:`Consider adding it to the sidebar for better discoverability.`})}return t}async function G(e){let t=[],n=e.doctorConfig.checks.performance;if(!n?.enabled)return t;let r=f.resolve(e.root,`.boltdocs`,`reports`,`performance.json`);if(!p.existsSync(r))return t.push({file:`(build)`,level:D(e,`budgetExceeded`,`warning`)??`warning`,message:"Performance metrics not found. Run `boltdocs build` first."}),t;let i;try{i=JSON.parse(p.readFileSync(r,`utf-8`))}catch{return t.push({file:`(build)`,level:D(e,`budgetExceeded`,`warning`)??`warning`,message:`Failed to parse performance metrics file.`}),t}let a=n.budgets,o=D(e,`budgetExceeded`,`warning`),s=E(a?.maxJSBundleSize,1/0),c=E(a?.maxCSSBundleSize,1/0),l=E(a?.maxPageHTMLSize,1/0),u=a?.maxImagesKB??1/0,d=a?.maxBuildTime??1/0,m=a?.maxFontCount??1/0;if(s!==1/0&&i.totalJSBundleSize>s){let e=(i.totalJSBundleSize/1024).toFixed(0),n=(s/1024).toFixed(0);t.push({file:`(build)`,level:o,message:`JS bundle size exceeds budget: ${e}kb > ${n}kb`,suggestion:`Code-split large dependencies or lazy-load route components.`})}if(c!==1/0&&i.totalCSSBundleSize>c){let e=(i.totalCSSBundleSize/1024).toFixed(0),n=(c/1024).toFixed(0);t.push({file:`(build)`,level:o,message:`CSS bundle size exceeds budget: ${e}kb > ${n}kb`,suggestion:`Remove unused styles or split CSS by route.`})}if(l!==1/0){for(let e of i.pages)if(e.htmlSize>l){let n=(e.htmlSize/1024).toFixed(0),r=(l/1024).toFixed(0);t.push({file:e.route,level:o,message:`Page HTML size exceeds budget: ${n}kb > ${r}kb`,suggestion:`Reduce the amount of inline content or split into sub-pages.`})}}let h=u*1024;if(u!==1/0&&i.totalImagesSize>h){let e=(i.totalImagesSize/1024).toFixed(0);t.push({file:`(build)`,level:o,message:`Image assets exceed budget: ${e}kb > ${u}kb`,suggestion:`Optimize images with lossy compression or use next-gen formats (webp/avif).`})}if(d!==1/0&&i.buildTime>d){let e=(i.buildTime/1e3).toFixed(1),n=(d/1e3).toFixed(1);t.push({file:`(build)`,level:o,message:`Build time exceeds budget: ${e}s > ${n}s`,suggestion:"Check for large unoptimized assets or increase `concurrency` in SSG options."})}return m!==1/0&&i.fontCount>m&&t.push({file:`(build)`,level:o,message:`Font files exceed budget: ${i.fontCount} > ${m}`,suggestion:`Reduce the number of font families or use variable fonts.`}),t}var K=e({DEFAULT_DOCTOR_CONFIG:()=>T,checkI18n:()=>U,checkLinks:()=>H,checkMetadata:()=>R,checkPerformance:()=>G,checkSidebar:()=>W,doctorAction:()=>J,doctorInit:()=>q,generateLinkTree:()=>N,loadDoctorConfig:()=>M});async function q(e){let t=f.resolve(e,`doctor.json`);if(p.existsSync(t)){S(`"doctor.json" already exists at ${e}.`);return}try{p.writeFileSync(t,JSON.stringify(T,null,2)),x(`Created "doctor.json" with default configuration.`)}catch(e){v(`Failed to create "doctor.json": ${e}`)}}async function J(e=process.cwd(),t={}){if(t.init){await q(e);return}d();try{let n=await M(e),{format:r}=n.reporting,i=performance.now(),a=await o(`docs`,e),d=f.resolve(e,`docs`);if(p.existsSync(d)||(r===`pretty`&&v(`Docs dir not found at ${d}`),process.exit(1)),r===`pretty`){let t=c?` ${s(`v${c}`)}`:``;console.log(`\n ${g.bold(`⚡`)} ${u(`boltdocs`)}${t} ${g.dim(`—`)} ${g.bold(`doctor`)} ${g.dim(`· documentation health check`)}\n`),console.log(` ${g.dim(`Docs dir ${d}`)}\n ${g.dim(`Reports ${e}/.boltdocs/reports/`)}\n`)}r===`pretty`&&y(g.dim(`🔍 Discovering files and routes...`));let S=te(n.exclude||[]),w=await new C().withFullPaths().filter(e=>{if(!(e.endsWith(`.md`)||e.endsWith(`.mdx`)))return!1;let t=f.relative(d,e).replace(/\\/g,`/`),n=t.split(`/`).some(e=>e.startsWith(`_`)&&e!==`_index.md`&&e!==`_index.mdx`);return!S(t)&&!n}).crawl(d).withPromise();for(let e of w)A.set(e,!0);let T=await N(d,e,a,w),E=a.base||`/`,D=E===`/`?``:E.endsWith(`/`)?E.slice(0,-1):E,O=new Set(T.routes),k=new Set(T.routes.map(e=>e.endsWith(`/`)?e:e+`/`)),j=new Set(T.routes.map(e=>e.endsWith(`/`)?e.slice(0,-1):e));r===`pretty`&&y(g.dim(`🧪 Running diagnostic checks in parallel...`));let P={root:e,docsDir:d,config:a,doctorConfig:n,linkTree:T,files:w,options:t,routeIndex:O,routeIndexWithSlash:k,routeIndexWithoutSlash:j,basePrefix:D};r===`pretty`&&y(g.dim(`🧪 Running diagnostic checks in parallel...`));let F=[R(P),H(P),U(P),W(P)];t.budget&&F.push(G(P));let[I,L,z,B,...V]=await Promise.all(F),K=t.budget?V[0]??[]:[],q=[...I,...L,...z,...B,...K];if(r===`pretty`){let e=e=>e>0?g.red(`${e} issue${e===1?``:`s`}`):g.green(`OK`),n=[{label:`Metadata checks ${e(I.length)}`,done:I.length===0},{label:`Link checks ${e(L.length)}`,done:L.length===0},{label:`i18n checks ${e(z.length)}`,done:z.length===0},{label:`Sidebar checks ${e(B.length)}`,done:B.length===0}];t.budget&&n.push({label:`Performance budget ${e(K.length)}`,done:K.length===0}),console.log(`\n${ee(n)}\n`)}let J=0;if(t.fix){for(let e of q)if(e.fix){if(P.doctorConfig.fix.confirmChanges&&!await _(`Fix issue in "${e.file}": ${e.message}?`))continue;if(P.doctorConfig.fix.backupFiles){let t=f.resolve(P.docsDir,e.file);p.existsSync(t)&&await ne(t,f.resolve(P.root,P.doctorConfig.fix.backupPath))}await e.fix(),J++}}let Y=((performance.now()-i)/1e3).toFixed(2),X=q.filter(e=>e.level===`high`).length,Z=q.filter(e=>e.level===`warning`).length,Q=q.filter(e=>e.level===`low`).length,$={summary:{total:q.length,high:X,warning:Z,low:Q,fixed:J,duration:Y},issues:q.map(e=>({...e,fix:void 0}))};if(n.reporting.outputFile){let t=f.resolve(e,n.reporting.outputFile);p.existsSync(f.dirname(t))||p.mkdirSync(f.dirname(t),{recursive:!0}),p.writeFileSync(t,JSON.stringify($,null,2))}if(r===`json`)console.log(JSON.stringify($,null,2));else if(r===`pretty`){let e=q.reduce((e,t)=>(e[t.file]||(e[t.file]=[]),e[t.file].push(t),e),{});if(q.length>0){console.log(b({title:`Issues`,colors:{title:l}}));for(let[n,r]of Object.entries(e)){let e=r.some(e=>e.level===`high`)?`high`:r.some(e=>e.level===`warning`)?`warning`:`low`,i=e.toUpperCase(),a=m(e===`high`?{label:i,status:`error`}:e===`warning`?{label:i,status:`warning`}:{label:i,colors:{text:`#ffffff`,bg:l}});console.log(`\n ${a} ${g.bold(n)}`);for(let e of r){let n=e.level===`high`?`✖`:e.level===`warning`?`⚠`:`ℹ`,r=e.level===`high`?g.red:e.level===`warning`?g.yellow:e=>h(e,l,`fg`);console.log(` ${r(n)} ${e.message}`),e.suggestion&&console.log(` ${g.dim(`💡 ${e.suggestion}`)}`),t.fix&&e.fix&&console.log(` ${g.green(`✅ Fixed automatically`)}`)}}console.log(``)}q.length===0?(console.log(` ${g.green.bold(`✨ Everything looks perfect!`)} ${g.dim(`— your documentation is in great shape.`)}`),console.log(` ${g.dim(`Scanned ${w.length} file${w.length===1?``:`s`} in ${Y}s`)}`)):(console.log(`\n${b({title:`Summary`,colors:{title:l}})}`),X>0&&console.log(` ${m({label:String(X),status:`error`})} ${g.bold(`high`)}`),Z>0&&console.log(` ${m({label:String(Z),status:`warning`})} ${g.bold(`warning`)}${Z===1?``:`s`}`),Q>0&&console.log(` ${m({label:String(Q),colors:{text:`#ffffff`,bg:l}})} ${g.bold(`low`)}`),console.log(` ${g.dim(`Scanned ${w.length} file${w.length===1?``:`s`} in ${Y}s`)}`),J>0&&x(`Successfully fixed ${J} issues automatically!`),X>0?v(`Please fix the critical errors before building for production.`):x(`No critical issues found. You are ready to go!`))}n.reporting.failOnError&&X>0&&process.exit(1),n.reporting.maxWarnings!==-1&&Z>n.reporting.maxWarnings&&(r===`pretty`&&v(`Failed: Too many warnings (${Z} > ${n.reporting.maxWarnings})`),process.exit(1))}catch(e){v(`Doctor failed: ${e}`),process.exit(1)}}export{N as n,K as t};
6
+ import{t as e}from"./chunk-BFSpntXv.mjs";import{a as t,d as n,g as r,u as i}from"./utils-8lzafE49.mjs";import{n as a}from"./pages-external-BBw8ObVK.mjs";import{n as o}from"./config-B3_iVsbi.mjs";import{i as s,n as c,r as l,s as u,t as d}from"./update-check-BXD1atVv.mjs";import f from"node:path";import p from"node:fs";import{badge as m,colorize as h,colors as g,confirm as _,error as v,info as y,section as b,success as x,tasks as ee,warn as S}from"@bdocs/dui";import{fdir as C}from"fdir";import te from"picomatch";import{distance as w}from"fastest-levenshtein";const T={$schema:`https://boltdocs.vercel.app/schemas/doctor-config.schema.json`,checks:{metadata:{enabled:!0,titleMin:10,titleMax:60,descriptionMin:50,required:[`title`,`description`],optional:[],validateDates:!1},links:{internal:!0,external:!1,timeout:1e4,concurrency:10,ignore:[]},i18n:{enabled:!0},performance:{enabled:!0,budgets:{maxJSBundleSize:`200kb`,maxCSSBundleSize:`30kb`,maxPageHTMLSize:`80kb`,maxImagesKB:500,maxBuildTime:3e4,maxFontCount:3}}},fix:{confirmChanges:!1,backupFiles:!1,backupPath:`.boltdocs/backups`},reporting:{format:`pretty`,outputFile:`.boltdocs/reports/doctor.json`,failOnError:!1,maxWarnings:-1},severity:{missingTranslation:`warning`,brokenLink:`high`,brokenAnchor:`warning`,largeFile:`warning`,orphanedPage:`low`,duplicateTitle:`low`,shortMetadata:`low`,missingMetadata:`warning`,malformedFrontmatter:`high`,invalidFrontmatter:`high`,budgetExceeded:`warning`},exclude:[]};function E(e,t){if(e==null)return t;if(typeof e==`number`)return e;let n=e.toLowerCase().match(/^(\d+(?:\.\d+)?)\s*(b|kb|mb|gb)?$/);if(!n)return t;let r=Number.parseFloat(n[1]),i=n[2]||`b`;return Math.round(r*({b:1,kb:1024,mb:1024*1024,gb:1024*1024*1024}[i]||1))}function D(e,t,n){return e.doctorConfig.severity[t]||n}async function ne(e,t){p.existsSync(t)||p.mkdirSync(t,{recursive:!0});let n=f.basename(e),r=new Date().toISOString().replace(/[:.]/g,`-`),i=f.join(t,`${n}.${r}.bak`);p.copyFileSync(e,i)}const O=new Map;function k(e){let t=O.get(e);if(t)return t;let r=(async()=>{let t=await n(e,!1);return{raw:t.raw,data:t.data,content:t.content}})();return O.set(e,r),r}const A=new Map;function j(e){if(A.has(e))return A.get(e);let t=!1;try{t=p.existsSync(e)&&p.statSync(e).isFile()}catch{t=!1}return A.set(e,t),t}async function M(e){let t=f.resolve(e,`doctor.json`);if(p.existsSync(t))try{let e=JSON.parse(p.readFileSync(t,`utf-8`));return{...T,...e,checks:{...T.checks,...e.checks,metadata:{...T.checks.metadata,...e.checks?.metadata},links:{...T.checks.links,...e.checks?.links},i18n:{...T.checks.i18n,...e.checks?.i18n},performance:{...T.checks.performance,...e.checks?.performance,budgets:{...T.checks.performance?.budgets,...e.checks?.performance?.budgets}}},fix:{...T.fix,...e.fix},reporting:{...T.reporting,...e.reporting},severity:{...T.severity,...e.severity},exclude:[...T.exclude,...e.exclude||[]]}}catch(e){S(`Failed to parse doctor.json: ${e}`)}return T}async function N(e,n=process.cwd(),r,i){let o=f.resolve(n,`.boltdocs`,`generated`);p.existsSync(o)||p.mkdirSync(o,{recursive:!0});let s=i;s||=await new C().withFullPaths().filter(e=>e.endsWith(`.md`)||e.endsWith(`.mdx`)).crawl(e).withPromise();let c=r?.base||`/`,l=[];for(let n=0;n<s.length;n+=100){let r=s.slice(n,n+100),i=await Promise.all(r.map(async n=>{let r=f.isAbsolute(n)?n:f.resolve(e,n),i=f.relative(e,r),{data:a}=await k(r),o;return o=a.permalink?String(a.permalink).startsWith(`/`)?String(a.permalink):`/${a.permalink}`:t(i),c===`/`?o:(c.endsWith(`/`)?c:c+`/`)+(o.startsWith(`/`)?o.substring(1):o)}));l.push(...i)}l.includes(c)||l.push(c);let u=a(e,r);for(let e of u)l.includes(e)||l.push(e);let d={routes:Array.from(new Set(l)).sort(),timestamp:Date.now()};return p.writeFileSync(f.resolve(o,`link-tree.json`),JSON.stringify(d,null,2)),d}function P(e,t){if(e===t)return 1;if(!e||!t)return 0;let n=e.split(`/`).filter(Boolean),r=t.split(`/`).filter(Boolean),i=n[n.length-1]||``,a=r[r.length-1]||``;if(i===a){let e=0;for(let t of n)r.includes(t)&&e++;return e>=2?.99:.9}if(i.length>3&&a.length>3&&(a.startsWith(i)||i.startsWith(a))&&Math.min(i.length,a.length)/Math.max(i.length,a.length)>.5)return .88;let o=1-w(i,a)/Math.max(i.length,a.length);return o>.8?o*.95:1-w(e,t)/Math.max(e.length,t.length)}const F=new Map;function I(e,t){if(F.has(e))return F.get(e);let n=e.length,r=``,i=0;for(let a of t){if(a===e)continue;let t=a.length,o=Math.max(n,t);if(o===0)continue;let s=1-Math.abs(n-t)/o;if(s<=.8&&s<=i)continue;let c=P(e,a);c>i&&(i=c,r=a)}let a={bestMatch:r,similarity:i};return F.set(e,a),a}function L(e,t,n){let r=/```[\s\S]*?```/g,i=/`[^`\n]*`/g,a=0,o=[],s=t=>{e=e.replace(t,e=>(o.push(e),`__BD_CODE_MASK_${a++}__`))};return s(r),s(i),e.split(t).join(n).replace(/__BD_CODE_MASK_(\d+)__/g,(e,t)=>o[Number(t)]??``)}async function R(e){let t=[];if(!e.doctorConfig.checks.metadata.enabled)return t;let{titleMin:n,titleMax:a,descriptionMin:o}=e.doctorConfig.checks.metadata,s=new Map;for(let c of e.files){let l=i(f.relative(e.docsDir,c));try{let{raw:i,data:u}=await k(c);if(i.trim().startsWith(`---`)&&i.split(`---`).length>=3&&Object.keys(u).length===0){let n=D(e,`malformedFrontmatter`,`high`);n!==`off`&&t.push({file:l,level:n,message:`Malformed frontmatter (YAML parsing failed).`,suggestion:`Check your YAML syntax for indentation or unquoted special characters.`})}let d=r.safeParse(u);if(!d.success){let n=D(e,`invalidFrontmatter`,`high`);if(n!==`off`)for(let e of d.error.issues)t.push({file:l,level:n,message:`Invalid frontmatter field "${e.path.join(`.`)}": ${e.message}`,suggestion:`Ensure the field follows the correct type.`})}let f=Array.from(new Set([`title`,...e.doctorConfig.checks.metadata.required]));for(let n of f)if(u[n]===void 0){let r=D(e,`missingMetadata`,`warning`);r!==`off`&&t.push({file:l,level:r,message:`Missing required frontmatter field: "${n}".`,suggestion:`Add the "${n}" field to your frontmatter.`})}if(e.doctorConfig.checks.metadata.validateDates){let n=[`date`,`lastUpdated`,...e.doctorConfig.checks.metadata.optional.filter(e=>e.toLowerCase().includes(`date`))];for(let r of n)if(u[r]&&Number.isNaN(Date.parse(String(u[r])))){let n=D(e,`invalidFrontmatter`,`high`);n!==`off`&&t.push({file:l,level:n,message:`Invalid date format in field "${r}": "${u[r]}".`,suggestion:`Use a valid ISO date format (e.g., YYYY-MM-DD).`})}}if(u.title){let r=String(u.title);if(r.length<n){let i=D(e,`shortMetadata`,`low`);i!==`off`&&t.push({file:l,level:i,message:`Title is too short (${r.length} chars).`,suggestion:`Titles should be at least ${n} characters for better SEO.`})}else if(r.length>a){let n=D(e,`shortMetadata`,`low`);n!==`off`&&t.push({file:l,level:n,message:`Title is too long (${r.length} chars).`,suggestion:`Titles should be under ${a} characters.`})}let i=s.get(r)||[];i.push(l),s.set(r,i)}if(u.description&&String(u.description).length<o){let n=D(e,`shortMetadata`,`low`);n!==`off`&&t.push({file:l,level:n,message:`Description is very short.`,suggestion:`Descriptions should ideally be at least ${o} characters.`})}}catch(n){if(n instanceof Error){let r=D(e,`malformedFrontmatter`,`high`);r!==`off`&&t.push({file:l,level:r,message:`Malformed frontmatter (YAML error): ${n.message}`,suggestion:`Check your YAML syntax for indentation or unquoted special characters.`})}}}for(let[n,r]of s.entries())if(r.length>1){let i=D(e,`duplicateTitle`,`low`);if(i!==`off`)for(let e of r)t.push({file:e,level:i,message:`Duplicate title found: "${n}"`,suggestion:`Ensure each page has a unique title. Also used in: ${r.filter(t=>t!==e).join(`, `)}`})}return t}const z=/(?:\[([^\]]*)\]\(([^)\s]+)(?:\s+["'][^"']*["'])?\))|(?:href=["']([^"']+)["'])|(?:<Link\s+[^>]*?to=["'](\/[^"']+)["'])/g,B=[``,`.md`,`.mdx`,`/index.md`,`/index.mdx`];function V(e){let t=[],n=e=>{t.includes(e)||t.push(e)};n(e),e.endsWith(`/`)?n(e.slice(0,-1)):n(e+`/`);let r=e.replace(/\.(md|mdx)$/i,``);r!==e&&(n(r),n(r+`/`));let i=e.replace(/\/index\.(md|mdx)$/i,``);return i!==e&&(n(i),n(i+`/`)),n(e.endsWith(`/`)?e+`index`:e+`/index`),e.endsWith(`/index`)&&n(e.replace(/\/index$/,``)),t}async function H(e){let t=[],{internal:n,external:r,ignore:a,timeout:o,concurrency:s}=e.doctorConfig.checks.links;if(!n&&!r&&!e.options.checkExternal)return t;let c=new Set,l=5e5;for(let o of e.files){let s=i(f.relative(e.docsDir,o)),{content:u}=await k(o),d=[...(u.length>l?u.slice(0,l):u).replace(/<!--[\s\S]*?-->/g,``).replace(/```[\s\S]*?```/g,``).replace(/`[^`\n]*`/g,``).matchAll(z)];for(let i of d){let l=i[2]||i[3]||i[4],u=!!i[2],d=!!i[4];if(!l||a.some(e=>l.includes(e)))continue;if(/^(https?:|mailto:|tel:|data:|javascript:|blob:|ftp:)/i.test(l)){(r||e.options.checkExternal)&&c.add({url:l,file:o});continue}if(l.startsWith(`//`)){(r||e.options.checkExternal)&&c.add({url:l,file:o});continue}if(!n||l.startsWith(`#`))continue;let m;try{m=decodeURIComponent(l.split(`#`)[0].split(`?`)[0])}catch{m=l.split(`#`)[0].split(`?`)[0]}if(!m)continue;let h=!1,g=!1,_=``;if(m.startsWith(`/`)){let t=V(m);for(let n of t)if(e.routeIndex.has(n)||e.routeIndexWithSlash.has(n)||e.routeIndexWithoutSlash.has(n)){h=!0;break}if(!h&&e.basePrefix)for(let n of t){let t=e.basePrefix+(n.startsWith(`/`)?n:`/`+n);if(t!==n&&(e.routeIndex.has(t)||e.routeIndexWithSlash.has(t))){g=!0,_=t;break}}if(!h&&!g){let t=m.replace(/^\/+/,``),n=f.join(e.docsDir,t);h=B.some(e=>j(n+e))}}else{let e=f.resolve(f.dirname(o),m);h=B.some(t=>j(e+t))}if(!h){let{bestMatch:n,similarity:r}=I(m,e.linkTree.routes);g&&(n=_,r=1);let i=r>.6||g,a=r>.75&&n!==m||g,c=D(e,`brokenLink`,`high`);c!==`off`&&t.push({file:s,level:c,message:`Broken internal link: "${l}"`,suggestion:i?`Did you mean "${n}"?`:`Ensure the target exists or check for typos.`,fix:a?async()=>{let e=l.includes(`#`)?`#`+l.split(`#`)[1]:``,t=u?`(${l})`:d?`to="${l}"`:`href="${l}"`,r=u?`(${n}${e})`:d?`to="${n}${e}"`:`href="${n}${e}"`,i=L(p.readFileSync(o,`utf-8`),t,r);p.writeFileSync(o,i),O.delete(o)}:void 0})}}}if(c.size>0){y(g.gray(`Verifying ${c.size} external links...`));let n=new Map;for(let e of c)n.has(e.url)||n.set(e.url,[]),n.get(e.url).push(e.file);let r=async e=>{try{let t=new AbortController,n=setTimeout(()=>t.abort(),o),r=await fetch(e,{method:`HEAD`,signal:t.signal,headers:{"User-Agent":`boltdocs-doctor/1.0`}});return clearTimeout(n),!r.ok&&r.status!==404?{url:e,ok:(await fetch(e,{method:`GET`,signal:t.signal,headers:{"User-Agent":`boltdocs-doctor/1.0`}})).ok}:{url:e,ok:r.ok}}catch(t){return{url:e,ok:!1,error:t instanceof Error?t.message:String(t)}}},a=Array.from(n.keys()),l=[];for(let e=0;e<a.length;e+=s){let t=a.slice(e,e+s),n=await Promise.allSettled(t.map(r));l.push(...n.map(e=>e.status===`fulfilled`?e.value:{url:`unknown`,ok:!1,error:String(e.reason)}))}for(let r of l)if(!r.ok){let a=D(e,`brokenLink`,`warning`);if(a!==`off`){let o=n.get(r.url)||[];for(let n of o)t.push({file:i(f.relative(e.docsDir,n)),level:a,message:`Broken external link: "${r.url}"`,suggestion:`Verify the URL or update it if it's permanently down. Error: ${r.error||`Status >= 400`}`})}}}return t}async function U(e){let t=[];if(!e.doctorConfig.checks.i18n.enabled||!e.config.i18n)return t;let{defaultLocale:n,locales:r}=e.config.i18n,a=Object.keys(r),o=a.filter(e=>e!==n);if(o.length===0)return t;let s=f.resolve(e.docsDir),c=f.join(s,n),l=p.existsSync(c)&&p.statSync(c).isDirectory(),u=e=>{let t=f.resolve(e);if(t!==s&&!t.startsWith(s+f.sep))throw Error(`Refusing to write outside docs dir: ${t}`);return t};for(let r of e.files){let d=i(f.relative(e.docsDir,r)),m=d.split(`/`),h=m[0],g,_;if(a.includes(h)&&h!==n?(g=h,_=m.slice(1).join(`/`)):h===n&&l?(g=n,_=m.slice(1).join(`/`)):(g=n,_=d),_)if(g===n)for(let n of o){let i=f.join(s,n,_);if(!j(i)){let a=D(e,`missingTranslation`,`warning`);a!==`off`&&t.push({file:d,level:a,message:`Missing translation for locale "${n}"`,suggestion:`Create a version at "${n}/${_}".`,fix:async()=>{let e=u(i),t=f.dirname(e);p.existsSync(t)||p.mkdirSync(t,{recursive:!0}),p.copyFileSync(r,e)}})}}else{let i=f.join(s,_),a=l?f.join(c,_):``;if(!(j(i)||a!==``&&j(a))){let i=D(e,`missingTranslation`,`low`);i!==`off`&&t.push({file:d,level:i,message:`Orphaned translation (source missing in "${n}")`,suggestion:`Remove this file or create the source at "${n}/${_}".`,fix:async()=>{p.unlinkSync(u(r))}})}}}return t}async function W(e){let t=[];if(!e.config.theme?.sidebar)return t;let n=new Set,r=e.config.theme.sidebar;for(let[i,a]of Object.entries(r))for(let r of a){if(!r.text){let n=D(e,`invalidFrontmatter`,`warning`);n!==`off`&&t.push({file:`boltdocs.config.ts`,level:n,message:`Sidebar item in group "${i}" is missing a label.`,suggestion:`Add a "text" property to the sidebar item.`})}if(r.link&&(n.add(r.link),!e.routeIndex.has(r.link))){let{bestMatch:n,similarity:i}=I(r.link,e.linkTree.routes),a=i>.6,o=D(e,`brokenLink`,`high`);o!==`off`&&t.push({file:`boltdocs.config.ts`,level:o,message:`Broken sidebar link: "${r.link}"`,suggestion:a?`Did you mean "${n}"?`:`Ensure the route exists and is correctly formatted.`})}}for(let r of e.linkTree.routes)if(!(r===`/`||r===``)&&!n.has(r)){let n=D(e,`orphanedPage`,`low`);n!==`off`&&t.push({file:`Sidebar`,level:n,message:`Orphaned page found: "${r}" is not linked in the sidebar.`,suggestion:`Consider adding it to the sidebar for better discoverability.`})}return t}async function G(e){let t=[],n=e.doctorConfig.checks.performance;if(!n?.enabled)return t;let r=f.resolve(e.root,`.boltdocs`,`reports`,`performance.json`);if(!p.existsSync(r))return t.push({file:`(build)`,level:D(e,`budgetExceeded`,`warning`)??`warning`,message:"Performance metrics not found. Run `boltdocs build` first."}),t;let i;try{i=JSON.parse(p.readFileSync(r,`utf-8`))}catch{return t.push({file:`(build)`,level:D(e,`budgetExceeded`,`warning`)??`warning`,message:`Failed to parse performance metrics file.`}),t}let a=n.budgets,o=D(e,`budgetExceeded`,`warning`),s=E(a?.maxJSBundleSize,1/0),c=E(a?.maxCSSBundleSize,1/0),l=E(a?.maxPageHTMLSize,1/0),u=a?.maxImagesKB??1/0,d=a?.maxBuildTime??1/0,m=a?.maxFontCount??1/0;if(s!==1/0&&i.totalJSBundleSize>s){let e=(i.totalJSBundleSize/1024).toFixed(0),n=(s/1024).toFixed(0);t.push({file:`(build)`,level:o,message:`JS bundle size exceeds budget: ${e}kb > ${n}kb`,suggestion:`Code-split large dependencies or lazy-load route components.`})}if(c!==1/0&&i.totalCSSBundleSize>c){let e=(i.totalCSSBundleSize/1024).toFixed(0),n=(c/1024).toFixed(0);t.push({file:`(build)`,level:o,message:`CSS bundle size exceeds budget: ${e}kb > ${n}kb`,suggestion:`Remove unused styles or split CSS by route.`})}if(l!==1/0){for(let e of i.pages)if(e.htmlSize>l){let n=(e.htmlSize/1024).toFixed(0),r=(l/1024).toFixed(0);t.push({file:e.route,level:o,message:`Page HTML size exceeds budget: ${n}kb > ${r}kb`,suggestion:`Reduce the amount of inline content or split into sub-pages.`})}}let h=u*1024;if(u!==1/0&&i.totalImagesSize>h){let e=(i.totalImagesSize/1024).toFixed(0);t.push({file:`(build)`,level:o,message:`Image assets exceed budget: ${e}kb > ${u}kb`,suggestion:`Optimize images with lossy compression or use next-gen formats (webp/avif).`})}if(d!==1/0&&i.buildTime>d){let e=(i.buildTime/1e3).toFixed(1),n=(d/1e3).toFixed(1);t.push({file:`(build)`,level:o,message:`Build time exceeds budget: ${e}s > ${n}s`,suggestion:"Check for large unoptimized assets or increase `concurrency` in SSG options."})}return m!==1/0&&i.fontCount>m&&t.push({file:`(build)`,level:o,message:`Font files exceed budget: ${i.fontCount} > ${m}`,suggestion:`Reduce the number of font families or use variable fonts.`}),t}var K=e({DEFAULT_DOCTOR_CONFIG:()=>T,checkI18n:()=>U,checkLinks:()=>H,checkMetadata:()=>R,checkPerformance:()=>G,checkSidebar:()=>W,doctorAction:()=>J,doctorInit:()=>q,generateLinkTree:()=>N,loadDoctorConfig:()=>M});async function q(e){let t=f.resolve(e,`doctor.json`);if(p.existsSync(t)){S(`"doctor.json" already exists at ${e}.`);return}try{p.writeFileSync(t,JSON.stringify(T,null,2)),x(`Created "doctor.json" with default configuration.`)}catch(e){v(`Failed to create "doctor.json": ${e}`)}}async function J(e=process.cwd(),t={}){if(t.init){await q(e);return}d();try{let n=await M(e),{format:r}=n.reporting,i=performance.now(),a=await o(`docs`,e),d=f.resolve(e,`docs`);if(p.existsSync(d)||(r===`pretty`&&v(`Docs dir not found at ${d}`),process.exit(1)),r===`pretty`){let t=c?` ${s(`v${c}`)}`:``;console.log(`\n ${g.bold(`⚡`)} ${u(`boltdocs`)}${t} ${g.dim(`—`)} ${g.bold(`doctor`)} ${g.dim(`· documentation health check`)}\n`),console.log(` ${g.dim(`Docs dir ${d}`)}\n ${g.dim(`Reports ${e}/.boltdocs/reports/`)}\n`)}r===`pretty`&&y(g.dim(`🔍 Discovering files and routes...`));let S=te(n.exclude||[]),w=await new C().withFullPaths().filter(e=>{if(!(e.endsWith(`.md`)||e.endsWith(`.mdx`)))return!1;let t=f.relative(d,e).replace(/\\/g,`/`),n=t.split(`/`).some(e=>e.startsWith(`_`)&&e!==`_index.md`&&e!==`_index.mdx`);return!S(t)&&!n}).crawl(d).withPromise();for(let e of w)A.set(e,!0);let T=await N(d,e,a,w),E=a.base||`/`,D=E===`/`?``:E.endsWith(`/`)?E.slice(0,-1):E,O=new Set(T.routes),k=new Set(T.routes.map(e=>e.endsWith(`/`)?e:e+`/`)),j=new Set(T.routes.map(e=>e.endsWith(`/`)?e.slice(0,-1):e));r===`pretty`&&y(g.dim(`🧪 Running diagnostic checks in parallel...`));let P={root:e,docsDir:d,config:a,doctorConfig:n,linkTree:T,files:w,options:t,routeIndex:O,routeIndexWithSlash:k,routeIndexWithoutSlash:j,basePrefix:D};r===`pretty`&&y(g.dim(`🧪 Running diagnostic checks in parallel...`));let F=[R(P),H(P),U(P),W(P)];t.budget&&F.push(G(P));let[I,L,z,B,...V]=await Promise.all(F),K=t.budget?V[0]??[]:[],q=[...I,...L,...z,...B,...K];if(r===`pretty`){let e=e=>e>0?g.red(`${e} issue${e===1?``:`s`}`):g.green(`OK`),n=[{label:`Metadata checks ${e(I.length)}`,done:I.length===0},{label:`Link checks ${e(L.length)}`,done:L.length===0},{label:`i18n checks ${e(z.length)}`,done:z.length===0},{label:`Sidebar checks ${e(B.length)}`,done:B.length===0}];t.budget&&n.push({label:`Performance budget ${e(K.length)}`,done:K.length===0}),console.log(`\n${ee(n)}\n`)}let J=0;if(t.fix){for(let e of q)if(e.fix){if(P.doctorConfig.fix.confirmChanges&&!await _(`Fix issue in "${e.file}": ${e.message}?`))continue;if(P.doctorConfig.fix.backupFiles){let t=f.resolve(P.docsDir,e.file);p.existsSync(t)&&await ne(t,f.resolve(P.root,P.doctorConfig.fix.backupPath))}await e.fix(),J++}}let Y=((performance.now()-i)/1e3).toFixed(2),X=q.filter(e=>e.level===`high`).length,Z=q.filter(e=>e.level===`warning`).length,Q=q.filter(e=>e.level===`low`).length,$={summary:{total:q.length,high:X,warning:Z,low:Q,fixed:J,duration:Y},issues:q.map(e=>({...e,fix:void 0}))};if(n.reporting.outputFile){let t=f.resolve(e,n.reporting.outputFile);p.existsSync(f.dirname(t))||p.mkdirSync(f.dirname(t),{recursive:!0}),p.writeFileSync(t,JSON.stringify($,null,2))}if(r===`json`)console.log(JSON.stringify($,null,2));else if(r===`pretty`){let e=q.reduce((e,t)=>(e[t.file]||(e[t.file]=[]),e[t.file].push(t),e),{});if(q.length>0){console.log(b({title:`Issues`,colors:{title:l}}));for(let[n,r]of Object.entries(e)){let e=r.some(e=>e.level===`high`)?`high`:r.some(e=>e.level===`warning`)?`warning`:`low`,i=e.toUpperCase(),a=m(e===`high`?{label:i,status:`error`}:e===`warning`?{label:i,status:`warning`}:{label:i,colors:{text:`#ffffff`,bg:l}});console.log(`\n ${a} ${g.bold(n)}`);for(let e of r){let n=e.level===`high`?`✖`:e.level===`warning`?`⚠`:`ℹ`,r=e.level===`high`?g.red:e.level===`warning`?g.yellow:e=>h(e,l,`fg`);console.log(` ${r(n)} ${e.message}`),e.suggestion&&console.log(` ${g.dim(`💡 ${e.suggestion}`)}`),t.fix&&e.fix&&console.log(` ${g.green(`✅ Fixed automatically`)}`)}}console.log(``)}q.length===0?(console.log(` ${g.green.bold(`✨ Everything looks perfect!`)} ${g.dim(`— your documentation is in great shape.`)}`),console.log(` ${g.dim(`Scanned ${w.length} file${w.length===1?``:`s`} in ${Y}s`)}`)):(console.log(`\n${b({title:`Summary`,colors:{title:l}})}`),X>0&&console.log(` ${m({label:String(X),status:`error`})} ${g.bold(`high`)}`),Z>0&&console.log(` ${m({label:String(Z),status:`warning`})} ${g.bold(`warning`)}${Z===1?``:`s`}`),Q>0&&console.log(` ${m({label:String(Q),colors:{text:`#ffffff`,bg:l}})} ${g.bold(`low`)}`),console.log(` ${g.dim(`Scanned ${w.length} file${w.length===1?``:`s`} in ${Y}s`)}`),J>0&&x(`Successfully fixed ${J} issues automatically!`),X>0?v(`Please fix the critical errors before building for production.`):x(`No critical issues found. You are ready to go!`))}n.reporting.failOnError&&X>0&&process.exit(1),n.reporting.maxWarnings!==-1&&Z>n.reporting.maxWarnings&&(r===`pretty`&&v(`Failed: Too many warnings (${Z} > ${n.reporting.maxWarnings})`),process.exit(1))}catch(e){v(`Doctor failed: ${e}`),process.exit(1)}}export{N as n,K as t};
@@ -3,4 +3,4 @@
3
3
  * Copyright (c) 2026 Jesus Alcala
4
4
  * Licensed under the MIT License.
5
5
  */
6
- const e=require(`./doctor-DMECtdK6.cjs`);exports.doctorAction=e.t;
6
+ const e=require(`./doctor-BqxOFRt3.cjs`);exports.doctorAction=e.t;
@@ -3,7 +3,7 @@
3
3
  * Copyright (c) 2026 Jesus Alcala
4
4
  * Licensed under the MIT License.
5
5
  */
6
- import { M as Link, W as useConfig, d as resolvePublicAssetUrl, o as cn, t as Link$1 } from "./link-CgdI6O2o.js";
6
+ import { G as useConfig, N as Link, f as resolvePublicAssetUrl, o as cn, t as Link$1 } from "./link-q1qHNGK_.js";
7
7
  import * as React$1 from "react";
8
8
  import { createContext, use, useEffect, useState } from "react";
9
9
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -4,7 +4,7 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  const require_router = require('./router-C3kygdRK.cjs');
7
- const require_link = require('./link-vZjmD-es.cjs');
7
+ const require_link = require('./link-hLWOsx0x.cjs');
8
8
  let react = require("react");
9
9
  react = require_router.__toESM(react);
10
10
  let react_jsx_runtime = require("react/jsx-runtime");
@@ -253,11 +253,15 @@ interface CreateRoutesOptions {
253
253
  collectionPosts?: Record<string, React$1.ComponentType<any>>;
254
254
  config: BoltdocsConfig;
255
255
  mdxModules: Record<string, any>;
256
- externalPages?: Record<string, React$1.ComponentType>;
256
+ externalPages?: Record<string, React$1.ComponentType | (() => Promise<{
257
+ default: React$1.ComponentType;
258
+ }>)>;
257
259
  externalLayout?: React$1.ComponentType<{
258
260
  children: React$1.ReactNode;
259
261
  }>;
260
- externalFilePages?: Record<string, React$1.ComponentType>;
262
+ externalFilePages?: Record<string, React$1.ComponentType | (() => Promise<{
263
+ default: React$1.ComponentType;
264
+ }>)>;
261
265
  externalFileMdx?: Record<string, unknown>;
262
266
  components?: Record<string, React$1.ComponentType>;
263
267
  }
@@ -391,7 +395,14 @@ declare function useSidebar(routes: ComponentRoute[]): {
391
395
  };
392
396
  //#endregion
393
397
  //#region src/client/hooks/use-search.d.ts
394
- declare function useSearch(routes: ComponentRoute[]): {
398
+ type SearchStatus = 'idle' | 'loading' | 'indexing' | 'ready' | 'searching' | 'error';
399
+ interface SearchHotContext {
400
+ on: (event: string, callback: (payload?: unknown) => void) => void;
401
+ off?: (event: string, callback: (payload?: unknown) => void) => void;
402
+ }
403
+ declare function useSearch(routes: ComponentRoute[], options?: {
404
+ hot?: SearchHotContext;
405
+ }): {
395
406
  isOpen: boolean;
396
407
  setIsOpen: React$2.Dispatch<React$2.SetStateAction<boolean>>;
397
408
  query: string;
@@ -403,12 +414,17 @@ declare function useSearch(routes: ComponentRoute[]): {
403
414
  bio: string;
404
415
  groupTitle: string | undefined;
405
416
  }[];
417
+ status: SearchStatus;
418
+ isLoading: boolean;
419
+ isIndexing: boolean;
420
+ error: Error | null;
406
421
  searchDataLoading: boolean;
407
422
  searchDataError: Error | null;
423
+ searchError: Error | null;
408
424
  handleSelect: (key: React.Key) => void;
409
425
  input: {
410
426
  value: string;
411
- onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
427
+ onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
412
428
  };
413
429
  };
414
430
  //#endregion
@@ -663,8 +679,16 @@ declare function SidebarHeader({
663
679
  */
664
680
  declare function SidebarContent({
665
681
  children,
666
- className
667
- }: ComponentBase): _$react_jsx_runtime0.JSX.Element;
682
+ className,
683
+ label
684
+ }: ComponentBase & {
685
+ /**
686
+ * Accessible name for the nav landmark. Pages render multiple navs
687
+ * (navbar links, sidebar); unlabeled landmarks fail axe's
688
+ * `landmark-unique` rule.
689
+ */
690
+ label?: string;
691
+ }): _$react_jsx_runtime0.JSX.Element;
668
692
  /**
669
693
  * Navigation Group
670
694
  */
@@ -253,11 +253,15 @@ interface CreateRoutesOptions {
253
253
  collectionPosts?: Record<string, React$1.ComponentType<any>>;
254
254
  config: BoltdocsConfig;
255
255
  mdxModules: Record<string, any>;
256
- externalPages?: Record<string, React$1.ComponentType>;
256
+ externalPages?: Record<string, React$1.ComponentType | (() => Promise<{
257
+ default: React$1.ComponentType;
258
+ }>)>;
257
259
  externalLayout?: React$1.ComponentType<{
258
260
  children: React$1.ReactNode;
259
261
  }>;
260
- externalFilePages?: Record<string, React$1.ComponentType>;
262
+ externalFilePages?: Record<string, React$1.ComponentType | (() => Promise<{
263
+ default: React$1.ComponentType;
264
+ }>)>;
261
265
  externalFileMdx?: Record<string, unknown>;
262
266
  components?: Record<string, React$1.ComponentType>;
263
267
  }
@@ -391,7 +395,14 @@ declare function useSidebar(routes: ComponentRoute[]): {
391
395
  };
392
396
  //#endregion
393
397
  //#region src/client/hooks/use-search.d.ts
394
- declare function useSearch(routes: ComponentRoute[]): {
398
+ type SearchStatus = 'idle' | 'loading' | 'indexing' | 'ready' | 'searching' | 'error';
399
+ interface SearchHotContext {
400
+ on: (event: string, callback: (payload?: unknown) => void) => void;
401
+ off?: (event: string, callback: (payload?: unknown) => void) => void;
402
+ }
403
+ declare function useSearch(routes: ComponentRoute[], options?: {
404
+ hot?: SearchHotContext;
405
+ }): {
395
406
  isOpen: boolean;
396
407
  setIsOpen: React$2.Dispatch<React$2.SetStateAction<boolean>>;
397
408
  query: string;
@@ -403,12 +414,17 @@ declare function useSearch(routes: ComponentRoute[]): {
403
414
  bio: string;
404
415
  groupTitle: string | undefined;
405
416
  }[];
417
+ status: SearchStatus;
418
+ isLoading: boolean;
419
+ isIndexing: boolean;
420
+ error: Error | null;
406
421
  searchDataLoading: boolean;
407
422
  searchDataError: Error | null;
423
+ searchError: Error | null;
408
424
  handleSelect: (key: React.Key) => void;
409
425
  input: {
410
426
  value: string;
411
- onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
427
+ onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
412
428
  };
413
429
  };
414
430
  //#endregion
@@ -663,8 +679,16 @@ declare function SidebarHeader({
663
679
  */
664
680
  declare function SidebarContent({
665
681
  children,
666
- className
667
- }: ComponentBase): _$react_jsx_runtime0.JSX.Element;
682
+ className,
683
+ label
684
+ }: ComponentBase & {
685
+ /**
686
+ * Accessible name for the nav landmark. Pages render multiple navs
687
+ * (navbar links, sidebar); unlabeled landmarks fail axe's
688
+ * `landmark-unique` rule.
689
+ */
690
+ label?: string;
691
+ }): _$react_jsx_runtime0.JSX.Element;
668
692
  /**
669
693
  * Navigation Group
670
694
  */