@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.d.ts
CHANGED
|
@@ -1830,32 +1830,62 @@ type OutputNode = BaseNode & {
|
|
|
1830
1830
|
//#endregion
|
|
1831
1831
|
//#region src/nodes/root.d.ts
|
|
1832
1832
|
/**
|
|
1833
|
-
*
|
|
1834
|
-
*
|
|
1833
|
+
* Metadata for an API document, populated by the adapter and available to every generator.
|
|
1834
|
+
*
|
|
1835
|
+
* All fields are plain JSON-serializable values — no `Set`, no `Map`, no class instances.
|
|
1836
|
+
* Computed fields (`circularNames`, `enumNames`) are pre-calculated once during the adapter
|
|
1837
|
+
* pre-scan so generators never need to iterate the full schema list themselves.
|
|
1835
1838
|
*
|
|
1836
1839
|
* @example
|
|
1837
1840
|
* ```ts
|
|
1838
|
-
* const meta: InputMeta = { title: 'Pet
|
|
1841
|
+
* const meta: InputMeta = { title: 'Pet Store', version: '1.0.0', baseURL: 'https://petstore.swagger.io/v2', circularNames: [], enumNames: [] }
|
|
1839
1842
|
* ```
|
|
1840
1843
|
*/
|
|
1841
1844
|
type InputMeta = {
|
|
1842
1845
|
/**
|
|
1843
|
-
* API title
|
|
1846
|
+
* API title from `info.title` in the source document.
|
|
1844
1847
|
*/
|
|
1845
1848
|
title?: string;
|
|
1846
1849
|
/**
|
|
1847
|
-
* API description
|
|
1850
|
+
* API description from `info.description` in the source document.
|
|
1848
1851
|
*/
|
|
1849
1852
|
description?: string;
|
|
1850
1853
|
/**
|
|
1851
|
-
* API version string
|
|
1854
|
+
* API version string from `info.version` in the source document.
|
|
1852
1855
|
*/
|
|
1853
1856
|
version?: string;
|
|
1854
1857
|
/**
|
|
1855
|
-
* Resolved
|
|
1856
|
-
* For OpenAPI and AsyncAPI, this comes from the selected server URL.
|
|
1858
|
+
* Resolved base URL from the first matching server entry in the source document.
|
|
1857
1859
|
*/
|
|
1858
1860
|
baseURL?: string;
|
|
1861
|
+
/**
|
|
1862
|
+
* Names of schemas that participate in a circular reference chain.
|
|
1863
|
+
* Computed once during the adapter pre-scan — use this instead of calling
|
|
1864
|
+
* `findCircularSchemas` per generator call.
|
|
1865
|
+
*
|
|
1866
|
+
* Convert to a `Set` once at the start of a generator, not per-schema,
|
|
1867
|
+
* to keep lookup O(1) without repeated allocations.
|
|
1868
|
+
*
|
|
1869
|
+
* @example Wrap a circular schema in z.lazy()
|
|
1870
|
+
* ```ts
|
|
1871
|
+
* const circular = new Set(meta.circularNames)
|
|
1872
|
+
* if (circular.has(schema.name)) { ... }
|
|
1873
|
+
* ```
|
|
1874
|
+
*/
|
|
1875
|
+
circularNames: readonly string[];
|
|
1876
|
+
/**
|
|
1877
|
+
* Names of schemas whose type is `enum`.
|
|
1878
|
+
* Computed once during the adapter pre-scan — use this instead of filtering
|
|
1879
|
+
* schemas per generator call.
|
|
1880
|
+
*
|
|
1881
|
+
* Convert to a `Set` once at the start of a generator when you need repeated
|
|
1882
|
+
* membership checks, rather than calling `.includes()` per schema.
|
|
1883
|
+
*
|
|
1884
|
+
* @example Check if a referenced schema is an enum
|
|
1885
|
+
* `const enums = new Set(meta.enumNames)`
|
|
1886
|
+
* `const isEnum = enums.has(schemaName)`
|
|
1887
|
+
*/
|
|
1888
|
+
enumNames: readonly string[];
|
|
1859
1889
|
};
|
|
1860
1890
|
/**
|
|
1861
1891
|
* Input AST node that contains all schemas and operations for one API document.
|
|
@@ -1884,9 +1914,9 @@ type InputNode = BaseNode & {
|
|
|
1884
1914
|
*/
|
|
1885
1915
|
operations: Array<OperationNode>;
|
|
1886
1916
|
/**
|
|
1887
|
-
*
|
|
1917
|
+
* Document metadata populated by the adapter.
|
|
1888
1918
|
*/
|
|
1889
|
-
meta
|
|
1919
|
+
meta: InputMeta;
|
|
1890
1920
|
};
|
|
1891
1921
|
/**
|
|
1892
1922
|
* Streaming variant of `InputNode` for memory-efficient processing of large API specs.
|
|
@@ -1903,9 +1933,20 @@ type InputNode = BaseNode & {
|
|
|
1903
1933
|
* ```
|
|
1904
1934
|
*/
|
|
1905
1935
|
type InputStreamNode = {
|
|
1906
|
-
kind: 'Input';
|
|
1907
|
-
|
|
1908
|
-
|
|
1936
|
+
kind: 'Input';
|
|
1937
|
+
/**
|
|
1938
|
+
* Lazily parsed schema nodes. Each `for await` creates a fresh parse pass, so
|
|
1939
|
+
* multiple plugins can iterate independently without sharing state.
|
|
1940
|
+
*/
|
|
1941
|
+
schemas: AsyncIterable<SchemaNode>;
|
|
1942
|
+
/**
|
|
1943
|
+
* Lazily parsed operation nodes. Each `for await` creates a fresh parse pass, so
|
|
1944
|
+
* multiple plugins can iterate independently without sharing state.
|
|
1945
|
+
*/
|
|
1946
|
+
operations: AsyncIterable<OperationNode>;
|
|
1947
|
+
/**
|
|
1948
|
+
* Document metadata available immediately, before the first yielded node.
|
|
1949
|
+
*/
|
|
1909
1950
|
meta?: InputMeta;
|
|
1910
1951
|
};
|
|
1911
1952
|
//#endregion
|
package/dist/index.js
CHANGED
|
@@ -265,6 +265,46 @@ function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) {
|
|
|
265
265
|
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
|
|
266
266
|
}
|
|
267
267
|
//#endregion
|
|
268
|
+
//#region ../../internals/utils/src/promise.ts
|
|
269
|
+
/**
|
|
270
|
+
* Wraps `factory` with a keyed cache backed by the provided store.
|
|
271
|
+
*
|
|
272
|
+
* Pass a `WeakMap` for object keys (results are GC-eligible when the key is
|
|
273
|
+
* collected) or a `Map` for primitive keys. For multi-argument functions,
|
|
274
|
+
* nest two `memoize` calls — the outer keyed by the first argument, the
|
|
275
|
+
* inner (created once per outer miss) keyed by the second.
|
|
276
|
+
*
|
|
277
|
+
* Because the cache is owned by the caller, it can be shared, inspected, or
|
|
278
|
+
* cleared independently of the memoized function.
|
|
279
|
+
*
|
|
280
|
+
* @example Single WeakMap key
|
|
281
|
+
* ```ts
|
|
282
|
+
* const cache = new WeakMap<SchemaNode, Set<string>>()
|
|
283
|
+
* const getRefs = memoize(cache, (node) => collectRefs(node))
|
|
284
|
+
* ```
|
|
285
|
+
*
|
|
286
|
+
* @example Single Map key (primitive)
|
|
287
|
+
* ```ts
|
|
288
|
+
* const cache = new Map<string, Resolver>()
|
|
289
|
+
* const getResolver = memoize(cache, (name) => buildResolver(name))
|
|
290
|
+
* ```
|
|
291
|
+
*
|
|
292
|
+
* @example Two-level (object + primitive)
|
|
293
|
+
* ```ts
|
|
294
|
+
* const outer = new WeakMap<Params[], Map<string, Params[]>>()
|
|
295
|
+
* const fn = memoize(outer, (params) => memoize(new Map(), (key) => transform(params, key)))
|
|
296
|
+
* fn(params)('camelcase')
|
|
297
|
+
* ```
|
|
298
|
+
*/
|
|
299
|
+
function memoize(store, factory) {
|
|
300
|
+
return (key) => {
|
|
301
|
+
if (store.has(key)) return store.get(key);
|
|
302
|
+
const value = factory(key);
|
|
303
|
+
store.set(key, value);
|
|
304
|
+
return value;
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
//#endregion
|
|
268
308
|
//#region ../../internals/utils/src/reserved.ts
|
|
269
309
|
/**
|
|
270
310
|
* JavaScript and Java reserved words.
|
|
@@ -511,35 +551,39 @@ function createLimit(concurrency) {
|
|
|
511
551
|
* ```
|
|
512
552
|
*/
|
|
513
553
|
function* getChildren(node, recurse) {
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
554
|
+
if (node.kind === "Input") {
|
|
555
|
+
yield* node.schemas;
|
|
556
|
+
yield* node.operations;
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
if (node.kind === "Output") return;
|
|
560
|
+
if (node.kind === "Operation") {
|
|
561
|
+
yield* node.parameters;
|
|
562
|
+
if (node.requestBody?.content) {
|
|
563
|
+
for (const c of node.requestBody.content) if (c.schema) yield c.schema;
|
|
564
|
+
}
|
|
565
|
+
yield* node.responses;
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
if (node.kind === "Schema") {
|
|
569
|
+
if (!recurse) return;
|
|
570
|
+
if ("properties" in node && node.properties.length > 0) yield* node.properties;
|
|
571
|
+
if ("items" in node && node.items) yield* node.items;
|
|
572
|
+
if ("members" in node && node.members) yield* node.members;
|
|
573
|
+
if ("additionalProperties" in node && node.additionalProperties && node.additionalProperties !== true) yield node.additionalProperties;
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
if (node.kind === "Property") {
|
|
577
|
+
yield node.schema;
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
if (node.kind === "Parameter") {
|
|
581
|
+
yield node.schema;
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
if (node.kind === "Response") {
|
|
585
|
+
if (node.schema) yield node.schema;
|
|
586
|
+
return;
|
|
543
587
|
}
|
|
544
588
|
}
|
|
545
589
|
/**
|
|
@@ -588,9 +632,6 @@ async function _walk(node, visitor, recurse, limit, parent) {
|
|
|
588
632
|
case "Response":
|
|
589
633
|
await limit(() => visitor.response?.(node, { parent }));
|
|
590
634
|
break;
|
|
591
|
-
case "FunctionParameter":
|
|
592
|
-
case "ParameterGroup":
|
|
593
|
-
case "FunctionParameters": break;
|
|
594
635
|
}
|
|
595
636
|
const children = getChildren(node, recurse);
|
|
596
637
|
for (const child of children) await _walk(child, visitor, recurse, limit, node);
|
|
@@ -598,96 +639,90 @@ async function _walk(node, visitor, recurse, limit, parent) {
|
|
|
598
639
|
function transform(node, options) {
|
|
599
640
|
const { depth, parent, ...visitor } = options;
|
|
600
641
|
const recurse = (depth ?? visitorDepths.deep) === visitorDepths.deep;
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
}) : void 0
|
|
633
|
-
}))
|
|
634
|
-
} : void 0,
|
|
635
|
-
responses: op.responses.map((r) => transform(r, {
|
|
636
|
-
...options,
|
|
637
|
-
parent: op
|
|
642
|
+
if (node.kind === "Input") {
|
|
643
|
+
const input = visitor.input?.(node, { parent }) ?? node;
|
|
644
|
+
return {
|
|
645
|
+
...input,
|
|
646
|
+
schemas: input.schemas.map((s) => transform(s, {
|
|
647
|
+
...options,
|
|
648
|
+
parent: input
|
|
649
|
+
})),
|
|
650
|
+
operations: input.operations.map((op) => transform(op, {
|
|
651
|
+
...options,
|
|
652
|
+
parent: input
|
|
653
|
+
}))
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
if (node.kind === "Output") return visitor.output?.(node, { parent }) ?? node;
|
|
657
|
+
if (node.kind === "Operation") {
|
|
658
|
+
const op = visitor.operation?.(node, { parent }) ?? node;
|
|
659
|
+
return {
|
|
660
|
+
...op,
|
|
661
|
+
parameters: op.parameters.map((p) => transform(p, {
|
|
662
|
+
...options,
|
|
663
|
+
parent: op
|
|
664
|
+
})),
|
|
665
|
+
requestBody: op.requestBody ? {
|
|
666
|
+
...op.requestBody,
|
|
667
|
+
content: op.requestBody.content?.map((c) => ({
|
|
668
|
+
...c,
|
|
669
|
+
schema: c.schema ? transform(c.schema, {
|
|
670
|
+
...options,
|
|
671
|
+
parent: op
|
|
672
|
+
}) : void 0
|
|
638
673
|
}))
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
case "Schema": {
|
|
642
|
-
const schema = visitor.schema?.(node, { parent }) ?? node;
|
|
643
|
-
const childOptions = {
|
|
674
|
+
} : void 0,
|
|
675
|
+
responses: op.responses.map((r) => transform(r, {
|
|
644
676
|
...options,
|
|
645
|
-
parent:
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
...
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
})
|
|
673
|
-
});
|
|
674
|
-
}
|
|
675
|
-
case "Response": {
|
|
676
|
-
const response = visitor.response?.(node, { parent }) ?? node;
|
|
677
|
-
return {
|
|
678
|
-
...response,
|
|
679
|
-
schema: transform(response.schema, {
|
|
680
|
-
...options,
|
|
681
|
-
parent: response
|
|
682
|
-
})
|
|
683
|
-
};
|
|
684
|
-
}
|
|
685
|
-
case "FunctionParameter":
|
|
686
|
-
case "ParameterGroup":
|
|
687
|
-
case "FunctionParameters":
|
|
688
|
-
case "Type": return node;
|
|
689
|
-
default: return node;
|
|
677
|
+
parent: op
|
|
678
|
+
}))
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
if (node.kind === "Schema") {
|
|
682
|
+
const schema = visitor.schema?.(node, { parent }) ?? node;
|
|
683
|
+
const childOptions = {
|
|
684
|
+
...options,
|
|
685
|
+
parent: schema
|
|
686
|
+
};
|
|
687
|
+
return {
|
|
688
|
+
...schema,
|
|
689
|
+
..."properties" in schema && recurse ? { properties: schema.properties.map((p) => transform(p, childOptions)) } : {},
|
|
690
|
+
..."items" in schema && recurse ? { items: schema.items?.map((i) => transform(i, childOptions)) } : {},
|
|
691
|
+
..."members" in schema && recurse ? { members: schema.members?.map((m) => transform(m, childOptions)) } : {},
|
|
692
|
+
..."additionalProperties" in schema && recurse && schema.additionalProperties && schema.additionalProperties !== true ? { additionalProperties: transform(schema.additionalProperties, childOptions) } : {}
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
if (node.kind === "Property") {
|
|
696
|
+
const prop = visitor.property?.(node, { parent }) ?? node;
|
|
697
|
+
return createProperty({
|
|
698
|
+
...prop,
|
|
699
|
+
schema: transform(prop.schema, {
|
|
700
|
+
...options,
|
|
701
|
+
parent: prop
|
|
702
|
+
})
|
|
703
|
+
});
|
|
690
704
|
}
|
|
705
|
+
if (node.kind === "Parameter") {
|
|
706
|
+
const param = visitor.parameter?.(node, { parent }) ?? node;
|
|
707
|
+
return createParameter({
|
|
708
|
+
...param,
|
|
709
|
+
schema: transform(param.schema, {
|
|
710
|
+
...options,
|
|
711
|
+
parent: param
|
|
712
|
+
})
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
if (node.kind === "Response") {
|
|
716
|
+
const response = visitor.response?.(node, { parent }) ?? node;
|
|
717
|
+
return {
|
|
718
|
+
...response,
|
|
719
|
+
schema: transform(response.schema, {
|
|
720
|
+
...options,
|
|
721
|
+
parent: response
|
|
722
|
+
})
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
return node;
|
|
691
726
|
}
|
|
692
727
|
/**
|
|
693
728
|
* Runs a depth-first synchronous collection pass.
|
|
@@ -735,9 +770,6 @@ function* collectLazy(node, options) {
|
|
|
735
770
|
case "Response":
|
|
736
771
|
v = visitor.response?.(node, { parent });
|
|
737
772
|
break;
|
|
738
|
-
case "FunctionParameter":
|
|
739
|
-
case "ParameterGroup":
|
|
740
|
-
case "FunctionParameters": break;
|
|
741
773
|
}
|
|
742
774
|
if (v !== void 0) yield v;
|
|
743
775
|
for (const child of getChildren(node, recurse)) yield* collectLazy(child, {
|
|
@@ -800,25 +832,16 @@ function isStringType(node) {
|
|
|
800
832
|
* the desired casing while preserving `OperationNode.parameters` for other consumers.
|
|
801
833
|
* The input array is not mutated. When `casing` is not set, the original array is returned unchanged.
|
|
802
834
|
*/
|
|
803
|
-
const
|
|
835
|
+
const caseParamsMemo = memoize(/* @__PURE__ */ new WeakMap(), (params) => memoize(/* @__PURE__ */ new Map(), (casing) => params.map((param) => {
|
|
836
|
+
const transformed = casing === "camelcase" || !isValidVarName(param.name) ? camelCase(param.name) : param.name;
|
|
837
|
+
return {
|
|
838
|
+
...param,
|
|
839
|
+
name: transformed
|
|
840
|
+
};
|
|
841
|
+
})));
|
|
804
842
|
function caseParams(params, casing) {
|
|
805
843
|
if (!casing) return params;
|
|
806
|
-
|
|
807
|
-
if (!byParams) {
|
|
808
|
-
byParams = /* @__PURE__ */ new Map();
|
|
809
|
-
caseParamsCache.set(params, byParams);
|
|
810
|
-
}
|
|
811
|
-
const cached = byParams.get(casing);
|
|
812
|
-
if (cached) return cached;
|
|
813
|
-
const result = params.map((param) => {
|
|
814
|
-
const transformed = casing === "camelcase" || !isValidVarName(param.name) ? camelCase(param.name) : param.name;
|
|
815
|
-
return {
|
|
816
|
-
...param,
|
|
817
|
-
name: transformed
|
|
818
|
-
};
|
|
819
|
-
});
|
|
820
|
-
byParams.set(casing, result);
|
|
821
|
-
return result;
|
|
844
|
+
return caseParamsMemo(params)(casing);
|
|
822
845
|
}
|
|
823
846
|
/**
|
|
824
847
|
* Creates a single-property object schema used as a discriminator literal.
|
|
@@ -1256,10 +1279,7 @@ function resolveRefName(node) {
|
|
|
1256
1279
|
* }
|
|
1257
1280
|
* ```
|
|
1258
1281
|
*/
|
|
1259
|
-
const
|
|
1260
|
-
function collectSchemaRefs(node) {
|
|
1261
|
-
const cached = schemaRefCache.get(node);
|
|
1262
|
-
if (cached) return cached;
|
|
1282
|
+
const collectSchemaRefs = memoize(/* @__PURE__ */ new WeakMap(), (node) => {
|
|
1263
1283
|
const refs = /* @__PURE__ */ new Set();
|
|
1264
1284
|
collect(node, { schema(child) {
|
|
1265
1285
|
if (child.type === "ref") {
|
|
@@ -1267,9 +1287,8 @@ function collectSchemaRefs(node) {
|
|
|
1267
1287
|
if (name) refs.add(name);
|
|
1268
1288
|
}
|
|
1269
1289
|
} });
|
|
1270
|
-
schemaRefCache.set(node, refs);
|
|
1271
1290
|
return refs;
|
|
1272
|
-
}
|
|
1291
|
+
});
|
|
1273
1292
|
function collectReferencedSchemaNames(node, out = /* @__PURE__ */ new Set()) {
|
|
1274
1293
|
if (!node) return out;
|
|
1275
1294
|
for (const name of collectSchemaRefs(node)) out.add(name);
|
|
@@ -1288,10 +1307,10 @@ function collectReferencedSchemaNames(node, out = /* @__PURE__ */ new Set()) {
|
|
|
1288
1307
|
*
|
|
1289
1308
|
* @example Only generate schemas referenced by included operations
|
|
1290
1309
|
* ```ts
|
|
1291
|
-
* const includedOps =
|
|
1292
|
-
* const allowed = collectUsedSchemaNames(includedOps,
|
|
1310
|
+
* const includedOps = operations.filter(op => resolver.resolveOptions(op, { options, include }) !== null)
|
|
1311
|
+
* const allowed = collectUsedSchemaNames(includedOps, schemas)
|
|
1293
1312
|
*
|
|
1294
|
-
* for (const schema of
|
|
1313
|
+
* for (const schema of schemas) {
|
|
1295
1314
|
* if (schema.name && !allowed.has(schema.name)) continue
|
|
1296
1315
|
* // … generate schema
|
|
1297
1316
|
* }
|
|
@@ -1299,19 +1318,12 @@ function collectReferencedSchemaNames(node, out = /* @__PURE__ */ new Set()) {
|
|
|
1299
1318
|
*
|
|
1300
1319
|
* @example Check whether a specific schema is needed
|
|
1301
1320
|
* ```ts
|
|
1302
|
-
* const allowed = collectUsedSchemaNames(includedOps,
|
|
1321
|
+
* const allowed = collectUsedSchemaNames(includedOps, schemas)
|
|
1303
1322
|
* allowed.has('OrderStatus') // false when no included operation references OrderStatus
|
|
1304
1323
|
* ```
|
|
1305
1324
|
*/
|
|
1306
|
-
const
|
|
1307
|
-
function
|
|
1308
|
-
let byOps = usedSchemaNamesCache.get(operations);
|
|
1309
|
-
if (!byOps) {
|
|
1310
|
-
byOps = /* @__PURE__ */ new WeakMap();
|
|
1311
|
-
usedSchemaNamesCache.set(operations, byOps);
|
|
1312
|
-
}
|
|
1313
|
-
const cached = byOps.get(schemas);
|
|
1314
|
-
if (cached) return cached;
|
|
1325
|
+
const collectUsedSchemaNamesMemo = memoize(/* @__PURE__ */ new WeakMap(), (ops) => memoize(/* @__PURE__ */ new WeakMap(), (schemas) => computeUsedSchemaNames(ops, schemas)));
|
|
1326
|
+
function computeUsedSchemaNames(operations, schemas) {
|
|
1315
1327
|
const schemaMap = /* @__PURE__ */ new Map();
|
|
1316
1328
|
for (const schema of schemas) if (schema.name) schemaMap.set(schema.name, schema);
|
|
1317
1329
|
const result = /* @__PURE__ */ new Set();
|
|
@@ -1327,24 +1339,13 @@ function collectUsedSchemaNames(operations, schemas) {
|
|
|
1327
1339
|
depth: "shallow",
|
|
1328
1340
|
schema: (node) => node
|
|
1329
1341
|
})) visitSchema(schema);
|
|
1330
|
-
byOps.set(schemas, result);
|
|
1331
1342
|
return result;
|
|
1332
1343
|
}
|
|
1344
|
+
function collectUsedSchemaNames(operations, schemas) {
|
|
1345
|
+
return collectUsedSchemaNamesMemo(operations)(schemas);
|
|
1346
|
+
}
|
|
1333
1347
|
const EMPTY_CIRCULAR_SET = /* @__PURE__ */ new Set();
|
|
1334
|
-
const
|
|
1335
|
-
/**
|
|
1336
|
-
* Identifies all schemas that participate in circular dependency chains, including direct self-loops.
|
|
1337
|
-
*
|
|
1338
|
-
* Returns a Set of schema names with circular dependencies. Use this to wrap recursive schema positions
|
|
1339
|
-
* in deferred constructs (lazy getter, `z.lazy(() => …)`) to prevent infinite recursion when generated code runs.
|
|
1340
|
-
* Refs are followed by name only, keeping the algorithm linear in the schema graph size.
|
|
1341
|
-
*
|
|
1342
|
-
* @note Call this once on the full schema graph, then use `containsCircularRef()` to check individual schemas.
|
|
1343
|
-
*/
|
|
1344
|
-
function findCircularSchemas(schemas) {
|
|
1345
|
-
if (schemas.length === 0) return EMPTY_CIRCULAR_SET;
|
|
1346
|
-
const cached = circularSchemaCache.get(schemas);
|
|
1347
|
-
if (cached) return cached;
|
|
1348
|
+
const findCircularSchemasMemo = memoize(/* @__PURE__ */ new WeakMap(), (schemas) => {
|
|
1348
1349
|
const graph = /* @__PURE__ */ new Map();
|
|
1349
1350
|
for (const schema of schemas) {
|
|
1350
1351
|
if (!schema.name) continue;
|
|
@@ -1366,8 +1367,20 @@ function findCircularSchemas(schemas) {
|
|
|
1366
1367
|
if (next) for (const r of next) stack.push(r);
|
|
1367
1368
|
}
|
|
1368
1369
|
}
|
|
1369
|
-
circularSchemaCache.set(schemas, circular);
|
|
1370
1370
|
return circular;
|
|
1371
|
+
});
|
|
1372
|
+
/**
|
|
1373
|
+
* Identifies all schemas that participate in circular dependency chains, including direct self-loops.
|
|
1374
|
+
*
|
|
1375
|
+
* Returns a Set of schema names with circular dependencies. Use this to wrap recursive schema positions
|
|
1376
|
+
* in deferred constructs (lazy getter, `z.lazy(() => …)`) to prevent infinite recursion when generated code runs.
|
|
1377
|
+
* Refs are followed by name only, keeping the algorithm linear in the schema graph size.
|
|
1378
|
+
*
|
|
1379
|
+
* @note Call this once on the full schema graph, then use `containsCircularRef()` to check individual schemas.
|
|
1380
|
+
*/
|
|
1381
|
+
function findCircularSchemas(schemas) {
|
|
1382
|
+
if (schemas.length === 0) return EMPTY_CIRCULAR_SET;
|
|
1383
|
+
return findCircularSchemasMemo(schemas);
|
|
1371
1384
|
}
|
|
1372
1385
|
/**
|
|
1373
1386
|
* Type guard returning `true` when a schema or anything nested within it contains a ref to a circular schema.
|
|
@@ -1421,6 +1434,10 @@ function createInput(overrides = {}) {
|
|
|
1421
1434
|
return {
|
|
1422
1435
|
schemas: [],
|
|
1423
1436
|
operations: [],
|
|
1437
|
+
meta: {
|
|
1438
|
+
circularNames: [],
|
|
1439
|
+
enumNames: []
|
|
1440
|
+
},
|
|
1424
1441
|
...overrides,
|
|
1425
1442
|
kind: "Input"
|
|
1426
1443
|
};
|