diff --git a/factory/parser.ts b/factory/parser.ts index 6bc089000..f682b2f24 100644 --- a/factory/parser.ts +++ b/factory/parser.ts @@ -16,6 +16,7 @@ import { BooleanLiteralNodeParser } from "../src/NodeParser/BooleanLiteralNodePa import { BooleanTypeNodeParser } from "../src/NodeParser/BooleanTypeNodeParser.js"; import { CallExpressionParser } from "../src/NodeParser/CallExpressionParser.js"; import { ConditionalTypeNodeParser } from "../src/NodeParser/ConditionalTypeNodeParser.js"; +import { NewExpressionParser } from "../src/NodeParser/NewExpressionParser.js"; import { ConstructorNodeParser } from "../src/NodeParser/ConstructorNodeParser.js"; import { EnumNodeParser } from "../src/NodeParser/EnumNodeParser.js"; import { ExpressionWithTypeArgumentsNodeParser } from "../src/NodeParser/ExpressionWithTypeArgumentsNodeParser.js"; @@ -149,6 +150,7 @@ export function createParser(program: ts.Program, config: CompletedConfig, augme .addNodeParser(new SpreadElementNodeParser(chainNodeParser)) .addNodeParser(new CallExpressionParser(typeChecker, chainNodeParser)) + .addNodeParser(new NewExpressionParser(typeChecker, chainNodeParser)) .addNodeParser(new PropertyAccessExpressionParser(typeChecker, chainNodeParser)) .addNodeParser(withCircular(withExpose(withJsDoc(new TypeAliasNodeParser(typeChecker, chainNodeParser))))) diff --git a/src/NodeParser/NewExpressionParser.ts b/src/NodeParser/NewExpressionParser.ts new file mode 100644 index 000000000..3efa4675c --- /dev/null +++ b/src/NodeParser/NewExpressionParser.ts @@ -0,0 +1,46 @@ +import ts from "typescript"; +import type { NodeParser } from "../NodeParser.js"; +import { Context } from "../NodeParser.js"; +import type { SubNodeParser } from "../SubNodeParser.js"; +import type { BaseType } from "../Type/BaseType.js"; +import { UnknownNodeError } from "../Error/Errors.js"; + +export class NewExpressionParser implements SubNodeParser { + public constructor( + protected typeChecker: ts.TypeChecker, + protected childNodeParser: NodeParser, + ) {} + + public supportsNode(node: ts.NewExpression): boolean { + return node.kind === ts.SyntaxKind.NewExpression; + } + + public createType(node: ts.NewExpression, context: Context): BaseType { + const type = this.typeChecker.getTypeAtLocation(node); + + const symbol = type.symbol || type.aliasSymbol; + + const decl = + this.typeChecker.typeToTypeNode(type, node, ts.NodeBuilderFlags.IgnoreErrors) || + symbol?.valueDeclaration || + symbol?.declarations?.[0]; + + if (!decl) { + throw new UnknownNodeError(node); + } + + return this.childNodeParser.createType(decl, this.createSubContext(node, context)); + } + + protected createSubContext(node: ts.NewExpression, parentContext: Context): Context { + const subContext = new Context(node); + + if (node.arguments) { + for (const arg of node.arguments) { + const type = this.childNodeParser.createType(arg, parentContext); + subContext.pushArgument(type); + } + } + return subContext; + } +} diff --git a/test/valid-data-struct.test.ts b/test/valid-data-struct.test.ts index 9cdb5463c..ff53cfb92 100644 --- a/test/valid-data-struct.test.ts +++ b/test/valid-data-struct.test.ts @@ -31,6 +31,7 @@ describe("valid-data-struct", () => { it("class-inheritance", assertValidSchema("class-inheritance", "MyObject")); it("class-generics", assertValidSchema("class-generics", "MyObject")); it("class-jsdoc", assertValidSchema("class-jsdoc", "MyObject")); + it("class-new-expression", assertValidSchema("class-new-expression", "MyType")); it("structure-private", assertValidSchema("structure-private", "MyObject")); it("structure-anonymous", assertValidSchema("structure-anonymous", "MyObject")); diff --git a/test/valid-data/class-new-expression/main.ts b/test/valid-data/class-new-expression/main.ts new file mode 100644 index 000000000..0d395f0d3 --- /dev/null +++ b/test/valid-data/class-new-expression/main.ts @@ -0,0 +1,5 @@ +class MyObject {} + +const obj = new MyObject(); + +export type MyType = typeof obj; diff --git a/test/valid-data/class-new-expression/schema.json b/test/valid-data/class-new-expression/schema.json new file mode 100644 index 000000000..3bcd16e19 --- /dev/null +++ b/test/valid-data/class-new-expression/schema.json @@ -0,0 +1,10 @@ +{ + "$ref": "#/definitions/MyType", + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "MyType": { + "additionalProperties": false, + "type": "object" + } + } +}