ts-class-to-openapi 1.4.1 → 1.4.2
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.
- package/dist/index.cjs +284 -192
- package/dist/index.mjs +284 -192
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -28,6 +28,53 @@ path = __toESM(path);
|
|
|
28
28
|
//#region src/transformer.fixtures.ts
|
|
29
29
|
const constants = {
|
|
30
30
|
TS_CONFIG_DEFAULT_PATH: path.default.resolve(process.cwd(), "tsconfig.json"),
|
|
31
|
+
JS_KEYWORDS: new Set([
|
|
32
|
+
"constructor",
|
|
33
|
+
"static",
|
|
34
|
+
"get",
|
|
35
|
+
"set",
|
|
36
|
+
"async",
|
|
37
|
+
"return",
|
|
38
|
+
"if",
|
|
39
|
+
"else",
|
|
40
|
+
"for",
|
|
41
|
+
"while",
|
|
42
|
+
"switch",
|
|
43
|
+
"case",
|
|
44
|
+
"break",
|
|
45
|
+
"throw",
|
|
46
|
+
"new",
|
|
47
|
+
"delete",
|
|
48
|
+
"typeof",
|
|
49
|
+
"void",
|
|
50
|
+
"try",
|
|
51
|
+
"catch",
|
|
52
|
+
"finally",
|
|
53
|
+
"this",
|
|
54
|
+
"super",
|
|
55
|
+
"class",
|
|
56
|
+
"const",
|
|
57
|
+
"let",
|
|
58
|
+
"var",
|
|
59
|
+
"function",
|
|
60
|
+
"yield",
|
|
61
|
+
"await",
|
|
62
|
+
"import",
|
|
63
|
+
"export",
|
|
64
|
+
"default",
|
|
65
|
+
"extends",
|
|
66
|
+
"implements",
|
|
67
|
+
"in",
|
|
68
|
+
"of",
|
|
69
|
+
"do",
|
|
70
|
+
"with",
|
|
71
|
+
"continue",
|
|
72
|
+
"instanceof",
|
|
73
|
+
"true",
|
|
74
|
+
"false",
|
|
75
|
+
"null",
|
|
76
|
+
"undefined"
|
|
77
|
+
]),
|
|
31
78
|
jsPrimitives: {
|
|
32
79
|
String: {
|
|
33
80
|
type: "String",
|
|
@@ -190,6 +237,7 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
190
237
|
autoCleanup;
|
|
191
238
|
classFileIndex = /* @__PURE__ */ new Map();
|
|
192
239
|
transformCallIndex = /* @__PURE__ */ new Map();
|
|
240
|
+
nonGenericTransformCalls = /* @__PURE__ */ new Set();
|
|
193
241
|
constructor(tsConfigPath = constants.TS_CONFIG_DEFAULT_PATH, options = {}) {
|
|
194
242
|
this.maxCacheSize = options.maxCacheSize ?? 100;
|
|
195
243
|
this.autoCleanup = options.autoCleanup ?? true;
|
|
@@ -236,78 +284,77 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
236
284
|
}
|
|
237
285
|
getPropertiesByClassMembers(members, parentClassNode, genericTypeMap = /* @__PURE__ */ new Map()) {
|
|
238
286
|
const properties = [];
|
|
239
|
-
for (const member of members) {
|
|
240
|
-
var
|
|
241
|
-
if (
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
if (
|
|
258
|
-
const
|
|
259
|
-
if (
|
|
260
|
-
const matches = this.classFileIndex.get(baseTypeName);
|
|
261
|
-
if (matches && matches.length > 0 && matches[0]) genericClassReference = matches[0].node;
|
|
262
|
-
}
|
|
287
|
+
for (const member of members) if (typescript.default.isPropertyDeclaration(member) && (typescript.default.isIdentifier(member.name) || typescript.default.isStringLiteral(member.name))) {
|
|
288
|
+
var _property$originalPro;
|
|
289
|
+
if (member.modifiers) {
|
|
290
|
+
if (member.modifiers.some((m) => m.kind === typescript.default.SyntaxKind.PrivateKeyword || m.kind === typescript.default.SyntaxKind.ProtectedKeyword)) continue;
|
|
291
|
+
}
|
|
292
|
+
const propertyName = member.name.text;
|
|
293
|
+
const type = this.getPropertyType(member, genericTypeMap);
|
|
294
|
+
const decorators = this.extractDecorators(member);
|
|
295
|
+
const isOptional = !!member.questionToken;
|
|
296
|
+
const isGeneric = this.isPropertyTypeGeneric(member);
|
|
297
|
+
const isEnum = this.isEnum(member);
|
|
298
|
+
const isPrimitive = this.isPrimitiveType(type) || isEnum;
|
|
299
|
+
const isClassType = this.isClassType(member);
|
|
300
|
+
const isArray = this.isArrayProperty(member);
|
|
301
|
+
const isTypeLiteral = this.isTypeLiteral(member);
|
|
302
|
+
let genericClassReference = void 0;
|
|
303
|
+
if (isGeneric && !isPrimitive) {
|
|
304
|
+
const baseTypeName = type.replace(/\[\]$/, "").trim();
|
|
305
|
+
if (!this.isPrimitiveType(baseTypeName)) {
|
|
306
|
+
const matches = this.classFileIndex.get(baseTypeName);
|
|
307
|
+
if (matches && matches.length > 0 && matches[0]) genericClassReference = matches[0].node;
|
|
263
308
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
309
|
+
}
|
|
310
|
+
const property = {
|
|
311
|
+
name: propertyName,
|
|
312
|
+
type,
|
|
313
|
+
decorators,
|
|
314
|
+
isOptional,
|
|
315
|
+
isGeneric,
|
|
316
|
+
originalProperty: member,
|
|
317
|
+
isPrimitive,
|
|
318
|
+
isClassType,
|
|
319
|
+
isArray,
|
|
320
|
+
isEnum,
|
|
321
|
+
isRef: false,
|
|
322
|
+
isTypeLiteral,
|
|
323
|
+
genericClassReference
|
|
324
|
+
};
|
|
325
|
+
if (property.isClassType) {
|
|
326
|
+
const declaration = this.getDeclarationProperty(property);
|
|
327
|
+
if (parentClassNode) {
|
|
328
|
+
if (declaration && declaration.name && this.checker.getSymbolAtLocation(declaration.name) === this.checker.getSymbolAtLocation(parentClassNode.name)) property.isRef = true;
|
|
284
329
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
330
|
+
}
|
|
331
|
+
if (property.isTypeLiteral && property.originalProperty.type !== void 0 && typescript.default.isTypeReferenceNode(property.originalProperty.type) && ((_property$originalPro = property.originalProperty.type.typeArguments) === null || _property$originalPro === void 0 ? void 0 : _property$originalPro.length) === 1) {
|
|
332
|
+
const typeArguments = property.originalProperty.type.typeArguments;
|
|
333
|
+
if (typeArguments && typeArguments[0]) {
|
|
334
|
+
const firstTypeArg = typeArguments[0];
|
|
335
|
+
if (typescript.default.isTypeReferenceNode(firstTypeArg)) {
|
|
336
|
+
const symbol = this.checker.getTypeAtLocation(firstTypeArg).getSymbol();
|
|
337
|
+
if (symbol && symbol.declarations) {
|
|
338
|
+
const classDeclaration = symbol.declarations.find((decl) => typescript.default.isClassDeclaration(decl));
|
|
339
|
+
if (classDeclaration && typescript.default.isClassDeclaration(classDeclaration)) property.typeLiteralClassReference = classDeclaration;
|
|
295
340
|
}
|
|
296
341
|
}
|
|
297
342
|
}
|
|
298
|
-
properties.push(property);
|
|
299
343
|
}
|
|
344
|
+
properties.push(property);
|
|
300
345
|
}
|
|
301
346
|
return properties;
|
|
302
347
|
}
|
|
303
348
|
getPropertyType(property, genericTypeMap = /* @__PURE__ */ new Map()) {
|
|
304
349
|
if (property.type) return this.getTypeNodeToString(property.type, genericTypeMap);
|
|
305
350
|
const type = this.checker.getTypeAtLocation(property);
|
|
306
|
-
return this.
|
|
351
|
+
return this.checker.typeToString(type);
|
|
307
352
|
}
|
|
308
353
|
getTypeNodeToString(typeNode, genericTypeMap = /* @__PURE__ */ new Map()) {
|
|
309
|
-
if (typescript.default.isTypeReferenceNode(typeNode)
|
|
310
|
-
|
|
354
|
+
if (typescript.default.isTypeReferenceNode(typeNode)) {
|
|
355
|
+
let typeName;
|
|
356
|
+
if (typescript.default.isIdentifier(typeNode.typeName)) typeName = typeNode.typeName.text;
|
|
357
|
+
else typeName = typeNode.typeName.right.text;
|
|
311
358
|
if (genericTypeMap.has(typeName)) return genericTypeMap.get(typeName);
|
|
312
359
|
if (typeName.toLowerCase() === "uploadfile") return "UploadFile";
|
|
313
360
|
if (typeName.toLowerCase() === "uploadfiledto") return "UploadFileDto";
|
|
@@ -319,7 +366,7 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
319
366
|
}
|
|
320
367
|
return this.resolveGenericType(typeNode);
|
|
321
368
|
}
|
|
322
|
-
return
|
|
369
|
+
return typeName;
|
|
323
370
|
}
|
|
324
371
|
switch (typeNode.kind) {
|
|
325
372
|
case typescript.default.SyntaxKind.StringKeyword: return constants.jsPrimitives.String.type;
|
|
@@ -334,31 +381,31 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
334
381
|
if (meaningfulTypes.length > 0 && meaningfulTypes[0]) return meaningfulTypes[0];
|
|
335
382
|
if (types.length > 0 && types[0]) return types[0];
|
|
336
383
|
return "object";
|
|
337
|
-
default:
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
if (
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
return typeText;
|
|
384
|
+
default: {
|
|
385
|
+
const resolvedType = this.checker.getTypeAtLocation(typeNode);
|
|
386
|
+
const resolved = this.checker.typeToString(resolvedType);
|
|
387
|
+
if (genericTypeMap && genericTypeMap.has(resolved)) return genericTypeMap.get(resolved);
|
|
388
|
+
if (this.isPrimitiveType(resolved)) return resolved;
|
|
389
|
+
if (resolved === "Date") return constants.jsPrimitives.Date.type;
|
|
390
|
+
if (resolved === "Buffer") return constants.jsPrimitives.Buffer.type;
|
|
391
|
+
if (resolved === "Uint8Array") return constants.jsPrimitives.Uint8Array.type;
|
|
392
|
+
return resolved;
|
|
393
|
+
}
|
|
348
394
|
}
|
|
349
395
|
}
|
|
350
396
|
resolveGenericType(typeNode) {
|
|
351
|
-
|
|
397
|
+
let typeName;
|
|
398
|
+
if (typescript.default.isIdentifier(typeNode.typeName)) typeName = typeNode.typeName.text;
|
|
399
|
+
else typeName = typeNode.typeName.right.text;
|
|
352
400
|
const typeArguments = typeNode.typeArguments;
|
|
353
401
|
if (!typeArguments || typeArguments.length === 0) return typeName;
|
|
354
402
|
const type = this.checker.getTypeAtLocation(typeNode);
|
|
355
|
-
|
|
356
|
-
|
|
403
|
+
if (!(type.flags & typescript.default.TypeFlags.Any)) {
|
|
404
|
+
const resolvedType = this.checker.typeToString(type);
|
|
405
|
+
if (resolvedType && resolvedType !== typeName) return resolvedType;
|
|
406
|
+
}
|
|
357
407
|
return typeName;
|
|
358
408
|
}
|
|
359
|
-
getStringFromType(type) {
|
|
360
|
-
return this.checker.typeToString(type);
|
|
361
|
-
}
|
|
362
409
|
extractDecorators(member) {
|
|
363
410
|
const decorators = [];
|
|
364
411
|
if (member.modifiers) {
|
|
@@ -378,6 +425,7 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
378
425
|
}
|
|
379
426
|
getDecoratorName(callExpression) {
|
|
380
427
|
if (typescript.default.isIdentifier(callExpression.expression)) return callExpression.expression.text;
|
|
428
|
+
if (typescript.default.isPropertyAccessExpression(callExpression.expression)) return callExpression.expression.name.text;
|
|
381
429
|
return "unknown";
|
|
382
430
|
}
|
|
383
431
|
getDecoratorArguments(callExpression) {
|
|
@@ -390,7 +438,13 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
390
438
|
});
|
|
391
439
|
}
|
|
392
440
|
getSafeDecoratorArgument(arg) {
|
|
393
|
-
if (arg && typeof arg === "object" && "kind" in arg)
|
|
441
|
+
if (arg && typeof arg === "object" && "kind" in arg) {
|
|
442
|
+
const node = arg;
|
|
443
|
+
const type = this.checker.getTypeAtLocation(node);
|
|
444
|
+
if (type.isNumberLiteral()) return type.value;
|
|
445
|
+
if (type.isStringLiteral()) return type.value;
|
|
446
|
+
return this.checker.typeToString(type);
|
|
447
|
+
}
|
|
394
448
|
return arg;
|
|
395
449
|
}
|
|
396
450
|
isPropertyTypeGeneric(property) {
|
|
@@ -414,15 +468,18 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
414
468
|
isGenericTypeFromSymbol(type) {
|
|
415
469
|
if (this.isSimpleArrayType(type)) return false;
|
|
416
470
|
if (type.aliasTypeArguments && type.aliasTypeArguments.length > 0) return true;
|
|
417
|
-
if (type.
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
471
|
+
if (type.flags & typescript.default.TypeFlags.Object && type.objectFlags & typescript.default.ObjectFlags.Reference) {
|
|
472
|
+
var _typeArgs$;
|
|
473
|
+
const typeArgs = this.checker.getTypeArguments(type);
|
|
474
|
+
if (typeArgs.length > 0 && ((_typeArgs$ = typeArgs[0]) === null || _typeArgs$ === void 0 || (_typeArgs$ = _typeArgs$.getSymbol()) === null || _typeArgs$ === void 0 ? void 0 : _typeArgs$.getName()) === "Array") {
|
|
475
|
+
const symbol = type.getSymbol();
|
|
476
|
+
if (symbol && symbol.getName() === "Array") {
|
|
477
|
+
const elementType = typeArgs[0];
|
|
478
|
+
return elementType ? this.isUtilityTypeFromType(elementType) : false;
|
|
479
|
+
}
|
|
480
|
+
const elementType = typeArgs[0];
|
|
481
|
+
return elementType ? this.isUtilityTypeFromType(elementType) : false;
|
|
423
482
|
}
|
|
424
|
-
const elementType = type.typeArguments[0];
|
|
425
|
-
return this.isUtilityTypeFromType(elementType);
|
|
426
483
|
}
|
|
427
484
|
if (type.flags & typescript.default.TypeFlags.TypeParameter) return true;
|
|
428
485
|
if (type.flags & typescript.default.TypeFlags.Conditional) return true;
|
|
@@ -454,13 +511,18 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
454
511
|
isSimpleArrayType(type) {
|
|
455
512
|
const symbol = type.getSymbol();
|
|
456
513
|
if (!symbol || symbol.getName() !== "Array") return false;
|
|
457
|
-
if (type.
|
|
458
|
-
const
|
|
459
|
-
if (
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
514
|
+
if (type.flags & typescript.default.TypeFlags.Object && type.objectFlags & typescript.default.ObjectFlags.Reference) {
|
|
515
|
+
const typeArgs = this.checker.getTypeArguments(type);
|
|
516
|
+
if (typeArgs.length === 1) {
|
|
517
|
+
const elementType = typeArgs[0];
|
|
518
|
+
if (this.isUtilityTypeFromType(elementType)) return false;
|
|
519
|
+
if (elementType.flags & typescript.default.TypeFlags.Object && elementType.objectFlags & typescript.default.ObjectFlags.Reference) {
|
|
520
|
+
if (this.checker.getTypeArguments(elementType).length > 0) return false;
|
|
521
|
+
}
|
|
522
|
+
const elementSymbol = elementType.getSymbol();
|
|
523
|
+
if (elementSymbol && elementSymbol.getName() !== "Array") return false;
|
|
524
|
+
return true;
|
|
525
|
+
}
|
|
464
526
|
}
|
|
465
527
|
return false;
|
|
466
528
|
}
|
|
@@ -518,23 +580,40 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
518
580
|
return matches[0];
|
|
519
581
|
}
|
|
520
582
|
findBestMatch(cls, matches) {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
583
|
+
const runtimeProps = this.extractRuntimePropertyNames(cls);
|
|
584
|
+
let bestMatch;
|
|
585
|
+
let bestScore = -1;
|
|
586
|
+
for (const match of matches) {
|
|
587
|
+
let score = 0;
|
|
588
|
+
for (const member of match.node.members) if (typescript.default.isPropertyDeclaration(member) && member.name && (typescript.default.isIdentifier(member.name) || typescript.default.isStringLiteral(member.name))) {
|
|
589
|
+
if (runtimeProps.has(member.name.text)) score++;
|
|
590
|
+
}
|
|
591
|
+
if (score > bestScore) {
|
|
592
|
+
bestScore = score;
|
|
593
|
+
bestMatch = match;
|
|
594
|
+
}
|
|
526
595
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
596
|
+
return bestMatch;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Safely extracts property names from a class constructor without instantiation.
|
|
600
|
+
* Parses the class source via Function.prototype.toString() and inspects
|
|
601
|
+
* the prototype for method names.
|
|
602
|
+
*/
|
|
603
|
+
extractRuntimePropertyNames(cls) {
|
|
604
|
+
const names = /* @__PURE__ */ new Set();
|
|
605
|
+
try {
|
|
606
|
+
const source = Function.prototype.toString.call(cls);
|
|
607
|
+
const thisAssign = /this\.(\w+)\s*=/g;
|
|
608
|
+
let m;
|
|
609
|
+
while ((m = thisAssign.exec(source)) !== null) if (m[1]) names.add(m[1]);
|
|
610
|
+
const classField = /[;}](\w+)(?=[=;}\s])/g;
|
|
611
|
+
while ((m = classField.exec(source)) !== null) if (m[1] && !constants.JS_KEYWORDS.has(m[1])) names.add(m[1]);
|
|
612
|
+
} catch {}
|
|
613
|
+
try {
|
|
614
|
+
for (const name of Object.getOwnPropertyNames(cls.prototype)) if (name !== "constructor") names.add(name);
|
|
615
|
+
} catch {}
|
|
616
|
+
return names;
|
|
538
617
|
}
|
|
539
618
|
getFilteredSourceFiles(sourceOptions) {
|
|
540
619
|
if (sourceOptions === null || sourceOptions === void 0 ? void 0 : sourceOptions.isExternal) return this.program.getSourceFiles().filter((sf) => {
|
|
@@ -549,77 +628,54 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
549
628
|
if (!propertyDeclaration.type) return false;
|
|
550
629
|
let typeNode = propertyDeclaration.type;
|
|
551
630
|
if (typescript.default.isArrayTypeNode(typeNode)) typeNode = typeNode.elementType;
|
|
552
|
-
if (typescript.default.
|
|
553
|
-
const
|
|
554
|
-
|
|
631
|
+
if (typescript.default.isUnionTypeNode(typeNode)) {
|
|
632
|
+
const nonNullTypes = typeNode.types.filter((t) => t.kind !== typescript.default.SyntaxKind.NullKeyword && t.kind !== typescript.default.SyntaxKind.UndefinedKeyword);
|
|
633
|
+
if (nonNullTypes.length === 1 && nonNullTypes[0]) typeNode = nonNullTypes[0];
|
|
555
634
|
}
|
|
635
|
+
if (typescript.default.isTypeReferenceNode(typeNode)) return !!(this.checker.getTypeAtLocation(typeNode).flags & typescript.default.TypeFlags.EnumLike);
|
|
556
636
|
return false;
|
|
557
637
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
const firstTypeArg = elementType.typeArguments[0];
|
|
568
|
-
if (firstTypeArg) {
|
|
569
|
-
const argSymbol = this.checker.getTypeAtLocation(firstTypeArg).getSymbol();
|
|
570
|
-
if (argSymbol && argSymbol.declarations) {
|
|
571
|
-
if (argSymbol.declarations.some((decl) => typescript.default.isClassDeclaration(decl))) return true;
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
const symbol = this.checker.getTypeAtLocation(elementType).getSymbol();
|
|
576
|
-
if (symbol && symbol.declarations) return symbol.declarations.some((decl) => typescript.default.isClassDeclaration(decl));
|
|
577
|
-
return false;
|
|
578
|
-
} else {
|
|
579
|
-
if (typescript.default.isTypeReferenceNode(propertyDeclaration.type) && propertyDeclaration.type.typeArguments && propertyDeclaration.type.typeArguments.length > 0) {
|
|
580
|
-
const firstTypeArg = propertyDeclaration.type.typeArguments[0];
|
|
581
|
-
if (firstTypeArg) {
|
|
582
|
-
const argSymbol = this.checker.getTypeAtLocation(firstTypeArg).getSymbol();
|
|
583
|
-
if (argSymbol && argSymbol.declarations) {
|
|
584
|
-
if (argSymbol.declarations.some((decl) => typescript.default.isClassDeclaration(decl))) return true;
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
const symbol = this.checker.getTypeAtLocation(propertyDeclaration.type).getSymbol();
|
|
589
|
-
if (symbol && symbol.declarations) return symbol.declarations.some((decl) => typescript.default.isClassDeclaration(decl));
|
|
590
|
-
return false;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
getDeclarationProperty(property) {
|
|
594
|
-
if (!property.originalProperty.type) return;
|
|
595
|
-
if (typescript.default.isArrayTypeNode(property.originalProperty.type)) {
|
|
596
|
-
const elementType = property.originalProperty.type.elementType;
|
|
597
|
-
if (typescript.default.isTypeReferenceNode(elementType) && elementType.typeArguments && elementType.typeArguments.length > 0) {
|
|
598
|
-
const firstTypeArg = elementType.typeArguments[0];
|
|
599
|
-
if (firstTypeArg) {
|
|
600
|
-
const argSymbol = this.checker.getTypeAtLocation(firstTypeArg).getSymbol();
|
|
601
|
-
if (argSymbol && argSymbol.declarations) {
|
|
602
|
-
const classDecl = argSymbol.declarations.find((decl) => typescript.default.isClassDeclaration(decl));
|
|
603
|
-
if (classDecl) return classDecl;
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
const symbol = this.checker.getTypeAtLocation(elementType).getSymbol();
|
|
608
|
-
if (symbol && symbol.declarations) return symbol.declarations.find((decl) => typescript.default.isClassDeclaration(decl)) || symbol.declarations[0];
|
|
609
|
-
return;
|
|
610
|
-
}
|
|
611
|
-
if (typescript.default.isTypeReferenceNode(property.originalProperty.type) && property.originalProperty.type.typeArguments && property.originalProperty.type.typeArguments.length > 0) {
|
|
612
|
-
const firstTypeArg = property.originalProperty.type.typeArguments[0];
|
|
638
|
+
/**
|
|
639
|
+
* Resolves a type node to its underlying symbol via the type-checker.
|
|
640
|
+
* For type references with type arguments (e.g., PayloadEntity<Person>),
|
|
641
|
+
* it checks the first type argument for a class declaration first.
|
|
642
|
+
* Returns the ts.Symbol or undefined.
|
|
643
|
+
*/
|
|
644
|
+
resolveClassSymbolFromTypeNode(typeNode) {
|
|
645
|
+
if (typescript.default.isTypeReferenceNode(typeNode) && typeNode.typeArguments && typeNode.typeArguments.length > 0) {
|
|
646
|
+
const firstTypeArg = typeNode.typeArguments[0];
|
|
613
647
|
if (firstTypeArg) {
|
|
614
648
|
const argSymbol = this.checker.getTypeAtLocation(firstTypeArg).getSymbol();
|
|
615
649
|
if (argSymbol && argSymbol.declarations) {
|
|
616
|
-
|
|
617
|
-
if (classDecl) return classDecl;
|
|
650
|
+
if (argSymbol.declarations.some((decl) => typescript.default.isClassDeclaration(decl))) return argSymbol;
|
|
618
651
|
}
|
|
619
652
|
}
|
|
620
653
|
}
|
|
621
|
-
|
|
622
|
-
|
|
654
|
+
return this.checker.getTypeAtLocation(typeNode).getSymbol() ?? void 0;
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Resolves the element type node from an array property declaration.
|
|
658
|
+
* Handles both `T[]` and `Array<T>` syntax.
|
|
659
|
+
*/
|
|
660
|
+
resolveArrayElementTypeNode(propertyDeclaration) {
|
|
661
|
+
var _propertyDeclaration$;
|
|
662
|
+
if (!propertyDeclaration.type) return void 0;
|
|
663
|
+
if (typescript.default.isArrayTypeNode(propertyDeclaration.type)) return propertyDeclaration.type.elementType;
|
|
664
|
+
if (typescript.default.isTypeReferenceNode(propertyDeclaration.type) && ((_propertyDeclaration$ = propertyDeclaration.type.typeArguments) === null || _propertyDeclaration$ === void 0 ? void 0 : _propertyDeclaration$[0])) return propertyDeclaration.type.typeArguments[0];
|
|
665
|
+
}
|
|
666
|
+
isClassType(propertyDeclaration) {
|
|
667
|
+
if (!propertyDeclaration.type) return false;
|
|
668
|
+
const typeNode = this.isArrayProperty(propertyDeclaration) ? this.resolveArrayElementTypeNode(propertyDeclaration) : propertyDeclaration.type;
|
|
669
|
+
if (!typeNode) return false;
|
|
670
|
+
const symbol = this.resolveClassSymbolFromTypeNode(typeNode);
|
|
671
|
+
if (symbol && symbol.declarations) return symbol.declarations.some((decl) => typescript.default.isClassDeclaration(decl));
|
|
672
|
+
return false;
|
|
673
|
+
}
|
|
674
|
+
getDeclarationProperty(property) {
|
|
675
|
+
if (!property.originalProperty.type) return;
|
|
676
|
+
const typeNode = typescript.default.isArrayTypeNode(property.originalProperty.type) ? property.originalProperty.type.elementType : property.originalProperty.type;
|
|
677
|
+
const symbol = this.resolveClassSymbolFromTypeNode(typeNode);
|
|
678
|
+
if (symbol && symbol.declarations) return symbol.declarations.find((decl) => typescript.default.isClassDeclaration(decl)) ?? symbol.declarations[0];
|
|
623
679
|
}
|
|
624
680
|
isArrayProperty(propertyDeclaration) {
|
|
625
681
|
if (!propertyDeclaration.type) return false;
|
|
@@ -666,16 +722,28 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
666
722
|
transformedSchema,
|
|
667
723
|
declaration: property.genericClassReference
|
|
668
724
|
});
|
|
669
|
-
else
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
725
|
+
else {
|
|
726
|
+
const inner = {
|
|
727
|
+
type: "object",
|
|
728
|
+
properties: {},
|
|
729
|
+
additionalProperties: true
|
|
730
|
+
};
|
|
731
|
+
schema = property.isArray ? {
|
|
732
|
+
type: "array",
|
|
733
|
+
items: inner
|
|
734
|
+
} : inner;
|
|
735
|
+
}
|
|
736
|
+
else {
|
|
737
|
+
const inner = {
|
|
738
|
+
type: "object",
|
|
739
|
+
properties: {},
|
|
740
|
+
additionalProperties: true
|
|
741
|
+
};
|
|
742
|
+
schema = property.isArray ? {
|
|
743
|
+
type: "array",
|
|
744
|
+
items: inner
|
|
745
|
+
} : inner;
|
|
746
|
+
}
|
|
679
747
|
this.applyDecorators(property, schema);
|
|
680
748
|
return schema;
|
|
681
749
|
}
|
|
@@ -771,7 +839,12 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
771
839
|
if (enumSchema) return enumSchema;
|
|
772
840
|
}
|
|
773
841
|
const propertySchema = { type: "object" };
|
|
774
|
-
|
|
842
|
+
let baseTypeNode = property.originalProperty.type;
|
|
843
|
+
if (property.isArray && baseTypeNode) baseTypeNode = this.resolveArrayElementTypeNode(property.originalProperty) ?? baseTypeNode;
|
|
844
|
+
const resolvedType = this.checker.getTypeAtLocation(baseTypeNode ?? property.originalProperty);
|
|
845
|
+
let propertyType;
|
|
846
|
+
if (resolvedType.flags & typescript.default.TypeFlags.TypeParameter) propertyType = property.type.toLowerCase().replace(/\[\]$/, "").trim();
|
|
847
|
+
else propertyType = this.checker.typeToString(resolvedType).toLowerCase();
|
|
775
848
|
let isFile = false;
|
|
776
849
|
switch (propertyType) {
|
|
777
850
|
case constants.jsPrimitives.String.value:
|
|
@@ -808,17 +881,26 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
808
881
|
propertySchema.type = constants.jsPrimitives.Symbol.value;
|
|
809
882
|
break;
|
|
810
883
|
case constants.jsPrimitives.Object.value:
|
|
884
|
+
case "unknown":
|
|
885
|
+
case "any":
|
|
811
886
|
propertySchema.type = constants.jsPrimitives.Object.value;
|
|
887
|
+
propertySchema.additionalProperties = true;
|
|
812
888
|
break;
|
|
813
889
|
default: propertySchema.type = constants.jsPrimitives.String.value;
|
|
814
890
|
}
|
|
815
891
|
if (property.isArray) {
|
|
816
892
|
delete propertySchema.format;
|
|
817
|
-
propertySchema.type
|
|
818
|
-
|
|
819
|
-
type: isFile ? constants.jsPrimitives.UploadFile.value :
|
|
893
|
+
const resolvedItemType = propertySchema.type;
|
|
894
|
+
const itemSchema = {
|
|
895
|
+
type: isFile ? constants.jsPrimitives.UploadFile.value : resolvedItemType,
|
|
820
896
|
format: isFile ? constants.jsPrimitives.UploadFile.format : propertySchema.format
|
|
821
897
|
};
|
|
898
|
+
if (propertySchema.additionalProperties) {
|
|
899
|
+
itemSchema.additionalProperties = true;
|
|
900
|
+
delete propertySchema.additionalProperties;
|
|
901
|
+
}
|
|
902
|
+
propertySchema.type = `array`;
|
|
903
|
+
propertySchema.items = itemSchema;
|
|
822
904
|
}
|
|
823
905
|
return propertySchema;
|
|
824
906
|
}
|
|
@@ -1016,21 +1098,24 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
1016
1098
|
const callee = node.expression;
|
|
1017
1099
|
if (typescript.default.isIdentifier(callee) && callee.text === "transform" || typescript.default.isPropertyAccessExpression(callee) && callee.name.text === "transform") {
|
|
1018
1100
|
const firstArg = node.arguments[0];
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
const
|
|
1022
|
-
if (
|
|
1101
|
+
if (typescript.default.isExpressionWithTypeArguments(firstArg) && firstArg.typeArguments && firstArg.typeArguments.length > 0) {
|
|
1102
|
+
const baseExpr = firstArg.expression;
|
|
1103
|
+
const className = typescript.default.isIdentifier(baseExpr) ? baseExpr.text : typescript.default.isPropertyAccessExpression(baseExpr) ? baseExpr.name.text : void 0;
|
|
1104
|
+
if (className) {
|
|
1023
1105
|
var _this$classFileIndex$;
|
|
1024
|
-
const classNode = (_this$classFileIndex$ = this.classFileIndex.get(
|
|
1106
|
+
const classNode = (_this$classFileIndex$ = this.classFileIndex.get(className)) === null || _this$classFileIndex$ === void 0 || (_this$classFileIndex$ = _this$classFileIndex$[0]) === null || _this$classFileIndex$ === void 0 ? void 0 : _this$classFileIndex$.node;
|
|
1025
1107
|
if (classNode === null || classNode === void 0 ? void 0 : classNode.typeParameters) {
|
|
1026
1108
|
const typeMap = /* @__PURE__ */ new Map();
|
|
1027
1109
|
classNode.typeParameters.forEach((param, i) => {
|
|
1028
|
-
const typeArg =
|
|
1110
|
+
const typeArg = firstArg.typeArguments[i];
|
|
1029
1111
|
if (typeArg) typeMap.set(param.name.text, this.getTypeNodeToString(typeArg, /* @__PURE__ */ new Map()));
|
|
1030
1112
|
});
|
|
1031
|
-
if (typeMap.size > 0) this.transformCallIndex.set(
|
|
1113
|
+
if (typeMap.size > 0) this.transformCallIndex.set(className, typeMap);
|
|
1032
1114
|
}
|
|
1033
1115
|
}
|
|
1116
|
+
} else {
|
|
1117
|
+
const className = typescript.default.isIdentifier(firstArg) ? firstArg.text : typescript.default.isPropertyAccessExpression(firstArg) ? firstArg.name.text : void 0;
|
|
1118
|
+
if (className) this.nonGenericTransformCalls.add(className);
|
|
1034
1119
|
}
|
|
1035
1120
|
}
|
|
1036
1121
|
}
|
|
@@ -1053,7 +1138,14 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
1053
1138
|
}
|
|
1054
1139
|
};
|
|
1055
1140
|
}
|
|
1056
|
-
const genericTypeMap =
|
|
1141
|
+
const genericTypeMap = /* @__PURE__ */ new Map();
|
|
1142
|
+
if (result.node.typeParameters) {
|
|
1143
|
+
const indexedTypeMap = this.transformCallIndex.get(cls.name);
|
|
1144
|
+
const hasNonGenericCall = this.nonGenericTransformCalls.has(cls.name);
|
|
1145
|
+
const allHaveDefaults = result.node.typeParameters.every((p) => !!p.default);
|
|
1146
|
+
if (indexedTypeMap && !(hasNonGenericCall && allHaveDefaults)) for (const [key, value] of indexedTypeMap) genericTypeMap.set(key, value);
|
|
1147
|
+
else for (const param of result.node.typeParameters) if (param.default) genericTypeMap.set(param.name.text, this.getTypeNodeToString(param.default, /* @__PURE__ */ new Map()));
|
|
1148
|
+
}
|
|
1057
1149
|
const hasGenericArgs = genericTypeMap.size > 0;
|
|
1058
1150
|
if (!hasGenericArgs && this.classCache.has(cls)) return this.classCache.get(cls);
|
|
1059
1151
|
let schema = {
|
package/dist/index.mjs
CHANGED
|
@@ -3,6 +3,53 @@ import path from "path";
|
|
|
3
3
|
//#region src/transformer.fixtures.ts
|
|
4
4
|
const constants = {
|
|
5
5
|
TS_CONFIG_DEFAULT_PATH: path.resolve(process.cwd(), "tsconfig.json"),
|
|
6
|
+
JS_KEYWORDS: new Set([
|
|
7
|
+
"constructor",
|
|
8
|
+
"static",
|
|
9
|
+
"get",
|
|
10
|
+
"set",
|
|
11
|
+
"async",
|
|
12
|
+
"return",
|
|
13
|
+
"if",
|
|
14
|
+
"else",
|
|
15
|
+
"for",
|
|
16
|
+
"while",
|
|
17
|
+
"switch",
|
|
18
|
+
"case",
|
|
19
|
+
"break",
|
|
20
|
+
"throw",
|
|
21
|
+
"new",
|
|
22
|
+
"delete",
|
|
23
|
+
"typeof",
|
|
24
|
+
"void",
|
|
25
|
+
"try",
|
|
26
|
+
"catch",
|
|
27
|
+
"finally",
|
|
28
|
+
"this",
|
|
29
|
+
"super",
|
|
30
|
+
"class",
|
|
31
|
+
"const",
|
|
32
|
+
"let",
|
|
33
|
+
"var",
|
|
34
|
+
"function",
|
|
35
|
+
"yield",
|
|
36
|
+
"await",
|
|
37
|
+
"import",
|
|
38
|
+
"export",
|
|
39
|
+
"default",
|
|
40
|
+
"extends",
|
|
41
|
+
"implements",
|
|
42
|
+
"in",
|
|
43
|
+
"of",
|
|
44
|
+
"do",
|
|
45
|
+
"with",
|
|
46
|
+
"continue",
|
|
47
|
+
"instanceof",
|
|
48
|
+
"true",
|
|
49
|
+
"false",
|
|
50
|
+
"null",
|
|
51
|
+
"undefined"
|
|
52
|
+
]),
|
|
6
53
|
jsPrimitives: {
|
|
7
54
|
String: {
|
|
8
55
|
type: "String",
|
|
@@ -165,6 +212,7 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
165
212
|
autoCleanup;
|
|
166
213
|
classFileIndex = /* @__PURE__ */ new Map();
|
|
167
214
|
transformCallIndex = /* @__PURE__ */ new Map();
|
|
215
|
+
nonGenericTransformCalls = /* @__PURE__ */ new Set();
|
|
168
216
|
constructor(tsConfigPath = constants.TS_CONFIG_DEFAULT_PATH, options = {}) {
|
|
169
217
|
this.maxCacheSize = options.maxCacheSize ?? 100;
|
|
170
218
|
this.autoCleanup = options.autoCleanup ?? true;
|
|
@@ -211,78 +259,77 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
211
259
|
}
|
|
212
260
|
getPropertiesByClassMembers(members, parentClassNode, genericTypeMap = /* @__PURE__ */ new Map()) {
|
|
213
261
|
const properties = [];
|
|
214
|
-
for (const member of members) {
|
|
215
|
-
var
|
|
216
|
-
if (
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if (
|
|
233
|
-
const
|
|
234
|
-
if (
|
|
235
|
-
const matches = this.classFileIndex.get(baseTypeName);
|
|
236
|
-
if (matches && matches.length > 0 && matches[0]) genericClassReference = matches[0].node;
|
|
237
|
-
}
|
|
262
|
+
for (const member of members) if (ts.isPropertyDeclaration(member) && (ts.isIdentifier(member.name) || ts.isStringLiteral(member.name))) {
|
|
263
|
+
var _property$originalPro;
|
|
264
|
+
if (member.modifiers) {
|
|
265
|
+
if (member.modifiers.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword || m.kind === ts.SyntaxKind.ProtectedKeyword)) continue;
|
|
266
|
+
}
|
|
267
|
+
const propertyName = member.name.text;
|
|
268
|
+
const type = this.getPropertyType(member, genericTypeMap);
|
|
269
|
+
const decorators = this.extractDecorators(member);
|
|
270
|
+
const isOptional = !!member.questionToken;
|
|
271
|
+
const isGeneric = this.isPropertyTypeGeneric(member);
|
|
272
|
+
const isEnum = this.isEnum(member);
|
|
273
|
+
const isPrimitive = this.isPrimitiveType(type) || isEnum;
|
|
274
|
+
const isClassType = this.isClassType(member);
|
|
275
|
+
const isArray = this.isArrayProperty(member);
|
|
276
|
+
const isTypeLiteral = this.isTypeLiteral(member);
|
|
277
|
+
let genericClassReference = void 0;
|
|
278
|
+
if (isGeneric && !isPrimitive) {
|
|
279
|
+
const baseTypeName = type.replace(/\[\]$/, "").trim();
|
|
280
|
+
if (!this.isPrimitiveType(baseTypeName)) {
|
|
281
|
+
const matches = this.classFileIndex.get(baseTypeName);
|
|
282
|
+
if (matches && matches.length > 0 && matches[0]) genericClassReference = matches[0].node;
|
|
238
283
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
284
|
+
}
|
|
285
|
+
const property = {
|
|
286
|
+
name: propertyName,
|
|
287
|
+
type,
|
|
288
|
+
decorators,
|
|
289
|
+
isOptional,
|
|
290
|
+
isGeneric,
|
|
291
|
+
originalProperty: member,
|
|
292
|
+
isPrimitive,
|
|
293
|
+
isClassType,
|
|
294
|
+
isArray,
|
|
295
|
+
isEnum,
|
|
296
|
+
isRef: false,
|
|
297
|
+
isTypeLiteral,
|
|
298
|
+
genericClassReference
|
|
299
|
+
};
|
|
300
|
+
if (property.isClassType) {
|
|
301
|
+
const declaration = this.getDeclarationProperty(property);
|
|
302
|
+
if (parentClassNode) {
|
|
303
|
+
if (declaration && declaration.name && this.checker.getSymbolAtLocation(declaration.name) === this.checker.getSymbolAtLocation(parentClassNode.name)) property.isRef = true;
|
|
259
304
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
305
|
+
}
|
|
306
|
+
if (property.isTypeLiteral && property.originalProperty.type !== void 0 && ts.isTypeReferenceNode(property.originalProperty.type) && ((_property$originalPro = property.originalProperty.type.typeArguments) === null || _property$originalPro === void 0 ? void 0 : _property$originalPro.length) === 1) {
|
|
307
|
+
const typeArguments = property.originalProperty.type.typeArguments;
|
|
308
|
+
if (typeArguments && typeArguments[0]) {
|
|
309
|
+
const firstTypeArg = typeArguments[0];
|
|
310
|
+
if (ts.isTypeReferenceNode(firstTypeArg)) {
|
|
311
|
+
const symbol = this.checker.getTypeAtLocation(firstTypeArg).getSymbol();
|
|
312
|
+
if (symbol && symbol.declarations) {
|
|
313
|
+
const classDeclaration = symbol.declarations.find((decl) => ts.isClassDeclaration(decl));
|
|
314
|
+
if (classDeclaration && ts.isClassDeclaration(classDeclaration)) property.typeLiteralClassReference = classDeclaration;
|
|
270
315
|
}
|
|
271
316
|
}
|
|
272
317
|
}
|
|
273
|
-
properties.push(property);
|
|
274
318
|
}
|
|
319
|
+
properties.push(property);
|
|
275
320
|
}
|
|
276
321
|
return properties;
|
|
277
322
|
}
|
|
278
323
|
getPropertyType(property, genericTypeMap = /* @__PURE__ */ new Map()) {
|
|
279
324
|
if (property.type) return this.getTypeNodeToString(property.type, genericTypeMap);
|
|
280
325
|
const type = this.checker.getTypeAtLocation(property);
|
|
281
|
-
return this.
|
|
326
|
+
return this.checker.typeToString(type);
|
|
282
327
|
}
|
|
283
328
|
getTypeNodeToString(typeNode, genericTypeMap = /* @__PURE__ */ new Map()) {
|
|
284
|
-
if (ts.isTypeReferenceNode(typeNode)
|
|
285
|
-
|
|
329
|
+
if (ts.isTypeReferenceNode(typeNode)) {
|
|
330
|
+
let typeName;
|
|
331
|
+
if (ts.isIdentifier(typeNode.typeName)) typeName = typeNode.typeName.text;
|
|
332
|
+
else typeName = typeNode.typeName.right.text;
|
|
286
333
|
if (genericTypeMap.has(typeName)) return genericTypeMap.get(typeName);
|
|
287
334
|
if (typeName.toLowerCase() === "uploadfile") return "UploadFile";
|
|
288
335
|
if (typeName.toLowerCase() === "uploadfiledto") return "UploadFileDto";
|
|
@@ -294,7 +341,7 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
294
341
|
}
|
|
295
342
|
return this.resolveGenericType(typeNode);
|
|
296
343
|
}
|
|
297
|
-
return
|
|
344
|
+
return typeName;
|
|
298
345
|
}
|
|
299
346
|
switch (typeNode.kind) {
|
|
300
347
|
case ts.SyntaxKind.StringKeyword: return constants.jsPrimitives.String.type;
|
|
@@ -309,31 +356,31 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
309
356
|
if (meaningfulTypes.length > 0 && meaningfulTypes[0]) return meaningfulTypes[0];
|
|
310
357
|
if (types.length > 0 && types[0]) return types[0];
|
|
311
358
|
return "object";
|
|
312
|
-
default:
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
if (
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
return typeText;
|
|
359
|
+
default: {
|
|
360
|
+
const resolvedType = this.checker.getTypeAtLocation(typeNode);
|
|
361
|
+
const resolved = this.checker.typeToString(resolvedType);
|
|
362
|
+
if (genericTypeMap && genericTypeMap.has(resolved)) return genericTypeMap.get(resolved);
|
|
363
|
+
if (this.isPrimitiveType(resolved)) return resolved;
|
|
364
|
+
if (resolved === "Date") return constants.jsPrimitives.Date.type;
|
|
365
|
+
if (resolved === "Buffer") return constants.jsPrimitives.Buffer.type;
|
|
366
|
+
if (resolved === "Uint8Array") return constants.jsPrimitives.Uint8Array.type;
|
|
367
|
+
return resolved;
|
|
368
|
+
}
|
|
323
369
|
}
|
|
324
370
|
}
|
|
325
371
|
resolveGenericType(typeNode) {
|
|
326
|
-
|
|
372
|
+
let typeName;
|
|
373
|
+
if (ts.isIdentifier(typeNode.typeName)) typeName = typeNode.typeName.text;
|
|
374
|
+
else typeName = typeNode.typeName.right.text;
|
|
327
375
|
const typeArguments = typeNode.typeArguments;
|
|
328
376
|
if (!typeArguments || typeArguments.length === 0) return typeName;
|
|
329
377
|
const type = this.checker.getTypeAtLocation(typeNode);
|
|
330
|
-
|
|
331
|
-
|
|
378
|
+
if (!(type.flags & ts.TypeFlags.Any)) {
|
|
379
|
+
const resolvedType = this.checker.typeToString(type);
|
|
380
|
+
if (resolvedType && resolvedType !== typeName) return resolvedType;
|
|
381
|
+
}
|
|
332
382
|
return typeName;
|
|
333
383
|
}
|
|
334
|
-
getStringFromType(type) {
|
|
335
|
-
return this.checker.typeToString(type);
|
|
336
|
-
}
|
|
337
384
|
extractDecorators(member) {
|
|
338
385
|
const decorators = [];
|
|
339
386
|
if (member.modifiers) {
|
|
@@ -353,6 +400,7 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
353
400
|
}
|
|
354
401
|
getDecoratorName(callExpression) {
|
|
355
402
|
if (ts.isIdentifier(callExpression.expression)) return callExpression.expression.text;
|
|
403
|
+
if (ts.isPropertyAccessExpression(callExpression.expression)) return callExpression.expression.name.text;
|
|
356
404
|
return "unknown";
|
|
357
405
|
}
|
|
358
406
|
getDecoratorArguments(callExpression) {
|
|
@@ -365,7 +413,13 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
365
413
|
});
|
|
366
414
|
}
|
|
367
415
|
getSafeDecoratorArgument(arg) {
|
|
368
|
-
if (arg && typeof arg === "object" && "kind" in arg)
|
|
416
|
+
if (arg && typeof arg === "object" && "kind" in arg) {
|
|
417
|
+
const node = arg;
|
|
418
|
+
const type = this.checker.getTypeAtLocation(node);
|
|
419
|
+
if (type.isNumberLiteral()) return type.value;
|
|
420
|
+
if (type.isStringLiteral()) return type.value;
|
|
421
|
+
return this.checker.typeToString(type);
|
|
422
|
+
}
|
|
369
423
|
return arg;
|
|
370
424
|
}
|
|
371
425
|
isPropertyTypeGeneric(property) {
|
|
@@ -389,15 +443,18 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
389
443
|
isGenericTypeFromSymbol(type) {
|
|
390
444
|
if (this.isSimpleArrayType(type)) return false;
|
|
391
445
|
if (type.aliasTypeArguments && type.aliasTypeArguments.length > 0) return true;
|
|
392
|
-
if (type.
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
446
|
+
if (type.flags & ts.TypeFlags.Object && type.objectFlags & ts.ObjectFlags.Reference) {
|
|
447
|
+
var _typeArgs$;
|
|
448
|
+
const typeArgs = this.checker.getTypeArguments(type);
|
|
449
|
+
if (typeArgs.length > 0 && ((_typeArgs$ = typeArgs[0]) === null || _typeArgs$ === void 0 || (_typeArgs$ = _typeArgs$.getSymbol()) === null || _typeArgs$ === void 0 ? void 0 : _typeArgs$.getName()) === "Array") {
|
|
450
|
+
const symbol = type.getSymbol();
|
|
451
|
+
if (symbol && symbol.getName() === "Array") {
|
|
452
|
+
const elementType = typeArgs[0];
|
|
453
|
+
return elementType ? this.isUtilityTypeFromType(elementType) : false;
|
|
454
|
+
}
|
|
455
|
+
const elementType = typeArgs[0];
|
|
456
|
+
return elementType ? this.isUtilityTypeFromType(elementType) : false;
|
|
398
457
|
}
|
|
399
|
-
const elementType = type.typeArguments[0];
|
|
400
|
-
return this.isUtilityTypeFromType(elementType);
|
|
401
458
|
}
|
|
402
459
|
if (type.flags & ts.TypeFlags.TypeParameter) return true;
|
|
403
460
|
if (type.flags & ts.TypeFlags.Conditional) return true;
|
|
@@ -429,13 +486,18 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
429
486
|
isSimpleArrayType(type) {
|
|
430
487
|
const symbol = type.getSymbol();
|
|
431
488
|
if (!symbol || symbol.getName() !== "Array") return false;
|
|
432
|
-
if (type.
|
|
433
|
-
const
|
|
434
|
-
if (
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
489
|
+
if (type.flags & ts.TypeFlags.Object && type.objectFlags & ts.ObjectFlags.Reference) {
|
|
490
|
+
const typeArgs = this.checker.getTypeArguments(type);
|
|
491
|
+
if (typeArgs.length === 1) {
|
|
492
|
+
const elementType = typeArgs[0];
|
|
493
|
+
if (this.isUtilityTypeFromType(elementType)) return false;
|
|
494
|
+
if (elementType.flags & ts.TypeFlags.Object && elementType.objectFlags & ts.ObjectFlags.Reference) {
|
|
495
|
+
if (this.checker.getTypeArguments(elementType).length > 0) return false;
|
|
496
|
+
}
|
|
497
|
+
const elementSymbol = elementType.getSymbol();
|
|
498
|
+
if (elementSymbol && elementSymbol.getName() !== "Array") return false;
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
439
501
|
}
|
|
440
502
|
return false;
|
|
441
503
|
}
|
|
@@ -493,23 +555,40 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
493
555
|
return matches[0];
|
|
494
556
|
}
|
|
495
557
|
findBestMatch(cls, matches) {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
558
|
+
const runtimeProps = this.extractRuntimePropertyNames(cls);
|
|
559
|
+
let bestMatch;
|
|
560
|
+
let bestScore = -1;
|
|
561
|
+
for (const match of matches) {
|
|
562
|
+
let score = 0;
|
|
563
|
+
for (const member of match.node.members) if (ts.isPropertyDeclaration(member) && member.name && (ts.isIdentifier(member.name) || ts.isStringLiteral(member.name))) {
|
|
564
|
+
if (runtimeProps.has(member.name.text)) score++;
|
|
565
|
+
}
|
|
566
|
+
if (score > bestScore) {
|
|
567
|
+
bestScore = score;
|
|
568
|
+
bestMatch = match;
|
|
569
|
+
}
|
|
501
570
|
}
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
571
|
+
return bestMatch;
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Safely extracts property names from a class constructor without instantiation.
|
|
575
|
+
* Parses the class source via Function.prototype.toString() and inspects
|
|
576
|
+
* the prototype for method names.
|
|
577
|
+
*/
|
|
578
|
+
extractRuntimePropertyNames(cls) {
|
|
579
|
+
const names = /* @__PURE__ */ new Set();
|
|
580
|
+
try {
|
|
581
|
+
const source = Function.prototype.toString.call(cls);
|
|
582
|
+
const thisAssign = /this\.(\w+)\s*=/g;
|
|
583
|
+
let m;
|
|
584
|
+
while ((m = thisAssign.exec(source)) !== null) if (m[1]) names.add(m[1]);
|
|
585
|
+
const classField = /[;}](\w+)(?=[=;}\s])/g;
|
|
586
|
+
while ((m = classField.exec(source)) !== null) if (m[1] && !constants.JS_KEYWORDS.has(m[1])) names.add(m[1]);
|
|
587
|
+
} catch {}
|
|
588
|
+
try {
|
|
589
|
+
for (const name of Object.getOwnPropertyNames(cls.prototype)) if (name !== "constructor") names.add(name);
|
|
590
|
+
} catch {}
|
|
591
|
+
return names;
|
|
513
592
|
}
|
|
514
593
|
getFilteredSourceFiles(sourceOptions) {
|
|
515
594
|
if (sourceOptions === null || sourceOptions === void 0 ? void 0 : sourceOptions.isExternal) return this.program.getSourceFiles().filter((sf) => {
|
|
@@ -524,77 +603,54 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
524
603
|
if (!propertyDeclaration.type) return false;
|
|
525
604
|
let typeNode = propertyDeclaration.type;
|
|
526
605
|
if (ts.isArrayTypeNode(typeNode)) typeNode = typeNode.elementType;
|
|
527
|
-
if (ts.
|
|
528
|
-
const
|
|
529
|
-
|
|
606
|
+
if (ts.isUnionTypeNode(typeNode)) {
|
|
607
|
+
const nonNullTypes = typeNode.types.filter((t) => t.kind !== ts.SyntaxKind.NullKeyword && t.kind !== ts.SyntaxKind.UndefinedKeyword);
|
|
608
|
+
if (nonNullTypes.length === 1 && nonNullTypes[0]) typeNode = nonNullTypes[0];
|
|
530
609
|
}
|
|
610
|
+
if (ts.isTypeReferenceNode(typeNode)) return !!(this.checker.getTypeAtLocation(typeNode).flags & ts.TypeFlags.EnumLike);
|
|
531
611
|
return false;
|
|
532
612
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
const firstTypeArg = elementType.typeArguments[0];
|
|
543
|
-
if (firstTypeArg) {
|
|
544
|
-
const argSymbol = this.checker.getTypeAtLocation(firstTypeArg).getSymbol();
|
|
545
|
-
if (argSymbol && argSymbol.declarations) {
|
|
546
|
-
if (argSymbol.declarations.some((decl) => ts.isClassDeclaration(decl))) return true;
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
const symbol = this.checker.getTypeAtLocation(elementType).getSymbol();
|
|
551
|
-
if (symbol && symbol.declarations) return symbol.declarations.some((decl) => ts.isClassDeclaration(decl));
|
|
552
|
-
return false;
|
|
553
|
-
} else {
|
|
554
|
-
if (ts.isTypeReferenceNode(propertyDeclaration.type) && propertyDeclaration.type.typeArguments && propertyDeclaration.type.typeArguments.length > 0) {
|
|
555
|
-
const firstTypeArg = propertyDeclaration.type.typeArguments[0];
|
|
556
|
-
if (firstTypeArg) {
|
|
557
|
-
const argSymbol = this.checker.getTypeAtLocation(firstTypeArg).getSymbol();
|
|
558
|
-
if (argSymbol && argSymbol.declarations) {
|
|
559
|
-
if (argSymbol.declarations.some((decl) => ts.isClassDeclaration(decl))) return true;
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
const symbol = this.checker.getTypeAtLocation(propertyDeclaration.type).getSymbol();
|
|
564
|
-
if (symbol && symbol.declarations) return symbol.declarations.some((decl) => ts.isClassDeclaration(decl));
|
|
565
|
-
return false;
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
getDeclarationProperty(property) {
|
|
569
|
-
if (!property.originalProperty.type) return;
|
|
570
|
-
if (ts.isArrayTypeNode(property.originalProperty.type)) {
|
|
571
|
-
const elementType = property.originalProperty.type.elementType;
|
|
572
|
-
if (ts.isTypeReferenceNode(elementType) && elementType.typeArguments && elementType.typeArguments.length > 0) {
|
|
573
|
-
const firstTypeArg = elementType.typeArguments[0];
|
|
574
|
-
if (firstTypeArg) {
|
|
575
|
-
const argSymbol = this.checker.getTypeAtLocation(firstTypeArg).getSymbol();
|
|
576
|
-
if (argSymbol && argSymbol.declarations) {
|
|
577
|
-
const classDecl = argSymbol.declarations.find((decl) => ts.isClassDeclaration(decl));
|
|
578
|
-
if (classDecl) return classDecl;
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
const symbol = this.checker.getTypeAtLocation(elementType).getSymbol();
|
|
583
|
-
if (symbol && symbol.declarations) return symbol.declarations.find((decl) => ts.isClassDeclaration(decl)) || symbol.declarations[0];
|
|
584
|
-
return;
|
|
585
|
-
}
|
|
586
|
-
if (ts.isTypeReferenceNode(property.originalProperty.type) && property.originalProperty.type.typeArguments && property.originalProperty.type.typeArguments.length > 0) {
|
|
587
|
-
const firstTypeArg = property.originalProperty.type.typeArguments[0];
|
|
613
|
+
/**
|
|
614
|
+
* Resolves a type node to its underlying symbol via the type-checker.
|
|
615
|
+
* For type references with type arguments (e.g., PayloadEntity<Person>),
|
|
616
|
+
* it checks the first type argument for a class declaration first.
|
|
617
|
+
* Returns the ts.Symbol or undefined.
|
|
618
|
+
*/
|
|
619
|
+
resolveClassSymbolFromTypeNode(typeNode) {
|
|
620
|
+
if (ts.isTypeReferenceNode(typeNode) && typeNode.typeArguments && typeNode.typeArguments.length > 0) {
|
|
621
|
+
const firstTypeArg = typeNode.typeArguments[0];
|
|
588
622
|
if (firstTypeArg) {
|
|
589
623
|
const argSymbol = this.checker.getTypeAtLocation(firstTypeArg).getSymbol();
|
|
590
624
|
if (argSymbol && argSymbol.declarations) {
|
|
591
|
-
|
|
592
|
-
if (classDecl) return classDecl;
|
|
625
|
+
if (argSymbol.declarations.some((decl) => ts.isClassDeclaration(decl))) return argSymbol;
|
|
593
626
|
}
|
|
594
627
|
}
|
|
595
628
|
}
|
|
596
|
-
|
|
597
|
-
|
|
629
|
+
return this.checker.getTypeAtLocation(typeNode).getSymbol() ?? void 0;
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Resolves the element type node from an array property declaration.
|
|
633
|
+
* Handles both `T[]` and `Array<T>` syntax.
|
|
634
|
+
*/
|
|
635
|
+
resolveArrayElementTypeNode(propertyDeclaration) {
|
|
636
|
+
var _propertyDeclaration$;
|
|
637
|
+
if (!propertyDeclaration.type) return void 0;
|
|
638
|
+
if (ts.isArrayTypeNode(propertyDeclaration.type)) return propertyDeclaration.type.elementType;
|
|
639
|
+
if (ts.isTypeReferenceNode(propertyDeclaration.type) && ((_propertyDeclaration$ = propertyDeclaration.type.typeArguments) === null || _propertyDeclaration$ === void 0 ? void 0 : _propertyDeclaration$[0])) return propertyDeclaration.type.typeArguments[0];
|
|
640
|
+
}
|
|
641
|
+
isClassType(propertyDeclaration) {
|
|
642
|
+
if (!propertyDeclaration.type) return false;
|
|
643
|
+
const typeNode = this.isArrayProperty(propertyDeclaration) ? this.resolveArrayElementTypeNode(propertyDeclaration) : propertyDeclaration.type;
|
|
644
|
+
if (!typeNode) return false;
|
|
645
|
+
const symbol = this.resolveClassSymbolFromTypeNode(typeNode);
|
|
646
|
+
if (symbol && symbol.declarations) return symbol.declarations.some((decl) => ts.isClassDeclaration(decl));
|
|
647
|
+
return false;
|
|
648
|
+
}
|
|
649
|
+
getDeclarationProperty(property) {
|
|
650
|
+
if (!property.originalProperty.type) return;
|
|
651
|
+
const typeNode = ts.isArrayTypeNode(property.originalProperty.type) ? property.originalProperty.type.elementType : property.originalProperty.type;
|
|
652
|
+
const symbol = this.resolveClassSymbolFromTypeNode(typeNode);
|
|
653
|
+
if (symbol && symbol.declarations) return symbol.declarations.find((decl) => ts.isClassDeclaration(decl)) ?? symbol.declarations[0];
|
|
598
654
|
}
|
|
599
655
|
isArrayProperty(propertyDeclaration) {
|
|
600
656
|
if (!propertyDeclaration.type) return false;
|
|
@@ -641,16 +697,28 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
641
697
|
transformedSchema,
|
|
642
698
|
declaration: property.genericClassReference
|
|
643
699
|
});
|
|
644
|
-
else
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
700
|
+
else {
|
|
701
|
+
const inner = {
|
|
702
|
+
type: "object",
|
|
703
|
+
properties: {},
|
|
704
|
+
additionalProperties: true
|
|
705
|
+
};
|
|
706
|
+
schema = property.isArray ? {
|
|
707
|
+
type: "array",
|
|
708
|
+
items: inner
|
|
709
|
+
} : inner;
|
|
710
|
+
}
|
|
711
|
+
else {
|
|
712
|
+
const inner = {
|
|
713
|
+
type: "object",
|
|
714
|
+
properties: {},
|
|
715
|
+
additionalProperties: true
|
|
716
|
+
};
|
|
717
|
+
schema = property.isArray ? {
|
|
718
|
+
type: "array",
|
|
719
|
+
items: inner
|
|
720
|
+
} : inner;
|
|
721
|
+
}
|
|
654
722
|
this.applyDecorators(property, schema);
|
|
655
723
|
return schema;
|
|
656
724
|
}
|
|
@@ -746,7 +814,12 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
746
814
|
if (enumSchema) return enumSchema;
|
|
747
815
|
}
|
|
748
816
|
const propertySchema = { type: "object" };
|
|
749
|
-
|
|
817
|
+
let baseTypeNode = property.originalProperty.type;
|
|
818
|
+
if (property.isArray && baseTypeNode) baseTypeNode = this.resolveArrayElementTypeNode(property.originalProperty) ?? baseTypeNode;
|
|
819
|
+
const resolvedType = this.checker.getTypeAtLocation(baseTypeNode ?? property.originalProperty);
|
|
820
|
+
let propertyType;
|
|
821
|
+
if (resolvedType.flags & ts.TypeFlags.TypeParameter) propertyType = property.type.toLowerCase().replace(/\[\]$/, "").trim();
|
|
822
|
+
else propertyType = this.checker.typeToString(resolvedType).toLowerCase();
|
|
750
823
|
let isFile = false;
|
|
751
824
|
switch (propertyType) {
|
|
752
825
|
case constants.jsPrimitives.String.value:
|
|
@@ -783,17 +856,26 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
783
856
|
propertySchema.type = constants.jsPrimitives.Symbol.value;
|
|
784
857
|
break;
|
|
785
858
|
case constants.jsPrimitives.Object.value:
|
|
859
|
+
case "unknown":
|
|
860
|
+
case "any":
|
|
786
861
|
propertySchema.type = constants.jsPrimitives.Object.value;
|
|
862
|
+
propertySchema.additionalProperties = true;
|
|
787
863
|
break;
|
|
788
864
|
default: propertySchema.type = constants.jsPrimitives.String.value;
|
|
789
865
|
}
|
|
790
866
|
if (property.isArray) {
|
|
791
867
|
delete propertySchema.format;
|
|
792
|
-
propertySchema.type
|
|
793
|
-
|
|
794
|
-
type: isFile ? constants.jsPrimitives.UploadFile.value :
|
|
868
|
+
const resolvedItemType = propertySchema.type;
|
|
869
|
+
const itemSchema = {
|
|
870
|
+
type: isFile ? constants.jsPrimitives.UploadFile.value : resolvedItemType,
|
|
795
871
|
format: isFile ? constants.jsPrimitives.UploadFile.format : propertySchema.format
|
|
796
872
|
};
|
|
873
|
+
if (propertySchema.additionalProperties) {
|
|
874
|
+
itemSchema.additionalProperties = true;
|
|
875
|
+
delete propertySchema.additionalProperties;
|
|
876
|
+
}
|
|
877
|
+
propertySchema.type = `array`;
|
|
878
|
+
propertySchema.items = itemSchema;
|
|
797
879
|
}
|
|
798
880
|
return propertySchema;
|
|
799
881
|
}
|
|
@@ -991,21 +1073,24 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
991
1073
|
const callee = node.expression;
|
|
992
1074
|
if (ts.isIdentifier(callee) && callee.text === "transform" || ts.isPropertyAccessExpression(callee) && callee.name.text === "transform") {
|
|
993
1075
|
const firstArg = node.arguments[0];
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
const
|
|
997
|
-
if (
|
|
1076
|
+
if (ts.isExpressionWithTypeArguments(firstArg) && firstArg.typeArguments && firstArg.typeArguments.length > 0) {
|
|
1077
|
+
const baseExpr = firstArg.expression;
|
|
1078
|
+
const className = ts.isIdentifier(baseExpr) ? baseExpr.text : ts.isPropertyAccessExpression(baseExpr) ? baseExpr.name.text : void 0;
|
|
1079
|
+
if (className) {
|
|
998
1080
|
var _this$classFileIndex$;
|
|
999
|
-
const classNode = (_this$classFileIndex$ = this.classFileIndex.get(
|
|
1081
|
+
const classNode = (_this$classFileIndex$ = this.classFileIndex.get(className)) === null || _this$classFileIndex$ === void 0 || (_this$classFileIndex$ = _this$classFileIndex$[0]) === null || _this$classFileIndex$ === void 0 ? void 0 : _this$classFileIndex$.node;
|
|
1000
1082
|
if (classNode === null || classNode === void 0 ? void 0 : classNode.typeParameters) {
|
|
1001
1083
|
const typeMap = /* @__PURE__ */ new Map();
|
|
1002
1084
|
classNode.typeParameters.forEach((param, i) => {
|
|
1003
|
-
const typeArg =
|
|
1085
|
+
const typeArg = firstArg.typeArguments[i];
|
|
1004
1086
|
if (typeArg) typeMap.set(param.name.text, this.getTypeNodeToString(typeArg, /* @__PURE__ */ new Map()));
|
|
1005
1087
|
});
|
|
1006
|
-
if (typeMap.size > 0) this.transformCallIndex.set(
|
|
1088
|
+
if (typeMap.size > 0) this.transformCallIndex.set(className, typeMap);
|
|
1007
1089
|
}
|
|
1008
1090
|
}
|
|
1091
|
+
} else {
|
|
1092
|
+
const className = ts.isIdentifier(firstArg) ? firstArg.text : ts.isPropertyAccessExpression(firstArg) ? firstArg.name.text : void 0;
|
|
1093
|
+
if (className) this.nonGenericTransformCalls.add(className);
|
|
1009
1094
|
}
|
|
1010
1095
|
}
|
|
1011
1096
|
}
|
|
@@ -1028,7 +1113,14 @@ var SchemaTransformer = class SchemaTransformer {
|
|
|
1028
1113
|
}
|
|
1029
1114
|
};
|
|
1030
1115
|
}
|
|
1031
|
-
const genericTypeMap =
|
|
1116
|
+
const genericTypeMap = /* @__PURE__ */ new Map();
|
|
1117
|
+
if (result.node.typeParameters) {
|
|
1118
|
+
const indexedTypeMap = this.transformCallIndex.get(cls.name);
|
|
1119
|
+
const hasNonGenericCall = this.nonGenericTransformCalls.has(cls.name);
|
|
1120
|
+
const allHaveDefaults = result.node.typeParameters.every((p) => !!p.default);
|
|
1121
|
+
if (indexedTypeMap && !(hasNonGenericCall && allHaveDefaults)) for (const [key, value] of indexedTypeMap) genericTypeMap.set(key, value);
|
|
1122
|
+
else for (const param of result.node.typeParameters) if (param.default) genericTypeMap.set(param.name.text, this.getTypeNodeToString(param.default, /* @__PURE__ */ new Map()));
|
|
1123
|
+
}
|
|
1032
1124
|
const hasGenericArgs = genericTypeMap.size > 0;
|
|
1033
1125
|
if (!hasGenericArgs && this.classCache.has(cls)) return this.classCache.get(cls);
|
|
1034
1126
|
let schema = {
|
package/package.json
CHANGED