@rethinkhealth/hl7v2-utils
v0.4.2
Published
hl7v2 utilities
Downloads
477
Maintainers
Readme
@rethinkhealth/hl7v2-utils
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.
This package provides core utilities including:
- Diagnostic reporting system for linters, validators, and transformers
- Standard HL7v2 delimiters
- AST node utility functions
- Conformance validation utilities (cardinality, length, optionality)
Installation
npm install @rethinkhealth/hl7v2-utilsAPI
report(file, rule, options?)
Report a diagnostic to a VFile. This function is the standard way to report issues in the HL7v2 ecosystem.
Parameters
file(VFile | null | undefined) - The VFile to report torule(Diagnostic) - The diagnostic rule definitionoptions(ReportOptions, optional)node(Node, optional) - The AST node related to the diagnosticcontext(Record<string, unknown>, optional) - Context data passed to the diagnostic's message function
Example
import { report } from '@rethinkhealth/hl7v2-utils';
import type { Diagnostic } from '@rethinkhealth/hl7v2-utils';
import { VFile } from 'vfile';
// Define a diagnostic rule
const requiredFieldRule: Diagnostic = {
type: 'lint',
namespace: 'field',
code: 'required',
title: 'Required Field Missing',
description: 'A required field is missing from the segment.',
severity: 'error',
message: (ctx) => `Field '${ctx.fieldPath}' is required`,
helpUrl: 'https://example.com/docs/required-field'
};
// Report the diagnostic
const file = new VFile();
report(file, requiredFieldRule, {
context: { fieldPath: 'PID-5' },
node: segmentNode
});getByteLength(node)
Calculate the byte length of any HL7v2 AST node. This utility efficiently computes the total serialized length including all children and separators (assumed to be 1 byte each).
Parameters
node(Nodes | null | undefined) - The AST node to measure
Returns
number - The total byte length when the node is serialized
Algorithm
- For literal nodes (Subcomponent, SegmentHeader): returns the byte length of the value using UTF-8 encoding (i.e.,
Buffer.byteLength(value, 'utf8')) - For parent nodes: recursively sums the byte length of all children plus 1 byte per separator between children
- Handles all node types: Root, Segment, Group, Field, FieldRepetition, Component, Subcomponent
Performance
The function is optimized for performance with O(n) time complexity where n is the total number of nodes in the tree. It uses a simple recursive approach with minimal overhead.
Example
import { getByteLength } from '@rethinkhealth/hl7v2-utils';
import type { Field } from '@rethinkhealth/hl7v2-ast';
const field: Field = {
type: 'field',
children: [
{
type: 'field-repetition',
children: [
{
type: 'component',
children: [
{ type: 'subcomponent', value: 'SMITH' },
{ type: 'subcomponent', value: 'JOHN' }
]
}
]
}
]
};
// Calculate: SMITH&JOHN = 5 + 1 + 4 = 10 bytes
const length = getByteLength(field); // Returns: 10Use Cases
- Validating field or message size constraints
- Memory allocation planning
- Message size reporting and analytics
- Performance optimization by avoiding full serialization
getLength(node)
Calculate the string length of any HL7v2 AST node. This utility efficiently computes the total serialized character length including all children and separators (assumed to be 1 character each).
Parameters
node(Nodes | null | undefined) - The AST node to measure
Returns
number - The total string length when the node is serialized
Algorithm
- For literal nodes (Subcomponent, SegmentHeader): returns
value.length(JavaScript string length) - For parent nodes: recursively sums the string length of all children plus 1 character per separator between children
- Handles all node types: Root, Segment, Group, Field, FieldRepetition, Component, Subcomponent
Important Note
Returns JavaScript string length (UTF-16 code units). For UTF-8 byte length (e.g., for wire protocol or size constraints), use getByteLength instead. These values differ for characters outside the ASCII range.
Performance
The function is optimized for performance with O(n) time complexity where n is the total number of nodes in the tree. It uses a simple recursive approach with minimal overhead.
Example
import { getLength } from '@rethinkhealth/hl7v2-utils';
import type { Field } from '@rethinkhealth/hl7v2-ast';
const field: Field = {
type: 'field',
children: [
{
type: 'field-repetition',
children: [
{
type: 'component',
children: [
{ type: 'subcomponent', value: 'SMITH' },
{ type: 'subcomponent', value: 'JOHN' }
]
}
]
}
]
};
// Calculate: SMITH&JOHN = 5 + 1 + 4 = 10 characters
const length = getLength(field); // Returns: 10Use Cases
- UI display and text formatting
- Character-based validation rules
- String manipulation operations
- Quick length checks where byte-level precision is not required
Comparison with getByteLength
import { getLength, getByteLength } from '@rethinkhealth/hl7v2-utils';
const subcomponent = { type: 'subcomponent', value: 'café' };
getLength(subcomponent); // Returns: 4 (4 characters)
getByteLength(subcomponent); // Returns: 5 (5 bytes in UTF-8: c-a-f-C3-A9)Conformance Utilities
The package provides stateless, composable functions to validate HL7v2 AST nodes against constraints like optionality (usage), cardinality, and length.
ValidationResult
All conformance functions return a ValidationResult object:
type ValidationResult =
| { ok: true }
| {
ok: false;
error: {
code: string;
message: string;
expected?: string | number | Array<string | number>;
actual?: string | number | Array<string | number>;
}
};checkOptionality(node, optionality)
Checks if a node satisfies the optionality (usage) constraint.
- node:
Nodes | undefined- The AST node to check. - optionality:
string- The usage code (e.g., 'R', 'O', 'X'). - Returns:
ValidationResult
import { checkOptionality } from '@rethinkhealth/hl7v2-utils';
// 'R' (Required), 'RE' (Required or Empty), 'O' (Optional), 'X' (Not Supported)
const result = checkOptionality(myFieldNode, 'R');
if (!result.ok) {
console.error(result.error.message); // "is required but missing"
}checkCardinality(node, min, max)
Checks if a field has the correct number of repetitions.
- node:
Field | undefined- The field node to check. - min:
number- Minimum repetitions. - max:
number | '*'- Maximum repetitions. - Returns:
ValidationResult
import { checkCardinality } from '@rethinkhealth/hl7v2-utils';
// Field must repeat between 1 and 5 times
const result = checkCardinality(myFieldNode, 1, 5);checkLength(node, max, min?)
Checks if the content of a node falls within the minimum and maximum length.
- node:
Nodes | undefined- The node to check (length is calculated recursively). - max:
number- Maximum length. - min:
number(optional, default: 0) - Minimum length. - Returns:
ValidationResult
import { checkLength } from '@rethinkhealth/hl7v2-utils';
// Content length must be between 1 and 10 characters
const result = checkLength(myNode, 10, 1);
// Content length must be at most 10 characters (min defaults to 0)
const result2 = checkLength(myNode, 10);Contributing
We welcome contributions! Please see our Contributing Guide for more details.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Code of Conduct
To ensure a welcoming and positive environment, we have a Code of Conduct that all contributors and participants are expected to adhere to.
License
Copyright 2025 Rethink Health, SUARL. All rights reserved.
This program is licensed to you under the terms of the MIT License. This program is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file for details.
