@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 hl7 = require('@cosyte/hl7');
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,17 +41,36 @@ 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.
39
57
  */
40
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",
41
65
  /**
42
66
  * A bare parse of a freshly-generated quirk artifact did not produce exactly the declared intended
43
67
  * warning code(s). Fatal, never emit a mislabeled fixture.
44
68
  */
45
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",
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",
46
74
  /** An integer range was requested with its maximum below its minimum. Fatal. */
47
75
  SYNTH_INVALID_RANGE: "SYNTH_INVALID_RANGE",
48
76
  /** A value was drawn from an empty pool. Fatal, never a fabricated substitute. */
@@ -55,7 +83,17 @@ var SYNTH_FATAL_CODES = {
55
83
  * see `resolveKind`: a selector union is erased at run time, and a selector that falls through
56
84
  * either mislabels the fixture or hands the value to a peer builder that quotes it back.
57
85
  */
58
- 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
+ });
59
97
  var SYNTH_FATAL_MESSAGES = Object.freeze({
60
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.",
61
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).",
@@ -121,6 +159,7 @@ function createRng(seed) {
121
159
  }
122
160
 
123
161
  // src/corpus.ts
162
+ var UNCHECKED = Object.freeze([]);
124
163
  function makeCorpus(seed, artifacts, quirks = []) {
125
164
  const counts = {};
126
165
  const formats = /* @__PURE__ */ new Set();
@@ -432,6 +471,30 @@ var safe = Object.freeze({
432
471
  npi,
433
472
  dea
434
473
  });
474
+ function defaultHost() {
475
+ if (typeof undefined !== "function") return { require: __require, resolve: void 0 };
476
+ 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) };
477
+ }
478
+ function isRequireEsmRefusal(error) {
479
+ return error?.code === "ERR_REQUIRE_ESM";
480
+ }
481
+ function loadPeer(specifier, host) {
482
+ if (host.resolve === void 0) return host.require(specifier);
483
+ const entry = url.fileURLToPath(host.resolve(specifier));
484
+ try {
485
+ return host.require(entry);
486
+ } catch (error) {
487
+ if (!isRequireEsmRefusal(error)) throw error;
488
+ return host.require(specifier);
489
+ }
490
+ }
491
+ function lazyPeer(specifier, host) {
492
+ let loaded;
493
+ return () => loaded ??= loadPeer(specifier, defaultHost());
494
+ }
495
+
496
+ // src/peers.ts
497
+ var hl7Peer = lazyPeer("@cosyte/hl7");
435
498
 
436
499
  // src/hl7/common.ts
437
500
  function seededTimestamp(rng) {
@@ -444,7 +507,7 @@ function seededTimestamp(rng) {
444
507
  function mshScaffold(rng, type) {
445
508
  const timestamp = seededTimestamp(rng);
446
509
  const controlId = `SYNTH${rng.digits(10)}`;
447
- const message = hl7.buildMessage({
510
+ const message = hl7Peer().buildMessage({
448
511
  type,
449
512
  sendingApp: "COSYTE-SYNTH",
450
513
  sendingFacility: "SYNTH-FAC",
@@ -571,6 +634,7 @@ function obxSegment(rng, setId) {
571
634
  const obs = rng.pick(EXAMPLE_LAB_OBSERVATIONS);
572
635
  const value = `${String(rng.int(1, 300))}.${String(rng.int(0, 9))}`;
573
636
  const observedAt = seededTimestamp(rng);
637
+ const units = obs.units ?? "";
574
638
  return [
575
639
  String(setId),
576
640
  // OBX-1 set id
@@ -582,7 +646,7 @@ function obxSegment(rng, setId) {
582
646
  // OBX-4 observation sub-id
583
647
  value,
584
648
  // OBX-5 observation value
585
- obs.units ?? "",
649
+ units,
586
650
  // OBX-6 units
587
651
  "",
588
652
  // OBX-7 reference range
@@ -796,9 +860,11 @@ function generateVxu(options = {}) {
796
860
  ]);
797
861
  return message;
798
862
  }
863
+
864
+ // src/hl7/round-trip.ts
799
865
  function roundTrip(message) {
800
866
  const content = message.toString();
801
- const reparsed = hl7.parseHL7(content);
867
+ const reparsed = hl7Peer().parseHL7(content);
802
868
  const warnings = reparsed.warnings.map((w) => String(w.code));
803
869
  const byteStable = reparsed.toString() === content;
804
870
  return {
@@ -808,6 +874,14 @@ function roundTrip(message) {
808
874
  specClean: warnings.length === 0 && byteStable
809
875
  };
810
876
  }
877
+ function hl7CorpusArtifact(message, verify) {
878
+ const content = message.toString();
879
+ if (!verify) return { content, warnings: UNCHECKED };
880
+ return {
881
+ content,
882
+ warnings: hl7Peer().parseHL7(content).warnings.map((w) => String(w.code))
883
+ };
884
+ }
811
885
 
812
886
  // src/profile.ts
813
887
  function defineSynthProfile(spec) {
@@ -883,7 +957,7 @@ var HL7_QUIRKS = Object.freeze({
883
957
  })
884
958
  });
885
959
  function toleratingProfile(quirk) {
886
- return quirk === "unknown-zsegment" ? hl7.profiles.visage : void 0;
960
+ return quirk === "unknown-zsegment" ? hl7Peer().profiles.visage : void 0;
887
961
  }
888
962
  function segmentsOf(wire) {
889
963
  return wire.split(/\r\n|\r|\n/).filter((s) => s.length > 0);
@@ -931,7 +1005,7 @@ function generateHl7Quirk(options) {
931
1005
  const content = applyQuirk(options.quirk, baseMessage(kind, seed).toString());
932
1006
  assertIntendedWarnings(
933
1007
  descriptor.intendedWarnings,
934
- hl7.parseHL7(content).warnings.map((w) => String(w.code))
1008
+ hl7Peer().parseHL7(content).warnings.map((w) => String(w.code))
935
1009
  );
936
1010
  return Object.freeze({
937
1011
  format: "hl7v2",
@@ -944,12 +1018,12 @@ function generateHl7Quirk(options) {
944
1018
  function hl7QuirkRoundTrip(artifact) {
945
1019
  const quirk = artifact.quirk;
946
1020
  const descriptor = resolveQuirk(HL7_QUIRKS, "hl7v2", quirk);
947
- const bare = hl7.parseHL7(artifact.content).warnings.map((w) => String(w.code));
1021
+ const bare = hl7Peer().parseHL7(artifact.content).warnings.map((w) => String(w.code));
948
1022
  const profile = toleratingProfile(quirk);
949
1023
  const withProfile = profile !== void 0 && descriptor.toleratingProfile !== void 0 ? {
950
1024
  profileName: descriptor.toleratingProfile,
951
1025
  disposition: descriptor.disposition,
952
- warnings: hl7.parseHL7(artifact.content, profile).warnings.map((w) => String(w.code)),
1026
+ warnings: hl7Peer().parseHL7(artifact.content, profile).warnings.map((w) => String(w.code)),
953
1027
  tolerated: false
954
1028
  } : void 0;
955
1029
  return {
@@ -1028,7 +1102,7 @@ function generateHl7(kind, seed) {
1028
1102
  }
1029
1103
  }
1030
1104
  function hl7Corpus(options) {
1031
- const { seed, count = 1 } = options;
1105
+ const { seed, count = 1, verify = true } = options;
1032
1106
  const kinds = options.triggers !== void 0 ? options.triggers.map(
1033
1107
  (t) => `ADT^${resolveKind(ADT_TRIGGERS2, t)}`
1034
1108
  ) : resolveMix(ALL_KINDS, options.mix, DEFAULT_MIX);
@@ -1036,7 +1110,7 @@ function hl7Corpus(options) {
1036
1110
  const artifacts = Array.from({ length: count }, (_unused, i) => {
1037
1111
  const kind = kinds[i % kinds.length] ?? "ADT^A01";
1038
1112
  const messageSeed = seedStream.nextUint32();
1039
- const rt = roundTrip(generateHl7(kind, messageSeed));
1113
+ const rt = hl7CorpusArtifact(generateHl7(kind, messageSeed), verify);
1040
1114
  return {
1041
1115
  format: "hl7v2",
1042
1116
  kind,