Remove modules from source

This commit is contained in:
Federico Grandi
2019-12-14 21:58:11 +01:00
parent f118062594
commit e5272e4c09
4269 changed files with 0 additions and 1074858 deletions

View File

@@ -1,22 +0,0 @@
Copyright (c) 2015-2016 Amjad Masad <amjad.masad@gmail.com>
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,79 +0,0 @@
# babel-plugin-minify-mangle-names
Context- and scope- aware variable renaming.
## Example
**In**
```javascript
var globalVariableName = 42;
function foo() {
var longLocalVariableName = 1;
if (longLocalVariableName) {
console.log(longLocalVariableName);
}
}
```
**Out**
```javascript
var globalVariableName = 42;
function foo() {
var a = 1;
if (a) {
console.log(a);
}
}
```
## Installation
```sh
npm install babel-plugin-minify-mangle-names --save-dev
```
## Usage
### Via `.babelrc` (Recommended)
**.babelrc**
```json
// without options
{
"plugins": ["minify-mangle-names"]
}
```
```json
// with options
{
"plugins": [
["minify-mangle-names", { "exclude": { "foo": true, "bar": true} }]
]
}
```
### Via CLI
```sh
babel --plugins minify-mangle-names script.js
```
### Via Node API
```javascript
require("@babel/core").transform("code", {
plugins: ["minify-mangle-names"]
});
```
## Options
+ `exclude` - A plain JS Object with keys as identifier names and values indicating whether to exclude (default: `{}`)
+ `eval` - mangle identifiers in scopes accessible by eval (default: `false`)
+ `keepFnName` - prevent mangler from altering function names. Useful for code depending on `fn.name` (default: `false`)
+ `topLevel` - mangle topLevel Identifiers (default: `false`)
+ `keepClassName` - prevent mangler from altering class names (default: `false`).

View File

@@ -1,105 +0,0 @@
"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;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = fns[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
const fn = _step.value;
if (typeof fn === "function") fn(current);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
const fields = getFields(current);
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = fields[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
const field = _step2.value;
const child = current.get(field);
if (Array.isArray(child)) {
// visit container left to right
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = child[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
const c = _step3.value;
if (c.node) queue.push(c);
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
} else {
if (child.node) queue.push(child);
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
};
};

View File

@@ -1,52 +0,0 @@
"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;
}
};

View File

@@ -1,37 +0,0 @@
"use strict";
// 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);
}
}
};

View File

@@ -1,50 +0,0 @@
"use strict";
// 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() || path.scope.getProgramParent();
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];
}
}
}
}
});
};

View File

@@ -1,589 +0,0 @@
"use strict";
const Charset = require("./charset");
const ScopeTracker = require("./scope-tracker");
const isLabelIdentifier = require("./is-label-identifier");
const bfsTraverseCreator = require("./bfs-traverse");
const fixupVarScoping = require("./fixup-var-scoping");
const _require = require("babel-helper-mark-eval-scopes"),
markEvalScopes = _require.markEvalScopes,
isEvalScopesMarked = _require.isMarked,
hasEval = _require.hasEval;
const newIssueUrl = "https://github.com/babel/minify/issues/new";
module.exports = babel => {
const t = babel.types,
traverse = babel.traverse;
const bfsTraverse = bfsTraverseCreator(babel);
const hop = Object.prototype.hasOwnProperty;
class Mangler {
constructor(charset, program, {
exclude = {},
keepFnName = false,
keepClassName = false,
eval: _eval = false,
topLevel = false
} = {}) {
this.charset = charset;
this.program = program; // user passed options
this.exclude = toObject(exclude);
this.keepFnName = keepFnName;
this.keepClassName = keepClassName;
this.topLevel = topLevel;
this.eval = _eval; // tracking
this.visitedScopes = new Set();
this.scopeTracker = new ScopeTracker();
this.renamedNodes = new Set();
}
/**
* Run the mangler
*/
run() {
this.crawlScope();
this.collect();
this.fixup();
this.charset.sort();
this.mangle();
}
/**
* Tells if a variable name is excluded
* @param {String} name
*/
isExcluded(name) {
return hop.call(this.exclude, name) && this.exclude[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
*/
crawlScope() {
(traverse.clearCache || traverse.cache.clear)();
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
*/
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
*/
collect() {
const mangler = this;
const scopeTracker = mangler.scopeTracker;
scopeTracker.addScope(this.program.scope);
/**
* Same usage as in DCE, whichever runs first
*/
if (!isEvalScopesMarked(mangler.program)) {
markEvalScopes(mangler.program);
}
/**
* 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
*/
const collectVisitor = {
Scopable({
scope
}) {
scopeTracker.addScope(scope); // Collect bindings defined in the scope
Object.keys(scope.bindings).forEach(name => {
scopeTracker.addBinding(scope.bindings[name]); // add all constant violations as references
scope.bindings[name].constantViolations.forEach(() => {
scopeTracker.addReference(scope, scope.bindings[name], name);
});
});
},
/**
* This is required because after function name transformation
* plugin (part of es2015), the function name is NOT added to the
* scope's bindings. So to fix this issue, we simply add a hack to
* handle that case - fix it to the scope tree.
*
* Related:
* - https://github.com/babel/minify/issues/829
*/
BindingIdentifier(path) {
if ( // the parent has this id as the name
(path.parentPath.isFunctionExpression({
id: path.node
}) || path.parentPath.isClassExpression({
id: path.node
})) && // and the id isn't yet added to the scope
!hop.call(path.parentPath.scope.bindings, path.node.name)) {
path.parentPath.scope.registerBinding("local", path.parentPath);
}
},
/**
* 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;
}
const scope = path.scope,
name = path.node.name;
const 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}" ` + `present in "${path.parentPath.type}". ` + `Please report this at ${newIssueUrl}`);
} else {
// Add it to our scope tracker if everything is fine
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) {
const 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({
node
}) {
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
*/
isExportedWithName(binding) {
// short circuit
if (!this.topLevel) {
return false;
}
const 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) {
const ref = _step.value;
if (ref.isExportNamedDeclaration()) {
return true;
}
} // default
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
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
*/
mangleScope(scope) {
const mangler = this;
const 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);
const bindings = scopeTracker.bindings.get(scope);
const names = [...bindings.keys()]; // A counter to generate names and reset
// so we can reuse removed names
let counter = 0;
/**
* 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 (var _i = 0; _i < names.length; _i++) {
const oldName = names[_i];
const binding = bindings.get(oldName);
if (mangler.canMangle(oldName, binding, scope)) {
let next;
do {
next = mangler.charset.getIdentifier(counter++);
} while (!mangler.isValidName(next, binding, scope)); // Reset so variables which are removed can be reused
//
// the following is an assumtion (for perf)
// the length 3 is an assumption that if the oldName isn't
// 1 or 2 characters, then probably we are not going to find
// a name - because for almost all usecases we have 1 or 2
// character new names only. And for the edge cases where
// one scope has lots and lots of variables, it's okay to
// name something with 3 characters instead of 1
if (oldName.length < 3) {
counter = 0;
} // 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
*/
mangle() {
const mangler = this;
bfsTraverse(this.program, {
Scopable(path) {
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
*/
renameBindingIds(path, oldName, newName, predicate = () => true) {
const bindingIds = path.getBindingIdentifierPaths(true, false);
for (const name in bindingIds) {
if (name !== oldName) continue;
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = bindingIds[name][Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
const idPath = _step2.value;
if (predicate(idPath)) {
idPath.node.name = newName; // babel-7 don't requeue
// idPath.replaceWith(t.identifier(newName));
this.renamedNodes.add(idPath.node);
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
}
/**
* 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
*/
rename(scope, binding, oldName, newName) {
const mangler = this;
const scopeTracker = mangler.scopeTracker; // rename at the declaration level
this.renameBindingIds(binding.path, oldName, newName, idPath => idPath.node === binding.identifier); // update mangler's ScopeTracker
scopeTracker.renameBinding(scope, oldName, newName); // update all constant violations
const violations = binding.constantViolations;
for (let i = 0; i < violations.length; i++) {
if (violations[i].isLabeledStatement()) continue;
this.renameBindingIds(violations[i], oldName, newName);
scopeTracker.updateReference(violations[i].scope, binding, oldName, newName);
} // update all referenced places
const refs = binding.referencePaths;
for (let i = 0; i < refs.length; i++) {
const path = refs[i];
const node = path.node;
if (!path.isIdentifier()) {
// Ideally, this should not happen
// it happens in these places now -
// case 1: Export Statements
// This is a bug in babel
// https://github.com/babel/babel/pull/3629
// case 2: Replacements in other plugins
// eg: https://github.com/babel/minify/issues/122
// replacement in dce from `x` to `!x` gives referencePath as `!x`
path.traverse({
ReferencedIdentifier(refPath) {
if (refPath.node.name !== oldName) {
return;
}
const actualBinding = refPath.scope.getBinding(oldName);
if (actualBinding !== binding) {
return;
}
refPath.node.name = newName; // babel-7 don't requeue
// refPath.replaceWith(t.identifier(newName));
mangler.renamedNodes.add(refPath.node);
scopeTracker.updateReference(refPath.scope, binding, oldName, newName);
}
});
} else if (!isLabelIdentifier(path)) {
if (path.node.name === oldName) {
path.node.name = newName; // babel-7 don't requeue
// 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 internal tracking
binding.identifier.name = newName; // update babel's internal scope tracking
const bindings = scope.bindings;
bindings[newName] = binding;
delete bindings[oldName];
}
}
return {
name: "minify-mangle-names",
visitor: {
/**
* 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.
const shouldConsiderSource = path.getSource().length > 70000;
const charset = new Charset(shouldConsiderSource);
const mangler = new Mangler(charset, path, this.opts);
mangler.run();
}
}
}
};
}; // convert value to object
function toObject(value) {
if (!Array.isArray(value)) {
return value;
}
const map = {};
for (let i = 0; i < value.length; i++) {
map[value[i]] = true;
}
return map;
} // for keepFnName
function isFunction(path) {
return path.isFunctionExpression() || path.isFunctionDeclaration();
} // for keepClassName
function isClass(path) {
return path.isClassExpression() || path.isClassDeclaration();
}

View File

@@ -1,14 +0,0 @@
"use strict";
module.exports = isLabelIdentifier;
function isLabelIdentifier(path) {
const node = path.node;
return path.parentPath.isLabeledStatement({
label: node
}) || path.parentPath.isBreakStatement({
label: node
}) || path.parentPath.isContinueStatement({
label: node
});
}

View File

@@ -1,269 +0,0 @@
"use strict";
const CountedSet = require("./counted-set");
const isLabelIdentifier = require("./is-label-identifier");
const newIssueUrl = "https://github.com/babel/minify/issues/new";
/**
* ScopeTracker
* references: Map<Scope, CountedSet<String> >
* bindings: Map<Scope, Map<String, Binding> >
*/
module.exports = class ScopeTracker {
constructor() {
this.references = new Map();
this.bindings = new Map();
}
/**
* Register a new Scope and initiliaze it with empty sets
* @param {Scope} scope
*/
addScope(scope) {
if (!this.references.has(scope)) {
this.references.set(scope, new CountedSet());
}
if (!this.bindings.has(scope)) {
this.bindings.set(scope, new Map());
}
}
/**
* Add reference to all Scopes between and including the ReferencedScope
* and Binding's Scope
* @param {Scope} scope
* @param {Binding} binding
* @param {String} name
*/
addReference(scope, binding, name) {
let parent = scope;
do {
this.references.get(parent).add(name);
if (!binding) {
throw new Error(`Binding Not Found for ${name} during scopeTracker.addRefernce. ` + `Please report at ${newIssueUrl}`);
}
if (binding.scope === parent) break;
} while (parent = parent.parent);
}
/**
* has a Reference in the given {Scope} or a child Scope
*
* Refer {addReference} to know why the following call will be valid
* for detecting references in child Scopes
*
* @param {Scope} scope
* @param {String} name
*/
hasReference(scope, name) {
return this.references.get(scope).has(name);
}
/**
* Update reference count in all scopes between and including the
* Referenced Scope and the Binding's Scope
*
* @param {Scope} scope
* @param {Binding} binding
* @param {String} oldName
* @param {String} newName
*/
updateReference(scope, binding, oldName, newName) {
let parent = scope;
do {
const ref = this.references.get(parent);
ref.delete(oldName);
ref.add(newName);
if (!binding) {
// Something went wrong - panic
throw new Error("Binding Not Found during scopeTracker.updateRefernce " + `while updating "${oldName}" to "${newName}". ` + `Please report at ${newIssueUrl}`);
}
if (binding.scope === parent) break;
} while (parent = parent.parent);
}
/**
* has either a Binding or a Reference
* @param {Scope} scope
* @param {Binding} binding
* @param {String} name
*/
hasBindingOrReference(scope, binding, name) {
return this.hasReference(scope, name) || this.hasBinding(scope, name);
}
/**
* For a Binding visit all places where the Binding is used and detect
* if the newName {next} can be used in all these places
*
* 1. binding's own scope
* 2. constant violations' scopes
* 3. referencePaths' scopes
*
* @param {Binding} binding
* @param {String} next
*/
canUseInReferencedScopes(binding, next) {
const tracker = this;
if (tracker.hasBindingOrReference(binding.scope, binding, next)) {
return false;
} // Safari raises a syntax error for a `let` or `const` declaration in a
// `for` loop initialization that shadows a parent function's parameter.
// https://github.com/babel/minify/issues/559
// https://bugs.webkit.org/show_bug.cgi?id=171041
// https://trac.webkit.org/changeset/217200/webkit/trunk/Source
const maybeDecl = binding.path.parentPath;
const isBlockScoped = maybeDecl.isVariableDeclaration({
kind: "let"
}) || maybeDecl.isVariableDeclaration({
kind: "const"
});
if (isBlockScoped) {
const maybeFor = maybeDecl.parentPath;
const isForLoopBinding = maybeFor.isForStatement({
init: maybeDecl.node
}) || maybeFor.isForXStatement({
left: maybeDecl.node
});
if (isForLoopBinding) {
const fnParent = getFunctionParent(maybeFor);
if (fnParent.isFunction({
body: maybeFor.parent
})) {
const parentFunctionBinding = this.bindings.get(fnParent.scope).get(next);
if (parentFunctionBinding) {
const parentFunctionHasParamBinding = parentFunctionBinding.kind === "param";
if (parentFunctionHasParamBinding) {
return false;
}
}
}
}
}
for (let i = 0; i < binding.constantViolations.length; i++) {
const violation = binding.constantViolations[i];
if (tracker.hasBindingOrReference(violation.scope, binding, next)) {
return false;
}
}
for (let i = 0; i < binding.referencePaths.length; i++) {
const ref = binding.referencePaths[i];
if (!ref.isIdentifier()) {
let canUse = true;
ref.traverse({
ReferencedIdentifier(path) {
if (path.node.name !== next) return;
if (tracker.hasBindingOrReference(path.scope, binding, next)) {
canUse = false;
}
}
});
if (!canUse) {
return canUse;
}
} else if (!isLabelIdentifier(ref)) {
if (tracker.hasBindingOrReference(ref.scope, binding, next)) {
return false;
}
}
}
return true;
}
/**
* Add a binding to Tracker in binding's own Scope
* @param {Binding} binding
*/
addBinding(binding) {
if (!binding) {
return;
}
const bindings = this.bindings.get(binding.scope);
const existingBinding = bindings.get(binding.identifier.name);
if (existingBinding && existingBinding !== binding) {
throw new Error(`scopeTracker.addBinding: ` + `Binding "${existingBinding.identifier.name}" already exists. ` + `Trying to add "${binding.identifier.name}" again.`);
}
bindings.set(binding.identifier.name, binding);
}
/**
* Moves Binding from it's own Scope to {@param toScope}
*
* required for fixup-var-scope
*
* @param {Binding} binding
* @param {Scope} toScope
*/
moveBinding(binding, toScope) {
this.bindings.get(binding.scope).delete(binding.identifier.name);
this.bindings.get(toScope).set(binding.identifier.name, binding);
}
/**
* has a Binding in the current {Scope}
* @param {Scope} scope
* @param {String} name
*/
hasBinding(scope, name) {
return this.bindings.get(scope).has(name);
}
/**
* Update the ScopeTracker on rename
* @param {Scope} scope
* @param {String} oldName
* @param {String} newName
*/
renameBinding(scope, oldName, newName) {
const bindings = this.bindings.get(scope);
bindings.set(newName, bindings.get(oldName));
bindings.delete(oldName);
}
};
/**
* Babel-7 returns null if there is no function parent
* and uses getProgramParent to get Program
*/
function getFunctionParent(path) {
return (path.scope.getFunctionParent() || path.scope.getProgramParent()).path;
}

View File

@@ -1,54 +0,0 @@
{
"_args": [
[
"babel-plugin-minify-mangle-names@0.5.0",
"/home/runner/work/add-and-commit/add-and-commit"
]
],
"_development": true,
"_from": "babel-plugin-minify-mangle-names@0.5.0",
"_id": "babel-plugin-minify-mangle-names@0.5.0",
"_inBundle": false,
"_integrity": "sha512-3jdNv6hCAw6fsX1p2wBGPfWuK69sfOjfd3zjUXkbq8McbohWy23tpXfy5RnToYWggvqzuMOwlId1PhyHOfgnGw==",
"_location": "/babel-plugin-minify-mangle-names",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "babel-plugin-minify-mangle-names@0.5.0",
"name": "babel-plugin-minify-mangle-names",
"escapedName": "babel-plugin-minify-mangle-names",
"rawSpec": "0.5.0",
"saveSpec": null,
"fetchSpec": "0.5.0"
},
"_requiredBy": [
"/babel-preset-minify"
],
"_resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.0.tgz",
"_spec": "0.5.0",
"_where": "/home/runner/work/add-and-commit/add-and-commit",
"author": {
"name": "amasad"
},
"bugs": {
"url": "https://github.com/babel/minify/issues"
},
"dependencies": {
"babel-helper-mark-eval-scopes": "^0.4.3"
},
"description": "Context- and scope- aware variable renaming.",
"gitHead": "4de390008da4a486b37819109d2021a0957ad405",
"homepage": "https://github.com/babel/minify#readme",
"keywords": [
"babel-plugin"
],
"license": "MIT",
"main": "lib/index.js",
"name": "babel-plugin-minify-mangle-names",
"repository": {
"type": "git",
"url": "https://github.com/babel/minify/tree/master/packages/babel-plugin-minify-mangle-names"
},
"version": "0.5.0"
}