@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.cjs CHANGED
@@ -47,6 +47,12 @@ var DELIMITER_POSITIONS = {
47
47
  component: 104,
48
48
  segment: 105
49
49
  };
50
+ function isVisibleDelimiterChar(c) {
51
+ const code = c.charCodeAt(0);
52
+ if (code < 32 || code === 127) return false;
53
+ if (/\s/u.test(c)) return false;
54
+ return true;
55
+ }
50
56
  function detectDelimiters(raw) {
51
57
  const fatalPosition = { segmentIndex: 0, interchangeIndex: 0 };
52
58
  const snip = snippet(raw);
@@ -70,19 +76,13 @@ function detectDelimiters(raw) {
70
76
  const repetition = raw.charAt(DELIMITER_POSITIONS.repetition);
71
77
  const component = raw.charAt(DELIMITER_POSITIONS.component);
72
78
  const segment = raw.charAt(DELIMITER_POSITIONS.segment);
73
- const isValidDelimiterChar = (c) => {
74
- const code = c.charCodeAt(0);
75
- if (code < 32 || code === 127) return false;
76
- if (/\s/u.test(c)) return false;
77
- return true;
78
- };
79
79
  for (const [name, ch] of [
80
80
  ["element", element],
81
81
  ["repetition", repetition],
82
82
  ["component", component],
83
83
  ["segment", segment]
84
84
  ]) {
85
- if (!isValidDelimiterChar(ch)) {
85
+ if (!isVisibleDelimiterChar(ch)) {
86
86
  throw new X12ParseError(
87
87
  FATAL_CODES.X12_INVALID_DELIMITERS,
88
88
  `Delimiter "${name}" at ISA byte ${String(DELIMITER_POSITIONS[name] + 1)} is whitespace, control, or empty.`,
@@ -224,7 +224,7 @@ var WARNING_MESSAGES = {
224
224
  X12_MISSING_REQUIRED_LOOP_2000B: 'Missing required loop "2000B" (Subscriber HL): no Subscriber HL precedes the CLM.',
225
225
  X12_MISSING_REQUIRED_LOOP_2010BA: 'Missing required loop "2010BA" (Subscriber Name): no Subscriber Name follows the Subscriber HL.',
226
226
  X12_MISSING_REQUIRED_LOOP_2010BB: 'Missing required loop "2010BB" (Payer Name): no Payer Name follows the Subscriber HL.',
227
- 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.",
227
+ 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.",
228
228
  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.",
229
229
  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.",
230
230
  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.",
@@ -868,8 +868,11 @@ function boundSegmentId(first) {
868
868
  return SEGMENT_ID_SHAPE_RE.test(first) ? first : NON_SPEC_SEGMENT_ID;
869
869
  }
870
870
  function decodeSegment(raw, delimiters, emit, position) {
871
- const elements = Object.freeze(splitWithRelease(raw, delimiters.element));
872
- if (raw.length > 0 && raw.endsWith(RELEASE_CHAR)) {
871
+ const degenerate = delimiters.element === RELEASE_CHAR;
872
+ const elements = Object.freeze(
873
+ degenerate ? raw.split(delimiters.element) : splitWithRelease(raw, delimiters.element)
874
+ );
875
+ if (!degenerate && raw.length > 0 && raw.endsWith(RELEASE_CHAR)) {
873
876
  let trailingRun = 0;
874
877
  for (let j = raw.length - 1; j >= 0 && raw.charAt(j) === RELEASE_CHAR; j -= 1) trailingRun += 1;
875
878
  if (trailingRun % 2 === 1) {
@@ -2706,10 +2709,70 @@ function requireCallerString(value, at, refuse) {
2706
2709
  `${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.`
2707
2710
  );
2708
2711
  }
2712
+ var DELIMITER_ROLES = [
2713
+ ["element", "element separator"],
2714
+ ["repetition", "repetition separator"],
2715
+ ["component", "component separator"],
2716
+ ["segment", "segment terminator"]
2717
+ ];
2718
+ function requireEscapableDelimiters(delimiters, at, refuse) {
2719
+ const degenerate = DELIMITER_ROLES.filter(([role]) => delimiters[role] === RELEASE_CHAR).map(
2720
+ ([, name]) => name
2721
+ );
2722
+ if (degenerate.length === 0) return;
2723
+ const roles = degenerate.length === 1 ? `the ${degenerate[0] ?? ""}` : `the ${degenerate.slice(0, -1).join(", the ")} and the ${degenerate[degenerate.length - 1] ?? ""}`;
2724
+ refuse(
2725
+ `${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}".`
2726
+ );
2727
+ }
2728
+ function requireWellShapedDelimiters(delimiters, at, refuse) {
2729
+ 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.`;
2730
+ for (const [role, name] of DELIMITER_ROLES) {
2731
+ const value = delimiters[role];
2732
+ if (typeof value !== "string") {
2733
+ refuse(
2734
+ `${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}`
2735
+ );
2736
+ }
2737
+ if (value.length !== 1) {
2738
+ refuse(
2739
+ `${at}: the ${name} must be exactly one character, but the declared value is ${value.length === 0 ? "empty" : `${String(value.length)} characters long`}. ${REMEDY}`
2740
+ );
2741
+ }
2742
+ if (!isVisibleDelimiterChar(value)) {
2743
+ refuse(
2744
+ `${at}: the ${name} must be a visible character, but the declared value is whitespace or a control character. ${REMEDY}`
2745
+ );
2746
+ }
2747
+ }
2748
+ for (const [i, [role, name]] of DELIMITER_ROLES.entries()) {
2749
+ const earlier = DELIMITER_ROLES.slice(0, i).find(([r]) => delimiters[r] === delimiters[role]);
2750
+ if (earlier !== void 0) {
2751
+ refuse(
2752
+ `${at}: the ${name} and the ${earlier[1]} are the same character. A reader cannot tell which role a character is playing. ${REMEDY}`
2753
+ );
2754
+ }
2755
+ }
2756
+ }
2709
2757
  function makeCallerEscaper(delimiters, at, refuse) {
2758
+ requireEscapableDelimiters(delimiters, at, refuse);
2759
+ requireWellShapedDelimiters(delimiters, at, refuse);
2710
2760
  return (value) => escapeRelease(requireCallerString(value, at, refuse), delimiters);
2711
2761
  }
2712
2762
 
2763
+ // src/builder/caller-control-number.ts
2764
+ function requireControlNumber(value, slot, field, at, refuse) {
2765
+ if (typeof value !== "string") {
2766
+ refuse(
2767
+ `${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.`
2768
+ );
2769
+ }
2770
+ if (value !== "") return value;
2771
+ refuse(
2772
+ `${at}: ${field} is empty. ${slot} is a required control number and this builder never invents one, so nothing is emitted. Supply ${field}.`
2773
+ );
2774
+ }
2775
+
2713
2776
  // src/transactions/remit/build-835.ts
2714
2777
  function refuseSpec(message) {
2715
2778
  throw new Remit835BuildError(REMIT_835_BUILD_ERROR_CODES.X12_835_BUILD_INVALID_SPEC, message);
@@ -2754,6 +2817,27 @@ function build835(spec) {
2754
2817
  const senderQualifier = envelope.senderQualifier ?? "ZZ";
2755
2818
  const receiverQualifier = envelope.receiverQualifier ?? "ZZ";
2756
2819
  const usageIndicator = envelope.usageIndicator ?? "P";
2820
+ requireControlNumber(
2821
+ envelope.interchangeControlNumber,
2822
+ "ISA-13 / IEA-02",
2823
+ "interchangeControlNumber",
2824
+ "build835",
2825
+ refuseSpec
2826
+ );
2827
+ requireControlNumber(
2828
+ envelope.groupControlNumber,
2829
+ "GS-06 / GE-02",
2830
+ "groupControlNumber",
2831
+ "build835",
2832
+ refuseSpec
2833
+ );
2834
+ requireControlNumber(
2835
+ envelope.transactionSetControlNumber,
2836
+ "ST-02 / SE-02",
2837
+ "transactionSetControlNumber",
2838
+ "build835",
2839
+ refuseSpec
2840
+ );
2757
2841
  const interchangeControlNumber = padControl(envelope.interchangeControlNumber, 9);
2758
2842
  const isa = [
2759
2843
  "ISA",
@@ -3331,6 +3415,14 @@ function wireLookup(entries) {
3331
3415
  return Object.freeze(table);
3332
3416
  }
3333
3417
 
3418
+ // src/transactions/shared/st03.ts
3419
+ var noopWarningSink = (_w) => {
3420
+ };
3421
+ function decodeSt03(raw, delimiters, position) {
3422
+ if (raw === void 0) return void 0;
3423
+ return unescapeRelease(raw, delimiters, noopWarningSink, position);
3424
+ }
3425
+
3334
3426
  // src/transactions/claim/address-segments.ts
3335
3427
  function emitsStreetLines(address) {
3336
3428
  return address.lines.length > 0;
@@ -3389,9 +3481,14 @@ function get837Claims(delimiters, tx, opts) {
3389
3481
  if (tx.st.elements[1] !== "837") return void 0;
3390
3482
  const warnings = [];
3391
3483
  const body = tx.se === void 0 ? tx.segments.slice(1) : tx.segments.slice(1, -1);
3392
- const implementationConventionReference = tx.st.elements[3];
3484
+ const implementationConventionReferenceRaw = tx.st.elements[3];
3485
+ const implementationConventionReference = decodeSt03(
3486
+ implementationConventionReferenceRaw,
3487
+ delimiters,
3488
+ { segmentIndex: 0, transactionIndex: 0 }
3489
+ );
3393
3490
  const explicitType = opts?.type;
3394
- const variantFromIcr = implementationConventionReference !== void 0 && implementationConventionReference !== "" ? VARIANT_BY_ICR[implementationConventionReference] : void 0;
3491
+ const variantFromIcr = implementationConventionReferenceRaw !== void 0 && implementationConventionReferenceRaw !== "" ? VARIANT_BY_ICR[implementationConventionReferenceRaw] : void 0;
3395
3492
  let variantFromSegment;
3396
3493
  let serviceSegmentVariantsConflict = false;
3397
3494
  if (explicitType === void 0 && variantFromIcr === void 0) {
@@ -4642,6 +4739,27 @@ function buildClaim837(variant, spec) {
4642
4739
  const senderQualifier = envelope.senderQualifier ?? "ZZ";
4643
4740
  const receiverQualifier = envelope.receiverQualifier ?? "ZZ";
4644
4741
  const usageIndicator = envelope.usageIndicator ?? "P";
4742
+ requireControlNumber(
4743
+ envelope.interchangeControlNumber,
4744
+ "ISA-13 / IEA-02",
4745
+ "interchangeControlNumber",
4746
+ "build837",
4747
+ refuseSpec2
4748
+ );
4749
+ requireControlNumber(
4750
+ envelope.groupControlNumber,
4751
+ "GS-06 / GE-02",
4752
+ "groupControlNumber",
4753
+ "build837",
4754
+ refuseSpec2
4755
+ );
4756
+ requireControlNumber(
4757
+ envelope.transactionSetControlNumber,
4758
+ "ST-02 / SE-02",
4759
+ "transactionSetControlNumber",
4760
+ "build837",
4761
+ refuseSpec2
4762
+ );
4645
4763
  const interchangeControlNumber = padControl2(envelope.interchangeControlNumber, 9);
4646
4764
  const isa = [
4647
4765
  "ISA",
@@ -5813,6 +5931,27 @@ function build271(spec) {
5813
5931
  const senderQualifier = envelope.senderQualifier ?? "ZZ";
5814
5932
  const receiverQualifier = envelope.receiverQualifier ?? "ZZ";
5815
5933
  const usageIndicator = envelope.usageIndicator ?? "P";
5934
+ requireControlNumber(
5935
+ envelope.interchangeControlNumber,
5936
+ "ISA-13 / IEA-02",
5937
+ "interchangeControlNumber",
5938
+ "build271",
5939
+ refuseSpec3
5940
+ );
5941
+ requireControlNumber(
5942
+ envelope.groupControlNumber,
5943
+ "GS-06 / GE-02",
5944
+ "groupControlNumber",
5945
+ "build271",
5946
+ refuseSpec3
5947
+ );
5948
+ requireControlNumber(
5949
+ envelope.transactionSetControlNumber,
5950
+ "ST-02 / SE-02",
5951
+ "transactionSetControlNumber",
5952
+ "build271",
5953
+ refuseSpec3
5954
+ );
5816
5955
  const interchangeControlNumber = padControl3(envelope.interchangeControlNumber, 9);
5817
5956
  const isa = [
5818
5957
  "ISA",
@@ -6183,8 +6322,13 @@ function get277CADisposition(delimiters, tx) {
6183
6322
  function walk277(delimiters, tx) {
6184
6323
  const warnings = [];
6185
6324
  const body = tx.se === void 0 ? tx.segments.slice(1) : tx.segments.slice(1, -1);
6186
- const implementationConventionReference = tx.st.elements[3];
6187
- const transactionType = implementationConventionReference === ICR_277CA ? "claim-acknowledgment" : "claim-status";
6325
+ const implementationConventionReferenceRaw = tx.st.elements[3];
6326
+ const implementationConventionReference = decodeSt03(
6327
+ implementationConventionReferenceRaw,
6328
+ delimiters,
6329
+ { segmentIndex: 0, transactionIndex: 0 }
6330
+ );
6331
+ const transactionType = implementationConventionReferenceRaw === ICR_277CA ? "claim-acknowledgment" : "claim-status";
6188
6332
  const hierarchies = [];
6189
6333
  const hlIndex = /* @__PURE__ */ new Map();
6190
6334
  const claims = [];
@@ -6539,6 +6683,27 @@ function buildClaimStatus(version, spec) {
6539
6683
  const senderQualifier = envelope.senderQualifier ?? "ZZ";
6540
6684
  const receiverQualifier = envelope.receiverQualifier ?? "ZZ";
6541
6685
  const usageIndicator = envelope.usageIndicator ?? "P";
6686
+ requireControlNumber(
6687
+ envelope.interchangeControlNumber,
6688
+ "ISA-13 / IEA-02",
6689
+ "interchangeControlNumber",
6690
+ "build277",
6691
+ refuseSpec4
6692
+ );
6693
+ requireControlNumber(
6694
+ envelope.groupControlNumber,
6695
+ "GS-06 / GE-02",
6696
+ "groupControlNumber",
6697
+ "build277",
6698
+ refuseSpec4
6699
+ );
6700
+ requireControlNumber(
6701
+ envelope.transactionSetControlNumber,
6702
+ "ST-02 / SE-02",
6703
+ "transactionSetControlNumber",
6704
+ "build277",
6705
+ refuseSpec4
6706
+ );
6542
6707
  const interchangeControlNumber = padControl4(envelope.interchangeControlNumber, 9);
6543
6708
  const isa = [
6544
6709
  "ISA",
@@ -7330,6 +7495,27 @@ function build820(spec) {
7330
7495
  const senderQualifier = envelope.senderQualifier ?? "ZZ";
7331
7496
  const receiverQualifier = envelope.receiverQualifier ?? "ZZ";
7332
7497
  const usageIndicator = envelope.usageIndicator ?? "P";
7498
+ requireControlNumber(
7499
+ envelope.interchangeControlNumber,
7500
+ "ISA-13 / IEA-02",
7501
+ "interchangeControlNumber",
7502
+ "build820",
7503
+ refuseSpec5
7504
+ );
7505
+ requireControlNumber(
7506
+ envelope.groupControlNumber,
7507
+ "GS-06 / GE-02",
7508
+ "groupControlNumber",
7509
+ "build820",
7510
+ refuseSpec5
7511
+ );
7512
+ requireControlNumber(
7513
+ envelope.transactionSetControlNumber,
7514
+ "ST-02 / SE-02",
7515
+ "transactionSetControlNumber",
7516
+ "build820",
7517
+ refuseSpec5
7518
+ );
7333
7519
  const interchangeControlNumber = padControl5(envelope.interchangeControlNumber, 9);
7334
7520
  const isa = [
7335
7521
  "ISA",
@@ -8037,6 +8223,27 @@ function build834(spec) {
8037
8223
  const senderQualifier = envelope.senderQualifier ?? "ZZ";
8038
8224
  const receiverQualifier = envelope.receiverQualifier ?? "ZZ";
8039
8225
  const usageIndicator = envelope.usageIndicator ?? "P";
8226
+ requireControlNumber(
8227
+ envelope.interchangeControlNumber,
8228
+ "ISA-13 / IEA-02",
8229
+ "interchangeControlNumber",
8230
+ "build834",
8231
+ refuseSpec6
8232
+ );
8233
+ requireControlNumber(
8234
+ envelope.groupControlNumber,
8235
+ "GS-06 / GE-02",
8236
+ "groupControlNumber",
8237
+ "build834",
8238
+ refuseSpec6
8239
+ );
8240
+ requireControlNumber(
8241
+ envelope.transactionSetControlNumber,
8242
+ "ST-02 / SE-02",
8243
+ "transactionSetControlNumber",
8244
+ "build834",
8245
+ refuseSpec6
8246
+ );
8040
8247
  const interchangeControlNumber = padControl6(envelope.interchangeControlNumber, 9);
8041
8248
  const isa = [
8042
8249
  "ISA",
@@ -8489,7 +8696,10 @@ function walk278(delimiters, tx, direction) {
8489
8696
  }
8490
8697
  }
8491
8698
  flushReview();
8492
- const icr = tx.st.elements[3];
8699
+ const icr = decodeSt03(tx.st.elements[3], delimiters, {
8700
+ segmentIndex: 0,
8701
+ transactionIndex: 0
8702
+ });
8493
8703
  return Object.freeze({
8494
8704
  direction,
8495
8705
  implementationConventionReference: icr === void 0 || icr === "" ? void 0 : icr,
@@ -8713,6 +8923,27 @@ function buildServicesReview(version, direction, spec) {
8713
8923
  const senderQualifier = envelope.senderQualifier ?? "ZZ";
8714
8924
  const receiverQualifier = envelope.receiverQualifier ?? "ZZ";
8715
8925
  const usageIndicator = envelope.usageIndicator ?? "P";
8926
+ requireControlNumber(
8927
+ envelope.interchangeControlNumber,
8928
+ "ISA-13 / IEA-02",
8929
+ "interchangeControlNumber",
8930
+ "build278",
8931
+ refuseSpec7
8932
+ );
8933
+ requireControlNumber(
8934
+ envelope.groupControlNumber,
8935
+ "GS-06 / GE-02",
8936
+ "groupControlNumber",
8937
+ "build278",
8938
+ refuseSpec7
8939
+ );
8940
+ requireControlNumber(
8941
+ envelope.transactionSetControlNumber,
8942
+ "ST-02 / SE-02",
8943
+ "transactionSetControlNumber",
8944
+ "build278",
8945
+ refuseSpec7
8946
+ );
8716
8947
  const interchangeControlNumber = padControl7(envelope.interchangeControlNumber, 9);
8717
8948
  const isa = [
8718
8949
  "ISA",
@@ -9420,11 +9651,12 @@ function parseTA1(interchange) {
9420
9651
  const ta1 = interchange.ta1Segments[0];
9421
9652
  if (ta1 === void 0) return void 0;
9422
9653
  const elements = ta1.elements;
9423
- const interchangeControlNumber = elements[1] ?? "";
9424
- const interchangeDate = elements[2] ?? "";
9425
- const interchangeTime = elements[3] ?? "";
9426
- const ackCodeRaw = elements[4] ?? "";
9427
- const noteCodeRaw = elements[5] ?? "";
9654
+ const value = (index) => unescapeRelease(elements[index] ?? "", interchange.delimiters, noop3, { segmentIndex: 0 });
9655
+ const interchangeControlNumber = value(1);
9656
+ const interchangeDate = value(2);
9657
+ const interchangeTime = value(3);
9658
+ const ackCodeRaw = value(4);
9659
+ const noteCodeRaw = value(5);
9428
9660
  const ackCode = narrowAckCode(ackCodeRaw) ?? TA1_ACK_CODES.R;
9429
9661
  const noteCode = narrowNoteCode(noteCodeRaw);
9430
9662
  return Object.freeze({
@@ -9437,6 +9669,8 @@ function parseTA1(interchange) {
9437
9669
  raw: ta1
9438
9670
  });
9439
9671
  }
9672
+ var noop3 = (_w) => {
9673
+ };
9440
9674
  function narrowAckCode(value) {
9441
9675
  switch (value) {
9442
9676
  case "A":
@@ -9478,6 +9712,27 @@ function build999(spec) {
9478
9712
  const senderQualifier = envelope.senderQualifier ?? "ZZ";
9479
9713
  const receiverQualifier = envelope.receiverQualifier ?? "ZZ";
9480
9714
  const usageIndicator = envelope.usageIndicator ?? "P";
9715
+ requireControlNumber(
9716
+ envelope.interchangeControlNumber,
9717
+ "ISA-13 / IEA-02",
9718
+ "interchangeControlNumber",
9719
+ "build999",
9720
+ refuseSpec8
9721
+ );
9722
+ requireControlNumber(
9723
+ envelope.groupControlNumber,
9724
+ "GS-06 / GE-02",
9725
+ "groupControlNumber",
9726
+ "build999",
9727
+ refuseSpec8
9728
+ );
9729
+ requireControlNumber(
9730
+ envelope.transactionSetControlNumber,
9731
+ "ST-02 / SE-02",
9732
+ "transactionSetControlNumber",
9733
+ "build999",
9734
+ refuseSpec8
9735
+ );
9481
9736
  const interchangeControlNumber = padControl8(envelope.interchangeControlNumber, 9);
9482
9737
  const isa = [
9483
9738
  "ISA",
@@ -9546,6 +9801,13 @@ function build999(spec) {
9546
9801
  elementSeparator,
9547
9802
  segmentTerminator
9548
9803
  );
9804
+ requireControlNumber(
9805
+ functionalGroup.groupControlNumber,
9806
+ "AK1-02",
9807
+ "functionalGroup.groupControlNumber",
9808
+ "build999",
9809
+ refuseSpec8
9810
+ );
9549
9811
  const ak1 = joinSeg(
9550
9812
  [
9551
9813
  "AK1",
@@ -9652,6 +9914,13 @@ function responseHasAnyError(response) {
9652
9914
  return false;
9653
9915
  }
9654
9916
  function buildAk2(response, esc, elementSeparator, segmentTerminator) {
9917
+ requireControlNumber(
9918
+ response.transactionSetControlNumber,
9919
+ "AK2-02",
9920
+ "transactionResponses[].transactionSetControlNumber",
9921
+ "build999",
9922
+ refuseSpec8
9923
+ );
9655
9924
  const parts = [
9656
9925
  "AK2",
9657
9926
  esc(response.transactionSetIdCode),
@@ -9770,13 +10039,29 @@ function buildTA1(spec, options = {}) {
9770
10039
  segment: options.segmentTerminator ?? "~"
9771
10040
  };
9772
10041
  const esc = makeCallerEscaper(delimiters, "buildTA1", refuseSpec9);
10042
+ requireControlNumber(
10043
+ spec.interchangeControlNumber,
10044
+ "TA1-01",
10045
+ "interchangeControlNumber",
10046
+ "buildTA1",
10047
+ refuseSpec9
10048
+ );
10049
+ const interchangeControlNumber = esc(spec.interchangeControlNumber);
10050
+ const interchangeDate = esc(spec.interchangeDate);
10051
+ const interchangeTime = esc(spec.interchangeTime);
10052
+ const ackCode = esc(spec.ackCode);
10053
+ const noteCode = esc(spec.noteCode);
10054
+ requireTa1Element(interchangeDate, "TA1-02", "interchangeDate");
10055
+ requireTa1Element(interchangeTime, "TA1-03", "interchangeTime");
10056
+ requireTa1Element(ackCode, "TA1-04", "ackCode");
10057
+ requireTa1Element(noteCode, "TA1-05", "noteCode");
9773
10058
  const elements = Object.freeze([
9774
10059
  "TA1",
9775
- esc(spec.interchangeControlNumber),
9776
- esc(spec.interchangeDate),
9777
- esc(spec.interchangeTime),
9778
- esc(spec.ackCode),
9779
- esc(spec.noteCode)
10060
+ interchangeControlNumber,
10061
+ interchangeDate,
10062
+ interchangeTime,
10063
+ ackCode,
10064
+ noteCode
9780
10065
  ]);
9781
10066
  const raw = elements.join(delimiters.element);
9782
10067
  return Object.freeze({ raw, elements });
@@ -9784,6 +10069,12 @@ function buildTA1(spec, options = {}) {
9784
10069
  function refuseSpec9(message) {
9785
10070
  throw new AckBuildError(ACK_BUILD_ERROR_CODES.X12_ACK_INVALID_SPEC, message);
9786
10071
  }
10072
+ function requireTa1Element(emitted, slot, field) {
10073
+ if (emitted !== "") return;
10074
+ refuseSpec9(
10075
+ `buildTA1: ${field} is empty. ${slot} is a required element and this builder never invents one, so nothing is emitted. Supply ${field}.`
10076
+ );
10077
+ }
9787
10078
  function enforceAcceptIsClean2(spec) {
9788
10079
  if (spec.ackCode === TA1_ACK_CODES.A && spec.noteCode !== "000") {
9789
10080
  throw new AckBuildError(
@@ -9991,6 +10282,13 @@ function buildInterchange(spec) {
9991
10282
  const receiverQualifier = spec.receiverQualifier ?? "ZZ";
9992
10283
  const usageIndicator = spec.usageIndicator ?? "P";
9993
10284
  const version = spec.version ?? "00501";
10285
+ requireControlNumber(
10286
+ spec.interchangeControlNumber,
10287
+ "ISA-13 / IEA-02",
10288
+ "interchangeControlNumber",
10289
+ "buildInterchange",
10290
+ refuseSpec10
10291
+ );
9994
10292
  const interchangeControlNumber = padControl9(spec.interchangeControlNumber, 9);
9995
10293
  const isa = [
9996
10294
  "ISA",
@@ -10040,23 +10338,32 @@ function buildInterchange(spec) {
10040
10338
  return parseX12(raw);
10041
10339
  }
10042
10340
  function buildGroup(group, spec, esc, elementSeparator, segmentTerminator) {
10341
+ requireControlNumber(
10342
+ group.groupControlNumber,
10343
+ "GS-06 / GE-02",
10344
+ "groupControlNumber",
10345
+ "buildInterchange",
10346
+ refuseSpec10
10347
+ );
10043
10348
  const applicationSenderCode = group.applicationSenderCode ?? spec.senderId;
10044
10349
  const applicationReceiverCode = group.applicationReceiverCode ?? spec.receiverId;
10045
10350
  const groupDate = group.groupDate ?? expandYY9(spec.interchangeDate);
10046
10351
  const groupTime = group.groupTime ?? spec.interchangeTime;
10047
10352
  const responsibleAgencyCode = group.responsibleAgencyCode ?? "X";
10353
+ const gsParts = [
10354
+ "GS",
10355
+ group.functionalIdCode,
10356
+ applicationSenderCode,
10357
+ applicationReceiverCode,
10358
+ groupDate,
10359
+ groupTime,
10360
+ group.groupControlNumber,
10361
+ responsibleAgencyCode,
10362
+ group.versionRelease
10363
+ ];
10364
+ requireCallerSegment(gsParts, "buildInterchange", refuseSpec10);
10048
10365
  const gs = joinSeg2(
10049
- [
10050
- "GS",
10051
- esc(group.functionalIdCode),
10052
- esc(applicationSenderCode),
10053
- esc(applicationReceiverCode),
10054
- groupDate,
10055
- groupTime,
10056
- esc(group.groupControlNumber),
10057
- responsibleAgencyCode,
10058
- esc(group.versionRelease)
10059
- ],
10366
+ gsParts.map((value, index) => index === 0 ? value : esc(value)),
10060
10367
  elementSeparator,
10061
10368
  segmentTerminator
10062
10369
  );
@@ -10072,6 +10379,13 @@ function buildGroup(group, spec, esc, elementSeparator, segmentTerminator) {
10072
10379
  return gs + transactions + ge;
10073
10380
  }
10074
10381
  function buildTransaction(tx, esc, elementSeparator, segmentTerminator) {
10382
+ requireControlNumber(
10383
+ tx.transactionSetControlNumber,
10384
+ "ST-02 / SE-02",
10385
+ "transactionSetControlNumber",
10386
+ "buildInterchange",
10387
+ refuseSpec10
10388
+ );
10075
10389
  const stParts = ["ST", esc(tx.transactionSetIdCode), esc(tx.transactionSetControlNumber)];
10076
10390
  if (tx.implementationConventionReference !== void 0) {
10077
10391
  stParts.push(esc(tx.implementationConventionReference));
@@ -10409,7 +10723,7 @@ var profiles = Object.freeze({
10409
10723
  });
10410
10724
 
10411
10725
  // src/index.ts
10412
- var VERSION = "0.0.15";
10726
+ var VERSION = "0.0.16";
10413
10727
 
10414
10728
  exports.ACK_BUILD_ERROR_CODES = ACK_BUILD_ERROR_CODES;
10415
10729
  exports.ALL_WARNING_MESSAGES = ALL_WARNING_MESSAGES;