From 1511fff5982cb3a0557a59b5840ac295de3402a5 Mon Sep 17 00:00:00 2001 From: chico Date: Thu, 12 Feb 2015 23:48:11 +0300 Subject: [PATCH] eslint --- .eslintignore | 1 + .eslintrc | 50 ++++++ .jshintrc | 18 -- Gruntfile.js | 93 +++++++---- README.md | 2 +- grunt/config/browserify.js | 3 +- grunt/config/compare_size.js | 2 +- grunt/config/copy.js | 2 +- grunt/config/jsx.js | 22 +-- grunt/config/populist.js | 14 +- grunt/config/server.js | 41 +++-- grunt/config/webdriver-all.js | 32 ++-- grunt/config/webdriver-jasmine.js | 10 +- grunt/config/webdriver-perf.js | 25 ++- grunt/tasks/coverage-parse.js | 39 ++--- grunt/tasks/download-previous-version.js | 60 +++---- grunt/tasks/eslint.js | 22 +++ grunt/tasks/gem-react-source.js | 24 +-- grunt/tasks/jsx.js | 22 +-- grunt/tasks/npm-react-tools.js | 21 +-- grunt/tasks/npm-react.js | 21 +-- grunt/tasks/npm.js | 48 +++--- grunt/tasks/populist.js | 7 +- grunt/tasks/release.js | 6 +- grunt/tasks/sauce-tunnel.js | 4 +- grunt/tasks/webdriver-all.js | 26 +-- grunt/tasks/webdriver-jasmine.js | 19 +-- grunt/tasks/webdriver-perf.js | 19 +-- grunt/tasks/webdriver-phantomjs.js | 12 +- main.js | 2 +- perf/.eslintrc | 21 +++ perf/lib/BrowserPerfRunnerApp.react.js | 106 ++++++------ perf/lib/BrowserPerfRunnerContext.react.js | 72 ++++---- perf/lib/perf-test-runner.browser.js | 182 ++++++++++++--------- perf/lib/todolist.browser.js | 90 ++++++---- perf/tests/basic-div.js | 13 +- perf/tests/basic-unmount.js | 24 ++- perf/tests/propTypes.js | 26 +-- perf/tests/renderComponent-basic.js | 26 ++- perf/tests/sanity.js | 10 +- perf/tests/setState-callback-5.js | 32 ++-- perf/tests/setState-callback.js | 24 +-- perf/tests/shouldComponentUpdate.js | 14 +- perf/tests/todolist-add.js | 20 ++- perf/tests/todolist-do-stuff.js | 34 ++-- perf/tests/todolist-edit.js | 22 +-- perf/tests/todolist-mount.js | 23 ++- test/.eslintrc | 8 + test/lib/jasmine-execute.js | 10 +- test/lib/postDataToURL.browser.js | 44 +++-- test/lib/reportTestResults.browser.js | 52 +++--- 51 files changed, 878 insertions(+), 642 deletions(-) create mode 100644 .eslintrc delete mode 100644 .jshintrc create mode 100644 grunt/tasks/eslint.js create mode 100644 perf/.eslintrc create mode 100644 test/.eslintrc 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 */
oyez
;" + '/** @jsx React.DOM */
oyez
;' ) + ')' ], { env: { NODE_PATH: nodePath } }, function(result, code) { assert.ok(result.stdout.indexOf( - 'React.DOM.div(null, "oyez");' + 'React.DOM.div(null, \'oyez\');' ) >= 0, result.stdout); if (--doneCount === 0) { diff --git a/grunt/tasks/populist.js b/grunt/tasks/populist.js index 7ea837d130c52..96c872b0494e9 100644 --- a/grunt/tasks/populist.js +++ b/grunt/tasks/populist.js @@ -2,12 +2,13 @@ var grunt = require('grunt'); var fs = require('fs'); +var path = require('path'); module.exports = function() { var config = this.data; var done = this.async(); - var theFilesToTestScript = fs.createWriteStream(__dirname + '/../../test/the-files-to-test.generated.js'); + var theFilesToTestScript = fs.createWriteStream(path.join(__dirname, '/../../test/the-files-to-test.generated.js')); theFilesToTestScript.write('// Generated by '); theFilesToTestScript.write(JSON.stringify(__filename.split(/(?=grunt)/)[1])); theFilesToTestScript.write(' at '); @@ -23,12 +24,12 @@ module.exports = function() { nonull: true, // Keep IDs that don't expand to anything. cwd: config.rootDirectory }, requires).forEach(function(name) { - name = name.replace(/\.js$/i, ""); + name = name.replace(/\.js$/i, ''); args.push(name); theFilesToTestScript.write('harness.enableTest(' + JSON.stringify(name) + ');\n'); }); - require("populist").buildP({ + require('populist').buildP({ rootDirectory: config.rootDirectory, args: args }).then(function(output) { diff --git a/grunt/tasks/release.js b/grunt/tasks/release.js index 3b23f793c97eb..aeb725415b1a6 100644 --- a/grunt/tasks/release.js +++ b/grunt/tasks/release.js @@ -1,6 +1,3 @@ -// function calls get bound so "possible strict mode violations" aren't -// jshint -W040 - 'use strict'; var grunt = require('grunt'); @@ -59,8 +56,7 @@ function _gitCommitAndTag(cwd, commitMsg, tag, cb) { grunt.util.spawn(gitCommit, function() { if (tag) { grunt.util.spawn(gitTag, cb); - } - else { + } else { cb(); } }); diff --git a/grunt/tasks/sauce-tunnel.js b/grunt/tasks/sauce-tunnel.js index d785f1f2387e5..68a1232893b60 100644 --- a/grunt/tasks/sauce-tunnel.js +++ b/grunt/tasks/sauce-tunnel.js @@ -22,7 +22,7 @@ module.exports = function() { var taskCompletedSuccessfully = task.async(); var stunnel = new SauceTunnel(SAUCE_USERNAME, SAUCE_ACCESS_KEY, IDENTIFIER, /*tunneled*/true, /*tunnelTimeout*/5); - process.on('exit', stunnel.stop.bind(stunnel, function(){})); + process.on('exit', stunnel.stop.bind(stunnel, function() {})); stunnel.on('log:error', grunt.log.error.bind(grunt.log)); stunnel.on('log:writeln', grunt.log.writeln.bind(grunt.log)); @@ -32,7 +32,7 @@ module.exports = function() { stunnel.on('verbose:debug', grunt.verbose.debug.bind(grunt.verbose)); stunnel.on('verbose:writeln', grunt.verbose.writeln.bind(grunt.verbose)); - stunnel.openTunnel(function(isOpen){ + stunnel.openTunnel(function(isOpen) { if (shouldStayAliveForever && isOpen) { grunt.verbose.writeln('Keeping the sauce-tunnel open forever because you used the keepalive flag `' + task.nameArgs + '`'); return; diff --git a/grunt/tasks/webdriver-all.js b/grunt/tasks/webdriver-all.js index 4571f697c958a..3e3f792f84f43 100644 --- a/grunt/tasks/webdriver-all.js +++ b/grunt/tasks/webdriver-all.js @@ -1,11 +1,10 @@ -/* jshint evil: true */ - +/*eslint-disable consistent-return*/ 'use strict'; -var grunt = require("grunt"); +var grunt = require('grunt'); var wd = require('wd'); -module.exports = function task(getJSReport){ +module.exports = function task(getJSReport) { var config = this.data; var taskSucceeded = this.async(); getJSReport = getJSReport.bind(this, config, wd); @@ -19,7 +18,7 @@ module.exports = function task(getJSReport){ desiredCapabilities[key] = config.desiredCapabilities[key]; }); } - grunt.verbose.writeln("desiredCapabilities", JSON.stringify(desiredCapabilities)); + grunt.verbose.writeln('desiredCapabilities', JSON.stringify(desiredCapabilities)); var browser = wd.promiseChainRemote(config.webdriver.remote); @@ -38,18 +37,23 @@ module.exports = function task(getJSReport){ .init(desiredCapabilities) .then(config.onStart && config.onStart.bind(config, browser)) .get(config.url) - .then(function(){return browser;}) + .then(function() { + return browser; + }) .then(getJSReport) - .then(function(data){ results = data; }) - .fail(function(error){ + .then(function(data) { + results = data; + }) + .fail(function(error) { grunt.log.error(error); return browser .eval('document.documentElement.innerText || document.documentElement.textContent') .then(grunt.verbose.writeln.bind(grunt.verbose)) - .then(function(){ throw error; }) - ; + .then(function() { + throw error; + }); }) - .finally(function(){ + .finally(function() { if (grunt.option('webdriver-keep-open')) { return; } diff --git a/grunt/tasks/webdriver-jasmine.js b/grunt/tasks/webdriver-jasmine.js index 613627dc927d5..87e3c0137b6db 100644 --- a/grunt/tasks/webdriver-jasmine.js +++ b/grunt/tasks/webdriver-jasmine.js @@ -1,17 +1,14 @@ -/* jshint evil: true */ - 'use strict'; -module.exports = function(){ - return require('./webdriver-all').call(this, function(config, wd, browser){ +module.exports = function() { + return require('./webdriver-all').call(this, function(config, wd, browser) { return browser - .waitFor(wd.asserters.jsCondition("typeof window.jasmine != 'undefined'"), 5e3, 50) - .fail(function(error){ - throw Error("The test page didn't load properly. " + error); + .waitFor(wd.asserters.jsCondition('typeof window.jasmine != \'undefined\''), 5e3, 50) + .fail(function(error) { + throw Error('The test page didn\'t load properly. ' + error); }) - .waitFor(wd.asserters.jsCondition("typeof window.jasmine.getJSReport != 'undefined'"), 60e3, 100) - .waitFor(wd.asserters.jsCondition("window.postDataToURL.running <= 0"), 30e3, 500) - .eval("jasmine.getJSReport().passed") - ; + .waitFor(wd.asserters.jsCondition('typeof window.jasmine.getJSReport != \'undefined\''), 60e3, 100) + .waitFor(wd.asserters.jsCondition('window.postDataToURL.running <= 0'), 30e3, 500) + .eval('jasmine.getJSReport().passed'); }); }; diff --git a/grunt/tasks/webdriver-perf.js b/grunt/tasks/webdriver-perf.js index 27143cf6a570e..240a13b54d52b 100644 --- a/grunt/tasks/webdriver-perf.js +++ b/grunt/tasks/webdriver-perf.js @@ -1,23 +1,20 @@ -/* jshint evil: true */ - 'use strict'; var grunt = require('grunt'); -module.exports = function(){ - return require('./webdriver-all').call(this, function(config, wd, browser){ +module.exports = function() { + return require('./webdriver-all').call(this, function(config, wd, browser) { if (!config.isDoneTimeout) { grunt.verbose.writeln('Expected isDoneTimeout config, using default value'); } grunt.verbose.writeln('isDoneTimeout:' + config.isDoneTimeout); return browser - .waitFor(wd.asserters.jsCondition("window.isDone === false"), 5e3, 50) - .fail(function(error){ - throw Error("The test page didn't load properly. " + error); + .waitFor(wd.asserters.jsCondition('window.isDone === false'), 5e3, 50) + .fail(function(error) { + throw Error('The test page didn\'t load properly. ' + error); }) - .waitFor(wd.asserters.jsCondition("window.isDone === true"), config.isDoneTimeout || 30e3, 1e3) - .waitFor(wd.asserters.jsCondition("window.postDataToURL.running <= 0"), 30e3, 500) - .eval("window.completedTestKeys || window._unhandledError") - ; + .waitFor(wd.asserters.jsCondition('window.isDone === true'), config.isDoneTimeout || 30e3, 1e3) + .waitFor(wd.asserters.jsCondition('window.postDataToURL.running <= 0'), 30e3, 500) + .eval('window.completedTestKeys || window._unhandledError'); }); }; diff --git a/grunt/tasks/webdriver-phantomjs.js b/grunt/tasks/webdriver-phantomjs.js index 4612e788ee0a8..eb270c8a25be1 100644 --- a/grunt/tasks/webdriver-phantomjs.js +++ b/grunt/tasks/webdriver-phantomjs.js @@ -2,17 +2,17 @@ var grunt = require('grunt'); -module.exports = function(){ +module.exports = function() { var onReadyCallback = this.async(); - var phantomjs = require("phantomjs").path; - var child_process = require('child_process'); + var phantomjs = require('phantomjs').path; + var childProcess = require('child_process'); var config = this.data || {}; - var args = ["--webdriver=" + (config.port || 9515)]; + var args = ['--webdriver=' + (config.port || 9515)]; grunt.verbose.writeln('phantomjs START path:%s args:%s', phantomjs, args); - var child = child_process.spawn(phantomjs, args); + var child = childProcess.spawn(phantomjs, args); process.on('exit', function() { child.kill(); }); @@ -29,7 +29,7 @@ module.exports = function(){ }); function verboseWrite(chunk) { - if (onReadyCallback && chunk.toString().indexOf('running on port') != -1) { + if (onReadyCallback && chunk.toString().indexOf('running on port') !== -1) { grunt.verbose.writeln('phantomjs STARTED'); onReadyCallback(); onReadyCallback = null; diff --git a/main.js b/main.js index 7a977556d76af..8d07141039916 100644 --- a/main.js +++ b/main.js @@ -1,5 +1,5 @@ 'use strict'; - +/*eslint-disable no-undef*/ var visitors = require('./vendor/fbtransform/visitors'); var transform = require('jstransform').transform; var typesSyntax = require('jstransform/visitors/type-syntax'); diff --git a/perf/.eslintrc b/perf/.eslintrc new file mode 100644 index 0000000000000..ba63cd1d144dd --- /dev/null +++ b/perf/.eslintrc @@ -0,0 +1,21 @@ +globals: + document: true + window: true + Benchmark: true + React: true + _rootNode: true + todolist: true + _app: true + _todo1: true + _todo2: true + _todo3: true + _timesToRun: true + setState: true + +rules: + strict: false + no-undef: false + no-unused-vars: false + block-scoped-var: false + consistent-return: false + no-shadow: false diff --git a/perf/lib/BrowserPerfRunnerApp.react.js b/perf/lib/BrowserPerfRunnerApp.react.js index 5b34f3bcaaec5..a614b722a4283 100644 --- a/perf/lib/BrowserPerfRunnerApp.react.js +++ b/perf/lib/BrowserPerfRunnerApp.react.js @@ -10,56 +10,59 @@ var BrowserPerfRunnerApp = React.createClass({ headless: React.PropTypes.bool }, - getInitialState: function(){ + getInitialState: function() { var queue = []; - this.props.tests.forEach(function(testName){ - this.props.react.forEach(function(version){ + this.props.tests.forEach(function(testName) { + this.props.react.forEach(function(version) { queue.push({ test: testName, react: version }); - },this); - },this); + }, this); + }, this); return { queue: queue, results: {} }; }, - handleResults: function(results){ + handleResults: function(results) { this.state.results[results.test + '@' + results.react] = results; this.replaceState(this.state); }, - handleComplete: function(queueItem){ + handleComplete: function(queueItem) { queueItem.completed = true; - + if (!this.props.onCompleteEach) { return; } // Can't get the resultsForAllVersions if there are still some queued var incompleteCount = 0; - for (var index = this.state.queue.length; --index >= 0;){ + for (var index = this.state.queue.length; --index >= 0;) { if (this.state.queue[index].completed) { continue; } if (this.state.queue[index].test === queueItem.test) { return; } - incompleteCount ++; + incompleteCount++; } var resultsForAllVersions = Object.keys(this.state.results) - .filter(function(key){return key.indexOf(queueItem.test) === 0;}) - .map(function(key){return this.state.results[key];}, this) - ; + .filter(function(key) { + return key.indexOf(queueItem.test) === 0; + }) + .map(function(key) { + return this.state.results[key]; + }, this); this.props.onCompleteEach(resultsForAllVersions); - + if (this.props.onComplete && incompleteCount === 0) { this.props.onComplete(this.state.results); } }, - render: function(){ + render: function() { var grid = null; if (!this.props.headless) { @@ -84,31 +87,38 @@ var BrowserPerfRunnerApp = React.createClass({ } }); -BrowserPerfRunnerApp.renderBenchmarkCell = function(props, row, col){ - if (col == null && row == null) return React.DOM.th(null); - if (row == null) return React.DOM.th({style:{verticalAlign:'top', textAlign:'center'}}, col); +BrowserPerfRunnerApp.renderBenchmarkCell = function(props, row, col) { + if (col == null && row == null) { + return React.DOM.th(null); + } + if (row == null) { + return React.DOM.th({style:{verticalAlign:'top', textAlign:'center'}}, col); + } var benchmarks = Object.keys(props.value) - .filter(function(key){ + .filter(function(key) { return key.indexOf(row) === 0; }) - .map(function(key){ + .map(function(key) { return props.value[key]; }) - .filter(function(benchmark){ + .filter(function(benchmark) { return benchmark && !benchmark.isRunning && benchmark.stats; - }) - ; - - if (col == null) return React.DOM.th({style:{verticalAlign:'top', textAlign:'right'}}, - React.DOM.a({href:'?test=' + row}, benchmarks[0] && benchmarks[0].name || row) - ); + }); + + if (col == null) { + return React.DOM.th({style:{verticalAlign:'top', textAlign:'right'}}, + React.DOM.a({href:'?test=' + row}, benchmarks[0] && benchmarks[0].name || row) + ); + } var key = row + '@' + col; var benchmark = props.value[key]; - if (!(benchmark && benchmark.stats)) return React.DOM.td({key:key}); - - + if (!(benchmark && benchmark.stats)) { + return React.DOM.td({key:key}); + } + + var colors = [ '000000', 'AA0000', @@ -129,21 +139,25 @@ BrowserPerfRunnerApp.renderBenchmarkCell = function(props, row, col){ 'FFFFFF' ]; - function chartValue(value){ + function chartValue(value) { return Math.round(valueFromRangeToRange(value, chartValue.min, chartValue.max, 0, 100)); } - chartValue.min = Math.min.apply(Math, benchmarks.map(function(benchmark){return Math.min.apply(Math, benchmark.stats.sample);})); - chartValue.max = Math.max.apply(Math, benchmarks.map(function(benchmark){return Math.max.apply(Math, benchmark.stats.sample);})); - - var means = benchmarks.map(function(benchmark){ + chartValue.min = Math.min.apply(Math, benchmarks.map(function(benchmark) { + return Math.min.apply(Math, benchmark.stats.sample); + })); + chartValue.max = Math.max.apply(Math, benchmarks.map(function(benchmark) { + return Math.max.apply(Math, benchmark.stats.sample); + })); + + var means = benchmarks.map(function(benchmark) { return benchmark.stats.mean; }); - benchmarks.forEach(function(benchmark){ + benchmarks.forEach(function(benchmark) { benchmark.isTheWinner = benchmark.stats.mean <= Math.min.apply(Math, means); }); - var chartValues = benchmarks.map(function(benchmark){ - // benchmark.stats.sample.sort(function(a,b){return b - a;}); + var chartValues = benchmarks.map(function(benchmark) { + // benchmark.stats.sample.sort(function(a,b) {return b - a;}); return benchmark.stats.sample.map(chartValue).join(','); }).join('|'); @@ -151,9 +165,9 @@ BrowserPerfRunnerApp.renderBenchmarkCell = function(props, row, col){ React.DOM.td({key:key, style:{textAlign:'center', width:234, verticalAlign:'top'}}, benchmark.error && benchmark.error.message || '', React.DOM.div({style: benchmark.isTheWinner ? { backgroundColor:'#0A5', color:'#AFA' } : {backgroundColor:'transparent', color:'inherit'}}, - Math.round(1 / benchmark.stats.mean * 100) / 100, " op/s ", - React.DOM.strong(null, Math.round(benchmark.stats.mean * 1000 * 100) / 100, " ms/op "), - React.DOM.small(null, "(±" + (Math.round(benchmark.stats.rme * 10) / 10) + "%)") + Math.round(1 / benchmark.stats.mean * 100) / 100, ' op/s ', + React.DOM.strong(null, Math.round(benchmark.stats.mean * 1000 * 100) / 100, ' ms/op '), + React.DOM.small(null, '(±' + (Math.round(benchmark.stats.rme * 10) / 10) + '%)') ), benchmark.isRunning && 'Running' || React.DOM.img({ style: { @@ -167,9 +181,9 @@ BrowserPerfRunnerApp.renderBenchmarkCell = function(props, row, col){ }) ) ); -} +}; -function valueFromRangeToRange(value, fromMin, fromMax, toMin, toMax){ +function valueFromRangeToRange(value, fromMin, fromMax, toMin, toMax) { var fromRange = fromMax - fromMin; var toRange = toMax - toMin; return (((value - fromMin) * toRange) / fromRange) + toMin; @@ -183,11 +197,11 @@ var GridViewTable = React.createClass({ renderCell: React.PropTypes.func.isRequired }, - _renderCell: function(col){ + _renderCell: function(col) { return this.props.renderCell({ value:this.props.value }, this._row, col); }, - _renderRow: function(row){ + _renderRow: function(row) { this._row = row; return React.DOM.tr({key:row}, this._renderCell(null, 0), @@ -195,7 +209,7 @@ var GridViewTable = React.createClass({ ); }, - render: function(){ + render: function() { return React.DOM.table(null, this._renderRow(null, 0), this.props.rows.map(this._renderRow, this) diff --git a/perf/lib/BrowserPerfRunnerContext.react.js b/perf/lib/BrowserPerfRunnerContext.react.js index 4712ec4c45ee3..48e8df7d16883 100644 --- a/perf/lib/BrowserPerfRunnerContext.react.js +++ b/perf/lib/BrowserPerfRunnerContext.react.js @@ -8,25 +8,25 @@ var BenchmarkQueue = React.createClass({ onError: React.PropTypes.func }, - getDefaultProps: function(){ + getDefaultProps: function() { return { maxTime: 5 }; }, - getInitialState: function(){ + getInitialState: function() { return { queue: this.props.initialQueue.slice() }; }, - setItemState: function(state){ + setItemState: function(state) { state.test = this.state.queue[0].test; state.react = this.state.queue[0].react; this.props.onChange(state); }, - handleContextReady: function(window){ + handleContextReady: function(window) { var benchmark = window.Benchmark(window.exports); benchmark.options.maxTime = this.props.maxTime; //DEBUG @@ -37,7 +37,7 @@ var BenchmarkQueue = React.createClass({ platform: window.Benchmark.platform.description, reactVersion: window.React.version, - isMinified: (function(){ + isMinified: (function() { var code = window.React.render.toString(); return code.indexOf(',') - code.indexOf('(') <= 2; }()) @@ -46,7 +46,7 @@ var BenchmarkQueue = React.createClass({ this.setItemState(itemState); var self = this; - benchmark.on('start error cycle complete', function(){ + benchmark.on('start error cycle complete', function() { var stats = JSON.parse(JSON.stringify(benchmark.stats)); itemState.stats = stats; itemState.isRunning = benchmark.running; @@ -56,7 +56,7 @@ var BenchmarkQueue = React.createClass({ if (this.props.onError) { benchmark.on('error', this.props.onError); } - benchmark.on('complete', function(){ + benchmark.on('complete', function() { var queue = self.state.queue.slice(); var queueItem = queue.shift(); if (self.props.onCompleteEach) { @@ -67,12 +67,12 @@ var BenchmarkQueue = React.createClass({ benchmark.run({async:true}); }, - shouldComponentUpdate: function(nextProps, nextState){ + shouldComponentUpdate: function(nextProps, nextState) { return nextState.queue.length < this.state.queue.length; }, - render: function(){ - if (!(this.state.queue && this.state.queue.length > 0)){ + render: function() { + if (!(this.state.queue && this.state.queue.length > 0)) { return React.DOM.div({style:{display:'none'}}); } return BrowserPerfRunnerContext({ @@ -88,61 +88,67 @@ var BrowserPerfRunnerContext = React.createClass({ propTypes: { debug: React.PropTypes.bool, - test: function(object, key){ + test: function(object, key) { React.PropTypes.string.isRequired(object, key); - if (/\.jsx?$/i.test(object[key])) return; + if (/\.jsx?$/i.test(object[key])) { + return; + } throw Error('Expected `' + key + '` to be a test file name with extension `.js` or `.jsx`'); }, - react: function(object, key){ + react: function(object, key) { React.PropTypes.string.isRequired(object, key); - if (/^(?:builds\/.+|edge|previous|(?:\d+\.){2}\d+)$/.test(object[key])) return; - throw Error('Expected `' + key + '` prop to be a valid react version string, build string or "edge" or "previous"'); + if (/^(?:builds\/.+|edge|previous|(?:\d+\.){2}\d+)$/.test(object[key])) { + return; + } + throw Error('Expected `' + key + '` prop to be a valid react version string, build string or \'edge\' or \'previous\''); }, onReady: React.PropTypes.func.isRequired }, - getInitialState: function(){ + getInitialState: function() { return { testRunnerURL:'about:blank' }; }, - // _handleFrameError: function(error){ + // _handleFrameError: function(error) { // console.error('BrowserPerfRunnerContext', error); // }, // - // _handleFrameLoad: function(event){ + // _handleFrameLoad: function(event) { // console.log('BrowserPerfRunnerContext', event); // }, // - _handleMessage: function(event){ - if (location.href.indexOf(event.origin) !== 0) + _handleMessage: function(event) { + if (location.href.indexOf(event.origin) !== 0) { return console.debug('BrowserPerfRunnerContext#_handleMessage ignored message from ' + event.origin); - if (event.source.location.href.indexOf(this.state.testRunnerURL) === -1) + } + if (event.source.location.href.indexOf(this.state.testRunnerURL) === -1) { return console.debug('BrowserPerfRunnerContext#_handleMessage ignored message from ' + event.source.location.href); - if (event.data !== 'Ready!') + } + if (event.data !== 'Ready!') { return console.debug('BrowserPerfRunnerContext#_handleMessage ignored message ' + JSON.stringify(event.data)); - + } this.props.onReady(event.source); }, - _getTestRunnerURL: function(props){ + _getTestRunnerURL: function(props) { return 'runner.html' + '?' + 'debug=' + (props.debug ? 1 : 0) + '&' + 'react=' + encodeURIComponent(props.react) + '&' + - 'test=' + encodeURIComponent(props.test) + 'test=' + encodeURIComponent(props.test); }, - _renderState: function(props){ + _renderState: function(props) { return { testRunnerURL: this._getTestRunnerURL(props) }; }, - componentDidMount: function(){ + componentDidMount: function() { var node = this.refs.iframe.getDOMNode(); // node.onload = this._handleFrameLoad; // node.onerror = this._handleFrameError; @@ -156,7 +162,7 @@ var BrowserPerfRunnerContext = React.createClass({ this.setState(this._renderState(this.props)); }, - componentWillUnmount: function(){ + componentWillUnmount: function() { if (window.removeEventListener) { window.removeEventListener('message', this._handleMessage); } else if (window.detachEvent) { @@ -167,19 +173,19 @@ var BrowserPerfRunnerContext = React.createClass({ this.refs.iframe.getDOMNode().src = ''; }, - componentWillReceiveProps: function(nextProps){ + componentWillReceiveProps: function(nextProps) { this.setState(this._renderState(nextProps)); }, - shouldComponentUpdate: function(nextProps, nextState){ - return nextState.testRunnerURL != this.state.testRunnerURL; + shouldComponentUpdate: function(nextProps, nextState) { + return nextState.testRunnerURL !== this.state.testRunnerURL; }, - render: function(){ + render: function() { return ( React.DOM.iframe({ ref: 'iframe', - name: "BrowserPerfRunnerContextFrame", + name: 'BrowserPerfRunnerContextFrame', style: this.style, src: this.state.testRunnerURL }) diff --git a/perf/lib/perf-test-runner.browser.js b/perf/lib/perf-test-runner.browser.js index 26e059f8c38c7..d2af7345fd191 100644 --- a/perf/lib/perf-test-runner.browser.js +++ b/perf/lib/perf-test-runner.browser.js @@ -1,38 +1,44 @@ -if (typeof console == 'undefined') console = { - log: function(){}, - warn: function(){}, - error: function(){}, - debug: function(){} -}; +if (typeof console === 'undefined') { + console = { + log: function() {}, + warn: function() {}, + error: function() {}, + debug: function() {} + }; +} var perfRunner; -if (typeof exports == 'object') { +if (typeof exports === 'object') { perfRunner = exports; } else { perfRunner = {}; } -perfRunner.assert = function(test, message){ - if (typeof test == 'function') test = test(); - if (test) return; +perfRunner.assert = function(test, message) { + if (typeof test === 'function') { + test = test(); + } + if (test) { + return; + } throw Error(message); -} +}; -perfRunner.WriteScript = function(props){ +perfRunner.WriteScript = function(props) { var type = ''; if (props.jsx) { - type = ' type="text/jsx"'; + type = ' type=\'text/jsx\''; } var src = props.src; if (!props.cache) { src += src.indexOf('?') === -1 ? '?_' : '&_'; src += perfRunner.WriteScript.cacheBust; } - document.write('<\/script>'); -} -perfRunner.WriteScript.cacheBust = (+new Date).toString(36); + document.write('<\/script>'); +}; +perfRunner.WriteScript.cacheBust = (+new Date()).toString(36); -perfRunner.WriteReactLibScript = function(params){ +perfRunner.WriteReactLibScript = function(params) { var src; var minSuffix; if (params.debug) { @@ -40,14 +46,16 @@ perfRunner.WriteReactLibScript = function(params){ } else { minSuffix = '.min'; } - - if (params.version && typeof params.version != 'string') throw TypeError("Expected 'version' to be a string"); - - if (params.version == 'edge' || !params.version) { + + if (params.version && typeof params.version !== 'string') { + throw TypeError('Expected \'version\' to be a string'); + } + + if (params.version === 'edge' || !params.version) { console.log('React edge (local)'); perfRunner.WriteScript({src:'../build/react' + minSuffix + '.js'}); perfRunner.WriteScript({src:'../build/JSXTransformer.js'}); - } else if (params.version == 'previous') { + } else if (params.version === 'previous') { console.log('React previous (local)'); perfRunner.WriteScript({cache:true, src:'../build/react-previous' + minSuffix + '.js'}); perfRunner.WriteScript({cache:true, src:'../build/JSXTransformer-previous.js'}); @@ -61,113 +69,123 @@ perfRunner.WriteReactLibScript = function(params){ } if (params.debug) { console.warn('Loading the unminified build of React, performance may suffer.'); - console.warn('Load "' + location.href.replace(/\bdebug=\w+&?|&\bdebug=\w+/ig, '') + '" for better perf.'); + console.warn('Load \'' + location.href.replace(/\bdebug=\w+&?|&\bdebug=\w+/ig, '') + '\' for better perf.'); } else { console.warn('Loading the minified build of React, debugging may be harder.'); - console.warn('Load "' + location.href.replace(/\bdebug=\w+&?|&\bdebug=\w+/ig, '') + '&debug=1' + '" for easier debugging.'); + console.warn('Load \'' + location.href.replace(/\bdebug=\w+&?|&\bdebug=\w+/ig, '') + '&debug=1' + '\' for easier debugging.'); } -} +}; -perfRunner.WriteTestScript = function(params){ +perfRunner.WriteTestScript = function(params) { if (Array.isArray(params.test)) { return params.test - .map(function(test){return {test:test};}) - .map(perfRunner.WriteTestScript) - ; + .map(function(test) { + return { + test:test + }; + }) + .map(perfRunner.WriteTestScript); } perfRunner.assert(params.test.indexOf('..') === -1, 'no relative paths allowed'); return perfRunner.WriteScript({jsx:true, src: './tests/' + params.test}); -} +}; -perfRunner.getQueryParamArray = function(key){ +perfRunner.getQueryParamArray = function(key) { var values; var queryString = location.search.substr(1); var _key = encodeURIComponent(key) + '='; - + if (queryString.indexOf(_key) > -1) { values = queryString .split(_key) .slice(1) - .map(function(part){return part.split('&')[0];}) + .map(function(part) { + return part.split('&')[0]; + }) .map(decodeURIComponent) - .map(function(string){ + .map(function(string) { try { return JSON.parse(string); - } catch(e){} + } catch(e) {} return string; - }) - ; + }); } - + perfRunner.assert(values && values.length && values[0], 'expected ' + key + ' query param'); return values; -} +}; -perfRunner.getQueryParamArrayOrDefault = function(key, defaultValue){ +perfRunner.getQueryParamArrayOrDefault = function(key, defaultValue) { try { return perfRunner.getQueryParamArray(key); } catch (e) {} return defaultValue; -} +}; -perfRunner.Polyfill = function(){ - if (typeof Function.prototype.bind != 'undefined') return; +perfRunner.Polyfill = function() { + if (typeof Function.prototype.bind !== 'undefined') { + return; + } perfRunner.WriteScript({src:'/node_modules/es5-shim/es5-shim.js', cache:true}); perfRunner.WriteScript({src:'/node_modules/es5-shim/es5-sham.js', cache:true}); -} +}; -perfRunner.BenchmarkResults = function(props){ - return perfRunner.roundNumberWithPrecision(props.stats.mean * 1000) + 'ms/op' -} +perfRunner.BenchmarkResults = function(props) { + return perfRunner.roundNumberWithPrecision(props.stats.mean * 1000) + 'ms/op'; +}; -perfRunner.roundNumberWithPrecision = function(number, precision){ - if (!precision) precision = 1000; +perfRunner.roundNumberWithPrecision = function(number, precision) { + if (!precision) { + precision = 1000; + } return Math.round(number * precision) / precision; -} +}; -perfRunner.quickBench = function(benchmarkOptions, onComplete, onBeforeStart){ +perfRunner.quickBench = function(benchmarkOptions, onComplete, onBeforeStart) { var bench = new Benchmark(benchmarkOptions); - if (onBeforeStart) onBeforeStart(null, bench); + if (onBeforeStart) { + onBeforeStart(null, bench); + } - bench.on('error', function(event){ + bench.on('error', function(event) { console.error(event.message); console.log(event.target.compiled.toString()); onComplete(Error(event.error)); }); - bench.on('start', function(){ + bench.on('start', function() { console.log('starting', bench.name); }); - bench.on('cycle', function(){ - var bench = this, - size = bench.stats.size; - - if (!bench.aborted) { - console.warn(bench.name + ' × ' + bench.count + - ' (' + bench.stats.sample.length + ' samples)' + - ' (' + Math.round(1 / bench.stats.mean) + ' ops/sec' + ')' + - ' (' + (bench.stats.mean * 1000) + ' ms/op' + ')' + - ' (±' + bench.stats.rme.toFixed(2) + '%)' + + bench.on('cycle', function() { + var benchmark = this, + size = benchmark.stats.size; + + if (!benchmark.aborted) { + console.warn(benchmark.name + ' × ' + benchmark.count + + ' (' + benchmark.stats.sample.length + ' samples)' + + ' (' + Math.round(1 / benchmark.stats.mean) + ' ops/sec' + ')' + + ' (' + (benchmark.stats.mean * 1000) + ' ms/op' + ')' + + ' (±' + benchmark.stats.rme.toFixed(2) + '%)' + ' with ' + React.version ); } }); - bench.on('complete', function(){ + bench.on('complete', function() { var results = { platform: Benchmark.platform.description, react: React.version, - name: bench.name, + name: bench.name // times: bench.times, // stats: bench.stats }; - - results['s/op'] = bench.stats.mean - results['ms/op'] = results['s/op'] * 1000 - results['op/s'] = 1 / results['s/op'] - results["% frame 60"] = results['ms/op'] / (1000 / 60) * 100 - + + results['s/op'] = bench.stats.mean; + results['ms/op'] = results['s/op'] * 1000; + results['op/s'] = 1 / results['s/op']; + results['% frame 60'] = results['ms/op'] / (1000 / 60) * 100; + console.log(results); onComplete(null, results); }); @@ -175,9 +193,9 @@ perfRunner.quickBench = function(benchmarkOptions, onComplete, onBeforeStart){ bench.run(); }; -perfRunner.singleTest = function(benchmarkOptions, onComplete){ +perfRunner.singleTest = function(benchmarkOptions, onComplete) { var bench = Benchmark(exports); - bench.on('complete', function(){ + bench.on('complete', function() { var results = { platform: Benchmark.platform.description, react: React.version, @@ -187,18 +205,20 @@ perfRunner.singleTest = function(benchmarkOptions, onComplete){ onComplete(results); }); bench.run(); -} +}; -perfRunner.ViewObject = function(props){ +perfRunner.ViewObject = function(props) { var value = props.value; delete props.value; - - if (typeof value != 'object') return React.DOM.span(props, [JSON.stringify(value), " ", typeof value]); - - return React.DOM.table(props, Object.keys(value).map(function(key){ + + if (typeof value !== 'object') { + return React.DOM.span(props, [JSON.stringify(value), ' ', typeof value]); + } + + return React.DOM.table(props, Object.keys(value).map(function(key) { return React.DOM.tr(null, React.DOM.th(null, key), React.DOM.td(null, perfRunner.ViewObject({key:key, value:value[key]})) ); })); -} +}; diff --git a/perf/lib/todolist.browser.js b/perf/lib/todolist.browser.js index bf8c0bcdcbc8c..dd7d86a9dafdc 100644 --- a/perf/lib/todolist.browser.js +++ b/perf/lib/todolist.browser.js @@ -1,4 +1,4 @@ -/*global*/todolist = {}; +todolist = {}; todolist.ID = Date.now(); @@ -9,11 +9,15 @@ todolist.App = React.createClass({ fakeDataCount: React.PropTypes.number }, - getInitialState: function(){ + getInitialState: function() { var todos; if (this.props.fakeDataCount) { - todos = Array(this.props.fakeDataCount + 1).join(',').split(',').map(function(ignore, index){ - return {id:index, title:"Title " + index + " " + Math.random().toString(36).substring(2,16), completed:!!(index % 2)}; + todos = Array(this.props.fakeDataCount + 1).join(',').split(',').map(function(ignore, index) { + return { + id: index, + title: 'Title ' + index + ' ' + Math.random().toString(36).substring(2, 16), + completed: !!(index % 2) + }; }); } return { @@ -23,15 +27,17 @@ todolist.App = React.createClass({ todos: todos || this.props.initialData || [] }; }, - componentWillUpdate: function(props, state){ - state.todos = state.todos.filter(function(todo){ + componentWillUpdate: function(props, state) { + state.todos = state.todos.filter(function(todo) { return !todo.deleted; }); }, - addItem: function(title, callback){ + addItem: function(title, callback) { if (title == null || title === '') { var error = Error('invalid title'); - if (!callback) throw error; + if (!callback) { + throw error; + } return callback(error); } var todos = this.state.todos.slice(); @@ -41,82 +47,98 @@ todolist.App = React.createClass({ completed: false }; todos.push(todo); - if (callback) callback = callback.bind(this, todo); + if (callback) { + callback = callback.bind(this, todo); + } this.setState({ timerEvent:'addItem', timerStart:todolist.now(), timerEnd:null, todos:todos }, callback); return todo; }, - deleteItemById: function(id, callback){ + deleteItemById: function(id, callback) { var todo = this._getById(id); - if (!todo) return callback && callback(Error('todo with id ' + id + ' not found')); + if (!todo) { + return callback && callback(Error('todo with id ' + id + ' not found')); + } todo.deleted = true; this.setState({ timerEvent:'deleteItemById', timerStart:todolist.now(), timerEnd:null, todos:this.state.todos }, callback); }, - setItemCompleted: function(id, completed, callback){ + setItemCompleted: function(id, completed, callback) { var todo = this._getById(id); - if (!todo) return callback && callback(Error('todo with id ' + id + ' not found')); + if (!todo) { + return callback && callback(Error('todo with id ' + id + ' not found')); + } todo.completed = completed; this.setState({ timerEvent:'setItemCompleted', timerStart:todolist.now(), timerEnd:null, todos:this.state.todos }, callback); }, - _getById: function(id){ + _getById: function(id) { id = +id; var todos = this.state.todos; - for (var index = todos.length; --index >= 0;){ - if (todos[index].id === id) return todos[index]; + for (var index = todos.length; --index >= 0;) { + if (todos[index].id === id) { + return todos[index]; + } } return null; }, - _handleItemCompletedCheckboxChange: function(event){ + _handleItemCompletedCheckboxChange: function(event) { var node = event.target; this.setItemCompleted(node.value, node.checked); }, - _handleItemDeletedButton: function(event){ + _handleItemDeletedButton: function(event) { var node = event.target; this.deleteItemById(node.value); }, - _renderTodoItem: function(todo, index){ + _renderTodoItem: function(todo, index) { return ( React.DOM.li({key:todo.id}, React.DOM.button({value:todo.id, onClick:this._handleItemDeletedButton}, 'x'), - React.DOM.input({type:"checkbox", value:todo.id, checked:todo.completed, onChange:this._handleItemCompletedCheckboxChange}), - " ", - React.DOM.span({style:{"text-decoration":todo.completed ? "line-through" : ""}}, todo.title) + React.DOM.input({type:'checkbox', value:todo.id, checked:todo.completed, onChange:this._handleItemCompletedCheckboxChange}), + ' ', + React.DOM.span({style:{'text-decoration':todo.completed ? 'line-through' : ''}}, todo.title) ) ); }, - render: function(){ - if (!this.state.timerEnd) this.state.timerEnd = todolist.now(); - if (this.props.onRender) this.props.onRender(); + render: function() { + if (!this.state.timerEnd) { + this.state.timerEnd = todolist.now(); + } + if (this.props.onRender) { + this.props.onRender(); + } return ( React.DOM.div(null, - React.DOM.h1(null, "TODO"), - React.DOM.h3(null, this.state.timerEvent, " ", this.state.timerEnd - this.state.timerStart, 'ms'), + React.DOM.h1(null, 'TODO'), + React.DOM.h3(null, this.state.timerEvent, ' ', this.state.timerEnd - this.state.timerStart, 'ms'), todolist.NewItemForm({onEnter:this.addItem, autoFocus:true}), React.DOM.ol(null, this.state.todos.map(this._renderTodoItem)) ) ); }, - componentDidMount: function(rootNode){ - if (this.props.onDidMount) this.props.onDidMount(rootNode); + componentDidMount: function(rootNode) { + if (this.props.onDidMount) { + this.props.onDidMount(rootNode); + } } }); todolist.NewItemForm = React.createClass({ - _handleNewItemKeyDown: function(event){ - if (event.which !== 13/*enter key*/) return; + _handleNewItemKeyDown: function(event) { + if (event.which !== 13/*enter key*/) { + return; + } var node = this.refs.text.getDOMNode(); var value = node.value; node.value = ''; this.props.onEnter(value); return false; }, - render: function(){ + render: function() { var props = {}; for (var key in this.props) { - if (key !== "onEnter") { + if (key !== 'onEnter') { props[key] = this.props[key]; } } - props.ref = "text"; + props.ref = 'text'; props.onKeyDown = this.props.onEnter && this._handleNewItemKeyDown; return React.DOM.input(props); } diff --git a/perf/tests/basic-div.js b/perf/tests/basic-div.js index b72d6ded6d490..1fe81d722bc99 100644 --- a/perf/tests/basic-div.js +++ b/perf/tests/basic-div.js @@ -1,16 +1,11 @@ -/* jshint undef: true, unused: true */ - -/* global document */ -/* global window */ -/* global Benchmark */ -/* global React */ - -if (typeof exports == 'undefined') exports = {}; +if (typeof exports === 'undefined') { + exports = {}; +} /*http://benchmarkjs.com/docs#options*/ exports.name = 'React.DOM.div, no props'; -exports.fn = function(){ +exports.fn = function() { React.DOM.div(null, 'lol, perf testing ', this.count); }; diff --git a/perf/tests/basic-unmount.js b/perf/tests/basic-unmount.js index 996a2e8892ede..a0b36d3877aaf 100644 --- a/perf/tests/basic-unmount.js +++ b/perf/tests/basic-unmount.js @@ -1,23 +1,21 @@ -/* jshint undef: true, unused: true */ - -/* global document */ -/* global window */ -/* global Benchmark */ -/* global React */ - -if (typeof exports == 'undefined') exports = {}; +if (typeof exports === 'undefined') { + exports = {}; +} /*http://benchmarkjs.com/docs#options*/ exports.name = 'unmountComponentAtNode'; -exports.setup = function(){ - /*global*/_rootNode = document.createElement('div'); +exports.setup = function() { + _rootNode = document.createElement('div'); document.body.appendChild(_rootNode); var _firstChild = React.DOM.div(null, 'lol, perf testing ', this.count); React.render(_firstChild, _rootNode); }; -exports.fn = function(){ - if (React.unmountAndReleaseReactRootNode) React.unmountAndReleaseReactRootNode(_rootNode); - else React.unmountComponentAtNode(_rootNode); +exports.fn = function() { + if (React.unmountAndReleaseReactRootNode) { + React.unmountAndReleaseReactRootNode(_rootNode); + } else { + React.unmountComponentAtNode(_rootNode); + } }; diff --git a/perf/tests/propTypes.js b/perf/tests/propTypes.js index 92d32fd241edd..991abe6062826 100644 --- a/perf/tests/propTypes.js +++ b/perf/tests/propTypes.js @@ -1,4 +1,6 @@ -if (typeof exports == 'undefined') exports = {}; +if (typeof exports === 'undefined') { + exports = {}; +} /*http://benchmarkjs.com/docs#options*/ @@ -10,7 +12,11 @@ var ListItem; var MyReactComponent; var _rootNode; -exports.setup = function(){ +function func() { + return 'this is a function'; +} + +exports.setup = function() { List = React.createClass({ propTypes: { array: React.PropTypes.array, @@ -38,7 +44,7 @@ exports.setup = function(){ instanceOf: React.PropTypes.instanceOf(Thing).isRequired, element: React.PropTypes.element.isRequired }, - render: function(){ + render: function() { return React.DOM.li(null, this.props.number + this.props.string + this.props.node ); @@ -54,7 +60,7 @@ exports.setup = function(){ _rootNode = document.createElement('div'); document.body.appendChild(_rootNode); }; -exports.fn = function(){ +exports.fn = function() { var items = []; for (var i = 0; i < 1000; i++) { items.push(ListItem({ @@ -62,24 +68,24 @@ exports.fn = function(){ bool: false, number: Math.random(), string: 'banana banana banana', - func: function() { return 'this is a function'; }, + func: func, node: 'renderable string', node2: [MyReactComponent(), 'a string'], - instanceOf: new Thing, + instanceOf: new Thing(), element: MyReactComponent() })); - }; + } React.render(List({ array: [11, 12, 13, 14, 15, 16, 17, 18, 19, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], bool: false, number: Math.random(), string: 'banana banana banana', - func: function() { return 'this is a function'; }, + func: func, renderable: 'renderable string', - instanceOf: new Thing + instanceOf: new Thing() }, items), _rootNode); }; -exports.teardown = function(){ +exports.teardown = function() { React.unmountComponentAtNode(_rootNode); }; diff --git a/perf/tests/renderComponent-basic.js b/perf/tests/renderComponent-basic.js index 182e4c231ddc1..16349f10c096f 100644 --- a/perf/tests/renderComponent-basic.js +++ b/perf/tests/renderComponent-basic.js @@ -1,24 +1,22 @@ -/* jshint undef: true, unused: true */ - -/* global document */ -/* global window */ -/* global Benchmark */ -/* global React */ - -if (typeof exports == 'undefined') exports = {}; +if (typeof exports === 'undefined') { + exports = {}; +} /*http://benchmarkjs.com/docs#options*/ exports.name = 'React.render single div'; -exports.setup = function(){ - /*global*/_rootNode = document.createElement('div'); +exports.setup = function() { + _rootNode = document.createElement('div'); document.body.appendChild(_rootNode); }; -exports.fn = function(){ +exports.fn = function() { React.render(React.DOM.div(null, 'lol, perf testing ', this.count), _rootNode); }; -exports.teardown = function(){ - if (React.unmountAndReleaseReactRootNode) React.unmountAndReleaseReactRootNode(_rootNode); - else React.unmountComponentAtNode(_rootNode); +exports.teardown = function() { + if (React.unmountAndReleaseReactRootNode) { + React.unmountAndReleaseReactRootNode(_rootNode); + } else { + React.unmountComponentAtNode(_rootNode); + } }; diff --git a/perf/tests/sanity.js b/perf/tests/sanity.js index 0150114f16d94..a92364c62f544 100644 --- a/perf/tests/sanity.js +++ b/perf/tests/sanity.js @@ -1,15 +1,17 @@ -if (typeof exports == 'undefined') exports = {}; +if (typeof exports === 'undefined') { + exports = {}; +} /*http://benchmarkjs.com/docs#options*/ exports.name = 'Trivial benchmark to verify that everything works'; -exports.setup = function(){ +exports.setup = function() { var foo; }; -exports.fn = function(){ +exports.fn = function() { foo = Array(999).join('Howdy!\n'); }; -exports.teardown = function(){ +exports.teardown = function() { foo = null; }; diff --git a/perf/tests/setState-callback-5.js b/perf/tests/setState-callback-5.js index a4cebef9bc339..41670e0ce2661 100644 --- a/perf/tests/setState-callback-5.js +++ b/perf/tests/setState-callback-5.js @@ -1,4 +1,6 @@ -if (typeof exports == 'undefined') exports = {}; +if (typeof exports === 'undefined') { + exports = {}; +} /*http://benchmarkjs.com/docs#options*/ @@ -6,29 +8,31 @@ exports.name = 'From setState to callback (x5)'; exports.defer = true; -exports.setup = function(){ - /*global*/_rootNode = document.createElement('div'); +exports.setup = function() { + _rootNode = document.createElement('div'); document.body.appendChild(_rootNode); - /*global*/setState = null; + setState = null; var AwesomeComponent = React.createClass({ - getInitialState: function(){ + getInitialState: function() { return { random:null }; }, - render: function(){ - if (!setState) setState = this.setState.bind(this); + render: function() { + if (!setState) { + setState = this.setState.bind(this); + } return React.DOM.div(null, this.state.random); } }); React.render(AwesomeComponent(null), _rootNode); }; -exports.fn = function(deferred){ - setState({random: Date.now() + Math.random()}, function(){ - setState({random: Date.now() + Math.random()}, function(){ - setState({random: Date.now() + Math.random()}, function(){ - setState({random: Date.now() + Math.random()}, function(){ - setState({random: Date.now() + Math.random()}, function(){ +exports.fn = function(deferred) { + setState({random: Date.now() + Math.random()}, function() { + setState({random: Date.now() + Math.random()}, function() { + setState({random: Date.now() + Math.random()}, function() { + setState({random: Date.now() + Math.random()}, function() { + setState({random: Date.now() + Math.random()}, function() { deferred.resolve(); }); }); @@ -36,6 +40,6 @@ exports.fn = function(deferred){ }); }); }; -exports.teardown = function(){ +exports.teardown = function() { React.unmountComponentAtNode(_rootNode); }; diff --git a/perf/tests/setState-callback.js b/perf/tests/setState-callback.js index 4eeffac34fe7c..fac49a99736b6 100644 --- a/perf/tests/setState-callback.js +++ b/perf/tests/setState-callback.js @@ -1,4 +1,6 @@ -if (typeof exports == 'undefined') exports = {}; +if (typeof exports === 'undefined') { + exports = {}; +} /*http://benchmarkjs.com/docs#options*/ @@ -6,28 +8,30 @@ exports.name = 'From setState to callback'; exports.defer = true; -exports.setup = function(){ - /*global*/_rootNode = document.createElement('div'); +exports.setup = function() { + _rootNode = document.createElement('div'); document.body.appendChild(_rootNode); - /*global*/setState = null; + setState = null; var AwesomeComponent = React.createClass({ - getInitialState: function(){ + getInitialState: function() { return { random:null }; }, - render: function(){ - if (!setState) setState = this.setState.bind(this); + render: function() { + if (!setState) { + setState = this.setState.bind(this); + } return React.DOM.div(null, this.state.random); } }); React.render(AwesomeComponent(null), _rootNode); }; -exports.fn = function(deferred){ - setState({random: Date.now() + Math.random()}, function(){ +exports.fn = function(deferred) { + setState({random: Date.now() + Math.random()}, function() { deferred.resolve(); }); }; -exports.teardown = function(){ +exports.teardown = function() { React.unmountComponentAtNode(_rootNode); }; diff --git a/perf/tests/shouldComponentUpdate.js b/perf/tests/shouldComponentUpdate.js index b791c9aa38038..4c738f6eb8ffa 100644 --- a/perf/tests/shouldComponentUpdate.js +++ b/perf/tests/shouldComponentUpdate.js @@ -1,15 +1,17 @@ -if (typeof exports == 'undefined') exports = {}; +if (typeof exports === 'undefined') { + exports = {}; +} /*http://benchmarkjs.com/docs#options*/ exports.name = 'shouldComponentUpdate'; -exports.setup = function(){ +exports.setup = function() { var AwesomeComponent = React.createClass({ - shouldComponentUpdate: function(){ + shouldComponentUpdate: function() { return false; }, - render: function(){ + render: function() { return React.DOM.div({}); } }); @@ -17,9 +19,9 @@ exports.setup = function(){ var _rootNode = document.createElement('div'); document.body.appendChild(_rootNode); }; -exports.fn = function(){ +exports.fn = function() { React.render(AwesomeComponent(null), _rootNode); }; -exports.teardown = function(){ +exports.teardown = function() { React.unmountComponentAtNode(_rootNode); }; diff --git a/perf/tests/todolist-add.js b/perf/tests/todolist-add.js index d129f51481c06..2c84e4427e002 100644 --- a/perf/tests/todolist-add.js +++ b/perf/tests/todolist-add.js @@ -1,4 +1,6 @@ -if (typeof exports == 'undefined') exports = {}; +if (typeof exports === 'undefined') { + exports = {}; +} /*http://benchmarkjs.com/docs#options*/ @@ -6,20 +8,22 @@ exports.name = 'todolist from addItem to callback'; exports.defer = true; -exports.setup = function(){ - /*global*/_rootNode = document.createElement('div'); +exports.setup = function() { + _rootNode = document.createElement('div'); document.body.appendChild(_rootNode); var appDescriptor = todolist.App({ fakeDataCount: 333 }); - /*global*/_app = React.render(appDescriptor, _rootNode); + _app = React.render(appDescriptor, _rootNode); }; -exports.fn = function(deferred){ +exports.fn = function(deferred) { var liCount = document.getElementsByTagName('li').length; - _app.addItem(Math.random(), function(){ - if (document.getElementsByTagName('li').length <= liCount) throw Error('expected a list item to be added to the dom'); + _app.addItem(Math.random(), function() { + if (document.getElementsByTagName('li').length <= liCount) { + throw Error('expected a list item to be added to the dom'); + } deferred.resolve(); }); }; -exports.teardown = function(){ +exports.teardown = function() { React.unmountComponentAtNode(_rootNode); _rootNode.parentNode.removeChild(_rootNode); _rootNode = null; diff --git a/perf/tests/todolist-do-stuff.js b/perf/tests/todolist-do-stuff.js index 78aadca8839c2..56cc749e142c2 100644 --- a/perf/tests/todolist-do-stuff.js +++ b/perf/tests/todolist-do-stuff.js @@ -1,52 +1,56 @@ -if (typeof exports == 'undefined') exports = {}; +if (typeof exports === 'undefined') { + exports = {}; +} /*http://benchmarkjs.com/docs#options*/ -/*global*/_timesToRun = 2; +_timesToRun = 2; exports.name = 'todolist add, complete, remove (x' + _timesToRun + ')'; exports.defer = true; -exports.setup = function(){ - /*global*/_rootNode = document.createElement('div'); +exports.setup = function() { + _rootNode = document.createElement('div'); document.body.appendChild(_rootNode); var appDescriptor = todolist.App({ fakeDataCount: 333 }); - /*global*/_app = React.render(appDescriptor, _rootNode); + _app = React.render(appDescriptor, _rootNode); }; -exports.fn = function(deferred){ +exports.fn = function(deferred) { var originalLiCount = document.getElementsByTagName('li').length; var todos = []; var times = _timesToRun; - while (times-- >= 0){ - todos.push(_app.addItem(times+1)); + while (times-- >= 0) { + todos.push(_app.addItem(times + 1)); } - todos.forEach(function(todo){ + todos.forEach(function(todo) { _app.setItemCompleted(todo.id); }); - todos.forEach(function(todo){ + todos.forEach(function(todo) { _app.deleteItemById(todo.id); }); todos = null; - _app.addItem(Math.random(), function(todo){ - if (document.getElementsByTagName('li').length <= originalLiCount) + _app.addItem(Math.random(), function(todo) { + if (document.getElementsByTagName('li').length <= originalLiCount) { throw Error('expected a list item to be added to the dom'); + } - _app.deleteItemById(todo.id, function(){ - if (document.getElementsByTagName('li').length != originalLiCount) + _app.deleteItemById(todo.id, function() { + if (document.getElementsByTagName('li').length !== originalLiCount) { throw Error('expected everything to be done by now'); + } deferred.resolve(); }); }); }; -exports.teardown = function(){ +exports.teardown = function() { React.unmountComponentAtNode(_rootNode); _rootNode.parentNode.removeChild(_rootNode); _rootNode = null; diff --git a/perf/tests/todolist-edit.js b/perf/tests/todolist-edit.js index 9a8185ac9fd0c..9d313194275e2 100644 --- a/perf/tests/todolist-edit.js +++ b/perf/tests/todolist-edit.js @@ -1,4 +1,6 @@ -if (typeof exports == 'undefined') exports = {}; +if (typeof exports === 'undefined') { + exports = {}; +} /*http://benchmarkjs.com/docs#options*/ @@ -6,25 +8,25 @@ exports.name = 'todolist setItemCompleted'; exports.defer = true; -exports.setup = function(){ - /*global*/_rootNode = document.createElement('div'); +exports.setup = function() { + _rootNode = document.createElement('div'); document.body.appendChild(_rootNode); var appDescriptor = todolist.App({ fakeDataCount: 333 }); - /*global*/_app = React.render(appDescriptor, _rootNode); - /*global*/_todo1 = _app.addItem("Howdy 1!"); - /*global*/_todo2 = _app.addItem("Howdy 2!"); - /*global*/_todo3 = _app.addItem("Howdy 3!"); + _app = React.render(appDescriptor, _rootNode); + _todo1 = _app.addItem('Howdy 1!'); + _todo2 = _app.addItem('Howdy 2!'); + _todo3 = _app.addItem('Howdy 3!'); }; -exports.fn = function(deferred){ +exports.fn = function(deferred) { _app.setItemCompleted(_todo1.id, !_todo1.completed); _app.setItemCompleted(_todo2.id, !_todo2.completed); - _app.setItemCompleted(_todo3.id, !_todo3.completed, function(){ + _app.setItemCompleted(_todo3.id, !_todo3.completed, function() { deferred.resolve(); }); }; -exports.teardown = function(){ +exports.teardown = function() { React.unmountComponentAtNode(_rootNode); _rootNode.parentNode.removeChild(_rootNode); _rootNode = null; diff --git a/perf/tests/todolist-mount.js b/perf/tests/todolist-mount.js index 8ef6c2433861a..0fa7b2cafcaff 100644 --- a/perf/tests/todolist-mount.js +++ b/perf/tests/todolist-mount.js @@ -1,22 +1,29 @@ -if (typeof exports == 'undefined') exports = {}; +if (typeof exports === 'undefined') { + exports = {}; +} /*http://benchmarkjs.com/docs#options*/ -exports.name = 'todolist from renderComponent to renderComponent callback (333 rows)'; +exports.name = + 'todolist from renderComponent to renderComponent callback (333 rows)'; exports.defer = true; -exports.setup = function(){ - if (typeof _rootNode != 'undefined') throw Error("should teardown before running setup again"); - /*global*/_rootNode = document.createElement('div'); +exports.setup = function() { + if (typeof _rootNode !== 'undefined') { + throw Error('should teardown before running setup again'); + } + _rootNode = document.createElement('div'); document.body.appendChild(_rootNode); }; -exports.fn = function(deferred){ - React.render(todolist.App({ fakeDataCount: 333 }), _rootNode, function(){ deferred.resolve(); }); +exports.fn = function(deferred) { + React.render(todolist.App({ fakeDataCount: 333 }), _rootNode, function() { + deferred.resolve(); + }); }; -exports.teardown = function(){ +exports.teardown = function() { React.unmountComponentAtNode(_rootNode); _rootNode.parentNode.removeChild(_rootNode); _rootNode = undefined; diff --git a/test/.eslintrc b/test/.eslintrc new file mode 100644 index 0000000000000..4137f6e09ff15 --- /dev/null +++ b/test/.eslintrc @@ -0,0 +1,8 @@ +globals: + harness: true + +rules: + strict: false + no-undef: false + no-unused-vars: false + block-scoped-var: false \ No newline at end of file diff --git a/test/lib/jasmine-execute.js b/test/lib/jasmine-execute.js index cb3404faa6a0a..177d55658c791 100644 --- a/test/lib/jasmine-execute.js +++ b/test/lib/jasmine-execute.js @@ -1,6 +1,6 @@ -document.write(''); +document.write(''); -;(function(env){ +(function(env) { var htmlReporter = new jasmine.HtmlReporter(); env.addReporter(htmlReporter); env.specFilter = function(spec) { @@ -10,10 +10,10 @@ document.write('