"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Parser = void 0; const configuration_1 = require("./configuration"); const tokenizer_1 = require("./tokenizer"); const events_1 = require("events"); const separators_1 = require("./edi/separators"); var States; (function (States) { States[States["EMPTY"] = 0] = "EMPTY"; States[States["SEGMENT"] = 1] = "SEGMENT"; States[States["ELEMENT"] = 2] = "ELEMENT"; States[States["COMPONENT"] = 3] = "COMPONENT"; States[States["MODESET"] = 4] = "MODESET"; States[States["DATA"] = 5] = "DATA"; States[States["CONTINUED"] = 6] = "CONTINUED"; })(States || (States = {})); class Parser extends events_1.EventEmitter { constructor(configuration) { super(); this.errors = { incompleteMessage: function () { return new Error("Cannot close an incomplete message"); }, invalidCharacter: function (character, index) { let message = ""; message += "Invalid character " + character; message += ` at position ${index}`; return new Error(message); }, invalidControlAfterSegment: function (segment, character) { let message = ""; message += "Invalid character '" + character; message += "' after reading segment name " + segment; return new Error(message); } }; events_1.EventEmitter.apply(this); if (configuration) { this.configuration = configuration; } else { this.configuration = new configuration_1.Configuration(); } this.validator = this.configuration.validator; this.tokenizer = new tokenizer_1.Tokenizer(this.configuration); this.state = States.EMPTY; } separators() { const builder = new separators_1.EdifactSeparatorsBuilder(); builder.elementSeparator(String.fromCharCode(this.configuration.config.dataElementSeparator)); builder.componentSeparator(String.fromCharCode(this.configuration.config.componentDataSeparator)); builder.decimalSeparator(String.fromCharCode(this.configuration.config.decimalMark)); builder.releaseIndicator(String.fromCharCode(this.configuration.config.releaseCharacter)); builder.segmentTerminator(String.fromCharCode(this.configuration.config.segmentTerminator)); return builder.build(); } onOpenSegment(segment) { this.emit("openSegment", segment); } onCloseSegment() { this.emit("closeSegment"); } onElement() { this.emit("element"); } onComponent(data) { this.emit("component", data); } updateCharset(charset) { const previous = this.configuration.charset; this.configuration.updateCharset(charset); if (this.configuration.charset !== previous) { this.tokenizer.setCharsetBasedOnConfig(this.configuration); } } end() { if (this.state !== States.SEGMENT || this.tokenizer.buffer !== "") { throw this.errors.incompleteMessage(); } else { this.state = States.EMPTY; } } una(chunk) { if (/^UNA.... ./g.test(chunk)) { this.configuration.config.componentDataSeparator = chunk.charCodeAt(3); this.configuration.config.dataElementSeparator = chunk.charCodeAt(4); this.configuration.config.decimalMark = chunk.charCodeAt(5); this.configuration.config.releaseCharacter = chunk.charCodeAt(6); this.configuration.config.segmentTerminator = chunk.charCodeAt(8); return true; } else { return false; } } write(chunk) { let index = 0; if (this.state === States.CONTINUED) { this.state = States.MODESET; } while (index < chunk.length) { switch (this.state) { case States.EMPTY: index = this.una(chunk) ? 9 : 0; this.state = States.SEGMENT; case States.SEGMENT: index = this.tokenizer.segment(chunk, index); switch (chunk.charCodeAt(index) || this.configuration.config.endOfTag) { case this.configuration.config.dataElementSeparator: this.validator.onOpenSegment(this.tokenizer.buffer); this.onOpenSegment(this.tokenizer.buffer); this.state = States.ELEMENT; this.tokenizer.buffer = ""; break; case this.configuration.config.segmentTerminator: this.validator.onOpenSegment(this.tokenizer.buffer); this.onOpenSegment(this.tokenizer.buffer); this.validator.onCloseSegment(""); this.onCloseSegment(); this.state = States.SEGMENT; this.tokenizer.buffer = ""; break; case this.configuration.config.endOfTag: case this.configuration.config.carriageReturn: case this.configuration.config.lineFeed: break; default: throw this.errors.invalidControlAfterSegment(this.tokenizer.buffer, chunk.charAt(index)); } break; case States.ELEMENT: this.validator.onElement(); this.onElement(); case States.COMPONENT: this.validator.onOpenComponent(this.tokenizer); case States.MODESET: case States.DATA: index = this.tokenizer.data(chunk, index); switch (chunk.charCodeAt(index) || this.configuration.config.endOfTag) { case this.configuration.config.componentDataSeparator: this.validator.onCloseComponent(this.tokenizer); this.onComponent(this.tokenizer.buffer); this.state = States.COMPONENT; this.tokenizer.buffer = ""; break; case this.configuration.config.dataElementSeparator: this.validator.onCloseComponent(this.tokenizer); this.onComponent(this.tokenizer.buffer); this.state = States.ELEMENT; this.tokenizer.buffer = ""; break; case this.configuration.config.segmentTerminator: this.validator.onCloseComponent(this.tokenizer); this.onComponent(this.tokenizer.buffer); this.validator.onCloseSegment(""); this.onCloseSegment(); this.state = States.SEGMENT; this.tokenizer.buffer = ""; break; case this.configuration.config.decimalMark: this.tokenizer.decimal(chunk, index); this.state = States.DATA; break; case this.configuration.config.releaseCharacter: index++; this.tokenizer.release(chunk, index); this.state = States.DATA; break; case this.configuration.config.endOfTag: case this.configuration.config.carriageReturn: case this.configuration.config.lineFeed: this.state = States.DATA; break; default: throw this.errors.invalidCharacter(chunk.charAt(index), index); } } index++; } } } exports.Parser = Parser; //# sourceMappingURL=parser.js.map