@kubb/plugin-faker 5.4.0-canary.20261111T122006 → 5.4.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 +255 -289
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -9
- package/dist/index.d.ts +8 -9
- package/dist/index.js +255 -289
- package/dist/index.js.map +1 -1
- package/docs/options.md +14 -11
- package/docs/overview.md +2 -2
- package/kubb-extension.json +1 -1
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
let node_path = require("node:path");
|
|
6
5
|
let _kubb_kit = require("@kubb/kit");
|
|
6
|
+
let node_path = require("node:path");
|
|
7
7
|
let _kubb_renderer_jsx = require("@kubb/renderer-jsx");
|
|
8
8
|
let _kubb_renderer_jsx_jsx_runtime = require("@kubb/renderer-jsx/jsx-runtime");
|
|
9
9
|
let _kubb_plugin_ts = require("@kubb/plugin-ts");
|
|
@@ -146,67 +146,76 @@ function ensureValidVarName(name) {
|
|
|
146
146
|
function isIdentifier(name) {
|
|
147
147
|
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
148
148
|
}
|
|
149
|
-
// ../../internals/utils/src/
|
|
149
|
+
// ../../internals/utils/src/codegen.ts
|
|
150
150
|
/**
|
|
151
|
-
*
|
|
152
|
-
*
|
|
151
|
+
* Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one
|
|
152
|
+
* level and closing the brace at column zero. Entries that are themselves multi-line objects indent
|
|
153
|
+
* cumulatively. Each entry ends with a trailing comma to match the formatter's multi-line style.
|
|
153
154
|
*
|
|
154
155
|
* @example
|
|
155
156
|
* ```ts
|
|
156
|
-
*
|
|
157
|
-
*
|
|
157
|
+
* buildObject(['id: z.number()', 'name: z.string()'])
|
|
158
|
+
* // '{\n id: z.number(),\n name: z.string(),\n}'
|
|
158
159
|
* ```
|
|
159
160
|
*/
|
|
160
|
-
function
|
|
161
|
-
if (
|
|
162
|
-
return `
|
|
161
|
+
function buildObject(entries) {
|
|
162
|
+
if (entries.length === 0) return "{}";
|
|
163
|
+
return `{\n${entries.map((entry) => `${_kubb_kit.text.indent({ text: entry })},`).join("\n")}\n}`;
|
|
163
164
|
}
|
|
164
165
|
/**
|
|
165
|
-
*
|
|
166
|
-
* Returns the string unchanged when no balanced quote pair is found.
|
|
166
|
+
* An object key, quoted only when it is not identifier-shaped. Reserved words such as `class` stay bare.
|
|
167
167
|
*
|
|
168
168
|
* @example
|
|
169
169
|
* ```ts
|
|
170
|
-
*
|
|
171
|
-
* trimQuotes('hello') // 'hello'
|
|
170
|
+
* objectKey('x-total') // "'x-total'"
|
|
172
171
|
* ```
|
|
173
172
|
*/
|
|
174
|
-
function
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
return
|
|
173
|
+
function objectKey(name) {
|
|
174
|
+
return isIdentifier(name) ? name : _kubb_kit.text.quote(name);
|
|
175
|
+
}
|
|
176
|
+
// ../../internals/utils/src/fs.ts
|
|
177
|
+
function toSlash(p) {
|
|
178
|
+
if (p.startsWith("\\\\?\\")) return p;
|
|
179
|
+
return p.replaceAll("\\", "/");
|
|
181
180
|
}
|
|
182
181
|
/**
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
* Escaping runs through `JSON.stringify`, then the result switches to single quotes so the generated
|
|
186
|
-
* code matches the repo style without a formatter.
|
|
182
|
+
* Returns the relative path from `rootDir` to `filePath`, always using forward slashes
|
|
183
|
+
* and prefixed with `./` when not already traversing upward.
|
|
187
184
|
*
|
|
188
185
|
* @example
|
|
189
186
|
* ```ts
|
|
190
|
-
*
|
|
191
|
-
*
|
|
187
|
+
* getRelativePath('/src/components', '/src/components/Button.tsx') // './Button.tsx'
|
|
188
|
+
* getRelativePath('/src/components', '/src/utils/helpers.ts') // '../utils/helpers.ts'
|
|
192
189
|
* ```
|
|
193
190
|
*/
|
|
194
|
-
function
|
|
195
|
-
|
|
196
|
-
return
|
|
191
|
+
function getRelativePath(rootDir, filePath) {
|
|
192
|
+
const relativePath = node_path.posix.relative(toSlash(rootDir), toSlash(filePath));
|
|
193
|
+
return relativePath.startsWith("../") ? relativePath : `./${relativePath}`;
|
|
197
194
|
}
|
|
198
195
|
/**
|
|
199
|
-
*
|
|
200
|
-
*
|
|
196
|
+
* Builds a nested file path from a dotted name. Splits on dots that precede a letter
|
|
197
|
+
* (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
|
|
198
|
+
* every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
|
|
201
199
|
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
200
|
+
* Empty segments are dropped before joining. They arise when the name starts with a dot
|
|
201
|
+
* followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
|
|
202
|
+
* an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
|
|
203
|
+
* absolute path, letting generated files escape the configured output directory.
|
|
204
|
+
*
|
|
205
|
+
* @example Nested path from a dotted name
|
|
206
|
+
* `toFilePath('pet.petId') // 'pet/petId'`
|
|
207
|
+
*
|
|
208
|
+
* @example PascalCase the final segment
|
|
209
|
+
* `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
|
|
210
|
+
*
|
|
211
|
+
* @example Suffix applied to the final segment only
|
|
212
|
+
* `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
|
|
206
213
|
*/
|
|
207
|
-
function
|
|
208
|
-
|
|
214
|
+
function toFilePath(name, caseLast = _kubb_kit.casing.camel) {
|
|
215
|
+
const parts = name.split(/\.(?=[a-zA-Z])/);
|
|
216
|
+
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : _kubb_kit.casing.camel(part)).filter(Boolean).join("/");
|
|
209
217
|
}
|
|
218
|
+
// ../../internals/utils/src/strings.ts
|
|
210
219
|
const NEEDS_UNICODE = /(?<!\\)(?:\\\\)*\\[pPu]\{|[\u{10000}-\u{10FFFF}]/u;
|
|
211
220
|
const KEPT_ESCAPE = /[A-Za-z0-9^$\\.*+?()[\]{}|/]/;
|
|
212
221
|
/**
|
|
@@ -246,8 +255,8 @@ function toRegExp(pattern, flags) {
|
|
|
246
255
|
* toRegExpString('^(?im)foo', null) // '/^foo/im'
|
|
247
256
|
* ```
|
|
248
257
|
*/
|
|
249
|
-
function toRegExpString(
|
|
250
|
-
const raw =
|
|
258
|
+
function toRegExpString(pattern, func = "RegExp") {
|
|
259
|
+
const raw = _kubb_kit.text.unquote(pattern);
|
|
251
260
|
const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i);
|
|
252
261
|
const replacementTarget = match?.[1] ?? "";
|
|
253
262
|
const matchedFlags = match?.[2];
|
|
@@ -255,84 +264,17 @@ function toRegExpString(text, func = "RegExp") {
|
|
|
255
264
|
if (func === null) return `/${source}/${flags}`;
|
|
256
265
|
return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`;
|
|
257
266
|
}
|
|
258
|
-
// ../../internals/utils/src/codegen.ts
|
|
259
|
-
const INDENT = " ";
|
|
260
|
-
/**
|
|
261
|
-
* Indents every non-empty line of `text` by one indent level, leaving blank lines empty.
|
|
262
|
-
*/
|
|
263
|
-
function indentLines(text) {
|
|
264
|
-
if (!text) return "";
|
|
265
|
-
return text.split("\n").map((line) => line.trim() ? `${INDENT}${line}` : "").join("\n");
|
|
266
|
-
}
|
|
267
267
|
/**
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
* @example
|
|
272
|
-
* ```ts
|
|
273
|
-
* objectKey('name') // 'name'
|
|
274
|
-
* objectKey('x-total') // "'x-total'"
|
|
275
|
-
* ```
|
|
276
|
-
*/
|
|
277
|
-
function objectKey(name) {
|
|
278
|
-
return isIdentifier(name) ? name : singleQuote(name);
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one
|
|
282
|
-
* level and closing the brace at column zero. Entries that are themselves multi-line objects indent
|
|
283
|
-
* cumulatively. Each entry ends with a trailing comma to match the formatter's multi-line style.
|
|
284
|
-
*
|
|
285
|
-
* @example
|
|
286
|
-
* ```ts
|
|
287
|
-
* buildObject(['id: z.number()', 'name: z.string()'])
|
|
288
|
-
* // '{\n id: z.number(),\n name: z.string(),\n}'
|
|
289
|
-
* ```
|
|
290
|
-
*/
|
|
291
|
-
function buildObject(entries) {
|
|
292
|
-
if (entries.length === 0) return "{}";
|
|
293
|
-
return `{\n${entries.map((entry) => `${indentLines(entry)},`).join("\n")}\n}`;
|
|
294
|
-
}
|
|
295
|
-
// ../../internals/utils/src/fs.ts
|
|
296
|
-
function toSlash(p) {
|
|
297
|
-
if (p.startsWith("\\\\?\\")) return p;
|
|
298
|
-
return p.replaceAll("\\", "/");
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
* Returns the relative path from `rootDir` to `filePath`, always using forward slashes
|
|
302
|
-
* and prefixed with `./` when not already traversing upward.
|
|
268
|
+
* Escapes an `@` at the start of a line, so a multi-line description can't start a new JSDoc tag.
|
|
269
|
+
* Editors render `\@` as `@` in hovers.
|
|
303
270
|
*
|
|
304
271
|
* @example
|
|
305
272
|
* ```ts
|
|
306
|
-
*
|
|
307
|
-
* getRelativePath('/src/components', '/src/utils/helpers.ts') // '../utils/helpers.ts'
|
|
273
|
+
* jsDocEscape('intro\n@example value') // 'intro\n\\@example value'
|
|
308
274
|
* ```
|
|
309
275
|
*/
|
|
310
|
-
function
|
|
311
|
-
|
|
312
|
-
return relativePath.startsWith("../") ? relativePath : `./${relativePath}`;
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
* Builds a nested file path from a dotted name. Splits on dots that precede a letter
|
|
316
|
-
* (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
|
|
317
|
-
* every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
|
|
318
|
-
*
|
|
319
|
-
* Empty segments are dropped before joining. They arise when the name starts with a dot
|
|
320
|
-
* followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
|
|
321
|
-
* an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
|
|
322
|
-
* absolute path, letting generated files escape the configured output directory.
|
|
323
|
-
*
|
|
324
|
-
* @example Nested path from a dotted name
|
|
325
|
-
* `toFilePath('pet.petId') // 'pet/petId'`
|
|
326
|
-
*
|
|
327
|
-
* @example PascalCase the final segment
|
|
328
|
-
* `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
|
|
329
|
-
*
|
|
330
|
-
* @example Suffix applied to the final segment only
|
|
331
|
-
* `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
|
|
332
|
-
*/
|
|
333
|
-
function toFilePath(name, caseLast = _kubb_kit.camelCase) {
|
|
334
|
-
const parts = name.split(/\.(?=[a-zA-Z])/);
|
|
335
|
-
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : (0, _kubb_kit.camelCase)(part)).filter(Boolean).join("/");
|
|
276
|
+
function jsDocEscape(input) {
|
|
277
|
+
return `${input}`.replace(/^(\s*)@/gm, "$1\\@");
|
|
336
278
|
}
|
|
337
279
|
// ../../internals/shared/src/operation.ts
|
|
338
280
|
/**
|
|
@@ -399,19 +341,12 @@ function resolveOperationFile(options) {
|
|
|
399
341
|
return file;
|
|
400
342
|
});
|
|
401
343
|
}
|
|
402
|
-
function baseContentType(contentType) {
|
|
403
|
-
return contentType.split(";")[0].trim().toLowerCase();
|
|
404
|
-
}
|
|
405
344
|
/**
|
|
406
|
-
*
|
|
407
|
-
* `application/x-ndjson`, `application/json-seq`, or any media type with an OpenAPI 3.2 `itemSchema`.
|
|
345
|
+
* How a content entry is framed as a stream: `'events'` for Server-Sent Events, `'lines'` for JSON Lines.
|
|
408
346
|
*/
|
|
409
|
-
function
|
|
410
|
-
|
|
411
|
-
return
|
|
412
|
-
}
|
|
413
|
-
function isJsonContentType(baseType) {
|
|
414
|
-
return baseType === "application/json" || baseType.endsWith("+json") || baseType === "text/json";
|
|
347
|
+
function getStreamFraming(entry) {
|
|
348
|
+
if (_kubb_kit.ast.mediaType.getBase(entry) === "text/event-stream") return "events";
|
|
349
|
+
return entry.stream && _kubb_kit.ast.mediaType.isStream(entry) ? "lines" : void 0;
|
|
415
350
|
}
|
|
416
351
|
/**
|
|
417
352
|
* Parser for one response content entry.
|
|
@@ -422,10 +357,10 @@ function isJsonContentType(baseType) {
|
|
|
422
357
|
* `image/*`, `audio/*`, and `video/*` are blobs.
|
|
423
358
|
*/
|
|
424
359
|
function responseTypeForContent(entry) {
|
|
425
|
-
const baseType =
|
|
360
|
+
const baseType = _kubb_kit.ast.mediaType.getBase(entry);
|
|
426
361
|
if (!baseType) return void 0;
|
|
427
|
-
if (
|
|
428
|
-
if (
|
|
362
|
+
if (getStreamFraming(entry)) return "stream";
|
|
363
|
+
if (_kubb_kit.ast.mediaType.isJson(baseType)) return void 0;
|
|
429
364
|
if (entry.schema?.type === "blob") return "blob";
|
|
430
365
|
if (baseType.startsWith("text/")) return "text";
|
|
431
366
|
if (isBinaryContentType(baseType)) return "blob";
|
|
@@ -463,14 +398,14 @@ function getPerContentTypeName(baseName, suffix) {
|
|
|
463
398
|
function toResponseContent(entry, entries = [entry]) {
|
|
464
399
|
const { contentType, schema } = entry;
|
|
465
400
|
if (!schema || entry.stream) return entry;
|
|
466
|
-
const baseType =
|
|
467
|
-
const resolved = _kubb_kit.ast.
|
|
401
|
+
const baseType = _kubb_kit.ast.mediaType.getBase(contentType);
|
|
402
|
+
const resolved = _kubb_kit.ast.ref.getSchema(schema);
|
|
468
403
|
if (isBinaryContentType(baseType)) return resolved.type === "blob" ? entry : {
|
|
469
404
|
...entry,
|
|
470
405
|
schema: _kubb_kit.ast.factory.createSchema({ type: "blob" }),
|
|
471
406
|
keysToOmit: null
|
|
472
407
|
};
|
|
473
|
-
const isPlainMediaType = Boolean(baseType) && !
|
|
408
|
+
const isPlainMediaType = Boolean(baseType) && !_kubb_kit.ast.mediaType.isJson(baseType) && !baseType.includes("*");
|
|
474
409
|
if (resolved.type === "blob") return isPlainMediaType && !entries.every((item) => item.schema?.type === "blob") ? {
|
|
475
410
|
...entry,
|
|
476
411
|
schema: _kubb_kit.ast.factory.createSchema({ type: "string" }),
|
|
@@ -513,50 +448,6 @@ function resolveContentTypeVariants(entries, baseName) {
|
|
|
513
448
|
};
|
|
514
449
|
});
|
|
515
450
|
}
|
|
516
|
-
const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
|
|
517
|
-
/**
|
|
518
|
-
* An OpenAPI 3.2 `querystring` parameter is the whole query string, so a form-encoded object becomes one query parameter
|
|
519
|
-
* per property, typed and serialized like any other.
|
|
520
|
-
* Another content type, such as JSON, stays one parameter named after it, and the runtime sends its value as the whole query string.
|
|
521
|
-
*/
|
|
522
|
-
function spreadQuerystring(param) {
|
|
523
|
-
const schema = param.schema.type === "ref" ? param.schema.schema : param.schema;
|
|
524
|
-
const formEncoded = !param.contentType || param.contentType.split(";")[0].trim().toLowerCase() === "application/x-www-form-urlencoded";
|
|
525
|
-
if (schema?.type !== "object" || !formEncoded) return [param];
|
|
526
|
-
return schema.properties.map((property) => _kubb_kit.ast.factory.createParameter({
|
|
527
|
-
name: property.name,
|
|
528
|
-
in: "query",
|
|
529
|
-
schema: property.schema,
|
|
530
|
-
required: param.required && property.required
|
|
531
|
-
}));
|
|
532
|
-
}
|
|
533
|
-
/**
|
|
534
|
-
* Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
|
|
535
|
-
* group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
|
|
536
|
-
* (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
|
|
537
|
-
* same parameters once per plugin.
|
|
538
|
-
*/
|
|
539
|
-
function getOperationParameters(node) {
|
|
540
|
-
const cached = operationParameterGroupsByNode.get(node);
|
|
541
|
-
if (cached) return cached;
|
|
542
|
-
const dedupe = (params) => {
|
|
543
|
-
const seen = /* @__PURE__ */ new Set();
|
|
544
|
-
return params.filter((param) => {
|
|
545
|
-
if (seen.has(param.name)) return false;
|
|
546
|
-
seen.add(param.name);
|
|
547
|
-
return true;
|
|
548
|
-
});
|
|
549
|
-
};
|
|
550
|
-
const group = (location) => dedupe(node.parameters.filter((param) => param.in === location));
|
|
551
|
-
const groups = {
|
|
552
|
-
path: group("path"),
|
|
553
|
-
query: dedupe([...group("query"), ...group("querystring").flatMap(spreadQuerystring)]),
|
|
554
|
-
header: group("header"),
|
|
555
|
-
cookie: group("cookie")
|
|
556
|
-
};
|
|
557
|
-
operationParameterGroupsByNode.set(node, groups);
|
|
558
|
-
return groups;
|
|
559
|
-
}
|
|
560
451
|
// ../../internals/shared/src/resolver.ts
|
|
561
452
|
/**
|
|
562
453
|
* Builds the allocation key for a declaration an operation owns. `scope` names which declaration
|
|
@@ -645,6 +536,13 @@ function createOperationResponseResolver() {
|
|
|
645
536
|
name
|
|
646
537
|
});
|
|
647
538
|
},
|
|
539
|
+
headers(node, statusCode) {
|
|
540
|
+
const name = this.name(`${node.operationId} Status ${statusCode} Headers`);
|
|
541
|
+
return this.resolveName({
|
|
542
|
+
key: operationKey(node, "response", "headers", statusCode),
|
|
543
|
+
name
|
|
544
|
+
});
|
|
545
|
+
},
|
|
648
546
|
body(node) {
|
|
649
547
|
const name = this.name(`${node.operationId} Body`);
|
|
650
548
|
return this.resolveName({
|
|
@@ -686,60 +584,13 @@ function createCasedFile(caseLast) {
|
|
|
686
584
|
* Names of the schemas in a circular reference chain, computed once per build.
|
|
687
585
|
*/
|
|
688
586
|
function getCircularNames(ctx) {
|
|
689
|
-
return ctx.memo("circularNames:set", () => _kubb_kit.ast.
|
|
690
|
-
}
|
|
691
|
-
// ../../internals/shared/src/group.ts
|
|
692
|
-
/**
|
|
693
|
-
* Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
|
|
694
|
-
* shared default naming so every plugin groups output consistently:
|
|
695
|
-
*
|
|
696
|
-
* - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
|
|
697
|
-
* - other groups use the camelCased group (`pet store` → `petStore`).
|
|
698
|
-
*
|
|
699
|
-
* A user-provided `group.name` always wins over the default namer, so callers stay in
|
|
700
|
-
* control of their output folders. Returns `null` when grouping is disabled, matching the
|
|
701
|
-
* per-plugin convention.
|
|
702
|
-
*
|
|
703
|
-
* @param group - The user-supplied group option, or `undefined` to disable grouping.
|
|
704
|
-
*
|
|
705
|
-
* @example
|
|
706
|
-
* ```ts
|
|
707
|
-
* createGroupConfig(group) // shared across every plugin
|
|
708
|
-
* ```
|
|
709
|
-
*/
|
|
710
|
-
function createGroupConfig(group) {
|
|
711
|
-
if (!group) return null;
|
|
712
|
-
const defaultName = (ctx) => {
|
|
713
|
-
if (group.type === "path") return `${ctx.group.split("/")[1]}`;
|
|
714
|
-
return (0, _kubb_kit.camelCase)(ctx.group);
|
|
715
|
-
};
|
|
716
|
-
return {
|
|
717
|
-
...group,
|
|
718
|
-
name: group.name ? group.name : defaultName
|
|
719
|
-
};
|
|
720
|
-
}
|
|
721
|
-
// ../../internals/shared/src/schemaTraversal.ts
|
|
722
|
-
/**
|
|
723
|
-
* Maps each member of a union or intersection schema to its transformed output, pairing every
|
|
724
|
-
* result with the original member.
|
|
725
|
-
*/
|
|
726
|
-
function mapSchemaMembers(node, transform) {
|
|
727
|
-
return (node.members ?? []).map((schema) => ({
|
|
728
|
-
schema,
|
|
729
|
-
output: transform(schema)
|
|
730
|
-
}));
|
|
731
|
-
}
|
|
732
|
-
/**
|
|
733
|
-
* Maps each item of an array or tuple schema to its transformed output, pairing every result with
|
|
734
|
-
* the original item.
|
|
735
|
-
*/
|
|
736
|
-
function mapSchemaItems(node, transform) {
|
|
737
|
-
return (node.items ?? []).map((schema) => ({
|
|
738
|
-
schema,
|
|
739
|
-
output: transform(schema)
|
|
740
|
-
}));
|
|
587
|
+
return ctx.memo("circularNames:set", () => _kubb_kit.ast.graph.getCircularNames(ctx.driver.inputNode?.schemas ?? []));
|
|
741
588
|
}
|
|
742
589
|
// src/utils.ts
|
|
590
|
+
/** The identifier a `dateParser` module is imported and called under: `my-date-lib` becomes `myDateLib`. */
|
|
591
|
+
function dateParserName(dateParser) {
|
|
592
|
+
return ensureValidVarName(_kubb_kit.casing.camel(dateParser));
|
|
593
|
+
}
|
|
743
594
|
/**
|
|
744
595
|
* Returns the `@faker-js/faker` named export for a locale code.
|
|
745
596
|
*
|
|
@@ -794,26 +645,29 @@ function canOverrideSchema(node) {
|
|
|
794
645
|
* Whether a schema can supply object properties when merging faker values.
|
|
795
646
|
*/
|
|
796
647
|
function isObjectSchema(node, seen = /* @__PURE__ */ new Set()) {
|
|
797
|
-
const resolved = _kubb_kit.ast.
|
|
648
|
+
const resolved = _kubb_kit.ast.ref.getSchema(node);
|
|
798
649
|
if (seen.has(resolved)) return false;
|
|
799
650
|
seen.add(resolved);
|
|
800
|
-
if (_kubb_kit.ast.
|
|
801
|
-
const composition = _kubb_kit.ast.
|
|
651
|
+
if (_kubb_kit.ast.schema.narrow(resolved, _kubb_kit.ast.schema.types.object) || _kubb_kit.ast.schema.narrow(resolved, _kubb_kit.ast.schema.types.ref)) return true;
|
|
652
|
+
const composition = _kubb_kit.ast.schema.narrow(resolved, _kubb_kit.ast.schema.types.intersection) ?? _kubb_kit.ast.schema.narrow(resolved, _kubb_kit.ast.schema.types.union);
|
|
802
653
|
if (!composition) return false;
|
|
803
|
-
return composition.type === _kubb_kit.ast.
|
|
654
|
+
return composition.type === _kubb_kit.ast.schema.types.intersection && !composition.members?.length || (composition.members ?? []).some((member) => isObjectSchema(member, seen));
|
|
804
655
|
}
|
|
805
656
|
function shouldInlineSingleResponseSchema(schema) {
|
|
806
657
|
return !NON_INLINABLE_RESPONSE_TYPES.has(schema.type);
|
|
807
658
|
}
|
|
808
659
|
/**
|
|
809
|
-
* Builds a response schema as a union of
|
|
660
|
+
* Builds a response schema as a union of the success response statuses, like the `<Operation>Response` type of
|
|
661
|
+
* `@kubb/plugin-ts`, so the mock never is an error body. Falls back to every response when no success response has a schema.
|
|
810
662
|
* Returns null if no responses are provided, or embeds single simple responses inline.
|
|
811
663
|
*/
|
|
812
664
|
function buildResponseUnionSchema(node, resolver) {
|
|
813
|
-
const
|
|
665
|
+
const withSchema = node.responses.map((response) => ({
|
|
814
666
|
...response,
|
|
815
667
|
content: response.content?.map((entry, _, content) => toResponseContent(entry, content))
|
|
816
668
|
})).filter((response) => response.content?.[0]?.schema);
|
|
669
|
+
const success = withSchema.filter((response) => _kubb_kit.ast.http.status.isSuccess(response));
|
|
670
|
+
const responses = success.length > 0 ? success : withSchema;
|
|
817
671
|
if (!responses.length) return null;
|
|
818
672
|
if (responses.length === 1) {
|
|
819
673
|
const schemas = responses[0].content?.flatMap((content) => content.schema ? [content.schema] : []) ?? [];
|
|
@@ -894,7 +748,7 @@ function getScalarType(node, typeName) {
|
|
|
894
748
|
* Determines the data type, return type, and whether it uses the type name.
|
|
895
749
|
*/
|
|
896
750
|
function resolveFakerTypeUsage(node, typeName, canOverride) {
|
|
897
|
-
const resolvedNode = _kubb_kit.ast.
|
|
751
|
+
const resolvedNode = _kubb_kit.ast.ref.getSchema(node);
|
|
898
752
|
const scalarType = SCALAR_TYPES.has(resolvedNode.type) ? `${getScalarType(resolvedNode, typeName)}${node.nullable || resolvedNode.nullable ? " | null" : ""}` : void 0;
|
|
899
753
|
const dataType = scalarType ?? `Partial<${typeName}>`;
|
|
900
754
|
const returnType = scalarType ?? (canOverride ? typeName : null);
|
|
@@ -913,8 +767,8 @@ function Faker({ node, description, name, typeName, printer, canOverride, typeMo
|
|
|
913
767
|
imp.name
|
|
914
768
|
].join("-")));
|
|
915
769
|
const isArray = node.type === "array";
|
|
916
|
-
const isObject = !!_kubb_kit.ast.
|
|
917
|
-
const isValueIntersection = node.type === _kubb_kit.ast.
|
|
770
|
+
const isObject = !!_kubb_kit.ast.schema.narrow(node, _kubb_kit.ast.schema.types.object) || node.type === _kubb_kit.ast.schema.types.intersection && isObjectSchema(node);
|
|
771
|
+
const isValueIntersection = node.type === _kubb_kit.ast.schema.types.intersection && !isObject;
|
|
918
772
|
const isTuple = node.type === "tuple";
|
|
919
773
|
const isScalar = SCALAR_TYPES.has(node.type);
|
|
920
774
|
const isUnion = node.type === "union";
|
|
@@ -923,13 +777,14 @@ function Faker({ node, description, name, typeName, printer, canOverride, typeMo
|
|
|
923
777
|
if (canOverride && node.type === "tuple") return `data && data.length === ${node.items?.length ?? 0} && !data.includes(undefined) ? data : ${fakerText}`;
|
|
924
778
|
if (canOverride && isArray) return `[\n ...${fakerText},\n ...(data || []).filter((item) => item !== undefined),\n]`;
|
|
925
779
|
if (canOverride && (isScalar || isUnion || isValueIntersection)) return node.nullable ? `data !== undefined ? data : ${fakerText}` : `data ?? ${fakerText}`;
|
|
780
|
+
if (canOverride && node.type === "ref" && node.nullable && SCALAR_TYPES.has(_kubb_kit.ast.ref.getSchema(node).type)) return `data === null ? data : ${fakerText}`;
|
|
926
781
|
return fakerText;
|
|
927
782
|
})();
|
|
928
783
|
const { dataType, returnType: resolvedReturnType } = resolveFakerTypeUsage(node, typeName, canOverride);
|
|
929
784
|
if (!useObjectOverride) {
|
|
930
785
|
const paramsSignature = `${/\bdata\b/.test(fakerTextWithOverride) ? "data" : "_data"}?: ${dataType}`;
|
|
931
786
|
const returnType = resolvedReturnType;
|
|
932
|
-
const returnExpression = canOverride && !!returnType && (node.type === "ref" && !SCALAR_TYPES.has(_kubb_kit.ast.
|
|
787
|
+
const returnExpression = canOverride && !!returnType && (node.type === "ref" && !SCALAR_TYPES.has(_kubb_kit.ast.ref.getSchema(node).type) || isArray || isTuple || isUnion) ? `${isTuple || isUnion ? `(${fakerTextWithOverride})` : fakerTextWithOverride} as ${returnType}` : fakerTextWithOverride;
|
|
933
788
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [imports, /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
934
789
|
name,
|
|
935
790
|
isExportable: true,
|
|
@@ -947,10 +802,11 @@ function Faker({ node, description, name, typeName, printer, canOverride, typeMo
|
|
|
947
802
|
const { cyclicSchemas, schemaName } = printer.options;
|
|
948
803
|
const isCyclic = !!schemaName && !!cyclicSchemas?.has(schemaName);
|
|
949
804
|
const returnType = typeMode === "schema" ? typeName : `Omit<${isCyclic ? typeName : "typeof defaultFakeData"}, keyof NoInfer<TData>> & NoInfer<TData>`;
|
|
950
|
-
const hasGetters = node.type === "object" && !!cyclicSchemas && (node.properties ?? []).some((p) =>
|
|
805
|
+
const hasGetters = node.type === "object" && !!cyclicSchemas && (node.properties ?? []).some((p) => _kubb_kit.ast.graph.containsCircular(p.schema, {
|
|
951
806
|
circularSchemas: cyclicSchemas,
|
|
952
807
|
excludeName: schemaName
|
|
953
808
|
}));
|
|
809
|
+
const castThroughUnknown = (node.type !== "object" || node.min !== void 0) && typeMode !== "schema";
|
|
954
810
|
const declaration = `const ${keysToOmit?.length ? `{ ${keysToOmit.map((key, index) => `${objectKey(key)}: _omit${index}`).join(", ")}, ...defaultFakeData }` : "defaultFakeData"} = ${fakerText}`;
|
|
955
811
|
const functionBody = hasGetters ? `${declaration}
|
|
956
812
|
if (data) {
|
|
@@ -962,7 +818,7 @@ return defaultFakeData as ${returnType}` : `${declaration}
|
|
|
962
818
|
return {
|
|
963
819
|
...defaultFakeData,
|
|
964
820
|
...(data || {}),
|
|
965
|
-
} as ${returnType}`;
|
|
821
|
+
} as ${castThroughUnknown ? "unknown as " : ""}${returnType}`;
|
|
966
822
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [imports, /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
967
823
|
name,
|
|
968
824
|
isExportable: true,
|
|
@@ -1039,18 +895,45 @@ const integerFormats = /* @__PURE__ */ new Set([
|
|
|
1039
895
|
"uint64"
|
|
1040
896
|
]);
|
|
1041
897
|
const maxInt32 = 2147483647;
|
|
898
|
+
const maxValueByFormat = {
|
|
899
|
+
int32: maxInt32,
|
|
900
|
+
uint32: 4294967295
|
|
901
|
+
};
|
|
902
|
+
function isCyclicRef(node, { schemaName, cyclicSchemas }) {
|
|
903
|
+
if (node.type !== "ref" || !schemaName) return false;
|
|
904
|
+
const refName = _kubb_kit.ast.ref.getName(node);
|
|
905
|
+
return refName === schemaName || Boolean(refName && cyclicSchemas?.has(schemaName) && cyclicSchemas.has(refName));
|
|
906
|
+
}
|
|
1042
907
|
/**
|
|
1043
|
-
* `faker.number.float()` or `faker.number.
|
|
908
|
+
* `faker.number.float()`, `faker.number.int()` or `faker.number.bigInt()`, with `min` and `max` passed only when set,
|
|
909
|
+
* moved inside an exclusive bound, or needed so a lone bound does not contradict faker's default for the other.
|
|
1044
910
|
*/
|
|
1045
|
-
function numberCall(kind, min, max) {
|
|
1046
|
-
const
|
|
911
|
+
function numberCall(kind, { min, max, exclusive, multipleOf }) {
|
|
912
|
+
const isWhole = kind !== "float";
|
|
913
|
+
const grid = isWhole && !Number.isInteger(multipleOf) ? void 0 : multipleOf;
|
|
914
|
+
const { min: lower, max: upper } = _kubb_kit.ast.schema.getNumberBounds({
|
|
915
|
+
min,
|
|
916
|
+
max,
|
|
917
|
+
exclusive,
|
|
918
|
+
integer: isWhole,
|
|
919
|
+
step: grid
|
|
920
|
+
});
|
|
921
|
+
const span = 100 * (grid ?? 1);
|
|
922
|
+
const maxValue = kind === "float" && lower !== void 0 && upper === void 0 && (lower >= 1 || grid !== void 0) ? lower + span : upper;
|
|
923
|
+
const minValue = maxValue !== void 0 && lower === void 0 && (isWhole ? maxValue < 0 : maxValue <= 0) ? maxValue - span : lower;
|
|
924
|
+
const suffix = kind === "bigInt" ? "n" : "";
|
|
925
|
+
const args = [
|
|
926
|
+
minValue !== void 0 && `min: ${minValue}${suffix}`,
|
|
927
|
+
maxValue !== void 0 && `max: ${maxValue}${suffix}`,
|
|
928
|
+
grid !== void 0 && `multipleOf: ${grid}${suffix}`
|
|
929
|
+
].filter(Boolean).join(", ");
|
|
1047
930
|
return `faker.number.${kind}(${args ? `{ ${args} }` : ""})`;
|
|
1048
931
|
}
|
|
1049
932
|
/**
|
|
1050
933
|
* A `date` or `time` value: an ISO substring, a `dateParser` call, or a `Date` when `representation` is `'date'`.
|
|
1051
934
|
*/
|
|
1052
935
|
function dateTimeCall(representation, { format, substring }, parser = "faker", schemaName) {
|
|
1053
|
-
if (representation === "string") return parser !== "faker" ? `${parser}(faker.date.anytime()).format("${format}")` : `faker.date.anytime().toISOString().substring(${substring})`;
|
|
936
|
+
if (representation === "string") return parser !== "faker" ? `${dateParserName(parser)}(faker.date.anytime()).format("${format}")` : `faker.date.anytime().toISOString().substring(${substring})`;
|
|
1054
937
|
if (parser !== "faker") throw new _kubb_kit.Diagnostics.Error({
|
|
1055
938
|
code: _kubb_kit.Diagnostics.code.invalidPluginOptions,
|
|
1056
939
|
severity: "error",
|
|
@@ -1061,12 +944,58 @@ function dateTimeCall(representation, { format, substring }, parser = "faker", s
|
|
|
1061
944
|
});
|
|
1062
945
|
return "faker.date.anytime()";
|
|
1063
946
|
}
|
|
947
|
+
const encodingCalls = /* @__PURE__ */ new Map([["base64", "btoa(faker.string.alpha())"], ["base64url", "faker.string.alphanumeric(8)"]]);
|
|
948
|
+
const stringFormatCalls = /* @__PURE__ */ new Map([
|
|
949
|
+
["jwt", "faker.internet.jwt()"],
|
|
950
|
+
["ulid", "faker.string.ulid()"],
|
|
951
|
+
["iban", "faker.finance.iban()"],
|
|
952
|
+
["duration", "'P1D'"],
|
|
953
|
+
["hostname", "faker.internet.domainName()"]
|
|
954
|
+
]);
|
|
955
|
+
const classEscapes = new Map([
|
|
956
|
+
["d", "0-9"],
|
|
957
|
+
["w", "A-Za-z0-9_"],
|
|
958
|
+
...Array.from("-!@#$&()`.+,\"", (char) => [char, char])
|
|
959
|
+
]);
|
|
960
|
+
function toFakerPattern(pattern) {
|
|
961
|
+
let result = "";
|
|
962
|
+
let inClass = false;
|
|
963
|
+
let classStart = -1;
|
|
964
|
+
for (let index = 0; index < pattern.length; index++) {
|
|
965
|
+
const char = pattern[index];
|
|
966
|
+
const next = pattern[index + 1];
|
|
967
|
+
if (char === "\\" && next !== void 0) {
|
|
968
|
+
index++;
|
|
969
|
+
if (inClass && next === "-") {
|
|
970
|
+
if (result[classStart] !== "-") result = `${result.slice(0, classStart)}-${result.slice(classStart)}`;
|
|
971
|
+
continue;
|
|
972
|
+
}
|
|
973
|
+
const classMembers = classEscapes.get(next);
|
|
974
|
+
if (classMembers === void 0) {
|
|
975
|
+
result += `\\${next}`;
|
|
976
|
+
continue;
|
|
977
|
+
}
|
|
978
|
+
result += inClass ? classMembers : `[${classMembers}]`;
|
|
979
|
+
continue;
|
|
980
|
+
}
|
|
981
|
+
if (char === "[" && !inClass) {
|
|
982
|
+
inClass = true;
|
|
983
|
+
result += next === "^" ? "[^" : "[";
|
|
984
|
+
if (next === "^") index++;
|
|
985
|
+
classStart = result.length;
|
|
986
|
+
continue;
|
|
987
|
+
}
|
|
988
|
+
if (char === "]") inClass = false;
|
|
989
|
+
result += char;
|
|
990
|
+
}
|
|
991
|
+
return result.replace(/\{(\d+),\}/g, (_, min) => `{${min},${Number(min) + 10}}`);
|
|
992
|
+
}
|
|
1064
993
|
function matches(value, regexGenerator = "faker") {
|
|
1065
994
|
if (regexGenerator === "randexp") return `${toRegExpString(value, "RandExp")}.gen()`;
|
|
1066
|
-
return `faker.helpers.fromRegExp(${toRegExpString(value, null)})`;
|
|
995
|
+
return `faker.helpers.fromRegExp(${toRegExpString(toFakerPattern(value), null)})`;
|
|
1067
996
|
}
|
|
1068
997
|
function parseEnumValue(value) {
|
|
1069
|
-
if (typeof value === "string") return
|
|
998
|
+
if (typeof value === "string") return _kubb_kit.text.quote(value);
|
|
1070
999
|
return value;
|
|
1071
1000
|
}
|
|
1072
1001
|
/**
|
|
@@ -1077,11 +1006,11 @@ function parseEnumValue(value) {
|
|
|
1077
1006
|
* (a `ref` to the enum shared by every branch, say) identifies no branch and narrows nothing.
|
|
1078
1007
|
*/
|
|
1079
1008
|
function getDiscriminator(member, discriminatorPropertyName) {
|
|
1080
|
-
for (const property of _kubb_kit.ast.
|
|
1009
|
+
for (const property of _kubb_kit.ast.schema.findProperties({
|
|
1081
1010
|
node: member,
|
|
1082
1011
|
propertyName: discriminatorPropertyName
|
|
1083
1012
|
})) {
|
|
1084
|
-
const values = _kubb_kit.ast.
|
|
1013
|
+
const values = _kubb_kit.ast.schema.getLiterals(property.schema);
|
|
1085
1014
|
if (values.length === 1) return {
|
|
1086
1015
|
value: values[0],
|
|
1087
1016
|
required: property.required
|
|
@@ -1098,11 +1027,14 @@ function indexedTypeName(typeName, propertyName, nestedInUnion) {
|
|
|
1098
1027
|
const key = JSON.stringify(propertyName);
|
|
1099
1028
|
return nestedInUnion ? `(NonNullable<${typeName}> & Record<${key}, unknown>)[${key}]` : `NonNullable<${typeName}>[${key}]`;
|
|
1100
1029
|
}
|
|
1030
|
+
function itemTypeName(typeName, nestedInUnion) {
|
|
1031
|
+
return nestedInUnion ? `Extract<NonNullable<${typeName}>, ReadonlyArray<unknown>>[number]` : `NonNullable<${typeName}>[number]`;
|
|
1032
|
+
}
|
|
1101
1033
|
/**
|
|
1102
1034
|
* Creates a Faker printer that generates mock data generation code from schema nodes.
|
|
1103
1035
|
* Handles circular references gracefully by emitting memoizing getters for cyclic properties.
|
|
1104
1036
|
*/
|
|
1105
|
-
const printerFaker = _kubb_kit.
|
|
1037
|
+
const printerFaker = (0, _kubb_kit.createPrinter)((options) => {
|
|
1106
1038
|
const printNested = (node, overrideOptions = {}) => {
|
|
1107
1039
|
return printerFaker({
|
|
1108
1040
|
...options,
|
|
@@ -1122,22 +1054,38 @@ const printerFaker = _kubb_kit.ast.createPrinter((options) => {
|
|
|
1122
1054
|
string(node) {
|
|
1123
1055
|
if (node.pattern) return matches(node.pattern, this.options.regexGenerator);
|
|
1124
1056
|
if (node.format && integerFormats.has(node.format)) return node.format === "int32" ? `faker.number.int({ max: ${maxInt32} }).toString()` : "faker.number.bigInt().toString()";
|
|
1057
|
+
const formatCall = stringFormatCalls.get(node.format);
|
|
1058
|
+
if (formatCall) return formatCall;
|
|
1059
|
+
const contentSchema = _kubb_kit.ast.schema.getEmbeddedJson(node);
|
|
1060
|
+
if (contentSchema) return `JSON.stringify(${printNested(contentSchema, {
|
|
1061
|
+
typeName: void 0,
|
|
1062
|
+
nestedInObject: true,
|
|
1063
|
+
nestedInUnion: false
|
|
1064
|
+
})})`;
|
|
1065
|
+
const encodingCall = encodingCalls.get(node.content?.encoding?.toLowerCase());
|
|
1066
|
+
if (encodingCall) return encodingCall;
|
|
1125
1067
|
const { min, max } = node;
|
|
1126
|
-
if (
|
|
1127
|
-
if (
|
|
1068
|
+
if (max !== void 0) return `faker.string.alpha({ length: { min: ${min ?? Math.min(1, max)}, max: ${Math.min(max, (min ?? 0) + 100)} } })`;
|
|
1069
|
+
if (min !== void 0) return `faker.string.alpha({ length: ${min} })`;
|
|
1128
1070
|
return "faker.string.alpha()";
|
|
1129
1071
|
},
|
|
1130
1072
|
email: () => "faker.internet.email()",
|
|
1131
1073
|
url: () => "faker.internet.url()",
|
|
1132
1074
|
uuid: () => "faker.string.uuid()",
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1075
|
+
ipv4: () => "faker.internet.ipv4()",
|
|
1076
|
+
ipv6: () => "faker.internet.ipv6()",
|
|
1077
|
+
number: (node) => numberCall("float", node),
|
|
1078
|
+
integer: (node) => numberCall("int", node.format && node.format in maxValueByFormat ? {
|
|
1079
|
+
...node,
|
|
1080
|
+
max: Math.min(node.max ?? Infinity, maxValueByFormat[node.format])
|
|
1081
|
+
} : node),
|
|
1082
|
+
bigint: (node) => numberCall("bigInt", node),
|
|
1083
|
+
blob: () => "new Blob([faker.string.alpha()])",
|
|
1137
1084
|
datetime(node) {
|
|
1138
1085
|
const parser = this.options.dateParser ?? "faker";
|
|
1139
1086
|
if (parser === "faker") return "faker.date.anytime().toISOString()";
|
|
1140
|
-
|
|
1087
|
+
const format = node.local ? "YYYY-MM-DDTHH:mm:ss" : node.offset ? "YYYY-MM-DDTHH:mm:ssZ" : "YYYY-MM-DDTHH:mm:ss[Z]";
|
|
1088
|
+
return `${dateParserName(parser)}(faker.date.anytime()).format("${format}")`;
|
|
1141
1089
|
},
|
|
1142
1090
|
date(node) {
|
|
1143
1091
|
return dateTimeCall(node.representation ?? "string", {
|
|
@@ -1152,28 +1100,30 @@ const printerFaker = _kubb_kit.ast.createPrinter((options) => {
|
|
|
1152
1100
|
}, this.options.dateParser, this.options.schemaName);
|
|
1153
1101
|
},
|
|
1154
1102
|
ref(node) {
|
|
1155
|
-
const refName = _kubb_kit.ast.
|
|
1103
|
+
const refName = _kubb_kit.ast.ref.getName(node);
|
|
1156
1104
|
if (!refName) throw new _kubb_kit.Diagnostics.Error({
|
|
1157
1105
|
code: _kubb_kit.Diagnostics.code.pluginFailed,
|
|
1158
1106
|
severity: "error",
|
|
1159
1107
|
message: `Ref node "${node.ref ?? node.name ?? "unknown"}"${this.options.schemaName ? ` in schema "${this.options.schemaName}"` : ""} has no name.`,
|
|
1160
1108
|
plugin: "plugin-faker"
|
|
1161
1109
|
});
|
|
1162
|
-
if (
|
|
1110
|
+
if (isCyclicRef(node, this.options)) return this.options.typeName ? `undefined as unknown as ${this.options.typeName}` : "undefined as unknown";
|
|
1163
1111
|
const resolvedName = node.ref ? this.options.resolver.name(refName) : refName;
|
|
1164
|
-
if (!this.options.nestedInObject && canOverrideSchema(_kubb_kit.ast.
|
|
1112
|
+
if (!this.options.nestedInObject && canOverrideSchema(_kubb_kit.ast.ref.getSchema(node))) return `${resolvedName}(data)`;
|
|
1165
1113
|
return `${resolvedName}()`;
|
|
1166
1114
|
},
|
|
1167
1115
|
enum(node) {
|
|
1168
1116
|
const { typeName } = this.options;
|
|
1169
|
-
const values = _kubb_kit.ast.
|
|
1117
|
+
const values = _kubb_kit.ast.schema.getLiterals(node);
|
|
1170
1118
|
if (values.length === 1 && values[0] !== null && typeof values[0] === "object") return JSON.stringify(values[0]);
|
|
1171
|
-
return `faker.helpers.arrayElement
|
|
1119
|
+
return `faker.helpers.arrayElement([${values.map(parseEnumValue).join(", ")}]${typeName ? ` as Array<${typeName}>` : ""})`;
|
|
1172
1120
|
},
|
|
1173
1121
|
union(node) {
|
|
1174
1122
|
const { discriminatorPropertyName } = node;
|
|
1175
1123
|
const baseTypeName = this.options.typeName;
|
|
1176
|
-
|
|
1124
|
+
const isCyclicMember = (member) => isCyclicRef(member, this.options) || member.type === "intersection" && (member.members ?? []).some((part) => isCyclicRef(part, this.options));
|
|
1125
|
+
const acyclicMembers = (node.members ?? []).filter((member) => !isCyclicMember(member));
|
|
1126
|
+
return `faker.helpers.arrayElement([${((acyclicMembers.length ? acyclicMembers : node.members) ?? []).map((member) => {
|
|
1177
1127
|
const discriminator = discriminatorPropertyName ? getDiscriminator(member, discriminatorPropertyName) : void 0;
|
|
1178
1128
|
if (baseTypeName && discriminator) {
|
|
1179
1129
|
const key = `${JSON.stringify(discriminatorPropertyName)}${discriminator.required ? "" : "?"}`;
|
|
@@ -1189,29 +1139,31 @@ const printerFaker = _kubb_kit.ast.createPrinter((options) => {
|
|
|
1189
1139
|
nestedInObject: true,
|
|
1190
1140
|
nestedInUnion: true
|
|
1191
1141
|
});
|
|
1192
|
-
}).
|
|
1142
|
+
}).filter((item) => Boolean(item)).join(", ")}])`;
|
|
1193
1143
|
},
|
|
1194
1144
|
intersection(node) {
|
|
1195
1145
|
const objectMembers = (node.members ?? []).filter((member) => isObjectSchema(member));
|
|
1196
|
-
const
|
|
1197
|
-
const items =
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
}
|
|
1146
|
+
const memberRank = (member) => member.type === "ref" ? 0 : member.type === "union" ? 2 : 1;
|
|
1147
|
+
const items = ((objectMembers.length ? objectMembers.toSorted((a, b) => memberRank(a) - memberRank(b)) : node.members) ?? []).map((member) => printNested(member, {
|
|
1148
|
+
nestedInObject: true,
|
|
1149
|
+
...member.type === "ref" && _kubb_kit.ast.ref.getName(member) !== this.options.schemaName ? { cyclicSchemas: void 0 } : {}
|
|
1150
|
+
})).filter((item) => Boolean(item) && item !== "undefined");
|
|
1201
1151
|
if (items.length === 0) return "{}";
|
|
1202
1152
|
return !objectMembers.length || items.length === 1 ? items.at(-1) : `{...${items.join(", ...")}}`;
|
|
1203
1153
|
},
|
|
1204
1154
|
array(node) {
|
|
1205
|
-
|
|
1206
|
-
|
|
1155
|
+
if (node.items?.length === 1 && isCyclicRef(node.items[0], this.options)) return this.options.typeName ? `[] as ${this.options.typeName}` : "[]";
|
|
1156
|
+
const items = (node.items ?? []).map((member) => printNested(member, {
|
|
1157
|
+
typeName: this.options.typeName ? itemTypeName(this.options.typeName, this.options.nestedInUnion) : void 0,
|
|
1207
1158
|
nestedInObject: true
|
|
1208
|
-
})).
|
|
1159
|
+
})).filter((item) => Boolean(item));
|
|
1209
1160
|
if (items.length > 1) return `faker.helpers.arrayElements([${items.join(", ")}])`;
|
|
1210
1161
|
const { min, max } = node;
|
|
1211
1162
|
const item = items[0];
|
|
1212
|
-
|
|
1163
|
+
const countRange = max === void 0 ? void 0 : `{ min: ${min ?? 0}, max: ${Math.min(max, (min ?? 0) + 100)} }`;
|
|
1164
|
+
if (node.unique) return `faker.helpers.uniqueArray(() => (${item}), ${countRange ? `faker.number.int(${countRange})` : min ?? 3})`;
|
|
1165
|
+
if (countRange) return `faker.helpers.multiple(() => (${item}), { count: ${countRange}})`;
|
|
1213
1166
|
if (min !== void 0) return `faker.helpers.multiple(() => (${item}), { count: ${min} })`;
|
|
1214
|
-
if (max !== void 0) return `faker.helpers.multiple(() => (${item}), { count: { min: 0, max: ${max} }})`;
|
|
1215
1167
|
return `faker.helpers.multiple(() => (${item}))`;
|
|
1216
1168
|
},
|
|
1217
1169
|
tuple(node) {
|
|
@@ -1222,18 +1174,30 @@ const printerFaker = _kubb_kit.ast.createPrinter((options) => {
|
|
|
1222
1174
|
},
|
|
1223
1175
|
object(node) {
|
|
1224
1176
|
const cyclicSchemas = this.options.cyclicSchemas;
|
|
1225
|
-
const keySchema = node.propertyNames &&
|
|
1177
|
+
const keySchema = node.propertyNames && _kubb_kit.ast.ref.mergeSchema(node.propertyNames);
|
|
1226
1178
|
const valueSchema = node.additionalProperties;
|
|
1227
|
-
const recordProperties = keySchema?.type === "enum" && typeof valueSchema === "object" ? _kubb_kit.ast.
|
|
1179
|
+
const recordProperties = keySchema?.type === "enum" && typeof valueSchema === "object" ? _kubb_kit.ast.schema.getLiterals(keySchema).filter((key) => typeof key === "string" && !node.properties.some((property) => property.name === key)).map((name) => _kubb_kit.ast.factory.createProperty({
|
|
1228
1180
|
name,
|
|
1229
1181
|
schema: valueSchema
|
|
1230
1182
|
})) : [];
|
|
1231
|
-
|
|
1183
|
+
const properties = [...node.properties, ...recordProperties];
|
|
1184
|
+
const keptProperties = node.max === void 0 ? properties : properties.toSorted((a, b) => Number(b.required) - Number(a.required)).slice(0, node.max);
|
|
1185
|
+
const declaredNames = new Set(properties.map((property) => property.name));
|
|
1186
|
+
const extras = [];
|
|
1187
|
+
for (let index = 1; typeof valueSchema === "object" && keptProperties.length + extras.length < (node.min ?? 0); index++) {
|
|
1188
|
+
const name = `additionalProperty${index}`;
|
|
1189
|
+
if (!declaredNames.has(name)) extras.push(_kubb_kit.ast.factory.createProperty({
|
|
1190
|
+
name,
|
|
1191
|
+
schema: valueSchema
|
|
1192
|
+
}));
|
|
1193
|
+
}
|
|
1194
|
+
return buildObject([...keptProperties, ...extras].map((property) => {
|
|
1232
1195
|
const value = printNested(property.schema, {
|
|
1233
1196
|
typeName: this.options.typeName ? indexedTypeName(this.options.typeName, property.name, this.options.nestedInUnion) : void 0,
|
|
1234
|
-
nestedInObject: true
|
|
1197
|
+
nestedInObject: true,
|
|
1198
|
+
...property.required && property.schema.type === "ref" ? { cyclicSchemas: void 0 } : {}
|
|
1235
1199
|
}) ?? "undefined";
|
|
1236
|
-
if (cyclicSchemas &&
|
|
1200
|
+
if (cyclicSchemas && _kubb_kit.ast.graph.containsCircular(property.schema, {
|
|
1237
1201
|
circularSchemas: cyclicSchemas,
|
|
1238
1202
|
excludeName: this.options.schemaName
|
|
1239
1203
|
})) 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 }`;
|
|
@@ -1261,7 +1225,7 @@ const fakerGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
1261
1225
|
if (!node.name) return;
|
|
1262
1226
|
const tsResolver = ctx.driver.getResolver(_kubb_plugin_ts.pluginTsName);
|
|
1263
1227
|
const schemaName = node.name;
|
|
1264
|
-
const isEnumSchema = !!_kubb_kit.ast.
|
|
1228
|
+
const isEnumSchema = !!_kubb_kit.ast.schema.narrow(node, _kubb_kit.ast.schema.types.enum);
|
|
1265
1229
|
const schemaTypeName = (0, _kubb_plugin_ts.enumTypeName)({
|
|
1266
1230
|
resolver: tsResolver,
|
|
1267
1231
|
name: schemaName,
|
|
@@ -1310,7 +1274,8 @@ const fakerGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
1310
1274
|
node,
|
|
1311
1275
|
root,
|
|
1312
1276
|
output,
|
|
1313
|
-
group: group ?? void 0
|
|
1277
|
+
group: group ?? void 0,
|
|
1278
|
+
checks: true
|
|
1314
1279
|
}), fakerText);
|
|
1315
1280
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
|
|
1316
1281
|
baseName: meta.file.baseName,
|
|
@@ -1346,7 +1311,7 @@ const fakerGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
1346
1311
|
}),
|
|
1347
1312
|
dateParser !== "faker" && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1348
1313
|
path: dateParser,
|
|
1349
|
-
name: dateParser
|
|
1314
|
+
name: dateParserName(dateParser)
|
|
1350
1315
|
}),
|
|
1351
1316
|
typeReference.importPath && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1352
1317
|
isTypeOnly: true,
|
|
@@ -1363,7 +1328,7 @@ const fakerGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
1363
1328
|
imp.path,
|
|
1364
1329
|
imp.name
|
|
1365
1330
|
].join("-"))),
|
|
1366
|
-
seed ? /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
1331
|
+
seed !== void 0 ? /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
1367
1332
|
name: "faker-seed",
|
|
1368
1333
|
children: `faker.seed(${JSON.stringify(seed)})`
|
|
1369
1334
|
}) : void 0,
|
|
@@ -1384,7 +1349,7 @@ const fakerGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
1384
1349
|
const { output, group, dateParser, regexGenerator, seed, locale, printer, typeMode } = ctx.options;
|
|
1385
1350
|
const pluginTs = ctx.requirePlugin(_kubb_plugin_ts.pluginTsName);
|
|
1386
1351
|
const tsResolver = ctx.driver.getResolver(_kubb_plugin_ts.pluginTsName);
|
|
1387
|
-
const { path: pathParams, query: queryParams, header: headerParams, cookie: cookieParams } =
|
|
1352
|
+
const { path: pathParams, query: queryParams, header: headerParams, cookie: cookieParams } = _kubb_kit.ast.http.groupParameters(node);
|
|
1388
1353
|
const paramGroups = [
|
|
1389
1354
|
{
|
|
1390
1355
|
params: pathParams,
|
|
@@ -1453,7 +1418,7 @@ const fakerGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
1453
1418
|
description: node.requestBody?.description ?? schema.description
|
|
1454
1419
|
}));
|
|
1455
1420
|
const responseName = resolver.response.response(node);
|
|
1456
|
-
const hasResponseNameCollision = new Set(
|
|
1421
|
+
const hasResponseNameCollision = new Set(_kubb_kit.ast.http.responses.getImportedNames(node.responses).map((name) => resolver.name(name))).has(responseName);
|
|
1457
1422
|
const localHelperNames = /* @__PURE__ */ new Set([
|
|
1458
1423
|
...paramGroups.map((group) => group.name),
|
|
1459
1424
|
...responseUnits.map((unit) => unit.name),
|
|
@@ -1484,12 +1449,13 @@ const fakerGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
1484
1449
|
node: schema,
|
|
1485
1450
|
root,
|
|
1486
1451
|
output,
|
|
1487
|
-
group: group ?? void 0
|
|
1452
|
+
group: group ?? void 0,
|
|
1453
|
+
checks: true
|
|
1488
1454
|
}).filter((entry) => entry.path !== meta.file.path);
|
|
1489
1455
|
}
|
|
1490
1456
|
function renderEntry({ schema, name, typeName, description, keysToOmit, skipImportNames = [] }) {
|
|
1491
1457
|
if (!schema) return null;
|
|
1492
|
-
if (schema.type === _kubb_kit.ast.
|
|
1458
|
+
if (schema.type === _kubb_kit.ast.schema.types.object && keysToOmit?.length) {
|
|
1493
1459
|
schema = {
|
|
1494
1460
|
...schema,
|
|
1495
1461
|
properties: schema.properties.filter((property) => !keysToOmit?.includes(property.name))
|
|
@@ -1583,9 +1549,9 @@ const fakerGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
1583
1549
|
}),
|
|
1584
1550
|
dateParser !== "faker" && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1585
1551
|
path: dateParser,
|
|
1586
|
-
name: dateParser
|
|
1552
|
+
name: dateParserName(dateParser)
|
|
1587
1553
|
}),
|
|
1588
|
-
seed ? /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
1554
|
+
seed !== void 0 ? /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
1589
1555
|
name: "faker-seed",
|
|
1590
1556
|
children: `faker.seed(${JSON.stringify(seed)})`
|
|
1591
1557
|
}) : void 0,
|
|
@@ -1604,11 +1570,11 @@ const fakerGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
1604
1570
|
});
|
|
1605
1571
|
// kubb-extension.json
|
|
1606
1572
|
var compatibility = {
|
|
1607
|
-
"kubb": ">=5.
|
|
1573
|
+
"kubb": ">=5.18.4",
|
|
1608
1574
|
"node": ">=22.22"
|
|
1609
1575
|
};
|
|
1610
1576
|
// package.json
|
|
1611
|
-
var version = "5.4.
|
|
1577
|
+
var version = "5.4.1";
|
|
1612
1578
|
// src/resolvers/resolverFaker.ts
|
|
1613
1579
|
/**
|
|
1614
1580
|
* Default resolver used by `@kubb/plugin-faker`. Decides the names and file
|
|
@@ -1625,9 +1591,9 @@ var version = "5.4.0-canary.20261111T122006";
|
|
|
1625
1591
|
const resolverFaker = (0, _kubb_kit.createResolver)({
|
|
1626
1592
|
pluginName: "plugin-faker",
|
|
1627
1593
|
name(name) {
|
|
1628
|
-
return this.memo(`name:${name}`, () => ensureValidVarName(
|
|
1594
|
+
return this.memo(`name:${name}`, () => ensureValidVarName(_kubb_kit.casing.camel(name, { prefix: "create" })));
|
|
1629
1595
|
},
|
|
1630
|
-
file: createCasedFile((part) =>
|
|
1596
|
+
file: createCasedFile((part) => _kubb_kit.casing.camel(part, { prefix: "create" })),
|
|
1631
1597
|
param: createOperationParamResolver(),
|
|
1632
1598
|
response: createOperationResponseResolver()
|
|
1633
1599
|
});
|
|
@@ -1685,7 +1651,7 @@ const pluginFaker = (0, _kubb_kit.defineExtension)({
|
|
|
1685
1651
|
include,
|
|
1686
1652
|
override,
|
|
1687
1653
|
typeMode,
|
|
1688
|
-
group:
|
|
1654
|
+
group: group ?? null,
|
|
1689
1655
|
dateParser,
|
|
1690
1656
|
regexGenerator,
|
|
1691
1657
|
printer
|