@kubb/ast 5.0.0-alpha.73 → 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 +75 -104
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +63 -96
- package/dist/index.js +75 -104
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/constants.ts +30 -15
- package/src/utils.ts +54 -94
package/dist/index.cjs
CHANGED
|
@@ -49,15 +49,11 @@ const nodeKinds = {
|
|
|
49
49
|
break: "Break"
|
|
50
50
|
};
|
|
51
51
|
/**
|
|
52
|
-
*
|
|
52
|
+
* Schema type discriminators used by all AST schema nodes.
|
|
53
53
|
*
|
|
54
|
-
* These values
|
|
55
|
-
* (
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
817
|
-
*
|
|
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
|
-
*
|
|
832
|
-
*
|
|
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
|
|
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
|
-
*
|
|
909
|
-
*
|
|
910
|
-
*
|
|
911
|
-
*
|
|
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
|
|
1127
|
-
*
|
|
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
|
|
1140
|
-
*
|
|
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
|
|
1181
|
-
*
|
|
1182
|
-
*
|
|
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
|
-
*
|
|
1224
|
+
* Extracts all string content from a `CodeNode` tree recursively.
|
|
1229
1225
|
*
|
|
1230
|
-
*
|
|
1231
|
-
*
|
|
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
|
|
1253
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
1273
|
-
*
|
|
1274
|
-
*
|
|
1275
|
-
*
|
|
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
|
|
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
|
-
*
|
|
1299
|
-
*
|
|
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
|
-
* @
|
|
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
|
-
*
|
|
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
|
-
*
|
|
1339
|
-
*
|
|
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
|
-
* @
|
|
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;
|