@cosyte/synth 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +165 -17
- package/README.md +47 -45
- package/dist/astm/index.cjs +7 -7
- package/dist/astm/index.cjs.map +1 -1
- package/dist/astm/index.d.cts +47 -47
- package/dist/astm/index.d.ts +47 -47
- package/dist/astm/index.mjs +7 -7
- package/dist/astm/index.mjs.map +1 -1
- package/dist/ccda/index.cjs +15 -15
- package/dist/ccda/index.cjs.map +1 -1
- package/dist/ccda/index.d.cts +31 -31
- package/dist/ccda/index.d.ts +31 -31
- package/dist/ccda/index.mjs +15 -15
- package/dist/ccda/index.mjs.map +1 -1
- package/dist/deid/index.cjs +15 -15
- package/dist/deid/index.cjs.map +1 -1
- package/dist/deid/index.d.cts +37 -37
- package/dist/deid/index.d.ts +37 -37
- package/dist/deid/index.mjs +15 -15
- package/dist/deid/index.mjs.map +1 -1
- package/dist/{example-codes-DeXcnCSK.d.cts → example-codes-88f3_bQZ.d.cts} +8 -8
- package/dist/{example-codes-DeXcnCSK.d.ts → example-codes-88f3_bQZ.d.ts} +8 -8
- package/dist/fhir/index.cjs +12 -12
- package/dist/fhir/index.cjs.map +1 -1
- package/dist/fhir/index.d.cts +46 -46
- package/dist/fhir/index.d.ts +46 -46
- package/dist/fhir/index.mjs +12 -12
- package/dist/fhir/index.mjs.map +1 -1
- package/dist/hl7/index.cjs +6 -6
- package/dist/hl7/index.cjs.map +1 -1
- package/dist/hl7/index.d.cts +45 -45
- package/dist/hl7/index.d.ts +45 -45
- package/dist/hl7/index.mjs +6 -6
- package/dist/hl7/index.mjs.map +1 -1
- package/dist/index.cjs +9 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -49
- package/dist/index.d.ts +49 -49
- package/dist/index.mjs +9 -9
- package/dist/index.mjs.map +1 -1
- package/dist/ncpdp/index.cjs +3 -3
- package/dist/ncpdp/index.cjs.map +1 -1
- package/dist/ncpdp/index.d.cts +42 -42
- package/dist/ncpdp/index.d.ts +42 -42
- package/dist/ncpdp/index.mjs +3 -3
- package/dist/ncpdp/index.mjs.map +1 -1
- package/dist/{providers-OLz3zAc-.d.cts → providers-B9uVinAe.d.cts} +24 -24
- package/dist/{providers-OLz3zAc-.d.ts → providers-B9uVinAe.d.ts} +24 -24
- package/dist/{quirk-C9t9CkPS.d.ts → quirk-HZdznAkM.d.ts} +23 -23
- package/dist/{quirk-DYMDojVw.d.cts → quirk-IaHp4z7N.d.cts} +23 -23
- package/dist/x12/index.cjs +6 -6
- package/dist/x12/index.cjs.map +1 -1
- package/dist/x12/index.d.cts +44 -44
- package/dist/x12/index.d.ts +44 -44
- package/dist/x12/index.mjs +6 -6
- package/dist/x12/index.mjs.map +1 -1
- package/package.json +3 -2
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The `Corpus` abstraction
|
|
2
|
+
* The `Corpus` abstraction: a seed plus a self-describing manifest of what was generated, so a
|
|
3
3
|
* fixture set is itself reproducible and regenerable. A downstream repo pins a seed
|
|
4
4
|
* and gets a stable fixture set that regenerates identically.
|
|
5
5
|
*
|
|
6
|
-
* Generated artifacts and the `Corpus` are **deep-frozen
|
|
6
|
+
* Generated artifacts and the `Corpus` are **deep-frozen**: this is where the archetype's immutability
|
|
7
7
|
* invariant lives in a generator: a consumer cannot mutate a shared fixture out from under
|
|
8
8
|
* another test.
|
|
9
9
|
*
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
/** The format an artifact was generated for. */
|
|
13
13
|
type SynthFormat = "hl7v2" | "fhir" | "ccda" | "x12" | "ncpdp" | "astm";
|
|
14
14
|
/**
|
|
15
|
-
* One generated artifact
|
|
15
|
+
* One generated artifact: the serialized wire text plus the metadata needed to reproduce and check
|
|
16
16
|
* it. `warnings` records what the artifact's own parser reported on the round-trip (zero for a
|
|
17
17
|
* spec-clean artifact).
|
|
18
18
|
*/
|
|
@@ -37,7 +37,7 @@ interface CorpusManifest {
|
|
|
37
37
|
}
|
|
38
38
|
/** A reproducible, self-describing set of generated artifacts. */
|
|
39
39
|
interface Corpus {
|
|
40
|
-
/** The seed the corpus was generated from
|
|
40
|
+
/** The seed the corpus was generated from: regenerating from it yields byte-identical artifacts. */
|
|
41
41
|
readonly seed: number;
|
|
42
42
|
/** The manifest describing what was generated. */
|
|
43
43
|
readonly manifest: CorpusManifest;
|
|
@@ -61,16 +61,16 @@ interface Corpus {
|
|
|
61
61
|
declare function makeCorpus(seed: number, artifacts: readonly Artifact[], quirks?: readonly string[]): Corpus;
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
|
-
* `Rng
|
|
64
|
+
* `Rng`: the seeded, deterministic random source every `@cosyte/synth` provider draws from.
|
|
65
65
|
*
|
|
66
|
-
* **The reproducibility contract.** A seed
|
|
66
|
+
* **The reproducibility contract.** A seed, and only the seed, determines the output.
|
|
67
67
|
* `createRng(seed)` expands the integer seed through {@link ./splitmix32.splitmix32} into the four
|
|
68
68
|
* `sfc32` state words, then every draw advances that state via {@link ./sfc32.sfc32Next}. Two `Rng`s
|
|
69
|
-
* created from the same seed emit the **identical** sequence on any machine, any run
|
|
69
|
+
* created from the same seed emit the **identical** sequence on any machine, any run: the property
|
|
70
70
|
* the parsers', `transform`'s, and `deid`'s regression suites depend on.
|
|
71
71
|
*
|
|
72
72
|
* **Explicit, never global.** An `Rng` is a value you thread through a build; there is no ambient
|
|
73
|
-
* shared generator and **`Math.random` is lint-banned** in `src/` (it is not seedable
|
|
73
|
+
* shared generator and **`Math.random` is lint-banned** in `src/` (it is not seedable: its seed is
|
|
74
74
|
* engine-chosen and cannot be reset, so a corpus built on it is not reproducible). Because each
|
|
75
75
|
* generation creates a fresh `Rng` from its seed, generations are independent and parallel-safe.
|
|
76
76
|
*
|
|
@@ -128,13 +128,13 @@ interface Rng {
|
|
|
128
128
|
declare function createRng(seed: number): Rng;
|
|
129
129
|
|
|
130
130
|
/**
|
|
131
|
-
* The synthetic-safety provider layer
|
|
131
|
+
* The synthetic-safety provider layer: every identifier, contact point, name, and date
|
|
132
132
|
* `@cosyte/synth` emits is minted here, and **only** from a guaranteed-non-colliding source. There is no code
|
|
133
133
|
* path that returns a value not drawn from a reserved range or the
|
|
134
134
|
* shipped fake-name pool. This is the inverse of a parser's liberality: the generator is *closed-world*
|
|
135
135
|
* on its data sources, so no output *can* be real or plausibly-real PHI.
|
|
136
136
|
*
|
|
137
|
-
* All providers are pure functions of an explicit {@link ../rng/rng.Rng}
|
|
137
|
+
* All providers are pure functions of an explicit {@link ../rng/rng.Rng}, same seed, same values.
|
|
138
138
|
*
|
|
139
139
|
* @module
|
|
140
140
|
*/
|
|
@@ -146,7 +146,7 @@ interface SyntheticName {
|
|
|
146
146
|
/** A clearly-fake family name. */
|
|
147
147
|
readonly family: string;
|
|
148
148
|
}
|
|
149
|
-
/** A synthetic postal address
|
|
149
|
+
/** A synthetic postal address: synthetic street + city, a fixed non-real ZIP. */
|
|
150
150
|
interface SyntheticAddress {
|
|
151
151
|
/** A clearly-fake street line. */
|
|
152
152
|
readonly street: string;
|
|
@@ -159,7 +159,7 @@ interface SyntheticAddress {
|
|
|
159
159
|
}
|
|
160
160
|
/** A synthetic identifier scoped to the synthetic assigning authority. */
|
|
161
161
|
interface SyntheticIdentifier {
|
|
162
|
-
/** The identifier value (digits)
|
|
162
|
+
/** The identifier value (digits): unique only within the synthetic namespace. */
|
|
163
163
|
readonly value: string;
|
|
164
164
|
/** HL7 identifier type code (`MR` = medical record, `AN` = account, `MB` = member). */
|
|
165
165
|
readonly typeCode: "MR" | "AN" | "MB";
|
|
@@ -171,7 +171,7 @@ interface SyntheticIdentifier {
|
|
|
171
171
|
/** Which SSN reserved space to draw from. */
|
|
172
172
|
type SsnBlock = "never-issued" | "advertising";
|
|
173
173
|
/**
|
|
174
|
-
* A **synthetic SSN
|
|
174
|
+
* A **synthetic SSN**: dashed `AAA-GG-SSSS`. Default draws the SSA never-issued area space
|
|
175
175
|
* (`900–999`); `block: "advertising"` draws SSA's reserved advertising block (`987-65-4320…4329`).
|
|
176
176
|
* A value from this function can never be a real SSN.
|
|
177
177
|
*
|
|
@@ -186,7 +186,7 @@ type SsnBlock = "never-issued" | "advertising";
|
|
|
186
186
|
*/
|
|
187
187
|
declare function ssn(rng: Rng, block?: SsnBlock): string;
|
|
188
188
|
/**
|
|
189
|
-
* A **synthetic phone** in the NANP reserved fictional block
|
|
189
|
+
* A **synthetic phone** in the NANP reserved fictional block: `(AAA) 555-01NN`. The reserved
|
|
190
190
|
* guarantee is the `555-01NN` tail (exchange 555, line 0100–0199); the area code is any NANP-valid
|
|
191
191
|
* `NXX`. Can never be a working number.
|
|
192
192
|
*
|
|
@@ -212,7 +212,7 @@ declare function phone(rng: Rng): string;
|
|
|
212
212
|
*/
|
|
213
213
|
declare function name(rng: Rng): SyntheticName;
|
|
214
214
|
/**
|
|
215
|
-
* A **synthetic email** at an RFC 2606 / 6761 reserved domain
|
|
215
|
+
* A **synthetic email** at an RFC 2606 / 6761 reserved domain: `<slug>@example.com`.
|
|
216
216
|
*
|
|
217
217
|
* @param rng - The seeded generator.
|
|
218
218
|
* @param person - Optional name to derive the local-part slug from; otherwise a random slug is used.
|
|
@@ -225,7 +225,7 @@ declare function name(rng: Rng): SyntheticName;
|
|
|
225
225
|
*/
|
|
226
226
|
declare function email(rng: Rng, person?: SyntheticName): string;
|
|
227
227
|
/**
|
|
228
|
-
* A **synthetic IPv4** in an RFC 5737 TEST-NET block
|
|
228
|
+
* A **synthetic IPv4** in an RFC 5737 TEST-NET block, never routable.
|
|
229
229
|
*
|
|
230
230
|
* @param rng - The seeded generator.
|
|
231
231
|
* @returns A TEST-NET IPv4 address string.
|
|
@@ -237,7 +237,7 @@ declare function email(rng: Rng, person?: SyntheticName): string;
|
|
|
237
237
|
*/
|
|
238
238
|
declare function ipv4(rng: Rng): string;
|
|
239
239
|
/**
|
|
240
|
-
* A **synthetic IPv6** in the RFC 3849 documentation prefix `2001:db8::/32
|
|
240
|
+
* A **synthetic IPv6** in the RFC 3849 documentation prefix `2001:db8::/32`, never routable.
|
|
241
241
|
*
|
|
242
242
|
* @param rng - The seeded generator.
|
|
243
243
|
* @returns A documentation-prefix IPv6 address string.
|
|
@@ -250,7 +250,7 @@ declare function ipv4(rng: Rng): string;
|
|
|
250
250
|
declare function ipv6(rng: Rng): string;
|
|
251
251
|
/**
|
|
252
252
|
* A **deterministic UUIDv4-shaped** surrogate key from the seeded generator. Because it is seeded (not
|
|
253
|
-
* from `node:crypto`, which is not reproducible), the cryptographic non-collision argument is weaker
|
|
253
|
+
* from `node:crypto`, which is not reproducible), the cryptographic non-collision argument is weaker,
|
|
254
254
|
* acceptable because the identifier namespace is synthetic anyway, and noted honestly.
|
|
255
255
|
*
|
|
256
256
|
* @param rng - The seeded generator.
|
|
@@ -263,7 +263,7 @@ declare function ipv6(rng: Rng): string;
|
|
|
263
263
|
*/
|
|
264
264
|
declare function uuid(rng: Rng): string;
|
|
265
265
|
/**
|
|
266
|
-
* A **synthetic NPI
|
|
266
|
+
* A **synthetic NPI**: a 10-digit National Provider Identifier with a **deliberately-invalid Luhn
|
|
267
267
|
* check digit**, so it can never be a NPPES-issued NPI (a real NPI must satisfy the `80840`-prefixed
|
|
268
268
|
* Luhn check). The 9-digit base is drawn from the seeded generator; the check digit is
|
|
269
269
|
* set to `(correct + 1) mod 10`, guaranteeing the full value fails validation.
|
|
@@ -273,18 +273,18 @@ declare function uuid(rng: Rng): string;
|
|
|
273
273
|
* @example
|
|
274
274
|
* ```ts
|
|
275
275
|
* import { createRng, npi, isSyntheticNpi } from "@cosyte/synth";
|
|
276
|
-
* isSyntheticNpi(npi(createRng(1))); // true
|
|
276
|
+
* isSyntheticNpi(npi(createRng(1))); // true: invalid check digit by construction
|
|
277
277
|
* ```
|
|
278
278
|
*/
|
|
279
279
|
declare function npi(rng: Rng): string;
|
|
280
280
|
/**
|
|
281
|
-
* A **synthetic DEA number
|
|
281
|
+
* A **synthetic DEA number**: `<registrant-type><initial>` + 7 digits with a **deliberately-invalid
|
|
282
282
|
* checksum**, so it can never be a validly-issued DEA registration (a real DEA number's 7th digit
|
|
283
283
|
* satisfies the published DEA checksum). The first letter is a registrant-type letter, the
|
|
284
284
|
* second is derived from `person` (its family initial) when supplied so the number reads plausibly; the
|
|
285
285
|
* 6-digit base is seeded and the check digit is set to `(correct + 1) mod 10`, guaranteeing the value
|
|
286
286
|
* fails validation. NCPDP carries prescriber DEA, and this is the identity locus a refuter attacks
|
|
287
|
-
* hardest, so
|
|
287
|
+
* hardest, so, like {@link npi}, non-collision is a construction-level guarantee, not a heuristic.
|
|
288
288
|
*
|
|
289
289
|
* @param rng - The seeded generator.
|
|
290
290
|
* @param person - Optional name whose family initial becomes the DEA's second letter.
|
|
@@ -292,7 +292,7 @@ declare function npi(rng: Rng): string;
|
|
|
292
292
|
* @example
|
|
293
293
|
* ```ts
|
|
294
294
|
* import { createRng, dea, isSyntheticDea } from "@cosyte/synth";
|
|
295
|
-
* isSyntheticDea(dea(createRng(1))); // true
|
|
295
|
+
* isSyntheticDea(dea(createRng(1))); // true: invalid checksum by construction
|
|
296
296
|
* ```
|
|
297
297
|
*/
|
|
298
298
|
declare function dea(rng: Rng, person?: SyntheticName): string;
|
|
@@ -312,7 +312,7 @@ declare function dea(rng: Rng, person?: SyntheticName): string;
|
|
|
312
312
|
*/
|
|
313
313
|
declare function identifier(rng: Rng, typeCode?: SyntheticIdentifier["typeCode"]): SyntheticIdentifier;
|
|
314
314
|
/**
|
|
315
|
-
* A **synthetic address
|
|
315
|
+
* A **synthetic address**: a fake street + city, a reserved non-real ZIP (`00000`). A real state
|
|
316
316
|
* abbreviation may appear (structural only) but is never combined with a real street + name + DOB.
|
|
317
317
|
*
|
|
318
318
|
* @param rng - The seeded generator.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The `Corpus` abstraction
|
|
2
|
+
* The `Corpus` abstraction: a seed plus a self-describing manifest of what was generated, so a
|
|
3
3
|
* fixture set is itself reproducible and regenerable. A downstream repo pins a seed
|
|
4
4
|
* and gets a stable fixture set that regenerates identically.
|
|
5
5
|
*
|
|
6
|
-
* Generated artifacts and the `Corpus` are **deep-frozen
|
|
6
|
+
* Generated artifacts and the `Corpus` are **deep-frozen**: this is where the archetype's immutability
|
|
7
7
|
* invariant lives in a generator: a consumer cannot mutate a shared fixture out from under
|
|
8
8
|
* another test.
|
|
9
9
|
*
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
/** The format an artifact was generated for. */
|
|
13
13
|
type SynthFormat = "hl7v2" | "fhir" | "ccda" | "x12" | "ncpdp" | "astm";
|
|
14
14
|
/**
|
|
15
|
-
* One generated artifact
|
|
15
|
+
* One generated artifact: the serialized wire text plus the metadata needed to reproduce and check
|
|
16
16
|
* it. `warnings` records what the artifact's own parser reported on the round-trip (zero for a
|
|
17
17
|
* spec-clean artifact).
|
|
18
18
|
*/
|
|
@@ -37,7 +37,7 @@ interface CorpusManifest {
|
|
|
37
37
|
}
|
|
38
38
|
/** A reproducible, self-describing set of generated artifacts. */
|
|
39
39
|
interface Corpus {
|
|
40
|
-
/** The seed the corpus was generated from
|
|
40
|
+
/** The seed the corpus was generated from: regenerating from it yields byte-identical artifacts. */
|
|
41
41
|
readonly seed: number;
|
|
42
42
|
/** The manifest describing what was generated. */
|
|
43
43
|
readonly manifest: CorpusManifest;
|
|
@@ -61,16 +61,16 @@ interface Corpus {
|
|
|
61
61
|
declare function makeCorpus(seed: number, artifacts: readonly Artifact[], quirks?: readonly string[]): Corpus;
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
|
-
* `Rng
|
|
64
|
+
* `Rng`: the seeded, deterministic random source every `@cosyte/synth` provider draws from.
|
|
65
65
|
*
|
|
66
|
-
* **The reproducibility contract.** A seed
|
|
66
|
+
* **The reproducibility contract.** A seed, and only the seed, determines the output.
|
|
67
67
|
* `createRng(seed)` expands the integer seed through {@link ./splitmix32.splitmix32} into the four
|
|
68
68
|
* `sfc32` state words, then every draw advances that state via {@link ./sfc32.sfc32Next}. Two `Rng`s
|
|
69
|
-
* created from the same seed emit the **identical** sequence on any machine, any run
|
|
69
|
+
* created from the same seed emit the **identical** sequence on any machine, any run: the property
|
|
70
70
|
* the parsers', `transform`'s, and `deid`'s regression suites depend on.
|
|
71
71
|
*
|
|
72
72
|
* **Explicit, never global.** An `Rng` is a value you thread through a build; there is no ambient
|
|
73
|
-
* shared generator and **`Math.random` is lint-banned** in `src/` (it is not seedable
|
|
73
|
+
* shared generator and **`Math.random` is lint-banned** in `src/` (it is not seedable: its seed is
|
|
74
74
|
* engine-chosen and cannot be reset, so a corpus built on it is not reproducible). Because each
|
|
75
75
|
* generation creates a fresh `Rng` from its seed, generations are independent and parallel-safe.
|
|
76
76
|
*
|
|
@@ -128,13 +128,13 @@ interface Rng {
|
|
|
128
128
|
declare function createRng(seed: number): Rng;
|
|
129
129
|
|
|
130
130
|
/**
|
|
131
|
-
* The synthetic-safety provider layer
|
|
131
|
+
* The synthetic-safety provider layer: every identifier, contact point, name, and date
|
|
132
132
|
* `@cosyte/synth` emits is minted here, and **only** from a guaranteed-non-colliding source. There is no code
|
|
133
133
|
* path that returns a value not drawn from a reserved range or the
|
|
134
134
|
* shipped fake-name pool. This is the inverse of a parser's liberality: the generator is *closed-world*
|
|
135
135
|
* on its data sources, so no output *can* be real or plausibly-real PHI.
|
|
136
136
|
*
|
|
137
|
-
* All providers are pure functions of an explicit {@link ../rng/rng.Rng}
|
|
137
|
+
* All providers are pure functions of an explicit {@link ../rng/rng.Rng}, same seed, same values.
|
|
138
138
|
*
|
|
139
139
|
* @module
|
|
140
140
|
*/
|
|
@@ -146,7 +146,7 @@ interface SyntheticName {
|
|
|
146
146
|
/** A clearly-fake family name. */
|
|
147
147
|
readonly family: string;
|
|
148
148
|
}
|
|
149
|
-
/** A synthetic postal address
|
|
149
|
+
/** A synthetic postal address: synthetic street + city, a fixed non-real ZIP. */
|
|
150
150
|
interface SyntheticAddress {
|
|
151
151
|
/** A clearly-fake street line. */
|
|
152
152
|
readonly street: string;
|
|
@@ -159,7 +159,7 @@ interface SyntheticAddress {
|
|
|
159
159
|
}
|
|
160
160
|
/** A synthetic identifier scoped to the synthetic assigning authority. */
|
|
161
161
|
interface SyntheticIdentifier {
|
|
162
|
-
/** The identifier value (digits)
|
|
162
|
+
/** The identifier value (digits): unique only within the synthetic namespace. */
|
|
163
163
|
readonly value: string;
|
|
164
164
|
/** HL7 identifier type code (`MR` = medical record, `AN` = account, `MB` = member). */
|
|
165
165
|
readonly typeCode: "MR" | "AN" | "MB";
|
|
@@ -171,7 +171,7 @@ interface SyntheticIdentifier {
|
|
|
171
171
|
/** Which SSN reserved space to draw from. */
|
|
172
172
|
type SsnBlock = "never-issued" | "advertising";
|
|
173
173
|
/**
|
|
174
|
-
* A **synthetic SSN
|
|
174
|
+
* A **synthetic SSN**: dashed `AAA-GG-SSSS`. Default draws the SSA never-issued area space
|
|
175
175
|
* (`900–999`); `block: "advertising"` draws SSA's reserved advertising block (`987-65-4320…4329`).
|
|
176
176
|
* A value from this function can never be a real SSN.
|
|
177
177
|
*
|
|
@@ -186,7 +186,7 @@ type SsnBlock = "never-issued" | "advertising";
|
|
|
186
186
|
*/
|
|
187
187
|
declare function ssn(rng: Rng, block?: SsnBlock): string;
|
|
188
188
|
/**
|
|
189
|
-
* A **synthetic phone** in the NANP reserved fictional block
|
|
189
|
+
* A **synthetic phone** in the NANP reserved fictional block: `(AAA) 555-01NN`. The reserved
|
|
190
190
|
* guarantee is the `555-01NN` tail (exchange 555, line 0100–0199); the area code is any NANP-valid
|
|
191
191
|
* `NXX`. Can never be a working number.
|
|
192
192
|
*
|
|
@@ -212,7 +212,7 @@ declare function phone(rng: Rng): string;
|
|
|
212
212
|
*/
|
|
213
213
|
declare function name(rng: Rng): SyntheticName;
|
|
214
214
|
/**
|
|
215
|
-
* A **synthetic email** at an RFC 2606 / 6761 reserved domain
|
|
215
|
+
* A **synthetic email** at an RFC 2606 / 6761 reserved domain: `<slug>@example.com`.
|
|
216
216
|
*
|
|
217
217
|
* @param rng - The seeded generator.
|
|
218
218
|
* @param person - Optional name to derive the local-part slug from; otherwise a random slug is used.
|
|
@@ -225,7 +225,7 @@ declare function name(rng: Rng): SyntheticName;
|
|
|
225
225
|
*/
|
|
226
226
|
declare function email(rng: Rng, person?: SyntheticName): string;
|
|
227
227
|
/**
|
|
228
|
-
* A **synthetic IPv4** in an RFC 5737 TEST-NET block
|
|
228
|
+
* A **synthetic IPv4** in an RFC 5737 TEST-NET block, never routable.
|
|
229
229
|
*
|
|
230
230
|
* @param rng - The seeded generator.
|
|
231
231
|
* @returns A TEST-NET IPv4 address string.
|
|
@@ -237,7 +237,7 @@ declare function email(rng: Rng, person?: SyntheticName): string;
|
|
|
237
237
|
*/
|
|
238
238
|
declare function ipv4(rng: Rng): string;
|
|
239
239
|
/**
|
|
240
|
-
* A **synthetic IPv6** in the RFC 3849 documentation prefix `2001:db8::/32
|
|
240
|
+
* A **synthetic IPv6** in the RFC 3849 documentation prefix `2001:db8::/32`, never routable.
|
|
241
241
|
*
|
|
242
242
|
* @param rng - The seeded generator.
|
|
243
243
|
* @returns A documentation-prefix IPv6 address string.
|
|
@@ -250,7 +250,7 @@ declare function ipv4(rng: Rng): string;
|
|
|
250
250
|
declare function ipv6(rng: Rng): string;
|
|
251
251
|
/**
|
|
252
252
|
* A **deterministic UUIDv4-shaped** surrogate key from the seeded generator. Because it is seeded (not
|
|
253
|
-
* from `node:crypto`, which is not reproducible), the cryptographic non-collision argument is weaker
|
|
253
|
+
* from `node:crypto`, which is not reproducible), the cryptographic non-collision argument is weaker,
|
|
254
254
|
* acceptable because the identifier namespace is synthetic anyway, and noted honestly.
|
|
255
255
|
*
|
|
256
256
|
* @param rng - The seeded generator.
|
|
@@ -263,7 +263,7 @@ declare function ipv6(rng: Rng): string;
|
|
|
263
263
|
*/
|
|
264
264
|
declare function uuid(rng: Rng): string;
|
|
265
265
|
/**
|
|
266
|
-
* A **synthetic NPI
|
|
266
|
+
* A **synthetic NPI**: a 10-digit National Provider Identifier with a **deliberately-invalid Luhn
|
|
267
267
|
* check digit**, so it can never be a NPPES-issued NPI (a real NPI must satisfy the `80840`-prefixed
|
|
268
268
|
* Luhn check). The 9-digit base is drawn from the seeded generator; the check digit is
|
|
269
269
|
* set to `(correct + 1) mod 10`, guaranteeing the full value fails validation.
|
|
@@ -273,18 +273,18 @@ declare function uuid(rng: Rng): string;
|
|
|
273
273
|
* @example
|
|
274
274
|
* ```ts
|
|
275
275
|
* import { createRng, npi, isSyntheticNpi } from "@cosyte/synth";
|
|
276
|
-
* isSyntheticNpi(npi(createRng(1))); // true
|
|
276
|
+
* isSyntheticNpi(npi(createRng(1))); // true: invalid check digit by construction
|
|
277
277
|
* ```
|
|
278
278
|
*/
|
|
279
279
|
declare function npi(rng: Rng): string;
|
|
280
280
|
/**
|
|
281
|
-
* A **synthetic DEA number
|
|
281
|
+
* A **synthetic DEA number**: `<registrant-type><initial>` + 7 digits with a **deliberately-invalid
|
|
282
282
|
* checksum**, so it can never be a validly-issued DEA registration (a real DEA number's 7th digit
|
|
283
283
|
* satisfies the published DEA checksum). The first letter is a registrant-type letter, the
|
|
284
284
|
* second is derived from `person` (its family initial) when supplied so the number reads plausibly; the
|
|
285
285
|
* 6-digit base is seeded and the check digit is set to `(correct + 1) mod 10`, guaranteeing the value
|
|
286
286
|
* fails validation. NCPDP carries prescriber DEA, and this is the identity locus a refuter attacks
|
|
287
|
-
* hardest, so
|
|
287
|
+
* hardest, so, like {@link npi}, non-collision is a construction-level guarantee, not a heuristic.
|
|
288
288
|
*
|
|
289
289
|
* @param rng - The seeded generator.
|
|
290
290
|
* @param person - Optional name whose family initial becomes the DEA's second letter.
|
|
@@ -292,7 +292,7 @@ declare function npi(rng: Rng): string;
|
|
|
292
292
|
* @example
|
|
293
293
|
* ```ts
|
|
294
294
|
* import { createRng, dea, isSyntheticDea } from "@cosyte/synth";
|
|
295
|
-
* isSyntheticDea(dea(createRng(1))); // true
|
|
295
|
+
* isSyntheticDea(dea(createRng(1))); // true: invalid checksum by construction
|
|
296
296
|
* ```
|
|
297
297
|
*/
|
|
298
298
|
declare function dea(rng: Rng, person?: SyntheticName): string;
|
|
@@ -312,7 +312,7 @@ declare function dea(rng: Rng, person?: SyntheticName): string;
|
|
|
312
312
|
*/
|
|
313
313
|
declare function identifier(rng: Rng, typeCode?: SyntheticIdentifier["typeCode"]): SyntheticIdentifier;
|
|
314
314
|
/**
|
|
315
|
-
* A **synthetic address
|
|
315
|
+
* A **synthetic address**: a fake street + city, a reserved non-real ZIP (`00000`). A real state
|
|
316
316
|
* abbreviation may appear (structural only) but is never combined with a real street + name + DOB.
|
|
317
317
|
*
|
|
318
318
|
* @param rng - The seeded generator.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { m as SynthFormat } from './providers-
|
|
1
|
+
import { m as SynthFormat } from './providers-B9uVinAe.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* `defineSynthProfile
|
|
4
|
+
* `defineSynthProfile`: the growth-loop hook for site/vendor fixture recipes. A profile bundles the
|
|
5
5
|
* value pools and the quirk recipe a fixture set should use, authored through the same public API as
|
|
6
6
|
* the built-ins: a validated, frozen `SynthProfile` carrying a name, optional value overrides, and the
|
|
7
7
|
* quirk names a format's quirk corpus should apply.
|
|
@@ -12,7 +12,7 @@ import { m as SynthFormat } from './providers-OLz3zAc-.js';
|
|
|
12
12
|
interface SynthProfileSpec {
|
|
13
13
|
/** A stable, human-readable profile name (e.g. `"acme-hospital"`). Required, non-empty. */
|
|
14
14
|
readonly name: string;
|
|
15
|
-
/** Optional given-name pool override (clearly-synthetic names only
|
|
15
|
+
/** Optional given-name pool override (clearly-synthetic names only, see the safety invariant). */
|
|
16
16
|
readonly givenNames?: readonly string[];
|
|
17
17
|
/** Optional family-name pool override (clearly-synthetic names only). */
|
|
18
18
|
readonly familyNames?: readonly string[];
|
|
@@ -52,9 +52,9 @@ declare function defineSynthProfile(spec: SynthProfileSpec): SynthProfile;
|
|
|
52
52
|
* The **quirk core**. Where the spec-clean generators prove
|
|
53
53
|
* *synthetic-by-construction* through each parser's own builder, the quirk layer proves the mirror
|
|
54
54
|
* property: a **deliberately off-spec** fixture round-trips to **exactly the intended parser warning
|
|
55
|
-
* code(s)
|
|
55
|
+
* code(s)**, no more, no fewer. The quirk vocabulary **is the parsers' own profile systems**
|
|
56
56
|
* (`hl7.defineProfile`, `ccda.defineCcdaProfile`, `astm.defineAstmProfile`): a quirk exercises exactly
|
|
57
|
-
* the tolerance the corresponding parser profile encodes, so a quirk fixture is never a fiction
|
|
57
|
+
* the tolerance the corresponding parser profile encodes, so a quirk fixture is never a fiction, it
|
|
58
58
|
* targets a documented, coded leniency (the **intended-warning contract**).
|
|
59
59
|
*
|
|
60
60
|
* This module is the **format-agnostic** part: the descriptor a quirk carries, the artifact a quirk
|
|
@@ -65,25 +65,25 @@ declare function defineSynthProfile(spec: SynthProfileSpec): SynthProfile;
|
|
|
65
65
|
*/
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
|
-
* How the parser's matching profile treats a quirk once it is active
|
|
68
|
+
* How the parser's matching profile treats a quirk once it is active: the three shapes the parsers'
|
|
69
69
|
* profile systems actually exhibit (verified firsthand against each parser):
|
|
70
70
|
*
|
|
71
|
-
* - `"suppressed"
|
|
71
|
+
* - `"suppressed"`, the profile makes the warning **disappear** (HL7 v2: a `defineProfile`
|
|
72
72
|
* `customSegments` claim suppresses `UNKNOWN_SEGMENT` for a declared Z-segment).
|
|
73
|
-
* - `"rebadged"
|
|
73
|
+
* - `"rebadged"`, the profile **downgrades** the warning to the value-free `PROFILE_QUIRK_APPLIED`
|
|
74
74
|
* marker with `expected: true` (C-CDA `defineCcdaProfile` / ASTM `defineAstmProfile`
|
|
75
75
|
* `profileQuirkApplied`).
|
|
76
|
-
* - `"bare"
|
|
76
|
+
* - `"bare"`, no shipped profile tolerates it; the quirk targets a real coded leniency a consumer can
|
|
77
77
|
* tolerate via their own `defineProfile`/`defineAstmProfile`, but no built-in re-badges it.
|
|
78
78
|
*/
|
|
79
79
|
type QuirkProfileDisposition = "suppressed" | "rebadged" | "bare";
|
|
80
80
|
/**
|
|
81
81
|
* The stable, value-free re-badge code the C-CDA and ASTM parsers emit when a profile tolerates a
|
|
82
|
-
* quirk. HL7 v2 has no equivalent (it suppresses instead
|
|
82
|
+
* quirk. HL7 v2 has no equivalent (it suppresses instead: see {@link QuirkProfileDisposition}).
|
|
83
83
|
*/
|
|
84
84
|
declare const PROFILE_QUIRK_APPLIED = "PROFILE_QUIRK_APPLIED";
|
|
85
85
|
/**
|
|
86
|
-
* A public, grounded description of one vendor quirk
|
|
86
|
+
* A public, grounded description of one vendor quirk: the metadata that binds a quirk recipe to a real
|
|
87
87
|
* parser warning code and a **publicly-groundable** deviation (cited-public, never a private
|
|
88
88
|
* vendor corpus).
|
|
89
89
|
*/
|
|
@@ -93,12 +93,12 @@ interface QuirkDescriptor {
|
|
|
93
93
|
/** The format this quirk applies to. */
|
|
94
94
|
readonly format: SynthFormat;
|
|
95
95
|
/**
|
|
96
|
-
* The **exact** parser warning code(s) a bare parse (no profile) surfaces for this quirk
|
|
96
|
+
* The **exact** parser warning code(s) a bare parse (no profile) surfaces for this quirk, the
|
|
97
97
|
* intended-warning contract. A quirk that produces any other code, or none, is a generation bug.
|
|
98
98
|
*/
|
|
99
99
|
readonly intendedWarnings: readonly string[];
|
|
100
100
|
/**
|
|
101
|
-
* The **public** grounding for this quirk
|
|
101
|
+
* The **public** grounding for this quirk, the spec clause or the parser's public profile that
|
|
102
102
|
* documents the tolerance. Never a private vendor-attributed corpus.
|
|
103
103
|
*/
|
|
104
104
|
readonly grounding: string;
|
|
@@ -107,7 +107,7 @@ interface QuirkDescriptor {
|
|
|
107
107
|
/** How {@link toleratingProfile} treats the quirk. */
|
|
108
108
|
readonly disposition: QuirkProfileDisposition;
|
|
109
109
|
}
|
|
110
|
-
/** One generated quirk artifact
|
|
110
|
+
/** One generated quirk artifact: the off-spec wire text plus the contract it is meant to satisfy. */
|
|
111
111
|
interface QuirkArtifact {
|
|
112
112
|
/** The format this artifact belongs to. */
|
|
113
113
|
readonly format: SynthFormat;
|
|
@@ -143,14 +143,14 @@ interface QuirkRoundTripResult {
|
|
|
143
143
|
/** The exact code(s) the quirk is meant to produce. */
|
|
144
144
|
readonly intendedWarnings: readonly string[];
|
|
145
145
|
/**
|
|
146
|
-
* `true` iff the bare parse produced **exactly** the intended code(s)
|
|
146
|
+
* `true` iff the bare parse produced **exactly** the intended code(s), the intended-warning contract.
|
|
147
147
|
*/
|
|
148
148
|
readonly intendedWarningHeld: boolean;
|
|
149
149
|
/** The verdict under the tolerating profile, when a built-in public one exists. */
|
|
150
150
|
readonly withProfile?: QuirkProfiledVerdict;
|
|
151
151
|
}
|
|
152
152
|
/**
|
|
153
|
-
* Exact multiset (order-independent) equality of two code lists
|
|
153
|
+
* Exact multiset (order-independent) equality of two code lists: the intended-warning comparison.
|
|
154
154
|
*
|
|
155
155
|
* @param a - The first code list.
|
|
156
156
|
* @param b - The second code list.
|
|
@@ -164,12 +164,12 @@ interface QuirkRoundTripResult {
|
|
|
164
164
|
declare function sameCodeSet(a: readonly string[], b: readonly string[]): boolean;
|
|
165
165
|
/**
|
|
166
166
|
* Resolve a requested quirk name against a format's registry, or **fail closed**. A quirk the format's
|
|
167
|
-
* profile system does not support is a fatal `SYNTH_UNSUPPORTED_QUIRK
|
|
167
|
+
* profile system does not support is a fatal `SYNTH_UNSUPPORTED_QUIRK`, never a silent no-op and never
|
|
168
168
|
* a fabricated quirk with a made-up warning.
|
|
169
169
|
*
|
|
170
170
|
* The refusal names neither the request nor the registry. `registry`, `format` and `name` are all
|
|
171
171
|
* caller-supplied, and a diagnostic that quotes its input is a diagnostic that can be made to carry
|
|
172
|
-
* anything the caller was holding
|
|
172
|
+
* anything the caller was holding, which for a fixture generator wired into someone else's pipeline
|
|
173
173
|
* is not a hypothetical. Branch on `err.code`; the supported set is the registry you passed
|
|
174
174
|
* (`HL7_QUIRKS`, `CCDA_QUIRKS`, `ASTM_QUIRKS`), which you can enumerate directly.
|
|
175
175
|
*
|
|
@@ -197,22 +197,22 @@ declare function resolveQuirk(registry: Readonly<Record<string, QuirkDescriptor>
|
|
|
197
197
|
* @example
|
|
198
198
|
* ```ts
|
|
199
199
|
* import { profileTolerated } from "@cosyte/synth";
|
|
200
|
-
* profileTolerated("suppressed", ["UNKNOWN_SEGMENT"], []); // true
|
|
200
|
+
* profileTolerated("suppressed", ["UNKNOWN_SEGMENT"], []); // true: the profile suppressed it
|
|
201
201
|
* ```
|
|
202
202
|
*/
|
|
203
203
|
declare function profileTolerated(disposition: QuirkProfileDisposition, intendedWarnings: readonly string[], warningsUnderProfile: readonly string[]): boolean;
|
|
204
204
|
/**
|
|
205
205
|
* Assert a freshly-generated quirk artifact **actually** round-trips to its intended warning(s), or
|
|
206
206
|
* **fail closed**. This is the generator's self-check on the intended-warning contract: a
|
|
207
|
-
* fixture whose bare parse does not produce exactly the declared code(s) is a *mislabeled* fixture
|
|
208
|
-
* golden file that lies about the parser verdict it anchors
|
|
207
|
+
* fixture whose bare parse does not produce exactly the declared code(s) is a *mislabeled* fixture, a
|
|
208
|
+
* golden file that lies about the parser verdict it anchors, and must never be emitted. It is a
|
|
209
209
|
* stronger guard than "the transform changed some bytes": a transform can mutate the wrong element (a
|
|
210
210
|
* template a given document type does not key its warning on) and still change bytes while producing no
|
|
211
211
|
* warning. Every format's `generate*Quirk` calls this after transforming, so the contract is enforced at
|
|
212
212
|
* generation time, not merely at round-trip time.
|
|
213
213
|
*
|
|
214
|
-
* It no longer takes the quirk name. That parameter existed for one reason
|
|
215
|
-
* the refusal
|
|
214
|
+
* It no longer takes the quirk name. That parameter existed for one reason, to be interpolated into
|
|
215
|
+
* the refusal, and a parameter whose only job is to reach a message is the exact shape this package
|
|
216
216
|
* is removing, so it is gone rather than merely unused. The refusal names neither code list either;
|
|
217
217
|
* both are caller-supplied, and the caller reads the comparison back off the arguments it holds.
|
|
218
218
|
*
|