@cosyte/synth 0.1.5 → 0.1.6
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 +12 -0
- package/dist/astm/index.cjs +55 -18
- package/dist/astm/index.cjs.map +1 -1
- package/dist/astm/index.d.cts +7 -0
- package/dist/astm/index.d.ts +7 -0
- package/dist/astm/index.mjs +54 -18
- package/dist/astm/index.mjs.map +1 -1
- package/dist/ccda/index.cjs +76 -26
- package/dist/ccda/index.cjs.map +1 -1
- package/dist/ccda/index.d.cts +6 -0
- package/dist/ccda/index.d.ts +6 -0
- package/dist/ccda/index.mjs +63 -14
- package/dist/ccda/index.mjs.map +1 -1
- package/dist/deid/index.cjs +207 -118
- package/dist/deid/index.cjs.map +1 -1
- package/dist/deid/index.mjs +194 -106
- package/dist/deid/index.mjs.map +1 -1
- package/dist/fhir/index.cjs +146 -74
- package/dist/fhir/index.cjs.map +1 -1
- package/dist/fhir/index.d.cts +6 -0
- package/dist/fhir/index.d.ts +6 -0
- package/dist/fhir/index.mjs +145 -74
- package/dist/fhir/index.mjs.map +1 -1
- package/dist/hl7/index.cjs +53 -9
- package/dist/hl7/index.cjs.map +1 -1
- package/dist/hl7/index.d.cts +6 -0
- package/dist/hl7/index.d.ts +6 -0
- package/dist/hl7/index.mjs +52 -9
- package/dist/hl7/index.mjs.map +1 -1
- package/dist/index.cjs +1 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1 -3
- package/dist/index.mjs.map +1 -1
- package/dist/ncpdp/index.cjs +74 -22
- package/dist/ncpdp/index.cjs.map +1 -1
- package/dist/ncpdp/index.d.cts +7 -0
- package/dist/ncpdp/index.d.ts +7 -0
- package/dist/ncpdp/index.mjs +73 -22
- package/dist/ncpdp/index.mjs.map +1 -1
- package/dist/x12/index.cjs +65 -17
- package/dist/x12/index.cjs.map +1 -1
- package/dist/x12/index.d.cts +6 -0
- package/dist/x12/index.d.ts +6 -0
- package/dist/x12/index.mjs +64 -17
- package/dist/x12/index.mjs.map +1 -1
- package/package.json +20 -15
package/dist/deid/index.mjs
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { extractX12Loci, deidentifyX12 } from '@cosyte/deid/x12';
|
|
4
|
-
import { extractTelecomLoci, deidentifyTelecom } from '@cosyte/deid/ncpdp';
|
|
5
|
-
import { deidentifyCcda } from '@cosyte/deid/ccda';
|
|
6
|
-
import { serializeResource, complex, list, primitive, decimal } from '@cosyte/fhir';
|
|
7
|
-
import { serializeX12, parseX12, build835, build271, X12Decimal, build837D, build837I, build837P } from '@cosyte/x12';
|
|
8
|
-
import { serializeCcda, buildCcda, NCI_ROUTE, SNOMED_CT, CVX, RXNORM, LOINC } from '@cosyte/ccda';
|
|
9
|
-
import { parseTelecom, serializeTelecom, buildTelecomRequest } from '@cosyte/ncpdp/telecom';
|
|
10
|
-
import { buildMessage } from '@cosyte/hl7';
|
|
11
|
-
import { defineDeidPolicy, SAFE_HARBOR_CATEGORIES } from '@cosyte/deid';
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
12
3
|
|
|
13
|
-
|
|
4
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
5
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
6
|
+
}) : x)(function(x) {
|
|
7
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
8
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
9
|
+
});
|
|
14
10
|
|
|
15
11
|
// src/rng/splitmix32.ts
|
|
16
12
|
function splitmix32(seed) {
|
|
@@ -450,6 +446,40 @@ var safe = Object.freeze({
|
|
|
450
446
|
npi,
|
|
451
447
|
dea
|
|
452
448
|
});
|
|
449
|
+
function defaultHost() {
|
|
450
|
+
if (typeof import.meta.resolve !== "function") return { require: __require, resolve: void 0 };
|
|
451
|
+
return { require: createRequire(import.meta.url), resolve: (s) => import.meta.resolve(s) };
|
|
452
|
+
}
|
|
453
|
+
function isRequireEsmRefusal(error) {
|
|
454
|
+
return error?.code === "ERR_REQUIRE_ESM";
|
|
455
|
+
}
|
|
456
|
+
function loadPeer(specifier, host) {
|
|
457
|
+
if (host.resolve === void 0) return host.require(specifier);
|
|
458
|
+
const entry = fileURLToPath(host.resolve(specifier));
|
|
459
|
+
try {
|
|
460
|
+
return host.require(entry);
|
|
461
|
+
} catch (error) {
|
|
462
|
+
if (!isRequireEsmRefusal(error)) throw error;
|
|
463
|
+
return host.require(specifier);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
function lazyPeer(specifier, host) {
|
|
467
|
+
let loaded;
|
|
468
|
+
return () => loaded ??= loadPeer(specifier, defaultHost());
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// src/peers.ts
|
|
472
|
+
var hl7Peer = lazyPeer("@cosyte/hl7");
|
|
473
|
+
var fhirPeer = lazyPeer("@cosyte/fhir");
|
|
474
|
+
var ccdaPeer = lazyPeer("@cosyte/ccda");
|
|
475
|
+
var x12Peer = lazyPeer("@cosyte/x12");
|
|
476
|
+
var ncpdpTelecomPeer = lazyPeer("@cosyte/ncpdp/telecom");
|
|
477
|
+
var deidPeer = lazyPeer("@cosyte/deid");
|
|
478
|
+
var deidHl7Peer = lazyPeer("@cosyte/deid/hl7");
|
|
479
|
+
var deidFhirPeer = lazyPeer("@cosyte/deid/fhir");
|
|
480
|
+
var deidX12Peer = lazyPeer("@cosyte/deid/x12");
|
|
481
|
+
var deidNcpdpPeer = lazyPeer("@cosyte/deid/ncpdp");
|
|
482
|
+
var deidCcdaPeer = lazyPeer("@cosyte/deid/ccda");
|
|
453
483
|
|
|
454
484
|
// src/hl7/common.ts
|
|
455
485
|
function seededTimestamp(rng) {
|
|
@@ -462,7 +492,7 @@ function seededTimestamp(rng) {
|
|
|
462
492
|
function mshScaffold(rng, type) {
|
|
463
493
|
const timestamp = seededTimestamp(rng);
|
|
464
494
|
const controlId = `SYNTH${rng.digits(10)}`;
|
|
465
|
-
const message = buildMessage({
|
|
495
|
+
const message = hl7Peer().buildMessage({
|
|
466
496
|
type,
|
|
467
497
|
sendingApp: "COSYTE-SYNTH",
|
|
468
498
|
sendingFacility: "SYNTH-FAC",
|
|
@@ -913,36 +943,36 @@ function prop(name2, value) {
|
|
|
913
943
|
return { name: name2, value };
|
|
914
944
|
}
|
|
915
945
|
function str(value) {
|
|
916
|
-
return primitive(value);
|
|
946
|
+
return fhirPeer().primitive(value);
|
|
917
947
|
}
|
|
918
948
|
function dec(raw) {
|
|
919
|
-
return primitive(decimal(raw));
|
|
949
|
+
return fhirPeer().primitive(fhirPeer().decimal(raw));
|
|
920
950
|
}
|
|
921
951
|
function bool(value) {
|
|
922
|
-
return primitive(value);
|
|
952
|
+
return fhirPeer().primitive(value);
|
|
923
953
|
}
|
|
924
954
|
function coding(concept) {
|
|
925
|
-
return complex([
|
|
955
|
+
return fhirPeer().complex([
|
|
926
956
|
prop("system", str(concept.system)),
|
|
927
957
|
prop("code", str(concept.code)),
|
|
928
958
|
prop("display", str(concept.display))
|
|
929
959
|
]);
|
|
930
960
|
}
|
|
931
961
|
function codeableConcept(concept) {
|
|
932
|
-
return complex([prop("coding", list([coding(concept)]))]);
|
|
962
|
+
return fhirPeer().complex([prop("coding", fhirPeer().list([coding(concept)]))]);
|
|
933
963
|
}
|
|
934
964
|
function reference(ref) {
|
|
935
|
-
return complex([prop("reference", str(ref))]);
|
|
965
|
+
return fhirPeer().complex([prop("reference", str(ref))]);
|
|
936
966
|
}
|
|
937
967
|
function narrative(text) {
|
|
938
968
|
const escaped = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
939
|
-
return complex([
|
|
969
|
+
return fhirPeer().complex([
|
|
940
970
|
prop("status", str("generated")),
|
|
941
971
|
prop("div", str(`<div xmlns="http://www.w3.org/1999/xhtml"><p>${escaped}</p></div>`))
|
|
942
972
|
]);
|
|
943
973
|
}
|
|
944
974
|
function meta(profiles) {
|
|
945
|
-
return complex([prop("profile", list(profiles.map((p) => str(p))))]);
|
|
975
|
+
return fhirPeer().complex([prop("profile", fhirPeer().list(profiles.map((p) => str(p))))]);
|
|
946
976
|
}
|
|
947
977
|
function toFhirDate(ymd) {
|
|
948
978
|
return `${ymd.slice(0, 4)}-${ymd.slice(4, 6)}-${ymd.slice(6, 8)}`;
|
|
@@ -959,13 +989,13 @@ function fhirPatientIdentity(rng) {
|
|
|
959
989
|
return { id, person, mrn, birthDate, gender, address: address2, phone: phone2, email: email2 };
|
|
960
990
|
}
|
|
961
991
|
function mrnIdentifier(mrn) {
|
|
962
|
-
return complex([
|
|
992
|
+
return fhirPeer().complex([
|
|
963
993
|
prop(
|
|
964
994
|
"type",
|
|
965
|
-
complex([
|
|
995
|
+
fhirPeer().complex([
|
|
966
996
|
prop(
|
|
967
997
|
"coding",
|
|
968
|
-
list([
|
|
998
|
+
fhirPeer().list([
|
|
969
999
|
coding({
|
|
970
1000
|
system: SYSTEM.IDENTIFIER_TYPE,
|
|
971
1001
|
code: "MR",
|
|
@@ -1250,13 +1280,16 @@ var EXAMPLE_ENCOUNTER_CLASSES = Object.freeze([
|
|
|
1250
1280
|
// src/fhir/patient.ts
|
|
1251
1281
|
var PATIENT_PROFILES = Object.freeze(["base", "us-core"]);
|
|
1252
1282
|
function ombExtension(url, category) {
|
|
1253
|
-
return complex([
|
|
1283
|
+
return fhirPeer().complex([
|
|
1254
1284
|
prop("url", str(url)),
|
|
1255
1285
|
prop(
|
|
1256
1286
|
"extension",
|
|
1257
|
-
list([
|
|
1258
|
-
complex([
|
|
1259
|
-
|
|
1287
|
+
fhirPeer().list([
|
|
1288
|
+
fhirPeer().complex([
|
|
1289
|
+
prop("url", str("ombCategory")),
|
|
1290
|
+
prop("valueCoding", coding(category))
|
|
1291
|
+
]),
|
|
1292
|
+
fhirPeer().complex([prop("url", str("text")), prop("valueString", str(category.display))])
|
|
1260
1293
|
])
|
|
1261
1294
|
)
|
|
1262
1295
|
]);
|
|
@@ -1287,24 +1320,27 @@ function generatePatient(options = {}) {
|
|
|
1287
1320
|
props.push(
|
|
1288
1321
|
prop(
|
|
1289
1322
|
"extension",
|
|
1290
|
-
list([
|
|
1323
|
+
fhirPeer().list([
|
|
1291
1324
|
ombExtension(US_CORE_RACE_EXTENSION, race),
|
|
1292
1325
|
ombExtension(US_CORE_ETHNICITY_EXTENSION, ethnicity),
|
|
1293
|
-
complex([
|
|
1326
|
+
fhirPeer().complex([
|
|
1327
|
+
prop("url", str(US_CORE_BIRTHSEX_EXTENSION)),
|
|
1328
|
+
prop("valueCode", str(birthsex))
|
|
1329
|
+
])
|
|
1294
1330
|
])
|
|
1295
1331
|
)
|
|
1296
1332
|
);
|
|
1297
1333
|
}
|
|
1298
|
-
props.push(prop("identifier", list([mrnIdentifier(id.mrn)])));
|
|
1334
|
+
props.push(prop("identifier", fhirPeer().list([mrnIdentifier(id.mrn)])));
|
|
1299
1335
|
props.push(prop("active", bool(true)));
|
|
1300
1336
|
props.push(
|
|
1301
1337
|
prop(
|
|
1302
1338
|
"name",
|
|
1303
|
-
list([
|
|
1304
|
-
complex([
|
|
1339
|
+
fhirPeer().list([
|
|
1340
|
+
fhirPeer().complex([
|
|
1305
1341
|
prop("use", str("official")),
|
|
1306
1342
|
prop("family", str(id.person.family)),
|
|
1307
|
-
prop("given", list([str(id.person.given)]))
|
|
1343
|
+
prop("given", fhirPeer().list([str(id.person.given)]))
|
|
1308
1344
|
])
|
|
1309
1345
|
])
|
|
1310
1346
|
)
|
|
@@ -1312,13 +1348,13 @@ function generatePatient(options = {}) {
|
|
|
1312
1348
|
props.push(
|
|
1313
1349
|
prop(
|
|
1314
1350
|
"telecom",
|
|
1315
|
-
list([
|
|
1316
|
-
complex([
|
|
1351
|
+
fhirPeer().list([
|
|
1352
|
+
fhirPeer().complex([
|
|
1317
1353
|
prop("system", str("phone")),
|
|
1318
1354
|
prop("value", str(id.phone)),
|
|
1319
1355
|
prop("use", str("home"))
|
|
1320
1356
|
]),
|
|
1321
|
-
complex([prop("system", str("email")), prop("value", str(id.email))])
|
|
1357
|
+
fhirPeer().complex([prop("system", str("email")), prop("value", str(id.email))])
|
|
1322
1358
|
])
|
|
1323
1359
|
)
|
|
1324
1360
|
);
|
|
@@ -1327,10 +1363,10 @@ function generatePatient(options = {}) {
|
|
|
1327
1363
|
props.push(
|
|
1328
1364
|
prop(
|
|
1329
1365
|
"address",
|
|
1330
|
-
list([
|
|
1331
|
-
complex([
|
|
1366
|
+
fhirPeer().list([
|
|
1367
|
+
fhirPeer().complex([
|
|
1332
1368
|
prop("use", str("home")),
|
|
1333
|
-
prop("line", list([str(id.address.street)])),
|
|
1369
|
+
prop("line", fhirPeer().list([str(id.address.street)])),
|
|
1334
1370
|
prop("city", str(id.address.city)),
|
|
1335
1371
|
prop("state", str(id.address.state)),
|
|
1336
1372
|
prop("postalCode", str(id.address.zip))
|
|
@@ -1338,8 +1374,10 @@ function generatePatient(options = {}) {
|
|
|
1338
1374
|
])
|
|
1339
1375
|
)
|
|
1340
1376
|
);
|
|
1341
|
-
return complex(props);
|
|
1377
|
+
return fhirPeer().complex(props);
|
|
1342
1378
|
}
|
|
1379
|
+
|
|
1380
|
+
// src/fhir/condition.ts
|
|
1343
1381
|
function generateCondition(options = {}) {
|
|
1344
1382
|
const { seed = 0, subject = "Patient/syn-patient-1", usCore = true } = options;
|
|
1345
1383
|
const rng = createRng(seed);
|
|
@@ -1369,7 +1407,7 @@ function generateCondition(options = {}) {
|
|
|
1369
1407
|
props.push(
|
|
1370
1408
|
prop(
|
|
1371
1409
|
"category",
|
|
1372
|
-
list([
|
|
1410
|
+
fhirPeer().list([
|
|
1373
1411
|
codeableConcept({
|
|
1374
1412
|
system: SYSTEM.CONDITION_CATEGORY,
|
|
1375
1413
|
code: "problem-list-item",
|
|
@@ -1380,15 +1418,17 @@ function generateCondition(options = {}) {
|
|
|
1380
1418
|
);
|
|
1381
1419
|
props.push(prop("code", codeableConcept(code)));
|
|
1382
1420
|
props.push(prop("subject", reference(subject)));
|
|
1383
|
-
return complex(props);
|
|
1421
|
+
return fhirPeer().complex(props);
|
|
1384
1422
|
}
|
|
1423
|
+
|
|
1424
|
+
// src/fhir/observation.ts
|
|
1385
1425
|
function drawValue(rng, concept) {
|
|
1386
1426
|
const span = concept.high - concept.low;
|
|
1387
1427
|
const raw = concept.low + rng.float() * span;
|
|
1388
1428
|
return raw.toFixed(concept.decimals);
|
|
1389
1429
|
}
|
|
1390
1430
|
function valueQuantity(rng, concept) {
|
|
1391
|
-
return complex([
|
|
1431
|
+
return fhirPeer().complex([
|
|
1392
1432
|
prop("value", dec(drawValue(rng, concept))),
|
|
1393
1433
|
prop("unit", str(concept.unit)),
|
|
1394
1434
|
prop("system", str(SYSTEM.UCUM)),
|
|
@@ -1410,7 +1450,7 @@ function buildObservation(seed, subject, usCore, profileUrl, category, pool, eff
|
|
|
1410
1450
|
props.push(
|
|
1411
1451
|
prop(
|
|
1412
1452
|
"category",
|
|
1413
|
-
list([
|
|
1453
|
+
fhirPeer().list([
|
|
1414
1454
|
codeableConcept({
|
|
1415
1455
|
system: SYSTEM.OBSERVATION_CATEGORY,
|
|
1416
1456
|
code: category.code,
|
|
@@ -1426,7 +1466,7 @@ function buildObservation(seed, subject, usCore, profileUrl, category, pool, eff
|
|
|
1426
1466
|
const d = String(rng.int(1, 28)).padStart(2, "0");
|
|
1427
1467
|
if (effective) props.push(prop("effectiveDateTime", str(`${String(y)}-${m}-${d}`)));
|
|
1428
1468
|
props.push(prop("valueQuantity", valueQuantity(rng, concept)));
|
|
1429
|
-
return complex(props);
|
|
1469
|
+
return fhirPeer().complex(props);
|
|
1430
1470
|
}
|
|
1431
1471
|
function generateObservationLab(options = {}) {
|
|
1432
1472
|
const { seed = 0, subject = "Patient/syn-patient-1", usCore = true } = options;
|
|
@@ -1452,6 +1492,8 @@ function generateVitalSign(options = {}) {
|
|
|
1452
1492
|
true
|
|
1453
1493
|
);
|
|
1454
1494
|
}
|
|
1495
|
+
|
|
1496
|
+
// src/fhir/medication-request.ts
|
|
1455
1497
|
function generateMedicationRequest(options = {}) {
|
|
1456
1498
|
const {
|
|
1457
1499
|
seed = 0,
|
|
@@ -1476,8 +1518,10 @@ function generateMedicationRequest(options = {}) {
|
|
|
1476
1518
|
props.push(prop("subject", reference(subject)));
|
|
1477
1519
|
props.push(prop("authoredOn", str(`${String(y)}-${m}-${d}`)));
|
|
1478
1520
|
props.push(prop("requester", reference(requester)));
|
|
1479
|
-
return complex(props);
|
|
1521
|
+
return fhirPeer().complex(props);
|
|
1480
1522
|
}
|
|
1523
|
+
|
|
1524
|
+
// src/fhir/encounter.ts
|
|
1481
1525
|
function generateEncounter(options = {}) {
|
|
1482
1526
|
const { seed = 0, subject = "Patient/syn-patient-1", usCore = true } = options;
|
|
1483
1527
|
const rng = createRng(seed);
|
|
@@ -1494,8 +1538,8 @@ function generateEncounter(options = {}) {
|
|
|
1494
1538
|
props.push(
|
|
1495
1539
|
prop(
|
|
1496
1540
|
"identifier",
|
|
1497
|
-
list([
|
|
1498
|
-
complex([
|
|
1541
|
+
fhirPeer().list([
|
|
1542
|
+
fhirPeer().complex([
|
|
1499
1543
|
prop("system", str(`urn:oid:${id.assigningAuthorityOid}`)),
|
|
1500
1544
|
prop("value", str(id.value))
|
|
1501
1545
|
])
|
|
@@ -1504,11 +1548,13 @@ function generateEncounter(options = {}) {
|
|
|
1504
1548
|
);
|
|
1505
1549
|
props.push(prop("status", str("finished")));
|
|
1506
1550
|
props.push(prop("class", coding(cls)));
|
|
1507
|
-
props.push(prop("type", list([codeableConcept(type)])));
|
|
1551
|
+
props.push(prop("type", fhirPeer().list([codeableConcept(type)])));
|
|
1508
1552
|
props.push(prop("subject", reference(subject)));
|
|
1509
|
-
props.push(prop("period", complex([prop("start", str(`${start}T09:00:00Z`))])));
|
|
1510
|
-
return complex(props);
|
|
1553
|
+
props.push(prop("period", fhirPeer().complex([prop("start", str(`${start}T09:00:00Z`))])));
|
|
1554
|
+
return fhirPeer().complex(props);
|
|
1511
1555
|
}
|
|
1556
|
+
|
|
1557
|
+
// src/fhir/immunization.ts
|
|
1512
1558
|
function generateImmunization(options = {}) {
|
|
1513
1559
|
const { seed = 0, patient = "Patient/syn-patient-1", usCore = true } = options;
|
|
1514
1560
|
const rng = createRng(seed);
|
|
@@ -1525,8 +1571,10 @@ function generateImmunization(options = {}) {
|
|
|
1525
1571
|
props.push(prop("patient", reference(patient)));
|
|
1526
1572
|
props.push(prop("occurrenceDateTime", str(occurrence)));
|
|
1527
1573
|
props.push(prop("primarySource", bool(true)));
|
|
1528
|
-
return complex(props);
|
|
1574
|
+
return fhirPeer().complex(props);
|
|
1529
1575
|
}
|
|
1576
|
+
|
|
1577
|
+
// src/fhir/allergy-intolerance.ts
|
|
1530
1578
|
function generateAllergyIntolerance(options = {}) {
|
|
1531
1579
|
const { seed = 0, patient = "Patient/syn-patient-1", usCore = true } = options;
|
|
1532
1580
|
const rng = createRng(seed);
|
|
@@ -1559,11 +1607,17 @@ function generateAllergyIntolerance(options = {}) {
|
|
|
1559
1607
|
props.push(
|
|
1560
1608
|
prop(
|
|
1561
1609
|
"reaction",
|
|
1562
|
-
|
|
1610
|
+
fhirPeer().list([
|
|
1611
|
+
fhirPeer().complex([
|
|
1612
|
+
prop("manifestation", fhirPeer().list([codeableConcept(manifestation)]))
|
|
1613
|
+
])
|
|
1614
|
+
])
|
|
1563
1615
|
)
|
|
1564
1616
|
);
|
|
1565
|
-
return complex(props);
|
|
1617
|
+
return fhirPeer().complex(props);
|
|
1566
1618
|
}
|
|
1619
|
+
|
|
1620
|
+
// src/fhir/procedure.ts
|
|
1567
1621
|
function generateProcedure(options = {}) {
|
|
1568
1622
|
const { seed = 0, subject = "Patient/syn-patient-1", usCore = true } = options;
|
|
1569
1623
|
const rng = createRng(seed);
|
|
@@ -1579,8 +1633,10 @@ function generateProcedure(options = {}) {
|
|
|
1579
1633
|
props.push(prop("code", codeableConcept(code)));
|
|
1580
1634
|
props.push(prop("subject", reference(subject)));
|
|
1581
1635
|
props.push(prop("performedDateTime", str(`${performed}T10:00:00Z`)));
|
|
1582
|
-
return complex(props);
|
|
1636
|
+
return fhirPeer().complex(props);
|
|
1583
1637
|
}
|
|
1638
|
+
|
|
1639
|
+
// src/fhir/diagnostic-report.ts
|
|
1584
1640
|
function generateDiagnosticReport(options = {}) {
|
|
1585
1641
|
const { seed = 0, subject = "Patient/syn-patient-1", results = [], usCore = true } = options;
|
|
1586
1642
|
const rng = createRng(seed);
|
|
@@ -1596,7 +1652,7 @@ function generateDiagnosticReport(options = {}) {
|
|
|
1596
1652
|
props.push(
|
|
1597
1653
|
prop(
|
|
1598
1654
|
"category",
|
|
1599
|
-
list([
|
|
1655
|
+
fhirPeer().list([
|
|
1600
1656
|
codeableConcept({
|
|
1601
1657
|
system: SYSTEM.DIAGNOSTIC_SERVICE_SECTION,
|
|
1602
1658
|
code: "LAB",
|
|
@@ -1610,15 +1666,17 @@ function generateDiagnosticReport(options = {}) {
|
|
|
1610
1666
|
props.push(prop("effectiveDateTime", str(`${day}T08:30:00Z`)));
|
|
1611
1667
|
props.push(prop("issued", str(`${day}T09:00:00.000Z`)));
|
|
1612
1668
|
if (results.length > 0) {
|
|
1613
|
-
props.push(prop("result", list(results.map((r) => reference(r)))));
|
|
1669
|
+
props.push(prop("result", fhirPeer().list(results.map((r) => reference(r)))));
|
|
1614
1670
|
}
|
|
1615
|
-
return complex(props);
|
|
1671
|
+
return fhirPeer().complex(props);
|
|
1616
1672
|
}
|
|
1673
|
+
|
|
1674
|
+
// src/fhir/composition.ts
|
|
1617
1675
|
function section(sec) {
|
|
1618
|
-
return complex([
|
|
1676
|
+
return fhirPeer().complex([
|
|
1619
1677
|
prop("title", str(sec.title)),
|
|
1620
1678
|
prop("code", codeableConcept({ system: SYSTEM.LOINC, code: sec.code, display: sec.title })),
|
|
1621
|
-
prop("entry", list(sec.entries.map((e) => reference(e))))
|
|
1679
|
+
prop("entry", fhirPeer().list(sec.entries.map((e) => reference(e))))
|
|
1622
1680
|
]);
|
|
1623
1681
|
}
|
|
1624
1682
|
function buildComposition(rng, input) {
|
|
@@ -1637,12 +1695,12 @@ function buildComposition(rng, input) {
|
|
|
1637
1695
|
),
|
|
1638
1696
|
prop("subject", reference(input.subject)),
|
|
1639
1697
|
prop("date", str(`${input.date}T09:00:00Z`)),
|
|
1640
|
-
prop("author", list([reference(input.organization)])),
|
|
1698
|
+
prop("author", fhirPeer().list([reference(input.organization)])),
|
|
1641
1699
|
prop("title", str("Synthetic Continuity of Care Document")),
|
|
1642
1700
|
prop("custodian", reference(input.organization)),
|
|
1643
|
-
prop("section", list(input.sections.map((s) => section(s))))
|
|
1701
|
+
prop("section", fhirPeer().list(input.sections.map((s) => section(s))))
|
|
1644
1702
|
];
|
|
1645
|
-
return complex(props);
|
|
1703
|
+
return fhirPeer().complex(props);
|
|
1646
1704
|
}
|
|
1647
1705
|
|
|
1648
1706
|
// src/fhir/bundle.ts
|
|
@@ -1657,14 +1715,14 @@ function resourceTypeOf(resource) {
|
|
|
1657
1715
|
}
|
|
1658
1716
|
function buildOrganization(rng) {
|
|
1659
1717
|
const id = safe.identifier(rng, "AN");
|
|
1660
|
-
return complex([
|
|
1718
|
+
return fhirPeer().complex([
|
|
1661
1719
|
prop("resourceType", str("Organization")),
|
|
1662
1720
|
prop("id", str(`syn-org-${rng.digits(8)}`)),
|
|
1663
1721
|
prop("text", narrative("Synthetic health organization.")),
|
|
1664
1722
|
prop(
|
|
1665
1723
|
"identifier",
|
|
1666
|
-
list([
|
|
1667
|
-
complex([
|
|
1724
|
+
fhirPeer().list([
|
|
1725
|
+
fhirPeer().complex([
|
|
1668
1726
|
prop("system", str(`urn:oid:${id.assigningAuthorityOid}`)),
|
|
1669
1727
|
prop("value", str(id.value))
|
|
1670
1728
|
])
|
|
@@ -1777,11 +1835,14 @@ function generateBundle(options = {}) {
|
|
|
1777
1835
|
entryProps.push(
|
|
1778
1836
|
prop(
|
|
1779
1837
|
"request",
|
|
1780
|
-
complex([
|
|
1838
|
+
fhirPeer().complex([
|
|
1839
|
+
prop("method", str("POST")),
|
|
1840
|
+
prop("url", str(resourceTypeOf(member.resource)))
|
|
1841
|
+
])
|
|
1781
1842
|
)
|
|
1782
1843
|
);
|
|
1783
1844
|
}
|
|
1784
|
-
return complex(entryProps);
|
|
1845
|
+
return fhirPeer().complex(entryProps);
|
|
1785
1846
|
});
|
|
1786
1847
|
const props = [
|
|
1787
1848
|
prop("resourceType", str("Bundle")),
|
|
@@ -1792,7 +1853,7 @@ function generateBundle(options = {}) {
|
|
|
1792
1853
|
props.push(
|
|
1793
1854
|
prop(
|
|
1794
1855
|
"identifier",
|
|
1795
|
-
complex([
|
|
1856
|
+
fhirPeer().complex([
|
|
1796
1857
|
prop("system", str(`urn:oid:${id.assigningAuthorityOid}`)),
|
|
1797
1858
|
prop("value", str(`urn:uuid:${safe.uuid(rng)}`))
|
|
1798
1859
|
])
|
|
@@ -1801,11 +1862,13 @@ function generateBundle(options = {}) {
|
|
|
1801
1862
|
}
|
|
1802
1863
|
props.push(prop("type", str(type)));
|
|
1803
1864
|
if (type === "document") props.push(prop("timestamp", str(`${spine.date}T09:00:00.000Z`)));
|
|
1804
|
-
props.push(prop("entry", list(entries)));
|
|
1805
|
-
return complex(props);
|
|
1865
|
+
props.push(prop("entry", fhirPeer().list(entries)));
|
|
1866
|
+
return fhirPeer().complex(props);
|
|
1806
1867
|
}
|
|
1868
|
+
|
|
1869
|
+
// src/x12/money.ts
|
|
1807
1870
|
function dec2(value) {
|
|
1808
|
-
const d = X12Decimal.fromString(value);
|
|
1871
|
+
const d = x12Peer().X12Decimal.fromString(value);
|
|
1809
1872
|
if (d === void 0) throw new SynthError(SYNTH_FATAL_CODES.SYNTH_INVALID_DECIMAL);
|
|
1810
1873
|
return d;
|
|
1811
1874
|
}
|
|
@@ -2110,11 +2173,11 @@ function generate837(variant, options) {
|
|
|
2110
2173
|
const spec = specOf(rng, resolved);
|
|
2111
2174
|
switch (resolved) {
|
|
2112
2175
|
case "P":
|
|
2113
|
-
return build837P(spec);
|
|
2176
|
+
return x12Peer().build837P(spec);
|
|
2114
2177
|
case "I":
|
|
2115
|
-
return build837I(spec);
|
|
2178
|
+
return x12Peer().build837I(spec);
|
|
2116
2179
|
case "D":
|
|
2117
|
-
return build837D(spec);
|
|
2180
|
+
return x12Peer().build837D(spec);
|
|
2118
2181
|
}
|
|
2119
2182
|
}
|
|
2120
2183
|
function generate837P(options) {
|
|
@@ -2126,6 +2189,8 @@ function generate837I(options) {
|
|
|
2126
2189
|
function generate837D(options) {
|
|
2127
2190
|
return generate837("D", options);
|
|
2128
2191
|
}
|
|
2192
|
+
|
|
2193
|
+
// src/x12/remit-835.ts
|
|
2129
2194
|
function generate835(options) {
|
|
2130
2195
|
const rng = createRng(options.seed);
|
|
2131
2196
|
const partners = x12TradingPartners(rng);
|
|
@@ -2226,8 +2291,10 @@ function generate835(options) {
|
|
|
2226
2291
|
},
|
|
2227
2292
|
claims: [claim]
|
|
2228
2293
|
};
|
|
2229
|
-
return build835(spec);
|
|
2294
|
+
return x12Peer().build835(spec);
|
|
2230
2295
|
}
|
|
2296
|
+
|
|
2297
|
+
// src/x12/eligibility-271.ts
|
|
2231
2298
|
function generate271(options) {
|
|
2232
2299
|
const rng = createRng(options.seed);
|
|
2233
2300
|
const partners = x12TradingPartners(rng);
|
|
@@ -2307,7 +2374,7 @@ function generate271(options) {
|
|
|
2307
2374
|
}
|
|
2308
2375
|
]
|
|
2309
2376
|
};
|
|
2310
|
-
return build271(spec);
|
|
2377
|
+
return x12Peer().build271(spec);
|
|
2311
2378
|
}
|
|
2312
2379
|
|
|
2313
2380
|
// src/ncpdp/identity.ts
|
|
@@ -2363,6 +2430,8 @@ var EXAMPLE_DRUGS = Object.freeze(
|
|
|
2363
2430
|
].map((entry) => Object.freeze(entry))
|
|
2364
2431
|
);
|
|
2365
2432
|
var DAW_CODES = Object.freeze(["0", "1", "2"]);
|
|
2433
|
+
|
|
2434
|
+
// src/ncpdp/telecom.ts
|
|
2366
2435
|
var SYNTHETIC_BIN = "999999";
|
|
2367
2436
|
function digitsOnly(value) {
|
|
2368
2437
|
return value.replace(/\D/g, "");
|
|
@@ -2462,7 +2531,9 @@ function generateTelecom(code, options) {
|
|
|
2462
2531
|
prescriberSegment(rng),
|
|
2463
2532
|
claimSegment(rng, false)
|
|
2464
2533
|
];
|
|
2465
|
-
return serializeTelecom(
|
|
2534
|
+
return ncpdpTelecomPeer().serializeTelecom(
|
|
2535
|
+
ncpdpTelecomPeer().buildTelecomRequest({ header: head, segments })
|
|
2536
|
+
);
|
|
2466
2537
|
}
|
|
2467
2538
|
function generateB1(options) {
|
|
2468
2539
|
return generateTelecom("B1", options);
|
|
@@ -2473,6 +2544,18 @@ function generateB2(options) {
|
|
|
2473
2544
|
function generateB3(options) {
|
|
2474
2545
|
return generateTelecom("B3", options);
|
|
2475
2546
|
}
|
|
2547
|
+
|
|
2548
|
+
// src/ccda/example-codes.ts
|
|
2549
|
+
var LOINC_OID = "2.16.840.1.113883.6.1";
|
|
2550
|
+
var SNOMED_CT_OID = "2.16.840.1.113883.6.96";
|
|
2551
|
+
var RXNORM_OID = "2.16.840.1.113883.6.88";
|
|
2552
|
+
var CVX_OID = "2.16.840.1.113883.12.292";
|
|
2553
|
+
var NCI_ROUTE_OID = "2.16.840.1.113883.3.26.1.1";
|
|
2554
|
+
var LOINC = LOINC_OID;
|
|
2555
|
+
var SNOMED_CT = SNOMED_CT_OID;
|
|
2556
|
+
var RXNORM = RXNORM_OID;
|
|
2557
|
+
var CVX = CVX_OID;
|
|
2558
|
+
var NCI_ROUTE = NCI_ROUTE_OID;
|
|
2476
2559
|
var URI_TO_OID = Object.freeze({
|
|
2477
2560
|
"http://loinc.org": LOINC,
|
|
2478
2561
|
"http://snomed.info/sct": SNOMED_CT,
|
|
@@ -2626,16 +2709,18 @@ function generateCcda(options = {}) {
|
|
|
2626
2709
|
const { seed = 0 } = options;
|
|
2627
2710
|
const documentType = resolveKind(CCDA_DOCUMENT_TYPES, options.documentType ?? "ccd");
|
|
2628
2711
|
const rng = createRng(seed);
|
|
2629
|
-
return buildCcda(buildInit(rng, documentType));
|
|
2712
|
+
return ccdaPeer().buildCcda(buildInit(rng, documentType));
|
|
2630
2713
|
}
|
|
2714
|
+
|
|
2715
|
+
// src/deid/loop.ts
|
|
2631
2716
|
var DEID_LOOP_POLICY_NAME = "synth-deid-loop-removal";
|
|
2632
2717
|
function deidLoopPolicy() {
|
|
2633
|
-
return defineDeidPolicy({
|
|
2718
|
+
return deidPeer().defineDeidPolicy({
|
|
2634
2719
|
name: DEID_LOOP_POLICY_NAME,
|
|
2635
2720
|
transforms: {
|
|
2636
|
-
[SAFE_HARBOR_CATEGORIES.MRN]: "redact",
|
|
2637
|
-
[SAFE_HARBOR_CATEGORIES.HEALTH_PLAN_BENEFICIARY]: "redact",
|
|
2638
|
-
[SAFE_HARBOR_CATEGORIES.ACCOUNT]: "redact"
|
|
2721
|
+
[deidPeer().SAFE_HARBOR_CATEGORIES.MRN]: "redact",
|
|
2722
|
+
[deidPeer().SAFE_HARBOR_CATEGORIES.HEALTH_PLAN_BENEFICIARY]: "redact",
|
|
2723
|
+
[deidPeer().SAFE_HARBOR_CATEGORIES.ACCOUNT]: "redact"
|
|
2639
2724
|
}
|
|
2640
2725
|
});
|
|
2641
2726
|
}
|
|
@@ -2772,7 +2857,8 @@ var DEID_LOOP_SKIPPED = Object.freeze([
|
|
|
2772
2857
|
reason: "@cosyte/synth does not generate DICOM, so there is nothing to pair."
|
|
2773
2858
|
})
|
|
2774
2859
|
]);
|
|
2775
|
-
var
|
|
2860
|
+
var policy;
|
|
2861
|
+
var loopPolicy = () => policy ??= deidLoopPolicy();
|
|
2776
2862
|
function residue(loci) {
|
|
2777
2863
|
return loci.map((l) => l.value).join("\n");
|
|
2778
2864
|
}
|
|
@@ -2797,8 +2883,8 @@ function hl7DeidLoop(options = {}) {
|
|
|
2797
2883
|
const kind = options.kind ?? "ORU^R01";
|
|
2798
2884
|
const message = generateHl7(kind, seed);
|
|
2799
2885
|
const original = message.toString();
|
|
2800
|
-
const planted = identifierSentinels(extractHl7Loci(message).loci, original);
|
|
2801
|
-
const deidDoc = deidentifyHl7(message, { policy:
|
|
2886
|
+
const planted = identifierSentinels(deidHl7Peer().extractHl7Loci(message).loci, original);
|
|
2887
|
+
const deidDoc = deidHl7Peer().deidentifyHl7(message, { policy: loopPolicy() }).document;
|
|
2802
2888
|
const deidentified = deidDoc.toString();
|
|
2803
2889
|
return assembleVerdict({
|
|
2804
2890
|
format: "hl7",
|
|
@@ -2807,17 +2893,17 @@ function hl7DeidLoop(options = {}) {
|
|
|
2807
2893
|
planted,
|
|
2808
2894
|
original,
|
|
2809
2895
|
deidentified,
|
|
2810
|
-
phiResidue: residue(extractHl7Loci(deidDoc).loci),
|
|
2896
|
+
phiResidue: residue(deidHl7Peer().extractHl7Loci(deidDoc).loci),
|
|
2811
2897
|
clinicalCodes: HL7_CLINICAL
|
|
2812
2898
|
});
|
|
2813
2899
|
}
|
|
2814
2900
|
function fhirDeidLoop(options = {}) {
|
|
2815
2901
|
const seed = options.seed ?? 0;
|
|
2816
2902
|
const bundle = generateBundle({ seed });
|
|
2817
|
-
const original = serializeResource(bundle);
|
|
2818
|
-
const planted = identifierSentinels(extractFhirLoci(bundle).loci, original);
|
|
2819
|
-
const deidDoc = deidentifyFhir(bundle, { policy:
|
|
2820
|
-
const deidentified = serializeResource(deidDoc);
|
|
2903
|
+
const original = fhirPeer().serializeResource(bundle);
|
|
2904
|
+
const planted = identifierSentinels(deidFhirPeer().extractFhirLoci(bundle).loci, original);
|
|
2905
|
+
const deidDoc = deidFhirPeer().deidentifyFhir(bundle, { policy: loopPolicy() }).document;
|
|
2906
|
+
const deidentified = fhirPeer().serializeResource(deidDoc);
|
|
2821
2907
|
return assembleVerdict({
|
|
2822
2908
|
format: "fhir",
|
|
2823
2909
|
artifact: "Bundle",
|
|
@@ -2825,7 +2911,7 @@ function fhirDeidLoop(options = {}) {
|
|
|
2825
2911
|
planted,
|
|
2826
2912
|
original,
|
|
2827
2913
|
deidentified,
|
|
2828
|
-
phiResidue: residue(extractFhirLoci(deidDoc).loci),
|
|
2914
|
+
phiResidue: residue(deidFhirPeer().extractFhirLoci(deidDoc).loci),
|
|
2829
2915
|
clinicalCodes: FHIR_CLINICAL
|
|
2830
2916
|
});
|
|
2831
2917
|
}
|
|
@@ -2847,9 +2933,9 @@ function x12DeidLoop(options = {}) {
|
|
|
2847
2933
|
const seed = options.seed ?? 0;
|
|
2848
2934
|
const variant = options.variant ?? "837P";
|
|
2849
2935
|
const interchange = generateX12(variant, seed);
|
|
2850
|
-
const original = serializeX12(interchange);
|
|
2851
|
-
const planted = identifierSentinels(extractX12Loci(interchange).loci, original);
|
|
2852
|
-
const deidentified = deidentifyX12(interchange, { policy:
|
|
2936
|
+
const original = x12Peer().serializeX12(interchange);
|
|
2937
|
+
const planted = identifierSentinels(deidX12Peer().extractX12Loci(interchange).loci, original);
|
|
2938
|
+
const deidentified = deidX12Peer().deidentifyX12(interchange, { policy: loopPolicy() }).x12;
|
|
2853
2939
|
return assembleVerdict({
|
|
2854
2940
|
format: "x12",
|
|
2855
2941
|
artifact: variant,
|
|
@@ -2857,7 +2943,7 @@ function x12DeidLoop(options = {}) {
|
|
|
2857
2943
|
planted,
|
|
2858
2944
|
original,
|
|
2859
2945
|
deidentified,
|
|
2860
|
-
phiResidue: residue(extractX12Loci(parseX12(deidentified)).loci),
|
|
2946
|
+
phiResidue: residue(deidX12Peer().extractX12Loci(x12Peer().parseX12(deidentified)).loci),
|
|
2861
2947
|
clinicalCodes: X12_CLINICAL
|
|
2862
2948
|
});
|
|
2863
2949
|
}
|
|
@@ -2875,9 +2961,9 @@ function ncpdpTelecomDeidLoop(options = {}) {
|
|
|
2875
2961
|
const seed = options.seed ?? 0;
|
|
2876
2962
|
const transaction = options.transaction ?? "B1";
|
|
2877
2963
|
const original = generateTelecomWire(transaction, seed);
|
|
2878
|
-
const tx = parseTelecom(original);
|
|
2879
|
-
const planted = identifierSentinels(extractTelecomLoci(tx).loci, original);
|
|
2880
|
-
const deidentified = deidentifyTelecom(tx, { policy:
|
|
2964
|
+
const tx = ncpdpTelecomPeer().parseTelecom(original);
|
|
2965
|
+
const planted = identifierSentinels(deidNcpdpPeer().extractTelecomLoci(tx).loci, original);
|
|
2966
|
+
const deidentified = deidNcpdpPeer().deidentifyTelecom(tx, { policy: loopPolicy() }).telecom;
|
|
2881
2967
|
return assembleVerdict({
|
|
2882
2968
|
format: "ncpdp-telecom",
|
|
2883
2969
|
artifact: transaction,
|
|
@@ -2885,7 +2971,9 @@ function ncpdpTelecomDeidLoop(options = {}) {
|
|
|
2885
2971
|
planted,
|
|
2886
2972
|
original,
|
|
2887
2973
|
deidentified,
|
|
2888
|
-
phiResidue: residue(
|
|
2974
|
+
phiResidue: residue(
|
|
2975
|
+
deidNcpdpPeer().extractTelecomLoci(ncpdpTelecomPeer().parseTelecom(deidentified)).loci
|
|
2976
|
+
),
|
|
2889
2977
|
clinicalCodes: NCPDP_CLINICAL
|
|
2890
2978
|
});
|
|
2891
2979
|
}
|
|
@@ -2893,9 +2981,9 @@ function ccdaDeidLoop(options = {}) {
|
|
|
2893
2981
|
const seed = options.seed ?? 0;
|
|
2894
2982
|
const documentType = options.documentType ?? "ccd";
|
|
2895
2983
|
const doc = generateCcda({ seed, documentType: documentType === "ccd" ? "ccd" : "referralNote" });
|
|
2896
|
-
const original = serializeCcda(doc);
|
|
2984
|
+
const original = ccdaPeer().serializeCcda(doc);
|
|
2897
2985
|
const planted = recordTargetSentinels(original);
|
|
2898
|
-
const deidentified = deidentifyCcda(doc, { policy:
|
|
2986
|
+
const deidentified = deidCcdaPeer().deidentifyCcda(doc, { policy: loopPolicy() }).document.toString();
|
|
2899
2987
|
return assembleVerdict({
|
|
2900
2988
|
format: "ccda",
|
|
2901
2989
|
artifact: documentType === "ccd" ? "CCD" : "ReferralNote",
|
|
@@ -2910,9 +2998,9 @@ function ccdaDeidLoop(options = {}) {
|
|
|
2910
2998
|
function summarizeDeidCoverage(results) {
|
|
2911
2999
|
const byFormatMap = /* @__PURE__ */ new Map();
|
|
2912
3000
|
for (const r of results) {
|
|
2913
|
-
const
|
|
2914
|
-
|
|
2915
|
-
byFormatMap.set(r.format,
|
|
3001
|
+
const list = byFormatMap.get(r.format) ?? [];
|
|
3002
|
+
list.push(r);
|
|
3003
|
+
byFormatMap.set(r.format, list);
|
|
2916
3004
|
}
|
|
2917
3005
|
const byFormat = [];
|
|
2918
3006
|
for (const [format, runs] of byFormatMap) {
|