babel-plugin-minify-mangle-names
Advanced tools
Comparing version 0.0.8 to 0.1.0
623
lib/index.js
@@ -5,4 +5,12 @@ "use strict"; | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
var Charset = require("./charset"); | ||
var ScopeTracker = require("./scope-tracker"); | ||
var isLabelIdentifier = require("./is-label-identifier"); | ||
var bfsTraverseCreator = require("./bfs-traverse"); | ||
var fixupVarScoping = require("./fixup-var-scoping"); | ||
var _require = require("babel-helper-mark-eval-scopes"), | ||
@@ -13,8 +21,9 @@ markEvalScopes = _require.markEvalScopes, | ||
var PATH_RENAME_MARKER = Symbol("PATH_RENAME_MARKER"); | ||
var newIssueUrl = "https://github.com/babel/babili/issues/new"; | ||
module.exports = function (_ref) { | ||
var t = _ref.types, | ||
traverse = _ref.traverse; | ||
module.exports = function (babel) { | ||
var t = babel.types, | ||
traverse = babel.traverse; | ||
var bfsTraverse = bfsTraverseCreator(babel); | ||
var hop = Object.prototype.hasOwnProperty; | ||
@@ -24,13 +33,13 @@ | ||
function Mangler(charset, program) { | ||
var _ref2 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, | ||
_ref2$blacklist = _ref2.blacklist, | ||
blacklist = _ref2$blacklist === undefined ? {} : _ref2$blacklist, | ||
_ref2$keepFnName = _ref2.keepFnName, | ||
keepFnName = _ref2$keepFnName === undefined ? false : _ref2$keepFnName, | ||
_ref2$eval = _ref2.eval, | ||
_eval = _ref2$eval === undefined ? false : _ref2$eval, | ||
_ref2$topLevel = _ref2.topLevel, | ||
topLevel = _ref2$topLevel === undefined ? false : _ref2$topLevel, | ||
_ref2$keepClassName = _ref2.keepClassName, | ||
keepClassName = _ref2$keepClassName === undefined ? false : _ref2$keepClassName; | ||
var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, | ||
_ref$blacklist = _ref.blacklist, | ||
blacklist = _ref$blacklist === undefined ? {} : _ref$blacklist, | ||
_ref$keepFnName = _ref.keepFnName, | ||
keepFnName = _ref$keepFnName === undefined ? false : _ref$keepFnName, | ||
_ref$keepClassName = _ref.keepClassName, | ||
keepClassName = _ref$keepClassName === undefined ? false : _ref$keepClassName, | ||
_ref$eval = _ref.eval, | ||
_eval = _ref$eval === undefined ? false : _ref$eval, | ||
_ref$topLevel = _ref.topLevel, | ||
topLevel = _ref$topLevel === undefined ? false : _ref$topLevel; | ||
@@ -41,29 +50,37 @@ _classCallCheck(this, Mangler); | ||
this.program = program; | ||
// user passed options | ||
this.blacklist = toObject(blacklist); | ||
this.keepFnName = keepFnName; | ||
this.keepClassName = keepClassName; | ||
this.topLevel = topLevel; | ||
this.eval = _eval; | ||
this.topLevel = topLevel; | ||
this.unsafeScopes = new Set(); | ||
// tracking | ||
this.visitedScopes = new Set(); | ||
this.referencesToUpdate = new Map(); | ||
this.scopeTracker = new ScopeTracker(); | ||
this.renamedNodes = new Set(); | ||
} | ||
/** | ||
* Run the mangler | ||
*/ | ||
_createClass(Mangler, [{ | ||
key: "run", | ||
value: function run() { | ||
this.cleanup(); | ||
this.crawlScope(); | ||
this.collect(); | ||
this.fixup(); | ||
this.charset.sort(); | ||
this.mangle(); | ||
} | ||
/** | ||
* Tells if a variable name is blacklisted | ||
* @param {String} name | ||
*/ | ||
}, { | ||
key: "cleanup", | ||
value: function cleanup() { | ||
traverse.clearCache(); | ||
this.program.scope.crawl(); | ||
} | ||
}, { | ||
key: "isBlacklist", | ||
@@ -73,15 +90,59 @@ value: function isBlacklist(name) { | ||
} | ||
/** | ||
* Clears traverse cache and recrawls the AST | ||
* | ||
* to recompute the bindings, references, other scope information | ||
* and paths because the other transformations in the same pipeline | ||
* (other plugins and presets) changes the AST and does NOT update | ||
* the scope objects | ||
*/ | ||
}, { | ||
key: "markUnsafeScopes", | ||
value: function markUnsafeScopes(scope) { | ||
var evalScope = scope; | ||
do { | ||
this.unsafeScopes.add(evalScope); | ||
} while (evalScope = evalScope.parent); | ||
key: "crawlScope", | ||
value: function crawlScope() { | ||
traverse.clearCache(); | ||
this.program.scope.crawl(); | ||
} | ||
/** | ||
* Re-crawling comes with a side-effect that let->var conversion | ||
* reverts the update of the binding information (block to fn scope). | ||
* This function takes care of it by updating it again. | ||
* | ||
* TODO: This is unnecessary work and needs to be fixed in babel. | ||
* https://github.com/babel/babel/issues/4818 | ||
* | ||
* When this is removed, remember to remove fixup's dependency in | ||
* ScopeTracker | ||
*/ | ||
}, { | ||
key: "fixup", | ||
value: function fixup() { | ||
fixupVarScoping(this); | ||
} | ||
/** | ||
* A single pass through the AST to collect info for | ||
* | ||
* 1. Scope Tracker | ||
* 2. Unsafe Scopes (direct eval scopes) | ||
* 3. Charset considerations for better gzip compression | ||
* | ||
* Traversed in the same fashion(BFS) the mangling is done | ||
*/ | ||
}, { | ||
key: "collect", | ||
value: function collect() { | ||
var mangler = this; | ||
var scopeTracker = mangler.scopeTracker; | ||
scopeTracker.addScope(this.program.scope); | ||
/** | ||
* Same usage as in DCE, whichever runs first | ||
*/ | ||
if (!isEvalScopesMarked(mangler.program.scope)) { | ||
@@ -91,32 +152,191 @@ markEvalScopes(mangler.program); | ||
if (this.charset.shouldConsider) { | ||
var collectVisitor = { | ||
Identifier(path) { | ||
var node = path.node; | ||
/** | ||
* The visitors to be used in traversal. | ||
* | ||
* Note: BFS traversal supports only the `enter` handlers, `exit` | ||
* handlers are simply dropped without Errors | ||
* | ||
* Collects items defined in the ScopeTracker | ||
*/ | ||
var collectVisitor = { | ||
Scopable(_ref2) { | ||
var scope = _ref2.scope; | ||
scopeTracker.addScope(scope); | ||
if (path.parentPath.isMemberExpression({ property: node }) || path.parentPath.isObjectProperty({ key: node })) { | ||
mangler.charset.consider(node.name); | ||
// Collect bindings defined in the scope | ||
Object.keys(scope.bindings).forEach(function (name) { | ||
scopeTracker.addBinding(scope.bindings[name]); | ||
}); | ||
}, | ||
/** | ||
* This is necessary because, in Babel, the scope.references | ||
* does NOT contain the references in that scope. Only the program | ||
* scope (top most level) contains all the references. | ||
* | ||
* We collect the references in a fashion where all the scopes between | ||
* and including the referenced scope and scope where it is declared | ||
* is considered as scope referencing that identifier | ||
*/ | ||
ReferencedIdentifier(path) { | ||
if (isLabelIdentifier(path)) return; | ||
var scope = path.scope, | ||
name = path.node.name; | ||
var binding = scope.getBinding(name); | ||
if (!binding) { | ||
// Do not collect globals as they are already available via | ||
// babel's API | ||
if (scope.hasGlobal(name)) return; | ||
// This should NOT happen ultimately. Panic if this code block is | ||
// reached | ||
throw new Error("Binding not found for ReferencedIdentifier. " + name + "Please report this at " + newIssueUrl); | ||
} else { | ||
// Add it to our scope tracker if everything is fine | ||
scopeTracker.addReference(scope, binding, name); | ||
} | ||
}, | ||
/** | ||
* This is useful to detect binding ids and add them to the | ||
* scopeTracker's bindings | ||
*/ | ||
BindingIdentifier(path) { | ||
if (isLabelIdentifier(path)) return; | ||
var scope = path.scope, | ||
name = path.node.name; | ||
var binding = scope.getBinding(name); | ||
if (!binding) { | ||
// ignore the globals as it's available via Babel's API | ||
if (scope.hasGlobal(name)) return; | ||
// Ignore the NamedExports as they should NOT be mangled | ||
if (path.parentPath.isExportSpecifier() && path.parentKey === "exported") { | ||
return; | ||
} | ||
}, | ||
Literal(_ref3) { | ||
var node = _ref3.node; | ||
mangler.charset.consider(String(node.value)); | ||
// This should NOT happen ultimately. Panic if this code is reached | ||
throw new Error("Binding not found for BindingIdentifier. " + name + "Please report this at " + newIssueUrl); | ||
} | ||
/** | ||
* Detect constant violations | ||
* | ||
* If it's a constant violation, then add the Identifier Path as | ||
* a Reference instead of Binding - This is because the ScopeTracker | ||
* tracks these Re-declaration and mutation of variables as References | ||
* as it is simple to rename them | ||
*/ | ||
if (binding.identifier === path.node) { | ||
scopeTracker.addBinding(binding); | ||
} else { | ||
// constant violation | ||
scopeTracker.addReference(scope, binding, name); | ||
} | ||
} | ||
}; | ||
/** | ||
* These visitors are for collecting the Characters used in the program | ||
* to measure the frequency and generate variable names for mangling so | ||
* as to improve the gzip compression - as gzip likes repetition | ||
*/ | ||
if (this.charset.shouldConsider) { | ||
collectVisitor.Identifier = function Identifer(path) { | ||
var node = path.node; | ||
// We don't mangle properties, so we collect them as they contribute | ||
// to the frequency of characters | ||
if (path.parentPath.isMemberExpression({ property: node }) || path.parentPath.isObjectProperty({ key: node })) { | ||
mangler.charset.consider(node.name); | ||
} | ||
}; | ||
collectVisitor.Literal = function Literal(_ref3) { | ||
var node = _ref3.node; | ||
mangler.program.traverse(collectVisitor); | ||
mangler.charset.consider(String(node.value)); | ||
}; | ||
} | ||
// Traverse the AST | ||
bfsTraverse(mangler.program, collectVisitor); | ||
} | ||
/** | ||
* Tells if a binding is exported as a NamedExport - so as to NOT mangle | ||
* | ||
* Babel treats NamedExports as a binding referenced by this NamedExport decl | ||
* @param {Binding} binding | ||
*/ | ||
}, { | ||
key: "isExportedWithName", | ||
value: function isExportedWithName(binding) { | ||
// short circuit | ||
if (!this.topLevel) { | ||
return false; | ||
} | ||
var refs = binding.referencePaths; | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = refs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var ref = _step.value; | ||
if (ref.isExportNamedDeclaration()) { | ||
return true; | ||
} | ||
} | ||
// default | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
/** | ||
* Mangle the scope | ||
* @param {Scope} scope | ||
*/ | ||
}, { | ||
key: "mangleScope", | ||
value: function mangleScope(scope) { | ||
var mangler = this; | ||
var scopeTracker = mangler.scopeTracker; | ||
// Unsafe Scope | ||
if (!mangler.eval && hasEval(scope)) return; | ||
// Already visited | ||
// This is because for a function, in Babel, the function and | ||
// the function body's BlockStatement has the same scope, and will | ||
// be visited twice by the Scopable handler, and we want to mangle | ||
// it only once | ||
if (mangler.visitedScopes.has(scope)) return; | ||
mangler.visitedScopes.add(scope); | ||
// Helpers to generate names | ||
var i = 0; | ||
@@ -126,42 +346,36 @@ function getNext() { | ||
} | ||
function resetNext() { | ||
i = 0; | ||
} | ||
// This is useful when we have vars of single character | ||
// => var a, ...z, A, ...Z, $, _; | ||
// to | ||
// => var aa, a, b ,c; | ||
// instead of | ||
// => var aa, ab, ...; | ||
// TODO: | ||
// Re-enable after enabling this feature | ||
// This doesn't work right now as we are concentrating | ||
// on performance improvements | ||
// function resetNext() { | ||
// i = 0; | ||
// } | ||
var bindings = scopeTracker.bindings.get(scope); | ||
var names = [].concat(_toConsumableArray(bindings.keys())); | ||
var bindings = scope.getAllBindings(); | ||
var names = Object.keys(bindings); | ||
/** | ||
* 1. Iterate through the list of BindingIdentifiers | ||
* 2. Rename each of them in-place | ||
* 3. Update the scope tree. | ||
*/ | ||
for (var _i = 0; _i < names.length; _i++) { | ||
var oldName = names[_i]; | ||
var binding = bindings[oldName]; | ||
var binding = bindings.get(oldName); | ||
// Names which should NOT be mangled | ||
if ( | ||
// arguments | ||
oldName === "arguments" | ||
// other scope bindings | ||
|| !scope.hasOwnBinding(oldName) | ||
// arguments - for non-strict mode | ||
oldName === "arguments" || | ||
// labels | ||
|| binding.path.isLabeledStatement() | ||
binding.path.isLabeledStatement() || | ||
// ClassDeclaration has binding in two scopes | ||
// 1. The scope in which it is declared | ||
// 2. The class's own scope | ||
// - https://github.com/babel/babel/issues/5156 | ||
|| binding.path.isClassDeclaration() && binding.path === scope.path | ||
binding.path.isClassDeclaration() && binding.path === scope.path || | ||
// blacklisted | ||
|| mangler.isBlacklist(oldName) | ||
mangler.isBlacklist(oldName) || ( | ||
// function names | ||
|| (mangler.keepFnName ? isFunction(binding.path) : false) | ||
mangler.keepFnName ? isFunction(binding.path) : false) || ( | ||
// class names | ||
|| (mangler.keepClassName ? isClass(binding.path) : false)) { | ||
mangler.keepClassName ? isClass(binding.path) : false) || | ||
// named export | ||
mangler.isExportedWithName(binding)) { | ||
continue; | ||
@@ -173,10 +387,18 @@ } | ||
next = getNext(); | ||
} while (!t.isValidIdentifier(next) || hop.call(bindings, next) || scope.hasGlobal(next) || scope.hasReference(next)); | ||
} while (!t.isValidIdentifier(next) || scopeTracker.hasBinding(scope, next) || scope.hasGlobal(next) || scopeTracker.hasReference(scope, next) || !scopeTracker.canUseInReferencedScopes(binding, next)); | ||
// TODO: | ||
// re-enable this - check above | ||
// resetNext(); | ||
mangler.rename(scope, oldName, 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); | ||
} | ||
} | ||
/** | ||
* The mangle function that traverses through all the Scopes in a BFS | ||
* fashion - calls mangleScope | ||
*/ | ||
}, { | ||
@@ -187,49 +409,57 @@ key: "mangle", | ||
if (mangler.topLevel) { | ||
mangler.mangleScope(mangler.program.scope); | ||
} | ||
this.program.traverse({ | ||
bfsTraverse(this.program, { | ||
Scopable(path) { | ||
mangler.mangleScope(path.scope); | ||
if (!path.isProgram() || mangler.topLevel) mangler.mangleScope(path.scope); | ||
} | ||
}); | ||
} | ||
/** | ||
* Given a NodePath, collects all the Identifiers which are BindingIdentifiers | ||
* and replaces them with the new name | ||
* | ||
* For example, | ||
* var a = 1, { b } = c; // a and b are BindingIdentifiers | ||
* | ||
* @param {NodePath} path | ||
* @param {String} oldName | ||
* @param {String} newName | ||
* @param {Function} predicate | ||
*/ | ||
}, { | ||
key: "rename", | ||
value: function rename(scope, oldName, newName) { | ||
var binding = scope.getBinding(oldName); | ||
key: "renameBindingIds", | ||
value: function renameBindingIds(path, oldName, newName) { | ||
var predicate = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : function () { | ||
return true; | ||
}; | ||
// rename at the declaration level | ||
var bindingPaths = binding.path.getBindingIdentifierPaths(true, false); | ||
// we traverse through all bindingPaths because, | ||
// there is no binding.identifierPath in babel | ||
for (var name in bindingPaths) { | ||
var bindingIds = path.getBindingIdentifierPaths(true, false); | ||
for (var name in bindingIds) { | ||
if (name !== oldName) continue; | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
var _iteratorNormalCompletion2 = true; | ||
var _didIteratorError2 = false; | ||
var _iteratorError2 = undefined; | ||
try { | ||
for (var _iterator = bindingPaths[name][Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var idPath = _step.value; | ||
for (var _iterator2 = bindingIds[name][Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | ||
var idPath = _step2.value; | ||
if (binding.identifier === idPath.node) { | ||
if (predicate(idPath)) { | ||
this.renamedNodes.add(idPath.node); | ||
idPath.replaceWith(t.identifier(newName)); | ||
binding.identifier = idPath.node; | ||
idPath[PATH_RENAME_MARKER] = true; | ||
this.renamedNodes.add(idPath.node); | ||
} | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
_didIteratorError2 = true; | ||
_iteratorError2 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return) { | ||
_iterator.return(); | ||
if (!_iteratorNormalCompletion2 && _iterator2.return) { | ||
_iterator2.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
if (_didIteratorError2) { | ||
throw _iteratorError2; | ||
} | ||
@@ -239,27 +469,42 @@ } | ||
} | ||
} | ||
var bindings = scope.bindings; | ||
/** | ||
* The Renamer: | ||
* Renames the following for one Binding in a Scope | ||
* | ||
* 1. Binding in that Scope | ||
* 2. All the Binding's constant violations | ||
* 3. All its References | ||
* 4. Updates mangler.scopeTracker | ||
* 5. Updates Babel's Scope tracking | ||
* | ||
* @param {Scope} scope | ||
* @param {Binding} binding | ||
* @param {String} oldName | ||
* @param {String} newName | ||
*/ | ||
bindings[newName] = binding; | ||
delete bindings[oldName]; | ||
}, { | ||
key: "rename", | ||
value: function rename(scope, binding, oldName, newName) { | ||
var mangler = this; | ||
var scopeTracker = mangler.scopeTracker; | ||
// update all constant violations & redeclarations | ||
var violations = binding.constantViolations; | ||
// rename at the declaration level | ||
var _loop = function _loop(i) { | ||
if (violations[i].isLabeledStatement()) return "continue"; | ||
this.renameBindingIds(binding.path, oldName, newName, function (idPath) { | ||
return idPath.node === binding.identifier; | ||
}); | ||
var bindings = violations[i].getBindingIdentifierPaths(); | ||
Object.keys(bindings).map(function (b) { | ||
if (b === oldName && !bindings[b][PATH_RENAME_MARKER]) { | ||
bindings[b].replaceWith(t.identifier(newName)); | ||
bindings[b][PATH_RENAME_MARKER] = true; | ||
} | ||
}); | ||
}; | ||
// update mangler's ScopeTracker | ||
scopeTracker.renameBinding(scope, oldName, newName); | ||
// update all constant violations | ||
var violations = binding.constantViolations; | ||
for (var i = 0; i < violations.length; i++) { | ||
var _ret = _loop(i); | ||
if (violations[i].isLabeledStatement()) continue; | ||
if (_ret === "continue") continue; | ||
this.renameBindingIds(violations[i], oldName, newName); | ||
scopeTracker.updateReference(violations[i].scope, binding, oldName, newName); | ||
} | ||
@@ -269,8 +514,8 @@ | ||
var refs = binding.referencePaths; | ||
for (var i = 0; i < refs.length; i++) { | ||
var path = refs[i]; | ||
if (path[PATH_RENAME_MARKER]) continue; | ||
for (var _i2 = 0; _i2 < refs.length; _i2++) { | ||
var path = refs[_i2]; | ||
var node = path.node; | ||
if (!path.isIdentifier()) { | ||
@@ -287,11 +532,38 @@ // Ideally, this should not happen | ||
ReferencedIdentifier(refPath) { | ||
if (refPath.node.name === oldName && refPath.scope === scope && !refPath[PATH_RENAME_MARKER]) { | ||
refPath.node.name = newName; | ||
if (refPath.node.name !== oldName) { | ||
return; | ||
} | ||
var actualBinding = refPath.scope.getBinding(oldName); | ||
if (actualBinding !== binding) { | ||
return; | ||
} | ||
mangler.renamedNodes.add(refPath.node); | ||
refPath.replaceWith(t.identifier(newName)); | ||
mangler.renamedNodes.add(refPath.node); | ||
scopeTracker.updateReference(refPath.scope, binding, oldName, newName); | ||
} | ||
}); | ||
} else if (!isLabelIdentifier(path)) { | ||
node.name = newName; | ||
if (path.node.name === oldName) { | ||
mangler.renamedNodes.add(path.node); | ||
path.replaceWith(t.identifier(newName)); | ||
mangler.renamedNodes.add(path.node); | ||
scopeTracker.updateReference(path.scope, binding, oldName, newName); | ||
} else if (mangler.renamedNodes.has(path.node)) { | ||
// already renamed, | ||
// just update the references | ||
scopeTracker.updateReference(path.scope, binding, oldName, newName); | ||
} else { | ||
throw new Error(`Unexpected Rename Error: ` + `Trying to replace ${node.name}: from ${oldName} to ${newName}` + `Please report it at ${newIssueUrl}`); | ||
} | ||
} | ||
// else label identifier - silently ignore | ||
} | ||
// update babel's scope tracking | ||
var bindings = scope.bindings; | ||
bindings[newName] = binding; | ||
delete bindings[oldName]; | ||
} | ||
@@ -306,13 +578,18 @@ }]); | ||
visitor: { | ||
Program(path) { | ||
// If the source code is small then we're going to assume that the user | ||
// is running on this on single files before bundling. Therefore we | ||
// need to achieve as much determinisim and we will not do any frequency | ||
// sorting on the character set. Currently the number is pretty arbitrary. | ||
var shouldConsiderSource = path.getSource().length > 70000; | ||
/** | ||
* Mangler is run as a single pass. It's the same pattern as used in DCE | ||
*/ | ||
Program: { | ||
exit(path) { | ||
// If the source code is small then we're going to assume that the user | ||
// is running on this on single files before bundling. Therefore we | ||
// need to achieve as much determinisim and we will not do any frequency | ||
// sorting on the character set. Currently the number is pretty arbitrary. | ||
var shouldConsiderSource = path.getSource().length > 70000; | ||
var charset = new Charset(shouldConsiderSource); | ||
var charset = new Charset(shouldConsiderSource); | ||
var mangler = new Mangler(charset, path, this.opts); | ||
mangler.run(); | ||
var mangler = new Mangler(charset, path, this.opts); | ||
mangler.run(); | ||
} | ||
} | ||
@@ -323,71 +600,3 @@ } | ||
var CHARSET = ("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ$_").split(""); | ||
var Charset = function () { | ||
function Charset(shouldConsider) { | ||
var _this = this; | ||
_classCallCheck(this, Charset); | ||
this.shouldConsider = shouldConsider; | ||
this.chars = CHARSET.slice(); | ||
this.frequency = {}; | ||
this.chars.forEach(function (c) { | ||
_this.frequency[c] = 0; | ||
}); | ||
this.finalized = false; | ||
} | ||
_createClass(Charset, [{ | ||
key: "consider", | ||
value: function consider(str) { | ||
var _this2 = this; | ||
if (!this.shouldConsider) { | ||
return; | ||
} | ||
str.split("").forEach(function (c) { | ||
if (_this2.frequency[c] != null) { | ||
_this2.frequency[c]++; | ||
} | ||
}); | ||
} | ||
}, { | ||
key: "sort", | ||
value: function sort() { | ||
var _this3 = this; | ||
if (this.shouldConsider) { | ||
this.chars = this.chars.sort(function (a, b) { | ||
return _this3.frequency[b] - _this3.frequency[a]; | ||
}); | ||
} | ||
this.finalized = true; | ||
} | ||
}, { | ||
key: "getIdentifier", | ||
value: function getIdentifier(num) { | ||
if (!this.finalized) { | ||
throw new Error("Should sort first"); | ||
} | ||
var ret = ""; | ||
num++; | ||
do { | ||
num--; | ||
ret += this.chars[num % this.chars.length]; | ||
num = Math.floor(num / this.chars.length); | ||
} while (num > 0); | ||
return ret; | ||
} | ||
}]); | ||
return Charset; | ||
}(); | ||
// convert value to object | ||
function toObject(value) { | ||
@@ -413,8 +622,2 @@ if (!Array.isArray(value)) { | ||
return path.isClassExpression() || path.isClassDeclaration(); | ||
} | ||
function isLabelIdentifier(path) { | ||
var node = path.node; | ||
return path.parentPath.isLabeledStatement({ label: node }) || path.parentPath.isBreakStatement({ label: node }) || path.parentPath.isContinueStatement({ label: node }); | ||
} |
{ | ||
"name": "babel-plugin-minify-mangle-names", | ||
"version": "0.0.8", | ||
"version": "0.1.0", | ||
"description": "", | ||
@@ -15,5 +15,5 @@ "homepage": "https://github.com/babel/babili#readme", | ||
"dependencies": { | ||
"babel-helper-mark-eval-scopes": "^0.0.3" | ||
"babel-helper-mark-eval-scopes": "^0.1.0" | ||
}, | ||
"devDependencies": {} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
38854
10
963
1
+ Addedbabel-helper-mark-eval-scopes@0.1.1(transitive)
- Removedbabel-helper-mark-eval-scopes@0.0.3(transitive)