From 9c3114d6bedeafc440d294646a0df07a76188ca6 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 28 Dec 2019 16:50:32 -0700 Subject: [PATCH 01/19] fix!: isExported should use the type checker This partially adds support for export declarations under the same name. BREAKING CHANGE: Global files previously had all declarations marked as not-exported. This was inconsistent with TypeScript's concept of visibility. Now non-modules will have all members exported. --- src/lib/converter/context.ts | 15 +++++ src/lib/converter/convert-expression.ts | 5 +- src/lib/converter/factories/declaration.ts | 16 ++--- src/lib/models/reflections/abstract.ts | 13 +++- src/test/converter.test.ts | 9 ++- src/test/converter/array/specs.json | 2 +- .../constructor-properties.ts | 13 ++-- .../constructor-properties/specs.json | 30 +++++----- src/test/converter/decorators/decorators.ts | 17 +++--- src/test/converter/decorators/specs.json | 14 ++--- .../converter/destructuring/destructuring.ts | 7 ++- src/test/converter/destructuring/specs.json | 32 +++++----- .../events-overloads/events-overloads.ts | 15 ++--- .../converter/events-overloads/specs.json | 18 +++--- src/test/converter/events/events.ts | 7 ++- src/test/converter/events/specs.json | 2 +- src/test/converter/function/specs.json | 4 +- .../converter/generic-class/generic-class.ts | 11 ++-- src/test/converter/generic-class/specs.json | 6 +- .../generic-function/generic-function.ts | 7 ++- .../converter/generic-function/specs.json | 2 +- .../converter/getter-setter/getter-setter.ts | 16 ++--- src/test/converter/getter-setter/specs.json | 10 ++-- .../interface-empty/interface-empty.ts | 5 +- src/test/converter/interface-empty/specs.json | 6 +- .../interface-implementation.ts | 60 ++++++++----------- .../interface-implementation/specs.json | 60 +++++++++---------- .../literal-object-callbacks.ts | 2 + .../literal-object/literal-object.ts | 4 +- src/test/converter/literal-object/specs.json | 6 +- .../converter/literal-type/literal-type.ts | 20 ++++--- src/test/converter/literal-type/specs.json | 6 +- .../promise-object/promise-object.ts | 2 + src/test/renderer.test.ts | 3 +- 34 files changed, 236 insertions(+), 209 deletions(-) diff --git a/src/lib/converter/context.ts b/src/lib/converter/context.ts index 6c6365908..93cc657f0 100644 --- a/src/lib/converter/context.ts +++ b/src/lib/converter/context.ts @@ -151,6 +151,14 @@ export class Context { return nodeType; } + getSymbolAtLocation(node: ts.Node): ts.Symbol | undefined { + let symbol = this.checker.getSymbolAtLocation(node); + if (!symbol && isNamedNode(node)) { + symbol = this.checker.getSymbolAtLocation(node.name); + } + return symbol; + } + /** * Return the current logger instance. * @@ -390,3 +398,10 @@ export class Context { return typeParameters; } } + +function isNamedNode(node: ts.Node): node is ts.Node & { name: ts.Identifier | ts.ComputedPropertyName } { + return node.hasOwnProperty('name') && ( + ts.isIdentifier(node['name']) || + ts.isComputedPropertyName(node['name']) + ); +} diff --git a/src/lib/converter/convert-expression.ts b/src/lib/converter/convert-expression.ts index 4a9ad0007..7501f6b83 100644 --- a/src/lib/converter/convert-expression.ts +++ b/src/lib/converter/convert-expression.ts @@ -26,8 +26,9 @@ export function convertExpression(expression: ts.Expression): string { return 'true'; case ts.SyntaxKind.FalseKeyword: return 'false'; + case ts.SyntaxKind.NullKeyword: + return 'null'; default: - const source = expression.getSourceFile(); - return source.text.substring(expression.pos, expression.end); + return expression.getText(expression.getSourceFile()); } } diff --git a/src/lib/converter/factories/declaration.ts b/src/lib/converter/factories/declaration.ts index 59a0c5365..f0c49a1cc 100644 --- a/src/lib/converter/factories/declaration.ts +++ b/src/lib/converter/factories/declaration.ts @@ -71,21 +71,15 @@ export function createDeclaration(context: Context, node: ts.Declaration, kind: // Test whether the node is exported let isExported: boolean; - if (container.kindOf([ReflectionKind.Module, ReflectionKind.ExternalModule])) { - isExported = false; // Don't inherit exported state in modules and namespaces + if (kind === ReflectionKind.ExternalModule || kind === ReflectionKind.Global) { + isExported = true; + } else if (container.kindOf([ReflectionKind.Module, ReflectionKind.ExternalModule])) { + const symbol = context.getSymbolAtLocation(node); + isExported = !!symbol?.parent?.exports?.get(symbol.escapedName); } else { isExported = container.flags.isExported; } - if (kind === ReflectionKind.ExternalModule) { - isExported = true; // Always mark external modules as exported - } else if (node.parent && node.parent.kind === ts.SyntaxKind.VariableDeclarationList) { - const parentModifiers = ts.getCombinedModifierFlags(node.parent.parent as ts.Declaration); - isExported = isExported || !!(parentModifiers & ts.ModifierFlags.Export); - } else { - isExported = isExported || !!(modifiers & ts.ModifierFlags.Export); - } - if (!isExported && context.converter.excludeNotExported) { return; } diff --git a/src/lib/models/reflections/abstract.ts b/src/lib/models/reflections/abstract.ts index 8b14b92bc..dea59c730 100644 --- a/src/lib/models/reflections/abstract.ts +++ b/src/lib/models/reflections/abstract.ts @@ -139,7 +139,18 @@ export class ReflectionFlags extends Array { } /** - * Is this member exported? + * True if the reflection is exported from its containing declaration. Note that if a file + * has no imports or exports, then TS assumes that the file is in a global scope and *all* + * declarations are exported. + * ```ts + * // a.ts + * namespace A { // isExported = false + * export const b = 1 // isExported = true, even though the container is false. + * } + * export const b = 2 // isExported = true + * // b.ts + * const c = 1 // isExported = true, no imports/exports + * ``` */ get isExported(): boolean { return this.hasFlag(ReflectionFlag.Exported); diff --git a/src/test/converter.test.ts b/src/test/converter.test.ts index d198ab6dc..ebb09ae07 100644 --- a/src/test/converter.test.ts +++ b/src/test/converter.test.ts @@ -69,7 +69,8 @@ describe('Converter', function() { module: 'CommonJS', experimentalDecorators: true, jsx: 'react', - name: 'typedoc' + name: 'typedoc', + ignoreCompilerErrors: true }); }); @@ -114,7 +115,8 @@ describe('Converter with categorizeByGroup=false', function() { experimentalDecorators: true, categorizeByGroup: false, jsx: 'react', - name: 'typedoc' + name: 'typedoc', + ignoreCompilerErrors: true }); }); @@ -169,7 +171,8 @@ describe('Converter with excludeNotExported=true', function() { experimentalDecorators: true, excludeNotExported: true, jsx: 'react', - name: 'typedoc' + name: 'typedoc', + ignoreCompilerErrors: true }); }); diff --git a/src/test/converter/array/specs.json b/src/test/converter/array/specs.json index 35919e420..ba7c0ab67 100644 --- a/src/test/converter/array/specs.json +++ b/src/test/converter/array/specs.json @@ -4057,7 +4057,7 @@ } } }, - "defaultValue": " []" + "defaultValue": "[]" }, { "id": 233, diff --git a/src/test/converter/constructor-properties/constructor-properties.ts b/src/test/converter/constructor-properties/constructor-properties.ts index 2763477f5..fe36efff9 100644 --- a/src/test/converter/constructor-properties/constructor-properties.ts +++ b/src/test/converter/constructor-properties/constructor-properties.ts @@ -1,32 +1,31 @@ /** * A class with constructor properties. */ -class Vector2 -{ +class Vector2 { /** * @param x X component of the Vector * @param y Y component of the Vector * @param name Vector name */ - constructor(public x:number, public y:number, + constructor(public x: number, public y: number, readonly name: string) { } } - /** * A class with inherited and overwritten constructor properties. */ -class Vector3 extends Vector2 -{ +class Vector3 extends Vector2 { /** * @param x X component of the Vector * @param y Y component of the Vector * @param z Z component of the Vector * @param name Vector name */ - constructor(x:number, public y:number, public z:number, + constructor(x: number, public y: number, public z: number, readonly name: string) { super(x, y, name); } } + +export {}; diff --git a/src/test/converter/constructor-properties/specs.json b/src/test/converter/constructor-properties/specs.json index 56c969dd9..043f56a93 100644 --- a/src/test/converter/constructor-properties/specs.json +++ b/src/test/converter/constructor-properties/specs.json @@ -93,8 +93,8 @@ "sources": [ { "fileName": "constructor-properties.ts", - "line": 5, - "character": 1 + "line": 4, + "character": 15 } ] }, @@ -112,7 +112,7 @@ "sources": [ { "fileName": "constructor-properties.ts", - "line": 12, + "line": 11, "character": 29 } ], @@ -136,7 +136,7 @@ "sources": [ { "fileName": "constructor-properties.ts", - "line": 11, + "line": 10, "character": 24 } ], @@ -160,8 +160,8 @@ "sources": [ { "fileName": "constructor-properties.ts", - "line": 11, - "character": 41 + "line": 10, + "character": 42 } ], "type": { @@ -301,8 +301,8 @@ "sources": [ { "fileName": "constructor-properties.ts", - "line": 21, - "character": 1 + "line": 18, + "character": 31 } ], "overwrites": { @@ -325,7 +325,7 @@ "sources": [ { "fileName": "constructor-properties.ts", - "line": 29, + "line": 26, "character": 29 } ], @@ -354,7 +354,7 @@ "sources": [ { "fileName": "constructor-properties.ts", - "line": 11, + "line": 10, "character": 24 } ], @@ -383,8 +383,8 @@ "sources": [ { "fileName": "constructor-properties.ts", - "line": 28, - "character": 34 + "line": 25, + "character": 35 } ], "type": { @@ -412,8 +412,8 @@ "sources": [ { "fileName": "constructor-properties.ts", - "line": 28, - "character": 51 + "line": 25, + "character": 53 } ], "type": { @@ -444,7 +444,7 @@ "sources": [ { "fileName": "constructor-properties.ts", - "line": 20, + "line": 18, "character": 13 } ], diff --git a/src/test/converter/decorators/decorators.ts b/src/test/converter/decorators/decorators.ts index 4c6c43abc..a876d2814 100644 --- a/src/test/converter/decorators/decorators.ts +++ b/src/test/converter/decorators/decorators.ts @@ -4,8 +4,7 @@ @decoratorWithOptions({ name: 'Name of class' }) -class DecoratedClass -{ +class DecoratedClass { /** * A decorated method. */ @@ -14,35 +13,33 @@ class DecoratedClass decoratedMethod() { } } - /** * A decorator with no options. */ -function decoratorAtom(target:Object, propertyKey:string|symbol, descriptor:TypedPropertyDescriptor) { +function decoratorAtom(target: Object, propertyKey: string|symbol, descriptor: TypedPropertyDescriptor) { target[propertyKey].writable = true; } - /** * A decorator with a parameter. * * @param value The parameter of this decorator. */ -function decoratorWithParam(value:boolean):MethodDecorator { - return function (target:Object, propertyKey:string|symbol, descriptor:TypedPropertyDescriptor) { +function decoratorWithParam(value: boolean): MethodDecorator { + return function (target: Object, propertyKey: string|symbol, descriptor: TypedPropertyDescriptor) { target[propertyKey].enumerable = value; - } + }; } - /** * A decorator consuming an options object. * * @param options The options object of this decorator. * @param options.name A property on the options object of this decorator. */ -function decoratorWithOptions(options:{name:string}): ClassDecorator { +function decoratorWithOptions(options: {name: string}): ClassDecorator { return function (target) { (target as any).options = options; }; } +export {} diff --git a/src/test/converter/decorators/specs.json b/src/test/converter/decorators/specs.json index 659929283..6f33a3c45 100644 --- a/src/test/converter/decorators/specs.json +++ b/src/test/converter/decorators/specs.json @@ -83,7 +83,7 @@ "sources": [ { "fileName": "decorators.ts", - "line": 14, + "line": 13, "character": 19 } ] @@ -188,7 +188,7 @@ "sources": [ { "fileName": "decorators.ts", - "line": 21, + "line": 19, "character": 22 } ] @@ -247,8 +247,8 @@ "sources": [ { "fileName": "decorators.ts", - "line": 44, - "character": 43 + "line": 40, + "character": 44 } ], "type": { @@ -269,7 +269,7 @@ "sources": [ { "fileName": "decorators.ts", - "line": 44, + "line": 40, "character": 38 } ] @@ -286,7 +286,7 @@ "sources": [ { "fileName": "decorators.ts", - "line": 44, + "line": 40, "character": 29 } ] @@ -339,7 +339,7 @@ "sources": [ { "fileName": "decorators.ts", - "line": 31, + "line": 28, "character": 27 } ] diff --git a/src/test/converter/destructuring/destructuring.ts b/src/test/converter/destructuring/destructuring.ts index 255e7bafb..30fa8963c 100644 --- a/src/test/converter/destructuring/destructuring.ts +++ b/src/test/converter/destructuring/destructuring.ts @@ -1,8 +1,7 @@ /** * Destructuring objects. */ -const {destructObjectA, destructObjectB, destructObjectC} = {destructObjectA:0, destructObjectB:'string', destructObjectC:0}; - +const {destructObjectA, destructObjectB, destructObjectC} = {destructObjectA: 0, destructObjectB: 'string', destructObjectC: 0}; /** * Destructuring arrays. @@ -22,4 +21,6 @@ const [destructArrayWithIgnoresA, , ...destructArrayWithIgnoresRest] = [1, 2, 3, /** * Destructuring function parameters. */ -function drawText({text = "", location:[x, y] = [0, 0], bold = false}) { } +function drawText({text = '', location: [x, y] = [0, 0], bold = false}) { } + +export {}; diff --git a/src/test/converter/destructuring/specs.json b/src/test/converter/destructuring/specs.json index b95cb2571..979a634d6 100644 --- a/src/test/converter/destructuring/specs.json +++ b/src/test/converter/destructuring/specs.json @@ -23,7 +23,7 @@ "sources": [ { "fileName": "destructuring.ts", - "line": 10, + "line": 9, "character": 21 } ], @@ -41,7 +41,7 @@ "sources": [ { "fileName": "destructuring.ts", - "line": 10, + "line": 9, "character": 37 } ], @@ -59,7 +59,7 @@ "sources": [ { "fileName": "destructuring.ts", - "line": 10, + "line": 9, "character": 53 } ], @@ -87,7 +87,7 @@ "sources": [ { "fileName": "destructuring.ts", - "line": 20, + "line": 19, "character": 32 } ], @@ -105,7 +105,7 @@ "sources": [ { "fileName": "destructuring.ts", - "line": 20, + "line": 19, "character": 67 } ], @@ -132,7 +132,7 @@ "sources": [ { "fileName": "destructuring.ts", - "line": 15, + "line": 14, "character": 79 } ], @@ -159,7 +159,7 @@ "sources": [ { "fileName": "destructuring.ts", - "line": 15, + "line": 14, "character": 29 } ], @@ -177,7 +177,7 @@ "sources": [ { "fileName": "destructuring.ts", - "line": 15, + "line": 14, "character": 53 } ], @@ -282,8 +282,8 @@ "sources": [ { "fileName": "destructuring.ts", - "line": 25, - "character": 60 + "line": 24, + "character": 61 } ], "type": { @@ -301,8 +301,8 @@ "sources": [ { "fileName": "destructuring.ts", - "line": 25, - "character": 45 + "line": 24, + "character": 46 } ], "type": { @@ -318,7 +318,7 @@ } ] }, - "defaultValue": " [0, 0]" + "defaultValue": "[0, 0]" }, { "id": 17, @@ -329,7 +329,7 @@ "sources": [ { "fileName": "destructuring.ts", - "line": 25, + "line": 24, "character": 23 } ], @@ -354,7 +354,7 @@ "sources": [ { "fileName": "destructuring.ts", - "line": 25, + "line": 24, "character": 18 } ] @@ -371,7 +371,7 @@ "sources": [ { "fileName": "destructuring.ts", - "line": 25, + "line": 24, "character": 17 } ] diff --git a/src/test/converter/events-overloads/events-overloads.ts b/src/test/converter/events-overloads/events-overloads.ts index 417f103e6..956830e5e 100644 --- a/src/test/converter/events-overloads/events-overloads.ts +++ b/src/test/converter/events-overloads/events-overloads.ts @@ -3,16 +3,15 @@ * * @see https://github.com/sebastian-lenz/typedoc/issues/136 */ -interface Test -{ +interface Test { /** * Subscribe for a general event by name. * * @event * @param event The name of the event to subscribe for. - * @param handler The handler called when the event occure. + * @param handler The handler called when the event occurs. */ - on(event: string, handler: (e:any) => void): void; + on(event: string, handler: (e: any) => void): void; /** * Subscribe for error notifications. @@ -21,7 +20,7 @@ interface Test * @param event The name of the event to subscribe for. * @param handler A handler that will receive the error details */ - on(event: "error", handler: (e:any) => void): void; + on(event: 'error', handler: (e: any) => void): void; /** * Subscribe for progress notifications. @@ -30,7 +29,7 @@ interface Test * @param event The name of the event to subscribe for. * @param handler A handler that will receive a progress event with the current and expected total bytes */ - on(event: "progress", handler: (e:any) => void): void; + on(event: 'progress', handler: (e: any) => void): void; /** * Subscribe for success notification. @@ -39,5 +38,7 @@ interface Test * @param event The name of the event to subscribe for. * @param handler A function that will be called with general event data upon successful completion */ - on(event: "complete", handler: (e:any) => void): void; + on(event: 'complete', handler: (e: any) => void): void; } + +export {}; diff --git a/src/test/converter/events-overloads/specs.json b/src/test/converter/events-overloads/specs.json index a1445fb20..aa09da62b 100644 --- a/src/test/converter/events-overloads/specs.json +++ b/src/test/converter/events-overloads/specs.json @@ -68,7 +68,7 @@ "kindString": "Parameter", "flags": {}, "comment": { - "text": "The handler called when the event occure.\n" + "text": "The handler called when the event occurs.\n" }, "type": { "type": "reflection", @@ -107,7 +107,7 @@ "sources": [ { "fileName": "events-overloads.ts", - "line": 15, + "line": 14, "character": 30 } ] @@ -190,7 +190,7 @@ "sources": [ { "fileName": "events-overloads.ts", - "line": 24, + "line": 23, "character": 31 } ] @@ -273,7 +273,7 @@ "sources": [ { "fileName": "events-overloads.ts", - "line": 33, + "line": 32, "character": 34 } ] @@ -356,7 +356,7 @@ "sources": [ { "fileName": "events-overloads.ts", - "line": 42, + "line": 41, "character": 34 } ] @@ -373,22 +373,22 @@ "sources": [ { "fileName": "events-overloads.ts", - "line": 15, + "line": 14, "character": 6 }, { "fileName": "events-overloads.ts", - "line": 24, + "line": 23, "character": 6 }, { "fileName": "events-overloads.ts", - "line": 33, + "line": 32, "character": 6 }, { "fileName": "events-overloads.ts", - "line": 42, + "line": 41, "character": 6 } ] diff --git a/src/test/converter/events/events.ts b/src/test/converter/events/events.ts index de371d6e4..4a68fbef2 100644 --- a/src/test/converter/events/events.ts +++ b/src/test/converter/events/events.ts @@ -1,9 +1,10 @@ -class EventDispatcher -{ +class EventDispatcher { /** * This is an event documentation. * @event */ - static EVENT_CLICK:string = 'click'; + static EVENT_CLICK = 'click'; } + +export {}; diff --git a/src/test/converter/events/specs.json b/src/test/converter/events/specs.json index ef807bbc9..c73496620 100644 --- a/src/test/converter/events/specs.json +++ b/src/test/converter/events/specs.json @@ -35,7 +35,7 @@ "sources": [ { "fileName": "events.ts", - "line": 7, + "line": 6, "character": 22 } ], diff --git a/src/test/converter/function/specs.json b/src/test/converter/function/specs.json index fa3d985cc..5201ebfc0 100644 --- a/src/test/converter/function/specs.json +++ b/src/test/converter/function/specs.json @@ -444,7 +444,7 @@ "type": "intrinsic", "name": "number" }, - "defaultValue": " Number.NaN" + "defaultValue": "Number.NaN" }, { "id": 23, @@ -474,7 +474,7 @@ "type": "intrinsic", "name": "boolean" }, - "defaultValue": " null" + "defaultValue": "null" } ], "type": { diff --git a/src/test/converter/generic-class/generic-class.ts b/src/test/converter/generic-class/generic-class.ts index 11cd1d723..7bbdf6dbb 100644 --- a/src/test/converter/generic-class/generic-class.ts +++ b/src/test/converter/generic-class/generic-class.ts @@ -6,18 +6,18 @@ class GenericClass { /** * Generic property. */ - protected value:T; + protected value: T; /** * Generic property array. */ - protected values:T[]; + protected values: T[]; /** * Constructor short text. * @param value Constructor parameter. */ - constructor(value:T) { + constructor(value: T) { this.value = value; } @@ -25,13 +25,14 @@ class GenericClass { * getValue short text. * @return Return value comment. */ - getValue():T { + getValue(): T { return this.value; } } - /** * NonGenericClass short text. */ class NonGenericClass extends GenericClass {} + +export {}; diff --git a/src/test/converter/generic-class/specs.json b/src/test/converter/generic-class/specs.json index d8eb54571..064df9970 100644 --- a/src/test/converter/generic-class/specs.json +++ b/src/test/converter/generic-class/specs.json @@ -82,7 +82,7 @@ { "fileName": "generic-class.ts", "line": 14, - "character": 25 + "character": 26 } ] }, @@ -267,7 +267,7 @@ { "fileName": "generic-class.ts", "line": 14, - "character": 25 + "character": 26 } ], "inheritedFrom": { @@ -404,7 +404,7 @@ "sources": [ { "fileName": "generic-class.ts", - "line": 37, + "line": 36, "character": 21 } ], diff --git a/src/test/converter/generic-function/generic-function.ts b/src/test/converter/generic-function/generic-function.ts index 066f2d88d..bbfe2f1a9 100644 --- a/src/test/converter/generic-function/generic-function.ts +++ b/src/test/converter/generic-function/generic-function.ts @@ -4,11 +4,10 @@ * @param value Generic function parameter. * @returns Generic function return value. */ -function genericFunction(value:T):T { +function genericFunction(value: T): T { return value; } - /** * A function with a generic type array parameter. * @@ -16,6 +15,8 @@ function genericFunction(value:T):T { * @param params A generic array parameter. * @returns A generic array. */ -function functionWithGenericArrayParameter(param:T, params:T[]):T[] { +function functionWithGenericArrayParameter(param: T, params: T[]): T[] { return params; } + +export {}; diff --git a/src/test/converter/generic-function/specs.json b/src/test/converter/generic-function/specs.json index 88e7e6f97..c8c6664ed 100644 --- a/src/test/converter/generic-function/specs.json +++ b/src/test/converter/generic-function/specs.json @@ -85,7 +85,7 @@ "sources": [ { "fileName": "generic-function.ts", - "line": 19, + "line": 18, "character": 42 } ] diff --git a/src/test/converter/getter-setter/getter-setter.ts b/src/test/converter/getter-setter/getter-setter.ts index 846111597..ebe9a3b54 100644 --- a/src/test/converter/getter-setter/getter-setter.ts +++ b/src/test/converter/getter-setter/getter-setter.ts @@ -1,12 +1,12 @@ -class GetterSetter -{ - private _name:string; +class GetterSetter { + private _name: string; + get name(): string { return this._name; } + set name(value: string) { this._name = value; } - get name():string { return this._name; } - set name(value:string) { this._name = value; } + get readOnlyName(): string { return this._name; } - get readOnlyName():string { return this._name; } - - set writeOnlyName(value:string) { this._name = value; } + set writeOnlyName(value: string) { this._name = value; } } + +export {}; diff --git a/src/test/converter/getter-setter/specs.json b/src/test/converter/getter-setter/specs.json index 5d158dc38..8d0393053 100644 --- a/src/test/converter/getter-setter/specs.json +++ b/src/test/converter/getter-setter/specs.json @@ -32,7 +32,7 @@ "sources": [ { "fileName": "getter-setter.ts", - "line": 3, + "line": 2, "character": 17 } ], @@ -89,12 +89,12 @@ "sources": [ { "fileName": "getter-setter.ts", - "line": 6, + "line": 4, "character": 12 }, { "fileName": "getter-setter.ts", - "line": 7, + "line": 5, "character": 12 } ] @@ -121,7 +121,7 @@ "sources": [ { "fileName": "getter-setter.ts", - "line": 9, + "line": 7, "character": 20 } ] @@ -161,7 +161,7 @@ "sources": [ { "fileName": "getter-setter.ts", - "line": 11, + "line": 9, "character": 21 } ] diff --git a/src/test/converter/interface-empty/interface-empty.ts b/src/test/converter/interface-empty/interface-empty.ts index 28c9ec80e..8da66b63a 100644 --- a/src/test/converter/interface-empty/interface-empty.ts +++ b/src/test/converter/interface-empty/interface-empty.ts @@ -4,11 +4,12 @@ interface EmptyInterface { } - /** * A class implementing an empty interface. */ class ClassImplementingEmptyInterface implements EmptyInterface { - private name:string; + private name: string; public goto() {} } + +export {}; diff --git a/src/test/converter/interface-empty/specs.json b/src/test/converter/interface-empty/specs.json index 74c39a6f7..d15f0db6b 100644 --- a/src/test/converter/interface-empty/specs.json +++ b/src/test/converter/interface-empty/specs.json @@ -35,7 +35,7 @@ "sources": [ { "fileName": "interface-empty.ts", - "line": 12, + "line": 11, "character": 16 } ], @@ -68,7 +68,7 @@ "sources": [ { "fileName": "interface-empty.ts", - "line": 13, + "line": 12, "character": 15 } ] @@ -93,7 +93,7 @@ "sources": [ { "fileName": "interface-empty.ts", - "line": 11, + "line": 10, "character": 37 } ], diff --git a/src/test/converter/interface-implementation/interface-implementation.ts b/src/test/converter/interface-implementation/interface-implementation.ts index 7b770503e..7f163c816 100644 --- a/src/test/converter/interface-implementation/interface-implementation.ts +++ b/src/test/converter/interface-implementation/interface-implementation.ts @@ -1,75 +1,67 @@ -module Forms -{ +module Forms { /** * Function signature of an event listener callback */ - interface IEventListener - { - (parameter:T):any; + interface IEventListener { + (parameter: T): any; } - /** * Encapsulates a subscription to an event dispatcher, and allows for unsubscribing */ - interface ISubscription - { - listener: IEventListener - priority: number - filter: any + interface ISubscription { + listener: IEventListener; + priority: number; + filter: any; /** * Remove this subscription from its dispatcher */ - unsubscribe():void + unsubscribe(): void; } + class Subscription implements ISubscription { + constructor(public listener: IEventListener, public filter: any, public priority: number, public dispatcher: EventDispatcher) { } - class Subscription implements ISubscription - { - constructor(public listener:IEventListener, public filter:any, public priority:number, public dispatcher:EventDispatcher) { } - - unsubscribe():void { } + unsubscribe(): void { } } - /** * The main interface of the event system. * An IEventDispatcher is an object that keeps a list of listeners, and sends dispatches events of a certain type to them. * This might otherwise be known as a Signal. */ - export interface IEventDispatcher - { - add(listener:IEventListener, filter?:any, priority?:number):ISubscription; - remove(subscription:ISubscription): void; - dispatch(parameter:U): boolean; - clear():void; - hasListeners():boolean; + export interface IEventDispatcher { + add(listener: IEventListener, filter?: any, priority?: number): ISubscription; + remove(subscription: ISubscription): void; + dispatch(parameter: U): boolean; + clear(): void; + hasListeners(): boolean; } - /** * Implementation of IEventDispatcher * @see IEventDispatcher */ - export class EventDispatcher implements IEventDispatcher - { - private subscriptions:ISubscription[]; + export class EventDispatcher implements IEventDispatcher { + private subscriptions: ISubscription[]; - add(listener:IEventListener, filter:any=null, priority:number = 0):ISubscription { + add(listener: IEventListener, filter: any= null, priority: number = 0): ISubscription { return new Subscription(listener, filter, priority, this); } - remove(subscription:ISubscription):void { } + remove(subscription: ISubscription): void { } - dispatch(event:T):boolean { + dispatch(event: T): boolean { return false; } - clear():void { } + clear(): void { } - hasListeners():boolean { + hasListeners(): boolean { return false; } } } + +export {}; diff --git a/src/test/converter/interface-implementation/specs.json b/src/test/converter/interface-implementation/specs.json index 24d069b30..dd27e5e87 100644 --- a/src/test/converter/interface-implementation/specs.json +++ b/src/test/converter/interface-implementation/specs.json @@ -60,7 +60,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 57, + "line": 47, "character": 29 } ], @@ -159,7 +159,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 59, + "line": 49, "character": 11 } ], @@ -198,7 +198,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 69, + "line": 59, "character": 13 } ], @@ -250,7 +250,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 65, + "line": 55, "character": 16 } ], @@ -289,7 +289,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 71, + "line": 61, "character": 20 } ], @@ -348,7 +348,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 63, + "line": 53, "character": 14 } ], @@ -382,7 +382,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 55, + "line": 46, "character": 32 } ], @@ -499,8 +499,8 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 29, - "character": 5 + "line": 23, + "character": 55 } ] }, @@ -516,8 +516,8 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 30, - "character": 115 + "line": 24, + "character": 118 } ], "type": { @@ -544,8 +544,8 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 30, - "character": 68 + "line": 24, + "character": 69 } ], "type": { @@ -570,7 +570,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 30, + "line": 24, "character": 35 } ], @@ -603,8 +603,8 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 30, - "character": 89 + "line": 24, + "character": 91 } ], "type": { @@ -644,7 +644,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 32, + "line": 26, "character": 19 } ], @@ -684,7 +684,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 28, + "line": 23, "character": 22 } ], @@ -800,7 +800,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 43, + "line": 35, "character": 11 } ] @@ -829,7 +829,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 46, + "line": 38, "character": 13 } ] @@ -871,7 +871,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 45, + "line": 37, "character": 16 } ] @@ -900,7 +900,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 47, + "line": 39, "character": 20 } ] @@ -949,7 +949,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 44, + "line": 36, "character": 14 } ] @@ -971,7 +971,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 41, + "line": 34, "character": 37 } ], @@ -1033,7 +1033,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 6, + "line": 5, "character": 28 } ] @@ -1066,7 +1066,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 19, + "line": 15, "character": 14 } ], @@ -1084,7 +1084,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 17, + "line": 13, "character": 16 } ], @@ -1109,7 +1109,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 18, + "line": 14, "character": 16 } ], @@ -1143,7 +1143,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 24, + "line": 20, "character": 19 } ] @@ -1170,7 +1170,7 @@ "sources": [ { "fileName": "interface-implementation.ts", - "line": 15, + "line": 12, "character": 27 } ], diff --git a/src/test/converter/literal-object-callbacks/literal-object-callbacks.ts b/src/test/converter/literal-object-callbacks/literal-object-callbacks.ts index 5761a5236..4a6823301 100644 --- a/src/test/converter/literal-object-callbacks/literal-object-callbacks.ts +++ b/src/test/converter/literal-object-callbacks/literal-object-callbacks.ts @@ -16,3 +16,5 @@ const callbackReturn = { return callbackReturn; } }; + +export {}; diff --git a/src/test/converter/literal-object/literal-object.ts b/src/test/converter/literal-object/literal-object.ts index 760b3c097..7780bfb12 100644 --- a/src/test/converter/literal-object/literal-object.ts +++ b/src/test/converter/literal-object/literal-object.ts @@ -6,9 +6,11 @@ const objectLiteral = { valueY: function() { return 'foo'; }, valueX: { valueZ: 'foo', - valueY: (z:string) => { return {a:'test', b:z}; }, + valueY: (z: string) => { return {a: 'test', b: z}; }, valueA: [100, 200, 300] }, valueA: 100, valueB: true }; + +export {}; diff --git a/src/test/converter/literal-object/specs.json b/src/test/converter/literal-object/specs.json index 5aac63ad6..6dbb44fd6 100644 --- a/src/test/converter/literal-object/specs.json +++ b/src/test/converter/literal-object/specs.json @@ -137,7 +137,7 @@ "name": "number" } }, - "defaultValue": " [100, 200, 300]" + "defaultValue": "[100, 200, 300]" }, { "id": 7, @@ -203,7 +203,7 @@ { "fileName": "literal-object.ts", "line": 9, - "character": 41 + "character": 42 } ], "type": { @@ -222,7 +222,7 @@ { "fileName": "literal-object.ts", "line": 9, - "character": 51 + "character": 53 } ], "type": { diff --git a/src/test/converter/literal-type/literal-type.ts b/src/test/converter/literal-type/literal-type.ts index 99aa5a4c4..147c744cf 100644 --- a/src/test/converter/literal-type/literal-type.ts +++ b/src/test/converter/literal-type/literal-type.ts @@ -1,11 +1,13 @@ -let typeLiteral:{ - valueZ:string; - valueY:{():string;}; - valueX:{ - valueZ:string; - valueY:{(z:string):{a:string; b:string}; }; - valueA:number[]; +let typeLiteral: { + valueZ: string; + valueY: {(): string; }; + valueX: { + valueZ: string; + valueY: {(z: string): {a: string; b: string}; }; + valueA: number[]; }; - valueA?:number; - valueB?:boolean; + valueA?: number; + valueB?: boolean; }; + +export {}; diff --git a/src/test/converter/literal-type/specs.json b/src/test/converter/literal-type/specs.json index 1d4145393..04a55104a 100644 --- a/src/test/converter/literal-type/specs.json +++ b/src/test/converter/literal-type/specs.json @@ -181,7 +181,7 @@ { "fileName": "literal-type.ts", "line": 6, - "character": 29 + "character": 32 } ], "type": { @@ -199,7 +199,7 @@ { "fileName": "literal-type.ts", "line": 6, - "character": 39 + "character": 43 } ], "type": { @@ -222,7 +222,7 @@ { "fileName": "literal-type.ts", "line": 6, - "character": 27 + "character": 29 } ] } diff --git a/src/test/converter/promise-object/promise-object.ts b/src/test/converter/promise-object/promise-object.ts index 5ab86a0b3..49056d7c7 100644 --- a/src/test/converter/promise-object/promise-object.ts +++ b/src/test/converter/promise-object/promise-object.ts @@ -1,3 +1,5 @@ let x: object; let y: Promise; let z: Promise; + +export {}; diff --git a/src/test/renderer.test.ts b/src/test/renderer.test.ts index ac5853c08..a6c1cb589 100644 --- a/src/test/renderer.test.ts +++ b/src/test/renderer.test.ts @@ -62,7 +62,8 @@ describe('Renderer', function() { readme: Path.join(src, '..', 'README.md'), module: 'CommonJS', gaSite: 'foo.com', // verify theme option without modifying output - name: 'typedoc' + name: 'typedoc', + ignoreCompilerErrors: true }); }); From a78c6267f7fb1a9d1b2b4a59e04b6c86efa7fed0 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 28 Dec 2019 21:35:29 -0700 Subject: [PATCH 02/19] feat: Use ReferenceReflections to describe exports Incomplete: Theme updates --- src/lib/converter/context.ts | 2 +- src/lib/converter/factories/reference.ts | 18 +- src/lib/converter/nodes/export.ts | 48 +++- src/lib/models/reflections/abstract.ts | 52 ++-- src/lib/models/reflections/index.ts | 1 + src/lib/models/reflections/project.ts | 2 +- src/lib/models/reflections/reference.ts | 100 ++++++++ .../serializers/reflections/index.ts | 1 + .../serializers/reflections/reference.ts | 18 ++ src/test/converter/export/export.ts | 12 +- src/test/converter/export/mod.ts | 16 ++ src/test/converter/export/specs.json | 237 +++++++++++++++--- 12 files changed, 447 insertions(+), 60 deletions(-) create mode 100644 src/lib/models/reflections/reference.ts create mode 100644 src/lib/serialization/serializers/reflections/reference.ts create mode 100644 src/test/converter/export/mod.ts diff --git a/src/lib/converter/context.ts b/src/lib/converter/context.ts index 93cc657f0..83ff631b0 100644 --- a/src/lib/converter/context.ts +++ b/src/lib/converter/context.ts @@ -400,7 +400,7 @@ export class Context { } function isNamedNode(node: ts.Node): node is ts.Node & { name: ts.Identifier | ts.ComputedPropertyName } { - return node.hasOwnProperty('name') && ( + return node['name'] && ( ts.isIdentifier(node['name']) || ts.isComputedPropertyName(node['name']) ); diff --git a/src/lib/converter/factories/reference.ts b/src/lib/converter/factories/reference.ts index c1b1b3c53..9839b505c 100644 --- a/src/lib/converter/factories/reference.ts +++ b/src/lib/converter/factories/reference.ts @@ -1,7 +1,8 @@ import * as ts from 'typescript'; -import { ReferenceType } from '../../models/types/index'; +import { ReferenceType, ReferenceReflection, ContainerReflection } from '../../models'; import { Context } from '../context'; +import { ReferenceState } from '../../models/reflections/reference'; /** * Create a new reference type pointing to the given symbol. @@ -26,3 +27,18 @@ export function createReferenceType(context: Context, symbol: ts.Symbol | undefi return new ReferenceType(name, id); } + +export function createReferenceReflection(context: Context, source: ts.Symbol, target: ts.Symbol): ReferenceReflection { + if (!(context.scope instanceof ContainerReflection)) { + throw new Error('Cannot add reference to a non-container'); + } + + const reflection = new ReferenceReflection(source.name, [ReferenceState.Unresolved, context.getSymbolID(target)!], context.scope); + if (!context.scope.children) { + context.scope.children = []; + } + context.scope.children.push(reflection); + context.registerReflection(reflection, undefined, source); + + return reflection; +} diff --git a/src/lib/converter/nodes/export.ts b/src/lib/converter/nodes/export.ts index dab11eac2..0bd585e5e 100644 --- a/src/lib/converter/nodes/export.ts +++ b/src/lib/converter/nodes/export.ts @@ -1,9 +1,11 @@ import * as ts from 'typescript'; -import { Reflection, ReflectionFlag, DeclarationReflection } from '../../models/index'; +import { Reflection, ReflectionFlag, DeclarationReflection, ContainerReflection } from '../../models/index'; import { Context } from '../context'; import { Component, ConverterNodeComponent } from '../components'; +import { createReferenceReflection } from '../factories/reference'; +// TODO: With 9c3114d this converter should no longer be necessary. Verify and remove. @Component({name: 'node:export'}) export class ExportConverter extends ConverterNodeComponent { /** @@ -53,3 +55,47 @@ export class ExportConverter extends ConverterNodeComponent return context.scope; } } + +@Component({ name: 'node:export-declaration' }) +export class ExportDeclarationConverter extends ConverterNodeComponent { + supports = [ts.SyntaxKind.ExportDeclaration]; + + convert(context: Context, node: ts.ExportDeclaration): Reflection | undefined { + const scope = context.scope; + if (!(scope instanceof ContainerReflection)) { + throw new Error('Expected to be within a container'); + } + + if (node.exportClause) { // export { a, a as b } + node.exportClause.elements.forEach(specifier => { + const source = context.getSymbolAtLocation(specifier.name); + const target = context.getSymbolAtLocation(specifier.propertyName ?? specifier.name); + if (source && target) { + const original = (target.flags & ts.SymbolFlags.Alias) ? context.checker.getAliasedSymbol(target) : target; + // If the original declaration is in this file, export {} was used with something + // defined in this file and we don't need to create a reference unless the name is different. + if (original.valueDeclaration.getSourceFile() === specifier.getSourceFile() && !specifier.propertyName) { + return; + } + + createReferenceReflection(context, source, original); + } + }); + } else if (node.moduleSpecifier) { // export * from ... + const thisModule = context.getSymbolAtLocation(node.getSourceFile())!; + const sourceFileSymbol = context.getSymbolAtLocation(node.moduleSpecifier); + sourceFileSymbol?.exports?.forEach((symbol, key) => { + // Default exports are not re-exported with export * from + if (key === 'default' as ts.__String) { + return; + } + const source = context.checker.tryGetMemberInModuleExports(key.toString().replace(/^__/, '_'), thisModule); + if (source) { + createReferenceReflection(context, source, symbol); + } + }); + } + + return context.scope; + } +} diff --git a/src/lib/models/reflections/abstract.ts b/src/lib/models/reflections/abstract.ts index dea59c730..a9ecf0f91 100644 --- a/src/lib/models/reflections/abstract.ts +++ b/src/lib/models/reflections/abstract.ts @@ -3,6 +3,7 @@ import { Type } from '../types/index'; import { Comment } from '../comments/comment'; import { TypeParameterReflection } from './type-parameter'; import { splitUnquotedString } from './utils'; +import { ProjectReflection } from './project'; /** * Holds all data models used by TypeDoc. @@ -35,29 +36,30 @@ export function resetReflectionID() { */ export enum ReflectionKind { Global = 0, - ExternalModule = 1, - Module = 2, - Enum = 4, - EnumMember = 16, - Variable = 32, - Function = 64, - Class = 128, - Interface = 256, - Constructor = 512, - Property = 1024, - Method = 2048, - CallSignature = 4096, - IndexSignature = 8192, - ConstructorSignature = 16384, - Parameter = 32768, - TypeLiteral = 65536, - TypeParameter = 131072, - Accessor = 262144, - GetSignature = 524288, - SetSignature = 1048576, - ObjectLiteral = 2097152, - TypeAlias = 4194304, - Event = 8388608, + ExternalModule = 1 << 0, + Module = 1 << 1, + Enum = 1 << 2, + EnumMember = 1 << 4, + Variable = 1 << 5, + Function = 1 << 6, + Class = 1 << 7, + Interface = 1 << 8, + Constructor = 1 << 9, + Property = 1 << 10, + Method = 1 << 11, + CallSignature = 1 << 12, + IndexSignature = 1 << 13, + ConstructorSignature = 1 << 14, + Parameter = 1 << 15, + TypeLiteral = 1 << 16, + TypeParameter = 1 << 17, + Accessor = 1 << 18, + GetSignature = 1 << 19, + SetSignature = 1 << 20, + ObjectLiteral = 1 << 21, + TypeAlias = 1 << 22, + Event = 1 << 23, + Reference = 1 << 24, ClassOrInterface = Class | Interface, VariableOrProperty = Variable | Property, @@ -319,7 +321,7 @@ export abstract class Reflection { /** * The symbol name of this reflection. */ - name = ''; + name: string; /** * The original name of the TypeScript declaration. @@ -513,7 +515,7 @@ export abstract class Reflection { /** * Return whether this reflection is the root / project reflection. */ - isProject(): boolean { // this is ProjectReflection + isProject(): this is ProjectReflection { return false; } diff --git a/src/lib/models/reflections/index.ts b/src/lib/models/reflections/index.ts index cc1d0ebd7..33cc0881b 100644 --- a/src/lib/models/reflections/index.ts +++ b/src/lib/models/reflections/index.ts @@ -3,6 +3,7 @@ export { ContainerReflection } from './container'; export { DeclarationReflection, DeclarationHierarchy } from './declaration'; export { ParameterReflection } from './parameter'; export { ProjectReflection } from './project'; +export { ReferenceReflection } from './reference'; export { SignatureReflection } from './signature'; export { TypeParameterReflection } from './type-parameter'; export { splitUnquotedString } from './utils'; diff --git a/src/lib/models/reflections/project.ts b/src/lib/models/reflections/project.ts index 0e69e8d54..1641e2d6c 100644 --- a/src/lib/models/reflections/project.ts +++ b/src/lib/models/reflections/project.ts @@ -57,7 +57,7 @@ export class ProjectReflection extends ContainerReflection { /** * Return whether this reflection is the root / project reflection. */ - isProject(): boolean { + isProject(): this is ProjectReflection { return true; } diff --git a/src/lib/models/reflections/reference.ts b/src/lib/models/reflections/reference.ts new file mode 100644 index 000000000..a17873e10 --- /dev/null +++ b/src/lib/models/reflections/reference.ts @@ -0,0 +1,100 @@ +import { Reflection, ReflectionKind, ReflectionFlag } from './abstract'; +import { ProjectReflection } from './project'; +import { DeclarationReflection } from './declaration'; + +export enum ReferenceState { + Unresolved, + Resolved +} + +/** + * Describes a reflection which does not exist at this location, but is referenced. Used for imported reflections. + * + * ```ts + * // a.ts + * export const a = 1; + * // b.ts + * import { a } from './a'; + * // Here to avoid extra work we create a reference to the original reflection in module a instead + * // of copying the reflection. + * export { a }; + * ``` + */ +export class ReferenceReflection extends DeclarationReflection { + private _state: [ReferenceState.Unresolved, number] | [ReferenceState.Resolved, number]; + private _project?: ProjectReflection; + + /** + * Creates a reference reflection. Should only be used within the factory function. + * @param name + * @param state + * @param parent + * + * @internal + */ + constructor(name: string, state: ReferenceReflection['_state'], parent?: Reflection) { + super(name, ReflectionKind.Reference, parent); + // References are only created for re-exported items, so they must be exported. + this.flags.setFlag(ReflectionFlag.Exported, true); + this._state = state; + } + + /** + * Gets the reflection that is referenced. This may be another reference reflection. + * To fully resolve any references, use [[getTargetReflectionDeep]]. + */ + getTargetReflection(): Reflection { + this._ensureProject(); + this._ensureResolved(); + + return this._project!.reflections[this._state[1]]; + } + + /** + * Gets the reflection that is referenced, this will fully resolve references. + * To only resolve one reference, use [[getTargetReflection]]. + */ + getTargetReflectionDeep(): Reflection { + let result = this.getTargetReflection(); + while (result instanceof ReferenceReflection) { + result = result.getTargetReflection(); + } + return result; + } + + /** + * Get a raw object representation of this reflection. + * @deprecated use serializers instead. + */ + toObject() { + return { + ...super.toObject(), + target: this.getTargetReflection().id + }; + } + + private _ensureResolved() { + if (this._state[0] === ReferenceState.Unresolved) { + const target = this._project!.symbolMapping[this._state[1]]; + if (!target) { + console.log({ ...this, parent: null, _project: null }, this._project!.symbolMapping); + throw new Error(`Tried to reference reflection for ${this.name} that does not exist.`); + } + this._state = [ReferenceState.Resolved, target]; + } + } + + private _ensureProject() { + if (this._project) { return; } + + let project = this.parent; + while (project && !project.isProject()) { + project = project.parent; + } + this._project = project; + + if (!this._project) { + throw new Error('Reference reflection has no project and is unable to resolve.'); + } + } +} diff --git a/src/lib/serialization/serializers/reflections/index.ts b/src/lib/serialization/serializers/reflections/index.ts index 99548c79d..032a60f3b 100644 --- a/src/lib/serialization/serializers/reflections/index.ts +++ b/src/lib/serialization/serializers/reflections/index.ts @@ -3,5 +3,6 @@ export * from './container'; export * from './declaration'; export * from './parameter'; export * from './project'; +export * from './reference'; export * from './signature'; export * from './type-parameter'; diff --git a/src/lib/serialization/serializers/reflections/reference.ts b/src/lib/serialization/serializers/reflections/reference.ts new file mode 100644 index 000000000..2a5d25335 --- /dev/null +++ b/src/lib/serialization/serializers/reflections/reference.ts @@ -0,0 +1,18 @@ +import { Component } from '../../../utils/component'; +import { ReferenceReflection } from '../../../models'; + +import { ReflectionSerializerComponent } from '../../components'; + +@Component({ name: 'serializer:reference-reflection' }) +export class ReferenceReflectionSerializer extends ReflectionSerializerComponent { + supports(t: unknown) { + return t instanceof ReferenceReflection; + } + + toObject(ref: ReferenceReflection, obj?: any): any { + return { + ...obj, + target: ref.getTargetReflection().id + }; + } +} diff --git a/src/test/converter/export/export.ts b/src/test/converter/export/export.ts index a74c72b55..9976c553f 100644 --- a/src/test/converter/export/export.ts +++ b/src/test/converter/export/export.ts @@ -1,5 +1,13 @@ -export const x = 5; +import ModDefault, { a as b } from './mod'; +import * as Mod from './mod'; +export * from './mod'; -export function add(x: number, y: number) { +export { b as c, add, Mod, ModDefault }; + +function add(x: number, y: number) { return x + y; } + +// Note that this will show up in the docs, not the default function from mod2. +// export * from './mod2' does *not* re-export the default function. +export default function (a: number) {} diff --git a/src/test/converter/export/mod.ts b/src/test/converter/export/mod.ts new file mode 100644 index 000000000..ac1a69ed5 --- /dev/null +++ b/src/test/converter/export/mod.ts @@ -0,0 +1,16 @@ +/** + * A simple named export that will be exported from export.ts + */ +export const a = 1; + +/** + * An export of a local under a different name. + */ +export { a as b }; + +/** + * Will not be re-exported from export.ts using export * from... + */ +export default function() { + console.log('Default'); +} diff --git a/src/test/converter/export/specs.json b/src/test/converter/export/specs.json index 852eff5c2..33abf2301 100644 --- a/src/test/converter/export/specs.json +++ b/src/test/converter/export/specs.json @@ -5,7 +5,7 @@ "flags": {}, "children": [ { - "id": 1, + "id": 6, "name": "\"export\"", "kind": 1, "kindString": "External module", @@ -15,45 +15,71 @@ "originalName": "%BASE%/export/export.ts", "children": [ { - "id": 2, - "name": "x", - "kind": 32, - "kindString": "Variable", + "id": 10, + "name": "Mod", + "kind": 16777216, + "kindString": "Reference", "flags": { - "isExported": true, - "isConst": true + "isExported": true }, - "sources": [ - { - "fileName": "export.ts", - "line": 1, - "character": 14 - } - ], - "type": { - "type": "unknown", - "name": "5" + "target": 1 + }, + { + "id": 11, + "name": "ModDefault", + "kind": 16777216, + "kindString": "Reference", + "flags": { + "isExported": true }, - "defaultValue": "5" + "target": 4 }, { - "id": 3, - "name": "add", - "kind": 64, - "kindString": "Function", + "id": 7, + "name": "a", + "kind": 16777216, + "kindString": "Reference", + "flags": { + "isExported": true + }, + "target": 2 + }, + { + "id": 8, + "name": "b", + "kind": 16777216, + "kindString": "Reference", "flags": { "isExported": true }, + "target": 3 + }, + { + "id": 9, + "name": "c", + "kind": 16777216, + "kindString": "Reference", + "flags": { + "isExported": true + }, + "target": 2 + }, + { + "id": 12, + "name": "add", + "kind": 64, + "kindString": "Function", + "flags": {}, "signatures": [ { - "id": 4, + "id": 13, "name": "add", "kind": 4096, "kindString": "Call signature", "flags": {}, "parameters": [ { - "id": 5, + "id": 14, "name": "x", "kind": 32768, "kindString": "Parameter", @@ -64,7 +90,7 @@ } }, { - "id": 6, + "id": 15, "name": "y", "kind": 32768, "kindString": "Parameter", @@ -84,13 +110,165 @@ "sources": [ { "fileName": "export.ts", - "line": 3, - "character": 19 + "line": 7, + "character": 12 + } + ] + }, + { + "id": 16, + "name": "default", + "kind": 64, + "kindString": "Function", + "flags": {}, + "signatures": [ + { + "id": 17, + "name": "default", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "parameters": [ + { + "id": 18, + "name": "a", + "kind": 32768, + "kindString": "Parameter", + "flags": {}, + "type": { + "type": "intrinsic", + "name": "number" + } + } + ], + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "export.ts", + "line": 9, + "character": 1 } ] } ], "groups": [ + { + "title": "References", + "kind": 16777216, + "children": [ + 10, + 11, + 7, + 8, + 9 + ] + }, + { + "title": "Functions", + "kind": 64, + "children": [ + 12, + 16 + ] + } + ], + "sources": [ + { + "fileName": "export.ts", + "line": 1, + "character": 0 + } + ] + }, + { + "id": 1, + "name": "\"mod\"", + "kind": 1, + "kindString": "External module", + "flags": { + "isExported": true + }, + "originalName": "%BASE%/export/mod.ts", + "children": [ + { + "id": 3, + "name": "b", + "kind": 16777216, + "kindString": "Reference", + "flags": { + "isExported": true + }, + "target": 2 + }, + { + "id": 2, + "name": "a", + "kind": 32, + "kindString": "Variable", + "flags": { + "isExported": true, + "isConst": true + }, + "comment": { + "shortText": "A simple named export that will be exported from export.ts" + }, + "sources": [ + { + "fileName": "mod.ts", + "line": 4, + "character": 14 + } + ], + "type": { + "type": "unknown", + "name": "1" + }, + "defaultValue": "1" + }, + { + "id": 4, + "name": "default", + "kind": 64, + "kindString": "Function", + "flags": {}, + "signatures": [ + { + "id": 5, + "name": "default", + "kind": 4096, + "kindString": "Call signature", + "flags": {}, + "comment": { + "shortText": "Will not be re-exported from export.ts using export * from..." + }, + "type": { + "type": "intrinsic", + "name": "void" + } + } + ], + "sources": [ + { + "fileName": "mod.ts", + "line": 9, + "character": 18 + } + ] + } + ], + "groups": [ + { + "title": "References", + "kind": 16777216, + "children": [ + 3 + ] + }, { "title": "Variables", "kind": 32, @@ -102,13 +280,13 @@ "title": "Functions", "kind": 64, "children": [ - 3 + 4 ] } ], "sources": [ { - "fileName": "export.ts", + "fileName": "mod.ts", "line": 1, "character": 0 } @@ -120,6 +298,7 @@ "title": "External modules", "kind": 1, "children": [ + 6, 1 ] } From e1e94c0c5a67591cd3cfaaea6185c97eb37abaad Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 29 Dec 2019 09:14:34 -0700 Subject: [PATCH 03/19] fix: Warn about dangling references instead of crashing --- src/lib/converter/converter.ts | 10 +++++++++ src/lib/converter/factories/reference.ts | 2 ++ src/lib/models/reflections/project.ts | 18 +++++++++++++++ src/lib/models/reflections/reference.ts | 22 +++++++++++++++++++ .../serializers/reflections/reference.ts | 2 +- 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/lib/converter/converter.ts b/src/lib/converter/converter.ts index 7633b90b6..a93c7a1a3 100644 --- a/src/lib/converter/converter.ts +++ b/src/lib/converter/converter.ts @@ -285,6 +285,16 @@ export class Converter extends ChildableComponent(); + for (const ref of Object.values(this.reflections)) { + if (ref instanceof ReferenceReflection) { + if (!ref.tryGetTargetReflection()) { + dangling.add(ref.name); + } + } + } + return [...dangling]; + } } diff --git a/src/lib/models/reflections/reference.ts b/src/lib/models/reflections/reference.ts index a17873e10..d9d09d18b 100644 --- a/src/lib/models/reflections/reference.ts +++ b/src/lib/models/reflections/reference.ts @@ -39,6 +39,28 @@ export class ReferenceReflection extends DeclarationReflection { this._state = state; } + /** + * Tries to get the reflection that is referenced. This may be another reference reflection. + * To fully resolve any references, use [[tryGetTargetReflectionDeep]]. + */ + tryGetTargetReflection(): Reflection | undefined { + this._ensureProject(); + this._ensureResolved(false); + return this._state[0] === ReferenceState.Resolved ? this._project!.reflections[this._state[1]] : undefined; + } + + /** + * Tries to get the reflection that is referenced, this will fully resolve references. + * To only resolve one reference, use [[tryGetTargetReflection]]. + */ + tryGetTargetReflectionDeep(): Reflection | undefined { + let result = this.tryGetTargetReflection(); + while (result instanceof ReferenceReflection) { + result = result.tryGetTargetReflection(); + } + return result; + } + /** * Gets the reflection that is referenced. This may be another reference reflection. * To fully resolve any references, use [[getTargetReflectionDeep]]. diff --git a/src/lib/serialization/serializers/reflections/reference.ts b/src/lib/serialization/serializers/reflections/reference.ts index 2a5d25335..030045835 100644 --- a/src/lib/serialization/serializers/reflections/reference.ts +++ b/src/lib/serialization/serializers/reflections/reference.ts @@ -12,7 +12,7 @@ export class ReferenceReflectionSerializer extends ReflectionSerializerComponent toObject(ref: ReferenceReflection, obj?: any): any { return { ...obj, - target: ref.getTargetReflection().id + target: ref.tryGetTargetReflection()?.id ?? -1 }; } } From 0733ef2583dd556b9422a18323cfdcd36c0a2747 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 29 Dec 2019 10:04:32 -0700 Subject: [PATCH 04/19] fix: Warn about dangling references instead of crashing --- src/lib/models/reflections/reference.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/lib/models/reflections/reference.ts b/src/lib/models/reflections/reference.ts index d9d09d18b..03a664373 100644 --- a/src/lib/models/reflections/reference.ts +++ b/src/lib/models/reflections/reference.ts @@ -67,7 +67,7 @@ export class ReferenceReflection extends DeclarationReflection { */ getTargetReflection(): Reflection { this._ensureProject(); - this._ensureResolved(); + this._ensureResolved(true); return this._project!.reflections[this._state[1]]; } @@ -91,16 +91,18 @@ export class ReferenceReflection extends DeclarationReflection { toObject() { return { ...super.toObject(), - target: this.getTargetReflection().id + target: this.tryGetTargetReflection()?.id ?? -1 }; } - private _ensureResolved() { + private _ensureResolved(throwIfFail: boolean) { if (this._state[0] === ReferenceState.Unresolved) { const target = this._project!.symbolMapping[this._state[1]]; if (!target) { - console.log({ ...this, parent: null, _project: null }, this._project!.symbolMapping); - throw new Error(`Tried to reference reflection for ${this.name} that does not exist.`); + if (throwIfFail) { + throw new Error(`Tried to reference reflection for ${this.name} that does not exist.`); + } + return; } this._state = [ReferenceState.Resolved, target]; } From dd22b9652e23a482392c20954c558134cc9c2dfa Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 29 Dec 2019 13:45:11 -0700 Subject: [PATCH 05/19] chore: Tests for theme support of export declarations --- examples/basic/src/mod.ts | 6 + examples/basic/src/mod2.ts | 6 + .../specs/classes/_access_.privateclass.html | 6 + .../specs/classes/_classes_.baseclass.html | 6 + .../specs/classes/_classes_.genericclass.html | 6 + .../classes/_classes_.internalclass.html | 6 + .../classes/_classes_.nongenericclass.html | 6 + .../specs/classes/_classes_.subclassa.html | 6 + .../specs/classes/_classes_.subclassb.html | 6 + ..._default_export_.defaultexportedclass.html | 9 + ..._default_export_.notexportedclassname.html | 9 + .../classes/_flattened_.flattenedclass.html | 6 + .../_single_export_.notexportedclass.html | 6 + .../_single_export_.singleexportedclass.html | 6 + ...script_1_3_.classwithprotectedmembers.html | 6 + ...ipt_1_3_.subclasswithprotectedmembers.html | 6 + .../classes/_typescript_1_4_.simpleclass.html | 6 + .../enums/_enumerations_.directions.html | 6 + .../specs/enums/_enumerations_.size.html | 6 + src/test/renderer/specs/globals.html | 8 + src/test/renderer/specs/index.html | 6 + .../interfaces/_classes_.inameinterface.html | 6 + .../interfaces/_classes_.iprintinterface.html | 6 + .../_classes_.iprintnameinterface.html | 6 + .../specs/interfaces/_generics_.a.html | 6 + .../specs/interfaces/_generics_.ab.html | 6 + .../specs/interfaces/_generics_.abnumber.html | 6 + .../specs/interfaces/_generics_.abstring.html | 6 + .../specs/interfaces/_generics_.b.html | 6 + .../_typescript_1_4_.runoptions.html | 6 + src/test/renderer/specs/modules/_access_.html | 6 + .../specs/modules/_access_.privatemodule.html | 6 + .../renderer/specs/modules/_classes_.html | 6 + .../specs/modules/_default_export_.html | 23 ++ .../specs/modules/_enumerations_.html | 6 + .../renderer/specs/modules/_flattened_.html | 6 + .../renderer/specs/modules/_functions_.html | 6 + .../modules/_functions_.modulefunction.html | 6 + .../renderer/specs/modules/_generics_.html | 6 + src/test/renderer/specs/modules/_mod2_.html | 258 +++++++++++++++++ src/test/renderer/specs/modules/_mod_.html | 263 ++++++++++++++++++ .../renderer/specs/modules/_modules_.html | 6 + .../specs/modules/_modules_.mymodule.html | 6 + .../_modules_.mymodule.mysubmodule.html | 6 + .../specs/modules/_single_export_.html | 6 + .../specs/modules/_typescript_1_3_.html | 6 + .../specs/modules/_typescript_1_4_.html | 6 + .../specs/modules/_typescript_1_5_.html | 6 + .../renderer/specs/modules/_variables_.html | 6 + .../renderer/specs/modules/_weird_names_.html | 6 + 50 files changed, 834 insertions(+) create mode 100644 examples/basic/src/mod.ts create mode 100644 examples/basic/src/mod2.ts create mode 100644 src/test/renderer/specs/modules/_mod2_.html create mode 100644 src/test/renderer/specs/modules/_mod_.html diff --git a/examples/basic/src/mod.ts b/examples/basic/src/mod.ts new file mode 100644 index 000000000..e9d57c5a7 --- /dev/null +++ b/examples/basic/src/mod.ts @@ -0,0 +1,6 @@ +export const a = 1; + +/** + * Will not be included in mod2 + */ +export default function() {} diff --git a/examples/basic/src/mod2.ts b/examples/basic/src/mod2.ts new file mode 100644 index 000000000..1e95d2cb1 --- /dev/null +++ b/examples/basic/src/mod2.ts @@ -0,0 +1,6 @@ +export * from './mod'; + +/** + * Will be exported from mod2, unlike the default function in mod + */ +export default function () {} diff --git a/src/test/renderer/specs/classes/_access_.privateclass.html b/src/test/renderer/specs/classes/_access_.privateclass.html index 7e8f08929..5d60cff42 100644 --- a/src/test/renderer/specs/classes/_access_.privateclass.html +++ b/src/test/renderer/specs/classes/_access_.privateclass.html @@ -218,6 +218,12 @@

Returns void "generics" +
  • + "mod" +
  • +
  • + "mod2" +
  • "modules"
  • diff --git a/src/test/renderer/specs/classes/_classes_.baseclass.html b/src/test/renderer/specs/classes/_classes_.baseclass.html index f1a74a641..e04968c59 100644 --- a/src/test/renderer/specs/classes/_classes_.baseclass.html +++ b/src/test/renderer/specs/classes/_classes_.baseclass.html @@ -508,6 +508,12 @@

    Returns string "generics" +
  • + "mod" +
  • +
  • + "mod2" +
  • "modules"
  • diff --git a/src/test/renderer/specs/classes/_classes_.genericclass.html b/src/test/renderer/specs/classes/_classes_.genericclass.html index 5b825276f..acefbd3d1 100644 --- a/src/test/renderer/specs/classes/_classes_.genericclass.html +++ b/src/test/renderer/specs/classes/_classes_.genericclass.html @@ -349,6 +349,12 @@

    Returns void "generics" +
  • + "mod" +
  • +
  • + "mod2" +
  • "modules"
  • diff --git a/src/test/renderer/specs/classes/_classes_.internalclass.html b/src/test/renderer/specs/classes/_classes_.internalclass.html index 325a283c3..a6d91b34d 100644 --- a/src/test/renderer/specs/classes/_classes_.internalclass.html +++ b/src/test/renderer/specs/classes/_classes_.internalclass.html @@ -164,6 +164,12 @@

    Returns "generics" +
  • + "mod" +
  • +
  • + "mod2" +
  • "modules"
  • diff --git a/src/test/renderer/specs/classes/_classes_.nongenericclass.html b/src/test/renderer/specs/classes/_classes_.nongenericclass.html index 476d7009b..51738ff22 100644 --- a/src/test/renderer/specs/classes/_classes_.nongenericclass.html +++ b/src/test/renderer/specs/classes/_classes_.nongenericclass.html @@ -327,6 +327,12 @@

    Returns void "generics" +
  • + "mod" +
  • +
  • + "mod2" +
  • "modules"
  • diff --git a/src/test/renderer/specs/classes/_classes_.subclassa.html b/src/test/renderer/specs/classes/_classes_.subclassa.html index 257fd02ca..ccc60f2ff 100644 --- a/src/test/renderer/specs/classes/_classes_.subclassa.html +++ b/src/test/renderer/specs/classes/_classes_.subclassa.html @@ -647,6 +647,12 @@

    Returns string "generics" +
  • + "mod" +
  • +
  • + "mod2" +
  • "modules"
  • diff --git a/src/test/renderer/specs/classes/_classes_.subclassb.html b/src/test/renderer/specs/classes/_classes_.subclassb.html index 16f8b9a6b..96290e344 100644 --- a/src/test/renderer/specs/classes/_classes_.subclassb.html +++ b/src/test/renderer/specs/classes/_classes_.subclassb.html @@ -482,6 +482,12 @@

    Returns string "generics" +
  • + "mod" +
  • +
  • + "mod2" +
  • "modules"
  • diff --git a/src/test/renderer/specs/classes/_default_export_.defaultexportedclass.html b/src/test/renderer/specs/classes/_default_export_.defaultexportedclass.html index b351c06e0..53bf45187 100644 --- a/src/test/renderer/specs/classes/_default_export_.defaultexportedclass.html +++ b/src/test/renderer/specs/classes/_default_export_.defaultexportedclass.html @@ -206,6 +206,12 @@

    Returns string "generics" +
  • + "mod" +
  • +
  • + "mod2" +
  • "modules"
  • @@ -231,6 +237,9 @@

    Returns string