@kubb/plugin-faker 5.0.0-beta.84 → 5.0.0-beta.86
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 +495 -372
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +69 -110
- package/dist/index.js +494 -349
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,10 +1,379 @@
|
|
|
1
1
|
import "./rolldown-runtime-C0LytTxp.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { posix } from "node:path";
|
|
3
|
+
import { Resolver, ast, createResolver, defineGenerator, definePlugin } from "kubb/kit";
|
|
4
|
+
import { buildParams, createFunctionParameter, createFunctionParameters, functionPrinter, pluginTsName } from "@kubb/plugin-ts";
|
|
4
5
|
import { File, Function, jsxRenderer } from "kubb/jsx";
|
|
5
|
-
import path, { posix } from "node:path";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "kubb/jsx/jsx-runtime";
|
|
7
|
-
|
|
7
|
+
//#region ../../internals/utils/src/casing.ts
|
|
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
|
+
]);
|
|
122
|
+
/**
|
|
123
|
+
* Returns `true` when `name` is a syntactically valid JavaScript variable name.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* isValidVarName('status') // true
|
|
128
|
+
* isValidVarName('class') // false (reserved word)
|
|
129
|
+
* isValidVarName('42foo') // false (starts with digit)
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
function isValidVarName(name) {
|
|
133
|
+
if (!name || reservedWords.has(name)) return false;
|
|
134
|
+
return isIdentifier(name);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Returns `name` when it's a syntactically valid JavaScript variable name,
|
|
138
|
+
* otherwise prefixes it with `_` so the result is a valid identifier.
|
|
139
|
+
*
|
|
140
|
+
* Useful for sanitizing OpenAPI schema names or operation IDs that start with
|
|
141
|
+
* a digit (e.g. `409`, `504AccountCancel`) before using them as exported
|
|
142
|
+
* variable, type, or function names.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```ts
|
|
146
|
+
* ensureValidVarName('409') // '_409'
|
|
147
|
+
* ensureValidVarName('504AccountCancel') // '_504AccountCancel'
|
|
148
|
+
* ensureValidVarName('Pet') // 'Pet'
|
|
149
|
+
* ensureValidVarName('class') // '_class'
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
function ensureValidVarName(name) {
|
|
153
|
+
if (!name || isValidVarName(name)) return name;
|
|
154
|
+
return `_${name}`;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
|
|
158
|
+
*
|
|
159
|
+
* Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
|
|
160
|
+
* even though they are not valid variable names, so use this (not {@link isValidVarName}) when
|
|
161
|
+
* deciding whether an object key needs quoting.
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```ts
|
|
165
|
+
* isIdentifier('name') // true
|
|
166
|
+
* isIdentifier('x-total')// false
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
function isIdentifier(name) {
|
|
170
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
171
|
+
}
|
|
172
|
+
//#endregion
|
|
173
|
+
//#region ../../internals/utils/src/strings.ts
|
|
174
|
+
/**
|
|
175
|
+
* Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping
|
|
176
|
+
* any backslash or single quote in the content.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```ts
|
|
180
|
+
* singleQuote('foo') // "'foo'"
|
|
181
|
+
* singleQuote("o'clock") // "'o\\'clock'"
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
function singleQuote(value) {
|
|
185
|
+
if (value === void 0 || value === null) return "''";
|
|
186
|
+
return `'${String(value).replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`.
|
|
190
|
+
* Returns the string unchanged when no balanced quote pair is found.
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```ts
|
|
194
|
+
* trimQuotes('"hello"') // 'hello'
|
|
195
|
+
* trimQuotes('hello') // 'hello'
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
function trimQuotes(text) {
|
|
199
|
+
if (text.length >= 2) {
|
|
200
|
+
const first = text[0];
|
|
201
|
+
const last = text[text.length - 1];
|
|
202
|
+
if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1);
|
|
203
|
+
}
|
|
204
|
+
return text;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Serializes a primitive to a single-quoted string literal, stripping any surrounding quotes first.
|
|
208
|
+
*
|
|
209
|
+
* Escaping runs through `JSON.stringify`, then the result switches to single quotes so the generated
|
|
210
|
+
* code matches the repo style without a formatter.
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```ts
|
|
214
|
+
* stringify('hello') // "'hello'"
|
|
215
|
+
* stringify('"hello"') // "'hello'"
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
function stringify(value) {
|
|
219
|
+
if (value === void 0 || value === null) return "''";
|
|
220
|
+
return `'${JSON.stringify(trimQuotes(value.toString())).slice(1, -1).replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Escapes characters that are not allowed inside JS string literals, covering quotes, backslashes,
|
|
224
|
+
* and the Unicode line terminators U+2028 and U+2029.
|
|
225
|
+
*
|
|
226
|
+
* @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* ```ts
|
|
230
|
+
* jsStringEscape('say "hi"\nbye') // 'say \\"hi\\"\\nbye'
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
function jsStringEscape(input) {
|
|
234
|
+
return `${input}`.replace(/["'\\\n\r\u2028\u2029]/g, (character) => {
|
|
235
|
+
switch (character) {
|
|
236
|
+
case "\"":
|
|
237
|
+
case "'":
|
|
238
|
+
case "\\": return `\\${character}`;
|
|
239
|
+
case "\n": return "\\n";
|
|
240
|
+
case "\r": return "\\r";
|
|
241
|
+
case "\u2028": return "\\u2028";
|
|
242
|
+
case "\u2029": return "\\u2029";
|
|
243
|
+
default: return "";
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.
|
|
249
|
+
* Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression.
|
|
250
|
+
* Pass `null` as the second argument to emit a `/pattern/flags` literal instead.
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```ts
|
|
254
|
+
* toRegExpString('^(?im)foo') // 'new RegExp("^foo", "im")'
|
|
255
|
+
* toRegExpString('^(?im)foo', null) // '/^foo/im'
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
function toRegExpString(text, func = "RegExp") {
|
|
259
|
+
const raw = trimQuotes(text);
|
|
260
|
+
const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i);
|
|
261
|
+
const replacementTarget = match?.[1] ?? "";
|
|
262
|
+
const matchedFlags = match?.[2];
|
|
263
|
+
const cleaned = raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, "");
|
|
264
|
+
const { source, flags } = new RegExp(cleaned, matchedFlags);
|
|
265
|
+
if (func === null) return `/${source}/${flags}`;
|
|
266
|
+
return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`;
|
|
267
|
+
}
|
|
268
|
+
//#endregion
|
|
269
|
+
//#region ../../internals/utils/src/codegen.ts
|
|
270
|
+
const INDENT = " ";
|
|
271
|
+
/**
|
|
272
|
+
* Indents every non-empty line of `text` by one indent level, leaving blank lines empty.
|
|
273
|
+
*/
|
|
274
|
+
function indentLines(text) {
|
|
275
|
+
if (!text) return "";
|
|
276
|
+
return text.split("\n").map((line) => line.trim() ? `${INDENT}${line}` : "").join("\n");
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Renders an object key, quoting it with single quotes only when it is not a valid identifier.
|
|
280
|
+
* Reserved words and globals (`name`, `class`, …) are valid bare keys and stay unquoted.
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```ts
|
|
284
|
+
* objectKey('name') // 'name'
|
|
285
|
+
* objectKey('x-total') // "'x-total'"
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
288
|
+
function objectKey(name) {
|
|
289
|
+
return isIdentifier(name) ? name : singleQuote(name);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one
|
|
293
|
+
* level and closing the brace at column zero. Entries that are themselves multi-line objects indent
|
|
294
|
+
* cumulatively. Each entry ends with a trailing comma to match the formatter's multi-line style.
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* ```ts
|
|
298
|
+
* buildObject(['id: z.number()', 'name: z.string()'])
|
|
299
|
+
* // '{\n id: z.number(),\n name: z.string(),\n}'
|
|
300
|
+
* ```
|
|
301
|
+
*/
|
|
302
|
+
function buildObject(entries) {
|
|
303
|
+
if (entries.length === 0) return "{}";
|
|
304
|
+
return `{\n${entries.map((entry) => `${indentLines(entry)},`).join("\n")}\n}`;
|
|
305
|
+
}
|
|
306
|
+
//#endregion
|
|
307
|
+
//#region ../../internals/utils/src/fs.ts
|
|
308
|
+
/**
|
|
309
|
+
* Builds a nested file path from a dotted name. Splits on dots that precede a letter
|
|
310
|
+
* (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
|
|
311
|
+
* every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
|
|
312
|
+
*
|
|
313
|
+
* Empty segments are dropped before joining. They arise when the name starts with a dot
|
|
314
|
+
* followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
|
|
315
|
+
* an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
|
|
316
|
+
* absolute path, letting generated files escape the configured output directory.
|
|
317
|
+
*
|
|
318
|
+
* @example Nested path from a dotted name
|
|
319
|
+
* `toFilePath('pet.petId') // 'pet/petId'`
|
|
320
|
+
*
|
|
321
|
+
* @example PascalCase the final segment
|
|
322
|
+
* `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
|
|
323
|
+
*
|
|
324
|
+
* @example Suffix applied to the final segment only
|
|
325
|
+
* `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
|
|
326
|
+
*/
|
|
327
|
+
function toFilePath(name, caseLast = camelCase) {
|
|
328
|
+
const parts = name.split(/\.(?=[a-zA-Z])/);
|
|
329
|
+
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
|
|
330
|
+
}
|
|
331
|
+
//#endregion
|
|
332
|
+
//#region ../../internals/utils/src/imports.ts
|
|
333
|
+
function escapeRegExp(value) {
|
|
334
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
335
|
+
}
|
|
336
|
+
function getImportNames(entry) {
|
|
337
|
+
return (Array.isArray(entry.name) ? entry.name : [entry.name]).map((name) => {
|
|
338
|
+
if (typeof name === "string") return name;
|
|
339
|
+
return name.name ?? name.propertyName;
|
|
340
|
+
}).filter((name) => Boolean(name));
|
|
341
|
+
}
|
|
342
|
+
function filterUsedImports(imports, text, skipImportNames = []) {
|
|
343
|
+
const skip = new Set(skipImportNames);
|
|
344
|
+
return imports.filter((entry) => {
|
|
345
|
+
return getImportNames(entry).some((name) => {
|
|
346
|
+
if (skip.has(name)) return false;
|
|
347
|
+
return new RegExp(`\\b${escapeRegExp(name)}\\b(?=\\s*\\()`).test(text);
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
function aliasConflictingImports(imports, reservedNames) {
|
|
352
|
+
const reservedNameSet = new Set(reservedNames);
|
|
353
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
354
|
+
return {
|
|
355
|
+
imports: imports.map((entry) => {
|
|
356
|
+
const aliasedNames = (Array.isArray(entry.name) ? entry.name : [entry.name]).map((item) => {
|
|
357
|
+
if (typeof item !== "string" || !reservedNameSet.has(item)) return item;
|
|
358
|
+
const alias = `${item}Schema`;
|
|
359
|
+
aliases.set(item, alias);
|
|
360
|
+
return {
|
|
361
|
+
propertyName: item,
|
|
362
|
+
name: alias
|
|
363
|
+
};
|
|
364
|
+
});
|
|
365
|
+
return aliasedNames.some((item) => typeof item === "object" && item.name) ? {
|
|
366
|
+
...entry,
|
|
367
|
+
name: aliasedNames
|
|
368
|
+
} : entry;
|
|
369
|
+
}),
|
|
370
|
+
aliases
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
function rewriteAliasedImports(text, aliases) {
|
|
374
|
+
return Array.from(aliases).reduce((acc, [name, alias]) => acc.replace(new RegExp(`\\b${escapeRegExp(name)}\\b`, "g"), alias), text);
|
|
375
|
+
}
|
|
376
|
+
//#endregion
|
|
8
377
|
//#region src/utils.ts
|
|
9
378
|
/**
|
|
10
379
|
* Returns the `@faker-js/faker` named export for a locale code.
|
|
@@ -53,17 +422,6 @@ function canOverrideSchema(node) {
|
|
|
53
422
|
"blob"
|
|
54
423
|
])).has(node.type);
|
|
55
424
|
}
|
|
56
|
-
/**
|
|
57
|
-
* Resolves a parameter name based on its location (path, query, header, etc.) using the provided resolver.
|
|
58
|
-
*/
|
|
59
|
-
function resolveParamNameByLocation(resolver, node, param) {
|
|
60
|
-
switch (param.in) {
|
|
61
|
-
case "path": return resolver.resolvePathParamsName(node, param);
|
|
62
|
-
case "query": return resolver.resolveQueryParamsName(node, param);
|
|
63
|
-
case "header": return resolver.resolveHeaderParamsName(node, param);
|
|
64
|
-
default: return resolver.resolveParamName(node, param);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
425
|
function shouldInlineSingleResponseSchema(schema) {
|
|
68
426
|
return (/* @__PURE__ */ new Set([
|
|
69
427
|
"any",
|
|
@@ -100,14 +458,14 @@ function buildResponseUnionSchema(node, resolver) {
|
|
|
100
458
|
if (schema && shouldInlineSingleResponseSchema(schema)) return schema;
|
|
101
459
|
return ast.factory.createSchema({
|
|
102
460
|
type: "ref",
|
|
103
|
-
name: resolver.
|
|
461
|
+
name: resolver.response.status(node, responses[0].statusCode)
|
|
104
462
|
});
|
|
105
463
|
}
|
|
106
464
|
return ast.factory.createSchema({
|
|
107
465
|
type: "union",
|
|
108
466
|
members: responses.map((response) => ast.factory.createSchema({
|
|
109
467
|
type: "ref",
|
|
110
|
-
name: resolver.
|
|
468
|
+
name: resolver.response.status(node, response.statusCode)
|
|
111
469
|
}))
|
|
112
470
|
});
|
|
113
471
|
}
|
|
@@ -126,7 +484,6 @@ const SCALAR_TYPES$1 = /* @__PURE__ */ new Set([
|
|
|
126
484
|
"blob",
|
|
127
485
|
"enum"
|
|
128
486
|
]);
|
|
129
|
-
const ARRAY_TYPES$1 = /* @__PURE__ */ new Set(["array"]);
|
|
130
487
|
function toRelativeImportPath(from, to) {
|
|
131
488
|
const relativePath = posix.relative(posix.dirname(from), to);
|
|
132
489
|
return relativePath.startsWith("../") ? relativePath : `./${relativePath}`;
|
|
@@ -171,7 +528,7 @@ function getScalarType(node, typeName) {
|
|
|
171
528
|
* Determines the data type, return type, and whether it uses the type name.
|
|
172
529
|
*/
|
|
173
530
|
function resolveFakerTypeUsage(node, typeName, canOverride) {
|
|
174
|
-
const isArray =
|
|
531
|
+
const isArray = node.type === "array";
|
|
175
532
|
const isTuple = node.type === "tuple";
|
|
176
533
|
const isScalar = SCALAR_TYPES$1.has(node.type);
|
|
177
534
|
let dataType = `Partial<${typeName}>`;
|
|
@@ -188,7 +545,6 @@ function resolveFakerTypeUsage(node, typeName, canOverride) {
|
|
|
188
545
|
//#endregion
|
|
189
546
|
//#region src/components/Faker.tsx
|
|
190
547
|
const OBJECT_TYPES = /* @__PURE__ */ new Set(["object", "intersection"]);
|
|
191
|
-
const ARRAY_TYPES = /* @__PURE__ */ new Set(["array"]);
|
|
192
548
|
const SCALAR_TYPES = /* @__PURE__ */ new Set([
|
|
193
549
|
"string",
|
|
194
550
|
"email",
|
|
@@ -207,7 +563,7 @@ const SCALAR_TYPES = /* @__PURE__ */ new Set([
|
|
|
207
563
|
const declarationPrinter = functionPrinter({ mode: "declaration" });
|
|
208
564
|
function Faker({ node, description, name, typeName, printer, seed, canOverride }) {
|
|
209
565
|
const fakerText = printer.print(node) ?? "undefined";
|
|
210
|
-
const isArray =
|
|
566
|
+
const isArray = node.type === "array";
|
|
211
567
|
const isObject = OBJECT_TYPES.has(node.type);
|
|
212
568
|
const isTuple = node.type === "tuple";
|
|
213
569
|
const isScalar = SCALAR_TYPES.has(node.type);
|
|
@@ -235,14 +591,14 @@ function Faker({ node, description, name, typeName, printer, seed, canOverride }
|
|
|
235
591
|
children: /* @__PURE__ */ jsxs(Function, {
|
|
236
592
|
export: true,
|
|
237
593
|
name,
|
|
238
|
-
JSDoc: { comments: description ? [`@description ${
|
|
594
|
+
JSDoc: { comments: description ? [`@description ${jsStringEscape(description)}`] : [] },
|
|
239
595
|
params: canOverride ? paramsSignature : void 0,
|
|
240
596
|
returnType: returnType ?? void 0,
|
|
241
597
|
children: [seed ? /* @__PURE__ */ jsxs(Fragment, { children: [`faker.seed(${JSON.stringify(seed)})`, /* @__PURE__ */ jsx("br", {})] }) : void 0, `return ${returnExpression}`]
|
|
242
598
|
})
|
|
243
599
|
});
|
|
244
600
|
}
|
|
245
|
-
const functionSignature = `${description ? `/**\n * @description ${
|
|
601
|
+
const functionSignature = `${description ? `/**\n * @description ${jsStringEscape(description)}\n */\n ` : ""}export function ${name}<TData extends Partial<${typeName}> = object>(data?: TData)`;
|
|
246
602
|
const seedCode = seed ? `faker.seed(${JSON.stringify(seed)})\n ` : "";
|
|
247
603
|
const { cyclicSchemas, schemaName } = printer.options;
|
|
248
604
|
const functionBody = node.type === "object" && !!cyclicSchemas && (node.properties ?? []).some((p) => ast.containsCircularRef(p.schema, {
|
|
@@ -271,226 +627,6 @@ function Faker({ node, description, name, typeName, printer, seed, canOverride }
|
|
|
271
627
|
});
|
|
272
628
|
}
|
|
273
629
|
//#endregion
|
|
274
|
-
//#region ../../internals/utils/src/casing.ts
|
|
275
|
-
/**
|
|
276
|
-
* Shared implementation for camelCase and PascalCase conversion.
|
|
277
|
-
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
|
|
278
|
-
* and capitalizes each word according to `pascal`.
|
|
279
|
-
*
|
|
280
|
-
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
281
|
-
*/
|
|
282
|
-
function toCamelOrPascal(text, pascal) {
|
|
283
|
-
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) => {
|
|
284
|
-
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
285
|
-
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
286
|
-
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Converts `text` to camelCase.
|
|
290
|
-
*
|
|
291
|
-
* @example Word boundaries
|
|
292
|
-
* `camelCase('hello-world') // 'helloWorld'`
|
|
293
|
-
*
|
|
294
|
-
* @example With a prefix
|
|
295
|
-
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
296
|
-
*/
|
|
297
|
-
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
298
|
-
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
299
|
-
}
|
|
300
|
-
//#endregion
|
|
301
|
-
//#region ../../internals/utils/src/fs.ts
|
|
302
|
-
/**
|
|
303
|
-
* Builds a nested file path from a dotted name. Splits on dots that precede a letter
|
|
304
|
-
* (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
|
|
305
|
-
* every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
|
|
306
|
-
*
|
|
307
|
-
* Empty segments are dropped before joining. They arise when the name starts with a dot
|
|
308
|
-
* followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
|
|
309
|
-
* an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
|
|
310
|
-
* absolute path, letting generated files escape the configured output directory.
|
|
311
|
-
*
|
|
312
|
-
* @example Nested path from a dotted name
|
|
313
|
-
* `toFilePath('pet.petId') // 'pet/petId'`
|
|
314
|
-
*
|
|
315
|
-
* @example PascalCase the final segment
|
|
316
|
-
* `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
|
|
317
|
-
*
|
|
318
|
-
* @example Suffix applied to the final segment only
|
|
319
|
-
* `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
|
|
320
|
-
*/
|
|
321
|
-
function toFilePath(name, caseLast = camelCase) {
|
|
322
|
-
const parts = name.split(/\.(?=[a-zA-Z])/);
|
|
323
|
-
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
|
|
324
|
-
}
|
|
325
|
-
//#endregion
|
|
326
|
-
//#region ../../internals/utils/src/imports.ts
|
|
327
|
-
function escapeRegExp(value) {
|
|
328
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
329
|
-
}
|
|
330
|
-
function getImportNames(entry) {
|
|
331
|
-
return (Array.isArray(entry.name) ? entry.name : [entry.name]).map((name) => {
|
|
332
|
-
if (typeof name === "string") return name;
|
|
333
|
-
return name.name ?? name.propertyName;
|
|
334
|
-
}).filter((name) => Boolean(name));
|
|
335
|
-
}
|
|
336
|
-
function filterUsedImports(imports, text, skipImportNames = []) {
|
|
337
|
-
const skip = new Set(skipImportNames);
|
|
338
|
-
return imports.filter((entry) => {
|
|
339
|
-
return getImportNames(entry).some((name) => {
|
|
340
|
-
if (skip.has(name)) return false;
|
|
341
|
-
return new RegExp(`\\b${escapeRegExp(name)}\\b(?=\\s*\\()`).test(text);
|
|
342
|
-
});
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
function aliasConflictingImports(imports, reservedNames) {
|
|
346
|
-
const reservedNameSet = new Set(reservedNames);
|
|
347
|
-
const aliases = /* @__PURE__ */ new Map();
|
|
348
|
-
return {
|
|
349
|
-
imports: imports.map((entry) => {
|
|
350
|
-
const aliasedNames = (Array.isArray(entry.name) ? entry.name : [entry.name]).map((item) => {
|
|
351
|
-
if (typeof item !== "string" || !reservedNameSet.has(item)) return item;
|
|
352
|
-
const alias = `${item}Schema`;
|
|
353
|
-
aliases.set(item, alias);
|
|
354
|
-
return {
|
|
355
|
-
propertyName: item,
|
|
356
|
-
name: alias
|
|
357
|
-
};
|
|
358
|
-
});
|
|
359
|
-
return aliasedNames.some((item) => typeof item === "object" && item.name) ? {
|
|
360
|
-
...entry,
|
|
361
|
-
name: aliasedNames
|
|
362
|
-
} : entry;
|
|
363
|
-
}),
|
|
364
|
-
aliases
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
function rewriteAliasedImports(text, aliases) {
|
|
368
|
-
return Array.from(aliases).reduce((acc, [name, alias]) => acc.replace(new RegExp(`\\b${escapeRegExp(name)}\\b`, "g"), alias), text);
|
|
369
|
-
}
|
|
370
|
-
//#endregion
|
|
371
|
-
//#region ../../internals/utils/src/reserved.ts
|
|
372
|
-
/**
|
|
373
|
-
* JavaScript and Java reserved words.
|
|
374
|
-
* @link https://github.com/jonschlinkert/reserved/blob/master/index.js
|
|
375
|
-
*/
|
|
376
|
-
const reservedWords = /* @__PURE__ */ new Set([
|
|
377
|
-
"abstract",
|
|
378
|
-
"arguments",
|
|
379
|
-
"boolean",
|
|
380
|
-
"break",
|
|
381
|
-
"byte",
|
|
382
|
-
"case",
|
|
383
|
-
"catch",
|
|
384
|
-
"char",
|
|
385
|
-
"class",
|
|
386
|
-
"const",
|
|
387
|
-
"continue",
|
|
388
|
-
"debugger",
|
|
389
|
-
"default",
|
|
390
|
-
"delete",
|
|
391
|
-
"do",
|
|
392
|
-
"double",
|
|
393
|
-
"else",
|
|
394
|
-
"enum",
|
|
395
|
-
"eval",
|
|
396
|
-
"export",
|
|
397
|
-
"extends",
|
|
398
|
-
"false",
|
|
399
|
-
"final",
|
|
400
|
-
"finally",
|
|
401
|
-
"float",
|
|
402
|
-
"for",
|
|
403
|
-
"function",
|
|
404
|
-
"goto",
|
|
405
|
-
"if",
|
|
406
|
-
"implements",
|
|
407
|
-
"import",
|
|
408
|
-
"in",
|
|
409
|
-
"instanceof",
|
|
410
|
-
"int",
|
|
411
|
-
"interface",
|
|
412
|
-
"let",
|
|
413
|
-
"long",
|
|
414
|
-
"native",
|
|
415
|
-
"new",
|
|
416
|
-
"null",
|
|
417
|
-
"package",
|
|
418
|
-
"private",
|
|
419
|
-
"protected",
|
|
420
|
-
"public",
|
|
421
|
-
"return",
|
|
422
|
-
"short",
|
|
423
|
-
"static",
|
|
424
|
-
"super",
|
|
425
|
-
"switch",
|
|
426
|
-
"synchronized",
|
|
427
|
-
"this",
|
|
428
|
-
"throw",
|
|
429
|
-
"throws",
|
|
430
|
-
"transient",
|
|
431
|
-
"true",
|
|
432
|
-
"try",
|
|
433
|
-
"typeof",
|
|
434
|
-
"var",
|
|
435
|
-
"void",
|
|
436
|
-
"volatile",
|
|
437
|
-
"while",
|
|
438
|
-
"with",
|
|
439
|
-
"yield",
|
|
440
|
-
"Array",
|
|
441
|
-
"Date",
|
|
442
|
-
"hasOwnProperty",
|
|
443
|
-
"Infinity",
|
|
444
|
-
"isFinite",
|
|
445
|
-
"isNaN",
|
|
446
|
-
"isPrototypeOf",
|
|
447
|
-
"length",
|
|
448
|
-
"Math",
|
|
449
|
-
"name",
|
|
450
|
-
"NaN",
|
|
451
|
-
"Number",
|
|
452
|
-
"Object",
|
|
453
|
-
"prototype",
|
|
454
|
-
"String",
|
|
455
|
-
"toString",
|
|
456
|
-
"undefined",
|
|
457
|
-
"valueOf"
|
|
458
|
-
]);
|
|
459
|
-
/**
|
|
460
|
-
* Returns `true` when `name` is a syntactically valid JavaScript variable name.
|
|
461
|
-
*
|
|
462
|
-
* @example
|
|
463
|
-
* ```ts
|
|
464
|
-
* isValidVarName('status') // true
|
|
465
|
-
* isValidVarName('class') // false (reserved word)
|
|
466
|
-
* isValidVarName('42foo') // false (starts with digit)
|
|
467
|
-
* ```
|
|
468
|
-
*/
|
|
469
|
-
function isValidVarName(name) {
|
|
470
|
-
if (!name || reservedWords.has(name)) return false;
|
|
471
|
-
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
472
|
-
}
|
|
473
|
-
/**
|
|
474
|
-
* Returns `name` when it's a syntactically valid JavaScript variable name,
|
|
475
|
-
* otherwise prefixes it with `_` so the result is a valid identifier.
|
|
476
|
-
*
|
|
477
|
-
* Useful for sanitizing OpenAPI schema names or operation IDs that start with
|
|
478
|
-
* a digit (e.g. `409`, `504AccountCancel`) before using them as exported
|
|
479
|
-
* variable, type, or function names.
|
|
480
|
-
*
|
|
481
|
-
* @example
|
|
482
|
-
* ```ts
|
|
483
|
-
* ensureValidVarName('409') // '_409'
|
|
484
|
-
* ensureValidVarName('504AccountCancel') // '_504AccountCancel'
|
|
485
|
-
* ensureValidVarName('Pet') // 'Pet'
|
|
486
|
-
* ensureValidVarName('class') // '_class'
|
|
487
|
-
* ```
|
|
488
|
-
*/
|
|
489
|
-
function ensureValidVarName(name) {
|
|
490
|
-
if (!name || isValidVarName(name)) return name;
|
|
491
|
-
return `_${name}`;
|
|
492
|
-
}
|
|
493
|
-
//#endregion
|
|
494
630
|
//#region ../../internals/shared/src/params.ts
|
|
495
631
|
const caseParamsCache = /* @__PURE__ */ new WeakMap();
|
|
496
632
|
/**
|
|
@@ -511,6 +647,23 @@ function caseParams(params, casing) {
|
|
|
511
647
|
caseParamsCache.set(params, result);
|
|
512
648
|
return result;
|
|
513
649
|
}
|
|
650
|
+
/**
|
|
651
|
+
* Drops parameters that collapse to the same property identity once camelCased, keeping the first.
|
|
652
|
+
*
|
|
653
|
+
* Some specs declare the same parameter twice under different casings (for example AWS S3 lists both
|
|
654
|
+
* `max-uploads` and `MaxUploads`). Both resolve to one output property, so emitting both would yield
|
|
655
|
+
* an object type with a duplicate member, which TypeScript rejects. De-duplicate by the camelCased
|
|
656
|
+
* identity so the resulting group is collision-free regardless of the names each caller carries.
|
|
657
|
+
*/
|
|
658
|
+
function dedupeByCasedName(params) {
|
|
659
|
+
const seen = /* @__PURE__ */ new Set();
|
|
660
|
+
return params.filter((param) => {
|
|
661
|
+
const key = camelCase(param.name);
|
|
662
|
+
if (seen.has(key)) return false;
|
|
663
|
+
seen.add(key);
|
|
664
|
+
return true;
|
|
665
|
+
});
|
|
666
|
+
}
|
|
514
667
|
//#endregion
|
|
515
668
|
//#region ../../internals/shared/src/operation.ts
|
|
516
669
|
/**
|
|
@@ -561,6 +714,15 @@ function resolveContentTypeVariants(entries, baseName) {
|
|
|
561
714
|
};
|
|
562
715
|
});
|
|
563
716
|
}
|
|
717
|
+
function getOperationParameters(node, options = {}) {
|
|
718
|
+
const params = caseParams(node.parameters, options.paramsCasing === "original" ? void 0 : "camelcase");
|
|
719
|
+
return {
|
|
720
|
+
path: dedupeByCasedName(params.filter((param) => param.in === "path")),
|
|
721
|
+
query: dedupeByCasedName(params.filter((param) => param.in === "query")),
|
|
722
|
+
header: dedupeByCasedName(params.filter((param) => param.in === "header")),
|
|
723
|
+
cookie: dedupeByCasedName(params.filter((param) => param.in === "cookie"))
|
|
724
|
+
};
|
|
725
|
+
}
|
|
564
726
|
//#endregion
|
|
565
727
|
//#region ../../internals/shared/src/group.ts
|
|
566
728
|
/**
|
|
@@ -655,7 +817,7 @@ const fakerKeywordMapper = {
|
|
|
655
817
|
return `{...${items.join(", ...")}}`;
|
|
656
818
|
},
|
|
657
819
|
matches: (value = "", regexGenerator = "faker") => {
|
|
658
|
-
if (regexGenerator === "randexp") return `${
|
|
820
|
+
if (regexGenerator === "randexp") return `${toRegExpString(value, "RandExp")}.gen()`;
|
|
659
821
|
return `faker.helpers.fromRegExp("${value}")`;
|
|
660
822
|
},
|
|
661
823
|
email: () => "faker.internet.email()",
|
|
@@ -666,7 +828,7 @@ function getEnumValues(node) {
|
|
|
666
828
|
return node.enumValues ?? [];
|
|
667
829
|
}
|
|
668
830
|
function parseEnumValue(value) {
|
|
669
|
-
if (typeof value === "string") return
|
|
831
|
+
if (typeof value === "string") return stringify(value);
|
|
670
832
|
return value;
|
|
671
833
|
}
|
|
672
834
|
/**
|
|
@@ -734,7 +896,7 @@ const printerFaker = ast.createPrinter((options) => {
|
|
|
734
896
|
const refName = node.ref ? this.options.nameMapping?.get(node.ref) ?? ast.extractRefName(node.ref) ?? node.name ?? node.schema?.name : node.name ?? node.schema?.name;
|
|
735
897
|
if (!refName) throw new Error("Name not defined for ref node");
|
|
736
898
|
if (this.options.schemaName && refName === this.options.schemaName) return this.options.typeName ? `undefined as unknown as ${this.options.typeName}` : "undefined as unknown";
|
|
737
|
-
const resolvedName = node.ref ? this.options.resolver.
|
|
899
|
+
const resolvedName = node.ref ? this.options.resolver.name(refName) : refName;
|
|
738
900
|
if (!this.options.nestedInObject) return `${resolvedName}(data)`;
|
|
739
901
|
return `${resolvedName}()`;
|
|
740
902
|
},
|
|
@@ -778,7 +940,7 @@ const printerFaker = ast.createPrinter((options) => {
|
|
|
778
940
|
},
|
|
779
941
|
object(node) {
|
|
780
942
|
const cyclicSchemas = this.options.cyclicSchemas;
|
|
781
|
-
|
|
943
|
+
return buildObject((node.properties ?? []).map((property) => {
|
|
782
944
|
const value = printNested(property.schema, {
|
|
783
945
|
typeName: this.options.typeName ? indexedTypeName(this.options.typeName, property.name, this.options.nestedInUnion) : void 0,
|
|
784
946
|
nestedInObject: true
|
|
@@ -786,10 +948,9 @@ const printerFaker = ast.createPrinter((options) => {
|
|
|
786
948
|
if (cyclicSchemas && ast.containsCircularRef(property.schema, {
|
|
787
949
|
circularSchemas: cyclicSchemas,
|
|
788
950
|
excludeName: this.options.schemaName
|
|
789
|
-
})) return `get ${
|
|
790
|
-
return `${
|
|
791
|
-
});
|
|
792
|
-
return ast.buildObject(entries);
|
|
951
|
+
})) return `get ${objectKey(property.name)}() { const _value = ${value}; Object.defineProperty(this, ${JSON.stringify(property.name)}, { value: _value, configurable: true, writable: true, enumerable: true }); return _value }`;
|
|
952
|
+
return `${objectKey(property.name)}: ${value}`;
|
|
953
|
+
}));
|
|
793
954
|
},
|
|
794
955
|
...options.nodes
|
|
795
956
|
},
|
|
@@ -819,22 +980,20 @@ const fakerGenerator = defineGenerator({
|
|
|
819
980
|
const isEnumSchema = !!ast.narrowSchema(node, ast.schemaTypes.enum);
|
|
820
981
|
const tsEnumType = pluginTs.options?.enum?.type;
|
|
821
982
|
const tsEnumTypeSuffix = pluginTs.options?.enum?.typeSuffix ?? "Key";
|
|
822
|
-
const schemaTypeName = isEnumSchema && tsEnumType === "asConst" ? tsResolver.
|
|
983
|
+
const schemaTypeName = isEnumSchema && tsEnumType === "asConst" ? tsResolver.enum.keyName({ name: schemaName }, tsEnumTypeSuffix) : tsResolver.name(schemaName);
|
|
823
984
|
const meta = {
|
|
824
|
-
name: resolver.
|
|
825
|
-
file: resolver.
|
|
985
|
+
name: resolver.name(schemaName),
|
|
986
|
+
file: resolver.file({
|
|
826
987
|
name: schemaName,
|
|
827
|
-
extname: ".ts"
|
|
828
|
-
}, {
|
|
988
|
+
extname: ".ts",
|
|
829
989
|
root,
|
|
830
990
|
output,
|
|
831
991
|
group: group ?? void 0
|
|
832
992
|
}),
|
|
833
993
|
typeName: schemaTypeName,
|
|
834
|
-
typeFile: tsResolver.
|
|
994
|
+
typeFile: tsResolver.file({
|
|
835
995
|
name: schemaName,
|
|
836
|
-
extname: ".ts"
|
|
837
|
-
}, {
|
|
996
|
+
extname: ".ts",
|
|
838
997
|
root,
|
|
839
998
|
output: pluginTs.options?.output ?? output,
|
|
840
999
|
group: pluginTs.options?.group ?? void 0
|
|
@@ -862,11 +1021,10 @@ const fakerGenerator = defineGenerator({
|
|
|
862
1021
|
typeFilePath: meta.typeFile.path
|
|
863
1022
|
});
|
|
864
1023
|
const usedImports = filterUsedImports(adapter.getImports(node, (schemaName) => ({
|
|
865
|
-
name: resolver.
|
|
866
|
-
path: resolver.
|
|
1024
|
+
name: resolver.name(schemaName),
|
|
1025
|
+
path: resolver.file({
|
|
867
1026
|
name: schemaName,
|
|
868
|
-
extname: ".ts"
|
|
869
|
-
}, {
|
|
1027
|
+
extname: ".ts",
|
|
870
1028
|
root,
|
|
871
1029
|
output,
|
|
872
1030
|
group: group ?? void 0
|
|
@@ -876,7 +1034,7 @@ const fakerGenerator = defineGenerator({
|
|
|
876
1034
|
baseName: meta.file.baseName,
|
|
877
1035
|
path: meta.file.path,
|
|
878
1036
|
meta: meta.file.meta,
|
|
879
|
-
banner: resolver.
|
|
1037
|
+
banner: resolver.default.banner(ctx.meta, {
|
|
880
1038
|
output,
|
|
881
1039
|
config,
|
|
882
1040
|
file: {
|
|
@@ -884,7 +1042,7 @@ const fakerGenerator = defineGenerator({
|
|
|
884
1042
|
baseName: meta.file.baseName
|
|
885
1043
|
}
|
|
886
1044
|
}),
|
|
887
|
-
footer: resolver.
|
|
1045
|
+
footer: resolver.default.footer(ctx.meta, {
|
|
888
1046
|
output,
|
|
889
1047
|
config,
|
|
890
1048
|
file: {
|
|
@@ -941,10 +1099,31 @@ const fakerGenerator = defineGenerator({
|
|
|
941
1099
|
const pluginTs = ctx.driver.getPlugin(pluginTsName);
|
|
942
1100
|
if (!pluginTs) return;
|
|
943
1101
|
const tsResolver = ctx.driver.getResolver(pluginTsName);
|
|
944
|
-
const
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1102
|
+
const params = caseParams(node.parameters, "camelcase");
|
|
1103
|
+
const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters({
|
|
1104
|
+
...node,
|
|
1105
|
+
parameters: params
|
|
1106
|
+
}, { paramsCasing: "original" });
|
|
1107
|
+
const paramGroups = [
|
|
1108
|
+
{
|
|
1109
|
+
params: pathParams,
|
|
1110
|
+
name: resolver.param.path,
|
|
1111
|
+
typeName: tsResolver.param.path
|
|
1112
|
+
},
|
|
1113
|
+
{
|
|
1114
|
+
params: queryParams,
|
|
1115
|
+
name: resolver.param.query,
|
|
1116
|
+
typeName: tsResolver.param.query
|
|
1117
|
+
},
|
|
1118
|
+
{
|
|
1119
|
+
params: headerParams,
|
|
1120
|
+
name: resolver.param.headers,
|
|
1121
|
+
typeName: tsResolver.param.headers
|
|
1122
|
+
}
|
|
1123
|
+
].filter((group) => group.params.length > 0).map((group) => ({
|
|
1124
|
+
schema: buildParams({ params: group.params }),
|
|
1125
|
+
name: group.name(node, group.params[0]),
|
|
1126
|
+
typeName: group.typeName(node, group.params[0])
|
|
948
1127
|
}));
|
|
949
1128
|
function expandContentUnits(entries, baseName, tsBaseName, description, decorate) {
|
|
950
1129
|
const withSchema = entries.filter((entry) => entry.schema);
|
|
@@ -981,36 +1160,34 @@ const fakerGenerator = defineGenerator({
|
|
|
981
1160
|
skipImportNames: variants.map((variant) => variant.name)
|
|
982
1161
|
}];
|
|
983
1162
|
}
|
|
984
|
-
const responseUnits = node.responses.flatMap((response) => expandContentUnits(response.content ?? [], resolver.
|
|
985
|
-
const dataUnits = expandContentUnits(node.requestBody?.content ?? [], resolver.
|
|
1163
|
+
const responseUnits = node.responses.flatMap((response) => expandContentUnits(response.content ?? [], resolver.response.status(node, response.statusCode), tsResolver.response.status(node, response.statusCode), response.description));
|
|
1164
|
+
const dataUnits = expandContentUnits(node.requestBody?.content ?? [], resolver.response.body(node), tsResolver.response.body(node), node.requestBody?.description, (schema) => ({
|
|
986
1165
|
...schema,
|
|
987
1166
|
description: node.requestBody?.description ?? schema.description
|
|
988
1167
|
}));
|
|
989
|
-
const responseName = resolver.
|
|
1168
|
+
const responseName = resolver.response.response(node);
|
|
990
1169
|
const localHelperNames = /* @__PURE__ */ new Set([
|
|
991
|
-
...
|
|
1170
|
+
...paramGroups.map((group) => group.name),
|
|
992
1171
|
...responseUnits.map((unit) => unit.name),
|
|
993
1172
|
...dataUnits.map((unit) => unit.name),
|
|
994
1173
|
responseName
|
|
995
1174
|
]);
|
|
996
1175
|
const cyclicSchemas = new Set(ctx.meta.circularNames);
|
|
997
1176
|
const meta = {
|
|
998
|
-
file: resolver.
|
|
1177
|
+
file: resolver.file({
|
|
999
1178
|
name: node.operationId,
|
|
1000
1179
|
extname: ".ts",
|
|
1001
1180
|
tag: node.tags[0] ?? "default",
|
|
1002
|
-
path: node.path
|
|
1003
|
-
}, {
|
|
1181
|
+
path: node.path,
|
|
1004
1182
|
root,
|
|
1005
1183
|
output,
|
|
1006
1184
|
group: group ?? void 0
|
|
1007
1185
|
}),
|
|
1008
|
-
typeFile: tsResolver.
|
|
1186
|
+
typeFile: tsResolver.file({
|
|
1009
1187
|
name: node.operationId,
|
|
1010
1188
|
extname: ".ts",
|
|
1011
1189
|
tag: node.tags[0] ?? "default",
|
|
1012
|
-
path: node.path
|
|
1013
|
-
}, {
|
|
1190
|
+
path: node.path,
|
|
1014
1191
|
root,
|
|
1015
1192
|
output: pluginTs.options?.output ?? output,
|
|
1016
1193
|
group: pluginTs.options?.group ?? void 0
|
|
@@ -1018,11 +1195,10 @@ const fakerGenerator = defineGenerator({
|
|
|
1018
1195
|
};
|
|
1019
1196
|
function resolveMockImports(schema) {
|
|
1020
1197
|
return adapter.getImports(schema, (schemaName) => ({
|
|
1021
|
-
name: resolver.
|
|
1022
|
-
path: resolver.
|
|
1198
|
+
name: resolver.name(schemaName),
|
|
1199
|
+
path: resolver.file({
|
|
1023
1200
|
name: schemaName,
|
|
1024
|
-
extname: ".ts"
|
|
1025
|
-
}, {
|
|
1201
|
+
extname: ".ts",
|
|
1026
1202
|
root,
|
|
1027
1203
|
output,
|
|
1028
1204
|
group: group ?? void 0
|
|
@@ -1087,7 +1263,7 @@ const fakerGenerator = defineGenerator({
|
|
|
1087
1263
|
baseName: meta.file.baseName,
|
|
1088
1264
|
path: meta.file.path,
|
|
1089
1265
|
meta: meta.file.meta,
|
|
1090
|
-
banner: resolver.
|
|
1266
|
+
banner: resolver.default.banner(ctx.meta, {
|
|
1091
1267
|
output,
|
|
1092
1268
|
config,
|
|
1093
1269
|
file: {
|
|
@@ -1095,7 +1271,7 @@ const fakerGenerator = defineGenerator({
|
|
|
1095
1271
|
baseName: meta.file.baseName
|
|
1096
1272
|
}
|
|
1097
1273
|
}),
|
|
1098
|
-
footer: resolver.
|
|
1274
|
+
footer: resolver.default.footer(ctx.meta, {
|
|
1099
1275
|
output,
|
|
1100
1276
|
config,
|
|
1101
1277
|
file: {
|
|
@@ -1119,11 +1295,7 @@ const fakerGenerator = defineGenerator({
|
|
|
1119
1295
|
path: dateParser,
|
|
1120
1296
|
name: dateParser
|
|
1121
1297
|
}),
|
|
1122
|
-
|
|
1123
|
-
schema: param.schema,
|
|
1124
|
-
name,
|
|
1125
|
-
typeName
|
|
1126
|
-
})),
|
|
1298
|
+
paramGroups.map((group) => renderEntry(group)),
|
|
1127
1299
|
responseUnits.map((unit) => renderEntry({
|
|
1128
1300
|
schema: unit.schema,
|
|
1129
1301
|
name: unit.name,
|
|
@@ -1141,7 +1313,7 @@ const fakerGenerator = defineGenerator({
|
|
|
1141
1313
|
renderEntry({
|
|
1142
1314
|
schema: buildResponseUnionSchema(node, resolver),
|
|
1143
1315
|
name: responseName,
|
|
1144
|
-
typeName: tsResolver.
|
|
1316
|
+
typeName: tsResolver.response.response(node),
|
|
1145
1317
|
skipImportNames: responseUnits.map((unit) => unit.name)
|
|
1146
1318
|
})
|
|
1147
1319
|
]
|
|
@@ -1159,69 +1331,45 @@ const fakerGenerator = defineGenerator({
|
|
|
1159
1331
|
* ```ts
|
|
1160
1332
|
* import { resolverFaker } from '@kubb/plugin-faker'
|
|
1161
1333
|
*
|
|
1162
|
-
* resolverFaker.
|
|
1334
|
+
* resolverFaker.name('list pets') // 'createListPets'
|
|
1163
1335
|
* ```
|
|
1164
1336
|
*/
|
|
1165
|
-
const resolverFaker =
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
resolvePathName(name, type) {
|
|
1177
|
-
return this.default(name, type);
|
|
1178
|
-
},
|
|
1179
|
-
resolveFile({ name, extname, tag, path: groupPath }, context) {
|
|
1180
|
-
const inputBaseName = `${context.output.mode === "file" ? "" : this.resolveName(name, "file")}${extname}`;
|
|
1181
|
-
const filePath = this.resolvePath({
|
|
1182
|
-
baseName: inputBaseName,
|
|
1183
|
-
tag,
|
|
1184
|
-
path: groupPath
|
|
1185
|
-
}, context);
|
|
1186
|
-
const baseName = path.basename(filePath);
|
|
1187
|
-
return {
|
|
1188
|
-
kind: "File",
|
|
1189
|
-
id: createHash("sha256").update(filePath).digest("hex"),
|
|
1190
|
-
name: path.basename(filePath, extname),
|
|
1191
|
-
path: filePath,
|
|
1192
|
-
baseName,
|
|
1193
|
-
extname,
|
|
1194
|
-
meta: { pluginName: this.pluginName },
|
|
1195
|
-
sources: [],
|
|
1196
|
-
imports: [],
|
|
1197
|
-
exports: []
|
|
1198
|
-
};
|
|
1199
|
-
},
|
|
1200
|
-
resolveParamName(node, param) {
|
|
1201
|
-
return this.resolveName(`${node.operationId} ${param.in} ${param.name}`);
|
|
1202
|
-
},
|
|
1203
|
-
resolveDataName(node) {
|
|
1204
|
-
return this.resolveName(`${node.operationId} Data`);
|
|
1337
|
+
const resolverFaker = createResolver({
|
|
1338
|
+
pluginName: "plugin-faker",
|
|
1339
|
+
name(name) {
|
|
1340
|
+
return ensureValidVarName(camelCase(name, { prefix: "create" }));
|
|
1341
|
+
},
|
|
1342
|
+
file: { baseName({ name, extname }) {
|
|
1343
|
+
return `${toFilePath(name, (part) => camelCase(part, { prefix: "create" }))}${extname}`;
|
|
1344
|
+
} },
|
|
1345
|
+
param: {
|
|
1346
|
+
name(node, param) {
|
|
1347
|
+
return this.name(`${node.operationId} ${param.in} ${param.name}`);
|
|
1205
1348
|
},
|
|
1206
|
-
|
|
1207
|
-
return this.
|
|
1349
|
+
path(node) {
|
|
1350
|
+
return this.name(`${node.operationId} Path`);
|
|
1208
1351
|
},
|
|
1209
|
-
|
|
1210
|
-
return this.
|
|
1352
|
+
query(node) {
|
|
1353
|
+
return this.name(`${node.operationId} Query`);
|
|
1211
1354
|
},
|
|
1212
|
-
|
|
1213
|
-
return this.
|
|
1355
|
+
headers(node) {
|
|
1356
|
+
return this.name(`${node.operationId} Headers`);
|
|
1357
|
+
}
|
|
1358
|
+
},
|
|
1359
|
+
response: {
|
|
1360
|
+
status(node, statusCode) {
|
|
1361
|
+
return this.name(`${node.operationId} Status ${statusCode}`);
|
|
1214
1362
|
},
|
|
1215
|
-
|
|
1216
|
-
return this.
|
|
1363
|
+
body(node) {
|
|
1364
|
+
return this.name(`${node.operationId} Body`);
|
|
1217
1365
|
},
|
|
1218
|
-
|
|
1219
|
-
return this.
|
|
1366
|
+
response(node) {
|
|
1367
|
+
return this.name(`${node.operationId} Response`);
|
|
1220
1368
|
},
|
|
1221
|
-
|
|
1222
|
-
return this.
|
|
1369
|
+
responses(node) {
|
|
1370
|
+
return this.name(`${node.operationId} Responses`);
|
|
1223
1371
|
}
|
|
1224
|
-
}
|
|
1372
|
+
}
|
|
1225
1373
|
});
|
|
1226
1374
|
//#endregion
|
|
1227
1375
|
//#region src/plugin.ts
|
|
@@ -1277,10 +1425,7 @@ const pluginFaker = definePlugin((options) => {
|
|
|
1277
1425
|
regexGenerator,
|
|
1278
1426
|
printer
|
|
1279
1427
|
});
|
|
1280
|
-
ctx.setResolver(userResolver ?
|
|
1281
|
-
...resolverFaker,
|
|
1282
|
-
...userResolver
|
|
1283
|
-
} : resolverFaker);
|
|
1428
|
+
ctx.setResolver(userResolver ? Resolver.merge(resolverFaker, userResolver) : resolverFaker);
|
|
1284
1429
|
if (userMacros?.length) ctx.setMacros(userMacros);
|
|
1285
1430
|
ctx.addGenerator(fakerGenerator);
|
|
1286
1431
|
} }
|