@kubb/ast 5.0.0-alpha.72 → 5.0.0-alpha.74

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
@@ -49,15 +49,11 @@ const nodeKinds = {
49
49
  break: "Break"
50
50
  };
51
51
  /**
52
- * Canonical schema type strings used by AST schema nodes.
52
+ * Schema type discriminators used by all AST schema nodes.
53
53
  *
54
- * These values are used across the AST as stable discriminators
55
- * (for example `schema.type === schemaTypes.object`).
56
- *
57
- * The map is grouped by intent:
58
- * - primitives (`string`, `number`, `boolean`, ...)
59
- * - structural/composite (`object`, `array`, `union`, ...)
60
- * - special OpenAPI-oriented types (`ref`, `datetime`, `uuid`, ...)
54
+ * These values serve as stable discriminators across the AST (e.g., `schema.type === schemaTypes.object`).
55
+ * Grouped by category: primitives (`string`, `number`, `boolean`), structural types (`object`, `array`, `union`),
56
+ * and format-specific types (`date`, `uuid`, `email`). Use `isScalarPrimitive()` to check for scalar types.
61
57
  */
62
58
  const schemaTypes = {
63
59
  /**
@@ -166,7 +162,9 @@ const schemaTypes = {
166
162
  never: "never"
167
163
  };
168
164
  /**
169
- * Primitive scalar schema types used when simplifying union members.
165
+ * Scalar primitive schema types used for union simplification and type narrowing.
166
+ *
167
+ * Use `isScalarPrimitive()` to safely check whether a type is a scalar primitive.
170
168
  */
171
169
  const SCALAR_PRIMITIVE_TYPES = new Set([
172
170
  "string",
@@ -176,11 +174,18 @@ const SCALAR_PRIMITIVE_TYPES = new Set([
176
174
  "boolean"
177
175
  ]);
178
176
  /**
179
- * Returns `true` when `type` is a scalar primitive schema type.
177
+ * Type guard that returns `true` when `type` is a scalar primitive schema type.
178
+ *
179
+ * Use this to check if a schema type can be directly assigned without wrapping (e.g., `string | number | boolean`).
180
180
  */
181
181
  function isScalarPrimitive(type) {
182
182
  return SCALAR_PRIMITIVE_TYPES.has(type);
183
183
  }
184
+ /**
185
+ * HTTP method identifiers used by operation nodes.
186
+ *
187
+ * Includes all standard HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE).
188
+ */
184
189
  const httpMethods = {
185
190
  get: "GET",
186
191
  post: "POST",
@@ -191,6 +196,12 @@ const httpMethods = {
191
196
  options: "OPTIONS",
192
197
  trace: "TRACE"
193
198
  };
199
+ /**
200
+ * Common MIME types used in request/response content negotiation.
201
+ *
202
+ * Covers JSON, XML, form data, PDFs, images, audio, and video formats.
203
+ * Use these as keys when serializing request/response bodies.
204
+ */
194
205
  const mediaTypes = {
195
206
  applicationJson: "application/json",
196
207
  applicationXml: "application/xml",
@@ -788,13 +799,17 @@ const plainStringTypes = new Set([
788
799
  "datetime"
789
800
  ]);
790
801
  /**
791
- * Returns a merged schema view for a ref node, combining the resolved `node.schema`
792
- * (base from the referenced definition) with any usage-site sibling fields set directly
793
- * on the ref node (description, readOnly, nullable, deprecated, etc.).
802
+ * Merges a ref node with its resolved schema, giving usage-site fields precedence.
794
803
  *
795
- * Usage-site fields take precedence over the resolved schema's own fields when both are defined.
804
+ * Usage-site fields (`description`, `readOnly`, `nullable`, `deprecated`) on the ref node
805
+ * override the same fields in the resolved `node.schema`. Non-ref nodes are returned unchanged.
796
806
  *
797
- * For non-ref nodes the node itself is returned unchanged.
807
+ * @example
808
+ * ```ts
809
+ * // Ref with description override
810
+ * const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A cute pet' })
811
+ * const merged = syncSchemaRef(ref) // merges with resolved Pet schema
812
+ * ```
798
813
  */
799
814
  function syncSchemaRef(node) {
800
815
  const ref = narrowSchema(node, "ref");
@@ -808,16 +823,10 @@ function syncSchemaRef(node) {
808
823
  });
809
824
  }
810
825
  /**
811
- * Returns `true` when a schema is emitted as a plain `string` type.
812
- *
813
- * - `string`, `uuid`, `email`, `url`, `datetime` are always plain strings.
814
- * - `date` and `time` are plain strings when their `representation` is `'string'` rather than `'date'`.
826
+ * Type guard that returns `true` when a schema emits as a plain `string` type.
815
827
  *
816
- * @example
817
- * ```ts
818
- * isStringType(createSchema({ type: 'uuid' })) // true
819
- * isStringType(createSchema({ type: 'date', representation: 'date' })) // false
820
- * ```
828
+ * Covers `string`, `uuid`, `email`, `url`, and `datetime` types. For `date` and `time`
829
+ * types, returns `true` only when `representation` is `'string'` rather than `'date'`.
821
830
  */
822
831
  function isStringType(node) {
823
832
  if (plainStringTypes.has(node.type)) return true;
@@ -828,19 +837,9 @@ function isStringType(node) {
828
837
  /**
829
838
  * Applies casing rules to parameter names and returns a new parameter array.
830
839
  *
831
- * The input array is not mutated.
832
- * If `casing` is not set, the original array is returned unchanged.
833
- *
834
- * Use this before passing parameters to schema builders so that property keys
835
- * in generated output match the desired casing while preserving
836
- * `OperationNode.parameters` for other consumers.
837
- *
838
- * @example
839
- * ```ts
840
- * const params = [createParameter({ name: 'pet_id', in: 'query', schema: createSchema({ type: 'string' }) })]
841
- * const cased = caseParams(params, 'camelcase')
842
- * // cased[0].name === 'petId'
843
- * ```
840
+ * Use this before passing parameters to schema builders so output property keys match
841
+ * the desired casing while preserving `OperationNode.parameters` for other consumers.
842
+ * The input array is not mutated. When `casing` is not set, the original array is returned unchanged.
844
843
  */
845
844
  function caseParams(params, casing) {
846
845
  if (!casing) return params;
@@ -900,20 +899,12 @@ function resolveParamsType({ node, param, resolver }) {
900
899
  });
901
900
  }
902
901
  /**
903
- * Converts an {@link OperationNode} into a {@link FunctionParametersNode}.
904
- *
905
- * Centralizes the per-plugin `getParams()` pattern. Provide a `resolver` for
906
- * type resolution and `extraParams` for plugin-specific trailing parameters.
902
+ * Converts an `OperationNode` into function parameters for code generation.
907
903
  *
908
- * @example
909
- * ```ts
910
- * const params = createOperationParams(node, {
911
- * paramsType: 'inline',
912
- * pathParamsType: 'inline',
913
- * resolver: tsResolver,
914
- * extraParams: [createFunctionParameter({ name: 'options', type: createParamsType({ variant: 'reference', name: 'Partial<RequestOptions>' }), default: '{}' })],
915
- * })
916
- * ```
904
+ * Centralizes parameter grouping logic for all plugins. Provide a `resolver` for type name resolution
905
+ * and `extraParams` for plugin-specific trailing parameters (e.g., `options` objects).
906
+ * Supports three grouping modes: `object` (single destructured param), `inline` (separate params),
907
+ * and `inlineSpread` (rest parameter). Use `CreateOperationParamsOptions` to fine-tune output.
917
908
  */
918
909
  function createOperationParams(node, options) {
919
910
  const { paramsType, pathParamsType, paramsCasing, resolver, pathParamsDefault, extraParams = [], paramNames, typeWrapper } = options;
@@ -1123,9 +1114,9 @@ function sortKey(node) {
1123
1114
  return `${isArray}:${typeOnly}:${node.path}:${hasName}:${name}`;
1124
1115
  }
1125
1116
  /**
1126
- * Deduplicates an array of `SourceNode` objects.
1127
- * Named sources are deduplicated by `name + isExportable + isTypeOnly`.
1128
- * Unnamed sources are deduplicated by object reference.
1117
+ * Deduplicates and merges `SourceNode` objects by `name + isExportable + isTypeOnly`.
1118
+ *
1119
+ * Unnamed sources are deduplicated by object reference. Returns a deduplicated array in original order.
1129
1120
  */
1130
1121
  function combineSources(sources) {
1131
1122
  const seen = /* @__PURE__ */ new Map();
@@ -1136,8 +1127,10 @@ function combineSources(sources) {
1136
1127
  return [...seen.values()];
1137
1128
  }
1138
1129
  /**
1139
- * Deduplicates and merges an array of `ExportNode` objects.
1140
- * Exports with the same path and `isTypeOnly` flag have their names merged.
1130
+ * Deduplicates and merges `ExportNode` objects by path and type.
1131
+ *
1132
+ * Named exports with the same path and `isTypeOnly` flag have their names merged into a single export.
1133
+ * Non-array exports are deduplicated by exact identity. Returns a sorted, deduplicated array.
1141
1134
  */
1142
1135
  function combineExports(exports) {
1143
1136
  const result = [];
@@ -1177,9 +1170,12 @@ function combineExports(exports) {
1177
1170
  return result;
1178
1171
  }
1179
1172
  /**
1180
- * Deduplicates and merges an array of `ImportNode` objects.
1181
- * Filters out unused imports (names not referenced in `source` or re-exported).
1182
- * Imports with the same path and `isTypeOnly` flag have their names merged.
1173
+ * Deduplicates and merges `ImportNode` objects, filtering out unused imports.
1174
+ *
1175
+ * Retains imports that are referenced in `source` or re-exported. Imports with the same path and
1176
+ * `isTypeOnly` flag have their names merged. Returns a sorted, deduplicated, filtered array.
1177
+ *
1178
+ * @note Use this when combining imports from multiple files to avoid duplicate declarations.
1183
1179
  */
1184
1180
  function combineImports(imports, exports, source) {
1185
1181
  const exportedNames = new Set(exports.flatMap((e) => Array.isArray(e.name) ? e.name : e.name ? [e.name] : []));
@@ -1225,11 +1221,10 @@ function combineImports(imports, exports, source) {
1225
1221
  return result;
1226
1222
  }
1227
1223
  /**
1228
- * Recursively extracts all string content embedded in a {@link CodeNode} tree.
1224
+ * Extracts all string content from a `CodeNode` tree recursively.
1229
1225
  *
1230
- * Includes text node values, and string attribute fields (`params`, `generics`,
1231
- * `returnType`, `type`) that may reference identifiers needing imports.
1232
- * Used by `createFile` to build the full source string for import filtering.
1226
+ * Collects text node values, identifier references in string fields (`params`, `generics`, `returnType`, `type`),
1227
+ * and nested node content. Used internally to build the full source string for import filtering.
1233
1228
  */
1234
1229
  function extractStringsFromNodes(nodes) {
1235
1230
  if (!nodes?.length) return "";
@@ -1249,9 +1244,10 @@ function extractStringsFromNodes(nodes) {
1249
1244
  }).filter(Boolean).join("\n");
1250
1245
  }
1251
1246
  /**
1252
- * Resolves the referenced schema name of a `ref` node, falling back through
1253
- * `ref` → `name` → nested `schema.name`. Returns `undefined` for non-ref
1254
- * nodes or when no name can be resolved.
1247
+ * Resolves the schema name of a ref node, falling back through `ref` → `name` → nested `schema.name`.
1248
+ *
1249
+ * Returns `undefined` for non-ref nodes or when no name can be resolved. Use this to get a schema's
1250
+ * identifier for type definitions or error messages.
1255
1251
  *
1256
1252
  * @example
1257
1253
  * ```ts
@@ -1265,15 +1261,12 @@ function resolveRefName(node) {
1265
1261
  return node.name ?? node.schema?.name ?? void 0;
1266
1262
  }
1267
1263
  /**
1268
- * Recursively collects every named schema referenced (transitively) from
1269
- * `node` via `ref` edges. Refs are followed by name only — the resolved
1270
- * `node.schema` of a ref is not traversed inline.
1264
+ * Collects every named schema referenced (transitively) from a node via ref edges.
1271
1265
  *
1272
- * @example
1273
- * ```ts
1274
- * const refs = collectReferencedSchemaNames(petSchema)
1275
- * // => Set { 'Cat', 'Dog' }
1276
- * ```
1266
+ * Refs are followed by name only — the resolved `node.schema` is not traversed inline.
1267
+ * Use this to determine schema dependencies, build reference graphs, or detect what schemas need to be emitted.
1268
+ *
1269
+ * @note Returns a Set of schema names for efficient membership testing.
1277
1270
  */
1278
1271
  function collectReferencedSchemaNames(node, out = /* @__PURE__ */ new Set()) {
1279
1272
  if (!node) return out;
@@ -1286,26 +1279,13 @@ function collectReferencedSchemaNames(node, out = /* @__PURE__ */ new Set()) {
1286
1279
  return out;
1287
1280
  }
1288
1281
  /**
1289
- * Identifies every named schema that participates in a circular dependency
1290
- * chain — including direct self-loops (e.g. `TreeNode → TreeNode`) and indirect
1291
- * cycles spanning multiple schemas (e.g. `Pet → Cat → Pet`).
1292
- *
1293
- * The returned set contains schema names. Plugins that translate schemas into
1294
- * a host language can use this to wrap recursive positions in a deferred
1295
- * construct (lazy getter, `z.lazy(() => …)`, etc.) and avoid runtime stack
1296
- * overflows when the generated code is executed.
1282
+ * Identifies all schemas that participate in circular dependency chains, including direct self-loops.
1297
1283
  *
1298
- * Refs are followed by name only `node.schema` (the resolved referent) is
1299
- * not traversed inline, which keeps the algorithm linear in the size of the
1300
- * schema graph.
1284
+ * Returns a Set of schema names with circular dependencies. Use this to wrap recursive schema positions
1285
+ * in deferred constructs (lazy getter, `z.lazy(() => …)`) to prevent infinite recursion when generated code runs.
1286
+ * Refs are followed by name only, keeping the algorithm linear in the schema graph size.
1301
1287
  *
1302
- * @example
1303
- * ```ts
1304
- * const circular = findCircularSchemas(inputNode.schemas)
1305
- * if (circular.has('Pet')) {
1306
- * // emit lazy wrapper for any property whose schema references Pet
1307
- * }
1308
- * ```
1288
+ * @note Call this once on the full schema graph, then use `containsCircularRef()` to check individual schemas.
1309
1289
  */
1310
1290
  function findCircularSchemas(schemas) {
1311
1291
  const graph = /* @__PURE__ */ new Map();
@@ -1332,21 +1312,12 @@ function findCircularSchemas(schemas) {
1332
1312
  return circular;
1333
1313
  }
1334
1314
  /**
1335
- * Returns true when `node` (or anything nested within it) carries a `ref`
1336
- * whose resolved name belongs to `circularSchemas`.
1315
+ * Type guard returning `true` when a schema or anything nested within it contains a ref to a circular schema.
1337
1316
  *
1338
- * When `excludeName` is provided, refs to that name are ignored — useful
1339
- * when self-references are already handled separately from cross-schema
1340
- * cycles (e.g. the faker plugin emits `undefined as any` for direct
1341
- * self-recursion but a lazy getter for indirect cycles).
1317
+ * Use `excludeName` to ignore refs to specific schemas (useful when self-references are handled separately).
1318
+ * Commonly used with `findCircularSchemas()` to detect where lazy wrappers are needed in code generation.
1342
1319
  *
1343
- * @example
1344
- * ```ts
1345
- * const circular = findCircularSchemas(schemas)
1346
- * if (containsCircularRef(property.schema, { circularSchemas: circular, excludeName: 'Pet' })) {
1347
- * // emit `get foo() { return fakeCat() }` instead of eager call
1348
- * }
1349
- * ```
1320
+ * @note Returns `true` for the first matching circular ref found; use for fast dependency checks.
1350
1321
  */
1351
1322
  function containsCircularRef(node, { circularSchemas, excludeName }) {
1352
1323
  if (!node || circularSchemas.size === 0) return false;