219 lines
6.2 KiB
JavaScript
219 lines
6.2 KiB
JavaScript
|
var Promise = require("bluebird");
|
||
|
var assert = require("assert");
|
||
|
var path = require("path");
|
||
|
var spawn = require("cross-spawn");
|
||
|
Promise.longStackTraces();
|
||
|
var fs = Promise.promisifyAll(require("fs"));
|
||
|
var notAscii = /[^\u000D\u0019-\u007E]/;
|
||
|
var Table = require('cli-table');
|
||
|
|
||
|
function noStackError(message) {
|
||
|
var e = new Error(message);
|
||
|
e.noStackPrint = true;
|
||
|
return e;
|
||
|
}
|
||
|
|
||
|
function checkAscii(fileName, contents) {
|
||
|
if (notAscii.test(contents)) {
|
||
|
contents.split("\n").forEach(function(line, i) {
|
||
|
if (notAscii.test(line)) {
|
||
|
var lineNo = i + 1;
|
||
|
var col = line.indexOf(RegExp.lastMatch) + 1;
|
||
|
var code = "U+" + (("0000" + line.charCodeAt(col-1)
|
||
|
.toString(16)).slice(-4));
|
||
|
code = RegExp.lastMatch + " (" + code.toUpperCase() + ")";
|
||
|
var fullPath = path.join(process.cwd(), "src", fileName);
|
||
|
throw noStackError("The file " + fullPath + "\ncontains an illegal character: " +
|
||
|
code + " on line " + lineNo + " at column " + col);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var license;
|
||
|
function getLicense() {
|
||
|
if (license) return license;
|
||
|
var licenseFile = path.join(__dirname, "..", "LICENSE");
|
||
|
return license = fs.readFileAsync(licenseFile, "utf8").then(function(text) {
|
||
|
return "/* @preserve\n" + text.split("\n").map(function(line) {
|
||
|
return " * " + line;
|
||
|
}).join("\n") + "\n */\n";
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function cursorTo(x, y) {
|
||
|
if (process.stdout.cursorTo)
|
||
|
process.stdout.cursorTo(x, y);
|
||
|
}
|
||
|
|
||
|
function clearScreenDown() {
|
||
|
if (process.stdout.clearScreenDown)
|
||
|
process.stdout.clearScreenDown();
|
||
|
}
|
||
|
|
||
|
function run(cmd, args, dir, log) {
|
||
|
return new Promise(function(resolve, reject) {
|
||
|
function makeResult(errorMessage) {
|
||
|
var ret = errorMessage ? new Error(errorMessage) : {};
|
||
|
ret.stdout = out.trim();
|
||
|
ret.stderr = err.trim();
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
var out = "";
|
||
|
var err = "";
|
||
|
var c = spawn(cmd, args, {stdin: ["ignore", "ignore", "ignore"], cwd: dir || process.cwd()});
|
||
|
|
||
|
c.stdout.on("data", function(data) {
|
||
|
if (log) process.stdout.write(data.toString());
|
||
|
out += data;
|
||
|
});
|
||
|
c.stderr.on("data", function(data) {
|
||
|
if (log) process.stderr.write(data.toString());
|
||
|
err += data;
|
||
|
});
|
||
|
|
||
|
c.on("error", function(err) {
|
||
|
reject(makeResult(err.message));
|
||
|
});
|
||
|
c.on("close", function(code) {
|
||
|
if (code == 0) resolve(makeResult())
|
||
|
else reject(makeResult(path.basename(cmd) + " exited with code: " + code + "\n" + err.trim()));
|
||
|
})
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function parseDeps(src) {
|
||
|
var rdeps = /function\s*\(\s*([^)]+)\)/;
|
||
|
var match = rdeps.exec(src);
|
||
|
assert.equal(match.length, 2);
|
||
|
var deps = match[1].split(/\s*,\s*/g).map(function(val) {
|
||
|
return val.trim();
|
||
|
});
|
||
|
return deps;
|
||
|
}
|
||
|
|
||
|
var tableLogger = (function() {
|
||
|
var metaKeyCodeReAnywhere = /(?:\x1b)([a-zA-Z0-9])/;
|
||
|
var metaKeyCodeRe = new RegExp('^' + metaKeyCodeReAnywhere.source + '$');
|
||
|
var functionKeyCodeReAnywhere = new RegExp('(?:\x1b+)(O|N|\\[|\\[\\[)(?:' + [
|
||
|
'(\\d+)(?:;(\\d+))?([~^$])',
|
||
|
'(?:M([@ #!a`])(.)(.))', // mouse
|
||
|
'(?:1;)?(\\d+)?([a-zA-Z])'
|
||
|
].join('|') + ')');
|
||
|
|
||
|
function stripVTControlCharacters(str) {
|
||
|
str = str.replace(new RegExp(functionKeyCodeReAnywhere.source, 'g'), '');
|
||
|
return str.replace(new RegExp(metaKeyCodeReAnywhere.source, 'g'), '');
|
||
|
}
|
||
|
|
||
|
var ROWS = 35;
|
||
|
var prevLog = new Array(ROWS);
|
||
|
var log = new Array(ROWS);
|
||
|
for (var i = 0; i < ROWS; ++i) log[i] = [];
|
||
|
var tableOpts = {
|
||
|
chars: {
|
||
|
'mid': '',
|
||
|
'left-mid': '',
|
||
|
'mid-mid': '',
|
||
|
'right-mid': ''
|
||
|
},
|
||
|
style: {
|
||
|
'padding-left': 0,
|
||
|
'padding-right': 0,
|
||
|
compact: true
|
||
|
}
|
||
|
};
|
||
|
var table;
|
||
|
var split;
|
||
|
|
||
|
function showTable() {
|
||
|
assert(!table);
|
||
|
table = new Table(tableOpts);
|
||
|
table.push.apply(table, log);
|
||
|
table = table.toString();
|
||
|
split = table.split("\n").map(function(line) {
|
||
|
return stripVTControlCharacters(line);
|
||
|
});
|
||
|
cursorTo(0, 0);
|
||
|
process.stdout.write(table);
|
||
|
cursorTo(0, split.length + 1);
|
||
|
}
|
||
|
|
||
|
function addTests(tests) {
|
||
|
var cols = 0;
|
||
|
tests.forEach(function(test) {
|
||
|
var index = test.index;
|
||
|
var row = index % ROWS;
|
||
|
var column = (index / ROWS) | 0;
|
||
|
cols = Math.max(column, cols);
|
||
|
log[row][column] = "\u001b[m" + test.name + " \u001b[31m\u00D7 ";
|
||
|
});
|
||
|
cols = cols + 1;
|
||
|
for (var i = 0; i < log.length; ++i) {
|
||
|
var row = log[i];
|
||
|
for (var j = 0; j < cols; ++j) {
|
||
|
if (!row[j]) {
|
||
|
row[j] = " ";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
showTable();
|
||
|
}
|
||
|
|
||
|
function getPosition(test) {
|
||
|
for (var y = 0; y < split.length; ++y) {
|
||
|
var s = split[y];
|
||
|
var x = s.search(new RegExp(test.nameMatcher));
|
||
|
if (x >= 0) {
|
||
|
return {
|
||
|
x: x + test.name.length,
|
||
|
y: y
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
assert(false);
|
||
|
}
|
||
|
|
||
|
function update(test, message) {
|
||
|
var pos = getPosition(test);
|
||
|
cursorTo(pos.x + 1, pos.y);
|
||
|
process.stdout.write(message);
|
||
|
cursorTo(0, split.length + 2);
|
||
|
}
|
||
|
|
||
|
function testFail(test) {
|
||
|
update(test, "\u001b[31m\u00D7 FAILURE\u001b[39m");
|
||
|
}
|
||
|
|
||
|
|
||
|
function testSuccess(test) {
|
||
|
update(test, "\u001b[32m\u221A\u001b[39m")
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
addTests: addTests,
|
||
|
testFail: testFail,
|
||
|
testSuccess: testSuccess
|
||
|
}
|
||
|
})();
|
||
|
|
||
|
function stringToStream(str) {
|
||
|
var Readable = require('stream').Readable;
|
||
|
var readable = new Readable()
|
||
|
readable.push(str + "");
|
||
|
readable.push(null);
|
||
|
return readable;
|
||
|
}
|
||
|
|
||
|
module.exports = {
|
||
|
checkAscii: checkAscii,
|
||
|
getLicense: getLicense,
|
||
|
run: run,
|
||
|
parseDeps: parseDeps,
|
||
|
tableLogger: tableLogger,
|
||
|
stringToStream: stringToStream,
|
||
|
cursorTo: cursorTo,
|
||
|
clearScreenDown: clearScreenDown
|
||
|
};
|