@rethinkhealth/hl7v2-parser 0.2.4 → 0.2.5

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/dist/index.js CHANGED
@@ -1,3 +1,48 @@
1
+ // src/parser.ts
2
+ import { DEFAULT_DELIMITERS } from "@rethinkhealth/hl7v2-utils";
3
+
4
+ // src/preprocessor.ts
5
+ var stripBOM = (ctx) => {
6
+ if (ctx.input.charCodeAt(0) === 65279) {
7
+ ctx.input = ctx.input.slice(1);
8
+ }
9
+ return ctx;
10
+ };
11
+ var normalizeNewlines = (ctx) => {
12
+ ctx.input = ctx.input.replace(/\r?\n/g, "\r");
13
+ return ctx;
14
+ };
15
+ var detectDelimiters = (ctx) => {
16
+ if (ctx.input.startsWith("MSH")) {
17
+ const fieldDelim = ctx.input.charAt(3) || "|";
18
+ const enc = ctx.input.slice(4, 8);
19
+ const component = enc.charAt(0) || "^";
20
+ const repetition = enc.charAt(1) || "~";
21
+ const _escape = enc.charAt(2) || "\\";
22
+ const subcomponent = enc.charAt(3) || "&";
23
+ ctx.delimiters = {
24
+ field: fieldDelim,
25
+ component,
26
+ repetition,
27
+ escape: _escape,
28
+ subcomponent,
29
+ segment: "\r"
30
+ };
31
+ }
32
+ return ctx;
33
+ };
34
+ var defaultPreprocessors = [
35
+ stripBOM,
36
+ normalizeNewlines,
37
+ detectDelimiters
38
+ ];
39
+ function runPreprocessors(ctx, steps) {
40
+ for (const step of steps) {
41
+ ctx = step(ctx);
42
+ }
43
+ return ctx;
44
+ }
45
+
1
46
  // src/processor.ts
2
47
  function createParserCore() {
3
48
  const root = { type: "root", children: [] };
@@ -155,9 +200,6 @@ function parseHL7v2FromIterator(tokens) {
155
200
  }
156
201
 
157
202
  // src/tokenizer.ts
158
- import {
159
- DEFAULT_DELIMITERS
160
- } from "@rethinkhealth/hl7v2-utils";
161
203
  var HL7v2Tokenizer = class {
162
204
  input = "";
163
205
  i = 0;
@@ -168,9 +210,9 @@ var HL7v2Tokenizer = class {
168
210
  didMshBootstrap = false;
169
211
  pendingBootstrap = null;
170
212
  // queue to emit TEXT('MSH'), FIELD_DELIM, TEXT('^~\\&')
171
- reset(input, opts) {
172
- this.input = input;
173
- this.delims = opts.delimiters || DEFAULT_DELIMITERS;
213
+ reset(ctx) {
214
+ this.input = ctx.input;
215
+ this.delims = ctx.delimiters;
174
216
  this.i = 0;
175
217
  this.line = 1;
176
218
  this.col = 1;
@@ -178,11 +220,13 @@ var HL7v2Tokenizer = class {
178
220
  this.pendingBootstrap = null;
179
221
  if (this.input.startsWith("MSH")) {
180
222
  const msh = this._slice(0, 3);
223
+ const msh1 = this._slice(3, 4);
181
224
  const msh2 = this._slice(4, 8);
182
225
  this.pendingBootstrap = [
183
226
  { kind: "TEXT", value: msh, advance: msh.length },
184
- { kind: "FIELD_DELIM", advance: 1 },
185
- // consume the single field delimiter char at index 3
227
+ { kind: "FIELD_DELIM", advance: 0 },
228
+ { kind: "TEXT", value: msh1, advance: msh1.length },
229
+ { kind: "FIELD_DELIM", advance: 0 },
186
230
  { kind: "TEXT", value: msh2, advance: msh2.length }
187
231
  ];
188
232
  }
@@ -304,62 +348,19 @@ function* iterateTokenizerSync(t) {
304
348
 
305
349
  // src/parser.ts
306
350
  function parseHL7v2(input, opts) {
351
+ let ctx = {
352
+ input,
353
+ delimiters: opts.delimiters || DEFAULT_DELIMITERS
354
+ };
355
+ ctx = runPreprocessors(ctx, opts.preprocess || defaultPreprocessors);
307
356
  const tokenizer = new HL7v2Tokenizer();
308
- tokenizer.reset(input, opts);
357
+ tokenizer.reset(ctx);
309
358
  return parseHL7v2FromIterator(iterateTokenizerSync(tokenizer));
310
359
  }
311
360
  var hl7v2Parser = function(options = {}) {
312
- const self = this;
313
- self.parser = (value) => parseHL7v2(value, options);
361
+ this.parser = (document) => parseHL7v2(document, options);
314
362
  };
315
363
  var parser_default = hl7v2Parser;
316
-
317
- // src/preprocessor.ts
318
- var stripBOM = (ctx) => {
319
- if (ctx.input.charCodeAt(0) === 65279) {
320
- ctx.input = ctx.input.slice(1);
321
- }
322
- return ctx;
323
- };
324
- var normalizeNewlines = (ctx) => {
325
- ctx.input = ctx.input.replace(/\r?\n/g, "\r");
326
- return ctx;
327
- };
328
- var detectDelimiters = (ctx) => {
329
- if (ctx.input.startsWith("MSH")) {
330
- const fieldDelim = ctx.input.charAt(3) || "|";
331
- const enc = ctx.input.slice(4, 8);
332
- const component = enc.charAt(0) || "^";
333
- const repetition = enc.charAt(1) || "~";
334
- const _escape = enc.charAt(2) || "\\";
335
- const subcomponent = enc.charAt(3) || "&";
336
- ctx.options.delimiters = {
337
- field: fieldDelim,
338
- component,
339
- repetition,
340
- escape: _escape,
341
- subcomponent,
342
- segment: "\r"
343
- };
344
- }
345
- return ctx;
346
- };
347
- var defaultPreprocessors = [
348
- stripBOM,
349
- normalizeNewlines,
350
- detectDelimiters
351
- ];
352
- function runPreprocessors(raw, opts = {}, steps = defaultPreprocessors) {
353
- let ctx = {
354
- input: raw,
355
- options: opts,
356
- metadata: {}
357
- };
358
- for (const step of steps) {
359
- ctx = step(ctx);
360
- }
361
- return ctx;
362
- }
363
364
  export {
364
365
  HL7v2Tokenizer,
365
366
  defaultPreprocessors,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/processor.ts","../src/tokenizer.ts","../src/utils.ts","../src/parser.ts","../src/preprocessor.ts"],"sourcesContent":["// src/parser.ts\n\nimport type {\n Component,\n Field,\n FieldRepetition,\n Root,\n Segment,\n Subcomponent,\n} from '@rethinkhealth/hl7v2-ast';\nimport type { Token } from './types';\n\n// Shared core: process a single token into mutable parse state\nfunction createParserCore() {\n const root: Root = { type: 'root', children: [] };\n\n let seg: Segment | null = null;\n let field: Field | null = null;\n let rep: FieldRepetition | null = null;\n let comp: Component | null = null;\n let currentSub: Subcomponent | null = null;\n let segmentHasContent = false;\n\n const openSegment = () => {\n seg = { type: 'segment', children: [] };\n root.children.push(seg);\n field = null;\n rep = null;\n comp = null;\n currentSub = null;\n segmentHasContent = false;\n };\n\n const ensureSegment = () => {\n if (!seg) {\n openSegment();\n }\n };\n\n const openField = () => {\n ensureSegment();\n field = { type: 'field', children: [] };\n // biome-ignore lint/style/noNonNullAssertion: seg is ensured above\n seg!.children.push(field);\n rep = { type: 'field-repetition', children: [] };\n field.children.push(rep);\n comp = { type: 'component', children: [] };\n rep.children.push(comp);\n currentSub = null;\n segmentHasContent = true;\n };\n\n const openRepetition = () => {\n if (!field) {\n openField();\n }\n rep = { type: 'field-repetition', children: [] };\n // biome-ignore lint/style/noNonNullAssertion: field is ensured above\n field!.children.push(rep);\n comp = { type: 'component', children: [] };\n rep.children.push(comp);\n currentSub = null;\n segmentHasContent = true;\n };\n\n const openComponent = () => {\n if (!field) {\n openField();\n }\n if (!rep) {\n rep = { type: 'field-repetition', children: [] };\n // biome-ignore lint/style/noNonNullAssertion: field is ensured above\n field!.children.push(rep);\n }\n comp = { type: 'component', children: [] };\n // biome-ignore lint/style/noNonNullAssertion: rep is ensured above\n rep!.children.push(comp);\n currentSub = null;\n segmentHasContent = true;\n };\n\n const ensureForText = () => {\n if (!field) {\n openField();\n }\n if (!rep) {\n openRepetition();\n }\n if (!comp) {\n openComponent();\n }\n if (!currentSub) {\n currentSub = { type: 'subcomponent', value: '' };\n // biome-ignore lint/style/noNonNullAssertion: comp is ensured above\n comp!.children.push(currentSub);\n segmentHasContent = true;\n }\n };\n\n const processToken = (tok: Token) => {\n switch (tok.type) {\n case 'SEGMENT_END': {\n dropTrailingEmptyFieldIfPresent();\n // Close current segment (if any) and reset; do not auto-open next segment\n seg = null;\n field = null;\n rep = null;\n comp = null;\n currentSub = null;\n segmentHasContent = false;\n return;\n }\n case 'FIELD_DELIM': {\n // Leading field delimiter implies an empty first field\n if (!field) {\n // Open an empty first field and record an empty subcomponent slot\n openField();\n // biome-ignore lint/style/noNonNullAssertion: comp is initialized in openField\n comp!.children.push({ type: 'subcomponent', value: '' });\n segmentHasContent = true;\n }\n openField();\n return;\n }\n case 'REPETITION_DELIM': {\n if (!field) {\n openField();\n }\n openRepetition();\n return;\n }\n case 'COMPONENT_DELIM': {\n openComponent();\n return;\n }\n case 'SUBCOMP_DELIM': {\n if (!comp) {\n openComponent();\n }\n // Start a new empty subcomponent slot\n currentSub = { type: 'subcomponent', value: '' };\n // biome-ignore lint/style/noNonNullAssertion: comp is ensured above\n comp!.children.push(currentSub);\n segmentHasContent = true;\n return;\n }\n case 'TEXT': {\n const val = tok.value ?? '';\n ensureForText();\n // biome-ignore lint/style/noNonNullAssertion: ensured above\n currentSub!.value += val;\n segmentHasContent = true;\n return;\n }\n default: {\n throw new Error(`Unexpected token type: ${tok.type}`);\n }\n }\n };\n\n // Do not pre-open a segment; lazily open upon first non-SEGMENT_END token.\n\n const finalize = () => {\n // Handle input that ends without an explicit segment delimiter as above.\n dropTrailingEmptyFieldIfPresent();\n if (seg && !segmentHasContent) {\n // Drop trailing empty segment if no content was added\n root.children.pop();\n }\n return root;\n };\n\n function dropTrailingEmptyFieldIfPresent() {\n if (!seg || seg.children.length === 0) {\n return;\n }\n // Drop only the final trailing empty field (created by the last delimiter),\n // preserving any intentional empty fields immediately before it.\n const lastField = seg.children.at(-1) as Field;\n const hasAnySubcomponents = lastField.children.some((r) =>\n r.children.some((c) => c.children.length > 0)\n );\n if (!hasAnySubcomponents) {\n seg.children.pop();\n }\n }\n\n return { processToken, finalize, root };\n}\n\n// Sync convenience wrapper over a sync Iterable token source\nexport function parseHL7v2FromIterator(tokens: Iterable<Token>): Root {\n const core = createParserCore();\n for (const tok of tokens) {\n core.processToken(tok);\n }\n return core.finalize();\n}\n","// src/tokenizer.ts\nimport {\n DEFAULT_DELIMITERS,\n type HL7v2Delimiters,\n} from '@rethinkhealth/hl7v2-utils';\nimport type {\n ParseOptions,\n Position,\n Token,\n Tokenizer,\n TokenType,\n} from './types';\n\nexport class HL7v2Tokenizer implements Tokenizer, Iterable<Token> {\n private input = '';\n private i = 0;\n private line = 1;\n private col = 1;\n private delims!: HL7v2Delimiters;\n\n // Only-run-once MSH bootstrap at the start of the file\n private didMshBootstrap = false;\n private pendingBootstrap: null | Array<\n | { kind: 'TEXT'; value: string; advance: number }\n | { kind: 'FIELD_DELIM'; advance: number }\n > = null; // queue to emit TEXT('MSH'), FIELD_DELIM, TEXT('^~\\\\&')\n\n reset(input: string, opts: ParseOptions) {\n this.input = input;\n this.delims = opts.delimiters || DEFAULT_DELIMITERS;\n this.i = 0;\n this.line = 1;\n this.col = 1;\n this.didMshBootstrap = false;\n this.pendingBootstrap = null;\n\n // Prepare a one-time bootstrap if file starts with MSH\n if (this.input.startsWith('MSH')) {\n // Precompute MSH and MSH.2; MSH.1 is the field delimiter char at index 3\n const msh = this._slice(0, 3);\n const msh2 = this._slice(4, 8); // may be shorter than 4 if truncated\n this.pendingBootstrap = [\n { kind: 'TEXT', value: msh, advance: msh.length },\n { kind: 'FIELD_DELIM', advance: 1 }, // consume the single field delimiter char at index 3\n { kind: 'TEXT', value: msh2, advance: msh2.length },\n ];\n // NOTE: we have not advanced indices yet; we will as we emit tokens\n }\n }\n\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: The cognitive complexity of this method is justified because it must handle the HL7v2 MSH segment bootstrap logic and multiple tokenization cases in a single method for performance and maintainability.\n next(): Token | null {\n const s = this.input;\n const n = s.length;\n if (this.i >= n && !this.pendingBootstrap?.length) {\n return null;\n }\n\n const start = { offset: this.i, line: this.line, column: this.col };\n\n // ---- One-time MSH bootstrap at file start ----\n if (!this.didMshBootstrap && this.pendingBootstrap) {\n const step = this.pendingBootstrap.shift();\n if (step) {\n if (step.kind === 'TEXT') {\n const take = Math.min(step.advance, n - this.i);\n const out = step.value.slice(0, take);\n this._fastAdvance(out);\n if (this.pendingBootstrap.length === 0) {\n this.pendingBootstrap = null;\n this.didMshBootstrap = true;\n }\n return this._tok('TEXT', out, start);\n }\n // FIELD_DELIM: advance exactly one char (the delimiter) and emit a FIELD_DELIM token\n this._advance(Math.min(step.advance, n - this.i));\n if (this.pendingBootstrap.length === 0) {\n this.pendingBootstrap = null;\n this.didMshBootstrap = true;\n }\n return this._tok('FIELD_DELIM', undefined, start);\n }\n }\n\n // ---- Normal tokenization (delimiters + text) ----\n if (this.i >= n) {\n return null;\n }\n const ch = s.charAt(this.i);\n\n if (ch === this.delims.segment) {\n this._advance(1, true);\n return this._tok('SEGMENT_END', undefined, start);\n }\n if (ch === this.delims.field) {\n this._advance(1);\n return this._tok('FIELD_DELIM', undefined, start);\n }\n if (ch === this.delims.repetition) {\n this._advance(1);\n return this._tok('REPETITION_DELIM', undefined, start);\n }\n if (ch === this.delims.component) {\n this._advance(1);\n return this._tok('COMPONENT_DELIM', undefined, start);\n }\n if (ch === this.delims.subcomponent) {\n this._advance(1);\n return this._tok('SUBCOMP_DELIM', undefined, start);\n }\n\n // TEXT until next delimiter or end\n let j = this.i;\n const seg = this.delims.segment,\n fld = this.delims.field,\n rep = this.delims.repetition,\n cmp = this.delims.component,\n sub = this.delims.subcomponent;\n\n while (j < s.length) {\n const c = s.charAt(j);\n if (c === seg || c === fld || c === rep || c === cmp || c === sub) {\n break;\n }\n j++;\n }\n\n const val = s.slice(this.i, j);\n this._fastAdvance(val);\n return this._tok('TEXT', val, start);\n }\n\n // ---- helpers ----\n private _slice(start: number, end: number): string {\n return this.input.slice(start, Math.min(end, this.input.length));\n }\n\n private _advance(n: number, isNewline = false) {\n this.i += n;\n if (isNewline) {\n this.line += 1;\n this.col = 1;\n } else {\n this.col += n;\n }\n }\n\n private _fastAdvance(chunk: string) {\n const parts = chunk.split('\\r');\n if (parts.length > 1) {\n this.line += parts.length - 1;\n this.col = (parts.at(-1)?.length ?? 0) + 1;\n } else {\n this.col += chunk.length;\n }\n this.i += chunk.length;\n }\n\n private _tok(\n type: TokenType,\n value: string | undefined,\n start: Position['start']\n ): Token {\n const end = { offset: this.i, line: this.line, column: this.col };\n return { type, value, position: { start, end } };\n }\n\n // Iterable protocol (sync)\n [Symbol.iterator](): Iterator<Token> {\n return {\n next: () => {\n const t = this.next();\n if (t == null) {\n return { done: true, value: undefined as unknown as Token };\n }\n return { done: false, value: t };\n },\n };\n }\n\n // Async iteration support removed to keep the API synchronous.\n}\n","import type { Token, Tokenizer } from './types';\n\nexport function* iterateTokenizerSync(t: Tokenizer): Iterable<Token> {\n for (let tok = t.next(); tok; tok = t.next()) {\n yield tok;\n }\n}\n\n// Removed async stream support; the parser now operates synchronously only.\n","import type { Root } from '@rethinkhealth/hl7v2-ast';\nimport type { Plugin } from 'unified';\nimport { parseHL7v2FromIterator } from './processor';\nimport { HL7v2Tokenizer } from './tokenizer';\nimport type { ParseOptions } from './types';\nimport { iterateTokenizerSync } from './utils';\n\n// Back-compat convenience API: parse from string using the built-in tokenizer (sync)\nexport function parseHL7v2(input: string, opts: ParseOptions): Root {\n const tokenizer = new HL7v2Tokenizer();\n tokenizer.reset(input, opts);\n return parseHL7v2FromIterator(iterateTokenizerSync(tokenizer));\n}\n\nconst hl7v2Parser: Plugin<[ParseOptions?], string, Root> = function (\n options = {}\n) {\n const self = this as { parser?: (value: string) => Root };\n self.parser = (value: string) => parseHL7v2(value, options);\n};\n\nexport default hl7v2Parser;\n","import type { ParseOptions, ParserContext } from './types';\n\n/**\n * A preprocessing step: takes a ParserContext, mutates or replaces it.\n */\nexport type PreprocessorStep = (ctx: ParserContext) => ParserContext;\n\n/**\n * Step: strip UTF-8 BOM.\n */\nexport const stripBOM: PreprocessorStep = (ctx) => {\n if (ctx.input.charCodeAt(0) === 0xfe_ff) {\n ctx.input = ctx.input.slice(1);\n }\n return ctx;\n};\n\n/**\n * Step: normalize newlines to CR (\\r).\n */\nexport const normalizeNewlines: PreprocessorStep = (ctx) => {\n ctx.input = ctx.input.replace(/\\r?\\n/g, '\\r');\n return ctx;\n};\n\n/**\n * Step: auto-detect delimiters from MSH.\n */\nexport const detectDelimiters: PreprocessorStep = (ctx) => {\n if (ctx.input.startsWith('MSH')) {\n const fieldDelim = ctx.input.charAt(3) || '|';\n const enc = ctx.input.slice(4, 8);\n const component = enc.charAt(0) || '^';\n const repetition = enc.charAt(1) || '~';\n const _escape = enc.charAt(2) || '\\\\';\n const subcomponent = enc.charAt(3) || '&';\n\n ctx.options.delimiters = {\n field: fieldDelim,\n component,\n repetition,\n escape: _escape,\n subcomponent,\n segment: '\\r',\n };\n }\n return ctx;\n};\n\n/**\n * Default preprocessing pipeline.\n */\nexport const defaultPreprocessors: PreprocessorStep[] = [\n stripBOM,\n normalizeNewlines,\n detectDelimiters,\n];\n\n/**\n * Run the pipeline to initialize ParserContext.\n */\nexport function runPreprocessors(\n raw: string,\n opts: ParseOptions = {},\n steps: PreprocessorStep[] = defaultPreprocessors\n): ParserContext {\n let ctx: ParserContext = {\n input: raw,\n options: opts,\n metadata: {},\n };\n\n for (const step of steps) {\n ctx = step(ctx);\n }\n\n return ctx;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/parser.ts","../src/preprocessor.ts","../src/processor.ts","../src/tokenizer.ts","../src/utils.ts"],"sourcesContent":["import type { Root } from '@rethinkhealth/hl7v2-ast';\nimport { DEFAULT_DELIMITERS } from '@rethinkhealth/hl7v2-utils';\nimport type { Plugin } from 'unified';\nimport { defaultPreprocessors, runPreprocessors } from './preprocessor';\nimport { parseHL7v2FromIterator } from './processor';\nimport { HL7v2Tokenizer } from './tokenizer';\nimport type { ParseOptions, ParserContext } from './types';\nimport { iterateTokenizerSync } from './utils';\n\nexport function parseHL7v2(input: string, opts: ParseOptions): Root {\n let ctx: ParserContext = {\n input,\n delimiters: opts.delimiters || DEFAULT_DELIMITERS,\n };\n // Run preprocessing\n ctx = runPreprocessors(ctx, opts.preprocess || defaultPreprocessors);\n // Run tokenizer\n const tokenizer = new HL7v2Tokenizer();\n // Reset tokenizer.\n tokenizer.reset(ctx);\n // Parse\n return parseHL7v2FromIterator(iterateTokenizerSync(tokenizer));\n}\n\nconst hl7v2Parser: Plugin<[ParseOptions?], string, Root> = function (\n options = {}\n) {\n this.parser = (document: string) => parseHL7v2(document, options);\n};\n\nexport default hl7v2Parser;\n","import type { ParserContext, PreprocessorStep } from './types';\n\n// PreprocessorStep is declared in `types.ts` to avoid circular imports\n\n/**\n * Step: strip UTF-8 BOM.\n */\nexport const stripBOM: PreprocessorStep = (ctx) => {\n if (ctx.input.charCodeAt(0) === 0xfe_ff) {\n ctx.input = ctx.input.slice(1);\n }\n return ctx;\n};\n\n/**\n * Step: normalize newlines to CR (\\r).\n */\nexport const normalizeNewlines: PreprocessorStep = (ctx) => {\n ctx.input = ctx.input.replace(/\\r?\\n/g, '\\r');\n return ctx;\n};\n\n/**\n * Step: auto-detect delimiters from MSH.\n */\nexport const detectDelimiters: PreprocessorStep = (ctx) => {\n if (ctx.input.startsWith('MSH')) {\n const fieldDelim = ctx.input.charAt(3) || '|';\n const enc = ctx.input.slice(4, 8);\n const component = enc.charAt(0) || '^';\n const repetition = enc.charAt(1) || '~';\n const _escape = enc.charAt(2) || '\\\\';\n const subcomponent = enc.charAt(3) || '&';\n\n ctx.delimiters = {\n field: fieldDelim,\n component,\n repetition,\n escape: _escape,\n subcomponent,\n segment: '\\r',\n };\n }\n return ctx;\n};\n\n/**\n * Default preprocessing pipeline.\n */\nexport const defaultPreprocessors: PreprocessorStep[] = [\n stripBOM,\n normalizeNewlines,\n detectDelimiters,\n];\n\n/**\n * Run the pipeline to initialize ParserContext.\n */\nexport function runPreprocessors(\n ctx: ParserContext,\n steps: PreprocessorStep[]\n): ParserContext {\n for (const step of steps) {\n // biome-ignore lint/style/noParameterAssign: this is necessary to keep no-copy\n ctx = step(ctx);\n }\n\n return ctx;\n}\n","// src/parser.ts\n\nimport type {\n Component,\n Field,\n FieldRepetition,\n Root,\n Segment,\n Subcomponent,\n} from '@rethinkhealth/hl7v2-ast';\nimport type { Token } from './types';\n\n// Shared core: process a single token into mutable parse state\nfunction createParserCore() {\n const root: Root = { type: 'root', children: [] };\n\n let seg: Segment | null = null;\n let field: Field | null = null;\n let rep: FieldRepetition | null = null;\n let comp: Component | null = null;\n let currentSub: Subcomponent | null = null;\n let segmentHasContent = false;\n\n const openSegment = () => {\n seg = { type: 'segment', children: [] };\n root.children.push(seg);\n field = null;\n rep = null;\n comp = null;\n currentSub = null;\n segmentHasContent = false;\n };\n\n const ensureSegment = () => {\n if (!seg) {\n openSegment();\n }\n };\n\n const openField = () => {\n ensureSegment();\n field = { type: 'field', children: [] };\n // biome-ignore lint/style/noNonNullAssertion: seg is ensured above\n seg!.children.push(field);\n rep = { type: 'field-repetition', children: [] };\n field.children.push(rep);\n comp = { type: 'component', children: [] };\n rep.children.push(comp);\n currentSub = null;\n segmentHasContent = true;\n };\n\n const openRepetition = () => {\n if (!field) {\n openField();\n }\n rep = { type: 'field-repetition', children: [] };\n // biome-ignore lint/style/noNonNullAssertion: field is ensured above\n field!.children.push(rep);\n comp = { type: 'component', children: [] };\n rep.children.push(comp);\n currentSub = null;\n segmentHasContent = true;\n };\n\n const openComponent = () => {\n if (!field) {\n openField();\n }\n if (!rep) {\n rep = { type: 'field-repetition', children: [] };\n // biome-ignore lint/style/noNonNullAssertion: field is ensured above\n field!.children.push(rep);\n }\n comp = { type: 'component', children: [] };\n // biome-ignore lint/style/noNonNullAssertion: rep is ensured above\n rep!.children.push(comp);\n currentSub = null;\n segmentHasContent = true;\n };\n\n const ensureForText = () => {\n if (!field) {\n openField();\n }\n if (!rep) {\n openRepetition();\n }\n if (!comp) {\n openComponent();\n }\n if (!currentSub) {\n currentSub = { type: 'subcomponent', value: '' };\n // biome-ignore lint/style/noNonNullAssertion: comp is ensured above\n comp!.children.push(currentSub);\n segmentHasContent = true;\n }\n };\n\n const processToken = (tok: Token) => {\n switch (tok.type) {\n case 'SEGMENT_END': {\n dropTrailingEmptyFieldIfPresent();\n // Close current segment (if any) and reset; do not auto-open next segment\n seg = null;\n field = null;\n rep = null;\n comp = null;\n currentSub = null;\n segmentHasContent = false;\n return;\n }\n case 'FIELD_DELIM': {\n // Leading field delimiter implies an empty first field\n if (!field) {\n // Open an empty first field and record an empty subcomponent slot\n openField();\n // biome-ignore lint/style/noNonNullAssertion: comp is initialized in openField\n comp!.children.push({ type: 'subcomponent', value: '' });\n segmentHasContent = true;\n }\n openField();\n return;\n }\n case 'REPETITION_DELIM': {\n if (!field) {\n openField();\n }\n openRepetition();\n return;\n }\n case 'COMPONENT_DELIM': {\n openComponent();\n return;\n }\n case 'SUBCOMP_DELIM': {\n if (!comp) {\n openComponent();\n }\n // Start a new empty subcomponent slot\n currentSub = { type: 'subcomponent', value: '' };\n // biome-ignore lint/style/noNonNullAssertion: comp is ensured above\n comp!.children.push(currentSub);\n segmentHasContent = true;\n return;\n }\n case 'TEXT': {\n const val = tok.value ?? '';\n ensureForText();\n // biome-ignore lint/style/noNonNullAssertion: ensured above\n currentSub!.value += val;\n segmentHasContent = true;\n return;\n }\n default: {\n throw new Error(`Unexpected token type: ${tok.type}`);\n }\n }\n };\n\n // Do not pre-open a segment; lazily open upon first non-SEGMENT_END token.\n\n const finalize = () => {\n // Handle input that ends without an explicit segment delimiter as above.\n dropTrailingEmptyFieldIfPresent();\n if (seg && !segmentHasContent) {\n // Drop trailing empty segment if no content was added\n root.children.pop();\n }\n return root;\n };\n\n function dropTrailingEmptyFieldIfPresent() {\n if (!seg || seg.children.length === 0) {\n return;\n }\n // Drop only the final trailing empty field (created by the last delimiter),\n // preserving any intentional empty fields immediately before it.\n const lastField = seg.children.at(-1) as Field;\n const hasAnySubcomponents = lastField.children.some((r) =>\n r.children.some((c) => c.children.length > 0)\n );\n if (!hasAnySubcomponents) {\n seg.children.pop();\n }\n }\n\n return { processToken, finalize, root };\n}\n\n// Sync convenience wrapper over a sync Iterable token source\nexport function parseHL7v2FromIterator(tokens: Iterable<Token>): Root {\n const core = createParserCore();\n for (const tok of tokens) {\n core.processToken(tok);\n }\n return core.finalize();\n}\n","// src/tokenizer.ts\nimport type { HL7v2Delimiters } from '@rethinkhealth/hl7v2-utils';\nimport type {\n ParserContext,\n Position,\n Token,\n Tokenizer,\n TokenType,\n} from './types';\n\nexport class HL7v2Tokenizer implements Tokenizer, Iterable<Token> {\n private input = '';\n private i = 0;\n private line = 1;\n private col = 1;\n private delims!: HL7v2Delimiters;\n\n // Only-run-once MSH bootstrap at the start of the file\n private didMshBootstrap = false;\n private pendingBootstrap: null | Array<\n | { kind: 'TEXT'; value: string; advance: number }\n | { kind: 'FIELD_DELIM'; advance: number }\n > = null; // queue to emit TEXT('MSH'), FIELD_DELIM, TEXT('^~\\\\&')\n\n reset(ctx: ParserContext) {\n this.input = ctx.input;\n this.delims = ctx.delimiters;\n this.i = 0;\n this.line = 1;\n this.col = 1;\n this.didMshBootstrap = false;\n this.pendingBootstrap = null;\n\n // Prepare a one-time bootstrap if file starts with MSH\n if (this.input.startsWith('MSH')) {\n // Precompute MSH and MSH.2; MSH.1 is the field delimiter char at index 3\n const msh = this._slice(0, 3);\n const msh1 = this._slice(3, 4); // the field delimiter char at index 3\n const msh2 = this._slice(4, 8); // may be shorter than 4 if truncated\n this.pendingBootstrap = [\n { kind: 'TEXT', value: msh, advance: msh.length },\n { kind: 'FIELD_DELIM', advance: 0 },\n { kind: 'TEXT', value: msh1, advance: msh1.length },\n { kind: 'FIELD_DELIM', advance: 0 },\n { kind: 'TEXT', value: msh2, advance: msh2.length },\n ];\n // NOTE: we have not advanced indices yet; we will as we emit tokens\n }\n }\n\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: The cognitive complexity of this method is justified because it must handle the HL7v2 MSH segment bootstrap logic and multiple tokenization cases in a single method for performance and maintainability.\n next(): Token | null {\n const s = this.input;\n const n = s.length;\n if (this.i >= n && !this.pendingBootstrap?.length) {\n return null;\n }\n\n const start = { offset: this.i, line: this.line, column: this.col };\n\n // ---- One-time MSH bootstrap at file start ----\n if (!this.didMshBootstrap && this.pendingBootstrap) {\n const step = this.pendingBootstrap.shift();\n if (step) {\n if (step.kind === 'TEXT') {\n const take = Math.min(step.advance, n - this.i);\n const out = step.value.slice(0, take);\n this._fastAdvance(out);\n if (this.pendingBootstrap.length === 0) {\n this.pendingBootstrap = null;\n this.didMshBootstrap = true;\n }\n return this._tok('TEXT', out, start);\n }\n // FIELD_DELIM: advance exactly one char (the delimiter) and emit a FIELD_DELIM token\n this._advance(Math.min(step.advance, n - this.i));\n if (this.pendingBootstrap.length === 0) {\n this.pendingBootstrap = null;\n this.didMshBootstrap = true;\n }\n return this._tok('FIELD_DELIM', undefined, start);\n }\n }\n\n // ---- Normal tokenization (delimiters + text) ----\n if (this.i >= n) {\n return null;\n }\n const ch = s.charAt(this.i);\n\n if (ch === this.delims.segment) {\n this._advance(1, true);\n return this._tok('SEGMENT_END', undefined, start);\n }\n if (ch === this.delims.field) {\n this._advance(1);\n return this._tok('FIELD_DELIM', undefined, start);\n }\n if (ch === this.delims.repetition) {\n this._advance(1);\n return this._tok('REPETITION_DELIM', undefined, start);\n }\n if (ch === this.delims.component) {\n this._advance(1);\n return this._tok('COMPONENT_DELIM', undefined, start);\n }\n if (ch === this.delims.subcomponent) {\n this._advance(1);\n return this._tok('SUBCOMP_DELIM', undefined, start);\n }\n\n // TEXT until next delimiter or end\n let j = this.i;\n const seg = this.delims.segment,\n fld = this.delims.field,\n rep = this.delims.repetition,\n cmp = this.delims.component,\n sub = this.delims.subcomponent;\n\n while (j < s.length) {\n const c = s.charAt(j);\n if (c === seg || c === fld || c === rep || c === cmp || c === sub) {\n break;\n }\n j++;\n }\n\n const val = s.slice(this.i, j);\n this._fastAdvance(val);\n return this._tok('TEXT', val, start);\n }\n\n // ---- helpers ----\n private _slice(start: number, end: number): string {\n return this.input.slice(start, Math.min(end, this.input.length));\n }\n\n private _advance(n: number, isNewline = false) {\n this.i += n;\n if (isNewline) {\n this.line += 1;\n this.col = 1;\n } else {\n this.col += n;\n }\n }\n\n private _fastAdvance(chunk: string) {\n const parts = chunk.split('\\r');\n if (parts.length > 1) {\n this.line += parts.length - 1;\n this.col = (parts.at(-1)?.length ?? 0) + 1;\n } else {\n this.col += chunk.length;\n }\n this.i += chunk.length;\n }\n\n private _tok(\n type: TokenType,\n value: string | undefined,\n start: Position['start']\n ): Token {\n const end = { offset: this.i, line: this.line, column: this.col };\n return { type, value, position: { start, end } };\n }\n\n // Iterable protocol (sync)\n [Symbol.iterator](): Iterator<Token> {\n return {\n next: () => {\n const t = this.next();\n if (t == null) {\n return { done: true, value: undefined as unknown as Token };\n }\n return { done: false, value: t };\n },\n };\n }\n\n // Async iteration support removed to keep the API synchronous.\n}\n","import type { Token, Tokenizer } from './types';\n\nexport function* iterateTokenizerSync(t: Tokenizer): Iterable<Token> {\n for (let tok = t.next(); tok; tok = t.next()) {\n yield tok;\n }\n}\n\n// Removed async stream support; the parser now operates synchronously only.\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAI5C,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAIlE;AAED,QAAA,MAAM,WAAW,EAAE,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAKtD,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAErD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAItC,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,SAAS,CAAC;AAG3D,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAalE;AAED,QAAA,MAAM,WAAW,EAAE,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAItD,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -1,8 +1,4 @@
1
- import type { ParseOptions, ParserContext } from './types';
2
- /**
3
- * A preprocessing step: takes a ParserContext, mutates or replaces it.
4
- */
5
- export type PreprocessorStep = (ctx: ParserContext) => ParserContext;
1
+ import type { ParserContext, PreprocessorStep } from './types';
6
2
  /**
7
3
  * Step: strip UTF-8 BOM.
8
4
  */
@@ -22,5 +18,5 @@ export declare const defaultPreprocessors: PreprocessorStep[];
22
18
  /**
23
19
  * Run the pipeline to initialize ParserContext.
24
20
  */
25
- export declare function runPreprocessors(raw: string, opts?: ParseOptions, steps?: PreprocessorStep[]): ParserContext;
21
+ export declare function runPreprocessors(ctx: ParserContext, steps: PreprocessorStep[]): ParserContext;
26
22
  //# sourceMappingURL=preprocessor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"preprocessor.d.ts","sourceRoot":"","sources":["../src/preprocessor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE3D;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,aAAa,KAAK,aAAa,CAAC;AAErE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,gBAKtB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,gBAG/B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,gBAmB9B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,gBAAgB,EAIlD,CAAC;AAEF;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,YAAiB,EACvB,KAAK,GAAE,gBAAgB,EAAyB,GAC/C,aAAa,CAYf"}
1
+ {"version":3,"file":"preprocessor.d.ts","sourceRoot":"","sources":["../src/preprocessor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAI/D;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,gBAKtB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,gBAG/B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,gBAmB9B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,gBAAgB,EAIlD,CAAC;AAEF;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,aAAa,EAClB,KAAK,EAAE,gBAAgB,EAAE,GACxB,aAAa,CAOf"}
@@ -1,4 +1,4 @@
1
- import type { ParseOptions, Token, Tokenizer } from './types';
1
+ import type { ParserContext, Token, Tokenizer } from './types';
2
2
  export declare class HL7v2Tokenizer implements Tokenizer, Iterable<Token> {
3
3
  private input;
4
4
  private i;
@@ -7,7 +7,7 @@ export declare class HL7v2Tokenizer implements Tokenizer, Iterable<Token> {
7
7
  private delims;
8
8
  private didMshBootstrap;
9
9
  private pendingBootstrap;
10
- reset(input: string, opts: ParseOptions): void;
10
+ reset(ctx: ParserContext): void;
11
11
  next(): Token | null;
12
12
  private _slice;
13
13
  private _advance;
@@ -1 +1 @@
1
- {"version":3,"file":"tokenizer.d.ts","sourceRoot":"","sources":["../src/tokenizer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,YAAY,EAEZ,KAAK,EACL,SAAS,EAEV,MAAM,SAAS,CAAC;AAEjB,qBAAa,cAAe,YAAW,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC;IAC/D,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,CAAC,CAAK;IACd,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,MAAM,CAAmB;IAGjC,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,gBAAgB,CAGf;IAET,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY;IAwBvC,IAAI,IAAI,KAAK,GAAG,IAAI;IAkFpB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,QAAQ;IAUhB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,IAAI;IAUZ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC;CAarC"}
1
+ {"version":3,"file":"tokenizer.d.ts","sourceRoot":"","sources":["../src/tokenizer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EAEb,KAAK,EACL,SAAS,EAEV,MAAM,SAAS,CAAC;AAEjB,qBAAa,cAAe,YAAW,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC;IAC/D,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,CAAC,CAAK;IACd,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,MAAM,CAAmB;IAGjC,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,gBAAgB,CAGf;IAET,KAAK,CAAC,GAAG,EAAE,aAAa;IA2BxB,IAAI,IAAI,KAAK,GAAG,IAAI;IAkFpB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,QAAQ;IAUhB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,IAAI;IAUZ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC;CAarC"}
package/dist/types.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  import type { HL7v2Delimiters } from '@rethinkhealth/hl7v2-utils';
2
+ export type PreprocessorStep = (ctx: ParserContext) => ParserContext;
2
3
  export type ParseOptions = {
3
4
  delimiters?: HL7v2Delimiters;
5
+ preprocess?: PreprocessorStep[];
4
6
  };
5
7
  export interface ParserContext {
6
8
  input: string;
7
- options: ParseOptions;
9
+ delimiters: HL7v2Delimiters;
8
10
  metadata?: Record<string, unknown>;
9
11
  }
10
12
  export type Position = {
@@ -26,7 +28,7 @@ export type Token = {
26
28
  };
27
29
  export type TokenType = 'SEGMENT_START' | 'SEGMENT_END' | 'FIELD_DELIM' | 'REPETITION_DELIM' | 'COMPONENT_DELIM' | 'SUBCOMP_DELIM' | 'TEXT';
28
30
  export interface Tokenizer {
29
- reset(input: string, opts: ParseOptions): void;
31
+ reset(ctx: ParserContext): void;
30
32
  next(): Token | null;
31
33
  }
32
34
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAElE,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,CAAC,EAAE,eAAe,CAAC;CAC9B,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,YAAY,CAAC;IAEtB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAGD,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACxD,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;CACpB,CAAC;AAGF,MAAM,MAAM,SAAS,GACjB,eAAe,GACf,aAAa,GACb,aAAa,GACb,kBAAkB,GAClB,iBAAiB,GACjB,eAAe,GACf,MAAM,CAAC;AAEX,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/C,IAAI,IAAI,KAAK,GAAG,IAAI,CAAC;CACtB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAIlE,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,aAAa,KAAK,aAAa,CAAC;AAErE,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,CAAC,EAAE,eAAe,CAAC;IAE7B,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,eAAe,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAGD,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACxD,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;CACpB,CAAC;AAGF,MAAM,MAAM,SAAS,GACjB,eAAe,GACf,aAAa,GACb,aAAa,GACb,kBAAkB,GAClB,iBAAiB,GACjB,eAAe,GACf,MAAM,CAAC;AAEX,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAAC;IAChC,IAAI,IAAI,KAAK,GAAG,IAAI,CAAC;CACtB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rethinkhealth/hl7v2-parser",
3
3
  "description": "hl7v2 plugin to parse hl7v2 messages",
4
- "version": "0.2.4",
4
+ "version": "0.2.5",
5
5
  "license": "MIT",
6
6
  "author": {
7
7
  "name": "Melek Somai",
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "unified": "11.0.1",
20
- "@rethinkhealth/hl7v2-utils": "0.2.4"
20
+ "@rethinkhealth/hl7v2-utils": "0.2.5"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@types/node": "22.15.31",
@@ -27,7 +27,7 @@
27
27
  "tsup": "8.5.0",
28
28
  "typescript": "^5.8.3",
29
29
  "vitest": "^3.2.4",
30
- "@rethinkhealth/hl7v2-ast": "0.2.4",
30
+ "@rethinkhealth/hl7v2-ast": "0.2.5",
31
31
  "@rethinkhealth/testing": "0.0.0",
32
32
  "@rethinkhealth/tsconfig": "0.0.0"
33
33
  },