mirror of https://github.com/lukechilds/rollup.git
Rich-Harris
9 years ago
54 changed files with 545 additions and 370 deletions
@ -0,0 +1,16 @@ |
|||||
|
export default function flatten ( node ) { |
||||
|
let parts = []; |
||||
|
while ( node.type === 'MemberExpression' ) { |
||||
|
if ( node.computed ) return null; |
||||
|
parts.unshift( node.property.name ); |
||||
|
|
||||
|
node = node.object; |
||||
|
} |
||||
|
|
||||
|
if ( node.type !== 'Identifier' ) return null; |
||||
|
|
||||
|
const name = node.name; |
||||
|
parts.unshift( name ); |
||||
|
|
||||
|
return { name, keypath: parts.join( '.' ) }; |
||||
|
} |
@ -0,0 +1,4 @@ |
|||||
|
export default { |
||||
|
AssignmentExpression: 'left', |
||||
|
UpdateExpression: 'argument' |
||||
|
}; |
@ -0,0 +1,92 @@ |
|||||
|
import { walk } from 'estree-walker'; |
||||
|
import modifierNodes from '../ast/modifierNodes.js'; |
||||
|
import flatten from '../ast/flatten'; |
||||
|
|
||||
|
let pureFunctions = {}; |
||||
|
[ |
||||
|
// TODO add others to this list
|
||||
|
'Object.keys' |
||||
|
].forEach( name => pureFunctions[ name ] = true ); |
||||
|
|
||||
|
export default function testForSideEffects ( node, scope, statement ) { |
||||
|
let hasSideEffect = false; |
||||
|
|
||||
|
walk( node, { |
||||
|
enter ( node ) { |
||||
|
if ( hasSideEffect ) return this.skip(); |
||||
|
if ( /Function/.test( node.type ) ) return this.skip(); |
||||
|
|
||||
|
if ( node._scope ) scope = node._scope; |
||||
|
|
||||
|
// If this is a top-level call expression, or an assignment to a global,
|
||||
|
// this statement will need to be marked
|
||||
|
if ( node.type === 'NewExpression' ) { |
||||
|
hasSideEffect = true; |
||||
|
return this.skip(); |
||||
|
} |
||||
|
|
||||
|
if ( node.type === 'CallExpression' ) { |
||||
|
if ( node.callee.type === 'Identifier' && !scope.contains( node.callee.name ) ) { |
||||
|
const declaration = statement.module.trace( node.callee.name ); |
||||
|
|
||||
|
if ( !declaration || declaration.isExternal ) { |
||||
|
// we're calling a global or an external function. Assume side-effects
|
||||
|
hasSideEffect = true; |
||||
|
return this.skip(); |
||||
|
} |
||||
|
|
||||
|
// we're calling a function defined in this bundle
|
||||
|
if ( declaration.hasSideEffect() ) { |
||||
|
hasSideEffect = true; |
||||
|
return this.skip(); |
||||
|
} |
||||
|
|
||||
|
// TODO does function mutate inputs that are needed?
|
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if ( node.callee.type === 'MemberExpression' ) { |
||||
|
const flattened = flatten( node.callee ); |
||||
|
|
||||
|
if ( !flattened ) { |
||||
|
// is not a keypath like `foo.bar.baz` – could be e.g.
|
||||
|
// `(a || b).foo()`. Err on the side of caution
|
||||
|
hasSideEffect = true; |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// if we're calling e.g. Object.keys(thing), there are no side-effects
|
||||
|
// TODO make pureFunctions configurable
|
||||
|
const declaration = statement.module.trace( flattened.name ); |
||||
|
if ( !declaration && pureFunctions[ flattened.keypath ] ) return; |
||||
|
|
||||
|
hasSideEffect = true; |
||||
|
return this.skip(); |
||||
|
} |
||||
|
|
||||
|
// otherwise we're probably dealing with a function expression
|
||||
|
if ( testForSideEffects( node.callee, scope, statement ) ) { |
||||
|
hasSideEffect = true; |
||||
|
return this.skip(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if ( node.type in modifierNodes ) { |
||||
|
let subject = node[ modifierNodes[ node.type ] ]; |
||||
|
while ( subject.type === 'MemberExpression' ) subject = subject.object; |
||||
|
|
||||
|
const declaration = statement.module.trace( subject.name ); |
||||
|
|
||||
|
if ( !declaration || declaration.isExternal || declaration.statement.isIncluded ) { |
||||
|
hasSideEffect = true; |
||||
|
return this.skip(); |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
leave ( node ) { |
||||
|
if ( node._scope ) scope = scope.parent; |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
return hasSideEffect; |
||||
|
} |
@ -1,15 +1,19 @@ |
|||||
define(function () { 'use strict'; |
define(function () { 'use strict'; |
||||
|
|
||||
function foo () { |
function foo () { |
||||
}; |
console.log( 'foo' ); |
||||
|
} |
||||
|
|
||||
function a () { |
function a () { |
||||
foo(); |
foo(); |
||||
foo(); |
foo(); |
||||
|
|
||||
var a; |
var a; |
||||
if ( a.b ) { |
if ( a.b ) { |
||||
|
// empty
|
||||
} |
} |
||||
} |
} |
||||
|
|
||||
a(); |
a(); |
||||
|
|
||||
}); |
}); |
@ -1,13 +1,17 @@ |
|||||
'use strict'; |
'use strict'; |
||||
|
|
||||
function foo () { |
function foo () { |
||||
}; |
console.log( 'foo' ); |
||||
|
} |
||||
|
|
||||
function a () { |
function a () { |
||||
foo(); |
foo(); |
||||
foo(); |
foo(); |
||||
|
|
||||
var a; |
var a; |
||||
if ( a.b ) { |
if ( a.b ) { |
||||
|
// empty
|
||||
} |
} |
||||
} |
} |
||||
|
|
||||
a(); |
a(); |
@ -1,11 +1,15 @@ |
|||||
function foo () { |
function foo () { |
||||
}; |
console.log( 'foo' ); |
||||
|
} |
||||
|
|
||||
function a () { |
function a () { |
||||
foo(); |
foo(); |
||||
foo(); |
foo(); |
||||
|
|
||||
var a; |
var a; |
||||
if ( a.b ) { |
if ( a.b ) { |
||||
|
// empty
|
||||
} |
} |
||||
} |
} |
||||
|
|
||||
a(); |
a(); |
@ -1,15 +1,19 @@ |
|||||
(function () { 'use strict'; |
(function () { 'use strict'; |
||||
|
|
||||
function foo () { |
function foo () { |
||||
}; |
console.log( 'foo' ); |
||||
|
} |
||||
|
|
||||
function a () { |
function a () { |
||||
foo(); |
foo(); |
||||
foo(); |
foo(); |
||||
|
|
||||
var a; |
var a; |
||||
if ( a.b ) { |
if ( a.b ) { |
||||
|
// empty
|
||||
} |
} |
||||
} |
} |
||||
|
|
||||
a(); |
a(); |
||||
|
|
||||
})(); |
})(); |
@ -0,0 +1,6 @@ |
|||||
|
module.exports = { |
||||
|
description: 'discards IIFE with no side-effects', |
||||
|
options: { |
||||
|
moduleName: 'myBundle' |
||||
|
} |
||||
|
}; |
@ -0,0 +1,7 @@ |
|||||
|
define(function () { 'use strict'; |
||||
|
|
||||
|
var main = 42; |
||||
|
|
||||
|
return main; |
||||
|
|
||||
|
}); |
@ -0,0 +1,5 @@ |
|||||
|
'use strict'; |
||||
|
|
||||
|
var main = 42; |
||||
|
|
||||
|
module.exports = main; |
@ -0,0 +1,3 @@ |
|||||
|
var main = 42; |
||||
|
|
||||
|
export default main; |
@ -0,0 +1,7 @@ |
|||||
|
var myBundle = (function () { 'use strict'; |
||||
|
|
||||
|
var main = 42; |
||||
|
|
||||
|
return main; |
||||
|
|
||||
|
})(); |
@ -0,0 +1,11 @@ |
|||||
|
(function (global, factory) { |
||||
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : |
||||
|
typeof define === 'function' && define.amd ? define(factory) : |
||||
|
global.myBundle = factory(); |
||||
|
}(this, function () { 'use strict'; |
||||
|
|
||||
|
var main = 42; |
||||
|
|
||||
|
return main; |
||||
|
|
||||
|
})); |
@ -0,0 +1,8 @@ |
|||||
|
var Unused = (function () { |
||||
|
function Unused () {} |
||||
|
Unused.prototype = {}; |
||||
|
|
||||
|
return Unused; |
||||
|
}()); |
||||
|
|
||||
|
export default 42; |
@ -0,0 +1,6 @@ |
|||||
|
module.exports = { |
||||
|
description: 'discards function with no side-effects', |
||||
|
options: { |
||||
|
moduleName: 'myBundle' |
||||
|
} |
||||
|
}; |
@ -0,0 +1,7 @@ |
|||||
|
define(function () { 'use strict'; |
||||
|
|
||||
|
var main = 42; |
||||
|
|
||||
|
return main; |
||||
|
|
||||
|
}); |
@ -0,0 +1,5 @@ |
|||||
|
'use strict'; |
||||
|
|
||||
|
var main = 42; |
||||
|
|
||||
|
module.exports = main; |
@ -0,0 +1,3 @@ |
|||||
|
var main = 42; |
||||
|
|
||||
|
export default main; |
@ -0,0 +1,7 @@ |
|||||
|
var myBundle = (function () { 'use strict'; |
||||
|
|
||||
|
var main = 42; |
||||
|
|
||||
|
return main; |
||||
|
|
||||
|
})(); |
@ -0,0 +1,11 @@ |
|||||
|
(function (global, factory) { |
||||
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : |
||||
|
typeof define === 'function' && define.amd ? define(factory) : |
||||
|
global.myBundle = factory(); |
||||
|
}(this, function () { 'use strict'; |
||||
|
|
||||
|
var main = 42; |
||||
|
|
||||
|
return main; |
||||
|
|
||||
|
})); |
@ -0,0 +1,10 @@ |
|||||
|
var factory = function () { |
||||
|
function Unused () {} |
||||
|
Unused.prototype = {}; |
||||
|
|
||||
|
return Unused; |
||||
|
}; |
||||
|
|
||||
|
var Unused = factory(); |
||||
|
|
||||
|
export default 42; |
@ -0,0 +1,6 @@ |
|||||
|
module.exports = { |
||||
|
description: 'excludes functions that are known to be pure', |
||||
|
options: { |
||||
|
moduleName: 'myBundle' |
||||
|
} |
||||
|
}; |
@ -0,0 +1,7 @@ |
|||||
|
define(function () { 'use strict'; |
||||
|
|
||||
|
var main = 42; |
||||
|
|
||||
|
return main; |
||||
|
|
||||
|
}); |
@ -0,0 +1,5 @@ |
|||||
|
'use strict'; |
||||
|
|
||||
|
var main = 42; |
||||
|
|
||||
|
module.exports = main; |
@ -0,0 +1,3 @@ |
|||||
|
var main = 42; |
||||
|
|
||||
|
export default main; |
@ -0,0 +1,7 @@ |
|||||
|
var myBundle = (function () { 'use strict'; |
||||
|
|
||||
|
var main = 42; |
||||
|
|
||||
|
return main; |
||||
|
|
||||
|
})(); |
@ -0,0 +1,11 @@ |
|||||
|
(function (global, factory) { |
||||
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : |
||||
|
typeof define === 'function' && define.amd ? define(factory) : |
||||
|
global.myBundle = factory(); |
||||
|
}(this, function () { 'use strict'; |
||||
|
|
||||
|
var main = 42; |
||||
|
|
||||
|
return main; |
||||
|
|
||||
|
})); |
@ -0,0 +1,4 @@ |
|||||
|
var obj = { foo: 1, bar: 2 }; |
||||
|
var keys = Object.keys( obj ); |
||||
|
|
||||
|
export default 42; |
Loading…
Reference in new issue