diff --git a/.eslintignore b/.eslintignore index a2f320ee445b1..74400538bb8ed 100644 --- a/.eslintignore +++ b/.eslintignore @@ -7,3 +7,4 @@ src/vendor_deprecated src/**/__tests__/** # This should be enabled but that folder has too much in it that doesn't belong src/test +test/the-files-to-test.generated.js \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000000000..9f593825e5ee9 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,50 @@ +--- +parser: esprima-fb + +env: + browser: true + node: true + +globals: + __DEV__: true + +rules: + # ERRORS + space-before-blocks: [2, 'always'] + brace-style: 2 + space-after-keywords: 2 + strict: 2 + # We actually have a transform to support this and we fix this for bundled + # releases but not for the npm package, so enforce it strictly + no-comma-dangle: 2 + # Make this a warning for now. We do this in a few places so we might need to + # disable + no-unused-expressions: 2 + block-scoped-var: 2 + eol-last: 2 + dot-notation: 2 + consistent-return: 2 + no-unused-vars: [2, args: none] + quotes: [2, 'single'] + + # WARNINGS + # This is the only one that's hard to track since we don't lint just changes. + max-len: [1, 80] + + # WISHLIST. One day... + # We'll need a custom version of this that does a subset of the whole rule. + # Otherwise this is just too noisy. + # valid-jsdoc: 1 + + # DISABLED. These aren't compatible with our style + # We use this for private/internal variables + no-underscore-dangle: 0 + # We pass constructors around / access them from members + new-cap: 0 + # We do this a lot. + no-use-before-define: 0 + # We do this in a few places to align values + key-spacing: 0 + + # DISABLED. These currently cause errors when running. + no-multi-spaces: 0 diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index dcb645fe05697..0000000000000 --- a/.jshintrc +++ /dev/null @@ -1,18 +0,0 @@ -{ - "node": true, - - "boss": true, - "curly": true, - "devel": true, - "eqnull": true, - "expr": true, - "funcscope": true, - "globalstrict": true, - "loopfunc": true, - "newcap": false, - "noempty": true, - "nonstandard": true, - "sub": true, - "undef": true, - "unused": "vars" -} diff --git a/Gruntfile.js b/Gruntfile.js index cb251253f3f3a..1a95ef0c1d195 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,6 +12,7 @@ var npmReactTasks = require('./grunt/tasks/npm-react'); var npmReactToolsTasks = require('./grunt/tasks/npm-react-tools'); var versionCheckTask = require('./grunt/tasks/version-check'); var gemReactSourceTasks = require('./grunt/tasks/gem-react-source'); +var eslintTask = require('./grunt/tasks/eslint'); module.exports = function(grunt) { @@ -22,45 +23,43 @@ module.exports = function(grunt) { browserify: require('./grunt/config/browserify'), populist: require('./grunt/config/populist')(grunt), connect: require('./grunt/config/server')(grunt), - "webdriver-jasmine": require('./grunt/config/webdriver-jasmine'), - "webdriver-perf": require('./grunt/config/webdriver-perf'), + 'webdriver-jasmine': require('./grunt/config/webdriver-jasmine'), + 'webdriver-perf': require('./grunt/config/webdriver-perf'), npm: require('./grunt/config/npm'), - clean: ['./build', './*.gem', './docs/_site', './examples/shared/*.js', '.module-cache'], + clean: [ + './build', + './*.gem', + './docs/_site', + './examples/shared/*.js', + '.module-cache' + ], jshint: require('./grunt/config/jshint'), + /*eslint-disable camelcase */ compare_size: require('./grunt/config/compare_size') + /*eslint-enable camelcase */ }); grunt.config.set('compress', require('./grunt/config/compress')); Object.keys(grunt.file.readJSON('package.json').devDependencies) - .filter(function(npmTaskName) { return npmTaskName.indexOf('grunt-') === 0; }) - .filter(function(npmTaskName) { return npmTaskName != 'grunt-cli'; }) - .forEach(function(npmTaskName) { grunt.loadNpmTasks(npmTaskName); }); - - // Super simplified eslint task that we can use to replace linting. This just - // shells out to eslint. - grunt.registerTask('eslint', function() { - var done = this.async(); - grunt.util.spawn({ - cmd: 'node_modules/.bin/eslint', - args: ['src'] - }, function(err, result, code) { - if (code === 0) { - grunt.log.ok('Lint passed (but may contain warnings)'); - } else { - grunt.log.error('Lint failed'); - } - if (result.stdout.length) { - grunt.log.writeln(result.stdout); - } - - done(code === 0); + .filter(function(npmTaskName) { + return npmTaskName.indexOf('grunt-') === 0; + }) + .filter(function(npmTaskName) { + return npmTaskName !== 'grunt-cli'; + }) + .forEach(function(npmTaskName) { + grunt.loadNpmTasks(npmTaskName); }); - }); + + grunt.registerTask('eslint', eslintTask); grunt.registerTask('lint', ['eslint']); - grunt.registerTask('download-previous-version', require('./grunt/tasks/download-previous-version.js')); + grunt.registerTask( + 'download-previous-version', + require('./grunt/tasks/download-previous-version.js') + ); grunt.registerTask('delete-build-modules', function() { if (grunt.file.exists('build/modules')) { @@ -93,11 +92,28 @@ module.exports = function(grunt) { grunt.registerTask('version-check', versionCheckTask); - grunt.registerTask('build:basic', ['jsx:normal', 'version-check', 'browserify:basic']); - grunt.registerTask('build:addons', ['jsx:normal', 'browserify:addons']); - grunt.registerTask('build:transformer', ['jsx:normal', 'browserify:transformer']); - grunt.registerTask('build:min', ['jsx:normal', 'version-check', 'browserify:min']); - grunt.registerTask('build:addons-min', ['jsx:normal', 'browserify:addonsMin']); + grunt.registerTask('build:basic', [ + 'jsx:normal', + 'version-check', + 'browserify:basic' + ]); + grunt.registerTask('build:addons', [ + 'jsx:normal', + 'browserify:addons' + ]); + grunt.registerTask('build:transformer', [ + 'jsx:normal', + 'browserify:transformer' + ]); + grunt.registerTask('build:min', [ + 'jsx:normal', + 'version-check', + 'browserify:min' + ]); + grunt.registerTask('build:addons-min', [ + 'jsx:normal', + 'browserify:addonsMin' + ]); grunt.registerTask('build:withCodeCoverageLogging', [ 'jsx:normal', 'version-check', @@ -117,8 +133,15 @@ module.exports = function(grunt) { 'version-check', 'populist:test' ]); - grunt.registerTask('build:npm-react', ['version-check', 'jsx:normal', 'npm-react:release']); - grunt.registerTask('build:gem-react-source', ['build', 'gem-react-source:release']); + grunt.registerTask('build:npm-react', [ + 'version-check', + 'jsx:normal', + 'npm-react:release' + ]); + grunt.registerTask('build:gem-react-source', [ + 'build', + 'gem-react-source:release' + ]); grunt.registerTask('webdriver-phantomjs', webdriverPhantomJSTask); @@ -161,7 +184,7 @@ module.exports = function(grunt) { 'webdriver-perf:saucelabs_firefox', 'webdriver-perf:saucelabs_chrome', 'webdriver-perf:saucelabs_ie11', - 'webdriver-perf:saucelabs_ie8', + 'webdriver-perf:saucelabs_ie8' ]); grunt.registerTask('test:webdriver:saucelabs', [ diff --git a/README.md b/README.md index 7c9cb8c5c87d3..68995dbaa660d 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ grunt test grunt test --debug # For speed, you can use fasttest and add --filter to only run one test grunt fasttest --filter=ReactIdentity -# Lint the code with JSHint +# Lint the code with ESLint grunt lint # Wipe out build directory grunt clean diff --git a/grunt/config/browserify.js b/grunt/config/browserify.js index 1ee95af99ce21..57b49802e920b 100644 --- a/grunt/config/browserify.js +++ b/grunt/config/browserify.js @@ -1,5 +1,4 @@ -/* jshint multistr:true */ -/* jshint -W040 */ +/*eslint-disable no-multi-str */ 'use strict'; diff --git a/grunt/config/compare_size.js b/grunt/config/compare_size.js index fb59d94cdbc5e..e9df497d5220a 100644 --- a/grunt/config/compare_size.js +++ b/grunt/config/compare_size.js @@ -12,6 +12,6 @@ module.exports = { return gzip.zip(contents, {}).length; } }, - cache: ".grunt/sizecache.json" + cache: '.grunt/sizecache.json' } }; diff --git a/grunt/config/copy.js b/grunt/config/copy.js index 94d2bcabf2860..9ecdc0a79ec84 100644 --- a/grunt/config/copy.js +++ b/grunt/config/copy.js @@ -1,5 +1,5 @@ 'use strict'; - +/*eslint-disable camelcase*/ module.exports = { react_docs: { diff --git a/grunt/config/jsx.js b/grunt/config/jsx.js index f5b3bc699004c..6e0d3644a116f 100644 --- a/grunt/config/jsx.js +++ b/grunt/config/jsx.js @@ -4,15 +4,15 @@ var grunt = require('grunt'); var _ = require('lodash'); var rootIDs = [ - "React", - "ReactWithAddons" + 'React', + 'ReactWithAddons' ]; // TODO: stop packaging these libraries rootIDs = rootIDs.concat([ - "merge", - "mergeInto", - "copyProperties" + 'merge', + 'mergeInto', + 'copyProperties' ]); var normal = { @@ -23,23 +23,23 @@ var normal = { constants: {} }; }, - sourceDir: "src", - outputDir: "build/modules" + sourceDir: 'src', + outputDir: 'build/modules' }; var test = { rootIDs: rootIDs.concat([ - "test/all.js", - "**/__tests__/*.js" + 'test/all.js', + '**/__tests__/*.js' ]), getConfig: function() { return _.merge({}, normal.getConfig(), { mocking: true }); }, - sourceDir: "src", - outputDir: "build/modules" + sourceDir: 'src', + outputDir: 'build/modules' }; diff --git a/grunt/config/populist.js b/grunt/config/populist.js index b156260353cbf..d2f19e7d47130 100644 --- a/grunt/config/populist.js +++ b/grunt/config/populist.js @@ -2,12 +2,12 @@ module.exports = function(grunt) { var jasmine = { - rootDirectory: "build/jasmine", - // This syntax means to require and expose the "jasmine" module + rootDirectory: 'build/jasmine', + // This syntax means to require and expose the 'jasmine' module // (build/jasmine/jasmine.js) as global.jasmine, and to require the - // "all" module (build/jasmine/all.js) but not expose it globally. - args: ["jasmine:jasmine", "all:"], - outfile: "./build/jasmine.js" + // 'all' module (build/jasmine/all.js) but not expose it globally. + args: ['jasmine:jasmine', 'all:'], + outfile: './build/jasmine.js' }; var filterExpr = grunt.option('filter'); @@ -19,8 +19,8 @@ module.exports = function(grunt) { } var test = { - rootDirectory: "build/modules", - args: ["test/all:harness"], + rootDirectory: 'build/modules', + args: ['test/all:harness'], requires: [filterExpr], outfile: './build/react-test.js' }; diff --git a/grunt/config/server.js b/grunt/config/server.js index 241ac109e60cb..8fa66599e39c6 100644 --- a/grunt/config/server.js +++ b/grunt/config/server.js @@ -1,9 +1,12 @@ 'use strict'; -module.exports = function(grunt){ +var fs = require('fs'); +var path = require('path'); + +module.exports = function(grunt) { var coverageWriteStream; - grunt.task.registerTask('finalize-coverage-stream', function(){ + grunt.task.registerTask('finalize-coverage-stream', function() { if (!coverageWriteStream) { return; } @@ -14,13 +17,13 @@ module.exports = function(grunt){ }); function consoleLoggerMiddleware(req, res, next) { - if (!(req.method == 'POST' && req._parsedUrl.pathname.replace(/\//g,'') == 'console' && Array.isArray(req.body))) { + if (!(req.method === 'POST' && req._parsedUrl.pathname.replace(/\//g, '') === 'console' && Array.isArray(req.body))) { return next(); } res.write(''); res.end('Got it, thanks!'); - req.body.forEach(function(log){ + req.body.forEach(function(log) { if (log.message.indexOf('not ok ') === 0) { log.type = 'error'; } else if (log.message.indexOf('ok ') === 0) { @@ -31,20 +34,20 @@ module.exports = function(grunt){ log.type = 'coverage done'; } - if (log.type == 'error') { + if (log.type === 'error') { grunt.log.error(log.message); - } else if (log.type == 'ok') { + } else if (log.type === 'ok') { grunt.log.ok(log.message); - } else if (log.type == 'log') { + } else if (log.type === 'log') { grunt.log.writeln(log.message); - } else if (log.type == 'coverage') { + } else if (log.type === 'coverage') { if (!coverageWriteStream) { - coverageWriteStream = require('fs').createWriteStream(__dirname + '/../../coverage.log'); + coverageWriteStream = fs.createWriteStream(path.join(__dirname, '/../../coverage.log')); } coverageWriteStream.write(log.message + '\n'); - } else if (log.type == 'coverage done') { + } else if (log.type === 'coverage done') { grunt.task.run('finalize-coverage-stream'); - } else if (log.type == 'perf') { + } else if (log.type === 'perf') { grunt.event.emit('perf results', log.message); } else { grunt.verbose.writeln(log); @@ -53,7 +56,7 @@ module.exports = function(grunt){ } function testResultLoggerMiddleware(req, res, next) { - if (!(req.method == 'POST' && req._parsedUrl.pathname.indexOf('/reportTestResults') === 0)) { + if (!(req.method === 'POST' && req._parsedUrl.pathname.indexOf('/reportTestResults') === 0)) { return next(); } res.write(''); @@ -62,8 +65,8 @@ module.exports = function(grunt){ var logType = 'writeln'; var message = req.body; - if (req.body.type && req.body.message){ - if (req.body.type == 'error') { + if (req.body.type && req.body.message) { + if (req.body.type === 'error') { logType = 'error'; } else if (req.body.message.indexOf('ok') === 0) { logType = 'ok'; @@ -72,7 +75,7 @@ module.exports = function(grunt){ } message = req.body.message; } - if (typeof message != 'string') { + if (typeof message !== 'string') { message = JSON.stringify(message, null, 2); } grunt.log[logType]('[%s][%s]', req.headers['user-agent'], Date.now(), message); @@ -86,8 +89,12 @@ module.exports = function(grunt){ port: 9999, middleware: function(connect, options) { - connect.logger.token('user-agent', function(req, res) { return req.headers['user-agent']; }); - connect.logger.token('timestamp', function(req, res) { return Date.now(); }); + connect.logger.token('user-agent', function(req, res) { + return req.headers['user-agent']; + }); + connect.logger.token('timestamp', function(req, res) { + return Date.now(); + }); return [ connect.json(), diff --git a/grunt/config/webdriver-all.js b/grunt/config/webdriver-all.js index 084ec578702a1..a9cf189dad2e0 100644 --- a/grunt/config/webdriver-all.js +++ b/grunt/config/webdriver-all.js @@ -2,20 +2,20 @@ var grunt = require('grunt'); -module.exports = function(props){ - if (typeof props.url != 'string') { +module.exports = function(props) { + if (typeof props.url !== 'string') { throw TypeError('expected url string'); } - if ('isDoneTimeout' in props && typeof props.isDoneTimeout != 'number') { + if ('isDoneTimeout' in props && typeof props.isDoneTimeout !== 'number') { throw TypeError('expected isDoneTimeout to be a number'); } - if ('onStart' in props && typeof props.onStart != 'function') { + if ('onStart' in props && typeof props.onStart !== 'function') { throw TypeError('expected onStart to be a function'); } - if ('onComplete' in props && typeof props.onComplete != 'function') { + if ('onComplete' in props && typeof props.onComplete !== 'function') { throw TypeError('expected onComplete to be a function'); } - if ('onError' in props && typeof props.onError != 'function') { + if ('onError' in props && typeof props.onError !== 'function') { throw TypeError('expected onError to be a function'); } @@ -33,7 +33,7 @@ module.exports = function(props){ }; if (grunt.option('debug')) { - exports.local.url += (exports.local.url.indexOf('?') == -1 ? '?' : '&') + 'debug=' + grunt.option('debug'); + exports.local.url += (exports.local.url.indexOf('?') === -1 ? '?' : '&') + 'debug=' + grunt.option('debug'); } exports.saucelabs = { @@ -49,13 +49,13 @@ module.exports = function(props){ } }, desiredCapabilities: { - "build": process.env.TRAVIS_BUILD_NUMBER || 'dev' + Date.now(), - "tunnel-identifier": process.env.TRAVIS_JOB_NUMBER || 'my awesome tunnel', - "browserName": "chrome" + 'build': process.env.TRAVIS_BUILD_NUMBER || 'dev' + Date.now(), + 'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER || 'my awesome tunnel', + 'browserName': 'chrome' }, url: exports.local.url, - onStart: function(browser){ - grunt.log.writeln("Starting WebDriver Test. Watch results here: http://saucelabs.com/tests/" + browser.sessionID); + onStart: function(browser) { + grunt.log.writeln('Starting WebDriver Test. Watch results here: http://saucelabs.com/tests/' + browser.sessionID); if (props.onStart) { return props.onStart(browser); } @@ -65,6 +65,7 @@ module.exports = function(props){ isDoneTimeout: exports.local.isDoneTimeout }; + /*eslint-disable camelcase*/ /* https://saucelabs.com/platforms */ exports.saucelabs_ios = exports.saucelabs_ios7 = sauceItUp({ browserName: 'iphone', version: '7', platform:'OS X 10.9' }); @@ -94,10 +95,11 @@ module.exports = function(props){ exports.saucelabs_ie9 = sauceItUp({ browserName: 'internet explorer', version: 9 }); exports.saucelabs_ie10 = sauceItUp({ browserName: 'internet explorer', version: 10 }); exports.saucelabs_ie11 = sauceItUp({ browserName: 'internet explorer', version: 11, platform:'Windows 8.1' }); + /*eslint-enable camelcase*/ function sauceItUp(desiredCapabilities) { - desiredCapabilities["build"] = exports.saucelabs.desiredCapabilities["build"]; - desiredCapabilities["tunnel-identifier"] = exports.saucelabs.desiredCapabilities["tunnel-identifier"]; + desiredCapabilities.build = exports.saucelabs.desiredCapabilities.build; + desiredCapabilities['tunnel-identifier'] = exports.saucelabs.desiredCapabilities['tunnel-identifier']; return { webdriver: exports.saucelabs.webdriver, url: exports.saucelabs.url, @@ -105,7 +107,7 @@ module.exports = function(props){ onComplete: exports.saucelabs.onComplete, onError: exports.saucelabs.onError, isDoneTimeout: exports.saucelabs.isDoneTimeout, - desiredCapabilities: desiredCapabilities, + desiredCapabilities: desiredCapabilities }; } diff --git a/grunt/config/webdriver-jasmine.js b/grunt/config/webdriver-jasmine.js index 3990c6271a64a..b81c50dcb3bc4 100644 --- a/grunt/config/webdriver-jasmine.js +++ b/grunt/config/webdriver-jasmine.js @@ -3,13 +3,13 @@ var grunt = require('grunt'); module.exports = require('./webdriver-all')({ - url: "http://127.0.0.1:9999/test/index.html", - onComplete: function(passed){ - if (!passed){ - grunt.fatal("tests failed"); + url: 'http://127.0.0.1:9999/test/index.html', + onComplete: function(passed) { + if (!passed) { + grunt.fatal('tests failed'); } }, - onError: function(error){ + onError: function(error) { grunt.fatal(error); } }); diff --git a/grunt/config/webdriver-perf.js b/grunt/config/webdriver-perf.js index df8d61d4d9a71..476155bdcf4dd 100644 --- a/grunt/config/webdriver-perf.js +++ b/grunt/config/webdriver-perf.js @@ -1,8 +1,9 @@ 'use strict'; var grunt = require('grunt'); +var path = require('path'); -var tests = grunt.file.expand(__dirname + '/../../perf/tests/*'); +var tests = grunt.file.expand(path.join(__dirname, '/../../perf/tests/*')); var maxTime = 5; @@ -15,33 +16,39 @@ var params = [] .concat('headless=false') .concat('maxTime=' + maxTime) .concat(tests - .map(function(path){ return path.split(/tests./i).reverse()[0]; }) + .map(function(testPath) { + return testPath.split(/tests./i).reverse()[0]; + }) .map(encodeURIComponent) - .map(function(filename){ return 'test=' + filename; }) + .map(function(filename) { + return 'test=' + filename; + }) ) .concat(reactVersions .map(encodeURIComponent) - .map(function(version){ return 'react=' + version; } + .map(function(version) { + return 'react=' + version; + } ) ); module.exports = require('./webdriver-all')({ - url: "http://127.0.0.1:9999/perf/index.html?" + params.join('&'), + url: 'http://127.0.0.1:9999/perf/index.html?' + params.join('&'), isDoneTimeout: 15 * 60 * 1000, - onStart: function(){ - grunt.event.on('perf results', function(results){ + onStart: function() { + grunt.event.on('perf results', function(results) { console.log(results); }); }, - onComplete: function(completedTestKeys){ + onComplete: function(completedTestKeys) { grunt.verbose.writeln('onComplete ' + JSON.stringify(completedTestKeys)); }, - onError: function(error){ + onError: function(error) { grunt.fatal(error); } diff --git a/grunt/tasks/coverage-parse.js b/grunt/tasks/coverage-parse.js index 223bed34bc551..a370be1cc6280 100644 --- a/grunt/tasks/coverage-parse.js +++ b/grunt/tasks/coverage-parse.js @@ -1,47 +1,48 @@ -"use strict"; +'use strict'; var grunt = require('grunt'); +var path = require('path'); +var fs = require('fs'); -module.exports = function(){ - var ROOT = require('path').normalize(__dirname + '/../..'); +module.exports = function() { + var ROOT = path.join(__dirname, '/../..'); var done = this.async(); var uncoveredExpressionCount = 0; var uncoveredLineCount = 0; - require('fs').createReadStream(ROOT + '/coverage.log') - .pipe(require('coverify/parse')(function(error, results){ + fs.createReadStream(ROOT + '/coverage.log') + .pipe(require('coverify/parse')(function(error, results) { if (error) { grunt.fatal(error); } Object.keys(results) - .sort(function(a, b){ + .sort(function(a, b) { return results[a].length - results[b].length; }) .reverse() - .forEach(function(path){ - if (results[path].length === 0) { + .forEach(function(concretePath) { + if (results[concretePath].length === 0) { return; } - var relativePath = path.replace(ROOT, ''); - uncoveredExpressionCount += results[path].length; - grunt.log.error(results[path].length + ' expressions not covered ' + relativePath); + var relativePath = concretePath.replace(ROOT, ''); + uncoveredExpressionCount += results[concretePath].length; + grunt.log.error(results[concretePath].length + ' expressions not covered ' + relativePath); - results[path].forEach(function(c){ + results[concretePath].forEach(function(c) { uncoveredLineCount += c.code.split('\n').length; - console.log('txmt://open?url=' + encodeURIComponent('file://' + path) + '&line=' + (c.lineNum+1) + '&column=' + (c.column[0]+2)); + console.log('txmt://open?url=' + encodeURIComponent('file://' + concretePath) + '&line=' + (c.lineNum + 1) + '&column=' + (c.column[0] + 2)); }); console.log(''); - }) - ; + }); - Object.keys(results).sort().forEach(function(path){ - if (results[path].length > 0) { + Object.keys(results).sort().forEach(function(concretePath) { + if (results[concretePath].length > 0) { return; } - var relativePath = path.replace(ROOT, ''); + var relativePath = concretePath.replace(ROOT, ''); grunt.log.ok('100% coverage ' + relativePath); }); - + if (uncoveredExpressionCount > 0) { grunt.log.error(uncoveredExpressionCount + ' expressions not covered'); } diff --git a/grunt/tasks/download-previous-version.js b/grunt/tasks/download-previous-version.js index fbb2c22d7de15..7e115d80e8025 100644 --- a/grunt/tasks/download-previous-version.js +++ b/grunt/tasks/download-previous-version.js @@ -1,47 +1,47 @@ -"use strict"; +'use strict'; var grunt = require('grunt'); var http = require('http'); var fs = require('fs'); +var path = require('path'); + +function get(url, targetFilePath, completedSuccessfully) { + grunt.verbose.writeln('getting url \'' + url + '\''); + http.get(url, function(response) { + grunt.verbose.writeln('Received status code ' + response.statusCode + ' for \'' + url + '\''); + + if (response.statusCode !== 200) { + if (response.headers.location) { + get(response.headers.location, targetFilePath); + return; + } else { + grunt.fatal('Nothing else to do.'); + completedSuccessfully(false); + return; + } + } + grunt.verbose.writeln('Writing url to \'' + targetFilePath + '\''); + response.pipe(fs.createWriteStream(targetFilePath)) + .on('close', function() { + completedSuccessfully(true); + }); + }); +} module.exports = function() { var completedSuccessfully = this.async(); get( - "http://react.zpao.com/builds/master/latest/react.min.js", - __dirname + '/../../build/react-previous.min.js', - function(success){ + 'http://react.zpao.com/builds/master/latest/react.min.js', + path.join(__dirname, '/../../build/react-previous.min.js'), + function(success) { if (!success) { return completedSuccessfully(success); } get( - "http://react.zpao.com/builds/master/latest/JSXTransformer.js", - __dirname + '/../../build/JSXTransformer-previous.js', + 'http://react.zpao.com/builds/master/latest/JSXTransformer.js', + path.join(__dirname, '/../../build/JSXTransformer-previous.js'), completedSuccessfully ); } ); - - function get(url, targetFilePath, completedSuccessfully) { - grunt.verbose.writeln('getting url "' + url + '"'); - http.get(url, function(response) { - grunt.verbose.writeln('Received status code ' + response.statusCode + ' for "' + url + '"'); - - if (response.statusCode != 200) { - if (response.headers.location) { - get(response.headers.location, targetFilePath); - return; - } else { - grunt.fatal('Nothing else to do.'); - completedSuccessfully(false); - return; - } - } - grunt.verbose.writeln('Writing url to "' + targetFilePath + '"'); - response.pipe(fs.createWriteStream(targetFilePath)) - .on('close', function() { - completedSuccessfully(true); - }) - ; - }); - } }; diff --git a/grunt/tasks/eslint.js b/grunt/tasks/eslint.js new file mode 100644 index 0000000000000..84a275fed49d9 --- /dev/null +++ b/grunt/tasks/eslint.js @@ -0,0 +1,22 @@ +'use strict'; + +var grunt = require('grunt'); + +module.exports = function() { + var done = this.async(); + grunt.util.spawn({ + cmd: 'node_modules/.bin/eslint', + args: ['src/', 'Gruntfile.js', 'grunt/', 'main.js', 'perf/', 'test/'] + }, function(err, result, code) { + if (err) { + grunt.log.error('Lint failed'); + } else { + grunt.log.ok('Lint passed (but may contain warnings)'); + } + if (result.stdout.length) { + grunt.log.writeln(result.stdout); + } + + done(code === 0); + }); +}; diff --git a/grunt/tasks/gem-react-source.js b/grunt/tasks/gem-react-source.js index a42d5c6c54617..2c6e40d4e14f3 100644 --- a/grunt/tasks/gem-react-source.js +++ b/grunt/tasks/gem-react-source.js @@ -12,19 +12,21 @@ var buildFiles = [ ]; function buildRelease() { - grunt.file.exists(dest) && grunt.file.delete(dest); + if (grunt.file.exists(dest)) { + grunt.file.delete(dest); + } // Copy gem-react-source/**/* to build/gem-react-source var mappings = [].concat( grunt.file.expandMapping('**/*', dest, {cwd: src}) ); mappings.forEach(function(mapping) { - var src = mapping.src[0]; - var dest = mapping.dest; - if (grunt.file.isDir(src)) { - grunt.file.mkdir(dest); + var mappingSrc = mapping.src[0]; + var mappingDest = mapping.dest; + if (grunt.file.isDir(mappingSrc)) { + grunt.file.mkdir(mappingDest); } else { - grunt.file.copy(src, dest); + grunt.file.copy(mappingSrc, mappingDest); } }); @@ -36,7 +38,6 @@ function buildRelease() { } function packRelease() { - /*jshint validthis:true */ var done = this.async(); var spawnCmd = { cmd: 'gem', @@ -46,12 +47,15 @@ function packRelease() { } }; grunt.util.spawn(spawnCmd, function(err, result) { + if (err) { + grunt.log.error(err); + } // Gem packing does weird things to versions so 0.12.0-alpha becomes // 0.12.0.pre.alpha. We need to get the filename printed to stdout. var filename = result.stdout.match(/File: (.*)$/)[1]; - var src = 'build/gem-react-source/' + filename; - var dest = 'build/react-source.tgz'; - fs.rename(src, dest, done); + var buildSrc = 'build/gem-react-source/' + filename; + var buildDest = 'build/react-source.tgz'; + fs.rename(buildSrc, buildDest, done); }); } diff --git a/grunt/tasks/jsx.js b/grunt/tasks/jsx.js index 3acde383bd733..045081409c4f6 100644 --- a/grunt/tasks/jsx.js +++ b/grunt/tasks/jsx.js @@ -1,7 +1,7 @@ 'use strict'; -var path = require("path"); -var grunt = require("grunt"); +var path = require('path'); +var grunt = require('grunt'); var expand = grunt.file.expand; var spawn = grunt.util.spawn; @@ -10,27 +10,27 @@ module.exports = function() { var config = this.data; var args = [ - "--cache-dir", ".module-cache", - "--relativize", - "--follow-requires", - "--use-provides-module", + '--cache-dir', '.module-cache', + '--relativize', + '--follow-requires', + '--use-provides-module', config.sourceDir, config.outputDir ]; var rootIDs = expand({ nonull: true, // Keep IDs that don't expand to anything. - cwd: "src" + cwd: 'src' }, config.rootIDs).map(function(id) { - return id.replace(/\.js$/i, ""); + return id.replace(/\.js$/i, ''); }); args.push.apply(args, rootIDs); - args.push("--config" /* from stdin */); + args.push('--config' /* from stdin */); var child = spawn({ - cmd: "node", - args: [path.join("bin", "jsx-internal")].concat(args) + cmd: 'node', + args: [path.join('bin', 'jsx-internal')].concat(args) }, function(error, result, code) { if (error) { grunt.log.error(error); diff --git a/grunt/tasks/npm-react-tools.js b/grunt/tasks/npm-react-tools.js index 543c15a6ec5cb..8b4e73d163d64 100644 --- a/grunt/tasks/npm-react-tools.js +++ b/grunt/tasks/npm-react-tools.js @@ -7,7 +7,9 @@ var src = 'npm-react-tools'; var dest = 'build/npm-react-tools/'; function buildRelease() { - grunt.file.exists(dest) && grunt.file.delete(dest); + if (grunt.file.exists(dest)) { + grunt.file.delete(dest); + } // read our required files from package.json var pkgFiles = grunt.config.data.pkg.files; @@ -27,18 +29,17 @@ function buildRelease() { }); mappings.forEach(function(mapping) { - var src = mapping.src[0]; - var dest = mapping.dest; - if (grunt.file.isDir(src)) { - grunt.file.mkdir(dest); + var mappingSrc = mapping.src[0]; + var mappingDest = mapping.dest; + if (grunt.file.isDir(mappingSrc)) { + grunt.file.mkdir(mappingDest); } else { - grunt.file.copy(src, dest); + grunt.file.copy(mappingSrc, mappingDest); } }); } function packRelease() { - /*jshint validthis:true */ var done = this.async(); var spawnCmd = { cmd: 'npm', @@ -48,9 +49,9 @@ function packRelease() { } }; grunt.util.spawn(spawnCmd, function() { - var src = 'build/react-tools-' + grunt.config.data.pkg.version + '.tgz'; - var dest = 'build/react-tools.tgz'; - fs.rename(src, dest, done); + var buildSrc = 'build/react-tools-' + grunt.config.data.pkg.version + '.tgz'; + var buildDest = 'build/react-tools.tgz'; + fs.rename(buildSrc, buildDest, done); }); } diff --git a/grunt/tasks/npm-react.js b/grunt/tasks/npm-react.js index 94fb53ae07049..2743f0c041d48 100644 --- a/grunt/tasks/npm-react.js +++ b/grunt/tasks/npm-react.js @@ -15,7 +15,9 @@ var distFiles = [ function buildRelease() { // delete build/react-core for fresh start - grunt.file.exists(dest) && grunt.file.delete(dest); + if (grunt.file.exists(dest)) { + grunt.file.delete(dest); + } // mkdir -p build/react-core/lib grunt.file.mkdir(lib); @@ -27,12 +29,12 @@ function buildRelease() { grunt.file.expandMapping('**/*', lib, {cwd: modSrc}) ); mappings.forEach(function(mapping) { - var src = mapping.src[0]; - var dest = mapping.dest; - if (grunt.file.isDir(src)) { - grunt.file.mkdir(dest); + var mappingSrc = mapping.src[0]; + var mappingDest = mapping.dest; + if (grunt.file.isDir(mappingSrc)) { + grunt.file.mkdir(mappingDest); } else { - grunt.file.copy(src, dest); + grunt.file.copy(mappingSrc, mappingDest); } }); @@ -49,7 +51,6 @@ function buildRelease() { } function packRelease() { - /*jshint validthis:true */ var done = this.async(); var spawnCmd = { cmd: 'npm', @@ -59,9 +60,9 @@ function packRelease() { } }; grunt.util.spawn(spawnCmd, function() { - var src = 'build/react-' + grunt.config.data.pkg.version + '.tgz'; - var dest = 'build/react.tgz'; - fs.rename(src, dest, done); + var buildSrc = 'build/react-' + grunt.config.data.pkg.version + '.tgz'; + var buildDest = 'build/react.tgz'; + fs.rename(buildSrc, buildDest, done); }); } diff --git a/grunt/tasks/npm.js b/grunt/tasks/npm.js index 72d95e536bf6f..202631778e477 100644 --- a/grunt/tasks/npm.js +++ b/grunt/tasks/npm.js @@ -1,26 +1,26 @@ 'use strict'; -var assert = require("assert"); -var path = require("path"); -var grunt = require("grunt"); +var assert = require('assert'); +var path = require('path'); +var grunt = require('grunt'); var spawn = grunt.util.spawn; module.exports = function() { var done = this.async(); function run(cmd, args, opts, callback) { - assert.strictEqual(typeof cmd, "string"); + assert.strictEqual(typeof cmd, 'string'); assert.ok(args instanceof Array); - if (typeof opts === "function" && !callback) { + if (typeof opts === 'function' && !callback) { callback = opts; opts = {}; } - assert.strictEqual(typeof opts, "object"); - assert.strictEqual(typeof callback, "function"); + assert.strictEqual(typeof opts, 'object'); + assert.strictEqual(typeof callback, 'function'); - grunt.log.writeln("> " + cmd + " " + args.join(" ")); + grunt.log.writeln('> ' + cmd + ' ' + args.join(' ')); // var proc = spawn({ @@ -42,33 +42,33 @@ module.exports = function() { } var pkg = grunt.config.data.pkg; - var tgz = pkg.name + "-" + pkg.version + ".tgz"; + var tgz = pkg.name + '-' + pkg.version + '.tgz'; - grunt.log.writeln("Packing " + tgz + " (this could take a while)..."); + grunt.log.writeln('Packing ' + tgz + ' (this could take a while)...'); - run("npm", ["pack", "--verbose", "."], function() { - require("tmp").dir(function(err, dir) { + run('npm', ['pack', '--verbose', '.'], function() { + require('tmp').dir(function(err, dir) { if (err) { grunt.log.error(err); done(false); return; } - run("cp", [tgz, dir], function() { - run("npm", [ - "install", - "--production", + run('cp', [tgz, dir], function() { + run('npm', [ + 'install', + '--production', tgz ], { cwd: dir }, function() { - var nodePath = path.join(dir, "node_modules"); + var nodePath = path.join(dir, 'node_modules'); var pkgDir = path.join(nodePath, pkg.name); var doneCount = 2; // Make sure that bin/jsx is runnable by echoing main.js. - run("bin/jsx", ["main.js"], { + run('bin/jsx', ['main.js'], { cwd: pkgDir }, function(result) { - assert.ok(result.stdout.indexOf("transform") >= 0, result.stdout); + assert.ok(result.stdout.indexOf('transform') >= 0, result.stdout); if (--doneCount === 0) { done(); @@ -76,17 +76,17 @@ module.exports = function() { }); // Make sure the .transform package method works. - run("node", [ - "--print", - 'require("react-tools").transform(' + + run('node', [ + '--print', + 'require(\'react-tools\').transform(' + JSON.stringify( - "/** @jsx React.DOM */