@cosyte/synth 0.0.2 → 0.0.4

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 +321 -0
  2. package/README.md +13 -4
  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
@@ -31,6 +31,45 @@ function sfc32Next(s) {
31
31
  return t >>> 0;
32
32
  }
33
33
 
34
+ // src/codes.ts
35
+ var SYNTH_FATAL_CODES = {
36
+ /** An integer range was requested with its maximum below its minimum. Fatal. */
37
+ SYNTH_INVALID_RANGE: "SYNTH_INVALID_RANGE",
38
+ /** A value was drawn from an empty pool. Fatal — never a fabricated substitute. */
39
+ SYNTH_EMPTY_POOL: "SYNTH_EMPTY_POOL",
40
+ /**
41
+ * A caller-supplied selector (a message kind, a document type, a corpus mix entry, a claim
42
+ * variant, a Bundle type, a resource profile) is not in the closed set that governs it. Fatal —
43
+ * see `resolveKind`: a selector union is erased at run time, and a selector that falls through
44
+ * either mislabels the fixture or hands the value to a peer builder that quotes it back.
45
+ */
46
+ SYNTH_UNSUPPORTED_KIND: "SYNTH_UNSUPPORTED_KIND"
47
+ };
48
+ var SYNTH_FATAL_MESSAGES = Object.freeze({
49
+ 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.",
50
+ 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).",
51
+ 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.",
52
+ 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.",
53
+ SYNTH_UNMAPPED_CODE_SYSTEM: "The concept's code-system URI has no OID mapping in the C-CDA example-code table.",
54
+ SYNTH_INVALID_DECIMAL: "The value could not be read as an X12 decimal.",
55
+ SYNTH_INVALID_RANGE: "An integer range was requested with its maximum below its minimum.",
56
+ SYNTH_EMPTY_POOL: "A value was drawn from an empty pool.",
57
+ SYNTH_INVALID_PROFILE: "defineSynthProfile requires a non-empty string name.",
58
+ 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."
59
+ });
60
+ var SynthError = class extends Error {
61
+ /** The stable fatal code. */
62
+ code;
63
+ /**
64
+ * @param code - The stable {@link SynthFatalCode}. The message comes from the frozen registry.
65
+ */
66
+ constructor(code) {
67
+ super(SYNTH_FATAL_MESSAGES[code]);
68
+ this.name = "SynthError";
69
+ this.code = code;
70
+ }
71
+ };
72
+
34
73
  // src/rng/rng.ts
35
74
  var Sfc32Rng = class {
36
75
  seed;
@@ -48,7 +87,7 @@ var Sfc32Rng = class {
48
87
  return this.nextUint32() / 4294967296;
49
88
  }
50
89
  int(min, max) {
51
- if (max < min) throw new RangeError(`Rng.int: max (${String(max)}) < min (${String(min)})`);
90
+ if (max < min) throw new SynthError(SYNTH_FATAL_CODES.SYNTH_INVALID_RANGE);
52
91
  const span = max - min + 1;
53
92
  return min + Math.floor(this.float() * span);
54
93
  }
@@ -56,7 +95,7 @@ var Sfc32Rng = class {
56
95
  return this.float() < p;
57
96
  }
58
97
  pick(items) {
59
- if (items.length === 0) throw new RangeError("Rng.pick: empty array");
98
+ if (items.length === 0) throw new SynthError(SYNTH_FATAL_CODES.SYNTH_EMPTY_POOL);
60
99
  return items[this.int(0, items.length - 1)];
61
100
  }
62
101
  digits(n) {
@@ -741,7 +780,19 @@ var EXAMPLE_ENCOUNTER_CLASSES = Object.freeze([
741
780
  Object.freeze({ system: SYSTEM.V3_ACT_CODE, code: "IMP", display: "inpatient encounter" })
742
781
  ]);
743
782
 
783
+ // src/select.ts
784
+ function resolveKind(allowed, requested) {
785
+ const match = allowed.find((value) => value === requested);
786
+ if (match === void 0) throw new SynthError(SYNTH_FATAL_CODES.SYNTH_UNSUPPORTED_KIND);
787
+ return match;
788
+ }
789
+ function resolveMix(allowed, requested, fallback) {
790
+ if (requested === void 0) return fallback;
791
+ return requested.map((entry) => resolveKind(allowed, entry));
792
+ }
793
+
744
794
  // src/fhir/patient.ts
795
+ var PATIENT_PROFILES = Object.freeze(["base", "us-core"]);
745
796
  function ombExtension(url, category) {
746
797
  return complex([
747
798
  prop("url", str(url)),
@@ -755,7 +806,8 @@ function ombExtension(url, category) {
755
806
  ]);
756
807
  }
757
808
  function generatePatient(options = {}) {
758
- const { seed = 0, profile = "base" } = options;
809
+ const { seed = 0 } = options;
810
+ const profile = resolveKind(PATIENT_PROFILES, options.profile ?? "base");
759
811
  const rng = createRng(seed);
760
812
  const id = fhirPatientIdentity(rng);
761
813
  const usCore = profile === "us-core";
@@ -1172,6 +1224,11 @@ function roundTrip(resource, options = {}) {
1172
1224
  }
1173
1225
 
1174
1226
  // src/fhir/bundle.ts
1227
+ var BUNDLE_TYPES = Object.freeze([
1228
+ "collection",
1229
+ "transaction",
1230
+ "document"
1231
+ ]);
1175
1232
  function resourceTypeOf(resource) {
1176
1233
  const rt = resource.properties.find((p) => p.name === "resourceType");
1177
1234
  return rt !== void 0 && rt.value.kind === "primitive" ? String(rt.value.value) : "Resource";
@@ -1273,7 +1330,8 @@ function documentSections(urls) {
1273
1330
  ];
1274
1331
  }
1275
1332
  function generateBundle(options = {}) {
1276
- const { seed = 0, type = "collection" } = options;
1333
+ const { seed = 0 } = options;
1334
+ const type = resolveKind(BUNDLE_TYPES, options.type ?? "collection");
1277
1335
  const rng = createRng(seed);
1278
1336
  const spine = buildSpine(rng);
1279
1337
  const members = type === "document" ? [
@@ -1324,6 +1382,21 @@ function generateBundle(options = {}) {
1324
1382
  props.push(prop("entry", list(entries)));
1325
1383
  return complex(props);
1326
1384
  }
1385
+ var ALL_KINDS = Object.freeze([
1386
+ "Patient",
1387
+ "USCorePatient",
1388
+ "Condition",
1389
+ "ObservationLab",
1390
+ "VitalSign",
1391
+ "MedicationRequest",
1392
+ "Encounter",
1393
+ "Immunization",
1394
+ "AllergyIntolerance",
1395
+ "Procedure",
1396
+ "DiagnosticReport",
1397
+ "Bundle",
1398
+ "DocumentBundle"
1399
+ ]);
1327
1400
  var DEFAULT_MIX = Object.freeze([
1328
1401
  "USCorePatient",
1329
1402
  "Condition",
@@ -1369,7 +1442,7 @@ function generateKind(kind, seed) {
1369
1442
  }
1370
1443
  function fhirCorpus(options) {
1371
1444
  const { seed, count = 1 } = options;
1372
- const kinds = options.mix ?? DEFAULT_MIX;
1445
+ const kinds = resolveMix(ALL_KINDS, options.mix, DEFAULT_MIX);
1373
1446
  const seedStream = createRng(seed);
1374
1447
  const artifacts = Array.from({ length: count }, (_unused, i) => {
1375
1448
  const kind = kinds[i % kinds.length] ?? "USCorePatient";