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 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;
@@ -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
+ }
@@ -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.3.2",
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.3.2"
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
+ }
@@ -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;