@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.
- package/README.md +39 -22
- package/dist/{components-vO0FIb2i.js → components-Bi7cN-ws.js} +111 -199
- package/dist/components-Bi7cN-ws.js.map +1 -0
- package/dist/{components-CLQ77DVn.cjs → components-Bp69JYOt.cjs} +113 -213
- package/dist/components-Bp69JYOt.cjs.map +1 -0
- package/dist/components.cjs +1 -2
- package/dist/components.d.ts +6 -19
- package/dist/components.js +2 -2
- package/dist/{generators-BPJCs1x1.js → generators-BnEvTy3q.js} +71 -39
- package/dist/generators-BnEvTy3q.js.map +1 -0
- package/dist/{generators-CrmMwWE4.cjs → generators-d22_s2UN.cjs} +69 -37
- package/dist/generators-d22_s2UN.cjs.map +1 -0
- package/dist/generators.cjs +1 -1
- package/dist/generators.d.ts +16 -5
- package/dist/generators.js +1 -1
- package/dist/index.cjs +112 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +33 -4
- package/dist/index.js +113 -18
- package/dist/index.js.map +1 -1
- package/dist/types-B1yTWOfj.d.ts +99 -0
- package/package.json +13 -23
- package/src/components/Mock.tsx +7 -6
- package/src/components/MockWithFaker.tsx +7 -6
- package/src/components/Response.tsx +1 -1
- package/src/components/index.ts +0 -1
- package/src/generators/handlersGenerator.ts +49 -0
- package/src/generators/index.ts +1 -1
- package/src/generators/mswGenerator.tsx +27 -16
- package/src/plugin.ts +35 -19
- package/src/resolvers/resolverMsw.ts +21 -5
- package/src/types.ts +36 -26
- package/src/utils.ts +26 -61
- package/dist/components-CLQ77DVn.cjs.map +0 -1
- package/dist/components-vO0FIb2i.js.map +0 -1
- package/dist/generators-BPJCs1x1.js.map +0 -1
- package/dist/generators-CrmMwWE4.cjs.map +0 -1
- package/dist/types-Dxu0KMQ4.d.ts +0 -89
- package/extension.yaml +0 -260
- package/src/components/Handlers.tsx +0 -19
- package/src/generators/handlersGenerator.tsx +0 -41
- /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
package/dist/index.cjs.map
CHANGED
|
@@ -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 *
|
|
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
|
|
2
|
-
import { n as PluginMsw, t as Options } from "./types-
|
|
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
|
-
|
|
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
|
|
2
|
-
import {
|
|
3
|
-
import { n as handlersGenerator, t as mswGenerator } from "./generators-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
73
|
+
* resolverMsw.resolveName('addPet') // 'addPetHandler'
|
|
74
|
+
* ```
|
|
12
75
|
*/
|
|
13
|
-
const resolverMsw = defineResolver((
|
|
76
|
+
const resolverMsw = defineResolver(() => ({
|
|
14
77
|
name: "default",
|
|
15
78
|
pluginName: "plugin-msw",
|
|
16
79
|
default(name, type) {
|
|
17
|
-
return
|
|
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
|
-
|
|
30
|
-
}, group, exclude = [], include, override = [],
|
|
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 :
|
|
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 *
|
|
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
|
-
"description": "Mock Service Worker (MSW) handlers
|
|
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-
|
|
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
|
-
"
|
|
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.
|
|
80
|
-
"@kubb/renderer-jsx": "5.0.0-beta.
|
|
81
|
-
"@kubb/plugin-faker": "5.0.0-beta.
|
|
82
|
-
"@kubb/plugin-ts": "5.0.0-beta.
|
|
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.
|
|
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
|
|
102
|
-
"clean": "
|
|
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"
|
package/src/components/Mock.tsx
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import {
|
|
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,
|
|
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 =
|
|
24
|
+
const url = Url.toPath(getMswUrl(node))
|
|
24
25
|
|
|
25
|
-
const headers = [contentType ? `'Content-Type': '${contentType}'` :
|
|
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 {
|
|
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
|
|
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 =
|
|
25
|
+
const url = Url.toPath(getMswUrl(node))
|
|
25
26
|
|
|
26
|
-
const headers = [contentType ? `'Content-Type': '${contentType}'` :
|
|
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}'` :
|
|
19
|
+
const headers = [contentType ? `'Content-Type': '${contentType}'` : null].filter(Boolean)
|
|
20
20
|
|
|
21
21
|
const params = declarationPrinter.print(
|
|
22
22
|
ast.createFunctionParameters({
|
package/src/components/index.ts
CHANGED
|
@@ -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
|
+
})
|
package/src/generators/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { handlersGenerator } from './handlersGenerator.
|
|
1
|
+
export { handlersGenerator } from './handlersGenerator.ts'
|
|
2
2
|
export { mswGenerator } from './mswGenerator.tsx'
|