hl7v2 1.3.2 → 1.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 +2 -17
- package/cjs/hl7-message-node.js +38 -0
- package/cjs/hl7-message.js +74 -0
- package/esm/hl7-message-node.js +34 -0
- package/esm/hl7-message.js +74 -0
- package/package.json +2 -2
- package/types/hl7-message-node.d.ts +14 -0
- package/types/hl7-message.d.ts +2 -0
package/README.md
CHANGED
|
@@ -24,33 +24,18 @@ $ npm install hl7v2 --save
|
|
|
24
24
|
HL7v2 is available under [MIT](LICENSE) license.
|
|
25
25
|
|
|
26
26
|
[npm-image]: https://img.shields.io/npm/v/hl7v2.svg
|
|
27
|
-
|
|
28
27
|
[npm-url]: https://npmjs.org/package/hl7v2
|
|
29
|
-
|
|
30
28
|
[ci-test-image]: https://github.com/panates/hl7v2/actions/workflows/test.yml/badge.svg
|
|
31
|
-
|
|
32
29
|
[ci-test-url]: https://github.com/panates/hl7v2/actions/workflows/test.yml
|
|
33
|
-
|
|
34
30
|
[coveralls-image]: https://img.shields.io/coveralls/panates/hl7v2/master.svg
|
|
35
|
-
|
|
36
31
|
[coveralls-url]: https://coveralls.io/r/panates/hl7v2
|
|
37
|
-
|
|
38
32
|
[downloads-image]: https://img.shields.io/npm/dm/hl7v2.svg
|
|
39
|
-
|
|
40
33
|
[downloads-url]: https://npmjs.org/package/hl7v2
|
|
41
|
-
|
|
42
34
|
[gitter-image]: https://badges.gitter.im/panates/hl7v2.svg
|
|
43
|
-
|
|
44
35
|
[gitter-url]: https://gitter.im/panates/hl7v2?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
|
45
|
-
|
|
46
36
|
[dependencies-image]: https://david-dm.org/panates/hl7v2/status.svg
|
|
47
|
-
|
|
48
|
-
[dependencies-url]:https://david-dm.org/panates/hl7v2
|
|
49
|
-
|
|
37
|
+
[dependencies-url]: https://david-dm.org/panates/hl7v2
|
|
50
38
|
[devdependencies-image]: https://david-dm.org/panates/hl7v2/dev-status.svg
|
|
51
|
-
|
|
52
|
-
[devdependencies-url]:https://david-dm.org/panates/hl7v2?type=dev
|
|
53
|
-
|
|
39
|
+
[devdependencies-url]: https://david-dm.org/panates/hl7v2?type=dev
|
|
54
40
|
[quality-image]: http://npm.packagequality.com/shield/hl7v2.png
|
|
55
|
-
|
|
56
41
|
[quality-url]: http://packagequality.com/#?package=hl7v2
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HL7MessageNode = void 0;
|
|
4
|
+
const hl7_segment_js_1 = require("./hl7-segment.js");
|
|
5
|
+
class HL7MessageNode {
|
|
6
|
+
constructor(name) {
|
|
7
|
+
this.name = '';
|
|
8
|
+
this.items = [];
|
|
9
|
+
this.name = name;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Searches for a segment of a given type
|
|
13
|
+
*/
|
|
14
|
+
getSegment(segmentType, index = 0) {
|
|
15
|
+
let k = 0;
|
|
16
|
+
for (const seg of this.items) {
|
|
17
|
+
if (seg instanceof hl7_segment_js_1.HL7Segment && seg.segmentType === segmentType) {
|
|
18
|
+
if (!index || index === k)
|
|
19
|
+
return seg;
|
|
20
|
+
k++;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Searches for a segment of a given type in reverse order
|
|
26
|
+
*/
|
|
27
|
+
getSegmentFromLast(segmentType, index = 0) {
|
|
28
|
+
for (let k = this.items.length - 1; k >= 0; k--) {
|
|
29
|
+
const seg = this.items[k];
|
|
30
|
+
if (seg instanceof hl7_segment_js_1.HL7Segment && seg.segmentType === segmentType) {
|
|
31
|
+
if (!index || index === k)
|
|
32
|
+
return seg;
|
|
33
|
+
k++;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.HL7MessageNode = HL7MessageNode;
|
package/cjs/hl7-message.js
CHANGED
|
@@ -8,6 +8,7 @@ const iconv_lite_1 = tslib_1.__importDefault(require("iconv-lite"));
|
|
|
8
8
|
const uid_1 = require("uid");
|
|
9
9
|
const constants_js_1 = require("./constants.js");
|
|
10
10
|
const hl7_error_js_1 = require("./hl7-error.js");
|
|
11
|
+
const hl7_message_node_js_1 = require("./hl7-message-node.js");
|
|
11
12
|
const hl7_segment_js_1 = require("./hl7-segment.js");
|
|
12
13
|
class HL7Message {
|
|
13
14
|
constructor(version = hl7v2_dictionary_1.HL7Version.v2_7_1, dictionaries) {
|
|
@@ -138,6 +139,79 @@ class HL7Message {
|
|
|
138
139
|
}
|
|
139
140
|
}
|
|
140
141
|
}
|
|
142
|
+
buildStructureTree() {
|
|
143
|
+
// Get the message type to determine the structure
|
|
144
|
+
const messageType = this.messageType.replace('^', '_');
|
|
145
|
+
const messageDefinition = this.dictionary.messages?.[messageType];
|
|
146
|
+
if (!messageDefinition?.segments) {
|
|
147
|
+
const result = new hl7_message_node_js_1.HL7MessageNode('MESSAGE');
|
|
148
|
+
result.items.push(...this.segments);
|
|
149
|
+
}
|
|
150
|
+
// Helper function to process a segment definition recursively
|
|
151
|
+
const processSegmentDefinition = (segmentDef, nodeName, currentSegmentIndex) => {
|
|
152
|
+
const node = new hl7_message_node_js_1.HL7MessageNode(nodeName);
|
|
153
|
+
// Sort segment definitions by their index
|
|
154
|
+
const sortedEntries = Object.entries(segmentDef).sort(([, a], [, b]) => (a.idx || 0) - (b.idx || 0));
|
|
155
|
+
for (const [key, def] of sortedEntries) {
|
|
156
|
+
if (def.segments) {
|
|
157
|
+
// This is a group - process recursively
|
|
158
|
+
const maxOccurrences = def.max || Number.MAX_SAFE_INTEGER;
|
|
159
|
+
let occurrenceCount = 0;
|
|
160
|
+
const initialSegmentIndex = currentSegmentIndex.value;
|
|
161
|
+
// Try to match segments for this group
|
|
162
|
+
while (occurrenceCount < maxOccurrences &&
|
|
163
|
+
currentSegmentIndex.value < this.segments.length) {
|
|
164
|
+
const groupStartIndex = currentSegmentIndex.value;
|
|
165
|
+
const groupNode = processSegmentDefinition(def.segments, key, currentSegmentIndex);
|
|
166
|
+
// Check if we actually consumed any segments
|
|
167
|
+
if (currentSegmentIndex.value > groupStartIndex &&
|
|
168
|
+
groupNode.items.length > 0) {
|
|
169
|
+
node.items.push(groupNode);
|
|
170
|
+
occurrenceCount++;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
// No segments matched, break the loop
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// If no occurrences found, reset to initial position
|
|
178
|
+
if (occurrenceCount === 0) {
|
|
179
|
+
currentSegmentIndex.value = initialSegmentIndex;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
// This is a leaf segment
|
|
184
|
+
const maxOccurrences = def.max || Number.MAX_SAFE_INTEGER;
|
|
185
|
+
const segmentType = key;
|
|
186
|
+
// Match segments of this type
|
|
187
|
+
let matchedCount = 0;
|
|
188
|
+
while (matchedCount < maxOccurrences &&
|
|
189
|
+
currentSegmentIndex.value < this.segments.length) {
|
|
190
|
+
const currentSegment = this.segments[currentSegmentIndex.value];
|
|
191
|
+
if (currentSegment.segmentType === segmentType) {
|
|
192
|
+
node.items.push(currentSegment);
|
|
193
|
+
currentSegmentIndex.value++;
|
|
194
|
+
matchedCount++;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
// Different segment type - stop matching
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return node;
|
|
204
|
+
};
|
|
205
|
+
const segmentIndexRef = { value: 0 };
|
|
206
|
+
const result = processSegmentDefinition(messageDefinition.segments, messageType, segmentIndexRef);
|
|
207
|
+
// Add any remaining unmatched segments to the result
|
|
208
|
+
while (segmentIndexRef.value < this.segments.length) {
|
|
209
|
+
const segment = this.segments[segmentIndexRef.value];
|
|
210
|
+
result.items.push(segment);
|
|
211
|
+
segmentIndexRef.value++;
|
|
212
|
+
}
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
141
215
|
createAck(ackCode = 'AA', textMessage) {
|
|
142
216
|
const out = new HL7Message(this.version, this._dictionaries);
|
|
143
217
|
const msh = out.header;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { HL7Segment } from './hl7-segment.js';
|
|
2
|
+
export class HL7MessageNode {
|
|
3
|
+
constructor(name) {
|
|
4
|
+
this.name = '';
|
|
5
|
+
this.items = [];
|
|
6
|
+
this.name = name;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Searches for a segment of a given type
|
|
10
|
+
*/
|
|
11
|
+
getSegment(segmentType, index = 0) {
|
|
12
|
+
let k = 0;
|
|
13
|
+
for (const seg of this.items) {
|
|
14
|
+
if (seg instanceof HL7Segment && seg.segmentType === segmentType) {
|
|
15
|
+
if (!index || index === k)
|
|
16
|
+
return seg;
|
|
17
|
+
k++;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Searches for a segment of a given type in reverse order
|
|
23
|
+
*/
|
|
24
|
+
getSegmentFromLast(segmentType, index = 0) {
|
|
25
|
+
for (let k = this.items.length - 1; k >= 0; k--) {
|
|
26
|
+
const seg = this.items[k];
|
|
27
|
+
if (seg instanceof HL7Segment && seg.segmentType === segmentType) {
|
|
28
|
+
if (!index || index === k)
|
|
29
|
+
return seg;
|
|
30
|
+
k++;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
package/esm/hl7-message.js
CHANGED
|
@@ -4,6 +4,7 @@ import iconv from 'iconv-lite';
|
|
|
4
4
|
import { uid } from 'uid';
|
|
5
5
|
import { COMPONENT_SEPARATOR, CR, ESCAPE_CHARACTER, FIELD_SEPARATOR, FS, LF, REPETITION_SEPARATOR, SUBCOMPONENT_SEPARATOR, VT, } from './constants.js';
|
|
6
6
|
import { HL7Error } from './hl7-error.js';
|
|
7
|
+
import { HL7MessageNode } from './hl7-message-node.js';
|
|
7
8
|
import { HL7Segment, } from './hl7-segment.js';
|
|
8
9
|
export class HL7Message {
|
|
9
10
|
constructor(version = HL7Version.v2_7_1, dictionaries) {
|
|
@@ -134,6 +135,79 @@ export class HL7Message {
|
|
|
134
135
|
}
|
|
135
136
|
}
|
|
136
137
|
}
|
|
138
|
+
buildStructureTree() {
|
|
139
|
+
// Get the message type to determine the structure
|
|
140
|
+
const messageType = this.messageType.replace('^', '_');
|
|
141
|
+
const messageDefinition = this.dictionary.messages?.[messageType];
|
|
142
|
+
if (!messageDefinition?.segments) {
|
|
143
|
+
const result = new HL7MessageNode('MESSAGE');
|
|
144
|
+
result.items.push(...this.segments);
|
|
145
|
+
}
|
|
146
|
+
// Helper function to process a segment definition recursively
|
|
147
|
+
const processSegmentDefinition = (segmentDef, nodeName, currentSegmentIndex) => {
|
|
148
|
+
const node = new HL7MessageNode(nodeName);
|
|
149
|
+
// Sort segment definitions by their index
|
|
150
|
+
const sortedEntries = Object.entries(segmentDef).sort(([, a], [, b]) => (a.idx || 0) - (b.idx || 0));
|
|
151
|
+
for (const [key, def] of sortedEntries) {
|
|
152
|
+
if (def.segments) {
|
|
153
|
+
// This is a group - process recursively
|
|
154
|
+
const maxOccurrences = def.max || Number.MAX_SAFE_INTEGER;
|
|
155
|
+
let occurrenceCount = 0;
|
|
156
|
+
const initialSegmentIndex = currentSegmentIndex.value;
|
|
157
|
+
// Try to match segments for this group
|
|
158
|
+
while (occurrenceCount < maxOccurrences &&
|
|
159
|
+
currentSegmentIndex.value < this.segments.length) {
|
|
160
|
+
const groupStartIndex = currentSegmentIndex.value;
|
|
161
|
+
const groupNode = processSegmentDefinition(def.segments, key, currentSegmentIndex);
|
|
162
|
+
// Check if we actually consumed any segments
|
|
163
|
+
if (currentSegmentIndex.value > groupStartIndex &&
|
|
164
|
+
groupNode.items.length > 0) {
|
|
165
|
+
node.items.push(groupNode);
|
|
166
|
+
occurrenceCount++;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
// No segments matched, break the loop
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// If no occurrences found, reset to initial position
|
|
174
|
+
if (occurrenceCount === 0) {
|
|
175
|
+
currentSegmentIndex.value = initialSegmentIndex;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
// This is a leaf segment
|
|
180
|
+
const maxOccurrences = def.max || Number.MAX_SAFE_INTEGER;
|
|
181
|
+
const segmentType = key;
|
|
182
|
+
// Match segments of this type
|
|
183
|
+
let matchedCount = 0;
|
|
184
|
+
while (matchedCount < maxOccurrences &&
|
|
185
|
+
currentSegmentIndex.value < this.segments.length) {
|
|
186
|
+
const currentSegment = this.segments[currentSegmentIndex.value];
|
|
187
|
+
if (currentSegment.segmentType === segmentType) {
|
|
188
|
+
node.items.push(currentSegment);
|
|
189
|
+
currentSegmentIndex.value++;
|
|
190
|
+
matchedCount++;
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
// Different segment type - stop matching
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return node;
|
|
200
|
+
};
|
|
201
|
+
const segmentIndexRef = { value: 0 };
|
|
202
|
+
const result = processSegmentDefinition(messageDefinition.segments, messageType, segmentIndexRef);
|
|
203
|
+
// Add any remaining unmatched segments to the result
|
|
204
|
+
while (segmentIndexRef.value < this.segments.length) {
|
|
205
|
+
const segment = this.segments[segmentIndexRef.value];
|
|
206
|
+
result.items.push(segment);
|
|
207
|
+
segmentIndexRef.value++;
|
|
208
|
+
}
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
137
211
|
createAck(ackCode = 'AA', textMessage) {
|
|
138
212
|
const out = new HL7Message(this.version, this._dictionaries);
|
|
139
213
|
const msh = out.header;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hl7v2",
|
|
3
3
|
"description": "HL7 v2 parser, serializer, validator for NodeJS",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.4.0",
|
|
5
5
|
"author": "Panates",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"dependencies": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"uid": "^2.0.2"
|
|
16
16
|
},
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"hl7v2-dictionary": "^1.
|
|
18
|
+
"hl7v2-dictionary": "^1.4.0"
|
|
19
19
|
},
|
|
20
20
|
"type": "module",
|
|
21
21
|
"exports": {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { HL7Segment } from './hl7-segment.js';
|
|
2
|
+
export declare class HL7MessageNode {
|
|
3
|
+
name: string;
|
|
4
|
+
items: (HL7Segment | HL7MessageNode)[];
|
|
5
|
+
constructor(name: string);
|
|
6
|
+
/**
|
|
7
|
+
* Searches for a segment of a given type
|
|
8
|
+
*/
|
|
9
|
+
getSegment(segmentType: string, index?: number): HL7Segment | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Searches for a segment of a given type in reverse order
|
|
12
|
+
*/
|
|
13
|
+
getSegmentFromLast(segmentType: string, index?: number): HL7Segment | undefined;
|
|
14
|
+
}
|
package/types/hl7-message.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AcknowledgmentCode, HL7Dictionary, HL7Version } from 'hl7v2-dictionary';
|
|
2
|
+
import { HL7MessageNode } from './hl7-message-node.js';
|
|
2
3
|
import { HL7Segment, Hl7SegmentParseOptions, Hl7SegmentSerializeOptions } from './hl7-segment.js';
|
|
3
4
|
export declare class HL7Message {
|
|
4
5
|
private readonly _dictionaries;
|
|
@@ -29,6 +30,7 @@ export declare class HL7Message {
|
|
|
29
30
|
getSegmentFromLast(segmentType: string, index?: number): HL7Segment | undefined;
|
|
30
31
|
toHL7String(options?: HL7MessageSerializeOptions): string;
|
|
31
32
|
parse(input: string | Buffer, options?: HL7MessageParseOptions): void;
|
|
33
|
+
buildStructureTree(): HL7MessageNode;
|
|
32
34
|
createAck(ackCode?: AcknowledgmentCode, textMessage?: string): HL7Message;
|
|
33
35
|
createNak(errors: (Error | string)[]): HL7Message;
|
|
34
36
|
addError(error: Error | string): void;
|