@anil-labs/factory 0.1.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/CHANGELOG.md +54 -0
- package/LICENSE +21 -0
- package/README.md +371 -0
- package/dist/builders/index.d.cts +40 -0
- package/dist/builders/index.d.ts +40 -0
- package/dist/chunks/faker-BOtDMmjd.cjs +1430 -0
- package/dist/chunks/faker-BOtDMmjd.cjs.map +1 -0
- package/dist/chunks/faker-BlEhpR26.mjs +1287 -0
- package/dist/chunks/faker-BlEhpR26.mjs.map +1 -0
- package/dist/chunks/persist-DcARfeC-.cjs +134 -0
- package/dist/chunks/persist-DcARfeC-.cjs.map +1 -0
- package/dist/chunks/persist-ZGX3NWMF.mjs +117 -0
- package/dist/chunks/persist-ZGX3NWMF.mjs.map +1 -0
- package/dist/core/collection.d.cts +41 -0
- package/dist/core/collection.d.ts +41 -0
- package/dist/core/factory.d.cts +115 -0
- package/dist/core/factory.d.ts +115 -0
- package/dist/core/index.d.cts +6 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/registry.d.cts +20 -0
- package/dist/core/registry.d.ts +20 -0
- package/dist/core/sequence.d.cts +36 -0
- package/dist/core/sequence.d.ts +36 -0
- package/dist/core/types.d.cts +47 -0
- package/dist/core/types.d.ts +47 -0
- package/dist/faker/color.d.cts +22 -0
- package/dist/faker/color.d.ts +22 -0
- package/dist/faker/commerce.d.cts +21 -0
- package/dist/faker/commerce.d.ts +21 -0
- package/dist/faker/company.d.cts +20 -0
- package/dist/faker/company.d.ts +20 -0
- package/dist/faker/datatype.d.cts +16 -0
- package/dist/faker/datatype.d.ts +16 -0
- package/dist/faker/date.d.cts +29 -0
- package/dist/faker/date.d.ts +29 -0
- package/dist/faker/faker.d.cts +82 -0
- package/dist/faker/faker.d.ts +82 -0
- package/dist/faker/finance.d.cts +25 -0
- package/dist/faker/finance.d.ts +25 -0
- package/dist/faker/helpers.d.cts +52 -0
- package/dist/faker/helpers.d.ts +52 -0
- package/dist/faker/image.d.cts +22 -0
- package/dist/faker/image.d.ts +22 -0
- package/dist/faker/index.d.cts +21 -0
- package/dist/faker/index.d.ts +21 -0
- package/dist/faker/internet.d.cts +33 -0
- package/dist/faker/internet.d.ts +33 -0
- package/dist/faker/locale.d.cts +26 -0
- package/dist/faker/locale.d.ts +26 -0
- package/dist/faker/location.d.cts +30 -0
- package/dist/faker/location.d.ts +30 -0
- package/dist/faker/lorem.d.cts +26 -0
- package/dist/faker/lorem.d.ts +26 -0
- package/dist/faker/number.d.cts +31 -0
- package/dist/faker/number.d.ts +31 -0
- package/dist/faker/person.d.cts +29 -0
- package/dist/faker/person.d.ts +29 -0
- package/dist/faker/regex.d.cts +19 -0
- package/dist/faker/regex.d.ts +19 -0
- package/dist/faker/string.d.cts +33 -0
- package/dist/faker/string.d.ts +33 -0
- package/dist/faker/system.d.cts +29 -0
- package/dist/faker/system.d.ts +29 -0
- package/dist/faker.cjs +26 -0
- package/dist/faker.mjs +3 -0
- package/dist/index.cjs +635 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +37 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.mjs +596 -0
- package/dist/index.mjs.map +1 -0
- package/dist/locales/en.cjs +351 -0
- package/dist/locales/en.cjs.map +1 -0
- package/dist/locales/en.d.cts +11 -0
- package/dist/locales/en.d.ts +11 -0
- package/dist/locales/en.mjs +350 -0
- package/dist/locales/en.mjs.map +1 -0
- package/dist/locales/types.d.cts +30 -0
- package/dist/locales/types.d.ts +30 -0
- package/dist/persist/console.d.cts +15 -0
- package/dist/persist/console.d.ts +15 -0
- package/dist/persist/http.d.cts +42 -0
- package/dist/persist/http.d.ts +42 -0
- package/dist/persist/index.d.cts +5 -0
- package/dist/persist/index.d.ts +5 -0
- package/dist/persist/memory.d.cts +26 -0
- package/dist/persist/memory.d.ts +26 -0
- package/dist/persist.cjs +5 -0
- package/dist/persist.mjs +2 -0
- package/dist/prng/index.d.cts +5 -0
- package/dist/prng/index.d.ts +5 -0
- package/dist/prng/mulberry32.d.cts +19 -0
- package/dist/prng/mulberry32.d.ts +19 -0
- package/dist/prng/types.d.cts +23 -0
- package/dist/prng/types.d.ts +23 -0
- package/dist/snapshot/index.d.cts +16 -0
- package/dist/snapshot/index.d.ts +16 -0
- package/package.json +136 -0
|
@@ -0,0 +1,1287 @@
|
|
|
1
|
+
import { en } from "../locales/en.mjs";
|
|
2
|
+
//#region src/prng/mulberry32.ts
|
|
3
|
+
/**
|
|
4
|
+
* Mulberry32 — 32-bit, ~4 billion period, very fast, deterministic.
|
|
5
|
+
*
|
|
6
|
+
* Good enough for test data and snapshots. NOT cryptographically secure.
|
|
7
|
+
*
|
|
8
|
+
* @see https://gist.github.com/tommyettinger/46a3b8f97c8e3a59e1e0c7f8e85bcde6
|
|
9
|
+
*/
|
|
10
|
+
var Mulberry32 = class {
|
|
11
|
+
state;
|
|
12
|
+
constructor(seed) {
|
|
13
|
+
this.state = normalizeSeed(seed);
|
|
14
|
+
}
|
|
15
|
+
get currentSeed() {
|
|
16
|
+
return this.state >>> 0;
|
|
17
|
+
}
|
|
18
|
+
seed(seed) {
|
|
19
|
+
this.state = normalizeSeed(seed);
|
|
20
|
+
}
|
|
21
|
+
next() {
|
|
22
|
+
this.state = this.state + 1831565813 >>> 0;
|
|
23
|
+
let t = this.state;
|
|
24
|
+
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
25
|
+
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
26
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
27
|
+
}
|
|
28
|
+
int(min, max) {
|
|
29
|
+
if (max < min) [min, max] = [max, min];
|
|
30
|
+
return Math.floor(this.next() * (max - min + 1)) + min;
|
|
31
|
+
}
|
|
32
|
+
float(min, max, decimals = 2) {
|
|
33
|
+
const v = this.next() * (max - min) + min;
|
|
34
|
+
const factor = 10 ** decimals;
|
|
35
|
+
return Math.round(v * factor) / factor;
|
|
36
|
+
}
|
|
37
|
+
bool(chance = .5) {
|
|
38
|
+
return this.next() < chance;
|
|
39
|
+
}
|
|
40
|
+
pick(items) {
|
|
41
|
+
if (items.length === 0) throw new Error("[Prng] pick(): array is empty.");
|
|
42
|
+
const picked = items[this.int(0, items.length - 1)];
|
|
43
|
+
if (picked === void 0) throw new Error("[Prng] pick(): unreachable index");
|
|
44
|
+
return picked;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Coerce any input into a non-zero 32-bit unsigned integer. We map `0` to the
|
|
49
|
+
* golden-ratio constant so callers passing `0` get a deterministic-but-non-zero
|
|
50
|
+
* starting state (zero would emit a long initial run of small numbers).
|
|
51
|
+
*/
|
|
52
|
+
function normalizeSeed(seed) {
|
|
53
|
+
if (typeof seed !== "number" || Number.isNaN(seed)) return (Date.now() ^ Math.floor(Math.random() * 4294967295)) >>> 0;
|
|
54
|
+
const truncated = Math.trunc(seed) >>> 0;
|
|
55
|
+
return truncated === 0 ? 2654435769 : truncated;
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/prng/index.ts
|
|
59
|
+
/** Construct a default PRNG (currently Mulberry32). */
|
|
60
|
+
function createPrng(seed) {
|
|
61
|
+
return new Mulberry32(seed);
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/faker/locale.ts
|
|
65
|
+
/**
|
|
66
|
+
* Live reference to the active locale data. A single instance is shared by
|
|
67
|
+
* every faker namespace, so swapping the locale at the `Faker` level
|
|
68
|
+
* propagates instantly without rebuilding modules.
|
|
69
|
+
*/
|
|
70
|
+
var LocaleRef = class {
|
|
71
|
+
currentName;
|
|
72
|
+
currentData;
|
|
73
|
+
constructor(initial = "en") {
|
|
74
|
+
this.currentName = initial;
|
|
75
|
+
const data = registry.get(initial);
|
|
76
|
+
if (!data) throw new Error(`[Locale] Unknown locale "${initial}". Registered: ${[...registry.keys()].join(", ")}`);
|
|
77
|
+
this.currentData = data;
|
|
78
|
+
}
|
|
79
|
+
/** Read the currently-active locale data. */
|
|
80
|
+
get data() {
|
|
81
|
+
return this.currentData;
|
|
82
|
+
}
|
|
83
|
+
/** Read the active locale's identifier (e.g. `"en"`). */
|
|
84
|
+
get name() {
|
|
85
|
+
return this.currentName;
|
|
86
|
+
}
|
|
87
|
+
/** Swap to a different registered locale. Throws if unknown. */
|
|
88
|
+
set(name) {
|
|
89
|
+
const data = registry.get(name);
|
|
90
|
+
if (!data) throw new Error(`[Locale] Unknown locale "${name}". Registered: ${[...registry.keys()].join(", ")}`);
|
|
91
|
+
this.currentName = name;
|
|
92
|
+
this.currentData = data;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
var registry = /* @__PURE__ */ new Map();
|
|
96
|
+
registry.set("en", en);
|
|
97
|
+
/** Register a new locale. Overwrites if `name` already exists. */
|
|
98
|
+
function registerLocale(name, data) {
|
|
99
|
+
registry.set(name, data);
|
|
100
|
+
}
|
|
101
|
+
/** Read a locale's raw data without making it active. */
|
|
102
|
+
function getLocale(name) {
|
|
103
|
+
return registry.get(name);
|
|
104
|
+
}
|
|
105
|
+
/** List every registered locale identifier. */
|
|
106
|
+
function listLocales() {
|
|
107
|
+
return [...registry.keys()];
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/faker/person.ts
|
|
111
|
+
/**
|
|
112
|
+
* Personal-name namespace.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* faker.person.firstName() // "Sarah"
|
|
117
|
+
* faker.person.firstName('male') // "James"
|
|
118
|
+
* faker.person.fullName() // "Olivia Patel"
|
|
119
|
+
* faker.person.jobTitle() // → from `company.jobTitle()`
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
var Person = class {
|
|
123
|
+
rng;
|
|
124
|
+
locale;
|
|
125
|
+
constructor(rng, locale) {
|
|
126
|
+
this.rng = rng;
|
|
127
|
+
this.locale = locale;
|
|
128
|
+
}
|
|
129
|
+
firstName(sex) {
|
|
130
|
+
const d = this.locale.data;
|
|
131
|
+
if (sex === "male" && d.firstNamesMale?.length) return this.rng.pick(d.firstNamesMale);
|
|
132
|
+
if (sex === "female" && d.firstNamesFemale?.length) return this.rng.pick(d.firstNamesFemale);
|
|
133
|
+
return this.rng.pick(d.firstNames);
|
|
134
|
+
}
|
|
135
|
+
lastName() {
|
|
136
|
+
return this.rng.pick(this.locale.data.lastNames);
|
|
137
|
+
}
|
|
138
|
+
fullName(opts = {}) {
|
|
139
|
+
const parts = [];
|
|
140
|
+
if (opts.withPrefix) parts.push(this.prefix());
|
|
141
|
+
parts.push(this.firstName(opts.sex), this.lastName());
|
|
142
|
+
if (opts.withSuffix) parts.push(this.suffix());
|
|
143
|
+
return parts.join(" ");
|
|
144
|
+
}
|
|
145
|
+
prefix() {
|
|
146
|
+
return this.rng.pick(this.locale.data.prefixes);
|
|
147
|
+
}
|
|
148
|
+
suffix() {
|
|
149
|
+
return this.rng.pick(this.locale.data.suffixes);
|
|
150
|
+
}
|
|
151
|
+
/** Returns `"male"` or `"female"`. */
|
|
152
|
+
sex() {
|
|
153
|
+
return this.rng.bool() ? "male" : "female";
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/faker/internet.ts
|
|
158
|
+
/**
|
|
159
|
+
* Internet / network namespace.
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```ts
|
|
163
|
+
* faker.internet.email() // "olivia.patel91@example.com"
|
|
164
|
+
* faker.internet.email({ firstName: 'Alice', lastName: 'Wu' }) // "alice.wu41@…"
|
|
165
|
+
* faker.internet.userName() // "alex_anderson"
|
|
166
|
+
* faker.internet.url() // "https://app.gupta.io"
|
|
167
|
+
* faker.internet.ipv4() // "172.16.42.7"
|
|
168
|
+
* faker.internet.password(12) // "K8m$pQrt2Wz!"
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
var Internet = class {
|
|
172
|
+
rng;
|
|
173
|
+
locale;
|
|
174
|
+
constructor(rng, locale) {
|
|
175
|
+
this.rng = rng;
|
|
176
|
+
this.locale = locale;
|
|
177
|
+
}
|
|
178
|
+
email(opts = {}) {
|
|
179
|
+
const first = (opts.firstName ?? this.rng.pick(this.locale.data.firstNames)).toLowerCase();
|
|
180
|
+
const last = (opts.lastName ?? this.rng.pick(this.locale.data.lastNames)).toLowerCase();
|
|
181
|
+
const suffix = this.rng.int(1, 99).toString();
|
|
182
|
+
return `${this.rng.pick([
|
|
183
|
+
`${first}.${last}`,
|
|
184
|
+
`${first}${last}`,
|
|
185
|
+
`${first}_${last}`
|
|
186
|
+
])}${suffix}@${this.rng.pick(this.locale.data.emailDomains)}`;
|
|
187
|
+
}
|
|
188
|
+
userName() {
|
|
189
|
+
const first = this.rng.pick(this.locale.data.firstNames).toLowerCase();
|
|
190
|
+
const last = this.rng.pick(this.locale.data.lastNames).toLowerCase();
|
|
191
|
+
const numeric = this.rng.int(1, 999).toString();
|
|
192
|
+
return this.rng.pick([
|
|
193
|
+
`${first}.${last}`,
|
|
194
|
+
`${first}_${last}`,
|
|
195
|
+
`${first}${numeric}`
|
|
196
|
+
]);
|
|
197
|
+
}
|
|
198
|
+
/** Bare domain (e.g. `acme.io`). */
|
|
199
|
+
domainName() {
|
|
200
|
+
return `${this.rng.pick(this.locale.data.firstNames).toLowerCase()}.${this.rng.pick(this.locale.data.tlds)}`;
|
|
201
|
+
}
|
|
202
|
+
url() {
|
|
203
|
+
return `https://${this.rng.pick([
|
|
204
|
+
"www",
|
|
205
|
+
"app",
|
|
206
|
+
"api",
|
|
207
|
+
"blog",
|
|
208
|
+
"docs"
|
|
209
|
+
])}.${this.domainName()}`;
|
|
210
|
+
}
|
|
211
|
+
ipv4() {
|
|
212
|
+
return [
|
|
213
|
+
this.rng.int(1, 255),
|
|
214
|
+
this.rng.int(0, 255),
|
|
215
|
+
this.rng.int(0, 255),
|
|
216
|
+
this.rng.int(1, 254)
|
|
217
|
+
].join(".");
|
|
218
|
+
}
|
|
219
|
+
ipv6() {
|
|
220
|
+
return Array.from({ length: 8 }, () => this.rng.int(0, 65535).toString(16).padStart(4, "0")).join(":");
|
|
221
|
+
}
|
|
222
|
+
/** Random MAC address (colon-separated). */
|
|
223
|
+
mac() {
|
|
224
|
+
return Array.from({ length: 6 }, () => this.rng.int(0, 255).toString(16).padStart(2, "0")).join(":");
|
|
225
|
+
}
|
|
226
|
+
password(length = 12) {
|
|
227
|
+
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_+=";
|
|
228
|
+
let out = "";
|
|
229
|
+
for (let i = 0; i < length; i++) {
|
|
230
|
+
const ch = chars[this.rng.int(0, 75)];
|
|
231
|
+
if (ch !== void 0) out += ch;
|
|
232
|
+
}
|
|
233
|
+
return out;
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
//#endregion
|
|
237
|
+
//#region src/faker/location.ts
|
|
238
|
+
/**
|
|
239
|
+
* Postal-address namespace.
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```ts
|
|
243
|
+
* faker.location.streetAddress() // "742 Oak Ave"
|
|
244
|
+
* faker.location.city() // "Seattle"
|
|
245
|
+
* faker.location.country() // "United States"
|
|
246
|
+
* faker.location.latitude() // 47.6062
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
var Location = class {
|
|
250
|
+
rng;
|
|
251
|
+
locale;
|
|
252
|
+
constructor(rng, locale) {
|
|
253
|
+
this.rng = rng;
|
|
254
|
+
this.locale = locale;
|
|
255
|
+
}
|
|
256
|
+
streetAddress() {
|
|
257
|
+
return `${this.rng.int(100, 9999).toString()} ${this.rng.pick(this.locale.data.streetNames)} ${this.rng.pick(this.locale.data.streetSuffixes)}`;
|
|
258
|
+
}
|
|
259
|
+
city() {
|
|
260
|
+
return this.rng.pick(this.locale.data.cities);
|
|
261
|
+
}
|
|
262
|
+
state() {
|
|
263
|
+
return this.rng.pick(this.locale.data.states);
|
|
264
|
+
}
|
|
265
|
+
zipCode() {
|
|
266
|
+
return String(this.rng.int(1e4, 99999));
|
|
267
|
+
}
|
|
268
|
+
/** Locale's primary country (e.g. `"United States"` for `en`). */
|
|
269
|
+
country() {
|
|
270
|
+
return this.locale.data.country;
|
|
271
|
+
}
|
|
272
|
+
/** Random country from the locale's broader country list. */
|
|
273
|
+
countryName() {
|
|
274
|
+
return this.rng.pick(this.locale.data.countries);
|
|
275
|
+
}
|
|
276
|
+
/** Full single-line address. */
|
|
277
|
+
fullAddress() {
|
|
278
|
+
return `${this.streetAddress()}, ${this.city()}, ${this.state()} ${this.zipCode()}`;
|
|
279
|
+
}
|
|
280
|
+
latitude(min = -90, max = 90) {
|
|
281
|
+
return this.rng.float(min, max, 4);
|
|
282
|
+
}
|
|
283
|
+
longitude(min = -180, max = 180) {
|
|
284
|
+
return this.rng.float(min, max, 4);
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region src/faker/lorem.ts
|
|
289
|
+
/** Capitalise the first character of a string. */
|
|
290
|
+
function capitalize(s) {
|
|
291
|
+
const first = s[0];
|
|
292
|
+
return first === void 0 ? s : first.toUpperCase() + s.slice(1);
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Lorem-ipsum text generator.
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* ```ts
|
|
299
|
+
* faker.lorem.word() // "consectetur"
|
|
300
|
+
* faker.lorem.words(3) // "dolor sit amet"
|
|
301
|
+
* faker.lorem.sentence() // "Ut labore et dolore magna aliqua."
|
|
302
|
+
* faker.lorem.paragraph()
|
|
303
|
+
* faker.lorem.paragraphs(3)
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
var Lorem = class {
|
|
307
|
+
rng;
|
|
308
|
+
locale;
|
|
309
|
+
constructor(rng, locale) {
|
|
310
|
+
this.rng = rng;
|
|
311
|
+
this.locale = locale;
|
|
312
|
+
}
|
|
313
|
+
word() {
|
|
314
|
+
return this.rng.pick(this.locale.data.loremWords);
|
|
315
|
+
}
|
|
316
|
+
words(count = 3) {
|
|
317
|
+
return Array.from({ length: count }, () => this.word()).join(" ");
|
|
318
|
+
}
|
|
319
|
+
sentence(wordCount) {
|
|
320
|
+
const count = wordCount ?? this.rng.int(4, 12);
|
|
321
|
+
return capitalize(this.words(count)) + ".";
|
|
322
|
+
}
|
|
323
|
+
paragraph(sentenceCount) {
|
|
324
|
+
const count = sentenceCount ?? this.rng.int(3, 6);
|
|
325
|
+
return Array.from({ length: count }, () => this.sentence()).join(" ");
|
|
326
|
+
}
|
|
327
|
+
paragraphs(count = 3) {
|
|
328
|
+
return Array.from({ length: count }, () => this.paragraph()).join("\n\n");
|
|
329
|
+
}
|
|
330
|
+
/** Alias of `paragraph()` — matches faker.js. */
|
|
331
|
+
text() {
|
|
332
|
+
return this.paragraph();
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
//#endregion
|
|
336
|
+
//#region src/faker/date.ts
|
|
337
|
+
var DAY_MS = 864e5;
|
|
338
|
+
/**
|
|
339
|
+
* Date / time generators.
|
|
340
|
+
*
|
|
341
|
+
* @example
|
|
342
|
+
* ```ts
|
|
343
|
+
* faker.date.past() // a Date in the last 365 days
|
|
344
|
+
* faker.date.recent(30) // last 30 days
|
|
345
|
+
* faker.date.future(60) // next 60 days
|
|
346
|
+
* faker.date.between(a, b)
|
|
347
|
+
* faker.date.birthdate({ min: 18, max: 65 })
|
|
348
|
+
* ```
|
|
349
|
+
*/
|
|
350
|
+
var DateGen = class {
|
|
351
|
+
rng;
|
|
352
|
+
constructor(rng) {
|
|
353
|
+
this.rng = rng;
|
|
354
|
+
}
|
|
355
|
+
past(days = 365) {
|
|
356
|
+
const now = Date.now();
|
|
357
|
+
return new Date(this.rng.int(now - days * DAY_MS, now - 1));
|
|
358
|
+
}
|
|
359
|
+
recent(days = 30) {
|
|
360
|
+
return this.past(days);
|
|
361
|
+
}
|
|
362
|
+
future(days = 30) {
|
|
363
|
+
const now = Date.now();
|
|
364
|
+
return new Date(this.rng.int(now + 1, now + days * DAY_MS));
|
|
365
|
+
}
|
|
366
|
+
soon(days = 7) {
|
|
367
|
+
return this.future(days);
|
|
368
|
+
}
|
|
369
|
+
between(from, to) {
|
|
370
|
+
const a = from.getTime();
|
|
371
|
+
const b = to.getTime();
|
|
372
|
+
return new Date(this.rng.int(Math.min(a, b), Math.max(a, b)));
|
|
373
|
+
}
|
|
374
|
+
/** ISO-8601 string of a random recent date. */
|
|
375
|
+
iso(days = 365) {
|
|
376
|
+
return this.past(days).toISOString();
|
|
377
|
+
}
|
|
378
|
+
/** A plausible birthdate for someone in `[min, max]` years old. */
|
|
379
|
+
birthdate(opts = {}) {
|
|
380
|
+
const min = opts.min ?? 18;
|
|
381
|
+
const max = opts.max ?? 80;
|
|
382
|
+
const now = Date.now();
|
|
383
|
+
const minTime = now - max * 365 * DAY_MS;
|
|
384
|
+
const maxTime = now - min * 365 * DAY_MS;
|
|
385
|
+
return new Date(this.rng.int(minTime, maxTime));
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
//#endregion
|
|
389
|
+
//#region src/faker/number.ts
|
|
390
|
+
/**
|
|
391
|
+
* Number generators.
|
|
392
|
+
*
|
|
393
|
+
* @example
|
|
394
|
+
* ```ts
|
|
395
|
+
* faker.number.int({ min: 1, max: 100 })
|
|
396
|
+
* faker.number.float({ min: 0, max: 1, decimals: 3 })
|
|
397
|
+
* faker.number.bigInt({ min: 0n, max: 1000n })
|
|
398
|
+
* faker.number.between(1, 5)
|
|
399
|
+
* ```
|
|
400
|
+
*/
|
|
401
|
+
var NumberGen = class {
|
|
402
|
+
rng;
|
|
403
|
+
constructor(rng) {
|
|
404
|
+
this.rng = rng;
|
|
405
|
+
}
|
|
406
|
+
int(opts = {}) {
|
|
407
|
+
return this.rng.int(opts.min ?? 0, opts.max ?? Number.MAX_SAFE_INTEGER);
|
|
408
|
+
}
|
|
409
|
+
float(opts = {}) {
|
|
410
|
+
return this.rng.float(opts.min ?? 0, opts.max ?? 1, opts.decimals ?? 2);
|
|
411
|
+
}
|
|
412
|
+
bigInt(opts = {}) {
|
|
413
|
+
const min = opts.min ?? 0n;
|
|
414
|
+
const max = opts.max ?? 1000000000n;
|
|
415
|
+
if (max < min) throw new Error("[Number] bigInt: max < min");
|
|
416
|
+
const range = max - min + 1n;
|
|
417
|
+
const lo = BigInt(this.rng.int(0, 4294967295));
|
|
418
|
+
return min + (BigInt(this.rng.int(0, 4294967295)) << 32n | lo) % range;
|
|
419
|
+
}
|
|
420
|
+
/** Convenience: integer in `[min, max]`. */
|
|
421
|
+
between(min, max) {
|
|
422
|
+
return this.rng.int(min, max);
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
//#endregion
|
|
426
|
+
//#region src/faker/string.ts
|
|
427
|
+
var ALPHA = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
428
|
+
var NUMERIC = "0123456789";
|
|
429
|
+
var ALPHANUMERIC = ALPHA + NUMERIC;
|
|
430
|
+
var HEX = "0123456789abcdef";
|
|
431
|
+
var NANOID = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
|
|
432
|
+
/**
|
|
433
|
+
* String / identifier generators.
|
|
434
|
+
*
|
|
435
|
+
* @example
|
|
436
|
+
* ```ts
|
|
437
|
+
* faker.string.uuid() // "f47ac10b-58cc-4372-a567-0e02b2c3d479"
|
|
438
|
+
* faker.string.nanoid()
|
|
439
|
+
* faker.string.alphanumeric(8)
|
|
440
|
+
* faker.string.hexadecimal(16)
|
|
441
|
+
* faker.string.sample(20) // any printable char
|
|
442
|
+
* faker.string.slug() // "dolor-sit-amet"
|
|
443
|
+
* ```
|
|
444
|
+
*/
|
|
445
|
+
var StringGen = class {
|
|
446
|
+
rng;
|
|
447
|
+
constructor(rng) {
|
|
448
|
+
this.rng = rng;
|
|
449
|
+
}
|
|
450
|
+
/** RFC-4122 v4 UUID. */
|
|
451
|
+
uuid() {
|
|
452
|
+
const bytes = Array.from({ length: 16 }, () => this.rng.int(0, 255));
|
|
453
|
+
bytes[6] = (bytes[6] ?? 0) & 15 | 64;
|
|
454
|
+
bytes[8] = (bytes[8] ?? 0) & 63 | 128;
|
|
455
|
+
const hex = bytes.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
456
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
|
|
457
|
+
}
|
|
458
|
+
/** URL-safe random ID — same alphabet as nanoid. */
|
|
459
|
+
nanoid(length = 21) {
|
|
460
|
+
return this.pickFrom(NANOID, length);
|
|
461
|
+
}
|
|
462
|
+
alpha(length = 10) {
|
|
463
|
+
return this.pickFrom(ALPHA, length);
|
|
464
|
+
}
|
|
465
|
+
numeric(length = 10) {
|
|
466
|
+
return this.pickFrom(NUMERIC, length);
|
|
467
|
+
}
|
|
468
|
+
alphanumeric(length = 10) {
|
|
469
|
+
return this.pickFrom(ALPHANUMERIC, length);
|
|
470
|
+
}
|
|
471
|
+
hexadecimal(length = 8, opts = {}) {
|
|
472
|
+
return (opts.prefix ?? "") + this.pickFrom(HEX, length);
|
|
473
|
+
}
|
|
474
|
+
/** Random printable ASCII (32–126), any character. */
|
|
475
|
+
sample(length = 10) {
|
|
476
|
+
let out = "";
|
|
477
|
+
for (let i = 0; i < length; i++) out += String.fromCharCode(this.rng.int(33, 126));
|
|
478
|
+
return out;
|
|
479
|
+
}
|
|
480
|
+
/** Lowercase, hyphen-joined word sequence. */
|
|
481
|
+
slug(words = 3, dictionary) {
|
|
482
|
+
const pool = dictionary ?? DEFAULT_SLUG_WORDS;
|
|
483
|
+
return Array.from({ length: words }, () => this.rng.pick(pool)).join("-");
|
|
484
|
+
}
|
|
485
|
+
pickFrom(pool, length) {
|
|
486
|
+
let out = "";
|
|
487
|
+
for (let i = 0; i < length; i++) {
|
|
488
|
+
const ch = pool[this.rng.int(0, pool.length - 1)];
|
|
489
|
+
if (ch !== void 0) out += ch;
|
|
490
|
+
}
|
|
491
|
+
return out;
|
|
492
|
+
}
|
|
493
|
+
};
|
|
494
|
+
var DEFAULT_SLUG_WORDS = [
|
|
495
|
+
"amber",
|
|
496
|
+
"azure",
|
|
497
|
+
"cedar",
|
|
498
|
+
"cobalt",
|
|
499
|
+
"coral",
|
|
500
|
+
"dawn",
|
|
501
|
+
"ember",
|
|
502
|
+
"fern",
|
|
503
|
+
"frost",
|
|
504
|
+
"glass",
|
|
505
|
+
"haven",
|
|
506
|
+
"iris",
|
|
507
|
+
"jade",
|
|
508
|
+
"lake",
|
|
509
|
+
"maple",
|
|
510
|
+
"meadow",
|
|
511
|
+
"nova",
|
|
512
|
+
"opal",
|
|
513
|
+
"pine",
|
|
514
|
+
"quartz",
|
|
515
|
+
"river",
|
|
516
|
+
"sage",
|
|
517
|
+
"silk",
|
|
518
|
+
"stone",
|
|
519
|
+
"tide",
|
|
520
|
+
"umber",
|
|
521
|
+
"velvet",
|
|
522
|
+
"wave",
|
|
523
|
+
"xeno",
|
|
524
|
+
"yarn",
|
|
525
|
+
"zenith"
|
|
526
|
+
];
|
|
527
|
+
//#endregion
|
|
528
|
+
//#region src/faker/color.ts
|
|
529
|
+
/**
|
|
530
|
+
* Color generators.
|
|
531
|
+
*
|
|
532
|
+
* @example
|
|
533
|
+
* ```ts
|
|
534
|
+
* faker.color.name() // "amber"
|
|
535
|
+
* faker.color.hex() // "#3f8ad5"
|
|
536
|
+
* faker.color.rgb() // "rgb(63, 138, 213)"
|
|
537
|
+
* faker.color.hsl() // "hsl(217, 64%, 54%)"
|
|
538
|
+
* ```
|
|
539
|
+
*/
|
|
540
|
+
var Color = class {
|
|
541
|
+
rng;
|
|
542
|
+
locale;
|
|
543
|
+
constructor(rng, locale) {
|
|
544
|
+
this.rng = rng;
|
|
545
|
+
this.locale = locale;
|
|
546
|
+
}
|
|
547
|
+
name() {
|
|
548
|
+
return this.rng.pick(this.locale.data.colors);
|
|
549
|
+
}
|
|
550
|
+
hex() {
|
|
551
|
+
return "#" + this.rng.int(0, 16777215).toString(16).padStart(6, "0");
|
|
552
|
+
}
|
|
553
|
+
rgb() {
|
|
554
|
+
return `rgb(${this.rng.int(0, 255).toString()}, ${this.rng.int(0, 255).toString()}, ${this.rng.int(0, 255).toString()})`;
|
|
555
|
+
}
|
|
556
|
+
hsl() {
|
|
557
|
+
return `hsl(${this.rng.int(0, 360).toString()}, ${this.rng.int(40, 90).toString()}%, ${this.rng.int(30, 70).toString()}%)`;
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
//#endregion
|
|
561
|
+
//#region src/faker/company.ts
|
|
562
|
+
/**
|
|
563
|
+
* Company / employment generators.
|
|
564
|
+
*
|
|
565
|
+
* @example
|
|
566
|
+
* ```ts
|
|
567
|
+
* faker.company.name() // "Stark Industries"
|
|
568
|
+
* faker.company.jobTitle() // "Frontend Developer"
|
|
569
|
+
* faker.company.buzzPhrase() // "leverage cross-platform synergies"
|
|
570
|
+
* ```
|
|
571
|
+
*/
|
|
572
|
+
var Company = class {
|
|
573
|
+
rng;
|
|
574
|
+
locale;
|
|
575
|
+
constructor(rng, locale) {
|
|
576
|
+
this.rng = rng;
|
|
577
|
+
this.locale = locale;
|
|
578
|
+
}
|
|
579
|
+
name() {
|
|
580
|
+
return this.rng.pick(this.locale.data.companies);
|
|
581
|
+
}
|
|
582
|
+
jobTitle() {
|
|
583
|
+
return this.rng.pick(this.locale.data.jobTitles);
|
|
584
|
+
}
|
|
585
|
+
buzzPhrase() {
|
|
586
|
+
return this.rng.pick(this.locale.data.buzzPhrases);
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
//#endregion
|
|
590
|
+
//#region src/faker/commerce.ts
|
|
591
|
+
/**
|
|
592
|
+
* Commerce generators.
|
|
593
|
+
*
|
|
594
|
+
* @example
|
|
595
|
+
* ```ts
|
|
596
|
+
* faker.commerce.productName() // "Bamboo Notebook"
|
|
597
|
+
* faker.commerce.price() // 24.99
|
|
598
|
+
* faker.commerce.department() // "Electronics"
|
|
599
|
+
* ```
|
|
600
|
+
*/
|
|
601
|
+
var Commerce = class {
|
|
602
|
+
rng;
|
|
603
|
+
locale;
|
|
604
|
+
constructor(rng, locale) {
|
|
605
|
+
this.rng = rng;
|
|
606
|
+
this.locale = locale;
|
|
607
|
+
}
|
|
608
|
+
productName() {
|
|
609
|
+
return this.rng.pick(this.locale.data.productNames);
|
|
610
|
+
}
|
|
611
|
+
department() {
|
|
612
|
+
return this.rng.pick(this.locale.data.departments);
|
|
613
|
+
}
|
|
614
|
+
price(min = 1, max = 1e3, decimals = 2) {
|
|
615
|
+
return this.rng.float(min, max, decimals);
|
|
616
|
+
}
|
|
617
|
+
productDescription() {
|
|
618
|
+
return `${this.rng.pick([
|
|
619
|
+
"Premium",
|
|
620
|
+
"Eco-friendly",
|
|
621
|
+
"Hand-crafted",
|
|
622
|
+
"Vintage",
|
|
623
|
+
"Modern"
|
|
624
|
+
])} ${this.productName().toLowerCase()} designed for everyday use.`;
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
//#endregion
|
|
628
|
+
//#region src/faker/finance.ts
|
|
629
|
+
/**
|
|
630
|
+
* Finance generators.
|
|
631
|
+
*
|
|
632
|
+
* @example
|
|
633
|
+
* ```ts
|
|
634
|
+
* faker.finance.amount() // "327.41"
|
|
635
|
+
* faker.finance.amount(0, 10, 2, '$') // "$4.27"
|
|
636
|
+
* faker.finance.accountNumber()
|
|
637
|
+
* faker.finance.creditCardNumber() // 16-digit Luhn-valid number
|
|
638
|
+
* faker.finance.currencyCode()
|
|
639
|
+
* faker.finance.iban()
|
|
640
|
+
* ```
|
|
641
|
+
*/
|
|
642
|
+
var Finance = class {
|
|
643
|
+
rng;
|
|
644
|
+
constructor(rng) {
|
|
645
|
+
this.rng = rng;
|
|
646
|
+
}
|
|
647
|
+
amount(min = 0, max = 1e3, decimals = 2, symbol = "") {
|
|
648
|
+
return symbol + this.rng.float(min, max, decimals).toFixed(decimals);
|
|
649
|
+
}
|
|
650
|
+
accountNumber(digits = 10) {
|
|
651
|
+
let out = "";
|
|
652
|
+
for (let i = 0; i < digits; i++) out += this.rng.int(0, 9).toString();
|
|
653
|
+
return out;
|
|
654
|
+
}
|
|
655
|
+
/** Generates a Luhn-valid 16-digit credit-card number. */
|
|
656
|
+
creditCardNumber() {
|
|
657
|
+
const digits = [];
|
|
658
|
+
for (let i = 0; i < 15; i++) digits.push(this.rng.int(0, 9));
|
|
659
|
+
let sum = 0;
|
|
660
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
661
|
+
const raw = digits[i];
|
|
662
|
+
if (raw === void 0) continue;
|
|
663
|
+
let d = raw;
|
|
664
|
+
if ((digits.length - i) % 2 === 1) {
|
|
665
|
+
d *= 2;
|
|
666
|
+
if (d > 9) d -= 9;
|
|
667
|
+
}
|
|
668
|
+
sum += d;
|
|
669
|
+
}
|
|
670
|
+
digits.push((10 - sum % 10) % 10);
|
|
671
|
+
return digits.join("");
|
|
672
|
+
}
|
|
673
|
+
currencyCode() {
|
|
674
|
+
return this.rng.pick(CURRENCY_CODES);
|
|
675
|
+
}
|
|
676
|
+
iban(countryCode = "GB", length = 22) {
|
|
677
|
+
let body = "";
|
|
678
|
+
for (let i = 0; i < length - 4; i++) body += this.rng.int(0, 9).toString();
|
|
679
|
+
return `${countryCode}${this.rng.int(10, 99).toString()}${body}`;
|
|
680
|
+
}
|
|
681
|
+
bitcoinAddress() {
|
|
682
|
+
const chars = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz123456789";
|
|
683
|
+
let out = this.rng.pick(["1", "3"]);
|
|
684
|
+
const length = this.rng.int(25, 33);
|
|
685
|
+
for (let i = 1; i < length; i++) {
|
|
686
|
+
const ch = chars[this.rng.int(0, 57)];
|
|
687
|
+
if (ch !== void 0) out += ch;
|
|
688
|
+
}
|
|
689
|
+
return out;
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
var CURRENCY_CODES = [
|
|
693
|
+
"USD",
|
|
694
|
+
"EUR",
|
|
695
|
+
"GBP",
|
|
696
|
+
"JPY",
|
|
697
|
+
"CHF",
|
|
698
|
+
"CAD",
|
|
699
|
+
"AUD",
|
|
700
|
+
"CNY",
|
|
701
|
+
"INR",
|
|
702
|
+
"NPR",
|
|
703
|
+
"BRL",
|
|
704
|
+
"MXN",
|
|
705
|
+
"SGD",
|
|
706
|
+
"HKD",
|
|
707
|
+
"KRW"
|
|
708
|
+
];
|
|
709
|
+
//#endregion
|
|
710
|
+
//#region src/faker/image.ts
|
|
711
|
+
/**
|
|
712
|
+
* Image-URL generators. No bytes are produced — just predictable URLs that
|
|
713
|
+
* resolve to real images from public providers.
|
|
714
|
+
*
|
|
715
|
+
* @example
|
|
716
|
+
* ```ts
|
|
717
|
+
* faker.image.url() // picsum.photos URL
|
|
718
|
+
* faker.image.avatar() // ui-avatars URL
|
|
719
|
+
* faker.image.dataUri(64, 64) // tiny embeddable PNG
|
|
720
|
+
* ```
|
|
721
|
+
*/
|
|
722
|
+
var Image = class {
|
|
723
|
+
rng;
|
|
724
|
+
constructor(rng) {
|
|
725
|
+
this.rng = rng;
|
|
726
|
+
}
|
|
727
|
+
/** Picsum-photos placeholder URL. */
|
|
728
|
+
url(width = 640, height = 480) {
|
|
729
|
+
const random = this.rng.int(1, 1e4).toString();
|
|
730
|
+
return `https://picsum.photos/${width.toString()}/${height.toString()}?random=${random}`;
|
|
731
|
+
}
|
|
732
|
+
/** ui-avatars.com avatar URL — needs a name to render initials. */
|
|
733
|
+
avatar(name = "User") {
|
|
734
|
+
return `https://ui-avatars.com/api/?${new URLSearchParams({
|
|
735
|
+
name,
|
|
736
|
+
size: String(this.rng.pick([
|
|
737
|
+
64,
|
|
738
|
+
96,
|
|
739
|
+
128,
|
|
740
|
+
256
|
|
741
|
+
])),
|
|
742
|
+
background: this.rng.int(0, 16777215).toString(16).padStart(6, "0"),
|
|
743
|
+
color: "fff"
|
|
744
|
+
}).toString()}`;
|
|
745
|
+
}
|
|
746
|
+
/** Tiny single-color PNG data-uri — useful for testing inline-image flows. */
|
|
747
|
+
dataUri(width = 1, height = 1) {
|
|
748
|
+
return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=";
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
//#endregion
|
|
752
|
+
//#region src/faker/system.ts
|
|
753
|
+
/**
|
|
754
|
+
* Filesystem / operating-system generators.
|
|
755
|
+
*
|
|
756
|
+
* @example
|
|
757
|
+
* ```ts
|
|
758
|
+
* faker.system.fileName() // "amber-cedar-pine.json"
|
|
759
|
+
* faker.system.commonFileExt() // "pdf"
|
|
760
|
+
* faker.system.mimeType() // "image/png"
|
|
761
|
+
* faker.system.filePath() // "/var/log/glass-stone.txt"
|
|
762
|
+
* ```
|
|
763
|
+
*/
|
|
764
|
+
var System = class {
|
|
765
|
+
rng;
|
|
766
|
+
locale;
|
|
767
|
+
strings;
|
|
768
|
+
constructor(rng, locale, strings) {
|
|
769
|
+
this.rng = rng;
|
|
770
|
+
this.locale = locale;
|
|
771
|
+
this.strings = strings;
|
|
772
|
+
}
|
|
773
|
+
commonFileExt() {
|
|
774
|
+
return this.rng.pick(this.locale.data.fileExtensions);
|
|
775
|
+
}
|
|
776
|
+
fileExt() {
|
|
777
|
+
return this.rng.pick(this.locale.data.fileExtensions);
|
|
778
|
+
}
|
|
779
|
+
fileName(opts = {}) {
|
|
780
|
+
const base = this.strings.slug(this.rng.int(2, 4));
|
|
781
|
+
return opts.withExt === false ? base : `${base}.${this.commonFileExt()}`;
|
|
782
|
+
}
|
|
783
|
+
directoryPath() {
|
|
784
|
+
const depth = this.rng.int(1, 4);
|
|
785
|
+
return "/" + Array.from({ length: depth }, () => this.strings.slug(1)).join("/");
|
|
786
|
+
}
|
|
787
|
+
filePath() {
|
|
788
|
+
return `${this.directoryPath()}/${this.fileName()}`;
|
|
789
|
+
}
|
|
790
|
+
mimeType() {
|
|
791
|
+
return this.rng.pick(this.locale.data.mimeTypes);
|
|
792
|
+
}
|
|
793
|
+
semver() {
|
|
794
|
+
return [
|
|
795
|
+
this.rng.int(0, 10),
|
|
796
|
+
this.rng.int(0, 20),
|
|
797
|
+
this.rng.int(0, 100)
|
|
798
|
+
].join(".");
|
|
799
|
+
}
|
|
800
|
+
};
|
|
801
|
+
//#endregion
|
|
802
|
+
//#region src/faker/datatype.ts
|
|
803
|
+
/**
|
|
804
|
+
* Primitive datatype generators.
|
|
805
|
+
*
|
|
806
|
+
* @example
|
|
807
|
+
* ```ts
|
|
808
|
+
* faker.datatype.boolean() // true or false
|
|
809
|
+
* faker.datatype.boolean(0.8) // true with 80% probability
|
|
810
|
+
* ```
|
|
811
|
+
*/
|
|
812
|
+
var Datatype = class {
|
|
813
|
+
rng;
|
|
814
|
+
constructor(rng) {
|
|
815
|
+
this.rng = rng;
|
|
816
|
+
}
|
|
817
|
+
/** Boolean with probability `chance` of `true` (default 0.5). */
|
|
818
|
+
boolean(chance = .5) {
|
|
819
|
+
return this.rng.bool(chance);
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
//#endregion
|
|
823
|
+
//#region src/faker/regex.ts
|
|
824
|
+
/**
|
|
825
|
+
* Generate a sample string that matches the given regular-expression pattern.
|
|
826
|
+
*
|
|
827
|
+
* Supports the regex subset commonly used in test data:
|
|
828
|
+
* - Literals, dot, escaped characters
|
|
829
|
+
* - Character classes `[a-z]`, `[^…]`, `\d`, `\D`, `\w`, `\W`, `\s`, `\S`
|
|
830
|
+
* - Groups `(...)`, non-capturing `(?:...)`, alternation `a|b|c`
|
|
831
|
+
* - Quantifiers `*`, `+`, `?`, `{n}`, `{n,m}` (lazy `?` is ignored)
|
|
832
|
+
*
|
|
833
|
+
* Unsupported regex features (lookbehind/lookahead, backreferences,
|
|
834
|
+
* named groups) are silently treated as literals.
|
|
835
|
+
*
|
|
836
|
+
* @example
|
|
837
|
+
* ```ts
|
|
838
|
+
* generateFromRegex(/[A-Z]{3}-\d{4}/, prng) // "ZQX-4172"
|
|
839
|
+
* ```
|
|
840
|
+
*/
|
|
841
|
+
function generateFromRegex(pattern, rng) {
|
|
842
|
+
return render(new RegexParser(pattern instanceof RegExp ? pattern.source : pattern).parse(), rng);
|
|
843
|
+
}
|
|
844
|
+
function charRange(startCode, endCode) {
|
|
845
|
+
const out = [];
|
|
846
|
+
for (let c = startCode; c <= endCode; c++) out.push(String.fromCharCode(c));
|
|
847
|
+
return out;
|
|
848
|
+
}
|
|
849
|
+
var D = charRange(48, 57);
|
|
850
|
+
var L = charRange(97, 122);
|
|
851
|
+
var U = charRange(65, 90);
|
|
852
|
+
var W = [
|
|
853
|
+
...D,
|
|
854
|
+
...L,
|
|
855
|
+
...U,
|
|
856
|
+
"_"
|
|
857
|
+
];
|
|
858
|
+
var S = [" ", " "];
|
|
859
|
+
var NW = [
|
|
860
|
+
" ",
|
|
861
|
+
"!",
|
|
862
|
+
"@",
|
|
863
|
+
"#",
|
|
864
|
+
"$",
|
|
865
|
+
"%",
|
|
866
|
+
"&",
|
|
867
|
+
"*",
|
|
868
|
+
"-",
|
|
869
|
+
"+",
|
|
870
|
+
"=",
|
|
871
|
+
";",
|
|
872
|
+
":",
|
|
873
|
+
",",
|
|
874
|
+
".",
|
|
875
|
+
"/",
|
|
876
|
+
"?"
|
|
877
|
+
];
|
|
878
|
+
var ALL = [
|
|
879
|
+
...W,
|
|
880
|
+
...S,
|
|
881
|
+
"!",
|
|
882
|
+
"@",
|
|
883
|
+
"#",
|
|
884
|
+
"$",
|
|
885
|
+
"%",
|
|
886
|
+
"^",
|
|
887
|
+
"&",
|
|
888
|
+
"*",
|
|
889
|
+
"(",
|
|
890
|
+
")",
|
|
891
|
+
"-",
|
|
892
|
+
"+"
|
|
893
|
+
];
|
|
894
|
+
function expandEscape(ch) {
|
|
895
|
+
switch (ch) {
|
|
896
|
+
case "d": return [...D];
|
|
897
|
+
case "D": return [
|
|
898
|
+
...L,
|
|
899
|
+
...U,
|
|
900
|
+
"_",
|
|
901
|
+
" "
|
|
902
|
+
];
|
|
903
|
+
case "w": return [...W];
|
|
904
|
+
case "W": return [...NW];
|
|
905
|
+
case "s": return [...S];
|
|
906
|
+
case "S": return [...W, ...NW];
|
|
907
|
+
case "n": return ["\n"];
|
|
908
|
+
case "t": return [" "];
|
|
909
|
+
case "r": return ["\r"];
|
|
910
|
+
default: return [ch];
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
var RegexParser = class {
|
|
914
|
+
src;
|
|
915
|
+
pos = 0;
|
|
916
|
+
constructor(src) {
|
|
917
|
+
this.src = src;
|
|
918
|
+
}
|
|
919
|
+
parse() {
|
|
920
|
+
return this.parseAlt();
|
|
921
|
+
}
|
|
922
|
+
peek() {
|
|
923
|
+
return this.src[this.pos];
|
|
924
|
+
}
|
|
925
|
+
parseAlt() {
|
|
926
|
+
const branches = [this.parseSeq()];
|
|
927
|
+
while (this.peek() === "|") {
|
|
928
|
+
this.pos++;
|
|
929
|
+
branches.push(this.parseSeq());
|
|
930
|
+
}
|
|
931
|
+
if (branches.length === 1) {
|
|
932
|
+
const only = branches[0];
|
|
933
|
+
if (only === void 0) throw new Error("[regex] unreachable: empty branches");
|
|
934
|
+
return only;
|
|
935
|
+
}
|
|
936
|
+
return {
|
|
937
|
+
kind: "alt",
|
|
938
|
+
branches
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
parseSeq() {
|
|
942
|
+
const items = [];
|
|
943
|
+
while (this.pos < this.src.length && this.peek() !== ")" && this.peek() !== "|") {
|
|
944
|
+
const node = this.parseAtom();
|
|
945
|
+
const q = this.parseQuant();
|
|
946
|
+
items.push({
|
|
947
|
+
node,
|
|
948
|
+
min: q.min,
|
|
949
|
+
max: q.max
|
|
950
|
+
});
|
|
951
|
+
if (this.peek() === "?") this.pos++;
|
|
952
|
+
}
|
|
953
|
+
return {
|
|
954
|
+
kind: "seq",
|
|
955
|
+
items
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
parseAtom() {
|
|
959
|
+
const ch = this.peek();
|
|
960
|
+
if (ch === "(") {
|
|
961
|
+
this.pos++;
|
|
962
|
+
if (this.peek() === "?") {
|
|
963
|
+
const colon = this.src.indexOf(":", this.pos);
|
|
964
|
+
if (colon !== -1) this.pos = colon + 1;
|
|
965
|
+
}
|
|
966
|
+
const inner = this.parseAlt();
|
|
967
|
+
if (this.peek() === ")") this.pos++;
|
|
968
|
+
return inner;
|
|
969
|
+
}
|
|
970
|
+
if (ch === "[") {
|
|
971
|
+
this.pos++;
|
|
972
|
+
return {
|
|
973
|
+
kind: "class",
|
|
974
|
+
pool: this.parseCharClass()
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
if (ch === ".") {
|
|
978
|
+
this.pos++;
|
|
979
|
+
return { kind: "dot" };
|
|
980
|
+
}
|
|
981
|
+
if (ch === "^" || ch === "$") {
|
|
982
|
+
this.pos++;
|
|
983
|
+
return {
|
|
984
|
+
kind: "lit",
|
|
985
|
+
value: ""
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
if (ch === "\\") {
|
|
989
|
+
this.pos++;
|
|
990
|
+
return {
|
|
991
|
+
kind: "class",
|
|
992
|
+
pool: expandEscape(this.src[this.pos++] ?? "")
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
this.pos++;
|
|
996
|
+
return {
|
|
997
|
+
kind: "lit",
|
|
998
|
+
value: ch ?? ""
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
parseCharClass() {
|
|
1002
|
+
let negate = false;
|
|
1003
|
+
if (this.peek() === "^") {
|
|
1004
|
+
negate = true;
|
|
1005
|
+
this.pos++;
|
|
1006
|
+
}
|
|
1007
|
+
const pool = [];
|
|
1008
|
+
while (this.pos < this.src.length && this.peek() !== "]") if (this.peek() === "\\") {
|
|
1009
|
+
this.pos++;
|
|
1010
|
+
pool.push(...expandEscape(this.src[this.pos++] ?? ""));
|
|
1011
|
+
} else if (this.src[this.pos + 1] === "-" && this.src[this.pos + 2] && this.src[this.pos + 2] !== "]") {
|
|
1012
|
+
const fromCh = this.src[this.pos];
|
|
1013
|
+
const toCh = this.src[this.pos + 2];
|
|
1014
|
+
if (fromCh !== void 0 && toCh !== void 0) {
|
|
1015
|
+
const from = fromCh.charCodeAt(0);
|
|
1016
|
+
const to = toCh.charCodeAt(0);
|
|
1017
|
+
for (let c = from; c <= to; c++) pool.push(String.fromCharCode(c));
|
|
1018
|
+
}
|
|
1019
|
+
this.pos += 3;
|
|
1020
|
+
} else {
|
|
1021
|
+
const ch = this.src[this.pos++];
|
|
1022
|
+
if (ch !== void 0) pool.push(ch);
|
|
1023
|
+
}
|
|
1024
|
+
if (this.peek() === "]") this.pos++;
|
|
1025
|
+
if (negate) {
|
|
1026
|
+
const set = new Set(pool);
|
|
1027
|
+
return ALL.filter((c) => !set.has(c));
|
|
1028
|
+
}
|
|
1029
|
+
return pool.length > 0 ? pool : ["a"];
|
|
1030
|
+
}
|
|
1031
|
+
parseQuant() {
|
|
1032
|
+
const ch = this.peek();
|
|
1033
|
+
if (ch === "*") {
|
|
1034
|
+
this.pos++;
|
|
1035
|
+
return {
|
|
1036
|
+
min: 0,
|
|
1037
|
+
max: 8
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
if (ch === "+") {
|
|
1041
|
+
this.pos++;
|
|
1042
|
+
return {
|
|
1043
|
+
min: 1,
|
|
1044
|
+
max: 8
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
if (ch === "?") {
|
|
1048
|
+
this.pos++;
|
|
1049
|
+
return {
|
|
1050
|
+
min: 0,
|
|
1051
|
+
max: 1
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
if (ch === "{") {
|
|
1055
|
+
const end = this.src.indexOf("}", this.pos);
|
|
1056
|
+
if (end !== -1) {
|
|
1057
|
+
const inner = this.src.slice(this.pos + 1, end);
|
|
1058
|
+
this.pos = end + 1;
|
|
1059
|
+
if (this.peek() === "?") this.pos++;
|
|
1060
|
+
const parts = inner.split(",");
|
|
1061
|
+
const lo = parseInt(parts[0] ?? "1", 10);
|
|
1062
|
+
const hi = parts.length > 1 ? parts[1] ? parseInt(parts[1], 10) : lo + 4 : lo;
|
|
1063
|
+
return {
|
|
1064
|
+
min: lo,
|
|
1065
|
+
max: Math.min(hi, lo + 10)
|
|
1066
|
+
};
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
return {
|
|
1070
|
+
min: 1,
|
|
1071
|
+
max: 1
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
function render(node, rng) {
|
|
1076
|
+
switch (node.kind) {
|
|
1077
|
+
case "lit": return node.value;
|
|
1078
|
+
case "class": return node.pool.length > 0 ? rng.pick(node.pool) : "";
|
|
1079
|
+
case "dot": return rng.pick([...W, " "]);
|
|
1080
|
+
case "seq": {
|
|
1081
|
+
let out = "";
|
|
1082
|
+
for (const item of node.items) {
|
|
1083
|
+
const count = rng.int(item.min, item.max);
|
|
1084
|
+
for (let i = 0; i < count; i++) out += render(item.node, rng);
|
|
1085
|
+
}
|
|
1086
|
+
return out;
|
|
1087
|
+
}
|
|
1088
|
+
case "alt": return render(rng.pick(node.branches), rng);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
//#endregion
|
|
1092
|
+
//#region src/faker/helpers.ts
|
|
1093
|
+
/**
|
|
1094
|
+
* General helpers — operate on arbitrary inputs, not tied to any locale or
|
|
1095
|
+
* faker namespace.
|
|
1096
|
+
*
|
|
1097
|
+
* @example
|
|
1098
|
+
* ```ts
|
|
1099
|
+
* faker.helpers.arrayElement([1, 2, 3]) // 2
|
|
1100
|
+
* faker.helpers.arrayElements([1, 2, 3, 4], 2) // [3, 1]
|
|
1101
|
+
* faker.helpers.shuffle([1, 2, 3]) // [2, 3, 1]
|
|
1102
|
+
* faker.helpers.weightedArrayElement([
|
|
1103
|
+
* { value: 'rare', weight: 1 },
|
|
1104
|
+
* { value: 'common', weight: 9 },
|
|
1105
|
+
* ])
|
|
1106
|
+
* faker.helpers.fromRegExp(/[A-Z]{3}\d{4}/) // "PWB7401"
|
|
1107
|
+
* faker.helpers.unique(() => faker.internet.email(), 5)
|
|
1108
|
+
* ```
|
|
1109
|
+
*/
|
|
1110
|
+
var Helpers = class {
|
|
1111
|
+
rng;
|
|
1112
|
+
constructor(rng) {
|
|
1113
|
+
this.rng = rng;
|
|
1114
|
+
}
|
|
1115
|
+
arrayElement(items) {
|
|
1116
|
+
return this.rng.pick(items);
|
|
1117
|
+
}
|
|
1118
|
+
/** Pick `count` distinct elements from `items` (no replacement). */
|
|
1119
|
+
arrayElements(items, count) {
|
|
1120
|
+
const n = count ?? this.rng.int(1, items.length);
|
|
1121
|
+
if (n > items.length) throw new Error(`[Helpers] arrayElements: requested ${n.toString()} from ${items.length.toString()} items.`);
|
|
1122
|
+
return this.shuffle(items).slice(0, n);
|
|
1123
|
+
}
|
|
1124
|
+
shuffle(items) {
|
|
1125
|
+
const copy = [...items];
|
|
1126
|
+
for (let i = copy.length - 1; i > 0; i--) {
|
|
1127
|
+
const j = this.rng.int(0, i);
|
|
1128
|
+
const a = copy[i];
|
|
1129
|
+
const b = copy[j];
|
|
1130
|
+
if (a === void 0 || b === void 0) continue;
|
|
1131
|
+
copy[i] = b;
|
|
1132
|
+
copy[j] = a;
|
|
1133
|
+
}
|
|
1134
|
+
return copy;
|
|
1135
|
+
}
|
|
1136
|
+
weightedArrayElement(items) {
|
|
1137
|
+
if (items.length === 0) throw new Error("[Helpers] weightedArrayElement: empty list.");
|
|
1138
|
+
const total = items.reduce((acc, it) => acc + it.weight, 0);
|
|
1139
|
+
if (total <= 0) throw new Error("[Helpers] weightedArrayElement: weights sum to <= 0.");
|
|
1140
|
+
let target = this.rng.next() * total;
|
|
1141
|
+
for (const it of items) {
|
|
1142
|
+
target -= it.weight;
|
|
1143
|
+
if (target <= 0) return it.value;
|
|
1144
|
+
}
|
|
1145
|
+
const last = items[items.length - 1];
|
|
1146
|
+
if (last === void 0) throw new Error("[Helpers] weightedArrayElement: unreachable");
|
|
1147
|
+
return last.value;
|
|
1148
|
+
}
|
|
1149
|
+
/** Build an array of length `length` by calling `fn(index)`. */
|
|
1150
|
+
multiple(length, fn) {
|
|
1151
|
+
return Array.from({ length }, (_, i) => fn(i));
|
|
1152
|
+
}
|
|
1153
|
+
/** Repeat a string `count` times. */
|
|
1154
|
+
repeat(value, count) {
|
|
1155
|
+
return value.repeat(count);
|
|
1156
|
+
}
|
|
1157
|
+
/** Sample-string matching a regex. */
|
|
1158
|
+
fromRegExp(pattern) {
|
|
1159
|
+
return generateFromRegex(pattern, this.rng);
|
|
1160
|
+
}
|
|
1161
|
+
/**
|
|
1162
|
+
* Collect `count` unique results from `fn`. Throws if the retry budget is
|
|
1163
|
+
* exhausted before reaching `count`.
|
|
1164
|
+
*/
|
|
1165
|
+
unique(fn, count, options = {}) {
|
|
1166
|
+
const out = /* @__PURE__ */ new Set();
|
|
1167
|
+
const budget = options.maxRetries ?? count * 10;
|
|
1168
|
+
let attempts = 0;
|
|
1169
|
+
while (out.size < count && attempts < budget) {
|
|
1170
|
+
out.add(fn());
|
|
1171
|
+
attempts++;
|
|
1172
|
+
}
|
|
1173
|
+
if (out.size < count) throw new Error(`[Helpers] unique: could not produce ${count.toString()} unique values after ${budget.toString()} attempts (got ${out.size.toString()}).`);
|
|
1174
|
+
return [...out];
|
|
1175
|
+
}
|
|
1176
|
+
/** Pick a random `enum` value, handling numeric reverse-mappings. */
|
|
1177
|
+
enumValue(enumObj) {
|
|
1178
|
+
const numericKeys = Object.keys(enumObj).filter((k) => /^\d+$/.test(k));
|
|
1179
|
+
const values = numericKeys.length > 0 ? numericKeys.map((k) => enumObj[k]) : Object.values(enumObj);
|
|
1180
|
+
if (values.length === 0) throw new Error("[Helpers] enumValue: enum has no values.");
|
|
1181
|
+
return this.rng.pick(values);
|
|
1182
|
+
}
|
|
1183
|
+
/** With probability `chance`, return `value`; otherwise `undefined`. */
|
|
1184
|
+
maybe(value, chance = .5) {
|
|
1185
|
+
return this.rng.bool(chance) ? value : void 0;
|
|
1186
|
+
}
|
|
1187
|
+
};
|
|
1188
|
+
//#endregion
|
|
1189
|
+
//#region src/faker/faker.ts
|
|
1190
|
+
/**
|
|
1191
|
+
* Faceted, seedable, locale-aware random-data generator.
|
|
1192
|
+
*
|
|
1193
|
+
* Every namespace shares the same PRNG and locale reference — `seed()` and
|
|
1194
|
+
* `locale()` mutate that shared state in place, so changes propagate without
|
|
1195
|
+
* re-constructing modules.
|
|
1196
|
+
*
|
|
1197
|
+
* @example
|
|
1198
|
+
* ```ts
|
|
1199
|
+
* import { Faker } from '@anil-labs/factory'
|
|
1200
|
+
*
|
|
1201
|
+
* const f = new Faker({ seed: 42, locale: 'en' })
|
|
1202
|
+
* f.person.fullName() // "Olivia Patel"
|
|
1203
|
+
* f.seed(42)
|
|
1204
|
+
* f.person.fullName() // "Olivia Patel" — deterministic
|
|
1205
|
+
*
|
|
1206
|
+
* // Or use the package's default instance:
|
|
1207
|
+
* import { faker } from '@anil-labs/factory'
|
|
1208
|
+
* faker.seed(1)
|
|
1209
|
+
* faker.internet.email()
|
|
1210
|
+
* ```
|
|
1211
|
+
*/
|
|
1212
|
+
var Faker = class Faker {
|
|
1213
|
+
rng;
|
|
1214
|
+
localeRef;
|
|
1215
|
+
person;
|
|
1216
|
+
internet;
|
|
1217
|
+
location;
|
|
1218
|
+
lorem;
|
|
1219
|
+
date;
|
|
1220
|
+
number;
|
|
1221
|
+
string;
|
|
1222
|
+
color;
|
|
1223
|
+
company;
|
|
1224
|
+
commerce;
|
|
1225
|
+
finance;
|
|
1226
|
+
image;
|
|
1227
|
+
system;
|
|
1228
|
+
datatype;
|
|
1229
|
+
helpers;
|
|
1230
|
+
constructor(opts = {}) {
|
|
1231
|
+
this.rng = createPrng(opts.seed);
|
|
1232
|
+
this.localeRef = new LocaleRef(opts.locale ?? "en");
|
|
1233
|
+
this.person = new Person(this.rng, this.localeRef);
|
|
1234
|
+
this.internet = new Internet(this.rng, this.localeRef);
|
|
1235
|
+
this.location = new Location(this.rng, this.localeRef);
|
|
1236
|
+
this.lorem = new Lorem(this.rng, this.localeRef);
|
|
1237
|
+
this.date = new DateGen(this.rng);
|
|
1238
|
+
this.number = new NumberGen(this.rng);
|
|
1239
|
+
this.string = new StringGen(this.rng);
|
|
1240
|
+
this.color = new Color(this.rng, this.localeRef);
|
|
1241
|
+
this.company = new Company(this.rng, this.localeRef);
|
|
1242
|
+
this.commerce = new Commerce(this.rng, this.localeRef);
|
|
1243
|
+
this.finance = new Finance(this.rng);
|
|
1244
|
+
this.image = new Image(this.rng);
|
|
1245
|
+
this.system = new System(this.rng, this.localeRef, this.string);
|
|
1246
|
+
this.datatype = new Datatype(this.rng);
|
|
1247
|
+
this.helpers = new Helpers(this.rng);
|
|
1248
|
+
}
|
|
1249
|
+
/** Reseed the underlying PRNG. Subsequent calls are deterministic from here. */
|
|
1250
|
+
seed(seed) {
|
|
1251
|
+
this.rng.seed(seed);
|
|
1252
|
+
return this;
|
|
1253
|
+
}
|
|
1254
|
+
/** Switch the active locale. Throws if unknown. */
|
|
1255
|
+
locale(name) {
|
|
1256
|
+
this.localeRef.set(name);
|
|
1257
|
+
return this;
|
|
1258
|
+
}
|
|
1259
|
+
/** Read the current locale identifier (e.g. `"en"`). */
|
|
1260
|
+
currentLocale() {
|
|
1261
|
+
return this.localeRef.name;
|
|
1262
|
+
}
|
|
1263
|
+
/** Read the current seed (useful for snapshot reproduction). */
|
|
1264
|
+
currentSeed() {
|
|
1265
|
+
return this.rng.currentSeed;
|
|
1266
|
+
}
|
|
1267
|
+
/**
|
|
1268
|
+
* Build a fresh, independent `Faker` with its own PRNG seeded from this
|
|
1269
|
+
* one's current state. Useful when you need to fork a deterministic stream.
|
|
1270
|
+
*/
|
|
1271
|
+
fork() {
|
|
1272
|
+
return new Faker({
|
|
1273
|
+
seed: this.rng.int(0, 4294967295),
|
|
1274
|
+
locale: this.localeRef.name
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
/** Access the underlying PRNG. Advanced use only. */
|
|
1278
|
+
rawPrng() {
|
|
1279
|
+
return this.rng;
|
|
1280
|
+
}
|
|
1281
|
+
};
|
|
1282
|
+
/** Default singleton — mutable via `faker.seed()` / `faker.locale()`. */
|
|
1283
|
+
var faker = new Faker();
|
|
1284
|
+
//#endregion
|
|
1285
|
+
export { createPrng as C, registerLocale as S, Internet as _, Datatype as a, getLocale as b, Finance as c, Color as d, StringGen as f, Location as g, Lorem as h, generateFromRegex as i, Commerce as l, DateGen as m, faker as n, System as o, NumberGen as p, Helpers as r, Image as s, Faker as t, Company as u, Person as v, Mulberry32 as w, listLocales as x, LocaleRef as y };
|
|
1286
|
+
|
|
1287
|
+
//# sourceMappingURL=faker-BlEhpR26.mjs.map
|