@kubb/ast 5.0.0-beta.60 → 5.0.0-beta.62

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.
Files changed (87) hide show
  1. package/README.md +2 -1
  2. package/dist/defineMacro-BryDiuQl.cjs +115 -0
  3. package/dist/defineMacro-BryDiuQl.cjs.map +1 -0
  4. package/dist/defineMacro-CNkUpxia.js +99 -0
  5. package/dist/defineMacro-CNkUpxia.js.map +1 -0
  6. package/dist/defineMacro-Vw-xQvq7.d.ts +467 -0
  7. package/dist/factory.cjs +64 -4
  8. package/dist/factory.cjs.map +1 -0
  9. package/dist/factory.d.ts +2 -37
  10. package/dist/factory.js +58 -3
  11. package/dist/factory.js.map +1 -0
  12. package/dist/{index-BzjwdK2M.d.ts → index-CTaN_ee_.d.ts} +235 -198
  13. package/dist/index.cjs +33 -32
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.ts +36 -36
  16. package/dist/index.js +19 -14
  17. package/dist/index.js.map +1 -1
  18. package/dist/macros.cjs +130 -0
  19. package/dist/macros.cjs.map +1 -0
  20. package/dist/macros.d.ts +61 -0
  21. package/dist/macros.js +128 -0
  22. package/dist/macros.js.map +1 -0
  23. package/dist/{operationParams-BZ07xDm0.d.ts → operationParams-B44p6EQy.d.ts} +2 -2
  24. package/dist/{response-DS5S3IG4.cjs → response-BeG6hq2D.cjs} +389 -173
  25. package/dist/response-BeG6hq2D.cjs.map +1 -0
  26. package/dist/{response-DKxTr522.js → response-Rd1uisM1.js} +377 -162
  27. package/dist/response-Rd1uisM1.js.map +1 -0
  28. package/dist/types-DQTgVSwE.d.ts +314 -0
  29. package/dist/types.d.ts +5 -5
  30. package/dist/{utils-D83JA6Xx.cjs → utils-BDI3kXlb.cjs} +20 -753
  31. package/dist/utils-BDI3kXlb.cjs.map +1 -0
  32. package/dist/{utils-Dj_KoXMv.js → utils-DW9rnfsD.js} +11 -630
  33. package/dist/utils-DW9rnfsD.js.map +1 -0
  34. package/dist/utils.cjs +11 -9
  35. package/dist/utils.d.ts +38 -4
  36. package/dist/utils.js +4 -3
  37. package/dist/visitor-B7Zlnp4c.cjs +604 -0
  38. package/dist/visitor-B7Zlnp4c.cjs.map +1 -0
  39. package/dist/visitor-DepQEKyp.js +510 -0
  40. package/dist/visitor-DepQEKyp.js.map +1 -0
  41. package/package.json +5 -1
  42. package/src/constants.ts +0 -30
  43. package/src/dedupe.ts +1 -9
  44. package/src/defineMacro.ts +139 -0
  45. package/src/{node.ts → defineNode.ts} +19 -42
  46. package/src/dialect.ts +42 -19
  47. package/src/factory.ts +3 -90
  48. package/src/index.ts +9 -15
  49. package/src/macros/index.ts +3 -0
  50. package/src/macros/macroDiscriminatorEnum.ts +50 -0
  51. package/src/macros/macroEnumName.ts +33 -0
  52. package/src/macros/macroSimplifyUnion.ts +60 -0
  53. package/src/nodes/code.ts +32 -75
  54. package/src/nodes/content.ts +2 -7
  55. package/src/nodes/file.ts +102 -14
  56. package/src/nodes/function.ts +46 -46
  57. package/src/nodes/index.ts +2 -3
  58. package/src/nodes/input.ts +13 -9
  59. package/src/nodes/operation.ts +5 -5
  60. package/src/nodes/output.ts +1 -1
  61. package/src/nodes/parameter.ts +6 -6
  62. package/src/nodes/property.ts +6 -6
  63. package/src/nodes/requestBody.ts +6 -13
  64. package/src/nodes/response.ts +93 -8
  65. package/src/nodes/schema.ts +1 -1
  66. package/src/registry.ts +1 -1
  67. package/src/types.ts +4 -4
  68. package/src/utils/extractStringsFromNodes.ts +1 -0
  69. package/src/utils/index.ts +2 -2
  70. package/src/utils/operationParams.ts +1 -1
  71. package/src/utils/refs.ts +27 -1
  72. package/src/utils/schemaMerge.ts +34 -0
  73. package/src/visitor.ts +2 -13
  74. package/dist/extractStringsFromNodes-WMYJ8nQL.d.ts +0 -82
  75. package/dist/factory-Cl8Z7mcc.cjs +0 -299
  76. package/dist/factory-Cl8Z7mcc.cjs.map +0 -1
  77. package/dist/factory-Du7nEP4B.js +0 -282
  78. package/dist/factory-Du7nEP4B.js.map +0 -1
  79. package/dist/response-DKxTr522.js.map +0 -1
  80. package/dist/response-DS5S3IG4.cjs.map +0 -1
  81. package/dist/types-olVl9v5p.d.ts +0 -764
  82. package/dist/utils-D83JA6Xx.cjs.map +0 -1
  83. package/dist/utils-Dj_KoXMv.js.map +0 -1
  84. package/src/mocks.ts +0 -56
  85. package/src/nodes/http.ts +0 -85
  86. package/src/transformers.ts +0 -191
  87. /package/src/{printer.ts → definePrinter.ts} +0 -0
@@ -33,7 +33,23 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
33
33
  enumerable: true
34
34
  }) : target, mod));
35
35
  //#endregion
36
- //#region src/node.ts
36
+ let node_crypto = require("node:crypto");
37
+ let node_path = require("node:path");
38
+ node_path = __toESM(node_path, 1);
39
+ //#region src/defineNode.ts
40
+ /**
41
+ * Visitor callback names, one per traversable node kind, in traversal order.
42
+ * Kept in sync with the keys of `Visitor` in `visitor.ts`.
43
+ */
44
+ const visitorKeys = [
45
+ "input",
46
+ "output",
47
+ "operation",
48
+ "schema",
49
+ "property",
50
+ "parameter",
51
+ "response"
52
+ ];
37
53
  /**
38
54
  * Builds a type guard that matches nodes of the given `kind`.
39
55
  */
@@ -41,52 +57,30 @@ function isKind(kind) {
41
57
  return (node) => node.kind === kind;
42
58
  }
43
59
  /**
44
- * Updates a schema's `optional` and `nullish` flags from a parent's `required`
45
- * value and the schema's own `nullable`. Mirrors how OpenAPI parameters and
46
- * object properties combine "required" and "nullable" into a single AST.
47
- *
48
- * - Non-required + non-nullable → `optional: true`.
49
- * - Non-required + nullable → `nullish: true`.
50
- * - Required → both flags cleared.
51
- */
52
- function syncOptionality(schema, required) {
53
- const nullable = schema.nullable ?? false;
54
- return {
55
- ...schema,
56
- optional: !required && !nullable ? true : void 0,
57
- nullish: !required && nullable ? true : void 0
58
- };
59
- }
60
- /**
61
60
  * Defines a node once and derives its `create` builder, `is` guard, and traversal
62
61
  * metadata. `create` merges `defaults`, the `build` hook (or the raw input), and the
63
62
  * `kind`, so node construction lives in one place without scattered `as` casts.
64
63
  *
65
- * Set `rebuild: true` when the `build` hook derives fields from children. After a
66
- * transform rewrites those children, the registry reruns `create` so the derived
67
- * fields stay correct.
68
- *
69
64
  * @example Simple node
70
65
  * ```ts
71
66
  * const importDef = defineNode<ImportNode>({ kind: 'Import' })
72
67
  * const createImport = importDef.create
73
68
  * ```
74
69
  *
75
- * @example Node with a build hook that is rerun on transform
70
+ * @example Node with a build hook
76
71
  * ```ts
77
72
  * const propertyDef = defineNode<PropertyNode, UserPropertyNode>({
78
73
  * kind: 'Property',
79
74
  * build: (props) => ({ ...props, required: props.required ?? false }),
80
75
  * children: ['schema'],
81
76
  * visitorKey: 'property',
82
- * rebuild: true,
83
77
  * })
84
78
  * ```
85
79
  */
86
80
  function defineNode(config) {
87
- const { kind, defaults, build, children, visitorKey, rebuild } = config;
88
- function create(input) {
89
- const base = build ? build(input) : input;
81
+ const { kind, defaults, build, children, visitorKey } = config;
82
+ function create(input, dialect) {
83
+ const base = build ? build(input, dialect) : input;
90
84
  return {
91
85
  ...defaults,
92
86
  ...base,
@@ -98,8 +92,7 @@ function defineNode(config) {
98
92
  create,
99
93
  is: isKind(kind),
100
94
  children,
101
- visitorKey,
102
- rebuild
95
+ visitorKey
103
96
  };
104
97
  }
105
98
  //#endregion
@@ -197,6 +190,23 @@ function pascalCase(text, { prefix = "", suffix = "" } = {}) {
197
190
  return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
198
191
  }
199
192
  //#endregion
193
+ //#region ../../internals/utils/src/fs.ts
194
+ /**
195
+ * Strips the file extension from a path or file name.
196
+ * Only removes the last `.ext` segment when the dot is not part of a directory name.
197
+ *
198
+ * @example
199
+ * trimExtName('petStore.ts') // 'petStore'
200
+ * trimExtName('/src/models/pet.ts') // '/src/models/pet'
201
+ * trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'
202
+ * trimExtName('noExtension') // 'noExtension'
203
+ */
204
+ function trimExtName(text) {
205
+ const dotIndex = text.lastIndexOf(".");
206
+ if (dotIndex > 0 && !text.includes("/", dotIndex)) return text.slice(0, dotIndex);
207
+ return text;
208
+ }
209
+ //#endregion
200
210
  //#region src/utils/extractStringsFromNodes.ts
201
211
  /**
202
212
  * Extracts all string content from a `CodeNode` tree recursively.
@@ -222,45 +232,44 @@ function extractStringsFromNodes(nodes) {
222
232
  }).filter(Boolean).join("\n");
223
233
  }
224
234
  //#endregion
225
- //#region src/nodes/property.ts
235
+ //#region src/nodes/code.ts
226
236
  /**
227
- * Definition for the {@link PropertyNode}. `required` defaults to `false` and the
228
- * schema's `optional`/`nullish` flags are kept in sync with it.
237
+ * Definition for the {@link ConstNode}.
229
238
  */
230
- const propertyDef = defineNode({
231
- kind: "Property",
232
- build: (props) => {
233
- const required = props.required ?? false;
234
- return {
235
- ...props,
236
- required,
237
- schema: syncOptionality(props.schema, required)
238
- };
239
- },
240
- children: ["schema"],
241
- visitorKey: "property",
242
- rebuild: true
239
+ const constDef = defineNode({ kind: "Const" });
240
+ /**
241
+ * Definition for the {@link TypeNode}.
242
+ */
243
+ const typeDef = defineNode({ kind: "Type" });
244
+ /**
245
+ * Definition for the {@link FunctionNode}.
246
+ */
247
+ const functionDef = defineNode({ kind: "Function" });
248
+ /**
249
+ * Definition for the {@link ArrowFunctionNode}.
250
+ */
251
+ const arrowFunctionDef = defineNode({ kind: "ArrowFunction" });
252
+ /**
253
+ * Definition for the {@link TextNode}.
254
+ */
255
+ const textDef = defineNode({
256
+ kind: "Text",
257
+ build: (value) => ({ value })
243
258
  });
244
259
  /**
245
- * Creates a `PropertyNode`.
246
- *
247
- * @example
248
- * ```ts
249
- * const property = createProperty({
250
- * name: 'status',
251
- * required: true,
252
- * schema: createSchema({ type: 'string', nullable: true }),
253
- * })
254
- * // required=true, no optional/nullish
255
- * ```
260
+ * Definition for the {@link BreakNode}.
256
261
  */
257
- const createProperty = propertyDef.create;
258
- //#endregion
259
- //#region src/nodes/code.ts
262
+ const breakDef = defineNode({
263
+ kind: "Break",
264
+ build: () => ({})
265
+ });
260
266
  /**
261
- * Definition for the {@link ConstNode}.
267
+ * Definition for the {@link JsxNode}.
262
268
  */
263
- const constDef = defineNode({ kind: "Const" });
269
+ const jsxDef = defineNode({
270
+ kind: "Jsx",
271
+ build: (value) => ({ value })
272
+ });
264
273
  /**
265
274
  * Creates a `ConstNode` representing a TypeScript `const` declaration.
266
275
  *
@@ -272,10 +281,6 @@ const constDef = defineNode({ kind: "Const" });
272
281
  */
273
282
  const createConst = constDef.create;
274
283
  /**
275
- * Definition for the {@link TypeNode}.
276
- */
277
- const typeDef = defineNode({ kind: "Type" });
278
- /**
279
284
  * Creates a `TypeNode` representing a TypeScript `type` alias declaration.
280
285
  *
281
286
  * @example
@@ -286,10 +291,6 @@ const typeDef = defineNode({ kind: "Type" });
286
291
  */
287
292
  const createType = typeDef.create;
288
293
  /**
289
- * Definition for the {@link FunctionNode}.
290
- */
291
- const functionDef = defineNode({ kind: "Function" });
292
- /**
293
294
  * Creates a `FunctionNode` representing a TypeScript `function` declaration.
294
295
  *
295
296
  * @example
@@ -300,10 +301,6 @@ const functionDef = defineNode({ kind: "Function" });
300
301
  */
301
302
  const createFunction = functionDef.create;
302
303
  /**
303
- * Definition for the {@link ArrowFunctionNode}.
304
- */
305
- const arrowFunctionDef = defineNode({ kind: "ArrowFunction" });
306
- /**
307
304
  * Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
308
305
  *
309
306
  * @example
@@ -314,13 +311,6 @@ const arrowFunctionDef = defineNode({ kind: "ArrowFunction" });
314
311
  */
315
312
  const createArrowFunction = arrowFunctionDef.create;
316
313
  /**
317
- * Definition for the {@link TextNode}.
318
- */
319
- const textDef = defineNode({
320
- kind: "Text",
321
- build: (value) => ({ value })
322
- });
323
- /**
324
314
  * Creates a {@link TextNode} representing a raw string fragment in the source output.
325
315
  *
326
316
  * @example
@@ -331,13 +321,6 @@ const textDef = defineNode({
331
321
  */
332
322
  const createText = textDef.create;
333
323
  /**
334
- * Definition for the {@link BreakNode}.
335
- */
336
- const breakDef = defineNode({
337
- kind: "Break",
338
- build: () => ({})
339
- });
340
- /**
341
324
  * Creates a {@link BreakNode} representing a line break in the source output.
342
325
  *
343
326
  * @example
@@ -350,13 +333,6 @@ function createBreak() {
350
333
  return breakDef.create();
351
334
  }
352
335
  /**
353
- * Definition for the {@link JsxNode}.
354
- */
355
- const jsxDef = defineNode({
356
- kind: "Jsx",
357
- build: (value) => ({ value })
358
- });
359
- /**
360
336
  * Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
361
337
  *
362
338
  * @example
@@ -380,12 +356,171 @@ const contentDef = defineNode({
380
356
  */
381
357
  const createContent = contentDef.create;
382
358
  //#endregion
359
+ //#region src/utils/fileMerge.ts
360
+ function sourceKey(source) {
361
+ return `${source.name ?? extractStringsFromNodes(source.nodes)}:${source.isExportable ?? false}:${source.isTypeOnly ?? false}`;
362
+ }
363
+ function pathTypeKey(path, isTypeOnly) {
364
+ return `${path}:${isTypeOnly ?? false}`;
365
+ }
366
+ function exportKey(path, name, isTypeOnly, asAlias) {
367
+ return `${path}:${name ?? ""}:${isTypeOnly ?? false}:${asAlias ?? ""}`;
368
+ }
369
+ function importKey(path, name, isTypeOnly) {
370
+ return `${path}:${name ?? ""}:${isTypeOnly ?? false}`;
371
+ }
372
+ /**
373
+ * Computes a multi-level sort key for exports and imports:
374
+ * non-array names first (wildcards/namespace aliases). Type-only before value. Alphabetical path. Unnamed before named.
375
+ */
376
+ function sortKey(node) {
377
+ const isArray = Array.isArray(node.name) ? "1" : "0";
378
+ const typeOnly = node.isTypeOnly ? "0" : "1";
379
+ const hasName = node.name != null ? "1" : "0";
380
+ const name = Array.isArray(node.name) ? node.name.toSorted().join("\0") : node.name ?? "";
381
+ return `${isArray}:${typeOnly}:${node.path}:${hasName}:${name}`;
382
+ }
383
+ /**
384
+ * Deduplicates and merges `SourceNode` objects by `name + isExportable + isTypeOnly`.
385
+ *
386
+ * Unnamed sources are deduplicated by object reference. Returns a deduplicated array in original order.
387
+ */
388
+ function combineSources(sources) {
389
+ const seen = /* @__PURE__ */ new Map();
390
+ for (const source of sources) {
391
+ const key = sourceKey(source);
392
+ if (!seen.has(key)) seen.set(key, source);
393
+ }
394
+ return [...seen.values()];
395
+ }
396
+ /**
397
+ * Merges `incoming` names into `existing`, preserving order and dropping duplicates.
398
+ *
399
+ * Shared by `combineExports` and `combineImports` for the same-path name-merge case.
400
+ */
401
+ function mergeNameArrays(existing, incoming) {
402
+ const merged = new Set(existing);
403
+ for (const name of incoming) merged.add(name);
404
+ return [...merged];
405
+ }
406
+ /**
407
+ * Deduplicates and merges `ExportNode` objects by path and type.
408
+ *
409
+ * Named exports with the same path and `isTypeOnly` flag have their names merged into a single export.
410
+ * Non-array exports are deduplicated by exact identity. Returns a sorted, deduplicated array.
411
+ */
412
+ function combineExports(exports) {
413
+ const result = [];
414
+ const namedByPath = /* @__PURE__ */ new Map();
415
+ const seen = /* @__PURE__ */ new Set();
416
+ const keyed = exports.map((node) => ({
417
+ node,
418
+ key: sortKey(node)
419
+ }));
420
+ keyed.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
421
+ for (const { node: curr } of keyed) {
422
+ const { name, path, isTypeOnly, asAlias } = curr;
423
+ if (Array.isArray(name)) {
424
+ if (!name.length) continue;
425
+ const key = pathTypeKey(path, isTypeOnly);
426
+ const existing = namedByPath.get(key);
427
+ if (existing && Array.isArray(existing.name)) existing.name = mergeNameArrays(existing.name, name);
428
+ else {
429
+ const newItem = {
430
+ ...curr,
431
+ name: [...new Set(name)]
432
+ };
433
+ result.push(newItem);
434
+ namedByPath.set(key, newItem);
435
+ }
436
+ } else {
437
+ const key = exportKey(path, name, isTypeOnly, asAlias);
438
+ if (!seen.has(key)) {
439
+ result.push(curr);
440
+ seen.add(key);
441
+ }
442
+ }
443
+ }
444
+ return result;
445
+ }
446
+ /**
447
+ * Deduplicates and merges `ImportNode` objects, filtering out unused imports.
448
+ *
449
+ * Retains imports that are referenced in `source` or re-exported. Imports with the same path and
450
+ * `isTypeOnly` flag have their names merged. Returns a sorted, deduplicated, filtered array.
451
+ */
452
+ function combineImports(imports, exports, source) {
453
+ const exportedNames = new Set(exports.flatMap((e) => Array.isArray(e.name) ? e.name : e.name ? [e.name] : []));
454
+ const isUsed = (importName) => !source || source.includes(importName) || exportedNames.has(importName);
455
+ const importNameMemo = /* @__PURE__ */ new Map();
456
+ const canonicalizeName = (n) => {
457
+ if (typeof n === "string") return n;
458
+ const key = `${n.propertyName}:${n.name ?? ""}`;
459
+ if (!importNameMemo.has(key)) importNameMemo.set(key, n);
460
+ return importNameMemo.get(key);
461
+ };
462
+ const pathsWithUsedNamedImport = /* @__PURE__ */ new Set();
463
+ for (const node of imports) {
464
+ if (!Array.isArray(node.name)) continue;
465
+ if (node.name.some((item) => typeof item === "string" ? isUsed(item) : isUsed(item.name ?? item.propertyName))) pathsWithUsedNamedImport.add(node.path);
466
+ }
467
+ const result = [];
468
+ const namedByPath = /* @__PURE__ */ new Map();
469
+ const seen = /* @__PURE__ */ new Set();
470
+ const keyed = imports.map((node) => ({
471
+ node,
472
+ key: sortKey(node)
473
+ }));
474
+ keyed.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
475
+ for (const { node: curr } of keyed) {
476
+ if (curr.path === curr.root) continue;
477
+ const { path, isTypeOnly } = curr;
478
+ let { name } = curr;
479
+ if (Array.isArray(name)) {
480
+ name = [...new Set(name.map(canonicalizeName))].filter((item) => typeof item === "string" ? isUsed(item) : isUsed(item.name ?? item.propertyName));
481
+ if (!name.length) continue;
482
+ const key = pathTypeKey(path, isTypeOnly);
483
+ const existing = namedByPath.get(key);
484
+ if (existing && Array.isArray(existing.name)) existing.name = mergeNameArrays(existing.name, name);
485
+ else {
486
+ const newItem = {
487
+ ...curr,
488
+ name
489
+ };
490
+ result.push(newItem);
491
+ namedByPath.set(key, newItem);
492
+ }
493
+ } else {
494
+ if (name && !isUsed(name) && !pathsWithUsedNamedImport.has(path)) continue;
495
+ const key = importKey(path, name, isTypeOnly);
496
+ if (!seen.has(key)) {
497
+ result.push(curr);
498
+ seen.add(key);
499
+ }
500
+ }
501
+ }
502
+ return result;
503
+ }
504
+ //#endregion
383
505
  //#region src/nodes/file.ts
384
506
  /**
385
507
  * Definition for the {@link ImportNode}.
386
508
  */
387
509
  const importDef = defineNode({ kind: "Import" });
388
510
  /**
511
+ * Definition for the {@link ExportNode}.
512
+ */
513
+ const exportDef = defineNode({ kind: "Export" });
514
+ /**
515
+ * Definition for the {@link SourceNode}.
516
+ */
517
+ const sourceDef = defineNode({ kind: "Source" });
518
+ /**
519
+ * Definition for the {@link FileNode}. The fully resolved builder lives in
520
+ * `createFile`, so this definition only supplies the guard.
521
+ */
522
+ const fileDef = defineNode({ kind: "File" });
523
+ /**
389
524
  * Creates an `ImportNode` representing a language-agnostic import/dependency declaration.
390
525
  *
391
526
  * @example Named import
@@ -396,10 +531,6 @@ const importDef = defineNode({ kind: "Import" });
396
531
  */
397
532
  const createImport = importDef.create;
398
533
  /**
399
- * Definition for the {@link ExportNode}.
400
- */
401
- const exportDef = defineNode({ kind: "Export" });
402
- /**
403
534
  * Creates an `ExportNode` representing a language-agnostic export/public API declaration.
404
535
  *
405
536
  * @example Named export
@@ -410,10 +541,6 @@ const exportDef = defineNode({ kind: "Export" });
410
541
  */
411
542
  const createExport = exportDef.create;
412
543
  /**
413
- * Definition for the {@link SourceNode}.
414
- */
415
- const sourceDef = defineNode({ kind: "Source" });
416
- /**
417
544
  * Creates a `SourceNode` representing a fragment of source code within a file.
418
545
  *
419
546
  * @example
@@ -423,10 +550,64 @@ const sourceDef = defineNode({ kind: "Source" });
423
550
  */
424
551
  const createSource = sourceDef.create;
425
552
  /**
426
- * Definition for the {@link FileNode}. The fully resolved builder lives in
427
- * `createFile`, so this definition only supplies the guard.
553
+ * Creates a fully resolved `FileNode` from a file input descriptor.
554
+ *
555
+ * Computes:
556
+ * - `id` SHA256 hash of the file path
557
+ * - `name` `baseName` without extension
558
+ * - `extname` extension extracted from `baseName`
559
+ *
560
+ * Deduplicates:
561
+ * - `sources` via `combineSources`
562
+ * - `exports` via `combineExports`
563
+ * - `imports` via `combineImports` (also filters unused imports)
564
+ *
565
+ * @throws {Error} when `baseName` has no extension.
566
+ *
567
+ * @example
568
+ * ```ts
569
+ * const file = createFile({
570
+ * baseName: 'petStore.ts',
571
+ * path: 'src/models/petStore.ts',
572
+ * sources: [createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')] })],
573
+ * imports: [createImport({ name: ['z'], path: 'zod' })],
574
+ * exports: [createExport({ name: ['Pet'], path: './petStore' })],
575
+ * })
576
+ * // file.id = SHA256 hash of 'src/models/petStore.ts'
577
+ * // file.name = 'petStore'
578
+ * // file.extname = '.ts'
579
+ * ```
428
580
  */
429
- const fileDef = defineNode({ kind: "File" });
581
+ function createFile(input) {
582
+ const extname = node_path.default.extname(input.baseName) || (input.baseName.startsWith(".") ? input.baseName : "");
583
+ if (!extname) throw new Error(`No extname found for ${input.baseName}`);
584
+ const source = (input.sources ?? []).flatMap((item) => item.nodes ?? []).map((node) => extractStringsFromNodes([node])).filter(Boolean).join("\n\n");
585
+ const resolvedExports = input.exports?.length ? combineExports(input.exports) : [];
586
+ const combinedImports = input.imports?.length ? combineImports(input.imports, resolvedExports, source || void 0) : [];
587
+ const localNames = new Set((input.sources ?? []).map((item) => item.name).filter((name) => Boolean(name)));
588
+ const nameOf = (item) => typeof item === "string" ? item : item.name ?? item.propertyName;
589
+ const resolvedImports = combinedImports.filter((imp) => imp.path !== input.path).flatMap((imp) => {
590
+ if (!Array.isArray(imp.name)) return typeof imp.name === "string" && localNames.has(imp.name) ? [] : [imp];
591
+ const kept = imp.name.filter((item) => !localNames.has(nameOf(item)));
592
+ if (!kept.length) return [];
593
+ return [kept.length === imp.name.length ? imp : {
594
+ ...imp,
595
+ name: kept
596
+ }];
597
+ });
598
+ const resolvedSources = input.sources?.length ? combineSources(input.sources) : [];
599
+ return {
600
+ kind: "File",
601
+ ...input,
602
+ id: (0, node_crypto.hash)("sha256", input.path, "hex"),
603
+ name: trimExtName(input.baseName),
604
+ extname,
605
+ imports: resolvedImports,
606
+ exports: resolvedExports,
607
+ sources: resolvedSources,
608
+ meta: input.meta ?? {}
609
+ };
610
+ }
430
611
  //#endregion
431
612
  //#region src/nodes/function.ts
432
613
  /**
@@ -434,44 +615,14 @@ const fileDef = defineNode({ kind: "File" });
434
615
  */
435
616
  const typeLiteralDef = defineNode({ kind: "TypeLiteral" });
436
617
  /**
437
- * Creates a {@link TypeLiteralNode} representing an inline anonymous object type.
438
- *
439
- * @example
440
- * ```ts
441
- * createTypeLiteral({ members: [{ name: 'petId', type: 'string', optional: false }] })
442
- * // { petId: string }
443
- * ```
444
- */
445
- const createTypeLiteral = typeLiteralDef.create;
446
- /**
447
618
  * Definition for the {@link IndexedAccessTypeNode}.
448
619
  */
449
620
  const indexedAccessTypeDef = defineNode({ kind: "IndexedAccessType" });
450
621
  /**
451
- * Creates an {@link IndexedAccessTypeNode} representing a single field accessed from a named type.
452
- *
453
- * @example
454
- * ```ts
455
- * createIndexedAccessType({ objectType: 'DeletePetPathParams', indexType: 'petId' })
456
- * // DeletePetPathParams['petId']
457
- * ```
458
- */
459
- const createIndexedAccessType = indexedAccessTypeDef.create;
460
- /**
461
622
  * Definition for the {@link ObjectBindingPatternNode}.
462
623
  */
463
624
  const objectBindingPatternDef = defineNode({ kind: "ObjectBindingPattern" });
464
625
  /**
465
- * Creates an {@link ObjectBindingPatternNode} for a destructured parameter binding.
466
- *
467
- * @example
468
- * ```ts
469
- * createObjectBindingPattern({ elements: [{ name: 'id' }, { name: 'name' }] })
470
- * // { id, name }
471
- * ```
472
- */
473
- const createObjectBindingPattern = objectBindingPatternDef.create;
474
- /**
475
626
  * Definition for the {@link FunctionParameterNode}. `optional` defaults to `false`.
476
627
  * Passing `properties` builds a destructured group: an {@link ObjectBindingPatternNode} name
477
628
  * paired with a {@link TypeLiteralNode} type.
@@ -496,6 +647,43 @@ const functionParameterDef = defineNode({
496
647
  }
497
648
  });
498
649
  /**
650
+ * Definition for the {@link FunctionParametersNode}.
651
+ */
652
+ const functionParametersDef = defineNode({
653
+ kind: "FunctionParameters",
654
+ defaults: { params: [] }
655
+ });
656
+ /**
657
+ * Creates a {@link TypeLiteralNode} representing an inline anonymous object type.
658
+ *
659
+ * @example
660
+ * ```ts
661
+ * createTypeLiteral({ members: [{ name: 'petId', type: 'string', optional: false }] })
662
+ * // { petId: string }
663
+ * ```
664
+ */
665
+ const createTypeLiteral = typeLiteralDef.create;
666
+ /**
667
+ * Creates an {@link IndexedAccessTypeNode} representing a single field accessed from a named type.
668
+ *
669
+ * @example
670
+ * ```ts
671
+ * createIndexedAccessType({ target: 'DeletePetPathParams', key: 'petId' })
672
+ * // DeletePetPathParams['petId']
673
+ * ```
674
+ */
675
+ const createIndexedAccessType = indexedAccessTypeDef.create;
676
+ /**
677
+ * Creates an {@link ObjectBindingPatternNode} for a destructured parameter binding.
678
+ *
679
+ * @example
680
+ * ```ts
681
+ * createObjectBindingPattern({ elements: [{ name: 'id' }, { name: 'name' }] })
682
+ * // { id, name }
683
+ * ```
684
+ */
685
+ const createObjectBindingPattern = objectBindingPatternDef.create;
686
+ /**
499
687
  * Creates a `FunctionParameterNode`. `optional` defaults to `false`.
500
688
  *
501
689
  * @example Optional param
@@ -512,13 +700,6 @@ const functionParameterDef = defineNode({
512
700
  */
513
701
  const createFunctionParameter = functionParameterDef.create;
514
702
  /**
515
- * Definition for the {@link FunctionParametersNode}.
516
- */
517
- const functionParametersDef = defineNode({
518
- kind: "FunctionParameters",
519
- defaults: { params: [] }
520
- });
521
- /**
522
703
  * Creates a `FunctionParametersNode` from an ordered list of parameters.
523
704
  *
524
705
  * @example
@@ -550,8 +731,8 @@ const inputDef = defineNode({
550
731
  });
551
732
  /**
552
733
  * Creates an `InputNode`. Pass `stream: true` for the streaming variant whose `schemas` and
553
- * `operations` are `AsyncIterable` sources and whose `meta` is optional. Otherwise it builds the
554
- * eager variant with array `schemas`/`operations` and the defaulted `meta`.
734
+ * `operations` are `AsyncIterable` sources. Otherwise it builds the eager variant with array
735
+ * `schemas`/`operations`. Both variants get the defaulted `meta`.
555
736
  *
556
737
  * @example Eager
557
738
  * ```ts
@@ -568,6 +749,10 @@ function createInput(options = {}) {
568
749
  const { stream, ...overrides } = options;
569
750
  if (stream) return {
570
751
  kind: "Input",
752
+ meta: {
753
+ circularNames: [],
754
+ enumNames: []
755
+ },
571
756
  ...overrides
572
757
  };
573
758
  return inputDef.create(overrides);
@@ -575,18 +760,15 @@ function createInput(options = {}) {
575
760
  //#endregion
576
761
  //#region src/nodes/requestBody.ts
577
762
  /**
578
- * Definition for the {@link RequestBodyNode}, normalizing each content entry into a `ContentNode`.
763
+ * Definition for the {@link RequestBodyNode}. Content entries are built upfront with
764
+ * {@link createContent}, mirroring how `parameters` and `responses` take prebuilt nodes.
579
765
  */
580
766
  const requestBodyDef = defineNode({
581
767
  kind: "RequestBody",
582
- build: (props) => ({
583
- ...props,
584
- content: props.content?.map(createContent)
585
- }),
586
768
  children: ["content"]
587
769
  });
588
770
  /**
589
- * Creates a `RequestBodyNode`, normalizing each content entry into a `ContentNode`.
771
+ * Creates a `RequestBodyNode`.
590
772
  */
591
773
  const createRequestBody = requestBodyDef.create;
592
774
  //#endregion
@@ -645,22 +827,22 @@ function createOutput(overrides = {}) {
645
827
  //#endregion
646
828
  //#region src/nodes/parameter.ts
647
829
  /**
648
- * Definition for the {@link ParameterNode}. `required` defaults to `false` and the
649
- * schema's `optional`/`nullish` flags are kept in sync with it.
830
+ * Definition for the {@link ParameterNode}. `required` defaults to `false`. When a `dialect` is
831
+ * passed to `create`, the schema's `optional`/`nullish` flags are derived through its
832
+ * `optionality`; without one, the schema is left as-is.
650
833
  */
651
834
  const parameterDef = defineNode({
652
835
  kind: "Parameter",
653
- build: (props) => {
836
+ build: (props, dialect) => {
654
837
  const required = props.required ?? false;
655
838
  return {
656
839
  ...props,
657
840
  required,
658
- schema: syncOptionality(props.schema, required)
841
+ schema: dialect ? dialect.schema.optionality(props.schema, required) : props.schema
659
842
  };
660
843
  },
661
844
  children: ["schema"],
662
- visitorKey: "parameter",
663
- rebuild: true
845
+ visitorKey: "parameter"
664
846
  });
665
847
  /**
666
848
  * Creates a `ParameterNode`.
@@ -677,6 +859,40 @@ const parameterDef = defineNode({
677
859
  */
678
860
  const createParameter = parameterDef.create;
679
861
  //#endregion
862
+ //#region src/nodes/property.ts
863
+ /**
864
+ * Definition for the {@link PropertyNode}. `required` defaults to `false`. When a `dialect` is
865
+ * passed to `create`, the schema's `optional`/`nullish` flags are derived through its
866
+ * `optionality`; without one, the schema is left as-is.
867
+ */
868
+ const propertyDef = defineNode({
869
+ kind: "Property",
870
+ build: (props, dialect) => {
871
+ const required = props.required ?? false;
872
+ return {
873
+ ...props,
874
+ required,
875
+ schema: dialect ? dialect.schema.optionality(props.schema, required) : props.schema
876
+ };
877
+ },
878
+ children: ["schema"],
879
+ visitorKey: "property"
880
+ });
881
+ /**
882
+ * Creates a `PropertyNode`.
883
+ *
884
+ * @example
885
+ * ```ts
886
+ * const property = createProperty({
887
+ * name: 'status',
888
+ * required: true,
889
+ * schema: createSchema({ type: 'string', nullable: true }),
890
+ * })
891
+ * // required=true, no optional/nullish
892
+ * ```
893
+ */
894
+ const createProperty = propertyDef.create;
895
+ //#endregion
680
896
  //#region src/nodes/response.ts
681
897
  /**
682
898
  * Definition for the {@link ResponseNode}. A single legacy `schema` (with optional
@@ -686,14 +902,14 @@ const responseDef = defineNode({
686
902
  kind: "Response",
687
903
  build: (props) => {
688
904
  const { schema, mediaType, keysToOmit, content, ...rest } = props;
689
- const entries = content ?? (schema ? [{
905
+ const entries = content ?? (schema ? [createContent({
690
906
  contentType: mediaType ?? "application/json",
691
907
  schema,
692
908
  keysToOmit: keysToOmit ?? null
693
- }] : void 0);
909
+ })] : void 0);
694
910
  return {
695
911
  ...rest,
696
- content: entries?.map(createContent)
912
+ content: entries
697
913
  };
698
914
  },
699
915
  children: ["content"],
@@ -706,7 +922,7 @@ const responseDef = defineNode({
706
922
  * ```ts
707
923
  * const response = createResponse({
708
924
  * statusCode: '200',
709
- * content: [{ contentType: 'application/json', schema: createSchema({ type: 'object', properties: [] }) }],
925
+ * content: [createContent({ contentType: 'application/json', schema: createSchema({ type: 'object', properties: [] }) })],
710
926
  * })
711
927
  * ```
712
928
  */
@@ -724,12 +940,6 @@ Object.defineProperty(exports, "__name", {
724
940
  return __name;
725
941
  }
726
942
  });
727
- Object.defineProperty(exports, "__toESM", {
728
- enumerable: true,
729
- get: function() {
730
- return __toESM;
731
- }
732
- });
733
943
  Object.defineProperty(exports, "arrowFunctionDef", {
734
944
  enumerable: true,
735
945
  get: function() {
@@ -790,6 +1000,12 @@ Object.defineProperty(exports, "createExport", {
790
1000
  return createExport;
791
1001
  }
792
1002
  });
1003
+ Object.defineProperty(exports, "createFile", {
1004
+ enumerable: true,
1005
+ get: function() {
1006
+ return createFile;
1007
+ }
1008
+ });
793
1009
  Object.defineProperty(exports, "createFunction", {
794
1010
  enumerable: true,
795
1011
  get: function() {
@@ -1030,12 +1246,6 @@ Object.defineProperty(exports, "sourceDef", {
1030
1246
  return sourceDef;
1031
1247
  }
1032
1248
  });
1033
- Object.defineProperty(exports, "syncOptionality", {
1034
- enumerable: true,
1035
- get: function() {
1036
- return syncOptionality;
1037
- }
1038
- });
1039
1249
  Object.defineProperty(exports, "textDef", {
1040
1250
  enumerable: true,
1041
1251
  get: function() {
@@ -1054,5 +1264,11 @@ Object.defineProperty(exports, "typeLiteralDef", {
1054
1264
  return typeLiteralDef;
1055
1265
  }
1056
1266
  });
1267
+ Object.defineProperty(exports, "visitorKeys", {
1268
+ enumerable: true,
1269
+ get: function() {
1270
+ return visitorKeys;
1271
+ }
1272
+ });
1057
1273
 
1058
- //# sourceMappingURL=response-DS5S3IG4.cjs.map
1274
+ //# sourceMappingURL=response-BeG6hq2D.cjs.map