@langchain/langgraph-api 1.1.2 → 1.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/package.json +9 -8
  2. package/CHANGELOG.md +0 -297
  3. package/dist/api/assistants.d.mts +0 -3
  4. package/dist/api/assistants.mjs +0 -193
  5. package/dist/api/meta.d.mts +0 -3
  6. package/dist/api/meta.mjs +0 -65
  7. package/dist/api/runs.d.mts +0 -3
  8. package/dist/api/runs.mjs +0 -324
  9. package/dist/api/store.d.mts +0 -3
  10. package/dist/api/store.mjs +0 -111
  11. package/dist/api/threads.d.mts +0 -3
  12. package/dist/api/threads.mjs +0 -143
  13. package/dist/auth/custom.d.mts +0 -9
  14. package/dist/auth/custom.mjs +0 -32
  15. package/dist/auth/index.d.mts +0 -43
  16. package/dist/auth/index.mjs +0 -163
  17. package/dist/cli/entrypoint.d.mts +0 -1
  18. package/dist/cli/entrypoint.mjs +0 -41
  19. package/dist/cli/spawn.d.mts +0 -42
  20. package/dist/cli/spawn.mjs +0 -47
  21. package/dist/cli/utils/ipc/client.d.mts +0 -5
  22. package/dist/cli/utils/ipc/client.mjs +0 -47
  23. package/dist/cli/utils/ipc/utils/get-pipe-path.d.mts +0 -1
  24. package/dist/cli/utils/ipc/utils/get-pipe-path.mjs +0 -29
  25. package/dist/cli/utils/ipc/utils/temporary-directory.d.mts +0 -5
  26. package/dist/cli/utils/ipc/utils/temporary-directory.mjs +0 -40
  27. package/dist/command.d.mts +0 -11
  28. package/dist/command.mjs +0 -15
  29. package/dist/experimental/embed.d.mts +0 -42
  30. package/dist/experimental/embed.mjs +0 -299
  31. package/dist/graph/api.d.mts +0 -1
  32. package/dist/graph/api.mjs +0 -2
  33. package/dist/graph/load.d.mts +0 -19
  34. package/dist/graph/load.hooks.d.mts +0 -2
  35. package/dist/graph/load.hooks.mjs +0 -52
  36. package/dist/graph/load.mjs +0 -96
  37. package/dist/graph/load.utils.d.mts +0 -22
  38. package/dist/graph/load.utils.mjs +0 -49
  39. package/dist/graph/parser/index.d.mts +0 -23
  40. package/dist/graph/parser/index.mjs +0 -58
  41. package/dist/graph/parser/parser.d.mts +0 -77
  42. package/dist/graph/parser/parser.mjs +0 -429
  43. package/dist/graph/parser/parser.worker.d.mts +0 -1
  44. package/dist/graph/parser/parser.worker.mjs +0 -7
  45. package/dist/graph/parser/schema/types.d.mts +0 -154
  46. package/dist/graph/parser/schema/types.mjs +0 -1496
  47. package/dist/graph/parser/schema/types.template.d.mts +0 -1
  48. package/dist/graph/parser/schema/types.template.mts +0 -92
  49. package/dist/http/custom.d.mts +0 -6
  50. package/dist/http/custom.mjs +0 -10
  51. package/dist/http/middleware.d.mts +0 -11
  52. package/dist/http/middleware.mjs +0 -57
  53. package/dist/logging.d.mts +0 -10
  54. package/dist/logging.mjs +0 -115
  55. package/dist/loopback.d.mts +0 -4
  56. package/dist/loopback.mjs +0 -10
  57. package/dist/preload.d.mts +0 -1
  58. package/dist/preload.mjs +0 -29
  59. package/dist/queue.d.mts +0 -2
  60. package/dist/queue.mjs +0 -119
  61. package/dist/schemas.d.mts +0 -1552
  62. package/dist/schemas.mjs +0 -492
  63. package/dist/semver/index.d.mts +0 -15
  64. package/dist/semver/index.mjs +0 -46
  65. package/dist/server.d.mts +0 -175
  66. package/dist/server.mjs +0 -181
  67. package/dist/state.d.mts +0 -3
  68. package/dist/state.mjs +0 -30
  69. package/dist/storage/checkpoint.d.mts +0 -19
  70. package/dist/storage/checkpoint.mjs +0 -127
  71. package/dist/storage/context.d.mts +0 -3
  72. package/dist/storage/context.mjs +0 -11
  73. package/dist/storage/importMap.d.mts +0 -55
  74. package/dist/storage/importMap.mjs +0 -55
  75. package/dist/storage/ops.d.mts +0 -169
  76. package/dist/storage/ops.mjs +0 -1262
  77. package/dist/storage/persist.d.mts +0 -18
  78. package/dist/storage/persist.mjs +0 -81
  79. package/dist/storage/store.d.mts +0 -17
  80. package/dist/storage/store.mjs +0 -41
  81. package/dist/storage/types.d.mts +0 -301
  82. package/dist/storage/types.mjs +0 -1
  83. package/dist/stream.d.mts +0 -43
  84. package/dist/stream.mjs +0 -235
  85. package/dist/ui/load.d.mts +0 -8
  86. package/dist/ui/load.mjs +0 -53
  87. package/dist/utils/abort.d.mts +0 -1
  88. package/dist/utils/abort.mjs +0 -8
  89. package/dist/utils/hono.d.mts +0 -5
  90. package/dist/utils/hono.mjs +0 -24
  91. package/dist/utils/importMap.d.mts +0 -55
  92. package/dist/utils/importMap.mjs +0 -55
  93. package/dist/utils/runnableConfig.d.mts +0 -3
  94. package/dist/utils/runnableConfig.mjs +0 -45
  95. package/dist/utils/serde.d.mts +0 -5
  96. package/dist/utils/serde.mjs +0 -20
  97. package/dist/vitest.config.d.ts +0 -2
  98. package/dist/vitest.config.js +0 -12
  99. package/dist/webhook.d.mts +0 -11
  100. package/dist/webhook.mjs +0 -30
@@ -1,1496 +0,0 @@
1
- // Copied from typescript-json-schema#70de093f2e148afab527aaf0d4dc38ce19de7715
2
- //
3
- // Copyright (c) 2016, typescript-json-schema contributors
4
- // All rights reserved.
5
- //
6
- // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
7
- //
8
- // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
9
- //
10
- // 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
11
- //
12
- // 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
13
- //
14
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15
- import * as ts from "typescript";
16
- import * as vm from "node:vm";
17
- import * as path from "node:path";
18
- import { createHash } from "node:crypto";
19
- const REGEX_FILE_NAME_OR_SPACE = /(\bimport\(".*?"\)|".*?")\.| /g;
20
- const REGEX_TJS_JSDOC = /^-([\w]+)\s+(\S|\S[\s\S]*\S)\s*$/g;
21
- const REGEX_GROUP_JSDOC = /^[.]?([\w]+)\s+(\S|\S[\s\S]*\S)\s*$/g;
22
- /**
23
- * Resolve required file, his path and a property name,
24
- * pattern: require([file_path]).[property_name]
25
- *
26
- * the part ".[property_name]" is optional in the regex
27
- *
28
- * will match:
29
- *
30
- * require('./path.ts')
31
- * require('./path.ts').objectName
32
- * require("./path.ts")
33
- * require("./path.ts").objectName
34
- * require('@module-name')
35
- *
36
- * match[2] = file_path (a path to the file with quotes)
37
- * match[3] = (optional) property_name (a property name, exported in the file)
38
- *
39
- * for more details, see tests/require.test.ts
40
- */
41
- const REGEX_REQUIRE = /^(\s+)?require\((\'@?[a-zA-Z0-9.\/_-]+\'|\"@?[a-zA-Z0-9.\/_-]+\")\)(\.([a-zA-Z0-9_$]+))?(\s+|$)/;
42
- const NUMERIC_INDEX_PATTERN = "^[0-9]+$";
43
- function pathEqual(actual, expected) {
44
- return (actual === expected || normalizePath(actual) === normalizePath(expected));
45
- }
46
- function normalizePath(path) {
47
- const replace = [
48
- [/\\/g, "/"],
49
- [/(\w):/, "/$1"],
50
- [/(\w+)\/\.\.\/?/g, ""],
51
- [/^\.\//, ""],
52
- [/\/\.\//, "/"],
53
- [/\/\.$/, ""],
54
- [/\/$/, ""],
55
- ];
56
- replace.forEach((array) => {
57
- while (array[0].test(path)) {
58
- path = path.replace(array[0], array[1]);
59
- }
60
- });
61
- return path;
62
- }
63
- function getDefaultArgs() {
64
- return {
65
- ref: true,
66
- aliasRef: false,
67
- topRef: false,
68
- titles: false,
69
- defaultProps: false,
70
- noExtraProps: false,
71
- propOrder: false,
72
- typeOfKeyword: false,
73
- required: false,
74
- strictNullChecks: false,
75
- esModuleInterop: false,
76
- experimentalDecorators: true,
77
- out: "",
78
- validationKeywords: [],
79
- include: [],
80
- excludePrivate: false,
81
- uniqueNames: false,
82
- rejectDateType: false,
83
- id: "",
84
- defaultNumberType: "number",
85
- constAsEnum: false,
86
- };
87
- }
88
- function extend(target, ..._) {
89
- if (target == null) {
90
- // TypeError if undefined or null
91
- throw new TypeError("Cannot convert undefined or null to object");
92
- }
93
- const to = Object(target);
94
- for (var index = 1; index < arguments.length; index++) {
95
- const nextSource = arguments[index];
96
- if (nextSource != null) {
97
- // Skip over if undefined or null
98
- for (const nextKey in nextSource) {
99
- // Avoid bugs when hasOwnProperty is shadowed
100
- if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
101
- to[nextKey] = nextSource[nextKey];
102
- }
103
- }
104
- }
105
- }
106
- return to;
107
- }
108
- function unique(arr) {
109
- const temp = {};
110
- for (const e of arr) {
111
- temp[e] = true;
112
- }
113
- const r = [];
114
- for (const k in temp) {
115
- // Avoid bugs when hasOwnProperty is shadowed
116
- if (Object.prototype.hasOwnProperty.call(temp, k)) {
117
- r.push(k);
118
- }
119
- }
120
- return r;
121
- }
122
- /**
123
- * Resolve required file
124
- */
125
- function resolveRequiredFile(symbol, key, fileName, objectName) {
126
- const sourceFile = getSourceFile(symbol);
127
- const requiredFilePath = /^[.\/]+/.test(fileName)
128
- ? fileName === "."
129
- ? path.resolve(sourceFile.fileName)
130
- : path.resolve(path.dirname(sourceFile.fileName), fileName)
131
- : fileName;
132
- const requiredFile = require(requiredFilePath);
133
- if (!requiredFile) {
134
- throw Error("Required: File couldn't be loaded");
135
- }
136
- const requiredObject = objectName
137
- ? requiredFile[objectName]
138
- : requiredFile.default;
139
- if (requiredObject === undefined) {
140
- throw Error("Required: Variable is undefined");
141
- }
142
- if (typeof requiredObject === "function") {
143
- throw Error("Required: Can't use function as a variable");
144
- }
145
- if (key === "examples" && !Array.isArray(requiredObject)) {
146
- throw Error("Required: Variable isn't an array");
147
- }
148
- return requiredObject;
149
- }
150
- function regexRequire(value) {
151
- return REGEX_REQUIRE.exec(value);
152
- }
153
- /**
154
- * Try to parse a value and returns the string if it fails.
155
- */
156
- function parseValue(symbol, key, value) {
157
- const match = regexRequire(value);
158
- if (match) {
159
- const fileName = match[2].substring(1, match[2].length - 2).trim();
160
- const objectName = match[4];
161
- return resolveRequiredFile(symbol, key, fileName, objectName);
162
- }
163
- try {
164
- return JSON.parse(value);
165
- }
166
- catch (error) {
167
- return value;
168
- }
169
- }
170
- function extractLiteralValue(typ) {
171
- let str = typ.value;
172
- if (str === undefined) {
173
- str = typ.text;
174
- }
175
- if (typ.flags & ts.TypeFlags.StringLiteral) {
176
- return str;
177
- }
178
- else if (typ.flags & ts.TypeFlags.BooleanLiteral) {
179
- return typ.intrinsicName === "true";
180
- }
181
- else if (typ.flags & ts.TypeFlags.EnumLiteral) {
182
- // or .text for old TS
183
- const num = parseFloat(str);
184
- return isNaN(num) ? str : num;
185
- }
186
- else if (typ.flags & ts.TypeFlags.NumberLiteral) {
187
- return parseFloat(str);
188
- }
189
- return undefined;
190
- }
191
- /**
192
- * Checks whether a type is a tuple type.
193
- */
194
- function resolveTupleType(propertyType) {
195
- if (!propertyType.getSymbol() &&
196
- propertyType.getFlags() & ts.TypeFlags.Object &&
197
- propertyType.objectFlags & ts.ObjectFlags.Reference) {
198
- return propertyType.target;
199
- }
200
- if (!(propertyType.getFlags() & ts.TypeFlags.Object &&
201
- propertyType.objectFlags & ts.ObjectFlags.Tuple)) {
202
- return null;
203
- }
204
- return propertyType;
205
- }
206
- const simpleTypesAllowedProperties = {
207
- type: true,
208
- description: true,
209
- };
210
- function addSimpleType(def, type) {
211
- for (const k in def) {
212
- if (!simpleTypesAllowedProperties[k]) {
213
- return false;
214
- }
215
- }
216
- if (!def.type) {
217
- def.type = type;
218
- }
219
- else if (typeof def.type !== "string") {
220
- if (!def.type.every((val) => {
221
- return typeof val === "string";
222
- })) {
223
- return false;
224
- }
225
- if (def.type.indexOf("null") === -1) {
226
- def.type.push("null");
227
- }
228
- }
229
- else {
230
- if (typeof def.type !== "string") {
231
- return false;
232
- }
233
- if (def.type !== "null") {
234
- def.type = [def.type, "null"];
235
- }
236
- }
237
- return true;
238
- }
239
- function makeNullable(def) {
240
- if (!addSimpleType(def, "null")) {
241
- const union = def.oneOf || def.anyOf;
242
- if (union) {
243
- union.push({ type: "null" });
244
- }
245
- else {
246
- const subdef = {};
247
- for (var k in def) {
248
- if (def.hasOwnProperty(k)) {
249
- subdef[k] = def[k];
250
- delete def[k];
251
- }
252
- }
253
- def.anyOf = [subdef, { type: "null" }];
254
- }
255
- }
256
- return def;
257
- }
258
- /**
259
- * Given a Symbol, returns a canonical Definition. That can be either:
260
- * 1) The Symbol's valueDeclaration parameter if defined, or
261
- * 2) The sole entry in the Symbol's declarations array, provided that array has a length of 1.
262
- *
263
- * valueDeclaration is listed as a required parameter in the definition of a Symbol, but I've
264
- * experienced crashes when it's undefined at runtime, which is the reason for this function's
265
- * existence. Not sure if that's a compiler API bug or what.
266
- */
267
- function getCanonicalDeclaration(sym) {
268
- if (sym.valueDeclaration !== undefined) {
269
- return sym.valueDeclaration;
270
- }
271
- else if (sym.declarations?.length === 1) {
272
- return sym.declarations[0];
273
- }
274
- const declarationCount = sym.declarations?.length ?? 0;
275
- throw new Error(`Symbol "${sym.name}" has no valueDeclaration and ${declarationCount} declarations.`);
276
- }
277
- /**
278
- * Given a Symbol, finds the place it was declared and chases parent pointers until we find a
279
- * node where SyntaxKind === SourceFile.
280
- */
281
- function getSourceFile(sym) {
282
- let currentDecl = getCanonicalDeclaration(sym);
283
- while (currentDecl.kind !== ts.SyntaxKind.SourceFile) {
284
- if (currentDecl.parent === undefined) {
285
- throw new Error(`Unable to locate source file for declaration "${sym.name}".`);
286
- }
287
- currentDecl = currentDecl.parent;
288
- }
289
- return currentDecl;
290
- }
291
- /**
292
- * JSDoc keywords that should be used to annotate the JSON schema.
293
- *
294
- * Many of these validation keywords are defined here: http://json-schema.org/latest/json-schema-validation.html
295
- */
296
- // prettier-ignore
297
- const validationKeywords = {
298
- multipleOf: true, // 6.1.
299
- maximum: true, // 6.2.
300
- exclusiveMaximum: true, // 6.3.
301
- minimum: true, // 6.4.
302
- exclusiveMinimum: true, // 6.5.
303
- maxLength: true, // 6.6.
304
- minLength: true, // 6.7.
305
- pattern: true, // 6.8.
306
- items: true, // 6.9.
307
- // additionalItems: true, // 6.10.
308
- maxItems: true, // 6.11.
309
- minItems: true, // 6.12.
310
- uniqueItems: true, // 6.13.
311
- contains: true, // 6.14.
312
- maxProperties: true, // 6.15.
313
- minProperties: true, // 6.16.
314
- // required: true, // 6.17. This is not required. It is auto-generated.
315
- // properties: true, // 6.18. This is not required. It is auto-generated.
316
- // patternProperties: true, // 6.19.
317
- additionalProperties: true, // 6.20.
318
- // dependencies: true, // 6.21.
319
- // propertyNames: true, // 6.22.
320
- enum: true, // 6.23.
321
- // const: true, // 6.24.
322
- type: true, // 6.25.
323
- // allOf: true, // 6.26.
324
- // anyOf: true, // 6.27.
325
- // oneOf: true, // 6.28.
326
- // not: true, // 6.29.
327
- examples: true, // Draft 6 (draft-handrews-json-schema-validation-01)
328
- ignore: true,
329
- description: true,
330
- format: true,
331
- default: true,
332
- $ref: true,
333
- id: true,
334
- $id: true,
335
- $comment: true,
336
- title: true
337
- };
338
- /**
339
- * Subset of descriptive, non-type keywords that are permitted alongside a $ref.
340
- * Prior to JSON Schema draft 2019-09, $ref is a special keyword that doesn't
341
- * permit keywords alongside it, and so AJV may raise warnings if it encounters
342
- * any type-related keywords; see https://github.com/ajv-validator/ajv/issues/1121
343
- */
344
- const annotationKeywords = {
345
- description: true,
346
- default: true,
347
- examples: true,
348
- title: true,
349
- // A JSDoc $ref annotation can appear as a $ref.
350
- $ref: true,
351
- };
352
- const subDefinitions = {
353
- items: true,
354
- additionalProperties: true,
355
- contains: true,
356
- };
357
- class JsonSchemaGenerator {
358
- args;
359
- tc;
360
- /**
361
- * Holds all symbols within a custom SymbolRef object, containing useful
362
- * information.
363
- */
364
- symbols;
365
- /**
366
- * All types for declarations of classes, interfaces, enums, and type aliases
367
- * defined in all TS files.
368
- */
369
- allSymbols;
370
- /**
371
- * All symbols for declarations of classes, interfaces, enums, and type aliases
372
- * defined in non-default-lib TS files.
373
- */
374
- userSymbols;
375
- /**
376
- * Maps from the names of base types to the names of the types that inherit from
377
- * them.
378
- */
379
- inheritingTypes;
380
- /**
381
- * This map holds references to all reffed definitions, including schema
382
- * overrides and generated definitions.
383
- */
384
- reffedDefinitions = {};
385
- /**
386
- * This map only holds explicit schema overrides. This helps differentiate between
387
- * user defined schema overrides and generated definitions.
388
- */
389
- schemaOverrides = new Map();
390
- /**
391
- * This is a set of all the user-defined validation keywords.
392
- */
393
- userValidationKeywords;
394
- /**
395
- * If true, this makes constants be defined as enums with a single value. This is useful
396
- * for cases where constant values are not supported, such as OpenAPI.
397
- */
398
- constAsEnum;
399
- /**
400
- * Types are assigned names which are looked up by their IDs. This is the
401
- * map from type IDs to type names.
402
- */
403
- typeNamesById = {};
404
- /**
405
- * Whenever a type is assigned its name, its entry in this dictionary is set,
406
- * so that we don't give the same name to two separate types.
407
- */
408
- typeIdsByName = {};
409
- constructor(symbols, allSymbols, userSymbols, inheritingTypes, tc, args = getDefaultArgs()) {
410
- this.args = args;
411
- this.symbols = symbols;
412
- this.allSymbols = allSymbols;
413
- this.userSymbols = userSymbols;
414
- this.inheritingTypes = inheritingTypes;
415
- this.tc = tc;
416
- this.userValidationKeywords = args.validationKeywords.reduce((acc, word) => ({ ...acc, [word]: true }), {});
417
- this.constAsEnum = args.constAsEnum;
418
- }
419
- get ReffedDefinitions() {
420
- return this.reffedDefinitions;
421
- }
422
- isFromDefaultLib(symbol) {
423
- const declarations = symbol.getDeclarations();
424
- if (declarations && declarations.length > 0 && declarations[0].parent) {
425
- return declarations[0].parent.getSourceFile().hasNoDefaultLib;
426
- }
427
- return false;
428
- }
429
- resetSchemaSpecificProperties(includeAllOverrides = false) {
430
- this.reffedDefinitions = {};
431
- this.typeIdsByName = {};
432
- this.typeNamesById = {};
433
- // restore schema overrides
434
- if (includeAllOverrides) {
435
- this.schemaOverrides.forEach((value, key) => {
436
- this.reffedDefinitions[key] = value;
437
- });
438
- }
439
- }
440
- /**
441
- * Parse the comments of a symbol into the definition and other annotations.
442
- */
443
- parseCommentsIntoDefinition(symbol, definition, otherAnnotations) {
444
- if (!symbol) {
445
- return;
446
- }
447
- if (!this.isFromDefaultLib(symbol)) {
448
- // the comments for a symbol
449
- const comments = symbol.getDocumentationComment(this.tc);
450
- if (comments.length) {
451
- definition.description = comments
452
- .map((comment) => {
453
- const newlineNormalizedComment = comment.text.replace(/\r\n/g, "\n");
454
- // If a comment contains a "{@link XYZ}" inline tag that could not be
455
- // resolved by the TS checker, then this comment will contain a trailing
456
- // whitespace that we need to remove.
457
- if (comment.kind === "linkText") {
458
- return newlineNormalizedComment.trim();
459
- }
460
- return newlineNormalizedComment;
461
- })
462
- .join("")
463
- .trim();
464
- }
465
- }
466
- // jsdocs are separate from comments
467
- const jsdocs = symbol.getJsDocTags();
468
- jsdocs.forEach((doc) => {
469
- // if we have @TJS-... annotations, we have to parse them
470
- let name = doc.name;
471
- const originalText = doc.text ? doc.text.map((t) => t.text).join("") : "";
472
- let text = originalText;
473
- // In TypeScript versions prior to 3.7, it stops parsing the annotation
474
- // at the first non-alphanumeric character and puts the rest of the line as the
475
- // "text" of the annotation, so we have a little hack to check for the name
476
- // "TJS" and then we sort of re-parse the annotation to support prior versions
477
- // of TypeScript.
478
- if (name.startsWith("TJS-")) {
479
- name = name.slice(4);
480
- if (!text) {
481
- text = "true";
482
- }
483
- }
484
- else if (name === "TJS" && text.startsWith("-")) {
485
- let match = new RegExp(REGEX_TJS_JSDOC).exec(originalText);
486
- if (match) {
487
- name = match[1];
488
- text = match[2];
489
- }
490
- else {
491
- // Treat empty text as boolean true
492
- name = text.replace(/^[\s\-]+/, "");
493
- text = "true";
494
- }
495
- }
496
- // In TypeScript ~3.5, the annotation name splits at the dot character so we have
497
- // to process the "." and beyond from the value
498
- if (subDefinitions[name]) {
499
- const match = new RegExp(REGEX_GROUP_JSDOC).exec(text);
500
- if (match) {
501
- const k = match[1];
502
- const v = match[2];
503
- definition[name] = {
504
- ...definition[name],
505
- [k]: v ? parseValue(symbol, k, v) : true,
506
- };
507
- return;
508
- }
509
- }
510
- // In TypeScript 3.7+, the "." is kept as part of the annotation name
511
- if (name.includes(".")) {
512
- const parts = name.split(".");
513
- const key = parts[0];
514
- if (parts.length === 2 && subDefinitions[key]) {
515
- definition[key] = {
516
- ...definition[key],
517
- [parts[1]]: text ? parseValue(symbol, name, text) : true,
518
- };
519
- }
520
- }
521
- if (validationKeywords[name] ||
522
- this.userValidationKeywords[name]) {
523
- definition[name] =
524
- text === undefined ? "" : parseValue(symbol, name, text);
525
- }
526
- else {
527
- // special annotations
528
- otherAnnotations[doc.name] = true;
529
- }
530
- });
531
- }
532
- getDefinitionForRootType(propertyType, reffedType, definition, defaultNumberType = this.args.defaultNumberType, ignoreUndefined = false) {
533
- const tupleType = resolveTupleType(propertyType);
534
- if (tupleType) {
535
- // tuple
536
- const elemTypes = propertyType
537
- .typeArguments;
538
- const fixedTypes = elemTypes.map((elType) => this.getTypeDefinition(elType));
539
- definition.type = "array";
540
- if (fixedTypes.length > 0) {
541
- definition.items = fixedTypes;
542
- }
543
- const targetTupleType = propertyType.target;
544
- definition.minItems = targetTupleType.minLength;
545
- if (targetTupleType.hasRestElement) {
546
- definition.additionalItems = fixedTypes[fixedTypes.length - 1];
547
- fixedTypes.splice(fixedTypes.length - 1, 1);
548
- }
549
- else {
550
- definition.maxItems = targetTupleType.fixedLength;
551
- }
552
- }
553
- else {
554
- const propertyTypeString = this.tc.typeToString(propertyType, undefined, ts.TypeFormatFlags.UseFullyQualifiedType);
555
- const flags = propertyType.flags;
556
- const arrayType = this.tc.getIndexTypeOfType(propertyType, ts.IndexKind.Number);
557
- if (flags & ts.TypeFlags.String) {
558
- definition.type = "string";
559
- }
560
- else if (flags & ts.TypeFlags.Number) {
561
- const isInteger = definition.type === "integer" ||
562
- reffedType?.getName() === "integer" ||
563
- defaultNumberType === "integer";
564
- definition.type = isInteger ? "integer" : "number";
565
- }
566
- else if (flags & ts.TypeFlags.Boolean) {
567
- definition.type = "boolean";
568
- }
569
- else if (flags & ts.TypeFlags.ESSymbol) {
570
- definition.type = "object";
571
- }
572
- else if (flags & ts.TypeFlags.Null) {
573
- definition.type = "null";
574
- }
575
- else if (flags & ts.TypeFlags.Undefined ||
576
- propertyTypeString === "void") {
577
- if (!ignoreUndefined) {
578
- throw new Error("Not supported: root type undefined");
579
- }
580
- // will be deleted
581
- definition.type = "undefined";
582
- }
583
- else if (flags & ts.TypeFlags.Any || flags & ts.TypeFlags.Unknown) {
584
- // no type restriction, so that anything will match
585
- }
586
- else if (propertyTypeString === "Date" && !this.args.rejectDateType) {
587
- definition.type = "string";
588
- definition.format = definition.format || "date-time";
589
- }
590
- else if (propertyTypeString === "object") {
591
- definition.type = "object";
592
- definition.properties = {};
593
- definition.additionalProperties = true;
594
- }
595
- else if (propertyTypeString === "bigint") {
596
- definition.type = "number";
597
- definition.properties = {};
598
- definition.additionalProperties = false;
599
- }
600
- else {
601
- const value = extractLiteralValue(propertyType);
602
- if (value !== undefined) {
603
- // typeof value can be: "string", "boolean", "number", or "object" if value is null
604
- const typeofValue = typeof value;
605
- switch (typeofValue) {
606
- case "string":
607
- case "boolean":
608
- definition.type = typeofValue;
609
- break;
610
- case "number":
611
- definition.type = this.args.defaultNumberType;
612
- break;
613
- case "object":
614
- definition.type = "null";
615
- break;
616
- default:
617
- throw new Error(`Not supported: ${value} as a enum value`);
618
- }
619
- if (this.constAsEnum) {
620
- definition.enum = [value];
621
- }
622
- else {
623
- definition.const = value;
624
- }
625
- }
626
- else if (arrayType !== undefined) {
627
- if (propertyType.flags & ts.TypeFlags.Object &&
628
- propertyType.objectFlags &
629
- (ts.ObjectFlags.Anonymous |
630
- ts.ObjectFlags.Interface |
631
- ts.ObjectFlags.Mapped)) {
632
- definition.type = "object";
633
- definition.additionalProperties = false;
634
- definition.patternProperties = {
635
- [NUMERIC_INDEX_PATTERN]: this.getTypeDefinition(arrayType),
636
- };
637
- if (!!Array.from(propertyType.members)?.find((member) => member[0] !== "__index")) {
638
- this.getClassDefinition(propertyType, definition);
639
- }
640
- }
641
- else if (propertyType.flags & ts.TypeFlags.TemplateLiteral) {
642
- definition.type = "string";
643
- // @ts-ignore
644
- const { texts, types } = propertyType;
645
- const pattern = [];
646
- for (let i = 0; i < texts.length; i++) {
647
- const text = texts[i].replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
648
- const type = types[i];
649
- if (i === 0) {
650
- pattern.push(`^`);
651
- }
652
- if (type) {
653
- if (type.flags & ts.TypeFlags.String) {
654
- pattern.push(`${text}.*`);
655
- }
656
- if (type.flags & ts.TypeFlags.Number ||
657
- type.flags & ts.TypeFlags.BigInt) {
658
- pattern.push(`${text}[0-9]*`);
659
- }
660
- if (type.flags & ts.TypeFlags.Undefined) {
661
- pattern.push(`${text}undefined`);
662
- }
663
- if (type.flags & ts.TypeFlags.Null) {
664
- pattern.push(`${text}null`);
665
- }
666
- }
667
- if (i === texts.length - 1) {
668
- pattern.push(`${text}$`);
669
- }
670
- }
671
- definition.pattern = pattern.join("");
672
- }
673
- else {
674
- definition.type = "array";
675
- if (!definition.items) {
676
- definition.items = this.getTypeDefinition(arrayType);
677
- }
678
- }
679
- }
680
- else {
681
- // Report that type could not be processed
682
- const error = new TypeError("Unsupported type: " + propertyTypeString);
683
- error.type = propertyType;
684
- throw error;
685
- // definition = this.getTypeDefinition(propertyType, tc);
686
- }
687
- }
688
- }
689
- return definition;
690
- }
691
- getReferencedTypeSymbol(prop) {
692
- const decl = prop.getDeclarations();
693
- if (decl?.length) {
694
- const type = decl[0].type;
695
- if (type && type.kind & ts.SyntaxKind.TypeReference && type.typeName) {
696
- const symbol = this.tc.getSymbolAtLocation(type.typeName);
697
- if (symbol && symbol.flags & ts.SymbolFlags.Alias) {
698
- return this.tc.getAliasedSymbol(symbol);
699
- }
700
- return symbol;
701
- }
702
- }
703
- return undefined;
704
- }
705
- getDefinitionForProperty(prop, node) {
706
- if (prop.flags & ts.SymbolFlags.Method) {
707
- return null;
708
- }
709
- const propertyName = prop.getName();
710
- const propertyType = this.tc.getTypeOfSymbolAtLocation(prop, node);
711
- const reffedType = this.getReferencedTypeSymbol(prop);
712
- const definition = this.getTypeDefinition(propertyType, undefined, undefined, prop, reffedType);
713
- if (this.args.titles) {
714
- definition.title = propertyName;
715
- }
716
- if (definition.hasOwnProperty("ignore")) {
717
- return null;
718
- }
719
- // try to get default value
720
- const valDecl = prop.valueDeclaration;
721
- if (valDecl?.initializer) {
722
- let initial = valDecl.initializer;
723
- while (ts.isTypeAssertionExpression(initial)) {
724
- initial = initial.expression;
725
- }
726
- if (initial.expression) {
727
- // node
728
- console.warn("initializer is expression for property " + propertyName);
729
- }
730
- else if (initial.kind &&
731
- initial.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral) {
732
- definition.default = initial.getText();
733
- }
734
- else {
735
- try {
736
- const sandbox = { sandboxvar: null };
737
- vm.runInNewContext("sandboxvar=" + initial.getText(), sandbox);
738
- const val = sandbox.sandboxvar;
739
- if (val === null ||
740
- typeof val === "string" ||
741
- typeof val === "number" ||
742
- typeof val === "boolean" ||
743
- Object.prototype.toString.call(val) === "[object Array]") {
744
- definition.default = val;
745
- }
746
- else if (val) {
747
- console.warn("unknown initializer for property " + propertyName + ": " + val);
748
- }
749
- }
750
- catch (e) {
751
- console.warn("exception evaluating initializer for property " + propertyName);
752
- }
753
- }
754
- }
755
- return definition;
756
- }
757
- getEnumDefinition(clazzType, definition) {
758
- const node = clazzType.getSymbol().getDeclarations()[0];
759
- const fullName = this.tc.typeToString(clazzType, undefined, ts.TypeFormatFlags.UseFullyQualifiedType);
760
- const members = node.kind === ts.SyntaxKind.EnumDeclaration
761
- ? node.members
762
- : ts.factory.createNodeArray([node]);
763
- var enumValues = [];
764
- const enumTypes = [];
765
- const addType = (type) => {
766
- if (enumTypes.indexOf(type) === -1) {
767
- enumTypes.push(type);
768
- }
769
- };
770
- members.forEach((member) => {
771
- const caseLabel = member.name.text;
772
- const constantValue = this.tc.getConstantValue(member);
773
- if (constantValue !== undefined) {
774
- enumValues.push(constantValue);
775
- addType(typeof constantValue); // can be only string or number;
776
- }
777
- else {
778
- // try to extract the enums value; it will probably by a cast expression
779
- const initial = member.initializer;
780
- if (initial) {
781
- if (initial.expression) {
782
- // node
783
- const exp = initial.expression;
784
- const text = exp.text;
785
- // if it is an expression with a text literal, chances are it is the enum convention:
786
- // CASELABEL = 'literal' as any
787
- if (text) {
788
- enumValues.push(text);
789
- addType("string");
790
- }
791
- else if (exp.kind === ts.SyntaxKind.TrueKeyword ||
792
- exp.kind === ts.SyntaxKind.FalseKeyword) {
793
- enumValues.push(exp.kind === ts.SyntaxKind.TrueKeyword);
794
- addType("boolean");
795
- }
796
- else {
797
- console.warn("initializer is expression for enum: " +
798
- fullName +
799
- "." +
800
- caseLabel);
801
- }
802
- }
803
- else if (initial.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral) {
804
- enumValues.push(initial.getText());
805
- addType("string");
806
- }
807
- else if (initial.kind === ts.SyntaxKind.NullKeyword) {
808
- enumValues.push(null);
809
- addType("null");
810
- }
811
- }
812
- }
813
- });
814
- if (enumTypes.length) {
815
- definition.type = enumTypes.length === 1 ? enumTypes[0] : enumTypes;
816
- }
817
- if (enumValues.length > 0) {
818
- if (enumValues.length > 1) {
819
- definition.enum = enumValues;
820
- }
821
- else {
822
- definition.const = enumValues[0];
823
- }
824
- }
825
- return definition;
826
- }
827
- getUnionDefinition(unionType, unionModifier, definition) {
828
- const enumValues = [];
829
- const simpleTypes = [];
830
- const schemas = [];
831
- const pushSimpleType = (type) => {
832
- if (simpleTypes.indexOf(type) === -1) {
833
- simpleTypes.push(type);
834
- }
835
- };
836
- const pushEnumValue = (val) => {
837
- if (enumValues.indexOf(val) === -1) {
838
- enumValues.push(val);
839
- }
840
- };
841
- for (const valueType of unionType.types) {
842
- const value = extractLiteralValue(valueType);
843
- if (value !== undefined) {
844
- pushEnumValue(value);
845
- }
846
- else {
847
- const symbol = valueType.aliasSymbol;
848
- const def = this.getTypeDefinition(valueType, undefined, undefined, symbol, symbol, undefined, undefined, true);
849
- if (def.type === "undefined") {
850
- continue;
851
- }
852
- const keys = Object.keys(def);
853
- if (keys.length === 1 && keys[0] === "type") {
854
- if (typeof def.type !== "string") {
855
- console.error("Expected only a simple type.");
856
- }
857
- else {
858
- pushSimpleType(def.type);
859
- }
860
- }
861
- else {
862
- schemas.push(def);
863
- }
864
- }
865
- }
866
- if (enumValues.length > 0) {
867
- // If the values are true and false, just add "boolean" as simple type
868
- const isOnlyBooleans = enumValues.length === 2 &&
869
- typeof enumValues[0] === "boolean" &&
870
- typeof enumValues[1] === "boolean" &&
871
- enumValues[0] !== enumValues[1];
872
- if (isOnlyBooleans) {
873
- pushSimpleType("boolean");
874
- }
875
- else {
876
- const enumSchema = enumValues.length > 1
877
- ? { enum: enumValues.sort() }
878
- : { const: enumValues[0] };
879
- // If all values are of the same primitive type, add a "type" field to the schema
880
- if (enumValues.every((x) => {
881
- return typeof x === "string";
882
- })) {
883
- enumSchema.type = "string";
884
- }
885
- else if (enumValues.every((x) => {
886
- return typeof x === "number";
887
- })) {
888
- enumSchema.type = "number";
889
- }
890
- else if (enumValues.every((x) => {
891
- return typeof x === "boolean";
892
- })) {
893
- enumSchema.type = "boolean";
894
- }
895
- schemas.push(enumSchema);
896
- }
897
- }
898
- if (simpleTypes.length > 0) {
899
- schemas.push({
900
- type: simpleTypes.length === 1 ? simpleTypes[0] : simpleTypes,
901
- });
902
- }
903
- if (schemas.length === 1) {
904
- for (const k in schemas[0]) {
905
- if (schemas[0].hasOwnProperty(k)) {
906
- if (k === "description" && definition.hasOwnProperty(k)) {
907
- // If we already have a more specific description, don't overwrite it.
908
- continue;
909
- }
910
- definition[k] =
911
- schemas[0][k];
912
- }
913
- }
914
- }
915
- else {
916
- definition[unionModifier] = schemas;
917
- }
918
- return definition;
919
- }
920
- getIntersectionDefinition(intersectionType, definition) {
921
- const simpleTypes = [];
922
- const schemas = [];
923
- const pushSimpleType = (type) => {
924
- if (simpleTypes.indexOf(type) === -1) {
925
- simpleTypes.push(type);
926
- }
927
- };
928
- for (const intersectionMember of intersectionType.types) {
929
- const def = this.getTypeDefinition(intersectionMember);
930
- const keys = Object.keys(def);
931
- if (keys.length === 1 && keys[0] === "type") {
932
- if (typeof def.type !== "string") {
933
- console.error("Expected only a simple type.");
934
- }
935
- else {
936
- pushSimpleType(def.type);
937
- }
938
- }
939
- else {
940
- schemas.push(def);
941
- }
942
- }
943
- if (simpleTypes.length > 0) {
944
- schemas.push({
945
- type: simpleTypes.length === 1 ? simpleTypes[0] : simpleTypes,
946
- });
947
- }
948
- if (schemas.length === 1) {
949
- for (const k in schemas[0]) {
950
- if (schemas[0].hasOwnProperty(k)) {
951
- definition[k] =
952
- schemas[0][k];
953
- }
954
- }
955
- }
956
- else {
957
- definition.allOf = schemas;
958
- }
959
- return definition;
960
- }
961
- getClassDefinition(clazzType, definition) {
962
- const node = clazzType.getSymbol().getDeclarations()[0];
963
- // Example: typeof globalThis may not have any declaration
964
- if (!node) {
965
- definition.type = "object";
966
- return definition;
967
- }
968
- if (this.args.typeOfKeyword && node.kind === ts.SyntaxKind.FunctionType) {
969
- definition.typeof = "function";
970
- return definition;
971
- }
972
- const clazz = node;
973
- const props = this.tc.getPropertiesOfType(clazzType).filter((prop) => {
974
- // filter never and undefined
975
- const propertyFlagType = this.tc
976
- .getTypeOfSymbolAtLocation(prop, node)
977
- .getFlags();
978
- if (ts.TypeFlags.Never === propertyFlagType ||
979
- ts.TypeFlags.Undefined === propertyFlagType) {
980
- return false;
981
- }
982
- if (!this.args.excludePrivate) {
983
- return true;
984
- }
985
- const decls = prop.declarations;
986
- return !(decls &&
987
- decls.filter((decl) => {
988
- const mods = decl.modifiers;
989
- return (mods &&
990
- mods.filter((mod) => mod.kind === ts.SyntaxKind.PrivateKeyword)
991
- .length > 0);
992
- }).length > 0);
993
- });
994
- const fullName = this.tc.typeToString(clazzType, undefined, ts.TypeFormatFlags.UseFullyQualifiedType);
995
- const modifierFlags = ts.getCombinedModifierFlags(node);
996
- if (modifierFlags & ts.ModifierFlags.Abstract &&
997
- this.inheritingTypes[fullName]) {
998
- const oneOf = this.inheritingTypes[fullName].map((typename) => {
999
- return this.getTypeDefinition(this.allSymbols[typename]);
1000
- });
1001
- definition.oneOf = oneOf;
1002
- }
1003
- else {
1004
- if (clazz.members) {
1005
- const indexSignatures = clazz.members == null
1006
- ? []
1007
- : clazz.members.filter((x) => x.kind === ts.SyntaxKind.IndexSignature);
1008
- if (indexSignatures.length === 1) {
1009
- // for case "array-types"
1010
- const indexSignature = indexSignatures[0];
1011
- if (indexSignature.parameters.length !== 1) {
1012
- throw new Error("Not supported: IndexSignatureDeclaration parameters.length != 1");
1013
- }
1014
- const indexSymbol = indexSignature.parameters[0]
1015
- .symbol;
1016
- const indexType = this.tc.getTypeOfSymbolAtLocation(indexSymbol, node);
1017
- const isIndexedObject = indexType.flags === ts.TypeFlags.String ||
1018
- indexType.flags === ts.TypeFlags.Number;
1019
- if (indexType.flags !== ts.TypeFlags.Number && !isIndexedObject) {
1020
- throw new Error("Not supported: IndexSignatureDeclaration with index symbol other than a number or a string");
1021
- }
1022
- const typ = this.tc.getTypeAtLocation(indexSignature.type);
1023
- let def;
1024
- if (typ.flags & ts.TypeFlags.IndexedAccess) {
1025
- const targetName = ts.escapeLeadingUnderscores(clazzType.mapper?.target?.value);
1026
- const indexedAccessType = typ;
1027
- const symbols = indexedAccessType.objectType.members;
1028
- const targetSymbol = symbols?.get(targetName);
1029
- if (targetSymbol) {
1030
- const targetNode = targetSymbol.getDeclarations()[0];
1031
- const targetDef = this.getDefinitionForProperty(targetSymbol, targetNode);
1032
- if (targetDef) {
1033
- def = targetDef;
1034
- }
1035
- }
1036
- }
1037
- if (!def) {
1038
- def = this.getTypeDefinition(typ, undefined, "anyOf");
1039
- }
1040
- if (isIndexedObject) {
1041
- definition.type = "object";
1042
- if (!Object.keys(definition.patternProperties || {}).length) {
1043
- definition.additionalProperties = def;
1044
- }
1045
- }
1046
- else {
1047
- definition.type = "array";
1048
- if (!definition.items) {
1049
- definition.items = def;
1050
- }
1051
- }
1052
- }
1053
- }
1054
- const propertyDefinitions = props.reduce((all, prop) => {
1055
- const propertyName = prop.getName();
1056
- const propDef = this.getDefinitionForProperty(prop, node);
1057
- if (propDef != null) {
1058
- all[propertyName] = propDef;
1059
- }
1060
- return all;
1061
- }, {});
1062
- if (definition.type === undefined) {
1063
- definition.type = "object";
1064
- }
1065
- if (definition.type === "object" &&
1066
- Object.keys(propertyDefinitions).length > 0) {
1067
- definition.properties = propertyDefinitions;
1068
- }
1069
- if (this.args.defaultProps) {
1070
- definition.defaultProperties = [];
1071
- }
1072
- if (this.args.noExtraProps &&
1073
- definition.additionalProperties === undefined) {
1074
- definition.additionalProperties = false;
1075
- }
1076
- if (this.args.propOrder) {
1077
- // propertyOrder is non-standard, but useful:
1078
- // https://github.com/json-schema/json-schema/issues/87
1079
- const propertyOrder = props.reduce((order, prop) => {
1080
- order.push(prop.getName());
1081
- return order;
1082
- }, []);
1083
- definition.propertyOrder = propertyOrder;
1084
- }
1085
- if (this.args.required) {
1086
- const requiredProps = props.reduce((required, prop) => {
1087
- const def = {};
1088
- this.parseCommentsIntoDefinition(prop, def, {});
1089
- const allUnionTypesFlags = prop.links?.type?.types?.map?.((t) => t.flags) ||
1090
- [];
1091
- if (!(prop.flags & ts.SymbolFlags.Optional) &&
1092
- !(prop.flags & ts.SymbolFlags.Method) &&
1093
- !allUnionTypesFlags.includes(ts.TypeFlags.Undefined) &&
1094
- !allUnionTypesFlags.includes(ts.TypeFlags.Void) &&
1095
- !def.hasOwnProperty("ignore")) {
1096
- required.push(prop.getName());
1097
- }
1098
- return required;
1099
- }, []);
1100
- if (requiredProps.length > 0) {
1101
- definition.required = unique(requiredProps).sort();
1102
- }
1103
- }
1104
- }
1105
- return definition;
1106
- }
1107
- /**
1108
- * Gets/generates a globally unique type name for the given type
1109
- */
1110
- getTypeName(typ) {
1111
- const id = typ.id;
1112
- if (this.typeNamesById[id]) {
1113
- // Name already assigned?
1114
- return this.typeNamesById[id];
1115
- }
1116
- return this.makeTypeNameUnique(typ, this.tc
1117
- .typeToString(typ, undefined, ts.TypeFormatFlags.NoTruncation |
1118
- ts.TypeFormatFlags.UseFullyQualifiedType)
1119
- .replace(REGEX_FILE_NAME_OR_SPACE, ""));
1120
- }
1121
- makeTypeNameUnique(typ, baseName) {
1122
- const id = typ.id;
1123
- let name = baseName;
1124
- // If a type with same name exists
1125
- // Try appending "_1", "_2", etc.
1126
- for (let i = 1; this.typeIdsByName[name] !== undefined && this.typeIdsByName[name] !== id; ++i) {
1127
- name = baseName + "_" + i;
1128
- }
1129
- this.typeNamesById[id] = name;
1130
- this.typeIdsByName[name] = id;
1131
- return name;
1132
- }
1133
- recursiveTypeRef = new Map();
1134
- getTypeDefinition(typ, asRef = this.args.ref, unionModifier = "anyOf", prop, reffedType, pairedSymbol, forceNotRef = false, ignoreUndefined = false) {
1135
- const definition = {}; // real definition
1136
- // Ignore any number of Readonly and Mutable type wrappings, since they only add and remove readonly modifiers on fields and JSON Schema is not concerned with mutability
1137
- while (typ.aliasSymbol &&
1138
- (typ.aliasSymbol.escapedName === "Readonly" ||
1139
- typ.aliasSymbol.escapedName === "Mutable") &&
1140
- typ.aliasTypeArguments &&
1141
- typ.aliasTypeArguments[0]) {
1142
- typ = typ.aliasTypeArguments[0];
1143
- reffedType = undefined;
1144
- }
1145
- if (this.args.typeOfKeyword &&
1146
- typ.flags & ts.TypeFlags.Object &&
1147
- typ.objectFlags & ts.ObjectFlags.Anonymous) {
1148
- definition.typeof = "function";
1149
- return definition;
1150
- }
1151
- let returnedDefinition = definition; // returned definition, may be a $ref
1152
- // Parse property comments now to skip recursive if ignore.
1153
- if (prop) {
1154
- const defs = {};
1155
- const others = {};
1156
- this.parseCommentsIntoDefinition(prop, defs, others);
1157
- if (defs.hasOwnProperty("ignore") || defs.hasOwnProperty("type")) {
1158
- return defs;
1159
- }
1160
- }
1161
- const symbol = typ.getSymbol();
1162
- // FIXME: We can't just compare the name of the symbol - it ignores the namespace
1163
- let isRawType = !symbol ||
1164
- // Window is incorrectly marked as rawType here for some reason
1165
- (this.tc.getFullyQualifiedName(symbol) !== "Window" &&
1166
- (this.tc.getFullyQualifiedName(symbol) === "Date" ||
1167
- symbol.name === "integer" ||
1168
- this.tc.getIndexInfoOfType(typ, ts.IndexKind.Number) !== undefined));
1169
- if (isRawType &&
1170
- typ.aliasSymbol?.escapedName &&
1171
- typ.types) {
1172
- isRawType = false;
1173
- }
1174
- // special case: an union where all child are string literals -> make an enum instead
1175
- let isStringEnum = false;
1176
- if (typ.flags & ts.TypeFlags.Union) {
1177
- const unionType = typ;
1178
- isStringEnum = unionType.types.every((propType) => {
1179
- return (propType.getFlags() & ts.TypeFlags.StringLiteral) !== 0;
1180
- });
1181
- }
1182
- // aliased types must be handled slightly different
1183
- const asTypeAliasRef = asRef && reffedType && (this.args.aliasRef || isStringEnum);
1184
- if (!asTypeAliasRef) {
1185
- if (isRawType ||
1186
- (typ.getFlags() & ts.TypeFlags.Object &&
1187
- typ.objectFlags & ts.ObjectFlags.Anonymous)) {
1188
- asRef = false; // raw types and inline types cannot be reffed,
1189
- // unless we are handling a type alias
1190
- // or it is recursive type - see below
1191
- }
1192
- }
1193
- let fullTypeName = "";
1194
- if (asTypeAliasRef) {
1195
- const typeName = this.tc
1196
- .getFullyQualifiedName(reffedType.getFlags() & ts.SymbolFlags.Alias
1197
- ? this.tc.getAliasedSymbol(reffedType)
1198
- : reffedType)
1199
- .replace(REGEX_FILE_NAME_OR_SPACE, "");
1200
- if (this.args.uniqueNames && reffedType) {
1201
- const sourceFile = getSourceFile(reffedType);
1202
- const relativePath = path.relative(process.cwd(), sourceFile.fileName);
1203
- fullTypeName = `${typeName}.${generateHashOfNode(getCanonicalDeclaration(reffedType), relativePath)}`;
1204
- }
1205
- else {
1206
- fullTypeName = this.makeTypeNameUnique(typ, typeName);
1207
- }
1208
- }
1209
- else {
1210
- // typ.symbol can be undefined
1211
- if (this.args.uniqueNames && typ.symbol) {
1212
- const sym = typ.symbol;
1213
- const sourceFile = getSourceFile(sym);
1214
- const relativePath = path.relative(process.cwd(), sourceFile.fileName);
1215
- fullTypeName = `${this.getTypeName(typ)}.${generateHashOfNode(getCanonicalDeclaration(sym), relativePath)}`;
1216
- }
1217
- else if (reffedType &&
1218
- this.schemaOverrides.has(reffedType.escapedName)) {
1219
- fullTypeName = reffedType.escapedName;
1220
- }
1221
- else {
1222
- fullTypeName = this.getTypeName(typ);
1223
- }
1224
- }
1225
- // Handle recursive types
1226
- if (!isRawType || !!typ.aliasSymbol) {
1227
- if (this.recursiveTypeRef.has(fullTypeName) && !forceNotRef) {
1228
- asRef = true;
1229
- }
1230
- else {
1231
- this.recursiveTypeRef.set(fullTypeName, definition);
1232
- }
1233
- }
1234
- if (asRef) {
1235
- // We don't return the full definition, but we put it into
1236
- // reffedDefinitions below.
1237
- returnedDefinition = {
1238
- $ref: `${this.args.id}#/definitions/` + fullTypeName,
1239
- };
1240
- }
1241
- // Parse comments
1242
- const otherAnnotations = {};
1243
- this.parseCommentsIntoDefinition(reffedType, definition, otherAnnotations); // handle comments in the type alias declaration
1244
- this.parseCommentsIntoDefinition(symbol, definition, otherAnnotations);
1245
- this.parseCommentsIntoDefinition(typ.aliasSymbol, definition, otherAnnotations);
1246
- if (prop) {
1247
- this.parseCommentsIntoDefinition(prop, returnedDefinition, otherAnnotations);
1248
- }
1249
- if (pairedSymbol && symbol && this.isFromDefaultLib(symbol)) {
1250
- this.parseCommentsIntoDefinition(pairedSymbol, definition, otherAnnotations);
1251
- }
1252
- // Create the actual definition only if is an inline definition, or
1253
- // if it will be a $ref and it is not yet created.
1254
- // Prioritise overrides.
1255
- const overrideDefinition = this.schemaOverrides.get(fullTypeName);
1256
- if (overrideDefinition) {
1257
- this.reffedDefinitions[fullTypeName] = overrideDefinition;
1258
- }
1259
- else if (!asRef || !this.reffedDefinitions[fullTypeName]) {
1260
- if (asRef) {
1261
- // must be here to prevent recursivity problems
1262
- let reffedDefinition;
1263
- if (asTypeAliasRef &&
1264
- reffedType &&
1265
- typ.symbol !== reffedType &&
1266
- symbol) {
1267
- reffedDefinition = this.getTypeDefinition(typ, true, undefined, symbol, symbol);
1268
- }
1269
- else {
1270
- reffedDefinition = definition;
1271
- }
1272
- this.reffedDefinitions[fullTypeName] = reffedDefinition;
1273
- if (this.args.titles && fullTypeName) {
1274
- definition.title = fullTypeName;
1275
- }
1276
- }
1277
- const node = symbol?.getDeclarations() !== undefined
1278
- ? symbol.getDeclarations()[0]
1279
- : null;
1280
- if (definition.type === undefined) {
1281
- // if users override the type, do not try to infer it
1282
- if (typ.flags & ts.TypeFlags.Union &&
1283
- (node === null || node.kind !== ts.SyntaxKind.EnumDeclaration)) {
1284
- this.getUnionDefinition(typ, unionModifier, definition);
1285
- }
1286
- else if (typ.flags & ts.TypeFlags.Intersection) {
1287
- if (this.args.noExtraProps) {
1288
- // extend object instead of using allOf because allOf does not work well with additional properties. See #107
1289
- if (this.args.noExtraProps) {
1290
- definition.additionalProperties = false;
1291
- }
1292
- const types = typ.types;
1293
- for (const member of types) {
1294
- const other = this.getTypeDefinition(member, false, undefined, undefined, undefined, undefined, true);
1295
- definition.type = other.type; // should always be object
1296
- definition.properties = {
1297
- ...definition.properties,
1298
- ...other.properties,
1299
- };
1300
- if (Object.keys(other.default || {}).length > 0) {
1301
- definition.default = extend(definition.default || {}, other.default);
1302
- }
1303
- if (other.required) {
1304
- definition.required = unique((definition.required || []).concat(other.required)).sort();
1305
- }
1306
- }
1307
- }
1308
- else {
1309
- this.getIntersectionDefinition(typ, definition);
1310
- }
1311
- }
1312
- else if (isRawType) {
1313
- if (pairedSymbol) {
1314
- this.parseCommentsIntoDefinition(pairedSymbol, definition, {});
1315
- }
1316
- this.getDefinitionForRootType(typ, reffedType, definition, undefined, ignoreUndefined);
1317
- }
1318
- else if (node &&
1319
- (node.kind === ts.SyntaxKind.EnumDeclaration ||
1320
- node.kind === ts.SyntaxKind.EnumMember)) {
1321
- this.getEnumDefinition(typ, definition);
1322
- }
1323
- else if (symbol &&
1324
- symbol.flags & ts.SymbolFlags.TypeLiteral &&
1325
- symbol.members.size === 0 &&
1326
- !(node && node.kind === ts.SyntaxKind.MappedType)) {
1327
- // {} is TypeLiteral with no members. Need special case because it doesn't have declarations.
1328
- definition.type = "object";
1329
- definition.properties = {};
1330
- }
1331
- else {
1332
- this.getClassDefinition(typ, definition);
1333
- }
1334
- }
1335
- }
1336
- if (this.recursiveTypeRef.get(fullTypeName) === definition) {
1337
- this.recursiveTypeRef.delete(fullTypeName);
1338
- // If the type was recursive (there is reffedDefinitions) - lets replace it to reference
1339
- if (this.reffedDefinitions[fullTypeName]) {
1340
- const annotations = Object.entries(returnedDefinition).reduce((acc, [key, value]) => {
1341
- if (annotationKeywords[key] &&
1342
- typeof value !== undefined) {
1343
- acc[key] = value;
1344
- }
1345
- return acc;
1346
- }, {});
1347
- returnedDefinition = {
1348
- $ref: `${this.args.id}#/definitions/` + fullTypeName,
1349
- ...annotations,
1350
- };
1351
- }
1352
- }
1353
- if (otherAnnotations["nullable"]) {
1354
- makeNullable(returnedDefinition);
1355
- }
1356
- return returnedDefinition;
1357
- }
1358
- setSchemaOverride(symbolName, schema) {
1359
- this.schemaOverrides.set(symbolName, schema);
1360
- }
1361
- getSchemaForSymbol(symbolName, includeReffedDefinitions = true, includeAllOverrides = false) {
1362
- const overrideDefinition = this.schemaOverrides.get(symbolName);
1363
- if (!this.allSymbols[symbolName] && !overrideDefinition) {
1364
- throw new Error(`type ${symbolName} not found`);
1365
- }
1366
- this.resetSchemaSpecificProperties(includeAllOverrides);
1367
- let def;
1368
- if (overrideDefinition) {
1369
- def = { ...overrideDefinition };
1370
- }
1371
- else {
1372
- def = overrideDefinition
1373
- ? overrideDefinition
1374
- : this.getTypeDefinition(this.allSymbols[symbolName], this.args.topRef, undefined, undefined, undefined, this.userSymbols[symbolName] || undefined);
1375
- }
1376
- if (this.args.ref &&
1377
- includeReffedDefinitions &&
1378
- Object.keys(this.reffedDefinitions).length > 0) {
1379
- def.definitions = this.reffedDefinitions;
1380
- }
1381
- def["$schema"] = "http://json-schema.org/draft-07/schema#";
1382
- const id = this.args.id;
1383
- if (id) {
1384
- def["$id"] = this.args.id;
1385
- }
1386
- return def;
1387
- }
1388
- getSchemaForSymbols(symbolNames, includeReffedDefinitions = true, includeAllOverrides = false) {
1389
- const root = {
1390
- $schema: "http://json-schema.org/draft-07/schema#",
1391
- definitions: {},
1392
- };
1393
- this.resetSchemaSpecificProperties(includeAllOverrides);
1394
- const id = this.args.id;
1395
- if (id) {
1396
- root["$id"] = id;
1397
- }
1398
- for (const symbolName of symbolNames) {
1399
- root.definitions[symbolName] = this.getTypeDefinition(this.allSymbols[symbolName], this.args.topRef, undefined, undefined, undefined, this.userSymbols[symbolName]);
1400
- }
1401
- if (this.args.ref &&
1402
- includeReffedDefinitions &&
1403
- Object.keys(this.reffedDefinitions).length > 0) {
1404
- root.definitions = { ...root.definitions, ...this.reffedDefinitions };
1405
- }
1406
- return root;
1407
- }
1408
- getSymbols(name) {
1409
- if (name === void 0) {
1410
- return this.symbols;
1411
- }
1412
- return this.symbols.filter((symbol) => symbol.typeName === name);
1413
- }
1414
- getUserSymbols() {
1415
- return Object.keys(this.userSymbols);
1416
- }
1417
- getMainFileSymbols(program, onlyIncludeFiles) {
1418
- function includeFile(file) {
1419
- if (onlyIncludeFiles === undefined) {
1420
- return !file.isDeclarationFile;
1421
- }
1422
- return (onlyIncludeFiles.filter((f) => pathEqual(f, file.fileName)).length > 0);
1423
- }
1424
- const files = program.getSourceFiles().filter(includeFile);
1425
- if (files.length) {
1426
- return Object.keys(this.userSymbols).filter((key) => {
1427
- const symbol = this.userSymbols[key];
1428
- if (!symbol || !symbol.declarations || !symbol.declarations.length) {
1429
- return false;
1430
- }
1431
- let node = symbol.declarations[0];
1432
- while (node?.parent) {
1433
- node = node.parent;
1434
- }
1435
- return files.indexOf(node.getSourceFile()) > -1;
1436
- });
1437
- }
1438
- return [];
1439
- }
1440
- }
1441
- function generateHashOfNode(node, relativePath) {
1442
- return createHash("md5")
1443
- .update(relativePath)
1444
- .update(node.pos.toString())
1445
- .digest("hex")
1446
- .substring(0, 8);
1447
- }
1448
- export function buildGenerator(program, args = {}) {
1449
- // Use defaults unless otherwise specified
1450
- const settings = getDefaultArgs();
1451
- for (const pref in args) {
1452
- if (args.hasOwnProperty(pref)) {
1453
- settings[pref] = args[pref];
1454
- }
1455
- }
1456
- const typeChecker = program.getTypeChecker();
1457
- const symbols = [];
1458
- const allSymbols = {};
1459
- const userSymbols = {};
1460
- const inheritingTypes = {};
1461
- const workingDir = program.getCurrentDirectory();
1462
- program.getSourceFiles().forEach((sourceFile, _sourceFileIdx) => {
1463
- const relativePath = path.relative(workingDir, sourceFile.fileName);
1464
- function inspect(node, tc) {
1465
- if (node.kind === ts.SyntaxKind.ClassDeclaration ||
1466
- node.kind === ts.SyntaxKind.InterfaceDeclaration ||
1467
- node.kind === ts.SyntaxKind.EnumDeclaration ||
1468
- node.kind === ts.SyntaxKind.TypeAliasDeclaration) {
1469
- const symbol = node.symbol;
1470
- const nodeType = tc.getTypeAtLocation(node);
1471
- const fullyQualifiedName = tc.getFullyQualifiedName(symbol);
1472
- const typeName = fullyQualifiedName.replace(/".*"\./, "");
1473
- const name = !args.uniqueNames
1474
- ? typeName
1475
- : `${typeName}.${generateHashOfNode(node, relativePath)}`;
1476
- symbols.push({ name, typeName, fullyQualifiedName, symbol });
1477
- if (!userSymbols[name]) {
1478
- allSymbols[name] = nodeType;
1479
- }
1480
- const baseTypes = nodeType.getBaseTypes() || [];
1481
- baseTypes.forEach((baseType) => {
1482
- var baseName = tc.typeToString(baseType, undefined, ts.TypeFormatFlags.UseFullyQualifiedType);
1483
- if (!inheritingTypes[baseName]) {
1484
- inheritingTypes[baseName] = [];
1485
- }
1486
- inheritingTypes[baseName].push(name);
1487
- });
1488
- }
1489
- else {
1490
- ts.forEachChild(node, (n) => inspect(n, tc));
1491
- }
1492
- }
1493
- inspect(sourceFile, typeChecker);
1494
- });
1495
- return new JsonSchemaGenerator(symbols, allSymbols, userSymbols, inheritingTypes, typeChecker, settings);
1496
- }