@kubb/plugin-msw 5.0.0-beta.10 → 5.0.0-beta.100

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/README.md CHANGED
@@ -1,18 +1,15 @@
1
1
  <div align="center">
2
- <h1>@kubb/plugin-msw</h1>
3
2
  <a href="https://kubb.dev" target="_blank" rel="noopener noreferrer">
4
- <img width="180" src="https://raw.githubusercontent.com/kubb-labs/kubb/main/assets/logo.png" alt="Kubb logo">
3
+ <img src="https://kubb.dev/og.png" alt="Kubb banner">
5
4
  </a>
6
5
 
7
6
  [![npm version][npm-version-src]][npm-version-href]
8
7
  [![npm downloads][npm-downloads-src]][npm-downloads-href]
9
- [![Coverage][coverage-src]][coverage-href]
8
+ [![Stars][stars-src]][stars-href]
10
9
  [![License][license-src]][license-href]
11
- [![Sponsors][sponsors-src]][sponsors-href]
10
+ [![Node][node-src]][node-href]
12
11
 
13
12
  <h4>
14
- <a href="https://codesandbox.io/s/github/kubb-labs/plugins/tree/main/examples/msw" target="_blank">View Demo</a>
15
- <span> · </span>
16
13
  <a href="https://kubb.dev/plugins/msw" target="_blank">Documentation</a>
17
14
  <span> · </span>
18
15
  <a href="https://github.com/kubb-labs/kubb/issues/" target="_blank">Report Bug</a>
@@ -21,14 +18,13 @@
21
18
  </h4>
22
19
  </div>
23
20
 
24
- `@kubb/plugin-msw` generates Mock Service Worker (MSW) request handlers from your OpenAPI specification. The handlers work in both browser and Node.js environments via MSW v2.
21
+ <br />
22
+
23
+ # @kubb/plugin-msw
25
24
 
26
- ## Features
25
+ ### Generate MSW request handlers with Kubb
27
26
 
28
- - Generates one handler per OpenAPI operation
29
- - Infers request and response types from the spec
30
- - Works in both browser (via service worker) and Node.js test environments
31
- - Works with `@kubb/plugin-faker` to serve realistic response data
27
+ `@kubb/plugin-msw` generates Mock Service Worker (MSW) request handlers with Kubb. The handlers work in both browser and Node.js environments via MSW v2.
32
28
 
33
29
  ## Installation
34
30
 
@@ -46,7 +42,7 @@ See the [full documentation](https://kubb.dev/plugins/msw) for configuration opt
46
42
 
47
43
  ## Supporting Kubb
48
44
 
49
- Kubb is an MIT-licensed open source project with its ongoing development made possible entirely by the support of Sponsors. If you would like to become a sponsor, please consider:
45
+ Kubb is an open source project, and its development is funded entirely by sponsors. If you would like to become a sponsor, please consider:
50
46
 
51
47
  - [Become a Sponsor on GitHub](https://github.com/sponsors/stijnvanhulle)
52
48
 
@@ -56,19 +52,19 @@ Kubb is an MIT-licensed open source project with its ongoing development made po
56
52
  </a>
57
53
  </p>
58
54
 
55
+ ## License
56
+
57
+ [MIT](https://github.com/kubb-labs/plugins/blob/main/LICENSE)
58
+
59
59
  <!-- Badges -->
60
60
 
61
- [npm-version-src]: https://img.shields.io/npm/v/@kubb/plugin-msw?flat&colorA=18181B&colorB=f58517
62
- [npm-version-href]: https://npmjs.com/package/@kubb/plugin-msw
63
- [npm-downloads-src]: https://img.shields.io/npm/dm/@kubb/plugin-msw?flat&colorA=18181B&colorB=f58517
64
- [npm-downloads-href]: https://npmjs.com/package/@kubb/plugin-msw
65
- [license-src]: https://img.shields.io/github/license/kubb-labs/kubb.svg?flat&colorA=18181B&colorB=f58517
61
+ [npm-version-src]: https://shieldcn.dev/npm/v/@kubb/plugin-msw.svg?variant=secondary&size=xs&theme=zinc&mode=dark
62
+ [npm-version-href]: https://npmx.dev/package/@kubb/plugin-msw
63
+ [npm-downloads-src]: https://shieldcn.dev/npm/dm/@kubb/plugin-msw.svg?variant=secondary&size=xs&theme=zinc&mode=dark
64
+ [npm-downloads-href]: https://npmx.dev/package/@kubb/plugin-msw
65
+ [stars-src]: https://shieldcn.dev/github/stars/kubb-labs/kubb.svg?variant=secondary&size=xs&theme=zinc&mode=dark
66
+ [stars-href]: https://github.com/kubb-labs/kubb
67
+ [license-src]: https://shieldcn.dev/npm/license/@kubb/plugin-msw.svg?variant=secondary&size=xs&theme=zinc
66
68
  [license-href]: https://github.com/kubb-labs/kubb/blob/main/LICENSE
67
- [build-src]: https://img.shields.io/github/actions/workflow/status/kubb-labs/kubb/ci.yaml?style=flat&colorA=18181B&colorB=f58517
68
- [build-href]: https://www.npmjs.com/package/@kubb/plugin-msw
69
- [minified-src]: https://img.shields.io/bundlephobia/min/@kubb/plugin-msw?style=flat&colorA=18181B&colorB=f58517
70
- [minified-href]: https://www.npmjs.com/package/@kubb/plugin-msw
71
- [coverage-src]: https://img.shields.io/codecov/c/github/kubb-labs/kubb?style=flat&colorA=18181B&colorB=f58517
72
- [coverage-href]: https://www.npmjs.com/package/@kubb/plugin-msw
73
- [sponsors-src]: https://img.shields.io/github/sponsors/stijnvanhulle?style=flat&colorA=18181B&colorB=f58517
74
- [sponsors-href]: https://github.com/sponsors/stijnvanhulle/
69
+ [node-src]: https://shieldcn.dev/npm/node/@kubb/plugin-msw.svg?variant=secondary&size=xs&theme=zinc&mode=dark
70
+ [node-href]: https://npmx.dev/package/@kubb/plugin-msw
package/dist/index.cjs CHANGED
@@ -2,60 +2,498 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_components = require("./components-BYvgvrY7.cjs");
6
- const require_generators = require("./generators-rZ99WaWQ.cjs");
7
- let _kubb_core = require("@kubb/core");
5
+ //#endregion
6
+ let kubb_kit = require("kubb/kit");
8
7
  let _kubb_plugin_faker = require("@kubb/plugin-faker");
9
8
  let _kubb_plugin_ts = require("@kubb/plugin-ts");
9
+ let kubb_jsx = require("kubb/jsx");
10
+ let kubb_jsx_jsx_runtime = require("kubb/jsx/jsx-runtime");
11
+ //#region ../../internals/shared/src/operation.ts
12
+ function getStatusCodeNumber(statusCode) {
13
+ const code = Number(statusCode);
14
+ return Number.isNaN(code) ? null : code;
15
+ }
16
+ function isSuccessStatusCode(statusCode) {
17
+ const code = getStatusCodeNumber(statusCode);
18
+ return code !== null && code >= 200 && code < 300;
19
+ }
20
+ function getSuccessResponses(responses) {
21
+ return responses.filter((response) => isSuccessStatusCode(response.statusCode));
22
+ }
23
+ function getOperationSuccessResponses(node) {
24
+ return getSuccessResponses(node.responses);
25
+ }
26
+ function getPrimarySuccessResponse(node) {
27
+ return getOperationSuccessResponses(node)[0] ?? null;
28
+ }
29
+ function resolveResponseTypes(node, resolver) {
30
+ const types = [];
31
+ for (const response of node.responses) {
32
+ if (response.statusCode === "default") {
33
+ types.push(["default", resolver.response.response(node)]);
34
+ continue;
35
+ }
36
+ const code = getStatusCodeNumber(response.statusCode);
37
+ if (code === null) continue;
38
+ types.push([code, isSuccessStatusCode(code) ? resolver.response.response(node) : resolver.response.status(node, response.statusCode)]);
39
+ }
40
+ return types;
41
+ }
42
+ //#endregion
43
+ //#region ../../internals/utils/src/casing.ts
44
+ /**
45
+ * Shared implementation for camelCase and PascalCase conversion.
46
+ * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
47
+ * and capitalizes each word according to `pascal`.
48
+ *
49
+ * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
50
+ */
51
+ function toCamelOrPascal(text, pascal) {
52
+ return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
53
+ if (word.length > 1 && word === word.toUpperCase()) return word;
54
+ return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
55
+ }).join("").replace(/[^a-zA-Z0-9]/g, "");
56
+ }
57
+ /**
58
+ * Converts `text` to camelCase.
59
+ *
60
+ * @example Word boundaries
61
+ * `camelCase('hello-world') // 'helloWorld'`
62
+ *
63
+ * @example With a prefix
64
+ * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
65
+ */
66
+ function camelCase(text, { prefix = "", suffix = "" } = {}) {
67
+ return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
68
+ }
69
+ //#endregion
70
+ //#region ../../internals/shared/src/group.ts
71
+ /**
72
+ * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
73
+ * shared default naming so every plugin groups output consistently:
74
+ *
75
+ * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
76
+ * - other groups use the camelCased group (`pet store` → `petStore`).
77
+ *
78
+ * A user-provided `group.name` always wins over the default namer, so callers stay in
79
+ * control of their output folders. Returns `null` when grouping is disabled, matching the
80
+ * per-plugin convention.
81
+ *
82
+ * @param group - The user-supplied group option, or `undefined` to disable grouping.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * createGroupConfig(group) // shared across every plugin
87
+ * ```
88
+ */
89
+ function createGroupConfig(group) {
90
+ if (!group) return null;
91
+ const defaultName = (ctx) => {
92
+ if (group.type === "path") return `${ctx.group.split("/")[1]}`;
93
+ return camelCase(ctx.group);
94
+ };
95
+ return {
96
+ ...group,
97
+ name: group.name ? group.name : defaultName
98
+ };
99
+ }
100
+ //#endregion
101
+ //#region src/generators/handlersGenerator.ts
102
+ /**
103
+ * Aggregate generator enabled by `pluginMsw({ handlers: true })`. Emits a
104
+ * `handlers.ts` file that re-exports every generated handler in operation
105
+ * order, ready to spread into `setupServer(...handlers)` or
106
+ * `setupWorker(...handlers)`.
107
+ */
108
+ const handlersGenerator = (0, kubb_kit.defineGenerator)({
109
+ name: "plugin-msw",
110
+ operations(nodes, ctx) {
111
+ const { resolver, config, root } = ctx;
112
+ const { output, group } = ctx.options;
113
+ const handlersName = resolver.handler.listName();
114
+ const file = resolver.file({
115
+ name: handlersName,
116
+ extname: ".ts",
117
+ root,
118
+ output,
119
+ group: group ?? void 0
120
+ });
121
+ const imports = nodes.map((node) => {
122
+ const operationName = resolver.handler.name(node);
123
+ const operationFile = resolver.file({
124
+ name: resolver.name(node.operationId),
125
+ extname: ".ts",
126
+ tag: node.tags[0] ?? "default",
127
+ path: node.path,
128
+ root,
129
+ output,
130
+ group: group ?? void 0
131
+ });
132
+ return kubb_kit.ast.factory.createImport({
133
+ name: [operationName],
134
+ root: file.path,
135
+ path: operationFile.path
136
+ });
137
+ });
138
+ const handlers = nodes.map((node) => `${resolver.handler.name(node)}()`);
139
+ return [kubb_kit.ast.factory.createFile({
140
+ baseName: file.baseName,
141
+ path: file.path,
142
+ meta: file.meta,
143
+ banner: resolver.default.banner(ctx.meta, {
144
+ output,
145
+ config,
146
+ file: {
147
+ path: file.path,
148
+ baseName: file.baseName
149
+ }
150
+ }),
151
+ footer: resolver.default.footer(ctx.meta, {
152
+ output,
153
+ config,
154
+ file: {
155
+ path: file.path,
156
+ baseName: file.baseName
157
+ }
158
+ }),
159
+ imports,
160
+ sources: [kubb_kit.ast.factory.createSource({
161
+ name: handlersName,
162
+ isIndexable: true,
163
+ isExportable: true,
164
+ nodes: [kubb_kit.ast.factory.createText(`export const ${handlersName} = ${JSON.stringify(handlers).replaceAll("\"", "")} as const`)]
165
+ })]
166
+ })];
167
+ }
168
+ });
169
+ //#endregion
170
+ //#region src/utils.ts
171
+ /**
172
+ * Gets the content type from a response, defaulting to 'application/json' if a schema exists.
173
+ */
174
+ function getContentType(response) {
175
+ if (!hasResponseSchema(response)) return null;
176
+ return getResponseContentType(response) ?? "application/json";
177
+ }
178
+ /**
179
+ * Determines if a response has a schema that is not void or any.
180
+ */
181
+ function hasResponseSchema(response) {
182
+ const schema = response?.content?.find((entry) => entry.schema)?.schema;
183
+ return !!schema && schema.type !== "void" && schema.type !== "any";
184
+ }
185
+ /**
186
+ * Picks the content type used for the mocked response header. When a response declares multiple
187
+ * content types, JSON is preferred (the faker mock body is JSON), otherwise the first declared type.
188
+ */
189
+ function getResponseContentType(response) {
190
+ const contents = response?.content ?? [];
191
+ const value = (contents.find((entry) => {
192
+ const baseType = entry.contentType?.split(";")[0]?.trim().toLowerCase();
193
+ return baseType === "application/json" || baseType?.endsWith("+json");
194
+ }) ?? contents[0])?.contentType;
195
+ return typeof value === "string" && value.length > 0 ? value : null;
196
+ }
197
+ /**
198
+ * Converts an HTTP method to its lowercase MSW equivalent (e.g., 'POST' → 'post').
199
+ */
200
+ function getMswMethod(node) {
201
+ return kubb_kit.ast.isHttpOperationNode(node) ? node.method.toLowerCase() : "";
202
+ }
203
+ /**
204
+ * Resolves faker metadata for an MSW operation, including response name and file path.
205
+ */
206
+ function resolveFakerMeta(node, options) {
207
+ const { root, fakerResolver, fakerOutput, fakerGroup } = options;
208
+ const tag = node.tags[0] ?? "default";
209
+ return {
210
+ name: fakerResolver.response.response(node),
211
+ file: fakerResolver.file({
212
+ name: node.operationId,
213
+ extname: ".ts",
214
+ tag,
215
+ path: node.path,
216
+ root,
217
+ output: fakerOutput,
218
+ group: fakerGroup ?? void 0
219
+ })
220
+ };
221
+ }
222
+ //#endregion
223
+ //#region src/components/Mock.tsx
224
+ const declarationPrinter$1 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
225
+ function Mock({ baseURL = "", name, fakerName, typeName, requestTypeName, node }) {
226
+ const method = getMswMethod(node);
227
+ const successResponse = getPrimarySuccessResponse(node);
228
+ const statusCode = successResponse ? Number(successResponse.statusCode) : 200;
229
+ const contentType = getContentType(successResponse);
230
+ const url = kubb_kit.ast.isHttpOperationNode(node) ? kubb_kit.Url.toPath(node.path) : "";
231
+ const headers = [contentType ? `'Content-Type': '${contentType}'` : null].filter(Boolean);
232
+ const dataType = hasResponseSchema(successResponse) ? typeName : "string | number | boolean | null | object";
233
+ const paramType = fakerName ? typeName : dataType;
234
+ const callbackType = requestTypeName ? `HttpResponseResolver<Record<string, string>, ${requestTypeName}>` : `((info: Parameters<Parameters<typeof http.${method}>[1]>[0]) => Response | Promise<Response>)`;
235
+ const params = declarationPrinter$1.print((0, _kubb_plugin_ts.createFunctionParameters)({ params: [(0, _kubb_plugin_ts.createFunctionParameter)({
236
+ name: "data",
237
+ type: `${paramType} | ${callbackType}`,
238
+ optional: true
239
+ })] }));
240
+ const httpCall = requestTypeName ? `http.${method}<Record<string, string>, ${requestTypeName}>` : `http.${method}`;
241
+ const requestUrl = `${baseURL}${url.replace(/([^/]):/g, "$1\\\\:")}`;
242
+ const urlLiteral = fakerName ? `'${requestUrl}'` : `\`${requestUrl}\``;
243
+ const responseBody = fakerName ? `JSON.stringify(data || ${fakerName}(data))` : "JSON.stringify(data)";
244
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
245
+ name,
246
+ isIndexable: true,
247
+ isExportable: true,
248
+ children: /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.Function, {
249
+ name,
250
+ export: true,
251
+ params: params ?? "",
252
+ children: `return ${httpCall}(${urlLiteral}, function handler(info) {
253
+ if(typeof data === 'function') return data(info)
254
+
255
+ return new Response(${responseBody}, {
256
+ status: ${statusCode},
257
+ ${headers.length ? ` headers: {
258
+ ${headers.join(", \n")}
259
+ },` : ""}
260
+ })
261
+ })`
262
+ })
263
+ });
264
+ }
265
+ //#endregion
266
+ //#region src/components/Response.tsx
267
+ const declarationPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
268
+ function Response({ name, typeName, response }) {
269
+ const statusCode = Number(response.statusCode);
270
+ const contentType = getContentType(response);
271
+ const headers = [contentType ? `'Content-Type': '${contentType}'` : null].filter(Boolean);
272
+ const params = declarationPrinter.print((0, _kubb_plugin_ts.createFunctionParameters)({ params: [(0, _kubb_plugin_ts.createFunctionParameter)({
273
+ name: "data",
274
+ type: typeName,
275
+ optional: !hasResponseSchema(response)
276
+ })] }));
277
+ const responseName = `${name}Response${statusCode}`;
278
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
279
+ name: responseName,
280
+ isIndexable: true,
281
+ isExportable: true,
282
+ children: /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.Function, {
283
+ name: responseName,
284
+ export: true,
285
+ params: params ?? "",
286
+ children: `
287
+ return new Response(JSON.stringify(data), {
288
+ status: ${statusCode},
289
+ ${headers.length ? ` headers: {
290
+ ${headers.join(", \n")}
291
+ },` : ""}
292
+ })`
293
+ })
294
+ });
295
+ }
296
+ //#endregion
297
+ //#region src/generators/mswGenerator.tsx
298
+ /**
299
+ * Built-in operation generator for `@kubb/plugin-msw`. Emits one MSW handler
300
+ * per OpenAPI operation. With `parser: 'faker'` the handler returns a value
301
+ * from `@kubb/plugin-faker`; with `parser: 'data'` it returns a typed empty
302
+ * payload for tests to fill in.
303
+ */
304
+ const mswGenerator = (0, kubb_kit.defineGenerator)({
305
+ name: "msw",
306
+ renderer: kubb_jsx.jsxRenderer,
307
+ operation(node, ctx) {
308
+ if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
309
+ const { driver, resolver, config, root } = ctx;
310
+ const { output, parser, baseURL, group } = ctx.options;
311
+ const fileName = resolver.name(node.operationId);
312
+ const mock = {
313
+ name: resolver.handler.name(node),
314
+ file: resolver.file({
315
+ name: fileName,
316
+ extname: ".ts",
317
+ tag: node.tags[0] ?? "default",
318
+ path: node.path,
319
+ root,
320
+ output,
321
+ group: group ?? void 0
322
+ })
323
+ };
324
+ const fakerPlugin = parser === "faker" ? driver.getPlugin(_kubb_plugin_faker.pluginFakerName) : null;
325
+ const faker = parser === "faker" && fakerPlugin ? resolveFakerMeta(node, {
326
+ root,
327
+ fakerResolver: driver.getResolver(_kubb_plugin_faker.pluginFakerName),
328
+ fakerOutput: fakerPlugin.options?.output ?? output,
329
+ fakerGroup: fakerPlugin.options?.group ?? null
330
+ }) : null;
331
+ const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
332
+ if (!pluginTs) return null;
333
+ const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
334
+ const type = {
335
+ file: tsResolver.file({
336
+ name: node.operationId,
337
+ extname: ".ts",
338
+ tag: node.tags[0] ?? "default",
339
+ path: node.path,
340
+ root,
341
+ output: pluginTs.options?.output ?? output,
342
+ group: pluginTs.options?.group ?? void 0
343
+ }),
344
+ responseName: tsResolver.response.response(node)
345
+ };
346
+ const types = resolveResponseTypes(node, tsResolver);
347
+ const hasSuccessSchema = getOperationSuccessResponses(node).some((response) => !!response.content?.[0]?.schema);
348
+ const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.response.body(node) : null;
349
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx.File, {
350
+ baseName: mock.file.baseName,
351
+ path: mock.file.path,
352
+ meta: mock.file.meta,
353
+ banner: resolver.default.banner(ctx.meta, {
354
+ output,
355
+ config,
356
+ file: {
357
+ path: mock.file.path,
358
+ baseName: mock.file.baseName
359
+ }
360
+ }),
361
+ footer: resolver.default.footer(ctx.meta, {
362
+ output,
363
+ config,
364
+ file: {
365
+ path: mock.file.path,
366
+ baseName: mock.file.baseName
367
+ }
368
+ }),
369
+ children: [
370
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
371
+ name: ["http"],
372
+ path: "msw"
373
+ }),
374
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
375
+ name: ["HttpResponseResolver"],
376
+ isTypeOnly: true,
377
+ path: "msw"
378
+ }),
379
+ /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
380
+ name: Array.from(/* @__PURE__ */ new Set([
381
+ type.responseName,
382
+ ...types.map((t) => t[1]),
383
+ ...requestName ? [requestName] : []
384
+ ])),
385
+ path: type.file.path,
386
+ root: mock.file.path,
387
+ isTypeOnly: true
388
+ }),
389
+ parser === "faker" && faker && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
390
+ name: [faker.name],
391
+ root: mock.file.path,
392
+ path: faker.file.path
393
+ }),
394
+ types.filter(([code]) => code !== "default").map(([code, typeName]) => {
395
+ const response = node.responses.find((item) => item.statusCode === String(code));
396
+ if (!response) return null;
397
+ return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(Response, {
398
+ typeName,
399
+ response,
400
+ name: mock.name
401
+ }, typeName);
402
+ }),
403
+ parser === "faker" && faker && hasSuccessSchema ? /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(Mock, {
404
+ name: mock.name,
405
+ typeName: type.responseName,
406
+ requestTypeName: requestName,
407
+ fakerName: faker.name,
408
+ node,
409
+ baseURL
410
+ }) : /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(Mock, {
411
+ name: mock.name,
412
+ typeName: type.responseName,
413
+ requestTypeName: requestName,
414
+ node,
415
+ baseURL
416
+ })
417
+ ]
418
+ });
419
+ }
420
+ });
421
+ //#endregion
10
422
  //#region src/resolvers/resolverMsw.ts
11
423
  /**
12
- * Naming convention resolver for MSW plugin.
424
+ * Default resolver used by `@kubb/plugin-msw`. Decides the names and file
425
+ * paths for every generated MSW handler. Function names get a `Handler`
426
+ * suffix; the aggregate export is always `handlers`.
427
+ *
428
+ * The top-level `name` applies the `handler` suffix, and `file` falls back to the built-in
429
+ * `toFilePath` casing. Operation-specific naming is grouped under the `handler` namespace.
430
+ *
431
+ * @example Resolve a handler name
432
+ * ```ts
433
+ * import { resolverMsw } from '@kubb/plugin-msw'
13
434
  *
14
- * Provides default naming helpers using camelCase with a `handler` suffix.
435
+ * resolverMsw.name('addPet') // 'addPetHandler'
436
+ * ```
15
437
  */
16
- const resolverMsw = (0, _kubb_core.defineResolver)(() => ({
17
- name: "default",
438
+ const resolverMsw = (0, kubb_kit.createResolver)({
18
439
  pluginName: "plugin-msw",
19
- default(name, type) {
20
- return require_components.camelCase(name, { isFile: type === "file" });
440
+ name(name) {
441
+ return camelCase(name, { suffix: "handler" });
21
442
  },
22
- resolveName(name) {
23
- return require_components.camelCase(name, { suffix: "handler" });
24
- },
25
- resolvePathName(name, type) {
26
- return this.default(name, type);
27
- },
28
- resolveHandlerName(node) {
29
- return this.resolveName(node.operationId);
30
- },
31
- resolveHandlersName() {
32
- return "handlers";
443
+ handler: {
444
+ name(node) {
445
+ return this.name(node.operationId);
446
+ },
447
+ listName() {
448
+ return "handlers";
449
+ }
33
450
  }
34
- }));
451
+ });
35
452
  //#endregion
36
453
  //#region src/plugin.ts
454
+ /**
455
+ * Canonical plugin name for `@kubb/plugin-msw`. Used for driver lookups and
456
+ * cross-plugin dependency references.
457
+ */
37
458
  const pluginMswName = "plugin-msw";
38
- const pluginMsw = (0, _kubb_core.definePlugin)((options) => {
459
+ /**
460
+ * Generates MSW request handlers from an OpenAPI spec. Drop them into your
461
+ * test setup or service worker to mock the API end-to-end. Request path,
462
+ * method, status, and response body all stay in sync with the spec. Combine
463
+ * with `@kubb/plugin-faker` (via `parser: 'faker'`) to seed handlers with
464
+ * realistic data.
465
+ *
466
+ * @example
467
+ * ```ts
468
+ * import { defineConfig } from 'kubb/config'
469
+ * import { pluginTs } from '@kubb/plugin-ts'
470
+ * import { pluginMsw } from '@kubb/plugin-msw'
471
+ *
472
+ * export default defineConfig({
473
+ * input: './petStore.yaml',
474
+ * output: { path: './src/gen' },
475
+ * plugins: [
476
+ * pluginTs(),
477
+ * pluginMsw({
478
+ * output: { path: './handlers' },
479
+ * handlers: true,
480
+ * }),
481
+ * ],
482
+ * })
483
+ * ```
484
+ */
485
+ const pluginMsw = (0, kubb_kit.definePlugin)((options) => {
39
486
  const { output = {
40
487
  path: "handlers",
41
- barrelType: "named"
42
- }, group, exclude = [], include, override = [], handlers = false, parser = "data", baseURL, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
43
- const groupConfig = group ? {
44
- ...group,
45
- name: group.name ? group.name : (ctx) => {
46
- if (group.type === "path") return `${ctx.group.split("/")[1]}`;
47
- return `${require_components.camelCase(ctx.group)}Controller`;
48
- }
49
- } : void 0;
488
+ barrel: { type: "named" }
489
+ }, group, exclude = [], include, override = [], handlers = false, parser = "data", baseURL, resolver: userResolver, macros: userMacros } = options;
490
+ const groupConfig = createGroupConfig(group);
50
491
  return {
51
492
  name: pluginMswName,
52
493
  options,
53
- dependencies: [_kubb_plugin_ts.pluginTsName, parser === "faker" ? _kubb_plugin_faker.pluginFakerName : void 0].filter((dependency) => Boolean(dependency)),
494
+ dependencies: [_kubb_plugin_ts.pluginTsName, parser === "faker" ? _kubb_plugin_faker.pluginFakerName : null].filter((dependency) => Boolean(dependency)),
54
495
  hooks: { "kubb:plugin:setup"(ctx) {
55
- const resolver = userResolver ? {
56
- ...resolverMsw,
57
- ...userResolver
58
- } : resolverMsw;
496
+ const resolver = userResolver ? kubb_kit.Resolver.merge(resolverMsw, userResolver) : resolverMsw;
59
497
  ctx.setOptions({
60
498
  output,
61
499
  parser,
@@ -68,10 +506,9 @@ const pluginMsw = (0, _kubb_core.definePlugin)((options) => {
68
506
  resolver
69
507
  });
70
508
  ctx.setResolver(resolver);
71
- if (userTransformer) ctx.setTransformer(userTransformer);
72
- ctx.addGenerator(require_generators.mswGenerator);
73
- if (handlers) ctx.addGenerator(require_generators.handlersGenerator);
74
- for (const gen of userGenerators) ctx.addGenerator(gen);
509
+ if (userMacros?.length) ctx.setMacros(userMacros);
510
+ ctx.addGenerator(mswGenerator);
511
+ if (handlers) ctx.addGenerator(handlersGenerator);
75
512
  } }
76
513
  };
77
514
  });
@@ -79,5 +516,6 @@ const pluginMsw = (0, _kubb_core.definePlugin)((options) => {
79
516
  exports.default = pluginMsw;
80
517
  exports.pluginMsw = pluginMsw;
81
518
  exports.pluginMswName = pluginMswName;
519
+ exports.resolverMsw = resolverMsw;
82
520
 
83
521
  //# sourceMappingURL=index.cjs.map