Skip to content

Commit

Permalink
Add type information to enum members
Browse files Browse the repository at this point in the history
Resolves #1942.
  • Loading branch information
Gerrit0 committed May 30, 2022
1 parent f82abcb commit 261b5a1
Show file tree
Hide file tree
Showing 21 changed files with 152 additions and 50 deletions.
7 changes: 5 additions & 2 deletions CHANGELOG.md
Expand Up @@ -4,10 +4,13 @@

- Added support for TypeScript 4.7, #1935.
- Support enum-like objects with numeric literal values tagged with `@enum`, #1918.
- Enum member reflections will now have their `type` set to either a `LiteralType` with a string or numeric value or an `IntrinsicType` with type `number`, #1942.
Using `defaultValue` on `EnumMember` reflections is now deprecated, and will be broken in 0.23.

### Bug Fixes

- Fixed invalid type output in some uncommon edge cases, TypeDoc also now renders fewer superfluous parenthesis when creating types.
- TypeDoc is now more consistent about ordering with `enum-value-ascending` or `enum-value-descending` sort strategies in mixed string/number enums.

### Thanks!

Expand Down Expand Up @@ -844,7 +847,7 @@
- isExternal flag wasn't set properly
- JSON schema had incorrect value types, closes #1389
- Hidden module-namespaces, closes #1396
- Some issues with inheritence
- Some issues with inheritance
- We pick up all properties now
- Support for specify a directory as an entry point
- Lint
Expand Down Expand Up @@ -963,7 +966,7 @@
- Missed a test configuration update
- Rename external modules to modules, closes #109
- Check for compiler errors before converting
- Moved @types/minimatch dependency to devDepencencies (#1206)
- Moved @types/minimatch dependency to devDependencies (#1206)
- Plugin resolution for relative paths (#1194), closes #1188

### Thanks!
Expand Down
7 changes: 4 additions & 3 deletions scripts/rebuild_specs.js
Expand Up @@ -85,9 +85,10 @@ function rebuildConverterTests(dirs) {
);
const serialized = app.serializer.toObject(result);

const data = JSON.stringify(serialized, null, " ")
.split(TypeDoc.normalizePath(base))
.join("%BASE%");
const data =
JSON.stringify(serialized, null, " ")
.split(TypeDoc.normalizePath(base))
.join("%BASE%") + "\n";
after();
fs.writeFileSync(out.replace("dist", "src"), data);
}
Expand Down
26 changes: 15 additions & 11 deletions src/lib/converter/symbols.ts
Expand Up @@ -2,6 +2,8 @@ import * as assert from "assert";
import * as ts from "typescript";
import {
DeclarationReflection,
IntrinsicType,
LiteralType,
ReferenceReflection,
Reflection,
ReflectionFlag,
Expand Down Expand Up @@ -245,11 +247,18 @@ function convertEnumMember(
exportSymbol
);

reflection.defaultValue = JSON.stringify(
context.checker.getConstantValue(
symbol.getDeclarations()![0] as ts.EnumMember
)
const defaultValue = context.checker.getConstantValue(
symbol.getDeclarations()![0] as ts.EnumMember
);
reflection.defaultValue = JSON.stringify(defaultValue);

if (defaultValue !== undefined) {
reflection.type = new LiteralType(defaultValue);
} else {
// We know this has to be a number, because computed values aren't allowed
// in string enums, so otherwise we would have to have the constant value
reflection.type = new IntrinsicType("number");
}

context.finalizeDeclarationReflection(reflection, symbol, exportSymbol);
}
Expand Down Expand Up @@ -657,16 +666,10 @@ function convertProperty(
}
reflection.defaultValue = declaration && convertDefaultValue(declaration);

// FIXME: This is a horrible hack because getTypeOfSymbol is not exposed.
// The right solution here is probably to keep track of parent nodes...
// but that's tricky because not every reflection is guaranteed to have a
// parent node. This will probably break in a future TS version.
reflection.type = context.converter.convertType(
context,
(context.isConvertingTypeNode() ? parameterType : void 0) ??
context.checker.getTypeOfSymbolAtLocation(symbol, {
kind: ts.SyntaxKind.SourceFile,
} as any)
context.checker.getTypeOfSymbol(symbol)
);

if (reflection.flags.isOptional) {
Expand Down Expand Up @@ -896,6 +899,7 @@ function convertVariableAsEnum(
assert(propType.isStringLiteral() || propType.isNumberLiteral());

reflection.defaultValue = JSON.stringify(propType.value);
reflection.type = new LiteralType(propType.value);

rc.finalizeDeclarationReflection(reflection, prop, void 0);
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib/models/reflections/declaration.ts
Expand Up @@ -79,6 +79,8 @@ export class DeclarationReflection extends ContainerReflection {
* The default value of this reflection.
*
* Applies to function parameters.
*
* Note: Using this for enum members is DEPRECATED and will be removed in 0.23.
*/
defaultValue?: string;

Expand Down
4 changes: 2 additions & 2 deletions src/lib/output/themes/default/partials/member.declaration.tsx
@@ -1,4 +1,4 @@
import { DeclarationReflection, ReflectionType } from "../../../../models";
import { DeclarationReflection, ReflectionKind, ReflectionType } from "../../../../models";
import { JSX } from "../../../../utils";
import { renderTypeParametersSignature, wbr } from "../../lib";
import type { DefaultThemeRenderContext } from "../DefaultThemeRenderContext";
Expand All @@ -14,7 +14,7 @@ export const memberDeclaration = (context: DefaultThemeRenderContext, props: Dec
{context.type(props.type)}
</>
)}
{!!props.defaultValue && (
{!!props.defaultValue && props.kind !== ReflectionKind.EnumMember && (
<>
<span class="tsd-signature-symbol">
{" = "}
Expand Down
3 changes: 3 additions & 0 deletions src/lib/types/ts-internal/index.d.ts
Expand Up @@ -20,6 +20,9 @@ declare module "typescript" {
getTypePredicateOfSignature(
signature: ts.Signature
): ts.TypePredicate | undefined;

//https://github.com/microsoft/TypeScript/blob/v4.7.2/src/compiler/types.ts#L4188
getTypeOfSymbol(symbol: Symbol): Type;
}

export interface Signature {
Expand Down
29 changes: 17 additions & 12 deletions src/lib/utils/sort.ts
Expand Up @@ -5,6 +5,7 @@

import { ReflectionKind } from "../models/reflections/kind";
import type { DeclarationReflection } from "../models/reflections/declaration";
import { LiteralType } from "../models";

export const SORT_STRATEGIES = [
"source-order",
Expand Down Expand Up @@ -59,10 +60,12 @@ const sorts: Record<
a.kind == ReflectionKind.EnumMember &&
b.kind == ReflectionKind.EnumMember
) {
return (
parseFloat(a.defaultValue ?? "0") <
parseFloat(b.defaultValue ?? "0")
);
const aValue =
a.type instanceof LiteralType ? a.type.value : -Infinity;
const bValue =
b.type instanceof LiteralType ? b.type.value : -Infinity;

return aValue! < bValue!;
}
return false;
},
Expand All @@ -71,10 +74,12 @@ const sorts: Record<
a.kind == ReflectionKind.EnumMember &&
b.kind == ReflectionKind.EnumMember
) {
return (
parseFloat(b.defaultValue ?? "0") <
parseFloat(a.defaultValue ?? "0")
);
const aValue =
a.type instanceof LiteralType ? a.type.value : -Infinity;
const bValue =
b.type instanceof LiteralType ? b.type.value : -Infinity;

return bValue! < aValue!;
}
return false;
},
Expand Down Expand Up @@ -138,11 +143,11 @@ const sorts: Record<
};

export function sortReflections(
strategies: DeclarationReflection[],
strats: readonly SortStrategy[]
reflections: DeclarationReflection[],
strategies: readonly SortStrategy[]
) {
strategies.sort((a, b) => {
for (const s of strats) {
reflections.sort((a, b) => {
for (const s of strategies) {
if (sorts[s](a, b)) {
return -1;
}
Expand Down
3 changes: 3 additions & 0 deletions src/test/behaviorTests.ts
@@ -1,6 +1,7 @@
import { deepStrictEqual as equal, ok } from "assert";
import {
DeclarationReflection,
LiteralType,
ProjectReflection,
ReflectionKind,
} from "../lib/models";
Expand All @@ -25,6 +26,7 @@ export const behaviorTests: Record<
"SomeEnumLikeTagged"
);
const A = query(project, "SomeEnumLikeTagged.a");
equal(A.type, new LiteralType("a"));
equal(A.defaultValue, '"a"');

const ManualEnum = query(project, "ManualEnum");
Expand Down Expand Up @@ -56,6 +58,7 @@ export const behaviorTests: Record<
"SomeEnumLikeTaggedNumeric"
);
const B = query(project, "SomeEnumLikeTaggedNumeric.b");
equal(B.type, new LiteralType(1));
equal(B.defaultValue, "1");

const ManualEnumNumeric = query(project, "ManualEnumNumeric");
Expand Down
2 changes: 1 addition & 1 deletion src/test/converter/comment/specs.json
Expand Up @@ -361,4 +361,4 @@
]
}
]
}
}
2 changes: 1 addition & 1 deletion src/test/converter/declaration/specs.json
Expand Up @@ -241,4 +241,4 @@
]
}
]
}
}
32 changes: 32 additions & 0 deletions src/test/converter/enum/specs.json
Expand Up @@ -88,6 +88,10 @@
"kind": 16,
"kindString": "Enumeration Member",
"flags": {},
"type": {
"type": "literal",
"value": 1
},
"defaultValue": "1"
},
{
Expand All @@ -96,6 +100,10 @@
"kind": 16,
"kindString": "Enumeration Member",
"flags": {},
"type": {
"type": "literal",
"value": 2
},
"defaultValue": "2"
}
],
Expand Down Expand Up @@ -129,6 +137,10 @@
"comment": {
"shortText": "This is the first enum member."
},
"type": {
"type": "literal",
"value": 1
},
"defaultValue": "1"
},
{
Expand All @@ -140,6 +152,10 @@
"comment": {
"shortText": "This is the second enum member."
},
"type": {
"type": "literal",
"value": 2
},
"defaultValue": "2"
},
{
Expand All @@ -151,6 +167,10 @@
"comment": {
"shortText": "This is the third enum member."
},
"type": {
"type": "literal",
"value": 4
},
"defaultValue": "4"
}
],
Expand Down Expand Up @@ -185,6 +205,10 @@
"comment": {
"shortText": "This is the first enum member."
},
"type": {
"type": "literal",
"value": 1
},
"defaultValue": "1"
},
{
Expand All @@ -196,6 +220,10 @@
"comment": {
"shortText": "This is the second enum member."
},
"type": {
"type": "literal",
"value": 2
},
"defaultValue": "2"
},
{
Expand All @@ -207,6 +235,10 @@
"comment": {
"shortText": "This is the third enum member."
},
"type": {
"type": "literal",
"value": 4
},
"defaultValue": "4"
}
],
Expand Down

0 comments on commit 261b5a1

Please sign in to comment.