@kubb/plugin-cypress 5.0.0-beta.42 → 5.0.0-beta.64
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 +100 -157
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +10 -14
- package/dist/index.js +101 -158
- package/dist/index.js.map +1 -1
- package/package.json +8 -16
- package/extension.yaml +0 -908
- package/src/components/Request.tsx +0 -113
- package/src/generators/cypressGenerator.tsx +0 -69
- package/src/index.ts +0 -9
- package/src/plugin.ts +0 -90
- package/src/resolvers/resolverCypress.ts +0 -29
- package/src/types.ts +0 -127
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import "./chunk-C0LytTxp.js";
|
|
2
2
|
import { ast, defineGenerator, definePlugin, defineResolver } from "@kubb/core";
|
|
3
|
+
import { caseParams, createOperationParams } from "@kubb/ast/utils";
|
|
3
4
|
import { functionPrinter, pluginTsName } from "@kubb/plugin-ts";
|
|
4
|
-
import { File, Function,
|
|
5
|
+
import { File, Function, jsxRenderer } from "@kubb/renderer-jsx";
|
|
5
6
|
import { jsx, jsxs } from "@kubb/renderer-jsx/jsx-runtime";
|
|
6
7
|
//#region ../../internals/utils/src/casing.ts
|
|
7
8
|
/**
|
|
@@ -14,36 +15,45 @@ import { jsx, jsxs } from "@kubb/renderer-jsx/jsx-runtime";
|
|
|
14
15
|
function toCamelOrPascal(text, pascal) {
|
|
15
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) => {
|
|
16
17
|
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
17
|
-
|
|
18
|
-
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
18
|
+
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
19
19
|
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* Converts `text` to camelCase.
|
|
23
|
+
*
|
|
24
|
+
* @example Word boundaries
|
|
25
|
+
* `camelCase('hello-world') // 'helloWorld'`
|
|
25
26
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
27
|
+
* @example With a prefix
|
|
28
|
+
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
28
29
|
*/
|
|
29
|
-
function
|
|
30
|
-
|
|
31
|
-
return parts.map((part, i) => transformPart(part, i === parts.length - 1)).join("/");
|
|
30
|
+
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
31
|
+
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
32
32
|
}
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region ../../internals/utils/src/fs.ts
|
|
33
35
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
+
* Builds a nested file path from a dotted name. Splits on dots that precede a letter
|
|
37
|
+
* (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
|
|
38
|
+
* every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
|
|
36
39
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
+
* Empty segments are dropped before joining. They arise when the name starts with a dot
|
|
41
|
+
* followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
|
|
42
|
+
* an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
|
|
43
|
+
* absolute path, letting generated files escape the configured output directory.
|
|
44
|
+
*
|
|
45
|
+
* @example Nested path from a dotted name
|
|
46
|
+
* `toFilePath('pet.petId') // 'pet/petId'`
|
|
47
|
+
*
|
|
48
|
+
* @example PascalCase the final segment
|
|
49
|
+
* `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
|
|
50
|
+
*
|
|
51
|
+
* @example Suffix applied to the final segment only
|
|
52
|
+
* `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
|
|
40
53
|
*/
|
|
41
|
-
function
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
suffix
|
|
45
|
-
} : {}));
|
|
46
|
-
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
54
|
+
function toFilePath(name, caseLast = camelCase) {
|
|
55
|
+
const parts = name.split(/\.(?=[a-zA-Z])/);
|
|
56
|
+
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
|
|
47
57
|
}
|
|
48
58
|
//#endregion
|
|
49
59
|
//#region ../../internals/utils/src/reserved.ts
|
|
@@ -149,99 +159,80 @@ function isValidVarName(name) {
|
|
|
149
159
|
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
150
160
|
}
|
|
151
161
|
//#endregion
|
|
152
|
-
//#region ../../internals/utils/src/
|
|
162
|
+
//#region ../../internals/utils/src/url.ts
|
|
163
|
+
function transformParam(raw, casing) {
|
|
164
|
+
const param = isValidVarName(raw) ? raw : camelCase(raw);
|
|
165
|
+
return casing === "camelcase" ? camelCase(param) : param;
|
|
166
|
+
}
|
|
167
|
+
function toParamsObject(path, { replacer, casing } = {}) {
|
|
168
|
+
const params = {};
|
|
169
|
+
for (const match of path.matchAll(/\{([^}]+)\}/g)) {
|
|
170
|
+
const param = transformParam(match[1], casing);
|
|
171
|
+
const key = replacer ? replacer(param) : param;
|
|
172
|
+
params[key] = key;
|
|
173
|
+
}
|
|
174
|
+
return Object.keys(params).length > 0 ? params : null;
|
|
175
|
+
}
|
|
153
176
|
/**
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
* @example
|
|
157
|
-
* const p = new URLPath('/pet/{petId}')
|
|
158
|
-
* p.URL // '/pet/:petId'
|
|
159
|
-
* p.template // '`/pet/${petId}`'
|
|
177
|
+
* Helpers for OpenAPI/Swagger paths, plus a thin wrapper over the native `URL`.
|
|
160
178
|
*/
|
|
161
|
-
var
|
|
179
|
+
var Url = class Url {
|
|
162
180
|
/**
|
|
163
|
-
*
|
|
164
|
-
*/
|
|
165
|
-
path;
|
|
166
|
-
#options;
|
|
167
|
-
constructor(path, options = {}) {
|
|
168
|
-
this.path = path;
|
|
169
|
-
this.#options = options;
|
|
170
|
-
}
|
|
171
|
-
/** Converts the OpenAPI path to Express-style colon syntax, e.g. `/pet/{petId}` → `/pet/:petId`.
|
|
181
|
+
* Reports whether `url` is a parseable absolute URL. Delegates to the native `URL.canParse`.
|
|
172
182
|
*
|
|
173
183
|
* @example
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
* ```
|
|
184
|
+
* Url.canParse('https://petstore.swagger.io/v2') // true
|
|
185
|
+
* Url.canParse('/pet/{petId}') // false
|
|
177
186
|
*/
|
|
178
|
-
|
|
179
|
-
return
|
|
187
|
+
static canParse(url, base) {
|
|
188
|
+
return URL.canParse(url, base);
|
|
180
189
|
}
|
|
181
|
-
/**
|
|
190
|
+
/**
|
|
191
|
+
* Converts an OpenAPI/Swagger path to Express-style colon syntax.
|
|
182
192
|
*
|
|
183
193
|
* @example
|
|
184
|
-
*
|
|
185
|
-
* new URLPath('https://petstore.swagger.io/v2/pet').isURL // true
|
|
186
|
-
* new URLPath('/pet/{petId}').isURL // false
|
|
187
|
-
* ```
|
|
194
|
+
* Url.toPath('/pet/{petId}') // '/pet/:petId'
|
|
188
195
|
*/
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
return !!new URL(this.path).href;
|
|
192
|
-
} catch {
|
|
193
|
-
return false;
|
|
194
|
-
}
|
|
196
|
+
static toPath(path) {
|
|
197
|
+
return path.replace(/\{([^}]+)\}/g, ":$1");
|
|
195
198
|
}
|
|
196
199
|
/**
|
|
197
|
-
* Converts
|
|
200
|
+
* Converts an OpenAPI/Swagger path to a TypeScript template literal string.
|
|
201
|
+
* `prefix` is prepended inside the literal, `replacer` transforms each parameter name,
|
|
202
|
+
* and `casing` controls parameter identifier casing.
|
|
198
203
|
*
|
|
199
204
|
* @example
|
|
200
|
-
*
|
|
201
|
-
* new URLPath('/account/monetary-accountID').template // '`/account/${monetaryAccountId}`'
|
|
202
|
-
*/
|
|
203
|
-
get template() {
|
|
204
|
-
return this.toTemplateString();
|
|
205
|
-
}
|
|
206
|
-
/** Returns the path and its extracted params as a structured `URLObject`, or as a stringified expression when `stringify` is set.
|
|
205
|
+
* Url.toTemplateString('/pet/{petId}') // '`/pet/${petId}`'
|
|
207
206
|
*
|
|
208
207
|
* @example
|
|
209
|
-
*
|
|
210
|
-
* new URLPath('/pet/{petId}').object
|
|
211
|
-
* // { url: '/pet/:petId', params: { petId: 'petId' } }
|
|
212
|
-
* ```
|
|
208
|
+
* Url.toTemplateString('/pet/{petId}', { prefix: 'https://api' }) // '`https://api/pet/${petId}`'
|
|
213
209
|
*/
|
|
214
|
-
|
|
215
|
-
|
|
210
|
+
static toTemplateString(path, { prefix, replacer, casing } = {}) {
|
|
211
|
+
const result = path.split(/\{([^}]+)\}/).map((part, i) => {
|
|
212
|
+
if (i % 2 === 0) return part;
|
|
213
|
+
const param = transformParam(part, casing);
|
|
214
|
+
return `\${${replacer ? replacer(param) : param}}`;
|
|
215
|
+
}).join("");
|
|
216
|
+
return `\`${prefix ?? ""}${result}\``;
|
|
216
217
|
}
|
|
217
|
-
/**
|
|
218
|
+
/**
|
|
219
|
+
* Returns the path and its extracted params as a structured `URLObject`, or as a stringified
|
|
220
|
+
* expression when `stringify` is set.
|
|
218
221
|
*
|
|
219
222
|
* @example
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
* new URLPath('/pet').params // null
|
|
223
|
-
* ```
|
|
224
|
-
*/
|
|
225
|
-
get params() {
|
|
226
|
-
return this.toParamsObject();
|
|
227
|
-
}
|
|
228
|
-
#transformParam(raw) {
|
|
229
|
-
const param = isValidVarName(raw) ? raw : camelCase(raw);
|
|
230
|
-
return this.#options.casing === "camelcase" ? camelCase(param) : param;
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Iterates over every `{param}` token in `path`, calling `fn` with the raw token and transformed name.
|
|
223
|
+
* Url.toObject('/pet/{petId}')
|
|
224
|
+
* // { url: '/pet/:petId', params: { petId: 'petId' } }
|
|
234
225
|
*/
|
|
235
|
-
|
|
236
|
-
for (const match of this.path.matchAll(/\{([^}]+)\}/g)) {
|
|
237
|
-
const raw = match[1];
|
|
238
|
-
fn(raw, this.#transformParam(raw));
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
toObject({ type = "path", replacer, stringify } = {}) {
|
|
226
|
+
static toObject(path, { type = "path", replacer, stringify, casing } = {}) {
|
|
242
227
|
const object = {
|
|
243
|
-
url: type === "path" ?
|
|
244
|
-
|
|
228
|
+
url: type === "path" ? Url.toPath(path) : Url.toTemplateString(path, {
|
|
229
|
+
replacer,
|
|
230
|
+
casing
|
|
231
|
+
}),
|
|
232
|
+
params: toParamsObject(path, {
|
|
233
|
+
replacer,
|
|
234
|
+
casing
|
|
235
|
+
})
|
|
245
236
|
};
|
|
246
237
|
if (stringify) {
|
|
247
238
|
if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
|
|
@@ -250,55 +241,11 @@ var URLPath = class {
|
|
|
250
241
|
}
|
|
251
242
|
return object;
|
|
252
243
|
}
|
|
253
|
-
/**
|
|
254
|
-
* Converts the OpenAPI path to a TypeScript template literal string.
|
|
255
|
-
* An optional `replacer` can transform each extracted parameter name before interpolation.
|
|
256
|
-
*
|
|
257
|
-
* @example
|
|
258
|
-
* new URLPath('/pet/{petId}').toTemplateString() // '`/pet/${petId}`'
|
|
259
|
-
*/
|
|
260
|
-
toTemplateString({ prefix, replacer } = {}) {
|
|
261
|
-
const result = this.path.split(/\{([^}]+)\}/).map((part, i) => {
|
|
262
|
-
if (i % 2 === 0) return part;
|
|
263
|
-
const param = this.#transformParam(part);
|
|
264
|
-
return `\${${replacer ? replacer(param) : param}}`;
|
|
265
|
-
}).join("");
|
|
266
|
-
return `\`${prefix ?? ""}${result}\``;
|
|
267
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* Extracts all `{param}` segments from the path and returns them as a key-value map.
|
|
270
|
-
* An optional `replacer` transforms each parameter name in both key and value positions.
|
|
271
|
-
* Returns `undefined` when no path parameters are found.
|
|
272
|
-
*
|
|
273
|
-
* @example
|
|
274
|
-
* ```ts
|
|
275
|
-
* new URLPath('/pet/{petId}/tag/{tagId}').toParamsObject()
|
|
276
|
-
* // { petId: 'petId', tagId: 'tagId' }
|
|
277
|
-
* ```
|
|
278
|
-
*/
|
|
279
|
-
toParamsObject(replacer) {
|
|
280
|
-
const params = {};
|
|
281
|
-
this.#eachParam((_raw, param) => {
|
|
282
|
-
const key = replacer ? replacer(param) : param;
|
|
283
|
-
params[key] = key;
|
|
284
|
-
});
|
|
285
|
-
return Object.keys(params).length > 0 ? params : null;
|
|
286
|
-
}
|
|
287
|
-
/** Converts the OpenAPI path to Express-style colon syntax.
|
|
288
|
-
*
|
|
289
|
-
* @example
|
|
290
|
-
* ```ts
|
|
291
|
-
* new URLPath('/pet/{petId}').toURLPath() // '/pet/:petId'
|
|
292
|
-
* ```
|
|
293
|
-
*/
|
|
294
|
-
toURLPath() {
|
|
295
|
-
return this.path.replace(/\{([^}]+)\}/g, ":$1");
|
|
296
|
-
}
|
|
297
244
|
};
|
|
298
245
|
//#endregion
|
|
299
246
|
//#region ../../internals/shared/src/operation.ts
|
|
300
247
|
function getOperationParameters(node, options = {}) {
|
|
301
|
-
const params =
|
|
248
|
+
const params = caseParams(node.parameters, options.paramsCasing);
|
|
302
249
|
return {
|
|
303
250
|
path: params.filter((param) => param.in === "path"),
|
|
304
251
|
query: params.filter((param) => param.in === "query"),
|
|
@@ -359,26 +306,24 @@ function resolveOperationTypeNames(node, resolver, options = {}) {
|
|
|
359
306
|
* shared default naming so every plugin groups output consistently:
|
|
360
307
|
*
|
|
361
308
|
* - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
|
|
362
|
-
* - other groups use
|
|
309
|
+
* - other groups use the camelCased group (`pet store` → `petStore`).
|
|
363
310
|
*
|
|
364
311
|
* A user-provided `group.name` always wins over the default namer, so callers stay in
|
|
365
312
|
* control of their output folders. Returns `null` when grouping is disabled, matching the
|
|
366
313
|
* per-plugin convention.
|
|
367
314
|
*
|
|
368
315
|
* @param group - The user-supplied group option, or `undefined` to disable grouping.
|
|
369
|
-
* @param options.suffix - Appended to non-`path` group names, e.g. `'Controller'` or `'Requests'`.
|
|
370
316
|
*
|
|
371
317
|
* @example
|
|
372
318
|
* ```ts
|
|
373
|
-
* createGroupConfig(group
|
|
374
|
-
* createGroupConfig(group, { suffix: 'Requests' }) // plugin-cypress, plugin-mcp
|
|
319
|
+
* createGroupConfig(group) // shared across every plugin
|
|
375
320
|
* ```
|
|
376
321
|
*/
|
|
377
|
-
function createGroupConfig(group
|
|
322
|
+
function createGroupConfig(group) {
|
|
378
323
|
if (!group) return null;
|
|
379
324
|
const defaultName = (ctx) => {
|
|
380
325
|
if (group.type === "path") return `${ctx.group.split("/")[1]}`;
|
|
381
|
-
return
|
|
326
|
+
return camelCase(ctx.group);
|
|
382
327
|
};
|
|
383
328
|
return {
|
|
384
329
|
...group,
|
|
@@ -390,17 +335,14 @@ function createGroupConfig(group, options) {
|
|
|
390
335
|
const declarationPrinter = functionPrinter({ mode: "declaration" });
|
|
391
336
|
function Request({ baseURL = "", name, dataReturnType, resolver, node, paramsType, pathParamsType, paramsCasing }) {
|
|
392
337
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
393
|
-
const paramsNode =
|
|
338
|
+
const paramsNode = createOperationParams(node, {
|
|
394
339
|
paramsType,
|
|
395
340
|
pathParamsType,
|
|
396
341
|
paramsCasing,
|
|
397
342
|
resolver,
|
|
398
|
-
extraParams: [ast.createFunctionParameter({
|
|
343
|
+
extraParams: [ast.factory.createFunctionParameter({
|
|
399
344
|
name: "options",
|
|
400
|
-
type:
|
|
401
|
-
variant: "reference",
|
|
402
|
-
name: "Partial<Cypress.RequestOptions>"
|
|
403
|
-
}),
|
|
345
|
+
type: "Partial<Cypress.RequestOptions>",
|
|
404
346
|
default: "{}"
|
|
405
347
|
})]
|
|
406
348
|
});
|
|
@@ -409,9 +351,10 @@ function Request({ baseURL = "", name, dataReturnType, resolver, node, paramsTyp
|
|
|
409
351
|
const returnType = dataReturnType === "data" ? `Cypress.Chainable<${responseType}>` : `Cypress.Chainable<Cypress.Response<${responseType}>>`;
|
|
410
352
|
const casedPathParams = getOperationParameters(node, { paramsCasing }).path;
|
|
411
353
|
const pathParamNameMap = new Map(casedPathParams.map((p) => [camelCase(p.name), p.name]));
|
|
412
|
-
const urlTemplate =
|
|
354
|
+
const urlTemplate = Url.toTemplateString(node.path, {
|
|
413
355
|
prefix: baseURL,
|
|
414
|
-
replacer: (param) => pathParamNameMap.get(camelCase(param)) ?? param
|
|
356
|
+
replacer: (param) => pathParamNameMap.get(camelCase(param)) ?? param,
|
|
357
|
+
casing: paramsCasing
|
|
415
358
|
});
|
|
416
359
|
const requestOptions = [`method: '${node.method}'`, `url: ${urlTemplate}`];
|
|
417
360
|
const queryParams = getOperationParameters(node).query;
|
|
@@ -458,7 +401,7 @@ function Request({ baseURL = "", name, dataReturnType, resolver, node, paramsTyp
|
|
|
458
401
|
*/
|
|
459
402
|
const cypressGenerator = defineGenerator({
|
|
460
403
|
name: "cypress",
|
|
461
|
-
renderer:
|
|
404
|
+
renderer: jsxRenderer,
|
|
462
405
|
operation(node, ctx) {
|
|
463
406
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
464
407
|
const { config, resolver, driver, root } = ctx;
|
|
@@ -546,7 +489,7 @@ const resolverCypress = defineResolver(() => ({
|
|
|
546
489
|
name: "default",
|
|
547
490
|
pluginName: "plugin-cypress",
|
|
548
491
|
default(name, type) {
|
|
549
|
-
return
|
|
492
|
+
return type === "file" ? toFilePath(name) : camelCase(name);
|
|
550
493
|
},
|
|
551
494
|
resolveName(name) {
|
|
552
495
|
return this.default(name, "function");
|
|
@@ -588,9 +531,9 @@ const pluginCypressName = "plugin-cypress";
|
|
|
588
531
|
const pluginCypress = definePlugin((options) => {
|
|
589
532
|
const { output = {
|
|
590
533
|
path: "cypress",
|
|
591
|
-
|
|
592
|
-
}, group, exclude = [], include, override = [], dataReturnType = "data", baseURL, paramsCasing, paramsType = "inline", pathParamsType = paramsType === "object" ? "object" : options.pathParamsType || "inline", resolver: userResolver,
|
|
593
|
-
const groupConfig = createGroupConfig(group
|
|
534
|
+
barrel: { type: "named" }
|
|
535
|
+
}, group, exclude = [], include, override = [], dataReturnType = "data", baseURL, paramsCasing, paramsType = "inline", pathParamsType = paramsType === "object" ? "object" : options.pathParamsType || "inline", resolver: userResolver, macros: userMacros, generators: userGenerators = [] } = options;
|
|
536
|
+
const groupConfig = createGroupConfig(group);
|
|
594
537
|
return {
|
|
595
538
|
name: pluginCypressName,
|
|
596
539
|
options,
|
|
@@ -614,7 +557,7 @@ const pluginCypress = definePlugin((options) => {
|
|
|
614
557
|
resolver
|
|
615
558
|
});
|
|
616
559
|
ctx.setResolver(resolver);
|
|
617
|
-
if (
|
|
560
|
+
if (userMacros?.length) ctx.setMacros(userMacros);
|
|
618
561
|
ctx.addGenerator(cypressGenerator);
|
|
619
562
|
for (const gen of userGenerators) ctx.addGenerator(gen);
|
|
620
563
|
} }
|