@cosyte/synth 0.1.8 → 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 +37 -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 +150 -15
  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 +150 -15
  10. package/dist/astm/index.mjs.map +1 -1
  11. package/dist/ccda/index.cjs +150 -15
  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 +150 -15
  16. package/dist/ccda/index.mjs.map +1 -1
  17. package/dist/deid/index.cjs +540 -28
  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 +540 -28
  22. package/dist/deid/index.mjs.map +1 -1
  23. package/dist/fhir/index.cjs +145 -12
  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 +145 -12
  28. package/dist/fhir/index.mjs.map +1 -1
  29. package/dist/hl7/index.cjs +569 -37
  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 +560 -38
  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 +145 -12
  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 +145 -12
  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 +145 -12
  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 +145 -12
  54. package/dist/x12/index.mjs.map +1 -1
  55. package/package.json +17 -6
package/dist/index.cjs CHANGED
@@ -62,7 +62,11 @@ var SYNTH_FATAL_CODES = Object.freeze({
62
62
  SYNTH_INVALID_DECIMAL: "SYNTH_INVALID_DECIMAL",
63
63
  /** An integer range was requested with its maximum below its minimum. Fatal. */
64
64
  SYNTH_INVALID_RANGE: "SYNTH_INVALID_RANGE",
65
- /** A value was drawn from an empty pool. Fatal, never a fabricated substitute. */
65
+ /**
66
+ * A value was drawn from an empty pool. Fatal, never a fabricated substitute. A corpus given an
67
+ * empty `mix`, `triggers` or `quirks` list (or a profile whose `quirks` is an empty list) raises it
68
+ * too: there is no kind to cycle through, and an empty list is never read as the default.
69
+ */
66
70
  SYNTH_EMPTY_POOL: "SYNTH_EMPTY_POOL",
67
71
  /** A `defineSynthProfile` spec was not usable (a missing or blank `name`). Fatal. */
68
72
  SYNTH_INVALID_PROFILE: "SYNTH_INVALID_PROFILE",
@@ -81,7 +85,21 @@ var SYNTH_FATAL_CODES = Object.freeze({
81
85
  * apart without matching message text. Fatal, and raised **before** anything is generated: a
82
86
  * mislabelled artifact is worse than no artifact.
83
87
  */
84
- SYNTH_PROFILE_NOT_GENERATED: "SYNTH_PROFILE_NOT_GENERATED"
88
+ SYNTH_PROFILE_NOT_GENERATED: "SYNTH_PROFILE_NOT_GENERATED",
89
+ /**
90
+ * The sibling parser a generator builds through is not installed. Raised on the first call that
91
+ * needs it, by both builds, only when the missing package is the parser itself: a missing
92
+ * dependency of an installed parser is thrown as Node.js raised it. The error carries the parser's
93
+ * package name on `peer`, a message from {@link SYNTH_PEER_MESSAGES} that names its install
94
+ * command, and the error Node.js raised on `cause`.
95
+ */
96
+ SYNTH_PEER_NOT_INSTALLED: "SYNTH_PEER_NOT_INSTALLED",
97
+ /**
98
+ * An HL7 v2 `ACK` was asked for an inbound message that carries no MSH-10 message control id.
99
+ * MSA-2 must echo that id, and an acknowledgment that cannot be matched to the message it answers
100
+ * is not a fixture worth having, so nothing is generated.
101
+ */
102
+ SYNTH_ACK_UNCORRELATED: "SYNTH_ACK_UNCORRELATED"
85
103
  });
86
104
  var SYNTH_FATAL_MESSAGES = Object.freeze({
87
105
  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.",
@@ -94,18 +112,38 @@ var SYNTH_FATAL_MESSAGES = Object.freeze({
94
112
  SYNTH_EMPTY_POOL: "A value was drawn from an empty pool.",
95
113
  SYNTH_INVALID_PROFILE: "defineSynthProfile requires a non-empty string name.",
96
114
  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.",
97
- 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."
115
+ 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.",
116
+ SYNTH_PEER_NOT_INSTALLED: "A sibling @cosyte parser this generator builds through is not installed. Install it beside @cosyte/synth.",
117
+ SYNTH_ACK_UNCORRELATED: (
118
+ // Stryker disable next-line all: a module-level table runs once, at import; the docs test holds it.
119
+ "The inbound message has no MSH-10 control id for an ACK to echo in MSA-2."
120
+ )
121
+ });
122
+ var SYNTH_PEER_MESSAGES = Object.freeze({
123
+ "@cosyte/hl7": "@cosyte/hl7 is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/hl7",
124
+ "@cosyte/fhir": "@cosyte/fhir is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/fhir",
125
+ "@cosyte/ccda": "@cosyte/ccda is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/ccda",
126
+ "@cosyte/x12": "@cosyte/x12 is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/x12",
127
+ "@cosyte/ncpdp": "@cosyte/ncpdp is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/ncpdp",
128
+ "@cosyte/astm": "@cosyte/astm is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/astm",
129
+ "@cosyte/deid": "@cosyte/deid is not installed, and this generator builds through it. Install it beside @cosyte/synth: npm install @cosyte/deid"
98
130
  });
99
131
  var SynthError = class extends Error {
100
132
  /** The stable fatal code. */
101
133
  code;
102
134
  /**
103
135
  * @param code - The stable {@link SynthFatalCode}. The message comes from the frozen registry.
136
+ * @param options - The error that caused this one, and for a missing parser its package.
104
137
  */
105
- constructor(code) {
106
- super(SYNTH_FATAL_MESSAGES[code]);
138
+ constructor(code, options = {}) {
139
+ const peer = code === SYNTH_FATAL_CODES.SYNTH_PEER_NOT_INSTALLED ? options.peer : void 0;
140
+ super(
141
+ peer === void 0 ? SYNTH_FATAL_MESSAGES[code] : SYNTH_PEER_MESSAGES[peer],
142
+ "cause" in options ? { cause: options.cause } : void 0
143
+ );
107
144
  this.name = "SynthError";
108
145
  this.code = code;
146
+ if (peer !== void 0) Object.defineProperty(this, "peer", { value: peer, enumerable: true });
109
147
  }
110
148
  };
111
149
 
@@ -191,7 +229,7 @@ function luhnMod10(digits) {
191
229
  if (d < 0 || d > 9) continue;
192
230
  if (double) {
193
231
  d *= 2;
194
- if (d > 9) d -= 9;
232
+ if (d >= 10) d -= 9;
195
233
  }
196
234
  sum += d;
197
235
  double = !double;
@@ -248,9 +286,7 @@ function isItinFormatted(value) {
248
286
  return ITIN_GROUP_RANGES.some((range) => group >= range.min && group <= range.max);
249
287
  }
250
288
  function isSyntheticPhone(value) {
251
- const digits = value.replace(/\D/g, "");
252
- const tail = digits.slice(-7);
253
- return /^555 ?01\d\d$/.test(tail) || /^55501\d\d$/.test(tail);
289
+ return /55501\d\d$/.test(value.replace(/\D/g, ""));
254
290
  }
255
291
  function isSyntheticEmail(value) {
256
292
  const at = value.lastIndexOf("@");
@@ -329,7 +365,7 @@ var SYNTHETIC_CITY_NAMES = Object.freeze([
329
365
  ]);
330
366
 
331
367
  // src/safe/providers.ts
332
- function ssn(rng, block = "never-issued") {
368
+ function ssn(rng, block) {
333
369
  if (block === "advertising") {
334
370
  return `987-00-432${String(rng.int(0, 9))}`;
335
371
  }
@@ -456,6 +492,66 @@ var US_STATES = Object.freeze([
456
492
  "WY"
457
493
  ]);
458
494
 
495
+ // src/safe/animal-code.ts
496
+ var ANIMAL_CODE_SYSTEM = "99COSYTE";
497
+ function animalCode(value, text) {
498
+ return Object.freeze({ code: value, text, system: ANIMAL_CODE_SYSTEM });
499
+ }
500
+ function animalSpecies(value, text, breeds) {
501
+ return Object.freeze({ ...animalCode(value, text), breeds: Object.freeze([...breeds]) });
502
+ }
503
+
504
+ // src/safe/animal.ts
505
+ var SYNTHETIC_ANIMAL_SPECIES = Object.freeze([
506
+ animalSpecies("DOG", "Dog", [
507
+ animalCode("DOG-LAB", "Labrador Retriever"),
508
+ animalCode("DOG-BGL", "Beagle"),
509
+ animalCode("DOG-MIX", "Mixed breed dog")
510
+ ]),
511
+ animalSpecies("CAT", "Cat", [animalCode("CAT-DSH", "Domestic Shorthair"), animalCode("CAT-SIA", "Siamese")]),
512
+ animalSpecies("HORSE", "Horse", [animalCode("HRS-QTR", "Quarter Horse"), animalCode("HRS-TB", "Thoroughbred")]),
513
+ animalSpecies("CATTLE", "Cattle", [animalCode("CTL-HOL", "Holstein"), animalCode("CTL-ANG", "Angus")])
514
+ ]);
515
+ var SYNTHETIC_PET_NAMES = Object.freeze([
516
+ "Fixturepaw",
517
+ "Mockwhisker",
518
+ "Stubtail",
519
+ "Seedpup",
520
+ "Testbiscuit",
521
+ "Placepurr",
522
+ "Synthfur",
523
+ "Dummymane",
524
+ "Examplehoof",
525
+ "Fauxfluff",
526
+ "Samplesnout",
527
+ "Voidwag"
528
+ ]);
529
+ var MICROCHIP_TEST_PREFIX = "999";
530
+ function petName(rng) {
531
+ return rng.pick(SYNTHETIC_PET_NAMES);
532
+ }
533
+ function animalBreed(rng) {
534
+ const picked = rng.pick(SYNTHETIC_ANIMAL_SPECIES);
535
+ const { breeds, ...bare } = picked;
536
+ return { species: Object.freeze(bare), breed: rng.pick(breeds) };
537
+ }
538
+ function microchip(rng) {
539
+ return `${MICROCHIP_TEST_PREFIX}${rng.digits(12)}`;
540
+ }
541
+ function isSyntheticMicrochip(value) {
542
+ return new RegExp(`^${MICROCHIP_TEST_PREFIX}\\d{12}$`).test(value);
543
+ }
544
+ function animalBirthDate(rng, onDate) {
545
+ const year = Number(onDate.slice(0, 4));
546
+ const month = Number(onDate.slice(4, 6)) - 1;
547
+ const day = Number(onDate.slice(6, 8));
548
+ const latest = Date.UTC(year, month, day);
549
+ const earliest = Date.UTC(year - 20, month, day);
550
+ const span = Math.round((latest - earliest) / 864e5);
551
+ const born = new Date(latest - rng.int(0, span) * 864e5);
552
+ return born.toISOString().slice(0, 10).replace(/-/g, "");
553
+ }
554
+
459
555
  // src/safe/index.ts
460
556
  var safe = Object.freeze({
461
557
  ssn,
@@ -469,7 +565,11 @@ var safe = Object.freeze({
469
565
  address,
470
566
  dateYmd,
471
567
  npi,
472
- dea
568
+ dea,
569
+ petName,
570
+ animalBreed,
571
+ microchip,
572
+ animalBirthDate
473
573
  });
474
574
  function makeCorpus(seed, artifacts, quirks = []) {
475
575
  const counts = {};
@@ -500,7 +600,7 @@ function defineSynthProfile(spec) {
500
600
  name: spec.name,
501
601
  ...spec.givenNames ? { givenNames: Object.freeze([...spec.givenNames]) } : {},
502
602
  ...spec.familyNames ? { familyNames: Object.freeze([...spec.familyNames]) } : {},
503
- quirks: Object.freeze([...spec.quirks ?? []])
603
+ ...spec.quirks !== void 0 ? { quirks: Object.freeze([...spec.quirks]) } : {}
504
604
  });
505
605
  }
506
606
 
@@ -542,6 +642,7 @@ function assertIntendedWarnings(intendedWarnings, bareWarnings) {
542
642
  }
543
643
  }
544
644
  function validateProfileQuirks(profile, registry, format) {
645
+ if (profile.quirks === void 0) return Object.keys(registry);
545
646
  for (const name2 of profile.quirks) resolveQuirk(registry, format, name2);
546
647
  return profile.quirks;
547
648
  }
@@ -558,25 +659,32 @@ function resolveMix(allowed, requested, fallback) {
558
659
  }
559
660
 
560
661
  // src/index.ts
561
- var VERSION = "0.1.8";
662
+ var VERSION = "0.1.10";
562
663
 
664
+ exports.ANIMAL_CODE_SYSTEM = ANIMAL_CODE_SYSTEM;
563
665
  exports.DEA_REGISTRANT_TYPES = DEA_REGISTRANT_TYPES;
564
666
  exports.DOC_V6_PREFIX = DOC_V6_PREFIX;
565
667
  exports.ITIN_GROUP_RANGES = ITIN_GROUP_RANGES;
668
+ exports.MICROCHIP_TEST_PREFIX = MICROCHIP_TEST_PREFIX;
566
669
  exports.NPI_LUHN_PREFIX = NPI_LUHN_PREFIX;
567
670
  exports.PROFILE_QUIRK_APPLIED = PROFILE_QUIRK_APPLIED;
568
671
  exports.RESERVED_EMAIL_DOMAINS = RESERVED_EMAIL_DOMAINS;
672
+ exports.SYNTHETIC_ANIMAL_SPECIES = SYNTHETIC_ANIMAL_SPECIES;
569
673
  exports.SYNTHETIC_ASSIGNING_AUTHORITY = SYNTHETIC_ASSIGNING_AUTHORITY;
570
674
  exports.SYNTHETIC_CITY_NAMES = SYNTHETIC_CITY_NAMES;
571
675
  exports.SYNTHETIC_FAMILY_NAMES = SYNTHETIC_FAMILY_NAMES;
572
676
  exports.SYNTHETIC_GIVEN_NAMES = SYNTHETIC_GIVEN_NAMES;
677
+ exports.SYNTHETIC_PET_NAMES = SYNTHETIC_PET_NAMES;
573
678
  exports.SYNTHETIC_STREET_NAMES = SYNTHETIC_STREET_NAMES;
574
679
  exports.SYNTH_FATAL_CODES = SYNTH_FATAL_CODES;
575
680
  exports.SYNTH_FATAL_MESSAGES = SYNTH_FATAL_MESSAGES;
681
+ exports.SYNTH_PEER_MESSAGES = SYNTH_PEER_MESSAGES;
576
682
  exports.SynthError = SynthError;
577
683
  exports.TEST_NET_V4_PREFIXES = TEST_NET_V4_PREFIXES;
578
684
  exports.VERSION = VERSION;
579
685
  exports.address = address;
686
+ exports.animalBirthDate = animalBirthDate;
687
+ exports.animalBreed = animalBreed;
580
688
  exports.assertIntendedWarnings = assertIntendedWarnings;
581
689
  exports.createRng = createRng;
582
690
  exports.dateYmd = dateYmd;
@@ -591,14 +699,17 @@ exports.isItinFormatted = isItinFormatted;
591
699
  exports.isSyntheticDea = isSyntheticDea;
592
700
  exports.isSyntheticEmail = isSyntheticEmail;
593
701
  exports.isSyntheticIp = isSyntheticIp;
702
+ exports.isSyntheticMicrochip = isSyntheticMicrochip;
594
703
  exports.isSyntheticNpi = isSyntheticNpi;
595
704
  exports.isSyntheticPhone = isSyntheticPhone;
596
705
  exports.isSyntheticSsn = isSyntheticSsn;
597
706
  exports.luhnMod10 = luhnMod10;
598
707
  exports.makeCorpus = makeCorpus;
708
+ exports.microchip = microchip;
599
709
  exports.name = name;
600
710
  exports.npi = npi;
601
711
  exports.npiCheckDigit = npiCheckDigit;
712
+ exports.petName = petName;
602
713
  exports.phone = phone;
603
714
  exports.profileTolerated = profileTolerated;
604
715
  exports.resolveKind = resolveKind;