@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.
Files changed (49) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +14 -10
  3. package/dist/astm/index.cjs +164 -102
  4. package/dist/astm/index.cjs.map +1 -1
  5. package/dist/astm/index.d.cts +7 -0
  6. package/dist/astm/index.d.ts +7 -0
  7. package/dist/astm/index.mjs +163 -102
  8. package/dist/astm/index.mjs.map +1 -1
  9. package/dist/ccda/index.cjs +100 -28
  10. package/dist/ccda/index.cjs.map +1 -1
  11. package/dist/ccda/index.d.cts +6 -0
  12. package/dist/ccda/index.d.ts +6 -0
  13. package/dist/ccda/index.mjs +87 -16
  14. package/dist/ccda/index.mjs.map +1 -1
  15. package/dist/deid/index.cjs +305 -165
  16. package/dist/deid/index.cjs.map +1 -1
  17. package/dist/deid/index.mjs +292 -153
  18. package/dist/deid/index.mjs.map +1 -1
  19. package/dist/fhir/index.cjs +179 -76
  20. package/dist/fhir/index.cjs.map +1 -1
  21. package/dist/fhir/index.d.cts +6 -0
  22. package/dist/fhir/index.d.ts +6 -0
  23. package/dist/fhir/index.mjs +178 -76
  24. package/dist/fhir/index.mjs.map +1 -1
  25. package/dist/hl7/index.cjs +86 -12
  26. package/dist/hl7/index.cjs.map +1 -1
  27. package/dist/hl7/index.d.cts +6 -0
  28. package/dist/hl7/index.d.ts +6 -0
  29. package/dist/hl7/index.mjs +85 -12
  30. package/dist/hl7/index.mjs.map +1 -1
  31. package/dist/index.cjs +3 -5
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.cts +8 -4
  34. package/dist/index.d.ts +8 -4
  35. package/dist/index.mjs +3 -5
  36. package/dist/index.mjs.map +1 -1
  37. package/dist/ncpdp/index.cjs +131 -36
  38. package/dist/ncpdp/index.cjs.map +1 -1
  39. package/dist/ncpdp/index.d.cts +7 -0
  40. package/dist/ncpdp/index.d.ts +7 -0
  41. package/dist/ncpdp/index.mjs +130 -36
  42. package/dist/ncpdp/index.mjs.map +1 -1
  43. package/dist/x12/index.cjs +147 -50
  44. package/dist/x12/index.cjs.map +1 -1
  45. package/dist/x12/index.d.cts +6 -0
  46. package/dist/x12/index.d.ts +6 -0
  47. package/dist/x12/index.mjs +146 -50
  48. package/dist/x12/index.mjs.map +1 -1
  49. package/package.json +20 -15
@@ -1,6 +1,15 @@
1
1
  'use strict';
2
2
 
3
- var x12 = require('@cosyte/x12');
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,20 +41,59 @@ 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",
54
+ /**
55
+ * A vendor quirk was requested that the target format's profile system does not support. Fatal,
56
+ * never a silent no-op and never a fabricated quirk.
57
+ */
58
+ SYNTH_UNSUPPORTED_QUIRK: "SYNTH_UNSUPPORTED_QUIRK",
59
+ /**
60
+ * A quirk transform found no structural anchor to mutate, so the fixture would not carry the
61
+ * deviation it is labelled with. Fatal: a golden file that lies about its parser verdict is worse
62
+ * than no golden file.
63
+ */
64
+ SYNTH_QUIRK_ANCHOR_ABSENT: "SYNTH_QUIRK_ANCHOR_ABSENT",
65
+ /**
66
+ * A bare parse of a freshly-generated quirk artifact did not produce exactly the declared intended
67
+ * warning code(s). Fatal, never emit a mislabeled fixture.
68
+ */
69
+ SYNTH_INTENDED_WARNING_MISMATCH: "SYNTH_INTENDED_WARNING_MISMATCH",
70
+ /** A concept's code-system URI has no OID mapping in the C-CDA example-code table. Fatal. */
71
+ SYNTH_UNMAPPED_CODE_SYSTEM: "SYNTH_UNMAPPED_CODE_SYSTEM",
36
72
  /** A money value could not be read as an X12 decimal. Fatal: a generator never rounds to a float. */
37
73
  SYNTH_INVALID_DECIMAL: "SYNTH_INVALID_DECIMAL",
38
74
  /** An integer range was requested with its maximum below its minimum. Fatal. */
39
75
  SYNTH_INVALID_RANGE: "SYNTH_INVALID_RANGE",
40
76
  /** A value was drawn from an empty pool. Fatal, never a fabricated substitute. */
41
77
  SYNTH_EMPTY_POOL: "SYNTH_EMPTY_POOL",
78
+ /** A `defineSynthProfile` spec was not usable (a missing or blank `name`). Fatal. */
79
+ SYNTH_INVALID_PROFILE: "SYNTH_INVALID_PROFILE",
42
80
  /**
43
81
  * A caller-supplied selector (a message kind, a document type, a corpus mix entry, a claim
44
82
  * variant, a Bundle type, a resource profile) is not in the closed set that governs it. Fatal:
45
83
  * see `resolveKind`: a selector union is erased at run time, and a selector that falls through
46
84
  * either mislabels the fixture or hands the value to a peer builder that quotes it back.
47
85
  */
48
- 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
+ });
49
97
  var SYNTH_FATAL_MESSAGES = Object.freeze({
50
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.",
51
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).",
@@ -111,6 +159,7 @@ function createRng(seed) {
111
159
  }
112
160
 
113
161
  // src/corpus.ts
162
+ var UNCHECKED = Object.freeze([]);
114
163
  function makeCorpus(seed, artifacts, quirks = []) {
115
164
  const counts = {};
116
165
  const formats = /* @__PURE__ */ new Set();
@@ -130,8 +179,32 @@ function makeCorpus(seed, artifacts, quirks = []) {
130
179
  artifacts: Object.freeze(frozenArtifacts)
131
180
  });
132
181
  }
182
+ function defaultHost() {
183
+ if (typeof undefined !== "function") return { require: __require, resolve: void 0 };
184
+ 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) };
185
+ }
186
+ function isRequireEsmRefusal(error) {
187
+ return error?.code === "ERR_REQUIRE_ESM";
188
+ }
189
+ function loadPeer(specifier, host) {
190
+ if (host.resolve === void 0) return host.require(specifier);
191
+ const entry = url.fileURLToPath(host.resolve(specifier));
192
+ try {
193
+ return host.require(entry);
194
+ } catch (error) {
195
+ if (!isRequireEsmRefusal(error)) throw error;
196
+ return host.require(specifier);
197
+ }
198
+ }
199
+ function lazyPeer(specifier, host) {
200
+ let loaded;
201
+ return () => loaded ??= loadPeer(specifier, defaultHost());
202
+ }
203
+ var x12Peer = lazyPeer("@cosyte/x12");
204
+
205
+ // src/x12/money.ts
133
206
  function dec(value) {
134
- const d = x12.X12Decimal.fromString(value);
207
+ const d = x12Peer().X12Decimal.fromString(value);
135
208
  if (d === void 0) throw new SynthError(SYNTH_FATAL_CODES.SYNTH_INVALID_DECIMAL);
136
209
  return d;
137
210
  }
@@ -484,39 +557,49 @@ function x12EnvelopeTiming(rng) {
484
557
  }
485
558
 
486
559
  // src/x12/example-codes.ts
487
- var PROFESSIONAL_PROCEDURES = Object.freeze([
488
- { code: "99213", label: "office/outpatient visit, established patient" },
489
- { code: "99214", label: "office/outpatient visit, established patient, moderate" },
490
- { code: "99203", label: "office/outpatient visit, new patient" },
491
- { code: "85025", label: "complete blood count with differential" },
492
- { code: "80053", label: "comprehensive metabolic panel" },
493
- { code: "93000", label: "electrocardiogram, routine" }
494
- ]);
560
+ var PROFESSIONAL_PROCEDURES = Object.freeze(
561
+ [
562
+ { code: "99213", label: "office/outpatient visit, established patient" },
563
+ { code: "99214", label: "office/outpatient visit, established patient, moderate" },
564
+ { code: "99203", label: "office/outpatient visit, new patient" },
565
+ { code: "85025", label: "complete blood count with differential" },
566
+ { code: "80053", label: "comprehensive metabolic panel" },
567
+ { code: "93000", label: "electrocardiogram, routine" }
568
+ ].map((entry) => Object.freeze(entry))
569
+ );
495
570
  var PROCEDURE_MODIFIERS = Object.freeze(["25", "59", "76", "GT"]);
496
571
  var PLACES_OF_SERVICE = Object.freeze(["11", "22", "21", "12", "49"]);
497
- var DIAGNOSES = Object.freeze([
498
- { code: "J20.9", label: "acute bronchitis, unspecified" },
499
- { code: "E11.9", label: "type 2 diabetes mellitus without complications" },
500
- { code: "I10", label: "essential (primary) hypertension" },
501
- { code: "M54.5", label: "low back pain" },
502
- { code: "R07.9", label: "chest pain, unspecified" },
503
- { code: "Z00.00", label: "general adult medical exam without abnormal findings" }
504
- ]);
505
- var REVENUE_CODES = Object.freeze([
506
- { code: "0120", label: "room & board, semi-private" },
507
- { code: "0300", label: "laboratory, general" },
508
- { code: "0450", label: "emergency room, general" },
509
- { code: "0636", label: "drugs requiring detailed coding" }
510
- ]);
511
- var INSTITUTIONAL_PROCEDURES = Object.freeze([
512
- { code: "99221", label: "initial hospital care, per day" },
513
- { code: "99231", label: "subsequent hospital care, per day" }
514
- ]);
515
- var DENTAL_PROCEDURES = Object.freeze([
516
- { code: "D2391", label: "resin-based composite, one surface, posterior" },
517
- { code: "D1110", label: "prophylaxis, adult" },
518
- { code: "D0120", label: "periodic oral evaluation" }
519
- ]);
572
+ var DIAGNOSES = Object.freeze(
573
+ [
574
+ { code: "J20.9", label: "acute bronchitis, unspecified" },
575
+ { code: "E11.9", label: "type 2 diabetes mellitus without complications" },
576
+ { code: "I10", label: "essential (primary) hypertension" },
577
+ { code: "M54.5", label: "low back pain" },
578
+ { code: "R07.9", label: "chest pain, unspecified" },
579
+ { code: "Z00.00", label: "general adult medical exam without abnormal findings" }
580
+ ].map((entry) => Object.freeze(entry))
581
+ );
582
+ var REVENUE_CODES = Object.freeze(
583
+ [
584
+ { code: "0120", label: "room & board, semi-private" },
585
+ { code: "0300", label: "laboratory, general" },
586
+ { code: "0450", label: "emergency room, general" },
587
+ { code: "0636", label: "drugs requiring detailed coding" }
588
+ ].map((entry) => Object.freeze(entry))
589
+ );
590
+ var INSTITUTIONAL_PROCEDURES = Object.freeze(
591
+ [
592
+ { code: "99221", label: "initial hospital care, per day" },
593
+ { code: "99231", label: "subsequent hospital care, per day" }
594
+ ].map((entry) => Object.freeze(entry))
595
+ );
596
+ var DENTAL_PROCEDURES = Object.freeze(
597
+ [
598
+ { code: "D2391", label: "resin-based composite, one surface, posterior" },
599
+ { code: "D1110", label: "prophylaxis, adult" },
600
+ { code: "D0120", label: "periodic oral evaluation" }
601
+ ].map((entry) => Object.freeze(entry))
602
+ );
520
603
  var TOOTH_CODES = Object.freeze(["14", "3", "19", "30"]);
521
604
  var TOOTH_SURFACES = Object.freeze(["M", "O", "D", "B", "L"]);
522
605
  var CARC_CODES = Object.freeze(["1", "2", "3", "45", "96", "197"]);
@@ -722,11 +805,11 @@ function generate837(variant, options) {
722
805
  const spec = specOf(rng, resolved);
723
806
  switch (resolved) {
724
807
  case "P":
725
- return x12.build837P(spec);
808
+ return x12Peer().build837P(spec);
726
809
  case "I":
727
- return x12.build837I(spec);
810
+ return x12Peer().build837I(spec);
728
811
  case "D":
729
- return x12.build837D(spec);
812
+ return x12Peer().build837D(spec);
730
813
  }
731
814
  }
732
815
  function generate837P(options) {
@@ -738,6 +821,8 @@ function generate837I(options) {
738
821
  function generate837D(options) {
739
822
  return generate837("D", options);
740
823
  }
824
+
825
+ // src/x12/remit-835.ts
741
826
  function generate835(options) {
742
827
  const rng = createRng(options.seed);
743
828
  const partners = x12TradingPartners(rng);
@@ -838,8 +923,10 @@ function generate835(options) {
838
923
  },
839
924
  claims: [claim]
840
925
  };
841
- return x12.build835(spec);
926
+ return x12Peer().build835(spec);
842
927
  }
928
+
929
+ // src/x12/eligibility-271.ts
843
930
  function generate271(options) {
844
931
  const rng = createRng(options.seed);
845
932
  const partners = x12TradingPartners(rng);
@@ -919,13 +1006,15 @@ function generate271(options) {
919
1006
  }
920
1007
  ]
921
1008
  };
922
- return x12.build271(spec);
1009
+ return x12Peer().build271(spec);
923
1010
  }
1011
+
1012
+ // src/x12/round-trip.ts
924
1013
  function roundTrip(interchange) {
925
- const content = x12.serializeX12(interchange);
926
- const reparsed = x12.parseX12(content);
1014
+ const content = x12Peer().serializeX12(interchange);
1015
+ const reparsed = x12Peer().parseX12(content);
927
1016
  const warnings = reparsed.warnings.map((w) => String(w.code));
928
- const byteStable = x12.serializeX12(reparsed) === content;
1017
+ const byteStable = x12Peer().serializeX12(reparsed) === content;
929
1018
  return {
930
1019
  content,
931
1020
  warnings,
@@ -933,6 +1022,14 @@ function roundTrip(interchange) {
933
1022
  specClean: warnings.length === 0 && byteStable
934
1023
  };
935
1024
  }
1025
+ function x12CorpusArtifact(interchange, verify) {
1026
+ const content = x12Peer().serializeX12(interchange);
1027
+ if (!verify) return { content, warnings: UNCHECKED };
1028
+ return {
1029
+ content,
1030
+ warnings: x12Peer().parseX12(content).warnings.map((w) => String(w.code))
1031
+ };
1032
+ }
936
1033
 
937
1034
  // src/x12/index.ts
938
1035
  var ALL_KINDS = Object.freeze(["837P", "837I", "837D", "835", "271"]);
@@ -940,26 +1037,26 @@ var DEFAULT_MIX = ALL_KINDS;
940
1037
  function generateKind(kind, seed) {
941
1038
  switch (kind) {
942
1039
  case "835":
943
- return roundTrip(generate835({ seed }));
1040
+ return generate835({ seed });
944
1041
  case "271":
945
- return roundTrip(generate271({ seed }));
1042
+ return generate271({ seed });
946
1043
  case "837P":
947
- return roundTrip(generate837("P", { seed }));
1044
+ return generate837("P", { seed });
948
1045
  case "837I":
949
- return roundTrip(generate837("I", { seed }));
1046
+ return generate837("I", { seed });
950
1047
  case "837D":
951
- return roundTrip(generate837("D", { seed }));
1048
+ return generate837("D", { seed });
952
1049
  }
953
1050
  }
954
1051
  function x12Corpus(options) {
955
- const { seed } = options;
1052
+ const { seed, verify = true } = options;
956
1053
  const mix = resolveMix(ALL_KINDS, options.mix, DEFAULT_MIX);
957
1054
  const count = options.count ?? mix.length;
958
1055
  const seedStream = createRng(seed);
959
1056
  const artifacts = Array.from({ length: count }, (_unused, i) => {
960
1057
  const kind = mix[i % mix.length] ?? "837P";
961
1058
  const txSeed = seedStream.nextUint32();
962
- const rt = generateKind(kind, txSeed);
1059
+ const rt = x12CorpusArtifact(generateKind(kind, txSeed), verify);
963
1060
  return {
964
1061
  format: "x12",
965
1062
  kind,