@cosyte/synth 0.0.3 → 0.0.5

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 +335 -0
  2. package/README.md +6 -2
  3. package/dist/astm/index.cjs +83 -42
  4. package/dist/astm/index.cjs.map +1 -1
  5. package/dist/astm/index.d.cts +1 -1
  6. package/dist/astm/index.d.ts +1 -1
  7. package/dist/astm/index.mjs +83 -42
  8. package/dist/astm/index.mjs.map +1 -1
  9. package/dist/ccda/index.cjs +89 -44
  10. package/dist/ccda/index.cjs.map +1 -1
  11. package/dist/ccda/index.d.cts +5 -3
  12. package/dist/ccda/index.d.ts +5 -3
  13. package/dist/ccda/index.mjs +89 -44
  14. package/dist/ccda/index.mjs.map +1 -1
  15. package/dist/deid/index.cjs +92 -13
  16. package/dist/deid/index.cjs.map +1 -1
  17. package/dist/deid/index.d.cts +1 -1
  18. package/dist/deid/index.d.ts +1 -1
  19. package/dist/deid/index.mjs +93 -14
  20. package/dist/deid/index.mjs.map +1 -1
  21. package/dist/fhir/index.cjs +78 -5
  22. package/dist/fhir/index.cjs.map +1 -1
  23. package/dist/fhir/index.mjs +78 -5
  24. package/dist/fhir/index.mjs.map +1 -1
  25. package/dist/hl7/index.cjs +89 -41
  26. package/dist/hl7/index.cjs.map +1 -1
  27. package/dist/hl7/index.d.cts +1 -1
  28. package/dist/hl7/index.d.ts +1 -1
  29. package/dist/hl7/index.mjs +89 -41
  30. package/dist/hl7/index.mjs.map +1 -1
  31. package/dist/index.cjs +91 -40
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.cts +126 -8
  34. package/dist/index.d.ts +126 -8
  35. package/dist/index.mjs +89 -41
  36. package/dist/index.mjs.map +1 -1
  37. package/dist/ncpdp/index.cjs +56 -4
  38. package/dist/ncpdp/index.cjs.map +1 -1
  39. package/dist/ncpdp/index.mjs +56 -4
  40. package/dist/ncpdp/index.mjs.map +1 -1
  41. package/dist/{quirk-JLyO1Ncj.d.ts → quirk-C9t9CkPS.d.ts} +17 -6
  42. package/dist/{quirk-DmkgoZdh.d.cts → quirk-DYMDojVw.d.cts} +17 -6
  43. package/dist/x12/index.cjs +82 -13
  44. package/dist/x12/index.cjs.map +1 -1
  45. package/dist/x12/index.d.cts +2 -1
  46. package/dist/x12/index.d.ts +2 -1
  47. package/dist/x12/index.mjs +83 -14
  48. package/dist/x12/index.mjs.map +1 -1
  49. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  import { S as SyntheticName, R as Rng, C as Corpus } from '../providers-OLz3zAc-.cjs';
2
- import { Q as QuirkDescriptor, S as SynthProfile, a as QuirkArtifact, b as QuirkRoundTripResult } from '../quirk-DmkgoZdh.cjs';
2
+ import { Q as QuirkDescriptor, S as SynthProfile, a as QuirkArtifact, b as QuirkRoundTripResult } from '../quirk-DYMDojVw.cjs';
3
3
 
4
4
  /**
5
5
  * Spec-clean ASTM (E1394 / CLSI LIS02) message generation — the `H`/`P`/`O`/`R`/`C`/`L` record report —
@@ -1,5 +1,5 @@
1
1
  import { S as SyntheticName, R as Rng, C as Corpus } from '../providers-OLz3zAc-.js';
2
- import { Q as QuirkDescriptor, S as SynthProfile, a as QuirkArtifact, b as QuirkRoundTripResult } from '../quirk-JLyO1Ncj.js';
2
+ import { Q as QuirkDescriptor, S as SynthProfile, a as QuirkArtifact, b as QuirkRoundTripResult } from '../quirk-C9t9CkPS.js';
3
3
 
4
4
  /**
5
5
  * Spec-clean ASTM (E1394 / CLSI LIS02) message generation — the `H`/`P`/`O`/`R`/`C`/`L` record report —
@@ -29,6 +29,63 @@ function sfc32Next(s) {
29
29
  return t >>> 0;
30
30
  }
31
31
 
32
+ // src/codes.ts
33
+ var SYNTH_FATAL_CODES = {
34
+ /**
35
+ * A vendor quirk was requested that the target format's profile system does not support. Fatal —
36
+ * never a silent no-op and never a fabricated quirk.
37
+ */
38
+ SYNTH_UNSUPPORTED_QUIRK: "SYNTH_UNSUPPORTED_QUIRK",
39
+ /**
40
+ * A quirk transform found no structural anchor to mutate, so the fixture would not carry the
41
+ * deviation it is labelled with. Fatal — a golden file that lies about its parser verdict is worse
42
+ * than no golden file.
43
+ */
44
+ SYNTH_QUIRK_ANCHOR_ABSENT: "SYNTH_QUIRK_ANCHOR_ABSENT",
45
+ /**
46
+ * A bare parse of a freshly-generated quirk artifact did not produce exactly the declared intended
47
+ * warning code(s). Fatal — never emit a mislabeled fixture.
48
+ */
49
+ SYNTH_INTENDED_WARNING_MISMATCH: "SYNTH_INTENDED_WARNING_MISMATCH",
50
+ /** An integer range was requested with its maximum below its minimum. Fatal. */
51
+ SYNTH_INVALID_RANGE: "SYNTH_INVALID_RANGE",
52
+ /** A value was drawn from an empty pool. Fatal — never a fabricated substitute. */
53
+ SYNTH_EMPTY_POOL: "SYNTH_EMPTY_POOL",
54
+ /** A `defineSynthProfile` spec was not usable (a missing or blank `name`). Fatal. */
55
+ SYNTH_INVALID_PROFILE: "SYNTH_INVALID_PROFILE",
56
+ /**
57
+ * A caller-supplied selector (a message kind, a document type, a corpus mix entry, a claim
58
+ * variant, a Bundle type, a resource profile) is not in the closed set that governs it. Fatal —
59
+ * see `resolveKind`: a selector union is erased at run time, and a selector that falls through
60
+ * either mislabels the fixture or hands the value to a peer builder that quotes it back.
61
+ */
62
+ SYNTH_UNSUPPORTED_KIND: "SYNTH_UNSUPPORTED_KIND"
63
+ };
64
+ var SYNTH_FATAL_MESSAGES = Object.freeze({
65
+ 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.",
66
+ 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).",
67
+ SYNTH_QUIRK_ANCHOR_ABSENT: "The quirk transform found no structural anchor to mutate, so the fixture would not carry the deviation it is labelled with. Refusing to emit a mislabeled fixture.",
68
+ SYNTH_INTENDED_WARNING_MISMATCH: "A bare parse of the generated quirk artifact did not produce exactly the declared intended warning code(s). Refusing to emit a mislabeled fixture.",
69
+ SYNTH_UNMAPPED_CODE_SYSTEM: "The concept's code-system URI has no OID mapping in the C-CDA example-code table.",
70
+ SYNTH_INVALID_DECIMAL: "The value could not be read as an X12 decimal.",
71
+ SYNTH_INVALID_RANGE: "An integer range was requested with its maximum below its minimum.",
72
+ SYNTH_EMPTY_POOL: "A value was drawn from an empty pool.",
73
+ SYNTH_INVALID_PROFILE: "defineSynthProfile requires a non-empty string name.",
74
+ SYNTH_UNSUPPORTED_KIND: "The requested kind, document type, corpus mix entry, variant or profile is not one this generator supports. The supported set is the exported union for that option."
75
+ });
76
+ var SynthError = class extends Error {
77
+ /** The stable fatal code. */
78
+ code;
79
+ /**
80
+ * @param code - The stable {@link SynthFatalCode}. The message comes from the frozen registry.
81
+ */
82
+ constructor(code) {
83
+ super(SYNTH_FATAL_MESSAGES[code]);
84
+ this.name = "SynthError";
85
+ this.code = code;
86
+ }
87
+ };
88
+
32
89
  // src/rng/rng.ts
33
90
  var Sfc32Rng = class {
34
91
  seed;
@@ -46,7 +103,7 @@ var Sfc32Rng = class {
46
103
  return this.nextUint32() / 4294967296;
47
104
  }
48
105
  int(min, max) {
49
- if (max < min) throw new RangeError(`Rng.int: max (${String(max)}) < min (${String(min)})`);
106
+ if (max < min) throw new SynthError(SYNTH_FATAL_CODES.SYNTH_INVALID_RANGE);
50
107
  const span = max - min + 1;
51
108
  return min + Math.floor(this.float() * span);
52
109
  }
@@ -54,7 +111,7 @@ var Sfc32Rng = class {
54
111
  return this.float() < p;
55
112
  }
56
113
  pick(items) {
57
- if (items.length === 0) throw new RangeError("Rng.pick: empty array");
114
+ if (items.length === 0) throw new SynthError(SYNTH_FATAL_CODES.SYNTH_EMPTY_POOL);
58
115
  return items[this.int(0, items.length - 1)];
59
116
  }
60
117
  digits(n) {
@@ -582,10 +639,21 @@ function latin1(bytes) {
582
639
  return out;
583
640
  }
584
641
 
642
+ // src/select.ts
643
+ function resolveKind(allowed, requested) {
644
+ const match = allowed.find((value) => value === requested);
645
+ if (match === void 0) throw new SynthError(SYNTH_FATAL_CODES.SYNTH_UNSUPPORTED_KIND);
646
+ return match;
647
+ }
648
+ function resolveMix(allowed, requested, fallback) {
649
+ if (requested === void 0) return fallback;
650
+ return requested.map((entry) => resolveKind(allowed, entry));
651
+ }
652
+
585
653
  // src/profile.ts
586
654
  function defineSynthProfile(spec) {
587
655
  if (typeof spec.name !== "string" || spec.name.trim().length === 0) {
588
- throw new TypeError("defineSynthProfile: `name` is required and must be a non-empty string.");
656
+ throw new SynthError(SYNTH_FATAL_CODES.SYNTH_INVALID_PROFILE);
589
657
  }
590
658
  return Object.freeze({
591
659
  name: spec.name,
@@ -595,28 +663,6 @@ function defineSynthProfile(spec) {
595
663
  });
596
664
  }
597
665
 
598
- // src/codes.ts
599
- var SYNTH_FATAL_CODES = {
600
- /**
601
- * A vendor quirk was requested that the target format's profile system does not support. Fatal —
602
- * never a silent no-op and never a fabricated quirk.
603
- */
604
- SYNTH_UNSUPPORTED_QUIRK: "SYNTH_UNSUPPORTED_QUIRK"
605
- };
606
- var SynthError = class extends Error {
607
- /** The stable fatal code. */
608
- code;
609
- /**
610
- * @param code - The stable {@link SynthFatalCode}.
611
- * @param message - A human-readable detail (never contains PHI — there is none).
612
- */
613
- constructor(code, message) {
614
- super(message);
615
- this.name = "SynthError";
616
- this.code = code;
617
- }
618
- };
619
-
620
666
  // src/quirk.ts
621
667
  var PROFILE_QUIRK_APPLIED = "PROFILE_QUIRK_APPLIED";
622
668
  function sameCodeSet(a, b) {
@@ -633,12 +679,8 @@ function sameCodeSet(a, b) {
633
679
  }
634
680
  function resolveQuirk(registry, format, name2) {
635
681
  const descriptor = registry[name2];
636
- if (descriptor === void 0) {
637
- const supported = Object.keys(registry).sort().join(", ");
638
- throw new SynthError(
639
- SYNTH_FATAL_CODES.SYNTH_UNSUPPORTED_QUIRK,
640
- `${format}: unsupported quirk "${name2}". The ${format} profile system supports: ${supported}.`
641
- );
682
+ if (descriptor === void 0 || descriptor.format !== format) {
683
+ throw new SynthError(SYNTH_FATAL_CODES.SYNTH_UNSUPPORTED_QUIRK);
642
684
  }
643
685
  return descriptor;
644
686
  }
@@ -653,11 +695,9 @@ function profileTolerated(disposition, intendedWarnings, warningsUnderProfile) {
653
695
  return false;
654
696
  }
655
697
  }
656
- function assertIntendedWarnings(quirk, intendedWarnings, bareWarnings) {
698
+ function assertIntendedWarnings(intendedWarnings, bareWarnings) {
657
699
  if (!sameCodeSet(bareWarnings, intendedWarnings)) {
658
- throw new Error(
659
- `quirk "${quirk}": the intended-warning contract does not hold \u2014 expected exactly [${intendedWarnings.join(", ")}] but a bare parse produced [${bareWarnings.join(", ")}]. Refusing to emit a mislabeled fixture.`
660
- );
700
+ throw new SynthError(SYNTH_FATAL_CODES.SYNTH_INTENDED_WARNING_MISMATCH);
661
701
  }
662
702
  }
663
703
  function validateProfileQuirks(profile, registry, format) {
@@ -666,6 +706,7 @@ function validateProfileQuirks(profile, registry, format) {
666
706
  }
667
707
 
668
708
  // src/astm/quirk.ts
709
+ var ALL_QUIRK_KINDS = Object.freeze(["Result"]);
669
710
  var ASTM_QUIRKS = Object.freeze({
670
711
  "unknown-escape": Object.freeze({
671
712
  name: "unknown-escape",
@@ -719,17 +760,14 @@ function applyQuirk(quirk, records) {
719
760
  }
720
761
  function generateAstmQuirk(options) {
721
762
  const seed = options.seed ?? 0;
722
- const kind = "Result";
763
+ const kind = resolveKind(ALL_QUIRK_KINDS, options.kind ?? "Result");
723
764
  const descriptor = resolveQuirk(ASTM_QUIRKS, "astm", options.quirk);
724
765
  const clean = generateAstmResult({ seed });
725
766
  const content = applyQuirk(options.quirk, clean);
726
767
  if (content === clean) {
727
- throw new Error(
728
- `generateAstmQuirk: quirk "${options.quirk}" found no structural anchor in a ${kind} report at seed ${seed} \u2014 refusing to emit a fixture that does not carry the intended deviation.`
729
- );
768
+ throw new SynthError(SYNTH_FATAL_CODES.SYNTH_QUIRK_ANCHOR_ABSENT);
730
769
  }
731
770
  assertIntendedWarnings(
732
- descriptor.name,
733
771
  descriptor.intendedWarnings,
734
772
  parseAstmRecords(content).warnings.map((w) => String(w.code))
735
773
  );
@@ -775,6 +813,7 @@ var ALL_ASTM_QUIRKS = Object.freeze(
775
813
  function astmQuirkCorpus(options) {
776
814
  const quirks = options.profile ? validateProfileQuirks(options.profile, ASTM_QUIRKS, "astm") : options.quirks ?? ALL_ASTM_QUIRKS;
777
815
  const names = quirks.length > 0 ? quirks : ALL_ASTM_QUIRKS;
816
+ for (const name2 of names) resolveQuirk(ASTM_QUIRKS, "astm", name2);
778
817
  const count = options.count ?? names.length;
779
818
  const seedStream = createRng(options.seed);
780
819
  const artifacts = Array.from({ length: count }, (_unused, i) => {
@@ -796,7 +835,8 @@ var astmQuirkProfile = defineSynthProfile({
796
835
  });
797
836
 
798
837
  // src/astm/index.ts
799
- var DEFAULT_MIX = Object.freeze(["Result", "Order"]);
838
+ var ALL_KINDS = Object.freeze(["Result", "Order"]);
839
+ var DEFAULT_MIX = ALL_KINDS;
800
840
  function generateKind(kind, seed) {
801
841
  switch (kind) {
802
842
  case "Result":
@@ -806,7 +846,8 @@ function generateKind(kind, seed) {
806
846
  }
807
847
  }
808
848
  function astmCorpus(options) {
809
- const { seed, mix = DEFAULT_MIX } = options;
849
+ const { seed } = options;
850
+ const mix = resolveMix(ALL_KINDS, options.mix, DEFAULT_MIX);
810
851
  const count = options.count ?? mix.length;
811
852
  const seedStream = createRng(seed);
812
853
  const artifacts = Array.from({ length: count }, (_unused, i) => {