@cosyte/synth 0.1.9 → 0.1.10
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 +29 -0
- package/README.md +28 -17
- package/dist/animal-code-Bdl_9Jma.d.cts +30 -0
- package/dist/animal-code-Bdl_9Jma.d.ts +30 -0
- package/dist/astm/index.cjs +147 -17
- package/dist/astm/index.cjs.map +1 -1
- package/dist/astm/index.d.cts +22 -9
- package/dist/astm/index.d.ts +22 -9
- package/dist/astm/index.mjs +147 -17
- package/dist/astm/index.mjs.map +1 -1
- package/dist/ccda/index.cjs +147 -17
- package/dist/ccda/index.cjs.map +1 -1
- package/dist/ccda/index.d.cts +12 -3
- package/dist/ccda/index.d.ts +12 -3
- package/dist/ccda/index.mjs +147 -17
- package/dist/ccda/index.mjs.map +1 -1
- package/dist/deid/index.cjs +537 -30
- package/dist/deid/index.cjs.map +1 -1
- package/dist/deid/index.d.cts +2 -1
- package/dist/deid/index.d.ts +2 -1
- package/dist/deid/index.mjs +537 -30
- package/dist/deid/index.mjs.map +1 -1
- package/dist/fhir/index.cjs +142 -14
- package/dist/fhir/index.cjs.map +1 -1
- package/dist/fhir/index.d.cts +4 -1
- package/dist/fhir/index.d.ts +4 -1
- package/dist/fhir/index.mjs +142 -14
- package/dist/fhir/index.mjs.map +1 -1
- package/dist/hl7/index.cjs +566 -39
- package/dist/hl7/index.cjs.map +1 -1
- package/dist/hl7/index.d.cts +402 -111
- package/dist/hl7/index.d.ts +402 -111
- package/dist/hl7/index.mjs +557 -40
- package/dist/hl7/index.mjs.map +1 -1
- package/dist/index.cjs +124 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +183 -10
- package/dist/index.d.ts +183 -10
- package/dist/index.mjs +115 -14
- package/dist/index.mjs.map +1 -1
- package/dist/ncpdp/index.cjs +142 -14
- package/dist/ncpdp/index.cjs.map +1 -1
- package/dist/ncpdp/index.d.cts +4 -1
- package/dist/ncpdp/index.d.ts +4 -1
- package/dist/ncpdp/index.mjs +142 -14
- package/dist/ncpdp/index.mjs.map +1 -1
- package/dist/{quirk-BfObsiWV.d.ts → quirk-CzknuYUo.d.ts} +16 -5
- package/dist/{quirk-BCSs1jPt.d.cts → quirk-Q5AxzHSC.d.cts} +16 -5
- package/dist/x12/index.cjs +142 -14
- package/dist/x12/index.cjs.map +1 -1
- package/dist/x12/index.d.cts +4 -1
- package/dist/x12/index.d.ts +4 -1
- package/dist/x12/index.mjs +142 -14
- package/dist/x12/index.mjs.map +1 -1
- package/package.json +7 -4
package/dist/astm/index.d.cts
CHANGED
|
@@ -134,8 +134,8 @@ declare function astmFramedRoundTrip(bytes: Uint8Array): AstmRoundTripResult;
|
|
|
134
134
|
|
|
135
135
|
/**
|
|
136
136
|
* Synthetic identity for ASTM (E1394 / CLSI LIS02) messages: every value `synth` puts into a `P`
|
|
137
|
-
* (patient) record, an `O` (order) accession, or the `H` header is minted here, and
|
|
138
|
-
* synthetic-safety providers. ASTM's PHI-dense locus is the **`P` record**: it carries the
|
|
137
|
+
* (patient) record, an `O` (order) accession, or the `H` header's sender is minted here, and
|
|
138
|
+
* **only** from the synthetic-safety providers. ASTM's PHI-dense locus is the **`P` record**: it carries the
|
|
139
139
|
* patient **name** (`Last^First^Middle`), **birthdate**, **sex**, and the **practice-assigned** and
|
|
140
140
|
* **laboratory-assigned** patient IDs, which must stay
|
|
141
141
|
* **distinct** (the parser keeps them distinct; a generator that let one default from the other would
|
|
@@ -169,11 +169,17 @@ interface AstmOrder {
|
|
|
169
169
|
/** Priority code, emitted verbatim (`R` routine, `S` stat). */
|
|
170
170
|
readonly priority: "R" | "S";
|
|
171
171
|
}
|
|
172
|
-
/**
|
|
172
|
+
/**
|
|
173
|
+
* A synthetic ASTM header identity: the sender name the `H` record carries in `H.5`, and an analyzer
|
|
174
|
+
* string that no generator writes into a message.
|
|
175
|
+
*/
|
|
173
176
|
interface AstmHeaderIdentity {
|
|
174
|
-
/** The sending system
|
|
177
|
+
/** The sending system's name, written to `H.5` (clearly synthetic). */
|
|
175
178
|
readonly sender: string;
|
|
176
|
-
/**
|
|
179
|
+
/**
|
|
180
|
+
* An analyzer / instrument string (clearly synthetic). Drawn so a seed keeps its draw order; the
|
|
181
|
+
* generators leave it out of the message.
|
|
182
|
+
*/
|
|
177
183
|
readonly analyzer: string;
|
|
178
184
|
}
|
|
179
185
|
/**
|
|
@@ -205,7 +211,8 @@ declare function astmPatient(rng: Rng): AstmPatient;
|
|
|
205
211
|
*/
|
|
206
212
|
declare function astmOrder(rng: Rng): AstmOrder;
|
|
207
213
|
/**
|
|
208
|
-
* Mint a synthetic header identity for the `H` record
|
|
214
|
+
* Mint a synthetic header identity: a clearly-synthetic sender for the `H` record's `H.5`, and an
|
|
215
|
+
* analyzer string, drawn after it, that the generators leave out of the message.
|
|
209
216
|
*
|
|
210
217
|
* @param rng - The seeded generator.
|
|
211
218
|
* @returns A synthetic {@link AstmHeaderIdentity}.
|
|
@@ -346,9 +353,15 @@ interface AstmQuirkCorpusOptions {
|
|
|
346
353
|
readonly seed: number;
|
|
347
354
|
/** How many quirk artifacts to generate. Defaults to the number of quirks. */
|
|
348
355
|
readonly count?: number;
|
|
349
|
-
/**
|
|
356
|
+
/**
|
|
357
|
+
* The quirk names to cycle through. Defaults to every ASTM quirk. Validated; unsupported ⇒ fatal.
|
|
358
|
+
* An empty list, or a `profile` whose `quirks` is an empty list, throws `SYNTH_EMPTY_POOL`.
|
|
359
|
+
*/
|
|
350
360
|
readonly quirks?: readonly AstmQuirkName[];
|
|
351
|
-
/**
|
|
361
|
+
/**
|
|
362
|
+
* A {@link SynthProfile} whose `quirks` drive the corpus (validated). Its `quirks`, when set, take
|
|
363
|
+
* precedence over `quirks`; a profile that leaves `quirks` out leaves the selection to `quirks`.
|
|
364
|
+
*/
|
|
352
365
|
readonly profile?: SynthProfile;
|
|
353
366
|
}
|
|
354
367
|
/**
|
|
@@ -397,7 +410,7 @@ interface AstmCorpusOptions {
|
|
|
397
410
|
readonly seed: number;
|
|
398
411
|
/** How many messages to generate. Defaults to the length of the mix. */
|
|
399
412
|
readonly count?: number;
|
|
400
|
-
/** The message kinds to cycle through. Defaults to one of each. */
|
|
413
|
+
/** The message kinds to cycle through. Defaults to one of each. An empty list throws `SYNTH_EMPTY_POOL`. */
|
|
401
414
|
readonly mix?: readonly AstmCorpusKind[];
|
|
402
415
|
/**
|
|
403
416
|
* Whether each artifact is read back through its parser and the parser's findings recorded as its
|
package/dist/astm/index.d.ts
CHANGED
|
@@ -134,8 +134,8 @@ declare function astmFramedRoundTrip(bytes: Uint8Array): AstmRoundTripResult;
|
|
|
134
134
|
|
|
135
135
|
/**
|
|
136
136
|
* Synthetic identity for ASTM (E1394 / CLSI LIS02) messages: every value `synth` puts into a `P`
|
|
137
|
-
* (patient) record, an `O` (order) accession, or the `H` header is minted here, and
|
|
138
|
-
* synthetic-safety providers. ASTM's PHI-dense locus is the **`P` record**: it carries the
|
|
137
|
+
* (patient) record, an `O` (order) accession, or the `H` header's sender is minted here, and
|
|
138
|
+
* **only** from the synthetic-safety providers. ASTM's PHI-dense locus is the **`P` record**: it carries the
|
|
139
139
|
* patient **name** (`Last^First^Middle`), **birthdate**, **sex**, and the **practice-assigned** and
|
|
140
140
|
* **laboratory-assigned** patient IDs, which must stay
|
|
141
141
|
* **distinct** (the parser keeps them distinct; a generator that let one default from the other would
|
|
@@ -169,11 +169,17 @@ interface AstmOrder {
|
|
|
169
169
|
/** Priority code, emitted verbatim (`R` routine, `S` stat). */
|
|
170
170
|
readonly priority: "R" | "S";
|
|
171
171
|
}
|
|
172
|
-
/**
|
|
172
|
+
/**
|
|
173
|
+
* A synthetic ASTM header identity: the sender name the `H` record carries in `H.5`, and an analyzer
|
|
174
|
+
* string that no generator writes into a message.
|
|
175
|
+
*/
|
|
173
176
|
interface AstmHeaderIdentity {
|
|
174
|
-
/** The sending system
|
|
177
|
+
/** The sending system's name, written to `H.5` (clearly synthetic). */
|
|
175
178
|
readonly sender: string;
|
|
176
|
-
/**
|
|
179
|
+
/**
|
|
180
|
+
* An analyzer / instrument string (clearly synthetic). Drawn so a seed keeps its draw order; the
|
|
181
|
+
* generators leave it out of the message.
|
|
182
|
+
*/
|
|
177
183
|
readonly analyzer: string;
|
|
178
184
|
}
|
|
179
185
|
/**
|
|
@@ -205,7 +211,8 @@ declare function astmPatient(rng: Rng): AstmPatient;
|
|
|
205
211
|
*/
|
|
206
212
|
declare function astmOrder(rng: Rng): AstmOrder;
|
|
207
213
|
/**
|
|
208
|
-
* Mint a synthetic header identity for the `H` record
|
|
214
|
+
* Mint a synthetic header identity: a clearly-synthetic sender for the `H` record's `H.5`, and an
|
|
215
|
+
* analyzer string, drawn after it, that the generators leave out of the message.
|
|
209
216
|
*
|
|
210
217
|
* @param rng - The seeded generator.
|
|
211
218
|
* @returns A synthetic {@link AstmHeaderIdentity}.
|
|
@@ -346,9 +353,15 @@ interface AstmQuirkCorpusOptions {
|
|
|
346
353
|
readonly seed: number;
|
|
347
354
|
/** How many quirk artifacts to generate. Defaults to the number of quirks. */
|
|
348
355
|
readonly count?: number;
|
|
349
|
-
/**
|
|
356
|
+
/**
|
|
357
|
+
* The quirk names to cycle through. Defaults to every ASTM quirk. Validated; unsupported ⇒ fatal.
|
|
358
|
+
* An empty list, or a `profile` whose `quirks` is an empty list, throws `SYNTH_EMPTY_POOL`.
|
|
359
|
+
*/
|
|
350
360
|
readonly quirks?: readonly AstmQuirkName[];
|
|
351
|
-
/**
|
|
361
|
+
/**
|
|
362
|
+
* A {@link SynthProfile} whose `quirks` drive the corpus (validated). Its `quirks`, when set, take
|
|
363
|
+
* precedence over `quirks`; a profile that leaves `quirks` out leaves the selection to `quirks`.
|
|
364
|
+
*/
|
|
352
365
|
readonly profile?: SynthProfile;
|
|
353
366
|
}
|
|
354
367
|
/**
|
|
@@ -397,7 +410,7 @@ interface AstmCorpusOptions {
|
|
|
397
410
|
readonly seed: number;
|
|
398
411
|
/** How many messages to generate. Defaults to the length of the mix. */
|
|
399
412
|
readonly count?: number;
|
|
400
|
-
/** The message kinds to cycle through. Defaults to one of each. */
|
|
413
|
+
/** The message kinds to cycle through. Defaults to one of each. An empty list throws `SYNTH_EMPTY_POOL`. */
|
|
401
414
|
readonly mix?: readonly AstmCorpusKind[];
|
|
402
415
|
/**
|
|
403
416
|
* Whether each artifact is read back through its parser and the parser's findings recorded as its
|
package/dist/astm/index.mjs
CHANGED
|
@@ -70,7 +70,11 @@ var SYNTH_FATAL_CODES = Object.freeze({
|
|
|
70
70
|
SYNTH_INVALID_DECIMAL: "SYNTH_INVALID_DECIMAL",
|
|
71
71
|
/** An integer range was requested with its maximum below its minimum. Fatal. */
|
|
72
72
|
SYNTH_INVALID_RANGE: "SYNTH_INVALID_RANGE",
|
|
73
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* A value was drawn from an empty pool. Fatal, never a fabricated substitute. A corpus given an
|
|
75
|
+
* empty `mix`, `triggers` or `quirks` list (or a profile whose `quirks` is an empty list) raises it
|
|
76
|
+
* too: there is no kind to cycle through, and an empty list is never read as the default.
|
|
77
|
+
*/
|
|
74
78
|
SYNTH_EMPTY_POOL: "SYNTH_EMPTY_POOL",
|
|
75
79
|
/** A `defineSynthProfile` spec was not usable (a missing or blank `name`). Fatal. */
|
|
76
80
|
SYNTH_INVALID_PROFILE: "SYNTH_INVALID_PROFILE",
|
|
@@ -89,7 +93,21 @@ var SYNTH_FATAL_CODES = Object.freeze({
|
|
|
89
93
|
* apart without matching message text. Fatal, and raised **before** anything is generated: a
|
|
90
94
|
* mislabelled artifact is worse than no artifact.
|
|
91
95
|
*/
|
|
92
|
-
SYNTH_PROFILE_NOT_GENERATED: "SYNTH_PROFILE_NOT_GENERATED"
|
|
96
|
+
SYNTH_PROFILE_NOT_GENERATED: "SYNTH_PROFILE_NOT_GENERATED",
|
|
97
|
+
/**
|
|
98
|
+
* The sibling parser a generator builds through is not installed. Raised on the first call that
|
|
99
|
+
* needs it, by both builds, only when the missing package is the parser itself: a missing
|
|
100
|
+
* dependency of an installed parser is thrown as Node.js raised it. The error carries the parser's
|
|
101
|
+
* package name on `peer`, a message from {@link SYNTH_PEER_MESSAGES} that names its install
|
|
102
|
+
* command, and the error Node.js raised on `cause`.
|
|
103
|
+
*/
|
|
104
|
+
SYNTH_PEER_NOT_INSTALLED: "SYNTH_PEER_NOT_INSTALLED",
|
|
105
|
+
/**
|
|
106
|
+
* An HL7 v2 `ACK` was asked for an inbound message that carries no MSH-10 message control id.
|
|
107
|
+
* MSA-2 must echo that id, and an acknowledgment that cannot be matched to the message it answers
|
|
108
|
+
* is not a fixture worth having, so nothing is generated.
|
|
109
|
+
*/
|
|
110
|
+
SYNTH_ACK_UNCORRELATED: "SYNTH_ACK_UNCORRELATED"
|
|
93
111
|
});
|
|
94
112
|
var SYNTH_FATAL_MESSAGES = Object.freeze({
|
|
95
113
|
SYNTH_UNSUPPORTED_FORMAT: "The requested format is not generable by this build. A generator has no byte fallback: it builds through a parser's own serializer or it refuses.",
|
|
@@ -102,18 +120,38 @@ var SYNTH_FATAL_MESSAGES = Object.freeze({
|
|
|
102
120
|
SYNTH_EMPTY_POOL: "A value was drawn from an empty pool.",
|
|
103
121
|
SYNTH_INVALID_PROFILE: "defineSynthProfile requires a non-empty string name.",
|
|
104
122
|
SYNTH_UNSUPPORTED_KIND: "The requested kind, document type, corpus mix entry, variant or profile is not one this generator supports. The supported set is the exported union for that option.",
|
|
105
|
-
SYNTH_PROFILE_NOT_GENERATED: "The requested profile is published by the adopted implementation guide, and this build does not generate it. The coverage surface reports, per adopted profile, whether it is generated."
|
|
123
|
+
SYNTH_PROFILE_NOT_GENERATED: "The requested profile is published by the adopted implementation guide, and this build does not generate it. The coverage surface reports, per adopted profile, whether it is generated.",
|
|
124
|
+
SYNTH_PEER_NOT_INSTALLED: "A sibling @cosyte parser this generator builds through is not installed. Install it beside @cosyte/synth.",
|
|
125
|
+
SYNTH_ACK_UNCORRELATED: (
|
|
126
|
+
// Stryker disable next-line all: a module-level table runs once, at import; the docs test holds it.
|
|
127
|
+
"The inbound message has no MSH-10 control id for an ACK to echo in MSA-2."
|
|
128
|
+
)
|
|
129
|
+
});
|
|
130
|
+
var SYNTH_PEER_MESSAGES = Object.freeze({
|
|
131
|
+
"@cosyte/hl7": "@cosyte/hl7 is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/hl7",
|
|
132
|
+
"@cosyte/fhir": "@cosyte/fhir is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/fhir",
|
|
133
|
+
"@cosyte/ccda": "@cosyte/ccda is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/ccda",
|
|
134
|
+
"@cosyte/x12": "@cosyte/x12 is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/x12",
|
|
135
|
+
"@cosyte/ncpdp": "@cosyte/ncpdp is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/ncpdp",
|
|
136
|
+
"@cosyte/astm": "@cosyte/astm is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/astm",
|
|
137
|
+
"@cosyte/deid": "@cosyte/deid is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/deid"
|
|
106
138
|
});
|
|
107
139
|
var SynthError = class extends Error {
|
|
108
140
|
/** The stable fatal code. */
|
|
109
141
|
code;
|
|
110
142
|
/**
|
|
111
143
|
* @param code - The stable {@link SynthFatalCode}. The message comes from the frozen registry.
|
|
144
|
+
* @param options - The error that caused this one, and for a missing parser its package.
|
|
112
145
|
*/
|
|
113
|
-
constructor(code) {
|
|
114
|
-
|
|
146
|
+
constructor(code, options = {}) {
|
|
147
|
+
const peer = code === SYNTH_FATAL_CODES.SYNTH_PEER_NOT_INSTALLED ? options.peer : void 0;
|
|
148
|
+
super(
|
|
149
|
+
peer === void 0 ? SYNTH_FATAL_MESSAGES[code] : SYNTH_PEER_MESSAGES[peer],
|
|
150
|
+
"cause" in options ? { cause: options.cause } : void 0
|
|
151
|
+
);
|
|
115
152
|
this.name = "SynthError";
|
|
116
153
|
this.code = code;
|
|
154
|
+
if (peer !== void 0) Object.defineProperty(this, "peer", { value: peer, enumerable: true });
|
|
117
155
|
}
|
|
118
156
|
};
|
|
119
157
|
|
|
@@ -221,7 +259,7 @@ function luhnMod10(digits) {
|
|
|
221
259
|
if (d < 0 || d > 9) continue;
|
|
222
260
|
if (double) {
|
|
223
261
|
d *= 2;
|
|
224
|
-
if (d
|
|
262
|
+
if (d >= 10) d -= 9;
|
|
225
263
|
}
|
|
226
264
|
sum += d;
|
|
227
265
|
double = !double;
|
|
@@ -318,7 +356,7 @@ var SYNTHETIC_CITY_NAMES = Object.freeze([
|
|
|
318
356
|
]);
|
|
319
357
|
|
|
320
358
|
// src/safe/providers.ts
|
|
321
|
-
function ssn(rng, block
|
|
359
|
+
function ssn(rng, block) {
|
|
322
360
|
if (block === "advertising") {
|
|
323
361
|
return `987-00-432${String(rng.int(0, 9))}`;
|
|
324
362
|
}
|
|
@@ -445,6 +483,63 @@ var US_STATES = Object.freeze([
|
|
|
445
483
|
"WY"
|
|
446
484
|
]);
|
|
447
485
|
|
|
486
|
+
// src/safe/animal-code.ts
|
|
487
|
+
var ANIMAL_CODE_SYSTEM = "99COSYTE";
|
|
488
|
+
function animalCode(value, text) {
|
|
489
|
+
return Object.freeze({ code: value, text, system: ANIMAL_CODE_SYSTEM });
|
|
490
|
+
}
|
|
491
|
+
function animalSpecies(value, text, breeds) {
|
|
492
|
+
return Object.freeze({ ...animalCode(value, text), breeds: Object.freeze([...breeds]) });
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// src/safe/animal.ts
|
|
496
|
+
var SYNTHETIC_ANIMAL_SPECIES = Object.freeze([
|
|
497
|
+
animalSpecies("DOG", "Dog", [
|
|
498
|
+
animalCode("DOG-LAB", "Labrador Retriever"),
|
|
499
|
+
animalCode("DOG-BGL", "Beagle"),
|
|
500
|
+
animalCode("DOG-MIX", "Mixed breed dog")
|
|
501
|
+
]),
|
|
502
|
+
animalSpecies("CAT", "Cat", [animalCode("CAT-DSH", "Domestic Shorthair"), animalCode("CAT-SIA", "Siamese")]),
|
|
503
|
+
animalSpecies("HORSE", "Horse", [animalCode("HRS-QTR", "Quarter Horse"), animalCode("HRS-TB", "Thoroughbred")]),
|
|
504
|
+
animalSpecies("CATTLE", "Cattle", [animalCode("CTL-HOL", "Holstein"), animalCode("CTL-ANG", "Angus")])
|
|
505
|
+
]);
|
|
506
|
+
var SYNTHETIC_PET_NAMES = Object.freeze([
|
|
507
|
+
"Fixturepaw",
|
|
508
|
+
"Mockwhisker",
|
|
509
|
+
"Stubtail",
|
|
510
|
+
"Seedpup",
|
|
511
|
+
"Testbiscuit",
|
|
512
|
+
"Placepurr",
|
|
513
|
+
"Synthfur",
|
|
514
|
+
"Dummymane",
|
|
515
|
+
"Examplehoof",
|
|
516
|
+
"Fauxfluff",
|
|
517
|
+
"Samplesnout",
|
|
518
|
+
"Voidwag"
|
|
519
|
+
]);
|
|
520
|
+
var MICROCHIP_TEST_PREFIX = "999";
|
|
521
|
+
function petName(rng) {
|
|
522
|
+
return rng.pick(SYNTHETIC_PET_NAMES);
|
|
523
|
+
}
|
|
524
|
+
function animalBreed(rng) {
|
|
525
|
+
const picked = rng.pick(SYNTHETIC_ANIMAL_SPECIES);
|
|
526
|
+
const { breeds, ...bare } = picked;
|
|
527
|
+
return { species: Object.freeze(bare), breed: rng.pick(breeds) };
|
|
528
|
+
}
|
|
529
|
+
function microchip(rng) {
|
|
530
|
+
return `${MICROCHIP_TEST_PREFIX}${rng.digits(12)}`;
|
|
531
|
+
}
|
|
532
|
+
function animalBirthDate(rng, onDate) {
|
|
533
|
+
const year = Number(onDate.slice(0, 4));
|
|
534
|
+
const month = Number(onDate.slice(4, 6)) - 1;
|
|
535
|
+
const day = Number(onDate.slice(6, 8));
|
|
536
|
+
const latest = Date.UTC(year, month, day);
|
|
537
|
+
const earliest = Date.UTC(year - 20, month, day);
|
|
538
|
+
const span = Math.round((latest - earliest) / 864e5);
|
|
539
|
+
const born = new Date(latest - rng.int(0, span) * 864e5);
|
|
540
|
+
return born.toISOString().slice(0, 10).replace(/-/g, "");
|
|
541
|
+
}
|
|
542
|
+
|
|
448
543
|
// src/safe/index.ts
|
|
449
544
|
var safe = Object.freeze({
|
|
450
545
|
ssn,
|
|
@@ -458,7 +553,11 @@ var safe = Object.freeze({
|
|
|
458
553
|
address,
|
|
459
554
|
dateYmd,
|
|
460
555
|
npi,
|
|
461
|
-
dea
|
|
556
|
+
dea,
|
|
557
|
+
petName,
|
|
558
|
+
animalBreed,
|
|
559
|
+
microchip,
|
|
560
|
+
animalBirthDate
|
|
462
561
|
});
|
|
463
562
|
|
|
464
563
|
// src/astm/identity.ts
|
|
@@ -597,19 +696,44 @@ function defaultHost() {
|
|
|
597
696
|
if (typeof import.meta.resolve !== "function") return { require: __require, resolve: void 0 };
|
|
598
697
|
return { require: createRequire(import.meta.url), resolve: (s) => import.meta.resolve(s) };
|
|
599
698
|
}
|
|
699
|
+
function isDenoResolveRefusal(error) {
|
|
700
|
+
return error instanceof TypeError && !("code" in error) && error.message === "Invalid arguments";
|
|
701
|
+
}
|
|
600
702
|
function isRequireEsmRefusal(error) {
|
|
601
703
|
return error?.code === "ERR_REQUIRE_ESM";
|
|
602
704
|
}
|
|
705
|
+
function peerPackage(specifier) {
|
|
706
|
+
const name2 = specifier.split("/").slice(0, 2).join("/");
|
|
707
|
+
return Object.hasOwn(SYNTH_PEER_MESSAGES, name2) ? name2 : void 0;
|
|
708
|
+
}
|
|
709
|
+
function isPeerNotFound(error, specifier, peer) {
|
|
710
|
+
const { code, message } = error ?? {};
|
|
711
|
+
if (typeof message !== "string") return false;
|
|
712
|
+
if (code === "ERR_MODULE_NOT_FOUND") return message.startsWith(`Cannot find package '${peer}'`);
|
|
713
|
+
if (code === "MODULE_NOT_FOUND") return message.startsWith(`Cannot find module '${specifier}'`);
|
|
714
|
+
return false;
|
|
715
|
+
}
|
|
603
716
|
function loadPeer(specifier, host) {
|
|
717
|
+
try {
|
|
718
|
+
return loadFrom(specifier, host);
|
|
719
|
+
} catch (error) {
|
|
720
|
+
const peer = peerPackage(specifier);
|
|
721
|
+
if (peer === void 0 || !isPeerNotFound(error, specifier, peer)) throw error;
|
|
722
|
+
throw new SynthError(SYNTH_FATAL_CODES.SYNTH_PEER_NOT_INSTALLED, { peer, cause: error });
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
function loadFrom(specifier, host) {
|
|
604
726
|
if (host.resolve === void 0) return host.require(specifier);
|
|
605
|
-
let
|
|
727
|
+
let url;
|
|
606
728
|
try {
|
|
607
|
-
|
|
608
|
-
} catch {
|
|
729
|
+
url = host.resolve(specifier);
|
|
730
|
+
} catch (error) {
|
|
731
|
+
if (!isDenoResolveRefusal(error)) throw error;
|
|
609
732
|
return host.require(specifier);
|
|
610
733
|
}
|
|
734
|
+
if (!url.startsWith("file:")) return host.require(specifier);
|
|
611
735
|
try {
|
|
612
|
-
return host.require(
|
|
736
|
+
return host.require(fileURLToPath(url));
|
|
613
737
|
} catch (error) {
|
|
614
738
|
if (!isRequireEsmRefusal(error)) throw error;
|
|
615
739
|
return host.require(specifier);
|
|
@@ -732,6 +856,10 @@ function resolveMix(allowed, requested, fallback) {
|
|
|
732
856
|
if (requested === void 0) return fallback;
|
|
733
857
|
return requested.map((entry) => resolveKind(allowed, entry));
|
|
734
858
|
}
|
|
859
|
+
function requireSelection(selection) {
|
|
860
|
+
if (selection.length === 0) throw new SynthError(SYNTH_FATAL_CODES.SYNTH_EMPTY_POOL);
|
|
861
|
+
return selection;
|
|
862
|
+
}
|
|
735
863
|
|
|
736
864
|
// src/profile.ts
|
|
737
865
|
function defineSynthProfile(spec) {
|
|
@@ -742,7 +870,7 @@ function defineSynthProfile(spec) {
|
|
|
742
870
|
name: spec.name,
|
|
743
871
|
...spec.givenNames ? { givenNames: Object.freeze([...spec.givenNames]) } : {},
|
|
744
872
|
...spec.familyNames ? { familyNames: Object.freeze([...spec.familyNames]) } : {},
|
|
745
|
-
quirks: Object.freeze([...spec.quirks
|
|
873
|
+
...spec.quirks !== void 0 ? { quirks: Object.freeze([...spec.quirks]) } : {}
|
|
746
874
|
});
|
|
747
875
|
}
|
|
748
876
|
|
|
@@ -784,6 +912,7 @@ function assertIntendedWarnings(intendedWarnings, bareWarnings) {
|
|
|
784
912
|
}
|
|
785
913
|
}
|
|
786
914
|
function validateProfileQuirks(profile, registry, format) {
|
|
915
|
+
if (profile.quirks === void 0) return Object.keys(registry);
|
|
787
916
|
for (const name2 of profile.quirks) resolveQuirk(registry, format, name2);
|
|
788
917
|
return profile.quirks;
|
|
789
918
|
}
|
|
@@ -892,8 +1021,9 @@ var ALL_ASTM_QUIRKS = Object.freeze(
|
|
|
892
1021
|
Object.keys(ASTM_QUIRKS)
|
|
893
1022
|
);
|
|
894
1023
|
function astmQuirkCorpus(options) {
|
|
895
|
-
const
|
|
896
|
-
|
|
1024
|
+
const names = requireSelection(
|
|
1025
|
+
options.profile?.quirks !== void 0 ? validateProfileQuirks(options.profile, ASTM_QUIRKS, "astm") : options.quirks ?? ALL_ASTM_QUIRKS
|
|
1026
|
+
);
|
|
897
1027
|
for (const name2 of names) resolveQuirk(ASTM_QUIRKS, "astm", name2);
|
|
898
1028
|
const count = options.count ?? names.length;
|
|
899
1029
|
const seedStream = createRng(options.seed);
|
|
@@ -928,11 +1058,11 @@ function generateKind(kind, seed, verify) {
|
|
|
928
1058
|
}
|
|
929
1059
|
function astmCorpus(options) {
|
|
930
1060
|
const { seed, verify = true } = options;
|
|
931
|
-
const mix = resolveMix(ALL_KINDS, options.mix, DEFAULT_MIX);
|
|
1061
|
+
const mix = requireSelection(resolveMix(ALL_KINDS, options.mix, DEFAULT_MIX));
|
|
932
1062
|
const count = options.count ?? mix.length;
|
|
933
1063
|
const seedStream = createRng(seed);
|
|
934
1064
|
const artifacts = Array.from({ length: count }, (_unused, i) => {
|
|
935
|
-
const kind = mix[i % mix.length]
|
|
1065
|
+
const kind = mix[i % mix.length];
|
|
936
1066
|
const msgSeed = seedStream.nextUint32();
|
|
937
1067
|
const rt = generateKind(kind, msgSeed, verify);
|
|
938
1068
|
return {
|