@kubb/plugin-fetch 5.0.0-beta.95 → 5.0.0-beta.99
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.
- package/dist/index.cjs +202 -326
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +202 -326
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -27,8 +27,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
let node_path = require("node:path");
|
|
28
28
|
node_path = __toESM(node_path, 1);
|
|
29
29
|
let kubb_kit = require("kubb/kit");
|
|
30
|
-
let kubb_jsx = require("kubb/jsx");
|
|
31
30
|
let _kubb_plugin_ts = require("@kubb/plugin-ts");
|
|
31
|
+
let kubb_jsx = require("kubb/jsx");
|
|
32
32
|
let kubb_jsx_jsx_runtime = require("kubb/jsx/jsx-runtime");
|
|
33
33
|
let _kubb_plugin_zod = require("@kubb/plugin-zod");
|
|
34
34
|
let node_url = require("node:url");
|
|
@@ -228,33 +228,17 @@ function buildJSDoc(comments, options = {}) {
|
|
|
228
228
|
}
|
|
229
229
|
//#endregion
|
|
230
230
|
//#region ../../internals/utils/src/url.ts
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
function
|
|
236
|
-
|
|
237
|
-
for (const match of path.matchAll(/\{([^}]+)\}/g)) {
|
|
238
|
-
const param = transformParam(match[1], casing);
|
|
239
|
-
const key = replacer ? replacer(param) : param;
|
|
240
|
-
params[key] = key;
|
|
241
|
-
}
|
|
242
|
-
return Object.keys(params).length > 0 ? params : null;
|
|
231
|
+
/**
|
|
232
|
+
* Keeps the OpenAPI parameter name as-is when it is already a valid JS identifier, and
|
|
233
|
+
* camelCases it only enough to become one otherwise (for example a hyphenated path segment).
|
|
234
|
+
*/
|
|
235
|
+
function transformParam(raw) {
|
|
236
|
+
return isValidVarName(raw) ? raw : camelCase(raw);
|
|
243
237
|
}
|
|
244
238
|
/**
|
|
245
|
-
* Helpers for OpenAPI/Swagger paths
|
|
239
|
+
* Helpers for OpenAPI/Swagger paths.
|
|
246
240
|
*/
|
|
247
241
|
var Url = class Url {
|
|
248
|
-
/**
|
|
249
|
-
* Reports whether `url` is a parseable absolute URL. Delegates to the native `URL.canParse`.
|
|
250
|
-
*
|
|
251
|
-
* @example
|
|
252
|
-
* Url.canParse('https://petstore.swagger.io/v2') // true
|
|
253
|
-
* Url.canParse('/pet/{petId}') // false
|
|
254
|
-
*/
|
|
255
|
-
static canParse(url, base) {
|
|
256
|
-
return URL.canParse(url, base);
|
|
257
|
-
}
|
|
258
242
|
/**
|
|
259
243
|
* Converts an OpenAPI/Swagger path to Express-style colon syntax.
|
|
260
244
|
*
|
|
@@ -270,15 +254,14 @@ var Url = class Url {
|
|
|
270
254
|
* key.
|
|
271
255
|
*
|
|
272
256
|
* @example
|
|
273
|
-
* Url.
|
|
257
|
+
* Url.toSafeTemplate('/user/{monetary-account-id}') // '/user/{monetaryAccountId}'
|
|
274
258
|
*/
|
|
275
|
-
static
|
|
276
|
-
return path.replace(/\{([^}]+)\}/g, (_, name) => `{${transformParam(name
|
|
259
|
+
static toSafeTemplate(path) {
|
|
260
|
+
return path.replace(/\{([^}]+)\}/g, (_, name) => `{${transformParam(name)}}`);
|
|
277
261
|
}
|
|
278
262
|
/**
|
|
279
263
|
* Converts an OpenAPI/Swagger path to a TypeScript template literal string.
|
|
280
|
-
* `prefix` is prepended inside the literal, `replacer` transforms each parameter name
|
|
281
|
-
* and `casing` controls parameter identifier casing.
|
|
264
|
+
* `prefix` is prepended inside the literal, and `replacer` transforms each parameter name.
|
|
282
265
|
*
|
|
283
266
|
* @example
|
|
284
267
|
* Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
|
|
@@ -286,10 +269,10 @@ var Url = class Url {
|
|
|
286
269
|
* @example
|
|
287
270
|
* Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
|
|
288
271
|
*/
|
|
289
|
-
static toTemplateString(path, { prefix, replacer
|
|
272
|
+
static toTemplateString(path, { prefix, replacer } = {}) {
|
|
290
273
|
const result = path.split(/\{([^}]+)\}/).map((part, i) => {
|
|
291
274
|
if (i % 2 === 0) return part;
|
|
292
|
-
const param = transformParam(part
|
|
275
|
+
const param = transformParam(part);
|
|
293
276
|
return `\${${replacer ? replacer(param) : param}}`;
|
|
294
277
|
}).join("");
|
|
295
278
|
return `\`${prefix ?? ""}${result}\``;
|
|
@@ -297,8 +280,8 @@ var Url = class Url {
|
|
|
297
280
|
/**
|
|
298
281
|
* Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the
|
|
299
282
|
* grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter
|
|
300
|
-
* names
|
|
301
|
-
*
|
|
283
|
+
* names match the generated `path` type, and `prefix` is prepended inside the literal. Shared by
|
|
284
|
+
* the client and cypress generators that pass a grouped `path` object.
|
|
302
285
|
*
|
|
303
286
|
* @example
|
|
304
287
|
* Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'
|
|
@@ -306,103 +289,28 @@ var Url = class Url {
|
|
|
306
289
|
static toGroupedTemplateString(path, { prefix } = {}) {
|
|
307
290
|
return Url.toTemplateString(path, {
|
|
308
291
|
prefix,
|
|
309
|
-
casing: "camelcase",
|
|
310
292
|
replacer: (name) => `path.${name}`
|
|
311
293
|
});
|
|
312
294
|
}
|
|
313
|
-
/**
|
|
314
|
-
* Returns the path and its extracted params as a structured `URLObject`, or as a stringified
|
|
315
|
-
* expression when `stringify` is set.
|
|
316
|
-
*
|
|
317
|
-
* @example
|
|
318
|
-
* Url.toObject('/pet/{petId}')
|
|
319
|
-
* // { url: '/pet/:petId', params: { petId: 'petId' } }
|
|
320
|
-
*/
|
|
321
|
-
static toObject(path, { type = "path", replacer, stringify, casing } = {}) {
|
|
322
|
-
const object = {
|
|
323
|
-
url: type === "path" ? Url.toPath(path) : Url.toTemplateString(path, {
|
|
324
|
-
replacer,
|
|
325
|
-
casing
|
|
326
|
-
}),
|
|
327
|
-
params: toParamsObject(path, {
|
|
328
|
-
replacer,
|
|
329
|
-
casing
|
|
330
|
-
})
|
|
331
|
-
};
|
|
332
|
-
if (stringify) {
|
|
333
|
-
if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
|
|
334
|
-
if (object.params) return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll("'", "").replaceAll(`"`, "")} }`;
|
|
335
|
-
return `{ url: '${object.url}' }`;
|
|
336
|
-
}
|
|
337
|
-
return object;
|
|
338
|
-
}
|
|
339
295
|
};
|
|
340
296
|
//#endregion
|
|
341
297
|
//#region ../../internals/shared/src/params.ts
|
|
342
|
-
const caseParamsCache = /* @__PURE__ */ new WeakMap();
|
|
343
|
-
/**
|
|
344
|
-
* Applies camelCase to parameter names and returns a new array without mutating the input.
|
|
345
|
-
*
|
|
346
|
-
* Run it before handing parameters to schema builders so output property keys get the right casing
|
|
347
|
-
* while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the
|
|
348
|
-
* original array is returned unchanged. Results are cached per input array.
|
|
349
|
-
*/
|
|
350
|
-
function caseParams(params, casing) {
|
|
351
|
-
if (!casing) return params;
|
|
352
|
-
const cached = caseParamsCache.get(params);
|
|
353
|
-
if (cached) return cached;
|
|
354
|
-
const result = params.map((param) => ({
|
|
355
|
-
...param,
|
|
356
|
-
name: camelCase(param.name)
|
|
357
|
-
}));
|
|
358
|
-
caseParamsCache.set(params, result);
|
|
359
|
-
return result;
|
|
360
|
-
}
|
|
361
298
|
/**
|
|
362
|
-
* Drops parameters that
|
|
299
|
+
* Drops parameters that share the same name, keeping the first.
|
|
363
300
|
*
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
*
|
|
367
|
-
*
|
|
301
|
+
* A malformed spec can declare the same parameter name twice within one `in` location. Both would
|
|
302
|
+
* resolve to the same output property, so emitting both would yield an object type with a duplicate
|
|
303
|
+
* member, which TypeScript rejects. This is a defensive guard against that case, not a casing guard:
|
|
304
|
+
* parameter names flow through unchanged, so no two distinct names ever collide here anymore.
|
|
368
305
|
*/
|
|
369
|
-
function
|
|
306
|
+
function dedupeParams(params) {
|
|
370
307
|
const seen = /* @__PURE__ */ new Set();
|
|
371
308
|
return params.filter((param) => {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
seen.add(key);
|
|
309
|
+
if (seen.has(param.name)) return false;
|
|
310
|
+
seen.add(param.name);
|
|
375
311
|
return true;
|
|
376
312
|
});
|
|
377
313
|
}
|
|
378
|
-
function buildParamsMapping(originalParams, mappedParams) {
|
|
379
|
-
const mapping = {};
|
|
380
|
-
let hasChanged = false;
|
|
381
|
-
originalParams.forEach((param, i) => {
|
|
382
|
-
const mappedName = mappedParams[i]?.name ?? param.name;
|
|
383
|
-
mapping[param.name] = mappedName;
|
|
384
|
-
if (param.name !== mappedName) hasChanged = true;
|
|
385
|
-
});
|
|
386
|
-
return hasChanged ? mapping : null;
|
|
387
|
-
}
|
|
388
|
-
function toAccess(object, name) {
|
|
389
|
-
return isValidVarName(name) ? `${object}.${name}` : `${object}[${JSON.stringify(name)}]`;
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
|
-
* Renders the object-literal expression that renames the camelCased keys of a grouped request
|
|
393
|
-
* option back to the names the OpenAPI document declares, guarded so an omitted optional group
|
|
394
|
-
* stays omitted. Shared by the client and cypress generators, which pass a `buildParamsMapping`
|
|
395
|
-
* result and the source expression to read the keys from.
|
|
396
|
-
*
|
|
397
|
-
* @example
|
|
398
|
-
* ```ts
|
|
399
|
-
* buildParamsRemapExpression({ source: 'config.query', mapping: { include_deleted: 'includeDeleted' } })
|
|
400
|
-
* // 'config.query ? { "include_deleted": config.query.includeDeleted } : config.query'
|
|
401
|
-
* ```
|
|
402
|
-
*/
|
|
403
|
-
function buildParamsRemapExpression({ source, mapping }) {
|
|
404
|
-
return `${source} ? { ${Object.entries(mapping).map(([originalName, casedName]) => `${JSON.stringify(originalName)}: ${toAccess(source, casedName)}`).join(", ")} } : ${source}`;
|
|
405
|
-
}
|
|
406
314
|
//#endregion
|
|
407
315
|
//#region ../../internals/shared/src/operation.ts
|
|
408
316
|
/**
|
|
@@ -536,13 +444,15 @@ function buildOperationComments(node, options = {}) {
|
|
|
536
444
|
if (!splitLines) return filteredComments;
|
|
537
445
|
return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
|
|
538
446
|
}
|
|
539
|
-
function getOperationParameters(node
|
|
540
|
-
const params = caseParams(node.parameters, options.paramsCasing === "original" ? void 0 : "camelcase");
|
|
447
|
+
function getOperationParameters(node) {
|
|
541
448
|
return {
|
|
542
|
-
path:
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
449
|
+
path: dedupeParams(node.parameters.filter((param) => param.in === "path").map((param) => isValidVarName(param.name) ? param : {
|
|
450
|
+
...param,
|
|
451
|
+
name: camelCase(param.name)
|
|
452
|
+
})),
|
|
453
|
+
query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
|
|
454
|
+
header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
|
|
455
|
+
cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
|
|
546
456
|
};
|
|
547
457
|
}
|
|
548
458
|
function getStatusCodeNumber(statusCode) {
|
|
@@ -594,64 +504,33 @@ function createGroupConfig(group) {
|
|
|
594
504
|
};
|
|
595
505
|
}
|
|
596
506
|
//#endregion
|
|
597
|
-
//#region ../../internals/client/src/builders/
|
|
598
|
-
/**
|
|
599
|
-
* Returns `true` when any direction of the validator uses zod (used for dependency checks).
|
|
600
|
-
*/
|
|
601
|
-
function isValidatorEnabled(validator) {
|
|
602
|
-
if (!validator) return false;
|
|
603
|
-
if (validator === "zod") return true;
|
|
604
|
-
return Boolean(validator.request || validator.response);
|
|
605
|
-
}
|
|
606
|
-
/**
|
|
607
|
-
* Returns `'zod'` when request body parsing is enabled, `null` otherwise. The string shorthand
|
|
608
|
-
* `'zod'` validates the response only, so it does not enable request parsing.
|
|
609
|
-
*/
|
|
610
|
-
function resolveRequestValidator(validator) {
|
|
611
|
-
if (!validator || validator === "zod") return null;
|
|
612
|
-
return validator.request ?? null;
|
|
613
|
-
}
|
|
614
|
-
/**
|
|
615
|
-
* Returns `'zod'` when query-parameters parsing is enabled, `null` otherwise. Only the object form
|
|
616
|
-
* `{ request: 'zod' }` enables it.
|
|
617
|
-
*/
|
|
618
|
-
function resolveQueryParamsValidator(validator) {
|
|
619
|
-
if (!validator || validator === "zod") return null;
|
|
620
|
-
return validator.request ?? null;
|
|
621
|
-
}
|
|
622
|
-
/**
|
|
623
|
-
* Returns `'zod'` when response parsing is enabled, `null` otherwise. The string shorthand `'zod'`
|
|
624
|
-
* maps to response parsing.
|
|
625
|
-
*/
|
|
626
|
-
function resolveResponseValidator(validator) {
|
|
627
|
-
if (!validator) return null;
|
|
628
|
-
if (validator === "zod") return "zod";
|
|
629
|
-
return validator.response ?? null;
|
|
630
|
-
}
|
|
507
|
+
//#region ../../internals/client/src/builders/generics.ts
|
|
631
508
|
/**
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
*
|
|
509
|
+
* Builds the `RequestResult` generic arguments for one operation: the plugin-ts per-status responses
|
|
510
|
+
* record plus the per-call `ThrowOnError` flag. `SuccessOf` / `ErrorOf` split the record inside the
|
|
511
|
+
* runtime, so this only names the record and threads `ThrowOnError`.
|
|
512
|
+
*
|
|
513
|
+
* @example
|
|
514
|
+
* `buildRequestResultGenerics({ node, tsResolver }) // 'AddPetResponses, ThrowOnError'`
|
|
635
515
|
*/
|
|
636
|
-
function
|
|
637
|
-
|
|
638
|
-
return name ? {
|
|
639
|
-
expression: name,
|
|
640
|
-
importNames: [name]
|
|
641
|
-
} : null;
|
|
516
|
+
function buildRequestResultGenerics({ node, tsResolver }) {
|
|
517
|
+
return `${tsResolver.response.responses(node)}, ThrowOnError`;
|
|
642
518
|
}
|
|
519
|
+
//#endregion
|
|
520
|
+
//#region ../../internals/client/src/builders/returnStatement.ts
|
|
643
521
|
/**
|
|
644
|
-
*
|
|
645
|
-
*
|
|
646
|
-
* operation
|
|
522
|
+
* Builds the return statement of a generated operation function. The runtime call already resolves
|
|
523
|
+
* to `{ data, error, request, response }`; the generated code forwards that result and casts it to
|
|
524
|
+
* the operation's `RequestResult`, which carries the `throwOnError` discrimination.
|
|
525
|
+
*
|
|
526
|
+
* @example
|
|
527
|
+
* `return request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>`
|
|
647
528
|
*/
|
|
648
|
-
function
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
importNames: [name]
|
|
654
|
-
} : null;
|
|
529
|
+
function buildReturnStatement({ node, tsResolver, callConfig }) {
|
|
530
|
+
return `return request(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
|
|
531
|
+
node,
|
|
532
|
+
tsResolver
|
|
533
|
+
})}>>`;
|
|
655
534
|
}
|
|
656
535
|
//#endregion
|
|
657
536
|
//#region ../../internals/client/src/builders/security.ts
|
|
@@ -722,67 +601,6 @@ function buildSecurityMetadata({ security }) {
|
|
|
722
601
|
return `[${security.map(serializeAuth).join(", ")}]`;
|
|
723
602
|
}
|
|
724
603
|
//#endregion
|
|
725
|
-
//#region ../../internals/client/src/builders/paramsRemap.ts
|
|
726
|
-
/**
|
|
727
|
-
* Builds the call-config entries that rename the camelCased `query` and `headers` keys back to the
|
|
728
|
-
* names the OpenAPI document declares, so the wire format follows the spec while the generated
|
|
729
|
-
* types keep camelCase keys. Returns an empty array when no name changes. Path parameters need no
|
|
730
|
-
* remap because the URL template placeholders are renamed in sync with the `path` keys. Emit the
|
|
731
|
-
* entries after the `...config` spread so they override the camelCased groups the caller passes in.
|
|
732
|
-
*
|
|
733
|
-
* @example
|
|
734
|
-
* ```ts
|
|
735
|
-
* // a query param named include_deleted in the spec
|
|
736
|
-
* buildParamsRemap({ node }) // ['query: config.query ? { "include_deleted": config.query.includeDeleted } : config.query']
|
|
737
|
-
* ```
|
|
738
|
-
*/
|
|
739
|
-
function buildParamsRemap({ node }) {
|
|
740
|
-
if (!kubb_kit.ast.isHttpOperationNode(node)) return [];
|
|
741
|
-
const original = getOperationParameters(node, { paramsCasing: "original" });
|
|
742
|
-
const cased = getOperationParameters(node);
|
|
743
|
-
const queryMapping = buildParamsMapping(original.query, cased.query);
|
|
744
|
-
const headerMapping = buildParamsMapping(original.header, cased.header);
|
|
745
|
-
const entries = [];
|
|
746
|
-
if (queryMapping) entries.push(`query: ${buildParamsRemapExpression({
|
|
747
|
-
source: "config.query",
|
|
748
|
-
mapping: queryMapping
|
|
749
|
-
})}`);
|
|
750
|
-
if (headerMapping) entries.push(`headers: ${buildParamsRemapExpression({
|
|
751
|
-
source: "config.headers",
|
|
752
|
-
mapping: headerMapping
|
|
753
|
-
})}`);
|
|
754
|
-
return entries;
|
|
755
|
-
}
|
|
756
|
-
//#endregion
|
|
757
|
-
//#region ../../internals/client/src/builders/generics.ts
|
|
758
|
-
/**
|
|
759
|
-
* Builds the `RequestResult` generic arguments for one operation: the plugin-ts per-status responses
|
|
760
|
-
* record plus the per-call `ThrowOnError` flag. `SuccessOf` / `ErrorOf` split the record inside the
|
|
761
|
-
* runtime, so this only names the record and threads `ThrowOnError`.
|
|
762
|
-
*
|
|
763
|
-
* @example
|
|
764
|
-
* `buildRequestResultGenerics({ node, tsResolver }) // 'AddPetResponses, ThrowOnError'`
|
|
765
|
-
*/
|
|
766
|
-
function buildRequestResultGenerics({ node, tsResolver }) {
|
|
767
|
-
return `${tsResolver.response.responses(node)}, ThrowOnError`;
|
|
768
|
-
}
|
|
769
|
-
//#endregion
|
|
770
|
-
//#region ../../internals/client/src/builders/returnStatement.ts
|
|
771
|
-
/**
|
|
772
|
-
* Builds the return statement of a generated operation function. The runtime call already resolves
|
|
773
|
-
* to `{ data, error, request, response }`; the generated code forwards that result and casts it to
|
|
774
|
-
* the operation's `RequestResult`, which carries the `throwOnError` discrimination.
|
|
775
|
-
*
|
|
776
|
-
* @example
|
|
777
|
-
* `return request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>`
|
|
778
|
-
*/
|
|
779
|
-
function buildReturnStatement({ node, tsResolver, callConfig }) {
|
|
780
|
-
return `return request(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
|
|
781
|
-
node,
|
|
782
|
-
tsResolver
|
|
783
|
-
})}>>`;
|
|
784
|
-
}
|
|
785
|
-
//#endregion
|
|
786
604
|
//#region ../../internals/client/src/builders/signature.ts
|
|
787
605
|
const declarationPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
|
|
788
606
|
/**
|
|
@@ -814,6 +632,151 @@ function buildGroupedOptionsSignature({ node, tsResolver }) {
|
|
|
814
632
|
};
|
|
815
633
|
}
|
|
816
634
|
//#endregion
|
|
635
|
+
//#region ../../internals/client/src/builders/validatorOptions.ts
|
|
636
|
+
/**
|
|
637
|
+
* Returns `true` when any direction of the validator uses zod (used for dependency checks).
|
|
638
|
+
*/
|
|
639
|
+
function isValidatorEnabled(validator) {
|
|
640
|
+
if (!validator) return false;
|
|
641
|
+
if (validator === "zod") return true;
|
|
642
|
+
return Boolean(validator.request || validator.response);
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Returns `'zod'` when request body parsing is enabled, `null` otherwise. The string shorthand
|
|
646
|
+
* `'zod'` validates the response only, so it does not enable request parsing.
|
|
647
|
+
*/
|
|
648
|
+
function resolveRequestValidator(validator) {
|
|
649
|
+
if (!validator || validator === "zod") return null;
|
|
650
|
+
return validator.request ?? null;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Returns `'zod'` when query-parameters parsing is enabled, `null` otherwise. Only the object form
|
|
654
|
+
* `{ request: 'zod' }` enables it.
|
|
655
|
+
*/
|
|
656
|
+
function resolveQueryParamsValidator(validator) {
|
|
657
|
+
if (!validator || validator === "zod") return null;
|
|
658
|
+
return validator.request ?? null;
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Returns `'zod'` when response parsing is enabled, `null` otherwise. The string shorthand `'zod'`
|
|
662
|
+
* maps to response parsing.
|
|
663
|
+
*/
|
|
664
|
+
function resolveResponseValidator(validator) {
|
|
665
|
+
if (!validator) return null;
|
|
666
|
+
if (validator === "zod") return "zod";
|
|
667
|
+
return validator.response ?? null;
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* Resolves the zod expression a generated client validates a success response with. Only success
|
|
671
|
+
* (2xx) bodies reach the parse under the throw-on-error contract, so the success-only
|
|
672
|
+
* `<operation>ResponseSchema` is used; error bodies are never zod-parsed.
|
|
673
|
+
*/
|
|
674
|
+
function buildZodResponseParse(node, zodResolver) {
|
|
675
|
+
const name = zodResolver.response.response(node);
|
|
676
|
+
return name ? {
|
|
677
|
+
expression: name,
|
|
678
|
+
importNames: [name]
|
|
679
|
+
} : null;
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Resolves the zod expression a generated client validates an error body with on the non-throw path.
|
|
683
|
+
* Uses the error-only `<operation>ErrorSchema` (the union of non-2xx statuses); returns `null` when the
|
|
684
|
+
* operation documents no error responses with a schema.
|
|
685
|
+
*/
|
|
686
|
+
function buildZodErrorParse(node, zodResolver) {
|
|
687
|
+
if (!node.responses.some((res) => !isSuccessStatusCode(res.statusCode) && res.content?.some((entry) => entry.schema))) return null;
|
|
688
|
+
const name = zodResolver.response.error?.(node);
|
|
689
|
+
return name ? {
|
|
690
|
+
expression: name,
|
|
691
|
+
importNames: [name]
|
|
692
|
+
} : null;
|
|
693
|
+
}
|
|
694
|
+
//#endregion
|
|
695
|
+
//#region ../../internals/client/src/builders/validator.ts
|
|
696
|
+
/**
|
|
697
|
+
* Builds the validator-hook references for one operation. Request validation runs before the send;
|
|
698
|
+
* response validation runs on the success body only. Returns `null` references when the matching
|
|
699
|
+
* direction is disabled or the schema is absent.
|
|
700
|
+
*/
|
|
701
|
+
function buildValidatorHooks({ node, validator, zodResolver }) {
|
|
702
|
+
const importedZodNames = [];
|
|
703
|
+
const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
704
|
+
const zodRequestName = zodResolver && resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body(node) : null;
|
|
705
|
+
const request = zodRequestName ?? null;
|
|
706
|
+
if (zodRequestName) importedZodNames.push(zodRequestName);
|
|
707
|
+
const responseParse = zodResolver && resolveResponseValidator(validator) === "zod" ? buildZodResponseParse(node, zodResolver) : null;
|
|
708
|
+
const response = responseParse ? responseParse.expression : null;
|
|
709
|
+
if (responseParse) importedZodNames.push(...responseParse.importNames);
|
|
710
|
+
const errorParse = zodResolver && resolveResponseValidator(validator) === "zod" ? buildZodErrorParse(node, zodResolver) : null;
|
|
711
|
+
const error = errorParse ? errorParse.expression : null;
|
|
712
|
+
if (errorParse) importedZodNames.push(...errorParse.importNames);
|
|
713
|
+
return {
|
|
714
|
+
request,
|
|
715
|
+
response,
|
|
716
|
+
error,
|
|
717
|
+
importedZodNames
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
//#endregion
|
|
721
|
+
//#region ../../internals/client/src/builders/sdkMethod.ts
|
|
722
|
+
/**
|
|
723
|
+
* Builds the call config literal forwarded to the contract client, mirroring the shared `Operation`
|
|
724
|
+
* component: `{ method, url, security?, validator?, ...config }`. The `...config` spread carries every
|
|
725
|
+
* per-call field (including `throwOnError`), so the method stays a thin wrapper over the contract.
|
|
726
|
+
*/
|
|
727
|
+
function buildCallConfig({ node, validator, zodResolver, security }) {
|
|
728
|
+
const validators = buildValidatorHooks({
|
|
729
|
+
node,
|
|
730
|
+
validator,
|
|
731
|
+
zodResolver
|
|
732
|
+
});
|
|
733
|
+
const validatorEntries = [validators.request ? `request: ${validators.request}` : null, validators.response ? `response: ${validators.response}` : null].filter(Boolean);
|
|
734
|
+
const validatorLiteral = validatorEntries.length ? `validator: { ${validatorEntries.join(", ")} }` : null;
|
|
735
|
+
const securityLiteral = buildSecurityMetadata({ security });
|
|
736
|
+
return `{ ${[
|
|
737
|
+
`method: '${node.method.toUpperCase()}'`,
|
|
738
|
+
`url: '${Url.toSafeTemplate(node.path)}'`,
|
|
739
|
+
securityLiteral ? `security: ${securityLiteral}` : null,
|
|
740
|
+
validatorLiteral,
|
|
741
|
+
"...config"
|
|
742
|
+
].filter(Boolean).join(", ")} }`;
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Builds a single instance method for a generated SDK class. The body forwards the single grouped
|
|
746
|
+
* `options` object to the instance's own client (`this.client`, built once in the constructor) and
|
|
747
|
+
* returns the `RequestResult`. A per-call `options.client` still overrides the instance client, so
|
|
748
|
+
* one operation can be routed to a different environment without a new instance.
|
|
749
|
+
*/
|
|
750
|
+
function buildSdkMethod({ node, name, tsResolver, zodResolver, validator, security }) {
|
|
751
|
+
if (!kubb_kit.ast.isHttpOperationNode(node)) return "";
|
|
752
|
+
const signature = buildGroupedOptionsSignature({
|
|
753
|
+
node,
|
|
754
|
+
tsResolver
|
|
755
|
+
});
|
|
756
|
+
const returnStatement = buildReturnStatement({
|
|
757
|
+
node,
|
|
758
|
+
tsResolver,
|
|
759
|
+
callConfig: buildCallConfig({
|
|
760
|
+
node,
|
|
761
|
+
validator,
|
|
762
|
+
zodResolver,
|
|
763
|
+
security
|
|
764
|
+
})
|
|
765
|
+
});
|
|
766
|
+
const generics = signature.generics.length ? `<${signature.generics.join(", ")}>` : "";
|
|
767
|
+
const jsdoc = buildJSDoc(buildOperationComments(node, {
|
|
768
|
+
link: "urlPath",
|
|
769
|
+
linkPosition: "beforeDeprecated",
|
|
770
|
+
splitLines: true
|
|
771
|
+
}));
|
|
772
|
+
const methodBody = [
|
|
773
|
+
"const { client: request = this.client, ...config } = options",
|
|
774
|
+
"",
|
|
775
|
+
returnStatement
|
|
776
|
+
].map((line) => line ? ` ${line}` : "").join("\n");
|
|
777
|
+
return `${jsdoc} public ${name}${generics}(${signature.paramsSignature}): ${signature.returnType} {\n${methodBody}\n }`;
|
|
778
|
+
}
|
|
779
|
+
//#endregion
|
|
817
780
|
//#region ../../internals/client/src/builders/styles.ts
|
|
818
781
|
/**
|
|
819
782
|
* Renders a parameter name as an object-literal key, quoted when it is not a bare identifier.
|
|
@@ -867,32 +830,6 @@ function buildStyles({ node }) {
|
|
|
867
830
|
return `{ ${locations.map((location) => `${location}: { ${groups[location].join(", ")} }`).join(", ")} }`;
|
|
868
831
|
}
|
|
869
832
|
//#endregion
|
|
870
|
-
//#region ../../internals/client/src/builders/validator.ts
|
|
871
|
-
/**
|
|
872
|
-
* Builds the validator-hook references for one operation. Request validation runs before the send;
|
|
873
|
-
* response validation runs on the success body only. Returns `null` references when the matching
|
|
874
|
-
* direction is disabled or the schema is absent.
|
|
875
|
-
*/
|
|
876
|
-
function buildValidatorHooks({ node, validator, zodResolver }) {
|
|
877
|
-
const importedZodNames = [];
|
|
878
|
-
const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
879
|
-
const zodRequestName = zodResolver && resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body(node) : null;
|
|
880
|
-
const request = zodRequestName ?? null;
|
|
881
|
-
if (zodRequestName) importedZodNames.push(zodRequestName);
|
|
882
|
-
const responseParse = zodResolver && resolveResponseValidator(validator) === "zod" ? buildZodResponseParse(node, zodResolver) : null;
|
|
883
|
-
const response = responseParse ? responseParse.expression : null;
|
|
884
|
-
if (responseParse) importedZodNames.push(...responseParse.importNames);
|
|
885
|
-
const errorParse = zodResolver && resolveResponseValidator(validator) === "zod" ? buildZodErrorParse(node, zodResolver) : null;
|
|
886
|
-
const error = errorParse ? errorParse.expression : null;
|
|
887
|
-
if (errorParse) importedZodNames.push(...errorParse.importNames);
|
|
888
|
-
return {
|
|
889
|
-
request,
|
|
890
|
-
response,
|
|
891
|
-
error,
|
|
892
|
-
importedZodNames
|
|
893
|
-
};
|
|
894
|
-
}
|
|
895
|
-
//#endregion
|
|
896
833
|
//#region ../../internals/client/src/components/Operation.tsx
|
|
897
834
|
/**
|
|
898
835
|
* Renders one client operation: the grouped `<Name>Request` type and the function that forwards a
|
|
@@ -927,14 +864,13 @@ function Operation({ name, node, tsResolver, zodResolver, validator, security, i
|
|
|
927
864
|
const validatorLiteral = validatorEntries.length ? `validator: { ${validatorEntries.join(", ")} }` : null;
|
|
928
865
|
const callConfig = `{ ${[
|
|
929
866
|
`method: '${node.method.toUpperCase()}'`,
|
|
930
|
-
`url: '${Url.
|
|
867
|
+
`url: '${Url.toSafeTemplate(node.path)}'`,
|
|
931
868
|
securityLiteral ? `security: ${securityLiteral}` : null,
|
|
932
869
|
stylesLiteral ? `styles: ${stylesLiteral}` : null,
|
|
933
870
|
validatorLiteral,
|
|
934
871
|
contentTypeLiteral,
|
|
935
872
|
responseTypeLiteral,
|
|
936
|
-
"...config"
|
|
937
|
-
...buildParamsRemap({ node })
|
|
873
|
+
"...config"
|
|
938
874
|
].filter(Boolean).join(", ")} }`;
|
|
939
875
|
const eventType = `SuccessOf<${tsResolver.response.responses(node)}>`;
|
|
940
876
|
const returnType = eventStream ? `Promise<EventStreamResult<${eventType}>>` : signature.returnType;
|
|
@@ -967,66 +903,6 @@ function Operation({ name, node, tsResolver, zodResolver, validator, security, i
|
|
|
967
903
|
});
|
|
968
904
|
}
|
|
969
905
|
//#endregion
|
|
970
|
-
//#region ../../internals/client/src/builders/sdkMethod.ts
|
|
971
|
-
/**
|
|
972
|
-
* Builds the call config literal forwarded to the contract client, mirroring the shared `Operation`
|
|
973
|
-
* component: `{ method, url, security?, validator?, ...config }`. The `...config` spread carries every
|
|
974
|
-
* per-call field (including `throwOnError`), so the method stays a thin wrapper over the contract.
|
|
975
|
-
*/
|
|
976
|
-
function buildCallConfig({ node, validator, zodResolver, security }) {
|
|
977
|
-
const validators = buildValidatorHooks({
|
|
978
|
-
node,
|
|
979
|
-
validator,
|
|
980
|
-
zodResolver
|
|
981
|
-
});
|
|
982
|
-
const validatorEntries = [validators.request ? `request: ${validators.request}` : null, validators.response ? `response: ${validators.response}` : null].filter(Boolean);
|
|
983
|
-
const validatorLiteral = validatorEntries.length ? `validator: { ${validatorEntries.join(", ")} }` : null;
|
|
984
|
-
const securityLiteral = buildSecurityMetadata({ security });
|
|
985
|
-
return `{ ${[
|
|
986
|
-
`method: '${node.method.toUpperCase()}'`,
|
|
987
|
-
`url: '${Url.toCasedTemplate(node.path, { casing: "camelcase" })}'`,
|
|
988
|
-
securityLiteral ? `security: ${securityLiteral}` : null,
|
|
989
|
-
validatorLiteral,
|
|
990
|
-
"...config",
|
|
991
|
-
...buildParamsRemap({ node })
|
|
992
|
-
].filter(Boolean).join(", ")} }`;
|
|
993
|
-
}
|
|
994
|
-
/**
|
|
995
|
-
* Builds a single instance method for a generated SDK class. The body forwards the single grouped
|
|
996
|
-
* `options` object to the instance's own client (`this.client`, built once in the constructor) and
|
|
997
|
-
* returns the `RequestResult`. A per-call `options.client` still overrides the instance client, so
|
|
998
|
-
* one operation can be routed to a different environment without a new instance.
|
|
999
|
-
*/
|
|
1000
|
-
function buildSdkMethod({ node, name, tsResolver, zodResolver, validator, security }) {
|
|
1001
|
-
if (!kubb_kit.ast.isHttpOperationNode(node)) return "";
|
|
1002
|
-
const signature = buildGroupedOptionsSignature({
|
|
1003
|
-
node,
|
|
1004
|
-
tsResolver
|
|
1005
|
-
});
|
|
1006
|
-
const returnStatement = buildReturnStatement({
|
|
1007
|
-
node,
|
|
1008
|
-
tsResolver,
|
|
1009
|
-
callConfig: buildCallConfig({
|
|
1010
|
-
node,
|
|
1011
|
-
validator,
|
|
1012
|
-
zodResolver,
|
|
1013
|
-
security
|
|
1014
|
-
})
|
|
1015
|
-
});
|
|
1016
|
-
const generics = signature.generics.length ? `<${signature.generics.join(", ")}>` : "";
|
|
1017
|
-
const jsdoc = buildJSDoc(buildOperationComments(node, {
|
|
1018
|
-
link: "urlPath",
|
|
1019
|
-
linkPosition: "beforeDeprecated",
|
|
1020
|
-
splitLines: true
|
|
1021
|
-
}));
|
|
1022
|
-
const methodBody = [
|
|
1023
|
-
"const { client: request = this.client, ...config } = options",
|
|
1024
|
-
"",
|
|
1025
|
-
returnStatement
|
|
1026
|
-
].map((line) => line ? ` ${line}` : "").join("\n");
|
|
1027
|
-
return `${jsdoc} public ${name}${generics}(${signature.paramsSignature}): ${signature.returnType} {\n${methodBody}\n }`;
|
|
1028
|
-
}
|
|
1029
|
-
//#endregion
|
|
1030
906
|
//#region ../../internals/client/src/components/SdkClient.tsx
|
|
1031
907
|
/**
|
|
1032
908
|
* Renders one instance class per tag with one method per operation. The constructor takes a client
|
|
@@ -1087,7 +963,7 @@ function resolveTypeImportNames(node, tsResolver) {
|
|
|
1087
963
|
return [tsResolver.response.options(node), tsResolver.response.responses(node)];
|
|
1088
964
|
}
|
|
1089
965
|
function resolveZodImportNames(node, zodResolver, validator) {
|
|
1090
|
-
const { query: queryParams } = getOperationParameters(node
|
|
966
|
+
const { query: queryParams } = getOperationParameters(node);
|
|
1091
967
|
return [
|
|
1092
968
|
resolveResponseValidator(validator) === "zod" ? zodResolver.response.response(node) : null,
|
|
1093
969
|
resolveResponseValidator(validator) === "zod" ? buildZodErrorParse(node, zodResolver)?.expression ?? null : null,
|