@kubb/plugin-msw 5.0.0-beta.98 → 5.0.0
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/dist/index.cjs +64 -266
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +65 -267
- package/dist/index.js.map +1 -1
- package/package.json +7 -10
package/dist/index.cjs
CHANGED
|
@@ -8,264 +8,46 @@ let _kubb_plugin_faker = require("@kubb/plugin-faker");
|
|
|
8
8
|
let _kubb_plugin_ts = require("@kubb/plugin-ts");
|
|
9
9
|
let kubb_jsx = require("kubb/jsx");
|
|
10
10
|
let kubb_jsx_jsx_runtime = require("kubb/jsx/jsx-runtime");
|
|
11
|
-
//#region ../../internals/
|
|
12
|
-
/**
|
|
13
|
-
* Shared implementation for camelCase and PascalCase conversion.
|
|
14
|
-
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
|
|
15
|
-
* and capitalizes each word according to `pascal`.
|
|
16
|
-
*
|
|
17
|
-
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
18
|
-
*/
|
|
19
|
-
function toCamelOrPascal(text, pascal) {
|
|
20
|
-
return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
|
|
21
|
-
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
22
|
-
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
23
|
-
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Converts `text` to camelCase.
|
|
27
|
-
*
|
|
28
|
-
* @example Word boundaries
|
|
29
|
-
* `camelCase('hello-world') // 'helloWorld'`
|
|
30
|
-
*
|
|
31
|
-
* @example With a prefix
|
|
32
|
-
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
33
|
-
*/
|
|
34
|
-
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
35
|
-
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
36
|
-
}
|
|
37
|
-
//#endregion
|
|
38
|
-
//#region ../../internals/utils/src/reserved.ts
|
|
39
|
-
/**
|
|
40
|
-
* JavaScript and Java reserved words.
|
|
41
|
-
* @link https://github.com/jonschlinkert/reserved/blob/master/index.js
|
|
42
|
-
*/
|
|
43
|
-
const reservedWords = /* @__PURE__ */ new Set([
|
|
44
|
-
"abstract",
|
|
45
|
-
"arguments",
|
|
46
|
-
"boolean",
|
|
47
|
-
"break",
|
|
48
|
-
"byte",
|
|
49
|
-
"case",
|
|
50
|
-
"catch",
|
|
51
|
-
"char",
|
|
52
|
-
"class",
|
|
53
|
-
"const",
|
|
54
|
-
"continue",
|
|
55
|
-
"debugger",
|
|
56
|
-
"default",
|
|
57
|
-
"delete",
|
|
58
|
-
"do",
|
|
59
|
-
"double",
|
|
60
|
-
"else",
|
|
61
|
-
"enum",
|
|
62
|
-
"eval",
|
|
63
|
-
"export",
|
|
64
|
-
"extends",
|
|
65
|
-
"false",
|
|
66
|
-
"final",
|
|
67
|
-
"finally",
|
|
68
|
-
"float",
|
|
69
|
-
"for",
|
|
70
|
-
"function",
|
|
71
|
-
"goto",
|
|
72
|
-
"if",
|
|
73
|
-
"implements",
|
|
74
|
-
"import",
|
|
75
|
-
"in",
|
|
76
|
-
"instanceof",
|
|
77
|
-
"int",
|
|
78
|
-
"interface",
|
|
79
|
-
"let",
|
|
80
|
-
"long",
|
|
81
|
-
"native",
|
|
82
|
-
"new",
|
|
83
|
-
"null",
|
|
84
|
-
"package",
|
|
85
|
-
"private",
|
|
86
|
-
"protected",
|
|
87
|
-
"public",
|
|
88
|
-
"return",
|
|
89
|
-
"short",
|
|
90
|
-
"static",
|
|
91
|
-
"super",
|
|
92
|
-
"switch",
|
|
93
|
-
"synchronized",
|
|
94
|
-
"this",
|
|
95
|
-
"throw",
|
|
96
|
-
"throws",
|
|
97
|
-
"transient",
|
|
98
|
-
"true",
|
|
99
|
-
"try",
|
|
100
|
-
"typeof",
|
|
101
|
-
"var",
|
|
102
|
-
"void",
|
|
103
|
-
"volatile",
|
|
104
|
-
"while",
|
|
105
|
-
"with",
|
|
106
|
-
"yield",
|
|
107
|
-
"Array",
|
|
108
|
-
"Date",
|
|
109
|
-
"hasOwnProperty",
|
|
110
|
-
"Infinity",
|
|
111
|
-
"isFinite",
|
|
112
|
-
"isNaN",
|
|
113
|
-
"isPrototypeOf",
|
|
114
|
-
"length",
|
|
115
|
-
"Math",
|
|
116
|
-
"name",
|
|
117
|
-
"NaN",
|
|
118
|
-
"Number",
|
|
119
|
-
"Object",
|
|
120
|
-
"prototype",
|
|
121
|
-
"String",
|
|
122
|
-
"toString",
|
|
123
|
-
"undefined",
|
|
124
|
-
"valueOf"
|
|
125
|
-
]);
|
|
11
|
+
//#region ../../internals/shared/src/operation.ts
|
|
126
12
|
/**
|
|
127
|
-
*
|
|
13
|
+
* Builds the `ResolverFileParams` every operation generator passes to
|
|
14
|
+
* `resolver.file`: a file named `name`, tagged by the operation's first
|
|
15
|
+
* tag (or `'default'`), at the operation's path. Centralizes the entry object
|
|
16
|
+
* that was repeated at dozens of call sites across the client and query plugins.
|
|
128
17
|
*
|
|
129
18
|
* @example
|
|
130
19
|
* ```ts
|
|
131
|
-
*
|
|
132
|
-
* isValidVarName('class') // false (reserved word)
|
|
133
|
-
* isValidVarName('42foo') // false (starts with digit)
|
|
20
|
+
* resolver.file(operationFileEntry(node, node.operationId), { root, output, group })
|
|
134
21
|
* ```
|
|
135
22
|
*/
|
|
136
|
-
function
|
|
137
|
-
|
|
138
|
-
|
|
23
|
+
function operationFileEntry(node, name, extname = ".ts") {
|
|
24
|
+
return {
|
|
25
|
+
name,
|
|
26
|
+
extname,
|
|
27
|
+
tag: node.tags[0] ?? "default",
|
|
28
|
+
path: node.path
|
|
29
|
+
};
|
|
139
30
|
}
|
|
140
31
|
/**
|
|
141
|
-
*
|
|
32
|
+
* Resolves a dependency plugin's generated file for `node.operationId`, cached in `cache` (the
|
|
33
|
+
* current node's `ctx.cache`) under the resolver's own plugin name. Several dependents reading the
|
|
34
|
+
* same dependency for the same operation in one pass (a query plugin's several hook generators, the
|
|
35
|
+
* MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.
|
|
142
36
|
*
|
|
143
|
-
*
|
|
144
|
-
* even though they are not valid variable names, so use this (not {@link isValidVarName}) when
|
|
145
|
-
* deciding whether an object key needs quoting.
|
|
146
|
-
*
|
|
147
|
-
* @example
|
|
37
|
+
* @example Cache `plugin-ts`'s file for the current operation
|
|
148
38
|
* ```ts
|
|
149
|
-
*
|
|
150
|
-
* isIdentifier('x-total')// false
|
|
39
|
+
* const fileTs = resolveDependencyOperationFile({ cache: ctx.cache, node, resolver: tsResolver, root, output })
|
|
151
40
|
* ```
|
|
152
41
|
*/
|
|
153
|
-
function
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
function toParamsObject(path, { replacer, casing } = {}) {
|
|
163
|
-
const params = {};
|
|
164
|
-
for (const match of path.matchAll(/\{([^}]+)\}/g)) {
|
|
165
|
-
const param = transformParam(match[1], casing);
|
|
166
|
-
const key = replacer ? replacer(param) : param;
|
|
167
|
-
params[key] = key;
|
|
168
|
-
}
|
|
169
|
-
return Object.keys(params).length > 0 ? params : null;
|
|
42
|
+
function resolveDependencyOperationFile(options) {
|
|
43
|
+
const { cache, node, resolver, root, output, group } = options;
|
|
44
|
+
return cache.ensureItem(`${resolver.pluginName}:operationFile`, () => resolver.file({
|
|
45
|
+
...operationFileEntry(node, node.operationId),
|
|
46
|
+
root,
|
|
47
|
+
output,
|
|
48
|
+
group: group ?? void 0
|
|
49
|
+
}));
|
|
170
50
|
}
|
|
171
|
-
/**
|
|
172
|
-
* Helpers for OpenAPI/Swagger paths, plus a thin wrapper over the native `URL`.
|
|
173
|
-
*/
|
|
174
|
-
var Url = class Url {
|
|
175
|
-
/**
|
|
176
|
-
* Reports whether `url` is a parseable absolute URL. Delegates to the native `URL.canParse`.
|
|
177
|
-
*
|
|
178
|
-
* @example
|
|
179
|
-
* Url.canParse('https://petstore.swagger.io/v2') // true
|
|
180
|
-
* Url.canParse('/pet/{petId}') // false
|
|
181
|
-
*/
|
|
182
|
-
static canParse(url, base) {
|
|
183
|
-
return URL.canParse(url, base);
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Converts an OpenAPI/Swagger path to Express-style colon syntax.
|
|
187
|
-
*
|
|
188
|
-
* @example
|
|
189
|
-
* Url.toPath('/pet/{petId}') // '/pet/:petId'
|
|
190
|
-
*/
|
|
191
|
-
static toPath(path) {
|
|
192
|
-
return path.replace(/\{([^}]+)\}/g, ":$1");
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Rewrites OpenAPI placeholder names while keeping the `{...}` braces, so the generated `url`
|
|
196
|
-
* literal aligns with the grouped `path` request option that the runtime client interpolates by
|
|
197
|
-
* key.
|
|
198
|
-
*
|
|
199
|
-
* @example
|
|
200
|
-
* Url.toCasedTemplate('/projects/{project_id}', { casing: 'camelcase' }) // '/projects/{projectId}'
|
|
201
|
-
*/
|
|
202
|
-
static toCasedTemplate(path, { casing } = {}) {
|
|
203
|
-
return path.replace(/\{([^}]+)\}/g, (_, name) => `{${transformParam(name, casing)}}`);
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Converts an OpenAPI/Swagger path to a TypeScript template literal string.
|
|
207
|
-
* `prefix` is prepended inside the literal, `replacer` transforms each parameter name,
|
|
208
|
-
* and `casing` controls parameter identifier casing.
|
|
209
|
-
*
|
|
210
|
-
* @example
|
|
211
|
-
* Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
|
|
212
|
-
*
|
|
213
|
-
* @example
|
|
214
|
-
* Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
|
|
215
|
-
*/
|
|
216
|
-
static toTemplateString(path, { prefix, replacer, casing } = {}) {
|
|
217
|
-
const result = path.split(/\{([^}]+)\}/).map((part, i) => {
|
|
218
|
-
if (i % 2 === 0) return part;
|
|
219
|
-
const param = transformParam(part, casing);
|
|
220
|
-
return `\${${replacer ? replacer(param) : param}}`;
|
|
221
|
-
}).join("");
|
|
222
|
-
return `\`${prefix ?? ""}${result}\``;
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the
|
|
226
|
-
* grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter
|
|
227
|
-
* names are camelCased to match the generated `path` type, and `prefix` is prepended inside the
|
|
228
|
-
* literal. Shared by the client and cypress generators that pass a grouped `path` object.
|
|
229
|
-
*
|
|
230
|
-
* @example
|
|
231
|
-
* Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'
|
|
232
|
-
*/
|
|
233
|
-
static toGroupedTemplateString(path, { prefix } = {}) {
|
|
234
|
-
return Url.toTemplateString(path, {
|
|
235
|
-
prefix,
|
|
236
|
-
casing: "camelcase",
|
|
237
|
-
replacer: (name) => `path.${name}`
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* Returns the path and its extracted params as a structured `URLObject`, or as a stringified
|
|
242
|
-
* expression when `stringify` is set.
|
|
243
|
-
*
|
|
244
|
-
* @example
|
|
245
|
-
* Url.toObject('/pet/{petId}')
|
|
246
|
-
* // { url: '/pet/:petId', params: { petId: 'petId' } }
|
|
247
|
-
*/
|
|
248
|
-
static toObject(path, { type = "path", replacer, stringify, casing } = {}) {
|
|
249
|
-
const object = {
|
|
250
|
-
url: type === "path" ? Url.toPath(path) : Url.toTemplateString(path, {
|
|
251
|
-
replacer,
|
|
252
|
-
casing
|
|
253
|
-
}),
|
|
254
|
-
params: toParamsObject(path, {
|
|
255
|
-
replacer,
|
|
256
|
-
casing
|
|
257
|
-
})
|
|
258
|
-
};
|
|
259
|
-
if (stringify) {
|
|
260
|
-
if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
|
|
261
|
-
if (object.params) return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll("'", "").replaceAll(`"`, "")} }`;
|
|
262
|
-
return `{ url: '${object.url}' }`;
|
|
263
|
-
}
|
|
264
|
-
return object;
|
|
265
|
-
}
|
|
266
|
-
};
|
|
267
|
-
//#endregion
|
|
268
|
-
//#region ../../internals/shared/src/operation.ts
|
|
269
51
|
function getStatusCodeNumber(statusCode) {
|
|
270
52
|
const code = Number(statusCode);
|
|
271
53
|
return Number.isNaN(code) ? null : code;
|
|
@@ -297,6 +79,33 @@ function resolveResponseTypes(node, resolver) {
|
|
|
297
79
|
return types;
|
|
298
80
|
}
|
|
299
81
|
//#endregion
|
|
82
|
+
//#region ../../internals/utils/src/casing.ts
|
|
83
|
+
/**
|
|
84
|
+
* Shared implementation for camelCase and PascalCase conversion.
|
|
85
|
+
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
|
|
86
|
+
* and capitalizes each word according to `pascal`.
|
|
87
|
+
*
|
|
88
|
+
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
89
|
+
*/
|
|
90
|
+
function toCamelOrPascal(text, pascal) {
|
|
91
|
+
return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
|
|
92
|
+
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
93
|
+
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
94
|
+
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Converts `text` to camelCase.
|
|
98
|
+
*
|
|
99
|
+
* @example Word boundaries
|
|
100
|
+
* `camelCase('hello-world') // 'helloWorld'`
|
|
101
|
+
*
|
|
102
|
+
* @example With a prefix
|
|
103
|
+
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
104
|
+
*/
|
|
105
|
+
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
106
|
+
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
300
109
|
//#region ../../internals/shared/src/group.ts
|
|
301
110
|
/**
|
|
302
111
|
* Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
|
|
@@ -431,12 +240,6 @@ function getMswMethod(node) {
|
|
|
431
240
|
return kubb_kit.ast.isHttpOperationNode(node) ? node.method.toLowerCase() : "";
|
|
432
241
|
}
|
|
433
242
|
/**
|
|
434
|
-
* Converts an OpenAPI-style path to an Express/MSW-style path by replacing `{param}` with `:param`.
|
|
435
|
-
*/
|
|
436
|
-
function getMswUrl(node) {
|
|
437
|
-
return kubb_kit.ast.isHttpOperationNode(node) ? node.path.replaceAll("{", ":").replaceAll("}", "") : "";
|
|
438
|
-
}
|
|
439
|
-
/**
|
|
440
243
|
* Resolves faker metadata for an MSW operation, including response name and file path.
|
|
441
244
|
*/
|
|
442
245
|
function resolveFakerMeta(node, options) {
|
|
@@ -463,7 +266,7 @@ function Mock({ baseURL = "", name, fakerName, typeName, requestTypeName, node }
|
|
|
463
266
|
const successResponse = getPrimarySuccessResponse(node);
|
|
464
267
|
const statusCode = successResponse ? Number(successResponse.statusCode) : 200;
|
|
465
268
|
const contentType = getContentType(successResponse);
|
|
466
|
-
const url = Url.toPath(
|
|
269
|
+
const url = kubb_kit.ast.isHttpOperationNode(node) ? kubb_kit.Url.toPath(node.path) : "";
|
|
467
270
|
const headers = [contentType ? `'Content-Type': '${contentType}'` : null].filter(Boolean);
|
|
468
271
|
const dataType = hasResponseSchema(successResponse) ? typeName : "string | number | boolean | null | object";
|
|
469
272
|
const paramType = fakerName ? typeName : dataType;
|
|
@@ -477,6 +280,7 @@ function Mock({ baseURL = "", name, fakerName, typeName, requestTypeName, node }
|
|
|
477
280
|
const requestUrl = `${baseURL}${url.replace(/([^/]):/g, "$1\\\\:")}`;
|
|
478
281
|
const urlLiteral = fakerName ? `'${requestUrl}'` : `\`${requestUrl}\``;
|
|
479
282
|
const responseBody = fakerName ? `JSON.stringify(data || ${fakerName}(data))` : "JSON.stringify(data)";
|
|
283
|
+
const headersBlock = headers.length ? `\n headers: {\n ${headers.join(", \n")}\n },` : "";
|
|
480
284
|
return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
|
|
481
285
|
name,
|
|
482
286
|
isIndexable: true,
|
|
@@ -489,10 +293,7 @@ function Mock({ baseURL = "", name, fakerName, typeName, requestTypeName, node }
|
|
|
489
293
|
if(typeof data === 'function') return data(info)
|
|
490
294
|
|
|
491
295
|
return new Response(${responseBody}, {
|
|
492
|
-
status: ${statusCode}
|
|
493
|
-
${headers.length ? ` headers: {
|
|
494
|
-
${headers.join(", \n")}
|
|
495
|
-
},` : ""}
|
|
296
|
+
status: ${statusCode},${headersBlock}
|
|
496
297
|
})
|
|
497
298
|
})`
|
|
498
299
|
})
|
|
@@ -511,6 +312,7 @@ function Response({ name, typeName, response }) {
|
|
|
511
312
|
optional: !hasResponseSchema(response)
|
|
512
313
|
})] }));
|
|
513
314
|
const responseName = `${name}Response${statusCode}`;
|
|
315
|
+
const headersBlock = headers.length ? `\n headers: {\n ${headers.join(", \n")}\n },` : "";
|
|
514
316
|
return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
|
|
515
317
|
name: responseName,
|
|
516
318
|
isIndexable: true,
|
|
@@ -521,10 +323,7 @@ function Response({ name, typeName, response }) {
|
|
|
521
323
|
params: params ?? "",
|
|
522
324
|
children: `
|
|
523
325
|
return new Response(JSON.stringify(data), {
|
|
524
|
-
status: ${statusCode}
|
|
525
|
-
${headers.length ? ` headers: {
|
|
526
|
-
${headers.join(", \n")}
|
|
527
|
-
},` : ""}
|
|
326
|
+
status: ${statusCode},${headersBlock}
|
|
528
327
|
})`
|
|
529
328
|
})
|
|
530
329
|
});
|
|
@@ -568,14 +367,13 @@ const mswGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
568
367
|
if (!pluginTs) return null;
|
|
569
368
|
const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
|
|
570
369
|
const type = {
|
|
571
|
-
file:
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
path: node.path,
|
|
370
|
+
file: resolveDependencyOperationFile({
|
|
371
|
+
cache: ctx.cache,
|
|
372
|
+
node,
|
|
373
|
+
resolver: tsResolver,
|
|
576
374
|
root,
|
|
577
375
|
output: pluginTs.options?.output ?? output,
|
|
578
|
-
group: pluginTs.options?.group
|
|
376
|
+
group: pluginTs.options?.group
|
|
579
377
|
}),
|
|
580
378
|
responseName: tsResolver.response.response(node)
|
|
581
379
|
};
|