adorn-api 1.0.8 → 1.0.10

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/cli.cjs CHANGED
@@ -154,6 +154,7 @@ function analyzeMethod(node, className, checker) {
154
154
  if (!signature) return null;
155
155
  let returnType = checker.getReturnTypeOfSignature(signature);
156
156
  returnType = unwrapPromise(returnType, checker);
157
+ const returnTypeNode = unwrapPromiseTypeNode(node.type);
157
158
  const parameters = [];
158
159
  for (let i = 0; i < node.parameters.length; i++) {
159
160
  const param = node.parameters[i];
@@ -178,6 +179,7 @@ function analyzeMethod(node, className, checker) {
178
179
  operationId: defaultOperationId(className, methodName),
179
180
  methodDeclaration: node,
180
181
  returnType,
182
+ returnTypeNode,
181
183
  parameters,
182
184
  pathParamIndices,
183
185
  bodyParamIndex,
@@ -308,6 +310,15 @@ function unwrapPromise(type, checker) {
308
310
  }
309
311
  return type;
310
312
  }
313
+ function unwrapPromiseTypeNode(typeNode) {
314
+ if (!typeNode) return void 0;
315
+ if (import_typescript2.default.isTypeReferenceNode(typeNode)) {
316
+ if (import_typescript2.default.isIdentifier(typeNode.typeName) && typeNode.typeName.text === "Promise") {
317
+ return typeNode.typeArguments?.[0] ?? typeNode;
318
+ }
319
+ }
320
+ return typeNode;
321
+ }
311
322
 
312
323
  // src/compiler/schema/openapi.ts
313
324
  var import_typescript6 = __toESM(require("typescript"), 1);
@@ -354,10 +365,10 @@ function typeToJsonSchema(type, ctx, typeNode) {
354
365
  return { type: "boolean", enum: [intrinsic === "true"] };
355
366
  }
356
367
  if (type.isUnion()) {
357
- return handleUnion(type.types, ctx, typeNode);
368
+ return handleUnion(type, ctx, typeNode);
358
369
  }
359
370
  if (type.isIntersection()) {
360
- return handleIntersection(type.types, ctx, typeNode);
371
+ return handleIntersection(type, ctx, typeNode);
361
372
  }
362
373
  if (checker.isArrayType(type)) {
363
374
  const typeArgs = type.typeArguments;
@@ -394,56 +405,96 @@ function isSetType(type, checker) {
394
405
  if (name === "Set") return true;
395
406
  return false;
396
407
  }
397
- function handleUnion(types, ctx, typeNode) {
398
- const nullType = types.find((t) => t.flags & import_typescript3.default.TypeFlags.Null);
399
- const otherTypes = types.filter((t) => !(t.flags & import_typescript3.default.TypeFlags.Null) && !(t.flags & import_typescript3.default.TypeFlags.Undefined));
400
- const allStringLiterals = otherTypes.every((t) => t.flags & import_typescript3.default.TypeFlags.StringLiteral);
401
- if (allStringLiterals && otherTypes.length > 0) {
402
- const enumValues = otherTypes.map((t) => t.value);
403
- const schema = { type: "string", enum: enumValues };
404
- if (nullType) {
405
- schema.type = ["string", "null"];
406
- }
407
- return schema;
408
+ function getSchemaName(type, typeNode) {
409
+ const aliasSymbol = type.aliasSymbol ?? type.aliasSymbol;
410
+ const aliasName = aliasSymbol?.getName();
411
+ if (aliasName && aliasName !== "__type") {
412
+ return aliasName;
408
413
  }
409
- if (otherTypes.length === 1 && nullType) {
410
- const innerSchema = typeToJsonSchema(otherTypes[0], ctx);
411
- if (typeof innerSchema.type === "string") {
412
- innerSchema.type = [innerSchema.type, "null"];
413
- }
414
- return innerSchema;
415
- }
416
- if (otherTypes.length > 1) {
417
- const branches = otherTypes.map((t) => typeToJsonSchema(t, ctx));
418
- const hasNull = !!nullType;
419
- const result = {};
420
- if (hasNull) {
421
- result.anyOf = [...branches, { type: "null" }];
422
- } else {
423
- result.anyOf = branches;
424
- }
425
- const discriminatorResult = detectDiscriminatedUnion(otherTypes, ctx, branches);
426
- if (discriminatorResult) {
427
- result.oneOf = branches;
428
- result.discriminator = discriminatorResult;
429
- }
430
- return result;
414
+ const symbol = type.getSymbol();
415
+ const symbolName = symbol?.getName?.();
416
+ if (symbolName && symbolName !== "__type") {
417
+ return symbolName;
431
418
  }
432
- if (otherTypes.length === 1) {
433
- return typeToJsonSchema(otherTypes[0], ctx);
419
+ const nodeName = getExplicitTypeNameFromNode(typeNode);
420
+ if (nodeName && nodeName !== "__type") {
421
+ return nodeName;
434
422
  }
435
- return {};
423
+ return null;
436
424
  }
437
- function handleIntersection(types, ctx, typeNode) {
438
- const brandCollapsed = tryCollapseBrandedIntersection(types, ctx, typeNode);
439
- if (brandCollapsed) {
440
- return brandCollapsed;
425
+ function buildNamedSchema(type, ctx, typeNode, build) {
426
+ const name = getSchemaName(type, typeNode);
427
+ if (!name) {
428
+ return build();
441
429
  }
442
- const allOf = [];
443
- for (const t of types) {
444
- allOf.push(typeToJsonSchema(t, ctx));
430
+ const { components, typeStack } = ctx;
431
+ if (components.has(name) || typeStack.has(type)) {
432
+ return { $ref: `#/components/schemas/${name}` };
445
433
  }
446
- return { allOf };
434
+ typeStack.add(type);
435
+ const schema = build();
436
+ typeStack.delete(type);
437
+ if (!components.has(name)) {
438
+ components.set(name, schema);
439
+ }
440
+ return { $ref: `#/components/schemas/${name}` };
441
+ }
442
+ function handleUnion(type, ctx, typeNode) {
443
+ return buildNamedSchema(type, ctx, typeNode, () => {
444
+ const types = type.types;
445
+ const nullType = types.find((t) => t.flags & import_typescript3.default.TypeFlags.Null);
446
+ const otherTypes = types.filter((t) => !(t.flags & import_typescript3.default.TypeFlags.Null) && !(t.flags & import_typescript3.default.TypeFlags.Undefined));
447
+ const allStringLiterals = otherTypes.every((t) => t.flags & import_typescript3.default.TypeFlags.StringLiteral);
448
+ if (allStringLiterals && otherTypes.length > 0) {
449
+ const enumValues = otherTypes.map((t) => t.value);
450
+ const schema = { type: "string", enum: enumValues };
451
+ if (nullType) {
452
+ schema.type = ["string", "null"];
453
+ }
454
+ return schema;
455
+ }
456
+ if (otherTypes.length === 1 && nullType) {
457
+ const innerSchema = typeToJsonSchema(otherTypes[0], ctx);
458
+ if (typeof innerSchema.type === "string") {
459
+ innerSchema.type = [innerSchema.type, "null"];
460
+ }
461
+ return innerSchema;
462
+ }
463
+ if (otherTypes.length > 1) {
464
+ const branches = otherTypes.map((t) => typeToJsonSchema(t, ctx));
465
+ const hasNull = !!nullType;
466
+ const result = {};
467
+ if (hasNull) {
468
+ result.anyOf = [...branches, { type: "null" }];
469
+ } else {
470
+ result.anyOf = branches;
471
+ }
472
+ const discriminatorResult = detectDiscriminatedUnion(otherTypes, ctx, branches);
473
+ if (discriminatorResult) {
474
+ result.oneOf = branches;
475
+ result.discriminator = discriminatorResult;
476
+ }
477
+ return result;
478
+ }
479
+ if (otherTypes.length === 1) {
480
+ return typeToJsonSchema(otherTypes[0], ctx);
481
+ }
482
+ return {};
483
+ });
484
+ }
485
+ function handleIntersection(type, ctx, typeNode) {
486
+ return buildNamedSchema(type, ctx, typeNode, () => {
487
+ const types = type.types;
488
+ const brandCollapsed = tryCollapseBrandedIntersection(types, ctx, typeNode);
489
+ if (brandCollapsed) {
490
+ return brandCollapsed;
491
+ }
492
+ const allOf = [];
493
+ for (const t of types) {
494
+ allOf.push(typeToJsonSchema(t, ctx));
495
+ }
496
+ return { allOf };
497
+ });
447
498
  }
448
499
  function tryCollapseBrandedIntersection(types, ctx, typeNode) {
449
500
  const { checker } = ctx;
@@ -574,8 +625,8 @@ function handleObjectType(type, ctx, typeNode) {
574
625
  typeStack.delete(type);
575
626
  return schema;
576
627
  }
577
- function getTypeNameFromNode(typeNode, ctx) {
578
- if (!typeNode) return `Anonymous_${ctx.typeNameStack.length}`;
628
+ function getExplicitTypeNameFromNode(typeNode) {
629
+ if (!typeNode) return null;
579
630
  if (import_typescript3.default.isTypeReferenceNode(typeNode)) {
580
631
  if (import_typescript3.default.isIdentifier(typeNode.typeName)) {
581
632
  return typeNode.typeName.text;
@@ -586,6 +637,11 @@ function getTypeNameFromNode(typeNode, ctx) {
586
637
  return typeNode.parent.name.text;
587
638
  }
588
639
  }
640
+ return null;
641
+ }
642
+ function getTypeNameFromNode(typeNode, ctx) {
643
+ const explicitName = getExplicitTypeNameFromNode(typeNode);
644
+ if (explicitName) return explicitName;
589
645
  return `Anonymous_${ctx.typeNameStack.length}`;
590
646
  }
591
647
  function buildObjectSchema(type, ctx, typeNode) {
@@ -884,7 +940,7 @@ function buildOperation(operation, ctx, controllerConsumes) {
884
940
  if (parameters.length > 0) {
885
941
  op.parameters = parameters;
886
942
  }
887
- const responseSchema = typeToJsonSchema(operation.returnType, ctx);
943
+ const responseSchema = typeToJsonSchema(operation.returnType, ctx, operation.returnTypeNode);
888
944
  const status = operation.httpMethod === "POST" ? 201 : 200;
889
945
  op.responses[status] = {
890
946
  description: status === 201 ? "Created" : "OK",
@@ -1121,7 +1177,7 @@ function buildOperationEntry(op, ctx) {
1121
1177
  };
1122
1178
  }
1123
1179
  }
1124
- const responseSchema = typeToJsonSchema(op.returnType, ctx);
1180
+ const responseSchema = typeToJsonSchema(op.returnType, ctx, op.returnTypeNode);
1125
1181
  const status = op.httpMethod === "POST" ? 201 : 200;
1126
1182
  let schemaRef = responseSchema.$ref;
1127
1183
  let isArray = false;