|
@ -29,6 +29,8 @@ export default class Statement { |
|
|
this.dependsOn = blank(); |
|
|
this.dependsOn = blank(); |
|
|
this.stronglyDependsOn = blank(); |
|
|
this.stronglyDependsOn = blank(); |
|
|
|
|
|
|
|
|
|
|
|
this.reassigns = blank(); |
|
|
|
|
|
|
|
|
this.isIncluded = false; |
|
|
this.isIncluded = false; |
|
|
|
|
|
|
|
|
this.isImportDeclaration = node.type === 'ImportDeclaration'; |
|
|
this.isImportDeclaration = node.type === 'ImportDeclaration'; |
|
@ -46,29 +48,23 @@ export default class Statement { |
|
|
let newScope; |
|
|
let newScope; |
|
|
|
|
|
|
|
|
switch ( node.type ) { |
|
|
switch ( node.type ) { |
|
|
case 'FunctionExpression': |
|
|
|
|
|
case 'FunctionDeclaration': |
|
|
case 'FunctionDeclaration': |
|
|
case 'ArrowFunctionExpression': |
|
|
scope.addDeclaration( node.id.name, node, false ); |
|
|
if ( node.type === 'FunctionDeclaration' ) { |
|
|
|
|
|
scope.addDeclaration( node.id.name, node, false ); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
newScope = new Scope({ |
|
|
|
|
|
parent: scope, |
|
|
|
|
|
params: node.params, // TODO rest params?
|
|
|
|
|
|
block: false |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// named function expressions - the name is considered
|
|
|
|
|
|
// part of the function's scope
|
|
|
|
|
|
if ( node.type === 'FunctionExpression' && node.id ) { |
|
|
|
|
|
newScope.addDeclaration( node.id.name, node, false ); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case 'BlockStatement': |
|
|
case 'BlockStatement': |
|
|
if ( !/Function/.test( parent.type ) ) { |
|
|
if ( parent && /Function/.test( parent.type ) ) { |
|
|
|
|
|
newScope = new Scope({ |
|
|
|
|
|
parent: scope, |
|
|
|
|
|
block: false, |
|
|
|
|
|
params: parent.params |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// named function expressions - the name is considered
|
|
|
|
|
|
// part of the function's scope
|
|
|
|
|
|
if ( parent.type === 'FunctionExpression' && parent.id ) { |
|
|
|
|
|
newScope.addDeclaration( parent.id.name, parent, false ); |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
newScope = new Scope({ |
|
|
newScope = new Scope({ |
|
|
parent: scope, |
|
|
parent: scope, |
|
|
block: true |
|
|
block: true |
|
@ -133,27 +129,19 @@ export default class Statement { |
|
|
if ( !this.isImportDeclaration ) { |
|
|
if ( !this.isImportDeclaration ) { |
|
|
walk( this.node, { |
|
|
walk( this.node, { |
|
|
enter: ( node, parent ) => { |
|
|
enter: ( node, parent ) => { |
|
|
if ( node._scope ) { |
|
|
if ( isFunctionDeclaration( node, parent ) ) writeDepth += 1; |
|
|
if ( !scope.isBlockScope ) { |
|
|
if ( /Function/.test( node.type ) && !isIife( node, parent ) ) readDepth += 1; |
|
|
if ( !isIife( node, parent ) ) readDepth += 1; |
|
|
|
|
|
if ( isFunctionDeclaration( node, parent ) ) writeDepth += 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
scope = node._scope; |
|
|
if ( node._scope ) scope = node._scope; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.checkForReads( scope, node, parent, !readDepth ); |
|
|
this.checkForReads( scope, node, parent, !readDepth ); |
|
|
this.checkForWrites( scope, node, writeDepth ); |
|
|
this.checkForWrites( scope, node, writeDepth ); |
|
|
}, |
|
|
}, |
|
|
leave: ( node, parent ) => { |
|
|
leave: ( node, parent ) => { |
|
|
if ( node._scope ) { |
|
|
if ( isFunctionDeclaration( node, parent ) ) writeDepth -= 1; |
|
|
if ( !scope.isBlockScope ) { |
|
|
if ( /Function/.test( node.type ) && !isIife( node, parent ) ) readDepth -= 1; |
|
|
if ( !isIife( node, parent ) ) readDepth -= 1; |
|
|
|
|
|
if ( isFunctionDeclaration( node, parent ) ) writeDepth -= 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
scope = scope.parent; |
|
|
if ( node._scope ) scope = scope.parent; |
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
@ -226,6 +214,17 @@ export default class Statement { |
|
|
this.module.exports.default.isModified = true; |
|
|
this.module.exports.default.isModified = true; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// we track updates/reassignments to variables, to know whether we
|
|
|
|
|
|
// need to rewrite it later from `foo` to `exports.foo` to keep
|
|
|
|
|
|
// bindings live
|
|
|
|
|
|
if ( |
|
|
|
|
|
depth === 0 && |
|
|
|
|
|
writeDepth > 0 && |
|
|
|
|
|
!scope.contains( node.name ) |
|
|
|
|
|
) { |
|
|
|
|
|
this.reassigns[ node.name ] = true; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// we only care about writes that happen a) at the top level,
|
|
|
// we only care about writes that happen a) at the top level,
|
|
@ -348,11 +347,6 @@ export default class Statement { |
|
|
let newNames = blank(); |
|
|
let newNames = blank(); |
|
|
let hasReplacements; |
|
|
let hasReplacements; |
|
|
|
|
|
|
|
|
// special case = function foo ( foo ) {...}
|
|
|
|
|
|
if ( node.id && names[ node.id.name ] && scope.declarations[ node.id.name ] ) { |
|
|
|
|
|
magicString.overwrite( node.id.start, node.id.end, names[ node.id.name ] ); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
keys( names ).forEach( name => { |
|
|
keys( names ).forEach( name => { |
|
|
if ( !scope.declarations[ name ] ) { |
|
|
if ( !scope.declarations[ name ] ) { |
|
|
newNames[ name ] = names[ name ]; |
|
|
newNames[ name ] = names[ name ]; |
|
@ -393,6 +387,8 @@ export default class Statement { |
|
|
if ( parent.type === 'MemberExpression' && !parent.computed && node !== parent.object ) return; |
|
|
if ( parent.type === 'MemberExpression' && !parent.computed && node !== parent.object ) return; |
|
|
if ( parent.type === 'Property' && node !== parent.value ) return; |
|
|
if ( parent.type === 'Property' && node !== parent.value ) return; |
|
|
if ( parent.type === 'MethodDefinition' && node === parent.key ) return; |
|
|
if ( parent.type === 'MethodDefinition' && node === parent.key ) return; |
|
|
|
|
|
if ( parent.type === 'FunctionExpression' ) return; |
|
|
|
|
|
if ( /Function/.test( parent.type ) && ~parent.params.indexOf( node ) ) return; |
|
|
// TODO others...?
|
|
|
// TODO others...?
|
|
|
|
|
|
|
|
|
// all other identifiers should be overwritten
|
|
|
// all other identifiers should be overwritten
|
|
|