@kubb/plugin-msw 5.0.0-beta.99 → 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 -222
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +65 -223
- package/dist/index.js.map +1 -1
- package/package.json +7 -10
package/dist/index.js
CHANGED
|
@@ -1,223 +1,49 @@
|
|
|
1
1
|
import "./rolldown-runtime-C0LytTxp.js";
|
|
2
|
-
import { Resolver, ast, createResolver, defineGenerator, definePlugin } from "kubb/kit";
|
|
2
|
+
import { Resolver, Url, ast, createResolver, defineGenerator, definePlugin } from "kubb/kit";
|
|
3
3
|
import { pluginFakerName } from "@kubb/plugin-faker";
|
|
4
4
|
import { createFunctionParameter, createFunctionParameters, functionPrinter, pluginTsName } from "@kubb/plugin-ts";
|
|
5
5
|
import { File, Function, jsxRenderer } from "kubb/jsx";
|
|
6
6
|
import { jsx, jsxs } from "kubb/jsx/jsx-runtime";
|
|
7
|
-
//#region ../../internals/
|
|
8
|
-
/**
|
|
9
|
-
* Shared implementation for camelCase and PascalCase conversion.
|
|
10
|
-
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
|
|
11
|
-
* and capitalizes each word according to `pascal`.
|
|
12
|
-
*
|
|
13
|
-
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
14
|
-
*/
|
|
15
|
-
function toCamelOrPascal(text, pascal) {
|
|
16
|
-
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) => {
|
|
17
|
-
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
18
|
-
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
19
|
-
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Converts `text` to camelCase.
|
|
23
|
-
*
|
|
24
|
-
* @example Word boundaries
|
|
25
|
-
* `camelCase('hello-world') // 'helloWorld'`
|
|
26
|
-
*
|
|
27
|
-
* @example With a prefix
|
|
28
|
-
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
29
|
-
*/
|
|
30
|
-
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
31
|
-
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
32
|
-
}
|
|
33
|
-
//#endregion
|
|
34
|
-
//#region ../../internals/utils/src/reserved.ts
|
|
35
|
-
/**
|
|
36
|
-
* JavaScript and Java reserved words.
|
|
37
|
-
* @link https://github.com/jonschlinkert/reserved/blob/master/index.js
|
|
38
|
-
*/
|
|
39
|
-
const reservedWords = /* @__PURE__ */ new Set([
|
|
40
|
-
"abstract",
|
|
41
|
-
"arguments",
|
|
42
|
-
"boolean",
|
|
43
|
-
"break",
|
|
44
|
-
"byte",
|
|
45
|
-
"case",
|
|
46
|
-
"catch",
|
|
47
|
-
"char",
|
|
48
|
-
"class",
|
|
49
|
-
"const",
|
|
50
|
-
"continue",
|
|
51
|
-
"debugger",
|
|
52
|
-
"default",
|
|
53
|
-
"delete",
|
|
54
|
-
"do",
|
|
55
|
-
"double",
|
|
56
|
-
"else",
|
|
57
|
-
"enum",
|
|
58
|
-
"eval",
|
|
59
|
-
"export",
|
|
60
|
-
"extends",
|
|
61
|
-
"false",
|
|
62
|
-
"final",
|
|
63
|
-
"finally",
|
|
64
|
-
"float",
|
|
65
|
-
"for",
|
|
66
|
-
"function",
|
|
67
|
-
"goto",
|
|
68
|
-
"if",
|
|
69
|
-
"implements",
|
|
70
|
-
"import",
|
|
71
|
-
"in",
|
|
72
|
-
"instanceof",
|
|
73
|
-
"int",
|
|
74
|
-
"interface",
|
|
75
|
-
"let",
|
|
76
|
-
"long",
|
|
77
|
-
"native",
|
|
78
|
-
"new",
|
|
79
|
-
"null",
|
|
80
|
-
"package",
|
|
81
|
-
"private",
|
|
82
|
-
"protected",
|
|
83
|
-
"public",
|
|
84
|
-
"return",
|
|
85
|
-
"short",
|
|
86
|
-
"static",
|
|
87
|
-
"super",
|
|
88
|
-
"switch",
|
|
89
|
-
"synchronized",
|
|
90
|
-
"this",
|
|
91
|
-
"throw",
|
|
92
|
-
"throws",
|
|
93
|
-
"transient",
|
|
94
|
-
"true",
|
|
95
|
-
"try",
|
|
96
|
-
"typeof",
|
|
97
|
-
"var",
|
|
98
|
-
"void",
|
|
99
|
-
"volatile",
|
|
100
|
-
"while",
|
|
101
|
-
"with",
|
|
102
|
-
"yield",
|
|
103
|
-
"Array",
|
|
104
|
-
"Date",
|
|
105
|
-
"hasOwnProperty",
|
|
106
|
-
"Infinity",
|
|
107
|
-
"isFinite",
|
|
108
|
-
"isNaN",
|
|
109
|
-
"isPrototypeOf",
|
|
110
|
-
"length",
|
|
111
|
-
"Math",
|
|
112
|
-
"name",
|
|
113
|
-
"NaN",
|
|
114
|
-
"Number",
|
|
115
|
-
"Object",
|
|
116
|
-
"prototype",
|
|
117
|
-
"String",
|
|
118
|
-
"toString",
|
|
119
|
-
"undefined",
|
|
120
|
-
"valueOf"
|
|
121
|
-
]);
|
|
7
|
+
//#region ../../internals/shared/src/operation.ts
|
|
122
8
|
/**
|
|
123
|
-
*
|
|
9
|
+
* Builds the `ResolverFileParams` every operation generator passes to
|
|
10
|
+
* `resolver.file`: a file named `name`, tagged by the operation's first
|
|
11
|
+
* tag (or `'default'`), at the operation's path. Centralizes the entry object
|
|
12
|
+
* that was repeated at dozens of call sites across the client and query plugins.
|
|
124
13
|
*
|
|
125
14
|
* @example
|
|
126
15
|
* ```ts
|
|
127
|
-
*
|
|
128
|
-
* isValidVarName('class') // false (reserved word)
|
|
129
|
-
* isValidVarName('42foo') // false (starts with digit)
|
|
16
|
+
* resolver.file(operationFileEntry(node, node.operationId), { root, output, group })
|
|
130
17
|
* ```
|
|
131
18
|
*/
|
|
132
|
-
function
|
|
133
|
-
|
|
134
|
-
|
|
19
|
+
function operationFileEntry(node, name, extname = ".ts") {
|
|
20
|
+
return {
|
|
21
|
+
name,
|
|
22
|
+
extname,
|
|
23
|
+
tag: node.tags[0] ?? "default",
|
|
24
|
+
path: node.path
|
|
25
|
+
};
|
|
135
26
|
}
|
|
136
27
|
/**
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
* deciding whether an object key needs quoting.
|
|
28
|
+
* Resolves a dependency plugin's generated file for `node.operationId`, cached in `cache` (the
|
|
29
|
+
* current node's `ctx.cache`) under the resolver's own plugin name. Several dependents reading the
|
|
30
|
+
* same dependency for the same operation in one pass (a query plugin's several hook generators, the
|
|
31
|
+
* MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.
|
|
142
32
|
*
|
|
143
|
-
* @example
|
|
33
|
+
* @example Cache `plugin-ts`'s file for the current operation
|
|
144
34
|
* ```ts
|
|
145
|
-
*
|
|
146
|
-
* isIdentifier('x-total')// false
|
|
35
|
+
* const fileTs = resolveDependencyOperationFile({ cache: ctx.cache, node, resolver: tsResolver, root, output })
|
|
147
36
|
* ```
|
|
148
37
|
*/
|
|
149
|
-
function
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
*/
|
|
158
|
-
function transformParam(raw) {
|
|
159
|
-
return isValidVarName(raw) ? raw : camelCase(raw);
|
|
38
|
+
function resolveDependencyOperationFile(options) {
|
|
39
|
+
const { cache, node, resolver, root, output, group } = options;
|
|
40
|
+
return cache.ensureItem(`${resolver.pluginName}:operationFile`, () => resolver.file({
|
|
41
|
+
...operationFileEntry(node, node.operationId),
|
|
42
|
+
root,
|
|
43
|
+
output,
|
|
44
|
+
group: group ?? void 0
|
|
45
|
+
}));
|
|
160
46
|
}
|
|
161
|
-
/**
|
|
162
|
-
* Helpers for OpenAPI/Swagger paths.
|
|
163
|
-
*/
|
|
164
|
-
var Url = class Url {
|
|
165
|
-
/**
|
|
166
|
-
* Converts an OpenAPI/Swagger path to Express-style colon syntax.
|
|
167
|
-
*
|
|
168
|
-
* @example
|
|
169
|
-
* Url.toPath('/pet/{petId}') // '/pet/:petId'
|
|
170
|
-
*/
|
|
171
|
-
static toPath(path) {
|
|
172
|
-
return path.replace(/\{([^}]+)\}/g, ":$1");
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Rewrites OpenAPI placeholder names while keeping the `{...}` braces, so the generated `url`
|
|
176
|
-
* literal aligns with the grouped `path` request option that the runtime client interpolates by
|
|
177
|
-
* key.
|
|
178
|
-
*
|
|
179
|
-
* @example
|
|
180
|
-
* Url.toSafeTemplate('/user/{monetary-account-id}') // '/user/{monetaryAccountId}'
|
|
181
|
-
*/
|
|
182
|
-
static toSafeTemplate(path) {
|
|
183
|
-
return path.replace(/\{([^}]+)\}/g, (_, name) => `{${transformParam(name)}}`);
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Converts an OpenAPI/Swagger path to a TypeScript template literal string.
|
|
187
|
-
* `prefix` is prepended inside the literal, and `replacer` transforms each parameter name.
|
|
188
|
-
*
|
|
189
|
-
* @example
|
|
190
|
-
* Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
|
|
191
|
-
*
|
|
192
|
-
* @example
|
|
193
|
-
* Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
|
|
194
|
-
*/
|
|
195
|
-
static toTemplateString(path, { prefix, replacer } = {}) {
|
|
196
|
-
const result = path.split(/\{([^}]+)\}/).map((part, i) => {
|
|
197
|
-
if (i % 2 === 0) return part;
|
|
198
|
-
const param = transformParam(part);
|
|
199
|
-
return `\${${replacer ? replacer(param) : param}}`;
|
|
200
|
-
}).join("");
|
|
201
|
-
return `\`${prefix ?? ""}${result}\``;
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the
|
|
205
|
-
* grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter
|
|
206
|
-
* names match the generated `path` type, and `prefix` is prepended inside the literal. Shared by
|
|
207
|
-
* the client and cypress generators that pass a grouped `path` object.
|
|
208
|
-
*
|
|
209
|
-
* @example
|
|
210
|
-
* Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'
|
|
211
|
-
*/
|
|
212
|
-
static toGroupedTemplateString(path, { prefix } = {}) {
|
|
213
|
-
return Url.toTemplateString(path, {
|
|
214
|
-
prefix,
|
|
215
|
-
replacer: (name) => `path.${name}`
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
//#endregion
|
|
220
|
-
//#region ../../internals/shared/src/operation.ts
|
|
221
47
|
function getStatusCodeNumber(statusCode) {
|
|
222
48
|
const code = Number(statusCode);
|
|
223
49
|
return Number.isNaN(code) ? null : code;
|
|
@@ -249,6 +75,33 @@ function resolveResponseTypes(node, resolver) {
|
|
|
249
75
|
return types;
|
|
250
76
|
}
|
|
251
77
|
//#endregion
|
|
78
|
+
//#region ../../internals/utils/src/casing.ts
|
|
79
|
+
/**
|
|
80
|
+
* Shared implementation for camelCase and PascalCase conversion.
|
|
81
|
+
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
|
|
82
|
+
* and capitalizes each word according to `pascal`.
|
|
83
|
+
*
|
|
84
|
+
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
85
|
+
*/
|
|
86
|
+
function toCamelOrPascal(text, pascal) {
|
|
87
|
+
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) => {
|
|
88
|
+
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
89
|
+
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
90
|
+
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Converts `text` to camelCase.
|
|
94
|
+
*
|
|
95
|
+
* @example Word boundaries
|
|
96
|
+
* `camelCase('hello-world') // 'helloWorld'`
|
|
97
|
+
*
|
|
98
|
+
* @example With a prefix
|
|
99
|
+
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
100
|
+
*/
|
|
101
|
+
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
102
|
+
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
252
105
|
//#region ../../internals/shared/src/group.ts
|
|
253
106
|
/**
|
|
254
107
|
* Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
|
|
@@ -383,12 +236,6 @@ function getMswMethod(node) {
|
|
|
383
236
|
return ast.isHttpOperationNode(node) ? node.method.toLowerCase() : "";
|
|
384
237
|
}
|
|
385
238
|
/**
|
|
386
|
-
* Converts an OpenAPI-style path to an Express/MSW-style path by replacing `{param}` with `:param`.
|
|
387
|
-
*/
|
|
388
|
-
function getMswUrl(node) {
|
|
389
|
-
return ast.isHttpOperationNode(node) ? node.path.replaceAll("{", ":").replaceAll("}", "") : "";
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
239
|
* Resolves faker metadata for an MSW operation, including response name and file path.
|
|
393
240
|
*/
|
|
394
241
|
function resolveFakerMeta(node, options) {
|
|
@@ -415,7 +262,7 @@ function Mock({ baseURL = "", name, fakerName, typeName, requestTypeName, node }
|
|
|
415
262
|
const successResponse = getPrimarySuccessResponse(node);
|
|
416
263
|
const statusCode = successResponse ? Number(successResponse.statusCode) : 200;
|
|
417
264
|
const contentType = getContentType(successResponse);
|
|
418
|
-
const url = Url.toPath(
|
|
265
|
+
const url = ast.isHttpOperationNode(node) ? Url.toPath(node.path) : "";
|
|
419
266
|
const headers = [contentType ? `'Content-Type': '${contentType}'` : null].filter(Boolean);
|
|
420
267
|
const dataType = hasResponseSchema(successResponse) ? typeName : "string | number | boolean | null | object";
|
|
421
268
|
const paramType = fakerName ? typeName : dataType;
|
|
@@ -429,6 +276,7 @@ function Mock({ baseURL = "", name, fakerName, typeName, requestTypeName, node }
|
|
|
429
276
|
const requestUrl = `${baseURL}${url.replace(/([^/]):/g, "$1\\\\:")}`;
|
|
430
277
|
const urlLiteral = fakerName ? `'${requestUrl}'` : `\`${requestUrl}\``;
|
|
431
278
|
const responseBody = fakerName ? `JSON.stringify(data || ${fakerName}(data))` : "JSON.stringify(data)";
|
|
279
|
+
const headersBlock = headers.length ? `\n headers: {\n ${headers.join(", \n")}\n },` : "";
|
|
432
280
|
return /* @__PURE__ */ jsx(File.Source, {
|
|
433
281
|
name,
|
|
434
282
|
isIndexable: true,
|
|
@@ -441,10 +289,7 @@ function Mock({ baseURL = "", name, fakerName, typeName, requestTypeName, node }
|
|
|
441
289
|
if(typeof data === 'function') return data(info)
|
|
442
290
|
|
|
443
291
|
return new Response(${responseBody}, {
|
|
444
|
-
status: ${statusCode}
|
|
445
|
-
${headers.length ? ` headers: {
|
|
446
|
-
${headers.join(", \n")}
|
|
447
|
-
},` : ""}
|
|
292
|
+
status: ${statusCode},${headersBlock}
|
|
448
293
|
})
|
|
449
294
|
})`
|
|
450
295
|
})
|
|
@@ -463,6 +308,7 @@ function Response({ name, typeName, response }) {
|
|
|
463
308
|
optional: !hasResponseSchema(response)
|
|
464
309
|
})] }));
|
|
465
310
|
const responseName = `${name}Response${statusCode}`;
|
|
311
|
+
const headersBlock = headers.length ? `\n headers: {\n ${headers.join(", \n")}\n },` : "";
|
|
466
312
|
return /* @__PURE__ */ jsx(File.Source, {
|
|
467
313
|
name: responseName,
|
|
468
314
|
isIndexable: true,
|
|
@@ -473,10 +319,7 @@ function Response({ name, typeName, response }) {
|
|
|
473
319
|
params: params ?? "",
|
|
474
320
|
children: `
|
|
475
321
|
return new Response(JSON.stringify(data), {
|
|
476
|
-
status: ${statusCode}
|
|
477
|
-
${headers.length ? ` headers: {
|
|
478
|
-
${headers.join(", \n")}
|
|
479
|
-
},` : ""}
|
|
322
|
+
status: ${statusCode},${headersBlock}
|
|
480
323
|
})`
|
|
481
324
|
})
|
|
482
325
|
});
|
|
@@ -520,14 +363,13 @@ const mswGenerator = defineGenerator({
|
|
|
520
363
|
if (!pluginTs) return null;
|
|
521
364
|
const tsResolver = driver.getResolver(pluginTsName);
|
|
522
365
|
const type = {
|
|
523
|
-
file:
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
path: node.path,
|
|
366
|
+
file: resolveDependencyOperationFile({
|
|
367
|
+
cache: ctx.cache,
|
|
368
|
+
node,
|
|
369
|
+
resolver: tsResolver,
|
|
528
370
|
root,
|
|
529
371
|
output: pluginTs.options?.output ?? output,
|
|
530
|
-
group: pluginTs.options?.group
|
|
372
|
+
group: pluginTs.options?.group
|
|
531
373
|
}),
|
|
532
374
|
responseName: tsResolver.response.response(node)
|
|
533
375
|
};
|