Skip to content

Commit

Permalink
fix: Properly resolve type parameters
Browse files Browse the repository at this point in the history
Closes #1438
  • Loading branch information
Gerrit0 committed Jan 1, 2021
1 parent 1153735 commit 60b6506
Show file tree
Hide file tree
Showing 10 changed files with 65 additions and 40 deletions.
13 changes: 13 additions & 0 deletions src/lib/converter/context.ts
Expand Up @@ -59,6 +59,18 @@ export class Context {
*/
readonly scope: Reflection;

/** @internal */
isConvertingTypeNode(): boolean {
return this.convertingTypeNode;
}

/** @internal */
setConvertingTypeNode() {
this.convertingTypeNode = true;
}

private convertingTypeNode = false;

/**
* Create a new Context instance.
*
Expand Down Expand Up @@ -231,6 +243,7 @@ export class Context {
this.project,
scope
);
context.convertingTypeNode = this.convertingTypeNode;
context.setActiveProgram(this._program);
return context;
}
Expand Down
4 changes: 2 additions & 2 deletions src/lib/converter/symbols.ts
Expand Up @@ -200,7 +200,7 @@ function convertTypeAlias(
);

reflection.type = context.converter.convertType(
context,
context.withScope(reflection),
declaration.type
);

Expand Down Expand Up @@ -550,7 +550,7 @@ function convertProperty(
// parent node. This will probably break in a future TS version.
reflection.type = context.converter.convertType(
context,
parameterType ??
(context.isConvertingTypeNode() ? parameterType : void 0) ??
context.checker.getTypeOfSymbolAtLocation(symbol, {} as any)
);
}
Expand Down
37 changes: 22 additions & 15 deletions src/lib/converter/types.ts
Expand Up @@ -124,6 +124,7 @@ export function convertType(
if (symbol) {
if (
node.kind !== ts.SyntaxKind.TypeReference &&
node.kind !== ts.SyntaxKind.ArrayType &&
seenTypeSymbols.has(symbol)
) {
const typeString = context.checker.typeToString(typeOrNode);
Expand Down Expand Up @@ -196,6 +197,9 @@ const constructorConverter: TypeConverter<ts.ConstructorTypeNode, ts.Type> = {
ReflectionKind.Constructor,
context.scope
);
const rc = context.withScope(reflection);
rc.setConvertingTypeNode();

context.registerReflection(reflection, symbol);
context.trigger(ConverterEvents.CREATE_DECLARATION, reflection, node);

Expand All @@ -205,7 +209,7 @@ const constructorConverter: TypeConverter<ts.ConstructorTypeNode, ts.Type> = {
reflection
);
context.registerReflection(signature, void 0);
const signatureCtx = context.withScope(signature);
const signatureCtx = rc.withScope(signature);

reflection.signatures = [signature];
signature.type = convertType(signatureCtx, node.type);
Expand All @@ -215,7 +219,7 @@ const constructorConverter: TypeConverter<ts.ConstructorTypeNode, ts.Type> = {
node.parameters
);
signature.typeParameters = convertTypeParameterNodes(
context.withScope(reflection),
signatureCtx,
node.typeParameters
);

Expand Down Expand Up @@ -287,6 +291,8 @@ const functionTypeConverter: TypeConverter<ts.FunctionTypeNode, ts.Type> = {
ReflectionKind.TypeLiteral,
context.scope
);
const rc = context.withScope(reflection);

context.registerReflection(reflection, symbol);
context.trigger(ConverterEvents.CREATE_DECLARATION, reflection, node);

Expand All @@ -296,7 +302,7 @@ const functionTypeConverter: TypeConverter<ts.FunctionTypeNode, ts.Type> = {
reflection
);
context.registerReflection(signature, void 0);
const signatureCtx = context.withScope(signature);
const signatureCtx = rc.withScope(signature);

reflection.signatures = [signature];
signature.type = convertType(signatureCtx, node.type);
Expand All @@ -306,7 +312,7 @@ const functionTypeConverter: TypeConverter<ts.FunctionTypeNode, ts.Type> = {
node.parameters
);
signature.typeParameters = convertTypeParameterNodes(
context.withScope(reflection),
signatureCtx,
node.typeParameters
);

Expand Down Expand Up @@ -468,24 +474,23 @@ const typeLiteralConverter: TypeConverter<ts.TypeLiteralNode> = {
ReflectionKind.TypeLiteral,
context.scope
);
const rc = context.withScope(reflection);
rc.setConvertingTypeNode();

context.registerReflection(reflection, symbol);
context.trigger(ConverterEvents.CREATE_DECLARATION, reflection, node);

for (const prop of context.checker.getPropertiesOfType(type)) {
convertSymbol(context.withScope(reflection), prop);
convertSymbol(rc, prop);
}
for (const signature of type.getCallSignatures()) {
reflection.signatures ??= [];
reflection.signatures.push(
createSignature(
context.withScope(reflection),
ReflectionKind.CallSignature,
signature
)
createSignature(rc, ReflectionKind.CallSignature, signature)
);
}

convertIndexSignature(context.withScope(reflection), symbol);
convertIndexSignature(rc, symbol);

return new ReflectionType(reflection);
},
Expand Down Expand Up @@ -575,10 +580,12 @@ const referenceConverter: TypeConverter<
convertType(context, type) {
const symbol = type.aliasSymbol ?? type.getSymbol();
if (!symbol) {
// If we get in here, the user is doing something bad. Probably using mixins.
const broken = new UnknownType(context.checker.typeToString(type));
context.logger.warn(`Bad reference type: ${broken.name}`);
return broken;
// This happens when we get a reference to a type parameter
// created within a mapped type, `K` in: `{ [K in T]: string }`
return ReferenceType.createBrokenReference(
context.checker.typeToString(type),
context.project
);
}

const ref = new ReferenceType(
Expand Down
17 changes: 11 additions & 6 deletions src/lib/models/types/reference.ts
Expand Up @@ -33,11 +33,11 @@ export class ReferenceType extends Type {
* The resolved reflection.
*/
get reflection() {
if (this._target instanceof Reflection) {
return this._target;
if (typeof this._target === "number") {
return this._project.getReflectionById(this._target);
}
const resolved = this._project.getReflectionFromSymbol(this._target);
if (resolved) this._target = resolved;
if (resolved) this._target = resolved.id;
return resolved;
}

Expand All @@ -47,23 +47,28 @@ export class ReferenceType extends Type {
*/
getReflection = () => this.reflection;

private _target: ts.Symbol | Reflection;
private _target: ts.Symbol | number;
private _project: ProjectReflection;

/**
* Create a new instance of ReferenceType.
*/
constructor(
name: string,
target: ts.Symbol | Reflection,
target: ts.Symbol | Reflection | number,
project: ProjectReflection
) {
super();
this.name = name;
this._target = target;
this._target = target instanceof Reflection ? target.id : target;
this._project = project;
}

/** @internal this is used for type parameters, which don't actually point to something */
static createBrokenReference(name: string, project: ProjectReflection) {
return new ReferenceType(name, -1, project);
}

/**
* Clone this type.
*
Expand Down
8 changes: 4 additions & 4 deletions src/test/converter/class/specs-with-lump-categories.json
Expand Up @@ -2905,8 +2905,8 @@
"shortText": "Generic property."
},
"type": {
"type": "reference",
"name": "T"
"type": "intrinsic",
"name": "string"
},
"inheritedFrom": {
"type": "reference",
Expand All @@ -2928,8 +2928,8 @@
"type": {
"type": "array",
"elementType": {
"type": "reference",
"name": "T"
"type": "intrinsic",
"name": "string"
}
},
"inheritedFrom": {
Expand Down
8 changes: 4 additions & 4 deletions src/test/converter/class/specs.json
Expand Up @@ -2901,8 +2901,8 @@
"shortText": "Generic property."
},
"type": {
"type": "reference",
"name": "T"
"type": "intrinsic",
"name": "string"
},
"inheritedFrom": {
"type": "reference",
Expand All @@ -2924,8 +2924,8 @@
"type": {
"type": "array",
"elementType": {
"type": "reference",
"name": "T"
"type": "intrinsic",
"name": "string"
}
},
"inheritedFrom": {
Expand Down
8 changes: 4 additions & 4 deletions src/test/converter/types/specs.json
Expand Up @@ -880,6 +880,10 @@
"elementType": {
"type": "union",
"types": [
{
"type": "intrinsic",
"name": "string"
},
{
"type": "array",
"elementType": {
Expand All @@ -897,10 +901,6 @@
}
]
}
},
{
"type": "intrinsic",
"name": "string"
}
]
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/renderer/specs/classes/classes.baseclass.html
Expand Up @@ -179,7 +179,7 @@ <h2>Properties</h2>
<section class="tsd-panel tsd-member tsd-kind-property tsd-parent-kind-class tsd-is-private">
<a name="internalclass" class="tsd-anchor"></a>
<h3><span class="tsd-flag ts-flagPrivate">Private</span> internal<wbr>Class</h3>
<div class="tsd-signature tsd-kind-icon">internal<wbr>Class<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">InternalClass</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-symbol">keyof </span><a href="classes.baseclass.html" class="tsd-signature-type" data-tsd-kind="Class">BaseClass</a><span class="tsd-signature-symbol">&gt;</span></div>
<div class="tsd-signature tsd-kind-icon">internal<wbr>Class<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">InternalClass</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">&quot;name&quot;</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">&quot;abstractMethod&quot;</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">&quot;getName&quot;</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">&quot;setName&quot;</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">&quot;arrowFunction&quot;</span><span class="tsd-signature-symbol">&gt;</span></div>
<aside class="tsd-sources">
</aside>
<div class="tsd-comment tsd-typography">
Expand Down
4 changes: 2 additions & 2 deletions src/test/renderer/specs/classes/classes.nongenericclass.html
Expand Up @@ -178,7 +178,7 @@ <h2>Properties</h2>
<section class="tsd-panel tsd-member tsd-kind-property tsd-parent-kind-class tsd-is-inherited tsd-is-protected">
<a name="p2" class="tsd-anchor"></a>
<h3><span class="tsd-flag ts-flagProtected">Protected</span> p2</h3>
<div class="tsd-signature tsd-kind-icon">p2<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">T</span></div>
<div class="tsd-signature tsd-kind-icon">p2<span class="tsd-signature-symbol">:</span> <a href="classes.subclassb.html" class="tsd-signature-type" data-tsd-kind="Class">SubClassB</a></div>
<aside class="tsd-sources">
<p>Inherited from <a href="classes.genericclass.html">GenericClass</a>.<a href="classes.genericclass.html#p2">p2</a></p>
</aside>
Expand All @@ -202,7 +202,7 @@ <h3><span class="tsd-flag ts-flagReadonly">Readonly</span> p5</h3>
<section class="tsd-panel tsd-member tsd-kind-property tsd-parent-kind-class tsd-is-inherited">
<a name="value" class="tsd-anchor"></a>
<h3>value</h3>
<div class="tsd-signature tsd-kind-icon">value<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">T</span></div>
<div class="tsd-signature tsd-kind-icon">value<span class="tsd-signature-symbol">:</span> <a href="classes.subclassb.html" class="tsd-signature-type" data-tsd-kind="Class">SubClassB</a></div>
<aside class="tsd-sources">
<p>Inherited from <a href="classes.genericclass.html">GenericClass</a>.<a href="classes.genericclass.html#value">value</a></p>
</aside>
Expand Down
4 changes: 2 additions & 2 deletions src/test/renderer/specs/modules/mixin.html
Expand Up @@ -126,7 +126,7 @@ <h4>A = <span class="tsd-signature-type">object</span></h4>
<h4>Type declaration</h4>
<ul class="tsd-parameters">
<li class="tsd-parameter-signature">
<ul class="tsd-signatures tsd-kind-constructor tsd-parent-kind-module">
<ul class="tsd-signatures tsd-kind-constructor tsd-parent-kind-type-alias">
<li class="tsd-signature tsd-kind-icon"><span class="tsd-signature-symbol">(</span><span class="tsd-signature-symbol">...</span>input<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">[]</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">A</span></li>
</ul>
<ul class="tsd-descriptions">
Expand Down Expand Up @@ -165,7 +165,7 @@ <h4>A = <span class="tsd-signature-type">any</span></h4>
<h4>Type declaration</h4>
<ul class="tsd-parameters">
<li class="tsd-parameter-signature">
<ul class="tsd-signatures tsd-kind-type-literal tsd-parent-kind-module">
<ul class="tsd-signatures tsd-kind-type-literal tsd-parent-kind-type-alias">
<li class="tsd-signature tsd-kind-icon"><span class="tsd-signature-symbol">(</span><span class="tsd-signature-symbol">...</span>input<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">[]</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">A</span></li>
</ul>
<ul class="tsd-descriptions">
Expand Down

0 comments on commit 60b6506

Please sign in to comment.