diff --git a/lib/Segment.ts b/lib/Segment.ts index 34fec54..9b5e0b2 100644 --- a/lib/Segment.ts +++ b/lib/Segment.ts @@ -2,7 +2,7 @@ import type { Delimiters, FormattedSegment } from './types.js'; export class Segment { #delimiters: Delimiters; - #parsed: string[][]; + #parsed: string[][][]; #name: string; /** @@ -30,13 +30,26 @@ export class Segment { get formatted(): FormattedSegment { const formatted: FormattedSegment = { name: this.#name }; - this.#parsed.forEach((element, elementIndex) => { + this.#parsed.forEach((elements, elementsIdx) => { // First item in parsed string is the segment value, everything else is components - formatted[`${elementIndex + 1}`] = element.shift() ?? ''; + formatted[`${elementsIdx + 1}`] = elements.at(0)?.at(0) ?? ''; + const repeats = elements.length > 1; - // Add components - element.forEach((component, componentIndex) => { - formatted[`${elementIndex + 1}-${componentIndex + 1}`] = component; + elements.forEach((element, repeatIdx) => { + const multiComponent = element.length > 1; + element.forEach((component, componentIdx) => { + // skipping first element + if (componentIdx == 0 && repeatIdx == 0) return; + // because we skipped first element we need to decrement index + // avoiding shifting because modifies internal list + if (repeatIdx == 0) componentIdx -= 1; + const repeatString = repeats ? `-${repeatIdx + 1}` : ''; + let key = `${elementsIdx + 1}`; + if (repeats || multiComponent) { + key = `${key}-${componentIdx + 1}${repeatString}`; + } + formatted[key] = component; + }); }); }); @@ -55,16 +68,18 @@ export class Segment { /** * Processes an element and formats it * @param element The string inside the element - * @returns A nested array of segments & components + * @returns A nested array of segments & repeated elements & components */ - processElement(element: string): string[] { + processElement(element: string): string[][] { // If this is ISA we don't want to split on component if (this.#name === 'ISA') { - return [Segment.cleanString(element)]; + return [[Segment.cleanString(element)]]; } else { - return element - .split(this.#delimiters.component) - .map((string) => Segment.cleanString(string)); + return element.split(this.#delimiters.repetition).map((string) => { + return string + .split(this.#delimiters.component) + .map((string) => Segment.cleanString(string)); + }); } } diff --git a/test/segment.test.ts b/test/segment.test.ts index 378aa01..0c0117f 100644 --- a/test/segment.test.ts +++ b/test/segment.test.ts @@ -21,14 +21,25 @@ describe('Segment', () => { it('Should return an array of strings, split by the component delimiter', () => { //TODO: Remove initial segment when type checking is added const mySegment = new Segment('AMT*AU*34.25', delimiters); - expect(mySegment.processElement('AU')).toStrictEqual(['AU']); + expect(mySegment.processElement('AU')).toStrictEqual([['AU']]); }); it('If ISA component is left in tact, since it is an actual element', () => { //TODO: Remove initial segment when type checking is added const isa = 'ISA*00* *00* *ZZ*EMEDNYBAT *ZZ*ETIN *100101*1000*^*00501*006000600*0*T*:'; const mySegment = new Segment(isa, delimiters); - expect(mySegment.processElement(':')).toStrictEqual([':']); + expect(mySegment.processElement(':')).toStrictEqual([[':']]); + }); + it('Should handle cases where elements are repeated', () => { + const ras = 'RAS*34.25*1234567890*12345:0^67890:1'; + const mySegment = new Segment(ras, delimiters); + expect(mySegment.processElement('1234567890')).toStrictEqual([ + ['1234567890'], + ]); + expect(mySegment.processElement('12345:0^67890:1')).toStrictEqual([ + ['12345', '0'], + ['67890', '1'], + ]); }); }); @@ -50,7 +61,7 @@ describe('Segment', () => { describe('#constructor()', () => { const mySegment = new Segment('AMT*AU*34.25', delimiters); it('Should parse passed raw element string', () => { - expect(mySegment.parsed).toStrictEqual([['AU'], ['34.25']]); + expect(mySegment.parsed).toStrictEqual([[['AU']], [['34.25']]]); }); it('Should parse out the name of the element', () => { @@ -67,5 +78,45 @@ describe('Segment', () => { 2: '34.25', }); }); + it('Should add repeat index to end if repeated element', () => { + const ras = 'RAS*34.25*1234567890*12345:0^67890:1'; + const segment = new Segment(ras, delimiters); + expect(segment.formatted).toStrictEqual({ + name: 'RAS', + 1: '34.25', + 2: '1234567890', + 3: '12345', + '3-1-1': '0', + '3-1-2': '67890', + '3-2-2': '1', + }); + }); + it('Should add repeat index to if repeated and first is single component', () => { + const ras = 'RAS*34.25*1234567890*abcde^12345:0^67890:1'; + const segment = new Segment(ras, delimiters); + expect(segment.formatted).toStrictEqual({ + name: 'RAS', + 1: '34.25', + 2: '1234567890', + 3: 'abcde', + '3-1-2': '12345', + '3-2-2': '0', + '3-1-3': '67890', + '3-2-3': '1', + }); + }); + it('Should format normal multi component elements', () => { + const ras = 'RAS*34.25*1234567890*12345:0:67890:1'; + const segment = new Segment(ras, delimiters); + expect(segment.formatted).toStrictEqual({ + name: 'RAS', + 1: '34.25', + 2: '1234567890', + 3: '12345', + '3-1': '0', + '3-2': '67890', + '3-3': '1', + }); + }); }); });