@cosyte/x12 0.0.18 → 0.1.0

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/CHANGELOG.md CHANGED
@@ -7,8 +7,49 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ **What 0.1 means for you.** This release is the first whose public API we treat as settled: the
11
+ exported readers, builders, types and warning codes are the surface we keep stable, and the warning
12
+ registry only ever gains codes. It covers typed read and typed emit for 270, 271, 276, 277 and
13
+ 277CA, 278 request and response, 820, 834, 835, 837P, 837I and 837D, 999 and TA1, plus the 277
14
+ request for additional information (`006020X313`) and the 275 that answers it (`006020X314`) at the
15
+ base 006020 structure; every amount as an exact `X12Decimal`; and a lenient parser whose only fatal
16
+ failures are the four structural ones. While the package is below 1.0, a breaking change bumps the
17
+ minor version and is called out here with its migration; a fix that changes no public value ships
18
+ as a patch. Upgrading from 0.0.x is itself breaking in five places, each described in the entries
19
+ below: `CodeListMeta`, `X12Eligibility` and `X12ProfileDescription` gain a required member,
20
+ `X12ClaimStatusResponse` gains a third `transactionType`, and `build278Response` declares
21
+ `005010X217`. Not covered yet: a byte-exact round trip in general (`KNOWN-LIMITATIONS.md` lists the
22
+ cases), implementation-guide usage checks and attachment decoding for the two 006020 guides,
23
+ non-healthcare sets, EDIFACT, transport, revisions before 005010, and any bundled CORE Code
24
+ Combinations table.
25
+
10
26
  ### Added
11
27
 
28
+ - **`toObject`, `toISO` and `toDate`: one date conversion surface, shared with every `@cosyte/*`
29
+ parser.** Three new package-root exports read a date off any typed reader, plus `DateParts`,
30
+ `ToDateOptions` and `X12DateValue`. Purely additive: no exported name is removed, renamed or
31
+ altered, `parseDocumentDate` keeps its own contract including its throwing one, no parse and no
32
+ emit behaviour moves, and there is still not a single runtime dependency.
33
+
34
+ The parameter is structural, so all eight `X12*Date` types are accepted through the same three
35
+ names with no per-transaction variant. What is decoded is exactly what this package already parses
36
+ or builds and nothing more: `D8`, a single `CCYYMMDD` day, and `RD8`, a `CCYYMMDD-CCYYMMDD` range.
37
+ `D8` converts to `{ year, month, day }` with `month` spec-native 1 to 12. Everything else answers
38
+ `undefined` and nothing ever throws: a qualifier outside that pair, an absent one (which is how
39
+ `X12PremiumDate` and `X12EnrollmentDate` reach this surface, since neither surfaces DTP-02 or
40
+ DTM-03 at all), a value whose digits do not match the shape its qualifier declares, and a day that
41
+ is not on the calendar.
42
+
43
+ **`RD8` converts to `undefined` from all three, deliberately.** An interval is not a point in
44
+ time; returning the first endpoint would be a quiet wrong answer with a right-looking shape.
45
+ **`toDate` returns an instant only when the caller states the zone**, through
46
+ `assumeOffsetMinutes`: no X12 date element decoded here carries a UTC offset, the host machine's
47
+ timezone is never read, and UTC is never assumed. A four-digit year below 100 stays that year.
48
+
49
+ Held by `test/conversion-surface.test.ts`, the same eleven-row case table every sibling parser
50
+ carries, five of whose rows are recorded as skips with a written reason and a live test measuring
51
+ the property behind each.
52
+
12
53
  - **`pnpm check:no-internal-refs` - a gate on internal project bookkeeping reaching a consumer**
13
54
  (`X12-NO-INTERNAL-REFS-GATE`), with `.github/workflows/no-internal-refs.yml` running it on every
14
55
  push and PR. Documentation and tooling only: the `src/` half of the diff is comment-only and
@@ -48,6 +89,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
48
89
 
49
90
  ### Changed
50
91
 
92
+ - **`build278Response` declares `005010X217` in GS-08 and ST-03, where it declared `005010X216`.**
93
+ This changes what goes on the wire: a trading partner that routed a built 278 response on either
94
+ element sees the new value. `005010X217` is the one guide 45 CFR 162.920 names for the 278 in both
95
+ directions and the one `build278Request` already wrote; `005010X216` is the 278 notification
96
+ guide, so a receiver routing on it could file a prior authorization decision as an admission or
97
+ discharge notification. Only those two identifiers move: the 278 body is unchanged, and so is the
98
+ read side, where a 278 declaring `005010X216` still carries `X12_GUIDE_NOT_IMPLEMENTED` on both
99
+ 278 readers. The builder's own output now reads back through `get278Response` with no
100
+ guide-mismatch warning, and the 278 response row of `X12_TR3_CONFORMANCE` records no divergence:
101
+ its `note` is `null`, like the request row's.
102
+
51
103
  - **`WARNING_MESSAGES.X12_PRE_005010` stops asserting what ISA-12 declares.** The message a consumer
52
104
  reads off `w.message` said _"ISA-12 declares a version other than the HIPAA baseline `00501`, so
53
105
  the input may diverge from 005010 semantics. The declared version is preserved verbatim on the
@@ -340,6 +392,46 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
340
392
 
341
393
  ### Fixed
342
394
 
395
+ - **🩺 A BDS or BIN segment's binary data is framed by the octet count its length element declares,
396
+ not by delimiters.** A BDS-03 or BIN-02 carrying the segment terminator used to end the segment
397
+ inside the data, and one carrying the element or component separator was split, so an attachment
398
+ came back in fragments and every segment after it was mis-framed. The data element now holds
399
+ exactly the declared octets whatever bytes they are, `getSegmentValue` / `getAllSegmentValues` /
400
+ `elementValue` return it verbatim, and `serializeX12` writes the segment back unchanged in both
401
+ modes. Four warning codes are added, additions only, each value-free and anchored at the segment:
402
+ **`X12_BINARY_DATA_TRUNCATED`**, **`X12_BINARY_LENGTH_INVALID`** (no length is inferred; the
403
+ segment is framed by its delimiters), **`X12_BINARY_LENGTH_MISMATCH`** (the data is the declared
404
+ span and the bytes after it stay on `raw`) and **`X12_BINARY_LENGTH_UNVERIFIABLE`** (a string span
405
+ holding a character above U+00FF; a `Buffer` never raises it). The length element is never
406
+ rewritten, and BDS-01's filter is not applied.
407
+
408
+ - **🩺 Every typed reader now checks the guide a transaction set declares, and warns when it is not
409
+ one that reader implements** (`X12-17`). Each reader used to admit a transaction set on ST-01
410
+ alone, so a 277 declaring `006020X313` (a claim request for additional information) came back
411
+ from `get277Status` labelled `claim-status`, and a 004010, 006020 or 008020 document of any type
412
+ was decoded against 005010 positions with nothing on the warning channel.
413
+
414
+ Two warning codes are added, additions only: **`X12_GUIDE_NOT_IMPLEMENTED`** where the declared
415
+ guide is outside the reader's set, and **`X12_GUIDE_NOT_DECLARED`** where nothing is declared.
416
+ Both are anchored at the ST, both messages are frozen literals that echo nothing, and their
417
+ factories `guideNotImplemented` / `guideNotDeclared` take a position only. The declaration is
418
+ ST-03, decoded of release escapes; **where ST-03 is absent or empty, GS-08 of the enclosing group,
419
+ decoded the same way**, which a parsed `X12TransactionSet` now carries on an optional `gs` member so
420
+ every reader keeps its `(delimiters, tx)` call. Where ST-03 is non-empty it alone decides, and a
421
+ disagreement with GS-08 is not reconciled. The implemented set is derived from
422
+ `X12_TR3_CONFORMANCE` (`tr3` plus `cfrAdopted` per row), plus every identifier the 837 variant
423
+ table resolves. The reading is still decoded and returned; nothing is refused, dropped or
424
+ re-decoded, and a document declaring an implemented guide reads exactly as before.
425
+
426
+ **Three things move for a consumer.** `X12ClaimStatusResponse.transactionType` widens to
427
+ `"claim-status" | "claim-acknowledgment" | "unrecognized-guide"`, the third set where
428
+ `get277Status`'s declared guide is outside its set or absent, **so an exhaustive `switch` over the
429
+ old two values stops compiling**; `get277CADisposition` admits what it admitted before. **A 278
430
+ declaring `005010X216` now warns on both 278 readers**, since the regulation names `005010X217` for
431
+ both directions, and `build278Response` still writes `005010X216`, so its round trip carries the
432
+ code until that builder moves. A 999 declaring the base `005010X231` warns too, because the
433
+ conformance row names only the errata.
434
+
343
435
  - **🩺 `implementationConventionReference` is POST-`?`-unescape in every typed reader that publishes
344
436
  it** (`X12-ST03-READ-NOT-RELEASE-AWARE`). A behaviour change on any document whose `ST-03` carries
345
437
  a release escape.
@@ -3533,10 +3625,14 @@ EV/SS`), and HL-04 has-child flag from the nested input tree, so an
3533
3625
  result types. Six synthetic fixtures + unit tests + byte-flip fuzz
3534
3626
  (never-throw outside the 4 Tier-3 fatals) across every Phase 6
3535
3627
  fixture.
3536
- - **Known limitations (deferred):** AAA request-validation segments,
3537
- HSD detail, and III / LS / LE markers in the 271, plus QTY / AMT
3538
- claim-summary roll-ups in a 277CA Loop 2200, are preserved on
3539
- `tx.segments` verbatim but not yet typed onto the model.
3628
+ - **Known limitations recorded for this release:** AAA
3629
+ request-validation segments, HSD detail, and III / LS / LE markers in
3630
+ the 271, plus QTY / AMT claim-summary roll-ups in a 277CA Loop 2200,
3631
+ are preserved on `tx.segments` verbatim, and this release carried
3632
+ none of them onto the typed model. The 271 AAA half of that list is
3633
+ CLOSED by a later release, which surfaces every AAA
3634
+ request-validation segment on `X12Eligibility.aaaConditions` with its
3635
+ level and both codes; the rest of the list stands.
3540
3636
  - **Phase 5: 837 Healthcare Claim, TR3s `005010X222A2` (Professional),
3541
3637
  `005010X223A3` (Institutional), `005010X224A2` (Dental).** The
3542
3638
  claim-creation surface: the volume side of HIPAA EDI traffic.