@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.
- package/README.md +46 -92
- package/package.json +11 -7
package/README.md
CHANGED
|
@@ -1,153 +1,107 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @glion/parser
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`unified`-compatible parser that converts HL7v2 text into a structured AST.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## What it does
|
|
6
6
|
|
|
7
|
-
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
```typescript
|
|
17
|
+
```ts
|
|
32
18
|
import { unified } from "unified";
|
|
33
19
|
import { hl7v2Parser } from "@glion/parser";
|
|
34
20
|
|
|
35
|
-
const message =
|
|
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
|
-
|
|
28
|
+
## API
|
|
29
|
+
|
|
30
|
+
### `unified().use(hl7v2Parser[, options])`
|
|
43
31
|
|
|
44
|
-
|
|
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
|
-
|
|
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
|
-
|
|
62
|
+
Options accept a partial `Delimiters` object, so only the characters you want to override need to be provided.
|
|
72
63
|
|
|
73
|
-
|
|
74
|
-
- `component`: `^`
|
|
75
|
-
- `repetition`: `~`
|
|
76
|
-
- `subcomponent`: `&`
|
|
77
|
-
- `escape`: `\`
|
|
78
|
-
- `segment`: `\r`
|
|
64
|
+
## Parsing model
|
|
79
65
|
|
|
80
|
-
|
|
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
|
-
|
|
71
|
+
### Experimental: empty-array mode
|
|
83
72
|
|
|
84
|
-
|
|
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
|
-
|
|
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
|
|
102
|
-
//
|
|
83
|
+
// PID-2 (empty field) becomes: { type: "field", children: [] }
|
|
84
|
+
// rather than: Field → Rep → Comp → Sub with value: ""
|
|
103
85
|
```
|
|
104
86
|
|
|
105
|
-
|
|
87
|
+
Rules:
|
|
106
88
|
|
|
107
|
-
- **Leaf nodes** (Subcomponent
|
|
108
|
-
- **Parent nodes** (Field
|
|
109
|
-
- **Presence vs
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
102
|
+
## Part of Glion
|
|
148
103
|
|
|
149
|
-
|
|
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
|
-
[
|
|
152
|
-
[
|
|
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.
|
|
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.
|
|
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.
|
|
48
|
-
"@glion/
|
|
49
|
-
"@glion/
|
|
50
|
-
"@glion/
|
|
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
|
}
|