Skip to content

Commit

Permalink
feat: Support for the remaining literal types
Browse files Browse the repository at this point in the history
... at least, I think I got them all.
  • Loading branch information
Gerrit0 committed Nov 1, 2020
1 parent 017fad1 commit 695f5c7
Show file tree
Hide file tree
Showing 17 changed files with 289 additions and 102 deletions.
2 changes: 2 additions & 0 deletions examples/basic/src/access.ts
Expand Up @@ -59,3 +59,5 @@ export class PrivateClass {
export module PrivateModule {
export function functionInsidePrivateModule() {}
}

export type BigIntLiteral = -123n;
6 changes: 3 additions & 3 deletions package-lock.json

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

4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -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",
Expand All @@ -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"
Expand Down
14 changes: 13 additions & 1 deletion src/lib/converter/nodes/block.ts
Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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;
}
51 changes: 41 additions & 10 deletions src/lib/converter/types.ts
Expand Up @@ -277,8 +277,6 @@ const keywordConverter: TypeConverter<ts.KeywordTypeNode> = {
},
};

// literal

const parensConverter: TypeConverter<ts.ParenthesizedTypeNode> = {
kind: [ts.SyntaxKind.ParenthesizedType],
convert(context, node) {
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
},
};
Expand Down
7 changes: 5 additions & 2 deletions src/lib/models/types/literal.ts
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
}
}
11 changes: 7 additions & 4 deletions src/lib/models/types/reference.ts
Expand Up @@ -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;
}

/**
Expand Down
6 changes: 0 additions & 6 deletions src/lib/output/helpers/json.ts

This file was deleted.

6 changes: 6 additions & 0 deletions 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);
}
9 changes: 8 additions & 1 deletion src/lib/serialization/schema.ts
Expand Up @@ -101,14 +101,21 @@ type _ModelToObject<T> =

type Primitive = string | number | undefined | null | boolean;

// Separate helper so that we can trigger distribution.
type ToSerialized<T> = T extends Primitive
? T
: T extends bigint
? { value: string; negative: boolean }
: ModelToObject<T>;

/**
* Helper to describe a set of serialized properties. Primitive types are returned
* directly, while other models are first passed through ModelToObject.
* This helper removes the readonly modifier from properties since the result of serialization
* is a plain object that consumers may modify as they choose, TypeDoc doesn't care.
*/
type S<T, K extends keyof T> = {
-readonly [K2 in K]: T[K2] extends Primitive ? T[K2] : ModelToObject<T[K2]>;
-readonly [K2 in K]: ToSerialized<T[K2]>;
};

// Reflections
Expand Down
10 changes: 10 additions & 0 deletions src/lib/serialization/serializers/types/literal.ts
Expand Up @@ -14,6 +14,16 @@ export class LiteralTypeSerializer extends TypeSerializerComponent<
type: LiteralType,
obj: Pick<JSONLiteralType, "type">
): JSONLiteralType {
if (typeof type.value === "bigint") {
return {
...obj,
value: {
value: type.value.toString().replace("-", ""),
negative: type.value < 0n,
},
};
}

return {
...obj,
value: type.value,
Expand Down
8 changes: 4 additions & 4 deletions src/test/converter/function/specs.json
Expand Up @@ -177,8 +177,8 @@
"name": "T"
},
{
"type": "unknown",
"name": "null"
"type": "literal",
"value": null
},
{
"type": "intrinsic",
Expand Down Expand Up @@ -574,8 +574,8 @@
"name": "T"
},
{
"type": "unknown",
"name": "null"
"type": "literal",
"value": null
},
{
"type": "intrinsic",
Expand Down
7 changes: 7 additions & 0 deletions src/test/converter/types/general.ts
@@ -0,0 +1,7 @@
export type BigIntLiteral = 1n;
export type NegativeBigIntLiteral = -1n;

declare function makeValue<T>(): T;

export const BigIntLiteralType = makeValue<1n>();
export const NegativeBigIntLiteralType = makeValue<-1n>();

0 comments on commit 695f5c7

Please sign in to comment.