@kubb/plugin-faker 5.1.9 → 5.1.11

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,5 +1,5 @@
1
1
  import { posix } from "node:path";
2
- import { Diagnostics, Resolver, addGenerator, assertPluginOption, ast, containsCircularRef, createResolver, defineExtension, defineGenerator, setMacros, setResolver } from "kubb/kit";
2
+ import { Diagnostics, Resolver, addGenerator, ast, containsCircularRef, createResolver, defineExtension, defineGenerator, setMacros, setResolver } from "kubb/kit";
3
3
  import { File, Function, jsxRenderer } from "kubb/jsx";
4
4
  import { Fragment, jsx, jsxs } from "kubb/jsx/jsx-runtime";
5
5
  import { buildParams, enumTypeName, pluginTsName } from "@kubb/plugin-ts";
@@ -12,12 +12,23 @@ import { buildParams, enumTypeName, pluginTsName } from "@kubb/plugin-ts";
12
12
  *
13
13
  * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
14
14
  */
15
- function toCamelOrPascal(text, pascal) {
15
+ function convert(text, pascal) {
16
16
  return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
17
17
  if (word.length > 1 && word === word.toUpperCase()) return word;
18
18
  return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
19
19
  }).join("").replace(/[^a-zA-Z0-9]/g, "");
20
20
  }
21
+ const cache = /* @__PURE__ */ new Map();
22
+ const cacheLimit = 1e4;
23
+ function toCamelOrPascal(text, pascal) {
24
+ const key = `${pascal ? "P" : "c"}${text}`;
25
+ const cached = cache.get(key);
26
+ if (cached !== void 0) return cached;
27
+ const result = convert(text, pascal);
28
+ if (cache.size >= cacheLimit) cache.clear();
29
+ cache.set(key, result);
30
+ return result;
31
+ }
21
32
  /**
22
33
  * Converts `text` to camelCase.
23
34
  *
@@ -220,29 +231,16 @@ function stringify(value) {
220
231
  return `'${JSON.stringify(trimQuotes(value.toString())).slice(1, -1).replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`;
221
232
  }
222
233
  /**
223
- * Escapes characters that are not allowed inside JS string literals, covering quotes, backslashes,
224
- * and the Unicode line terminators U+2028 and U+2029.
225
- *
226
- * @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4
234
+ * Escapes an `@` at the start of a line, so a multi-line description can't start a new JSDoc tag.
235
+ * Editors render `\@` as `@` in hovers.
227
236
  *
228
237
  * @example
229
238
  * ```ts
230
- * jsStringEscape('say "hi"\nbye') // 'say \\"hi\\"\\nbye'
239
+ * jsDocEscape('intro\n@example value') // 'intro\n\\@example value'
231
240
  * ```
232
241
  */
233
- function jsStringEscape(input) {
234
- return `${input}`.replace(/["'\\\n\r\u2028\u2029]/g, (character) => {
235
- switch (character) {
236
- case "\"":
237
- case "'":
238
- case "\\": return `\\${character}`;
239
- case "\n": return "\\n";
240
- case "\r": return "\\r";
241
- case "\u2028": return "\\u2028";
242
- case "\u2029": return "\\u2029";
243
- default: return "";
244
- }
245
- });
242
+ function jsDocEscape(input) {
243
+ return `${input}`.replace(/^(\s*)@/gm, "$1\\@");
246
244
  }
247
245
  /**
248
246
  * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.
@@ -398,6 +396,12 @@ const NON_INLINABLE_RESPONSE_TYPES = /* @__PURE__ */ new Set([
398
396
  function canOverrideSchema(node) {
399
397
  return !NON_OVERRIDABLE_TYPES.has(node.type);
400
398
  }
399
+ /**
400
+ * Follows a ref, including alias chains, to the schema it resolves to. Unresolved refs are returned as is.
401
+ */
402
+ function resolveRefTarget(node) {
403
+ return node.type === "ref" && node.schema ? resolveRefTarget(node.schema) : node;
404
+ }
401
405
  function shouldInlineSingleResponseSchema(schema) {
402
406
  return !NON_INLINABLE_RESPONSE_TYPES.has(schema.type);
403
407
  }
@@ -488,7 +492,7 @@ function resolveFakerTypeUsage(node, typeName, canOverride) {
488
492
  return {
489
493
  dataType,
490
494
  returnType,
491
- usesTypeName: dataType.includes(typeName) || Boolean(returnType?.includes(typeName))
495
+ usesTypeName: canOverride && dataType.includes(typeName) || Boolean(returnType?.includes(typeName))
492
496
  };
493
497
  }
494
498
  //#endregion
@@ -520,7 +524,7 @@ function Faker({ node, description, name, typeName, printer, canOverride, typeMo
520
524
  children: /* @__PURE__ */ jsx(Function, {
521
525
  export: true,
522
526
  name,
523
- JSDoc: { comments: description ? [`@description ${jsStringEscape(description)}`] : [] },
527
+ JSDoc: { comments: description ? [`@description ${jsDocEscape(description)}`] : [] },
524
528
  params: canOverride ? paramsSignature : void 0,
525
529
  returnType: returnType ?? void 0,
526
530
  children: `return ${returnExpression}`
@@ -550,7 +554,7 @@ return {
550
554
  children: /* @__PURE__ */ jsx(Function, {
551
555
  export: true,
552
556
  name,
553
- JSDoc: { comments: description ? [`@description ${jsStringEscape(description)}`] : [] },
557
+ JSDoc: { comments: description ? [`@description ${jsDocEscape(description)}`] : [] },
554
558
  generics: typeMode === "schema" ? void 0 : `TData extends Partial<${typeName}> = object`,
555
559
  params: typeMode === "schema" ? `data?: Partial<${typeName}>` : "data?: TData",
556
560
  returnType: typeMode === "schema" ? typeName : void 0,
@@ -892,18 +896,22 @@ function parseEnumValue(value) {
892
896
  return value;
893
897
  }
894
898
  /**
895
- * Reads the discriminator literal off a variant, or `undefined` when it can't be determined.
899
+ * Reads the discriminator literal off a variant, with whether its property is required, or
900
+ * `undefined` when it can't be determined.
896
901
  *
897
902
  * A variant carries exactly one discriminator value, so a property resolving to several literals
898
903
  * (a `ref` to the enum shared by every branch, say) identifies no branch and narrows nothing.
899
904
  */
900
- function getDiscriminatorValue(member, discriminatorPropertyName) {
905
+ function getDiscriminator(member, discriminatorPropertyName) {
901
906
  for (const property of ast.resolveSchemaProperties({
902
907
  node: member,
903
908
  propertyName: discriminatorPropertyName
904
909
  })) {
905
910
  const values = ast.getSchemaLiteralValues(property.schema);
906
- if (values.length === 1) return values[0];
911
+ if (values.length === 1) return {
912
+ value: values[0],
913
+ required: property.required
914
+ };
907
915
  }
908
916
  }
909
917
  /**
@@ -975,7 +983,7 @@ const printerFaker = ast.createPrinter((options) => {
975
983
  });
976
984
  if (this.options.schemaName && refName === this.options.schemaName) return this.options.typeName ? `undefined as unknown as ${this.options.typeName}` : "undefined as unknown";
977
985
  const resolvedName = node.ref ? this.options.resolver.name(refName) : refName;
978
- if (!this.options.nestedInObject) return `${resolvedName}(data)`;
986
+ if (!this.options.nestedInObject && canOverrideSchema(resolveRefTarget(node))) return `${resolvedName}(data)`;
979
987
  return `${resolvedName}()`;
980
988
  },
981
989
  enum(node) {
@@ -986,9 +994,10 @@ const printerFaker = ast.createPrinter((options) => {
986
994
  const { discriminatorPropertyName } = node;
987
995
  const baseTypeName = this.options.typeName;
988
996
  return `faker.helpers.arrayElement([${mapSchemaMembers(node, (member) => {
989
- const value = discriminatorPropertyName ? getDiscriminatorValue(member, discriminatorPropertyName) : void 0;
990
- if (baseTypeName && value !== void 0) {
991
- const typeName = `Extract<NonNullable<${baseTypeName}>, { ${JSON.stringify(discriminatorPropertyName)}: ${parseEnumValue(value)} }>`;
997
+ const discriminator = discriminatorPropertyName ? getDiscriminator(member, discriminatorPropertyName) : void 0;
998
+ if (baseTypeName && discriminator) {
999
+ const key = `${JSON.stringify(discriminatorPropertyName)}${discriminator.required ? "" : "?"}`;
1000
+ const typeName = `Extract<NonNullable<${baseTypeName}>, { ${key}: ${parseEnumValue(discriminator.value)} }>`;
992
1001
  return printNested(member, {
993
1002
  typeName,
994
1003
  nestedInObject: true,
@@ -1398,7 +1407,7 @@ var compatibility = {
1398
1407
  };
1399
1408
  //#endregion
1400
1409
  //#region package.json
1401
- var version = "5.1.9";
1410
+ var version = "5.1.11";
1402
1411
  //#endregion
1403
1412
  //#region src/resolvers/resolverFaker.ts
1404
1413
  /**
@@ -1466,18 +1475,6 @@ const pluginFaker = defineExtension({
1466
1475
  path: "mocks",
1467
1476
  barrel: { type: "named" }
1468
1477
  }, 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
- });
1481
1478
  setResolver(userResolver ? Resolver.merge(resolverFaker, userResolver) : resolverFaker);
1482
1479
  if (userMacros?.length) setMacros(userMacros);
1483
1480
  addGenerator(fakerGenerator);