"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('
")) {
const regexp = /^([\d]*)\s*?([X|\\*]?)\s* ")) {
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