@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.
Files changed (58) hide show
  1. package/CHANGELOG.md +414 -0
  2. package/LICENSE +21 -0
  3. package/README.md +325 -0
  4. package/dist/astm/index.cjs +847 -0
  5. package/dist/astm/index.cjs.map +1 -0
  6. package/dist/astm/index.d.cts +418 -0
  7. package/dist/astm/index.d.ts +418 -0
  8. package/dist/astm/index.mjs +828 -0
  9. package/dist/astm/index.mjs.map +1 -0
  10. package/dist/ccda/index.cjs +1103 -0
  11. package/dist/ccda/index.cjs.map +1 -0
  12. package/dist/ccda/index.d.cts +380 -0
  13. package/dist/ccda/index.d.ts +380 -0
  14. package/dist/ccda/index.mjs +1077 -0
  15. package/dist/ccda/index.mjs.map +1 -0
  16. package/dist/deid/index.cjs +2809 -0
  17. package/dist/deid/index.cjs.map +1 -0
  18. package/dist/deid/index.d.cts +464 -0
  19. package/dist/deid/index.d.ts +464 -0
  20. package/dist/deid/index.mjs +2793 -0
  21. package/dist/deid/index.mjs.map +1 -0
  22. package/dist/example-codes-DeXcnCSK.d.cts +105 -0
  23. package/dist/example-codes-DeXcnCSK.d.ts +105 -0
  24. package/dist/fhir/index.cjs +1429 -0
  25. package/dist/fhir/index.cjs.map +1 -0
  26. package/dist/fhir/index.d.cts +772 -0
  27. package/dist/fhir/index.d.ts +772 -0
  28. package/dist/fhir/index.mjs +1384 -0
  29. package/dist/fhir/index.mjs.map +1 -0
  30. package/dist/hl7/index.cjs +1012 -0
  31. package/dist/hl7/index.cjs.map +1 -0
  32. package/dist/hl7/index.d.cts +548 -0
  33. package/dist/hl7/index.d.ts +548 -0
  34. package/dist/hl7/index.mjs +990 -0
  35. package/dist/hl7/index.mjs.map +1 -0
  36. package/dist/index.cjs +535 -0
  37. package/dist/index.cjs.map +1 -0
  38. package/dist/index.d.cts +407 -0
  39. package/dist/index.d.ts +407 -0
  40. package/dist/index.mjs +488 -0
  41. package/dist/index.mjs.map +1 -0
  42. package/dist/ncpdp/index.cjs +714 -0
  43. package/dist/ncpdp/index.cjs.map +1 -0
  44. package/dist/ncpdp/index.d.cts +432 -0
  45. package/dist/ncpdp/index.d.ts +432 -0
  46. package/dist/ncpdp/index.mjs +695 -0
  47. package/dist/ncpdp/index.mjs.map +1 -0
  48. package/dist/providers-OLz3zAc-.d.cts +343 -0
  49. package/dist/providers-OLz3zAc-.d.ts +343 -0
  50. package/dist/quirk-DmkgoZdh.d.cts +239 -0
  51. package/dist/quirk-JLyO1Ncj.d.ts +239 -0
  52. package/dist/x12/index.cjs +920 -0
  53. package/dist/x12/index.cjs.map +1 -0
  54. package/dist/x12/index.d.cts +484 -0
  55. package/dist/x12/index.d.ts +484 -0
  56. package/dist/x12/index.mjs +892 -0
  57. package/dist/x12/index.mjs.map +1 -0
  58. package/package.json +210 -0
@@ -0,0 +1,1429 @@
1
+ 'use strict';
2
+
3
+ var fhir = require('@cosyte/fhir');
4
+
5
+ // src/fhir/patient.ts
6
+
7
+ // src/rng/splitmix32.ts
8
+ function splitmix32(seed) {
9
+ let a = seed | 0;
10
+ return function next() {
11
+ a = a + 2654435769 | 0;
12
+ let t = a ^ a >>> 16;
13
+ t = Math.imul(t, 569420461);
14
+ t = t ^ t >>> 15;
15
+ t = Math.imul(t, 1935289751);
16
+ t = t ^ t >>> 15;
17
+ return t >>> 0;
18
+ };
19
+ }
20
+
21
+ // src/rng/sfc32.ts
22
+ function sfc32Next(s) {
23
+ s.a |= 0;
24
+ s.b |= 0;
25
+ s.c |= 0;
26
+ s.d |= 0;
27
+ const t = (s.a + s.b | 0) + s.d | 0;
28
+ s.d = s.d + 1 | 0;
29
+ s.a = s.b ^ s.b >>> 9;
30
+ s.b = s.c + (s.c << 3) | 0;
31
+ s.c = s.c << 21 | s.c >>> 11;
32
+ s.c = s.c + t | 0;
33
+ return t >>> 0;
34
+ }
35
+
36
+ // src/rng/rng.ts
37
+ var Sfc32Rng = class {
38
+ seed;
39
+ #state;
40
+ constructor(seed) {
41
+ this.seed = seed | 0;
42
+ const mix = splitmix32(this.seed);
43
+ this.#state = { a: mix(), b: mix(), c: mix(), d: mix() };
44
+ for (let i = 0; i < 8; i += 1) sfc32Next(this.#state);
45
+ }
46
+ nextUint32() {
47
+ return sfc32Next(this.#state);
48
+ }
49
+ float() {
50
+ return this.nextUint32() / 4294967296;
51
+ }
52
+ int(min, max) {
53
+ if (max < min) throw new RangeError(`Rng.int: max (${String(max)}) < min (${String(min)})`);
54
+ const span = max - min + 1;
55
+ return min + Math.floor(this.float() * span);
56
+ }
57
+ bool(p = 0.5) {
58
+ return this.float() < p;
59
+ }
60
+ pick(items) {
61
+ if (items.length === 0) throw new RangeError("Rng.pick: empty array");
62
+ return items[this.int(0, items.length - 1)];
63
+ }
64
+ digits(n) {
65
+ let out = "";
66
+ for (let i = 0; i < n; i += 1) out += String(this.int(0, 9));
67
+ return out;
68
+ }
69
+ };
70
+ function createRng(seed) {
71
+ return new Sfc32Rng(seed);
72
+ }
73
+
74
+ // src/safe/reserved.ts
75
+ var SYNTHETIC_ASSIGNING_AUTHORITY = Object.freeze({
76
+ /** The human-readable assigning-authority namespace id (HL7 HD.1). */
77
+ namespaceId: "COSYTE-SYNTH",
78
+ /** The universal id — an OID under HL7's example arc `2.16.840.1.113883.19` (HD.2). */
79
+ universalId: "2.16.840.1.113883.19.999",
80
+ /** The universal id type (HD.3). */
81
+ universalIdType: "ISO"
82
+ });
83
+ var RESERVED_EMAIL_DOMAINS = Object.freeze([
84
+ "example.com",
85
+ "example.org",
86
+ "example.net"
87
+ ]);
88
+ var TEST_NET_V4_PREFIXES = Object.freeze([
89
+ "192.0.2",
90
+ // TEST-NET-1
91
+ "198.51.100",
92
+ // TEST-NET-2
93
+ "203.0.113"
94
+ // TEST-NET-3
95
+ ]);
96
+ var DOC_V6_PREFIX = "2001:db8";
97
+ var NPI_LUHN_PREFIX = "80840";
98
+ function luhnMod10(digits) {
99
+ let sum = 0;
100
+ let double = false;
101
+ for (let i = digits.length - 1; i >= 0; i -= 1) {
102
+ let d = digits.charCodeAt(i) - 48;
103
+ if (d < 0 || d > 9) continue;
104
+ if (double) {
105
+ d *= 2;
106
+ if (d > 9) d -= 9;
107
+ }
108
+ sum += d;
109
+ double = !double;
110
+ }
111
+ return sum % 10;
112
+ }
113
+ function npiCheckDigit(base9) {
114
+ const partial = luhnMod10(`${NPI_LUHN_PREFIX}${base9}0`);
115
+ return (10 - partial) % 10;
116
+ }
117
+ var DEA_REGISTRANT_TYPES = Object.freeze([
118
+ "A",
119
+ "B",
120
+ "F",
121
+ "G",
122
+ "M",
123
+ "P",
124
+ "R",
125
+ "X"
126
+ ]);
127
+ function deaCheckDigit(base6) {
128
+ let odd = 0;
129
+ let even = 0;
130
+ for (let i = 0; i < 6; i += 1) {
131
+ const digit = base6.charCodeAt(i) - 48;
132
+ if (i % 2 === 0) odd += digit;
133
+ else even += digit;
134
+ }
135
+ return (odd + 2 * even) % 10;
136
+ }
137
+
138
+ // src/safe/names-pool.ts
139
+ var SYNTHETIC_GIVEN_NAMES = Object.freeze([
140
+ "Testina",
141
+ "Fixtura",
142
+ "Synthos",
143
+ "Placeholda",
144
+ "Sampleton",
145
+ "Prototius",
146
+ "Stubbina",
147
+ "Exampla",
148
+ "Quilliam",
149
+ "Fabrica",
150
+ "Simula",
151
+ "Testry",
152
+ "Seedwin",
153
+ "Corpora",
154
+ "Reprodo",
155
+ "Mocktavia",
156
+ "Dummett",
157
+ "Voidwin",
158
+ "Deteria",
159
+ "Randomir"
160
+ ]);
161
+ var SYNTHETIC_FAMILY_NAMES = Object.freeze([
162
+ "Testerson",
163
+ "Fauxman",
164
+ "Placeholt",
165
+ "Mockridge",
166
+ "Fixtingham",
167
+ "Synthwell",
168
+ "Dummerton",
169
+ "Examplewood",
170
+ "Fabricant",
171
+ "Simulacre",
172
+ "Nonesuch",
173
+ "Seedman",
174
+ "Corpusworth",
175
+ "Reprodus",
176
+ "Voidmark",
177
+ "Deterwood",
178
+ "Randomson",
179
+ "Quillfeather",
180
+ "Notreal",
181
+ "Genfield"
182
+ ]);
183
+ var SYNTHETIC_STREET_NAMES = Object.freeze([
184
+ "Fixture Lane",
185
+ "Sample Street",
186
+ "Placeholder Avenue",
187
+ "Synthetic Way",
188
+ "Example Boulevard",
189
+ "Testing Terrace",
190
+ "Mock Road",
191
+ "Prototype Court"
192
+ ]);
193
+ var SYNTHETIC_CITY_NAMES = Object.freeze([
194
+ "Faketon",
195
+ "Synthville",
196
+ "Exampleburg",
197
+ "Testford",
198
+ "Mockhaven",
199
+ "Fixtureton"
200
+ ]);
201
+
202
+ // src/safe/providers.ts
203
+ function ssn(rng, block = "never-issued") {
204
+ if (block === "advertising") {
205
+ return `987-65-432${String(rng.int(0, 9))}`;
206
+ }
207
+ const area = rng.int(900, 999);
208
+ const group = rng.digits(2);
209
+ const serial = rng.digits(4);
210
+ return `${String(area)}-${group}-${serial}`;
211
+ }
212
+ function phone(rng) {
213
+ const area = `${String(rng.int(2, 9))}${rng.digits(2)}`;
214
+ const line = `01${rng.digits(2)}`;
215
+ return `(${area}) 555-${line}`;
216
+ }
217
+ function name(rng) {
218
+ return { given: rng.pick(SYNTHETIC_GIVEN_NAMES), family: rng.pick(SYNTHETIC_FAMILY_NAMES) };
219
+ }
220
+ function email(rng, person) {
221
+ const domain = rng.pick(RESERVED_EMAIL_DOMAINS);
222
+ const slug = person ? `${person.given}.${person.family}`.toLowerCase() : `synth${rng.digits(6)}`;
223
+ return `${slug}@${domain}`;
224
+ }
225
+ function ipv4(rng) {
226
+ return `${rng.pick(TEST_NET_V4_PREFIXES)}.${String(rng.int(1, 254))}`;
227
+ }
228
+ function ipv6(rng) {
229
+ const tail = rng.nextUint32().toString(16).padStart(4, "0").slice(-4);
230
+ return `${DOC_V6_PREFIX}::${tail}`;
231
+ }
232
+ function uuid(rng) {
233
+ const bytes = new Uint8Array(16);
234
+ for (let i = 0; i < 16; i += 1) bytes[i] = rng.int(0, 255);
235
+ bytes[6] = (bytes[6] ?? 0) & 15 | 64;
236
+ bytes[8] = (bytes[8] ?? 0) & 63 | 128;
237
+ const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0"));
238
+ return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10, 16).join("")}`;
239
+ }
240
+ function npi(rng) {
241
+ const base9 = rng.digits(9);
242
+ const wrongCheck = (npiCheckDigit(base9) + 1) % 10;
243
+ return `${base9}${String(wrongCheck)}`;
244
+ }
245
+ function dea(rng, person) {
246
+ const type = rng.pick(DEA_REGISTRANT_TYPES);
247
+ const initialSource = person?.family ?? rng.pick(SYNTHETIC_FAMILY_NAMES);
248
+ const initial = initialSource.slice(0, 1).toUpperCase();
249
+ const base6 = rng.digits(6);
250
+ const wrongCheck = (deaCheckDigit(base6) + 1) % 10;
251
+ return `${type}${initial}${base6}${String(wrongCheck)}`;
252
+ }
253
+ function identifier(rng, typeCode = "MR") {
254
+ return {
255
+ value: rng.digits(8),
256
+ typeCode,
257
+ assigningAuthority: SYNTHETIC_ASSIGNING_AUTHORITY.namespaceId,
258
+ assigningAuthorityOid: SYNTHETIC_ASSIGNING_AUTHORITY.universalId
259
+ };
260
+ }
261
+ function address(rng) {
262
+ const number = rng.int(1, 9999);
263
+ return {
264
+ street: `${String(number)} ${rng.pick(SYNTHETIC_STREET_NAMES)}`,
265
+ city: rng.pick(SYNTHETIC_CITY_NAMES),
266
+ state: rng.pick(US_STATES),
267
+ zip: "00000"
268
+ };
269
+ }
270
+ function dateYmd(rng, minYear = 1930, maxYear = 2010) {
271
+ const year = rng.int(minYear, maxYear);
272
+ const month = rng.int(1, 12);
273
+ const daysInMonth = new Date(Date.UTC(year, month, 0)).getUTCDate();
274
+ const day = rng.int(1, daysInMonth);
275
+ return `${String(year).padStart(4, "0")}${String(month).padStart(2, "0")}${String(day).padStart(2, "0")}`;
276
+ }
277
+ var US_STATES = Object.freeze([
278
+ "AL",
279
+ "AK",
280
+ "AZ",
281
+ "AR",
282
+ "CA",
283
+ "CO",
284
+ "CT",
285
+ "DE",
286
+ "FL",
287
+ "GA",
288
+ "HI",
289
+ "ID",
290
+ "IL",
291
+ "IN",
292
+ "IA",
293
+ "KS",
294
+ "KY",
295
+ "LA",
296
+ "ME",
297
+ "MD",
298
+ "MA",
299
+ "MI",
300
+ "MN",
301
+ "MS",
302
+ "MO",
303
+ "MT",
304
+ "NE",
305
+ "NV",
306
+ "NH",
307
+ "NJ",
308
+ "NM",
309
+ "NY",
310
+ "NC",
311
+ "ND",
312
+ "OH",
313
+ "OK",
314
+ "OR",
315
+ "PA",
316
+ "RI",
317
+ "SC",
318
+ "SD",
319
+ "TN",
320
+ "TX",
321
+ "UT",
322
+ "VT",
323
+ "VA",
324
+ "WA",
325
+ "WV",
326
+ "WI",
327
+ "WY"
328
+ ]);
329
+
330
+ // src/safe/index.ts
331
+ var safe = Object.freeze({
332
+ ssn,
333
+ phone,
334
+ name,
335
+ email,
336
+ ipv4,
337
+ ipv6,
338
+ uuid,
339
+ identifier,
340
+ address,
341
+ dateYmd,
342
+ npi,
343
+ dea
344
+ });
345
+
346
+ // src/fhir/us-core.ts
347
+ var US_CORE_PROFILE = Object.freeze({
348
+ /** US Core Patient. */
349
+ PATIENT: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient",
350
+ /** US Core Condition (Problems and Health Concerns). */
351
+ CONDITION: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition-problems-health-concerns",
352
+ /** US Core Laboratory Result Observation. */
353
+ OBSERVATION_LAB: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-observation-lab",
354
+ /** US Core Vital Signs (derived from the base FHIR vital-signs profile). */
355
+ VITAL_SIGNS: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-vital-signs",
356
+ /** US Core MedicationRequest. */
357
+ MEDICATION_REQUEST: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-medicationrequest",
358
+ /** US Core Encounter. */
359
+ ENCOUNTER: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-encounter",
360
+ /** US Core DiagnosticReport Profile for Laboratory Results Reporting. */
361
+ DIAGNOSTIC_REPORT_LAB: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-diagnosticreport-lab",
362
+ /** US Core Immunization. */
363
+ IMMUNIZATION: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-immunization",
364
+ /** US Core AllergyIntolerance. */
365
+ ALLERGY_INTOLERANCE: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-allergyintolerance",
366
+ /** US Core Procedure. */
367
+ PROCEDURE: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-procedure"
368
+ });
369
+ var US_CORE_RACE_EXTENSION = "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race";
370
+ var US_CORE_ETHNICITY_EXTENSION = "http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity";
371
+ var US_CORE_BIRTHSEX_EXTENSION = "http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex";
372
+ var SYSTEM = Object.freeze({
373
+ /** FHIR `administrative-gender` (`Patient.gender`). */
374
+ ADMINISTRATIVE_GENDER: "http://hl7.org/fhir/administrative-gender",
375
+ /** HL7 Terminology `observation-category`. */
376
+ OBSERVATION_CATEGORY: "http://terminology.hl7.org/CodeSystem/observation-category",
377
+ /** HL7 Terminology `condition-category`. */
378
+ CONDITION_CATEGORY: "http://terminology.hl7.org/CodeSystem/condition-category",
379
+ /** HL7 Terminology `condition-clinical`. */
380
+ CONDITION_CLINICAL: "http://terminology.hl7.org/CodeSystem/condition-clinical",
381
+ /** HL7 Terminology `condition-ver-status`. */
382
+ CONDITION_VER_STATUS: "http://terminology.hl7.org/CodeSystem/condition-ver-status",
383
+ /** HL7 v2 `0203` identifier-type (`Identifier.type.coding.code` = `MR`). */
384
+ IDENTIFIER_TYPE: "http://terminology.hl7.org/CodeSystem/v2-0203",
385
+ /** OMB race & ethnicity category system (US Core race/ethnicity `ombCategory`). */
386
+ OMB_RACE_ETHNICITY: "urn:oid:2.16.840.1.113883.6.238",
387
+ /** LOINC — `Observation.code` (lab + vital-signs). */
388
+ LOINC: "http://loinc.org",
389
+ /** SNOMED CT — `Condition.code`. */
390
+ SNOMED: "http://snomed.info/sct",
391
+ /** RxNorm — `MedicationRequest.medicationCodeableConcept` + an allergen substance. */
392
+ RXNORM: "http://www.nlm.nih.gov/research/umls/rxnorm",
393
+ /** UCUM — `Quantity.system` for units of measure. */
394
+ UCUM: "http://unitsofmeasure.org",
395
+ /** CVX (CDC vaccine administered) — `Immunization.vaccineCode`. */
396
+ CVX: "http://hl7.org/fhir/sid/cvx",
397
+ /** HL7 v3 `ActCode` — `Encounter.class`. */
398
+ V3_ACT_CODE: "http://terminology.hl7.org/CodeSystem/v3-ActCode",
399
+ /** HL7 v2 `0074` diagnostic-service-section — `DiagnosticReport.category` (`LAB`). */
400
+ DIAGNOSTIC_SERVICE_SECTION: "http://terminology.hl7.org/CodeSystem/v2-0074",
401
+ /** HL7 Terminology `allergyintolerance-clinical` — `AllergyIntolerance.clinicalStatus`. */
402
+ ALLERGY_CLINICAL: "http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical",
403
+ /** HL7 Terminology `allergyintolerance-verification` — `AllergyIntolerance.verificationStatus`. */
404
+ ALLERGY_VERIFICATION: "http://terminology.hl7.org/CodeSystem/allergyintolerance-verification"
405
+ });
406
+
407
+ // src/fhir/builder.ts
408
+ function prop(name2, value) {
409
+ return { name: name2, value };
410
+ }
411
+ function str(value) {
412
+ return fhir.primitive(value);
413
+ }
414
+ function dec(raw) {
415
+ return fhir.primitive(fhir.decimal(raw));
416
+ }
417
+ function bool(value) {
418
+ return fhir.primitive(value);
419
+ }
420
+ function coding(concept) {
421
+ return fhir.complex([
422
+ prop("system", str(concept.system)),
423
+ prop("code", str(concept.code)),
424
+ prop("display", str(concept.display))
425
+ ]);
426
+ }
427
+ function codeableConcept(concept) {
428
+ return fhir.complex([prop("coding", fhir.list([coding(concept)]))]);
429
+ }
430
+ function reference(ref) {
431
+ return fhir.complex([prop("reference", str(ref))]);
432
+ }
433
+ function narrative(text) {
434
+ const escaped = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
435
+ return fhir.complex([
436
+ prop("status", str("generated")),
437
+ prop("div", str(`<div xmlns="http://www.w3.org/1999/xhtml"><p>${escaped}</p></div>`))
438
+ ]);
439
+ }
440
+ function meta(profiles) {
441
+ return fhir.complex([prop("profile", fhir.list(profiles.map((p) => str(p))))]);
442
+ }
443
+ function toFhirDate(ymd) {
444
+ return `${ymd.slice(0, 4)}-${ymd.slice(4, 6)}-${ymd.slice(6, 8)}`;
445
+ }
446
+ function fhirPatientIdentity(rng) {
447
+ const id = safe.uuid(rng);
448
+ const person = safe.name(rng);
449
+ const mrn = safe.identifier(rng, "MR");
450
+ const birthDate = toFhirDate(safe.dateYmd(rng, 1930, 2010));
451
+ const gender = rng.pick(["male", "female"]);
452
+ const address2 = safe.address(rng);
453
+ const phone2 = safe.phone(rng);
454
+ const email2 = safe.email(rng, person);
455
+ return { id, person, mrn, birthDate, gender, address: address2, phone: phone2, email: email2 };
456
+ }
457
+ function mrnIdentifier(mrn) {
458
+ return fhir.complex([
459
+ prop(
460
+ "type",
461
+ fhir.complex([
462
+ prop(
463
+ "coding",
464
+ fhir.list([
465
+ coding({
466
+ system: SYSTEM.IDENTIFIER_TYPE,
467
+ code: "MR",
468
+ display: "Medical Record Number"
469
+ })
470
+ ])
471
+ )
472
+ ])
473
+ ),
474
+ prop("system", str(`urn:oid:${mrn.assigningAuthorityOid}`)),
475
+ prop("value", str(mrn.value))
476
+ ]);
477
+ }
478
+
479
+ // src/fhir/example-codes.ts
480
+ var EXAMPLE_LAB_OBSERVATIONS = Object.freeze([
481
+ Object.freeze({
482
+ system: SYSTEM.LOINC,
483
+ code: "2345-7",
484
+ display: "Glucose [Mass/volume] in Serum or Plasma",
485
+ unit: "mg/dL",
486
+ low: 70,
487
+ high: 140,
488
+ decimals: 0
489
+ }),
490
+ Object.freeze({
491
+ system: SYSTEM.LOINC,
492
+ code: "718-7",
493
+ display: "Hemoglobin [Mass/volume] in Blood",
494
+ unit: "g/dL",
495
+ low: 12,
496
+ high: 17,
497
+ decimals: 1
498
+ }),
499
+ Object.freeze({
500
+ system: SYSTEM.LOINC,
501
+ code: "2951-2",
502
+ display: "Sodium [Moles/volume] in Serum or Plasma",
503
+ unit: "mmol/L",
504
+ low: 135,
505
+ high: 145,
506
+ decimals: 0
507
+ }),
508
+ Object.freeze({
509
+ system: SYSTEM.LOINC,
510
+ code: "2823-3",
511
+ display: "Potassium [Moles/volume] in Serum or Plasma",
512
+ unit: "mmol/L",
513
+ low: 4,
514
+ high: 5,
515
+ decimals: 1
516
+ }),
517
+ Object.freeze({
518
+ system: SYSTEM.LOINC,
519
+ code: "4548-4",
520
+ display: "Hemoglobin A1c/Hemoglobin.total in Blood",
521
+ unit: "%",
522
+ low: 4,
523
+ high: 9,
524
+ decimals: 1
525
+ })
526
+ ]);
527
+ var EXAMPLE_VITAL_SIGNS = Object.freeze([
528
+ Object.freeze({
529
+ system: SYSTEM.LOINC,
530
+ code: "8867-4",
531
+ display: "Heart rate",
532
+ unit: "/min",
533
+ low: 55,
534
+ high: 100,
535
+ decimals: 0
536
+ }),
537
+ Object.freeze({
538
+ system: SYSTEM.LOINC,
539
+ code: "9279-1",
540
+ display: "Respiratory rate",
541
+ unit: "/min",
542
+ low: 12,
543
+ high: 20,
544
+ decimals: 0
545
+ }),
546
+ Object.freeze({
547
+ system: SYSTEM.LOINC,
548
+ code: "8310-5",
549
+ display: "Body temperature",
550
+ unit: "Cel",
551
+ low: 36,
552
+ high: 38,
553
+ decimals: 1
554
+ }),
555
+ Object.freeze({
556
+ system: SYSTEM.LOINC,
557
+ code: "29463-7",
558
+ display: "Body weight",
559
+ unit: "kg",
560
+ low: 50,
561
+ high: 100,
562
+ decimals: 1
563
+ }),
564
+ Object.freeze({
565
+ system: SYSTEM.LOINC,
566
+ code: "8302-2",
567
+ display: "Body height",
568
+ unit: "cm",
569
+ low: 150,
570
+ high: 190,
571
+ decimals: 0
572
+ })
573
+ ]);
574
+ var EXAMPLE_CONDITIONS = Object.freeze([
575
+ Object.freeze({ system: SYSTEM.SNOMED, code: "59621000", display: "Essential hypertension" }),
576
+ Object.freeze({ system: SYSTEM.SNOMED, code: "44054006", display: "Type 2 diabetes mellitus" }),
577
+ Object.freeze({ system: SYSTEM.SNOMED, code: "195967001", display: "Asthma" }),
578
+ Object.freeze({
579
+ system: SYSTEM.SNOMED,
580
+ code: "13645005",
581
+ display: "Chronic obstructive lung disease"
582
+ }),
583
+ Object.freeze({ system: SYSTEM.SNOMED, code: "38341003", display: "Hypertensive disorder" })
584
+ ]);
585
+ var EXAMPLE_MEDICATIONS = Object.freeze([
586
+ Object.freeze({
587
+ system: SYSTEM.RXNORM,
588
+ code: "1049221",
589
+ display: "Acetaminophen 325 MG Oral Tablet"
590
+ }),
591
+ Object.freeze({ system: SYSTEM.RXNORM, code: "197361", display: "Amlodipine 5 MG Oral Tablet" }),
592
+ Object.freeze({
593
+ system: SYSTEM.RXNORM,
594
+ code: "860975",
595
+ display: "24 HR Metformin hydrochloride 500 MG Extended Release Oral Tablet"
596
+ }),
597
+ Object.freeze({
598
+ system: SYSTEM.RXNORM,
599
+ code: "308136",
600
+ display: "Amoxicillin 250 MG Oral Capsule"
601
+ }),
602
+ Object.freeze({
603
+ system: SYSTEM.RXNORM,
604
+ code: "617314",
605
+ display: "Atorvastatin 40 MG Oral Tablet"
606
+ })
607
+ ]);
608
+ var EXAMPLE_RACE_CATEGORIES = Object.freeze([
609
+ Object.freeze({ system: SYSTEM.OMB_RACE_ETHNICITY, code: "2106-3", display: "White" }),
610
+ Object.freeze({
611
+ system: SYSTEM.OMB_RACE_ETHNICITY,
612
+ code: "2054-5",
613
+ display: "Black or African American"
614
+ }),
615
+ Object.freeze({ system: SYSTEM.OMB_RACE_ETHNICITY, code: "2028-9", display: "Asian" }),
616
+ Object.freeze({
617
+ system: SYSTEM.OMB_RACE_ETHNICITY,
618
+ code: "1002-5",
619
+ display: "American Indian or Alaska Native"
620
+ }),
621
+ Object.freeze({
622
+ system: SYSTEM.OMB_RACE_ETHNICITY,
623
+ code: "2076-8",
624
+ display: "Native Hawaiian or Other Pacific Islander"
625
+ })
626
+ ]);
627
+ var EXAMPLE_ETHNICITY_CATEGORIES = Object.freeze([
628
+ Object.freeze({
629
+ system: SYSTEM.OMB_RACE_ETHNICITY,
630
+ code: "2135-2",
631
+ display: "Hispanic or Latino"
632
+ }),
633
+ Object.freeze({
634
+ system: SYSTEM.OMB_RACE_ETHNICITY,
635
+ code: "2186-5",
636
+ display: "Not Hispanic or Latino"
637
+ })
638
+ ]);
639
+ var EXAMPLE_VACCINES = Object.freeze([
640
+ Object.freeze({
641
+ system: SYSTEM.CVX,
642
+ code: "140",
643
+ display: "Influenza, seasonal, injectable, preservative free"
644
+ }),
645
+ Object.freeze({ system: SYSTEM.CVX, code: "03", display: "MMR" }),
646
+ Object.freeze({ system: SYSTEM.CVX, code: "20", display: "DTaP" }),
647
+ Object.freeze({ system: SYSTEM.CVX, code: "133", display: "Pneumococcal conjugate PCV 13" }),
648
+ Object.freeze({
649
+ system: SYSTEM.CVX,
650
+ code: "208",
651
+ display: "COVID-19, mRNA, LNP-S, PF, 30 mcg/0.3 mL dose"
652
+ })
653
+ ]);
654
+ var EXAMPLE_ALLERGENS = Object.freeze([
655
+ Object.freeze({ system: SYSTEM.RXNORM, code: "7980", display: "Penicillin G" }),
656
+ Object.freeze({ system: SYSTEM.RXNORM, code: "2670", display: "Codeine" }),
657
+ Object.freeze({ system: SYSTEM.SNOMED, code: "762952008", display: "Peanut (substance)" }),
658
+ Object.freeze({ system: SYSTEM.SNOMED, code: "227493005", display: "Cashew nuts (substance)" }),
659
+ Object.freeze({ system: SYSTEM.SNOMED, code: "3718001", display: "Cow's milk (substance)" })
660
+ ]);
661
+ var EXAMPLE_ALLERGY_MANIFESTATIONS = Object.freeze([
662
+ Object.freeze({ system: SYSTEM.SNOMED, code: "247472004", display: "Wheal (finding)" }),
663
+ Object.freeze({ system: SYSTEM.SNOMED, code: "126485001", display: "Urticaria (disorder)" }),
664
+ Object.freeze({
665
+ system: SYSTEM.SNOMED,
666
+ code: "271807003",
667
+ display: "Eruption of skin (disorder)"
668
+ }),
669
+ Object.freeze({ system: SYSTEM.SNOMED, code: "267036007", display: "Dyspnea (finding)" }),
670
+ Object.freeze({ system: SYSTEM.SNOMED, code: "422587007", display: "Nausea (finding)" })
671
+ ]);
672
+ var EXAMPLE_PROCEDURES = Object.freeze([
673
+ Object.freeze({
674
+ system: SYSTEM.SNOMED,
675
+ code: "80146002",
676
+ display: "Excision of appendix (procedure)"
677
+ }),
678
+ Object.freeze({ system: SYSTEM.SNOMED, code: "73761001", display: "Colonoscopy (procedure)" }),
679
+ Object.freeze({
680
+ system: SYSTEM.SNOMED,
681
+ code: "5880005",
682
+ display: "Physical examination procedure (procedure)"
683
+ }),
684
+ Object.freeze({
685
+ system: SYSTEM.SNOMED,
686
+ code: "108252007",
687
+ display: "Laboratory procedure (procedure)"
688
+ }),
689
+ Object.freeze({ system: SYSTEM.SNOMED, code: "71651007", display: "Mammography (procedure)" })
690
+ ]);
691
+ var EXAMPLE_DIAGNOSTIC_REPORTS = Object.freeze([
692
+ Object.freeze({
693
+ system: SYSTEM.LOINC,
694
+ code: "24323-8",
695
+ display: "Comprehensive metabolic 2000 panel - Serum or Plasma"
696
+ }),
697
+ Object.freeze({
698
+ system: SYSTEM.LOINC,
699
+ code: "58410-2",
700
+ display: "CBC panel - Blood by Automated count"
701
+ }),
702
+ Object.freeze({
703
+ system: SYSTEM.LOINC,
704
+ code: "24357-6",
705
+ display: "Urinalysis complete panel - Urine"
706
+ }),
707
+ Object.freeze({
708
+ system: SYSTEM.LOINC,
709
+ code: "24331-1",
710
+ display: "Lipid 1996 panel - Serum or Plasma"
711
+ }),
712
+ Object.freeze({
713
+ system: SYSTEM.LOINC,
714
+ code: "24321-2",
715
+ display: "Basic metabolic 1998 panel - Serum or Plasma"
716
+ })
717
+ ]);
718
+ var EXAMPLE_ENCOUNTER_TYPES = Object.freeze([
719
+ Object.freeze({
720
+ system: SYSTEM.SNOMED,
721
+ code: "308335008",
722
+ display: "Patient encounter procedure (procedure)"
723
+ }),
724
+ Object.freeze({
725
+ system: SYSTEM.SNOMED,
726
+ code: "185349003",
727
+ display: "Encounter for check up (procedure)"
728
+ }),
729
+ Object.freeze({
730
+ system: SYSTEM.SNOMED,
731
+ code: "185347001",
732
+ display: "Encounter for problem (procedure)"
733
+ }),
734
+ Object.freeze({
735
+ system: SYSTEM.SNOMED,
736
+ code: "390906007",
737
+ display: "Follow-up encounter (procedure)"
738
+ })
739
+ ]);
740
+ var EXAMPLE_ENCOUNTER_CLASSES = Object.freeze([
741
+ Object.freeze({ system: SYSTEM.V3_ACT_CODE, code: "AMB", display: "ambulatory" }),
742
+ Object.freeze({ system: SYSTEM.V3_ACT_CODE, code: "EMER", display: "emergency" }),
743
+ Object.freeze({ system: SYSTEM.V3_ACT_CODE, code: "IMP", display: "inpatient encounter" })
744
+ ]);
745
+
746
+ // src/fhir/patient.ts
747
+ function ombExtension(url, category) {
748
+ return fhir.complex([
749
+ prop("url", str(url)),
750
+ prop(
751
+ "extension",
752
+ fhir.list([
753
+ fhir.complex([prop("url", str("ombCategory")), prop("valueCoding", coding(category))]),
754
+ fhir.complex([prop("url", str("text")), prop("valueString", str(category.display))])
755
+ ])
756
+ )
757
+ ]);
758
+ }
759
+ function generatePatient(options = {}) {
760
+ const { seed = 0, profile = "base" } = options;
761
+ const rng = createRng(seed);
762
+ const id = fhirPatientIdentity(rng);
763
+ const usCore = profile === "us-core";
764
+ const props = [
765
+ prop("resourceType", str("Patient")),
766
+ prop("id", str(`syn-patient-${id.id}`))
767
+ ];
768
+ if (usCore) props.push(prop("meta", meta([US_CORE_PROFILE.PATIENT])));
769
+ props.push(
770
+ prop(
771
+ "text",
772
+ narrative(
773
+ `Synthetic patient ${id.person.given} ${id.person.family} (${id.gender}, born ${id.birthDate}).`
774
+ )
775
+ )
776
+ );
777
+ if (usCore) {
778
+ const race = rng.pick(EXAMPLE_RACE_CATEGORIES);
779
+ const ethnicity = rng.pick(EXAMPLE_ETHNICITY_CATEGORIES);
780
+ const birthsex = id.gender === "male" ? "M" : "F";
781
+ props.push(
782
+ prop(
783
+ "extension",
784
+ fhir.list([
785
+ ombExtension(US_CORE_RACE_EXTENSION, race),
786
+ ombExtension(US_CORE_ETHNICITY_EXTENSION, ethnicity),
787
+ fhir.complex([prop("url", str(US_CORE_BIRTHSEX_EXTENSION)), prop("valueCode", str(birthsex))])
788
+ ])
789
+ )
790
+ );
791
+ }
792
+ props.push(prop("identifier", fhir.list([mrnIdentifier(id.mrn)])));
793
+ props.push(prop("active", bool(true)));
794
+ props.push(
795
+ prop(
796
+ "name",
797
+ fhir.list([
798
+ fhir.complex([
799
+ prop("use", str("official")),
800
+ prop("family", str(id.person.family)),
801
+ prop("given", fhir.list([str(id.person.given)]))
802
+ ])
803
+ ])
804
+ )
805
+ );
806
+ props.push(
807
+ prop(
808
+ "telecom",
809
+ fhir.list([
810
+ fhir.complex([
811
+ prop("system", str("phone")),
812
+ prop("value", str(id.phone)),
813
+ prop("use", str("home"))
814
+ ]),
815
+ fhir.complex([prop("system", str("email")), prop("value", str(id.email))])
816
+ ])
817
+ )
818
+ );
819
+ props.push(prop("gender", str(id.gender)));
820
+ props.push(prop("birthDate", str(id.birthDate)));
821
+ props.push(
822
+ prop(
823
+ "address",
824
+ fhir.list([
825
+ fhir.complex([
826
+ prop("use", str("home")),
827
+ prop("line", fhir.list([str(id.address.street)])),
828
+ prop("city", str(id.address.city)),
829
+ prop("state", str(id.address.state)),
830
+ prop("postalCode", str(id.address.zip))
831
+ ])
832
+ ])
833
+ )
834
+ );
835
+ return fhir.complex(props);
836
+ }
837
+ function generateCondition(options = {}) {
838
+ const { seed = 0, subject = "Patient/syn-patient-1", usCore = true } = options;
839
+ const rng = createRng(seed);
840
+ const code = rng.pick(EXAMPLE_CONDITIONS);
841
+ const props = [
842
+ prop("resourceType", str("Condition")),
843
+ prop("id", str(`syn-cond-${rng.digits(8)}`))
844
+ ];
845
+ if (usCore) props.push(prop("meta", meta([US_CORE_PROFILE.CONDITION])));
846
+ props.push(prop("text", narrative(`Synthetic condition: ${code.display}.`)));
847
+ props.push(
848
+ prop(
849
+ "clinicalStatus",
850
+ codeableConcept({ system: SYSTEM.CONDITION_CLINICAL, code: "active", display: "Active" })
851
+ )
852
+ );
853
+ props.push(
854
+ prop(
855
+ "verificationStatus",
856
+ codeableConcept({
857
+ system: SYSTEM.CONDITION_VER_STATUS,
858
+ code: "confirmed",
859
+ display: "Confirmed"
860
+ })
861
+ )
862
+ );
863
+ props.push(
864
+ prop(
865
+ "category",
866
+ fhir.list([
867
+ codeableConcept({
868
+ system: SYSTEM.CONDITION_CATEGORY,
869
+ code: "problem-list-item",
870
+ display: "Problem List Item"
871
+ })
872
+ ])
873
+ )
874
+ );
875
+ props.push(prop("code", codeableConcept(code)));
876
+ props.push(prop("subject", reference(subject)));
877
+ return fhir.complex(props);
878
+ }
879
+ function drawValue(rng, concept) {
880
+ const span = concept.high - concept.low;
881
+ const raw = concept.low + rng.float() * span;
882
+ return raw.toFixed(concept.decimals);
883
+ }
884
+ function valueQuantity(rng, concept) {
885
+ return fhir.complex([
886
+ prop("value", dec(drawValue(rng, concept))),
887
+ prop("unit", str(concept.unit)),
888
+ prop("system", str(SYSTEM.UCUM)),
889
+ prop("code", str(concept.unit))
890
+ ]);
891
+ }
892
+ function buildObservation(seed, subject, usCore, profileUrl, category, pool, effective) {
893
+ const rng = createRng(seed);
894
+ const concept = rng.pick(pool);
895
+ const props = [
896
+ prop("resourceType", str("Observation")),
897
+ prop("id", str(`syn-obs-${rng.digits(8)}`))
898
+ ];
899
+ if (usCore) props.push(prop("meta", meta([profileUrl])));
900
+ props.push(
901
+ prop("text", narrative(`Synthetic ${category.display.toLowerCase()}: ${concept.display}.`))
902
+ );
903
+ props.push(prop("status", str("final")));
904
+ props.push(
905
+ prop(
906
+ "category",
907
+ fhir.list([
908
+ codeableConcept({
909
+ system: SYSTEM.OBSERVATION_CATEGORY,
910
+ code: category.code,
911
+ display: category.display
912
+ })
913
+ ])
914
+ )
915
+ );
916
+ props.push(prop("code", codeableConcept(concept)));
917
+ props.push(prop("subject", reference(subject)));
918
+ const y = rng.int(2020, 2025);
919
+ const m = String(rng.int(1, 12)).padStart(2, "0");
920
+ const d = String(rng.int(1, 28)).padStart(2, "0");
921
+ if (effective) props.push(prop("effectiveDateTime", str(`${String(y)}-${m}-${d}`)));
922
+ props.push(prop("valueQuantity", valueQuantity(rng, concept)));
923
+ return fhir.complex(props);
924
+ }
925
+ function generateObservationLab(options = {}) {
926
+ const { seed = 0, subject = "Patient/syn-patient-1", usCore = true } = options;
927
+ return buildObservation(
928
+ seed,
929
+ subject,
930
+ usCore,
931
+ US_CORE_PROFILE.OBSERVATION_LAB,
932
+ { code: "laboratory", display: "Laboratory" },
933
+ EXAMPLE_LAB_OBSERVATIONS,
934
+ false
935
+ );
936
+ }
937
+ function generateVitalSign(options = {}) {
938
+ const { seed = 0, subject = "Patient/syn-patient-1", usCore = true } = options;
939
+ return buildObservation(
940
+ seed,
941
+ subject,
942
+ usCore,
943
+ US_CORE_PROFILE.VITAL_SIGNS,
944
+ { code: "vital-signs", display: "Vital Signs" },
945
+ EXAMPLE_VITAL_SIGNS,
946
+ true
947
+ );
948
+ }
949
+ function generateMedicationRequest(options = {}) {
950
+ const {
951
+ seed = 0,
952
+ subject = "Patient/syn-patient-1",
953
+ requester = "Practitioner/syn-practitioner-1",
954
+ usCore = true
955
+ } = options;
956
+ const rng = createRng(seed);
957
+ const med = rng.pick(EXAMPLE_MEDICATIONS);
958
+ const y = rng.int(2020, 2025);
959
+ const m = String(rng.int(1, 12)).padStart(2, "0");
960
+ const d = String(rng.int(1, 28)).padStart(2, "0");
961
+ const props = [
962
+ prop("resourceType", str("MedicationRequest")),
963
+ prop("id", str(`syn-medreq-${rng.digits(8)}`))
964
+ ];
965
+ if (usCore) props.push(prop("meta", meta([US_CORE_PROFILE.MEDICATION_REQUEST])));
966
+ props.push(prop("text", narrative(`Synthetic medication order: ${med.display}.`)));
967
+ props.push(prop("status", str("active")));
968
+ props.push(prop("intent", str("order")));
969
+ props.push(prop("medicationCodeableConcept", codeableConcept(med)));
970
+ props.push(prop("subject", reference(subject)));
971
+ props.push(prop("authoredOn", str(`${String(y)}-${m}-${d}`)));
972
+ props.push(prop("requester", reference(requester)));
973
+ return fhir.complex(props);
974
+ }
975
+ function generateEncounter(options = {}) {
976
+ const { seed = 0, subject = "Patient/syn-patient-1", usCore = true } = options;
977
+ const rng = createRng(seed);
978
+ const cls = rng.pick(EXAMPLE_ENCOUNTER_CLASSES);
979
+ const type = rng.pick(EXAMPLE_ENCOUNTER_TYPES);
980
+ const id = safe.identifier(rng, "AN");
981
+ const start = toFhirDate(safe.dateYmd(rng, 2018, 2024));
982
+ const props = [
983
+ prop("resourceType", str("Encounter")),
984
+ prop("id", str(`syn-enc-${rng.digits(8)}`))
985
+ ];
986
+ if (usCore) props.push(prop("meta", meta([US_CORE_PROFILE.ENCOUNTER])));
987
+ props.push(prop("text", narrative(`Synthetic encounter: ${type.display}.`)));
988
+ props.push(
989
+ prop(
990
+ "identifier",
991
+ fhir.list([
992
+ fhir.complex([
993
+ prop("system", str(`urn:oid:${id.assigningAuthorityOid}`)),
994
+ prop("value", str(id.value))
995
+ ])
996
+ ])
997
+ )
998
+ );
999
+ props.push(prop("status", str("finished")));
1000
+ props.push(prop("class", coding(cls)));
1001
+ props.push(prop("type", fhir.list([codeableConcept(type)])));
1002
+ props.push(prop("subject", reference(subject)));
1003
+ props.push(prop("period", fhir.complex([prop("start", str(`${start}T09:00:00Z`))])));
1004
+ return fhir.complex(props);
1005
+ }
1006
+ function generateImmunization(options = {}) {
1007
+ const { seed = 0, patient = "Patient/syn-patient-1", usCore = true } = options;
1008
+ const rng = createRng(seed);
1009
+ const vaccine = rng.pick(EXAMPLE_VACCINES);
1010
+ const occurrence = toFhirDate(safe.dateYmd(rng, 2015, 2024));
1011
+ const props = [
1012
+ prop("resourceType", str("Immunization")),
1013
+ prop("id", str(`syn-imm-${rng.digits(8)}`))
1014
+ ];
1015
+ if (usCore) props.push(prop("meta", meta([US_CORE_PROFILE.IMMUNIZATION])));
1016
+ props.push(prop("text", narrative(`Synthetic immunization: ${vaccine.display}.`)));
1017
+ props.push(prop("status", str("completed")));
1018
+ props.push(prop("vaccineCode", codeableConcept(vaccine)));
1019
+ props.push(prop("patient", reference(patient)));
1020
+ props.push(prop("occurrenceDateTime", str(occurrence)));
1021
+ props.push(prop("primarySource", bool(true)));
1022
+ return fhir.complex(props);
1023
+ }
1024
+ function generateAllergyIntolerance(options = {}) {
1025
+ const { seed = 0, patient = "Patient/syn-patient-1", usCore = true } = options;
1026
+ const rng = createRng(seed);
1027
+ const allergen = rng.pick(EXAMPLE_ALLERGENS);
1028
+ const manifestation = rng.pick(EXAMPLE_ALLERGY_MANIFESTATIONS);
1029
+ const props = [
1030
+ prop("resourceType", str("AllergyIntolerance")),
1031
+ prop("id", str(`syn-allergy-${rng.digits(8)}`))
1032
+ ];
1033
+ if (usCore) props.push(prop("meta", meta([US_CORE_PROFILE.ALLERGY_INTOLERANCE])));
1034
+ props.push(prop("text", narrative(`Synthetic allergy: ${allergen.display}.`)));
1035
+ props.push(
1036
+ prop(
1037
+ "clinicalStatus",
1038
+ codeableConcept({ system: SYSTEM.ALLERGY_CLINICAL, code: "active", display: "Active" })
1039
+ )
1040
+ );
1041
+ props.push(
1042
+ prop(
1043
+ "verificationStatus",
1044
+ codeableConcept({
1045
+ system: SYSTEM.ALLERGY_VERIFICATION,
1046
+ code: "confirmed",
1047
+ display: "Confirmed"
1048
+ })
1049
+ )
1050
+ );
1051
+ props.push(prop("code", codeableConcept(allergen)));
1052
+ props.push(prop("patient", reference(patient)));
1053
+ props.push(
1054
+ prop(
1055
+ "reaction",
1056
+ fhir.list([fhir.complex([prop("manifestation", fhir.list([codeableConcept(manifestation)]))])])
1057
+ )
1058
+ );
1059
+ return fhir.complex(props);
1060
+ }
1061
+ function generateProcedure(options = {}) {
1062
+ const { seed = 0, subject = "Patient/syn-patient-1", usCore = true } = options;
1063
+ const rng = createRng(seed);
1064
+ const code = rng.pick(EXAMPLE_PROCEDURES);
1065
+ const performed = toFhirDate(safe.dateYmd(rng, 2018, 2024));
1066
+ const props = [
1067
+ prop("resourceType", str("Procedure")),
1068
+ prop("id", str(`syn-proc-${rng.digits(8)}`))
1069
+ ];
1070
+ if (usCore) props.push(prop("meta", meta([US_CORE_PROFILE.PROCEDURE])));
1071
+ props.push(prop("text", narrative(`Synthetic procedure: ${code.display}.`)));
1072
+ props.push(prop("status", str("completed")));
1073
+ props.push(prop("code", codeableConcept(code)));
1074
+ props.push(prop("subject", reference(subject)));
1075
+ props.push(prop("performedDateTime", str(`${performed}T10:00:00Z`)));
1076
+ return fhir.complex(props);
1077
+ }
1078
+ function generateDiagnosticReport(options = {}) {
1079
+ const { seed = 0, subject = "Patient/syn-patient-1", results = [], usCore = true } = options;
1080
+ const rng = createRng(seed);
1081
+ const code = rng.pick(EXAMPLE_DIAGNOSTIC_REPORTS);
1082
+ const day = toFhirDate(safe.dateYmd(rng, 2018, 2024));
1083
+ const props = [
1084
+ prop("resourceType", str("DiagnosticReport")),
1085
+ prop("id", str(`syn-dr-${rng.digits(8)}`))
1086
+ ];
1087
+ if (usCore) props.push(prop("meta", meta([US_CORE_PROFILE.DIAGNOSTIC_REPORT_LAB])));
1088
+ props.push(prop("text", narrative(`Synthetic laboratory report: ${code.display}.`)));
1089
+ props.push(prop("status", str("final")));
1090
+ props.push(
1091
+ prop(
1092
+ "category",
1093
+ fhir.list([
1094
+ codeableConcept({
1095
+ system: SYSTEM.DIAGNOSTIC_SERVICE_SECTION,
1096
+ code: "LAB",
1097
+ display: "Laboratory"
1098
+ })
1099
+ ])
1100
+ )
1101
+ );
1102
+ props.push(prop("code", codeableConcept(code)));
1103
+ props.push(prop("subject", reference(subject)));
1104
+ props.push(prop("effectiveDateTime", str(`${day}T08:30:00Z`)));
1105
+ props.push(prop("issued", str(`${day}T09:00:00.000Z`)));
1106
+ if (results.length > 0) {
1107
+ props.push(prop("result", fhir.list(results.map((r) => reference(r)))));
1108
+ }
1109
+ return fhir.complex(props);
1110
+ }
1111
+
1112
+ // src/corpus.ts
1113
+ function makeCorpus(seed, artifacts, quirks = []) {
1114
+ const counts = {};
1115
+ const formats = /* @__PURE__ */ new Set();
1116
+ const frozenArtifacts = artifacts.map((a) => {
1117
+ counts[a.kind] = (counts[a.kind] ?? 0) + 1;
1118
+ formats.add(a.format);
1119
+ return Object.freeze({ ...a, warnings: Object.freeze([...a.warnings]) });
1120
+ });
1121
+ const manifest = Object.freeze({
1122
+ formats: Object.freeze([...formats]),
1123
+ counts: Object.freeze(counts),
1124
+ quirks: Object.freeze([...quirks])
1125
+ });
1126
+ return Object.freeze({
1127
+ seed,
1128
+ manifest,
1129
+ artifacts: Object.freeze(frozenArtifacts)
1130
+ });
1131
+ }
1132
+ function section(sec) {
1133
+ return fhir.complex([
1134
+ prop("title", str(sec.title)),
1135
+ prop("code", codeableConcept({ system: SYSTEM.LOINC, code: sec.code, display: sec.title })),
1136
+ prop("entry", fhir.list(sec.entries.map((e) => reference(e))))
1137
+ ]);
1138
+ }
1139
+ function buildComposition(rng, input) {
1140
+ const props = [
1141
+ prop("resourceType", str("Composition")),
1142
+ prop("id", str(`syn-comp-${rng.digits(8)}`)),
1143
+ prop("text", narrative("Synthetic continuity-of-care document summary.")),
1144
+ prop("status", str("final")),
1145
+ prop(
1146
+ "type",
1147
+ codeableConcept({
1148
+ system: SYSTEM.LOINC,
1149
+ code: "34133-9",
1150
+ display: "Summarization of Episode Note"
1151
+ })
1152
+ ),
1153
+ prop("subject", reference(input.subject)),
1154
+ prop("date", str(`${input.date}T09:00:00Z`)),
1155
+ prop("author", fhir.list([reference(input.organization)])),
1156
+ prop("title", str("Synthetic Continuity of Care Document")),
1157
+ prop("custodian", reference(input.organization)),
1158
+ prop("section", fhir.list(input.sections.map((s) => section(s))))
1159
+ ];
1160
+ return fhir.complex(props);
1161
+ }
1162
+ function roundTrip(resource, options = {}) {
1163
+ const content = fhir.serializeResource(resource);
1164
+ const { resource: reparsed } = fhir.parseResource(content);
1165
+ const byteStable = fhir.serializeResource(reparsed) === content;
1166
+ const result = fhir.validateResource(
1167
+ reparsed,
1168
+ options.profiles !== void 0 ? { mode: "strict", profiles: options.profiles } : { mode: "strict" }
1169
+ );
1170
+ const errors = result.issues.filter((i) => i.severity === "error" || i.severity === "fatal").map((i) => i.code);
1171
+ const warnings = result.issues.filter((i) => i.severity === "error" || i.severity === "fatal" || i.severity === "warning").map((i) => i.code);
1172
+ const valid = result.valid;
1173
+ return { content, errors, warnings, byteStable, valid, specClean: valid && byteStable };
1174
+ }
1175
+
1176
+ // src/fhir/bundle.ts
1177
+ function resourceTypeOf(resource) {
1178
+ const rt = resource.properties.find((p) => p.name === "resourceType");
1179
+ return rt !== void 0 && rt.value.kind === "primitive" ? String(rt.value.value) : "Resource";
1180
+ }
1181
+ function buildOrganization(rng) {
1182
+ const id = safe.identifier(rng, "AN");
1183
+ return fhir.complex([
1184
+ prop("resourceType", str("Organization")),
1185
+ prop("id", str(`syn-org-${rng.digits(8)}`)),
1186
+ prop("text", narrative("Synthetic health organization.")),
1187
+ prop(
1188
+ "identifier",
1189
+ fhir.list([
1190
+ fhir.complex([
1191
+ prop("system", str(`urn:oid:${id.assigningAuthorityOid}`)),
1192
+ prop("value", str(id.value))
1193
+ ])
1194
+ ])
1195
+ ),
1196
+ prop("active", bool(true)),
1197
+ prop("name", str("Synthetic Health Organization"))
1198
+ ]);
1199
+ }
1200
+ function buildSpine(rng) {
1201
+ const patientUrl = `urn:uuid:${safe.uuid(rng)}`;
1202
+ const orgUrl = `urn:uuid:${safe.uuid(rng)}`;
1203
+ const date = toFhirDate(safe.dateYmd(rng, 2018, 2024));
1204
+ const patient = {
1205
+ fullUrl: patientUrl,
1206
+ resource: generatePatient({ seed: rng.nextUint32(), profile: "us-core" })
1207
+ };
1208
+ const org = { fullUrl: orgUrl, resource: buildOrganization(rng) };
1209
+ const condUrl = `urn:uuid:${safe.uuid(rng)}`;
1210
+ const cond = generateCondition({ seed: rng.nextUint32(), subject: patientUrl });
1211
+ const labUrl = `urn:uuid:${safe.uuid(rng)}`;
1212
+ const lab = generateObservationLab({ seed: rng.nextUint32(), subject: patientUrl });
1213
+ const vitalUrl = `urn:uuid:${safe.uuid(rng)}`;
1214
+ const vital = generateVitalSign({ seed: rng.nextUint32(), subject: patientUrl });
1215
+ const medUrl = `urn:uuid:${safe.uuid(rng)}`;
1216
+ const med = generateMedicationRequest({
1217
+ seed: rng.nextUint32(),
1218
+ subject: patientUrl,
1219
+ requester: orgUrl
1220
+ });
1221
+ const encUrl = `urn:uuid:${safe.uuid(rng)}`;
1222
+ const enc = generateEncounter({ seed: rng.nextUint32(), subject: patientUrl });
1223
+ const immUrl = `urn:uuid:${safe.uuid(rng)}`;
1224
+ const imm = generateImmunization({ seed: rng.nextUint32(), patient: patientUrl });
1225
+ const allergyUrl = `urn:uuid:${safe.uuid(rng)}`;
1226
+ const allergy = generateAllergyIntolerance({ seed: rng.nextUint32(), patient: patientUrl });
1227
+ const procUrl = `urn:uuid:${safe.uuid(rng)}`;
1228
+ const proc = generateProcedure({ seed: rng.nextUint32(), subject: patientUrl });
1229
+ const drUrl = `urn:uuid:${safe.uuid(rng)}`;
1230
+ const dr = generateDiagnosticReport({
1231
+ seed: rng.nextUint32(),
1232
+ subject: patientUrl,
1233
+ results: [labUrl]
1234
+ });
1235
+ const entries = [
1236
+ patient,
1237
+ org,
1238
+ { fullUrl: condUrl, resource: cond },
1239
+ { fullUrl: labUrl, resource: lab },
1240
+ { fullUrl: vitalUrl, resource: vital },
1241
+ { fullUrl: medUrl, resource: med },
1242
+ { fullUrl: encUrl, resource: enc },
1243
+ { fullUrl: immUrl, resource: imm },
1244
+ { fullUrl: allergyUrl, resource: allergy },
1245
+ { fullUrl: procUrl, resource: proc },
1246
+ { fullUrl: drUrl, resource: dr }
1247
+ ];
1248
+ const urls = {
1249
+ condition: condUrl,
1250
+ lab: labUrl,
1251
+ vital: vitalUrl,
1252
+ medication: medUrl,
1253
+ encounter: encUrl,
1254
+ immunization: immUrl,
1255
+ allergy: allergyUrl,
1256
+ procedure: procUrl,
1257
+ diagnosticReport: drUrl
1258
+ };
1259
+ return { patientUrl, orgUrl, date, urls, entries };
1260
+ }
1261
+ function documentSections(urls) {
1262
+ const at = (k) => urls[k] !== void 0 ? [urls[k]] : [];
1263
+ return [
1264
+ { code: "11450-4", title: "Problem List", entries: at("condition") },
1265
+ {
1266
+ code: "30954-2",
1267
+ title: "Relevant Diagnostic Tests/Laboratory Data",
1268
+ entries: [...at("diagnosticReport"), ...at("lab"), ...at("vital")]
1269
+ },
1270
+ { code: "10160-0", title: "History of Medication Use", entries: at("medication") },
1271
+ { code: "48765-2", title: "Allergies and Adverse Reactions", entries: at("allergy") },
1272
+ { code: "11369-6", title: "History of Immunizations", entries: at("immunization") },
1273
+ { code: "47519-4", title: "History of Procedures", entries: at("procedure") },
1274
+ { code: "46240-8", title: "History of Encounters", entries: at("encounter") }
1275
+ ];
1276
+ }
1277
+ function generateBundle(options = {}) {
1278
+ const { seed = 0, type = "collection" } = options;
1279
+ const rng = createRng(seed);
1280
+ const spine = buildSpine(rng);
1281
+ const members = type === "document" ? [
1282
+ {
1283
+ fullUrl: `urn:uuid:${safe.uuid(rng)}`,
1284
+ resource: buildComposition(rng, {
1285
+ subject: spine.patientUrl,
1286
+ organization: spine.orgUrl,
1287
+ date: spine.date,
1288
+ sections: documentSections(spine.urls)
1289
+ })
1290
+ },
1291
+ ...spine.entries
1292
+ ] : [...spine.entries];
1293
+ const entries = members.map((member) => {
1294
+ const entryProps = [
1295
+ prop("fullUrl", str(member.fullUrl)),
1296
+ prop("resource", member.resource)
1297
+ ];
1298
+ if (type === "transaction") {
1299
+ entryProps.push(
1300
+ prop(
1301
+ "request",
1302
+ fhir.complex([prop("method", str("POST")), prop("url", str(resourceTypeOf(member.resource)))])
1303
+ )
1304
+ );
1305
+ }
1306
+ return fhir.complex(entryProps);
1307
+ });
1308
+ const props = [
1309
+ prop("resourceType", str("Bundle")),
1310
+ prop("id", str(`syn-bundle-${rng.digits(8)}`))
1311
+ ];
1312
+ if (type === "document") {
1313
+ const id = safe.identifier(rng, "AN");
1314
+ props.push(
1315
+ prop(
1316
+ "identifier",
1317
+ fhir.complex([
1318
+ prop("system", str(`urn:oid:${id.assigningAuthorityOid}`)),
1319
+ prop("value", str(`urn:uuid:${safe.uuid(rng)}`))
1320
+ ])
1321
+ )
1322
+ );
1323
+ }
1324
+ props.push(prop("type", str(type)));
1325
+ if (type === "document") props.push(prop("timestamp", str(`${spine.date}T09:00:00.000Z`)));
1326
+ props.push(prop("entry", fhir.list(entries)));
1327
+ return fhir.complex(props);
1328
+ }
1329
+ var DEFAULT_MIX = Object.freeze([
1330
+ "USCorePatient",
1331
+ "Condition",
1332
+ "ObservationLab",
1333
+ "VitalSign",
1334
+ "MedicationRequest",
1335
+ "Encounter",
1336
+ "Immunization",
1337
+ "AllergyIntolerance",
1338
+ "Procedure",
1339
+ "DiagnosticReport",
1340
+ "Bundle"
1341
+ ]);
1342
+ function generateKind(kind, seed) {
1343
+ switch (kind) {
1344
+ case "Patient":
1345
+ return generatePatient({ seed, profile: "base" });
1346
+ case "USCorePatient":
1347
+ return generatePatient({ seed, profile: "us-core" });
1348
+ case "Condition":
1349
+ return generateCondition({ seed });
1350
+ case "ObservationLab":
1351
+ return generateObservationLab({ seed });
1352
+ case "VitalSign":
1353
+ return generateVitalSign({ seed });
1354
+ case "MedicationRequest":
1355
+ return generateMedicationRequest({ seed });
1356
+ case "Encounter":
1357
+ return generateEncounter({ seed });
1358
+ case "Immunization":
1359
+ return generateImmunization({ seed });
1360
+ case "AllergyIntolerance":
1361
+ return generateAllergyIntolerance({ seed });
1362
+ case "Procedure":
1363
+ return generateProcedure({ seed });
1364
+ case "DiagnosticReport":
1365
+ return generateDiagnosticReport({ seed });
1366
+ case "Bundle":
1367
+ return generateBundle({ seed });
1368
+ case "DocumentBundle":
1369
+ return generateBundle({ seed, type: "document" });
1370
+ }
1371
+ }
1372
+ function fhirCorpus(options) {
1373
+ const { seed, count = 1 } = options;
1374
+ const kinds = options.mix ?? DEFAULT_MIX;
1375
+ const seedStream = createRng(seed);
1376
+ const artifacts = Array.from({ length: count }, (_unused, i) => {
1377
+ const kind = kinds[i % kinds.length] ?? "USCorePatient";
1378
+ const rt = roundTrip(generateKind(kind, seedStream.nextUint32()));
1379
+ return { format: "fhir", kind, content: rt.content, warnings: rt.errors };
1380
+ });
1381
+ return makeCorpus(seed, artifacts);
1382
+ }
1383
+
1384
+ exports.EXAMPLE_ALLERGENS = EXAMPLE_ALLERGENS;
1385
+ exports.EXAMPLE_ALLERGY_MANIFESTATIONS = EXAMPLE_ALLERGY_MANIFESTATIONS;
1386
+ exports.EXAMPLE_CONDITIONS = EXAMPLE_CONDITIONS;
1387
+ exports.EXAMPLE_DIAGNOSTIC_REPORTS = EXAMPLE_DIAGNOSTIC_REPORTS;
1388
+ exports.EXAMPLE_ENCOUNTER_CLASSES = EXAMPLE_ENCOUNTER_CLASSES;
1389
+ exports.EXAMPLE_ENCOUNTER_TYPES = EXAMPLE_ENCOUNTER_TYPES;
1390
+ exports.EXAMPLE_ETHNICITY_CATEGORIES = EXAMPLE_ETHNICITY_CATEGORIES;
1391
+ exports.EXAMPLE_LAB_OBSERVATIONS = EXAMPLE_LAB_OBSERVATIONS;
1392
+ exports.EXAMPLE_MEDICATIONS = EXAMPLE_MEDICATIONS;
1393
+ exports.EXAMPLE_PROCEDURES = EXAMPLE_PROCEDURES;
1394
+ exports.EXAMPLE_RACE_CATEGORIES = EXAMPLE_RACE_CATEGORIES;
1395
+ exports.EXAMPLE_VACCINES = EXAMPLE_VACCINES;
1396
+ exports.EXAMPLE_VITAL_SIGNS = EXAMPLE_VITAL_SIGNS;
1397
+ exports.SYSTEM = SYSTEM;
1398
+ exports.US_CORE_BIRTHSEX_EXTENSION = US_CORE_BIRTHSEX_EXTENSION;
1399
+ exports.US_CORE_ETHNICITY_EXTENSION = US_CORE_ETHNICITY_EXTENSION;
1400
+ exports.US_CORE_PROFILE = US_CORE_PROFILE;
1401
+ exports.US_CORE_RACE_EXTENSION = US_CORE_RACE_EXTENSION;
1402
+ exports.bool = bool;
1403
+ exports.buildComposition = buildComposition;
1404
+ exports.codeableConcept = codeableConcept;
1405
+ exports.coding = coding;
1406
+ exports.dec = dec;
1407
+ exports.fhirCorpus = fhirCorpus;
1408
+ exports.fhirPatientIdentity = fhirPatientIdentity;
1409
+ exports.generateAllergyIntolerance = generateAllergyIntolerance;
1410
+ exports.generateBundle = generateBundle;
1411
+ exports.generateCondition = generateCondition;
1412
+ exports.generateDiagnosticReport = generateDiagnosticReport;
1413
+ exports.generateEncounter = generateEncounter;
1414
+ exports.generateImmunization = generateImmunization;
1415
+ exports.generateMedicationRequest = generateMedicationRequest;
1416
+ exports.generateObservationLab = generateObservationLab;
1417
+ exports.generatePatient = generatePatient;
1418
+ exports.generateProcedure = generateProcedure;
1419
+ exports.generateVitalSign = generateVitalSign;
1420
+ exports.meta = meta;
1421
+ exports.mrnIdentifier = mrnIdentifier;
1422
+ exports.narrative = narrative;
1423
+ exports.prop = prop;
1424
+ exports.reference = reference;
1425
+ exports.roundTrip = roundTrip;
1426
+ exports.str = str;
1427
+ exports.toFhirDate = toFhirDate;
1428
+ //# sourceMappingURL=index.cjs.map
1429
+ //# sourceMappingURL=index.cjs.map