ng-openapi 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/cli.cjs +1412 -340
  2. package/index.d.ts +368 -28
  3. package/index.js +1491 -330
  4. package/package.json +1 -1
package/index.js CHANGED
@@ -53,7 +53,7 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
53
53
  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);
54
54
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
55
55
  var __async = (__this, __arguments, generator) => {
56
- return new Promise((resolve, reject) => {
56
+ return new Promise((resolve2, reject) => {
57
57
  var fulfilled = (value) => {
58
58
  try {
59
59
  step(generator.next(value));
@@ -68,7 +68,7 @@ var __async = (__this, __arguments, generator) => {
68
68
  reject(e);
69
69
  }
70
70
  };
71
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
71
+ var step = (x) => x.done ? resolve2(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
72
72
  step((generator = generator.apply(__this, __arguments)).next());
73
73
  });
74
74
  };
@@ -78,31 +78,50 @@ var index_exports = {};
78
78
  __export(index_exports, {
79
79
  BASE_INTERCEPTOR_HEADER_COMMENT: () => BASE_INTERCEPTOR_HEADER_COMMENT,
80
80
  CONTENT_TYPES: () => CONTENT_TYPES,
81
+ ConfigLoadError: () => ConfigLoadError,
81
82
  ConfigValidationError: () => ConfigValidationError,
83
+ DuplicateGeneratedNameError: () => DuplicateGeneratedNameError,
82
84
  HTTP_RESOURCE_GENERATOR_HEADER_COMMENT: () => HTTP_RESOURCE_GENERATOR_HEADER_COMMENT,
85
+ InvalidIdentifierError: () => InvalidIdentifierError,
83
86
  MAIN_INDEX_GENERATOR_HEADER_COMMENT: () => MAIN_INDEX_GENERATOR_HEADER_COMMENT,
84
87
  NgOpenApiError: () => NgOpenApiError,
85
88
  PROVIDER_GENERATOR_HEADER_COMMENT: () => PROVIDER_GENERATOR_HEADER_COMMENT,
86
89
  REQUEST_PARAMS_GENERATOR_HEADER_COMMENT: () => REQUEST_PARAMS_GENERATOR_HEADER_COMMENT,
90
+ RESERVED_MEMBER_NAMES: () => RESERVED_MEMBER_NAMES,
91
+ RESOURCE_ARGUMENT_PROFILE: () => RESOURCE_ARGUMENT_PROFILE,
92
+ SERVICE_ARGUMENT_PROFILE: () => SERVICE_ARGUMENT_PROFILE,
87
93
  SERVICE_GENERATOR_HEADER_COMMENT: () => SERVICE_GENERATOR_HEADER_COMMENT,
88
94
  SERVICE_INDEX_GENERATOR_HEADER_COMMENT: () => SERVICE_INDEX_GENERATOR_HEADER_COMMENT,
89
95
  SpecLoadError: () => SpecLoadError,
90
96
  SpecParseError: () => SpecParseError,
91
97
  SwaggerParser: () => SwaggerParser,
92
98
  TYPE_GENERATOR_HEADER_COMMENT: () => TYPE_GENERATOR_HEADER_COMMENT,
99
+ UnresolvedPathTemplateError: () => UnresolvedPathTemplateError,
93
100
  ZOD_PLUGIN_GENERATOR_HEADER_COMMENT: () => ZOD_PLUGIN_GENERATOR_HEADER_COMMENT,
94
101
  ZOD_PLUGIN_INDEX_GENERATOR_HEADER_COMMENT: () => ZOD_PLUGIN_INDEX_GENERATOR_HEADER_COMMENT,
102
+ assertDistinctMemberNames: () => assertDistinctMemberNames,
95
103
  camelCase: () => camelCase,
104
+ capitalizeFirst: () => capitalizeFirst,
105
+ clientNameIdentifier: () => clientNameIdentifier,
96
106
  defineConfig: () => defineConfig,
107
+ describeOperation: () => describeOperation,
108
+ effectiveClientName: () => effectiveClientName,
97
109
  emitDefaultHeadersMerge: () => emitDefaultHeadersMerge,
110
+ emitDocs: () => emitDocs,
98
111
  emitHeaders: () => emitHeaders,
112
+ emitObjectKey: () => emitObjectKey,
113
+ emitPropertyName: () => emitPropertyName,
99
114
  emitQueryParams: () => emitQueryParams,
100
115
  emitResponseTypeOption: () => emitResponseTypeOption,
101
116
  emitServiceDecorator: () => emitServiceDecorator,
102
117
  emitSignalAwareQueryParams: () => emitSignalAwareQueryParams,
103
118
  emitUrlConstruction: () => emitUrlConstruction,
104
119
  emitUrlExpression: () => emitUrlExpression,
105
- escapeString: () => escapeString,
120
+ escapeDoubleQuoted: () => escapeDoubleQuoted,
121
+ escapeJsDoc: () => escapeJsDoc,
122
+ escapeSingleQuoted: () => escapeSingleQuoted,
123
+ escapeString: () => escapeSingleQuoted,
124
+ escapeTemplateLiteral: () => escapeTemplateLiteral,
106
125
  extractPaths: () => extractPaths,
107
126
  generateFromConfig: () => generateFromConfig,
108
127
  generateParseRequestTypeParams: () => generateParseRequestTypeParams,
@@ -110,6 +129,7 @@ __export(index_exports, {
110
129
  getClientContextTokenName: () => getClientContextTokenName,
111
130
  getInterceptorsTokenName: () => getInterceptorsTokenName,
112
131
  getModelTypeName: () => getModelTypeName,
132
+ getOperationMethodName: () => getOperationMethodName,
113
133
  getRequestBodyType: () => getRequestBodyType,
114
134
  getResourceClassName: () => getResourceClassName,
115
135
  getResponseInfoFromResponse: () => getResponseInfoFromResponse,
@@ -117,21 +137,27 @@ __export(index_exports, {
117
137
  getResponseTypeFromResponse: () => getResponseTypeFromResponse,
118
138
  getServiceClassName: () => getServiceClassName,
119
139
  getTypeScriptType: () => getTypeScriptType,
140
+ groupOperationsByController: () => groupOperationsByController,
120
141
  hasDuplicateFunctionNames: () => hasDuplicateFunctionNames,
121
142
  inferResponseTypeFromContentType: () => inferResponseTypeFromContentType,
122
143
  isDataTypeInterface: () => isDataTypeInterface,
123
144
  isPrimitiveType: () => isPrimitiveType,
124
145
  isUrl: () => isUrl,
146
+ isValidIdentifier: () => isValidIdentifier,
125
147
  joinRequestOptionEntries: () => joinRequestOptionEntries,
126
148
  kebabCase: () => kebabCase,
127
149
  listGeneratedBarrelDirs: () => listGeneratedBarrelDirs,
128
150
  listGeneratedFileNames: () => listGeneratedFileNames,
151
+ loadConfigFile: () => loadConfigFile,
129
152
  normalizeSchema: () => normalizeSchema,
130
153
  normalizeSpec: () => normalizeSpec,
131
154
  nullableType: () => nullableType,
132
155
  pascalCase: () => pascalCase,
133
156
  pascalCaseForEnums: () => pascalCaseForEnums,
134
157
  plainParamValue: () => plainParamValue,
158
+ quoteLiteral: () => quoteLiteral,
159
+ reservedMemberCollision: () => reservedMemberCollision,
160
+ resolveArgumentNames: () => resolveArgumentNames,
135
161
  screamingSnakeCase: () => screamingSnakeCase,
136
162
  signalAwareParamValue: () => signalAwareParamValue,
137
163
  validateGeneratorConfig: () => validateGeneratorConfig,
@@ -160,17 +186,100 @@ function isUrl(input) {
160
186
  __name(isUrl, "isUrl");
161
187
 
162
188
  // ../shared/src/errors.ts
189
+ var NG_OPENAPI_ERROR_BRAND = "__ngOpenApiError";
190
+ var ERROR_LINEAGE = /* @__PURE__ */ new WeakMap();
191
+ var FALLBACK_LINEAGE = Object.freeze([
192
+ "NgOpenApiError"
193
+ ]);
194
+ function registerError(cls, lineage) {
195
+ ERROR_LINEAGE.set(cls, Object.freeze([
196
+ ...lineage
197
+ ]));
198
+ return cls;
199
+ }
200
+ __name(registerError, "registerError");
201
+ function inheritedLineage(cls) {
202
+ for (let current = cls; typeof current === "function"; current = Object.getPrototypeOf(current)) {
203
+ const lineage = ERROR_LINEAGE.get(current);
204
+ if (lineage) {
205
+ return lineage;
206
+ }
207
+ }
208
+ return FALLBACK_LINEAGE;
209
+ }
210
+ __name(inheritedLineage, "inheritedLineage");
163
211
  var _NgOpenApiError = class _NgOpenApiError extends Error {
164
212
  constructor(message, cause) {
165
213
  super(message);
166
214
  /** The underlying error that caused this one, when there is one. */
167
215
  __publicField(this, "cause");
168
- this.name = new.target.name;
216
+ const lineage = inheritedLineage(new.target);
217
+ this.name = lineage[0];
169
218
  this.cause = cause;
219
+ Object.defineProperty(this, NG_OPENAPI_ERROR_BRAND, {
220
+ value: lineage,
221
+ enumerable: false,
222
+ writable: false,
223
+ configurable: false
224
+ });
225
+ }
226
+ /**
227
+ * `message` and `name` are non-enumerable on Error, so the default
228
+ * JSON.stringify dropped both — the least useful possible serialization for
229
+ * something that exists to be logged.
230
+ *
231
+ * The payload is spread rather than enumerated: `source`, `issues`,
232
+ * `operation`, `names` and `placeholders` are why these classes are typed
233
+ * in the first place, and listing fields by hand silently drops whichever
234
+ * ones a later subclass adds.
235
+ */
236
+ toJSON() {
237
+ const cause = this.cause instanceof Error ? this.cause.message : this.cause;
238
+ return __spreadValues(__spreadValues({
239
+ name: this.name,
240
+ message: this.message
241
+ }, cause === void 0 ? {} : {
242
+ cause
243
+ }), Object.fromEntries(Object.entries(this).filter(([key]) => key !== "cause")));
244
+ }
245
+ /**
246
+ * Recognizes branded errors from another bundled copy of this module, so
247
+ * `error instanceof SpecLoadError` works for a plugin-thrown error too.
248
+ * The prototype chain is checked first, so a caller's own subclass of these
249
+ * classes still matches even though it carries no lineage entry.
250
+ *
251
+ * Never throws and never runs foreign code: both reflective reads sit
252
+ * inside the try, because a Proxy traps `getPrototypeOf` just as readily as
253
+ * `getOwnPropertyDescriptor`.
254
+ */
255
+ static [Symbol.hasInstance](value) {
256
+ var _a;
257
+ if (typeof value !== "object" || value === null) {
258
+ return false;
259
+ }
260
+ try {
261
+ if (Object.prototype.isPrototypeOf.call(this.prototype, value)) {
262
+ return true;
263
+ }
264
+ const expected = (_a = ERROR_LINEAGE.get(this)) == null ? void 0 : _a[0];
265
+ if (expected === void 0) {
266
+ return false;
267
+ }
268
+ const descriptor = Object.getOwnPropertyDescriptor(value, NG_OPENAPI_ERROR_BRAND);
269
+ if (!descriptor || descriptor.enumerable || !("value" in descriptor)) {
270
+ return false;
271
+ }
272
+ return Array.isArray(descriptor.value) && descriptor.value.includes(expected);
273
+ } catch (e) {
274
+ return false;
275
+ }
170
276
  }
171
277
  };
172
278
  __name(_NgOpenApiError, "NgOpenApiError");
173
279
  var NgOpenApiError = _NgOpenApiError;
280
+ registerError(NgOpenApiError, [
281
+ "NgOpenApiError"
282
+ ]);
174
283
  var _SpecLoadError = class _SpecLoadError extends NgOpenApiError {
175
284
  constructor(message, source, cause) {
176
285
  super(message, cause);
@@ -181,6 +290,10 @@ var _SpecLoadError = class _SpecLoadError extends NgOpenApiError {
181
290
  };
182
291
  __name(_SpecLoadError, "SpecLoadError");
183
292
  var SpecLoadError = _SpecLoadError;
293
+ registerError(SpecLoadError, [
294
+ "SpecLoadError",
295
+ "NgOpenApiError"
296
+ ]);
184
297
  var _SpecParseError = class _SpecParseError extends NgOpenApiError {
185
298
  constructor(message, source, cause) {
186
299
  super(message, cause);
@@ -191,6 +304,108 @@ var _SpecParseError = class _SpecParseError extends NgOpenApiError {
191
304
  };
192
305
  __name(_SpecParseError, "SpecParseError");
193
306
  var SpecParseError = _SpecParseError;
307
+ registerError(SpecParseError, [
308
+ "SpecParseError",
309
+ "NgOpenApiError"
310
+ ]);
311
+ function describeOperation(operation) {
312
+ const location = `(${operation.method}) ${operation.path}`;
313
+ return operation.operationId ? `${operation.operationId} (${location})` : location;
314
+ }
315
+ __name(describeOperation, "describeOperation");
316
+ function captureOperation(operation) {
317
+ return Object.freeze({
318
+ operationId: operation.operationId,
319
+ method: operation.method,
320
+ path: operation.path
321
+ });
322
+ }
323
+ __name(captureOperation, "captureOperation");
324
+ var _InvalidIdentifierError = class _InvalidIdentifierError extends NgOpenApiError {
325
+ constructor(message, operation, identifier) {
326
+ super(message);
327
+ /** The rejected name, verbatim; absent when no name could be derived. */
328
+ __publicField(this, "identifier");
329
+ /** The operation whose name was being derived. */
330
+ __publicField(this, "operation");
331
+ this.operation = captureOperation(operation);
332
+ this.identifier = identifier;
333
+ }
334
+ };
335
+ __name(_InvalidIdentifierError, "InvalidIdentifierError");
336
+ var InvalidIdentifierError = _InvalidIdentifierError;
337
+ registerError(InvalidIdentifierError, [
338
+ "InvalidIdentifierError",
339
+ "NgOpenApiError"
340
+ ]);
341
+ var _DuplicateGeneratedNameError = class _DuplicateGeneratedNameError extends NgOpenApiError {
342
+ constructor(message, names, operations = []) {
343
+ super(message);
344
+ /** The colliding generated names. */
345
+ __publicField(this, "names");
346
+ /** The operations that produced them, when known. */
347
+ __publicField(this, "operations");
348
+ this.names = Object.freeze([
349
+ ...names
350
+ ]);
351
+ this.operations = Object.freeze(operations.map(captureOperation));
352
+ }
353
+ };
354
+ __name(_DuplicateGeneratedNameError, "DuplicateGeneratedNameError");
355
+ var DuplicateGeneratedNameError = _DuplicateGeneratedNameError;
356
+ registerError(DuplicateGeneratedNameError, [
357
+ "DuplicateGeneratedNameError",
358
+ "NgOpenApiError"
359
+ ]);
360
+ var _UnresolvedPathTemplateError = class _UnresolvedPathTemplateError extends NgOpenApiError {
361
+ constructor(message, path15, placeholders) {
362
+ super(message);
363
+ /** The path as written in the spec. */
364
+ __publicField(this, "path");
365
+ /** Placeholder names with no declared parameter. */
366
+ __publicField(this, "placeholders");
367
+ this.path = path15;
368
+ this.placeholders = Object.freeze([
369
+ ...placeholders
370
+ ]);
371
+ }
372
+ };
373
+ __name(_UnresolvedPathTemplateError, "UnresolvedPathTemplateError");
374
+ var UnresolvedPathTemplateError = _UnresolvedPathTemplateError;
375
+ registerError(UnresolvedPathTemplateError, [
376
+ "UnresolvedPathTemplateError",
377
+ "NgOpenApiError"
378
+ ]);
379
+ var _ConfigValidationError = class _ConfigValidationError extends NgOpenApiError {
380
+ constructor(issues) {
381
+ super(`Invalid ng-openapi configuration:
382
+ ${issues.map((issue) => ` - ${issue}`).join("\n")}`);
383
+ __publicField(this, "issues");
384
+ this.issues = Object.freeze([
385
+ ...issues
386
+ ]);
387
+ }
388
+ };
389
+ __name(_ConfigValidationError, "ConfigValidationError");
390
+ var ConfigValidationError = _ConfigValidationError;
391
+ registerError(ConfigValidationError, [
392
+ "ConfigValidationError",
393
+ "NgOpenApiError"
394
+ ]);
395
+ var _ConfigLoadError = class _ConfigLoadError extends NgOpenApiError {
396
+ constructor(message, source, cause) {
397
+ super(message, cause);
398
+ /** Path of the config file that failed to load. */
399
+ __publicField(this, "source");
400
+ this.source = source;
401
+ }
402
+ };
403
+ __name(_ConfigLoadError, "ConfigLoadError");
404
+ var ConfigLoadError = _ConfigLoadError;
405
+ registerError(ConfigLoadError, [
406
+ "ConfigLoadError",
407
+ "NgOpenApiError"
408
+ ]);
194
409
 
195
410
  // ../shared/src/core/spec-loader.ts
196
411
  function loadSpecContent(pathOrUrl) {
@@ -296,6 +511,439 @@ function detectFormat(content) {
296
511
  }
297
512
  __name(detectFormat, "detectFormat");
298
513
 
514
+ // ../shared/src/utils/string.utils.ts
515
+ var IDENTIFIER_SEPARATORS = /(?:_|[^\p{ID_Continue}$])+(.)?/gu;
516
+ var INVALID_IDENTIFIER_START = /^[^\p{ID_Start}$_]/u;
517
+ function toIdentifier(converted) {
518
+ if (converted === "") {
519
+ return "_";
520
+ }
521
+ return converted.replace(INVALID_IDENTIFIER_START, (char) => `_${char}`);
522
+ }
523
+ __name(toIdentifier, "toIdentifier");
524
+ function isValidIdentifier(name) {
525
+ return /^[\p{ID_Start}$_][\p{ID_Continue}$]*$/u.test(name);
526
+ }
527
+ __name(isValidIdentifier, "isValidIdentifier");
528
+ function camelCase(str) {
529
+ const converted = str.replace(IDENTIFIER_SEPARATORS, (_, char) => char ? char.toUpperCase() : "").replace(/^./u, (char) => char.toLowerCase());
530
+ return toIdentifier(converted);
531
+ }
532
+ __name(camelCase, "camelCase");
533
+ function kebabCase(str) {
534
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[-_\s]+/g, "-").toLowerCase();
535
+ }
536
+ __name(kebabCase, "kebabCase");
537
+ function pascalCase(str) {
538
+ const converted = str.replace(IDENTIFIER_SEPARATORS, (_, char) => char ? char.toUpperCase() : "").replace(/^./u, (char) => char.toUpperCase());
539
+ return toIdentifier(converted);
540
+ }
541
+ __name(pascalCase, "pascalCase");
542
+ function screamingSnakeCase(str) {
543
+ return str.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/[-\s]+/g, "_").toUpperCase();
544
+ }
545
+ __name(screamingSnakeCase, "screamingSnakeCase");
546
+ function pascalCaseForEnums(str) {
547
+ const converted = str.replace(/[^a-zA-Z0-9]/g, "_").replace(/(?:^|_)([a-z])/g, (_, char) => char.toUpperCase()).replace(/^([0-9])/, "_$1");
548
+ return converted === "" ? "_" : converted;
549
+ }
550
+ __name(pascalCaseForEnums, "pascalCaseForEnums");
551
+ function capitalizeFirst(str) {
552
+ return str.charAt(0).toUpperCase() + str.slice(1);
553
+ }
554
+ __name(capitalizeFirst, "capitalizeFirst");
555
+
556
+ // ../shared/src/core/inline-nested-refs.ts
557
+ function inlineNestedRefs(spec, onWarning) {
558
+ const ctx = {
559
+ root: spec,
560
+ onWarning,
561
+ warned: /* @__PURE__ */ new Set(),
562
+ emittedPerCause: /* @__PURE__ */ new Map(),
563
+ deferred: /* @__PURE__ */ new Map(),
564
+ budget: MAX_INLINED_NODES,
565
+ budgetExhausted: false
566
+ };
567
+ const result = transform(spec, ctx, [], false);
568
+ flushDeferredWarnings(ctx);
569
+ return result;
570
+ }
571
+ __name(inlineNestedRefs, "inlineNestedRefs");
572
+ var MAX_REF_DEPTH = 64;
573
+ var MAX_INLINED_NODES = 1e5;
574
+ var MAX_WARNINGS_PER_CAUSE = 10;
575
+ var WARNING_CAUSE_LABELS = {
576
+ cyclic: "cyclic nested $ref(s) left in place",
577
+ unresolvable: "unresolvable nested $ref(s) left in place",
578
+ "not-a-schema": "nested $ref(s) resolving to a non-schema value",
579
+ "not-a-schema-position": "nested $ref(s) that do not address a schema position",
580
+ depth: "nested $ref(s) past the pointer-hop limit",
581
+ budget: "nested $ref(s) left uninlined after the expansion budget ran out",
582
+ "sibling-conflict": "nested $ref site(s) whose siblings overrode the target",
583
+ "sibling-on-boolean": "nested $ref site(s) whose siblings were dropped on a boolean target",
584
+ "malformed-ref": "non-string $ref value(s)",
585
+ "unsupported-pointer-root": "deep $ref(s) into a root this pass does not inline"
586
+ };
587
+ var REFUSED = /* @__PURE__ */ Symbol("refused");
588
+ function transform(node, ctx, chain, keysAreNames) {
589
+ var _a;
590
+ if (Array.isArray(node)) {
591
+ let changed2 = false;
592
+ const items = node.map((item) => {
593
+ const next = transform(item, ctx, chain, false);
594
+ changed2 || (changed2 = next !== item);
595
+ return next;
596
+ });
597
+ return changed2 ? items : node;
598
+ }
599
+ if (!isPlainObject(node)) {
600
+ return node;
601
+ }
602
+ const ref = keysAreNames ? void 0 : node["$ref"];
603
+ if (typeof ref === "string") {
604
+ if (isDeepSchemaPointer(ref)) {
605
+ const inlined = inlineTarget(node, ref, ctx, chain);
606
+ if (inlined !== REFUSED) {
607
+ return inlined;
608
+ }
609
+ } else if (isDeepPointerIntoUnsupportedRoot(ref)) {
610
+ const emittedName = pascalCase((_a = ref.split("/").pop()) != null ? _a : "");
611
+ warnOnce(ctx, "unsupported-pointer-root", ref, `Nested $ref "${ref}" points into a part of the document this generator does not inline (only #/components/schemas/\u2026 and #/definitions/\u2026 are) \u2014 it will be emitted as the type "${emittedName}", which nothing defines. Promote the target to a named schema and reference that. ${WRONG_TYPE_SUFFIX}`);
612
+ }
613
+ } else if (ref !== void 0) {
614
+ warnOnce(ctx, "malformed-ref", safeStringify(ref), `Ignoring a "$ref" whose value is ${describeKind(ref)}, not a string (${safeStringify(ref)}) \u2014 a $ref must be a JSON pointer string.`);
615
+ }
616
+ let changed = false;
617
+ const entries = Object.entries(node).map(([key, value]) => {
618
+ const next = transformEntry(key, value, ctx, chain, keysAreNames);
619
+ changed || (changed = next !== value);
620
+ return [
621
+ key,
622
+ next
623
+ ];
624
+ });
625
+ return changed ? Object.fromEntries(entries) : node;
626
+ }
627
+ __name(transform, "transform");
628
+ function transformEntry(key, value, ctx, chain, keysAreNames) {
629
+ if (!keysAreNames && PAYLOAD_KEYS.has(key)) {
630
+ return value;
631
+ }
632
+ return transform(value, ctx, chain, !keysAreNames && NAME_KEYED_CONTAINERS.has(key));
633
+ }
634
+ __name(transformEntry, "transformEntry");
635
+ function inlineTarget(node, ref, ctx, chain) {
636
+ if (chain.includes(ref)) {
637
+ warnOnce(ctx, "cyclic", ref, `Nested $ref "${ref}" is cyclic and cannot be inlined finitely \u2014 restructure the target as a named definition. ${WRONG_TYPE_SUFFIX}`);
638
+ return REFUSED;
639
+ }
640
+ const target = resolvePointer(ctx.root, ref);
641
+ if (target === void 0) {
642
+ warnOnce(ctx, "unresolvable", ref, `Could not resolve nested $ref "${ref}". ${WRONG_TYPE_SUFFIX}`);
643
+ return REFUSED;
644
+ }
645
+ if (!isPlainObject(target) && typeof target !== "boolean") {
646
+ warnOnce(ctx, "not-a-schema", ref, `Nested $ref "${ref}" resolves to ${describeKind(target)}, not a schema \u2014 point it at a schema object. ${WRONG_TYPE_SUFFIX}`);
647
+ return REFUSED;
648
+ }
649
+ const nonSchemaSegment = firstNonSchemaSegment(ref);
650
+ if (nonSchemaSegment !== void 0) {
651
+ warnOnce(ctx, "not-a-schema-position", ref, `Nested $ref "${ref}" does not address a schema \u2014 its "${nonSchemaSegment}" segment is not a schema-valued position (expected one of properties/<name>, items, additionalProperties, allOf|anyOf|oneOf/<index>, not, $defs/<name>). ${WRONG_TYPE_SUFFIX}`);
652
+ return REFUSED;
653
+ }
654
+ if (chain.length >= MAX_REF_DEPTH) {
655
+ warnOnce(ctx, "depth", ref, `Nested $ref "${ref}" is more than ${MAX_REF_DEPTH} pointer hops deep and was left uninlined \u2014 restructure the target as a named definition. ${WRONG_TYPE_SUFFIX}`);
656
+ return REFUSED;
657
+ }
658
+ if (ctx.budgetExhausted) {
659
+ warnOnce(ctx, "budget", ref, `Nested $ref "${ref}" was left uninlined: the ${MAX_INLINED_NODES}-node expansion budget was already exhausted earlier in this spec. ${WRONG_TYPE_SUFFIX}`);
660
+ return REFUSED;
661
+ }
662
+ const cost = countNodes(target);
663
+ if (cost > ctx.budget) {
664
+ ctx.budgetExhausted = true;
665
+ warnOnce(ctx, "budget", ref, `Inlining nested $refs exceeded the ${MAX_INLINED_NODES}-node expansion budget at "${ref}" \u2014 it and every deep $ref after it were left uninlined. The spec expands combinatorially; restructure the repeated targets as named definitions. ${WRONG_TYPE_SUFFIX}`);
666
+ return REFUSED;
667
+ }
668
+ ctx.budget -= cost;
669
+ const inlined = transform(structuredClone(target), ctx, [
670
+ ...chain,
671
+ ref
672
+ ], false);
673
+ return mergeSiblings(node, inlined, ref, ctx, chain);
674
+ }
675
+ __name(inlineTarget, "inlineTarget");
676
+ var WRONG_TYPE_SUFFIX = "The generated type will not match the spec (generated files ship @ts-nocheck, so this surfaces as a silently wrong type rather than a compile error).";
677
+ var PAYLOAD_KEYS = /* @__PURE__ */ new Set([
678
+ "example",
679
+ "examples",
680
+ "default",
681
+ "enum",
682
+ "const"
683
+ ]);
684
+ var NAME_KEYED_CONTAINERS = /* @__PURE__ */ new Set([
685
+ // Schema keyword maps
686
+ "properties",
687
+ "patternProperties",
688
+ "dependentSchemas",
689
+ "$defs",
690
+ "definitions",
691
+ // Document-level maps keyed by name, status code, path or media type
692
+ "schemas",
693
+ "responses",
694
+ "parameters",
695
+ "requestBodies",
696
+ "headers",
697
+ "securitySchemes",
698
+ "links",
699
+ "callbacks",
700
+ "encoding",
701
+ "variables",
702
+ "content",
703
+ "paths",
704
+ "webhooks",
705
+ "pathItems"
706
+ ]);
707
+ function mergeSiblings(node, inlined, ref, ctx, chain) {
708
+ const siblings = Object.entries(node).filter(([key]) => key !== "$ref");
709
+ if (siblings.length === 0) {
710
+ return inlined;
711
+ }
712
+ if (!isPlainObject(inlined)) {
713
+ const dropped = siblings.map(([key]) => key);
714
+ warnOnce(ctx, "sibling-on-boolean", ref, `Nested $ref "${ref}" resolves to a boolean schema, so the keys next to it (${dropped.join(", ")}) were dropped.`, dropped);
715
+ return inlined;
716
+ }
717
+ const conflicts = siblings.filter(([key, value]) => !ANNOTATION_ONLY_KEYS.has(key) && Object.prototype.hasOwnProperty.call(inlined, key) && !sameValue(value, inlined[key])).map(([key]) => key);
718
+ if (conflicts.length > 0) {
719
+ warnOnce(ctx, "sibling-conflict", ref, `Nested $ref "${ref}" sits next to key(s) (${conflicts.join(", ")}) that its target also defines \u2014 the local value won and the target's was dropped, per JSON Schema 2020-12, where $ref composes with its siblings; OpenAPI 3.0 would have ignored the local one instead. The generated type follows the sibling, not the target \u2014 drop it if the target's value was meant to apply.`, conflicts);
720
+ }
721
+ return Object.fromEntries([
722
+ ...Object.entries(inlined),
723
+ // The ref node is a schema, so its keys are keywords: a payload sibling
724
+ // stays verbatim, exactly as it would one level up.
725
+ ...siblings.map(([key, value]) => [
726
+ key,
727
+ transformEntry(key, value, ctx, chain, false)
728
+ ])
729
+ ]);
730
+ }
731
+ __name(mergeSiblings, "mergeSiblings");
732
+ var ANNOTATION_ONLY_KEYS = /* @__PURE__ */ new Set([
733
+ "description",
734
+ "title",
735
+ "summary",
736
+ "example",
737
+ "examples",
738
+ "externalDocs",
739
+ "deprecated",
740
+ "xml",
741
+ "$comment"
742
+ ]);
743
+ function sameValue(a, b) {
744
+ if (a === b) {
745
+ return true;
746
+ }
747
+ if (Array.isArray(a) || Array.isArray(b)) {
748
+ return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((item, index) => sameValue(item, b[index]));
749
+ }
750
+ if (isPlainObject(a) && isPlainObject(b)) {
751
+ const keys = Object.keys(a);
752
+ return keys.length === Object.keys(b).length && keys.every((key) => Object.prototype.hasOwnProperty.call(b, key) && sameValue(a[key], b[key]));
753
+ }
754
+ return typeof a === "object" && typeof b === "object" && safeStringify(a) === safeStringify(b);
755
+ }
756
+ __name(sameValue, "sameValue");
757
+ function warnOnce(ctx, cause, ref, message, site) {
758
+ var _a, _b, _c;
759
+ const key = site === void 0 ? `${cause}:${ref}` : `${cause}:${ref}|${[
760
+ ...site
761
+ ].sort().join(",")}`;
762
+ if (ctx.warned.has(key)) {
763
+ return;
764
+ }
765
+ ctx.warned.add(key);
766
+ const emitted = (_a = ctx.emittedPerCause.get(cause)) != null ? _a : 0;
767
+ if (emitted >= MAX_WARNINGS_PER_CAUSE) {
768
+ const refs = (_b = ctx.deferred.get(cause)) != null ? _b : /* @__PURE__ */ new Set();
769
+ refs.add(ref);
770
+ ctx.deferred.set(cause, refs);
771
+ return;
772
+ }
773
+ ctx.emittedPerCause.set(cause, emitted + 1);
774
+ (_c = ctx.onWarning) == null ? void 0 : _c.call(ctx, message);
775
+ }
776
+ __name(warnOnce, "warnOnce");
777
+ function flushDeferredWarnings(ctx) {
778
+ var _a;
779
+ for (const [cause, refs] of ctx.deferred) {
780
+ (_a = ctx.onWarning) == null ? void 0 : _a.call(ctx, `\u2026and ${refs.size} more ${WARNING_CAUSE_LABELS[cause]} (only the first ${MAX_WARNINGS_PER_CAUSE} are reported in full): ${[
781
+ ...refs
782
+ ].join(", ")}.`);
783
+ }
784
+ }
785
+ __name(flushDeferredWarnings, "flushDeferredWarnings");
786
+ function describeKind(value) {
787
+ var _a, _b;
788
+ if (value === null) {
789
+ return "null";
790
+ }
791
+ if (Array.isArray(value)) {
792
+ return "an array";
793
+ }
794
+ if (isPlainObject(value)) {
795
+ return "an object";
796
+ }
797
+ if (typeof value === "object") {
798
+ const className = (_b = (_a = Object.getPrototypeOf(value)) == null ? void 0 : _a.constructor) == null ? void 0 : _b.name;
799
+ return typeof className === "string" ? `a ${className}` : "a non-plain object";
800
+ }
801
+ return `a ${typeof value}`;
802
+ }
803
+ __name(describeKind, "describeKind");
804
+ function safeStringify(value) {
805
+ var _a;
806
+ try {
807
+ return (_a = JSON.stringify(value)) != null ? _a : String(value);
808
+ } catch (e) {
809
+ return String(value);
810
+ }
811
+ }
812
+ __name(safeStringify, "safeStringify");
813
+ function countNodes(value) {
814
+ if (Array.isArray(value)) {
815
+ return value.reduce((total, item) => total + countNodes(item), 1);
816
+ }
817
+ if (!isPlainObject(value)) {
818
+ return 1;
819
+ }
820
+ return Object.values(value).reduce((total, item) => total + countNodes(item), 1);
821
+ }
822
+ __name(countNodes, "countNodes");
823
+ function isDeepSchemaPointer(ref) {
824
+ if (!ref.startsWith("#/")) {
825
+ return false;
826
+ }
827
+ const segments = ref.slice(2).split("/");
828
+ if (segments[0] === "components" && segments[1] === "schemas") {
829
+ return segments.length > 3;
830
+ }
831
+ if (segments[0] === "definitions") {
832
+ return segments.length > 2;
833
+ }
834
+ return false;
835
+ }
836
+ __name(isDeepSchemaPointer, "isDeepSchemaPointer");
837
+ function isDeepPointerIntoUnsupportedRoot(ref) {
838
+ if (!ref.startsWith("#/") || isDeepSchemaPointer(ref)) {
839
+ return false;
840
+ }
841
+ const segments = ref.slice(2).split("/");
842
+ const wholeEntryDepth = segments[0] === "components" ? 3 : 2;
843
+ return segments.length > wholeEntryDepth;
844
+ }
845
+ __name(isDeepPointerIntoUnsupportedRoot, "isDeepPointerIntoUnsupportedRoot");
846
+ var SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
847
+ "not",
848
+ "additionalProperties",
849
+ "unevaluatedItems",
850
+ "unevaluatedProperties",
851
+ "contains",
852
+ "propertyNames",
853
+ "contentSchema",
854
+ "if",
855
+ "then",
856
+ "else"
857
+ ]);
858
+ var SCHEMA_MAP_KEYWORDS = /* @__PURE__ */ new Set([
859
+ "properties",
860
+ "patternProperties",
861
+ "dependentSchemas",
862
+ "$defs",
863
+ "definitions"
864
+ ]);
865
+ var SCHEMA_LIST_KEYWORDS = /* @__PURE__ */ new Set([
866
+ "allOf",
867
+ "anyOf",
868
+ "oneOf",
869
+ "prefixItems"
870
+ ]);
871
+ var SCHEMA_OR_LIST_KEYWORDS = /* @__PURE__ */ new Set([
872
+ "items",
873
+ "additionalItems"
874
+ ]);
875
+ function firstNonSchemaSegment(ref) {
876
+ const segments = pointerSegments(ref);
877
+ const rest = segments.slice(segments[0] === "definitions" ? 2 : 3);
878
+ let position = "schema";
879
+ for (const segment of rest) {
880
+ if (position === "schema-map") {
881
+ position = "schema";
882
+ continue;
883
+ }
884
+ if (position === "schema-list") {
885
+ if (toArrayIndex(segment) === void 0) {
886
+ return segment;
887
+ }
888
+ position = "schema";
889
+ continue;
890
+ }
891
+ if (position === "schema-or-list" && toArrayIndex(segment) !== void 0) {
892
+ position = "schema";
893
+ continue;
894
+ }
895
+ if (SCHEMA_KEYWORDS.has(segment)) {
896
+ position = "schema";
897
+ } else if (SCHEMA_MAP_KEYWORDS.has(segment)) {
898
+ position = "schema-map";
899
+ } else if (SCHEMA_LIST_KEYWORDS.has(segment)) {
900
+ position = "schema-list";
901
+ } else if (SCHEMA_OR_LIST_KEYWORDS.has(segment)) {
902
+ position = "schema-or-list";
903
+ } else {
904
+ return segment;
905
+ }
906
+ }
907
+ return position === "schema" || position === "schema-or-list" ? void 0 : rest[rest.length - 1];
908
+ }
909
+ __name(firstNonSchemaSegment, "firstNonSchemaSegment");
910
+ function pointerSegments(ref) {
911
+ return ref.slice(2).split("/").map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~"));
912
+ }
913
+ __name(pointerSegments, "pointerSegments");
914
+ function resolvePointer(root, ref) {
915
+ let current = root;
916
+ const segments = pointerSegments(ref);
917
+ for (const segment of segments) {
918
+ if (Array.isArray(current)) {
919
+ const index = toArrayIndex(segment);
920
+ if (index === void 0 || index >= current.length) {
921
+ return void 0;
922
+ }
923
+ current = current[index];
924
+ continue;
925
+ }
926
+ if (!isPlainObject(current) || !Object.prototype.hasOwnProperty.call(current, segment)) {
927
+ return void 0;
928
+ }
929
+ current = current[segment];
930
+ }
931
+ return current;
932
+ }
933
+ __name(resolvePointer, "resolvePointer");
934
+ function toArrayIndex(segment) {
935
+ return /^(?:0|[1-9][0-9]*)$/.test(segment) ? Number(segment) : void 0;
936
+ }
937
+ __name(toArrayIndex, "toArrayIndex");
938
+ function isPlainObject(value) {
939
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
940
+ return false;
941
+ }
942
+ const proto = Object.getPrototypeOf(value);
943
+ return proto === Object.prototype || proto === null;
944
+ }
945
+ __name(isPlainObject, "isPlainObject");
946
+
299
947
  // ../shared/src/utils/content-types.constants.ts
300
948
  var CONTENT_TYPES = {
301
949
  MULTIPART: "multipart/form-data",
@@ -312,20 +960,20 @@ function extractPaths(swaggerPaths = {}, methods = [
312
960
  "delete",
313
961
  "options",
314
962
  "head"
315
- ]) {
963
+ ], onWarning, resolveParameter) {
316
964
  const paths = [];
317
- Object.entries(swaggerPaths).forEach(([path14, pathItem]) => {
965
+ Object.entries(swaggerPaths).forEach(([path15, pathItem]) => {
318
966
  methods.forEach((method) => {
319
967
  const operation = pathItem[method];
320
968
  if (operation) {
321
969
  paths.push({
322
- path: path14,
970
+ path: path15,
323
971
  method: method.toUpperCase(),
324
- operationId: operation.operationId,
972
+ operationId: asName(operation.operationId),
325
973
  summary: operation.summary,
326
974
  description: operation.description,
327
- tags: operation.tags || [],
328
- parameters: parseParameters(operation.parameters || [], pathItem.parameters || []),
975
+ tags: Array.isArray(operation.tags) ? operation.tags.flatMap(nameOrNothing) : [],
976
+ parameters: parseParameters(operation.parameters || [], pathItem.parameters || [], `(${method.toUpperCase()}) ${path15}`, onWarning, resolveParameter),
329
977
  requestBody: operation.requestBody,
330
978
  responses: operation.responses || {}
331
979
  });
@@ -335,13 +983,55 @@ function extractPaths(swaggerPaths = {}, methods = [
335
983
  return paths;
336
984
  }
337
985
  __name(extractPaths, "extractPaths");
338
- function parseParameters(operationParams, pathParams) {
986
+ function asName(value) {
987
+ if (typeof value === "string") {
988
+ return value;
989
+ }
990
+ return typeof value === "number" && Number.isFinite(value) ? String(value) : void 0;
991
+ }
992
+ __name(asName, "asName");
993
+ function nameOrNothing(value) {
994
+ const name = asName(value);
995
+ return name === void 0 ? [] : [
996
+ name
997
+ ];
998
+ }
999
+ __name(nameOrNothing, "nameOrNothing");
1000
+ function parseParameters(operationParams, pathParams, location, onWarning, resolveParameter) {
339
1001
  const allParams = [
340
1002
  ...pathParams,
341
1003
  ...operationParams
342
- ];
343
- return allParams.map((param) => ({
344
- name: param.name,
1004
+ ].flatMap((param) => {
1005
+ var _a;
1006
+ const ref = param.$ref;
1007
+ if (typeof ref !== "string") {
1008
+ return [
1009
+ param
1010
+ ];
1011
+ }
1012
+ const resolution = (_a = resolveParameter == null ? void 0 : resolveParameter(ref)) != null ? _a : {
1013
+ problem: "cannot be resolved here: no reusable parameters were provided"
1014
+ };
1015
+ if ("parameter" in resolution) {
1016
+ return [
1017
+ resolution.parameter
1018
+ ];
1019
+ }
1020
+ onWarning == null ? void 0 : onWarning(`A parameter of ${location} references "${ref}", which ${resolution.problem}. The parameter was skipped.`);
1021
+ return [];
1022
+ });
1023
+ const named = allParams.filter((param) => {
1024
+ const name = asName(param.name);
1025
+ if (name !== void 0 && name !== "") {
1026
+ return true;
1027
+ }
1028
+ const where = typeof param.in === "string" ? `${param.in} parameter` : "parameter";
1029
+ const shown = param.name === void 0 ? "no name" : `name ${JSON.stringify(param.name)}`;
1030
+ onWarning == null ? void 0 : onWarning(`A ${where} of ${location} has ${shown} and was skipped. Give it a name in the spec.`);
1031
+ return false;
1032
+ });
1033
+ return named.map((param) => ({
1034
+ name: asName(param.name),
345
1035
  in: param.in,
346
1036
  required: param.required || param.in === "path",
347
1037
  schema: param.schema,
@@ -352,27 +1042,43 @@ function parseParameters(operationParams, pathParams) {
352
1042
  }
353
1043
  __name(parseParameters, "parseParameters");
354
1044
 
355
- // ../shared/src/utils/string.utils.ts
356
- function camelCase(str) {
357
- return str.replace(/[-_.\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : "").replace(/^./, (char) => char.toLowerCase());
1045
+ // ../shared/src/emit/literal.emit.ts
1046
+ function quoteLiteral(value) {
1047
+ return `'${escapeSingleQuoted(value)}'`;
358
1048
  }
359
- __name(camelCase, "camelCase");
360
- function kebabCase(str) {
361
- return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[-_\s]+/g, "-").toLowerCase();
1049
+ __name(quoteLiteral, "quoteLiteral");
1050
+ function escapeSingleQuoted(value) {
1051
+ return value.replace(/[\\']/g, (char) => `\\${char}`).replace(/\r/g, "\\r").replace(/\n/g, "\\n");
362
1052
  }
363
- __name(kebabCase, "kebabCase");
364
- function pascalCase(str) {
365
- return str.replace(/[-_.\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : "").replace(/^./, (char) => char.toUpperCase());
1053
+ __name(escapeSingleQuoted, "escapeSingleQuoted");
1054
+ function escapeTemplateLiteral(value) {
1055
+ return value.replace(/[\\`]/g, (char) => `\\${char}`).replace(/\$\{/g, "\\${").replace(/\r/g, "\\r");
366
1056
  }
367
- __name(pascalCase, "pascalCase");
368
- function screamingSnakeCase(str) {
369
- return str.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/[-\s]+/g, "_").toUpperCase();
1057
+ __name(escapeTemplateLiteral, "escapeTemplateLiteral");
1058
+ function emitObjectKey(name, quoteStyle = "double") {
1059
+ const quoted = quoteStyle === "single" ? quoteLiteral(name) : `"${escapeDoubleQuoted(name)}"`;
1060
+ return name === "__proto__" ? `[${quoted}]` : quoted;
370
1061
  }
371
- __name(screamingSnakeCase, "screamingSnakeCase");
372
- function pascalCaseForEnums(str) {
373
- return str.replace(/[^a-zA-Z0-9]/g, "_").replace(/(?:^|_)([a-z])/g, (_, char) => char.toUpperCase()).replace(/^([0-9])/, "_$1");
1062
+ __name(emitObjectKey, "emitObjectKey");
1063
+ function escapeDoubleQuoted(value) {
1064
+ return value.replace(/[\\"]/g, (char) => `\\${char}`).replace(/\r/g, "\\r").replace(/\n/g, "\\n");
374
1065
  }
375
- __name(pascalCaseForEnums, "pascalCaseForEnums");
1066
+ __name(escapeDoubleQuoted, "escapeDoubleQuoted");
1067
+ function emitPropertyName(name) {
1068
+ return IDENTIFIER_NAME.test(name) ? name : `"${escapeDoubleQuoted(name)}"`;
1069
+ }
1070
+ __name(emitPropertyName, "emitPropertyName");
1071
+ var IDENTIFIER_NAME = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
1072
+ function escapeJsDoc(text) {
1073
+ return text.replace(/\*\//g, "*\\/");
1074
+ }
1075
+ __name(escapeJsDoc, "escapeJsDoc");
1076
+ function emitDocs(description) {
1077
+ return typeof description === "string" && description ? [
1078
+ escapeJsDoc(description)
1079
+ ] : void 0;
1080
+ }
1081
+ __name(emitDocs, "emitDocs");
376
1082
 
377
1083
  // ../shared/src/utils/functions/class-names.ts
378
1084
  function decorate(base, defaultSuffix, naming) {
@@ -422,7 +1128,7 @@ function getTypeScriptType(schemaOrType, config, formatOrNullable, isNullable, c
422
1128
  switch (schema.type) {
423
1129
  case "string":
424
1130
  if (schema.enum) {
425
- return schema.enum.map((value) => typeof value === "string" ? `'${escapeString(value)}'` : String(value)).join(" | ");
1131
+ return schema.enum.map((value) => typeof value === "string" ? `'${escapeSingleQuoted(value)}'` : String(value)).join(" | ");
426
1132
  }
427
1133
  if (schema.format === "date" || schema.format === "date-time") {
428
1134
  const dateType = config.options.dateType === "Date" ? "Date" : "string";
@@ -458,10 +1164,6 @@ function nullableType(type, isNullable) {
458
1164
  return type + (isNullable ? " | null" : "");
459
1165
  }
460
1166
  __name(nullableType, "nullableType");
461
- function escapeString(str) {
462
- return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
463
- }
464
- __name(escapeString, "escapeString");
465
1167
 
466
1168
  // ../shared/src/utils/functions/extract-swagger-response-type.ts
467
1169
  function getResponseTypeFromResponse(response, responseTypeMapping) {
@@ -610,7 +1312,7 @@ function getResponseType(response, config) {
610
1312
  __name(getResponseType, "getResponseType");
611
1313
 
612
1314
  // ../shared/src/core/normalize.ts
613
- function normalizeSpec(spec) {
1315
+ function normalizeSpec(spec, onWarning) {
614
1316
  var _a;
615
1317
  const rawDefinitions = spec.definitions || ((_a = spec.components) == null ? void 0 : _a.schemas) || {};
616
1318
  const definitions = Object.fromEntries(Object.entries(rawDefinitions).map(([name, definition]) => [
@@ -621,6 +1323,7 @@ function normalizeSpec(spec) {
621
1323
  const parts = ref.split("/");
622
1324
  return definitions[parts[parts.length - 1]];
623
1325
  }, "resolveReference");
1326
+ const resolveParameter = createParameterResolver(spec);
624
1327
  return {
625
1328
  version: spec.swagger ? {
626
1329
  type: "swagger",
@@ -630,7 +1333,7 @@ function normalizeSpec(spec) {
630
1333
  version: spec.openapi
631
1334
  } : null,
632
1335
  definitions,
633
- operations: extractPaths(spec.paths).map((operation) => normalizeOperation(normalizeOperationSchemas(operation), resolveReference)),
1336
+ operations: extractPaths(spec.paths, void 0, onWarning, resolveParameter).map((operation) => normalizeOperation(normalizeOperationSchemas(operation), resolveReference, onWarning)),
634
1337
  resolveReference
635
1338
  };
636
1339
  }
@@ -714,24 +1417,29 @@ function normalizeContentSchemas(content) {
714
1417
  ]));
715
1418
  }
716
1419
  __name(normalizeContentSchemas, "normalizeContentSchemas");
717
- function normalizeOperation(operation, resolveRef) {
1420
+ function normalizeOperation(operation, resolveRef, onWarning) {
718
1421
  var _a, _b, _c;
1422
+ warnAboutUnboundParameters(operation, onWarning);
719
1423
  const content = (_a = operation.requestBody) == null ? void 0 : _a.content;
720
1424
  const isMultipart = !!(content == null ? void 0 : content[CONTENT_TYPES.MULTIPART]);
721
1425
  const isUrlEncoded = !!(content == null ? void 0 : content[CONTENT_TYPES.FORM_URLENCODED]) && !(content == null ? void 0 : content[CONTENT_TYPES.JSON]);
722
1426
  const formDataSchema = isMultipart ? resolveBodySchema(operation.requestBody, CONTENT_TYPES.MULTIPART, resolveRef) : void 0;
723
1427
  const urlEncodedSchema = isUrlEncoded ? resolveBodySchema(operation.requestBody, CONTENT_TYPES.FORM_URLENCODED, resolveRef) : void 0;
724
1428
  const responseInfo = determineResponseInfo(operation);
1429
+ const pathParams = ((_b = operation.parameters) == null ? void 0 : _b.filter((p) => p.in === "path")) || [];
1430
+ const queryParams = ((_c = operation.parameters) == null ? void 0 : _c.filter((p) => p.in === "query")) || [];
1431
+ const formDataFields = Object.keys((formDataSchema == null ? void 0 : formDataSchema.properties) || {});
1432
+ const urlEncodedFields = Object.keys((urlEncodedSchema == null ? void 0 : urlEncodedSchema.properties) || {});
725
1433
  return __spreadProps(__spreadValues({}, operation), {
726
- pathParams: ((_b = operation.parameters) == null ? void 0 : _b.filter((p) => p.in === "path")) || [],
727
- queryParams: ((_c = operation.parameters) == null ? void 0 : _c.filter((p) => p.in === "query")) || [],
1434
+ pathParams,
1435
+ queryParams,
728
1436
  hasBody: !!operation.requestBody,
729
1437
  isMultipart,
730
1438
  isUrlEncoded,
731
1439
  formDataSchema,
732
- formDataFields: Object.keys((formDataSchema == null ? void 0 : formDataSchema.properties) || {}),
1440
+ formDataFields,
733
1441
  urlEncodedSchema,
734
- urlEncodedFields: Object.keys((urlEncodedSchema == null ? void 0 : urlEncodedSchema.properties) || {}),
1442
+ urlEncodedFields,
735
1443
  responseType: responseInfo.responseType,
736
1444
  acceptHeader: responseInfo.acceptHeader
737
1445
  });
@@ -762,31 +1470,107 @@ function determineResponseInfo(operation) {
762
1470
  };
763
1471
  }
764
1472
  __name(determineResponseInfo, "determineResponseInfo");
1473
+ function createParameterResolver(spec) {
1474
+ var _a, _b;
1475
+ const components = (_b = spec.swagger ? spec.parameters : (_a = spec.components) == null ? void 0 : _a.parameters) != null ? _b : {};
1476
+ const prefix = spec.swagger ? "#/parameters/" : "#/components/parameters/";
1477
+ return (ref) => {
1478
+ const chain = [];
1479
+ let current = ref;
1480
+ for (; ; ) {
1481
+ if (chain.includes(current)) {
1482
+ return {
1483
+ problem: `is part of a reference cycle (${[
1484
+ ...chain,
1485
+ current
1486
+ ].map((r) => `"${r}"`).join(" -> ")})`
1487
+ };
1488
+ }
1489
+ chain.push(current);
1490
+ const hash = current.indexOf("#");
1491
+ if (hash > 0) {
1492
+ return {
1493
+ problem: `points into another document ("${current.slice(0, hash)}"); references into other documents are not supported, so bundle the spec into one document first`
1494
+ };
1495
+ }
1496
+ if (!current.startsWith(prefix)) {
1497
+ return {
1498
+ problem: `is not a parameter component pointer (expected "${prefix}<name>")`
1499
+ };
1500
+ }
1501
+ const name = current.slice(prefix.length).replace(/~1/g, "/").replace(/~0/g, "~");
1502
+ const candidate = Object.prototype.hasOwnProperty.call(components, name) ? components[name] : void 0;
1503
+ if (!candidate || typeof candidate !== "object") {
1504
+ return {
1505
+ problem: `does not resolve: there is no parameter component named "${name}"`
1506
+ };
1507
+ }
1508
+ const next = candidate.$ref;
1509
+ if (typeof next === "string") {
1510
+ current = next;
1511
+ continue;
1512
+ }
1513
+ return {
1514
+ parameter: candidate
1515
+ };
1516
+ }
1517
+ };
1518
+ }
1519
+ __name(createParameterResolver, "createParameterResolver");
1520
+ function warnAboutUnboundParameters(operation, onWarning) {
1521
+ var _a;
1522
+ for (const param of (_a = operation.parameters) != null ? _a : []) {
1523
+ if (param.in === "path" || param.in === "query") {
1524
+ continue;
1525
+ }
1526
+ if (param.in === "header" || param.in === "cookie") {
1527
+ if (param.required) {
1528
+ onWarning == null ? void 0 : onWarning(`Required ${param.in} parameter "${param.name}" of ${describeOperation(operation)} is not bound by the generated clients \u2014 callers must pass it through the trailing options parameter.`);
1529
+ }
1530
+ continue;
1531
+ }
1532
+ const kind = param.in === "formData" || param.in === "body" ? `Swagger 2.0 \`in: ${param.in}\`` : `\`in: ${String(param.in)}\``;
1533
+ onWarning == null ? void 0 : onWarning(`${kind} parameter "${param.name}" of ${describeOperation(operation)} is not supported and was dropped` + (param.required ? " (it is marked required)" : "") + ". Describe it as a requestBody, or as a path or query parameter, to have it generated.");
1534
+ }
1535
+ }
1536
+ __name(warnAboutUnboundParameters, "warnAboutUnboundParameters");
765
1537
 
766
1538
  // ../shared/src/core/swagger-parser.ts
767
1539
  var _SwaggerParser = class _SwaggerParser {
768
- constructor(spec, config) {
1540
+ constructor(spec, onWarning) {
769
1541
  __publicField(this, "spec");
770
1542
  __publicField(this, "normalized");
771
- var _a, _b;
772
- const isInputValid = (_b = (_a = config.validateInput) == null ? void 0 : _a.call(config, spec)) != null ? _b : true;
773
- if (!isInputValid) {
774
- throw new SpecParseError("Swagger spec is not valid. Check your `validateInput` condition.");
775
- }
1543
+ /** Non-fatal problems found while normalizing — a parameter with no usable name, for one. */
1544
+ __publicField(this, "onWarning");
776
1545
  this.spec = spec;
1546
+ this.onWarning = onWarning;
777
1547
  }
778
1548
  /**
779
1549
  * Loads, parses and wraps a spec.
780
1550
  *
1551
+ * @param onWarning receives non-fatal spec problems found while parsing or
1552
+ * normalizing — a deep-pointer `$ref` that cannot be inlined, a parameter
1553
+ * with no usable name.
781
1554
  * @throws SpecLoadError when the file/URL cannot be read.
782
- * @throws SpecParseError when the content cannot be parsed or the
783
- * config's `validateInput` hook rejects the spec.
1555
+ * @throws SpecParseError when the content cannot be parsed, `$ref` inlining
1556
+ * fails, or the config's `validateInput` hook rejects the spec.
784
1557
  */
785
- static create(swaggerPathOrUrl, config) {
1558
+ static create(swaggerPathOrUrl, config, onWarning) {
786
1559
  return __async(this, null, function* () {
1560
+ var _a, _b;
787
1561
  const swaggerContent = yield loadSpecContent(swaggerPathOrUrl);
788
1562
  const spec = parseSpecContent(swaggerContent, swaggerPathOrUrl);
789
- return new _SwaggerParser(spec, config);
1563
+ const isInputValid = (_b = (_a = config.validateInput) == null ? void 0 : _a.call(config, spec)) != null ? _b : true;
1564
+ if (!isInputValid) {
1565
+ throw new SpecParseError("Swagger spec is not valid. Check your `validateInput` condition.");
1566
+ }
1567
+ let inlinedSpec;
1568
+ try {
1569
+ inlinedSpec = inlineNestedRefs(spec, onWarning);
1570
+ } catch (error) {
1571
+ throw new SpecParseError(`Failed to inline nested $refs in the spec: ${error instanceof Error ? error.message : String(error)}`, swaggerPathOrUrl, error);
1572
+ }
1573
+ return new _SwaggerParser(inlinedSpec, onWarning);
790
1574
  });
791
1575
  }
792
1576
  /**
@@ -796,7 +1580,7 @@ var _SwaggerParser = class _SwaggerParser {
796
1580
  */
797
1581
  getNormalizedSpec() {
798
1582
  var _a;
799
- (_a = this.normalized) != null ? _a : this.normalized = normalizeSpec(this.spec);
1583
+ (_a = this.normalized) != null ? _a : this.normalized = normalizeSpec(this.spec, this.onWarning);
800
1584
  return this.normalized;
801
1585
  }
802
1586
  /** Definition map regardless of version: 2.0 `definitions` or 3.x `components.schemas`. */
@@ -827,20 +1611,20 @@ var _SwaggerParser = class _SwaggerParser {
827
1611
  }
828
1612
  /** Whether the spec declares a supported version (Swagger 2.x or OpenAPI 3.x). */
829
1613
  isValidSpec() {
830
- return !!(this.spec.swagger && this.spec.swagger.startsWith("2.") || this.spec.openapi && this.spec.openapi.startsWith("3."));
1614
+ return specVersionOf(this.spec.swagger, "2.") || specVersionOf(this.spec.openapi, "3.");
831
1615
  }
832
1616
  /** Detected flavor + literal version string, or null when neither field is present. */
833
1617
  getSpecVersion() {
834
- if (this.spec.swagger) {
1618
+ if (this.spec.swagger !== void 0 && this.spec.swagger !== null) {
835
1619
  return {
836
1620
  type: "swagger",
837
- version: this.spec.swagger
1621
+ version: String(this.spec.swagger)
838
1622
  };
839
1623
  }
840
- if (this.spec.openapi) {
1624
+ if (this.spec.openapi !== void 0 && this.spec.openapi !== null) {
841
1625
  return {
842
1626
  type: "openapi",
843
- version: this.spec.openapi
1627
+ version: String(this.spec.openapi)
844
1628
  };
845
1629
  }
846
1630
  return null;
@@ -848,6 +1632,10 @@ var _SwaggerParser = class _SwaggerParser {
848
1632
  };
849
1633
  __name(_SwaggerParser, "SwaggerParser");
850
1634
  var SwaggerParser = _SwaggerParser;
1635
+ function specVersionOf(value, majorPrefix) {
1636
+ return typeof value === "string" || typeof value === "number" ? String(value).startsWith(majorPrefix) : false;
1637
+ }
1638
+ __name(specVersionOf, "specVersionOf");
851
1639
 
852
1640
  // ../shared/src/emit/headers.emit.ts
853
1641
  function emitHeaders(options) {
@@ -868,7 +1656,7 @@ ${emitDefaultHeaderGuards(customHeaders)}`;
868
1656
  headerCode += `
869
1657
  // Advertise the response content type declared in the spec
870
1658
  if (!headers.has('Accept')) {
871
- headers = headers.set('Accept', '${accept}');
1659
+ headers = headers.set('Accept', ${quoteLiteral(accept)});
872
1660
  }`;
873
1661
  }
874
1662
  if (contentType == null ? void 0 : contentType.isMultipart) {
@@ -892,7 +1680,7 @@ if (!headers.has('Content-Type')) {
892
1680
  }
893
1681
  __name(emitHeaders, "emitHeaders");
894
1682
  function emitDefaultHeadersMerge(optionsExpression, customHeaders) {
895
- const defaultsLiteral = Object.entries(customHeaders).map(([key, value]) => `'${key}': '${value}'`).join(", ");
1683
+ const defaultsLiteral = Object.entries(customHeaders).map(([key, value]) => `${emitObjectKey(key, "single")}: ${quoteLiteral(value)}`).join(", ");
896
1684
  return `
897
1685
  // Add default headers if not already present
898
1686
  let headers = ${optionsExpression}?.headers;
@@ -904,12 +1692,242 @@ ${emitDefaultHeaderGuards(customHeaders)}
904
1692
  }
905
1693
  __name(emitDefaultHeadersMerge, "emitDefaultHeadersMerge");
906
1694
  function emitDefaultHeaderGuards(customHeaders) {
907
- return Object.entries(customHeaders).map(([key, value]) => `if (!headers.has('${key}')) {
908
- headers = headers.set('${key}', '${value}');
909
- }`).join("\n");
1695
+ return Object.entries(customHeaders).map(([key, value]) => {
1696
+ const name = quoteLiteral(key);
1697
+ return `if (!headers.has(${name})) {
1698
+ headers = headers.set(${name}, ${quoteLiteral(value)});
1699
+ }`;
1700
+ }).join("\n");
910
1701
  }
911
1702
  __name(emitDefaultHeaderGuards, "emitDefaultHeaderGuards");
912
1703
 
1704
+ // ../shared/src/utils/functions/get-request-body-type.ts
1705
+ function getRequestBodyType(requestBody, config) {
1706
+ const content = requestBody.content || {};
1707
+ const jsonContent = content[CONTENT_TYPES.JSON];
1708
+ if (jsonContent == null ? void 0 : jsonContent.schema) {
1709
+ return getTypeScriptType(jsonContent.schema, config, jsonContent.schema.nullable);
1710
+ }
1711
+ return "any";
1712
+ }
1713
+ __name(getRequestBodyType, "getRequestBodyType");
1714
+
1715
+ // ../shared/src/utils/functions/is-data-type-interface.ts
1716
+ function isDataTypeInterface(type) {
1717
+ const invalidTypes = [
1718
+ "any",
1719
+ "File",
1720
+ "string",
1721
+ "number",
1722
+ "boolean",
1723
+ "object",
1724
+ "unknown",
1725
+ "[]",
1726
+ "Array"
1727
+ ];
1728
+ return !invalidTypes.some((invalidType) => type.includes(invalidType));
1729
+ }
1730
+ __name(isDataTypeInterface, "isDataTypeInterface");
1731
+
1732
+ // ../shared/src/utils/functions/argument-names.ts
1733
+ var RESERVED_WORDS = [
1734
+ "arguments",
1735
+ "await",
1736
+ "break",
1737
+ "case",
1738
+ "catch",
1739
+ "class",
1740
+ "const",
1741
+ "continue",
1742
+ "debugger",
1743
+ "default",
1744
+ "delete",
1745
+ "do",
1746
+ "else",
1747
+ "enum",
1748
+ "eval",
1749
+ "export",
1750
+ "extends",
1751
+ "false",
1752
+ "finally",
1753
+ "for",
1754
+ "function",
1755
+ "if",
1756
+ "implements",
1757
+ "import",
1758
+ "in",
1759
+ "instanceof",
1760
+ "interface",
1761
+ "let",
1762
+ "new",
1763
+ "null",
1764
+ "package",
1765
+ "private",
1766
+ "protected",
1767
+ "public",
1768
+ "return",
1769
+ "static",
1770
+ "super",
1771
+ "switch",
1772
+ "this",
1773
+ "throw",
1774
+ "true",
1775
+ "try",
1776
+ "typeof",
1777
+ "var",
1778
+ "void",
1779
+ "while",
1780
+ "with",
1781
+ "yield"
1782
+ ];
1783
+ var SERVICE_ARGUMENT_PROFILE = Object.freeze({
1784
+ reserved: Object.freeze([
1785
+ "observe",
1786
+ "options",
1787
+ "url",
1788
+ "params",
1789
+ "headers",
1790
+ "formData",
1791
+ "formBody"
1792
+ ]),
1793
+ bindsRequestBody: true
1794
+ });
1795
+ var RESOURCE_ARGUMENT_PROFILE = Object.freeze({
1796
+ reserved: Object.freeze([
1797
+ "resourceOptions",
1798
+ "requestOptions",
1799
+ "params",
1800
+ "headers"
1801
+ ]),
1802
+ bindsRequestBody: false
1803
+ });
1804
+ var REQUEST_BODY_KEY = /* @__PURE__ */ Symbol("requestBody");
1805
+ function resolveArgumentNames(operation, config, profile) {
1806
+ let byConfig = RESOLVED.get(operation);
1807
+ if (!byConfig) {
1808
+ byConfig = /* @__PURE__ */ new WeakMap();
1809
+ RESOLVED.set(operation, byConfig);
1810
+ }
1811
+ let byProfile = byConfig.get(config);
1812
+ if (!byProfile) {
1813
+ byProfile = /* @__PURE__ */ new WeakMap();
1814
+ byConfig.set(config, byProfile);
1815
+ }
1816
+ const cached = byProfile.get(profile);
1817
+ if (cached) {
1818
+ return cached;
1819
+ }
1820
+ const resolved = computeArgumentNames(operation, config, profile);
1821
+ byProfile.set(profile, resolved);
1822
+ return resolved;
1823
+ }
1824
+ __name(resolveArgumentNames, "resolveArgumentNames");
1825
+ var RESOLVED = /* @__PURE__ */ new WeakMap();
1826
+ function computeArgumentNames(operation, config, profile) {
1827
+ const entries = [
1828
+ ...operation.pathParams.map((param) => ({
1829
+ key: param.name,
1830
+ base: camelCase(param.name)
1831
+ })),
1832
+ ...operation.formDataFields.map((field) => ({
1833
+ key: field,
1834
+ base: camelCase(field)
1835
+ })),
1836
+ ...operation.urlEncodedFields.map((field) => ({
1837
+ key: field,
1838
+ base: camelCase(field)
1839
+ }))
1840
+ ];
1841
+ const bodyBase = profile.bindsRequestBody ? jsonBodyIdentifier(operation, config) : void 0;
1842
+ if (bodyBase !== void 0) {
1843
+ entries.push({
1844
+ key: REQUEST_BODY_KEY,
1845
+ base: bodyBase
1846
+ });
1847
+ }
1848
+ entries.push(...operation.queryParams.map((param) => ({
1849
+ key: param.name,
1850
+ base: camelCase(param.name)
1851
+ })));
1852
+ const identifiers = /* @__PURE__ */ new Map();
1853
+ const used = /* @__PURE__ */ new Set([
1854
+ ...profile.reserved,
1855
+ ...RESERVED_WORDS
1856
+ ]);
1857
+ const renamed = [];
1858
+ const merged = /* @__PURE__ */ new Set();
1859
+ for (const { key, base } of entries) {
1860
+ if (identifiers.has(key)) {
1861
+ if (typeof key === "string") {
1862
+ merged.add(key);
1863
+ }
1864
+ continue;
1865
+ }
1866
+ let identifier = base;
1867
+ let suffix = 2;
1868
+ while (used.has(identifier)) {
1869
+ identifier = `${base}${suffix}`;
1870
+ suffix++;
1871
+ }
1872
+ if (identifier !== base) {
1873
+ renamed.push(Object.freeze({
1874
+ source: typeof key === "string" ? key : base,
1875
+ identifier
1876
+ }));
1877
+ }
1878
+ used.add(identifier);
1879
+ identifiers.set(key, identifier);
1880
+ }
1881
+ return {
1882
+ // The fallback runs the *same* rules the resolver would have, rather
1883
+ // than a bare camelCase: an unregistered wire name otherwise came back
1884
+ // as `class` or `options`, names the resolver never assigns.
1885
+ // Uniquified against everything already assigned, not just the reserved
1886
+ // words: an unregistered wire name that camelCases onto an identifier
1887
+ // this operation already bound would otherwise alias it — compiling
1888
+ // fine and sending the wrong value. Only reachable for operations built
1889
+ // outside the normalizer, but the resolver is public API.
1890
+ of: /* @__PURE__ */ __name((wireName) => {
1891
+ var _a;
1892
+ return (_a = identifiers.get(wireName)) != null ? _a : deriveLocalName(camelCase(wireName), [
1893
+ ...used
1894
+ ]);
1895
+ }, "of"),
1896
+ body: identifiers.get(REQUEST_BODY_KEY),
1897
+ all: Object.freeze([
1898
+ ...identifiers.values()
1899
+ ]),
1900
+ renamed: Object.freeze(renamed),
1901
+ merged: Object.freeze([
1902
+ ...merged
1903
+ ])
1904
+ };
1905
+ }
1906
+ __name(computeArgumentNames, "computeArgumentNames");
1907
+ function jsonBodyIdentifier(operation, config) {
1908
+ var _a;
1909
+ if (!operation.requestBody || operation.isMultipart) {
1910
+ return void 0;
1911
+ }
1912
+ if (!((_a = operation.requestBody.content) == null ? void 0 : _a[CONTENT_TYPES.JSON])) {
1913
+ return void 0;
1914
+ }
1915
+ const bodyType = getRequestBodyType(operation.requestBody, config);
1916
+ return isDataTypeInterface(bodyType) ? camelCase(bodyType) : "requestBody";
1917
+ }
1918
+ __name(jsonBodyIdentifier, "jsonBodyIdentifier");
1919
+ function deriveLocalName(base, taken) {
1920
+ const used = new Set(taken);
1921
+ let name = base;
1922
+ let suffix = 2;
1923
+ while (used.has(name)) {
1924
+ name = `${base}${suffix}`;
1925
+ suffix++;
1926
+ }
1927
+ return name;
1928
+ }
1929
+ __name(deriveLocalName, "deriveLocalName");
1930
+
913
1931
  // ../shared/src/emit/url.emit.ts
914
1932
  function plainParamValue(identifier) {
915
1933
  return identifier;
@@ -919,40 +1937,54 @@ function signalAwareParamValue(identifier) {
919
1937
  return `typeof ${identifier} === 'function' ? ${identifier}() : ${identifier}`;
920
1938
  }
921
1939
  __name(signalAwareParamValue, "signalAwareParamValue");
922
- function emitUrlExpression(path14, pathParams, paramValue = plainParamValue) {
923
- let urlExpression = `\`\${this.basePath}${path14}\``;
1940
+ function emitUrlExpression(path15, pathParams, argumentNames, paramValue = plainParamValue) {
1941
+ var _a;
1942
+ const declared = new Set(pathParams.map((param) => param.name));
1943
+ const unresolved = ((_a = path15.match(/{([^{}]*)}/g)) != null ? _a : []).map((placeholder) => placeholder.slice(1, -1)).filter((name) => !declared.has(name));
1944
+ if (unresolved.length > 0) {
1945
+ throw new UnresolvedPathTemplateError(`Path "${path15}" declares no parameter for ${unresolved.map((name) => `{${name}}`).join(", ")}. Declare each placeholder as a path parameter, or remove it from the path.`, path15, unresolved);
1946
+ }
1947
+ let urlExpression = "`${this.basePath}" + escapeTemplateLiteral(path15) + "`";
924
1948
  pathParams.forEach((param) => {
925
- urlExpression = urlExpression.replace(`{${param.name}}`, `\${${paramValue(camelCase(param.name))}}`);
1949
+ const replacement = "${" + paramValue(argumentNames.of(param.name)) + "}";
1950
+ urlExpression = urlExpression.split(`{${escapeTemplateLiteral(param.name)}}`).join(replacement);
926
1951
  });
927
1952
  return urlExpression;
928
1953
  }
929
1954
  __name(emitUrlExpression, "emitUrlExpression");
930
- function emitUrlConstruction(path14, pathParams) {
931
- return `const url = ${emitUrlExpression(path14, pathParams)};`;
1955
+ function emitUrlConstruction(path15, pathParams, argumentNames) {
1956
+ return `const url = ${emitUrlExpression(path15, pathParams, argumentNames)};`;
932
1957
  }
933
1958
  __name(emitUrlConstruction, "emitUrlConstruction");
934
1959
 
935
1960
  // ../shared/src/emit/query-params.emit.ts
936
- function emitQueryParams(queryParams) {
1961
+ function emitQueryParams(queryParams, argumentNames) {
937
1962
  if (queryParams.length === 0) {
938
1963
  return "";
939
1964
  }
940
- const paramMappings = queryParams.map((param) => `if (${camelCase(param.name)} != null) {
941
- params = HttpParamsBuilder.addToHttpParams(params, ${camelCase(param.name)}, '${param.name}');
942
- }`).join("\n");
1965
+ const paramMappings = queryParams.map((param) => {
1966
+ const identifier = argumentNames.of(param.name);
1967
+ return `if (${identifier} != null) {
1968
+ params = HttpParamsBuilder.addToHttpParams(params, ${identifier}, ${quoteLiteral(param.name)});
1969
+ }`;
1970
+ }).join("\n");
943
1971
  return `
944
1972
  let params = new HttpParams();
945
1973
  ${paramMappings}`;
946
1974
  }
947
1975
  __name(emitQueryParams, "emitQueryParams");
948
- function emitSignalAwareQueryParams(queryParams) {
1976
+ function emitSignalAwareQueryParams(queryParams, argumentNames) {
949
1977
  if (queryParams.length === 0) {
950
1978
  return "";
951
1979
  }
952
- const paramMappings = queryParams.map((param) => `const ${camelCase(param.name)}Value = ${signalAwareParamValue(camelCase(param.name))};
953
- if (${camelCase(param.name)}Value != null) {
954
- params = HttpParamsBuilder.addToHttpParams(params, ${camelCase(param.name)}Value, '${param.name}');
955
- }`).join("\n");
1980
+ const paramMappings = queryParams.map((param) => {
1981
+ const identifier = argumentNames.of(param.name);
1982
+ const local = deriveLocalName(`${identifier}Value`, argumentNames.all);
1983
+ return `const ${local} = ${signalAwareParamValue(identifier)};
1984
+ if (${local} != null) {
1985
+ params = HttpParamsBuilder.addToHttpParams(params, ${local}, ${quoteLiteral(param.name)});
1986
+ }`;
1987
+ }).join("\n");
956
1988
  return `
957
1989
  let params = new HttpParams();
958
1990
  ${paramMappings}`;
@@ -1014,55 +2046,166 @@ function listGeneratedBarrelDirs(project, rootPath) {
1014
2046
  __name(listGeneratedBarrelDirs, "listGeneratedBarrelDirs");
1015
2047
 
1016
2048
  // ../shared/src/utils/functions/token-names.ts
1017
- function getClientContextTokenName(clientName = "default") {
1018
- const clientSuffix = clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
2049
+ function effectiveClientName(clientName) {
2050
+ return clientName ? clientName : "default";
2051
+ }
2052
+ __name(effectiveClientName, "effectiveClientName");
2053
+ function clientNameIdentifier(clientName) {
2054
+ return isValidIdentifier(clientName) ? capitalizeFirst(clientName) : pascalCase(clientName);
2055
+ }
2056
+ __name(clientNameIdentifier, "clientNameIdentifier");
2057
+ function tokenSuffix(clientName) {
2058
+ return effectiveClientName(clientName).toUpperCase().replace(/[^A-Z0-9]/g, "_");
2059
+ }
2060
+ __name(tokenSuffix, "tokenSuffix");
2061
+ function getClientContextTokenName(clientName) {
2062
+ const clientSuffix = tokenSuffix(clientName);
1019
2063
  return `CLIENT_CONTEXT_TOKEN_${clientSuffix}`;
1020
2064
  }
1021
2065
  __name(getClientContextTokenName, "getClientContextTokenName");
1022
- function getBasePathTokenName(clientName = "default") {
1023
- const clientSuffix = clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
2066
+ function getBasePathTokenName(clientName) {
2067
+ const clientSuffix = tokenSuffix(clientName);
1024
2068
  return `BASE_PATH_${clientSuffix}`;
1025
2069
  }
1026
2070
  __name(getBasePathTokenName, "getBasePathTokenName");
1027
- function getInterceptorsTokenName(clientName = "default") {
1028
- const clientSuffix = clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
2071
+ function getInterceptorsTokenName(clientName) {
2072
+ const clientSuffix = tokenSuffix(clientName);
1029
2073
  return `HTTP_INTERCEPTORS_${clientSuffix}`;
1030
2074
  }
1031
2075
  __name(getInterceptorsTokenName, "getInterceptorsTokenName");
1032
2076
 
1033
- // ../shared/src/utils/functions/duplicate-function-name.ts
1034
- function hasDuplicateFunctionNames(arr) {
1035
- return new Set(arr.map((fn) => fn.getName())).size !== arr.length;
2077
+ // ../shared/src/utils/functions/controller-groups.ts
2078
+ function groupOperationsByController(operations, onWarning) {
2079
+ const groups = {};
2080
+ const controllerByFold = /* @__PURE__ */ new Map();
2081
+ const tagSpellings = /* @__PURE__ */ new Map();
2082
+ const namelessTags = /* @__PURE__ */ new Set();
2083
+ operations.forEach((operation) => {
2084
+ var _a, _b, _c;
2085
+ const tag = (_a = operation.tags) == null ? void 0 : _a[0];
2086
+ let rawName = "Default";
2087
+ if (tag !== void 0) {
2088
+ rawName = tag;
2089
+ } else {
2090
+ const pathParts = operation.path.split("/").filter((part) => part && !part.startsWith("{"));
2091
+ if (pathParts.length > 1) {
2092
+ rawName = pathParts[1];
2093
+ }
2094
+ }
2095
+ const sanitized = pascalCase(rawName);
2096
+ const isNameless = !new RegExp("\\p{L}", "u").test(sanitized);
2097
+ const candidate = isNameless ? "Default" : sanitized;
2098
+ const fold = candidate.toLowerCase();
2099
+ const controllerName = (_b = controllerByFold.get(fold)) != null ? _b : candidate;
2100
+ controllerByFold.set(fold, controllerName);
2101
+ if (tag !== void 0 && isNameless) {
2102
+ namelessTags.add(tag);
2103
+ } else if (tag !== void 0) {
2104
+ const spellings = (_c = tagSpellings.get(controllerName)) != null ? _c : /* @__PURE__ */ new Set();
2105
+ spellings.add(tag);
2106
+ tagSpellings.set(controllerName, spellings);
2107
+ }
2108
+ if (!groups[controllerName]) {
2109
+ groups[controllerName] = [];
2110
+ }
2111
+ groups[controllerName].push(operation);
2112
+ });
2113
+ for (const tag of namelessTags) {
2114
+ onWarning == null ? void 0 : onWarning(`Tag "${tag}" contains no characters usable in a name \u2014 its operations are generated into the "Default" controller. Rename the tag to give them a file of their own.`);
2115
+ }
2116
+ for (const [controllerName, spellings] of tagSpellings) {
2117
+ if (spellings.size > 1) {
2118
+ onWarning == null ? void 0 : onWarning(`Tags ${[
2119
+ ...spellings
2120
+ ].map((name) => `"${name}"`).join(" and ")} all map to the controller "${controllerName}" \u2014 their operations are generated into one file. Rename one tag to keep them apart.`);
2121
+ }
2122
+ }
2123
+ return groups;
1036
2124
  }
1037
- __name(hasDuplicateFunctionNames, "hasDuplicateFunctionNames");
2125
+ __name(groupOperationsByController, "groupOperationsByController");
1038
2126
 
1039
- // ../shared/src/utils/functions/get-request-body-type.ts
1040
- function getRequestBodyType(requestBody, config) {
1041
- const content = requestBody.content || {};
1042
- const jsonContent = content[CONTENT_TYPES.JSON];
1043
- if (jsonContent == null ? void 0 : jsonContent.schema) {
1044
- return getTypeScriptType(jsonContent.schema, config, jsonContent.schema.nullable);
2127
+ // ../shared/src/utils/functions/method-names.ts
2128
+ var RESERVED_MEMBER_NAMES = Object.freeze([
2129
+ "constructor",
2130
+ "httpClient",
2131
+ "basePath",
2132
+ "clientContextToken",
2133
+ "createContextWithClientId"
2134
+ ]);
2135
+ var RESERVED_MEMBER_SET = new Set(RESERVED_MEMBER_NAMES);
2136
+ function reservedMemberCollision(operation, config) {
2137
+ if (config.options.customizeMethodName || !operation.operationId) {
2138
+ return void 0;
1045
2139
  }
1046
- return "any";
2140
+ const natural = camelCase(operation.operationId);
2141
+ return RESERVED_MEMBER_SET.has(natural) ? {
2142
+ from: natural,
2143
+ to: `_${natural}`
2144
+ } : void 0;
1047
2145
  }
1048
- __name(getRequestBodyType, "getRequestBodyType");
2146
+ __name(reservedMemberCollision, "reservedMemberCollision");
2147
+ function getOperationMethodName(operation, config) {
2148
+ const customize = config.options.customizeMethodName;
2149
+ if (!customize) {
2150
+ return defaultOperationMethodName(operation);
2151
+ }
2152
+ if (operation.operationId == null) {
2153
+ throw new InvalidIdentifierError(`customizeMethodName needs an operationId, and ${describeOperation(operation)} has none. Add one to the spec, or drop customizeMethodName to use the derived name.`, operation);
2154
+ }
2155
+ const customName = customize(operation.operationId);
2156
+ if (!isValidIdentifier(customName) || RESERVED_MEMBER_SET.has(customName)) {
2157
+ throw new InvalidIdentifierError(`customizeMethodName returned "${customName}" for ${describeOperation(operation)}, which is not a usable TypeScript method name. Return an identifier \u2014 letters, digits, "_" and "$", not starting with a digit \u2014 and not one of ${RESERVED_MEMBER_NAMES.map((name) => `"${name}"`).join(", ")}.`, operation, customName);
2158
+ }
2159
+ return customName;
2160
+ }
2161
+ __name(getOperationMethodName, "getOperationMethodName");
2162
+ function defaultOperationMethodName(operation) {
2163
+ if (operation.operationId) {
2164
+ const name = camelCase(operation.operationId);
2165
+ return RESERVED_MEMBER_SET.has(name) ? `_${name}` : name;
2166
+ }
2167
+ const method = pascalCase(operation.method.toLowerCase());
2168
+ const pathParts = operation.path.split("/").filter((segment) => segment !== "").map((segment) => pascalCase(segment));
2169
+ const resource = pathParts.join("") || "resource";
2170
+ return `${camelCase(resource)}${method}`;
2171
+ }
2172
+ __name(defaultOperationMethodName, "defaultOperationMethodName");
1049
2173
 
1050
- // ../shared/src/utils/functions/is-data-type-interface.ts
1051
- function isDataTypeInterface(type) {
1052
- const invalidTypes = [
1053
- "any",
1054
- "File",
1055
- "string",
1056
- "number",
1057
- "boolean",
1058
- "object",
1059
- "unknown",
1060
- "[]",
1061
- "Array"
2174
+ // ../shared/src/utils/functions/distinct-member-names.ts
2175
+ function assertDistinctMemberNames(serviceClass, className, operations, methodNameOf) {
2176
+ var _a;
2177
+ const methodNames = serviceClass.getMethods().map((method) => method.getName());
2178
+ const propertyNames = new Set(serviceClass.getProperties().map((property) => property.getName()));
2179
+ const duplicates = [
2180
+ ...new Set(methodNames.filter((name, index) => methodNames.indexOf(name) !== index || propertyNames.has(name)))
1062
2181
  ];
1063
- return !invalidTypes.some((invalidType) => type.includes(invalidType));
2182
+ if (duplicates.length === 0) {
2183
+ return;
2184
+ }
2185
+ const byName = new Map(duplicates.map((name) => [
2186
+ name,
2187
+ []
2188
+ ]));
2189
+ for (const operation of operations) {
2190
+ (_a = byName.get(methodNameOf(operation))) == null ? void 0 : _a.push(operation);
2191
+ }
2192
+ const detail = [
2193
+ ...byName
2194
+ ].map(([name, ops]) => {
2195
+ const from = ops.map(describeOperation).join(" and ");
2196
+ return propertyNames.has(name) ? `"${name}" from ${from} (a property of ${className})` : `"${name}" from ${from}`;
2197
+ }).join("; ");
2198
+ throw new DuplicateGeneratedNameError(`Operations map to the same member name in ${className}: ${detail}. Ensure each operationId maps to a unique name.`, duplicates, [
2199
+ ...byName.values()
2200
+ ].flat());
1064
2201
  }
1065
- __name(isDataTypeInterface, "isDataTypeInterface");
2202
+ __name(assertDistinctMemberNames, "assertDistinctMemberNames");
2203
+
2204
+ // ../shared/src/utils/functions/duplicate-function-name.ts
2205
+ function hasDuplicateFunctionNames(arr) {
2206
+ return new Set(arr.map((fn) => fn.getName())).size !== arr.length;
2207
+ }
2208
+ __name(hasDuplicateFunctionNames, "hasDuplicateFunctionNames");
1066
2209
 
1067
2210
  // ../shared/src/utils/functions/generate-parse-request-type-params.ts
1068
2211
  function generateParseRequestTypeParams(params) {
@@ -1117,7 +2260,7 @@ var PROVIDER_GENERATOR_HEADER_COMMENT = defaultHeaderComment + `* Generated prov
1117
2260
  * Do not edit this file manually
1118
2261
  */
1119
2262
  `;
1120
- var BASE_INTERCEPTOR_HEADER_COMMENT = /* @__PURE__ */ __name((clientName) => defaultHeaderComment + `* Generated Base Interceptor for client ${clientName}
2263
+ var BASE_INTERCEPTOR_HEADER_COMMENT = /* @__PURE__ */ __name((clientName) => defaultHeaderComment + `* Generated Base Interceptor for client ${escapeJsDoc(clientName)}
1121
2264
  * Do not edit this file manually
1122
2265
  */
1123
2266
  `, "BASE_INTERCEPTOR_HEADER_COMMENT");
@@ -1138,17 +2281,8 @@ var ZOD_PLUGIN_INDEX_GENERATOR_HEADER_COMMENT = defaultHeaderComment + `* Genera
1138
2281
  var import_ts_morph = require("ts-morph");
1139
2282
 
1140
2283
  // src/lib/generators/type/type-resolver.ts
1141
- function escapeString2(str) {
1142
- return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
1143
- }
1144
- __name(escapeString2, "escapeString");
1145
- function sanitizePropertyName(name) {
1146
- if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)) {
1147
- return `"${name}"`;
1148
- }
1149
- return name;
1150
- }
1151
- __name(sanitizePropertyName, "sanitizePropertyName");
2284
+ var escapeString = escapeSingleQuoted;
2285
+ var sanitizePropertyName = emitPropertyName;
1152
2286
  var _TypeResolver = class _TypeResolver {
1153
2287
  constructor(config, onWarning) {
1154
2288
  __publicField(this, "config");
@@ -1217,7 +2351,7 @@ var _TypeResolver = class _TypeResolver {
1217
2351
  return this.resolveReference(schema.$ref);
1218
2352
  }
1219
2353
  if (schema.enum) {
1220
- return schema.enum.map((value) => typeof value === "string" ? `'${escapeString2(value)}'` : String(value)).join(" | ");
2354
+ return schema.enum.map((value) => typeof value === "string" ? `'${escapeString(value)}'` : String(value)).join(" | ");
1221
2355
  }
1222
2356
  if (schema.allOf) {
1223
2357
  return schema.allOf.map((def) => this.resolve(def)).filter((type) => type !== "any" && type !== "unknown").join(" & ") || "Record<string, unknown>";
@@ -1323,9 +2457,7 @@ var _EnumBuilder = class _EnumBuilder {
1323
2457
  build(name, definition) {
1324
2458
  var _a;
1325
2459
  if (!((_a = definition.enum) == null ? void 0 : _a.length)) return [];
1326
- const docs = !this.config.options.generateEnumBasedOnDescription && definition.description ? [
1327
- definition.description
1328
- ] : void 0;
2460
+ const docs = this.config.options.generateEnumBasedOnDescription ? void 0 : emitDocs(definition.description);
1329
2461
  if (this.config.options.enumStyle === "enum") {
1330
2462
  return this.buildEnumAsEnum(name, definition, docs);
1331
2463
  } else {
@@ -1368,7 +2500,7 @@ var _EnumBuilder = class _EnumBuilder {
1368
2500
  const objectProperties = [];
1369
2501
  const unionType = definition.enum.map((value) => {
1370
2502
  const key = toEnumKey(value);
1371
- const val = typeof value === "string" ? `'${escapeString2(value)}'` : isNaN(value) ? `'${value}'` : `${value}`;
2503
+ const val = typeof value === "string" ? `'${escapeString(value)}'` : isNaN(value) ? `'${value}'` : `${value}`;
1372
2504
  objectProperties.push(`${key}: ${val} as ${name}`);
1373
2505
  return val;
1374
2506
  }).join(" | ");
@@ -1428,9 +2560,7 @@ var _InterfaceBuilder = class _InterfaceBuilder {
1428
2560
  kind: import_ts_morph2.StructureKind.Interface,
1429
2561
  name,
1430
2562
  isExported: true,
1431
- docs: definition.description ? [
1432
- definition.description
1433
- ] : void 0,
2563
+ docs: emitDocs(definition.description),
1434
2564
  properties: this.buildProperties(definition),
1435
2565
  indexSignatures: this.buildIndexSignatures(definition)
1436
2566
  };
@@ -1450,9 +2580,7 @@ var _InterfaceBuilder = class _InterfaceBuilder {
1450
2580
  type: propertyType,
1451
2581
  isReadonly: isReadOnly,
1452
2582
  hasQuestionToken: !isRequired,
1453
- docs: property.description ? [
1454
- property.description
1455
- ] : void 0
2583
+ docs: emitDocs(property.description)
1456
2584
  };
1457
2585
  });
1458
2586
  }
@@ -1624,26 +2752,49 @@ var _TypeGenerator = class _TypeGenerator {
1624
2752
  generate() {
1625
2753
  return __async(this, null, function* () {
1626
2754
  var _a;
1627
- try {
1628
- const definitions = this.parser.getNormalizedSpec().definitions;
1629
- if (!definitions || Object.keys(definitions).length === 0) {
1630
- (_a = this.onWarning) == null ? void 0 : _a.call(this, "No definitions found in swagger file");
1631
- }
1632
- if (this.config.options.modelFileStructure === "per-type") {
1633
- this.generatePerType(definitions);
1634
- return;
1635
- }
1636
- Object.entries(definitions).forEach(([name, definition]) => {
1637
- this.statements.push(...this.collectTypeStructure(name, definition));
1638
- });
1639
- this.statements.push(...buildSdkTypes(this.config));
1640
- this.applyBatchUpdates();
1641
- yield this.finalize();
1642
- } catch (error) {
1643
- throw new Error(`Failed to generate types: ${error instanceof Error ? error.message : "Unknown error"}`);
2755
+ const definitions = this.parser.getNormalizedSpec().definitions;
2756
+ if (!definitions || Object.keys(definitions).length === 0) {
2757
+ (_a = this.onWarning) == null ? void 0 : _a.call(this, "No definitions found in swagger file");
1644
2758
  }
2759
+ this.assertDistinctTypeNames(definitions);
2760
+ if (this.config.options.modelFileStructure === "per-type") {
2761
+ this.generatePerType(definitions);
2762
+ return;
2763
+ }
2764
+ Object.entries(definitions).forEach(([name, definition]) => {
2765
+ this.statements.push(...this.collectTypeStructure(name, definition));
2766
+ });
2767
+ this.statements.push(...buildSdkTypes(this.config));
2768
+ this.applyBatchUpdates();
2769
+ yield this.finalize();
1645
2770
  });
1646
2771
  }
2772
+ /**
2773
+ * Two schemas whose names sanitize onto one type name (`Pet-Store` and
2774
+ * `Pet.Store` both become `Pet_Store`) would emit two declarations of one
2775
+ * interface — and TypeScript declaration-merges those, so the compile
2776
+ * check cannot see it and one model silently acquires the other's
2777
+ * properties. Worse than a hard error, hence a hard error.
2778
+ */
2779
+ assertDistinctTypeNames(definitions) {
2780
+ var _a;
2781
+ const rawByType = /* @__PURE__ */ new Map();
2782
+ for (const rawName of Object.keys(definitions)) {
2783
+ const typeName = this.resolver.pascalName(rawName);
2784
+ rawByType.set(typeName, [
2785
+ ...(_a = rawByType.get(typeName)) != null ? _a : [],
2786
+ rawName
2787
+ ]);
2788
+ }
2789
+ const collisions = [
2790
+ ...rawByType
2791
+ ].filter(([, raws]) => raws.length > 1);
2792
+ if (collisions.length === 0) {
2793
+ return;
2794
+ }
2795
+ const detail = collisions.map(([typeName, raws]) => `"${typeName}" from schemas ${raws.map((raw) => `"${raw}"`).join(" and ")}`).join("; ");
2796
+ throw new DuplicateGeneratedNameError(`Schemas map to the same type name: ${detail}. Rename one schema to keep them apart.`, collisions.map(([typeName]) => typeName));
2797
+ }
1647
2798
  collectTypeStructure(name, definition) {
1648
2799
  const typeName = this.resolver.pascalName(name);
1649
2800
  if (definition.enum) {
@@ -1666,9 +2817,7 @@ var _TypeGenerator = class _TypeGenerator {
1666
2817
  kind: import_ts_morph4.StructureKind.TypeAlias,
1667
2818
  name: typeName,
1668
2819
  isExported: true,
1669
- docs: definition.description ? [
1670
- definition.description
1671
- ] : void 0,
2820
+ docs: emitDocs(definition.description),
1672
2821
  type: this.resolver.resolve(definition)
1673
2822
  }
1674
2823
  ];
@@ -1685,9 +2834,7 @@ var _TypeGenerator = class _TypeGenerator {
1685
2834
  name,
1686
2835
  type: typeExpression,
1687
2836
  isExported: true,
1688
- docs: definition.description ? [
1689
- definition.description
1690
- ] : void 0
2837
+ docs: emitDocs(definition.description)
1691
2838
  };
1692
2839
  }
1693
2840
  buildArrayTypeAlias(name, definition) {
@@ -1696,9 +2843,7 @@ var _TypeGenerator = class _TypeGenerator {
1696
2843
  kind: import_ts_morph4.StructureKind.TypeAlias,
1697
2844
  name,
1698
2845
  isExported: true,
1699
- docs: definition.description ? [
1700
- definition.description
1701
- ] : void 0,
2846
+ docs: emitDocs(definition.description),
1702
2847
  type: `Array<${itemType}>`
1703
2848
  };
1704
2849
  }
@@ -1707,11 +2852,8 @@ var _TypeGenerator = class _TypeGenerator {
1707
2852
  this.sourceFile.addStatements(this.statements);
1708
2853
  }
1709
2854
  finalize() {
1710
- return __async(this, null, function* () {
1711
- this.sourceFile.formatText();
1712
- this.sourceFile.insertText(0, TYPE_GENERATOR_HEADER_COMMENT);
1713
- yield this.sourceFile.save();
1714
- });
2855
+ this.sourceFile.formatText();
2856
+ this.sourceFile.insertText(0, TYPE_GENERATOR_HEADER_COMMENT);
1715
2857
  }
1716
2858
  generatePerType(definitions) {
1717
2859
  const registry = new ModelFileRegistry(this.onWarning);
@@ -1801,7 +2943,6 @@ var _TypeGenerator = class _TypeGenerator {
1801
2943
  finalizeModelSourceFile(sourceFile) {
1802
2944
  sourceFile.formatText();
1803
2945
  sourceFile.insertText(0, TYPE_GENERATOR_HEADER_COMMENT);
1804
- sourceFile.saveSync();
1805
2946
  }
1806
2947
  };
1807
2948
  __name(_TypeGenerator, "TypeGenerator");
@@ -1811,11 +2952,11 @@ var TypeGenerator = _TypeGenerator;
1811
2952
  var import_ts_morph5 = require("ts-morph");
1812
2953
  var path2 = __toESM(require("path"));
1813
2954
  var _TokenGenerator = class _TokenGenerator {
1814
- constructor(project, clientName = "default") {
2955
+ constructor(project, clientName) {
1815
2956
  __publicField(this, "project");
1816
2957
  __publicField(this, "clientName");
1817
2958
  this.project = project;
1818
- this.clientName = clientName;
2959
+ this.clientName = effectiveClientName(clientName);
1819
2960
  }
1820
2961
  generate(outputDir) {
1821
2962
  const tokensDir = path2.join(outputDir, "tokens");
@@ -1838,9 +2979,9 @@ var _TokenGenerator = class _TokenGenerator {
1838
2979
  moduleSpecifier: "@angular/common/http"
1839
2980
  }
1840
2981
  ]);
1841
- const basePathTokenName = this.getBasePathTokenName();
1842
- const interceptorsTokenName = this.getInterceptorsTokenName();
1843
- const clientContextTokenName = this.getClientContextTokenName();
2982
+ const basePathTokenName = getBasePathTokenName(this.clientName);
2983
+ const interceptorsTokenName = getInterceptorsTokenName(this.clientName);
2984
+ const clientContextTokenName = getClientContextTokenName(this.clientName);
1844
2985
  sourceFile.addVariableStatement({
1845
2986
  isExported: true,
1846
2987
  declarationKind: import_ts_morph5.VariableDeclarationKind.Const,
@@ -1854,7 +2995,7 @@ var _TokenGenerator = class _TokenGenerator {
1854
2995
  }
1855
2996
  ],
1856
2997
  leadingTrivia: `/**
1857
- * Injection token for the ${this.clientName} client base API path
2998
+ * Injection token for the ${escapeJsDoc(this.clientName)} client base API path
1858
2999
  */
1859
3000
  `
1860
3001
  });
@@ -1871,7 +3012,7 @@ var _TokenGenerator = class _TokenGenerator {
1871
3012
  }
1872
3013
  ],
1873
3014
  leadingTrivia: `/**
1874
- * Injection token for the ${this.clientName} client HTTP interceptor instances
3015
+ * Injection token for the ${escapeJsDoc(this.clientName)} client HTTP interceptor instances
1875
3016
  */
1876
3017
  `
1877
3018
  });
@@ -1881,11 +3022,11 @@ var _TokenGenerator = class _TokenGenerator {
1881
3022
  declarations: [
1882
3023
  {
1883
3024
  name: clientContextTokenName,
1884
- initializer: `new HttpContextToken<string>(() => '${this.clientName}')`
3025
+ initializer: `new HttpContextToken<string>(() => ${quoteLiteral(this.clientName)})`
1885
3026
  }
1886
3027
  ],
1887
3028
  leadingTrivia: `/**
1888
- * HttpContext token to identify requests belonging to the ${this.clientName} client
3029
+ * HttpContext token to identify requests belonging to the ${escapeJsDoc(this.clientName)} client
1889
3030
  */
1890
3031
  `
1891
3032
  });
@@ -1920,19 +3061,6 @@ var _TokenGenerator = class _TokenGenerator {
1920
3061
  });
1921
3062
  }
1922
3063
  sourceFile.formatText();
1923
- sourceFile.saveSync();
1924
- }
1925
- getBasePathTokenName() {
1926
- const clientSuffix = this.clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
1927
- return `BASE_PATH_${clientSuffix}`;
1928
- }
1929
- getInterceptorsTokenName() {
1930
- const clientSuffix = this.clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
1931
- return `HTTP_INTERCEPTORS_${clientSuffix}`;
1932
- }
1933
- getClientContextTokenName() {
1934
- const clientSuffix = this.clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
1935
- return `CLIENT_CONTEXT_TOKEN_${clientSuffix}`;
1936
3064
  }
1937
3065
  };
1938
3066
  __name(_TokenGenerator, "TokenGenerator");
@@ -2071,7 +3199,6 @@ var _FileDownloadGenerator = class _FileDownloadGenerator {
2071
3199
  return fallbackFilename;`
2072
3200
  });
2073
3201
  sourceFile.formatText();
2074
- sourceFile.saveSync();
2075
3202
  }
2076
3203
  };
2077
3204
  __name(_FileDownloadGenerator, "FileDownloadGenerator");
@@ -2224,7 +3351,6 @@ var _DateTransformerGenerator = class _DateTransformerGenerator {
2224
3351
  ]
2225
3352
  });
2226
3353
  sourceFile.formatText();
2227
- sourceFile.saveSync();
2228
3354
  }
2229
3355
  };
2230
3356
  __name(_DateTransformerGenerator, "DateTransformerGenerator");
@@ -2286,7 +3412,6 @@ var _MainIndexGenerator = class _MainIndexGenerator {
2286
3412
  });
2287
3413
  });
2288
3414
  sourceFile.formatText();
2289
- sourceFile.saveSync();
2290
3415
  }
2291
3416
  };
2292
3417
  __name(_MainIndexGenerator, "MainIndexGenerator");
@@ -2301,7 +3426,7 @@ var _ProviderGenerator = class _ProviderGenerator {
2301
3426
  __publicField(this, "clientName");
2302
3427
  this.project = project;
2303
3428
  this.config = config;
2304
- this.clientName = config.clientName || "default";
3429
+ this.clientName = effectiveClientName(config.clientName);
2305
3430
  }
2306
3431
  generate(outputDir) {
2307
3432
  const filePath = path6.join(outputDir, "providers.ts");
@@ -2310,7 +3435,7 @@ var _ProviderGenerator = class _ProviderGenerator {
2310
3435
  });
2311
3436
  const basePathTokenName = getBasePathTokenName(this.clientName);
2312
3437
  const interceptorsTokenName = getInterceptorsTokenName(this.clientName);
2313
- const baseInterceptorClassName = `${this.capitalizeFirst(this.clientName)}BaseInterceptor`;
3438
+ const baseInterceptorClassName = `${clientNameIdentifier(this.clientName)}BaseInterceptor`;
2314
3439
  sourceFile.addImportDeclarations([
2315
3440
  {
2316
3441
  namedImports: [
@@ -2386,22 +3511,19 @@ var _ProviderGenerator = class _ProviderGenerator {
2386
3511
  });
2387
3512
  }
2388
3513
  sourceFile.addInterface({
2389
- name: `${this.capitalizeFirst(this.clientName)}Config`,
3514
+ name: `${clientNameIdentifier(this.clientName)}Config`,
2390
3515
  isExported: true,
2391
- docs: [
2392
- `Configuration options for ${this.clientName} client`
2393
- ],
3516
+ docs: emitDocs(`Configuration options for ${this.clientName} client`),
2394
3517
  properties: configProperties
2395
3518
  });
2396
3519
  this.addMainProviderFunction(sourceFile, basePathTokenName, interceptorsTokenName, baseInterceptorClassName);
2397
3520
  sourceFile.insertText(0, PROVIDER_GENERATOR_HEADER_COMMENT);
2398
3521
  sourceFile.formatText();
2399
- sourceFile.saveSync();
2400
3522
  }
2401
3523
  addMainProviderFunction(sourceFile, basePathTokenName, interceptorsTokenName, baseInterceptorClassName) {
2402
3524
  const hasDateInterceptor = this.config.options.dateType === "Date";
2403
- const functionName = `provide${this.capitalizeFirst(this.clientName)}Client`;
2404
- const configTypeName = `${this.capitalizeFirst(this.clientName)}Config`;
3525
+ const functionName = `provide${clientNameIdentifier(this.clientName)}Client`;
3526
+ const configTypeName = `${clientNameIdentifier(this.clientName)}Config`;
2405
3527
  const functionBody = `
2406
3528
  const providers: Provider[] = [
2407
3529
  // Base path token for this client
@@ -2449,7 +3571,7 @@ return makeEnvironmentProviders(providers);`;
2449
3571
  name: functionName,
2450
3572
  isExported: true,
2451
3573
  docs: [
2452
- `Provides configuration for ${this.clientName} client`,
3574
+ `Provides configuration for ${escapeJsDoc(this.clientName)} client`,
2453
3575
  "",
2454
3576
  "@example",
2455
3577
  "```typescript",
@@ -2495,9 +3617,6 @@ return makeEnvironmentProviders(providers);`;
2495
3617
  });
2496
3618
  }
2497
3619
  }
2498
- capitalizeFirst(str) {
2499
- return str.charAt(0).toUpperCase() + str.slice(1);
2500
- }
2501
3620
  };
2502
3621
  __name(_ProviderGenerator, "ProviderGenerator");
2503
3622
  var ProviderGenerator = _ProviderGenerator;
@@ -2507,11 +3626,11 @@ var import_ts_morph7 = require("ts-morph");
2507
3626
  var path7 = __toESM(require("path"));
2508
3627
  var _project, _clientName;
2509
3628
  var _BaseInterceptorGenerator = class _BaseInterceptorGenerator {
2510
- constructor(project, clientName = "default") {
3629
+ constructor(project, clientName) {
2511
3630
  __privateAdd(this, _project);
2512
3631
  __privateAdd(this, _clientName);
2513
3632
  __privateSet(this, _project, project);
2514
- __privateSet(this, _clientName, clientName);
3633
+ __privateSet(this, _clientName, effectiveClientName(clientName));
2515
3634
  }
2516
3635
  generate(outputDir) {
2517
3636
  const utilsDir = path7.join(outputDir, "utils");
@@ -2554,7 +3673,7 @@ var _BaseInterceptorGenerator = class _BaseInterceptorGenerator {
2554
3673
  }
2555
3674
  ]);
2556
3675
  sourceFile.addClass({
2557
- name: `${this.capitalizeFirst(__privateGet(this, _clientName))}BaseInterceptor`,
3676
+ name: `${clientNameIdentifier(__privateGet(this, _clientName))}BaseInterceptor`,
2558
3677
  isExported: true,
2559
3678
  decorators: [
2560
3679
  {
@@ -2618,10 +3737,6 @@ var _BaseInterceptorGenerator = class _BaseInterceptorGenerator {
2618
3737
  });
2619
3738
  sourceFile.insertText(0, BASE_INTERCEPTOR_HEADER_COMMENT(__privateGet(this, _clientName)));
2620
3739
  sourceFile.formatText();
2621
- sourceFile.saveSync();
2622
- }
2623
- capitalizeFirst(str) {
2624
- return str.charAt(0).toUpperCase() + str.slice(1);
2625
3740
  }
2626
3741
  };
2627
3742
  _project = new WeakMap();
@@ -2655,7 +3770,6 @@ var _HttpParamsBuilderGenerator = class _HttpParamsBuilderGenerator {
2655
3770
  });
2656
3771
  this.addMethods(classDeclaration);
2657
3772
  sourceFile.formatText();
2658
- sourceFile.saveSync();
2659
3773
  }
2660
3774
  addMethods(classDeclaration) {
2661
3775
  const methods = [
@@ -2851,22 +3965,23 @@ var _ServiceMethodBodyGenerator = class _ServiceMethodBodyGenerator {
2851
3965
  }
2852
3966
  generateMethodBody(operation) {
2853
3967
  var _a;
3968
+ const argumentNames = resolveArgumentNames(operation, this.config, SERVICE_ARGUMENT_PROFILE);
2854
3969
  const bodyParts = [
2855
- emitUrlConstruction(operation.path, operation.pathParams),
2856
- emitQueryParams(operation.queryParams),
3970
+ emitUrlConstruction(operation.path, operation.pathParams, argumentNames),
3971
+ emitQueryParams(operation.queryParams, argumentNames),
2857
3972
  emitHeaders({
2858
3973
  optionsExpression: "options",
2859
3974
  customHeaders: this.config.options.customHeaders,
2860
3975
  accept: ((_a = this.config.options.emitAcceptHeader) != null ? _a : true) ? operation.acceptHeader : void 0,
2861
3976
  contentType: operation
2862
3977
  }),
2863
- this.generateMultipartFormData(operation),
2864
- this.generateUrlEncodedFormData(operation),
2865
- this.generateHttpRequest(operation)
3978
+ this.generateMultipartFormData(operation, argumentNames),
3979
+ this.generateUrlEncodedFormData(operation, argumentNames),
3980
+ this.generateHttpRequest(operation, argumentNames)
2866
3981
  ];
2867
3982
  return bodyParts.filter(Boolean).join("\n");
2868
3983
  }
2869
- generateMultipartFormData(operation) {
3984
+ generateMultipartFormData(operation, argumentNames) {
2870
3985
  var _a;
2871
3986
  if (!operation.isMultipart || operation.formDataFields.length === 0) {
2872
3987
  return "";
@@ -2876,21 +3991,22 @@ var _ServiceMethodBodyGenerator = class _ServiceMethodBodyGenerator {
2876
3991
  const fieldSchema = properties[field];
2877
3992
  const isFile = (fieldSchema == null ? void 0 : fieldSchema.type) === "string" && (fieldSchema == null ? void 0 : fieldSchema.format) === "binary";
2878
3993
  const isArray = (fieldSchema == null ? void 0 : fieldSchema.type) === "array";
3994
+ const arg = argumentNames.of(field);
2879
3995
  if (isArray) {
2880
3996
  const itemSchema = Array.isArray(fieldSchema.items) ? fieldSchema.items[0] : fieldSchema.items;
2881
3997
  const isFileArray = (itemSchema == null ? void 0 : itemSchema.type) === "string" && (itemSchema == null ? void 0 : itemSchema.format) === "binary";
2882
3998
  const valueExpression = isFileArray ? "item" : "String(item)";
2883
- return `if (${field} !== undefined && Array.isArray(${field})) {
2884
- ${field}.forEach((item) => {
3999
+ return `if (${arg} !== undefined && Array.isArray(${arg})) {
4000
+ ${arg}.forEach((item) => {
2885
4001
  if (item !== undefined && item !== null) {
2886
- formData.append('${field}', ${valueExpression});
4002
+ formData.append(${quoteLiteral(field)}, ${valueExpression});
2887
4003
  }
2888
4004
  });
2889
4005
  }`;
2890
4006
  } else {
2891
- const valueExpression = isFile ? field : `String(${field})`;
2892
- return `if (${field} !== undefined) {
2893
- formData.append('${field}', ${valueExpression});
4007
+ const valueExpression = isFile ? arg : `String(${arg})`;
4008
+ return `if (${arg} !== undefined) {
4009
+ formData.append(${quoteLiteral(field)}, ${valueExpression});
2894
4010
  }`;
2895
4011
  }
2896
4012
  }).join("\n");
@@ -2898,7 +4014,7 @@ var _ServiceMethodBodyGenerator = class _ServiceMethodBodyGenerator {
2898
4014
  const formData = new FormData();
2899
4015
  ${formDataAppends}`;
2900
4016
  }
2901
- generateUrlEncodedFormData(operation) {
4017
+ generateUrlEncodedFormData(operation, argumentNames) {
2902
4018
  var _a;
2903
4019
  if (!operation.isUrlEncoded || operation.urlEncodedFields.length === 0) {
2904
4020
  return "";
@@ -2907,17 +4023,18 @@ ${formDataAppends}`;
2907
4023
  const formBodyAppends = operation.urlEncodedFields.map((field) => {
2908
4024
  const fieldSchema = properties[field];
2909
4025
  const isArray = (fieldSchema == null ? void 0 : fieldSchema.type) === "array";
4026
+ const arg = argumentNames.of(field);
2910
4027
  if (isArray) {
2911
- return `if (${field} !== undefined && Array.isArray(${field})) {
2912
- ${field}.forEach((item) => {
4028
+ return `if (${arg} !== undefined && Array.isArray(${arg})) {
4029
+ ${arg}.forEach((item) => {
2913
4030
  if (item !== undefined && item !== null) {
2914
- formBody.append('${field}', String(item));
4031
+ formBody.append(${quoteLiteral(field)}, String(item));
2915
4032
  }
2916
4033
  });
2917
4034
  }`;
2918
4035
  } else {
2919
- return `if (${field} !== undefined && ${field} !== null) {
2920
- formBody.append('${field}', String(${field}));
4036
+ return `if (${arg} !== undefined && ${arg} !== null) {
4037
+ formBody.append(${quoteLiteral(field)}, String(${arg}));
2921
4038
  }`;
2922
4039
  }
2923
4040
  }).join("\n");
@@ -2925,8 +4042,8 @@ ${formDataAppends}`;
2925
4042
  const formBody = new URLSearchParams();
2926
4043
  ${formBodyAppends}`;
2927
4044
  }
2928
- generateHttpRequest(operation) {
2929
- var _a, _b, _c;
4045
+ generateHttpRequest(operation, argumentNames) {
4046
+ var _a, _b, _c, _d;
2930
4047
  const httpMethod = operation.method.toLowerCase();
2931
4048
  let bodyParam = "";
2932
4049
  if (operation.hasBody) {
@@ -2935,9 +4052,7 @@ ${formBodyAppends}`;
2935
4052
  } else if (operation.isUrlEncoded) {
2936
4053
  bodyParam = "formBody.toString()";
2937
4054
  } else if ((_b = (_a = operation.requestBody) == null ? void 0 : _a.content) == null ? void 0 : _b[CONTENT_TYPES.JSON]) {
2938
- const bodyType = getRequestBodyType(operation.requestBody, this.config);
2939
- const isInterface = isDataTypeInterface(bodyType);
2940
- bodyParam = isInterface ? camelCase(bodyType) : "requestBody";
4055
+ bodyParam = (_c = argumentNames.body) != null ? _c : "requestBody";
2941
4056
  }
2942
4057
  }
2943
4058
  const methodsWithBody = [
@@ -2945,7 +4060,7 @@ ${formBodyAppends}`;
2945
4060
  "put",
2946
4061
  "patch"
2947
4062
  ];
2948
- const parseResponse = ((_c = this.config.options.validation) == null ? void 0 : _c.response) ? `.pipe(map(response => options?.parse?.(response) ?? response))` : "";
4063
+ const parseResponse = ((_d = this.config.options.validation) == null ? void 0 : _d.response) ? `.pipe(map(response => options?.parse?.(response) ?? response))` : "";
2949
4064
  const entries = [];
2950
4065
  if (methodsWithBody.includes(httpMethod)) {
2951
4066
  entries.push(`body: ${bodyParam || "null"}`);
@@ -3051,9 +4166,10 @@ var _ServiceMethodParamsGenerator = class _ServiceMethodParamsGenerator {
3051
4166
  generateApiParameters(operation) {
3052
4167
  var _a;
3053
4168
  const params = [];
4169
+ const argumentNames = resolveArgumentNames(operation, this.config, SERVICE_ARGUMENT_PROFILE);
3054
4170
  operation.pathParams.forEach((param) => {
3055
4171
  params.push({
3056
- name: camelCase(param.name),
4172
+ name: argumentNames.of(param.name),
3057
4173
  // Swagger 2.0 puts type/format/enum on the parameter itself; the
3058
4174
  // spread (vs passing param directly) is needed because Parameter
3059
4175
  // lacks TypeSchema's index signature — a fresh literal satisfies it.
@@ -3065,24 +4181,22 @@ var _ServiceMethodParamsGenerator = class _ServiceMethodParamsGenerator {
3065
4181
  if (requestBody) {
3066
4182
  const jsonContent = (_a = requestBody.content) == null ? void 0 : _a[CONTENT_TYPES.JSON];
3067
4183
  if (operation.isMultipart) {
3068
- params.push(...this.convertObjectToSingleParams(operation.formDataSchema));
4184
+ params.push(...this.convertObjectToSingleParams(operation.formDataSchema, argumentNames));
3069
4185
  }
3070
4186
  if (operation.isUrlEncoded) {
3071
- params.push(...this.convertObjectToSingleParams(operation.urlEncodedSchema));
4187
+ params.push(...this.convertObjectToSingleParams(operation.urlEncodedSchema, argumentNames));
3072
4188
  }
3073
- if (jsonContent && !operation.isMultipart) {
3074
- const bodyType = this.getRequestBodyType(requestBody);
3075
- const isInterface = isDataTypeInterface(bodyType);
4189
+ if (jsonContent && !operation.isMultipart && argumentNames.body) {
3076
4190
  params.push({
3077
- name: isInterface ? camelCase(bodyType) : "requestBody",
3078
- type: bodyType,
4191
+ name: argumentNames.body,
4192
+ type: this.getRequestBodyType(requestBody),
3079
4193
  hasQuestionToken: !requestBody.required
3080
4194
  });
3081
4195
  }
3082
4196
  }
3083
4197
  operation.queryParams.forEach((param) => {
3084
4198
  params.push({
3085
- name: camelCase(param.name),
4199
+ name: argumentNames.of(param.name),
3086
4200
  type: getTypeScriptType(param.schema || __spreadValues({}, param), this.config),
3087
4201
  hasQuestionToken: !param.required
3088
4202
  });
@@ -3124,13 +4238,13 @@ var _ServiceMethodParamsGenerator = class _ServiceMethodParamsGenerator {
3124
4238
  return "any";
3125
4239
  }
3126
4240
  /** `schema` arrives ref-resolved from the normalizer (formData/urlEncoded schema). */
3127
- convertObjectToSingleParams(schema) {
4241
+ convertObjectToSingleParams(schema, argumentNames) {
3128
4242
  var _a;
3129
4243
  const params = [];
3130
4244
  Object.entries((_a = schema == null ? void 0 : schema.properties) != null ? _a : {}).forEach(([key, value]) => {
3131
4245
  var _a2;
3132
4246
  params.push({
3133
- name: key,
4247
+ name: argumentNames.of(key),
3134
4248
  type: getTypeScriptType(value, this.config, value.nullable),
3135
4249
  hasQuestionToken: !((_a2 = schema == null ? void 0 : schema.required) == null ? void 0 : _a2.includes(key))
3136
4250
  });
@@ -3267,9 +4381,7 @@ ${methodBody}`;
3267
4381
  returnType,
3268
4382
  statements: methodBody,
3269
4383
  overloads: methodOverLoads,
3270
- docs: operation.description ? [
3271
- operation.description
3272
- ] : void 0
4384
+ docs: emitDocs(operation.description)
3273
4385
  });
3274
4386
  }
3275
4387
  generateSingleRequestParameters(requestObject) {
@@ -3279,29 +4391,11 @@ ${methodBody}`;
3279
4391
  ];
3280
4392
  }
3281
4393
  generateMethodName(operation) {
3282
- if (this.config.options.customizeMethodName) {
3283
- if (operation.operationId == null) {
3284
- throw new Error(`Operation ID is required for method name customization of operation: (${operation.method}) ${operation.path}`);
3285
- }
3286
- return this.config.options.customizeMethodName(operation.operationId);
3287
- } else {
3288
- return this.defaultNameGenerator(operation);
3289
- }
4394
+ return getOperationMethodName(operation, this.config);
3290
4395
  }
3291
4396
  generateReturnType() {
3292
4397
  return "Observable<any>";
3293
4398
  }
3294
- defaultNameGenerator(operation) {
3295
- if (operation.operationId) {
3296
- return camelCase(operation.operationId);
3297
- }
3298
- const method = pascalCase(operation.method.toLowerCase());
3299
- const pathParts = operation.path.split("/").map((str) => {
3300
- return pascalCase(pascalCase(str).replace(/[^a-zA-Z0-9]/g, ""));
3301
- });
3302
- const resource = pathParts.join("") || "resource";
3303
- return `${camelCase(resource)}${method}`;
3304
- }
3305
4399
  };
3306
4400
  __name(_ServiceMethodGenerator, "ServiceMethodGenerator");
3307
4401
  var ServiceMethodGenerator = _ServiceMethodGenerator;
@@ -3309,12 +4403,14 @@ var ServiceMethodGenerator = _ServiceMethodGenerator;
3309
4403
  // src/lib/generators/service/request-params.generator.ts
3310
4404
  var path9 = __toESM(require("path"));
3311
4405
  var _RequestParamsGenerator = class _RequestParamsGenerator {
3312
- constructor(project, config) {
4406
+ constructor(project, config, onWarning) {
3313
4407
  __publicField(this, "project");
3314
4408
  __publicField(this, "paramsGenerator");
3315
4409
  __publicField(this, "registry", /* @__PURE__ */ new Map());
3316
4410
  __publicField(this, "usedInterfaceNames", /* @__PURE__ */ new Set());
4411
+ __publicField(this, "onWarning");
3317
4412
  this.project = project;
4413
+ this.onWarning = onWarning;
3318
4414
  this.paramsGenerator = new ServiceMethodParamsGenerator(config);
3319
4415
  }
3320
4416
  buildRegistry(controllerGroups, getMethodName) {
@@ -3324,10 +4420,6 @@ var _RequestParamsGenerator = class _RequestParamsGenerator {
3324
4420
  if (parameters.length === 0) {
3325
4421
  return;
3326
4422
  }
3327
- const reserved = parameters.find((param) => param.name === "observe" || param.name === "options");
3328
- if (reserved) {
3329
- throw new Error(`Parameter name '${reserved.name}' conflicts with the reserved '${reserved.name}' method parameter when useSingleRequestParameter is enabled: (${operation.method}) ${operation.path}`);
3330
- }
3331
4423
  const interfaceName = this.reserveInterfaceName(controllerName, getMethodName(operation));
3332
4424
  this.registry.set(operation, ServiceMethodRequestObjectGenerator.createEntry(interfaceName, parameters));
3333
4425
  });
@@ -3347,15 +4439,12 @@ var _RequestParamsGenerator = class _RequestParamsGenerator {
3347
4439
  name: entry.interfaceName,
3348
4440
  isExported: true,
3349
4441
  properties: ServiceMethodRequestObjectGenerator.toInterfaceProperties(entry),
3350
- docs: operation.description ? [
3351
- operation.description
3352
- ] : void 0
4442
+ docs: emitDocs(operation.description)
3353
4443
  });
3354
4444
  });
3355
4445
  this.addMissingImports(sourceFile);
3356
4446
  sourceFile.formatText();
3357
4447
  sourceFile.insertText(0, REQUEST_PARAMS_GENERATOR_HEADER_COMMENT);
3358
- sourceFile.saveSync();
3359
4448
  this.addModelsBarrelExport(outputRoot);
3360
4449
  }
3361
4450
  /**
@@ -3385,19 +4474,24 @@ var _RequestParamsGenerator = class _RequestParamsGenerator {
3385
4474
  base,
3386
4475
  `${pascalCase(controllerName)}${base}`
3387
4476
  ];
3388
- for (const candidate of candidates) {
3389
- if (!this.usedInterfaceNames.has(candidate)) {
3390
- this.usedInterfaceNames.add(candidate);
3391
- return candidate;
3392
- }
4477
+ if (!this.usedInterfaceNames.has(base)) {
4478
+ this.usedInterfaceNames.add(base);
4479
+ return base;
4480
+ }
4481
+ const warnRenamed = /* @__PURE__ */ __name((name) => {
4482
+ var _a;
4483
+ this.usedInterfaceNames.add(name);
4484
+ (_a = this.onWarning) == null ? void 0 : _a.call(this, `Request-parameter interface "${base}" is already taken; the parameters of "${methodName}" in ${controllerName} are exposed as "${name}". Renaming the operationId keeps the type name stable.`);
4485
+ return name;
4486
+ }, "warnRenamed");
4487
+ if (!this.usedInterfaceNames.has(candidates[1])) {
4488
+ return warnRenamed(candidates[1]);
3393
4489
  }
3394
4490
  let suffix = 2;
3395
4491
  while (this.usedInterfaceNames.has(`${candidates[1]}${suffix}`)) {
3396
4492
  suffix++;
3397
4493
  }
3398
- const name = `${candidates[1]}${suffix}`;
3399
- this.usedInterfaceNames.add(name);
3400
- return name;
4494
+ return warnRenamed(`${candidates[1]}${suffix}`);
3401
4495
  }
3402
4496
  addModelsBarrelExport(outputRoot) {
3403
4497
  const modelsIndex = this.project.getSourceFile(path9.join(outputRoot, "models", "index.ts"));
@@ -3408,7 +4502,6 @@ var _RequestParamsGenerator = class _RequestParamsGenerator {
3408
4502
  moduleSpecifier: "./request-params"
3409
4503
  });
3410
4504
  modelsIndex.formatText();
3411
- modelsIndex.saveSync();
3412
4505
  }
3413
4506
  };
3414
4507
  __name(_RequestParamsGenerator, "RequestParamsGenerator");
@@ -3438,35 +4531,15 @@ var _ServiceGenerator = class _ServiceGenerator {
3438
4531
  (_a = this.onWarning) == null ? void 0 : _a.call(this, "No API paths found in the specification");
3439
4532
  return;
3440
4533
  }
3441
- const controllerGroups = this.groupPathsByController(paths);
4534
+ const controllerGroups = groupOperationsByController(paths, this.onWarning);
3442
4535
  if (this.config.options.useSingleRequestParameter) {
3443
- const requestParamsGenerator = new RequestParamsGenerator(this.project, this.config);
4536
+ const requestParamsGenerator = new RequestParamsGenerator(this.project, this.config, this.onWarning);
3444
4537
  this.requestObjects = requestParamsGenerator.buildRegistry(controllerGroups, (operation) => this.methodGenerator.generateMethodName(operation));
3445
4538
  requestParamsGenerator.generate(outputRoot);
3446
4539
  }
3447
4540
  yield Promise.all(Object.entries(controllerGroups).map(([controllerName, operations]) => this.generateServiceFile(controllerName, operations, outputDir)));
3448
4541
  });
3449
4542
  }
3450
- groupPathsByController(paths) {
3451
- const groups = {};
3452
- paths.forEach((path14) => {
3453
- let controllerName = "Default";
3454
- if (path14.tags && path14.tags.length > 0) {
3455
- controllerName = path14.tags[0];
3456
- } else {
3457
- const pathParts = path14.path.split("/").filter((p) => p && !p.startsWith("{"));
3458
- if (pathParts.length > 1) {
3459
- controllerName = pascalCase(pathParts[1]);
3460
- }
3461
- }
3462
- controllerName = pascalCase(controllerName);
3463
- if (!groups[controllerName]) {
3464
- groups[controllerName] = [];
3465
- }
3466
- groups[controllerName].push(path14);
3467
- });
3468
- return groups;
3469
- }
3470
4543
  generateServiceFile(controllerName, operations, outputDir) {
3471
4544
  return __async(this, null, function* () {
3472
4545
  const fileName = `${camelCase(controllerName)}.service.ts`;
@@ -3477,9 +4550,24 @@ var _ServiceGenerator = class _ServiceGenerator {
3477
4550
  this.addServiceClass(sourceFile, controllerName, operations);
3478
4551
  sourceFile.fixMissingImports().formatText();
3479
4552
  sourceFile.insertText(0, SERVICE_GENERATOR_HEADER_COMMENT(controllerName));
3480
- sourceFile.saveSync();
3481
4553
  });
3482
4554
  }
4555
+ /**
4556
+ * A renamed argument is part of the method's public signature, and the
4557
+ * suffix depends on which other arguments the operation has — so adding or
4558
+ * removing one renumbers the survivor and breaks call sites. Silent is the
4559
+ * one thing that must not happen.
4560
+ */
4561
+ warnAboutRenamedArguments(operation) {
4562
+ var _a, _b;
4563
+ const { renamed, merged } = resolveArgumentNames(operation, this.config, SERVICE_ARGUMENT_PROFILE);
4564
+ for (const { source, identifier } of renamed) {
4565
+ (_a = this.onWarning) == null ? void 0 : _a.call(this, `Parameter "${source}" of ${describeOperation(operation)} is exposed as "${identifier}" \u2014 its natural name is already taken by another parameter or by the method itself. Renaming it in the spec keeps the generated signature stable.`);
4566
+ }
4567
+ for (const wireName of merged) {
4568
+ (_b = this.onWarning) == null ? void 0 : _b.call(this, `Parameter "${wireName}" of ${describeOperation(operation)} is declared in more than one location; they collapse into one argument, so the first declaration's type wins and the same value is sent for both.`);
4569
+ }
4570
+ }
3483
4571
  addServiceClass(sourceFile, controllerName, operations) {
3484
4572
  var _a;
3485
4573
  const className = getServiceClassName(controllerName, (_a = this.config.options.naming) == null ? void 0 : _a.services);
@@ -3566,14 +4654,26 @@ var _ServiceGenerator = class _ServiceGenerator {
3566
4654
  ],
3567
4655
  returnType: "HttpContext",
3568
4656
  statements: `const context = existingContext || new HttpContext();
3569
- return context.set(this.clientContextToken, '${this.config.clientName || "default"}');`
4657
+ return context.set(this.clientContextToken, ${quoteLiteral(effectiveClientName(this.config.clientName))});`
3570
4658
  });
3571
4659
  operations.forEach((operation) => {
3572
4660
  var _a2;
4661
+ this.warnAboutRenamedArguments(operation);
4662
+ this.warnAboutReservedMethodName(operation);
3573
4663
  this.methodGenerator.addServiceMethod(serviceClass, operation, (_a2 = this.requestObjects) == null ? void 0 : _a2.get(operation));
3574
4664
  });
3575
- if (hasDuplicateFunctionNames(serviceClass.getMethods())) {
3576
- throw new Error(`Duplicate method names found in service class ${className}. Please ensure unique method names for each operation.`);
4665
+ assertDistinctMemberNames(serviceClass, className, operations, (op) => this.methodGenerator.generateMethodName(op));
4666
+ }
4667
+ /**
4668
+ * A derived method name that landed on a member the class binds itself is
4669
+ * prefixed rather than rejected — the spec is valid — but the rename is
4670
+ * public signature and must be said out loud.
4671
+ */
4672
+ warnAboutReservedMethodName(operation) {
4673
+ var _a;
4674
+ const collision = reservedMemberCollision(operation, this.config);
4675
+ if (collision) {
4676
+ (_a = this.onWarning) == null ? void 0 : _a.call(this, `Operation ${describeOperation(operation)} would be named "${collision.from}", which the generated class already binds \u2014 it is emitted as "${collision.to}". Rename the operationId to choose the name.`);
3577
4677
  }
3578
4678
  }
3579
4679
  };
@@ -3609,7 +4709,6 @@ var _ServiceIndexGenerator = class _ServiceIndexGenerator {
3609
4709
  moduleSpecifier: `./${serviceName}.service`
3610
4710
  });
3611
4711
  });
3612
- sourceFile.saveSync();
3613
4712
  }
3614
4713
  };
3615
4714
  __name(_ServiceIndexGenerator, "ServiceIndexGenerator");
@@ -3629,17 +4728,6 @@ var NAMING_KEYS = [
3629
4728
  ];
3630
4729
  var NAME_PREFIX_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
3631
4730
  var NAME_SUFFIX_PATTERN = /^[A-Za-z0-9_]*$/;
3632
- var _ConfigValidationError = class _ConfigValidationError extends Error {
3633
- constructor(issues) {
3634
- super(`Invalid ng-openapi configuration:
3635
- ${issues.map((issue) => ` - ${issue}`).join("\n")}`);
3636
- __publicField(this, "issues");
3637
- this.name = "ConfigValidationError";
3638
- this.issues = issues;
3639
- }
3640
- };
3641
- __name(_ConfigValidationError, "ConfigValidationError");
3642
- var ConfigValidationError = _ConfigValidationError;
3643
4731
  function validateGeneratorConfig(config) {
3644
4732
  if (!config || typeof config !== "object") {
3645
4733
  throw new ConfigValidationError([
@@ -3793,15 +4881,20 @@ function validateInput(inputPath) {
3793
4881
  __name(validateInput, "validateInput");
3794
4882
  function generateFromConfig(_0) {
3795
4883
  return __async(this, arguments, function* (config, reporter = {}) {
3796
- var _a, _b, _c, _d, _e, _f, _g;
4884
+ var _a, _b, _c, _d, _e, _f, _g, _h;
3797
4885
  const startedAt = Date.now();
3798
4886
  validateGeneratorConfig(config);
3799
4887
  validateInput(config.input);
3800
4888
  const outputPath = config.output;
3801
4889
  const generateServices = (_a = config.options.generateServices) != null ? _a : true;
3802
4890
  const warnings = [];
4891
+ const seenWarnings = /* @__PURE__ */ new Set();
3803
4892
  const onWarning = /* @__PURE__ */ __name((message) => {
3804
4893
  var _a2;
4894
+ if (seenWarnings.has(message)) {
4895
+ return;
4896
+ }
4897
+ seenWarnings.add(message);
3805
4898
  warnings.push(message);
3806
4899
  (_a2 = reporter.onWarning) == null ? void 0 : _a2.call(reporter, message);
3807
4900
  }, "onWarning");
@@ -3825,7 +4918,7 @@ function generateFromConfig(_0) {
3825
4918
  }, config.compilerOptions)
3826
4919
  });
3827
4920
  (_b = reporter.onPhase) == null ? void 0 : _b.call(reporter, "processing-spec");
3828
- const swaggerParser = yield SwaggerParser.create(config.input, config);
4921
+ const swaggerParser = yield SwaggerParser.create(config.input, config, onWarning);
3829
4922
  if (!swaggerParser.isValidSpec()) {
3830
4923
  const versionInfo = swaggerParser.getSpecVersion();
3831
4924
  throw new SpecParseError(`Invalid or unsupported specification format. Expected OpenAPI 3.x or Swagger 2.x. ${versionInfo ? `Found: ${versionInfo.type} ${versionInfo.version}` : "No version info found"}`, config.input);
@@ -3834,7 +4927,7 @@ function generateFromConfig(_0) {
3834
4927
  const typeGenerator = new TypeGenerator(swaggerParser, project, config, outputPath, onWarning);
3835
4928
  yield typeGenerator.generate();
3836
4929
  (_c = reporter.onPhase) == null ? void 0 : _c.call(reporter, "types-generated");
3837
- if (generateServices) {
4930
+ if (generateServices || ((_d = config.plugins) == null ? void 0 : _d.length)) {
3838
4931
  const tokenGenerator = new TokenGenerator(project, config.clientName);
3839
4932
  tokenGenerator.generate(outputPath);
3840
4933
  if (config.options.dateType === "Date") {
@@ -3849,13 +4942,15 @@ function generateFromConfig(_0) {
3849
4942
  providerGenerator.generate(outputPath);
3850
4943
  const baseInterceptorGenerator = new BaseInterceptorGenerator(project, config.clientName);
3851
4944
  baseInterceptorGenerator.generate(outputPath);
4945
+ }
4946
+ if (generateServices) {
3852
4947
  const serviceGenerator = new ServiceGenerator(swaggerParser, project, config, onWarning);
3853
4948
  yield serviceGenerator.generate(outputPath);
3854
- const indexGenerator = new ServiceIndexGenerator(project, (_d = config.options.naming) == null ? void 0 : _d.services);
4949
+ const indexGenerator = new ServiceIndexGenerator(project, (_e = config.options.naming) == null ? void 0 : _e.services);
3855
4950
  indexGenerator.generateIndex(outputPath);
3856
- (_e = reporter.onPhase) == null ? void 0 : _e.call(reporter, "services-generated");
4951
+ (_f = reporter.onPhase) == null ? void 0 : _f.call(reporter, "services-generated");
3857
4952
  }
3858
- if ((_f = config.plugins) == null ? void 0 : _f.length) {
4953
+ if ((_g = config.plugins) == null ? void 0 : _g.length) {
3859
4954
  for (const plugin of config.plugins) {
3860
4955
  const pluginGenerator = new plugin({
3861
4956
  spec: normalizedSpec,
@@ -3865,10 +4960,11 @@ function generateFromConfig(_0) {
3865
4960
  });
3866
4961
  yield pluginGenerator.generate(outputPath);
3867
4962
  }
3868
- (_g = reporter.onPhase) == null ? void 0 : _g.call(reporter, "plugins-generated");
4963
+ (_h = reporter.onPhase) == null ? void 0 : _h.call(reporter, "plugins-generated");
3869
4964
  }
3870
4965
  const mainIndexGenerator = new MainIndexGenerator(project, config);
3871
4966
  mainIndexGenerator.generateMainIndex(outputPath);
4967
+ yield project.save();
3872
4968
  return {
3873
4969
  client: config.clientName,
3874
4970
  filesWritten: project.getSourceFiles().map((sourceFile) => sourceFile.getFilePath()),
@@ -3878,35 +4974,93 @@ function generateFromConfig(_0) {
3878
4974
  });
3879
4975
  }
3880
4976
  __name(generateFromConfig, "generateFromConfig");
4977
+
4978
+ // src/lib/core/config-loader.ts
4979
+ var fs3 = __toESM(require("fs"));
4980
+ var path14 = __toESM(require("path"));
4981
+ function loadConfigFile(configPath) {
4982
+ return __async(this, null, function* () {
4983
+ const resolvedPath = path14.resolve(configPath);
4984
+ if (!fs3.existsSync(resolvedPath)) {
4985
+ throw new ConfigLoadError(`Configuration file not found: ${resolvedPath}`, resolvedPath);
4986
+ }
4987
+ try {
4988
+ delete require.cache[require.resolve(resolvedPath)];
4989
+ if (resolvedPath.endsWith(".ts")) {
4990
+ require("ts-node/register");
4991
+ }
4992
+ const configModule = require(resolvedPath);
4993
+ const config = configModule.default || configModule.config || configModule;
4994
+ if (!config.input || !config.output) {
4995
+ throw new ConfigValidationError([
4996
+ 'Configuration must include "input" and "output" properties'
4997
+ ]);
4998
+ }
4999
+ const configDir = path14.dirname(resolvedPath);
5000
+ if (!isUrl(config.input) && !path14.isAbsolute(config.input)) {
5001
+ config.input = path14.resolve(configDir, config.input);
5002
+ }
5003
+ if (!path14.isAbsolute(config.output)) {
5004
+ config.output = path14.resolve(configDir, config.output);
5005
+ }
5006
+ return config;
5007
+ } catch (error) {
5008
+ if (error instanceof NgOpenApiError) {
5009
+ throw error;
5010
+ }
5011
+ throw new ConfigLoadError(`Failed to load configuration file: ${resolvedPath}`, resolvedPath, error);
5012
+ }
5013
+ });
5014
+ }
5015
+ __name(loadConfigFile, "loadConfigFile");
3881
5016
  // Annotate the CommonJS export names for ESM import in node:
3882
5017
  0 && (module.exports = {
3883
5018
  BASE_INTERCEPTOR_HEADER_COMMENT,
3884
5019
  CONTENT_TYPES,
5020
+ ConfigLoadError,
3885
5021
  ConfigValidationError,
5022
+ DuplicateGeneratedNameError,
3886
5023
  HTTP_RESOURCE_GENERATOR_HEADER_COMMENT,
5024
+ InvalidIdentifierError,
3887
5025
  MAIN_INDEX_GENERATOR_HEADER_COMMENT,
3888
5026
  NgOpenApiError,
3889
5027
  PROVIDER_GENERATOR_HEADER_COMMENT,
3890
5028
  REQUEST_PARAMS_GENERATOR_HEADER_COMMENT,
5029
+ RESERVED_MEMBER_NAMES,
5030
+ RESOURCE_ARGUMENT_PROFILE,
5031
+ SERVICE_ARGUMENT_PROFILE,
3891
5032
  SERVICE_GENERATOR_HEADER_COMMENT,
3892
5033
  SERVICE_INDEX_GENERATOR_HEADER_COMMENT,
3893
5034
  SpecLoadError,
3894
5035
  SpecParseError,
3895
5036
  SwaggerParser,
3896
5037
  TYPE_GENERATOR_HEADER_COMMENT,
5038
+ UnresolvedPathTemplateError,
3897
5039
  ZOD_PLUGIN_GENERATOR_HEADER_COMMENT,
3898
5040
  ZOD_PLUGIN_INDEX_GENERATOR_HEADER_COMMENT,
5041
+ assertDistinctMemberNames,
3899
5042
  camelCase,
5043
+ capitalizeFirst,
5044
+ clientNameIdentifier,
3900
5045
  defineConfig,
5046
+ describeOperation,
5047
+ effectiveClientName,
3901
5048
  emitDefaultHeadersMerge,
5049
+ emitDocs,
3902
5050
  emitHeaders,
5051
+ emitObjectKey,
5052
+ emitPropertyName,
3903
5053
  emitQueryParams,
3904
5054
  emitResponseTypeOption,
3905
5055
  emitServiceDecorator,
3906
5056
  emitSignalAwareQueryParams,
3907
5057
  emitUrlConstruction,
3908
5058
  emitUrlExpression,
5059
+ escapeDoubleQuoted,
5060
+ escapeJsDoc,
5061
+ escapeSingleQuoted,
3909
5062
  escapeString,
5063
+ escapeTemplateLiteral,
3910
5064
  extractPaths,
3911
5065
  generateFromConfig,
3912
5066
  generateParseRequestTypeParams,
@@ -3914,6 +5068,7 @@ __name(generateFromConfig, "generateFromConfig");
3914
5068
  getClientContextTokenName,
3915
5069
  getInterceptorsTokenName,
3916
5070
  getModelTypeName,
5071
+ getOperationMethodName,
3917
5072
  getRequestBodyType,
3918
5073
  getResourceClassName,
3919
5074
  getResponseInfoFromResponse,
@@ -3921,21 +5076,27 @@ __name(generateFromConfig, "generateFromConfig");
3921
5076
  getResponseTypeFromResponse,
3922
5077
  getServiceClassName,
3923
5078
  getTypeScriptType,
5079
+ groupOperationsByController,
3924
5080
  hasDuplicateFunctionNames,
3925
5081
  inferResponseTypeFromContentType,
3926
5082
  isDataTypeInterface,
3927
5083
  isPrimitiveType,
3928
5084
  isUrl,
5085
+ isValidIdentifier,
3929
5086
  joinRequestOptionEntries,
3930
5087
  kebabCase,
3931
5088
  listGeneratedBarrelDirs,
3932
5089
  listGeneratedFileNames,
5090
+ loadConfigFile,
3933
5091
  normalizeSchema,
3934
5092
  normalizeSpec,
3935
5093
  nullableType,
3936
5094
  pascalCase,
3937
5095
  pascalCaseForEnums,
3938
5096
  plainParamValue,
5097
+ quoteLiteral,
5098
+ reservedMemberCollision,
5099
+ resolveArgumentNames,
3939
5100
  screamingSnakeCase,
3940
5101
  signalAwareParamValue,
3941
5102
  validateGeneratorConfig,