@rethinkhealth/hl7v2-utils 0.3.4 → 0.4.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/README.md +79 -1
- package/dist/constants.d.ts +8 -0
- package/dist/constraints.d.ts +92 -0
- package/dist/index.d.ts +3 -48
- package/dist/index.js +183 -1
- package/dist/index.js.map +1 -1
- package/dist/utils.d.ts +40 -0
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
A utility package for working with HL7v2 messages, most commonly used within the `@rethinkhealth/hl7v2` ecosystem — a unist-inspired collection of plugins and utilities designed to parse, transform, validate, and manipulate HL7v2 messages.
|
|
4
4
|
|
|
5
5
|
This package provides core utilities including:
|
|
6
|
+
|
|
6
7
|
- Diagnostic reporting system for linters, validators, and transformers
|
|
7
8
|
- Standard HL7v2 delimiters
|
|
8
9
|
- AST node utility functions
|
|
10
|
+
- Conformance validation utilities (cardinality, length, optionality)
|
|
9
11
|
|
|
10
12
|
## Installation
|
|
11
13
|
|
|
@@ -183,6 +185,82 @@ getLength(subcomponent); // Returns: 4 (4 characters)
|
|
|
183
185
|
getByteLength(subcomponent); // Returns: 5 (5 bytes in UTF-8: c-a-f-C3-A9)
|
|
184
186
|
```
|
|
185
187
|
|
|
188
|
+
### Conformance Utilities
|
|
189
|
+
|
|
190
|
+
The package provides stateless, composable functions to validate HL7v2 AST nodes against constraints like optionality (usage), cardinality, and length.
|
|
191
|
+
|
|
192
|
+
#### `ValidationResult`
|
|
193
|
+
|
|
194
|
+
All conformance functions return a `ValidationResult` object:
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
type ValidationResult =
|
|
198
|
+
| { ok: true }
|
|
199
|
+
| {
|
|
200
|
+
ok: false;
|
|
201
|
+
error: {
|
|
202
|
+
code: string;
|
|
203
|
+
message: string;
|
|
204
|
+
expected?: string | number | Array<string | number>;
|
|
205
|
+
actual?: string | number | Array<string | number>;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
#### `checkOptionality(node, optionality)`
|
|
211
|
+
|
|
212
|
+
Checks if a node satisfies the optionality (usage) constraint.
|
|
213
|
+
|
|
214
|
+
- **node**: `Nodes | undefined` - The AST node to check.
|
|
215
|
+
- **optionality**: `string` - The usage code (e.g., 'R', 'O', 'X').
|
|
216
|
+
- **Returns**: `ValidationResult`
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
import { checkOptionality } from '@rethinkhealth/hl7v2-utils';
|
|
220
|
+
|
|
221
|
+
// 'R' (Required), 'RE' (Required or Empty), 'O' (Optional), 'X' (Not Supported)
|
|
222
|
+
const result = checkOptionality(myFieldNode, 'R');
|
|
223
|
+
|
|
224
|
+
if (!result.ok) {
|
|
225
|
+
console.error(result.error.message); // "is required but missing"
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
#### `checkCardinality(node, min, max)`
|
|
230
|
+
|
|
231
|
+
Checks if a field has the correct number of repetitions.
|
|
232
|
+
|
|
233
|
+
- **node**: `Field | undefined` - The field node to check.
|
|
234
|
+
- **min**: `number` - Minimum repetitions.
|
|
235
|
+
- **max**: `number | '*'` - Maximum repetitions.
|
|
236
|
+
- **Returns**: `ValidationResult`
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
import { checkCardinality } from '@rethinkhealth/hl7v2-utils';
|
|
240
|
+
|
|
241
|
+
// Field must repeat between 1 and 5 times
|
|
242
|
+
const result = checkCardinality(myFieldNode, 1, 5);
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
#### `checkLength(node, max, min?)`
|
|
246
|
+
|
|
247
|
+
Checks if the content of a node falls within the minimum and maximum length.
|
|
248
|
+
|
|
249
|
+
- **node**: `Nodes | undefined` - The node to check (length is calculated recursively).
|
|
250
|
+
- **max**: `number` - Maximum length.
|
|
251
|
+
- **min**: `number` (optional, default: 0) - Minimum length.
|
|
252
|
+
- **Returns**: `ValidationResult`
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
import { checkLength } from '@rethinkhealth/hl7v2-utils';
|
|
256
|
+
|
|
257
|
+
// Content length must be between 1 and 10 characters
|
|
258
|
+
const result = checkLength(myNode, 10, 1);
|
|
259
|
+
|
|
260
|
+
// Content length must be at most 10 characters (min defaults to 0)
|
|
261
|
+
const result2 = checkLength(myNode, 10);
|
|
262
|
+
```
|
|
263
|
+
|
|
186
264
|
## Contributing
|
|
187
265
|
|
|
188
266
|
We welcome contributions! Please see our [Contributing Guide][github-contributing] for more details.
|
|
@@ -205,4 +283,4 @@ This program is licensed to you under the terms of the [MIT License](https://ope
|
|
|
205
283
|
|
|
206
284
|
[github-code-of-conduct]: https://github.com/rethinkhealth/hl7v2/blob/main/CODE_OF_CONDUCT.md
|
|
207
285
|
[github-license]: https://github.com/rethinkhealth/hl7v2/blob/main/LICENSE
|
|
208
|
-
[github-contributing]: https://github.com/rethinkhealth/hl7v2/blob/main/CONTRIBUTING.md
|
|
286
|
+
[github-contributing]: https://github.com/rethinkhealth/hl7v2/blob/main/CONTRIBUTING.md
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { Field, Nodes } from "@rethinkhealth/hl7v2-ast";
|
|
2
|
+
export type ValidationErrorCode = "MISSING" | "EMPTY" | "UNEXPECTED_CONTENT" | "CARDINALITY_UNDERFLOW" | "CARDINALITY_OVERFLOW" | "LENGTH_UNDERFLOW" | "LENGTH_OVERFLOW" | "VALUE_NOT_IN_TABLE";
|
|
3
|
+
export type ValidationError = {
|
|
4
|
+
code: ValidationErrorCode;
|
|
5
|
+
message: string;
|
|
6
|
+
expected?: string | number | Array<string | number>;
|
|
7
|
+
actual?: string | number | Array<string | number>;
|
|
8
|
+
};
|
|
9
|
+
export type ValidationSuccess = {
|
|
10
|
+
ok: true;
|
|
11
|
+
};
|
|
12
|
+
export type ValidationFailure = {
|
|
13
|
+
ok: false;
|
|
14
|
+
error: ValidationError;
|
|
15
|
+
};
|
|
16
|
+
export type ValidationResult = ValidationSuccess | ValidationFailure;
|
|
17
|
+
export declare const OptionalityCode: {
|
|
18
|
+
readonly Required: "R";
|
|
19
|
+
/**
|
|
20
|
+
* Required, but may be empty.
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* The use of the RE usage code is qualified with the “if data is known”
|
|
24
|
+
* clause. The sender must interpret the clause as “the capability must always
|
|
25
|
+
* be supported, and data must always be sent if known”. To clarify, the
|
|
26
|
+
* sender does not determine whether the data should be sent; to be conformant
|
|
27
|
+
* to the rule, the data must be sent. There is a misconception where the RE
|
|
28
|
+
* usage is interpreted as “the capability must always be supported, and data
|
|
29
|
+
* may or may not be sent even when known based on a condition external to the
|
|
30
|
+
* profile specification”.
|
|
31
|
+
*
|
|
32
|
+
* The receiving application must process in a meaningful way the information
|
|
33
|
+
* conveyed by an element with an “RE” usage designation.
|
|
34
|
+
* The receiving application must process the message if the element is omitted
|
|
35
|
+
* (that is, an exception must not be raised because the element is missing). A
|
|
36
|
+
* receiving application must not raise an exception due to the presence of a
|
|
37
|
+
* required element.
|
|
38
|
+
*/
|
|
39
|
+
readonly RequiredOrEmpty: "RE";
|
|
40
|
+
/**
|
|
41
|
+
* Optional
|
|
42
|
+
*
|
|
43
|
+
* There are no implementation requirements. The “O” usage designation is a
|
|
44
|
+
* placeholder indicating that the usage for this element has not yet been
|
|
45
|
+
* specified.
|
|
46
|
+
*/
|
|
47
|
+
readonly Optional: "O";
|
|
48
|
+
/**
|
|
49
|
+
* Undeclared / Conditional.
|
|
50
|
+
*
|
|
51
|
+
* There are no implementation requirements. The “C” usage designation is a
|
|
52
|
+
* placeholder indicating that the usage for this element has not yet been
|
|
53
|
+
* specified.
|
|
54
|
+
*/
|
|
55
|
+
readonly Conditional: "C";
|
|
56
|
+
/**
|
|
57
|
+
* Not Supported.
|
|
58
|
+
*
|
|
59
|
+
* There are no implementation requirements. The application must not value an
|
|
60
|
+
* element with an “X” usage designation.
|
|
61
|
+
*/
|
|
62
|
+
readonly NotSupported: "X";
|
|
63
|
+
/**
|
|
64
|
+
* Backward Compatible
|
|
65
|
+
*
|
|
66
|
+
* There are no implementation requirements. The “B” usage indicates that the
|
|
67
|
+
* element is retained for backwards compatibility of the element. Another
|
|
68
|
+
* usage indicator may be assigned in a derived profile.
|
|
69
|
+
*/
|
|
70
|
+
readonly BackwardCompatible: "B";
|
|
71
|
+
/**
|
|
72
|
+
* Withdrawn
|
|
73
|
+
*
|
|
74
|
+
* The element has been withdrawn from the standard. There are no
|
|
75
|
+
* implementation requirements. The application must not value an element with
|
|
76
|
+
* a "W" usage designation.
|
|
77
|
+
*/
|
|
78
|
+
readonly Withdrawn: "W";
|
|
79
|
+
};
|
|
80
|
+
export type OptionalityCode = (typeof OptionalityCode)[keyof typeof OptionalityCode];
|
|
81
|
+
/**
|
|
82
|
+
* Checks if a field satisfies the cardinality constraint.
|
|
83
|
+
*/
|
|
84
|
+
export declare function checkCardinality(node: Field | undefined, min: number, max: number | "*"): ValidationResult;
|
|
85
|
+
/**
|
|
86
|
+
* Checks if a node satisfies the length constraint.
|
|
87
|
+
*/
|
|
88
|
+
export declare function checkLength(node: Nodes | undefined, max: number, min?: number): ValidationResult;
|
|
89
|
+
/**
|
|
90
|
+
* Checks if a node satisfies the optionality constraint.
|
|
91
|
+
*/
|
|
92
|
+
export declare function checkOptionality(node: Nodes | undefined, optionality: OptionalityCode | string): ValidationResult;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,48 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
component: string;
|
|
5
|
-
repetition: string;
|
|
6
|
-
subcomponent: string;
|
|
7
|
-
escape: string;
|
|
8
|
-
segment: string;
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* Utility: check if a node is semantically empty
|
|
12
|
-
*/
|
|
13
|
-
export declare function isEmptyNode(node: Nodes | null | undefined): boolean;
|
|
14
|
-
/**
|
|
15
|
-
* Calculate the byte length of any HL7v2 AST node.
|
|
16
|
-
*
|
|
17
|
-
* For literal nodes (Subcomponent, SegmentHeader), returns the UTF-8 byte length of the value.
|
|
18
|
-
* For parent nodes, recursively calculates the length of all children. Delimiters are NOT included.
|
|
19
|
-
*
|
|
20
|
-
* @param node - The HL7v2 AST node to measure
|
|
21
|
-
* @returns The total byte length of the node content
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```ts
|
|
25
|
-
* const field: Field = { type: "field", children: [...] };
|
|
26
|
-
* const length = getByteLength(field); // e.g., 42
|
|
27
|
-
* ```
|
|
28
|
-
*/
|
|
29
|
-
export declare function getByteLength(node: Nodes | null | undefined): number;
|
|
30
|
-
/**
|
|
31
|
-
* Calculate the string length of any HL7v2 AST node.
|
|
32
|
-
*
|
|
33
|
-
* For literal nodes (Subcomponent, SegmentHeader), returns `value.length`.
|
|
34
|
-
* For parent nodes, recursively calculates the length of all children. Delimiters are NOT included.
|
|
35
|
-
*
|
|
36
|
-
* Note: Returns JavaScript string length (UTF-16 code units). For UTF-8 byte
|
|
37
|
-
* length (e.g., for wire protocol), use `getByteLength` instead.
|
|
38
|
-
*
|
|
39
|
-
* @param node - The HL7v2 AST node to measure
|
|
40
|
-
* @returns The total string length of the node content
|
|
41
|
-
*
|
|
42
|
-
* @example
|
|
43
|
-
* ```ts
|
|
44
|
-
* const field: Field = { type: "field", children: [...] };
|
|
45
|
-
* const length = getLength(field); // e.g., 42
|
|
46
|
-
* ```
|
|
47
|
-
*/
|
|
48
|
-
export declare function getLength(node: Nodes | null | undefined): number;
|
|
1
|
+
export * from "./constants";
|
|
2
|
+
export * from "./constraints";
|
|
3
|
+
export * from "./utils";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/
|
|
1
|
+
// src/constants.ts
|
|
2
2
|
var DEFAULT_DELIMITERS = {
|
|
3
3
|
field: "|",
|
|
4
4
|
component: "^",
|
|
@@ -7,6 +7,8 @@ var DEFAULT_DELIMITERS = {
|
|
|
7
7
|
escape: "\\",
|
|
8
8
|
segment: "\r"
|
|
9
9
|
};
|
|
10
|
+
|
|
11
|
+
// src/utils.ts
|
|
10
12
|
function isEmptyNode(node) {
|
|
11
13
|
if (!node) {
|
|
12
14
|
return true;
|
|
@@ -46,8 +48,188 @@ function getLength(node) {
|
|
|
46
48
|
}
|
|
47
49
|
return node.children.reduce((total, child) => total + getLength(child), 0);
|
|
48
50
|
}
|
|
51
|
+
|
|
52
|
+
// src/constraints.ts
|
|
53
|
+
var OptionalityCode = {
|
|
54
|
+
Required: "R",
|
|
55
|
+
/**
|
|
56
|
+
* Required, but may be empty.
|
|
57
|
+
*
|
|
58
|
+
* @remarks
|
|
59
|
+
* The use of the RE usage code is qualified with the “if data is known”
|
|
60
|
+
* clause. The sender must interpret the clause as “the capability must always
|
|
61
|
+
* be supported, and data must always be sent if known”. To clarify, the
|
|
62
|
+
* sender does not determine whether the data should be sent; to be conformant
|
|
63
|
+
* to the rule, the data must be sent. There is a misconception where the RE
|
|
64
|
+
* usage is interpreted as “the capability must always be supported, and data
|
|
65
|
+
* may or may not be sent even when known based on a condition external to the
|
|
66
|
+
* profile specification”.
|
|
67
|
+
*
|
|
68
|
+
* The receiving application must process in a meaningful way the information
|
|
69
|
+
* conveyed by an element with an “RE” usage designation.
|
|
70
|
+
* The receiving application must process the message if the element is omitted
|
|
71
|
+
* (that is, an exception must not be raised because the element is missing). A
|
|
72
|
+
* receiving application must not raise an exception due to the presence of a
|
|
73
|
+
* required element.
|
|
74
|
+
*/
|
|
75
|
+
RequiredOrEmpty: "RE",
|
|
76
|
+
/**
|
|
77
|
+
* Optional
|
|
78
|
+
*
|
|
79
|
+
* There are no implementation requirements. The “O” usage designation is a
|
|
80
|
+
* placeholder indicating that the usage for this element has not yet been
|
|
81
|
+
* specified.
|
|
82
|
+
*/
|
|
83
|
+
Optional: "O",
|
|
84
|
+
/**
|
|
85
|
+
* Undeclared / Conditional.
|
|
86
|
+
*
|
|
87
|
+
* There are no implementation requirements. The “C” usage designation is a
|
|
88
|
+
* placeholder indicating that the usage for this element has not yet been
|
|
89
|
+
* specified.
|
|
90
|
+
*/
|
|
91
|
+
Conditional: "C",
|
|
92
|
+
/**
|
|
93
|
+
* Not Supported.
|
|
94
|
+
*
|
|
95
|
+
* There are no implementation requirements. The application must not value an
|
|
96
|
+
* element with an “X” usage designation.
|
|
97
|
+
*/
|
|
98
|
+
NotSupported: "X",
|
|
99
|
+
/**
|
|
100
|
+
* Backward Compatible
|
|
101
|
+
*
|
|
102
|
+
* There are no implementation requirements. The “B” usage indicates that the
|
|
103
|
+
* element is retained for backwards compatibility of the element. Another
|
|
104
|
+
* usage indicator may be assigned in a derived profile.
|
|
105
|
+
*/
|
|
106
|
+
BackwardCompatible: "B",
|
|
107
|
+
/**
|
|
108
|
+
* Withdrawn
|
|
109
|
+
*
|
|
110
|
+
* The element has been withdrawn from the standard. There are no
|
|
111
|
+
* implementation requirements. The application must not value an element with
|
|
112
|
+
* a "W" usage designation.
|
|
113
|
+
*/
|
|
114
|
+
Withdrawn: "W"
|
|
115
|
+
};
|
|
116
|
+
function checkCardinality(node, min, max) {
|
|
117
|
+
if (min < 0 || max !== "*" && max < 0) {
|
|
118
|
+
throw new Error("Min and max lengths must be non-negative");
|
|
119
|
+
}
|
|
120
|
+
if (max !== "*" && min > max) {
|
|
121
|
+
throw new Error("Min length cannot be greater than max length");
|
|
122
|
+
}
|
|
123
|
+
const count = node?.children ? node.children.length : 0;
|
|
124
|
+
if (count < min) {
|
|
125
|
+
return {
|
|
126
|
+
ok: false,
|
|
127
|
+
error: {
|
|
128
|
+
code: "CARDINALITY_UNDERFLOW",
|
|
129
|
+
message: `has ${count} repetitions but requires at least ${min}`,
|
|
130
|
+
expected: min,
|
|
131
|
+
actual: count
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
if (max !== "*" && count > max) {
|
|
136
|
+
return {
|
|
137
|
+
ok: false,
|
|
138
|
+
error: {
|
|
139
|
+
code: "CARDINALITY_OVERFLOW",
|
|
140
|
+
message: `has ${count} repetitions but allows at most ${max}`,
|
|
141
|
+
expected: max,
|
|
142
|
+
actual: count
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return { ok: true };
|
|
147
|
+
}
|
|
148
|
+
function checkLength(node, max, min = 0) {
|
|
149
|
+
if (min < 0 || max < 0) {
|
|
150
|
+
throw new Error("Min and max lengths must be non-negative");
|
|
151
|
+
}
|
|
152
|
+
if (min > max) {
|
|
153
|
+
throw new Error("Min length cannot be greater than max length");
|
|
154
|
+
}
|
|
155
|
+
const length = getLength(node);
|
|
156
|
+
if (length < min) {
|
|
157
|
+
return {
|
|
158
|
+
ok: false,
|
|
159
|
+
error: {
|
|
160
|
+
code: "LENGTH_UNDERFLOW",
|
|
161
|
+
message: `has length ${length} but requires at least ${min}`,
|
|
162
|
+
expected: min,
|
|
163
|
+
actual: length
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
if (length > max) {
|
|
168
|
+
return {
|
|
169
|
+
ok: false,
|
|
170
|
+
error: {
|
|
171
|
+
code: "LENGTH_OVERFLOW",
|
|
172
|
+
message: `has length ${length} but allows at most ${max}`,
|
|
173
|
+
expected: max,
|
|
174
|
+
actual: length
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
return { ok: true };
|
|
179
|
+
}
|
|
180
|
+
function checkOptionality(node, optionality) {
|
|
181
|
+
const code = optionality.toUpperCase();
|
|
182
|
+
switch (code) {
|
|
183
|
+
case OptionalityCode.Required:
|
|
184
|
+
if (!node) {
|
|
185
|
+
return {
|
|
186
|
+
ok: false,
|
|
187
|
+
error: {
|
|
188
|
+
code: "MISSING",
|
|
189
|
+
message: "is required but missing",
|
|
190
|
+
expected: "R"
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
if (isEmptyNode(node)) {
|
|
195
|
+
return {
|
|
196
|
+
ok: false,
|
|
197
|
+
error: {
|
|
198
|
+
code: "EMPTY",
|
|
199
|
+
message: "is required but empty",
|
|
200
|
+
expected: "R"
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
return { ok: true };
|
|
205
|
+
case OptionalityCode.NotSupported:
|
|
206
|
+
if (node && !isEmptyNode(node)) {
|
|
207
|
+
return {
|
|
208
|
+
ok: false,
|
|
209
|
+
error: {
|
|
210
|
+
code: "UNEXPECTED_CONTENT",
|
|
211
|
+
message: "is not supported but present",
|
|
212
|
+
expected: "X"
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
return { ok: true };
|
|
217
|
+
case OptionalityCode.RequiredOrEmpty:
|
|
218
|
+
case OptionalityCode.Optional:
|
|
219
|
+
case OptionalityCode.Conditional:
|
|
220
|
+
case OptionalityCode.BackwardCompatible:
|
|
221
|
+
case OptionalityCode.Withdrawn:
|
|
222
|
+
return { ok: true };
|
|
223
|
+
default:
|
|
224
|
+
return { ok: true };
|
|
225
|
+
}
|
|
226
|
+
}
|
|
49
227
|
export {
|
|
50
228
|
DEFAULT_DELIMITERS,
|
|
229
|
+
OptionalityCode,
|
|
230
|
+
checkCardinality,
|
|
231
|
+
checkLength,
|
|
232
|
+
checkOptionality,
|
|
51
233
|
getByteLength,
|
|
52
234
|
getLength,
|
|
53
235
|
isEmptyNode
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Nodes } from \"@rethinkhealth/hl7v2-ast\";\n\n// -------------\n// Delimiters\n// -------------\n\nexport const DEFAULT_DELIMITERS = {\n field: \"|\",\n component: \"^\",\n repetition: \"~\",\n subcomponent: \"&\",\n escape: \"\\\\\",\n segment: \"\\r\",\n};\n\n// -------------\n// General\n// -------------\n\n/**\n * Utility: check if a node is semantically empty\n */\nexport function isEmptyNode(node: Nodes | null | undefined): boolean {\n if (!node) {\n return true;\n }\n\n // If node has a \"value\" property (Subcomponent, maybe Component)\n if (\"value\" in node) {\n return !node.value || node.value.trim() === \"\";\n }\n\n // If node has children (Field, Component, Repetition, Segment, Root, etc.)\n if (\"children\" in node) {\n if (!node.children || node.children.length === 0) {\n return true;\n }\n\n // If node has more than one child, then it is considered non-empty\n if (node.children.length > 1) {\n return false;\n }\n\n // If node has only one child, then it is considered empty if the child is also empty\n return isEmptyNode(node.children[0]);\n }\n\n // Fallback: consider unknown node as non-empty\n return false;\n}\n\n// -------------\n// Byte Length\n// -------------\n\n/**\n * Calculate the byte length of any HL7v2 AST node.\n *\n * For literal nodes (Subcomponent, SegmentHeader), returns the UTF-8 byte length of the value.\n * For parent nodes, recursively calculates the length of all children. Delimiters are NOT included.\n *\n * @param node - The HL7v2 AST node to measure\n * @returns The total byte length of the node content\n *\n * @example\n * ```ts\n * const field: Field = { type: \"field\", children: [...] };\n * const length = getByteLength(field); // e.g., 42\n * ```\n */\nexport function getByteLength(node: Nodes | null | undefined): number {\n if (!node) {\n return 0;\n }\n\n if (\"value\" in node) {\n return Buffer.byteLength(node.value, \"utf8\");\n }\n\n return node.children.reduce(\n (total, child) => total + getByteLength(child),\n 0\n );\n}\n\n// -------------\n// Length\n// -------------\n\n/**\n * Calculate the string length of any HL7v2 AST node.\n *\n * For literal nodes (Subcomponent, SegmentHeader), returns `value.length`.\n * For parent nodes, recursively calculates the length of all children. Delimiters are NOT included.\n *\n * Note: Returns JavaScript string length (UTF-16 code units). For UTF-8 byte\n * length (e.g., for wire protocol), use `getByteLength` instead.\n *\n * @param node - The HL7v2 AST node to measure\n * @returns The total string length of the node content\n *\n * @example\n * ```ts\n * const field: Field = { type: \"field\", children: [...] };\n * const length = getLength(field); // e.g., 42\n * ```\n */\nexport function getLength(node: Nodes | null | undefined): number {\n if (!node) {\n return 0;\n }\n\n if (\"value\" in node) {\n return node.value.length;\n }\n\n return node.children.reduce((total, child) => total + getLength(child), 0);\n}\n"],"mappings":";AAMO,IAAM,qBAAqB;AAAA,EAChC,OAAO;AAAA,EACP,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,SAAS;AACX;AASO,SAAS,YAAY,MAAyC;AACnE,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAGA,MAAI,WAAW,MAAM;AACnB,WAAO,CAAC,KAAK,SAAS,KAAK,MAAM,KAAK,MAAM;AAAA,EAC9C;AAGA,MAAI,cAAc,MAAM;AACtB,QAAI,CAAC,KAAK,YAAY,KAAK,SAAS,WAAW,GAAG;AAChD,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,SAAS,SAAS,GAAG;AAC5B,aAAO;AAAA,IACT;AAGA,WAAO,YAAY,KAAK,SAAS,CAAC,CAAC;AAAA,EACrC;AAGA,SAAO;AACT;AAqBO,SAAS,cAAc,MAAwC;AACpE,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAEA,MAAI,WAAW,MAAM;AACnB,WAAO,OAAO,WAAW,KAAK,OAAO,MAAM;AAAA,EAC7C;AAEA,SAAO,KAAK,SAAS;AAAA,IACnB,CAAC,OAAO,UAAU,QAAQ,cAAc,KAAK;AAAA,IAC7C;AAAA,EACF;AACF;AAwBO,SAAS,UAAU,MAAwC;AAChE,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAEA,MAAI,WAAW,MAAM;AACnB,WAAO,KAAK,MAAM;AAAA,EACpB;AAEA,SAAO,KAAK,SAAS,OAAO,CAAC,OAAO,UAAU,QAAQ,UAAU,KAAK,GAAG,CAAC;AAC3E;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts","../src/utils.ts","../src/constraints.ts"],"sourcesContent":["// -------------\n// Delimiters\n// -------------\n\nexport const DEFAULT_DELIMITERS = {\n field: \"|\",\n component: \"^\",\n repetition: \"~\",\n subcomponent: \"&\",\n escape: \"\\\\\",\n segment: \"\\r\",\n};\n","import type { Nodes } from \"@rethinkhealth/hl7v2-ast\";\n\n// -------------\n// General\n// -------------\n\n/**\n * Utility: check if a node is semantically empty\n */\nexport function isEmptyNode(node: Nodes | null | undefined): boolean {\n if (!node) {\n return true;\n }\n\n // If node has a \"value\" property (Subcomponent, maybe Component)\n if (\"value\" in node) {\n return !node.value || node.value.trim() === \"\";\n }\n\n // If node has children (Field, Component, Repetition, Segment, Root, etc.)\n if (\"children\" in node) {\n if (!node.children || node.children.length === 0) {\n return true;\n }\n\n // If node has more than one child, then it is considered non-empty\n if (node.children.length > 1) {\n return false;\n }\n\n // If node has only one child, then it is considered empty if the child is also empty\n return isEmptyNode(node.children[0]);\n }\n\n // Fallback: consider unknown node as non-empty\n return false;\n}\n\n// -------------\n// Byte Length\n// -------------\n\n/**\n * Calculate the byte length of any HL7v2 AST node.\n *\n * For literal nodes (Subcomponent, SegmentHeader), returns the UTF-8 byte length of the value.\n * For parent nodes, recursively calculates the length of all children. Delimiters are NOT included.\n *\n * @param node - The HL7v2 AST node to measure\n * @returns The total byte length of the node content\n *\n * @example\n * ```ts\n * const field: Field = { type: \"field\", children: [...] };\n * const length = getByteLength(field); // e.g., 42\n * ```\n */\nexport function getByteLength(node: Nodes | null | undefined): number {\n if (!node) {\n return 0;\n }\n\n if (\"value\" in node) {\n return Buffer.byteLength(node.value, \"utf8\");\n }\n\n return node.children.reduce(\n (total, child) => total + getByteLength(child),\n 0\n );\n}\n\n// -------------\n// Length\n// -------------\n\n/**\n * Calculate the string length of any HL7v2 AST node.\n *\n * For literal nodes (Subcomponent, SegmentHeader), returns `value.length`.\n * For parent nodes, recursively calculates the length of all children. Delimiters are NOT included.\n *\n * Note: Returns JavaScript string length (UTF-16 code units). For UTF-8 byte\n * length (e.g., for wire protocol), use `getByteLength` instead.\n *\n * @param node - The HL7v2 AST node to measure\n * @returns The total string length of the node content\n *\n * @example\n * ```ts\n * const field: Field = { type: \"field\", children: [...] };\n * const length = getLength(field); // e.g., 42\n * ```\n */\nexport function getLength(node: Nodes | null | undefined): number {\n if (!node) {\n return 0;\n }\n\n if (\"value\" in node) {\n return node.value.length;\n }\n\n return node.children.reduce((total, child) => total + getLength(child), 0);\n}\n","import type { Field, Nodes } from \"@rethinkhealth/hl7v2-ast\";\nimport { getLength, isEmptyNode } from \"./utils\";\n\nexport type ValidationErrorCode =\n // Constraints\n | \"MISSING\"\n | \"EMPTY\"\n | \"UNEXPECTED_CONTENT\"\n | \"CARDINALITY_UNDERFLOW\"\n | \"CARDINALITY_OVERFLOW\"\n | \"LENGTH_UNDERFLOW\"\n | \"LENGTH_OVERFLOW\"\n // Value Sets\n | \"VALUE_NOT_IN_TABLE\";\n\nexport type ValidationError = {\n code: ValidationErrorCode;\n message: string;\n expected?: string | number | Array<string | number>;\n actual?: string | number | Array<string | number>;\n};\n\nexport type ValidationSuccess = {\n ok: true;\n};\n\nexport type ValidationFailure = {\n ok: false;\n error: ValidationError;\n};\n\nexport type ValidationResult = ValidationSuccess | ValidationFailure;\n\nexport const OptionalityCode = {\n Required: \"R\",\n /**\n * Required, but may be empty.\n *\n * @remarks\n * The use of the RE usage code is qualified with the “if data is known”\n * clause. The sender must interpret the clause as “the capability must always\n * be supported, and data must always be sent if known”. To clarify, the\n * sender does not determine whether the data should be sent; to be conformant\n * to the rule, the data must be sent. There is a misconception where the RE\n * usage is interpreted as “the capability must always be supported, and data\n * may or may not be sent even when known based on a condition external to the\n * profile specification”.\n *\n * The receiving application must process in a meaningful way the information\n * conveyed by an element with an “RE” usage designation.\n * The receiving application must process the message if the element is omitted\n * (that is, an exception must not be raised because the element is missing). A\n * receiving application must not raise an exception due to the presence of a\n * required element.\n */\n RequiredOrEmpty: \"RE\",\n /**\n * Optional\n *\n * There are no implementation requirements. The “O” usage designation is a\n * placeholder indicating that the usage for this element has not yet been\n * specified.\n */\n Optional: \"O\",\n /**\n * Undeclared / Conditional.\n *\n * There are no implementation requirements. The “C” usage designation is a\n * placeholder indicating that the usage for this element has not yet been\n * specified.\n */\n Conditional: \"C\",\n /**\n * Not Supported.\n *\n * There are no implementation requirements. The application must not value an\n * element with an “X” usage designation.\n */\n NotSupported: \"X\",\n /**\n * Backward Compatible\n *\n * There are no implementation requirements. The “B” usage indicates that the\n * element is retained for backwards compatibility of the element. Another\n * usage indicator may be assigned in a derived profile.\n */\n BackwardCompatible: \"B\",\n /**\n * Withdrawn\n *\n * The element has been withdrawn from the standard. There are no\n * implementation requirements. The application must not value an element with\n * a \"W\" usage designation.\n */\n Withdrawn: \"W\",\n} as const;\n\nexport type OptionalityCode =\n (typeof OptionalityCode)[keyof typeof OptionalityCode];\n\n/**\n * Checks if a field satisfies the cardinality constraint.\n */\nexport function checkCardinality(\n node: Field | undefined,\n min: number,\n max: number | \"*\"\n): ValidationResult {\n if (min < 0 || (max !== \"*\" && max < 0)) {\n throw new Error(\"Min and max lengths must be non-negative\");\n }\n\n if (max !== \"*\" && min > max) {\n throw new Error(\"Min length cannot be greater than max length\");\n }\n\n const count = node?.children ? node.children.length : 0;\n\n if (count < min) {\n return {\n ok: false,\n error: {\n code: \"CARDINALITY_UNDERFLOW\",\n message: `has ${count} repetitions but requires at least ${min}`,\n expected: min,\n actual: count,\n },\n };\n }\n\n if (max !== \"*\" && count > max) {\n return {\n ok: false,\n error: {\n code: \"CARDINALITY_OVERFLOW\",\n message: `has ${count} repetitions but allows at most ${max}`,\n expected: max,\n actual: count,\n },\n };\n }\n\n return { ok: true };\n}\n\n/**\n * Checks if a node satisfies the length constraint.\n */\nexport function checkLength(\n node: Nodes | undefined,\n max: number,\n min = 0\n): ValidationResult {\n if (min < 0 || max < 0) {\n throw new Error(\"Min and max lengths must be non-negative\");\n }\n\n if (min > max) {\n throw new Error(\"Min length cannot be greater than max length\");\n }\n\n const length = getLength(node);\n\n if (length < min) {\n return {\n ok: false,\n error: {\n code: \"LENGTH_UNDERFLOW\",\n message: `has length ${length} but requires at least ${min}`,\n expected: min,\n actual: length,\n },\n };\n }\n\n if (length > max) {\n return {\n ok: false,\n error: {\n code: \"LENGTH_OVERFLOW\",\n message: `has length ${length} but allows at most ${max}`,\n expected: max,\n actual: length,\n },\n };\n }\n\n return { ok: true };\n}\n\n/**\n * Checks if a node satisfies the optionality constraint.\n */\nexport function checkOptionality(\n node: Nodes | undefined,\n optionality: OptionalityCode | string\n): ValidationResult {\n const code = optionality.toUpperCase();\n\n switch (code) {\n case OptionalityCode.Required:\n if (!node) {\n return {\n ok: false,\n error: {\n code: \"MISSING\",\n message: \"is required but missing\",\n expected: \"R\",\n },\n };\n }\n if (isEmptyNode(node)) {\n return {\n ok: false,\n error: {\n code: \"EMPTY\",\n message: \"is required but empty\",\n expected: \"R\",\n },\n };\n }\n return { ok: true };\n\n case OptionalityCode.NotSupported:\n if (node && !isEmptyNode(node)) {\n return {\n ok: false,\n error: {\n code: \"UNEXPECTED_CONTENT\",\n message: \"is not supported but present\",\n expected: \"X\",\n },\n };\n }\n return { ok: true };\n\n case OptionalityCode.RequiredOrEmpty:\n case OptionalityCode.Optional:\n case OptionalityCode.Conditional:\n case OptionalityCode.BackwardCompatible:\n case OptionalityCode.Withdrawn:\n return { ok: true };\n\n default:\n return { ok: true };\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Nodes } from "@rethinkhealth/hl7v2-ast";
|
|
2
|
+
/**
|
|
3
|
+
* Utility: check if a node is semantically empty
|
|
4
|
+
*/
|
|
5
|
+
export declare function isEmptyNode(node: Nodes | null | undefined): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Calculate the byte length of any HL7v2 AST node.
|
|
8
|
+
*
|
|
9
|
+
* For literal nodes (Subcomponent, SegmentHeader), returns the UTF-8 byte length of the value.
|
|
10
|
+
* For parent nodes, recursively calculates the length of all children. Delimiters are NOT included.
|
|
11
|
+
*
|
|
12
|
+
* @param node - The HL7v2 AST node to measure
|
|
13
|
+
* @returns The total byte length of the node content
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const field: Field = { type: "field", children: [...] };
|
|
18
|
+
* const length = getByteLength(field); // e.g., 42
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function getByteLength(node: Nodes | null | undefined): number;
|
|
22
|
+
/**
|
|
23
|
+
* Calculate the string length of any HL7v2 AST node.
|
|
24
|
+
*
|
|
25
|
+
* For literal nodes (Subcomponent, SegmentHeader), returns `value.length`.
|
|
26
|
+
* For parent nodes, recursively calculates the length of all children. Delimiters are NOT included.
|
|
27
|
+
*
|
|
28
|
+
* Note: Returns JavaScript string length (UTF-16 code units). For UTF-8 byte
|
|
29
|
+
* length (e.g., for wire protocol), use `getByteLength` instead.
|
|
30
|
+
*
|
|
31
|
+
* @param node - The HL7v2 AST node to measure
|
|
32
|
+
* @returns The total string length of the node content
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* const field: Field = { type: "field", children: [...] };
|
|
37
|
+
* const length = getLength(field); // e.g., 42
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function getLength(node: Nodes | null | undefined): number;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rethinkhealth/hl7v2-utils",
|
|
3
3
|
"description": "hl7v2 utilities",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Melek Somai",
|
|
@@ -16,17 +16,17 @@
|
|
|
16
16
|
".": "./dist/index.js"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@types/node": "24.10.
|
|
19
|
+
"@types/node": "24.10.1",
|
|
20
20
|
"@types/unist": "^3.0.3",
|
|
21
|
-
"@vitest/coverage-v8": "
|
|
22
|
-
"tsup": "8.5.
|
|
21
|
+
"@vitest/coverage-v8": "4.0.14",
|
|
22
|
+
"tsup": "8.5.1",
|
|
23
23
|
"typescript": "^5.9.3",
|
|
24
24
|
"unist-builder": "^4.0.0",
|
|
25
25
|
"vfile": "^6.0.3",
|
|
26
|
-
"vitest": "
|
|
26
|
+
"vitest": "4.0.14",
|
|
27
|
+
"@rethinkhealth/hl7v2-ast": "0.4.0",
|
|
27
28
|
"@rethinkhealth/testing": "0.0.2",
|
|
28
|
-
"@rethinkhealth/tsconfig": "0.0.1"
|
|
29
|
-
"@rethinkhealth/hl7v2-ast": "0.3.4"
|
|
29
|
+
"@rethinkhealth/tsconfig": "0.0.1"
|
|
30
30
|
},
|
|
31
31
|
"engines": {
|
|
32
32
|
"node": ">=18"
|