UNPKG

butterknife

Version:

Spread the awesome blend of Grunt.js, Travis and Sauce

237 lines (210 loc) 7.16 kB
var fs = require('fs') , walk = require('walk') , _ = require('underscore') , esprima = require('esprima') , escodegen = require('escodegen') , async = require('async') , npm = require('npm') , init = require('init-package-json') ; var GRUNTFILE = 'Gruntfile.js'; var FRAMEWORKS = ['qunit', 'jasmine', 'mocha']; var PACKAGEJSON = 'package.json'; // naive implementation for js unit test cases discovery var findTestCases = function(cb) { var grepFrameworks = function(file, cb) { var success = false , framework = null; fs.readFile(file, function(err, data) { var contents = data.toString().toLowerCase(); _.forEach(FRAMEWORKS, function(v, i) { if (contents.indexOf(v) > -1) { success = true; framework = v; } }); cb(success, framework); }); }; var tests = [] , framework = null; walker = walk.walk('.'); walker.on('names', function(baseDir, namesArr) { if (baseDir.indexOf('node_modules') > -1) { return; } _.forEach(namesArr, function(v, i) { var lcName = v.toLowerCase(); // should also cover cases of .html if (lcName.indexOf('.htm') > -1) { var file = baseDir + '/' + v; grepFrameworks(file, function(success, fmk) { if (success) { tests.push(file); framework = fmk; } }); } }); }); walker.on('end', function() { cb(null, tests, framework); }); }; var setupGrunt = function(tree, tests, framework, done) { // Courtesy of http://sevinf.github.io/blog/2012/09/29/esprima-tutorial/ var traverse = function (node, func) { func(node);//1 for (var key in node) { //2 if (node.hasOwnProperty(key)) { //3 var child = node[key]; var pnt = node; if (typeof child === 'object' && child !== null && key !== 'parent') { //4 if (Array.isArray(child)) { child.forEach(function(node) { //5 node.parent = pnt; traverse(node, func); }); } else { child.parent = pnt; traverse(child, func); //6 } } } } }; // find grunt.initConfig var setupGruntSaucelabs = function(tree, cb) { var available = [] , gruntcfg = null ; traverse(tree, function(node) { if (node.type === 'CallExpression' && node.callee && node.callee.object && node.callee.object.name === 'grunt' && node.callee.property && node.callee.property.name === 'initConfig') { gruntcfg = node; traverse(node, function(sub) { if (sub.type === 'Literal' || sub.type === 'Identifier') { var val = sub.name || sub.value; if (val.toString().indexOf('saucelabs-') > -1 || val === 'connect') { available.push(val); } } }); } }); cb(gruntcfg, available); }; var setupGruntDeps = function(tree, framework, cb) { var done = false; traverse(tree, function(node) { if (node.type === 'CallExpression' && node.callee && node.callee.object && node.callee.object.name === 'grunt' && node.callee.property && node.callee.property.name === 'loadNpmTasks') { var loop = 0 , insert = -1; var gruntDeps = require('../templates/ast/deps.json'); gruntDeps.task = require('../templates/ast/task.json'); gruntDeps.browsers = require('../templates/ast/browsers.json'); if (!done) { // fun, fun, fun... _.forEach(node.parent.parent.body, function(v, i) { loop++; if (v.type === 'ExpressionStatement' && v.expression.type === 'CallExpression' && v.expression.callee && v.expression.callee.property.name === 'loadNpmTasks') { insert = loop; } if (v.type === "ExpressionStatement" && v.expression.arguments && v.expression.arguments.length > 0 && v.expression.arguments[0].value === 'default') { v.expression.arguments[1].elements.push({ "type": "Literal", "value": "sauce" }); } }); var num = 0; if (insert > -1) { _.forEach(gruntDeps.deps, function(v, i) { num++; node.parent.parent.body.splice(insert, 0, v); }); } gruntDeps.task.expression.arguments[1].elements[1].value = 'saucelabs-' + framework; gruntDeps.task.expression.arguments[1].elements[1].raw = "'saucelabs-" + framework + "'"; node.parent.parent.body.splice(insert+num, 0, gruntDeps.task); node.parent.parent.body.splice(1, 0, gruntDeps.browsers); done = true; cb(null); } } }); }; setupGruntSaucelabs(tree, function(gruntCfg, cfgs) { if (cfgs < 2) { var gslAst = require('../templates/ast/saucelabs.json'); gslAst.key.value = gslAst.key.value + framework; _.forEach(tests, function(v, i) { // Weeeeeeeeeee gslAst.value.properties[0].value.properties[0].value.properties[0].value.elements.push({ type: 'Literal', value: v.replace("./", "http://localhost:9999/") }); }); var conAst = require('../templates/ast/connect.json') gruntCfg.arguments[0].properties.push(gslAst); gruntCfg.arguments[0].properties.push(conAst); setupGruntDeps(tree, framework, function(err) { done(null, src); var src = escodegen.generate(tree); src = "/*jshint node:true*/\n" + src; // make jshint happy fs.writeFileSync(GRUNTFILE, src); }); } }); }; module.exports = function(cb) { console.log('Setting up grunt.js and respective tasks.'); fs.exists(GRUNTFILE, function(exists) { if (!exists) { fs.createReadStream(__dirname + '/../' + 'templates/' + GRUNTFILE).pipe(fs.createWriteStream(GRUNTFILE)); } findTestCases(function(err, tests, framework) { var gf = fs.readFileSync(GRUNTFILE); var ast = esprima.parse(gf, { comment: true }); setupGrunt(ast, tests, framework, function(err, src) { npm.load({ 'save-dev': true }, function() { async.series([ function(done) { fs.exists(PACKAGEJSON, function(exists) { if (exists) { return done(null, {}); } init('.', 'package.json', function(err, obj) { obj.scripts.test = 'grunt'; fs.writeFileSync(PACKAGEJSON, JSON.stringify(obj)); done(err, obj); }); }); }, function(done) { npm.commands.install(['process', 'grunt-contrib-uglify', 'grunt-contrib-connect', 'grunt-saucelabs'], function(err, obj) { cb(null); }); } ]); }); }); }); }); };