@nitronjs/framework 0.1.22 → 0.1.23
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/cli/njs.js +33 -5
- package/lib/Console/Commands/MigrateCommand.js +27 -70
- package/lib/Console/Commands/MigrateFreshCommand.js +49 -66
- package/lib/Console/Commands/MigrateRollbackCommand.js +52 -0
- package/lib/Console/Commands/MigrateStatusCommand.js +38 -0
- package/lib/Console/Commands/SeedCommand.js +36 -65
- package/lib/Core/Paths.js +8 -0
- package/lib/Database/Migration/Checksum.js +23 -0
- package/lib/Database/Migration/MigrationRepository.js +92 -0
- package/lib/Database/Migration/MigrationRunner.js +327 -0
- package/lib/Database/Migration/migrations/0000_00_00_00_00_create_migrations_table.js +21 -0
- package/lib/Database/Migration/migrations/0000_00_00_00_01_create_seeders_table.js +20 -0
- package/lib/Database/Schema/Blueprint.js +0 -40
- package/lib/Database/Schema/Manager.js +29 -40
- package/lib/Database/Seeder/SeederRepository.js +49 -0
- package/lib/Database/Seeder/SeederRunner.js +183 -0
- package/lib/Faker/Data/Address.js +63 -0
- package/lib/Faker/Data/Color.js +72 -0
- package/lib/Faker/Data/Company.js +59 -0
- package/lib/Faker/Data/Date.js +49 -0
- package/lib/Faker/Data/Finance.js +65 -0
- package/lib/Faker/Data/Internet.js +73 -0
- package/lib/Faker/Data/Lorem.js +45 -0
- package/lib/Faker/Data/Person.js +67 -0
- package/lib/Faker/Data/Phone.js +26 -0
- package/lib/Faker/Faker.d.ts +205 -0
- package/lib/Faker/Faker.js +812 -0
- package/lib/View/Manager.js +26 -5
- package/lib/index.d.ts +407 -0
- package/lib/index.js +12 -0
- package/package.json +6 -2
- package/skeleton/config/app.js +20 -0
- package/skeleton/globals.d.ts +68 -1
- package/skeleton/tsconfig.json +6 -16
|
@@ -0,0 +1,812 @@
|
|
|
1
|
+
import * as PersonData from './Data/Person.js';
|
|
2
|
+
import * as AddressData from './Data/Address.js';
|
|
3
|
+
import * as InternetData from './Data/Internet.js';
|
|
4
|
+
import * as CompanyData from './Data/Company.js';
|
|
5
|
+
import * as LoremData from './Data/Lorem.js';
|
|
6
|
+
import * as FinanceData from './Data/Finance.js';
|
|
7
|
+
import * as ColorData from './Data/Color.js';
|
|
8
|
+
import * as DateData from './Data/Date.js';
|
|
9
|
+
import * as PhoneData from './Data/Phone.js';
|
|
10
|
+
|
|
11
|
+
class FakerClass {
|
|
12
|
+
|
|
13
|
+
#usedValues = new Map();
|
|
14
|
+
#allowDuplicates = false;
|
|
15
|
+
#maxAttempts = 1000;
|
|
16
|
+
|
|
17
|
+
constructor() {
|
|
18
|
+
this.#usedValues = new Map();
|
|
19
|
+
this.#allowDuplicates = false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
allowDuplicates() {
|
|
23
|
+
const instance = new FakerClass();
|
|
24
|
+
instance.#allowDuplicates = true;
|
|
25
|
+
return instance;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
reset() {
|
|
29
|
+
this.#usedValues.clear();
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
#random(min, max) {
|
|
34
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
#randomFloat(min, max, decimals = 2) {
|
|
38
|
+
const value = Math.random() * (max - min) + min;
|
|
39
|
+
return parseFloat(value.toFixed(decimals));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#pick(array) {
|
|
43
|
+
return array[this.#random(0, array.length - 1)];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
#pickMultiple(array, count) {
|
|
47
|
+
const shuffled = [...array].sort(() => Math.random() - 0.5);
|
|
48
|
+
return shuffled.slice(0, Math.min(count, array.length));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
#unique(key, generator) {
|
|
52
|
+
if (this.#allowDuplicates) {
|
|
53
|
+
return generator();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!this.#usedValues.has(key)) {
|
|
57
|
+
this.#usedValues.set(key, new Set());
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const used = this.#usedValues.get(key);
|
|
61
|
+
let attempts = 0;
|
|
62
|
+
|
|
63
|
+
while (attempts < this.#maxAttempts) {
|
|
64
|
+
const value = generator();
|
|
65
|
+
if (!used.has(value)) {
|
|
66
|
+
used.add(value);
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
attempts++;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
throw new Error(`Faker: Could not generate unique value for "${key}" after ${this.#maxAttempts} attempts`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ==================== PERSON ====================
|
|
76
|
+
|
|
77
|
+
firstName(gender) {
|
|
78
|
+
return this.#unique('firstName', () => {
|
|
79
|
+
if (gender === 'male') return this.#pick(PersonData.firstNamesMale);
|
|
80
|
+
if (gender === 'female') return this.#pick(PersonData.firstNamesFemale);
|
|
81
|
+
return this.#pick([...PersonData.firstNamesMale, ...PersonData.firstNamesFemale]);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
lastName() {
|
|
86
|
+
return this.#unique('lastName', () => this.#pick(PersonData.lastNames));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
fullName(gender) {
|
|
90
|
+
return this.#unique('fullName', () => `${this.firstName(gender)} ${this.lastName()}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
gender() {
|
|
94
|
+
return this.#pick(PersonData.genders);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
prefix(gender) {
|
|
98
|
+
if (gender === 'male') return this.#pick(PersonData.prefixes.male);
|
|
99
|
+
if (gender === 'female') return this.#pick(PersonData.prefixes.female);
|
|
100
|
+
return this.#pick([...PersonData.prefixes.male, ...PersonData.prefixes.female]);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
suffix() {
|
|
104
|
+
return this.#pick(PersonData.suffixes);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
age(min = 18, max = 80) {
|
|
108
|
+
return this.#random(min, max);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
birthDate(minAge = 18, maxAge = 80) {
|
|
112
|
+
const today = new Date();
|
|
113
|
+
const age = this.#random(minAge, maxAge);
|
|
114
|
+
const year = today.getFullYear() - age;
|
|
115
|
+
const month = this.#random(0, 11);
|
|
116
|
+
const day = this.#random(1, 28);
|
|
117
|
+
return new Date(year, month, day);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
jobTitle() {
|
|
121
|
+
return this.#pick(PersonData.jobTitles);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
jobArea() {
|
|
125
|
+
return this.#pick(PersonData.jobAreas);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
jobType() {
|
|
129
|
+
return this.#pick(PersonData.jobTypes);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ==================== INTERNET ====================
|
|
133
|
+
|
|
134
|
+
email(firstName, lastName) {
|
|
135
|
+
return this.#unique('email', () => {
|
|
136
|
+
const fn = (firstName || this.firstName()).toLowerCase().replace(/[^a-z]/g, '');
|
|
137
|
+
const ln = (lastName || this.lastName()).toLowerCase().replace(/[^a-z]/g, '');
|
|
138
|
+
const provider = this.#pick(InternetData.emailProviders);
|
|
139
|
+
const separator = this.#pick(['', '.', '_', '-']);
|
|
140
|
+
const number = this.boolean() ? this.#random(1, 999) : '';
|
|
141
|
+
return `${fn}${separator}${ln}${number}@${provider}`;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
username(firstName, lastName) {
|
|
146
|
+
return this.#unique('username', () => {
|
|
147
|
+
const fn = (firstName || this.firstName()).toLowerCase().replace(/[^a-z]/g, '');
|
|
148
|
+
const ln = (lastName || this.lastName()).toLowerCase().replace(/[^a-z]/g, '');
|
|
149
|
+
const separator = this.#pick(['', '.', '_', '-', '']);
|
|
150
|
+
const number = this.#random(1, 9999);
|
|
151
|
+
const patterns = [
|
|
152
|
+
`${fn}${separator}${ln}`,
|
|
153
|
+
`${fn}${number}`,
|
|
154
|
+
`${fn}${separator}${ln}${number}`,
|
|
155
|
+
`${ln}${separator}${fn}`,
|
|
156
|
+
`${fn.charAt(0)}${ln}${number}`
|
|
157
|
+
];
|
|
158
|
+
return this.#pick(patterns);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
password(length = 12, options = {}) {
|
|
163
|
+
const lowercase = 'abcdefghijklmnopqrstuvwxyz';
|
|
164
|
+
const uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
165
|
+
const numbers = '0123456789';
|
|
166
|
+
const symbols = '!@#$%^&*()_+-=[]{}|;:,.<>?';
|
|
167
|
+
|
|
168
|
+
let chars = lowercase;
|
|
169
|
+
if (options.uppercase !== false) chars += uppercase;
|
|
170
|
+
if (options.numbers !== false) chars += numbers;
|
|
171
|
+
if (options.symbols === true) chars += symbols;
|
|
172
|
+
|
|
173
|
+
let password = '';
|
|
174
|
+
for (let i = 0; i < length; i++) {
|
|
175
|
+
password += chars.charAt(this.#random(0, chars.length - 1));
|
|
176
|
+
}
|
|
177
|
+
return password;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
url(protocol = 'https') {
|
|
181
|
+
return this.#unique('url', () => {
|
|
182
|
+
const domain = this.domainName();
|
|
183
|
+
const path = this.boolean() ? `/${this.slug()}` : '';
|
|
184
|
+
return `${protocol}://${domain}${path}`;
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
domainName() {
|
|
189
|
+
return this.#unique('domainName', () => {
|
|
190
|
+
const word = this.#pick(LoremData.words).toLowerCase();
|
|
191
|
+
const suffix = this.#pick(InternetData.domainSuffixes);
|
|
192
|
+
return `${word}${suffix}`;
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
domainWord() {
|
|
197
|
+
return this.#pick(LoremData.words).toLowerCase();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
domainSuffix() {
|
|
201
|
+
return this.#pick(InternetData.domainSuffixes);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
ip() {
|
|
205
|
+
return `${this.#random(1, 255)}.${this.#random(0, 255)}.${this.#random(0, 255)}.${this.#random(1, 255)}`;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
ipv6() {
|
|
209
|
+
const segments = [];
|
|
210
|
+
for (let i = 0; i < 8; i++) {
|
|
211
|
+
segments.push(this.#random(0, 65535).toString(16).padStart(4, '0'));
|
|
212
|
+
}
|
|
213
|
+
return segments.join(':');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
mac(separator = ':') {
|
|
217
|
+
const segments = [];
|
|
218
|
+
for (let i = 0; i < 6; i++) {
|
|
219
|
+
segments.push(this.#random(0, 255).toString(16).padStart(2, '0').toUpperCase());
|
|
220
|
+
}
|
|
221
|
+
return segments.join(separator);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
port() {
|
|
225
|
+
return this.#random(1024, 65535);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
userAgent() {
|
|
229
|
+
return this.#pick(InternetData.userAgents);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
browser() {
|
|
233
|
+
const browser = this.#pick(InternetData.browsers);
|
|
234
|
+
return {
|
|
235
|
+
name: browser.name,
|
|
236
|
+
version: this.#pick(browser.versions)
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
httpMethod() {
|
|
241
|
+
return this.#pick(InternetData.httpMethods);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
httpStatusCode() {
|
|
245
|
+
return this.#pick(InternetData.httpStatusCodes);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
mimeType() {
|
|
249
|
+
return this.#pick(InternetData.mimeTypes);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
fileExtension(type) {
|
|
253
|
+
if (type && InternetData.fileExtensions[type]) {
|
|
254
|
+
return this.#pick(InternetData.fileExtensions[type]);
|
|
255
|
+
}
|
|
256
|
+
const allExtensions = Object.values(InternetData.fileExtensions).flat();
|
|
257
|
+
return this.#pick(allExtensions);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
fileName(extension) {
|
|
261
|
+
const ext = extension || this.fileExtension();
|
|
262
|
+
const name = this.slug();
|
|
263
|
+
return `${name}.${ext}`;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
slug(wordCount = 3) {
|
|
267
|
+
const words = this.#pickMultiple(LoremData.words, wordCount);
|
|
268
|
+
return words.join('-').toLowerCase();
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// ==================== ADDRESS ====================
|
|
272
|
+
|
|
273
|
+
streetAddress() {
|
|
274
|
+
const number = this.#random(1, 9999);
|
|
275
|
+
const name = this.#pick(AddressData.streetNames);
|
|
276
|
+
const suffix = this.#pick(AddressData.streetSuffixes);
|
|
277
|
+
return `${number} ${name} ${suffix}`;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
streetName() {
|
|
281
|
+
return `${this.#pick(AddressData.streetNames)} ${this.#pick(AddressData.streetSuffixes)}`;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
city() {
|
|
285
|
+
return this.#pick(AddressData.cities);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
state(abbreviated = false) {
|
|
289
|
+
const state = this.#pick(AddressData.states);
|
|
290
|
+
return abbreviated ? state.abbr : state.name;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
stateAbbr() {
|
|
294
|
+
return this.state(true);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
country(abbreviated = false) {
|
|
298
|
+
const country = this.#pick(AddressData.countries);
|
|
299
|
+
return abbreviated ? country.code : country.name;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
countryCode() {
|
|
303
|
+
return this.country(true);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
zipCode() {
|
|
307
|
+
return `${this.#random(10000, 99999)}`;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
latitude(min = -90, max = 90) {
|
|
311
|
+
return this.#randomFloat(min, max, 6);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
longitude(min = -180, max = 180) {
|
|
315
|
+
return this.#randomFloat(min, max, 6);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
coordinates() {
|
|
319
|
+
return {
|
|
320
|
+
latitude: this.latitude(),
|
|
321
|
+
longitude: this.longitude()
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
direction() {
|
|
326
|
+
return this.#pick(AddressData.directions);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
secondaryAddress() {
|
|
330
|
+
const type = this.#pick(AddressData.secondaryAddresses);
|
|
331
|
+
const number = this.#random(1, 999);
|
|
332
|
+
return `${type} ${number}`;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
fullAddress() {
|
|
336
|
+
return this.#unique('fullAddress', () => {
|
|
337
|
+
const street = this.streetAddress();
|
|
338
|
+
const city = this.city();
|
|
339
|
+
const state = this.stateAbbr();
|
|
340
|
+
const zip = this.zipCode();
|
|
341
|
+
return `${street}, ${city}, ${state} ${zip}`;
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
timeZone() {
|
|
346
|
+
return this.#pick(AddressData.timeZones);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// ==================== PHONE ====================
|
|
350
|
+
|
|
351
|
+
phoneNumber(format) {
|
|
352
|
+
const pattern = format || this.#pick(PhoneData.phoneFormats);
|
|
353
|
+
return pattern.replace(/#/g, () => this.#random(0, 9).toString());
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
phoneCountryCode() {
|
|
357
|
+
return this.#pick(PhoneData.countryCodes);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// ==================== COMPANY ====================
|
|
361
|
+
|
|
362
|
+
companyName() {
|
|
363
|
+
return this.#unique('companyName', () => {
|
|
364
|
+
const patterns = [
|
|
365
|
+
() => `${this.lastName()} ${this.#pick(CompanyData.companySuffixes)}`,
|
|
366
|
+
() => `${this.lastName()} and ${this.lastName()}`,
|
|
367
|
+
() => `${this.lastName()}, ${this.lastName()} and ${this.lastName()}`,
|
|
368
|
+
() => `${this.#pick(CompanyData.companyPrefixes)} ${this.lastName()}`,
|
|
369
|
+
() => `${this.lastName()} ${this.#pick(CompanyData.industries)}`
|
|
370
|
+
];
|
|
371
|
+
return this.#pick(patterns)();
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
companySuffix() {
|
|
376
|
+
return this.#pick(CompanyData.companySuffixes);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
industry() {
|
|
380
|
+
return this.#pick(CompanyData.industries);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
catchPhrase() {
|
|
384
|
+
const adj = this.#pick(CompanyData.catchPhraseAdjectives);
|
|
385
|
+
const desc = this.#pick(CompanyData.catchPhraseDescriptors);
|
|
386
|
+
const noun = this.#pick(CompanyData.catchPhraseNouns);
|
|
387
|
+
return `${adj} ${desc} ${noun}`;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
buzzword() {
|
|
391
|
+
return this.#pick(CompanyData.buzzwords);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
department() {
|
|
395
|
+
return this.#pick(CompanyData.departments);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// ==================== LOREM ====================
|
|
399
|
+
|
|
400
|
+
word() {
|
|
401
|
+
return this.#pick(LoremData.words);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
words(count = 5) {
|
|
405
|
+
return this.#pickMultiple(LoremData.words, count).join(' ');
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
sentence(wordCount) {
|
|
409
|
+
const count = wordCount || this.#random(5, 15);
|
|
410
|
+
const words = this.words(count);
|
|
411
|
+
return words.charAt(0).toUpperCase() + words.slice(1) + '.';
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
sentences(count = 3) {
|
|
415
|
+
const result = [];
|
|
416
|
+
for (let i = 0; i < count; i++) {
|
|
417
|
+
result.push(this.sentence());
|
|
418
|
+
}
|
|
419
|
+
return result.join(' ');
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
paragraph(sentenceCount) {
|
|
423
|
+
const count = sentenceCount || this.#random(3, 7);
|
|
424
|
+
return this.sentences(count);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
paragraphs(count = 3, separator = '\n\n') {
|
|
428
|
+
const result = [];
|
|
429
|
+
for (let i = 0; i < count; i++) {
|
|
430
|
+
result.push(this.paragraph());
|
|
431
|
+
}
|
|
432
|
+
return result.join(separator);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
text(length = 200) {
|
|
436
|
+
let result = '';
|
|
437
|
+
while (result.length < length) {
|
|
438
|
+
result += this.sentence() + ' ';
|
|
439
|
+
}
|
|
440
|
+
return result.trim().substring(0, length);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// ==================== DATE ====================
|
|
444
|
+
|
|
445
|
+
past(years = 1, refDate) {
|
|
446
|
+
const ref = refDate ? new Date(refDate) : new Date();
|
|
447
|
+
const min = ref.getTime() - years * 365 * 24 * 60 * 60 * 1000;
|
|
448
|
+
const max = ref.getTime();
|
|
449
|
+
return new Date(this.#random(min, max));
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
future(years = 1, refDate) {
|
|
453
|
+
const ref = refDate ? new Date(refDate) : new Date();
|
|
454
|
+
const min = ref.getTime();
|
|
455
|
+
const max = ref.getTime() + years * 365 * 24 * 60 * 60 * 1000;
|
|
456
|
+
return new Date(this.#random(min, max));
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
recent(days = 7) {
|
|
460
|
+
const now = new Date();
|
|
461
|
+
const min = now.getTime() - days * 24 * 60 * 60 * 1000;
|
|
462
|
+
return new Date(this.#random(min, now.getTime()));
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
soon(days = 7) {
|
|
466
|
+
const now = new Date();
|
|
467
|
+
const max = now.getTime() + days * 24 * 60 * 60 * 1000;
|
|
468
|
+
return new Date(this.#random(now.getTime(), max));
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
between(from, to) {
|
|
472
|
+
const fromTime = new Date(from).getTime();
|
|
473
|
+
const toTime = new Date(to).getTime();
|
|
474
|
+
return new Date(this.#random(Math.min(fromTime, toTime), Math.max(fromTime, toTime)));
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
month(abbreviated = false) {
|
|
478
|
+
const month = this.#pick(DateData.months);
|
|
479
|
+
return abbreviated ? month.abbr : month.name;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
weekday(abbreviated = false) {
|
|
483
|
+
const day = this.#pick(DateData.weekdays);
|
|
484
|
+
return abbreviated ? day.abbr : day.name;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
year(min, max) {
|
|
488
|
+
const minYear = min || new Date().getFullYear() - 50;
|
|
489
|
+
const maxYear = max || new Date().getFullYear();
|
|
490
|
+
return this.#random(minYear, maxYear);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// ==================== FINANCE ====================
|
|
494
|
+
|
|
495
|
+
amount(min = 0, max = 1000, decimals = 2, symbol = '$') {
|
|
496
|
+
const amount = this.#randomFloat(min, max, decimals);
|
|
497
|
+
return `${symbol}${amount.toFixed(decimals)}`;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
currency() {
|
|
501
|
+
return this.#pick(FinanceData.currencies);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
currencyCode() {
|
|
505
|
+
return this.currency().code;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
currencySymbol() {
|
|
509
|
+
return this.currency().symbol;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
creditCard(type) {
|
|
513
|
+
const cardType = type
|
|
514
|
+
? FinanceData.creditCardTypes.find(c => c.name.toLowerCase() === type.toLowerCase())
|
|
515
|
+
: this.#pick(FinanceData.creditCardTypes);
|
|
516
|
+
|
|
517
|
+
if (!cardType) {
|
|
518
|
+
throw new Error(`Unknown credit card type: ${type}`);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const prefix = this.#pick(cardType.prefix);
|
|
522
|
+
let number = prefix;
|
|
523
|
+
|
|
524
|
+
while (number.length < cardType.length - 1) {
|
|
525
|
+
number += this.#random(0, 9);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// Luhn algorithm for check digit
|
|
529
|
+
let sum = 0;
|
|
530
|
+
let isEven = true;
|
|
531
|
+
for (let i = number.length - 1; i >= 0; i--) {
|
|
532
|
+
let digit = parseInt(number[i], 10);
|
|
533
|
+
if (isEven) {
|
|
534
|
+
digit *= 2;
|
|
535
|
+
if (digit > 9) digit -= 9;
|
|
536
|
+
}
|
|
537
|
+
sum += digit;
|
|
538
|
+
isEven = !isEven;
|
|
539
|
+
}
|
|
540
|
+
const checkDigit = (10 - (sum % 10)) % 10;
|
|
541
|
+
number += checkDigit;
|
|
542
|
+
|
|
543
|
+
return number;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
creditCardFormatted(type) {
|
|
547
|
+
const number = this.creditCard(type);
|
|
548
|
+
return number.replace(/(.{4})/g, '$1 ').trim();
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
creditCardCVV() {
|
|
552
|
+
return this.#random(100, 999).toString();
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
creditCardExpiry() {
|
|
556
|
+
const month = this.#random(1, 12).toString().padStart(2, '0');
|
|
557
|
+
const year = (new Date().getFullYear() + this.#random(1, 5)).toString().slice(-2);
|
|
558
|
+
return `${month}/${year}`;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
iban(countryCode) {
|
|
562
|
+
const country = countryCode
|
|
563
|
+
? FinanceData.ibanCountryCodes.find(c => c.country === countryCode.toUpperCase())
|
|
564
|
+
: this.#pick(FinanceData.ibanCountryCodes);
|
|
565
|
+
|
|
566
|
+
if (!country) {
|
|
567
|
+
throw new Error(`Unknown IBAN country code: ${countryCode}`);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
let iban = country.country;
|
|
571
|
+
const checkDigits = this.#random(10, 99).toString();
|
|
572
|
+
iban += checkDigits;
|
|
573
|
+
|
|
574
|
+
while (iban.length < country.length) {
|
|
575
|
+
iban += this.#random(0, 9);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
return iban;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
bic() {
|
|
582
|
+
const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
583
|
+
let bic = '';
|
|
584
|
+
for (let i = 0; i < 4; i++) bic += letters.charAt(this.#random(0, 25));
|
|
585
|
+
bic += this.countryCode();
|
|
586
|
+
for (let i = 0; i < 2; i++) bic += letters.charAt(this.#random(0, 25));
|
|
587
|
+
return bic;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
transactionType() {
|
|
591
|
+
return this.#pick(FinanceData.transactionTypes);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
accountType() {
|
|
595
|
+
return this.#pick(FinanceData.accountTypes);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
accountNumber(length = 10) {
|
|
599
|
+
let number = '';
|
|
600
|
+
for (let i = 0; i < length; i++) {
|
|
601
|
+
number += this.#random(0, 9);
|
|
602
|
+
}
|
|
603
|
+
return number;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
routingNumber() {
|
|
607
|
+
return this.accountNumber(9);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
bitcoinAddress() {
|
|
611
|
+
const chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
612
|
+
const prefix = this.#pick(['1', '3', 'bc1']);
|
|
613
|
+
let address = prefix;
|
|
614
|
+
const length = prefix === 'bc1' ? 39 : 33;
|
|
615
|
+
while (address.length < length) {
|
|
616
|
+
address += chars.charAt(this.#random(0, chars.length - 1));
|
|
617
|
+
}
|
|
618
|
+
return address;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
ethereumAddress() {
|
|
622
|
+
const chars = '0123456789abcdef';
|
|
623
|
+
let address = '0x';
|
|
624
|
+
for (let i = 0; i < 40; i++) {
|
|
625
|
+
address += chars.charAt(this.#random(0, 15));
|
|
626
|
+
}
|
|
627
|
+
return address;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
cryptoCurrency() {
|
|
631
|
+
return this.#pick(FinanceData.cryptoCurrencies);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// ==================== COLOR ====================
|
|
635
|
+
|
|
636
|
+
colorName() {
|
|
637
|
+
return this.#pick(ColorData.colorNames);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
hexColor() {
|
|
641
|
+
const hex = this.#random(0, 16777215).toString(16).padStart(6, '0');
|
|
642
|
+
return `#${hex}`;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
rgbColor() {
|
|
646
|
+
return {
|
|
647
|
+
r: this.#random(0, 255),
|
|
648
|
+
g: this.#random(0, 255),
|
|
649
|
+
b: this.#random(0, 255)
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
rgbString() {
|
|
654
|
+
const { r, g, b } = this.rgbColor();
|
|
655
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
rgbaString(alpha) {
|
|
659
|
+
const { r, g, b } = this.rgbColor();
|
|
660
|
+
const a = alpha !== undefined ? alpha : this.#randomFloat(0, 1, 2);
|
|
661
|
+
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
hslColor() {
|
|
665
|
+
return {
|
|
666
|
+
h: this.#random(0, 360),
|
|
667
|
+
s: this.#random(0, 100),
|
|
668
|
+
l: this.#random(0, 100)
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
hslString() {
|
|
673
|
+
const { h, s, l } = this.hslColor();
|
|
674
|
+
return `hsl(${h}, ${s}%, ${l}%)`;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
cssColor() {
|
|
678
|
+
return this.#pick(ColorData.cssColors);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
tailwindColor(color, shade) {
|
|
682
|
+
if (color && ColorData.tailwindColors[color]) {
|
|
683
|
+
const shades = ColorData.tailwindColors[color];
|
|
684
|
+
const index = shade ? Math.floor(shade / 100) - 1 : this.#random(0, 9);
|
|
685
|
+
return shades[Math.max(0, Math.min(9, index))];
|
|
686
|
+
}
|
|
687
|
+
const colors = Object.keys(ColorData.tailwindColors);
|
|
688
|
+
const randomColor = this.#pick(colors);
|
|
689
|
+
return this.#pick(ColorData.tailwindColors[randomColor]);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// ==================== IMAGE ====================
|
|
693
|
+
|
|
694
|
+
imageUrl(width = 640, height = 480, category) {
|
|
695
|
+
const categories = ['nature', 'city', 'technology', 'food', 'animals', 'people', 'abstract'];
|
|
696
|
+
const cat = category || this.#pick(categories);
|
|
697
|
+
return `https://picsum.photos/seed/${this.uuid().slice(0, 8)}/${width}/${height}`;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
avatarUrl(size = 200) {
|
|
701
|
+
const styles = ['adventurer', 'avataaars', 'big-ears', 'bottts', 'croodles', 'fun-emoji', 'icons', 'identicon', 'initials', 'lorelei', 'micah', 'miniavs', 'open-peeps', 'personas', 'pixel-art', 'shapes', 'thumbs'];
|
|
702
|
+
const style = this.#pick(styles);
|
|
703
|
+
const seed = this.uuid().slice(0, 8);
|
|
704
|
+
return `https://api.dicebear.com/7.x/${style}/svg?seed=${seed}&size=${size}`;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
placeholderUrl(width = 640, height = 480, text, bgColor, textColor) {
|
|
708
|
+
const bg = (bgColor || this.hexColor()).replace('#', '');
|
|
709
|
+
const fg = (textColor || (parseInt(bg, 16) > 8388607 ? '000000' : 'ffffff'));
|
|
710
|
+
const txt = text || `${width}x${height}`;
|
|
711
|
+
return `https://via.placeholder.com/${width}x${height}/${bg}/${fg}?text=${encodeURIComponent(txt)}`;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// ==================== UUID ====================
|
|
715
|
+
|
|
716
|
+
uuid() {
|
|
717
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
718
|
+
const r = this.#random(0, 15);
|
|
719
|
+
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
720
|
+
return v.toString(16);
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// ==================== NUMBER ====================
|
|
725
|
+
|
|
726
|
+
int(min = 0, max = 100) {
|
|
727
|
+
return this.#random(min, max);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
float(min = 0, max = 100, decimals = 2) {
|
|
731
|
+
return this.#randomFloat(min, max, decimals);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
boolean(probability = 0.5) {
|
|
735
|
+
return Math.random() < probability;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
arrayElement(array) {
|
|
739
|
+
return this.#pick(array);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
arrayElements(array, count) {
|
|
743
|
+
return this.#pickMultiple(array, count || this.#random(1, array.length));
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
objectElement(obj) {
|
|
747
|
+
const keys = Object.keys(obj);
|
|
748
|
+
const key = this.#pick(keys);
|
|
749
|
+
return { key, value: obj[key] };
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
shuffle(array) {
|
|
753
|
+
return [...array].sort(() => Math.random() - 0.5);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
// ==================== HELPERS ====================
|
|
757
|
+
|
|
758
|
+
maybe(callback, probability = 0.5) {
|
|
759
|
+
return this.boolean(probability) ? callback() : null;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
times(count, callback) {
|
|
763
|
+
const results = [];
|
|
764
|
+
for (let i = 0; i < count; i++) {
|
|
765
|
+
results.push(callback(i));
|
|
766
|
+
}
|
|
767
|
+
return results;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
oneOf(...values) {
|
|
771
|
+
return this.#pick(values);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
weightedPick(items) {
|
|
775
|
+
const totalWeight = items.reduce((sum, item) => sum + (item.weight || 1), 0);
|
|
776
|
+
let random = Math.random() * totalWeight;
|
|
777
|
+
|
|
778
|
+
for (const item of items) {
|
|
779
|
+
random -= item.weight || 1;
|
|
780
|
+
if (random <= 0) {
|
|
781
|
+
return item.value;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
return items[items.length - 1].value;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
template(str, data = {}) {
|
|
789
|
+
return str.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (match, path) => {
|
|
790
|
+
const parts = path.split('.');
|
|
791
|
+
let value = this;
|
|
792
|
+
|
|
793
|
+
for (const part of parts) {
|
|
794
|
+
if (typeof value[part] === 'function') {
|
|
795
|
+
value = value[part]();
|
|
796
|
+
} else if (data[part] !== undefined) {
|
|
797
|
+
value = data[part];
|
|
798
|
+
} else {
|
|
799
|
+
return match;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
return value;
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
const Faker = new FakerClass();
|
|
810
|
+
|
|
811
|
+
export default Faker;
|
|
812
|
+
export { FakerClass };
|