@kubb/plugin-faker 5.4.0-canary.20261111T122006 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -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/strings.ts
149
+ // ../../internals/utils/src/codegen.ts
150
150
  /**
151
- * Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping
152
- * any backslash or single quote in the content.
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
- * singleQuote('foo') // "'foo'"
157
- * singleQuote("o'clock") // "'o\\'clock'"
157
+ * buildObject(['id: z.number()', 'name: z.string()'])
158
+ * // '{\n id: z.number(),\n name: z.string(),\n}'
158
159
  * ```
159
160
  */
160
- function singleQuote(value) {
161
- if (value === void 0 || value === null) return "''";
162
- return `'${String(value).replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
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
- * Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`.
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
- * trimQuotes('"hello"') // 'hello'
171
- * trimQuotes('hello') // 'hello'
170
+ * objectKey('x-total') // "'x-total'"
172
171
  * ```
173
172
  */
174
- function trimQuotes(text) {
175
- if (text.length >= 2) {
176
- const first = text[0];
177
- const last = text[text.length - 1];
178
- if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1);
179
- }
180
- return text;
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
- * Serializes a primitive to a single-quoted string literal, stripping any surrounding quotes first.
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
- * stringify('hello') // "'hello'"
191
- * stringify('"hello"') // "'hello'"
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 stringify(value) {
195
- if (value === void 0 || value === null) return "''";
196
- return `'${JSON.stringify(trimQuotes(value.toString())).slice(1, -1).replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`;
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
- * Escapes an `@` at the start of a line, so a multi-line description can't start a new JSDoc tag.
200
- * Editors render `\@` as `@` in hovers.
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
- * @example
203
- * ```ts
204
- * jsDocEscape('intro\n@example value') // 'intro\n\\@example value'
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 jsDocEscape(input) {
208
- return `${input}`.replace(/^(\s*)@/gm, "$1\\@");
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(text, func = "RegExp") {
250
- const raw = trimQuotes(text);
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
- * Renders an object key, quoting it with single quotes only when it is not a valid identifier.
269
- * Reserved words and globals (`name`, `class`, …) are valid bare keys and stay unquoted.
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
- * getRelativePath('/src/components', '/src/components/Button.tsx') // './Button.tsx'
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 getRelativePath(rootDir, filePath) {
311
- const relativePath = node_path.posix.relative(toSlash(rootDir), toSlash(filePath));
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
- * Whether a content entry is a sequence of JSON values the adapter marks as a stream, such as `application/jsonl`,
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 isJsonLines(entry) {
410
- const baseType = baseContentType(entry.contentType);
411
- return Boolean(entry.stream) && baseType !== "text/event-stream" && !baseType.startsWith("multipart/");
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 = baseContentType(entry.contentType);
360
+ const baseType = _kubb_kit.ast.mediaType.getBase(entry);
426
361
  if (!baseType) return void 0;
427
- if (baseType === "text/event-stream" || isJsonLines(entry)) return "stream";
428
- if (isJsonContentType(baseType)) return void 0;
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 = baseContentType(contentType);
467
- const resolved = _kubb_kit.ast.resolveRef(schema);
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) && !isJsonContentType(baseType) && !baseType.includes("*");
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,58 +584,7 @@ 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.findCircularSchemas(ctx.driver.inputNode?.schemas ?? []));
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
743
590
  /**
@@ -794,26 +641,29 @@ function canOverrideSchema(node) {
794
641
  * Whether a schema can supply object properties when merging faker values.
795
642
  */
796
643
  function isObjectSchema(node, seen = /* @__PURE__ */ new Set()) {
797
- const resolved = _kubb_kit.ast.resolveRef(node);
644
+ const resolved = _kubb_kit.ast.ref.getSchema(node);
798
645
  if (seen.has(resolved)) return false;
799
646
  seen.add(resolved);
800
- if (_kubb_kit.ast.narrowSchema(resolved, _kubb_kit.ast.schemaTypes.object) || _kubb_kit.ast.narrowSchema(resolved, _kubb_kit.ast.schemaTypes.ref)) return true;
801
- const composition = _kubb_kit.ast.narrowSchema(resolved, _kubb_kit.ast.schemaTypes.intersection) ?? _kubb_kit.ast.narrowSchema(resolved, _kubb_kit.ast.schemaTypes.union);
647
+ 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;
648
+ 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
649
  if (!composition) return false;
803
- return composition.type === _kubb_kit.ast.schemaTypes.intersection && !composition.members?.length || (composition.members ?? []).some((member) => isObjectSchema(member, seen));
650
+ return composition.type === _kubb_kit.ast.schema.types.intersection && !composition.members?.length || (composition.members ?? []).some((member) => isObjectSchema(member, seen));
804
651
  }
805
652
  function shouldInlineSingleResponseSchema(schema) {
806
653
  return !NON_INLINABLE_RESPONSE_TYPES.has(schema.type);
807
654
  }
808
655
  /**
809
- * Builds a response schema as a union of all response statuses.
656
+ * Builds a response schema as a union of the success response statuses, like the `<Operation>Response` type of
657
+ * `@kubb/plugin-ts`, so the mock never is an error body. Falls back to every response when no success response has a schema.
810
658
  * Returns null if no responses are provided, or embeds single simple responses inline.
811
659
  */
812
660
  function buildResponseUnionSchema(node, resolver) {
813
- const responses = node.responses.map((response) => ({
661
+ const withSchema = node.responses.map((response) => ({
814
662
  ...response,
815
663
  content: response.content?.map((entry, _, content) => toResponseContent(entry, content))
816
664
  })).filter((response) => response.content?.[0]?.schema);
665
+ const success = withSchema.filter((response) => _kubb_kit.ast.http.status.isSuccess(response));
666
+ const responses = success.length > 0 ? success : withSchema;
817
667
  if (!responses.length) return null;
818
668
  if (responses.length === 1) {
819
669
  const schemas = responses[0].content?.flatMap((content) => content.schema ? [content.schema] : []) ?? [];
@@ -894,7 +744,7 @@ function getScalarType(node, typeName) {
894
744
  * Determines the data type, return type, and whether it uses the type name.
895
745
  */
896
746
  function resolveFakerTypeUsage(node, typeName, canOverride) {
897
- const resolvedNode = _kubb_kit.ast.resolveRef(node);
747
+ const resolvedNode = _kubb_kit.ast.ref.getSchema(node);
898
748
  const scalarType = SCALAR_TYPES.has(resolvedNode.type) ? `${getScalarType(resolvedNode, typeName)}${node.nullable || resolvedNode.nullable ? " | null" : ""}` : void 0;
899
749
  const dataType = scalarType ?? `Partial<${typeName}>`;
900
750
  const returnType = scalarType ?? (canOverride ? typeName : null);
@@ -913,8 +763,8 @@ function Faker({ node, description, name, typeName, printer, canOverride, typeMo
913
763
  imp.name
914
764
  ].join("-")));
915
765
  const isArray = node.type === "array";
916
- const isObject = !!_kubb_kit.ast.narrowSchema(node, _kubb_kit.ast.schemaTypes.object) || node.type === _kubb_kit.ast.schemaTypes.intersection && isObjectSchema(node);
917
- const isValueIntersection = node.type === _kubb_kit.ast.schemaTypes.intersection && !isObject;
766
+ const isObject = !!_kubb_kit.ast.schema.narrow(node, _kubb_kit.ast.schema.types.object) || node.type === _kubb_kit.ast.schema.types.intersection && isObjectSchema(node);
767
+ const isValueIntersection = node.type === _kubb_kit.ast.schema.types.intersection && !isObject;
918
768
  const isTuple = node.type === "tuple";
919
769
  const isScalar = SCALAR_TYPES.has(node.type);
920
770
  const isUnion = node.type === "union";
@@ -923,13 +773,14 @@ function Faker({ node, description, name, typeName, printer, canOverride, typeMo
923
773
  if (canOverride && node.type === "tuple") return `data && data.length === ${node.items?.length ?? 0} && !data.includes(undefined) ? data : ${fakerText}`;
924
774
  if (canOverride && isArray) return `[\n ...${fakerText},\n ...(data || []).filter((item) => item !== undefined),\n]`;
925
775
  if (canOverride && (isScalar || isUnion || isValueIntersection)) return node.nullable ? `data !== undefined ? data : ${fakerText}` : `data ?? ${fakerText}`;
776
+ if (canOverride && node.type === "ref" && node.nullable && SCALAR_TYPES.has(_kubb_kit.ast.ref.getSchema(node).type)) return `data === null ? data : ${fakerText}`;
926
777
  return fakerText;
927
778
  })();
928
779
  const { dataType, returnType: resolvedReturnType } = resolveFakerTypeUsage(node, typeName, canOverride);
929
780
  if (!useObjectOverride) {
930
781
  const paramsSignature = `${/\bdata\b/.test(fakerTextWithOverride) ? "data" : "_data"}?: ${dataType}`;
931
782
  const returnType = resolvedReturnType;
932
- const returnExpression = canOverride && !!returnType && (node.type === "ref" && !SCALAR_TYPES.has(_kubb_kit.ast.resolveRef(node).type) || isArray || isTuple || isUnion) ? `${isTuple || isUnion ? `(${fakerTextWithOverride})` : fakerTextWithOverride} as ${returnType}` : fakerTextWithOverride;
783
+ 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
784
  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
785
  name,
935
786
  isExportable: true,
@@ -947,10 +798,11 @@ function Faker({ node, description, name, typeName, printer, canOverride, typeMo
947
798
  const { cyclicSchemas, schemaName } = printer.options;
948
799
  const isCyclic = !!schemaName && !!cyclicSchemas?.has(schemaName);
949
800
  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) => (0, _kubb_kit.containsCircularRef)(p.schema, {
801
+ const hasGetters = node.type === "object" && !!cyclicSchemas && (node.properties ?? []).some((p) => _kubb_kit.ast.graph.containsCircular(p.schema, {
951
802
  circularSchemas: cyclicSchemas,
952
803
  excludeName: schemaName
953
804
  }));
805
+ const castThroughUnknown = (node.type !== "object" || node.min !== void 0) && typeMode !== "schema";
954
806
  const declaration = `const ${keysToOmit?.length ? `{ ${keysToOmit.map((key, index) => `${objectKey(key)}: _omit${index}`).join(", ")}, ...defaultFakeData }` : "defaultFakeData"} = ${fakerText}`;
955
807
  const functionBody = hasGetters ? `${declaration}
956
808
  if (data) {
@@ -962,7 +814,7 @@ return defaultFakeData as ${returnType}` : `${declaration}
962
814
  return {
963
815
  ...defaultFakeData,
964
816
  ...(data || {}),
965
- } as ${returnType}`;
817
+ } as ${castThroughUnknown ? "unknown as " : ""}${returnType}`;
966
818
  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
819
  name,
968
820
  isExportable: true,
@@ -1039,11 +891,38 @@ const integerFormats = /* @__PURE__ */ new Set([
1039
891
  "uint64"
1040
892
  ]);
1041
893
  const maxInt32 = 2147483647;
894
+ const maxValueByFormat = {
895
+ int32: maxInt32,
896
+ uint32: 4294967295
897
+ };
898
+ function isCyclicRef(node, { schemaName, cyclicSchemas }) {
899
+ if (node.type !== "ref" || !schemaName) return false;
900
+ const refName = _kubb_kit.ast.ref.getName(node);
901
+ return refName === schemaName || Boolean(refName && cyclicSchemas?.has(schemaName) && cyclicSchemas.has(refName));
902
+ }
1042
903
  /**
1043
- * `faker.number.float()` or `faker.number.int()`, with `min` and `max` passed only when set.
904
+ * `faker.number.float()`, `faker.number.int()` or `faker.number.bigInt()`, with `min` and `max` passed only when set,
905
+ * moved inside an exclusive bound, or needed so a lone bound does not contradict faker's default for the other.
1044
906
  */
1045
- function numberCall(kind, min, max) {
1046
- const args = [min !== void 0 && `min: ${min}`, max !== void 0 && `max: ${max}`].filter(Boolean).join(", ");
907
+ function numberCall(kind, { min, max, exclusive, multipleOf }) {
908
+ const isWhole = kind !== "float";
909
+ const grid = isWhole && !Number.isInteger(multipleOf) ? void 0 : multipleOf;
910
+ const { min: lower, max: upper } = _kubb_kit.ast.schema.getNumberBounds({
911
+ min,
912
+ max,
913
+ exclusive,
914
+ integer: isWhole,
915
+ step: grid
916
+ });
917
+ const span = 100 * (grid ?? 1);
918
+ const maxValue = kind === "float" && lower !== void 0 && upper === void 0 && (lower >= 1 || grid !== void 0) ? lower + span : upper;
919
+ const minValue = maxValue !== void 0 && lower === void 0 && (isWhole ? maxValue < 0 : maxValue <= 0) ? maxValue - span : lower;
920
+ const suffix = kind === "bigInt" ? "n" : "";
921
+ const args = [
922
+ minValue !== void 0 && `min: ${minValue}${suffix}`,
923
+ maxValue !== void 0 && `max: ${maxValue}${suffix}`,
924
+ grid !== void 0 && `multipleOf: ${grid}${suffix}`
925
+ ].filter(Boolean).join(", ");
1047
926
  return `faker.number.${kind}(${args ? `{ ${args} }` : ""})`;
1048
927
  }
1049
928
  /**
@@ -1061,12 +940,58 @@ function dateTimeCall(representation, { format, substring }, parser = "faker", s
1061
940
  });
1062
941
  return "faker.date.anytime()";
1063
942
  }
943
+ const encodingCalls = /* @__PURE__ */ new Map([["base64", "btoa(faker.string.alpha())"], ["base64url", "faker.string.alphanumeric(8)"]]);
944
+ const stringFormatCalls = /* @__PURE__ */ new Map([
945
+ ["jwt", "faker.internet.jwt()"],
946
+ ["ulid", "faker.string.ulid()"],
947
+ ["iban", "faker.finance.iban()"],
948
+ ["duration", "'P1D'"],
949
+ ["hostname", "faker.internet.domainName()"]
950
+ ]);
951
+ const classEscapes = new Map([
952
+ ["d", "0-9"],
953
+ ["w", "A-Za-z0-9_"],
954
+ ...Array.from("-!@#$&()`.+,\"", (char) => [char, char])
955
+ ]);
956
+ function toFakerPattern(pattern) {
957
+ let result = "";
958
+ let inClass = false;
959
+ let classStart = -1;
960
+ for (let index = 0; index < pattern.length; index++) {
961
+ const char = pattern[index];
962
+ const next = pattern[index + 1];
963
+ if (char === "\\" && next !== void 0) {
964
+ index++;
965
+ if (inClass && next === "-") {
966
+ if (result[classStart] !== "-") result = `${result.slice(0, classStart)}-${result.slice(classStart)}`;
967
+ continue;
968
+ }
969
+ const classMembers = classEscapes.get(next);
970
+ if (classMembers === void 0) {
971
+ result += `\\${next}`;
972
+ continue;
973
+ }
974
+ result += inClass ? classMembers : `[${classMembers}]`;
975
+ continue;
976
+ }
977
+ if (char === "[" && !inClass) {
978
+ inClass = true;
979
+ result += next === "^" ? "[^" : "[";
980
+ if (next === "^") index++;
981
+ classStart = result.length;
982
+ continue;
983
+ }
984
+ if (char === "]") inClass = false;
985
+ result += char;
986
+ }
987
+ return result.replace(/\{(\d+),\}/g, (_, min) => `{${min},${Number(min) + 10}}`);
988
+ }
1064
989
  function matches(value, regexGenerator = "faker") {
1065
990
  if (regexGenerator === "randexp") return `${toRegExpString(value, "RandExp")}.gen()`;
1066
- return `faker.helpers.fromRegExp(${toRegExpString(value, null)})`;
991
+ return `faker.helpers.fromRegExp(${toRegExpString(toFakerPattern(value), null)})`;
1067
992
  }
1068
993
  function parseEnumValue(value) {
1069
- if (typeof value === "string") return stringify(value);
994
+ if (typeof value === "string") return _kubb_kit.text.quote(value);
1070
995
  return value;
1071
996
  }
1072
997
  /**
@@ -1077,11 +1002,11 @@ function parseEnumValue(value) {
1077
1002
  * (a `ref` to the enum shared by every branch, say) identifies no branch and narrows nothing.
1078
1003
  */
1079
1004
  function getDiscriminator(member, discriminatorPropertyName) {
1080
- for (const property of _kubb_kit.ast.resolveSchemaProperties({
1005
+ for (const property of _kubb_kit.ast.schema.findProperties({
1081
1006
  node: member,
1082
1007
  propertyName: discriminatorPropertyName
1083
1008
  })) {
1084
- const values = _kubb_kit.ast.getSchemaLiteralValues(property.schema);
1009
+ const values = _kubb_kit.ast.schema.getLiterals(property.schema);
1085
1010
  if (values.length === 1) return {
1086
1011
  value: values[0],
1087
1012
  required: property.required
@@ -1098,11 +1023,14 @@ function indexedTypeName(typeName, propertyName, nestedInUnion) {
1098
1023
  const key = JSON.stringify(propertyName);
1099
1024
  return nestedInUnion ? `(NonNullable<${typeName}> & Record<${key}, unknown>)[${key}]` : `NonNullable<${typeName}>[${key}]`;
1100
1025
  }
1026
+ function itemTypeName(typeName, nestedInUnion) {
1027
+ return nestedInUnion ? `Extract<NonNullable<${typeName}>, ReadonlyArray<unknown>>[number]` : `NonNullable<${typeName}>[number]`;
1028
+ }
1101
1029
  /**
1102
1030
  * Creates a Faker printer that generates mock data generation code from schema nodes.
1103
1031
  * Handles circular references gracefully by emitting memoizing getters for cyclic properties.
1104
1032
  */
1105
- const printerFaker = _kubb_kit.ast.createPrinter((options) => {
1033
+ const printerFaker = (0, _kubb_kit.createPrinter)((options) => {
1106
1034
  const printNested = (node, overrideOptions = {}) => {
1107
1035
  return printerFaker({
1108
1036
  ...options,
@@ -1122,18 +1050,33 @@ const printerFaker = _kubb_kit.ast.createPrinter((options) => {
1122
1050
  string(node) {
1123
1051
  if (node.pattern) return matches(node.pattern, this.options.regexGenerator);
1124
1052
  if (node.format && integerFormats.has(node.format)) return node.format === "int32" ? `faker.number.int({ max: ${maxInt32} }).toString()` : "faker.number.bigInt().toString()";
1053
+ const formatCall = stringFormatCalls.get(node.format);
1054
+ if (formatCall) return formatCall;
1055
+ const contentSchema = _kubb_kit.ast.schema.getEmbeddedJson(node);
1056
+ if (contentSchema) return `JSON.stringify(${printNested(contentSchema, {
1057
+ typeName: void 0,
1058
+ nestedInObject: true,
1059
+ nestedInUnion: false
1060
+ })})`;
1061
+ const encodingCall = encodingCalls.get(node.content?.encoding?.toLowerCase());
1062
+ if (encodingCall) return encodingCall;
1125
1063
  const { min, max } = node;
1126
- if (min !== void 0 && max !== void 0) return `faker.string.alpha({ length: { min: ${min}, max: ${max} } })`;
1127
- if (max !== void 0 || min !== void 0) return `faker.string.alpha({ length: ${max ?? min} })`;
1064
+ if (max !== void 0) return `faker.string.alpha({ length: { min: ${min ?? Math.min(1, max)}, max: ${Math.min(max, (min ?? 0) + 100)} } })`;
1065
+ if (min !== void 0) return `faker.string.alpha({ length: ${min} })`;
1128
1066
  return "faker.string.alpha()";
1129
1067
  },
1130
1068
  email: () => "faker.internet.email()",
1131
1069
  url: () => "faker.internet.url()",
1132
1070
  uuid: () => "faker.string.uuid()",
1133
- number: (node) => numberCall("float", node.min, node.max),
1134
- integer: (node) => numberCall("int", node.min, node.max),
1135
- bigint: () => "faker.number.bigInt()",
1136
- blob: () => "faker.image.url() as unknown as Blob",
1071
+ ipv4: () => "faker.internet.ipv4()",
1072
+ ipv6: () => "faker.internet.ipv6()",
1073
+ number: (node) => numberCall("float", node),
1074
+ integer: (node) => numberCall("int", node.format && node.format in maxValueByFormat ? {
1075
+ ...node,
1076
+ max: Math.min(node.max ?? Infinity, maxValueByFormat[node.format])
1077
+ } : node),
1078
+ bigint: (node) => numberCall("bigInt", node),
1079
+ blob: () => "new Blob([faker.string.alpha()])",
1137
1080
  datetime(node) {
1138
1081
  const parser = this.options.dateParser ?? "faker";
1139
1082
  if (parser === "faker") return "faker.date.anytime().toISOString()";
@@ -1152,28 +1095,30 @@ const printerFaker = _kubb_kit.ast.createPrinter((options) => {
1152
1095
  }, this.options.dateParser, this.options.schemaName);
1153
1096
  },
1154
1097
  ref(node) {
1155
- const refName = _kubb_kit.ast.resolveRefName(node);
1098
+ const refName = _kubb_kit.ast.ref.getName(node);
1156
1099
  if (!refName) throw new _kubb_kit.Diagnostics.Error({
1157
1100
  code: _kubb_kit.Diagnostics.code.pluginFailed,
1158
1101
  severity: "error",
1159
1102
  message: `Ref node "${node.ref ?? node.name ?? "unknown"}"${this.options.schemaName ? ` in schema "${this.options.schemaName}"` : ""} has no name.`,
1160
1103
  plugin: "plugin-faker"
1161
1104
  });
1162
- if (this.options.schemaName && refName === this.options.schemaName) return this.options.typeName ? `undefined as unknown as ${this.options.typeName}` : "undefined as unknown";
1105
+ if (isCyclicRef(node, this.options)) return this.options.typeName ? `undefined as unknown as ${this.options.typeName}` : "undefined as unknown";
1163
1106
  const resolvedName = node.ref ? this.options.resolver.name(refName) : refName;
1164
- if (!this.options.nestedInObject && canOverrideSchema(_kubb_kit.ast.resolveRef(node))) return `${resolvedName}(data)`;
1107
+ if (!this.options.nestedInObject && canOverrideSchema(_kubb_kit.ast.ref.getSchema(node))) return `${resolvedName}(data)`;
1165
1108
  return `${resolvedName}()`;
1166
1109
  },
1167
1110
  enum(node) {
1168
1111
  const { typeName } = this.options;
1169
- const values = _kubb_kit.ast.getSchemaLiteralValues(node);
1112
+ const values = _kubb_kit.ast.schema.getLiterals(node);
1170
1113
  if (values.length === 1 && values[0] !== null && typeof values[0] === "object") return JSON.stringify(values[0]);
1171
- return `faker.helpers.arrayElement${typeName ? `<${typeName}>` : ""}([${values.map(parseEnumValue).join(", ")}])`;
1114
+ return `faker.helpers.arrayElement([${values.map(parseEnumValue).join(", ")}]${typeName ? ` as Array<${typeName}>` : ""})`;
1172
1115
  },
1173
1116
  union(node) {
1174
1117
  const { discriminatorPropertyName } = node;
1175
1118
  const baseTypeName = this.options.typeName;
1176
- return `faker.helpers.arrayElement([${mapSchemaMembers(node, (member) => {
1119
+ const isCyclicMember = (member) => isCyclicRef(member, this.options) || member.type === "intersection" && (member.members ?? []).some((part) => isCyclicRef(part, this.options));
1120
+ const acyclicMembers = (node.members ?? []).filter((member) => !isCyclicMember(member));
1121
+ return `faker.helpers.arrayElement([${((acyclicMembers.length ? acyclicMembers : node.members) ?? []).map((member) => {
1177
1122
  const discriminator = discriminatorPropertyName ? getDiscriminator(member, discriminatorPropertyName) : void 0;
1178
1123
  if (baseTypeName && discriminator) {
1179
1124
  const key = `${JSON.stringify(discriminatorPropertyName)}${discriminator.required ? "" : "?"}`;
@@ -1189,29 +1134,31 @@ const printerFaker = _kubb_kit.ast.createPrinter((options) => {
1189
1134
  nestedInObject: true,
1190
1135
  nestedInUnion: true
1191
1136
  });
1192
- }).map(({ output }) => output).filter((item) => Boolean(item)).join(", ")}])`;
1137
+ }).filter((item) => Boolean(item)).join(", ")}])`;
1193
1138
  },
1194
1139
  intersection(node) {
1195
1140
  const objectMembers = (node.members ?? []).filter((member) => isObjectSchema(member));
1196
- const members = objectMembers.length ? objectMembers : node.members;
1197
- const items = mapSchemaMembers({
1198
- ...node,
1199
- members
1200
- }, (member) => printNested(member, { nestedInObject: true })).map(({ output }) => output).filter((item) => Boolean(item) && item !== "undefined");
1141
+ const memberRank = (member) => member.type === "ref" ? 0 : member.type === "union" ? 2 : 1;
1142
+ const items = ((objectMembers.length ? objectMembers.toSorted((a, b) => memberRank(a) - memberRank(b)) : node.members) ?? []).map((member) => printNested(member, {
1143
+ nestedInObject: true,
1144
+ ...member.type === "ref" && _kubb_kit.ast.ref.getName(member) !== this.options.schemaName ? { cyclicSchemas: void 0 } : {}
1145
+ })).filter((item) => Boolean(item) && item !== "undefined");
1201
1146
  if (items.length === 0) return "{}";
1202
1147
  return !objectMembers.length || items.length === 1 ? items.at(-1) : `{...${items.join(", ...")}}`;
1203
1148
  },
1204
1149
  array(node) {
1205
- const items = mapSchemaItems(node, (member) => printNested(member, {
1206
- typeName: this.options.typeName ? `NonNullable<${this.options.typeName}>[number]` : void 0,
1150
+ if (node.items?.length === 1 && isCyclicRef(node.items[0], this.options)) return this.options.typeName ? `[] as ${this.options.typeName}` : "[]";
1151
+ const items = (node.items ?? []).map((member) => printNested(member, {
1152
+ typeName: this.options.typeName ? itemTypeName(this.options.typeName, this.options.nestedInUnion) : void 0,
1207
1153
  nestedInObject: true
1208
- })).map(({ output }) => output).filter((item) => Boolean(item));
1154
+ })).filter((item) => Boolean(item));
1209
1155
  if (items.length > 1) return `faker.helpers.arrayElements([${items.join(", ")}])`;
1210
1156
  const { min, max } = node;
1211
1157
  const item = items[0];
1212
- if (min !== void 0 && max !== void 0) return `faker.helpers.multiple(() => (${item}), { count: { min: ${min}, max: ${max} }})`;
1158
+ const countRange = max === void 0 ? void 0 : `{ min: ${min ?? 0}, max: ${Math.min(max, (min ?? 0) + 100)} }`;
1159
+ if (node.unique) return `faker.helpers.uniqueArray(() => (${item}), ${countRange ? `faker.number.int(${countRange})` : min ?? 3})`;
1160
+ if (countRange) return `faker.helpers.multiple(() => (${item}), { count: ${countRange}})`;
1213
1161
  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
1162
  return `faker.helpers.multiple(() => (${item}))`;
1216
1163
  },
1217
1164
  tuple(node) {
@@ -1222,18 +1169,30 @@ const printerFaker = _kubb_kit.ast.createPrinter((options) => {
1222
1169
  },
1223
1170
  object(node) {
1224
1171
  const cyclicSchemas = this.options.cyclicSchemas;
1225
- const keySchema = node.propertyNames && (0, _kubb_kit.syncSchemaRef)(node.propertyNames);
1172
+ const keySchema = node.propertyNames && _kubb_kit.ast.ref.mergeSchema(node.propertyNames);
1226
1173
  const valueSchema = node.additionalProperties;
1227
- const recordProperties = keySchema?.type === "enum" && typeof valueSchema === "object" ? _kubb_kit.ast.getSchemaLiteralValues(keySchema).filter((key) => typeof key === "string" && !node.properties.some((property) => property.name === key)).map((name) => _kubb_kit.ast.factory.createProperty({
1174
+ 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
1175
  name,
1229
1176
  schema: valueSchema
1230
1177
  })) : [];
1231
- return buildObject([...node.properties, ...recordProperties].map((property) => {
1178
+ const properties = [...node.properties, ...recordProperties];
1179
+ const keptProperties = node.max === void 0 ? properties : properties.toSorted((a, b) => Number(b.required) - Number(a.required)).slice(0, node.max);
1180
+ const declaredNames = new Set(properties.map((property) => property.name));
1181
+ const extras = [];
1182
+ for (let index = 1; typeof valueSchema === "object" && keptProperties.length + extras.length < (node.min ?? 0); index++) {
1183
+ const name = `additionalProperty${index}`;
1184
+ if (!declaredNames.has(name)) extras.push(_kubb_kit.ast.factory.createProperty({
1185
+ name,
1186
+ schema: valueSchema
1187
+ }));
1188
+ }
1189
+ return buildObject([...keptProperties, ...extras].map((property) => {
1232
1190
  const value = printNested(property.schema, {
1233
1191
  typeName: this.options.typeName ? indexedTypeName(this.options.typeName, property.name, this.options.nestedInUnion) : void 0,
1234
- nestedInObject: true
1192
+ nestedInObject: true,
1193
+ ...property.required && property.schema.type === "ref" ? { cyclicSchemas: void 0 } : {}
1235
1194
  }) ?? "undefined";
1236
- if (cyclicSchemas && (0, _kubb_kit.containsCircularRef)(property.schema, {
1195
+ if (cyclicSchemas && _kubb_kit.ast.graph.containsCircular(property.schema, {
1237
1196
  circularSchemas: cyclicSchemas,
1238
1197
  excludeName: this.options.schemaName
1239
1198
  })) 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 +1220,7 @@ const fakerGenerator = (0, _kubb_kit.defineGenerator)({
1261
1220
  if (!node.name) return;
1262
1221
  const tsResolver = ctx.driver.getResolver(_kubb_plugin_ts.pluginTsName);
1263
1222
  const schemaName = node.name;
1264
- const isEnumSchema = !!_kubb_kit.ast.narrowSchema(node, _kubb_kit.ast.schemaTypes.enum);
1223
+ const isEnumSchema = !!_kubb_kit.ast.schema.narrow(node, _kubb_kit.ast.schema.types.enum);
1265
1224
  const schemaTypeName = (0, _kubb_plugin_ts.enumTypeName)({
1266
1225
  resolver: tsResolver,
1267
1226
  name: schemaName,
@@ -1310,7 +1269,8 @@ const fakerGenerator = (0, _kubb_kit.defineGenerator)({
1310
1269
  node,
1311
1270
  root,
1312
1271
  output,
1313
- group: group ?? void 0
1272
+ group: group ?? void 0,
1273
+ checks: true
1314
1274
  }), fakerText);
1315
1275
  return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
1316
1276
  baseName: meta.file.baseName,
@@ -1384,7 +1344,7 @@ const fakerGenerator = (0, _kubb_kit.defineGenerator)({
1384
1344
  const { output, group, dateParser, regexGenerator, seed, locale, printer, typeMode } = ctx.options;
1385
1345
  const pluginTs = ctx.requirePlugin(_kubb_plugin_ts.pluginTsName);
1386
1346
  const tsResolver = ctx.driver.getResolver(_kubb_plugin_ts.pluginTsName);
1387
- const { path: pathParams, query: queryParams, header: headerParams, cookie: cookieParams } = getOperationParameters(node);
1347
+ const { path: pathParams, query: queryParams, header: headerParams, cookie: cookieParams } = _kubb_kit.ast.http.groupParameters(node);
1388
1348
  const paramGroups = [
1389
1349
  {
1390
1350
  params: pathParams,
@@ -1453,7 +1413,7 @@ const fakerGenerator = (0, _kubb_kit.defineGenerator)({
1453
1413
  description: node.requestBody?.description ?? schema.description
1454
1414
  }));
1455
1415
  const responseName = resolver.response.response(node);
1456
- const hasResponseNameCollision = new Set(node.responses.flatMap((response) => (response.content ?? []).flatMap((entry) => entry.schema ? _kubb_kit.ast.collectImportedRefNames(entry.schema).map((name) => resolver.name(name)) : []))).has(responseName);
1416
+ const hasResponseNameCollision = new Set(_kubb_kit.ast.http.responses.getImportedNames(node.responses).map((name) => resolver.name(name))).has(responseName);
1457
1417
  const localHelperNames = /* @__PURE__ */ new Set([
1458
1418
  ...paramGroups.map((group) => group.name),
1459
1419
  ...responseUnits.map((unit) => unit.name),
@@ -1484,12 +1444,13 @@ const fakerGenerator = (0, _kubb_kit.defineGenerator)({
1484
1444
  node: schema,
1485
1445
  root,
1486
1446
  output,
1487
- group: group ?? void 0
1447
+ group: group ?? void 0,
1448
+ checks: true
1488
1449
  }).filter((entry) => entry.path !== meta.file.path);
1489
1450
  }
1490
1451
  function renderEntry({ schema, name, typeName, description, keysToOmit, skipImportNames = [] }) {
1491
1452
  if (!schema) return null;
1492
- if (schema.type === _kubb_kit.ast.schemaTypes.object && keysToOmit?.length) {
1453
+ if (schema.type === _kubb_kit.ast.schema.types.object && keysToOmit?.length) {
1493
1454
  schema = {
1494
1455
  ...schema,
1495
1456
  properties: schema.properties.filter((property) => !keysToOmit?.includes(property.name))
@@ -1604,11 +1565,11 @@ const fakerGenerator = (0, _kubb_kit.defineGenerator)({
1604
1565
  });
1605
1566
  // kubb-extension.json
1606
1567
  var compatibility = {
1607
- "kubb": ">=5.16.0",
1568
+ "kubb": ">=5.18.4",
1608
1569
  "node": ">=22.22"
1609
1570
  };
1610
1571
  // package.json
1611
- var version = "5.4.0-canary.20261111T122006";
1572
+ var version = "5.4.0";
1612
1573
  // src/resolvers/resolverFaker.ts
1613
1574
  /**
1614
1575
  * Default resolver used by `@kubb/plugin-faker`. Decides the names and file
@@ -1625,9 +1586,9 @@ var version = "5.4.0-canary.20261111T122006";
1625
1586
  const resolverFaker = (0, _kubb_kit.createResolver)({
1626
1587
  pluginName: "plugin-faker",
1627
1588
  name(name) {
1628
- return this.memo(`name:${name}`, () => ensureValidVarName((0, _kubb_kit.camelCase)(name, { prefix: "create" })));
1589
+ return this.memo(`name:${name}`, () => ensureValidVarName(_kubb_kit.casing.camel(name, { prefix: "create" })));
1629
1590
  },
1630
- file: createCasedFile((part) => (0, _kubb_kit.camelCase)(part, { prefix: "create" })),
1591
+ file: createCasedFile((part) => _kubb_kit.casing.camel(part, { prefix: "create" })),
1631
1592
  param: createOperationParamResolver(),
1632
1593
  response: createOperationResponseResolver()
1633
1594
  });
@@ -1685,7 +1646,7 @@ const pluginFaker = (0, _kubb_kit.defineExtension)({
1685
1646
  include,
1686
1647
  override,
1687
1648
  typeMode,
1688
- group: createGroupConfig(group),
1649
+ group: group ?? null,
1689
1650
  dateParser,
1690
1651
  regexGenerator,
1691
1652
  printer