@kubb/plugin-faker 5.0.0-beta.99 → 5.0.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.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";
@@ -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
  })] });
@@ -601,7 +602,7 @@ function Faker({ node, description, name, typeName, printer, seed, canOverride }
601
602
  const functionSignature = `${description ? `/**\n * @description ${jsStringEscape(description)}\n */\n ` : ""}export function ${name}<TData extends Partial<${typeName}> = object>(data?: TData)`;
602
603
  const seedCode = seed ? `faker.seed(${JSON.stringify(seed)})\n ` : "";
603
604
  const { cyclicSchemas, schemaName } = printer.options;
604
- const functionBody = node.type === "object" && !!cyclicSchemas && (node.properties ?? []).some((p) => ast.containsCircularRef(p.schema, {
605
+ const functionBody = node.type === "object" && !!cyclicSchemas && (node.properties ?? []).some((p) => containsCircularRef(p.schema, {
605
606
  circularSchemas: cyclicSchemas,
606
607
  excludeName: schemaName
607
608
  })) ? `{
@@ -647,6 +648,45 @@ function dedupeParams(params) {
647
648
  //#endregion
648
649
  //#region ../../internals/shared/src/operation.ts
649
650
  /**
651
+ * Builds the `ResolverFileParams` every operation generator passes to
652
+ * `resolver.file`: a file named `name`, tagged by the operation's first
653
+ * tag (or `'default'`), at the operation's path. Centralizes the entry object
654
+ * that was repeated at dozens of call sites across the client and query plugins.
655
+ *
656
+ * @example
657
+ * ```ts
658
+ * resolver.file(operationFileEntry(node, node.operationId), { root, output, group })
659
+ * ```
660
+ */
661
+ function operationFileEntry(node, name, extname = ".ts") {
662
+ return {
663
+ name,
664
+ extname,
665
+ tag: node.tags[0] ?? "default",
666
+ path: node.path
667
+ };
668
+ }
669
+ /**
670
+ * Resolves a dependency plugin's generated file for `node.operationId`, cached in `cache` (the
671
+ * current node's `ctx.cache`) under the resolver's own plugin name. Several dependents reading the
672
+ * same dependency for the same operation in one pass (a query plugin's several hook generators, the
673
+ * MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.
674
+ *
675
+ * @example Cache `plugin-ts`'s file for the current operation
676
+ * ```ts
677
+ * const fileTs = resolveDependencyOperationFile({ cache: ctx.cache, node, resolver: tsResolver, root, output })
678
+ * ```
679
+ */
680
+ function resolveDependencyOperationFile(options) {
681
+ const { cache, node, resolver, root, output, group } = options;
682
+ return cache.ensureItem(`${resolver.pluginName}:operationFile`, () => resolver.file({
683
+ ...operationFileEntry(node, node.operationId),
684
+ root,
685
+ output,
686
+ group: group ?? void 0
687
+ }));
688
+ }
689
+ /**
650
690
  * Maps a content type to the PascalCase suffix used to name per-content-type variants
651
691
  * (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).
652
692
  */
@@ -694,16 +734,24 @@ function resolveContentTypeVariants(entries, baseName) {
694
734
  };
695
735
  });
696
736
  }
737
+ const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
738
+ /**
739
+ * Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
740
+ * group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
741
+ * (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
742
+ * same parameters once per plugin.
743
+ */
697
744
  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
- })),
745
+ const cached = operationParameterGroupsByNode.get(node);
746
+ if (cached) return cached;
747
+ const groups = {
748
+ path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
703
749
  query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
704
750
  header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
705
751
  cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
706
752
  };
753
+ operationParameterGroupsByNode.set(node, groups);
754
+ return groups;
707
755
  }
708
756
  //#endregion
709
757
  //#region ../../internals/shared/src/resolver.ts
@@ -835,6 +883,18 @@ function mapSchemaItems(node, transform) {
835
883
  }
836
884
  //#endregion
837
885
  //#region src/printers/printerFaker.ts
886
+ /**
887
+ * Formats that put a whole number inside a `type: 'string'` schema, the way ProtoJSON encodes
888
+ * 64-bit integers, so the mock has to be digits rather than letters.
889
+ *
890
+ * @see https://protobuf.dev/programming-guides/json/#int64-strings
891
+ */
892
+ const integerFormats = /* @__PURE__ */ new Set([
893
+ "int32",
894
+ "int64",
895
+ "uint64"
896
+ ]);
897
+ const maxInt32 = 2147483647;
838
898
  const fakerKeywordMapper = {
839
899
  any: () => "undefined",
840
900
  unknown: () => "undefined",
@@ -852,6 +912,10 @@ const fakerKeywordMapper = {
852
912
  return "faker.number.int()";
853
913
  },
854
914
  bigint: () => "faker.number.bigInt()",
915
+ integerString: (format) => {
916
+ if (format === "int32") return `faker.number.int({ max: ${maxInt32} }).toString()`;
917
+ return "faker.number.bigInt().toString()";
918
+ },
855
919
  string: (min, max) => {
856
920
  if (max !== void 0 && min !== void 0) return `faker.string.alpha({ length: { min: ${min}, max: ${max} } })`;
857
921
  if (max !== void 0) return `faker.string.alpha({ length: ${max} })`;
@@ -951,6 +1015,7 @@ const printerFaker = ast.createPrinter((options) => {
951
1015
  null: () => fakerKeywordMapper.null(),
952
1016
  string(node) {
953
1017
  if (node.pattern) return fakerKeywordMapper.matches(node.pattern, this.options.regexGenerator);
1018
+ if (node.format && integerFormats.has(node.format)) return fakerKeywordMapper.integerString(node.format);
954
1019
  return fakerKeywordMapper.string(node.min, node.max);
955
1020
  },
956
1021
  email: () => fakerKeywordMapper.email(),
@@ -1027,7 +1092,7 @@ const printerFaker = ast.createPrinter((options) => {
1027
1092
  typeName: this.options.typeName ? indexedTypeName(this.options.typeName, property.name, this.options.nestedInUnion) : void 0,
1028
1093
  nestedInObject: true
1029
1094
  }) ?? "undefined";
1030
- if (cyclicSchemas && ast.containsCircularRef(property.schema, {
1095
+ if (cyclicSchemas && containsCircularRef(property.schema, {
1031
1096
  circularSchemas: cyclicSchemas,
1032
1097
  excludeName: this.options.schemaName
1033
1098
  })) 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 }`;
@@ -1256,14 +1321,13 @@ const fakerGenerator = defineGenerator({
1256
1321
  output,
1257
1322
  group: group ?? void 0
1258
1323
  }),
1259
- typeFile: tsResolver.file({
1260
- name: node.operationId,
1261
- extname: ".ts",
1262
- tag: node.tags[0] ?? "default",
1263
- path: node.path,
1324
+ typeFile: resolveDependencyOperationFile({
1325
+ cache: ctx.cache,
1326
+ node,
1327
+ resolver: tsResolver,
1264
1328
  root,
1265
1329
  output: pluginTs.options?.output ?? output,
1266
- group: pluginTs.options?.group ?? void 0
1330
+ group: pluginTs.options?.group
1267
1331
  })
1268
1332
  };
1269
1333
  function resolveMockImports(schema) {