eyereasonerjs
Version:
A TypeScript wrapper for the EYE reasoner
129 lines (128 loc) • 5 kB
JavaScript
;
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;