Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make hidden undefined #1928

Draft
wants to merge 1 commit into
base: next
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 0 additions & 2 deletions factory/formatter.ts
Expand Up @@ -12,7 +12,6 @@ import { ConstructorTypeFormatter } from "../src/TypeFormatter/ConstructorTypeFo
import { DefinitionTypeFormatter } from "../src/TypeFormatter/DefinitionTypeFormatter.js";
import { EnumTypeFormatter } from "../src/TypeFormatter/EnumTypeFormatter.js";
import { FunctionTypeFormatter } from "../src/TypeFormatter/FunctionTypeFormatter.js";
import { HiddenTypeFormatter } from "../src/TypeFormatter/HiddenTypeFormatter.js";
import { IntersectionTypeFormatter } from "../src/TypeFormatter/IntersectionTypeFormatter.js";
import { LiteralTypeFormatter } from "../src/TypeFormatter/LiteralTypeFormatter.js";
import { LiteralUnionTypeFormatter } from "../src/TypeFormatter/LiteralUnionTypeFormatter.js";
Expand Down Expand Up @@ -58,7 +57,6 @@ export function createFormatter(config: CompletedConfig, augmentor?: FormatterAu
.addTypeFormatter(new UndefinedTypeFormatter())
.addTypeFormatter(new UnknownTypeFormatter())
.addTypeFormatter(new VoidTypeFormatter())
.addTypeFormatter(new HiddenTypeFormatter())
.addTypeFormatter(new NeverTypeFormatter())

.addTypeFormatter(new LiteralTypeFormatter())
Expand Down
2 changes: 0 additions & 2 deletions index.ts
Expand Up @@ -49,7 +49,6 @@ export * from "./src/Type/BooleanType.js";
export * from "./src/Type/DefinitionType.js";
export * from "./src/Type/EnumType.js";
export * from "./src/Type/FunctionType.js";
export * from "./src/Type/HiddenType.js";
export * from "./src/Type/IntersectionType.js";
export * from "./src/Type/LiteralType.js";
export * from "./src/Type/NeverType.js";
Expand Down Expand Up @@ -83,7 +82,6 @@ export * from "./src/TypeFormatter/ArrayTypeFormatter.js";
export * from "./src/TypeFormatter/BooleanTypeFormatter.js";
export * from "./src/TypeFormatter/DefinitionTypeFormatter.js";
export * from "./src/TypeFormatter/EnumTypeFormatter.js";
export * from "./src/TypeFormatter/HiddenTypeFormatter.js";
export * from "./src/TypeFormatter/IntersectionTypeFormatter.js";
export * from "./src/TypeFormatter/LiteralTypeFormatter.js";
export * from "./src/TypeFormatter/LiteralUnionTypeFormatter.js";
Expand Down
4 changes: 2 additions & 2 deletions src/ChainNodeParser.ts
Expand Up @@ -7,7 +7,7 @@ import { BaseType } from "./Type/BaseType.js";
import { ReferenceType } from "./Type/ReferenceType.js";

export class ChainNodeParser implements SubNodeParser, MutableParser {
protected readonly typeCaches = new WeakMap<ts.Node, Map<string, BaseType>>();
protected readonly typeCaches = new WeakMap<ts.Node, Map<string, BaseType | undefined>>();

public constructor(
protected typeChecker: ts.TypeChecker,
Expand All @@ -23,7 +23,7 @@ export class ChainNodeParser implements SubNodeParser, MutableParser {
return this.nodeParsers.some((nodeParser) => nodeParser.supportsNode(node));
}

public createType(node: ts.Node, context: Context, reference?: ReferenceType): BaseType {
public createType(node: ts.Node, context: Context, reference?: ReferenceType): BaseType | undefined {
let typeCache = this.typeCaches.get(node);
if (typeCache == null) {
typeCache = new Map<string, BaseType>();
Expand Down
2 changes: 1 addition & 1 deletion src/CircularReferenceNodeParser.ts
Expand Up @@ -13,7 +13,7 @@ export class CircularReferenceNodeParser implements SubNodeParser {
public supportsNode(node: ts.Node): boolean {
return this.childNodeParser.supportsNode(node);
}
public createType(node: ts.Node, context: Context): BaseType {
public createType(node: ts.Node, context: Context): BaseType | undefined {
const key = getKey(node, context);
if (this.circular.has(key)) {
return this.circular.get(key)!;
Expand Down
3 changes: 2 additions & 1 deletion src/ExposeNodeParser.ts
Expand Up @@ -19,8 +19,9 @@
return this.subNodeParser.supportsNode(node);
}

public createType(node: ts.Node, context: Context, reference?: ReferenceType): BaseType {
public createType(node: ts.Node, context: Context, reference?: ReferenceType): BaseType | undefined {
const baseType = this.subNodeParser.createType(node, context, reference);
if (!baseType) return undefined;

if (!this.isExportNode(node)) {
return baseType;
Expand All @@ -38,7 +39,7 @@
return false;
}

const localSymbol: ts.Symbol = (node as any).localSymbol;

Check warning on line 42 in src/ExposeNodeParser.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest)

Unsafe assignment of an `any` value

Check warning on line 42 in src/ExposeNodeParser.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest)

Unsafe member access .localSymbol on an `any` value

Check warning on line 42 in src/ExposeNodeParser.ts

View workflow job for this annotation

GitHub Actions / Test (windows-latest)

Unsafe assignment of an `any` value

Check warning on line 42 in src/ExposeNodeParser.ts

View workflow job for this annotation

GitHub Actions / Test (windows-latest)

Unsafe member access .localSymbol on an `any` value
return localSymbol ? "exportSymbol" in localSymbol : false;
}

Expand Down
2 changes: 1 addition & 1 deletion src/NodeParser.ts
Expand Up @@ -61,5 +61,5 @@ export class Context {
}

export interface NodeParser {
createType(node: ts.Node, context: Context, reference?: ReferenceType): BaseType;
createType(node: ts.Node, context: Context, reference?: ReferenceType): BaseType | undefined;
}
6 changes: 5 additions & 1 deletion src/NodeParser/AnnotatedNodeParser.ts
Expand Up @@ -21,7 +21,7 @@ export class AnnotatedNodeParser implements SubNodeParser {
return this.childNodeParser.supportsNode(node);
}

public createType(node: ts.Node, context: Context, reference?: ReferenceType): BaseType {
public createType(node: ts.Node, context: Context, reference?: ReferenceType): BaseType | undefined {
const annotatedNode = this.getAnnotatedNode(node);
let annotations = this.annotationsReader.getAnnotations(annotatedNode);
const nullable = this.getNullable(annotatedNode);
Expand All @@ -33,6 +33,10 @@ export class AnnotatedNodeParser implements SubNodeParser {

const baseType = this.childNodeParser.createType(node, context, reference);

if (!baseType) {
return undefined;
}

// Don't return annotations for lib types such as Exclude.
// Sourceless nodes may not have a fileName, just ignore them.
if (node.getSourceFile()?.fileName.match(/[/\\]typescript[/\\]lib[/\\]lib\.[^/\\]+\.d\.ts$/i)) {
Expand Down
3 changes: 2 additions & 1 deletion src/NodeParser/ArrayLiteralExpressionNodeParser.ts
Expand Up @@ -3,6 +3,7 @@ import { Context, NodeParser } from "../NodeParser.js";
import { SubNodeParser } from "../SubNodeParser.js";
import { BaseType } from "../Type/BaseType.js";
import { TupleType } from "../Type/TupleType.js";
import { notUndefined } from "../Utils/notUndefined.js";

export class ArrayLiteralExpressionNodeParser implements SubNodeParser {
public constructor(protected childNodeParser: NodeParser) {}
Expand All @@ -12,7 +13,7 @@ export class ArrayLiteralExpressionNodeParser implements SubNodeParser {
}

public createType(node: ts.ArrayLiteralExpression, context: Context): BaseType {
const elements = node.elements.map((t) => this.childNodeParser.createType(t, context));
const elements = node.elements.map((t) => this.childNodeParser.createType(t, context)).filter(notUndefined);
return new TupleType(elements);
}
}
4 changes: 2 additions & 2 deletions src/NodeParser/ArrayNodeParser.ts
Expand Up @@ -11,8 +11,8 @@ export class ArrayNodeParser implements SubNodeParser {
return node.kind === ts.SyntaxKind.ArrayType;
}

public createType(node: ts.ArrayTypeNode, context: Context): BaseType {
public createType(node: ts.ArrayTypeNode, context: Context): BaseType | undefined {
const type = this.childNodeParser.createType(node.elementType, context);
return new ArrayType(type);
return type && new ArrayType(type);
}
}
2 changes: 1 addition & 1 deletion src/NodeParser/AsExpressionNodeParser.ts
Expand Up @@ -10,7 +10,7 @@ export class AsExpressionNodeParser implements SubNodeParser {
public supportsNode(node: ts.AsExpression): boolean {
return node.kind === ts.SyntaxKind.AsExpression;
}
public createType(node: ts.AsExpression, context: Context): BaseType {
public createType(node: ts.AsExpression, context: Context): BaseType | undefined {
// only implement `as const` for now where we just ignore the as expression
return this.childNodeParser.createType(node.expression, context);
}
Expand Down
4 changes: 2 additions & 2 deletions src/NodeParser/CallExpressionParser.ts
Expand Up @@ -16,13 +16,13 @@
public supportsNode(node: ts.CallExpression): boolean {
return node.kind === ts.SyntaxKind.CallExpression;
}
public createType(node: ts.CallExpression, context: Context): BaseType {
public createType(node: ts.CallExpression, context: Context): BaseType | undefined {
const type = this.typeChecker.getTypeAtLocation(node);

// FIXME: remove special case
if ((type as any)?.typeArguments) {

Check warning on line 23 in src/NodeParser/CallExpressionParser.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest)

Unsafe member access .typeArguments on an `any` value

Check warning on line 23 in src/NodeParser/CallExpressionParser.ts

View workflow job for this annotation

GitHub Actions / Test (windows-latest)

Unsafe member access .typeArguments on an `any` value
return new TupleType([
new UnionType((type as any).typeArguments[0].types.map((t: any) => new LiteralType(t.value))),

Check warning on line 25 in src/NodeParser/CallExpressionParser.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest)

Unsafe argument of type `any` assigned to a parameter of type `readonly BaseType[]`

Check warning on line 25 in src/NodeParser/CallExpressionParser.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest)

Unsafe call of an `any` typed value

Check warning on line 25 in src/NodeParser/CallExpressionParser.ts

View workflow job for this annotation

GitHub Actions / Test (windows-latest)

Unsafe argument of type `any` assigned to a parameter of type `readonly BaseType[]`

Check warning on line 25 in src/NodeParser/CallExpressionParser.ts

View workflow job for this annotation

GitHub Actions / Test (windows-latest)

Unsafe call of an `any` typed value
]);
}

Expand All @@ -42,7 +42,7 @@

for (const arg of node.arguments) {
const type = this.childNodeParser.createType(arg, parentContext);
subContext.pushArgument(type);
type && subContext.pushArgument(type);
}
return subContext;
}
Expand Down
6 changes: 5 additions & 1 deletion src/NodeParser/ConditionalTypeNodeParser.ts
Expand Up @@ -24,11 +24,15 @@ export class ConditionalTypeNodeParser implements SubNodeParser {
return node.kind === ts.SyntaxKind.ConditionalType;
}

public createType(node: ts.ConditionalTypeNode, context: Context): BaseType {
public createType(node: ts.ConditionalTypeNode, context: Context): BaseType | undefined {
const checkType = this.childNodeParser.createType(node.checkType, context);
const extendsType = this.childNodeParser.createType(node.extendsType, context);
const checkTypeParameterName = this.getTypeParameterName(node.checkType);

if (!checkType || !extendsType) {
return undefined;
}

const inferMap = new Map();

// If check-type is not a type parameter then condition is very simple, no type narrowing needed
Expand Down
5 changes: 1 addition & 4 deletions src/NodeParser/EnumNodeParser.ts
Expand Up @@ -3,7 +3,6 @@ import { Context } from "../NodeParser.js";
import { SubNodeParser } from "../SubNodeParser.js";
import { BaseType } from "../Type/BaseType.js";
import { EnumType, EnumValue } from "../Type/EnumType.js";
import { isNodeHidden } from "../Utils/isHidden.js";
import { getKey } from "../Utils/nodeKey.js";

export class EnumNodeParser implements SubNodeParser {
Expand All @@ -17,9 +16,7 @@ export class EnumNodeParser implements SubNodeParser {

return new EnumType(
`enum-${getKey(node, context)}`,
members
.filter((member: ts.EnumMember) => !isNodeHidden(member))
.map((member, index) => this.getMemberValue(member, index)),
members.map((member, index) => this.getMemberValue(member, index)),
);
}

Expand Down
4 changes: 2 additions & 2 deletions src/NodeParser/ExpressionWithTypeArgumentsNodeParser.ts
Expand Up @@ -12,7 +12,7 @@ export class ExpressionWithTypeArgumentsNodeParser implements SubNodeParser {
public supportsNode(node: ts.ExpressionWithTypeArguments): boolean {
return node.kind === ts.SyntaxKind.ExpressionWithTypeArguments;
}
public createType(node: ts.ExpressionWithTypeArguments, context: Context): BaseType {
public createType(node: ts.ExpressionWithTypeArguments, context: Context): BaseType | undefined {
const typeSymbol = this.typeChecker.getSymbolAtLocation(node.expression)!;
if (typeSymbol.flags & ts.SymbolFlags.Alias) {
const aliasedSymbol = this.typeChecker.getAliasedSymbol(typeSymbol);
Expand All @@ -32,7 +32,7 @@ export class ExpressionWithTypeArgumentsNodeParser implements SubNodeParser {
if (node.typeArguments?.length) {
node.typeArguments.forEach((typeArg) => {
const type = this.childNodeParser.createType(typeArg, parentContext);
subContext.pushArgument(type);
type && subContext.pushArgument(type);
});
}
return subContext;
Expand Down
7 changes: 4 additions & 3 deletions src/NodeParser/FunctionNodeParser.ts
Expand Up @@ -8,6 +8,7 @@ import { DefinitionType } from "../Type/DefinitionType.js";
import { Context, NodeParser } from "../NodeParser.js";
import { ObjectProperty, ObjectType } from "../Type/ObjectType.js";
import { getKey } from "../Utils/nodeKey.js";
import { notUndefined } from "../Utils/notUndefined.js";

export class FunctionNodeParser implements SubNodeParser {
constructor(
Expand Down Expand Up @@ -53,9 +54,9 @@ export function getNamedArguments(
return undefined;
}

const parameterTypes = node.parameters.map((parameter) => {
return childNodeParser.createType(parameter, context);
});
const parameterTypes = node.parameters
.map((parameter) => childNodeParser.createType(parameter, context))
.filter(notUndefined);

return new ObjectType(
`object-${getKey(node, context)}`,
Expand Down
6 changes: 2 additions & 4 deletions src/NodeParser/HiddenTypeNodeParser.ts
@@ -1,8 +1,6 @@
import ts from "typescript";
import { Context } from "../NodeParser.js";
import { SubNodeParser } from "../SubNodeParser.js";
import { BaseType } from "../Type/BaseType.js";
import { HiddenType } from "../Type/HiddenType.js";
import { isNodeHidden } from "../Utils/isHidden.js";

export class HiddenNodeParser implements SubNodeParser {
Expand All @@ -12,7 +10,7 @@ export class HiddenNodeParser implements SubNodeParser {
return isNodeHidden(node);
}

public createType(_node: ts.KeywordTypeNode, _context: Context): BaseType {
return new HiddenType();
public createType(_node: ts.KeywordTypeNode, _context: Context): undefined {
return undefined;
}
}
10 changes: 7 additions & 3 deletions src/NodeParser/IndexedAccessTypeNodeParser.ts
Expand Up @@ -45,15 +45,19 @@ export class IndexedAccessTypeNodeParser implements SubNodeParser {
return undefined;
}

public createType(node: ts.IndexedAccessTypeNode, context: Context): BaseType {
const indexType = derefType(this.childNodeParser.createType(node.indexType, context));
public createType(node: ts.IndexedAccessTypeNode, context: Context): BaseType | undefined {
const it = this.childNodeParser.createType(node.indexType, context);
if (!it) return undefined;
const indexType = derefType(it);
const indexedType = this.createIndexedType(node.objectType, context, indexType);

if (indexedType) {
return indexedType;
}

const objectType = derefType(this.childNodeParser.createType(node.objectType, context));
const ot = this.childNodeParser.createType(node.objectType, context);
if (!ot) return undefined;
const objectType = derefType(ot);
if (objectType instanceof NeverType || indexType instanceof NeverType) {
return new NeverType();
}
Expand Down
30 changes: 16 additions & 14 deletions src/NodeParser/InterfaceAndClassNodeParser.ts
Expand Up @@ -6,9 +6,9 @@ import { BaseType } from "../Type/BaseType.js";
import { NeverType } from "../Type/NeverType.js";
import { ObjectProperty, ObjectType } from "../Type/ObjectType.js";
import { ReferenceType } from "../Type/ReferenceType.js";
import { isNodeHidden } from "../Utils/isHidden.js";
import { isPublic, isStatic } from "../Utils/modifiers.js";
import { getKey } from "../Utils/nodeKey.js";
import { notUndefined } from "../Utils/notUndefined.js";

export class InterfaceAndClassNodeParser implements SubNodeParser {
public constructor(
Expand All @@ -25,15 +25,15 @@ export class InterfaceAndClassNodeParser implements SubNodeParser {
node: ts.InterfaceDeclaration | ts.ClassDeclaration,
context: Context,
reference?: ReferenceType,
): BaseType {
): BaseType | undefined {
if (node.typeParameters?.length) {
node.typeParameters.forEach((typeParam) => {
const nameSymbol = this.typeChecker.getSymbolAtLocation(typeParam.name)!;
context.pushParameter(nameSymbol.name);

if (typeParam.default) {
const type = this.childNodeParser.createType(typeParam.default, context);
context.setDefault(nameSymbol.name, type);
type && context.setDefault(nameSymbol.name, type);
}
});
}
Expand All @@ -56,7 +56,8 @@ export class InterfaceAndClassNodeParser implements SubNodeParser {
if (properties.length === 0 && additionalProperties === false) {
const arrayItemType = this.getArrayItemType(node);
if (arrayItemType) {
return new ArrayType(this.childNodeParser.createType(arrayItemType, context));
const type = this.childNodeParser.createType(arrayItemType, context);
return type && new ArrayType(type);
}
}

Expand Down Expand Up @@ -95,7 +96,9 @@ export class InterfaceAndClassNodeParser implements SubNodeParser {
return node.heritageClauses.reduce(
(result: BaseType[], baseType) => [
...result,
...baseType.types.map((expression) => this.childNodeParser.createType(expression, context)),
...baseType.types
.map((expression) => this.childNodeParser.createType(expression, context))
.filter(notUndefined),
],
[],
);
Expand All @@ -122,7 +125,7 @@ export class InterfaceAndClassNodeParser implements SubNodeParser {
},
[] as (ts.PropertyDeclaration | ts.PropertySignature | ts.ParameterPropertyDeclaration)[],
)
.filter((member) => isPublic(member) && !isStatic(member) && !isNodeHidden(member))
.filter((member) => isPublic(member) && !isStatic(member))
.reduce((entries, member) => {
let memberType: ts.Node | undefined = member.type;

Expand All @@ -138,14 +141,13 @@ export class InterfaceAndClassNodeParser implements SubNodeParser {
}
return entries;
}, [])
.map(
({ member, memberType }) =>
new ObjectProperty(
this.getPropertyName(member.name),
this.childNodeParser.createType(memberType, context),
!member.questionToken,
),
)
.map(({ member, memberType }) => {
const type = this.childNodeParser.createType(memberType, context);
return type
? new ObjectProperty(this.getPropertyName(member.name), type, !member.questionToken)
: undefined;
})
.filter(notUndefined)
.filter((prop) => {
const type = prop.getType();
if (prop.isRequired() && type instanceof NeverType) {
Expand Down
5 changes: 3 additions & 2 deletions src/NodeParser/IntersectionNodeParser.ts
Expand Up @@ -9,6 +9,7 @@ import { derefType } from "../Utils/derefType.js";
import { uniqueTypeArray } from "../Utils/uniqueTypeArray.js";
import { UndefinedType } from "../Type/UndefinedType.js";
import { NeverType } from "../Type/NeverType.js";
import { notUndefined } from "../Utils/notUndefined.js";

export class IntersectionNodeParser implements SubNodeParser {
public constructor(
Expand All @@ -24,11 +25,11 @@ export class IntersectionNodeParser implements SubNodeParser {
const types = node.types.map((subnode) => this.childNodeParser.createType(subnode, context));

// if any type is never, the intersection type resolves to never
if (types.filter((t) => t instanceof NeverType).length) {
if (types.some((t) => t instanceof NeverType)) {
return new NeverType();
}

return translate(types);
return translate(types.filter(notUndefined));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/NodeParser/LiteralNodeParser.ts
Expand Up @@ -9,7 +9,7 @@ export class LiteralNodeParser implements SubNodeParser {
public supportsNode(node: ts.LiteralTypeNode): boolean {
return node.kind === ts.SyntaxKind.LiteralType;
}
public createType(node: ts.LiteralTypeNode, context: Context): BaseType {
public createType(node: ts.LiteralTypeNode, context: Context): BaseType | undefined {
return this.childNodeParser.createType(node.literal, context);
}
}