@venn-lang/data 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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +143 -0
  3. package/dist/index.d.ts +152 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +1941 -0
  6. package/dist/index.js.map +1 -0
  7. package/package.json +54 -0
  8. package/src/actions/faker-actions.ts +22 -0
  9. package/src/actions/index.ts +7 -0
  10. package/src/actions/parse-actions.ts +31 -0
  11. package/src/actions/random-actions.ts +51 -0
  12. package/src/csv/csv.types.ts +2 -0
  13. package/src/csv/index.ts +2 -0
  14. package/src/csv/parse-csv.ts +30 -0
  15. package/src/faker/address.ts +70 -0
  16. package/src/faker/all-specs.ts +25 -0
  17. package/src/faker/brazil-documents.ts +46 -0
  18. package/src/faker/brazil.ts +75 -0
  19. package/src/faker/check-digits.ts +56 -0
  20. package/src/faker/commerce.ts +59 -0
  21. package/src/faker/company.ts +41 -0
  22. package/src/faker/data/business.ts +80 -0
  23. package/src/faker/data/commerce.ts +73 -0
  24. package/src/faker/data/index.ts +36 -0
  25. package/src/faker/data/names.ts +93 -0
  26. package/src/faker/data/places.ts +109 -0
  27. package/src/faker/data/web.ts +45 -0
  28. package/src/faker/data/words.ts +104 -0
  29. package/src/faker/datetime.ts +102 -0
  30. package/src/faker/faker.types.ts +24 -0
  31. package/src/faker/finance.ts +86 -0
  32. package/src/faker/ids.ts +80 -0
  33. package/src/faker/index.ts +8 -0
  34. package/src/faker/internet.ts +100 -0
  35. package/src/faker/person.ts +88 -0
  36. package/src/faker/primitives.ts +77 -0
  37. package/src/faker/text.ts +56 -0
  38. package/src/index.ts +8 -0
  39. package/src/plugin.ts +17 -0
  40. package/src/rng/index.ts +4 -0
  41. package/src/rng/mulberry32.ts +18 -0
  42. package/src/rng/rng.types.ts +2 -0
  43. package/src/rng/shared-rng.ts +15 -0
  44. package/src/rng/shuffle.ts +17 -0
  45. package/src/types.ts +14 -0
package/dist/index.js ADDED
@@ -0,0 +1,1941 @@
1
+ import { arg, defineAction, definePlugin, optionalArg, restArg } from "@venn-lang/sdk";
2
+ import { t } from "@venn-lang/types";
3
+ //#region src/faker/data/business.ts
4
+ const COMPANY_ROOTS = [
5
+ "Northwind",
6
+ "Acme",
7
+ "Globex",
8
+ "Initech",
9
+ "Umbrella",
10
+ "Vandelay",
11
+ "Stark",
12
+ "Wayne",
13
+ "Tyrell",
14
+ "Cyberdyne",
15
+ "Aperture",
16
+ "Soylent",
17
+ "Massive",
18
+ "Hooli"
19
+ ];
20
+ const COMPANY_SUFFIXES = [
21
+ "Ltd",
22
+ "Inc",
23
+ "GmbH",
24
+ "S.A.",
25
+ "LLC",
26
+ "Group",
27
+ "Labs",
28
+ "Systems",
29
+ "Holdings"
30
+ ];
31
+ const DEPARTMENTS = [
32
+ "Engineering",
33
+ "Design",
34
+ "Sales",
35
+ "Marketing",
36
+ "Support",
37
+ "Finance",
38
+ "Legal",
39
+ "People",
40
+ "Operations",
41
+ "Security",
42
+ "Data",
43
+ "Research"
44
+ ];
45
+ const JOB_TITLES = [
46
+ "Software Engineer",
47
+ "Product Designer",
48
+ "Data Analyst",
49
+ "Engineering Manager",
50
+ "QA Engineer",
51
+ "Site Reliability Engineer",
52
+ "Technical Writer",
53
+ "Product Manager",
54
+ "Security Analyst",
55
+ "Solutions Architect",
56
+ "Support Specialist",
57
+ "Accountant"
58
+ ];
59
+ const BUZZWORDS = [
60
+ "synergy",
61
+ "scalability",
62
+ "throughput",
63
+ "observability",
64
+ "resilience",
65
+ "alignment",
66
+ "velocity",
67
+ "leverage",
68
+ "bandwidth",
69
+ "runway"
70
+ ];
71
+ const CATCH_VERBS = [
72
+ "streamline",
73
+ "orchestrate",
74
+ "unlock",
75
+ "accelerate",
76
+ "simplify",
77
+ "amplify"
78
+ ];
79
+ //#endregion
80
+ //#region src/faker/data/commerce.ts
81
+ const PRODUCTS = [
82
+ "Chair",
83
+ "Keyboard",
84
+ "Lamp",
85
+ "Backpack",
86
+ "Mug",
87
+ "Notebook",
88
+ "Headphones",
89
+ "Monitor",
90
+ "Desk",
91
+ "Bottle",
92
+ "Jacket",
93
+ "Sneakers",
94
+ "Table",
95
+ "Shelf",
96
+ "Camera"
97
+ ];
98
+ const MATERIALS = [
99
+ "cotton",
100
+ "steel",
101
+ "oak",
102
+ "leather",
103
+ "glass",
104
+ "aluminium",
105
+ "ceramic",
106
+ "linen"
107
+ ];
108
+ const CATEGORIES = [
109
+ "Electronics",
110
+ "Home",
111
+ "Outdoors",
112
+ "Books",
113
+ "Clothing",
114
+ "Toys",
115
+ "Grocery",
116
+ "Sports",
117
+ "Beauty",
118
+ "Automotive"
119
+ ];
120
+ const COLORS = [
121
+ ["black", "#000000"],
122
+ ["white", "#ffffff"],
123
+ ["red", "#e53935"],
124
+ ["blue", "#1e88e5"],
125
+ ["green", "#43a047"],
126
+ ["amber", "#ffb300"],
127
+ ["violet", "#8e24aa"],
128
+ ["teal", "#00897b"],
129
+ ["slate", "#546e7a"],
130
+ ["coral", "#ff7043"]
131
+ ];
132
+ /** `[code, symbol, name]`. */
133
+ const CURRENCIES = [
134
+ [
135
+ "BRL",
136
+ "R$",
137
+ "Brazilian Real"
138
+ ],
139
+ [
140
+ "USD",
141
+ "$",
142
+ "US Dollar"
143
+ ],
144
+ [
145
+ "EUR",
146
+ "€",
147
+ "Euro"
148
+ ],
149
+ [
150
+ "GBP",
151
+ "£",
152
+ "Pound Sterling"
153
+ ],
154
+ [
155
+ "JPY",
156
+ "¥",
157
+ "Japanese Yen"
158
+ ],
159
+ [
160
+ "CAD",
161
+ "$",
162
+ "Canadian Dollar"
163
+ ]
164
+ ];
165
+ /** `[brand, prefix, length]`. The prefixes are the real issuer ranges. */
166
+ const CARD_BRANDS = [
167
+ [
168
+ "Visa",
169
+ "4",
170
+ 16
171
+ ],
172
+ [
173
+ "Mastercard",
174
+ "51",
175
+ 16
176
+ ],
177
+ [
178
+ "Mastercard",
179
+ "55",
180
+ 16
181
+ ],
182
+ [
183
+ "Discover",
184
+ "6011",
185
+ 16
186
+ ],
187
+ [
188
+ "Elo",
189
+ "4011",
190
+ 16
191
+ ]
192
+ ];
193
+ //#endregion
194
+ //#region src/faker/data/names.ts
195
+ /** Given names, mixing the computing pantheon with names common in Brazil. */
196
+ const FIRST_NAMES = [
197
+ "Ada",
198
+ "Alan",
199
+ "Grace",
200
+ "Linus",
201
+ "Edsger",
202
+ "Barbara",
203
+ "Katherine",
204
+ "Dennis",
205
+ "Margaret",
206
+ "Donald",
207
+ "Anita",
208
+ "Tim",
209
+ "Radia",
210
+ "Ken",
211
+ "Frances",
212
+ "Vint",
213
+ "Ana",
214
+ "Bruno",
215
+ "Camila",
216
+ "Diego",
217
+ "Eduarda",
218
+ "Felipe",
219
+ "Gabriela",
220
+ "Heitor",
221
+ "Isabela",
222
+ "João",
223
+ "Larissa",
224
+ "Mateus",
225
+ "Natália",
226
+ "Otávio",
227
+ "Paula",
228
+ "Rafael",
229
+ "Sofia",
230
+ "Thiago",
231
+ "Valentina",
232
+ "Yuri",
233
+ "Beatriz",
234
+ "Caio",
235
+ "Débora",
236
+ "Enzo"
237
+ ];
238
+ /** Family names, likewise mixed. */
239
+ const LAST_NAMES = [
240
+ "Lovelace",
241
+ "Turing",
242
+ "Hopper",
243
+ "Torvalds",
244
+ "Dijkstra",
245
+ "Liskov",
246
+ "Johnson",
247
+ "Ritchie",
248
+ "Hamilton",
249
+ "Knuth",
250
+ "Borg",
251
+ "Berners-Lee",
252
+ "Perlman",
253
+ "Thompson",
254
+ "Allen",
255
+ "Cerf",
256
+ "Silva",
257
+ "Santos",
258
+ "Oliveira",
259
+ "Souza",
260
+ "Rodrigues",
261
+ "Ferreira",
262
+ "Almeida",
263
+ "Costa",
264
+ "Gomes",
265
+ "Martins",
266
+ "Araújo",
267
+ "Melo",
268
+ "Barbosa",
269
+ "Ribeiro",
270
+ "Carvalho",
271
+ "Pereira",
272
+ "Lima",
273
+ "Moreira",
274
+ "Cardoso",
275
+ "Teixeira",
276
+ "Correia"
277
+ ];
278
+ /** Honorifics that precede a name. */
279
+ const NAME_PREFIXES = [
280
+ "Dr.",
281
+ "Dra.",
282
+ "Sr.",
283
+ "Sra.",
284
+ "Prof.",
285
+ "Eng."
286
+ ];
287
+ /** Generational suffixes that follow a name. */
288
+ const NAME_SUFFIXES = [
289
+ "Jr.",
290
+ "Neto",
291
+ "Filho",
292
+ "II",
293
+ "III"
294
+ ];
295
+ /** Gender values shaped the way most forms model them. */
296
+ const GENDERS = [
297
+ "female",
298
+ "male",
299
+ "non-binary",
300
+ "prefer not to say"
301
+ ];
302
+ //#endregion
303
+ //#region src/faker/data/places.ts
304
+ const CITIES = [
305
+ "Lisbon",
306
+ "Porto",
307
+ "Amsterdam",
308
+ "Berlin",
309
+ "Toronto",
310
+ "Austin",
311
+ "Dublin",
312
+ "Wellington",
313
+ "Reykjavík",
314
+ "Kyoto",
315
+ "Montréal",
316
+ "Helsinki",
317
+ "Tallinn",
318
+ "Bergen"
319
+ ];
320
+ const COUNTRIES = [
321
+ ["Brazil", "BR"],
322
+ ["Portugal", "PT"],
323
+ ["Netherlands", "NL"],
324
+ ["Germany", "DE"],
325
+ ["Canada", "CA"],
326
+ ["United States", "US"],
327
+ ["Ireland", "IE"],
328
+ ["New Zealand", "NZ"],
329
+ ["Japan", "JP"],
330
+ ["Finland", "FI"],
331
+ ["Estonia", "EE"],
332
+ ["Norway", "NO"]
333
+ ];
334
+ const STREET_TYPES = [
335
+ "Street",
336
+ "Avenue",
337
+ "Road",
338
+ "Lane",
339
+ "Way",
340
+ "Square"
341
+ ];
342
+ const TIMEZONES = [
343
+ "America/Sao_Paulo",
344
+ "America/New_York",
345
+ "Europe/Lisbon",
346
+ "Europe/Berlin",
347
+ "Europe/Helsinki",
348
+ "Asia/Tokyo",
349
+ "Pacific/Auckland",
350
+ "UTC"
351
+ ];
352
+ /** Brazilian federal units, as `[name, code]`. */
353
+ const BR_STATES = [
354
+ ["São Paulo", "SP"],
355
+ ["Rio de Janeiro", "RJ"],
356
+ ["Minas Gerais", "MG"],
357
+ ["Bahia", "BA"],
358
+ ["Paraná", "PR"],
359
+ ["Rio Grande do Sul", "RS"],
360
+ ["Pernambuco", "PE"],
361
+ ["Ceará", "CE"],
362
+ ["Santa Catarina", "SC"],
363
+ ["Goiás", "GO"],
364
+ ["Pará", "PA"],
365
+ ["Espírito Santo", "ES"],
366
+ ["Amazonas", "AM"],
367
+ ["Distrito Federal", "DF"]
368
+ ];
369
+ const BR_CITIES = [
370
+ "São Paulo",
371
+ "Rio de Janeiro",
372
+ "Belo Horizonte",
373
+ "Salvador",
374
+ "Curitiba",
375
+ "Porto Alegre",
376
+ "Recife",
377
+ "Fortaleza",
378
+ "Florianópolis",
379
+ "Goiânia",
380
+ "Belém",
381
+ "Vitória",
382
+ "Manaus",
383
+ "Brasília",
384
+ "Campinas",
385
+ "Uberlândia"
386
+ ];
387
+ const BR_STREET_TYPES = [
388
+ "Rua",
389
+ "Avenida",
390
+ "Travessa",
391
+ "Alameda",
392
+ "Praça"
393
+ ];
394
+ const BR_STREET_NAMES = [
395
+ "das Flores",
396
+ "Sete de Setembro",
397
+ "Getúlio Vargas",
398
+ "XV de Novembro",
399
+ "Santos Dumont",
400
+ "do Comércio",
401
+ "Paulista",
402
+ "Brasil",
403
+ "das Palmeiras",
404
+ "Tiradentes"
405
+ ];
406
+ //#endregion
407
+ //#region src/faker/data/web.ts
408
+ /** Reserved by RFC 2606/6761, so a generated address never resolves to anyone real. */
409
+ const SAFE_DOMAINS = [
410
+ "example.test",
411
+ "example.com",
412
+ "example.org",
413
+ "example.net",
414
+ "test.invalid"
415
+ ];
416
+ const TLDS = [
417
+ "com",
418
+ "org",
419
+ "net",
420
+ "io",
421
+ "dev",
422
+ "app",
423
+ "com.br"
424
+ ];
425
+ const HTTP_METHODS = [
426
+ "GET",
427
+ "POST",
428
+ "PUT",
429
+ "PATCH",
430
+ "DELETE",
431
+ "HEAD",
432
+ "OPTIONS"
433
+ ];
434
+ const HTTP_STATUSES = [
435
+ 200,
436
+ 201,
437
+ 202,
438
+ 204,
439
+ 301,
440
+ 302,
441
+ 304,
442
+ 400,
443
+ 401,
444
+ 403,
445
+ 404,
446
+ 409,
447
+ 422,
448
+ 429,
449
+ 500,
450
+ 502,
451
+ 503
452
+ ];
453
+ const MIME_TYPES = [
454
+ "application/json",
455
+ "text/html",
456
+ "text/plain",
457
+ "text/csv",
458
+ "application/pdf",
459
+ "image/png",
460
+ "image/jpeg",
461
+ "image/svg+xml",
462
+ "application/octet-stream"
463
+ ];
464
+ const USER_AGENTS = [
465
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36",
466
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15",
467
+ "Mozilla/5.0 (X11; Linux x86_64; rv:127.0) Gecko/20100101 Firefox/127.0",
468
+ "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
469
+ ];
470
+ const PROTOCOLS = ["https", "http"];
471
+ //#endregion
472
+ //#region src/faker/data/words.ts
473
+ /** Classic lorem vocabulary: filler text that is obviously filler. */
474
+ const LOREM = [
475
+ "lorem",
476
+ "ipsum",
477
+ "dolor",
478
+ "sit",
479
+ "amet",
480
+ "consectetur",
481
+ "adipiscing",
482
+ "elit",
483
+ "sed",
484
+ "do",
485
+ "eiusmod",
486
+ "tempor",
487
+ "incididunt",
488
+ "ut",
489
+ "labore",
490
+ "et",
491
+ "dolore",
492
+ "magna",
493
+ "aliqua",
494
+ "enim",
495
+ "ad",
496
+ "minim",
497
+ "veniam",
498
+ "quis",
499
+ "nostrud",
500
+ "exercitation",
501
+ "ullamco",
502
+ "laboris",
503
+ "nisi",
504
+ "aliquip",
505
+ "ex",
506
+ "ea",
507
+ "commodo",
508
+ "consequat",
509
+ "duis",
510
+ "aute",
511
+ "irure",
512
+ "in",
513
+ "reprehenderit",
514
+ "voluptate",
515
+ "velit",
516
+ "esse",
517
+ "cillum",
518
+ "eu",
519
+ "fugiat",
520
+ "nulla",
521
+ "pariatur",
522
+ "excepteur",
523
+ "sint",
524
+ "occaecat",
525
+ "cupidatat",
526
+ "non",
527
+ "proident",
528
+ "culpa",
529
+ "officia",
530
+ "deserunt",
531
+ "mollit",
532
+ "anim",
533
+ "id",
534
+ "est",
535
+ "laborum"
536
+ ];
537
+ /** Adjectives, for product and project names. */
538
+ const ADJECTIVES = [
539
+ "quiet",
540
+ "bright",
541
+ "rapid",
542
+ "solid",
543
+ "gentle",
544
+ "bold",
545
+ "clever",
546
+ "plain",
547
+ "sturdy",
548
+ "sleek",
549
+ "warm",
550
+ "crisp",
551
+ "amber",
552
+ "hollow",
553
+ "northern",
554
+ "silent"
555
+ ];
556
+ /** Concrete nouns, for the same. */
557
+ const NOUNS = [
558
+ "harbour",
559
+ "lantern",
560
+ "meadow",
561
+ "compass",
562
+ "anchor",
563
+ "ridge",
564
+ "beacon",
565
+ "quarry",
566
+ "willow",
567
+ "falcon",
568
+ "cascade",
569
+ "summit",
570
+ "orchard",
571
+ "canyon",
572
+ "delta",
573
+ "ember"
574
+ ];
575
+ //#endregion
576
+ //#region src/faker/primitives.ts
577
+ const COMBINING = /[\u0300-\u036f]/g;
578
+ const DIGITS = "0123456789";
579
+ const HEX = "0123456789abcdef";
580
+ const LOWER = "abcdefghijklmnopqrstuvwxyz";
581
+ const ALNUM = `${LOWER}${LOWER.toUpperCase()}${DIGITS}`;
582
+ /** Pick one item from a list. Drawing from an empty list is a programming error. */
583
+ function pick(items, rng) {
584
+ const chosen = items[Math.floor(rng() * items.length)];
585
+ if (chosen === void 0) throw new Error("faker: cannot pick from an empty list");
586
+ return chosen;
587
+ }
588
+ /** An integer in the inclusive range [min, max]. */
589
+ function intBetween(args) {
590
+ return args.min + Math.floor(args.rng() * (args.max - args.min + 1));
591
+ }
592
+ /** A number in [min, max), rounded to `decimals` places. */
593
+ function floatBetween(args) {
594
+ const raw = args.min + args.rng() * (args.max - args.min);
595
+ return Number(raw.toFixed(args.decimals));
596
+ }
597
+ /** `count` characters drawn from `alphabet`. */
598
+ function chars(args) {
599
+ let out = "";
600
+ for (let index = 0; index < args.count; index += 1) out += args.alphabet.charAt(Math.floor(args.rng() * args.alphabet.length));
601
+ return out;
602
+ }
603
+ /** `count` decimal digits, e.g. `"40721"`. */
604
+ function digits(count, rng) {
605
+ return chars({
606
+ count,
607
+ alphabet: DIGITS,
608
+ rng
609
+ });
610
+ }
611
+ /** Upper-case the first character, leaving the rest alone. */
612
+ function capitalize(word) {
613
+ return word.charAt(0).toUpperCase() + word.slice(1);
614
+ }
615
+ /** Zero-pad a number to `width` digits. */
616
+ function pad(value, width) {
617
+ return String(value).padStart(width, "0");
618
+ }
619
+ /** Strip diacritics so a name can become an email local part or a URL slug. */
620
+ function ascii(text) {
621
+ return text.normalize("NFD").replace(COMBINING, "");
622
+ }
623
+ /** ASCII-safe lowercase slug: `"João Gonçalves"` → `"joao-goncalves"`. */
624
+ function slug(text) {
625
+ return ascii(text).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
626
+ }
627
+ /** Read a positional argument as a number, falling back when it is absent. */
628
+ function numArg(args, index, fallback) {
629
+ const raw = Number(args[index]);
630
+ return args[index] === void 0 || Number.isNaN(raw) ? fallback : raw;
631
+ }
632
+ /** Build `count` values, each drawn independently. */
633
+ function times(count, make) {
634
+ return Array.from({ length: count }, make);
635
+ }
636
+ //#endregion
637
+ //#region src/faker/address.ts
638
+ function street$1(rng) {
639
+ return `${capitalize(pick(NOUNS, rng))} ${pick(STREET_TYPES, rng)}`;
640
+ }
641
+ function streetAddress(rng) {
642
+ return `${intBetween({
643
+ min: 1,
644
+ max: 9999,
645
+ rng
646
+ })} ${street$1(rng)}`;
647
+ }
648
+ function country(rng) {
649
+ return pick(COUNTRIES, rng)[0];
650
+ }
651
+ function countryCode(rng) {
652
+ return pick(COUNTRIES, rng)[1];
653
+ }
654
+ /** A one-line postal address, the shape a shipping form expects. */
655
+ function address$1(rng) {
656
+ return `${streetAddress(rng)}, ${pick(CITIES, rng)} ${digits(5, rng)}, ${country(rng)}`;
657
+ }
658
+ const addressSpecs = [
659
+ {
660
+ name: "street",
661
+ doc: "A street name.",
662
+ result: t.string,
663
+ make: street$1
664
+ },
665
+ {
666
+ name: "streetAddress",
667
+ doc: "A street name with a building number.",
668
+ result: t.string,
669
+ make: streetAddress
670
+ },
671
+ {
672
+ name: "address",
673
+ doc: "A full one-line postal address.",
674
+ result: t.string,
675
+ make: address$1
676
+ },
677
+ {
678
+ name: "buildingNumber",
679
+ doc: "A building number.",
680
+ result: t.number,
681
+ make: (rng) => intBetween({
682
+ min: 1,
683
+ max: 9999,
684
+ rng
685
+ })
686
+ },
687
+ {
688
+ name: "city",
689
+ doc: "A city name.",
690
+ result: t.string,
691
+ make: (rng) => pick(CITIES, rng)
692
+ },
693
+ {
694
+ name: "country",
695
+ doc: "A country name.",
696
+ result: t.string,
697
+ make: country
698
+ },
699
+ {
700
+ name: "countryCode",
701
+ doc: "An ISO 3166-1 alpha-2 code.",
702
+ result: t.string,
703
+ make: countryCode
704
+ },
705
+ {
706
+ name: "zip",
707
+ doc: "A five-digit postal code.",
708
+ result: t.string,
709
+ make: (rng) => digits(5, rng)
710
+ },
711
+ {
712
+ name: "latitude",
713
+ doc: "A latitude in degrees, between -90 and 90.",
714
+ result: t.number,
715
+ make: (rng) => floatBetween({
716
+ min: -90,
717
+ max: 90,
718
+ decimals: 6,
719
+ rng
720
+ })
721
+ },
722
+ {
723
+ name: "longitude",
724
+ doc: "A longitude in degrees, between -180 and 180.",
725
+ result: t.number,
726
+ make: (rng) => floatBetween({
727
+ min: -180,
728
+ max: 180,
729
+ decimals: 6,
730
+ rng
731
+ })
732
+ },
733
+ {
734
+ name: "timezone",
735
+ doc: "An IANA time zone name.",
736
+ result: t.string,
737
+ make: (rng) => pick(TIMEZONES, rng)
738
+ }
739
+ ];
740
+ //#endregion
741
+ //#region src/faker/brazil-documents.ts
742
+ /**
743
+ * The two CPF check digits.
744
+ *
745
+ * @param base The first nine digits, unformatted.
746
+ * @returns Two digits to append.
747
+ */
748
+ function cpfDigits(base) {
749
+ const first = cpfDigit(base, 10);
750
+ return `${first}${cpfDigit(`${base}${first}`, 11)}`;
751
+ }
752
+ function cpfDigit(base, weight) {
753
+ let sum = 0;
754
+ for (let index = 0; index < base.length; index += 1) sum += Number(base[index]) * (weight - index);
755
+ const rest = sum * 10 % 11;
756
+ return String(rest === 10 ? 0 : rest);
757
+ }
758
+ const CNPJ_WEIGHTS = [
759
+ 6,
760
+ 5,
761
+ 4,
762
+ 3,
763
+ 2,
764
+ 9,
765
+ 8,
766
+ 7,
767
+ 6,
768
+ 5,
769
+ 4,
770
+ 3,
771
+ 2
772
+ ];
773
+ /**
774
+ * The two CNPJ check digits.
775
+ *
776
+ * @param base The first twelve digits, unformatted.
777
+ * @returns Two digits to append.
778
+ */
779
+ function cnpjDigits(base) {
780
+ const first = cnpjDigit(base);
781
+ return `${first}${cnpjDigit(`${base}${first}`)}`;
782
+ }
783
+ function cnpjDigit(base) {
784
+ const weights = CNPJ_WEIGHTS.slice(CNPJ_WEIGHTS.length - base.length);
785
+ let sum = 0;
786
+ for (let index = 0; index < base.length; index += 1) sum += Number(base[index]) * (weights[index] ?? 0);
787
+ const rest = sum % 11;
788
+ return String(rest < 2 ? 0 : 11 - rest);
789
+ }
790
+ //#endregion
791
+ //#region src/faker/brazil.ts
792
+ /** A CPF with correct check digits, formatted `000.000.000-00`. */
793
+ function cpf(rng) {
794
+ const base = digits(9, rng);
795
+ const full = `${base}${cpfDigits(base)}`;
796
+ return `${full.slice(0, 3)}.${full.slice(3, 6)}.${full.slice(6, 9)}-${full.slice(9)}`;
797
+ }
798
+ /** A CNPJ with correct check digits, formatted `00.000.000/0001-00`. */
799
+ function cnpj(rng) {
800
+ const base = `${digits(8, rng)}0001`;
801
+ const full = `${base}${cnpjDigits(base)}`;
802
+ return `${full.slice(0, 2)}.${full.slice(2, 5)}.${full.slice(5, 8)}/${full.slice(8, 12)}-${full.slice(12)}`;
803
+ }
804
+ function cep(rng) {
805
+ return `${digits(5, rng)}-${digits(3, rng)}`;
806
+ }
807
+ /** A mobile number, `(11) 9XXXX-XXXX`. */
808
+ function phone$1(rng) {
809
+ return `(${intBetween({
810
+ min: 11,
811
+ max: 99,
812
+ rng
813
+ })}) 9${digits(4, rng)}-${digits(4, rng)}`;
814
+ }
815
+ /** A Mercosul plate, `ABC1D23`. */
816
+ function plate(rng) {
817
+ const letters = (count) => chars({
818
+ count,
819
+ alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
820
+ rng
821
+ });
822
+ return `${letters(3)}${digits(1, rng)}${letters(1)}${digits(2, rng)}`;
823
+ }
824
+ function street(rng) {
825
+ return `${pick(BR_STREET_TYPES, rng)} ${pick(BR_STREET_NAMES, rng)}`;
826
+ }
827
+ function address(rng) {
828
+ const state = pick(BR_STATES, rng)[1];
829
+ const number = intBetween({
830
+ min: 1,
831
+ max: 4e3,
832
+ rng
833
+ });
834
+ return `${street(rng)}, ${number} — ${pick(BR_CITIES, rng)}/${state}, ${cep(rng)}`;
835
+ }
836
+ const brazilSpecs = [
837
+ {
838
+ name: "br.cpf",
839
+ doc: "A CPF with valid check digits.",
840
+ result: t.string,
841
+ make: cpf
842
+ },
843
+ {
844
+ name: "br.cnpj",
845
+ doc: "A CNPJ with valid check digits.",
846
+ result: t.string,
847
+ make: cnpj
848
+ },
849
+ {
850
+ name: "br.cep",
851
+ doc: "A postal code as `00000-000`.",
852
+ result: t.string,
853
+ make: cep
854
+ },
855
+ {
856
+ name: "br.phone",
857
+ doc: "A Brazilian mobile number.",
858
+ result: t.string,
859
+ make: phone$1
860
+ },
861
+ {
862
+ name: "br.plate",
863
+ doc: "A Mercosul licence plate.",
864
+ result: t.string,
865
+ make: plate
866
+ },
867
+ {
868
+ name: "br.street",
869
+ doc: "A Brazilian street name.",
870
+ result: t.string,
871
+ make: street
872
+ },
873
+ {
874
+ name: "br.address",
875
+ doc: "A full Brazilian address.",
876
+ result: t.string,
877
+ make: address
878
+ },
879
+ {
880
+ name: "br.city",
881
+ doc: "A Brazilian city.",
882
+ result: t.string,
883
+ make: (rng) => pick(BR_CITIES, rng)
884
+ },
885
+ {
886
+ name: "br.state",
887
+ doc: "A Brazilian federal unit, by name.",
888
+ result: t.string,
889
+ make: (rng) => pick(BR_STATES, rng)[0]
890
+ },
891
+ {
892
+ name: "br.stateCode",
893
+ doc: "A Brazilian federal unit, by two-letter code.",
894
+ result: t.string,
895
+ make: (rng) => pick(BR_STATES, rng)[1]
896
+ }
897
+ ];
898
+ //#endregion
899
+ //#region src/faker/check-digits.ts
900
+ /**
901
+ * The Luhn check digit for a card number.
902
+ *
903
+ * @param base The digits preceding the check digit.
904
+ * @returns One digit. Appending it makes `base` pass the Luhn test.
905
+ */
906
+ function luhnDigit(base) {
907
+ let sum = 0;
908
+ let double = true;
909
+ for (let index = base.length - 1; index >= 0; index -= 1) {
910
+ const scaled = Number(base[index]) * (double ? 2 : 1);
911
+ sum += scaled > 9 ? scaled - 9 : scaled;
912
+ double = !double;
913
+ }
914
+ return String((10 - sum % 10) % 10);
915
+ }
916
+ /**
917
+ * The EAN-13 check digit for the leading 12 digits of a barcode.
918
+ *
919
+ * @param base Exactly 12 digits.
920
+ * @returns The thirteenth digit.
921
+ */
922
+ function eanDigit(base) {
923
+ let sum = 0;
924
+ for (let index = 0; index < base.length; index += 1) sum += Number(base[index]) * (index % 2 === 0 ? 1 : 3);
925
+ return String((10 - sum % 10) % 10);
926
+ }
927
+ /**
928
+ * The two IBAN check digits: mod-97 over the rearranged, letter-expanded account.
929
+ *
930
+ * @param country The two-letter country code, upper case.
931
+ * @param account The account part, without check digits.
932
+ * @returns Two digits, zero-padded, to be inserted after the country code.
933
+ */
934
+ function ibanCheck(country, account) {
935
+ return pad(98 - mod97(`${account}${country}00`.replace(/[A-Z]/g, (letter) => String(letter.charCodeAt(0) - 55))), 2);
936
+ }
937
+ /** Mod 97 digit by digit, because an expanded IBAN overflows `Number`. */
938
+ function mod97(value) {
939
+ let rest = 0;
940
+ for (const char of value) rest = (rest * 10 + Number(char)) % 97;
941
+ return rest;
942
+ }
943
+ //#endregion
944
+ //#region src/faker/commerce.ts
945
+ function productName(rng) {
946
+ return `${capitalize(pick(ADJECTIVES, rng))} ${pick(MATERIALS, rng)} ${pick(PRODUCTS, rng)}`;
947
+ }
948
+ function sku(rng) {
949
+ return `${chars({
950
+ count: 3,
951
+ alphabet: "ABCDEFGHJKLMNPQRSTUVWXYZ",
952
+ rng
953
+ })}-${digits(5, rng)}`;
954
+ }
955
+ /** A 13-digit EAN with a real check digit, so barcode validators accept it. */
956
+ function barcode(rng) {
957
+ const base = digits(12, rng);
958
+ return `${base}${eanDigit(base)}`;
959
+ }
960
+ const commerceSpecs = [
961
+ {
962
+ name: "product",
963
+ doc: "A product noun.",
964
+ result: t.string,
965
+ make: (rng) => pick(PRODUCTS, rng)
966
+ },
967
+ {
968
+ name: "productName",
969
+ doc: "A full product name.",
970
+ result: t.string,
971
+ make: productName
972
+ },
973
+ {
974
+ name: "sku",
975
+ doc: "A stock keeping unit.",
976
+ result: t.string,
977
+ make: sku
978
+ },
979
+ {
980
+ name: "barcode",
981
+ doc: "A valid EAN-13 barcode.",
982
+ result: t.string,
983
+ make: barcode
984
+ },
985
+ {
986
+ name: "category",
987
+ doc: "A product category.",
988
+ result: t.string,
989
+ make: (rng) => pick(CATEGORIES, rng)
990
+ },
991
+ {
992
+ name: "material",
993
+ doc: "A material, like `leather`.",
994
+ result: t.string,
995
+ make: (rng) => pick(MATERIALS, rng)
996
+ },
997
+ {
998
+ name: "color",
999
+ doc: "A colour name.",
1000
+ result: t.string,
1001
+ make: (rng) => pick(COLORS, rng)[0]
1002
+ },
1003
+ {
1004
+ name: "hexColor",
1005
+ doc: "A colour as a hex triplet, like `#1e88e5`.",
1006
+ result: t.string,
1007
+ make: (rng) => pick(COLORS, rng)[1]
1008
+ },
1009
+ {
1010
+ name: "price",
1011
+ doc: "A retail price with two decimal places.",
1012
+ result: t.number,
1013
+ make: (rng) => floatBetween({
1014
+ min: 5,
1015
+ max: 500,
1016
+ decimals: 2,
1017
+ rng
1018
+ })
1019
+ }
1020
+ ];
1021
+ //#endregion
1022
+ //#region src/faker/company.ts
1023
+ function company(rng) {
1024
+ return `${pick(COMPANY_ROOTS, rng)} ${pick(COMPANY_SUFFIXES, rng)}`;
1025
+ }
1026
+ function catchPhrase(rng) {
1027
+ return `${capitalize(pick(CATCH_VERBS, rng))} your ${pick(BUZZWORDS, rng)}`;
1028
+ }
1029
+ const companySpecs = [
1030
+ {
1031
+ name: "company",
1032
+ doc: "A company name.",
1033
+ result: t.string,
1034
+ make: company
1035
+ },
1036
+ {
1037
+ name: "department",
1038
+ doc: "A department name.",
1039
+ result: t.string,
1040
+ make: (rng) => pick(DEPARTMENTS, rng)
1041
+ },
1042
+ {
1043
+ name: "catchPhrase",
1044
+ doc: "A marketing catch phrase.",
1045
+ result: t.string,
1046
+ make: catchPhrase
1047
+ },
1048
+ {
1049
+ name: "buzzword",
1050
+ doc: "A single piece of business jargon.",
1051
+ result: t.string,
1052
+ make: (rng) => pick(BUZZWORDS, rng)
1053
+ }
1054
+ ];
1055
+ //#endregion
1056
+ //#region src/faker/datetime.ts
1057
+ /**
1058
+ * The instant every generated date is measured from.
1059
+ *
1060
+ * Dates hang off a fixed anchor rather than the wall clock: `Date.now()` would
1061
+ * give a different answer on every run and break the seeded replay guarantee.
1062
+ */
1063
+ const ANCHOR = Date.UTC(2025, 0, 1);
1064
+ const DAY = 864e5;
1065
+ const YEAR = 365 * DAY;
1066
+ const WEEKDAYS = [
1067
+ "Monday",
1068
+ "Tuesday",
1069
+ "Wednesday",
1070
+ "Thursday",
1071
+ "Friday",
1072
+ "Saturday",
1073
+ "Sunday"
1074
+ ];
1075
+ const MONTHS = [
1076
+ "January",
1077
+ "February",
1078
+ "March",
1079
+ "April",
1080
+ "May",
1081
+ "June",
1082
+ "July",
1083
+ "August",
1084
+ "September",
1085
+ "October",
1086
+ "November",
1087
+ "December"
1088
+ ];
1089
+ function offsetFrom(args) {
1090
+ return ANCHOR + intBetween({
1091
+ min: args.min,
1092
+ max: args.max,
1093
+ rng: args.rng
1094
+ });
1095
+ }
1096
+ /** `YYYY-MM-DD` within five years either side of the anchor. */
1097
+ function isoDate(rng) {
1098
+ const at = offsetFrom({
1099
+ rng,
1100
+ min: -5 * YEAR,
1101
+ max: 5 * YEAR
1102
+ });
1103
+ return new Date(at).toISOString().slice(0, 10);
1104
+ }
1105
+ function isoDateTime(rng) {
1106
+ return new Date(offsetFrom({
1107
+ rng,
1108
+ min: -5 * YEAR,
1109
+ max: 5 * YEAR
1110
+ })).toISOString();
1111
+ }
1112
+ function pastDate(rng) {
1113
+ return new Date(offsetFrom({
1114
+ rng,
1115
+ min: -5 * YEAR,
1116
+ max: -864e5
1117
+ })).toISOString();
1118
+ }
1119
+ function futureDate(rng) {
1120
+ return new Date(offsetFrom({
1121
+ rng,
1122
+ min: DAY,
1123
+ max: 5 * YEAR
1124
+ })).toISOString();
1125
+ }
1126
+ /** `HH:MM:SS` on a 24-hour clock. */
1127
+ function time(rng) {
1128
+ const part = (max) => pad(intBetween({
1129
+ min: 0,
1130
+ max,
1131
+ rng
1132
+ }), 2);
1133
+ return `${part(23)}:${part(59)}:${part(59)}`;
1134
+ }
1135
+ /** Seconds since the epoch, the unit `exp` and `iat` claims use. */
1136
+ function timestamp(rng) {
1137
+ return Math.floor(offsetFrom({
1138
+ rng,
1139
+ min: -5 * YEAR,
1140
+ max: 5 * YEAR
1141
+ }) / 1e3);
1142
+ }
1143
+ const datetimeSpecs = [
1144
+ {
1145
+ name: "date",
1146
+ doc: "A date as `YYYY-MM-DD`.",
1147
+ result: t.string,
1148
+ make: isoDate
1149
+ },
1150
+ {
1151
+ name: "dateTime",
1152
+ doc: "An ISO 8601 instant.",
1153
+ result: t.string,
1154
+ make: isoDateTime
1155
+ },
1156
+ {
1157
+ name: "pastDate",
1158
+ doc: "An ISO 8601 instant before the anchor.",
1159
+ result: t.string,
1160
+ make: pastDate
1161
+ },
1162
+ {
1163
+ name: "futureDate",
1164
+ doc: "An ISO 8601 instant after the anchor.",
1165
+ result: t.string,
1166
+ make: futureDate
1167
+ },
1168
+ {
1169
+ name: "time",
1170
+ doc: "A time of day as `HH:MM:SS`.",
1171
+ result: t.string,
1172
+ make: time
1173
+ },
1174
+ {
1175
+ name: "timestamp",
1176
+ doc: "Seconds since the Unix epoch.",
1177
+ result: t.number,
1178
+ make: timestamp
1179
+ },
1180
+ {
1181
+ name: "weekday",
1182
+ doc: "A day of the week.",
1183
+ result: t.string,
1184
+ make: (rng) => pick(WEEKDAYS, rng)
1185
+ },
1186
+ {
1187
+ name: "month",
1188
+ doc: "A month name.",
1189
+ result: t.string,
1190
+ make: (rng) => pick(MONTHS, rng)
1191
+ },
1192
+ {
1193
+ name: "year",
1194
+ doc: "A year. `faker.year(2000, 2030)` bounds it.",
1195
+ result: t.number,
1196
+ args: [optionalArg("from", t.number, "The earliest year, included."), optionalArg("to", t.number, "The latest year, included.")],
1197
+ make: (rng, args) => intBetween({
1198
+ min: numArg(args, 0, 1980),
1199
+ max: numArg(args, 1, 2030),
1200
+ rng
1201
+ })
1202
+ }
1203
+ ];
1204
+ //#endregion
1205
+ //#region src/faker/finance.ts
1206
+ /** A 16-digit card number that passes Luhn, grouped `#### #### #### ####`. */
1207
+ function creditCard(rng) {
1208
+ const [, prefix, length] = pick(CARD_BRANDS, rng);
1209
+ const base = `${prefix}${digits(length - prefix.length - 1, rng)}`;
1210
+ return (`${base}${luhnDigit(base)}`.match(/.{1,4}/g) ?? []).join(" ");
1211
+ }
1212
+ function expiryDate(rng) {
1213
+ return `${pad(intBetween({
1214
+ min: 1,
1215
+ max: 12,
1216
+ rng
1217
+ }), 2)}/${intBetween({
1218
+ min: 26,
1219
+ max: 34,
1220
+ rng
1221
+ })}`;
1222
+ }
1223
+ /** An IBAN with correct mod-97 check digits. */
1224
+ function iban(rng) {
1225
+ const country = "DE";
1226
+ const account = digits(18, rng);
1227
+ return `${country}${ibanCheck(country, account)}${account}`;
1228
+ }
1229
+ function bic(rng) {
1230
+ const letters = (count) => chars({
1231
+ count,
1232
+ alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
1233
+ rng
1234
+ });
1235
+ return `${letters(4)}${letters(2)}${letters(2)}`;
1236
+ }
1237
+ const financeSpecs = [
1238
+ {
1239
+ name: "creditCard",
1240
+ doc: "A 16-digit card number that passes the Luhn check.",
1241
+ result: t.string,
1242
+ make: creditCard
1243
+ },
1244
+ {
1245
+ name: "cardType",
1246
+ doc: "A card brand, like `Visa`.",
1247
+ result: t.string,
1248
+ make: (rng) => pick(CARD_BRANDS, rng)[0]
1249
+ },
1250
+ {
1251
+ name: "cvv",
1252
+ doc: "A three-digit card security code.",
1253
+ result: t.string,
1254
+ make: (rng) => digits(3, rng)
1255
+ },
1256
+ {
1257
+ name: "expiryDate",
1258
+ doc: "A card expiry as `MM/YY`.",
1259
+ result: t.string,
1260
+ make: expiryDate
1261
+ },
1262
+ {
1263
+ name: "iban",
1264
+ doc: "An IBAN with valid check digits.",
1265
+ result: t.string,
1266
+ make: iban
1267
+ },
1268
+ {
1269
+ name: "bic",
1270
+ doc: "A SWIFT/BIC code.",
1271
+ result: t.string,
1272
+ make: bic
1273
+ },
1274
+ {
1275
+ name: "accountNumber",
1276
+ doc: "A bank account number.",
1277
+ result: t.string,
1278
+ make: (rng) => digits(10, rng)
1279
+ },
1280
+ {
1281
+ name: "currencyCode",
1282
+ doc: "An ISO 4217 currency code, like `BRL`.",
1283
+ result: t.string,
1284
+ make: (rng) => pick(CURRENCIES, rng)[0]
1285
+ },
1286
+ {
1287
+ name: "currencySymbol",
1288
+ doc: "A currency symbol, like `R$`.",
1289
+ result: t.string,
1290
+ make: (rng) => pick(CURRENCIES, rng)[1]
1291
+ },
1292
+ {
1293
+ name: "currencyName",
1294
+ doc: "A currency name, like `Brazilian Real`.",
1295
+ result: t.string,
1296
+ make: (rng) => pick(CURRENCIES, rng)[2]
1297
+ },
1298
+ {
1299
+ name: "amount",
1300
+ doc: "A monetary amount with two decimal places.",
1301
+ result: t.number,
1302
+ make: (rng) => floatBetween({
1303
+ min: 1,
1304
+ max: 1e4,
1305
+ decimals: 2,
1306
+ rng
1307
+ })
1308
+ }
1309
+ ];
1310
+ //#endregion
1311
+ //#region src/faker/ids.ts
1312
+ /** An RFC 4122 v4 UUID. The version and variant bits are stamped, not drawn. */
1313
+ function uuid(rng) {
1314
+ const hex = (count) => chars({
1315
+ count,
1316
+ alphabet: HEX,
1317
+ rng
1318
+ });
1319
+ const variant = "89ab".charAt(Math.floor(rng() * 4));
1320
+ return `${hex(8)}-${hex(4)}-4${hex(3)}-${variant}${hex(3)}-${hex(12)}`;
1321
+ }
1322
+ const NANO_ALPHABET = `${ALNUM}_-`;
1323
+ const idSpecs = [
1324
+ {
1325
+ name: "uuid",
1326
+ doc: "A v4 UUID.",
1327
+ result: t.string,
1328
+ make: uuid
1329
+ },
1330
+ {
1331
+ name: "nanoid",
1332
+ doc: "A 21-character NanoID. `faker.nanoid(10)` sets the length.",
1333
+ result: t.string,
1334
+ args: [optionalArg("length", t.number, "How many characters. 21 by default.")],
1335
+ make: (rng, args) => chars({
1336
+ count: numArg(args, 0, 21),
1337
+ alphabet: NANO_ALPHABET,
1338
+ rng
1339
+ })
1340
+ },
1341
+ {
1342
+ name: "objectId",
1343
+ doc: "A 24-character MongoDB ObjectId.",
1344
+ result: t.string,
1345
+ make: (rng) => chars({
1346
+ count: 24,
1347
+ alphabet: HEX,
1348
+ rng
1349
+ })
1350
+ },
1351
+ {
1352
+ name: "hex",
1353
+ doc: "Hex characters. `faker.hex(32)` sets how many.",
1354
+ result: t.string,
1355
+ args: [optionalArg("length", t.number, "How many characters.")],
1356
+ make: (rng, args) => chars({
1357
+ count: numArg(args, 0, 16),
1358
+ alphabet: HEX,
1359
+ rng
1360
+ })
1361
+ },
1362
+ {
1363
+ name: "token",
1364
+ doc: "A 32-character opaque token.",
1365
+ result: t.string,
1366
+ make: (rng) => chars({
1367
+ count: 32,
1368
+ alphabet: ALNUM,
1369
+ rng
1370
+ })
1371
+ },
1372
+ {
1373
+ name: "alphanumeric",
1374
+ doc: "Letters and digits. `faker.alphanumeric(8)` sets how many.",
1375
+ result: t.string,
1376
+ args: [optionalArg("length", t.number, "How many characters.")],
1377
+ make: (rng, args) => chars({
1378
+ count: numArg(args, 0, 8),
1379
+ alphabet: ALNUM,
1380
+ rng
1381
+ })
1382
+ },
1383
+ {
1384
+ name: "digits",
1385
+ doc: "Decimal digits. `faker.digits(6)` sets how many.",
1386
+ result: t.string,
1387
+ args: [optionalArg("length", t.number, "How many digits.")],
1388
+ make: (rng, args) => digits(numArg(args, 0, 6), rng)
1389
+ },
1390
+ {
1391
+ name: "int",
1392
+ doc: "An integer. `faker.int(1, 10)` bounds it, inclusive.",
1393
+ result: t.number,
1394
+ args: [optionalArg("min", t.number, "The lowest it may be, included."), optionalArg("max", t.number, "The highest it may be, included.")],
1395
+ make: (rng, args) => intBetween({
1396
+ min: numArg(args, 0, 0),
1397
+ max: numArg(args, 1, 100),
1398
+ rng
1399
+ })
1400
+ },
1401
+ {
1402
+ name: "float",
1403
+ doc: "A number with two decimals. `faker.float(0, 1)` bounds it.",
1404
+ result: t.number,
1405
+ args: [optionalArg("min", t.number, "The lowest it may be."), optionalArg("max", t.number, "The highest it may be.")],
1406
+ make: (rng, args) => floatBetween({
1407
+ min: numArg(args, 0, 0),
1408
+ max: numArg(args, 1, 1),
1409
+ decimals: 2,
1410
+ rng
1411
+ })
1412
+ },
1413
+ {
1414
+ name: "boolean",
1415
+ doc: "`true` or `false`.",
1416
+ result: t.bool,
1417
+ make: (rng) => rng() < .5
1418
+ }
1419
+ ];
1420
+ //#endregion
1421
+ //#region src/faker/person.ts
1422
+ /** A given name, e.g. `"Grace"`. */
1423
+ function firstName(rng) {
1424
+ return pick(FIRST_NAMES, rng);
1425
+ }
1426
+ /** A family name, e.g. `"Hopper"`. */
1427
+ function lastName(rng) {
1428
+ return pick(LAST_NAMES, rng);
1429
+ }
1430
+ /** A full name, e.g. `"Grace Hopper"`. */
1431
+ function fullName(rng) {
1432
+ return `${firstName(rng)} ${lastName(rng)}`;
1433
+ }
1434
+ function birthDate(rng) {
1435
+ const year = intBetween({
1436
+ min: 1950,
1437
+ max: 2006,
1438
+ rng
1439
+ });
1440
+ const month = intBetween({
1441
+ min: 1,
1442
+ max: 12,
1443
+ rng
1444
+ });
1445
+ const day = intBetween({
1446
+ min: 1,
1447
+ max: 28,
1448
+ rng
1449
+ });
1450
+ return `${year}-${pad(month, 2)}-${pad(day, 2)}`;
1451
+ }
1452
+ /** `+1 555 01xx`, the range reserved for fiction, so it can never reach anyone. */
1453
+ function phone(rng) {
1454
+ return `+1 555 01${digits(2, rng)}`;
1455
+ }
1456
+ const personSpecs = [
1457
+ {
1458
+ name: "firstName",
1459
+ doc: "A given name.",
1460
+ result: t.string,
1461
+ make: firstName
1462
+ },
1463
+ {
1464
+ name: "lastName",
1465
+ doc: "A family name.",
1466
+ result: t.string,
1467
+ make: lastName
1468
+ },
1469
+ {
1470
+ name: "name",
1471
+ doc: "A full name.",
1472
+ result: t.string,
1473
+ make: fullName
1474
+ },
1475
+ {
1476
+ name: "fullName",
1477
+ doc: "A full name.",
1478
+ result: t.string,
1479
+ make: fullName
1480
+ },
1481
+ {
1482
+ name: "prefix",
1483
+ doc: "An honorific that precedes a name, like `Dra.`.",
1484
+ result: t.string,
1485
+ make: (rng) => pick(NAME_PREFIXES, rng)
1486
+ },
1487
+ {
1488
+ name: "suffix",
1489
+ doc: "A generational suffix that follows a name, like `Neto`.",
1490
+ result: t.string,
1491
+ make: (rng) => pick(NAME_SUFFIXES, rng)
1492
+ },
1493
+ {
1494
+ name: "gender",
1495
+ doc: "A gender value shaped the way most forms model them.",
1496
+ result: t.string,
1497
+ make: (rng) => pick(GENDERS, rng)
1498
+ },
1499
+ {
1500
+ name: "jobTitle",
1501
+ doc: "A job title, like `Site Reliability Engineer`.",
1502
+ result: t.string,
1503
+ make: (rng) => pick(JOB_TITLES, rng)
1504
+ },
1505
+ {
1506
+ name: "age",
1507
+ doc: "An adult age, between 18 and 80.",
1508
+ result: t.number,
1509
+ make: (rng) => intBetween({
1510
+ min: 18,
1511
+ max: 80,
1512
+ rng
1513
+ })
1514
+ },
1515
+ {
1516
+ name: "birthDate",
1517
+ doc: "A birth date as `YYYY-MM-DD`.",
1518
+ result: t.string,
1519
+ make: birthDate
1520
+ },
1521
+ {
1522
+ name: "phone",
1523
+ doc: "An international phone number in the range reserved for fiction.",
1524
+ result: t.string,
1525
+ make: phone
1526
+ }
1527
+ ];
1528
+ //#endregion
1529
+ //#region src/faker/internet.ts
1530
+ /** An email on a reserved domain, e.g. `"grace.hopper@example.test"`. It reaches nobody. */
1531
+ function email(rng) {
1532
+ return `${`${slug(firstName(rng))}.${slug(lastName(rng))}`}@${pick(SAFE_DOMAINS, rng)}`;
1533
+ }
1534
+ function username(rng) {
1535
+ return `${slug(firstName(rng))}${intBetween({
1536
+ min: 1,
1537
+ max: 99,
1538
+ rng
1539
+ })}`;
1540
+ }
1541
+ function password(rng) {
1542
+ return chars({
1543
+ count: 14,
1544
+ alphabet: `${ALNUM}!@#$%&*?`,
1545
+ rng
1546
+ });
1547
+ }
1548
+ function domain(rng) {
1549
+ return `${pick(ADJECTIVES, rng)}${pick(NOUNS, rng)}.${pick(TLDS, rng)}`;
1550
+ }
1551
+ function url(rng) {
1552
+ return `${pick(PROTOCOLS, rng)}://${domain(rng)}/${pick(NOUNS, rng)}`;
1553
+ }
1554
+ function ipv4(rng) {
1555
+ const octet = () => intBetween({
1556
+ min: 1,
1557
+ max: 254,
1558
+ rng
1559
+ });
1560
+ return `${octet()}.${octet()}.${octet()}.${octet()}`;
1561
+ }
1562
+ function ipv6(rng) {
1563
+ const group = () => chars({
1564
+ count: 4,
1565
+ alphabet: HEX,
1566
+ rng
1567
+ });
1568
+ return Array.from({ length: 8 }, group).join(":");
1569
+ }
1570
+ function mac(rng) {
1571
+ const pair = () => chars({
1572
+ count: 2,
1573
+ alphabet: HEX,
1574
+ rng
1575
+ }).toUpperCase();
1576
+ return Array.from({ length: 6 }, pair).join(":");
1577
+ }
1578
+ const internetSpecs = [
1579
+ {
1580
+ name: "email",
1581
+ doc: "An email address on a reserved domain.",
1582
+ result: t.string,
1583
+ make: email
1584
+ },
1585
+ {
1586
+ name: "username",
1587
+ doc: "A login name.",
1588
+ result: t.string,
1589
+ make: username
1590
+ },
1591
+ {
1592
+ name: "password",
1593
+ doc: "A 14-character password.",
1594
+ result: t.string,
1595
+ make: password
1596
+ },
1597
+ {
1598
+ name: "domain",
1599
+ doc: "A domain name.",
1600
+ result: t.string,
1601
+ make: domain
1602
+ },
1603
+ {
1604
+ name: "url",
1605
+ doc: "An absolute URL.",
1606
+ result: t.string,
1607
+ make: url
1608
+ },
1609
+ {
1610
+ name: "ipv4",
1611
+ doc: "An IPv4 address.",
1612
+ result: t.string,
1613
+ make: ipv4
1614
+ },
1615
+ {
1616
+ name: "ipv6",
1617
+ doc: "An IPv6 address.",
1618
+ result: t.string,
1619
+ make: ipv6
1620
+ },
1621
+ {
1622
+ name: "mac",
1623
+ doc: "A MAC address.",
1624
+ result: t.string,
1625
+ make: mac
1626
+ },
1627
+ {
1628
+ name: "port",
1629
+ doc: "An unprivileged TCP port.",
1630
+ result: t.number,
1631
+ make: (rng) => intBetween({
1632
+ min: 1024,
1633
+ max: 65535,
1634
+ rng
1635
+ })
1636
+ },
1637
+ {
1638
+ name: "userAgent",
1639
+ doc: "A browser User-Agent string.",
1640
+ result: t.string,
1641
+ make: (rng) => pick(USER_AGENTS, rng)
1642
+ },
1643
+ {
1644
+ name: "slug",
1645
+ doc: "A URL slug, like `bright-harbour-417`.",
1646
+ result: t.string,
1647
+ make: (rng) => `${pick(ADJECTIVES, rng)}-${pick(NOUNS, rng)}-${digits(3, rng)}`
1648
+ },
1649
+ {
1650
+ name: "httpMethod",
1651
+ doc: "An HTTP verb.",
1652
+ result: t.string,
1653
+ make: (rng) => pick(HTTP_METHODS, rng)
1654
+ },
1655
+ {
1656
+ name: "httpStatus",
1657
+ doc: "An HTTP status code that servers really return.",
1658
+ result: t.number,
1659
+ make: (rng) => pick(HTTP_STATUSES, rng)
1660
+ },
1661
+ {
1662
+ name: "mimeType",
1663
+ doc: "A MIME type.",
1664
+ result: t.string,
1665
+ make: (rng) => pick(MIME_TYPES, rng)
1666
+ }
1667
+ ];
1668
+ //#endregion
1669
+ //#region src/faker/text.ts
1670
+ function words(rng, count) {
1671
+ return times(count, () => pick(LOREM, rng)).join(" ");
1672
+ }
1673
+ /** A capitalised sentence of 6 to 14 words, ending in a full stop. */
1674
+ function sentence(rng) {
1675
+ return `${capitalize(words(rng, intBetween({
1676
+ min: 6,
1677
+ max: 14,
1678
+ rng
1679
+ })))}.`;
1680
+ }
1681
+ function sentences(rng, count) {
1682
+ return times(count, () => sentence(rng)).join(" ");
1683
+ }
1684
+ function paragraph(rng) {
1685
+ return sentences(rng, intBetween({
1686
+ min: 3,
1687
+ max: 6,
1688
+ rng
1689
+ }));
1690
+ }
1691
+ /** A headline in title case, e.g. `"Bright Harbour"`. */
1692
+ function title(rng) {
1693
+ return `${capitalize(pick(ADJECTIVES, rng))} ${capitalize(pick(NOUNS, rng))}`;
1694
+ }
1695
+ const textSpecs = [
1696
+ {
1697
+ name: "word",
1698
+ doc: "A single word.",
1699
+ result: t.string,
1700
+ make: (rng) => pick(LOREM, rng)
1701
+ },
1702
+ {
1703
+ name: "words",
1704
+ doc: "Several words. `faker.words(5)` sets how many.",
1705
+ result: t.string,
1706
+ args: [optionalArg("count", t.number, "How many words.")],
1707
+ make: (rng, args) => words(rng, numArg(args, 0, 3))
1708
+ },
1709
+ {
1710
+ name: "sentence",
1711
+ doc: "One sentence.",
1712
+ result: t.string,
1713
+ make: sentence
1714
+ },
1715
+ {
1716
+ name: "sentences",
1717
+ doc: "Several sentences. `faker.sentences(3)` sets how many.",
1718
+ result: t.string,
1719
+ args: [optionalArg("count", t.number, "How many sentences.")],
1720
+ make: (rng, args) => sentences(rng, numArg(args, 0, 3))
1721
+ },
1722
+ {
1723
+ name: "paragraph",
1724
+ doc: "One paragraph.",
1725
+ result: t.string,
1726
+ make: paragraph
1727
+ },
1728
+ {
1729
+ name: "paragraphs",
1730
+ doc: "Several paragraphs, separated by blank lines. `faker.paragraphs(4)` sets how many.",
1731
+ result: t.string,
1732
+ args: [optionalArg("count", t.number, "How many paragraphs.")],
1733
+ make: (rng, args) => times(numArg(args, 0, 2), () => paragraph(rng)).join("\n\n")
1734
+ },
1735
+ {
1736
+ name: "title",
1737
+ doc: "A short headline in title case.",
1738
+ result: t.string,
1739
+ make: title
1740
+ }
1741
+ ];
1742
+ //#endregion
1743
+ //#region src/faker/all-specs.ts
1744
+ /** Every `data.faker.*` verb. Adding a whole category is one line here. */
1745
+ const allFakerSpecs = [
1746
+ ...personSpecs,
1747
+ ...internetSpecs,
1748
+ ...addressSpecs,
1749
+ ...companySpecs,
1750
+ ...commerceSpecs,
1751
+ ...financeSpecs,
1752
+ ...datetimeSpecs,
1753
+ ...textSpecs,
1754
+ ...idSpecs,
1755
+ ...brazilSpecs
1756
+ ];
1757
+ //#endregion
1758
+ //#region src/rng/mulberry32.ts
1759
+ /**
1760
+ * Mulberry32: a tiny, fast, fully deterministic PRNG.
1761
+ *
1762
+ * @param seed Any number. It is coerced to a uint32, so the same seed always
1763
+ * yields the same stream.
1764
+ * @returns A generator producing the next float in [0, 1) on each call.
1765
+ */
1766
+ function mulberry32(seed) {
1767
+ let state = seed >>> 0;
1768
+ return () => {
1769
+ state = state + 1831565813 | 0;
1770
+ let t = Math.imul(state ^ state >>> 15, 1 | state);
1771
+ t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
1772
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
1773
+ };
1774
+ }
1775
+ //#endregion
1776
+ //#region src/rng/shared-rng.ts
1777
+ /** The fixed seed. A constant seed is what makes every generated value reproducible. */
1778
+ const SEED = 1;
1779
+ let shared = mulberry32(SEED);
1780
+ /** The module-level deterministic PRNG shared by every generator in this package. */
1781
+ const rng = () => shared();
1782
+ /** Reset the shared PRNG to its seed so the same stream can be drawn again. Used by tests. */
1783
+ function resetRng() {
1784
+ shared = mulberry32(SEED);
1785
+ }
1786
+ //#endregion
1787
+ //#region src/rng/shuffle.ts
1788
+ /**
1789
+ * Fisher-Yates shuffle driven by the given PRNG.
1790
+ *
1791
+ * @returns A new array holding the same elements in a new order. `items` is untouched.
1792
+ */
1793
+ function shuffleWith(items, rng) {
1794
+ const out = [...items];
1795
+ for (let i = out.length - 1; i > 0; i -= 1) {
1796
+ const j = Math.floor(rng() * (i + 1));
1797
+ const tmp = out[i];
1798
+ out[i] = out[j];
1799
+ out[j] = tmp;
1800
+ }
1801
+ return out;
1802
+ }
1803
+ //#endregion
1804
+ //#region src/actions/faker-actions.ts
1805
+ /** Turn one spec into the `data.faker.<name>` verb, drawn from the shared PRNG. */
1806
+ function toAction(spec) {
1807
+ return defineAction({
1808
+ name: `faker.${spec.name}`,
1809
+ doc: spec.doc,
1810
+ args: spec.args,
1811
+ result: spec.result,
1812
+ run: (_ctx, input) => spec.make(rng, input.args)
1813
+ });
1814
+ }
1815
+ /**
1816
+ * The `data.faker.*` verbs. Every value is deterministic under the shared seed,
1817
+ * so a failing run replays exactly. The catalogue itself lives in `faker/`.
1818
+ */
1819
+ const fakerActions = allFakerSpecs.map(toAction);
1820
+ //#endregion
1821
+ //#region src/csv/parse-csv.ts
1822
+ /**
1823
+ * Parse a CSV string into row objects. The first line supplies the headers.
1824
+ *
1825
+ * A minimal splitter: it takes inline content only (never a path) and does not
1826
+ * understand quoting, so a quoted cell containing a comma splits in two.
1827
+ *
1828
+ * @param content The CSV text. Blank lines are skipped.
1829
+ * @returns One object per data line, keyed by header. Empty when there is no header line.
1830
+ */
1831
+ function parseCsv(content) {
1832
+ const [header, ...rows] = content.split(/\r?\n/).filter((line) => line.trim() !== "");
1833
+ if (header === void 0) return [];
1834
+ const headers = splitLine(header);
1835
+ return rows.map((row) => toRow(headers, splitLine(row)));
1836
+ }
1837
+ function splitLine(line) {
1838
+ return line.split(",").map((cell) => cell.trim());
1839
+ }
1840
+ function toRow(headers, cells) {
1841
+ const row = {};
1842
+ headers.forEach((key, index) => {
1843
+ row[key] = cells[index] ?? "";
1844
+ });
1845
+ return row;
1846
+ }
1847
+ //#endregion
1848
+ //#region src/actions/parse-actions.ts
1849
+ /**
1850
+ * `data.csv(text)`: parse an inline CSV string into a list of `data.Row`.
1851
+ *
1852
+ * The first line names the columns. Every cell arrives as a string.
1853
+ */
1854
+ const csv = defineAction({
1855
+ name: "csv",
1856
+ doc: "Parse an inline CSV string into an array of row objects (first line = headers).",
1857
+ args: [arg("text", t.string, "The CSV itself. Its first line names the columns.")],
1858
+ result: t.list(t.ref("data.Row")),
1859
+ run: (_ctx, input) => parseCsv(String(input.args[0] ?? ""))
1860
+ });
1861
+ /**
1862
+ * `data.json(text)`: parse a JSON string into a value.
1863
+ *
1864
+ * Throws whatever `JSON.parse` throws when the text is not valid JSON.
1865
+ */
1866
+ const json = defineAction({
1867
+ name: "json",
1868
+ doc: "Parse a JSON string into a value.",
1869
+ args: [arg("text", t.string, "The JSON to read.")],
1870
+ result: t.dynamic,
1871
+ run: (_ctx, input) => JSON.parse(String(input.args[0] ?? "null"))
1872
+ });
1873
+ //#endregion
1874
+ //#region src/actions/random-actions.ts
1875
+ /** `data.oneOf("free", "pro")`: pick one of the given values via the shared PRNG. */
1876
+ const oneOf = defineAction({
1877
+ name: "oneOf",
1878
+ doc: "Pick one of the given values deterministically.",
1879
+ args: [restArg("choices", t.dynamic, "The candidates. One of them comes back.")],
1880
+ result: t.dynamic,
1881
+ run: (_ctx, input) => input.args[Math.floor(rng() * input.args.length)]
1882
+ });
1883
+ /** `data.range(1, 10)`: a deterministic integer in the inclusive range [min, max]. */
1884
+ const range = defineAction({
1885
+ name: "range",
1886
+ doc: "A deterministic integer within the inclusive range [min, max].",
1887
+ args: [arg("min", t.number, "The lowest it may be, included."), arg("max", t.number, "The highest it may be, included.")],
1888
+ result: t.number,
1889
+ run: (_ctx, input) => integerInRange(input)
1890
+ });
1891
+ function integerInRange(input) {
1892
+ const min = Math.trunc(Number(input.args[0] ?? 0));
1893
+ const max = Math.trunc(Number(input.args[1] ?? 0));
1894
+ return min + Math.floor(rng() * (max - min + 1));
1895
+ }
1896
+ /** `data.shuffle([1, 2, 3])`: a deterministic permutation of the given array. */
1897
+ const shuffle = defineAction({
1898
+ name: "shuffle",
1899
+ doc: "A deterministic shuffle of the given array.",
1900
+ args: [arg("values", t.list(t.dynamic), "What to shuffle. The original is left alone.")],
1901
+ result: t.list(t.dynamic),
1902
+ run: (_ctx, input) => shuffleWith(toArray(input.args[0]), rng)
1903
+ });
1904
+ function toArray(value) {
1905
+ return Array.isArray(value) ? value : [];
1906
+ }
1907
+ //#endregion
1908
+ //#region src/actions/index.ts
1909
+ /** Every verb in the `data` namespace. Adding one is a single line here. */
1910
+ const dataActions = [
1911
+ ...fakerActions,
1912
+ oneOf,
1913
+ range,
1914
+ shuffle,
1915
+ csv,
1916
+ json
1917
+ ];
1918
+ //#endregion
1919
+ //#region src/plugin.ts
1920
+ /**
1921
+ * The `data` plugin: pure, deterministic test-data generators.
1922
+ *
1923
+ * Every verb draws from a seeded module-level PRNG, so the same script replays the
1924
+ * same values. Nothing here does I/O, so there is no capability and no port to bind.
1925
+ */
1926
+ const dataPlugin = definePlugin({
1927
+ name: "venn/data",
1928
+ version: "0.0.0",
1929
+ namespace: "data",
1930
+ actions: dataActions,
1931
+ typeDefs: {
1932
+ /**
1933
+ * One parsed CSV record. The keys come from the file's header line, so they
1934
+ * cannot be named here. Only the cell type is knowable, and it is always a string.
1935
+ */
1936
+ Row: t.map(t.string) }
1937
+ });
1938
+ //#endregion
1939
+ export { ANCHOR, allFakerSpecs, cnpjDigits, cpfDigits, dataActions, dataPlugin, dataPlugin as default, eanDigit, email, firstName, fullName, ibanCheck, lastName, luhnDigit, mulberry32, parseCsv, resetRng, rng, shuffleWith, uuid };
1940
+
1941
+ //# sourceMappingURL=index.js.map