mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-01 07:47:49 +00:00
Track less variables and optimize dead variable removal in build.js.
Former-commit-id: 926dae3b46fd491634559391c888fca8a83c84ac
This commit is contained in:
114
build.js
114
build.js
@@ -664,7 +664,9 @@
|
||||
* @returns {String} Returns the modified source.
|
||||
*/
|
||||
function cleanupCompiled(source) {
|
||||
return source.replace(/([{}]) *;/g, '$1');
|
||||
return source
|
||||
.replace(/\b(function) *(\()/g, '$1$2')
|
||||
.replace(/([{}]) *;/g, '$1');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -978,32 +980,6 @@
|
||||
) || methodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of times a given variable is referenced in `source`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The source to process.
|
||||
* @param {String} varName The name of the variable.
|
||||
* @returns {Number} Returns the number of times `varName` is referenced.
|
||||
*/
|
||||
function getRefCount(source, varName) {
|
||||
var indentA = isRemoved(source, 'runInContext') ? ' {2}' : ' {2,4}',
|
||||
indentB = isRemoved(source, 'runInContext') ? ' {6}' : ' {6,8}',
|
||||
snippet = source.replace(/^ *(?:\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/|\/\/.+)\n/gm, '');
|
||||
|
||||
var match = RegExp(
|
||||
'^(' + indentA + ')var ' + varName + ' *(?:|= *(?:.+?(?:|&&\\n[^;]+)|(?:\\w+\\(|[{(]\\n)[\\s\\S]+?\\n\\1[^\\n ]+?));\\n|' +
|
||||
'^' + indentA + 'var ' + varName + ' *=.+?,\\n(?= *\\w+ *=)|' +
|
||||
'^' + indentB + varName + ' *=.+?[,;]\\n'
|
||||
,'m')
|
||||
.exec(snippet);
|
||||
|
||||
if (match) {
|
||||
snippet = snippet.slice(0, match.index) + snippet.slice(match.index + match[0].length);
|
||||
}
|
||||
return _.size(match && snippet.match(RegExp('[^.\\w]' + varName + '\\b', 'g')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a sorted array of all variables defined outside of Lo-Dash methods.
|
||||
*
|
||||
@@ -1018,7 +994,7 @@
|
||||
result = [];
|
||||
|
||||
snippet.replace(RegExp(
|
||||
'^(' + indentA + ')var (\\w+) *(?:|= *(?:.+?(?:|&&\\n[^;]+)|(?:\\w+\\(|[{(]\\n)[\\s\\S]+?\\n\\1[^\\n ]+?));\\n|' +
|
||||
'^(' + indentA + ')var (\\w+) *(?:|= *(?:.+?(?:|&&\\n[^;]+)|(?:\\w+\\(|[{[(]\\n)[\\s\\S]+?\\n\\1[^\\n ]+?));\\n|' +
|
||||
'^' + indentA + 'var (\\w+) *=.+?,\\n(?= *\\w+ *=)|' +
|
||||
'^' + indentB + '(\\w+) *=.+?[,;]\\n'
|
||||
,'gm'), function(match, indent, varA, varB, varC) {
|
||||
@@ -1045,6 +1021,37 @@
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if given variable is used in `source`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The source to process.
|
||||
* @param {String} varName The name of the variable.
|
||||
* @param {Boolean} [isShallow=false] A flag to indicate looking for varaibles one closure deep.
|
||||
* @returns {Boolean} Returns `true` if the variable is used, else `false`.
|
||||
*/
|
||||
function isVarUsed(source, varName, isShallow) {
|
||||
if (isShallow == null) {
|
||||
isShallow = isRemoved(source, 'runInContext');
|
||||
}
|
||||
var indentA = isShallow ? ' {2}' : ' {2,4}',
|
||||
indentB = isShallow ? ' {6}' : ' {6,8}',
|
||||
snippet = source.replace(/^ *(?:\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/|\/\/.+)\n/gm, '');
|
||||
|
||||
var match = RegExp(
|
||||
'^(' + indentA + ')var ' + varName + ' *(?:|= *(?:.+?(?:|&&\\n[^;]+)|(?:\\w+\\(|[{[(]\\n)[\\s\\S]+?\\n\\1[^\\n ]+?));\\n|' +
|
||||
'^' + indentA + 'var ' + varName + ' *=.+?,\\n(?= *\\w+ *=)|' +
|
||||
'^' + indentB + varName + ' *=.+?[,;]\\n'
|
||||
, 'm')
|
||||
.exec(snippet);
|
||||
|
||||
if (!match) {
|
||||
return false;
|
||||
}
|
||||
snippet = snippet.slice(0, match.index) + snippet.slice(match.index + match[0].length);
|
||||
return RegExp('[^.\\w"\']' + varName + '\\b').test(snippet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches `source` for a `funcName` function declaration, expression, or
|
||||
* assignment and returns the matched snippet.
|
||||
@@ -1068,7 +1075,7 @@
|
||||
// match a function declaration
|
||||
'function ' + funcName + '\\b[\\s\\S]+?\\n\\1}|' +
|
||||
// match a variable declaration with function expression
|
||||
'var ' + funcName + ' *=.*?function[\\s\\S]+?\\n\\1}(?:\\(\\)\\))?;' +
|
||||
'var ' + funcName + ' *=.*?function\\(.+?\{\\n[\\s\\S]+?\\n\\1}(?:\\(\\)\\))?;' +
|
||||
// end non-capturing group
|
||||
')\\n'
|
||||
)));
|
||||
@@ -1278,9 +1285,6 @@
|
||||
* @returns {String} Returns the modified source.
|
||||
*/
|
||||
function removeBindingOptimization(source) {
|
||||
source = removeVar(source, 'fnToString');
|
||||
source = removeVar(source, 'reThis');
|
||||
|
||||
// remove `reThis` from `createCallback`
|
||||
source = source.replace(matchFunction(source, 'createCallback'), function(match) {
|
||||
return match.replace(/\s*\|\|\s*\(reThis[\s\S]+?\)\)\)/, '');
|
||||
@@ -1486,7 +1490,6 @@
|
||||
function removeSupportNonEnumShadows(source) {
|
||||
source = removeSupportProp(source, 'nonEnumShadows');
|
||||
source = removeVar(source, 'nonEnumProps');
|
||||
source = removeVar(source, 'shadowedProps');
|
||||
source = removeFromCreateIterator(source, 'shadowedProps');
|
||||
|
||||
// remove nested `nonEnumProps` assignments
|
||||
@@ -1577,8 +1580,6 @@
|
||||
* @returns {String} Returns the modified source.
|
||||
*/
|
||||
function removeRunInContext(source) {
|
||||
source = removeVar(source, 'contextProps');
|
||||
|
||||
// replace reference in `reThis` assignment
|
||||
source = source.replace(/\btest\(runInContext\)/, 'test(function() { return this; })');
|
||||
|
||||
@@ -1607,8 +1608,6 @@
|
||||
* @returns {String} Returns the modified source.
|
||||
*/
|
||||
function removeSetImmediate(source) {
|
||||
source = removeVar(source, 'setImmediate');
|
||||
|
||||
// remove the `setImmediate` fork of `_.defer`.
|
||||
source = source.replace(/(?:\s*\/\/.*)*\n( *)if *\(isV8 *&& *freeModule[\s\S]+?\n\1}/, '');
|
||||
|
||||
@@ -1646,7 +1645,7 @@
|
||||
function removeVar(source, varName) {
|
||||
// simplify complex variable assignments
|
||||
if (/^(?:cloneableClasses|contextProps|ctorByClass|freeGlobal|nonEnumProps|shadowedProps|whitespace)$/.test(varName)) {
|
||||
source = source.replace(RegExp('(var ' + varName + ' *=)[\\s\\S]+?[;}]\\n\\n'), '$1=null;\n\n');
|
||||
source = source.replace(RegExp('(var ' + varName + ' *=)[\\s\\S]+?[;}]\\n\\n'), '$1 null;\n\n');
|
||||
}
|
||||
|
||||
source = removeFunction(source, varName);
|
||||
@@ -1654,7 +1653,7 @@
|
||||
// match a variable declaration that's not part of a declaration list
|
||||
source = source.replace(RegExp(
|
||||
multilineComment +
|
||||
'( *)var ' + varName + ' *(?:|= *(?:.+?(?:|&&\\n[^;]+)|(?:\\w+\\(|[{(]\\n)[\\s\\S]+?\\n\\1[^\\n ]+?));\\n'
|
||||
'( *)var ' + varName + ' *(?:|= *(?:.+?(?:|&&\\n[^;]+)|(?:\\w+\\(|[{[(]\\n)[\\s\\S]+?\\n\\1[^\\n ]+?));\\n'
|
||||
), '');
|
||||
|
||||
// match a variable declaration in a declaration list
|
||||
@@ -2198,10 +2197,6 @@
|
||||
source = removeSupportProp(source, 'fastBind');
|
||||
source = replaceSupportProp(source, 'argsClass', 'false');
|
||||
|
||||
_.each(['isIeOpera', 'isV8', 'getPrototypeOf', 'nativeBind', 'nativeCreate', 'nativeIsArray', 'nativeKeys', 'reNative'], function(varName) {
|
||||
source = removeVar(source, varName);
|
||||
});
|
||||
|
||||
// remove native `Function#bind` branch in `_.bind`
|
||||
source = source.replace(matchFunction(source, 'bind'), function(match) {
|
||||
return match.replace(/(?:\s*\/\/.*)*\s*return support\.fastBind[^:]+:\s*/, 'return ');
|
||||
@@ -2367,7 +2362,7 @@
|
||||
return match;
|
||||
}
|
||||
}
|
||||
return match.replace(/^(( *)if *\(.*?\bisArray\([^\)]+\).*?\) *{\n)(( *)var index[^;]+.+\n+)/m, function(snippet, statement, indent, vars) {
|
||||
return match.replace(/^(( *)if *\(.*?\bisArray\([^\)]+\).*?\) *\{\n)(( *)var index[^;]+.+\n+)/m, function(snippet, statement, indent, vars) {
|
||||
vars = vars
|
||||
.replace(/\b(length *=)[^;=]+/, '$1 collection' + (methodName == 'reduce' ? '.length' : ' ? collection.length : 0'))
|
||||
.replace(RegExp('^ ' + indent, 'gm'), indent);
|
||||
@@ -3028,11 +3023,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
// remove unneeded variables
|
||||
if (!useLodashMethod('clone') && !useLodashMethod('cloneDeep')) {
|
||||
source = removeVar(source, 'cloneableClasses');
|
||||
source = removeVar(source, 'ctorByClass');
|
||||
}
|
||||
// remove `_.isEqual` use from `createCallback`
|
||||
if (!useLodashMethod('where')) {
|
||||
source = source.replace(matchFunction(source, 'createCallback'), function(match) {
|
||||
@@ -3305,7 +3295,8 @@
|
||||
|
||||
// modify/remove references to removed methods/variables
|
||||
if (!isTemplate) {
|
||||
if (isRemoved(source, 'clone')) {
|
||||
if (isRemoved(source, 'clone') ||
|
||||
isUnderscore && (!useLodashMethod('clone') && !useLodashMethod('cloneDeep'))) {
|
||||
source = removeVar(source, 'cloneableClasses');
|
||||
source = removeVar(source, 'ctorByClass');
|
||||
}
|
||||
@@ -3465,21 +3456,26 @@
|
||||
|
||||
// remove unused variables
|
||||
(function() {
|
||||
var varMap = {},
|
||||
varNames = getVars(source);
|
||||
var useMap = {},
|
||||
varNames = getVars(source),
|
||||
isShallow = isRemoved(source, 'runInContext');
|
||||
|
||||
while (varNames.length) {
|
||||
varNames = _.sortBy(varNames, function(varName) {
|
||||
var count = getRefCount(source, varName);
|
||||
varMap[varName] = count;
|
||||
return count;
|
||||
var result = isVarUsed(source, varName, isShallow);
|
||||
useMap[varName] = result;
|
||||
return result;
|
||||
});
|
||||
|
||||
var varName = varNames[0];
|
||||
if (!varMap[varName]) {
|
||||
source = removeVar(source, varName);
|
||||
if (useMap[varNames[0]]) {
|
||||
varNames.shift();
|
||||
}
|
||||
else {
|
||||
while (!useMap[varNames[0]]) {
|
||||
source = removeVar(source, varNames[0]);
|
||||
varNames.shift();
|
||||
}
|
||||
}
|
||||
varNames.shift();
|
||||
}
|
||||
}());
|
||||
}
|
||||
|
||||
10
dist/lodash.js
vendored
10
dist/lodash.js
vendored
@@ -863,7 +863,7 @@
|
||||
* @param {Object} object The object to inspect.
|
||||
* @returns {Array} Returns a new array of property names.
|
||||
*/
|
||||
var shimKeys = function (object) {
|
||||
var shimKeys = function(object) {
|
||||
var index, iterable = object, result = [];
|
||||
if (!iterable) return result;
|
||||
if (!(objectTypes[typeof object])) return result;
|
||||
@@ -946,7 +946,7 @@
|
||||
* defaults(food, { 'name': 'banana', 'type': 'fruit' });
|
||||
* // => { 'name': 'apple', 'type': 'fruit' }
|
||||
*/
|
||||
var assign = function (object, source, guard) {
|
||||
var assign = function(object, source, guard) {
|
||||
var index, iterable = object, result = iterable;
|
||||
if (!iterable) return result;
|
||||
var args = arguments,
|
||||
@@ -1169,7 +1169,7 @@
|
||||
* _.defaults(food, { 'name': 'banana', 'type': 'fruit' });
|
||||
* // => { 'name': 'apple', 'type': 'fruit' }
|
||||
*/
|
||||
var defaults = function (object, source, guard) {
|
||||
var defaults = function(object, source, guard) {
|
||||
var index, iterable = object, result = iterable;
|
||||
if (!iterable) return result;
|
||||
var args = arguments,
|
||||
@@ -1252,7 +1252,7 @@
|
||||
* });
|
||||
* // => alerts 'name' and 'bark' (order is not guaranteed)
|
||||
*/
|
||||
var forIn = function (collection, callback, thisArg) {
|
||||
var forIn = function(collection, callback, thisArg) {
|
||||
var index, iterable = collection, result = iterable;
|
||||
if (!iterable) return result;
|
||||
if (!objectTypes[typeof iterable]) return result;
|
||||
@@ -1284,7 +1284,7 @@
|
||||
* });
|
||||
* // => alerts '0', '1', and 'length' (order is not guaranteed)
|
||||
*/
|
||||
var forOwn = function (collection, callback, thisArg) {
|
||||
var forOwn = function(collection, callback, thisArg) {
|
||||
var index, iterable = collection, result = iterable;
|
||||
if (!iterable) return result;
|
||||
if (!objectTypes[typeof iterable]) return result;
|
||||
|
||||
6
dist/lodash.underscore.js
vendored
6
dist/lodash.underscore.js
vendored
@@ -538,7 +538,7 @@
|
||||
* @param {Object} object The object to inspect.
|
||||
* @returns {Array} Returns a new array of property names.
|
||||
*/
|
||||
var shimKeys = function (object) {
|
||||
var shimKeys = function(object) {
|
||||
var index, iterable = object, result = [];
|
||||
if (!iterable) return result;
|
||||
if (!(objectTypes[typeof object])) return result;
|
||||
@@ -750,7 +750,7 @@
|
||||
* });
|
||||
* // => alerts 'name' and 'bark' (order is not guaranteed)
|
||||
*/
|
||||
var forIn = function (collection, callback) {
|
||||
var forIn = function(collection, callback) {
|
||||
var index, iterable = collection, result = iterable;
|
||||
if (!iterable) return result;
|
||||
if (!objectTypes[typeof iterable]) return result;
|
||||
@@ -781,7 +781,7 @@
|
||||
* });
|
||||
* // => alerts '0', '1', and 'length' (order is not guaranteed)
|
||||
*/
|
||||
var forOwn = function (collection, callback) {
|
||||
var forOwn = function(collection, callback) {
|
||||
var index, iterable = collection, result = iterable;
|
||||
if (!iterable) return result;
|
||||
if (!objectTypes[typeof iterable]) return result;
|
||||
|
||||
Reference in New Issue
Block a user