@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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vinicius Borges
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # @venn-lang/data
2
+
3
+ > The `data` namespace: 96 deterministic faker verbs, plus picking, shuffling and parsing.
4
+
5
+ Test data that changes between runs makes a failure impossible to reproduce. Every value this
6
+ package draws comes from one seeded PRNG (mulberry32, seed 1) held at module level, so the same
7
+ flow replays the same person, the same card number, the same CPF. The plugin declares no
8
+ capability and rides no port: `data` is pure computation, no network and no clock.
9
+
10
+ ## Install
11
+
12
+ The package is part of the stdlib the `venn` CLI loads, so nothing to install. Reach it from a
13
+ flow with a `use` line:
14
+
15
+ ```ruby
16
+ use "venn/data"
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```ruby
22
+ module demo.signup
23
+
24
+ use "venn/assert"
25
+ use "venn/data"
26
+
27
+ flow "A generated Brazilian signup" {
28
+ const name = data.faker.name
29
+ const email = data.faker.email
30
+ const cpf = data.faker.br.cpf
31
+ const card = data.faker.creditCard
32
+
33
+ step "the generated person is plausible" {
34
+ expect name contains " "
35
+ expect email contains "@"
36
+ expect cpf contains "-"
37
+ expect card contains " "
38
+ }
39
+
40
+ step "and the rest of the namespace is there too" {
41
+ const plan = data.oneOf "free" "pro"
42
+ const roll = data.range 1 10
43
+ const rows = data.csv "name,plan\nada,pro\nlinus,free"
44
+
45
+ expect roll >= 1
46
+ expect rows.len == 2
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## Verbs
52
+
53
+ Five verbs sit directly on the namespace:
54
+
55
+ | Verb | Gives back | Notes |
56
+ | --- | --- | --- |
57
+ | `data.oneOf a b c…` | `dynamic` | One of the positional arguments. |
58
+ | `data.range min max` | `number` | An integer in the inclusive range. |
59
+ | `data.shuffle values` | `list<dynamic>` | A permutation. The input array is left alone. |
60
+ | `data.csv text` | `list<data.Row>` | Parses inline CSV; the first line names the columns. |
61
+ | `data.json text` | `dynamic` | `JSON.parse`, with the shape left to the caller. |
62
+
63
+ The other 96 are `data.faker.*`, grouped by what a form asks for:
64
+
65
+ | Family | Verbs |
66
+ | --- | --- |
67
+ | Person | `firstName` `lastName` `name` `fullName` `prefix` `suffix` `gender` `jobTitle` `age` `birthDate` `phone` |
68
+ | Internet | `email` `username` `password` `domain` `url` `ipv4` `ipv6` `mac` `port` `userAgent` `slug` `httpMethod` `httpStatus` `mimeType` |
69
+ | Address | `street` `streetAddress` `address` `buildingNumber` `city` `country` `countryCode` `zip` `latitude` `longitude` `timezone` |
70
+ | Company | `company` `department` `catchPhrase` `buzzword` |
71
+ | Commerce | `product` `productName` `sku` `barcode` `category` `material` `color` `hexColor` `price` |
72
+ | Finance | `creditCard` `cardType` `cvv` `expiryDate` `iban` `bic` `accountNumber` `currencyCode` `currencySymbol` `currencyName` `amount` |
73
+ | Date and time | `date` `dateTime` `pastDate` `futureDate` `time` `timestamp` `weekday` `month` `year` |
74
+ | Text | `word` `words` `sentence` `sentences` `paragraph` `paragraphs` `title` |
75
+ | Identifiers | `uuid` `nanoid` `objectId` `hex` `token` `alphanumeric` `digits` `int` `float` `boolean` |
76
+ | Brazil | `br.cpf` `br.cnpj` `br.cep` `br.phone` `br.plate` `br.street` `br.address` `br.city` `br.state` `br.stateCode` |
77
+
78
+ Ten of them read positional bounds; the rest take nothing.
79
+
80
+ ```ruby
81
+ const pin = data.faker.digits 4 # four decimal digits
82
+ const quantity = data.faker.int 1 6 # inclusive on both ends
83
+ const blurb = data.faker.words 5
84
+ const born = data.faker.year 1980 2005
85
+ ```
86
+
87
+ The full list of verbs that read arguments: `nanoid(length)`, `hex(length)`,
88
+ `alphanumeric(length)`, `digits(length)`, `int(min, max)`, `float(min, max)`, `words(count)`,
89
+ `sentences(count)`, `paragraphs(count)`, `year(from, to)`. All arguments are optional and every
90
+ one has a default.
91
+
92
+ ### Check digits are real
93
+
94
+ A value a form rejects before it reaches the server is useless in a test, so the generators that
95
+ carry a checksum compute it: `creditCard` passes Luhn, `barcode` passes the EAN-13 check, `iban`
96
+ passes mod-97, and `br.cpf` and `br.cnpj` carry the digits a Brazilian form validates.
97
+
98
+ ## API
99
+
100
+ | Export | What it is |
101
+ | --- | --- |
102
+ | `dataPlugin` (also the default export) | The `PluginDefinition` for the `data` namespace. |
103
+ | `dataActions` | The `ActionDefinition[]` behind it, faker verbs included. |
104
+ | `allFakerSpecs`, `FakerSpec` | The catalogue as data: `name`, `doc`, a `TypeSpec` result, optional `args`, and `make(rng, args)`. |
105
+ | `rng`, `resetRng()` | The shared PRNG and the reset that rewinds it to the seed. |
106
+ | `mulberry32(seed)`, `Rng` | The generator itself, for an independent stream. |
107
+ | `shuffleWith(items, rng)` | Fisher-Yates against a given PRNG. Returns a new array. |
108
+ | `parseCsv(content)`, `CsvRow` | The splitter behind `data.csv`. |
109
+ | `uuid`, `email`, `firstName`, `lastName`, `fullName` | Single generators, each taking an `Rng`. |
110
+ | `cpfDigits`, `cnpjDigits`, `luhnDigit`, `eanDigit`, `ibanCheck` | The check-digit functions on their own. |
111
+ | `ANCHOR` | The fixed instant the date verbs are drawn around, `2025-01-01T00:00:00Z`. |
112
+
113
+ The plugin publishes one named type, `data.Row`: a map of string to string, which is what
114
+ `data.csv` gives back per record.
115
+
116
+ ## Determinism
117
+
118
+ `rng` is a module-level mulberry32 seeded with `1`. Draws advance one shared stream, so the
119
+ sequence of calls a flow makes is what determines the values, not the wall clock. `resetRng()`
120
+ rewinds it, which is how the tests here assert that a whole catalogue replays identically:
121
+
122
+ ```ts
123
+ import { allFakerSpecs, resetRng, rng } from "@venn-lang/data";
124
+
125
+ resetRng();
126
+ const first = allFakerSpecs.map((spec) => spec.make(rng, []));
127
+ resetRng();
128
+ const again = allFakerSpecs.map((spec) => spec.make(rng, []));
129
+ // `again` equals `first`: the same 96 values, in the same order
130
+ ```
131
+
132
+ Dates are drawn around `ANCHOR` rather than `Date.now()`, for the same reason.
133
+
134
+ ## Limits
135
+
136
+ `parseCsv` is a minimal splitter: it reads inline content only (no file paths yet), splits on
137
+ commas and trims cells, and does not handle quoted commas.
138
+
139
+ ## See also
140
+
141
+ - [`@venn-lang/crypto`](../std-crypto) for hashing and signing the values generated here.
142
+ - [`@venn-lang/mock`](../std-mock) for freezing the clock and flipping flags.
143
+ - [`@venn-lang/sdk`](../sdk) for `defineAction` and `definePlugin`.
@@ -0,0 +1,152 @@
1
+ import { ActionDefinition, ArgSpec, PluginDefinition } from "@venn-lang/sdk";
2
+ import { TypeSpec } from "@venn-lang/types";
3
+ //#region src/actions/index.d.ts
4
+ /** Every verb in the `data` namespace. Adding one is a single line here. */
5
+ declare const dataActions: ActionDefinition[];
6
+ //#endregion
7
+ //#region src/csv/csv.types.d.ts
8
+ /** One parsed CSV record: header name → cell value, both strings. */
9
+ type CsvRow = Record<string, string>;
10
+ //#endregion
11
+ //#region src/csv/parse-csv.d.ts
12
+ /**
13
+ * Parse a CSV string into row objects. The first line supplies the headers.
14
+ *
15
+ * A minimal splitter: it takes inline content only (never a path) and does not
16
+ * understand quoting, so a quoted cell containing a comma splits in two.
17
+ *
18
+ * @param content The CSV text. Blank lines are skipped.
19
+ * @returns One object per data line, keyed by header. Empty when there is no header line.
20
+ */
21
+ declare function parseCsv(content: string): CsvRow[];
22
+ //#endregion
23
+ //#region src/rng/rng.types.d.ts
24
+ /** A deterministic pseudo-random generator: each call yields the next float in [0, 1). */
25
+ type Rng = () => number;
26
+ //#endregion
27
+ //#region src/rng/mulberry32.d.ts
28
+ /**
29
+ * Mulberry32: a tiny, fast, fully deterministic PRNG.
30
+ *
31
+ * @param seed Any number. It is coerced to a uint32, so the same seed always
32
+ * yields the same stream.
33
+ * @returns A generator producing the next float in [0, 1) on each call.
34
+ */
35
+ declare function mulberry32(seed: number): Rng;
36
+ //#endregion
37
+ //#region src/rng/shared-rng.d.ts
38
+ /** The module-level deterministic PRNG shared by every generator in this package. */
39
+ declare const rng: Rng;
40
+ /** Reset the shared PRNG to its seed so the same stream can be drawn again. Used by tests. */
41
+ declare function resetRng(): void;
42
+ //#endregion
43
+ //#region src/rng/shuffle.d.ts
44
+ /**
45
+ * Fisher-Yates shuffle driven by the given PRNG.
46
+ *
47
+ * @returns A new array holding the same elements in a new order. `items` is untouched.
48
+ */
49
+ declare function shuffleWith(items: readonly unknown[], rng: Rng): unknown[];
50
+ //#endregion
51
+ //#region src/faker/faker.types.d.ts
52
+ /**
53
+ * One `data.faker.*` verb: what it is called, what it means, and how to draw a
54
+ * value. A spec is plain data, so the action wiring reads the list as it stands
55
+ * and needs no edit when a category grows.
56
+ */
57
+ interface FakerSpec {
58
+ /** The verb, without the namespace: `email`, `br.cpf`. */
59
+ name: string;
60
+ /** One line, in the user's domain. Shown on hover and in completion. */
61
+ doc: string;
62
+ /** The type it draws. A `TypeSpec`, not a name, so the checker can act on it. */
63
+ result: TypeSpec;
64
+ /**
65
+ * The positional arguments `make` reads, in order. Most verbs read none and
66
+ * leave this out. The action wiring turns it into the signature the checker sees.
67
+ */
68
+ args?: readonly ArgSpec[];
69
+ /** Draw a value. `args` carries the call's positional arguments, if any. */
70
+ make(rng: Rng, args: readonly unknown[]): unknown;
71
+ }
72
+ //#endregion
73
+ //#region src/faker/all-specs.d.ts
74
+ /** Every `data.faker.*` verb. Adding a whole category is one line here. */
75
+ declare const allFakerSpecs: readonly FakerSpec[];
76
+ //#endregion
77
+ //#region src/faker/brazil-documents.d.ts
78
+ /**
79
+ * The two CPF check digits.
80
+ *
81
+ * @param base The first nine digits, unformatted.
82
+ * @returns Two digits to append.
83
+ */
84
+ declare function cpfDigits(base: string): string;
85
+ /**
86
+ * The two CNPJ check digits.
87
+ *
88
+ * @param base The first twelve digits, unformatted.
89
+ * @returns Two digits to append.
90
+ */
91
+ declare function cnpjDigits(base: string): string;
92
+ //#endregion
93
+ //#region src/faker/check-digits.d.ts
94
+ /**
95
+ * The Luhn check digit for a card number.
96
+ *
97
+ * @param base The digits preceding the check digit.
98
+ * @returns One digit. Appending it makes `base` pass the Luhn test.
99
+ */
100
+ declare function luhnDigit(base: string): string;
101
+ /**
102
+ * The EAN-13 check digit for the leading 12 digits of a barcode.
103
+ *
104
+ * @param base Exactly 12 digits.
105
+ * @returns The thirteenth digit.
106
+ */
107
+ declare function eanDigit(base: string): string;
108
+ /**
109
+ * The two IBAN check digits: mod-97 over the rearranged, letter-expanded account.
110
+ *
111
+ * @param country The two-letter country code, upper case.
112
+ * @param account The account part, without check digits.
113
+ * @returns Two digits, zero-padded, to be inserted after the country code.
114
+ */
115
+ declare function ibanCheck(country: string, account: string): string;
116
+ //#endregion
117
+ //#region src/faker/datetime.d.ts
118
+ /**
119
+ * The instant every generated date is measured from.
120
+ *
121
+ * Dates hang off a fixed anchor rather than the wall clock: `Date.now()` would
122
+ * give a different answer on every run and break the seeded replay guarantee.
123
+ */
124
+ declare const ANCHOR: number;
125
+ //#endregion
126
+ //#region src/faker/ids.d.ts
127
+ /** An RFC 4122 v4 UUID. The version and variant bits are stamped, not drawn. */
128
+ declare function uuid(rng: Rng): string;
129
+ //#endregion
130
+ //#region src/faker/internet.d.ts
131
+ /** An email on a reserved domain, e.g. `"grace.hopper@example.test"`. It reaches nobody. */
132
+ declare function email(rng: Rng): string;
133
+ //#endregion
134
+ //#region src/faker/person.d.ts
135
+ /** A given name, e.g. `"Grace"`. */
136
+ declare function firstName(rng: Rng): string;
137
+ /** A family name, e.g. `"Hopper"`. */
138
+ declare function lastName(rng: Rng): string;
139
+ /** A full name, e.g. `"Grace Hopper"`. */
140
+ declare function fullName(rng: Rng): string;
141
+ //#endregion
142
+ //#region src/plugin.d.ts
143
+ /**
144
+ * The `data` plugin: pure, deterministic test-data generators.
145
+ *
146
+ * Every verb draws from a seeded module-level PRNG, so the same script replays the
147
+ * same values. Nothing here does I/O, so there is no capability and no port to bind.
148
+ */
149
+ declare const dataPlugin: PluginDefinition;
150
+ //#endregion
151
+ export { ANCHOR, type CsvRow, type FakerSpec, type Rng, allFakerSpecs, cnpjDigits, cpfDigits, dataActions, dataPlugin, dataPlugin as default, eanDigit, email, firstName, fullName, ibanCheck, lastName, luhnDigit, mulberry32, parseCsv, resetRng, rng, shuffleWith, uuid };
152
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/actions/index.ts","../src/csv/csv.types.ts","../src/csv/parse-csv.ts","../src/rng/rng.types.ts","../src/rng/mulberry32.ts","../src/rng/shared-rng.ts","../src/rng/shuffle.ts","../src/faker/faker.types.ts","../src/faker/all-specs.ts","../src/faker/brazil-documents.ts","../src/faker/check-digits.ts","../src/faker/datetime.ts","../src/faker/ids.ts","../src/faker/internet.ts","../src/faker/person.ts","../src/plugin.ts"],"mappings":";;;;cAMa,aAAa;;;;KCLd,SAAS;;;;;;;;;;;;iBCUL,SAAS,kBAAkB;;;;KCV/B;;;;;;;;;;iBCQI,WAAW,eAAe;;;;cCA7B,KAAK;;iBAGF;;;;;;;;iBCLA,YAAY,2BAA2B,KAAK;;;;;;;;UCE3C;;EAEf;;EAEA;;EAEA,QAAQ;;;;;EAKR,gBAAgB;;EAEhB,KAAK,KAAK,KAAK;;;;;cCTJ,wBAAwB;;;;;;;;;iBCHrB,UAAU;;;;;;;iBAsBV,WAAW;;;;;;;;;iBCpBX,UAAU;;;;;;;iBAiBV,SAAS;;;;;;;;iBAeT,UAAU,iBAAiB;;;;;;;;;cChC9B;;;;iBCLG,KAAK,KAAK;;;;iBCWV,MAAM,KAAK;;;;iBCJX,UAAU,KAAK;;iBAKf,SAAS,KAAK;;iBAKd,SAAS,KAAK;;;;;;;;;cCdjB,YAAY"}