UNPKG

jspurefix

Version:
151 lines (134 loc) 6.34 kB
import { ComponentFieldDefinition, FixDefinitions, MessageDefinition } from '../../dictionary/definition' import { ContainedComponentField, ContainedFieldType, ContainedGroupField, ContainedSimpleField } from '../../dictionary/contained' import { SegmentDescription, SegmentType } from '../segment-description' import { Structure } from '../structure' import { Tags } from '../tags' import { MsgTag } from '../../types/enum/msg_tag' export class AsciiSegmentParser { private readonly headerDefinition: ComponentFieldDefinition private readonly trailerDefinition: ComponentFieldDefinition constructor (public readonly definitions: FixDefinitions) { this.headerDefinition = definitions.component.get('header') this.trailerDefinition = definitions.component.get('trailer') } public parse (msgType: string, tags: Tags, last: number): Structure { const segments: SegmentDescription[] = [] const tr = this.trailerDefinition const hd = this.headerDefinition const msgDefinition: MessageDefinition = this.definitions.message.get(msgType) if (!msgDefinition) { return null } const structureStack: SegmentDescription[] = [] let currentTagPosition: number = 0 // let currentContainedField: ContainedField; let peek: SegmentDescription function init (): void { const firstTag: number = tags.tagPos[0].tag structureStack[structureStack.length] = new SegmentDescription(tr.name, tags.tagPos[last].tag, tr, currentTagPosition, structureStack.length, SegmentType.Component) structureStack[structureStack.length] = new SegmentDescription(msgDefinition.name, firstTag, msgDefinition, currentTagPosition, structureStack.length, SegmentType.Msg) structureStack[structureStack.length] = new SegmentDescription(hd.name, firstTag, hd, currentTagPosition, structureStack.length, SegmentType.Component) } // having finished one segments keep unwinding until tag matches further up stack function unwind (tag: number): void { while (structureStack.length > 1) { const done: SegmentDescription = structureStack.pop() done.end(segments.length, currentTagPosition - 1, tags.tagPos[currentTagPosition - 1].tag) segments[segments.length] = done peek = structureStack[structureStack.length - 1] if (peek.set.containedTag[tag]) { // unwound to point this tag lives in this set. break } if (peek.type === SegmentType.Msg && !tr.localTag[tag]) { // this is unknown tag and it is not part of trailer so raise unknown break } } } function examine (tag: number): void { switch (peek.currentField.type) { case ContainedFieldType.Simple: { const sf: ContainedSimpleField = peek.currentField as ContainedSimpleField if (sf.definition.tag === tag) { currentTagPosition = currentTagPosition + 1 } break } // moving deeper into structure, start a new context case ContainedFieldType.Component: { const cf: ContainedComponentField = peek.currentField as ContainedComponentField structureStack[structureStack.length] = new SegmentDescription(cf.name, tag, cf.definition, currentTagPosition, structureStack.length - 1, SegmentType.Component) break } case ContainedFieldType.Group: { const gf: ContainedComponentField = peek.currentField as ContainedGroupField const structure: SegmentDescription = new SegmentDescription(gf.name, tag, gf.definition, currentTagPosition, structureStack.length - 1, SegmentType.Group) structureStack[structureStack.length] = structure currentTagPosition = currentTagPosition + 1 structure.startGroup(tags.tagPos[currentTagPosition].tag) break } default: throw new Error(`unknown tag type ${tag}`) } } function groupDelimiter (tag: number): boolean { let delimiter: boolean = false if (tag === peek.delimiterTag) { peek.addDelimiterPosition(currentTagPosition) } else if (structureStack.length > 1) { // if a group is represented by a repeated component, then the tag representing delimiter // needs to be added further up stack to group itself. delimiter = structureStack[structureStack.length - 2].groupAddDelimiter(tag, currentTagPosition) } return delimiter } function gap (tag: number): void { const gap = new SegmentDescription('.undefined', tag, peek.set, currentTagPosition, structureStack.length, SegmentType.Gap) gap.end(segments.length, currentTagPosition, tag) segments[segments.length] = gap currentTagPosition++ } function discover (): void { while (currentTagPosition <= last) { const tag: number = tags.tagPos[currentTagPosition].tag peek = structureStack[structureStack.length - 1] peek.setCurrentField(tag) if (!peek.set.containedTag[tag] || groupDelimiter(tag)) { const unknown = peek.type === SegmentType.Msg && tag !== MsgTag.CheckSum if (unknown) { gap(tag) } else if (structureStack.length > 1) { // move back up the segments and save the finished group / component unwind(tag) } continue } examine(tag) } } function clean (): void { while (structureStack.length > 0) { const done: SegmentDescription = structureStack.pop() done.end(segments.length, currentTagPosition - 1, tags.tagPos[currentTagPosition - 1].tag) segments[segments.length] = done } const msg: SegmentDescription = segments[segments.length - 2] const trl: SegmentDescription = segments[segments.length - 1] msg.startTag = tags.tagPos[msg.startPosition].tag trl.startPosition = msg.endPosition + 1 msg.endPosition = trl.endPosition } init() discover() clean() return new Structure(tags, segments) } }