@kubb/plugin-faker 5.1.5 → 5.1.7

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.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import "./rolldown-runtime-C0LytTxp.js";
2
2
  import { posix } from "node:path";
3
- import { Resolver, addGenerator, ast, containsCircularRef, createResolver, defineExtension, defineGenerator, setMacros, setResolver } from "kubb/kit";
4
- import { buildParams, createFunctionParameter, createFunctionParameters, functionPrinter, pluginTsName } from "@kubb/plugin-ts";
3
+ import { Diagnostics, Resolver, addGenerator, assertPluginOption, ast, containsCircularRef, createResolver, defineExtension, defineGenerator, setMacros, setResolver } from "kubb/kit";
5
4
  import { File, Function, jsxRenderer } from "kubb/jsx";
6
5
  import { Fragment, jsx, jsxs } from "kubb/jsx/jsx-runtime";
6
+ import { buildParams, enumTypeName, pluginTsName } from "@kubb/plugin-ts";
7
7
  //#region ../../internals/utils/src/casing.ts
8
8
  /**
9
9
  * Shared implementation for camelCase and PascalCase conversion.
@@ -305,6 +305,24 @@ function buildObject(entries) {
305
305
  }
306
306
  //#endregion
307
307
  //#region ../../internals/utils/src/fs.ts
308
+ function toSlash(p) {
309
+ if (p.startsWith("\\\\?\\")) return p;
310
+ return p.replaceAll("\\", "/");
311
+ }
312
+ /**
313
+ * Returns the relative path from `rootDir` to `filePath`, always using forward slashes
314
+ * and prefixed with `./` when not already traversing upward.
315
+ *
316
+ * @example
317
+ * ```ts
318
+ * getRelativePath('/src/components', '/src/components/Button.tsx') // './Button.tsx'
319
+ * getRelativePath('/src/components', '/src/utils/helpers.ts') // '../utils/helpers.ts'
320
+ * ```
321
+ */
322
+ function getRelativePath(rootDir, filePath) {
323
+ const relativePath = posix.relative(toSlash(rootDir), toSlash(filePath));
324
+ return relativePath.startsWith("../") ? relativePath : `./${relativePath}`;
325
+ }
308
326
  /**
309
327
  * Builds a nested file path from a dotted name. Splits on dots that precede a letter
310
328
  * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
@@ -329,51 +347,6 @@ function toFilePath(name, caseLast = camelCase) {
329
347
  return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
330
348
  }
331
349
  //#endregion
332
- //#region ../../internals/utils/src/imports.ts
333
- function escapeRegExp(value) {
334
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
335
- }
336
- function getImportNames(entry) {
337
- return (Array.isArray(entry.name) ? entry.name : [entry.name]).map((name) => {
338
- if (typeof name === "string") return name;
339
- return name.name ?? name.propertyName;
340
- }).filter((name) => Boolean(name));
341
- }
342
- function filterUsedImports(imports, text, skipImportNames = []) {
343
- const skip = new Set(skipImportNames);
344
- return imports.filter((entry) => {
345
- return getImportNames(entry).some((name) => {
346
- if (skip.has(name)) return false;
347
- return new RegExp(`\\b${escapeRegExp(name)}\\b(?=\\s*[<(])`).test(text);
348
- });
349
- });
350
- }
351
- function aliasConflictingImports(imports, reservedNames) {
352
- const reservedNameSet = new Set(reservedNames);
353
- const aliases = /* @__PURE__ */ new Map();
354
- return {
355
- imports: imports.map((entry) => {
356
- const aliasedNames = (Array.isArray(entry.name) ? entry.name : [entry.name]).map((item) => {
357
- if (typeof item !== "string" || !reservedNameSet.has(item)) return item;
358
- const alias = `${item}Schema`;
359
- aliases.set(item, alias);
360
- return {
361
- propertyName: item,
362
- name: alias
363
- };
364
- });
365
- return aliasedNames.some((item) => typeof item === "object" && item.name) ? {
366
- ...entry,
367
- name: aliasedNames
368
- } : entry;
369
- }),
370
- aliases
371
- };
372
- }
373
- function rewriteAliasedImports(text, aliases) {
374
- return Array.from(aliases).reduce((acc, [name, alias]) => acc.replace(new RegExp(`\\b${escapeRegExp(name)}\\b`, "g"), alias), text);
375
- }
376
- //#endregion
377
350
  //#region src/utils.ts
378
351
  /**
379
352
  * Returns the `@faker-js/faker` named export for a locale code.
@@ -397,54 +370,36 @@ function localeToFakerImport(locale) {
397
370
  return `faker${parts.join("_")}`;
398
371
  }
399
372
  /**
373
+ * Schema types a factory cannot override with `data`: they print a constant or have no faker value.
374
+ */
375
+ const NON_OVERRIDABLE_TYPES = /* @__PURE__ */ new Set([
376
+ "any",
377
+ "unknown",
378
+ "void",
379
+ "null",
380
+ "never",
381
+ "ipv4",
382
+ "ipv6"
383
+ ]);
384
+ /**
385
+ * Schema types a single response cannot inline: they reference or compose other schemas.
386
+ */
387
+ const NON_INLINABLE_RESPONSE_TYPES = /* @__PURE__ */ new Set([
388
+ "object",
389
+ "intersection",
390
+ "ref",
391
+ "never",
392
+ "ipv4",
393
+ "ipv6"
394
+ ]);
395
+ /**
400
396
  * Determines if a schema node can be overridden during faker generation.
401
397
  */
402
398
  function canOverrideSchema(node) {
403
- return (/* @__PURE__ */ new Set([
404
- "array",
405
- "tuple",
406
- "object",
407
- "intersection",
408
- "union",
409
- "enum",
410
- "ref",
411
- "string",
412
- "email",
413
- "url",
414
- "uuid",
415
- "number",
416
- "integer",
417
- "bigint",
418
- "boolean",
419
- "date",
420
- "time",
421
- "datetime",
422
- "blob"
423
- ])).has(node.type);
399
+ return !NON_OVERRIDABLE_TYPES.has(node.type);
424
400
  }
425
401
  function shouldInlineSingleResponseSchema(schema) {
426
- return (/* @__PURE__ */ new Set([
427
- "any",
428
- "unknown",
429
- "void",
430
- "null",
431
- "array",
432
- "tuple",
433
- "string",
434
- "email",
435
- "url",
436
- "uuid",
437
- "number",
438
- "integer",
439
- "bigint",
440
- "boolean",
441
- "date",
442
- "time",
443
- "datetime",
444
- "blob",
445
- "enum",
446
- "union"
447
- ])).has(schema.type);
402
+ return !NON_INLINABLE_RESPONSE_TYPES.has(schema.type);
448
403
  }
449
404
  /**
450
405
  * Builds a response schema as a union of all response statuses.
@@ -473,7 +428,7 @@ function buildResponseUnionSchema(node, resolver) {
473
428
  })
474
429
  });
475
430
  }
476
- const SCALAR_TYPES$1 = /* @__PURE__ */ new Set([
431
+ const SCALAR_TYPES = /* @__PURE__ */ new Set([
477
432
  "string",
478
433
  "email",
479
434
  "url",
@@ -488,10 +443,6 @@ const SCALAR_TYPES$1 = /* @__PURE__ */ new Set([
488
443
  "blob",
489
444
  "enum"
490
445
  ]);
491
- function toRelativeImportPath(from, to) {
492
- const relativePath = posix.relative(posix.dirname(from), to);
493
- return relativePath.startsWith("../") ? relativePath : `./${relativePath}`;
494
- }
495
446
  /**
496
447
  * Resolves a type reference, determining if it needs an import statement or inline type reference.
497
448
  * Takes into account whether the type can be overridden and the file paths.
@@ -499,7 +450,7 @@ function toRelativeImportPath(from, to) {
499
450
  function resolveTypeReference({ node, canOverride, name, typeName, filePath, typeFilePath }) {
500
451
  const { usesTypeName } = resolveFakerTypeUsage(node, typeName, canOverride);
501
452
  if (!usesTypeName) return { typeName };
502
- if (name === typeName) return { typeName: `import('${toRelativeImportPath(filePath, typeFilePath)}').${typeName}` };
453
+ if (name === typeName) return { typeName: `import('${getRelativePath(posix.dirname(filePath), typeFilePath)}').${typeName}` };
503
454
  return {
504
455
  importPath: typeFilePath,
505
456
  typeName
@@ -523,28 +474,17 @@ function getScalarType(node, typeName) {
523
474
  case "time": return node.representation === "date" ? "Date" : "string";
524
475
  case "datetime": return "string";
525
476
  case "blob": return "Blob";
526
- case "enum": return typeName;
527
477
  default: return typeName;
528
478
  }
529
479
  }
530
480
  /**
531
- * A nullable scalar inlines its primitive instead of naming the generated type, so the
532
- * nullability the type plugin emitted has to be reapplied here. Non-scalars keep `typeName`,
533
- * which already carries it.
534
- */
535
- function withNullability(type, node) {
536
- return node.nullable ? `${type} | null` : type;
537
- }
538
- /**
539
481
  * Resolves faker type usage information for a schema.
540
482
  * Determines the data type, return type, and whether it uses the type name.
541
483
  */
542
484
  function resolveFakerTypeUsage(node, typeName, canOverride) {
543
- const isScalar = SCALAR_TYPES$1.has(node.type);
544
- let dataType = `Partial<${typeName}>`;
545
- if (isScalar) dataType = withNullability(getScalarType(node, typeName), node);
546
- let returnType = canOverride ? typeName : null;
547
- if (isScalar) returnType = withNullability(getScalarType(node, typeName), node);
485
+ const scalarType = SCALAR_TYPES.has(node.type) ? `${getScalarType(node, typeName)}${node.nullable ? " | null" : ""}` : void 0;
486
+ const dataType = scalarType ?? `Partial<${typeName}>`;
487
+ const returnType = scalarType ?? (canOverride ? typeName : null);
548
488
  return {
549
489
  dataType,
550
490
  returnType,
@@ -554,22 +494,6 @@ function resolveFakerTypeUsage(node, typeName, canOverride) {
554
494
  //#endregion
555
495
  //#region src/components/Faker.tsx
556
496
  const OBJECT_TYPES = /* @__PURE__ */ new Set(["object", "intersection"]);
557
- const SCALAR_TYPES = /* @__PURE__ */ new Set([
558
- "string",
559
- "email",
560
- "url",
561
- "uuid",
562
- "number",
563
- "integer",
564
- "bigint",
565
- "boolean",
566
- "date",
567
- "time",
568
- "datetime",
569
- "blob",
570
- "enum"
571
- ]);
572
- const declarationPrinter = functionPrinter({ mode: "declaration" });
573
497
  function Faker({ node, description, name, typeName, printer, canOverride, typeMode = "inferred" }) {
574
498
  const fakerText = printer.print(node) ?? "undefined";
575
499
  const isArray = node.type === "array";
@@ -586,13 +510,7 @@ function Faker({ node, description, name, typeName, printer, canOverride, typeMo
586
510
  })();
587
511
  const { dataType, returnType: resolvedReturnType } = resolveFakerTypeUsage(node, typeName, canOverride);
588
512
  if (!useObjectOverride) {
589
- const dataParamName = /\bdata\b/.test(fakerTextWithOverride) ? "data" : "_data";
590
- const params = createFunctionParameters({ params: [createFunctionParameter({
591
- name: dataParamName,
592
- type: dataType,
593
- optional: true
594
- })] });
595
- const paramsSignature = declarationPrinter.print(params) ?? "";
513
+ const paramsSignature = `${/\bdata\b/.test(fakerTextWithOverride) ? "data" : "_data"}?: ${dataType}`;
596
514
  const returnType = resolvedReturnType;
597
515
  const returnExpression = canOverride && !!returnType && (node.type === "ref" || isArray || isTuple || isUnion) ? `${isTuple || isUnion ? `(${fakerTextWithOverride})` : fakerTextWithOverride} as ${returnType}` : fakerTextWithOverride;
598
516
  return /* @__PURE__ */ jsx(File.Source, {
@@ -641,24 +559,6 @@ return {
641
559
  });
642
560
  }
643
561
  //#endregion
644
- //#region ../../internals/shared/src/params.ts
645
- /**
646
- * Drops parameters that share the same name, keeping the first.
647
- *
648
- * A malformed spec can declare the same parameter name twice within one `in` location. Both would
649
- * resolve to the same output property, so emitting both would yield an object type with a duplicate
650
- * member, which TypeScript rejects. This is a defensive guard against that case, not a casing guard:
651
- * parameter names flow through unchanged, so no two distinct names ever collide here anymore.
652
- */
653
- function dedupeParams(params) {
654
- const seen = /* @__PURE__ */ new Set();
655
- return params.filter((param) => {
656
- if (seen.has(param.name)) return false;
657
- seen.add(param.name);
658
- return true;
659
- });
660
- }
661
- //#endregion
662
562
  //#region ../../internals/shared/src/operation.ts
663
563
  /**
664
564
  * Builds the `ResolverFileParams` every operation generator passes to
@@ -757,11 +657,19 @@ const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
757
657
  function getOperationParameters(node) {
758
658
  const cached = operationParameterGroupsByNode.get(node);
759
659
  if (cached) return cached;
660
+ const group = (location) => {
661
+ const seen = /* @__PURE__ */ new Set();
662
+ return node.parameters.filter((param) => {
663
+ if (param.in !== location || seen.has(param.name)) return false;
664
+ seen.add(param.name);
665
+ return true;
666
+ });
667
+ };
760
668
  const groups = {
761
- path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
762
- query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
763
- header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
764
- cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
669
+ path: group("path"),
670
+ query: group("query"),
671
+ header: group("header"),
672
+ cookie: group("cookie")
765
673
  };
766
674
  operationParameterGroupsByNode.set(node, groups);
767
675
  return groups;
@@ -842,20 +750,6 @@ function createCasedFile(caseLast) {
842
750
  } };
843
751
  }
844
752
  //#endregion
845
- //#region ../../internals/shared/src/refs.ts
846
- /**
847
- * Collects the resolved target name of every pointer-carrying ref in a schema tree, in
848
- * first-occurrence order. Use this for name-only checks (e.g. redeclaration detection) where
849
- * `resolver.imports` would resolve file paths that are then discarded.
850
- */
851
- function collectRefNames(schema) {
852
- return ast.collectSync(schema, { schema: (node) => {
853
- const refNode = ast.narrowSchema(node, "ref");
854
- if (!refNode?.ref) return null;
855
- return ast.resolveRefName(refNode);
856
- } });
857
- }
858
- //#endregion
859
753
  //#region ../../internals/shared/src/group.ts
860
754
  /**
861
755
  * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
@@ -909,6 +803,51 @@ function mapSchemaItems(node, transform) {
909
803
  }));
910
804
  }
911
805
  //#endregion
806
+ //#region src/utils/imports.ts
807
+ function escapeRegExp(value) {
808
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
809
+ }
810
+ function getImportNames(entry) {
811
+ return (Array.isArray(entry.name) ? entry.name : [entry.name]).map((name) => {
812
+ if (typeof name === "string") return name;
813
+ return name.name ?? name.propertyName;
814
+ }).filter((name) => Boolean(name));
815
+ }
816
+ function filterUsedImports(imports, text, skipImportNames = []) {
817
+ const skip = new Set(skipImportNames);
818
+ return imports.filter((entry) => {
819
+ return getImportNames(entry).some((name) => {
820
+ if (skip.has(name)) return false;
821
+ return new RegExp(`\\b${escapeRegExp(name)}\\b(?=\\s*[<(])`).test(text);
822
+ });
823
+ });
824
+ }
825
+ function aliasConflictingImports(imports, reservedNames) {
826
+ const reservedNameSet = new Set(reservedNames);
827
+ const aliases = /* @__PURE__ */ new Map();
828
+ return {
829
+ imports: imports.map((entry) => {
830
+ const aliasedNames = (Array.isArray(entry.name) ? entry.name : [entry.name]).map((item) => {
831
+ if (typeof item !== "string" || !reservedNameSet.has(item)) return item;
832
+ const alias = `${item}Schema`;
833
+ aliases.set(item, alias);
834
+ return {
835
+ propertyName: item,
836
+ name: alias
837
+ };
838
+ });
839
+ return aliasedNames.some((item) => typeof item === "object" && item.name) ? {
840
+ ...entry,
841
+ name: aliasedNames
842
+ } : entry;
843
+ }),
844
+ aliases
845
+ };
846
+ }
847
+ function rewriteAliasedImports(text, aliases) {
848
+ return Array.from(aliases).reduce((acc, [name, alias]) => acc.replace(new RegExp(`\\b${escapeRegExp(name)}\\b`, "g"), alias), text);
849
+ }
850
+ //#endregion
912
851
  //#region src/printers/printerFaker.ts
913
852
  /**
914
853
  * Formats that put a whole number inside a `type: 'string'` schema, the way ProtoJSON encodes
@@ -922,77 +861,32 @@ const integerFormats = /* @__PURE__ */ new Set([
922
861
  "uint64"
923
862
  ]);
924
863
  const maxInt32 = 2147483647;
925
- const fakerKeywordMapper = {
926
- any: () => "undefined",
927
- unknown: () => "undefined",
928
- void: () => "undefined",
929
- number: (min, max) => {
930
- if (max !== void 0 && min !== void 0) return `faker.number.float({ min: ${min}, max: ${max} })`;
931
- if (max !== void 0) return `faker.number.float({ max: ${max} })`;
932
- if (min !== void 0) return `faker.number.float({ min: ${min} })`;
933
- return "faker.number.float()";
934
- },
935
- integer: (min, max) => {
936
- if (max !== void 0 && min !== void 0) return `faker.number.int({ min: ${min}, max: ${max} })`;
937
- if (max !== void 0) return `faker.number.int({ max: ${max} })`;
938
- if (min !== void 0) return `faker.number.int({ min: ${min} })`;
939
- return "faker.number.int()";
940
- },
941
- bigint: () => "faker.number.bigInt()",
942
- integerString: (format) => {
943
- if (format === "int32") return `faker.number.int({ max: ${maxInt32} }).toString()`;
944
- return "faker.number.bigInt().toString()";
945
- },
946
- string: (min, max) => {
947
- if (max !== void 0 && min !== void 0) return `faker.string.alpha({ length: { min: ${min}, max: ${max} } })`;
948
- if (max !== void 0) return `faker.string.alpha({ length: ${max} })`;
949
- if (min !== void 0) return `faker.string.alpha({ length: ${min} })`;
950
- return "faker.string.alpha()";
951
- },
952
- boolean: () => "faker.datatype.boolean()",
953
- null: () => "null",
954
- array: (items = [], min, max) => {
955
- if (items.length > 1) return `faker.helpers.arrayElements([${items.join(", ")}])`;
956
- const item = items.at(0);
957
- if (min !== void 0 && max !== void 0) return `faker.helpers.multiple(() => (${item}), { count: { min: ${min}, max: ${max} }})`;
958
- if (min !== void 0) return `faker.helpers.multiple(() => (${item}), { count: ${min} })`;
959
- if (max !== void 0) return `faker.helpers.multiple(() => (${item}), { count: { min: 0, max: ${max} }})`;
960
- return `faker.helpers.multiple(() => (${item}))`;
961
- },
962
- tuple: (items = []) => `[${items.join(", ")}]`,
963
- enum: (items = [], type) => `faker.helpers.arrayElement${type ? `<${type}>` : ""}([${items.join(", ")}])`,
964
- union: (items = []) => `faker.helpers.arrayElement([${items.join(", ")}])`,
965
- datetime: () => "faker.date.anytime().toISOString()",
966
- date: (representation = "string", parser = "faker") => {
967
- if (representation === "string") {
968
- if (parser !== "faker") return `${parser}(faker.date.anytime()).format("YYYY-MM-DD")`;
969
- return "faker.date.anytime().toISOString().substring(0, 10)";
970
- }
971
- if (parser !== "faker") throw new Error(`type '${representation}' and parser '${parser}' can not work together`);
972
- return "faker.date.anytime()";
973
- },
974
- time: (representation = "string", parser = "faker") => {
975
- if (representation === "string") {
976
- if (parser !== "faker") return `${parser}(faker.date.anytime()).format("HH:mm:ss")`;
977
- return "faker.date.anytime().toISOString().substring(11, 19)";
978
- }
979
- if (parser !== "faker") throw new Error(`type '${representation}' and parser '${parser}' can not work together`);
980
- return "faker.date.anytime()";
981
- },
982
- uuid: () => "faker.string.uuid()",
983
- url: () => "faker.internet.url()",
984
- and: (items = []) => {
985
- if (items.length === 0) return "{}";
986
- if (items.length === 1) return items[0] ?? "{}";
987
- return `{...${items.join(", ...")}}`;
988
- },
989
- matches: (value = "", regexGenerator = "faker") => {
990
- if (regexGenerator === "randexp") return `${toRegExpString(value, "RandExp")}.gen()`;
991
- return `faker.helpers.fromRegExp("${value}")`;
992
- },
993
- email: () => "faker.internet.email()",
994
- blob: () => "faker.image.url() as unknown as Blob"
995
- };
864
+ /**
865
+ * `faker.number.float()` or `faker.number.int()`, with `min` and `max` passed only when set.
866
+ */
867
+ function numberCall(kind, min, max) {
868
+ const args = [min !== void 0 && `min: ${min}`, max !== void 0 && `max: ${max}`].filter(Boolean).join(", ");
869
+ return `faker.number.${kind}(${args ? `{ ${args} }` : ""})`;
870
+ }
871
+ /**
872
+ * A `date` or `time` value: an ISO substring, a `dateParser` call, or a `Date` when `representation` is `'date'`.
873
+ */
874
+ function dateTimeCall(representation, { format, substring }, parser = "faker", schemaName) {
875
+ if (representation === "string") return parser !== "faker" ? `${parser}(faker.date.anytime()).format("${format}")` : `faker.date.anytime().toISOString().substring(${substring})`;
876
+ if (parser !== "faker") throw new Diagnostics.Error({
877
+ code: Diagnostics.code.invalidPluginOptions,
878
+ severity: "error",
879
+ message: `Option \`dateParser: '${parser}'\` cannot format the adapter's \`dateType: 'date'\` values${schemaName ? ` in schema "${schemaName}"` : ""}.`,
880
+ help: "Set adapterOas({ dateType: 'string' }) or remove `dateParser`.",
881
+ location: { kind: "config" },
882
+ plugin: "plugin-faker"
883
+ });
884
+ return "faker.date.anytime()";
885
+ }
886
+ function matches(value, regexGenerator = "faker") {
887
+ if (regexGenerator === "randexp") return `${toRegExpString(value, "RandExp")}.gen()`;
888
+ return `faker.helpers.fromRegExp(${toRegExpString(value, null)})`;
889
+ }
996
890
  function parseEnumValue(value) {
997
891
  if (typeof value === "string") return stringify(value);
998
892
  return value;
@@ -1038,49 +932,60 @@ const printerFaker = ast.createPrinter((options) => {
1038
932
  name: "faker",
1039
933
  options,
1040
934
  nodes: {
1041
- any: () => fakerKeywordMapper.any(),
1042
- unknown: () => fakerKeywordMapper.unknown(),
1043
- void: () => fakerKeywordMapper.void(),
1044
- boolean: () => fakerKeywordMapper.boolean(),
1045
- null: () => fakerKeywordMapper.null(),
935
+ any: () => "undefined",
936
+ unknown: () => "undefined",
937
+ void: () => "undefined",
938
+ boolean: () => "faker.datatype.boolean()",
939
+ null: () => "null",
1046
940
  string(node) {
1047
- if (node.pattern) return fakerKeywordMapper.matches(node.pattern, this.options.regexGenerator);
1048
- if (node.format && integerFormats.has(node.format)) return fakerKeywordMapper.integerString(node.format);
1049
- return fakerKeywordMapper.string(node.min, node.max);
1050
- },
1051
- email: () => fakerKeywordMapper.email(),
1052
- url: () => fakerKeywordMapper.url(),
1053
- uuid: () => fakerKeywordMapper.uuid(),
1054
- number(node) {
1055
- return fakerKeywordMapper.number(node.min, node.max);
941
+ if (node.pattern) return matches(node.pattern, this.options.regexGenerator);
942
+ if (node.format && integerFormats.has(node.format)) return node.format === "int32" ? `faker.number.int({ max: ${maxInt32} }).toString()` : "faker.number.bigInt().toString()";
943
+ const { min, max } = node;
944
+ if (min !== void 0 && max !== void 0) return `faker.string.alpha({ length: { min: ${min}, max: ${max} } })`;
945
+ if (max !== void 0 || min !== void 0) return `faker.string.alpha({ length: ${max ?? min} })`;
946
+ return "faker.string.alpha()";
1056
947
  },
1057
- integer(node) {
1058
- return fakerKeywordMapper.integer(node.min, node.max);
1059
- },
1060
- bigint: () => fakerKeywordMapper.bigint(),
1061
- blob: () => fakerKeywordMapper.blob(),
1062
- datetime: () => fakerKeywordMapper.datetime(),
948
+ email: () => "faker.internet.email()",
949
+ url: () => "faker.internet.url()",
950
+ uuid: () => "faker.string.uuid()",
951
+ number: (node) => numberCall("float", node.min, node.max),
952
+ integer: (node) => numberCall("int", node.min, node.max),
953
+ bigint: () => "faker.number.bigInt()",
954
+ blob: () => "faker.image.url() as unknown as Blob",
955
+ datetime: () => "faker.date.anytime().toISOString()",
1063
956
  date(node) {
1064
- return fakerKeywordMapper.date(node.representation ?? "string", this.options.dateParser);
957
+ return dateTimeCall(node.representation ?? "string", {
958
+ format: "YYYY-MM-DD",
959
+ substring: "0, 10"
960
+ }, this.options.dateParser, this.options.schemaName);
1065
961
  },
1066
962
  time(node) {
1067
- return fakerKeywordMapper.time(node.representation ?? "string", this.options.dateParser);
963
+ return dateTimeCall(node.representation ?? "string", {
964
+ format: "HH:mm:ss",
965
+ substring: "11, 19"
966
+ }, this.options.dateParser, this.options.schemaName);
1068
967
  },
1069
968
  ref(node) {
1070
969
  const refName = ast.resolveRefName(node);
1071
- if (!refName) throw new Error("Name not defined for ref node");
970
+ if (!refName) throw new Diagnostics.Error({
971
+ code: Diagnostics.code.pluginFailed,
972
+ severity: "error",
973
+ message: `Ref node "${node.ref ?? node.name ?? "unknown"}"${this.options.schemaName ? ` in schema "${this.options.schemaName}"` : ""} has no name.`,
974
+ plugin: "plugin-faker"
975
+ });
1072
976
  if (this.options.schemaName && refName === this.options.schemaName) return this.options.typeName ? `undefined as unknown as ${this.options.typeName}` : "undefined as unknown";
1073
977
  const resolvedName = node.ref ? this.options.resolver.name(refName) : refName;
1074
978
  if (!this.options.nestedInObject) return `${resolvedName}(data)`;
1075
979
  return `${resolvedName}()`;
1076
980
  },
1077
981
  enum(node) {
1078
- return fakerKeywordMapper.enum(ast.getSchemaLiteralValues(node).map(parseEnumValue), this.options.typeName);
982
+ const { typeName } = this.options;
983
+ return `faker.helpers.arrayElement${typeName ? `<${typeName}>` : ""}([${ast.getSchemaLiteralValues(node).map(parseEnumValue).join(", ")}])`;
1079
984
  },
1080
985
  union(node) {
1081
986
  const { discriminatorPropertyName } = node;
1082
987
  const baseTypeName = this.options.typeName;
1083
- const items = mapSchemaMembers(node, (member) => {
988
+ return `faker.helpers.arrayElement([${mapSchemaMembers(node, (member) => {
1084
989
  const value = discriminatorPropertyName ? getDiscriminatorValue(member, discriminatorPropertyName) : void 0;
1085
990
  if (baseTypeName && value !== void 0) {
1086
991
  const typeName = `Extract<NonNullable<${baseTypeName}>, { ${JSON.stringify(discriminatorPropertyName)}: ${parseEnumValue(value)} }>`;
@@ -1095,26 +1000,31 @@ const printerFaker = ast.createPrinter((options) => {
1095
1000
  nestedInObject: true,
1096
1001
  nestedInUnion: true
1097
1002
  });
1098
- }).map(({ output }) => output).filter((item) => Boolean(item));
1099
- return fakerKeywordMapper.union(items);
1003
+ }).map(({ output }) => output).filter((item) => Boolean(item)).join(", ")}])`;
1100
1004
  },
1101
1005
  intersection(node) {
1102
1006
  const items = mapSchemaMembers(node, (member) => printNested(member, { nestedInObject: true })).map(({ output }) => output).filter((item) => Boolean(item) && item !== "undefined");
1103
- return fakerKeywordMapper.and(items);
1007
+ if (items.length === 0) return "{}";
1008
+ return items.length === 1 ? items[0] : `{...${items.join(", ...")}}`;
1104
1009
  },
1105
1010
  array(node) {
1106
1011
  const items = mapSchemaItems(node, (member) => printNested(member, {
1107
1012
  typeName: this.options.typeName ? `NonNullable<${this.options.typeName}>[number]` : void 0,
1108
1013
  nestedInObject: true
1109
1014
  })).map(({ output }) => output).filter((item) => Boolean(item));
1110
- return fakerKeywordMapper.array(items, node.min, node.max);
1015
+ if (items.length > 1) return `faker.helpers.arrayElements([${items.join(", ")}])`;
1016
+ const { min, max } = node;
1017
+ const item = items[0];
1018
+ if (min !== void 0 && max !== void 0) return `faker.helpers.multiple(() => (${item}), { count: { min: ${min}, max: ${max} }})`;
1019
+ if (min !== void 0) return `faker.helpers.multiple(() => (${item}), { count: ${min} })`;
1020
+ if (max !== void 0) return `faker.helpers.multiple(() => (${item}), { count: { min: 0, max: ${max} }})`;
1021
+ return `faker.helpers.multiple(() => (${item}))`;
1111
1022
  },
1112
1023
  tuple(node) {
1113
- const items = (node.items ?? []).map((member, index) => printNested(member, {
1024
+ return `[${(node.items ?? []).map((member, index) => printNested(member, {
1114
1025
  typeName: this.options.typeName ? `NonNullable<${this.options.typeName}>[${index}]` : void 0,
1115
1026
  nestedInObject: true
1116
- })).filter((item) => Boolean(item));
1117
- return fakerKeywordMapper.tuple(items);
1027
+ })).filter((item) => Boolean(item)).join(", ")}]`;
1118
1028
  },
1119
1029
  object(node) {
1120
1030
  const cyclicSchemas = this.options.cyclicSchemas;
@@ -1131,10 +1041,7 @@ const printerFaker = ast.createPrinter((options) => {
1131
1041
  }));
1132
1042
  }
1133
1043
  },
1134
- overrides: options.nodes,
1135
- print(node) {
1136
- return this.transform(node) ?? null;
1137
- }
1044
+ overrides: options.nodes
1138
1045
  };
1139
1046
  });
1140
1047
  //#endregion
@@ -1156,9 +1063,12 @@ const fakerGenerator = defineGenerator({
1156
1063
  const tsResolver = ctx.driver.getResolver(pluginTsName);
1157
1064
  const schemaName = node.name;
1158
1065
  const isEnumSchema = !!ast.narrowSchema(node, ast.schemaTypes.enum);
1159
- const tsEnumType = pluginTs.options?.enum?.type;
1160
- const tsEnumTypeSuffix = pluginTs.options?.enum?.typeSuffix ?? "Key";
1161
- const schemaTypeName = isEnumSchema && tsEnumType === "asConst" ? tsResolver.enum.keyName({ name: schemaName }, tsEnumTypeSuffix) : tsResolver.name(schemaName);
1066
+ const schemaTypeName = enumTypeName({
1067
+ resolver: tsResolver,
1068
+ name: schemaName,
1069
+ enumOptions: pluginTs.options?.enum,
1070
+ isEnum: isEnumSchema
1071
+ });
1162
1072
  const meta = {
1163
1073
  name: resolver.name(schemaName),
1164
1074
  file: resolver.file({
@@ -1339,7 +1249,7 @@ const fakerGenerator = defineGenerator({
1339
1249
  description: node.requestBody?.description ?? schema.description
1340
1250
  }));
1341
1251
  const responseName = resolver.response.response(node);
1342
- const hasResponseNameCollision = new Set(node.responses.flatMap((response) => (response.content ?? []).flatMap((entry) => entry.schema ? collectRefNames(entry.schema).map((name) => resolver.name(name)) : []))).has(responseName);
1252
+ const hasResponseNameCollision = new Set(node.responses.flatMap((response) => (response.content ?? []).flatMap((entry) => entry.schema ? ast.collectImportedRefNames(entry.schema).map((name) => resolver.name(name)) : []))).has(responseName);
1343
1253
  const localHelperNames = /* @__PURE__ */ new Set([
1344
1254
  ...paramGroups.map((group) => group.name),
1345
1255
  ...responseUnits.map((unit) => unit.name),
@@ -1468,20 +1378,8 @@ const fakerGenerator = defineGenerator({
1468
1378
  children: `faker.seed(${JSON.stringify(seed)})`
1469
1379
  }) : void 0,
1470
1380
  paramGroups.map((group) => renderEntry(group)),
1471
- responseUnits.map((unit) => renderEntry({
1472
- schema: unit.schema,
1473
- name: unit.name,
1474
- typeName: unit.typeName,
1475
- description: unit.description,
1476
- skipImportNames: unit.skipImportNames
1477
- })),
1478
- dataUnits.map((unit) => renderEntry({
1479
- schema: unit.schema,
1480
- name: unit.name,
1481
- typeName: unit.typeName,
1482
- description: unit.description,
1483
- skipImportNames: unit.skipImportNames
1484
- })),
1381
+ responseUnits.map((unit) => renderEntry(unit)),
1382
+ dataUnits.map((unit) => renderEntry(unit)),
1485
1383
  !hasResponseNameCollision && renderEntry({
1486
1384
  schema: buildResponseUnionSchema(node, resolver),
1487
1385
  name: responseName,
@@ -1500,7 +1398,7 @@ var compatibility = {
1500
1398
  };
1501
1399
  //#endregion
1502
1400
  //#region package.json
1503
- var version = "5.1.5";
1401
+ var version = "5.1.7";
1504
1402
  //#endregion
1505
1403
  //#region src/resolvers/resolverFaker.ts
1506
1404
  /**
@@ -1568,6 +1466,18 @@ const pluginFaker = defineExtension({
1568
1466
  path: "mocks",
1569
1467
  barrel: { type: "named" }
1570
1468
  }, seed, locale = "en", group, exclude = [], include, override = [], typeMode = "inferred", dateParser = "faker", regexGenerator = "faker", printer, resolver: userResolver, macros: userMacros } = options;
1469
+ assertPluginOption({
1470
+ plugin: pluginFakerName,
1471
+ option: "typeMode",
1472
+ value: typeMode,
1473
+ allowed: ["inferred", "schema"]
1474
+ });
1475
+ assertPluginOption({
1476
+ plugin: pluginFakerName,
1477
+ option: "regexGenerator",
1478
+ value: regexGenerator,
1479
+ allowed: ["faker", "randexp"]
1480
+ });
1571
1481
  setResolver(userResolver ? Resolver.merge(resolverFaker, userResolver) : resolverFaker);
1572
1482
  if (userMacros?.length) setMacros(userMacros);
1573
1483
  addGenerator(fakerGenerator);