UNPKG

63.8 kBJavaScriptView Raw
1"use strict";
2var __assign = (this && this.__assign) || function () {
3 __assign = Object.assign || function(t) {
4 for (var s, i = 1, n = arguments.length; i < n; i++) {
5 s = arguments[i];
6 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7 t[p] = s[p];
8 }
9 return t;
10 };
11 return __assign.apply(this, arguments);
12};
13var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15 return new (P || (P = Promise))(function (resolve, reject) {
16 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19 step((generator = generator.apply(thisArg, _arguments || [])).next());
20 });
21};
22var __generator = (this && this.__generator) || function (thisArg, body) {
23 var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24 return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25 function verb(n) { return function (v) { return step([n, v]); }; }
26 function step(op) {
27 if (f) throw new TypeError("Generator is already executing.");
28 while (g && (g = 0, op[0] && (_ = 0)), _) try {
29 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;
30 if (y = 0, t) op = [op[0] & 2, t.value];
31 switch (op[0]) {
32 case 0: case 1: t = op; break;
33 case 4: _.label++; return { value: op[1], done: false };
34 case 5: _.label++; y = op[1]; op = [0]; continue;
35 case 7: op = _.ops.pop(); _.trys.pop(); continue;
36 default:
37 if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38 if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39 if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40 if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41 if (t[2]) _.ops.pop();
42 _.trys.pop(); continue;
43 }
44 op = body.call(thisArg, _);
45 } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46 if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47 }
48};
49Object.defineProperty(exports, "__esModule", { value: true });
50exports.exec = exports.programFromConfig = exports.generateSchema = exports.buildGenerator = exports.getProgramFromFiles = exports.JsonSchemaGenerator = exports.regexRequire = exports.getDefaultArgs = void 0;
51var glob = require("glob");
52var safe_stable_stringify_1 = require("safe-stable-stringify");
53var path = require("path");
54var crypto_1 = require("crypto");
55var ts = require("typescript");
56var path_equal_1 = require("path-equal");
57var vm = require("vm");
58var REGEX_FILE_NAME_OR_SPACE = /(\bimport\(".*?"\)|".*?")\.| /g;
59var REGEX_TSCONFIG_NAME = /^.*\.json$/;
60var REGEX_TJS_JSDOC = /^-([\w]+)\s+(\S|\S[\s\S]*\S)\s*$/g;
61var REGEX_GROUP_JSDOC = /^[.]?([\w]+)\s+(\S|\S[\s\S]*\S)\s*$/g;
62var REGEX_REQUIRE = /^(\s+)?require\((\'@?[a-zA-Z0-9.\/_-]+\'|\"@?[a-zA-Z0-9.\/_-]+\")\)(\.([a-zA-Z0-9_$]+))?(\s+|$)/;
63var NUMERIC_INDEX_PATTERN = "^[0-9]+$";
64function getDefaultArgs() {
65 return {
66 ref: true,
67 aliasRef: false,
68 topRef: false,
69 titles: false,
70 defaultProps: false,
71 noExtraProps: false,
72 propOrder: false,
73 typeOfKeyword: false,
74 required: false,
75 strictNullChecks: false,
76 esModuleInterop: false,
77 skipLibCheck: false,
78 experimentalDecorators: true,
79 ignoreErrors: false,
80 out: "",
81 validationKeywords: [],
82 include: [],
83 excludePrivate: false,
84 uniqueNames: false,
85 rejectDateType: false,
86 id: "",
87 defaultNumberType: "number",
88 tsNodeRegister: false,
89 constAsEnum: false,
90 };
91}
92exports.getDefaultArgs = getDefaultArgs;
93function extend(target) {
94 var _ = [];
95 for (var _i = 1; _i < arguments.length; _i++) {
96 _[_i - 1] = arguments[_i];
97 }
98 if (target == null) {
99 throw new TypeError("Cannot convert undefined or null to object");
100 }
101 var to = Object(target);
102 for (var index = 1; index < arguments.length; index++) {
103 var nextSource = arguments[index];
104 if (nextSource != null) {
105 for (var nextKey in nextSource) {
106 if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
107 to[nextKey] = nextSource[nextKey];
108 }
109 }
110 }
111 }
112 return to;
113}
114function unique(arr) {
115 var temp = {};
116 for (var _i = 0, arr_1 = arr; _i < arr_1.length; _i++) {
117 var e = arr_1[_i];
118 temp[e] = true;
119 }
120 var r = [];
121 for (var k in temp) {
122 if (Object.prototype.hasOwnProperty.call(temp, k)) {
123 r.push(k);
124 }
125 }
126 return r;
127}
128function resolveRequiredFile(symbol, key, fileName, objectName) {
129 var sourceFile = getSourceFile(symbol);
130 var requiredFilePath = /^[.\/]+/.test(fileName)
131 ? fileName === "."
132 ? path.resolve(sourceFile.fileName)
133 : path.resolve(path.dirname(sourceFile.fileName), fileName)
134 : fileName;
135 var requiredFile = require(requiredFilePath);
136 if (!requiredFile) {
137 throw Error("Required: File couldn't be loaded");
138 }
139 var requiredObject = objectName ? requiredFile[objectName] : requiredFile.default;
140 if (requiredObject === undefined) {
141 throw Error("Required: Variable is undefined");
142 }
143 if (typeof requiredObject === "function") {
144 throw Error("Required: Can't use function as a variable");
145 }
146 if (key === "examples" && !Array.isArray(requiredObject)) {
147 throw Error("Required: Variable isn't an array");
148 }
149 return requiredObject;
150}
151function regexRequire(value) {
152 return REGEX_REQUIRE.exec(value);
153}
154exports.regexRequire = regexRequire;
155function parseValue(symbol, key, value) {
156 var match = regexRequire(value);
157 if (match) {
158 var fileName = match[2].substr(1, match[2].length - 2).trim();
159 var objectName = match[4];
160 return resolveRequiredFile(symbol, key, fileName, objectName);
161 }
162 try {
163 return JSON.parse(value);
164 }
165 catch (error) {
166 return value;
167 }
168}
169function extractLiteralValue(typ) {
170 var str = typ.value;
171 if (str === undefined) {
172 str = typ.text;
173 }
174 if (typ.flags & ts.TypeFlags.StringLiteral) {
175 return str;
176 }
177 else if (typ.flags & ts.TypeFlags.BooleanLiteral) {
178 return typ.intrinsicName === "true";
179 }
180 else if (typ.flags & ts.TypeFlags.EnumLiteral) {
181 var num = parseFloat(str);
182 return isNaN(num) ? str : num;
183 }
184 else if (typ.flags & ts.TypeFlags.NumberLiteral) {
185 return parseFloat(str);
186 }
187 return undefined;
188}
189function resolveTupleType(propertyType) {
190 if (!propertyType.getSymbol() &&
191 propertyType.getFlags() & ts.TypeFlags.Object &&
192 propertyType.objectFlags & ts.ObjectFlags.Reference) {
193 return propertyType.target;
194 }
195 if (!(propertyType.getFlags() & ts.TypeFlags.Object &&
196 propertyType.objectFlags & ts.ObjectFlags.Tuple)) {
197 return null;
198 }
199 return propertyType;
200}
201var simpleTypesAllowedProperties = {
202 type: true,
203 description: true,
204};
205function addSimpleType(def, type) {
206 for (var k in def) {
207 if (!simpleTypesAllowedProperties[k]) {
208 return false;
209 }
210 }
211 if (!def.type) {
212 def.type = type;
213 }
214 else if (typeof def.type !== "string") {
215 if (!def.type.every(function (val) {
216 return typeof val === "string";
217 })) {
218 return false;
219 }
220 if (def.type.indexOf("null") === -1) {
221 def.type.push("null");
222 }
223 }
224 else {
225 if (typeof def.type !== "string") {
226 return false;
227 }
228 if (def.type !== "null") {
229 def.type = [def.type, "null"];
230 }
231 }
232 return true;
233}
234function makeNullable(def) {
235 if (!addSimpleType(def, "null")) {
236 var union = def.oneOf || def.anyOf;
237 if (union) {
238 union.push({ type: "null" });
239 }
240 else {
241 var subdef = {};
242 for (var k in def) {
243 if (def.hasOwnProperty(k)) {
244 subdef[k] = def[k];
245 delete def[k];
246 }
247 }
248 def.anyOf = [subdef, { type: "null" }];
249 }
250 }
251 return def;
252}
253function getCanonicalDeclaration(sym) {
254 var _a, _b, _c;
255 if (sym.valueDeclaration !== undefined) {
256 return sym.valueDeclaration;
257 }
258 else if (((_a = sym.declarations) === null || _a === void 0 ? void 0 : _a.length) === 1) {
259 return sym.declarations[0];
260 }
261 var declarationCount = (_c = (_b = sym.declarations) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0;
262 throw new Error("Symbol \"".concat(sym.name, "\" has no valueDeclaration and ").concat(declarationCount, " declarations."));
263}
264function getSourceFile(sym) {
265 var currentDecl = getCanonicalDeclaration(sym);
266 while (currentDecl.kind !== ts.SyntaxKind.SourceFile) {
267 if (currentDecl.parent === undefined) {
268 throw new Error("Unable to locate source file for declaration \"".concat(sym.name, "\"."));
269 }
270 currentDecl = currentDecl.parent;
271 }
272 return currentDecl;
273}
274var validationKeywords = {
275 multipleOf: true,
276 maximum: true,
277 exclusiveMaximum: true,
278 minimum: true,
279 exclusiveMinimum: true,
280 maxLength: true,
281 minLength: true,
282 pattern: true,
283 items: true,
284 maxItems: true,
285 minItems: true,
286 uniqueItems: true,
287 contains: true,
288 maxProperties: true,
289 minProperties: true,
290 additionalProperties: true,
291 enum: true,
292 type: true,
293 examples: true,
294 ignore: true,
295 description: true,
296 format: true,
297 default: true,
298 $ref: true,
299 id: true,
300 $id: true,
301 $comment: true,
302 title: true
303};
304var annotationKeywords = {
305 description: true,
306 default: true,
307 examples: true,
308 title: true,
309 $ref: true,
310};
311var subDefinitions = {
312 items: true,
313 additionalProperties: true,
314 contains: true,
315};
316var JsonSchemaGenerator = (function () {
317 function JsonSchemaGenerator(symbols, allSymbols, userSymbols, inheritingTypes, tc, args) {
318 if (args === void 0) { args = getDefaultArgs(); }
319 this.args = args;
320 this.reffedDefinitions = {};
321 this.schemaOverrides = new Map();
322 this.typeNamesById = {};
323 this.typeIdsByName = {};
324 this.recursiveTypeRef = new Map();
325 this.symbols = symbols;
326 this.allSymbols = allSymbols;
327 this.userSymbols = userSymbols;
328 this.inheritingTypes = inheritingTypes;
329 this.tc = tc;
330 this.userValidationKeywords = args.validationKeywords.reduce(function (acc, word) {
331 var _a;
332 return (__assign(__assign({}, acc), (_a = {}, _a[word] = true, _a)));
333 }, {});
334 this.constAsEnum = args.constAsEnum;
335 }
336 Object.defineProperty(JsonSchemaGenerator.prototype, "ReffedDefinitions", {
337 get: function () {
338 return this.reffedDefinitions;
339 },
340 enumerable: false,
341 configurable: true
342 });
343 JsonSchemaGenerator.prototype.isFromDefaultLib = function (symbol) {
344 var declarations = symbol.getDeclarations();
345 if (declarations && declarations.length > 0 && declarations[0].parent) {
346 return declarations[0].parent.getSourceFile().hasNoDefaultLib;
347 }
348 return false;
349 };
350 JsonSchemaGenerator.prototype.resetSchemaSpecificProperties = function (includeAllOverrides) {
351 var _this = this;
352 if (includeAllOverrides === void 0) { includeAllOverrides = false; }
353 this.reffedDefinitions = {};
354 this.typeIdsByName = {};
355 this.typeNamesById = {};
356 if (includeAllOverrides) {
357 this.schemaOverrides.forEach(function (value, key) {
358 _this.reffedDefinitions[key] = value;
359 });
360 }
361 };
362 JsonSchemaGenerator.prototype.parseCommentsIntoDefinition = function (symbol, definition, otherAnnotations) {
363 var _this = this;
364 if (!symbol) {
365 return;
366 }
367 if (!this.isFromDefaultLib(symbol)) {
368 var comments = symbol.getDocumentationComment(this.tc);
369 if (comments.length) {
370 definition.description = comments
371 .map(function (comment) {
372 var newlineNormalizedComment = comment.text.replace(/\r\n/g, "\n");
373 if (comment.kind === "linkText") {
374 return newlineNormalizedComment.trim();
375 }
376 return newlineNormalizedComment;
377 })
378 .join("").trim();
379 }
380 }
381 var jsdocs = symbol.getJsDocTags();
382 jsdocs.forEach(function (doc) {
383 var _a, _b;
384 var name = doc.name;
385 var originalText = doc.text ? doc.text.map(function (t) { return t.text; }).join("") : "";
386 var text = originalText;
387 if (name.startsWith("TJS-")) {
388 name = name.slice(4);
389 if (!text) {
390 text = "true";
391 }
392 }
393 else if (name === "TJS" && text.startsWith("-")) {
394 var match = new RegExp(REGEX_TJS_JSDOC).exec(originalText);
395 if (match) {
396 name = match[1];
397 text = match[2];
398 }
399 else {
400 name = text.replace(/^[\s\-]+/, "");
401 text = "true";
402 }
403 }
404 if (subDefinitions[name]) {
405 var match = new RegExp(REGEX_GROUP_JSDOC).exec(text);
406 if (match) {
407 var k = match[1];
408 var v = match[2];
409 definition[name] = __assign(__assign({}, definition[name]), (_a = {}, _a[k] = v ? parseValue(symbol, k, v) : true, _a));
410 return;
411 }
412 }
413 if (name.includes(".")) {
414 var parts = name.split(".");
415 var key = parts[0];
416 if (parts.length === 2 && subDefinitions[key]) {
417 definition[key] = __assign(__assign({}, definition[key]), (_b = {}, _b[parts[1]] = text ? parseValue(symbol, name, text) : true, _b));
418 }
419 }
420 if (validationKeywords[name] || _this.userValidationKeywords[name]) {
421 definition[name] = text === undefined ? "" : parseValue(symbol, name, text);
422 }
423 else {
424 otherAnnotations[doc.name] = true;
425 }
426 });
427 };
428 JsonSchemaGenerator.prototype.getDefinitionForRootType = function (propertyType, reffedType, definition, defaultNumberType, ignoreUndefined) {
429 var _a;
430 var _this = this;
431 var _b;
432 if (defaultNumberType === void 0) { defaultNumberType = this.args.defaultNumberType; }
433 if (ignoreUndefined === void 0) { ignoreUndefined = false; }
434 var tupleType = resolveTupleType(propertyType);
435 if (tupleType) {
436 var elemTypes = propertyType.typeArguments;
437 var fixedTypes = elemTypes.map(function (elType) { return _this.getTypeDefinition(elType); });
438 definition.type = "array";
439 if (fixedTypes.length > 0) {
440 definition.items = fixedTypes;
441 }
442 var targetTupleType = propertyType.target;
443 definition.minItems = targetTupleType.minLength;
444 if (targetTupleType.hasRestElement) {
445 definition.additionalItems = fixedTypes[fixedTypes.length - 1];
446 fixedTypes.splice(fixedTypes.length - 1, 1);
447 }
448 else {
449 definition.maxItems = targetTupleType.fixedLength;
450 }
451 }
452 else {
453 var propertyTypeString = this.tc.typeToString(propertyType, undefined, ts.TypeFormatFlags.UseFullyQualifiedType);
454 var flags = propertyType.flags;
455 var arrayType = this.tc.getIndexTypeOfType(propertyType, ts.IndexKind.Number);
456 if (flags & ts.TypeFlags.String) {
457 definition.type = "string";
458 }
459 else if (flags & ts.TypeFlags.Number) {
460 var isInteger = definition.type === "integer" ||
461 (reffedType === null || reffedType === void 0 ? void 0 : reffedType.getName()) === "integer" ||
462 defaultNumberType === "integer";
463 definition.type = isInteger ? "integer" : "number";
464 }
465 else if (flags & ts.TypeFlags.Boolean) {
466 definition.type = "boolean";
467 }
468 else if (flags & ts.TypeFlags.ESSymbol) {
469 definition.type = "object";
470 }
471 else if (flags & ts.TypeFlags.Null) {
472 definition.type = "null";
473 }
474 else if (flags & ts.TypeFlags.Undefined || propertyTypeString === "void") {
475 if (!ignoreUndefined) {
476 throw new Error("Not supported: root type undefined");
477 }
478 definition.type = "undefined";
479 }
480 else if (flags & ts.TypeFlags.Any || flags & ts.TypeFlags.Unknown) {
481 }
482 else if (propertyTypeString === "Date" && !this.args.rejectDateType) {
483 definition.type = "string";
484 definition.format = definition.format || "date-time";
485 }
486 else if (propertyTypeString === "object") {
487 definition.type = "object";
488 definition.properties = {};
489 definition.additionalProperties = true;
490 }
491 else if (propertyTypeString === "bigint") {
492 definition.type = "number";
493 definition.properties = {};
494 definition.additionalProperties = false;
495 }
496 else {
497 var value = extractLiteralValue(propertyType);
498 if (value !== undefined) {
499 var typeofValue = typeof value;
500 switch (typeofValue) {
501 case "string":
502 case "boolean":
503 definition.type = typeofValue;
504 break;
505 case "number":
506 definition.type = this.args.defaultNumberType;
507 break;
508 case "object":
509 definition.type = "null";
510 break;
511 default:
512 throw new Error("Not supported: ".concat(value, " as a enum value"));
513 }
514 if (this.constAsEnum) {
515 definition.enum = [value];
516 }
517 else {
518 definition.const = value;
519 }
520 }
521 else if (arrayType !== undefined) {
522 if (propertyType.flags & ts.TypeFlags.Object &&
523 propertyType.objectFlags &
524 (ts.ObjectFlags.Anonymous | ts.ObjectFlags.Interface | ts.ObjectFlags.Mapped)) {
525 definition.type = "object";
526 definition.additionalProperties = false;
527 definition.patternProperties = (_a = {},
528 _a[NUMERIC_INDEX_PATTERN] = this.getTypeDefinition(arrayType),
529 _a);
530 if (!!((_b = Array.from(propertyType.members)) === null || _b === void 0 ? void 0 : _b.find(function (member) { return member[0] !== "__index"; }))) {
531 this.getClassDefinition(propertyType, definition);
532 }
533 }
534 else if (propertyType.flags & ts.TypeFlags.TemplateLiteral) {
535 definition.type = "string";
536 var texts = propertyType.texts, types = propertyType.types;
537 var pattern = [];
538 for (var i = 0; i < texts.length; i++) {
539 var text = texts[i].replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
540 var type = types[i];
541 if (i === 0) {
542 pattern.push("^");
543 }
544 if (type) {
545 if (type.flags & ts.TypeFlags.String) {
546 pattern.push("".concat(text, ".*"));
547 }
548 if (type.flags & ts.TypeFlags.Number
549 || type.flags & ts.TypeFlags.BigInt) {
550 pattern.push("".concat(text, "[0-9]*"));
551 }
552 if (type.flags & ts.TypeFlags.Undefined) {
553 pattern.push("".concat(text, "undefined"));
554 }
555 if (type.flags & ts.TypeFlags.Null) {
556 pattern.push("".concat(text, "null"));
557 }
558 }
559 if (i === texts.length - 1) {
560 pattern.push("".concat(text, "$"));
561 }
562 }
563 definition.pattern = pattern.join("");
564 }
565 else {
566 definition.type = "array";
567 if (!definition.items) {
568 definition.items = this.getTypeDefinition(arrayType);
569 }
570 }
571 }
572 else {
573 var error = new TypeError("Unsupported type: " + propertyTypeString);
574 error.type = propertyType;
575 throw error;
576 }
577 }
578 }
579 return definition;
580 };
581 JsonSchemaGenerator.prototype.getReferencedTypeSymbol = function (prop) {
582 var decl = prop.getDeclarations();
583 if (decl === null || decl === void 0 ? void 0 : decl.length) {
584 var type = decl[0].type;
585 if (type && type.kind & ts.SyntaxKind.TypeReference && type.typeName) {
586 var symbol = this.tc.getSymbolAtLocation(type.typeName);
587 if (symbol && symbol.flags & ts.SymbolFlags.Alias) {
588 return this.tc.getAliasedSymbol(symbol);
589 }
590 return symbol;
591 }
592 }
593 return undefined;
594 };
595 JsonSchemaGenerator.prototype.getDefinitionForProperty = function (prop, node) {
596 if (prop.flags & ts.SymbolFlags.Method) {
597 return null;
598 }
599 var propertyName = prop.getName();
600 var propertyType = this.tc.getTypeOfSymbolAtLocation(prop, node);
601 var reffedType = this.getReferencedTypeSymbol(prop);
602 var definition = this.getTypeDefinition(propertyType, undefined, undefined, prop, reffedType);
603 if (this.args.titles) {
604 definition.title = propertyName;
605 }
606 if (definition.hasOwnProperty("ignore")) {
607 return null;
608 }
609 var valDecl = prop.valueDeclaration;
610 if (valDecl === null || valDecl === void 0 ? void 0 : valDecl.initializer) {
611 var initial = valDecl.initializer;
612 while (ts.isTypeAssertionExpression(initial)) {
613 initial = initial.expression;
614 }
615 if (initial.expression) {
616 console.warn("initializer is expression for property " + propertyName);
617 }
618 else if (initial.kind && initial.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral) {
619 definition.default = initial.getText();
620 }
621 else {
622 try {
623 var sandbox = { sandboxvar: null };
624 vm.runInNewContext("sandboxvar=" + initial.getText(), sandbox);
625 var val = sandbox.sandboxvar;
626 if (val === null ||
627 typeof val === "string" ||
628 typeof val === "number" ||
629 typeof val === "boolean" ||
630 Object.prototype.toString.call(val) === "[object Array]") {
631 definition.default = val;
632 }
633 else if (val) {
634 console.warn("unknown initializer for property " + propertyName + ": " + val);
635 }
636 }
637 catch (e) {
638 console.warn("exception evaluating initializer for property " + propertyName);
639 }
640 }
641 }
642 return definition;
643 };
644 JsonSchemaGenerator.prototype.getEnumDefinition = function (clazzType, definition) {
645 var _this = this;
646 var node = clazzType.getSymbol().getDeclarations()[0];
647 var fullName = this.tc.typeToString(clazzType, undefined, ts.TypeFormatFlags.UseFullyQualifiedType);
648 var members = node.kind === ts.SyntaxKind.EnumDeclaration
649 ? node.members
650 : ts.factory.createNodeArray([node]);
651 var enumValues = [];
652 var enumTypes = [];
653 var addType = function (type) {
654 if (enumTypes.indexOf(type) === -1) {
655 enumTypes.push(type);
656 }
657 };
658 members.forEach(function (member) {
659 var caseLabel = member.name.text;
660 var constantValue = _this.tc.getConstantValue(member);
661 if (constantValue !== undefined) {
662 enumValues.push(constantValue);
663 addType(typeof constantValue);
664 }
665 else {
666 var initial = member.initializer;
667 if (initial) {
668 if (initial.expression) {
669 var exp = initial.expression;
670 var text = exp.text;
671 if (text) {
672 enumValues.push(text);
673 addType("string");
674 }
675 else if (exp.kind === ts.SyntaxKind.TrueKeyword || exp.kind === ts.SyntaxKind.FalseKeyword) {
676 enumValues.push(exp.kind === ts.SyntaxKind.TrueKeyword);
677 addType("boolean");
678 }
679 else {
680 console.warn("initializer is expression for enum: " + fullName + "." + caseLabel);
681 }
682 }
683 else if (initial.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral) {
684 enumValues.push(initial.getText());
685 addType("string");
686 }
687 else if (initial.kind === ts.SyntaxKind.NullKeyword) {
688 enumValues.push(null);
689 addType("null");
690 }
691 }
692 }
693 });
694 if (enumTypes.length) {
695 definition.type = enumTypes.length === 1 ? enumTypes[0] : enumTypes;
696 }
697 if (enumValues.length > 0) {
698 if (enumValues.length > 1) {
699 definition.enum = enumValues;
700 }
701 else {
702 definition.const = enumValues[0];
703 }
704 }
705 return definition;
706 };
707 JsonSchemaGenerator.prototype.getUnionDefinition = function (unionType, unionModifier, definition) {
708 var enumValues = [];
709 var simpleTypes = [];
710 var schemas = [];
711 var pushSimpleType = function (type) {
712 if (simpleTypes.indexOf(type) === -1) {
713 simpleTypes.push(type);
714 }
715 };
716 var pushEnumValue = function (val) {
717 if (enumValues.indexOf(val) === -1) {
718 enumValues.push(val);
719 }
720 };
721 for (var _i = 0, _a = unionType.types; _i < _a.length; _i++) {
722 var valueType = _a[_i];
723 var value = extractLiteralValue(valueType);
724 if (value !== undefined) {
725 pushEnumValue(value);
726 }
727 else {
728 var symbol = valueType.aliasSymbol;
729 var def = this.getTypeDefinition(valueType, undefined, undefined, symbol, symbol, undefined, undefined, true);
730 if (def.type === "undefined") {
731 continue;
732 }
733 var keys = Object.keys(def);
734 if (keys.length === 1 && keys[0] === "type") {
735 if (typeof def.type !== "string") {
736 console.error("Expected only a simple type.");
737 }
738 else {
739 pushSimpleType(def.type);
740 }
741 }
742 else {
743 schemas.push(def);
744 }
745 }
746 }
747 if (enumValues.length > 0) {
748 var isOnlyBooleans = enumValues.length === 2 &&
749 typeof enumValues[0] === "boolean" &&
750 typeof enumValues[1] === "boolean" &&
751 enumValues[0] !== enumValues[1];
752 if (isOnlyBooleans) {
753 pushSimpleType("boolean");
754 }
755 else {
756 var enumSchema = enumValues.length > 1 ? { enum: enumValues.sort() } : { const: enumValues[0] };
757 if (enumValues.every(function (x) {
758 return typeof x === "string";
759 })) {
760 enumSchema.type = "string";
761 }
762 else if (enumValues.every(function (x) {
763 return typeof x === "number";
764 })) {
765 enumSchema.type = "number";
766 }
767 else if (enumValues.every(function (x) {
768 return typeof x === "boolean";
769 })) {
770 enumSchema.type = "boolean";
771 }
772 schemas.push(enumSchema);
773 }
774 }
775 if (simpleTypes.length > 0) {
776 schemas.push({ type: simpleTypes.length === 1 ? simpleTypes[0] : simpleTypes });
777 }
778 if (schemas.length === 1) {
779 for (var k in schemas[0]) {
780 if (schemas[0].hasOwnProperty(k)) {
781 if (k === "description" && definition.hasOwnProperty(k)) {
782 continue;
783 }
784 definition[k] = schemas[0][k];
785 }
786 }
787 }
788 else {
789 definition[unionModifier] = schemas;
790 }
791 return definition;
792 };
793 JsonSchemaGenerator.prototype.getIntersectionDefinition = function (intersectionType, definition) {
794 var simpleTypes = [];
795 var schemas = [];
796 var pushSimpleType = function (type) {
797 if (simpleTypes.indexOf(type) === -1) {
798 simpleTypes.push(type);
799 }
800 };
801 for (var _i = 0, _a = intersectionType.types; _i < _a.length; _i++) {
802 var intersectionMember = _a[_i];
803 var def = this.getTypeDefinition(intersectionMember);
804 var keys = Object.keys(def);
805 if (keys.length === 1 && keys[0] === "type") {
806 if (typeof def.type !== "string") {
807 console.error("Expected only a simple type.");
808 }
809 else {
810 pushSimpleType(def.type);
811 }
812 }
813 else {
814 schemas.push(def);
815 }
816 }
817 if (simpleTypes.length > 0) {
818 schemas.push({ type: simpleTypes.length === 1 ? simpleTypes[0] : simpleTypes });
819 }
820 if (schemas.length === 1) {
821 for (var k in schemas[0]) {
822 if (schemas[0].hasOwnProperty(k)) {
823 definition[k] = schemas[0][k];
824 }
825 }
826 }
827 else {
828 definition.allOf = schemas;
829 }
830 return definition;
831 };
832 JsonSchemaGenerator.prototype.getClassDefinition = function (clazzType, definition) {
833 var _this = this;
834 var _a, _b;
835 var node = clazzType.getSymbol().getDeclarations()[0];
836 if (!node) {
837 definition.type = "object";
838 return definition;
839 }
840 if (this.args.typeOfKeyword && node.kind === ts.SyntaxKind.FunctionType) {
841 definition.typeof = "function";
842 return definition;
843 }
844 var clazz = node;
845 var props = this.tc.getPropertiesOfType(clazzType).filter(function (prop) {
846 var propertyFlagType = _this.tc.getTypeOfSymbolAtLocation(prop, node).getFlags();
847 if (ts.TypeFlags.Never === propertyFlagType || ts.TypeFlags.Undefined === propertyFlagType) {
848 return false;
849 }
850 if (!_this.args.excludePrivate) {
851 return true;
852 }
853 var decls = prop.declarations;
854 return !(decls &&
855 decls.filter(function (decl) {
856 var mods = decl.modifiers;
857 return mods && mods.filter(function (mod) { return mod.kind === ts.SyntaxKind.PrivateKeyword; }).length > 0;
858 }).length > 0);
859 });
860 var fullName = this.tc.typeToString(clazzType, undefined, ts.TypeFormatFlags.UseFullyQualifiedType);
861 var modifierFlags = ts.getCombinedModifierFlags(node);
862 if (modifierFlags & ts.ModifierFlags.Abstract && this.inheritingTypes[fullName]) {
863 var oneOf = this.inheritingTypes[fullName].map(function (typename) {
864 return _this.getTypeDefinition(_this.allSymbols[typename]);
865 });
866 definition.oneOf = oneOf;
867 }
868 else {
869 if (clazz.members) {
870 var indexSignatures = clazz.members == null ? [] : clazz.members.filter(function (x) { return x.kind === ts.SyntaxKind.IndexSignature; });
871 if (indexSignatures.length === 1) {
872 var indexSignature = indexSignatures[0];
873 if (indexSignature.parameters.length !== 1) {
874 throw new Error("Not supported: IndexSignatureDeclaration parameters.length != 1");
875 }
876 var indexSymbol = indexSignature.parameters[0].symbol;
877 var indexType = this.tc.getTypeOfSymbolAtLocation(indexSymbol, node);
878 var isIndexedObject = indexType.flags === ts.TypeFlags.String || indexType.flags === ts.TypeFlags.Number;
879 if (indexType.flags !== ts.TypeFlags.Number && !isIndexedObject) {
880 throw new Error("Not supported: IndexSignatureDeclaration with index symbol other than a number or a string");
881 }
882 var typ = this.tc.getTypeAtLocation(indexSignature.type);
883 var def = void 0;
884 if (typ.flags & ts.TypeFlags.IndexedAccess) {
885 var targetName = ts.escapeLeadingUnderscores((_b = (_a = clazzType.mapper) === null || _a === void 0 ? void 0 : _a.target) === null || _b === void 0 ? void 0 : _b.value);
886 var indexedAccessType = typ;
887 var symbols = indexedAccessType.objectType.members;
888 var targetSymbol = symbols === null || symbols === void 0 ? void 0 : symbols.get(targetName);
889 if (targetSymbol) {
890 var targetNode = targetSymbol.getDeclarations()[0];
891 var targetDef = this.getDefinitionForProperty(targetSymbol, targetNode);
892 if (targetDef) {
893 def = targetDef;
894 }
895 }
896 }
897 if (!def) {
898 def = this.getTypeDefinition(typ, undefined, "anyOf");
899 }
900 if (isIndexedObject) {
901 definition.type = "object";
902 if (!Object.keys(definition.patternProperties || {}).length) {
903 definition.additionalProperties = def;
904 }
905 }
906 else {
907 definition.type = "array";
908 if (!definition.items) {
909 definition.items = def;
910 }
911 }
912 }
913 }
914 var propertyDefinitions = props.reduce(function (all, prop) {
915 var propertyName = prop.getName();
916 var propDef = _this.getDefinitionForProperty(prop, node);
917 if (propDef != null) {
918 all[propertyName] = propDef;
919 }
920 return all;
921 }, {});
922 if (definition.type === undefined) {
923 definition.type = "object";
924 }
925 if (definition.type === "object" && Object.keys(propertyDefinitions).length > 0) {
926 definition.properties = propertyDefinitions;
927 }
928 if (this.args.defaultProps) {
929 definition.defaultProperties = [];
930 }
931 if (this.args.noExtraProps && definition.additionalProperties === undefined) {
932 definition.additionalProperties = false;
933 }
934 if (this.args.propOrder) {
935 var propertyOrder = props.reduce(function (order, prop) {
936 order.push(prop.getName());
937 return order;
938 }, []);
939 definition.propertyOrder = propertyOrder;
940 }
941 if (this.args.required) {
942 var requiredProps = props.reduce(function (required, prop) {
943 var _a, _b, _c, _d;
944 var def = {};
945 _this.parseCommentsIntoDefinition(prop, def, {});
946 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; })) || [];
947 if (!(prop.flags & ts.SymbolFlags.Optional) &&
948 !(prop.flags & ts.SymbolFlags.Method) &&
949 !allUnionTypesFlags.includes(ts.TypeFlags.Undefined) &&
950 !allUnionTypesFlags.includes(ts.TypeFlags.Void) &&
951 !def.hasOwnProperty("ignore")) {
952 required.push(prop.getName());
953 }
954 return required;
955 }, []);
956 if (requiredProps.length > 0) {
957 definition.required = unique(requiredProps).sort();
958 }
959 }
960 }
961 return definition;
962 };
963 JsonSchemaGenerator.prototype.getTypeName = function (typ) {
964 var id = typ.id;
965 if (this.typeNamesById[id]) {
966 return this.typeNamesById[id];
967 }
968 return this.makeTypeNameUnique(typ, this.tc
969 .typeToString(typ, undefined, ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.UseFullyQualifiedType)
970 .replace(REGEX_FILE_NAME_OR_SPACE, ""));
971 };
972 JsonSchemaGenerator.prototype.makeTypeNameUnique = function (typ, baseName) {
973 var id = typ.id;
974 var name = baseName;
975 for (var i = 1; this.typeIdsByName[name] !== undefined && this.typeIdsByName[name] !== id; ++i) {
976 name = baseName + "_" + i;
977 }
978 this.typeNamesById[id] = name;
979 this.typeIdsByName[name] = id;
980 return name;
981 };
982 JsonSchemaGenerator.prototype.getTypeDefinition = function (typ, asRef, unionModifier, prop, reffedType, pairedSymbol, forceNotRef, ignoreUndefined) {
983 var _a;
984 if (asRef === void 0) { asRef = this.args.ref; }
985 if (unionModifier === void 0) { unionModifier = "anyOf"; }
986 if (forceNotRef === void 0) { forceNotRef = false; }
987 if (ignoreUndefined === void 0) { ignoreUndefined = false; }
988 var definition = {};
989 while (typ.aliasSymbol &&
990 (typ.aliasSymbol.escapedName === "Readonly" || typ.aliasSymbol.escapedName === "Mutable") &&
991 typ.aliasTypeArguments &&
992 typ.aliasTypeArguments[0]) {
993 typ = typ.aliasTypeArguments[0];
994 reffedType = undefined;
995 }
996 if (this.args.typeOfKeyword &&
997 typ.flags & ts.TypeFlags.Object &&
998 typ.objectFlags & ts.ObjectFlags.Anonymous) {
999 definition.typeof = "function";
1000 return definition;
1001 }
1002 var returnedDefinition = definition;
1003 if (prop) {
1004 var defs = {};
1005 var others = {};
1006 this.parseCommentsIntoDefinition(prop, defs, others);
1007 if (defs.hasOwnProperty("ignore") || defs.hasOwnProperty("type")) {
1008 return defs;
1009 }
1010 }
1011 var symbol = typ.getSymbol();
1012 var isRawType = !symbol ||
1013 (this.tc.getFullyQualifiedName(symbol) !== "Window" &&
1014 (this.tc.getFullyQualifiedName(symbol) === "Date" ||
1015 symbol.name === "integer" ||
1016 this.tc.getIndexInfoOfType(typ, ts.IndexKind.Number) !== undefined));
1017 if (isRawType && ((_a = typ.aliasSymbol) === null || _a === void 0 ? void 0 : _a.escapedName) && typ.types) {
1018 isRawType = false;
1019 }
1020 var isStringEnum = false;
1021 if (typ.flags & ts.TypeFlags.Union) {
1022 var unionType = typ;
1023 isStringEnum = unionType.types.every(function (propType) {
1024 return (propType.getFlags() & ts.TypeFlags.StringLiteral) !== 0;
1025 });
1026 }
1027 var asTypeAliasRef = asRef && reffedType && (this.args.aliasRef || isStringEnum);
1028 if (!asTypeAliasRef) {
1029 if (isRawType ||
1030 (typ.getFlags() & ts.TypeFlags.Object && typ.objectFlags & ts.ObjectFlags.Anonymous)) {
1031 asRef = false;
1032 }
1033 }
1034 var fullTypeName = "";
1035 if (asTypeAliasRef) {
1036 var typeName = this.tc
1037 .getFullyQualifiedName(reffedType.getFlags() & ts.SymbolFlags.Alias ? this.tc.getAliasedSymbol(reffedType) : reffedType)
1038 .replace(REGEX_FILE_NAME_OR_SPACE, "");
1039 if (this.args.uniqueNames && reffedType) {
1040 var sourceFile = getSourceFile(reffedType);
1041 var relativePath = path.relative(process.cwd(), sourceFile.fileName);
1042 fullTypeName = "".concat(typeName, ".").concat(generateHashOfNode(getCanonicalDeclaration(reffedType), relativePath));
1043 }
1044 else {
1045 fullTypeName = this.makeTypeNameUnique(typ, typeName);
1046 }
1047 }
1048 else {
1049 if (this.args.uniqueNames && typ.symbol) {
1050 var sym = typ.symbol;
1051 var sourceFile = getSourceFile(sym);
1052 var relativePath = path.relative(process.cwd(), sourceFile.fileName);
1053 fullTypeName = "".concat(this.getTypeName(typ), ".").concat(generateHashOfNode(getCanonicalDeclaration(sym), relativePath));
1054 }
1055 else if (reffedType && this.schemaOverrides.has(reffedType.escapedName)) {
1056 fullTypeName = reffedType.escapedName;
1057 }
1058 else {
1059 fullTypeName = this.getTypeName(typ);
1060 }
1061 }
1062 if (!isRawType || !!typ.aliasSymbol) {
1063 if (this.recursiveTypeRef.has(fullTypeName) && !forceNotRef) {
1064 asRef = true;
1065 }
1066 else {
1067 this.recursiveTypeRef.set(fullTypeName, definition);
1068 }
1069 }
1070 if (asRef) {
1071 returnedDefinition = {
1072 $ref: "".concat(this.args.id, "#/definitions/") + fullTypeName,
1073 };
1074 }
1075 var otherAnnotations = {};
1076 this.parseCommentsIntoDefinition(reffedType, definition, otherAnnotations);
1077 this.parseCommentsIntoDefinition(symbol, definition, otherAnnotations);
1078 this.parseCommentsIntoDefinition(typ.aliasSymbol, definition, otherAnnotations);
1079 if (prop) {
1080 this.parseCommentsIntoDefinition(prop, returnedDefinition, otherAnnotations);
1081 }
1082 if (pairedSymbol && symbol && this.isFromDefaultLib(symbol)) {
1083 this.parseCommentsIntoDefinition(pairedSymbol, definition, otherAnnotations);
1084 }
1085 var overrideDefinition = this.schemaOverrides.get(fullTypeName);
1086 if (overrideDefinition) {
1087 this.reffedDefinitions[fullTypeName] = overrideDefinition;
1088 }
1089 else if (!asRef || !this.reffedDefinitions[fullTypeName]) {
1090 if (asRef) {
1091 var reffedDefinition = void 0;
1092 if (asTypeAliasRef && reffedType && typ.symbol !== reffedType && symbol) {
1093 reffedDefinition = this.getTypeDefinition(typ, true, undefined, symbol, symbol);
1094 }
1095 else {
1096 reffedDefinition = definition;
1097 }
1098 this.reffedDefinitions[fullTypeName] = reffedDefinition;
1099 if (this.args.titles && fullTypeName) {
1100 definition.title = fullTypeName;
1101 }
1102 }
1103 var node = (symbol === null || symbol === void 0 ? void 0 : symbol.getDeclarations()) !== undefined ? symbol.getDeclarations()[0] : null;
1104 if (definition.type === undefined) {
1105 if (typ.flags & ts.TypeFlags.Union && (node === null || node.kind !== ts.SyntaxKind.EnumDeclaration)) {
1106 this.getUnionDefinition(typ, unionModifier, definition);
1107 }
1108 else if (typ.flags & ts.TypeFlags.Intersection) {
1109 if (this.args.noExtraProps) {
1110 if (this.args.noExtraProps) {
1111 definition.additionalProperties = false;
1112 }
1113 var types = typ.types;
1114 for (var _i = 0, types_1 = types; _i < types_1.length; _i++) {
1115 var member = types_1[_i];
1116 var other = this.getTypeDefinition(member, false, undefined, undefined, undefined, undefined, true);
1117 definition.type = other.type;
1118 definition.properties = __assign(__assign({}, definition.properties), other.properties);
1119 if (Object.keys(other.default || {}).length > 0) {
1120 definition.default = extend(definition.default || {}, other.default);
1121 }
1122 if (other.required) {
1123 definition.required = unique((definition.required || []).concat(other.required)).sort();
1124 }
1125 }
1126 }
1127 else {
1128 this.getIntersectionDefinition(typ, definition);
1129 }
1130 }
1131 else if (isRawType) {
1132 if (pairedSymbol) {
1133 this.parseCommentsIntoDefinition(pairedSymbol, definition, {});
1134 }
1135 this.getDefinitionForRootType(typ, reffedType, definition, undefined, ignoreUndefined);
1136 }
1137 else if (node &&
1138 (node.kind === ts.SyntaxKind.EnumDeclaration || node.kind === ts.SyntaxKind.EnumMember)) {
1139 this.getEnumDefinition(typ, definition);
1140 }
1141 else if (symbol &&
1142 symbol.flags & ts.SymbolFlags.TypeLiteral &&
1143 symbol.members.size === 0 &&
1144 !(node && node.kind === ts.SyntaxKind.MappedType)) {
1145 definition.type = "object";
1146 definition.properties = {};
1147 }
1148 else {
1149 this.getClassDefinition(typ, definition);
1150 }
1151 }
1152 }
1153 if (this.recursiveTypeRef.get(fullTypeName) === definition) {
1154 this.recursiveTypeRef.delete(fullTypeName);
1155 if (this.reffedDefinitions[fullTypeName]) {
1156 var annotations = Object.entries(returnedDefinition).reduce(function (acc, _a) {
1157 var key = _a[0], value = _a[1];
1158 if (annotationKeywords[key] && typeof value !== undefined) {
1159 acc[key] = value;
1160 }
1161 return acc;
1162 }, {});
1163 returnedDefinition = __assign({ $ref: "".concat(this.args.id, "#/definitions/") + fullTypeName }, annotations);
1164 }
1165 }
1166 if (otherAnnotations["nullable"]) {
1167 makeNullable(returnedDefinition);
1168 }
1169 return returnedDefinition;
1170 };
1171 JsonSchemaGenerator.prototype.setSchemaOverride = function (symbolName, schema) {
1172 this.schemaOverrides.set(symbolName, schema);
1173 };
1174 JsonSchemaGenerator.prototype.getSchemaForSymbol = function (symbolName, includeReffedDefinitions, includeAllOverrides) {
1175 if (includeReffedDefinitions === void 0) { includeReffedDefinitions = true; }
1176 if (includeAllOverrides === void 0) { includeAllOverrides = false; }
1177 var overrideDefinition = this.schemaOverrides.get(symbolName);
1178 if (!this.allSymbols[symbolName] && !overrideDefinition) {
1179 throw new Error("type ".concat(symbolName, " not found"));
1180 }
1181 this.resetSchemaSpecificProperties(includeAllOverrides);
1182 var def;
1183 if (overrideDefinition) {
1184 def = __assign({}, overrideDefinition);
1185 }
1186 else {
1187 def = overrideDefinition ? overrideDefinition : this.getTypeDefinition(this.allSymbols[symbolName], this.args.topRef, undefined, undefined, undefined, this.userSymbols[symbolName] || undefined);
1188 }
1189 if (this.args.ref && includeReffedDefinitions && Object.keys(this.reffedDefinitions).length > 0) {
1190 def.definitions = this.reffedDefinitions;
1191 }
1192 def["$schema"] = "http://json-schema.org/draft-07/schema#";
1193 var id = this.args.id;
1194 if (id) {
1195 def["$id"] = this.args.id;
1196 }
1197 return def;
1198 };
1199 JsonSchemaGenerator.prototype.getSchemaForSymbols = function (symbolNames, includeReffedDefinitions, includeAllOverrides) {
1200 if (includeReffedDefinitions === void 0) { includeReffedDefinitions = true; }
1201 if (includeAllOverrides === void 0) { includeAllOverrides = false; }
1202 var root = {
1203 $schema: "http://json-schema.org/draft-07/schema#",
1204 definitions: {},
1205 };
1206 this.resetSchemaSpecificProperties(includeAllOverrides);
1207 var id = this.args.id;
1208 if (id) {
1209 root["$id"] = id;
1210 }
1211 for (var _i = 0, symbolNames_1 = symbolNames; _i < symbolNames_1.length; _i++) {
1212 var symbolName = symbolNames_1[_i];
1213 root.definitions[symbolName] = this.getTypeDefinition(this.allSymbols[symbolName], this.args.topRef, undefined, undefined, undefined, this.userSymbols[symbolName]);
1214 }
1215 if (this.args.ref && includeReffedDefinitions && Object.keys(this.reffedDefinitions).length > 0) {
1216 root.definitions = __assign(__assign({}, root.definitions), this.reffedDefinitions);
1217 }
1218 return root;
1219 };
1220 JsonSchemaGenerator.prototype.getSymbols = function (name) {
1221 if (name === void 0) {
1222 return this.symbols;
1223 }
1224 return this.symbols.filter(function (symbol) { return symbol.typeName === name; });
1225 };
1226 JsonSchemaGenerator.prototype.getUserSymbols = function () {
1227 return Object.keys(this.userSymbols);
1228 };
1229 JsonSchemaGenerator.prototype.getMainFileSymbols = function (program, onlyIncludeFiles) {
1230 var _this = this;
1231 function includeFile(file) {
1232 if (onlyIncludeFiles === undefined) {
1233 return !file.isDeclarationFile;
1234 }
1235 return onlyIncludeFiles.filter(function (f) { return (0, path_equal_1.pathEqual)(f, file.fileName); }).length > 0;
1236 }
1237 var files = program.getSourceFiles().filter(includeFile);
1238 if (files.length) {
1239 return Object.keys(this.userSymbols).filter(function (key) {
1240 var symbol = _this.userSymbols[key];
1241 if (!symbol || !symbol.declarations || !symbol.declarations.length) {
1242 return false;
1243 }
1244 var node = symbol.declarations[0];
1245 while (node === null || node === void 0 ? void 0 : node.parent) {
1246 node = node.parent;
1247 }
1248 return files.indexOf(node.getSourceFile()) > -1;
1249 });
1250 }
1251 return [];
1252 };
1253 return JsonSchemaGenerator;
1254}());
1255exports.JsonSchemaGenerator = JsonSchemaGenerator;
1256function getProgramFromFiles(files, jsonCompilerOptions, basePath) {
1257 if (jsonCompilerOptions === void 0) { jsonCompilerOptions = {}; }
1258 if (basePath === void 0) { basePath = "./"; }
1259 var compilerOptions = ts.convertCompilerOptionsFromJson(jsonCompilerOptions, basePath).options;
1260 var options = {
1261 noEmit: true,
1262 emitDecoratorMetadata: true,
1263 experimentalDecorators: true,
1264 target: ts.ScriptTarget.ES5,
1265 module: ts.ModuleKind.CommonJS,
1266 allowUnusedLabels: true,
1267 };
1268 for (var k in compilerOptions) {
1269 if (compilerOptions.hasOwnProperty(k)) {
1270 options[k] = compilerOptions[k];
1271 }
1272 }
1273 return ts.createProgram(files, options);
1274}
1275exports.getProgramFromFiles = getProgramFromFiles;
1276function generateHashOfNode(node, relativePath) {
1277 return (0, crypto_1.createHash)("md5").update(relativePath).update(node.pos.toString()).digest("hex").substring(0, 8);
1278}
1279function buildGenerator(program, args, onlyIncludeFiles) {
1280 if (args === void 0) { args = {}; }
1281 function isUserFile(file) {
1282 if (onlyIncludeFiles === undefined) {
1283 return !file.hasNoDefaultLib;
1284 }
1285 return onlyIncludeFiles.indexOf(file.fileName) >= 0;
1286 }
1287 var settings = getDefaultArgs();
1288 for (var pref in args) {
1289 if (args.hasOwnProperty(pref)) {
1290 settings[pref] = args[pref];
1291 }
1292 }
1293 if (args.tsNodeRegister) {
1294 require("ts-node/register");
1295 }
1296 var diagnostics = [];
1297 if (!args.ignoreErrors) {
1298 diagnostics = ts.getPreEmitDiagnostics(program);
1299 }
1300 if (diagnostics.length === 0) {
1301 var typeChecker_1 = program.getTypeChecker();
1302 var symbols_1 = [];
1303 var allSymbols_1 = {};
1304 var userSymbols_1 = {};
1305 var inheritingTypes_1 = {};
1306 var workingDir_1 = program.getCurrentDirectory();
1307 program.getSourceFiles().forEach(function (sourceFile, _sourceFileIdx) {
1308 var relativePath = path.relative(workingDir_1, sourceFile.fileName);
1309 function inspect(node, tc) {
1310 if (node.kind === ts.SyntaxKind.ClassDeclaration ||
1311 node.kind === ts.SyntaxKind.InterfaceDeclaration ||
1312 node.kind === ts.SyntaxKind.EnumDeclaration ||
1313 node.kind === ts.SyntaxKind.TypeAliasDeclaration) {
1314 var symbol = node.symbol;
1315 var nodeType = tc.getTypeAtLocation(node);
1316 var fullyQualifiedName = tc.getFullyQualifiedName(symbol);
1317 var typeName = fullyQualifiedName.replace(/".*"\./, "");
1318 var name_1 = !args.uniqueNames ? typeName : "".concat(typeName, ".").concat(generateHashOfNode(node, relativePath));
1319 symbols_1.push({ name: name_1, typeName: typeName, fullyQualifiedName: fullyQualifiedName, symbol: symbol });
1320 if (!userSymbols_1[name_1]) {
1321 allSymbols_1[name_1] = nodeType;
1322 }
1323 if (isUserFile(sourceFile)) {
1324 userSymbols_1[name_1] = symbol;
1325 }
1326 var baseTypes = nodeType.getBaseTypes() || [];
1327 baseTypes.forEach(function (baseType) {
1328 var baseName = tc.typeToString(baseType, undefined, ts.TypeFormatFlags.UseFullyQualifiedType);
1329 if (!inheritingTypes_1[baseName]) {
1330 inheritingTypes_1[baseName] = [];
1331 }
1332 inheritingTypes_1[baseName].push(name_1);
1333 });
1334 }
1335 else {
1336 ts.forEachChild(node, function (n) { return inspect(n, tc); });
1337 }
1338 }
1339 inspect(sourceFile, typeChecker_1);
1340 });
1341 return new JsonSchemaGenerator(symbols_1, allSymbols_1, userSymbols_1, inheritingTypes_1, typeChecker_1, settings);
1342 }
1343 else {
1344 diagnostics.forEach(function (diagnostic) {
1345 var message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
1346 if (diagnostic.file) {
1347 var _a = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start), line = _a.line, character = _a.character;
1348 console.error("".concat(diagnostic.file.fileName, " (").concat(line + 1, ",").concat(character + 1, "): ").concat(message));
1349 }
1350 else {
1351 console.error(message);
1352 }
1353 });
1354 return null;
1355 }
1356}
1357exports.buildGenerator = buildGenerator;
1358function generateSchema(program, fullTypeName, args, onlyIncludeFiles, externalGenerator) {
1359 if (args === void 0) { args = {}; }
1360 var generator = externalGenerator !== null && externalGenerator !== void 0 ? externalGenerator : buildGenerator(program, args, onlyIncludeFiles);
1361 if (generator === null) {
1362 return null;
1363 }
1364 if (fullTypeName === "*") {
1365 return generator.getSchemaForSymbols(generator.getMainFileSymbols(program, onlyIncludeFiles), true, true);
1366 }
1367 else if (args.uniqueNames) {
1368 var matchingSymbols = generator.getSymbols(fullTypeName);
1369 if (matchingSymbols.length === 1) {
1370 return generator.getSchemaForSymbol(matchingSymbols[0].name);
1371 }
1372 else {
1373 throw new Error("".concat(matchingSymbols.length, " definitions found for requested type \"").concat(fullTypeName, "\"."));
1374 }
1375 }
1376 else {
1377 return generator.getSchemaForSymbol(fullTypeName);
1378 }
1379}
1380exports.generateSchema = generateSchema;
1381function programFromConfig(configFileName, onlyIncludeFiles) {
1382 var result = ts.parseConfigFileTextToJson(configFileName, ts.sys.readFile(configFileName));
1383 var configObject = result.config;
1384 var configParseResult = ts.parseJsonConfigFileContent(configObject, ts.sys, path.dirname(configFileName), {}, path.basename(configFileName));
1385 var options = configParseResult.options;
1386 options.noEmit = true;
1387 delete options.out;
1388 delete options.outDir;
1389 delete options.outFile;
1390 delete options.declaration;
1391 delete options.declarationDir;
1392 delete options.declarationMap;
1393 var program = ts.createProgram({
1394 rootNames: onlyIncludeFiles || configParseResult.fileNames,
1395 options: options,
1396 projectReferences: configParseResult.projectReferences,
1397 });
1398 return program;
1399}
1400exports.programFromConfig = programFromConfig;
1401function normalizeFileName(fn) {
1402 while (fn.substr(0, 2) === "./") {
1403 fn = fn.substr(2);
1404 }
1405 return fn;
1406}
1407function exec(filePattern, fullTypeName, args) {
1408 if (args === void 0) { args = getDefaultArgs(); }
1409 return __awaiter(this, void 0, void 0, function () {
1410 var program, onlyIncludeFiles, globs, definition, json, hasBeenBuffered;
1411 var _a;
1412 return __generator(this, function (_b) {
1413 onlyIncludeFiles = undefined;
1414 if (REGEX_TSCONFIG_NAME.test(path.basename(filePattern))) {
1415 if (args.include && args.include.length > 0) {
1416 globs = args.include.map(function (f) { return glob.sync(f); });
1417 onlyIncludeFiles = (_a = []).concat.apply(_a, globs).map(normalizeFileName);
1418 }
1419 program = programFromConfig(filePattern, onlyIncludeFiles);
1420 }
1421 else {
1422 onlyIncludeFiles = glob.sync(filePattern);
1423 program = getProgramFromFiles(onlyIncludeFiles, {
1424 strictNullChecks: args.strictNullChecks,
1425 esModuleInterop: args.esModuleInterop,
1426 skipLibCheck: args.skipLibCheck,
1427 emitDecoratorMetadata: args.experimentalDecorators,
1428 experimentalDecorators: args.experimentalDecorators,
1429 });
1430 onlyIncludeFiles = onlyIncludeFiles.map(normalizeFileName);
1431 }
1432 definition = generateSchema(program, fullTypeName, args, onlyIncludeFiles);
1433 if (definition === null) {
1434 throw new Error("No output definition. Probably caused by errors prior to this?");
1435 }
1436 json = (0, safe_stable_stringify_1.stringify)(definition, null, 4) + "\n\n";
1437 if (args.out) {
1438 return [2, new Promise(function (resolve, reject) {
1439 var fs = require("fs");
1440 fs.mkdir(path.dirname(args.out), { recursive: true }, function (mkErr) {
1441 if (mkErr) {
1442 return reject(new Error("Unable to create parent directory for output file: " + mkErr.message));
1443 }
1444 fs.writeFile(args.out, json, function (wrErr) {
1445 if (wrErr) {
1446 return reject(new Error("Unable to write output file: " + wrErr.message));
1447 }
1448 resolve();
1449 });
1450 });
1451 })];
1452 }
1453 else {
1454 hasBeenBuffered = process.stdout.write(json);
1455 if (hasBeenBuffered) {
1456 return [2, new Promise(function (resolve) { return process.stdout.on("drain", function () { return resolve(); }); })];
1457 }
1458 }
1459 return [2];
1460 });
1461 });
1462}
1463exports.exec = exec;
1464//# sourceMappingURL=typescript-json-schema.js.map
\No newline at end of file