@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.cjs CHANGED
@@ -140,7 +140,12 @@ var WARNING_CODES = {
140
140
  X12_837_UNKNOWN_VARIANT: "X12_837_UNKNOWN_VARIANT",
141
141
  X12_UNKNOWN_CLAIM_STATUS_CATEGORY: "X12_UNKNOWN_CLAIM_STATUS_CATEGORY",
142
142
  X12_UNKNOWN_CLAIM_STATUS: "X12_UNKNOWN_CLAIM_STATUS",
143
- X12_834_UNKNOWN_MAINTENANCE_TYPE: "X12_834_UNKNOWN_MAINTENANCE_TYPE"
143
+ X12_834_UNKNOWN_MAINTENANCE_TYPE: "X12_834_UNKNOWN_MAINTENANCE_TYPE",
144
+ X12_UNPARSEABLE_DECIMAL: "X12_UNPARSEABLE_DECIMAL",
145
+ X12_837_SERVICE_LINE_NOT_DECODED: "X12_837_SERVICE_LINE_NOT_DECODED",
146
+ X12_837_SERVICE_LINE_DROPPED: "X12_837_SERVICE_LINE_DROPPED",
147
+ X12_837_SERVICE_SEGMENT_WITHOUT_LX: "X12_837_SERVICE_SEGMENT_WITHOUT_LX",
148
+ X12_837_ENTITY_SEGMENT_DISCARDED_AFTER_LX: "X12_837_ENTITY_SEGMENT_DISCARDED_AFTER_LX"
144
149
  };
145
150
  var CONTROL_NUMBER_PAIRS = {
146
151
  /** ISA-13 against IEA-02. */
@@ -213,7 +218,12 @@ var WARNING_MESSAGES = {
213
218
  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.`,
214
219
  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.",
215
220
  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.",
216
- 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."
221
+ 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.",
222
+ 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.",
223
+ 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.",
224
+ 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.",
225
+ 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.",
226
+ 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."
217
227
  };
218
228
  var ALL_WARNING_MESSAGES = new Set(
219
229
  Object.values(WARNING_MESSAGES)
@@ -374,6 +384,34 @@ function unknown837Variant(position) {
374
384
  position
375
385
  };
376
386
  }
387
+ function serviceLineNotDecoded(position) {
388
+ return {
389
+ code: WARNING_CODES.X12_837_SERVICE_LINE_NOT_DECODED,
390
+ message: WARNING_MESSAGES.X12_837_SERVICE_LINE_NOT_DECODED,
391
+ position
392
+ };
393
+ }
394
+ function serviceLineDropped(position) {
395
+ return {
396
+ code: WARNING_CODES.X12_837_SERVICE_LINE_DROPPED,
397
+ message: WARNING_MESSAGES.X12_837_SERVICE_LINE_DROPPED,
398
+ position
399
+ };
400
+ }
401
+ function serviceSegmentWithoutLx(position) {
402
+ return {
403
+ code: WARNING_CODES.X12_837_SERVICE_SEGMENT_WITHOUT_LX,
404
+ message: WARNING_MESSAGES.X12_837_SERVICE_SEGMENT_WITHOUT_LX,
405
+ position
406
+ };
407
+ }
408
+ function entitySegmentDiscardedAfterLx(position) {
409
+ return {
410
+ code: WARNING_CODES.X12_837_ENTITY_SEGMENT_DISCARDED_AFTER_LX,
411
+ message: WARNING_MESSAGES.X12_837_ENTITY_SEGMENT_DISCARDED_AFTER_LX,
412
+ position
413
+ };
414
+ }
377
415
  function unknownClaimStatusCategory(position) {
378
416
  return {
379
417
  code: WARNING_CODES.X12_UNKNOWN_CLAIM_STATUS_CATEGORY,
@@ -395,6 +433,13 @@ function unknownMaintenanceType(position) {
395
433
  position
396
434
  };
397
435
  }
436
+ function unparseableDecimal(position) {
437
+ return {
438
+ code: WARNING_CODES.X12_UNPARSEABLE_DECIMAL,
439
+ message: WARNING_MESSAGES.X12_UNPARSEABLE_DECIMAL,
440
+ position
441
+ };
442
+ }
398
443
 
399
444
  // src/parser/release.ts
400
445
  var RELEASE_CHAR = "?";
@@ -908,13 +953,26 @@ function componentOptional(seg, n, p, delimiters) {
908
953
  const v = getSegmentValue(seg, `${String(n).padStart(2, "0")}-${String(p)}`, delimiters);
909
954
  return v === void 0 || v === "" ? void 0 : v;
910
955
  }
911
- function elementDecimal(seg, n, delimiters) {
956
+ function readElementDecimal(seg, n, delimiters) {
912
957
  const raw = elementOptional(seg, n, delimiters);
913
- if (raw === void 0) return void 0;
914
- return X12Decimal.fromString(raw);
958
+ if (raw === void 0) return { value: void 0, status: "absent" };
959
+ const value = X12Decimal.fromString(raw);
960
+ if (value === void 0) return { value: void 0, status: "unparseable" };
961
+ return { value, status: "decoded" };
915
962
  }
916
- function elementDecimalOrZero(seg, n, delimiters) {
917
- return elementDecimal(seg, n, delimiters) ?? X12Decimal.ZERO;
963
+ function elementDecimal(seg, n, delimiters, sink) {
964
+ const read = readElementDecimal(seg, n, delimiters);
965
+ if (read.status === "unparseable" && sink !== void 0) {
966
+ sink.warnings.push(unparseableDecimal({ ...sink.position, elementIndex: n }));
967
+ }
968
+ return read.value;
969
+ }
970
+ function elementDecimalOrZero(seg, n, delimiters, sink) {
971
+ const read = readElementDecimal(seg, n, delimiters);
972
+ if (read.status === "unparseable" && sink !== void 0) {
973
+ sink.warnings.push(unparseableDecimal({ ...sink.position, elementIndex: n }));
974
+ }
975
+ return read.value ?? X12Decimal.ZERO;
918
976
  }
919
977
  function collectElementValues(seg, start, end, delimiters) {
920
978
  const out = [];
@@ -1420,6 +1478,7 @@ function defineLoopSpec(input) {
1420
1478
  // src/code-lists/meta.ts
1421
1479
  function makeLookup(snapshot) {
1422
1480
  return (code) => {
1481
+ if (!Object.hasOwn(snapshot.codes, code)) return void 0;
1423
1482
  const description = snapshot.codes[code];
1424
1483
  if (description === void 0) return void 0;
1425
1484
  return Object.freeze({ code, description });
@@ -1668,7 +1727,7 @@ var CLAIM_ADJUSTMENT_GROUP_CODES = {
1668
1727
  PI: "PI"
1669
1728
  };
1670
1729
  function isClaimAdjustmentGroupCode(value) {
1671
- return value in CLAIM_ADJUSTMENT_GROUP_CODES;
1730
+ return Object.hasOwn(CLAIM_ADJUSTMENT_GROUP_CODES, value);
1672
1731
  }
1673
1732
 
1674
1733
  // src/code-lists/rarc.ts
@@ -1808,6 +1867,7 @@ var HI_QUALIFIERS = {
1808
1867
  }
1809
1868
  };
1810
1869
  function resolveHiQualifier(qualifier) {
1870
+ if (!Object.hasOwn(HI_QUALIFIERS, qualifier)) return void 0;
1811
1871
  return HI_QUALIFIERS[qualifier];
1812
1872
  }
1813
1873
  function isDiagnosisQualifier(qualifier) {
@@ -1917,9 +1977,10 @@ function get835(delimiters, tx) {
1917
1977
  const seg = body[i];
1918
1978
  if (seg === void 0) continue;
1919
1979
  const position = { segmentIndex: i + 1, transactionIndex: 0 };
1980
+ const sink = { warnings, position };
1920
1981
  switch (seg.id) {
1921
1982
  case "BPR": {
1922
- payment = decodeBpr(seg, delimiters);
1983
+ payment = decodeBpr(seg, delimiters, sink);
1923
1984
  bprSegmentIndex = position.segmentIndex;
1924
1985
  break;
1925
1986
  }
@@ -1994,7 +2055,7 @@ function get835(delimiters, tx) {
1994
2055
  case "CLP": {
1995
2056
  flushClaim();
1996
2057
  lastParty = void 0;
1997
- currentClaim = openClaim(seg, delimiters, position.segmentIndex);
2058
+ currentClaim = openClaim(seg, delimiters, position.segmentIndex, sink);
1998
2059
  break;
1999
2060
  }
2000
2061
  case "CAS": {
@@ -2046,7 +2107,7 @@ function get835(delimiters, tx) {
2046
2107
  break;
2047
2108
  }
2048
2109
  case "AMT": {
2049
- const amount = decodeAmt(seg, delimiters);
2110
+ const amount = decodeAmt(seg, delimiters, sink);
2050
2111
  if (amount === void 0) break;
2051
2112
  if (currentServiceLine !== void 0) currentServiceLine.amounts.push(amount);
2052
2113
  else if (currentClaim !== void 0) currentClaim.amounts.push(amount);
@@ -2065,12 +2126,12 @@ function get835(delimiters, tx) {
2065
2126
  }
2066
2127
  case "SVC": {
2067
2128
  flushServiceLine();
2068
- currentServiceLine = openServiceLine(seg, delimiters);
2129
+ currentServiceLine = openServiceLine(seg, delimiters, sink);
2069
2130
  break;
2070
2131
  }
2071
2132
  case "PLB": {
2072
2133
  flushClaim();
2073
- for (const p of decodePlb(seg, delimiters)) providerAdjustments.push(p);
2134
+ for (const p of decodePlb(seg, delimiters, sink)) providerAdjustments.push(p);
2074
2135
  break;
2075
2136
  }
2076
2137
  }
@@ -2101,10 +2162,10 @@ function get835(delimiters, tx) {
2101
2162
  warnings: Object.freeze(warnings.slice())
2102
2163
  });
2103
2164
  }
2104
- function decodeBpr(seg, delimiters) {
2165
+ function decodeBpr(seg, delimiters, sink) {
2105
2166
  return Object.freeze({
2106
2167
  transactionHandlingCode: elementValue(seg, 1, delimiters),
2107
- totalActualPayment: elementDecimalOrZero(seg, 2, delimiters),
2168
+ totalActualPayment: elementDecimalOrZero(seg, 2, delimiters, sink),
2108
2169
  creditDebitFlag: elementValue(seg, 3, delimiters),
2109
2170
  method: elementValue(seg, 4, delimiters),
2110
2171
  paymentFormatCode: elementOptional(seg, 5, delimiters),
@@ -2163,8 +2224,8 @@ function decodePer(seg, delimiters) {
2163
2224
  communications: Object.freeze(comms)
2164
2225
  });
2165
2226
  }
2166
- function decodeAmt(seg, delimiters) {
2167
- const amount = elementDecimal(seg, 2, delimiters);
2227
+ function decodeAmt(seg, delimiters, sink) {
2228
+ const amount = elementDecimal(seg, 2, delimiters, sink);
2168
2229
  if (amount === void 0) return void 0;
2169
2230
  return Object.freeze({
2170
2231
  qualifier: elementValue(seg, 1, delimiters),
@@ -2200,13 +2261,14 @@ function collectMoaRemarks(seg, delimiters) {
2200
2261
  return out;
2201
2262
  }
2202
2263
  function decodeCasAdjustments(seg, delimiters, warnings, position) {
2264
+ const sink = { warnings, position };
2203
2265
  const groupCode = elementValue(seg, 1, delimiters);
2204
2266
  const out = [];
2205
2267
  for (let triple = 0; triple < 6; triple += 1) {
2206
2268
  const base = 2 + triple * 3;
2207
2269
  const reasonCode = elementOptional(seg, base, delimiters);
2208
- const amount = elementDecimal(seg, base + 1, delimiters);
2209
- const quantity = elementDecimal(seg, base + 2, delimiters);
2270
+ const amount = elementDecimal(seg, base + 1, delimiters, sink);
2271
+ const quantity = elementDecimal(seg, base + 2, delimiters, sink);
2210
2272
  if (reasonCode === void 0 && amount === void 0) continue;
2211
2273
  const code = reasonCode ?? "";
2212
2274
  const entry = code === "" ? void 0 : lookupCarc(code);
@@ -2250,7 +2312,7 @@ function decodeNm1(seg, delimiters) {
2250
2312
  })
2251
2313
  };
2252
2314
  }
2253
- function openClaim(seg, delimiters, clpSegmentIndex) {
2315
+ function openClaim(seg, delimiters, clpSegmentIndex, sink) {
2254
2316
  const claimStatusCode = elementValue(seg, 2, delimiters);
2255
2317
  const claimStatusDescription = lookupClpStatus(claimStatusCode)?.description;
2256
2318
  const facilityTypeCode = componentOptional(seg, 8, 1, delimiters) ?? elementOptional(seg, 8, delimiters);
@@ -2260,9 +2322,9 @@ function openClaim(seg, delimiters, clpSegmentIndex) {
2260
2322
  patientControlNumber: elementValue(seg, 1, delimiters),
2261
2323
  claimStatusCode,
2262
2324
  claimStatusDescription,
2263
- totalChargeAmount: elementDecimalOrZero(seg, 3, delimiters),
2264
- totalPaymentAmount: elementDecimalOrZero(seg, 4, delimiters),
2265
- patientResponsibilityAmount: elementDecimalOrZero(seg, 5, delimiters),
2325
+ totalChargeAmount: elementDecimalOrZero(seg, 3, delimiters, sink),
2326
+ totalPaymentAmount: elementDecimalOrZero(seg, 4, delimiters, sink),
2327
+ patientResponsibilityAmount: elementDecimalOrZero(seg, 5, delimiters, sink),
2266
2328
  claimFilingIndicatorCode: elementOptional(seg, 6, delimiters),
2267
2329
  payerClaimControlNumber: elementOptional(seg, 7, delimiters),
2268
2330
  facilityTypeCode,
@@ -2281,7 +2343,7 @@ function openClaim(seg, delimiters, clpSegmentIndex) {
2281
2343
  serviceLines: []
2282
2344
  };
2283
2345
  }
2284
- function openServiceLine(seg, delimiters) {
2346
+ function openServiceLine(seg, delimiters, sink) {
2285
2347
  const productServiceIdQualifier = componentOptional(seg, 1, 1, delimiters) ?? "";
2286
2348
  const productServiceId = componentOptional(seg, 1, 2, delimiters) ?? "";
2287
2349
  const modifiers = [];
@@ -2289,18 +2351,20 @@ function openServiceLine(seg, delimiters) {
2289
2351
  const m = componentOptional(seg, 1, comp, delimiters);
2290
2352
  if (m !== void 0) modifiers.push(m);
2291
2353
  }
2292
- const revenueCode = elementOptional(seg, 5, delimiters);
2293
- const paidUnitsOfService = elementDecimal(seg, 7, delimiters);
2354
+ const revenueCode = elementOptional(seg, 4, delimiters);
2355
+ const paidUnitsOfService = elementDecimal(seg, 5, delimiters, sink);
2356
+ const originalUnitsOfService = elementDecimal(seg, 7, delimiters, sink);
2294
2357
  const originalServiceIdQualifier = componentOptional(seg, 6, 1, delimiters);
2295
2358
  const originalServiceId = componentOptional(seg, 6, 2, delimiters);
2296
2359
  return {
2297
2360
  productServiceIdQualifier,
2298
2361
  productServiceId,
2299
2362
  modifiers,
2300
- chargeAmount: elementDecimalOrZero(seg, 2, delimiters),
2301
- paymentAmount: elementDecimalOrZero(seg, 3, delimiters),
2363
+ chargeAmount: elementDecimalOrZero(seg, 2, delimiters, sink),
2364
+ paymentAmount: elementDecimalOrZero(seg, 3, delimiters, sink),
2302
2365
  revenueCode,
2303
2366
  paidUnitsOfService,
2367
+ originalUnitsOfService,
2304
2368
  originalServiceId,
2305
2369
  originalServiceIdQualifier,
2306
2370
  serviceDateStart: void 0,
@@ -2326,13 +2390,13 @@ function attachServiceLineDtm(line, seg, delimiters) {
2326
2390
  if (qualifier === "472" || qualifier === "150") line.serviceDateStart = date;
2327
2391
  if (qualifier === "472" || qualifier === "151") line.serviceDateEnd = date;
2328
2392
  }
2329
- function decodePlb(seg, delimiters) {
2393
+ function decodePlb(seg, delimiters, sink) {
2330
2394
  const providerId = elementValue(seg, 1, delimiters);
2331
2395
  const fiscalPeriodDate = elementValue(seg, 2, delimiters);
2332
2396
  const out = [];
2333
2397
  for (let pair = 0; pair < 6; pair += 1) {
2334
2398
  const composite = 3 + pair * 2;
2335
- const amount = elementDecimal(seg, composite + 1, delimiters);
2399
+ const amount = elementDecimal(seg, composite + 1, delimiters, sink);
2336
2400
  const reasonCode = componentOptional(seg, composite, 1, delimiters);
2337
2401
  const subCode = componentOptional(seg, composite, 2, delimiters);
2338
2402
  if (amount === void 0 && reasonCode === void 0) continue;
@@ -2396,6 +2460,7 @@ function freezeServiceLine(acc) {
2396
2460
  paymentAmount: acc.paymentAmount,
2397
2461
  revenueCode: acc.revenueCode,
2398
2462
  paidUnitsOfService: acc.paidUnitsOfService,
2463
+ originalUnitsOfService: acc.originalUnitsOfService,
2399
2464
  originalServiceId: acc.originalServiceId,
2400
2465
  originalServiceIdQualifier: acc.originalServiceIdQualifier,
2401
2466
  serviceDateStart: acc.serviceDateStart,
@@ -2481,7 +2546,7 @@ function renderCallerJson(value) {
2481
2546
  var NONE = Object.freeze([]);
2482
2547
  function describeShape(value) {
2483
2548
  if (typeof value !== "object") {
2484
- return `a ${typeof value} (${renderCallerValue(value)})`;
2549
+ return `a ${typeof value}`;
2485
2550
  }
2486
2551
  let length;
2487
2552
  try {
@@ -2511,6 +2576,50 @@ function isRealArray(value) {
2511
2576
  return Array.isArray(value);
2512
2577
  }
2513
2578
 
2579
+ // src/builder/caller-decimal.ts
2580
+ function describeCallerDecimal(value) {
2581
+ if (value === null) return "null";
2582
+ if (value === void 0) return "undefined";
2583
+ const type = typeof value;
2584
+ if (type === "object") return Array.isArray(value) ? "an array" : "an object";
2585
+ if (type === "function") return "a function";
2586
+ return `a ${type}`;
2587
+ }
2588
+ function requireCallerDecimal(value, at, refuse) {
2589
+ if (value instanceof X12Decimal) return value;
2590
+ refuse(
2591
+ `${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.`
2592
+ );
2593
+ }
2594
+
2595
+ // src/builder/caller-segment.ts
2596
+ var SEGMENT_ID_RE2 = /^[A-Z][A-Z0-9]{1,2}$/u;
2597
+ function describeSegmentValue(value) {
2598
+ if (value === null) return "null";
2599
+ if (value === void 0) return "undefined";
2600
+ const type = typeof value;
2601
+ if (type === "object") return Array.isArray(value) ? "an array" : "an object";
2602
+ if (type === "function") return "a function";
2603
+ return `a ${type}`;
2604
+ }
2605
+ function locateSlot(parts, index) {
2606
+ const id = parts[0];
2607
+ const position = String(index).padStart(2, "0");
2608
+ if (typeof id !== "string" || !SEGMENT_ID_RE2.test(id)) return `element ${String(index)}`;
2609
+ return `"${id}"-${position}`;
2610
+ }
2611
+ function requireCallerSegment(parts, at, refuse) {
2612
+ let index = 0;
2613
+ for (const part of parts) {
2614
+ if (typeof part !== "string") {
2615
+ refuse(
2616
+ `${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.`
2617
+ );
2618
+ }
2619
+ index += 1;
2620
+ }
2621
+ }
2622
+
2514
2623
  // src/builder/caller-string.ts
2515
2624
  function describeCallerValue(value) {
2516
2625
  if (value === null) return "null";
@@ -2518,7 +2627,7 @@ function describeCallerValue(value) {
2518
2627
  const type = typeof value;
2519
2628
  if (type === "object") return Array.isArray(value) ? "an array" : "an object";
2520
2629
  if (type === "function") return "a function";
2521
- return `a ${type} (${renderCallerValue(value)})`;
2630
+ return `a ${type}`;
2522
2631
  }
2523
2632
  function requireCallerString(value, at, refuse) {
2524
2633
  if (typeof value === "string") return value;
@@ -2534,6 +2643,9 @@ function makeCallerEscaper(delimiters, at, refuse) {
2534
2643
  function refuseSpec(message) {
2535
2644
  throw new Remit835BuildError(REMIT_835_BUILD_ERROR_CODES.X12_835_BUILD_INVALID_SPEC, message);
2536
2645
  }
2646
+ function escDec(value, esc) {
2647
+ return esc(requireCallerDecimal(value, "build835", refuseSpec).toString());
2648
+ }
2537
2649
  var X221A1_VERSION_RELEASE = "005010X221A1";
2538
2650
  var X12_835_FUNCTIONAL_ID = "HP";
2539
2651
  var X12_AGENCY_CODE = "X";
@@ -2557,6 +2669,7 @@ function build835(spec) {
2557
2669
  };
2558
2670
  const esc = makeCallerEscaper(delimiters, "build835", refuseSpec);
2559
2671
  const seg = (parts) => {
2672
+ requireCallerSegment(parts, "build835", refuseSpec);
2560
2673
  let end = parts.length;
2561
2674
  while (end > 1 && parts[end - 1] === "") end -= 1;
2562
2675
  return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
@@ -2618,9 +2731,9 @@ function build835(spec) {
2618
2731
  // GS-02
2619
2732
  esc(applicationReceiverCode),
2620
2733
  // GS-03
2621
- groupDate,
2734
+ esc(groupDate),
2622
2735
  // GS-04 - CCYYMMDD
2623
- groupTime,
2736
+ esc(groupTime),
2624
2737
  // GS-05 - HHMM
2625
2738
  esc(envelope.groupControlNumber),
2626
2739
  // GS-06
@@ -2636,7 +2749,7 @@ function build835(spec) {
2636
2749
  seg([
2637
2750
  "BPR",
2638
2751
  esc(spec.payment.transactionHandlingCode),
2639
- esc(spec.payment.totalActualPayment.toString()),
2752
+ escDec(spec.payment.totalActualPayment, esc),
2640
2753
  esc(spec.payment.creditDebitFlag),
2641
2754
  esc(spec.payment.method),
2642
2755
  esc(spec.payment.paymentFormatCode ?? ""),
@@ -2771,6 +2884,7 @@ function materializeServiceLine(spec) {
2771
2884
  paymentAmount: spec.paymentAmount,
2772
2885
  revenueCode: spec.revenueCode,
2773
2886
  paidUnitsOfService: spec.paidUnitsOfService,
2887
+ originalUnitsOfService: spec.originalUnitsOfService,
2774
2888
  originalServiceId: spec.originalServiceId,
2775
2889
  originalServiceIdQualifier: spec.originalServiceIdQualifier,
2776
2890
  serviceDateStart: spec.serviceDateStart,
@@ -2866,9 +2980,9 @@ function emitClaim(claim, body, seg, esc, comp) {
2866
2980
  "CLP",
2867
2981
  esc(claim.patientControlNumber),
2868
2982
  esc(claim.claimStatusCode),
2869
- esc(claim.totalChargeAmount.toString()),
2870
- esc(claim.totalPaymentAmount.toString()),
2871
- esc(claim.patientResponsibilityAmount.toString()),
2983
+ escDec(claim.totalChargeAmount, esc),
2984
+ escDec(claim.totalPaymentAmount, esc),
2985
+ escDec(claim.patientResponsibilityAmount, esc),
2872
2986
  esc(claim.claimFilingIndicatorCode ?? ""),
2873
2987
  esc(claim.payerClaimControlNumber ?? ""),
2874
2988
  comp([claim.facilityTypeCode ?? "", "", claim.claimFrequencyCode ?? ""])
@@ -2890,7 +3004,7 @@ function emitClaim(claim, body, seg, esc, comp) {
2890
3004
  }
2891
3005
  for (const ref of claim.references ?? []) body.push(emitRef(ref, seg, esc));
2892
3006
  for (const amt of claim.amounts ?? []) {
2893
- body.push(seg(["AMT", esc(amt.qualifier), esc(amt.amount.toString())]));
3007
+ body.push(seg(["AMT", esc(amt.qualifier), escDec(amt.amount, esc)]));
2894
3008
  }
2895
3009
  for (const remark of claim.remarks ?? []) {
2896
3010
  body.push(seg(["LQ", esc(remark.system), esc(remark.code)]));
@@ -2910,20 +3024,24 @@ function emitServiceLine(line, body, seg, esc, comp) {
2910
3024
  seg([
2911
3025
  "SVC",
2912
3026
  svc01,
2913
- esc(line.chargeAmount.toString()),
2914
- esc(line.paymentAmount.toString()),
2915
- "",
2916
- // SVC-04 - revenue code is SVC-05 in X221A1; SVC-04 unused
3027
+ escDec(line.chargeAmount, esc),
3028
+ escDec(line.paymentAmount, esc),
3029
+ // SVC-04 is the NUBC revenue code (element 234, Product/Service ID) and
3030
+ // SVC-05 is the Units of Service PAID Count (element 380, Quantity).
3031
+ // SVC-07 is the ORIGINAL (submitted) units, a different quantity from
3032
+ // SVC-05 - so the two never share a field. See the SVC note in
3033
+ // KNOWN-LIMITATIONS.md for the sources.
2917
3034
  esc(line.revenueCode ?? ""),
3035
+ line.paidUnitsOfService === void 0 ? "" : escDec(line.paidUnitsOfService, esc),
2918
3036
  svc06,
2919
- line.paidUnitsOfService === void 0 ? "" : esc(line.paidUnitsOfService.toString())
3037
+ line.originalUnitsOfService === void 0 ? "" : escDec(line.originalUnitsOfService, esc)
2920
3038
  ])
2921
3039
  );
2922
3040
  emitServiceLineDtm(line, body, seg, esc);
2923
3041
  emitCasGroup(line.adjustments, "build835: serviceLine.adjustments", body, seg, esc);
2924
3042
  for (const ref of line.references ?? []) body.push(emitRef(ref, seg, esc));
2925
3043
  for (const amt of line.amounts ?? []) {
2926
- body.push(seg(["AMT", esc(amt.qualifier), esc(amt.amount.toString())]));
3044
+ body.push(seg(["AMT", esc(amt.qualifier), escDec(amt.amount, esc)]));
2927
3045
  }
2928
3046
  for (const remark of line.remarks ?? []) {
2929
3047
  body.push(seg(["LQ", esc(remark.system), esc(remark.code)]));
@@ -2955,8 +3073,8 @@ function emitCasGroup(raw, at, body, seg, esc) {
2955
3073
  if (adj === void 0 || adj.groupCode !== groupCode) break;
2956
3074
  parts.push(
2957
3075
  esc(adj.reasonCode),
2958
- esc(adj.amount.toString()),
2959
- adj.quantity === void 0 ? "" : esc(adj.quantity.toString())
3076
+ escDec(adj.amount, esc),
3077
+ adj.quantity === void 0 ? "" : escDec(adj.quantity, esc)
2960
3078
  );
2961
3079
  triples += 1;
2962
3080
  i += 1;
@@ -3014,7 +3132,7 @@ function emitProviderAdjustments(raw, at, body, seg, esc, comp) {
3014
3132
  if (adj === void 0 || adj.providerId !== providerId || adj.fiscalPeriodDate !== fiscalPeriodDate) {
3015
3133
  break;
3016
3134
  }
3017
- parts.push(comp([adj.reasonCode, adj.subCode ?? ""]), esc(adj.amount.toString()));
3135
+ parts.push(comp([adj.reasonCode, adj.subCode ?? ""]), escDec(adj.amount, esc));
3018
3136
  pairs += 1;
3019
3137
  i += 1;
3020
3138
  }
@@ -3112,13 +3230,22 @@ var REMIT_835_LOOP_1000B = defineLoopSpec({
3112
3230
  ]
3113
3231
  });
3114
3232
 
3233
+ // src/parser/lookup.ts
3234
+ function wireLookup(entries) {
3235
+ const table = /* @__PURE__ */ Object.create(null);
3236
+ for (const [key, value] of Object.entries(entries)) {
3237
+ table[key] = value;
3238
+ }
3239
+ return Object.freeze(table);
3240
+ }
3241
+
3115
3242
  // src/transactions/claim/get-837.ts
3116
- var VARIANT_BY_ICR = Object.freeze({
3243
+ var VARIANT_BY_ICR = wireLookup({
3117
3244
  "005010X222A2": "P",
3118
3245
  "005010X223A3": "I",
3119
3246
  "005010X224A2": "D"
3120
3247
  });
3121
- var VARIANT_BY_SV_SEGMENT = Object.freeze({
3248
+ var VARIANT_BY_SV_SEGMENT = wireLookup({
3122
3249
  SV1: "P",
3123
3250
  SV2: "I",
3124
3251
  SV3: "D"
@@ -3139,7 +3266,7 @@ var NM1_QUALIFIERS = Object.freeze({
3139
3266
  PAYER: "PR",
3140
3267
  PATIENT: "QC"
3141
3268
  });
3142
- var EXPECTED_PARENT_LEVEL = Object.freeze({
3269
+ var EXPECTED_PARENT_LEVEL = wireLookup({
3143
3270
  [HL_LEVEL_CODES.INFORMATION_SOURCE]: void 0,
3144
3271
  [HL_LEVEL_CODES.SUBSCRIBER]: HL_LEVEL_CODES.INFORMATION_SOURCE,
3145
3272
  [HL_LEVEL_CODES.DEPENDENT]: HL_LEVEL_CODES.SUBSCRIBER
@@ -3161,7 +3288,7 @@ function get837Claims(delimiters, tx, opts) {
3161
3288
  }
3162
3289
  const variant = explicitType ?? variantFromIcr ?? variantFromSegment ?? "unknown";
3163
3290
  if (variant === "unknown") {
3164
- warnings.push(unknown837Variant({ segmentIndex: 1, transactionIndex: 0 }));
3291
+ warnings.push(unknown837Variant({ segmentIndex: 0, transactionIndex: 0 }));
3165
3292
  }
3166
3293
  const hierarchies = [];
3167
3294
  const hlIndex = /* @__PURE__ */ new Map();
@@ -3184,7 +3311,9 @@ function get837Claims(delimiters, tx, opts) {
3184
3311
  let currentOtherSubscriber;
3185
3312
  let currentAdjudication;
3186
3313
  let context = { kind: "header" };
3314
+ let droppedLineReported = false;
3187
3315
  let activeEntity;
3316
+ let entityLoopClosedByStrayLx = false;
3188
3317
  const flushAdjudication = () => {
3189
3318
  if (currentAdjudication !== void 0 && currentServiceLine !== void 0) {
3190
3319
  currentServiceLine.adjudications.push(freezeAdjudication(currentAdjudication));
@@ -3194,9 +3323,21 @@ function get837Claims(delimiters, tx, opts) {
3194
3323
  const flushServiceLine = () => {
3195
3324
  flushAdjudication();
3196
3325
  if (currentServiceLine !== void 0 && currentClaim !== void 0) {
3326
+ if (!currentServiceLine.serviceSegmentDecoded) {
3327
+ warnings.push(serviceLineNotDecoded(currentServiceLine.position));
3328
+ }
3197
3329
  currentClaim.serviceLines.push(freezeServiceLine2(currentServiceLine));
3198
3330
  }
3199
3331
  currentServiceLine = void 0;
3332
+ droppedLineReported = false;
3333
+ };
3334
+ const reportOrphanServiceSegment = (position) => {
3335
+ if (droppedLineReported) return;
3336
+ warnings.push(serviceSegmentWithoutLx(position));
3337
+ };
3338
+ const reportDiscardedEntitySegment = (position) => {
3339
+ if (!entityLoopClosedByStrayLx) return;
3340
+ warnings.push(entitySegmentDiscardedAfterLx(position));
3200
3341
  };
3201
3342
  const flushOtherSubscriber = () => {
3202
3343
  if (currentOtherSubscriber !== void 0 && currentClaim !== void 0) {
@@ -3267,6 +3408,7 @@ function get837Claims(delimiters, tx, opts) {
3267
3408
  const seg = body[i];
3268
3409
  if (seg === void 0) continue;
3269
3410
  const position = { segmentIndex: i + 1, transactionIndex: 0 };
3411
+ const sink = { warnings, position };
3270
3412
  switch (seg.id) {
3271
3413
  case "HL": {
3272
3414
  flushClaim();
@@ -3299,6 +3441,7 @@ function get837Claims(delimiters, tx, opts) {
3299
3441
  context = { kind: "header" };
3300
3442
  }
3301
3443
  activeEntity = void 0;
3444
+ entityLoopClosedByStrayLx = false;
3302
3445
  break;
3303
3446
  }
3304
3447
  case "SBR": {
@@ -3315,6 +3458,7 @@ function get837Claims(delimiters, tx, opts) {
3315
3458
  otherPayer: void 0
3316
3459
  };
3317
3460
  activeEntity = { kind: "otherSubscriber" };
3461
+ entityLoopClosedByStrayLx = false;
3318
3462
  }
3319
3463
  break;
3320
3464
  }
@@ -3330,6 +3474,7 @@ function get837Claims(delimiters, tx, opts) {
3330
3474
  case "NM1": {
3331
3475
  const qualifier = elementValue(seg, 1, delimiters);
3332
3476
  const entity = decodeNm12(seg, delimiters);
3477
+ entityLoopClosedByStrayLx = false;
3333
3478
  if (qualifier === NM1_QUALIFIERS.SUBMITTER) {
3334
3479
  submitter = entity;
3335
3480
  activeEntity = { kind: "submitter" };
@@ -3374,16 +3519,19 @@ function get837Claims(delimiters, tx, opts) {
3374
3519
  case "N3": {
3375
3520
  const lines = collectElementValues(seg, 1, 2, delimiters);
3376
3521
  attachAddressLines(lines, activeEntity, entityMutators);
3522
+ reportDiscardedEntitySegment(position);
3377
3523
  break;
3378
3524
  }
3379
3525
  case "N4": {
3380
3526
  const partial = decodeN42(seg, delimiters);
3381
3527
  attachAddressFields(partial, activeEntity, entityMutators);
3528
+ reportDiscardedEntitySegment(position);
3382
3529
  break;
3383
3530
  }
3384
3531
  case "PER": {
3385
3532
  const contact = decodePer2(seg, delimiters);
3386
3533
  attachContact(contact, activeEntity, entityMutators);
3534
+ reportDiscardedEntitySegment(position);
3387
3535
  break;
3388
3536
  }
3389
3537
  case "REF": {
@@ -3395,6 +3543,7 @@ function get837Claims(delimiters, tx, opts) {
3395
3543
  currentClaim.references.push(ref);
3396
3544
  } else {
3397
3545
  attachReference(ref, activeEntity, entityMutators);
3546
+ reportDiscardedEntitySegment(position);
3398
3547
  }
3399
3548
  break;
3400
3549
  }
@@ -3414,17 +3563,23 @@ function get837Claims(delimiters, tx, opts) {
3414
3563
  warnings.push(missingRequiredLoop(position, REQUIRED_LOOPS.PAYER_NAME_2010BB));
3415
3564
  }
3416
3565
  }
3417
- currentClaim = openClaim2(seg, delimiters, {
3418
- variant,
3419
- hierarchy: currentPatientHl ?? currentSubscriberHl,
3420
- billingProvider,
3421
- payToAddress,
3422
- payToPlan,
3423
- subscriber: currentSubscriberMember,
3424
- payer: currentPayer,
3425
- patient: currentPatientMember
3426
- });
3566
+ currentClaim = openClaim2(
3567
+ seg,
3568
+ delimiters,
3569
+ {
3570
+ variant,
3571
+ hierarchy: currentPatientHl ?? currentSubscriberHl,
3572
+ billingProvider,
3573
+ payToAddress,
3574
+ payToPlan,
3575
+ subscriber: currentSubscriberMember,
3576
+ payer: currentPayer,
3577
+ patient: currentPatientMember
3578
+ },
3579
+ sink
3580
+ );
3427
3581
  activeEntity = void 0;
3582
+ entityLoopClosedByStrayLx = false;
3428
3583
  context = { kind: "loop2300" };
3429
3584
  break;
3430
3585
  }
@@ -3462,7 +3617,7 @@ function get837Claims(delimiters, tx, opts) {
3462
3617
  break;
3463
3618
  }
3464
3619
  case "AMT": {
3465
- const amount = decodeAmt2(seg, delimiters);
3620
+ const amount = decodeAmt2(seg, delimiters, sink);
3466
3621
  if (amount === void 0) break;
3467
3622
  if (currentAdjudication !== void 0) break;
3468
3623
  if (currentServiceLine !== void 0) currentServiceLine.amounts.push(amount);
@@ -3471,22 +3626,55 @@ function get837Claims(delimiters, tx, opts) {
3471
3626
  }
3472
3627
  case "LX": {
3473
3628
  flushServiceLine();
3474
- if (currentClaim === void 0) break;
3475
- currentServiceLine = openServiceLine2(seg, delimiters, currentClaim.variant);
3629
+ if (currentClaim === void 0) {
3630
+ warnings.push(serviceLineDropped(position));
3631
+ droppedLineReported = true;
3632
+ entityLoopClosedByStrayLx ||= activeEntity !== void 0;
3633
+ activeEntity = void 0;
3634
+ break;
3635
+ }
3636
+ currentServiceLine = openServiceLine2(seg, delimiters, currentClaim.variant, position);
3637
+ if (currentServiceLine === void 0) {
3638
+ warnings.push(serviceLineDropped(position));
3639
+ droppedLineReported = true;
3640
+ }
3476
3641
  activeEntity = void 0;
3642
+ entityLoopClosedByStrayLx = false;
3477
3643
  context = { kind: "loop2400" };
3478
3644
  break;
3479
3645
  }
3646
+ // A service segment with no line open to decode into is a loss the
3647
+ // walker used to take in silence. Two ways to reach it, and only one
3648
+ // was ever reported: an LX that opened nothing already warned at the
3649
+ // LX (`droppedLineReported`), while a segment with no Loop 2400 open
3650
+ // at all had no anchor to warn at and so reported on no channel - a
3651
+ // charge, a quantity, a procedure code and its modifiers off the wire
3652
+ // and onto nothing. `reportOrphanServiceSegment` closes only the
3653
+ // second: it anchors at the service segment itself, because that is
3654
+ // the only segment the case has. Note the condition is "no line open",
3655
+ // NOT "no LX in the file": an LX in an earlier claim is still an LX.
3656
+ //
3657
+ // It does NOT decode the segment. The charge is SV1-02 / SV2-03 and
3658
+ // the units SV1-04 / SV2-05 / SV3-06, so reading a service segment
3659
+ // into a line the walker never opened is how a mis-read charge gets
3660
+ // minted. Refusing to read is the safe half; doing it silently was the
3661
+ // defect. This says nothing about VARIANT resolution, which happens
3662
+ // before the walk and scans every SVx in the body: an orphan segment
3663
+ // is eligible for that fallback like any other, which is pre-existing
3664
+ // and disclosed in KNOWN-LIMITATIONS.md rather than changed here.
3480
3665
  case "SV1": {
3481
- if (currentServiceLine !== void 0) decodeSv1(currentServiceLine, seg, delimiters);
3666
+ if (currentServiceLine !== void 0) decodeSv1(currentServiceLine, seg, delimiters, sink);
3667
+ else reportOrphanServiceSegment(position);
3482
3668
  break;
3483
3669
  }
3484
3670
  case "SV2": {
3485
- if (currentServiceLine !== void 0) decodeSv2(currentServiceLine, seg, delimiters);
3671
+ if (currentServiceLine !== void 0) decodeSv2(currentServiceLine, seg, delimiters, sink);
3672
+ else reportOrphanServiceSegment(position);
3486
3673
  break;
3487
3674
  }
3488
3675
  case "SV3": {
3489
- if (currentServiceLine !== void 0) decodeSv3(currentServiceLine, seg, delimiters);
3676
+ if (currentServiceLine !== void 0) decodeSv3(currentServiceLine, seg, delimiters, sink);
3677
+ else reportOrphanServiceSegment(position);
3490
3678
  break;
3491
3679
  }
3492
3680
  case "TOO": {
@@ -3512,7 +3700,7 @@ function get837Claims(delimiters, tx, opts) {
3512
3700
  }
3513
3701
  currentServiceLine.drug = {
3514
3702
  ...currentServiceLine.drug,
3515
- quantity: elementDecimal(seg, 4, delimiters),
3703
+ quantity: elementDecimal(seg, 4, delimiters, sink),
3516
3704
  unitOfMeasure: componentOptional(seg, 5, 1, delimiters)
3517
3705
  };
3518
3706
  break;
@@ -3520,7 +3708,7 @@ function get837Claims(delimiters, tx, opts) {
3520
3708
  case "SVD": {
3521
3709
  flushAdjudication();
3522
3710
  if (currentServiceLine === void 0) break;
3523
- currentAdjudication = openAdjudication(seg, delimiters);
3711
+ currentAdjudication = openAdjudication(seg, delimiters, sink);
3524
3712
  break;
3525
3713
  }
3526
3714
  case "CAS": {
@@ -3698,19 +3886,20 @@ function decodeNte(seg, delimiters) {
3698
3886
  description: note
3699
3887
  });
3700
3888
  }
3701
- function decodeAmt2(seg, delimiters) {
3702
- const amount = elementDecimal(seg, 2, delimiters);
3889
+ function decodeAmt2(seg, delimiters, sink) {
3890
+ const amount = elementDecimal(seg, 2, delimiters, sink);
3703
3891
  if (amount === void 0) return void 0;
3704
3892
  return Object.freeze({ qualifier: elementValue(seg, 1, delimiters), amount });
3705
3893
  }
3706
3894
  function decodeCas(seg, delimiters, warnings, position) {
3895
+ const sink = { warnings, position };
3707
3896
  const groupCode = elementValue(seg, 1, delimiters);
3708
3897
  const out = [];
3709
3898
  for (let triple = 0; triple < 6; triple += 1) {
3710
3899
  const base = 2 + triple * 3;
3711
3900
  const reasonCode = elementOptional(seg, base, delimiters);
3712
- const amount = elementDecimal(seg, base + 1, delimiters);
3713
- const quantity = elementDecimal(seg, base + 2, delimiters);
3901
+ const amount = elementDecimal(seg, base + 1, delimiters, sink);
3902
+ const quantity = elementDecimal(seg, base + 2, delimiters, sink);
3714
3903
  if (reasonCode === void 0 && amount === void 0) continue;
3715
3904
  const code = reasonCode ?? "";
3716
3905
  const entry = code === "" ? void 0 : lookupCarc(code);
@@ -3745,7 +3934,7 @@ var EMPTY_SUBSCRIBER_INFO = Object.freeze({
3745
3934
  groupName: void 0,
3746
3935
  claimFilingIndicator: void 0
3747
3936
  });
3748
- function openClaim2(seg, delimiters, ctx) {
3937
+ function openClaim2(seg, delimiters, ctx, sink) {
3749
3938
  const {
3750
3939
  variant,
3751
3940
  hierarchy,
@@ -3766,7 +3955,7 @@ function openClaim2(seg, delimiters, ctx) {
3766
3955
  payer,
3767
3956
  patient,
3768
3957
  claimId: elementValue(seg, 1, delimiters),
3769
- totalCharge: elementDecimalOrZero(seg, 2, delimiters),
3958
+ totalCharge: elementDecimalOrZero(seg, 2, delimiters, sink),
3770
3959
  placeOfServiceCode: componentOptional(seg, 5, 1, delimiters),
3771
3960
  facilityCodeQualifier: componentOptional(seg, 5, 2, delimiters),
3772
3961
  claimFrequencyCode: componentOptional(seg, 5, 3, delimiters),
@@ -3786,10 +3975,12 @@ function openClaim2(seg, delimiters, ctx) {
3786
3975
  serviceLines: []
3787
3976
  };
3788
3977
  }
3789
- function openServiceLine2(seg, delimiters, variant) {
3978
+ function openServiceLine2(seg, delimiters, variant, position) {
3790
3979
  const lineNumber = elementValue(seg, 1, delimiters);
3791
3980
  const base = {
3792
3981
  lineNumber,
3982
+ position,
3983
+ serviceSegmentDecoded: false,
3793
3984
  charge: X12Decimal.ZERO,
3794
3985
  units: X12Decimal.ZERO,
3795
3986
  unitOfMeasure: void 0,
@@ -3841,8 +4032,9 @@ function openServiceLine2(seg, delimiters, variant) {
3841
4032
  }
3842
4033
  return void 0;
3843
4034
  }
3844
- function decodeSv1(acc, seg, delimiters) {
4035
+ function decodeSv1(acc, seg, delimiters, sink) {
3845
4036
  if (acc.variant !== "P") return;
4037
+ acc.serviceSegmentDecoded = true;
3846
4038
  acc.procedureQualifier = componentOptional(seg, 1, 1, delimiters) ?? "";
3847
4039
  acc.procedureCode = componentOptional(seg, 1, 2, delimiters) ?? "";
3848
4040
  const mods = [];
@@ -3851,9 +4043,9 @@ function decodeSv1(acc, seg, delimiters) {
3851
4043
  if (m !== void 0) mods.push(m);
3852
4044
  }
3853
4045
  acc.modifiers = mods;
3854
- acc.charge = elementDecimalOrZero(seg, 2, delimiters);
4046
+ acc.charge = elementDecimalOrZero(seg, 2, delimiters, sink);
3855
4047
  acc.unitOfMeasure = elementOptional(seg, 3, delimiters);
3856
- acc.units = elementDecimalOrZero(seg, 4, delimiters);
4048
+ acc.units = elementDecimalOrZero(seg, 4, delimiters, sink);
3857
4049
  acc.placeOfServiceCode = elementOptional(seg, 5, delimiters);
3858
4050
  const pointers = [];
3859
4051
  for (let p = 1; p <= 4; p += 1) {
@@ -3865,8 +4057,9 @@ function decodeSv1(acc, seg, delimiters) {
3865
4057
  acc.epsdtIndicator = elementOptional(seg, 11, delimiters);
3866
4058
  acc.familyPlanningIndicator = elementOptional(seg, 12, delimiters);
3867
4059
  }
3868
- function decodeSv2(acc, seg, delimiters) {
4060
+ function decodeSv2(acc, seg, delimiters, sink) {
3869
4061
  if (acc.variant !== "I") return;
4062
+ acc.serviceSegmentDecoded = true;
3870
4063
  acc.revenueCode = elementValue(seg, 1, delimiters);
3871
4064
  acc.procedureQualifier = componentOptional(seg, 2, 1, delimiters);
3872
4065
  acc.procedureCode = componentOptional(seg, 2, 2, delimiters);
@@ -3876,14 +4069,15 @@ function decodeSv2(acc, seg, delimiters) {
3876
4069
  if (m !== void 0) mods.push(m);
3877
4070
  }
3878
4071
  acc.modifiers = mods;
3879
- acc.charge = elementDecimalOrZero(seg, 3, delimiters);
4072
+ acc.charge = elementDecimalOrZero(seg, 3, delimiters, sink);
3880
4073
  acc.unitOfMeasure = elementOptional(seg, 4, delimiters);
3881
- acc.units = elementDecimalOrZero(seg, 5, delimiters);
3882
- acc.serviceLineRate = elementDecimal(seg, 6, delimiters);
3883
- acc.nonCoveredCharge = elementDecimal(seg, 7, delimiters);
4074
+ acc.units = elementDecimalOrZero(seg, 5, delimiters, sink);
4075
+ acc.serviceLineRate = elementDecimal(seg, 6, delimiters, sink);
4076
+ acc.nonCoveredCharge = elementDecimal(seg, 7, delimiters, sink);
3884
4077
  }
3885
- function decodeSv3(acc, seg, delimiters) {
4078
+ function decodeSv3(acc, seg, delimiters, sink) {
3886
4079
  if (acc.variant !== "D") return;
4080
+ acc.serviceSegmentDecoded = true;
3887
4081
  acc.procedureQualifier = componentOptional(seg, 1, 1, delimiters) ?? "";
3888
4082
  acc.procedureCode = componentOptional(seg, 1, 2, delimiters) ?? "";
3889
4083
  const mods = [];
@@ -3892,7 +4086,7 @@ function decodeSv3(acc, seg, delimiters) {
3892
4086
  if (m !== void 0) mods.push(m);
3893
4087
  }
3894
4088
  acc.modifiers = mods;
3895
- acc.charge = elementDecimalOrZero(seg, 2, delimiters);
4089
+ acc.charge = elementDecimalOrZero(seg, 2, delimiters, sink);
3896
4090
  acc.placeOfServiceCode = elementOptional(seg, 3, delimiters);
3897
4091
  const cavities = [];
3898
4092
  for (let p = 1; p <= 5; p += 1) {
@@ -3901,15 +4095,15 @@ function decodeSv3(acc, seg, delimiters) {
3901
4095
  }
3902
4096
  acc.oralCavityArea = cavities;
3903
4097
  acc.prosthesisCrownInlayCode = elementOptional(seg, 5, delimiters);
3904
- acc.units = elementDecimalOrZero(seg, 6, delimiters);
4098
+ acc.units = elementDecimalOrZero(seg, 6, delimiters, sink);
3905
4099
  }
3906
- function openAdjudication(seg, delimiters) {
4100
+ function openAdjudication(seg, delimiters, sink) {
3907
4101
  return {
3908
4102
  otherPayerId: elementValue(seg, 1, delimiters),
3909
- amountPaid: elementDecimalOrZero(seg, 2, delimiters),
4103
+ amountPaid: elementDecimalOrZero(seg, 2, delimiters, sink),
3910
4104
  procedureQualifier: componentOptional(seg, 3, 1, delimiters),
3911
4105
  procedureCode: componentOptional(seg, 3, 2, delimiters),
3912
- paidUnits: elementDecimal(seg, 5, delimiters),
4106
+ paidUnits: elementDecimal(seg, 5, delimiters, sink),
3913
4107
  adjustments: [],
3914
4108
  dateAdjudicated: void 0
3915
4109
  };
@@ -4201,6 +4395,12 @@ function refuseHierarchy(message) {
4201
4395
  function refuseSpec2(message) {
4202
4396
  throw new Claim837BuildError(CLAIM_837_BUILD_ERROR_CODES.X12_837_BUILD_INVALID_SPEC, message);
4203
4397
  }
4398
+ function decStr(value) {
4399
+ return requireCallerDecimal(value, "build837", refuseSpec2).toString();
4400
+ }
4401
+ function escDec2(value, esc) {
4402
+ return esc(decStr(value));
4403
+ }
4204
4404
  var VERSION_BY_VARIANT = {
4205
4405
  P: "005010X222A2",
4206
4406
  I: "005010X223A3",
@@ -4234,6 +4434,7 @@ function buildClaim837(variant, spec) {
4234
4434
  };
4235
4435
  const esc = makeCallerEscaper(delimiters, "build837", refuseSpec2);
4236
4436
  const seg = (parts) => {
4437
+ requireCallerSegment(parts, "build837", refuseSpec2);
4237
4438
  let end = parts.length;
4238
4439
  while (end > 1 && parts[end - 1] === "") end -= 1;
4239
4440
  return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
@@ -4277,8 +4478,8 @@ function buildClaim837(variant, spec) {
4277
4478
  X12_837_FUNCTIONAL_ID,
4278
4479
  esc(applicationSenderCode),
4279
4480
  esc(applicationReceiverCode),
4280
- groupDate,
4281
- groupTime,
4481
+ esc(groupDate),
4482
+ esc(groupTime),
4282
4483
  esc(envelope.groupControlNumber),
4283
4484
  X12_AGENCY_CODE2,
4284
4485
  versionRelease
@@ -4493,7 +4694,7 @@ function emitClaim2(variant, claim, body, ctx) {
4493
4694
  ctx.seg([
4494
4695
  "CLM",
4495
4696
  ctx.esc(claim.claimId),
4496
- ctx.esc(claim.totalCharge.toString()),
4697
+ escDec2(claim.totalCharge, ctx.esc),
4497
4698
  "",
4498
4699
  "",
4499
4700
  ctx.comp([
@@ -4541,8 +4742,8 @@ function emitOtherSubscriber(other, body, ctx) {
4541
4742
  if (other.otherPayer !== void 0) emitEntity(other.otherPayer, body, ctx);
4542
4743
  }
4543
4744
  function emitServiceLine2(variant, line, lineNumber, body, ctx) {
4544
- body.push(ctx.seg(["LX", line.lineNumber ?? String(lineNumber)]));
4545
- const units = line.units === void 0 ? "0" : line.units.toString();
4745
+ body.push(ctx.seg(["LX", ctx.esc(line.lineNumber ?? String(lineNumber))]));
4746
+ const units = line.units === void 0 ? "0" : decStr(line.units);
4546
4747
  if (line.variant === "P") {
4547
4748
  const proc = ctx.comp([line.procedureQualifier, line.procedureCode, ...line.modifiers ?? []]);
4548
4749
  const pointers = ctx.comp(line.diagnosisPointers ?? []);
@@ -4550,7 +4751,7 @@ function emitServiceLine2(variant, line, lineNumber, body, ctx) {
4550
4751
  ctx.seg([
4551
4752
  "SV1",
4552
4753
  proc,
4553
- ctx.esc(line.charge.toString()),
4754
+ escDec2(line.charge, ctx.esc),
4554
4755
  ctx.esc(line.unitOfMeasure ?? ""),
4555
4756
  ctx.esc(units),
4556
4757
  ctx.esc(line.placeOfServiceCode ?? ""),
@@ -4574,11 +4775,11 @@ function emitServiceLine2(variant, line, lineNumber, body, ctx) {
4574
4775
  "SV2",
4575
4776
  ctx.esc(line.revenueCode),
4576
4777
  proc,
4577
- ctx.esc(line.charge.toString()),
4778
+ escDec2(line.charge, ctx.esc),
4578
4779
  ctx.esc(line.unitOfMeasure ?? ""),
4579
4780
  ctx.esc(units),
4580
- line.serviceLineRate === void 0 ? "" : ctx.esc(line.serviceLineRate.toString()),
4581
- line.nonCoveredCharge === void 0 ? "" : ctx.esc(line.nonCoveredCharge.toString())
4781
+ line.serviceLineRate === void 0 ? "" : escDec2(line.serviceLineRate, ctx.esc),
4782
+ line.nonCoveredCharge === void 0 ? "" : escDec2(line.nonCoveredCharge, ctx.esc)
4582
4783
  ])
4583
4784
  );
4584
4785
  } else {
@@ -4588,7 +4789,7 @@ function emitServiceLine2(variant, line, lineNumber, body, ctx) {
4588
4789
  ctx.seg([
4589
4790
  "SV3",
4590
4791
  proc,
4591
- ctx.esc(line.charge.toString()),
4792
+ escDec2(line.charge, ctx.esc),
4592
4793
  ctx.esc(line.placeOfServiceCode ?? ""),
4593
4794
  cavity,
4594
4795
  ctx.esc(line.prosthesisCrownInlayCode ?? ""),
@@ -4607,7 +4808,7 @@ function emitServiceLine2(variant, line, lineNumber, body, ctx) {
4607
4808
  "",
4608
4809
  "",
4609
4810
  "",
4610
- drug.quantity === void 0 ? "" : ctx.esc(drug.quantity.toString()),
4811
+ drug.quantity === void 0 ? "" : escDec2(drug.quantity, ctx.esc),
4611
4812
  ctx.esc(drug.unitOfMeasure ?? "")
4612
4813
  ])
4613
4814
  );
@@ -4637,10 +4838,10 @@ function emitAdjudication(adj, body, ctx) {
4637
4838
  ctx.seg([
4638
4839
  "SVD",
4639
4840
  ctx.esc(adj.otherPayerId),
4640
- ctx.esc(adj.amountPaid.toString()),
4841
+ escDec2(adj.amountPaid, ctx.esc),
4641
4842
  proc,
4642
4843
  "",
4643
- adj.paidUnits === void 0 ? "" : ctx.esc(adj.paidUnits.toString())
4844
+ adj.paidUnits === void 0 ? "" : escDec2(adj.paidUnits, ctx.esc)
4644
4845
  ])
4645
4846
  );
4646
4847
  emitCasGroup2(adj.adjustments, "build837: adjudication.adjustments", body, ctx);
@@ -4665,8 +4866,8 @@ function emitCasGroup2(raw, at, body, ctx) {
4665
4866
  if (adj === void 0 || adj.groupCode !== groupCode) break;
4666
4867
  parts.push(
4667
4868
  ctx.esc(adj.reasonCode),
4668
- ctx.esc(adj.amount.toString()),
4669
- adj.quantity === void 0 ? "" : ctx.esc(adj.quantity.toString())
4869
+ escDec2(adj.amount, ctx.esc),
4870
+ adj.quantity === void 0 ? "" : escDec2(adj.quantity, ctx.esc)
4670
4871
  );
4671
4872
  triples += 1;
4672
4873
  i += 1;
@@ -4737,7 +4938,7 @@ function emitNote(note, body, ctx) {
4737
4938
  body.push(ctx.seg(["NTE", ctx.esc(note.noteReferenceCode), ctx.esc(note.description)]));
4738
4939
  }
4739
4940
  function emitAmount(amt, body, ctx) {
4740
- body.push(ctx.seg(["AMT", ctx.esc(amt.qualifier), ctx.esc(amt.amount.toString())]));
4941
+ body.push(ctx.seg(["AMT", ctx.esc(amt.qualifier), escDec2(amt.amount, ctx.esc)]));
4741
4942
  }
4742
4943
  function emitHi(hi, body, ctx) {
4743
4944
  const composite = ctx.comp([
@@ -4745,8 +4946,10 @@ function emitHi(hi, body, ctx) {
4745
4946
  hi.code,
4746
4947
  hi.dateQualifier ?? "",
4747
4948
  hi.date ?? "",
4748
- hi.monetaryAmount === void 0 ? "" : hi.monetaryAmount.toString(),
4749
- hi.quantity === void 0 ? "" : hi.quantity.toString(),
4949
+ // `decStr`, not `escDec`: `ctx.comp` maps `esc` over every component, so
4950
+ // escaping here would double-release an active delimiter.
4951
+ hi.monetaryAmount === void 0 ? "" : decStr(hi.monetaryAmount),
4952
+ hi.quantity === void 0 ? "" : decStr(hi.quantity),
4750
4953
  hi.versionId ?? "",
4751
4954
  "",
4752
4955
  hi.poaIndicator ?? ""
@@ -5058,6 +5261,7 @@ function get271Eligibility(delimiters, tx) {
5058
5261
  const seg = body[i];
5059
5262
  if (seg === void 0) continue;
5060
5263
  const position = { segmentIndex: i + 1, transactionIndex: 0 };
5264
+ const sink = { warnings, position };
5061
5265
  switch (seg.id) {
5062
5266
  case "HL": {
5063
5267
  const hl = decodeHl2(seg, delimiters);
@@ -5161,7 +5365,7 @@ function get271Eligibility(delimiters, tx) {
5161
5365
  case "EB": {
5162
5366
  flushBenefit();
5163
5367
  if (currentSubscriber === void 0 && currentDependent === void 0) break;
5164
- currentBenefit = openBenefit(seg, delimiters);
5368
+ currentBenefit = openBenefit(seg, delimiters, sink);
5165
5369
  break;
5166
5370
  }
5167
5371
  case "MSG": {
@@ -5258,7 +5462,7 @@ function decodeDtp2(seg, delimiters) {
5258
5462
  value
5259
5463
  });
5260
5464
  }
5261
- function openBenefit(seg, delimiters) {
5465
+ function openBenefit(seg, delimiters, sink) {
5262
5466
  const serviceTypeCodes = [];
5263
5467
  for (const code of getAllSegmentValues(seg, "03", delimiters)) {
5264
5468
  if (code === "") continue;
@@ -5273,10 +5477,10 @@ function openBenefit(seg, delimiters) {
5273
5477
  insuranceTypeCode: elementOptional(seg, 4, delimiters),
5274
5478
  planCoverageDescription: elementOptional(seg, 5, delimiters),
5275
5479
  timePeriodQualifier: elementOptional(seg, 6, delimiters),
5276
- monetaryAmount: elementDecimal(seg, 7, delimiters),
5277
- percent: elementDecimal(seg, 8, delimiters),
5480
+ monetaryAmount: elementDecimal(seg, 7, delimiters, sink),
5481
+ percent: elementDecimal(seg, 8, delimiters, sink),
5278
5482
  quantityQualifier: elementOptional(seg, 9, delimiters),
5279
- quantity: elementDecimal(seg, 10, delimiters),
5483
+ quantity: elementDecimal(seg, 10, delimiters, sink),
5280
5484
  authorizationRequired: elementOptional(seg, 11, delimiters),
5281
5485
  inPlanNetwork: elementOptional(seg, 12, delimiters),
5282
5486
  references: [],
@@ -5379,6 +5583,9 @@ function refuseSpec3(message) {
5379
5583
  message
5380
5584
  );
5381
5585
  }
5586
+ function escDec3(value, esc) {
5587
+ return esc(requireCallerDecimal(value, "build271", refuseSpec3).toString());
5588
+ }
5382
5589
  var X279A1_VERSION_RELEASE = "005010X279A1";
5383
5590
  var X12_271_FUNCTIONAL_ID = "HB";
5384
5591
  var X12_AGENCY_CODE3 = "X";
@@ -5398,6 +5605,7 @@ function build271(spec) {
5398
5605
  };
5399
5606
  const esc = makeCallerEscaper(delimiters, "build271", refuseSpec3);
5400
5607
  const seg = (parts) => {
5608
+ requireCallerSegment(parts, "build271", refuseSpec3);
5401
5609
  let end = parts.length;
5402
5610
  while (end > 1 && parts[end - 1] === "") end -= 1;
5403
5611
  return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
@@ -5435,8 +5643,8 @@ function build271(spec) {
5435
5643
  X12_271_FUNCTIONAL_ID,
5436
5644
  esc(applicationSenderCode),
5437
5645
  esc(applicationReceiverCode),
5438
- groupDate,
5439
- groupTime,
5646
+ esc(groupDate),
5647
+ esc(groupTime),
5440
5648
  esc(envelope.groupControlNumber),
5441
5649
  X12_AGENCY_CODE3,
5442
5650
  X279A1_VERSION_RELEASE
@@ -5606,10 +5814,10 @@ function emitBenefit(benefit, body, ctx) {
5606
5814
  ctx.esc(benefit.insuranceTypeCode ?? ""),
5607
5815
  ctx.esc(benefit.planCoverageDescription ?? ""),
5608
5816
  ctx.esc(benefit.timePeriodQualifier ?? ""),
5609
- benefit.monetaryAmount === void 0 ? "" : ctx.esc(benefit.monetaryAmount.toString()),
5610
- benefit.percent === void 0 ? "" : ctx.esc(benefit.percent.toString()),
5817
+ benefit.monetaryAmount === void 0 ? "" : escDec3(benefit.monetaryAmount, ctx.esc),
5818
+ benefit.percent === void 0 ? "" : escDec3(benefit.percent, ctx.esc),
5611
5819
  ctx.esc(benefit.quantityQualifier ?? ""),
5612
- benefit.quantity === void 0 ? "" : ctx.esc(benefit.quantity.toString()),
5820
+ benefit.quantity === void 0 ? "" : escDec3(benefit.quantity, ctx.esc),
5613
5821
  ctx.esc(benefit.authorizationRequired ?? ""),
5614
5822
  ctx.esc(benefit.inPlanNetwork ?? "")
5615
5823
  ])
@@ -5816,6 +6024,7 @@ function walk277(delimiters, tx) {
5816
6024
  const seg = body[i];
5817
6025
  if (seg === void 0) continue;
5818
6026
  const position = { segmentIndex: i + 1, transactionIndex: 0 };
6027
+ const sink = { warnings, position };
5819
6028
  switch (seg.id) {
5820
6029
  case "HL": {
5821
6030
  flushClaim();
@@ -5893,7 +6102,7 @@ function walk277(delimiters, tx) {
5893
6102
  case "SVC": {
5894
6103
  flushServiceLine();
5895
6104
  if (currentClaim === void 0) currentClaim = openClaim3();
5896
- currentServiceLine = openServiceLine3(seg, delimiters);
6105
+ currentServiceLine = openServiceLine3(seg, delimiters, sink);
5897
6106
  break;
5898
6107
  }
5899
6108
  case "REF": {
@@ -5967,6 +6176,7 @@ function decodeDtp3(seg, delimiters) {
5967
6176
  });
5968
6177
  }
5969
6178
  function decodeStc(seg, delimiters, warnings, position) {
6179
+ const sink = { warnings, position };
5970
6180
  const statuses = [];
5971
6181
  for (const elementIndex of [1, 10, 11]) {
5972
6182
  const code = decodeStatusComposite(seg, elementIndex, delimiters, warnings, position);
@@ -5975,8 +6185,8 @@ function decodeStc(seg, delimiters, warnings, position) {
5975
6185
  return Object.freeze({
5976
6186
  statusEffectiveDate: elementOptional(seg, 2, delimiters),
5977
6187
  actionCode: elementOptional(seg, 3, delimiters),
5978
- totalChargeAmount: elementDecimal(seg, 4, delimiters),
5979
- paymentAmount: elementDecimal(seg, 5, delimiters),
6188
+ totalChargeAmount: elementDecimal(seg, 4, delimiters, sink),
6189
+ paymentAmount: elementDecimal(seg, 5, delimiters, sink),
5980
6190
  adjudicationDate: elementOptional(seg, 6, delimiters),
5981
6191
  message: elementOptional(seg, 12, delimiters),
5982
6192
  statuses: Object.freeze(statuses)
@@ -6003,7 +6213,7 @@ function decodeStatusComposite(seg, n, delimiters, warnings, position) {
6003
6213
  entityCode
6004
6214
  });
6005
6215
  }
6006
- function openServiceLine3(seg, delimiters) {
6216
+ function openServiceLine3(seg, delimiters, sink) {
6007
6217
  const modifiers = [];
6008
6218
  for (let comp = 3; comp <= 6; comp += 1) {
6009
6219
  const m = componentOptional(seg, 1, comp, delimiters);
@@ -6013,9 +6223,13 @@ function openServiceLine3(seg, delimiters) {
6013
6223
  serviceIdQualifier: componentOptional(seg, 1, 1, delimiters),
6014
6224
  procedureCode: componentOptional(seg, 1, 2, delimiters),
6015
6225
  modifiers,
6016
- lineChargeAmount: elementDecimal(seg, 2, delimiters),
6017
- linePaymentAmount: elementDecimal(seg, 3, delimiters),
6226
+ lineChargeAmount: elementDecimal(seg, 2, delimiters, sink),
6227
+ linePaymentAmount: elementDecimal(seg, 3, delimiters, sink),
6018
6228
  revenueCode: elementOptional(seg, 4, delimiters),
6229
+ // SVC-07. SVC-05 (Quantity) and SVC-06 (a second composite) are NOT USED
6230
+ // in both X212 and X214, so they are deliberately left unread rather than
6231
+ // decoded "for symmetry" with the 835, whose SVC-05 IS the paid count.
6232
+ unitsOfService: elementDecimal(seg, 7, delimiters, sink),
6019
6233
  statuses: [],
6020
6234
  references: [],
6021
6235
  dates: []
@@ -6029,6 +6243,7 @@ function freezeServiceLine3(acc) {
6029
6243
  lineChargeAmount: acc.lineChargeAmount,
6030
6244
  linePaymentAmount: acc.linePaymentAmount,
6031
6245
  revenueCode: acc.revenueCode,
6246
+ unitsOfService: acc.unitsOfService,
6032
6247
  statuses: Object.freeze(acc.statuses.slice()),
6033
6248
  references: Object.freeze(acc.references.slice()),
6034
6249
  dates: Object.freeze(acc.dates.slice())
@@ -6077,6 +6292,9 @@ function refuseSpec4(message) {
6077
6292
  message
6078
6293
  );
6079
6294
  }
6295
+ function escDec4(value, esc) {
6296
+ return esc(requireCallerDecimal(value, "build277", refuseSpec4).toString());
6297
+ }
6080
6298
  var X12_277_FUNCTIONAL_ID = "HN";
6081
6299
  var X12_AGENCY_CODE4 = "X";
6082
6300
  var HL_LEVEL3 = {
@@ -6094,7 +6312,7 @@ function build277CA(spec) {
6094
6312
  }
6095
6313
  function buildClaimStatus(version, spec) {
6096
6314
  const { envelope } = spec;
6097
- enforceStructuralSpec4(spec);
6315
+ enforceStructuralSpec4(version, spec);
6098
6316
  const elementSeparator = envelope.elementSeparator ?? "*";
6099
6317
  const repetitionSeparator = envelope.repetitionSeparator ?? "^";
6100
6318
  const componentSeparator = envelope.componentSeparator ?? ":";
@@ -6107,6 +6325,7 @@ function buildClaimStatus(version, spec) {
6107
6325
  };
6108
6326
  const esc = makeCallerEscaper(delimiters, "build277", refuseSpec4);
6109
6327
  const seg = (parts) => {
6328
+ requireCallerSegment(parts, "build277", refuseSpec4);
6110
6329
  let end = parts.length;
6111
6330
  while (end > 1 && parts[end - 1] === "") end -= 1;
6112
6331
  return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
@@ -6150,8 +6369,8 @@ function buildClaimStatus(version, spec) {
6150
6369
  X12_277_FUNCTIONAL_ID,
6151
6370
  esc(applicationSenderCode),
6152
6371
  esc(applicationReceiverCode),
6153
- groupDate,
6154
- groupTime,
6372
+ esc(groupDate),
6373
+ esc(groupTime),
6155
6374
  esc(envelope.groupControlNumber),
6156
6375
  X12_AGENCY_CODE4,
6157
6376
  version
@@ -6170,7 +6389,7 @@ function buildClaimStatus(version, spec) {
6170
6389
  const raw = isa + gs + st + body.join("") + se + ge + iea;
6171
6390
  return parseX12(raw);
6172
6391
  }
6173
- function enforceStructuralSpec4(spec) {
6392
+ function enforceStructuralSpec4(version, spec) {
6174
6393
  const sources = requireCallerArray(
6175
6394
  spec.informationSources,
6176
6395
  "build277: spec.informationSources",
@@ -6228,13 +6447,13 @@ function enforceStructuralSpec4(spec) {
6228
6447
  for (let u = 0; u < subscribers.length; u += 1) {
6229
6448
  const subscriber = subscribers[u];
6230
6449
  if (subscriber === void 0) continue;
6231
- enforceSubscriber(subscriber, `${locator}.subscriber[${String(u)}]`);
6450
+ enforceSubscriber(version, subscriber, `${locator}.subscriber[${String(u)}]`);
6232
6451
  }
6233
6452
  }
6234
6453
  }
6235
6454
  }
6236
6455
  }
6237
- function enforceSubscriber(subscriber, locator) {
6456
+ function enforceSubscriber(version, subscriber, locator) {
6238
6457
  const claims = requireCallerArray(
6239
6458
  subscriber.claims,
6240
6459
  `build277: subscriber at ${locator}: claims`,
@@ -6253,7 +6472,8 @@ function enforceSubscriber(subscriber, locator) {
6253
6472
  }
6254
6473
  for (let c = 0; c < claims.length; c += 1) {
6255
6474
  const claim = claims[c];
6256
- if (claim !== void 0) enforceClaim2(claim, `${locator}.claim[${String(c)}]`, c === 0);
6475
+ if (claim !== void 0)
6476
+ enforceClaim2(version, claim, `${locator}.claim[${String(c)}]`, c === 0);
6257
6477
  }
6258
6478
  for (let d = 0; d < dependents.length; d += 1) {
6259
6479
  const dependent = dependents[d];
@@ -6272,11 +6492,12 @@ function enforceSubscriber(subscriber, locator) {
6272
6492
  }
6273
6493
  for (let c = 0; c < depClaims.length; c += 1) {
6274
6494
  const claim = depClaims[c];
6275
- if (claim !== void 0) enforceClaim2(claim, `${depLocator}.claim[${String(c)}]`, c === 0);
6495
+ if (claim !== void 0)
6496
+ enforceClaim2(version, claim, `${depLocator}.claim[${String(c)}]`, c === 0);
6276
6497
  }
6277
6498
  }
6278
6499
  }
6279
- function enforceClaim2(claim, locator, isFirst) {
6500
+ function enforceClaim2(version, claim, locator, isFirst) {
6280
6501
  const statuses = requireCallerArray(
6281
6502
  claim.statuses,
6282
6503
  `build277: claim at ${locator}: statuses`,
@@ -6305,6 +6526,12 @@ function enforceClaim2(claim, locator, isFirst) {
6305
6526
  for (let l = 0; l < serviceLines.length; l += 1) {
6306
6527
  const line = serviceLines[l];
6307
6528
  if (line === void 0) continue;
6529
+ if (version === "005010X212" && line.unitsOfService === void 0) {
6530
+ throw new ClaimStatus277BuildError(
6531
+ CLAIM_STATUS_277_BUILD_ERROR_CODES.X12_277_BUILD_INVALID_SPEC,
6532
+ `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.`
6533
+ );
6534
+ }
6308
6535
  const lineStatuses = requireCallerArray(
6309
6536
  line.statuses,
6310
6537
  `build277: claim at ${locator}.line[${String(l)}]: statuses`,
@@ -6398,9 +6625,12 @@ function emitServiceLine3(line, body, ctx) {
6398
6625
  ctx.seg([
6399
6626
  "SVC",
6400
6627
  svc01,
6401
- line.lineChargeAmount === void 0 ? "" : ctx.esc(line.lineChargeAmount.toString()),
6402
- line.linePaymentAmount === void 0 ? "" : ctx.esc(line.linePaymentAmount.toString()),
6403
- ctx.esc(line.revenueCode ?? "")
6628
+ line.lineChargeAmount === void 0 ? "" : escDec4(line.lineChargeAmount, ctx.esc),
6629
+ line.linePaymentAmount === void 0 ? "" : escDec4(line.linePaymentAmount, ctx.esc),
6630
+ ctx.esc(line.revenueCode ?? ""),
6631
+ "",
6632
+ "",
6633
+ line.unitsOfService === void 0 ? "" : escDec4(line.unitsOfService, ctx.esc)
6404
6634
  ])
6405
6635
  );
6406
6636
  for (const status of line.statuses ?? []) emitStatus(status, body, ctx);
@@ -6419,8 +6649,8 @@ function emitStatus(status, body, ctx) {
6419
6649
  composite(0),
6420
6650
  ctx.esc(status.statusEffectiveDate ?? ""),
6421
6651
  ctx.esc(status.actionCode ?? ""),
6422
- status.totalChargeAmount === void 0 ? "" : ctx.esc(status.totalChargeAmount.toString()),
6423
- status.paymentAmount === void 0 ? "" : ctx.esc(status.paymentAmount.toString()),
6652
+ status.totalChargeAmount === void 0 ? "" : escDec4(status.totalChargeAmount, ctx.esc),
6653
+ status.paymentAmount === void 0 ? "" : escDec4(status.paymentAmount, ctx.esc),
6424
6654
  ctx.esc(status.adjudicationDate ?? ""),
6425
6655
  "",
6426
6656
  "",
@@ -6590,9 +6820,11 @@ function get820Payments(delimiters, tx) {
6590
6820
  for (let i = 0; i < body.length; i += 1) {
6591
6821
  const seg = body[i];
6592
6822
  if (seg === void 0) continue;
6823
+ const position = { segmentIndex: i + 1, transactionIndex: 0 };
6824
+ const sink = { warnings, position };
6593
6825
  switch (seg.id) {
6594
6826
  case "BPR": {
6595
- payment = decodeBpr2(seg, delimiters);
6827
+ payment = decodeBpr2(seg, delimiters, sink);
6596
6828
  break;
6597
6829
  }
6598
6830
  case "TRN": {
@@ -6659,13 +6891,13 @@ function get820Payments(delimiters, tx) {
6659
6891
  }
6660
6892
  case "RMR": {
6661
6893
  if (current === void 0) break;
6662
- const item = decodeRmr(seg, delimiters);
6894
+ const item = decodeRmr(seg, delimiters, sink);
6663
6895
  if (item !== void 0) current.openItems.push(item);
6664
6896
  break;
6665
6897
  }
6666
6898
  case "ADX": {
6667
6899
  if (current === void 0) break;
6668
- const adjustment = decodeAdx(seg, delimiters);
6900
+ const adjustment = decodeAdx(seg, delimiters, sink);
6669
6901
  if (adjustment !== void 0) current.adjustments.push(adjustment);
6670
6902
  break;
6671
6903
  }
@@ -6717,10 +6949,10 @@ function freezeRemittance(acc) {
6717
6949
  adjustments: Object.freeze(acc.adjustments.slice())
6718
6950
  });
6719
6951
  }
6720
- function decodeBpr2(seg, delimiters) {
6952
+ function decodeBpr2(seg, delimiters, sink) {
6721
6953
  return Object.freeze({
6722
6954
  transactionHandlingCode: elementValue(seg, 1, delimiters),
6723
- totalPremiumAmount: elementDecimalOrZero(seg, 2, delimiters),
6955
+ totalPremiumAmount: elementDecimalOrZero(seg, 2, delimiters, sink),
6724
6956
  creditDebitFlag: elementValue(seg, 3, delimiters),
6725
6957
  method: elementValue(seg, 4, delimiters),
6726
6958
  paymentFormatCode: elementOptional(seg, 5, delimiters),
@@ -6788,7 +7020,7 @@ function decodeNm13(seg, delimiters) {
6788
7020
  idCode: elementOptional(seg, 9, delimiters)
6789
7021
  });
6790
7022
  }
6791
- function decodeRmr(seg, delimiters) {
7023
+ function decodeRmr(seg, delimiters, sink) {
6792
7024
  const qualifier = elementValue(seg, 1, delimiters);
6793
7025
  const referenceId = elementValue(seg, 2, delimiters);
6794
7026
  if (qualifier === "" && referenceId === "") return void 0;
@@ -6796,12 +7028,12 @@ function decodeRmr(seg, delimiters) {
6796
7028
  qualifier,
6797
7029
  referenceId,
6798
7030
  paymentActionCode: elementOptional(seg, 3, delimiters),
6799
- amountPaid: elementDecimalOrZero(seg, 4, delimiters),
6800
- amountDue: elementDecimal(seg, 5, delimiters)
7031
+ amountPaid: elementDecimalOrZero(seg, 4, delimiters, sink),
7032
+ amountDue: elementDecimal(seg, 5, delimiters, sink)
6801
7033
  });
6802
7034
  }
6803
- function decodeAdx(seg, delimiters) {
6804
- const amount = elementDecimal(seg, 1, delimiters);
7035
+ function decodeAdx(seg, delimiters, sink) {
7036
+ const amount = elementDecimal(seg, 1, delimiters, sink);
6805
7037
  if (amount === void 0) return void 0;
6806
7038
  return Object.freeze({
6807
7039
  amount,
@@ -6862,6 +7094,9 @@ var Premium820BuildError = class extends Error {
6862
7094
  function refuseSpec5(message) {
6863
7095
  throw new Premium820BuildError(PREMIUM_820_BUILD_ERROR_CODES.X12_820_BUILD_INVALID_SPEC, message);
6864
7096
  }
7097
+ function escDec5(value, esc) {
7098
+ return esc(requireCallerDecimal(value, "build820", refuseSpec5).toString());
7099
+ }
6865
7100
  var X218_VERSION_RELEASE = "005010X218";
6866
7101
  var X12_820_FUNCTIONAL_ID = "RA";
6867
7102
  var X12_AGENCY_CODE5 = "X";
@@ -6880,6 +7115,7 @@ function build820(spec) {
6880
7115
  };
6881
7116
  const esc = makeCallerEscaper(delimiters, "build820", refuseSpec5);
6882
7117
  const seg = (parts) => {
7118
+ requireCallerSegment(parts, "build820", refuseSpec5);
6883
7119
  let end = parts.length;
6884
7120
  while (end > 1 && parts[end - 1] === "") end -= 1;
6885
7121
  return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
@@ -6935,9 +7171,9 @@ function build820(spec) {
6935
7171
  // GS-02
6936
7172
  esc(applicationReceiverCode),
6937
7173
  // GS-03
6938
- groupDate,
7174
+ esc(groupDate),
6939
7175
  // GS-04 - CCYYMMDD
6940
- groupTime,
7176
+ esc(groupTime),
6941
7177
  // GS-05 - HHMM
6942
7178
  esc(envelope.groupControlNumber),
6943
7179
  // GS-06
@@ -6953,7 +7189,7 @@ function build820(spec) {
6953
7189
  seg([
6954
7190
  "BPR",
6955
7191
  esc(spec.payment.transactionHandlingCode),
6956
- esc(spec.payment.totalPremiumAmount.toString()),
7192
+ escDec5(spec.payment.totalPremiumAmount, esc),
6957
7193
  esc(spec.payment.creditDebitFlag),
6958
7194
  esc(spec.payment.method),
6959
7195
  esc(spec.payment.paymentFormatCode ?? ""),
@@ -7110,7 +7346,7 @@ function emitRemittance(remittance, body, seg, esc) {
7110
7346
  body.push(
7111
7347
  seg([
7112
7348
  "ADX",
7113
- esc(adjustment.amount.toString()),
7349
+ escDec5(adjustment.amount, esc),
7114
7350
  esc(adjustment.reasonCode),
7115
7351
  esc(adjustment.referenceQualifier ?? ""),
7116
7352
  esc(adjustment.referenceId ?? "")
@@ -7140,8 +7376,8 @@ function emitOpenItem(item, seg, esc) {
7140
7376
  esc(item.qualifier),
7141
7377
  esc(item.referenceId),
7142
7378
  esc(item.paymentActionCode ?? ""),
7143
- esc(item.amountPaid.toString()),
7144
- item.amountDue === void 0 ? "" : esc(item.amountDue.toString())
7379
+ escDec5(item.amountPaid, esc),
7380
+ item.amountDue === void 0 ? "" : escDec5(item.amountDue, esc)
7145
7381
  ]);
7146
7382
  }
7147
7383
  function emitRef5(ref, seg, esc) {
@@ -7372,7 +7608,8 @@ async function* get834Enrollments(delimiters, tx) {
7372
7608
  }
7373
7609
  case "AMT": {
7374
7610
  if (currentCoverage === void 0) break;
7375
- const amount = decodeAmt3(seg, delimiters);
7611
+ const sink = { warnings: current.warnings, position };
7612
+ const amount = decodeAmt3(seg, delimiters, sink);
7376
7613
  if (amount !== void 0) currentCoverage.amounts.push(amount);
7377
7614
  break;
7378
7615
  }
@@ -7498,8 +7735,8 @@ function decodeDtp4(seg, delimiters) {
7498
7735
  value
7499
7736
  });
7500
7737
  }
7501
- function decodeAmt3(seg, delimiters) {
7502
- const amount = elementDecimal(seg, 2, delimiters);
7738
+ function decodeAmt3(seg, delimiters, sink) {
7739
+ const amount = elementDecimal(seg, 2, delimiters, sink);
7503
7740
  if (amount === void 0) return void 0;
7504
7741
  return Object.freeze({
7505
7742
  qualifier: elementValue(seg, 1, delimiters),
@@ -7561,6 +7798,9 @@ function refuseSpec6(message) {
7561
7798
  message
7562
7799
  );
7563
7800
  }
7801
+ function escDec6(value, esc) {
7802
+ return esc(requireCallerDecimal(value, "build834", refuseSpec6).toString());
7803
+ }
7564
7804
  var X220A1_VERSION_RELEASE = "005010X220A1";
7565
7805
  var X12_834_FUNCTIONAL_ID = "BE";
7566
7806
  var X12_AGENCY_CODE6 = "X";
@@ -7581,6 +7821,7 @@ function build834(spec) {
7581
7821
  };
7582
7822
  const esc = makeCallerEscaper(delimiters, "build834", refuseSpec6);
7583
7823
  const seg = (parts) => {
7824
+ requireCallerSegment(parts, "build834", refuseSpec6);
7584
7825
  let end = parts.length;
7585
7826
  while (end > 1 && parts[end - 1] === "") end -= 1;
7586
7827
  return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
@@ -7636,9 +7877,9 @@ function build834(spec) {
7636
7877
  // GS-02
7637
7878
  esc(applicationReceiverCode),
7638
7879
  // GS-03
7639
- groupDate,
7880
+ esc(groupDate),
7640
7881
  // GS-04 - CCYYMMDD
7641
- groupTime,
7882
+ esc(groupTime),
7642
7883
  // GS-05 - HHMM
7643
7884
  esc(envelope.groupControlNumber),
7644
7885
  // GS-06
@@ -7819,7 +8060,7 @@ function emitCoverage(coverage, body, seg, esc) {
7819
8060
  );
7820
8061
  for (const date of coverage.dates ?? []) body.push(emitDate4(date, seg, esc));
7821
8062
  for (const amount of coverage.amounts ?? []) {
7822
- body.push(seg(["AMT", esc(amount.qualifier), esc(amount.amount.toString())]));
8063
+ body.push(seg(["AMT", esc(amount.qualifier), escDec6(amount.amount, esc)]));
7823
8064
  }
7824
8065
  }
7825
8066
  function emitRef6(ref, seg, esc) {
@@ -8227,6 +8468,7 @@ var HL_LEVEL4 = {
8227
8468
  DEPENDENT: "23"
8228
8469
  };
8229
8470
  var DEFAULT_REVIEW_LEVEL = "EV";
8471
+ var REVIEW_LEVEL_CODES = Object.freeze(["EV", "SS"]);
8230
8472
  function build278Request(spec) {
8231
8473
  return buildServicesReview("005010X217", "request", spec);
8232
8474
  }
@@ -8248,6 +8490,7 @@ function buildServicesReview(version, direction, spec) {
8248
8490
  };
8249
8491
  const esc = makeCallerEscaper(delimiters, "build278", refuseSpec7);
8250
8492
  const seg = (parts) => {
8493
+ requireCallerSegment(parts, "build278", refuseSpec7);
8251
8494
  let end = parts.length;
8252
8495
  while (end > 1 && parts[end - 1] === "") end -= 1;
8253
8496
  return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
@@ -8291,8 +8534,8 @@ function buildServicesReview(version, direction, spec) {
8291
8534
  X12_278_FUNCTIONAL_ID,
8292
8535
  esc(applicationSenderCode),
8293
8536
  esc(applicationReceiverCode),
8294
- groupDate,
8295
- groupTime,
8537
+ esc(groupDate),
8538
+ esc(groupTime),
8296
8539
  esc(envelope.groupControlNumber),
8297
8540
  X12_AGENCY_CODE7,
8298
8541
  version
@@ -8364,6 +8607,13 @@ function enforceStructuralSpec7(spec, direction) {
8364
8607
  }
8365
8608
  }
8366
8609
  function enforceReview(review, locator, direction) {
8610
+ const resolvedLevel = review.levelCode ?? DEFAULT_REVIEW_LEVEL;
8611
+ if (!REVIEW_LEVEL_CODES.includes(resolvedLevel)) {
8612
+ throw new ServicesReview278BuildError(
8613
+ AUTH_278_BUILD_ERROR_CODES.X12_278_BUILD_INVALID_SPEC,
8614
+ `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.`
8615
+ );
8616
+ }
8367
8617
  if (review.requestCategoryCode === "") {
8368
8618
  throw new ServicesReview278BuildError(
8369
8619
  AUTH_278_BUILD_ERROR_CODES.X12_278_BUILD_INVALID_SPEC,
@@ -8421,7 +8671,7 @@ function emitReview(review, parentHlId, direction, body, ctx, counter) {
8421
8671
  const nested = review.reviews ?? [];
8422
8672
  const hasChild = nested.length > 0 ? "1" : "0";
8423
8673
  const levelCode = review.levelCode ?? DEFAULT_REVIEW_LEVEL;
8424
- body.push(ctx.seg(["HL", hlId, parentHlId, levelCode, hasChild]));
8674
+ body.push(ctx.seg(["HL", hlId, parentHlId, ctx.esc(levelCode), hasChild]));
8425
8675
  for (const trace of review.traces ?? []) {
8426
8676
  body.push(
8427
8677
  ctx.seg([
@@ -9068,13 +9318,13 @@ function build999(spec) {
9068
9318
  // GS-02
9069
9319
  esc(envelope.receiverId),
9070
9320
  // GS-03
9071
- groupDate,
9321
+ esc(groupDate),
9072
9322
  // GS-04 - CCYYMMDD
9073
- groupTime,
9323
+ esc(groupTime),
9074
9324
  // GS-05 - HHMM
9075
- envelope.groupControlNumber,
9325
+ esc(envelope.groupControlNumber),
9076
9326
  // GS-06
9077
- groupResponsibleAgency,
9327
+ esc(groupResponsibleAgency),
9078
9328
  // GS-07
9079
9329
  X231A1_VERSION_RELEASE
9080
9330
  // GS-08 - the 999 TR3
@@ -9084,7 +9334,7 @@ function build999(spec) {
9084
9334
  );
9085
9335
  const stControlNumber = envelope.transactionSetControlNumber;
9086
9336
  const st = joinSeg(
9087
- ["ST", "999", stControlNumber, X231A1_VERSION_RELEASE],
9337
+ ["ST", "999", esc(stControlNumber), X231A1_VERSION_RELEASE],
9088
9338
  elementSeparator,
9089
9339
  segmentTerminator
9090
9340
  );
@@ -9117,8 +9367,16 @@ function build999(spec) {
9117
9367
  const ak9 = buildAk9(functionalGroup, esc, elementSeparator, segmentTerminator);
9118
9368
  const bodySegments = [st, ak1, ...responseSegments, ak9];
9119
9369
  const seCount = bodySegments.length + 1;
9120
- const se = joinSeg(["SE", String(seCount), stControlNumber], elementSeparator, segmentTerminator);
9121
- const ge = joinSeg(["GE", "1", envelope.groupControlNumber], elementSeparator, segmentTerminator);
9370
+ const se = joinSeg(
9371
+ ["SE", String(seCount), esc(stControlNumber)],
9372
+ elementSeparator,
9373
+ segmentTerminator
9374
+ );
9375
+ const ge = joinSeg(
9376
+ ["GE", "1", esc(envelope.groupControlNumber)],
9377
+ elementSeparator,
9378
+ segmentTerminator
9379
+ );
9122
9380
  const iea = joinSeg(["IEA", "1", interchangeControlNumber], elementSeparator, segmentTerminator);
9123
9381
  const raw = isa + gs + bodySegments.join("") + se + ge + iea;
9124
9382
  return parseX12(raw);
@@ -9240,7 +9498,7 @@ function buildIk4(elemError, esc, componentSeparator, elementSeparator, segmentT
9240
9498
  return joinSeg(parts, elementSeparator, segmentTerminator);
9241
9499
  }
9242
9500
  function buildIk5(response, esc, elementSeparator, segmentTerminator) {
9243
- const parts = ["IK5", response.disposition];
9501
+ const parts = ["IK5", esc(response.disposition)];
9244
9502
  const codes = response.syntaxErrorCodes ?? [];
9245
9503
  if (codes.length > 5) {
9246
9504
  throw new AckBuildError(
@@ -9254,7 +9512,7 @@ function buildIk5(response, esc, elementSeparator, segmentTerminator) {
9254
9512
  function buildAk9(group, esc, elementSeparator, segmentTerminator) {
9255
9513
  const parts = [
9256
9514
  "AK9",
9257
- group.disposition,
9515
+ esc(group.disposition),
9258
9516
  String(group.numberOfTransactionSets),
9259
9517
  String(group.numberOfReceivedTransactionSets),
9260
9518
  String(group.numberOfAcceptedTransactionSets)
@@ -9270,6 +9528,7 @@ function buildAk9(group, esc, elementSeparator, segmentTerminator) {
9270
9528
  return joinSeg(parts, elementSeparator, segmentTerminator);
9271
9529
  }
9272
9530
  function joinSeg(parts, elementSeparator, segmentTerminator) {
9531
+ requireCallerSegment(parts, "build999", refuseSpec8);
9273
9532
  return parts.join(elementSeparator) + segmentTerminator;
9274
9533
  }
9275
9534
  function pad8(value, width) {
@@ -9624,6 +9883,7 @@ function buildTransaction(tx, esc, elementSeparator, segmentTerminator) {
9624
9883
  return st + bodySegments + se;
9625
9884
  }
9626
9885
  function joinSeg2(parts, elementSeparator, segmentTerminator) {
9886
+ requireCallerSegment(parts, "buildInterchange", refuseSpec9);
9627
9887
  return parts.join(elementSeparator) + segmentTerminator;
9628
9888
  }
9629
9889
  function pad9(value, width) {
@@ -9932,7 +10192,7 @@ var profiles = Object.freeze({
9932
10192
  });
9933
10193
 
9934
10194
  // src/index.ts
9935
- var VERSION = "0.0.9";
10195
+ var VERSION = "0.0.11";
9936
10196
 
9937
10197
  exports.ACK_BUILD_ERROR_CODES = ACK_BUILD_ERROR_CODES;
9938
10198
  exports.ALL_WARNING_MESSAGES = ALL_WARNING_MESSAGES;
@@ -10069,6 +10329,7 @@ exports.elementDecimal = elementDecimal;
10069
10329
  exports.elementDecimalOrZero = elementDecimalOrZero;
10070
10330
  exports.elementOptional = elementOptional;
10071
10331
  exports.elementValue = elementValue;
10332
+ exports.entitySegmentDiscardedAfterLx = entitySegmentDiscardedAfterLx;
10072
10333
  exports.escapeRelease = escapeRelease;
10073
10334
  exports.get271Eligibility = get271Eligibility;
10074
10335
  exports.get277CADisposition = get277CADisposition;
@@ -10107,11 +10368,15 @@ exports.parseX12 = parseX12;
10107
10368
  exports.partitionWarnings = partitionWarnings;
10108
10369
  exports.pre005010 = pre005010;
10109
10370
  exports.profiles = profiles;
10371
+ exports.readElementDecimal = readElementDecimal;
10110
10372
  exports.remitBalanceMismatch = remitBalanceMismatch;
10111
10373
  exports.renderCallerValue = renderCallerValue;
10112
10374
  exports.resolveHiQualifier = resolveHiQualifier;
10113
10375
  exports.segmentCountMismatch = segmentCountMismatch;
10114
10376
  exports.serializeX12 = serializeX12;
10377
+ exports.serviceLineDropped = serviceLineDropped;
10378
+ exports.serviceLineNotDecoded = serviceLineNotDecoded;
10379
+ exports.serviceSegmentWithoutLx = serviceSegmentWithoutLx;
10115
10380
  exports.setDefaultProfile = setDefaultProfile;
10116
10381
  exports.trailingGarbage = trailingGarbage;
10117
10382
  exports.transactionCountMismatch = transactionCountMismatch;
@@ -10124,5 +10389,6 @@ exports.unknownClaimStatusCategory = unknownClaimStatusCategory;
10124
10389
  exports.unknownHiQualifier = unknownHiQualifier;
10125
10390
  exports.unknownMaintenanceType = unknownMaintenanceType;
10126
10391
  exports.unknownRarc = unknownRarc;
10392
+ exports.unparseableDecimal = unparseableDecimal;
10127
10393
  //# sourceMappingURL=index.cjs.map
10128
10394
  //# sourceMappingURL=index.cjs.map