@kubb/plugin-ts 5.0.0-beta.56 → 5.0.0-beta.73

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 CHANGED
@@ -13,6 +13,15 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
13
  var __getOwnPropNames = Object.getOwnPropertyNames;
14
14
  var __getProtoOf = Object.getPrototypeOf;
15
15
  var __hasOwnProp = Object.prototype.hasOwnProperty;
16
+ var __exportAll = (all, no_symbols) => {
17
+ let target = {};
18
+ for (var name in all) __defProp(target, name, {
19
+ get: all[name],
20
+ enumerable: true
21
+ });
22
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
23
+ return target;
24
+ };
16
25
  var __copyProps = (to, from, except, desc) => {
17
26
  if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
18
27
  key = keys[i];
@@ -31,10 +40,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
40
  let _kubb_ast_utils = require("@kubb/ast/utils");
32
41
  let _kubb_parser_ts = require("@kubb/parser-ts");
33
42
  let _kubb_renderer_jsx = require("@kubb/renderer-jsx");
34
- let _kubb_core = require("@kubb/core");
35
43
  let typescript = require("typescript");
36
44
  typescript = __toESM(typescript, 1);
37
45
  let _kubb_renderer_jsx_jsx_runtime = require("@kubb/renderer-jsx/jsx-runtime");
46
+ let _kubb_core = require("@kubb/core");
38
47
  //#region ../../internals/utils/src/casing.ts
39
48
  /**
40
49
  * Shared implementation for camelCase and PascalCase conversion.
@@ -288,7 +297,59 @@ const PARAM_RANK = {
288
297
  };
289
298
  //#endregion
290
299
  //#region src/factory.ts
300
+ var factory_exports = /* @__PURE__ */ __exportAll({
301
+ SyntaxKind: () => SyntaxKind,
302
+ appendJSDocToNode: () => appendJSDocToNode,
303
+ buildIndexSignatures: () => buildIndexSignatures,
304
+ buildMemberNodes: () => buildMemberNodes,
305
+ buildPropertyType: () => buildPropertyType,
306
+ buildTupleNode: () => buildTupleNode,
307
+ constToTypeNode: () => constToTypeNode,
308
+ createArrayDeclaration: () => createArrayDeclaration,
309
+ createArrayTypeNode: () => createArrayTypeNode,
310
+ createEnumDeclaration: () => createEnumDeclaration,
311
+ createExportDeclaration: () => createExportDeclaration,
312
+ createFalse: () => createFalse,
313
+ createIdentifier: () => createIdentifier,
314
+ createImportDeclaration: () => createImportDeclaration,
315
+ createIndexSignature: () => createIndexSignature,
316
+ createInterfaceDeclaration: () => createInterfaceDeclaration,
317
+ createIntersectionDeclaration: () => createIntersectionDeclaration,
318
+ createJSDoc: () => createJSDoc,
319
+ createLiteralTypeNode: () => createLiteralTypeNode,
320
+ createNumericLiteral: () => createNumericLiteral,
321
+ createOmitDeclaration: () => createOmitDeclaration,
322
+ createOptionalTypeNode: () => createOptionalTypeNode,
323
+ createParameterSignature: () => createParameterSignature,
324
+ createPrefixUnaryExpression: () => createPrefixUnaryExpression,
325
+ createPropertySignature: () => createPropertySignature,
326
+ createQuestionToken: () => createQuestionToken,
327
+ createRestTypeNode: () => createRestTypeNode,
328
+ createStringLiteral: () => createStringLiteral,
329
+ createTrue: () => createTrue,
330
+ createTupleTypeNode: () => createTupleTypeNode,
331
+ createTypeAliasDeclaration: () => createTypeAliasDeclaration,
332
+ createTypeDeclaration: () => createTypeDeclaration,
333
+ createTypeLiteralNode: () => createTypeLiteralNode,
334
+ createTypeReferenceNode: () => createTypeReferenceNode,
335
+ createUnionDeclaration: () => createUnionDeclaration,
336
+ createUrlTemplateType: () => createUrlTemplateType,
337
+ dateOrStringNode: () => dateOrStringNode,
338
+ isNonNullable: () => isNonNullable$1,
339
+ keywordTypeNodes: () => keywordTypeNodes,
340
+ modifiers: () => modifiers,
341
+ syntaxKind: () => syntaxKind
342
+ });
291
343
  const { SyntaxKind, factory } = typescript.default;
344
+ /**
345
+ * Compares two strings by UTF-16 code unit, keeping sorted output identical across platforms
346
+ * regardless of locale.
347
+ */
348
+ function compareStrings(a, b) {
349
+ if (a < b) return -1;
350
+ if (a > b) return 1;
351
+ return 0;
352
+ }
292
353
  function isNumber(value) {
293
354
  return typeof value === "number" && !Number.isNaN(value);
294
355
  }
@@ -396,6 +457,17 @@ function createParameterSignature(name, { modifiers, dotDotDotToken, questionTok
396
457
  return factory.createParameterDeclaration(modifiers, dotDotDotToken, name, createQuestionToken(questionToken), type, initializer);
397
458
  }
398
459
  /**
460
+ * Creates a JSDoc comment node from an array of comment strings.
461
+ * Returns null if no comments are provided.
462
+ */
463
+ function createJSDoc({ comments }) {
464
+ if (!comments.length) return null;
465
+ return factory.createJSDocComment(factory.createNodeArray(comments.map((comment, i) => {
466
+ if (i === comments.length - 1) return factory.createJSDocText(comment);
467
+ return factory.createJSDocText(`${comment}\n`);
468
+ })));
469
+ }
470
+ /**
399
471
  * Attaches JSDoc comments to an AST node as synthetic leading comments.
400
472
  * Filters out undefined comments before attaching.
401
473
  *
@@ -453,6 +525,50 @@ function createTypeDeclaration({ syntax, isExportable, comments, name, type }) {
453
525
  });
454
526
  }
455
527
  /**
528
+ * Creates an import declaration with support for default imports, named imports, namespace imports, and type-only imports.
529
+ * Optionally rename imported members with `propertyName` and `name` pairs.
530
+ *
531
+ * @example Default import
532
+ * `import Pet from './Pet'`
533
+ *
534
+ * @example Named imports with rename
535
+ * `import { Pet as Cat } from './Pet'`
536
+ *
537
+ * @example Namespace import
538
+ * `import * as Pet from './Pet'`
539
+ */
540
+ function createImportDeclaration({ name, path, isTypeOnly = false, isNameSpace = false }) {
541
+ if (!Array.isArray(name)) {
542
+ const importPropertyName = isNameSpace ? void 0 : factory.createIdentifier(name);
543
+ const importName = isNameSpace ? factory.createNamespaceImport(factory.createIdentifier(name)) : void 0;
544
+ return factory.createImportDeclaration(void 0, factory.createImportClause(isTypeOnly, importPropertyName, importName), factory.createStringLiteral(path), void 0);
545
+ }
546
+ const sortedName = name.toSorted((a, b) => compareStrings(typeof a === "object" ? a.propertyName : a, typeof b === "object" ? b.propertyName : b));
547
+ return factory.createImportDeclaration(void 0, factory.createImportClause(isTypeOnly, void 0, factory.createNamedImports(sortedName.map((item) => {
548
+ if (typeof item === "object") {
549
+ const obj = item;
550
+ if (obj.name) return factory.createImportSpecifier(false, factory.createIdentifier(obj.propertyName), factory.createIdentifier(obj.name));
551
+ return factory.createImportSpecifier(false, void 0, factory.createIdentifier(obj.propertyName));
552
+ }
553
+ return factory.createImportSpecifier(false, void 0, factory.createIdentifier(item));
554
+ }))), factory.createStringLiteral(path), void 0);
555
+ }
556
+ /**
557
+ * Creates an export declaration with support for named exports, namespace exports, and type-only exports.
558
+ * Sorts export names alphabetically for consistent output across platforms.
559
+ */
560
+ function createExportDeclaration({ path, asAlias, isTypeOnly = false, name }) {
561
+ if (name && !Array.isArray(name) && !asAlias) console.warn(`When using name as string, asAlias should be true ${name}`);
562
+ if (!Array.isArray(name)) {
563
+ const parsedName = name?.match(/^\d/) ? `_${name?.slice(1)}` : name;
564
+ return factory.createExportDeclaration(void 0, isTypeOnly, asAlias && parsedName ? factory.createNamespaceExport(factory.createIdentifier(parsedName)) : void 0, factory.createStringLiteral(path), void 0);
565
+ }
566
+ const sortedName = name.toSorted((a, b) => compareStrings(typeof a === "string" ? a : a.text, typeof b === "string" ? b : b.text));
567
+ return factory.createExportDeclaration(void 0, isTypeOnly, factory.createNamedExports(sortedName.map((propertyName) => {
568
+ return factory.createExportSpecifier(false, void 0, typeof propertyName === "string" ? factory.createIdentifier(propertyName) : propertyName);
569
+ })), factory.createStringLiteral(path), void 0);
570
+ }
571
+ /**
456
572
  * Apply casing transformation to enum keys
457
573
  */
458
574
  function applyEnumKeyCasing(key, casing = "none") {
@@ -484,7 +600,7 @@ function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCa
484
600
  return factory.createLiteralTypeNode(factory.createNumericLiteral(value?.toString()));
485
601
  }
486
602
  if (typeof value === "boolean") return factory.createLiteralTypeNode(value ? factory.createTrue() : factory.createFalse());
487
- if (value) return factory.createLiteralTypeNode(factory.createStringLiteral(value.toString()));
603
+ if (value !== null && value !== void 0) return factory.createLiteralTypeNode(factory.createStringLiteral(value.toString()));
488
604
  }).filter((node) => node !== void 0)))];
489
605
  if (type === "enum" || type === "constEnum") return [void 0, factory.createEnumDeclaration([factory.createToken(typescript.default.SyntaxKind.ExportKeyword), type === "constEnum" ? factory.createToken(typescript.default.SyntaxKind.ConstKeyword) : void 0].filter((modifier) => modifier !== void 0), factory.createIdentifier(typeName), enums.map(([key, value]) => {
490
606
  let initializer = factory.createStringLiteral(value?.toString());
@@ -495,7 +611,7 @@ function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCa
495
611
  const casingKey = applyEnumKeyCasing(`${typeName}_${key}`, enumKeyCasing);
496
612
  return factory.createEnumMember(propertyName(casingKey), initializer);
497
613
  }
498
- if (key) {
614
+ if (key !== null && key !== void 0) {
499
615
  const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
500
616
  return factory.createEnumMember(propertyName(casingKey), initializer);
501
617
  }
@@ -507,7 +623,7 @@ function createEnumDeclaration({ type = "enum", name, typeName, enums, enumKeyCa
507
623
  if (isNumber(value)) if (value < 0) initializer = factory.createPrefixUnaryExpression(typescript.default.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value)));
508
624
  else initializer = factory.createNumericLiteral(value);
509
625
  if (typeof value === "boolean") initializer = value ? factory.createTrue() : factory.createFalse();
510
- if (key) {
626
+ if (key !== null && key !== void 0) {
511
627
  const casingKey = applyEnumKeyCasing(key.toString(), enumKeyCasing);
512
628
  return factory.createPropertyAssignment(propertyName(casingKey), initializer);
513
629
  }
@@ -668,12 +784,12 @@ function buildTupleNode(node, print) {
668
784
  /**
669
785
  * Applies `nullable` and optional/nullish `| undefined` union modifiers to a property's resolved base type.
670
786
  */
671
- function buildPropertyType(schema, baseType, optionalType) {
787
+ function buildPropertyType(schema, baseType, optionalType, optional) {
672
788
  const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(optionalType);
673
- const meta = _kubb_core.ast.syncSchemaRef(schema);
789
+ const meta = (0, _kubb_ast_utils.syncSchemaRef)(schema);
674
790
  let type = baseType;
675
791
  if (meta.nullable) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.null] });
676
- if ((meta.nullish || meta.optional) && addsUndefined) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
792
+ if ((optional || meta.nullish || meta.optional) && addsUndefined) type = createUnionDeclaration({ nodes: [type, keywordTypeNodes.undefined] });
677
793
  return type;
678
794
  }
679
795
  /**
@@ -787,6 +903,27 @@ function Type({ name, node, printer, enum: enumOptions, resolver }) {
787
903
  })] });
788
904
  }
789
905
  //#endregion
906
+ //#region ../../internals/shared/src/params.ts
907
+ const caseParamsCache = /* @__PURE__ */ new WeakMap();
908
+ /**
909
+ * Applies camelCase to parameter names and returns a new array without mutating the input.
910
+ *
911
+ * Run it before handing parameters to schema builders so output property keys get the right casing
912
+ * while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the
913
+ * original array is returned unchanged. Results are cached per input array.
914
+ */
915
+ function caseParams(params, casing) {
916
+ if (!casing) return params;
917
+ const cached = caseParamsCache.get(params);
918
+ if (cached) return cached;
919
+ const result = params.map((param) => ({
920
+ ...param,
921
+ name: camelCase(param.name)
922
+ }));
923
+ caseParamsCache.set(params, result);
924
+ return result;
925
+ }
926
+ //#endregion
790
927
  //#region ../../internals/shared/src/operation.ts
791
928
  /**
792
929
  * Maps a content type to the PascalCase suffix used to name per-content-type variants
@@ -837,7 +974,7 @@ function resolveContentTypeVariants(entries, baseName) {
837
974
  });
838
975
  }
839
976
  function getOperationParameters(node, options = {}) {
840
- const params = _kubb_core.ast.caseParams(node.parameters, options.paramsCasing);
977
+ const params = caseParams(node.parameters, options.paramsCasing === "original" ? void 0 : "camelcase");
841
978
  return {
842
979
  path: params.filter((param) => param.in === "path"),
843
980
  query: params.filter((param) => param.in === "query"),
@@ -885,11 +1022,15 @@ function createGroupConfig(group) {
885
1022
  * Constraint metadata (min/max length, pattern, multipleOf, min/maxProperties) is emitted as plain-text lines.
886
1023
 
887
1024
  */
888
- function buildPropertyJSDocComments(schema) {
889
- const meta = _kubb_core.ast.syncSchemaRef(schema);
1025
+ function isSchemaOptional(schema) {
1026
+ return Boolean("optional" in schema && schema.optional || "nullish" in schema && schema.nullish);
1027
+ }
1028
+ function buildPropertyJSDocComments(schema, optional) {
1029
+ const meta = (0, _kubb_ast_utils.syncSchemaRef)(schema);
890
1030
  const isArray = meta?.primitive === "array";
891
1031
  const hasDescription = meta && "description" in meta && meta.description;
892
1032
  const formatComment = meta && "format" in meta && meta.format ? hasDescription ? [" ", `Format: \`${meta.format}\``] : ["@description", `Format: \`${meta.format}\``] : [];
1033
+ const exampleValues = meta?.examples ?? [];
893
1034
  return [
894
1035
  hasDescription ? `@description ${(0, _kubb_ast_utils.jsStringEscape)(meta.description)}` : null,
895
1036
  ...formatComment,
@@ -898,99 +1039,102 @@ function buildPropertyJSDocComments(schema) {
898
1039
  !isArray && meta && "max" in meta && meta.max !== void 0 ? `@maxLength ${meta.max}` : null,
899
1040
  meta && "pattern" in meta && meta.pattern ? `@pattern ${meta.pattern}` : null,
900
1041
  meta && "default" in meta && meta.default !== void 0 ? `@default ${"primitive" in meta && meta.primitive === "string" ? (0, _kubb_ast_utils.stringify)(meta.default) : meta.default}` : null,
901
- meta && "example" in meta && meta.example !== void 0 ? `@example ${meta.example}` : null,
902
- meta && "primitive" in meta && meta.primitive ? [`@type ${meta.primitive}`, "optional" in schema && schema.optional ? " | undefined" : null].filter(Boolean).join("") : null
1042
+ ...exampleValues.map((example) => `@example ${example}`),
1043
+ meta && "primitive" in meta && meta.primitive ? [`@type ${meta.primitive}`, optional ?? isSchemaOptional(schema) ? " | undefined" : null].filter(Boolean).join("") : null
903
1044
  ].filter(Boolean);
904
1045
  }
905
1046
  function buildParams(node, { params, resolver }) {
906
- return _kubb_core.ast.createSchema({
1047
+ return _kubb_core.ast.factory.createSchema({
907
1048
  type: "object",
908
- properties: params.map((param) => _kubb_core.ast.createProperty({
1049
+ properties: params.map((param) => _kubb_core.ast.factory.createProperty({
909
1050
  name: param.name,
910
1051
  required: param.required,
911
- schema: _kubb_core.ast.createSchema({
1052
+ schema: _kubb_core.ast.factory.createSchema({
912
1053
  type: "ref",
913
- name: resolver.resolveParamName(node, param)
1054
+ name: resolver.resolveParamName(node, param),
1055
+ optional: !param.required
914
1056
  })
915
1057
  }))
916
1058
  });
917
1059
  }
918
1060
  function buildData(node, { resolver }) {
919
- const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node);
920
- return _kubb_core.ast.createSchema({
1061
+ const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node, { paramsCasing: "original" });
1062
+ const hasBody = Boolean(node.requestBody?.content?.[0]?.schema);
1063
+ const hasRequiredPath = pathParams.some((param) => param.required);
1064
+ const hasRequiredQuery = queryParams.some((param) => param.required);
1065
+ const hasRequiredHeader = headerParams.some((param) => param.required);
1066
+ return _kubb_core.ast.factory.createSchema({
921
1067
  type: "object",
922
1068
  deprecated: node.deprecated,
923
1069
  properties: [
924
- _kubb_core.ast.createProperty({
925
- name: "data",
926
- schema: node.requestBody?.content?.[0]?.schema ? _kubb_core.ast.createSchema({
1070
+ _kubb_core.ast.factory.createProperty({
1071
+ name: "body",
1072
+ required: hasBody,
1073
+ schema: hasBody ? _kubb_core.ast.factory.createSchema({
927
1074
  type: "ref",
928
- name: resolver.resolveDataName(node),
929
- optional: true
930
- }) : _kubb_core.ast.createSchema({
1075
+ name: resolver.resolveDataName(node)
1076
+ }) : _kubb_core.ast.factory.createSchema({
931
1077
  type: "never",
932
1078
  primitive: void 0,
933
1079
  optional: true
934
1080
  })
935
1081
  }),
936
- _kubb_core.ast.createProperty({
937
- name: "pathParams",
938
- required: pathParams.length > 0,
939
- schema: pathParams.length > 0 ? buildParams(node, {
940
- params: pathParams,
941
- resolver
942
- }) : _kubb_core.ast.createSchema({
1082
+ _kubb_core.ast.factory.createProperty({
1083
+ name: "path",
1084
+ required: hasRequiredPath,
1085
+ schema: pathParams.length > 0 ? _kubb_core.ast.factory.createSchema({
1086
+ ...buildParams(node, {
1087
+ params: pathParams,
1088
+ resolver
1089
+ }),
1090
+ optional: !hasRequiredPath
1091
+ }) : _kubb_core.ast.factory.createSchema({
943
1092
  type: "never",
944
- primitive: void 0
1093
+ primitive: void 0,
1094
+ optional: true
945
1095
  })
946
1096
  }),
947
- _kubb_core.ast.createProperty({
948
- name: "queryParams",
949
- schema: queryParams.length > 0 ? _kubb_core.ast.createSchema({
1097
+ _kubb_core.ast.factory.createProperty({
1098
+ name: "query",
1099
+ required: hasRequiredQuery,
1100
+ schema: queryParams.length > 0 ? _kubb_core.ast.factory.createSchema({
950
1101
  ...buildParams(node, {
951
1102
  params: queryParams,
952
1103
  resolver
953
1104
  }),
954
- optional: true
955
- }) : _kubb_core.ast.createSchema({
1105
+ optional: !hasRequiredQuery
1106
+ }) : _kubb_core.ast.factory.createSchema({
956
1107
  type: "never",
957
1108
  primitive: void 0,
958
1109
  optional: true
959
1110
  })
960
1111
  }),
961
- _kubb_core.ast.createProperty({
962
- name: "headerParams",
963
- schema: headerParams.length > 0 ? _kubb_core.ast.createSchema({
1112
+ _kubb_core.ast.factory.createProperty({
1113
+ name: "headers",
1114
+ required: hasRequiredHeader,
1115
+ schema: headerParams.length > 0 ? _kubb_core.ast.factory.createSchema({
964
1116
  ...buildParams(node, {
965
1117
  params: headerParams,
966
1118
  resolver
967
1119
  }),
968
- optional: true
969
- }) : _kubb_core.ast.createSchema({
1120
+ optional: !hasRequiredHeader
1121
+ }) : _kubb_core.ast.factory.createSchema({
970
1122
  type: "never",
971
1123
  primitive: void 0,
972
1124
  optional: true
973
1125
  })
974
- }),
975
- _kubb_core.ast.createProperty({
976
- name: "url",
977
- required: true,
978
- schema: _kubb_core.ast.createSchema({
979
- type: "url",
980
- path: node.path
981
- })
982
1126
  })
983
1127
  ]
984
1128
  });
985
1129
  }
986
1130
  function buildResponses(node, { resolver }) {
987
1131
  if (node.responses.length === 0) return null;
988
- return _kubb_core.ast.createSchema({
1132
+ return _kubb_core.ast.factory.createSchema({
989
1133
  type: "object",
990
- properties: node.responses.map((res) => _kubb_core.ast.createProperty({
1134
+ properties: node.responses.map((res) => _kubb_core.ast.factory.createProperty({
991
1135
  name: String(res.statusCode),
992
1136
  required: true,
993
- schema: _kubb_core.ast.createSchema({
1137
+ schema: _kubb_core.ast.factory.createSchema({
994
1138
  type: "ref",
995
1139
  name: resolver.resolveResponseStatusName(node, res.statusCode)
996
1140
  })
@@ -1000,9 +1144,9 @@ function buildResponses(node, { resolver }) {
1000
1144
  function buildResponseUnion(node, { resolver }) {
1001
1145
  const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema));
1002
1146
  if (responsesWithSchema.length === 0) return null;
1003
- return _kubb_core.ast.createSchema({
1147
+ return _kubb_core.ast.factory.createSchema({
1004
1148
  type: "union",
1005
- members: responsesWithSchema.map((res) => _kubb_core.ast.createSchema({
1149
+ members: responsesWithSchema.map((res) => _kubb_core.ast.factory.createSchema({
1006
1150
  type: "ref",
1007
1151
  name: resolver.resolveResponseStatusName(node, res.statusCode)
1008
1152
  }))
@@ -1010,9 +1154,7 @@ function buildResponseUnion(node, { resolver }) {
1010
1154
  }
1011
1155
  //#endregion
1012
1156
  //#region src/printers/printerTs.ts
1013
- function isNonNullable(value) {
1014
- return value !== null && value !== void 0;
1015
- }
1157
+ const { isNonNullable } = factory_exports;
1016
1158
  /**
1017
1159
  * TypeScript type printer built with `definePrinter`.
1018
1160
  *
@@ -1036,7 +1178,7 @@ function isNonNullable(value) {
1036
1178
  * const declaration = printer.print(schemaNode) // ts.TypeAliasDeclaration | ts.InterfaceDeclaration
1037
1179
  * ```
1038
1180
  */
1039
- const printerTs = _kubb_core.ast.definePrinter((options) => {
1181
+ const printerTs = _kubb_core.ast.createPrinter((options) => {
1040
1182
  const addsUndefined = OPTIONAL_ADDS_UNDEFINED.has(options.optionalType);
1041
1183
  return {
1042
1184
  name: "typescript",
@@ -1082,11 +1224,11 @@ const printerTs = _kubb_core.ast.definePrinter((options) => {
1082
1224
  const hasStringLiteral = members.some((m) => {
1083
1225
  return _kubb_core.ast.narrowSchema(m, _kubb_core.ast.schemaTypes.enum)?.primitive === "string";
1084
1226
  });
1085
- const hasPlainString = members.some((m) => _kubb_core.ast.isStringType(m));
1227
+ const hasPlainString = members.some((m) => (0, _kubb_ast_utils.isStringType)(m));
1086
1228
  if (hasStringLiteral && hasPlainString) return createUnionDeclaration({
1087
1229
  withParentheses: true,
1088
1230
  nodes: members.map((m) => {
1089
- if (_kubb_core.ast.isStringType(m)) return createIntersectionDeclaration({
1231
+ if ((0, _kubb_ast_utils.isStringType)(m)) return createIntersectionDeclaration({
1090
1232
  nodes: [keywordTypeNodes.string, createTypeLiteralNode([])],
1091
1233
  withParentheses: true
1092
1234
  });
@@ -1106,7 +1248,7 @@ const printerTs = _kubb_core.ast.definePrinter((options) => {
1106
1248
  },
1107
1249
  array(node) {
1108
1250
  return createArrayDeclaration({
1109
- nodes: (node.items ?? []).map((item) => this.transform(item)).filter(isNonNullable),
1251
+ nodes: (0, _kubb_ast_utils.mapSchemaItems)(node, (item) => this.transform(item)).map(({ output }) => output).filter(isNonNullable),
1110
1252
  arrayType: this.options.arrayType
1111
1253
  }) ?? null;
1112
1254
  },
@@ -1116,18 +1258,19 @@ const printerTs = _kubb_core.ast.definePrinter((options) => {
1116
1258
  object(node) {
1117
1259
  const { transform, options } = this;
1118
1260
  const addsQuestionToken = OPTIONAL_ADDS_QUESTION_TOKEN.has(options.optionalType);
1119
- const propertyNodes = node.properties.map((prop) => {
1120
- const baseType = transform(prop.schema) ?? keywordTypeNodes.unknown;
1121
- const type = buildPropertyType(prop.schema, baseType, options.optionalType);
1122
- const propMeta = _kubb_core.ast.syncSchemaRef(prop.schema);
1261
+ const propertyNodes = (0, _kubb_ast_utils.mapSchemaProperties)(node, (schema) => transform(schema)).map(({ name, property, output }) => {
1262
+ const baseType = output ?? keywordTypeNodes.unknown;
1263
+ const optional = !property.required || !!property.schema.optional || !!property.schema.nullish;
1264
+ const type = buildPropertyType(property.schema, baseType, options.optionalType, optional);
1265
+ const propMeta = (0, _kubb_ast_utils.syncSchemaRef)(property.schema);
1123
1266
  return appendJSDocToNode({
1124
1267
  node: createPropertySignature({
1125
- questionToken: prop.schema.optional || prop.schema.nullish ? addsQuestionToken : false,
1126
- name: prop.name,
1268
+ questionToken: optional ? addsQuestionToken : false,
1269
+ name,
1127
1270
  type,
1128
1271
  readOnly: propMeta?.readOnly
1129
1272
  }),
1130
- comments: buildPropertyJSDocComments(prop.schema)
1273
+ comments: buildPropertyJSDocComments(property.schema, optional)
1131
1274
  });
1132
1275
  });
1133
1276
  const allElements = [...propertyNodes, ...buildIndexSignatures(node, propertyNodes.length, transform)];
@@ -1140,7 +1283,7 @@ const printerTs = _kubb_core.ast.definePrinter((options) => {
1140
1283
  const { name, syntaxType = "type", description, keysToOmit } = this.options;
1141
1284
  const transformed = this.transform(node);
1142
1285
  if (!transformed) return null;
1143
- const meta = _kubb_core.ast.syncSchemaRef(node);
1286
+ const meta = (0, _kubb_ast_utils.syncSchemaRef)(node);
1144
1287
  if (!name) {
1145
1288
  const withNullable = meta.nullable ? createUnionDeclaration({ nodes: [transformed, keywordTypeNodes.null] }) : transformed;
1146
1289
  const result = (meta.nullish || meta.optional) && addsUndefined ? createUnionDeclaration({ nodes: [withNullable, keywordTypeNodes.undefined] }) : withNullable;
@@ -1262,9 +1405,9 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1262
1405
  });
1263
1406
  },
1264
1407
  operation(node, ctx) {
1265
- const { enum: enumOptions, optionalType, arrayType, syntaxType, paramsCasing, group, output, printer } = ctx.options;
1408
+ const { enum: enumOptions, optionalType, arrayType, syntaxType, group, output, printer } = ctx.options;
1266
1409
  const { adapter, config, resolver, root } = ctx;
1267
- const params = _kubb_core.ast.caseParams(node.parameters, paramsCasing);
1410
+ const params = caseParams(node.parameters, "camelcase");
1268
1411
  const meta = { file: resolver.resolveFile({
1269
1412
  name: node.operationId,
1270
1413
  extname: ".ts",
@@ -1328,9 +1471,9 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1328
1471
  */
1329
1472
  function buildContentTypeVariants(entries, baseName, decorate) {
1330
1473
  const variants = resolveContentTypeVariants(entries, baseName);
1331
- const unionSchema = _kubb_core.ast.createSchema({
1474
+ const unionSchema = _kubb_core.ast.factory.createSchema({
1332
1475
  type: "union",
1333
- members: variants.map((variant) => _kubb_core.ast.createSchema({
1476
+ members: variants.map((variant) => _kubb_core.ast.factory.createSchema({
1334
1477
  type: "ref",
1335
1478
  name: variant.name
1336
1479
  }))
@@ -1345,7 +1488,10 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1345
1488
  })] });
1346
1489
  }
1347
1490
  const paramTypes = params.map((param) => renderSchemaType({
1348
- schema: param.schema,
1491
+ schema: {
1492
+ ...param.schema,
1493
+ optional: !param.required
1494
+ },
1349
1495
  name: resolver.resolveParamName(node, param)
1350
1496
  }));
1351
1497
  const requestBodyContent = node.requestBody?.content ?? [];
@@ -1541,7 +1687,7 @@ const pluginTs = (0, _kubb_core.definePlugin)((options) => {
1541
1687
  const { output = {
1542
1688
  path: "types",
1543
1689
  barrel: { type: "named" }
1544
- }, group, exclude = [], include, override = [], enum: enumOptions = {}, optionalType = "questionToken", arrayType = "array", syntaxType = "type", paramsCasing, printer, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
1690
+ }, group, exclude = [], include, override = [], enum: enumOptions = {}, optionalType = "questionToken", arrayType = "array", syntaxType = "type", printer, resolver: userResolver, macros: userMacros } = options;
1545
1691
  const groupConfig = createGroupConfig(group);
1546
1692
  const resolvedEnum = {
1547
1693
  type: enumOptions.type ?? "asConst",
@@ -1563,52 +1709,237 @@ const pluginTs = (0, _kubb_core.definePlugin)((options) => {
1563
1709
  arrayType,
1564
1710
  enum: resolvedEnum,
1565
1711
  syntaxType,
1566
- paramsCasing,
1567
1712
  printer
1568
1713
  });
1569
1714
  ctx.setResolver(userResolver ? {
1570
1715
  ...resolverTs,
1571
1716
  ...userResolver
1572
1717
  } : resolverTs);
1573
- if (userTransformer) ctx.setTransformer(userTransformer);
1718
+ if (userMacros?.length) ctx.setMacros(userMacros);
1574
1719
  ctx.addGenerator(typeGenerator);
1575
- for (const gen of userGenerators) ctx.addGenerator(gen);
1576
1720
  } }
1577
1721
  };
1578
1722
  });
1579
1723
  //#endregion
1724
+ //#region src/printers/functionParams.ts
1725
+ /**
1726
+ * Narrows a {@link TypeExpression} to a {@link TypeLiteralNode}.
1727
+ */
1728
+ function isTypeLiteral(type) {
1729
+ return typeof type !== "string" && type.kind === "TypeLiteral";
1730
+ }
1731
+ /**
1732
+ * Narrows a {@link TypeExpression} to an {@link IndexedAccessTypeNode}.
1733
+ */
1734
+ function isIndexedAccessType(type) {
1735
+ return typeof type !== "string" && type.kind === "IndexedAccessType";
1736
+ }
1737
+ /**
1738
+ * Creates a {@link TypeLiteralNode} representing an inline anonymous object type.
1739
+ *
1740
+ * @example
1741
+ * ```ts
1742
+ * createTypeLiteral({ members: [{ name: 'petId', type: 'string', optional: false }] })
1743
+ * // { petId: string }
1744
+ * ```
1745
+ */
1746
+ function createTypeLiteral(props) {
1747
+ return {
1748
+ kind: "TypeLiteral",
1749
+ ...props
1750
+ };
1751
+ }
1752
+ /**
1753
+ * Creates an {@link IndexedAccessTypeNode} representing a single field accessed from a named type.
1754
+ *
1755
+ * @example
1756
+ * ```ts
1757
+ * createIndexedAccessType({ target: 'DeletePetPathParams', key: 'petId' })
1758
+ * // DeletePetPathParams['petId']
1759
+ * ```
1760
+ */
1761
+ function createIndexedAccessType(props) {
1762
+ return {
1763
+ kind: "IndexedAccessType",
1764
+ ...props
1765
+ };
1766
+ }
1767
+ /**
1768
+ * Creates an {@link ObjectBindingPatternNode} for a destructured parameter binding.
1769
+ *
1770
+ * @example
1771
+ * ```ts
1772
+ * createObjectBindingPattern({ elements: [{ name: 'id' }, { name: 'name' }] })
1773
+ * // { id, name }
1774
+ * ```
1775
+ */
1776
+ function createObjectBindingPattern(props) {
1777
+ return {
1778
+ kind: "ObjectBindingPattern",
1779
+ ...props
1780
+ };
1781
+ }
1782
+ /**
1783
+ * Creates a {@link FunctionParameterNode}. `optional` defaults to `false`.
1784
+ * Passing `properties` builds a destructured group: an {@link ObjectBindingPatternNode} name
1785
+ * paired with a {@link TypeLiteralNode} type.
1786
+ *
1787
+ * @example Optional param
1788
+ * ```ts
1789
+ * createFunctionParameter({ name: 'params', type: 'QueryParams', optional: true })
1790
+ * // → params?: QueryParams
1791
+ * ```
1792
+ *
1793
+ * @example Destructured group
1794
+ * ```ts
1795
+ * createFunctionParameter({ properties: [{ name: 'id', type: 'string' }, { name: 'name', type: 'string', optional: true }], default: '{}' })
1796
+ * // → { id, name }: { id: string; name?: string } = {}
1797
+ * ```
1798
+ */
1799
+ function createFunctionParameter(input) {
1800
+ if ("properties" in input) return {
1801
+ kind: "FunctionParameter",
1802
+ name: createObjectBindingPattern({ elements: input.properties.map((p) => ({ name: p.name })) }),
1803
+ type: createTypeLiteral({ members: input.properties.map((p) => ({
1804
+ name: p.name,
1805
+ type: p.type,
1806
+ optional: p.optional ?? false
1807
+ })) }),
1808
+ optional: input.optional ?? false,
1809
+ ...input.default !== void 0 ? { default: input.default } : {}
1810
+ };
1811
+ return {
1812
+ kind: "FunctionParameter",
1813
+ optional: false,
1814
+ ...input
1815
+ };
1816
+ }
1817
+ /**
1818
+ * Creates a {@link FunctionParametersNode} from an ordered list of parameters.
1819
+ *
1820
+ * @example
1821
+ * ```ts
1822
+ * const empty = createFunctionParameters()
1823
+ * // { params: [] }
1824
+ * ```
1825
+ */
1826
+ function createFunctionParameters(props = {}) {
1827
+ return {
1828
+ kind: "FunctionParameters",
1829
+ params: [],
1830
+ ...props
1831
+ };
1832
+ }
1833
+ //#endregion
1580
1834
  //#region src/printers/functionPrinter.ts
1581
- const kindToHandlerKey = {
1582
- FunctionParameter: "functionParameter",
1583
- ParameterGroup: "parameterGroup",
1584
- FunctionParameters: "functionParameters",
1585
- ParamsType: "paramsType"
1586
- };
1587
1835
  /**
1588
- * Creates a function-parameter printer factory.
1836
+ * Renders a {@link TypeExpression} to its TypeScript source.
1589
1837
  *
1590
- * Uses `createPrinterFactory` and dispatches handlers by `node.kind`
1591
- * (for function nodes) rather than by `node.type` (for schema nodes).
1838
+ * - a `string` is a type reference, returned as-is
1839
+ * - an `IndexedAccessType` becomes `objectType['indexType']`
1840
+ * - a `TypeLiteral` becomes `{ key: Type; key?: Type }`
1841
+ *
1842
+ * `transformType` is applied once to the fully rendered type, matching how the
1843
+ * printer wrapped reference types before the `ts.factory` model.
1844
+ */
1845
+ function renderType(type, transformType) {
1846
+ const rendered = renderTypeExpression(type);
1847
+ return transformType ? transformType(rendered) : rendered;
1848
+ }
1849
+ /**
1850
+ * Renders an object-type key, quoting it as a string literal when it is not a valid
1851
+ * identifier so `{ 'content-type': string }` stays valid TypeScript.
1592
1852
  */
1593
- const defineFunctionPrinter = _kubb_core.ast.createPrinterFactory((node) => kindToHandlerKey[node.kind]);
1853
+ function renderKey(name) {
1854
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
1855
+ }
1856
+ function renderTypeExpression(type) {
1857
+ if (typeof type === "string") return type;
1858
+ if (isIndexedAccessType(type)) return `${type.target}['${type.key}']`;
1859
+ return `{ ${type.members.map((member) => {
1860
+ const value = renderTypeExpression(member.type);
1861
+ return member.optional ? `${renderKey(member.name)}?: ${value}` : `${renderKey(member.name)}: ${value}`;
1862
+ }).join("; ")} }`;
1863
+ }
1864
+ function groupMembers(param) {
1865
+ if (typeof param.name === "string") return null;
1866
+ return param.type && isTypeLiteral(param.type) ? param.type.members : [];
1867
+ }
1594
1868
  function rank(param) {
1595
- if (param.kind === "ParameterGroup") {
1596
- if (param.default) return PARAM_RANK.withDefault;
1597
- return param.optional ?? param.properties.every((p) => p.optional || p.default !== void 0) ? PARAM_RANK.optional : PARAM_RANK.required;
1598
- }
1599
1869
  if (param.rest) return PARAM_RANK.rest;
1600
1870
  if (param.default) return PARAM_RANK.withDefault;
1871
+ const members = groupMembers(param);
1872
+ if (members) return members.every((m) => m.optional) ? PARAM_RANK.optional : PARAM_RANK.required;
1601
1873
  return param.optional ? PARAM_RANK.optional : PARAM_RANK.required;
1602
1874
  }
1603
1875
  function sortParams(params) {
1604
1876
  return params.toSorted((a, b) => rank(a) - rank(b));
1605
1877
  }
1606
- function sortChildParams(params) {
1607
- return params.toSorted((a, b) => rank(a) - rank(b));
1878
+ function sortedGroupMembers(name, type) {
1879
+ const members = type && isTypeLiteral(type) ? type.members : [];
1880
+ const memberRank = (optional) => optional ? PARAM_RANK.optional : PARAM_RANK.required;
1881
+ return name.elements.map((element, index) => ({
1882
+ name: element.name,
1883
+ propertyName: element.propertyName,
1884
+ type: members[index]?.type,
1885
+ optional: members[index]?.optional
1886
+ })).toSorted((a, b) => memberRank(a.optional) - memberRank(b.optional));
1608
1887
  }
1609
1888
  /**
1610
- * Default function-signature printer.
1611
- * Covers the four standard output modes used across Kubb plugins.
1889
+ * Renders one binding element: the local name, prefixed with its source key when the
1890
+ * binding renames the property, as in `{ petId: id }`.
1891
+ */
1892
+ function renderBindingMember(member, transformName) {
1893
+ const local = transformName ? transformName(member.name) : member.name;
1894
+ return member.propertyName ? `${member.propertyName}: ${local}` : local;
1895
+ }
1896
+ /**
1897
+ * Renders the type annotation of a destructured group. An inline object type is
1898
+ * rendered from the already-sorted members so its key order matches the binding;
1899
+ * a reference type is rendered as-is.
1900
+ */
1901
+ function renderGroupType(type, sorted, transformType) {
1902
+ if (!type) return void 0;
1903
+ if (!isTypeLiteral(type)) return renderType(type);
1904
+ const typed = sorted.filter((member) => member.type !== void 0);
1905
+ if (!typed.length) return void 0;
1906
+ return `{ ${typed.map((member) => {
1907
+ const key = renderKey(member.propertyName ?? member.name);
1908
+ const value = renderType(member.type, transformType);
1909
+ return member.optional ? `${key}?: ${value}` : `${key}: ${value}`;
1910
+ }).join("; ")} }`;
1911
+ }
1912
+ function printParameter(node, options) {
1913
+ const { mode, transformName, transformType } = options;
1914
+ const isGroup = typeof node.name !== "string";
1915
+ if (mode === "call") {
1916
+ if (isGroup) return `{ ${sortedGroupMembers(node.name, node.type).map((member) => renderBindingMember(member)).join(", ")} }`;
1917
+ const name = transformName ? transformName(node.name) : node.name;
1918
+ return node.rest ? `...${name}` : name;
1919
+ }
1920
+ if (isGroup) {
1921
+ const sorted = sortedGroupMembers(node.name, node.type);
1922
+ const binding = `{ ${sorted.map((member) => renderBindingMember(member, transformName)).join(", ")} }`;
1923
+ const allOptional = sorted.every((member) => member.optional);
1924
+ const type = renderGroupType(node.type, sorted, transformType);
1925
+ if (type) {
1926
+ if (allOptional) return `${binding}: ${type} = ${node.default ?? "{}"}`;
1927
+ return node.default ? `${binding}: ${type} = ${node.default}` : `${binding}: ${type}`;
1928
+ }
1929
+ return node.default ? `${binding} = ${node.default}` : binding;
1930
+ }
1931
+ const name = transformName ? transformName(node.name) : node.name;
1932
+ const type = node.type ? renderType(node.type, transformType) : void 0;
1933
+ if (node.rest) return type ? `...${name}: ${type}` : `...${name}`;
1934
+ if (type) {
1935
+ if (node.optional) return `${name}?: ${type}`;
1936
+ return node.default ? `${name}: ${type} = ${node.default}` : `${name}: ${type}`;
1937
+ }
1938
+ return node.default ? `${name} = ${node.default}` : name;
1939
+ }
1940
+ /**
1941
+ * Default function-signature printer. Renders a parameter list in one of two modes:
1942
+ * `declaration` for the function signature and `call` for the call arguments.
1612
1943
  *
1613
1944
  * @example
1614
1945
  * ```ts
@@ -1624,75 +1955,212 @@ function sortChildParams(params) {
1624
1955
  * printer.print(sig) // → "petId: string, config: Config = {}"
1625
1956
  * ```
1626
1957
  */
1627
- const functionPrinter = defineFunctionPrinter((options) => ({
1628
- name: "functionParameters",
1629
- options,
1630
- nodes: {
1631
- paramsType(node) {
1632
- if (node.kind !== "ParamsType") return null;
1633
- if (node.variant === "member") return `${node.base}['${node.key}']`;
1634
- if (node.variant === "struct") return `{ ${node.properties.map((p) => {
1635
- const typeStr = this.transform(p.type);
1636
- const key = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(p.name) ? p.name : JSON.stringify(p.name);
1637
- return p.optional ? `${key}?: ${typeStr}` : `${key}: ${typeStr}`;
1638
- }).join("; ")} }`;
1639
- if (node.variant === "reference") return node.name;
1640
- return null;
1641
- },
1642
- functionParameter(node) {
1643
- const { mode, transformName, transformType } = this.options;
1644
- const name = transformName ? transformName(node.name) : node.name;
1645
- const rawType = node.type ? this.transform(node.type) : void 0;
1646
- const type = rawType != null && transformType ? transformType(rawType) : rawType;
1647
- if (mode === "keys" || mode === "values") return node.rest ? `...${name}` : name;
1648
- if (mode === "call") return node.rest ? `...${name}` : name;
1649
- if (node.rest) return type ? `...${name}: ${type}` : `...${name}`;
1650
- if (type) {
1651
- if (node.optional) return `${name}?: ${type}`;
1652
- return node.default ? `${name}: ${type} = ${node.default}` : `${name}: ${type}`;
1653
- }
1654
- return node.default ? `${name} = ${node.default}` : name;
1655
- },
1656
- parameterGroup(node) {
1657
- const { mode, transformName, transformType } = this.options;
1658
- const sorted = sortChildParams(node.properties);
1659
- const isOptional = node.optional ?? sorted.every((p) => p.optional || p.default !== void 0);
1660
- if (node.inline) return sorted.map((p) => this.transform(p)).filter(Boolean).join(", ");
1661
- if (mode === "keys" || mode === "values") return `{ ${sorted.map((p) => p.name).join(", ")} }`;
1662
- if (mode === "call") return `{ ${sorted.map((p) => p.name).join(", ")} }`;
1663
- const names = sorted.map((p) => {
1664
- return transformName ? transformName(p.name) : p.name;
1665
- });
1666
- const nameStr = names.length ? `{ ${names.join(", ")} }` : void 0;
1667
- if (!nameStr) return null;
1668
- let typeAnnotation = node.type ? this.transform(node.type) ?? void 0 : void 0;
1669
- if (!typeAnnotation) {
1670
- const typeParts = sorted.filter((p) => p.type).map((p) => {
1671
- const rawT = p.type ? this.transform(p.type) : void 0;
1672
- const t = rawT != null && transformType ? transformType(rawT) : rawT;
1673
- return p.optional || p.default !== void 0 ? `${p.name}?: ${t}` : `${p.name}: ${t}`;
1674
- });
1675
- typeAnnotation = typeParts.length ? `{ ${typeParts.join("; ")} }` : void 0;
1676
- }
1677
- if (typeAnnotation) {
1678
- if (isOptional) return `${nameStr}: ${typeAnnotation} = ${node.default ?? "{}"}`;
1679
- return node.default ? `${nameStr}: ${typeAnnotation} = ${node.default}` : `${nameStr}: ${typeAnnotation}`;
1680
- }
1681
- return node.default ? `${nameStr} = ${node.default}` : nameStr;
1682
- },
1683
- functionParameters(node) {
1684
- return sortParams(node.params).map((p) => this.transform(p)).filter(Boolean).join(", ");
1958
+ function functionPrinter(options) {
1959
+ return {
1960
+ name: "functionParameters",
1961
+ options,
1962
+ print(node) {
1963
+ return sortParams(node.params).map((p) => printParameter(p, options)).filter(Boolean).join(", ");
1964
+ }
1965
+ };
1966
+ }
1967
+ //#endregion
1968
+ //#region src/printers/operationParams.ts
1969
+ /**
1970
+ * Resolves the {@link TypeExpression} for an individual parameter.
1971
+ *
1972
+ * Without a resolver, it falls back to the schema primitive (a plain type-name string). When the
1973
+ * parameter belongs to a named group, it emits an `IndexedAccessType` like `GroupParams['petId']`,
1974
+ * otherwise the resolved individual name.
1975
+ */
1976
+ function resolveParamType({ node, param, resolver }) {
1977
+ if (!resolver) return param.schema.primitive ?? "unknown";
1978
+ const individualName = resolver.resolveParamName(node, param);
1979
+ const groupLocation = param.in === "path" || param.in === "query" || param.in === "header" ? param.in : void 0;
1980
+ const groupResolvers = {
1981
+ path: resolver.resolvePathParamsName,
1982
+ query: resolver.resolveQueryParamsName,
1983
+ header: resolver.resolveHeaderParamsName
1984
+ };
1985
+ const groupName = groupLocation ? groupResolvers[groupLocation].call(resolver, node, param) : void 0;
1986
+ if (groupName && groupName !== individualName) return createIndexedAccessType({
1987
+ target: groupName,
1988
+ key: param.name
1989
+ });
1990
+ return individualName;
1991
+ }
1992
+ /**
1993
+ * Derives a {@link ParamGroupType} for a query or header group from the resolver.
1994
+ *
1995
+ * Returns `null` when there is no resolver, no params, or the group name equals the
1996
+ * individual param name (so there is no real group to emit).
1997
+ */
1998
+ function resolveGroupType({ node, params, group, resolver }) {
1999
+ if (!resolver || !params.length) return null;
2000
+ const firstParam = params[0];
2001
+ const groupName = (group === "query" ? resolver.resolveQueryParamsName : resolver.resolveHeaderParamsName).call(resolver, node, firstParam);
2002
+ if (groupName === resolver.resolveParamName(node, firstParam)) return null;
2003
+ return {
2004
+ type: groupName,
2005
+ optional: params.every((p) => !p.required)
2006
+ };
2007
+ }
2008
+ /**
2009
+ * Converts an `OperationNode` into function parameters for code generation.
2010
+ *
2011
+ * Centralizes parameter grouping logic for all plugins. `paramsType` chooses between one
2012
+ * destructured object parameter (`object`) and separate top-level parameters (`inline`), while
2013
+ * `pathParamsType` controls how path params render in inline mode. Provide a `resolver` for type
2014
+ * name resolution and `extraParams` for plugin-specific trailing parameters such as an `options` object.
2015
+ */
2016
+ function createOperationParams(node, options) {
2017
+ const { paramsType, pathParamsType, paramsCasing, resolver, pathParamsDefault, extraParams = [], paramNames, typeWrapper } = options;
2018
+ const dataName = paramNames?.data ?? "data";
2019
+ const paramsName = paramNames?.params ?? "params";
2020
+ const headersName = paramNames?.headers ?? "headers";
2021
+ const pathName = paramNames?.path ?? "pathParams";
2022
+ const wrapType = (type) => typeWrapper ? typeWrapper(type) : type;
2023
+ const wrapTypeExpression = (type) => typeof type === "string" ? wrapType(type) : type;
2024
+ const casedParams = caseParams(node.parameters, paramsCasing);
2025
+ const pathParams = casedParams.filter((p) => p.in === "path");
2026
+ const queryParams = casedParams.filter((p) => p.in === "query");
2027
+ const headerParams = casedParams.filter((p) => p.in === "header");
2028
+ const toProperty = (param) => ({
2029
+ name: param.name,
2030
+ type: wrapTypeExpression(resolveParamType({
2031
+ node,
2032
+ param,
2033
+ resolver
2034
+ })),
2035
+ optional: !param.required
2036
+ });
2037
+ const emptyObjectDefault = (props) => props.every((p) => p.optional) ? "{}" : void 0;
2038
+ const bodyType = node.requestBody?.content?.[0]?.schema ? wrapType(resolver?.resolveDataName(node) ?? "unknown") : void 0;
2039
+ const bodyProperty = bodyType ? [{
2040
+ name: dataName,
2041
+ type: bodyType,
2042
+ optional: !(node.requestBody?.required ?? false)
2043
+ }] : [];
2044
+ const trailingGroups = [{
2045
+ name: paramsName,
2046
+ node,
2047
+ params: queryParams,
2048
+ groupType: resolveGroupType({
2049
+ node,
2050
+ params: queryParams,
2051
+ group: "query",
2052
+ resolver
2053
+ }),
2054
+ resolver,
2055
+ wrapType
2056
+ }, {
2057
+ name: headersName,
2058
+ node,
2059
+ params: headerParams,
2060
+ groupType: resolveGroupType({
2061
+ node,
2062
+ params: headerParams,
2063
+ group: "header",
2064
+ resolver
2065
+ }),
2066
+ resolver,
2067
+ wrapType
2068
+ }];
2069
+ const params = [];
2070
+ if (paramsType === "object") {
2071
+ const children = [
2072
+ ...pathParams.map(toProperty),
2073
+ ...bodyProperty,
2074
+ ...trailingGroups.flatMap(buildGroupProperty)
2075
+ ];
2076
+ if (children.length) params.push(createFunctionParameter({
2077
+ properties: children,
2078
+ default: emptyObjectDefault(children)
2079
+ }));
2080
+ } else {
2081
+ if (pathParamsType === "inlineSpread" && pathParams.length) {
2082
+ const spreadType = resolver?.resolvePathParamsName(node, pathParams[0]);
2083
+ params.push(createFunctionParameter({
2084
+ name: pathName,
2085
+ type: spreadType ? wrapType(spreadType) : void 0,
2086
+ rest: true
2087
+ }));
2088
+ } else if (pathParamsType === "inline") params.push(...pathParams.map((p) => createFunctionParameter(toProperty(p))));
2089
+ else if (pathParams.length) {
2090
+ const pathChildren = pathParams.map(toProperty);
2091
+ params.push(createFunctionParameter({
2092
+ properties: pathChildren,
2093
+ default: pathParamsDefault ?? emptyObjectDefault(pathChildren)
2094
+ }));
1685
2095
  }
2096
+ params.push(...bodyProperty.map((p) => createFunctionParameter(p)));
2097
+ params.push(...trailingGroups.flatMap(buildGroupParam));
1686
2098
  }
1687
- }));
2099
+ params.push(...extraParams);
2100
+ return createFunctionParameters({ params });
2101
+ }
2102
+ /**
2103
+ * Builds the property descriptor for a query or header group.
2104
+ * Returns an empty array when there are no params to emit.
2105
+ *
2106
+ * A pre-resolved `groupType` emits `name: GroupType`. Otherwise it builds an inline
2107
+ * {@link TypeLiteralNode} from the individual params.
2108
+ */
2109
+ function buildGroupProperty({ name, node, params, groupType, resolver, wrapType }) {
2110
+ if (groupType) return [{
2111
+ name,
2112
+ type: typeof groupType.type === "string" ? wrapType(groupType.type) : groupType.type,
2113
+ optional: groupType.optional
2114
+ }];
2115
+ if (params.length) return [{
2116
+ name,
2117
+ type: buildTypeLiteral({
2118
+ node,
2119
+ params,
2120
+ resolver
2121
+ }),
2122
+ optional: params.every((p) => !p.required)
2123
+ }];
2124
+ return [];
2125
+ }
2126
+ /**
2127
+ * Builds a single {@link FunctionParameterNode} for a query or header group.
2128
+ * Returns an empty array when there are no params to emit.
2129
+ */
2130
+ function buildGroupParam(args) {
2131
+ return buildGroupProperty(args).map((p) => createFunctionParameter(p));
2132
+ }
2133
+ /**
2134
+ * Builds a {@link TypeLiteralNode} for an inline anonymous type grouping named fields.
2135
+ *
2136
+ * Used when query or header parameters have no dedicated group type name.
2137
+ */
2138
+ function buildTypeLiteral({ node, params, resolver }) {
2139
+ return createTypeLiteral({ members: params.map((p) => ({
2140
+ name: p.name,
2141
+ type: resolveParamType({
2142
+ node,
2143
+ param: p,
2144
+ resolver
2145
+ }),
2146
+ optional: !p.required
2147
+ })) });
2148
+ }
1688
2149
  //#endregion
1689
2150
  exports.Enum = Enum;
1690
2151
  exports.Type = Type;
2152
+ exports.createFunctionParameter = createFunctionParameter;
2153
+ exports.createFunctionParameters = createFunctionParameters;
2154
+ exports.createIndexedAccessType = createIndexedAccessType;
2155
+ exports.createObjectBindingPattern = createObjectBindingPattern;
2156
+ exports.createOperationParams = createOperationParams;
2157
+ exports.createTypeLiteral = createTypeLiteral;
1691
2158
  exports.default = pluginTs;
1692
2159
  exports.functionPrinter = functionPrinter;
1693
2160
  exports.pluginTs = pluginTs;
1694
2161
  exports.pluginTsName = pluginTsName;
1695
2162
  exports.printerTs = printerTs;
2163
+ exports.renderType = renderType;
1696
2164
  exports.resolverTs = resolverTs;
1697
2165
  exports.typeGenerator = typeGenerator;
1698
2166