From 695f5c75ca1511aba04de6eb483b5f54a647503a Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 31 Oct 2020 20:42:26 -0600 Subject: [PATCH] feat: Support for the remaining literal types ... at least, I think I got them all. --- examples/basic/src/access.ts | 2 + package-lock.json | 6 +- package.json | 4 +- src/lib/converter/nodes/block.ts | 14 +- src/lib/converter/types.ts | 51 +++- src/lib/models/types/literal.ts | 7 +- src/lib/models/types/reference.ts | 11 +- src/lib/output/helpers/json.ts | 6 - src/lib/output/helpers/stringify.ts | 6 + src/lib/serialization/schema.ts | 9 +- .../serializers/types/literal.ts | 10 + src/test/converter/function/specs.json | 8 +- src/test/converter/types/general.ts | 7 + src/test/converter/types/specs.json | 226 ++++++++++++------ .../specs/classes/access.privateclass.html | 3 + src/test/renderer/specs/modules/access.html | 19 ++ tsconfig.json | 2 +- 17 files changed, 289 insertions(+), 102 deletions(-) delete mode 100644 src/lib/output/helpers/json.ts create mode 100644 src/lib/output/helpers/stringify.ts create mode 100644 src/test/converter/types/general.ts diff --git a/examples/basic/src/access.ts b/examples/basic/src/access.ts index e0c17bc61..0f9061bd8 100644 --- a/examples/basic/src/access.ts +++ b/examples/basic/src/access.ts @@ -59,3 +59,5 @@ export class PrivateClass { export module PrivateModule { export function functionInsidePrivateModule() {} } + +export type BigIntLiteral = -123n; diff --git a/package-lock.json b/package-lock.json index 8a9b04a7f..30061fa30 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2647,9 +2647,9 @@ } }, "typedoc-default-themes": { - "version": "0.12.0-beta.4", - "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.12.0-beta.4.tgz", - "integrity": "sha512-WQk7FDARYRAC43Cm2qgIu+GBcxYDFi3Id2ncG9QuAz2eNVWD4h6HywRMV98gEPy6J2kqH2rsfm2uvnjUjDpidA==" + "version": "0.12.0-beta.5", + "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.12.0-beta.5.tgz", + "integrity": "sha512-RHcw/iUdLcgikWhNYQOr4qqt02G+/L32AmS3wK6INUgOatjJeaAWK7qyvO1xqp0m3VLjUhuCk1B/PkO6V3LFxQ==" }, "typescript": { "version": "4.0.3", diff --git a/package.json b/package.json index 368cac828..1bafacd6d 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "url": "https://github.com/TypeStrong/TypeDoc/issues" }, "engines": { - "node": ">= 10.0.0" + "node": ">= 10.8.0" }, "dependencies": { "fs-extra": "^9.0.1", @@ -30,7 +30,7 @@ "progress": "^2.0.3", "semver": "^7.3.2", "shelljs": "^0.8.4", - "typedoc-default-themes": "beta" + "typedoc-default-themes": "0.12.0-beta.5" }, "peerDependencies": { "typescript": "3.9.x || 4.0.x" diff --git a/src/lib/converter/nodes/block.ts b/src/lib/converter/nodes/block.ts index d87a7f5bc..a35c0d85d 100644 --- a/src/lib/converter/nodes/block.ts +++ b/src/lib/converter/nodes/block.ts @@ -49,7 +49,9 @@ export class BlockConverter extends ConverterNodeComponent< return this.convertSourceFile(context, node); } else { for (const exp of this.getExports(context, node)) { - for (const decl of exp.getDeclarations() ?? []) { + for (const decl of (exp.getDeclarations() ?? []).filter((d) => + hasParent(d, node) + )) { this.owner.convertNode(context, decl); } } @@ -196,3 +198,13 @@ export class BlockConverter extends ConverterNodeComponent< return fileName.replace(/\\/g, "/"); } } + +function hasParent(node: ts.Node, parent: ts.Node) { + while (node.parent) { + if (node.parent === parent) { + return true; + } + node = node.parent; + } + return false; +} diff --git a/src/lib/converter/types.ts b/src/lib/converter/types.ts index 9b5b5e8c5..219f81698 100644 --- a/src/lib/converter/types.ts +++ b/src/lib/converter/types.ts @@ -277,8 +277,6 @@ const keywordConverter: TypeConverter = { }, }; -// literal - const parensConverter: TypeConverter = { kind: [ts.SyntaxKind.ParenthesizedType], convert(context, node) { @@ -499,12 +497,38 @@ const literalTypeConverter: TypeConverter< > = { kind: [ts.SyntaxKind.LiteralType], convert(context, node) { - if (node.literal.kind === ts.SyntaxKind.StringLiteral) { - return new LiteralType(node.literal.text); - } else if (node.literal.kind === ts.SyntaxKind.NumericLiteral) { - return new LiteralType(+node.literal.text); + switch (node.literal.kind) { + case ts.SyntaxKind.TrueKeyword: + case ts.SyntaxKind.FalseKeyword: + return new LiteralType( + node.literal.kind === ts.SyntaxKind.TrueKeyword + ); + case ts.SyntaxKind.StringLiteral: + return new LiteralType(node.literal.text); + case ts.SyntaxKind.NumericLiteral: + return new LiteralType(Number(node.literal.text)); + case ts.SyntaxKind.NullKeyword: + return new LiteralType(null); + case ts.SyntaxKind.PrefixUnaryExpression: { + const operand = (node.literal as ts.PrefixUnaryExpression) + .operand; + switch (operand.kind) { + case ts.SyntaxKind.NumericLiteral: + return new LiteralType(Number(node.literal.getText())); + case ts.SyntaxKind.BigIntLiteral: + return new LiteralType( + BigInt(node.literal.getText().replace("n", "")) + ); + default: + return requestBugReport(context, node.literal); + } + } + case ts.SyntaxKind.BigIntLiteral: + return new LiteralType( + BigInt(node.literal.getText().replace("n", "")) + ); } - // There's quite a few literal types to do here... skipping for now. + return requestBugReport(context, node.literal); }, convertType(context, type, node) { @@ -518,11 +542,18 @@ const literalTypeConverter: TypeConverter< return new LiteralType( node.literal.kind === ts.SyntaxKind.TrueKeyword ); + case ts.SyntaxKind.NullKeyword: + return new LiteralType(null); + } + + if (typeof type.value === "object") { + return new LiteralType( + BigInt( + `${type.value.negative ? "-" : ""}${type.value.base10Value}` + ) + ); } - // There's quite a few literal types to do here... skipping for now. - // Be aware of https://github.com/microsoft/TypeScript/issues/40203 - // and also https://github.com/microsoft/TypeScript/issues/26075 return requestBugReport(context, type); }, }; diff --git a/src/lib/models/types/literal.ts b/src/lib/models/types/literal.ts index 587042b6a..bce096786 100644 --- a/src/lib/models/types/literal.ts +++ b/src/lib/models/types/literal.ts @@ -9,14 +9,14 @@ import { Type } from "./abstract"; * ``` */ export class LiteralType extends Type { - value: string | number | boolean; + value: string | number | boolean | null | bigint; /** * The type name identifier. */ readonly type = "literal"; - constructor(value: string | number | boolean) { + constructor(value: LiteralType["value"]) { super(); this.value = value; } @@ -44,6 +44,9 @@ export class LiteralType extends Type { * Return a string representation of this type. */ toString(): string { + if (typeof this.value === "bigint") { + return this.value.toString(); + } return JSON.stringify(this.value); } } diff --git a/src/lib/models/types/reference.ts b/src/lib/models/types/reference.ts index c8214936e..5a4c8125f 100644 --- a/src/lib/models/types/reference.ts +++ b/src/lib/models/types/reference.ts @@ -82,10 +82,13 @@ export class ReferenceType extends Type { * @returns TRUE if the given type equals this type, FALSE otherwise. */ equals(other: ReferenceType): boolean { - return ( - other instanceof ReferenceType && - other.reflection === this.reflection - ); + if (other instanceof ReferenceType) { + if (this.reflection != null) { + return this.reflection === other.reflection; + } + return this._target === other._target; + } + return false; } /** diff --git a/src/lib/output/helpers/json.ts b/src/lib/output/helpers/json.ts deleted file mode 100644 index 26f14d554..000000000 --- a/src/lib/output/helpers/json.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * JSON stringify the given value, useful for debugging. - */ -export function json(this: any, options: any) { - return JSON.stringify(options); -} diff --git a/src/lib/output/helpers/stringify.ts b/src/lib/output/helpers/stringify.ts new file mode 100644 index 000000000..e9e422e27 --- /dev/null +++ b/src/lib/output/helpers/stringify.ts @@ -0,0 +1,6 @@ +export function stringify(data: unknown) { + if (typeof data === "bigint") { + return data.toString() + "n"; + } + return JSON.stringify(data); +} diff --git a/src/lib/serialization/schema.ts b/src/lib/serialization/schema.ts index 82bed1176..78c5a32e9 100644 --- a/src/lib/serialization/schema.ts +++ b/src/lib/serialization/schema.ts @@ -101,6 +101,13 @@ type _ModelToObject = type Primitive = string | number | undefined | null | boolean; +// Separate helper so that we can trigger distribution. +type ToSerialized = T extends Primitive + ? T + : T extends bigint + ? { value: string; negative: boolean } + : ModelToObject; + /** * Helper to describe a set of serialized properties. Primitive types are returned * directly, while other models are first passed through ModelToObject. @@ -108,7 +115,7 @@ type Primitive = string | number | undefined | null | boolean; * is a plain object that consumers may modify as they choose, TypeDoc doesn't care. */ type S = { - -readonly [K2 in K]: T[K2] extends Primitive ? T[K2] : ModelToObject; + -readonly [K2 in K]: ToSerialized; }; // Reflections diff --git a/src/lib/serialization/serializers/types/literal.ts b/src/lib/serialization/serializers/types/literal.ts index 2c06f7310..ca6da8a57 100644 --- a/src/lib/serialization/serializers/types/literal.ts +++ b/src/lib/serialization/serializers/types/literal.ts @@ -14,6 +14,16 @@ export class LiteralTypeSerializer extends TypeSerializerComponent< type: LiteralType, obj: Pick ): JSONLiteralType { + if (typeof type.value === "bigint") { + return { + ...obj, + value: { + value: type.value.toString().replace("-", ""), + negative: type.value < 0n, + }, + }; + } + return { ...obj, value: type.value, diff --git a/src/test/converter/function/specs.json b/src/test/converter/function/specs.json index 5c0f7bf0b..95568ad76 100644 --- a/src/test/converter/function/specs.json +++ b/src/test/converter/function/specs.json @@ -177,8 +177,8 @@ "name": "T" }, { - "type": "unknown", - "name": "null" + "type": "literal", + "value": null }, { "type": "intrinsic", @@ -574,8 +574,8 @@ "name": "T" }, { - "type": "unknown", - "name": "null" + "type": "literal", + "value": null }, { "type": "intrinsic", diff --git a/src/test/converter/types/general.ts b/src/test/converter/types/general.ts new file mode 100644 index 000000000..3df3ded4c --- /dev/null +++ b/src/test/converter/types/general.ts @@ -0,0 +1,7 @@ +export type BigIntLiteral = 1n; +export type NegativeBigIntLiteral = -1n; + +declare function makeValue(): T; + +export const BigIntLiteralType = makeValue<1n>(); +export const NegativeBigIntLiteralType = makeValue<-1n>(); diff --git a/src/test/converter/types/specs.json b/src/test/converter/types/specs.json index a6ec432fa..b82daa20f 100644 --- a/src/test/converter/types/specs.json +++ b/src/test/converter/types/specs.json @@ -6,20 +6,109 @@ "children": [ { "id": 1, + "name": "general", + "kind": 1, + "kindString": "Module", + "flags": {}, + "children": [ + { + "id": 2, + "name": "BigIntLiteral", + "kind": 4194304, + "kindString": "Type alias", + "flags": {}, + "type": { + "type": "literal", + "value": { + "value": "1", + "negative": false + } + } + }, + { + "id": 3, + "name": "NegativeBigIntLiteral", + "kind": 4194304, + "kindString": "Type alias", + "flags": {}, + "type": { + "type": "literal", + "value": { + "value": "1", + "negative": true + } + } + }, + { + "id": 4, + "name": "BigIntLiteralType", + "kind": 32, + "kindString": "Variable", + "flags": { + "isConst": true + }, + "type": { + "type": "literal", + "value": { + "value": "1", + "negative": false + } + }, + "defaultValue": "makeValue<1n>()" + }, + { + "id": 5, + "name": "NegativeBigIntLiteralType", + "kind": 32, + "kindString": "Variable", + "flags": { + "isConst": true + }, + "type": { + "type": "literal", + "value": { + "value": "1", + "negative": true + } + }, + "defaultValue": "makeValue<-1n>()" + } + ], + "groups": [ + { + "title": "Type aliases", + "kind": 4194304, + "children": [ + 2, + 3 + ] + }, + { + "title": "Variables", + "kind": 32, + "children": [ + 4, + 5 + ] + } + ] + }, + { + "id": 6, "name": "mapped", "kind": 1, "kindString": "Module", "flags": {}, "children": [ { - "id": 6, + "id": 11, "name": "Mappy", "kind": 4194304, "kindString": "Type alias", "flags": {}, "typeParameter": [ { - "id": 7, + "id": 12, "name": "T", "kind": 131072, "kindString": "Type parameter", @@ -51,21 +140,21 @@ } }, { - "id": 2, + "id": 7, "name": "mapped", "kind": 64, "kindString": "Function", "flags": {}, "signatures": [ { - "id": 3, + "id": 8, "name": "mapped", "kind": 4096, "kindString": "Call signature", "flags": {}, "typeParameter": [ { - "id": 4, + "id": 9, "name": "T", "kind": 131072, "kindString": "Type parameter", @@ -74,7 +163,7 @@ ], "parameters": [ { - "id": 5, + "id": 10, "name": "arg", "kind": 32768, "kindString": "Parameter", @@ -121,27 +210,27 @@ "title": "Type aliases", "kind": 4194304, "children": [ - 6 + 11 ] }, { "title": "Functions", "kind": 64, "children": [ - 2 + 7 ] } ] }, { - "id": 8, + "id": 13, "name": "parens", "kind": 1, "kindString": "Module", "flags": {}, "children": [ { - "id": 9, + "id": 14, "name": "ZZ", "kind": 4194304, "kindString": "Type alias", @@ -156,14 +245,14 @@ { "type": "reflection", "declaration": { - "id": 10, + "id": 15, "name": "__type", "kind": 65536, "kindString": "Type literal", "flags": {}, "children": [ { - "id": 11, + "id": 16, "name": "a", "kind": 32, "kindString": "Variable", @@ -179,7 +268,7 @@ "title": "Variables", "kind": 32, "children": [ - 11 + 16 ] } ] @@ -194,20 +283,20 @@ "title": "Type aliases", "kind": 4194304, "children": [ - 9 + 14 ] } ] }, { - "id": 12, + "id": 17, "name": "query", "kind": 1, "kindString": "Module", "flags": {}, "children": [ { - "id": 14, + "id": 19, "name": "TypeOfX", "kind": 4194304, "kindString": "Type alias", @@ -216,13 +305,13 @@ "type": "query", "queryType": { "type": "reference", - "id": 13, + "id": 18, "name": "x" } } }, { - "id": 13, + "id": 18, "name": "x", "kind": 32, "kindString": "Variable", @@ -241,27 +330,27 @@ "title": "Type aliases", "kind": 4194304, "children": [ - 14 + 19 ] }, { "title": "Variables", "kind": 32, "children": [ - 13 + 18 ] } ] }, { - "id": 15, + "id": 20, "name": "tuple", "kind": 1, "kindString": "Module", "flags": {}, "children": [ { - "id": 16, + "id": 21, "name": "NamedTuple", "kind": 4194304, "kindString": "Type alias", @@ -291,7 +380,7 @@ } }, { - "id": 17, + "id": 22, "name": "namedTuple", "kind": 32, "kindString": "Variable", @@ -319,27 +408,27 @@ "title": "Type aliases", "kind": 4194304, "children": [ - 16 + 21 ] }, { "title": "Variables", "kind": 32, "children": [ - 17 + 22 ] } ] }, { - "id": 18, + "id": 23, "name": "type-operator", "kind": 1, "kindString": "Module", "flags": {}, "children": [ { - "id": 20, + "id": 25, "name": "B", "kind": 4194304, "kindString": "Type alias", @@ -357,7 +446,7 @@ } }, { - "id": 21, + "id": 26, "name": "C", "kind": 4194304, "kindString": "Type alias", @@ -365,14 +454,14 @@ "type": { "type": "reflection", "declaration": { - "id": 22, + "id": 27, "name": "__type", "kind": 65536, "kindString": "Type literal", "flags": {}, "children": [ { - "id": 23, + "id": 28, "name": "prop1", "kind": 32, "kindString": "Variable", @@ -383,7 +472,7 @@ } }, { - "id": 24, + "id": 29, "name": "prop2", "kind": 32, "kindString": "Variable", @@ -399,8 +488,8 @@ "title": "Variables", "kind": 32, "children": [ - 23, - 24 + 28, + 29 ] } ] @@ -408,7 +497,7 @@ } }, { - "id": 25, + "id": 30, "name": "D", "kind": 4194304, "kindString": "Type alias", @@ -418,13 +507,13 @@ "operator": "keyof", "target": { "type": "reference", - "id": 21, + "id": 26, "name": "C" } } }, { - "id": 19, + "id": 24, "name": "a", "kind": 32, "kindString": "Variable", @@ -447,29 +536,29 @@ "title": "Type aliases", "kind": 4194304, "children": [ - 20, - 21, - 25 + 25, + 26, + 30 ] }, { "title": "Variables", "kind": 32, "children": [ - 19 + 24 ] } ] }, { - "id": 26, + "id": 31, "name": "union-or-intersection", "kind": 1, "kindString": "Module", "flags": {}, "children": [ { - "id": 27, + "id": 32, "name": "FirstType", "kind": 256, "kindString": "Interface", @@ -479,7 +568,7 @@ }, "children": [ { - "id": 28, + "id": 33, "name": "firstProperty", "kind": 1024, "kindString": "Property", @@ -498,13 +587,13 @@ "title": "Properties", "kind": 1024, "children": [ - 28 + 33 ] } ] }, { - "id": 29, + "id": 34, "name": "SecondType", "kind": 256, "kindString": "Interface", @@ -514,7 +603,7 @@ }, "children": [ { - "id": 30, + "id": 35, "name": "secondProperty", "kind": 1024, "kindString": "Property", @@ -533,13 +622,13 @@ "title": "Properties", "kind": 1024, "children": [ - 30 + 35 ] } ] }, { - "id": 31, + "id": 36, "name": "ThirdType", "kind": 256, "kindString": "Interface", @@ -549,7 +638,7 @@ }, "children": [ { - "id": 34, + "id": 39, "name": "thirdComplexProperty", "kind": 1024, "kindString": "Property", @@ -569,12 +658,12 @@ "types": [ { "type": "reference", - "id": 27, + "id": 32, "name": "FirstType" }, { "type": "reference", - "id": 29, + "id": 34, "name": "SecondType" } ] @@ -589,7 +678,7 @@ } }, { - "id": 33, + "id": 38, "name": "thirdIntersectionProperty", "kind": 1024, "kindString": "Property", @@ -602,19 +691,19 @@ "types": [ { "type": "reference", - "id": 27, + "id": 32, "name": "FirstType" }, { "type": "reference", - "id": 31, + "id": 36, "name": "ThirdType" } ] } }, { - "id": 32, + "id": 37, "name": "thirdUnionProperty", "kind": 1024, "kindString": "Property", @@ -627,12 +716,12 @@ "types": [ { "type": "reference", - "id": 27, + "id": 32, "name": "FirstType" }, { "type": "reference", - "id": 29, + "id": 34, "name": "SecondType" } ] @@ -644,9 +733,9 @@ "title": "Properties", "kind": 1024, "children": [ - 34, - 33, - 32 + 39, + 38, + 37 ] } ] @@ -657,9 +746,9 @@ "title": "Interfaces", "kind": 256, "children": [ - 27, - 29, - 31 + 32, + 34, + 36 ] } ] @@ -671,11 +760,12 @@ "kind": 1, "children": [ 1, - 8, - 12, - 15, - 18, - 26 + 6, + 13, + 17, + 20, + 23, + 31 ] } ] diff --git a/src/test/renderer/specs/classes/access.privateclass.html b/src/test/renderer/specs/classes/access.privateclass.html index 832244479..c477d930d 100644 --- a/src/test/renderer/specs/classes/access.privateclass.html +++ b/src/test/renderer/specs/classes/access.privateclass.html @@ -247,6 +247,9 @@

Returns void
    +
  • + BigIntLiteral +
  • fakePrivateVariable
  • diff --git a/src/test/renderer/specs/modules/access.html b/src/test/renderer/specs/modules/access.html index 54989449e..c7e1d2b3a 100644 --- a/src/test/renderer/specs/modules/access.html +++ b/src/test/renderer/specs/modules/access.html @@ -80,6 +80,12 @@

    Classes

  • PrivateClass
+
+

Type aliases

+ +

Variables

    @@ -97,6 +103,16 @@

    Functions

+
+

Type aliases

+
+ +

BigIntLiteral

+
BigIntLiteral: -123n
+ +
+

Variables

@@ -223,6 +239,9 @@

Returns void PrivateClass +
  • + BigIntLiteral +
  • fakePrivateVariable
  • diff --git a/tsconfig.json b/tsconfig.json index 91f369a3d..ee2e91b06 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "module": "CommonJS", "lib": ["ES2018"], - "target": "ES2018", + "target": "ES2020", "experimentalDecorators": true,