From 8f76a6b14cb5093947099d53c39f4fa072586645 Mon Sep 17 00:00:00 2001 From: jay7tech Date: Sun, 22 Mar 2026 10:49:09 +0530 Subject: [PATCH 1/3] fix(theme): preserve TypeScript semantics in type resolver --- plugins/theme/partials/types.mjs | 68 +++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/plugins/theme/partials/types.mjs b/plugins/theme/partials/types.mjs index ad23e02..6095e31 100644 --- a/plugins/theme/partials/types.mjs +++ b/plugins/theme/partials/types.mjs @@ -1,11 +1,14 @@ -const union = (arr) => (arr?.length ? arr.map(resolve).join("|") : "unknown"); - const resolve = (type) => { if (!type) return "unknown"; switch (type.type) { case "intrinsic": + return type.name; + case "reference": + if (type.typeArguments?.length) { + return `${type.name}<${type.typeArguments.map(resolve).join(", ")}>`; + } return type.name; case "literal": @@ -14,37 +17,74 @@ const resolve = (type) => { : String(type.value); case "array": - return resolve(type.elementType) + "[]"; + return `${resolve(type.elementType)}[]`; case "tuple": - return union(type.elements); + return `[${type.elements?.map(resolve).join(", ") ?? ""}]`; + + case "named-tuple-member": + return type.name + ? `${type.name}${type.isOptional ? "?" : ""}: ${resolve(type.element)}` + : resolve(type.element); case "union": + return type.types?.map(resolve).join(" | ") ?? "unknown"; + case "intersection": - return union(type.types); + return type.types?.map(resolve).join(" & ") ?? "unknown"; case "optional": + return `${resolve(type.elementType)}?`; + case "indexedAccess": - return resolve(type.elementType ?? type.objectType); + return `${resolve(type.objectType)}[${resolve(type.indexType)}]`; case "query": - return resolve(type.queryType); + return `typeof ${resolve(type.queryType)}`; case "typeOperator": - return resolve(type.target); + return type.operator + ? `${type.operator} ${resolve(type.target)}` + : resolve(type.target); case "conditional": - return `${resolve(type.trueType)}|${resolve(type.falseType)}`; + return `${resolve(type.checkType)} extends ${resolve(type.extendsType)} ? ${resolve(type.trueType)} : ${resolve(type.falseType)}`; + + case "reflection": { + const decl = type.declaration; + if (decl?.signatures?.length) { + const sig = decl.signatures[0]; + const params = (sig.parameters ?? []) + .map((p) => `${p.name}: ${resolve(p.type)}`) + .join(", "); + return `(${params}) => ${sig.type ? resolve(sig.type) : "void"}`; + } + if (decl?.children?.length) { + const props = decl.children + .map((c) => `${c.name}${c.flags?.isOptional ? "?" : ""}: ${resolve(c.type)}`) + .join("; "); + return `{ ${props} }`; + } + return "object"; + } - case "named-tuple-member": - return resolve(type.element); + case "predicate": + return type.targetType + ? `${type.name} is ${resolve(type.targetType)}` + : `${type.name} is unknown`; - case "reflection": - return "object"; + case "rest": + return `...${resolve(type.elementType)}`; case "inferred": + return type.name ? `infer ${type.name}` : "unknown"; + + case "template-literal": + case "mapped": + return "object"; + case "unknown": - return "unknown"; + return type.name ?? "unknown"; default: return type.name ?? "unknown"; From 22e16bbd3b71b351788232742a82f5b083e7fb25 Mon Sep 17 00:00:00 2001 From: jay7tech Date: Sun, 22 Mar 2026 10:49:09 +0530 Subject: [PATCH 2/3] fix(generate-md): add guard for missing webpack sibling checkout --- generate-md.mjs | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/generate-md.mjs b/generate-md.mjs index b9bf048..b02348d 100644 --- a/generate-md.mjs +++ b/generate-md.mjs @@ -1,12 +1,27 @@ import { Application } from "typedoc"; -import webpack from "./webpack/package.json" with { type: "json" }; +import { existsSync } from "node:fs"; +import { join } from "node:path"; import { major } from "semver"; +const webpackDir = join(import.meta.dirname, "webpack"); + +if (!existsSync(webpackDir)) { + console.error( + `[webpack-doc-kit] Missing sibling webpack checkout at ${webpackDir}\n` + + ` git clone https://github.com/webpack/webpack.git ../webpack\n` + + ` cd ../webpack && git checkout $(cat ../webpack-doc-kit/HEAD_COMMIT)`, + ); + process.exit(1); +} + +const { default: webpack } = await import("./webpack/package.json", { + with: { type: "json" }, +}); + const app = await Application.bootstrapWithPlugins({ - entryPoints: ["./webpack/types.d.ts"], + entryPoints: [join(webpackDir, "types.d.ts")], out: `pages/v${major(webpack.version)}.x`, - // Plugins plugin: [ "typedoc-plugin-markdown", "./plugins/processor.mjs", @@ -14,7 +29,6 @@ const app = await Application.bootstrapWithPlugins({ ], theme: "doc-kit", - // Formatting hideGroupHeadings: true, hideBreadcrumbs: true, hidePageHeader: true, @@ -28,6 +42,9 @@ const app = await Application.bootstrapWithPlugins({ const project = await app.convert(); -if (project) { - await app.generateOutputs(project); +if (!project) { + console.error("[webpack-doc-kit] TypeDoc failed to convert the project."); + process.exit(1); } + +await app.generateOutputs(project); From 704d0eefcf5a431cbaf6c248aff2312e065f6f35 Mon Sep 17 00:00:00 2001 From: jay7tech Date: Sun, 22 Mar 2026 11:24:44 +0530 Subject: [PATCH 3/3] refactor(theme): map tuples to Tuple and drop unsupported AST forms based on review --- generate-md.mjs | 29 +++------------ plugins/theme/partials/types.mjs | 64 ++++++++------------------------ 2 files changed, 22 insertions(+), 71 deletions(-) diff --git a/generate-md.mjs b/generate-md.mjs index b02348d..b9bf048 100644 --- a/generate-md.mjs +++ b/generate-md.mjs @@ -1,27 +1,12 @@ import { Application } from "typedoc"; -import { existsSync } from "node:fs"; -import { join } from "node:path"; +import webpack from "./webpack/package.json" with { type: "json" }; import { major } from "semver"; -const webpackDir = join(import.meta.dirname, "webpack"); - -if (!existsSync(webpackDir)) { - console.error( - `[webpack-doc-kit] Missing sibling webpack checkout at ${webpackDir}\n` + - ` git clone https://github.com/webpack/webpack.git ../webpack\n` + - ` cd ../webpack && git checkout $(cat ../webpack-doc-kit/HEAD_COMMIT)`, - ); - process.exit(1); -} - -const { default: webpack } = await import("./webpack/package.json", { - with: { type: "json" }, -}); - const app = await Application.bootstrapWithPlugins({ - entryPoints: [join(webpackDir, "types.d.ts")], + entryPoints: ["./webpack/types.d.ts"], out: `pages/v${major(webpack.version)}.x`, + // Plugins plugin: [ "typedoc-plugin-markdown", "./plugins/processor.mjs", @@ -29,6 +14,7 @@ const app = await Application.bootstrapWithPlugins({ ], theme: "doc-kit", + // Formatting hideGroupHeadings: true, hideBreadcrumbs: true, hidePageHeader: true, @@ -42,9 +28,6 @@ const app = await Application.bootstrapWithPlugins({ const project = await app.convert(); -if (!project) { - console.error("[webpack-doc-kit] TypeDoc failed to convert the project."); - process.exit(1); +if (project) { + await app.generateOutputs(project); } - -await app.generateOutputs(project); diff --git a/plugins/theme/partials/types.mjs b/plugins/theme/partials/types.mjs index 6095e31..db3729f 100644 --- a/plugins/theme/partials/types.mjs +++ b/plugins/theme/partials/types.mjs @@ -5,27 +5,27 @@ const resolve = (type) => { case "intrinsic": return type.name; + case "literal": + return typeof type.value === "string" + ? JSON.stringify(type.value) + : String(type.value); + case "reference": + // Preserve generics as doc-kit natively supports them if (type.typeArguments?.length) { return `${type.name}<${type.typeArguments.map(resolve).join(", ")}>`; } return type.name; - case "literal": - return typeof type.value === "string" - ? JSON.stringify(type.value) - : String(type.value); - case "array": return `${resolve(type.elementType)}[]`; case "tuple": - return `[${type.elements?.map(resolve).join(", ") ?? ""}]`; + // Rewrite tuples to Generic representation to satisfy doc-kit limitations + return `Tuple<${type.elements?.map(resolve).join(", ") ?? ""}>`; case "named-tuple-member": - return type.name - ? `${type.name}${type.isOptional ? "?" : ""}: ${resolve(type.element)}` - : resolve(type.element); + return resolve(type.element); case "union": return type.types?.map(resolve).join(" | ") ?? "unknown"; @@ -33,52 +33,20 @@ const resolve = (type) => { case "intersection": return type.types?.map(resolve).join(" & ") ?? "unknown"; + // Revert all advanced type forms to doc-kit safe fallbacks case "optional": - return `${resolve(type.elementType)}?`; + return resolve(type.elementType || type.objectType); case "indexedAccess": - return `${resolve(type.objectType)}[${resolve(type.indexType)}]`; - - case "query": - return `typeof ${resolve(type.queryType)}`; + return resolve(type.objectType); case "typeOperator": - return type.operator - ? `${type.operator} ${resolve(type.target)}` - : resolve(type.target); + return resolve(type.target); case "conditional": - return `${resolve(type.checkType)} extends ${resolve(type.extendsType)} ? ${resolve(type.trueType)} : ${resolve(type.falseType)}`; - - case "reflection": { - const decl = type.declaration; - if (decl?.signatures?.length) { - const sig = decl.signatures[0]; - const params = (sig.parameters ?? []) - .map((p) => `${p.name}: ${resolve(p.type)}`) - .join(", "); - return `(${params}) => ${sig.type ? resolve(sig.type) : "void"}`; - } - if (decl?.children?.length) { - const props = decl.children - .map((c) => `${c.name}${c.flags?.isOptional ? "?" : ""}: ${resolve(c.type)}`) - .join("; "); - return `{ ${props} }`; - } - return "object"; - } - - case "predicate": - return type.targetType - ? `${type.name} is ${resolve(type.targetType)}` - : `${type.name} is unknown`; - - case "rest": - return `...${resolve(type.elementType)}`; - - case "inferred": - return type.name ? `infer ${type.name}` : "unknown"; + return `${resolve(type.trueType)} | ${resolve(type.falseType)}`; + case "reflection": case "template-literal": case "mapped": return "object"; @@ -87,7 +55,7 @@ const resolve = (type) => { return type.name ?? "unknown"; default: - return type.name ?? "unknown"; + return "unknown"; } };