jspurefix
Version:
pure node js fix engine
169 lines (148 loc) • 4.82 kB
text/typescript
import * as fs from 'fs'
import * as path from 'path'
import { SAXParser } from 'sax'
import { promisify } from 'util'
import { IDictDoneCb, ISaxNode, SAXStream } from '../../dict-primitive'
import { FixDefinitions } from '../../definition'
import { AbbreviationsParser } from './abbreviations-parser'
import { BaseParser } from './base-parser'
import { ComponentsParser } from './components-parser'
import { EnumsParser } from './enums-parser'
import { FieldsParser } from './fields-parser'
import { MessagesParser } from './messages-parser'
import { MsgContentsParser } from './msg-contents-parser'
import { Repository } from './repository'
import { FixParser } from '../../fix-parser'
import { VersionUtil } from '../../fix-versions'
import { GetJsFixLogger, IJsFixLogger } from '../../../config'
export class RepositoryXmlParser extends FixParser {
public readonly repository: Repository
private readonly singlePass = promisify(RepositoryXmlParser.subscribe)
private readonly logger: IJsFixLogger
constructor (public readonly rootPath: string, public readonly getLogger: GetJsFixLogger) {
super()
this.logger = getLogger('RepositoryXmlParser')
this.repository = new Repository(VersionUtil.resolve(this.rootPath), getLogger)
}
private static subscribe (instance: RepositoryXmlParser, saxStream: SAXStream, done: IDictDoneCb): void {
let parser: BaseParser
let pending: string
const saxParser: SAXParser = saxStream._parser
saxStream.on('error', (e: Error) => {
done(e, null)
})
saxStream.on('closetag', (name) => {
switch (name) {
case 'Abbreviations':
case 'Messages':
case 'MsgContents':
case 'Components':
case 'Fields':
case 'Enums': {
if (parser != null) {
parser.close(saxParser.line, name)
instance.repository.assign(name, parser.data)
parser = null
}
break
}
case 'Abbreviation':
case 'MsgContent':
case 'Field':
case 'Enum':
case 'Component':
case 'Message': {
if (parser != null) {
parser.close(saxParser.line, name)
}
break
}
default: {
pending = null
break
}
}
})
saxStream.on('text', (t: string) => {
t = t.trim()
if (pending) {
parser.value(saxParser.line, pending, t)
}
})
saxStream.on('opentag', (node) => {
const saxNode: ISaxNode = node as ISaxNode
switch (saxNode.name) {
case 'Fields': {
parser = new FieldsParser(instance)
break
}
case 'Enums': {
parser = new EnumsParser(instance)
break
}
case 'Components': {
parser = new ComponentsParser(instance)
break
}
case 'Messages': {
parser = new MessagesParser(instance)
break
}
case 'MsgContents': {
parser = new MsgContentsParser(instance)
break
}
case 'Abbreviations': {
parser = new AbbreviationsParser(instance)
break
}
case 'Abbreviation':
case 'Field':
case 'Message':
case 'MsgContent':
case 'Enum':
case 'Component': {
if (parser != null) {
parser.open(saxParser.line, saxNode)
}
break
}
default: {
pending = saxNode.name
}
}
})
saxStream.on('ready', () => {
if (done) {
parser = null
done(null, instance.repository.definitions)
}
})
}
public parse (): Promise<FixDefinitions> {
return new Promise<FixDefinitions>(async (accept, reject) => {
try {
await this.onePass('Fields.xml')
await this.onePass('Enums.xml')
await this.onePass('Components.xml')
await this.onePass('Messages.xml')
await this.onePass('MsgContents.xml')
if (this.repository.includesAbbreviations) {
await this.onePass('Abbreviations.xml')
}
accept(this.repository.definitions)
} catch (e) {
reject(e)
}
})
}
private async onePass (fileName: string): Promise<any> {
const logger = this.logger
const fullFileName = path.join(this.rootPath, fileName)
const pass: fs.ReadStream = fs.createReadStream(fullFileName)
logger.info(`reading ${fullFileName}`)
const saxStream: SAXStream = require('sax').createStream(true, {})
pass.pipe(saxStream)
await this.singlePass(this, saxStream)
}
}