@kubb/plugin-faker 5.0.0-beta.98 → 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.cjs +116 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +117 -53
- package/dist/index.js.map +1 -1
- package/package.json +6 -9
package/dist/index.cjs
CHANGED
|
@@ -580,8 +580,9 @@ function Faker({ node, description, name, typeName, printer, seed, canOverride }
|
|
|
580
580
|
})();
|
|
581
581
|
const { dataType, returnType: resolvedReturnType } = resolveFakerTypeUsage(node, typeName, canOverride);
|
|
582
582
|
if (!useGenericOverride) {
|
|
583
|
+
const dataParamName = /\bdata\b/.test(fakerTextWithOverride) ? "data" : "_data";
|
|
583
584
|
const params = (0, _kubb_plugin_ts.createFunctionParameters)({ params: [(0, _kubb_plugin_ts.createFunctionParameter)({
|
|
584
|
-
name:
|
|
585
|
+
name: dataParamName,
|
|
585
586
|
type: dataType,
|
|
586
587
|
optional: true
|
|
587
588
|
})] });
|
|
@@ -605,7 +606,7 @@ function Faker({ node, description, name, typeName, printer, seed, canOverride }
|
|
|
605
606
|
const functionSignature = `${description ? `/**\n * @description ${jsStringEscape(description)}\n */\n ` : ""}export function ${name}<TData extends Partial<${typeName}> = object>(data?: TData)`;
|
|
606
607
|
const seedCode = seed ? `faker.seed(${JSON.stringify(seed)})\n ` : "";
|
|
607
608
|
const { cyclicSchemas, schemaName } = printer.options;
|
|
608
|
-
const functionBody = node.type === "object" && !!cyclicSchemas && (node.properties ?? []).some((p) => kubb_kit.
|
|
609
|
+
const functionBody = node.type === "object" && !!cyclicSchemas && (node.properties ?? []).some((p) => (0, kubb_kit.containsCircularRef)(p.schema, {
|
|
609
610
|
circularSchemas: cyclicSchemas,
|
|
610
611
|
excludeName: schemaName
|
|
611
612
|
})) ? `{
|
|
@@ -632,45 +633,64 @@ function Faker({ node, description, name, typeName, printer, seed, canOverride }
|
|
|
632
633
|
}
|
|
633
634
|
//#endregion
|
|
634
635
|
//#region ../../internals/shared/src/params.ts
|
|
635
|
-
const caseParamsCache = /* @__PURE__ */ new WeakMap();
|
|
636
636
|
/**
|
|
637
|
-
*
|
|
637
|
+
* Drops parameters that share the same name, keeping the first.
|
|
638
638
|
*
|
|
639
|
-
*
|
|
640
|
-
*
|
|
641
|
-
*
|
|
639
|
+
* A malformed spec can declare the same parameter name twice within one `in` location. Both would
|
|
640
|
+
* resolve to the same output property, so emitting both would yield an object type with a duplicate
|
|
641
|
+
* member, which TypeScript rejects. This is a defensive guard against that case, not a casing guard:
|
|
642
|
+
* parameter names flow through unchanged, so no two distinct names ever collide here anymore.
|
|
642
643
|
*/
|
|
643
|
-
function
|
|
644
|
-
if (!casing) return params;
|
|
645
|
-
const cached = caseParamsCache.get(params);
|
|
646
|
-
if (cached) return cached;
|
|
647
|
-
const result = params.map((param) => ({
|
|
648
|
-
...param,
|
|
649
|
-
name: camelCase(param.name)
|
|
650
|
-
}));
|
|
651
|
-
caseParamsCache.set(params, result);
|
|
652
|
-
return result;
|
|
653
|
-
}
|
|
654
|
-
/**
|
|
655
|
-
* Drops parameters that collapse to the same property identity once camelCased, keeping the first.
|
|
656
|
-
*
|
|
657
|
-
* Some specs declare the same parameter twice under different casings (for example AWS S3 lists both
|
|
658
|
-
* `max-uploads` and `MaxUploads`). Both resolve to one output property, so emitting both would yield
|
|
659
|
-
* an object type with a duplicate member, which TypeScript rejects. De-duplicate by the camelCased
|
|
660
|
-
* identity so the resulting group is collision-free regardless of the names each caller carries.
|
|
661
|
-
*/
|
|
662
|
-
function dedupeByCasedName(params) {
|
|
644
|
+
function dedupeParams(params) {
|
|
663
645
|
const seen = /* @__PURE__ */ new Set();
|
|
664
646
|
return params.filter((param) => {
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
seen.add(key);
|
|
647
|
+
if (seen.has(param.name)) return false;
|
|
648
|
+
seen.add(param.name);
|
|
668
649
|
return true;
|
|
669
650
|
});
|
|
670
651
|
}
|
|
671
652
|
//#endregion
|
|
672
653
|
//#region ../../internals/shared/src/operation.ts
|
|
673
654
|
/**
|
|
655
|
+
* Builds the `ResolverFileParams` every operation generator passes to
|
|
656
|
+
* `resolver.file`: a file named `name`, tagged by the operation's first
|
|
657
|
+
* tag (or `'default'`), at the operation's path. Centralizes the entry object
|
|
658
|
+
* that was repeated at dozens of call sites across the client and query plugins.
|
|
659
|
+
*
|
|
660
|
+
* @example
|
|
661
|
+
* ```ts
|
|
662
|
+
* resolver.file(operationFileEntry(node, node.operationId), { root, output, group })
|
|
663
|
+
* ```
|
|
664
|
+
*/
|
|
665
|
+
function operationFileEntry(node, name, extname = ".ts") {
|
|
666
|
+
return {
|
|
667
|
+
name,
|
|
668
|
+
extname,
|
|
669
|
+
tag: node.tags[0] ?? "default",
|
|
670
|
+
path: node.path
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Resolves a dependency plugin's generated file for `node.operationId`, cached in `cache` (the
|
|
675
|
+
* current node's `ctx.cache`) under the resolver's own plugin name. Several dependents reading the
|
|
676
|
+
* same dependency for the same operation in one pass (a query plugin's several hook generators, the
|
|
677
|
+
* MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.
|
|
678
|
+
*
|
|
679
|
+
* @example Cache `plugin-ts`'s file for the current operation
|
|
680
|
+
* ```ts
|
|
681
|
+
* const fileTs = resolveDependencyOperationFile({ cache: ctx.cache, node, resolver: tsResolver, root, output })
|
|
682
|
+
* ```
|
|
683
|
+
*/
|
|
684
|
+
function resolveDependencyOperationFile(options) {
|
|
685
|
+
const { cache, node, resolver, root, output, group } = options;
|
|
686
|
+
return cache.ensureItem(`${resolver.pluginName}:operationFile`, () => resolver.file({
|
|
687
|
+
...operationFileEntry(node, node.operationId),
|
|
688
|
+
root,
|
|
689
|
+
output,
|
|
690
|
+
group: group ?? void 0
|
|
691
|
+
}));
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
674
694
|
* Maps a content type to the PascalCase suffix used to name per-content-type variants
|
|
675
695
|
* (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).
|
|
676
696
|
*/
|
|
@@ -718,14 +738,24 @@ function resolveContentTypeVariants(entries, baseName) {
|
|
|
718
738
|
};
|
|
719
739
|
});
|
|
720
740
|
}
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
741
|
+
const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
|
|
742
|
+
/**
|
|
743
|
+
* Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
|
|
744
|
+
* group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
|
|
745
|
+
* (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
|
|
746
|
+
* same parameters once per plugin.
|
|
747
|
+
*/
|
|
748
|
+
function getOperationParameters(node) {
|
|
749
|
+
const cached = operationParameterGroupsByNode.get(node);
|
|
750
|
+
if (cached) return cached;
|
|
751
|
+
const groups = {
|
|
752
|
+
path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
|
|
753
|
+
query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
|
|
754
|
+
header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
|
|
755
|
+
cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
|
|
728
756
|
};
|
|
757
|
+
operationParameterGroupsByNode.set(node, groups);
|
|
758
|
+
return groups;
|
|
729
759
|
}
|
|
730
760
|
//#endregion
|
|
731
761
|
//#region ../../internals/shared/src/resolver.ts
|
|
@@ -834,7 +864,41 @@ function createGroupConfig(group) {
|
|
|
834
864
|
};
|
|
835
865
|
}
|
|
836
866
|
//#endregion
|
|
867
|
+
//#region ../../internals/shared/src/schemaTraversal.ts
|
|
868
|
+
/**
|
|
869
|
+
* Maps each member of a union or intersection schema to its transformed output, pairing every
|
|
870
|
+
* result with the original member.
|
|
871
|
+
*/
|
|
872
|
+
function mapSchemaMembers(node, transform) {
|
|
873
|
+
return (node.members ?? []).map((schema) => ({
|
|
874
|
+
schema,
|
|
875
|
+
output: transform(schema)
|
|
876
|
+
}));
|
|
877
|
+
}
|
|
878
|
+
/**
|
|
879
|
+
* Maps each item of an array or tuple schema to its transformed output, pairing every result with
|
|
880
|
+
* the original item.
|
|
881
|
+
*/
|
|
882
|
+
function mapSchemaItems(node, transform) {
|
|
883
|
+
return (node.items ?? []).map((schema) => ({
|
|
884
|
+
schema,
|
|
885
|
+
output: transform(schema)
|
|
886
|
+
}));
|
|
887
|
+
}
|
|
888
|
+
//#endregion
|
|
837
889
|
//#region src/printers/printerFaker.ts
|
|
890
|
+
/**
|
|
891
|
+
* Formats that put a whole number inside a `type: 'string'` schema, the way ProtoJSON encodes
|
|
892
|
+
* 64-bit integers, so the mock has to be digits rather than letters.
|
|
893
|
+
*
|
|
894
|
+
* @see https://protobuf.dev/programming-guides/json/#int64-strings
|
|
895
|
+
*/
|
|
896
|
+
const integerFormats = /* @__PURE__ */ new Set([
|
|
897
|
+
"int32",
|
|
898
|
+
"int64",
|
|
899
|
+
"uint64"
|
|
900
|
+
]);
|
|
901
|
+
const maxInt32 = 2147483647;
|
|
838
902
|
const fakerKeywordMapper = {
|
|
839
903
|
any: () => "undefined",
|
|
840
904
|
unknown: () => "undefined",
|
|
@@ -852,6 +916,10 @@ const fakerKeywordMapper = {
|
|
|
852
916
|
return "faker.number.int()";
|
|
853
917
|
},
|
|
854
918
|
bigint: () => "faker.number.bigInt()",
|
|
919
|
+
integerString: (format) => {
|
|
920
|
+
if (format === "int32") return `faker.number.int({ max: ${maxInt32} }).toString()`;
|
|
921
|
+
return "faker.number.bigInt().toString()";
|
|
922
|
+
},
|
|
855
923
|
string: (min, max) => {
|
|
856
924
|
if (max !== void 0 && min !== void 0) return `faker.string.alpha({ length: { min: ${min}, max: ${max} } })`;
|
|
857
925
|
if (max !== void 0) return `faker.string.alpha({ length: ${max} })`;
|
|
@@ -951,6 +1019,7 @@ const printerFaker = kubb_kit.ast.createPrinter((options) => {
|
|
|
951
1019
|
null: () => fakerKeywordMapper.null(),
|
|
952
1020
|
string(node) {
|
|
953
1021
|
if (node.pattern) return fakerKeywordMapper.matches(node.pattern, this.options.regexGenerator);
|
|
1022
|
+
if (node.format && integerFormats.has(node.format)) return fakerKeywordMapper.integerString(node.format);
|
|
954
1023
|
return fakerKeywordMapper.string(node.min, node.max);
|
|
955
1024
|
},
|
|
956
1025
|
email: () => fakerKeywordMapper.email(),
|
|
@@ -985,7 +1054,7 @@ const printerFaker = kubb_kit.ast.createPrinter((options) => {
|
|
|
985
1054
|
union(node) {
|
|
986
1055
|
const { discriminatorPropertyName } = node;
|
|
987
1056
|
const baseTypeName = this.options.typeName;
|
|
988
|
-
const items =
|
|
1057
|
+
const items = mapSchemaMembers(node, (member) => {
|
|
989
1058
|
const value = discriminatorPropertyName ? getDiscriminatorValue(member, discriminatorPropertyName) : void 0;
|
|
990
1059
|
if (baseTypeName && value !== void 0) {
|
|
991
1060
|
const typeName = `Extract<NonNullable<${baseTypeName}>, { ${JSON.stringify(discriminatorPropertyName)}: ${parseEnumValue(value)} }>`;
|
|
@@ -1003,11 +1072,11 @@ const printerFaker = kubb_kit.ast.createPrinter((options) => {
|
|
|
1003
1072
|
return fakerKeywordMapper.union(items);
|
|
1004
1073
|
},
|
|
1005
1074
|
intersection(node) {
|
|
1006
|
-
const items =
|
|
1075
|
+
const items = mapSchemaMembers(node, (member) => printNested(member, { nestedInObject: true })).map(({ output }) => output).filter((item) => Boolean(item) && item !== "undefined");
|
|
1007
1076
|
return fakerKeywordMapper.and(items);
|
|
1008
1077
|
},
|
|
1009
1078
|
array(node) {
|
|
1010
|
-
const items =
|
|
1079
|
+
const items = mapSchemaItems(node, (member) => printNested(member, {
|
|
1011
1080
|
typeName: this.options.typeName ? `NonNullable<${this.options.typeName}>[number]` : void 0,
|
|
1012
1081
|
nestedInObject: true
|
|
1013
1082
|
})).map(({ output }) => output).filter((item) => Boolean(item));
|
|
@@ -1027,7 +1096,7 @@ const printerFaker = kubb_kit.ast.createPrinter((options) => {
|
|
|
1027
1096
|
typeName: this.options.typeName ? indexedTypeName(this.options.typeName, property.name, this.options.nestedInUnion) : void 0,
|
|
1028
1097
|
nestedInObject: true
|
|
1029
1098
|
}) ?? "undefined";
|
|
1030
|
-
if (cyclicSchemas && kubb_kit.
|
|
1099
|
+
if (cyclicSchemas && (0, kubb_kit.containsCircularRef)(property.schema, {
|
|
1031
1100
|
circularSchemas: cyclicSchemas,
|
|
1032
1101
|
excludeName: this.options.schemaName
|
|
1033
1102
|
})) 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 }`;
|
|
@@ -1176,11 +1245,7 @@ const fakerGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1176
1245
|
const pluginTs = ctx.driver.getPlugin(_kubb_plugin_ts.pluginTsName);
|
|
1177
1246
|
if (!pluginTs) return;
|
|
1178
1247
|
const tsResolver = ctx.driver.getResolver(_kubb_plugin_ts.pluginTsName);
|
|
1179
|
-
const
|
|
1180
|
-
const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters({
|
|
1181
|
-
...node,
|
|
1182
|
-
parameters: params
|
|
1183
|
-
}, { paramsCasing: "original" });
|
|
1248
|
+
const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node);
|
|
1184
1249
|
const paramGroups = [
|
|
1185
1250
|
{
|
|
1186
1251
|
params: pathParams,
|
|
@@ -1260,14 +1325,13 @@ const fakerGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1260
1325
|
output,
|
|
1261
1326
|
group: group ?? void 0
|
|
1262
1327
|
}),
|
|
1263
|
-
typeFile:
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
path: node.path,
|
|
1328
|
+
typeFile: resolveDependencyOperationFile({
|
|
1329
|
+
cache: ctx.cache,
|
|
1330
|
+
node,
|
|
1331
|
+
resolver: tsResolver,
|
|
1268
1332
|
root,
|
|
1269
1333
|
output: pluginTs.options?.output ?? output,
|
|
1270
|
-
group: pluginTs.options?.group
|
|
1334
|
+
group: pluginTs.options?.group
|
|
1271
1335
|
})
|
|
1272
1336
|
};
|
|
1273
1337
|
function resolveMockImports(schema) {
|