From b16921646d076e0cb8b0912e3ca28c62eb016d0a Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Fri, 30 Oct 2015 22:54:15 -0400 Subject: [PATCH 01/21] exclude dead branches --- src/Module.js | 13 ++++ src/ast/conditions.js | 65 +++++++++++++++++++ src/ast/create.js | 7 ++ .../function/skips-dead-branches-b/_config.js | 8 +++ test/function/skips-dead-branches-b/main.js | 10 +++ .../function/skips-dead-branches-c/_config.js | 8 +++ test/function/skips-dead-branches-c/main.js | 10 +++ .../function/skips-dead-branches-d/_config.js | 8 +++ test/function/skips-dead-branches-d/main.js | 10 +++ .../function/skips-dead-branches-e/_config.js | 8 +++ test/function/skips-dead-branches-e/main.js | 10 +++ test/function/skips-dead-branches/_config.js | 8 +++ test/function/skips-dead-branches/main.js | 10 +++ test/test.js | 2 + 14 files changed, 177 insertions(+) create mode 100644 src/ast/conditions.js create mode 100644 src/ast/create.js create mode 100644 test/function/skips-dead-branches-b/_config.js create mode 100644 test/function/skips-dead-branches-b/main.js create mode 100644 test/function/skips-dead-branches-c/_config.js create mode 100644 test/function/skips-dead-branches-c/main.js create mode 100644 test/function/skips-dead-branches-d/_config.js create mode 100644 test/function/skips-dead-branches-d/main.js create mode 100644 test/function/skips-dead-branches-e/_config.js create mode 100644 test/function/skips-dead-branches-e/main.js create mode 100644 test/function/skips-dead-branches/_config.js create mode 100644 test/function/skips-dead-branches/main.js diff --git a/src/Module.js b/src/Module.js index 3bbf32e..159f466 100644 --- a/src/Module.js +++ b/src/Module.js @@ -7,6 +7,8 @@ import { basename, extname } from './utils/path.js'; import getLocation from './utils/getLocation.js'; import makeLegalIdentifier from './utils/makeLegalIdentifier.js'; import SOURCEMAPPING_URL from './utils/sourceMappingURL.js'; +import { isFalsy, isTruthy } from './ast/conditions.js'; +import { emptyBlockStatement } from './ast/create.js'; class SyntheticDefaultDeclaration { constructor ( node, statement, name ) { @@ -446,6 +448,17 @@ export default class Module { walk( ast, { enter: node => { + // eliminate dead branches early + if ( node.type === 'IfStatement' ) { + if ( isFalsy( node.test ) ) { + this.magicString.overwrite( node.consequent.start, node.consequent.end, '{}' ); + node.consequent = emptyBlockStatement( node.consequent.start, node.consequent.end ); + } else if ( node.alternate && isTruthy( node.test ) ) { + this.magicString.overwrite( node.alternate.start, node.alternate.end, '{}' ); + node.alternate = emptyBlockStatement( node.alternate.start, node.alternate.end ); + } + } + this.magicString.addSourcemapLocation( node.start ); this.magicString.addSourcemapLocation( node.end ); } diff --git a/src/ast/conditions.js b/src/ast/conditions.js new file mode 100644 index 0000000..e3d905f --- /dev/null +++ b/src/ast/conditions.js @@ -0,0 +1,65 @@ +function isEqualTest ( node ) { + return node.type === 'BinaryExpression' && ( node.operator === '===' || node.operator === '==' ); +} + +function isNotEqualTest ( node ) { + return node.type === 'BinaryExpression' && ( node.operator === '!==' || node.operator === '!=' ); +} + +function nodesAreEqual ( a, b ) { + if ( a.type !== b.type ) return false; + if ( a.type === 'Literal' ) return a.value === b.value; + if ( a.type === 'Identifier' ) return a.name === b.name; + + return false; +} + +function nodesAreNotEqual ( a, b ) { + if ( a.type !== b.type ) return false; + if ( a.type === 'Literal' ) return a.value != b.value; + if ( a.type === 'Identifier' ) return a.name != b.name; + + return false; +} + +export function isTruthy ( node ) { + if ( node.type === 'Literal' && node.value ) return true; + if ( node.type === 'ParenthesizedExpression' ) return isTruthy( node.expression ); + + if ( isEqualTest( node ) ) return nodesAreEqual( node.left, node.right ); + if ( isNotEqualTest( node ) ) return nodesAreNotEqual( node.left, node.right ); + + if ( node.type === 'UnaryExpression' ) { + if ( node.operator === '!' ) return isFalsy( node.argument ); + return false; + } + + if ( node.type === 'LogicalExpression' ) { + if ( node.operator === '&&' ) return isTruthy( node.left ) && isTruthy( node.right ); + if ( node.operator === '||' ) return isTruthy( node.left ) || isTruthy( node.right ); + return false; + } + + return false; +} + +export function isFalsy ( node ) { + if ( node.type === 'Literal' && !node.value ) return true; + if ( node.type === 'ParenthesizedExpression' ) return isFalsy( node.expression ); + + if ( isEqualTest( node ) ) return nodesAreNotEqual( node.left, node.right ); + if ( isNotEqualTest( node ) ) return nodesAreEqual( node.left, node.right ); + + if ( node.type === 'UnaryExpression' ) { + if ( node.operator === '!' ) return isTruthy( node.argument ); + return false; + } + + if ( node.type === 'LogicalExpression' ) { + if ( node.operator === '&&' ) return isFalsy( node.left ) || isFalsy( node.right ); + if ( node.operator === '||' ) return isFalsy( node.left ) && isFalsy( node.right ); + return false; + } + + return false; +} diff --git a/src/ast/create.js b/src/ast/create.js new file mode 100644 index 0000000..e767dbd --- /dev/null +++ b/src/ast/create.js @@ -0,0 +1,7 @@ +export function emptyBlockStatement ( start, end ) { + return { + start, end, + type: 'BlockStatement', + body: [] + }; +} diff --git a/test/function/skips-dead-branches-b/_config.js b/test/function/skips-dead-branches-b/_config.js new file mode 100644 index 0000000..3bdcfdd --- /dev/null +++ b/test/function/skips-dead-branches-b/_config.js @@ -0,0 +1,8 @@ +var assert = require( 'assert' ); + +module.exports = { + description: 'skips a dead branch (b)', + code: function ( code ) { + assert.equal( code.indexOf( 'function foo' ), -1, code ); + } +} diff --git a/test/function/skips-dead-branches-b/main.js b/test/function/skips-dead-branches-b/main.js new file mode 100644 index 0000000..fd91f85 --- /dev/null +++ b/test/function/skips-dead-branches-b/main.js @@ -0,0 +1,10 @@ +function foo () { + console.log( 'this should be excluded' ); +} + +function bar () { + console.log( 'this should be included' ); +} + +if ( true ) bar(); +else foo(); diff --git a/test/function/skips-dead-branches-c/_config.js b/test/function/skips-dead-branches-c/_config.js new file mode 100644 index 0000000..2d4a166 --- /dev/null +++ b/test/function/skips-dead-branches-c/_config.js @@ -0,0 +1,8 @@ +var assert = require( 'assert' ); + +module.exports = { + description: 'skips a dead branch (c)', + code: function ( code ) { + assert.equal( code.indexOf( 'function foo' ), -1, code ); + } +} diff --git a/test/function/skips-dead-branches-c/main.js b/test/function/skips-dead-branches-c/main.js new file mode 100644 index 0000000..55460e9 --- /dev/null +++ b/test/function/skips-dead-branches-c/main.js @@ -0,0 +1,10 @@ +function foo () { + console.log( 'this should be excluded' ); +} + +function bar () { + console.log( 'this should be included' ); +} + +if ( !true ) foo(); +bar(); diff --git a/test/function/skips-dead-branches-d/_config.js b/test/function/skips-dead-branches-d/_config.js new file mode 100644 index 0000000..2d4a166 --- /dev/null +++ b/test/function/skips-dead-branches-d/_config.js @@ -0,0 +1,8 @@ +var assert = require( 'assert' ); + +module.exports = { + description: 'skips a dead branch (c)', + code: function ( code ) { + assert.equal( code.indexOf( 'function foo' ), -1, code ); + } +} diff --git a/test/function/skips-dead-branches-d/main.js b/test/function/skips-dead-branches-d/main.js new file mode 100644 index 0000000..9e4894c --- /dev/null +++ b/test/function/skips-dead-branches-d/main.js @@ -0,0 +1,10 @@ +function foo () { + console.log( 'this should be excluded' ); +} + +function bar () { + console.log( 'this should be included' ); +} + +if ( 'development' === 'production' ) foo(); +bar(); diff --git a/test/function/skips-dead-branches-e/_config.js b/test/function/skips-dead-branches-e/_config.js new file mode 100644 index 0000000..2d4a166 --- /dev/null +++ b/test/function/skips-dead-branches-e/_config.js @@ -0,0 +1,8 @@ +var assert = require( 'assert' ); + +module.exports = { + description: 'skips a dead branch (c)', + code: function ( code ) { + assert.equal( code.indexOf( 'function foo' ), -1, code ); + } +} diff --git a/test/function/skips-dead-branches-e/main.js b/test/function/skips-dead-branches-e/main.js new file mode 100644 index 0000000..bf8e903 --- /dev/null +++ b/test/function/skips-dead-branches-e/main.js @@ -0,0 +1,10 @@ +function foo () { + console.log( 'this should be excluded' ); +} + +function bar () { + console.log( 'this should be included' ); +} + +if ( 'production' !== 'production' ) foo(); +bar(); diff --git a/test/function/skips-dead-branches/_config.js b/test/function/skips-dead-branches/_config.js new file mode 100644 index 0000000..aacc756 --- /dev/null +++ b/test/function/skips-dead-branches/_config.js @@ -0,0 +1,8 @@ +var assert = require( 'assert' ); + +module.exports = { + description: 'skips a dead branch', + code: function ( code ) { + assert.equal( code.indexOf( 'function foo' ), -1, code ); + } +} diff --git a/test/function/skips-dead-branches/main.js b/test/function/skips-dead-branches/main.js new file mode 100644 index 0000000..2b44506 --- /dev/null +++ b/test/function/skips-dead-branches/main.js @@ -0,0 +1,10 @@ +function foo () { + console.log( 'this should be excluded' ); +} + +function bar () { + console.log( 'this should be included' ); +} + +if ( false ) foo(); +else bar(); diff --git a/test/test.js b/test/test.js index cdb2952..83ed90e 100644 --- a/test/test.js +++ b/test/test.js @@ -161,6 +161,8 @@ describe( 'rollup', function () { code = result.code; } + if ( config.code ) config.code( code ); + var module = { exports: {} }; From 8410826b7f5f12d5ce16cc22e0f21cd190465b0f Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Fri, 30 Oct 2015 23:01:53 -0400 Subject: [PATCH 02/21] more stringent tests --- test/function/skips-dead-branches-b/_config.js | 2 +- test/function/skips-dead-branches-b/main.js | 5 +++-- test/function/skips-dead-branches-c/_config.js | 2 +- test/function/skips-dead-branches-c/main.js | 5 +++-- test/function/skips-dead-branches-d/_config.js | 2 +- test/function/skips-dead-branches-d/main.js | 5 +++-- test/function/skips-dead-branches-e/_config.js | 2 +- test/function/skips-dead-branches-e/main.js | 5 +++-- test/function/skips-dead-branches/_config.js | 2 +- test/function/skips-dead-branches/main.js | 5 +++-- 10 files changed, 20 insertions(+), 15 deletions(-) diff --git a/test/function/skips-dead-branches-b/_config.js b/test/function/skips-dead-branches-b/_config.js index 3bdcfdd..bb15b49 100644 --- a/test/function/skips-dead-branches-b/_config.js +++ b/test/function/skips-dead-branches-b/_config.js @@ -3,6 +3,6 @@ var assert = require( 'assert' ); module.exports = { description: 'skips a dead branch (b)', code: function ( code ) { - assert.equal( code.indexOf( 'function foo' ), -1, code ); + assert.equal( code.indexOf( 'obj.foo = function' ), -1, code ); } } diff --git a/test/function/skips-dead-branches-b/main.js b/test/function/skips-dead-branches-b/main.js index fd91f85..de00a11 100644 --- a/test/function/skips-dead-branches-b/main.js +++ b/test/function/skips-dead-branches-b/main.js @@ -1,4 +1,5 @@ -function foo () { +var obj = {}; +obj.foo = function () { console.log( 'this should be excluded' ); } @@ -7,4 +8,4 @@ function bar () { } if ( true ) bar(); -else foo(); +else obj.foo(); diff --git a/test/function/skips-dead-branches-c/_config.js b/test/function/skips-dead-branches-c/_config.js index 2d4a166..47111d5 100644 --- a/test/function/skips-dead-branches-c/_config.js +++ b/test/function/skips-dead-branches-c/_config.js @@ -3,6 +3,6 @@ var assert = require( 'assert' ); module.exports = { description: 'skips a dead branch (c)', code: function ( code ) { - assert.equal( code.indexOf( 'function foo' ), -1, code ); + assert.equal( code.indexOf( 'obj.foo = function' ), -1, code ); } } diff --git a/test/function/skips-dead-branches-c/main.js b/test/function/skips-dead-branches-c/main.js index 55460e9..98720e4 100644 --- a/test/function/skips-dead-branches-c/main.js +++ b/test/function/skips-dead-branches-c/main.js @@ -1,4 +1,5 @@ -function foo () { +var obj = {}; +obj.foo = function () { console.log( 'this should be excluded' ); } @@ -6,5 +7,5 @@ function bar () { console.log( 'this should be included' ); } -if ( !true ) foo(); +if ( !true ) obj.foo(); bar(); diff --git a/test/function/skips-dead-branches-d/_config.js b/test/function/skips-dead-branches-d/_config.js index 2d4a166..47111d5 100644 --- a/test/function/skips-dead-branches-d/_config.js +++ b/test/function/skips-dead-branches-d/_config.js @@ -3,6 +3,6 @@ var assert = require( 'assert' ); module.exports = { description: 'skips a dead branch (c)', code: function ( code ) { - assert.equal( code.indexOf( 'function foo' ), -1, code ); + assert.equal( code.indexOf( 'obj.foo = function' ), -1, code ); } } diff --git a/test/function/skips-dead-branches-d/main.js b/test/function/skips-dead-branches-d/main.js index 9e4894c..bfff556 100644 --- a/test/function/skips-dead-branches-d/main.js +++ b/test/function/skips-dead-branches-d/main.js @@ -1,4 +1,5 @@ -function foo () { +var obj = {}; +obj.foo = function () { console.log( 'this should be excluded' ); } @@ -6,5 +7,5 @@ function bar () { console.log( 'this should be included' ); } -if ( 'development' === 'production' ) foo(); +if ( 'development' === 'production' ) obj.foo(); bar(); diff --git a/test/function/skips-dead-branches-e/_config.js b/test/function/skips-dead-branches-e/_config.js index 2d4a166..47111d5 100644 --- a/test/function/skips-dead-branches-e/_config.js +++ b/test/function/skips-dead-branches-e/_config.js @@ -3,6 +3,6 @@ var assert = require( 'assert' ); module.exports = { description: 'skips a dead branch (c)', code: function ( code ) { - assert.equal( code.indexOf( 'function foo' ), -1, code ); + assert.equal( code.indexOf( 'obj.foo = function' ), -1, code ); } } diff --git a/test/function/skips-dead-branches-e/main.js b/test/function/skips-dead-branches-e/main.js index bf8e903..12f705d 100644 --- a/test/function/skips-dead-branches-e/main.js +++ b/test/function/skips-dead-branches-e/main.js @@ -1,4 +1,5 @@ -function foo () { +var obj = {}; +obj.foo = function () { console.log( 'this should be excluded' ); } @@ -6,5 +7,5 @@ function bar () { console.log( 'this should be included' ); } -if ( 'production' !== 'production' ) foo(); +if ( 'production' !== 'production' ) obj.foo(); bar(); diff --git a/test/function/skips-dead-branches/_config.js b/test/function/skips-dead-branches/_config.js index aacc756..1278d35 100644 --- a/test/function/skips-dead-branches/_config.js +++ b/test/function/skips-dead-branches/_config.js @@ -3,6 +3,6 @@ var assert = require( 'assert' ); module.exports = { description: 'skips a dead branch', code: function ( code ) { - assert.equal( code.indexOf( 'function foo' ), -1, code ); + assert.equal( code.indexOf( 'obj.foo = function' ), -1, code ); } } diff --git a/test/function/skips-dead-branches/main.js b/test/function/skips-dead-branches/main.js index 2b44506..e25eb6e 100644 --- a/test/function/skips-dead-branches/main.js +++ b/test/function/skips-dead-branches/main.js @@ -1,4 +1,5 @@ -function foo () { +var obj = {}; +obj.foo = function () { console.log( 'this should be excluded' ); } @@ -6,5 +7,5 @@ function bar () { console.log( 'this should be included' ); } -if ( false ) foo(); +if ( false ) obj.foo(); else bar(); From cabc4ee097c6b0ee1b03c300709233ef9495d293 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Mon, 2 Nov 2015 20:41:06 -0500 Subject: [PATCH 03/21] support async transformers (closes #260) --- src/utils/transform.js | 35 ++++++++++++---------- test/function/transformer-async/_config.js | 24 +++++++++++++++ test/function/transformer-async/main.js | 1 + 3 files changed, 45 insertions(+), 15 deletions(-) create mode 100644 test/function/transformer-async/_config.js create mode 100644 test/function/transformer-async/main.js diff --git a/src/utils/transform.js b/src/utils/transform.js index 16ca598..761a217 100644 --- a/src/utils/transform.js +++ b/src/utils/transform.js @@ -1,3 +1,5 @@ +import Promise from 'es6-promise/lib/es6-promise/promise.js'; + export default function transform ( source, id, transformers ) { let sourceMapChain = []; @@ -11,24 +13,27 @@ export default function transform ( source, id, transformers ) { let originalCode = source.code; let ast = source.ast; - let code = transformers.reduce( ( previous, transformer ) => { - let result = transformer( previous, id ); + return transformers.reduce( ( promise, transformer ) => { + return promise.then( previous => { + return Promise.resolve( transformer( previous, id ) ).then( result => { + if ( result == null ) return previous; - if ( result == null ) return previous; + if ( typeof result === 'string' ) { + result = { + code: result, + ast: null, + map: null + }; + } - if ( typeof result === 'string' ) { - result = { - code: result, - ast: null, - map: null - }; - } + sourceMapChain.push( result.map ); + ast = result.ast; - sourceMapChain.push( result.map ); - ast = result.ast; + return result.code; + }); + }); - return result.code; - }, source.code ); + }, Promise.resolve( source.code ) ) - return { code, originalCode, ast, sourceMapChain }; + .then( code => ({ code, originalCode, ast, sourceMapChain }) ); } diff --git a/test/function/transformer-async/_config.js b/test/function/transformer-async/_config.js new file mode 100644 index 0000000..960eb69 --- /dev/null +++ b/test/function/transformer-async/_config.js @@ -0,0 +1,24 @@ +var Promise = require( 'es6-promise' ).Promise; + +module.exports = { + description: 'transformers can be asynchronous', + options: { + plugins: [ + { + transform: function ( code ) { + return Promise.resolve( code.replace( 'x', 1 ) ); + } + }, + { + transform: function ( code ) { + return code.replace( '1', 2 ); + } + }, + { + transform: function ( code ) { + return Promise.resolve( code.replace( '2', 3 ) ); + } + } + ] + } +}; diff --git a/test/function/transformer-async/main.js b/test/function/transformer-async/main.js new file mode 100644 index 0000000..a09d995 --- /dev/null +++ b/test/function/transformer-async/main.js @@ -0,0 +1 @@ +assert.equal( x, 3 ); From 939a94b1c3454ebc69be6886f86d60ae4f367256 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Mon, 2 Nov 2015 20:42:29 -0500 Subject: [PATCH 04/21] =?UTF-8?q?import=20Promise=20to=20src/rollup.js=20?= =?UTF-8?q?=E2=80=93=20fixes=20#254?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rollup.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rollup.js b/src/rollup.js index 4829d23..0b75d2e 100644 --- a/src/rollup.js +++ b/src/rollup.js @@ -1,3 +1,4 @@ +import Promise from 'es6-promise/lib/es6-promise/promise.js'; import { basename } from './utils/path.js'; import { writeFile } from './utils/fs.js'; import { keys } from './utils/object.js'; From 4580b4bf54a918f88ebd0c85dc0fd73bcdcb9674 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Tue, 3 Nov 2015 08:30:26 -0500 Subject: [PATCH 05/21] handle NaN --- src/ast/conditions.js | 6 +++--- test/function/skips-dead-branches-d/_config.js | 2 +- test/function/skips-dead-branches-e/_config.js | 2 +- test/function/skips-dead-branches-f/_config.js | 9 +++++++++ test/function/skips-dead-branches-f/main.js | 11 +++++++++++ 5 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 test/function/skips-dead-branches-f/_config.js create mode 100644 test/function/skips-dead-branches-f/main.js diff --git a/src/ast/conditions.js b/src/ast/conditions.js index e3d905f..e544e43 100644 --- a/src/ast/conditions.js +++ b/src/ast/conditions.js @@ -8,8 +8,8 @@ function isNotEqualTest ( node ) { function nodesAreEqual ( a, b ) { if ( a.type !== b.type ) return false; - if ( a.type === 'Literal' ) return a.value === b.value; - if ( a.type === 'Identifier' ) return a.name === b.name; + if ( a.type === 'Literal' ) return a.value === b.value + if ( a.type === 'Identifier' ) return a.name === b.name && a.name !== 'NaN'; return false; } @@ -17,7 +17,7 @@ function nodesAreEqual ( a, b ) { function nodesAreNotEqual ( a, b ) { if ( a.type !== b.type ) return false; if ( a.type === 'Literal' ) return a.value != b.value; - if ( a.type === 'Identifier' ) return a.name != b.name; + if ( a.type === 'Identifier' ) return a.name != b.name || a.name === 'NaN'; return false; } diff --git a/test/function/skips-dead-branches-d/_config.js b/test/function/skips-dead-branches-d/_config.js index 47111d5..3cc97d3 100644 --- a/test/function/skips-dead-branches-d/_config.js +++ b/test/function/skips-dead-branches-d/_config.js @@ -1,7 +1,7 @@ var assert = require( 'assert' ); module.exports = { - description: 'skips a dead branch (c)', + description: 'skips a dead branch (d)', code: function ( code ) { assert.equal( code.indexOf( 'obj.foo = function' ), -1, code ); } diff --git a/test/function/skips-dead-branches-e/_config.js b/test/function/skips-dead-branches-e/_config.js index 47111d5..15deabf 100644 --- a/test/function/skips-dead-branches-e/_config.js +++ b/test/function/skips-dead-branches-e/_config.js @@ -1,7 +1,7 @@ var assert = require( 'assert' ); module.exports = { - description: 'skips a dead branch (c)', + description: 'skips a dead branch (e)', code: function ( code ) { assert.equal( code.indexOf( 'obj.foo = function' ), -1, code ); } diff --git a/test/function/skips-dead-branches-f/_config.js b/test/function/skips-dead-branches-f/_config.js new file mode 100644 index 0000000..7893ccb --- /dev/null +++ b/test/function/skips-dead-branches-f/_config.js @@ -0,0 +1,9 @@ +var assert = require( 'assert' ); + +module.exports = { + solo: true, + description: 'skips a dead branch (f)', + code: function ( code ) { + assert.equal( code.indexOf( 'obj.foo = function' ), -1, code ); + } +} diff --git a/test/function/skips-dead-branches-f/main.js b/test/function/skips-dead-branches-f/main.js new file mode 100644 index 0000000..ab95b46 --- /dev/null +++ b/test/function/skips-dead-branches-f/main.js @@ -0,0 +1,11 @@ +var obj = {}; +obj.foo = function () { + console.log( 'this should be excluded' ); +} + +function bar () { + console.log( 'this should be included' ); +} + +if ( NaN === NaN ) obj.foo(); +bar(); From 98e890986f7f11a7d9f32fa81229555a0ddeaf3e Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Tue, 3 Nov 2015 09:00:33 -0500 Subject: [PATCH 06/21] DRY out code, handle strict vs non-strict --- src/ast/conditions.js | 76 ++++++------------- .../function/skips-dead-branches-f/_config.js | 1 - .../function/skips-dead-branches-g/_config.js | 8 ++ test/function/skips-dead-branches-g/main.js | 11 +++ 4 files changed, 44 insertions(+), 52 deletions(-) create mode 100644 test/function/skips-dead-branches-g/_config.js create mode 100644 test/function/skips-dead-branches-g/main.js diff --git a/src/ast/conditions.js b/src/ast/conditions.js index e544e43..e454891 100644 --- a/src/ast/conditions.js +++ b/src/ast/conditions.js @@ -1,65 +1,39 @@ -function isEqualTest ( node ) { - return node.type === 'BinaryExpression' && ( node.operator === '===' || node.operator === '==' ); +export function isTruthy ( node ) { + if ( node.type === 'Literal' ) return !!node.value; + if ( node.type === 'ParenthesizedExpression' ) return isTruthy( node.expression ); + if ( node.operator in operators ) return operators[ node.operator ]( node ); } -function isNotEqualTest ( node ) { - return node.type === 'BinaryExpression' && ( node.operator === '!==' || node.operator === '!=' ); +export function isFalsy ( node ) { + return not( isTruthy( node ) ); } -function nodesAreEqual ( a, b ) { - if ( a.type !== b.type ) return false; - if ( a.type === 'Literal' ) return a.value === b.value - if ( a.type === 'Identifier' ) return a.name === b.name && a.name !== 'NaN'; - - return false; +function not ( value ) { + return value === undefined ? value : !value; } -function nodesAreNotEqual ( a, b ) { - if ( a.type !== b.type ) return false; - if ( a.type === 'Literal' ) return a.value != b.value; - if ( a.type === 'Identifier' ) return a.name != b.name || a.name === 'NaN'; - - return false; +function equals ( a, b, strict ) { + if ( a.type !== b.type ) return undefined; + if ( a.type === 'Identifier' ) return a.name === b.name && a.name !== 'NaN'; + if ( a.type === 'Literal' ) return strict ? a.value === b.value : a.value == b.value; } -export function isTruthy ( node ) { - if ( node.type === 'Literal' && node.value ) return true; - if ( node.type === 'ParenthesizedExpression' ) return isTruthy( node.expression ); - - if ( isEqualTest( node ) ) return nodesAreEqual( node.left, node.right ); - if ( isNotEqualTest( node ) ) return nodesAreNotEqual( node.left, node.right ); +const operators = { + '==': x => { + return equals( x.left, x.right, false ); + }, - if ( node.type === 'UnaryExpression' ) { - if ( node.operator === '!' ) return isFalsy( node.argument ); - return false; - } + '!=': x => not( operators['==']( x ) ), - if ( node.type === 'LogicalExpression' ) { - if ( node.operator === '&&' ) return isTruthy( node.left ) && isTruthy( node.right ); - if ( node.operator === '||' ) return isTruthy( node.left ) || isTruthy( node.right ); - return false; - } + '===': x => { + return equals( x.left, x.right, true ); + }, - return false; -} + '!==': x => not( operators['===']( x ) ), -export function isFalsy ( node ) { - if ( node.type === 'Literal' && !node.value ) return true; - if ( node.type === 'ParenthesizedExpression' ) return isFalsy( node.expression ); + '!': x => isFalsy( x.argument ), - if ( isEqualTest( node ) ) return nodesAreNotEqual( node.left, node.right ); - if ( isNotEqualTest( node ) ) return nodesAreEqual( node.left, node.right ); + '&&': x => isTruthy( x.left ) && isTruthy( x.right ), - if ( node.type === 'UnaryExpression' ) { - if ( node.operator === '!' ) return isTruthy( node.argument ); - return false; - } - - if ( node.type === 'LogicalExpression' ) { - if ( node.operator === '&&' ) return isFalsy( node.left ) || isFalsy( node.right ); - if ( node.operator === '||' ) return isFalsy( node.left ) && isFalsy( node.right ); - return false; - } - - return false; -} + '||': x => isTruthy( x.left ) || isTruthy( x.right ) +}; diff --git a/test/function/skips-dead-branches-f/_config.js b/test/function/skips-dead-branches-f/_config.js index 7893ccb..e43c622 100644 --- a/test/function/skips-dead-branches-f/_config.js +++ b/test/function/skips-dead-branches-f/_config.js @@ -1,7 +1,6 @@ var assert = require( 'assert' ); module.exports = { - solo: true, description: 'skips a dead branch (f)', code: function ( code ) { assert.equal( code.indexOf( 'obj.foo = function' ), -1, code ); diff --git a/test/function/skips-dead-branches-g/_config.js b/test/function/skips-dead-branches-g/_config.js new file mode 100644 index 0000000..428bd69 --- /dev/null +++ b/test/function/skips-dead-branches-g/_config.js @@ -0,0 +1,8 @@ +var assert = require( 'assert' ); + +module.exports = { + description: 'skips a dead branch (g)', + code: function ( code ) { + assert.equal( code.indexOf( 'obj.foo = function' ), -1, code ); + } +} diff --git a/test/function/skips-dead-branches-g/main.js b/test/function/skips-dead-branches-g/main.js new file mode 100644 index 0000000..d53efc8 --- /dev/null +++ b/test/function/skips-dead-branches-g/main.js @@ -0,0 +1,11 @@ +var obj = {}; +obj.foo = function () { + console.log( 'this should be excluded' ); +} + +function bar () { + console.log( 'this should be included' ); +} + +if ( 42 != '42' ) obj.foo(); +bar(); From 9c8f12d49c2d11aa216a996ab730a5fb0349dd16 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 3 Nov 2015 10:27:41 -0500 Subject: [PATCH 07/21] remove identifier comparison checks --- src/ast/conditions.js | 1 - test/function/skips-dead-branches-f/_config.js | 2 +- test/function/skips-dead-branches-f/main.js | 2 +- test/function/skips-dead-branches-g/_config.js | 8 -------- test/function/skips-dead-branches-g/main.js | 11 ----------- 5 files changed, 2 insertions(+), 22 deletions(-) delete mode 100644 test/function/skips-dead-branches-g/_config.js delete mode 100644 test/function/skips-dead-branches-g/main.js diff --git a/src/ast/conditions.js b/src/ast/conditions.js index e454891..b21e4d4 100644 --- a/src/ast/conditions.js +++ b/src/ast/conditions.js @@ -14,7 +14,6 @@ function not ( value ) { function equals ( a, b, strict ) { if ( a.type !== b.type ) return undefined; - if ( a.type === 'Identifier' ) return a.name === b.name && a.name !== 'NaN'; if ( a.type === 'Literal' ) return strict ? a.value === b.value : a.value == b.value; } diff --git a/test/function/skips-dead-branches-f/_config.js b/test/function/skips-dead-branches-f/_config.js index e43c622..428bd69 100644 --- a/test/function/skips-dead-branches-f/_config.js +++ b/test/function/skips-dead-branches-f/_config.js @@ -1,7 +1,7 @@ var assert = require( 'assert' ); module.exports = { - description: 'skips a dead branch (f)', + description: 'skips a dead branch (g)', code: function ( code ) { assert.equal( code.indexOf( 'obj.foo = function' ), -1, code ); } diff --git a/test/function/skips-dead-branches-f/main.js b/test/function/skips-dead-branches-f/main.js index ab95b46..d53efc8 100644 --- a/test/function/skips-dead-branches-f/main.js +++ b/test/function/skips-dead-branches-f/main.js @@ -7,5 +7,5 @@ function bar () { console.log( 'this should be included' ); } -if ( NaN === NaN ) obj.foo(); +if ( 42 != '42' ) obj.foo(); bar(); diff --git a/test/function/skips-dead-branches-g/_config.js b/test/function/skips-dead-branches-g/_config.js deleted file mode 100644 index 428bd69..0000000 --- a/test/function/skips-dead-branches-g/_config.js +++ /dev/null @@ -1,8 +0,0 @@ -var assert = require( 'assert' ); - -module.exports = { - description: 'skips a dead branch (g)', - code: function ( code ) { - assert.equal( code.indexOf( 'obj.foo = function' ), -1, code ); - } -} diff --git a/test/function/skips-dead-branches-g/main.js b/test/function/skips-dead-branches-g/main.js deleted file mode 100644 index d53efc8..0000000 --- a/test/function/skips-dead-branches-g/main.js +++ /dev/null @@ -1,11 +0,0 @@ -var obj = {}; -obj.foo = function () { - console.log( 'this should be excluded' ); -} - -function bar () { - console.log( 'this should be included' ); -} - -if ( 42 != '42' ) obj.foo(); -bar(); From d820ddfdc1b0b43ae50182f33d317b8f2a5ddf18 Mon Sep 17 00:00:00 2001 From: greenkeeperio-bot Date: Wed, 4 Nov 2015 09:23:06 -0500 Subject: [PATCH 08/21] chore(package): update remap-istanbul to version 0.4.0 http://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e62f50a..828796c 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "istanbul": "^0.4.0", "magic-string": "^0.8.0", "mocha": "^2.3.3", - "remap-istanbul": "^0.3.1", + "remap-istanbul": "^0.4.0", "rollup": "^0.20.2", "rollup-plugin-babel": "^1.0.0", "rollup-plugin-npm": "^1.0.0", From 61a89445987df3c64610b0687875840c1dc647eb Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Wed, 4 Nov 2015 11:15:35 -0800 Subject: [PATCH 09/21] Add failing test case. --- test/function/assignment-to-re-exports/_config.js | 10 ++++++++++ test/function/assignment-to-re-exports/count.js | 5 +++++ test/function/assignment-to-re-exports/main.js | 1 + 3 files changed, 16 insertions(+) create mode 100644 test/function/assignment-to-re-exports/_config.js create mode 100644 test/function/assignment-to-re-exports/count.js create mode 100644 test/function/assignment-to-re-exports/main.js diff --git a/test/function/assignment-to-re-exports/_config.js b/test/function/assignment-to-re-exports/_config.js new file mode 100644 index 0000000..376ba32 --- /dev/null +++ b/test/function/assignment-to-re-exports/_config.js @@ -0,0 +1,10 @@ +var assert = require( 'assert' ); + +module.exports = { + description: 're-exports are kept up-to-date', + exports: function ( exports ) { + assert.equal( exports.count, 0 ); + exports.incr(); + assert.equal( exports.count, 1 ); + } +}; diff --git a/test/function/assignment-to-re-exports/count.js b/test/function/assignment-to-re-exports/count.js new file mode 100644 index 0000000..2ed71df --- /dev/null +++ b/test/function/assignment-to-re-exports/count.js @@ -0,0 +1,5 @@ +export var count = 0; + +export function incr () { + count += 1; +} diff --git a/test/function/assignment-to-re-exports/main.js b/test/function/assignment-to-re-exports/main.js new file mode 100644 index 0000000..97b1267 --- /dev/null +++ b/test/function/assignment-to-re-exports/main.js @@ -0,0 +1 @@ +export {count, incr} from './count'; From 8c3f09dd37f472b5b5a7fd5e013b717fdcbde9b2 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Wed, 4 Nov 2015 11:51:24 -0800 Subject: [PATCH 10/21] =?UTF-8?q?Don=E2=80=99t=20assume=20re-exported=20bi?= =?UTF-8?q?ndings=20are=20globals.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #267. --- src/Module.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module.js b/src/Module.js index 3bbf32e..1ee1320 100644 --- a/src/Module.js +++ b/src/Module.js @@ -344,7 +344,7 @@ export default class Module { if ( declaration ) { declaration.addReference( reference ); - } else { + } else if ( statement.node.type !== 'ExportNamedDeclaration' || !this.reexports[ reference.name ] ) { // TODO handle globals this.bundle.assumedGlobals[ reference.name ] = true; } From 0afe2d9601fe7ad5b6815548650e5cd7c565bb0b Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Wed, 4 Nov 2015 12:10:01 -0800 Subject: [PATCH 11/21] Add another failing test. --- .../assignment-to-re-exports-conflict/_config.js | 10 ++++++++++ .../assignment-to-re-exports-conflict/count.js | 10 ++++++++++ .../function/assignment-to-re-exports-conflict/main.js | 1 + 3 files changed, 21 insertions(+) create mode 100644 test/function/assignment-to-re-exports-conflict/_config.js create mode 100644 test/function/assignment-to-re-exports-conflict/count.js create mode 100644 test/function/assignment-to-re-exports-conflict/main.js diff --git a/test/function/assignment-to-re-exports-conflict/_config.js b/test/function/assignment-to-re-exports-conflict/_config.js new file mode 100644 index 0000000..376ba32 --- /dev/null +++ b/test/function/assignment-to-re-exports-conflict/_config.js @@ -0,0 +1,10 @@ +var assert = require( 'assert' ); + +module.exports = { + description: 're-exports are kept up-to-date', + exports: function ( exports ) { + assert.equal( exports.count, 0 ); + exports.incr(); + assert.equal( exports.count, 1 ); + } +}; diff --git a/test/function/assignment-to-re-exports-conflict/count.js b/test/function/assignment-to-re-exports-conflict/count.js new file mode 100644 index 0000000..64bbd5a --- /dev/null +++ b/test/function/assignment-to-re-exports-conflict/count.js @@ -0,0 +1,10 @@ +export var count = 0; + +export function conflict () { + var foo = 0, + count = 42; +} + +export function incr () { + count += 1; +} diff --git a/test/function/assignment-to-re-exports-conflict/main.js b/test/function/assignment-to-re-exports-conflict/main.js new file mode 100644 index 0000000..1f290f5 --- /dev/null +++ b/test/function/assignment-to-re-exports-conflict/main.js @@ -0,0 +1 @@ +export {count, incr, conflict} from './count'; From f2333fd42bf1c1e3fc04b9e7d6e43e2588e15a1d Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Wed, 4 Nov 2015 12:12:43 -0800 Subject: [PATCH 12/21] Include all declared variables. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The comment suggest multi-variable declarations are split up, but that doesn’t appear to be the case. --- src/ast/attachScopes.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ast/attachScopes.js b/src/ast/attachScopes.js index 77b8af4..3f44684 100644 --- a/src/ast/attachScopes.js +++ b/src/ast/attachScopes.js @@ -17,11 +17,10 @@ export default function attachScopes ( statement ) { scope.addDeclaration( node, false, false ); } - // var foo = 1 + // var foo = 1, bar = 2 if ( node.type === 'VariableDeclaration' ) { const isBlockDeclaration = blockDeclarations[ node.kind ]; - // only one declarator per block, because we split them up already - scope.addDeclaration( node.declarations[0], isBlockDeclaration, true ); + node.declarations.forEach( declaration => scope.addDeclaration( declaration, isBlockDeclaration, true ) ); } let newScope; From 6593d5824c550b89bc005c2ec6748839507adf92 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 4 Nov 2015 15:28:21 -0500 Subject: [PATCH 13/21] -> 0.20.4 --- CHANGELOG.md | 8 ++++++++ package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33db186..0b2564f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # rollup changelog +## 0.20.4 + +* Check file exists at resolve time, to allow filenames with non-extension dots in them ([#250](https://github.com/rollup/rollup/pull/250)) +* Import `Promise` where used, for Node 0.10 support ([#254](https://github.com/rollup/rollup/issues/254)) +* Allow asynchronous transformer plugins ([#260](https://github.com/rollup/rollup/issues/260)) +* Don't assume re-exported bindings are globals when deconflicting ([#267](https://github.com/rollup/rollup/issues/267)) + + ## 0.20.3 * Fix bug where multiple `export *` declarations caused error ([#244](https://github.com/rollup/rollup/pulls/244)) diff --git a/package.json b/package.json index 828796c..2fb0eee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rollup", - "version": "0.20.3", + "version": "0.20.4", "description": "Next-generation ES6 module bundler", "main": "dist/rollup.js", "jsnext:main": "src/rollup.js", From 093d33e616cfdc88ed5825d5892d475a455a0554 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Wed, 4 Nov 2015 14:18:39 -0800 Subject: [PATCH 14/21] =?UTF-8?q?Add=20a=20test=20that=20should=20fail,=20?= =?UTF-8?q?but=20doesn=E2=80=99t.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/function/export-from-no-local-binding-var/_config.js | 5 +++++ test/function/export-from-no-local-binding-var/foo.js | 1 + test/function/export-from-no-local-binding-var/main.js | 3 +++ 3 files changed, 9 insertions(+) create mode 100644 test/function/export-from-no-local-binding-var/_config.js create mode 100644 test/function/export-from-no-local-binding-var/foo.js create mode 100644 test/function/export-from-no-local-binding-var/main.js diff --git a/test/function/export-from-no-local-binding-var/_config.js b/test/function/export-from-no-local-binding-var/_config.js new file mode 100644 index 0000000..3b1a85e --- /dev/null +++ b/test/function/export-from-no-local-binding-var/_config.js @@ -0,0 +1,5 @@ +var assert = require( 'assert' ); + +module.exports = { + description: 'export from does not create a local binding' +}; diff --git a/test/function/export-from-no-local-binding-var/foo.js b/test/function/export-from-no-local-binding-var/foo.js new file mode 100644 index 0000000..6ab80bc --- /dev/null +++ b/test/function/export-from-no-local-binding-var/foo.js @@ -0,0 +1 @@ +export default function() {} diff --git a/test/function/export-from-no-local-binding-var/main.js b/test/function/export-from-no-local-binding-var/main.js new file mode 100644 index 0000000..4d5595c --- /dev/null +++ b/test/function/export-from-no-local-binding-var/main.js @@ -0,0 +1,3 @@ +export {default as foo} from './foo'; + +export var foo1 = foo(); // This should fail as foo lacks a local binding. From dc564da15a65b09d7bd6c7c1c66e186f21cd6746 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 4 Nov 2015 17:52:01 -0500 Subject: [PATCH 15/21] alternative fix for #270 --- src/Module.js | 2 +- src/Statement.js | 3 +++ test/function/export-from-no-local-binding-var/_config.js | 5 ++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Module.js b/src/Module.js index 1ee1320..3bbf32e 100644 --- a/src/Module.js +++ b/src/Module.js @@ -344,7 +344,7 @@ export default class Module { if ( declaration ) { declaration.addReference( reference ); - } else if ( statement.node.type !== 'ExportNamedDeclaration' || !this.reexports[ reference.name ] ) { + } else { // TODO handle globals this.bundle.assumedGlobals[ reference.name ] = true; } diff --git a/src/Statement.js b/src/Statement.js index d5ec856..f6d086a 100644 --- a/src/Statement.js +++ b/src/Statement.js @@ -100,6 +100,9 @@ export default class Statement { module.bundle.onwarn( `Use of \`eval\` (in ${module.id}) is discouraged, as it may cause issues with minification. See https://github.com/rollup/rollup/wiki/Troubleshooting#avoiding-eval for more details` ); } + // skip re-export declarations + if ( node.type === 'ExportNamedDeclaration' && node.source ) return this.skip(); + if ( node.type === 'TemplateElement' ) stringLiteralRanges.push([ node.start, node.end ]); if ( node.type === 'Literal' && typeof node.value === 'string' && /\n/.test( node.raw ) ) { stringLiteralRanges.push([ node.start + 1, node.end - 1 ]); diff --git a/test/function/export-from-no-local-binding-var/_config.js b/test/function/export-from-no-local-binding-var/_config.js index 3b1a85e..e0b2e42 100644 --- a/test/function/export-from-no-local-binding-var/_config.js +++ b/test/function/export-from-no-local-binding-var/_config.js @@ -1,5 +1,8 @@ var assert = require( 'assert' ); module.exports = { - description: 'export from does not create a local binding' + description: 'export from does not create a local binding', + runtimeError: function ( err ) { + assert.ok( /foo is not defined/.test( err.message ) ); + } }; From 161a44731935af51ab30e7f29fee1b97eb2b0a89 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 4 Nov 2015 17:59:18 -0500 Subject: [PATCH 16/21] -> 0.20.5 --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b2564f..3c6bca2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # rollup changelog +## 0.20.5 + +* Ensure re-exports don't create a local binding ([#270](https://github.com/rollup/rollup/pull/270)) + ## 0.20.4 * Check file exists at resolve time, to allow filenames with non-extension dots in them ([#250](https://github.com/rollup/rollup/pull/250)) diff --git a/package.json b/package.json index 2fb0eee..25746f8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rollup", - "version": "0.20.4", + "version": "0.20.5", "description": "Next-generation ES6 module bundler", "main": "dist/rollup.js", "jsnext:main": "src/rollup.js", From c7843808a61d0a08d07bec30f58037f431b3d46c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Segersv=C3=A4rd?= Date: Fri, 6 Nov 2015 09:35:53 +0100 Subject: [PATCH 17/21] More eslint * Lint before test * Fix lint errors --- .eslintrc | 3 +++ package.json | 2 +- src/utils/defaults.js | 4 ++-- src/utils/first.js | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.eslintrc b/.eslintrc index 6e5fb1a..3a7900e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -16,6 +16,9 @@ "mocha": true, "node": true }, + "globals": { + "Promise": false + }, "extends": "eslint:recommended", "ecmaFeatures": { "modules": true diff --git a/package.json b/package.json index 25746f8..83afd34 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "rollup": "./bin/rollup" }, "scripts": { - "pretest": "npm run build", + "pretest": "eslint src/**/*.js && npm run build", "test": "mocha", "pretest-coverage": "npm run build", "test-coverage": "rm -rf coverage/* && istanbul cover --report json node_modules/.bin/_mocha -- -u exports -R spec test/test.js", diff --git a/src/utils/defaults.js b/src/utils/defaults.js index fef4f8a..9deea1f 100644 --- a/src/utils/defaults.js +++ b/src/utils/defaults.js @@ -1,5 +1,5 @@ import { isFile, readFileSync } from './fs.js'; -import { dirname, extname, isAbsolute, resolve } from './path.js'; +import { dirname, isAbsolute, resolve } from './path.js'; export function load ( id ) { return readFileSync( id, 'utf-8' ); @@ -28,5 +28,5 @@ export function resolveId ( importee, importer ) { } export function onwarn ( msg ) { - console.error( msg ); + console.error( msg ); //eslint-disable-line no-console } diff --git a/src/utils/first.js b/src/utils/first.js index 0fe2587..21d6fe3 100644 --- a/src/utils/first.js +++ b/src/utils/first.js @@ -9,5 +9,5 @@ export default function first ( candidates ) { result : Promise.resolve( candidate( ...args ) ) ); }, Promise.resolve() ); - } + }; } From ae9643fb3114e6946bac98741b08a55669080c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Segersv=C3=A4rd?= Date: Wed, 11 Nov 2015 14:07:05 +0100 Subject: [PATCH 18/21] Remove .eslintrc Promise global. Fix lint redundancy in package. --- .eslintrc | 3 --- package.json | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.eslintrc b/.eslintrc index 3a7900e..6e5fb1a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -16,9 +16,6 @@ "mocha": true, "node": true }, - "globals": { - "Promise": false - }, "extends": "eslint:recommended", "ecmaFeatures": { "modules": true diff --git a/package.json b/package.json index 83afd34..9594074 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "rollup": "./bin/rollup" }, "scripts": { - "pretest": "eslint src/**/*.js && npm run build", + "pretest": "npm run lint && npm run build", "test": "mocha", "pretest-coverage": "npm run build", "test-coverage": "rm -rf coverage/* && istanbul cover --report json node_modules/.bin/_mocha -- -u exports -R spec test/test.js", @@ -17,7 +17,7 @@ "build": "git rev-parse HEAD > .commithash && rollup -c -o dist/rollup.js", "build:browser": "git rev-parse HEAD > .commithash && rollup -c rollup.config.browser.js -o dist/rollup.browser.js", "prepublish": "npm test && npm run build:browser", - "lint": "eslint src" + "lint": "eslint src browser" }, "repository": { "type": "git", From 7a677359c6159966484ab96a8e9a68f1541d0998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Segersv=C3=A4rd?= Date: Wed, 11 Nov 2015 15:19:33 +0100 Subject: [PATCH 19/21] Log errors when using `rollup -c` --- bin/runRollup.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/bin/runRollup.js b/bin/runRollup.js index 4c2e5e2..bff21a1 100644 --- a/bin/runRollup.js +++ b/bin/runRollup.js @@ -4,6 +4,9 @@ var path = require( 'path' ); var handleError = require( './handleError' ); var rollup = require( '../' ); +// log to stderr to keep `rollup main.js > bundle.js` from breaking +var log = console.error.bind(console); + module.exports = function ( command ) { if ( command._.length > 1 ) { handleError({ code: 'ONE_AT_A_TIME' }); @@ -24,7 +27,7 @@ module.exports = function ( command ) { rollup.rollup({ entry: config, - onwarn: function () {} + onwarn: log }).then( function ( bundle ) { var code = bundle.generate({ format: 'cjs' @@ -49,7 +52,8 @@ module.exports = function ( command ) { execute( options, command ); require.extensions[ '.js' ] = defaultLoader; - }); + }) + .catch(log); } else { execute( {}, command ); } @@ -84,6 +88,8 @@ function execute ( options, command ) { command.globals = globals; } + options.onwarn = options.onwarn || log; + options.external = external; options.indent = command.indent !== false; From c29f4c24f181d8251f74e045a58de0cc3f96ee6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Segersv=C3=A4rd?= Date: Wed, 11 Nov 2015 17:25:57 +0100 Subject: [PATCH 20/21] Point TravisCI shield to the master branch --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bde1685..eb25481 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

- build status From 262334d70da1ac5ed9d811e1a20e22d4c9ff7b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Segersv=C3=A4rd?= Date: Wed, 11 Nov 2015 17:54:48 +0100 Subject: [PATCH 21/21] Check isUsed to prevent potentially infinite recursion --- src/Module.js | 4 ++++ src/ast/Scope.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/Module.js b/src/Module.js index 3bbf32e..be1397d 100644 --- a/src/Module.js +++ b/src/Module.js @@ -17,6 +17,8 @@ class SyntheticDefaultDeclaration { this.original = null; this.isExported = false; this.aliases = []; + + this.isUsed = false; } addAlias ( declaration ) { @@ -42,6 +44,8 @@ class SyntheticDefaultDeclaration { } use () { + if ( this.isUsed ) return; + this.isUsed = true; this.statement.mark(); diff --git a/src/ast/Scope.js b/src/ast/Scope.js index 7a210a4..cf61ba9 100644 --- a/src/ast/Scope.js +++ b/src/ast/Scope.js @@ -40,6 +40,8 @@ class Declaration { this.isReassigned = false; this.aliases = []; + + this.isUsed = false; } addAlias ( declaration ) { @@ -61,6 +63,8 @@ class Declaration { } use () { + if ( this.isUsed ) return; + this.isUsed = true; if ( this.statement ) this.statement.mark();