@schmock/faker 1.9.5 → 1.10.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/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -0
- package/dist/field-mappings.d.ts +11 -0
- package/dist/field-mappings.d.ts.map +1 -0
- package/dist/field-mappings.js +1107 -0
- package/dist/field-name-matcher.d.ts +31 -0
- package/dist/field-name-matcher.d.ts.map +1 -0
- package/dist/field-name-matcher.js +136 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/jsf-config.d.ts.map +1 -1
- package/dist/jsf-config.js +2 -2
- package/dist/schema-enhancement.d.ts.map +1 -1
- package/dist/schema-enhancement.js +42 -53
- package/package.json +2 -2
- package/src/constants.ts +3 -0
- package/src/field-mappings.test.ts +340 -0
- package/src/field-mappings.ts +1141 -0
- package/src/field-name-matcher.test.ts +252 -0
- package/src/field-name-matcher.ts +172 -0
- package/src/index.ts +58 -5
- package/src/jsf-config.ts +2 -2
- package/src/schema-enhancement.ts +58 -55
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { JSONSchema7 } from "json-schema";
|
|
2
|
+
import type { FieldMapping } from "./field-mappings.js";
|
|
3
|
+
/**
|
|
4
|
+
* Split a field name (camelCase, snake_case, kebab-case) into lowercase tokens.
|
|
5
|
+
* "userFirstName" → ["user", "first", "name"]
|
|
6
|
+
* "created_at" → ["created", "at"]
|
|
7
|
+
* "HTMLParser" → ["html", "parser"]
|
|
8
|
+
* "is_active" → ["is", "active"]
|
|
9
|
+
*/
|
|
10
|
+
export declare function tokenizeFieldName(name: string): string[];
|
|
11
|
+
/**
|
|
12
|
+
* Score how well a set of keyword tokens matches field name tokens.
|
|
13
|
+
* Returns 0-1:
|
|
14
|
+
* 1.0 — exact full match (joined tokens equal joined keywords)
|
|
15
|
+
* 0.9 — all keyword tokens found in field tokens with high coverage (>50%)
|
|
16
|
+
* 0.8 — field ends with keyword tokens
|
|
17
|
+
* 0.7 — substring match (keyword appears in joined field name)
|
|
18
|
+
* 0.65 — all keyword tokens found but low coverage (<=50%)
|
|
19
|
+
*/
|
|
20
|
+
export declare function scoreMatch(fieldTokens: string[], keywords: string[]): number;
|
|
21
|
+
interface MatchResult {
|
|
22
|
+
mapping: FieldMapping;
|
|
23
|
+
score: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Find the best field mapping for a given field name and schema.
|
|
27
|
+
* Returns the highest-scoring match above its threshold, or undefined.
|
|
28
|
+
*/
|
|
29
|
+
export declare function findBestMapping(fieldName: string, schema: JSONSchema7, mappings?: FieldMapping[]): MatchResult | undefined;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=field-name-matcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-name-matcher.d.ts","sourceRoot":"","sources":["../src/field-name-matcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAmBxD;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAsC5E;AAED,UAAU,WAAW;IACnB,OAAO,EAAE,YAAY,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,EACnB,QAAQ,GAAE,YAAY,EAAuB,GAC5C,WAAW,GAAG,SAAS,CA6EzB"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { ALL_FIELD_MAPPINGS } from "./field-mappings.js";
|
|
2
|
+
/**
|
|
3
|
+
* Split a field name (camelCase, snake_case, kebab-case) into lowercase tokens.
|
|
4
|
+
* "userFirstName" → ["user", "first", "name"]
|
|
5
|
+
* "created_at" → ["created", "at"]
|
|
6
|
+
* "HTMLParser" → ["html", "parser"]
|
|
7
|
+
* "is_active" → ["is", "active"]
|
|
8
|
+
*/
|
|
9
|
+
export function tokenizeFieldName(name) {
|
|
10
|
+
// Split on _ and -
|
|
11
|
+
const parts = name.split(/[_-]/);
|
|
12
|
+
const tokens = [];
|
|
13
|
+
for (const part of parts) {
|
|
14
|
+
if (!part)
|
|
15
|
+
continue;
|
|
16
|
+
// Split camelCase and consecutive uppercase (e.g., HTMLParser → HTML, Parser)
|
|
17
|
+
const camelTokens = part
|
|
18
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
|
|
19
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
|
|
20
|
+
.split("_");
|
|
21
|
+
for (const t of camelTokens) {
|
|
22
|
+
if (t)
|
|
23
|
+
tokens.push(t.toLowerCase());
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return tokens;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Score how well a set of keyword tokens matches field name tokens.
|
|
30
|
+
* Returns 0-1:
|
|
31
|
+
* 1.0 — exact full match (joined tokens equal joined keywords)
|
|
32
|
+
* 0.9 — all keyword tokens found in field tokens with high coverage (>50%)
|
|
33
|
+
* 0.8 — field ends with keyword tokens
|
|
34
|
+
* 0.7 — substring match (keyword appears in joined field name)
|
|
35
|
+
* 0.65 — all keyword tokens found but low coverage (<=50%)
|
|
36
|
+
*/
|
|
37
|
+
export function scoreMatch(fieldTokens, keywords) {
|
|
38
|
+
const fieldJoined = fieldTokens.join("");
|
|
39
|
+
let bestScore = 0;
|
|
40
|
+
// Try each keyword variant, keep the highest score
|
|
41
|
+
for (const keyword of keywords) {
|
|
42
|
+
const kwTokens = tokenizeFieldName(keyword);
|
|
43
|
+
const kwJoined = kwTokens.join("");
|
|
44
|
+
// Exact match: joined tokens are identical
|
|
45
|
+
if (fieldJoined === kwJoined)
|
|
46
|
+
return 1.0;
|
|
47
|
+
// All keyword tokens present in field tokens with high coverage
|
|
48
|
+
if (kwTokens.length > 0 &&
|
|
49
|
+
kwTokens.every((kt) => fieldTokens.includes(kt))) {
|
|
50
|
+
const coverage = kwTokens.length / fieldTokens.length;
|
|
51
|
+
const score = coverage > 0.5 ? 0.9 : 0.65;
|
|
52
|
+
bestScore = Math.max(bestScore, score);
|
|
53
|
+
}
|
|
54
|
+
// Field ends with keyword tokens
|
|
55
|
+
if (kwTokens.length > 0 && kwTokens.length <= fieldTokens.length) {
|
|
56
|
+
const tail = fieldTokens.slice(-kwTokens.length);
|
|
57
|
+
if (tail.every((t, i) => t === kwTokens[i])) {
|
|
58
|
+
bestScore = Math.max(bestScore, 0.8);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Substring match: keyword joined appears in field joined
|
|
62
|
+
if (kwJoined.length >= 3 && fieldJoined.includes(kwJoined)) {
|
|
63
|
+
bestScore = Math.max(bestScore, 0.7);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return bestScore;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Find the best field mapping for a given field name and schema.
|
|
70
|
+
* Returns the highest-scoring match above its threshold, or undefined.
|
|
71
|
+
*/
|
|
72
|
+
export function findBestMapping(fieldName, schema, mappings = ALL_FIELD_MAPPINGS) {
|
|
73
|
+
const schemaAny = schema;
|
|
74
|
+
const schemaType = typeof schema.type === "string" ? schema.type : undefined;
|
|
75
|
+
// Priority: format:uuid always maps to string.uuid
|
|
76
|
+
if (schemaType === "string" && schema.format === "uuid") {
|
|
77
|
+
return {
|
|
78
|
+
mapping: {
|
|
79
|
+
keywords: ["uuid"],
|
|
80
|
+
fakerMethod: "string.uuid",
|
|
81
|
+
schemaType: "string",
|
|
82
|
+
minScore: 0.5,
|
|
83
|
+
},
|
|
84
|
+
score: 1.0,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
// Skip if schema already has pattern, enum, or faker constraint
|
|
88
|
+
if (schemaAny.pattern || schemaAny.enum || schemaAny.faker) {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
// Skip numeric faker mapping when schema already constrains the range
|
|
92
|
+
const hasNumericConstraints = schema.minimum !== undefined ||
|
|
93
|
+
schema.maximum !== undefined ||
|
|
94
|
+
schema.exclusiveMinimum !== undefined ||
|
|
95
|
+
schema.exclusiveMaximum !== undefined;
|
|
96
|
+
const tokens = tokenizeFieldName(fieldName);
|
|
97
|
+
let best;
|
|
98
|
+
for (const mapping of mappings) {
|
|
99
|
+
// Skip numeric faker mappings when schema has explicit constraints
|
|
100
|
+
if (hasNumericConstraints &&
|
|
101
|
+
(mapping.schemaType === "number" || mapping.schemaType === "integer")) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
// Check schema type constraint
|
|
105
|
+
if (mapping.schemaType && schemaType && mapping.schemaType !== schemaType) {
|
|
106
|
+
const isNumeric = (mapping.schemaType === "number" && schemaType === "integer") ||
|
|
107
|
+
(mapping.schemaType === "integer" && schemaType === "number");
|
|
108
|
+
if (!isNumeric)
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const score = scoreMatch(tokens, mapping.keywords);
|
|
112
|
+
if (score >= mapping.minScore && (!best || score > best.score)) {
|
|
113
|
+
best = { mapping, score };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// ID suffix detection: fields ending in Id/_id with string type → UUID
|
|
117
|
+
// Only if no better match was found or the existing match is weak
|
|
118
|
+
if (schemaType === "string") {
|
|
119
|
+
const lastToken = tokens[tokens.length - 1];
|
|
120
|
+
if (lastToken === "id" && tokens.length > 1) {
|
|
121
|
+
const idScore = 0.8;
|
|
122
|
+
if (!best || best.score < idScore) {
|
|
123
|
+
best = {
|
|
124
|
+
mapping: {
|
|
125
|
+
keywords: ["id"],
|
|
126
|
+
fakerMethod: "string.uuid",
|
|
127
|
+
schemaType: "string",
|
|
128
|
+
minScore: 0.5,
|
|
129
|
+
},
|
|
130
|
+
score: idScore,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return best;
|
|
136
|
+
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/C,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CA+CvE;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,uBAAuB,GAAG,GAAG,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/C,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CA+CvE;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,uBAAuB,GAAG,GAAG,CA8CxE"}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ResourceLimitError as N,SchemaGenerationError as m,SchemaValidationError as S}from"@schmock/core";var G=1e4,P=10,V=3,M=3,j=100;import{en as l,Faker as p}from"@faker-js/faker";import C from"json-schema-faker";function L(B){let W=new p({locale:[l]});if(B!==void 0)W.seed(B);return W}var R=!1,A;function d(B){let W=B|0;return()=>{W=W+1831565813|0;let $=W;return $=Math.imul($^$>>>15,$|1),$^=$+Math.imul($^$>>>7,$|61),(($^$>>>14)>>>0)/4294967296}}function F(B){if(!R||B!==A)A=B,C.extend("faker",()=>L(B)),C.option({requiredOnly:!1,alwaysFakeOptionals:!0,useDefaultValue:!0,ignoreMissingRefs:!0,failOnInvalidTypes:!1,failOnInvalidFormat:!1}),R=!0;if(B!==void 0)C.option({random:d(B)}),C.extend("faker",()=>L(B));else C.option({random:Math.random});return C}var k=new Set(["__proto__","constructor","prototype"]);function f(B,W,$=Math.random){if(W!==void 0){if(W<0)return 0;return W}if(B.minItems!==void 0&&B.maxItems!==void 0)return Math.floor($()*(B.maxItems-B.minItems+1))+B.minItems;if(B.minItems!==void 0)return Math.max(B.minItems,V);if(B.maxItems!==void 0)return Math.min(B.maxItems,V);return V}function I(B,W,$,Q,K){if(!W)return B;let b=structuredClone(B);for(let[z,Z]of Object.entries(W)){if(k.has(z))continue;if(z.includes("."))o(b,z,Z,{params:$,state:Q,query:K});else if(typeof Z==="object"&&Z!==null&&!Array.isArray(Z))if(b[z]&&typeof b[z]==="object")b[z]=I(b[z],Z,$,Q,K);else b[z]=I({},Z,$,Q,K);else if(typeof Z==="string"&&Z.includes("{{"))b[z]=E(Z,{params:$,state:Q,query:K});else b[z]=Z}return b}function o(B,W,$,Q){let K=W.split("."),b=B;for(let Z=0;Z<K.length-1;Z++){let X=K[Z];if(k.has(X))return;if(!(X in b)||typeof b[X]!=="object"||b[X]===null)b[X]={};b=b[X]}let z=K[K.length-1];if(k.has(z))return;if(typeof $==="string"&&$.includes("{{"))b[z]=E($,Q);else b[z]=$}function E(B,W){let $=B.match(/^\{\{\s*([^}]+)\s*\}\}$/);if($){let b=$[1].trim().split("."),z=W;for(let Z of b)if(z&&typeof z==="object")z=z[Z];else return B;return z!==void 0?z:B}return B.replace(/\{\{\s*([^}]+)\s*\}\}/g,(K,b)=>{let z=b.trim().split("."),Z=W;for(let X of z)if(Z&&typeof Z==="object")Z=Z[X];else return K;return Z!==void 0?String(Z):K})}import{ResourceLimitError as O,SchemaValidationError as q}from"@schmock/core";var x;function U(B){return typeof B==="object"&&B!==null&&!Array.isArray(B)}function H(B,W="$"){if(!B||typeof B!=="object")throw new q(W,"Schema must be a valid JSON Schema object");if(Object.keys(B).length===0)throw new q(W,"Schema cannot be empty");let $=["object","array","string","number","integer","boolean","null"];if(B.type&&typeof B.type==="string"&&!$.includes(B.type))throw new q(W,`Invalid schema type: "${B.type}"`,"Supported types are: object, array, string, number, integer, boolean, null");if(B.type==="object"&&B.properties){if(typeof B.properties!=="object"||Array.isArray(B.properties))throw new q(`${W}.properties`,"Properties must be an object mapping property names to schemas",'Use { "propertyName": { "type": "string" } } format');for(let[K,b]of Object.entries(B.properties))if(typeof b==="object"&&b!==null){let z="faker"in b?String(b.faker):void 0;if(z)try{D(z)}catch(Z){if(Z instanceof q){let X=Z.context,J="Invalid faker method",Y;if(X&&typeof X==="object"){if("issue"in X&&typeof X.issue==="string")J=X.issue;if("suggestion"in X&&typeof X.suggestion==="string")Y=X.suggestion}throw new q(`${W}.properties.${K}.faker`,J,Y)}if(Z instanceof Error)throw Z;throw Error(String(Z))}H(b,`${W}.properties.${K}`)}}if(B.type==="array"){if(B.items===null||B.items===void 0)throw new q(`${W}.items`,"Array schema must have valid items definition","Define items as a schema object or array of schemas");if(Array.isArray(B.items)){if(B.items.length===0)throw new q(`${W}.items`,"Array items cannot be empty array","Provide at least one item schema");B.items.forEach((K,b)=>{if(typeof K==="object"&&K!==null)H(K,`${W}.items[${b}]`)})}else if(typeof B.items==="object"&&B.items!==null)H(B.items,`${W}.items`)}if(_(B))throw new q(W,"Schema contains circular references which are not supported");let Q=g(B);if(Q>P)throw new O("schema_nesting_depth",P,Q);if(Q>=M)i(B,W);if(w(B,W),B.$ref==="#")throw new q(W,"Self-referencing schemas are not supported")}function _(B,W=new Set){if(W.has(B))return!0;if(B.$ref==="#")return!0;if(W.add(B),B.type==="object"&&B.properties){for(let $ of Object.values(B.properties))if(U($)){if(_($,W))return!0}}if(B.type==="array"&&B.items){let $=Array.isArray(B.items)?B.items:[B.items];for(let Q of $)if(U(Q)){if(_(Q,W))return!0}}return W.delete(B),!1}function g(B,W=0){if(W>P)return W;let $=W;if(B.type==="object"&&B.properties){for(let Q of Object.values(B.properties))if(U(Q))$=Math.max($,g(Q,W+1))}if(B.type==="array"&&B.items){let Q=Array.isArray(B.items)?B.items:[B.items];for(let K of Q)if(U(K))$=Math.max($,g(K,W+1))}return $}function i(B,W){function $(Q,K){let b=Q.type;if(Array.isArray(b)?b.includes("array"):b==="array"){let Z=Q.maxItems||V;if(K>=M&&Z>=j)throw new O("deep_nesting_memory_risk",M*j,K*Z);if(Q.items){let X=Array.isArray(Q.items)?Q.items:[Q.items];for(let J of X)if(U(J))$(J,K+1)}return}if(b==="object"&&Q.properties){for(let Z of Object.values(Q.properties))if(U(Z))$(Z,K+1)}}$(B,0)}function w(B,W){if(B.type==="array"){if(B.maxItems&&B.maxItems>G)throw new O("array_max_items",G,B.maxItems);let $=g(B),Q=B.maxItems||B.minItems||V;if($>M&&Q>j)throw new O("memory_estimation",M*j,$*Q)}if(B.type==="object"&&B.properties){for(let[$,Q]of Object.entries(B.properties))if(U(Q))w(Q,`${W}.properties.${$}`)}if(B.type==="array"&&B.items){if(Array.isArray(B.items))B.items.forEach(($,Q)=>{if(U($))w($,`${W}.items[${Q}]`)});else if(U(B.items))w(B.items,`${W}.items`)}}function D(B){let W=B.split(".");if(W.length<2)throw new q("$.faker",`Invalid faker method format: "${B}"`,"Use format like 'person.firstName' or 'internet.email'");if(!x)x=L();let Q=x;for(let K of W)if(Q&&typeof Q==="object"&&K in Q)Q=Q[K];else throw new q("$.faker",`Invalid faker method: "${B}"`,"Check faker.js documentation for valid methods");if(typeof Q!=="function")throw new q("$.faker",`Invalid faker method: "${B}" is not a function`,"Check faker.js documentation for valid methods")}function y(B){if(!B||typeof B!=="object")return B;let W={...B};if(W.type==="object"&&W.properties){W.properties={...W.properties};for(let[$,Q]of Object.entries(W.properties))if(U(Q))W.properties[$]=n($,Q)}return W}function n(B,W){let $={...W};if($.faker)return D($.faker),$;let Q=B.toLowerCase();if(Q.includes("email"))$.format="email",$.faker="internet.email";else if(Q==="firstname"||Q==="first_name")$.faker="person.firstName";else if(Q==="lastname"||Q==="last_name")$.faker="person.lastName";else if(Q==="name"||Q==="fullname")$.faker="person.fullName";else if(Q.includes("phone")||Q==="mobile")$.faker="phone.number";else if(Q==="street"||Q==="address")$.faker="location.streetAddress";else if(Q==="city")$.faker="location.city";else if(Q==="zipcode"||Q==="zip")$.faker="location.zipCode";else if(Q==="uuid"||Q==="id"&&$.format==="uuid")$.faker="string.uuid";else if(Q.includes("createdat")||Q.includes("created_at")||Q.includes("updatedat")||Q.includes("updated_at"))$.format="date-time",$.faker="date.recent";else if(Q.includes("company"))$.faker="company.name";else if(Q==="position"||Q==="jobtitle")$.faker="person.jobTitle";else if(Q==="price"||Q==="amount")$.faker="commerce.price";return $}function VB(B){return H(B.schema),{name:"faker",version:"1.0.1",process(W,$){if($!==void 0&&$!==null)return{context:W,response:$};try{let Q=h({schema:B.schema,count:B.count,overrides:B.overrides,params:W.params,state:W.routeState,query:W.query,seed:B.seed});return{context:W,response:Q}}catch(Q){if(Q instanceof S||Q instanceof N)throw Q;throw new m(W.path,Q instanceof Error?Q:Error(String(Q)),B.schema)}}}}function h(B){let{schema:W,count:$,overrides:Q,params:K,state:b,query:z,seed:Z}=B;H(W);let X;if(W.type==="array"&&W.items){let J=f(W,$);if(J>G)throw new N("array_size",G,J);let Y=Array.isArray(W.items)?W.items[0]:W.items;if(!Y||typeof Y==="boolean")throw new S("$.items","Array schema must have valid items definition");let u=Y;X=[];for(let v=0;v<J;v++){let T=F(Z).generate(y(u));T=I(T,Q,K,b,z),X.push(T)}}else{let J=y(W);X=F(Z).generate(J),X=I(X,Q,K,b,z)}return X}export{h as generateFromSchema,VB as fakerPlugin};
|
|
1
|
+
import{ResourceLimitError as o,SchemaGenerationError as LQ,SchemaValidationError as i}from"@schmock/core";var J=1e4,b=10,G=3,w=3,M=100,E=0.05;import{base as n,en as m,Faker as r}from"@faker-js/faker";import C from"json-schema-faker";function L(Q){let $=new r({locale:[m,n]});if(Q!==void 0)$.seed(Q);return $}var f=!1,k;function h(Q){let $=Q|0;return()=>{$=$+1831565813|0;let B=$;return B=Math.imul(B^B>>>15,B|1),B^=B+Math.imul(B^B>>>7,B|61),((B^B>>>14)>>>0)/4294967296}}function v(Q){if(!f||Q!==k)k=Q,C.extend("faker",()=>L(Q)),C.option({requiredOnly:!1,alwaysFakeOptionals:!0,useDefaultValue:!0,ignoreMissingRefs:!0,failOnInvalidTypes:!1,failOnInvalidFormat:!1}),f=!0;if(Q!==void 0)C.option({random:h(Q)}),C.extend("faker",()=>L(Q));else C.option({random:Math.random});return C}var g=new Set(["__proto__","constructor","prototype"]);function u(Q,$,B=Math.random){if($!==void 0){if($<0)return 0;return $}if(Q.minItems!==void 0&&Q.maxItems!==void 0)return Math.floor(B()*(Q.maxItems-Q.minItems+1))+Q.minItems;if(Q.minItems!==void 0)return Math.max(Q.minItems,G);if(Q.maxItems!==void 0)return Math.min(Q.maxItems,G);return G}function P(Q,$,B,Z,K){if(!$)return Q;let X=structuredClone(Q);for(let[q,z]of Object.entries($)){if(g.has(q))continue;if(q.includes("."))c(X,q,z,{params:B,state:Z,query:K});else if(typeof z==="object"&&z!==null&&!Array.isArray(z))if(X[q]&&typeof X[q]==="object")X[q]=P(X[q],z,B,Z,K);else X[q]=P({},z,B,Z,K);else if(typeof z==="string"&&z.includes("{{"))X[q]=S(z,{params:B,state:Z,query:K});else X[q]=z}return X}function c(Q,$,B,Z){let K=$.split("."),X=Q;for(let z=0;z<K.length-1;z++){let W=K[z];if(g.has(W))return;if(!(W in X)||typeof X[W]!=="object"||X[W]===null)X[W]={};X=X[W]}let q=K[K.length-1];if(g.has(q))return;if(typeof B==="string"&&B.includes("{{"))X[q]=S(B,Z);else X[q]=B}function S(Q,$){let B=Q.match(/^\{\{\s*([^}]+)\s*\}\}$/);if(B){let X=B[1].trim().split("."),q=$;for(let z of X)if(q&&typeof q==="object")q=q[z];else return Q;return q!==void 0?q:Q}return Q.replace(/\{\{\s*([^}]+)\s*\}\}/g,(K,X)=>{let q=X.trim().split("."),z=$;for(let W of q)if(z&&typeof z==="object")z=z[W];else return K;return z!==void 0?String(z):K})}var s=[{keywords:["email"],fakerMethod:"internet.email",schemaType:"string",minScore:0.6,format:"email"},{keywords:["username","user_name","login","handle"],fakerMethod:"internet.username",schemaType:"string",minScore:0.6},{keywords:["password","passwd","secret"],fakerMethod:"internet.password",schemaType:"string",minScore:0.6},{keywords:["token","api_key","apikey","access_token","refresh_token"],fakerMethod:"string.alphanumeric",schemaType:"string",minScore:0.8}],t=[{keywords:["first_name","firstname","given_name","forename"],fakerMethod:"person.firstName",schemaType:"string",minScore:0.6},{keywords:["last_name","lastname","surname","family_name"],fakerMethod:"person.lastName",schemaType:"string",minScore:0.6},{keywords:["full_name","fullname","display_name","displayname","full_name"],fakerMethod:"person.fullName",schemaType:"string",minScore:0.6},{keywords:["name"],fakerMethod:"person.fullName",schemaType:"string",minScore:0.6},{keywords:["middle_name","middlename"],fakerMethod:"person.middleName",schemaType:"string",minScore:0.8},{keywords:["prefix","honorific","salutation"],fakerMethod:"person.prefix",schemaType:"string",minScore:0.8},{keywords:["suffix"],fakerMethod:"person.suffix",schemaType:"string",minScore:0.9},{keywords:["gender","sex"],fakerMethod:"person.sex",schemaType:"string",minScore:0.8},{keywords:["bio","biography"],fakerMethod:"lorem.paragraph",schemaType:"string",minScore:0.8},{keywords:["job_title","jobtitle","position","occupation","job","role"],fakerMethod:"person.jobTitle",schemaType:"string",minScore:0.6},{keywords:["job_area","department","division","team"],fakerMethod:"person.jobArea",schemaType:"string",minScore:0.8},{keywords:["zodiac","zodiac_sign"],fakerMethod:"person.zodiacSign",schemaType:"string",minScore:0.9}],a=[{keywords:["phone","mobile","cell","tel","telephone","cellphone","fax"],fakerMethod:"phone.number",schemaType:"string",minScore:0.6},{keywords:["imei"],fakerMethod:"phone.imei",schemaType:"string",minScore:0.9}],e=[{keywords:["street","street_address"],fakerMethod:"location.streetAddress",schemaType:"string",minScore:0.6},{keywords:["address","mailing_address","postal_address"],fakerMethod:"location.streetAddress",schemaType:"string",minScore:0.6},{keywords:["city","town"],fakerMethod:"location.city",schemaType:"string",minScore:0.6},{keywords:["state","province","region"],fakerMethod:"location.state",schemaType:"string",minScore:0.8},{keywords:["country"],fakerMethod:"location.country",schemaType:"string",minScore:0.8},{keywords:["country_code","countrycode"],fakerMethod:"location.countryCode",schemaType:"string",minScore:0.8},{keywords:["county"],fakerMethod:"location.county",schemaType:"string",minScore:0.9},{keywords:["continent"],fakerMethod:"location.continent",schemaType:"string",minScore:0.9},{keywords:["zip","zipcode","zip_code","postal","postal_code"],fakerMethod:"location.zipCode",schemaType:"string",minScore:0.6},{keywords:["latitude","lat"],fakerMethod:"location.latitude",schemaType:"number",minScore:0.6},{keywords:["longitude","lng","lon","long"],fakerMethod:"location.longitude",schemaType:"number",minScore:0.6},{keywords:["timezone","time_zone","tz"],fakerMethod:"location.timeZone",schemaType:"string",minScore:0.8},{keywords:["building_number"],fakerMethod:"location.buildingNumber",schemaType:"string",minScore:0.9}],QQ=[{keywords:["url","website","link","href","homepage","webpage"],fakerMethod:"internet.url",schemaType:"string",minScore:0.6},{keywords:["avatar","photo_url","profile_image","image_url","picture","thumbnail","icon"],fakerMethod:"image.avatar",schemaType:"string",minScore:0.6},{keywords:["domain","hostname","domain_name"],fakerMethod:"internet.domainName",schemaType:"string",minScore:0.8},{keywords:["ip","ip_address","ipaddress","ipv4"],fakerMethod:"internet.ipv4",schemaType:"string",minScore:0.8},{keywords:["ipv6"],fakerMethod:"internet.ipv6",schemaType:"string",minScore:0.9},{keywords:["mac","mac_address"],fakerMethod:"internet.mac",schemaType:"string",minScore:0.9},{keywords:["user_agent","useragent"],fakerMethod:"internet.userAgent",schemaType:"string",minScore:0.9},{keywords:["port"],fakerMethod:"internet.port",schemaType:"number",minScore:0.9},{keywords:["protocol"],fakerMethod:"internet.protocol",schemaType:"string",minScore:0.9}],$Q=[{keywords:["uuid","guid"],fakerMethod:"string.uuid",schemaType:"string",minScore:0.6},{keywords:["sku"],fakerMethod:"string.alphanumeric",schemaType:"string",minScore:0.9},{keywords:["slug"],fakerMethod:"lorem.slug",schemaType:"string",minScore:0.8},{keywords:["isbn"],fakerMethod:"commerce.isbn",schemaType:"string",minScore:0.9},{keywords:["vin"],fakerMethod:"vehicle.vin",schemaType:"string",minScore:0.9},{keywords:["iban"],fakerMethod:"finance.iban",schemaType:"string",minScore:0.9},{keywords:["bic","swift"],fakerMethod:"finance.bic",schemaType:"string",minScore:0.9},{keywords:["ssn","social_security"],fakerMethod:"string.numeric",schemaType:"string",minScore:0.9}],BQ=[{keywords:["description","desc","summary","overview","about","excerpt"],fakerMethod:"lorem.paragraph",schemaType:"string",minScore:0.6},{keywords:["content","body","text","message"],fakerMethod:"lorem.paragraphs",schemaType:"string",minScore:0.6},{keywords:["title","heading","subject","headline"],fakerMethod:"lorem.sentence",schemaType:"string",minScore:0.6},{keywords:["tag","label","category","keyword"],fakerMethod:"lorem.word",schemaType:"string",minScore:0.8},{keywords:["comment","note","remark","feedback","review"],fakerMethod:"lorem.sentence",schemaType:"string",minScore:0.8},{keywords:["sentence"],fakerMethod:"lorem.sentence",schemaType:"string",minScore:0.9},{keywords:["paragraph"],fakerMethod:"lorem.paragraph",schemaType:"string",minScore:0.9},{keywords:["word"],fakerMethod:"lorem.word",schemaType:"string",minScore:0.9}],ZQ=[{keywords:["company","organization","org","employer","brand"],fakerMethod:"company.name",schemaType:"string",minScore:0.6},{keywords:["product","product_name","item_name"],fakerMethod:"commerce.productName",schemaType:"string",minScore:0.8},{keywords:["price","amount","cost","fee","salary","wage","total","subtotal","balance","revenue","income"],fakerMethod:"commerce.price",minScore:0.6},{keywords:["currency","currency_code"],fakerMethod:"finance.currencyCode",schemaType:"string",minScore:0.8},{keywords:["currency_name"],fakerMethod:"finance.currencyName",schemaType:"string",minScore:0.8},{keywords:["currency_symbol"],fakerMethod:"finance.currencySymbol",schemaType:"string",minScore:0.8},{keywords:["account_number","account_no"],fakerMethod:"finance.accountNumber",schemaType:"string",minScore:0.8},{keywords:["credit_card","card_number"],fakerMethod:"finance.creditCardNumber",schemaType:"string",minScore:0.8},{keywords:["cvv"],fakerMethod:"finance.creditCardCVV",schemaType:"string",minScore:0.9},{keywords:["transaction_type"],fakerMethod:"finance.transactionType",schemaType:"string",minScore:0.9}],KQ=[{keywords:["created_at","createdat","creation_date","date_created","createddate"],fakerMethod:"date.recent",schemaType:"string",minScore:0.6,format:"date-time"},{keywords:["updated_at","updatedat","modified_at","modifiedat","date_updated","last_modified","date_modified"],fakerMethod:"date.recent",schemaType:"string",minScore:0.6,format:"date-time"},{keywords:["deleted_at","deletedat"],fakerMethod:"date.recent",schemaType:"string",minScore:0.6,format:"date-time"},{keywords:["published_at","publishedat","publish_date"],fakerMethod:"date.recent",schemaType:"string",minScore:0.6,format:"date-time"},{keywords:["expires_at","expiresat","expiration","expiry"],fakerMethod:"date.future",schemaType:"string",minScore:0.6,format:"date-time"},{keywords:["birthday","date_of_birth","dob","birthdate","born"],fakerMethod:"date.birthdate",schemaType:"string",minScore:0.8},{keywords:["start_date","begin_date"],fakerMethod:"date.past",schemaType:"string",minScore:0.8},{keywords:["end_date","due_date","deadline"],fakerMethod:"date.future",schemaType:"string",minScore:0.8},{keywords:["timestamp","ts"],fakerMethod:"date.recent",schemaType:"string",minScore:0.8}],XQ=[{keywords:["color","colour"],fakerMethod:"color.human",schemaType:"string",minScore:0.8},{keywords:["hex_color","hexcolor"],fakerMethod:"color.rgb",schemaType:"string",minScore:0.9}],zQ=[{keywords:["age"],fakerMethod:"number.int",schemaType:"number",minScore:0.8,fakerArgs:{min:18,max:80}},{keywords:["rating","score","stars"],fakerMethod:"number.int",schemaType:"number",minScore:0.8,fakerArgs:{min:1,max:5}},{keywords:["count","quantity","qty"],fakerMethod:"number.int",schemaType:"number",minScore:0.8,fakerArgs:{min:1,max:100}},{keywords:["percentage","percent"],fakerMethod:"number.int",schemaType:"number",minScore:0.8,fakerArgs:{min:0,max:100}},{keywords:["weight"],fakerMethod:"number.float",schemaType:"number",minScore:0.8,fakerArgs:{min:0.1,max:200}},{keywords:["height"],fakerMethod:"number.int",schemaType:"number",minScore:0.8,fakerArgs:{min:100,max:220}},{keywords:["width","length","depth"],fakerMethod:"number.int",schemaType:"number",minScore:0.8,fakerArgs:{min:1,max:1000}},{keywords:["priority","order","rank","level"],fakerMethod:"number.int",schemaType:"number",minScore:0.8,fakerArgs:{min:1,max:10}},{keywords:["version"],fakerMethod:"system.semver",schemaType:"string",minScore:0.8}],WQ=[{keywords:["is_active","isactive","active","enabled","is_enabled"],fakerMethod:"datatype.boolean",schemaType:"boolean",minScore:0.6,trueProbability:0.9},{keywords:["is_deleted","isdeleted","deleted"],fakerMethod:"datatype.boolean",schemaType:"boolean",minScore:0.6,trueProbability:0.05},{keywords:["is_archived","isarchived","archived"],fakerMethod:"datatype.boolean",schemaType:"boolean",minScore:0.6,trueProbability:0.1},{keywords:["is_verified","isverified","verified","confirmed","is_confirmed"],fakerMethod:"datatype.boolean",schemaType:"boolean",minScore:0.6,trueProbability:0.8},{keywords:["is_admin","isadmin","admin"],fakerMethod:"datatype.boolean",schemaType:"boolean",minScore:0.6,trueProbability:0.1},{keywords:["is_public","ispublic","public","visible","is_visible"],fakerMethod:"datatype.boolean",schemaType:"boolean",minScore:0.6,trueProbability:0.7},{keywords:["is_read","isread","read","seen","is_seen"],fakerMethod:"datatype.boolean",schemaType:"boolean",minScore:0.6,trueProbability:0.6},{keywords:["is_default","isdefault"],fakerMethod:"datatype.boolean",schemaType:"boolean",minScore:0.8,trueProbability:0.1},{keywords:["is_required","isrequired","required","mandatory"],fakerMethod:"datatype.boolean",schemaType:"boolean",minScore:0.6,trueProbability:0.5},{keywords:["is_featured","isfeatured","featured","promoted"],fakerMethod:"datatype.boolean",schemaType:"boolean",minScore:0.8,trueProbability:0.15},{keywords:["available","in_stock"],fakerMethod:"datatype.boolean",schemaType:"boolean",minScore:0.8,trueProbability:0.85}],qQ=[{keywords:["filename","file_name"],fakerMethod:"system.fileName",schemaType:"string",minScore:0.8},{keywords:["file_type","filetype","mime_type","mimetype","content_type"],fakerMethod:"system.mimeType",schemaType:"string",minScore:0.8},{keywords:["file_ext","extension"],fakerMethod:"system.fileExt",schemaType:"string",minScore:0.9},{keywords:["file_path","filepath","path"],fakerMethod:"system.filePath",schemaType:"string",minScore:0.9},{keywords:["cron","cron_expression"],fakerMethod:"system.cron",schemaType:"string",minScore:0.9},{keywords:["semver"],fakerMethod:"system.semver",schemaType:"string",minScore:0.9}],UQ=[{keywords:["aircraft_type","airplane","aircraft"],fakerMethod:"airline.aircraftType",schemaType:"string",minScore:0.9},{keywords:["flight_number","flight"],fakerMethod:"airline.flightNumber",schemaType:"string",minScore:0.9},{keywords:["record_locator","booking_ref","pnr"],fakerMethod:"airline.recordLocator",schemaType:"string",minScore:0.9},{keywords:["seat","seat_number"],fakerMethod:"airline.seat",schemaType:"string",minScore:0.9}],VQ=[{keywords:["animal","animal_type","species"],fakerMethod:"animal.type",schemaType:"string",minScore:0.9},{keywords:["pet_name"],fakerMethod:"animal.petName",schemaType:"string",minScore:0.9},{keywords:["breed"],fakerMethod:"animal.dog",schemaType:"string",minScore:0.9},{keywords:["bird"],fakerMethod:"animal.bird",schemaType:"string",minScore:0.9},{keywords:["fish"],fakerMethod:"animal.fish",schemaType:"string",minScore:0.9},{keywords:["horse"],fakerMethod:"animal.horse",schemaType:"string",minScore:0.9},{keywords:["insect"],fakerMethod:"animal.insect",schemaType:"string",minScore:0.9}],YQ=[{keywords:["book_title"],fakerMethod:"book.title",schemaType:"string",minScore:0.9},{keywords:["author","book_author","writer"],fakerMethod:"book.author",schemaType:"string",minScore:0.9},{keywords:["genre","book_genre"],fakerMethod:"book.genre",schemaType:"string",minScore:0.9},{keywords:["publisher","publishing_house"],fakerMethod:"book.publisher",schemaType:"string",minScore:0.9},{keywords:["book_series","series_name"],fakerMethod:"book.series",schemaType:"string",minScore:0.9}],FQ=[{keywords:["dish","meal","recipe_name"],fakerMethod:"food.dish",schemaType:"string",minScore:0.9},{keywords:["ingredient"],fakerMethod:"food.ingredient",schemaType:"string",minScore:0.9},{keywords:["spice"],fakerMethod:"food.spice",schemaType:"string",minScore:0.9},{keywords:["fruit"],fakerMethod:"food.fruit",schemaType:"string",minScore:0.9},{keywords:["vegetable"],fakerMethod:"food.vegetable",schemaType:"string",minScore:0.9},{keywords:["meat"],fakerMethod:"food.meat",schemaType:"string",minScore:0.9},{keywords:["food_description"],fakerMethod:"food.description",schemaType:"string",minScore:0.9},{keywords:["ethnic_category","cuisine"],fakerMethod:"food.ethnicCategory",schemaType:"string",minScore:0.9}],HQ=[{keywords:["song","song_name","track","track_name"],fakerMethod:"music.songName",schemaType:"string",minScore:0.9},{keywords:["album","album_name"],fakerMethod:"music.album",schemaType:"string",minScore:0.9},{keywords:["artist","musician","band"],fakerMethod:"music.artist",schemaType:"string",minScore:0.9},{keywords:["music_genre"],fakerMethod:"music.genre",schemaType:"string",minScore:0.9}],GQ=[],JQ=[{keywords:["vehicle","vehicle_name"],fakerMethod:"vehicle.vehicle",schemaType:"string",minScore:0.9},{keywords:["vehicle_type"],fakerMethod:"vehicle.type",schemaType:"string",minScore:0.9},{keywords:["vehicle_manufacturer","car_make"],fakerMethod:"vehicle.manufacturer",schemaType:"string",minScore:0.9},{keywords:["vehicle_model","car_model"],fakerMethod:"vehicle.model",schemaType:"string",minScore:0.9},{keywords:["fuel","fuel_type"],fakerMethod:"vehicle.fuel",schemaType:"string",minScore:0.9},{keywords:["bicycle"],fakerMethod:"vehicle.bicycle",schemaType:"string",minScore:0.9},{keywords:["vehicle_color","car_color"],fakerMethod:"vehicle.color",schemaType:"string",minScore:0.9}],wQ=[{keywords:["branch","branch_name","git_branch"],fakerMethod:"git.branch",schemaType:"string",minScore:0.9},{keywords:["commit_sha","commit_hash","sha"],fakerMethod:"git.commitSha",schemaType:"string",minScore:0.9},{keywords:["commit_message"],fakerMethod:"git.commitMessage",schemaType:"string",minScore:0.9}],CQ=[{keywords:["db_column","column_name"],fakerMethod:"database.column",schemaType:"string",minScore:0.9},{keywords:["db_type","column_type"],fakerMethod:"database.type",schemaType:"string",minScore:0.9},{keywords:["db_engine","database_engine"],fakerMethod:"database.engine",schemaType:"string",minScore:0.9},{keywords:["collation"],fakerMethod:"database.collation",schemaType:"string",minScore:0.9},{keywords:["mongodb_id","object_id"],fakerMethod:"database.mongodbObjectId",schemaType:"string",minScore:0.9}],jQ=[{keywords:["abbreviation","tech_abbreviation"],fakerMethod:"hacker.abbreviation",schemaType:"string",minScore:0.9},{keywords:["hacker_phrase","tech_phrase"],fakerMethod:"hacker.phrase",schemaType:"string",minScore:0.9}],IQ=[{keywords:["adjective"],fakerMethod:"word.adjective",schemaType:"string",minScore:0.8},{keywords:["adverb"],fakerMethod:"word.adverb",schemaType:"string",minScore:0.8},{keywords:["noun"],fakerMethod:"word.noun",schemaType:"string",minScore:0.8},{keywords:["verb"],fakerMethod:"word.verb",schemaType:"string",minScore:0.8}],l=[...s,...t,...a,...e,...QQ,...$Q,...BQ,...ZQ,...KQ,...XQ,...zQ,...WQ,...qQ,...UQ,...VQ,...YQ,...FQ,...HQ,...GQ,...JQ,...wQ,...CQ,...jQ,...IQ];function d(Q){let $=Q.split(/[_-]/),B=[];for(let Z of $){if(!Z)continue;let K=Z.replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z0-9])([A-Z])/g,"$1_$2").split("_");for(let X of K)if(X)B.push(X.toLowerCase())}return B}function MQ(Q,$){let B=Q.join(""),Z=0;for(let K of $){let X=d(K),q=X.join("");if(B===q)return 1;if(X.length>0&&X.every((z)=>Q.includes(z))){let W=X.length/Q.length>0.5?0.9:0.65;Z=Math.max(Z,W)}if(X.length>0&&X.length<=Q.length){if(Q.slice(-X.length).every((W,U)=>W===X[U]))Z=Math.max(Z,0.8)}if(q.length>=3&&B.includes(q))Z=Math.max(Z,0.7)}return Z}function p(Q,$,B=l){let Z=$,K=typeof $.type==="string"?$.type:void 0;if(K==="string"&&$.format==="uuid")return{mapping:{keywords:["uuid"],fakerMethod:"string.uuid",schemaType:"string",minScore:0.5},score:1};if(Z.pattern||Z.enum||Z.faker)return;let X=$.minimum!==void 0||$.maximum!==void 0||$.exclusiveMinimum!==void 0||$.exclusiveMaximum!==void 0,q=d(Q),z;for(let W of B){if(X&&(W.schemaType==="number"||W.schemaType==="integer"))continue;if(W.schemaType&&K&&W.schemaType!==K){if(!(W.schemaType==="number"&&K==="integer"||W.schemaType==="integer"&&K==="number"))continue}let U=MQ(q,W.keywords);if(U>=W.minScore&&(!z||U>z.score))z={mapping:W,score:U}}if(K==="string"){if(q[q.length-1]==="id"&&q.length>1){if(!z||z.score<0.8)z={mapping:{keywords:["id"],fakerMethod:"string.uuid",schemaType:"string",minScore:0.5},score:0.8}}}return z}import{ResourceLimitError as x,SchemaValidationError as Y}from"@schmock/core";var R;function V(Q){return typeof Q==="object"&&Q!==null&&!Array.isArray(Q)}function j(Q,$="$"){if(!Q||typeof Q!=="object")throw new Y($,"Schema must be a valid JSON Schema object");if(Object.keys(Q).length===0)throw new Y($,"Schema cannot be empty");let B=["object","array","string","number","integer","boolean","null"];if(Q.type&&typeof Q.type==="string"&&!B.includes(Q.type))throw new Y($,`Invalid schema type: "${Q.type}"`,"Supported types are: object, array, string, number, integer, boolean, null");if(Q.type==="object"&&Q.properties){if(typeof Q.properties!=="object"||Array.isArray(Q.properties))throw new Y(`${$}.properties`,"Properties must be an object mapping property names to schemas",'Use { "propertyName": { "type": "string" } } format');for(let[K,X]of Object.entries(Q.properties))if(typeof X==="object"&&X!==null){let q="faker"in X?String(X.faker):void 0;if(q)try{A(q)}catch(z){if(z instanceof Y){let W=z.context,U="Invalid faker method",H;if(W&&typeof W==="object"){if("issue"in W&&typeof W.issue==="string")U=W.issue;if("suggestion"in W&&typeof W.suggestion==="string")H=W.suggestion}throw new Y(`${$}.properties.${K}.faker`,U,H)}if(z instanceof Error)throw z;throw Error(String(z))}j(X,`${$}.properties.${K}`)}}if(Q.type==="array"){if(Q.items===null||Q.items===void 0)throw new Y(`${$}.items`,"Array schema must have valid items definition","Define items as a schema object or array of schemas");if(Array.isArray(Q.items)){if(Q.items.length===0)throw new Y(`${$}.items`,"Array items cannot be empty array","Provide at least one item schema");Q.items.forEach((K,X)=>{if(typeof K==="object"&&K!==null)j(K,`${$}.items[${X}]`)})}else if(typeof Q.items==="object"&&Q.items!==null)j(Q.items,`${$}.items`)}if(N(Q))throw new Y($,"Schema contains circular references which are not supported");let Z=D(Q);if(Z>b)throw new x("schema_nesting_depth",b,Z);if(Z>=w)PQ(Q,$);if(O(Q,$),Q.$ref==="#")throw new Y($,"Self-referencing schemas are not supported")}function N(Q,$=new Set){if($.has(Q))return!0;if(Q.$ref==="#")return!0;if($.add(Q),Q.type==="object"&&Q.properties){for(let B of Object.values(Q.properties))if(V(B)){if(N(B,$))return!0}}if(Q.type==="array"&&Q.items){let B=Array.isArray(Q.items)?Q.items:[Q.items];for(let Z of B)if(V(Z)){if(N(Z,$))return!0}}return $.delete(Q),!1}function D(Q,$=0){if($>b)return $;let B=$;if(Q.type==="object"&&Q.properties){for(let Z of Object.values(Q.properties))if(V(Z))B=Math.max(B,D(Z,$+1))}if(Q.type==="array"&&Q.items){let Z=Array.isArray(Q.items)?Q.items:[Q.items];for(let K of Z)if(V(K))B=Math.max(B,D(K,$+1))}return B}function PQ(Q,$){function B(Z,K){let X=Z.type;if(Array.isArray(X)?X.includes("array"):X==="array"){let z=Z.maxItems||G;if(K>=w&&z>=M)throw new x("deep_nesting_memory_risk",w*M,K*z);if(Z.items){let W=Array.isArray(Z.items)?Z.items:[Z.items];for(let U of W)if(V(U))B(U,K+1)}return}if(X==="object"&&Z.properties){for(let z of Object.values(Z.properties))if(V(z))B(z,K+1)}}B(Q,0)}function O(Q,$){if(Q.type==="array"){if(Q.maxItems&&Q.maxItems>J)throw new x("array_max_items",J,Q.maxItems);let B=D(Q),Z=Q.maxItems||Q.minItems||G;if(B>w&&Z>M)throw new x("memory_estimation",w*M,B*Z)}if(Q.type==="object"&&Q.properties){for(let[B,Z]of Object.entries(Q.properties))if(V(Z))O(Z,`${$}.properties.${B}`)}if(Q.type==="array"&&Q.items){if(Array.isArray(Q.items))Q.items.forEach((B,Z)=>{if(V(B))O(B,`${$}.items[${Z}]`)});else if(V(Q.items))O(Q.items,`${$}.items`)}}function A(Q){let $=Q.split(".");if($.length<2)throw new Y("$.faker",`Invalid faker method format: "${Q}"`,"Use format like 'person.firstName' or 'internet.email'");if(!R)R=L();let Z=R;for(let K of $)if(Z&&typeof Z==="object"&&K in Z)Z=Z[K];else throw new Y("$.faker",`Invalid faker method: "${Q}"`,"Check faker.js documentation for valid methods");if(typeof Z!=="function")throw new Y("$.faker",`Invalid faker method: "${Q}" is not a function`,"Check faker.js documentation for valid methods")}function F(Q){if(!Q||typeof Q!=="object")return Q;let $={...Q};if($.properties){$.properties={...$.properties};for(let[B,Z]of Object.entries($.properties))if(V(Z))$.properties[B]=bQ(B,Z)}for(let B of["allOf","anyOf","oneOf"]){let Z=$[B];if(Array.isArray(Z))$[B]=Z.map((K)=>V(K)?F(K):K)}if($.items){if(Array.isArray($.items))$.items=$.items.map((B)=>V(B)?F(B):B);else if(V($.items))$.items=F($.items)}if($.additionalProperties&&typeof $.additionalProperties==="object"&&!Array.isArray($.additionalProperties))$.additionalProperties=F($.additionalProperties);return $}function bQ(Q,$){let B={...$};if(B.faker)return A(B.faker),B;let Z=B.allOf||B.anyOf||B.oneOf;if(B.properties||Z||B.items){let X=F(B);Object.assign(B,X)}if(Z)return B;let K=p(Q,B);if(K){if(B.faker=K.mapping.fakerMethod,K.mapping.format)B.format=K.mapping.format;if(K.mapping.trueProbability!==void 0)B.schmockTrueProbability=K.mapping.trueProbability}return B}function hQ(Q){return j(Q.schema),{name:"faker",version:"1.0.1",process($,B){if(B!==void 0&&B!==null)return{context:$,response:B};try{let Z=OQ({schema:Q.schema,count:Q.count,overrides:Q.overrides,params:$.params,state:$.routeState,query:$.query,seed:Q.seed});return{context:$,response:Z}}catch(Z){if(Z instanceof i||Z instanceof o)throw Z;throw new LQ($.path,Z instanceof Error?Z:Error(String(Z)),Q.schema)}}}}function OQ(Q){let{schema:$,count:B,overrides:Z,params:K,state:X,query:q,seed:z}=Q;j($);let W;if($.type==="array"&&$.items){let U=u($,B);if(U>J)throw new o("array_size",J,U);let H=Array.isArray($.items)?$.items[0]:$.items;if(!H||typeof H==="boolean")throw new i("$.items","Array schema must have valid items definition");let T=F(H);W=[];for(let y=0;y<U;y++){let I=v(z).generate(T);I=_(I,T),I=P(I,Z,K,X,q),W.push(I)}}else{let U=F($);W=v(z).generate(U),W=_(W,U),W=P(W,Z,K,X,q)}return W}function _(Q,$){if(Q===null||Q===void 0||!$||typeof $!=="object")return Q;let B=$;if(B.schmockNullable===!0){if(Math.random()<E)return null}if($.type==="boolean"&&typeof B.schmockTrueProbability==="number")return Math.random()<B.schmockTrueProbability;if(typeof Q==="object"&&!Array.isArray(Q)&&$.properties){for(let[Z,K]of Object.entries($.properties))if(Z in Q&&V(K))Q[Z]=_(Q[Z],K)}if(Array.isArray(Q)&&$.items&&V($.items))for(let Z=0;Z<Q.length;Z++)Q[Z]=_(Q[Z],$.items);return Q}export{OQ as generateFromSchema,hQ as fakerPlugin};
|
package/dist/jsf-config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsf-config.d.ts","sourceRoot":"","sources":["../src/jsf-config.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"jsf-config.d.ts","sourceRoot":"","sources":["../src/jsf-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,GAAG,MAAM,mBAAmB,CAAC;AAEpC;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE,MAAM,SAMhD;AAoBD,wBAAgB,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,CAuBhD"}
|
package/dist/jsf-config.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { en, Faker } from "@faker-js/faker";
|
|
1
|
+
import { base, en, Faker } from "@faker-js/faker";
|
|
2
2
|
import jsf from "json-schema-faker";
|
|
3
3
|
/**
|
|
4
4
|
* Create isolated faker instance to avoid race conditions
|
|
@@ -6,7 +6,7 @@ import jsf from "json-schema-faker";
|
|
|
6
6
|
* @returns Fresh Faker instance with English locale
|
|
7
7
|
*/
|
|
8
8
|
export function createFakerInstance(seed) {
|
|
9
|
-
const faker = new Faker({ locale: [en] });
|
|
9
|
+
const faker = new Faker({ locale: [en, base] });
|
|
10
10
|
if (seed !== undefined) {
|
|
11
11
|
faker.seed(seed);
|
|
12
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-enhancement.d.ts","sourceRoot":"","sources":["../src/schema-enhancement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"schema-enhancement.d.ts","sourceRoot":"","sources":["../src/schema-enhancement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAW/C,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,WAAW,GAClB,WAAW,CAwDb"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { findBestMapping } from "./field-name-matcher.js";
|
|
1
2
|
import { isJSONSchema7, validateFakerMethod } from "./validation.js";
|
|
2
3
|
export function enhanceSchemaWithSmartMapping(schema) {
|
|
3
4
|
if (!schema || typeof schema !== "object") {
|
|
@@ -5,7 +6,7 @@ export function enhanceSchemaWithSmartMapping(schema) {
|
|
|
5
6
|
}
|
|
6
7
|
const enhanced = { ...schema };
|
|
7
8
|
// Handle object properties
|
|
8
|
-
if (enhanced.
|
|
9
|
+
if (enhanced.properties) {
|
|
9
10
|
enhanced.properties = { ...enhanced.properties };
|
|
10
11
|
for (const [fieldName, fieldSchema] of Object.entries(enhanced.properties)) {
|
|
11
12
|
if (isJSONSchema7(fieldSchema)) {
|
|
@@ -13,6 +14,28 @@ export function enhanceSchemaWithSmartMapping(schema) {
|
|
|
13
14
|
}
|
|
14
15
|
}
|
|
15
16
|
}
|
|
17
|
+
// Recurse into composition keywords
|
|
18
|
+
for (const keyword of ["allOf", "anyOf", "oneOf"]) {
|
|
19
|
+
const branches = enhanced[keyword];
|
|
20
|
+
if (Array.isArray(branches)) {
|
|
21
|
+
enhanced[keyword] = branches.map((branch) => isJSONSchema7(branch) ? enhanceSchemaWithSmartMapping(branch) : branch);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// Recurse into array items
|
|
25
|
+
if (enhanced.items) {
|
|
26
|
+
if (Array.isArray(enhanced.items)) {
|
|
27
|
+
enhanced.items = enhanced.items.map((item) => isJSONSchema7(item) ? enhanceSchemaWithSmartMapping(item) : item);
|
|
28
|
+
}
|
|
29
|
+
else if (isJSONSchema7(enhanced.items)) {
|
|
30
|
+
enhanced.items = enhanceSchemaWithSmartMapping(enhanced.items);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Recurse into additionalProperties
|
|
34
|
+
if (enhanced.additionalProperties &&
|
|
35
|
+
typeof enhanced.additionalProperties === "object" &&
|
|
36
|
+
!Array.isArray(enhanced.additionalProperties)) {
|
|
37
|
+
enhanced.additionalProperties = enhanceSchemaWithSmartMapping(enhanced.additionalProperties);
|
|
38
|
+
}
|
|
16
39
|
return enhanced;
|
|
17
40
|
}
|
|
18
41
|
function enhanceFieldSchema(fieldName, fieldSchema) {
|
|
@@ -22,60 +45,26 @@ function enhanceFieldSchema(fieldName, fieldSchema) {
|
|
|
22
45
|
validateFakerMethod(enhanced.faker);
|
|
23
46
|
return enhanced;
|
|
24
47
|
}
|
|
25
|
-
//
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
enhanced
|
|
30
|
-
enhanced.faker = "internet.email";
|
|
31
|
-
}
|
|
32
|
-
// Name fields
|
|
33
|
-
else if (lowerFieldName === "firstname" || lowerFieldName === "first_name") {
|
|
34
|
-
enhanced.faker = "person.firstName";
|
|
35
|
-
}
|
|
36
|
-
else if (lowerFieldName === "lastname" || lowerFieldName === "last_name") {
|
|
37
|
-
enhanced.faker = "person.lastName";
|
|
38
|
-
}
|
|
39
|
-
else if (lowerFieldName === "name" || lowerFieldName === "fullname") {
|
|
40
|
-
enhanced.faker = "person.fullName";
|
|
41
|
-
}
|
|
42
|
-
// Phone fields
|
|
43
|
-
else if (lowerFieldName.includes("phone") || lowerFieldName === "mobile") {
|
|
44
|
-
enhanced.faker = "phone.number";
|
|
48
|
+
// Recursively enhance nested schemas first
|
|
49
|
+
const hasComposition = enhanced.allOf || enhanced.anyOf || enhanced.oneOf;
|
|
50
|
+
if (enhanced.properties || hasComposition || enhanced.items) {
|
|
51
|
+
const recursed = enhanceSchemaWithSmartMapping(enhanced);
|
|
52
|
+
Object.assign(enhanced, recursed);
|
|
45
53
|
}
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
enhanced
|
|
49
|
-
}
|
|
50
|
-
else if (lowerFieldName === "city") {
|
|
51
|
-
enhanced.faker = "location.city";
|
|
52
|
-
}
|
|
53
|
-
else if (lowerFieldName === "zipcode" || lowerFieldName === "zip") {
|
|
54
|
-
enhanced.faker = "location.zipCode";
|
|
55
|
-
}
|
|
56
|
-
// UUID fields
|
|
57
|
-
else if (lowerFieldName === "uuid" ||
|
|
58
|
-
(lowerFieldName === "id" && enhanced.format === "uuid")) {
|
|
59
|
-
enhanced.faker = "string.uuid";
|
|
60
|
-
}
|
|
61
|
-
// Date fields
|
|
62
|
-
else if (lowerFieldName.includes("createdat") ||
|
|
63
|
-
lowerFieldName.includes("created_at") ||
|
|
64
|
-
lowerFieldName.includes("updatedat") ||
|
|
65
|
-
lowerFieldName.includes("updated_at")) {
|
|
66
|
-
enhanced.format = "date-time";
|
|
67
|
-
enhanced.faker = "date.recent";
|
|
68
|
-
}
|
|
69
|
-
// Company fields
|
|
70
|
-
else if (lowerFieldName.includes("company")) {
|
|
71
|
-
enhanced.faker = "company.name";
|
|
72
|
-
}
|
|
73
|
-
else if (lowerFieldName === "position" || lowerFieldName === "jobtitle") {
|
|
74
|
-
enhanced.faker = "person.jobTitle";
|
|
54
|
+
// Don't apply field-level faker mapping to composition schemas — the branches define their own types
|
|
55
|
+
if (hasComposition) {
|
|
56
|
+
return enhanced;
|
|
75
57
|
}
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
|
|
58
|
+
// Apply smart field name mapping via the scoring matcher
|
|
59
|
+
const match = findBestMapping(fieldName, enhanced);
|
|
60
|
+
if (match) {
|
|
61
|
+
enhanced.faker = match.mapping.fakerMethod;
|
|
62
|
+
if (match.mapping.format) {
|
|
63
|
+
enhanced.format = match.mapping.format;
|
|
64
|
+
}
|
|
65
|
+
if (match.mapping.trueProbability !== undefined) {
|
|
66
|
+
enhanced.schmockTrueProbability = match.mapping.trueProbability;
|
|
67
|
+
}
|
|
79
68
|
}
|
|
80
69
|
return enhanced;
|
|
81
70
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schmock/faker",
|
|
3
3
|
"description": "Faker-powered automatic data generation for Schmock",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.10.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"json-schema-faker": "^0.5.6"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@schmock/core": "^1.
|
|
37
|
+
"@schmock/core": "^1.10.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@amiceli/vitest-cucumber": "^6.2.0",
|
package/src/constants.ts
CHANGED
|
@@ -4,3 +4,6 @@ export const MAX_NESTING_DEPTH = 10; // Reasonable limit for schema nesting
|
|
|
4
4
|
export const DEFAULT_ARRAY_COUNT = 3; // Default items to generate when not specified
|
|
5
5
|
export const DEEP_NESTING_THRESHOLD = 3; // Depth at which to check for memory risks
|
|
6
6
|
export const LARGE_ARRAY_THRESHOLD = 100; // Array size considered "large"
|
|
7
|
+
|
|
8
|
+
// Data quality tuning
|
|
9
|
+
export const NULLABLE_NULL_PROBABILITY = 0.05; // 5% chance nullable fields are null
|