@rethinkhealth/hl7v2-utils 0.4.1 → 0.5.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
@@ -32,27 +32,27 @@ Report a diagnostic to a VFile. This function is the standard way to report issu
32
32
  #### Example
33
33
 
34
34
  ```typescript
35
- import { report } from '@rethinkhealth/hl7v2-utils';
36
- import type { Diagnostic } from '@rethinkhealth/hl7v2-utils';
37
- import { VFile } from 'vfile';
35
+ import { report } from "@rethinkhealth/hl7v2-utils";
36
+ import type { Diagnostic } from "@rethinkhealth/hl7v2-utils";
37
+ import { VFile } from "vfile";
38
38
 
39
39
  // Define a diagnostic rule
40
40
  const requiredFieldRule: Diagnostic = {
41
- type: 'lint',
42
- namespace: 'field',
43
- code: 'required',
44
- title: 'Required Field Missing',
45
- description: 'A required field is missing from the segment.',
46
- severity: 'error',
41
+ type: "lint",
42
+ namespace: "field",
43
+ code: "required",
44
+ title: "Required Field Missing",
45
+ description: "A required field is missing from the segment.",
46
+ severity: "error",
47
47
  message: (ctx) => `Field '${ctx.fieldPath}' is required`,
48
- helpUrl: 'https://example.com/docs/required-field'
48
+ helpUrl: "https://example.com/docs/required-field",
49
49
  };
50
50
 
51
51
  // Report the diagnostic
52
52
  const file = new VFile();
53
53
  report(file, requiredFieldRule, {
54
- context: { fieldPath: 'PID-5' },
55
- node: segmentNode
54
+ context: { fieldPath: "PID-5" },
55
+ node: segmentNode,
56
56
  });
57
57
  ```
58
58
 
@@ -81,25 +81,25 @@ The function is optimized for performance with O(n) time complexity where n is t
81
81
  #### Example
82
82
 
83
83
  ```typescript
84
- import { getByteLength } from '@rethinkhealth/hl7v2-utils';
85
- import type { Field } from '@rethinkhealth/hl7v2-ast';
84
+ import { getByteLength } from "@rethinkhealth/hl7v2-utils";
85
+ import type { Field } from "@rethinkhealth/hl7v2-ast";
86
86
 
87
87
  const field: Field = {
88
- type: 'field',
88
+ type: "field",
89
89
  children: [
90
90
  {
91
- type: 'field-repetition',
91
+ type: "field-repetition",
92
92
  children: [
93
93
  {
94
- type: 'component',
94
+ type: "component",
95
95
  children: [
96
- { type: 'subcomponent', value: 'SMITH' },
97
- { type: 'subcomponent', value: 'JOHN' }
98
- ]
99
- }
100
- ]
101
- }
102
- ]
96
+ { type: "subcomponent", value: "SMITH" },
97
+ { type: "subcomponent", value: "JOHN" },
98
+ ],
99
+ },
100
+ ],
101
+ },
102
+ ],
103
103
  };
104
104
 
105
105
  // Calculate: SMITH&JOHN = 5 + 1 + 4 = 10 bytes
@@ -142,25 +142,25 @@ The function is optimized for performance with O(n) time complexity where n is t
142
142
  #### Example
143
143
 
144
144
  ```typescript
145
- import { getLength } from '@rethinkhealth/hl7v2-utils';
146
- import type { Field } from '@rethinkhealth/hl7v2-ast';
145
+ import { getLength } from "@rethinkhealth/hl7v2-utils";
146
+ import type { Field } from "@rethinkhealth/hl7v2-ast";
147
147
 
148
148
  const field: Field = {
149
- type: 'field',
149
+ type: "field",
150
150
  children: [
151
151
  {
152
- type: 'field-repetition',
152
+ type: "field-repetition",
153
153
  children: [
154
154
  {
155
- type: 'component',
155
+ type: "component",
156
156
  children: [
157
- { type: 'subcomponent', value: 'SMITH' },
158
- { type: 'subcomponent', value: 'JOHN' }
159
- ]
160
- }
161
- ]
162
- }
163
- ]
157
+ { type: "subcomponent", value: "SMITH" },
158
+ { type: "subcomponent", value: "JOHN" },
159
+ ],
160
+ },
161
+ ],
162
+ },
163
+ ],
164
164
  };
165
165
 
166
166
  // Calculate: SMITH&JOHN = 5 + 1 + 4 = 10 characters
@@ -177,11 +177,11 @@ const length = getLength(field); // Returns: 10
177
177
  #### Comparison with `getByteLength`
178
178
 
179
179
  ```typescript
180
- import { getLength, getByteLength } from '@rethinkhealth/hl7v2-utils';
180
+ import { getLength, getByteLength } from "@rethinkhealth/hl7v2-utils";
181
181
 
182
- const subcomponent = { type: 'subcomponent', value: 'café' };
182
+ const subcomponent = { type: "subcomponent", value: "café" };
183
183
 
184
- getLength(subcomponent); // Returns: 4 (4 characters)
184
+ getLength(subcomponent); // Returns: 4 (4 characters)
185
185
  getByteLength(subcomponent); // Returns: 5 (5 bytes in UTF-8: c-a-f-C3-A9)
186
186
  ```
187
187
 
@@ -194,16 +194,16 @@ The package provides stateless, composable functions to validate HL7v2 AST nodes
194
194
  All conformance functions return a `ValidationResult` object:
195
195
 
196
196
  ```typescript
197
- type ValidationResult =
197
+ type ValidationResult =
198
198
  | { ok: true }
199
- | {
200
- ok: false;
201
- error: {
202
- code: string;
199
+ | {
200
+ ok: false;
201
+ error: {
202
+ code: string;
203
203
  message: string;
204
204
  expected?: string | number | Array<string | number>;
205
205
  actual?: string | number | Array<string | number>;
206
- }
206
+ };
207
207
  };
208
208
  ```
209
209
 
@@ -216,10 +216,10 @@ Checks if a node satisfies the optionality (usage) constraint.
216
216
  - **Returns**: `ValidationResult`
217
217
 
218
218
  ```typescript
219
- import { checkOptionality } from '@rethinkhealth/hl7v2-utils';
219
+ import { checkOptionality } from "@rethinkhealth/hl7v2-utils";
220
220
 
221
221
  // 'R' (Required), 'RE' (Required or Empty), 'O' (Optional), 'X' (Not Supported)
222
- const result = checkOptionality(myFieldNode, 'R');
222
+ const result = checkOptionality(myFieldNode, "R");
223
223
 
224
224
  if (!result.ok) {
225
225
  console.error(result.error.message); // "is required but missing"
@@ -236,7 +236,7 @@ Checks if a field has the correct number of repetitions.
236
236
  - **Returns**: `ValidationResult`
237
237
 
238
238
  ```typescript
239
- import { checkCardinality } from '@rethinkhealth/hl7v2-utils';
239
+ import { checkCardinality } from "@rethinkhealth/hl7v2-utils";
240
240
 
241
241
  // Field must repeat between 1 and 5 times
242
242
  const result = checkCardinality(myFieldNode, 1, 5);
@@ -252,7 +252,7 @@ Checks if the content of a node falls within the minimum and maximum length.
252
252
  - **Returns**: `ValidationResult`
253
253
 
254
254
  ```typescript
255
- import { checkLength } from '@rethinkhealth/hl7v2-utils';
255
+ import { checkLength } from "@rethinkhealth/hl7v2-utils";
256
256
 
257
257
  // Content length must be between 1 and 10 characters
258
258
  const result = checkLength(myNode, 10, 1);
@@ -1,8 +1,9 @@
1
1
  export declare const DEFAULT_DELIMITERS: {
2
- field: string;
3
2
  component: string;
4
- repetition: string;
5
- subcomponent: string;
6
3
  escape: string;
4
+ field: string;
5
+ repetition: string;
7
6
  segment: string;
7
+ subcomponent: string;
8
8
  };
9
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,kBAAkB;;;;;;;CAO9B,CAAC"}
@@ -1,50 +1,28 @@
1
1
  import type { Field, Nodes } from "@rethinkhealth/hl7v2-ast";
2
2
  export type ValidationErrorCode = "MISSING" | "EMPTY" | "UNEXPECTED_CONTENT" | "CARDINALITY_UNDERFLOW" | "CARDINALITY_OVERFLOW" | "LENGTH_UNDERFLOW" | "LENGTH_OVERFLOW" | "VALUE_NOT_IN_TABLE";
3
- export type ValidationError = {
3
+ export interface ValidationError {
4
4
  code: ValidationErrorCode;
5
5
  message: string;
6
6
  expected?: string | number | Array<string | number>;
7
7
  actual?: string | number | Array<string | number>;
8
- };
9
- export type ValidationSuccess = {
8
+ }
9
+ export interface ValidationSuccess {
10
10
  ok: true;
11
- };
12
- export type ValidationFailure = {
11
+ }
12
+ export interface ValidationFailure {
13
13
  ok: false;
14
14
  error: ValidationError;
15
- };
15
+ }
16
16
  export type ValidationResult = ValidationSuccess | ValidationFailure;
17
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
18
  /**
41
- * Optional
19
+ * Backward Compatible
42
20
  *
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.
21
+ * There are no implementation requirements. The “B” usage indicates that the
22
+ * element is retained for backwards compatibility of the element. Another
23
+ * usage indicator may be assigned in a derived profile.
46
24
  */
47
- readonly Optional: "O";
25
+ readonly BackwardCompatible: "B";
48
26
  /**
49
27
  * Undeclared / Conditional.
50
28
  *
@@ -61,13 +39,37 @@ export declare const OptionalityCode: {
61
39
  */
62
40
  readonly NotSupported: "X";
63
41
  /**
64
- * Backward Compatible
42
+ * Optional
65
43
  *
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.
44
+ * There are no implementation requirements. The “O” usage designation is a
45
+ * placeholder indicating that the usage for this element has not yet been
46
+ * specified.
69
47
  */
70
- readonly BackwardCompatible: "B";
48
+ readonly Optional: "O";
49
+ /**
50
+ * Required
51
+ */
52
+ readonly Required: "R";
53
+ /**
54
+ * Required, but may be empty.
55
+ *
56
+ * The use of the RE usage code is qualified with the “if data is known”
57
+ * clause. The sender must interpret the clause as “the capability must always
58
+ * be supported, and data must always be sent if known”. To clarify, the
59
+ * sender does not determine whether the data should be sent; to be conformant
60
+ * to the rule, the data must be sent. There is a misconception where the RE
61
+ * usage is interpreted as “the capability must always be supported, and data
62
+ * may or may not be sent even when known based on a condition external to the
63
+ * profile specification”.
64
+ *
65
+ * The receiving application must process in a meaningful way the information
66
+ * conveyed by an element with an “RE” usage designation.
67
+ * The receiving application must process the message if the element is omitted
68
+ * (that is, an exception must not be raised because the element is missing). A
69
+ * receiving application must not raise an exception due to the presence of a
70
+ * required element.
71
+ */
72
+ readonly RequiredOrEmpty: "RE";
71
73
  /**
72
74
  * Withdrawn
73
75
  *
@@ -90,3 +92,4 @@ export declare function checkLength(node: Nodes | undefined, max: number, min?:
90
92
  * Checks if a node satisfies the optionality constraint.
91
93
  */
92
94
  export declare function checkOptionality(node: Nodes | undefined, optionality: OptionalityCode | string): ValidationResult;
95
+ //# sourceMappingURL=constraints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constraints.d.ts","sourceRoot":"","sources":["../src/constraints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAI7D,MAAM,MAAM,mBAAmB,GAE3B,SAAS,GACT,OAAO,GACP,oBAAoB,GACpB,uBAAuB,GACvB,sBAAsB,GACtB,kBAAkB,GAClB,iBAAiB,GAEjB,oBAAoB,CAAC;AAEzB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IACpD,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,IAAI,CAAC;CACV;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AAErE,eAAO,MAAM,eAAe;IAC1B;;;;;;OAMG;;IAGH;;;;;;OAMG;;IAGH;;;;;OAKG;;IAGH;;;;;;OAMG;;IAGH;;OAEG;;IAGH;;;;;;;;;;;;;;;;;;OAkBG;;IAGH;;;;;;OAMG;;CAEK,CAAC;AAEX,MAAM,MAAM,eAAe,GACzB,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,OAAO,eAAe,CAAC,CAAC;AAEzD;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,KAAK,GAAG,SAAS,EACvB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GAAG,GAAG,GAChB,gBAAgB,CAoClB;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,KAAK,GAAG,SAAS,EACvB,GAAG,EAAE,MAAM,EACX,GAAG,SAAI,GACN,gBAAgB,CAoClB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,KAAK,GAAG,SAAS,EACvB,WAAW,EAAE,eAAe,GAAG,MAAM,GACpC,gBAAgB,CAsDlB"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./constants";
2
2
  export * from "./constraints";
3
3
  export * from "./utils";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  // src/constants.ts
2
2
  var DEFAULT_DELIMITERS = {
3
- field: "|",
4
3
  component: "^",
5
- repetition: "~",
6
- subcomponent: "&",
7
4
  escape: "\\",
8
- segment: "\r"
5
+ field: "|",
6
+ repetition: "~",
7
+ segment: "\r",
8
+ subcomponent: "&"
9
9
  };
10
10
 
11
11
  // src/utils.ts
@@ -34,10 +34,8 @@ function getByteLength(node) {
34
34
  if ("value" in node) {
35
35
  return Buffer.byteLength(node.value, "utf8");
36
36
  }
37
- return node.children.reduce(
38
- (total, child) => total + getByteLength(child),
39
- 0
40
- );
37
+ const nameLength = node.type === "segment" ? Buffer.byteLength(node.name, "utf8") : 0;
38
+ return nameLength + node.children.reduce((total, child) => total + getByteLength(child), 0);
41
39
  }
42
40
  function getLength(node) {
43
41
  if (!node) {
@@ -46,41 +44,20 @@ function getLength(node) {
46
44
  if ("value" in node) {
47
45
  return node.value.length;
48
46
  }
49
- return node.children.reduce((total, child) => total + getLength(child), 0);
47
+ const nameLength = node.type === "segment" ? node.name.length : 0;
48
+ return nameLength + node.children.reduce((total, child) => total + getLength(child), 0);
50
49
  }
51
50
 
52
51
  // src/constraints.ts
53
52
  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
53
  /**
77
- * Optional
54
+ * Backward Compatible
78
55
  *
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.
56
+ * There are no implementation requirements. The “B” usage indicates that the
57
+ * element is retained for backwards compatibility of the element. Another
58
+ * usage indicator may be assigned in a derived profile.
82
59
  */
83
- Optional: "O",
60
+ BackwardCompatible: "B",
84
61
  /**
85
62
  * Undeclared / Conditional.
86
63
  *
@@ -97,13 +74,37 @@ var OptionalityCode = {
97
74
  */
98
75
  NotSupported: "X",
99
76
  /**
100
- * Backward Compatible
77
+ * Optional
101
78
  *
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.
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.
105
82
  */
106
- BackwardCompatible: "B",
83
+ Optional: "O",
84
+ /**
85
+ * Required
86
+ */
87
+ Required: "R",
88
+ /**
89
+ * Required, but may be empty.
90
+ *
91
+ * The use of the RE usage code is qualified with the “if data is known”
92
+ * clause. The sender must interpret the clause as “the capability must always
93
+ * be supported, and data must always be sent if known”. To clarify, the
94
+ * sender does not determine whether the data should be sent; to be conformant
95
+ * to the rule, the data must be sent. There is a misconception where the RE
96
+ * usage is interpreted as “the capability must always be supported, and data
97
+ * may or may not be sent even when known based on a condition external to the
98
+ * profile specification”.
99
+ *
100
+ * The receiving application must process in a meaningful way the information
101
+ * conveyed by an element with an “RE” usage designation.
102
+ * The receiving application must process the message if the element is omitted
103
+ * (that is, an exception must not be raised because the element is missing). A
104
+ * receiving application must not raise an exception due to the presence of a
105
+ * required element.
106
+ */
107
+ RequiredOrEmpty: "RE",
107
108
  /**
108
109
  * Withdrawn
109
110
  *
@@ -123,24 +124,24 @@ function checkCardinality(node, min, max) {
123
124
  const count = node?.children ? node.children.length : 0;
124
125
  if (count < min) {
125
126
  return {
126
- ok: false,
127
127
  error: {
128
+ actual: count,
128
129
  code: "CARDINALITY_UNDERFLOW",
129
- message: `has ${count} repetitions but requires at least ${min}`,
130
130
  expected: min,
131
- actual: count
132
- }
131
+ message: `has ${count} repetitions but requires at least ${min}`
132
+ },
133
+ ok: false
133
134
  };
134
135
  }
135
136
  if (max !== "*" && count > max) {
136
137
  return {
137
- ok: false,
138
138
  error: {
139
+ actual: count,
139
140
  code: "CARDINALITY_OVERFLOW",
140
- message: `has ${count} repetitions but allows at most ${max}`,
141
141
  expected: max,
142
- actual: count
143
- }
142
+ message: `has ${count} repetitions but allows at most ${max}`
143
+ },
144
+ ok: false
144
145
  };
145
146
  }
146
147
  return { ok: true };
@@ -155,24 +156,24 @@ function checkLength(node, max, min = 0) {
155
156
  const length = getLength(node);
156
157
  if (length < min) {
157
158
  return {
158
- ok: false,
159
159
  error: {
160
+ actual: length,
160
161
  code: "LENGTH_UNDERFLOW",
161
- message: `has length ${length} but requires at least ${min}`,
162
162
  expected: min,
163
- actual: length
164
- }
163
+ message: `has length ${length} but requires at least ${min}`
164
+ },
165
+ ok: false
165
166
  };
166
167
  }
167
168
  if (length > max) {
168
169
  return {
169
- ok: false,
170
170
  error: {
171
+ actual: length,
171
172
  code: "LENGTH_OVERFLOW",
172
- message: `has length ${length} but allows at most ${max}`,
173
173
  expected: max,
174
- actual: length
175
- }
174
+ message: `has length ${length} but allows at most ${max}`
175
+ },
176
+ ok: false
176
177
  };
177
178
  }
178
179
  return { ok: true };
@@ -180,48 +181,52 @@ function checkLength(node, max, min = 0) {
180
181
  function checkOptionality(node, optionality) {
181
182
  const code = optionality.toUpperCase();
182
183
  switch (code) {
183
- case OptionalityCode.Required:
184
+ case OptionalityCode.Required: {
184
185
  if (!node) {
185
186
  return {
186
- ok: false,
187
187
  error: {
188
188
  code: "MISSING",
189
- message: "is required but missing",
190
- expected: "R"
191
- }
189
+ expected: "R",
190
+ message: "is required but missing"
191
+ },
192
+ ok: false
192
193
  };
193
194
  }
194
195
  if (isEmptyNode(node)) {
195
196
  return {
196
- ok: false,
197
197
  error: {
198
198
  code: "EMPTY",
199
- message: "is required but empty",
200
- expected: "R"
201
- }
199
+ expected: "R",
200
+ message: "is required but empty"
201
+ },
202
+ ok: false
202
203
  };
203
204
  }
204
205
  return { ok: true };
205
- case OptionalityCode.NotSupported:
206
+ }
207
+ case OptionalityCode.NotSupported: {
206
208
  if (node && !isEmptyNode(node)) {
207
209
  return {
208
- ok: false,
209
210
  error: {
210
211
  code: "UNEXPECTED_CONTENT",
211
- message: "is not supported but present",
212
- expected: "X"
213
- }
212
+ expected: "X",
213
+ message: "is not supported but present"
214
+ },
215
+ ok: false
214
216
  };
215
217
  }
216
218
  return { ok: true };
219
+ }
217
220
  case OptionalityCode.RequiredOrEmpty:
218
221
  case OptionalityCode.Optional:
219
222
  case OptionalityCode.Conditional:
220
223
  case OptionalityCode.BackwardCompatible:
221
- case OptionalityCode.Withdrawn:
224
+ case OptionalityCode.Withdrawn: {
222
225
  return { ok: true };
223
- default:
226
+ }
227
+ default: {
224
228
  return { ok: true };
229
+ }
225
230
  }
226
231
  }
227
232
  export {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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":[]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/utils.ts","../src/constraints.ts"],"sourcesContent":["// -------------\n// Delimiters\n// -------------\n\nexport const DEFAULT_DELIMITERS = {\n component: \"^\",\n escape: \"\\\\\",\n field: \"|\",\n repetition: \"~\",\n segment: \"\\r\",\n subcomponent: \"&\",\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), 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 const nameLength =\n node.type === \"segment\" ? Buffer.byteLength(node.name, \"utf8\") : 0;\n\n return (\n nameLength +\n node.children.reduce((total, child) => total + getByteLength(child), 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), 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 const nameLength = node.type === \"segment\" ? node.name.length : 0;\n\n return (\n nameLength +\n node.children.reduce((total, child) => total + getLength(child), 0)\n );\n}\n","import type { Field, Nodes } from \"@rethinkhealth/hl7v2-ast\";\n\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 interface ValidationError {\n code: ValidationErrorCode;\n message: string;\n expected?: string | number | Array<string | number>;\n actual?: string | number | Array<string | number>;\n}\n\nexport interface ValidationSuccess {\n ok: true;\n}\n\nexport interface ValidationFailure {\n ok: false;\n error: ValidationError;\n}\n\nexport type ValidationResult = ValidationSuccess | ValidationFailure;\n\nexport const OptionalityCode = {\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 /**\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 /**\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 /**\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 /**\n * Required\n */\n Required: \"R\",\n\n /**\n * Required, but may be empty.\n *\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 /**\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 error: {\n actual: count,\n code: \"CARDINALITY_UNDERFLOW\",\n expected: min,\n message: `has ${count} repetitions but requires at least ${min}`,\n },\n ok: false,\n };\n }\n\n if (max !== \"*\" && count > max) {\n return {\n error: {\n actual: count,\n code: \"CARDINALITY_OVERFLOW\",\n expected: max,\n message: `has ${count} repetitions but allows at most ${max}`,\n },\n ok: false,\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 error: {\n actual: length,\n code: \"LENGTH_UNDERFLOW\",\n expected: min,\n message: `has length ${length} but requires at least ${min}`,\n },\n ok: false,\n };\n }\n\n if (length > max) {\n return {\n error: {\n actual: length,\n code: \"LENGTH_OVERFLOW\",\n expected: max,\n message: `has length ${length} but allows at most ${max}`,\n },\n ok: false,\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 error: {\n code: \"MISSING\",\n expected: \"R\",\n message: \"is required but missing\",\n },\n ok: false,\n };\n }\n if (isEmptyNode(node)) {\n return {\n error: {\n code: \"EMPTY\",\n expected: \"R\",\n message: \"is required but empty\",\n },\n ok: false,\n };\n }\n return { ok: true };\n }\n\n case OptionalityCode.NotSupported: {\n if (node && !isEmptyNode(node)) {\n return {\n error: {\n code: \"UNEXPECTED_CONTENT\",\n expected: \"X\",\n message: \"is not supported but present\",\n },\n ok: false,\n };\n }\n return { ok: true };\n }\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\n default: {\n return { ok: true };\n }\n }\n}\n"],"mappings":"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","names":[]}
package/dist/utils.d.ts CHANGED
@@ -2,11 +2,11 @@ import type { Nodes } from "@rethinkhealth/hl7v2-ast";
2
2
  /**
3
3
  * Utility: check if a node is semantically empty
4
4
  */
5
- export declare function isEmptyNode(node: Nodes | null | undefined): boolean;
5
+ export declare function isEmptyNode(node?: Nodes | null | undefined): boolean;
6
6
  /**
7
7
  * Calculate the byte length of any HL7v2 AST node.
8
8
  *
9
- * For literal nodes (Subcomponent, SegmentHeader), returns the UTF-8 byte length of the value.
9
+ * For literal nodes (Subcomponent), returns the UTF-8 byte length of the value.
10
10
  * For parent nodes, recursively calculates the length of all children. Delimiters are NOT included.
11
11
  *
12
12
  * @param node - The HL7v2 AST node to measure
@@ -18,11 +18,11 @@ export declare function isEmptyNode(node: Nodes | null | undefined): boolean;
18
18
  * const length = getByteLength(field); // e.g., 42
19
19
  * ```
20
20
  */
21
- export declare function getByteLength(node: Nodes | null | undefined): number;
21
+ export declare function getByteLength(node?: Nodes | null | undefined): number;
22
22
  /**
23
23
  * Calculate the string length of any HL7v2 AST node.
24
24
  *
25
- * For literal nodes (Subcomponent, SegmentHeader), returns `value.length`.
25
+ * For literal nodes (Subcomponent), returns `value.length`.
26
26
  * For parent nodes, recursively calculates the length of all children. Delimiters are NOT included.
27
27
  *
28
28
  * Note: Returns JavaScript string length (UTF-16 code units). For UTF-8 byte
@@ -37,4 +37,5 @@ export declare function getByteLength(node: Nodes | null | undefined): number;
37
37
  * const length = getLength(field); // e.g., 42
38
38
  * ```
39
39
  */
40
- export declare function getLength(node: Nodes | null | undefined): number;
40
+ export declare function getLength(node?: Nodes | null | undefined): number;
41
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAMtD;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CA2BpE;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAgBrE;AAMD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAejE"}
package/package.json CHANGED
@@ -1,50 +1,50 @@
1
1
  {
2
2
  "name": "@rethinkhealth/hl7v2-utils",
3
+ "version": "0.5.0",
3
4
  "description": "hl7v2 utilities",
4
- "version": "0.4.1",
5
+ "keywords": [
6
+ "health",
7
+ "healthcare",
8
+ "hl7",
9
+ "hl7v2",
10
+ "nodejs",
11
+ "typescript"
12
+ ],
13
+ "homepage": "https://www.rethinkhealth.io/hl7v2/docs",
5
14
  "license": "MIT",
6
15
  "author": {
7
16
  "name": "Melek Somai",
8
17
  "email": "melek@rethinkhealth.io"
9
18
  },
10
- "type": "module",
11
- "types": "./dist/index.d.ts",
19
+ "repository": "rethinkhealth/hl7v2.git",
12
20
  "files": [
13
21
  "dist"
14
22
  ],
23
+ "type": "module",
24
+ "types": "./dist/index.d.ts",
15
25
  "exports": {
16
26
  ".": "./dist/index.js"
17
27
  },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
18
31
  "devDependencies": {
19
32
  "@types/node": "24.10.1",
20
33
  "@types/unist": "^3.0.3",
21
- "@vitest/coverage-v8": "4.0.14",
34
+ "@vitest/coverage-v8": "4.0.18",
22
35
  "tsup": "8.5.1",
23
36
  "typescript": "^5.9.3",
24
37
  "unist-builder": "^4.0.0",
25
38
  "vfile": "^6.0.3",
26
39
  "vitest": "4.0.14",
27
- "@rethinkhealth/hl7v2-ast": "0.4.1",
40
+ "@rethinkhealth/hl7v2-ast": "0.5.0",
28
41
  "@rethinkhealth/testing": "0.0.2",
29
42
  "@rethinkhealth/tsconfig": "0.0.1"
30
43
  },
31
44
  "engines": {
32
45
  "node": ">=18"
33
46
  },
34
- "repository": "rethinkhealth/hl7v2.git",
35
- "homepage": "https://www.rethinkhealth.io/hl7v2/docs",
36
- "keywords": [
37
- "health",
38
- "healthcare",
39
- "hl7",
40
- "hl7v2",
41
- "nodejs",
42
- "typescript"
43
- ],
44
47
  "packageManager": "pnpm@10.14.0",
45
- "publishConfig": {
46
- "access": "public"
47
- },
48
48
  "scripts": {
49
49
  "build": "tsup && tsc --emitDeclarationOnly",
50
50
  "check-types": "tsc --noEmit",