UNPKG

typescript-json-schema

Version:

typescript-json-schema generates JSON Schema files from your Typescript sources

1,163 lines 63.8 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.exec = exports.programFromConfig = exports.generateSchema = exports.buildGenerator = exports.getProgramFromFiles = exports.JsonSchemaGenerator = exports.regexRequire = exports.getDefaultArgs = void 0; var glob = require("glob"); var safe_stable_stringify_1 = require("safe-stable-stringify"); var path = require("path"); var crypto_1 = require("crypto"); var ts = require("typescript"); var path_equal_1 = require("path-equal"); var vm = require("vm"); var REGEX_FILE_NAME_OR_SPACE = /(\bimport\(".*?"\)|".*?")\.| /g; var REGEX_TSCONFIG_NAME = /^.*\.json$/; var REGEX_TJS_JSDOC = /^-([\w]+)\s+(\S|\S[\s\S]*\S)\s*$/g; var REGEX_GROUP_JSDOC = /^[.]?([\w]+)\s+(\S|\S[\s\S]*\S)\s*$/g; var REGEX_REQUIRE = /^(\s+)?require\((\'@?[a-zA-Z0-9.\/_-]+\'|\"@?[a-zA-Z0-9.\/_-]+\")\)(\.([a-zA-Z0-9_$]+))?(\s+|$)/; var NUMERIC_INDEX_PATTERN = "^[0-9]+$"; function getDefaultArgs() { return { ref: true, aliasRef: false, topRef: false, titles: false, defaultProps: false, noExtraProps: false, propOrder: false, typeOfKeyword: false, required: false, strictNullChecks: false, esModuleInterop: false, skipLibCheck: false, experimentalDecorators: true, ignoreErrors: false, out: "", validationKeywords: [], include: [], excludePrivate: false, uniqueNames: false, rejectDateType: false, id: "", defaultNumberType: "number", tsNodeRegister: false, constAsEnum: false, }; } exports.getDefaultArgs = getDefaultArgs; function extend(target) { var _ = []; for (var _i = 1; _i < arguments.length; _i++) { _[_i - 1] = arguments[_i]; } if (target == null) { throw new TypeError("Cannot convert undefined or null to object"); } var to = Object(target); for (var index = 1; index < arguments.length; index++) { var nextSource = arguments[index]; if (nextSource != null) { for (var nextKey in nextSource) { if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { to[nextKey] = nextSource[nextKey]; } } } } return to; } function unique(arr) { var temp = {}; for (var _i = 0, arr_1 = arr; _i < arr_1.length; _i++) { var e = arr_1[_i]; temp[e] = true; } var r = []; for (var k in temp) { if (Object.prototype.hasOwnProperty.call(temp, k)) { r.push(k); } } return r; } function resolveRequiredFile(symbol, key, fileName, objectName) { var sourceFile = getSourceFile(symbol); var requiredFilePath = /^[.\/]+/.test(fileName) ? fileName === "." ? path.resolve(sourceFile.fileName) : path.resolve(path.dirname(sourceFile.fileName), fileName) : fileName; var requiredFile = require(requiredFilePath); if (!requiredFile) { throw Error("Required: File couldn't be loaded"); } var requiredObject = objectName ? requiredFile[objectName] : requiredFile.default; if (requiredObject === undefined) { throw Error("Required: Variable is undefined"); } if (typeof requiredObject === "function") { throw Error("Required: Can't use function as a variable"); } if (key === "examples" && !Array.isArray(requiredObject)) { throw Error("Required: Variable isn't an array"); } return requiredObject; } function regexRequire(value) { return REGEX_REQUIRE.exec(value); } exports.regexRequire = regexRequire; function parseValue(symbol, key, value) { var match = regexRequire(value); if (match) { var fileName = match[2].substr(1, match[2].length - 2).trim(); var objectName = match[4]; return resolveRequiredFile(symbol, key, fileName, objectName); } try { return JSON.parse(value); } catch (error) { return value; } } function extractLiteralValue(typ) { var str = typ.value; if (str === undefined) { str = typ.text; } if (typ.flags & ts.TypeFlags.StringLiteral) { return str; } else if (typ.flags & ts.TypeFlags.BooleanLiteral) { return typ.intrinsicName === "true"; } else if (typ.flags & ts.TypeFlags.EnumLiteral) { var num = parseFloat(str); return isNaN(num) ? str : num; } else if (typ.flags & ts.TypeFlags.NumberLiteral) { return parseFloat(str); } return undefined; } function resolveTupleType(propertyType) { if (!propertyType.getSymbol() && propertyType.getFlags() & ts.TypeFlags.Object && propertyType.objectFlags & ts.ObjectFlags.Reference) { return propertyType.target; } if (!(propertyType.getFlags() & ts.TypeFlags.Object && propertyType.objectFlags & ts.ObjectFlags.Tuple)) { return null; } return propertyType; } var simpleTypesAllowedProperties = { type: true, description: true, }; function addSimpleType(def, type) { for (var k in def) { if (!simpleTypesAllowedProperties[k]) { return false; } } if (!def.type) { def.type = type; } else if (typeof def.type !== "string") { if (!def.type.every(function (val) { return typeof val === "string"; })) { return false; } if (def.type.indexOf("null") === -1) { def.type.push("null"); } } else { if (typeof def.type !== "string") { return false; } if (def.type !== "null") { def.type = [def.type, "null"]; } } return true; } function makeNullable(def) { if (!addSimpleType(def, "null")) { var union = def.oneOf || def.anyOf; if (union) { union.push({ type: "null" }); } else { var subdef = {}; for (var k in def) { if (def.hasOwnProperty(k)) { subdef[k] = def[k]; delete def[k]; } } def.anyOf = [subdef, { type: "null" }]; } } return def; } function getCanonicalDeclaration(sym) { var _a, _b, _c; if (sym.valueDeclaration !== undefined) { return sym.valueDeclaration; } else if (((_a = sym.declarations) === null || _a === void 0 ? void 0 : _a.length) === 1) { return sym.declarations[0]; } var declarationCount = (_c = (_b = sym.declarations) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0; throw new Error("Symbol \"".concat(sym.name, "\" has no valueDeclaration and ").concat(declarationCount, " declarations.")); } function getSourceFile(sym) { var currentDecl = getCanonicalDeclaration(sym); while (currentDecl.kind !== ts.SyntaxKind.SourceFile) { if (currentDecl.parent === undefined) { throw new Error("Unable to locate source file for declaration \"".concat(sym.name, "\".")); } currentDecl = currentDecl.parent; } return currentDecl; } var validationKeywords = { multipleOf: true, maximum: true, exclusiveMaximum: true, minimum: true, exclusiveMinimum: true, maxLength: true, minLength: true, pattern: true, items: true, maxItems: true, minItems: true, uniqueItems: true, contains: true, maxProperties: true, minProperties: true, additionalProperties: true, enum: true, type: true, examples: true, ignore: true, description: true, format: true, default: true, $ref: true, id: true, $id: true, $comment: true, title: true }; var annotationKeywords = { description: true, default: true, examples: true, title: true, $ref: true, }; var subDefinitions = { items: true, additionalProperties: true, contains: true, }; var JsonSchemaGenerator = (function () { function JsonSchemaGenerator(symbols, allSymbols, userSymbols, inheritingTypes, tc, args) { if (args === void 0) { args = getDefaultArgs(); } this.args = args; this.reffedDefinitions = {}; this.schemaOverrides = new Map(); this.typeNamesById = {}; this.typeIdsByName = {}; this.recursiveTypeRef = new Map(); this.symbols = symbols; this.allSymbols = allSymbols; this.userSymbols = userSymbols; this.inheritingTypes = inheritingTypes; this.tc = tc; this.userValidationKeywords = args.validationKeywords.reduce(function (acc, word) { var _a; return (__assign(__assign({}, acc), (_a = {}, _a[word] = true, _a))); }, {}); this.constAsEnum = args.constAsEnum; } Object.defineProperty(JsonSchemaGenerator.prototype, "ReffedDefinitions", { get: function () { return this.reffedDefinitions; }, enumerable: false, configurable: true }); JsonSchemaGenerator.prototype.isFromDefaultLib = function (symbol) { var declarations = symbol.getDeclarations(); if (declarations && declarations.length > 0 && declarations[0].parent) { return declarations[0].parent.getSourceFile().hasNoDefaultLib; } return false; }; JsonSchemaGenerator.prototype.resetSchemaSpecificProperties = function (includeAllOverrides) { var _this = this; if (includeAllOverrides === void 0) { includeAllOverrides = false; } this.reffedDefinitions = {}; this.typeIdsByName = {}; this.typeNamesById = {}; if (includeAllOverrides) { this.schemaOverrides.forEach(function (value, key) { _this.reffedDefinitions[key] = value; }); } }; JsonSchemaGenerator.prototype.parseCommentsIntoDefinition = function (symbol, definition, otherAnnotations) { var _this = this; if (!symbol) { return; } if (!this.isFromDefaultLib(symbol)) { var comments = symbol.getDocumentationComment(this.tc); if (comments.length) { definition.description = comments .map(function (comment) { var newlineNormalizedComment = comment.text.replace(/\r\n/g, "\n"); if (comment.kind === "linkText") { return newlineNormalizedComment.trim(); } return newlineNormalizedComment; }) .join("").trim(); } } var jsdocs = symbol.getJsDocTags(); jsdocs.forEach(function (doc) { var _a, _b; var name = doc.name; var originalText = doc.text ? doc.text.map(function (t) { return t.text; }).join("") : ""; var text = originalText; if (name.startsWith("TJS-")) { name = name.slice(4); if (!text) { text = "true"; } } else if (name === "TJS" && text.startsWith("-")) { var match = new RegExp(REGEX_TJS_JSDOC).exec(originalText); if (match) { name = match[1]; text = match[2]; } else { name = text.replace(/^[\s\-]+/, ""); text = "true"; } } if (subDefinitions[name]) { var match = new RegExp(REGEX_GROUP_JSDOC).exec(text); if (match) { var k = match[1]; var v = match[2]; definition[name] = __assign(__assign({}, definition[name]), (_a = {}, _a[k] = v ? parseValue(symbol, k, v) : true, _a)); return; } } if (name.includes(".")) { var parts = name.split("."); var key = parts[0]; if (parts.length === 2 && subDefinitions[key]) { definition[key] = __assign(__assign({}, definition[key]), (_b = {}, _b[parts[1]] = text ? parseValue(symbol, name, text) : true, _b)); } } if (validationKeywords[name] || _this.userValidationKeywords[name]) { definition[name] = text === undefined ? "" : parseValue(symbol, name, text); } else { otherAnnotations[doc.name] = true; } }); }; JsonSchemaGenerator.prototype.getDefinitionForRootType = function (propertyType, reffedType, definition, defaultNumberType, ignoreUndefined) { var _a; var _this = this; var _b; if (defaultNumberType === void 0) { defaultNumberType = this.args.defaultNumberType; } if (ignoreUndefined === void 0) { ignoreUndefined = false; } var tupleType = resolveTupleType(propertyType); if (tupleType) { var elemTypes = propertyType.typeArguments; var fixedTypes = elemTypes.map(function (elType) { return _this.getTypeDefinition(elType); }); definition.type = "array"; if (fixedTypes.length > 0) { definition.items = fixedTypes; } var targetTupleType = propertyType.target; definition.minItems = targetTupleType.minLength; if (targetTupleType.hasRestElement) { definition.additionalItems = fixedTypes[fixedTypes.length - 1]; fixedTypes.splice(fixedTypes.length - 1, 1); } else { definition.maxItems = targetTupleType.fixedLength; } } else { var propertyTypeString = this.tc.typeToString(propertyType, undefined, ts.TypeFormatFlags.UseFullyQualifiedType); var flags = propertyType.flags; var arrayType = this.tc.getIndexTypeOfType(propertyType, ts.IndexKind.Number); if (flags & ts.TypeFlags.String) { definition.type = "string"; } else if (flags & ts.TypeFlags.Number) { var isInteger = definition.type === "integer" || (reffedType === null || reffedType === void 0 ? void 0 : reffedType.getName()) === "integer" || defaultNumberType === "integer"; definition.type = isInteger ? "integer" : "number"; } else if (flags & ts.TypeFlags.Boolean) { definition.type = "boolean"; } else if (flags & ts.TypeFlags.ESSymbol) { definition.type = "object"; } else if (flags & ts.TypeFlags.Null) { definition.type = "null"; } else if (flags & ts.TypeFlags.Undefined || propertyTypeString === "void") { if (!ignoreUndefined) { throw new Error("Not supported: root type undefined"); } definition.type = "undefined"; } else if (flags & ts.TypeFlags.Any || flags & ts.TypeFlags.Unknown) { } else if (propertyTypeString === "Date" && !this.args.rejectDateType) { definition.type = "string"; definition.format = definition.format || "date-time"; } else if (propertyTypeString === "object") { definition.type = "object"; definition.properties = {}; definition.additionalProperties = true; } else if (propertyTypeString === "bigint") { definition.type = "number"; definition.properties = {}; definition.additionalProperties = false; } else { var value = extractLiteralValue(propertyType); if (value !== undefined) { var typeofValue = typeof value; switch (typeofValue) { case "string": case "boolean": definition.type = typeofValue; break; case "number": definition.type = this.args.defaultNumberType; break; case "object": definition.type = "null"; break; default: throw new Error("Not supported: ".concat(value, " as a enum value")); } if (this.constAsEnum) { definition.enum = [value]; } else { definition.const = value; } } else if (arrayType !== undefined) { if (propertyType.flags & ts.TypeFlags.Object && propertyType.objectFlags & (ts.ObjectFlags.Anonymous | ts.ObjectFlags.Interface | ts.ObjectFlags.Mapped)) { definition.type = "object"; definition.additionalProperties = false; definition.patternProperties = (_a = {}, _a[NUMERIC_INDEX_PATTERN] = this.getTypeDefinition(arrayType), _a); if (!!((_b = Array.from(propertyType.members)) === null || _b === void 0 ? void 0 : _b.find(function (member) { return member[0] !== "__index"; }))) { this.getClassDefinition(propertyType, definition); } } else if (propertyType.flags & ts.TypeFlags.TemplateLiteral) { definition.type = "string"; var texts = propertyType.texts, types = propertyType.types; var pattern = []; for (var i = 0; i < texts.length; i++) { var text = texts[i].replace(/[\\^$.*+?()[\]{}|]/g, "\\$&"); var type = types[i]; if (i === 0) { pattern.push("^"); } if (type) { if (type.flags & ts.TypeFlags.String) { pattern.push("".concat(text, ".*")); } if (type.flags & ts.TypeFlags.Number || type.flags & ts.TypeFlags.BigInt) { pattern.push("".concat(text, "[0-9]*")); } if (type.flags & ts.TypeFlags.Undefined) { pattern.push("".concat(text, "undefined")); } if (type.flags & ts.TypeFlags.Null) { pattern.push("".concat(text, "null")); } } if (i === texts.length - 1) { pattern.push("".concat(text, "$")); } } definition.pattern = pattern.join(""); } else { definition.type = "array"; if (!definition.items) { definition.items = this.getTypeDefinition(arrayType); } } } else { var error = new TypeError("Unsupported type: " + propertyTypeString); error.type = propertyType; throw error; } } } return definition; }; JsonSchemaGenerator.prototype.getReferencedTypeSymbol = function (prop) { var decl = prop.getDeclarations(); if (decl === null || decl === void 0 ? void 0 : decl.length) { var type = decl[0].type; if (type && type.kind & ts.SyntaxKind.TypeReference && type.typeName) { var symbol = this.tc.getSymbolAtLocation(type.typeName); if (symbol && symbol.flags & ts.SymbolFlags.Alias) { return this.tc.getAliasedSymbol(symbol); } return symbol; } } return undefined; }; JsonSchemaGenerator.prototype.getDefinitionForProperty = function (prop, node) { if (prop.flags & ts.SymbolFlags.Method) { return null; } var propertyName = prop.getName(); var propertyType = this.tc.getTypeOfSymbolAtLocation(prop, node); var reffedType = this.getReferencedTypeSymbol(prop); var definition = this.getTypeDefinition(propertyType, undefined, undefined, prop, reffedType); if (this.args.titles) { definition.title = propertyName; } if (definition.hasOwnProperty("ignore")) { return null; } var valDecl = prop.valueDeclaration; if (valDecl === null || valDecl === void 0 ? void 0 : valDecl.initializer) { var initial = valDecl.initializer; while (ts.isTypeAssertionExpression(initial)) { initial = initial.expression; } if (initial.expression) { console.warn("initializer is expression for property " + propertyName); } else if (initial.kind && initial.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral) { definition.default = initial.getText(); } else { try { var sandbox = { sandboxvar: null }; vm.runInNewContext("sandboxvar=" + initial.getText(), sandbox); var val = sandbox.sandboxvar; if (val === null || typeof val === "string" || typeof val === "number" || typeof val === "boolean" || Object.prototype.toString.call(val) === "[object Array]") { definition.default = val; } else if (val) { console.warn("unknown initializer for property " + propertyName + ": " + val); } } catch (e) { console.warn("exception evaluating initializer for property " + propertyName); } } } return definition; }; JsonSchemaGenerator.prototype.getEnumDefinition = function (clazzType, definition) { var _this = this; var node = clazzType.getSymbol().getDeclarations()[0]; var fullName = this.tc.typeToString(clazzType, undefined, ts.TypeFormatFlags.UseFullyQualifiedType); var members = node.kind === ts.SyntaxKind.EnumDeclaration ? node.members : ts.factory.createNodeArray([node]); var enumValues = []; var enumTypes = []; var addType = function (type) { if (enumTypes.indexOf(type) === -1) { enumTypes.push(type); } }; members.forEach(function (member) { var caseLabel = member.name.text; var constantValue = _this.tc.getConstantValue(member); if (constantValue !== undefined) { enumValues.push(constantValue); addType(typeof constantValue); } else { var initial = member.initializer; if (initial) { if (initial.expression) { var exp = initial.expression; var text = exp.text; if (text) { enumValues.push(text); addType("string"); } else if (exp.kind === ts.SyntaxKind.TrueKeyword || exp.kind === ts.SyntaxKind.FalseKeyword) { enumValues.push(exp.kind === ts.SyntaxKind.TrueKeyword); addType("boolean"); } else { console.warn("initializer is expression for enum: " + fullName + "." + caseLabel); } } else if (initial.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral) { enumValues.push(initial.getText()); addType("string"); } else if (initial.kind === ts.SyntaxKind.NullKeyword) { enumValues.push(null); addType("null"); } } } }); if (enumTypes.length) { definition.type = enumTypes.length === 1 ? enumTypes[0] : enumTypes; } if (enumValues.length > 0) { if (enumValues.length > 1) { definition.enum = enumValues; } else { definition.const = enumValues[0]; } } return definition; }; JsonSchemaGenerator.prototype.getUnionDefinition = function (unionType, unionModifier, definition) { var enumValues = []; var simpleTypes = []; var schemas = []; var pushSimpleType = function (type) { if (simpleTypes.indexOf(type) === -1) { simpleTypes.push(type); } }; var pushEnumValue = function (val) { if (enumValues.indexOf(val) === -1) { enumValues.push(val); } }; for (var _i = 0, _a = unionType.types; _i < _a.length; _i++) { var valueType = _a[_i]; var value = extractLiteralValue(valueType); if (value !== undefined) { pushEnumValue(value); } else { var symbol = valueType.aliasSymbol; var def = this.getTypeDefinition(valueType, undefined, undefined, symbol, symbol, undefined, undefined, true); if (def.type === "undefined") { continue; } var keys = Object.keys(def); if (keys.length === 1 && keys[0] === "type") { if (typeof def.type !== "string") { console.error("Expected only a simple type."); } else { pushSimpleType(def.type); } } else { schemas.push(def); } } } if (enumValues.length > 0) { var isOnlyBooleans = enumValues.length === 2 && typeof enumValues[0] === "boolean" && typeof enumValues[1] === "boolean" && enumValues[0] !== enumValues[1]; if (isOnlyBooleans) { pushSimpleType("boolean"); } else { var enumSchema = enumValues.length > 1 ? { enum: enumValues.sort() } : { const: enumValues[0] }; if (enumValues.every(function (x) { return typeof x === "string"; })) { enumSchema.type = "string"; } else if (enumValues.every(function (x) { return typeof x === "number"; })) { enumSchema.type = "number"; } else if (enumValues.every(function (x) { return typeof x === "boolean"; })) { enumSchema.type = "boolean"; } schemas.push(enumSchema); } } if (simpleTypes.length > 0) { schemas.push({ type: simpleTypes.length === 1 ? simpleTypes[0] : simpleTypes }); } if (schemas.length === 1) { for (var k in schemas[0]) { if (schemas[0].hasOwnProperty(k)) { if (k === "description" && definition.hasOwnProperty(k)) { continue; } definition[k] = schemas[0][k]; } } } else { definition[unionModifier] = schemas; } return definition; }; JsonSchemaGenerator.prototype.getIntersectionDefinition = function (intersectionType, definition) { var simpleTypes = []; var schemas = []; var pushSimpleType = function (type) { if (simpleTypes.indexOf(type) === -1) { simpleTypes.push(type); } }; for (var _i = 0, _a = intersectionType.types; _i < _a.length; _i++) { var intersectionMember = _a[_i]; var def = this.getTypeDefinition(intersectionMember); var keys = Object.keys(def); if (keys.length === 1 && keys[0] === "type") { if (typeof def.type !== "string") { console.error("Expected only a simple type."); } else { pushSimpleType(def.type); } } else { schemas.push(def); } } if (simpleTypes.length > 0) { schemas.push({ type: simpleTypes.length === 1 ? simpleTypes[0] : simpleTypes }); } if (schemas.length === 1) { for (var k in schemas[0]) { if (schemas[0].hasOwnProperty(k)) { definition[k] = schemas[0][k]; } } } else { definition.allOf = schemas; } return definition; }; JsonSchemaGenerator.prototype.getClassDefinition = function (clazzType, definition) { var _this = this; var _a, _b; var node = clazzType.getSymbol().getDeclarations()[0]; if (!node) { definition.type = "object"; return definition; } if (this.args.typeOfKeyword && node.kind === ts.SyntaxKind.FunctionType) { definition.typeof = "function"; return definition; } var clazz = node; var props = this.tc.getPropertiesOfType(clazzType).filter(function (prop) { var propertyFlagType = _this.tc.getTypeOfSymbolAtLocation(prop, node).getFlags(); if (ts.TypeFlags.Never === propertyFlagType || ts.TypeFlags.Undefined === propertyFlagType) { return false; } if (!_this.args.excludePrivate) { return true; } var decls = prop.declarations; return !(decls && decls.filter(function (decl) { var mods = decl.modifiers; return mods && mods.filter(function (mod) { return mod.kind === ts.SyntaxKind.PrivateKeyword; }).length > 0; }).length > 0); }); var fullName = this.tc.typeToString(clazzType, undefined, ts.TypeFormatFlags.UseFullyQualifiedType); var modifierFlags = ts.getCombinedModifierFlags(node); if (modifierFlags & ts.ModifierFlags.Abstract && this.inheritingTypes[fullName]) { var oneOf = this.inheritingTypes[fullName].map(function (typename) { return _this.getTypeDefinition(_this.allSymbols[typename]); }); definition.oneOf = oneOf; } else { if (clazz.members) { var indexSignatures = clazz.members == null ? [] : clazz.members.filter(function (x) { return x.kind === ts.SyntaxKind.IndexSignature; }); if (indexSignatures.length === 1) { var indexSignature = indexSignatures[0]; if (indexSignature.parameters.length !== 1) { throw new Error("Not supported: IndexSignatureDeclaration parameters.length != 1"); } var indexSymbol = indexSignature.parameters[0].symbol; var indexType = this.tc.getTypeOfSymbolAtLocation(indexSymbol, node); var isIndexedObject = indexType.flags === ts.TypeFlags.String || indexType.flags === ts.TypeFlags.Number; if (indexType.flags !== ts.TypeFlags.Number && !isIndexedObject) { throw new Error("Not supported: IndexSignatureDeclaration with index symbol other than a number or a string"); } var typ = this.tc.getTypeAtLocation(indexSignature.type); var def = void 0; if (typ.flags & ts.TypeFlags.IndexedAccess) { var targetName = ts.escapeLeadingUnderscores((_b = (_a = clazzType.mapper) === null || _a === void 0 ? void 0 : _a.target) === null || _b === void 0 ? void 0 : _b.value); var indexedAccessType = typ; var symbols = indexedAccessType.objectType.members; var targetSymbol = symbols === null || symbols === void 0 ? void 0 : symbols.get(targetName); if (targetSymbol) { var targetNode = targetSymbol.getDeclarations()[0]; var targetDef = this.getDefinitionForProperty(targetSymbol, targetNode); if (targetDef) { def = targetDef; } } } if (!def) { def = this.getTypeDefinition(typ, undefined, "anyOf"); } if (isIndexedObject) { definition.type = "object"; if (!Object.keys(definition.patternProperties || {}).length) { definition.additionalProperties = def; } } else { definition.type = "array"; if (!definition.items) { definition.items = def; } } } } var propertyDefinitions = props.reduce(function (all, prop) { var propertyName = prop.getName(); var propDef = _this.getDefinitionForProperty(prop, node); if (propDef != null) { all[propertyName] = propDef; } return all; }, {}); if (definition.type === undefined) { definition.type = "object"; } if (definition.type === "object" && Object.keys(propertyDefinitions).length > 0) { definition.properties = propertyDefinitions; } if (this.args.defaultProps) { definition.defaultProperties = []; } if (this.args.noExtraProps && definition.additionalProperties === undefined) { definition.additionalProperties = false; } if (this.args.propOrder) { var propertyOrder = props.reduce(function (order, prop) { order.push(prop.getName()); return order; }, []); definition.propertyOrder = propertyOrder; } if (this.args.required) { var requiredProps = props.reduce(function (required, prop) { var _a, _b, _c, _d; var def = {}; _this.parseCommentsIntoDefinition(prop, def, {}); var allUnionTypesFlags = ((_d = (_c = (_b = (_a = prop.links) === null || _a === void 0 ? void 0 : _a.type) === null || _b === void 0 ? void 0 : _b.types) === null || _c === void 0 ? void 0 : _c.map) === null || _d === void 0 ? void 0 : _d.call(_c, function (t) { return t.flags; })) || []; if (!(prop.flags & ts.SymbolFlags.Optional) && !(prop.flags & ts.SymbolFlags.Method) && !allUnionTypesFlags.includes(ts.TypeFlags.Undefined) && !allUnionTypesFlags.includes(ts.TypeFlags.Void) && !def.hasOwnProperty("ignore")) { required.push(prop.getName()); } return required; }, []); if (requiredProps.length > 0) { definition.required = unique(requiredProps).sort(); } } } return definition; }; JsonSchemaGenerator.prototype.getTypeName = function (typ) { var id = typ.id; if (this.typeNamesById[id]) { return this.typeNamesById[id]; } return this.makeTypeNameUnique(typ, this.tc .typeToString(typ, undefined, ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.UseFullyQualifiedType) .replace(REGEX_FILE_NAME_OR_SPACE, "")); }; JsonSchemaGenerator.prototype.makeTypeNameUnique = function (typ, baseName) { var id = typ.id; var name = baseName; for (var i = 1; this.typeIdsByName[name] !== undefined && this.typeIdsByName[name] !== id; ++i) { name = baseName + "_" + i; } this.typeNamesById[id] = name; this.typeIdsByName[name] = id; return name; }; JsonSchemaGenerator.prototype.getTypeDefinition = function (typ, asRef, unionModifier, prop, reffedType, pairedSymbol, forceNotRef, ignoreUndefined) { var _a; if (asRef === void 0) { asRef = this.args.ref; } if (unionModifier === void 0) { unionModifier = "anyOf"; } if (forceNotRef === void 0) { forceNotRef = false; } if (ignoreUndefined === void 0) { ignoreUndefined = false; } var definition = {}; while (typ.aliasSymbol && (typ.aliasSymbol.escapedName === "Readonly" || typ.aliasSymbol.escapedName === "Mutable") && typ.aliasTypeArguments && typ.aliasTypeArguments[0]) { typ = typ.aliasTypeArguments[0]; reffedType = undefined; } if (this.args.typeOfKeyword && typ.flags & ts.TypeFlags.Object && typ.objectFlags & ts.ObjectFlags.Anonymous) { definition.typeof = "function"; return definition; } var returnedDefinition = definition; if (prop) { var defs = {}; var others = {}; this.parseCommentsIntoDefinition(prop, defs, others); if (defs.hasOwnProperty("ignore") || defs.hasOwnProperty("type")) { return defs; } } var symbol = typ.getSymbol(); var isRawType = !symbol || (this.tc.getFullyQualifiedName(symbol) !== "Window" && (this.tc.getFullyQualifiedName(symbol) === "Date" || symbol.name === "integer" || this.tc.getIndexInfoOfType(typ, ts.IndexKind.Number) !== undefined)); if (isRawType && ((_a = typ.aliasSymbol) === null || _a === void 0 ? void 0 : _a.escapedName) && typ.types) { isRawType = false; } var isStringEnum = false; if (typ.flags & ts.TypeFlags.Union) { var unionType = typ; isStringEnum = unionType.types.every(function (propType) { return (propType.getFlags() & ts.TypeFlags.StringLiteral) !== 0; }); } var asTypeAliasRef = asRef && reffedType && (this.args.aliasRef || isStringEnum); if (!asTypeAliasRef) { if (isRawType || (typ.getFlags() & ts.TypeFlags.Object && typ.objectFlags & ts.ObjectFlags.Anonymous)) { asRef = false; } } var fullTypeName = ""; if (asTypeAliasRef) { var typeName = this.tc .getFullyQualifiedName(reffedType.getFlags() & ts.SymbolFlags.Alias ? this.tc.getAliasedSymbol(reffedType) : reffedType) .replace(REGEX_FILE_NAME_OR_SPACE, ""); if (this.args.uniqueNames && reffedType) { var sourceFile = getSourceFile(reffedType); var relativePath = path.relative(process.cwd(), sourceFile.fileName); fullTypeName = "".concat(typeName, ".").concat(generateHashOfNode(getCanonicalDeclaration(reffedType), relativePath)); } else { fullTypeName = this.makeTypeNameUnique(typ, typeName); } } else { if (this.args.uniqueNames && typ.symbol) { var sym = typ.symbol; var sourceFile = getSourceFile(sym); var relativePath = path.relative(process.cwd(), sourceFile.fileName); fullTypeName = "".concat(this.getTypeName(typ), ".").concat(generateHashOfNode(getCanonicalDeclaration(sym), relativePath)); } else if (reffedType && this.schemaOverrides.has(reffedType.escapedName)) { fullTypeName = reffedType.escapedName; } else { fullTypeName = this.getTypeName(typ); } } if (!isRawType || !!typ.aliasSymbol) { if (this.recursiveTypeRef.has(fullTypeName) && !forceNotRef) { asRef = true; } else { this.recursiveTypeRef.set(fullTypeName, definition); } } if (asRef) { returnedDefinition = { $ref: "".concat(this.args.id, "#/definitions/") + fullTypeName, }; } var otherAnnotations = {}; this.parseCommentsIntoDefinition(reffedType, definition, otherAnnotations); this.parseCommentsIntoDefinition(symbol, definition, otherAnnotations); this.parseCommentsIntoDefinition(typ.aliasSymbol, definition, otherAnnotations); if (prop) { this.parseCommentsIntoDefinition(prop, returnedDefinition, otherAnnotations); } if (pairedSymbol && symbol && this.isFromDefaultLib(symbol)) { this.parseCommentsIntoDefinition(pairedSymbol, definition, otherAnnotations); } var overrideDefinition = this.schemaOverrides.get(fullTypeName); if (overrideDefinition) { this.reffedDefinitions[fullTypeName] = overrideDefinition; } else if (!asRef || !this.reffedDefinitions[fullTypeName]) { if (asRef) { var reffedDefinition = void 0; if (asTypeAliasRef && reffedType && typ.symbol !== reffedType && symbol) { reffedDefinition = this.getTypeDefinition(typ, true, undefined, symbol, symbol); } else { reffedDefinition = definition; } this.reffedDefinitions[fullTypeName] = reffedDefinition; if (this.args.titles && fullTypeName) { definition.title = fullTypeName; } } var node = (symbol === null || symbol === void 0 ? void 0 : symbol.getDeclarations()) !== undefined ? symbol.getDeclarations()[0] : null; if (definition.type === undefined) { if (typ.flags & ts.TypeFlags.Union && (node === null || node.kind !== ts.SyntaxKind.EnumDeclaration)) { this.getUnionDefinition(typ, unionModifier, definition); } else if (typ.flags & ts.TypeFlags.Intersection) { if (this.args.noExtraProps) { if (this.args.noExtraProps) { definition.additionalProperties = false; } var types = typ.types; for (var _i = 0, types_1 = types; _i < types_1.length; _i++) { var member = types_1[_i]; var other = this.getTypeDefinition(member, false, undefined, undefined, undefined, undefined, true); definition.type = other.type; definition.properties = __assign(__assign({}, definition.properties), other.properties); if (Object.keys(other.default || {}).length > 0) { definition.default = extend(definition.default || {}, other.default); } if (other.required) { definition.required = unique((definition.required || []).concat(other.required)).sort(); } } } else { this.getIntersectionDefinition(typ, definition); } } else if (isRawType) { if (pairedSymbol) { this.parseCommentsIntoDefinition(pairedSymbol, definition, {}); } this.getDefinitionForRootType(typ, reffedType, definition, undefined, ignoreUndefined); } else if (node && (node.kind === ts.SyntaxKind.EnumDeclaration || node.kind === ts.SyntaxKind.EnumMember)) { this.getEnumDefinition(typ, definition); } else if (symbol && symbol.flags & ts.SymbolFlags.TypeLiteral && symbol.members.size === 0 && !(node && node.kind === ts.SyntaxKind.MappedType)) { definition.type = "object"; definition.properties = {}; } else { this.getClassDefinition(typ, definition); } } } if (this.recursiveTypeRef.get(fullTypeName) === definition) { this.recursiveTypeRef.delete(fullTypeName); if (this.reffedDefinitions[fullTypeName]) { var annotations = Object.entries(returnedDefinition).reduce(function (acc, _a) { var key = _a[0], value = _a[1]; if (annotationKeywords[key] && typeof value !== undefined) { acc[key] = value; } return acc; }, {}); returnedDefinition = __assign({ $ref: ""