@kubb/ast 5.0.0-beta.99 → 5.0.0

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/README.md CHANGED
@@ -30,15 +30,13 @@ Defines the node tree, visitor pattern, factory functions, and type guards used
30
30
 
31
31
  | Path | Contents |
32
32
  | ------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
33
- | `@kubb/ast` | Runtime: node definitions, guards, visitor, macro engine, string and ref helpers, constants |
33
+ | `@kubb/ast` | Runtime: node definitions, guards, visitor, macro engine, constants |
34
34
  | `ast.factory` (via `@kubb/ast`) | Node constructors (`createSchema`, `createFile`, and friends), the `ts.factory` analogue |
35
35
  | `@kubb/ast/types` | Types only: all node interfaces, type aliases, visitor types |
36
36
  | `kubb/kit` | Re-exports the `ast` and `factory` namespaces, the way most Kubb code reaches the AST without a direct dependency |
37
37
 
38
38
  `@kubb/ast` is an internal library. Inside the Kubb ecosystem the whole surface travels on the `ast` namespace from `kubb/kit`, so plugins and generators reach it there instead of depending on this package directly. The examples below import from `@kubb/ast` for clarity; through `kubb/kit` the same calls read as `ast.walk`, `ast.factory.createSchema`, and so on.
39
39
 
40
- The macro presets (`macroDiscriminatorEnum`, `macroSimplifyUnion`, `macroEnumName`) and the string, identifier, and ref helpers live on the root `@kubb/ast` export. They no longer ship as separate `@kubb/ast/macros` and `@kubb/ast/utils` subpaths.
41
-
42
40
  ## Node tree
43
41
 
44
42
  ```
@@ -94,14 +92,7 @@ const root = createInput({
94
92
  ### Visitor
95
93
 
96
94
  ```ts
97
- import { walk, transform, collect } from '@kubb/ast'
98
-
99
- // Side effects
100
- await walk(root, {
101
- schema(node) {
102
- console.log(node.type)
103
- },
104
- })
95
+ import { collectSync, transform } from '@kubb/ast'
105
96
 
106
97
  // Immutable transformation
107
98
  const updated = transform(root, {
@@ -111,7 +102,7 @@ const updated = transform(root, {
111
102
  })
112
103
 
113
104
  // Extraction
114
- const types = collect<string>(root, {
105
+ const types = collectSync<string>(root, {
115
106
  schema(node) {
116
107
  return node.type
117
108
  },
@@ -135,9 +126,9 @@ function process(node: Node) {
135
126
  ### Refs
136
127
 
137
128
  ```ts
138
- import { extractRefName } from '@kubb/ast'
129
+ import { resolveRefName } from '@kubb/ast'
139
130
 
140
- extractRefName('#/components/schemas/Pet') // 'Pet'
131
+ resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' }) // 'Pet'
141
132
  ```
142
133
 
143
134
  ## Adding a node
package/dist/index.cjs CHANGED
@@ -25,7 +25,7 @@ var __copyProps = (to, from, except, desc) => {
25
25
  }
26
26
  return to;
27
27
  };
28
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
28
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
29
29
  value: mod,
30
30
  enumerable: true
31
31
  }) : target, mod));
@@ -363,33 +363,6 @@ const contentDef = defineNode({
363
363
  */
364
364
  const createContent = contentDef.create;
365
365
  //#endregion
366
- //#region ../../internals/utils/src/casing.ts
367
- /**
368
- * Shared implementation for camelCase and PascalCase conversion.
369
- * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
370
- * and capitalizes each word according to `pascal`.
371
- *
372
- * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
373
- */
374
- function toCamelOrPascal(text, pascal) {
375
- return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
376
- if (word.length > 1 && word === word.toUpperCase()) return word;
377
- return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
378
- }).join("").replace(/[^a-zA-Z0-9]/g, "");
379
- }
380
- /**
381
- * Converts `text` to PascalCase.
382
- *
383
- * @example Word boundaries
384
- * `pascalCase('hello-world') // 'HelloWorld'`
385
- *
386
- * @example With a suffix
387
- * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`
388
- */
389
- function pascalCase(text, { prefix = "", suffix = "" } = {}) {
390
- return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
391
- }
392
- //#endregion
393
366
  //#region ../../internals/utils/src/fs.ts
394
367
  /**
395
368
  * Strips the file extension from a path or file name.
@@ -484,6 +457,17 @@ function extractStringsFromNodes(nodes) {
484
457
  }
485
458
  //#endregion
486
459
  //#region src/utils/combineFileMembers.ts
460
+ const IDENTIFIER_RUN = /[\w$]+/g;
461
+ /**
462
+ * How many imports a file needs before indexing the source beats scanning it once per name.
463
+ */
464
+ const INDEX_ABOVE_IMPORTS = 128;
465
+ /**
466
+ * Every unbroken run of identifier characters in the source.
467
+ */
468
+ function collectIdentifiers(source) {
469
+ return new Set(source.match(IDENTIFIER_RUN));
470
+ }
487
471
  function sourceKey(source) {
488
472
  return `${source.name ?? extractStringsFromNodes(source.nodes)}:${source.isExportable ?? false}:${source.isTypeOnly ?? false}`;
489
473
  }
@@ -578,7 +562,8 @@ function combineExports(exports) {
578
562
  */
579
563
  function combineImports(imports, exports, source) {
580
564
  const exportedNames = new Set(exports.flatMap((e) => Array.isArray(e.name) ? e.name : e.name ? [e.name] : []));
581
- const isUsed = (importName) => !source || source.includes(importName) || exportedNames.has(importName);
565
+ const identifiers = source && imports.length > INDEX_ABOVE_IMPORTS ? collectIdentifiers(source) : null;
566
+ const isUsed = (importName) => !source || identifiers?.has(importName) || source.includes(importName) || exportedNames.has(importName);
582
567
  const importNameMemo = /* @__PURE__ */ new Map();
583
568
  const canonicalizeName = (n) => {
584
569
  if (typeof n === "string") return n;
@@ -1097,9 +1082,9 @@ function* getChildren(node, recurse) {
1097
1082
  * context. The result is a replacement node, a collected value, or `undefined`
1098
1083
  * when no callback is registered for the kind.
1099
1084
  *
1100
- * Shared by `transform` and `collectLazy` so node-kind dispatch lives in one place.
1085
+ * Shared by `transform` and `collect` so node-kind dispatch lives in one place.
1101
1086
  * `TResult` is the caller's expected return: the same node type for `transform`,
1102
- * the collected value type for `collectLazy`.
1087
+ * the collected value type for `collect`.
1103
1088
  */
1104
1089
  function applyVisitor(node, visitor, parent) {
1105
1090
  const key = VISITOR_KEY_BY_KIND[node.kind];
@@ -1157,12 +1142,12 @@ function transformChildren(node, visitor, recurse) {
1157
1142
  }
1158
1143
  /**
1159
1144
  * Lazy depth-first collection pass. Yields every non-null value returned by
1160
- * the visitor callbacks. Use `collect` for the eager array form.
1145
+ * the visitor callbacks. Use `collectSync` for the eager array form.
1161
1146
  *
1162
1147
  * @example Collect every operationId
1163
1148
  * ```ts
1164
1149
  * const ids: string[] = []
1165
- * for (const id of collectLazy<string>(root, {
1150
+ * for (const id of collect<string>(root, {
1166
1151
  * operation(node) {
1167
1152
  * return node.operationId
1168
1153
  * },
@@ -1171,7 +1156,7 @@ function transformChildren(node, visitor, recurse) {
1171
1156
  * }
1172
1157
  * ```
1173
1158
  */
1174
- function* collectLazy(node, options) {
1159
+ function* collect(node, options) {
1175
1160
  const { depth, parent, ...visitor } = options;
1176
1161
  yield* collectNode(node, visitor, (depth ?? visitorDepths.deep) === visitorDepths.deep, parent);
1177
1162
  }
@@ -1186,15 +1171,15 @@ function* collectNode(node, visitor, recurse, parent) {
1186
1171
  *
1187
1172
  * @example Collect every operationId
1188
1173
  * ```ts
1189
- * const ids = collect<string>(root, {
1174
+ * const ids = collectSync<string>(root, {
1190
1175
  * operation(node) {
1191
1176
  * return node.operationId
1192
1177
  * },
1193
1178
  * })
1194
1179
  * ```
1195
1180
  */
1196
- function collect(node, options) {
1197
- return Array.from(collectLazy(node, options));
1181
+ function collectSync(node, options) {
1182
+ return Array.from(collect(node, options));
1198
1183
  }
1199
1184
  //#endregion
1200
1185
  //#region src/defineMacro.ts
@@ -1234,7 +1219,7 @@ function chain({ macros, key, node, context }) {
1234
1219
  for (const macro of macros) {
1235
1220
  const callback = macro[key];
1236
1221
  if (!callback) continue;
1237
- if (macro.when && !macro.when(current)) continue;
1222
+ if (macro.match && !macro.match(current)) continue;
1238
1223
  const next = callback(current, context);
1239
1224
  if (next != null) current = next;
1240
1225
  }
@@ -1361,54 +1346,7 @@ function createPrinter(build) {
1361
1346
  };
1362
1347
  }
1363
1348
  //#endregion
1364
- //#region src/utils/mergeAdjacentSchemas.ts
1365
- /**
1366
- * Merges a run of adjacent anonymous object members into one. Named or non-object members break the
1367
- * run and pass through unchanged. The merge follows member order, so callers control which members
1368
- * combine by where they place them in the sequence.
1369
- *
1370
- * @example
1371
- * ```ts
1372
- * const merged = [...mergeAdjacentObjectsLazy([objectA, objectB])]
1373
- * ```
1374
- */
1375
- function* mergeAdjacentObjectsLazy(members) {
1376
- let acc;
1377
- for (const member of members) {
1378
- const objectMember = narrowSchema(member, "object");
1379
- if (objectMember && !objectMember.name && acc !== void 0) {
1380
- const accObject = narrowSchema(acc, "object");
1381
- if (accObject && !accObject.name) {
1382
- acc = createSchema({
1383
- ...accObject,
1384
- properties: [...accObject.properties ?? [], ...objectMember.properties ?? []]
1385
- });
1386
- continue;
1387
- }
1388
- }
1389
- if (acc !== void 0) yield acc;
1390
- acc = member;
1391
- }
1392
- if (acc !== void 0) yield acc;
1393
- }
1394
- //#endregion
1395
1349
  //#region src/utils/refs.ts
1396
- const plainStringTypes = /* @__PURE__ */ new Set([
1397
- "string",
1398
- "uuid",
1399
- "email",
1400
- "url",
1401
- "datetime"
1402
- ]);
1403
- /**
1404
- * Returns the last path segment of a reference string.
1405
- *
1406
- * @example
1407
- * `extractRefName('#/components/schemas/Pet') // 'Pet'`
1408
- */
1409
- function extractRefName(ref) {
1410
- return ref.split("/").at(-1) ?? ref;
1411
- }
1412
1350
  /**
1413
1351
  * Resolves the emitted name of the schema a ref node points at. Prefers `targetName` (set when
1414
1352
  * the referenced schema was renamed, e.g. to break a collision), then the last segment of `ref`,
@@ -1425,73 +1363,9 @@ function extractRefName(ref) {
1425
1363
  function resolveRefName(node) {
1426
1364
  if (!node || node.type !== "ref") return null;
1427
1365
  if (node.targetName) return node.targetName;
1428
- if (node.ref) return extractRefName(node.ref);
1366
+ if (node.ref) return node.ref.split("/").at(-1) ?? node.ref;
1429
1367
  return node.name ?? node.schema?.name ?? null;
1430
1368
  }
1431
- /**
1432
- * Builds a PascalCase child schema name by joining a parent name and property name.
1433
- * Returns `null` when there is no parent to nest under.
1434
- *
1435
- * @example Nested under a parent
1436
- * `childName('Order', 'shipping_address') // 'OrderShippingAddress'`
1437
- *
1438
- * @example No parent
1439
- * `childName(undefined, 'params') // null`
1440
- */
1441
- function childName(parentName, propName) {
1442
- return parentName ? pascalCase([parentName, propName].join(" ")) : null;
1443
- }
1444
- /**
1445
- * Builds a PascalCase enum name from the parent name, property name, and a suffix, skipping any
1446
- * empty parts.
1447
- *
1448
- * @example
1449
- * `enumPropName('Order', 'status', 'enum') // 'OrderStatusEnum'`
1450
- */
1451
- function enumPropName(parentName, propName, enumSuffix) {
1452
- return pascalCase([
1453
- parentName,
1454
- propName,
1455
- enumSuffix
1456
- ].filter(Boolean).join(" "));
1457
- }
1458
- /**
1459
- * Merges a ref node with its resolved schema, giving usage-site fields precedence.
1460
- *
1461
- * Every field set on the ref node except `kind`, `type`, `name`, `ref`, and `schema` overrides the
1462
- * same field in the resolved `node.schema` (for example `description`, `nullable`, `readOnly`,
1463
- * `deprecated`). Fields left `undefined` on the ref do not shadow the resolved schema. Non-ref
1464
- * nodes and refs without a resolved `schema` are returned unchanged.
1465
- *
1466
- * @example
1467
- * ```ts
1468
- * const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A cute pet' })
1469
- * const merged = syncSchemaRef(ref) // merges with resolved Pet schema
1470
- * ```
1471
- */
1472
- function syncSchemaRef(node) {
1473
- const ref = narrowSchema(node, "ref");
1474
- if (!ref) return node;
1475
- if (!ref.schema) return node;
1476
- const { kind: _kind, type: _type, name: _name, ref: _ref, schema: _schema, ...overrides } = ref;
1477
- const definedOverrides = Object.fromEntries(Object.entries(overrides).filter(([, v]) => v !== void 0));
1478
- return createSchema({
1479
- ...ref.schema,
1480
- ...definedOverrides
1481
- });
1482
- }
1483
- /**
1484
- * Returns `true` when a schema emits as a plain `string` type.
1485
- *
1486
- * Covers `string`, `uuid`, `email`, `url`, and `datetime` types. For `date` and `time`
1487
- * types, returns `true` only when `representation` is `'string'` rather than `'date'`.
1488
- */
1489
- function isStringType(node) {
1490
- if (plainStringTypes.has(node.type)) return true;
1491
- const temporal = narrowSchema(node, "date") ?? narrowSchema(node, "time");
1492
- if (temporal) return temporal.representation !== "date";
1493
- return false;
1494
- }
1495
1369
  //#endregion
1496
1370
  //#region src/utils/schemaGraph.ts
1497
1371
  /**
@@ -1499,7 +1373,7 @@ function isStringType(node) {
1499
1373
  */
1500
1374
  const collectSchemaRefs = memoize(/* @__PURE__ */ new WeakMap(), (node) => {
1501
1375
  const refs = /* @__PURE__ */ new Set();
1502
- collect(node, { schema(child) {
1376
+ collectSync(node, { schema(child) {
1503
1377
  if (child.type === "ref") {
1504
1378
  const name = resolveRefName(child);
1505
1379
  if (name) refs.add(name);
@@ -1532,6 +1406,36 @@ function collectReferencedSchemaNames(node, out = /* @__PURE__ */ new Set()) {
1532
1406
  for (const name of collectSchemaRefs(node)) out.add(name);
1533
1407
  return out;
1534
1408
  }
1409
+ /**
1410
+ * Collects the de-duplicated target names of every pointer-carrying ref in a node's subtree, in
1411
+ * first-occurrence order. The walk is memoized by node identity, so the subtree is scanned once and
1412
+ * `resolver.imports` reads the same result across the ts, zod, and faker plugins instead of
1413
+ * re-scanning the same schema per plugin.
1414
+ *
1415
+ * Only refs that carry a `$ref` pointer count, so a synthesized ref pointing at a sibling in the
1416
+ * same file (a union member created by name) is left out. That leaves exactly the set
1417
+ * `resolver.imports` emits. This is the ordered, import-facing counterpart to
1418
+ * {@link collectReferencedSchemaNames}, which returns an unordered set for graph analysis.
1419
+ *
1420
+ * @example
1421
+ * ```ts
1422
+ * collectImportedRefNames(petSchema)
1423
+ * // ['Category', 'Tag']
1424
+ * ```
1425
+ */
1426
+ const collectImportedRefNames = memoize(/* @__PURE__ */ new WeakMap(), (node) => {
1427
+ const seen = /* @__PURE__ */ new Set();
1428
+ const names = [];
1429
+ collectSync(node, { schema(child) {
1430
+ if (child.type !== "ref" || !child.ref) return;
1431
+ const name = resolveRefName(child);
1432
+ if (name && !seen.has(name)) {
1433
+ seen.add(name);
1434
+ names.push(name);
1435
+ }
1436
+ } });
1437
+ return names;
1438
+ });
1535
1439
  function computeUsedSchemaNames(operations, schemas) {
1536
1440
  const schemaMap = /* @__PURE__ */ new Map();
1537
1441
  for (const schema of schemas) if (schema.name) schemaMap.set(schema.name, schema);
@@ -1544,7 +1448,7 @@ function computeUsedSchemaNames(operations, schemas) {
1544
1448
  if (namedSchema) visitSchema(namedSchema);
1545
1449
  }
1546
1450
  }
1547
- for (const op of operations) for (const schema of collectLazy(op, {
1451
+ for (const op of operations) for (const schema of collect(op, {
1548
1452
  depth: "shallow",
1549
1453
  schema: (node) => node
1550
1454
  })) visitSchema(schema);
@@ -1574,12 +1478,24 @@ function collectUsedSchemaNames(operations, schemas) {
1574
1478
  return computeUsedSchemaNames(operations, schemas);
1575
1479
  }
1576
1480
  const EMPTY_CIRCULAR_SET = /* @__PURE__ */ new Set();
1577
- const findCircularSchemasMemo = memoize(/* @__PURE__ */ new WeakMap(), (schemas) => {
1578
- const graph = /* @__PURE__ */ new Map();
1579
- for (const schema of schemas) {
1580
- if (!schema.name) continue;
1581
- graph.set(schema.name, collectReferencedSchemaNames(schema));
1582
- }
1481
+ /**
1482
+ * Finds every schema that takes part in a circular dependency chain in a schema dependency graph
1483
+ * that maps each schema name to the names it references directly.
1484
+ *
1485
+ * Use this when the graph was already collected during another pass (e.g. the adapter's convert
1486
+ * walk), so the schema nodes are not swept a second time. `findCircularSchemas` builds the graph
1487
+ * from schema nodes and delegates here.
1488
+ *
1489
+ * @example
1490
+ * ```ts
1491
+ * const graph = new Map([
1492
+ * ['Pet', new Set(['Category'])],
1493
+ * ['Category', new Set(['Pet'])],
1494
+ * ])
1495
+ * findCircularSchemasFromGraph(graph) // Set { 'Pet', 'Category' }
1496
+ * ```
1497
+ */
1498
+ function findCircularSchemasFromGraph(graph) {
1583
1499
  const circular = /* @__PURE__ */ new Set();
1584
1500
  for (const start of graph.keys()) {
1585
1501
  const visited = /* @__PURE__ */ new Set();
@@ -1597,6 +1513,14 @@ const findCircularSchemasMemo = memoize(/* @__PURE__ */ new WeakMap(), (schemas)
1597
1513
  }
1598
1514
  }
1599
1515
  return circular;
1516
+ }
1517
+ const findCircularSchemasMemo = memoize(/* @__PURE__ */ new WeakMap(), (schemas) => {
1518
+ const graph = /* @__PURE__ */ new Map();
1519
+ for (const schema of schemas) {
1520
+ if (!schema.name) continue;
1521
+ graph.set(schema.name, collectReferencedSchemaNames(schema));
1522
+ }
1523
+ return findCircularSchemasFromGraph(graph);
1600
1524
  });
1601
1525
  /**
1602
1526
  * Finds every schema that takes part in a circular dependency chain, including direct self-loops.
@@ -1611,174 +1535,6 @@ function findCircularSchemas(schemas) {
1611
1535
  if (schemas.length === 0) return EMPTY_CIRCULAR_SET;
1612
1536
  return findCircularSchemasMemo(schemas);
1613
1537
  }
1614
- /**
1615
- * Returns `true` when a schema, or anything nested inside it, references a circular schema.
1616
- *
1617
- * Pass `excludeName` to skip refs to a specific schema, which helps when self-references are handled
1618
- * on their own. Pair it with `findCircularSchemas()` to decide where lazy wrappers go.
1619
- *
1620
- * @note Stops at the first matching circular ref.
1621
- */
1622
- function containsCircularRef(node, { circularSchemas, excludeName }) {
1623
- if (!node || circularSchemas.size === 0) return false;
1624
- for (const _ of collectLazy(node, { schema(child) {
1625
- if (child.type !== "ref") return null;
1626
- const name = resolveRefName(child);
1627
- return name && name !== excludeName && circularSchemas.has(name) ? true : null;
1628
- } })) return true;
1629
- return false;
1630
- }
1631
- //#endregion
1632
- //#region src/macros/macroDiscriminatorEnum.ts
1633
- /**
1634
- * Builds a macro that replaces a discriminator property's schema with a string enum of the given
1635
- * values. Object schemas that lack the property are returned unchanged.
1636
- *
1637
- * @example
1638
- * ```ts
1639
- * const macro = macroDiscriminatorEnum({ propertyName: 'type', values: ['dog', 'cat'] })
1640
- * const next = applyMacros(objectSchema, [macro], { depth: 'shallow' })
1641
- * ```
1642
- */
1643
- function macroDiscriminatorEnum({ propertyName, values, enumName }) {
1644
- return defineMacro({
1645
- name: "discriminator-enum",
1646
- schema(node) {
1647
- const objectNode = narrowSchema(node, "object");
1648
- if (!objectNode?.properties?.length) return void 0;
1649
- if (!objectNode.properties.some((prop) => prop.name === propertyName)) return void 0;
1650
- return createSchema({
1651
- ...objectNode,
1652
- properties: objectNode.properties.map((prop) => {
1653
- if (prop.name !== propertyName) return prop;
1654
- return createProperty({
1655
- ...prop,
1656
- schema: createSchema({
1657
- type: "enum",
1658
- primitive: "string",
1659
- enumValues: values,
1660
- name: enumName,
1661
- readOnly: prop.schema.readOnly,
1662
- writeOnly: prop.schema.writeOnly
1663
- })
1664
- });
1665
- })
1666
- });
1667
- }
1668
- });
1669
- }
1670
- //#endregion
1671
- //#region src/macros/macroEnumName.ts
1672
- /**
1673
- * Builds a macro that names an inline enum schema from its parent and property name. Boolean enums
1674
- * are left anonymous. Non-enum nodes are returned unchanged.
1675
- *
1676
- * @example
1677
- * ```ts
1678
- * const macro = macroEnumName({ parentName: 'Pet', propName: 'status', enumSuffix: 'enum' })
1679
- * const named = applyMacros(propSchema, [macro], { depth: 'shallow' })
1680
- * ```
1681
- */
1682
- function macroEnumName({ parentName, propName, enumSuffix }) {
1683
- return defineMacro({
1684
- name: "enum-name",
1685
- schema(node) {
1686
- const enumNode = narrowSchema(node, "enum");
1687
- if (enumNode?.primitive === "boolean") return {
1688
- ...node,
1689
- name: null
1690
- };
1691
- if (enumNode) return {
1692
- ...node,
1693
- name: enumPropName(parentName, propName, enumSuffix)
1694
- };
1695
- }
1696
- });
1697
- }
1698
- //#endregion
1699
- //#region src/macros/macroRenameSchema.ts
1700
- /**
1701
- * Builds a macro that renames a schema consistently: the declaration (`name`) and every ref
1702
- * pointing at it (`targetName`) change together, so imports and printed references stay in
1703
- * sync. Renaming only one side by hand produces imports for files that are never generated.
1704
- *
1705
- * @example
1706
- * `const macro = macroRenameSchema({ from: 'Order', to: 'StoreOrder' })`
1707
- */
1708
- function macroRenameSchema({ from, to }) {
1709
- return defineMacro({
1710
- name: "rename-schema",
1711
- schema(node) {
1712
- const refNode = narrowSchema(node, "ref");
1713
- if (!refNode) return node.name === from ? {
1714
- ...node,
1715
- name: to
1716
- } : void 0;
1717
- const renamesDeclaration = refNode.name === from;
1718
- const renamesTarget = resolveRefName(refNode) === from;
1719
- if (!renamesDeclaration && !renamesTarget) return void 0;
1720
- return {
1721
- ...refNode,
1722
- ...renamesDeclaration ? { name: to } : {},
1723
- ...renamesTarget ? { targetName: to } : {}
1724
- };
1725
- }
1726
- });
1727
- }
1728
- //#endregion
1729
- //#region src/macros/macroSimplifyUnion.ts
1730
- /**
1731
- * Scalar primitive schema types used for union simplification and type narrowing.
1732
- */
1733
- const SCALAR_PRIMITIVE_TYPES = /* @__PURE__ */ new Set([
1734
- "string",
1735
- "number",
1736
- "integer",
1737
- "bigint",
1738
- "boolean"
1739
- ]);
1740
- function isScalarPrimitive(type) {
1741
- return SCALAR_PRIMITIVE_TYPES.has(type);
1742
- }
1743
- /**
1744
- * Filters union members, dropping enum members that a broader scalar primitive already covers.
1745
- */
1746
- function simplifyUnionMembers(members) {
1747
- const scalarPrimitives = new Set(members.filter((member) => isScalarPrimitive(member.type)).map((m) => m.type));
1748
- if (!scalarPrimitives.size) return members;
1749
- return members.filter((member) => {
1750
- const enumNode = narrowSchema(member, "enum");
1751
- if (!enumNode) return true;
1752
- const primitive = enumNode.primitive;
1753
- if (!primitive) return true;
1754
- if ((enumNode.namedEnumValues?.length ?? enumNode.enumValues?.length ?? 0) <= 1) return true;
1755
- if (scalarPrimitives.has(primitive)) return false;
1756
- if ((primitive === "integer" || primitive === "number") && (scalarPrimitives.has("integer") || scalarPrimitives.has("number"))) return false;
1757
- return true;
1758
- });
1759
- }
1760
- /**
1761
- * Removes union members a broader scalar primitive already covers, such as a multi-value string enum
1762
- * sitting next to a plain `string`. Single-value enums are kept.
1763
- *
1764
- * @example
1765
- * ```ts
1766
- * const next = applyMacros(unionSchema, [macroSimplifyUnion], { depth: 'shallow' })
1767
- * ```
1768
- */
1769
- const macroSimplifyUnion = defineMacro({
1770
- name: "simplify-union",
1771
- schema(node) {
1772
- const unionNode = narrowSchema(node, "union");
1773
- if (!unionNode?.members?.length) return void 0;
1774
- const simplified = simplifyUnionMembers(unionNode.members);
1775
- if (simplified.length === unionNode.members.length) return void 0;
1776
- return {
1777
- ...unionNode,
1778
- members: simplified
1779
- };
1780
- }
1781
- });
1782
1538
  //#endregion
1783
1539
  //#region src/factory.ts
1784
1540
  var factory_exports = /* @__PURE__ */ __exportAll({
@@ -1833,37 +1589,27 @@ var exports_exports = /* @__PURE__ */ __exportAll({
1833
1589
  applyMacros: () => applyMacros,
1834
1590
  arrowFunctionDef: () => arrowFunctionDef,
1835
1591
  breakDef: () => breakDef,
1836
- childName: () => childName,
1837
1592
  collect: () => collect,
1593
+ collectImportedRefNames: () => collectImportedRefNames,
1594
+ collectSync: () => collectSync,
1838
1595
  collectUsedSchemaNames: () => collectUsedSchemaNames,
1839
- combineExports: () => combineExports,
1840
- combineImports: () => combineImports,
1841
- combineSources: () => combineSources,
1842
1596
  composeMacros: () => composeMacros,
1843
1597
  constDef: () => constDef,
1844
- containsCircularRef: () => containsCircularRef,
1845
1598
  contentDef: () => contentDef,
1846
1599
  createPrinter: () => createPrinter,
1847
1600
  defineMacro: () => defineMacro,
1848
1601
  defineNode: () => defineNode,
1849
- enumPropName: () => enumPropName,
1850
1602
  exportDef: () => exportDef,
1851
- extractRefName: () => extractRefName,
1852
1603
  extractStringsFromNodes: () => extractStringsFromNodes,
1853
1604
  factory: () => factory_exports,
1854
1605
  fileDef: () => fileDef,
1855
1606
  findCircularSchemas: () => findCircularSchemas,
1607
+ findCircularSchemasFromGraph: () => findCircularSchemasFromGraph,
1856
1608
  functionDef: () => functionDef,
1857
1609
  importDef: () => importDef,
1858
1610
  inputDef: () => inputDef,
1859
1611
  isHttpOperationNode: () => isHttpOperationNode,
1860
- isStringType: () => isStringType,
1861
1612
  jsxDef: () => jsxDef,
1862
- macroDiscriminatorEnum: () => macroDiscriminatorEnum,
1863
- macroEnumName: () => macroEnumName,
1864
- macroRenameSchema: () => macroRenameSchema,
1865
- macroSimplifyUnion: () => macroSimplifyUnion,
1866
- mergeAdjacentObjectsLazy: () => mergeAdjacentObjectsLazy,
1867
1613
  narrowSchema: () => narrowSchema,
1868
1614
  nodeDefs: () => nodeDefs,
1869
1615
  operationDef: () => operationDef,
@@ -1877,7 +1623,6 @@ var exports_exports = /* @__PURE__ */ __exportAll({
1877
1623
  schemaDef: () => schemaDef,
1878
1624
  schemaTypes: () => schemaTypes,
1879
1625
  sourceDef: () => sourceDef,
1880
- syncSchemaRef: () => syncSchemaRef,
1881
1626
  textDef: () => textDef,
1882
1627
  transform: () => transform,
1883
1628
  typeDef: () => typeDef
@@ -1892,22 +1637,17 @@ Object.defineProperty(exports, "ast", {
1892
1637
  }
1893
1638
  });
1894
1639
  exports.breakDef = breakDef;
1895
- exports.childName = childName;
1896
1640
  exports.collect = collect;
1641
+ exports.collectImportedRefNames = collectImportedRefNames;
1642
+ exports.collectSync = collectSync;
1897
1643
  exports.collectUsedSchemaNames = collectUsedSchemaNames;
1898
- exports.combineExports = combineExports;
1899
- exports.combineImports = combineImports;
1900
- exports.combineSources = combineSources;
1901
1644
  exports.composeMacros = composeMacros;
1902
1645
  exports.constDef = constDef;
1903
- exports.containsCircularRef = containsCircularRef;
1904
1646
  exports.contentDef = contentDef;
1905
1647
  exports.createPrinter = createPrinter;
1906
1648
  exports.defineMacro = defineMacro;
1907
1649
  exports.defineNode = defineNode;
1908
- exports.enumPropName = enumPropName;
1909
1650
  exports.exportDef = exportDef;
1910
- exports.extractRefName = extractRefName;
1911
1651
  exports.extractStringsFromNodes = extractStringsFromNodes;
1912
1652
  Object.defineProperty(exports, "factory", {
1913
1653
  enumerable: true,
@@ -1917,17 +1657,12 @@ Object.defineProperty(exports, "factory", {
1917
1657
  });
1918
1658
  exports.fileDef = fileDef;
1919
1659
  exports.findCircularSchemas = findCircularSchemas;
1660
+ exports.findCircularSchemasFromGraph = findCircularSchemasFromGraph;
1920
1661
  exports.functionDef = functionDef;
1921
1662
  exports.importDef = importDef;
1922
1663
  exports.inputDef = inputDef;
1923
1664
  exports.isHttpOperationNode = isHttpOperationNode;
1924
- exports.isStringType = isStringType;
1925
1665
  exports.jsxDef = jsxDef;
1926
- exports.macroDiscriminatorEnum = macroDiscriminatorEnum;
1927
- exports.macroEnumName = macroEnumName;
1928
- exports.macroRenameSchema = macroRenameSchema;
1929
- exports.macroSimplifyUnion = macroSimplifyUnion;
1930
- exports.mergeAdjacentObjectsLazy = mergeAdjacentObjectsLazy;
1931
1666
  exports.narrowSchema = narrowSchema;
1932
1667
  exports.nodeDefs = nodeDefs;
1933
1668
  exports.operationDef = operationDef;
@@ -1941,7 +1676,6 @@ exports.responseDef = responseDef;
1941
1676
  exports.schemaDef = schemaDef;
1942
1677
  exports.schemaTypes = schemaTypes;
1943
1678
  exports.sourceDef = sourceDef;
1944
- exports.syncSchemaRef = syncSchemaRef;
1945
1679
  exports.textDef = textDef;
1946
1680
  exports.transform = transform;
1947
1681
  exports.typeDef = typeDef;