Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reuse removed vars in mangler (#395)
* Reuse removed vars in mangler ResetNext identifier only when reuse is true Fix tests - add keepClassName Reuse vars as default I dont know why it works - #326 Extract tracker to a separate file, Add topLevel Option * BFS traverse * Fix scope tracking * Fix tests * Fix mangle blacklist tests * Fix formatting * Remove unnecessary preset tests * Add JSDoc Comments and update Error messages * Remove duplicate tests * Fix Error message
- Loading branch information
Showing
9 changed files
with
1,116 additions
and
604 deletions.
There are no files selected for viewing
797 changes: 356 additions & 441 deletions
797
packages/babel-plugin-minify-mangle-names/__tests__/mangle-names-test.js
Large diffs are not rendered by default.
Oops, something went wrong.
48 changes: 48 additions & 0 deletions
48
packages/babel-plugin-minify-mangle-names/src/bfs-traverse.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
"use strict"; | ||
|
||
module.exports = function bfsTraverseCreator({ types: t, traverse }) { | ||
function getFields(path) { | ||
return t.VISITOR_KEYS[path.type]; | ||
} | ||
|
||
return function bfsTraverse(path, _visitor) { | ||
if (!path.node) { | ||
throw new Error("Not a valid path"); | ||
} | ||
const visitor = traverse.explode(_visitor); | ||
|
||
const queue = [path]; | ||
let current; | ||
|
||
while (queue.length > 0) { | ||
current = queue.shift(); | ||
|
||
// call | ||
if ( | ||
visitor && | ||
visitor[current.type] && | ||
Array.isArray(visitor[current.type].enter) | ||
) { | ||
const fns = visitor[current.type].enter; | ||
for (const fn of fns) { | ||
if (typeof fn === "function") fn(current); | ||
} | ||
} | ||
|
||
const fields = getFields(current); | ||
|
||
for (const field of fields) { | ||
const child = current.get(field); | ||
|
||
if (Array.isArray(child)) { | ||
// visit container left to right | ||
for (const c of child) { | ||
if (c.node) queue.push(c); | ||
} | ||
} else { | ||
if (child.node) queue.push(child); | ||
} | ||
} | ||
} | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
"use strict"; | ||
|
||
const CHARSET = ("abcdefghijklmnopqrstuvwxyz" + | ||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ$_").split(""); | ||
|
||
module.exports = class Charset { | ||
constructor(shouldConsider) { | ||
this.shouldConsider = shouldConsider; | ||
this.chars = CHARSET.slice(); | ||
this.frequency = {}; | ||
this.chars.forEach(c => { | ||
this.frequency[c] = 0; | ||
}); | ||
this.finalized = false; | ||
} | ||
|
||
consider(str) { | ||
if (!this.shouldConsider) { | ||
return; | ||
} | ||
|
||
str.split("").forEach(c => { | ||
if (this.frequency[c] != null) { | ||
this.frequency[c]++; | ||
} | ||
}); | ||
} | ||
|
||
sort() { | ||
if (this.shouldConsider) { | ||
this.chars = this.chars.sort( | ||
(a, b) => this.frequency[b] - this.frequency[a] | ||
); | ||
} | ||
|
||
this.finalized = true; | ||
} | ||
|
||
getIdentifier(num) { | ||
if (!this.finalized) { | ||
throw new Error("Should sort first"); | ||
} | ||
|
||
let ret = ""; | ||
num++; | ||
do { | ||
num--; | ||
ret += this.chars[num % this.chars.length]; | ||
num = Math.floor(num / this.chars.length); | ||
} while (num > 0); | ||
return ret; | ||
} | ||
}; |
28 changes: 28 additions & 0 deletions
28
packages/babel-plugin-minify-mangle-names/src/counted-set.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// Set that counts | ||
module.exports = class CountedSet { | ||
constructor() { | ||
// because you can't simply extend Builtins yet | ||
this.map = new Map(); | ||
} | ||
keys() { | ||
return [...this.map.keys()]; | ||
} | ||
has(value) { | ||
return this.map.has(value); | ||
} | ||
add(value) { | ||
if (!this.has(value)) { | ||
this.map.set(value, 0); | ||
} | ||
this.map.set(value, this.map.get(value) + 1); | ||
} | ||
delete(value) { | ||
if (!this.has(value)) return; | ||
const count = this.map.get(value); | ||
if (count <= 1) { | ||
this.map.delete(value); | ||
} else { | ||
this.map.set(value, count - 1); | ||
} | ||
} | ||
}; |
55 changes: 55 additions & 0 deletions
55
packages/babel-plugin-minify-mangle-names/src/fixup-var-scoping.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// this fixes a bug where converting let to var | ||
// doesn't change the binding's scope to function scope | ||
// https://github.com/babel/babel/issues/4818 | ||
module.exports = function(mangler) { | ||
mangler.program.traverse({ | ||
VariableDeclaration(path) { | ||
if (path.node.kind !== "var") { | ||
return; | ||
} | ||
const fnScope = path.scope.getFunctionParent(); | ||
const bindingIds = path.getOuterBindingIdentifierPaths(); | ||
|
||
for (const name in bindingIds) { | ||
const binding = path.scope.getBinding(name); | ||
|
||
// var isn't hoisted to fnScope | ||
if (binding.scope !== fnScope) { | ||
const existingBinding = fnScope.bindings[name]; | ||
// make sure we are clear that the fnScope doesn't already have | ||
// an existing binding | ||
if (!existingBinding) { | ||
// move binding to the function scope | ||
|
||
// update our scopeTracker first before | ||
// we mutate the scope | ||
mangler.scopeTracker.moveBinding(binding, fnScope); | ||
|
||
fnScope.bindings[name] = binding; | ||
binding.scope = fnScope; | ||
delete binding.scope.bindings[name]; | ||
} else { | ||
// we need a new binding that's valid in both the scopes | ||
// binding.scope and fnScope | ||
const newName = fnScope.generateUid( | ||
binding.scope.generateUid(name) | ||
); | ||
|
||
// rename binding in the original scope | ||
mangler.rename(binding.scope, binding, name, newName); | ||
|
||
// move binding to fnScope as newName | ||
|
||
// update our scopeTracker first before | ||
// we mutate the scope | ||
mangler.scopeTracker.moveBinding(binding, fnScope); | ||
|
||
fnScope.bindings[newName] = binding; | ||
binding.scope = fnScope; | ||
delete binding.scope.bindings[newName]; | ||
} | ||
} | ||
} | ||
} | ||
}); | ||
}; |
Oops, something went wrong.