@kubb/plugin-msw 5.0.0-beta.99 → 5.0.1

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 CHANGED
@@ -8,220 +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/utils/src/casing.ts
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
- * Returns `true` when `name` is a syntactically valid JavaScript variable name.
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
- * isValidVarName('status') // true
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 isValidVarName(name) {
137
- if (!name || reservedWords.has(name)) return false;
138
- return isIdentifier(name);
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
- * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
142
- *
143
- * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
144
- * even though they are not valid variable names, so use this (not {@link isValidVarName}) when
145
- * deciding whether an object key needs quoting.
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.
146
36
  *
147
- * @example
37
+ * @example Cache `plugin-ts`'s file for the current operation
148
38
  * ```ts
149
- * isIdentifier('name') // true
150
- * isIdentifier('x-total')// false
39
+ * const fileTs = resolveDependencyOperationFile({ cache: ctx.cache, node, resolver: tsResolver, root, output })
151
40
  * ```
152
41
  */
153
- function isIdentifier(name) {
154
- return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
155
- }
156
- //#endregion
157
- //#region ../../internals/utils/src/url.ts
158
- /**
159
- * Keeps the OpenAPI parameter name as-is when it is already a valid JS identifier, and
160
- * camelCases it only enough to become one otherwise (for example a hyphenated path segment).
161
- */
162
- function transformParam(raw) {
163
- return isValidVarName(raw) ? raw : camelCase(raw);
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
+ }));
164
50
  }
165
- /**
166
- * Helpers for OpenAPI/Swagger paths.
167
- */
168
- var Url = class Url {
169
- /**
170
- * Converts an OpenAPI/Swagger path to Express-style colon syntax.
171
- *
172
- * @example
173
- * Url.toPath('/pet/{petId}') // '/pet/:petId'
174
- */
175
- static toPath(path) {
176
- return path.replace(/\{([^}]+)\}/g, ":$1");
177
- }
178
- /**
179
- * Rewrites OpenAPI placeholder names while keeping the `{...}` braces, so the generated `url`
180
- * literal aligns with the grouped `path` request option that the runtime client interpolates by
181
- * key.
182
- *
183
- * @example
184
- * Url.toSafeTemplate('/user/{monetary-account-id}') // '/user/{monetaryAccountId}'
185
- */
186
- static toSafeTemplate(path) {
187
- return path.replace(/\{([^}]+)\}/g, (_, name) => `{${transformParam(name)}}`);
188
- }
189
- /**
190
- * Converts an OpenAPI/Swagger path to a TypeScript template literal string.
191
- * `prefix` is prepended inside the literal, and `replacer` transforms each parameter name.
192
- *
193
- * @example
194
- * Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
195
- *
196
- * @example
197
- * Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
198
- */
199
- static toTemplateString(path, { prefix, replacer } = {}) {
200
- const result = path.split(/\{([^}]+)\}/).map((part, i) => {
201
- if (i % 2 === 0) return part;
202
- const param = transformParam(part);
203
- return `\${${replacer ? replacer(param) : param}}`;
204
- }).join("");
205
- return `\`${prefix ?? ""}${result}\``;
206
- }
207
- /**
208
- * Converts an OpenAPI/Swagger path to a template literal that reads each parameter off the
209
- * grouped `path` request option, e.g. `/pet/{petId}` becomes `` `/pet/${path.petId}` ``. Parameter
210
- * names match the generated `path` type, and `prefix` is prepended inside the literal. Shared by
211
- * the client and cypress generators that pass a grouped `path` object.
212
- *
213
- * @example
214
- * Url.toGroupedTemplateString('/pet/{petId}') // '`/pet/${path.petId}`'
215
- */
216
- static toGroupedTemplateString(path, { prefix } = {}) {
217
- return Url.toTemplateString(path, {
218
- prefix,
219
- replacer: (name) => `path.${name}`
220
- });
221
- }
222
- };
223
- //#endregion
224
- //#region ../../internals/shared/src/operation.ts
225
51
  function getStatusCodeNumber(statusCode) {
226
52
  const code = Number(statusCode);
227
53
  return Number.isNaN(code) ? null : code;
@@ -253,6 +79,33 @@ function resolveResponseTypes(node, resolver) {
253
79
  return types;
254
80
  }
255
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
256
109
  //#region ../../internals/shared/src/group.ts
257
110
  /**
258
111
  * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
@@ -387,12 +240,6 @@ function getMswMethod(node) {
387
240
  return kubb_kit.ast.isHttpOperationNode(node) ? node.method.toLowerCase() : "";
388
241
  }
389
242
  /**
390
- * Converts an OpenAPI-style path to an Express/MSW-style path by replacing `{param}` with `:param`.
391
- */
392
- function getMswUrl(node) {
393
- return kubb_kit.ast.isHttpOperationNode(node) ? node.path.replaceAll("{", ":").replaceAll("}", "") : "";
394
- }
395
- /**
396
243
  * Resolves faker metadata for an MSW operation, including response name and file path.
397
244
  */
398
245
  function resolveFakerMeta(node, options) {
@@ -419,7 +266,7 @@ function Mock({ baseURL = "", name, fakerName, typeName, requestTypeName, node }
419
266
  const successResponse = getPrimarySuccessResponse(node);
420
267
  const statusCode = successResponse ? Number(successResponse.statusCode) : 200;
421
268
  const contentType = getContentType(successResponse);
422
- const url = Url.toPath(getMswUrl(node));
269
+ const url = kubb_kit.ast.isHttpOperationNode(node) ? kubb_kit.Url.toPath(node.path) : "";
423
270
  const headers = [contentType ? `'Content-Type': '${contentType}'` : null].filter(Boolean);
424
271
  const dataType = hasResponseSchema(successResponse) ? typeName : "string | number | boolean | null | object";
425
272
  const paramType = fakerName ? typeName : dataType;
@@ -433,6 +280,7 @@ function Mock({ baseURL = "", name, fakerName, typeName, requestTypeName, node }
433
280
  const requestUrl = `${baseURL}${url.replace(/([^/]):/g, "$1\\\\:")}`;
434
281
  const urlLiteral = fakerName ? `'${requestUrl}'` : `\`${requestUrl}\``;
435
282
  const responseBody = fakerName ? `JSON.stringify(data || ${fakerName}(data))` : "JSON.stringify(data)";
283
+ const headersBlock = headers.length ? `\n headers: {\n ${headers.join(", \n")}\n },` : "";
436
284
  return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
437
285
  name,
438
286
  isIndexable: true,
@@ -445,10 +293,7 @@ function Mock({ baseURL = "", name, fakerName, typeName, requestTypeName, node }
445
293
  if(typeof data === 'function') return data(info)
446
294
 
447
295
  return new Response(${responseBody}, {
448
- status: ${statusCode},
449
- ${headers.length ? ` headers: {
450
- ${headers.join(", \n")}
451
- },` : ""}
296
+ status: ${statusCode},${headersBlock}
452
297
  })
453
298
  })`
454
299
  })
@@ -467,6 +312,7 @@ function Response({ name, typeName, response }) {
467
312
  optional: !hasResponseSchema(response)
468
313
  })] }));
469
314
  const responseName = `${name}Response${statusCode}`;
315
+ const headersBlock = headers.length ? `\n headers: {\n ${headers.join(", \n")}\n },` : "";
470
316
  return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
471
317
  name: responseName,
472
318
  isIndexable: true,
@@ -477,10 +323,7 @@ function Response({ name, typeName, response }) {
477
323
  params: params ?? "",
478
324
  children: `
479
325
  return new Response(JSON.stringify(data), {
480
- status: ${statusCode},
481
- ${headers.length ? ` headers: {
482
- ${headers.join(", \n")}
483
- },` : ""}
326
+ status: ${statusCode},${headersBlock}
484
327
  })`
485
328
  })
486
329
  });
@@ -524,14 +367,13 @@ const mswGenerator = (0, kubb_kit.defineGenerator)({
524
367
  if (!pluginTs) return null;
525
368
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
526
369
  const type = {
527
- file: tsResolver.file({
528
- name: node.operationId,
529
- extname: ".ts",
530
- tag: node.tags[0] ?? "default",
531
- path: node.path,
370
+ file: resolveDependencyOperationFile({
371
+ cache: ctx.cache,
372
+ node,
373
+ resolver: tsResolver,
532
374
  root,
533
375
  output: pluginTs.options?.output ?? output,
534
- group: pluginTs.options?.group ?? void 0
376
+ group: pluginTs.options?.group
535
377
  }),
536
378
  responseName: tsResolver.response.response(node)
537
379
  };