@kubb/plugin-cypress 5.1.1 → 5.1.3

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.d.cts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Exclude, Group, Include, Output, OutputOptions, Override, PluginType, Resolver, ResolverPatch, ast } from "kubb/kit";
2
2
  import { ResolverTs } from "@kubb/plugin-ts";
3
3
  import { KubbReactNode } from "kubb/jsx";
4
- //#region src/components/Request.d.ts
5
4
  type Props = {
6
5
  /**
7
6
  * Name of the function
@@ -18,8 +17,6 @@ type Props = {
18
17
  baseURL: string | null | undefined;
19
18
  };
20
19
  export declare function Request({ baseURL, name, resolver, node }: Props): KubbReactNode;
21
- //#endregion
22
- //#region src/types.d.ts
23
20
  /**
24
21
  * Resolver for Cypress that provides naming methods for test functions.
25
22
  */
@@ -73,16 +70,12 @@ declare global {
73
70
  }
74
71
  }
75
72
  }
76
- //#endregion
77
- //#region src/generators/cypressGenerator.d.ts
78
73
  /**
79
74
  * Built-in generator for `@kubb/plugin-cypress`. Emits one typed
80
75
  * `cy.request()` wrapper per OpenAPI operation, ready to call inside Cypress
81
76
  * test specs and custom commands.
82
77
  */
83
78
  export declare const cypressGenerator: import("kubb/kit").Generator<PluginCypress, unknown>;
84
- //#endregion
85
- //#region src/plugin.d.ts
86
79
  /**
87
80
  * Canonical plugin name for `@kubb/plugin-cypress`. Used for driver lookups and
88
81
  * cross-plugin dependency references.
@@ -112,8 +105,6 @@ export declare const pluginCypressName = "plugin-cypress";
112
105
  * ```
113
106
  */
114
107
  export declare const pluginCypress: import("kubb/kit").PluginFactory<PluginCypress>;
115
- //#endregion
116
- //#region src/resolvers/resolverCypress.d.ts
117
108
  /**
118
109
  * Default resolver used by `@kubb/plugin-cypress`. Decides the names and file
119
110
  * paths for every generated `cy.request()` wrapper. Functions and files use
@@ -127,6 +118,5 @@ export declare const pluginCypress: import("kubb/kit").PluginFactory<PluginCypre
127
118
  * ```
128
119
  */
129
120
  export declare const resolverCypress: import("kubb/kit").Resolver;
130
- //#endregion
131
121
  export { type PluginCypress, type ResolverCypress, pluginCypress as default };
132
122
  //# sourceMappingURL=index.d.cts.map
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Exclude, Group, Include, Output, OutputOptions, Override, PluginType, Resolver, ResolverPatch, ast } from "kubb/kit";
2
2
  import { ResolverTs } from "@kubb/plugin-ts";
3
3
  import { KubbReactNode } from "kubb/jsx";
4
- //#region src/components/Request.d.ts
5
4
  type Props = {
6
5
  /**
7
6
  * Name of the function
@@ -18,8 +17,6 @@ type Props = {
18
17
  baseURL: string | null | undefined;
19
18
  };
20
19
  export declare function Request({ baseURL, name, resolver, node }: Props): KubbReactNode;
21
- //#endregion
22
- //#region src/types.d.ts
23
20
  /**
24
21
  * Resolver for Cypress that provides naming methods for test functions.
25
22
  */
@@ -73,16 +70,12 @@ declare global {
73
70
  }
74
71
  }
75
72
  }
76
- //#endregion
77
- //#region src/generators/cypressGenerator.d.ts
78
73
  /**
79
74
  * Built-in generator for `@kubb/plugin-cypress`. Emits one typed
80
75
  * `cy.request()` wrapper per OpenAPI operation, ready to call inside Cypress
81
76
  * test specs and custom commands.
82
77
  */
83
78
  export declare const cypressGenerator: import("kubb/kit").Generator<PluginCypress, unknown>;
84
- //#endregion
85
- //#region src/plugin.d.ts
86
79
  /**
87
80
  * Canonical plugin name for `@kubb/plugin-cypress`. Used for driver lookups and
88
81
  * cross-plugin dependency references.
@@ -112,8 +105,6 @@ export declare const pluginCypressName = "plugin-cypress";
112
105
  * ```
113
106
  */
114
107
  export declare const pluginCypress: import("kubb/kit").PluginFactory<PluginCypress>;
115
- //#endregion
116
- //#region src/resolvers/resolverCypress.d.ts
117
108
  /**
118
109
  * Default resolver used by `@kubb/plugin-cypress`. Decides the names and file
119
110
  * paths for every generated `cy.request()` wrapper. Functions and files use
@@ -127,6 +118,5 @@ export declare const pluginCypress: import("kubb/kit").PluginFactory<PluginCypre
127
118
  * ```
128
119
  */
129
120
  export declare const resolverCypress: import("kubb/kit").Resolver;
130
- //#endregion
131
121
  export { type PluginCypress, type ResolverCypress, pluginCypress as default };
132
122
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,9 +1,8 @@
1
- import { Resolver, Url, addGenerator, ast, createResolver, defineExtension, defineGenerator, setMacros, setResolver } from "kubb/kit";
1
+ import { Resolver, Url, addGenerator, ast, camelCase, createResolver, defineExtension, defineGenerator, setMacros, setResolver } from "kubb/kit";
2
2
  import { File, Function, jsxRenderer } from "kubb/jsx";
3
3
  import { jsx, jsxs } from "kubb/jsx/jsx-runtime";
4
4
  import { pluginTsName } from "@kubb/plugin-ts";
5
- //#endregion
6
- //#region ../../internals/shared/src/operation.ts
5
+ // ../../internals/shared/src/operation.ts
7
6
  /**
8
7
  * Builds the `ResolverFileParams` every operation generator passes to
9
8
  * `resolver.file`: a file named `name`, tagged by the operation's first
@@ -120,8 +119,9 @@ function buildRequestParamsSignature(node, resolver, options = {}) {
120
119
  "body",
121
120
  "headers"
122
121
  ].filter((key) => groups[key]);
122
+ const optionsType = hasRequestContentTypeChoice(node) ? `Pick<${resolver.response.options(node)}, ${names.map((name) => `'${name}'`).join(" | ")}>` : resolver.response.options(node);
123
123
  return {
124
- signature: [names.length > 0 ? `{ ${names.join(", ")} }: ${resolver.response.options(node)}${isOptional ? " = {}" : ""}` : null, isConfigurable ? `config: ${buildRequestConfigType(node)} = {}` : null].filter(Boolean).join(", "),
124
+ signature: [names.length > 0 ? `{ ${names.join(", ")} }: ${optionsType}${isOptional ? " = {}" : ""}` : null, isConfigurable ? `config: ${buildRequestConfigType(node)} = {}` : null].filter(Boolean).join(", "),
125
125
  groups
126
126
  };
127
127
  }
@@ -152,6 +152,16 @@ function getOperationParameters(node) {
152
152
  operationParameterGroupsByNode.set(node, groups);
153
153
  return groups;
154
154
  }
155
+ /**
156
+ * Builds the combined `{ body, path, query, headers }` options object schema for an operation,
157
+ * referencing the already-resolved body and grouped param names. Shared by `@kubb/plugin-ts`'s
158
+ * `Options` type and `@kubb/plugin-zod`'s inferred options schema, so both printers emit the same
159
+ * shape from the same inputs. `primitive: 'object'` is a no-op for the TS printer and tells the Zod
160
+ * printer to emit `z.object(…)` rather than a record.
161
+ */
162
+ function hasRequestContentTypeChoice(node) {
163
+ return (node.requestBody?.content ?? []).filter((entry) => entry.schema).length > 1;
164
+ }
155
165
  function getStatusCodeNumber(statusCode) {
156
166
  const code = Number(statusCode);
157
167
  return Number.isNaN(code) ? null : code;
@@ -179,78 +189,198 @@ function resolveErrorNames(node, resolver) {
179
189
  function resolveStatusCodeNames(node, resolver) {
180
190
  return node.responses.map((response) => resolver.response.status(node, response.statusCode));
181
191
  }
182
- const typeNamesByResolver = /* @__PURE__ */ new WeakMap();
192
+ /**
193
+ * Lists the type names an operation's types file declares, computed once per resolver and `options` so every
194
+ * dependent reads the same list.
195
+ */
183
196
  function resolveOperationTypeNames(node, resolver, options = {}) {
184
- const cacheKey = `${node.operationId}\0${options.order ?? ""}\0${options.responseStatusNames ?? ""}\0${options.includeParams === false ? "noparams" : ""}\0${(options.exclude ?? []).join(",")}`;
185
- let byResolver = typeNamesByResolver.get(resolver);
186
- if (byResolver) {
187
- const cached = byResolver.get(cacheKey);
188
- if (cached) return cached;
189
- } else {
190
- byResolver = /* @__PURE__ */ new Map();
191
- typeNamesByResolver.set(resolver, byResolver);
192
- }
193
- const { path, query, header } = getOperationParameters(node);
194
- const responseStatusNames = options.responseStatusNames === "error" ? resolveErrorNames(node, resolver) : options.responseStatusNames === false ? [] : resolveStatusCodeNames(node, resolver);
195
- const exclude = new Set(options.exclude ?? []);
196
- const paramNames = options.includeParams === false ? [] : [
197
- ...path.map((param) => resolver.param.path(node, param)),
198
- ...query.map((param) => resolver.param.query(node, param)),
199
- ...header.map((param) => resolver.param.headers(node, param))
200
- ];
201
- const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.response.body(node) : null, resolver.response.response(node)];
202
- const result = (options.order === "body-response-first" ? [
203
- ...bodyAndResponseNames,
204
- ...paramNames,
205
- ...responseStatusNames
206
- ] : [
207
- ...paramNames,
208
- ...bodyAndResponseNames,
209
- ...responseStatusNames
210
- ]).filter((name) => Boolean(name) && !exclude.has(name));
211
- byResolver.set(cacheKey, result);
212
- return result;
197
+ const key = `${node.operationId}\0${options.order ?? ""}\0${options.responseStatusNames ?? ""}\0${options.includeParams === false ? "noparams" : ""}\0${(options.exclude ?? []).join(",")}`;
198
+ return resolver.memo(`operationTypeNames:${key}`, () => {
199
+ const { path, query, header } = getOperationParameters(node);
200
+ const responseStatusNames = options.responseStatusNames === "error" ? resolveErrorNames(node, resolver) : options.responseStatusNames === false ? [] : resolveStatusCodeNames(node, resolver);
201
+ const exclude = new Set(options.exclude ?? []);
202
+ const paramNames = options.includeParams === false ? [] : [
203
+ ...path.map((param) => resolver.param.path(node, param)),
204
+ ...query.map((param) => resolver.param.query(node, param)),
205
+ ...header.map((param) => resolver.param.headers(node, param))
206
+ ];
207
+ const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.response.body(node) : null, resolver.response.response(node)];
208
+ return (options.order === "body-response-first" ? [
209
+ ...bodyAndResponseNames,
210
+ ...paramNames,
211
+ ...responseStatusNames
212
+ ] : [
213
+ ...paramNames,
214
+ ...bodyAndResponseNames,
215
+ ...responseStatusNames
216
+ ]).filter((name) => Boolean(name) && !exclude.has(name));
217
+ });
213
218
  }
214
- //#endregion
215
- //#region ../../internals/utils/src/casing.ts
219
+ // ../../internals/utils/src/reserved.ts
216
220
  /**
217
- * Shared implementation for camelCase and PascalCase conversion.
218
- * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
219
- * and capitalizes each word according to `pascal`.
221
+ * JavaScript and Java reserved words.
222
+ * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
223
+ */
224
+ const reservedWords = /* @__PURE__ */ new Set([
225
+ "abstract",
226
+ "arguments",
227
+ "await",
228
+ "boolean",
229
+ "break",
230
+ "byte",
231
+ "case",
232
+ "catch",
233
+ "char",
234
+ "class",
235
+ "const",
236
+ "continue",
237
+ "debugger",
238
+ "default",
239
+ "delete",
240
+ "do",
241
+ "double",
242
+ "else",
243
+ "enum",
244
+ "eval",
245
+ "export",
246
+ "extends",
247
+ "false",
248
+ "final",
249
+ "finally",
250
+ "float",
251
+ "for",
252
+ "function",
253
+ "goto",
254
+ "if",
255
+ "implements",
256
+ "import",
257
+ "in",
258
+ "instanceof",
259
+ "int",
260
+ "interface",
261
+ "let",
262
+ "long",
263
+ "native",
264
+ "new",
265
+ "null",
266
+ "package",
267
+ "private",
268
+ "protected",
269
+ "public",
270
+ "return",
271
+ "short",
272
+ "static",
273
+ "super",
274
+ "switch",
275
+ "synchronized",
276
+ "this",
277
+ "throw",
278
+ "throws",
279
+ "transient",
280
+ "true",
281
+ "try",
282
+ "typeof",
283
+ "var",
284
+ "void",
285
+ "volatile",
286
+ "while",
287
+ "with",
288
+ "yield",
289
+ "Array",
290
+ "Date",
291
+ "hasOwnProperty",
292
+ "Infinity",
293
+ "isFinite",
294
+ "isNaN",
295
+ "isPrototypeOf",
296
+ "length",
297
+ "Math",
298
+ "name",
299
+ "NaN",
300
+ "Number",
301
+ "Object",
302
+ "prototype",
303
+ "String",
304
+ "toString",
305
+ "undefined",
306
+ "valueOf"
307
+ ]);
308
+ /**
309
+ * Returns `true` when `name` is a syntactically valid JavaScript variable name.
220
310
  *
221
- * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
311
+ * @example
312
+ * ```ts
313
+ * isValidVarName('status') // true
314
+ * isValidVarName('class') // false (reserved word)
315
+ * isValidVarName('42foo') // false (starts with digit)
316
+ * ```
222
317
  */
223
- function convert(text, pascal) {
224
- 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) => {
225
- if (word.length > 1 && word === word.toUpperCase()) return word;
226
- return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
227
- }).join("").replace(/[^a-zA-Z0-9]/g, "");
318
+ function isValidVarName(name) {
319
+ if (!name || reservedWords.has(name)) return false;
320
+ return isIdentifier(name);
228
321
  }
229
- const cache = /* @__PURE__ */ new Map();
230
- const cacheLimit = 1e4;
231
- function toCamelOrPascal(text, pascal) {
232
- const key = `${pascal ? "P" : "c"}${text}`;
233
- const cached = cache.get(key);
234
- if (cached !== void 0) return cached;
235
- const result = convert(text, pascal);
236
- if (cache.size >= cacheLimit) cache.clear();
237
- cache.set(key, result);
238
- return result;
322
+ /**
323
+ * Returns `name` when it's a syntactically valid JavaScript variable name,
324
+ * otherwise prefixes it with `_` so the result is a valid identifier.
325
+ *
326
+ * Useful for sanitizing OpenAPI schema names or operation IDs that start with
327
+ * a digit (e.g. `409`, `504AccountCancel`) before using them as exported
328
+ * variable, type, or function names.
329
+ *
330
+ * @example
331
+ * ```ts
332
+ * ensureValidVarName('409') // '_409'
333
+ * ensureValidVarName('504AccountCancel') // '_504AccountCancel'
334
+ * ensureValidVarName('Pet') // 'Pet'
335
+ * ensureValidVarName('class') // '_class'
336
+ * ```
337
+ */
338
+ function ensureValidVarName(name) {
339
+ if (!name || isValidVarName(name)) return name;
340
+ return `_${name}`;
239
341
  }
240
342
  /**
241
- * Converts `text` to camelCase.
343
+ * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
344
+ *
345
+ * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
346
+ * even though they are not valid variable names, so use this (not {@link isValidVarName}) when
347
+ * deciding whether an object key needs quoting.
242
348
  *
243
- * @example Word boundaries
244
- * `camelCase('hello-world') // 'helloWorld'`
349
+ * @example
350
+ * ```ts
351
+ * isIdentifier('name') // true
352
+ * isIdentifier('x-total')// false
353
+ * ```
354
+ */
355
+ function isIdentifier(name) {
356
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
357
+ }
358
+ // ../../internals/shared/src/resolver.ts
359
+ /**
360
+ * The shared top-level `name` of the operation plugins, computed once per operation name and build.
361
+ */
362
+ function resolveOperationName(name) {
363
+ return this.memo(`operation:${name}`, () => ensureValidVarName(camelCase(name)));
364
+ }
365
+ /**
366
+ * Builds the allocation key for a declaration an operation owns. `scope` names which declaration
367
+ * it is, so two of them never share an allocation even when a custom resolver gives both the same
368
+ * name. Leave `scope` empty for the operation's own declaration.
245
369
  *
246
- * @example With a prefix
247
- * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
370
+ * @example
371
+ * ```ts
372
+ * resolver.resolveName({ key: operationKey(node, 'response', 'status', 404), name })
373
+ * ```
248
374
  */
249
- function camelCase(text, { prefix = "", suffix = "" } = {}) {
250
- return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
375
+ function operationKey(node, ...scope) {
376
+ return [
377
+ "operation",
378
+ node.method,
379
+ node.path,
380
+ ...scope.map(String)
381
+ ];
251
382
  }
252
- //#endregion
253
- //#region ../../internals/shared/src/group.ts
383
+ // ../../internals/shared/src/group.ts
254
384
  /**
255
385
  * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
256
386
  * shared default naming so every plugin groups output consistently:
@@ -280,8 +410,7 @@ function createGroupConfig(group) {
280
410
  name: group.name ? group.name : defaultName
281
411
  };
282
412
  }
283
- //#endregion
284
- //#region src/components/Request.tsx
413
+ // src/components/Request.tsx
285
414
  function Request({ baseURL = "", name, resolver, node }) {
286
415
  const { signature, groups } = buildRequestParamsSignature(node, resolver, { isConfigurable: false });
287
416
  const paramsSignature = [signature, "options: Partial<Cypress.RequestOptions> = {}"].filter(Boolean).join(", ");
@@ -311,8 +440,7 @@ function Request({ baseURL = "", name, resolver, node }) {
311
440
  })
312
441
  });
313
442
  }
314
- //#endregion
315
- //#region src/generators/cypressGenerator.tsx
443
+ // src/generators/cypressGenerator.tsx
316
444
  /**
317
445
  * Built-in generator for `@kubb/plugin-cypress`. Emits one typed
318
446
  * `cy.request()` wrapper per OpenAPI operation, ready to call inside Cypress
@@ -328,8 +456,12 @@ const cypressGenerator = defineGenerator({
328
456
  const pluginTs = ctx.requirePlugin(pluginTsName);
329
457
  const tsResolver = driver.getResolver(pluginTsName);
330
458
  const importedTypeNames = [tsResolver.response.options(node), ...resolveOperationTypeNames(node, tsResolver, { includeParams: false })];
459
+ const name = resolver.name(node.operationId);
331
460
  const meta = {
332
- name: resolver.name(node.operationId),
461
+ name: resolver.resolveName({
462
+ key: operationKey(node),
463
+ name
464
+ }),
333
465
  file: resolver.file({
334
466
  name: node.operationId,
335
467
  extname: ".ts",
@@ -382,17 +514,14 @@ const cypressGenerator = defineGenerator({
382
514
  });
383
515
  }
384
516
  });
385
- //#endregion
386
- //#region kubb-extension.json
517
+ // kubb-extension.json
387
518
  var compatibility = {
388
- "kubb": ">=5.8.3",
519
+ "kubb": ">=5.14.6",
389
520
  "node": ">=22.22"
390
521
  };
391
- //#endregion
392
- //#region package.json
393
- var version = "5.1.1";
394
- //#endregion
395
- //#region src/resolvers/resolverCypress.ts
522
+ // package.json
523
+ var version = "5.1.3";
524
+ // src/resolvers/resolverCypress.ts
396
525
  /**
397
526
  * Default resolver used by `@kubb/plugin-cypress`. Decides the names and file
398
527
  * paths for every generated `cy.request()` wrapper. Functions and files use
@@ -405,9 +534,11 @@ var version = "5.1.1";
405
534
  * resolverCypress.name('list pets') // 'listPets'
406
535
  * ```
407
536
  */
408
- const resolverCypress = createResolver({ pluginName: "plugin-cypress" });
409
- //#endregion
410
- //#region src/plugin.ts
537
+ const resolverCypress = createResolver({
538
+ pluginName: "plugin-cypress",
539
+ name: resolveOperationName
540
+ });
541
+ // src/plugin.ts
411
542
  /**
412
543
  * Canonical plugin name for `@kubb/plugin-cypress`. Used for driver lookups and
413
544
  * cross-plugin dependency references.
@@ -463,7 +594,6 @@ const pluginCypress = defineExtension({
463
594
  };
464
595
  }
465
596
  });
466
- //#endregion
467
597
  export { Request, cypressGenerator, pluginCypress as default, pluginCypress, pluginCypressName, resolverCypress };
468
598
 
469
599
  //# sourceMappingURL=index.js.map