@kubb/plugin-faker 5.0.0-beta.99 → 5.0.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.d.ts CHANGED
@@ -229,11 +229,10 @@ type Props = {
229
229
  typeName: string;
230
230
  node: ast.SchemaNode;
231
231
  printer: ast.Printer<PrinterFakerFactory>;
232
- seed?: PluginFaker['options']['seed'];
233
232
  description?: string;
234
233
  canOverride: boolean;
235
234
  };
236
- declare function Faker({ node, description, name, typeName, printer, seed, canOverride }: Props): KubbReactNode;
235
+ declare function Faker({ node, description, name, typeName, printer, canOverride }: Props): KubbReactNode;
237
236
  //#endregion
238
237
  //#region src/generators/fakerGenerator.d.ts
239
238
  /**
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import "./rolldown-runtime-C0LytTxp.js";
2
2
  import { posix } from "node:path";
3
- import { Resolver, ast, createResolver, defineGenerator, definePlugin } from "kubb/kit";
3
+ import { Resolver, ast, containsCircularRef, createResolver, defineGenerator, definePlugin } from "kubb/kit";
4
4
  import { buildParams, createFunctionParameter, createFunctionParameters, functionPrinter, pluginTsName } from "@kubb/plugin-ts";
5
5
  import { File, Function, jsxRenderer } from "kubb/jsx";
6
6
  import { Fragment, jsx, jsxs } from "kubb/jsx/jsx-runtime";
@@ -561,7 +561,7 @@ const SCALAR_TYPES = /* @__PURE__ */ new Set([
561
561
  "enum"
562
562
  ]);
563
563
  const declarationPrinter = functionPrinter({ mode: "declaration" });
564
- function Faker({ node, description, name, typeName, printer, seed, canOverride }) {
564
+ function Faker({ node, description, name, typeName, printer, canOverride }) {
565
565
  const fakerText = printer.print(node) ?? "undefined";
566
566
  const isArray = node.type === "array";
567
567
  const isObject = OBJECT_TYPES.has(node.type);
@@ -576,8 +576,9 @@ function Faker({ node, description, name, typeName, printer, seed, canOverride }
576
576
  })();
577
577
  const { dataType, returnType: resolvedReturnType } = resolveFakerTypeUsage(node, typeName, canOverride);
578
578
  if (!useGenericOverride) {
579
+ const dataParamName = /\bdata\b/.test(fakerTextWithOverride) ? "data" : "_data";
579
580
  const params = createFunctionParameters({ params: [createFunctionParameter({
580
- name: /\bdata\b/.test(fakerTextWithOverride) ? "data" : "_data",
581
+ name: dataParamName,
581
582
  type: dataType,
582
583
  optional: true
583
584
  })] });
@@ -588,24 +589,23 @@ function Faker({ node, description, name, typeName, printer, seed, canOverride }
588
589
  name,
589
590
  isExportable: true,
590
591
  isIndexable: true,
591
- children: /* @__PURE__ */ jsxs(Function, {
592
+ children: /* @__PURE__ */ jsx(Function, {
592
593
  export: true,
593
594
  name,
594
595
  JSDoc: { comments: description ? [`@description ${jsStringEscape(description)}`] : [] },
595
596
  params: canOverride ? paramsSignature : void 0,
596
597
  returnType: returnType ?? void 0,
597
- children: [seed ? /* @__PURE__ */ jsxs(Fragment, { children: [`faker.seed(${JSON.stringify(seed)})`, /* @__PURE__ */ jsx("br", {})] }) : void 0, `return ${returnExpression}`]
598
+ children: `return ${returnExpression}`
598
599
  })
599
600
  });
600
601
  }
601
602
  const functionSignature = `${description ? `/**\n * @description ${jsStringEscape(description)}\n */\n ` : ""}export function ${name}<TData extends Partial<${typeName}> = object>(data?: TData)`;
602
- const seedCode = seed ? `faker.seed(${JSON.stringify(seed)})\n ` : "";
603
603
  const { cyclicSchemas, schemaName } = printer.options;
604
- const functionBody = node.type === "object" && !!cyclicSchemas && (node.properties ?? []).some((p) => ast.containsCircularRef(p.schema, {
604
+ const functionBody = node.type === "object" && !!cyclicSchemas && (node.properties ?? []).some((p) => containsCircularRef(p.schema, {
605
605
  circularSchemas: cyclicSchemas,
606
606
  excludeName: schemaName
607
607
  })) ? `{
608
- ${seedCode}const defaultFakeData = ${fakerText}
608
+ const defaultFakeData = ${fakerText}
609
609
  if (data) {
610
610
  for (const [key, value] of Object.entries(data)) {
611
611
  Object.defineProperty(defaultFakeData, key, { value, configurable: true, writable: true, enumerable: true })
@@ -613,7 +613,7 @@ function Faker({ node, description, name, typeName, printer, seed, canOverride }
613
613
  }
614
614
  return defaultFakeData as Omit<typeof defaultFakeData, keyof TData> & TData
615
615
  }` : `{
616
- ${seedCode}const defaultFakeData = ${fakerText}
616
+ const defaultFakeData = ${fakerText}
617
617
  return {
618
618
  ...defaultFakeData,
619
619
  ...(data || {}),
@@ -647,6 +647,45 @@ function dedupeParams(params) {
647
647
  //#endregion
648
648
  //#region ../../internals/shared/src/operation.ts
649
649
  /**
650
+ * Builds the `ResolverFileParams` every operation generator passes to
651
+ * `resolver.file`: a file named `name`, tagged by the operation's first
652
+ * tag (or `'default'`), at the operation's path. Centralizes the entry object
653
+ * that was repeated at dozens of call sites across the client and query plugins.
654
+ *
655
+ * @example
656
+ * ```ts
657
+ * resolver.file(operationFileEntry(node, node.operationId), { root, output, group })
658
+ * ```
659
+ */
660
+ function operationFileEntry(node, name, extname = ".ts") {
661
+ return {
662
+ name,
663
+ extname,
664
+ tag: node.tags[0] ?? "default",
665
+ path: node.path
666
+ };
667
+ }
668
+ /**
669
+ * Resolves a dependency plugin's generated file for `node.operationId`, cached in `cache` (the
670
+ * current node's `ctx.cache`) under the resolver's own plugin name. Several dependents reading the
671
+ * same dependency for the same operation in one pass (a query plugin's several hook generators, the
672
+ * MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.
673
+ *
674
+ * @example Cache `plugin-ts`'s file for the current operation
675
+ * ```ts
676
+ * const fileTs = resolveDependencyOperationFile({ cache: ctx.cache, node, resolver: tsResolver, root, output })
677
+ * ```
678
+ */
679
+ function resolveDependencyOperationFile(options) {
680
+ const { cache, node, resolver, root, output, group } = options;
681
+ return cache.ensureItem(`${resolver.pluginName}:operationFile`, () => resolver.file({
682
+ ...operationFileEntry(node, node.operationId),
683
+ root,
684
+ output,
685
+ group: group ?? void 0
686
+ }));
687
+ }
688
+ /**
650
689
  * Maps a content type to the PascalCase suffix used to name per-content-type variants
651
690
  * (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).
652
691
  */
@@ -694,16 +733,24 @@ function resolveContentTypeVariants(entries, baseName) {
694
733
  };
695
734
  });
696
735
  }
736
+ const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
737
+ /**
738
+ * Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
739
+ * group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
740
+ * (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
741
+ * same parameters once per plugin.
742
+ */
697
743
  function getOperationParameters(node) {
698
- return {
699
- path: dedupeParams(node.parameters.filter((param) => param.in === "path").map((param) => isValidVarName(param.name) ? param : {
700
- ...param,
701
- name: camelCase(param.name)
702
- })),
744
+ const cached = operationParameterGroupsByNode.get(node);
745
+ if (cached) return cached;
746
+ const groups = {
747
+ path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
703
748
  query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
704
749
  header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
705
750
  cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
706
751
  };
752
+ operationParameterGroupsByNode.set(node, groups);
753
+ return groups;
707
754
  }
708
755
  //#endregion
709
756
  //#region ../../internals/shared/src/resolver.ts
@@ -835,6 +882,18 @@ function mapSchemaItems(node, transform) {
835
882
  }
836
883
  //#endregion
837
884
  //#region src/printers/printerFaker.ts
885
+ /**
886
+ * Formats that put a whole number inside a `type: 'string'` schema, the way ProtoJSON encodes
887
+ * 64-bit integers, so the mock has to be digits rather than letters.
888
+ *
889
+ * @see https://protobuf.dev/programming-guides/json/#int64-strings
890
+ */
891
+ const integerFormats = /* @__PURE__ */ new Set([
892
+ "int32",
893
+ "int64",
894
+ "uint64"
895
+ ]);
896
+ const maxInt32 = 2147483647;
838
897
  const fakerKeywordMapper = {
839
898
  any: () => "undefined",
840
899
  unknown: () => "undefined",
@@ -852,6 +911,10 @@ const fakerKeywordMapper = {
852
911
  return "faker.number.int()";
853
912
  },
854
913
  bigint: () => "faker.number.bigInt()",
914
+ integerString: (format) => {
915
+ if (format === "int32") return `faker.number.int({ max: ${maxInt32} }).toString()`;
916
+ return "faker.number.bigInt().toString()";
917
+ },
855
918
  string: (min, max) => {
856
919
  if (max !== void 0 && min !== void 0) return `faker.string.alpha({ length: { min: ${min}, max: ${max} } })`;
857
920
  if (max !== void 0) return `faker.string.alpha({ length: ${max} })`;
@@ -951,6 +1014,7 @@ const printerFaker = ast.createPrinter((options) => {
951
1014
  null: () => fakerKeywordMapper.null(),
952
1015
  string(node) {
953
1016
  if (node.pattern) return fakerKeywordMapper.matches(node.pattern, this.options.regexGenerator);
1017
+ if (node.format && integerFormats.has(node.format)) return fakerKeywordMapper.integerString(node.format);
954
1018
  return fakerKeywordMapper.string(node.min, node.max);
955
1019
  },
956
1020
  email: () => fakerKeywordMapper.email(),
@@ -1027,7 +1091,7 @@ const printerFaker = ast.createPrinter((options) => {
1027
1091
  typeName: this.options.typeName ? indexedTypeName(this.options.typeName, property.name, this.options.nestedInUnion) : void 0,
1028
1092
  nestedInObject: true
1029
1093
  }) ?? "undefined";
1030
- if (cyclicSchemas && ast.containsCircularRef(property.schema, {
1094
+ if (cyclicSchemas && containsCircularRef(property.schema, {
1031
1095
  circularSchemas: cyclicSchemas,
1032
1096
  excludeName: this.options.schemaName
1033
1097
  })) 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 }`;
@@ -1158,13 +1222,16 @@ const fakerGenerator = defineGenerator({
1158
1222
  imp.path,
1159
1223
  imp.name
1160
1224
  ].join("-"))),
1225
+ seed ? /* @__PURE__ */ jsx(File.Source, {
1226
+ name: "faker-seed",
1227
+ children: `faker.seed(${JSON.stringify(seed)})`
1228
+ }) : void 0,
1161
1229
  /* @__PURE__ */ jsx(Faker, {
1162
1230
  name: meta.name,
1163
1231
  typeName: typeReference.typeName,
1164
1232
  description: node.description,
1165
1233
  node,
1166
1234
  printer: printerInstance,
1167
- seed,
1168
1235
  canOverride
1169
1236
  })
1170
1237
  ]
@@ -1256,14 +1323,13 @@ const fakerGenerator = defineGenerator({
1256
1323
  output,
1257
1324
  group: group ?? void 0
1258
1325
  }),
1259
- typeFile: tsResolver.file({
1260
- name: node.operationId,
1261
- extname: ".ts",
1262
- tag: node.tags[0] ?? "default",
1263
- path: node.path,
1326
+ typeFile: resolveDependencyOperationFile({
1327
+ cache: ctx.cache,
1328
+ node,
1329
+ resolver: tsResolver,
1264
1330
  root,
1265
1331
  output: pluginTs.options?.output ?? output,
1266
- group: pluginTs.options?.group ?? void 0
1332
+ group: pluginTs.options?.group
1267
1333
  })
1268
1334
  };
1269
1335
  function resolveMockImports(schema) {
@@ -1322,7 +1388,6 @@ const fakerGenerator = defineGenerator({
1322
1388
  ...printerInstance,
1323
1389
  print: () => rewrittenFakerText
1324
1390
  },
1325
- seed,
1326
1391
  canOverride
1327
1392
  })
1328
1393
  ] });
@@ -1363,6 +1428,10 @@ const fakerGenerator = defineGenerator({
1363
1428
  path: dateParser,
1364
1429
  name: dateParser
1365
1430
  }),
1431
+ seed ? /* @__PURE__ */ jsx(File.Source, {
1432
+ name: "faker-seed",
1433
+ children: `faker.seed(${JSON.stringify(seed)})`
1434
+ }) : void 0,
1366
1435
  paramGroups.map((group) => renderEntry(group)),
1367
1436
  responseUnits.map((unit) => renderEntry({
1368
1437
  schema: unit.schema,