@ahoo-wang/fetcher-generator 2.5.2 → 2.5.3

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 (38) hide show
  1. package/dist/aggregate/aggregateResolver.d.ts.map +1 -1
  2. package/dist/aggregate/index.d.ts +1 -1
  3. package/dist/aggregate/utils.d.ts +1 -1
  4. package/dist/aggregate/utils.d.ts.map +1 -1
  5. package/dist/cli.cjs +1 -1
  6. package/dist/cli.cjs.map +1 -1
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +25 -26
  9. package/dist/cli.js.map +1 -1
  10. package/dist/client/apiClientGenerator.d.ts.map +1 -1
  11. package/dist/client/commandClientGenerator.d.ts +1 -1
  12. package/dist/client/commandClientGenerator.d.ts.map +1 -1
  13. package/dist/client/index.d.ts +1 -1
  14. package/dist/client/index.d.ts.map +1 -1
  15. package/dist/client/queryClientGenerator.d.ts +1 -1
  16. package/dist/client/queryClientGenerator.d.ts.map +1 -1
  17. package/dist/generateContext.d.ts +2 -2
  18. package/dist/generateContext.d.ts.map +1 -1
  19. package/dist/index.cjs +8 -8
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +670 -670
  23. package/dist/index.js.map +1 -1
  24. package/dist/model/modelGenerator.d.ts +1 -1
  25. package/dist/model/modelGenerator.d.ts.map +1 -1
  26. package/dist/model/modelInfo.d.ts +1 -1
  27. package/dist/model/modelInfo.d.ts.map +1 -1
  28. package/dist/types.d.ts +1 -2
  29. package/dist/types.d.ts.map +1 -1
  30. package/dist/utils/clis.d.ts +1 -0
  31. package/dist/utils/clis.d.ts.map +1 -1
  32. package/dist/utils/index.d.ts +1 -1
  33. package/dist/utils/index.d.ts.map +1 -1
  34. package/dist/utils/parsers.d.ts.map +1 -1
  35. package/dist/utils/responses.d.ts +1 -1
  36. package/dist/utils/responses.d.ts.map +1 -1
  37. package/dist/utils/sourceFiles.d.ts.map +1 -1
  38. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1,40 +1,9 @@
1
+ import { Scope as ae, VariableDeclarationKind as v, Project as ce } from "ts-morph";
1
2
  import { ContentTypeValues as S, combineURLs as w } from "@ahoo-wang/fetcher";
2
- import { VariableDeclarationKind as v, Scope as ae } from "ts-morph";
3
3
  import { ResourceAttributionPathSpec as j } from "@ahoo-wang/fetcher-wow";
4
4
  import { parse as B } from "yaml";
5
- import { readFile as ce } from "fs";
6
- import { join as ge, relative as le } from "path";
7
- function pe(r) {
8
- const e = r.split(".");
9
- return e.length != 2 || e[0].length === 0 || e[1].length === 0 ? null : e;
10
- }
11
- function ue(r) {
12
- const e = pe(r.name);
13
- return e ? {
14
- tag: r,
15
- contextAlias: e[0],
16
- aggregateName: e[1]
17
- } : null;
18
- }
19
- function me(r) {
20
- const e = r?.map((n) => ue(n)).filter((n) => n !== null);
21
- if (!e)
22
- return /* @__PURE__ */ new Map();
23
- const t = /* @__PURE__ */ new Map();
24
- return e.forEach((n) => {
25
- t.set(n.tag.name, {
26
- aggregate: n,
27
- commands: /* @__PURE__ */ new Map(),
28
- events: /* @__PURE__ */ new Map()
29
- });
30
- }), t;
31
- }
32
- function de(r) {
33
- if (!r)
34
- return null;
35
- const e = r.split(".");
36
- return e.length != 3 ? null : e[2];
37
- }
5
+ import { readFile as ge } from "fs";
6
+ import { join as le, relative as pe } from "path";
38
7
  function $(r) {
39
8
  return r.$ref.split("/").pop();
40
9
  }
@@ -56,11 +25,11 @@ function T(r, e) {
56
25
  schema: R(r, e)
57
26
  };
58
27
  }
59
- const G = /[-_\s.]+/;
28
+ const F = /[-_\s.]+/;
60
29
  function L(r) {
61
- return Array.isArray(r) ? r.flatMap((e) => _(e.split(G))) : _(r.split(G));
30
+ return Array.isArray(r) ? r.flatMap((e) => G(e.split(F))) : G(r.split(F));
62
31
  }
63
- function _(r) {
32
+ function G(r) {
64
33
  return r.flatMap((e) => {
65
34
  if (e.length === 0)
66
35
  return [];
@@ -83,58 +52,9 @@ function h(r) {
83
52
  const e = A(r);
84
53
  return e.charAt(0).toLowerCase() + e.slice(1);
85
54
  }
86
- function fe(r) {
55
+ function ue(r) {
87
56
  return r === "" || Array.isArray(r) && r.length === 0 ? "" : L(r).filter((t) => t.length > 0).map((t) => t.toUpperCase()).join("_");
88
57
  }
89
- function U(r) {
90
- return r.startsWith("http://") || r.startsWith("https://") ? he(r) : ye(r);
91
- }
92
- async function he(r) {
93
- return await (await fetch(r)).text();
94
- }
95
- function ye(r) {
96
- return new Promise((e, t) => {
97
- ce(r, "utf-8", (n, o) => {
98
- n ? t(n) : e(o);
99
- });
100
- });
101
- }
102
- async function xe(r) {
103
- const e = await U(r);
104
- switch (J(e)) {
105
- case "json":
106
- return JSON.parse(e);
107
- case "yaml":
108
- return B(e);
109
- default:
110
- throw new Error(`Unsupported file format: ${r}`);
111
- }
112
- }
113
- async function Ae(r) {
114
- const e = await U(r);
115
- switch (J(e)) {
116
- case "json":
117
- return JSON.parse(e);
118
- case "yaml":
119
- return B(e);
120
- default:
121
- throw new Error(`Unsupported file format: ${r}`);
122
- }
123
- }
124
- function J(r) {
125
- const e = r.trimStart();
126
- if (e.startsWith("{") || e.startsWith("["))
127
- return "json";
128
- if (e.startsWith("-") || e.startsWith("%YAML"))
129
- return "yaml";
130
- try {
131
- return JSON.parse(e), "json";
132
- } catch {
133
- if (e.length > 0)
134
- return "yaml";
135
- }
136
- throw new Error("Unable to infer file format");
137
- }
138
58
  function l(r) {
139
59
  return !!(r && typeof r == "object" && "$ref" in r);
140
60
  }
@@ -142,16 +62,16 @@ function D(r, e) {
142
62
  if (e && !l(e) && e.content)
143
63
  return e.content[r]?.schema;
144
64
  }
145
- function V(r) {
65
+ function U(r) {
146
66
  return D(S.APPLICATION_JSON, r);
147
67
  }
148
- function Ce(r) {
68
+ function me(r) {
149
69
  return D(S.TEXT_EVENT_STREAM, r);
150
70
  }
151
- function Pe(r) {
71
+ function de(r) {
152
72
  return D("*/*", r);
153
73
  }
154
- const $e = [
74
+ const fe = [
155
75
  "string",
156
76
  "number",
157
77
  "integer",
@@ -159,33 +79,33 @@ const $e = [
159
79
  "null"
160
80
  ];
161
81
  function b(r) {
162
- return Array.isArray(r) ? !0 : $e.includes(r);
82
+ return Array.isArray(r) ? !0 : fe.includes(r);
163
83
  }
164
84
  function O(r) {
165
85
  return r.type === "array";
166
86
  }
167
- function Te(r) {
87
+ function he(r) {
168
88
  return Array.isArray(r.enum) && r.enum.length > 0;
169
89
  }
170
- function K(r) {
90
+ function J(r) {
171
91
  return Array.isArray(r.anyOf) && r.anyOf.length > 0;
172
92
  }
173
- function H(r) {
93
+ function V(r) {
174
94
  return Array.isArray(r.oneOf) && r.oneOf.length > 0;
175
95
  }
176
- function Ie(r) {
177
- return K(r) || H(r);
96
+ function ye(r) {
97
+ return J(r) || V(r);
178
98
  }
179
- function Se(r) {
99
+ function xe(r) {
180
100
  return Array.isArray(r.allOf) && r.allOf.length > 0;
181
101
  }
182
- function F(r) {
183
- return K(r) || H(r) || Se(r);
102
+ function _(r) {
103
+ return J(r) || V(r) || xe(r);
184
104
  }
185
105
  function W(r) {
186
106
  return r.includes("|") || r.includes("&") ? `(${r})[]` : `${r}[]`;
187
107
  }
188
- function we(r) {
108
+ function Ae(r) {
189
109
  return r.type !== "object" ? !1 : r.properties ? Object.keys(r.properties).length === 0 : !0;
190
110
  }
191
111
  function C(r) {
@@ -205,7 +125,7 @@ function C(r) {
205
125
  return "any";
206
126
  }
207
127
  }
208
- function Y(r) {
128
+ function K(r) {
209
129
  return [
210
130
  { method: "get", operation: r.get },
211
131
  { method: "put", operation: r.put },
@@ -222,17 +142,66 @@ function q(r) {
222
142
  }
223
143
  function z(r) {
224
144
  const e = q(r);
225
- return V(e);
145
+ return U(e);
226
146
  }
227
- function Re(r, e) {
147
+ function Ce(r, e) {
228
148
  return r.parameters ? r.parameters.map((t) => l(t) ? Q(t, e) : t).filter((t) => t.in === "path") : [];
229
149
  }
230
- const Ee = "string";
150
+ const Pe = "string";
151
+ function H(r) {
152
+ return !r.schema || l(r.schema) || !r.schema.type || !b(r.schema.type) ? Pe : C(r.schema.type);
153
+ }
154
+ function Y(r) {
155
+ return r.startsWith("http://") || r.startsWith("https://") ? $e(r) : Te(r);
156
+ }
157
+ async function $e(r) {
158
+ return await (await fetch(r)).text();
159
+ }
160
+ function Te(r) {
161
+ return new Promise((e, t) => {
162
+ ge(r, "utf-8", (n, o) => {
163
+ n ? t(n) : e(o);
164
+ });
165
+ });
166
+ }
167
+ async function Ie(r) {
168
+ const e = await Y(r);
169
+ switch (X(e)) {
170
+ case "json":
171
+ return JSON.parse(e);
172
+ case "yaml":
173
+ return B(e);
174
+ default:
175
+ throw new Error(`Unsupported file format: ${r}`);
176
+ }
177
+ }
178
+ async function Se(r) {
179
+ const e = await Y(r);
180
+ switch (X(e)) {
181
+ case "json":
182
+ return JSON.parse(e);
183
+ case "yaml":
184
+ return B(e);
185
+ default:
186
+ throw new Error(`Unsupported file format: ${r}`);
187
+ }
188
+ }
231
189
  function X(r) {
232
- return !r.schema || l(r.schema) || !r.schema.type || !b(r.schema.type) ? Ee : C(r.schema.type);
190
+ const e = r.trimStart();
191
+ if (e.startsWith("{") || e.startsWith("["))
192
+ return "json";
193
+ if (e.startsWith("-") || e.startsWith("%YAML"))
194
+ return "yaml";
195
+ try {
196
+ return JSON.parse(e), "json";
197
+ } catch {
198
+ if (e.length > 0)
199
+ return "yaml";
200
+ }
201
+ throw new Error("Unable to infer file format");
233
202
  }
234
- const Z = "types.ts", ve = "@";
235
- function Oe(r) {
203
+ const Z = "types.ts", we = "@";
204
+ function Re(r) {
236
205
  return w(r.path, Z);
237
206
  }
238
207
  function ee(r, e, t) {
@@ -254,18 +223,18 @@ function E(r, e, t) {
254
223
  });
255
224
  }
256
225
  function f(r, e, t) {
257
- if (t.path.startsWith(ve)) {
226
+ if (t.path.startsWith(we)) {
258
227
  E(r, t.path, [t.name]);
259
228
  return;
260
229
  }
261
- const n = r.getDirectoryPath(), o = ge(e, t.path, Z);
262
- let s = le(n, o);
230
+ const n = r.getDirectoryPath(), o = le(e, t.path, Z);
231
+ let s = pe(n, o);
263
232
  s = s.replace(/\.ts$/, ""), s.startsWith(".") || (s = "./" + s), E(r, s, [t.name]);
264
233
  }
265
234
  function I(r, e, t, n) {
266
235
  r.path !== n.path && f(e, t, n);
267
236
  }
268
- function Ne(r, e) {
237
+ function Ee(r, e) {
269
238
  const t = [r, e].filter(
270
239
  (n) => n !== void 0 && n.length > 0
271
240
  );
@@ -273,19 +242,50 @@ function Ne(r, e) {
273
242
  `) : void 0;
274
243
  }
275
244
  function x(r, e, t) {
276
- const n = Ne(e, t);
245
+ const n = Ee(e, t);
277
246
  n && r.addJsDoc({
278
247
  description: n
279
248
  });
280
249
  }
281
- const De = "#/components/responses/wow.CommandOk", be = "#/components/parameters/wow.id";
282
- class qe {
250
+ function ve(r) {
251
+ const e = r.split(".");
252
+ return e.length != 2 || e[0].length === 0 || e[1].length === 0 ? null : e;
253
+ }
254
+ function Oe(r) {
255
+ const e = ve(r.name);
256
+ return e ? {
257
+ tag: r,
258
+ contextAlias: e[0],
259
+ aggregateName: e[1]
260
+ } : null;
261
+ }
262
+ function Ne(r) {
263
+ const e = r?.map((n) => Oe(n)).filter((n) => n !== null);
264
+ if (!e)
265
+ return /* @__PURE__ */ new Map();
266
+ const t = /* @__PURE__ */ new Map();
267
+ return e.forEach((n) => {
268
+ t.set(n.tag.name, {
269
+ aggregate: n,
270
+ commands: /* @__PURE__ */ new Map(),
271
+ events: /* @__PURE__ */ new Map()
272
+ });
273
+ }), t;
274
+ }
275
+ function De(r) {
276
+ if (!r)
277
+ return null;
278
+ const e = r.split(".");
279
+ return e.length != 3 ? null : e[2];
280
+ }
281
+ const be = "#/components/responses/wow.CommandOk", qe = "#/components/parameters/wow.id";
282
+ class Me {
283
283
  /**
284
284
  * Creates a new AggregateResolver instance.
285
285
  * @param openAPI - The OpenAPI specification to resolve aggregates from
286
286
  */
287
287
  constructor(e) {
288
- this.openAPI = e, this.aggregates = me(e.tags), this.build();
288
+ this.openAPI = e, this.aggregates = Ne(e.tags), this.build();
289
289
  }
290
290
  aggregates;
291
291
  /**
@@ -294,7 +294,7 @@ class qe {
294
294
  */
295
295
  build() {
296
296
  for (const [e, t] of Object.entries(this.openAPI.paths)) {
297
- const n = Y(t);
297
+ const n = K(t);
298
298
  for (const o of n)
299
299
  this.commands(e, o), this.state(o.operation), this.events(o.operation), this.fields(o.operation);
300
300
  }
@@ -323,13 +323,13 @@ class qe {
323
323
  const n = t.operation;
324
324
  if (n.operationId === "wow.command.send")
325
325
  return;
326
- const o = de(n.operationId);
326
+ const o = De(n.operationId);
327
327
  if (!o)
328
328
  return;
329
329
  const s = q(n);
330
- if (!s || !l(s) || s.$ref !== De || !n.requestBody)
330
+ if (!s || !l(s) || s.$ref !== be || !n.requestBody)
331
331
  return;
332
- const i = n.parameters ?? [], a = i.filter((m) => l(m) && m.$ref === be).at(0), c = i.filter(
332
+ const i = n.parameters ?? [], a = i.filter((m) => l(m) && m.$ref === qe).at(0), c = i.filter(
333
333
  (m) => !l(m) && m.in === "path"
334
334
  );
335
335
  if (a) {
@@ -432,7 +432,7 @@ class qe {
432
432
  });
433
433
  }
434
434
  }
435
- const P = "@ahoo-wang/fetcher-wow", Me = {
435
+ const P = "@ahoo-wang/fetcher-wow", je = {
436
436
  "wow.command.CommandResult": "CommandResult",
437
437
  "wow.MessageHeaderSqlType": "MessageHeaderSqlType",
438
438
  "wow.api.BindingError": "BindingError",
@@ -464,7 +464,7 @@ const P = "@ahoo-wang/fetcher-wow", Me = {
464
464
  function d(r) {
465
465
  if (!r)
466
466
  return { name: "", path: "/" };
467
- const e = Me[r];
467
+ const e = je[r];
468
468
  if (e)
469
469
  return { name: e, path: P };
470
470
  const t = r.split(".");
@@ -483,12 +483,12 @@ function y(r) {
483
483
  const e = $(r);
484
484
  return d(e);
485
485
  }
486
- class je {
486
+ class Fe {
487
487
  constructor(e) {
488
488
  this.context = e;
489
489
  }
490
490
  getOrCreateSourceFile(e) {
491
- const t = Oe(e);
491
+ const t = Re(e);
492
492
  return this.context.getOrCreateSourceFile(t);
493
493
  }
494
494
  /**
@@ -567,12 +567,12 @@ class je {
567
567
  s && x(s, t.title, t.description);
568
568
  }
569
569
  process(e, t, n) {
570
- if (Te(n))
570
+ if (he(n))
571
571
  return t.addEnum({
572
572
  name: e.name,
573
573
  isExported: !0,
574
574
  members: n.enum.filter((s) => typeof s == "string" && s.length > 0).map((s) => ({
575
- name: fe(s),
575
+ name: ue(s),
576
576
  initializer: `'${s}'`
577
577
  }))
578
578
  });
@@ -598,7 +598,7 @@ class je {
598
598
  e,
599
599
  n,
600
600
  o
601
- ) : (F(n) && (n.anyOf || n.oneOf || n.allOf).forEach((i) => {
601
+ ) : (_(n) && (n.anyOf || n.oneOf || n.allOf).forEach((i) => {
602
602
  if (l(i)) {
603
603
  const a = y(i);
604
604
  I(
@@ -668,7 +668,7 @@ class je {
668
668
  }
669
669
  if (o.type && b(o.type))
670
670
  return C(o.type);
671
- if (F(o))
671
+ if (_(o))
672
672
  return this.resolvePropertyCompositionType(
673
673
  e,
674
674
  t,
@@ -702,191 +702,455 @@ class je {
702
702
  }
703
703
  s.add(C(a.type ?? "string"));
704
704
  });
705
- const i = Ie(n) ? "|" : "&";
705
+ const i = ye(n) ? "|" : "&";
706
706
  return Array.from(s).join(i);
707
707
  }
708
708
  }
709
- function Ge(r) {
709
+ const Ge = "@ahoo-wang/fetcher-decorator", _e = [
710
+ "type ApiMetadata",
711
+ "type ApiMetadataCapable",
712
+ "api",
713
+ "post",
714
+ "put",
715
+ "patch",
716
+ "del",
717
+ "request",
718
+ "attribute",
719
+ "path",
720
+ "autoGeneratedError"
721
+ ], te = `{
722
+ headers: { Accept: ContentTypeValues.TEXT_EVENT_STREAM },
723
+ resultExtractor: JsonEventStreamResultExtractor,
724
+ }`;
725
+ function ne(r) {
726
+ E(r, Ge, _e);
727
+ }
728
+ function oe(r, e, t = []) {
729
+ return e.addClass({
730
+ name: r,
731
+ isExported: !0,
732
+ decorators: [
733
+ {
734
+ name: "api",
735
+ arguments: t
736
+ }
737
+ ]
738
+ });
739
+ }
740
+ function re(r, e) {
741
+ r.addImplements("ApiMetadataCapable"), r.addConstructor({
742
+ parameters: [
743
+ {
744
+ name: "apiMetadata",
745
+ type: "ApiMetadata",
746
+ hasQuestionToken: e === void 0,
747
+ scope: ae.Public,
748
+ isReadonly: !0,
749
+ initializer: e
750
+ }
751
+ ]
752
+ });
753
+ }
754
+ function We(r) {
710
755
  let e = 0, t = 0;
711
756
  return r.commands.forEach((n) => {
712
757
  n.path.startsWith(j.TENANT) && (e += 1), n.path.startsWith(j.OWNER) && (t += 1);
713
758
  }), e === 0 && t === 0 ? "ResourceAttributionPathSpec.NONE" : e > t ? "ResourceAttributionPathSpec.TENANT" : "ResourceAttributionPathSpec.OWNER";
714
759
  }
715
- function te(r, e, t, n) {
760
+ function se(r, e, t, n) {
716
761
  const o = `${t.contextAlias}/${t.aggregateName}/${n}.ts`;
717
762
  return ee(r, e, o);
718
763
  }
719
- function _e(r, e) {
764
+ function ze(r, e) {
720
765
  return `${A(r.aggregateName)}${e}`;
721
766
  }
722
767
  function N(r) {
723
768
  return r === "delete" ? "del" : r;
724
769
  }
725
- class Fe {
770
+ class Be {
726
771
  /**
727
- * Creates a new QueryClientGenerator instance.
728
- * @param context - The generation context containing OpenAPI spec and project details
772
+ * Creates a new ApiClientGenerator instance.
773
+ * @param context - The generation context containing OpenAPI spec and configuration
729
774
  */
730
775
  constructor(e) {
731
- this.context = e;
776
+ this.context = e, this.apiMetadataCtorInitializer = this.context.currentContextAlias ? `{basePath:'${this.context.currentContextAlias}'}` : void 0;
732
777
  }
778
+ defaultParameterRequestType = "ParameterRequest";
779
+ defaultReturnType = { type: "Promise<any>" };
780
+ apiMetadataCtorInitializer;
733
781
  /**
734
- * Generates query client classes for all aggregates.
782
+ * Generates API client classes for all valid tags in the OpenAPI specification.
783
+ * Processes tags, groups operations, and creates client classes with methods.
735
784
  */
736
785
  generate() {
737
- const e = Array.from(this.context.contextAggregates.values()).reduce(
738
- (n, o) => n + o.size,
739
- 0
740
- );
741
- this.context.logger.info("--- Generating Query Clients ---"), this.context.logger.progress(
742
- `Generating query clients for ${e} aggregates`
786
+ this.context.logger.info("Starting API client generation");
787
+ const e = this.resolveApiTags();
788
+ this.context.logger.info(
789
+ `Resolved ${e.size} API client tags: ${Array.from(e.keys()).join(", ")}`
743
790
  );
744
- let t = 0;
745
- for (const [, n] of this.context.contextAggregates)
746
- n.forEach((o) => {
747
- t++, this.context.logger.progressWithCount(
748
- t,
749
- e,
750
- `Processing query client for aggregate: ${o.aggregate.aggregateName}`
751
- ), this.processQueryClient(o);
752
- });
753
- this.context.logger.success("Query client generation completed");
791
+ const t = this.groupOperations(e);
792
+ this.context.logger.info(
793
+ `Grouped operations into ${t.size} tag groups`
794
+ ), this.generateApiClients(e, t), this.context.logger.success("API client generation completed");
754
795
  }
755
796
  /**
756
- * Creates or retrieves a source file for client generation.
757
- * @param aggregate - The aggregate metadata
758
- * @param fileName - The name of the client file
759
- * @returns The source file for the client
797
+ * Generates API client classes for each tag group.
798
+ * @param apiClientTags - Map of valid API client tags
799
+ * @param groupOperations - Map of operations grouped by tag
760
800
  */
761
- createClientFilePath(e, t) {
762
- return te(
763
- this.context.project,
764
- this.context.outputDir,
765
- e,
766
- t
801
+ generateApiClients(e, t) {
802
+ this.context.logger.info(
803
+ `Generating ${t.size} API client classes`
767
804
  );
805
+ let n = 0;
806
+ for (const [o, s] of t) {
807
+ n++, this.context.logger.progressWithCount(
808
+ n,
809
+ t.size,
810
+ `Generating API client for tag: ${o}`
811
+ );
812
+ const i = e.get(o);
813
+ this.generateApiClient(i, s);
814
+ }
768
815
  }
769
816
  /**
770
- * Processes and generates query client classes for an aggregate.
771
- * @param aggregate - The aggregate definition
772
- */
773
- processQueryClient(e) {
774
- const t = this.createClientFilePath(
775
- e.aggregate,
776
- "queryClient"
817
+ * Creates a new source file for the API client.
818
+ * @param modelInfo - The model information for the client
819
+ * @returns The created source file
820
+ */
821
+ createApiClientFile(e) {
822
+ let t = e.path;
823
+ return this.context.currentContextAlias && (t = w(this.context.currentContextAlias, t)), t = w(t, `${e.name}ApiClient.ts`), this.context.logger.info(`Creating API client file: ${t}`), this.context.getOrCreateSourceFile(t);
824
+ }
825
+ /**
826
+ * Generates a single API client class for the given tag and operations.
827
+ * @param tag - The OpenAPI tag for the client
828
+ * @param operations - Set of operations for this client
829
+ */
830
+ generateApiClient(e, t) {
831
+ const n = d(e.name);
832
+ this.context.logger.info(
833
+ `Generating API client class: ${n.name}ApiClient with ${t.size} operations`
834
+ );
835
+ const o = this.createApiClientFile(n);
836
+ ne(o);
837
+ const s = oe(
838
+ n.name + "ApiClient",
839
+ o
840
+ );
841
+ x(s, e.description), re(s, this.apiMetadataCtorInitializer), this.context.logger.info(
842
+ `Processing ${t.size} operations for ${n.name}ApiClient`
843
+ ), t.forEach((i) => {
844
+ this.processOperation(e, o, s, i);
845
+ }), this.context.logger.success(
846
+ `Completed API client: ${n.name}ApiClient`
777
847
  );
848
+ }
849
+ /**
850
+ * Generates a unique method name for the operation.
851
+ * @param apiClientClass - The client class to check for existing methods
852
+ * @param operation - The operation to generate a name for
853
+ * @returns A unique camelCase method name
854
+ */
855
+ getMethodName(e, t) {
856
+ const n = t.operationId.split(".");
857
+ for (let o = n.length - 1; o >= 0; o--) {
858
+ const s = h(n.slice(o));
859
+ if (!e.getMethod(s))
860
+ return s;
861
+ }
862
+ return h(n);
863
+ }
864
+ /**
865
+ * Resolves the request type for an operation based on its request body.
866
+ * @param sourceFile - The source file to add imports to
867
+ * @param operation - The operation to resolve the request type for
868
+ * @returns The resolved request type string
869
+ */
870
+ resolveRequestType(e, t) {
871
+ if (!t.requestBody)
872
+ return this.context.logger.info(
873
+ `No request body found for operation ${t.operationId}, using default: ${this.defaultParameterRequestType}`
874
+ ), this.defaultParameterRequestType;
875
+ let n;
876
+ if (l(t.requestBody) ? (this.context.logger.info(
877
+ `Extracting request body from reference for operation: ${t.operationId}`
878
+ ), n = k(
879
+ t.requestBody,
880
+ this.context.openAPI.components
881
+ )) : n = t.requestBody, !n)
882
+ return this.context.logger.info(
883
+ `Request body extraction failed for operation ${t.operationId}, using default: ${this.defaultParameterRequestType}`
884
+ ), this.defaultParameterRequestType;
885
+ if (n.content["multipart/form-data"])
886
+ return this.context.logger.info(
887
+ `Detected multipart/form-data content for operation ${t.operationId}, using ParameterRequest<FormData>`
888
+ ), "ParameterRequest<FormData>";
889
+ if (n.content["application/json"]) {
890
+ const o = n.content["application/json"].schema;
891
+ if (l(o)) {
892
+ const s = y(o);
893
+ this.context.logger.info(
894
+ `Adding import for request body model: ${s.name} from ${s.path}`
895
+ ), f(e, this.context.outputDir, s);
896
+ const i = `ParameterRequest<${s.name}>`;
897
+ return this.context.logger.info(
898
+ `Resolved request type for operation ${t.operationId}: ${i}`
899
+ ), i;
900
+ }
901
+ }
902
+ return this.context.logger.info(
903
+ `Using default request type for operation ${t.operationId}: ${this.defaultParameterRequestType}`
904
+ ), this.defaultParameterRequestType;
905
+ }
906
+ /**
907
+ * Resolves method parameters for an operation.
908
+ * @param tag - The tag for parameter filtering
909
+ * @param sourceFile - The source file to add imports to
910
+ * @param operation - The operation to resolve parameters for
911
+ * @returns Array of parameter declarations
912
+ */
913
+ resolveParameters(e, t, n) {
914
+ const o = Ce(n, this.context.openAPI.components).filter((a) => !this.context.isIgnoreApiClientPathParameters(
915
+ e.name,
916
+ a.name
917
+ ));
778
918
  this.context.logger.info(
779
- `Processing query client for aggregate: ${e.aggregate.aggregateName} in context: ${e.aggregate.contextAlias}`
780
- ), this.context.logger.info(
781
- `Adding imports from ${P}: QueryClientFactory, QueryClientOptions, ResourceAttributionPathSpec`
782
- ), t.addImportDeclaration({
783
- moduleSpecifier: P,
784
- namedImports: [
785
- "QueryClientFactory",
786
- "QueryClientOptions",
787
- "ResourceAttributionPathSpec"
919
+ `Found ${o.length} path parameters for operation ${n.operationId}`
920
+ );
921
+ const s = o.map((a) => {
922
+ const c = H(a);
923
+ return this.context.logger.info(
924
+ `Adding path parameter: ${a.name} (type: ${c})`
925
+ ), {
926
+ name: a.name,
927
+ type: c,
928
+ hasQuestionToken: !1,
929
+ decorators: [
930
+ {
931
+ name: "path",
932
+ arguments: [`'${a.name}'`]
933
+ }
934
+ ]
935
+ };
936
+ }), i = this.resolveRequestType(t, n);
937
+ return this.context.logger.info(`Adding httpRequest parameter: ${i}`), s.push({
938
+ name: "httpRequest",
939
+ hasQuestionToken: i === this.defaultParameterRequestType,
940
+ type: `${i}`,
941
+ decorators: [
942
+ {
943
+ name: "request",
944
+ arguments: []
945
+ }
788
946
  ]
789
- });
790
- const n = "DEFAULT_QUERY_CLIENT_OPTIONS";
791
- this.context.logger.info(
792
- `Creating default query client options: ${n}`
793
- ), t.addVariableStatement({
794
- declarationKind: v.Const,
795
- declarations: [
947
+ }), this.context.logger.info(
948
+ "Adding attributes parameter: Record<string, any>"
949
+ ), s.push({
950
+ name: "attributes",
951
+ hasQuestionToken: !0,
952
+ type: "Record<string, any>",
953
+ decorators: [
796
954
  {
797
- name: n,
798
- type: "QueryClientOptions",
799
- initializer: `{
800
- contextAlias: '${e.aggregate.contextAlias}',
801
- aggregateName: '${e.aggregate.aggregateName}',
802
- resourceAttribution: ${Ge(e)},
803
- }`
955
+ name: "attribute",
956
+ arguments: []
804
957
  }
805
- ],
806
- isExported: !1
807
- });
808
- const o = [];
809
- this.context.logger.info(
810
- `Processing ${e.events.size} domain events for aggregate: ${e.aggregate.aggregateName}`
811
- );
812
- for (const u of e.events.values()) {
813
- const p = d(u.schema.key);
958
+ ]
959
+ }), s;
960
+ }
961
+ /**
962
+ * Resolves the return type for a schema.
963
+ * @param sourceFile - The source file to add imports to
964
+ * @param schema - The schema to resolve the return type for
965
+ * @returns The resolved return type string
966
+ */
967
+ resolveSchemaReturnType(e, t) {
968
+ if (l(t)) {
969
+ const n = y(t);
814
970
  this.context.logger.info(
815
- `Adding import for event model: ${p.name} from path: ${p.path}`
816
- ), f(t, this.context.outputDir, p), o.push(p);
971
+ `Adding import for response model: ${n.name} from ${n.path}`
972
+ ), f(e, this.context.outputDir, n);
973
+ const o = `Promise<${n.name}>`;
974
+ return this.context.logger.info(`Resolved reference return type: ${o}`), o;
817
975
  }
818
- const s = "DOMAIN_EVENT_TYPES", i = o.map((u) => u.name).join(" | ");
976
+ if (!t.type)
977
+ return this.context.logger.info(
978
+ `Schema has no type, using default return type: ${this.defaultReturnType.type}`
979
+ ), this.defaultReturnType.type;
980
+ if (b(t.type)) {
981
+ const o = `Promise<${C(t.type)}>`;
982
+ return this.context.logger.info(`Resolved primitive return type: ${o}`), o;
983
+ }
984
+ return this.context.logger.info(
985
+ `Using default return type: ${this.defaultReturnType.type}`
986
+ ), this.defaultReturnType.type;
987
+ }
988
+ /**
989
+ * Resolves the return type for an operation based on its responses.
990
+ * @param sourceFile - The source file to add imports to
991
+ * @param operation - The operation to resolve the return type for
992
+ * @returns Object containing type and optional stream flag
993
+ */
994
+ resolveReturnType(e, t) {
995
+ const n = q(t);
996
+ if (!n)
997
+ return this.context.logger.info(
998
+ `No OK response found for operation ${t.operationId}, using default return type: ${this.defaultReturnType.type}`
999
+ ), this.defaultReturnType;
1000
+ const o = U(n);
1001
+ if (o) {
1002
+ const a = this.resolveSchemaReturnType(e, o);
1003
+ return this.context.logger.info(
1004
+ `Resolved JSON response return type for operation ${t.operationId}: ${a}`
1005
+ ), {
1006
+ stream: !1,
1007
+ type: a
1008
+ };
1009
+ }
1010
+ const s = me(n);
1011
+ if (s) {
1012
+ if (l(s)) {
1013
+ const c = R(
1014
+ s,
1015
+ this.context.openAPI.components
1016
+ );
1017
+ if (O(c) && l(c.items)) {
1018
+ const g = y(c.items);
1019
+ this.context.logger.info(
1020
+ `Adding import for event stream model: ${g.name} from ${g.path}`
1021
+ ), f(e, this.context.outputDir, g);
1022
+ const p = `Promise<JsonServerSentEventStream<${g.name.includes("ServerSentEvent") ? `${g.name}['data']` : g.name}>>`;
1023
+ return this.context.logger.info(
1024
+ `Resolved event stream return type for operation ${t.operationId}: ${p}`
1025
+ ), {
1026
+ stream: !0,
1027
+ type: p
1028
+ };
1029
+ }
1030
+ }
1031
+ const a = "Promise<JsonServerSentEventStream<any>>";
1032
+ return this.context.logger.info(
1033
+ `Resolved generic event stream return type for operation ${t.operationId}: ${a}`
1034
+ ), { stream: !0, type: a };
1035
+ }
1036
+ const i = de(n);
1037
+ if (i) {
1038
+ const a = this.resolveSchemaReturnType(
1039
+ e,
1040
+ i
1041
+ );
1042
+ return this.context.logger.info(
1043
+ `Resolved wildcard response return type for operation ${t.operationId}: ${a}`
1044
+ ), { type: a };
1045
+ }
1046
+ return this.context.logger.info(
1047
+ `Using default return type for operation ${t.operationId}: ${this.defaultReturnType.type}`
1048
+ ), this.defaultReturnType;
1049
+ }
1050
+ /**
1051
+ * Processes a single operation and adds it as a method to the client class.
1052
+ * @param tag - The tag for parameter filtering
1053
+ * @param sourceFile - The source file containing the client
1054
+ * @param apiClientClass - The client class to add the method to
1055
+ * @param operation - The operation to process
1056
+ */
1057
+ processOperation(e, t, n, o) {
819
1058
  this.context.logger.info(
820
- `Creating domain event types union: ${s} = ${i}`
821
- ), t.addTypeAlias({
822
- name: s,
823
- type: i
824
- });
825
- const a = `${h(e.aggregate.aggregateName)}QueryClientFactory`, c = d(e.state.key), g = d(e.fields.key);
1059
+ `Processing operation: ${o.operation.operationId} (${o.method} ${o.path})`
1060
+ );
1061
+ const s = this.getMethodName(n, o.operation);
1062
+ this.context.logger.info(`Generated method name: ${s}`);
1063
+ const i = this.resolveParameters(
1064
+ e,
1065
+ t,
1066
+ o.operation
1067
+ ), a = this.resolveReturnType(t, o.operation), c = a.stream ? {
1068
+ name: N(o.method),
1069
+ arguments: [`'${o.path}'`, te]
1070
+ } : {
1071
+ name: N(o.method),
1072
+ arguments: [`'${o.path}'`]
1073
+ };
826
1074
  this.context.logger.info(
827
- `Adding import for state model: ${c.name} from path: ${c.path}`
828
- ), f(t, this.context.outputDir, c), this.context.logger.info(
829
- `Adding import for fields model: ${g.name} from path: ${g.path}`
830
- ), f(t, this.context.outputDir, g), this.context.logger.info(`Creating query client factory: ${a}`), t.addVariableStatement({
831
- declarationKind: v.Const,
832
- declarations: [
833
- {
834
- name: a,
835
- initializer: `new QueryClientFactory<${c.name}, ${g.name} | string, ${s}>(${n})`
836
- }
837
- ],
838
- isExported: !0
839
- }), this.context.logger.success(
840
- `Query client generation completed for aggregate: ${e.aggregate.aggregateName}`
1075
+ `Creating method with ${i.length} parameters, return type: ${a.type}, stream: ${a.stream || !1}`
841
1076
  );
1077
+ const g = n.addMethod({
1078
+ name: s,
1079
+ decorators: [c],
1080
+ parameters: i,
1081
+ returnType: a.type,
1082
+ statements: [
1083
+ `throw autoGeneratedError(${i.map((u) => u.name).join(",")});`
1084
+ ]
1085
+ });
1086
+ x(
1087
+ g,
1088
+ o.operation.summary,
1089
+ o.operation.description
1090
+ ), this.context.logger.success(`Operation method generated: ${s}`);
1091
+ }
1092
+ /**
1093
+ * Groups operations by their tags for client generation.
1094
+ * @param apiClientTags - Map of valid API client tags
1095
+ * @returns Map of operations grouped by tag name
1096
+ */
1097
+ groupOperations(e) {
1098
+ this.context.logger.info("Grouping operations by API client tags");
1099
+ const t = /* @__PURE__ */ new Map();
1100
+ let n = 0;
1101
+ for (const [o, s] of Object.entries(this.context.openAPI.paths)) {
1102
+ const i = K(s).filter(
1103
+ (a) => {
1104
+ if (!a.operation.operationId)
1105
+ return !1;
1106
+ const c = a.operation.tags;
1107
+ return !c || c.length == 0 ? !1 : c.every((g) => e.has(g));
1108
+ }
1109
+ );
1110
+ this.context.logger.info(
1111
+ `Path ${o}: found ${i.length} valid operations`
1112
+ );
1113
+ for (const a of i)
1114
+ a.operation.tags.forEach((c) => {
1115
+ const g = {
1116
+ ...a,
1117
+ path: o
1118
+ };
1119
+ t.has(c) || t.set(c, /* @__PURE__ */ new Set()), t.get(c).add(g), n++;
1120
+ });
1121
+ }
1122
+ return this.context.logger.info(
1123
+ `Grouped ${n} operations into ${t.size} tag groups`
1124
+ ), t;
1125
+ }
1126
+ /**
1127
+ * Resolves valid API client tags from the OpenAPI specification.
1128
+ * Filters out system tags like 'wow' and 'Actuator' and aggregate tags.
1129
+ * @returns Map of valid API client tags
1130
+ */
1131
+ resolveApiTags() {
1132
+ this.context.logger.info(
1133
+ "Resolving API client tags from OpenAPI specification"
1134
+ );
1135
+ const e = /* @__PURE__ */ new Map(), t = this.context.openAPI.tags?.length || 0;
1136
+ let n = 0;
1137
+ return this.context.openAPI.tags?.forEach((o) => {
1138
+ o.name != "wow" && o.name != "Actuator" && !this.isAggregateTag(o) ? (e.set(o.name, o), n++, this.context.logger.info(`Included API client tag: ${o.name}`)) : this.context.logger.info(
1139
+ `Excluded tag: ${o.name} (wow/Actuator/aggregate)`
1140
+ );
1141
+ }), this.context.logger.info(
1142
+ `Resolved ${n} API client tags from ${t} total tags`
1143
+ ), e;
1144
+ }
1145
+ isAggregateTag(e) {
1146
+ for (const t of this.context.contextAggregates.values())
1147
+ for (const n of t)
1148
+ if (n.aggregate.tag.name === e.name)
1149
+ return !0;
1150
+ return !1;
842
1151
  }
843
1152
  }
844
- const We = "@ahoo-wang/fetcher-decorator", ze = [
845
- "type ApiMetadata",
846
- "type ApiMetadataCapable",
847
- "api",
848
- "post",
849
- "put",
850
- "patch",
851
- "del",
852
- "request",
853
- "attribute",
854
- "path",
855
- "autoGeneratedError"
856
- ], ne = `{
857
- headers: { Accept: ContentTypeValues.TEXT_EVENT_STREAM },
858
- resultExtractor: JsonEventStreamResultExtractor,
859
- }`;
860
- function oe(r) {
861
- E(r, We, ze);
862
- }
863
- function re(r, e, t = []) {
864
- return e.addClass({
865
- name: r,
866
- isExported: !0,
867
- decorators: [
868
- {
869
- name: "api",
870
- arguments: t
871
- }
872
- ]
873
- });
874
- }
875
- function se(r, e) {
876
- r.addImplements("ApiMetadataCapable"), r.addConstructor({
877
- parameters: [
878
- {
879
- name: "apiMetadata",
880
- type: "ApiMetadata",
881
- hasQuestionToken: e === void 0,
882
- scope: ae.Public,
883
- isReadonly: !0,
884
- initializer: e
885
- }
886
- ]
887
- });
888
- }
889
- class Be {
1153
+ class ke {
890
1154
  /**
891
1155
  * Creates a new CommandClientGenerator instance.
892
1156
  * @param context - The generation context containing OpenAPI spec and project details
@@ -926,7 +1190,7 @@ class Be {
926
1190
  this.context.logger.info(
927
1191
  `Processing command client for aggregate: ${e.aggregate.aggregateName} in context: ${e.aggregate.contextAlias}`
928
1192
  );
929
- const t = te(
1193
+ const t = se(
930
1194
  this.context.project,
931
1195
  this.context.outputDir,
932
1196
  e.aggregate,
@@ -969,7 +1233,7 @@ class Be {
969
1233
  "Adding import from @ahoo-wang/fetcher: ContentTypeValues"
970
1234
  ), E(t, "@ahoo-wang/fetcher", ["ContentTypeValues"]), this.context.logger.info(
971
1235
  "Adding imports from @ahoo-wang/fetcher-decorator: ApiMetadata types and decorators"
972
- ), oe(t), this.context.logger.info("Generating standard command client class"), this.processCommandClient(t, e), this.context.logger.info("Generating stream command client class"), this.processCommandClient(t, e, !0), this.context.logger.success(
1236
+ ), ne(t), this.context.logger.info("Generating standard command client class"), this.processCommandClient(t, e), this.context.logger.info("Generating stream command client class"), this.processCommandClient(t, e, !0), this.context.logger.success(
973
1237
  `Command client generation completed for aggregate: ${e.aggregate.aggregateName}`
974
1238
  );
975
1239
  }
@@ -998,13 +1262,13 @@ class Be {
998
1262
  let o = "CommandClient", s = [], i = "Promise<CommandResult>";
999
1263
  n && (o = "Stream" + o, s = [
1000
1264
  "''",
1001
- ne
1265
+ te
1002
1266
  ], i = "Promise<CommandResultEventStream>");
1003
- const a = _e(
1267
+ const a = ze(
1004
1268
  t.aggregate,
1005
1269
  o
1006
- ), c = re(a, e, s);
1007
- se(c, this.defaultCommandClientOptionsName), t.commands.forEach((g) => {
1270
+ ), c = oe(a, e, s);
1271
+ re(c, this.defaultCommandClientOptionsName), t.commands.forEach((g) => {
1008
1272
  this.processCommandMethod(t, e, c, g, i);
1009
1273
  });
1010
1274
  }
@@ -1017,7 +1281,7 @@ class Be {
1017
1281
  e.name,
1018
1282
  i.name
1019
1283
  )).map((i) => {
1020
- const a = X(i);
1284
+ const a = H(i);
1021
1285
  return this.context.logger.info(
1022
1286
  `Adding path parameter: ${i.name} (type: ${a})`
1023
1287
  ), {
@@ -1036,7 +1300,7 @@ class Be {
1036
1300
  `Adding command request parameter: commandRequest (type: CommandRequest<${o.name}>)`
1037
1301
  ), s.push({
1038
1302
  name: "commandRequest",
1039
- hasQuestionToken: we(n.schema.schema),
1303
+ hasQuestionToken: Ae(n.schema.schema),
1040
1304
  type: `CommandRequest<${o.name}>`,
1041
1305
  decorators: [
1042
1306
  {
@@ -1072,409 +1336,145 @@ class Be {
1072
1336
  arguments: [`${this.getEndpointPath(o)}`]
1073
1337
  }
1074
1338
  ],
1075
- parameters: i,
1076
- returnType: s,
1077
- statements: [
1078
- `throw autoGeneratedError(${i.map((c) => c.name).join(",")});`
1079
- ]
1080
- });
1081
- (o.summary || o.description) && this.context.logger.info(
1082
- `Adding JSDoc documentation for method: ${h(o.name)}`
1083
- ), x(a, o.summary, o.description), this.context.logger.success(
1084
- `Command method generated: ${h(o.name)}`
1085
- );
1086
- }
1087
- }
1088
- class ke {
1089
- /**
1090
- * Creates a new ApiClientGenerator instance.
1091
- * @param context - The generation context containing OpenAPI spec and configuration
1092
- */
1093
- constructor(e) {
1094
- this.context = e, this.apiMetadataCtorInitializer = this.context.currentContextAlias ? `{basePath:'${this.context.currentContextAlias}'}` : void 0;
1095
- }
1096
- defaultParameterRequestType = "ParameterRequest";
1097
- defaultReturnType = { type: "Promise<any>" };
1098
- apiMetadataCtorInitializer;
1099
- /**
1100
- * Generates API client classes for all valid tags in the OpenAPI specification.
1101
- * Processes tags, groups operations, and creates client classes with methods.
1102
- */
1103
- generate() {
1104
- this.context.logger.info("Starting API client generation");
1105
- const e = this.resolveApiTags();
1106
- this.context.logger.info(
1107
- `Resolved ${e.size} API client tags: ${Array.from(e.keys()).join(", ")}`
1108
- );
1109
- const t = this.groupOperations(e);
1110
- this.context.logger.info(
1111
- `Grouped operations into ${t.size} tag groups`
1112
- ), this.generateApiClients(e, t), this.context.logger.success("API client generation completed");
1113
- }
1114
- /**
1115
- * Generates API client classes for each tag group.
1116
- * @param apiClientTags - Map of valid API client tags
1117
- * @param groupOperations - Map of operations grouped by tag
1118
- */
1119
- generateApiClients(e, t) {
1120
- this.context.logger.info(
1121
- `Generating ${t.size} API client classes`
1122
- );
1123
- let n = 0;
1124
- for (const [o, s] of t) {
1125
- n++, this.context.logger.progressWithCount(
1126
- n,
1127
- t.size,
1128
- `Generating API client for tag: ${o}`
1129
- );
1130
- const i = e.get(o);
1131
- this.generateApiClient(i, s);
1132
- }
1133
- }
1134
- /**
1135
- * Creates a new source file for the API client.
1136
- * @param modelInfo - The model information for the client
1137
- * @returns The created source file
1138
- */
1139
- createApiClientFile(e) {
1140
- let t = e.path;
1141
- return this.context.currentContextAlias && (t = w(this.context.currentContextAlias, t)), t = w(t, `${e.name}ApiClient.ts`), this.context.logger.info(`Creating API client file: ${t}`), this.context.getOrCreateSourceFile(t);
1142
- }
1143
- /**
1144
- * Generates a single API client class for the given tag and operations.
1145
- * @param tag - The OpenAPI tag for the client
1146
- * @param operations - Set of operations for this client
1147
- */
1148
- generateApiClient(e, t) {
1149
- const n = d(e.name);
1150
- this.context.logger.info(
1151
- `Generating API client class: ${n.name}ApiClient with ${t.size} operations`
1152
- );
1153
- const o = this.createApiClientFile(n);
1154
- oe(o);
1155
- const s = re(
1156
- n.name + "ApiClient",
1157
- o
1158
- );
1159
- x(s, e.description), se(s, this.apiMetadataCtorInitializer), this.context.logger.info(
1160
- `Processing ${t.size} operations for ${n.name}ApiClient`
1161
- ), t.forEach((i) => {
1162
- this.processOperation(e, o, s, i);
1163
- }), this.context.logger.success(
1164
- `Completed API client: ${n.name}ApiClient`
1165
- );
1166
- }
1167
- /**
1168
- * Generates a unique method name for the operation.
1169
- * @param apiClientClass - The client class to check for existing methods
1170
- * @param operation - The operation to generate a name for
1171
- * @returns A unique camelCase method name
1172
- */
1173
- getMethodName(e, t) {
1174
- const n = t.operationId.split(".");
1175
- for (let o = n.length - 1; o >= 0; o--) {
1176
- const s = h(n.slice(o));
1177
- if (!e.getMethod(s))
1178
- return s;
1179
- }
1180
- return h(n);
1181
- }
1182
- /**
1183
- * Resolves the request type for an operation based on its request body.
1184
- * @param sourceFile - The source file to add imports to
1185
- * @param operation - The operation to resolve the request type for
1186
- * @returns The resolved request type string
1187
- */
1188
- resolveRequestType(e, t) {
1189
- if (!t.requestBody)
1190
- return this.context.logger.info(
1191
- `No request body found for operation ${t.operationId}, using default: ${this.defaultParameterRequestType}`
1192
- ), this.defaultParameterRequestType;
1193
- let n;
1194
- if (l(t.requestBody) ? (this.context.logger.info(
1195
- `Extracting request body from reference for operation: ${t.operationId}`
1196
- ), n = k(
1197
- t.requestBody,
1198
- this.context.openAPI.components
1199
- )) : n = t.requestBody, !n)
1200
- return this.context.logger.info(
1201
- `Request body extraction failed for operation ${t.operationId}, using default: ${this.defaultParameterRequestType}`
1202
- ), this.defaultParameterRequestType;
1203
- if (n.content["multipart/form-data"])
1204
- return this.context.logger.info(
1205
- `Detected multipart/form-data content for operation ${t.operationId}, using ParameterRequest<FormData>`
1206
- ), "ParameterRequest<FormData>";
1207
- if (n.content["application/json"]) {
1208
- const o = n.content["application/json"].schema;
1209
- if (l(o)) {
1210
- const s = y(o);
1211
- this.context.logger.info(
1212
- `Adding import for request body model: ${s.name} from ${s.path}`
1213
- ), f(e, this.context.outputDir, s);
1214
- const i = `ParameterRequest<${s.name}>`;
1215
- return this.context.logger.info(
1216
- `Resolved request type for operation ${t.operationId}: ${i}`
1217
- ), i;
1218
- }
1219
- }
1220
- return this.context.logger.info(
1221
- `Using default request type for operation ${t.operationId}: ${this.defaultParameterRequestType}`
1222
- ), this.defaultParameterRequestType;
1223
- }
1224
- /**
1225
- * Resolves method parameters for an operation.
1226
- * @param tag - The tag for parameter filtering
1227
- * @param sourceFile - The source file to add imports to
1228
- * @param operation - The operation to resolve parameters for
1229
- * @returns Array of parameter declarations
1230
- */
1231
- resolveParameters(e, t, n) {
1232
- const o = Re(n, this.context.openAPI.components).filter((a) => !this.context.isIgnoreApiClientPathParameters(
1233
- e.name,
1234
- a.name
1235
- ));
1236
- this.context.logger.info(
1237
- `Found ${o.length} path parameters for operation ${n.operationId}`
1238
- );
1239
- const s = o.map((a) => {
1240
- const c = X(a);
1241
- return this.context.logger.info(
1242
- `Adding path parameter: ${a.name} (type: ${c})`
1243
- ), {
1244
- name: a.name,
1245
- type: c,
1246
- hasQuestionToken: !1,
1247
- decorators: [
1248
- {
1249
- name: "path",
1250
- arguments: [`'${a.name}'`]
1251
- }
1252
- ]
1253
- };
1254
- }), i = this.resolveRequestType(t, n);
1255
- return this.context.logger.info(`Adding httpRequest parameter: ${i}`), s.push({
1256
- name: "httpRequest",
1257
- hasQuestionToken: i === this.defaultParameterRequestType,
1258
- type: `${i}`,
1259
- decorators: [
1260
- {
1261
- name: "request",
1262
- arguments: []
1263
- }
1264
- ]
1265
- }), this.context.logger.info(
1266
- "Adding attributes parameter: Record<string, any>"
1267
- ), s.push({
1268
- name: "attributes",
1269
- hasQuestionToken: !0,
1270
- type: "Record<string, any>",
1271
- decorators: [
1272
- {
1273
- name: "attribute",
1274
- arguments: []
1275
- }
1276
- ]
1277
- }), s;
1278
- }
1279
- /**
1280
- * Resolves the return type for a schema.
1281
- * @param sourceFile - The source file to add imports to
1282
- * @param schema - The schema to resolve the return type for
1283
- * @returns The resolved return type string
1284
- */
1285
- resolveSchemaReturnType(e, t) {
1286
- if (l(t)) {
1287
- const n = y(t);
1288
- this.context.logger.info(
1289
- `Adding import for response model: ${n.name} from ${n.path}`
1290
- ), f(e, this.context.outputDir, n);
1291
- const o = `Promise<${n.name}>`;
1292
- return this.context.logger.info(`Resolved reference return type: ${o}`), o;
1293
- }
1294
- if (!t.type)
1295
- return this.context.logger.info(
1296
- `Schema has no type, using default return type: ${this.defaultReturnType.type}`
1297
- ), this.defaultReturnType.type;
1298
- if (b(t.type)) {
1299
- const o = `Promise<${C(t.type)}>`;
1300
- return this.context.logger.info(`Resolved primitive return type: ${o}`), o;
1301
- }
1302
- return this.context.logger.info(
1303
- `Using default return type: ${this.defaultReturnType.type}`
1304
- ), this.defaultReturnType.type;
1339
+ parameters: i,
1340
+ returnType: s,
1341
+ statements: [
1342
+ `throw autoGeneratedError(${i.map((c) => c.name).join(",")});`
1343
+ ]
1344
+ });
1345
+ (o.summary || o.description) && this.context.logger.info(
1346
+ `Adding JSDoc documentation for method: ${h(o.name)}`
1347
+ ), x(a, o.summary, o.description), this.context.logger.success(
1348
+ `Command method generated: ${h(o.name)}`
1349
+ );
1305
1350
  }
1351
+ }
1352
+ class Qe {
1306
1353
  /**
1307
- * Resolves the return type for an operation based on its responses.
1308
- * @param sourceFile - The source file to add imports to
1309
- * @param operation - The operation to resolve the return type for
1310
- * @returns Object containing type and optional stream flag
1354
+ * Creates a new QueryClientGenerator instance.
1355
+ * @param context - The generation context containing OpenAPI spec and project details
1311
1356
  */
1312
- resolveReturnType(e, t) {
1313
- const n = q(t);
1314
- if (!n)
1315
- return this.context.logger.info(
1316
- `No OK response found for operation ${t.operationId}, using default return type: ${this.defaultReturnType.type}`
1317
- ), this.defaultReturnType;
1318
- const o = V(n);
1319
- if (o) {
1320
- const a = this.resolveSchemaReturnType(e, o);
1321
- return this.context.logger.info(
1322
- `Resolved JSON response return type for operation ${t.operationId}: ${a}`
1323
- ), {
1324
- stream: !1,
1325
- type: a
1326
- };
1327
- }
1328
- const s = Ce(n);
1329
- if (s) {
1330
- if (l(s)) {
1331
- const c = R(
1332
- s,
1333
- this.context.openAPI.components
1334
- );
1335
- if (O(c) && l(c.items)) {
1336
- const g = y(c.items);
1337
- this.context.logger.info(
1338
- `Adding import for event stream model: ${g.name} from ${g.path}`
1339
- ), f(e, this.context.outputDir, g);
1340
- const p = `Promise<JsonServerSentEventStream<${g.name.includes("ServerSentEvent") ? `${g.name}['data']` : g.name}>>`;
1341
- return this.context.logger.info(
1342
- `Resolved event stream return type for operation ${t.operationId}: ${p}`
1343
- ), {
1344
- stream: !0,
1345
- type: p
1346
- };
1347
- }
1348
- }
1349
- const a = "Promise<JsonServerSentEventStream<any>>";
1350
- return this.context.logger.info(
1351
- `Resolved generic event stream return type for operation ${t.operationId}: ${a}`
1352
- ), { stream: !0, type: a };
1353
- }
1354
- const i = Pe(n);
1355
- if (i) {
1356
- const a = this.resolveSchemaReturnType(
1357
- e,
1358
- i
1359
- );
1360
- return this.context.logger.info(
1361
- `Resolved wildcard response return type for operation ${t.operationId}: ${a}`
1362
- ), { type: a };
1363
- }
1364
- return this.context.logger.info(
1365
- `Using default return type for operation ${t.operationId}: ${this.defaultReturnType.type}`
1366
- ), this.defaultReturnType;
1357
+ constructor(e) {
1358
+ this.context = e;
1367
1359
  }
1368
1360
  /**
1369
- * Processes a single operation and adds it as a method to the client class.
1370
- * @param tag - The tag for parameter filtering
1371
- * @param sourceFile - The source file containing the client
1372
- * @param apiClientClass - The client class to add the method to
1373
- * @param operation - The operation to process
1361
+ * Generates query client classes for all aggregates.
1374
1362
  */
1375
- processOperation(e, t, n, o) {
1376
- this.context.logger.info(
1377
- `Processing operation: ${o.operation.operationId} (${o.method} ${o.path})`
1363
+ generate() {
1364
+ const e = Array.from(this.context.contextAggregates.values()).reduce(
1365
+ (n, o) => n + o.size,
1366
+ 0
1378
1367
  );
1379
- const s = this.getMethodName(n, o.operation);
1380
- this.context.logger.info(`Generated method name: ${s}`);
1381
- const i = this.resolveParameters(
1368
+ this.context.logger.info("--- Generating Query Clients ---"), this.context.logger.progress(
1369
+ `Generating query clients for ${e} aggregates`
1370
+ );
1371
+ let t = 0;
1372
+ for (const [, n] of this.context.contextAggregates)
1373
+ n.forEach((o) => {
1374
+ t++, this.context.logger.progressWithCount(
1375
+ t,
1376
+ e,
1377
+ `Processing query client for aggregate: ${o.aggregate.aggregateName}`
1378
+ ), this.processQueryClient(o);
1379
+ });
1380
+ this.context.logger.success("Query client generation completed");
1381
+ }
1382
+ /**
1383
+ * Creates or retrieves a source file for client generation.
1384
+ * @param aggregate - The aggregate metadata
1385
+ * @param fileName - The name of the client file
1386
+ * @returns The source file for the client
1387
+ */
1388
+ createClientFilePath(e, t) {
1389
+ return se(
1390
+ this.context.project,
1391
+ this.context.outputDir,
1382
1392
  e,
1383
- t,
1384
- o.operation
1385
- ), a = this.resolveReturnType(t, o.operation), c = a.stream ? {
1386
- name: N(o.method),
1387
- arguments: [`'${o.path}'`, ne]
1388
- } : {
1389
- name: N(o.method),
1390
- arguments: [`'${o.path}'`]
1391
- };
1392
- this.context.logger.info(
1393
- `Creating method with ${i.length} parameters, return type: ${a.type}, stream: ${a.stream || !1}`
1393
+ t
1394
1394
  );
1395
- const g = n.addMethod({
1396
- name: s,
1397
- decorators: [c],
1398
- parameters: i,
1399
- returnType: a.type,
1400
- statements: [
1401
- `throw autoGeneratedError(${i.map((u) => u.name).join(",")});`
1402
- ]
1403
- });
1404
- x(
1405
- g,
1406
- o.operation.summary,
1407
- o.operation.description
1408
- ), this.context.logger.success(`Operation method generated: ${s}`);
1409
1395
  }
1410
1396
  /**
1411
- * Groups operations by their tags for client generation.
1412
- * @param apiClientTags - Map of valid API client tags
1413
- * @returns Map of operations grouped by tag name
1397
+ * Processes and generates query client classes for an aggregate.
1398
+ * @param aggregate - The aggregate definition
1414
1399
  */
1415
- groupOperations(e) {
1416
- this.context.logger.info("Grouping operations by API client tags");
1417
- const t = /* @__PURE__ */ new Map();
1418
- let n = 0;
1419
- for (const [o, s] of Object.entries(this.context.openAPI.paths)) {
1420
- const i = Y(s).filter(
1421
- (a) => {
1422
- if (!a.operation.operationId)
1423
- return !1;
1424
- const c = a.operation.tags;
1425
- return !c || c.length == 0 ? !1 : c.every((g) => e.has(g));
1400
+ processQueryClient(e) {
1401
+ const t = this.createClientFilePath(
1402
+ e.aggregate,
1403
+ "queryClient"
1404
+ );
1405
+ this.context.logger.info(
1406
+ `Processing query client for aggregate: ${e.aggregate.aggregateName} in context: ${e.aggregate.contextAlias}`
1407
+ ), this.context.logger.info(
1408
+ `Adding imports from ${P}: QueryClientFactory, QueryClientOptions, ResourceAttributionPathSpec`
1409
+ ), t.addImportDeclaration({
1410
+ moduleSpecifier: P,
1411
+ namedImports: [
1412
+ "QueryClientFactory",
1413
+ "QueryClientOptions",
1414
+ "ResourceAttributionPathSpec"
1415
+ ]
1416
+ });
1417
+ const n = "DEFAULT_QUERY_CLIENT_OPTIONS";
1418
+ this.context.logger.info(
1419
+ `Creating default query client options: ${n}`
1420
+ ), t.addVariableStatement({
1421
+ declarationKind: v.Const,
1422
+ declarations: [
1423
+ {
1424
+ name: n,
1425
+ type: "QueryClientOptions",
1426
+ initializer: `{
1427
+ contextAlias: '${e.aggregate.contextAlias}',
1428
+ aggregateName: '${e.aggregate.aggregateName}',
1429
+ resourceAttribution: ${We(e)},
1430
+ }`
1426
1431
  }
1427
- );
1432
+ ],
1433
+ isExported: !1
1434
+ });
1435
+ const o = [];
1436
+ this.context.logger.info(
1437
+ `Processing ${e.events.size} domain events for aggregate: ${e.aggregate.aggregateName}`
1438
+ );
1439
+ for (const u of e.events.values()) {
1440
+ const p = d(u.schema.key);
1428
1441
  this.context.logger.info(
1429
- `Path ${o}: found ${i.length} valid operations`
1430
- );
1431
- for (const a of i)
1432
- a.operation.tags.forEach((c) => {
1433
- const g = {
1434
- ...a,
1435
- path: o
1436
- };
1437
- t.has(c) || t.set(c, /* @__PURE__ */ new Set()), t.get(c).add(g), n++;
1438
- });
1442
+ `Adding import for event model: ${p.name} from path: ${p.path}`
1443
+ ), f(t, this.context.outputDir, p), o.push(p);
1439
1444
  }
1440
- return this.context.logger.info(
1441
- `Grouped ${n} operations into ${t.size} tag groups`
1442
- ), t;
1443
- }
1444
- /**
1445
- * Resolves valid API client tags from the OpenAPI specification.
1446
- * Filters out system tags like 'wow' and 'Actuator' and aggregate tags.
1447
- * @returns Map of valid API client tags
1448
- */
1449
- resolveApiTags() {
1445
+ const s = "DOMAIN_EVENT_TYPES", i = o.map((u) => u.name).join(" | ");
1450
1446
  this.context.logger.info(
1451
- "Resolving API client tags from OpenAPI specification"
1447
+ `Creating domain event types union: ${s} = ${i}`
1448
+ ), t.addTypeAlias({
1449
+ name: s,
1450
+ type: i
1451
+ });
1452
+ const a = `${h(e.aggregate.aggregateName)}QueryClientFactory`, c = d(e.state.key), g = d(e.fields.key);
1453
+ this.context.logger.info(
1454
+ `Adding import for state model: ${c.name} from path: ${c.path}`
1455
+ ), f(t, this.context.outputDir, c), this.context.logger.info(
1456
+ `Adding import for fields model: ${g.name} from path: ${g.path}`
1457
+ ), f(t, this.context.outputDir, g), this.context.logger.info(`Creating query client factory: ${a}`), t.addVariableStatement({
1458
+ declarationKind: v.Const,
1459
+ declarations: [
1460
+ {
1461
+ name: a,
1462
+ initializer: `new QueryClientFactory<${c.name}, ${g.name} | string, ${s}>(${n})`
1463
+ }
1464
+ ],
1465
+ isExported: !0
1466
+ }), this.context.logger.success(
1467
+ `Query client generation completed for aggregate: ${e.aggregate.aggregateName}`
1452
1468
  );
1453
- const e = /* @__PURE__ */ new Map(), t = this.context.openAPI.tags?.length || 0;
1454
- let n = 0;
1455
- return this.context.openAPI.tags?.forEach((o) => {
1456
- o.name != "wow" && o.name != "Actuator" && !this.isAggregateTag(o) ? (e.set(o.name, o), n++, this.context.logger.info(`Included API client tag: ${o.name}`)) : this.context.logger.info(
1457
- `Excluded tag: ${o.name} (wow/Actuator/aggregate)`
1458
- );
1459
- }), this.context.logger.info(
1460
- `Resolved ${n} API client tags from ${t} total tags`
1461
- ), e;
1462
- }
1463
- isAggregateTag(e) {
1464
- for (const t of this.context.contextAggregates.values())
1465
- for (const n of t)
1466
- if (n.aggregate.tag.name === e.name)
1467
- return !0;
1468
- return !1;
1469
1469
  }
1470
1470
  }
1471
- class Qe {
1471
+ class Le {
1472
1472
  /**
1473
1473
  * Creates a new ClientGenerator instance.
1474
1474
  * @param context - The generation context containing OpenAPI spec and project details
1475
1475
  */
1476
1476
  constructor(e) {
1477
- this.context = e, this.queryClientGenerator = new Fe(e), this.commandClientGenerator = new Be(e), this.apiClientGenerator = new ke(e);
1477
+ this.context = e, this.queryClientGenerator = new Qe(e), this.commandClientGenerator = new ke(e), this.apiClientGenerator = new Be(e);
1478
1478
  }
1479
1479
  queryClientGenerator;
1480
1480
  commandClientGenerator;
@@ -1513,7 +1513,7 @@ class Qe {
1513
1513
  );
1514
1514
  }
1515
1515
  }
1516
- class Le {
1516
+ class Ue {
1517
1517
  /** The ts-morph project instance used for code generation */
1518
1518
  project;
1519
1519
  /** The OpenAPI specification object */
@@ -1540,14 +1540,14 @@ class Le {
1540
1540
  return this.defaultIgnorePathParameters.includes(t);
1541
1541
  }
1542
1542
  }
1543
- const Ue = "./fetcher-generator.config.json";
1544
- class Ze {
1543
+ const Je = "./fetcher-generator.config.json";
1544
+ class et {
1545
1545
  /**
1546
1546
  * Creates a new CodeGenerator instance.
1547
1547
  * @param options - Configuration options for code generation
1548
1548
  */
1549
1549
  constructor(e) {
1550
- this.options = e, this.project = e.project, this.options.logger.info("CodeGenerator instance created");
1550
+ this.options = e, this.project = new ce({ tsConfigFilePath: this.options.tsConfigFilePath }), this.options.logger.info("Project instance created with tsConfigFilePath: ", this.options.tsConfigFilePath);
1551
1551
  }
1552
1552
  project;
1553
1553
  /**
@@ -1559,20 +1559,20 @@ class Ze {
1559
1559
  this.options.logger.info(
1560
1560
  "Starting code generation from OpenAPI specification"
1561
1561
  ), this.options.logger.info(`Input path: ${this.options.inputPath}`), this.options.logger.info(`Output directory: ${this.options.outputDir}`), this.options.logger.info("Parsing OpenAPI specification");
1562
- const e = await xe(this.options.inputPath);
1562
+ const e = await Ie(this.options.inputPath);
1563
1563
  this.options.logger.info("OpenAPI specification parsed successfully"), this.options.logger.info("Resolving bounded context aggregates");
1564
- const n = new qe(e).resolve();
1564
+ const n = new Me(e).resolve();
1565
1565
  this.options.logger.info(
1566
1566
  `Resolved ${n.size} bounded context aggregates`
1567
1567
  );
1568
- const o = this.options.configPath ?? Ue;
1568
+ const o = this.options.configPath ?? Je;
1569
1569
  let s = {};
1570
1570
  try {
1571
- this.options.logger.info("Parsing configuration file:", o), s = await Ae(o);
1571
+ this.options.logger.info("Parsing configuration file:", o), s = await Se(o);
1572
1572
  } catch (g) {
1573
1573
  this.options.logger.info("Configuration file parsing failed ", g);
1574
1574
  }
1575
- const i = new Le({
1575
+ const i = new Ue({
1576
1576
  openAPI: e,
1577
1577
  project: this.project,
1578
1578
  outputDir: this.options.outputDir,
@@ -1580,7 +1580,7 @@ class Ze {
1580
1580
  logger: this.options.logger,
1581
1581
  config: s
1582
1582
  });
1583
- this.options.logger.info("Generating models"), new je(i).generate(), this.options.logger.info("Models generated successfully"), this.options.logger.info("Generating clients"), new Qe(i).generate(), this.options.logger.info("Clients generated successfully"), this.options.logger.info("Generating index files"), this.generateIndex(), this.options.logger.info("Index files generated successfully"), this.options.logger.info("Optimizing source files"), this.optimizeSourceFiles(), this.options.logger.info("Source files optimized successfully"), this.options.logger.info("Saving project to disk"), await this.project.save(), this.options.logger.info("Code generation completed successfully");
1583
+ this.options.logger.info("Generating models"), new Fe(i).generate(), this.options.logger.info("Models generated successfully"), this.options.logger.info("Generating clients"), new Le(i).generate(), this.options.logger.info("Clients generated successfully"), this.options.logger.info("Generating index files"), this.generateIndex(), this.options.logger.info("Index files generated successfully"), this.options.logger.info("Optimizing source files"), this.optimizeSourceFiles(), this.options.logger.info("Source files optimized successfully"), this.options.logger.info("Saving project to disk"), await this.project.save(), this.options.logger.info("Code generation completed successfully");
1584
1584
  }
1585
1585
  /**
1586
1586
  * Generates index.ts files for all subdirectories in the output directory.
@@ -1660,7 +1660,7 @@ class Ze {
1660
1660
  }
1661
1661
  }
1662
1662
  export {
1663
- Ze as CodeGenerator,
1664
- Ue as DEFAULT_CONFIG_PATH
1663
+ et as CodeGenerator,
1664
+ Je as DEFAULT_CONFIG_PATH
1665
1665
  };
1666
1666
  //# sourceMappingURL=index.js.map