@kubb/plugin-ts 5.0.0-beta.77 → 5.0.0-beta.79

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.d.ts CHANGED
@@ -126,6 +126,11 @@ type PrinterTsOptions = {
126
126
  * Schema names that represent enums for suffixed key references.
127
127
  */
128
128
  enumSchemaNames?: Set<string>;
129
+ /**
130
+ * Maps a component `$ref` path to its collision-resolved name, so a reference to a renamed
131
+ * component (e.g. `#/components/schemas/Order` → `OrderSchema`) emits the renamed name.
132
+ */
133
+ nameMapping?: ReadonlyMap<string, string>;
129
134
  /**
130
135
  * Custom handler map for node type overrides.
131
136
  */
package/dist/index.js CHANGED
@@ -98,7 +98,7 @@ function toFilePath(name, caseLast = camelCase) {
98
98
  * JavaScript and Java reserved words.
99
99
  * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
100
100
  */
101
- const reservedWords = new Set([
101
+ const reservedWords = /* @__PURE__ */ new Set([
102
102
  "abstract",
103
103
  "arguments",
104
104
  "boolean",
@@ -220,19 +220,19 @@ function ensureValidVarName(name) {
220
220
  /**
221
221
  * `optionalType` values that cause a property's type to include `| undefined`.
222
222
  */
223
- const OPTIONAL_ADDS_UNDEFINED = new Set(["undefined", "questionTokenAndUndefined"]);
223
+ const OPTIONAL_ADDS_UNDEFINED = /* @__PURE__ */ new Set(["undefined", "questionTokenAndUndefined"]);
224
224
  /**
225
225
  * `optionalType` values that render the property key with a `?` token.
226
226
  */
227
- const OPTIONAL_ADDS_QUESTION_TOKEN = new Set(["questionToken", "questionTokenAndUndefined"]);
227
+ const OPTIONAL_ADDS_QUESTION_TOKEN = /* @__PURE__ */ new Set(["questionToken", "questionTokenAndUndefined"]);
228
228
  /**
229
229
  * `enum.type` values that append a `typeSuffix` to the generated enum type alias.
230
230
  */
231
- const ENUM_TYPES_WITH_KEY_SUFFIX = new Set(["asConst"]);
231
+ const ENUM_TYPES_WITH_KEY_SUFFIX = /* @__PURE__ */ new Set(["asConst"]);
232
232
  /**
233
233
  * `enum.type` values that require a runtime value declaration (object, enum, or literal).
234
234
  */
235
- const ENUM_TYPES_WITH_RUNTIME_VALUE = new Set([
235
+ const ENUM_TYPES_WITH_RUNTIME_VALUE = /* @__PURE__ */ new Set([
236
236
  "enum",
237
237
  "asConst",
238
238
  "constEnum",
@@ -242,7 +242,7 @@ const ENUM_TYPES_WITH_RUNTIME_VALUE = new Set([
242
242
  /**
243
243
  * `enum.type` values whose type declaration is type-only (no runtime value emitted for the type alias).
244
244
  */
245
- const ENUM_TYPES_WITH_TYPE_ONLY = new Set([
245
+ const ENUM_TYPES_WITH_TYPE_ONLY = /* @__PURE__ */ new Set([
246
246
  "asConst",
247
247
  "literal",
248
248
  void 0
@@ -800,7 +800,7 @@ function buildIndexSignatures(node, propertyCount, print) {
800
800
  * resolve to the same name, which TypeScript merges into a single value+type declaration.
801
801
  */
802
802
  function getEnumNames({ node, enum: enumOptions, resolver }) {
803
- const resolved = resolver.default(node.name, "type");
803
+ const resolved = resolver.resolveTypeName(node.name);
804
804
  return {
805
805
  enumName: enumOptions.constCasing === "pascalCase" ? resolved : camelCase(node.name),
806
806
  typeName: ENUM_TYPES_WITH_KEY_SUFFIX.has(enumOptions.type) ? resolver.resolveEnumKeyName(node, enumOptions.typeSuffix) : resolved
@@ -870,6 +870,23 @@ function caseParams(params, casing) {
870
870
  caseParamsCache.set(params, result);
871
871
  return result;
872
872
  }
873
+ /**
874
+ * Drops parameters that collapse to the same property identity once camelCased, keeping the first.
875
+ *
876
+ * Some specs declare the same parameter twice under different casings (for example AWS S3 lists both
877
+ * `max-uploads` and `MaxUploads`). Both resolve to one output property, so emitting both would yield
878
+ * an object type with a duplicate member, which TypeScript rejects. De-duplicate by the camelCased
879
+ * identity so the resulting group is collision-free regardless of the names each caller carries.
880
+ */
881
+ function dedupeByCasedName(params) {
882
+ const seen = /* @__PURE__ */ new Set();
883
+ return params.filter((param) => {
884
+ const key = camelCase(param.name);
885
+ if (seen.has(key)) return false;
886
+ seen.add(key);
887
+ return true;
888
+ });
889
+ }
873
890
  //#endregion
874
891
  //#region ../../internals/shared/src/operation.ts
875
892
  /**
@@ -923,10 +940,10 @@ function resolveContentTypeVariants(entries, baseName) {
923
940
  function getOperationParameters(node, options = {}) {
924
941
  const params = caseParams(node.parameters, options.paramsCasing === "original" ? void 0 : "camelcase");
925
942
  return {
926
- path: params.filter((param) => param.in === "path"),
927
- query: params.filter((param) => param.in === "query"),
928
- header: params.filter((param) => param.in === "header"),
929
- cookie: params.filter((param) => param.in === "cookie")
943
+ path: dedupeByCasedName(params.filter((param) => param.in === "path")),
944
+ query: dedupeByCasedName(params.filter((param) => param.in === "query")),
945
+ header: dedupeByCasedName(params.filter((param) => param.in === "header")),
946
+ cookie: dedupeByCasedName(params.filter((param) => param.in === "cookie"))
930
947
  };
931
948
  }
932
949
  //#endregion
@@ -1086,17 +1103,48 @@ function buildData(node, { resolver }) {
1086
1103
  ]
1087
1104
  });
1088
1105
  }
1106
+ /**
1107
+ * The schema a status occupies in the `<Name>Responses` record. A status that documents several
1108
+ * content types becomes a `{ contentType; data }` union so the runtime can surface the negotiated type
1109
+ * on `result.parsed`, while the standalone `<Name>StatusNNN` alias stays the plain body union that the
1110
+ * query hooks and `result.data` use.
1111
+ */
1112
+ function buildResponseRecordEntry(node, res, resolver) {
1113
+ const statusName = resolver.resolveResponseStatusName(node, res.statusCode);
1114
+ const variants = (res.content ?? []).filter((entry) => entry.schema);
1115
+ if (variants.length <= 1) return ast.factory.createSchema({
1116
+ type: "ref",
1117
+ name: statusName
1118
+ });
1119
+ return ast.factory.createSchema({
1120
+ type: "union",
1121
+ members: resolveContentTypeVariants(variants, statusName).map((variant) => ast.factory.createSchema({
1122
+ type: "object",
1123
+ properties: [ast.factory.createProperty({
1124
+ name: "contentType",
1125
+ required: true,
1126
+ schema: ast.factory.createSchema({
1127
+ type: "enum",
1128
+ enumValues: [variant.contentType]
1129
+ })
1130
+ }), ast.factory.createProperty({
1131
+ name: "data",
1132
+ required: true,
1133
+ schema: ast.factory.createSchema({
1134
+ type: "ref",
1135
+ name: variant.name
1136
+ })
1137
+ })]
1138
+ }))
1139
+ });
1140
+ }
1089
1141
  function buildResponses(node, { resolver }) {
1090
- if (node.responses.length === 0) return null;
1091
1142
  return ast.factory.createSchema({
1092
1143
  type: "object",
1093
1144
  properties: node.responses.map((res) => ast.factory.createProperty({
1094
1145
  name: String(res.statusCode),
1095
1146
  required: true,
1096
- schema: ast.factory.createSchema({
1097
- type: "ref",
1098
- name: resolver.resolveResponseStatusName(node, res.statusCode)
1099
- })
1147
+ schema: buildResponseRecordEntry(node, res, resolver)
1100
1148
  }))
1101
1149
  });
1102
1150
  }
@@ -1200,8 +1248,8 @@ const printerTs = ast.createPrinter((options) => {
1200
1248
  time: dateOrStringNode,
1201
1249
  ref(node) {
1202
1250
  if (!node.name) return null;
1203
- const refName = node.ref ? extractRefName(node.ref) ?? node.name : node.name;
1204
- return createTypeReferenceNode(node.ref && ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enum.type) && this.options.enum.typeSuffix && this.options.enumSchemaNames?.has(refName) ? this.options.resolver.resolveEnumKeyName({ name: refName }, this.options.enum.typeSuffix) : node.ref ? this.options.resolver.default(refName, "type") : refName, void 0);
1251
+ const refName = node.ref ? this.options.nameMapping?.get(node.ref) ?? extractRefName(node.ref) ?? node.name : node.name;
1252
+ return createTypeReferenceNode(node.ref && ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enum.type) && this.options.enum.typeSuffix && this.options.enumSchemaNames?.has(refName) ? this.options.resolver.resolveEnumKeyName({ name: refName }, this.options.enum.typeSuffix) : node.ref ? this.options.resolver.resolveTypeName(refName) : refName, void 0);
1205
1253
  },
1206
1254
  enum(node) {
1207
1255
  const values = node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? [];
@@ -1209,7 +1257,7 @@ const printerTs = ast.createPrinter((options) => {
1209
1257
  withParentheses: true,
1210
1258
  nodes: values.filter((v) => v !== null && v !== void 0).map((value) => constToTypeNode(value, typeof value)).filter(isNonNullable)
1211
1259
  }) ?? void 0;
1212
- return createTypeReferenceNode(ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enum.type) && this.options.enum.typeSuffix ? this.options.resolver.resolveEnumKeyName(node, this.options.enum.typeSuffix) : this.options.resolver.default(node.name, "type"), void 0);
1260
+ return createTypeReferenceNode(ENUM_TYPES_WITH_KEY_SUFFIX.has(this.options.enum.type) && this.options.enum.typeSuffix ? this.options.resolver.resolveEnumKeyName(node, this.options.enum.typeSuffix) : this.options.resolver.resolveTypeName(node.name), void 0);
1213
1261
  },
1214
1262
  union(node) {
1215
1263
  const members = node.members ?? [];
@@ -1357,6 +1405,7 @@ const typeGenerator = defineGenerator({
1357
1405
  description: node.description,
1358
1406
  resolver,
1359
1407
  enumSchemaNames,
1408
+ nameMapping: adapter.options.nameMapping,
1360
1409
  nodes: printer?.nodes
1361
1410
  });
1362
1411
  return /* @__PURE__ */ jsxs(File, {
@@ -1439,6 +1488,7 @@ const typeGenerator = defineGenerator({
1439
1488
  keysToOmit,
1440
1489
  resolver,
1441
1490
  enumSchemaNames,
1491
+ nameMapping: adapter.options.nameMapping,
1442
1492
  nodes: printer?.nodes
1443
1493
  });
1444
1494
  return /* @__PURE__ */ jsxs(Fragment, { children: [imports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
@@ -1459,8 +1509,10 @@ const typeGenerator = defineGenerator({
1459
1509
  })] });
1460
1510
  }
1461
1511
  /**
1462
- * Emits an individual type per content type plus a union alias under `baseName`.
1463
- * Shared by the request body and multi-content-type responses.
1512
+ * Emits an individual type per content type plus a plain union alias under `baseName`. Shared by
1513
+ * the request body and multi-content-type responses. The response record discriminates these
1514
+ * variants by content type in {@link buildResponses}; the standalone alias stays a plain union so
1515
+ * query hooks and `result.data` keep the bare body.
1464
1516
  */
1465
1517
  function buildContentTypeVariants(entries, baseName, decorate) {
1466
1518
  const variants = resolveContentTypeVariants(entries, baseName);