@rethinkhealth/hl7v2-parser 0.2.7 → 0.2.9
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.d.ts.map +1 -1
- package/dist/index.js +15 -3
- package/dist/index.js.map +1 -1
- package/dist/tokenizer.d.ts.map +1 -1
- package/dist/types.d.ts +4 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -6
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,UAAU,CAAC;AAClD,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -254,6 +254,12 @@ function parseHL7v2FromIterator(tokens) {
|
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
// src/tokenizer.ts
|
|
257
|
+
var MSH_SEGMENT_START = 0;
|
|
258
|
+
var MSH_SEGMENT_END = 3;
|
|
259
|
+
var MSH_FIELD_SEPERATOR_START = 3;
|
|
260
|
+
var MSH_FIELD_SEPERATOR_END = 4;
|
|
261
|
+
var MSH_FIELD_DELIMITER_START = 4;
|
|
262
|
+
var MSH_FIELD_DELIMITER_END = 8;
|
|
257
263
|
var HL7v2Tokenizer = class {
|
|
258
264
|
input = "";
|
|
259
265
|
i = 0;
|
|
@@ -273,9 +279,15 @@ var HL7v2Tokenizer = class {
|
|
|
273
279
|
this.didMshBootstrap = false;
|
|
274
280
|
this.pendingBootstrap = null;
|
|
275
281
|
if (this.input.startsWith("MSH")) {
|
|
276
|
-
const msh = this._slice(
|
|
277
|
-
const msh1 = this._slice(
|
|
278
|
-
|
|
282
|
+
const msh = this._slice(MSH_SEGMENT_START, MSH_SEGMENT_END);
|
|
283
|
+
const msh1 = this._slice(
|
|
284
|
+
MSH_FIELD_SEPERATOR_START,
|
|
285
|
+
MSH_FIELD_SEPERATOR_END
|
|
286
|
+
);
|
|
287
|
+
const msh2 = this._slice(
|
|
288
|
+
MSH_FIELD_DELIMITER_START,
|
|
289
|
+
MSH_FIELD_DELIMITER_END
|
|
290
|
+
);
|
|
279
291
|
this.pendingBootstrap = [
|
|
280
292
|
{ kind: "TEXT", value: msh, advance: msh.length },
|
|
281
293
|
{ kind: "FIELD_DELIM", advance: 0 },
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 { Position, 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 let lastContentEnd: Position['end'] | null = null;\n\n const openSegment = (start: Position['start']) => {\n seg = { type: 'segment', children: [], position: { start, end: start } };\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 = (start: Position['start']) => {\n if (!seg) {\n openSegment(start);\n }\n };\n\n const openField = (start: Position['start']) => {\n ensureSegment(start);\n field = { type: 'field', children: [], position: { start, end: start } };\n // biome-ignore lint/style/noNonNullAssertion: seg is ensured above\n seg!.children.push(field);\n rep = {\n type: 'field-repetition',\n children: [],\n position: { start, end: start },\n };\n field.children.push(rep);\n comp = { type: 'component', children: [], position: { start, end: start } };\n rep.children.push(comp);\n currentSub = null;\n segmentHasContent = true;\n };\n\n const openRepetition = (start: Position['start']) => {\n if (!field) {\n openField(start);\n }\n rep = {\n type: 'field-repetition',\n children: [],\n position: { start, end: start },\n };\n // biome-ignore lint/style/noNonNullAssertion: field is ensured above\n field!.children.push(rep);\n comp = { type: 'component', children: [], position: { start, end: start } };\n rep.children.push(comp);\n currentSub = null;\n segmentHasContent = true;\n };\n\n const openComponent = (start: Position['start']) => {\n if (!field) {\n openField(start);\n }\n if (!rep) {\n rep = {\n type: 'field-repetition',\n children: [],\n position: { start, end: start },\n };\n // biome-ignore lint/style/noNonNullAssertion: field is ensured above\n field!.children.push(rep);\n }\n comp = { type: 'component', children: [], position: { start, end: start } };\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 = (start: Position['start']) => {\n if (!field) {\n openField(start);\n }\n if (!rep) {\n openRepetition(start);\n }\n if (!comp) {\n openComponent(start);\n }\n if (!currentSub) {\n currentSub = {\n type: 'subcomponent',\n value: '',\n position: { start, end: start },\n };\n // biome-ignore lint/style/noNonNullAssertion: comp is ensured above\n comp!.children.push(currentSub);\n segmentHasContent = true;\n }\n };\n\n const updatePositionsToEnd = (endPos: Position['end']) => {\n if (currentSub?.position) {\n currentSub.position.end = endPos;\n }\n if (comp?.position) {\n comp.position.end = endPos;\n }\n if (rep?.position) {\n rep.position.end = endPos;\n }\n if (field?.position) {\n field.position.end = endPos;\n }\n if (seg?.position) {\n seg.position.end = endPos;\n }\n };\n\n const processToken = (tok: Token) => {\n switch (tok.type) {\n case 'SEGMENT_END': {\n // Use the last content position instead of the segment delimiter position\n const endPos = lastContentEnd || tok.position.start;\n updatePositionsToEnd(endPos);\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 lastContentEnd = null;\n return;\n }\n case 'FIELD_DELIM': {\n lastContentEnd = tok.position.end;\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(tok.position.start);\n // biome-ignore lint/style/noNonNullAssertion: comp is initialized in openField\n comp!.children.push({\n type: 'subcomponent',\n value: '',\n position: { start: tok.position.start, end: tok.position.start },\n });\n segmentHasContent = true;\n }\n openField(tok.position.end);\n return;\n }\n case 'REPETITION_DELIM': {\n lastContentEnd = tok.position.end;\n if (!field) {\n openField(tok.position.start);\n }\n openRepetition(tok.position.end);\n return;\n }\n case 'COMPONENT_DELIM': {\n lastContentEnd = tok.position.end;\n openComponent(tok.position.end);\n return;\n }\n case 'SUBCOMP_DELIM': {\n lastContentEnd = tok.position.end;\n if (!comp) {\n openComponent(tok.position.start);\n }\n // Start a new empty subcomponent slot\n currentSub = {\n type: 'subcomponent',\n value: '',\n position: { start: tok.position.end, end: tok.position.end },\n };\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(tok.position.start);\n // biome-ignore lint/style/noNonNullAssertion: ensured above\n currentSub!.value += val;\n updatePositionsToEnd(tok.position.end);\n lastContentEnd = tok.position.end;\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 if (lastContentEnd && seg) {\n updatePositionsToEnd(lastContentEnd);\n }\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
|
+
{"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 { Position, 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 let lastContentEnd: Position['end'] | null = null;\n\n const openSegment = (start: Position['start']) => {\n seg = { type: 'segment', children: [], position: { start, end: start } };\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 = (start: Position['start']) => {\n if (!seg) {\n openSegment(start);\n }\n };\n\n const openField = (start: Position['start']) => {\n ensureSegment(start);\n field = { type: 'field', children: [], position: { start, end: start } };\n // biome-ignore lint/style/noNonNullAssertion: seg is ensured above\n seg!.children.push(field);\n rep = {\n type: 'field-repetition',\n children: [],\n position: { start, end: start },\n };\n field.children.push(rep);\n comp = { type: 'component', children: [], position: { start, end: start } };\n rep.children.push(comp);\n currentSub = null;\n segmentHasContent = true;\n };\n\n const openRepetition = (start: Position['start']) => {\n if (!field) {\n openField(start);\n }\n rep = {\n type: 'field-repetition',\n children: [],\n position: { start, end: start },\n };\n // biome-ignore lint/style/noNonNullAssertion: field is ensured above\n field!.children.push(rep);\n comp = { type: 'component', children: [], position: { start, end: start } };\n rep.children.push(comp);\n currentSub = null;\n segmentHasContent = true;\n };\n\n const openComponent = (start: Position['start']) => {\n if (!field) {\n openField(start);\n }\n if (!rep) {\n rep = {\n type: 'field-repetition',\n children: [],\n position: { start, end: start },\n };\n // biome-ignore lint/style/noNonNullAssertion: field is ensured above\n field!.children.push(rep);\n }\n comp = { type: 'component', children: [], position: { start, end: start } };\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 = (start: Position['start']) => {\n if (!field) {\n openField(start);\n }\n if (!rep) {\n openRepetition(start);\n }\n if (!comp) {\n openComponent(start);\n }\n if (!currentSub) {\n currentSub = {\n type: 'subcomponent',\n value: '',\n position: { start, end: start },\n };\n // biome-ignore lint/style/noNonNullAssertion: comp is ensured above\n comp!.children.push(currentSub);\n segmentHasContent = true;\n }\n };\n\n const updatePositionsToEnd = (endPos: Position['end']) => {\n if (currentSub?.position) {\n currentSub.position.end = endPos;\n }\n if (comp?.position) {\n comp.position.end = endPos;\n }\n if (rep?.position) {\n rep.position.end = endPos;\n }\n if (field?.position) {\n field.position.end = endPos;\n }\n if (seg?.position) {\n seg.position.end = endPos;\n }\n };\n\n const processToken = (tok: Token) => {\n switch (tok.type) {\n case 'SEGMENT_END': {\n // Use the last content position instead of the segment delimiter position\n const endPos = lastContentEnd || tok.position.start;\n updatePositionsToEnd(endPos);\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 lastContentEnd = null;\n return;\n }\n case 'FIELD_DELIM': {\n lastContentEnd = tok.position.end;\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(tok.position.start);\n // biome-ignore lint/style/noNonNullAssertion: comp is initialized in openField\n comp!.children.push({\n type: 'subcomponent',\n value: '',\n position: { start: tok.position.start, end: tok.position.start },\n });\n segmentHasContent = true;\n }\n openField(tok.position.end);\n return;\n }\n case 'REPETITION_DELIM': {\n lastContentEnd = tok.position.end;\n if (!field) {\n openField(tok.position.start);\n }\n openRepetition(tok.position.end);\n return;\n }\n case 'COMPONENT_DELIM': {\n lastContentEnd = tok.position.end;\n openComponent(tok.position.end);\n return;\n }\n case 'SUBCOMP_DELIM': {\n lastContentEnd = tok.position.end;\n if (!comp) {\n openComponent(tok.position.start);\n }\n // Start a new empty subcomponent slot\n currentSub = {\n type: 'subcomponent',\n value: '',\n position: { start: tok.position.end, end: tok.position.end },\n };\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(tok.position.start);\n // biome-ignore lint/style/noNonNullAssertion: ensured above\n currentSub!.value += val;\n updatePositionsToEnd(tok.position.end);\n lastContentEnd = tok.position.end;\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 if (lastContentEnd && seg) {\n updatePositionsToEnd(lastContentEnd);\n }\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\nconst MSH_SEGMENT_START = 0;\nconst MSH_SEGMENT_END = 3;\nconst MSH_FIELD_SEPERATOR_START = 3;\nconst MSH_FIELD_SEPERATOR_END = 4;\nconst MSH_FIELD_DELIMITER_START = 4;\nconst MSH_FIELD_DELIMITER_END = 8;\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(MSH_SEGMENT_START, MSH_SEGMENT_END);\n const msh1 = this._slice(\n MSH_FIELD_SEPERATOR_START,\n MSH_FIELD_SEPERATOR_END\n ); // the field delimiter char at index 3\n const msh2 = this._slice(\n MSH_FIELD_DELIMITER_START,\n MSH_FIELD_DELIMITER_END\n ); // 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":[]}
|
package/dist/tokenizer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AASjB,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;IAiCxB,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
|
@@ -4,11 +4,11 @@ export type ParseOptions = {
|
|
|
4
4
|
delimiters?: HL7v2Delimiters;
|
|
5
5
|
preprocess?: PreprocessorStep[];
|
|
6
6
|
};
|
|
7
|
-
export
|
|
7
|
+
export type ParserContext = {
|
|
8
8
|
input: string;
|
|
9
9
|
delimiters: HL7v2Delimiters;
|
|
10
10
|
metadata?: Record<string, unknown>;
|
|
11
|
-
}
|
|
11
|
+
};
|
|
12
12
|
export type Position = {
|
|
13
13
|
start: {
|
|
14
14
|
offset: number;
|
|
@@ -27,8 +27,8 @@ export type Token = {
|
|
|
27
27
|
position: Position;
|
|
28
28
|
};
|
|
29
29
|
export type TokenType = 'SEGMENT_START' | 'SEGMENT_END' | 'FIELD_DELIM' | 'REPETITION_DELIM' | 'COMPONENT_DELIM' | 'SUBCOMP_DELIM' | 'TEXT';
|
|
30
|
-
export
|
|
30
|
+
export type Tokenizer = {
|
|
31
31
|
reset(ctx: ParserContext): void;
|
|
32
32
|
next(): Token | null;
|
|
33
|
-
}
|
|
33
|
+
};
|
|
34
34
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -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;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,
|
|
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,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,eAAe,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAGF,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,MAAM,SAAS,GAAG;IACtB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAAC;IAChC,IAAI,IAAI,KAAK,GAAG,IAAI,CAAC;CACtB,CAAC"}
|
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
|
+
"version": "0.2.9",
|
|
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.
|
|
20
|
+
"@rethinkhealth/hl7v2-utils": "0.2.9"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@types/node": "22.15.31",
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"tsup": "8.5.0",
|
|
28
28
|
"typescript": "^5.8.3",
|
|
29
29
|
"vitest": "^3.2.4",
|
|
30
|
-
"@rethinkhealth/hl7v2-ast": "0.2.
|
|
31
|
-
"@rethinkhealth/testing": "0.0.
|
|
32
|
-
"@rethinkhealth/tsconfig": "0.0.
|
|
30
|
+
"@rethinkhealth/hl7v2-ast": "0.2.9",
|
|
31
|
+
"@rethinkhealth/testing": "0.0.1",
|
|
32
|
+
"@rethinkhealth/tsconfig": "0.0.1"
|
|
33
33
|
},
|
|
34
34
|
"repository": "rethinkhealth/hl7v2.git",
|
|
35
35
|
"homepage": "https://www.rethinkhealth.io/hl7v2/docs",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"nodejs",
|
|
42
42
|
"typescript"
|
|
43
43
|
],
|
|
44
|
-
"packageManager": "pnpm@10.
|
|
44
|
+
"packageManager": "pnpm@10.14.0",
|
|
45
45
|
"publishConfig": {
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|