Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: split mangleScope logic to smaller functions #853

Merged
merged 1 commit into from
May 16, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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