@kubb/plugin-msw 5.0.0-beta.42 → 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 (36) hide show
  1. package/dist/{components--3aER8iM.js → components-Bi7cN-ws.js} +63 -152
  2. package/dist/components-Bi7cN-ws.js.map +1 -0
  3. package/dist/{components-BW5VCVSO.cjs → components-Bp69JYOt.cjs} +62 -157
  4. package/dist/components-Bp69JYOt.cjs.map +1 -0
  5. package/dist/components.cjs +1 -2
  6. package/dist/components.d.ts +1 -14
  7. package/dist/components.js +2 -2
  8. package/dist/{generators-CLKAZMic.js → generators-BnEvTy3q.js} +14 -12
  9. package/dist/generators-BnEvTy3q.js.map +1 -0
  10. package/dist/{generators-B6qnyBTW.cjs → generators-d22_s2UN.cjs} +13 -11
  11. package/dist/generators-d22_s2UN.cjs.map +1 -0
  12. package/dist/generators.cjs +1 -1
  13. package/dist/generators.d.ts +1 -1
  14. package/dist/generators.js +1 -1
  15. package/dist/index.cjs +34 -11
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.js +34 -11
  19. package/dist/index.js.map +1 -1
  20. package/dist/{types-CwhQTrui.d.ts → types-B1yTWOfj.d.ts} +9 -13
  21. package/package.json +8 -16
  22. package/src/components/Mock.tsx +2 -2
  23. package/src/components/MockWithFaker.tsx +2 -2
  24. package/src/components/index.ts +0 -1
  25. package/src/generators/{handlersGenerator.tsx → handlersGenerator.ts} +20 -18
  26. package/src/generators/index.ts +1 -1
  27. package/src/generators/mswGenerator.tsx +2 -2
  28. package/src/plugin.ts +2 -2
  29. package/src/resolvers/resolverMsw.ts +2 -2
  30. package/src/types.ts +8 -12
  31. package/dist/components--3aER8iM.js.map +0 -1
  32. package/dist/components-BW5VCVSO.cjs.map +0 -1
  33. package/dist/generators-B6qnyBTW.cjs.map +0 -1
  34. package/dist/generators-CLKAZMic.js.map +0 -1
  35. package/extension.yaml +0 -752
  36. package/src/components/Handlers.tsx +0 -19
@@ -1,4 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_generators = require("./generators-B6qnyBTW.cjs");
2
+ const require_generators = require("./generators-d22_s2UN.cjs");
3
3
  exports.handlersGenerator = require_generators.handlersGenerator;
4
4
  exports.mswGenerator = require_generators.mswGenerator;
@@ -1,5 +1,5 @@
1
1
  import { t as __name } from "./chunk-C0LytTxp.js";
2
- import { n as PluginMsw } from "./types-CwhQTrui.js";
2
+ import { n as PluginMsw } from "./types-B1yTWOfj.js";
3
3
 
4
4
  //#region src/generators/handlersGenerator.d.ts
5
5
  /**
@@ -1,2 +1,2 @@
1
- import { n as handlersGenerator, t as mswGenerator } from "./generators-CLKAZMic.js";
1
+ import { n as handlersGenerator, t as mswGenerator } from "./generators-BnEvTy3q.js";
2
2
  export { handlersGenerator, mswGenerator };
package/dist/index.cjs CHANGED
@@ -2,37 +2,60 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_components = require("./components-BW5VCVSO.cjs");
6
- const require_generators = require("./generators-B6qnyBTW.cjs");
5
+ const require_components = require("./components-Bp69JYOt.cjs");
6
+ const require_generators = require("./generators-d22_s2UN.cjs");
7
7
  let _kubb_core = require("@kubb/core");
8
8
  let _kubb_plugin_faker = require("@kubb/plugin-faker");
9
9
  let _kubb_plugin_ts = require("@kubb/plugin-ts");
10
+ //#region ../../internals/utils/src/fs.ts
11
+ /**
12
+ * Builds a nested file path from a dotted name. Splits on dots that precede a letter
13
+ * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
14
+ * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
15
+ *
16
+ * Empty segments are dropped before joining. They arise when the name starts with a dot
17
+ * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
18
+ * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
19
+ * absolute path, letting generated files escape the configured output directory.
20
+ *
21
+ * @example Nested path from a dotted name
22
+ * `toFilePath('pet.petId') // 'pet/petId'`
23
+ *
24
+ * @example PascalCase the final segment
25
+ * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
26
+ *
27
+ * @example Suffix applied to the final segment only
28
+ * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
29
+ */
30
+ function toFilePath(name, caseLast = require_components.camelCase) {
31
+ const parts = name.split(/\.(?=[a-zA-Z])/);
32
+ return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : require_components.camelCase(part)).filter(Boolean).join("/");
33
+ }
34
+ //#endregion
10
35
  //#region ../../internals/shared/src/group.ts
11
36
  /**
12
37
  * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
13
38
  * shared default naming so every plugin groups output consistently:
14
39
  *
15
40
  * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
16
- * - other groups use `${camelCase(group)}${suffix}` (e.g. `petController`).
41
+ * - other groups use the camelCased group (`pet store``petStore`).
17
42
  *
18
43
  * A user-provided `group.name` always wins over the default namer, so callers stay in
19
44
  * control of their output folders. Returns `null` when grouping is disabled, matching the
20
45
  * per-plugin convention.
21
46
  *
22
47
  * @param group - The user-supplied group option, or `undefined` to disable grouping.
23
- * @param options.suffix - Appended to non-`path` group names, e.g. `'Controller'` or `'Requests'`.
24
48
  *
25
49
  * @example
26
50
  * ```ts
27
- * createGroupConfig(group, { suffix: 'Controller' }) // plugin-ts, plugin-client, …
28
- * createGroupConfig(group, { suffix: 'Requests' }) // plugin-cypress, plugin-mcp
51
+ * createGroupConfig(group) // shared across every plugin
29
52
  * ```
30
53
  */
31
- function createGroupConfig(group, options) {
54
+ function createGroupConfig(group) {
32
55
  if (!group) return null;
33
56
  const defaultName = (ctx) => {
34
57
  if (group.type === "path") return `${ctx.group.split("/")[1]}`;
35
- return `${require_components.camelCase(ctx.group)}${options.suffix}`;
58
+ return require_components.camelCase(ctx.group);
36
59
  };
37
60
  return {
38
61
  ...group,
@@ -57,7 +80,7 @@ const resolverMsw = (0, _kubb_core.defineResolver)(() => ({
57
80
  name: "default",
58
81
  pluginName: "plugin-msw",
59
82
  default(name, type) {
60
- return require_components.camelCase(name, { isFile: type === "file" });
83
+ return type === "file" ? toFilePath(name) : require_components.camelCase(name);
61
84
  },
62
85
  resolveName(name) {
63
86
  return require_components.camelCase(name, { suffix: "handler" });
@@ -108,9 +131,9 @@ const pluginMswName = "plugin-msw";
108
131
  const pluginMsw = (0, _kubb_core.definePlugin)((options) => {
109
132
  const { output = {
110
133
  path: "handlers",
111
- barrelType: "named"
134
+ barrel: { type: "named" }
112
135
  }, group, exclude = [], include, override = [], handlers = false, parser = "data", baseURL, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
113
- const groupConfig = createGroupConfig(group, { suffix: "Controller" });
136
+ const groupConfig = createGroupConfig(group);
114
137
  return {
115
138
  name: pluginMswName,
116
139
  options,
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["camelCase","camelCase","pluginTsName","pluginFakerName","mswGenerator","handlersGenerator"],"sources":["../../../internals/shared/src/group.ts","../src/resolvers/resolverMsw.ts","../src/plugin.ts"],"sourcesContent":["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 `${camelCase(group)}${suffix}` (e.g. `petController`).\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 * @param options.suffix - Appended to non-`path` group names, e.g. `'Controller'` or `'Requests'`.\n *\n * @example\n * ```ts\n * createGroupConfig(group, { suffix: 'Controller' }) // plugin-ts, plugin-client, …\n * createGroupConfig(group, { suffix: 'Requests' }) // plugin-cypress, plugin-mcp\n * ```\n */\nexport function createGroupConfig(group: Group | undefined, options: { suffix: string }): 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)}${options.suffix}`\n }\n\n return {\n ...group,\n name: group.name ? group.name : defaultName,\n } satisfies Group\n}\n","import { camelCase } 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 camelCase(name, { isFile: type === 'file' })\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', barrelType: '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, { suffix: 'Controller' })\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,kBAAkB,OAA0B,SAA2C;CACrG,IAAI,CAAC,OACH,OAAO;CAGT,MAAM,eAAe,QAAmC;EACtD,IAAI,MAAM,SAAS,QACjB,OAAO,GAAG,IAAI,MAAM,MAAM,GAAG,EAAE;EAGjC,OAAO,GAAGA,mBAAAA,UAAU,IAAI,KAAK,IAAI,QAAQ;CAC3C;CAEA,OAAO;EACL,GAAG;EACH,MAAM,MAAM,OAAO,MAAM,OAAO;CAClC;AACF;;;;;;;;;;;;;;;ACxBA,MAAa,eAAA,GAAA,WAAA,uBAA+C;CAC1D,MAAM;CACN,YAAY;CACZ,QAAQ,MAAM,MAAM;EAClB,OAAOC,mBAAAA,UAAU,MAAM,EAAE,QAAQ,SAAS,OAAO,CAAC;CACpD;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,eAAqC,YAAY;CAC5D,MAAM,EACJ,SAAS;EAAE,MAAM;EAAY,YAAY;CAAQ,GACjD,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,OAAO,EAAE,QAAQ,aAAa,CAAC;CAErE,OAAO;EACL,MAAM;EACN;EACA,cAAc,CAACC,gBAAAA,cAAc,WAAW,UAAUC,mBAAAA,kBAAkB,IAAI,EAAE,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"}
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,5 +1,5 @@
1
1
  import { t as __name } from "./chunk-C0LytTxp.js";
2
- import { n as PluginMsw, t as Options } from "./types-CwhQTrui.js";
2
+ import { n as PluginMsw, t as Options } from "./types-B1yTWOfj.js";
3
3
 
4
4
  //#region src/plugin.d.ts
5
5
  /**
package/dist/index.js CHANGED
@@ -1,35 +1,58 @@
1
1
  import "./chunk-C0LytTxp.js";
2
- import { c as camelCase } from "./components--3aER8iM.js";
3
- import { n as handlersGenerator, t as mswGenerator } from "./generators-CLKAZMic.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
7
32
  //#region ../../internals/shared/src/group.ts
8
33
  /**
9
34
  * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
10
35
  * shared default naming so every plugin groups output consistently:
11
36
  *
12
37
  * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
13
- * - other groups use `${camelCase(group)}${suffix}` (e.g. `petController`).
38
+ * - other groups use the camelCased group (`pet store``petStore`).
14
39
  *
15
40
  * A user-provided `group.name` always wins over the default namer, so callers stay in
16
41
  * control of their output folders. Returns `null` when grouping is disabled, matching the
17
42
  * per-plugin convention.
18
43
  *
19
44
  * @param group - The user-supplied group option, or `undefined` to disable grouping.
20
- * @param options.suffix - Appended to non-`path` group names, e.g. `'Controller'` or `'Requests'`.
21
45
  *
22
46
  * @example
23
47
  * ```ts
24
- * createGroupConfig(group, { suffix: 'Controller' }) // plugin-ts, plugin-client, …
25
- * createGroupConfig(group, { suffix: 'Requests' }) // plugin-cypress, plugin-mcp
48
+ * createGroupConfig(group) // shared across every plugin
26
49
  * ```
27
50
  */
28
- function createGroupConfig(group, options) {
51
+ function createGroupConfig(group) {
29
52
  if (!group) return null;
30
53
  const defaultName = (ctx) => {
31
54
  if (group.type === "path") return `${ctx.group.split("/")[1]}`;
32
- return `${camelCase(ctx.group)}${options.suffix}`;
55
+ return camelCase(ctx.group);
33
56
  };
34
57
  return {
35
58
  ...group,
@@ -54,7 +77,7 @@ const resolverMsw = defineResolver(() => ({
54
77
  name: "default",
55
78
  pluginName: "plugin-msw",
56
79
  default(name, type) {
57
- return camelCase(name, { isFile: type === "file" });
80
+ return type === "file" ? toFilePath(name) : camelCase(name);
58
81
  },
59
82
  resolveName(name) {
60
83
  return camelCase(name, { suffix: "handler" });
@@ -105,9 +128,9 @@ const pluginMswName = "plugin-msw";
105
128
  const pluginMsw = definePlugin((options) => {
106
129
  const { output = {
107
130
  path: "handlers",
108
- barrelType: "named"
131
+ barrel: { type: "named" }
109
132
  }, group, exclude = [], include, override = [], handlers = false, parser = "data", baseURL, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
110
- const groupConfig = createGroupConfig(group, { suffix: "Controller" });
133
+ const groupConfig = createGroupConfig(group);
111
134
  return {
112
135
  name: pluginMswName,
113
136
  options,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../internals/shared/src/group.ts","../src/resolvers/resolverMsw.ts","../src/plugin.ts"],"sourcesContent":["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 `${camelCase(group)}${suffix}` (e.g. `petController`).\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 * @param options.suffix - Appended to non-`path` group names, e.g. `'Controller'` or `'Requests'`.\n *\n * @example\n * ```ts\n * createGroupConfig(group, { suffix: 'Controller' }) // plugin-ts, plugin-client, …\n * createGroupConfig(group, { suffix: 'Requests' }) // plugin-cypress, plugin-mcp\n * ```\n */\nexport function createGroupConfig(group: Group | undefined, options: { suffix: string }): 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)}${options.suffix}`\n }\n\n return {\n ...group,\n name: group.name ? group.name : defaultName,\n } satisfies Group\n}\n","import { camelCase } 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 camelCase(name, { isFile: type === 'file' })\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', barrelType: '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, { suffix: 'Controller' })\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,kBAAkB,OAA0B,SAA2C;CACrG,IAAI,CAAC,OACH,OAAO;CAGT,MAAM,eAAe,QAAmC;EACtD,IAAI,MAAM,SAAS,QACjB,OAAO,GAAG,IAAI,MAAM,MAAM,GAAG,EAAE;EAGjC,OAAO,GAAG,UAAU,IAAI,KAAK,IAAI,QAAQ;CAC3C;CAEA,OAAO;EACL,GAAG;EACH,MAAM,MAAM,OAAO,MAAM,OAAO;CAClC;AACF;;;;;;;;;;;;;;;ACxBA,MAAa,cAAc,sBAAiC;CAC1D,MAAM;CACN,YAAY;CACZ,QAAQ,MAAM,MAAM;EAClB,OAAO,UAAU,MAAM,EAAE,QAAQ,SAAS,OAAO,CAAC;CACpD;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,YAAY;CAAQ,GACjD,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,OAAO,EAAE,QAAQ,aAAa,CAAC;CAErE,OAAO;EACL,MAAM;EACN;EACA,cAAc,CAAC,cAAc,WAAW,UAAU,kBAAkB,IAAI,EAAE,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"}
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"}
@@ -1,5 +1,5 @@
1
1
  import { t as __name } from "./chunk-C0LytTxp.js";
2
- import { Exclude, Generator, Group, Include, Output, Override, PluginFactoryOptions, Resolver, ast } from "@kubb/core";
2
+ import { Exclude, Generator, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver, ast } from "@kubb/core";
3
3
 
4
4
  //#region src/types.d.ts
5
5
  /**
@@ -23,22 +23,18 @@ type ResolverMsw = Resolver & {
23
23
  */
24
24
  resolveHandlersName(this: ResolverMsw): string;
25
25
  };
26
- type Options = {
27
- /**
28
- * Where the generated MSW handlers are written and how they are exported.
29
- *
30
- * @default { path: 'handlers', barrel: { type: 'named' } }
31
- */
32
- output?: Output;
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
33
  /**
34
34
  * Base URL prepended to every handler's request URL. When omitted, falls back
35
35
  * to the adapter's server URL (typically `servers[0].url`).
36
36
  */
37
37
  baseURL?: string;
38
- /**
39
- * Split generated files into subfolders based on the operation's tag.
40
- */
41
- group?: Group;
42
38
  /**
43
39
  * Skip operations matching at least one entry in the list.
44
40
  */
@@ -100,4 +96,4 @@ declare global {
100
96
  }
101
97
  //#endregion
102
98
  export { PluginMsw as n, Options as t };
103
- //# sourceMappingURL=types-CwhQTrui.d.ts.map
99
+ //# sourceMappingURL=types-B1yTWOfj.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/plugin-msw",
3
- "version": "5.0.0-beta.42",
3
+ "version": "5.0.0-beta.56",
4
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",
@@ -26,7 +26,6 @@
26
26
  "files": [
27
27
  "src",
28
28
  "dist",
29
- "extension.yaml",
30
29
  "!/**/**.test.**",
31
30
  "!/**/__tests__/**",
32
31
  "!/**/__snapshots__/**"
@@ -72,31 +71,24 @@
72
71
  "registry": "https://registry.npmjs.org/"
73
72
  },
74
73
  "dependencies": {
75
- "@kubb/core": "5.0.0-beta.42",
76
- "@kubb/renderer-jsx": "5.0.0-beta.42",
77
- "@kubb/plugin-faker": "5.0.0-beta.42",
78
- "@kubb/plugin-ts": "5.0.0-beta.42"
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"
79
78
  },
80
79
  "devDependencies": {
81
80
  "@internals/shared": "0.0.0",
82
81
  "@internals/utils": "0.0.0"
83
82
  },
84
83
  "peerDependencies": {
85
- "@kubb/renderer-jsx": "5.0.0-beta.42"
84
+ "@kubb/renderer-jsx": "5.0.0-beta.55"
86
85
  },
87
- "size-limit": [
88
- {
89
- "path": "./dist/*.js",
90
- "limit": "510 KiB",
91
- "gzip": true
92
- }
93
- ],
94
86
  "engines": {
95
87
  "node": ">=22"
96
88
  },
97
89
  "scripts": {
98
- "build": "tsdown && size-limit",
99
- "clean": "npx rimraf ./dist",
90
+ "build": "tsdown",
91
+ "clean": "node -e \"require('node:fs').rmSync('./dist', {recursive:true,force:true})\"",
100
92
  "lint": "oxlint .",
101
93
  "lint:fix": "oxlint --fix .",
102
94
  "release": "pnpm publish --no-git-check",
@@ -1,5 +1,5 @@
1
1
  import { getPrimarySuccessResponse } from '@internals/shared'
2
- import { URLPath } from '@internals/utils'
2
+ import { Url } from '@internals/utils'
3
3
  import { ast } from '@kubb/core'
4
4
  import { functionPrinter } from '@kubb/plugin-ts'
5
5
  import { File, Function } from '@kubb/renderer-jsx'
@@ -21,7 +21,7 @@ export function Mock({ baseURL = '', name, typeName, requestTypeName, node }: Pr
21
21
  const successResponse = getPrimarySuccessResponse(node)
22
22
  const statusCode = successResponse ? Number(successResponse.statusCode) : 200
23
23
  const contentType = getContentType(successResponse)
24
- const url = new URLPath(getMswUrl(node)).toURLPath()
24
+ const url = Url.toPath(getMswUrl(node))
25
25
 
26
26
  const headers = [contentType ? `'Content-Type': '${contentType}'` : null].filter(Boolean)
27
27
  const responseHasSchema = hasResponseSchema(successResponse)
@@ -1,5 +1,5 @@
1
1
  import { getPrimarySuccessResponse } from '@internals/shared'
2
- import { URLPath } from '@internals/utils'
2
+ import { Url } from '@internals/utils'
3
3
  import { ast } from '@kubb/core'
4
4
  import { functionPrinter } from '@kubb/plugin-ts'
5
5
  import { File, Function } from '@kubb/renderer-jsx'
@@ -22,7 +22,7 @@ export function MockWithFaker({ baseURL = '', name, fakerName, typeName, request
22
22
  const successResponse = getPrimarySuccessResponse(node)
23
23
  const statusCode = successResponse ? Number(successResponse.statusCode) : 200
24
24
  const contentType = getContentType(successResponse)
25
- const url = new URLPath(getMswUrl(node)).toURLPath()
25
+ const url = Url.toPath(getMswUrl(node))
26
26
 
27
27
  const headers = [contentType ? `'Content-Type': '${contentType}'` : null].filter(Boolean)
28
28
 
@@ -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'
@@ -1,6 +1,4 @@
1
- import { defineGenerator } from '@kubb/core'
2
- import { File, jsxRendererSync } from '@kubb/renderer-jsx'
3
- import { Handlers } from '../components/Handlers.tsx'
1
+ import { ast, defineGenerator } from '@kubb/core'
4
2
  import type { PluginMsw } from '../types'
5
3
 
6
4
  /**
@@ -11,7 +9,6 @@ import type { PluginMsw } from '../types'
11
9
  */
12
10
  export const handlersGenerator = defineGenerator<PluginMsw>({
13
11
  name: 'plugin-msw',
14
- renderer: jsxRendererSync,
15
12
  operations(nodes, ctx) {
16
13
  const { resolver, config, root } = ctx
17
14
  const { output, group } = ctx.options
@@ -25,23 +22,28 @@ export const handlersGenerator = defineGenerator<PluginMsw>({
25
22
  { name: resolver.resolveName(node.operationId), extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
26
23
  { root, output, group: group ?? undefined },
27
24
  )
28
-
29
- return <File.Import key={operationFile.path} name={[operationName]} root={file.path} path={operationFile.path} />
25
+ return ast.createImport({ name: [operationName], root: file.path, path: operationFile.path })
30
26
  })
31
27
 
32
28
  const handlers = nodes.map((node) => `${resolver.resolveHandlerName(node)}()`)
33
29
 
34
- return (
35
- <File
36
- baseName={file.baseName}
37
- path={file.path}
38
- meta={file.meta}
39
- banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: file.path, baseName: file.baseName } })}
40
- footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: file.path, baseName: file.baseName } })}
41
- >
42
- {imports}
43
- <Handlers name={handlersName} handlers={handlers} />
44
- </File>
45
- )
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
+ ]
46
48
  },
47
49
  })
@@ -1,2 +1,2 @@
1
- export { handlersGenerator } from './handlersGenerator.tsx'
1
+ export { handlersGenerator } from './handlersGenerator.ts'
2
2
  export { mswGenerator } from './mswGenerator.tsx'
@@ -2,7 +2,7 @@ import { getOperationSuccessResponses, resolveResponseTypes } from '@internals/s
2
2
  import { ast, defineGenerator } from '@kubb/core'
3
3
  import { pluginFakerName } from '@kubb/plugin-faker'
4
4
  import { pluginTsName } from '@kubb/plugin-ts'
5
- import { File, jsxRendererSync } from '@kubb/renderer-jsx'
5
+ import { File, jsxRenderer } from '@kubb/renderer-jsx'
6
6
  import { Mock, MockWithFaker, Response } from '../components'
7
7
  import type { PluginMsw } from '../types'
8
8
  import { resolveFakerMeta } from '../utils.ts'
@@ -15,7 +15,7 @@ import { resolveFakerMeta } from '../utils.ts'
15
15
  */
16
16
  export const mswGenerator = defineGenerator<PluginMsw>({
17
17
  name: 'msw',
18
- renderer: jsxRendererSync,
18
+ renderer: jsxRenderer,
19
19
  operation(node, ctx) {
20
20
  if (!ast.isHttpOperationNode(node)) return null
21
21
  const { driver, resolver, config, root } = ctx
package/src/plugin.ts CHANGED
@@ -40,7 +40,7 @@ export const pluginMswName = 'plugin-msw' satisfies PluginMsw['name']
40
40
  */
41
41
  export const pluginMsw = definePlugin<PluginMsw>((options) => {
42
42
  const {
43
- output = { path: 'handlers', barrelType: 'named' },
43
+ output = { path: 'handlers', barrel: { type: 'named' } },
44
44
  group,
45
45
  exclude = [],
46
46
  include,
@@ -53,7 +53,7 @@ export const pluginMsw = definePlugin<PluginMsw>((options) => {
53
53
  generators: userGenerators = [],
54
54
  } = options
55
55
 
56
- const groupConfig = createGroupConfig(group, { suffix: 'Controller' })
56
+ const groupConfig = createGroupConfig(group)
57
57
 
58
58
  return {
59
59
  name: pluginMswName,
@@ -1,4 +1,4 @@
1
- import { camelCase } from '@internals/utils'
1
+ import { camelCase, toFilePath } from '@internals/utils'
2
2
  import { defineResolver } from '@kubb/core'
3
3
  import type { PluginMsw } from '../types.ts'
4
4
 
@@ -18,7 +18,7 @@ export const resolverMsw = defineResolver<PluginMsw>(() => ({
18
18
  name: 'default',
19
19
  pluginName: 'plugin-msw',
20
20
  default(name, type) {
21
- return camelCase(name, { isFile: type === 'file' })
21
+ return type === 'file' ? toFilePath(name) : camelCase(name)
22
22
  },
23
23
  resolveName(name) {
24
24
  return camelCase(name, { suffix: 'handler' })
package/src/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ast, Exclude, Generator, Group, Include, Output, Override, PluginFactoryOptions, Resolver } from '@kubb/core'
1
+ import type { ast, Exclude, Generator, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver } from '@kubb/core'
2
2
 
3
3
  /**
4
4
  * Resolver for MSW that provides naming methods for handler functions.
@@ -22,22 +22,18 @@ export type ResolverMsw = Resolver & {
22
22
  resolveHandlersName(this: ResolverMsw): string
23
23
  }
24
24
 
25
- export type Options = {
26
- /**
27
- * Where the generated MSW handlers are written and how they are exported.
28
- *
29
- * @default { path: 'handlers', barrel: { type: 'named' } }
30
- */
31
- output?: Output
25
+ /**
26
+ * Where the generated MSW handlers are written and how they are exported, plus the optional
27
+ * `group` strategy. The `group` option organizes `output.mode: 'directory'` output into per-tag or per-path subdirectories.
28
+ *
29
+ * @default { path: 'handlers', barrel: { type: 'named' } }
30
+ */
31
+ export type Options = OutputOptions & {
32
32
  /**
33
33
  * Base URL prepended to every handler's request URL. When omitted, falls back
34
34
  * to the adapter's server URL (typically `servers[0].url`).
35
35
  */
36
36
  baseURL?: string
37
- /**
38
- * Split generated files into subfolders based on the operation's tag.
39
- */
40
- group?: Group
41
37
  /**
42
38
  * Skip operations matching at least one entry in the list.
43
39
  */