@kubb/ast 5.0.0-beta.19 → 5.0.0-beta.20
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 +191 -174
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +54 -13
- package/dist/index.js +191 -174
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/factory.ts +1 -0
- package/src/nodes/root.ts +51 -13
- package/src/utils.ts +39 -58
- package/src/visitor.ts +119 -138
package/dist/index.cjs
CHANGED
|
@@ -288,6 +288,46 @@ function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) {
|
|
|
288
288
|
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
|
|
289
289
|
}
|
|
290
290
|
//#endregion
|
|
291
|
+
//#region ../../internals/utils/src/promise.ts
|
|
292
|
+
/**
|
|
293
|
+
* Wraps `factory` with a keyed cache backed by the provided store.
|
|
294
|
+
*
|
|
295
|
+
* Pass a `WeakMap` for object keys (results are GC-eligible when the key is
|
|
296
|
+
* collected) or a `Map` for primitive keys. For multi-argument functions,
|
|
297
|
+
* nest two `memoize` calls — the outer keyed by the first argument, the
|
|
298
|
+
* inner (created once per outer miss) keyed by the second.
|
|
299
|
+
*
|
|
300
|
+
* Because the cache is owned by the caller, it can be shared, inspected, or
|
|
301
|
+
* cleared independently of the memoized function.
|
|
302
|
+
*
|
|
303
|
+
* @example Single WeakMap key
|
|
304
|
+
* ```ts
|
|
305
|
+
* const cache = new WeakMap<SchemaNode, Set<string>>()
|
|
306
|
+
* const getRefs = memoize(cache, (node) => collectRefs(node))
|
|
307
|
+
* ```
|
|
308
|
+
*
|
|
309
|
+
* @example Single Map key (primitive)
|
|
310
|
+
* ```ts
|
|
311
|
+
* const cache = new Map<string, Resolver>()
|
|
312
|
+
* const getResolver = memoize(cache, (name) => buildResolver(name))
|
|
313
|
+
* ```
|
|
314
|
+
*
|
|
315
|
+
* @example Two-level (object + primitive)
|
|
316
|
+
* ```ts
|
|
317
|
+
* const outer = new WeakMap<Params[], Map<string, Params[]>>()
|
|
318
|
+
* const fn = memoize(outer, (params) => memoize(new Map(), (key) => transform(params, key)))
|
|
319
|
+
* fn(params)('camelcase')
|
|
320
|
+
* ```
|
|
321
|
+
*/
|
|
322
|
+
function memoize(store, factory) {
|
|
323
|
+
return (key) => {
|
|
324
|
+
if (store.has(key)) return store.get(key);
|
|
325
|
+
const value = factory(key);
|
|
326
|
+
store.set(key, value);
|
|
327
|
+
return value;
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
//#endregion
|
|
291
331
|
//#region ../../internals/utils/src/reserved.ts
|
|
292
332
|
/**
|
|
293
333
|
* JavaScript and Java reserved words.
|
|
@@ -534,35 +574,39 @@ function createLimit(concurrency) {
|
|
|
534
574
|
* ```
|
|
535
575
|
*/
|
|
536
576
|
function* getChildren(node, recurse) {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
577
|
+
if (node.kind === "Input") {
|
|
578
|
+
yield* node.schemas;
|
|
579
|
+
yield* node.operations;
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
if (node.kind === "Output") return;
|
|
583
|
+
if (node.kind === "Operation") {
|
|
584
|
+
yield* node.parameters;
|
|
585
|
+
if (node.requestBody?.content) {
|
|
586
|
+
for (const c of node.requestBody.content) if (c.schema) yield c.schema;
|
|
587
|
+
}
|
|
588
|
+
yield* node.responses;
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
if (node.kind === "Schema") {
|
|
592
|
+
if (!recurse) return;
|
|
593
|
+
if ("properties" in node && node.properties.length > 0) yield* node.properties;
|
|
594
|
+
if ("items" in node && node.items) yield* node.items;
|
|
595
|
+
if ("members" in node && node.members) yield* node.members;
|
|
596
|
+
if ("additionalProperties" in node && node.additionalProperties && node.additionalProperties !== true) yield node.additionalProperties;
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
if (node.kind === "Property") {
|
|
600
|
+
yield node.schema;
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
if (node.kind === "Parameter") {
|
|
604
|
+
yield node.schema;
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
if (node.kind === "Response") {
|
|
608
|
+
if (node.schema) yield node.schema;
|
|
609
|
+
return;
|
|
566
610
|
}
|
|
567
611
|
}
|
|
568
612
|
/**
|
|
@@ -611,9 +655,6 @@ async function _walk(node, visitor, recurse, limit, parent) {
|
|
|
611
655
|
case "Response":
|
|
612
656
|
await limit(() => visitor.response?.(node, { parent }));
|
|
613
657
|
break;
|
|
614
|
-
case "FunctionParameter":
|
|
615
|
-
case "ParameterGroup":
|
|
616
|
-
case "FunctionParameters": break;
|
|
617
658
|
}
|
|
618
659
|
const children = getChildren(node, recurse);
|
|
619
660
|
for (const child of children) await _walk(child, visitor, recurse, limit, node);
|
|
@@ -621,96 +662,90 @@ async function _walk(node, visitor, recurse, limit, parent) {
|
|
|
621
662
|
function transform(node, options) {
|
|
622
663
|
const { depth, parent, ...visitor } = options;
|
|
623
664
|
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep;
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
}) : void 0
|
|
656
|
-
}))
|
|
657
|
-
} : void 0,
|
|
658
|
-
responses: op.responses.map((r) => transform(r, {
|
|
659
|
-
...options,
|
|
660
|
-
parent: op
|
|
665
|
+
if (node.kind === "Input") {
|
|
666
|
+
const input = visitor.input?.(node, { parent }) ?? node;
|
|
667
|
+
return {
|
|
668
|
+
...input,
|
|
669
|
+
schemas: input.schemas.map((s) => transform(s, {
|
|
670
|
+
...options,
|
|
671
|
+
parent: input
|
|
672
|
+
})),
|
|
673
|
+
operations: input.operations.map((op) => transform(op, {
|
|
674
|
+
...options,
|
|
675
|
+
parent: input
|
|
676
|
+
}))
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
if (node.kind === "Output") return visitor.output?.(node, { parent }) ?? node;
|
|
680
|
+
if (node.kind === "Operation") {
|
|
681
|
+
const op = visitor.operation?.(node, { parent }) ?? node;
|
|
682
|
+
return {
|
|
683
|
+
...op,
|
|
684
|
+
parameters: op.parameters.map((p) => transform(p, {
|
|
685
|
+
...options,
|
|
686
|
+
parent: op
|
|
687
|
+
})),
|
|
688
|
+
requestBody: op.requestBody ? {
|
|
689
|
+
...op.requestBody,
|
|
690
|
+
content: op.requestBody.content?.map((c) => ({
|
|
691
|
+
...c,
|
|
692
|
+
schema: c.schema ? transform(c.schema, {
|
|
693
|
+
...options,
|
|
694
|
+
parent: op
|
|
695
|
+
}) : void 0
|
|
661
696
|
}))
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
case "Schema": {
|
|
665
|
-
const schema = visitor.schema?.(node, { parent }) ?? node;
|
|
666
|
-
const childOptions = {
|
|
697
|
+
} : void 0,
|
|
698
|
+
responses: op.responses.map((r) => transform(r, {
|
|
667
699
|
...options,
|
|
668
|
-
parent:
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
...
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
})
|
|
696
|
-
});
|
|
697
|
-
}
|
|
698
|
-
case "Response": {
|
|
699
|
-
const response = visitor.response?.(node, { parent }) ?? node;
|
|
700
|
-
return {
|
|
701
|
-
...response,
|
|
702
|
-
schema: transform(response.schema, {
|
|
703
|
-
...options,
|
|
704
|
-
parent: response
|
|
705
|
-
})
|
|
706
|
-
};
|
|
707
|
-
}
|
|
708
|
-
case "FunctionParameter":
|
|
709
|
-
case "ParameterGroup":
|
|
710
|
-
case "FunctionParameters":
|
|
711
|
-
case "Type": return node;
|
|
712
|
-
default: return node;
|
|
700
|
+
parent: op
|
|
701
|
+
}))
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
if (node.kind === "Schema") {
|
|
705
|
+
const schema = visitor.schema?.(node, { parent }) ?? node;
|
|
706
|
+
const childOptions = {
|
|
707
|
+
...options,
|
|
708
|
+
parent: schema
|
|
709
|
+
};
|
|
710
|
+
return {
|
|
711
|
+
...schema,
|
|
712
|
+
..."properties" in schema && recurse ? { properties: schema.properties.map((p) => transform(p, childOptions)) } : {},
|
|
713
|
+
..."items" in schema && recurse ? { items: schema.items?.map((i) => transform(i, childOptions)) } : {},
|
|
714
|
+
..."members" in schema && recurse ? { members: schema.members?.map((m) => transform(m, childOptions)) } : {},
|
|
715
|
+
..."additionalProperties" in schema && recurse && schema.additionalProperties && schema.additionalProperties !== true ? { additionalProperties: transform(schema.additionalProperties, childOptions) } : {}
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
if (node.kind === "Property") {
|
|
719
|
+
const prop = visitor.property?.(node, { parent }) ?? node;
|
|
720
|
+
return createProperty({
|
|
721
|
+
...prop,
|
|
722
|
+
schema: transform(prop.schema, {
|
|
723
|
+
...options,
|
|
724
|
+
parent: prop
|
|
725
|
+
})
|
|
726
|
+
});
|
|
713
727
|
}
|
|
728
|
+
if (node.kind === "Parameter") {
|
|
729
|
+
const param = visitor.parameter?.(node, { parent }) ?? node;
|
|
730
|
+
return createParameter({
|
|
731
|
+
...param,
|
|
732
|
+
schema: transform(param.schema, {
|
|
733
|
+
...options,
|
|
734
|
+
parent: param
|
|
735
|
+
})
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
if (node.kind === "Response") {
|
|
739
|
+
const response = visitor.response?.(node, { parent }) ?? node;
|
|
740
|
+
return {
|
|
741
|
+
...response,
|
|
742
|
+
schema: transform(response.schema, {
|
|
743
|
+
...options,
|
|
744
|
+
parent: response
|
|
745
|
+
})
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
return node;
|
|
714
749
|
}
|
|
715
750
|
/**
|
|
716
751
|
* Runs a depth-first synchronous collection pass.
|
|
@@ -758,9 +793,6 @@ function* collectLazy(node, options) {
|
|
|
758
793
|
case "Response":
|
|
759
794
|
v = visitor.response?.(node, { parent });
|
|
760
795
|
break;
|
|
761
|
-
case "FunctionParameter":
|
|
762
|
-
case "ParameterGroup":
|
|
763
|
-
case "FunctionParameters": break;
|
|
764
796
|
}
|
|
765
797
|
if (v !== void 0) yield v;
|
|
766
798
|
for (const child of getChildren(node, recurse)) yield* collectLazy(child, {
|
|
@@ -823,25 +855,16 @@ function isStringType(node) {
|
|
|
823
855
|
* the desired casing while preserving `OperationNode.parameters` for other consumers.
|
|
824
856
|
* The input array is not mutated. When `casing` is not set, the original array is returned unchanged.
|
|
825
857
|
*/
|
|
826
|
-
const
|
|
858
|
+
const caseParamsMemo = memoize(/* @__PURE__ */ new WeakMap(), (params) => memoize(/* @__PURE__ */ new Map(), (casing) => params.map((param) => {
|
|
859
|
+
const transformed = casing === "camelcase" || !isValidVarName(param.name) ? camelCase(param.name) : param.name;
|
|
860
|
+
return {
|
|
861
|
+
...param,
|
|
862
|
+
name: transformed
|
|
863
|
+
};
|
|
864
|
+
})));
|
|
827
865
|
function caseParams(params, casing) {
|
|
828
866
|
if (!casing) return params;
|
|
829
|
-
|
|
830
|
-
if (!byParams) {
|
|
831
|
-
byParams = /* @__PURE__ */ new Map();
|
|
832
|
-
caseParamsCache.set(params, byParams);
|
|
833
|
-
}
|
|
834
|
-
const cached = byParams.get(casing);
|
|
835
|
-
if (cached) return cached;
|
|
836
|
-
const result = params.map((param) => {
|
|
837
|
-
const transformed = casing === "camelcase" || !isValidVarName(param.name) ? camelCase(param.name) : param.name;
|
|
838
|
-
return {
|
|
839
|
-
...param,
|
|
840
|
-
name: transformed
|
|
841
|
-
};
|
|
842
|
-
});
|
|
843
|
-
byParams.set(casing, result);
|
|
844
|
-
return result;
|
|
867
|
+
return caseParamsMemo(params)(casing);
|
|
845
868
|
}
|
|
846
869
|
/**
|
|
847
870
|
* Creates a single-property object schema used as a discriminator literal.
|
|
@@ -1279,10 +1302,7 @@ function resolveRefName(node) {
|
|
|
1279
1302
|
* }
|
|
1280
1303
|
* ```
|
|
1281
1304
|
*/
|
|
1282
|
-
const
|
|
1283
|
-
function collectSchemaRefs(node) {
|
|
1284
|
-
const cached = schemaRefCache.get(node);
|
|
1285
|
-
if (cached) return cached;
|
|
1305
|
+
const collectSchemaRefs = memoize(/* @__PURE__ */ new WeakMap(), (node) => {
|
|
1286
1306
|
const refs = /* @__PURE__ */ new Set();
|
|
1287
1307
|
collect(node, { schema(child) {
|
|
1288
1308
|
if (child.type === "ref") {
|
|
@@ -1290,9 +1310,8 @@ function collectSchemaRefs(node) {
|
|
|
1290
1310
|
if (name) refs.add(name);
|
|
1291
1311
|
}
|
|
1292
1312
|
} });
|
|
1293
|
-
schemaRefCache.set(node, refs);
|
|
1294
1313
|
return refs;
|
|
1295
|
-
}
|
|
1314
|
+
});
|
|
1296
1315
|
function collectReferencedSchemaNames(node, out = /* @__PURE__ */ new Set()) {
|
|
1297
1316
|
if (!node) return out;
|
|
1298
1317
|
for (const name of collectSchemaRefs(node)) out.add(name);
|
|
@@ -1311,10 +1330,10 @@ function collectReferencedSchemaNames(node, out = /* @__PURE__ */ new Set()) {
|
|
|
1311
1330
|
*
|
|
1312
1331
|
* @example Only generate schemas referenced by included operations
|
|
1313
1332
|
* ```ts
|
|
1314
|
-
* const includedOps =
|
|
1315
|
-
* const allowed = collectUsedSchemaNames(includedOps,
|
|
1333
|
+
* const includedOps = operations.filter(op => resolver.resolveOptions(op, { options, include }) !== null)
|
|
1334
|
+
* const allowed = collectUsedSchemaNames(includedOps, schemas)
|
|
1316
1335
|
*
|
|
1317
|
-
* for (const schema of
|
|
1336
|
+
* for (const schema of schemas) {
|
|
1318
1337
|
* if (schema.name && !allowed.has(schema.name)) continue
|
|
1319
1338
|
* // … generate schema
|
|
1320
1339
|
* }
|
|
@@ -1322,19 +1341,12 @@ function collectReferencedSchemaNames(node, out = /* @__PURE__ */ new Set()) {
|
|
|
1322
1341
|
*
|
|
1323
1342
|
* @example Check whether a specific schema is needed
|
|
1324
1343
|
* ```ts
|
|
1325
|
-
* const allowed = collectUsedSchemaNames(includedOps,
|
|
1344
|
+
* const allowed = collectUsedSchemaNames(includedOps, schemas)
|
|
1326
1345
|
* allowed.has('OrderStatus') // false when no included operation references OrderStatus
|
|
1327
1346
|
* ```
|
|
1328
1347
|
*/
|
|
1329
|
-
const
|
|
1330
|
-
function
|
|
1331
|
-
let byOps = usedSchemaNamesCache.get(operations);
|
|
1332
|
-
if (!byOps) {
|
|
1333
|
-
byOps = /* @__PURE__ */ new WeakMap();
|
|
1334
|
-
usedSchemaNamesCache.set(operations, byOps);
|
|
1335
|
-
}
|
|
1336
|
-
const cached = byOps.get(schemas);
|
|
1337
|
-
if (cached) return cached;
|
|
1348
|
+
const collectUsedSchemaNamesMemo = memoize(/* @__PURE__ */ new WeakMap(), (ops) => memoize(/* @__PURE__ */ new WeakMap(), (schemas) => computeUsedSchemaNames(ops, schemas)));
|
|
1349
|
+
function computeUsedSchemaNames(operations, schemas) {
|
|
1338
1350
|
const schemaMap = /* @__PURE__ */ new Map();
|
|
1339
1351
|
for (const schema of schemas) if (schema.name) schemaMap.set(schema.name, schema);
|
|
1340
1352
|
const result = /* @__PURE__ */ new Set();
|
|
@@ -1350,24 +1362,13 @@ function collectUsedSchemaNames(operations, schemas) {
|
|
|
1350
1362
|
depth: "shallow",
|
|
1351
1363
|
schema: (node) => node
|
|
1352
1364
|
})) visitSchema(schema);
|
|
1353
|
-
byOps.set(schemas, result);
|
|
1354
1365
|
return result;
|
|
1355
1366
|
}
|
|
1367
|
+
function collectUsedSchemaNames(operations, schemas) {
|
|
1368
|
+
return collectUsedSchemaNamesMemo(operations)(schemas);
|
|
1369
|
+
}
|
|
1356
1370
|
const EMPTY_CIRCULAR_SET = /* @__PURE__ */ new Set();
|
|
1357
|
-
const
|
|
1358
|
-
/**
|
|
1359
|
-
* Identifies all schemas that participate in circular dependency chains, including direct self-loops.
|
|
1360
|
-
*
|
|
1361
|
-
* Returns a Set of schema names with circular dependencies. Use this to wrap recursive schema positions
|
|
1362
|
-
* in deferred constructs (lazy getter, `z.lazy(() => …)`) to prevent infinite recursion when generated code runs.
|
|
1363
|
-
* Refs are followed by name only, keeping the algorithm linear in the schema graph size.
|
|
1364
|
-
*
|
|
1365
|
-
* @note Call this once on the full schema graph, then use `containsCircularRef()` to check individual schemas.
|
|
1366
|
-
*/
|
|
1367
|
-
function findCircularSchemas(schemas) {
|
|
1368
|
-
if (schemas.length === 0) return EMPTY_CIRCULAR_SET;
|
|
1369
|
-
const cached = circularSchemaCache.get(schemas);
|
|
1370
|
-
if (cached) return cached;
|
|
1371
|
+
const findCircularSchemasMemo = memoize(/* @__PURE__ */ new WeakMap(), (schemas) => {
|
|
1371
1372
|
const graph = /* @__PURE__ */ new Map();
|
|
1372
1373
|
for (const schema of schemas) {
|
|
1373
1374
|
if (!schema.name) continue;
|
|
@@ -1389,8 +1390,20 @@ function findCircularSchemas(schemas) {
|
|
|
1389
1390
|
if (next) for (const r of next) stack.push(r);
|
|
1390
1391
|
}
|
|
1391
1392
|
}
|
|
1392
|
-
circularSchemaCache.set(schemas, circular);
|
|
1393
1393
|
return circular;
|
|
1394
|
+
});
|
|
1395
|
+
/**
|
|
1396
|
+
* Identifies all schemas that participate in circular dependency chains, including direct self-loops.
|
|
1397
|
+
*
|
|
1398
|
+
* Returns a Set of schema names with circular dependencies. Use this to wrap recursive schema positions
|
|
1399
|
+
* in deferred constructs (lazy getter, `z.lazy(() => …)`) to prevent infinite recursion when generated code runs.
|
|
1400
|
+
* Refs are followed by name only, keeping the algorithm linear in the schema graph size.
|
|
1401
|
+
*
|
|
1402
|
+
* @note Call this once on the full schema graph, then use `containsCircularRef()` to check individual schemas.
|
|
1403
|
+
*/
|
|
1404
|
+
function findCircularSchemas(schemas) {
|
|
1405
|
+
if (schemas.length === 0) return EMPTY_CIRCULAR_SET;
|
|
1406
|
+
return findCircularSchemasMemo(schemas);
|
|
1394
1407
|
}
|
|
1395
1408
|
/**
|
|
1396
1409
|
* Type guard returning `true` when a schema or anything nested within it contains a ref to a circular schema.
|
|
@@ -1444,6 +1457,10 @@ function createInput(overrides = {}) {
|
|
|
1444
1457
|
return {
|
|
1445
1458
|
schemas: [],
|
|
1446
1459
|
operations: [],
|
|
1460
|
+
meta: {
|
|
1461
|
+
circularNames: [],
|
|
1462
|
+
enumNames: []
|
|
1463
|
+
},
|
|
1447
1464
|
...overrides,
|
|
1448
1465
|
kind: "Input"
|
|
1449
1466
|
};
|