UNPKG

jspurefix

Version:
292 lines (261 loc) 9.54 kB
import { ILooseObject } from '../../../collections/collection' import { SimpleFieldDefinition, GroupFieldDefinition, ComponentFieldDefinition, MessageDefinition, FixDefinitions } from '../../definition' import { Dictionary } from '../../../collections' import { ContainedFieldSet, ContainedComponentField, ContainedGroupField, ContainedSimpleField } from '../../contained' import { ContainedSetType } from '../../dict-primitive' import { FixDefinitionSource, FixVersion } from '../../fix-versions' import { GetJsFixLogger, IJsFixLogger } from '../../../config' export interface IRepositoryField extends ILooseObject { Tag: string Name: string Type: string Description: string AbbrName: string NotReqXML: string BaseCategory: string BaseCategoryAbbrName: string } export interface IRepositoryEnum extends ILooseObject { Tag: string Value: string SymbolicName: string Description: string } export interface IRepositoryComponent extends ILooseObject { ComponentID: string ComponentType: string CategoryID: string Name: string AbbrName: string NotReqXML: string Description: string } export interface IRepositoryMessage extends ILooseObject { ComponentID: string MsgType: string Name: string CategoryID: string SectionID: string AbbrName: string NotReqXML: string Description: string } export interface IRepositoryMsgContent extends ILooseObject { ComponentID: string TagText: string Indent: string Position: string Reqd: string Description: string } export interface IRepositoryAbbreviation extends ILooseObject { Term: string AbbrTerm: string } export class Repository { public Enums: IRepositoryEnum[] public Fields: IRepositoryField[] public Components: IRepositoryComponent[] public Messages: IRepositoryMessage[] public MsgContents: IRepositoryMsgContent[] public Abbreviations: IRepositoryAbbreviation[] public includesAbbreviations: boolean // derived from above public readonly definitions: FixDefinitions private readonly groupLookup: Dictionary<GroupFieldDefinition> = new Dictionary<GroupFieldDefinition>() private contentLookup: Dictionary<IRepositoryMsgContent[]> private componentLookup: Dictionary<IRepositoryComponent> private readonly logger: IJsFixLogger constructor (public readonly version: FixVersion, public readonly getLogger: GetJsFixLogger) { this.logger = getLogger('Repository') switch (version) { case FixVersion.FIX44: case FixVersion.FIX50: case FixVersion.FIX50SP1: case FixVersion.FIX50SP2: this.includesAbbreviations = true break default: { this.includesAbbreviations = false break } } this.definitions = new FixDefinitions(FixDefinitionSource.FixRepo, version) } public assign (name: string, data: ILooseObject[]): void { switch (name) { case 'Fields': { this.Fields = data as IRepositoryField[] break } case 'Enums': { this.Enums = data as IRepositoryEnum[] break } case 'Components': { this.Components = data as IRepositoryComponent[] break } case 'Messages': { this.Messages = data as IRepositoryMessage[] break } case 'MsgContents': { this.MsgContents = data as IRepositoryMsgContent[] if (!this.includesAbbreviations) { this.toDefinitions() } break } case 'Abbreviations': { this.Abbreviations = data as IRepositoryAbbreviation[] this.toDefinitions() break } } } private summarise (): void { const logger = this.logger logger.info(`definitions: ${this.definitions.simple.count()} fields`) logger.info(`definitions: ${this.definitions.component.count()} components`) logger.info(`definitions: ${this.definitions.message.count()} messages`) } private toDefinitions (): void { this.fields() this.complex() this.header() this.trailer() this.summarise() } private complex (): void { this.contentLookup = this.contents() this.componentLookup = this.components() this.Components.forEach((c: IRepositoryComponent) => this.resolve(c)) this.Messages.forEach((m: IRepositoryMessage) => { const msg = this.message(m) this.logger.debug(`${msg.toString()}`) this.definitions.addMessage(msg) }) } private header (): void { const h: ComponentFieldDefinition = this.definitions.component.get('StandardHeader') this.definitions.component.add('header', h) } private trailer (): void { const t: ComponentFieldDefinition = this.definitions.component.get('StandardTrailer') this.definitions.component.add('trailer', t) } private fields (): void { const definitions = this.definitions this.Fields.forEach((f: IRepositoryField) => { definitions.addSimpleFieldDef(new SimpleFieldDefinition( f.Tag, f.Name, f.AbbrName ? f.AbbrName : f.Name, f.BaseCategory, f.BaseCategoryAbbrName, f.Type.toUpperCase(), f.Description)) }) for (const e of this.Enums) { const field: SimpleFieldDefinition = definitions.tagToSimple[parseInt(e.Tag, 10)] if (field == null) { continue } if (e.Value && e.SymbolicName) { field.addEnum(e.Value, e.SymbolicName, e.Description) } } } private contents (): Dictionary<IRepositoryMsgContent[]> { return this.MsgContents.reduce((a, current) => { let content: IRepositoryMsgContent[] = a.get(current.ComponentID) if (!content) { content = [] a.add(current.ComponentID, content) } content[content.length] = current return a }, new Dictionary<IRepositoryMsgContent[]>()) } private resolveToFieldSet (content: IRepositoryMsgContent[], parentSet: ContainedFieldSet): void { content.forEach((current: IRepositoryMsgContent) => { const required: boolean = current.Reqd === '1' const tag: number = parseInt(current.TagText, 10) if (!isNaN(tag)) { const sf: SimpleFieldDefinition = this.definitions.tagToSimple[tag] if (sf) { parentSet.add(new ContainedSimpleField(sf, parentSet.fields.length, required, false)) } } else { // is there a definition for this type yet create. let childSet: ContainedFieldSet = this.definitions.component.get(current.TagText) if (!childSet) { const cl: IRepositoryComponent = this.componentLookup.get(current.TagText) if (cl) { childSet = this.resolve(cl) } } switch (childSet.type) { case ContainedSetType.Component: { parentSet.add(new ContainedComponentField(childSet, parentSet.fields.length, required)) break } case ContainedSetType.Group: { parentSet.add(new ContainedGroupField(childSet as GroupFieldDefinition, parentSet.fields.length, required)) break } default: { throw new Error(`unknown set type ${childSet.type}`) } } } return parentSet }) } private resolve (c: IRepositoryComponent): ContainedFieldSet { switch (c.ComponentType) { case 'ImplicitBlockRepeating': case 'BlockRepeating': { const content: IRepositoryMsgContent[] = this.contentLookup.get(c.ComponentID) const noField: SimpleFieldDefinition = this.definitions.tagToSimple[parseInt(content[0].TagText, 10)] let def: GroupFieldDefinition = this.groupLookup.get(c.ComponentID) if (!def) { def = new GroupFieldDefinition(c.Name, c.AbbrName, c.CategoryID, noField, c.Description) this.resolveToFieldSet(content.slice(1), def) this.groupLookup.add(c.ComponentID, def) } return def } default: { const content: IRepositoryMsgContent[] = this.contentLookup.get(c.ComponentID) let def: ComponentFieldDefinition = this.definitions.component.get(c.Name) if (!def) { def = new ComponentFieldDefinition(c.Name, c.AbbrName, c.CategoryID, c.Description) this.resolveToFieldSet(content, def) this.definitions.addComponentFieldDef(def) } return def } } } private message (m: IRepositoryMessage): MessageDefinition { const definitions = this.definitions const content: IRepositoryMsgContent[] = this.contentLookup.get(m.ComponentID) let def: MessageDefinition = definitions.message.get(m.Name) if (!def) { def = new MessageDefinition(m.Name, m.AbbrName, m.MsgType, m.CategoryID, m.Description) this.resolveToFieldSet(content, def) definitions.addComponentFieldDef(def) } return def } private components (): Dictionary<IRepositoryComponent> { return this.Components.reduce((a: Dictionary<IRepositoryComponent>, current: IRepositoryComponent) => { a.add(current.Name, current) a.add(current.ComponentID, current) return a }, new Dictionary<IRepositoryComponent>()) } }