@kubb/ast 5.0.0-beta.61 → 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 (86) hide show
  1. package/dist/{defineMacro-Bv9R_9a2.cjs → defineMacro-BryDiuQl.cjs} +12 -20
  2. package/dist/defineMacro-BryDiuQl.cjs.map +1 -0
  3. package/dist/{defineMacro-BTXvS8nI.js → defineMacro-CNkUpxia.js} +12 -19
  4. package/dist/defineMacro-CNkUpxia.js.map +1 -0
  5. package/dist/{defineMacro-BLIR6k-j.d.ts → defineMacro-Vw-xQvq7.d.ts} +9 -17
  6. package/dist/factory.cjs +64 -4
  7. package/dist/factory.cjs.map +1 -0
  8. package/dist/factory.d.ts +2 -37
  9. package/dist/factory.js +58 -3
  10. package/dist/factory.js.map +1 -0
  11. package/dist/{index-BzjwdK2M.d.ts → index-CTaN_ee_.d.ts} +235 -198
  12. package/dist/index.cjs +19 -20
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.ts +36 -37
  15. package/dist/index.js +19 -17
  16. package/dist/index.js.map +1 -1
  17. package/dist/macros.cjs +33 -20
  18. package/dist/macros.cjs.map +1 -1
  19. package/dist/macros.d.ts +13 -11
  20. package/dist/macros.js +33 -20
  21. package/dist/macros.js.map +1 -1
  22. package/dist/{operationParams-BZ07xDm0.d.ts → operationParams-B44p6EQy.d.ts} +2 -2
  23. package/dist/{response-hnSw2NKE.cjs → response-BeG6hq2D.cjs} +394 -147
  24. package/dist/response-BeG6hq2D.cjs.map +1 -0
  25. package/dist/{response-KUdWiDWw.js → response-Rd1uisM1.js} +376 -136
  26. package/dist/response-Rd1uisM1.js.map +1 -0
  27. package/dist/{types-DyDzizSf.d.ts → types-DQTgVSwE.d.ts} +4 -54
  28. package/dist/types.d.ts +5 -6
  29. package/dist/{utils-BLJwyza-.cjs → utils-BDI3kXlb.cjs} +5 -5
  30. package/dist/{utils-BLJwyza-.cjs.map → utils-BDI3kXlb.cjs.map} +1 -1
  31. package/dist/{utils-CF_-Pn_c.js → utils-DW9rnfsD.js} +5 -5
  32. package/dist/{utils-CF_-Pn_c.js.map → utils-DW9rnfsD.js.map} +1 -1
  33. package/dist/utils.cjs +4 -4
  34. package/dist/utils.d.ts +11 -3
  35. package/dist/utils.js +3 -3
  36. package/dist/{visitor-DpKZ9Tk0.cjs → visitor-B7Zlnp4c.cjs} +3 -53
  37. package/dist/visitor-B7Zlnp4c.cjs.map +1 -0
  38. package/dist/{visitor-DJ6ZEJvq.js → visitor-DepQEKyp.js} +4 -42
  39. package/dist/visitor-DepQEKyp.js.map +1 -0
  40. package/package.json +1 -1
  41. package/src/constants.ts +0 -30
  42. package/src/dedupe.ts +1 -9
  43. package/src/defineMacro.ts +19 -12
  44. package/src/{node.ts → defineNode.ts} +19 -42
  45. package/src/dialect.ts +42 -19
  46. package/src/factory.ts +3 -90
  47. package/src/index.ts +6 -8
  48. package/src/macros/macroDiscriminatorEnum.ts +7 -1
  49. package/src/macros/macroEnumName.ts +9 -1
  50. package/src/macros/macroSimplifyUnion.ts +29 -19
  51. package/src/nodes/code.ts +32 -75
  52. package/src/nodes/content.ts +2 -7
  53. package/src/nodes/file.ts +102 -14
  54. package/src/nodes/function.ts +46 -46
  55. package/src/nodes/index.ts +2 -3
  56. package/src/nodes/input.ts +13 -9
  57. package/src/nodes/operation.ts +5 -5
  58. package/src/nodes/output.ts +1 -1
  59. package/src/nodes/parameter.ts +6 -6
  60. package/src/nodes/property.ts +6 -6
  61. package/src/nodes/requestBody.ts +6 -13
  62. package/src/nodes/response.ts +93 -8
  63. package/src/nodes/schema.ts +1 -1
  64. package/src/registry.ts +1 -1
  65. package/src/types.ts +4 -5
  66. package/src/utils/extractStringsFromNodes.ts +1 -0
  67. package/src/utils/operationParams.ts +1 -1
  68. package/src/visitor.ts +2 -13
  69. package/dist/defineMacro-BTXvS8nI.js.map +0 -1
  70. package/dist/defineMacro-Bv9R_9a2.cjs.map +0 -1
  71. package/dist/extractStringsFromNodes-Cja-xxx5.js +0 -29
  72. package/dist/extractStringsFromNodes-Cja-xxx5.js.map +0 -1
  73. package/dist/extractStringsFromNodes-DKgDjFO0.cjs +0 -34
  74. package/dist/extractStringsFromNodes-DKgDjFO0.cjs.map +0 -1
  75. package/dist/extractStringsFromNodes-p4mX1TQD.d.ts +0 -14
  76. package/dist/factory-CZNOGI-N.js +0 -283
  77. package/dist/factory-CZNOGI-N.js.map +0 -1
  78. package/dist/factory-DG1CVkEb.cjs +0 -300
  79. package/dist/factory-DG1CVkEb.cjs.map +0 -1
  80. package/dist/response-KUdWiDWw.js.map +0 -1
  81. package/dist/response-hnSw2NKE.cjs.map +0 -1
  82. package/dist/visitor-DJ6ZEJvq.js.map +0 -1
  83. package/dist/visitor-DpKZ9Tk0.cjs.map +0 -1
  84. package/src/mocks.ts +0 -56
  85. package/src/nodes/http.ts +0 -85
  86. /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,12 +190,87 @@ 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
210
+ //#region src/utils/extractStringsFromNodes.ts
211
+ /**
212
+ * Extracts all string content from a `CodeNode` tree recursively.
213
+ *
214
+ * Collects text node values, identifier references in string fields (`params`, `generics`, `returnType`, `type`),
215
+ * and nested node content. Used to build the full source string for import filtering.
216
+ */
217
+ function extractStringsFromNodes(nodes) {
218
+ if (!nodes?.length) return "";
219
+ return nodes.map((node) => {
220
+ if (typeof node === "string") return node;
221
+ if (node.kind === "Text") return node.value;
222
+ if (node.kind === "Break") return "";
223
+ if (node.kind === "Jsx") return node.value;
224
+ const parts = [];
225
+ if ("params" in node && node.params) parts.push(node.params);
226
+ if ("generics" in node && node.generics) parts.push(Array.isArray(node.generics) ? node.generics.join(", ") : node.generics);
227
+ if ("returnType" in node && node.returnType) parts.push(node.returnType);
228
+ if ("type" in node && typeof node.type === "string") parts.push(node.type);
229
+ const nested = extractStringsFromNodes(node.nodes);
230
+ if (nested) parts.push(nested);
231
+ return parts.join("\n");
232
+ }).filter(Boolean).join("\n");
233
+ }
234
+ //#endregion
200
235
  //#region src/nodes/code.ts
201
236
  /**
202
237
  * Definition for the {@link ConstNode}.
203
238
  */
204
239
  const constDef = defineNode({ kind: "Const" });
205
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 })
258
+ });
259
+ /**
260
+ * Definition for the {@link BreakNode}.
261
+ */
262
+ const breakDef = defineNode({
263
+ kind: "Break",
264
+ build: () => ({})
265
+ });
266
+ /**
267
+ * Definition for the {@link JsxNode}.
268
+ */
269
+ const jsxDef = defineNode({
270
+ kind: "Jsx",
271
+ build: (value) => ({ value })
272
+ });
273
+ /**
206
274
  * Creates a `ConstNode` representing a TypeScript `const` declaration.
207
275
  *
208
276
  * @example Exported constant with type and `as const`
@@ -213,10 +281,6 @@ const constDef = defineNode({ kind: "Const" });
213
281
  */
214
282
  const createConst = constDef.create;
215
283
  /**
216
- * Definition for the {@link TypeNode}.
217
- */
218
- const typeDef = defineNode({ kind: "Type" });
219
- /**
220
284
  * Creates a `TypeNode` representing a TypeScript `type` alias declaration.
221
285
  *
222
286
  * @example
@@ -227,10 +291,6 @@ const typeDef = defineNode({ kind: "Type" });
227
291
  */
228
292
  const createType = typeDef.create;
229
293
  /**
230
- * Definition for the {@link FunctionNode}.
231
- */
232
- const functionDef = defineNode({ kind: "Function" });
233
- /**
234
294
  * Creates a `FunctionNode` representing a TypeScript `function` declaration.
235
295
  *
236
296
  * @example
@@ -241,10 +301,6 @@ const functionDef = defineNode({ kind: "Function" });
241
301
  */
242
302
  const createFunction = functionDef.create;
243
303
  /**
244
- * Definition for the {@link ArrowFunctionNode}.
245
- */
246
- const arrowFunctionDef = defineNode({ kind: "ArrowFunction" });
247
- /**
248
304
  * Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
249
305
  *
250
306
  * @example
@@ -255,13 +311,6 @@ const arrowFunctionDef = defineNode({ kind: "ArrowFunction" });
255
311
  */
256
312
  const createArrowFunction = arrowFunctionDef.create;
257
313
  /**
258
- * Definition for the {@link TextNode}.
259
- */
260
- const textDef = defineNode({
261
- kind: "Text",
262
- build: (value) => ({ value })
263
- });
264
- /**
265
314
  * Creates a {@link TextNode} representing a raw string fragment in the source output.
266
315
  *
267
316
  * @example
@@ -272,13 +321,6 @@ const textDef = defineNode({
272
321
  */
273
322
  const createText = textDef.create;
274
323
  /**
275
- * Definition for the {@link BreakNode}.
276
- */
277
- const breakDef = defineNode({
278
- kind: "Break",
279
- build: () => ({})
280
- });
281
- /**
282
324
  * Creates a {@link BreakNode} representing a line break in the source output.
283
325
  *
284
326
  * @example
@@ -291,13 +333,6 @@ function createBreak() {
291
333
  return breakDef.create();
292
334
  }
293
335
  /**
294
- * Definition for the {@link JsxNode}.
295
- */
296
- const jsxDef = defineNode({
297
- kind: "Jsx",
298
- build: (value) => ({ value })
299
- });
300
- /**
301
336
  * Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
302
337
  *
303
338
  * @example
@@ -321,12 +356,171 @@ const contentDef = defineNode({
321
356
  */
322
357
  const createContent = contentDef.create;
323
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
324
505
  //#region src/nodes/file.ts
325
506
  /**
326
507
  * Definition for the {@link ImportNode}.
327
508
  */
328
509
  const importDef = defineNode({ kind: "Import" });
329
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
+ /**
330
524
  * Creates an `ImportNode` representing a language-agnostic import/dependency declaration.
331
525
  *
332
526
  * @example Named import
@@ -337,10 +531,6 @@ const importDef = defineNode({ kind: "Import" });
337
531
  */
338
532
  const createImport = importDef.create;
339
533
  /**
340
- * Definition for the {@link ExportNode}.
341
- */
342
- const exportDef = defineNode({ kind: "Export" });
343
- /**
344
534
  * Creates an `ExportNode` representing a language-agnostic export/public API declaration.
345
535
  *
346
536
  * @example Named export
@@ -351,10 +541,6 @@ const exportDef = defineNode({ kind: "Export" });
351
541
  */
352
542
  const createExport = exportDef.create;
353
543
  /**
354
- * Definition for the {@link SourceNode}.
355
- */
356
- const sourceDef = defineNode({ kind: "Source" });
357
- /**
358
544
  * Creates a `SourceNode` representing a fragment of source code within a file.
359
545
  *
360
546
  * @example
@@ -364,10 +550,64 @@ const sourceDef = defineNode({ kind: "Source" });
364
550
  */
365
551
  const createSource = sourceDef.create;
366
552
  /**
367
- * Definition for the {@link FileNode}. The fully resolved builder lives in
368
- * `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
+ * ```
369
580
  */
370
- 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
+ }
371
611
  //#endregion
372
612
  //#region src/nodes/function.ts
373
613
  /**
@@ -375,44 +615,14 @@ const fileDef = defineNode({ kind: "File" });
375
615
  */
376
616
  const typeLiteralDef = defineNode({ kind: "TypeLiteral" });
377
617
  /**
378
- * Creates a {@link TypeLiteralNode} representing an inline anonymous object type.
379
- *
380
- * @example
381
- * ```ts
382
- * createTypeLiteral({ members: [{ name: 'petId', type: 'string', optional: false }] })
383
- * // { petId: string }
384
- * ```
385
- */
386
- const createTypeLiteral = typeLiteralDef.create;
387
- /**
388
618
  * Definition for the {@link IndexedAccessTypeNode}.
389
619
  */
390
620
  const indexedAccessTypeDef = defineNode({ kind: "IndexedAccessType" });
391
621
  /**
392
- * Creates an {@link IndexedAccessTypeNode} representing a single field accessed from a named type.
393
- *
394
- * @example
395
- * ```ts
396
- * createIndexedAccessType({ objectType: 'DeletePetPathParams', indexType: 'petId' })
397
- * // DeletePetPathParams['petId']
398
- * ```
399
- */
400
- const createIndexedAccessType = indexedAccessTypeDef.create;
401
- /**
402
622
  * Definition for the {@link ObjectBindingPatternNode}.
403
623
  */
404
624
  const objectBindingPatternDef = defineNode({ kind: "ObjectBindingPattern" });
405
625
  /**
406
- * Creates an {@link ObjectBindingPatternNode} for a destructured parameter binding.
407
- *
408
- * @example
409
- * ```ts
410
- * createObjectBindingPattern({ elements: [{ name: 'id' }, { name: 'name' }] })
411
- * // { id, name }
412
- * ```
413
- */
414
- const createObjectBindingPattern = objectBindingPatternDef.create;
415
- /**
416
626
  * Definition for the {@link FunctionParameterNode}. `optional` defaults to `false`.
417
627
  * Passing `properties` builds a destructured group: an {@link ObjectBindingPatternNode} name
418
628
  * paired with a {@link TypeLiteralNode} type.
@@ -437,6 +647,43 @@ const functionParameterDef = defineNode({
437
647
  }
438
648
  });
439
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
+ /**
440
687
  * Creates a `FunctionParameterNode`. `optional` defaults to `false`.
441
688
  *
442
689
  * @example Optional param
@@ -453,13 +700,6 @@ const functionParameterDef = defineNode({
453
700
  */
454
701
  const createFunctionParameter = functionParameterDef.create;
455
702
  /**
456
- * Definition for the {@link FunctionParametersNode}.
457
- */
458
- const functionParametersDef = defineNode({
459
- kind: "FunctionParameters",
460
- defaults: { params: [] }
461
- });
462
- /**
463
703
  * Creates a `FunctionParametersNode` from an ordered list of parameters.
464
704
  *
465
705
  * @example
@@ -491,8 +731,8 @@ const inputDef = defineNode({
491
731
  });
492
732
  /**
493
733
  * Creates an `InputNode`. Pass `stream: true` for the streaming variant whose `schemas` and
494
- * `operations` are `AsyncIterable` sources and whose `meta` is optional. Otherwise it builds the
495
- * 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`.
496
736
  *
497
737
  * @example Eager
498
738
  * ```ts
@@ -509,6 +749,10 @@ function createInput(options = {}) {
509
749
  const { stream, ...overrides } = options;
510
750
  if (stream) return {
511
751
  kind: "Input",
752
+ meta: {
753
+ circularNames: [],
754
+ enumNames: []
755
+ },
512
756
  ...overrides
513
757
  };
514
758
  return inputDef.create(overrides);
@@ -516,18 +760,15 @@ function createInput(options = {}) {
516
760
  //#endregion
517
761
  //#region src/nodes/requestBody.ts
518
762
  /**
519
- * 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.
520
765
  */
521
766
  const requestBodyDef = defineNode({
522
767
  kind: "RequestBody",
523
- build: (props) => ({
524
- ...props,
525
- content: props.content?.map(createContent)
526
- }),
527
768
  children: ["content"]
528
769
  });
529
770
  /**
530
- * Creates a `RequestBodyNode`, normalizing each content entry into a `ContentNode`.
771
+ * Creates a `RequestBodyNode`.
531
772
  */
532
773
  const createRequestBody = requestBodyDef.create;
533
774
  //#endregion
@@ -586,22 +827,22 @@ function createOutput(overrides = {}) {
586
827
  //#endregion
587
828
  //#region src/nodes/parameter.ts
588
829
  /**
589
- * Definition for the {@link ParameterNode}. `required` defaults to `false` and the
590
- * 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.
591
833
  */
592
834
  const parameterDef = defineNode({
593
835
  kind: "Parameter",
594
- build: (props) => {
836
+ build: (props, dialect) => {
595
837
  const required = props.required ?? false;
596
838
  return {
597
839
  ...props,
598
840
  required,
599
- schema: syncOptionality(props.schema, required)
841
+ schema: dialect ? dialect.schema.optionality(props.schema, required) : props.schema
600
842
  };
601
843
  },
602
844
  children: ["schema"],
603
- visitorKey: "parameter",
604
- rebuild: true
845
+ visitorKey: "parameter"
605
846
  });
606
847
  /**
607
848
  * Creates a `ParameterNode`.
@@ -620,22 +861,22 @@ const createParameter = parameterDef.create;
620
861
  //#endregion
621
862
  //#region src/nodes/property.ts
622
863
  /**
623
- * Definition for the {@link PropertyNode}. `required` defaults to `false` and the
624
- * schema's `optional`/`nullish` flags are kept in sync with it.
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.
625
867
  */
626
868
  const propertyDef = defineNode({
627
869
  kind: "Property",
628
- build: (props) => {
870
+ build: (props, dialect) => {
629
871
  const required = props.required ?? false;
630
872
  return {
631
873
  ...props,
632
874
  required,
633
- schema: syncOptionality(props.schema, required)
875
+ schema: dialect ? dialect.schema.optionality(props.schema, required) : props.schema
634
876
  };
635
877
  },
636
878
  children: ["schema"],
637
- visitorKey: "property",
638
- rebuild: true
879
+ visitorKey: "property"
639
880
  });
640
881
  /**
641
882
  * Creates a `PropertyNode`.
@@ -661,14 +902,14 @@ const responseDef = defineNode({
661
902
  kind: "Response",
662
903
  build: (props) => {
663
904
  const { schema, mediaType, keysToOmit, content, ...rest } = props;
664
- const entries = content ?? (schema ? [{
905
+ const entries = content ?? (schema ? [createContent({
665
906
  contentType: mediaType ?? "application/json",
666
907
  schema,
667
908
  keysToOmit: keysToOmit ?? null
668
- }] : void 0);
909
+ })] : void 0);
669
910
  return {
670
911
  ...rest,
671
- content: entries?.map(createContent)
912
+ content: entries
672
913
  };
673
914
  },
674
915
  children: ["content"],
@@ -681,7 +922,7 @@ const responseDef = defineNode({
681
922
  * ```ts
682
923
  * const response = createResponse({
683
924
  * statusCode: '200',
684
- * content: [{ contentType: 'application/json', schema: createSchema({ type: 'object', properties: [] }) }],
925
+ * content: [createContent({ contentType: 'application/json', schema: createSchema({ type: 'object', properties: [] }) })],
685
926
  * })
686
927
  * ```
687
928
  */
@@ -699,12 +940,6 @@ Object.defineProperty(exports, "__name", {
699
940
  return __name;
700
941
  }
701
942
  });
702
- Object.defineProperty(exports, "__toESM", {
703
- enumerable: true,
704
- get: function() {
705
- return __toESM;
706
- }
707
- });
708
943
  Object.defineProperty(exports, "arrowFunctionDef", {
709
944
  enumerable: true,
710
945
  get: function() {
@@ -765,6 +1000,12 @@ Object.defineProperty(exports, "createExport", {
765
1000
  return createExport;
766
1001
  }
767
1002
  });
1003
+ Object.defineProperty(exports, "createFile", {
1004
+ enumerable: true,
1005
+ get: function() {
1006
+ return createFile;
1007
+ }
1008
+ });
768
1009
  Object.defineProperty(exports, "createFunction", {
769
1010
  enumerable: true,
770
1011
  get: function() {
@@ -891,6 +1132,12 @@ Object.defineProperty(exports, "exportDef", {
891
1132
  return exportDef;
892
1133
  }
893
1134
  });
1135
+ Object.defineProperty(exports, "extractStringsFromNodes", {
1136
+ enumerable: true,
1137
+ get: function() {
1138
+ return extractStringsFromNodes;
1139
+ }
1140
+ });
894
1141
  Object.defineProperty(exports, "fileDef", {
895
1142
  enumerable: true,
896
1143
  get: function() {
@@ -999,12 +1246,6 @@ Object.defineProperty(exports, "sourceDef", {
999
1246
  return sourceDef;
1000
1247
  }
1001
1248
  });
1002
- Object.defineProperty(exports, "syncOptionality", {
1003
- enumerable: true,
1004
- get: function() {
1005
- return syncOptionality;
1006
- }
1007
- });
1008
1249
  Object.defineProperty(exports, "textDef", {
1009
1250
  enumerable: true,
1010
1251
  get: function() {
@@ -1023,5 +1264,11 @@ Object.defineProperty(exports, "typeLiteralDef", {
1023
1264
  return typeLiteralDef;
1024
1265
  }
1025
1266
  });
1267
+ Object.defineProperty(exports, "visitorKeys", {
1268
+ enumerable: true,
1269
+ get: function() {
1270
+ return visitorKeys;
1271
+ }
1272
+ });
1026
1273
 
1027
- //# sourceMappingURL=response-hnSw2NKE.cjs.map
1274
+ //# sourceMappingURL=response-BeG6hq2D.cjs.map