@cosyte/synth 0.1.4 → 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 +24 -0
- package/README.md +14 -10
- package/dist/astm/index.cjs +164 -102
- 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 +163 -102
- package/dist/astm/index.mjs.map +1 -1
- package/dist/ccda/index.cjs +100 -28
- 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 +87 -16
- package/dist/ccda/index.mjs.map +1 -1
- package/dist/deid/index.cjs +305 -165
- package/dist/deid/index.cjs.map +1 -1
- package/dist/deid/index.mjs +292 -153
- package/dist/deid/index.mjs.map +1 -1
- package/dist/fhir/index.cjs +179 -76
- 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 +178 -76
- package/dist/fhir/index.mjs.map +1 -1
- package/dist/hl7/index.cjs +86 -12
- 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 +85 -12
- package/dist/hl7/index.mjs.map +1 -1
- package/dist/index.cjs +3 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.mjs +3 -5
- package/dist/index.mjs.map +1 -1
- package/dist/ncpdp/index.cjs +131 -36
- 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 +130 -36
- package/dist/ncpdp/index.mjs.map +1 -1
- package/dist/x12/index.cjs +147 -50
- 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 +146 -50
- package/dist/x12/index.mjs.map +1 -1
- package/package.json +20 -15
package/dist/ccda/index.cjs
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var module$1 = require('module');
|
|
4
|
+
var url = require('url');
|
|
5
|
+
|
|
6
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
7
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
8
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
9
|
+
}) : x)(function(x) {
|
|
10
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
11
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
12
|
+
});
|
|
4
13
|
|
|
5
14
|
// src/rng/splitmix32.ts
|
|
6
15
|
function splitmix32(seed) {
|
|
@@ -32,7 +41,16 @@ function sfc32Next(s) {
|
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
// src/codes.ts
|
|
35
|
-
var SYNTH_FATAL_CODES = {
|
|
44
|
+
var SYNTH_FATAL_CODES = Object.freeze({
|
|
45
|
+
/**
|
|
46
|
+
* A format was requested that this build cannot generate through a real parser builder/serializer.
|
|
47
|
+
* Fatal, never a hand-written byte fallback.
|
|
48
|
+
*
|
|
49
|
+
* **No code path in this build raises it.** All six formats generate, so it is reserved for a
|
|
50
|
+
* future format that does not, and is kept because removing a published code is a breaking change.
|
|
51
|
+
* An unsupported *kind* within a format that does generate is `SYNTH_UNSUPPORTED_KIND`.
|
|
52
|
+
*/
|
|
53
|
+
SYNTH_UNSUPPORTED_FORMAT: "SYNTH_UNSUPPORTED_FORMAT",
|
|
36
54
|
/**
|
|
37
55
|
* A vendor quirk was requested that the target format's profile system does not support. Fatal,
|
|
38
56
|
* never a silent no-op and never a fabricated quirk.
|
|
@@ -51,6 +69,8 @@ var SYNTH_FATAL_CODES = {
|
|
|
51
69
|
SYNTH_INTENDED_WARNING_MISMATCH: "SYNTH_INTENDED_WARNING_MISMATCH",
|
|
52
70
|
/** A concept's code-system URI has no OID mapping in the C-CDA example-code table. Fatal. */
|
|
53
71
|
SYNTH_UNMAPPED_CODE_SYSTEM: "SYNTH_UNMAPPED_CODE_SYSTEM",
|
|
72
|
+
/** A money value could not be read as an X12 decimal. Fatal: a generator never rounds to a float. */
|
|
73
|
+
SYNTH_INVALID_DECIMAL: "SYNTH_INVALID_DECIMAL",
|
|
54
74
|
/** An integer range was requested with its maximum below its minimum. Fatal. */
|
|
55
75
|
SYNTH_INVALID_RANGE: "SYNTH_INVALID_RANGE",
|
|
56
76
|
/** A value was drawn from an empty pool. Fatal, never a fabricated substitute. */
|
|
@@ -63,7 +83,17 @@ var SYNTH_FATAL_CODES = {
|
|
|
63
83
|
* see `resolveKind`: a selector union is erased at run time, and a selector that falls through
|
|
64
84
|
* either mislabels the fixture or hands the value to a peer builder that quotes it back.
|
|
65
85
|
*/
|
|
66
|
-
SYNTH_UNSUPPORTED_KIND: "SYNTH_UNSUPPORTED_KIND"
|
|
86
|
+
SYNTH_UNSUPPORTED_KIND: "SYNTH_UNSUPPORTED_KIND",
|
|
87
|
+
/**
|
|
88
|
+
* A requested profile IS published by the adopted implementation guide, and this build does not
|
|
89
|
+
* generate it. Deliberately distinct from `SYNTH_UNSUPPORTED_KIND`, which says the name is not in
|
|
90
|
+
* the adopted set at all: "the guide does not publish this" and "we do not generate this yet" are
|
|
91
|
+
* different answers, and a caller building to a regulatory profile set has to be able to tell them
|
|
92
|
+
* apart without matching message text. Fatal, and raised **before** anything is generated: a
|
|
93
|
+
* mislabelled artifact is worse than no artifact.
|
|
94
|
+
*/
|
|
95
|
+
SYNTH_PROFILE_NOT_GENERATED: "SYNTH_PROFILE_NOT_GENERATED"
|
|
96
|
+
});
|
|
67
97
|
var SYNTH_FATAL_MESSAGES = Object.freeze({
|
|
68
98
|
SYNTH_UNSUPPORTED_FORMAT: "The requested format is not generable by this build. A generator has no byte fallback: it builds through a parser's own serializer or it refuses.",
|
|
69
99
|
SYNTH_UNSUPPORTED_QUIRK: "The requested vendor quirk is not in the target format's quirk registry. Compare the request against that format's exported registry (HL7_QUIRKS, CCDA_QUIRKS, ASTM_QUIRKS).",
|
|
@@ -129,6 +159,7 @@ function createRng(seed) {
|
|
|
129
159
|
}
|
|
130
160
|
|
|
131
161
|
// src/corpus.ts
|
|
162
|
+
var UNCHECKED = Object.freeze([]);
|
|
132
163
|
function makeCorpus(seed, artifacts, quirks = []) {
|
|
133
164
|
const counts = {};
|
|
134
165
|
const formats = /* @__PURE__ */ new Set();
|
|
@@ -739,11 +770,21 @@ Object.freeze([
|
|
|
739
770
|
]);
|
|
740
771
|
|
|
741
772
|
// src/ccda/example-codes.ts
|
|
773
|
+
var LOINC_OID = "2.16.840.1.113883.6.1";
|
|
774
|
+
var SNOMED_CT_OID = "2.16.840.1.113883.6.96";
|
|
775
|
+
var RXNORM_OID = "2.16.840.1.113883.6.88";
|
|
776
|
+
var CVX_OID = "2.16.840.1.113883.12.292";
|
|
777
|
+
var NCI_ROUTE_OID = "2.16.840.1.113883.3.26.1.1";
|
|
778
|
+
var LOINC = LOINC_OID;
|
|
779
|
+
var SNOMED_CT = SNOMED_CT_OID;
|
|
780
|
+
var RXNORM = RXNORM_OID;
|
|
781
|
+
var CVX = CVX_OID;
|
|
782
|
+
var NCI_ROUTE = NCI_ROUTE_OID;
|
|
742
783
|
var URI_TO_OID = Object.freeze({
|
|
743
|
-
"http://loinc.org":
|
|
744
|
-
"http://snomed.info/sct":
|
|
745
|
-
"http://www.nlm.nih.gov/research/umls/rxnorm":
|
|
746
|
-
"http://hl7.org/fhir/sid/cvx":
|
|
784
|
+
"http://loinc.org": LOINC,
|
|
785
|
+
"http://snomed.info/sct": SNOMED_CT,
|
|
786
|
+
"http://www.nlm.nih.gov/research/umls/rxnorm": RXNORM,
|
|
787
|
+
"http://hl7.org/fhir/sid/cvx": CVX
|
|
747
788
|
});
|
|
748
789
|
function toBuildCode(concept) {
|
|
749
790
|
const codeSystem = URI_TO_OID[concept.system];
|
|
@@ -767,24 +808,24 @@ var VITAL_SIGNS = EXAMPLE_VITAL_SIGNS;
|
|
|
767
808
|
var VACCINES = EXAMPLE_VACCINES;
|
|
768
809
|
var PROCEDURES = EXAMPLE_PROCEDURES;
|
|
769
810
|
var SMOKING_STATUSES = Object.freeze([
|
|
770
|
-
Object.freeze({ code: "266919005", codeSystem:
|
|
771
|
-
Object.freeze({ code: "8517006", codeSystem:
|
|
811
|
+
Object.freeze({ code: "266919005", codeSystem: SNOMED_CT, displayName: "Never smoker" }),
|
|
812
|
+
Object.freeze({ code: "8517006", codeSystem: SNOMED_CT, displayName: "Former smoker" }),
|
|
772
813
|
Object.freeze({
|
|
773
814
|
code: "449868002",
|
|
774
|
-
codeSystem:
|
|
815
|
+
codeSystem: SNOMED_CT,
|
|
775
816
|
displayName: "Current every day smoker"
|
|
776
817
|
}),
|
|
777
818
|
Object.freeze({
|
|
778
819
|
code: "428041000124106",
|
|
779
|
-
codeSystem:
|
|
820
|
+
codeSystem: SNOMED_CT,
|
|
780
821
|
displayName: "Current some day smoker"
|
|
781
822
|
})
|
|
782
823
|
]);
|
|
783
824
|
var ROUTES = Object.freeze([
|
|
784
|
-
Object.freeze({ code: "C38288", codeSystem:
|
|
785
|
-
Object.freeze({ code: "C28161", codeSystem:
|
|
786
|
-
Object.freeze({ code: "C38276", codeSystem:
|
|
787
|
-
Object.freeze({ code: "C38299", codeSystem:
|
|
825
|
+
Object.freeze({ code: "C38288", codeSystem: NCI_ROUTE, displayName: "Oral" }),
|
|
826
|
+
Object.freeze({ code: "C28161", codeSystem: NCI_ROUTE, displayName: "Intramuscular" }),
|
|
827
|
+
Object.freeze({ code: "C38276", codeSystem: NCI_ROUTE, displayName: "Intravenous" }),
|
|
828
|
+
Object.freeze({ code: "C38299", codeSystem: NCI_ROUTE, displayName: "Subcutaneous" })
|
|
788
829
|
]);
|
|
789
830
|
|
|
790
831
|
// src/ccda/identity.ts
|
|
@@ -815,6 +856,28 @@ function resolveMix(allowed, requested, fallback) {
|
|
|
815
856
|
if (requested === void 0) return fallback;
|
|
816
857
|
return requested.map((entry) => resolveKind(allowed, entry));
|
|
817
858
|
}
|
|
859
|
+
function defaultHost() {
|
|
860
|
+
if (typeof undefined !== "function") return { require: __require, resolve: void 0 };
|
|
861
|
+
return { require: module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))), resolve: (s) => undefined(s) };
|
|
862
|
+
}
|
|
863
|
+
function isRequireEsmRefusal(error) {
|
|
864
|
+
return error?.code === "ERR_REQUIRE_ESM";
|
|
865
|
+
}
|
|
866
|
+
function loadPeer(specifier, host) {
|
|
867
|
+
if (host.resolve === void 0) return host.require(specifier);
|
|
868
|
+
const entry = url.fileURLToPath(host.resolve(specifier));
|
|
869
|
+
try {
|
|
870
|
+
return host.require(entry);
|
|
871
|
+
} catch (error) {
|
|
872
|
+
if (!isRequireEsmRefusal(error)) throw error;
|
|
873
|
+
return host.require(specifier);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
function lazyPeer(specifier, host) {
|
|
877
|
+
let loaded;
|
|
878
|
+
return () => loaded ??= loadPeer(specifier, defaultHost());
|
|
879
|
+
}
|
|
880
|
+
var ccdaPeer = lazyPeer("@cosyte/ccda");
|
|
818
881
|
|
|
819
882
|
// src/ccda/ccd.ts
|
|
820
883
|
var CCDA_DOCUMENT_TYPES = Object.freeze(["ccd", "referralNote"]);
|
|
@@ -903,7 +966,7 @@ function generateCcda(options = {}) {
|
|
|
903
966
|
const { seed = 0 } = options;
|
|
904
967
|
const documentType = resolveKind(CCDA_DOCUMENT_TYPES, options.documentType ?? "ccd");
|
|
905
968
|
const rng = createRng(seed);
|
|
906
|
-
return
|
|
969
|
+
return ccdaPeer().buildCcda(buildInit(rng, documentType));
|
|
907
970
|
}
|
|
908
971
|
function generateCcd(options = {}) {
|
|
909
972
|
return generateCcda({ ...options, documentType: "ccd" });
|
|
@@ -911,11 +974,13 @@ function generateCcd(options = {}) {
|
|
|
911
974
|
function generateReferralNote(options = {}) {
|
|
912
975
|
return generateCcda({ ...options, documentType: "referralNote" });
|
|
913
976
|
}
|
|
977
|
+
|
|
978
|
+
// src/ccda/round-trip.ts
|
|
914
979
|
function roundTrip(doc) {
|
|
915
|
-
const content =
|
|
916
|
-
const reparsed =
|
|
980
|
+
const content = ccdaPeer().serializeCcda(doc);
|
|
981
|
+
const reparsed = ccdaPeer().parseCcda(content);
|
|
917
982
|
const warnings = reparsed.warnings.map((w) => String(w.code));
|
|
918
|
-
const byteStable =
|
|
983
|
+
const byteStable = ccdaPeer().serializeCcda(reparsed) === content;
|
|
919
984
|
return {
|
|
920
985
|
content,
|
|
921
986
|
warnings,
|
|
@@ -923,6 +988,14 @@ function roundTrip(doc) {
|
|
|
923
988
|
specClean: warnings.length === 0 && byteStable
|
|
924
989
|
};
|
|
925
990
|
}
|
|
991
|
+
function ccdaCorpusArtifact(doc, verify) {
|
|
992
|
+
const content = ccdaPeer().serializeCcda(doc);
|
|
993
|
+
if (!verify) return { content, warnings: UNCHECKED };
|
|
994
|
+
return {
|
|
995
|
+
content,
|
|
996
|
+
warnings: ccdaPeer().parseCcda(content).warnings.map((w) => String(w.code))
|
|
997
|
+
};
|
|
998
|
+
}
|
|
926
999
|
|
|
927
1000
|
// src/profile.ts
|
|
928
1001
|
function defineSynthProfile(spec) {
|
|
@@ -1007,7 +1080,7 @@ var CCDA_QUIRKS = Object.freeze({
|
|
|
1007
1080
|
})
|
|
1008
1081
|
});
|
|
1009
1082
|
function toleratingProfile(quirk) {
|
|
1010
|
-
return quirk === "template-extension-absent" ?
|
|
1083
|
+
return quirk === "template-extension-absent" ? ccdaPeer().ccdaProfiles.legacyR11 : ccdaPeer().ccdaProfiles.smartScorecard;
|
|
1011
1084
|
}
|
|
1012
1085
|
var DOC_TEMPLATE_ROOTS = [
|
|
1013
1086
|
"2.16.840.1.113883.10.20.22.1.1",
|
|
@@ -1047,11 +1120,11 @@ function generateCcdaQuirk(options) {
|
|
|
1047
1120
|
const seed = options.seed ?? 0;
|
|
1048
1121
|
const documentType = options.documentType ?? "ccd";
|
|
1049
1122
|
const descriptor = resolveQuirk(CCDA_QUIRKS, "ccda", options.quirk);
|
|
1050
|
-
const clean =
|
|
1123
|
+
const clean = ccdaPeer().serializeCcda(generateCcda({ seed, documentType }));
|
|
1051
1124
|
const content = injectCcdaQuirk(options.quirk, clean);
|
|
1052
1125
|
assertIntendedWarnings(
|
|
1053
1126
|
descriptor.intendedWarnings,
|
|
1054
|
-
|
|
1127
|
+
ccdaPeer().parseCcda(content).warnings.map((w) => String(w.code))
|
|
1055
1128
|
);
|
|
1056
1129
|
return Object.freeze({
|
|
1057
1130
|
format: "ccda",
|
|
@@ -1064,17 +1137,16 @@ function generateCcdaQuirk(options) {
|
|
|
1064
1137
|
function ccdaQuirkRoundTrip(artifact) {
|
|
1065
1138
|
const quirk = artifact.quirk;
|
|
1066
1139
|
const descriptor = resolveQuirk(CCDA_QUIRKS, "ccda", quirk);
|
|
1067
|
-
const bare =
|
|
1140
|
+
const bare = ccdaPeer().parseCcda(artifact.content).warnings.map((w) => String(w.code));
|
|
1068
1141
|
const profile = toleratingProfile(quirk);
|
|
1069
|
-
const profiledWarnings =
|
|
1070
|
-
(w) => String(w.code)
|
|
1071
|
-
);
|
|
1142
|
+
const profiledWarnings = ccdaPeer().parseCcda(artifact.content, { profile }).warnings.map((w) => String(w.code));
|
|
1072
1143
|
return {
|
|
1073
1144
|
content: artifact.content,
|
|
1074
1145
|
warnings: bare,
|
|
1075
1146
|
intendedWarnings: artifact.intendedWarnings,
|
|
1076
1147
|
intendedWarningHeld: sameCodeSet(bare, artifact.intendedWarnings),
|
|
1077
1148
|
withProfile: {
|
|
1149
|
+
/* v8 ignore next -- the `?? profile.name` is unreachable: every descriptor in the frozen CCDA_QUIRKS names its toleratingProfile */
|
|
1078
1150
|
profileName: descriptor.toleratingProfile ?? profile.name,
|
|
1079
1151
|
disposition: descriptor.disposition,
|
|
1080
1152
|
warnings: profiledWarnings,
|
|
@@ -1118,13 +1190,13 @@ var ccdaQuirkProfile = defineSynthProfile({
|
|
|
1118
1190
|
var ALL_KINDS = Object.freeze(["ccd", "referralNote"]);
|
|
1119
1191
|
var DEFAULT_MIX = ALL_KINDS;
|
|
1120
1192
|
function ccdaCorpus(options) {
|
|
1121
|
-
const { seed, count = 1 } = options;
|
|
1193
|
+
const { seed, count = 1, verify = true } = options;
|
|
1122
1194
|
const mix = resolveMix(ALL_KINDS, options.mix, DEFAULT_MIX);
|
|
1123
1195
|
const seedStream = createRng(seed);
|
|
1124
1196
|
const artifacts = Array.from({ length: count }, (_unused, i) => {
|
|
1125
1197
|
const documentType = mix[i % mix.length] ?? "ccd";
|
|
1126
1198
|
const docSeed = seedStream.nextUint32();
|
|
1127
|
-
const rt =
|
|
1199
|
+
const rt = ccdaCorpusArtifact(generateCcda({ seed: docSeed, documentType }), verify);
|
|
1128
1200
|
return {
|
|
1129
1201
|
format: "ccda",
|
|
1130
1202
|
kind: documentType,
|