Skip to content

Commit

Permalink
Support TypeScript 5.7, drop TS <5.0
Browse files Browse the repository at this point in the history
Also fix readonly index signatures.
  • Loading branch information
Gerrit0 committed Nov 9, 2024
1 parent 6aff5d6 commit 70491cc
Show file tree
Hide file tree
Showing 15 changed files with 572 additions and 226 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ title: Changelog

## Breaking Changes

- Drop support for TypeScript <5.0, no longer supported by DefinitelyTyped
- Relaxed requirements for file names and generated url fragments. This may
result in a different file name structure, #2714.
- Anchors to document headings and reflections within a HTML generated pages
Expand All @@ -30,6 +31,7 @@ title: Changelog

## Features

- Add support for TypeScript 5.7
- TypeDoc will now discover entry points from `package.json` exports if they
are not provided manually, #1937.
- Relative links to markdown files may now include `#anchor` links to
Expand Down Expand Up @@ -79,6 +81,7 @@ title: Changelog

## Bug Fixes

- TypeDoc now properly flags `readonly` index signatures.
- TypeDoc will now use the first signature's comment for later signatures in
overloads if present, #2718.
- Fixed handling of `@enum` if the type was declared before the variable, #2719.
Expand Down
3 changes: 3 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ const config = {
parserOptions: {
project: true,
tsconfigRootDir: import.meta.dirname,
// We're fairly frequently on a later version of the TS compiler than
// is officially supported. So far this has never been a real problem.
warnOnUnsupportedTypeScriptVersion: false,
},
},
rules: {
Expand Down
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"yaml": "^2.6.0"
},
"peerDependencies": {
"typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x"
"typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x"
},
"devDependencies": {
"@types/lunr": "^2.3.7",
Expand All @@ -49,7 +49,7 @@
"puppeteer": "^23.6.1",
"semver": "^7.6.3",
"tsx": "^4.19.2",
"typescript": "5.6.3",
"typescript": "5.7.1-rc",
"typescript-eslint": "^8.12.2"
},
"files": [
Expand Down
2 changes: 1 addition & 1 deletion site/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ support more versions of TypeScript.

| TypeDoc Version | TypeScript Version |
| --------------- | ------------------ |
| 0.27 | 4.6 through 5.7 |
| 0.27 | 5.0 through 5.7 |
| 0.26 | 4.6 through 5.6 |
| 0.25 | 4.6 through 5.4 |
| 0.24 | 4.6 through 5.1 |
Expand Down
73 changes: 57 additions & 16 deletions src/lib/converter/factories/index-signature.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,97 @@
import assert from "assert";
import ts from "typescript";
import type ts from "typescript";
import {
DeclarationReflection,
ParameterReflection,
ReflectionFlag,
ReflectionKind,
SignatureReflection,
UnionType,
} from "../../models/index.js";
import type { Context } from "../context.js";
import { ConverterEvents } from "../converter-events.js";

export function convertIndexSignatures(context: Context, symbol: ts.Symbol) {
export function convertIndexSignatures(context: Context, type: ts.Type) {
assert(context.scope instanceof DeclarationReflection);

const indexSymbol = symbol.members?.get("__index" as ts.__String);
if (!indexSymbol) return;
// Each declaration should have one SignatureReflection
// If we don't have a declaration, the index signature was inferred by TS
// and we should make a separate SignatureReflection for each index signature.
const seenByDeclaration = new Map<ts.Declaration, SignatureReflection>();
const createdSignatures: [
ts.IndexSignatureDeclaration | undefined,
SignatureReflection,
][] = [];

for (const indexDeclaration of indexSymbol.getDeclarations() || []) {
assert(ts.isIndexSignatureDeclaration(indexDeclaration));
const param = indexDeclaration.parameters[0] as
| ts.ParameterDeclaration
| undefined;
assert(param && ts.isParameter(param));
for (const indexInfo of context.checker.getIndexInfosOfType(type)) {
// Check if we've already created an index signature for this type
if (
indexInfo.declaration &&
seenByDeclaration.has(indexInfo.declaration)
) {
const createdSig = seenByDeclaration.get(indexInfo.declaration)!;
if (createdSig.parameters![0].type?.type !== "union") {
createdSig.parameters![0].type = new UnionType([
createdSig.parameters![0].type!,
]);
}
createdSig.parameters![0].type.types.push(
context.converter.convertType(
context.withScope(createdSig),
indexInfo.keyType,
),
);
// No need to update the return type as it will be the same for all members.
continue;
}

// Otherwise create a new one
const index = new SignatureReflection(
"__index",
ReflectionKind.IndexSignature,
context.scope,
);
index.comment = context.getNodeComment(indexDeclaration, false);
if (indexInfo.isReadonly) {
index.setFlag(ReflectionFlag.Readonly);
}

createdSignatures.push([indexInfo.declaration, index]);
if (indexInfo.declaration) {
seenByDeclaration.set(indexInfo.declaration, index);
index.comment = context.getNodeComment(
indexInfo.declaration,
/* moduleComment */ false,
);
}

index.parameters = [
new ParameterReflection(
param.name.getText(),
indexInfo.declaration?.parameters[0].name.getText() ?? "key",
ReflectionKind.Parameter,
index,
),
];
index.parameters[0].type = context.converter.convertType(
context.withScope(index.parameters[0]),
param.type,
indexInfo.keyType,
);
index.type = context.converter.convertType(
context.withScope(index),
indexDeclaration.type,
indexInfo.type,
);
context.registerReflection(index, indexSymbol);

context.registerReflection(index, indexInfo.declaration?.symbol);
context.scope.indexSignatures ||= [];
context.scope.indexSignatures.push(index);
}

// Now that we've created everything, trigger events for them.
for (const [declaration, index] of createdSignatures) {
context.converter.trigger(
ConverterEvents.CREATE_SIGNATURE,
context,
index,
indexDeclaration,
declaration,
);
}
}
4 changes: 2 additions & 2 deletions src/lib/converter/symbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ function convertTypeAliasAsInterface(
convertConstructSignatures(rc, symbol);

// And finally, index signatures
convertIndexSignatures(rc, symbol);
convertIndexSignatures(rc, type);
}

function convertFunctionOrMethod(
Expand Down Expand Up @@ -674,7 +674,7 @@ function convertClassOrInterface(
convertConstructSignatures(reflectionContext, symbol);

// And finally, index signatures
convertIndexSignatures(reflectionContext, symbol);
convertIndexSignatures(reflectionContext, instanceType);

// Normally this shouldn't matter, unless someone did something with skipLibCheck on.
return ts.SymbolFlags.Alias;
Expand Down
4 changes: 2 additions & 2 deletions src/lib/converter/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ const typeLiteralConverter: TypeConverter<ts.TypeLiteralNode> = {
);
}

convertIndexSignatures(rc, symbol);
convertIndexSignatures(rc, type);

return new ReflectionType(reflection);
},
Expand Down Expand Up @@ -670,7 +670,7 @@ const typeLiteralConverter: TypeConverter<ts.TypeLiteralNode> = {
}

if (symbol) {
convertIndexSignatures(context.withScope(reflection), symbol);
convertIndexSignatures(context.withScope(reflection), type);
}

return new ReflectionType(reflection);
Expand Down
10 changes: 10 additions & 0 deletions src/lib/output/formatter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,16 @@ export class FormattedCodeBuilder {
for (const index of reflection.indexSignatures) {
members.push(
nodes(
...(index.flags.isReadonly
? [
simpleElement(
<span class="tsd-signature-keyword">
readonly
</span>,
),
space(),
]
: []),
simpleElement(
<span class="tsd-signature-symbol">[</span>,
),
Expand Down
1 change: 1 addition & 0 deletions src/lib/output/themes/default/partials/typeDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ function renderIndexSignature(context: DefaultThemeRenderContext, index: Signatu
return (
<li class="tsd-parameter-index-signature">
<h5>
{index.flags.isReadonly && <span class="tsd-signature-keyword">readonly </span>}
<span class="tsd-signature-symbol">[</span>
{index.parameters!.map((item) => (
<>
Expand Down
1 change: 1 addition & 0 deletions src/lib/output/themes/default/templates/reflection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ function renderIndexSignature(context: DefaultThemeRenderContext, index: Signatu
return (
<li class="tsd-index-signature">
<div class="tsd-signature">
{index.flags.isReadonly && <span class="tsd-signature-keyword">readonly </span>}
<span class="tsd-signature-symbol">[</span>
{index.parameters!.map((item) => (
<>
Expand Down
4 changes: 3 additions & 1 deletion src/lib/utils/jsx.elements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,9 @@ export interface IntrinsicElements {
text: JsxTextElementProps;
}

export const JsxFragment: unique symbol = Symbol();
export function JsxFragment(): never {
throw new Error("Should never be called");
}

export type JsxComponent<P> = (props: P) => JsxElement | null | undefined;

Expand Down
Loading

0 comments on commit 70491cc

Please sign in to comment.