@cosyte/x12 0.0.15 → 0.0.16

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.
package/dist/index.mjs CHANGED
@@ -45,6 +45,12 @@ var DELIMITER_POSITIONS = {
45
45
  component: 104,
46
46
  segment: 105
47
47
  };
48
+ function isVisibleDelimiterChar(c) {
49
+ const code = c.charCodeAt(0);
50
+ if (code < 32 || code === 127) return false;
51
+ if (/\s/u.test(c)) return false;
52
+ return true;
53
+ }
48
54
  function detectDelimiters(raw) {
49
55
  const fatalPosition = { segmentIndex: 0, interchangeIndex: 0 };
50
56
  const snip = snippet(raw);
@@ -68,19 +74,13 @@ function detectDelimiters(raw) {
68
74
  const repetition = raw.charAt(DELIMITER_POSITIONS.repetition);
69
75
  const component = raw.charAt(DELIMITER_POSITIONS.component);
70
76
  const segment = raw.charAt(DELIMITER_POSITIONS.segment);
71
- const isValidDelimiterChar = (c) => {
72
- const code = c.charCodeAt(0);
73
- if (code < 32 || code === 127) return false;
74
- if (/\s/u.test(c)) return false;
75
- return true;
76
- };
77
77
  for (const [name, ch] of [
78
78
  ["element", element],
79
79
  ["repetition", repetition],
80
80
  ["component", component],
81
81
  ["segment", segment]
82
82
  ]) {
83
- if (!isValidDelimiterChar(ch)) {
83
+ if (!isVisibleDelimiterChar(ch)) {
84
84
  throw new X12ParseError(
85
85
  FATAL_CODES.X12_INVALID_DELIMITERS,
86
86
  `Delimiter "${name}" at ISA byte ${String(DELIMITER_POSITIONS[name] + 1)} is whitespace, control, or empty.`,
@@ -222,7 +222,7 @@ var WARNING_MESSAGES = {
222
222
  X12_MISSING_REQUIRED_LOOP_2000B: 'Missing required loop "2000B" (Subscriber HL): no Subscriber HL precedes the CLM.',
223
223
  X12_MISSING_REQUIRED_LOOP_2010BA: 'Missing required loop "2010BA" (Subscriber Name): no Subscriber Name follows the Subscriber HL.',
224
224
  X12_MISSING_REQUIRED_LOOP_2010BB: 'Missing required loop "2010BB" (Payer Name): no Payer Name follows the Subscriber HL.',
225
- X12_837_UNKNOWN_VARIANT: "837 variant could not be resolved: ST-03's implementation convention reference is absent, empty, or not an 837 Technical Report Type 3 identifier this reader recognises, and no SVx service-line segment was present to fall back on. The set of references it recognises covers the professional, institutional and dental 837 guides HIPAA adopts at 45 CFR 162.1102 together with their published errata; it is NOT claimed to be exhaustive, and this message deliberately does not enumerate it, because a list here goes stale the moment a guide is added. A reference outside that set is not asserted to be invalid - all this code reports is that this reader could not turn it into a variant and had nothing to fall back on. The verbatim reference is preserved on the model; read it there rather than inferring what the sender meant.",
225
+ X12_837_UNKNOWN_VARIANT: "837 variant could not be resolved: ST-03's implementation convention reference is absent, empty, or not an 837 Technical Report Type 3 identifier this reader recognises, and no SVx service-line segment was present to fall back on. The set of references it recognises covers the professional, institutional and dental 837 guides HIPAA adopts at 45 CFR 162.1102 together with their published errata; it is NOT claimed to be exhaustive, and this message deliberately does not enumerate it, because a list here goes stale the moment a guide is added. A reference outside that set is not asserted to be invalid - all this code reports is that this reader could not turn it into a variant and had nothing to fall back on.",
226
226
  X12_837_AMBIGUOUS_VARIANT: "837 variant resolved from a service segment while the transaction body carries service segments of more than one variant: no caller `type` option was supplied and ST-03's implementation convention reference is absent, empty, or not an 837 Technical Report Type 3 identifier this reader recognises, so this reader fell back to the FIRST SV1 / SV2 / SV3 in the body, and a later one names a different variant. `submission.variant` is therefore a guess between contradictory evidence, and every claim and service line in the submission was read against it. Which service segment is the stray one is NOT decided here and is not derivable from the TR3s: this reader cannot tell a stray service segment from a conformant one, and the fallback takes the first regardless of whether any Loop 2400 was open at it, so an orphan segment decides the variant like any other. Read the bound literally, as a property of the RESOLUTION rather than of the document: this reports the fallback's own ambiguity, so a caller-supplied `type`, or an ST-03 this reader does turn into a variant, means no guess was made and this code is NOT raised however mixed the body is. Whatever else this reader raised on a document that reaches this code, it still raises, at the same position, and this one is added beside them. It is NOT a list of what else you will see, and it does not promise that any particular loss on such a document is reported at all. Re-read with the `type` option to decode the document against a variant you trust. The verbatim segments are preserved on the transaction set; read them there before acting on the submission's type.",
227
227
  X12_UNKNOWN_CLAIM_STATUS_CATEGORY: "Unknown claim status category (CSCC): the STC composite's first component is outside the bundled snapshot. The verbatim code is preserved on the status; only its description is unavailable.",
228
228
  X12_UNKNOWN_CLAIM_STATUS: "Unknown claim status code (CSC): the STC composite's second component is outside the bundled snapshot. The verbatim code is preserved on the status; only its description is unavailable.",
@@ -866,8 +866,11 @@ function boundSegmentId(first) {
866
866
  return SEGMENT_ID_SHAPE_RE.test(first) ? first : NON_SPEC_SEGMENT_ID;
867
867
  }
868
868
  function decodeSegment(raw, delimiters, emit, position) {
869
- const elements = Object.freeze(splitWithRelease(raw, delimiters.element));
870
- if (raw.length > 0 && raw.endsWith(RELEASE_CHAR)) {
869
+ const degenerate = delimiters.element === RELEASE_CHAR;
870
+ const elements = Object.freeze(
871
+ degenerate ? raw.split(delimiters.element) : splitWithRelease(raw, delimiters.element)
872
+ );
873
+ if (!degenerate && raw.length > 0 && raw.endsWith(RELEASE_CHAR)) {
871
874
  let trailingRun = 0;
872
875
  for (let j = raw.length - 1; j >= 0 && raw.charAt(j) === RELEASE_CHAR; j -= 1) trailingRun += 1;
873
876
  if (trailingRun % 2 === 1) {
@@ -2704,10 +2707,70 @@ function requireCallerString(value, at, refuse) {
2704
2707
  `${at}: every element value must be a string, but received ${describeCallerValue(value)}. Values are never coerced - a JavaScript number cannot carry a leading-zero identifier, so converting here could emit a different value than the caller sent. Convert at the call site.`
2705
2708
  );
2706
2709
  }
2710
+ var DELIMITER_ROLES = [
2711
+ ["element", "element separator"],
2712
+ ["repetition", "repetition separator"],
2713
+ ["component", "component separator"],
2714
+ ["segment", "segment terminator"]
2715
+ ];
2716
+ function requireEscapableDelimiters(delimiters, at, refuse) {
2717
+ const degenerate = DELIMITER_ROLES.filter(([role]) => delimiters[role] === RELEASE_CHAR).map(
2718
+ ([, name]) => name
2719
+ );
2720
+ if (degenerate.length === 0) return;
2721
+ const roles = degenerate.length === 1 ? `the ${degenerate[0] ?? ""}` : `the ${degenerate.slice(0, -1).join(", the ")} and the ${degenerate[degenerate.length - 1] ?? ""}`;
2722
+ refuse(
2723
+ `${at}: "${RELEASE_CHAR}" is the X12 release character and cannot also be ${roles}. An escape is written by prefixing "${RELEASE_CHAR}" to the byte it protects, so on this set the protection is emitted as structure; and a composite or a repetition joined with "${RELEASE_CHAR}" is emitted as an escape. Neither reads back, and no element value avoids it. Declare a delimiter set in which no role is "${RELEASE_CHAR}".`
2724
+ );
2725
+ }
2726
+ function requireWellShapedDelimiters(delimiters, at, refuse) {
2727
+ const REMEDY = `A delimiter occupies ONE fixed position of the ISA (ISA-11, ISA-16 and the position after it), so this set cannot be transmitted and this library's own parser would reject a document declaring it. Declare four distinct, visible, single-character delimiters.`;
2728
+ for (const [role, name] of DELIMITER_ROLES) {
2729
+ const value = delimiters[role];
2730
+ if (typeof value !== "string") {
2731
+ refuse(
2732
+ `${at}: the ${name} must be a string, but received ${describeCallerValue(value)}. Values are never coerced - a coerced delimiter frames the document while the release escape still compares against what you passed, so no element value is protected from it. ${REMEDY}`
2733
+ );
2734
+ }
2735
+ if (value.length !== 1) {
2736
+ refuse(
2737
+ `${at}: the ${name} must be exactly one character, but the declared value is ${value.length === 0 ? "empty" : `${String(value.length)} characters long`}. ${REMEDY}`
2738
+ );
2739
+ }
2740
+ if (!isVisibleDelimiterChar(value)) {
2741
+ refuse(
2742
+ `${at}: the ${name} must be a visible character, but the declared value is whitespace or a control character. ${REMEDY}`
2743
+ );
2744
+ }
2745
+ }
2746
+ for (const [i, [role, name]] of DELIMITER_ROLES.entries()) {
2747
+ const earlier = DELIMITER_ROLES.slice(0, i).find(([r]) => delimiters[r] === delimiters[role]);
2748
+ if (earlier !== void 0) {
2749
+ refuse(
2750
+ `${at}: the ${name} and the ${earlier[1]} are the same character. A reader cannot tell which role a character is playing. ${REMEDY}`
2751
+ );
2752
+ }
2753
+ }
2754
+ }
2707
2755
  function makeCallerEscaper(delimiters, at, refuse) {
2756
+ requireEscapableDelimiters(delimiters, at, refuse);
2757
+ requireWellShapedDelimiters(delimiters, at, refuse);
2708
2758
  return (value) => escapeRelease(requireCallerString(value, at, refuse), delimiters);
2709
2759
  }
2710
2760
 
2761
+ // src/builder/caller-control-number.ts
2762
+ function requireControlNumber(value, slot, field, at, refuse) {
2763
+ if (typeof value !== "string") {
2764
+ refuse(
2765
+ `${at}: ${field} must be a string, but received ${describeCallerValue(value)}. ${slot} is a required control number and this builder never coerces one, so nothing is emitted. Convert ${field} at the call site.`
2766
+ );
2767
+ }
2768
+ if (value !== "") return value;
2769
+ refuse(
2770
+ `${at}: ${field} is empty. ${slot} is a required control number and this builder never invents one, so nothing is emitted. Supply ${field}.`
2771
+ );
2772
+ }
2773
+
2711
2774
  // src/transactions/remit/build-835.ts
2712
2775
  function refuseSpec(message) {
2713
2776
  throw new Remit835BuildError(REMIT_835_BUILD_ERROR_CODES.X12_835_BUILD_INVALID_SPEC, message);
@@ -2752,6 +2815,27 @@ function build835(spec) {
2752
2815
  const senderQualifier = envelope.senderQualifier ?? "ZZ";
2753
2816
  const receiverQualifier = envelope.receiverQualifier ?? "ZZ";
2754
2817
  const usageIndicator = envelope.usageIndicator ?? "P";
2818
+ requireControlNumber(
2819
+ envelope.interchangeControlNumber,
2820
+ "ISA-13 / IEA-02",
2821
+ "interchangeControlNumber",
2822
+ "build835",
2823
+ refuseSpec
2824
+ );
2825
+ requireControlNumber(
2826
+ envelope.groupControlNumber,
2827
+ "GS-06 / GE-02",
2828
+ "groupControlNumber",
2829
+ "build835",
2830
+ refuseSpec
2831
+ );
2832
+ requireControlNumber(
2833
+ envelope.transactionSetControlNumber,
2834
+ "ST-02 / SE-02",
2835
+ "transactionSetControlNumber",
2836
+ "build835",
2837
+ refuseSpec
2838
+ );
2755
2839
  const interchangeControlNumber = padControl(envelope.interchangeControlNumber, 9);
2756
2840
  const isa = [
2757
2841
  "ISA",
@@ -3329,6 +3413,14 @@ function wireLookup(entries) {
3329
3413
  return Object.freeze(table);
3330
3414
  }
3331
3415
 
3416
+ // src/transactions/shared/st03.ts
3417
+ var noopWarningSink = (_w) => {
3418
+ };
3419
+ function decodeSt03(raw, delimiters, position) {
3420
+ if (raw === void 0) return void 0;
3421
+ return unescapeRelease(raw, delimiters, noopWarningSink, position);
3422
+ }
3423
+
3332
3424
  // src/transactions/claim/address-segments.ts
3333
3425
  function emitsStreetLines(address) {
3334
3426
  return address.lines.length > 0;
@@ -3387,9 +3479,14 @@ function get837Claims(delimiters, tx, opts) {
3387
3479
  if (tx.st.elements[1] !== "837") return void 0;
3388
3480
  const warnings = [];
3389
3481
  const body = tx.se === void 0 ? tx.segments.slice(1) : tx.segments.slice(1, -1);
3390
- const implementationConventionReference = tx.st.elements[3];
3482
+ const implementationConventionReferenceRaw = tx.st.elements[3];
3483
+ const implementationConventionReference = decodeSt03(
3484
+ implementationConventionReferenceRaw,
3485
+ delimiters,
3486
+ { segmentIndex: 0, transactionIndex: 0 }
3487
+ );
3391
3488
  const explicitType = opts?.type;
3392
- const variantFromIcr = implementationConventionReference !== void 0 && implementationConventionReference !== "" ? VARIANT_BY_ICR[implementationConventionReference] : void 0;
3489
+ const variantFromIcr = implementationConventionReferenceRaw !== void 0 && implementationConventionReferenceRaw !== "" ? VARIANT_BY_ICR[implementationConventionReferenceRaw] : void 0;
3393
3490
  let variantFromSegment;
3394
3491
  let serviceSegmentVariantsConflict = false;
3395
3492
  if (explicitType === void 0 && variantFromIcr === void 0) {
@@ -4640,6 +4737,27 @@ function buildClaim837(variant, spec) {
4640
4737
  const senderQualifier = envelope.senderQualifier ?? "ZZ";
4641
4738
  const receiverQualifier = envelope.receiverQualifier ?? "ZZ";
4642
4739
  const usageIndicator = envelope.usageIndicator ?? "P";
4740
+ requireControlNumber(
4741
+ envelope.interchangeControlNumber,
4742
+ "ISA-13 / IEA-02",
4743
+ "interchangeControlNumber",
4744
+ "build837",
4745
+ refuseSpec2
4746
+ );
4747
+ requireControlNumber(
4748
+ envelope.groupControlNumber,
4749
+ "GS-06 / GE-02",
4750
+ "groupControlNumber",
4751
+ "build837",
4752
+ refuseSpec2
4753
+ );
4754
+ requireControlNumber(
4755
+ envelope.transactionSetControlNumber,
4756
+ "ST-02 / SE-02",
4757
+ "transactionSetControlNumber",
4758
+ "build837",
4759
+ refuseSpec2
4760
+ );
4643
4761
  const interchangeControlNumber = padControl2(envelope.interchangeControlNumber, 9);
4644
4762
  const isa = [
4645
4763
  "ISA",
@@ -5811,6 +5929,27 @@ function build271(spec) {
5811
5929
  const senderQualifier = envelope.senderQualifier ?? "ZZ";
5812
5930
  const receiverQualifier = envelope.receiverQualifier ?? "ZZ";
5813
5931
  const usageIndicator = envelope.usageIndicator ?? "P";
5932
+ requireControlNumber(
5933
+ envelope.interchangeControlNumber,
5934
+ "ISA-13 / IEA-02",
5935
+ "interchangeControlNumber",
5936
+ "build271",
5937
+ refuseSpec3
5938
+ );
5939
+ requireControlNumber(
5940
+ envelope.groupControlNumber,
5941
+ "GS-06 / GE-02",
5942
+ "groupControlNumber",
5943
+ "build271",
5944
+ refuseSpec3
5945
+ );
5946
+ requireControlNumber(
5947
+ envelope.transactionSetControlNumber,
5948
+ "ST-02 / SE-02",
5949
+ "transactionSetControlNumber",
5950
+ "build271",
5951
+ refuseSpec3
5952
+ );
5814
5953
  const interchangeControlNumber = padControl3(envelope.interchangeControlNumber, 9);
5815
5954
  const isa = [
5816
5955
  "ISA",
@@ -6181,8 +6320,13 @@ function get277CADisposition(delimiters, tx) {
6181
6320
  function walk277(delimiters, tx) {
6182
6321
  const warnings = [];
6183
6322
  const body = tx.se === void 0 ? tx.segments.slice(1) : tx.segments.slice(1, -1);
6184
- const implementationConventionReference = tx.st.elements[3];
6185
- const transactionType = implementationConventionReference === ICR_277CA ? "claim-acknowledgment" : "claim-status";
6323
+ const implementationConventionReferenceRaw = tx.st.elements[3];
6324
+ const implementationConventionReference = decodeSt03(
6325
+ implementationConventionReferenceRaw,
6326
+ delimiters,
6327
+ { segmentIndex: 0, transactionIndex: 0 }
6328
+ );
6329
+ const transactionType = implementationConventionReferenceRaw === ICR_277CA ? "claim-acknowledgment" : "claim-status";
6186
6330
  const hierarchies = [];
6187
6331
  const hlIndex = /* @__PURE__ */ new Map();
6188
6332
  const claims = [];
@@ -6537,6 +6681,27 @@ function buildClaimStatus(version, spec) {
6537
6681
  const senderQualifier = envelope.senderQualifier ?? "ZZ";
6538
6682
  const receiverQualifier = envelope.receiverQualifier ?? "ZZ";
6539
6683
  const usageIndicator = envelope.usageIndicator ?? "P";
6684
+ requireControlNumber(
6685
+ envelope.interchangeControlNumber,
6686
+ "ISA-13 / IEA-02",
6687
+ "interchangeControlNumber",
6688
+ "build277",
6689
+ refuseSpec4
6690
+ );
6691
+ requireControlNumber(
6692
+ envelope.groupControlNumber,
6693
+ "GS-06 / GE-02",
6694
+ "groupControlNumber",
6695
+ "build277",
6696
+ refuseSpec4
6697
+ );
6698
+ requireControlNumber(
6699
+ envelope.transactionSetControlNumber,
6700
+ "ST-02 / SE-02",
6701
+ "transactionSetControlNumber",
6702
+ "build277",
6703
+ refuseSpec4
6704
+ );
6540
6705
  const interchangeControlNumber = padControl4(envelope.interchangeControlNumber, 9);
6541
6706
  const isa = [
6542
6707
  "ISA",
@@ -7328,6 +7493,27 @@ function build820(spec) {
7328
7493
  const senderQualifier = envelope.senderQualifier ?? "ZZ";
7329
7494
  const receiverQualifier = envelope.receiverQualifier ?? "ZZ";
7330
7495
  const usageIndicator = envelope.usageIndicator ?? "P";
7496
+ requireControlNumber(
7497
+ envelope.interchangeControlNumber,
7498
+ "ISA-13 / IEA-02",
7499
+ "interchangeControlNumber",
7500
+ "build820",
7501
+ refuseSpec5
7502
+ );
7503
+ requireControlNumber(
7504
+ envelope.groupControlNumber,
7505
+ "GS-06 / GE-02",
7506
+ "groupControlNumber",
7507
+ "build820",
7508
+ refuseSpec5
7509
+ );
7510
+ requireControlNumber(
7511
+ envelope.transactionSetControlNumber,
7512
+ "ST-02 / SE-02",
7513
+ "transactionSetControlNumber",
7514
+ "build820",
7515
+ refuseSpec5
7516
+ );
7331
7517
  const interchangeControlNumber = padControl5(envelope.interchangeControlNumber, 9);
7332
7518
  const isa = [
7333
7519
  "ISA",
@@ -8035,6 +8221,27 @@ function build834(spec) {
8035
8221
  const senderQualifier = envelope.senderQualifier ?? "ZZ";
8036
8222
  const receiverQualifier = envelope.receiverQualifier ?? "ZZ";
8037
8223
  const usageIndicator = envelope.usageIndicator ?? "P";
8224
+ requireControlNumber(
8225
+ envelope.interchangeControlNumber,
8226
+ "ISA-13 / IEA-02",
8227
+ "interchangeControlNumber",
8228
+ "build834",
8229
+ refuseSpec6
8230
+ );
8231
+ requireControlNumber(
8232
+ envelope.groupControlNumber,
8233
+ "GS-06 / GE-02",
8234
+ "groupControlNumber",
8235
+ "build834",
8236
+ refuseSpec6
8237
+ );
8238
+ requireControlNumber(
8239
+ envelope.transactionSetControlNumber,
8240
+ "ST-02 / SE-02",
8241
+ "transactionSetControlNumber",
8242
+ "build834",
8243
+ refuseSpec6
8244
+ );
8038
8245
  const interchangeControlNumber = padControl6(envelope.interchangeControlNumber, 9);
8039
8246
  const isa = [
8040
8247
  "ISA",
@@ -8487,7 +8694,10 @@ function walk278(delimiters, tx, direction) {
8487
8694
  }
8488
8695
  }
8489
8696
  flushReview();
8490
- const icr = tx.st.elements[3];
8697
+ const icr = decodeSt03(tx.st.elements[3], delimiters, {
8698
+ segmentIndex: 0,
8699
+ transactionIndex: 0
8700
+ });
8491
8701
  return Object.freeze({
8492
8702
  direction,
8493
8703
  implementationConventionReference: icr === void 0 || icr === "" ? void 0 : icr,
@@ -8711,6 +8921,27 @@ function buildServicesReview(version, direction, spec) {
8711
8921
  const senderQualifier = envelope.senderQualifier ?? "ZZ";
8712
8922
  const receiverQualifier = envelope.receiverQualifier ?? "ZZ";
8713
8923
  const usageIndicator = envelope.usageIndicator ?? "P";
8924
+ requireControlNumber(
8925
+ envelope.interchangeControlNumber,
8926
+ "ISA-13 / IEA-02",
8927
+ "interchangeControlNumber",
8928
+ "build278",
8929
+ refuseSpec7
8930
+ );
8931
+ requireControlNumber(
8932
+ envelope.groupControlNumber,
8933
+ "GS-06 / GE-02",
8934
+ "groupControlNumber",
8935
+ "build278",
8936
+ refuseSpec7
8937
+ );
8938
+ requireControlNumber(
8939
+ envelope.transactionSetControlNumber,
8940
+ "ST-02 / SE-02",
8941
+ "transactionSetControlNumber",
8942
+ "build278",
8943
+ refuseSpec7
8944
+ );
8714
8945
  const interchangeControlNumber = padControl7(envelope.interchangeControlNumber, 9);
8715
8946
  const isa = [
8716
8947
  "ISA",
@@ -9418,11 +9649,12 @@ function parseTA1(interchange) {
9418
9649
  const ta1 = interchange.ta1Segments[0];
9419
9650
  if (ta1 === void 0) return void 0;
9420
9651
  const elements = ta1.elements;
9421
- const interchangeControlNumber = elements[1] ?? "";
9422
- const interchangeDate = elements[2] ?? "";
9423
- const interchangeTime = elements[3] ?? "";
9424
- const ackCodeRaw = elements[4] ?? "";
9425
- const noteCodeRaw = elements[5] ?? "";
9652
+ const value = (index) => unescapeRelease(elements[index] ?? "", interchange.delimiters, noop3, { segmentIndex: 0 });
9653
+ const interchangeControlNumber = value(1);
9654
+ const interchangeDate = value(2);
9655
+ const interchangeTime = value(3);
9656
+ const ackCodeRaw = value(4);
9657
+ const noteCodeRaw = value(5);
9426
9658
  const ackCode = narrowAckCode(ackCodeRaw) ?? TA1_ACK_CODES.R;
9427
9659
  const noteCode = narrowNoteCode(noteCodeRaw);
9428
9660
  return Object.freeze({
@@ -9435,6 +9667,8 @@ function parseTA1(interchange) {
9435
9667
  raw: ta1
9436
9668
  });
9437
9669
  }
9670
+ var noop3 = (_w) => {
9671
+ };
9438
9672
  function narrowAckCode(value) {
9439
9673
  switch (value) {
9440
9674
  case "A":
@@ -9476,6 +9710,27 @@ function build999(spec) {
9476
9710
  const senderQualifier = envelope.senderQualifier ?? "ZZ";
9477
9711
  const receiverQualifier = envelope.receiverQualifier ?? "ZZ";
9478
9712
  const usageIndicator = envelope.usageIndicator ?? "P";
9713
+ requireControlNumber(
9714
+ envelope.interchangeControlNumber,
9715
+ "ISA-13 / IEA-02",
9716
+ "interchangeControlNumber",
9717
+ "build999",
9718
+ refuseSpec8
9719
+ );
9720
+ requireControlNumber(
9721
+ envelope.groupControlNumber,
9722
+ "GS-06 / GE-02",
9723
+ "groupControlNumber",
9724
+ "build999",
9725
+ refuseSpec8
9726
+ );
9727
+ requireControlNumber(
9728
+ envelope.transactionSetControlNumber,
9729
+ "ST-02 / SE-02",
9730
+ "transactionSetControlNumber",
9731
+ "build999",
9732
+ refuseSpec8
9733
+ );
9479
9734
  const interchangeControlNumber = padControl8(envelope.interchangeControlNumber, 9);
9480
9735
  const isa = [
9481
9736
  "ISA",
@@ -9544,6 +9799,13 @@ function build999(spec) {
9544
9799
  elementSeparator,
9545
9800
  segmentTerminator
9546
9801
  );
9802
+ requireControlNumber(
9803
+ functionalGroup.groupControlNumber,
9804
+ "AK1-02",
9805
+ "functionalGroup.groupControlNumber",
9806
+ "build999",
9807
+ refuseSpec8
9808
+ );
9547
9809
  const ak1 = joinSeg(
9548
9810
  [
9549
9811
  "AK1",
@@ -9650,6 +9912,13 @@ function responseHasAnyError(response) {
9650
9912
  return false;
9651
9913
  }
9652
9914
  function buildAk2(response, esc, elementSeparator, segmentTerminator) {
9915
+ requireControlNumber(
9916
+ response.transactionSetControlNumber,
9917
+ "AK2-02",
9918
+ "transactionResponses[].transactionSetControlNumber",
9919
+ "build999",
9920
+ refuseSpec8
9921
+ );
9653
9922
  const parts = [
9654
9923
  "AK2",
9655
9924
  esc(response.transactionSetIdCode),
@@ -9768,13 +10037,29 @@ function buildTA1(spec, options = {}) {
9768
10037
  segment: options.segmentTerminator ?? "~"
9769
10038
  };
9770
10039
  const esc = makeCallerEscaper(delimiters, "buildTA1", refuseSpec9);
10040
+ requireControlNumber(
10041
+ spec.interchangeControlNumber,
10042
+ "TA1-01",
10043
+ "interchangeControlNumber",
10044
+ "buildTA1",
10045
+ refuseSpec9
10046
+ );
10047
+ const interchangeControlNumber = esc(spec.interchangeControlNumber);
10048
+ const interchangeDate = esc(spec.interchangeDate);
10049
+ const interchangeTime = esc(spec.interchangeTime);
10050
+ const ackCode = esc(spec.ackCode);
10051
+ const noteCode = esc(spec.noteCode);
10052
+ requireTa1Element(interchangeDate, "TA1-02", "interchangeDate");
10053
+ requireTa1Element(interchangeTime, "TA1-03", "interchangeTime");
10054
+ requireTa1Element(ackCode, "TA1-04", "ackCode");
10055
+ requireTa1Element(noteCode, "TA1-05", "noteCode");
9771
10056
  const elements = Object.freeze([
9772
10057
  "TA1",
9773
- esc(spec.interchangeControlNumber),
9774
- esc(spec.interchangeDate),
9775
- esc(spec.interchangeTime),
9776
- esc(spec.ackCode),
9777
- esc(spec.noteCode)
10058
+ interchangeControlNumber,
10059
+ interchangeDate,
10060
+ interchangeTime,
10061
+ ackCode,
10062
+ noteCode
9778
10063
  ]);
9779
10064
  const raw = elements.join(delimiters.element);
9780
10065
  return Object.freeze({ raw, elements });
@@ -9782,6 +10067,12 @@ function buildTA1(spec, options = {}) {
9782
10067
  function refuseSpec9(message) {
9783
10068
  throw new AckBuildError(ACK_BUILD_ERROR_CODES.X12_ACK_INVALID_SPEC, message);
9784
10069
  }
10070
+ function requireTa1Element(emitted, slot, field) {
10071
+ if (emitted !== "") return;
10072
+ refuseSpec9(
10073
+ `buildTA1: ${field} is empty. ${slot} is a required element and this builder never invents one, so nothing is emitted. Supply ${field}.`
10074
+ );
10075
+ }
9785
10076
  function enforceAcceptIsClean2(spec) {
9786
10077
  if (spec.ackCode === TA1_ACK_CODES.A && spec.noteCode !== "000") {
9787
10078
  throw new AckBuildError(
@@ -9989,6 +10280,13 @@ function buildInterchange(spec) {
9989
10280
  const receiverQualifier = spec.receiverQualifier ?? "ZZ";
9990
10281
  const usageIndicator = spec.usageIndicator ?? "P";
9991
10282
  const version = spec.version ?? "00501";
10283
+ requireControlNumber(
10284
+ spec.interchangeControlNumber,
10285
+ "ISA-13 / IEA-02",
10286
+ "interchangeControlNumber",
10287
+ "buildInterchange",
10288
+ refuseSpec10
10289
+ );
9992
10290
  const interchangeControlNumber = padControl9(spec.interchangeControlNumber, 9);
9993
10291
  const isa = [
9994
10292
  "ISA",
@@ -10038,23 +10336,32 @@ function buildInterchange(spec) {
10038
10336
  return parseX12(raw);
10039
10337
  }
10040
10338
  function buildGroup(group, spec, esc, elementSeparator, segmentTerminator) {
10339
+ requireControlNumber(
10340
+ group.groupControlNumber,
10341
+ "GS-06 / GE-02",
10342
+ "groupControlNumber",
10343
+ "buildInterchange",
10344
+ refuseSpec10
10345
+ );
10041
10346
  const applicationSenderCode = group.applicationSenderCode ?? spec.senderId;
10042
10347
  const applicationReceiverCode = group.applicationReceiverCode ?? spec.receiverId;
10043
10348
  const groupDate = group.groupDate ?? expandYY9(spec.interchangeDate);
10044
10349
  const groupTime = group.groupTime ?? spec.interchangeTime;
10045
10350
  const responsibleAgencyCode = group.responsibleAgencyCode ?? "X";
10351
+ const gsParts = [
10352
+ "GS",
10353
+ group.functionalIdCode,
10354
+ applicationSenderCode,
10355
+ applicationReceiverCode,
10356
+ groupDate,
10357
+ groupTime,
10358
+ group.groupControlNumber,
10359
+ responsibleAgencyCode,
10360
+ group.versionRelease
10361
+ ];
10362
+ requireCallerSegment(gsParts, "buildInterchange", refuseSpec10);
10046
10363
  const gs = joinSeg2(
10047
- [
10048
- "GS",
10049
- esc(group.functionalIdCode),
10050
- esc(applicationSenderCode),
10051
- esc(applicationReceiverCode),
10052
- groupDate,
10053
- groupTime,
10054
- esc(group.groupControlNumber),
10055
- responsibleAgencyCode,
10056
- esc(group.versionRelease)
10057
- ],
10364
+ gsParts.map((value, index) => index === 0 ? value : esc(value)),
10058
10365
  elementSeparator,
10059
10366
  segmentTerminator
10060
10367
  );
@@ -10070,6 +10377,13 @@ function buildGroup(group, spec, esc, elementSeparator, segmentTerminator) {
10070
10377
  return gs + transactions + ge;
10071
10378
  }
10072
10379
  function buildTransaction(tx, esc, elementSeparator, segmentTerminator) {
10380
+ requireControlNumber(
10381
+ tx.transactionSetControlNumber,
10382
+ "ST-02 / SE-02",
10383
+ "transactionSetControlNumber",
10384
+ "buildInterchange",
10385
+ refuseSpec10
10386
+ );
10073
10387
  const stParts = ["ST", esc(tx.transactionSetIdCode), esc(tx.transactionSetControlNumber)];
10074
10388
  if (tx.implementationConventionReference !== void 0) {
10075
10389
  stParts.push(esc(tx.implementationConventionReference));
@@ -10407,7 +10721,7 @@ var profiles = Object.freeze({
10407
10721
  });
10408
10722
 
10409
10723
  // src/index.ts
10410
- var VERSION = "0.0.15";
10724
+ var VERSION = "0.0.16";
10411
10725
 
10412
10726
  export { ACK_BUILD_ERROR_CODES, ALL_WARNING_MESSAGES, AUTH_278_BUILD_ERROR_CODES, AUTH_278_LOOP_2000A, AUTH_278_LOOP_2000B, AUTH_278_LOOP_2000C, AUTH_278_LOOP_2000D, AUTH_278_LOOP_2000E, AUTH_278_LOOP_2000F, AckBuildError, BALANCE_INVARIANTS, BUILD_REFUSAL_VALUE_MAX_LENGTH, BUILD_REFUSAL_VALUE_MAX_RENDERED, CARC, CLAIM_837D_LOOP_2000A, CLAIM_837D_LOOP_2300, CLAIM_837D_LOOP_2400, CLAIM_837I_LOOP_2000A, CLAIM_837I_LOOP_2300, CLAIM_837I_LOOP_2400, CLAIM_837P_LOOP_2000A, CLAIM_837P_LOOP_2300, CLAIM_837P_LOOP_2400, CLAIM_837P_LOOP_2410, CLAIM_837_BUILD_ERROR_CODES, CLAIM_837_LOOP_1000A, CLAIM_837_LOOP_1000B, CLAIM_837_LOOP_2010AA, CLAIM_837_LOOP_2010BA, CLAIM_837_LOOP_2010BB, CLAIM_837_LOOP_2010CA, CLAIM_837_LOOP_2430, CLAIM_ADJUSTMENT_GROUP_CODES, CLAIM_STATUS_277_BUILD_ERROR_CODES, CLAIM_STATUS_CATEGORY_CODES, CLAIM_STATUS_CODES, CLP_STATUS, CONTROL_NUMBER_PAIRS, Claim837BuildError, ClaimStatus277BuildError, DELIMITER_POSITIONS, ELIGIBILITY_271_BUILD_ERROR_CODES, ELIGIBILITY_271_LOOP_2000A, ELIGIBILITY_271_LOOP_2000B, ELIGIBILITY_271_LOOP_2000C, ELIGIBILITY_271_LOOP_2000D, ELIGIBILITY_271_LOOP_2100C, ELIGIBILITY_271_LOOP_2100D, ELIGIBILITY_271_LOOP_2110, ENROLLMENT_834_BUILD_ERROR_CODES, ENROLLMENT_834_LOOP_1000A, ENROLLMENT_834_LOOP_1000B, ENROLLMENT_834_LOOP_2000, ENROLLMENT_834_LOOP_2100A, ENROLLMENT_834_LOOP_2300, ENROLLMENT_834_LOOP_2320, Eligibility271BuildError, Enrollment834BuildError, FATAL_CODES, HI_QUALIFIERS, HL_LEVEL_CODES, IK3_SYNTAX_ERROR_CODES, IK4_SYNTAX_ERROR_CODES, ISA_MIN_LENGTH, LoopSpecDefinitionError, MAINTENANCE_TYPE_CODES, NM1_QUALIFIERS, NON_SPEC_SEGMENT_ID, PREMIUM_820_BUILD_ERROR_CODES, PREMIUM_820_LOOP_1000A, PREMIUM_820_LOOP_1000B, PREMIUM_820_LOOP_2000A, PREMIUM_820_LOOP_2100A, PREMIUM_820_LOOP_2300A, PREMIUM_820_LOOP_2310A, Premium820BuildError, RARC, RELEASE_CHAR, REMIT_835_BUILD_ERROR_CODES, REMIT_835_LOOP_1000A, REMIT_835_LOOP_1000B, REMIT_835_LOOP_2000, REMIT_835_LOOP_2100, REMIT_835_LOOP_2110, REQUIRED_LOOPS, Remit835BuildError, SERVICE_TYPE_CODES, STATUS_277_LOOP_2000A, STATUS_277_LOOP_2000B, STATUS_277_LOOP_2000C, STATUS_277_LOOP_2000D, STATUS_277_LOOP_2000E, STATUS_277_LOOP_2200, STATUS_277_LOOP_2220, ServicesReview278BuildError, TA1_ACK_CODES, TA1_NOTE_CODES, UNEXPECTED_SEGMENT_CONTEXTS, VERSION, WARNING_CODES, X12BuildError, X12Decimal, X12ParseError, X12ProfileError, X12_ACK_DISPOSITION_CODES, X12_BUILD_ERROR_CODES, ambiguous837Variant, amountRowDropped, balanceNotEvaluable, build271, build277, build277CA, build278Request, build278Response, build820, build834, build835, build837D, build837I, build837P, build999, buildInterchange, buildTA1, checkClaimBalance, checkRemitTotalBalance, checkServiceLineBalance, collectElementValues, componentOptional, controlNumberMismatch, danglingReleaseChar, decodeSegment, defineLoopSpec, defineProfile, detectDelimiters, elementDecimal, elementDecimalOrZero, elementOptional, elementValue, entitySegmentDiscardedAfterLx, escapeRelease, get271Eligibility, get277CADisposition, get277Status, get278Request, get278Response, get820Payments, get834Enrollments, get834Header, get835, get837Claims, getAllSegmentValues, getDefaultProfile, getSegmentValue, groupCountMismatch, hlParentLevelInvalid, hlParentMismatch, isAcceptDisposition, isClaimAdjustmentGroupCode, isDiagnosisQualifier, isProcedureQualifier, lookupCarc, lookupClaimStatus, lookupClaimStatusCategory, lookupClpStatus, lookupMaintenanceType, lookupRarc, lookupServiceType, missingGe, missingIea, missingRequiredLoop, missingSe, parse999, parseTA1, parseX12, partitionWarnings, payToAddressRepeated, pre005010, profiles, readElementDecimal, remitBalanceMismatch, renderCallerValue, resolveHiQualifier, segmentCountMismatch, serializeX12, serviceLineDropped, serviceLineNotDecoded, serviceSegmentRepeated, serviceSegmentWithoutLx, setDefaultProfile, statedAmountDiscarded, trailingGarbage, transactionCountMismatch, unescapeRelease, unexpectedSegment, unknown837Variant, unknownCarc, unknownClaimStatus, unknownClaimStatusCategory, unknownHiQualifier, unknownMaintenanceType, unknownRarc, unparseableDecimal };
10413
10727
  //# sourceMappingURL=index.mjs.map