@kubb/agent 5.0.0-beta.3 → 5.0.0-beta.31

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 (156) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/server/chunks/nitro/nitro.mjs +1965 -1827
  3. package/.output/server/chunks/nitro/nitro.mjs.map +1 -1
  4. package/.output/server/chunks/routes/api/health.get.mjs +1 -1
  5. package/.output/server/index.mjs +1 -1
  6. package/.output/server/node_modules/ajv/dist/2019.d.ts +1 -1
  7. package/.output/server/node_modules/ajv/dist/2019.js.map +1 -1
  8. package/.output/server/node_modules/ajv/dist/2020.d.ts +1 -1
  9. package/.output/server/node_modules/ajv/dist/2020.js.map +1 -1
  10. package/.output/server/node_modules/ajv/dist/ajv.d.ts +1 -1
  11. package/.output/server/node_modules/ajv/dist/ajv.js.map +1 -1
  12. package/.output/server/node_modules/ajv/dist/compile/index.d.ts +2 -1
  13. package/.output/server/node_modules/ajv/dist/compile/index.js +10 -3
  14. package/.output/server/node_modules/ajv/dist/compile/index.js.map +1 -1
  15. package/.output/server/node_modules/ajv/dist/compile/jtd/parse.js +1 -1
  16. package/.output/server/node_modules/ajv/dist/compile/jtd/parse.js.map +1 -1
  17. package/.output/server/node_modules/ajv/dist/compile/jtd/serialize.js +1 -1
  18. package/.output/server/node_modules/ajv/dist/compile/jtd/serialize.js.map +1 -1
  19. package/.output/server/node_modules/ajv/dist/compile/names.d.ts +1 -0
  20. package/.output/server/node_modules/ajv/dist/compile/names.js +1 -0
  21. package/.output/server/node_modules/ajv/dist/compile/names.js.map +1 -1
  22. package/.output/server/node_modules/ajv/dist/compile/validate/index.d.ts +1 -1
  23. package/.output/server/node_modules/ajv/dist/compile/validate/index.js +18 -4
  24. package/.output/server/node_modules/ajv/dist/compile/validate/index.js.map +1 -1
  25. package/.output/server/node_modules/ajv/dist/core.d.ts +4 -0
  26. package/.output/server/node_modules/ajv/dist/core.js +15 -1
  27. package/.output/server/node_modules/ajv/dist/core.js.map +1 -1
  28. package/.output/server/node_modules/ajv/dist/draft4.d.ts +19 -0
  29. package/.output/server/node_modules/ajv/dist/draft4.js +57 -0
  30. package/.output/server/node_modules/ajv/dist/draft4.js.map +1 -0
  31. package/.output/server/node_modules/ajv/dist/refs/json-schema-draft-04.json +138 -0
  32. package/.output/server/node_modules/ajv/dist/types/index.d.ts +3 -0
  33. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/additionalProperties.js +2 -1
  34. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/additionalProperties.js.map +1 -1
  35. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/allOf.js +1 -1
  36. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/allOf.js.map +1 -1
  37. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/properties.js +2 -1
  38. package/.output/server/node_modules/ajv/dist/vocabularies/applicator/properties.js.map +1 -1
  39. package/.output/server/node_modules/ajv/dist/vocabularies/code.d.ts +1 -1
  40. package/.output/server/node_modules/ajv/dist/vocabularies/code.js +10 -3
  41. package/.output/server/node_modules/ajv/dist/vocabularies/code.js.map +1 -1
  42. package/.output/server/node_modules/ajv/dist/vocabularies/core/ref.js +12 -2
  43. package/.output/server/node_modules/ajv/dist/vocabularies/core/ref.js.map +1 -1
  44. package/.output/server/node_modules/ajv/dist/vocabularies/discriminator/index.js +56 -21
  45. package/.output/server/node_modules/ajv/dist/vocabularies/discriminator/index.js.map +1 -1
  46. package/.output/server/node_modules/ajv/dist/vocabularies/draft4.d.ts +3 -0
  47. package/.output/server/node_modules/ajv/dist/vocabularies/draft4.js +29 -0
  48. package/.output/server/node_modules/ajv/dist/vocabularies/draft4.js.map +1 -0
  49. package/.output/server/node_modules/ajv/dist/vocabularies/metadata.js +10 -2
  50. package/.output/server/node_modules/ajv/dist/vocabularies/metadata.js.map +1 -1
  51. package/.output/server/node_modules/ajv/dist/vocabularies/oasContext.d.ts +3 -0
  52. package/.output/server/node_modules/ajv/dist/vocabularies/oasContext.js +26 -0
  53. package/.output/server/node_modules/ajv/dist/vocabularies/oasContext.js.map +1 -0
  54. package/.output/server/node_modules/ajv/dist/vocabularies/unevaluated/unevaluatedProperties.js +22 -3
  55. package/.output/server/node_modules/ajv/dist/vocabularies/unevaluated/unevaluatedProperties.js.map +1 -1
  56. package/.output/server/node_modules/ajv/dist/vocabularies/validation/draft04/limitNumber.d.ts +12 -0
  57. package/.output/server/node_modules/ajv/dist/vocabularies/validation/draft04/limitNumber.js +43 -0
  58. package/.output/server/node_modules/ajv/dist/vocabularies/validation/draft04/limitNumber.js.map +1 -0
  59. package/.output/server/node_modules/ajv/dist/vocabularies/validation/draft04/limitNumberExclusive.d.ts +3 -0
  60. package/.output/server/node_modules/ajv/dist/vocabularies/validation/draft04/limitNumberExclusive.js +19 -0
  61. package/.output/server/node_modules/ajv/dist/vocabularies/validation/draft04/limitNumberExclusive.js.map +1 -0
  62. package/.output/server/node_modules/ajv/dist/vocabularies/validation/index.js +4 -0
  63. package/.output/server/node_modules/ajv/dist/vocabularies/validation/index.js.map +1 -1
  64. package/.output/server/node_modules/ajv/dist/vocabularies/validation/readOnly.d.ts +3 -0
  65. package/.output/server/node_modules/ajv/dist/vocabularies/validation/readOnly.js +20 -0
  66. package/.output/server/node_modules/ajv/dist/vocabularies/validation/readOnly.js.map +1 -0
  67. package/.output/server/node_modules/ajv/dist/vocabularies/validation/required.js +8 -1
  68. package/.output/server/node_modules/ajv/dist/vocabularies/validation/required.js.map +1 -1
  69. package/.output/server/node_modules/ajv/dist/vocabularies/validation/writeOnly.d.ts +3 -0
  70. package/.output/server/node_modules/ajv/dist/vocabularies/validation/writeOnly.js +20 -0
  71. package/.output/server/node_modules/ajv/dist/vocabularies/validation/writeOnly.js.map +1 -0
  72. package/.output/server/node_modules/ajv/lib/2019.ts +1 -0
  73. package/.output/server/node_modules/ajv/lib/2020.ts +1 -0
  74. package/.output/server/node_modules/ajv/lib/ajv.ts +1 -0
  75. package/.output/server/node_modules/ajv/lib/compile/index.ts +16 -3
  76. package/.output/server/node_modules/ajv/lib/compile/jtd/parse.ts +3 -1
  77. package/.output/server/node_modules/ajv/lib/compile/jtd/serialize.ts +3 -1
  78. package/.output/server/node_modules/ajv/lib/compile/names.ts +1 -0
  79. package/.output/server/node_modules/ajv/lib/compile/validate/index.ts +21 -4
  80. package/.output/server/node_modules/ajv/lib/core.ts +20 -1
  81. package/.output/server/node_modules/ajv/lib/draft4.ts +79 -0
  82. package/.output/server/node_modules/ajv/lib/refs/json-schema-draft-04.json +138 -0
  83. package/.output/server/node_modules/ajv/lib/types/index.ts +4 -0
  84. package/.output/server/node_modules/ajv/lib/vocabularies/applicator/additionalProperties.ts +2 -1
  85. package/.output/server/node_modules/ajv/lib/vocabularies/applicator/allOf.ts +1 -1
  86. package/.output/server/node_modules/ajv/lib/vocabularies/applicator/properties.ts +4 -1
  87. package/.output/server/node_modules/ajv/lib/vocabularies/code.ts +10 -3
  88. package/.output/server/node_modules/ajv/lib/vocabularies/core/ref.ts +21 -5
  89. package/.output/server/node_modules/ajv/lib/vocabularies/discriminator/index.ts +69 -19
  90. package/.output/server/node_modules/ajv/lib/vocabularies/draft4.ts +32 -0
  91. package/.output/server/node_modules/ajv/lib/vocabularies/metadata.ts +10 -2
  92. package/.output/server/node_modules/ajv/lib/vocabularies/oasContext.ts +27 -0
  93. package/.output/server/node_modules/ajv/lib/vocabularies/unevaluated/unevaluatedProperties.ts +29 -7
  94. package/.output/server/node_modules/ajv/lib/vocabularies/validation/draft04/limitNumber.ts +75 -0
  95. package/.output/server/node_modules/ajv/lib/vocabularies/validation/draft04/limitNumberExclusive.ts +26 -0
  96. package/.output/server/node_modules/ajv/lib/vocabularies/validation/index.ts +4 -0
  97. package/.output/server/node_modules/ajv/lib/vocabularies/validation/readOnly.ts +23 -0
  98. package/.output/server/node_modules/ajv/lib/vocabularies/validation/required.ts +7 -1
  99. package/.output/server/node_modules/ajv/lib/vocabularies/validation/writeOnly.ts +22 -0
  100. package/.output/server/node_modules/ajv/package.json +9 -6
  101. package/.output/server/node_modules/fflate/esm/index.mjs +87 -56
  102. package/.output/server/node_modules/fflate/package.json +12 -11
  103. package/.output/server/node_modules/jiti/LICENSE +21 -0
  104. package/.output/server/node_modules/jiti/README.md +258 -0
  105. package/.output/server/node_modules/jiti/dist/babel.cjs +257 -0
  106. package/.output/server/node_modules/jiti/dist/jiti.cjs +1 -0
  107. package/.output/server/node_modules/jiti/lib/jiti-cli.mjs +34 -0
  108. package/.output/server/node_modules/jiti/lib/jiti-hooks.mjs +124 -0
  109. package/.output/server/node_modules/jiti/lib/jiti-native.mjs +121 -0
  110. package/.output/server/node_modules/jiti/lib/jiti-register.d.mts +1 -0
  111. package/.output/server/node_modules/jiti/lib/jiti-register.mjs +4 -0
  112. package/.output/server/node_modules/jiti/lib/jiti-static.mjs +23 -0
  113. package/.output/server/node_modules/jiti/lib/jiti.cjs +30 -0
  114. package/.output/server/node_modules/jiti/lib/jiti.d.cts +8 -0
  115. package/.output/server/node_modules/jiti/lib/jiti.d.mts +8 -0
  116. package/.output/server/node_modules/jiti/lib/jiti.mjs +29 -0
  117. package/.output/server/node_modules/jiti/lib/types.d.ts +420 -0
  118. package/.output/server/node_modules/jiti/package.json +146 -0
  119. package/.output/server/node_modules/remeda/dist/hasProp.js +2 -0
  120. package/.output/server/node_modules/remeda/dist/index.js +1 -1
  121. package/.output/server/node_modules/remeda/package.json +12 -12
  122. package/.output/server/node_modules/ws/lib/receiver.js +54 -0
  123. package/.output/server/node_modules/ws/lib/sender.js +6 -1
  124. package/.output/server/node_modules/ws/lib/websocket-server.js +8 -0
  125. package/.output/server/node_modules/ws/lib/websocket.js +14 -0
  126. package/.output/server/node_modules/ws/package.json +1 -1
  127. package/.output/server/package.json +5 -8
  128. package/README.md +62 -27
  129. package/package.json +15 -14
  130. package/.output/server/node_modules/@rolldown/binding-linux-x64-gnu/package.json +0 -40
  131. package/.output/server/node_modules/@rolldown/binding-linux-x64-gnu/rolldown-binding.linux-x64-gnu.node +0 -0
  132. package/.output/server/node_modules/@rolldown/pluginutils/dist/filter/composable-filters.js +0 -256
  133. package/.output/server/node_modules/@rolldown/pluginutils/dist/filter/filter-vite-plugins.js +0 -75
  134. package/.output/server/node_modules/@rolldown/pluginutils/dist/filter/index.js +0 -3
  135. package/.output/server/node_modules/@rolldown/pluginutils/dist/filter/simple-filters.js +0 -70
  136. package/.output/server/node_modules/@rolldown/pluginutils/dist/index.js +0 -1
  137. package/.output/server/node_modules/@rolldown/pluginutils/dist/utils.js +0 -17
  138. package/.output/server/node_modules/@rolldown/pluginutils/package.json +0 -37
  139. package/.output/server/node_modules/rolldown/dist/index.mjs +0 -50
  140. package/.output/server/node_modules/rolldown/dist/parse-ast-index.mjs +0 -60
  141. package/.output/server/node_modules/rolldown/dist/shared/binding-BeU_1iEk.mjs +0 -582
  142. package/.output/server/node_modules/rolldown/dist/shared/bindingify-input-options-DbbBhzky.mjs +0 -2211
  143. package/.output/server/node_modules/rolldown/dist/shared/define-config-DJOr6Iwt.mjs +0 -6
  144. package/.output/server/node_modules/rolldown/dist/shared/error-DL-e8-oE.mjs +0 -85
  145. package/.output/server/node_modules/rolldown/dist/shared/logs-D80CXhvg.mjs +0 -180
  146. package/.output/server/node_modules/rolldown/dist/shared/misc-DJYbNKZX.mjs +0 -21
  147. package/.output/server/node_modules/rolldown/dist/shared/normalize-string-or-regex-CbQQ69gT.mjs +0 -66
  148. package/.output/server/node_modules/rolldown/dist/shared/parse-B_ZnWxLZ.mjs +0 -74
  149. package/.output/server/node_modules/rolldown/dist/shared/prompt-U5ajztzG.mjs +0 -847
  150. package/.output/server/node_modules/rolldown/dist/shared/rolldown-D3JZ9rMt.mjs +0 -40
  151. package/.output/server/node_modules/rolldown/dist/shared/rolldown-build-DSxL8qiP.mjs +0 -3325
  152. package/.output/server/node_modules/rolldown/dist/shared/watch-Bd8v9ewv.mjs +0 -374
  153. package/.output/server/node_modules/rolldown/package.json +0 -153
  154. package/.output/server/node_modules/unrun/dist/index.mjs +0 -2
  155. package/.output/server/node_modules/unrun/dist/src-GU5PtktT.mjs +0 -887
  156. package/.output/server/node_modules/unrun/package.json +0 -125
@@ -18,7 +18,7 @@ import { deflateSync } from 'fflate';
18
18
  import { x } from 'tinyexec';
19
19
  import { access, rm, readFile as readFile$1, readdir as readdir$1, mkdir, writeFile as writeFile$1 } from 'node:fs/promises';
20
20
  import { styleText } from 'node:util';
21
- import { unrun } from 'unrun';
21
+ import { createJiti } from 'jiti';
22
22
  import { mergeDeep } from 'remeda';
23
23
  import WebSocket from 'ws';
24
24
 
@@ -4426,12 +4426,17 @@ function sendToBetterStack(level, tag, message, ctx) {
4426
4426
  const fullMessage = message !== void 0 ? `[${tag}] ${message}` : tag;
4427
4427
  const context = toBetterStackContext(ctx);
4428
4428
  if (level === "error") {
4429
- client.error(fullMessage, context).then(() => client.flush());
4430
- } else if (level === "warn") {
4431
- client.warn(fullMessage, context).then(() => client.flush());
4432
- } else {
4433
- client.info(fullMessage, context).then(() => client.flush());
4429
+ client.error(fullMessage, context).then(() => client.flush()).catch(() => {
4430
+ });
4431
+ return;
4432
+ }
4433
+ if (level === "warn") {
4434
+ client.warn(fullMessage, context).then(() => client.flush()).catch(() => {
4435
+ });
4436
+ return;
4434
4437
  }
4438
+ client.info(fullMessage, context).then(() => client.flush()).catch(() => {
4439
+ });
4435
4440
  } catch (_e) {
4436
4441
  }
4437
4442
  }
@@ -4705,15 +4710,17 @@ async function disconnect({ sessionId, token, studioUrl }) {
4705
4710
  }
4706
4711
  }
4707
4712
 
4708
- var __defProp$2 = Object.defineProperty;
4709
- var __name = (target, value) => __defProp$2(target, "name", {
4710
- value,
4711
- configurable: true
4712
- });
4713
-
4714
4713
  const visitorDepths = {
4715
4714
  deep: "deep"
4716
4715
  };
4716
+ function memoize$1(store, factory) {
4717
+ return (key) => {
4718
+ if (store.has(key)) return store.get(key);
4719
+ const value = factory(key);
4720
+ store.set(key, value);
4721
+ return value;
4722
+ };
4723
+ }
4717
4724
  function trimExtName(text) {
4718
4725
  const dotIndex = text.lastIndexOf(".");
4719
4726
  if (dotIndex > 0 && !text.includes("/", dotIndex)) return text.slice(0, dotIndex);
@@ -4728,265 +4735,112 @@ function extractRefName(ref) {
4728
4735
  var _a;
4729
4736
  return (_a = ref.split("/").at(-1)) != null ? _a : ref;
4730
4737
  }
4731
- function createLimit(concurrency) {
4732
- let active = 0;
4733
- const queue = [];
4734
- function next() {
4735
- if (active < concurrency && queue.length > 0) {
4736
- active++;
4737
- queue.shift()();
4738
- }
4739
- }
4740
- return function limit(fn) {
4741
- return new Promise((resolve, reject) => {
4742
- queue.push(() => {
4743
- Promise.resolve(fn()).then(resolve, reject).finally(() => {
4744
- active--;
4745
- next();
4746
- });
4747
- });
4748
- next();
4749
- });
4750
- };
4751
- }
4752
- function getChildren(node, recurse) {
4753
- var _a, _b, _c;
4754
- switch (node.kind) {
4755
- case "Input":
4756
- return [...node.schemas, ...node.operations];
4757
- case "Output":
4758
- return [];
4759
- case "Operation":
4760
- return [
4761
- ...node.parameters,
4762
- ...(_c = (_b = (_a = node.requestBody) == null ? void 0 : _a.content) == null ? void 0 : _b.flatMap((c) => c.schema ? [c.schema] : [])) != null ? _c : [],
4763
- ...node.responses
4764
- ];
4765
- case "Schema": {
4766
- const children = [];
4767
- if (!recurse) return [];
4768
- if ("properties" in node && node.properties.length > 0) children.push(...node.properties);
4769
- if ("items" in node && node.items) children.push(...node.items);
4770
- if ("members" in node && node.members) children.push(...node.members);
4771
- if ("additionalProperties" in node && node.additionalProperties && node.additionalProperties !== true) children.push(node.additionalProperties);
4772
- return children;
4773
- }
4774
- case "Property":
4775
- return [node.schema];
4776
- case "Parameter":
4777
- return [node.schema];
4778
- case "Response":
4779
- return node.schema ? [node.schema] : [];
4780
- case "FunctionParameter":
4781
- case "ParameterGroup":
4782
- case "FunctionParameters":
4783
- case "Type":
4784
- return [];
4785
- default:
4786
- return [];
4787
- }
4788
- }
4789
- async function walk(node, options) {
4790
- var _a, _b;
4791
- return _walk(node, options, ((_a = options.depth) != null ? _a : visitorDepths.deep) === visitorDepths.deep, createLimit((_b = options.concurrency) != null ? _b : 30), void 0);
4792
- }
4793
- async function _walk(node, visitor, recurse, limit, parent) {
4794
- switch (node.kind) {
4795
- case "Input":
4796
- await limit(() => {
4797
- var _a;
4798
- return (_a = visitor.input) == null ? void 0 : _a.call(visitor, node, { parent });
4799
- });
4800
- break;
4801
- case "Output":
4802
- await limit(() => {
4803
- var _a;
4804
- return (_a = visitor.output) == null ? void 0 : _a.call(visitor, node, { parent });
4805
- });
4806
- break;
4807
- case "Operation":
4808
- await limit(() => {
4809
- var _a;
4810
- return (_a = visitor.operation) == null ? void 0 : _a.call(visitor, node, { parent });
4811
- });
4812
- break;
4813
- case "Schema":
4814
- await limit(() => {
4815
- var _a;
4816
- return (_a = visitor.schema) == null ? void 0 : _a.call(visitor, node, { parent });
4817
- });
4818
- break;
4819
- case "Property":
4820
- await limit(() => {
4821
- var _a;
4822
- return (_a = visitor.property) == null ? void 0 : _a.call(visitor, node, { parent });
4823
- });
4824
- break;
4825
- case "Parameter":
4826
- await limit(() => {
4827
- var _a;
4828
- return (_a = visitor.parameter) == null ? void 0 : _a.call(visitor, node, { parent });
4829
- });
4830
- break;
4831
- case "Response":
4832
- await limit(() => {
4833
- var _a;
4834
- return (_a = visitor.response) == null ? void 0 : _a.call(visitor, node, { parent });
4835
- });
4836
- break;
4837
- }
4838
- const children = getChildren(node, recurse);
4839
- for (const child of children) await _walk(child, visitor, recurse, limit, node);
4738
+ const visitorKeysByKind = {
4739
+ Input: ["schemas", "operations"],
4740
+ Operation: [
4741
+ "parameters",
4742
+ "requestBody",
4743
+ "responses"
4744
+ ],
4745
+ RequestBody: ["content"],
4746
+ Content: ["schema"],
4747
+ Response: ["content"],
4748
+ Schema: [
4749
+ "properties",
4750
+ "items",
4751
+ "members",
4752
+ "additionalProperties"
4753
+ ],
4754
+ Property: ["schema"],
4755
+ Parameter: ["schema"]
4756
+ };
4757
+ function isNode(value) {
4758
+ return typeof value === "object" && value !== null && "kind" in value;
4759
+ }
4760
+ function* getChildren(node, recurse) {
4761
+ if (node.kind === "Schema" && !recurse) return;
4762
+ const keys = visitorKeysByKind[node.kind];
4763
+ if (!keys) return;
4764
+ const record = node;
4765
+ for (const key of keys) {
4766
+ const value = record[key];
4767
+ if (Array.isArray(value)) {
4768
+ for (const item of value) if (isNode(item)) yield item;
4769
+ } else if (isNode(value)) yield value;
4770
+ }
4771
+ }
4772
+ const VISITOR_KEY_BY_KIND = {
4773
+ Input: "input",
4774
+ Output: "output",
4775
+ Operation: "operation",
4776
+ Schema: "schema",
4777
+ Property: "property",
4778
+ Parameter: "parameter",
4779
+ Response: "response"
4780
+ };
4781
+ function applyVisitor(node, visitor, parent) {
4782
+ const key = VISITOR_KEY_BY_KIND[node.kind];
4783
+ if (!key) return void 0;
4784
+ const fn = visitor[key];
4785
+ return fn == null ? void 0 : fn(node, { parent });
4840
4786
  }
4841
4787
  function transform(node, options) {
4842
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
4788
+ var _a;
4843
4789
  const { depth, parent, ...visitor } = options;
4844
4790
  const recurse = (depth != null ? depth : visitorDepths.deep) === visitorDepths.deep;
4845
- switch (node.kind) {
4846
- case "Input": {
4847
- let input = node;
4848
- const replaced = (_a = visitor.input) == null ? void 0 : _a.call(visitor, input, { parent });
4849
- if (replaced) input = replaced;
4850
- return {
4851
- ...input,
4852
- schemas: input.schemas.map((s) => transform(s, {
4853
- ...options,
4854
- parent: input
4855
- })),
4856
- operations: input.operations.map((op) => transform(op, {
4857
- ...options,
4858
- parent: input
4859
- }))
4860
- };
4861
- }
4862
- case "Output": {
4863
- let output = node;
4864
- const replaced = (_b = visitor.output) == null ? void 0 : _b.call(visitor, output, { parent });
4865
- if (replaced) output = replaced;
4866
- return output;
4867
- }
4868
- case "Operation": {
4869
- let op = node;
4870
- const replaced = (_c = visitor.operation) == null ? void 0 : _c.call(visitor, op, { parent });
4871
- if (replaced) op = replaced;
4872
- return {
4873
- ...op,
4874
- parameters: op.parameters.map((p) => transform(p, {
4875
- ...options,
4876
- parent: op
4877
- })),
4878
- requestBody: op.requestBody ? {
4879
- ...op.requestBody,
4880
- content: (_d = op.requestBody.content) == null ? void 0 : _d.map((c) => ({
4881
- ...c,
4882
- schema: c.schema ? transform(c.schema, {
4883
- ...options,
4884
- parent: op
4885
- }) : void 0
4886
- }))
4887
- } : void 0,
4888
- responses: op.responses.map((r) => transform(r, {
4889
- ...options,
4890
- parent: op
4891
- }))
4892
- };
4893
- }
4894
- case "Schema": {
4895
- let schema = node;
4896
- const replaced = (_e = visitor.schema) == null ? void 0 : _e.call(visitor, schema, { parent });
4897
- if (replaced) schema = replaced;
4898
- const childOptions = {
4899
- ...options,
4900
- parent: schema
4901
- };
4902
- return {
4903
- ...schema,
4904
- ..."properties" in schema && recurse ? { properties: schema.properties.map((p) => transform(p, childOptions)) } : {},
4905
- ..."items" in schema && recurse ? { items: (_f = schema.items) == null ? void 0 : _f.map((i) => transform(i, childOptions)) } : {},
4906
- ..."members" in schema && recurse ? { members: (_g = schema.members) == null ? void 0 : _g.map((m) => transform(m, childOptions)) } : {},
4907
- ..."additionalProperties" in schema && recurse && schema.additionalProperties && schema.additionalProperties !== true ? { additionalProperties: transform(schema.additionalProperties, childOptions) } : {}
4908
- };
4909
- }
4910
- case "Property": {
4911
- let prop = node;
4912
- const replaced = (_h = visitor.property) == null ? void 0 : _h.call(visitor, prop, { parent });
4913
- if (replaced) prop = replaced;
4914
- return createProperty({
4915
- ...prop,
4916
- schema: transform(prop.schema, {
4917
- ...options,
4918
- parent: prop
4919
- })
4920
- });
4921
- }
4922
- case "Parameter": {
4923
- let param = node;
4924
- const replaced = (_i = visitor.parameter) == null ? void 0 : _i.call(visitor, param, { parent });
4925
- if (replaced) param = replaced;
4926
- return createParameter({
4927
- ...param,
4928
- schema: transform(param.schema, {
4929
- ...options,
4930
- parent: param
4931
- })
4791
+ const rebuilt = transformChildren((_a = applyVisitor(node, visitor, parent)) != null ? _a : node, options, recurse);
4792
+ if (rebuilt === node) return node;
4793
+ const finalize = nodeFinalizers[rebuilt.kind];
4794
+ return finalize ? finalize(rebuilt) : rebuilt;
4795
+ }
4796
+ const nodeFinalizers = {
4797
+ Property: (node) => createProperty(node),
4798
+ Parameter: (node) => createParameter(node)
4799
+ };
4800
+ function transformChildren(node, options, recurse) {
4801
+ if (node.kind === "Schema" && !recurse) return node;
4802
+ const keys = visitorKeysByKind[node.kind];
4803
+ if (!keys) return node;
4804
+ const record = node;
4805
+ const childOptions = {
4806
+ ...options,
4807
+ parent: node
4808
+ };
4809
+ let updates;
4810
+ for (const key of keys) {
4811
+ if (!(key in record)) continue;
4812
+ const value = record[key];
4813
+ if (Array.isArray(value)) {
4814
+ let changed = false;
4815
+ const mapped = value.map((item) => {
4816
+ if (!isNode(item)) return item;
4817
+ const next = transform(item, childOptions);
4818
+ if (next !== item) changed = true;
4819
+ return next;
4932
4820
  });
4821
+ if (changed) (updates != null ? updates : updates = {})[key] = mapped;
4822
+ } else if (isNode(value)) {
4823
+ const next = transform(value, childOptions);
4824
+ if (next !== value) (updates != null ? updates : updates = {})[key] = next;
4933
4825
  }
4934
- case "Response": {
4935
- let response = node;
4936
- const replaced = (_j = visitor.response) == null ? void 0 : _j.call(visitor, response, { parent });
4937
- if (replaced) response = replaced;
4938
- return {
4939
- ...response,
4940
- schema: transform(response.schema, {
4941
- ...options,
4942
- parent: response
4943
- })
4944
- };
4945
- }
4946
- case "FunctionParameter":
4947
- case "ParameterGroup":
4948
- case "FunctionParameters":
4949
- case "Type":
4950
- return node;
4951
- default:
4952
- return node;
4953
4826
  }
4827
+ return updates ? {
4828
+ ...node,
4829
+ ...updates
4830
+ } : node;
4954
4831
  }
4955
- function collect(node, options) {
4956
- var _a, _b, _c, _d, _e, _f, _g;
4832
+ function* collectLazy(node, options) {
4957
4833
  const { depth, parent, ...visitor } = options;
4958
4834
  const recurse = (depth != null ? depth : visitorDepths.deep) === visitorDepths.deep;
4959
- const results = [];
4960
- let v;
4961
- switch (node.kind) {
4962
- case "Input":
4963
- v = (_a = visitor.input) == null ? void 0 : _a.call(visitor, node, { parent });
4964
- break;
4965
- case "Output":
4966
- v = (_b = visitor.output) == null ? void 0 : _b.call(visitor, node, { parent });
4967
- break;
4968
- case "Operation":
4969
- v = (_c = visitor.operation) == null ? void 0 : _c.call(visitor, node, { parent });
4970
- break;
4971
- case "Schema":
4972
- v = (_d = visitor.schema) == null ? void 0 : _d.call(visitor, node, { parent });
4973
- break;
4974
- case "Property":
4975
- v = (_e = visitor.property) == null ? void 0 : _e.call(visitor, node, { parent });
4976
- break;
4977
- case "Parameter":
4978
- v = (_f = visitor.parameter) == null ? void 0 : _f.call(visitor, node, { parent });
4979
- break;
4980
- case "Response":
4981
- v = (_g = visitor.response) == null ? void 0 : _g.call(visitor, node, { parent });
4982
- break;
4983
- }
4984
- if (v !== void 0) results.push(v);
4985
- for (const child of getChildren(node, recurse)) for (const item of collect(child, {
4835
+ const v = applyVisitor(node, visitor, parent);
4836
+ if (v != null) yield v;
4837
+ for (const child of getChildren(node, recurse)) yield* collectLazy(child, {
4986
4838
  ...options,
4987
4839
  parent: node
4988
- })) results.push(item);
4989
- return results;
4840
+ });
4841
+ }
4842
+ function collect(node, options) {
4843
+ return Array.from(collectLazy(node, options));
4990
4844
  }
4991
4845
  function sourceKey(source) {
4992
4846
  var _a, _b, _c;
@@ -5017,11 +4871,16 @@ function combineSources(sources) {
5017
4871
  }
5018
4872
  return [...seen.values()];
5019
4873
  }
5020
- function combineExports(exports$1) {
4874
+ function mergeNameArrays(existing, incoming) {
4875
+ const merged = new Set(existing);
4876
+ for (const name of incoming) merged.add(name);
4877
+ return [...merged];
4878
+ }
4879
+ function combineExports(exports) {
5021
4880
  const result = [];
5022
4881
  const namedByPath = /* @__PURE__ */ new Map();
5023
4882
  const seen = /* @__PURE__ */ new Set();
5024
- const keyed = exports$1.map((node) => ({
4883
+ const keyed = exports.map((node) => ({
5025
4884
  node,
5026
4885
  key: sortKey(node)
5027
4886
  }));
@@ -5032,11 +4891,8 @@ function combineExports(exports$1) {
5032
4891
  if (!name.length) continue;
5033
4892
  const key = pathTypeKey(path2, isTypeOnly);
5034
4893
  const existing = namedByPath.get(key);
5035
- if (existing && Array.isArray(existing.name)) {
5036
- const merged = new Set(existing.name);
5037
- for (const n of name) merged.add(n);
5038
- existing.name = [...merged];
5039
- } else {
4894
+ if (existing && Array.isArray(existing.name)) existing.name = mergeNameArrays(existing.name, name);
4895
+ else {
5040
4896
  const newItem = {
5041
4897
  ...curr,
5042
4898
  name: [...new Set(name)]
@@ -5054,8 +4910,8 @@ function combineExports(exports$1) {
5054
4910
  }
5055
4911
  return result;
5056
4912
  }
5057
- function combineImports(imports, exports$1, source) {
5058
- const exportedNames = new Set(exports$1.flatMap((e) => Array.isArray(e.name) ? e.name : e.name ? [e.name] : []));
4913
+ function combineImports(imports, exports, source) {
4914
+ const exportedNames = new Set(exports.flatMap((e) => Array.isArray(e.name) ? e.name : e.name ? [e.name] : []));
5059
4915
  const isUsed = (importName) => !source || source.includes(importName) || exportedNames.has(importName);
5060
4916
  const importNameMemo = /* @__PURE__ */ new Map();
5061
4917
  const canonicalizeName = (n) => {
@@ -5065,6 +4921,14 @@ function combineImports(imports, exports$1, source) {
5065
4921
  if (!importNameMemo.has(key)) importNameMemo.set(key, n);
5066
4922
  return importNameMemo.get(key);
5067
4923
  };
4924
+ const pathsWithUsedNamedImport = /* @__PURE__ */ new Set();
4925
+ for (const node of imports) {
4926
+ if (!Array.isArray(node.name)) continue;
4927
+ if (node.name.some((item) => {
4928
+ var _a;
4929
+ return typeof item === "string" ? isUsed(item) : isUsed((_a = item.name) != null ? _a : item.propertyName);
4930
+ })) pathsWithUsedNamedImport.add(node.path);
4931
+ }
5068
4932
  const result = [];
5069
4933
  const namedByPath = /* @__PURE__ */ new Map();
5070
4934
  const seen = /* @__PURE__ */ new Set();
@@ -5085,11 +4949,8 @@ function combineImports(imports, exports$1, source) {
5085
4949
  if (!name.length) continue;
5086
4950
  const key = pathTypeKey(path2, isTypeOnly);
5087
4951
  const existing = namedByPath.get(key);
5088
- if (existing && Array.isArray(existing.name)) {
5089
- const merged = new Set(existing.name);
5090
- for (const n of name) merged.add(n);
5091
- existing.name = [...merged];
5092
- } else {
4952
+ if (existing && Array.isArray(existing.name)) existing.name = mergeNameArrays(existing.name, name);
4953
+ else {
5093
4954
  const newItem = {
5094
4955
  ...curr,
5095
4956
  name
@@ -5098,7 +4959,7 @@ function combineImports(imports, exports$1, source) {
5098
4959
  namedByPath.set(key, newItem);
5099
4960
  }
5100
4961
  } else {
5101
- if (name && !isUsed(name)) continue;
4962
+ if (name && !isUsed(name) && !pathsWithUsedNamedImport.has(path2)) continue;
5102
4963
  const key = importKey(path2, name, isTypeOnly);
5103
4964
  if (!seen.has(key)) {
5104
4965
  result.push(curr);
@@ -5127,21 +4988,27 @@ function extractStringsFromNodes(nodes) {
5127
4988
  }
5128
4989
  function resolveRefName(node) {
5129
4990
  var _a, _b, _c, _d, _e, _f, _g;
5130
- if (!node || node.type !== "ref") return void 0;
5131
- if (node.ref) return (_d = (_c = (_a = extractRefName(node.ref)) != null ? _a : node.name) != null ? _c : (_b = node.schema) == null ? void 0 : _b.name) != null ? _d : void 0;
5132
- return (_g = (_f = node.name) != null ? _f : (_e = node.schema) == null ? void 0 : _e.name) != null ? _g : void 0;
4991
+ if (!node || node.type !== "ref") return null;
4992
+ if (node.ref) return (_d = (_c = (_a = extractRefName(node.ref)) != null ? _a : node.name) != null ? _c : (_b = node.schema) == null ? void 0 : _b.name) != null ? _d : null;
4993
+ return (_g = (_f = node.name) != null ? _f : (_e = node.schema) == null ? void 0 : _e.name) != null ? _g : null;
5133
4994
  }
5134
- function collectReferencedSchemaNames(node, out = /* @__PURE__ */ new Set()) {
5135
- if (!node) return out;
4995
+ const collectSchemaRefs = memoize$1(/* @__PURE__ */ new WeakMap(), (node) => {
4996
+ const refs = /* @__PURE__ */ new Set();
5136
4997
  collect(node, { schema(child) {
5137
4998
  if (child.type === "ref") {
5138
4999
  const name = resolveRefName(child);
5139
- if (name) out.add(name);
5000
+ if (name) refs.add(name);
5140
5001
  }
5141
5002
  } });
5003
+ return refs;
5004
+ });
5005
+ function collectReferencedSchemaNames(node, out = /* @__PURE__ */ new Set()) {
5006
+ if (!node) return out;
5007
+ for (const name of collectSchemaRefs(node)) out.add(name);
5142
5008
  return out;
5143
5009
  }
5144
- function collectUsedSchemaNames(operations, schemas) {
5010
+ const collectUsedSchemaNamesMemo = memoize$1(/* @__PURE__ */ new WeakMap(), (ops) => memoize$1(/* @__PURE__ */ new WeakMap(), (schemas) => computeUsedSchemaNames(ops, schemas)));
5011
+ function computeUsedSchemaNames(operations, schemas) {
5145
5012
  const schemaMap = /* @__PURE__ */ new Map();
5146
5013
  for (const schema of schemas) if (schema.name) schemaMap.set(schema.name, schema);
5147
5014
  const result = /* @__PURE__ */ new Set();
@@ -5153,12 +5020,15 @@ function collectUsedSchemaNames(operations, schemas) {
5153
5020
  if (namedSchema) visitSchema(namedSchema);
5154
5021
  }
5155
5022
  }
5156
- for (const op of operations) for (const schema of collect(op, {
5023
+ for (const op of operations) for (const schema of collectLazy(op, {
5157
5024
  depth: "shallow",
5158
5025
  schema: (node) => node
5159
5026
  })) visitSchema(schema);
5160
5027
  return result;
5161
5028
  }
5029
+ function collectUsedSchemaNames(operations, schemas) {
5030
+ return collectUsedSchemaNamesMemo(operations)(schemas);
5031
+ }
5162
5032
  function syncOptionality(schema, required) {
5163
5033
  var _a;
5164
5034
  const nullable = (_a = schema.nullable) != null ? _a : false;
@@ -5168,6 +5038,14 @@ function syncOptionality(schema, required) {
5168
5038
  nullish: !required && nullable ? true : void 0
5169
5039
  };
5170
5040
  }
5041
+ function createStreamInput(schemas, operations, meta) {
5042
+ return {
5043
+ kind: "Input",
5044
+ schemas,
5045
+ operations,
5046
+ meta
5047
+ };
5048
+ }
5171
5049
  function createProperty(props) {
5172
5050
  var _a;
5173
5051
  const required = (_a = props.required) != null ? _a : false;
@@ -5223,7 +5101,115 @@ var __privateGet$1 = (obj, member, getter) => (__accessCheck$1(obj, member, "rea
5223
5101
  var __privateAdd$1 = (obj, member, value) => member.has(obj) ? __typeError$1("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
5224
5102
  var __privateSet$1 = (obj, member, value, setter) => (__accessCheck$1(obj, member, "write to private field"), member.set(obj, value), value);
5225
5103
  var __privateMethod$1 = (obj, member, method) => (__accessCheck$1(obj, member, "access private method"), method);
5226
- var _cache, _filesCache, _FileManager_instances, store_fn, _a$1, _studioIsOpen, _pluginsWithEventGenerators, _resolvers, _defaultResolvers, _hookListeners, _PluginDriver_instances, normalizePlugin_fn, trackHookListener_fn, createDefaultResolver_fn, _b$1;
5104
+ var _emitter, _AsyncEventEmitter_instances, emitAll_fn, _a$1, _options, _URLPath_instances, transformParam_fn, eachParam_fn, _b, _cache, _sorted, _onUpsert, _FileManager_instances, store_fn, dedupe_fn, _c, _studio, _middlewareListeners, _fileProcessor, _eventGeneratorPlugins, _resolvers, _defaultResolvers, _hookListeners, _KubbDriver_instances, normalizePlugin_fn, registerAdapter_fn, registerMiddleware_fn, registerPlugin_fn, filesPayload_fn, emitPluginEnd_fn, runGenerators_fn, trackHookListener_fn, _getDefaultResolver, _d;
5105
+ var BuildError = class extends Error {
5106
+ constructor(message, options) {
5107
+ super(message, { cause: options.cause });
5108
+ __publicField$1(this, "errors");
5109
+ this.name = "BuildError";
5110
+ this.errors = options.errors;
5111
+ }
5112
+ };
5113
+ function toError(value) {
5114
+ return value instanceof Error ? value : new Error(String(value));
5115
+ }
5116
+ var AsyncEventEmitter = (_a$1 = class {
5117
+ /**
5118
+ * Maximum number of listeners per event before Node emits a memory-leak warning.
5119
+ * @default 10
5120
+ */
5121
+ constructor(maxListener = 10) {
5122
+ __privateAdd$1(this, _AsyncEventEmitter_instances);
5123
+ __privateAdd$1(this, _emitter, new EventEmitter());
5124
+ __privateGet$1(this, _emitter).setMaxListeners(maxListener);
5125
+ }
5126
+ /**
5127
+ * Emits `eventName` and awaits all registered listeners sequentially.
5128
+ * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.
5129
+ *
5130
+ * @example
5131
+ * ```ts
5132
+ * await emitter.emit('build', 'petstore')
5133
+ * ```
5134
+ */
5135
+ emit(eventName, ...eventArgs) {
5136
+ const listeners = __privateGet$1(this, _emitter).listeners(eventName);
5137
+ if (listeners.length === 0) return;
5138
+ return __privateMethod$1(this, _AsyncEventEmitter_instances, emitAll_fn).call(this, eventName, listeners, eventArgs);
5139
+ }
5140
+ /**
5141
+ * Registers a persistent listener for `eventName`.
5142
+ *
5143
+ * @example
5144
+ * ```ts
5145
+ * emitter.on('build', async (name) => { console.log(name) })
5146
+ * ```
5147
+ */
5148
+ on(eventName, handler) {
5149
+ __privateGet$1(this, _emitter).on(eventName, handler);
5150
+ }
5151
+ /**
5152
+ * Registers a one-shot listener that removes itself after the first invocation.
5153
+ *
5154
+ * @example
5155
+ * ```ts
5156
+ * emitter.onOnce('build', async (name) => { console.log(name) })
5157
+ * ```
5158
+ */
5159
+ onOnce(eventName, handler) {
5160
+ const wrapper = (...args) => {
5161
+ this.off(eventName, wrapper);
5162
+ return handler(...args);
5163
+ };
5164
+ this.on(eventName, wrapper);
5165
+ }
5166
+ /**
5167
+ * Removes a previously registered listener.
5168
+ *
5169
+ * @example
5170
+ * ```ts
5171
+ * emitter.off('build', handler)
5172
+ * ```
5173
+ */
5174
+ off(eventName, handler) {
5175
+ __privateGet$1(this, _emitter).off(eventName, handler);
5176
+ }
5177
+ /**
5178
+ * Returns the number of listeners registered for `eventName`.
5179
+ *
5180
+ * @example
5181
+ * ```ts
5182
+ * emitter.on('build', handler)
5183
+ * emitter.listenerCount('build') // 1
5184
+ * ```
5185
+ */
5186
+ listenerCount(eventName) {
5187
+ return __privateGet$1(this, _emitter).listenerCount(eventName);
5188
+ }
5189
+ /**
5190
+ * Removes all listeners from every event channel.
5191
+ *
5192
+ * @example
5193
+ * ```ts
5194
+ * emitter.removeAll()
5195
+ * ```
5196
+ */
5197
+ removeAll() {
5198
+ __privateGet$1(this, _emitter).removeAllListeners();
5199
+ }
5200
+ }, _emitter = new WeakMap(), _AsyncEventEmitter_instances = new WeakSet(), emitAll_fn = async function(eventName, listeners, eventArgs) {
5201
+ for (const listener of listeners) try {
5202
+ await listener(...eventArgs);
5203
+ } catch (err) {
5204
+ let serializedArgs;
5205
+ try {
5206
+ serializedArgs = JSON.stringify(eventArgs);
5207
+ } catch {
5208
+ serializedArgs = String(eventArgs);
5209
+ }
5210
+ throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) });
5211
+ }
5212
+ }, _a$1);
5227
5213
  function toCamelOrPascal(text, pascal) {
5228
5214
  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) => {
5229
5215
  if (word.length > 1 && word === word.toUpperCase()) return word;
@@ -5249,1170 +5235,1543 @@ function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) {
5249
5235
  }) : camelCase(part));
5250
5236
  return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
5251
5237
  }
5252
- const DEFAULT_STUDIO_URL = "https://studio.kubb.dev";
5253
- const DEFAULT_BANNER = "simple";
5254
- const DEFAULT_EXTENSION = { ".ts": ".ts" };
5255
- const stringPatternCache = /* @__PURE__ */ new Map();
5256
- function testPattern(value, pattern) {
5257
- if (typeof pattern === "string") {
5258
- let regex = stringPatternCache.get(pattern);
5259
- if (!regex) {
5260
- regex = new RegExp(pattern);
5261
- stringPatternCache.set(pattern, regex);
5262
- }
5263
- return regex.test(value);
5264
- }
5265
- return value.match(pattern) !== null;
5266
- }
5267
- function matchesOperationPattern(node, type, pattern) {
5268
- var _a2, _b2, _c;
5269
- switch (type) {
5270
- case "tag":
5271
- return node.tags.some((tag) => testPattern(tag, pattern));
5272
- case "operationId":
5273
- return testPattern(node.operationId, pattern);
5274
- case "path":
5275
- return testPattern(node.path, pattern);
5276
- case "method":
5277
- return testPattern(node.method.toLowerCase(), pattern);
5278
- case "contentType":
5279
- return (_c = (_b2 = (_a2 = node.requestBody) == null ? void 0 : _a2.content) == null ? void 0 : _b2.some((c) => testPattern(c.contentType, pattern))) != null ? _c : false;
5280
- default:
5281
- return false;
5282
- }
5238
+ function getElapsedMs(hrStart) {
5239
+ const [seconds, nanoseconds] = process.hrtime(hrStart);
5240
+ const ms = seconds * 1e3 + nanoseconds / 1e6;
5241
+ return Math.round(ms * 100) / 100;
5283
5242
  }
5284
- function matchesSchemaPattern(node, type, pattern) {
5285
- switch (type) {
5286
- case "schemaName":
5287
- return node.name ? testPattern(node.name, pattern) : false;
5288
- default:
5289
- return null;
5290
- }
5243
+ function formatMs(ms) {
5244
+ if (ms >= 6e4) return `${Math.floor(ms / 6e4)}m ${(ms % 6e4 / 1e3).toFixed(1)}s`;
5245
+ if (ms >= 1e3) return `${(ms / 1e3).toFixed(2)}s`;
5246
+ return `${Math.round(ms)}ms`;
5291
5247
  }
5292
- function defaultResolver(name, type) {
5293
- let resolvedName = camelCase(name);
5294
- if (type === "file" || type === "function") resolvedName = camelCase(name, { isFile: type === "file" });
5295
- if (type === "type") resolvedName = pascalCase(name);
5296
- return resolvedName;
5248
+ function* chunks(arr, size) {
5249
+ for (let i = 0; i < arr.length; i += size) yield arr.slice(i, i + size);
5297
5250
  }
5298
- function defaultResolveOptions(node, { options, exclude = [], include, override = [] }) {
5299
- var _a2, _b2;
5300
- if (isOperationNode(node)) {
5301
- if (exclude.some(({ type, pattern }) => matchesOperationPattern(node, type, pattern))) return null;
5302
- if (include && !include.some(({ type, pattern }) => matchesOperationPattern(node, type, pattern))) return null;
5303
- const overrideOptions = (_a2 = override.find(({ type, pattern }) => matchesOperationPattern(node, type, pattern))) == null ? void 0 : _a2.options;
5304
- return {
5305
- ...options,
5306
- ...overrideOptions
5307
- };
5251
+ async function forBatches(source, process2, options) {
5252
+ const { concurrency, flush } = options;
5253
+ if (Array.isArray(source)) {
5254
+ for (const batch2 of chunks(source, concurrency)) {
5255
+ await process2(batch2);
5256
+ if (flush) await flush();
5257
+ }
5258
+ return;
5308
5259
  }
5309
- if (isSchemaNode(node)) {
5310
- if (exclude.some(({ type, pattern }) => matchesSchemaPattern(node, type, pattern) === true)) return null;
5311
- if (include) {
5312
- const applicable = include.map(({ type, pattern }) => matchesSchemaPattern(node, type, pattern)).filter((r) => r !== null);
5313
- if (applicable.length > 0 && !applicable.includes(true)) return null;
5260
+ const batch = [];
5261
+ for await (const item of source) {
5262
+ batch.push(item);
5263
+ if (batch.length >= concurrency) {
5264
+ await process2(batch.splice(0));
5265
+ if (flush) await flush();
5314
5266
  }
5315
- const overrideOptions = (_b2 = override.find(({ type, pattern }) => matchesSchemaPattern(node, type, pattern) === true)) == null ? void 0 : _b2.options;
5316
- return {
5317
- ...options,
5318
- ...overrideOptions
5319
- };
5320
5267
  }
5321
- return options;
5268
+ if (batch.length > 0) {
5269
+ await process2(batch.splice(0));
5270
+ if (flush) await flush();
5271
+ }
5322
5272
  }
5323
- function defaultResolvePath({ baseName, pathMode, tag, path: groupPath }, { root, output, group }) {
5324
- var _a2;
5325
- if ((pathMode != null ? pathMode : PluginDriver.getMode(path$1.resolve(root, output.path))) === "single") return path$1.resolve(root, output.path);
5326
- let result;
5327
- if (group && (groupPath || tag)) {
5328
- const groupValue = group.type === "path" ? groupPath : tag;
5329
- const defaultName = group.type === "tag" ? ({ group: g }) => `${camelCase(g)}Controller` : ({ group: g }) => {
5330
- const segment = g.split("/").filter((s) => s !== "" && s !== "." && s !== "..")[0];
5331
- return segment ? camelCase(segment) : "";
5332
- };
5333
- const resolveName = (_a2 = group.name) != null ? _a2 : defaultName;
5334
- result = path$1.resolve(root, output.path, resolveName({ group: groupValue }), baseName);
5335
- } else result = path$1.resolve(root, output.path, baseName);
5336
- const outputDir = path$1.resolve(root, output.path);
5337
- const outputDirWithSep = outputDir.endsWith(path$1.sep) ? outputDir : `${outputDir}${path$1.sep}`;
5338
- if (result !== outputDir && !result.startsWith(outputDirWithSep)) throw new Error(`[Kubb] Resolved path "${result}" is outside the output directory "${outputDir}". This may indicate a path traversal attempt in the OpenAPI specification or a misconfigured group.name function.`);
5339
- return result;
5273
+ function isPromise(result) {
5274
+ return result !== null && result !== void 0 && typeof result["then"] === "function";
5340
5275
  }
5341
- function defaultResolveFile({ name, extname: extname2, tag, path: groupPath }, context, ctx) {
5342
- const pathMode = PluginDriver.getMode(path$1.resolve(context.root, context.output.path));
5343
- const baseName = `${pathMode === "single" ? "" : ctx.default(name, "file")}${extname2}`;
5344
- const filePath = ctx.resolvePath({
5345
- baseName,
5346
- pathMode,
5347
- tag,
5348
- path: groupPath
5349
- }, context);
5350
- return createFile({
5351
- path: filePath,
5352
- baseName: path$1.basename(filePath),
5353
- meta: { pluginName: ctx.pluginName },
5354
- sources: [],
5355
- imports: [],
5356
- exports: []
5357
- });
5276
+ function memoize(store, factory) {
5277
+ return (key) => {
5278
+ if (store.has(key)) return store.get(key);
5279
+ const value = factory(key);
5280
+ store.set(key, value);
5281
+ return value;
5282
+ };
5358
5283
  }
5359
- function buildDefaultBanner({ title, description, version, config }) {
5360
- try {
5361
- let source = "";
5362
- if (Array.isArray(config.input)) {
5363
- const first = config.input[0];
5364
- if (first && "path" in first) source = path$1.basename(first.path);
5365
- } else if ("path" in config.input) source = path$1.basename(config.input.path);
5366
- else if ("data" in config.input) source = "text content";
5367
- let banner = "/**\n* Generated by Kubb (https://kubb.dev/).\n* Do not edit manually.\n";
5368
- if (config.output.defaultBanner === "simple") {
5369
- banner += "*/\n";
5370
- return banner;
5371
- }
5372
- if (source) banner += `* Source: ${source}
5373
- `;
5374
- if (title) banner += `* Title: ${title}
5375
- `;
5376
- if (description) {
5377
- const formattedDescription = description.replace(/\n/gm, "\n* ");
5378
- banner += `* Description: ${formattedDescription}
5379
- `;
5380
- }
5381
- if (version) banner += `* OpenAPI spec version: ${version}
5382
- `;
5383
- banner += "*/\n";
5384
- return banner;
5385
- } catch (_error) {
5386
- return "/**\n* Generated by Kubb (https://kubb.dev/).\n* Do not edit manually.\n*/";
5387
- }
5388
- }
5389
- function defaultResolveBanner(node, { output, config }) {
5390
- var _a2, _b2;
5391
- if (typeof (output == null ? void 0 : output.banner) === "function") return output.banner(node);
5392
- if (typeof (output == null ? void 0 : output.banner) === "string") return output.banner;
5393
- if (config.output.defaultBanner === false) return;
5394
- return buildDefaultBanner({
5395
- title: (_a2 = node == null ? void 0 : node.meta) == null ? void 0 : _a2.title,
5396
- version: (_b2 = node == null ? void 0 : node.meta) == null ? void 0 : _b2.version,
5397
- config
5398
- });
5399
- }
5400
- function defaultResolveFooter(node, { output }) {
5401
- if (typeof (output == null ? void 0 : output.footer) === "function") return node ? output.footer(node) : void 0;
5402
- if (typeof (output == null ? void 0 : output.footer) === "string") return output.footer;
5403
- }
5404
- function defineResolver(build) {
5405
- const resolver = {};
5406
- Object.assign(resolver, {
5407
- default: defaultResolver,
5408
- resolveOptions: defaultResolveOptions,
5409
- resolvePath: defaultResolvePath,
5410
- resolveFile: (params, context) => defaultResolveFile(params, context, resolver),
5411
- resolveBanner: defaultResolveBanner,
5412
- resolveFooter: defaultResolveFooter,
5413
- ...build(resolver)
5414
- });
5415
- return resolver;
5416
- }
5417
- function encodeAst(input) {
5418
- const compressed = deflateSync(new TextEncoder().encode(JSON.stringify(input)));
5419
- return Buffer.from(compressed).toString("base64url");
5420
- }
5421
- function getStudioUrl(input, studioUrl, options = {}) {
5422
- return `${studioUrl.replace(/\/$/, "")}${options.ast ? "/ast" : ""}?root=${encodeAst(input)}`;
5423
- }
5424
- async function openInStudio(input, studioUrl, options = {}) {
5425
- const url = getStudioUrl(input, studioUrl, options);
5426
- const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
5427
- const args = process.platform === "win32" ? [
5428
- "/c",
5429
- "start",
5430
- "",
5431
- url
5432
- ] : [url];
5433
- try {
5434
- await x(cmd, args);
5435
- } catch {
5436
- console.log(`
5437
- ${url}
5438
- `);
5439
- }
5440
- }
5441
- function mergeFile(a, b) {
5442
- return {
5443
- ...a,
5444
- banner: b.banner,
5445
- footer: b.footer,
5446
- sources: [...a.sources || [], ...b.sources || []],
5447
- imports: [...a.imports || [], ...b.imports || []],
5448
- exports: [...a.exports || [], ...b.exports || []]
5449
- };
5450
- }
5451
- function mergeFilesByPath(files) {
5452
- const merged = /* @__PURE__ */ new Map();
5453
- for (const file of files) {
5454
- const existing = merged.get(file.path);
5455
- merged.set(file.path, existing ? mergeFile(existing, file) : file);
5456
- }
5457
- return merged;
5458
- }
5459
- var FileManager = (_a$1 = class {
5460
- constructor() {
5461
- __privateAdd$1(this, _FileManager_instances);
5462
- __privateAdd$1(this, _cache, /* @__PURE__ */ new Map());
5463
- __privateAdd$1(this, _filesCache, null);
5464
- }
5465
- /**
5466
- * Adds one or more files. Incoming files with the same path are merged
5467
- * (sources/imports/exports concatenated), but existing cache entries are
5468
- * replaced — use {@link upsert} when you want to merge into the cache too.
5469
- */
5470
- add(...files) {
5471
- return __privateMethod$1(this, _FileManager_instances, store_fn).call(this, files, false);
5472
- }
5473
- /**
5474
- * Adds or merges one or more files.
5475
- * If a file with the same path already exists in the cache, its
5476
- * sources/imports/exports are merged into the incoming file.
5477
- */
5478
- upsert(...files) {
5479
- return __privateMethod$1(this, _FileManager_instances, store_fn).call(this, files, true);
5480
- }
5481
- getByPath(path2) {
5482
- var _a2;
5483
- return (_a2 = __privateGet$1(this, _cache).get(path2)) != null ? _a2 : null;
5484
- }
5485
- deleteByPath(path2) {
5486
- __privateGet$1(this, _cache).delete(path2);
5487
- __privateSet$1(this, _filesCache, null);
5488
- }
5489
- clear() {
5490
- __privateGet$1(this, _cache).clear();
5491
- __privateSet$1(this, _filesCache, null);
5492
- }
5493
- /**
5494
- * All stored files, sorted by path length (shorter paths first).
5495
- */
5496
- get files() {
5497
- if (__privateGet$1(this, _filesCache)) return __privateGet$1(this, _filesCache);
5498
- __privateSet$1(this, _filesCache, [...__privateGet$1(this, _cache).values()].sort((a, b) => {
5499
- const lenDiff = a.path.length - b.path.length;
5500
- if (lenDiff !== 0) return lenDiff;
5501
- const aIsIndex = a.path.endsWith("/index.ts") || a.path === "index.ts";
5502
- const bIsIndex = b.path.endsWith("/index.ts") || b.path === "index.ts";
5503
- if (aIsIndex && !bIsIndex) return 1;
5504
- if (!aIsIndex && bIsIndex) return -1;
5505
- return 0;
5506
- }));
5507
- return __privateGet$1(this, _filesCache);
5508
- }
5509
- }, _cache = new WeakMap(), _filesCache = new WeakMap(), _FileManager_instances = new WeakSet(), store_fn = function(files, mergeExisting) {
5510
- const resolvedFiles = [];
5511
- for (const file of mergeFilesByPath(files).values()) {
5512
- const existing = mergeExisting ? __privateGet$1(this, _cache).get(file.path) : void 0;
5513
- const resolvedFile = createFile(existing ? mergeFile(existing, file) : file);
5514
- __privateGet$1(this, _cache).set(resolvedFile.path, resolvedFile);
5515
- resolvedFiles.push(resolvedFile);
5516
- }
5517
- __privateSet$1(this, _filesCache, null);
5518
- return resolvedFiles;
5519
- }, _a$1);
5520
- async function applyHookResult(result, driver, rendererFactory) {
5521
- if (!result) return;
5522
- if (Array.isArray(result)) {
5523
- driver.fileManager.upsert(...result);
5524
- return;
5525
- }
5526
- if (!rendererFactory) return;
5527
- const renderer = rendererFactory();
5528
- await renderer.render(result);
5529
- driver.fileManager.upsert(...renderer.files);
5530
- renderer.unmount();
5284
+ function arrayToAsyncIterable(arr) {
5285
+ return { [Symbol.asyncIterator]() {
5286
+ return (async function* () {
5287
+ yield* arr;
5288
+ })();
5289
+ } };
5531
5290
  }
5532
- function enforceOrder(enforce) {
5533
- return enforce === "pre" ? -1 : enforce === "post" ? 1 : 0;
5291
+ const reservedWords = /* @__PURE__ */ new Set([
5292
+ "abstract",
5293
+ "arguments",
5294
+ "boolean",
5295
+ "break",
5296
+ "byte",
5297
+ "case",
5298
+ "catch",
5299
+ "char",
5300
+ "class",
5301
+ "const",
5302
+ "continue",
5303
+ "debugger",
5304
+ "default",
5305
+ "delete",
5306
+ "do",
5307
+ "double",
5308
+ "else",
5309
+ "enum",
5310
+ "eval",
5311
+ "export",
5312
+ "extends",
5313
+ "false",
5314
+ "final",
5315
+ "finally",
5316
+ "float",
5317
+ "for",
5318
+ "function",
5319
+ "goto",
5320
+ "if",
5321
+ "implements",
5322
+ "import",
5323
+ "in",
5324
+ "instanceof",
5325
+ "int",
5326
+ "interface",
5327
+ "let",
5328
+ "long",
5329
+ "native",
5330
+ "new",
5331
+ "null",
5332
+ "package",
5333
+ "private",
5334
+ "protected",
5335
+ "public",
5336
+ "return",
5337
+ "short",
5338
+ "static",
5339
+ "super",
5340
+ "switch",
5341
+ "synchronized",
5342
+ "this",
5343
+ "throw",
5344
+ "throws",
5345
+ "transient",
5346
+ "true",
5347
+ "try",
5348
+ "typeof",
5349
+ "var",
5350
+ "void",
5351
+ "volatile",
5352
+ "while",
5353
+ "with",
5354
+ "yield",
5355
+ "Array",
5356
+ "Date",
5357
+ "hasOwnProperty",
5358
+ "Infinity",
5359
+ "isFinite",
5360
+ "isNaN",
5361
+ "isPrototypeOf",
5362
+ "length",
5363
+ "Math",
5364
+ "name",
5365
+ "NaN",
5366
+ "Number",
5367
+ "Object",
5368
+ "prototype",
5369
+ "String",
5370
+ "toString",
5371
+ "undefined",
5372
+ "valueOf"
5373
+ ]);
5374
+ function isValidVarName(name) {
5375
+ if (!name || reservedWords.has(name)) return false;
5376
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
5534
5377
  }
5535
- var PluginDriver = (_b$1 = class {
5536
- constructor(config, options) {
5537
- __privateAdd$1(this, _PluginDriver_instances);
5538
- __publicField$1(this, "config");
5539
- __publicField$1(this, "options");
5540
- /**
5541
- * The universal `@kubb/ast` `InputNode` produced by the adapter, set by
5542
- * the build pipeline after the adapter's `parse()` resolves.
5543
- */
5544
- __publicField$1(this, "inputNode");
5545
- __publicField$1(this, "adapter");
5546
- __privateAdd$1(this, _studioIsOpen, false);
5547
- /**
5548
- * Central file store for all generated files.
5549
- * Plugins should use `this.addFile()` / `this.upsertFile()` (via their context) to
5550
- * add files; this property gives direct read/write access when needed.
5551
- */
5552
- __publicField$1(this, "fileManager", new FileManager());
5553
- __publicField$1(this, "plugins", /* @__PURE__ */ new Map());
5378
+ var URLPath = (_b = class {
5379
+ constructor(path2, options = {}) {
5380
+ __privateAdd$1(this, _URLPath_instances);
5554
5381
  /**
5555
- * Tracks which plugins have generators registered via `addGenerator()` (event-based path).
5556
- * Used by the build loop to decide whether to emit generator events for a given plugin.
5382
+ * The raw OpenAPI/Swagger path string, e.g. `/pet/{petId}`.
5557
5383
  */
5558
- __privateAdd$1(this, _pluginsWithEventGenerators, /* @__PURE__ */ new Set());
5559
- __privateAdd$1(this, _resolvers, /* @__PURE__ */ new Map());
5560
- __privateAdd$1(this, _defaultResolvers, /* @__PURE__ */ new Map());
5561
- __privateAdd$1(this, _hookListeners, /* @__PURE__ */ new Map());
5562
- this.config = config;
5563
- this.options = options;
5564
- config.plugins.map((rawPlugin) => __privateMethod$1(this, _PluginDriver_instances, normalizePlugin_fn).call(this, rawPlugin)).filter((plugin) => {
5565
- if (typeof plugin.apply === "function") return plugin.apply(config);
5566
- return true;
5567
- }).sort((a, b) => {
5568
- var _a2, _b2;
5569
- if ((_a2 = b.dependencies) == null ? void 0 : _a2.includes(a.name)) return -1;
5570
- if ((_b2 = a.dependencies) == null ? void 0 : _b2.includes(b.name)) return 1;
5571
- return enforceOrder(a.enforce) - enforceOrder(b.enforce);
5572
- }).forEach((plugin) => {
5573
- this.plugins.set(plugin.name, plugin);
5574
- });
5384
+ __publicField$1(this, "path");
5385
+ __privateAdd$1(this, _options);
5386
+ this.path = path2;
5387
+ __privateSet$1(this, _options, options);
5575
5388
  }
5576
- /**
5577
- * Returns `'single'` when `fileOrFolder` has a file extension, `'split'` otherwise.
5389
+ /** Converts the OpenAPI path to Express-style colon syntax, e.g. `/pet/{petId}` → `/pet/:petId`.
5578
5390
  *
5579
5391
  * @example
5580
5392
  * ```ts
5581
- * PluginDriver.getMode('src/gen/types.ts') // 'single'
5582
- * PluginDriver.getMode('src/gen/types') // 'split'
5393
+ * new URLPath('/pet/{petId}').URL // '/pet/:petId'
5583
5394
  * ```
5584
5395
  */
5585
- static getMode(fileOrFolder) {
5586
- if (!fileOrFolder) return "split";
5587
- return extname(fileOrFolder) ? "single" : "split";
5588
- }
5589
- get hooks() {
5590
- return this.options.hooks;
5396
+ get URL() {
5397
+ return this.toURLPath();
5591
5398
  }
5592
- /**
5593
- * Registers a hook-style plugin's lifecycle handlers on the shared `AsyncEventEmitter`.
5594
- *
5595
- * For `kubb:plugin:setup`, the registered listener wraps the globally emitted context with a
5596
- * plugin-specific one so that `addGenerator`, `setResolver`, `setTransformer`, and
5597
- * `setRenderer` all target the correct `normalizedPlugin` entry in the plugins map.
5598
- *
5599
- * All other hooks are iterated and registered directly as pass-through listeners.
5600
- * Any event key present in the global `KubbHooks` interface can be subscribed to.
5601
- *
5602
- * External tooling can subscribe to any of these events via `hooks.on(...)` to observe
5603
- * the plugin lifecycle without modifying plugin behavior.
5399
+ /** Returns `true` when `path` is a fully-qualified URL (e.g. starts with `https://`).
5604
5400
  *
5605
- * @internal
5401
+ * @example
5402
+ * ```ts
5403
+ * new URLPath('https://petstore.swagger.io/v2/pet').isURL // true
5404
+ * new URLPath('/pet/{petId}').isURL // false
5405
+ * ```
5606
5406
  */
5607
- registerPluginHooks(hookPlugin, normalizedPlugin) {
5608
- const { hooks } = hookPlugin;
5609
- if (hooks["kubb:plugin:setup"]) {
5610
- const setupHandler = (globalCtx) => {
5611
- var _a2;
5612
- const pluginCtx = {
5613
- ...globalCtx,
5614
- options: (_a2 = hookPlugin.options) != null ? _a2 : {},
5615
- addGenerator: (gen) => {
5616
- this.registerGenerator(normalizedPlugin.name, gen);
5617
- },
5618
- setResolver: (resolver) => {
5619
- this.setPluginResolver(normalizedPlugin.name, resolver);
5620
- },
5621
- setTransformer: (visitor) => {
5622
- normalizedPlugin.transformer = visitor;
5623
- },
5624
- setRenderer: (renderer) => {
5625
- normalizedPlugin.renderer = renderer;
5626
- },
5627
- setOptions: (opts) => {
5628
- normalizedPlugin.options = {
5629
- ...normalizedPlugin.options,
5630
- ...opts
5631
- };
5632
- },
5633
- injectFile: (userFileNode) => {
5634
- this.fileManager.add(createFile(userFileNode));
5635
- }
5636
- };
5637
- return hooks["kubb:plugin:setup"](pluginCtx);
5638
- };
5639
- this.hooks.on("kubb:plugin:setup", setupHandler);
5640
- __privateMethod$1(this, _PluginDriver_instances, trackHookListener_fn).call(this, "kubb:plugin:setup", setupHandler);
5641
- }
5642
- for (const [event, handler] of Object.entries(hooks)) {
5643
- if (event === "kubb:plugin:setup" || !handler) continue;
5644
- this.hooks.on(event, handler);
5645
- __privateMethod$1(this, _PluginDriver_instances, trackHookListener_fn).call(this, event, handler);
5407
+ get isURL() {
5408
+ try {
5409
+ return !!new URL(this.path).href;
5410
+ } catch {
5411
+ return false;
5646
5412
  }
5647
5413
  }
5648
5414
  /**
5649
- * Emits the `kubb:plugin:setup` event so that all registered hook-style plugin listeners
5650
- * can configure generators, resolvers, transformers and renderers before `buildStart` runs.
5415
+ * Converts the OpenAPI path to a TypeScript template literal string.
5651
5416
  *
5652
- * Call this once from `safeBuild` before the plugin execution loop begins.
5653
- */
5654
- async emitSetupHooks() {
5655
- const noop = () => {
5656
- };
5657
- await this.hooks.emit("kubb:plugin:setup", {
5658
- config: this.config,
5659
- options: {},
5660
- addGenerator: noop,
5661
- setResolver: noop,
5662
- setTransformer: noop,
5663
- setRenderer: noop,
5664
- setOptions: noop,
5665
- injectFile: noop,
5666
- updateConfig: noop
5667
- });
5668
- }
5669
- /**
5670
- * Registers a generator for the given plugin on the shared event emitter.
5671
- *
5672
- * The generator's `schema`, `operation`, and `operations` methods are registered as
5673
- * listeners on `kubb:generate:schema`, `kubb:generate:operation`, and `kubb:generate:operations`
5674
- * respectively. Each listener is scoped to the owning plugin via a `ctx.plugin.name` check
5675
- * so that generators from different plugins do not cross-fire.
5676
- *
5677
- * The renderer resolution chain is: `generator.renderer → plugin.renderer → config.renderer`.
5678
- * Set `generator.renderer = null` to explicitly opt out of rendering even when the plugin
5679
- * declares a renderer.
5680
- *
5681
- * Call this method inside `addGenerator()` (in `kubb:plugin:setup`) to wire up a generator.
5682
- */
5683
- registerGenerator(pluginName, gen) {
5684
- const resolveRenderer = () => {
5685
- var _a2, _b2;
5686
- const plugin = this.plugins.get(pluginName);
5687
- return gen.renderer === null ? void 0 : (_b2 = (_a2 = gen.renderer) != null ? _a2 : plugin == null ? void 0 : plugin.renderer) != null ? _b2 : this.config.renderer;
5688
- };
5689
- if (gen.schema) {
5690
- const schemaHandler = async (node, ctx) => {
5691
- if (ctx.plugin.name !== pluginName) return;
5692
- await applyHookResult(await gen.schema(node, ctx), this, resolveRenderer());
5693
- };
5694
- this.hooks.on("kubb:generate:schema", schemaHandler);
5695
- __privateMethod$1(this, _PluginDriver_instances, trackHookListener_fn).call(this, "kubb:generate:schema", schemaHandler);
5696
- }
5697
- if (gen.operation) {
5698
- const operationHandler = async (node, ctx) => {
5699
- if (ctx.plugin.name !== pluginName) return;
5700
- await applyHookResult(await gen.operation(node, ctx), this, resolveRenderer());
5701
- };
5702
- this.hooks.on("kubb:generate:operation", operationHandler);
5703
- __privateMethod$1(this, _PluginDriver_instances, trackHookListener_fn).call(this, "kubb:generate:operation", operationHandler);
5704
- }
5705
- if (gen.operations) {
5706
- const operationsHandler = async (nodes, ctx) => {
5707
- if (ctx.plugin.name !== pluginName) return;
5708
- await applyHookResult(await gen.operations(nodes, ctx), this, resolveRenderer());
5709
- };
5710
- this.hooks.on("kubb:generate:operations", operationsHandler);
5711
- __privateMethod$1(this, _PluginDriver_instances, trackHookListener_fn).call(this, "kubb:generate:operations", operationsHandler);
5712
- }
5713
- __privateGet$1(this, _pluginsWithEventGenerators).add(pluginName);
5714
- }
5715
- /**
5716
- * Returns `true` when at least one generator was registered for the given plugin
5717
- * via `addGenerator()` in `kubb:plugin:setup` (event-based path).
5718
- *
5719
- * Used by the build loop to decide whether to walk the AST and emit generator events
5720
- * for a plugin that has no static `plugin.generators`.
5417
+ * @example
5418
+ * new URLPath('/pet/{petId}').template // '`/pet/${petId}`'
5419
+ * new URLPath('/account/monetary-accountID').template // '`/account/${monetaryAccountId}`'
5721
5420
  */
5722
- hasRegisteredGenerators(pluginName) {
5723
- return __privateGet$1(this, _pluginsWithEventGenerators).has(pluginName);
5421
+ get template() {
5422
+ return this.toTemplateString();
5724
5423
  }
5725
- /**
5726
- * Unregisters all plugin lifecycle listeners from the shared event emitter.
5727
- * Called at the end of a build to prevent listener leaks across repeated builds.
5424
+ /** Returns the path and its extracted params as a structured `URLObject`, or as a stringified expression when `stringify` is set.
5728
5425
  *
5729
- * @internal
5730
- */
5731
- dispose() {
5732
- for (const [event, handlers] of __privateGet$1(this, _hookListeners)) for (const handler of handlers) this.hooks.off(event, handler);
5733
- __privateGet$1(this, _hookListeners).clear();
5734
- __privateGet$1(this, _pluginsWithEventGenerators).clear();
5735
- }
5736
- /**
5737
- * Merges `partial` with the plugin's default resolver and stores the result.
5738
- * Also mirrors it onto `plugin.resolver` so callers using `getPlugin(name).resolver`
5739
- * get the up-to-date resolver without going through `getResolver()`.
5740
- */
5741
- setPluginResolver(pluginName, partial) {
5742
- const merged = {
5743
- ...__privateMethod$1(this, _PluginDriver_instances, createDefaultResolver_fn).call(this, pluginName),
5744
- ...partial
5745
- };
5746
- __privateGet$1(this, _resolvers).set(pluginName, merged);
5747
- const plugin = this.plugins.get(pluginName);
5748
- if (plugin) plugin.resolver = merged;
5749
- }
5750
- getResolver(pluginName) {
5751
- var _a2, _b2, _c;
5752
- return (_c = (_b2 = __privateGet$1(this, _resolvers).get(pluginName)) != null ? _b2 : (_a2 = this.plugins.get(pluginName)) == null ? void 0 : _a2.resolver) != null ? _c : __privateMethod$1(this, _PluginDriver_instances, createDefaultResolver_fn).call(this, pluginName);
5753
- }
5754
- getContext(plugin) {
5755
- const driver = this;
5756
- return {
5757
- config: driver.config,
5758
- get root() {
5759
- return resolve(driver.config.root, driver.config.output.path);
5760
- },
5761
- getMode(output) {
5762
- return _b$1.getMode(resolve(driver.config.root, driver.config.output.path, output.path));
5763
- },
5764
- hooks: driver.hooks,
5765
- plugin,
5766
- getPlugin: driver.getPlugin.bind(driver),
5767
- requirePlugin: driver.requirePlugin.bind(driver),
5768
- getResolver: driver.getResolver.bind(driver),
5769
- driver,
5770
- addFile: async (...files) => {
5771
- driver.fileManager.add(...files);
5772
- },
5773
- upsertFile: async (...files) => {
5774
- driver.fileManager.upsert(...files);
5775
- },
5776
- get inputNode() {
5777
- return driver.inputNode;
5778
- },
5779
- get adapter() {
5780
- return driver.adapter;
5781
- },
5782
- get resolver() {
5783
- return driver.getResolver(plugin.name);
5784
- },
5785
- get transformer() {
5786
- return plugin.transformer;
5787
- },
5788
- warn(message) {
5789
- driver.hooks.emit("kubb:warn", { message });
5790
- },
5791
- error(error) {
5792
- driver.hooks.emit("kubb:error", { error: typeof error === "string" ? new Error(error) : error });
5793
- },
5794
- info(message) {
5795
- driver.hooks.emit("kubb:info", { message });
5796
- },
5797
- openInStudio(options) {
5798
- var _a2, _b2;
5799
- if (!driver.config.devtools || __privateGet$1(driver, _studioIsOpen)) return;
5800
- if (typeof driver.config.devtools !== "object") throw new Error("Devtools must be an object");
5801
- if (!driver.inputNode || !driver.adapter) throw new Error("adapter is not defined, make sure you have set the parser in kubb.config.ts");
5802
- __privateSet$1(driver, _studioIsOpen, true);
5803
- const studioUrl = (_b2 = (_a2 = driver.config.devtools) == null ? void 0 : _a2.studioUrl) != null ? _b2 : "https://studio.kubb.dev";
5804
- return openInStudio(driver.inputNode, studioUrl, options);
5805
- }
5806
- };
5807
- }
5808
- getPlugin(pluginName) {
5809
- return this.plugins.get(pluginName);
5810
- }
5811
- requirePlugin(pluginName) {
5812
- const plugin = this.plugins.get(pluginName);
5813
- if (!plugin) throw new Error(`[kubb] Plugin "${pluginName}" is required but not found. Make sure it is included in your Kubb config.`);
5814
- return plugin;
5815
- }
5816
- }, _studioIsOpen = new WeakMap(), _pluginsWithEventGenerators = new WeakMap(), _resolvers = new WeakMap(), _defaultResolvers = new WeakMap(), _hookListeners = new WeakMap(), _PluginDriver_instances = new WeakSet(), /**
5817
- * Creates an `NormalizedPlugin` from a hook-style plugin and registers
5818
- * its lifecycle handlers on the `AsyncEventEmitter`.
5819
- */
5820
- normalizePlugin_fn = function(hookPlugin) {
5821
- const normalizedPlugin = {
5822
- name: hookPlugin.name,
5823
- dependencies: hookPlugin.dependencies,
5824
- enforce: hookPlugin.enforce,
5825
- options: {
5826
- output: { path: "." },
5827
- exclude: [],
5828
- override: []
5829
- }
5830
- };
5831
- this.registerPluginHooks(hookPlugin, normalizedPlugin);
5832
- return normalizedPlugin;
5833
- }, trackHookListener_fn = function(event, handler) {
5834
- let handlers = __privateGet$1(this, _hookListeners).get(event);
5835
- if (!handlers) {
5836
- handlers = /* @__PURE__ */ new Set();
5837
- __privateGet$1(this, _hookListeners).set(event, handlers);
5838
- }
5839
- handlers.add(handler);
5840
- }, createDefaultResolver_fn = function(pluginName) {
5841
- const existingResolver = __privateGet$1(this, _defaultResolvers).get(pluginName);
5842
- if (existingResolver) return existingResolver;
5843
- const resolver = defineResolver((_ctx) => ({
5844
- name: "default",
5845
- pluginName
5846
- }));
5847
- __privateGet$1(this, _defaultResolvers).set(pluginName, resolver);
5848
- return resolver;
5849
- }, _b$1);
5850
-
5851
- var __defProp = Object.defineProperty;
5852
- var __typeError = (msg) => {
5853
- throw TypeError(msg);
5854
- };
5855
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5856
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5857
- var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
5858
- var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
5859
- var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
5860
- var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
5861
- var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
5862
- var __privateWrapper = (obj, member, setter, getter) => ({
5863
- set _(value) {
5864
- __privateSet(obj, member, value);
5865
- },
5866
- get _() {
5867
- return __privateGet(obj, member, getter);
5868
- }
5869
- });
5870
- var _emitter, _a, _options, _URLPath_instances, transformParam_fn, eachParam_fn, _b, _c, _head, _tail, _size, _d, _limit, _e;
5871
- var BuildError = class extends Error {
5872
- constructor(message, options) {
5873
- super(message, { cause: options.cause });
5874
- __publicField(this, "errors");
5875
- this.name = "BuildError";
5876
- this.errors = options.errors;
5877
- }
5878
- };
5879
- function toError(value) {
5880
- return value instanceof Error ? value : new Error(String(value));
5881
- }
5882
- var AsyncEventEmitter = (_a = class {
5883
- /**
5884
- * Maximum number of listeners per event before Node emits a memory-leak warning.
5885
- * @default 10
5426
+ * @example
5427
+ * ```ts
5428
+ * new URLPath('/pet/{petId}').object
5429
+ * // { url: '/pet/:petId', params: { petId: 'petId' } }
5430
+ * ```
5886
5431
  */
5887
- constructor(maxListener = 10) {
5888
- __privateAdd(this, _emitter, new EventEmitter());
5889
- __privateGet(this, _emitter).setMaxListeners(maxListener);
5432
+ get object() {
5433
+ return this.toObject();
5890
5434
  }
5891
- /**
5892
- * Emits `eventName` and awaits all registered listeners sequentially.
5893
- * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.
5435
+ /** Returns a map of path parameter names, or `undefined` when the path has no parameters.
5894
5436
  *
5895
5437
  * @example
5896
5438
  * ```ts
5897
- * await emitter.emit('build', 'petstore')
5439
+ * new URLPath('/pet/{petId}').params // { petId: 'petId' }
5440
+ * new URLPath('/pet').params // undefined
5898
5441
  * ```
5899
5442
  */
5900
- async emit(eventName, ...eventArgs) {
5901
- const listeners = __privateGet(this, _emitter).listeners(eventName);
5902
- if (listeners.length === 0) return;
5903
- for (const listener of listeners) try {
5904
- await listener(...eventArgs);
5905
- } catch (err) {
5906
- let serializedArgs;
5907
- try {
5908
- serializedArgs = JSON.stringify(eventArgs);
5909
- } catch {
5910
- serializedArgs = String(eventArgs);
5911
- }
5912
- throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) });
5443
+ get params() {
5444
+ return this.getParams();
5445
+ }
5446
+ toObject({ type = "path", replacer, stringify } = {}) {
5447
+ const object = {
5448
+ url: type === "path" ? this.toURLPath() : this.toTemplateString({ replacer }),
5449
+ params: this.getParams()
5450
+ };
5451
+ if (stringify) {
5452
+ if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
5453
+ if (object.params) return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll("'", "").replaceAll(`"`, "")} }`;
5454
+ return `{ url: '${object.url}' }`;
5913
5455
  }
5456
+ return object;
5914
5457
  }
5915
5458
  /**
5916
- * Registers a persistent listener for `eventName`.
5459
+ * Converts the OpenAPI path to a TypeScript template literal string.
5460
+ * An optional `replacer` can transform each extracted parameter name before interpolation.
5917
5461
  *
5918
5462
  * @example
5919
- * ```ts
5920
- * emitter.on('build', async (name) => { console.log(name) })
5921
- * ```
5463
+ * new URLPath('/pet/{petId}').toTemplateString() // '`/pet/${petId}`'
5922
5464
  */
5923
- on(eventName, handler) {
5924
- __privateGet(this, _emitter).on(eventName, handler);
5465
+ toTemplateString({ prefix, replacer } = {}) {
5466
+ const result = this.path.split(/\{([^}]+)\}/).map((part, i) => {
5467
+ if (i % 2 === 0) return part;
5468
+ const param = __privateMethod$1(this, _URLPath_instances, transformParam_fn).call(this, part);
5469
+ return `\${${replacer ? replacer(param) : param}}`;
5470
+ }).join("");
5471
+ return `\`${prefix != null ? prefix : ""}${result}\``;
5925
5472
  }
5926
5473
  /**
5927
- * Registers a one-shot listener that removes itself after the first invocation.
5474
+ * Extracts all `{param}` segments from the path and returns them as a key-value map.
5475
+ * An optional `replacer` transforms each parameter name in both key and value positions.
5476
+ * Returns `undefined` when no path parameters are found.
5928
5477
  *
5929
5478
  * @example
5930
5479
  * ```ts
5931
- * emitter.onOnce('build', async (name) => { console.log(name) })
5480
+ * new URLPath('/pet/{petId}/tag/{tagId}').getParams()
5481
+ * // { petId: 'petId', tagId: 'tagId' }
5932
5482
  * ```
5933
5483
  */
5934
- onOnce(eventName, handler) {
5935
- const wrapper = (...args) => {
5936
- this.off(eventName, wrapper);
5937
- return handler(...args);
5938
- };
5939
- this.on(eventName, wrapper);
5484
+ getParams(replacer) {
5485
+ const params = {};
5486
+ __privateMethod$1(this, _URLPath_instances, eachParam_fn).call(this, (_raw, param) => {
5487
+ const key = replacer ? replacer(param) : param;
5488
+ params[key] = key;
5489
+ });
5490
+ return Object.keys(params).length > 0 ? params : void 0;
5940
5491
  }
5941
- /**
5942
- * Removes a previously registered listener.
5492
+ /** Converts the OpenAPI path to Express-style colon syntax.
5943
5493
  *
5944
5494
  * @example
5945
5495
  * ```ts
5946
- * emitter.off('build', handler)
5496
+ * new URLPath('/pet/{petId}').toURLPath() // '/pet/:petId'
5947
5497
  * ```
5948
5498
  */
5949
- off(eventName, handler) {
5950
- __privateGet(this, _emitter).off(eventName, handler);
5951
- }
5952
- /**
5953
- * Returns the number of listeners registered for `eventName`.
5954
- *
5955
- * @example
5956
- * ```ts
5957
- * emitter.on('build', handler)
5958
- * emitter.listenerCount('build') // 1
5959
- * ```
5960
- */
5961
- listenerCount(eventName) {
5962
- return __privateGet(this, _emitter).listenerCount(eventName);
5499
+ toURLPath() {
5500
+ return this.path.replace(/\{([^}]+)\}/g, ":$1");
5963
5501
  }
5964
- /**
5965
- * Removes all listeners from every event channel.
5966
- *
5967
- * @example
5968
- * ```ts
5969
- * emitter.removeAll()
5970
- * ```
5971
- */
5972
- removeAll() {
5973
- __privateGet(this, _emitter).removeAllListeners();
5502
+ }, _options = new WeakMap(), _URLPath_instances = new WeakSet(), transformParam_fn = function(raw) {
5503
+ const param = isValidVarName(raw) ? raw : camelCase(raw);
5504
+ return __privateGet$1(this, _options).casing === "camelcase" ? camelCase(param) : param;
5505
+ }, /**
5506
+ * Iterates over every `{param}` token in `path`, calling `fn` with the raw token and transformed name.
5507
+ */
5508
+ eachParam_fn = function(fn) {
5509
+ for (const match of this.path.matchAll(/\{([^}]+)\}/g)) {
5510
+ const raw = match[1];
5511
+ fn(raw, __privateMethod$1(this, _URLPath_instances, transformParam_fn).call(this, raw));
5974
5512
  }
5975
- }, _emitter = new WeakMap(), _a);
5976
- function getElapsedMs(hrStart) {
5977
- const [seconds, nanoseconds] = process.hrtime(hrStart);
5978
- const ms = seconds * 1e3 + nanoseconds / 1e6;
5979
- return Math.round(ms * 100) / 100;
5513
+ }, _b);
5514
+ const DEFAULT_STUDIO_URL = "https://kubb.studio";
5515
+ const DEFAULT_BANNER = "simple";
5516
+ const DEFAULT_EXTENSION = { ".ts": ".ts" };
5517
+ function getMode(fileOrFolder) {
5518
+ if (!fileOrFolder) return "split";
5519
+ return extname(fileOrFolder) ? "single" : "split";
5980
5520
  }
5981
- function formatMs(ms) {
5982
- if (ms >= 6e4) return `${Math.floor(ms / 6e4)}m ${(ms % 6e4 / 1e3).toFixed(1)}s`;
5983
- if (ms >= 1e3) return `${(ms / 1e3).toFixed(2)}s`;
5984
- return `${Math.round(ms)}ms`;
5521
+ function buildBannerMeta({ meta, file }) {
5522
+ var _a2, _b2, _c2, _d2, _e, _f;
5523
+ return {
5524
+ title: meta == null ? void 0 : meta.title,
5525
+ description: meta == null ? void 0 : meta.description,
5526
+ version: meta == null ? void 0 : meta.version,
5527
+ baseURL: meta == null ? void 0 : meta.baseURL,
5528
+ circularNames: (_a2 = meta == null ? void 0 : meta.circularNames) != null ? _a2 : [],
5529
+ enumNames: (_b2 = meta == null ? void 0 : meta.enumNames) != null ? _b2 : [],
5530
+ filePath: (_c2 = file == null ? void 0 : file.path) != null ? _c2 : "",
5531
+ baseName: (_d2 = file == null ? void 0 : file.baseName) != null ? _d2 : "",
5532
+ isBarrel: (_e = file == null ? void 0 : file.isBarrel) != null ? _e : false,
5533
+ isAggregation: (_f = file == null ? void 0 : file.isAggregation) != null ? _f : false
5534
+ };
5985
5535
  }
5986
- async function exists(path) {
5987
- if (typeof Bun !== "undefined") return Bun.file(path).exists();
5988
- return access(path).then(() => true, () => false);
5536
+ const stringPatternCache = /* @__PURE__ */ new Map();
5537
+ function testPattern(value, pattern) {
5538
+ if (typeof pattern === "string") {
5539
+ let regex = stringPatternCache.get(pattern);
5540
+ if (!regex) {
5541
+ regex = new RegExp(pattern);
5542
+ stringPatternCache.set(pattern, regex);
5543
+ }
5544
+ return regex.test(value);
5545
+ }
5546
+ return value.match(pattern) !== null;
5989
5547
  }
5990
- async function write(path, data, options = {}) {
5991
- const trimmed = data.trim();
5992
- if (trimmed === "") return null;
5993
- const resolved = resolve(path);
5994
- if (typeof Bun !== "undefined") {
5995
- const file = Bun.file(resolved);
5996
- if ((await file.exists() ? await file.text() : null) === trimmed) return null;
5997
- await Bun.write(resolved, trimmed);
5998
- return trimmed;
5548
+ function matchesOperationPattern(node, type, pattern) {
5549
+ var _a2, _b2, _c2;
5550
+ if (type === "tag") return node.tags.some((tag) => testPattern(tag, pattern));
5551
+ if (type === "operationId") return testPattern(node.operationId, pattern);
5552
+ if (type === "path") return node.path !== void 0 && testPattern(node.path, pattern);
5553
+ if (type === "method") return node.method !== void 0 && testPattern(node.method.toLowerCase(), pattern);
5554
+ if (type === "contentType") return (_c2 = (_b2 = (_a2 = node.requestBody) == null ? void 0 : _a2.content) == null ? void 0 : _b2.some((c) => testPattern(c.contentType, pattern))) != null ? _c2 : false;
5555
+ return false;
5556
+ }
5557
+ function matchesSchemaPattern(node, type, pattern) {
5558
+ if (type === "schemaName") return node.name ? testPattern(node.name, pattern) : false;
5559
+ return null;
5560
+ }
5561
+ function defaultResolver(name, type) {
5562
+ if (type === "file" || type === "function") return camelCase(name, { isFile: type === "file" });
5563
+ if (type === "type") return pascalCase(name);
5564
+ return camelCase(name);
5565
+ }
5566
+ const resolveOptionsCache = /* @__PURE__ */ new WeakMap();
5567
+ function computeOptions(node, options, exclude, include, override) {
5568
+ var _a2, _b2;
5569
+ if (isOperationNode(node)) {
5570
+ if (exclude.some(({ type, pattern }) => matchesOperationPattern(node, type, pattern))) return null;
5571
+ if (include && !include.some(({ type, pattern }) => matchesOperationPattern(node, type, pattern))) return null;
5572
+ const overrideOptions = (_a2 = override.find(({ type, pattern }) => matchesOperationPattern(node, type, pattern))) == null ? void 0 : _a2.options;
5573
+ return {
5574
+ ...options,
5575
+ ...overrideOptions
5576
+ };
5999
5577
  }
5578
+ if (isSchemaNode(node)) {
5579
+ if (exclude.some(({ type, pattern }) => matchesSchemaPattern(node, type, pattern) === true)) return null;
5580
+ if (include) {
5581
+ const applicable = include.map(({ type, pattern }) => matchesSchemaPattern(node, type, pattern)).filter((r) => r !== null);
5582
+ if (applicable.length > 0 && !applicable.includes(true)) return null;
5583
+ }
5584
+ const overrideOptions = (_b2 = override.find(({ type, pattern }) => matchesSchemaPattern(node, type, pattern) === true)) == null ? void 0 : _b2.options;
5585
+ return {
5586
+ ...options,
5587
+ ...overrideOptions
5588
+ };
5589
+ }
5590
+ return options;
5591
+ }
5592
+ function defaultResolveOptions(node, { options, exclude = [], include, override = [] }) {
5593
+ const optionsKey = options;
5594
+ let byOptions = resolveOptionsCache.get(optionsKey);
5595
+ if (!byOptions) {
5596
+ byOptions = /* @__PURE__ */ new WeakMap();
5597
+ resolveOptionsCache.set(optionsKey, byOptions);
5598
+ }
5599
+ const cached = byOptions.get(node);
5600
+ if (cached !== void 0) return cached.value;
5601
+ const result = computeOptions(node, options, exclude, include, override);
5602
+ byOptions.set(node, { value: result });
5603
+ return result;
5604
+ }
5605
+ function defaultResolvePath({ baseName, pathMode, tag, path: groupPath }, { root, output, group }) {
5606
+ if ((pathMode != null ? pathMode : getMode(path$1.resolve(root, output.path))) === "single") return path$1.resolve(root, output.path);
5607
+ const result = (() => {
5608
+ var _a2;
5609
+ if (group && (groupPath || tag)) {
5610
+ const groupValue = group.type === "path" ? groupPath : tag;
5611
+ const defaultName = group.type === "tag" ? ({ group: g }) => `${camelCase(g)}Controller` : ({ group: g }) => {
5612
+ const segment = g.split("/").filter((s) => s !== "" && s !== "." && s !== "..")[0];
5613
+ return segment ? camelCase(segment) : "";
5614
+ };
5615
+ const resolveName = (_a2 = group.name) != null ? _a2 : defaultName;
5616
+ return path$1.resolve(root, output.path, resolveName({ group: groupValue }), baseName);
5617
+ }
5618
+ return path$1.resolve(root, output.path, baseName);
5619
+ })();
5620
+ const outputDir = path$1.resolve(root, output.path);
5621
+ const outputDirWithSep = outputDir.endsWith(path$1.sep) ? outputDir : `${outputDir}${path$1.sep}`;
5622
+ if (result !== outputDir && !result.startsWith(outputDirWithSep)) throw new Error(`[Kubb] Resolved path "${result}" is outside the output directory "${outputDir}". This may indicate a path traversal attempt in the OpenAPI specification or a misconfigured group.name function.`);
5623
+ return result;
5624
+ }
5625
+ function defaultResolveFile({ name, extname: extname2, tag, path: groupPath }, context) {
5626
+ const pathMode = getMode(path$1.resolve(context.root, context.output.path));
5627
+ const baseName = `${pathMode === "single" ? "" : this.default(name, "file")}${extname2}`;
5628
+ const filePath = this.resolvePath({
5629
+ baseName,
5630
+ pathMode,
5631
+ tag,
5632
+ path: groupPath
5633
+ }, context);
5634
+ return createFile({
5635
+ path: filePath,
5636
+ baseName: path$1.basename(filePath),
5637
+ meta: { pluginName: this.pluginName },
5638
+ sources: [],
5639
+ imports: [],
5640
+ exports: []
5641
+ });
5642
+ }
5643
+ function buildDefaultBanner({ title, description, version, config }) {
6000
5644
  try {
6001
- if (await readFile$1(resolved, { encoding: "utf-8" }) === trimmed) return null;
6002
- } catch {
5645
+ const source = (() => {
5646
+ if (Array.isArray(config.input)) {
5647
+ const first = config.input[0];
5648
+ if (first && "path" in first) return path$1.basename(first.path);
5649
+ return "";
5650
+ }
5651
+ if (config.input && "path" in config.input) return path$1.basename(config.input.path);
5652
+ if (config.input && "data" in config.input) return "text content";
5653
+ return "";
5654
+ })();
5655
+ let banner = "/**\n* Generated by Kubb (https://kubb.dev/).\n* Do not edit manually.\n";
5656
+ if (config.output.defaultBanner === "simple") {
5657
+ banner += "*/\n";
5658
+ return banner;
5659
+ }
5660
+ if (source) banner += `* Source: ${source}
5661
+ `;
5662
+ if (title) banner += `* Title: ${title}
5663
+ `;
5664
+ if (description) {
5665
+ const formattedDescription = description.replace(/\n/gm, "\n* ");
5666
+ banner += `* Description: ${formattedDescription}
5667
+ `;
5668
+ }
5669
+ if (version) banner += `* OpenAPI spec version: ${version}
5670
+ `;
5671
+ banner += "*/\n";
5672
+ return banner;
5673
+ } catch (_error) {
5674
+ return "/**\n* Generated by Kubb (https://kubb.dev/).\n* Do not edit manually.\n*/";
6003
5675
  }
6004
- await mkdir(dirname(resolved), { recursive: true });
6005
- await writeFile$1(resolved, trimmed, { encoding: "utf-8" });
6006
- if (options.sanity) {
6007
- const savedData = await readFile$1(resolved, { encoding: "utf-8" });
6008
- if (savedData !== trimmed) throw new Error(`Sanity check failed for ${path}
6009
-
6010
- Data[${data.length}]:
6011
- ${data}
6012
-
6013
- Saved[${savedData.length}]:
6014
- ${savedData}
5676
+ }
5677
+ function defaultResolveBanner(meta, { output, config, file }) {
5678
+ if (typeof (output == null ? void 0 : output.banner) === "function") return output.banner(buildBannerMeta({
5679
+ meta,
5680
+ file
5681
+ }));
5682
+ if (typeof (output == null ? void 0 : output.banner) === "string") return output.banner;
5683
+ if (config.output.defaultBanner === false) return null;
5684
+ return buildDefaultBanner({
5685
+ title: meta == null ? void 0 : meta.title,
5686
+ version: meta == null ? void 0 : meta.version,
5687
+ config
5688
+ });
5689
+ }
5690
+ function defaultResolveFooter(meta, { output, file }) {
5691
+ if (typeof (output == null ? void 0 : output.footer) === "function") return output.footer(buildBannerMeta({
5692
+ meta,
5693
+ file
5694
+ }));
5695
+ if (typeof (output == null ? void 0 : output.footer) === "string") return output.footer;
5696
+ return null;
5697
+ }
5698
+ function defineResolver(build) {
5699
+ let resolver;
5700
+ resolver = {
5701
+ default: defaultResolver,
5702
+ resolveOptions: defaultResolveOptions,
5703
+ resolvePath: defaultResolvePath,
5704
+ resolveFile: (params, context) => defaultResolveFile.call(resolver, params, context),
5705
+ resolveBanner: defaultResolveBanner,
5706
+ resolveFooter: defaultResolveFooter,
5707
+ ...build()
5708
+ };
5709
+ return resolver;
5710
+ }
5711
+ function encodeAst(input) {
5712
+ const compressed = deflateSync(new TextEncoder().encode(JSON.stringify(input)));
5713
+ return Buffer.from(compressed).toString("base64url");
5714
+ }
5715
+ function getStudioUrl(input, studioUrl, options = {}) {
5716
+ return `${studioUrl.replace(/\/$/, "")}${options.ast ? "/ast" : ""}?root=${encodeAst(input)}`;
5717
+ }
5718
+ async function openInStudio(input, studioUrl, options = {}) {
5719
+ const url = getStudioUrl(input, studioUrl, options);
5720
+ const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
5721
+ const args = process.platform === "win32" ? [
5722
+ "/c",
5723
+ "start",
5724
+ "",
5725
+ url
5726
+ ] : [url];
5727
+ try {
5728
+ await x(cmd, args);
5729
+ } catch {
5730
+ console.log(`
5731
+ ${url}
6015
5732
  `);
6016
- return savedData;
6017
5733
  }
6018
- return trimmed;
6019
5734
  }
6020
- async function clean(path) {
6021
- return rm(path, {
6022
- recursive: true,
6023
- force: true
6024
- });
5735
+ function mergeFile(a, b) {
5736
+ return {
5737
+ ...a,
5738
+ banner: b.banner,
5739
+ footer: b.footer,
5740
+ sources: a.sources.length ? b.sources.length ? [...a.sources, ...b.sources] : a.sources : b.sources,
5741
+ imports: a.imports.length ? b.imports.length ? [...a.imports, ...b.imports] : a.imports : b.imports,
5742
+ exports: a.exports.length ? b.exports.length ? [...a.exports, ...b.exports] : a.exports : b.exports
5743
+ };
6025
5744
  }
6026
- const reservedWords = /* @__PURE__ */ new Set([
6027
- "abstract",
6028
- "arguments",
6029
- "boolean",
6030
- "break",
6031
- "byte",
6032
- "case",
6033
- "catch",
6034
- "char",
6035
- "class",
6036
- "const",
6037
- "continue",
6038
- "debugger",
6039
- "default",
6040
- "delete",
6041
- "do",
6042
- "double",
6043
- "else",
6044
- "enum",
6045
- "eval",
6046
- "export",
6047
- "extends",
6048
- "false",
6049
- "final",
6050
- "finally",
6051
- "float",
6052
- "for",
6053
- "function",
6054
- "goto",
6055
- "if",
6056
- "implements",
6057
- "import",
6058
- "in",
6059
- "instanceof",
6060
- "int",
6061
- "interface",
6062
- "let",
6063
- "long",
6064
- "native",
6065
- "new",
6066
- "null",
6067
- "package",
6068
- "private",
6069
- "protected",
6070
- "public",
6071
- "return",
6072
- "short",
6073
- "static",
6074
- "super",
6075
- "switch",
6076
- "synchronized",
6077
- "this",
6078
- "throw",
6079
- "throws",
6080
- "transient",
6081
- "true",
6082
- "try",
6083
- "typeof",
6084
- "var",
6085
- "void",
6086
- "volatile",
6087
- "while",
6088
- "with",
6089
- "yield",
6090
- "Array",
6091
- "Date",
6092
- "hasOwnProperty",
6093
- "Infinity",
6094
- "isFinite",
6095
- "isNaN",
6096
- "isPrototypeOf",
6097
- "length",
6098
- "Math",
6099
- "name",
6100
- "NaN",
6101
- "Number",
6102
- "Object",
6103
- "prototype",
6104
- "String",
6105
- "toString",
6106
- "undefined",
6107
- "valueOf"
6108
- ]);
6109
- function isValidVarName(name) {
6110
- if (!name || reservedWords.has(name)) return false;
6111
- return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
5745
+ function isIndexPath(path2) {
5746
+ return path2.endsWith("/index.ts") || path2 === "index.ts";
5747
+ }
5748
+ function compareFiles(a, b) {
5749
+ const lenDiff = a.path.length - b.path.length;
5750
+ if (lenDiff !== 0) return lenDiff;
5751
+ const aIsIndex = isIndexPath(a.path);
5752
+ const bIsIndex = isIndexPath(b.path);
5753
+ if (aIsIndex && !bIsIndex) return 1;
5754
+ if (!aIsIndex && bIsIndex) return -1;
5755
+ return 0;
5756
+ }
5757
+ var FileManager = (_c = class {
5758
+ constructor() {
5759
+ __privateAdd$1(this, _FileManager_instances);
5760
+ __privateAdd$1(this, _cache, /* @__PURE__ */ new Map());
5761
+ __privateAdd$1(this, _sorted, null);
5762
+ __privateAdd$1(this, _onUpsert, null);
5763
+ }
5764
+ /**
5765
+ * Registers a callback invoked with the resolved {@link FileNode} on every
5766
+ * `add` / `upsert`. Used by the build loop to track newly written files
5767
+ * without keeping its own scan-based diff. Single subscriber by design —
5768
+ * setting again replaces the previous callback. Pass `null` to detach.
5769
+ */
5770
+ setOnUpsert(callback) {
5771
+ __privateSet$1(this, _onUpsert, callback);
5772
+ }
5773
+ add(...files) {
5774
+ return __privateMethod$1(this, _FileManager_instances, store_fn).call(this, files, false);
5775
+ }
5776
+ upsert(...files) {
5777
+ return __privateMethod$1(this, _FileManager_instances, store_fn).call(this, files, true);
5778
+ }
5779
+ getByPath(path2) {
5780
+ var _a2;
5781
+ return (_a2 = __privateGet$1(this, _cache).get(path2)) != null ? _a2 : null;
5782
+ }
5783
+ deleteByPath(path2) {
5784
+ if (!__privateGet$1(this, _cache).delete(path2)) return;
5785
+ __privateSet$1(this, _sorted, null);
5786
+ }
5787
+ clear() {
5788
+ __privateGet$1(this, _cache).clear();
5789
+ __privateSet$1(this, _sorted, null);
5790
+ }
5791
+ /**
5792
+ * Releases all stored files. Called by the core after `kubb:build:end`.
5793
+ */
5794
+ dispose() {
5795
+ this.clear();
5796
+ __privateSet$1(this, _onUpsert, null);
5797
+ }
5798
+ [Symbol.dispose]() {
5799
+ this.dispose();
5800
+ }
5801
+ /**
5802
+ * All stored files in stable sort order (shortest path first, barrel files
5803
+ * last within a length bucket). Returns a cached view — do not mutate.
5804
+ */
5805
+ get files() {
5806
+ var _a2;
5807
+ return (_a2 = __privateGet$1(this, _sorted)) != null ? _a2 : __privateSet$1(this, _sorted, [...__privateGet$1(this, _cache).values()].sort(compareFiles));
5808
+ }
5809
+ }, _cache = new WeakMap(), _sorted = new WeakMap(), _onUpsert = new WeakMap(), _FileManager_instances = new WeakSet(), store_fn = function(files, mergeExisting) {
5810
+ var _a2;
5811
+ const batch = files.length > 1 ? __privateMethod$1(this, _FileManager_instances, dedupe_fn).call(this, files) : files;
5812
+ const resolved = [];
5813
+ for (const file of batch) {
5814
+ const existing = __privateGet$1(this, _cache).get(file.path);
5815
+ const merged = existing && mergeExisting ? createFile(mergeFile(existing, file)) : createFile(file);
5816
+ __privateGet$1(this, _cache).set(merged.path, merged);
5817
+ resolved.push(merged);
5818
+ (_a2 = __privateGet$1(this, _onUpsert)) == null ? void 0 : _a2.call(this, merged);
5819
+ }
5820
+ if (resolved.length > 0) __privateSet$1(this, _sorted, null);
5821
+ return resolved;
5822
+ }, dedupe_fn = function(files) {
5823
+ const seen = /* @__PURE__ */ new Map();
5824
+ for (const file of files) {
5825
+ const prev = seen.get(file.path);
5826
+ seen.set(file.path, prev ? mergeFile(prev, file) : file);
5827
+ }
5828
+ return [...seen.values()];
5829
+ }, _c);
5830
+ function joinSources(file) {
5831
+ const sources = file.sources;
5832
+ if (sources.length === 0) return "";
5833
+ const parts = [];
5834
+ for (const source of sources) {
5835
+ const s = extractStringsFromNodes(source.nodes);
5836
+ if (s) parts.push(s);
5837
+ }
5838
+ return parts.join("\n\n");
6112
5839
  }
6113
- var URLPath = (_b = class {
6114
- constructor(path, options = {}) {
6115
- __privateAdd(this, _URLPath_instances);
5840
+ var FileProcessor = class {
5841
+ constructor() {
5842
+ __publicField$1(this, "events", new AsyncEventEmitter());
5843
+ }
5844
+ parse(file, { parsers, extension } = {}) {
5845
+ const parseExtName = (extension == null ? void 0 : extension[file.extname]) || void 0;
5846
+ if (!parsers || !file.extname) return joinSources(file);
5847
+ const parser = parsers.get(file.extname);
5848
+ if (!parser) return joinSources(file);
5849
+ return parser.parse(file, { extname: parseExtName });
5850
+ }
5851
+ *stream(files, options = {}) {
5852
+ const total = files.length;
5853
+ if (total === 0) return;
5854
+ let processed = 0;
5855
+ for (const file of files) {
5856
+ const source = this.parse(file, options);
5857
+ processed++;
5858
+ yield {
5859
+ file,
5860
+ source,
5861
+ processed,
5862
+ total,
5863
+ percentage: processed / total * 100
5864
+ };
5865
+ }
5866
+ }
5867
+ async run(files, options = {}) {
5868
+ await this.events.emit("start", files);
5869
+ for (const { file, source, processed, total, percentage } of this.stream(files, options)) await this.events.emit("update", {
5870
+ file,
5871
+ source,
5872
+ processed,
5873
+ percentage,
5874
+ total
5875
+ });
5876
+ await this.events.emit("end", files);
5877
+ return files;
5878
+ }
5879
+ /**
5880
+ * Clears all registered event listeners.
5881
+ */
5882
+ dispose() {
5883
+ this.events.removeAll();
5884
+ }
5885
+ [Symbol.dispose]() {
5886
+ this.dispose();
5887
+ }
5888
+ };
5889
+ function _usingCtx() {
5890
+ var r = "function" == typeof SuppressedError ? SuppressedError : function(r2, e2) {
5891
+ var n2 = Error();
5892
+ return n2.name = "SuppressedError", n2.error = r2, n2.suppressed = e2, n2;
5893
+ };
5894
+ var e = {};
5895
+ var n = [];
5896
+ function using(r2, e2) {
5897
+ if (null != e2) {
5898
+ if (Object(e2) !== e2) throw new TypeError("using declarations can only be used with objects, functions, null, or undefined.");
5899
+ if (r2) var o = e2[Symbol.asyncDispose || Symbol["for"]("Symbol.asyncDispose")];
5900
+ if (void 0 === o && (o = e2[Symbol.dispose || Symbol["for"]("Symbol.dispose")], r2)) var t = o;
5901
+ if ("function" != typeof o) throw new TypeError("Object is not disposable.");
5902
+ t && (o = function o2() {
5903
+ try {
5904
+ t.call(e2);
5905
+ } catch (r3) {
5906
+ return Promise.reject(r3);
5907
+ }
5908
+ }), n.push({
5909
+ v: e2,
5910
+ d: o,
5911
+ a: r2
5912
+ });
5913
+ } else r2 && n.push({
5914
+ d: e2,
5915
+ a: r2
5916
+ });
5917
+ return e2;
5918
+ }
5919
+ return {
5920
+ e,
5921
+ u: using.bind(null, false),
5922
+ a: using.bind(null, true),
5923
+ d: function d() {
5924
+ var o;
5925
+ var t = this.e;
5926
+ var s = 0;
5927
+ function next() {
5928
+ for (; o = n.pop(); ) try {
5929
+ if (!o.a && 1 === s) return s = 0, n.push(o), Promise.resolve().then(next);
5930
+ if (o.d) {
5931
+ var r2 = o.d.call(o.v);
5932
+ if (o.a) return s |= 2, Promise.resolve(r2).then(next, err);
5933
+ } else s |= 1;
5934
+ } catch (r3) {
5935
+ return err(r3);
5936
+ }
5937
+ if (1 === s) return t !== e ? Promise.reject(t) : Promise.resolve();
5938
+ if (t !== e) throw t;
5939
+ }
5940
+ function err(n2) {
5941
+ return t = t !== e ? new r(n2, t) : n2, next();
5942
+ }
5943
+ return next();
5944
+ }
5945
+ };
5946
+ }
5947
+ function enforceOrder(enforce) {
5948
+ return enforce === "pre" ? -1 : enforce === "post" ? 1 : 0;
5949
+ }
5950
+ const OPERATION_FILTER_TYPES = /* @__PURE__ */ new Set([
5951
+ "tag",
5952
+ "operationId",
5953
+ "path",
5954
+ "method",
5955
+ "contentType"
5956
+ ]);
5957
+ var KubbDriver = (_d = class {
5958
+ constructor(config, options) {
5959
+ __privateAdd$1(this, _KubbDriver_instances);
5960
+ __publicField$1(this, "config");
5961
+ __publicField$1(this, "options");
6116
5962
  /**
6117
- * The raw OpenAPI/Swagger path string, e.g. `/pet/{petId}`.
5963
+ * The streaming `InputStreamNode` produced by the adapter.
5964
+ * Always set after adapter setup — parse-only adapters are wrapped automatically.
5965
+ */
5966
+ __publicField$1(this, "inputNode", null);
5967
+ __publicField$1(this, "adapter", null);
5968
+ /**
5969
+ * Studio session state, kept together so `dispose()` can reset it atomically.
5970
+ *
5971
+ * - `source` holds the raw adapter source so `adapter.parse()` can be called lazily.
5972
+ * Intentionally outlives the build; cleared by `dispose()`.
5973
+ * - `isOpen` prevents opening the studio more than once per build.
5974
+ * - `inputNode` caches the parse promise so `adapter.parse()` is called at most once
5975
+ * per studio session, even when `openInStudio()` is called multiple times.
5976
+ */
5977
+ __privateAdd$1(this, _studio, {
5978
+ source: null,
5979
+ isOpen: false,
5980
+ inputNode: null
5981
+ });
5982
+ __privateAdd$1(this, _middlewareListeners, []);
5983
+ /**
5984
+ * Central file store for all generated files.
5985
+ * Plugins should use `this.addFile()` / `this.upsertFile()` (via their context) to
5986
+ * add files; this property gives direct read/write access when needed.
5987
+ */
5988
+ __publicField$1(this, "fileManager", new FileManager());
5989
+ __privateAdd$1(this, _fileProcessor, new FileProcessor());
5990
+ __publicField$1(this, "plugins", /* @__PURE__ */ new Map());
5991
+ /**
5992
+ * Tracks which plugins have generators registered via `addGenerator()` (event-based path).
5993
+ * Used by the build loop to decide whether to emit generator events for a given plugin.
6118
5994
  */
6119
- __publicField(this, "path");
6120
- __privateAdd(this, _options);
6121
- this.path = path;
6122
- __privateSet(this, _options, options);
5995
+ __privateAdd$1(this, _eventGeneratorPlugins, /* @__PURE__ */ new Set());
5996
+ __privateAdd$1(this, _resolvers, /* @__PURE__ */ new Map());
5997
+ __privateAdd$1(this, _defaultResolvers, /* @__PURE__ */ new Map());
5998
+ __privateAdd$1(this, _hookListeners, /* @__PURE__ */ new Map());
5999
+ __privateAdd$1(this, _getDefaultResolver, memoize(__privateGet$1(this, _defaultResolvers), (pluginName) => defineResolver(() => ({
6000
+ name: "default",
6001
+ pluginName
6002
+ }))));
6003
+ var _a2;
6004
+ this.config = config;
6005
+ this.options = options;
6006
+ this.adapter = (_a2 = config.adapter) != null ? _a2 : null;
6123
6007
  }
6124
- /** Converts the OpenAPI path to Express-style colon syntax, e.g. `/pet/{petId}` → `/pet/:petId`.
6008
+ /**
6009
+ * Returns `'single'` when `fileOrFolder` has a file extension, `'split'` otherwise.
6125
6010
  *
6126
6011
  * @example
6127
6012
  * ```ts
6128
- * new URLPath('/pet/{petId}').URL // '/pet/:petId'
6013
+ * KubbDriver.getMode('src/gen/types.ts') // 'single'
6014
+ * KubbDriver.getMode('src/gen/types') // 'split'
6129
6015
  * ```
6130
6016
  */
6131
- get URL() {
6132
- return this.toURLPath();
6017
+ static getMode(fileOrFolder) {
6018
+ return getMode(fileOrFolder);
6133
6019
  }
6134
- /** Returns `true` when `path` is a fully-qualified URL (e.g. starts with `https://`).
6135
- *
6136
- * @example
6137
- * ```ts
6138
- * new URLPath('https://petstore.swagger.io/v2/pet').isURL // true
6139
- * new URLPath('/pet/{petId}').isURL // false
6140
- * ```
6141
- */
6142
- get isURL() {
6143
- try {
6144
- return !!new URL(this.path).href;
6145
- } catch {
6146
- return false;
6020
+ async setup() {
6021
+ const normalized = this.config.plugins.map((rawPlugin) => __privateMethod$1(this, _KubbDriver_instances, normalizePlugin_fn).call(this, rawPlugin));
6022
+ normalized.sort((a, b) => {
6023
+ var _a2, _b2;
6024
+ if ((_a2 = b.dependencies) == null ? void 0 : _a2.includes(a.name)) return -1;
6025
+ if ((_b2 = a.dependencies) == null ? void 0 : _b2.includes(b.name)) return 1;
6026
+ return enforceOrder(a.enforce) - enforceOrder(b.enforce);
6027
+ });
6028
+ for (const plugin of normalized) {
6029
+ if (plugin.apply) plugin.apply(this.config);
6030
+ __privateMethod$1(this, _KubbDriver_instances, registerPlugin_fn).call(this, plugin);
6031
+ this.plugins.set(plugin.name, plugin);
6147
6032
  }
6033
+ if (this.config.middleware) for (const middleware of this.config.middleware) for (const event of Object.keys(middleware.hooks)) __privateMethod$1(this, _KubbDriver_instances, registerMiddleware_fn).call(this, event, middleware.hooks);
6034
+ if (this.config.adapter) await __privateMethod$1(this, _KubbDriver_instances, registerAdapter_fn).call(this, this.config.adapter);
6035
+ }
6036
+ get hooks() {
6037
+ return this.options.hooks;
6148
6038
  }
6149
6039
  /**
6150
- * Converts the OpenAPI path to a TypeScript template literal string.
6040
+ * Emits the `kubb:plugin:setup` event so that all registered hook-style plugin listeners
6041
+ * can configure generators, resolvers, transformers and renderers before `buildStart` runs.
6151
6042
  *
6152
- * @example
6153
- * new URLPath('/pet/{petId}').template // '`/pet/${petId}`'
6154
- * new URLPath('/account/monetary-accountID').template // '`/account/${monetaryAccountId}`'
6043
+ * Call this once from `safeBuild` before the plugin execution loop begins.
6155
6044
  */
6156
- get template() {
6157
- return this.toTemplateString();
6045
+ async emitSetupHooks() {
6046
+ const noop = () => {
6047
+ };
6048
+ await this.hooks.emit("kubb:plugin:setup", {
6049
+ config: this.config,
6050
+ options: {},
6051
+ addGenerator: noop,
6052
+ setResolver: noop,
6053
+ setTransformer: noop,
6054
+ setRenderer: noop,
6055
+ setOptions: noop,
6056
+ injectFile: noop,
6057
+ updateConfig: noop
6058
+ });
6158
6059
  }
6159
- /** Returns the path and its extracted params as a structured `URLObject`, or as a stringified expression when `stringify` is set.
6060
+ /**
6061
+ * Registers a generator for the given plugin on the shared event emitter.
6160
6062
  *
6161
- * @example
6162
- * ```ts
6163
- * new URLPath('/pet/{petId}').object
6164
- * // { url: '/pet/:petId', params: { petId: 'petId' } }
6165
- * ```
6166
- */
6167
- get object() {
6168
- return this.toObject();
6169
- }
6170
- /** Returns a map of path parameter names, or `undefined` when the path has no parameters.
6063
+ * The generator's `schema`, `operation`, and `operations` methods are registered as
6064
+ * listeners on `kubb:generate:schema`, `kubb:generate:operation`, and `kubb:generate:operations`
6065
+ * respectively. Each listener is scoped to the owning plugin via a `ctx.plugin.name` check
6066
+ * so that generators from different plugins do not cross-fire.
6171
6067
  *
6172
- * @example
6173
- * ```ts
6174
- * new URLPath('/pet/{petId}').params // { petId: 'petId' }
6175
- * new URLPath('/pet').params // undefined
6176
- * ```
6068
+ * The renderer resolution chain is: `generator.renderer → plugin.renderer → config.renderer`.
6069
+ * Set `generator.renderer = null` to explicitly opt out of rendering even when the plugin
6070
+ * declares a renderer.
6071
+ *
6072
+ * Call this method inside `addGenerator()` (in `kubb:plugin:setup`) to wire up a generator.
6177
6073
  */
6178
- get params() {
6179
- return this.getParams();
6180
- }
6181
- toObject({ type = "path", replacer, stringify } = {}) {
6182
- const object = {
6183
- url: type === "path" ? this.toURLPath() : this.toTemplateString({ replacer }),
6184
- params: this.getParams()
6074
+ registerGenerator(pluginName, gen) {
6075
+ const resolveRenderer = () => {
6076
+ var _a2, _b2;
6077
+ const plugin = this.plugins.get(pluginName);
6078
+ return gen.renderer === null ? void 0 : (_b2 = (_a2 = gen.renderer) != null ? _a2 : plugin == null ? void 0 : plugin.renderer) != null ? _b2 : this.config.renderer;
6185
6079
  };
6186
- if (stringify) {
6187
- if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
6188
- if (object.params) return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll("'", "").replaceAll(`"`, "")} }`;
6189
- return `{ url: '${object.url}' }`;
6080
+ if (gen.schema) {
6081
+ const schemaHandler = async (node, ctx) => {
6082
+ if (ctx.plugin.name !== pluginName) return;
6083
+ await applyHookResult({
6084
+ result: await gen.schema(node, ctx),
6085
+ driver: this,
6086
+ rendererFactory: resolveRenderer()
6087
+ });
6088
+ };
6089
+ this.hooks.on("kubb:generate:schema", schemaHandler);
6090
+ __privateMethod$1(this, _KubbDriver_instances, trackHookListener_fn).call(this, "kubb:generate:schema", schemaHandler);
6190
6091
  }
6191
- return object;
6092
+ if (gen.operation) {
6093
+ const operationHandler = async (node, ctx) => {
6094
+ if (ctx.plugin.name !== pluginName) return;
6095
+ await applyHookResult({
6096
+ result: await gen.operation(node, ctx),
6097
+ driver: this,
6098
+ rendererFactory: resolveRenderer()
6099
+ });
6100
+ };
6101
+ this.hooks.on("kubb:generate:operation", operationHandler);
6102
+ __privateMethod$1(this, _KubbDriver_instances, trackHookListener_fn).call(this, "kubb:generate:operation", operationHandler);
6103
+ }
6104
+ if (gen.operations) {
6105
+ const operationsHandler = async (nodes, ctx) => {
6106
+ if (ctx.plugin.name !== pluginName) return;
6107
+ await applyHookResult({
6108
+ result: await gen.operations(nodes, ctx),
6109
+ driver: this,
6110
+ rendererFactory: resolveRenderer()
6111
+ });
6112
+ };
6113
+ this.hooks.on("kubb:generate:operations", operationsHandler);
6114
+ __privateMethod$1(this, _KubbDriver_instances, trackHookListener_fn).call(this, "kubb:generate:operations", operationsHandler);
6115
+ }
6116
+ __privateGet$1(this, _eventGeneratorPlugins).add(pluginName);
6192
6117
  }
6193
6118
  /**
6194
- * Converts the OpenAPI path to a TypeScript template literal string.
6195
- * An optional `replacer` can transform each extracted parameter name before interpolation.
6119
+ * Returns `true` when at least one generator was registered for the given plugin
6120
+ * via `addGenerator()` in `kubb:plugin:setup` (event-based path).
6196
6121
  *
6197
- * @example
6198
- * new URLPath('/pet/{petId}').toTemplateString() // '`/pet/${petId}`'
6122
+ * Used by the build loop to decide whether to walk the AST and emit generator events
6123
+ * for a plugin that has no static `plugin.generators`.
6199
6124
  */
6200
- toTemplateString({ prefix = "", replacer } = {}) {
6201
- return `\`${prefix}${this.path.split(/\{([^}]+)\}/).map((part, i) => {
6202
- if (i % 2 === 0) return part;
6203
- const param = __privateMethod(this, _URLPath_instances, transformParam_fn).call(this, part);
6204
- return `\${${replacer ? replacer(param) : param}}`;
6205
- }).join("")}\``;
6125
+ hasEventGenerators(pluginName) {
6126
+ return __privateGet$1(this, _eventGeneratorPlugins).has(pluginName);
6206
6127
  }
6207
6128
  /**
6208
- * Extracts all `{param}` segments from the path and returns them as a key-value map.
6209
- * An optional `replacer` transforms each parameter name in both key and value positions.
6210
- * Returns `undefined` when no path parameters are found.
6129
+ * Runs the full plugin pipeline. Returns timings/failures collected so far even
6130
+ * when an outer hook throws the orchestrator preserves partial state by capturing
6131
+ * the error into `error` instead of propagating.
6132
+ */
6133
+ async run({ storage }) {
6134
+ var _a2;
6135
+ const hooks = this.hooks;
6136
+ const config = this.config;
6137
+ const failedPlugins = /* @__PURE__ */ new Set();
6138
+ const pluginTimings = /* @__PURE__ */ new Map();
6139
+ const parsersMap = /* @__PURE__ */ new Map();
6140
+ for (const parser of config.parsers) if (parser.extNames) for (const ext of parser.extNames) parsersMap.set(ext, parser);
6141
+ const pendingFiles = /* @__PURE__ */ new Map();
6142
+ this.fileManager.setOnUpsert((file) => {
6143
+ pendingFiles.set(file.path, file);
6144
+ });
6145
+ try {
6146
+ const flushPending = async () => {
6147
+ if (pendingFiles.size === 0) return;
6148
+ const files2 = [...pendingFiles.values()];
6149
+ pendingFiles.clear();
6150
+ await hooks.emit("kubb:debug", {
6151
+ date: /* @__PURE__ */ new Date(),
6152
+ logs: [`Writing ${files2.length} files...`]
6153
+ });
6154
+ await hooks.emit("kubb:files:processing:start", { files: files2 });
6155
+ const items = [...__privateGet$1(this, _fileProcessor).stream(files2, {
6156
+ parsers: parsersMap,
6157
+ extension: config.output.extension
6158
+ })];
6159
+ await hooks.emit("kubb:files:processing:update", { files: items.map(({ file, source, processed, total, percentage }) => ({
6160
+ file,
6161
+ source,
6162
+ processed,
6163
+ total,
6164
+ percentage,
6165
+ config
6166
+ })) });
6167
+ const queue = [];
6168
+ for (const { file, source } of items) if (source) {
6169
+ queue.push(storage.setItem(file.path, source));
6170
+ if (queue.length >= 50) await Promise.all(queue.splice(0));
6171
+ }
6172
+ await Promise.all(queue);
6173
+ await hooks.emit("kubb:files:processing:end", { files: files2 });
6174
+ await hooks.emit("kubb:debug", {
6175
+ date: /* @__PURE__ */ new Date(),
6176
+ logs: [`\u2713 File write process completed for ${files2.length} files`]
6177
+ });
6178
+ };
6179
+ await this.emitSetupHooks();
6180
+ if (this.adapter && this.inputNode) await hooks.emit("kubb:build:start", Object.assign({
6181
+ config,
6182
+ adapter: this.adapter,
6183
+ meta: this.inputNode.meta,
6184
+ getPlugin: this.getPlugin.bind(this)
6185
+ }, __privateMethod$1(this, _KubbDriver_instances, filesPayload_fn).call(this)));
6186
+ const generatorPlugins = [];
6187
+ for (const plugin of this.plugins.values()) {
6188
+ const context = this.getContext(plugin);
6189
+ const hrStart = process.hrtime();
6190
+ try {
6191
+ await hooks.emit("kubb:plugin:start", { plugin });
6192
+ await hooks.emit("kubb:debug", {
6193
+ date: /* @__PURE__ */ new Date(),
6194
+ logs: ["Starting plugin...", ` \u2022 Plugin Name: ${plugin.name}`]
6195
+ });
6196
+ } catch (caughtError) {
6197
+ const error = caughtError;
6198
+ const duration2 = getElapsedMs(hrStart);
6199
+ pluginTimings.set(plugin.name, duration2);
6200
+ await __privateMethod$1(this, _KubbDriver_instances, emitPluginEnd_fn).call(this, {
6201
+ plugin,
6202
+ duration: duration2,
6203
+ success: false,
6204
+ error
6205
+ });
6206
+ failedPlugins.add({
6207
+ plugin,
6208
+ error
6209
+ });
6210
+ continue;
6211
+ }
6212
+ if (((_a2 = plugin.generators) == null ? void 0 : _a2.length) || this.hasEventGenerators(plugin.name)) {
6213
+ generatorPlugins.push({
6214
+ plugin,
6215
+ context,
6216
+ hrStart
6217
+ });
6218
+ continue;
6219
+ }
6220
+ const duration = getElapsedMs(hrStart);
6221
+ pluginTimings.set(plugin.name, duration);
6222
+ await __privateMethod$1(this, _KubbDriver_instances, emitPluginEnd_fn).call(this, {
6223
+ plugin,
6224
+ duration,
6225
+ success: true
6226
+ });
6227
+ await hooks.emit("kubb:debug", {
6228
+ date: /* @__PURE__ */ new Date(),
6229
+ logs: [`\u2713 Plugin started successfully (${formatMs(duration)})`]
6230
+ });
6231
+ }
6232
+ if (generatorPlugins.length > 0) if (this.inputNode) {
6233
+ const { timings, failed } = await __privateMethod$1(this, _KubbDriver_instances, runGenerators_fn).call(this, generatorPlugins, flushPending);
6234
+ await flushPending();
6235
+ for (const [name, duration] of timings) pluginTimings.set(name, duration);
6236
+ for (const entry of failed) failedPlugins.add(entry);
6237
+ } else for (const { plugin, hrStart } of generatorPlugins) {
6238
+ const duration = getElapsedMs(hrStart);
6239
+ pluginTimings.set(plugin.name, duration);
6240
+ await __privateMethod$1(this, _KubbDriver_instances, emitPluginEnd_fn).call(this, {
6241
+ plugin,
6242
+ duration,
6243
+ success: true
6244
+ });
6245
+ }
6246
+ await hooks.emit("kubb:plugins:end", Object.assign({ config }, __privateMethod$1(this, _KubbDriver_instances, filesPayload_fn).call(this)));
6247
+ await flushPending();
6248
+ const files = this.fileManager.files;
6249
+ await hooks.emit("kubb:build:end", {
6250
+ files,
6251
+ config,
6252
+ outputDir: resolve(config.root, config.output.path)
6253
+ });
6254
+ return {
6255
+ failedPlugins,
6256
+ pluginTimings
6257
+ };
6258
+ } catch (caughtError) {
6259
+ return {
6260
+ failedPlugins,
6261
+ pluginTimings,
6262
+ error: caughtError
6263
+ };
6264
+ } finally {
6265
+ this.fileManager.setOnUpsert(null);
6266
+ }
6267
+ }
6268
+ /**
6269
+ * Unregisters all plugin lifecycle listeners from the shared event emitter.
6270
+ * Called at the end of a build to prevent listener leaks across repeated builds.
6211
6271
  *
6212
- * @example
6213
- * ```ts
6214
- * new URLPath('/pet/{petId}/tag/{tagId}').getParams()
6215
- * // { petId: 'petId', tagId: 'tagId' }
6216
- * ```
6272
+ * @internal
6217
6273
  */
6218
- getParams(replacer) {
6219
- const params = {};
6220
- __privateMethod(this, _URLPath_instances, eachParam_fn).call(this, (_raw, param) => {
6221
- const key = replacer ? replacer(param) : param;
6222
- params[key] = key;
6274
+ dispose() {
6275
+ for (const [event, handlers] of __privateGet$1(this, _hookListeners)) for (const handler of handlers) this.hooks.off(event, handler);
6276
+ __privateGet$1(this, _hookListeners).clear();
6277
+ __privateGet$1(this, _eventGeneratorPlugins).clear();
6278
+ __privateGet$1(this, _resolvers).clear();
6279
+ __privateGet$1(this, _defaultResolvers).clear();
6280
+ this.fileManager.dispose();
6281
+ __privateGet$1(this, _fileProcessor).dispose();
6282
+ this.inputNode = null;
6283
+ __privateSet$1(this, _studio, {
6284
+ source: null,
6285
+ isOpen: false,
6286
+ inputNode: null
6223
6287
  });
6224
- return Object.keys(params).length > 0 ? params : void 0;
6288
+ for (const [event, handler] of __privateGet$1(this, _middlewareListeners)) this.hooks.off(event, handler);
6225
6289
  }
6226
- /** Converts the OpenAPI path to Express-style colon syntax.
6227
- *
6228
- * @example
6229
- * ```ts
6230
- * new URLPath('/pet/{petId}').toURLPath() // '/pet/:petId'
6231
- * ```
6290
+ [Symbol.dispose]() {
6291
+ this.dispose();
6292
+ }
6293
+ /**
6294
+ * Merges `partial` with the plugin's default resolver and stores the result.
6295
+ * Also mirrors it onto `plugin.resolver` so callers using `getPlugin(name).resolver`
6296
+ * get the up-to-date resolver without going through `getResolver()`.
6232
6297
  */
6233
- toURLPath() {
6234
- return this.path.replace(/\{([^}]+)\}/g, ":$1");
6298
+ setPluginResolver(pluginName, partial) {
6299
+ const merged = {
6300
+ ...__privateGet$1(this, _getDefaultResolver).call(this, pluginName),
6301
+ ...partial
6302
+ };
6303
+ __privateGet$1(this, _resolvers).set(pluginName, merged);
6304
+ const plugin = this.plugins.get(pluginName);
6305
+ if (plugin) plugin.resolver = merged;
6235
6306
  }
6236
- }, _options = new WeakMap(), _URLPath_instances = new WeakSet(), transformParam_fn = function(raw) {
6237
- const param = isValidVarName(raw) ? raw : camelCase(raw);
6238
- return __privateGet(this, _options).casing === "camelcase" ? camelCase(param) : param;
6239
- }, /**
6240
- * Iterates over every `{param}` token in `path`, calling `fn` with the raw token and transformed name.
6241
- */
6242
- eachParam_fn = function(fn) {
6243
- for (const match of this.path.matchAll(/\{([^}]+)\}/g)) {
6244
- const raw = match[1];
6245
- fn(raw, __privateMethod(this, _URLPath_instances, transformParam_fn).call(this, raw));
6307
+ getResolver(pluginName) {
6308
+ var _a2, _b2, _c2;
6309
+ return (_c2 = (_b2 = __privateGet$1(this, _resolvers).get(pluginName)) != null ? _b2 : (_a2 = this.plugins.get(pluginName)) == null ? void 0 : _a2.resolver) != null ? _c2 : __privateGet$1(this, _getDefaultResolver).call(this, pluginName);
6246
6310
  }
6247
- }, _b);
6248
- var Node$1 = (_c = class {
6249
- constructor(value) {
6250
- __publicField(this, "value");
6251
- __publicField(this, "next");
6252
- this.value = value;
6253
- }
6254
- }, __name(_c, "Node"), _c);
6255
- var Queue = (_d = class {
6256
- constructor() {
6257
- __privateAdd(this, _head);
6258
- __privateAdd(this, _tail);
6259
- __privateAdd(this, _size);
6260
- this.clear();
6311
+ getContext(plugin) {
6312
+ const driver = this;
6313
+ return {
6314
+ config: driver.config,
6315
+ get root() {
6316
+ return resolve(driver.config.root, driver.config.output.path);
6317
+ },
6318
+ getMode(output) {
6319
+ return _d.getMode(resolve(driver.config.root, driver.config.output.path, output.path));
6320
+ },
6321
+ hooks: driver.hooks,
6322
+ plugin,
6323
+ getPlugin: driver.getPlugin.bind(driver),
6324
+ requirePlugin: driver.requirePlugin.bind(driver),
6325
+ getResolver: driver.getResolver.bind(driver),
6326
+ driver,
6327
+ addFile: async (...files) => {
6328
+ driver.fileManager.add(...files);
6329
+ },
6330
+ upsertFile: async (...files) => {
6331
+ driver.fileManager.upsert(...files);
6332
+ },
6333
+ get meta() {
6334
+ var _a2, _b2;
6335
+ return (_b2 = (_a2 = driver.inputNode) == null ? void 0 : _a2.meta) != null ? _b2 : {
6336
+ circularNames: [],
6337
+ enumNames: []
6338
+ };
6339
+ },
6340
+ get adapter() {
6341
+ return driver.adapter;
6342
+ },
6343
+ get resolver() {
6344
+ return driver.getResolver(plugin.name);
6345
+ },
6346
+ get transformer() {
6347
+ return plugin.transformer;
6348
+ },
6349
+ warn(message) {
6350
+ driver.hooks.emit("kubb:warn", { message });
6351
+ },
6352
+ error(error) {
6353
+ driver.hooks.emit("kubb:error", { error: typeof error === "string" ? new Error(error) : error });
6354
+ },
6355
+ info(message) {
6356
+ driver.hooks.emit("kubb:info", { message });
6357
+ },
6358
+ async openInStudio(options) {
6359
+ var _a2, _b2, _c2, _d2;
6360
+ if (!driver.config.devtools || __privateGet$1(driver, _studio).isOpen) return;
6361
+ if (typeof driver.config.devtools !== "object") throw new Error("Devtools must be an object");
6362
+ if (!driver.adapter || !__privateGet$1(driver, _studio).source) throw new Error("adapter is not defined, make sure you have set the parser in kubb.config.ts");
6363
+ __privateGet$1(driver, _studio).isOpen = true;
6364
+ const studioUrl = (_b2 = (_a2 = driver.config.devtools) == null ? void 0 : _a2.studioUrl) != null ? _b2 : "https://kubb.studio";
6365
+ (_d2 = (_c2 = __privateGet$1(driver, _studio)).inputNode) != null ? _d2 : _c2.inputNode = Promise.resolve(driver.adapter.parse(__privateGet$1(driver, _studio).source));
6366
+ return openInStudio(await __privateGet$1(driver, _studio).inputNode, studioUrl, options);
6367
+ }
6368
+ };
6261
6369
  }
6262
- enqueue(value) {
6263
- const node = new Node$1(value);
6264
- if (__privateGet(this, _head)) {
6265
- __privateGet(this, _tail).next = node;
6266
- __privateSet(this, _tail, node);
6267
- } else {
6268
- __privateSet(this, _head, node);
6269
- __privateSet(this, _tail, node);
6370
+ getPlugin(pluginName) {
6371
+ return this.plugins.get(pluginName);
6372
+ }
6373
+ requirePlugin(pluginName) {
6374
+ const plugin = this.plugins.get(pluginName);
6375
+ if (!plugin) throw new Error(`[kubb] Plugin "${pluginName}" is required but not found. Make sure it is included in your Kubb config.`);
6376
+ return plugin;
6377
+ }
6378
+ }, _studio = new WeakMap(), _middlewareListeners = new WeakMap(), _fileProcessor = new WeakMap(), _eventGeneratorPlugins = new WeakMap(), _resolvers = new WeakMap(), _defaultResolvers = new WeakMap(), _hookListeners = new WeakMap(), _KubbDriver_instances = new WeakSet(), /**
6379
+ * Creates an `NormalizedPlugin` from a hook-style plugin and registers
6380
+ * its lifecycle handlers on the `AsyncEventEmitter`.
6381
+ */
6382
+ normalizePlugin_fn = function(plugin) {
6383
+ var _a2;
6384
+ const normalized = {
6385
+ name: plugin.name,
6386
+ dependencies: plugin.dependencies,
6387
+ enforce: plugin.enforce,
6388
+ hooks: plugin.hooks,
6389
+ options: (_a2 = plugin.options) != null ? _a2 : {
6390
+ output: { path: "." },
6391
+ exclude: [],
6392
+ override: []
6270
6393
  }
6271
- __privateWrapper(this, _size)._++;
6394
+ };
6395
+ if ("apply" in plugin && typeof plugin.apply === "function") normalized.apply = plugin.apply;
6396
+ return normalized;
6397
+ }, registerAdapter_fn = async function(adapter) {
6398
+ const source = inputToAdapterSource(this.config);
6399
+ __privateGet$1(this, _studio).source = source;
6400
+ if (adapter.stream) {
6401
+ this.inputNode = await adapter.stream(source);
6402
+ await this.hooks.emit("kubb:debug", {
6403
+ date: /* @__PURE__ */ new Date(),
6404
+ logs: [`\u2713 Adapter '${adapter.name}' producing input stream`]
6405
+ });
6406
+ } else {
6407
+ const inputNode = await adapter.parse(source);
6408
+ this.inputNode = createStreamInput(arrayToAsyncIterable(inputNode.schemas), arrayToAsyncIterable(inputNode.operations), inputNode.meta);
6409
+ await this.hooks.emit("kubb:debug", {
6410
+ date: /* @__PURE__ */ new Date(),
6411
+ logs: [
6412
+ `\u2713 Adapter '${adapter.name}' resolved InputNode (wrapped as stream)`,
6413
+ ` \u2022 Schemas: ${inputNode.schemas.length}`,
6414
+ ` \u2022 Operations: ${inputNode.operations.length}`
6415
+ ]
6416
+ });
6272
6417
  }
6273
- dequeue() {
6274
- const current = __privateGet(this, _head);
6275
- if (!current) return;
6276
- __privateSet(this, _head, __privateGet(this, _head).next);
6277
- __privateWrapper(this, _size)._--;
6278
- if (!__privateGet(this, _head)) __privateSet(this, _tail, void 0);
6279
- return current.value;
6418
+ }, registerMiddleware_fn = function(event, middlewareHooks) {
6419
+ const handler = middlewareHooks[event];
6420
+ if (!handler) return;
6421
+ this.hooks.on(event, handler);
6422
+ __privateGet$1(this, _middlewareListeners).push([event, handler]);
6423
+ }, /**
6424
+ * Registers a hook-style plugin's lifecycle handlers on the shared `AsyncEventEmitter`.
6425
+ *
6426
+ * For `kubb:plugin:setup`, the registered listener wraps the globally emitted context with a
6427
+ * plugin-specific one so that `addGenerator`, `setResolver`, `setTransformer`, and
6428
+ * `setRenderer` all target the correct `normalizedPlugin` entry in the plugins map.
6429
+ *
6430
+ * All other hooks are iterated and registered directly as pass-through listeners.
6431
+ * Any event key present in the global `KubbHooks` interface can be subscribed to.
6432
+ *
6433
+ * External tooling can subscribe to any of these events via `hooks.on(...)` to observe
6434
+ * the plugin lifecycle without modifying plugin behavior.
6435
+ *
6436
+ * @internal
6437
+ */
6438
+ registerPlugin_fn = function(plugin) {
6439
+ const { hooks } = plugin;
6440
+ if (!hooks) return;
6441
+ if (hooks["kubb:plugin:setup"]) {
6442
+ const setupHandler = (globalCtx) => {
6443
+ var _a2;
6444
+ const pluginCtx = {
6445
+ ...globalCtx,
6446
+ options: (_a2 = plugin.options) != null ? _a2 : {},
6447
+ addGenerator: (gen) => {
6448
+ this.registerGenerator(plugin.name, gen);
6449
+ },
6450
+ setResolver: (resolver) => {
6451
+ this.setPluginResolver(plugin.name, resolver);
6452
+ },
6453
+ setTransformer: (visitor) => {
6454
+ plugin.transformer = visitor;
6455
+ },
6456
+ setRenderer: (renderer) => {
6457
+ plugin.renderer = renderer;
6458
+ },
6459
+ setOptions: (opts) => {
6460
+ plugin.options = {
6461
+ ...plugin.options,
6462
+ ...opts
6463
+ };
6464
+ },
6465
+ injectFile: (userFileNode) => {
6466
+ this.fileManager.add(createFile(userFileNode));
6467
+ }
6468
+ };
6469
+ return hooks["kubb:plugin:setup"](pluginCtx);
6470
+ };
6471
+ this.hooks.on("kubb:plugin:setup", setupHandler);
6472
+ __privateMethod$1(this, _KubbDriver_instances, trackHookListener_fn).call(this, "kubb:plugin:setup", setupHandler);
6280
6473
  }
6281
- peek() {
6282
- if (!__privateGet(this, _head)) return;
6283
- return __privateGet(this, _head).value;
6474
+ for (const [event, handler] of Object.entries(hooks)) {
6475
+ if (event === "kubb:plugin:setup" || !handler) continue;
6476
+ this.hooks.on(event, handler);
6477
+ __privateMethod$1(this, _KubbDriver_instances, trackHookListener_fn).call(this, event, handler);
6284
6478
  }
6285
- clear() {
6286
- __privateSet(this, _head, void 0);
6287
- __privateSet(this, _tail, void 0);
6288
- __privateSet(this, _size, 0);
6289
- }
6290
- get size() {
6291
- return __privateGet(this, _size);
6292
- }
6293
- *[Symbol.iterator]() {
6294
- let current = __privateGet(this, _head);
6295
- while (current) {
6296
- yield current.value;
6297
- current = current.next;
6298
- }
6299
- }
6300
- *drain() {
6301
- while (__privateGet(this, _head)) yield this.dequeue();
6302
- }
6303
- }, _head = new WeakMap(), _tail = new WeakMap(), _size = new WeakMap(), _d);
6304
- function pLimit(concurrency) {
6305
- let rejectOnClear = false;
6306
- if (typeof concurrency === "object") ({ concurrency, rejectOnClear = false } = concurrency);
6307
- validateConcurrency(concurrency);
6308
- if (typeof rejectOnClear !== "boolean") throw new TypeError("Expected `rejectOnClear` to be a boolean");
6309
- const queue = new Queue();
6310
- let activeCount = 0;
6311
- const resumeNext = () => {
6312
- if (activeCount < concurrency && queue.size > 0) {
6313
- activeCount++;
6314
- queue.dequeue().run();
6315
- }
6479
+ }, filesPayload_fn = function() {
6480
+ const driver = this;
6481
+ return {
6482
+ get files() {
6483
+ return driver.fileManager.files;
6484
+ },
6485
+ upsertFile: (...files) => driver.fileManager.upsert(...files)
6316
6486
  };
6317
- const next = () => {
6318
- activeCount--;
6319
- resumeNext();
6487
+ }, emitPluginEnd_fn = function({ plugin, duration, success, error }) {
6488
+ return this.hooks.emit("kubb:plugin:end", Object.assign({
6489
+ plugin,
6490
+ duration,
6491
+ success,
6492
+ ...error ? { error } : {},
6493
+ config: this.config
6494
+ }, __privateMethod$1(this, _KubbDriver_instances, filesPayload_fn).call(this)));
6495
+ }, runGenerators_fn = async function(entries, flushPending) {
6496
+ var _a2, _b2;
6497
+ const timings = /* @__PURE__ */ new Map();
6498
+ const failed = /* @__PURE__ */ new Set();
6499
+ const driver = this;
6500
+ const { schemas, operations } = this.inputNode;
6501
+ const states = entries.map(({ plugin, context, hrStart }) => {
6502
+ var _a3;
6503
+ const { exclude, include, override } = plugin.options;
6504
+ const hasExclude = Array.isArray(exclude) && exclude.length > 0;
6505
+ const hasInclude = Array.isArray(include) && include.length > 0;
6506
+ const hasOverride = Array.isArray(override) && override.length > 0;
6507
+ return {
6508
+ plugin,
6509
+ generatorContext: {
6510
+ ...context,
6511
+ resolver: this.getResolver(plugin.name)
6512
+ },
6513
+ generators: (_a3 = plugin.generators) != null ? _a3 : [],
6514
+ hrStart,
6515
+ failed: false,
6516
+ error: null,
6517
+ optionsAreStatic: !hasExclude && !hasInclude && !hasOverride,
6518
+ allowedSchemaNames: null
6519
+ };
6520
+ });
6521
+ const emitsSchemaHook = this.hooks.listenerCount("kubb:generate:schema") > 0;
6522
+ const emitsOperationHook = this.hooks.listenerCount("kubb:generate:operation") > 0;
6523
+ const pruningStates = states.filter(({ plugin }) => {
6524
+ var _a3, _b3;
6525
+ const { include } = plugin.options;
6526
+ return ((_a3 = include == null ? void 0 : include.some(({ type }) => OPERATION_FILTER_TYPES.has(type))) != null ? _a3 : false) && !((_b3 = include == null ? void 0 : include.some(({ type }) => type === "schemaName")) != null ? _b3 : false);
6527
+ });
6528
+ if (pruningStates.length > 0) {
6529
+ const allSchemas = [];
6530
+ for await (const schema of schemas) allSchemas.push(schema);
6531
+ const includedOpsByState = new Map(pruningStates.map((s) => [s, []]));
6532
+ for await (const operation of operations) for (const state of pruningStates) {
6533
+ const { exclude, include, override } = state.plugin.options;
6534
+ if (state.generatorContext.resolver.resolveOptions(operation, {
6535
+ options: state.plugin.options,
6536
+ exclude,
6537
+ include,
6538
+ override
6539
+ }) !== null) (_a2 = includedOpsByState.get(state)) == null ? void 0 : _a2.push(operation);
6540
+ }
6541
+ for (const state of pruningStates) {
6542
+ state.allowedSchemaNames = collectUsedSchemaNames((_b2 = includedOpsByState.get(state)) != null ? _b2 : [], allSchemas);
6543
+ includedOpsByState.delete(state);
6544
+ }
6545
+ }
6546
+ const resolveRendererFor = (gen, state) => {
6547
+ var _a3, _b3;
6548
+ return gen.renderer === null ? void 0 : (_b3 = (_a3 = gen.renderer) != null ? _a3 : state.plugin.renderer) != null ? _b3 : state.generatorContext.config.renderer;
6320
6549
  };
6321
- const run = async (function_, resolve2, arguments_) => {
6322
- const result = (async () => function_(...arguments_))();
6323
- resolve2(result);
6550
+ const dispatchNode = async (state, node, dispatch) => {
6551
+ if (state.failed) return;
6324
6552
  try {
6325
- await result;
6326
- } catch {
6553
+ const { plugin, generatorContext, generators } = state;
6554
+ const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node;
6555
+ if (dispatch.checkAllowedNames && state.allowedSchemaNames !== null && "name" in transformedNode && transformedNode.name && !state.allowedSchemaNames.has(transformedNode.name)) return;
6556
+ const { exclude, include, override } = plugin.options;
6557
+ const options = state.optionsAreStatic ? plugin.options : generatorContext.resolver.resolveOptions(transformedNode, {
6558
+ options: plugin.options,
6559
+ exclude,
6560
+ include,
6561
+ override
6562
+ });
6563
+ if (options === null) return;
6564
+ const ctx = {
6565
+ ...generatorContext,
6566
+ options
6567
+ };
6568
+ for (const gen of generators) {
6569
+ const generate = gen[dispatch.method];
6570
+ if (!generate) continue;
6571
+ const raw = generate(transformedNode, ctx);
6572
+ const applied = applyHookResult({
6573
+ result: isPromise(raw) ? await raw : raw,
6574
+ driver,
6575
+ rendererFactory: resolveRendererFor(gen, state)
6576
+ });
6577
+ if (isPromise(applied)) await applied;
6578
+ }
6579
+ if (dispatch.emit) await dispatch.emit(transformedNode, ctx);
6580
+ } catch (caughtError) {
6581
+ state.failed = true;
6582
+ state.error = caughtError;
6327
6583
  }
6328
- next();
6329
6584
  };
6330
- const enqueue = (function_, resolve2, reject, arguments_) => {
6331
- const queueItem = { reject };
6332
- new Promise((internalResolve) => {
6333
- queueItem.run = internalResolve;
6334
- queue.enqueue(queueItem);
6335
- }).then(run.bind(void 0, function_, resolve2, arguments_));
6336
- if (activeCount < concurrency) resumeNext();
6585
+ const schemaDispatch = {
6586
+ method: "schema",
6587
+ checkAllowedNames: true,
6588
+ emit: emitsSchemaHook ? (node, ctx) => this.hooks.emit("kubb:generate:schema", node, ctx) : null
6589
+ };
6590
+ const operationDispatch = {
6591
+ method: "operation",
6592
+ checkAllowedNames: false,
6593
+ emit: emitsOperationHook ? (node, ctx) => this.hooks.emit("kubb:generate:operation", node, ctx) : null
6337
6594
  };
6338
- const generator = (function_, ...arguments_) => new Promise((resolve2, reject) => {
6339
- enqueue(function_, resolve2, reject, arguments_);
6595
+ const needsCollectedOperations = this.hooks.listenerCount("kubb:generate:operations") > 0 || states.some((s) => s.generators.some((g) => !!g.operations));
6596
+ const collectedOperations = needsCollectedOperations ? [] : void 0;
6597
+ await forBatches(schemas, (nodes) => Promise.all(nodes.flatMap((n) => states.map((state) => dispatchNode(state, n, schemaDispatch)))), {
6598
+ concurrency: 8,
6599
+ flush: flushPending
6340
6600
  });
6341
- Object.defineProperties(generator, {
6342
- activeCount: { get: () => activeCount },
6343
- pendingCount: { get: () => queue.size },
6344
- clearQueue: { value() {
6345
- if (!rejectOnClear) {
6346
- queue.clear();
6347
- return;
6348
- }
6349
- const abortError = AbortSignal.abort().reason;
6350
- while (queue.size > 0) queue.dequeue().reject(abortError);
6351
- } },
6352
- concurrency: {
6353
- get: () => concurrency,
6354
- set(newConcurrency) {
6355
- validateConcurrency(newConcurrency);
6356
- concurrency = newConcurrency;
6357
- queueMicrotask(() => {
6358
- while (activeCount < concurrency && queue.size > 0) resumeNext();
6601
+ await forBatches(operations, (nodes) => {
6602
+ if (needsCollectedOperations) collectedOperations.push(...nodes);
6603
+ return Promise.all(nodes.flatMap((n) => states.map((state) => dispatchNode(state, n, operationDispatch))));
6604
+ }, {
6605
+ concurrency: 8,
6606
+ flush: flushPending
6607
+ });
6608
+ for (const state of states) {
6609
+ if (!state.failed && needsCollectedOperations) try {
6610
+ const { plugin, generatorContext, generators } = state;
6611
+ const ctx = {
6612
+ ...generatorContext,
6613
+ options: plugin.options
6614
+ };
6615
+ const pluginOperations = state.optionsAreStatic ? collectedOperations : collectedOperations.filter((node) => {
6616
+ const transformed = plugin.transformer ? transform(node, plugin.transformer) : node;
6617
+ const { exclude, include, override } = plugin.options;
6618
+ return generatorContext.resolver.resolveOptions(transformed, {
6619
+ options: plugin.options,
6620
+ exclude,
6621
+ include,
6622
+ override
6623
+ }) !== null;
6624
+ });
6625
+ for (const gen of generators) {
6626
+ if (!gen.operations) continue;
6627
+ await applyHookResult({
6628
+ result: await gen.operations(pluginOperations, ctx),
6629
+ driver,
6630
+ rendererFactory: resolveRendererFor(gen, state)
6359
6631
  });
6360
6632
  }
6361
- },
6362
- map: { async value(iterable, function_) {
6363
- const promises = Array.from(iterable, (value, index) => this(function_, value, index));
6364
- return Promise.all(promises);
6365
- } }
6633
+ await this.hooks.emit("kubb:generate:operations", pluginOperations, ctx);
6634
+ } catch (caughtError) {
6635
+ state.failed = true;
6636
+ state.error = caughtError;
6637
+ }
6638
+ const duration = getElapsedMs(state.hrStart);
6639
+ timings.set(state.plugin.name, duration);
6640
+ await __privateMethod$1(this, _KubbDriver_instances, emitPluginEnd_fn).call(this, {
6641
+ plugin: state.plugin,
6642
+ duration,
6643
+ success: !state.failed,
6644
+ error: state.failed && state.error ? state.error : void 0
6645
+ });
6646
+ if (state.failed && state.error) failed.add({
6647
+ plugin: state.plugin,
6648
+ error: state.error
6649
+ });
6650
+ await this.hooks.emit("kubb:debug", {
6651
+ date: /* @__PURE__ */ new Date(),
6652
+ logs: [state.failed ? "\u2717 Plugin start failed" : `\u2713 Plugin started successfully (${formatMs(duration)})`]
6653
+ });
6654
+ }
6655
+ return {
6656
+ timings,
6657
+ failed
6658
+ };
6659
+ }, trackHookListener_fn = function(event, handler) {
6660
+ let handlers = __privateGet$1(this, _hookListeners).get(event);
6661
+ if (!handlers) {
6662
+ handlers = /* @__PURE__ */ new Set();
6663
+ __privateGet$1(this, _hookListeners).set(event, handlers);
6664
+ }
6665
+ handlers.add(handler);
6666
+ }, _getDefaultResolver = new WeakMap(), _d);
6667
+ function applyHookResult({ result, driver, rendererFactory }) {
6668
+ if (!result) return;
6669
+ if (Array.isArray(result)) {
6670
+ driver.fileManager.upsert(...result);
6671
+ return;
6672
+ }
6673
+ if (!rendererFactory) return;
6674
+ const renderer = rendererFactory();
6675
+ if (renderer.stream) try {
6676
+ var _usingCtx$1 = _usingCtx();
6677
+ const r = _usingCtx$1.u(renderer);
6678
+ for (const file of r.stream(result)) driver.fileManager.upsert(file);
6679
+ return;
6680
+ } catch (_) {
6681
+ _usingCtx$1.e = _;
6682
+ } finally {
6683
+ _usingCtx$1.d();
6684
+ }
6685
+ return applyAsyncRender({
6686
+ renderer,
6687
+ result,
6688
+ driver
6366
6689
  });
6367
- return generator;
6368
6690
  }
6369
- function validateConcurrency(concurrency) {
6370
- if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) throw new TypeError("Expected `concurrency` to be a number from 1 and up");
6691
+ async function applyAsyncRender({ renderer, result, driver }) {
6692
+ try {
6693
+ var _usingCtx3 = _usingCtx();
6694
+ const r = _usingCtx3.u(renderer);
6695
+ await r.render(result);
6696
+ driver.fileManager.upsert(...r.files);
6697
+ } catch (_) {
6698
+ _usingCtx3.e = _;
6699
+ } finally {
6700
+ _usingCtx3.d();
6701
+ }
6371
6702
  }
6372
- function joinSources(file) {
6373
- return file.sources.map((item) => extractStringsFromNodes(item.nodes)).filter(Boolean).join("\n\n");
6703
+ function inputToAdapterSource(config) {
6704
+ const input = config.input;
6705
+ if (!input) throw new Error("[kubb] input is required when using an adapter. Provide input.path or input.data in your config.");
6706
+ if ("data" in input) return {
6707
+ type: "data",
6708
+ data: input.data
6709
+ };
6710
+ if (new URLPath(input.path).isURL) return {
6711
+ type: "path",
6712
+ path: input.path
6713
+ };
6714
+ return {
6715
+ type: "path",
6716
+ path: resolve(config.root, input.path)
6717
+ };
6374
6718
  }
6375
- var FileProcessor = (_e = class {
6376
- constructor() {
6377
- __privateAdd(this, _limit, pLimit(100));
6719
+
6720
+ var __defProp = Object.defineProperty;
6721
+ var __typeError = (msg) => {
6722
+ throw TypeError(msg);
6723
+ };
6724
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6725
+ var __publicField = (obj, key, value) => __defNormalProp(obj, key + "" , value);
6726
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
6727
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
6728
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
6729
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
6730
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
6731
+ var _userConfig, _config, _driver, _storage, _Kubb_instances, configLogs_fn, _a;
6732
+ async function exists(path) {
6733
+ if (typeof Bun !== "undefined") return Bun.file(path).exists();
6734
+ return access(path).then(() => true, () => false);
6735
+ }
6736
+ async function write(path, data, options = {}) {
6737
+ const trimmed = data.trim();
6738
+ if (trimmed === "") return null;
6739
+ const resolved = resolve(path);
6740
+ if (typeof Bun !== "undefined") {
6741
+ const file = Bun.file(resolved);
6742
+ if ((await file.exists() ? await file.text() : null) === trimmed) return null;
6743
+ await Bun.write(resolved, trimmed);
6744
+ return trimmed;
6378
6745
  }
6379
- async parse(file, { parsers, extension } = {}) {
6380
- const parseExtName = (extension == null ? void 0 : extension[file.extname]) || void 0;
6381
- if (!parsers || !file.extname) return joinSources(file);
6382
- const parser = parsers.get(file.extname);
6383
- if (!parser) return joinSources(file);
6384
- return parser.parse(file, { extname: parseExtName });
6746
+ try {
6747
+ if (await readFile$1(resolved, { encoding: "utf-8" }) === trimmed) return null;
6748
+ } catch {
6385
6749
  }
6386
- async run(files, { parsers, mode = "sequential", extension, onStart, onEnd, onUpdate } = {}) {
6387
- await (onStart == null ? void 0 : onStart(files));
6388
- const total = files.length;
6389
- let processed = 0;
6390
- const processOne = async (file) => {
6391
- const source = await this.parse(file, {
6392
- extension,
6393
- parsers
6394
- });
6395
- const currentProcessed = ++processed;
6396
- const percentage = currentProcessed / total * 100;
6397
- await (onUpdate == null ? void 0 : onUpdate({
6398
- file,
6399
- source,
6400
- processed: currentProcessed,
6401
- percentage,
6402
- total
6403
- }));
6404
- };
6405
- if (mode === "sequential") for (const file of files) await processOne(file);
6406
- else await Promise.all(files.map((file) => __privateGet(this, _limit).call(this, () => processOne(file))));
6407
- await (onEnd == null ? void 0 : onEnd(files));
6408
- return files;
6750
+ await mkdir(dirname(resolved), { recursive: true });
6751
+ await writeFile$1(resolved, trimmed, { encoding: "utf-8" });
6752
+ if (options.sanity) {
6753
+ const savedData = await readFile$1(resolved, { encoding: "utf-8" });
6754
+ if (savedData !== trimmed) throw new Error(`Sanity check failed for ${path}
6755
+
6756
+ Data[${data.length}]:
6757
+ ${data}
6758
+
6759
+ Saved[${savedData.length}]:
6760
+ ${savedData}
6761
+ `);
6762
+ return savedData;
6409
6763
  }
6410
- }, _limit = new WeakMap(), _e);
6411
- function createStorage(build2) {
6412
- return (options) => build2(options != null ? options : {});
6764
+ return trimmed;
6765
+ }
6766
+ async function clean(path) {
6767
+ return rm(path, {
6768
+ recursive: true,
6769
+ force: true
6770
+ });
6413
6771
  }
6414
- function isMissingPathError(error) {
6415
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
6772
+ var version$1 = "5.0.0-beta.31";
6773
+ function createStorage(build) {
6774
+ return (options) => build(options != null ? options : {});
6416
6775
  }
6417
6776
  const fsStorage = createStorage(() => ({
6418
6777
  name: "fs",
@@ -6420,17 +6779,15 @@ const fsStorage = createStorage(() => ({
6420
6779
  try {
6421
6780
  await access(resolve(key));
6422
6781
  return true;
6423
- } catch (error) {
6424
- if (isMissingPathError(error)) return false;
6425
- throw new Error(`Failed to access storage item "${key}"`, { cause: error });
6782
+ } catch (_error) {
6783
+ return false;
6426
6784
  }
6427
6785
  },
6428
6786
  async getItem(key) {
6429
6787
  try {
6430
6788
  return await readFile$1(resolve(key), "utf8");
6431
- } catch (error) {
6432
- if (isMissingPathError(error)) return null;
6433
- throw new Error(`Failed to read storage item "${key}"`, { cause: error });
6789
+ } catch (_error) {
6790
+ return null;
6434
6791
  }
6435
6792
  },
6436
6793
  async setItem(key, value) {
@@ -6440,23 +6797,22 @@ const fsStorage = createStorage(() => ({
6440
6797
  await rm(resolve(key), { force: true });
6441
6798
  },
6442
6799
  async getKeys(base) {
6443
- const keys = [];
6444
6800
  const resolvedBase = resolve(base != null ? base : process.cwd());
6445
- async function walk2(dir, prefix) {
6801
+ async function* walk(dir, prefix) {
6446
6802
  let entries;
6447
6803
  try {
6448
6804
  entries = await readdir$1(dir, { withFileTypes: true });
6449
- } catch (error) {
6450
- if (isMissingPathError(error)) return;
6451
- throw new Error(`Failed to list storage keys under "${resolvedBase}"`, { cause: error });
6805
+ } catch (_error) {
6806
+ return;
6452
6807
  }
6453
6808
  for (const entry of entries) {
6454
6809
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
6455
- if (entry.isDirectory()) await walk2(join(dir, entry.name), rel);
6456
- else keys.push(rel);
6810
+ if (entry.isDirectory()) yield* walk(join(dir, entry.name), rel);
6811
+ else yield rel;
6457
6812
  }
6458
6813
  }
6459
- await walk2(resolvedBase, "");
6814
+ const keys = [];
6815
+ for await (const key of walk(resolvedBase, "")) keys.push(key);
6460
6816
  return keys;
6461
6817
  },
6462
6818
  async clear(base) {
@@ -6464,410 +6820,192 @@ const fsStorage = createStorage(() => ({
6464
6820
  await clean(resolve(base));
6465
6821
  }
6466
6822
  }));
6467
- var version$1 = "5.0.0-beta.3";
6468
- function getDiagnosticInfo() {
6469
- return {
6470
- nodeVersion: version$2,
6471
- KubbVersion: version$1,
6472
- platform: process.platform,
6473
- arch: process.arch,
6474
- cwd: process.cwd()
6475
- };
6476
- }
6477
- function isInputPath(config) {
6478
- return typeof (config == null ? void 0 : config.input) === "object" && config.input !== null && "path" in config.input;
6479
- }
6480
- async function setup(userConfig, options = {}) {
6481
- var _a2, _b2, _c2, _d2, _e2, _f, _g, _h, _i;
6482
- const hooks = (_a2 = options.hooks) != null ? _a2 : new AsyncEventEmitter();
6483
- const sources = /* @__PURE__ */ new Map();
6484
- const diagnosticInfo = getDiagnosticInfo();
6485
- if (Array.isArray(userConfig.input)) await hooks.emit("kubb:warn", { message: "This feature is still under development \u2014 use with caution" });
6486
- await hooks.emit("kubb:debug", {
6487
- date: /* @__PURE__ */ new Date(),
6488
- logs: [
6489
- "Configuration:",
6490
- ` \u2022 Name: ${userConfig.name || "unnamed"}`,
6491
- ` \u2022 Root: ${userConfig.root || process.cwd()}`,
6492
- ` \u2022 Output: ${((_b2 = userConfig.output) == null ? void 0 : _b2.path) || "not specified"}`,
6493
- ` \u2022 Plugins: ${((_c2 = userConfig.plugins) == null ? void 0 : _c2.length) || 0}`,
6494
- "Output Settings:",
6495
- ` \u2022 Storage: ${userConfig.storage ? `custom(${userConfig.storage.name})` : ((_d2 = userConfig.output) == null ? void 0 : _d2.write) === false ? "disabled" : "filesystem (default)"}`,
6496
- ` \u2022 Formatter: ${((_e2 = userConfig.output) == null ? void 0 : _e2.format) || "none"}`,
6497
- ` \u2022 Linter: ${((_f = userConfig.output) == null ? void 0 : _f.lint) || "none"}`,
6498
- "Environment:",
6499
- Object.entries(diagnosticInfo).map(([key, value]) => ` \u2022 ${key}: ${value}`).join("\n")
6500
- ]
6501
- });
6502
- try {
6503
- if (isInputPath(userConfig) && !new URLPath(userConfig.input.path).isURL) {
6504
- await exists(userConfig.input.path);
6505
- await hooks.emit("kubb:debug", {
6506
- date: /* @__PURE__ */ new Date(),
6507
- logs: [`\u2713 Input file validated: ${userConfig.input.path}`]
6508
- });
6509
- }
6510
- } catch (caughtError) {
6511
- if (isInputPath(userConfig)) {
6512
- const error = caughtError;
6513
- throw new Error(`Cannot read file/URL defined in \`input.path\` or set with \`kubb generate PATH\` in the CLI of your Kubb config ${userConfig.input.path}`, { cause: error });
6823
+ function createSourcesView(storage) {
6824
+ const paths = /* @__PURE__ */ new Set();
6825
+ return createStorage(() => ({
6826
+ name: `${storage.name}:sources`,
6827
+ async hasItem(key) {
6828
+ return paths.has(key) && await storage.hasItem(key);
6829
+ },
6830
+ async getItem(key) {
6831
+ return paths.has(key) ? storage.getItem(key) : null;
6832
+ },
6833
+ async setItem(key, value) {
6834
+ paths.add(key);
6835
+ await storage.setItem(key, value);
6836
+ },
6837
+ async removeItem(key) {
6838
+ paths.delete(key);
6839
+ await storage.removeItem(key);
6840
+ },
6841
+ async getKeys(base) {
6842
+ if (!base) return [...paths];
6843
+ const result = [];
6844
+ for (const key of paths) if (key.startsWith(base)) result.push(key);
6845
+ return result;
6846
+ },
6847
+ async clear() {
6848
+ paths.clear();
6849
+ await storage.clear();
6514
6850
  }
6515
- }
6516
- if (!userConfig.adapter) throw new Error("Adapter should be defined");
6517
- const config = {
6851
+ }))();
6852
+ }
6853
+ function resolveConfig(userConfig) {
6854
+ var _a2, _b, _c;
6855
+ return {
6518
6856
  ...userConfig,
6519
6857
  root: userConfig.root || process.cwd(),
6520
- parsers: (_g = userConfig.parsers) != null ? _g : [],
6521
- adapter: userConfig.adapter,
6858
+ parsers: (_a2 = userConfig.parsers) != null ? _a2 : [],
6522
6859
  output: {
6523
6860
  format: false,
6524
6861
  lint: false,
6525
- write: true,
6526
6862
  extension: DEFAULT_EXTENSION,
6527
6863
  defaultBanner: DEFAULT_BANNER,
6528
6864
  ...userConfig.output
6529
6865
  },
6866
+ storage: (_b = userConfig.storage) != null ? _b : fsStorage(),
6530
6867
  devtools: userConfig.devtools ? {
6531
6868
  studioUrl: DEFAULT_STUDIO_URL,
6532
6869
  ...typeof userConfig.devtools === "boolean" ? {} : userConfig.devtools
6533
6870
  } : void 0,
6534
- plugins: userConfig.plugins
6871
+ plugins: (_c = userConfig.plugins) != null ? _c : []
6535
6872
  };
6536
- const storage = config.output.write === false ? null : (_h = config.storage) != null ? _h : fsStorage();
6537
- if (config.output.clean) {
6538
- await hooks.emit("kubb:debug", {
6539
- date: /* @__PURE__ */ new Date(),
6540
- logs: ["Cleaning output directories", ` \u2022 Output: ${config.output.path}`]
6541
- });
6542
- await (storage == null ? void 0 : storage.clear(resolve(config.root, config.output.path)));
6543
- }
6544
- const driver = new PluginDriver(config, { hooks });
6545
- function registerMiddlewareHook(event, middlewareHooks) {
6546
- const handler = middlewareHooks[event];
6547
- if (handler) hooks.on(event, handler);
6548
- }
6549
- for (const middleware of (_i = config.middleware) != null ? _i : []) for (const event of Object.keys(middleware.hooks)) registerMiddlewareHook(event, middleware.hooks);
6550
- const adapter = config.adapter;
6551
- if (!adapter) throw new Error("No adapter configured. Please provide an adapter in your kubb.config.ts.");
6552
- const source = inputToAdapterSource(config);
6553
- await hooks.emit("kubb:debug", {
6554
- date: /* @__PURE__ */ new Date(),
6555
- logs: [`Running adapter: ${adapter.name}`]
6556
- });
6557
- driver.adapter = adapter;
6558
- driver.inputNode = await adapter.parse(source);
6559
- await hooks.emit("kubb:debug", {
6560
- date: /* @__PURE__ */ new Date(),
6561
- logs: [
6562
- `\u2713 Adapter '${adapter.name}' resolved InputNode`,
6563
- ` \u2022 Schemas: ${driver.inputNode.schemas.length}`,
6564
- ` \u2022 Operations: ${driver.inputNode.operations.length}`
6565
- ]
6566
- });
6873
+ }
6874
+ function getDiagnosticInfo() {
6567
6875
  return {
6568
- config,
6569
- hooks,
6570
- driver,
6571
- sources,
6572
- storage
6876
+ nodeVersion: version$2,
6877
+ KubbVersion: version$1,
6878
+ platform: process.platform,
6879
+ arch: process.arch,
6880
+ cwd: process.cwd()
6573
6881
  };
6574
6882
  }
6575
- async function runPluginAstHooks(plugin, context) {
6576
- var _a2, _b2, _c2;
6577
- const { adapter, inputNode, resolver, driver } = context;
6578
- const { exclude, include, override } = plugin.options;
6579
- if (!adapter || !inputNode) throw new Error(`[${plugin.name}] No adapter found. Add an OAS adapter (e.g. pluginOas()) before this plugin in your Kubb config.`);
6580
- function resolveRenderer(gen) {
6581
- var _a3, _b3;
6582
- return gen.renderer === null ? void 0 : (_b3 = (_a3 = gen.renderer) != null ? _a3 : plugin.renderer) != null ? _b3 : context.config.renderer;
6883
+ function isInputPath(config) {
6884
+ return typeof (config == null ? void 0 : config.input) === "object" && config.input !== null && "path" in config.input;
6885
+ }
6886
+ var Kubb = (_a = class {
6887
+ constructor(userConfig, options = {}) {
6888
+ __privateAdd(this, _Kubb_instances);
6889
+ __publicField(this, "hooks");
6890
+ __privateAdd(this, _userConfig);
6891
+ __privateAdd(this, _config, null);
6892
+ __privateAdd(this, _driver, null);
6893
+ __privateAdd(this, _storage, null);
6894
+ var _a2;
6895
+ __privateSet(this, _userConfig, userConfig);
6896
+ this.hooks = (_a2 = options.hooks) != null ? _a2 : new AsyncEventEmitter();
6583
6897
  }
6584
- const generators = (_a2 = plugin.generators) != null ? _a2 : [];
6585
- const collectedOperations = [];
6586
- const generatorContext = {
6587
- ...context,
6588
- resolver: driver.getResolver(plugin.name)
6589
- };
6590
- const operationFilterTypes = /* @__PURE__ */ new Set([
6591
- "tag",
6592
- "operationId",
6593
- "path",
6594
- "method",
6595
- "contentType"
6596
- ]);
6597
- const hasOperationBasedIncludes = (_b2 = include == null ? void 0 : include.some(({ type }) => operationFilterTypes.has(type))) != null ? _b2 : false;
6598
- const hasSchemaNameIncludes = (_c2 = include == null ? void 0 : include.some(({ type }) => type === "schemaName")) != null ? _c2 : false;
6599
- let allowedSchemaNames;
6600
- if (hasOperationBasedIncludes && !hasSchemaNameIncludes) allowedSchemaNames = collectUsedSchemaNames(inputNode.operations.filter((op) => resolver.resolveOptions(op, {
6601
- options: plugin.options,
6602
- exclude,
6603
- include,
6604
- override
6605
- }) !== null), inputNode.schemas);
6606
- await walk(inputNode, {
6607
- depth: "shallow",
6608
- async schema(node) {
6609
- const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node;
6610
- if (allowedSchemaNames !== void 0 && transformedNode.name && !allowedSchemaNames.has(transformedNode.name)) return;
6611
- const options = resolver.resolveOptions(transformedNode, {
6612
- options: plugin.options,
6613
- exclude,
6614
- include,
6615
- override
6616
- });
6617
- if (options === null) return;
6618
- const ctx = {
6619
- ...generatorContext,
6620
- options
6621
- };
6622
- for (const gen of generators) {
6623
- if (!gen.schema) continue;
6624
- await applyHookResult(await gen.schema(transformedNode, ctx), driver, resolveRenderer(gen));
6625
- }
6626
- await driver.hooks.emit("kubb:generate:schema", transformedNode, ctx);
6627
- },
6628
- async operation(node) {
6629
- const transformedNode = plugin.transformer ? transform(node, plugin.transformer) : node;
6630
- const options = resolver.resolveOptions(transformedNode, {
6631
- options: plugin.options,
6632
- exclude,
6633
- include,
6634
- override
6898
+ get storage() {
6899
+ if (!__privateGet(this, _storage)) throw new Error("[kubb] setup() must be called before accessing storage");
6900
+ return __privateGet(this, _storage);
6901
+ }
6902
+ get driver() {
6903
+ if (!__privateGet(this, _driver)) throw new Error("[kubb] setup() must be called before accessing driver");
6904
+ return __privateGet(this, _driver);
6905
+ }
6906
+ get config() {
6907
+ if (!__privateGet(this, _config)) throw new Error("[kubb] setup() must be called before accessing config");
6908
+ return __privateGet(this, _config);
6909
+ }
6910
+ /**
6911
+ * Resolves config and initializes the driver. `build()` calls this automatically.
6912
+ */
6913
+ async setup() {
6914
+ const config = resolveConfig(__privateGet(this, _userConfig));
6915
+ const driver = new KubbDriver(config, { hooks: this.hooks });
6916
+ const storage = createSourcesView(config.storage);
6917
+ await this.hooks.emit("kubb:debug", {
6918
+ date: /* @__PURE__ */ new Date(),
6919
+ logs: __privateMethod(this, _Kubb_instances, configLogs_fn).call(this, config)
6920
+ });
6921
+ if (isInputPath(__privateGet(this, _userConfig)) && !new URLPath(__privateGet(this, _userConfig).input.path).isURL) try {
6922
+ await exists(__privateGet(this, _userConfig).input.path);
6923
+ await this.hooks.emit("kubb:debug", {
6924
+ date: /* @__PURE__ */ new Date(),
6925
+ logs: [`\u2713 Input file validated: ${__privateGet(this, _userConfig).input.path}`]
6635
6926
  });
6636
- if (options !== null) {
6637
- collectedOperations.push(transformedNode);
6638
- const ctx = {
6639
- ...generatorContext,
6640
- options
6641
- };
6642
- for (const gen of generators) {
6643
- if (!gen.operation) continue;
6644
- await applyHookResult(await gen.operation(transformedNode, ctx), driver, resolveRenderer(gen));
6645
- }
6646
- await driver.hooks.emit("kubb:generate:operation", transformedNode, ctx);
6647
- }
6927
+ } catch (caughtError) {
6928
+ throw new Error(`Cannot read file/URL defined in \`input.path\` or set with \`kubb generate PATH\` in the CLI of your Kubb config ${__privateGet(this, _userConfig).input.path}`, { cause: caughtError });
6648
6929
  }
6649
- });
6650
- if (collectedOperations.length > 0) {
6651
- const ctx = {
6652
- ...generatorContext,
6653
- options: plugin.options
6654
- };
6655
- for (const gen of generators) {
6656
- if (!gen.operations) continue;
6657
- await applyHookResult(await gen.operations(collectedOperations, ctx), driver, resolveRenderer(gen));
6930
+ if (config.output.clean) {
6931
+ await this.hooks.emit("kubb:debug", {
6932
+ date: /* @__PURE__ */ new Date(),
6933
+ logs: ["Cleaning output directories", ` \u2022 Output: ${config.output.path}`]
6934
+ });
6935
+ await config.storage.clear(resolve(config.root, config.output.path));
6658
6936
  }
6659
- await driver.hooks.emit("kubb:generate:operations", collectedOperations, ctx);
6937
+ await driver.setup();
6938
+ __privateSet(this, _config, config);
6939
+ __privateSet(this, _driver, driver);
6940
+ __privateSet(this, _storage, storage);
6660
6941
  }
6661
- }
6662
- async function safeBuild(setupResult) {
6663
- var _a2;
6664
- const { driver, hooks, sources, storage } = setupResult;
6665
- const failedPlugins = /* @__PURE__ */ new Set();
6666
- const pluginTimings = /* @__PURE__ */ new Map();
6667
- const config = driver.config;
6668
- try {
6669
- await driver.emitSetupHooks();
6670
- if (driver.adapter && driver.inputNode) await hooks.emit("kubb:build:start", {
6671
- config,
6672
- adapter: driver.adapter,
6673
- inputNode: driver.inputNode,
6674
- getPlugin: driver.getPlugin.bind(driver),
6675
- get files() {
6676
- return driver.fileManager.files;
6677
- },
6678
- upsertFile: (...files2) => driver.fileManager.upsert(...files2)
6679
- });
6680
- for (const plugin of driver.plugins.values()) {
6681
- const context = driver.getContext(plugin);
6682
- const hrStart = process.hrtime();
6683
- try {
6684
- const timestamp = /* @__PURE__ */ new Date();
6685
- await hooks.emit("kubb:plugin:start", { plugin });
6686
- await hooks.emit("kubb:debug", {
6687
- date: timestamp,
6688
- logs: ["Starting plugin...", ` \u2022 Plugin Name: ${plugin.name}`]
6689
- });
6690
- if (((_a2 = plugin.generators) == null ? void 0 : _a2.length) || driver.hasRegisteredGenerators(plugin.name)) await runPluginAstHooks(plugin, context);
6691
- const duration = getElapsedMs(hrStart);
6692
- pluginTimings.set(plugin.name, duration);
6693
- await hooks.emit("kubb:plugin:end", {
6694
- plugin,
6695
- duration,
6696
- success: true,
6697
- config,
6698
- get files() {
6699
- return driver.fileManager.files;
6700
- },
6701
- upsertFile: (...files2) => driver.fileManager.upsert(...files2)
6702
- });
6703
- await hooks.emit("kubb:debug", {
6704
- date: /* @__PURE__ */ new Date(),
6705
- logs: [`\u2713 Plugin started successfully (${formatMs(duration)})`]
6706
- });
6707
- } catch (caughtError) {
6708
- const error = caughtError;
6709
- const errorTimestamp = /* @__PURE__ */ new Date();
6710
- const duration = getElapsedMs(hrStart);
6711
- await hooks.emit("kubb:plugin:end", {
6712
- plugin,
6713
- duration,
6714
- success: false,
6715
- error,
6716
- config,
6717
- get files() {
6718
- return driver.fileManager.files;
6719
- },
6720
- upsertFile: (...files2) => driver.fileManager.upsert(...files2)
6721
- });
6722
- await hooks.emit("kubb:debug", {
6723
- date: errorTimestamp,
6724
- logs: [
6725
- "\u2717 Plugin start failed",
6726
- ` \u2022 Plugin Name: ${plugin.name}`,
6727
- ` \u2022 Error: ${error.constructor.name} - ${error.message}`,
6728
- " \u2022 Stack Trace:",
6729
- error.stack || "No stack trace available"
6730
- ]
6731
- });
6732
- failedPlugins.add({
6733
- plugin,
6734
- error
6735
- });
6736
- }
6942
+ /**
6943
+ * Runs the full pipeline and throws on any plugin error.
6944
+ * Automatically calls `setup()` if needed.
6945
+ */
6946
+ async build() {
6947
+ const out = await this.safeBuild();
6948
+ if (out.error) throw out.error;
6949
+ if (out.failedPlugins.size > 0) {
6950
+ const errors = [...out.failedPlugins].map(({ error }) => error);
6951
+ throw new BuildError(`Build Error with ${out.failedPlugins.size} failed plugins`, { errors });
6737
6952
  }
6738
- await hooks.emit("kubb:plugins:end", {
6739
- config,
6740
- get files() {
6741
- return driver.fileManager.files;
6742
- },
6743
- upsertFile: (...files2) => driver.fileManager.upsert(...files2)
6744
- });
6745
- const files = driver.fileManager.files;
6746
- const parsersMap = /* @__PURE__ */ new Map();
6747
- for (const parser of config.parsers) if (parser.extNames) for (const extname of parser.extNames) parsersMap.set(extname, parser);
6748
- const fileProcessor = new FileProcessor();
6749
- await hooks.emit("kubb:debug", {
6750
- date: /* @__PURE__ */ new Date(),
6751
- logs: [`Writing ${files.length} files...`]
6752
- });
6753
- await fileProcessor.run(files, {
6754
- parsers: parsersMap,
6755
- extension: config.output.extension,
6756
- onStart: async (processingFiles) => {
6757
- await hooks.emit("kubb:files:processing:start", { files: processingFiles });
6758
- },
6759
- onUpdate: async ({ file, source, processed, total, percentage }) => {
6760
- await hooks.emit("kubb:file:processing:update", {
6761
- file,
6762
- source,
6763
- processed,
6764
- total,
6765
- percentage,
6766
- config
6767
- });
6768
- if (source) {
6769
- await (storage == null ? void 0 : storage.setItem(file.path, source));
6770
- sources.set(file.path, source);
6771
- }
6772
- },
6773
- onEnd: async (processedFiles) => {
6774
- await hooks.emit("kubb:files:processing:end", { files: processedFiles });
6775
- await hooks.emit("kubb:debug", {
6776
- date: /* @__PURE__ */ new Date(),
6777
- logs: [`\u2713 File write process completed for ${processedFiles.length} files`]
6778
- });
6779
- }
6780
- });
6781
- await hooks.emit("kubb:build:end", {
6782
- files,
6783
- config,
6784
- outputDir: resolve(config.root, config.output.path)
6785
- });
6786
- return {
6787
- failedPlugins,
6788
- files,
6789
- driver,
6790
- pluginTimings,
6791
- sources
6792
- };
6793
- } catch (error) {
6794
- return {
6795
- failedPlugins,
6796
- files: [],
6797
- driver,
6798
- pluginTimings,
6799
- error,
6800
- sources
6801
- };
6802
- } finally {
6803
- driver.dispose();
6953
+ return out;
6804
6954
  }
6805
- }
6806
- async function build(setupResult) {
6807
- const { files, driver, failedPlugins, pluginTimings, error, sources } = await safeBuild(setupResult);
6808
- if (error) throw error;
6809
- if (failedPlugins.size > 0) {
6810
- const errors = [...failedPlugins].map(({ error: error2 }) => error2);
6811
- throw new BuildError(`Build Error with ${failedPlugins.size} failed plugins`, { errors });
6955
+ /**
6956
+ * Runs the full pipeline and captures errors in `BuildOutput` instead of throwing.
6957
+ * Automatically calls `setup()` if needed.
6958
+ */
6959
+ async safeBuild() {
6960
+ try {
6961
+ var _usingCtx$1 = _usingCtx();
6962
+ if (!__privateGet(this, _driver)) await this.setup();
6963
+ const cleanup = _usingCtx$1.u(this);
6964
+ const driver = cleanup.driver;
6965
+ const storage = cleanup.storage;
6966
+ const { failedPlugins, pluginTimings, error } = await driver.run({ storage });
6967
+ return {
6968
+ failedPlugins,
6969
+ files: driver.fileManager.files,
6970
+ driver,
6971
+ pluginTimings,
6972
+ storage,
6973
+ ...error ? { error } : {}
6974
+ };
6975
+ } catch (_) {
6976
+ _usingCtx$1.e = _;
6977
+ } finally {
6978
+ _usingCtx$1.d();
6979
+ }
6812
6980
  }
6813
- return {
6814
- failedPlugins,
6815
- files,
6816
- driver,
6817
- pluginTimings,
6818
- error: void 0,
6819
- sources
6820
- };
6821
- }
6822
- function inputToAdapterSource(config) {
6823
- if (Array.isArray(config.input)) return {
6824
- type: "paths",
6825
- paths: config.input.map((i) => new URLPath(i.path).isURL ? i.path : resolve(config.root, i.path))
6826
- };
6827
- if ("data" in config.input) return {
6828
- type: "data",
6829
- data: config.input.data
6830
- };
6831
- if (new URLPath(config.input.path).isURL) return {
6832
- type: "path",
6833
- path: config.input.path
6834
- };
6835
- return {
6836
- type: "path",
6837
- path: resolve(config.root, config.input.path)
6838
- };
6839
- }
6981
+ dispose() {
6982
+ var _a2;
6983
+ (_a2 = __privateGet(this, _driver)) == null ? void 0 : _a2.dispose();
6984
+ }
6985
+ [Symbol.dispose]() {
6986
+ this.dispose();
6987
+ }
6988
+ }, _userConfig = new WeakMap(), _config = new WeakMap(), _driver = new WeakMap(), _storage = new WeakMap(), _Kubb_instances = new WeakSet(), configLogs_fn = function(config) {
6989
+ var _a2, _b, _c, _d, _e;
6990
+ const u = __privateGet(this, _userConfig);
6991
+ const diag = getDiagnosticInfo();
6992
+ return [
6993
+ "Configuration:",
6994
+ ` \u2022 Name: ${u.name || "unnamed"}`,
6995
+ ` \u2022 Root: ${u.root || process.cwd()}`,
6996
+ ` \u2022 Output: ${((_a2 = u.output) == null ? void 0 : _a2.path) || "not specified"}`,
6997
+ ` \u2022 Plugins: ${((_b = u.plugins) == null ? void 0 : _b.length) || 0}`,
6998
+ "Output Settings:",
6999
+ ` \u2022 Storage: ${config.storage.name}`,
7000
+ ` \u2022 Formatter: ${((_c = u.output) == null ? void 0 : _c.format) || "none"}`,
7001
+ ` \u2022 Linter: ${((_d = u.output) == null ? void 0 : _d.lint) || "none"}`,
7002
+ `Running adapter: ${((_e = config.adapter) == null ? void 0 : _e.name) || "none"}`,
7003
+ "Environment:",
7004
+ Object.entries(diag).map(([key, value]) => ` \u2022 ${key}: ${value}`).join("\n")
7005
+ ];
7006
+ }, _a);
6840
7007
  function createKubb(userConfig, options = {}) {
6841
- var _a2;
6842
- const hooks = (_a2 = options.hooks) != null ? _a2 : new AsyncEventEmitter();
6843
- let setupResult;
6844
- const instance = {
6845
- get hooks() {
6846
- return hooks;
6847
- },
6848
- get sources() {
6849
- var _a3;
6850
- return (_a3 = setupResult == null ? void 0 : setupResult.sources) != null ? _a3 : /* @__PURE__ */ new Map();
6851
- },
6852
- get driver() {
6853
- return setupResult == null ? void 0 : setupResult.driver;
6854
- },
6855
- get config() {
6856
- return setupResult == null ? void 0 : setupResult.config;
6857
- },
6858
- async setup() {
6859
- setupResult = await setup(userConfig, { hooks });
6860
- },
6861
- async build() {
6862
- if (!setupResult) await instance.setup();
6863
- return build(setupResult);
6864
- },
6865
- async safeBuild() {
6866
- if (!setupResult) await instance.setup();
6867
- return safeBuild(setupResult);
6868
- }
6869
- };
6870
- return instance;
7008
+ return new Kubb(userConfig, options);
6871
7009
  }
6872
7010
  const memoryStorage = createStorage(() => {
6873
7011
  const store = /* @__PURE__ */ new Map();
@@ -6900,7 +7038,7 @@ const memoryStorage = createStorage(() => {
6900
7038
  };
6901
7039
  });
6902
7040
 
6903
- var version = "5.0.0-beta.3";
7041
+ var version = "5.0.0-beta.31";
6904
7042
 
6905
7043
  function isCommandMessage(msg) {
6906
7044
  return msg.type === "command";
@@ -6911,9 +7049,6 @@ function isPongMessage(msg) {
6911
7049
  function isDisconnectMessage(msg) {
6912
7050
  return msg.type === "disconnect";
6913
7051
  }
6914
- function isPublishCommandMessage(msg) {
6915
- return msg.type === "command" && msg.command === "publish";
6916
- }
6917
7052
 
6918
7053
  function getStorage() {
6919
7054
  return useStorage("kubb");
@@ -6957,7 +7092,7 @@ async function generate({ config, hooks }) {
6957
7092
  const kubb = createKubb(config, { hooks });
6958
7093
  await kubb.setup();
6959
7094
  await hooks.emit("kubb:info", { message: config.name ? `Build generation ${config.name}` : "Build generation" });
6960
- const { files, failedPlugins, error } = await kubb.safeBuild();
7095
+ const { failedPlugins, error } = await kubb.safeBuild();
6961
7096
  await hooks.emit("kubb:info", { message: "Load summary" });
6962
7097
  const hasFailures = failedPlugins.size > 0 || error;
6963
7098
  if (hasFailures) {
@@ -6968,11 +7103,11 @@ async function generate({ config, hooks }) {
6968
7103
  allErrors.forEach((err) => {
6969
7104
  hooks.emit("kubb:error", { error: err });
6970
7105
  });
6971
- await hooks.emit("kubb:generation:end", { config, files, sources: kubb.sources });
7106
+ await hooks.emit("kubb:generation:end", { config, storage: kubb.storage });
6972
7107
  throw new Error("Generation failed");
6973
7108
  }
6974
7109
  await hooks.emit("kubb:success", { message: "Generation successfully" });
6975
- await hooks.emit("kubb:generation:end", { config, files, sources: kubb.sources });
7110
+ await hooks.emit("kubb:generation:end", { config, storage: kubb.storage });
6976
7111
  if (config.output.format) {
6977
7112
  await hooks.emit("kubb:format:start");
6978
7113
  let formatter = config.output.format;
@@ -7047,20 +7182,15 @@ async function generate({ config, hooks }) {
7047
7182
  }
7048
7183
  }
7049
7184
 
7050
- const unrunInputOptions = {
7051
- transform: {
7052
- jsx: {
7053
- runtime: "automatic",
7054
- importSource: "@kubb/renderer-jsx"
7055
- }
7056
- }
7057
- };
7185
+ const jiti = createJiti(globalThis._importMeta_.url, {
7186
+ jsx: {
7187
+ runtime: "automatic",
7188
+ importSource: "@kubb/renderer-jsx"
7189
+ },
7190
+ moduleCache: false
7191
+ });
7058
7192
  const tsLoader = async (configFile) => {
7059
- const { module } = await unrun({
7060
- path: configFile,
7061
- inputOptions: unrunInputOptions
7062
- });
7063
- return module;
7193
+ return jiti.import(configFile, { default: true });
7064
7194
  };
7065
7195
  async function getCosmiConfig(configPath) {
7066
7196
  var _a;
@@ -7121,6 +7251,21 @@ async function resolvePlugins(plugins) {
7121
7251
  })
7122
7252
  );
7123
7253
  }
7254
+ async function resolveMiddlewares(middlewares) {
7255
+ return Promise.all(
7256
+ middlewares.map(async ({ name, options }) => {
7257
+ const factory = await loadPluginFactory(name);
7258
+ return factory(options != null ? options : {});
7259
+ })
7260
+ );
7261
+ }
7262
+ async function checkPeerDependencies() {
7263
+ try {
7264
+ await import('@kubb/renderer-jsx');
7265
+ } catch {
7266
+ logger.warn("Missing peer dependency @kubb/renderer-jsx. Install it alongside kubb plugins.");
7267
+ }
7268
+ }
7124
7269
 
7125
7270
  async function mergePlugins(diskPlugins, studioPlugins) {
7126
7271
  if (!diskPlugins && !studioPlugins) return void 0;
@@ -7149,44 +7294,6 @@ async function mergePlugins(diskPlugins, studioPlugins) {
7149
7294
  return [...mergedDisk, ...studioOnly];
7150
7295
  }
7151
7296
 
7152
- async function publish({ command, outputPath, root, hooks }) {
7153
- var _a, _b, _c, _d;
7154
- const resolvedOutputPath = path$1.isAbsolute(outputPath) ? outputPath : path$1.resolve(root, outputPath);
7155
- const [cmd, ...args] = tokenize(command);
7156
- if (!cmd) {
7157
- throw new Error(`[plugin-publish] Invalid publish command: "${command}"`);
7158
- }
7159
- const commandWithArgs = args.length ? `${cmd} ${args.join(" ")}` : cmd;
7160
- await hooks.emit("kubb:info", { message: `[publish] Running "${commandWithArgs}" in "${resolvedOutputPath}"` });
7161
- const startTime = Date.now();
7162
- let exitCode = null;
7163
- try {
7164
- const proc = x(cmd, args, {
7165
- nodeOptions: { cwd: resolvedOutputPath }
7166
- });
7167
- for await (const line of proc) {
7168
- if (line.trim()) {
7169
- await hooks.emit("kubb:info", { message: line.trim() });
7170
- }
7171
- }
7172
- const result = await proc;
7173
- exitCode = (_a = result.exitCode) != null ? _a : null;
7174
- } catch (err) {
7175
- const message = (_d = (_c = (_b = err == null ? void 0 : err.stderr) == null ? void 0 : _b.trim()) != null ? _c : err == null ? void 0 : err.message) != null ? _d : String(err);
7176
- const error = new Error(`[publish] Failed to run "${commandWithArgs}": ${message}`);
7177
- error.cause = err;
7178
- await hooks.emit("kubb:error", { error });
7179
- throw error;
7180
- }
7181
- if (exitCode !== 0) {
7182
- const error = new Error(`[publish] "${commandWithArgs}" exited with code ${exitCode}`);
7183
- await hooks.emit("kubb:error", { error });
7184
- throw error;
7185
- }
7186
- const duration = Date.now() - startTime;
7187
- await hooks.emit("kubb:success", { message: `[publish] Published successfully in ${duration}ms` });
7188
- }
7189
-
7190
7297
  function setupHookListener(hooks, root) {
7191
7298
  hooks.on("kubb:hook:start", async (ctx) => {
7192
7299
  const { id, command, args } = ctx;
@@ -7222,7 +7329,7 @@ function setupHookListener(hooks, root) {
7222
7329
  }
7223
7330
 
7224
7331
  const agentDefaults = {
7225
- studioUrl: "https://studio.kubb.dev",
7332
+ studioUrl: "https://kubb.studio",
7226
7333
  configPath: "kubb.config.ts",
7227
7334
  retryIntervalMs: 3e4,
7228
7335
  heartbeatIntervalMs: 3e4,
@@ -7257,24 +7364,38 @@ function sendAgentMessage(ws, message) {
7257
7364
  throw new Error("Failed to send message to Kubb Studio", { cause: error });
7258
7365
  }
7259
7366
  }
7260
- function setupEventsStream(ws, hooks, getSource) {
7367
+ function setupEventsStream(ws, hooks) {
7261
7368
  function sendDataMessage(payload) {
7262
7369
  sendAgentMessage(ws, {
7263
7370
  type: "data",
7264
- payload: { ...payload, source: getSource == null ? void 0 : getSource() }
7371
+ payload
7265
7372
  });
7266
7373
  }
7267
7374
  hooks.on("kubb:plugin:start", (ctx) => {
7268
7375
  sendDataMessage({
7269
7376
  type: "kubb:plugin:start",
7270
- data: [ctx.plugin],
7377
+ data: [{ plugin: ctx.plugin }],
7271
7378
  timestamp: Date.now()
7272
7379
  });
7273
7380
  });
7274
7381
  hooks.on("kubb:plugin:end", (ctx) => {
7275
7382
  sendDataMessage({
7276
7383
  type: "kubb:plugin:end",
7277
- data: [ctx.plugin, { duration: ctx.duration, success: ctx.success }],
7384
+ data: [{ plugin: ctx.plugin, duration: ctx.duration, success: ctx.success }],
7385
+ timestamp: Date.now()
7386
+ });
7387
+ });
7388
+ hooks.on("kubb:build:start", ({ config, adapter }) => {
7389
+ sendDataMessage({
7390
+ type: "kubb:build:start",
7391
+ data: [{ config: { name: config.name }, adapter: { name: adapter.name } }],
7392
+ timestamp: Date.now()
7393
+ });
7394
+ });
7395
+ hooks.on("kubb:build:end", ({ files, outputDir }) => {
7396
+ sendDataMessage({
7397
+ type: "kubb:build:end",
7398
+ data: [{ files: files.map((file) => ({ path: file.path, name: file.name })), outputDir }],
7278
7399
  timestamp: Date.now()
7279
7400
  });
7280
7401
  });
@@ -7285,15 +7406,17 @@ function setupEventsStream(ws, hooks, getSource) {
7285
7406
  timestamp: Date.now()
7286
7407
  });
7287
7408
  });
7288
- hooks.on("kubb:file:processing:update", (ctx) => {
7409
+ hooks.on("kubb:files:processing:update", ({ files }) => {
7289
7410
  sendDataMessage({
7290
- type: "kubb:file:processing:update",
7411
+ type: "kubb:files:processing:update",
7291
7412
  data: [
7292
7413
  {
7293
- file: ctx.file.path,
7294
- processed: ctx.processed,
7295
- total: ctx.total,
7296
- percentage: ctx.percentage
7414
+ files: files.map((ctx) => ({
7415
+ file: ctx.file.path,
7416
+ processed: ctx.processed,
7417
+ total: ctx.total,
7418
+ percentage: ctx.percentage
7419
+ }))
7297
7420
  }
7298
7421
  ],
7299
7422
  timestamp: Date.now()
@@ -7309,21 +7432,21 @@ function setupEventsStream(ws, hooks, getSource) {
7309
7432
  hooks.on("kubb:info", ({ message, info }) => {
7310
7433
  sendDataMessage({
7311
7434
  type: "kubb:info",
7312
- data: [message, info],
7435
+ data: [{ message, info }],
7313
7436
  timestamp: Date.now()
7314
7437
  });
7315
7438
  });
7316
7439
  hooks.on("kubb:success", ({ message, info }) => {
7317
7440
  sendDataMessage({
7318
7441
  type: "kubb:success",
7319
- data: [message, info],
7442
+ data: [{ message, info }],
7320
7443
  timestamp: Date.now()
7321
7444
  });
7322
7445
  });
7323
7446
  hooks.on("kubb:warn", ({ message, info }) => {
7324
7447
  sendDataMessage({
7325
7448
  type: "kubb:warn",
7326
- data: [message, info],
7449
+ data: [{ message, info }],
7327
7450
  timestamp: Date.now()
7328
7451
  });
7329
7452
  });
@@ -7339,14 +7462,17 @@ function setupEventsStream(ws, hooks, getSource) {
7339
7462
  timestamp: Date.now()
7340
7463
  });
7341
7464
  });
7342
- hooks.on("kubb:generation:end", ({ config, files, sources }) => {
7465
+ hooks.on("kubb:generation:end", async ({ config, storage }) => {
7343
7466
  const sourcesRecord = {};
7344
- sources.forEach((value, key) => {
7345
- sourcesRecord[key] = value;
7346
- });
7467
+ for (const key of await storage.getKeys()) {
7468
+ const value = await storage.getItem(key);
7469
+ if (value !== null) {
7470
+ sourcesRecord[key] = value;
7471
+ }
7472
+ }
7347
7473
  sendDataMessage({
7348
7474
  type: "kubb:generation:end",
7349
- data: [config, files, sourcesRecord],
7475
+ data: [{ config, storage: sourcesRecord }],
7350
7476
  timestamp: Date.now()
7351
7477
  });
7352
7478
  });
@@ -7362,6 +7488,33 @@ function setupEventsStream(ws, hooks, getSource) {
7362
7488
  timestamp: Date.now()
7363
7489
  });
7364
7490
  });
7491
+ hooks.on("kubb:generation:summary", ({ failedPlugins, status, hrStart, filesCreated }) => {
7492
+ const [seconds, nanoseconds] = process.hrtime(hrStart);
7493
+ const duration = Math.round(seconds * 1e3 + nanoseconds / 1e6);
7494
+ sendDataMessage({
7495
+ type: "kubb:generation:summary",
7496
+ data: [{ duration, fileCount: filesCreated, failedPlugins: failedPlugins.size, status }],
7497
+ timestamp: Date.now()
7498
+ });
7499
+ });
7500
+ hooks.on("kubb:lifecycle:start", () => {
7501
+ sendDataMessage({ type: "kubb:lifecycle:start", data: [], timestamp: Date.now() });
7502
+ });
7503
+ hooks.on("kubb:lifecycle:end", () => {
7504
+ sendDataMessage({ type: "kubb:lifecycle:end", data: [], timestamp: Date.now() });
7505
+ });
7506
+ hooks.on("kubb:format:start", () => {
7507
+ sendDataMessage({ type: "kubb:format:start", data: [], timestamp: Date.now() });
7508
+ });
7509
+ hooks.on("kubb:format:end", () => {
7510
+ sendDataMessage({ type: "kubb:format:end", data: [], timestamp: Date.now() });
7511
+ });
7512
+ hooks.on("kubb:lint:start", () => {
7513
+ sendDataMessage({ type: "kubb:lint:start", data: [], timestamp: Date.now() });
7514
+ });
7515
+ hooks.on("kubb:lint:end", () => {
7516
+ sendDataMessage({ type: "kubb:lint:end", data: [], timestamp: Date.now() });
7517
+ });
7365
7518
  }
7366
7519
 
7367
7520
  async function connectToStudio(options) {
@@ -7373,7 +7526,6 @@ async function connectToStudio(options) {
7373
7526
  resolvedConfigPath,
7374
7527
  allowAll,
7375
7528
  allowWrite,
7376
- allowPublish,
7377
7529
  root,
7378
7530
  retryInterval,
7379
7531
  heartbeatInterval = 3e4,
@@ -7381,7 +7533,6 @@ async function connectToStudio(options) {
7381
7533
  nitro
7382
7534
  } = options;
7383
7535
  const hooks = new AsyncEventEmitter();
7384
- let currentSource;
7385
7536
  async function reconnect() {
7386
7537
  logger.info(`Retrying connection in ${formatMs$1(retryInterval)} to Kubb Studio ...`);
7387
7538
  setTimeout(() => connectToStudio({ ...options, initialSession: void 0 }), retryInterval);
@@ -7396,7 +7547,6 @@ async function connectToStudio(options) {
7396
7547
  const maskedSessionId = maskString(sessionId);
7397
7548
  const effectiveAllowAll = isSandbox ? false : allowAll;
7398
7549
  const effectiveWrite = isSandbox ? false : allowWrite;
7399
- const effectivePublish = isSandbox ? false : allowPublish;
7400
7550
  let serverDisconnected = false;
7401
7551
  let heartbeatTimer;
7402
7552
  async function cleanup(reason = "cleanup") {
@@ -7408,6 +7558,7 @@ async function connectToStudio(options) {
7408
7558
  ws.removeEventListener("open", onOpen);
7409
7559
  ws.removeEventListener("close", onClose);
7410
7560
  ws.removeEventListener("error", onError);
7561
+ ws.removeEventListener("message", onMessage);
7411
7562
  } catch (_error) {
7412
7563
  }
7413
7564
  }
@@ -7440,9 +7591,9 @@ async function connectToStudio(options) {
7440
7591
  });
7441
7592
  });
7442
7593
  heartbeatTimer = setInterval(() => sendAgentMessage(ws, { type: "ping" }), heartbeatInterval);
7443
- setupEventsStream(ws, hooks, () => currentSource);
7444
- ws.addEventListener("message", async (message) => {
7445
- var _a2, _b, _c, _d, _e, _f;
7594
+ setupEventsStream(ws, hooks);
7595
+ const onMessage = async (message) => {
7596
+ var _a2, _b, _c, _d;
7446
7597
  try {
7447
7598
  const data = JSON.parse(message.data);
7448
7599
  logger.info(`[${maskedSessionId}] Received "${data.type}" from Studio`);
@@ -7464,11 +7615,11 @@ async function connectToStudio(options) {
7464
7615
  }
7465
7616
  if (isCommandMessage(data)) {
7466
7617
  if (data.command === "generate") {
7467
- currentSource = "generate";
7468
7618
  const config = await loadConfig(resolvedConfigPath);
7469
7619
  const storedConfig = data.payload ? null : await getLatestStudioConfigFromStorage({ sessionId }).catch(() => null);
7470
7620
  const patch = (_b = (_a2 = data.payload) != null ? _a2 : storedConfig) != null ? _b : void 0;
7471
7621
  const plugins = await mergePlugins(config.plugins, patch == null ? void 0 : patch.plugins);
7622
+ const middleware = (patch == null ? void 0 : patch.middleware) ? await resolveMiddlewares(patch.middleware) : config.middleware;
7472
7623
  const inputOverride = isSandbox ? { data: (_c = patch == null ? void 0 : patch.input) != null ? _c : "" } : void 0;
7473
7624
  if (allowWrite && isSandbox) {
7474
7625
  logger.warn(`[${maskedSessionId}] Agent is running in a sandbox environment, write will be disabled`);
@@ -7484,6 +7635,9 @@ async function connectToStudio(options) {
7484
7635
  logger.warn(`[${maskedSessionId}] Failed to save studio config: ${err == null ? void 0 : err.message}`);
7485
7636
  });
7486
7637
  }
7638
+ const generationHooks = new AsyncEventEmitter();
7639
+ setupHookListener(generationHooks, root);
7640
+ setupEventsStream(ws, generationHooks);
7487
7641
  await generate({
7488
7642
  config: {
7489
7643
  ...config,
@@ -7493,12 +7647,15 @@ async function connectToStudio(options) {
7493
7647
  output: {
7494
7648
  ...config.output
7495
7649
  },
7496
- plugins
7650
+ plugins,
7651
+ middleware,
7652
+ // Studio may send an opaque adapter options blob; forward it unchanged to createKubb.
7653
+ // The adapter factory is responsible for validating and merging its own options.
7654
+ ...(patch == null ? void 0 : patch.adapter) != null && { adapter: patch.adapter }
7497
7655
  },
7498
- hooks
7656
+ hooks: generationHooks
7499
7657
  });
7500
7658
  logger.success(`[${maskedSessionId}] Completed "${data.type}" from Studio`);
7501
- currentSource = void 0;
7502
7659
  return;
7503
7660
  }
7504
7661
  if (data.command === "connect") {
@@ -7510,8 +7667,7 @@ async function connectToStudio(options) {
7510
7667
  configPath,
7511
7668
  permissions: {
7512
7669
  allowAll: effectiveAllowAll,
7513
- allowWrite: effectiveWrite,
7514
- allowPublish: effectivePublish
7670
+ allowWrite: effectiveWrite
7515
7671
  },
7516
7672
  config: {
7517
7673
  plugins: config.plugins.map((plugin) => ({
@@ -7524,30 +7680,13 @@ async function connectToStudio(options) {
7524
7680
  logger.success(`[${maskedSessionId}] Completed "${data.type}" from Studio`);
7525
7681
  return;
7526
7682
  }
7527
- if (isPublishCommandMessage(data)) {
7528
- if (!effectivePublish) {
7529
- logger.warn(`[${maskedSessionId}] Publish command rejected \u2014 KUBB_AGENT_ALLOW_PUBLISH is not enabled`);
7530
- return;
7531
- }
7532
- currentSource = "publish";
7533
- const config = await loadConfig(resolvedConfigPath);
7534
- const resolvedCommand = (_e = (_d = data.payload.command) != null ? _d : process.env.KUBB_AGENT_PUBLISH_COMMAND) != null ? _e : "npm publish";
7535
- await publish({
7536
- command: resolvedCommand,
7537
- outputPath: config.output.path,
7538
- root,
7539
- hooks
7540
- });
7541
- logger.success(`[${maskedSessionId}] Completed "${data.command}" from Studio`);
7542
- currentSource = void 0;
7543
- return;
7544
- }
7545
7683
  }
7546
7684
  logger.warn(`[${maskedSessionId}] Unknown message type from Kubb Studio: ${message.data}`);
7547
7685
  } catch (error) {
7548
- logger.error(`[${maskedSessionId}] [unhandledRejection] ${(_f = error == null ? void 0 : error.message) != null ? _f : error}`);
7686
+ logger.error(`[${maskedSessionId}] [unhandledRejection] ${(_d = error == null ? void 0 : error.message) != null ? _d : error}`);
7549
7687
  }
7550
- });
7688
+ };
7689
+ ws.addEventListener("message", onMessage);
7551
7690
  } catch (error) {
7552
7691
  throw new Error(`[unhandledRejection] ${(_a = error == null ? void 0 : error.message) != null ? _a : error}`, {
7553
7692
  cause: error
@@ -7577,7 +7716,6 @@ function resolveStudioRuntimeConfig(env = process$1.env, cwd = process$1.cwd())
7577
7716
  root,
7578
7717
  allowAll,
7579
7718
  allowWrite: allowAll || parseBooleanEnv(env.KUBB_AGENT_ALLOW_WRITE),
7580
- allowPublish: allowAll || parseBooleanEnv(env.KUBB_AGENT_ALLOW_PUBLISH),
7581
7719
  poolSize: parsePositiveIntegerEnv(env.KUBB_AGENT_POOL_SIZE, agentDefaults.poolSize),
7582
7720
  hasSecret: Boolean(env.KUBB_AGENT_SECRET)
7583
7721
  };
@@ -7587,7 +7725,7 @@ function getErrorMessage(error) {
7587
7725
  return error instanceof Error ? error.message : String(error);
7588
7726
  }
7589
7727
  const _zcw7I4pYH8OiCfaDcjy_x7I6IH1tLDQR3W_yRZgP6E = defineNitroPlugin(async (nitro) => {
7590
- const { studioUrl, token, configPath, resolvedConfigPath, retryInterval, heartbeatInterval, root, allowAll, allowWrite, allowPublish, poolSize, hasSecret } = resolveStudioRuntimeConfig(process$1.env);
7728
+ const { studioUrl, token, configPath, resolvedConfigPath, retryInterval, heartbeatInterval, root, allowAll, allowWrite, poolSize, hasSecret } = resolveStudioRuntimeConfig(process$1.env);
7591
7729
  if (!token) {
7592
7730
  logger.warn("KUBB_AGENT_TOKEN not set", "cannot authenticate with studio");
7593
7731
  return null;
@@ -7597,6 +7735,7 @@ const _zcw7I4pYH8OiCfaDcjy_x7I6IH1tLDQR3W_yRZgP6E = defineNitroPlugin(async (nit
7597
7735
  }
7598
7736
  const maskedToken = maskString(token);
7599
7737
  try {
7738
+ await checkPeerDependencies();
7600
7739
  await registerAgent({ token, studioUrl, poolSize });
7601
7740
  const baseOptions = {
7602
7741
  token,
@@ -7605,7 +7744,6 @@ const _zcw7I4pYH8OiCfaDcjy_x7I6IH1tLDQR3W_yRZgP6E = defineNitroPlugin(async (nit
7605
7744
  resolvedConfigPath,
7606
7745
  allowAll,
7607
7746
  allowWrite,
7608
- allowPublish,
7609
7747
  root,
7610
7748
  retryInterval,
7611
7749
  heartbeatInterval,