@kubb/plugin-msw 5.0.0-alpha.9 → 5.0.0-beta.10

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 (44) hide show
  1. package/LICENSE +17 -10
  2. package/README.md +26 -7
  3. package/dist/components-BYvgvrY7.cjs +569 -0
  4. package/dist/components-BYvgvrY7.cjs.map +1 -0
  5. package/dist/components-Cm17DMTE.js +510 -0
  6. package/dist/components-Cm17DMTE.js.map +1 -0
  7. package/dist/components.cjs +1 -1
  8. package/dist/components.d.ts +17 -21
  9. package/dist/components.js +1 -1
  10. package/dist/generators-D9gvdP7Z.js +177 -0
  11. package/dist/generators-D9gvdP7Z.js.map +1 -0
  12. package/dist/generators-rZ99WaWQ.cjs +187 -0
  13. package/dist/generators-rZ99WaWQ.cjs.map +1 -0
  14. package/dist/generators.cjs +1 -1
  15. package/dist/generators.d.ts +4 -500
  16. package/dist/generators.js +1 -1
  17. package/dist/index.cjs +62 -65
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.ts +4 -4
  20. package/dist/index.js +59 -65
  21. package/dist/index.js.map +1 -1
  22. package/dist/types-ItsHsMvC.d.ts +94 -0
  23. package/extension.yaml +233 -0
  24. package/package.json +57 -58
  25. package/src/components/Handlers.tsx +3 -3
  26. package/src/components/Mock.tsx +37 -28
  27. package/src/components/MockWithFaker.tsx +37 -24
  28. package/src/components/Response.tsx +23 -17
  29. package/src/generators/handlersGenerator.tsx +19 -19
  30. package/src/generators/mswGenerator.tsx +50 -60
  31. package/src/index.ts +1 -1
  32. package/src/plugin.ts +47 -86
  33. package/src/resolvers/resolverMsw.ts +28 -0
  34. package/src/types.ts +55 -27
  35. package/src/utils.ts +58 -0
  36. package/dist/components-8XBwMbFa.cjs +0 -343
  37. package/dist/components-8XBwMbFa.cjs.map +0 -1
  38. package/dist/components-DgtTZkWX.js +0 -277
  39. package/dist/components-DgtTZkWX.js.map +0 -1
  40. package/dist/generators-CY1SNd5X.cjs +0 -171
  41. package/dist/generators-CY1SNd5X.cjs.map +0 -1
  42. package/dist/generators-CvyZTxOm.js +0 -161
  43. package/dist/generators-CvyZTxOm.js.map +0 -1
  44. package/dist/types-MdHRNpgi.d.ts +0 -68
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["mswGenerator","handlersGenerator","pluginOasName","pluginTsName","pluginFakerName","path","camelCase","OperationGenerator"],"sources":["../src/plugin.ts"],"sourcesContent":["import path from 'node:path'\nimport { camelCase } from '@internals/utils'\nimport { createPlugin, type Group, getBarrelFiles, getMode } from '@kubb/core'\nimport { pluginFakerName } from '@kubb/plugin-faker'\nimport { OperationGenerator, pluginOasName } from '@kubb/plugin-oas'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { handlersGenerator, mswGenerator } from './generators'\nimport type { PluginMsw } from './types.ts'\n\nexport const pluginMswName = 'plugin-msw' satisfies PluginMsw['name']\n\nexport const pluginMsw = createPlugin<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 generators = [mswGenerator, handlers ? handlersGenerator : undefined].filter(Boolean),\n contentType,\n baseURL,\n } = options\n\n return {\n name: pluginMswName,\n options: {\n output,\n parser,\n group,\n baseURL,\n },\n pre: [pluginOasName, pluginTsName, parser === 'faker' ? pluginFakerName : undefined].filter(Boolean),\n resolvePath(baseName, pathMode, options) {\n const root = path.resolve(this.config.root, this.config.output.path)\n const mode = pathMode ?? getMode(path.resolve(root, output.path))\n\n if (mode === 'single') {\n /**\n * when output is a file then we will always append to the same file(output file), see fileManager.addOrAppend\n * Other plugins then need to call addOrAppend instead of just add from the fileManager class\n */\n return path.resolve(root, output.path)\n }\n\n if (group && (options?.group?.path || options?.group?.tag)) {\n const groupName: Group['name'] = group?.name\n ? group.name\n : (ctx) => {\n if (group?.type === 'path') {\n return `${ctx.group.split('/')[1]}`\n }\n return `${camelCase(ctx.group)}Controller`\n }\n\n return path.resolve(\n root,\n output.path,\n groupName({\n group: group.type === 'path' ? options.group.path! : options.group.tag!,\n }),\n baseName,\n )\n }\n\n return path.resolve(root, output.path, baseName)\n },\n resolveName(name, type) {\n const resolvedName = camelCase(name, {\n suffix: type ? 'handler' : undefined,\n isFile: type === 'file',\n })\n\n if (type) {\n return transformers?.name?.(resolvedName, type) || resolvedName\n }\n\n return resolvedName\n },\n async install() {\n const root = path.resolve(this.config.root, this.config.output.path)\n const mode = getMode(path.resolve(root, output.path))\n const oas = await this.getOas()\n\n const operationGenerator = new OperationGenerator(this.plugin.options, {\n fabric: this.fabric,\n oas,\n driver: this.driver,\n events: this.events,\n plugin: this.plugin,\n contentType,\n exclude,\n include,\n override,\n mode,\n })\n\n const files = await operationGenerator.build(...generators)\n await this.upsertFile(...files)\n\n const barrelFiles = await getBarrelFiles(this.fabric.files, {\n type: output.barrelType ?? 'named',\n root,\n output,\n meta: {\n pluginName: this.plugin.name,\n },\n })\n\n await this.upsertFile(...barrelFiles)\n },\n }\n})\n"],"mappings":";;;;;;;;;;AASA,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,aAAa,CAACA,mBAAAA,cAAc,WAAWC,mBAAAA,oBAAoB,KAAA,EAAU,CAAC,OAAO,QAAQ,EACrF,aACA,YACE;AAEJ,QAAO;EACL,MAAM;EACN,SAAS;GACP;GACA;GACA;GACA;GACD;EACD,KAAK;GAACC,iBAAAA;GAAeC,gBAAAA;GAAc,WAAW,UAAUC,mBAAAA,kBAAkB,KAAA;GAAU,CAAC,OAAO,QAAQ;EACpG,YAAY,UAAU,UAAU,SAAS;GACvC,MAAM,OAAOC,UAAAA,QAAK,QAAQ,KAAK,OAAO,MAAM,KAAK,OAAO,OAAO,KAAK;AAGpE,QAFa,aAAA,GAAA,WAAA,SAAoBA,UAAAA,QAAK,QAAQ,MAAM,OAAO,KAAK,CAAC,MAEpD;;;;;AAKX,UAAOA,UAAAA,QAAK,QAAQ,MAAM,OAAO,KAAK;AAGxC,OAAI,UAAU,SAAS,OAAO,QAAQ,SAAS,OAAO,MAAM;IAC1D,MAAM,YAA2B,OAAO,OACpC,MAAM,QACL,QAAQ;AACP,SAAI,OAAO,SAAS,OAClB,QAAO,GAAG,IAAI,MAAM,MAAM,IAAI,CAAC;AAEjC,YAAO,GAAGC,mBAAAA,UAAU,IAAI,MAAM,CAAC;;AAGrC,WAAOD,UAAAA,QAAK,QACV,MACA,OAAO,MACP,UAAU,EACR,OAAO,MAAM,SAAS,SAAS,QAAQ,MAAM,OAAQ,QAAQ,MAAM,KACpE,CAAC,EACF,SACD;;AAGH,UAAOA,UAAAA,QAAK,QAAQ,MAAM,OAAO,MAAM,SAAS;;EAElD,YAAY,MAAM,MAAM;GACtB,MAAM,eAAeC,mBAAAA,UAAU,MAAM;IACnC,QAAQ,OAAO,YAAY,KAAA;IAC3B,QAAQ,SAAS;IAClB,CAAC;AAEF,OAAI,KACF,QAAO,cAAc,OAAO,cAAc,KAAK,IAAI;AAGrD,UAAO;;EAET,MAAM,UAAU;GACd,MAAM,OAAOD,UAAAA,QAAK,QAAQ,KAAK,OAAO,MAAM,KAAK,OAAO,OAAO,KAAK;GACpE,MAAM,QAAA,GAAA,WAAA,SAAeA,UAAAA,QAAK,QAAQ,MAAM,OAAO,KAAK,CAAC;GACrD,MAAM,MAAM,MAAM,KAAK,QAAQ;GAe/B,MAAM,QAAQ,MAba,IAAIE,iBAAAA,mBAAmB,KAAK,OAAO,SAAS;IACrE,QAAQ,KAAK;IACb;IACA,QAAQ,KAAK;IACb,QAAQ,KAAK;IACb,QAAQ,KAAK;IACb;IACA;IACA;IACA;IACA;IACD,CAAC,CAEqC,MAAM,GAAG,WAAW;AAC3D,SAAM,KAAK,WAAW,GAAG,MAAM;GAE/B,MAAM,cAAc,OAAA,GAAA,WAAA,gBAAqB,KAAK,OAAO,OAAO;IAC1D,MAAM,OAAO,cAAc;IAC3B;IACA;IACA,MAAM,EACJ,YAAY,KAAK,OAAO,MACzB;IACF,CAAC;AAEF,SAAM,KAAK,WAAW,GAAG,YAAY;;EAExC;EACD"}
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>(() => ({\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 { 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 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((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":";;;;;;;;;;;;;;;AASA,MAAa,eAAA,GAAA,WAAA,uBAA+C;CAC1D,MAAM;CACN,YAAY;CACZ,QAAQ,MAAM,MAAM;EAClB,OAAOA,mBAAAA,UAAU,MAAM,EAAE,QAAQ,SAAS,QAAQ,CAAC;;CAErD,YAAY,MAAM;EAChB,OAAOA,mBAAAA,UAAU,MAAM,EAAE,QAAQ,WAAW,CAAC;;CAE/C,gBAAgB,MAAM,MAAM;EAC1B,OAAO,KAAK,QAAQ,MAAM,KAAK;;CAEjC,mBAAmB,MAAM;EACvB,OAAO,KAAK,YAAY,KAAK,YAAY;;CAE3C,sBAAsB;EACpB,OAAO;;CAEV,EAAE;;;ACnBH,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,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;GAC1B,IAAI,MAAM,SAAS,QACjB,OAAO,GAAG,IAAI,MAAM,MAAM,IAAI,CAAC;GAEjC,OAAO,GAAGC,mBAAAA,UAAU,IAAI,MAAM,CAAC;;EAEtC,GACD,KAAA;CAEJ,OAAO;EACL,MAAM;EACN;EACA,cAAc,CAACC,gBAAAA,cAAc,WAAW,UAAUC,mBAAAA,kBAAkB,KAAA,EAAU,CAAC,QAAQ,eAAqC,QAAQ,WAAW,CAAC;EAChJ,OAAO,EACL,oBAAoB,KAAK;GACvB,MAAM,WAAW,eAAe;IAAE,GAAG;IAAa,GAAG;IAAc,GAAG;GAEtE,IAAI,WAAW;IACb;IACA;IACA;IACA,OAAO;IACP;IACA;IACA;IACA;IACA;IACD,CAAC;GACF,IAAI,YAAY,SAAS;GACzB,IAAI,iBACF,IAAI,eAAe,gBAAgB;GAGrC,IAAI,aAAaC,mBAAAA,aAAa;GAC9B,IAAI,UACF,IAAI,aAAaC,mBAAAA,kBAAkB;GAErC,KAAK,MAAM,OAAO,gBAChB,IAAI,aAAa,IAAI;KAG1B;EACF;EACD"}
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { t as __name } from "./chunk--u3MIqq1.js";
2
- import { n as PluginMsw, t as Options } from "./types-MdHRNpgi.js";
3
- import * as _kubb_core0 from "@kubb/core";
2
+ import { n as PluginMsw, t as Options } from "./types-ItsHsMvC.js";
3
+ import * as _$_kubb_core0 from "@kubb/core";
4
4
 
5
5
  //#region src/plugin.d.ts
6
6
  declare const pluginMswName = "plugin-msw";
7
- declare const pluginMsw: (options?: Options | undefined) => _kubb_core0.UserPluginWithLifeCycle<PluginMsw>;
7
+ declare const pluginMsw: (options?: Options | undefined) => _$_kubb_core0.Plugin<PluginMsw>;
8
8
  //#endregion
9
- export { type PluginMsw, pluginMsw, pluginMswName };
9
+ export { type PluginMsw, pluginMsw as default, pluginMsw, pluginMswName };
10
10
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,84 +1,78 @@
1
1
  import "./chunk--u3MIqq1.js";
2
- import { a as camelCase } from "./components-DgtTZkWX.js";
3
- import { n as handlersGenerator, t as mswGenerator } from "./generators-CvyZTxOm.js";
4
- import path from "node:path";
5
- import { createPlugin, getBarrelFiles, getMode } from "@kubb/core";
2
+ import { c as camelCase } from "./components-Cm17DMTE.js";
3
+ import { n as handlersGenerator, t as mswGenerator } from "./generators-D9gvdP7Z.js";
4
+ import { definePlugin, defineResolver } from "@kubb/core";
6
5
  import { pluginFakerName } from "@kubb/plugin-faker";
7
- import { OperationGenerator, pluginOasName } from "@kubb/plugin-oas";
8
6
  import { pluginTsName } from "@kubb/plugin-ts";
7
+ //#region src/resolvers/resolverMsw.ts
8
+ /**
9
+ * Naming convention resolver for MSW plugin.
10
+ *
11
+ * Provides default naming helpers using camelCase with a `handler` suffix.
12
+ */
13
+ const resolverMsw = defineResolver(() => ({
14
+ name: "default",
15
+ pluginName: "plugin-msw",
16
+ default(name, type) {
17
+ return camelCase(name, { isFile: type === "file" });
18
+ },
19
+ resolveName(name) {
20
+ return camelCase(name, { suffix: "handler" });
21
+ },
22
+ resolvePathName(name, type) {
23
+ return this.default(name, type);
24
+ },
25
+ resolveHandlerName(node) {
26
+ return this.resolveName(node.operationId);
27
+ },
28
+ resolveHandlersName() {
29
+ return "handlers";
30
+ }
31
+ }));
32
+ //#endregion
9
33
  //#region src/plugin.ts
10
34
  const pluginMswName = "plugin-msw";
11
- const pluginMsw = createPlugin((options) => {
35
+ const pluginMsw = definePlugin((options) => {
12
36
  const { output = {
13
37
  path: "handlers",
14
38
  barrelType: "named"
15
- }, group, exclude = [], include, override = [], transformers = {}, handlers = false, parser = "data", generators = [mswGenerator, handlers ? handlersGenerator : void 0].filter(Boolean), contentType, baseURL } = options;
39
+ }, group, exclude = [], include, override = [], handlers = false, parser = "data", baseURL, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
40
+ const groupConfig = group ? {
41
+ ...group,
42
+ name: group.name ? group.name : (ctx) => {
43
+ if (group.type === "path") return `${ctx.group.split("/")[1]}`;
44
+ return `${camelCase(ctx.group)}Controller`;
45
+ }
46
+ } : void 0;
16
47
  return {
17
48
  name: pluginMswName,
18
- options: {
19
- output,
20
- parser,
21
- group,
22
- baseURL
23
- },
24
- pre: [
25
- pluginOasName,
26
- pluginTsName,
27
- parser === "faker" ? pluginFakerName : void 0
28
- ].filter(Boolean),
29
- resolvePath(baseName, pathMode, options) {
30
- const root = path.resolve(this.config.root, this.config.output.path);
31
- if ((pathMode ?? getMode(path.resolve(root, output.path))) === "single")
32
- /**
33
- * when output is a file then we will always append to the same file(output file), see fileManager.addOrAppend
34
- * Other plugins then need to call addOrAppend instead of just add from the fileManager class
35
- */
36
- return path.resolve(root, output.path);
37
- if (group && (options?.group?.path || options?.group?.tag)) {
38
- const groupName = group?.name ? group.name : (ctx) => {
39
- if (group?.type === "path") return `${ctx.group.split("/")[1]}`;
40
- return `${camelCase(ctx.group)}Controller`;
41
- };
42
- return path.resolve(root, output.path, groupName({ group: group.type === "path" ? options.group.path : options.group.tag }), baseName);
43
- }
44
- return path.resolve(root, output.path, baseName);
45
- },
46
- resolveName(name, type) {
47
- const resolvedName = camelCase(name, {
48
- suffix: type ? "handler" : void 0,
49
- isFile: type === "file"
50
- });
51
- if (type) return transformers?.name?.(resolvedName, type) || resolvedName;
52
- return resolvedName;
53
- },
54
- async install() {
55
- const root = path.resolve(this.config.root, this.config.output.path);
56
- const mode = getMode(path.resolve(root, output.path));
57
- const oas = await this.getOas();
58
- const files = await new OperationGenerator(this.plugin.options, {
59
- fabric: this.fabric,
60
- oas,
61
- driver: this.driver,
62
- events: this.events,
63
- plugin: this.plugin,
64
- contentType,
49
+ options,
50
+ dependencies: [pluginTsName, parser === "faker" ? pluginFakerName : void 0].filter((dependency) => Boolean(dependency)),
51
+ hooks: { "kubb:plugin:setup"(ctx) {
52
+ const resolver = userResolver ? {
53
+ ...resolverMsw,
54
+ ...userResolver
55
+ } : resolverMsw;
56
+ ctx.setOptions({
57
+ output,
58
+ parser,
59
+ baseURL,
60
+ group: groupConfig,
65
61
  exclude,
66
62
  include,
67
63
  override,
68
- mode
69
- }).build(...generators);
70
- await this.upsertFile(...files);
71
- const barrelFiles = await getBarrelFiles(this.fabric.files, {
72
- type: output.barrelType ?? "named",
73
- root,
74
- output,
75
- meta: { pluginName: this.plugin.name }
64
+ handlers,
65
+ resolver
76
66
  });
77
- await this.upsertFile(...barrelFiles);
78
- }
67
+ ctx.setResolver(resolver);
68
+ if (userTransformer) ctx.setTransformer(userTransformer);
69
+ ctx.addGenerator(mswGenerator);
70
+ if (handlers) ctx.addGenerator(handlersGenerator);
71
+ for (const gen of userGenerators) ctx.addGenerator(gen);
72
+ } }
79
73
  };
80
74
  });
81
75
  //#endregion
82
- export { pluginMsw, pluginMswName };
76
+ export { pluginMsw as default, pluginMsw, pluginMswName };
83
77
 
84
78
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["import path from 'node:path'\nimport { camelCase } from '@internals/utils'\nimport { createPlugin, type Group, getBarrelFiles, getMode } from '@kubb/core'\nimport { pluginFakerName } from '@kubb/plugin-faker'\nimport { OperationGenerator, pluginOasName } from '@kubb/plugin-oas'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { handlersGenerator, mswGenerator } from './generators'\nimport type { PluginMsw } from './types.ts'\n\nexport const pluginMswName = 'plugin-msw' satisfies PluginMsw['name']\n\nexport const pluginMsw = createPlugin<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 generators = [mswGenerator, handlers ? handlersGenerator : undefined].filter(Boolean),\n contentType,\n baseURL,\n } = options\n\n return {\n name: pluginMswName,\n options: {\n output,\n parser,\n group,\n baseURL,\n },\n pre: [pluginOasName, pluginTsName, parser === 'faker' ? pluginFakerName : undefined].filter(Boolean),\n resolvePath(baseName, pathMode, options) {\n const root = path.resolve(this.config.root, this.config.output.path)\n const mode = pathMode ?? getMode(path.resolve(root, output.path))\n\n if (mode === 'single') {\n /**\n * when output is a file then we will always append to the same file(output file), see fileManager.addOrAppend\n * Other plugins then need to call addOrAppend instead of just add from the fileManager class\n */\n return path.resolve(root, output.path)\n }\n\n if (group && (options?.group?.path || options?.group?.tag)) {\n const groupName: Group['name'] = group?.name\n ? group.name\n : (ctx) => {\n if (group?.type === 'path') {\n return `${ctx.group.split('/')[1]}`\n }\n return `${camelCase(ctx.group)}Controller`\n }\n\n return path.resolve(\n root,\n output.path,\n groupName({\n group: group.type === 'path' ? options.group.path! : options.group.tag!,\n }),\n baseName,\n )\n }\n\n return path.resolve(root, output.path, baseName)\n },\n resolveName(name, type) {\n const resolvedName = camelCase(name, {\n suffix: type ? 'handler' : undefined,\n isFile: type === 'file',\n })\n\n if (type) {\n return transformers?.name?.(resolvedName, type) || resolvedName\n }\n\n return resolvedName\n },\n async install() {\n const root = path.resolve(this.config.root, this.config.output.path)\n const mode = getMode(path.resolve(root, output.path))\n const oas = await this.getOas()\n\n const operationGenerator = new OperationGenerator(this.plugin.options, {\n fabric: this.fabric,\n oas,\n driver: this.driver,\n events: this.events,\n plugin: this.plugin,\n contentType,\n exclude,\n include,\n override,\n mode,\n })\n\n const files = await operationGenerator.build(...generators)\n await this.upsertFile(...files)\n\n const barrelFiles = await getBarrelFiles(this.fabric.files, {\n type: output.barrelType ?? 'named',\n root,\n output,\n meta: {\n pluginName: this.plugin.name,\n },\n })\n\n await this.upsertFile(...barrelFiles)\n },\n }\n})\n"],"mappings":";;;;;;;;;AASA,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,aAAa,CAAC,cAAc,WAAW,oBAAoB,KAAA,EAAU,CAAC,OAAO,QAAQ,EACrF,aACA,YACE;AAEJ,QAAO;EACL,MAAM;EACN,SAAS;GACP;GACA;GACA;GACA;GACD;EACD,KAAK;GAAC;GAAe;GAAc,WAAW,UAAU,kBAAkB,KAAA;GAAU,CAAC,OAAO,QAAQ;EACpG,YAAY,UAAU,UAAU,SAAS;GACvC,MAAM,OAAO,KAAK,QAAQ,KAAK,OAAO,MAAM,KAAK,OAAO,OAAO,KAAK;AAGpE,QAFa,YAAY,QAAQ,KAAK,QAAQ,MAAM,OAAO,KAAK,CAAC,MAEpD;;;;;AAKX,UAAO,KAAK,QAAQ,MAAM,OAAO,KAAK;AAGxC,OAAI,UAAU,SAAS,OAAO,QAAQ,SAAS,OAAO,MAAM;IAC1D,MAAM,YAA2B,OAAO,OACpC,MAAM,QACL,QAAQ;AACP,SAAI,OAAO,SAAS,OAClB,QAAO,GAAG,IAAI,MAAM,MAAM,IAAI,CAAC;AAEjC,YAAO,GAAG,UAAU,IAAI,MAAM,CAAC;;AAGrC,WAAO,KAAK,QACV,MACA,OAAO,MACP,UAAU,EACR,OAAO,MAAM,SAAS,SAAS,QAAQ,MAAM,OAAQ,QAAQ,MAAM,KACpE,CAAC,EACF,SACD;;AAGH,UAAO,KAAK,QAAQ,MAAM,OAAO,MAAM,SAAS;;EAElD,YAAY,MAAM,MAAM;GACtB,MAAM,eAAe,UAAU,MAAM;IACnC,QAAQ,OAAO,YAAY,KAAA;IAC3B,QAAQ,SAAS;IAClB,CAAC;AAEF,OAAI,KACF,QAAO,cAAc,OAAO,cAAc,KAAK,IAAI;AAGrD,UAAO;;EAET,MAAM,UAAU;GACd,MAAM,OAAO,KAAK,QAAQ,KAAK,OAAO,MAAM,KAAK,OAAO,OAAO,KAAK;GACpE,MAAM,OAAO,QAAQ,KAAK,QAAQ,MAAM,OAAO,KAAK,CAAC;GACrD,MAAM,MAAM,MAAM,KAAK,QAAQ;GAe/B,MAAM,QAAQ,MAba,IAAI,mBAAmB,KAAK,OAAO,SAAS;IACrE,QAAQ,KAAK;IACb;IACA,QAAQ,KAAK;IACb,QAAQ,KAAK;IACb,QAAQ,KAAK;IACb;IACA;IACA;IACA;IACA;IACD,CAAC,CAEqC,MAAM,GAAG,WAAW;AAC3D,SAAM,KAAK,WAAW,GAAG,MAAM;GAE/B,MAAM,cAAc,MAAM,eAAe,KAAK,OAAO,OAAO;IAC1D,MAAM,OAAO,cAAc;IAC3B;IACA;IACA,MAAM,EACJ,YAAY,KAAK,OAAO,MACzB;IACF,CAAC;AAEF,SAAM,KAAK,WAAW,GAAG,YAAY;;EAExC;EACD"}
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>(() => ({\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 { 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 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((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":";;;;;;;;;;;;AASA,MAAa,cAAc,sBAAiC;CAC1D,MAAM;CACN,YAAY;CACZ,QAAQ,MAAM,MAAM;EAClB,OAAO,UAAU,MAAM,EAAE,QAAQ,SAAS,QAAQ,CAAC;;CAErD,YAAY,MAAM;EAChB,OAAO,UAAU,MAAM,EAAE,QAAQ,WAAW,CAAC;;CAE/C,gBAAgB,MAAM,MAAM;EAC1B,OAAO,KAAK,QAAQ,MAAM,KAAK;;CAEjC,mBAAmB,MAAM;EACvB,OAAO,KAAK,YAAY,KAAK,YAAY;;CAE3C,sBAAsB;EACpB,OAAO;;CAEV,EAAE;;;ACnBH,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,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;GAC1B,IAAI,MAAM,SAAS,QACjB,OAAO,GAAG,IAAI,MAAM,MAAM,IAAI,CAAC;GAEjC,OAAO,GAAG,UAAU,IAAI,MAAM,CAAC;;EAEtC,GACD,KAAA;CAEJ,OAAO;EACL,MAAM;EACN;EACA,cAAc,CAAC,cAAc,WAAW,UAAU,kBAAkB,KAAA,EAAU,CAAC,QAAQ,eAAqC,QAAQ,WAAW,CAAC;EAChJ,OAAO,EACL,oBAAoB,KAAK;GACvB,MAAM,WAAW,eAAe;IAAE,GAAG;IAAa,GAAG;IAAc,GAAG;GAEtE,IAAI,WAAW;IACb;IACA;IACA;IACA,OAAO;IACP;IACA;IACA;IACA;IACA;IACD,CAAC;GACF,IAAI,YAAY,SAAS;GACzB,IAAI,iBACF,IAAI,eAAe,gBAAgB;GAGrC,IAAI,aAAa,aAAa;GAC9B,IAAI,UACF,IAAI,aAAa,kBAAkB;GAErC,KAAK,MAAM,OAAO,gBAChB,IAAI,aAAa,IAAI;KAG1B;EACF;EACD"}
@@ -0,0 +1,94 @@
1
+ import { t as __name } from "./chunk--u3MIqq1.js";
2
+ import { Exclude, Generator, Group, Include, Output, 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
+ type Options = {
27
+ /**
28
+ * Specify the export location for the files and define the behavior of the output
29
+ * @default { path: 'handlers', barrelType: 'named' }
30
+ */
31
+ output?: Output;
32
+ baseURL?: string;
33
+ /**
34
+ * Group the MSW mocks based on the provided name.
35
+ */
36
+ group?: Group;
37
+ /**
38
+ * Tags, operations, or paths to exclude from generation.
39
+ */
40
+ exclude?: Array<Exclude>;
41
+ /**
42
+ * Tags, operations, or paths to include in generation.
43
+ */
44
+ include?: Array<Include>;
45
+ /**
46
+ * Override options for specific tags, operations, or paths.
47
+ */
48
+ override?: Array<Override<ResolvedOptions>>;
49
+ /**
50
+ * Override naming conventions for function names and types.
51
+ */
52
+ resolver?: Partial<ResolverMsw> & ThisType<ResolverMsw>;
53
+ /**
54
+ * AST visitor to transform generated nodes.
55
+ */
56
+ transformer?: ast.Visitor;
57
+ /**
58
+ * Create `handlers.ts` file with all handlers grouped by methods.
59
+ * @default false
60
+ */
61
+ handlers?: boolean;
62
+ /**
63
+ * Which parser to use for generating response data.
64
+ *
65
+ * @default 'data'
66
+ */
67
+ parser?: 'data' | 'faker';
68
+ /**
69
+ * Additional generators alongside the default generators.
70
+ */
71
+ generators?: Array<Generator<PluginMsw>>;
72
+ };
73
+ type ResolvedOptions = {
74
+ output: Output;
75
+ group: Group | undefined;
76
+ exclude: NonNullable<Options['exclude']>;
77
+ include: Options['include'];
78
+ override: NonNullable<Options['override']>;
79
+ parser: NonNullable<Options['parser']>;
80
+ baseURL: Options['baseURL'] | undefined;
81
+ handlers: boolean;
82
+ resolver: ResolverMsw;
83
+ };
84
+ type PluginMsw = PluginFactoryOptions<'plugin-msw', Options, ResolvedOptions, ResolverMsw>;
85
+ declare global {
86
+ namespace Kubb {
87
+ interface PluginRegistry {
88
+ 'plugin-msw': PluginMsw;
89
+ }
90
+ }
91
+ }
92
+ //#endregion
93
+ export { PluginMsw as n, Options as t };
94
+ //# sourceMappingURL=types-ItsHsMvC.d.ts.map
package/extension.yaml ADDED
@@ -0,0 +1,233 @@
1
+ $schema: https://kubb.dev/schemas/extension.json
2
+ kind: plugin
3
+ id: plugin-msw
4
+ name: MSW
5
+ description: Generate Mock Service Worker (MSW) handlers from OpenAPI specifications.
6
+ category: mocks
7
+ type: official
8
+ npmPackage: '@kubb/plugin-msw'
9
+ docsPath: /plugins/plugin-msw
10
+ repo: https://github.com/kubb-labs/plugins
11
+ maintainers:
12
+ - name: Stijn Van Hulle
13
+ github: stijnvanhulle
14
+ compatibility:
15
+ kubb: '>=5.0.0'
16
+ node: '>=22'
17
+ tags:
18
+ - msw
19
+ - mock-service-worker
20
+ - api-mocking
21
+ - mocks
22
+ - testing
23
+ - codegen
24
+ - openapi
25
+ dependencies:
26
+ - plugin-ts
27
+ - plugin-faker
28
+ resources:
29
+ documentation: https://kubb.dev/plugins/plugin-msw
30
+ repository: https://github.com/kubb-labs/plugins
31
+ issues: https://github.com/kubb-labs/plugins/issues
32
+ changelog: https://github.com/kubb-labs/plugins/blob/main/packages/plugin-msw/CHANGELOG.md
33
+ codesandbox: https://codesandbox.io/p/github/kubb-labs/plugins/main/examples/msw
34
+ featured: false
35
+ icon:
36
+ light: https://kubb.dev/feature/msw.svg
37
+ intro: |
38
+ # @kubb/plugin-msw
39
+
40
+ Generate [MSW](https://mswjs.io/) API mock handlers from your OpenAPI schema. Mock API requests in development and tests with type-safe handlers.
41
+ options:
42
+ - name: output
43
+ type: Output
44
+ required: false
45
+ default: "{ path: 'handlers', barrel: { type: 'named' } }"
46
+ description: Specify the export location for the files and define the behavior of the output.
47
+ properties:
48
+ - name: path
49
+ type: string
50
+ required: true
51
+ description: Output directory or file for the generated code, relative to the global `output.path`.
52
+ tip: |
53
+ if `output.path` is a file, `group` cannot be used.
54
+ default: "'handlers'"
55
+ - name: barrel
56
+ type: "{ type: 'named' | 'all', nested?: boolean } | false"
57
+ required: false
58
+ default: "{ type: 'named' }"
59
+ description: "Configure barrel file export strategy. Use `type` to control named vs. wildcard exports; set `nested: true` to generate hierarchical barrels in subdirectories."
60
+ examples:
61
+ - name: all
62
+ files:
63
+ - lang: typescript
64
+ code: |
65
+ export * from './gen/petService.ts'
66
+ twoslash: false
67
+ - name: named
68
+ files:
69
+ - lang: typescript
70
+ code: |
71
+ export { PetService } from './gen/petService.ts'
72
+ twoslash: false
73
+ - name: 'false'
74
+ files:
75
+ - lang: typescript
76
+ code: ''
77
+ twoslash: false
78
+ - name: banner
79
+ type: 'string | ((node: RootNode) => string)'
80
+ required: false
81
+ description: Add a banner comment at the top of every generated file. Accepts a static string or a function that receives the `RootNode` and returns a string.
82
+ - name: footer
83
+ type: 'string | ((node: RootNode) => string)'
84
+ required: false
85
+ description: Add a footer comment at the end of every generated file. Accepts a static string or a function that receives the `RootNode` and returns a string.
86
+ - name: override
87
+ type: boolean
88
+ required: false
89
+ default: 'false'
90
+ description: Whether Kubb overrides existing external files that can be generated if they already exist.
91
+ - name: handlers
92
+ type: boolean
93
+ required: false
94
+ default: 'false'
95
+ description: Create a `handlers.ts` file with all handlers grouped by methods.
96
+ - name: baseURL
97
+ type: string
98
+ required: false
99
+ description: Sets a custom base URL for all generated calls. When not set, the base URL is automatically taken from the OAS spec via the adapter (e.g. the `servers[0].url` field).
100
+ - name: group
101
+ type: Group
102
+ required: false
103
+ description: |
104
+ Grouping combines files in a folder based on a specific `type`.
105
+ examples:
106
+ - name: kubb.config.ts
107
+ files:
108
+ - lang: typescript
109
+ code: |
110
+ group: {
111
+ type: 'tag',
112
+ name({ group }) {
113
+ return `${group}Controller`
114
+ }
115
+ }
116
+ twoslash: false
117
+ body: |
118
+ With the configuration above, the generator emits:
119
+
120
+ ```text
121
+ .
122
+ ├── src/
123
+ │ └── petController/
124
+ │ │ ├── addPet.ts
125
+ │ │ └── getPet.ts
126
+ │ └── storeController/
127
+ │ ├── createStore.ts
128
+ │ └── getStoreById.ts
129
+ ├── petStore.yaml
130
+ ├── kubb.config.ts
131
+ └── package.json
132
+ ```
133
+ properties:
134
+ - name: type
135
+ type: "'tag'"
136
+ required: true
137
+ description: Specify the property to group files by. Required when `group` is defined.
138
+ note: |
139
+ `Required: true*` means this is required only when the `group` option is used. The `group` option itself is optional.
140
+ body: |
141
+ - `'tag'`: Uses the first tag from `operation.getTags().at(0)?.name`
142
+ - name: name
143
+ type: '(context: GroupContext) => string'
144
+ required: false
145
+ default: (ctx) => `${ctx.group}Controller`
146
+ description: Return the name of a group based on the group name. This is used for file and identifier generation.
147
+ - name: parser
148
+ type: "'data' | 'faker'"
149
+ required: false
150
+ default: "'data'"
151
+ description: Choose which parser to use when generating response data.
152
+ body: |
153
+ - `'faker'` will use `@kubb/plugin-faker` to generate the data for the response.
154
+ - `'data'` will use your custom data to generate the data for the response.
155
+ - name: include
156
+ type: Array<Include>
157
+ required: false
158
+ description: Array containing include parameters to include tags, operations, methods, paths, or content types.
159
+ codeBlock:
160
+ lang: typescript
161
+ title: Include
162
+ code: |
163
+ export type Include = {
164
+ type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
165
+ pattern: string | RegExp
166
+ }
167
+ - name: exclude
168
+ type: Array<Exclude>
169
+ required: false
170
+ description: Array containing exclude parameters to exclude or skip tags, operations, methods, paths, or content types.
171
+ codeBlock:
172
+ lang: typescript
173
+ title: Exclude
174
+ code: |
175
+ export type Exclude = {
176
+ type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
177
+ pattern: string | RegExp
178
+ }
179
+ - name: override
180
+ type: Array<Override>
181
+ required: false
182
+ description: Array containing override parameters to override `options` based on tags, operations, methods, paths, or content types.
183
+ codeBlock:
184
+ lang: typescript
185
+ title: Override
186
+ code: |
187
+ export type Override = {
188
+ type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
189
+ pattern: string | RegExp
190
+ options: PluginOptions
191
+ }
192
+ - name: generators
193
+ type: Array<Generator<PluginMsw>>
194
+ required: false
195
+ experimental: true
196
+ description: |
197
+ Define additional generators next to the built-in generators.
198
+
199
+ See [Generators](https://kubb.dev/docs/5.x/guides/creating-plugins) for more information on how to use generators.
200
+ examples:
201
+ - name: kubb.config.ts
202
+ files:
203
+ - lang: typescript
204
+ code: |
205
+ import { defineConfig } from 'kubb'
206
+ import { pluginMsw } from '@kubb/plugin-msw'
207
+ import { pluginTs } from '@kubb/plugin-ts'
208
+
209
+ export default defineConfig({
210
+ input: {
211
+ path: './petStore.yaml',
212
+ },
213
+ output: {
214
+ path: './src/gen',
215
+ },
216
+ plugins: [
217
+ pluginTs(),
218
+ pluginMsw({
219
+ output: {
220
+ path: './mocks',
221
+ barrel: { type: 'named' },
222
+ banner: '/* eslint-disable no-alert, no-console */',
223
+ footer: '',
224
+ },
225
+ group: {
226
+ type: 'tag',
227
+ name: ({ group }) => `${group}Service`,
228
+ },
229
+ handlers: true,
230
+ }),
231
+ ],
232
+ })
233
+ twoslash: false