isoxml-angular
Version:
JavaScript library to parse and generate ISOXML (ISO11783-10) files
296 lines (295 loc) • 18.5 kB
JavaScript
;
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());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = require("fs");
const jszip_1 = __importDefault(require("jszip"));
const ISOXMLManager_1 = require("./ISOXMLManager");
const xmlManager_1 = require("./xmlManager");
// make sure that Array and Object prototype pollution doesn't break the library
Array.prototype.anyCustomMethod = () => 0;
Object.prototype.anyCustomMethod = () => 0;
function modifyZip(filename, modifier) {
return __awaiter(this, void 0, void 0, function* () {
const data = (0, fs_1.readFileSync)(filename);
const zip = yield jszip_1.default.loadAsync(data);
yield modifier(zip);
return yield zip.generateAsync({ type: 'uint8array' });
});
}
describe('ISOXML Manager', () => {
it('should parse ISOXML as ZIP', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlData = (0, fs_1.readFileSync)('./data/test1.zip');
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
yield isoxmlManager.parseISOXMLFile(new Uint8Array(isoxmlData.buffer), 'application/zip');
expect(isoxmlManager.rootElement).toBeTruthy();
expect(isoxmlManager.getWarnings()).toHaveLength(0);
}));
it('should parse TASKDATA.XML as string', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlData = (0, fs_1.readFileSync)('./data/test1.zip');
const zip = yield jszip_1.default.loadAsync(isoxmlData);
const taskDataStr = yield zip.file("TASKDATA/TASKDATA.XML").async('string');
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
yield isoxmlManager.parseISOXMLFile(taskDataStr, 'application/xml');
expect(isoxmlManager.rootElement).toBeTruthy();
expect(isoxmlManager.rootElement.attributes.Task).toHaveLength(2);
expect(isoxmlManager.options.rootFolder).toBe('');
}));
it('should parse ISOXML with external files', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlData = (0, fs_1.readFileSync)('./data/2021-04-09T15_33_26_taskdata.zip');
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
yield isoxmlManager.parseISOXMLFile(new Uint8Array(isoxmlData.buffer), 'application/zip');
expect(isoxmlManager.rootElement.attributes.Task).toBeTruthy();
expect(isoxmlManager.getReferenceByXmlId('TSK-1').entity).toBeTruthy();
expect(isoxmlManager.rootElement.attributes.ExternalFileReference).toHaveLength(0);
expect(isoxmlManager.getWarnings()).toHaveLength(2);
// const data = await isoxmlManager.saveISOXML()
// writeFileSync('./data/test1_out.zip', data)
}));
it('should parse and save grid files', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlData = (0, fs_1.readFileSync)('./data/task_with_grid.zip');
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
yield isoxmlManager.parseISOXMLFile(new Uint8Array(isoxmlData.buffer), 'application/zip');
expect(isoxmlManager.getWarnings()).toHaveLength(1);
const data = yield isoxmlManager.saveISOXML();
// writeFileSync('./data/test_grid_out.zip', data)
expect(data.length).toBe(14065);
const zip = yield jszip_1.default.loadAsync(data);
expect(zip.file("TASKDATA/GRD00001.bin")).toBeTruthy();
}));
it('should parse and save timelog files', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlData = (0, fs_1.readFileSync)('./data/2021-04-09T15_33_26_taskdata.zip');
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
yield isoxmlManager.parseISOXMLFile(new Uint8Array(isoxmlData.buffer), 'application/zip');
expect(isoxmlManager.getWarnings()).toHaveLength(2);
const data = yield isoxmlManager.saveISOXML();
// writeFileSync('./data/test_timelog_out.zip', data)
const zip = yield jszip_1.default.loadAsync(data);
expect(zip.file("TASKDATA/TLG00001.xml")).toBeTruthy();
expect(zip.file("TASKDATA/TLG00001.bin")).toBeTruthy();
}));
it('should preserve attached files', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlData = (0, fs_1.readFileSync)('./data/task_full.zip');
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
yield isoxmlManager.parseISOXMLFile(new Uint8Array(isoxmlData.buffer), 'application/zip');
expect(isoxmlManager.getWarnings()).toHaveLength(0);
const data = yield isoxmlManager.saveISOXML();
// writeFileSync('./data/test_grid_out.zip', data)
const zip = yield jszip_1.default.loadAsync(data);
expect(zip.file("TASKDATA/TEST1234.BIN")).toBeTruthy();
}));
it('should preserve proprietary attributes and elements', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlData = (0, fs_1.readFileSync)('./data/task_full.zip');
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
yield isoxmlManager.parseISOXMLFile(new Uint8Array(isoxmlData.buffer), 'application/zip');
expect(isoxmlManager.getWarnings()).toHaveLength(0);
const data = yield isoxmlManager.saveISOXML();
// writeFileSync('./data/test_grid_out.zip', data)
const isoxmlManager2 = new ISOXMLManager_1.ISOXMLManager();
yield isoxmlManager2.parseISOXMLFile(data, 'application/zip');
expect(isoxmlManager2.getWarnings()).toHaveLength(0);
expect(isoxmlManager2.rootElement.attributes.ProprietaryTags).toHaveProperty('P1234_Area');
expect(isoxmlManager2.rootElement.attributes.BaseStation[0].attributes.ProprietaryAttributes).toHaveProperty('P123_Area');
}));
it('should parse and save ISOXML', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlData = (0, fs_1.readFileSync)('./data/test1.zip');
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
yield isoxmlManager.parseISOXMLFile(new Uint8Array(isoxmlData.buffer), 'application/zip');
expect(isoxmlManager.getWarnings()).toHaveLength(0);
const data = yield isoxmlManager.saveISOXML();
// writeFileSync('./data/test1_out.zip', data)
expect(data.length).toBe(4044);
}));
it('should manually create ISOXML', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
const task = isoxmlManager.createEntityFromAttributes("TSK" /* TAGS.Task */, {
TaskStatus: "1" /* TaskTaskStatusEnum.Planned */
});
isoxmlManager.registerEntity(task);
isoxmlManager.rootElement.attributes.Task = [task];
const data = yield isoxmlManager.saveISOXML();
// writeFileSync('./data/test1_out.zip', data)
expect(data.length).toBe(470);
const zip = yield jszip_1.default.loadAsync(data);
expect(zip.file("TASKDATA/TASKDATA.XML")).toBeTruthy();
}));
it('should handle strings with special characters properly', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
const task = isoxmlManager.createEntityFromAttributes("TSK" /* TAGS.Task */, {
TaskStatus: "1" /* TaskTaskStatusEnum.Planned */
});
isoxmlManager.registerEntity(task);
isoxmlManager.rootElement.attributes.Task = [task];
isoxmlManager.updateOptions({ fmisTitle: `&<>'"` });
const data = yield isoxmlManager.saveISOXML();
// writeFileSync('./data/out_characters.zip', data)
const isoxmlManager2 = new ISOXMLManager_1.ISOXMLManager();
yield isoxmlManager2.parseISOXMLFile(data, 'application/zip');
expect(isoxmlManager2.options.fmisTitle).toBe(`&<>'"`);
}));
it('should preserve FMIS IDs', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager({ fmisURI: 'http://example.com' });
const task = isoxmlManager.createEntityFromAttributes("TSK" /* TAGS.Task */, {
TaskStatus: "1" /* TaskTaskStatusEnum.Planned */
});
const ref = isoxmlManager.registerEntity(task, null, '777');
isoxmlManager.rootElement.attributes.Task = [task];
const data = yield isoxmlManager.saveISOXML();
// writeFileSync('./data/test1_out.zip', data)
const isoxmlManager2 = new ISOXMLManager_1.ISOXMLManager({ fmisURI: 'http://example.com' });
yield isoxmlManager2.parseISOXMLFile(data, 'application/zip');
const parsedRef = isoxmlManager2.getReferenceByXmlId(ref.xmlId);
expect(parsedRef.fmisId).toBe('777');
}));
it('should support "rootFolder" option', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager({ rootFolder: "testFolder" });
const task = isoxmlManager.createEntityFromAttributes("TSK" /* TAGS.Task */, {
TaskStatus: "1" /* TaskTaskStatusEnum.Planned */
});
isoxmlManager.registerEntity(task);
isoxmlManager.rootElement.attributes.Task = [task];
const data = yield isoxmlManager.saveISOXML();
const zip = yield jszip_1.default.loadAsync(data);
expect(zip.file("testFolder/TASKDATA.XML")).toBeTruthy();
}));
it('should generate unique filenames', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
const firstName = isoxmlManager.generateUniqueFilename("GRD" /* TAGS.Grid */);
expect(firstName).toBe('GRD00001');
isoxmlManager.addFileToSave('', firstName + '.BIN');
const secondName = isoxmlManager.generateUniqueFilename("GRD" /* TAGS.Grid */);
expect(secondName).toBe('GRD00002');
}));
it('should not save V4Only elements in V3', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlData = (0, fs_1.readFileSync)('./data/task_full.zip');
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
yield isoxmlManager.parseISOXMLFile(new Uint8Array(isoxmlData.buffer), 'application/zip');
expect(isoxmlManager.getWarnings()).toHaveLength(0);
isoxmlManager.updateOptions({ version: 3 });
const data = yield isoxmlManager.saveISOXML();
// writeFileSync('./data/test_grid_out.zip', data)
const isoxmlManager2 = new ISOXMLManager_1.ISOXMLManager();
yield isoxmlManager2.parseISOXMLFile(data, 'application/zip');
expect(isoxmlManager2.getWarnings()).toHaveLength(0);
expect(isoxmlManager2.options.version).toBe(3);
expect(isoxmlManager2.rootElement.attributes).not.toHaveProperty('BaseStation');
expect(isoxmlManager2.rootElement.attributes.CropType[0].attributes).not.toHaveProperty('ProductGroupIdRef');
}));
it('should add warnings', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlData = (0, fs_1.readFileSync)('./data/task_with_warnings.zip');
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
yield isoxmlManager.parseISOXMLFile(new Uint8Array(isoxmlData.buffer), 'application/zip');
const warnings = isoxmlManager.getWarnings();
expect(warnings).toHaveLength(3);
expect(warnings.find(warn => warn.startsWith('[TSK1->TZN[1]]'))).toBeTruthy();
expect(warnings.find(warn => warn.startsWith('[TSK1]'))).toBeTruthy();
}));
it('getParsedFile should not throw errors', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlData = (0, fs_1.readFileSync)('./data/test1.zip');
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
expect(isoxmlManager.getParsedFile('not_existing.xml', false)).toBeNull();
yield isoxmlManager.parseISOXMLFile(new Uint8Array(isoxmlData.buffer), 'application/zip');
expect(isoxmlManager.getParsedFile('not_existing.xml', false)).toBeNull();
}));
it('getEntityByXmlId should not throw errors', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
expect(isoxmlManager.getEntityByXmlId('XXX')).toBeNull();
}));
it('should handle unknown data types', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
yield expect(isoxmlManager.parseISOXMLFile('XXX', 'unknown/type')).rejects.toThrow();
}));
it('should handle invalid XML', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
const invalidXML = (0, xmlManager_1.js2xml)({ 'tag': 'value' });
yield expect(isoxmlManager.parseISOXMLFile(invalidXML, 'application/xml')).rejects.toThrow();
const zipWriter = new jszip_1.default();
zipWriter.file('TASKDATA/TASKDATA.XML', invalidXML);
const zip = yield zipWriter.generateAsync({ type: 'uint8array' });
yield expect(isoxmlManager.parseISOXMLFile(zip, 'application/zip')).rejects.toThrow();
}));
it('should add a warning for zip files with multiple main files', () => __awaiter(void 0, void 0, void 0, function* () {
// create updated file
const updatedZip = yield modifyZip('./data/test1.zip', (zip) => __awaiter(void 0, void 0, void 0, function* () {
const taskDataStr = yield zip.file("TASKDATA/TASKDATA.XML").async('string');
zip.file("TASKDATA_NEW/TASKDATA.XML", taskDataStr);
}));
// parse updated file
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
yield isoxmlManager.parseISOXMLFile(updatedZip, 'application/zip');
expect(isoxmlManager.getWarnings()).toHaveLength(1);
}));
it('should read main file from any directory', () => __awaiter(void 0, void 0, void 0, function* () {
// create updated file
const updatedZip = yield modifyZip('./data/test1.zip', (zip) => __awaiter(void 0, void 0, void 0, function* () {
const taskDataStr = yield zip.file("TASKDATA/TASKDATA.XML").async('string');
zip.remove("TASKDATA/TASKDATA.XML");
zip.file("TASKDATA_NEW/TASKDATA.xml", taskDataStr);
}));
// parse updated file
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
yield isoxmlManager.parseISOXMLFile(updatedZip, 'application/zip');
expect(isoxmlManager.getWarnings()).toHaveLength(1);
}));
it('should add a warning for zip files with wrong letter case', () => __awaiter(void 0, void 0, void 0, function* () {
// create updated file
const updatedZip = yield modifyZip('./data/test1.zip', (zip) => __awaiter(void 0, void 0, void 0, function* () {
const taskDataStr = yield zip.file("TASKDATA/TASKDATA.XML").async('string');
zip.remove("TASKDATA/TASKDATA.XML");
zip.file("TASKDATA/TaskData.xml", taskDataStr);
}));
// parse updated file
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
yield isoxmlManager.parseISOXMLFile(updatedZip, 'application/zip');
expect(isoxmlManager.getWarnings()).toHaveLength(1);
}));
it('should not parse zip files without main file', () => __awaiter(void 0, void 0, void 0, function* () {
// create updated file
const updatedZip = yield modifyZip('./data/test1.zip', (zip) => __awaiter(void 0, void 0, void 0, function* () {
zip.remove("TASKDATA/TASKDATA.XML");
}));
// parse updated file
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
yield expect(isoxmlManager.parseISOXMLFile(updatedZip, 'application/zip')).rejects.toThrow();
}));
it('should return null for unknown entity types', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
expect(isoxmlManager.createEntityFromAttributes('unknown_tag', {})).toBeNull();
expect(isoxmlManager.createEntityFromXML('unknown_tag', {})).toBeNull();
}));
describe('registerEntity', () => {
it('should catch inconsistency errors in entities', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
const task = isoxmlManager.createEntityFromAttributes("TSK" /* TAGS.Task */, {
TaskStatus: "1" /* TaskTaskStatusEnum.Planned */
});
expect(isoxmlManager.registerEntity(task, 'invalid')).toBeUndefined();
expect(isoxmlManager.registerEntity(task, 'FRM-1')).toBeUndefined();
expect(isoxmlManager.registerEntity()).toBeUndefined();
}));
it('should not register duplicated entities', () => __awaiter(void 0, void 0, void 0, function* () {
const isoxmlManager = new ISOXMLManager_1.ISOXMLManager();
const task1 = isoxmlManager.createEntityFromAttributes("TSK" /* TAGS.Task */, {
TaskStatus: "1" /* TaskTaskStatusEnum.Planned */
});
const task2 = isoxmlManager.createEntityFromAttributes("TSK" /* TAGS.Task */, {
TaskStatus: "1" /* TaskTaskStatusEnum.Planned */
});
isoxmlManager.registerEntity(task1, 'TSK-1', 'ext_id_1');
const ref1 = isoxmlManager.registerEntity(task1);
expect(ref1.xmlId).toEqual('TSK-1');
const ref2 = isoxmlManager.registerEntity(task2, null, 'ext_id_1');
expect(ref2.xmlId).toEqual('TSK-1');
}));
});
});