@glion/parser 0.15.1 → 0.15.2

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.
Files changed (2) hide show
  1. package/README.md +46 -92
  2. package/package.json +11 -7
package/README.md CHANGED
@@ -1,153 +1,107 @@
1
- # HL7v2 Parser
1
+ # @glion/parser
2
2
 
3
- This package is a utility that takes a raw HL7v2 message as input and turns it into an HL7v2 syntax tree following the [@glion/ast](../hl7v2-ast/README.md) definition.
3
+ `unified`-compatible parser that converts HL7v2 text into a structured AST.
4
4
 
5
- This utility is a low level project. It’s used in [@glion/hl7v2](../hl7v2/), which focusses on making it easier to transform content by abstracting these internals away.
5
+ ## What it does
6
6
 
7
- ## When should I use this?
8
-
9
- If you want to handle syntax trees manually, use this. For an easier time processing content, use the [@glion/hl7v2](../hl7v2/) ecosystem instead.
10
-
11
- ## Features
12
-
13
- - **Speed-first**: pull-based tokenizer, single pass, minimal object allocations.
14
- - **Spec-aware**: auto-detects delimiters from MSH-1 and MSH-2.
15
- - **AST design**: outputs a unist-compatible tree for use in the HL7v2 unified ecosystem.
16
- - **Composable**: works directly as a unified parser plugin or as a standalone function.
17
- - **Streaming-friendly**: pull-based design is ready for streaming use cases.
7
+ `@glion/parser` is a low-level parser that turns raw HL7v2 messages into a `unist`-compatible syntax tree following the [`@glion/ast`](../ast/) spec. It runs as a `unified` parser plugin — feeding its output into any downstream `unified` processor — and auto-detects delimiters from MSH-1 and MSH-2 so non-standard delimiter sets work without configuration. Most applications should use [`@glion/hl7v2`](../hl7v2/), which bundles this parser with the standard transform and compile stages; reach for `@glion/parser` when you are building a custom pipeline.
18
8
 
19
9
  ## Install
20
10
 
21
- This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c). In Node.js (version 16+), install with npm:
22
-
23
11
  ```bash
24
12
  npm install @glion/parser
25
13
  ```
26
14
 
27
15
  ## Use
28
16
 
29
- ### Basic Usage
30
-
31
- ```typescript
17
+ ```ts
32
18
  import { unified } from "unified";
33
19
  import { hl7v2Parser } from "@glion/parser";
34
20
 
35
- const message = `MSH|^~\\&|SENDING_APP|SENDING_FAC|...`;
21
+ const message = "MSH|^~\\&|SENDING_APP|SENDING_FAC|...\rPID|1||12345";
36
22
 
37
23
  const tree = unified().use(hl7v2Parser).parse(message);
38
24
 
39
25
  console.log(tree);
40
26
  ```
41
27
 
42
- ### Custom Delimiters
28
+ ## API
29
+
30
+ ### `unified().use(hl7v2Parser[, options])`
43
31
 
44
- You can specify custom delimiters for parsing non-standard HL7v2 messages. The `delimiters` option accepts a partial object, so you only need to specify the delimiters you want to override:
32
+ Register the parser as the reader for a `unified` processor. The parser reads from the input string and produces a `Root` AST; it never mutates its input.
45
33
 
46
- ```typescript
34
+ ### Options
35
+
36
+ | Option | Type | Description |
37
+ | ------------------------ | --------------------- | ---------------------------------------------------------------------------------------- |
38
+ | `delimiters` | `Partial<Delimiters>` | Override one or more delimiters. The parser merges with MSH-derived values and defaults. |
39
+ | `experimental.emptyMode` | `"empty-array"` | Opt in to the empty-array representation of empty fields (see below). |
40
+
41
+ The default delimiters are `|` (field), `^` (component), `~` (repetition), `&` (subcomponent), `\` (escape), and `\r` (segment).
42
+
43
+ ### Custom delimiters
44
+
45
+ ```ts
47
46
  import { unified } from "unified";
48
47
  import { hl7v2Parser } from "@glion/parser";
49
48
 
50
49
  // Override only the segment delimiter
51
50
  const tree = unified()
52
- .use(hl7v2Parser, {
53
- delimiters: {
54
- segment: "\n", // Use newline instead of carriage return
55
- },
56
- })
51
+ .use(hl7v2Parser, { delimiters: { segment: "\n" } })
57
52
  .parse(message);
58
53
 
59
54
  // Override multiple delimiters
60
55
  const customTree = unified()
61
56
  .use(hl7v2Parser, {
62
- delimiters: {
63
- field: "$",
64
- component: "%",
65
- segment: "\n",
66
- },
57
+ delimiters: { field: "$", component: "%", segment: "\n" },
67
58
  })
68
59
  .parse(customMessage);
69
60
  ```
70
61
 
71
- The default delimiters are:
62
+ Options accept a partial `Delimiters` object, so only the characters you want to override need to be provided.
72
63
 
73
- - `field`: `|`
74
- - `component`: `^`
75
- - `repetition`: `~`
76
- - `subcomponent`: `&`
77
- - `escape`: `\`
78
- - `segment`: `\r`
64
+ ## Parsing model
79
65
 
80
- ### Experimental Features
66
+ - **Pull-based tokenizer.** Single pass, minimal object allocations — suitable for high-throughput ingestion.
67
+ - **Delimiter auto-detection.** MSH-1 and MSH-2 are read before the rest of the message is tokenized so custom delimiter sets are honored without configuration.
68
+ - **`unist`-compatible output.** Nodes follow the `@glion/ast` spec and integrate with `unist-util-visit`, `unist-builder`, and the wider Glion plugin ecosystem.
69
+ - **Streaming-friendly.** The pull-based design is ready for streaming ingestion even though the current public API takes a complete string.
81
70
 
82
- The parser supports experimental features through the `experimental` option. These features are subject to change but provide opt-in access to upcoming behaviors.
71
+ ### Experimental: empty-array mode
83
72
 
84
- #### Empty Array Mode
73
+ By default the parser represents empty fields with full scaffolding (`Field → FieldRepetition → Component → Subcomponent` with `value: ""`). Passing `experimental: { emptyMode: "empty-array" }` switches to a more compact representation where empty parents carry `children: []` instead of nested empties.
85
74
 
86
- By default, the parser represents empty fields with full scaffolding (Field → FieldRepetition → Component → Subcomponent with `value: ""`). The `emptyMode: 'empty'` option changes this behavior to use empty children arrays instead, making the AST more compact and easier to work with.
87
-
88
- ```typescript
75
+ ```ts
89
76
  import { unified } from "unified";
90
77
  import { hl7v2Parser } from "@glion/parser";
91
78
 
92
- // With empty-array mode (new behavior)
93
79
  const tree = unified()
94
- .use(hl7v2Parser, {
95
- experimental: {
96
- emptyMode: "empty-array",
97
- },
98
- })
80
+ .use(hl7v2Parser, { experimental: { emptyMode: "empty-array" } })
99
81
  .parse("PID|1||");
100
82
 
101
- // PID.2 (empty field) will have: { type: 'field', children: [] }
102
- // Instead of: Field → Rep → Comp → Sub with value: ""
83
+ // PID-2 (empty field) becomes: { type: "field", children: [] }
84
+ // rather than: Field → Rep → Comp → Sub with value: ""
103
85
  ```
104
86
 
105
- **Spec Rules:**
87
+ Rules:
106
88
 
107
- - **Leaf nodes** (Subcomponent, SegmentHeader) with no value: `value: ""`
108
- - **Parent nodes** (Field, FieldRepetition, Component) with no content: `children: []`
109
- - **Presence vs Value**:
110
- - Node exists in parent's children array = position exists
111
- - Node has empty children array = no value at that position
89
+ - **Leaf nodes** (`Subcomponent`, `SegmentHeader`) with no value carry `value: ""`.
90
+ - **Parent nodes** (`Field`, `FieldRepetition`, `Component`) with no content carry `children: []`.
91
+ - **Presence vs value:** a node in the parent's `children` array means the position exists; empty `children` means the position has no value.
112
92
 
113
- **Examples:**
114
-
115
- | Wire Format | Legacy Mode | Empty-Array Mode |
93
+ | Wire format | Legacy mode | Empty-array mode |
116
94
  | --------------- | ---------------------------------------------- | -------------------------------------- |
117
95
  | `PID\|1\|\|` | Field → Rep → Comp → Sub("") | Field(children: []) |
118
96
  | `PID\|1\|^\|` | Field → Rep → [Comp → Sub(""), Comp → Sub("")] | Field → Rep → [Comp[], Comp[]] |
119
97
  | `PID\|1\|~\|` | Field → [Rep → Comp → Sub(""), Rep → ...] | Field → [Rep[], Rep[]] |
120
98
  | `PID\|1\|ABC\|` | Field → Rep → Comp → Sub("ABC") | Field → Rep → Comp → Sub("ABC") (same) |
121
99
 
122
- **Benefits:**
123
-
124
- - 37-63% reduction in node count for messages with empty fields
125
- - ~11% performance improvement for sparse messages
126
- - Cleaner AST structure for visitor patterns and transformations
127
- - Easier to distinguish "field exists but is empty" from "field has content"
128
-
129
- **Note:** This feature will become the default behavior in future versions. The legacy mode will be deprecated.
130
-
131
- ## Contributing
132
-
133
- We welcome contributions! Please see our [Contributing Guide][github-contributing] for more details.
134
-
135
- 1. Fork the repository
136
- 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
137
- 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
138
- 4. Push to the branch (`git push origin feature/amazing-feature`)
139
- 5. Open a Pull Request
140
-
141
- ## Code of Conduct
142
-
143
- To ensure a welcoming and positive environment, we have a [Code of Conduct][github-code-of-conduct] that all contributors and participants are expected to adhere to.
144
-
145
- ## License
100
+ For messages with many empty fields, the empty-array representation reduces node count by 37–63% and improves sparse-message parsing throughput by about 11%. Empty-array mode is planned to become the default; the legacy representation will be retired.
146
101
 
147
- Copyright 2025 Rethink Health, SUARL. All rights reserved.
102
+ ## Part of Glion
148
103
 
149
- This program is licensed to you under the terms of the [MIT License](https://opensource.org/licenses/MIT). This program is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the [LICENSE][github-license] file for details.
104
+ `@glion/parser` is part of **[Glion]**, the application framework for HL7v2. See the [Glion README] for the full package catalog and architecture.
150
105
 
151
- [github-code-of-conduct]: https://github.com/rethinkhealth/glion/blob/main/CODE_OF_CONDUCT.md
152
- [github-license]: https://github.com/rethinkhealth/glion/blob/main/LICENSE
153
- [github-contributing]: https://github.com/rethinkhealth/glion/blob/main/CONTRIBUTING.md
106
+ [Glion]: https://github.com/rethinkhealth/glion#readme
107
+ [Glion README]: https://github.com/rethinkhealth/glion#readme
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glion/parser",
3
- "version": "0.15.1",
3
+ "version": "0.15.2",
4
4
  "description": "hl7v2 plugin to parse hl7v2 messages",
5
5
  "keywords": [
6
6
  "health",
@@ -34,20 +34,22 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "unified": "11.0.5",
37
- "@glion/utils": "0.15.1"
37
+ "@glion/utils": "0.15.2"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/node": "^25.5.0",
41
41
  "@types/unist": "^3.0.3",
42
42
  "@vitest/coverage-v8": "4.1.2",
43
+ "publint": "0.3.18",
43
44
  "tsdown": "0.21.7",
44
45
  "typescript": "^5.9.3",
45
46
  "unist": "^0.0.1",
46
47
  "vitest": "4.1.2",
47
- "@glion/ast": "0.15.1",
48
- "@glion/config": "0.15.1",
49
- "@glion/tsconfig": "0.15.1",
50
- "@glion/testing": "0.15.1"
48
+ "@glion/ast": "0.15.2",
49
+ "@glion/check-readme": "0.15.2",
50
+ "@glion/testing": "0.15.2",
51
+ "@glion/tsconfig": "0.15.2",
52
+ "@glion/config": "0.15.2"
51
53
  },
52
54
  "engines": {
53
55
  "node": ">=18"
@@ -57,8 +59,10 @@
57
59
  "bench": "vitest bench --run",
58
60
  "build": "tsdown && tsc --emitDeclarationOnly",
59
61
  "check-types": "tsc --noEmit",
62
+ "check:readme": "glion-check-readme",
60
63
  "test": "vitest run",
61
64
  "test:coverage": "vitest run --coverage",
62
- "test:watch": "vitest"
65
+ "test:watch": "vitest",
66
+ "publint": "publint --strict"
63
67
  }
64
68
  }