UNPKG

eyereasonerjs

Version:

A TypeScript wrapper for the EYE reasoner

129 lines (128 loc) 5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const child_process_1 = require("child_process"); const fs_1 = require("fs"); const tmp_promise_1 = require("tmp-promise"); class Eye { constructor(options) { this.commentRegex = /^#.*$\n/mg; this.localIdentifierRegex = /<\/tmp\/([^#]+)#([^>]+>)/g; this.prefixDeclarationRegex = /^@prefix|PREFIX ([\w\-]*:) <([^>]+)>\.?\n/g; this.eyeSignatureRegex = /^(Id: euler\.yap|EYE)/m; this.errorRegex = /^\*\* ERROR \*\*\s*(.*)$/m; this.options = options || { spawn: child_process_1.spawn }; this.eyePath = process.platform === 'win32' ? 'eye.cmd' : 'eye'; this.spawn = this.options.spawn; } async queryTmp(files, query, flags) { const tmp = await (0, tmp_promise_1.file)(); await this.queryFile(files, query, tmp.path, flags); return tmp; } async queryFile(files, query, path, flags) { const output = await this.query(files, query, flags); return new Promise(resolve => { (0, fs_1.writeFile)(path, output, (err) => { if (err) throw err; resolve(path); }); }); } pass(files, flags) { const params = files.concat('--nope', flags ? flags : []); const eye = this.spawn(this.eyePath, params); let output = ''; let error = ''; eye.stdout.on('data', data => output += data); eye.stderr.on('data', data => error += data); return new Promise((resolve, reject) => { eye.once('error', e => { eye.removeAllListeners(); return reject(e); }); eye.stdout.once('end', () => { eye.stdout.removeAllListeners(); resolve(this.eyeFinished(error, output)); }); eye.stderr.once('end', () => { eye.stderr.removeAllListeners(); resolve(this.eyeFinished(error, output)); }); }); } query(files, query, flags) { return this.pass(files.concat('--query', query), flags); } clean(n3) { // remove comments n3 = n3.replace(this.commentRegex, ''); // remove prefix declarations from the document, storing them in an object const prefixes = {}; n3 = n3.replace(this.prefixDeclarationRegex, (match, prefix, namespace) => { prefixes[prefix] = namespace.replace(/^file:\/\/.*?([^\/]+)$/, '$1'); return ''; }); // remove unnecessary whitespace from the document n3 = n3.trim(); // find the used prefixes const prefixLines = []; for (const prefix of Object.keys(prefixes)) { const namespace = prefixes[prefix]; // EYE does not use prefixes of namespaces ending in a slash (instead of a hash), // so we apply them manually if (namespace.match(/\/$/)) // warning: this could wreck havoc inside string literals n3 = n3.replace(new RegExp('<' + this.escapeForRegExp(namespace) + '(\\w+)>', 'gm'), prefix + '$1'); // add the prefix if it's used // (we conservatively employ a wide definition of "used") if (n3.match(prefix)) prefixLines.push('PREFIX ', prefix, ' <', namespace, '>\n'); } // join the used prefixes and the rest of the N3 return !prefixLines.length ? n3 : (prefixLines.join('') + '\n' + n3); } // after both streams are complete, report output or error eyeFinished(error, output) { // if (!(eye.stdout.finished && eye.stderr.finished)) // return ''; // resources.forEach(function (resource) { // self.resourceCache.release(resource, function () { }); // }); // has EYE not been executed? if (!error.match(this.eyeSignatureRegex)) throw new Error(error); // EYE has been executed else { const errorMatch = error.match(this.errorRegex); // did EYE report errors? if (errorMatch) throw new Error(errorMatch[1]); // EYE reported no errors else return this.clean(output); } } stopEye(eye) { if (eye) { eye.removeAllListeners('exit'); eye.stdout.removeAllListeners(); eye.stderr.removeAllListeners(); eye.kill(); } } escapeForRegExp(text) { return text.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); } async stringToTmp(input) { const tmp = await (0, tmp_promise_1.file)(); return new Promise(resolve => { (0, fs_1.writeFile)(tmp.path, input, (err) => { if (err) throw err; resolve(tmp); }); }); } } exports.default = Eye;