UNPKG

ts-edifact

Version:
340 lines 16.8 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.UNECEMessageStructureParser = exports.EdifactMessageSpecificationImpl = void 0; const validator_1 = require("../validator"); const httpClient_1 = require("../httpClient"); const htmlparser2_1 = require("htmlparser2"); const util_1 = require("../util"); class EdifactMessageSpecificationImpl { constructor(messageType, version, release, controllingAgency) { this.segmentTable = new validator_1.Dictionary(); this.elementTable = new validator_1.Dictionary(); this.messageStructureDefinition = []; this.messageType = messageType; this.version = version; this.release = release; this.controllingAgency = controllingAgency; } type() { return this.version + this.release + "_" + this.messageType; } versionAbbr() { return this.version + this.release; } } exports.EdifactMessageSpecificationImpl = EdifactMessageSpecificationImpl; var Part; (function (Part) { Part[Part["BeforeStructureDef"] = 0] = "BeforeStructureDef"; Part[Part["RefLink"] = 1] = "RefLink"; Part[Part["Pos"] = 2] = "Pos"; Part[Part["Tag"] = 3] = "Tag"; Part[Part["Deprecated"] = 4] = "Deprecated"; Part[Part["Name"] = 5] = "Name"; Part[Part["AfterStructureDef"] = 6] = "AfterStructureDef"; })(Part || (Part = {})); var SegmentPart; (function (SegmentPart) { SegmentPart[SegmentPart["BeforeStructureDef"] = 0] = "BeforeStructureDef"; SegmentPart[SegmentPart["Data"] = 1] = "Data"; SegmentPart[SegmentPart["AfterStructureDef"] = 2] = "AfterStructureDef"; })(SegmentPart || (SegmentPart = {})); class UNECEMessageStructureParser { constructor(version, type) { this.version = version.toLowerCase(); this.type = type.toLowerCase(); const baseUrl = "https://service.unece.org/trade/untdid/" + this.version + "/trmd/" + this.type + "_c.htm"; this.httpClient = new httpClient_1.HttpClient(baseUrl); } extractTextValue(text, regex, index = 0) { const arr = regex.exec(text); if ((0, util_1.isDefined)(arr)) { return arr[index]; } return ""; } loadPage(page) { return __awaiter(this, void 0, void 0, function* () { const data = yield this.httpClient.get(page); return data; }); } parseSegmentDefinitionPage(segment, page, definition) { return __awaiter(this, void 0, void 0, function* () { if (definition.segmentTable.contains(segment)) { return Promise.resolve(definition); } const segEntry = { "requires": 0, "elements": [] }; let state = SegmentPart.BeforeStructureDef; let dataSection = false; let skipAddingElement = false; let overflowLine = null; let complexEleId = null; let complexEleEntry = null; for (let line of page.split("\n")) { line = line.trimRight(); if (overflowLine !== null) { line = overflowLine.trimRight() + " " + line.trim(); overflowLine = null; } if (state === SegmentPart.BeforeStructureDef && line.includes('<HR>')) { dataSection = true; } else if (state === SegmentPart.BeforeStructureDef && (line.includes("<H3>") || (dataSection && line.includes('<B>')))) { state = SegmentPart.Data; } else if (state === SegmentPart.Data && !line.includes("<P>")) { const regexp = /^([\d]*)\s*?([X|\\*]?)\s*<A.*>([a-zA-Z0-9]*)<\/A>([a-zA-Z0-9 ,\-\\/&]{44,})([M|C])\s*([\d]*)\s*([a-zA-Z0-9\\.]*).*$/g; const arr = regexp.exec(line); if ((0, util_1.isDefined)(arr)) { const segGroupId = arr[1] === "" ? undefined : arr[1]; const id = arr[3]; const mandatory = arr[5] === "M" ? true : false; const elementDef = arr[7] === "" ? undefined : arr[7]; if (segGroupId) { if (id === "") { console.warn(`Could not determine element ID based on line ${line}`); continue; } segEntry.elements.push(id); skipAddingElement = false; if (mandatory) { segEntry.requires = segEntry.requires + 1; } if (elementDef) { if (complexEleEntry !== null && complexEleId !== null) { definition.elementTable.add(complexEleId, complexEleEntry); } complexEleId = null; complexEleEntry = null; if (definition.elementTable.contains(id)) { continue; } const eleEntry = { "requires": 0, "components": [] }; if (mandatory) { eleEntry.requires = eleEntry.requires + 1; } eleEntry.components.push(elementDef); definition.elementTable.add(id, eleEntry); } else { if (complexEleEntry !== null && complexEleId !== null) { definition.elementTable.add(complexEleId, complexEleEntry); } if (definition.elementTable.contains(id)) { skipAddingElement = true; continue; } complexEleId = id; complexEleEntry = { "requires": 0, "components": [] }; } } else { if (!skipAddingElement) { if (complexEleEntry !== null && elementDef) { complexEleEntry.components.push(elementDef); complexEleEntry.requires = mandatory ? complexEleEntry.requires + 1 : complexEleEntry.requires; } else { if (definition.elementTable.contains(id)) { continue; } const eleEntry = { "requires": 0, "components": [] }; if (mandatory) { eleEntry.requires = eleEntry.requires + 1; } if (elementDef) { eleEntry.components.push(elementDef); } definition.elementTable.add(id, eleEntry); } } } } else { const regexpAlt = /^([\d]*)\s*([X|\\*]?)\s*<A.*>([a-zA-Z0-9]*)<\/A>\s*([a-zA-Z0-9 \\-\\/&]*)/g; const arrAlt = regexpAlt.exec(line); if ((0, util_1.isDefined)(arrAlt)) { overflowLine = line; } } } else if (state === SegmentPart.Data && line.includes("<P>")) { state = SegmentPart.AfterStructureDef; break; } } if (complexEleEntry !== null && complexEleId !== null) { definition.elementTable.add(complexEleId, complexEleEntry); } if (segment !== "") { definition.segmentTable.add(segment, segEntry); } return Promise.resolve(definition); }); } parsePage(page) { return __awaiter(this, void 0, void 0, function* () { let definition; const handler = new htmlparser2_1.DomHandler(); let state = Part.BeforeStructureDef; let section = "header"; const segStack = []; const lookupSegmentPromises = []; const nextState = () => { if (state === Part.RefLink) { state = Part.Pos; } else if (state === Part.Pos) { state = Part.Deprecated; } else if (state === Part.Deprecated) { state = Part.Tag; } else if (state === Part.Tag) { state = Part.Name; } else if (state === Part.Name) { state = Part.RefLink; } }; handler.ontext = (text) => { if (text.includes("Message Type") && text.includes("Version") && text.includes("Release")) { const messageType = this.extractTextValue(text, /Message Type\s*: ([A-Z]*)\s/g, 1); const version = this.extractTextValue(text, /Version\s*: ([A-Z]*)\s/g, 1); const release = this.extractTextValue(text, /Release\s*: ([0-9A-Z]*)\s/g, 1); const controllingAgency = this.extractTextValue(text, /Contr. Agency\s*: ([0-9A-Z]*)\s/g, 1); definition = new EdifactMessageSpecificationImpl(messageType, version, release, controllingAgency); segStack.push(definition.messageStructureDefinition); } else if (text.includes("Message structure")) { state = Part.RefLink; } else if (state !== Part.BeforeStructureDef && state !== Part.AfterStructureDef) { if (state === Part.RefLink) { } else if (state === Part.Pos) { } else if (state === Part.Deprecated) { if (text.includes("- Segment group")) { const regex = /^[\s*+-]*-* (Segment group \d*)\s*-*\s*([M|C])\s*(\d*)([-|\\+|\\|]*).*/g; const arr = regex.exec(text); if ((0, util_1.isDefined)(arr)) { const groupArray = []; const group = { content: groupArray, mandatory: arr[2] === "M" ? true : false, repetition: parseInt(arr[3]), name: arr[1], section: (0, util_1.isDefined)(section) ? section : undefined }; section = null; segStack[segStack.length - 1].push(group); segStack.push(groupArray); } state = Part.RefLink; } else { nextState(); } } else if (state === Part.Tag) { const _section = section !== null ? section : undefined; let _data; if (definition) { _data = text === "UNH" ? [definition.versionAbbr(), definition.messageType] : undefined; } const segment = { content: text, mandatory: false, repetition: 0, data: _data, section: _section }; if (definition) { segStack[segStack.length - 1].push(segment); } section = null; } else if (state === Part.Name) { const regex = /^([a-zA-Z /\\-]*)\s*?([M|C])\s*?([0-9]*?)([^0-9]*)$/g; const arr = regex.exec(text); if ((0, util_1.isDefined)(arr)) { const sMandatory = arr[2]; const sRepetition = arr[3]; const remainder = arr[4]; const segArr = segStack[segStack.length - 1]; const segData = segArr[segArr.length - 1]; segData.mandatory = sMandatory === "M" ? true : false; segData.repetition = parseInt(sRepetition); if (remainder.includes("-") && remainder.includes("+")) { for (let i = 0; i < remainder.split("+").length - 1; i++) { segStack.pop(); } } nextState(); } if (text.includes("DETAIL SECTION")) { section = "detail"; } else if (text.includes("SUMMARY SECTION")) { section = "summary"; } } else { console.warn(`Unknown part: ${text}`); } } }; handler.onopentag = (name, attribs) => { if (name === "p" && state !== Part.BeforeStructureDef && state !== Part.AfterStructureDef) { state = Part.AfterStructureDef; } if (state === Part.Tag && attribs.href !== undefined) { if (definition) { const end = attribs.href.indexOf(".htm"); const curSeg = attribs.href.substring(end - 3, end).toUpperCase(); if (curSeg !== "UNH" && curSeg !== "UNS" && curSeg !== "UNT") { const def = definition; lookupSegmentPromises.push(this.loadPage(attribs.href) .then(result => this.parseSegmentDefinitionPage(curSeg, result, def))); } } } }; handler.onclosetag = () => { nextState(); }; const parser = new htmlparser2_1.Parser(handler); parser.write(page); parser.end(); if (definition) { return Promise.resolve({ specObj: definition, promises: lookupSegmentPromises }); } return Promise.reject(new Error("Could not extract values from read page successfully")); }); } loadTypeSpec() { const url = "./" + this.type + "_c.htm"; return this.loadPage(url) .then((page) => this.parsePage(page)) .then((result) => Promise.all(result.promises) .then(() => result.specObj) .catch((error) => { console.warn(`Error while processing segment definition promises: Reason ${error.message}`); return result.specObj; })); } } exports.UNECEMessageStructureParser = UNECEMessageStructureParser; //# sourceMappingURL=messageStructureParser.js.map