@cosyte/synth 0.0.1
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 +414 -0
- package/LICENSE +21 -0
- package/README.md +325 -0
- package/dist/astm/index.cjs +847 -0
- package/dist/astm/index.cjs.map +1 -0
- package/dist/astm/index.d.cts +418 -0
- package/dist/astm/index.d.ts +418 -0
- package/dist/astm/index.mjs +828 -0
- package/dist/astm/index.mjs.map +1 -0
- package/dist/ccda/index.cjs +1103 -0
- package/dist/ccda/index.cjs.map +1 -0
- package/dist/ccda/index.d.cts +380 -0
- package/dist/ccda/index.d.ts +380 -0
- package/dist/ccda/index.mjs +1077 -0
- package/dist/ccda/index.mjs.map +1 -0
- package/dist/deid/index.cjs +2809 -0
- package/dist/deid/index.cjs.map +1 -0
- package/dist/deid/index.d.cts +464 -0
- package/dist/deid/index.d.ts +464 -0
- package/dist/deid/index.mjs +2793 -0
- package/dist/deid/index.mjs.map +1 -0
- package/dist/example-codes-DeXcnCSK.d.cts +105 -0
- package/dist/example-codes-DeXcnCSK.d.ts +105 -0
- package/dist/fhir/index.cjs +1429 -0
- package/dist/fhir/index.cjs.map +1 -0
- package/dist/fhir/index.d.cts +772 -0
- package/dist/fhir/index.d.ts +772 -0
- package/dist/fhir/index.mjs +1384 -0
- package/dist/fhir/index.mjs.map +1 -0
- package/dist/hl7/index.cjs +1012 -0
- package/dist/hl7/index.cjs.map +1 -0
- package/dist/hl7/index.d.cts +548 -0
- package/dist/hl7/index.d.ts +548 -0
- package/dist/hl7/index.mjs +990 -0
- package/dist/hl7/index.mjs.map +1 -0
- package/dist/index.cjs +535 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +407 -0
- package/dist/index.d.ts +407 -0
- package/dist/index.mjs +488 -0
- package/dist/index.mjs.map +1 -0
- package/dist/ncpdp/index.cjs +714 -0
- package/dist/ncpdp/index.cjs.map +1 -0
- package/dist/ncpdp/index.d.cts +432 -0
- package/dist/ncpdp/index.d.ts +432 -0
- package/dist/ncpdp/index.mjs +695 -0
- package/dist/ncpdp/index.mjs.map +1 -0
- package/dist/providers-OLz3zAc-.d.cts +343 -0
- package/dist/providers-OLz3zAc-.d.ts +343 -0
- package/dist/quirk-DmkgoZdh.d.cts +239 -0
- package/dist/quirk-JLyO1Ncj.d.ts +239 -0
- package/dist/x12/index.cjs +920 -0
- package/dist/x12/index.cjs.map +1 -0
- package/dist/x12/index.d.cts +484 -0
- package/dist/x12/index.d.ts +484 -0
- package/dist/x12/index.mjs +892 -0
- package/dist/x12/index.mjs.map +1 -0
- package/package.json +210 -0
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import { S as SyntheticName, R as Rng, C as Corpus } from '../providers-OLz3zAc-.cjs';
|
|
2
|
+
import { Q as QuirkDescriptor, S as SynthProfile, a as QuirkArtifact, b as QuirkRoundTripResult } from '../quirk-DmkgoZdh.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Spec-clean ASTM (E1394 / CLSI LIS02) message generation — the `H`/`P`/`O`/`R`/`C`/`L` record report —
|
|
6
|
+
* built through `@cosyte/astm`'s `buildAstmMessage` so the delimiter declaration (`H|\^&`), the record
|
|
7
|
+
* type letters, the per-type sequence counters, the `L` terminator, and every escape are the parser's
|
|
8
|
+
* own conservative emit. Nothing clinical is defaulted: a
|
|
9
|
+
* result's status/flag/units/value are supplied from the example pool, never invented by the builder.
|
|
10
|
+
*
|
|
11
|
+
* A framed **E1381 / CLSI LIS01** variant is also offered ({@link generateAstmResultFramed}) via
|
|
12
|
+
* `composeAstmFrames`, which frames each record into `<STX> FN text <ETB|ETX> CS <CR><LF>` with the
|
|
13
|
+
* **modulo-256 checksum and the `0`–`7` frame number computed by the parser** — never faked. Both round
|
|
14
|
+
* trip through `@cosyte/astm` cleanly (`parseAstmRecords` / `parseFramedAstm` — see `./round-trip`).
|
|
15
|
+
*
|
|
16
|
+
* Every value at a PHI-bearing locus (the `P` record's name / DOB / practice+lab IDs) is
|
|
17
|
+
* drawn from the synthetic-safety providers via `./identity`, so no output can be real or plausibly-real
|
|
18
|
+
* PHI. `synth` is a **format/conformance generator, not a clinical simulator**: a generated
|
|
19
|
+
* result pairs a code and a value with no claim of clinical coherence.
|
|
20
|
+
*
|
|
21
|
+
* @module
|
|
22
|
+
*/
|
|
23
|
+
/** Options for the ASTM message generators. */
|
|
24
|
+
interface GenerateAstmOptions {
|
|
25
|
+
/** The seed (deterministic — same seed yields a byte-identical message). */
|
|
26
|
+
readonly seed: number;
|
|
27
|
+
/** How many `R` (result) records to emit. Defaults to a seeded 1–4. */
|
|
28
|
+
readonly resultCount?: number;
|
|
29
|
+
/** Whether to append a `C` (comment) record after the results. Defaults to `true`. */
|
|
30
|
+
readonly comment?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Generate a spec-clean ASTM **result message** — an `H`/`P`/`O`/`R`…/`C`/`L` record stream — built
|
|
34
|
+
* through `@cosyte/astm`'s `buildAstmMessage`. Every identity value is synthetic-by-construction; the message
|
|
35
|
+
* round-trips through `parseAstmRecords` with zero warnings and re-serializes
|
|
36
|
+
* byte-identically (see `./round-trip`).
|
|
37
|
+
*
|
|
38
|
+
* @param options - The seed, optional result count, and whether to append a comment.
|
|
39
|
+
* @returns The `CR`-terminated ASTM record stream.
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* import { generateAstmResult } from "@cosyte/synth/astm";
|
|
43
|
+
* const raw = generateAstmResult({ seed: 42 });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
declare function generateAstmResult(options: GenerateAstmOptions): string;
|
|
47
|
+
/**
|
|
48
|
+
* Generate a spec-clean ASTM **order message** — an `H`/`P`/`O`/`L` record stream with no results, for
|
|
49
|
+
* the order side of the flow. Built through `buildAstmMessage`; synthetic-by-construction; round-trips
|
|
50
|
+
* clean.
|
|
51
|
+
*
|
|
52
|
+
* @param options - The seed.
|
|
53
|
+
* @returns The `CR`-terminated ASTM record stream.
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* import { generateAstmOrder } from "@cosyte/synth/astm";
|
|
57
|
+
* const raw = generateAstmOrder({ seed: 7 });
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
declare function generateAstmOrder(options: GenerateAstmOptions): string;
|
|
61
|
+
/**
|
|
62
|
+
* Generate a spec-clean **framed** ASTM result message — the same `H`/`P`/`O`/`R`…/`C`/`L` records,
|
|
63
|
+
* wrapped in the **E1381 / CLSI LIS01** frame envelope (`<STX> FN text <ETB|ETX> CS <CR><LF>`) via
|
|
64
|
+
* `@cosyte/astm`'s `composeAstmFrames`. The **modulo-256 checksum and the `0`–`7` frame number are
|
|
65
|
+
* computed by the parser** (never hand-written), and a record over 240 bytes is split across frames —
|
|
66
|
+
* so the bytes round-trip through `parseFramedAstm` with zero frame **and** record warnings (see
|
|
67
|
+
* `./round-trip`). Each record is framed independently (one `ETX`-closed run per record), mirroring what
|
|
68
|
+
* `decodeAstmFrames` reassembles.
|
|
69
|
+
*
|
|
70
|
+
* @param options - The seed, optional result count, and whether to append a comment.
|
|
71
|
+
* @returns The framed byte stream.
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* import { generateAstmResultFramed } from "@cosyte/synth/astm";
|
|
75
|
+
* const bytes = generateAstmResultFramed({ seed: 42 }); // Uint8Array — E1381 framed
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
declare function generateAstmResultFramed(options: GenerateAstmOptions): Uint8Array;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The **round-trip-through-the-parser harness** for ASTM — the headline gate for the synthetic-fixture
|
|
82
|
+
* generator. A generated ASTM record stream (or framed byte stream) is "spec-clean" only
|
|
83
|
+
* if `@cosyte/astm` — not `@cosyte/synth`'s own opinion — reads it back cleanly. Each harness parses the
|
|
84
|
+
* generated wire straight back through the parser and reports what it found, so a false "spec-clean"
|
|
85
|
+
* claim cannot hide.
|
|
86
|
+
*
|
|
87
|
+
* The **record** layer (E1394) and the **frame** layer (E1381) are separate concerns, so each gets its
|
|
88
|
+
* own harness; both report the same {@link AstmRoundTripResult} shape (the framed one additionally folds
|
|
89
|
+
* the frame-layer warnings — bad checksum, sequence gap, unterminated, oversize — into `warnings`, so a
|
|
90
|
+
* framing defect is caught by the same gate).
|
|
91
|
+
*
|
|
92
|
+
* @module
|
|
93
|
+
*/
|
|
94
|
+
/** The verdict of one round-trip through `@cosyte/astm`. */
|
|
95
|
+
interface AstmRoundTripResult {
|
|
96
|
+
/** The serialized ASTM wire text (records: the `CR`-terminated stream; framed: the raw bytes as latin1). */
|
|
97
|
+
readonly content: string;
|
|
98
|
+
/** The warning codes the parser emitted on re-parse (record + frame layers). Empty ⇒ spec-clean. */
|
|
99
|
+
readonly warnings: readonly string[];
|
|
100
|
+
/** Whether re-serializing the re-parsed message is byte-identical to the input. */
|
|
101
|
+
readonly byteStable: boolean;
|
|
102
|
+
/** `true` iff the artifact is spec-clean: zero warnings **and** byte-stable. */
|
|
103
|
+
readonly specClean: boolean;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Round-trip a generated ASTM **record** stream through parse → serialize and report the verdict. A
|
|
107
|
+
* spec-clean message re-parses with **zero warnings** and re-serializes byte-identically.
|
|
108
|
+
*
|
|
109
|
+
* @param raw - The ASTM record stream (typically from `generateAstmResult` / `generateAstmOrder`).
|
|
110
|
+
* @returns The {@link AstmRoundTripResult}.
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* import { generateAstmResult, astmRoundTrip } from "@cosyte/synth/astm";
|
|
114
|
+
* const { specClean } = astmRoundTrip(generateAstmResult({ seed: 1 })); // specClean === true
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
declare function astmRoundTrip(raw: string): AstmRoundTripResult;
|
|
118
|
+
/**
|
|
119
|
+
* Round-trip a generated **framed** ASTM byte stream (E1381) through decode+parse → re-frame and report
|
|
120
|
+
* the verdict. A spec-clean framed message re-parses with **zero record and zero frame warnings** (every
|
|
121
|
+
* modulo-256 checksum verifies, no sequence gap, no unterminated/oversize frame) and re-frames
|
|
122
|
+
* byte-identically.
|
|
123
|
+
*
|
|
124
|
+
* @param bytes - The framed byte stream (typically from `generateAstmResultFramed`).
|
|
125
|
+
* @returns The {@link AstmRoundTripResult} — `content` holds the framed bytes decoded as latin1.
|
|
126
|
+
* @example
|
|
127
|
+
* ```ts
|
|
128
|
+
* import { generateAstmResultFramed, astmFramedRoundTrip } from "@cosyte/synth/astm";
|
|
129
|
+
* const { specClean } = astmFramedRoundTrip(generateAstmResultFramed({ seed: 1 })); // true
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
declare function astmFramedRoundTrip(bytes: Uint8Array): AstmRoundTripResult;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Synthetic identity for ASTM (E1394 / CLSI LIS02) messages — every value `synth` puts into a `P`
|
|
136
|
+
* (patient) record, an `O` (order) accession, or the `H` header is minted here, and **only** from the
|
|
137
|
+
* synthetic-safety providers. ASTM's PHI-dense locus is the **`P` record**: it carries the
|
|
138
|
+
* patient **name** (`Last^First^Middle`), **birthdate**, **sex**, and the **practice-assigned** and
|
|
139
|
+
* **laboratory-assigned** patient IDs, which must stay
|
|
140
|
+
* **distinct** (the parser keeps them distinct; a generator that let one default from the other would
|
|
141
|
+
* defeat that). Every identifier is scoped to the synthetic assigning authority: there is no reserved
|
|
142
|
+
* patient-ID range for ASTM (as for MRNs generally), so the **namespace** is the
|
|
143
|
+
* guarantee. The IDs carry a clearly-synthetic prefix (`PRA` / `LAB` / `ACC`) so the `phi-scan` ASTM
|
|
144
|
+
* arm can recognize them as synthetic-AA-scoped and a real bare numeric MRN can never masquerade as one.
|
|
145
|
+
*
|
|
146
|
+
* @module
|
|
147
|
+
*/
|
|
148
|
+
|
|
149
|
+
/** A synthetic ASTM patient — every field drawn from `../safe`. */
|
|
150
|
+
interface AstmPatient {
|
|
151
|
+
/** Name from the shipped fake-name pool, plus a fictional middle initial. */
|
|
152
|
+
readonly person: SyntheticName;
|
|
153
|
+
/** Middle initial (clearly synthetic). */
|
|
154
|
+
readonly middle: string;
|
|
155
|
+
/** Birthdate `YYYYMMDD`, from the seeded generator (no real event implied). */
|
|
156
|
+
readonly birthDate: string;
|
|
157
|
+
/** Sex code, emitted verbatim (`M` / `F` — structural, never defaulted by the builder). */
|
|
158
|
+
readonly sex: "M" | "F";
|
|
159
|
+
/** Practice-assigned patient ID — synthetic-AA scoped (`PRA`-prefixed). Distinct from the lab ID. */
|
|
160
|
+
readonly practiceAssignedId: string;
|
|
161
|
+
/** Laboratory-assigned patient ID — synthetic-AA scoped (`LAB`-prefixed). Distinct from the practice ID. */
|
|
162
|
+
readonly laboratoryAssignedId: string;
|
|
163
|
+
}
|
|
164
|
+
/** A synthetic ASTM order identity — the specimen / accession id and priority. */
|
|
165
|
+
interface AstmOrder {
|
|
166
|
+
/** Specimen / accession id — synthetic-AA scoped (`ACC`-prefixed). */
|
|
167
|
+
readonly specimenId: string;
|
|
168
|
+
/** Priority code, emitted verbatim (`R` routine, `S` stat). */
|
|
169
|
+
readonly priority: "R" | "S";
|
|
170
|
+
}
|
|
171
|
+
/** A synthetic ASTM header identity — the sender and analyzer strings for the `H` record. */
|
|
172
|
+
interface AstmHeaderIdentity {
|
|
173
|
+
/** The sending system id (clearly synthetic). */
|
|
174
|
+
readonly sender: string;
|
|
175
|
+
/** The analyzer / instrument string (clearly synthetic). */
|
|
176
|
+
readonly analyzer: string;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Mint a synthetic patient for a `P` record. Fixed draw order (name → middle → DOB → sex → practice id
|
|
180
|
+
* → lab id) so the same seed yields the same patient. The two patient IDs are minted from
|
|
181
|
+
* **independent** synthetic-identifier draws, so they are distinct by construction.
|
|
182
|
+
*
|
|
183
|
+
* @param rng - The seeded generator.
|
|
184
|
+
* @returns A synthetic {@link AstmPatient}.
|
|
185
|
+
* @example
|
|
186
|
+
* ```ts
|
|
187
|
+
* import { createRng } from "@cosyte/synth";
|
|
188
|
+
* import { astmPatient } from "@cosyte/synth/astm";
|
|
189
|
+
* const { person, practiceAssignedId, laboratoryAssignedId } = astmPatient(createRng(1));
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
declare function astmPatient(rng: Rng): AstmPatient;
|
|
193
|
+
/**
|
|
194
|
+
* Mint a synthetic order identity for an `O` record — a synthetic-AA-scoped accession id and a priority.
|
|
195
|
+
*
|
|
196
|
+
* @param rng - The seeded generator.
|
|
197
|
+
* @returns A synthetic {@link AstmOrder}.
|
|
198
|
+
* @example
|
|
199
|
+
* ```ts
|
|
200
|
+
* import { createRng } from "@cosyte/synth";
|
|
201
|
+
* import { astmOrder } from "@cosyte/synth/astm";
|
|
202
|
+
* const { specimenId } = astmOrder(createRng(1));
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
declare function astmOrder(rng: Rng): AstmOrder;
|
|
206
|
+
/**
|
|
207
|
+
* Mint a synthetic header identity for the `H` record — a clearly-synthetic sender and analyzer.
|
|
208
|
+
*
|
|
209
|
+
* @param rng - The seeded generator.
|
|
210
|
+
* @returns A synthetic {@link AstmHeaderIdentity}.
|
|
211
|
+
* @example
|
|
212
|
+
* ```ts
|
|
213
|
+
* import { createRng } from "@cosyte/synth";
|
|
214
|
+
* import { astmHeaderIdentity } from "@cosyte/synth/astm";
|
|
215
|
+
* const { sender } = astmHeaderIdentity(createRng(1));
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
declare function astmHeaderIdentity(rng: Rng): AstmHeaderIdentity;
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* A small, **license-clean** pool of example ASTM laboratory tests — the analyte codes, units, and
|
|
222
|
+
* plausible value ranges `synth` draws on when populating `O` (order) and `R` (result) records. The
|
|
223
|
+
* codes are **facts** (a LOINC number is a public identifier, and the local analyzer codes here are
|
|
224
|
+
* invented), never a bundled terminology table. Nothing clinical is asserted — a `synth` result pairs a value
|
|
225
|
+
* and a code with no claim of clinical coherence: the pool exists only to make a *structurally* realistic
|
|
226
|
+
* result record.
|
|
227
|
+
*
|
|
228
|
+
* @module
|
|
229
|
+
*/
|
|
230
|
+
/** One example laboratory analyte — its codes, units, reference range, and a seeded value window. */
|
|
231
|
+
interface AstmExampleTest {
|
|
232
|
+
/** A local analyzer test code (invented — never a real vendor assay id). */
|
|
233
|
+
readonly localCode: string;
|
|
234
|
+
/** The public LOINC identifier for the analyte (a fact, not bundled terminology prose). */
|
|
235
|
+
readonly loinc: string;
|
|
236
|
+
/** The human-readable test name, emitted in the Universal Test ID name component. */
|
|
237
|
+
readonly name: string;
|
|
238
|
+
/** The units string, emitted verbatim in `R`-field 5 (never converted or guessed). */
|
|
239
|
+
readonly units: string;
|
|
240
|
+
/** The reference range text, emitted verbatim in `R`-field 6. */
|
|
241
|
+
readonly referenceRange: string;
|
|
242
|
+
/** Inclusive integer low bound of the seeded synthetic value (structural, not clinical). */
|
|
243
|
+
readonly valueLow: number;
|
|
244
|
+
/** Inclusive integer high bound of the seeded synthetic value. */
|
|
245
|
+
readonly valueHigh: number;
|
|
246
|
+
/** Number of decimal places to render the synthetic value with. */
|
|
247
|
+
readonly decimals: number;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* The example test pool. A handful of common chemistry/hematology analytes, each with a public LOINC
|
|
251
|
+
* code, invented local code, units, and a value window the seeded generator samples. Frozen — the pool
|
|
252
|
+
* is shared, immutable data.
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* ```ts
|
|
256
|
+
* import { EXAMPLE_ASTM_TESTS } from "@cosyte/synth/astm";
|
|
257
|
+
* EXAMPLE_ASTM_TESTS[0]?.name; // "Glucose"
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
declare const EXAMPLE_ASTM_TESTS: readonly AstmExampleTest[];
|
|
261
|
+
/** HL7 Table 0078 abnormal-flag codes `synth` draws from (emitted verbatim; never defaulted). */
|
|
262
|
+
declare const ASTM_ABNORMAL_FLAGS: readonly string[];
|
|
263
|
+
/** Result-status codes `synth` draws from (`F` final, `P` preliminary, `C` correction). */
|
|
264
|
+
declare const ASTM_RESULT_STATUSES: readonly string[];
|
|
265
|
+
/** Free-text result comments — clearly synthetic, carry no PHI. */
|
|
266
|
+
declare const ASTM_COMMENT_TEXT: readonly string[];
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* ASTM E1394 **vendor-quirk generation**. A quirk deviates the
|
|
270
|
+
* *structure* of an otherwise spec-clean record report (built through `@cosyte/astm`'s
|
|
271
|
+
* `buildAstmMessage`) so it round-trips through `parseAstmRecords` to **exactly** one intended, stable
|
|
272
|
+
* warning code — a code in the parser's `defineAstmProfile` tolerable set. Where a built-in public
|
|
273
|
+
* profile tolerates the quirk, the warning is **re-badged** to the value-free `PROFILE_QUIRK_APPLIED`
|
|
274
|
+
* marker (`expected: true`), exactly as the parser's `profileQuirkApplied` does.
|
|
275
|
+
*
|
|
276
|
+
* The deviation is applied **post-serialize** on the record stream. Two quirks ship:
|
|
277
|
+
*
|
|
278
|
+
* - **`unknown-escape`** → `ASTM_UNKNOWN_ESCAPE_SEQUENCE` (profile `referenceCorpus`). A non-standard
|
|
279
|
+
* `&Z&` escape body is injected into a result's units field. Grounded on `@cosyte/astm`'s public
|
|
280
|
+
* `referenceCorpus` profile (the redistributable kxepal/python-astm + senaite OSS corpus), which
|
|
281
|
+
* re-badges it.
|
|
282
|
+
* - **`unknown-record-type`** → `ASTM_RECORD_UNKNOWN_TYPE`. A record's leading type letter is changed to
|
|
283
|
+
* a site-defined `Z` — a real ASTM tolerance (the parser's tolerable set includes this code), but no
|
|
284
|
+
* built-in profile tolerates it, so it is a `"bare"` quirk (a consumer authors a `defineAstmProfile`
|
|
285
|
+
* to re-badge it).
|
|
286
|
+
*
|
|
287
|
+
* A quirk **never** introduces a real-looking value — it changes an escape body or a record type letter,
|
|
288
|
+
* never a P-record identity locus, so the synthetic-safety gate still runs and stays zero.
|
|
289
|
+
*
|
|
290
|
+
* @module
|
|
291
|
+
*/
|
|
292
|
+
|
|
293
|
+
/** Every ASTM quirk this package ships. */
|
|
294
|
+
type AstmQuirkName = "unknown-escape" | "unknown-record-type";
|
|
295
|
+
/**
|
|
296
|
+
* Both shipped ASTM quirks are **result-report** deviations — `unknown-escape` targets an `R` record's
|
|
297
|
+
* units field and `unknown-record-type` a `C` (comment) record, neither of which an *order* report
|
|
298
|
+
* carries. So the quirk base is always a result report (`generateAstmResult`).
|
|
299
|
+
*/
|
|
300
|
+
type AstmQuirkKind = "Result";
|
|
301
|
+
/** The ASTM quirk registry — each recipe bound to the exact `@cosyte/astm` warning code it targets. */
|
|
302
|
+
declare const ASTM_QUIRKS: Readonly<Record<AstmQuirkName, QuirkDescriptor>>;
|
|
303
|
+
/** Options for {@link generateAstmQuirk}. */
|
|
304
|
+
interface GenerateAstmQuirkOptions {
|
|
305
|
+
/** The seed — the same seed + quirk yields a byte-identical record stream. Defaults to `0`. */
|
|
306
|
+
readonly seed?: number;
|
|
307
|
+
/** The quirk to inject. Required. */
|
|
308
|
+
readonly quirk: AstmQuirkName;
|
|
309
|
+
/** The spec-clean base report kind. Always `"Result"` (see {@link AstmQuirkKind}). */
|
|
310
|
+
readonly kind?: AstmQuirkKind;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Generate one ASTM **quirk** artifact: a spec-clean record report (built through `@cosyte/astm`) with
|
|
314
|
+
* the requested vendor deviation injected post-serialize. Deterministic in `seed` + `quirk` + `kind`.
|
|
315
|
+
*
|
|
316
|
+
* @param options - Seed, quirk, and base kind. See {@link GenerateAstmQuirkOptions}.
|
|
317
|
+
* @returns The {@link QuirkArtifact} — its `content` round-trips to `intendedWarnings` exactly.
|
|
318
|
+
* @throws SynthError `SYNTH_UNSUPPORTED_QUIRK` if `quirk` is not a supported ASTM quirk.
|
|
319
|
+
* @throws Error if the base report does not contain the structural anchor the quirk targets.
|
|
320
|
+
* @example
|
|
321
|
+
* ```ts
|
|
322
|
+
* import { generateAstmQuirk, astmQuirkRoundTrip } from "@cosyte/synth/astm";
|
|
323
|
+
* const rt = astmQuirkRoundTrip(generateAstmQuirk({ seed: 1, quirk: "unknown-escape" }));
|
|
324
|
+
* rt.withProfile?.tolerated; // true — `referenceCorpus` re-badges ASTM_UNKNOWN_ESCAPE_SEQUENCE
|
|
325
|
+
* ```
|
|
326
|
+
*/
|
|
327
|
+
declare function generateAstmQuirk(options: GenerateAstmQuirkOptions): QuirkArtifact;
|
|
328
|
+
/**
|
|
329
|
+
* Round-trip an ASTM quirk artifact through `@cosyte/astm` and report the intended-warning verdict: a bare
|
|
330
|
+
* parse must produce **exactly** the intended code, and — when a built-in public
|
|
331
|
+
* profile tolerates the quirk — the profiled parse must re-badge it to `PROFILE_QUIRK_APPLIED`.
|
|
332
|
+
*
|
|
333
|
+
* @param artifact - The quirk artifact (from {@link generateAstmQuirk}).
|
|
334
|
+
* @returns The {@link QuirkRoundTripResult}.
|
|
335
|
+
* @example
|
|
336
|
+
* ```ts
|
|
337
|
+
* import { generateAstmQuirk, astmQuirkRoundTrip } from "@cosyte/synth/astm";
|
|
338
|
+
* astmQuirkRoundTrip(generateAstmQuirk({ seed: 1, quirk: "unknown-escape" })).intendedWarningHeld;
|
|
339
|
+
* ```
|
|
340
|
+
*/
|
|
341
|
+
declare function astmQuirkRoundTrip(artifact: QuirkArtifact): QuirkRoundTripResult;
|
|
342
|
+
/** Options for {@link astmQuirkCorpus}. */
|
|
343
|
+
interface AstmQuirkCorpusOptions {
|
|
344
|
+
/** The seed for the whole corpus (deterministic). */
|
|
345
|
+
readonly seed: number;
|
|
346
|
+
/** How many quirk artifacts to generate. Defaults to the number of quirks. */
|
|
347
|
+
readonly count?: number;
|
|
348
|
+
/** The quirk names to cycle through. Defaults to every ASTM quirk. Validated; unsupported ⇒ fatal. */
|
|
349
|
+
readonly quirks?: readonly AstmQuirkName[];
|
|
350
|
+
/** A {@link SynthProfile} whose `quirks` drive the corpus (validated). Takes precedence over `quirks`. */
|
|
351
|
+
readonly profile?: SynthProfile;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Build a reproducible {@link Corpus} of ASTM quirk artifacts. Each artifact's `warnings` record the
|
|
355
|
+
* intended code for its quirk; the manifest lists the applied quirk names.
|
|
356
|
+
*
|
|
357
|
+
* @param options - Seed, count, and the quirk selection. See {@link AstmQuirkCorpusOptions}.
|
|
358
|
+
* @returns A deep-frozen {@link Corpus}.
|
|
359
|
+
* @example
|
|
360
|
+
* ```ts
|
|
361
|
+
* import { astmQuirkCorpus } from "@cosyte/synth/astm";
|
|
362
|
+
* astmQuirkCorpus({ seed: 42 }).manifest.quirks; // the applied quirk names
|
|
363
|
+
* ```
|
|
364
|
+
*/
|
|
365
|
+
declare function astmQuirkCorpus(options: AstmQuirkCorpusOptions): Corpus;
|
|
366
|
+
/** A ready-made {@link SynthProfile} requesting every built-in ASTM quirk. */
|
|
367
|
+
declare const astmQuirkProfile: SynthProfile;
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* `@cosyte/synth/astm` — the ASTM generation surface, exposed as its own subpath so importing the
|
|
371
|
+
* package root does **not** pull `@cosyte/astm`. This is the **lazy, per-format** boundary: a consumer
|
|
372
|
+
* who only needs ASTM fixtures imports `@cosyte/synth/astm`; one who needs only the core primitives
|
|
373
|
+
* never loads a parser.
|
|
374
|
+
* `@cosyte/astm` is an **optional peer dependency** — present only for this subpath.
|
|
375
|
+
*
|
|
376
|
+
* This subpath ships spec-clean generation of the E1394 record report and its E1381 framed twin, each
|
|
377
|
+
* built through `@cosyte/astm`'s own emit surface:
|
|
378
|
+
*
|
|
379
|
+
* - **Records (E1394):** `generateAstmResult` (`H`/`P`/`O`/`R`…/`C`/`L`) and `generateAstmOrder`
|
|
380
|
+
* (`H`/`P`/`O`/`L`) via `buildAstmMessage` — each round-tripping through `parseAstmRecords` with zero
|
|
381
|
+
* warnings and byte-stable, and carrying a `P` record whose name / DOB / practice+lab IDs are all
|
|
382
|
+
* synthetic-by-construction. The practice- and laboratory-assigned patient IDs are
|
|
383
|
+
* minted independently, so they stay **distinct**.
|
|
384
|
+
* - **Framing (E1381):** `generateAstmResultFramed` via `composeAstmFrames` — the modulo-256 checksum
|
|
385
|
+
* and the `0`–`7` frame number are **computed by the parser, never faked**, and the bytes round-trip
|
|
386
|
+
* through `parseFramedAstm` with zero frame **and** record warnings.
|
|
387
|
+
*
|
|
388
|
+
* @module
|
|
389
|
+
*/
|
|
390
|
+
|
|
391
|
+
/** Every ASTM message kind {@link astmCorpus} generates — the label used as the corpus `kind`. */
|
|
392
|
+
type AstmCorpusKind = "Result" | "Order";
|
|
393
|
+
/** Options for {@link astmCorpus}. */
|
|
394
|
+
interface AstmCorpusOptions {
|
|
395
|
+
/** The seed for the whole corpus (deterministic). */
|
|
396
|
+
readonly seed: number;
|
|
397
|
+
/** How many messages to generate. Defaults to the length of the mix. */
|
|
398
|
+
readonly count?: number;
|
|
399
|
+
/** The message kinds to cycle through. Defaults to one of each. */
|
|
400
|
+
readonly mix?: readonly AstmCorpusKind[];
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Build a reproducible {@link Corpus} of spec-clean ASTM messages. Each message is generated from a
|
|
404
|
+
* distinct sub-seed derived from the corpus seed (so the set is deterministic) and round-tripped through
|
|
405
|
+
* `@cosyte/astm`; the per-artifact `warnings` record the parser's verdict (empty ⇒ spec-clean).
|
|
406
|
+
*
|
|
407
|
+
* @param options - Seed, count, and the message mix. See {@link AstmCorpusOptions}.
|
|
408
|
+
* @returns A deep-frozen {@link Corpus}.
|
|
409
|
+
* @example
|
|
410
|
+
* ```ts
|
|
411
|
+
* import { astmCorpus } from "@cosyte/synth/astm";
|
|
412
|
+
* const corpus = astmCorpus({ seed: 42 });
|
|
413
|
+
* corpus.artifacts.every((a) => a.warnings.length === 0); // true — spec-clean
|
|
414
|
+
* ```
|
|
415
|
+
*/
|
|
416
|
+
declare function astmCorpus(options: AstmCorpusOptions): Corpus;
|
|
417
|
+
|
|
418
|
+
export { ASTM_ABNORMAL_FLAGS, ASTM_COMMENT_TEXT, ASTM_QUIRKS, ASTM_RESULT_STATUSES, type AstmCorpusKind, type AstmCorpusOptions, type AstmExampleTest, type AstmHeaderIdentity, type AstmOrder, type AstmPatient, type AstmQuirkCorpusOptions, type AstmQuirkKind, type AstmQuirkName, type AstmRoundTripResult, EXAMPLE_ASTM_TESTS, type GenerateAstmOptions, type GenerateAstmQuirkOptions, astmCorpus, astmFramedRoundTrip, astmHeaderIdentity, astmOrder, astmPatient, astmQuirkCorpus, astmQuirkProfile, astmQuirkRoundTrip, astmRoundTrip, generateAstmOrder, generateAstmQuirk, generateAstmResult, generateAstmResultFramed };
|