diff --git a/components/SideBar.jsx b/components/SideBar.jsx
new file mode 100644
index 00000000..ad858ac4
--- /dev/null
+++ b/components/SideBar.jsx
@@ -0,0 +1,22 @@
+import SideBar from '@node-core/ui-components/Containers/Sidebar';
+import { sidebar } from '#theme/site' with { type: 'json' };
+
+/** @param {string} url */
+const redirect = url => (window.location.href = url);
+
+const PrefetchLink = props => ;
+
+const pathnameFor = path => path.replace(/\/index$/, '') || '/';
+
+/**
+ * Sidebar component for MDX documentation with page navigation.
+ */
+export default ({ metadata }) => (
+
+);
diff --git a/doc-kit.config.mjs b/doc-kit.config.mjs
index ba276858..de1e52d1 100644
--- a/doc-kit.config.mjs
+++ b/doc-kit.config.mjs
@@ -1,3 +1,11 @@
+import { dirname, join } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { major } from 'semver';
+import webpack from './webpack/package.json' with { type: 'json' };
+
+const ROOT = dirname(fileURLToPath(import.meta.url));
+const DOCS_DIR = `pages/v${major(webpack.version)}.x`;
+
/**
* Configuration for @node-core/doc-kit when generating webpack API docs.
*
@@ -9,7 +17,7 @@ export default {
repository: 'webpack/webpack',
// Input & Output
- input: ['./pages/v5.x/**/*.md', './pages/v5.x/*.md'],
+ input: [`./${DOCS_DIR}/**/*.md`],
output: 'out',
// Base URL,
@@ -17,11 +25,21 @@ export default {
? `https://${process.env.VERCEL_URL}`
: 'http://localhost:3000',
},
+ threads: 1,
metadata: {
- typeMap: './pages/v5.x/type-map.json',
+ typeMap: `./${DOCS_DIR}/type-map.json`,
+ },
+ 'jsx-ast': {
+ generateIndexPage: false,
+ generateAllPage: false,
},
web: {
project: 'webpack',
useAbsoluteURLs: true,
+ remoteConfigUrl: null,
+ imports: {
+ '#theme/Sidebar': join(ROOT, 'components/SideBar.jsx'),
+ '#theme/site': join(ROOT, DOCS_DIR, 'site.json'),
+ },
},
};
diff --git a/package-lock.json b/package-lock.json
index 73b17a06..3e6cc8ef 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4,7 +4,6 @@
"requires": true,
"packages": {
"": {
- "name": "webpack-doc-kit",
"dependencies": {
"@node-core/doc-kit": "^1.3.6",
"semver": "^7.8.1",
@@ -22,9 +21,9 @@
}
},
"node_modules/@actions/core": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@actions/core/-/core-3.0.0.tgz",
- "integrity": "sha512-zYt6cz+ivnTmiT/ksRVriMBOiuoUpDCJJlZ5KPl2/FRdvwU3f7MPh9qftvbkXJThragzUZieit2nyHUyw53Seg==",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@actions/core/-/core-3.0.1.tgz",
+ "integrity": "sha512-a6d/Nwahm9fliVGRhdhofo40HjHQasUPusmc7vBfyky+7Z+P2A1J68zyFVaNcEclc/Se+eO595oAr5nwEIoIUA==",
"license": "MIT",
"dependencies": {
"@actions/exec": "^3.0.0",
@@ -41,9 +40,9 @@
}
},
"node_modules/@actions/http-client": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-4.0.0.tgz",
- "integrity": "sha512-QuwPsgVMsD6qaPD57GLZi9sqzAZCtiJT8kVBCDpLtxhL5MydQ4gS+DrejtZZPdIYyB1e95uCK9Luyds7ybHI3g==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-4.0.1.tgz",
+ "integrity": "sha512-+Nvd1ImaOZBSoPbsUtEhv+1z99H12xzncCkz0a3RuehINE81FZSe2QTj3uvAPTcJX/SCzUQHQ0D1GrPMbrPitg==",
"license": "MIT",
"dependencies": {
"tunnel": "^0.0.6",
@@ -69,20 +68,20 @@
}
},
"node_modules/@emnapi/core": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz",
- "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==",
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
+ "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
"license": "MIT",
"optional": true,
"dependencies": {
- "@emnapi/wasi-threads": "1.2.0",
+ "@emnapi/wasi-threads": "1.2.1",
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/runtime": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz",
- "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==",
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
+ "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
"license": "MIT",
"optional": true,
"dependencies": {
@@ -90,9 +89,9 @@
}
},
"node_modules/@emnapi/wasi-threads": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz",
- "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
+ "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
"license": "MIT",
"optional": true,
"dependencies": {
@@ -306,29 +305,43 @@
}
},
"node_modules/@humanfs/core": {
- "version": "0.19.1",
- "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
- "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+ "version": "0.19.2",
+ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
+ "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==",
"dev": true,
"license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/types": "^0.15.0"
+ },
"engines": {
"node": ">=18.18.0"
}
},
"node_modules/@humanfs/node": {
- "version": "0.16.7",
- "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
- "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
+ "version": "0.16.8",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz",
+ "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@humanfs/core": "^0.19.1",
+ "@humanfs/core": "^0.19.2",
+ "@humanfs/types": "^0.15.0",
"@humanwhocodes/retry": "^0.4.0"
},
"engines": {
"node": ">=18.18.0"
}
},
+ "node_modules/@humanfs/types": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz",
+ "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
"node_modules/@humanwhocodes/module-importer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
@@ -724,19 +737,21 @@
}
},
"node_modules/@napi-rs/wasm-runtime": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz",
- "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==",
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
+ "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
"license": "MIT",
"optional": true,
"dependencies": {
- "@emnapi/core": "^1.7.1",
- "@emnapi/runtime": "^1.7.1",
"@tybys/wasm-util": "^0.10.1"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
+ },
+ "peerDependencies": {
+ "@emnapi/core": "^1.7.1",
+ "@emnapi/runtime": "^1.7.1"
}
},
"node_modules/@noble/hashes": {
@@ -744,6 +759,7 @@
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
"integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": "^14.21.3 || >=16"
},
@@ -901,13 +917,26 @@
"@types/hast": "^3.0.4"
}
},
+ "node_modules/@node-core/rehype-shiki/node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
"node_modules/@node-core/ui-components": {
- "version": "1.6.3",
- "resolved": "https://registry.npmjs.org/@node-core/ui-components/-/ui-components-1.6.3.tgz",
- "integrity": "sha512-Oy/bI4mZC6V/i8CdIX8q62r81zR6bAEARZE0jwTpv7w49SNomB2WAVb5fnFBSumyigOCgQKgR/OJtwh8XQJnkw==",
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/@node-core/ui-components/-/ui-components-1.7.0.tgz",
+ "integrity": "sha512-vZY+P4oEuA8w1sTh6hbMxf4OcujOnb+VZ8U33mcEYHB3fAtluh/qU9IeNEVk2ajWz0PrjI42uqrifyh3ysR7mw==",
"dependencies": {
"@heroicons/react": "^2.2.0",
- "@orama/core": "^1.2.19",
+ "@orama/orama": "^3.1.18",
"@orama/ui": "^1.5.4",
"@radix-ui/react-avatar": "^1.1.11",
"@radix-ui/react-dialog": "^1.1.15",
@@ -917,7 +946,7 @@
"@radix-ui/react-separator": "^1.1.8",
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-tooltip": "^1.2.8",
- "@tailwindcss/postcss": "~4.2.1",
+ "@tailwindcss/postcss": "~4.2.2",
"@types/react": "^19.2.13",
"@vcarl/remark-headings": "~0.1.0",
"classnames": "~2.5.1",
@@ -931,11 +960,25 @@
"node": ">=20"
}
},
+ "node_modules/@node-core/ui-components/node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
"node_modules/@orama/core": {
"version": "1.2.19",
"resolved": "https://registry.npmjs.org/@orama/core/-/core-1.2.19.tgz",
"integrity": "sha512-AVEI0eG/a1RUQK+tBloRMppQf46Ky4kIYKEVjo0V0VfIGZHdLOE2PJR4v949kFwiTnfSJCUaxgwM74FCA1uHUA==",
"license": "AGPL-3.0",
+ "peer": true,
"dependencies": {
"@orama/cuid2": "2.2.3",
"@orama/oramacore-events-parser": "0.0.5"
@@ -946,6 +989,7 @@
"resolved": "https://registry.npmjs.org/@orama/cuid2/-/cuid2-2.2.3.tgz",
"integrity": "sha512-Lcak3chblMejdlSHgYU2lS2cdOhDpU6vkfIJH4m+YKvqQyLqs1bB8+w6NT1MG5bO12NUK2GFc34Mn2xshMIQ1g==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@noble/hashes": "^1.1.5"
}
@@ -963,7 +1007,8 @@
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/@orama/oramacore-events-parser/-/oramacore-events-parser-0.0.5.tgz",
"integrity": "sha512-yAuSwog+HQBAXgZ60TNKEwu04y81/09mpbYBCmz1RCxnr4ObNY2JnPZI7HmALbjAhLJ8t5p+wc2JHRK93ubO4w==",
- "license": "AGPL-3.0"
+ "license": "AGPL-3.0",
+ "peer": true
},
"node_modules/@orama/stopwords": {
"version": "3.1.18",
@@ -2560,6 +2605,18 @@
"hast-util-to-html": "^9.0.5"
}
},
+ "node_modules/@shikijs/engine-javascript": {
+ "version": "3.23.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.23.0.tgz",
+ "integrity": "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==",
+ "extraneous": true,
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "3.23.0",
+ "@shikijs/vscode-textmate": "^10.0.2",
+ "oniguruma-to-es": "^4.3.4"
+ }
+ },
"node_modules/@shikijs/engine-oniguruma": {
"version": "3.23.0",
"resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz",
@@ -2571,21 +2628,21 @@
}
},
"node_modules/@shikijs/langs": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.0.2.tgz",
- "integrity": "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.1.0.tgz",
+ "integrity": "sha512-nwOMruEkbgdZfQ/b8CgpNBVOpvG1k0N5tbmgiFeqsan401+x3ILqlzZJowSla4Agmq4hG2Uf2wh5jLTEhR8VSg==",
"license": "MIT",
"dependencies": {
- "@shikijs/types": "4.0.2"
+ "@shikijs/types": "4.1.0"
},
"engines": {
"node": ">=20"
}
},
"node_modules/@shikijs/langs/node_modules/@shikijs/types": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz",
- "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.1.0.tgz",
+ "integrity": "sha512-3EQWX54fMpniOrDblzAhiwiJwpiTMW6+B9DWyUd9ska483tbayFYuw47UxwuPknI31bKnySfVQ/QW+jFL4rFdA==",
"license": "MIT",
"dependencies": {
"@shikijs/vscode-textmate": "^10.0.2",
@@ -2596,12 +2653,12 @@
}
},
"node_modules/@shikijs/primitive": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.0.2.tgz",
- "integrity": "sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.1.0.tgz",
+ "integrity": "sha512-zx2/2Uwj2q9X3KSyYREEhXO23xBw5WUhP4orK2lE4r+t9JGITmEe0JH+wPmJhqHpOT2bRRs6lAL945+LDvOAGw==",
"license": "MIT",
"dependencies": {
- "@shikijs/types": "4.0.2",
+ "@shikijs/types": "4.1.0",
"@shikijs/vscode-textmate": "^10.0.2",
"@types/hast": "^3.0.4"
},
@@ -2610,9 +2667,9 @@
}
},
"node_modules/@shikijs/primitive/node_modules/@shikijs/types": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz",
- "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.1.0.tgz",
+ "integrity": "sha512-3EQWX54fMpniOrDblzAhiwiJwpiTMW6+B9DWyUd9ska483tbayFYuw47UxwuPknI31bKnySfVQ/QW+jFL4rFdA==",
"license": "MIT",
"dependencies": {
"@shikijs/vscode-textmate": "^10.0.2",
@@ -2623,21 +2680,21 @@
}
},
"node_modules/@shikijs/themes": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.0.2.tgz",
- "integrity": "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.1.0.tgz",
+ "integrity": "sha512-emCcTnUM7yO2wltYbaxm+yLvcCI4+h8XBKc4KmJ7EZUXoSGjcCHifkI//R4OFit9ewpg7H2/9tjOuXrT2v/Knw==",
"license": "MIT",
"dependencies": {
- "@shikijs/types": "4.0.2"
+ "@shikijs/types": "4.1.0"
},
"engines": {
"node": ">=20"
}
},
"node_modules/@shikijs/themes/node_modules/@shikijs/types": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz",
- "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.1.0.tgz",
+ "integrity": "sha512-3EQWX54fMpniOrDblzAhiwiJwpiTMW6+B9DWyUd9ska483tbayFYuw47UxwuPknI31bKnySfVQ/QW+jFL4rFdA==",
"license": "MIT",
"dependencies": {
"@shikijs/vscode-textmate": "^10.0.2",
@@ -2678,15 +2735,15 @@
"license": "MIT"
},
"node_modules/@swc/html-wasm": {
- "version": "1.15.21",
- "resolved": "https://registry.npmjs.org/@swc/html-wasm/-/html-wasm-1.15.21.tgz",
- "integrity": "sha512-2Wo2S5DbfAswldF/X5gSmqgTy4uMBEUix7zYcIFsXgZyVJ8PDPE19cgxSBkauJxxGXfvo5rVCcEjx0XrJHpDEA==",
+ "version": "1.15.40",
+ "resolved": "https://registry.npmjs.org/@swc/html-wasm/-/html-wasm-1.15.40.tgz",
+ "integrity": "sha512-WbRp7vSPK9bAGwpP1U8+RDE/xw1yj6P8ZYVqzA/64nlnFuB4MrW92EdkHiKvTPdlFDUZUno8yJKRKcRkE/UK6Q==",
"license": "Apache-2.0"
},
"node_modules/@tailwindcss/node": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.2.tgz",
- "integrity": "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.4.tgz",
+ "integrity": "sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==",
"license": "MIT",
"dependencies": {
"@jridgewell/remapping": "^2.3.5",
@@ -2695,42 +2752,42 @@
"lightningcss": "1.32.0",
"magic-string": "^0.30.21",
"source-map-js": "^1.2.1",
- "tailwindcss": "4.2.2"
+ "tailwindcss": "4.2.4"
}
},
"node_modules/@tailwindcss/node/node_modules/tailwindcss": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz",
- "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.4.tgz",
+ "integrity": "sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA==",
"license": "MIT"
},
"node_modules/@tailwindcss/oxide": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.2.tgz",
- "integrity": "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.4.tgz",
+ "integrity": "sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q==",
"license": "MIT",
"engines": {
"node": ">= 20"
},
"optionalDependencies": {
- "@tailwindcss/oxide-android-arm64": "4.2.2",
- "@tailwindcss/oxide-darwin-arm64": "4.2.2",
- "@tailwindcss/oxide-darwin-x64": "4.2.2",
- "@tailwindcss/oxide-freebsd-x64": "4.2.2",
- "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2",
- "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2",
- "@tailwindcss/oxide-linux-arm64-musl": "4.2.2",
- "@tailwindcss/oxide-linux-x64-gnu": "4.2.2",
- "@tailwindcss/oxide-linux-x64-musl": "4.2.2",
- "@tailwindcss/oxide-wasm32-wasi": "4.2.2",
- "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2",
- "@tailwindcss/oxide-win32-x64-msvc": "4.2.2"
+ "@tailwindcss/oxide-android-arm64": "4.2.4",
+ "@tailwindcss/oxide-darwin-arm64": "4.2.4",
+ "@tailwindcss/oxide-darwin-x64": "4.2.4",
+ "@tailwindcss/oxide-freebsd-x64": "4.2.4",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.4",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.2.4",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.2.4",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.2.4",
+ "@tailwindcss/oxide-linux-x64-musl": "4.2.4",
+ "@tailwindcss/oxide-wasm32-wasi": "4.2.4",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.2.4",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.2.4"
}
},
"node_modules/@tailwindcss/oxide-android-arm64": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.2.tgz",
- "integrity": "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.4.tgz",
+ "integrity": "sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==",
"cpu": [
"arm64"
],
@@ -2744,9 +2801,9 @@
}
},
"node_modules/@tailwindcss/oxide-darwin-arm64": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.2.tgz",
- "integrity": "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.4.tgz",
+ "integrity": "sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg==",
"cpu": [
"arm64"
],
@@ -2760,9 +2817,9 @@
}
},
"node_modules/@tailwindcss/oxide-darwin-x64": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.2.tgz",
- "integrity": "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.4.tgz",
+ "integrity": "sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg==",
"cpu": [
"x64"
],
@@ -2776,9 +2833,9 @@
}
},
"node_modules/@tailwindcss/oxide-freebsd-x64": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.2.tgz",
- "integrity": "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.4.tgz",
+ "integrity": "sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw==",
"cpu": [
"x64"
],
@@ -2792,9 +2849,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.2.tgz",
- "integrity": "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.4.tgz",
+ "integrity": "sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA==",
"cpu": [
"arm"
],
@@ -2808,9 +2865,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.2.tgz",
- "integrity": "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.4.tgz",
+ "integrity": "sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw==",
"cpu": [
"arm64"
],
@@ -2824,9 +2881,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.2.tgz",
- "integrity": "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.4.tgz",
+ "integrity": "sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g==",
"cpu": [
"arm64"
],
@@ -2840,9 +2897,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.2.tgz",
- "integrity": "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.4.tgz",
+ "integrity": "sha512-7Mx25E4WTfnht0TVRTyC00j3i0M+EeFe7wguMDTlX4mRxafznw0CA8WJkFjWYH5BlgELd1kSjuU2JiPnNZbJDA==",
"cpu": [
"x64"
],
@@ -2856,9 +2913,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.2.tgz",
- "integrity": "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.4.tgz",
+ "integrity": "sha512-2wwJRF7nyhOR0hhHoChc04xngV3iS+akccHTGtz965FwF0up4b2lOdo6kI1EbDaEXKgvcrFBYcYQQ/rrnWFVfA==",
"cpu": [
"x64"
],
@@ -2872,9 +2929,9 @@
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.2.tgz",
- "integrity": "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.4.tgz",
+ "integrity": "sha512-FQsqApeor8Fo6gUEklzmaa9994orJZZDBAlQpK2Mq+DslRKFJeD6AjHpBQ0kZFQohVr8o85PPh8eOy86VlSCmw==",
"bundleDependencies": [
"@napi-rs/wasm-runtime",
"@emnapi/core",
@@ -2901,9 +2958,9 @@
}
},
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.2.tgz",
- "integrity": "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.4.tgz",
+ "integrity": "sha512-L9BXqxC4ToVgwMFqj3pmZRqyHEztulpUJzCxUtLjobMCzTPsGt1Fa9enKbOpY2iIyVtaHNeNvAK8ERP/64sqGQ==",
"cpu": [
"arm64"
],
@@ -2917,9 +2974,9 @@
}
},
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.2.tgz",
- "integrity": "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.4.tgz",
+ "integrity": "sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw==",
"cpu": [
"x64"
],
@@ -2933,28 +2990,28 @@
}
},
"node_modules/@tailwindcss/postcss": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.2.2.tgz",
- "integrity": "sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.2.4.tgz",
+ "integrity": "sha512-wgAVj6nUWAolAu8YFvzT2cTBIElWHkjZwFYovF+xsqKsW2ADxM/X2opxj5NsF/qVccAOjRNe8X2IdPzMsWyHTg==",
"license": "MIT",
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
- "@tailwindcss/node": "4.2.2",
- "@tailwindcss/oxide": "4.2.2",
+ "@tailwindcss/node": "4.2.4",
+ "@tailwindcss/oxide": "4.2.4",
"postcss": "^8.5.6",
- "tailwindcss": "4.2.2"
+ "tailwindcss": "4.2.4"
}
},
"node_modules/@tailwindcss/postcss/node_modules/tailwindcss": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz",
- "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.4.tgz",
+ "integrity": "sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA==",
"license": "MIT"
},
"node_modules/@tybys/wasm-util": {
- "version": "0.10.1",
- "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
- "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
+ "version": "0.10.2",
+ "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
+ "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
"license": "MIT",
"optional": true,
"dependencies": {
@@ -2978,9 +3035,9 @@
"license": "MIT"
},
"node_modules/@types/estree": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
- "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
"license": "MIT"
},
"node_modules/@types/estree-jsx": {
@@ -3032,9 +3089,9 @@
}
},
"node_modules/@types/react": {
- "version": "19.2.14",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
- "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
+ "version": "19.2.15",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz",
+ "integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==",
"license": "MIT",
"dependencies": {
"csstype": "^3.2.2"
@@ -3059,9 +3116,9 @@
}
},
"node_modules/@ungap/structured-clone": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
- "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz",
+ "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==",
"license": "ISC"
},
"node_modules/@vcarl/remark-headings": {
@@ -3314,9 +3371,9 @@
}
},
"node_modules/ajv": {
- "version": "6.14.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
- "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
+ "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3483,9 +3540,9 @@
}
},
"node_modules/baseline-browser-mapping": {
- "version": "2.10.10",
- "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.10.tgz",
- "integrity": "sha512-sUoJ3IMxx4AyRqO4MLeHlnGDkyXRoUG0/AI9fjK+vS72ekpV0yWVY7O0BVjmBcRtkNcsAO2QDZ4tdKKGoI6YaQ==",
+ "version": "2.10.32",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.32.tgz",
+ "integrity": "sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==",
"license": "Apache-2.0",
"bin": {
"baseline-browser-mapping": "dist/cli.cjs"
@@ -3537,9 +3594,9 @@
}
},
"node_modules/browserslist": {
- "version": "4.28.1",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
- "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
+ "version": "4.28.2",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
+ "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
"funding": [
{
"type": "opencollective",
@@ -3556,11 +3613,11 @@
],
"license": "MIT",
"dependencies": {
- "baseline-browser-mapping": "^2.9.0",
- "caniuse-lite": "^1.0.30001759",
- "electron-to-chromium": "^1.5.263",
- "node-releases": "^2.0.27",
- "update-browserslist-db": "^1.2.0"
+ "baseline-browser-mapping": "^2.10.12",
+ "caniuse-lite": "^1.0.30001782",
+ "electron-to-chromium": "^1.5.328",
+ "node-releases": "^2.0.36",
+ "update-browserslist-db": "^1.2.3"
},
"bin": {
"browserslist": "cli.js"
@@ -3576,9 +3633,9 @@
"license": "MIT"
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001781",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001781.tgz",
- "integrity": "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==",
+ "version": "1.0.30001793",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz",
+ "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==",
"funding": [
{
"type": "opencollective",
@@ -4003,9 +4060,9 @@
}
},
"node_modules/electron-to-chromium": {
- "version": "1.5.321",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.321.tgz",
- "integrity": "sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==",
+ "version": "1.5.361",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.361.tgz",
+ "integrity": "sha512-Q6Hts7N9FnJc5LeGRINFvLhCI9xZmNtTDe5ZbcVezQz7cU4a8Aua3GH1b8J2XY8Al9PF+OCwYqhgsOOheMdvkA==",
"license": "ISC"
},
"node_modules/emoji-regex": {
@@ -4453,9 +4510,9 @@
"license": "ISC"
},
"node_modules/fs-extra": {
- "version": "11.3.4",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz",
- "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==",
+ "version": "11.3.5",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz",
+ "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==",
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.0",
@@ -4959,9 +5016,9 @@
}
},
"node_modules/jiti": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
- "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
+ "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
"license": "MIT",
"bin": {
"jiti": "lib/jiti-cli.mjs"
@@ -4989,9 +5046,9 @@
"license": "MIT"
},
"node_modules/jsonfile": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz",
- "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==",
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz",
+ "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==",
"license": "MIT",
"dependencies": {
"universalify": "^2.0.0"
@@ -5310,9 +5367,19 @@
}
},
"node_modules/linkify-it": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
- "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz",
+ "integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/puzrin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/markdown-it"
+ }
+ ],
"license": "MIT",
"dependencies": {
"uc.micro": "^2.0.0"
@@ -5495,14 +5562,24 @@
}
},
"node_modules/markdown-it": {
- "version": "14.1.1",
- "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz",
- "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==",
+ "version": "14.2.0",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz",
+ "integrity": "sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/puzrin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/markdown-it"
+ }
+ ],
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1",
"entities": "^4.4.0",
- "linkify-it": "^5.0.0",
+ "linkify-it": "^5.0.1",
"mdurl": "^2.0.0",
"punycode.js": "^2.3.1",
"uc.micro": "^2.1.0"
@@ -6512,10 +6589,13 @@
"license": "MIT"
},
"node_modules/node-releases": {
- "version": "2.0.36",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz",
- "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==",
- "license": "MIT"
+ "version": "2.0.46",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz",
+ "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
},
"node_modules/normalize-path": {
"version": "3.0.0",
@@ -6555,18 +6635,18 @@
}
},
"node_modules/oniguruma-parser": {
- "version": "0.12.1",
- "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz",
- "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==",
+ "version": "0.12.2",
+ "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz",
+ "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==",
"license": "MIT"
},
"node_modules/oniguruma-to-es": {
- "version": "4.3.5",
- "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.5.tgz",
- "integrity": "sha512-Zjygswjpsewa0NLTsiizVuMQZbp0MDyM6lIt66OxsF21npUDlzpHi1Mgb/qhQdkb+dWFTzJmFbEWdvZgRho8eQ==",
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz",
+ "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==",
"license": "MIT",
"dependencies": {
- "oniguruma-parser": "^0.12.1",
+ "oniguruma-parser": "^0.12.2",
"regex": "^6.1.0",
"regex-recursion": "^6.0.2"
}
@@ -6966,25 +7046,25 @@
}
},
"node_modules/react": {
- "version": "19.2.4",
- "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
- "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
+ "version": "19.2.6",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz",
+ "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-dom": {
- "version": "19.2.4",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
- "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
+ "version": "19.2.6",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz",
+ "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
"peerDependencies": {
- "react": "^19.2.4"
+ "react": "^19.2.6"
}
},
"node_modules/react-markdown": {
@@ -7480,17 +7560,17 @@
}
},
"node_modules/shiki": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.0.2.tgz",
- "integrity": "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.1.0.tgz",
+ "integrity": "sha512-l/ABZPUR5v70jI10EzqfMS/I96vjSGv2y0ihUV+WYFzv0EfvW4s54m0Lg8wCrrL+2IkwBzFTuxkZjPf8b2NX9Q==",
"license": "MIT",
"dependencies": {
- "@shikijs/core": "4.0.2",
- "@shikijs/engine-javascript": "4.0.2",
- "@shikijs/engine-oniguruma": "4.0.2",
- "@shikijs/langs": "4.0.2",
- "@shikijs/themes": "4.0.2",
- "@shikijs/types": "4.0.2",
+ "@shikijs/core": "4.1.0",
+ "@shikijs/engine-javascript": "4.1.0",
+ "@shikijs/engine-oniguruma": "4.1.0",
+ "@shikijs/langs": "4.1.0",
+ "@shikijs/themes": "4.1.0",
+ "@shikijs/types": "4.1.0",
"@shikijs/vscode-textmate": "^10.0.2",
"@types/hast": "^3.0.4"
},
@@ -7499,13 +7579,13 @@
}
},
"node_modules/shiki/node_modules/@shikijs/core": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.0.2.tgz",
- "integrity": "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.1.0.tgz",
+ "integrity": "sha512-jLJtSJeuFffqX6/inRE1zqU5aFv2hrszvYgq3OjbAgFRZiWv7abKMDdQzYxuSDfmUPQozZvI/kuy6VMTvnvqTQ==",
"license": "MIT",
"dependencies": {
- "@shikijs/primitive": "4.0.2",
- "@shikijs/types": "4.0.2",
+ "@shikijs/primitive": "4.1.0",
+ "@shikijs/types": "4.1.0",
"@shikijs/vscode-textmate": "^10.0.2",
"@types/hast": "^3.0.4",
"hast-util-to-html": "^9.0.5"
@@ -7515,26 +7595,26 @@
}
},
"node_modules/shiki/node_modules/@shikijs/engine-javascript": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.0.2.tgz",
- "integrity": "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.1.0.tgz",
+ "integrity": "sha512-YquhawCUgaBfhsS72e2Y/dI59gCBNPHu3fEO/tvLaXrTssxZrY5ddjtNLTwndrMgPo8b3IscE+xoICDzpTmlFQ==",
"license": "MIT",
"dependencies": {
- "@shikijs/types": "4.0.2",
+ "@shikijs/types": "4.1.0",
"@shikijs/vscode-textmate": "^10.0.2",
- "oniguruma-to-es": "^4.3.4"
+ "oniguruma-to-es": "^4.3.6"
},
"engines": {
"node": ">=20"
}
},
"node_modules/shiki/node_modules/@shikijs/engine-oniguruma": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.0.2.tgz",
- "integrity": "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.1.0.tgz",
+ "integrity": "sha512-axLpjVs45YBvvINa+dJF+NPW+KtFkNXsFr4SDw2BMj9GdeMnGxVB9PQb2xXlJYovslt/nz6giedAyOANkfc7hg==",
"license": "MIT",
"dependencies": {
- "@shikijs/types": "4.0.2",
+ "@shikijs/types": "4.1.0",
"@shikijs/vscode-textmate": "^10.0.2"
},
"engines": {
@@ -7542,9 +7622,9 @@
}
},
"node_modules/shiki/node_modules/@shikijs/types": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz",
- "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.1.0.tgz",
+ "integrity": "sha512-3EQWX54fMpniOrDblzAhiwiJwpiTMW6+B9DWyUd9ska483tbayFYuw47UxwuPknI31bKnySfVQ/QW+jFL4rFdA==",
"license": "MIT",
"dependencies": {
"@shikijs/vscode-textmate": "^10.0.2",
@@ -7837,9 +7917,9 @@
"license": "MIT"
},
"node_modules/thenby": {
- "version": "1.3.4",
- "resolved": "https://registry.npmjs.org/thenby/-/thenby-1.3.4.tgz",
- "integrity": "sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==",
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/thenby/-/thenby-1.4.1.tgz",
+ "integrity": "sha512-D5a/bO0KdalOE3q8MlrRmSxjbKZHT3MQmXkJP+r97Vw8MMwOZKOwUSEyTtK7eSMj2y0kyAjpYMRMZmmLw1FtNQ==",
"license": "Apache-2.0"
},
"node_modules/throttleit": {
@@ -7865,13 +7945,13 @@
}
},
"node_modules/tinyglobby": {
- "version": "0.2.15",
- "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
- "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+ "version": "0.2.16",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
+ "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
- "picomatch": "^4.0.3"
+ "picomatch": "^4.0.4"
},
"engines": {
"node": ">=12.0.0"
@@ -7928,22 +8008,22 @@
}
},
"node_modules/twoslash": {
- "version": "0.3.6",
- "resolved": "https://registry.npmjs.org/twoslash/-/twoslash-0.3.6.tgz",
- "integrity": "sha512-VuI5OKl+MaUO9UIW3rXKoPgHI3X40ZgB/j12VY6h98Ae1mCBihjPvhOPeJWlxCYcmSbmeZt5ZKkK0dsVtp+6pA==",
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/twoslash/-/twoslash-0.3.8.tgz",
+ "integrity": "sha512-OeDz0kDl8sqPUN3nr7gqcvOs70f5lZsdhKYTX3/SgB9OvdadzzoYJI/4SBXhXV1HG8E9fLc+e17itoRYTxmoig==",
"license": "MIT",
"dependencies": {
- "@typescript/vfs": "^1.6.2",
- "twoslash-protocol": "0.3.6"
+ "@typescript/vfs": "^1.6.4",
+ "twoslash-protocol": "0.3.8"
},
"peerDependencies": {
- "typescript": "^5.5.0"
+ "typescript": "^5.5.0 || ^6.0.0"
}
},
"node_modules/twoslash-protocol": {
- "version": "0.3.6",
- "resolved": "https://registry.npmjs.org/twoslash-protocol/-/twoslash-protocol-0.3.6.tgz",
- "integrity": "sha512-FHGsJ9Q+EsNr5bEbgG3hnbkvEBdW5STgPU824AHUjB4kw0Dn4p8tABT7Ncg1Ie6V0+mDg3Qpy41VafZXcQhWMA==",
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/twoslash-protocol/-/twoslash-protocol-0.3.8.tgz",
+ "integrity": "sha512-HmvAHoiEviK8LqvAQyc9/irkdvwTUiR1fHmNwH/0gq8EHxyBt4PWVPixjEXg6wJu1u6yBrILEWXGK9Kw58/8yQ==",
"license": "MIT"
},
"node_modules/type-check": {
@@ -7995,10 +8075,11 @@
}
},
"node_modules/typescript": {
- "version": "5.9.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
- "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
+ "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
"license": "Apache-2.0",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -8014,9 +8095,9 @@
"license": "MIT"
},
"node_modules/undici": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz",
- "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==",
+ "version": "6.25.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-6.25.0.tgz",
+ "integrity": "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==",
"license": "MIT",
"engines": {
"node": ">=18.17"
diff --git a/plugins/processor.mjs b/plugins/processor.mjs
deleted file mode 100644
index 0ea5f5c2..00000000
--- a/plugins/processor.mjs
+++ /dev/null
@@ -1,53 +0,0 @@
-import { Converter, ReflectionKind, Renderer } from 'typedoc';
-import { writeFileSync } from 'node:fs';
-import { join } from 'node:path';
-
-/**
- * @param {import('typedoc-plugin-markdown').MarkdownApplication} app
- */
-export function load(app) {
- app.converter.on(Converter.EVENT_RESOLVE_BEGIN, context => {
- // Convert accessors to properties
- context.project
- .getReflectionsByKind(ReflectionKind.Accessor)
- .forEach(accessor => {
- accessor.kind = ReflectionKind.Property;
- if (accessor.getSignature) {
- accessor.type = accessor.getSignature.type;
- accessor.comment = accessor.getSignature.comment;
- } else if (accessor.setSignature) {
- accessor.type = accessor.setSignature.parameters?.[0]?.type;
- accessor.comment = accessor.setSignature.comment;
- }
- });
-
- // Remove re-exports
- context.project
- .getReflectionsByKind(ReflectionKind.Reference)
- .forEach(ref => context.project.removeReflection(ref));
-
- // Merge `export=` namespaces into their parent
- context.project
- .getReflectionsByKind(ReflectionKind.Namespace)
- .filter(ref => ref.name === 'export=')
- .forEach(namespace =>
- context.project.mergeReflections(namespace, namespace.parent)
- );
- });
-
- app.renderer.on(Renderer.EVENT_END, () => {
- const typeMap = Object.fromEntries(
- app.renderer.router
- .getLinkTargets()
- .map(target => [
- target.getFullName(),
- app.renderer.router.getAnchoredURL(target),
- ])
- );
-
- writeFileSync(
- join(app.options.getValue('out'), 'type-map.json'),
- JSON.stringify(typeMap, null, 2)
- );
- });
-}
diff --git a/plugins/processor/exportEquals.mjs b/plugins/processor/exportEquals.mjs
new file mode 100644
index 00000000..bf19537e
--- /dev/null
+++ b/plugins/processor/exportEquals.mjs
@@ -0,0 +1,46 @@
+import { ReflectionKind } from 'typedoc';
+import { setPublicName } from './metadata.mjs';
+
+const EXPORT_EQUALS_NAME = 'export=';
+
+/**
+ * @param {import('typedoc').ProjectReflection} project
+ * @param {import('typedoc').Reflection} reflection
+ * @returns {string | undefined}
+ */
+const exportEqualsPublicName = (project, reflection) => {
+ const rawParts = String(reflection.getFullName?.() ?? reflection.name).split(
+ '.'
+ );
+
+ if (!rawParts.includes(EXPORT_EQUALS_NAME)) {
+ return;
+ }
+
+ const parts = rawParts.filter(part => part && part !== EXPORT_EQUALS_NAME);
+ return parts[0] === project.name
+ ? parts.join('.')
+ : [project.name, ...parts].filter(Boolean).join('.');
+};
+
+/**
+ * TypeDoc exposes CommonJS `export = webpack` containers and callables as
+ * `export=`. Normalize every such reflection while the processor still owns
+ * the reflection graph: containers are merged into their parent and remaining
+ * declarations get public webpack names.
+ *
+ * @param {import('typedoc').ProjectReflection} project
+ */
+export const applyExportEqualsReflections = project => {
+ project
+ .getReflectionsByKind(ReflectionKind.SomeModule)
+ .filter(ref => ref.name === EXPORT_EQUALS_NAME && ref.parent)
+ .forEach(namespace =>
+ project.mergeReflections(namespace, namespace.parent)
+ );
+
+ for (const reflection of project.getReflectionsByKind(ReflectionKind.All)) {
+ const name = exportEqualsPublicName(project, reflection);
+ if (name) setPublicName(reflection, name || project.name);
+ }
+};
diff --git a/plugins/processor/index.mjs b/plugins/processor/index.mjs
new file mode 100644
index 00000000..eacf6b11
--- /dev/null
+++ b/plugins/processor/index.mjs
@@ -0,0 +1,64 @@
+import { Converter, ReflectionKind, Renderer } from 'typedoc';
+import { writeFileSync } from 'node:fs';
+import { join } from 'node:path';
+import { applyExportEqualsReflections } from './exportEquals.mjs';
+import { applySourceMetadata } from './source.mjs';
+import { DocKitRouter } from './router.mjs';
+import { sidebar } from './site.mjs';
+import { createTypeMap } from './typeMap.mjs';
+
+/**
+ * @param {import('typedoc-plugin-markdown').MarkdownApplication} app
+ */
+export function load(app) {
+ // Keep router ownership in the processor plugin because routing depends on
+ // source metadata and the synthetic type pages created during conversion.
+ app.renderer.defineRouter('doc-kit', DocKitRouter);
+
+ app.converter.on(Converter.EVENT_RESOLVE_BEGIN, context => {
+ // doc-kit has property metadata, not TypeDoc accessor metadata.
+ context.project
+ .getReflectionsByKind(ReflectionKind.Accessor)
+ .forEach(accessor => {
+ accessor.kind = ReflectionKind.Property;
+ if (accessor.getSignature) {
+ accessor.type = accessor.getSignature.type;
+ accessor.comment = accessor.getSignature.comment;
+ } else if (accessor.setSignature) {
+ accessor.type = accessor.setSignature.parameters?.[0]?.type;
+ accessor.comment = accessor.setSignature.comment;
+ }
+ });
+
+ // Reference reflections duplicate the real declaration entries and confuse
+ // both routing and the custom type map.
+ context.project
+ .getReflectionsByKind(ReflectionKind.Reference)
+ .forEach(ref => context.project.removeReflection(ref));
+
+ applyExportEqualsReflections(context.project);
+ applySourceMetadata(context.project);
+ });
+
+ app.renderer.on(Renderer.EVENT_END, () => {
+ // doc-kit resolves custom type annotations from this map while generating
+ // HTML, so use the final router URLs instead of recomputing paths here.
+ const typeMap = createTypeMap(app.renderer.router);
+
+ writeFileSync(
+ join(app.options.getValue('out'), 'type-map.json'),
+ JSON.stringify(typeMap, null, 2)
+ );
+
+ writeFileSync(
+ join(app.options.getValue('out'), 'site.json'),
+ JSON.stringify(
+ {
+ sidebar: sidebar(app.renderer.router),
+ },
+ null,
+ 2
+ )
+ );
+ });
+}
diff --git a/plugins/processor/metadata.mjs b/plugins/processor/metadata.mjs
new file mode 100644
index 00000000..63b4b8c2
--- /dev/null
+++ b/plugins/processor/metadata.mjs
@@ -0,0 +1,73 @@
+/**
+ * @typedef {object} SourceMetadata
+ * @property {string} sourcePath Absolute source file path.
+ * @property {string} sourceRelativePath Path relative to webpack/lib.
+ * @property {string} fileBase Source file name without extension.
+ * @property {string | undefined} anchorName Preferred page anchor for members
+ * whose public name differs from the source file name.
+ * @property {string | undefined} publicPath Public webpack export path.
+ */
+
+/**
+ * @typedef {object} TypePageMetadata
+ * @property {string} baseName Router base name for the synthetic page.
+ * @property {string} title Rendered page title.
+ */
+
+const sourceMetadata = new WeakMap();
+const typePageMetadata = new WeakMap();
+const publicNames = new WeakMap();
+
+/**
+ * Attach source-file metadata discovered from webpack/lib to a reflection.
+ *
+ * @param {import('typedoc').Reflection} reflection
+ * @param {SourceMetadata} metadata
+ */
+export const setSourceMetadata = (reflection, metadata) => {
+ sourceMetadata.set(reflection, metadata);
+};
+
+/**
+ * @param {import('typedoc').Reflection} reflection
+ * @returns {SourceMetadata | undefined}
+ */
+export const getSourceMetadata = reflection => sourceMetadata.get(reflection);
+
+/**
+ * Synthetic type pages are not TypeDoc source declarations, so their routing
+ * and title metadata lives beside other processor-owned overlays.
+ *
+ * @param {import('typedoc').Reflection} reflection
+ * @param {TypePageMetadata} metadata
+ */
+export const setTypePageMetadata = (reflection, metadata) => {
+ typePageMetadata.set(reflection, metadata);
+};
+
+/**
+ * @param {import('typedoc').Reflection} reflection
+ * @returns {string | undefined}
+ */
+export const getTypePageTitle = reflection =>
+ typePageMetadata.get(reflection)?.title;
+
+/** @param {import('typedoc').Reflection} reflection */
+export const isTypePage = reflection => typePageMetadata.has(reflection);
+
+/**
+ * Some declaration-file shapes need processor-owned public names that differ
+ * from TypeDoc's internal reflection names.
+ *
+ * @param {import('typedoc').Reflection} reflection
+ * @param {string} name
+ */
+export const setPublicName = (reflection, name) => {
+ publicNames.set(reflection, name);
+};
+
+/**
+ * @param {import('typedoc').Reflection} reflection
+ * @returns {string | undefined}
+ */
+export const getPublicName = reflection => publicNames.get(reflection);
diff --git a/plugins/processor/router.mjs b/plugins/processor/router.mjs
new file mode 100644
index 00000000..c5f6bef0
--- /dev/null
+++ b/plugins/processor/router.mjs
@@ -0,0 +1,257 @@
+import createNodeSlugger from '@node-core/doc-kit/src/generators/metadata/utils/slugger.mjs';
+import { PageKind, Reflection, ReflectionKind } from 'typedoc';
+import { MemberRouter } from 'typedoc-plugin-markdown';
+import { categoryForReflection } from '../shared/categories.mjs';
+import { getConstructorTitle, getMemberTitle } from '../shared/titles.mjs';
+import { getSourceMetadata, isTypePage } from './metadata.mjs';
+import { createTypePages, TYPE_PAGE_HEADING_KINDS } from './synthetic.mjs';
+
+/**
+ * The router owns the public Markdown shape. It keeps one class per file,
+ * namespaces on index pages, namespace functions/constants as anchored entries,
+ * root plugin classes under plugins/, and structural types on category types
+ * pages instead of the root README.
+ */
+const sluggers = new Map();
+
+const NON_HEADING_KINDS =
+ ReflectionKind.Property |
+ ReflectionKind.EnumMember |
+ ReflectionKind.SomeSignature |
+ ReflectionKind.TypeLiteral |
+ ReflectionKind.TypeParameter;
+
+const fullNameParts = reflection => reflection.getFullName().split('.');
+
+const pagePath = parts => parts.join('/');
+
+const categoryNameForReflection = reflection =>
+ categoryForReflection(reflection)?.category;
+
+const rootExportBaseName = reflection => {
+ const category = categoryNameForReflection(reflection);
+ return category ? `${category}/${reflection.name}` : reflection.name;
+};
+
+const namespaceBaseName = reflection => {
+ if (!reflection.kindOf(ReflectionKind.Namespace)) {
+ return;
+ }
+
+ const parts = fullNameParts(reflection);
+
+ if (parts.length === 1) {
+ const category = categoryNameForReflection(reflection);
+
+ if (category) {
+ return `${category}/${reflection.name}`;
+ }
+
+ // Lowercase root namespaces behave like source directories: their classes
+ // can live beside an index page, while uppercase namespace-like objects
+ // (for example RuntimeGlobals) remain a single file.
+ return /^[a-z]/.test(reflection.name)
+ ? `${reflection.name}/index`
+ : reflection.name;
+ }
+
+ return /^[a-z]/.test(reflection.name)
+ ? pagePath([...parts, 'index'])
+ : pagePath(parts);
+};
+
+const classBaseName = reflection => {
+ const parts = fullNameParts(reflection);
+
+ if (parts.length === 1) {
+ return rootExportBaseName(reflection);
+ }
+
+ return pagePath(parts);
+};
+
+export const sourcePageBaseName = reflection => {
+ if (
+ !(reflection instanceof Reflection) ||
+ !reflection.kindOf(ReflectionKind.Class | ReflectionKind.Namespace)
+ ) {
+ return;
+ }
+
+ if (reflection.kindOf(ReflectionKind.Class)) {
+ return classBaseName(reflection);
+ }
+
+ if (reflection.kindOf(ReflectionKind.Namespace)) {
+ return namespaceBaseName(reflection);
+ }
+
+ return;
+};
+
+export const hasSourcePage = reflection =>
+ Boolean(sourcePageBaseName(reflection));
+
+export const sourceAnchorName = reflection => {
+ if (
+ !(reflection instanceof Reflection) ||
+ !reflection.kindOf(ReflectionKind.Function | ReflectionKind.Variable)
+ ) {
+ return;
+ }
+
+ const anchorName = getSourceMetadata(reflection)?.anchorName;
+ if (!anchorName) {
+ return;
+ }
+
+ const baseName = sourcePageBaseName(reflection.parent);
+ if (baseName?.split('/').at(-1) === reflection.name) {
+ return;
+ }
+
+ return anchorName;
+};
+
+const rendersHeading = (target, pageTarget) => {
+ if (!target.isDeclaration() || target.kindOf(NON_HEADING_KINDS)) {
+ return false;
+ }
+
+ return isTypePage(pageTarget) ? target.kindOf(TYPE_PAGE_HEADING_KINDS) : true;
+};
+
+const anchorTitle = (target, pageTarget) =>
+ target.kindOf(ReflectionKind.Constructor)
+ ? getConstructorTitle(target)
+ : getMemberTitle(target, { local: isTypePage(pageTarget) });
+
+export class DocKitRouter extends MemberRouter {
+ /** @param {import('typedoc').ProjectReflection} project */
+ buildPages(project) {
+ const typePages = createTypePages(project);
+ const pages = super.buildPages(project);
+
+ for (const { baseName, children, model } of typePages) {
+ const url = this.getFileName(baseName);
+ this.fullUrls.set(model, url);
+ pages.push({ kind: PageKind.Reflection, model, url });
+
+ for (const child of children) {
+ this.buildAnchors(child, model, { includeChildren: false });
+ }
+ }
+
+ return pages;
+ }
+
+ /**
+ * @param {import('typedoc').DeclarationReflection} reflection
+ * @param {import('typedoc').MarkdownPageEvent[]} outPages
+ */
+ buildChildPages(reflection, outPages) {
+ const kind = this.getPageKind(reflection);
+
+ if (!kind) {
+ // Functions and constants are entries on their parent page, never files.
+ this.buildAnchors(reflection, reflection.parent);
+ return;
+ }
+
+ if (hasSourcePage(reflection)) {
+ const shouldWritePage = this.shouldWritePage(reflection);
+ const idealName = this.getIdealBaseName(reflection);
+ const actualName = shouldWritePage
+ ? this.getFileName(idealName)
+ : `${idealName}${this.extension}`;
+
+ this.fullUrls.set(reflection, actualName);
+
+ if (shouldWritePage) {
+ outPages.push({ kind, model: reflection, url: actualName });
+ }
+ } else if (
+ !reflection.kindOf(
+ ReflectionKind.Module |
+ ReflectionKind.Namespace |
+ ReflectionKind.Document
+ )
+ ) {
+ this.buildAnchors(reflection, reflection.parent);
+ }
+
+ reflection.traverse(child => {
+ this.buildChildPages(child, outPages);
+ return true;
+ });
+ }
+
+ /** @param {import('typedoc').DeclarationReflection} reflection */
+ getIdealBaseName(reflection) {
+ return sourcePageBaseName(reflection) ?? super.getIdealBaseName(reflection);
+ }
+
+ /** @param {import('typedoc').RouterTarget} pageTarget */
+ getSlugger(pageTarget) {
+ if (sluggers.has(pageTarget)) {
+ return sluggers.get(pageTarget);
+ }
+
+ // Use doc-kit's slugger so type-map anchors match the parser's heading
+ // normalization instead of TypeDoc's default GitHub-style slugs.
+ const slugger = createNodeSlugger();
+ sluggers.set(pageTarget, slugger);
+ return slugger;
+ }
+
+ /** @param {import('typedoc').RouterTarget} target */
+ getAnchoredURL(target) {
+ const fullUrl = this.getFullUrl(target);
+ const [page, routedAnchor] = fullUrl.split('#');
+ const anchor =
+ sourceAnchorName(target) ?? routedAnchor ?? this.getAnchor(target);
+ const pageUrl = page.replace(/\.md$/, '.html');
+
+ return anchor ? `${pageUrl}#${anchor}` : pageUrl;
+ }
+
+ /**
+ * @param {import('typedoc').RouterTarget} target
+ * @param {import('typedoc').RouterTarget} pageTarget
+ * @param {{ includeChildren?: boolean }} [options]
+ */
+ buildAnchors(target, pageTarget, { includeChildren = true } = {}) {
+ if (
+ !(target instanceof Reflection) ||
+ !(pageTarget instanceof Reflection)
+ ) {
+ return;
+ }
+
+ const pageUrl = this.fullUrls.get(pageTarget);
+ if (!pageUrl) return;
+
+ // Only publish URLs for headings the custom theme actually renders. TypeDoc
+ // exposes signatures, type parameters, class properties, and type literals as
+ // reflections too, but in these docs they are signature bodies or typed list
+ // items rather than linkable headings.
+ if (!rendersHeading(target, pageTarget)) {
+ return;
+ }
+
+ const title = anchorTitle(target, pageTarget);
+ const anchor = this.getSlugger(pageTarget).slug(title);
+
+ this.fullUrls.set(target, `${pageUrl.replace(/\.md$/, '.html')}#${anchor}`);
+ this.anchors.set(target, anchor);
+
+ if (!includeChildren) {
+ return;
+ }
+
+ target.traverse(child => {
+ this.buildAnchors(child, pageTarget);
+ return true;
+ });
+ }
+}
diff --git a/plugins/processor/site.mjs b/plugins/processor/site.mjs
new file mode 100644
index 00000000..b4def82b
--- /dev/null
+++ b/plugins/processor/site.mjs
@@ -0,0 +1,74 @@
+import { ReflectionKind } from 'typedoc';
+import { CATEGORY_RULES } from '../shared/categories.mjs';
+
+const SIDEBAR_KINDS =
+ ReflectionKind.Project | ReflectionKind.Namespace | ReflectionKind.Class;
+
+const SIDEBAR_GROUP_NAME = 'API Documentation';
+
+const getFirstAtxHeading = text => text.match(/^#\s+(.+)$/m)?.[1]?.trim();
+
+const getFirstPathSegment = url => url.replace(/^\//, '').split('/')[0];
+
+const toSidebarLink = url => {
+ const path = url.replace(/\.md$/, '').replace(/\/index$/, '');
+ return path ? `/${path}` : '/';
+};
+
+const defaultLabelFor = (target, url) => {
+ if (url.endsWith('/index.md')) return 'Overview';
+ if (url.endsWith('/types.md')) return 'Types';
+ return target.name;
+};
+
+const isSidebarTarget = (router, target) => {
+ if (!target.kindOf?.(SIDEBAR_KINDS)) return false;
+ if (!router.hasOwnDocument(target)) return false;
+
+ const url = router.getFullUrl(target);
+ return url.endsWith('.md') && !url.includes('#');
+};
+
+export const sidebar = router => {
+ const categories = new Map();
+ const seen = new Set();
+
+ for (const target of router.getLinkTargets()) {
+ if (!isSidebarTarget(router, target)) continue;
+
+ const url = router.getFullUrl(target);
+ if (seen.has(url)) continue;
+ seen.add(url);
+
+ const firstPathSegment = getFirstPathSegment(url);
+ const category = CATEGORY_RULES.find(
+ cat => cat.category === firstPathSegment
+ );
+
+ if (!category) continue;
+
+ const headingName = getFirstAtxHeading(
+ target.comment?.summary?.[0]?.text ?? ''
+ );
+ const label = headingName ?? defaultLabelFor(target, url);
+
+ const group = categories.get(category.category) ?? {
+ label: category.label,
+ items: [],
+ };
+
+ group.items.push({
+ link: toSidebarLink(url),
+ label,
+ });
+
+ categories.set(category.category, group);
+ }
+
+ return [
+ {
+ groupName: SIDEBAR_GROUP_NAME,
+ items: [...categories.values()].filter(category => category.items.length),
+ },
+ ];
+};
diff --git a/plugins/processor/source.mjs b/plugins/processor/source.mjs
new file mode 100644
index 00000000..1af04165
--- /dev/null
+++ b/plugins/processor/source.mjs
@@ -0,0 +1,735 @@
+import ts from 'typescript';
+import { Comment, CommentTag, ReflectionKind, ReflectionType } from 'typedoc';
+import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
+import { basename, dirname, extname, join, relative, resolve } from 'node:path';
+import { getPublicName, setSourceMetadata } from './metadata.mjs';
+
+/**
+ * Source metadata is intentionally a documentation-only overlay:
+ * 1. types.d.ts decides which symbols exist and what their signatures are.
+ * 2. webpack/lib/index.js maps those public symbols back to implementation files.
+ * 3. all JS files under webpack/lib contribute summaries, params, returns,
+ * and stability/deprecation tags when that source comment has real content.
+ */
+const DOC_BLOCK_TAGS = new Set([
+ '@deprecated',
+ '@example',
+ '@legacy',
+ '@remarks',
+ '@see',
+ '@since',
+ '@throws',
+]);
+
+const MODIFIER_TAGS = new Set([
+ '@alpha',
+ '@beta',
+ '@experimental',
+ '@internal',
+]);
+
+const textPart = text => [{ kind: 'text', text }];
+
+const normalizeText = value =>
+ String(value ?? '')
+ .replace(/\r\n?/g, '\n')
+ .trim();
+
+const jsDocText = value => {
+ if (!value) return '';
+ if (Array.isArray(value)) {
+ return normalizeText(
+ value.map(part => part.text ?? part.getText?.() ?? '').join('')
+ );
+ }
+ return normalizeText(value);
+};
+
+const hasCommentContent = comment =>
+ Boolean(
+ comment?.summary ||
+ comment?.returns ||
+ comment?.params?.size ||
+ comment?.blockTags?.length ||
+ comment?.modifierTags?.size
+ );
+
+const hasRenderableCommentContent = comment =>
+ Boolean(
+ comment?.summary ||
+ comment?.returns ||
+ [...(comment?.params?.values() ?? [])].some(Boolean) ||
+ comment?.blockTags?.some(tag => tag.content) ||
+ comment?.modifierTags?.size
+ );
+
+const mergeComments = comments => {
+ const merged = {
+ summary: '',
+ params: new Map(),
+ returns: '',
+ blockTags: [],
+ modifierTags: new Set(),
+ };
+
+ for (const comment of comments.filter(Boolean)) {
+ if (comment.summary) merged.summary = comment.summary;
+ if (comment.returns) merged.returns = comment.returns;
+ for (const [name, value] of comment.params) {
+ if (value) merged.params.set(name, value);
+ }
+ for (const tag of comment.blockTags) {
+ if (tag.content) merged.blockTags.push(tag);
+ }
+ for (const tag of comment.modifierTags) {
+ merged.modifierTags.add(tag);
+ }
+ }
+
+ return hasCommentContent(merged) ? merged : undefined;
+};
+
+// TypeScript exposes JSDoc differently depending on whether a comment belongs
+// to a declaration, assignment, or export wrapper. Walk up a tiny amount so
+// comments attached to CommonJS assignment statements are still discovered.
+const getJsDocs = node => {
+ let current = node;
+
+ while (current && !ts.isSourceFile(current)) {
+ if (current.jsDoc?.length) return current.jsDoc;
+ if (ts.isBlock(current) || ts.isClassDeclaration(current)) break;
+ current = current.parent;
+ }
+
+ return [];
+};
+
+const getJsDocComment = node => {
+ const jsDocs = getJsDocs(node);
+ const comments = jsDocs.map(jsDoc => {
+ const comment = {
+ summary: jsDocText(jsDoc.comment),
+ params: new Map(),
+ returns: '',
+ blockTags: [],
+ modifierTags: new Set(),
+ };
+
+ for (const tag of jsDoc.tags ?? []) {
+ const tagName = `@${tag.tagName?.escapedText ?? ''}`;
+ const content = jsDocText(tag.comment);
+
+ if (ts.isJSDocParameterTag(tag) && tag.name) {
+ comment.params.set(tag.name.getText(), content);
+ continue;
+ }
+
+ if (ts.isJSDocReturnTag(tag)) {
+ comment.returns = content;
+ continue;
+ }
+
+ if (MODIFIER_TAGS.has(tagName)) {
+ comment.modifierTags.add(tagName);
+ continue;
+ }
+
+ if (DOC_BLOCK_TAGS.has(tagName)) {
+ comment.blockTags.push({ tag: tagName, content });
+ }
+ }
+
+ return hasCommentContent(comment) ? comment : undefined;
+ });
+
+ return mergeComments(comments);
+};
+
+const toTypedocComment = sourceComment => {
+ if (!sourceComment || !hasRenderableCommentContent(sourceComment)) {
+ return undefined;
+ }
+
+ const blockTags = [];
+ if (sourceComment.returns) {
+ blockTags.push(new CommentTag('@returns', textPart(sourceComment.returns)));
+ }
+
+ for (const { tag, content } of sourceComment.blockTags ?? []) {
+ blockTags.push(new CommentTag(tag, textPart(content)));
+ }
+
+ return new Comment(
+ sourceComment.summary ? textPart(sourceComment.summary) : [],
+ blockTags,
+ new Set(sourceComment.modifierTags ?? [])
+ );
+};
+
+const toParameterComment = text => {
+ const content = normalizeText(text);
+ return content ? new Comment(textPart(content)) : undefined;
+};
+
+const assignComment = (target, sourceComment) => {
+ const typedocComment = toTypedocComment(sourceComment);
+ if (typedocComment) target.comment = typedocComment;
+};
+
+const applySignatureComment = (signature, sourceComment) => {
+ if (!signature || !hasRenderableCommentContent(sourceComment)) return;
+
+ assignComment(signature, sourceComment);
+
+ const params = [...sourceComment.params.values()].filter(Boolean);
+
+ for (const parameter of signature.parameters ?? []) {
+ const comment =
+ sourceComment.params.get(parameter.name) ??
+ (parameter.name.startsWith('__') && params.length === 1
+ ? params[0]
+ : undefined);
+ const parameterComment = toParameterComment(comment);
+ if (parameterComment) parameter.comment = parameterComment;
+ }
+};
+
+const propertyNameText = name => {
+ if (!name) return undefined;
+ if (
+ ts.isIdentifier(name) ||
+ ts.isStringLiteral(name) ||
+ ts.isNumericLiteral(name)
+ ) {
+ return name.text;
+ }
+ return undefined;
+};
+
+const getAssignedProperty = expression => {
+ if (!ts.isPropertyAccessExpression(expression)) return undefined;
+
+ const property = expression.name.text;
+ const owner = expression.expression;
+
+ if (
+ ts.isPropertyAccessExpression(owner) &&
+ owner.expression.getText() === 'module' &&
+ owner.name.text === 'exports'
+ ) {
+ return property;
+ }
+
+ if (owner.getText() === 'exports') return property;
+
+ return undefined;
+};
+
+const isModuleExports = expression =>
+ ts.isPropertyAccessExpression(expression) &&
+ expression.expression.getText() === 'module' &&
+ expression.name.text === 'exports';
+
+const expressionLocalName = expression =>
+ ts.isIdentifier(expression) ? expression.text : undefined;
+
+const resolveSourceRequest = (fromFile, request) => {
+ if (!request.startsWith('.')) return undefined;
+
+ const base = resolve(dirname(fromFile), request);
+ const candidates = [base, `${base}.js`, join(base, 'index.js')];
+ return candidates.find(candidate => existsSync(candidate));
+};
+
+const firstRequire = expression => {
+ let found;
+
+ const visit = node => {
+ if (found) return;
+
+ if (
+ ts.isCallExpression(node) &&
+ node.expression.getText() === 'require' &&
+ ts.isStringLiteral(node.arguments[0])
+ ) {
+ found = {
+ request: node.arguments[0].text,
+ property:
+ node.parent && ts.isPropertyAccessExpression(node.parent)
+ ? node.parent.name.text
+ : undefined,
+ };
+ return;
+ }
+
+ ts.forEachChild(node, visit);
+ };
+
+ visit(expression);
+ return found;
+};
+
+const listJsFiles = directory => {
+ const entries = readdirSync(directory, { withFileTypes: true });
+ const files = [];
+
+ for (const entry of entries) {
+ const path = join(directory, entry.name);
+ if (entry.isDirectory()) {
+ files.push(...listJsFiles(path));
+ } else if (entry.isFile() && extname(entry.name) === '.js') {
+ files.push(path);
+ }
+ }
+
+ return files;
+};
+
+const sourceFileFor = filePath =>
+ ts.createSourceFile(
+ filePath,
+ readFileSync(filePath, 'utf8'),
+ ts.ScriptTarget.Latest,
+ true,
+ ts.ScriptKind.JS
+ );
+
+const sourceFileBase = filePath => basename(filePath, extname(filePath));
+
+const createFileMetadata = (filePath, libDir) => {
+ const sourceFile = sourceFileFor(filePath);
+ const symbols = new Map();
+ const classes = new Map();
+ const namedExports = new Map();
+ let defaultExport;
+
+ const rememberSymbol = (name, data) => {
+ if (!name) return;
+ const existing = symbols.get(name) ?? {};
+ symbols.set(name, {
+ ...existing,
+ ...data,
+ comment: data.comment ?? existing.comment,
+ members: data.members ?? existing.members,
+ });
+ };
+
+ // Keep per-class member comments separate from file-level exports. A public
+ // class comes from types.d.ts, but method/constructor prose usually lives in
+ // the implementation file next to the code.
+ const classMembers = node => {
+ const members = new Map();
+
+ for (const member of node.members ?? []) {
+ if (ts.isConstructorDeclaration(member)) {
+ const comment = getJsDocComment(member);
+ if (comment) members.set('constructor', comment);
+ continue;
+ }
+
+ const name = propertyNameText(member.name);
+ if (!name) continue;
+
+ const comment = getJsDocComment(member);
+ if (comment) members.set(name, comment);
+ }
+
+ return members;
+ };
+
+ const visit = node => {
+ if (ts.isClassDeclaration(node) && node.name) {
+ const data = {
+ kind: 'class',
+ localName: node.name.text,
+ comment: getJsDocComment(node),
+ members: classMembers(node),
+ };
+ symbols.set(node.name.text, data);
+ classes.set(node.name.text, data);
+ }
+
+ if (ts.isFunctionDeclaration(node) && node.name) {
+ rememberSymbol(node.name.text, {
+ kind: 'function',
+ localName: node.name.text,
+ comment: getJsDocComment(node),
+ });
+ }
+
+ if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
+ const comment = getJsDocComment(node);
+ if (comment) {
+ rememberSymbol(node.name.text, {
+ kind: 'variable',
+ localName: node.name.text,
+ comment,
+ });
+ }
+ }
+
+ if (
+ ts.isExpressionStatement(node) &&
+ ts.isBinaryExpression(node.expression)
+ ) {
+ const { left, right } = node.expression;
+ const comment = getJsDocComment(node) ?? getJsDocComment(right);
+
+ if (isModuleExports(left)) {
+ defaultExport = {
+ localName: expressionLocalName(right),
+ comment,
+ };
+ } else {
+ const property = getAssignedProperty(left);
+ if (property) {
+ namedExports.set(property, {
+ localName: expressionLocalName(right),
+ comment,
+ });
+ }
+ }
+
+ if (
+ ts.isPropertyAccessExpression(left) &&
+ ts.isIdentifier(left.expression) &&
+ classes.has(left.expression.text) &&
+ comment
+ ) {
+ classes.get(left.expression.text).members.set(left.name.text, comment);
+ }
+ }
+
+ ts.forEachChild(node, visit);
+ };
+
+ visit(sourceFile);
+
+ return {
+ filePath,
+ fileBase: sourceFileBase(filePath),
+ relativePath: relative(libDir, filePath).replace(/\\/g, '/'),
+ symbols,
+ classes,
+ namedExports,
+ defaultExport,
+ };
+};
+
+const getExportObject = sourceFile => {
+ let exportObject;
+
+ const visit = node => {
+ if (exportObject) return;
+
+ if (
+ ts.isExpressionStatement(node) &&
+ ts.isBinaryExpression(node.expression) &&
+ isModuleExports(node.expression.left) &&
+ ts.isCallExpression(node.expression.right)
+ ) {
+ const objectArg = [...node.expression.right.arguments].find(
+ ts.isObjectLiteralExpression
+ );
+ if (objectArg) exportObject = objectArg;
+ }
+
+ ts.forEachChild(node, visit);
+ };
+
+ visit(sourceFile);
+ return exportObject;
+};
+
+const buildExportMap = libDir => {
+ const indexPath = join(libDir, 'index.js');
+ const sourceFile = sourceFileFor(indexPath);
+ const exportMap = new Map();
+ const exportObject = getExportObject(sourceFile);
+
+ const addExport = (parts, data) => {
+ exportMap.set(parts.join('.'), {
+ publicPath: parts.join('.'),
+ publicName: parts.at(-1),
+ ...data,
+ });
+ };
+
+ // webpack's callable export is assigned outside lib/index.js, so seed the
+ // root namespace before walking the object tree of re-exported helpers.
+ addExport(['webpack'], {
+ sourcePath: join(libDir, 'webpack.js'),
+ localName: 'webpack',
+ });
+
+ const walkObject = (object, parts = []) => {
+ for (const property of object.properties) {
+ const name = propertyNameText(property.name);
+ if (!name) continue;
+
+ if (
+ ts.isPropertyAssignment(property) &&
+ ts.isObjectLiteralExpression(property.initializer)
+ ) {
+ walkObject(property.initializer, [...parts, name]);
+ continue;
+ }
+
+ const expression = ts.isGetAccessor(property)
+ ? property.body?.statements.filter(ts.isReturnStatement).at(-1)
+ ?.expression
+ : ts.isPropertyAssignment(property)
+ ? property.initializer
+ : undefined;
+
+ if (!expression) continue;
+
+ const requireCall = firstRequire(expression);
+ const sourcePath = requireCall?.request
+ ? resolveSourceRequest(indexPath, requireCall.request)
+ : undefined;
+
+ addExport([...parts, name], {
+ sourcePath,
+ localName: requireCall?.property,
+ comment: getJsDocComment(property),
+ });
+ }
+ };
+
+ if (exportObject) walkObject(exportObject);
+ return exportMap;
+};
+
+const buildSourceIndex = libDir => {
+ const sourceFiles = new Map();
+ for (const file of listJsFiles(libDir)) {
+ sourceFiles.set(file, createFileMetadata(file, libDir));
+ }
+ return sourceFiles;
+};
+
+const publicName = reflection =>
+ getPublicName(reflection) ?? reflection.getFullName?.();
+
+const exportEntryFor = (name, exportMap) => {
+ const exact = exportMap.get(name);
+ if (exact) return exact;
+
+ const parts = name.split('.');
+ for (let i = parts.length - 1; i > 0; i--) {
+ const parent = exportMap.get(parts.slice(0, i).join('.'));
+ if (!parent?.sourcePath) continue;
+
+ const memberPath = parts.slice(i);
+ // If lib/index.js exports an object, types.d.ts may expose its properties as
+ // public members. Reuse the parent source file and match the leaf locally.
+ return {
+ ...parent,
+ publicPath: name,
+ publicName: memberPath.at(-1),
+ localName: memberPath.at(-1),
+ parentPublicPath: parent.publicPath,
+ memberPath,
+ };
+ }
+};
+
+const sourceEntryFor = (entry, sourceFiles) => {
+ const file = entry.sourcePath ? sourceFiles.get(entry.sourcePath) : undefined;
+ if (!file) return undefined;
+
+ const exported = entry.publicName
+ ? file.namedExports.get(entry.publicName)
+ : undefined;
+ const localName =
+ entry.localName ??
+ exported?.localName ??
+ file.defaultExport?.localName ??
+ entry.publicName;
+ const symbol =
+ file.symbols.get(localName) ?? file.symbols.get(entry.publicName);
+
+ return {
+ file,
+ localName,
+ comment:
+ symbol?.comment ??
+ entry.comment ??
+ exported?.comment ??
+ file.defaultExport?.comment,
+ symbol,
+ };
+};
+
+const commentForSourceEntry = sourceEntry =>
+ sourceEntry?.comment ?? sourceEntry?.symbol?.comment;
+
+const memberSourceComment = (sourceEntry, memberName) =>
+ sourceEntry?.symbol?.members?.get(memberName) ??
+ sourceEntry?.file.namedExports.get(memberName)?.comment ??
+ sourceEntry?.file.symbols.get(memberName)?.comment;
+
+const namedExportComment = (sourceEntry, memberName) => {
+ const exported = sourceEntry?.file.namedExports.get(memberName);
+ if (!exported) return undefined;
+ return (
+ exported.comment ??
+ sourceEntry.file.symbols.get(exported.localName)?.comment ??
+ sourceEntry.file.symbols.get(memberName)?.comment
+ );
+};
+
+const ownSignatures = reflection => [
+ ...(reflection.signatures ?? []),
+ ...(reflection.type instanceof ReflectionType
+ ? (reflection.type.declaration.signatures ?? [])
+ : []),
+];
+
+const applyFunctionLikeComment = (reflection, sourceComment) => {
+ if (!hasRenderableCommentContent(sourceComment)) return;
+
+ const signatures = ownSignatures(reflection);
+ if (signatures.length) {
+ signatures.forEach(signature =>
+ applySignatureComment(signature, sourceComment)
+ );
+ } else {
+ assignComment(reflection, sourceComment);
+ }
+};
+
+// Exported object literals (for example helper namespaces) often document their
+// individual properties as named exports in the implementation file.
+const applyObjectMembers = (reflection, sourceEntry) => {
+ const declaration =
+ reflection.type instanceof ReflectionType
+ ? reflection.type.declaration
+ : undefined;
+
+ for (const child of declaration?.children ?? []) {
+ const sourceComment =
+ namedExportComment(sourceEntry, child.name) ??
+ sourceEntry?.file.symbols.get(child.name)?.comment;
+
+ if (!hasRenderableCommentContent(sourceComment)) continue;
+
+ const signatures = ownSignatures(child);
+ if (signatures.length) {
+ signatures.forEach(signature =>
+ applySignatureComment(signature, sourceComment)
+ );
+ } else {
+ assignComment(child, sourceComment);
+ }
+ }
+};
+
+const applyNamespaceMembers = (reflection, sourceEntry) => {
+ for (const child of reflection.children ?? []) {
+ const sourceComment =
+ namedExportComment(sourceEntry, child.name) ??
+ sourceEntry?.file.symbols.get(child.name)?.comment;
+
+ if (!hasRenderableCommentContent(sourceComment)) continue;
+
+ applyFunctionLikeComment(child, sourceComment);
+ }
+};
+
+const applyClassMembers = (reflection, sourceEntry) => {
+ assignComment(reflection, commentForSourceEntry(sourceEntry));
+
+ for (const child of reflection.children ?? []) {
+ if (child.kindOf(ReflectionKind.Constructor)) {
+ const comment = memberSourceComment(sourceEntry, 'constructor');
+ child.signatures?.forEach(signature =>
+ applySignatureComment(signature, comment)
+ );
+ continue;
+ }
+
+ const comment = memberSourceComment(sourceEntry, child.name);
+ if (!hasRenderableCommentContent(comment)) continue;
+
+ if (child.signatures?.length) {
+ child.signatures.forEach(signature =>
+ applySignatureComment(signature, comment)
+ );
+ } else {
+ assignComment(child, comment);
+ }
+ }
+};
+
+const attachSourceMetadata = (reflection, sourceEntry, exportEntry) => {
+ if (!sourceEntry?.file) return;
+
+ const leaf = publicName(reflection)?.split('.').at(-1);
+ const fileBase = sourceEntry.file.fileBase;
+
+ setSourceMetadata(reflection, {
+ sourcePath: sourceEntry.file.filePath,
+ sourceRelativePath: sourceEntry.file.relativePath,
+ fileBase,
+ anchorName: fileBase !== leaf ? leaf : undefined,
+ publicPath: exportEntry.publicPath,
+ });
+};
+
+/**
+ * Enrich declaration reflections with comments and source locations recovered
+ * from webpack/lib. The declaration file remains authoritative for public API
+ * shape; this pass only adds documentation content and routing hints.
+ *
+ * @param {import('typedoc').ProjectReflection} project
+ * @param {{ libDir?: string }} [options]
+ */
+export const applySourceMetadata = (
+ project,
+ { libDir = './webpack/lib' } = {}
+) => {
+ const absoluteLibDir = resolve(libDir);
+ if (!existsSync(absoluteLibDir) || !statSync(absoluteLibDir).isDirectory()) {
+ return;
+ }
+
+ const sourceFiles = buildSourceIndex(absoluteLibDir);
+ const exportMap = buildExportMap(absoluteLibDir);
+
+ // The declaration file remains authoritative for shape. This pass only
+ // enriches public reflections that can be matched back to webpack/lib source.
+ for (const reflection of project.getReflectionsByKind(ReflectionKind.All)) {
+ if (
+ !reflection.kindOf(
+ ReflectionKind.Class |
+ ReflectionKind.Namespace |
+ ReflectionKind.Function |
+ ReflectionKind.Variable
+ )
+ ) {
+ continue;
+ }
+
+ const name = publicName(reflection);
+ const exportEntry = name ? exportEntryFor(name, exportMap) : undefined;
+ if (!exportEntry?.sourcePath) continue;
+
+ const sourceEntry = sourceEntryFor(exportEntry, sourceFiles);
+ attachSourceMetadata(reflection, sourceEntry, exportEntry);
+
+ if (reflection.kindOf(ReflectionKind.Namespace)) {
+ applyNamespaceMembers(reflection, sourceEntry);
+ continue;
+ }
+
+ if (reflection.kindOf(ReflectionKind.Class)) {
+ applyClassMembers(reflection, sourceEntry);
+ continue;
+ }
+
+ applyFunctionLikeComment(reflection, commentForSourceEntry(sourceEntry));
+ applyObjectMembers(reflection, sourceEntry);
+ }
+};
diff --git a/plugins/processor/synthetic.mjs b/plugins/processor/synthetic.mjs
new file mode 100644
index 00000000..dcaf5bb2
--- /dev/null
+++ b/plugins/processor/synthetic.mjs
@@ -0,0 +1,117 @@
+import { Comment, DeclarationReflection, ReflectionKind } from 'typedoc';
+import { categoryForReflection } from '../shared/categories.mjs';
+import { setTypePageMetadata } from './metadata.mjs';
+
+export const TYPE_PAGE_HEADING_KINDS =
+ ReflectionKind.Interface | ReflectionKind.TypeAlias;
+
+const TYPE_PAGE_NOTICE =
+ 'These types are not exported by webpack, but they are available to TypeScript consumers.';
+
+const categoryNameForReflection = reflection =>
+ categoryForReflection(reflection)?.category;
+
+const typePageBaseName = reflection => {
+ const category = categoryNameForReflection(reflection);
+ return category ? `${category}/types` : 'types';
+};
+
+const typePageNamespace = baseName =>
+ baseName === 'types'
+ ? 'webpack'
+ : `webpack.${baseName.replace(/\/types$/, '').replace(/\//g, '.')}`;
+
+const typePageTitle = baseName => `\`${typePageNamespace(baseName)}\` Types`;
+
+const typePageName = baseName => baseName.replace(/\//g, '.');
+
+const typePageComment = () =>
+ new Comment([
+ {
+ kind: 'text',
+ text: TYPE_PAGE_NOTICE,
+ },
+ ]);
+
+const removeChildren = (items, moved) =>
+ items?.filter(item => !moved.has(item));
+
+const removeFromGroups = (groups, moved) =>
+ groups
+ ?.map(group => ({
+ ...group,
+ children: group.children.filter(child => !moved.has(child)),
+ categories: removeFromGroups(group.categories, moved),
+ }))
+ .filter(group => group.children.length || group.categories?.length);
+
+const makeTypeGroup = (title, children) =>
+ children.length ? { title, children } : undefined;
+
+const createTypePage = (project, baseName, children) => {
+ const page = new DeclarationReflection(
+ typePageName(baseName),
+ ReflectionKind.Namespace,
+ project
+ );
+ const interfaces = children.filter(child =>
+ child.kindOf(ReflectionKind.Interface)
+ );
+ const typeAliases = children.filter(child =>
+ child.kindOf(ReflectionKind.TypeAlias)
+ );
+
+ page.children = children;
+ page.childrenIncludingDocuments = children;
+ page.comment = typePageComment();
+ page.groups = [
+ makeTypeGroup('Interfaces', interfaces),
+ makeTypeGroup('Type Aliases', typeAliases),
+ ].filter(Boolean);
+
+ setTypePageMetadata(page, {
+ baseName,
+ title: typePageTitle(baseName),
+ });
+
+ return page;
+};
+
+const compareByName = (a, b) => a.name.localeCompare(b.name);
+
+/**
+ * Move root interfaces and type aliases onto synthetic category pages so they
+ * remain linkable without appearing as root API exports.
+ *
+ * @param {import('typedoc').ProjectReflection} project
+ */
+export const createTypePages = project => {
+ const movedTypes = (project.children ?? [])
+ .filter(child => child.kindOf(TYPE_PAGE_HEADING_KINDS))
+ .sort(compareByName);
+ const movedSet = new Set(movedTypes);
+ const byPage = new Map();
+
+ for (const reflection of movedTypes) {
+ const baseName = typePageBaseName(reflection);
+ const group = byPage.get(baseName) ?? [];
+ group.push(reflection);
+ byPage.set(baseName, group);
+ }
+
+ // Remove moved structural types from the project root before TypeDoc builds
+ // README.md; their URLs are rebuilt by the router against these pages.
+ project.children = removeChildren(project.children, movedSet);
+ project.childrenIncludingDocuments = removeChildren(
+ project.childrenIncludingDocuments,
+ movedSet
+ );
+ project.groups = removeFromGroups(project.groups, movedSet);
+ project.categories = removeFromGroups(project.categories, movedSet);
+
+ return [...byPage].map(([baseName, children]) => ({
+ baseName,
+ children,
+ model: createTypePage(project, baseName, children),
+ }));
+};
diff --git a/plugins/processor/typeMap.mjs b/plugins/processor/typeMap.mjs
new file mode 100644
index 00000000..de327c33
--- /dev/null
+++ b/plugins/processor/typeMap.mjs
@@ -0,0 +1,31 @@
+import { ReflectionKind } from 'typedoc';
+import { isTypePage } from './metadata.mjs';
+
+const TYPE_MAP_KINDS =
+ ReflectionKind.Class |
+ ReflectionKind.Interface |
+ ReflectionKind.TypeAlias |
+ ReflectionKind.Enum;
+
+const isTypeMapTarget = target =>
+ !isTypePage(target) && target.kindOf?.(TYPE_MAP_KINDS);
+
+/**
+ * Build the annotation resolver map from the router's final public URLs.
+ *
+ * @param {import('typedoc-plugin-markdown').Router} router
+ */
+export const createTypeMap = router => {
+ const typeMap = new Map();
+
+ for (const target of router.getLinkTargets()) {
+ if (!isTypeMapTarget(target)) continue;
+
+ const { name } = target;
+ if (!typeMap.has(name)) {
+ typeMap.set(name, router.getAnchoredURL(target));
+ }
+ }
+
+ return Object.fromEntries(typeMap);
+};
diff --git a/plugins/shared/categories.mjs b/plugins/shared/categories.mjs
new file mode 100644
index 00000000..801f0d31
--- /dev/null
+++ b/plugins/shared/categories.mjs
@@ -0,0 +1,127 @@
+import { ReflectionKind } from 'typedoc';
+
+// First match wins. Keep more specific groups above broad API-family rules so
+// adding a new category is usually a single RegExp entry rather than router code.
+export const CATEGORY_RULES = [
+ {
+ category: 'plugins',
+ label: 'Plugins',
+ match: reflection =>
+ reflection.kindOf(ReflectionKind.Class) &&
+ reflection.name.endsWith('Plugin'),
+ pattern: /^WebpackPlugin/,
+ },
+ {
+ category: 'cli',
+ label: 'Command-Line Interface',
+ pattern: /^(?:Argument|Colors|ColorsOptions|Problem)$/,
+ },
+ {
+ category: 'assets',
+ label: 'Assets',
+ pattern: /^Asset|AssetInfo$/,
+ },
+ {
+ category: 'cache',
+ label: 'Cache',
+ pattern: /Cache|Cached|Etag|ValueCache/,
+ },
+ {
+ category: 'runtime',
+ label: 'Runtime',
+ pattern: /^Runtime.*/,
+ },
+ {
+ category: 'stats',
+ label: 'Stats',
+ pattern: /^(?:Multi)?Stats/,
+ },
+ {
+ category: 'errors',
+ label: 'Errors',
+ pattern: /(?:Error|ValidationError)$/,
+ },
+ {
+ category: 'chunks',
+ label: 'Chunks',
+ pattern: /^(?:.*Chunk.*|Entrypoint)$/,
+ },
+ {
+ category: 'compilation',
+ label: 'Compilation',
+ pattern:
+ /^(?:Compilation|Compiler|MultiCompiler|Watching|PathData|CodeGenerationResults?)$/,
+ },
+ {
+ category: 'dependencies',
+ label: 'Dependencies',
+ pattern: /Dependency/,
+ },
+ {
+ category: 'entries',
+ label: 'Entries',
+ pattern: /^Entry/,
+ },
+ {
+ category: 'externals',
+ label: 'Externals',
+ pattern: /^External|Externals/,
+ },
+ {
+ category: 'filesystem',
+ label: 'File System',
+ pattern: /FileSystem$/,
+ },
+ {
+ category: 'library',
+ label: 'Library',
+ pattern: /Library/,
+ },
+ {
+ category: 'loaders',
+ label: 'Loaders',
+ pattern: /Loader/,
+ },
+ {
+ category: 'modules',
+ label: 'Modules',
+ pattern:
+ /^(?:AsyncDependenciesBlock|.*Dependency|.*Module.*|Generator|Parser)$/,
+ },
+ {
+ category: 'resolvers',
+ label: 'Resolvers',
+ pattern: /^Resolve/,
+ },
+ {
+ category: 'rules',
+ label: 'Rules',
+ pattern: /^RuleSet/,
+ },
+ {
+ category: 'serialization',
+ label: 'Serialization',
+ pattern: /(?:Serializer|Deserializer)/,
+ },
+ {
+ category: 'templates',
+ label: 'Templates',
+ pattern: /^(?:Template|RenderManifest)/,
+ },
+ {
+ category: 'config',
+ label: 'Configuration',
+ pattern:
+ /^(?:Configuration|MultiConfiguration|.*Options(?:Normalized)?|validate(?:Schema)?|WebpackOptions.*)$/,
+ },
+];
+
+export const categoryForReflection = reflection => {
+ for (const rule of CATEGORY_RULES) {
+ if (rule.match?.(reflection) || rule.pattern?.test(reflection.name)) {
+ return rule;
+ }
+ }
+
+ return null;
+};
diff --git a/plugins/shared/titles.mjs b/plugins/shared/titles.mjs
new file mode 100644
index 00000000..97c30114
--- /dev/null
+++ b/plugins/shared/titles.mjs
@@ -0,0 +1,120 @@
+import { ReflectionKind } from 'typedoc';
+import { getPublicName } from '../processor/metadata.mjs';
+
+// Heading text is also anchor input. Keep all programmatic names formatted here
+// so the Markdown theme and router cannot drift into different slugs.
+const KIND_PREFIX = {
+ [ReflectionKind.Class]: 'Class',
+ [ReflectionKind.Interface]: 'Interface',
+ [ReflectionKind.Enum]: 'Enum',
+ [ReflectionKind.TypeAlias]: 'Type',
+ [ReflectionKind.Namespace]: 'Namespace',
+ [ReflectionKind.Accessor]: 'Accessor',
+};
+
+const STATIC_PREFIX = {
+ [ReflectionKind.Method]: 'Static method',
+};
+
+const escapeCode = value => String(value).replace(/`/g, '\\`');
+
+const hasQualifiedParent = model => {
+ let parent = model.parent;
+
+ while (parent) {
+ if (parent.kindOf?.(ReflectionKind.Class | ReflectionKind.Namespace)) {
+ return true;
+ }
+
+ if (parent.kindOf?.(ReflectionKind.Project)) {
+ return false;
+ }
+
+ parent = parent.parent;
+ }
+
+ return false;
+};
+
+const memberName = (model, { local = false } = {}) => {
+ return local || hasQualifiedParent(model) ? model.name : fullName(model);
+};
+
+export const fullName = model => {
+ const publicName = getPublicName(model);
+ if (publicName) return publicName;
+
+ const name = model.getFullName?.() ?? model.name;
+ let root = model;
+
+ while (root.parent) root = root.parent;
+
+ if (model === root) {
+ return name;
+ }
+
+ // TypeDoc omits the project name from nested full names. The generated docs
+ // treat the project as the public webpack namespace, so add it back whenever
+ // TypeDoc has not already included it.
+ if (!root.name || name.startsWith(`${root.name}.`)) {
+ return name;
+ }
+
+ return `${root.name}.${name}`;
+};
+
+export const formatParams = (params = []) =>
+ params
+ .map(({ name, flags }, i) => {
+ const paramName = flags?.isRest ? `...${name}` : name;
+ if (flags?.isRest) return i ? `, ${paramName}` : paramName;
+
+ return flags?.isOptional
+ ? i
+ ? `[, ${paramName}]`
+ : `[${paramName}]`
+ : i
+ ? `, ${paramName}`
+ : paramName;
+ })
+ .join('');
+
+export const signatureExpression = (
+ model,
+ params = [],
+ name = fullName(model)
+) => `${name}(${formatParams(params)})`;
+
+export const callableSignatures = model =>
+ model.signatures ?? model.type?.declaration?.signatures ?? [];
+
+export const getConstructorTitle = (model, signature = model.signatures?.[0]) =>
+ `\`new ${escapeCode(model.parent.name)}(${formatParams(signature?.parameters ?? [])})\``;
+
+export const getMemberPrefix = model => {
+ const prefix = model.flags?.isStatic
+ ? STATIC_PREFIX[model.kind]
+ : KIND_PREFIX[model.kind];
+
+ return prefix ? `${prefix}: ` : '';
+};
+
+export const getMemberTitle = (model, options) => {
+ const prefix = getMemberPrefix(model);
+ const params = model.parameters ?? callableSignatures(model)[0]?.parameters;
+ const name = escapeCode(memberName(model, options));
+
+ if (params) {
+ return `${prefix}\`${escapeCode(signatureExpression(model, params, name))}\``;
+ }
+
+ return `${prefix}\`${name}\``;
+};
+
+export const getPageTitle = model => {
+ const title = model.kindOf?.(ReflectionKind.Class)
+ ? `Class: \`${escapeCode(fullName(model))}\``
+ : `\`${escapeCode(fullName(model))}\``;
+
+ return title;
+};
diff --git a/plugins/theme/helpers/index.mjs b/plugins/theme/helpers/index.mjs
index 0b77228e..f5dfdcae 100644
--- a/plugins/theme/helpers/index.mjs
+++ b/plugins/theme/helpers/index.mjs
@@ -40,19 +40,23 @@ export default ctx => ({
return entries.map(ctx.helpers.typedListItem).join('\n');
},
- examples(comment, { headingLevel }) {
+ examples(comment) {
const examples =
comment?.blockTags?.filter(t => t.tag === '@example') ?? [];
if (!examples.length) return null;
- const prefix = '#'.repeat(headingLevel + 1);
- const single = examples.length === 1;
+ // Source JSDoc examples in webpack are usually plain code snippets. The
+ // doc-kit spec expects code examples to be fenced, so wrap bare snippets
+ // while leaving already-fenced examples untouched.
return examples
.map((tag, i) => {
const body = ctx.helpers.getCommentParts(tag.content).trim();
- return (
- body && `${prefix} Example${single ? '' : ` ${i + 1}`}\n\n${body}`
- );
+ if (!body) return;
+ if (body.includes('```')) return body;
+
+ const displayName =
+ examples.length > 1 ? ` displayName="Example ${i + 1}"` : '';
+ return `\`\`\`js${displayName}\n${body}\n\`\`\``;
})
.filter(Boolean)
.join('\n\n');
diff --git a/plugins/theme/index.mjs b/plugins/theme/index.mjs
index dd2857a0..245434ea 100644
--- a/plugins/theme/index.mjs
+++ b/plugins/theme/index.mjs
@@ -2,8 +2,6 @@ import { MarkdownTheme, MarkdownThemeContext } from 'typedoc-plugin-markdown';
import helpers from './helpers/index.mjs';
import partials from './partials/index.mjs';
-import { DocKitRouter } from './router.mjs';
-
export class DocKitTheme extends MarkdownTheme {
getRenderContext(page) {
return new DocKitThemeContext(this, page, this.application.options);
@@ -25,5 +23,4 @@ export class DocKitThemeContext extends MarkdownThemeContext {
*/
export function load(app) {
app.renderer.defineTheme('doc-kit', DocKitTheme);
- app.renderer.defineRouter('doc-kit', DocKitRouter);
}
diff --git a/plugins/theme/partials/index.mjs b/plugins/theme/partials/index.mjs
index a5dc697f..c56ee3a1 100644
--- a/plugins/theme/partials/index.mjs
+++ b/plugins/theme/partials/index.mjs
@@ -1,115 +1,309 @@
-import { ReflectionKind } from 'typedoc';
+import { getTypePageTitle, isTypePage } from '../../processor/metadata.mjs';
+import {
+ ArrayType,
+ i18n,
+ IntersectionType,
+ ReflectionKind,
+ ReflectionType,
+ UnionType,
+} from 'typedoc';
+import {
+ callableSignatures,
+ getConstructorTitle,
+ getMemberTitle,
+ getPageTitle,
+} from '../../shared/titles.mjs';
import * as typePartials from './types.mjs';
-const KIND_PREFIX = {
- [ReflectionKind.Class]: 'Class',
- [ReflectionKind.Interface]: 'Interface',
- [ReflectionKind.Enum]: 'Enum',
- [ReflectionKind.TypeAlias]: 'Type',
- [ReflectionKind.Namespace]: 'Namespace',
- [ReflectionKind.Accessor]: 'Accessor',
-};
-
-const STATIC_PREFIX = {
- [ReflectionKind.Method]: 'Static method',
-};
-
-const formatParams = (params = []) =>
- params
- .map(({ name, flags }, i) =>
- flags?.isOptional
- ? i
- ? `[, ${name}]`
- : `[${name}]`
- : i
- ? `, ${name}`
- : name
- )
- .join('');
-
-export const getMemberPrefix = model => {
- const prefix = model.flags?.isStatic
- ? STATIC_PREFIX[model.kind]
- : KIND_PREFIX[model.kind];
-
- return prefix ? `${prefix}: ` : '';
-};
+const heading = (level, title) => `${'#'.repeat(level)} ${title}`;
-export const getMemberTitle = model => {
- const prefix = getMemberPrefix(model);
- const params = model.signatures?.[0]?.parameters;
+// These partials deliberately trade TypeDoc's default blockquote signatures for
+// doc-kit headings and typed lists. The router uses the same title helpers, so
+// rendered anchors and type-map URLs stay in sync.
+const inheritedComment = (model, options) =>
+ options.multipleSignatures
+ ? model.comment
+ : model.comment || model.parent?.comment;
- if (!params) {
- return `${prefix}\`${model.name}\``;
- }
-
- return `${prefix}\`${model.name}(${formatParams(params)})\``;
-};
+const declarationType = model =>
+ model.type ??
+ model.getSignature?.type ??
+ model.setSignature?.parameters?.[0]?.type;
/**
* @param {import('typedoc-plugin-markdown').MarkdownThemeContext} ctx
* @returns {import('typedoc-plugin-markdown').MarkdownThemeContext['partials']}
*/
-export default ctx => ({
- ...ctx.partials,
- ...typePartials,
-
- signature(model, options) {
- const comment = options.multipleSignatures
- ? model.comment
- : model.comment || model.parent?.comment;
-
- const stability = ctx.helpers.stabilityBlockquote(comment);
-
- return [
- stability,
- stability && '',
- model.typeParameters?.length &&
- ctx.partials.typeParametersList(model.typeParameters, {
- headingLevel: options.headingLevel,
- }),
- model.parameters?.length &&
- ctx.partials.parametersList(model.parameters, {
- headingLevel: options.headingLevel,
- }),
- ctx.helpers.typedListItem({
- label: 'Returns',
- type: model.type ?? 'void',
- comment: model.comment?.getTag('@returns'),
- }),
- '',
- comment &&
- ctx.partials.comment(comment, {
- headingLevel: options.headingLevel,
- showTags: false,
+export default ctx => {
+ return {
+ ...ctx.partials,
+ ...typePartials,
+
+ pageTitle() {
+ const model = ctx.page.model;
+ const typePageTitle = getTypePageTitle(model);
+ if (typePageTitle) return typePageTitle;
+ if (model.getFullName) return getPageTitle(model);
+ return ctx.partials.pageTitle();
+ },
+
+ signature(model, options) {
+ const comment = inheritedComment(model, options);
+ const stability = ctx.helpers.stabilityBlockquote(comment);
+
+ return [
+ stability,
+ stability && '',
+ model.parameters?.length &&
+ ctx.partials.parametersList(model.parameters, {
+ headingLevel: options.headingLevel,
+ }),
+ ctx.helpers.typedListItem({
+ label: 'Returns',
+ type: model.type ?? 'void',
+ comment: model.comment?.getTag('@returns'),
}),
- ctx.helpers.examples(comment, options),
- ]
- .filter(x => typeof x === 'string' || Boolean(x))
- .join('\n');
- },
+ '',
+ comment &&
+ ctx.partials.comment(comment, {
+ headingLevel: options.headingLevel,
+ showTags: false,
+ }),
+ ctx.helpers.examples(comment, options),
+ ]
+ .filter(x => typeof x === 'string' || Boolean(x))
+ .join('\n');
+ },
+
+ declaration(model, options) {
+ const opts = { headingLevel: 2, nested: false, ...options };
+ const signatures = callableSignatures(model);
+
+ if (signatures.length) {
+ return signatures
+ .map(signature =>
+ ctx.partials.signature(signature, {
+ headingLevel: opts.headingLevel,
+ multipleSignatures: signatures.length > 1,
+ })
+ )
+ .join('\n\n');
+ }
- constructor(model, options) {
- const md = [];
- const heading = '#'.repeat(options.headingLevel);
+ const comment = model.comment;
+ const stability = ctx.helpers.stabilityBlockquote(comment);
+ const md = [
+ stability,
+ stability && '',
+ ctx.partials.declarationTitle(model),
+ ];
- model.signatures?.forEach(signature => {
- const paramsString = formatParams(signature.parameters ?? []);
+ if (comment) {
+ md.push(
+ '',
+ ctx.partials.comment(comment, {
+ headingLevel: opts.headingLevel,
+ showSummary: true,
+ showTags: false,
+ })
+ );
+ }
- md.push(`${heading} \`new ${model.parent.name}(${paramsString})\``);
+ let typeDeclaration = model.type?.declaration;
+ if (
+ model.type instanceof ArrayType &&
+ model.type.elementType instanceof ReflectionType
+ ) {
+ typeDeclaration = model.type.elementType.declaration;
+ }
+
+ if (model.type instanceof IntersectionType) {
+ for (const intersectionType of model.type.types ?? []) {
+ if (
+ intersectionType instanceof ReflectionType &&
+ intersectionType.declaration.children &&
+ !intersectionType.declaration.signatures
+ ) {
+ md.push(heading(opts.headingLevel, i18n.theme_type_declaration()));
+ md.push(
+ ctx.partials.typeDeclaration(intersectionType.declaration, {
+ headingLevel: opts.headingLevel,
+ })
+ );
+ }
+ }
+ }
+
+ const hasUnionDetails =
+ model.type instanceof UnionType &&
+ ctx.helpers.hasUsefulTypeDetails(model.type);
+ if (hasUnionDetails) {
+ md.push(heading(opts.headingLevel, i18n.theme_union_members()));
+ md.push(ctx.partials.typeDeclarationUnionContainer(model, opts));
+ } else if (typeDeclaration) {
+ const useHeading =
+ typeDeclaration.children?.length &&
+ (model.kind !== ReflectionKind.Property ||
+ ctx.helpers.useTableFormat('properties'));
+ if (useHeading) {
+ md.push(heading(opts.headingLevel, i18n.theme_type_declaration()));
+ }
+ md.push(
+ ctx.partials.typeDeclarationContainer(model, typeDeclaration, opts)
+ );
+ }
+
+ md.push(ctx.helpers.examples(comment, opts));
md.push(
- ctx.partials.signature(signature, {
- headingLevel: options.headingLevel + 1,
- })
+ ctx.partials.inheritance(model, { headingLevel: opts.headingLevel })
);
- });
- return md.join('\n\n');
- },
- typeParametersList: () => '',
+ return md.filter(x => typeof x === 'string' || Boolean(x)).join('\n\n');
+ },
+
+ declarationTitle(model) {
+ return ctx.helpers.typedListItem({
+ label: 'Type',
+ type: declarationType(model) ?? 'unknown',
+ });
+ },
- memberTitle: getMemberTitle,
- parametersList: ctx.helpers.typedList,
- typeDeclarationList: ctx.helpers.typedList,
- propertiesTable: ctx.helpers.typedList,
-});
+ indexSignature(model) {
+ const params = model.parameters ?? [];
+ const name = params.length
+ ? `[${params
+ .map(param => `${param.name}: ${ctx.partials.someType(param.type)}`)
+ .join(', ')}]`
+ : 'index';
+
+ return ctx.helpers.typedListItem({
+ name,
+ type: model.type,
+ comment: model.comment,
+ });
+ },
+
+ memberWithGroups(model, options) {
+ const md = [];
+ const stability = ctx.helpers.stabilityBlockquote(model.comment);
+
+ if (stability) md.push(stability);
+
+ if (model.kind === ReflectionKind.TypeAlias) {
+ md.push(ctx.partials.declarationTitle(model));
+ }
+
+ if (model.comment) {
+ md.push(
+ ctx.partials.comment(model.comment, {
+ headingLevel: options.headingLevel,
+ showTags: false,
+ })
+ );
+ }
+
+ if (model.typeHierarchy?.next) {
+ md.push(
+ ctx.partials.hierarchy(model.typeHierarchy, {
+ headingLevel: options.headingLevel,
+ })
+ );
+ }
+
+ if (model.typeParameters?.length) {
+ md.push(
+ heading(
+ options.headingLevel,
+ ReflectionKind.pluralString(ReflectionKind.TypeParameter)
+ )
+ );
+ md.push(
+ ctx.partials.typeParametersList(model.typeParameters, {
+ headingLevel: options.headingLevel,
+ })
+ );
+ }
+
+ if (model.implementedTypes?.length) {
+ md.push(heading(options.headingLevel, i18n.theme_implements()));
+ md.push(
+ model.implementedTypes
+ .map(type => `* ${ctx.partials.someType(type)}`)
+ .join('\n')
+ );
+ }
+
+ if (model.kind === ReflectionKind.Class && model.categories?.length) {
+ model.groups
+ ?.filter(group => group.title === i18n.kind_plural_constructor())
+ .forEach(group => {
+ md.push(
+ heading(options.headingLevel, i18n.kind_plural_constructor())
+ );
+ group.children.forEach(child => {
+ md.push(
+ ctx.partials.constructor(child, {
+ headingLevel: options.headingLevel + 1,
+ })
+ );
+ });
+ });
+ }
+
+ if (model.signatures?.length) {
+ const multipleSignatures = model.signatures.length > 1;
+ model.signatures.forEach(signature => {
+ if (multipleSignatures) {
+ md.push(heading(options.headingLevel, i18n.kind_call_signature()));
+ }
+ md.push(
+ ctx.partials.signature(signature, {
+ headingLevel: multipleSignatures
+ ? options.headingLevel + 1
+ : options.headingLevel,
+ multipleSignatures,
+ })
+ );
+ });
+ }
+
+ if (model.indexSignatures?.length) {
+ md.push(heading(options.headingLevel, i18n.theme_indexable()));
+ model.indexSignatures.forEach(indexSignature => {
+ md.push(
+ ctx.partials.indexSignature(indexSignature, {
+ headingLevel: options.headingLevel + 1,
+ })
+ );
+ });
+ }
+
+ md.push(ctx.partials.body(model, { headingLevel: options.headingLevel }));
+ return md.filter(x => typeof x === 'string' || Boolean(x)).join('\n\n');
+ },
+
+ constructor(model, options) {
+ const md = [];
+ const heading = '#'.repeat(options.headingLevel);
+
+ model.signatures?.forEach(signature => {
+ md.push(`${heading} ${getConstructorTitle(model, signature)}`);
+ md.push(
+ ctx.partials.signature(signature, {
+ headingLevel: options.headingLevel + 1,
+ hideTypeParameters: true,
+ })
+ );
+ });
+ return md.join('\n\n');
+ },
+
+ memberTitle: model =>
+ getMemberTitle(model, { local: isTypePage(ctx.page.model) }),
+ parametersList: ctx.helpers.typedList,
+ typeDeclarationList: ctx.helpers.typedList,
+ propertiesTable: ctx.helpers.typedList,
+
+ typeParametersList: () => '',
+ };
+};
diff --git a/plugins/theme/router.mjs b/plugins/theme/router.mjs
deleted file mode 100644
index 339ff1d7..00000000
--- a/plugins/theme/router.mjs
+++ /dev/null
@@ -1,72 +0,0 @@
-import createNodeSlugger from '@node-core/doc-kit/src/generators/metadata/utils/slugger.mjs';
-import { Reflection, ReflectionKind } from 'typedoc';
-import { ModuleRouter } from 'typedoc-plugin-markdown';
-import { getMemberTitle } from './partials/index.mjs';
-
-const sluggers = new Map([]);
-
-export class DocKitRouter extends ModuleRouter {
- /** @param {import('typedoc').RouterTarget} pageTarget */
- getSlugger(pageTarget) {
- if (sluggers.has(pageTarget)) {
- return sluggers.get(pageTarget);
- } else {
- const slugger = createNodeSlugger();
- sluggers.set(pageTarget, slugger);
- return slugger;
- }
- }
-
- /** @param {import('typedoc').RouterTarget} target */
- getAnchoredURL(target) {
- const anchor = this.getAnchor(target);
- const [page] = this.getFullUrl(target).split('#');
-
- return anchor ? `${page}#${anchor}` : page;
- }
-
- /**
- * @param {import('typedoc').RouterTarget} target
- * @param {import('typedoc').RouterTarget} pageTarget
- */
- buildAnchors(target, pageTarget) {
- if (
- !(target instanceof Reflection) ||
- !(pageTarget instanceof Reflection)
- ) {
- return;
- }
-
- if (
- !target.isDeclaration() &&
- !target.isSignature() &&
- !target.isTypeParameter()
- ) {
- return;
- }
-
- if (
- target.kindOf(ReflectionKind.TypeLiteral) &&
- (!target.parent?.kindOf(ReflectionKind.SomeExport) ||
- target.parent.type?.type !== 'reflection')
- ) {
- return;
- }
-
- if (!target.kindOf(ReflectionKind.TypeLiteral)) {
- const title = getMemberTitle(target);
- const anchor = this.getSlugger(pageTarget).slug(title);
-
- this.fullUrls.set(
- target,
- `${this.fullUrls.get(pageTarget).replace(/\.md$/, '.html')}#${anchor}`
- );
- this.anchors.set(target, anchor);
- }
-
- target.traverse(child => {
- this.buildAnchors(child, pageTarget);
- return true;
- });
- }
-}
diff --git a/scripts/markdown.mjs b/scripts/markdown.mjs
index 0bcc2064..6a094891 100644
--- a/scripts/markdown.mjs
+++ b/scripts/markdown.mjs
@@ -9,20 +9,24 @@ const app = await Application.bootstrapWithPlugins({
// Plugins
plugin: [
'typedoc-plugin-markdown',
- './plugins/processor.mjs',
+ './plugins/processor/index.mjs',
'./plugins/theme/index.mjs',
],
theme: 'doc-kit',
router: 'doc-kit',
+ publicPath: '/',
// Formatting
hideGroupHeadings: true,
hideBreadcrumbs: true,
hidePageHeader: true,
+ readme: 'none',
disableSources: true,
propertiesFormat: 'table',
+ membersWithOwnFile: ['Class'],
modulesFileName: 'index',
+ entryFileName: 'index',
tsconfig: 'tsconfig.json',
});