UNPKG

ts-json-schema-generator

Version:

Generate JSON schema from your Typescript sources

138 lines 6.37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.InterfaceAndClassNodeParser = void 0; const tslib_1 = require("tslib"); const typescript_1 = tslib_1.__importDefault(require("typescript")); const ArrayType_js_1 = require("../Type/ArrayType.js"); const NeverType_js_1 = require("../Type/NeverType.js"); const ObjectType_js_1 = require("../Type/ObjectType.js"); const isHidden_js_1 = require("../Utils/isHidden.js"); const modifiers_js_1 = require("../Utils/modifiers.js"); const nodeKey_js_1 = require("../Utils/nodeKey.js"); class InterfaceAndClassNodeParser { typeChecker; childNodeParser; additionalProperties; constructor(typeChecker, childNodeParser, additionalProperties) { this.typeChecker = typeChecker; this.childNodeParser = childNodeParser; this.additionalProperties = additionalProperties; } supportsNode(node) { return node.kind === typescript_1.default.SyntaxKind.InterfaceDeclaration || node.kind === typescript_1.default.SyntaxKind.ClassDeclaration; } createType(node, context, reference) { 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); } }); } const id = this.getTypeId(node, context); if (reference) { reference.setId(id); reference.setName(id); } const properties = this.getProperties(node, context); if (properties === undefined) { return new NeverType_js_1.NeverType(); } const additionalProperties = this.getAdditionalProperties(node, context); if (properties.length === 0 && additionalProperties === false) { const arrayItemType = this.getArrayItemType(node); if (arrayItemType) { return new ArrayType_js_1.ArrayType(this.childNodeParser.createType(arrayItemType, context)); } } return new ObjectType_js_1.ObjectType(id, this.getBaseTypes(node, context), properties, additionalProperties); } getArrayItemType(node) { if (node.heritageClauses && node.heritageClauses.length === 1) { const clause = node.heritageClauses[0]; if (clause.types.length === 1) { const type = clause.types[0]; const symbol = this.typeChecker.getSymbolAtLocation(type.expression); if (symbol && (symbol.name === "Array" || symbol.name === "ReadonlyArray")) { const typeArguments = type.typeArguments; if (typeArguments?.length === 1) { return typeArguments[0]; } } } } return null; } getBaseTypes(node, context) { if (!node.heritageClauses) { return []; } return node.heritageClauses.reduce((result, baseType) => [ ...result, ...baseType.types.map((expression) => this.childNodeParser.createType(expression, context)), ], []); } getProperties(node, context) { let hasRequiredNever = false; const properties = node.members .reduce((members, member) => { if (typescript_1.default.isConstructorDeclaration(member)) { const params = member.parameters.filter((param) => typescript_1.default.isParameterPropertyDeclaration(param, param.parent)); members.push(...params); } else if (typescript_1.default.isPropertySignature(member) || typescript_1.default.isPropertyDeclaration(member)) { members.push(member); } return members; }, []) .filter((member) => (0, modifiers_js_1.isPublic)(member) && !(0, modifiers_js_1.isStatic)(member) && !(0, isHidden_js_1.isNodeHidden)(member)) .reduce((entries, member) => { let memberType = member.type; if (memberType === undefined && member?.initializer !== undefined) { const type = this.typeChecker.getTypeAtLocation(member); memberType = this.typeChecker.typeToTypeNode(type, node, typescript_1.default.NodeBuilderFlags.NoTruncation); } if (memberType !== undefined) { return [...entries, { member, memberType }]; } return entries; }, []) .map(({ member, memberType }) => new ObjectType_js_1.ObjectProperty(this.getPropertyName(member.name), this.childNodeParser.createType(memberType, context), !member.questionToken)) .filter((prop) => { const type = prop.getType(); if (prop.isRequired() && type instanceof NeverType_js_1.NeverType) { hasRequiredNever = true; } return !(type instanceof NeverType_js_1.NeverType); }); if (hasRequiredNever) { return undefined; } return properties; } getAdditionalProperties(node, context) { const indexSignature = node.members.find(typescript_1.default.isIndexSignatureDeclaration); if (!indexSignature) { return this.additionalProperties; } return this.childNodeParser.createType(indexSignature.type, context) ?? this.additionalProperties; } getTypeId(node, context) { const nodeType = typescript_1.default.isInterfaceDeclaration(node) ? "interface" : "class"; return `${nodeType}-${(0, nodeKey_js_1.getKey)(node, context)}`; } getPropertyName(propertyName) { if (propertyName.kind === typescript_1.default.SyntaxKind.ComputedPropertyName) { const symbol = this.typeChecker.getSymbolAtLocation(propertyName); if (symbol) { return symbol.getName(); } } return propertyName.getText(); } } exports.InterfaceAndClassNodeParser = InterfaceAndClassNodeParser; //# sourceMappingURL=InterfaceAndClassNodeParser.js.map