@kubb/plugin-client 5.5.10 → 5.5.12
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 +164 -187
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +165 -188
- package/dist/index.js.map +1 -1
- package/docs/guides/write-your-client.md +12 -0
- package/docs/overview.md +1 -1
- package/package.json +5 -5
- package/src/plugin.ts +2 -2
package/dist/index.js
CHANGED
|
@@ -1,28 +1,10 @@
|
|
|
1
1
|
import "./rolldown-runtime-C0LytTxp.js";
|
|
2
|
-
import { Resolver, Url, addGenerator, ast, createResolver, defineExtension, defineGenerator, macroSimplifyUnion, setMacros, setResolver } from "kubb/kit";
|
|
2
|
+
import { Diagnostics, Resolver, Url, addGenerator, ast, createResolver, defineExtension, defineGenerator, macroSimplifyUnion, setMacros, setResolver } from "kubb/kit";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { createFunctionParameter, createFunctionParameters, functionPrinter, pluginTsName } from "@kubb/plugin-ts";
|
|
5
5
|
import { pluginZodName } from "@kubb/plugin-zod";
|
|
6
6
|
import { File, Function, jsxRenderer } from "kubb/jsx";
|
|
7
7
|
import { jsx, jsxs } from "kubb/jsx/jsx-runtime";
|
|
8
|
-
//#region ../../internals/shared/src/params.ts
|
|
9
|
-
/**
|
|
10
|
-
* Drops parameters that share the same name, keeping the first.
|
|
11
|
-
*
|
|
12
|
-
* A malformed spec can declare the same parameter name twice within one `in` location. Both would
|
|
13
|
-
* resolve to the same output property, so emitting both would yield an object type with a duplicate
|
|
14
|
-
* member, which TypeScript rejects. This is a defensive guard against that case, not a casing guard:
|
|
15
|
-
* parameter names flow through unchanged, so no two distinct names ever collide here anymore.
|
|
16
|
-
*/
|
|
17
|
-
function dedupeParams(params) {
|
|
18
|
-
const seen = /* @__PURE__ */ new Set();
|
|
19
|
-
return params.filter((param) => {
|
|
20
|
-
if (seen.has(param.name)) return false;
|
|
21
|
-
seen.add(param.name);
|
|
22
|
-
return true;
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
//#endregion
|
|
26
8
|
//#region ../../internals/shared/src/operation.ts
|
|
27
9
|
/**
|
|
28
10
|
* Builds the `ResolverFileParams` every operation generator passes to
|
|
@@ -184,11 +166,19 @@ const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
|
|
|
184
166
|
function getOperationParameters(node) {
|
|
185
167
|
const cached = operationParameterGroupsByNode.get(node);
|
|
186
168
|
if (cached) return cached;
|
|
169
|
+
const group = (location) => {
|
|
170
|
+
const seen = /* @__PURE__ */ new Set();
|
|
171
|
+
return node.parameters.filter((param) => {
|
|
172
|
+
if (param.in !== location || seen.has(param.name)) return false;
|
|
173
|
+
seen.add(param.name);
|
|
174
|
+
return true;
|
|
175
|
+
});
|
|
176
|
+
};
|
|
187
177
|
const groups = {
|
|
188
|
-
path:
|
|
189
|
-
query:
|
|
190
|
-
header:
|
|
191
|
-
cookie:
|
|
178
|
+
path: group("path"),
|
|
179
|
+
query: group("query"),
|
|
180
|
+
header: group("header"),
|
|
181
|
+
cookie: group("cookie")
|
|
192
182
|
};
|
|
193
183
|
operationParameterGroupsByNode.set(node, groups);
|
|
194
184
|
return groups;
|
|
@@ -427,7 +417,135 @@ var compatibility = {
|
|
|
427
417
|
};
|
|
428
418
|
//#endregion
|
|
429
419
|
//#region package.json
|
|
430
|
-
var version = "5.5.
|
|
420
|
+
var version = "5.5.12";
|
|
421
|
+
//#endregion
|
|
422
|
+
//#region ../../internals/client/src/builders/validatorOptions.ts
|
|
423
|
+
/**
|
|
424
|
+
* Returns `true` when any direction of the validator uses zod (used for dependency checks).
|
|
425
|
+
*/
|
|
426
|
+
function isValidatorEnabled(validator) {
|
|
427
|
+
if (!validator) return false;
|
|
428
|
+
if (validator === "zod") return true;
|
|
429
|
+
return Boolean(validator.request || validator.response);
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Returns `'zod'` when request body parsing is enabled, `null` otherwise. The string shorthand
|
|
433
|
+
* `'zod'` validates the response only, so it does not enable request parsing.
|
|
434
|
+
*/
|
|
435
|
+
function resolveRequestValidator(validator) {
|
|
436
|
+
if (!validator || validator === "zod") return null;
|
|
437
|
+
return validator.request ?? null;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Returns `'zod'` when response parsing is enabled, `null` otherwise. The string shorthand `'zod'`
|
|
441
|
+
* maps to response parsing.
|
|
442
|
+
*/
|
|
443
|
+
function resolveResponseValidator(validator) {
|
|
444
|
+
if (!validator) return null;
|
|
445
|
+
if (validator === "zod") return "zod";
|
|
446
|
+
return validator.response ?? null;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Resolves the zod schema name a generated client validates an error body with on the non-throw path.
|
|
450
|
+
* Uses the error-only `<operation>ErrorSchema` (the union of non-2xx statuses); returns `null` when the
|
|
451
|
+
* operation documents no error responses with a schema.
|
|
452
|
+
*/
|
|
453
|
+
function buildZodErrorParse(node, zodResolver) {
|
|
454
|
+
if (!node.responses.some((res) => !isSuccessStatusCode(res.statusCode) && res.content?.some((entry) => entry.schema))) return null;
|
|
455
|
+
return zodResolver.response.error?.(node) || null;
|
|
456
|
+
}
|
|
457
|
+
//#endregion
|
|
458
|
+
//#region ../../internals/client/src/builders/validator.ts
|
|
459
|
+
/**
|
|
460
|
+
* Builds the validator-hook references for one operation. Request validation runs before the send;
|
|
461
|
+
* response validation runs on the success body only. Returns `null` references when the matching
|
|
462
|
+
* direction is disabled or the schema is absent.
|
|
463
|
+
*/
|
|
464
|
+
function buildValidatorHooks({ node, validator, zodResolver }) {
|
|
465
|
+
const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
466
|
+
const parsesResponse = zodResolver && resolveResponseValidator(validator) === "zod";
|
|
467
|
+
const response = parsesResponse ? zodResolver.response.response(node) || null : null;
|
|
468
|
+
const error = parsesResponse ? buildZodErrorParse(node, zodResolver) : null;
|
|
469
|
+
const request = zodResolver && resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body(node) || null : null;
|
|
470
|
+
return {
|
|
471
|
+
request,
|
|
472
|
+
response,
|
|
473
|
+
error,
|
|
474
|
+
importedZodNames: [
|
|
475
|
+
response,
|
|
476
|
+
error,
|
|
477
|
+
request
|
|
478
|
+
].filter((name) => Boolean(name))
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
//#endregion
|
|
482
|
+
//#region ../../internals/client/src/builders/security.ts
|
|
483
|
+
function serializeAuth(auth) {
|
|
484
|
+
const parts = [`type: '${auth.type}'`];
|
|
485
|
+
if (auth.scheme) parts.push(`scheme: '${auth.scheme}'`);
|
|
486
|
+
if (auth.name) parts.push(`name: '${auth.name}'`);
|
|
487
|
+
if (auth.in) parts.push(`in: '${auth.in}'`);
|
|
488
|
+
return `{ ${parts.join(", ")} }`;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Maps an OpenAPI security scheme to the inline `Auth` object, or `null` when the runtime cannot
|
|
492
|
+
* place it (an unresolved `$ref`, or an `apiKey` without a name or outside `header` / `query` /
|
|
493
|
+
* `cookie`). `http` schemes other than `basic` are treated as bearer.
|
|
494
|
+
*/
|
|
495
|
+
function resolveSecurityScheme(scheme) {
|
|
496
|
+
if (!scheme || "$ref" in scheme) return null;
|
|
497
|
+
if (scheme.type === "apiKey") {
|
|
498
|
+
if (!scheme.name || scheme.in !== "header" && scheme.in !== "query" && scheme.in !== "cookie") return null;
|
|
499
|
+
return {
|
|
500
|
+
type: "apiKey",
|
|
501
|
+
name: scheme.name,
|
|
502
|
+
in: scheme.in
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
if (scheme.type === "http") return {
|
|
506
|
+
type: "http",
|
|
507
|
+
scheme: scheme.scheme?.toLowerCase() === "basic" ? "basic" : "bearer"
|
|
508
|
+
};
|
|
509
|
+
if (scheme.type === "oauth2") return { type: "oauth2" };
|
|
510
|
+
if (scheme.type === "openIdConnect") return { type: "openIdConnect" };
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Derives the per-operation security metadata from the OpenAPI document. The operation's own
|
|
515
|
+
* `security` overrides the global `security` (an explicit empty array disables auth), and every
|
|
516
|
+
* referenced scheme is resolved from `components.securitySchemes` into a flat, de-duplicated list of
|
|
517
|
+
* `Auth` objects the runtime walks in order.
|
|
518
|
+
*
|
|
519
|
+
* @example
|
|
520
|
+
* `getOperationSecurity({ document, method: 'POST', path: '/pet' })`
|
|
521
|
+
* `// [{ type: 'http', scheme: 'bearer' }]`
|
|
522
|
+
*/
|
|
523
|
+
function getOperationSecurity({ document, method, path }) {
|
|
524
|
+
if (!document) return void 0;
|
|
525
|
+
const requirements = (document.paths?.[path]?.[method.toLowerCase()])?.security ?? document.security;
|
|
526
|
+
if (!requirements?.length) return void 0;
|
|
527
|
+
const definitions = document.components?.securitySchemes ?? {};
|
|
528
|
+
const security = [];
|
|
529
|
+
const seen = /* @__PURE__ */ new Set();
|
|
530
|
+
for (const requirement of requirements) for (const schemeName of Object.keys(requirement)) {
|
|
531
|
+
if (seen.has(schemeName)) continue;
|
|
532
|
+
seen.add(schemeName);
|
|
533
|
+
const auth = resolveSecurityScheme(definitions[schemeName]);
|
|
534
|
+
if (auth) security.push(auth);
|
|
535
|
+
}
|
|
536
|
+
return security.length ? security : void 0;
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Serializes the per-operation security into the literal emitted on each generated call's `security`
|
|
540
|
+
* field. The runtime `resolveAuth` helper walks it, calling the configured `auth` resolver per entry.
|
|
541
|
+
*
|
|
542
|
+
* @example
|
|
543
|
+
* `buildSecurityMetadata({ security: [{ type: 'http', scheme: 'bearer' }] }) // "[{ type: 'http', scheme: 'bearer' }]"`
|
|
544
|
+
*/
|
|
545
|
+
function buildSecurityMetadata({ security }) {
|
|
546
|
+
if (!security?.length) return null;
|
|
547
|
+
return `[${security.map(serializeAuth).join(", ")}]`;
|
|
548
|
+
}
|
|
431
549
|
//#endregion
|
|
432
550
|
//#region ../../internals/client/src/builders/contentType.ts
|
|
433
551
|
/**
|
|
@@ -521,74 +639,6 @@ function buildReturnStatement({ node, types, callConfig, returnType, throwOnErro
|
|
|
521
639
|
})}>>)`;
|
|
522
640
|
}
|
|
523
641
|
//#endregion
|
|
524
|
-
//#region ../../internals/client/src/builders/security.ts
|
|
525
|
-
function serializeAuth(auth) {
|
|
526
|
-
const parts = [`type: '${auth.type}'`];
|
|
527
|
-
if (auth.scheme) parts.push(`scheme: '${auth.scheme}'`);
|
|
528
|
-
if (auth.name) parts.push(`name: '${auth.name}'`);
|
|
529
|
-
if (auth.in) parts.push(`in: '${auth.in}'`);
|
|
530
|
-
return `{ ${parts.join(", ")} }`;
|
|
531
|
-
}
|
|
532
|
-
/**
|
|
533
|
-
* Maps an OpenAPI security scheme to the inline `Auth` object, or `null` when the runtime cannot
|
|
534
|
-
* place it (an unresolved `$ref`, or an `apiKey` without a name or outside `header` / `query` /
|
|
535
|
-
* `cookie`). `http` schemes other than `basic` are treated as bearer.
|
|
536
|
-
*/
|
|
537
|
-
function resolveSecurityScheme(scheme) {
|
|
538
|
-
if (!scheme || "$ref" in scheme) return null;
|
|
539
|
-
if (scheme.type === "apiKey") {
|
|
540
|
-
if (!scheme.name || scheme.in !== "header" && scheme.in !== "query" && scheme.in !== "cookie") return null;
|
|
541
|
-
return {
|
|
542
|
-
type: "apiKey",
|
|
543
|
-
name: scheme.name,
|
|
544
|
-
in: scheme.in
|
|
545
|
-
};
|
|
546
|
-
}
|
|
547
|
-
if (scheme.type === "http") return {
|
|
548
|
-
type: "http",
|
|
549
|
-
scheme: scheme.scheme?.toLowerCase() === "basic" ? "basic" : "bearer"
|
|
550
|
-
};
|
|
551
|
-
if (scheme.type === "oauth2") return { type: "oauth2" };
|
|
552
|
-
if (scheme.type === "openIdConnect") return { type: "openIdConnect" };
|
|
553
|
-
return null;
|
|
554
|
-
}
|
|
555
|
-
/**
|
|
556
|
-
* Derives the per-operation security metadata from the OpenAPI document. The operation's own
|
|
557
|
-
* `security` overrides the global `security` (an explicit empty array disables auth), and every
|
|
558
|
-
* referenced scheme is resolved from `components.securitySchemes` into a flat, de-duplicated list of
|
|
559
|
-
* `Auth` objects the runtime walks in order.
|
|
560
|
-
*
|
|
561
|
-
* @example
|
|
562
|
-
* `getOperationSecurity({ document, method: 'POST', path: '/pet' })`
|
|
563
|
-
* `// [{ type: 'http', scheme: 'bearer' }]`
|
|
564
|
-
*/
|
|
565
|
-
function getOperationSecurity({ document, method, path }) {
|
|
566
|
-
if (!document) return void 0;
|
|
567
|
-
const requirements = (document.paths?.[path]?.[method.toLowerCase()])?.security ?? document.security;
|
|
568
|
-
if (!requirements?.length) return void 0;
|
|
569
|
-
const definitions = document.components?.securitySchemes ?? {};
|
|
570
|
-
const security = [];
|
|
571
|
-
const seen = /* @__PURE__ */ new Set();
|
|
572
|
-
for (const requirement of requirements) for (const schemeName of Object.keys(requirement)) {
|
|
573
|
-
if (seen.has(schemeName)) continue;
|
|
574
|
-
seen.add(schemeName);
|
|
575
|
-
const auth = resolveSecurityScheme(definitions[schemeName]);
|
|
576
|
-
if (auth) security.push(auth);
|
|
577
|
-
}
|
|
578
|
-
return security.length ? security : void 0;
|
|
579
|
-
}
|
|
580
|
-
/**
|
|
581
|
-
* Serializes the per-operation security into the literal emitted on each generated call's `security`
|
|
582
|
-
* field. The runtime `resolveAuth` helper walks it, calling the configured `auth` resolver per entry.
|
|
583
|
-
*
|
|
584
|
-
* @example
|
|
585
|
-
* `buildSecurityMetadata({ security: [{ type: 'http', scheme: 'bearer' }] }) // "[{ type: 'http', scheme: 'bearer' }]"`
|
|
586
|
-
*/
|
|
587
|
-
function buildSecurityMetadata({ security }) {
|
|
588
|
-
if (!security?.length) return null;
|
|
589
|
-
return `[${security.map(serializeAuth).join(", ")}]`;
|
|
590
|
-
}
|
|
591
|
-
//#endregion
|
|
592
642
|
//#region ../../internals/client/src/builders/signature.ts
|
|
593
643
|
const declarationPrinter = functionPrinter({ mode: "declaration" });
|
|
594
644
|
/**
|
|
@@ -618,76 +668,6 @@ function buildGroupedOptionsSignature({ node, types, returnType, throwOnErrorDef
|
|
|
618
668
|
};
|
|
619
669
|
}
|
|
620
670
|
//#endregion
|
|
621
|
-
//#region ../../internals/client/src/builders/validatorOptions.ts
|
|
622
|
-
/**
|
|
623
|
-
* Returns `'zod'` when request body parsing is enabled, `null` otherwise. The string shorthand
|
|
624
|
-
* `'zod'` validates the response only, so it does not enable request parsing.
|
|
625
|
-
*/
|
|
626
|
-
function resolveRequestValidator(validator) {
|
|
627
|
-
if (!validator || validator === "zod") return null;
|
|
628
|
-
return validator.request ?? null;
|
|
629
|
-
}
|
|
630
|
-
/**
|
|
631
|
-
* Returns `'zod'` when response parsing is enabled, `null` otherwise. The string shorthand `'zod'`
|
|
632
|
-
* maps to response parsing.
|
|
633
|
-
*/
|
|
634
|
-
function resolveResponseValidator(validator) {
|
|
635
|
-
if (!validator) return null;
|
|
636
|
-
if (validator === "zod") return "zod";
|
|
637
|
-
return validator.response ?? null;
|
|
638
|
-
}
|
|
639
|
-
/**
|
|
640
|
-
* Resolves the zod expression a generated client validates a success response with. Only success
|
|
641
|
-
* (2xx) bodies reach the parse under the throw-on-error contract, so the success-only
|
|
642
|
-
* `<operation>ResponseSchema` is used; error bodies are never zod-parsed.
|
|
643
|
-
*/
|
|
644
|
-
function buildZodResponseParse(node, zodResolver) {
|
|
645
|
-
const name = zodResolver.response.response(node);
|
|
646
|
-
return name ? {
|
|
647
|
-
expression: name,
|
|
648
|
-
importNames: [name]
|
|
649
|
-
} : null;
|
|
650
|
-
}
|
|
651
|
-
/**
|
|
652
|
-
* Resolves the zod expression a generated client validates an error body with on the non-throw path.
|
|
653
|
-
* Uses the error-only `<operation>ErrorSchema` (the union of non-2xx statuses); returns `null` when the
|
|
654
|
-
* operation documents no error responses with a schema.
|
|
655
|
-
*/
|
|
656
|
-
function buildZodErrorParse(node, zodResolver) {
|
|
657
|
-
if (!node.responses.some((res) => !isSuccessStatusCode(res.statusCode) && res.content?.some((entry) => entry.schema))) return null;
|
|
658
|
-
const name = zodResolver.response.error?.(node);
|
|
659
|
-
return name ? {
|
|
660
|
-
expression: name,
|
|
661
|
-
importNames: [name]
|
|
662
|
-
} : null;
|
|
663
|
-
}
|
|
664
|
-
//#endregion
|
|
665
|
-
//#region ../../internals/client/src/builders/validator.ts
|
|
666
|
-
/**
|
|
667
|
-
* Builds the validator-hook references for one operation. Request validation runs before the send;
|
|
668
|
-
* response validation runs on the success body only. Returns `null` references when the matching
|
|
669
|
-
* direction is disabled or the schema is absent.
|
|
670
|
-
*/
|
|
671
|
-
function buildValidatorHooks({ node, validator, zodResolver }) {
|
|
672
|
-
const importedZodNames = [];
|
|
673
|
-
const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
674
|
-
const zodRequestName = zodResolver && resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body(node) : null;
|
|
675
|
-
const request = zodRequestName ?? null;
|
|
676
|
-
if (zodRequestName) importedZodNames.push(zodRequestName);
|
|
677
|
-
const responseParse = zodResolver && resolveResponseValidator(validator) === "zod" ? buildZodResponseParse(node, zodResolver) : null;
|
|
678
|
-
const response = responseParse ? responseParse.expression : null;
|
|
679
|
-
if (responseParse) importedZodNames.push(...responseParse.importNames);
|
|
680
|
-
const errorParse = zodResolver && resolveResponseValidator(validator) === "zod" ? buildZodErrorParse(node, zodResolver) : null;
|
|
681
|
-
const error = errorParse ? errorParse.expression : null;
|
|
682
|
-
if (errorParse) importedZodNames.push(...errorParse.importNames);
|
|
683
|
-
return {
|
|
684
|
-
request,
|
|
685
|
-
response,
|
|
686
|
-
error,
|
|
687
|
-
importedZodNames
|
|
688
|
-
};
|
|
689
|
-
}
|
|
690
|
-
//#endregion
|
|
691
671
|
//#region ../../internals/client/src/builders/styles.ts
|
|
692
672
|
/**
|
|
693
673
|
* Renders a parameter name as an object-literal key, quoted when it is not a bare identifier.
|
|
@@ -748,7 +728,7 @@ function buildStyles({ node }) {
|
|
|
748
728
|
* type, signature, and call config are built with the AST factory, and only the jsx-renderer emits
|
|
749
729
|
* the source.
|
|
750
730
|
*/
|
|
751
|
-
function Operation({ name, node, types, zodResolver, validator, returnType, throwOnErrorDefault, security
|
|
731
|
+
function Operation({ name, node, types, zodResolver, validator, returnType, throwOnErrorDefault, security }) {
|
|
752
732
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
753
733
|
const signature = buildGroupedOptionsSignature({
|
|
754
734
|
node,
|
|
@@ -795,11 +775,11 @@ function Operation({ name, node, types, zodResolver, validator, returnType, thro
|
|
|
795
775
|
});
|
|
796
776
|
return /* @__PURE__ */ jsx(File.Source, {
|
|
797
777
|
name,
|
|
798
|
-
isExportable,
|
|
799
|
-
isIndexable,
|
|
778
|
+
isExportable: true,
|
|
779
|
+
isIndexable: true,
|
|
800
780
|
children: /* @__PURE__ */ jsxs(Function, {
|
|
801
781
|
name,
|
|
802
|
-
export:
|
|
782
|
+
export: true,
|
|
803
783
|
generics: signature.generics,
|
|
804
784
|
params: signature.paramsSignature,
|
|
805
785
|
returnType: functionReturnType,
|
|
@@ -819,27 +799,22 @@ function Operation({ name, node, types, zodResolver, validator, returnType, thro
|
|
|
819
799
|
//#endregion
|
|
820
800
|
//#region ../../internals/client/src/resolveOperationTypes.ts
|
|
821
801
|
/**
|
|
822
|
-
* Warning a client generator reports when neither plugin can supply the operation types, so the
|
|
823
|
-
* pipeline says why nothing was generated instead of silently emitting no files.
|
|
824
|
-
*/
|
|
825
|
-
const MISSING_OPERATION_TYPES_WARNING = "Skipped: no operation types available. Add `pluginTs()`, or `pluginZod({ inferred: true })` to type the client from its zod schemas.";
|
|
826
|
-
/**
|
|
827
802
|
* Picks the plugin a generated client takes its `Options` and `Responses` types from.
|
|
828
803
|
*
|
|
829
804
|
* `plugin-ts` wins whenever it is in the pipeline, so existing configs keep the types they generate
|
|
830
805
|
* today. Without it, `pluginZod({ inferred: true })` takes over: its inferred options and responses
|
|
831
806
|
* types are built from the same shared schemas as the `plugin-ts` ones, so a client typed off
|
|
832
807
|
* `z.infer` carries what the codecs decode to (a `Temporal` instance, a `Date`) rather than the raw
|
|
833
|
-
* wire type.
|
|
808
|
+
* wire type. Throws `KUBB_MISSING_DEPENDENCY` for `pluginName` when neither is available, since the
|
|
809
|
+
* client has nothing to type against.
|
|
834
810
|
*
|
|
835
811
|
* @example
|
|
836
812
|
* ```ts
|
|
837
|
-
* const types = resolveOperationTypes(ctx.driver)
|
|
838
|
-
* if (!types) return null
|
|
813
|
+
* const types = resolveOperationTypes(ctx.driver, ctx.plugin.name)
|
|
839
814
|
* types.response.options(node) // 'GetPetByIdOptions', or 'GetPetByIdOptionsSchemaType' from zod
|
|
840
815
|
* ```
|
|
841
816
|
*/
|
|
842
|
-
function resolveOperationTypes(driver) {
|
|
817
|
+
function resolveOperationTypes(driver, pluginName) {
|
|
843
818
|
const pluginTs = driver.getPlugin(pluginTsName);
|
|
844
819
|
if (pluginTs) {
|
|
845
820
|
const resolver = driver.getResolver(pluginTsName);
|
|
@@ -851,7 +826,14 @@ function resolveOperationTypes(driver) {
|
|
|
851
826
|
};
|
|
852
827
|
}
|
|
853
828
|
const pluginZod = driver.getPlugin(pluginZodName);
|
|
854
|
-
if (!pluginZod?.options?.inferred)
|
|
829
|
+
if (!pluginZod?.options?.inferred) throw new Diagnostics.Error({
|
|
830
|
+
code: Diagnostics.code.missingDependency,
|
|
831
|
+
severity: "error",
|
|
832
|
+
message: `Plugin "${pluginName}" has no source for operation types.`,
|
|
833
|
+
help: `Add \`pluginTs()\` before "${pluginName}", or add \`pluginZod({ inferred: true })\`.`,
|
|
834
|
+
location: { kind: "config" },
|
|
835
|
+
plugin: pluginName
|
|
836
|
+
});
|
|
855
837
|
const resolver = driver.getResolver(pluginZodName);
|
|
856
838
|
return {
|
|
857
839
|
response: {
|
|
@@ -881,20 +863,15 @@ function createClientGenerator(name, resolveClientPath) {
|
|
|
881
863
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
882
864
|
const { config, driver, resolver, root } = ctx;
|
|
883
865
|
const { output, validator, returnType, throwOnErrorDefault, group } = ctx.options;
|
|
884
|
-
const types = resolveOperationTypes(driver);
|
|
885
|
-
if (!types) {
|
|
886
|
-
ctx.warn(MISSING_OPERATION_TYPES_WARNING);
|
|
887
|
-
return null;
|
|
888
|
-
}
|
|
866
|
+
const types = resolveOperationTypes(driver, ctx.plugin.name);
|
|
889
867
|
const pluginZod = resolveResponseValidator(validator) === "zod" || resolveRequestValidator(validator) === "zod" ? driver.getPlugin(pluginZodName) : null;
|
|
890
868
|
const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null;
|
|
891
|
-
const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
892
869
|
const importedTypeNames = [types.response.options(node), types.response.responses(node)];
|
|
893
|
-
const importedZodNames =
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
870
|
+
const importedZodNames = buildValidatorHooks({
|
|
871
|
+
node,
|
|
872
|
+
validator,
|
|
873
|
+
zodResolver
|
|
874
|
+
}).importedZodNames;
|
|
898
875
|
const meta = {
|
|
899
876
|
name: resolver.name(node.operationId),
|
|
900
877
|
file: resolver.file({
|
|
@@ -1070,7 +1047,7 @@ const pluginClient = defineExtension({
|
|
|
1070
1047
|
},
|
|
1071
1048
|
dependencies: (options) => ({
|
|
1072
1049
|
[pluginTsName]: { optional: true },
|
|
1073
|
-
[pluginZodName]: { optional: !options.validator }
|
|
1050
|
+
[pluginZodName]: { optional: !isValidatorEnabled(options.validator) }
|
|
1074
1051
|
}),
|
|
1075
1052
|
setup(options) {
|
|
1076
1053
|
const { output = {
|