@cosyte/synth 0.1.9 → 0.1.10

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 (55) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +28 -17
  3. package/dist/animal-code-Bdl_9Jma.d.cts +30 -0
  4. package/dist/animal-code-Bdl_9Jma.d.ts +30 -0
  5. package/dist/astm/index.cjs +147 -17
  6. package/dist/astm/index.cjs.map +1 -1
  7. package/dist/astm/index.d.cts +22 -9
  8. package/dist/astm/index.d.ts +22 -9
  9. package/dist/astm/index.mjs +147 -17
  10. package/dist/astm/index.mjs.map +1 -1
  11. package/dist/ccda/index.cjs +147 -17
  12. package/dist/ccda/index.cjs.map +1 -1
  13. package/dist/ccda/index.d.cts +12 -3
  14. package/dist/ccda/index.d.ts +12 -3
  15. package/dist/ccda/index.mjs +147 -17
  16. package/dist/ccda/index.mjs.map +1 -1
  17. package/dist/deid/index.cjs +537 -30
  18. package/dist/deid/index.cjs.map +1 -1
  19. package/dist/deid/index.d.cts +2 -1
  20. package/dist/deid/index.d.ts +2 -1
  21. package/dist/deid/index.mjs +537 -30
  22. package/dist/deid/index.mjs.map +1 -1
  23. package/dist/fhir/index.cjs +142 -14
  24. package/dist/fhir/index.cjs.map +1 -1
  25. package/dist/fhir/index.d.cts +4 -1
  26. package/dist/fhir/index.d.ts +4 -1
  27. package/dist/fhir/index.mjs +142 -14
  28. package/dist/fhir/index.mjs.map +1 -1
  29. package/dist/hl7/index.cjs +566 -39
  30. package/dist/hl7/index.cjs.map +1 -1
  31. package/dist/hl7/index.d.cts +402 -111
  32. package/dist/hl7/index.d.ts +402 -111
  33. package/dist/hl7/index.mjs +557 -40
  34. package/dist/hl7/index.mjs.map +1 -1
  35. package/dist/index.cjs +124 -13
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.d.cts +183 -10
  38. package/dist/index.d.ts +183 -10
  39. package/dist/index.mjs +115 -14
  40. package/dist/index.mjs.map +1 -1
  41. package/dist/ncpdp/index.cjs +142 -14
  42. package/dist/ncpdp/index.cjs.map +1 -1
  43. package/dist/ncpdp/index.d.cts +4 -1
  44. package/dist/ncpdp/index.d.ts +4 -1
  45. package/dist/ncpdp/index.mjs +142 -14
  46. package/dist/ncpdp/index.mjs.map +1 -1
  47. package/dist/{quirk-BfObsiWV.d.ts → quirk-CzknuYUo.d.ts} +16 -5
  48. package/dist/{quirk-BCSs1jPt.d.cts → quirk-Q5AxzHSC.d.cts} +16 -5
  49. package/dist/x12/index.cjs +142 -14
  50. package/dist/x12/index.cjs.map +1 -1
  51. package/dist/x12/index.d.cts +4 -1
  52. package/dist/x12/index.d.ts +4 -1
  53. package/dist/x12/index.mjs +142 -14
  54. package/dist/x12/index.mjs.map +1 -1
  55. package/package.json +7 -4
package/dist/index.mjs CHANGED
@@ -60,7 +60,11 @@ var SYNTH_FATAL_CODES = Object.freeze({
60
60
  SYNTH_INVALID_DECIMAL: "SYNTH_INVALID_DECIMAL",
61
61
  /** An integer range was requested with its maximum below its minimum. Fatal. */
62
62
  SYNTH_INVALID_RANGE: "SYNTH_INVALID_RANGE",
63
- /** A value was drawn from an empty pool. Fatal, never a fabricated substitute. */
63
+ /**
64
+ * A value was drawn from an empty pool. Fatal, never a fabricated substitute. A corpus given an
65
+ * empty `mix`, `triggers` or `quirks` list (or a profile whose `quirks` is an empty list) raises it
66
+ * too: there is no kind to cycle through, and an empty list is never read as the default.
67
+ */
64
68
  SYNTH_EMPTY_POOL: "SYNTH_EMPTY_POOL",
65
69
  /** A `defineSynthProfile` spec was not usable (a missing or blank `name`). Fatal. */
66
70
  SYNTH_INVALID_PROFILE: "SYNTH_INVALID_PROFILE",
@@ -79,7 +83,21 @@ var SYNTH_FATAL_CODES = Object.freeze({
79
83
  * apart without matching message text. Fatal, and raised **before** anything is generated: a
80
84
  * mislabelled artifact is worse than no artifact.
81
85
  */
82
- SYNTH_PROFILE_NOT_GENERATED: "SYNTH_PROFILE_NOT_GENERATED"
86
+ SYNTH_PROFILE_NOT_GENERATED: "SYNTH_PROFILE_NOT_GENERATED",
87
+ /**
88
+ * The sibling parser a generator builds through is not installed. Raised on the first call that
89
+ * needs it, by both builds, only when the missing package is the parser itself: a missing
90
+ * dependency of an installed parser is thrown as Node.js raised it. The error carries the parser's
91
+ * package name on `peer`, a message from {@link SYNTH_PEER_MESSAGES} that names its install
92
+ * command, and the error Node.js raised on `cause`.
93
+ */
94
+ SYNTH_PEER_NOT_INSTALLED: "SYNTH_PEER_NOT_INSTALLED",
95
+ /**
96
+ * An HL7 v2 `ACK` was asked for an inbound message that carries no MSH-10 message control id.
97
+ * MSA-2 must echo that id, and an acknowledgment that cannot be matched to the message it answers
98
+ * is not a fixture worth having, so nothing is generated.
99
+ */
100
+ SYNTH_ACK_UNCORRELATED: "SYNTH_ACK_UNCORRELATED"
83
101
  });
84
102
  var SYNTH_FATAL_MESSAGES = Object.freeze({
85
103
  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.",
@@ -92,18 +110,38 @@ var SYNTH_FATAL_MESSAGES = Object.freeze({
92
110
  SYNTH_EMPTY_POOL: "A value was drawn from an empty pool.",
93
111
  SYNTH_INVALID_PROFILE: "defineSynthProfile requires a non-empty string name.",
94
112
  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.",
95
- SYNTH_PROFILE_NOT_GENERATED: "The requested profile is published by the adopted implementation guide, and this build does not generate it. The coverage surface reports, per adopted profile, whether it is generated."
113
+ SYNTH_PROFILE_NOT_GENERATED: "The requested profile is published by the adopted implementation guide, and this build does not generate it. The coverage surface reports, per adopted profile, whether it is generated.",
114
+ SYNTH_PEER_NOT_INSTALLED: "A sibling @cosyte parser this generator builds through is not installed. Install it beside @cosyte/synth.",
115
+ SYNTH_ACK_UNCORRELATED: (
116
+ // Stryker disable next-line all: a module-level table runs once, at import; the docs test holds it.
117
+ "The inbound message has no MSH-10 control id for an ACK to echo in MSA-2."
118
+ )
119
+ });
120
+ var SYNTH_PEER_MESSAGES = Object.freeze({
121
+ "@cosyte/hl7": "@cosyte/hl7 is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/hl7",
122
+ "@cosyte/fhir": "@cosyte/fhir is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/fhir",
123
+ "@cosyte/ccda": "@cosyte/ccda is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/ccda",
124
+ "@cosyte/x12": "@cosyte/x12 is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/x12",
125
+ "@cosyte/ncpdp": "@cosyte/ncpdp is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/ncpdp",
126
+ "@cosyte/astm": "@cosyte/astm is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/astm",
127
+ "@cosyte/deid": "@cosyte/deid is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/deid"
96
128
  });
97
129
  var SynthError = class extends Error {
98
130
  /** The stable fatal code. */
99
131
  code;
100
132
  /**
101
133
  * @param code - The stable {@link SynthFatalCode}. The message comes from the frozen registry.
134
+ * @param options - The error that caused this one, and for a missing parser its package.
102
135
  */
103
- constructor(code) {
104
- super(SYNTH_FATAL_MESSAGES[code]);
136
+ constructor(code, options = {}) {
137
+ const peer = code === SYNTH_FATAL_CODES.SYNTH_PEER_NOT_INSTALLED ? options.peer : void 0;
138
+ super(
139
+ peer === void 0 ? SYNTH_FATAL_MESSAGES[code] : SYNTH_PEER_MESSAGES[peer],
140
+ "cause" in options ? { cause: options.cause } : void 0
141
+ );
105
142
  this.name = "SynthError";
106
143
  this.code = code;
144
+ if (peer !== void 0) Object.defineProperty(this, "peer", { value: peer, enumerable: true });
107
145
  }
108
146
  };
109
147
 
@@ -189,7 +227,7 @@ function luhnMod10(digits) {
189
227
  if (d < 0 || d > 9) continue;
190
228
  if (double) {
191
229
  d *= 2;
192
- if (d > 9) d -= 9;
230
+ if (d >= 10) d -= 9;
193
231
  }
194
232
  sum += d;
195
233
  double = !double;
@@ -246,9 +284,7 @@ function isItinFormatted(value) {
246
284
  return ITIN_GROUP_RANGES.some((range) => group >= range.min && group <= range.max);
247
285
  }
248
286
  function isSyntheticPhone(value) {
249
- const digits = value.replace(/\D/g, "");
250
- const tail = digits.slice(-7);
251
- return /^555 ?01\d\d$/.test(tail) || /^55501\d\d$/.test(tail);
287
+ return /55501\d\d$/.test(value.replace(/\D/g, ""));
252
288
  }
253
289
  function isSyntheticEmail(value) {
254
290
  const at = value.lastIndexOf("@");
@@ -327,7 +363,7 @@ var SYNTHETIC_CITY_NAMES = Object.freeze([
327
363
  ]);
328
364
 
329
365
  // src/safe/providers.ts
330
- function ssn(rng, block = "never-issued") {
366
+ function ssn(rng, block) {
331
367
  if (block === "advertising") {
332
368
  return `987-00-432${String(rng.int(0, 9))}`;
333
369
  }
@@ -454,6 +490,66 @@ var US_STATES = Object.freeze([
454
490
  "WY"
455
491
  ]);
456
492
 
493
+ // src/safe/animal-code.ts
494
+ var ANIMAL_CODE_SYSTEM = "99COSYTE";
495
+ function animalCode(value, text) {
496
+ return Object.freeze({ code: value, text, system: ANIMAL_CODE_SYSTEM });
497
+ }
498
+ function animalSpecies(value, text, breeds) {
499
+ return Object.freeze({ ...animalCode(value, text), breeds: Object.freeze([...breeds]) });
500
+ }
501
+
502
+ // src/safe/animal.ts
503
+ var SYNTHETIC_ANIMAL_SPECIES = Object.freeze([
504
+ animalSpecies("DOG", "Dog", [
505
+ animalCode("DOG-LAB", "Labrador Retriever"),
506
+ animalCode("DOG-BGL", "Beagle"),
507
+ animalCode("DOG-MIX", "Mixed breed dog")
508
+ ]),
509
+ animalSpecies("CAT", "Cat", [animalCode("CAT-DSH", "Domestic Shorthair"), animalCode("CAT-SIA", "Siamese")]),
510
+ animalSpecies("HORSE", "Horse", [animalCode("HRS-QTR", "Quarter Horse"), animalCode("HRS-TB", "Thoroughbred")]),
511
+ animalSpecies("CATTLE", "Cattle", [animalCode("CTL-HOL", "Holstein"), animalCode("CTL-ANG", "Angus")])
512
+ ]);
513
+ var SYNTHETIC_PET_NAMES = Object.freeze([
514
+ "Fixturepaw",
515
+ "Mockwhisker",
516
+ "Stubtail",
517
+ "Seedpup",
518
+ "Testbiscuit",
519
+ "Placepurr",
520
+ "Synthfur",
521
+ "Dummymane",
522
+ "Examplehoof",
523
+ "Fauxfluff",
524
+ "Samplesnout",
525
+ "Voidwag"
526
+ ]);
527
+ var MICROCHIP_TEST_PREFIX = "999";
528
+ function petName(rng) {
529
+ return rng.pick(SYNTHETIC_PET_NAMES);
530
+ }
531
+ function animalBreed(rng) {
532
+ const picked = rng.pick(SYNTHETIC_ANIMAL_SPECIES);
533
+ const { breeds, ...bare } = picked;
534
+ return { species: Object.freeze(bare), breed: rng.pick(breeds) };
535
+ }
536
+ function microchip(rng) {
537
+ return `${MICROCHIP_TEST_PREFIX}${rng.digits(12)}`;
538
+ }
539
+ function isSyntheticMicrochip(value) {
540
+ return new RegExp(`^${MICROCHIP_TEST_PREFIX}\\d{12}$`).test(value);
541
+ }
542
+ function animalBirthDate(rng, onDate) {
543
+ const year = Number(onDate.slice(0, 4));
544
+ const month = Number(onDate.slice(4, 6)) - 1;
545
+ const day = Number(onDate.slice(6, 8));
546
+ const latest = Date.UTC(year, month, day);
547
+ const earliest = Date.UTC(year - 20, month, day);
548
+ const span = Math.round((latest - earliest) / 864e5);
549
+ const born = new Date(latest - rng.int(0, span) * 864e5);
550
+ return born.toISOString().slice(0, 10).replace(/-/g, "");
551
+ }
552
+
457
553
  // src/safe/index.ts
458
554
  var safe = Object.freeze({
459
555
  ssn,
@@ -467,7 +563,11 @@ var safe = Object.freeze({
467
563
  address,
468
564
  dateYmd,
469
565
  npi,
470
- dea
566
+ dea,
567
+ petName,
568
+ animalBreed,
569
+ microchip,
570
+ animalBirthDate
471
571
  });
472
572
  function makeCorpus(seed, artifacts, quirks = []) {
473
573
  const counts = {};
@@ -498,7 +598,7 @@ function defineSynthProfile(spec) {
498
598
  name: spec.name,
499
599
  ...spec.givenNames ? { givenNames: Object.freeze([...spec.givenNames]) } : {},
500
600
  ...spec.familyNames ? { familyNames: Object.freeze([...spec.familyNames]) } : {},
501
- quirks: Object.freeze([...spec.quirks ?? []])
601
+ ...spec.quirks !== void 0 ? { quirks: Object.freeze([...spec.quirks]) } : {}
502
602
  });
503
603
  }
504
604
 
@@ -540,6 +640,7 @@ function assertIntendedWarnings(intendedWarnings, bareWarnings) {
540
640
  }
541
641
  }
542
642
  function validateProfileQuirks(profile, registry, format) {
643
+ if (profile.quirks === void 0) return Object.keys(registry);
543
644
  for (const name2 of profile.quirks) resolveQuirk(registry, format, name2);
544
645
  return profile.quirks;
545
646
  }
@@ -556,8 +657,8 @@ function resolveMix(allowed, requested, fallback) {
556
657
  }
557
658
 
558
659
  // src/index.ts
559
- var VERSION = "0.1.9";
660
+ var VERSION = "0.1.10";
560
661
 
561
- export { DEA_REGISTRANT_TYPES, DOC_V6_PREFIX, ITIN_GROUP_RANGES, NPI_LUHN_PREFIX, PROFILE_QUIRK_APPLIED, RESERVED_EMAIL_DOMAINS, SYNTHETIC_ASSIGNING_AUTHORITY, SYNTHETIC_CITY_NAMES, SYNTHETIC_FAMILY_NAMES, SYNTHETIC_GIVEN_NAMES, SYNTHETIC_STREET_NAMES, SYNTH_FATAL_CODES, SYNTH_FATAL_MESSAGES, SynthError, TEST_NET_V4_PREFIXES, VERSION, address, assertIntendedWarnings, createRng, dateYmd, dea, deaCheckDigit, defineSynthProfile, email, identifier, ipv4, ipv6, isItinFormatted, isSyntheticDea, isSyntheticEmail, isSyntheticIp, isSyntheticNpi, isSyntheticPhone, isSyntheticSsn, luhnMod10, makeCorpus, name, npi, npiCheckDigit, phone, profileTolerated, resolveKind, resolveMix, resolveQuirk, safe, sameCodeSet, sfc32Next, splitmix32, ssn, uuid, validateProfileQuirks };
662
+ export { ANIMAL_CODE_SYSTEM, DEA_REGISTRANT_TYPES, DOC_V6_PREFIX, ITIN_GROUP_RANGES, MICROCHIP_TEST_PREFIX, NPI_LUHN_PREFIX, PROFILE_QUIRK_APPLIED, RESERVED_EMAIL_DOMAINS, SYNTHETIC_ANIMAL_SPECIES, SYNTHETIC_ASSIGNING_AUTHORITY, SYNTHETIC_CITY_NAMES, SYNTHETIC_FAMILY_NAMES, SYNTHETIC_GIVEN_NAMES, SYNTHETIC_PET_NAMES, SYNTHETIC_STREET_NAMES, SYNTH_FATAL_CODES, SYNTH_FATAL_MESSAGES, SYNTH_PEER_MESSAGES, SynthError, TEST_NET_V4_PREFIXES, VERSION, address, animalBirthDate, animalBreed, assertIntendedWarnings, createRng, dateYmd, dea, deaCheckDigit, defineSynthProfile, email, identifier, ipv4, ipv6, isItinFormatted, isSyntheticDea, isSyntheticEmail, isSyntheticIp, isSyntheticMicrochip, isSyntheticNpi, isSyntheticPhone, isSyntheticSsn, luhnMod10, makeCorpus, microchip, name, npi, npiCheckDigit, petName, phone, profileTolerated, resolveKind, resolveMix, resolveQuirk, safe, sameCodeSet, sfc32Next, splitmix32, ssn, uuid, validateProfileQuirks };
562
663
  //# sourceMappingURL=index.mjs.map
563
664
  //# sourceMappingURL=index.mjs.map