@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.
Files changed (46) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/astm/index.cjs +57 -19
  3. package/dist/astm/index.cjs.map +1 -1
  4. package/dist/astm/index.d.cts +7 -0
  5. package/dist/astm/index.d.ts +7 -0
  6. package/dist/astm/index.mjs +56 -19
  7. package/dist/astm/index.mjs.map +1 -1
  8. package/dist/ccda/index.cjs +76 -26
  9. package/dist/ccda/index.cjs.map +1 -1
  10. package/dist/ccda/index.d.cts +6 -0
  11. package/dist/ccda/index.d.ts +6 -0
  12. package/dist/ccda/index.mjs +63 -14
  13. package/dist/ccda/index.mjs.map +1 -1
  14. package/dist/deid/index.cjs +216 -125
  15. package/dist/deid/index.cjs.map +1 -1
  16. package/dist/deid/index.mjs +203 -113
  17. package/dist/deid/index.mjs.map +1 -1
  18. package/dist/fhir/index.cjs +146 -74
  19. package/dist/fhir/index.cjs.map +1 -1
  20. package/dist/fhir/index.d.cts +6 -0
  21. package/dist/fhir/index.d.ts +6 -0
  22. package/dist/fhir/index.mjs +145 -74
  23. package/dist/fhir/index.mjs.map +1 -1
  24. package/dist/hl7/index.cjs +53 -9
  25. package/dist/hl7/index.cjs.map +1 -1
  26. package/dist/hl7/index.d.cts +6 -0
  27. package/dist/hl7/index.d.ts +6 -0
  28. package/dist/hl7/index.mjs +52 -9
  29. package/dist/hl7/index.mjs.map +1 -1
  30. package/dist/index.cjs +1 -3
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.mjs +1 -3
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/ncpdp/index.cjs +76 -23
  35. package/dist/ncpdp/index.cjs.map +1 -1
  36. package/dist/ncpdp/index.d.cts +7 -0
  37. package/dist/ncpdp/index.d.ts +7 -0
  38. package/dist/ncpdp/index.mjs +75 -23
  39. package/dist/ncpdp/index.mjs.map +1 -1
  40. package/dist/x12/index.cjs +72 -23
  41. package/dist/x12/index.cjs.map +1 -1
  42. package/dist/x12/index.d.cts +8 -1
  43. package/dist/x12/index.d.ts +8 -1
  44. package/dist/x12/index.mjs +71 -23
  45. package/dist/x12/index.mjs.map +1 -1
  46. package/package.json +20 -15
@@ -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
@@ -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
@@ -1,6 +1,12 @@
1
- import { buildNewRx, serializeScript, ScriptMessage, parseScript } from '@cosyte/ncpdp/script';
2
- import { decimalValue, codedValue } from '@cosyte/ncpdp/common';
3
- import { serializeTelecom, buildTelecomRequest, parseTelecom } from '@cosyte/ncpdp/telecom';
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(new ScriptMessage({ header: header2, body, warnings: [] }));
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(new ScriptMessage({ header: header2, body, warnings: [] }));
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(buildTelecomRequest({ header: head, segments }));
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 scriptRoundTrip(generateNewRx({ seed }));
822
+ return scriptCorpusArtifact(generateNewRx({ seed }), verify);
771
823
  case "RxRenewalRequest":
772
- return scriptRoundTrip(generateRxRenewalRequest({ seed }));
824
+ return scriptCorpusArtifact(generateRxRenewalRequest({ seed }), verify);
773
825
  case "RxChangeRequest":
774
- return scriptRoundTrip(generateRxChangeRequest({ seed }));
826
+ return scriptCorpusArtifact(generateRxChangeRequest({ seed }), verify);
775
827
  case "B1":
776
828
  case "B2":
777
829
  case "B3":
778
- return telecomRoundTrip(generateTelecom(kind, { seed }));
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,