@cosyte/x12 0.0.9 → 0.0.11

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
@@ -138,7 +138,12 @@ var WARNING_CODES = {
138
138
  X12_837_UNKNOWN_VARIANT: "X12_837_UNKNOWN_VARIANT",
139
139
  X12_UNKNOWN_CLAIM_STATUS_CATEGORY: "X12_UNKNOWN_CLAIM_STATUS_CATEGORY",
140
140
  X12_UNKNOWN_CLAIM_STATUS: "X12_UNKNOWN_CLAIM_STATUS",
141
- X12_834_UNKNOWN_MAINTENANCE_TYPE: "X12_834_UNKNOWN_MAINTENANCE_TYPE"
141
+ X12_834_UNKNOWN_MAINTENANCE_TYPE: "X12_834_UNKNOWN_MAINTENANCE_TYPE",
142
+ X12_UNPARSEABLE_DECIMAL: "X12_UNPARSEABLE_DECIMAL",
143
+ X12_837_SERVICE_LINE_NOT_DECODED: "X12_837_SERVICE_LINE_NOT_DECODED",
144
+ X12_837_SERVICE_LINE_DROPPED: "X12_837_SERVICE_LINE_DROPPED",
145
+ X12_837_SERVICE_SEGMENT_WITHOUT_LX: "X12_837_SERVICE_SEGMENT_WITHOUT_LX",
146
+ X12_837_ENTITY_SEGMENT_DISCARDED_AFTER_LX: "X12_837_ENTITY_SEGMENT_DISCARDED_AFTER_LX"
142
147
  };
143
148
  var CONTROL_NUMBER_PAIRS = {
144
149
  /** ISA-13 against IEA-02. */
@@ -211,7 +216,12 @@ var WARNING_MESSAGES = {
211
216
  X12_837_UNKNOWN_VARIANT: `837 variant could not be resolved: ST-03's implementation convention reference is not one of "005010X222A2" / "005010X223A3" / "005010X224A2", and no SVx service-line segment was present to fall back on. The verbatim reference is preserved on the model.`,
212
217
  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.",
213
218
  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.",
214
- X12_834_UNKNOWN_MAINTENANCE_TYPE: "Unknown 834 maintenance type: the INS-03/HD-01 code is outside the bundled snapshot. The verbatim code is preserved on the enrollment and the action is NEVER inferred."
219
+ X12_834_UNKNOWN_MAINTENANCE_TYPE: "Unknown 834 maintenance type: the INS-03/HD-01 code is outside the bundled snapshot. The verbatim code is preserved on the enrollment and the action is NEVER inferred.",
220
+ X12_UNPARSEABLE_DECIMAL: "Unparseable decimal: the element at `position.elementIndex` held bytes this library could not decode as a decimal, so NO value was decoded from it. Whatever occupies that slot on the model, including 0 and undefined, is a stand-in and is NOT a value the sender supplied. The verbatim bytes are preserved on the segment; read them there before acting on the amount, quantity or percent.",
221
+ X12_837_SERVICE_LINE_NOT_DECODED: "837 service line with no decoded service segment: the Loop 2400 line opened at `position.segmentIndex` is followed by no SV1 / SV2 / SV3 matching the variant this submission resolved to, so NOTHING carried by the service segment was read. The line's `charge` and `units` hold 0 as a stand-in and are NOT values the sender supplied; its procedure code, modifiers, unit of measure and place of service are equally undecoded. Two common causes: the line carries no SVx at all, or it carries one for a different 837 variant than ST-03 (or the caller's `type` option) named. Which side is wrong is NOT decided here, because a caller-supplied `type` can disagree with a perfectly conformant document. The verbatim segments are preserved on the transaction set; read them there before acting on the charge or the quantity.",
222
+ X12_837_SERVICE_LINE_DROPPED: "837 service line dropped from the typed model: the LX at `position.segmentIndex` opened no Loop 2400, so no line appears on any claim's `serviceLines` for it and the SV1 / SV2 / SV3 that followed - its charge, units, procedure code and modifiers - was read into nothing. Compare `X12_837_SERVICE_LINE_NOT_DECODED`, where the line IS on the model and only its service segment went unread. Two causes: no Loop 2300 (CLM) is open at this LX, so there is no claim to attach a line to; or the submission's variant is not one of P / I / D, so no variant-specific line shape could be built. Read `submission.variant` and `submission.claims` to tell them apart; do NOT expect `X12_837_UNKNOWN_VARIANT` alongside this code, because a caller-supplied `type` outside P / I / D reaches the second cause without it. Nothing is fabricated to stand in for the missing line and no claim is synthesized. What becomes of a DTP / AMT / NTE / REF that follows the dropped LX depends on the route and this message does not say; see KNOWN-LIMITATIONS.md. The verbatim segments are preserved on the transaction set; read them there before concluding the claim had no service lines.",
223
+ X12_837_SERVICE_SEGMENT_WITHOUT_LX: "837 service segment with no Loop 2400 to read it into: no service line was open at the SV1 / SV2 / SV3 at `position.segmentIndex`, so NOTHING it carries - its charge, units, procedure code, modifiers, unit of measure and place of service - was read. Read that literally: an LX may well appear earlier in the transaction, and what this reports is that none of them had opened a Loop 2400 still current at this segment. No line appears on any claim's `serviceLines` for it and nothing is fabricated to stand in. Compare the two codes anchored at an LX: `X12_837_SERVICE_LINE_DROPPED`, where an LX IS present and opened no line, and `X12_837_SERVICE_LINE_NOT_DECODED`, where the line is on the model and only its service segment went unread. Neither of those can report the SAME service segment as this code, because both are raised at an LX and this one only where no Loop 2400 is open; a document with several claims can still carry all three. This says NOTHING about how the submission's variant resolved: absent a caller-supplied `type` option, and where ST-03 names no known implementation convention, the reader falls back to the first SV1 / SV2 / SV3 in the transaction, and a segment reported here is eligible for that fallback like any other, so a stray one can decide the variant every line is read against. Read `submission.variant`. The verbatim segments are preserved on the transaction set; read them there before concluding the claim had no service lines.",
224
+ X12_837_ENTITY_SEGMENT_DISCARDED_AFTER_LX: "837 entity segment read into nothing after a dropped LX: the N3 / N4 / PER / REF at `position.segmentIndex` arrived while no entity loop was open, because an earlier LX in this transaction opened no Loop 2400 (no CLM was open at it) and closed the entity loop that was current there. NOTHING this segment carries reached the model: no party's `address`, `contacts` or `references` was written from it, and no party, claim or line was synthesized to hold it. This is the code that names THAT loss; `X12_837_SERVICE_LINE_DROPPED` is raised at the LX itself and names the SERVICE LINE's loss, never an entity segment, so the two report different things about the same stretch of the document. Read the bound literally, because this code does NOT report every unattached entity segment: it reports one discarded after such an LX and only while nothing since has opened a new loop, so an N3 / N4 / PER / REF that reaches no party by any other route is still silent, and one arriving after a later NM1 is outside this code's scope, whether or not this reader surfaces that segment kind on that party. It reports that the segment reached NO party; it does not claim it would have reached one had the LX been absent, because this reader does not surface every one of these segment kinds on every party (a PER on a patient or a pay-to address, for one). Which party a segment following a stray LX belongs to is not derivable from the TR3s in either direction, so it is discarded rather than attributed: see KNOWN-LIMITATIONS.md. The verbatim segments are preserved on the transaction set; read them there before concluding a party had no address, no secondary identifier or no contact."
215
225
  };
216
226
  var ALL_WARNING_MESSAGES = new Set(
217
227
  Object.values(WARNING_MESSAGES)
@@ -372,6 +382,34 @@ function unknown837Variant(position) {
372
382
  position
373
383
  };
374
384
  }
385
+ function serviceLineNotDecoded(position) {
386
+ return {
387
+ code: WARNING_CODES.X12_837_SERVICE_LINE_NOT_DECODED,
388
+ message: WARNING_MESSAGES.X12_837_SERVICE_LINE_NOT_DECODED,
389
+ position
390
+ };
391
+ }
392
+ function serviceLineDropped(position) {
393
+ return {
394
+ code: WARNING_CODES.X12_837_SERVICE_LINE_DROPPED,
395
+ message: WARNING_MESSAGES.X12_837_SERVICE_LINE_DROPPED,
396
+ position
397
+ };
398
+ }
399
+ function serviceSegmentWithoutLx(position) {
400
+ return {
401
+ code: WARNING_CODES.X12_837_SERVICE_SEGMENT_WITHOUT_LX,
402
+ message: WARNING_MESSAGES.X12_837_SERVICE_SEGMENT_WITHOUT_LX,
403
+ position
404
+ };
405
+ }
406
+ function entitySegmentDiscardedAfterLx(position) {
407
+ return {
408
+ code: WARNING_CODES.X12_837_ENTITY_SEGMENT_DISCARDED_AFTER_LX,
409
+ message: WARNING_MESSAGES.X12_837_ENTITY_SEGMENT_DISCARDED_AFTER_LX,
410
+ position
411
+ };
412
+ }
375
413
  function unknownClaimStatusCategory(position) {
376
414
  return {
377
415
  code: WARNING_CODES.X12_UNKNOWN_CLAIM_STATUS_CATEGORY,
@@ -393,6 +431,13 @@ function unknownMaintenanceType(position) {
393
431
  position
394
432
  };
395
433
  }
434
+ function unparseableDecimal(position) {
435
+ return {
436
+ code: WARNING_CODES.X12_UNPARSEABLE_DECIMAL,
437
+ message: WARNING_MESSAGES.X12_UNPARSEABLE_DECIMAL,
438
+ position
439
+ };
440
+ }
396
441
 
397
442
  // src/parser/release.ts
398
443
  var RELEASE_CHAR = "?";
@@ -906,13 +951,26 @@ function componentOptional(seg, n, p, delimiters) {
906
951
  const v = getSegmentValue(seg, `${String(n).padStart(2, "0")}-${String(p)}`, delimiters);
907
952
  return v === void 0 || v === "" ? void 0 : v;
908
953
  }
909
- function elementDecimal(seg, n, delimiters) {
954
+ function readElementDecimal(seg, n, delimiters) {
910
955
  const raw = elementOptional(seg, n, delimiters);
911
- if (raw === void 0) return void 0;
912
- return X12Decimal.fromString(raw);
956
+ if (raw === void 0) return { value: void 0, status: "absent" };
957
+ const value = X12Decimal.fromString(raw);
958
+ if (value === void 0) return { value: void 0, status: "unparseable" };
959
+ return { value, status: "decoded" };
913
960
  }
914
- function elementDecimalOrZero(seg, n, delimiters) {
915
- return elementDecimal(seg, n, delimiters) ?? X12Decimal.ZERO;
961
+ function elementDecimal(seg, n, delimiters, sink) {
962
+ const read = readElementDecimal(seg, n, delimiters);
963
+ if (read.status === "unparseable" && sink !== void 0) {
964
+ sink.warnings.push(unparseableDecimal({ ...sink.position, elementIndex: n }));
965
+ }
966
+ return read.value;
967
+ }
968
+ function elementDecimalOrZero(seg, n, delimiters, sink) {
969
+ const read = readElementDecimal(seg, n, delimiters);
970
+ if (read.status === "unparseable" && sink !== void 0) {
971
+ sink.warnings.push(unparseableDecimal({ ...sink.position, elementIndex: n }));
972
+ }
973
+ return read.value ?? X12Decimal.ZERO;
916
974
  }
917
975
  function collectElementValues(seg, start, end, delimiters) {
918
976
  const out = [];
@@ -1418,6 +1476,7 @@ function defineLoopSpec(input) {
1418
1476
  // src/code-lists/meta.ts
1419
1477
  function makeLookup(snapshot) {
1420
1478
  return (code) => {
1479
+ if (!Object.hasOwn(snapshot.codes, code)) return void 0;
1421
1480
  const description = snapshot.codes[code];
1422
1481
  if (description === void 0) return void 0;
1423
1482
  return Object.freeze({ code, description });
@@ -1666,7 +1725,7 @@ var CLAIM_ADJUSTMENT_GROUP_CODES = {
1666
1725
  PI: "PI"
1667
1726
  };
1668
1727
  function isClaimAdjustmentGroupCode(value) {
1669
- return value in CLAIM_ADJUSTMENT_GROUP_CODES;
1728
+ return Object.hasOwn(CLAIM_ADJUSTMENT_GROUP_CODES, value);
1670
1729
  }
1671
1730
 
1672
1731
  // src/code-lists/rarc.ts
@@ -1806,6 +1865,7 @@ var HI_QUALIFIERS = {
1806
1865
  }
1807
1866
  };
1808
1867
  function resolveHiQualifier(qualifier) {
1868
+ if (!Object.hasOwn(HI_QUALIFIERS, qualifier)) return void 0;
1809
1869
  return HI_QUALIFIERS[qualifier];
1810
1870
  }
1811
1871
  function isDiagnosisQualifier(qualifier) {
@@ -1915,9 +1975,10 @@ function get835(delimiters, tx) {
1915
1975
  const seg = body[i];
1916
1976
  if (seg === void 0) continue;
1917
1977
  const position = { segmentIndex: i + 1, transactionIndex: 0 };
1978
+ const sink = { warnings, position };
1918
1979
  switch (seg.id) {
1919
1980
  case "BPR": {
1920
- payment = decodeBpr(seg, delimiters);
1981
+ payment = decodeBpr(seg, delimiters, sink);
1921
1982
  bprSegmentIndex = position.segmentIndex;
1922
1983
  break;
1923
1984
  }
@@ -1992,7 +2053,7 @@ function get835(delimiters, tx) {
1992
2053
  case "CLP": {
1993
2054
  flushClaim();
1994
2055
  lastParty = void 0;
1995
- currentClaim = openClaim(seg, delimiters, position.segmentIndex);
2056
+ currentClaim = openClaim(seg, delimiters, position.segmentIndex, sink);
1996
2057
  break;
1997
2058
  }
1998
2059
  case "CAS": {
@@ -2044,7 +2105,7 @@ function get835(delimiters, tx) {
2044
2105
  break;
2045
2106
  }
2046
2107
  case "AMT": {
2047
- const amount = decodeAmt(seg, delimiters);
2108
+ const amount = decodeAmt(seg, delimiters, sink);
2048
2109
  if (amount === void 0) break;
2049
2110
  if (currentServiceLine !== void 0) currentServiceLine.amounts.push(amount);
2050
2111
  else if (currentClaim !== void 0) currentClaim.amounts.push(amount);
@@ -2063,12 +2124,12 @@ function get835(delimiters, tx) {
2063
2124
  }
2064
2125
  case "SVC": {
2065
2126
  flushServiceLine();
2066
- currentServiceLine = openServiceLine(seg, delimiters);
2127
+ currentServiceLine = openServiceLine(seg, delimiters, sink);
2067
2128
  break;
2068
2129
  }
2069
2130
  case "PLB": {
2070
2131
  flushClaim();
2071
- for (const p of decodePlb(seg, delimiters)) providerAdjustments.push(p);
2132
+ for (const p of decodePlb(seg, delimiters, sink)) providerAdjustments.push(p);
2072
2133
  break;
2073
2134
  }
2074
2135
  }
@@ -2099,10 +2160,10 @@ function get835(delimiters, tx) {
2099
2160
  warnings: Object.freeze(warnings.slice())
2100
2161
  });
2101
2162
  }
2102
- function decodeBpr(seg, delimiters) {
2163
+ function decodeBpr(seg, delimiters, sink) {
2103
2164
  return Object.freeze({
2104
2165
  transactionHandlingCode: elementValue(seg, 1, delimiters),
2105
- totalActualPayment: elementDecimalOrZero(seg, 2, delimiters),
2166
+ totalActualPayment: elementDecimalOrZero(seg, 2, delimiters, sink),
2106
2167
  creditDebitFlag: elementValue(seg, 3, delimiters),
2107
2168
  method: elementValue(seg, 4, delimiters),
2108
2169
  paymentFormatCode: elementOptional(seg, 5, delimiters),
@@ -2161,8 +2222,8 @@ function decodePer(seg, delimiters) {
2161
2222
  communications: Object.freeze(comms)
2162
2223
  });
2163
2224
  }
2164
- function decodeAmt(seg, delimiters) {
2165
- const amount = elementDecimal(seg, 2, delimiters);
2225
+ function decodeAmt(seg, delimiters, sink) {
2226
+ const amount = elementDecimal(seg, 2, delimiters, sink);
2166
2227
  if (amount === void 0) return void 0;
2167
2228
  return Object.freeze({
2168
2229
  qualifier: elementValue(seg, 1, delimiters),
@@ -2198,13 +2259,14 @@ function collectMoaRemarks(seg, delimiters) {
2198
2259
  return out;
2199
2260
  }
2200
2261
  function decodeCasAdjustments(seg, delimiters, warnings, position) {
2262
+ const sink = { warnings, position };
2201
2263
  const groupCode = elementValue(seg, 1, delimiters);
2202
2264
  const out = [];
2203
2265
  for (let triple = 0; triple < 6; triple += 1) {
2204
2266
  const base = 2 + triple * 3;
2205
2267
  const reasonCode = elementOptional(seg, base, delimiters);
2206
- const amount = elementDecimal(seg, base + 1, delimiters);
2207
- const quantity = elementDecimal(seg, base + 2, delimiters);
2268
+ const amount = elementDecimal(seg, base + 1, delimiters, sink);
2269
+ const quantity = elementDecimal(seg, base + 2, delimiters, sink);
2208
2270
  if (reasonCode === void 0 && amount === void 0) continue;
2209
2271
  const code = reasonCode ?? "";
2210
2272
  const entry = code === "" ? void 0 : lookupCarc(code);
@@ -2248,7 +2310,7 @@ function decodeNm1(seg, delimiters) {
2248
2310
  })
2249
2311
  };
2250
2312
  }
2251
- function openClaim(seg, delimiters, clpSegmentIndex) {
2313
+ function openClaim(seg, delimiters, clpSegmentIndex, sink) {
2252
2314
  const claimStatusCode = elementValue(seg, 2, delimiters);
2253
2315
  const claimStatusDescription = lookupClpStatus(claimStatusCode)?.description;
2254
2316
  const facilityTypeCode = componentOptional(seg, 8, 1, delimiters) ?? elementOptional(seg, 8, delimiters);
@@ -2258,9 +2320,9 @@ function openClaim(seg, delimiters, clpSegmentIndex) {
2258
2320
  patientControlNumber: elementValue(seg, 1, delimiters),
2259
2321
  claimStatusCode,
2260
2322
  claimStatusDescription,
2261
- totalChargeAmount: elementDecimalOrZero(seg, 3, delimiters),
2262
- totalPaymentAmount: elementDecimalOrZero(seg, 4, delimiters),
2263
- patientResponsibilityAmount: elementDecimalOrZero(seg, 5, delimiters),
2323
+ totalChargeAmount: elementDecimalOrZero(seg, 3, delimiters, sink),
2324
+ totalPaymentAmount: elementDecimalOrZero(seg, 4, delimiters, sink),
2325
+ patientResponsibilityAmount: elementDecimalOrZero(seg, 5, delimiters, sink),
2264
2326
  claimFilingIndicatorCode: elementOptional(seg, 6, delimiters),
2265
2327
  payerClaimControlNumber: elementOptional(seg, 7, delimiters),
2266
2328
  facilityTypeCode,
@@ -2279,7 +2341,7 @@ function openClaim(seg, delimiters, clpSegmentIndex) {
2279
2341
  serviceLines: []
2280
2342
  };
2281
2343
  }
2282
- function openServiceLine(seg, delimiters) {
2344
+ function openServiceLine(seg, delimiters, sink) {
2283
2345
  const productServiceIdQualifier = componentOptional(seg, 1, 1, delimiters) ?? "";
2284
2346
  const productServiceId = componentOptional(seg, 1, 2, delimiters) ?? "";
2285
2347
  const modifiers = [];
@@ -2287,18 +2349,20 @@ function openServiceLine(seg, delimiters) {
2287
2349
  const m = componentOptional(seg, 1, comp, delimiters);
2288
2350
  if (m !== void 0) modifiers.push(m);
2289
2351
  }
2290
- const revenueCode = elementOptional(seg, 5, delimiters);
2291
- const paidUnitsOfService = elementDecimal(seg, 7, delimiters);
2352
+ const revenueCode = elementOptional(seg, 4, delimiters);
2353
+ const paidUnitsOfService = elementDecimal(seg, 5, delimiters, sink);
2354
+ const originalUnitsOfService = elementDecimal(seg, 7, delimiters, sink);
2292
2355
  const originalServiceIdQualifier = componentOptional(seg, 6, 1, delimiters);
2293
2356
  const originalServiceId = componentOptional(seg, 6, 2, delimiters);
2294
2357
  return {
2295
2358
  productServiceIdQualifier,
2296
2359
  productServiceId,
2297
2360
  modifiers,
2298
- chargeAmount: elementDecimalOrZero(seg, 2, delimiters),
2299
- paymentAmount: elementDecimalOrZero(seg, 3, delimiters),
2361
+ chargeAmount: elementDecimalOrZero(seg, 2, delimiters, sink),
2362
+ paymentAmount: elementDecimalOrZero(seg, 3, delimiters, sink),
2300
2363
  revenueCode,
2301
2364
  paidUnitsOfService,
2365
+ originalUnitsOfService,
2302
2366
  originalServiceId,
2303
2367
  originalServiceIdQualifier,
2304
2368
  serviceDateStart: void 0,
@@ -2324,13 +2388,13 @@ function attachServiceLineDtm(line, seg, delimiters) {
2324
2388
  if (qualifier === "472" || qualifier === "150") line.serviceDateStart = date;
2325
2389
  if (qualifier === "472" || qualifier === "151") line.serviceDateEnd = date;
2326
2390
  }
2327
- function decodePlb(seg, delimiters) {
2391
+ function decodePlb(seg, delimiters, sink) {
2328
2392
  const providerId = elementValue(seg, 1, delimiters);
2329
2393
  const fiscalPeriodDate = elementValue(seg, 2, delimiters);
2330
2394
  const out = [];
2331
2395
  for (let pair = 0; pair < 6; pair += 1) {
2332
2396
  const composite = 3 + pair * 2;
2333
- const amount = elementDecimal(seg, composite + 1, delimiters);
2397
+ const amount = elementDecimal(seg, composite + 1, delimiters, sink);
2334
2398
  const reasonCode = componentOptional(seg, composite, 1, delimiters);
2335
2399
  const subCode = componentOptional(seg, composite, 2, delimiters);
2336
2400
  if (amount === void 0 && reasonCode === void 0) continue;
@@ -2394,6 +2458,7 @@ function freezeServiceLine(acc) {
2394
2458
  paymentAmount: acc.paymentAmount,
2395
2459
  revenueCode: acc.revenueCode,
2396
2460
  paidUnitsOfService: acc.paidUnitsOfService,
2461
+ originalUnitsOfService: acc.originalUnitsOfService,
2397
2462
  originalServiceId: acc.originalServiceId,
2398
2463
  originalServiceIdQualifier: acc.originalServiceIdQualifier,
2399
2464
  serviceDateStart: acc.serviceDateStart,
@@ -2479,7 +2544,7 @@ function renderCallerJson(value) {
2479
2544
  var NONE = Object.freeze([]);
2480
2545
  function describeShape(value) {
2481
2546
  if (typeof value !== "object") {
2482
- return `a ${typeof value} (${renderCallerValue(value)})`;
2547
+ return `a ${typeof value}`;
2483
2548
  }
2484
2549
  let length;
2485
2550
  try {
@@ -2509,6 +2574,50 @@ function isRealArray(value) {
2509
2574
  return Array.isArray(value);
2510
2575
  }
2511
2576
 
2577
+ // src/builder/caller-decimal.ts
2578
+ function describeCallerDecimal(value) {
2579
+ if (value === null) return "null";
2580
+ if (value === void 0) return "undefined";
2581
+ const type = typeof value;
2582
+ if (type === "object") return Array.isArray(value) ? "an array" : "an object";
2583
+ if (type === "function") return "a function";
2584
+ return `a ${type}`;
2585
+ }
2586
+ function requireCallerDecimal(value, at, refuse) {
2587
+ if (value instanceof X12Decimal) return value;
2588
+ refuse(
2589
+ `${at}: every numeric element value must be an X12Decimal, but received ${describeCallerDecimal(value)}. Values are never coerced - a JavaScript number has no X12 lexical form (0.1 + 0.2 renders as "0.30000000000000004", 1e21 as "1e+21", NaN as "NaN"), and rounding one here would guess a scale the caller never stated. Build it with X12Decimal.fromString() at the call site.`
2590
+ );
2591
+ }
2592
+
2593
+ // src/builder/caller-segment.ts
2594
+ var SEGMENT_ID_RE2 = /^[A-Z][A-Z0-9]{1,2}$/u;
2595
+ function describeSegmentValue(value) {
2596
+ if (value === null) return "null";
2597
+ if (value === void 0) return "undefined";
2598
+ const type = typeof value;
2599
+ if (type === "object") return Array.isArray(value) ? "an array" : "an object";
2600
+ if (type === "function") return "a function";
2601
+ return `a ${type}`;
2602
+ }
2603
+ function locateSlot(parts, index) {
2604
+ const id = parts[0];
2605
+ const position = String(index).padStart(2, "0");
2606
+ if (typeof id !== "string" || !SEGMENT_ID_RE2.test(id)) return `element ${String(index)}`;
2607
+ return `"${id}"-${position}`;
2608
+ }
2609
+ function requireCallerSegment(parts, at, refuse) {
2610
+ let index = 0;
2611
+ for (const part of parts) {
2612
+ if (typeof part !== "string") {
2613
+ refuse(
2614
+ `${at}: ${locateSlot(parts, index)} must be a string, but received ${describeSegmentValue(part)}. 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.`
2615
+ );
2616
+ }
2617
+ index += 1;
2618
+ }
2619
+ }
2620
+
2512
2621
  // src/builder/caller-string.ts
2513
2622
  function describeCallerValue(value) {
2514
2623
  if (value === null) return "null";
@@ -2516,7 +2625,7 @@ function describeCallerValue(value) {
2516
2625
  const type = typeof value;
2517
2626
  if (type === "object") return Array.isArray(value) ? "an array" : "an object";
2518
2627
  if (type === "function") return "a function";
2519
- return `a ${type} (${renderCallerValue(value)})`;
2628
+ return `a ${type}`;
2520
2629
  }
2521
2630
  function requireCallerString(value, at, refuse) {
2522
2631
  if (typeof value === "string") return value;
@@ -2532,6 +2641,9 @@ function makeCallerEscaper(delimiters, at, refuse) {
2532
2641
  function refuseSpec(message) {
2533
2642
  throw new Remit835BuildError(REMIT_835_BUILD_ERROR_CODES.X12_835_BUILD_INVALID_SPEC, message);
2534
2643
  }
2644
+ function escDec(value, esc) {
2645
+ return esc(requireCallerDecimal(value, "build835", refuseSpec).toString());
2646
+ }
2535
2647
  var X221A1_VERSION_RELEASE = "005010X221A1";
2536
2648
  var X12_835_FUNCTIONAL_ID = "HP";
2537
2649
  var X12_AGENCY_CODE = "X";
@@ -2555,6 +2667,7 @@ function build835(spec) {
2555
2667
  };
2556
2668
  const esc = makeCallerEscaper(delimiters, "build835", refuseSpec);
2557
2669
  const seg = (parts) => {
2670
+ requireCallerSegment(parts, "build835", refuseSpec);
2558
2671
  let end = parts.length;
2559
2672
  while (end > 1 && parts[end - 1] === "") end -= 1;
2560
2673
  return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
@@ -2616,9 +2729,9 @@ function build835(spec) {
2616
2729
  // GS-02
2617
2730
  esc(applicationReceiverCode),
2618
2731
  // GS-03
2619
- groupDate,
2732
+ esc(groupDate),
2620
2733
  // GS-04 - CCYYMMDD
2621
- groupTime,
2734
+ esc(groupTime),
2622
2735
  // GS-05 - HHMM
2623
2736
  esc(envelope.groupControlNumber),
2624
2737
  // GS-06
@@ -2634,7 +2747,7 @@ function build835(spec) {
2634
2747
  seg([
2635
2748
  "BPR",
2636
2749
  esc(spec.payment.transactionHandlingCode),
2637
- esc(spec.payment.totalActualPayment.toString()),
2750
+ escDec(spec.payment.totalActualPayment, esc),
2638
2751
  esc(spec.payment.creditDebitFlag),
2639
2752
  esc(spec.payment.method),
2640
2753
  esc(spec.payment.paymentFormatCode ?? ""),
@@ -2769,6 +2882,7 @@ function materializeServiceLine(spec) {
2769
2882
  paymentAmount: spec.paymentAmount,
2770
2883
  revenueCode: spec.revenueCode,
2771
2884
  paidUnitsOfService: spec.paidUnitsOfService,
2885
+ originalUnitsOfService: spec.originalUnitsOfService,
2772
2886
  originalServiceId: spec.originalServiceId,
2773
2887
  originalServiceIdQualifier: spec.originalServiceIdQualifier,
2774
2888
  serviceDateStart: spec.serviceDateStart,
@@ -2864,9 +2978,9 @@ function emitClaim(claim, body, seg, esc, comp) {
2864
2978
  "CLP",
2865
2979
  esc(claim.patientControlNumber),
2866
2980
  esc(claim.claimStatusCode),
2867
- esc(claim.totalChargeAmount.toString()),
2868
- esc(claim.totalPaymentAmount.toString()),
2869
- esc(claim.patientResponsibilityAmount.toString()),
2981
+ escDec(claim.totalChargeAmount, esc),
2982
+ escDec(claim.totalPaymentAmount, esc),
2983
+ escDec(claim.patientResponsibilityAmount, esc),
2870
2984
  esc(claim.claimFilingIndicatorCode ?? ""),
2871
2985
  esc(claim.payerClaimControlNumber ?? ""),
2872
2986
  comp([claim.facilityTypeCode ?? "", "", claim.claimFrequencyCode ?? ""])
@@ -2888,7 +3002,7 @@ function emitClaim(claim, body, seg, esc, comp) {
2888
3002
  }
2889
3003
  for (const ref of claim.references ?? []) body.push(emitRef(ref, seg, esc));
2890
3004
  for (const amt of claim.amounts ?? []) {
2891
- body.push(seg(["AMT", esc(amt.qualifier), esc(amt.amount.toString())]));
3005
+ body.push(seg(["AMT", esc(amt.qualifier), escDec(amt.amount, esc)]));
2892
3006
  }
2893
3007
  for (const remark of claim.remarks ?? []) {
2894
3008
  body.push(seg(["LQ", esc(remark.system), esc(remark.code)]));
@@ -2908,20 +3022,24 @@ function emitServiceLine(line, body, seg, esc, comp) {
2908
3022
  seg([
2909
3023
  "SVC",
2910
3024
  svc01,
2911
- esc(line.chargeAmount.toString()),
2912
- esc(line.paymentAmount.toString()),
2913
- "",
2914
- // SVC-04 - revenue code is SVC-05 in X221A1; SVC-04 unused
3025
+ escDec(line.chargeAmount, esc),
3026
+ escDec(line.paymentAmount, esc),
3027
+ // SVC-04 is the NUBC revenue code (element 234, Product/Service ID) and
3028
+ // SVC-05 is the Units of Service PAID Count (element 380, Quantity).
3029
+ // SVC-07 is the ORIGINAL (submitted) units, a different quantity from
3030
+ // SVC-05 - so the two never share a field. See the SVC note in
3031
+ // KNOWN-LIMITATIONS.md for the sources.
2915
3032
  esc(line.revenueCode ?? ""),
3033
+ line.paidUnitsOfService === void 0 ? "" : escDec(line.paidUnitsOfService, esc),
2916
3034
  svc06,
2917
- line.paidUnitsOfService === void 0 ? "" : esc(line.paidUnitsOfService.toString())
3035
+ line.originalUnitsOfService === void 0 ? "" : escDec(line.originalUnitsOfService, esc)
2918
3036
  ])
2919
3037
  );
2920
3038
  emitServiceLineDtm(line, body, seg, esc);
2921
3039
  emitCasGroup(line.adjustments, "build835: serviceLine.adjustments", body, seg, esc);
2922
3040
  for (const ref of line.references ?? []) body.push(emitRef(ref, seg, esc));
2923
3041
  for (const amt of line.amounts ?? []) {
2924
- body.push(seg(["AMT", esc(amt.qualifier), esc(amt.amount.toString())]));
3042
+ body.push(seg(["AMT", esc(amt.qualifier), escDec(amt.amount, esc)]));
2925
3043
  }
2926
3044
  for (const remark of line.remarks ?? []) {
2927
3045
  body.push(seg(["LQ", esc(remark.system), esc(remark.code)]));
@@ -2953,8 +3071,8 @@ function emitCasGroup(raw, at, body, seg, esc) {
2953
3071
  if (adj === void 0 || adj.groupCode !== groupCode) break;
2954
3072
  parts.push(
2955
3073
  esc(adj.reasonCode),
2956
- esc(adj.amount.toString()),
2957
- adj.quantity === void 0 ? "" : esc(adj.quantity.toString())
3074
+ escDec(adj.amount, esc),
3075
+ adj.quantity === void 0 ? "" : escDec(adj.quantity, esc)
2958
3076
  );
2959
3077
  triples += 1;
2960
3078
  i += 1;
@@ -3012,7 +3130,7 @@ function emitProviderAdjustments(raw, at, body, seg, esc, comp) {
3012
3130
  if (adj === void 0 || adj.providerId !== providerId || adj.fiscalPeriodDate !== fiscalPeriodDate) {
3013
3131
  break;
3014
3132
  }
3015
- parts.push(comp([adj.reasonCode, adj.subCode ?? ""]), esc(adj.amount.toString()));
3133
+ parts.push(comp([adj.reasonCode, adj.subCode ?? ""]), escDec(adj.amount, esc));
3016
3134
  pairs += 1;
3017
3135
  i += 1;
3018
3136
  }
@@ -3110,13 +3228,22 @@ var REMIT_835_LOOP_1000B = defineLoopSpec({
3110
3228
  ]
3111
3229
  });
3112
3230
 
3231
+ // src/parser/lookup.ts
3232
+ function wireLookup(entries) {
3233
+ const table = /* @__PURE__ */ Object.create(null);
3234
+ for (const [key, value] of Object.entries(entries)) {
3235
+ table[key] = value;
3236
+ }
3237
+ return Object.freeze(table);
3238
+ }
3239
+
3113
3240
  // src/transactions/claim/get-837.ts
3114
- var VARIANT_BY_ICR = Object.freeze({
3241
+ var VARIANT_BY_ICR = wireLookup({
3115
3242
  "005010X222A2": "P",
3116
3243
  "005010X223A3": "I",
3117
3244
  "005010X224A2": "D"
3118
3245
  });
3119
- var VARIANT_BY_SV_SEGMENT = Object.freeze({
3246
+ var VARIANT_BY_SV_SEGMENT = wireLookup({
3120
3247
  SV1: "P",
3121
3248
  SV2: "I",
3122
3249
  SV3: "D"
@@ -3137,7 +3264,7 @@ var NM1_QUALIFIERS = Object.freeze({
3137
3264
  PAYER: "PR",
3138
3265
  PATIENT: "QC"
3139
3266
  });
3140
- var EXPECTED_PARENT_LEVEL = Object.freeze({
3267
+ var EXPECTED_PARENT_LEVEL = wireLookup({
3141
3268
  [HL_LEVEL_CODES.INFORMATION_SOURCE]: void 0,
3142
3269
  [HL_LEVEL_CODES.SUBSCRIBER]: HL_LEVEL_CODES.INFORMATION_SOURCE,
3143
3270
  [HL_LEVEL_CODES.DEPENDENT]: HL_LEVEL_CODES.SUBSCRIBER
@@ -3159,7 +3286,7 @@ function get837Claims(delimiters, tx, opts) {
3159
3286
  }
3160
3287
  const variant = explicitType ?? variantFromIcr ?? variantFromSegment ?? "unknown";
3161
3288
  if (variant === "unknown") {
3162
- warnings.push(unknown837Variant({ segmentIndex: 1, transactionIndex: 0 }));
3289
+ warnings.push(unknown837Variant({ segmentIndex: 0, transactionIndex: 0 }));
3163
3290
  }
3164
3291
  const hierarchies = [];
3165
3292
  const hlIndex = /* @__PURE__ */ new Map();
@@ -3182,7 +3309,9 @@ function get837Claims(delimiters, tx, opts) {
3182
3309
  let currentOtherSubscriber;
3183
3310
  let currentAdjudication;
3184
3311
  let context = { kind: "header" };
3312
+ let droppedLineReported = false;
3185
3313
  let activeEntity;
3314
+ let entityLoopClosedByStrayLx = false;
3186
3315
  const flushAdjudication = () => {
3187
3316
  if (currentAdjudication !== void 0 && currentServiceLine !== void 0) {
3188
3317
  currentServiceLine.adjudications.push(freezeAdjudication(currentAdjudication));
@@ -3192,9 +3321,21 @@ function get837Claims(delimiters, tx, opts) {
3192
3321
  const flushServiceLine = () => {
3193
3322
  flushAdjudication();
3194
3323
  if (currentServiceLine !== void 0 && currentClaim !== void 0) {
3324
+ if (!currentServiceLine.serviceSegmentDecoded) {
3325
+ warnings.push(serviceLineNotDecoded(currentServiceLine.position));
3326
+ }
3195
3327
  currentClaim.serviceLines.push(freezeServiceLine2(currentServiceLine));
3196
3328
  }
3197
3329
  currentServiceLine = void 0;
3330
+ droppedLineReported = false;
3331
+ };
3332
+ const reportOrphanServiceSegment = (position) => {
3333
+ if (droppedLineReported) return;
3334
+ warnings.push(serviceSegmentWithoutLx(position));
3335
+ };
3336
+ const reportDiscardedEntitySegment = (position) => {
3337
+ if (!entityLoopClosedByStrayLx) return;
3338
+ warnings.push(entitySegmentDiscardedAfterLx(position));
3198
3339
  };
3199
3340
  const flushOtherSubscriber = () => {
3200
3341
  if (currentOtherSubscriber !== void 0 && currentClaim !== void 0) {
@@ -3265,6 +3406,7 @@ function get837Claims(delimiters, tx, opts) {
3265
3406
  const seg = body[i];
3266
3407
  if (seg === void 0) continue;
3267
3408
  const position = { segmentIndex: i + 1, transactionIndex: 0 };
3409
+ const sink = { warnings, position };
3268
3410
  switch (seg.id) {
3269
3411
  case "HL": {
3270
3412
  flushClaim();
@@ -3297,6 +3439,7 @@ function get837Claims(delimiters, tx, opts) {
3297
3439
  context = { kind: "header" };
3298
3440
  }
3299
3441
  activeEntity = void 0;
3442
+ entityLoopClosedByStrayLx = false;
3300
3443
  break;
3301
3444
  }
3302
3445
  case "SBR": {
@@ -3313,6 +3456,7 @@ function get837Claims(delimiters, tx, opts) {
3313
3456
  otherPayer: void 0
3314
3457
  };
3315
3458
  activeEntity = { kind: "otherSubscriber" };
3459
+ entityLoopClosedByStrayLx = false;
3316
3460
  }
3317
3461
  break;
3318
3462
  }
@@ -3328,6 +3472,7 @@ function get837Claims(delimiters, tx, opts) {
3328
3472
  case "NM1": {
3329
3473
  const qualifier = elementValue(seg, 1, delimiters);
3330
3474
  const entity = decodeNm12(seg, delimiters);
3475
+ entityLoopClosedByStrayLx = false;
3331
3476
  if (qualifier === NM1_QUALIFIERS.SUBMITTER) {
3332
3477
  submitter = entity;
3333
3478
  activeEntity = { kind: "submitter" };
@@ -3372,16 +3517,19 @@ function get837Claims(delimiters, tx, opts) {
3372
3517
  case "N3": {
3373
3518
  const lines = collectElementValues(seg, 1, 2, delimiters);
3374
3519
  attachAddressLines(lines, activeEntity, entityMutators);
3520
+ reportDiscardedEntitySegment(position);
3375
3521
  break;
3376
3522
  }
3377
3523
  case "N4": {
3378
3524
  const partial = decodeN42(seg, delimiters);
3379
3525
  attachAddressFields(partial, activeEntity, entityMutators);
3526
+ reportDiscardedEntitySegment(position);
3380
3527
  break;
3381
3528
  }
3382
3529
  case "PER": {
3383
3530
  const contact = decodePer2(seg, delimiters);
3384
3531
  attachContact(contact, activeEntity, entityMutators);
3532
+ reportDiscardedEntitySegment(position);
3385
3533
  break;
3386
3534
  }
3387
3535
  case "REF": {
@@ -3393,6 +3541,7 @@ function get837Claims(delimiters, tx, opts) {
3393
3541
  currentClaim.references.push(ref);
3394
3542
  } else {
3395
3543
  attachReference(ref, activeEntity, entityMutators);
3544
+ reportDiscardedEntitySegment(position);
3396
3545
  }
3397
3546
  break;
3398
3547
  }
@@ -3412,17 +3561,23 @@ function get837Claims(delimiters, tx, opts) {
3412
3561
  warnings.push(missingRequiredLoop(position, REQUIRED_LOOPS.PAYER_NAME_2010BB));
3413
3562
  }
3414
3563
  }
3415
- currentClaim = openClaim2(seg, delimiters, {
3416
- variant,
3417
- hierarchy: currentPatientHl ?? currentSubscriberHl,
3418
- billingProvider,
3419
- payToAddress,
3420
- payToPlan,
3421
- subscriber: currentSubscriberMember,
3422
- payer: currentPayer,
3423
- patient: currentPatientMember
3424
- });
3564
+ currentClaim = openClaim2(
3565
+ seg,
3566
+ delimiters,
3567
+ {
3568
+ variant,
3569
+ hierarchy: currentPatientHl ?? currentSubscriberHl,
3570
+ billingProvider,
3571
+ payToAddress,
3572
+ payToPlan,
3573
+ subscriber: currentSubscriberMember,
3574
+ payer: currentPayer,
3575
+ patient: currentPatientMember
3576
+ },
3577
+ sink
3578
+ );
3425
3579
  activeEntity = void 0;
3580
+ entityLoopClosedByStrayLx = false;
3426
3581
  context = { kind: "loop2300" };
3427
3582
  break;
3428
3583
  }
@@ -3460,7 +3615,7 @@ function get837Claims(delimiters, tx, opts) {
3460
3615
  break;
3461
3616
  }
3462
3617
  case "AMT": {
3463
- const amount = decodeAmt2(seg, delimiters);
3618
+ const amount = decodeAmt2(seg, delimiters, sink);
3464
3619
  if (amount === void 0) break;
3465
3620
  if (currentAdjudication !== void 0) break;
3466
3621
  if (currentServiceLine !== void 0) currentServiceLine.amounts.push(amount);
@@ -3469,22 +3624,55 @@ function get837Claims(delimiters, tx, opts) {
3469
3624
  }
3470
3625
  case "LX": {
3471
3626
  flushServiceLine();
3472
- if (currentClaim === void 0) break;
3473
- currentServiceLine = openServiceLine2(seg, delimiters, currentClaim.variant);
3627
+ if (currentClaim === void 0) {
3628
+ warnings.push(serviceLineDropped(position));
3629
+ droppedLineReported = true;
3630
+ entityLoopClosedByStrayLx ||= activeEntity !== void 0;
3631
+ activeEntity = void 0;
3632
+ break;
3633
+ }
3634
+ currentServiceLine = openServiceLine2(seg, delimiters, currentClaim.variant, position);
3635
+ if (currentServiceLine === void 0) {
3636
+ warnings.push(serviceLineDropped(position));
3637
+ droppedLineReported = true;
3638
+ }
3474
3639
  activeEntity = void 0;
3640
+ entityLoopClosedByStrayLx = false;
3475
3641
  context = { kind: "loop2400" };
3476
3642
  break;
3477
3643
  }
3644
+ // A service segment with no line open to decode into is a loss the
3645
+ // walker used to take in silence. Two ways to reach it, and only one
3646
+ // was ever reported: an LX that opened nothing already warned at the
3647
+ // LX (`droppedLineReported`), while a segment with no Loop 2400 open
3648
+ // at all had no anchor to warn at and so reported on no channel - a
3649
+ // charge, a quantity, a procedure code and its modifiers off the wire
3650
+ // and onto nothing. `reportOrphanServiceSegment` closes only the
3651
+ // second: it anchors at the service segment itself, because that is
3652
+ // the only segment the case has. Note the condition is "no line open",
3653
+ // NOT "no LX in the file": an LX in an earlier claim is still an LX.
3654
+ //
3655
+ // It does NOT decode the segment. The charge is SV1-02 / SV2-03 and
3656
+ // the units SV1-04 / SV2-05 / SV3-06, so reading a service segment
3657
+ // into a line the walker never opened is how a mis-read charge gets
3658
+ // minted. Refusing to read is the safe half; doing it silently was the
3659
+ // defect. This says nothing about VARIANT resolution, which happens
3660
+ // before the walk and scans every SVx in the body: an orphan segment
3661
+ // is eligible for that fallback like any other, which is pre-existing
3662
+ // and disclosed in KNOWN-LIMITATIONS.md rather than changed here.
3478
3663
  case "SV1": {
3479
- if (currentServiceLine !== void 0) decodeSv1(currentServiceLine, seg, delimiters);
3664
+ if (currentServiceLine !== void 0) decodeSv1(currentServiceLine, seg, delimiters, sink);
3665
+ else reportOrphanServiceSegment(position);
3480
3666
  break;
3481
3667
  }
3482
3668
  case "SV2": {
3483
- if (currentServiceLine !== void 0) decodeSv2(currentServiceLine, seg, delimiters);
3669
+ if (currentServiceLine !== void 0) decodeSv2(currentServiceLine, seg, delimiters, sink);
3670
+ else reportOrphanServiceSegment(position);
3484
3671
  break;
3485
3672
  }
3486
3673
  case "SV3": {
3487
- if (currentServiceLine !== void 0) decodeSv3(currentServiceLine, seg, delimiters);
3674
+ if (currentServiceLine !== void 0) decodeSv3(currentServiceLine, seg, delimiters, sink);
3675
+ else reportOrphanServiceSegment(position);
3488
3676
  break;
3489
3677
  }
3490
3678
  case "TOO": {
@@ -3510,7 +3698,7 @@ function get837Claims(delimiters, tx, opts) {
3510
3698
  }
3511
3699
  currentServiceLine.drug = {
3512
3700
  ...currentServiceLine.drug,
3513
- quantity: elementDecimal(seg, 4, delimiters),
3701
+ quantity: elementDecimal(seg, 4, delimiters, sink),
3514
3702
  unitOfMeasure: componentOptional(seg, 5, 1, delimiters)
3515
3703
  };
3516
3704
  break;
@@ -3518,7 +3706,7 @@ function get837Claims(delimiters, tx, opts) {
3518
3706
  case "SVD": {
3519
3707
  flushAdjudication();
3520
3708
  if (currentServiceLine === void 0) break;
3521
- currentAdjudication = openAdjudication(seg, delimiters);
3709
+ currentAdjudication = openAdjudication(seg, delimiters, sink);
3522
3710
  break;
3523
3711
  }
3524
3712
  case "CAS": {
@@ -3696,19 +3884,20 @@ function decodeNte(seg, delimiters) {
3696
3884
  description: note
3697
3885
  });
3698
3886
  }
3699
- function decodeAmt2(seg, delimiters) {
3700
- const amount = elementDecimal(seg, 2, delimiters);
3887
+ function decodeAmt2(seg, delimiters, sink) {
3888
+ const amount = elementDecimal(seg, 2, delimiters, sink);
3701
3889
  if (amount === void 0) return void 0;
3702
3890
  return Object.freeze({ qualifier: elementValue(seg, 1, delimiters), amount });
3703
3891
  }
3704
3892
  function decodeCas(seg, delimiters, warnings, position) {
3893
+ const sink = { warnings, position };
3705
3894
  const groupCode = elementValue(seg, 1, delimiters);
3706
3895
  const out = [];
3707
3896
  for (let triple = 0; triple < 6; triple += 1) {
3708
3897
  const base = 2 + triple * 3;
3709
3898
  const reasonCode = elementOptional(seg, base, delimiters);
3710
- const amount = elementDecimal(seg, base + 1, delimiters);
3711
- const quantity = elementDecimal(seg, base + 2, delimiters);
3899
+ const amount = elementDecimal(seg, base + 1, delimiters, sink);
3900
+ const quantity = elementDecimal(seg, base + 2, delimiters, sink);
3712
3901
  if (reasonCode === void 0 && amount === void 0) continue;
3713
3902
  const code = reasonCode ?? "";
3714
3903
  const entry = code === "" ? void 0 : lookupCarc(code);
@@ -3743,7 +3932,7 @@ var EMPTY_SUBSCRIBER_INFO = Object.freeze({
3743
3932
  groupName: void 0,
3744
3933
  claimFilingIndicator: void 0
3745
3934
  });
3746
- function openClaim2(seg, delimiters, ctx) {
3935
+ function openClaim2(seg, delimiters, ctx, sink) {
3747
3936
  const {
3748
3937
  variant,
3749
3938
  hierarchy,
@@ -3764,7 +3953,7 @@ function openClaim2(seg, delimiters, ctx) {
3764
3953
  payer,
3765
3954
  patient,
3766
3955
  claimId: elementValue(seg, 1, delimiters),
3767
- totalCharge: elementDecimalOrZero(seg, 2, delimiters),
3956
+ totalCharge: elementDecimalOrZero(seg, 2, delimiters, sink),
3768
3957
  placeOfServiceCode: componentOptional(seg, 5, 1, delimiters),
3769
3958
  facilityCodeQualifier: componentOptional(seg, 5, 2, delimiters),
3770
3959
  claimFrequencyCode: componentOptional(seg, 5, 3, delimiters),
@@ -3784,10 +3973,12 @@ function openClaim2(seg, delimiters, ctx) {
3784
3973
  serviceLines: []
3785
3974
  };
3786
3975
  }
3787
- function openServiceLine2(seg, delimiters, variant) {
3976
+ function openServiceLine2(seg, delimiters, variant, position) {
3788
3977
  const lineNumber = elementValue(seg, 1, delimiters);
3789
3978
  const base = {
3790
3979
  lineNumber,
3980
+ position,
3981
+ serviceSegmentDecoded: false,
3791
3982
  charge: X12Decimal.ZERO,
3792
3983
  units: X12Decimal.ZERO,
3793
3984
  unitOfMeasure: void 0,
@@ -3839,8 +4030,9 @@ function openServiceLine2(seg, delimiters, variant) {
3839
4030
  }
3840
4031
  return void 0;
3841
4032
  }
3842
- function decodeSv1(acc, seg, delimiters) {
4033
+ function decodeSv1(acc, seg, delimiters, sink) {
3843
4034
  if (acc.variant !== "P") return;
4035
+ acc.serviceSegmentDecoded = true;
3844
4036
  acc.procedureQualifier = componentOptional(seg, 1, 1, delimiters) ?? "";
3845
4037
  acc.procedureCode = componentOptional(seg, 1, 2, delimiters) ?? "";
3846
4038
  const mods = [];
@@ -3849,9 +4041,9 @@ function decodeSv1(acc, seg, delimiters) {
3849
4041
  if (m !== void 0) mods.push(m);
3850
4042
  }
3851
4043
  acc.modifiers = mods;
3852
- acc.charge = elementDecimalOrZero(seg, 2, delimiters);
4044
+ acc.charge = elementDecimalOrZero(seg, 2, delimiters, sink);
3853
4045
  acc.unitOfMeasure = elementOptional(seg, 3, delimiters);
3854
- acc.units = elementDecimalOrZero(seg, 4, delimiters);
4046
+ acc.units = elementDecimalOrZero(seg, 4, delimiters, sink);
3855
4047
  acc.placeOfServiceCode = elementOptional(seg, 5, delimiters);
3856
4048
  const pointers = [];
3857
4049
  for (let p = 1; p <= 4; p += 1) {
@@ -3863,8 +4055,9 @@ function decodeSv1(acc, seg, delimiters) {
3863
4055
  acc.epsdtIndicator = elementOptional(seg, 11, delimiters);
3864
4056
  acc.familyPlanningIndicator = elementOptional(seg, 12, delimiters);
3865
4057
  }
3866
- function decodeSv2(acc, seg, delimiters) {
4058
+ function decodeSv2(acc, seg, delimiters, sink) {
3867
4059
  if (acc.variant !== "I") return;
4060
+ acc.serviceSegmentDecoded = true;
3868
4061
  acc.revenueCode = elementValue(seg, 1, delimiters);
3869
4062
  acc.procedureQualifier = componentOptional(seg, 2, 1, delimiters);
3870
4063
  acc.procedureCode = componentOptional(seg, 2, 2, delimiters);
@@ -3874,14 +4067,15 @@ function decodeSv2(acc, seg, delimiters) {
3874
4067
  if (m !== void 0) mods.push(m);
3875
4068
  }
3876
4069
  acc.modifiers = mods;
3877
- acc.charge = elementDecimalOrZero(seg, 3, delimiters);
4070
+ acc.charge = elementDecimalOrZero(seg, 3, delimiters, sink);
3878
4071
  acc.unitOfMeasure = elementOptional(seg, 4, delimiters);
3879
- acc.units = elementDecimalOrZero(seg, 5, delimiters);
3880
- acc.serviceLineRate = elementDecimal(seg, 6, delimiters);
3881
- acc.nonCoveredCharge = elementDecimal(seg, 7, delimiters);
4072
+ acc.units = elementDecimalOrZero(seg, 5, delimiters, sink);
4073
+ acc.serviceLineRate = elementDecimal(seg, 6, delimiters, sink);
4074
+ acc.nonCoveredCharge = elementDecimal(seg, 7, delimiters, sink);
3882
4075
  }
3883
- function decodeSv3(acc, seg, delimiters) {
4076
+ function decodeSv3(acc, seg, delimiters, sink) {
3884
4077
  if (acc.variant !== "D") return;
4078
+ acc.serviceSegmentDecoded = true;
3885
4079
  acc.procedureQualifier = componentOptional(seg, 1, 1, delimiters) ?? "";
3886
4080
  acc.procedureCode = componentOptional(seg, 1, 2, delimiters) ?? "";
3887
4081
  const mods = [];
@@ -3890,7 +4084,7 @@ function decodeSv3(acc, seg, delimiters) {
3890
4084
  if (m !== void 0) mods.push(m);
3891
4085
  }
3892
4086
  acc.modifiers = mods;
3893
- acc.charge = elementDecimalOrZero(seg, 2, delimiters);
4087
+ acc.charge = elementDecimalOrZero(seg, 2, delimiters, sink);
3894
4088
  acc.placeOfServiceCode = elementOptional(seg, 3, delimiters);
3895
4089
  const cavities = [];
3896
4090
  for (let p = 1; p <= 5; p += 1) {
@@ -3899,15 +4093,15 @@ function decodeSv3(acc, seg, delimiters) {
3899
4093
  }
3900
4094
  acc.oralCavityArea = cavities;
3901
4095
  acc.prosthesisCrownInlayCode = elementOptional(seg, 5, delimiters);
3902
- acc.units = elementDecimalOrZero(seg, 6, delimiters);
4096
+ acc.units = elementDecimalOrZero(seg, 6, delimiters, sink);
3903
4097
  }
3904
- function openAdjudication(seg, delimiters) {
4098
+ function openAdjudication(seg, delimiters, sink) {
3905
4099
  return {
3906
4100
  otherPayerId: elementValue(seg, 1, delimiters),
3907
- amountPaid: elementDecimalOrZero(seg, 2, delimiters),
4101
+ amountPaid: elementDecimalOrZero(seg, 2, delimiters, sink),
3908
4102
  procedureQualifier: componentOptional(seg, 3, 1, delimiters),
3909
4103
  procedureCode: componentOptional(seg, 3, 2, delimiters),
3910
- paidUnits: elementDecimal(seg, 5, delimiters),
4104
+ paidUnits: elementDecimal(seg, 5, delimiters, sink),
3911
4105
  adjustments: [],
3912
4106
  dateAdjudicated: void 0
3913
4107
  };
@@ -4199,6 +4393,12 @@ function refuseHierarchy(message) {
4199
4393
  function refuseSpec2(message) {
4200
4394
  throw new Claim837BuildError(CLAIM_837_BUILD_ERROR_CODES.X12_837_BUILD_INVALID_SPEC, message);
4201
4395
  }
4396
+ function decStr(value) {
4397
+ return requireCallerDecimal(value, "build837", refuseSpec2).toString();
4398
+ }
4399
+ function escDec2(value, esc) {
4400
+ return esc(decStr(value));
4401
+ }
4202
4402
  var VERSION_BY_VARIANT = {
4203
4403
  P: "005010X222A2",
4204
4404
  I: "005010X223A3",
@@ -4232,6 +4432,7 @@ function buildClaim837(variant, spec) {
4232
4432
  };
4233
4433
  const esc = makeCallerEscaper(delimiters, "build837", refuseSpec2);
4234
4434
  const seg = (parts) => {
4435
+ requireCallerSegment(parts, "build837", refuseSpec2);
4235
4436
  let end = parts.length;
4236
4437
  while (end > 1 && parts[end - 1] === "") end -= 1;
4237
4438
  return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
@@ -4275,8 +4476,8 @@ function buildClaim837(variant, spec) {
4275
4476
  X12_837_FUNCTIONAL_ID,
4276
4477
  esc(applicationSenderCode),
4277
4478
  esc(applicationReceiverCode),
4278
- groupDate,
4279
- groupTime,
4479
+ esc(groupDate),
4480
+ esc(groupTime),
4280
4481
  esc(envelope.groupControlNumber),
4281
4482
  X12_AGENCY_CODE2,
4282
4483
  versionRelease
@@ -4491,7 +4692,7 @@ function emitClaim2(variant, claim, body, ctx) {
4491
4692
  ctx.seg([
4492
4693
  "CLM",
4493
4694
  ctx.esc(claim.claimId),
4494
- ctx.esc(claim.totalCharge.toString()),
4695
+ escDec2(claim.totalCharge, ctx.esc),
4495
4696
  "",
4496
4697
  "",
4497
4698
  ctx.comp([
@@ -4539,8 +4740,8 @@ function emitOtherSubscriber(other, body, ctx) {
4539
4740
  if (other.otherPayer !== void 0) emitEntity(other.otherPayer, body, ctx);
4540
4741
  }
4541
4742
  function emitServiceLine2(variant, line, lineNumber, body, ctx) {
4542
- body.push(ctx.seg(["LX", line.lineNumber ?? String(lineNumber)]));
4543
- const units = line.units === void 0 ? "0" : line.units.toString();
4743
+ body.push(ctx.seg(["LX", ctx.esc(line.lineNumber ?? String(lineNumber))]));
4744
+ const units = line.units === void 0 ? "0" : decStr(line.units);
4544
4745
  if (line.variant === "P") {
4545
4746
  const proc = ctx.comp([line.procedureQualifier, line.procedureCode, ...line.modifiers ?? []]);
4546
4747
  const pointers = ctx.comp(line.diagnosisPointers ?? []);
@@ -4548,7 +4749,7 @@ function emitServiceLine2(variant, line, lineNumber, body, ctx) {
4548
4749
  ctx.seg([
4549
4750
  "SV1",
4550
4751
  proc,
4551
- ctx.esc(line.charge.toString()),
4752
+ escDec2(line.charge, ctx.esc),
4552
4753
  ctx.esc(line.unitOfMeasure ?? ""),
4553
4754
  ctx.esc(units),
4554
4755
  ctx.esc(line.placeOfServiceCode ?? ""),
@@ -4572,11 +4773,11 @@ function emitServiceLine2(variant, line, lineNumber, body, ctx) {
4572
4773
  "SV2",
4573
4774
  ctx.esc(line.revenueCode),
4574
4775
  proc,
4575
- ctx.esc(line.charge.toString()),
4776
+ escDec2(line.charge, ctx.esc),
4576
4777
  ctx.esc(line.unitOfMeasure ?? ""),
4577
4778
  ctx.esc(units),
4578
- line.serviceLineRate === void 0 ? "" : ctx.esc(line.serviceLineRate.toString()),
4579
- line.nonCoveredCharge === void 0 ? "" : ctx.esc(line.nonCoveredCharge.toString())
4779
+ line.serviceLineRate === void 0 ? "" : escDec2(line.serviceLineRate, ctx.esc),
4780
+ line.nonCoveredCharge === void 0 ? "" : escDec2(line.nonCoveredCharge, ctx.esc)
4580
4781
  ])
4581
4782
  );
4582
4783
  } else {
@@ -4586,7 +4787,7 @@ function emitServiceLine2(variant, line, lineNumber, body, ctx) {
4586
4787
  ctx.seg([
4587
4788
  "SV3",
4588
4789
  proc,
4589
- ctx.esc(line.charge.toString()),
4790
+ escDec2(line.charge, ctx.esc),
4590
4791
  ctx.esc(line.placeOfServiceCode ?? ""),
4591
4792
  cavity,
4592
4793
  ctx.esc(line.prosthesisCrownInlayCode ?? ""),
@@ -4605,7 +4806,7 @@ function emitServiceLine2(variant, line, lineNumber, body, ctx) {
4605
4806
  "",
4606
4807
  "",
4607
4808
  "",
4608
- drug.quantity === void 0 ? "" : ctx.esc(drug.quantity.toString()),
4809
+ drug.quantity === void 0 ? "" : escDec2(drug.quantity, ctx.esc),
4609
4810
  ctx.esc(drug.unitOfMeasure ?? "")
4610
4811
  ])
4611
4812
  );
@@ -4635,10 +4836,10 @@ function emitAdjudication(adj, body, ctx) {
4635
4836
  ctx.seg([
4636
4837
  "SVD",
4637
4838
  ctx.esc(adj.otherPayerId),
4638
- ctx.esc(adj.amountPaid.toString()),
4839
+ escDec2(adj.amountPaid, ctx.esc),
4639
4840
  proc,
4640
4841
  "",
4641
- adj.paidUnits === void 0 ? "" : ctx.esc(adj.paidUnits.toString())
4842
+ adj.paidUnits === void 0 ? "" : escDec2(adj.paidUnits, ctx.esc)
4642
4843
  ])
4643
4844
  );
4644
4845
  emitCasGroup2(adj.adjustments, "build837: adjudication.adjustments", body, ctx);
@@ -4663,8 +4864,8 @@ function emitCasGroup2(raw, at, body, ctx) {
4663
4864
  if (adj === void 0 || adj.groupCode !== groupCode) break;
4664
4865
  parts.push(
4665
4866
  ctx.esc(adj.reasonCode),
4666
- ctx.esc(adj.amount.toString()),
4667
- adj.quantity === void 0 ? "" : ctx.esc(adj.quantity.toString())
4867
+ escDec2(adj.amount, ctx.esc),
4868
+ adj.quantity === void 0 ? "" : escDec2(adj.quantity, ctx.esc)
4668
4869
  );
4669
4870
  triples += 1;
4670
4871
  i += 1;
@@ -4735,7 +4936,7 @@ function emitNote(note, body, ctx) {
4735
4936
  body.push(ctx.seg(["NTE", ctx.esc(note.noteReferenceCode), ctx.esc(note.description)]));
4736
4937
  }
4737
4938
  function emitAmount(amt, body, ctx) {
4738
- body.push(ctx.seg(["AMT", ctx.esc(amt.qualifier), ctx.esc(amt.amount.toString())]));
4939
+ body.push(ctx.seg(["AMT", ctx.esc(amt.qualifier), escDec2(amt.amount, ctx.esc)]));
4739
4940
  }
4740
4941
  function emitHi(hi, body, ctx) {
4741
4942
  const composite = ctx.comp([
@@ -4743,8 +4944,10 @@ function emitHi(hi, body, ctx) {
4743
4944
  hi.code,
4744
4945
  hi.dateQualifier ?? "",
4745
4946
  hi.date ?? "",
4746
- hi.monetaryAmount === void 0 ? "" : hi.monetaryAmount.toString(),
4747
- hi.quantity === void 0 ? "" : hi.quantity.toString(),
4947
+ // `decStr`, not `escDec`: `ctx.comp` maps `esc` over every component, so
4948
+ // escaping here would double-release an active delimiter.
4949
+ hi.monetaryAmount === void 0 ? "" : decStr(hi.monetaryAmount),
4950
+ hi.quantity === void 0 ? "" : decStr(hi.quantity),
4748
4951
  hi.versionId ?? "",
4749
4952
  "",
4750
4953
  hi.poaIndicator ?? ""
@@ -5056,6 +5259,7 @@ function get271Eligibility(delimiters, tx) {
5056
5259
  const seg = body[i];
5057
5260
  if (seg === void 0) continue;
5058
5261
  const position = { segmentIndex: i + 1, transactionIndex: 0 };
5262
+ const sink = { warnings, position };
5059
5263
  switch (seg.id) {
5060
5264
  case "HL": {
5061
5265
  const hl = decodeHl2(seg, delimiters);
@@ -5159,7 +5363,7 @@ function get271Eligibility(delimiters, tx) {
5159
5363
  case "EB": {
5160
5364
  flushBenefit();
5161
5365
  if (currentSubscriber === void 0 && currentDependent === void 0) break;
5162
- currentBenefit = openBenefit(seg, delimiters);
5366
+ currentBenefit = openBenefit(seg, delimiters, sink);
5163
5367
  break;
5164
5368
  }
5165
5369
  case "MSG": {
@@ -5256,7 +5460,7 @@ function decodeDtp2(seg, delimiters) {
5256
5460
  value
5257
5461
  });
5258
5462
  }
5259
- function openBenefit(seg, delimiters) {
5463
+ function openBenefit(seg, delimiters, sink) {
5260
5464
  const serviceTypeCodes = [];
5261
5465
  for (const code of getAllSegmentValues(seg, "03", delimiters)) {
5262
5466
  if (code === "") continue;
@@ -5271,10 +5475,10 @@ function openBenefit(seg, delimiters) {
5271
5475
  insuranceTypeCode: elementOptional(seg, 4, delimiters),
5272
5476
  planCoverageDescription: elementOptional(seg, 5, delimiters),
5273
5477
  timePeriodQualifier: elementOptional(seg, 6, delimiters),
5274
- monetaryAmount: elementDecimal(seg, 7, delimiters),
5275
- percent: elementDecimal(seg, 8, delimiters),
5478
+ monetaryAmount: elementDecimal(seg, 7, delimiters, sink),
5479
+ percent: elementDecimal(seg, 8, delimiters, sink),
5276
5480
  quantityQualifier: elementOptional(seg, 9, delimiters),
5277
- quantity: elementDecimal(seg, 10, delimiters),
5481
+ quantity: elementDecimal(seg, 10, delimiters, sink),
5278
5482
  authorizationRequired: elementOptional(seg, 11, delimiters),
5279
5483
  inPlanNetwork: elementOptional(seg, 12, delimiters),
5280
5484
  references: [],
@@ -5377,6 +5581,9 @@ function refuseSpec3(message) {
5377
5581
  message
5378
5582
  );
5379
5583
  }
5584
+ function escDec3(value, esc) {
5585
+ return esc(requireCallerDecimal(value, "build271", refuseSpec3).toString());
5586
+ }
5380
5587
  var X279A1_VERSION_RELEASE = "005010X279A1";
5381
5588
  var X12_271_FUNCTIONAL_ID = "HB";
5382
5589
  var X12_AGENCY_CODE3 = "X";
@@ -5396,6 +5603,7 @@ function build271(spec) {
5396
5603
  };
5397
5604
  const esc = makeCallerEscaper(delimiters, "build271", refuseSpec3);
5398
5605
  const seg = (parts) => {
5606
+ requireCallerSegment(parts, "build271", refuseSpec3);
5399
5607
  let end = parts.length;
5400
5608
  while (end > 1 && parts[end - 1] === "") end -= 1;
5401
5609
  return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
@@ -5433,8 +5641,8 @@ function build271(spec) {
5433
5641
  X12_271_FUNCTIONAL_ID,
5434
5642
  esc(applicationSenderCode),
5435
5643
  esc(applicationReceiverCode),
5436
- groupDate,
5437
- groupTime,
5644
+ esc(groupDate),
5645
+ esc(groupTime),
5438
5646
  esc(envelope.groupControlNumber),
5439
5647
  X12_AGENCY_CODE3,
5440
5648
  X279A1_VERSION_RELEASE
@@ -5604,10 +5812,10 @@ function emitBenefit(benefit, body, ctx) {
5604
5812
  ctx.esc(benefit.insuranceTypeCode ?? ""),
5605
5813
  ctx.esc(benefit.planCoverageDescription ?? ""),
5606
5814
  ctx.esc(benefit.timePeriodQualifier ?? ""),
5607
- benefit.monetaryAmount === void 0 ? "" : ctx.esc(benefit.monetaryAmount.toString()),
5608
- benefit.percent === void 0 ? "" : ctx.esc(benefit.percent.toString()),
5815
+ benefit.monetaryAmount === void 0 ? "" : escDec3(benefit.monetaryAmount, ctx.esc),
5816
+ benefit.percent === void 0 ? "" : escDec3(benefit.percent, ctx.esc),
5609
5817
  ctx.esc(benefit.quantityQualifier ?? ""),
5610
- benefit.quantity === void 0 ? "" : ctx.esc(benefit.quantity.toString()),
5818
+ benefit.quantity === void 0 ? "" : escDec3(benefit.quantity, ctx.esc),
5611
5819
  ctx.esc(benefit.authorizationRequired ?? ""),
5612
5820
  ctx.esc(benefit.inPlanNetwork ?? "")
5613
5821
  ])
@@ -5814,6 +6022,7 @@ function walk277(delimiters, tx) {
5814
6022
  const seg = body[i];
5815
6023
  if (seg === void 0) continue;
5816
6024
  const position = { segmentIndex: i + 1, transactionIndex: 0 };
6025
+ const sink = { warnings, position };
5817
6026
  switch (seg.id) {
5818
6027
  case "HL": {
5819
6028
  flushClaim();
@@ -5891,7 +6100,7 @@ function walk277(delimiters, tx) {
5891
6100
  case "SVC": {
5892
6101
  flushServiceLine();
5893
6102
  if (currentClaim === void 0) currentClaim = openClaim3();
5894
- currentServiceLine = openServiceLine3(seg, delimiters);
6103
+ currentServiceLine = openServiceLine3(seg, delimiters, sink);
5895
6104
  break;
5896
6105
  }
5897
6106
  case "REF": {
@@ -5965,6 +6174,7 @@ function decodeDtp3(seg, delimiters) {
5965
6174
  });
5966
6175
  }
5967
6176
  function decodeStc(seg, delimiters, warnings, position) {
6177
+ const sink = { warnings, position };
5968
6178
  const statuses = [];
5969
6179
  for (const elementIndex of [1, 10, 11]) {
5970
6180
  const code = decodeStatusComposite(seg, elementIndex, delimiters, warnings, position);
@@ -5973,8 +6183,8 @@ function decodeStc(seg, delimiters, warnings, position) {
5973
6183
  return Object.freeze({
5974
6184
  statusEffectiveDate: elementOptional(seg, 2, delimiters),
5975
6185
  actionCode: elementOptional(seg, 3, delimiters),
5976
- totalChargeAmount: elementDecimal(seg, 4, delimiters),
5977
- paymentAmount: elementDecimal(seg, 5, delimiters),
6186
+ totalChargeAmount: elementDecimal(seg, 4, delimiters, sink),
6187
+ paymentAmount: elementDecimal(seg, 5, delimiters, sink),
5978
6188
  adjudicationDate: elementOptional(seg, 6, delimiters),
5979
6189
  message: elementOptional(seg, 12, delimiters),
5980
6190
  statuses: Object.freeze(statuses)
@@ -6001,7 +6211,7 @@ function decodeStatusComposite(seg, n, delimiters, warnings, position) {
6001
6211
  entityCode
6002
6212
  });
6003
6213
  }
6004
- function openServiceLine3(seg, delimiters) {
6214
+ function openServiceLine3(seg, delimiters, sink) {
6005
6215
  const modifiers = [];
6006
6216
  for (let comp = 3; comp <= 6; comp += 1) {
6007
6217
  const m = componentOptional(seg, 1, comp, delimiters);
@@ -6011,9 +6221,13 @@ function openServiceLine3(seg, delimiters) {
6011
6221
  serviceIdQualifier: componentOptional(seg, 1, 1, delimiters),
6012
6222
  procedureCode: componentOptional(seg, 1, 2, delimiters),
6013
6223
  modifiers,
6014
- lineChargeAmount: elementDecimal(seg, 2, delimiters),
6015
- linePaymentAmount: elementDecimal(seg, 3, delimiters),
6224
+ lineChargeAmount: elementDecimal(seg, 2, delimiters, sink),
6225
+ linePaymentAmount: elementDecimal(seg, 3, delimiters, sink),
6016
6226
  revenueCode: elementOptional(seg, 4, delimiters),
6227
+ // SVC-07. SVC-05 (Quantity) and SVC-06 (a second composite) are NOT USED
6228
+ // in both X212 and X214, so they are deliberately left unread rather than
6229
+ // decoded "for symmetry" with the 835, whose SVC-05 IS the paid count.
6230
+ unitsOfService: elementDecimal(seg, 7, delimiters, sink),
6017
6231
  statuses: [],
6018
6232
  references: [],
6019
6233
  dates: []
@@ -6027,6 +6241,7 @@ function freezeServiceLine3(acc) {
6027
6241
  lineChargeAmount: acc.lineChargeAmount,
6028
6242
  linePaymentAmount: acc.linePaymentAmount,
6029
6243
  revenueCode: acc.revenueCode,
6244
+ unitsOfService: acc.unitsOfService,
6030
6245
  statuses: Object.freeze(acc.statuses.slice()),
6031
6246
  references: Object.freeze(acc.references.slice()),
6032
6247
  dates: Object.freeze(acc.dates.slice())
@@ -6075,6 +6290,9 @@ function refuseSpec4(message) {
6075
6290
  message
6076
6291
  );
6077
6292
  }
6293
+ function escDec4(value, esc) {
6294
+ return esc(requireCallerDecimal(value, "build277", refuseSpec4).toString());
6295
+ }
6078
6296
  var X12_277_FUNCTIONAL_ID = "HN";
6079
6297
  var X12_AGENCY_CODE4 = "X";
6080
6298
  var HL_LEVEL3 = {
@@ -6092,7 +6310,7 @@ function build277CA(spec) {
6092
6310
  }
6093
6311
  function buildClaimStatus(version, spec) {
6094
6312
  const { envelope } = spec;
6095
- enforceStructuralSpec4(spec);
6313
+ enforceStructuralSpec4(version, spec);
6096
6314
  const elementSeparator = envelope.elementSeparator ?? "*";
6097
6315
  const repetitionSeparator = envelope.repetitionSeparator ?? "^";
6098
6316
  const componentSeparator = envelope.componentSeparator ?? ":";
@@ -6105,6 +6323,7 @@ function buildClaimStatus(version, spec) {
6105
6323
  };
6106
6324
  const esc = makeCallerEscaper(delimiters, "build277", refuseSpec4);
6107
6325
  const seg = (parts) => {
6326
+ requireCallerSegment(parts, "build277", refuseSpec4);
6108
6327
  let end = parts.length;
6109
6328
  while (end > 1 && parts[end - 1] === "") end -= 1;
6110
6329
  return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
@@ -6148,8 +6367,8 @@ function buildClaimStatus(version, spec) {
6148
6367
  X12_277_FUNCTIONAL_ID,
6149
6368
  esc(applicationSenderCode),
6150
6369
  esc(applicationReceiverCode),
6151
- groupDate,
6152
- groupTime,
6370
+ esc(groupDate),
6371
+ esc(groupTime),
6153
6372
  esc(envelope.groupControlNumber),
6154
6373
  X12_AGENCY_CODE4,
6155
6374
  version
@@ -6168,7 +6387,7 @@ function buildClaimStatus(version, spec) {
6168
6387
  const raw = isa + gs + st + body.join("") + se + ge + iea;
6169
6388
  return parseX12(raw);
6170
6389
  }
6171
- function enforceStructuralSpec4(spec) {
6390
+ function enforceStructuralSpec4(version, spec) {
6172
6391
  const sources = requireCallerArray(
6173
6392
  spec.informationSources,
6174
6393
  "build277: spec.informationSources",
@@ -6226,13 +6445,13 @@ function enforceStructuralSpec4(spec) {
6226
6445
  for (let u = 0; u < subscribers.length; u += 1) {
6227
6446
  const subscriber = subscribers[u];
6228
6447
  if (subscriber === void 0) continue;
6229
- enforceSubscriber(subscriber, `${locator}.subscriber[${String(u)}]`);
6448
+ enforceSubscriber(version, subscriber, `${locator}.subscriber[${String(u)}]`);
6230
6449
  }
6231
6450
  }
6232
6451
  }
6233
6452
  }
6234
6453
  }
6235
- function enforceSubscriber(subscriber, locator) {
6454
+ function enforceSubscriber(version, subscriber, locator) {
6236
6455
  const claims = requireCallerArray(
6237
6456
  subscriber.claims,
6238
6457
  `build277: subscriber at ${locator}: claims`,
@@ -6251,7 +6470,8 @@ function enforceSubscriber(subscriber, locator) {
6251
6470
  }
6252
6471
  for (let c = 0; c < claims.length; c += 1) {
6253
6472
  const claim = claims[c];
6254
- if (claim !== void 0) enforceClaim2(claim, `${locator}.claim[${String(c)}]`, c === 0);
6473
+ if (claim !== void 0)
6474
+ enforceClaim2(version, claim, `${locator}.claim[${String(c)}]`, c === 0);
6255
6475
  }
6256
6476
  for (let d = 0; d < dependents.length; d += 1) {
6257
6477
  const dependent = dependents[d];
@@ -6270,11 +6490,12 @@ function enforceSubscriber(subscriber, locator) {
6270
6490
  }
6271
6491
  for (let c = 0; c < depClaims.length; c += 1) {
6272
6492
  const claim = depClaims[c];
6273
- if (claim !== void 0) enforceClaim2(claim, `${depLocator}.claim[${String(c)}]`, c === 0);
6493
+ if (claim !== void 0)
6494
+ enforceClaim2(version, claim, `${depLocator}.claim[${String(c)}]`, c === 0);
6274
6495
  }
6275
6496
  }
6276
6497
  }
6277
- function enforceClaim2(claim, locator, isFirst) {
6498
+ function enforceClaim2(version, claim, locator, isFirst) {
6278
6499
  const statuses = requireCallerArray(
6279
6500
  claim.statuses,
6280
6501
  `build277: claim at ${locator}: statuses`,
@@ -6303,6 +6524,12 @@ function enforceClaim2(claim, locator, isFirst) {
6303
6524
  for (let l = 0; l < serviceLines.length; l += 1) {
6304
6525
  const line = serviceLines[l];
6305
6526
  if (line === void 0) continue;
6527
+ if (version === "005010X212" && line.unitsOfService === void 0) {
6528
+ throw new ClaimStatus277BuildError(
6529
+ CLAIM_STATUS_277_BUILD_ERROR_CODES.X12_277_BUILD_INVALID_SPEC,
6530
+ `build277: service line at ${locator}.line[${String(l)}] has no unitsOfService, and SVC-07 is a required element in 005010X212. Supply the submitted count; it is never defaulted. In 005010X214 it is situational, so build277CA accepts the same line.`
6531
+ );
6532
+ }
6306
6533
  const lineStatuses = requireCallerArray(
6307
6534
  line.statuses,
6308
6535
  `build277: claim at ${locator}.line[${String(l)}]: statuses`,
@@ -6396,9 +6623,12 @@ function emitServiceLine3(line, body, ctx) {
6396
6623
  ctx.seg([
6397
6624
  "SVC",
6398
6625
  svc01,
6399
- line.lineChargeAmount === void 0 ? "" : ctx.esc(line.lineChargeAmount.toString()),
6400
- line.linePaymentAmount === void 0 ? "" : ctx.esc(line.linePaymentAmount.toString()),
6401
- ctx.esc(line.revenueCode ?? "")
6626
+ line.lineChargeAmount === void 0 ? "" : escDec4(line.lineChargeAmount, ctx.esc),
6627
+ line.linePaymentAmount === void 0 ? "" : escDec4(line.linePaymentAmount, ctx.esc),
6628
+ ctx.esc(line.revenueCode ?? ""),
6629
+ "",
6630
+ "",
6631
+ line.unitsOfService === void 0 ? "" : escDec4(line.unitsOfService, ctx.esc)
6402
6632
  ])
6403
6633
  );
6404
6634
  for (const status of line.statuses ?? []) emitStatus(status, body, ctx);
@@ -6417,8 +6647,8 @@ function emitStatus(status, body, ctx) {
6417
6647
  composite(0),
6418
6648
  ctx.esc(status.statusEffectiveDate ?? ""),
6419
6649
  ctx.esc(status.actionCode ?? ""),
6420
- status.totalChargeAmount === void 0 ? "" : ctx.esc(status.totalChargeAmount.toString()),
6421
- status.paymentAmount === void 0 ? "" : ctx.esc(status.paymentAmount.toString()),
6650
+ status.totalChargeAmount === void 0 ? "" : escDec4(status.totalChargeAmount, ctx.esc),
6651
+ status.paymentAmount === void 0 ? "" : escDec4(status.paymentAmount, ctx.esc),
6422
6652
  ctx.esc(status.adjudicationDate ?? ""),
6423
6653
  "",
6424
6654
  "",
@@ -6588,9 +6818,11 @@ function get820Payments(delimiters, tx) {
6588
6818
  for (let i = 0; i < body.length; i += 1) {
6589
6819
  const seg = body[i];
6590
6820
  if (seg === void 0) continue;
6821
+ const position = { segmentIndex: i + 1, transactionIndex: 0 };
6822
+ const sink = { warnings, position };
6591
6823
  switch (seg.id) {
6592
6824
  case "BPR": {
6593
- payment = decodeBpr2(seg, delimiters);
6825
+ payment = decodeBpr2(seg, delimiters, sink);
6594
6826
  break;
6595
6827
  }
6596
6828
  case "TRN": {
@@ -6657,13 +6889,13 @@ function get820Payments(delimiters, tx) {
6657
6889
  }
6658
6890
  case "RMR": {
6659
6891
  if (current === void 0) break;
6660
- const item = decodeRmr(seg, delimiters);
6892
+ const item = decodeRmr(seg, delimiters, sink);
6661
6893
  if (item !== void 0) current.openItems.push(item);
6662
6894
  break;
6663
6895
  }
6664
6896
  case "ADX": {
6665
6897
  if (current === void 0) break;
6666
- const adjustment = decodeAdx(seg, delimiters);
6898
+ const adjustment = decodeAdx(seg, delimiters, sink);
6667
6899
  if (adjustment !== void 0) current.adjustments.push(adjustment);
6668
6900
  break;
6669
6901
  }
@@ -6715,10 +6947,10 @@ function freezeRemittance(acc) {
6715
6947
  adjustments: Object.freeze(acc.adjustments.slice())
6716
6948
  });
6717
6949
  }
6718
- function decodeBpr2(seg, delimiters) {
6950
+ function decodeBpr2(seg, delimiters, sink) {
6719
6951
  return Object.freeze({
6720
6952
  transactionHandlingCode: elementValue(seg, 1, delimiters),
6721
- totalPremiumAmount: elementDecimalOrZero(seg, 2, delimiters),
6953
+ totalPremiumAmount: elementDecimalOrZero(seg, 2, delimiters, sink),
6722
6954
  creditDebitFlag: elementValue(seg, 3, delimiters),
6723
6955
  method: elementValue(seg, 4, delimiters),
6724
6956
  paymentFormatCode: elementOptional(seg, 5, delimiters),
@@ -6786,7 +7018,7 @@ function decodeNm13(seg, delimiters) {
6786
7018
  idCode: elementOptional(seg, 9, delimiters)
6787
7019
  });
6788
7020
  }
6789
- function decodeRmr(seg, delimiters) {
7021
+ function decodeRmr(seg, delimiters, sink) {
6790
7022
  const qualifier = elementValue(seg, 1, delimiters);
6791
7023
  const referenceId = elementValue(seg, 2, delimiters);
6792
7024
  if (qualifier === "" && referenceId === "") return void 0;
@@ -6794,12 +7026,12 @@ function decodeRmr(seg, delimiters) {
6794
7026
  qualifier,
6795
7027
  referenceId,
6796
7028
  paymentActionCode: elementOptional(seg, 3, delimiters),
6797
- amountPaid: elementDecimalOrZero(seg, 4, delimiters),
6798
- amountDue: elementDecimal(seg, 5, delimiters)
7029
+ amountPaid: elementDecimalOrZero(seg, 4, delimiters, sink),
7030
+ amountDue: elementDecimal(seg, 5, delimiters, sink)
6799
7031
  });
6800
7032
  }
6801
- function decodeAdx(seg, delimiters) {
6802
- const amount = elementDecimal(seg, 1, delimiters);
7033
+ function decodeAdx(seg, delimiters, sink) {
7034
+ const amount = elementDecimal(seg, 1, delimiters, sink);
6803
7035
  if (amount === void 0) return void 0;
6804
7036
  return Object.freeze({
6805
7037
  amount,
@@ -6860,6 +7092,9 @@ var Premium820BuildError = class extends Error {
6860
7092
  function refuseSpec5(message) {
6861
7093
  throw new Premium820BuildError(PREMIUM_820_BUILD_ERROR_CODES.X12_820_BUILD_INVALID_SPEC, message);
6862
7094
  }
7095
+ function escDec5(value, esc) {
7096
+ return esc(requireCallerDecimal(value, "build820", refuseSpec5).toString());
7097
+ }
6863
7098
  var X218_VERSION_RELEASE = "005010X218";
6864
7099
  var X12_820_FUNCTIONAL_ID = "RA";
6865
7100
  var X12_AGENCY_CODE5 = "X";
@@ -6878,6 +7113,7 @@ function build820(spec) {
6878
7113
  };
6879
7114
  const esc = makeCallerEscaper(delimiters, "build820", refuseSpec5);
6880
7115
  const seg = (parts) => {
7116
+ requireCallerSegment(parts, "build820", refuseSpec5);
6881
7117
  let end = parts.length;
6882
7118
  while (end > 1 && parts[end - 1] === "") end -= 1;
6883
7119
  return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
@@ -6933,9 +7169,9 @@ function build820(spec) {
6933
7169
  // GS-02
6934
7170
  esc(applicationReceiverCode),
6935
7171
  // GS-03
6936
- groupDate,
7172
+ esc(groupDate),
6937
7173
  // GS-04 - CCYYMMDD
6938
- groupTime,
7174
+ esc(groupTime),
6939
7175
  // GS-05 - HHMM
6940
7176
  esc(envelope.groupControlNumber),
6941
7177
  // GS-06
@@ -6951,7 +7187,7 @@ function build820(spec) {
6951
7187
  seg([
6952
7188
  "BPR",
6953
7189
  esc(spec.payment.transactionHandlingCode),
6954
- esc(spec.payment.totalPremiumAmount.toString()),
7190
+ escDec5(spec.payment.totalPremiumAmount, esc),
6955
7191
  esc(spec.payment.creditDebitFlag),
6956
7192
  esc(spec.payment.method),
6957
7193
  esc(spec.payment.paymentFormatCode ?? ""),
@@ -7108,7 +7344,7 @@ function emitRemittance(remittance, body, seg, esc) {
7108
7344
  body.push(
7109
7345
  seg([
7110
7346
  "ADX",
7111
- esc(adjustment.amount.toString()),
7347
+ escDec5(adjustment.amount, esc),
7112
7348
  esc(adjustment.reasonCode),
7113
7349
  esc(adjustment.referenceQualifier ?? ""),
7114
7350
  esc(adjustment.referenceId ?? "")
@@ -7138,8 +7374,8 @@ function emitOpenItem(item, seg, esc) {
7138
7374
  esc(item.qualifier),
7139
7375
  esc(item.referenceId),
7140
7376
  esc(item.paymentActionCode ?? ""),
7141
- esc(item.amountPaid.toString()),
7142
- item.amountDue === void 0 ? "" : esc(item.amountDue.toString())
7377
+ escDec5(item.amountPaid, esc),
7378
+ item.amountDue === void 0 ? "" : escDec5(item.amountDue, esc)
7143
7379
  ]);
7144
7380
  }
7145
7381
  function emitRef5(ref, seg, esc) {
@@ -7370,7 +7606,8 @@ async function* get834Enrollments(delimiters, tx) {
7370
7606
  }
7371
7607
  case "AMT": {
7372
7608
  if (currentCoverage === void 0) break;
7373
- const amount = decodeAmt3(seg, delimiters);
7609
+ const sink = { warnings: current.warnings, position };
7610
+ const amount = decodeAmt3(seg, delimiters, sink);
7374
7611
  if (amount !== void 0) currentCoverage.amounts.push(amount);
7375
7612
  break;
7376
7613
  }
@@ -7496,8 +7733,8 @@ function decodeDtp4(seg, delimiters) {
7496
7733
  value
7497
7734
  });
7498
7735
  }
7499
- function decodeAmt3(seg, delimiters) {
7500
- const amount = elementDecimal(seg, 2, delimiters);
7736
+ function decodeAmt3(seg, delimiters, sink) {
7737
+ const amount = elementDecimal(seg, 2, delimiters, sink);
7501
7738
  if (amount === void 0) return void 0;
7502
7739
  return Object.freeze({
7503
7740
  qualifier: elementValue(seg, 1, delimiters),
@@ -7559,6 +7796,9 @@ function refuseSpec6(message) {
7559
7796
  message
7560
7797
  );
7561
7798
  }
7799
+ function escDec6(value, esc) {
7800
+ return esc(requireCallerDecimal(value, "build834", refuseSpec6).toString());
7801
+ }
7562
7802
  var X220A1_VERSION_RELEASE = "005010X220A1";
7563
7803
  var X12_834_FUNCTIONAL_ID = "BE";
7564
7804
  var X12_AGENCY_CODE6 = "X";
@@ -7579,6 +7819,7 @@ function build834(spec) {
7579
7819
  };
7580
7820
  const esc = makeCallerEscaper(delimiters, "build834", refuseSpec6);
7581
7821
  const seg = (parts) => {
7822
+ requireCallerSegment(parts, "build834", refuseSpec6);
7582
7823
  let end = parts.length;
7583
7824
  while (end > 1 && parts[end - 1] === "") end -= 1;
7584
7825
  return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
@@ -7634,9 +7875,9 @@ function build834(spec) {
7634
7875
  // GS-02
7635
7876
  esc(applicationReceiverCode),
7636
7877
  // GS-03
7637
- groupDate,
7878
+ esc(groupDate),
7638
7879
  // GS-04 - CCYYMMDD
7639
- groupTime,
7880
+ esc(groupTime),
7640
7881
  // GS-05 - HHMM
7641
7882
  esc(envelope.groupControlNumber),
7642
7883
  // GS-06
@@ -7817,7 +8058,7 @@ function emitCoverage(coverage, body, seg, esc) {
7817
8058
  );
7818
8059
  for (const date of coverage.dates ?? []) body.push(emitDate4(date, seg, esc));
7819
8060
  for (const amount of coverage.amounts ?? []) {
7820
- body.push(seg(["AMT", esc(amount.qualifier), esc(amount.amount.toString())]));
8061
+ body.push(seg(["AMT", esc(amount.qualifier), escDec6(amount.amount, esc)]));
7821
8062
  }
7822
8063
  }
7823
8064
  function emitRef6(ref, seg, esc) {
@@ -8225,6 +8466,7 @@ var HL_LEVEL4 = {
8225
8466
  DEPENDENT: "23"
8226
8467
  };
8227
8468
  var DEFAULT_REVIEW_LEVEL = "EV";
8469
+ var REVIEW_LEVEL_CODES = Object.freeze(["EV", "SS"]);
8228
8470
  function build278Request(spec) {
8229
8471
  return buildServicesReview("005010X217", "request", spec);
8230
8472
  }
@@ -8246,6 +8488,7 @@ function buildServicesReview(version, direction, spec) {
8246
8488
  };
8247
8489
  const esc = makeCallerEscaper(delimiters, "build278", refuseSpec7);
8248
8490
  const seg = (parts) => {
8491
+ requireCallerSegment(parts, "build278", refuseSpec7);
8249
8492
  let end = parts.length;
8250
8493
  while (end > 1 && parts[end - 1] === "") end -= 1;
8251
8494
  return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
@@ -8289,8 +8532,8 @@ function buildServicesReview(version, direction, spec) {
8289
8532
  X12_278_FUNCTIONAL_ID,
8290
8533
  esc(applicationSenderCode),
8291
8534
  esc(applicationReceiverCode),
8292
- groupDate,
8293
- groupTime,
8535
+ esc(groupDate),
8536
+ esc(groupTime),
8294
8537
  esc(envelope.groupControlNumber),
8295
8538
  X12_AGENCY_CODE7,
8296
8539
  version
@@ -8362,6 +8605,13 @@ function enforceStructuralSpec7(spec, direction) {
8362
8605
  }
8363
8606
  }
8364
8607
  function enforceReview(review, locator, direction) {
8608
+ const resolvedLevel = review.levelCode ?? DEFAULT_REVIEW_LEVEL;
8609
+ if (!REVIEW_LEVEL_CODES.includes(resolvedLevel)) {
8610
+ throw new ServicesReview278BuildError(
8611
+ AUTH_278_BUILD_ERROR_CODES.X12_278_BUILD_INVALID_SPEC,
8612
+ `build278: review at ${locator} has HL-03 level code ${renderCallerValue(resolvedLevel)}; a review level must be "EV" (patient event) or "SS" (service). A level outside those two emits a well-formed document whose review loop no reader opens, so the review and its HCR-01 certification decision would not decode.`
8613
+ );
8614
+ }
8365
8615
  if (review.requestCategoryCode === "") {
8366
8616
  throw new ServicesReview278BuildError(
8367
8617
  AUTH_278_BUILD_ERROR_CODES.X12_278_BUILD_INVALID_SPEC,
@@ -8419,7 +8669,7 @@ function emitReview(review, parentHlId, direction, body, ctx, counter) {
8419
8669
  const nested = review.reviews ?? [];
8420
8670
  const hasChild = nested.length > 0 ? "1" : "0";
8421
8671
  const levelCode = review.levelCode ?? DEFAULT_REVIEW_LEVEL;
8422
- body.push(ctx.seg(["HL", hlId, parentHlId, levelCode, hasChild]));
8672
+ body.push(ctx.seg(["HL", hlId, parentHlId, ctx.esc(levelCode), hasChild]));
8423
8673
  for (const trace of review.traces ?? []) {
8424
8674
  body.push(
8425
8675
  ctx.seg([
@@ -9066,13 +9316,13 @@ function build999(spec) {
9066
9316
  // GS-02
9067
9317
  esc(envelope.receiverId),
9068
9318
  // GS-03
9069
- groupDate,
9319
+ esc(groupDate),
9070
9320
  // GS-04 - CCYYMMDD
9071
- groupTime,
9321
+ esc(groupTime),
9072
9322
  // GS-05 - HHMM
9073
- envelope.groupControlNumber,
9323
+ esc(envelope.groupControlNumber),
9074
9324
  // GS-06
9075
- groupResponsibleAgency,
9325
+ esc(groupResponsibleAgency),
9076
9326
  // GS-07
9077
9327
  X231A1_VERSION_RELEASE
9078
9328
  // GS-08 - the 999 TR3
@@ -9082,7 +9332,7 @@ function build999(spec) {
9082
9332
  );
9083
9333
  const stControlNumber = envelope.transactionSetControlNumber;
9084
9334
  const st = joinSeg(
9085
- ["ST", "999", stControlNumber, X231A1_VERSION_RELEASE],
9335
+ ["ST", "999", esc(stControlNumber), X231A1_VERSION_RELEASE],
9086
9336
  elementSeparator,
9087
9337
  segmentTerminator
9088
9338
  );
@@ -9115,8 +9365,16 @@ function build999(spec) {
9115
9365
  const ak9 = buildAk9(functionalGroup, esc, elementSeparator, segmentTerminator);
9116
9366
  const bodySegments = [st, ak1, ...responseSegments, ak9];
9117
9367
  const seCount = bodySegments.length + 1;
9118
- const se = joinSeg(["SE", String(seCount), stControlNumber], elementSeparator, segmentTerminator);
9119
- const ge = joinSeg(["GE", "1", envelope.groupControlNumber], elementSeparator, segmentTerminator);
9368
+ const se = joinSeg(
9369
+ ["SE", String(seCount), esc(stControlNumber)],
9370
+ elementSeparator,
9371
+ segmentTerminator
9372
+ );
9373
+ const ge = joinSeg(
9374
+ ["GE", "1", esc(envelope.groupControlNumber)],
9375
+ elementSeparator,
9376
+ segmentTerminator
9377
+ );
9120
9378
  const iea = joinSeg(["IEA", "1", interchangeControlNumber], elementSeparator, segmentTerminator);
9121
9379
  const raw = isa + gs + bodySegments.join("") + se + ge + iea;
9122
9380
  return parseX12(raw);
@@ -9238,7 +9496,7 @@ function buildIk4(elemError, esc, componentSeparator, elementSeparator, segmentT
9238
9496
  return joinSeg(parts, elementSeparator, segmentTerminator);
9239
9497
  }
9240
9498
  function buildIk5(response, esc, elementSeparator, segmentTerminator) {
9241
- const parts = ["IK5", response.disposition];
9499
+ const parts = ["IK5", esc(response.disposition)];
9242
9500
  const codes = response.syntaxErrorCodes ?? [];
9243
9501
  if (codes.length > 5) {
9244
9502
  throw new AckBuildError(
@@ -9252,7 +9510,7 @@ function buildIk5(response, esc, elementSeparator, segmentTerminator) {
9252
9510
  function buildAk9(group, esc, elementSeparator, segmentTerminator) {
9253
9511
  const parts = [
9254
9512
  "AK9",
9255
- group.disposition,
9513
+ esc(group.disposition),
9256
9514
  String(group.numberOfTransactionSets),
9257
9515
  String(group.numberOfReceivedTransactionSets),
9258
9516
  String(group.numberOfAcceptedTransactionSets)
@@ -9268,6 +9526,7 @@ function buildAk9(group, esc, elementSeparator, segmentTerminator) {
9268
9526
  return joinSeg(parts, elementSeparator, segmentTerminator);
9269
9527
  }
9270
9528
  function joinSeg(parts, elementSeparator, segmentTerminator) {
9529
+ requireCallerSegment(parts, "build999", refuseSpec8);
9271
9530
  return parts.join(elementSeparator) + segmentTerminator;
9272
9531
  }
9273
9532
  function pad8(value, width) {
@@ -9622,6 +9881,7 @@ function buildTransaction(tx, esc, elementSeparator, segmentTerminator) {
9622
9881
  return st + bodySegments + se;
9623
9882
  }
9624
9883
  function joinSeg2(parts, elementSeparator, segmentTerminator) {
9884
+ requireCallerSegment(parts, "buildInterchange", refuseSpec9);
9625
9885
  return parts.join(elementSeparator) + segmentTerminator;
9626
9886
  }
9627
9887
  function pad9(value, width) {
@@ -9930,8 +10190,8 @@ var profiles = Object.freeze({
9930
10190
  });
9931
10191
 
9932
10192
  // src/index.ts
9933
- var VERSION = "0.0.9";
10193
+ var VERSION = "0.0.11";
9934
10194
 
9935
- 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, 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, 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, pre005010, profiles, remitBalanceMismatch, renderCallerValue, resolveHiQualifier, segmentCountMismatch, serializeX12, setDefaultProfile, trailingGarbage, transactionCountMismatch, unescapeRelease, unexpectedSegment, unknown837Variant, unknownCarc, unknownClaimStatus, unknownClaimStatusCategory, unknownHiQualifier, unknownMaintenanceType, unknownRarc };
10195
+ 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, 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, pre005010, profiles, readElementDecimal, remitBalanceMismatch, renderCallerValue, resolveHiQualifier, segmentCountMismatch, serializeX12, serviceLineDropped, serviceLineNotDecoded, serviceSegmentWithoutLx, setDefaultProfile, trailingGarbage, transactionCountMismatch, unescapeRelease, unexpectedSegment, unknown837Variant, unknownCarc, unknownClaimStatus, unknownClaimStatusCategory, unknownHiQualifier, unknownMaintenanceType, unknownRarc, unparseableDecimal };
9936
10196
  //# sourceMappingURL=index.mjs.map
9937
10197
  //# sourceMappingURL=index.mjs.map