@cosyte/synth 0.1.5 → 0.1.7
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 +30 -0
- package/dist/astm/index.cjs +57 -19
- 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 +56 -19
- 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 +216 -125
- package/dist/deid/index.cjs.map +1 -1
- package/dist/deid/index.mjs +203 -113
- 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 +76 -23
- 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 +75 -23
- package/dist/ncpdp/index.mjs.map +1 -1
- package/dist/x12/index.cjs +72 -23
- package/dist/x12/index.cjs.map +1 -1
- package/dist/x12/index.d.cts +8 -1
- package/dist/x12/index.d.ts +8 -1
- package/dist/x12/index.mjs +71 -23
- package/dist/x12/index.mjs.map +1 -1
- package/package.json +20 -15
package/dist/ncpdp/index.d.cts
CHANGED
|
@@ -158,6 +158,7 @@ declare function generateB3(options: GenerateTelecomOptions): string;
|
|
|
158
158
|
*
|
|
159
159
|
* @module
|
|
160
160
|
*/
|
|
161
|
+
|
|
161
162
|
/** The verdict of one round-trip through `@cosyte/ncpdp`. */
|
|
162
163
|
interface RoundTripResult {
|
|
163
164
|
/** The serialized NCPDP wire text (the serializer's own conservative emit). */
|
|
@@ -412,6 +413,12 @@ interface NcpdpCorpusOptions {
|
|
|
412
413
|
readonly count?: number;
|
|
413
414
|
/** The transaction kinds to cycle through. Defaults to one of each. */
|
|
414
415
|
readonly mix?: readonly NcpdpCorpusKind[];
|
|
416
|
+
/**
|
|
417
|
+
* Whether each artifact is read back through its parser and the parser's findings recorded as its
|
|
418
|
+
* `warnings`. Defaults to `true`. `false` skips the read, a large share of a corpus's time; every
|
|
419
|
+
* artifact's `warnings` is then empty without having been checked.
|
|
420
|
+
*/
|
|
421
|
+
readonly verify?: boolean;
|
|
415
422
|
}
|
|
416
423
|
/**
|
|
417
424
|
* Build a reproducible {@link Corpus} of spec-clean NCPDP transactions. Each transaction is generated
|
package/dist/ncpdp/index.d.ts
CHANGED
|
@@ -158,6 +158,7 @@ declare function generateB3(options: GenerateTelecomOptions): string;
|
|
|
158
158
|
*
|
|
159
159
|
* @module
|
|
160
160
|
*/
|
|
161
|
+
|
|
161
162
|
/** The verdict of one round-trip through `@cosyte/ncpdp`. */
|
|
162
163
|
interface RoundTripResult {
|
|
163
164
|
/** The serialized NCPDP wire text (the serializer's own conservative emit). */
|
|
@@ -412,6 +413,12 @@ interface NcpdpCorpusOptions {
|
|
|
412
413
|
readonly count?: number;
|
|
413
414
|
/** The transaction kinds to cycle through. Defaults to one of each. */
|
|
414
415
|
readonly mix?: readonly NcpdpCorpusKind[];
|
|
416
|
+
/**
|
|
417
|
+
* Whether each artifact is read back through its parser and the parser's findings recorded as its
|
|
418
|
+
* `warnings`. Defaults to `true`. `false` skips the read, a large share of a corpus's time; every
|
|
419
|
+
* artifact's `warnings` is then empty without having been checked.
|
|
420
|
+
*/
|
|
421
|
+
readonly verify?: boolean;
|
|
415
422
|
}
|
|
416
423
|
/**
|
|
417
424
|
* Build a reproducible {@link Corpus} of spec-clean NCPDP transactions. Each transaction is generated
|
package/dist/ncpdp/index.mjs
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
|
|
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
|
+
});
|
|
4
10
|
|
|
5
11
|
// src/rng/splitmix32.ts
|
|
6
12
|
function splitmix32(seed) {
|
|
@@ -150,6 +156,7 @@ function createRng(seed) {
|
|
|
150
156
|
}
|
|
151
157
|
|
|
152
158
|
// src/corpus.ts
|
|
159
|
+
var UNCHECKED = Object.freeze([]);
|
|
153
160
|
function makeCorpus(seed, artifacts, quirks = []) {
|
|
154
161
|
const counts = {};
|
|
155
162
|
const formats = /* @__PURE__ */ new Set();
|
|
@@ -528,6 +535,30 @@ var EXAMPLE_SIG_TEXT = Object.freeze([
|
|
|
528
535
|
"Inhale 2 puffs by mouth every 4 to 6 hours as needed"
|
|
529
536
|
]);
|
|
530
537
|
var DAW_CODES = Object.freeze(["0", "1", "2"]);
|
|
538
|
+
function defaultHost() {
|
|
539
|
+
if (typeof import.meta.resolve !== "function") return { require: __require, resolve: void 0 };
|
|
540
|
+
return { require: createRequire(import.meta.url), resolve: (s) => import.meta.resolve(s) };
|
|
541
|
+
}
|
|
542
|
+
function isRequireEsmRefusal(error) {
|
|
543
|
+
return error?.code === "ERR_REQUIRE_ESM";
|
|
544
|
+
}
|
|
545
|
+
function loadPeer(specifier, host) {
|
|
546
|
+
if (host.resolve === void 0) return host.require(specifier);
|
|
547
|
+
const entry = fileURLToPath(host.resolve(specifier));
|
|
548
|
+
try {
|
|
549
|
+
return host.require(entry);
|
|
550
|
+
} catch (error) {
|
|
551
|
+
if (!isRequireEsmRefusal(error)) throw error;
|
|
552
|
+
return host.require(specifier);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
function lazyPeer(specifier, host) {
|
|
556
|
+
let loaded;
|
|
557
|
+
return () => loaded ??= loadPeer(specifier, defaultHost());
|
|
558
|
+
}
|
|
559
|
+
var ncpdpScriptPeer = lazyPeer("@cosyte/ncpdp/script");
|
|
560
|
+
var ncpdpTelecomPeer = lazyPeer("@cosyte/ncpdp/telecom");
|
|
561
|
+
var ncpdpCommonPeer = lazyPeer("@cosyte/ncpdp/common");
|
|
531
562
|
|
|
532
563
|
// src/ncpdp/script.ts
|
|
533
564
|
var SCRIPT_VERSION = "2017071";
|
|
@@ -558,13 +589,13 @@ function medicationModel(rng, routing) {
|
|
|
558
589
|
const written = `${routing.date.slice(0, 4)}-${routing.date.slice(4, 6)}-${routing.date.slice(6, 8)}`;
|
|
559
590
|
return {
|
|
560
591
|
description: drug.description,
|
|
561
|
-
coded: { productCode: codedValue(drug.ndc, "ND") },
|
|
592
|
+
coded: { productCode: ncpdpCommonPeer().codedValue(drug.ndc, "ND") },
|
|
562
593
|
quantity: {
|
|
563
|
-
value: decimalValue(String(rng.int(30, 90))),
|
|
594
|
+
value: ncpdpCommonPeer().decimalValue(String(rng.int(30, 90))),
|
|
564
595
|
unitOfMeasure: drug.form,
|
|
565
596
|
codeListQualifier: "38"
|
|
566
597
|
},
|
|
567
|
-
daysSupply: decimalValue(String(rng.pick([30, 60, 90]))),
|
|
598
|
+
daysSupply: ncpdpCommonPeer().decimalValue(String(rng.pick([30, 60, 90]))),
|
|
568
599
|
numberOfRefills: String(rng.int(0, 5)),
|
|
569
600
|
substitutions: rng.pick(["0", "1"]),
|
|
570
601
|
writtenDate: written,
|
|
@@ -588,14 +619,14 @@ function generateNewRx(options) {
|
|
|
588
619
|
const pharmacy = pharmacyModel(rng);
|
|
589
620
|
const prescriber = prescriberModel(rng);
|
|
590
621
|
const medication = medicationModel(rng, routing);
|
|
591
|
-
const message = buildNewRx({
|
|
622
|
+
const message = ncpdpScriptPeer().buildNewRx({
|
|
592
623
|
header: headerModel(routing),
|
|
593
624
|
patient,
|
|
594
625
|
pharmacy,
|
|
595
626
|
prescriber,
|
|
596
627
|
medication
|
|
597
628
|
});
|
|
598
|
-
return serializeScript(message);
|
|
629
|
+
return ncpdpScriptPeer().serializeScript(message);
|
|
599
630
|
}
|
|
600
631
|
function lifecycleFields(rng) {
|
|
601
632
|
const routing = ncpdpScriptRouting(rng);
|
|
@@ -612,14 +643,20 @@ function generateRxRenewalRequest(options) {
|
|
|
612
643
|
const rng = createRng(options.seed);
|
|
613
644
|
const { header: header2, ...fields } = lifecycleFields(rng);
|
|
614
645
|
const body = { kind: "RxRenewalRequest", ...fields };
|
|
615
|
-
return serializeScript(
|
|
646
|
+
return ncpdpScriptPeer().serializeScript(
|
|
647
|
+
new (ncpdpScriptPeer()).ScriptMessage({ header: header2, body, warnings: [] })
|
|
648
|
+
);
|
|
616
649
|
}
|
|
617
650
|
function generateRxChangeRequest(options) {
|
|
618
651
|
const rng = createRng(options.seed);
|
|
619
652
|
const { header: header2, ...fields } = lifecycleFields(rng);
|
|
620
653
|
const body = { kind: "RxChangeRequest", ...fields };
|
|
621
|
-
return serializeScript(
|
|
654
|
+
return ncpdpScriptPeer().serializeScript(
|
|
655
|
+
new (ncpdpScriptPeer()).ScriptMessage({ header: header2, body, warnings: [] })
|
|
656
|
+
);
|
|
622
657
|
}
|
|
658
|
+
|
|
659
|
+
// src/ncpdp/telecom.ts
|
|
623
660
|
var SYNTHETIC_BIN = "999999";
|
|
624
661
|
function digitsOnly(value) {
|
|
625
662
|
return value.replace(/\D/g, "");
|
|
@@ -703,7 +740,8 @@ function claimSegment(rng, minimal) {
|
|
|
703
740
|
field("E1", "03"),
|
|
704
741
|
// 03 = NDC
|
|
705
742
|
field("D7", drug.ndc),
|
|
706
|
-
field("E7", String(rng.int(30, 90))),
|
|
743
|
+
field("E7", String(rng.int(30, 90) * 1e3)),
|
|
744
|
+
// 442-E7 carries three implied decimals
|
|
707
745
|
field("D5", String(rng.pick([30, 60, 90]))),
|
|
708
746
|
field("D8", rng.pick(DAW_CODES))
|
|
709
747
|
]
|
|
@@ -719,7 +757,9 @@ function generateTelecom(code, options) {
|
|
|
719
757
|
prescriberSegment(rng),
|
|
720
758
|
claimSegment(rng, false)
|
|
721
759
|
];
|
|
722
|
-
return serializeTelecom(
|
|
760
|
+
return ncpdpTelecomPeer().serializeTelecom(
|
|
761
|
+
ncpdpTelecomPeer().buildTelecomRequest({ header: head, segments })
|
|
762
|
+
);
|
|
723
763
|
}
|
|
724
764
|
function generateB1(options) {
|
|
725
765
|
return generateTelecom("B1", options);
|
|
@@ -730,18 +770,30 @@ function generateB2(options) {
|
|
|
730
770
|
function generateB3(options) {
|
|
731
771
|
return generateTelecom("B3", options);
|
|
732
772
|
}
|
|
773
|
+
|
|
774
|
+
// src/ncpdp/round-trip.ts
|
|
733
775
|
function scriptRoundTrip(xml) {
|
|
734
|
-
const message = parseScript(xml);
|
|
776
|
+
const message = ncpdpScriptPeer().parseScript(xml);
|
|
735
777
|
const warnings = message.warnings.map((w) => String(w.code));
|
|
736
|
-
const byteStable = serializeScript(message) === xml;
|
|
778
|
+
const byteStable = ncpdpScriptPeer().serializeScript(message) === xml;
|
|
737
779
|
return { content: xml, warnings, byteStable, specClean: warnings.length === 0 && byteStable };
|
|
738
780
|
}
|
|
739
781
|
function telecomRoundTrip(wire) {
|
|
740
|
-
const transaction = parseTelecom(wire);
|
|
782
|
+
const transaction = ncpdpTelecomPeer().parseTelecom(wire);
|
|
741
783
|
const warnings = transaction.warnings.map((w) => String(w.code));
|
|
742
|
-
const byteStable = serializeTelecom(transaction) === wire;
|
|
784
|
+
const byteStable = ncpdpTelecomPeer().serializeTelecom(transaction) === wire;
|
|
743
785
|
return { content: wire, warnings, byteStable, specClean: warnings.length === 0 && byteStable };
|
|
744
786
|
}
|
|
787
|
+
function scriptCorpusArtifact(xml, verify) {
|
|
788
|
+
if (!verify) return { content: xml, warnings: UNCHECKED };
|
|
789
|
+
const warnings = ncpdpScriptPeer().parseScript(xml).warnings.map((w) => String(w.code));
|
|
790
|
+
return { content: xml, warnings };
|
|
791
|
+
}
|
|
792
|
+
function telecomCorpusArtifact(wire, verify) {
|
|
793
|
+
if (!verify) return { content: wire, warnings: UNCHECKED };
|
|
794
|
+
const warnings = ncpdpTelecomPeer().parseTelecom(wire).warnings.map((w) => String(w.code));
|
|
795
|
+
return { content: wire, warnings };
|
|
796
|
+
}
|
|
745
797
|
|
|
746
798
|
// src/select.ts
|
|
747
799
|
function resolveKind(allowed, requested) {
|
|
@@ -764,29 +816,29 @@ var ALL_KINDS = Object.freeze([
|
|
|
764
816
|
"B3"
|
|
765
817
|
]);
|
|
766
818
|
var DEFAULT_MIX = ALL_KINDS;
|
|
767
|
-
function generateKind(kind, seed) {
|
|
819
|
+
function generateKind(kind, seed, verify) {
|
|
768
820
|
switch (kind) {
|
|
769
821
|
case "NewRx":
|
|
770
|
-
return
|
|
822
|
+
return scriptCorpusArtifact(generateNewRx({ seed }), verify);
|
|
771
823
|
case "RxRenewalRequest":
|
|
772
|
-
return
|
|
824
|
+
return scriptCorpusArtifact(generateRxRenewalRequest({ seed }), verify);
|
|
773
825
|
case "RxChangeRequest":
|
|
774
|
-
return
|
|
826
|
+
return scriptCorpusArtifact(generateRxChangeRequest({ seed }), verify);
|
|
775
827
|
case "B1":
|
|
776
828
|
case "B2":
|
|
777
829
|
case "B3":
|
|
778
|
-
return
|
|
830
|
+
return telecomCorpusArtifact(generateTelecom(kind, { seed }), verify);
|
|
779
831
|
}
|
|
780
832
|
}
|
|
781
833
|
function ncpdpCorpus(options) {
|
|
782
|
-
const { seed } = options;
|
|
834
|
+
const { seed, verify = true } = options;
|
|
783
835
|
const mix = resolveMix(ALL_KINDS, options.mix, DEFAULT_MIX);
|
|
784
836
|
const count = options.count ?? mix.length;
|
|
785
837
|
const seedStream = createRng(seed);
|
|
786
838
|
const artifacts = Array.from({ length: count }, (_unused, i) => {
|
|
787
839
|
const kind = mix[i % mix.length] ?? "NewRx";
|
|
788
840
|
const txSeed = seedStream.nextUint32();
|
|
789
|
-
const rt = generateKind(kind, txSeed);
|
|
841
|
+
const rt = generateKind(kind, txSeed, verify);
|
|
790
842
|
return {
|
|
791
843
|
format: "ncpdp",
|
|
792
844
|
kind,
|