@kubb/plugin-msw 5.0.0-beta.4 → 5.0.0-beta.56

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 (42) hide show
  1. package/README.md +39 -22
  2. package/dist/{components-vO0FIb2i.js → components-Bi7cN-ws.js} +111 -199
  3. package/dist/components-Bi7cN-ws.js.map +1 -0
  4. package/dist/{components-CLQ77DVn.cjs → components-Bp69JYOt.cjs} +113 -213
  5. package/dist/components-Bp69JYOt.cjs.map +1 -0
  6. package/dist/components.cjs +1 -2
  7. package/dist/components.d.ts +6 -19
  8. package/dist/components.js +2 -2
  9. package/dist/{generators-BPJCs1x1.js → generators-BnEvTy3q.js} +71 -39
  10. package/dist/generators-BnEvTy3q.js.map +1 -0
  11. package/dist/{generators-CrmMwWE4.cjs → generators-d22_s2UN.cjs} +69 -37
  12. package/dist/generators-d22_s2UN.cjs.map +1 -0
  13. package/dist/generators.cjs +1 -1
  14. package/dist/generators.d.ts +16 -5
  15. package/dist/generators.js +1 -1
  16. package/dist/index.cjs +112 -17
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.ts +33 -4
  19. package/dist/index.js +113 -18
  20. package/dist/index.js.map +1 -1
  21. package/dist/types-B1yTWOfj.d.ts +99 -0
  22. package/package.json +13 -23
  23. package/src/components/Mock.tsx +7 -6
  24. package/src/components/MockWithFaker.tsx +7 -6
  25. package/src/components/Response.tsx +1 -1
  26. package/src/components/index.ts +0 -1
  27. package/src/generators/handlersGenerator.ts +49 -0
  28. package/src/generators/index.ts +1 -1
  29. package/src/generators/mswGenerator.tsx +27 -16
  30. package/src/plugin.ts +35 -19
  31. package/src/resolvers/resolverMsw.ts +21 -5
  32. package/src/types.ts +36 -26
  33. package/src/utils.ts +26 -61
  34. package/dist/components-CLQ77DVn.cjs.map +0 -1
  35. package/dist/components-vO0FIb2i.js.map +0 -1
  36. package/dist/generators-BPJCs1x1.js.map +0 -1
  37. package/dist/generators-CrmMwWE4.cjs.map +0 -1
  38. package/dist/types-Dxu0KMQ4.d.ts +0 -89
  39. package/extension.yaml +0 -260
  40. package/src/components/Handlers.tsx +0 -19
  41. package/src/generators/handlersGenerator.tsx +0 -41
  42. /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["camelCase","camelCase","pluginTsName","pluginFakerName","mswGenerator","handlersGenerator"],"sources":["../src/resolvers/resolverMsw.ts","../src/plugin.ts"],"sourcesContent":["import { camelCase } from '@internals/utils'\nimport { defineResolver } from '@kubb/core'\nimport type { PluginMsw } from '../types.ts'\n\n/**\n * Naming convention resolver for MSW plugin.\n *\n * Provides default naming helpers using camelCase with a `handler` suffix.\n */\nexport const resolverMsw = defineResolver<PluginMsw>((_ctx) => ({\n name: 'default',\n pluginName: 'plugin-msw',\n default(name, type) {\n return camelCase(name, { isFile: type === 'file' })\n },\n resolveName(name) {\n return camelCase(name, { suffix: 'handler' })\n },\n}))\n","import { camelCase } from '@internals/utils'\nimport { definePlugin, type Group } from '@kubb/core'\nimport { pluginFakerName } from '@kubb/plugin-faker'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { handlersGenerator, mswGenerator } from './generators'\nimport { resolverMsw } from './resolvers/resolverMsw.ts'\nimport type { PluginMsw } from './types.ts'\n\nexport const pluginMswName = 'plugin-msw' satisfies PluginMsw['name']\n\nexport const pluginMsw = definePlugin<PluginMsw>((options) => {\n const {\n output = { path: 'handlers', barrelType: 'named' },\n group,\n exclude = [],\n include,\n override = [],\n transformers = {},\n handlers = false,\n parser = 'data',\n baseURL,\n resolver: userResolver,\n transformer: userTransformer,\n generators: userGenerators = [],\n } = options\n\n const groupConfig = group\n ? ({\n ...group,\n name: group.name\n ? group.name\n : (ctx: { group: string }) => {\n if (group.type === 'path') {\n return `${ctx.group.split('/')[1]}`\n }\n return `${camelCase(ctx.group)}Controller`\n },\n } satisfies Group)\n : undefined\n\n return {\n name: pluginMswName,\n options,\n dependencies: [pluginTsName, parser === 'faker' ? pluginFakerName : undefined].filter(Boolean),\n hooks: {\n 'kubb:plugin:setup'(ctx) {\n const resolver = userResolver ? { ...resolverMsw, ...userResolver } : resolverMsw\n\n ctx.setOptions({\n output,\n parser,\n baseURL,\n group: groupConfig,\n exclude,\n include,\n override,\n handlers,\n transformers,\n resolver,\n })\n ctx.setResolver(resolver)\n if (userTransformer) {\n ctx.setTransformer(userTransformer)\n }\n\n ctx.addGenerator(mswGenerator)\n if (handlers) {\n ctx.addGenerator(handlersGenerator)\n }\n for (const gen of userGenerators) {\n ctx.addGenerator(gen)\n }\n },\n },\n }\n})\n\nexport default pluginMsw\n"],"mappings":";;;;;;;;;;;;;;;AASA,MAAa,eAAA,GAAA,WAAA,iBAAyC,UAAU;CAC9D,MAAM;CACN,YAAY;CACZ,QAAQ,MAAM,MAAM;AAClB,SAAOA,mBAAAA,UAAU,MAAM,EAAE,QAAQ,SAAS,QAAQ,CAAC;;CAErD,YAAY,MAAM;AAChB,SAAOA,mBAAAA,UAAU,MAAM,EAAE,QAAQ,WAAW,CAAC;;CAEhD,EAAE;;;ACVH,MAAa,gBAAgB;AAE7B,MAAa,aAAA,GAAA,WAAA,eAAqC,YAAY;CAC5D,MAAM,EACJ,SAAS;EAAE,MAAM;EAAY,YAAY;EAAS,EAClD,OACA,UAAU,EAAE,EACZ,SACA,WAAW,EAAE,EACb,eAAe,EAAE,EACjB,WAAW,OACX,SAAS,QACT,SACA,UAAU,cACV,aAAa,iBACb,YAAY,iBAAiB,EAAE,KAC7B;CAEJ,MAAM,cAAc,QACf;EACC,GAAG;EACH,MAAM,MAAM,OACR,MAAM,QACL,QAA2B;AAC1B,OAAI,MAAM,SAAS,OACjB,QAAO,GAAG,IAAI,MAAM,MAAM,IAAI,CAAC;AAEjC,UAAO,GAAGC,mBAAAA,UAAU,IAAI,MAAM,CAAC;;EAEtC,GACD,KAAA;AAEJ,QAAO;EACL,MAAM;EACN;EACA,cAAc,CAACC,gBAAAA,cAAc,WAAW,UAAUC,mBAAAA,kBAAkB,KAAA,EAAU,CAAC,OAAO,QAAQ;EAC9F,OAAO,EACL,oBAAoB,KAAK;GACvB,MAAM,WAAW,eAAe;IAAE,GAAG;IAAa,GAAG;IAAc,GAAG;AAEtE,OAAI,WAAW;IACb;IACA;IACA;IACA,OAAO;IACP;IACA;IACA;IACA;IACA;IACA;IACD,CAAC;AACF,OAAI,YAAY,SAAS;AACzB,OAAI,gBACF,KAAI,eAAe,gBAAgB;AAGrC,OAAI,aAAaC,mBAAAA,aAAa;AAC9B,OAAI,SACF,KAAI,aAAaC,mBAAAA,kBAAkB;AAErC,QAAK,MAAM,OAAO,eAChB,KAAI,aAAa,IAAI;KAG1B;EACF;EACD"}
1
+ {"version":3,"file":"index.cjs","names":["camelCase","camelCase","camelCase","pluginTsName","pluginFakerName","mswGenerator","handlersGenerator"],"sources":["../../../internals/utils/src/fs.ts","../../../internals/shared/src/group.ts","../src/resolvers/resolverMsw.ts","../src/plugin.ts"],"sourcesContent":["import { posix } from 'node:path'\nimport { camelCase } from './casing.ts'\n\nfunction toSlash(p: string): string {\n if (p.startsWith('\\\\\\\\?\\\\')) return p\n return p.replaceAll('\\\\', '/')\n}\n\n/**\n * Returns the relative path from `rootDir` to `filePath`, always using forward slashes\n * and prefixed with `./` when not already traversing upward.\n *\n * @example\n * ```ts\n * getRelativePath('/src/components', '/src/components/Button.tsx') // './Button.tsx'\n * getRelativePath('/src/components', '/src/utils/helpers.ts') // '../utils/helpers.ts'\n * ```\n */\nexport function getRelativePath(rootDir?: string | null, filePath?: string | null): string {\n if (!rootDir || !filePath) {\n throw new Error(`Root and file should be filled in when retrieving the relativePath, ${rootDir || ''} ${filePath || ''}`)\n }\n\n const relativePath = posix.relative(toSlash(rootDir), toSlash(filePath))\n\n return relativePath.startsWith('../') ? relativePath : `./${relativePath}`\n}\n\n/**\n * Builds a nested file path from a dotted name. Splits on dots that precede a letter\n * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases\n * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.\n *\n * Empty segments are dropped before joining. They arise when the name starts with a dot\n * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to\n * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an\n * absolute path, letting generated files escape the configured output directory.\n *\n * @example Nested path from a dotted name\n * `toFilePath('pet.petId') // 'pet/petId'`\n *\n * @example PascalCase the final segment\n * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`\n *\n * @example Suffix applied to the final segment only\n * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`\n */\nexport function toFilePath(name: string, caseLast: (part: string) => string = camelCase): string {\n const parts = name.split(/\\.(?=[a-zA-Z])/)\n return parts\n .map((part, i) => (i === parts.length - 1 ? caseLast(part) : camelCase(part)))\n .filter(Boolean)\n .join('/')\n}\n","import { camelCase } from '@internals/utils'\nimport type { Group } from '@kubb/core'\n\n/**\n * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the\n * shared default naming so every plugin groups output consistently:\n *\n * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).\n * - other groups use the camelCased group (`pet store` → `petStore`).\n *\n * A user-provided `group.name` always wins over the default namer, so callers stay in\n * control of their output folders. Returns `null` when grouping is disabled, matching the\n * per-plugin convention.\n *\n * @param group - The user-supplied group option, or `undefined` to disable grouping.\n *\n * @example\n * ```ts\n * createGroupConfig(group) // shared across every plugin\n * ```\n */\nexport function createGroupConfig(group: Group | undefined): Group | null {\n if (!group) {\n return null\n }\n\n const defaultName = (ctx: { group: string }): string => {\n if (group.type === 'path') {\n return `${ctx.group.split('/')[1]}`\n }\n\n return camelCase(ctx.group)\n }\n\n return {\n ...group,\n name: group.name ? group.name : defaultName,\n } satisfies Group\n}\n","import { camelCase, toFilePath } from '@internals/utils'\nimport { defineResolver } from '@kubb/core'\nimport type { PluginMsw } from '../types.ts'\n\n/**\n * Default resolver used by `@kubb/plugin-msw`. Decides the names and file\n * paths for every generated MSW handler. Function names get a `Handler`\n * suffix; the aggregate export is always `handlers`.\n *\n * @example Resolve a handler name\n * ```ts\n * import { resolverMsw } from '@kubb/plugin-msw'\n *\n * resolverMsw.resolveName('addPet') // 'addPetHandler'\n * ```\n */\nexport const resolverMsw = defineResolver<PluginMsw>(() => ({\n name: 'default',\n pluginName: 'plugin-msw',\n default(name, type) {\n return type === 'file' ? toFilePath(name) : camelCase(name)\n },\n resolveName(name) {\n return camelCase(name, { suffix: 'handler' })\n },\n resolvePathName(name, type) {\n return this.default(name, type)\n },\n resolveHandlerName(node) {\n return this.resolveName(node.operationId)\n },\n resolveHandlersName() {\n return 'handlers'\n },\n}))\n","import { createGroupConfig } from '@internals/shared'\nimport { definePlugin } from '@kubb/core'\nimport { pluginFakerName } from '@kubb/plugin-faker'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { handlersGenerator, mswGenerator } from './generators'\nimport { resolverMsw } from './resolvers/resolverMsw.ts'\nimport type { PluginMsw } from './types.ts'\n\n/**\n * Canonical plugin name for `@kubb/plugin-msw`. Used for driver lookups and\n * cross-plugin dependency references.\n */\nexport const pluginMswName = 'plugin-msw' satisfies PluginMsw['name']\n\n/**\n * Generates MSW request handlers from an OpenAPI spec. Drop them into your\n * test setup or service worker to mock the API end-to-end. Request path,\n * method, status, and response body all stay in sync with the spec. Combine\n * with `@kubb/plugin-faker` (via `parser: 'faker'`) to seed handlers with\n * realistic data.\n *\n * @example\n * ```ts\n * import { defineConfig } from 'kubb'\n * import { pluginTs } from '@kubb/plugin-ts'\n * import { pluginMsw } from '@kubb/plugin-msw'\n *\n * export default defineConfig({\n * input: { path: './petStore.yaml' },\n * output: { path: './src/gen' },\n * plugins: [\n * pluginTs(),\n * pluginMsw({\n * output: { path: './handlers' },\n * handlers: true,\n * }),\n * ],\n * })\n * ```\n */\nexport const pluginMsw = definePlugin<PluginMsw>((options) => {\n const {\n output = { path: 'handlers', barrel: { type: 'named' } },\n group,\n exclude = [],\n include,\n override = [],\n handlers = false,\n parser = 'data',\n baseURL,\n resolver: userResolver,\n transformer: userTransformer,\n generators: userGenerators = [],\n } = options\n\n const groupConfig = createGroupConfig(group)\n\n return {\n name: pluginMswName,\n options,\n dependencies: [pluginTsName, parser === 'faker' ? pluginFakerName : null].filter((dependency): dependency is string => Boolean(dependency)),\n hooks: {\n 'kubb:plugin:setup'(ctx) {\n const resolver = userResolver ? { ...resolverMsw, ...userResolver } : resolverMsw\n\n ctx.setOptions({\n output,\n parser,\n baseURL,\n group: groupConfig,\n exclude,\n include,\n override,\n handlers,\n resolver,\n })\n ctx.setResolver(resolver)\n if (userTransformer) {\n ctx.setTransformer(userTransformer)\n }\n\n ctx.addGenerator(mswGenerator)\n if (handlers) {\n ctx.addGenerator(handlersGenerator)\n }\n for (const gen of userGenerators) {\n ctx.addGenerator(gen)\n }\n },\n },\n }\n})\n\nexport default pluginMsw\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CA,SAAgB,WAAW,MAAc,WAAqCA,mBAAAA,WAAmB;CAC/F,MAAM,QAAQ,KAAK,MAAM,gBAAgB;CACzC,OAAO,MACJ,KAAK,MAAM,MAAO,MAAM,MAAM,SAAS,IAAI,SAAS,IAAI,IAAIA,mBAAAA,UAAU,IAAI,CAAE,CAAC,CAC7E,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;AACb;;;;;;;;;;;;;;;;;;;;;AChCA,SAAgB,kBAAkB,OAAwC;CACxE,IAAI,CAAC,OACH,OAAO;CAGT,MAAM,eAAe,QAAmC;EACtD,IAAI,MAAM,SAAS,QACjB,OAAO,GAAG,IAAI,MAAM,MAAM,GAAG,CAAC,CAAC;EAGjC,OAAOC,mBAAAA,UAAU,IAAI,KAAK;CAC5B;CAEA,OAAO;EACL,GAAG;EACH,MAAM,MAAM,OAAO,MAAM,OAAO;CAClC;AACF;;;;;;;;;;;;;;;ACtBA,MAAa,eAAA,GAAA,WAAA,eAAA,QAA+C;CAC1D,MAAM;CACN,YAAY;CACZ,QAAQ,MAAM,MAAM;EAClB,OAAO,SAAS,SAAS,WAAW,IAAI,IAAIC,mBAAAA,UAAU,IAAI;CAC5D;CACA,YAAY,MAAM;EAChB,OAAOA,mBAAAA,UAAU,MAAM,EAAE,QAAQ,UAAU,CAAC;CAC9C;CACA,gBAAgB,MAAM,MAAM;EAC1B,OAAO,KAAK,QAAQ,MAAM,IAAI;CAChC;CACA,mBAAmB,MAAM;EACvB,OAAO,KAAK,YAAY,KAAK,WAAW;CAC1C;CACA,sBAAsB;EACpB,OAAO;CACT;AACF,EAAE;;;;;;;ACtBF,MAAa,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4B7B,MAAa,aAAA,GAAA,WAAA,aAAA,EAAqC,YAAY;CAC5D,MAAM,EACJ,SAAS;EAAE,MAAM;EAAY,QAAQ,EAAE,MAAM,QAAQ;CAAE,GACvD,OACA,UAAU,CAAC,GACX,SACA,WAAW,CAAC,GACZ,WAAW,OACX,SAAS,QACT,SACA,UAAU,cACV,aAAa,iBACb,YAAY,iBAAiB,CAAC,MAC5B;CAEJ,MAAM,cAAc,kBAAkB,KAAK;CAE3C,OAAO;EACL,MAAM;EACN;EACA,cAAc,CAACC,gBAAAA,cAAc,WAAW,UAAUC,mBAAAA,kBAAkB,IAAI,CAAC,CAAC,QAAQ,eAAqC,QAAQ,UAAU,CAAC;EAC1I,OAAO,EACL,oBAAoB,KAAK;GACvB,MAAM,WAAW,eAAe;IAAE,GAAG;IAAa,GAAG;GAAa,IAAI;GAEtE,IAAI,WAAW;IACb;IACA;IACA;IACA,OAAO;IACP;IACA;IACA;IACA;IACA;GACF,CAAC;GACD,IAAI,YAAY,QAAQ;GACxB,IAAI,iBACF,IAAI,eAAe,eAAe;GAGpC,IAAI,aAAaC,mBAAAA,YAAY;GAC7B,IAAI,UACF,IAAI,aAAaC,mBAAAA,iBAAiB;GAEpC,KAAK,MAAM,OAAO,gBAChB,IAAI,aAAa,GAAG;EAExB,EACF;CACF;AACF,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,10 +1,39 @@
1
- import { t as __name } from "./chunk--u3MIqq1.js";
2
- import { n as PluginMsw, t as Options } from "./types-Dxu0KMQ4.js";
3
- import * as _$_kubb_core0 from "@kubb/core";
1
+ import { t as __name } from "./chunk-C0LytTxp.js";
2
+ import { n as PluginMsw, t as Options } from "./types-B1yTWOfj.js";
4
3
 
5
4
  //#region src/plugin.d.ts
5
+ /**
6
+ * Canonical plugin name for `@kubb/plugin-msw`. Used for driver lookups and
7
+ * cross-plugin dependency references.
8
+ */
6
9
  declare const pluginMswName = "plugin-msw";
7
- declare const pluginMsw: (options?: Options | undefined) => _$_kubb_core0.Plugin<PluginMsw>;
10
+ /**
11
+ * Generates MSW request handlers from an OpenAPI spec. Drop them into your
12
+ * test setup or service worker to mock the API end-to-end. Request path,
13
+ * method, status, and response body all stay in sync with the spec. Combine
14
+ * with `@kubb/plugin-faker` (via `parser: 'faker'`) to seed handlers with
15
+ * realistic data.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { defineConfig } from 'kubb'
20
+ * import { pluginTs } from '@kubb/plugin-ts'
21
+ * import { pluginMsw } from '@kubb/plugin-msw'
22
+ *
23
+ * export default defineConfig({
24
+ * input: { path: './petStore.yaml' },
25
+ * output: { path: './src/gen' },
26
+ * plugins: [
27
+ * pluginTs(),
28
+ * pluginMsw({
29
+ * output: { path: './handlers' },
30
+ * handlers: true,
31
+ * }),
32
+ * ],
33
+ * })
34
+ * ```
35
+ */
36
+ declare const pluginMsw: (options?: Options | undefined) => import("@kubb/core").Plugin<PluginMsw>;
8
37
  //#endregion
9
38
  export { type PluginMsw, pluginMsw as default, pluginMsw, pluginMswName };
10
39
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,44 +1,140 @@
1
- import "./chunk--u3MIqq1.js";
2
- import { l as camelCase } from "./components-vO0FIb2i.js";
3
- import { n as handlersGenerator, t as mswGenerator } from "./generators-BPJCs1x1.js";
1
+ import "./chunk-C0LytTxp.js";
2
+ import { s as camelCase } from "./components-Bi7cN-ws.js";
3
+ import { n as handlersGenerator, t as mswGenerator } from "./generators-BnEvTy3q.js";
4
4
  import { definePlugin, defineResolver } from "@kubb/core";
5
5
  import { pluginFakerName } from "@kubb/plugin-faker";
6
6
  import { pluginTsName } from "@kubb/plugin-ts";
7
+ //#region ../../internals/utils/src/fs.ts
8
+ /**
9
+ * Builds a nested file path from a dotted name. Splits on dots that precede a letter
10
+ * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
11
+ * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
12
+ *
13
+ * Empty segments are dropped before joining. They arise when the name starts with a dot
14
+ * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
15
+ * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
16
+ * absolute path, letting generated files escape the configured output directory.
17
+ *
18
+ * @example Nested path from a dotted name
19
+ * `toFilePath('pet.petId') // 'pet/petId'`
20
+ *
21
+ * @example PascalCase the final segment
22
+ * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
23
+ *
24
+ * @example Suffix applied to the final segment only
25
+ * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
26
+ */
27
+ function toFilePath(name, caseLast = camelCase) {
28
+ const parts = name.split(/\.(?=[a-zA-Z])/);
29
+ return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
30
+ }
31
+ //#endregion
32
+ //#region ../../internals/shared/src/group.ts
33
+ /**
34
+ * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
35
+ * shared default naming so every plugin groups output consistently:
36
+ *
37
+ * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
38
+ * - other groups use the camelCased group (`pet store` → `petStore`).
39
+ *
40
+ * A user-provided `group.name` always wins over the default namer, so callers stay in
41
+ * control of their output folders. Returns `null` when grouping is disabled, matching the
42
+ * per-plugin convention.
43
+ *
44
+ * @param group - The user-supplied group option, or `undefined` to disable grouping.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * createGroupConfig(group) // shared across every plugin
49
+ * ```
50
+ */
51
+ function createGroupConfig(group) {
52
+ if (!group) return null;
53
+ const defaultName = (ctx) => {
54
+ if (group.type === "path") return `${ctx.group.split("/")[1]}`;
55
+ return camelCase(ctx.group);
56
+ };
57
+ return {
58
+ ...group,
59
+ name: group.name ? group.name : defaultName
60
+ };
61
+ }
62
+ //#endregion
7
63
  //#region src/resolvers/resolverMsw.ts
8
64
  /**
9
- * Naming convention resolver for MSW plugin.
65
+ * Default resolver used by `@kubb/plugin-msw`. Decides the names and file
66
+ * paths for every generated MSW handler. Function names get a `Handler`
67
+ * suffix; the aggregate export is always `handlers`.
68
+ *
69
+ * @example Resolve a handler name
70
+ * ```ts
71
+ * import { resolverMsw } from '@kubb/plugin-msw'
10
72
  *
11
- * Provides default naming helpers using camelCase with a `handler` suffix.
73
+ * resolverMsw.resolveName('addPet') // 'addPetHandler'
74
+ * ```
12
75
  */
13
- const resolverMsw = defineResolver((_ctx) => ({
76
+ const resolverMsw = defineResolver(() => ({
14
77
  name: "default",
15
78
  pluginName: "plugin-msw",
16
79
  default(name, type) {
17
- return camelCase(name, { isFile: type === "file" });
80
+ return type === "file" ? toFilePath(name) : camelCase(name);
18
81
  },
19
82
  resolveName(name) {
20
83
  return camelCase(name, { suffix: "handler" });
84
+ },
85
+ resolvePathName(name, type) {
86
+ return this.default(name, type);
87
+ },
88
+ resolveHandlerName(node) {
89
+ return this.resolveName(node.operationId);
90
+ },
91
+ resolveHandlersName() {
92
+ return "handlers";
21
93
  }
22
94
  }));
23
95
  //#endregion
24
96
  //#region src/plugin.ts
97
+ /**
98
+ * Canonical plugin name for `@kubb/plugin-msw`. Used for driver lookups and
99
+ * cross-plugin dependency references.
100
+ */
25
101
  const pluginMswName = "plugin-msw";
102
+ /**
103
+ * Generates MSW request handlers from an OpenAPI spec. Drop them into your
104
+ * test setup or service worker to mock the API end-to-end. Request path,
105
+ * method, status, and response body all stay in sync with the spec. Combine
106
+ * with `@kubb/plugin-faker` (via `parser: 'faker'`) to seed handlers with
107
+ * realistic data.
108
+ *
109
+ * @example
110
+ * ```ts
111
+ * import { defineConfig } from 'kubb'
112
+ * import { pluginTs } from '@kubb/plugin-ts'
113
+ * import { pluginMsw } from '@kubb/plugin-msw'
114
+ *
115
+ * export default defineConfig({
116
+ * input: { path: './petStore.yaml' },
117
+ * output: { path: './src/gen' },
118
+ * plugins: [
119
+ * pluginTs(),
120
+ * pluginMsw({
121
+ * output: { path: './handlers' },
122
+ * handlers: true,
123
+ * }),
124
+ * ],
125
+ * })
126
+ * ```
127
+ */
26
128
  const pluginMsw = definePlugin((options) => {
27
129
  const { output = {
28
130
  path: "handlers",
29
- barrelType: "named"
30
- }, group, exclude = [], include, override = [], transformers = {}, handlers = false, parser = "data", baseURL, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
31
- const groupConfig = group ? {
32
- ...group,
33
- name: group.name ? group.name : (ctx) => {
34
- if (group.type === "path") return `${ctx.group.split("/")[1]}`;
35
- return `${camelCase(ctx.group)}Controller`;
36
- }
37
- } : void 0;
131
+ barrel: { type: "named" }
132
+ }, group, exclude = [], include, override = [], handlers = false, parser = "data", baseURL, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
133
+ const groupConfig = createGroupConfig(group);
38
134
  return {
39
135
  name: pluginMswName,
40
136
  options,
41
- dependencies: [pluginTsName, parser === "faker" ? pluginFakerName : void 0].filter(Boolean),
137
+ dependencies: [pluginTsName, parser === "faker" ? pluginFakerName : null].filter((dependency) => Boolean(dependency)),
42
138
  hooks: { "kubb:plugin:setup"(ctx) {
43
139
  const resolver = userResolver ? {
44
140
  ...resolverMsw,
@@ -53,7 +149,6 @@ const pluginMsw = definePlugin((options) => {
53
149
  include,
54
150
  override,
55
151
  handlers,
56
- transformers,
57
152
  resolver
58
153
  });
59
154
  ctx.setResolver(resolver);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/resolvers/resolverMsw.ts","../src/plugin.ts"],"sourcesContent":["import { camelCase } from '@internals/utils'\nimport { defineResolver } from '@kubb/core'\nimport type { PluginMsw } from '../types.ts'\n\n/**\n * Naming convention resolver for MSW plugin.\n *\n * Provides default naming helpers using camelCase with a `handler` suffix.\n */\nexport const resolverMsw = defineResolver<PluginMsw>((_ctx) => ({\n name: 'default',\n pluginName: 'plugin-msw',\n default(name, type) {\n return camelCase(name, { isFile: type === 'file' })\n },\n resolveName(name) {\n return camelCase(name, { suffix: 'handler' })\n },\n}))\n","import { camelCase } from '@internals/utils'\nimport { definePlugin, type Group } from '@kubb/core'\nimport { pluginFakerName } from '@kubb/plugin-faker'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { handlersGenerator, mswGenerator } from './generators'\nimport { resolverMsw } from './resolvers/resolverMsw.ts'\nimport type { PluginMsw } from './types.ts'\n\nexport const pluginMswName = 'plugin-msw' satisfies PluginMsw['name']\n\nexport const pluginMsw = definePlugin<PluginMsw>((options) => {\n const {\n output = { path: 'handlers', barrelType: 'named' },\n group,\n exclude = [],\n include,\n override = [],\n transformers = {},\n handlers = false,\n parser = 'data',\n baseURL,\n resolver: userResolver,\n transformer: userTransformer,\n generators: userGenerators = [],\n } = options\n\n const groupConfig = group\n ? ({\n ...group,\n name: group.name\n ? group.name\n : (ctx: { group: string }) => {\n if (group.type === 'path') {\n return `${ctx.group.split('/')[1]}`\n }\n return `${camelCase(ctx.group)}Controller`\n },\n } satisfies Group)\n : undefined\n\n return {\n name: pluginMswName,\n options,\n dependencies: [pluginTsName, parser === 'faker' ? pluginFakerName : undefined].filter(Boolean),\n hooks: {\n 'kubb:plugin:setup'(ctx) {\n const resolver = userResolver ? { ...resolverMsw, ...userResolver } : resolverMsw\n\n ctx.setOptions({\n output,\n parser,\n baseURL,\n group: groupConfig,\n exclude,\n include,\n override,\n handlers,\n transformers,\n resolver,\n })\n ctx.setResolver(resolver)\n if (userTransformer) {\n ctx.setTransformer(userTransformer)\n }\n\n ctx.addGenerator(mswGenerator)\n if (handlers) {\n ctx.addGenerator(handlersGenerator)\n }\n for (const gen of userGenerators) {\n ctx.addGenerator(gen)\n }\n },\n },\n }\n})\n\nexport default pluginMsw\n"],"mappings":";;;;;;;;;;;;AASA,MAAa,cAAc,gBAA2B,UAAU;CAC9D,MAAM;CACN,YAAY;CACZ,QAAQ,MAAM,MAAM;AAClB,SAAO,UAAU,MAAM,EAAE,QAAQ,SAAS,QAAQ,CAAC;;CAErD,YAAY,MAAM;AAChB,SAAO,UAAU,MAAM,EAAE,QAAQ,WAAW,CAAC;;CAEhD,EAAE;;;ACVH,MAAa,gBAAgB;AAE7B,MAAa,YAAY,cAAyB,YAAY;CAC5D,MAAM,EACJ,SAAS;EAAE,MAAM;EAAY,YAAY;EAAS,EAClD,OACA,UAAU,EAAE,EACZ,SACA,WAAW,EAAE,EACb,eAAe,EAAE,EACjB,WAAW,OACX,SAAS,QACT,SACA,UAAU,cACV,aAAa,iBACb,YAAY,iBAAiB,EAAE,KAC7B;CAEJ,MAAM,cAAc,QACf;EACC,GAAG;EACH,MAAM,MAAM,OACR,MAAM,QACL,QAA2B;AAC1B,OAAI,MAAM,SAAS,OACjB,QAAO,GAAG,IAAI,MAAM,MAAM,IAAI,CAAC;AAEjC,UAAO,GAAG,UAAU,IAAI,MAAM,CAAC;;EAEtC,GACD,KAAA;AAEJ,QAAO;EACL,MAAM;EACN;EACA,cAAc,CAAC,cAAc,WAAW,UAAU,kBAAkB,KAAA,EAAU,CAAC,OAAO,QAAQ;EAC9F,OAAO,EACL,oBAAoB,KAAK;GACvB,MAAM,WAAW,eAAe;IAAE,GAAG;IAAa,GAAG;IAAc,GAAG;AAEtE,OAAI,WAAW;IACb;IACA;IACA;IACA,OAAO;IACP;IACA;IACA;IACA;IACA;IACA;IACD,CAAC;AACF,OAAI,YAAY,SAAS;AACzB,OAAI,gBACF,KAAI,eAAe,gBAAgB;AAGrC,OAAI,aAAa,aAAa;AAC9B,OAAI,SACF,KAAI,aAAa,kBAAkB;AAErC,QAAK,MAAM,OAAO,eAChB,KAAI,aAAa,IAAI;KAG1B;EACF;EACD"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../internals/utils/src/fs.ts","../../../internals/shared/src/group.ts","../src/resolvers/resolverMsw.ts","../src/plugin.ts"],"sourcesContent":["import { posix } from 'node:path'\nimport { camelCase } from './casing.ts'\n\nfunction toSlash(p: string): string {\n if (p.startsWith('\\\\\\\\?\\\\')) return p\n return p.replaceAll('\\\\', '/')\n}\n\n/**\n * Returns the relative path from `rootDir` to `filePath`, always using forward slashes\n * and prefixed with `./` when not already traversing upward.\n *\n * @example\n * ```ts\n * getRelativePath('/src/components', '/src/components/Button.tsx') // './Button.tsx'\n * getRelativePath('/src/components', '/src/utils/helpers.ts') // '../utils/helpers.ts'\n * ```\n */\nexport function getRelativePath(rootDir?: string | null, filePath?: string | null): string {\n if (!rootDir || !filePath) {\n throw new Error(`Root and file should be filled in when retrieving the relativePath, ${rootDir || ''} ${filePath || ''}`)\n }\n\n const relativePath = posix.relative(toSlash(rootDir), toSlash(filePath))\n\n return relativePath.startsWith('../') ? relativePath : `./${relativePath}`\n}\n\n/**\n * Builds a nested file path from a dotted name. Splits on dots that precede a letter\n * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases\n * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.\n *\n * Empty segments are dropped before joining. They arise when the name starts with a dot\n * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to\n * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an\n * absolute path, letting generated files escape the configured output directory.\n *\n * @example Nested path from a dotted name\n * `toFilePath('pet.petId') // 'pet/petId'`\n *\n * @example PascalCase the final segment\n * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`\n *\n * @example Suffix applied to the final segment only\n * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`\n */\nexport function toFilePath(name: string, caseLast: (part: string) => string = camelCase): string {\n const parts = name.split(/\\.(?=[a-zA-Z])/)\n return parts\n .map((part, i) => (i === parts.length - 1 ? caseLast(part) : camelCase(part)))\n .filter(Boolean)\n .join('/')\n}\n","import { camelCase } from '@internals/utils'\nimport type { Group } from '@kubb/core'\n\n/**\n * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the\n * shared default naming so every plugin groups output consistently:\n *\n * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).\n * - other groups use the camelCased group (`pet store` → `petStore`).\n *\n * A user-provided `group.name` always wins over the default namer, so callers stay in\n * control of their output folders. Returns `null` when grouping is disabled, matching the\n * per-plugin convention.\n *\n * @param group - The user-supplied group option, or `undefined` to disable grouping.\n *\n * @example\n * ```ts\n * createGroupConfig(group) // shared across every plugin\n * ```\n */\nexport function createGroupConfig(group: Group | undefined): Group | null {\n if (!group) {\n return null\n }\n\n const defaultName = (ctx: { group: string }): string => {\n if (group.type === 'path') {\n return `${ctx.group.split('/')[1]}`\n }\n\n return camelCase(ctx.group)\n }\n\n return {\n ...group,\n name: group.name ? group.name : defaultName,\n } satisfies Group\n}\n","import { camelCase, toFilePath } from '@internals/utils'\nimport { defineResolver } from '@kubb/core'\nimport type { PluginMsw } from '../types.ts'\n\n/**\n * Default resolver used by `@kubb/plugin-msw`. Decides the names and file\n * paths for every generated MSW handler. Function names get a `Handler`\n * suffix; the aggregate export is always `handlers`.\n *\n * @example Resolve a handler name\n * ```ts\n * import { resolverMsw } from '@kubb/plugin-msw'\n *\n * resolverMsw.resolveName('addPet') // 'addPetHandler'\n * ```\n */\nexport const resolverMsw = defineResolver<PluginMsw>(() => ({\n name: 'default',\n pluginName: 'plugin-msw',\n default(name, type) {\n return type === 'file' ? toFilePath(name) : camelCase(name)\n },\n resolveName(name) {\n return camelCase(name, { suffix: 'handler' })\n },\n resolvePathName(name, type) {\n return this.default(name, type)\n },\n resolveHandlerName(node) {\n return this.resolveName(node.operationId)\n },\n resolveHandlersName() {\n return 'handlers'\n },\n}))\n","import { createGroupConfig } from '@internals/shared'\nimport { definePlugin } from '@kubb/core'\nimport { pluginFakerName } from '@kubb/plugin-faker'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { handlersGenerator, mswGenerator } from './generators'\nimport { resolverMsw } from './resolvers/resolverMsw.ts'\nimport type { PluginMsw } from './types.ts'\n\n/**\n * Canonical plugin name for `@kubb/plugin-msw`. Used for driver lookups and\n * cross-plugin dependency references.\n */\nexport const pluginMswName = 'plugin-msw' satisfies PluginMsw['name']\n\n/**\n * Generates MSW request handlers from an OpenAPI spec. Drop them into your\n * test setup or service worker to mock the API end-to-end. Request path,\n * method, status, and response body all stay in sync with the spec. Combine\n * with `@kubb/plugin-faker` (via `parser: 'faker'`) to seed handlers with\n * realistic data.\n *\n * @example\n * ```ts\n * import { defineConfig } from 'kubb'\n * import { pluginTs } from '@kubb/plugin-ts'\n * import { pluginMsw } from '@kubb/plugin-msw'\n *\n * export default defineConfig({\n * input: { path: './petStore.yaml' },\n * output: { path: './src/gen' },\n * plugins: [\n * pluginTs(),\n * pluginMsw({\n * output: { path: './handlers' },\n * handlers: true,\n * }),\n * ],\n * })\n * ```\n */\nexport const pluginMsw = definePlugin<PluginMsw>((options) => {\n const {\n output = { path: 'handlers', barrel: { type: 'named' } },\n group,\n exclude = [],\n include,\n override = [],\n handlers = false,\n parser = 'data',\n baseURL,\n resolver: userResolver,\n transformer: userTransformer,\n generators: userGenerators = [],\n } = options\n\n const groupConfig = createGroupConfig(group)\n\n return {\n name: pluginMswName,\n options,\n dependencies: [pluginTsName, parser === 'faker' ? pluginFakerName : null].filter((dependency): dependency is string => Boolean(dependency)),\n hooks: {\n 'kubb:plugin:setup'(ctx) {\n const resolver = userResolver ? { ...resolverMsw, ...userResolver } : resolverMsw\n\n ctx.setOptions({\n output,\n parser,\n baseURL,\n group: groupConfig,\n exclude,\n include,\n override,\n handlers,\n resolver,\n })\n ctx.setResolver(resolver)\n if (userTransformer) {\n ctx.setTransformer(userTransformer)\n }\n\n ctx.addGenerator(mswGenerator)\n if (handlers) {\n ctx.addGenerator(handlersGenerator)\n }\n for (const gen of userGenerators) {\n ctx.addGenerator(gen)\n }\n },\n },\n }\n})\n\nexport default pluginMsw\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA+CA,SAAgB,WAAW,MAAc,WAAqC,WAAmB;CAC/F,MAAM,QAAQ,KAAK,MAAM,gBAAgB;CACzC,OAAO,MACJ,KAAK,MAAM,MAAO,MAAM,MAAM,SAAS,IAAI,SAAS,IAAI,IAAI,UAAU,IAAI,CAAE,CAAC,CAC7E,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;AACb;;;;;;;;;;;;;;;;;;;;;AChCA,SAAgB,kBAAkB,OAAwC;CACxE,IAAI,CAAC,OACH,OAAO;CAGT,MAAM,eAAe,QAAmC;EACtD,IAAI,MAAM,SAAS,QACjB,OAAO,GAAG,IAAI,MAAM,MAAM,GAAG,CAAC,CAAC;EAGjC,OAAO,UAAU,IAAI,KAAK;CAC5B;CAEA,OAAO;EACL,GAAG;EACH,MAAM,MAAM,OAAO,MAAM,OAAO;CAClC;AACF;;;;;;;;;;;;;;;ACtBA,MAAa,cAAc,sBAAiC;CAC1D,MAAM;CACN,YAAY;CACZ,QAAQ,MAAM,MAAM;EAClB,OAAO,SAAS,SAAS,WAAW,IAAI,IAAI,UAAU,IAAI;CAC5D;CACA,YAAY,MAAM;EAChB,OAAO,UAAU,MAAM,EAAE,QAAQ,UAAU,CAAC;CAC9C;CACA,gBAAgB,MAAM,MAAM;EAC1B,OAAO,KAAK,QAAQ,MAAM,IAAI;CAChC;CACA,mBAAmB,MAAM;EACvB,OAAO,KAAK,YAAY,KAAK,WAAW;CAC1C;CACA,sBAAsB;EACpB,OAAO;CACT;AACF,EAAE;;;;;;;ACtBF,MAAa,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4B7B,MAAa,YAAY,cAAyB,YAAY;CAC5D,MAAM,EACJ,SAAS;EAAE,MAAM;EAAY,QAAQ,EAAE,MAAM,QAAQ;CAAE,GACvD,OACA,UAAU,CAAC,GACX,SACA,WAAW,CAAC,GACZ,WAAW,OACX,SAAS,QACT,SACA,UAAU,cACV,aAAa,iBACb,YAAY,iBAAiB,CAAC,MAC5B;CAEJ,MAAM,cAAc,kBAAkB,KAAK;CAE3C,OAAO;EACL,MAAM;EACN;EACA,cAAc,CAAC,cAAc,WAAW,UAAU,kBAAkB,IAAI,CAAC,CAAC,QAAQ,eAAqC,QAAQ,UAAU,CAAC;EAC1I,OAAO,EACL,oBAAoB,KAAK;GACvB,MAAM,WAAW,eAAe;IAAE,GAAG;IAAa,GAAG;GAAa,IAAI;GAEtE,IAAI,WAAW;IACb;IACA;IACA;IACA,OAAO;IACP;IACA;IACA;IACA;IACA;GACF,CAAC;GACD,IAAI,YAAY,QAAQ;GACxB,IAAI,iBACF,IAAI,eAAe,eAAe;GAGpC,IAAI,aAAa,YAAY;GAC7B,IAAI,UACF,IAAI,aAAa,iBAAiB;GAEpC,KAAK,MAAM,OAAO,gBAChB,IAAI,aAAa,GAAG;EAExB,EACF;CACF;AACF,CAAC"}
@@ -0,0 +1,99 @@
1
+ import { t as __name } from "./chunk-C0LytTxp.js";
2
+ import { Exclude, Generator, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver, ast } from "@kubb/core";
3
+
4
+ //#region src/types.d.ts
5
+ /**
6
+ * Resolver for MSW that provides naming methods for handler functions.
7
+ */
8
+ type ResolverMsw = Resolver & {
9
+ /**
10
+ * Resolves the base handler function name for an operation.
11
+ */
12
+ resolveName(this: ResolverMsw, name: string): string;
13
+ /**
14
+ * Resolves the output file name for an MSW handler module.
15
+ */
16
+ resolvePathName(this: ResolverMsw, name: string, type?: 'file' | 'function' | 'type' | 'const'): string;
17
+ /**
18
+ * Resolves the handler function name for an operation.
19
+ */
20
+ resolveHandlerName(this: ResolverMsw, node: ast.OperationNode): string;
21
+ /**
22
+ * Resolves the exported handlers collection name.
23
+ */
24
+ resolveHandlersName(this: ResolverMsw): string;
25
+ };
26
+ /**
27
+ * Where the generated MSW handlers are written and how they are exported, plus the optional
28
+ * `group` strategy. The `group` option organizes `output.mode: 'directory'` output into per-tag or per-path subdirectories.
29
+ *
30
+ * @default { path: 'handlers', barrel: { type: 'named' } }
31
+ */
32
+ type Options = OutputOptions & {
33
+ /**
34
+ * Base URL prepended to every handler's request URL. When omitted, falls back
35
+ * to the adapter's server URL (typically `servers[0].url`).
36
+ */
37
+ baseURL?: string;
38
+ /**
39
+ * Skip operations matching at least one entry in the list.
40
+ */
41
+ exclude?: Array<Exclude>;
42
+ /**
43
+ * Restrict generation to operations matching at least one entry in the list.
44
+ */
45
+ include?: Array<Include>;
46
+ /**
47
+ * Apply a different options object to operations matching a pattern.
48
+ */
49
+ override?: Array<Override<ResolvedOptions>>;
50
+ /**
51
+ * Override how handler names and file paths are built.
52
+ */
53
+ resolver?: Partial<ResolverMsw> & ThisType<ResolverMsw>;
54
+ /**
55
+ * AST visitor applied to operation nodes before printing.
56
+ */
57
+ transformer?: ast.Visitor;
58
+ /**
59
+ * Emit a `handlers.ts` file that re-exports every handler grouped by HTTP method.
60
+ * Drop the file into `setupServer(...handlers)` or `setupWorker(...handlers)`.
61
+ *
62
+ * @default false
63
+ */
64
+ handlers?: boolean;
65
+ /**
66
+ * Source of the response body returned by each generated handler.
67
+ * - `'data'` — typed empty/example payload, ready for you to fill in from tests.
68
+ * - `'faker'` — value produced by `@kubb/plugin-faker`.
69
+ *
70
+ * @default 'data'
71
+ */
72
+ parser?: 'data' | 'faker';
73
+ /**
74
+ * Custom generators that run alongside the built-in MSW generators.
75
+ */
76
+ generators?: Array<Generator<PluginMsw>>;
77
+ };
78
+ type ResolvedOptions = {
79
+ output: Output;
80
+ group: Group | null;
81
+ exclude: NonNullable<Options['exclude']>;
82
+ include: Options['include'];
83
+ override: NonNullable<Options['override']>;
84
+ parser: NonNullable<Options['parser']>;
85
+ baseURL: Options['baseURL'] | undefined;
86
+ handlers: boolean;
87
+ resolver: ResolverMsw;
88
+ };
89
+ type PluginMsw = PluginFactoryOptions<'plugin-msw', Options, ResolvedOptions, ResolverMsw>;
90
+ declare global {
91
+ namespace Kubb {
92
+ interface PluginRegistry {
93
+ 'plugin-msw': PluginMsw;
94
+ }
95
+ }
96
+ }
97
+ //#endregion
98
+ export { PluginMsw as n, Options as t };
99
+ //# sourceMappingURL=types-B1yTWOfj.d.ts.map
package/package.json CHANGED
@@ -1,23 +1,19 @@
1
1
  {
2
2
  "name": "@kubb/plugin-msw",
3
- "version": "5.0.0-beta.4",
4
- "description": "Mock Service Worker (MSW) handlers generator plugin for Kubb, creating API mocks from OpenAPI specifications for frontend development and testing.",
3
+ "version": "5.0.0-beta.56",
4
+ "description": "Generate Mock Service Worker (MSW) request handlers from your OpenAPI specification. Intercept HTTP requests in the browser or Node.js for seamless frontend development and testing.",
5
5
  "keywords": [
6
6
  "api-mocking",
7
- "code-generator",
7
+ "code-generation",
8
8
  "codegen",
9
- "development",
10
- "interceptor",
11
9
  "kubb",
12
10
  "mock-service-worker",
13
11
  "mocking",
14
12
  "mocks",
15
13
  "msw",
16
- "oas",
17
14
  "openapi",
18
- "plugins",
15
+ "service-worker",
19
16
  "swagger",
20
- "testing",
21
17
  "typescript"
22
18
  ],
23
19
  "license": "MIT",
@@ -30,7 +26,6 @@
30
26
  "files": [
31
27
  "src",
32
28
  "dist",
33
- "extension.yaml",
34
29
  "!/**/**.test.**",
35
30
  "!/**/__tests__/**",
36
31
  "!/**/__snapshots__/**"
@@ -76,34 +71,29 @@
76
71
  "registry": "https://registry.npmjs.org/"
77
72
  },
78
73
  "dependencies": {
79
- "@kubb/core": "5.0.0-beta.4",
80
- "@kubb/renderer-jsx": "5.0.0-beta.4",
81
- "@kubb/plugin-faker": "5.0.0-beta.4",
82
- "@kubb/plugin-ts": "5.0.0-beta.4"
74
+ "@kubb/core": "5.0.0-beta.55",
75
+ "@kubb/renderer-jsx": "5.0.0-beta.55",
76
+ "@kubb/plugin-faker": "5.0.0-beta.56",
77
+ "@kubb/plugin-ts": "5.0.0-beta.56"
83
78
  },
84
79
  "devDependencies": {
80
+ "@internals/shared": "0.0.0",
85
81
  "@internals/utils": "0.0.0"
86
82
  },
87
83
  "peerDependencies": {
88
- "@kubb/renderer-jsx": "5.0.0-beta.4"
84
+ "@kubb/renderer-jsx": "5.0.0-beta.55"
89
85
  },
90
- "size-limit": [
91
- {
92
- "path": "./dist/*.js",
93
- "limit": "510 KiB",
94
- "gzip": true
95
- }
96
- ],
97
86
  "engines": {
98
87
  "node": ">=22"
99
88
  },
100
89
  "scripts": {
101
- "build": "tsdown && size-limit",
102
- "clean": "npx rimraf ./dist",
90
+ "build": "tsdown",
91
+ "clean": "node -e \"require('node:fs').rmSync('./dist', {recursive:true,force:true})\"",
103
92
  "lint": "oxlint .",
104
93
  "lint:fix": "oxlint --fix .",
105
94
  "release": "pnpm publish --no-git-check",
106
95
  "release:canary": "bash ../../.github/canary.sh && node ../../scripts/build.js canary && pnpm publish --no-git-check",
96
+ "release:stage": "pnpm stage publish --no-git-check",
107
97
  "start": "tsdown --watch",
108
98
  "test": "vitest --passWithNoTests",
109
99
  "typecheck": "tsc -p ./tsconfig.json --noEmit --emitDeclarationOnly false"
@@ -1,15 +1,16 @@
1
- import { URLPath } from '@internals/utils'
1
+ import { getPrimarySuccessResponse } from '@internals/shared'
2
+ import { Url } from '@internals/utils'
2
3
  import { ast } from '@kubb/core'
3
4
  import { functionPrinter } from '@kubb/plugin-ts'
4
5
  import { File, Function } from '@kubb/renderer-jsx'
5
6
  import type { KubbReactNode } from '@kubb/renderer-jsx/types'
6
- import { getContentType, getMswMethod, getMswUrl, getPrimarySuccessResponse, hasResponseSchema } from '../utils.ts'
7
+ import { getContentType, getMswMethod, getMswUrl, hasResponseSchema } from '../utils.ts'
7
8
 
8
9
  type Props = {
9
10
  name: string
10
11
  typeName: string
11
- requestTypeName?: string
12
- baseURL: string | undefined
12
+ requestTypeName?: string | null
13
+ baseURL: string | null | undefined
13
14
  node: ast.OperationNode
14
15
  }
15
16
 
@@ -20,9 +21,9 @@ export function Mock({ baseURL = '', name, typeName, requestTypeName, node }: Pr
20
21
  const successResponse = getPrimarySuccessResponse(node)
21
22
  const statusCode = successResponse ? Number(successResponse.statusCode) : 200
22
23
  const contentType = getContentType(successResponse)
23
- const url = new URLPath(getMswUrl(node)).toURLPath()
24
+ const url = Url.toPath(getMswUrl(node))
24
25
 
25
- const headers = [contentType ? `'Content-Type': '${contentType}'` : undefined].filter(Boolean)
26
+ const headers = [contentType ? `'Content-Type': '${contentType}'` : null].filter(Boolean)
26
27
  const responseHasSchema = hasResponseSchema(successResponse)
27
28
  const dataType = responseHasSchema ? typeName : 'string | number | boolean | null | object'
28
29
 
@@ -1,16 +1,17 @@
1
- import { URLPath } from '@internals/utils'
1
+ import { getPrimarySuccessResponse } from '@internals/shared'
2
+ import { Url } from '@internals/utils'
2
3
  import { ast } from '@kubb/core'
3
4
  import { functionPrinter } from '@kubb/plugin-ts'
4
5
  import { File, Function } from '@kubb/renderer-jsx'
5
6
  import type { KubbReactNode } from '@kubb/renderer-jsx/types'
6
- import { getContentType, getMswMethod, getMswUrl, getPrimarySuccessResponse } from '../utils.ts'
7
+ import { getContentType, getMswMethod, getMswUrl } from '../utils.ts'
7
8
 
8
9
  type Props = {
9
10
  name: string
10
11
  typeName: string
11
- requestTypeName?: string
12
+ requestTypeName?: string | null
12
13
  fakerName: string
13
- baseURL: string | undefined
14
+ baseURL: string | null | undefined
14
15
  node: ast.OperationNode
15
16
  }
16
17
 
@@ -21,9 +22,9 @@ export function MockWithFaker({ baseURL = '', name, fakerName, typeName, request
21
22
  const successResponse = getPrimarySuccessResponse(node)
22
23
  const statusCode = successResponse ? Number(successResponse.statusCode) : 200
23
24
  const contentType = getContentType(successResponse)
24
- const url = new URLPath(getMswUrl(node)).toURLPath()
25
+ const url = Url.toPath(getMswUrl(node))
25
26
 
26
- const headers = [contentType ? `'Content-Type': '${contentType}'` : undefined].filter(Boolean)
27
+ const headers = [contentType ? `'Content-Type': '${contentType}'` : null].filter(Boolean)
27
28
 
28
29
  const callbackType = requestTypeName
29
30
  ? `HttpResponseResolver<Record<string, string>, ${requestTypeName}, any>`
@@ -16,7 +16,7 @@ const declarationPrinter = functionPrinter({ mode: 'declaration' })
16
16
  export function Response({ name, typeName, response }: Props): KubbReactNode {
17
17
  const statusCode = Number(response.statusCode)
18
18
  const contentType = getContentType(response)
19
- const headers = [contentType ? `'Content-Type': '${contentType}'` : undefined].filter(Boolean)
19
+ const headers = [contentType ? `'Content-Type': '${contentType}'` : null].filter(Boolean)
20
20
 
21
21
  const params = declarationPrinter.print(
22
22
  ast.createFunctionParameters({
@@ -1,4 +1,3 @@
1
- export { Handlers } from './Handlers.tsx'
2
1
  export { Mock } from './Mock.tsx'
3
2
  export { MockWithFaker } from './MockWithFaker.tsx'
4
3
  export { Response } from './Response.tsx'
@@ -0,0 +1,49 @@
1
+ import { ast, defineGenerator } from '@kubb/core'
2
+ import type { PluginMsw } from '../types'
3
+
4
+ /**
5
+ * Aggregate generator enabled by `pluginMsw({ handlers: true })`. Emits a
6
+ * `handlers.ts` file that re-exports every generated handler grouped by HTTP
7
+ * method, ready to spread into `setupServer(...handlers)` or
8
+ * `setupWorker(...handlers)`.
9
+ */
10
+ export const handlersGenerator = defineGenerator<PluginMsw>({
11
+ name: 'plugin-msw',
12
+ operations(nodes, ctx) {
13
+ const { resolver, config, root } = ctx
14
+ const { output, group } = ctx.options
15
+
16
+ const handlersName = resolver.resolveHandlersName()
17
+ const file = resolver.resolveFile({ name: resolver.resolvePathName(handlersName, 'file'), extname: '.ts' }, { root, output, group: group ?? undefined })
18
+
19
+ const imports = nodes.map((node) => {
20
+ const operationName = resolver.resolveHandlerName(node)
21
+ const operationFile = resolver.resolveFile(
22
+ { name: resolver.resolveName(node.operationId), extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
23
+ { root, output, group: group ?? undefined },
24
+ )
25
+ return ast.createImport({ name: [operationName], root: file.path, path: operationFile.path })
26
+ })
27
+
28
+ const handlers = nodes.map((node) => `${resolver.resolveHandlerName(node)}()`)
29
+
30
+ return [
31
+ ast.createFile({
32
+ baseName: file.baseName,
33
+ path: file.path,
34
+ meta: file.meta,
35
+ banner: resolver.resolveBanner(ctx.meta, { output, config, file: { path: file.path, baseName: file.baseName } }),
36
+ footer: resolver.resolveFooter(ctx.meta, { output, config, file: { path: file.path, baseName: file.baseName } }),
37
+ imports,
38
+ sources: [
39
+ ast.createSource({
40
+ name: handlersName,
41
+ isIndexable: true,
42
+ isExportable: true,
43
+ nodes: [ast.createText(`export const ${handlersName} = ${JSON.stringify(handlers).replaceAll('"', '')} as const`)],
44
+ }),
45
+ ],
46
+ }),
47
+ ]
48
+ },
49
+ })
@@ -1,2 +1,2 @@
1
- export { handlersGenerator } from './handlersGenerator.tsx'
1
+ export { handlersGenerator } from './handlersGenerator.ts'
2
2
  export { mswGenerator } from './mswGenerator.tsx'