@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 +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/package.json
CHANGED
package/src/constants.ts
CHANGED
|
@@ -4,7 +4,10 @@ import type { HttpMethod } from './nodes/operation.ts'
|
|
|
4
4
|
import type { SchemaType } from './nodes/schema.ts'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Traversal depth
|
|
7
|
+
* Traversal depth for AST visitor utilities.
|
|
8
|
+
*
|
|
9
|
+
* - `'shallow'` — visits only the immediate node, skipping children.
|
|
10
|
+
* - `'deep'` — recursively visits all descendant nodes.
|
|
8
11
|
*/
|
|
9
12
|
export type VisitorDepth = 'shallow' | 'deep'
|
|
10
13
|
|
|
@@ -34,15 +37,11 @@ export const nodeKinds = {
|
|
|
34
37
|
} as const satisfies Record<string, NodeKind>
|
|
35
38
|
|
|
36
39
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* These values are used across the AST as stable discriminators
|
|
40
|
-
* (for example `schema.type === schemaTypes.object`).
|
|
40
|
+
* Schema type discriminators used by all AST schema nodes.
|
|
41
41
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* -
|
|
45
|
-
* - special OpenAPI-oriented types (`ref`, `datetime`, `uuid`, ...)
|
|
42
|
+
* These values serve as stable discriminators across the AST (e.g., `schema.type === schemaTypes.object`).
|
|
43
|
+
* Grouped by category: primitives (`string`, `number`, `boolean`), structural types (`object`, `array`, `union`),
|
|
44
|
+
* and format-specific types (`date`, `uuid`, `email`). Use `isScalarPrimitive()` to check for scalar types.
|
|
46
45
|
*/
|
|
47
46
|
export const schemaTypes = {
|
|
48
47
|
/**
|
|
@@ -154,17 +153,26 @@ export const schemaTypes = {
|
|
|
154
153
|
export type ScalarPrimitive = 'string' | 'number' | 'integer' | 'bigint' | 'boolean'
|
|
155
154
|
|
|
156
155
|
/**
|
|
157
|
-
*
|
|
156
|
+
* Scalar primitive schema types used for union simplification and type narrowing.
|
|
157
|
+
*
|
|
158
|
+
* Use `isScalarPrimitive()` to safely check whether a type is a scalar primitive.
|
|
158
159
|
*/
|
|
159
160
|
export const SCALAR_PRIMITIVE_TYPES = new Set<ScalarPrimitive>(['string', 'number', 'integer', 'bigint', 'boolean'])
|
|
160
161
|
|
|
161
162
|
/**
|
|
162
|
-
*
|
|
163
|
+
* Type guard that returns `true` when `type` is a scalar primitive schema type.
|
|
164
|
+
*
|
|
165
|
+
* Use this to check if a schema type can be directly assigned without wrapping (e.g., `string | number | boolean`).
|
|
163
166
|
*/
|
|
164
167
|
export function isScalarPrimitive(type: string): type is ScalarPrimitive {
|
|
165
168
|
return SCALAR_PRIMITIVE_TYPES.has(type as ScalarPrimitive)
|
|
166
169
|
}
|
|
167
170
|
|
|
171
|
+
/**
|
|
172
|
+
* HTTP method identifiers used by operation nodes.
|
|
173
|
+
*
|
|
174
|
+
* Includes all standard HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE).
|
|
175
|
+
*/
|
|
168
176
|
export const httpMethods = {
|
|
169
177
|
get: 'GET',
|
|
170
178
|
post: 'POST',
|
|
@@ -177,19 +185,26 @@ export const httpMethods = {
|
|
|
177
185
|
} as const satisfies Record<Lowercase<HttpMethod>, HttpMethod>
|
|
178
186
|
|
|
179
187
|
/**
|
|
180
|
-
* Default
|
|
188
|
+
* Default concurrency limit for `walk()` traversal utility.
|
|
181
189
|
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
* large spec traversals.
|
|
190
|
+
* Set to 30 to balance I/O-bound resolver parallelism against event loop pressure and memory usage during large spec traversals.
|
|
191
|
+
* Use `WALK_CONCURRENCY` when calling `walk()` or override for different hardware constraints.
|
|
185
192
|
*
|
|
186
193
|
* @example
|
|
187
194
|
* ```ts
|
|
195
|
+
* import { walk, WALK_CONCURRENCY } from '@kubb/ast'
|
|
196
|
+
*
|
|
188
197
|
* walk(root, { concurrency: WALK_CONCURRENCY, root: () => {} })
|
|
189
198
|
* ```
|
|
190
199
|
*/
|
|
191
200
|
export const WALK_CONCURRENCY = 30
|
|
192
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Common MIME types used in request/response content negotiation.
|
|
204
|
+
*
|
|
205
|
+
* Covers JSON, XML, form data, PDFs, images, audio, and video formats.
|
|
206
|
+
* Use these as keys when serializing request/response bodies.
|
|
207
|
+
*/
|
|
193
208
|
export const mediaTypes = {
|
|
194
209
|
applicationJson: 'application/json',
|
|
195
210
|
applicationXml: 'application/xml',
|
package/src/utils.ts
CHANGED
|
@@ -22,13 +22,17 @@ import { collect } from './visitor.ts'
|
|
|
22
22
|
const plainStringTypes = new Set<SchemaType>(['string', 'uuid', 'email', 'url', 'datetime'] as const)
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
26
|
-
* (base from the referenced definition) with any usage-site sibling fields set directly
|
|
27
|
-
* on the ref node (description, readOnly, nullable, deprecated, etc.).
|
|
25
|
+
* Merges a ref node with its resolved schema, giving usage-site fields precedence.
|
|
28
26
|
*
|
|
29
|
-
* Usage-site fields
|
|
27
|
+
* Usage-site fields (`description`, `readOnly`, `nullable`, `deprecated`) on the ref node
|
|
28
|
+
* override the same fields in the resolved `node.schema`. Non-ref nodes are returned unchanged.
|
|
30
29
|
*
|
|
31
|
-
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* // Ref with description override
|
|
33
|
+
* const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A cute pet' })
|
|
34
|
+
* const merged = syncSchemaRef(ref) // merges with resolved Pet schema
|
|
35
|
+
* ```
|
|
32
36
|
*/
|
|
33
37
|
export function syncSchemaRef(node: SchemaNode): SchemaNode {
|
|
34
38
|
const ref = narrowSchema(node, 'ref')
|
|
@@ -45,16 +49,10 @@ export function syncSchemaRef(node: SchemaNode): SchemaNode {
|
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* - `string`, `uuid`, `email`, `url`, `datetime` are always plain strings.
|
|
51
|
-
* - `date` and `time` are plain strings when their `representation` is `'string'` rather than `'date'`.
|
|
52
|
+
* Type guard that returns `true` when a schema emits as a plain `string` type.
|
|
52
53
|
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* isStringType(createSchema({ type: 'uuid' })) // true
|
|
56
|
-
* isStringType(createSchema({ type: 'date', representation: 'date' })) // false
|
|
57
|
-
* ```
|
|
54
|
+
* Covers `string`, `uuid`, `email`, `url`, and `datetime` types. For `date` and `time`
|
|
55
|
+
* types, returns `true` only when `representation` is `'string'` rather than `'date'`.
|
|
58
56
|
*/
|
|
59
57
|
export function isStringType(node: SchemaNode): boolean {
|
|
60
58
|
if (plainStringTypes.has(node.type)) {
|
|
@@ -72,19 +70,9 @@ export function isStringType(node: SchemaNode): boolean {
|
|
|
72
70
|
/**
|
|
73
71
|
* Applies casing rules to parameter names and returns a new parameter array.
|
|
74
72
|
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* Use this before passing parameters to schema builders so that property keys
|
|
79
|
-
* in generated output match the desired casing while preserving
|
|
80
|
-
* `OperationNode.parameters` for other consumers.
|
|
81
|
-
*
|
|
82
|
-
* @example
|
|
83
|
-
* ```ts
|
|
84
|
-
* const params = [createParameter({ name: 'pet_id', in: 'query', schema: createSchema({ type: 'string' }) })]
|
|
85
|
-
* const cased = caseParams(params, 'camelcase')
|
|
86
|
-
* // cased[0].name === 'petId'
|
|
87
|
-
* ```
|
|
73
|
+
* Use this before passing parameters to schema builders so output property keys match
|
|
74
|
+
* the desired casing while preserving `OperationNode.parameters` for other consumers.
|
|
75
|
+
* The input array is not mutated. When `casing` is not set, the original array is returned unchanged.
|
|
88
76
|
*/
|
|
89
77
|
export function caseParams(params: Array<ParameterNode>, casing: 'camelcase' | undefined): Array<ParameterNode> {
|
|
90
78
|
if (!casing) {
|
|
@@ -305,20 +293,12 @@ function resolveParamsType({
|
|
|
305
293
|
}
|
|
306
294
|
|
|
307
295
|
/**
|
|
308
|
-
* Converts an
|
|
296
|
+
* Converts an `OperationNode` into function parameters for code generation.
|
|
309
297
|
*
|
|
310
|
-
* Centralizes
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
* ```ts
|
|
315
|
-
* const params = createOperationParams(node, {
|
|
316
|
-
* paramsType: 'inline',
|
|
317
|
-
* pathParamsType: 'inline',
|
|
318
|
-
* resolver: tsResolver,
|
|
319
|
-
* extraParams: [createFunctionParameter({ name: 'options', type: createParamsType({ variant: 'reference', name: 'Partial<RequestOptions>' }), default: '{}' })],
|
|
320
|
-
* })
|
|
321
|
-
* ```
|
|
298
|
+
* Centralizes parameter grouping logic for all plugins. Provide a `resolver` for type name resolution
|
|
299
|
+
* and `extraParams` for plugin-specific trailing parameters (e.g., `options` objects).
|
|
300
|
+
* Supports three grouping modes: `object` (single destructured param), `inline` (separate params),
|
|
301
|
+
* and `inlineSpread` (rest parameter). Use `CreateOperationParamsOptions` to fine-tune output.
|
|
322
302
|
*/
|
|
323
303
|
export function createOperationParams(node: OperationNode, options: CreateOperationParamsOptions): FunctionParametersNode {
|
|
324
304
|
const { paramsType, pathParamsType, paramsCasing, resolver, pathParamsDefault, extraParams = [], paramNames, typeWrapper } = options
|
|
@@ -599,9 +579,9 @@ function sortKey(node: { name?: string | Array<unknown>; isTypeOnly?: boolean; p
|
|
|
599
579
|
}
|
|
600
580
|
|
|
601
581
|
/**
|
|
602
|
-
* Deduplicates
|
|
603
|
-
*
|
|
604
|
-
* Unnamed sources are deduplicated by object reference.
|
|
582
|
+
* Deduplicates and merges `SourceNode` objects by `name + isExportable + isTypeOnly`.
|
|
583
|
+
*
|
|
584
|
+
* Unnamed sources are deduplicated by object reference. Returns a deduplicated array in original order.
|
|
605
585
|
*/
|
|
606
586
|
export function combineSources(sources: Array<SourceNode>): Array<SourceNode> {
|
|
607
587
|
const seen = new Map<string, SourceNode>()
|
|
@@ -613,8 +593,10 @@ export function combineSources(sources: Array<SourceNode>): Array<SourceNode> {
|
|
|
613
593
|
}
|
|
614
594
|
|
|
615
595
|
/**
|
|
616
|
-
* Deduplicates and merges
|
|
617
|
-
*
|
|
596
|
+
* Deduplicates and merges `ExportNode` objects by path and type.
|
|
597
|
+
*
|
|
598
|
+
* Named exports with the same path and `isTypeOnly` flag have their names merged into a single export.
|
|
599
|
+
* Non-array exports are deduplicated by exact identity. Returns a sorted, deduplicated array.
|
|
618
600
|
*/
|
|
619
601
|
export function combineExports(exports: Array<ExportNode>): Array<ExportNode> {
|
|
620
602
|
const result: Array<ExportNode> = []
|
|
@@ -658,9 +640,12 @@ export function combineExports(exports: Array<ExportNode>): Array<ExportNode> {
|
|
|
658
640
|
}
|
|
659
641
|
|
|
660
642
|
/**
|
|
661
|
-
* Deduplicates and merges
|
|
662
|
-
*
|
|
663
|
-
*
|
|
643
|
+
* Deduplicates and merges `ImportNode` objects, filtering out unused imports.
|
|
644
|
+
*
|
|
645
|
+
* Retains imports that are referenced in `source` or re-exported. Imports with the same path and
|
|
646
|
+
* `isTypeOnly` flag have their names merged. Returns a sorted, deduplicated, filtered array.
|
|
647
|
+
*
|
|
648
|
+
* @note Use this when combining imports from multiple files to avoid duplicate declarations.
|
|
664
649
|
*/
|
|
665
650
|
export function combineImports(imports: Array<ImportNode>, exports: Array<ExportNode>, source?: string): Array<ImportNode> {
|
|
666
651
|
// Build a lookup of all exported names to retain imports that are re-exported
|
|
@@ -714,11 +699,10 @@ export function combineImports(imports: Array<ImportNode>, exports: Array<Export
|
|
|
714
699
|
}
|
|
715
700
|
|
|
716
701
|
/**
|
|
717
|
-
*
|
|
702
|
+
* Extracts all string content from a `CodeNode` tree recursively.
|
|
718
703
|
*
|
|
719
|
-
*
|
|
720
|
-
*
|
|
721
|
-
* Used by `createFile` to build the full source string for import filtering.
|
|
704
|
+
* Collects text node values, identifier references in string fields (`params`, `generics`, `returnType`, `type`),
|
|
705
|
+
* and nested node content. Used internally to build the full source string for import filtering.
|
|
722
706
|
*/
|
|
723
707
|
export function extractStringsFromNodes(nodes: Array<CodeNode> | undefined): string {
|
|
724
708
|
if (!nodes?.length) return ''
|
|
@@ -743,9 +727,10 @@ export function extractStringsFromNodes(nodes: Array<CodeNode> | undefined): str
|
|
|
743
727
|
}
|
|
744
728
|
|
|
745
729
|
/**
|
|
746
|
-
* Resolves the
|
|
747
|
-
*
|
|
748
|
-
* nodes or when no name can be resolved.
|
|
730
|
+
* Resolves the schema name of a ref node, falling back through `ref` → `name` → nested `schema.name`.
|
|
731
|
+
*
|
|
732
|
+
* Returns `undefined` for non-ref nodes or when no name can be resolved. Use this to get a schema's
|
|
733
|
+
* identifier for type definitions or error messages.
|
|
749
734
|
*
|
|
750
735
|
* @example
|
|
751
736
|
* ```ts
|
|
@@ -761,15 +746,12 @@ export function resolveRefName(node: SchemaNode | undefined): string | undefined
|
|
|
761
746
|
}
|
|
762
747
|
|
|
763
748
|
/**
|
|
764
|
-
*
|
|
765
|
-
* `node` via `ref` edges. Refs are followed by name only — the resolved
|
|
766
|
-
* `node.schema` of a ref is not traversed inline.
|
|
749
|
+
* Collects every named schema referenced (transitively) from a node via ref edges.
|
|
767
750
|
*
|
|
768
|
-
*
|
|
769
|
-
*
|
|
770
|
-
*
|
|
771
|
-
*
|
|
772
|
-
* ```
|
|
751
|
+
* Refs are followed by name only — the resolved `node.schema` is not traversed inline.
|
|
752
|
+
* Use this to determine schema dependencies, build reference graphs, or detect what schemas need to be emitted.
|
|
753
|
+
*
|
|
754
|
+
* @note Returns a Set of schema names for efficient membership testing.
|
|
773
755
|
*/
|
|
774
756
|
export function collectReferencedSchemaNames(node: SchemaNode | undefined, out: Set<string> = new Set()): Set<string> {
|
|
775
757
|
if (!node) return out
|
|
@@ -787,26 +769,13 @@ export function collectReferencedSchemaNames(node: SchemaNode | undefined, out:
|
|
|
787
769
|
}
|
|
788
770
|
|
|
789
771
|
/**
|
|
790
|
-
* Identifies
|
|
791
|
-
* chain — including direct self-loops (e.g. `TreeNode → TreeNode`) and indirect
|
|
792
|
-
* cycles spanning multiple schemas (e.g. `Pet → Cat → Pet`).
|
|
793
|
-
*
|
|
794
|
-
* The returned set contains schema names. Plugins that translate schemas into
|
|
795
|
-
* a host language can use this to wrap recursive positions in a deferred
|
|
796
|
-
* construct (lazy getter, `z.lazy(() => …)`, etc.) and avoid runtime stack
|
|
797
|
-
* overflows when the generated code is executed.
|
|
772
|
+
* Identifies all schemas that participate in circular dependency chains, including direct self-loops.
|
|
798
773
|
*
|
|
799
|
-
*
|
|
800
|
-
*
|
|
801
|
-
* schema graph.
|
|
774
|
+
* Returns a Set of schema names with circular dependencies. Use this to wrap recursive schema positions
|
|
775
|
+
* in deferred constructs (lazy getter, `z.lazy(() => …)`) to prevent infinite recursion when generated code runs.
|
|
776
|
+
* Refs are followed by name only, keeping the algorithm linear in the schema graph size.
|
|
802
777
|
*
|
|
803
|
-
* @
|
|
804
|
-
* ```ts
|
|
805
|
-
* const circular = findCircularSchemas(inputNode.schemas)
|
|
806
|
-
* if (circular.has('Pet')) {
|
|
807
|
-
* // emit lazy wrapper for any property whose schema references Pet
|
|
808
|
-
* }
|
|
809
|
-
* ```
|
|
778
|
+
* @note Call this once on the full schema graph, then use `containsCircularRef()` to check individual schemas.
|
|
810
779
|
*/
|
|
811
780
|
export function findCircularSchemas(schemas: ReadonlyArray<SchemaNode>): Set<string> {
|
|
812
781
|
const graph = new Map<string, Set<string>>()
|
|
@@ -838,21 +807,12 @@ export function findCircularSchemas(schemas: ReadonlyArray<SchemaNode>): Set<str
|
|
|
838
807
|
}
|
|
839
808
|
|
|
840
809
|
/**
|
|
841
|
-
*
|
|
842
|
-
* whose resolved name belongs to `circularSchemas`.
|
|
810
|
+
* Type guard returning `true` when a schema or anything nested within it contains a ref to a circular schema.
|
|
843
811
|
*
|
|
844
|
-
*
|
|
845
|
-
*
|
|
846
|
-
* cycles (e.g. the faker plugin emits `undefined as any` for direct
|
|
847
|
-
* self-recursion but a lazy getter for indirect cycles).
|
|
812
|
+
* Use `excludeName` to ignore refs to specific schemas (useful when self-references are handled separately).
|
|
813
|
+
* Commonly used with `findCircularSchemas()` to detect where lazy wrappers are needed in code generation.
|
|
848
814
|
*
|
|
849
|
-
* @
|
|
850
|
-
* ```ts
|
|
851
|
-
* const circular = findCircularSchemas(schemas)
|
|
852
|
-
* if (containsCircularRef(property.schema, { circularSchemas: circular, excludeName: 'Pet' })) {
|
|
853
|
-
* // emit `get foo() { return fakeCat() }` instead of eager call
|
|
854
|
-
* }
|
|
855
|
-
* ```
|
|
815
|
+
* @note Returns `true` for the first matching circular ref found; use for fast dependency checks.
|
|
856
816
|
*/
|
|
857
817
|
export function containsCircularRef(
|
|
858
818
|
node: SchemaNode | undefined,
|