phpjs
Version:
268 lines (232 loc) • 7.79 kB
JavaScript
var cli = require('cli').enable('status', 'help', 'version', 'glob', 'timeout');
var fs = require('fs');
var glob = require('glob');
var path = require('path');
var _ = require('underscore');
var phpjsutil = new require('../lib/phpjsutil');
var equal = require('deep-equal');
var __root = __dirname + '/..';
var beautify = require('js-beautify').js_beautify;
// Not ideal: http://stackoverflow.com/questions/8083410/how-to-set-default-timezone-in-node-js
process.env.TZ = 'UTC';
// --debug works out of the box. See -h
cli.parse({
action : ['a', 'Test / Build', 'string', 'test'],
output : ['o', 'Build output file', 'string', __root + '/build/npm.js'],
name : ['n', 'Function name to test', 'path', '*'],
category: ['c', 'Category to test', 'path', '*'],
abort : ['a', 'Abort on first failure']
});
var PhpjsUtil = phpjsutil({
injectDependencies: ['ini_set', 'ini_get'],
equal : equal,
debug : cli.debug,
globals : {
'XMLHttpRequest': '{}',
'window': '{' +
'window: {},' +
'document: {' +
'lastModified: 1388954399,' +
'getElementsByTagName: function(){return [];}' +
'},' +
'location: {' +
'href: ""' +
'}' +
'}',
}
});
// Environment-specific file opener. function name needs to
// be translated to code. The difficulty is in finding the
// category.
PhpjsUtil.opener = function(name, cb) {
var pattern = __root + '/functions/*/' + name + '.js';
glob(pattern, {}, function(err, files) {
if (err) {
return self.error('Could not glob for ' + pattern + '. ' + err);
}
var filepath = files[0];
if (!filepath) {
return cb('Could not find ' + pattern);
}
fs.readFile(filepath, 'utf-8', function(err, code) {
if (err) {
return cb('Error while opening ' + filepath + '. ' + err);
}
return cb(null, code);
});
});
};
cli.lpad = function(str, len, pad) {
if (!pad) pad = ' ';
if (!len) len = 20;
str = str + '';
if (str.length > len) {
return str;
}
return (new Array(len - str.length).join(pad)) + str;
};
cli.cleanup = function(args, options) {
var self = this;
var pattern = __root + '/functions/' + options.category + '/' + options.name + '.js';
self.glob(pattern, function (err, params, file) {
if (err) {
return self.error('Could not glob for ' + pattern + '. ' + err);
}
var buf = '';
buf += params.func_signature.trim() + '\n';
var longestKey = 0;
_.each(params.headKeys, function (items, key) {
var len = key.length;
if (key === 'example') {
key += 3;
}
if (len >= longestKey) {
longestKey = len;
}
});
longestKey += 1;
var key, val, items, vals, i, itemNr;
var headKeys = {
'discuss at': [['http://phpjs.org/functions/' + params.name]]
};
_.extend(headKeys, params.headKeys);
// If you want to overwrite:
// headKeys['discuss at'] = [['http://phpjs.org/functions/' + params.name + '/']];
for (key in headKeys){
items = headKeys[key];
for (itemNr in items) {
vals = items[itemNr];
for (i in vals) {
val = vals[i];
buf += ' // ' + self.lpad((key === 'example' ? (key + ' ' + ((itemNr*1)+1)) : key), longestKey) + ': ' + val + '\n';
}
if (key === 'example') {
vals = headKeys.returns[itemNr];
for (i in vals) {
val = vals[i];
buf += ' // ' + self.lpad('returns' + ' ' + ((itemNr*1)+1), longestKey) + ': ' + val + '\n';
}
delete headKeys.returns[itemNr];
}
}
}
buf += '\n';
buf += ' ' + params.body;
buf += '\n';
buf += '}\n';
buf.replace(/\r/g, '');
buf = beautify(buf, {
"indent_size": 2,
"indent_char": " ",
"indent_level": 0,
"indent_with_tabs": false,
"preserve_newlines": true,
"max_preserve_newlines": 2,
"jslint_happy": false,
"brace_style": "collapse",
"keep_array_indentation": false,
"keep_function_indentation": false,
"space_before_conditional": true,
"break_chained_methods": true,
"eval_code": false,
"unescape_strings": false,
"wrap_line_length": 120
});
// console.log(buf);
fs.writeFileSync(file, buf);
});
};
cli.buildnpm = function(args, options) {
var self = this;
var pattern = __root + '/functions/' + options.category + '/' + options.name + '.js';
fs.writeFileSync(options.output, '// This file is generated by `make build`. \n');
fs.appendFileSync(options.output, '// Do NOT edit by hand. \n');
fs.appendFileSync(options.output, '// \n');
fs.appendFileSync(options.output, '// Make function changes in ./functions and \n');
fs.appendFileSync(options.output, '// generator changes in ./lib/phpjsutil.js \n');
for (var global in PhpjsUtil.globals) {
fs.appendFileSync(options.output, 'exports.' + global + ' = ' + PhpjsUtil.globals[global] + ';\n');
}
fs.appendFileSync(options.output, 'exports.window.window = exports.window;\n');
self.glob(pattern, function (err, params, file) {
if (err) {
return self.error('Could not glob for ' + pattern + '. ' + err);
}
var buf = '\n';
buf += 'exports.' + params.func_name + ' = function (' + params.func_arguments.join(', ') + ') {\n';
buf += ' ' + params.body.split('\n').join('\n ').replace(/^ $/g, '') + '\n';
buf += '};\n';
fs.appendFileSync(options.output, buf);
});
};
cli.glob = function(pattern, cb) {
glob(pattern, {}, function(err, files) {
var names = [];
var map = {};
for (var i in files) {
var file = files[i];
var name = path.basename(file, '.js');
if (file.indexOf('/_') === -1) {
names.push(name);
map[name] = file;
}
}
names.forEach(function(name) {
PhpjsUtil.load(name, function(err, params) {
if (err) {
return cb(err);
}
return cb(null, params, map[name]);
});
});
});
};
cli.test = function(args, options) {
var self = this;
var pattern = __root + '/functions/' + options.category + '/' + options.name + '.js';
self.pass_cnt = 0;
self.know_cnt = 0;
self.fail_cnt = 0;
self.skip_cnt = 0;
process.on('exit', function() {
var msg = self.pass_cnt + ' passed / ' + self.fail_cnt + ' failed / ' + self.know_cnt + ' known / ' + self.skip_cnt + ' skipped';
if (self.fail_cnt) {
cli.fatal(msg);
} else {
cli.ok(msg);
}
});
var knownFailures = fs.readFileSync(__root + '/known_failures.txt', 'utf-8').split('\n');
self.glob(pattern, function(err, params, file) {
if (err) {
return self.error('Could not glob for ' + pattern + '. ' + err);
}
if (params.headKeys.test && params.headKeys.test[0][0] === 'skip') {
self.skip_cnt++;
return cli.info('--> ' + params.name + ' skipped as instructed. ');
}
PhpjsUtil.test(params, function(err, test, params) {
var testName = params.name + '#' + ( + (test.number * 1) + 1);
if (!err) {
self.pass_cnt++;
cli.debug('--> ' + testName + ' passed. ');
} else {
if (knownFailures.indexOf(testName) > -1) {
cli.error('--> ' + testName + ' known error. ');
cli.error(err);
self.know_cnt++;
} else {
cli.error('--> ' + testName + ' failed. ');
cli.error(err);
self.fail_cnt++;
if (options.abort) {
cli.fatal('Aborting on first failure as instructed. ');
}
}
}
});
});
};
cli.main(function(args, options) {
cli[options.action](args, options);
});