Skip to content

Commit

Permalink
refactor: split mangleScope logic to smaller functions (#853)
Browse files Browse the repository at this point in the history
  • Loading branch information
boopathi committed May 16, 2018
1 parent 1cb46b7 commit 7195fa9
Showing 1 changed file with 64 additions and 37 deletions.
101 changes: 64 additions & 37 deletions packages/babel-plugin-minify-mangle-names/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,54 @@ module.exports = babel => {
return false;
}

/**
* Tells if the name can be mangled in the current observed scope with
* the input binding
*
* @param {string} oldName the old name that needs to be mangled
* @param {Binding} binding Binding of the name
* @param {Scope} scope The current scope the mangler is run
*/
canMangle(oldName, binding, scope) {
const cannotMangle =
// arguments - for non-strict mode
oldName === "arguments" ||
// labels
binding.path.isLabeledStatement() ||
// ClassDeclaration has binding in two scopes
// 1. The scope in which it is declared
// 2. The class's own scope
(binding.path.isClassDeclaration() && binding.path === scope.path) ||
// excluded
this.isExcluded(oldName) ||
// function names
(this.keepFnName ? isFunction(binding.path) : false) ||
// class names
(this.keepClassName ? isClass(binding.path) : false) ||
// named export
this.isExportedWithName(binding);

return !cannotMangle;
}

/**
* Tells if the newName can be used as a valid name for the input binding
* in the input scope
*
* @param {string} newName the old name that needs to be mangled
* @param {Binding} binding Binding of the name that this new name will replace
* @param {Scope} scope The current scope the mangler is run
*/
isValidName(newName, binding, scope) {
return (
t.isValidIdentifier(newName) &&
!this.scopeTracker.hasBinding(scope, newName) &&
!scope.hasGlobal(newName) &&
!this.scopeTracker.hasReference(scope, newName) &&
this.scopeTracker.canUseInReferencedScopes(binding, newName)
);
}

/**
* Mangle the scope
* @param {Scope} scope
Expand Down Expand Up @@ -288,50 +336,29 @@ module.exports = babel => {
* 1. Iterate through the list of BindingIdentifiers
* 2. Rename each of them in-place
* 3. Update the scope tree.
*
* We cannot use a for..of loop over bindings.keys()
* because (2) we rename in place and update the bindings
* as we traverse through the keys
*/
for (let i = 0; i < names.length; i++) {
const oldName = names[i];
const binding = bindings.get(oldName);

// Names which should NOT be mangled
if (
// arguments - for non-strict mode
oldName === "arguments" ||
// labels
binding.path.isLabeledStatement() ||
// ClassDeclaration has binding in two scopes
// 1. The scope in which it is declared
// 2. The class's own scope
(binding.path.isClassDeclaration() && binding.path === scope.path) ||
// excluded
mangler.isExcluded(oldName) ||
// function names
(mangler.keepFnName ? isFunction(binding.path) : false) ||
// class names
(mangler.keepClassName ? isClass(binding.path) : false) ||
// named export
mangler.isExportedWithName(binding)
) {
continue;
if (mangler.canMangle(oldName, binding, scope)) {
let next;
do {
next = getNext();
} while (!mangler.isValidName(next, binding, scope));

// Reset so variables which are removed can be reused
resetNext();

// Once we detected a valid `next` Identifier which could be used,
// call the renamer
mangler.rename(scope, binding, oldName, next);
}

let next;
do {
next = getNext();
} while (
!t.isValidIdentifier(next) ||
scopeTracker.hasBinding(scope, next) ||
scope.hasGlobal(next) ||
scopeTracker.hasReference(scope, next) ||
!scopeTracker.canUseInReferencedScopes(binding, next)
);

// Reset so variables which are removed can be reused
resetNext();

// Once we detected a valid `next` Identifier which could be used,
// call the renamer
mangler.rename(scope, binding, oldName, next);
}
}

Expand Down

0 comments on commit 7195fa9

Please sign in to comment.