mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-01-29 06:27:49 +00:00
Add custom build include and exclude options to build.js.
Former-commit-id: 5d61f47840e51937506d94f65bb55b4f97fe9f19
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
.DS_Store
|
||||
dist/
|
||||
node_modules/
|
||||
lodash.custom*
|
||||
394
build.js
394
build.js
@@ -6,16 +6,404 @@
|
||||
var fs = require('fs'),
|
||||
path = require('path');
|
||||
|
||||
/** The minify module */
|
||||
var Minify = require(path.join(__dirname, 'build', 'minify'));
|
||||
/** Load other modules */
|
||||
var lodash = require(path.join(__dirname, 'lodash')),
|
||||
minify = require(path.join(__dirname, 'build', 'minify'));
|
||||
|
||||
/** Flag used to specify a custom build */
|
||||
var isCustom = false;
|
||||
|
||||
/** The lodash.js source */
|
||||
var source = fs.readFileSync(path.join(__dirname, 'lodash.js'), 'utf8');
|
||||
|
||||
/** Used to associate aliases with their real names */
|
||||
var aliasToRealMap = {
|
||||
'all': 'every',
|
||||
'any': 'some',
|
||||
'collect': 'map',
|
||||
'detect': 'find',
|
||||
'each': 'forEach',
|
||||
'foldl': 'reduce',
|
||||
'foldr': 'reduceRight',
|
||||
'head': 'first',
|
||||
'include': 'contains',
|
||||
'inject': 'reduce',
|
||||
'intersect': 'intersection',
|
||||
'methods': 'functions',
|
||||
'select': 'filter',
|
||||
'tail': 'rest',
|
||||
'take': 'first',
|
||||
'unique': 'uniq'
|
||||
};
|
||||
|
||||
/** Used to associate real names with their aliases */
|
||||
var realToAliasMap = {
|
||||
'contains': ['include'],
|
||||
'every': ['all'],
|
||||
'filter': ['select'],
|
||||
'find': ['detect'],
|
||||
'first': ['head', 'take'],
|
||||
'forEach': ['each'],
|
||||
'functions': ['methods'],
|
||||
'intersection': ['intersect'],
|
||||
'map': ['collect'],
|
||||
'reduce': ['foldl', 'inject'],
|
||||
'reduceRight': ['foldr'],
|
||||
'rest': ['tail'],
|
||||
'some': ['any'],
|
||||
'uniq': ['unique']
|
||||
};
|
||||
|
||||
/** Used to track function dependencies */
|
||||
var dependencyMap = {
|
||||
'after': [],
|
||||
'bind': [],
|
||||
'bindAll': ['bind'],
|
||||
'chain': [],
|
||||
'clone': ['extend', 'isArray'],
|
||||
'compact': [],
|
||||
'compose': [],
|
||||
'contains': ['createIterator'],
|
||||
'createIterator': ['template'],
|
||||
'debounce': [],
|
||||
'defaults': ['createIterator'],
|
||||
'defer': [],
|
||||
'delay': [],
|
||||
'difference': ['indexOf'],
|
||||
'escape': [],
|
||||
'every': ['bind', 'createIterator', 'identity'],
|
||||
'extend': ['createIterator'],
|
||||
'filter': ['bind', 'createIterator', 'identity'],
|
||||
'find': ['createIterator'],
|
||||
'first': [],
|
||||
'flatten': ['isArray'],
|
||||
'forEach': ['bind', 'createIterator'],
|
||||
'functions': ['createIterator'],
|
||||
'groupBy': ['bind', 'createIterator'],
|
||||
'has': [],
|
||||
'identity': [],
|
||||
'indexOf': ['sortedIndex'],
|
||||
'initial': [],
|
||||
'intersection': ['every', 'indexOf'],
|
||||
'invoke': [],
|
||||
'isArguments': [],
|
||||
'isArray': [],
|
||||
'isBoolean': [],
|
||||
'isDate': [],
|
||||
'isElement': [],
|
||||
'isEmpty': ['createIterator'],
|
||||
'isEqual': [],
|
||||
'isFinite': [],
|
||||
'isFunction': [],
|
||||
'isNaN': [],
|
||||
'isNull': [],
|
||||
'isNumber': [],
|
||||
'isObject': [],
|
||||
'isRegExp': [],
|
||||
'isString': [],
|
||||
'isUndefined': [],
|
||||
'keys': ['createIterator'],
|
||||
'last': [],
|
||||
'lastIndexOf': [],
|
||||
'map': ['bind', 'createIterator', 'identity'],
|
||||
'max': ['bind'],
|
||||
'memoize': [],
|
||||
'min': ['bind'],
|
||||
'mixin': ['forEach'],
|
||||
'noConflict': [],
|
||||
'once': [],
|
||||
'partial': [],
|
||||
'pick': [],
|
||||
'pluck': ['createIterator'],
|
||||
'range': [],
|
||||
'reduce': ['bind', 'createIterator'],
|
||||
'reduceRight': ['bind', 'keys'],
|
||||
'reject': ['bind', 'createIterator', 'identity'],
|
||||
'rest': [],
|
||||
'result': [],
|
||||
'shuffle': [],
|
||||
'size': ['keys'],
|
||||
'some': ['bind', 'createIterator', 'identity'],
|
||||
'sortBy': ['bind', 'map', 'pluck'],
|
||||
'sortedIndex': [],
|
||||
'tap': [],
|
||||
'template': ['escape'],
|
||||
'throttle': [],
|
||||
'times': ['bind'],
|
||||
'toArray': ['values'],
|
||||
'union': ['indexOf'],
|
||||
'uniq': ['indexOf'],
|
||||
'uniqueId': [],
|
||||
'values': ['createIterator'],
|
||||
'without': ['indexOf'],
|
||||
'wrap': [],
|
||||
'zip': ['max', 'pluck']
|
||||
};
|
||||
|
||||
/** Used to indicate core functions */
|
||||
var coreFuncs = ['extend', 'forEach', 'mixin'];
|
||||
|
||||
/** Used to determine the remaining functions in the source */
|
||||
var funcNames = Object.keys(dependencyMap);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Gets the aliases associated with a given `funcName`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} funcName The name of the function to get aliases for.
|
||||
* @returns {Array} Returns an array of aliases.
|
||||
*/
|
||||
function getAliases(funcName) {
|
||||
return realToAliasMap[funcName] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of depenants for a function by the given `funcName`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} funcName The name of the function to query.
|
||||
* @returns {Array} Returns an array of function dependants.
|
||||
*/
|
||||
function getDependants(funcName) {
|
||||
// iterate over `dependencyMap`, adding the names of functions that
|
||||
// have `funcName` as a dependency
|
||||
return lodash.reduce(dependencyMap, function(result, dependencies, otherName) {
|
||||
if (dependencies.indexOf(funcName) > -1) {
|
||||
result.push(otherName);
|
||||
}
|
||||
return result;
|
||||
}, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of dependencies for a function of the given `funcName`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} funcName The name of the function to query.
|
||||
* @returns {Array} Returns an array of function dependencies.
|
||||
*/
|
||||
function getDependencies(funcName) {
|
||||
var dependencies = dependencyMap[funcName],
|
||||
result = [];
|
||||
|
||||
if (!dependencies) {
|
||||
return result;
|
||||
}
|
||||
// recursively accumulate the dependencies of the `funcName` function, and
|
||||
// the dependencies of its dependencies, and so on.
|
||||
return dependencies.reduce(function(result, otherName) {
|
||||
result.push.apply(result, getDependencies(otherName).concat(otherName));
|
||||
return result;
|
||||
}, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the real name, not alias, of a given `funcName`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} funcName The name of the function to resolve.
|
||||
* @returns {String} Returns the real name.
|
||||
*/
|
||||
function getRealName(funcName) {
|
||||
return aliasToRealMap[funcName] || funcName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if all functions of the given names have been removed.
|
||||
*
|
||||
* @private
|
||||
* @param {String} [funcName1, funcName2, ...] The names of functions to check.
|
||||
* @returns {Boolean} Returns `true` if all functions have been removed, else `false`.
|
||||
*/
|
||||
function isRemoved() {
|
||||
return !lodash.intersection(funcNames, arguments).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a function and associated code from the `source`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The source to process.
|
||||
* @param {String} funcName The name of the function to remove.
|
||||
* @returns {String} Returns the source with the function removed.
|
||||
*/
|
||||
function removeFunction(source, funcName) {
|
||||
// remove function
|
||||
source = source.replace(RegExp(
|
||||
// match multi-line comment block (could be on a single line)
|
||||
'\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/\\n' +
|
||||
// begin non-capturing group
|
||||
'(?:' +
|
||||
// match a function declaration
|
||||
'( +)function ' + funcName + '\\b[\\s\\S]+?\\n\\1}|' +
|
||||
// match a variable declaration with `createIerator`
|
||||
' +var ' + funcName + ' *= *(?:[a-zA-Z]+ *\\|\\| *)?createIterator\\((?:{|[a-zA-Z])[\\s\\S]+?\\);|' +
|
||||
// match a variable declaration with function expression
|
||||
'( +)var ' + funcName + ' *= *(?:[a-zA-Z]+ *\\|\\| *)?function[\\s\\S]+?\\n\\2};' +
|
||||
// end non-capturing group
|
||||
')\\n'
|
||||
), '');
|
||||
|
||||
// exit early if function is already removed
|
||||
var found = funcNames.indexOf(funcName);
|
||||
if (found < 0) {
|
||||
return source;
|
||||
}
|
||||
|
||||
// grab `lodash` method assignments snippet
|
||||
var assignmentSnippet = source.match(/( +)extend\(lodash,(?:[\s\S]+?\},)?([\s\S]+?\n\1}\))/)[2];
|
||||
|
||||
// remove `funcName` from method assignments
|
||||
var modifiedSnippet = getAliases(funcName).concat(funcName).reduce(function(result, otherName) {
|
||||
result = result.replace(RegExp(" *'" + otherName + "'[^\\n]+\\n"), '');
|
||||
return result;
|
||||
}, assignmentSnippet)
|
||||
|
||||
// remove any trailing commas and comments from the method assignments
|
||||
modifiedSnippet = modifiedSnippet.replace(/,(?:\s*\/\/[^\n]*)?(\s*}\))/, '$1');
|
||||
|
||||
// replace method assignments snippet with the modified snippet
|
||||
source = source.replace(assignmentSnippet, modifiedSnippet);
|
||||
|
||||
// remove from remaining function names
|
||||
funcNames.splice(found, 1);
|
||||
|
||||
// remove associated code snippets
|
||||
switch(funcName) {
|
||||
case 'isArguments':
|
||||
// remove `isArguments` if-statement
|
||||
source = source.replace(/ +(?:\/\/[^\n]*\s+)?if *\(!isArguments[^)]+\)[\s\S]+?};?\s*}\n/, '');
|
||||
break;
|
||||
|
||||
case 'template':
|
||||
// remove associated functions
|
||||
['detokenize', 'escapeChar', 'tokenizeEscape', 'tokenizeInterpolate', 'tokenizeEvaluate'].forEach(function(otherName) {
|
||||
source = removeFunction(source, otherName);
|
||||
});
|
||||
// remove associated variables
|
||||
['escapes', 'iteratorTemplate', 'reEscapeDelimiter', 'reEvaluateDelimiter', 'reInterpolateDelimiter', 'reToken', 'reUnescaped', 'token', 'tokenized'].forEach(function(varName) {
|
||||
source = removeVar(source, varName);
|
||||
});
|
||||
// remove `templateSettings` assignment
|
||||
source = source.replace(/\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/\n( +)'templateSettings'[\s\S]+?},\n/, '');
|
||||
break;
|
||||
|
||||
case 'uniqueId':
|
||||
source = removeVar(source, 'idCounter');
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a given variable from the `source`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The source to process.
|
||||
* @param {String} varName The name of the variable to remove.
|
||||
* @returns {String} Returns the source with the variable removed.
|
||||
*/
|
||||
function removeVar(source, varName) {
|
||||
return source.replace(RegExp(
|
||||
// match multi-line comment block
|
||||
'\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/\\n' +
|
||||
// match a variable declaration
|
||||
'( +)var ' + varName + ' *= *(?:.*?;|[\\s\\S]+?\\n\\1[^\\n]+;)\\n'
|
||||
), '');
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// custom build
|
||||
process.argv.some(function(arg) {
|
||||
// exit early if not the "exclude" or "include" command option
|
||||
var pair = arg.match(/^(exclude|include)=(.+)$/);
|
||||
if (!pair) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var filterType = pair[1],
|
||||
filterNames = pair[2].split(',');
|
||||
|
||||
// set custom build flag
|
||||
isCustom = true;
|
||||
|
||||
// remove the specified functions and their dependants
|
||||
if (filterType == 'exclude') {
|
||||
filterNames.forEach(function(funcName) {
|
||||
funcName = getRealName(funcName);
|
||||
var otherNames = getDependants(funcName).concat(funcName);
|
||||
|
||||
// skip removal if `funcName` is a required core function
|
||||
if (otherNames.some(function(otherName) {
|
||||
return coreFuncs.indexOf(otherName) > -1;
|
||||
})) {
|
||||
return;
|
||||
}
|
||||
otherNames.forEach(function(otherName) {
|
||||
source = removeFunction(source, otherName);
|
||||
});
|
||||
});
|
||||
}
|
||||
// else remove all but the specified functions and their dependencies
|
||||
else {
|
||||
filterNames = lodash.uniq(filterNames.concat(coreFuncs).reduce(function(result, funcName) {
|
||||
funcName = getRealName(funcName);
|
||||
result.push.apply(result, getDependencies(funcName).concat(funcName));
|
||||
return result;
|
||||
}, []));
|
||||
|
||||
lodash.each(dependencyMap, function(dependencies, otherName) {
|
||||
if (filterNames.indexOf(otherName) < 0) {
|
||||
source = removeFunction(source, otherName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// remove shared variables
|
||||
if (isRemoved('createIterator', 'isEqual')) {
|
||||
source = removeVar(source, 'hasDontEnumBug');
|
||||
}
|
||||
if (isRemoved('every', 'filter', 'find', 'forEach', 'groupBy', 'map', 'reject', 'some')) {
|
||||
source = removeVar(source, 'baseIteratorOptions');
|
||||
}
|
||||
if (isRemoved('every', 'some')) {
|
||||
source = removeVar(source, 'everyIteratorOptions');
|
||||
}
|
||||
if (isRemoved('defaults', 'extend')) {
|
||||
source = removeVar(source, 'extendIteratorOptions');
|
||||
}
|
||||
if (isRemoved('filter', 'reject')) {
|
||||
source = removeVar(source, 'filterIteratorOptions');
|
||||
}
|
||||
if (isRemoved('map', 'pluck', 'values')) {
|
||||
source = removeVar(source, 'mapIteratorOptions');
|
||||
}
|
||||
if (isRemoved('max', 'min')) {
|
||||
// remove varaible and associated try-catch
|
||||
source = removeVar(source, 'argsLimit');
|
||||
source = source.replace(/\n *try\s*\{\s*\(function[\s\S]+?catch[^}]+}\n/, '');
|
||||
}
|
||||
|
||||
// consolidate consecutive horizontal rule comment separators
|
||||
source = source.replace(/(?:\s*\/\*-+\*\/\s*){2,}/g, function(separators) {
|
||||
return separators.match(/^\s*/)[0] + separators.slice(separators.lastIndexOf('/*'));
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// begin the minification process
|
||||
new Minify(source, 'lodash.min', function(result) {
|
||||
if (isCustom) {
|
||||
minify(source, 'lodash.custom.min', function(result) {
|
||||
fs.writeFileSync(path.join(__dirname, 'lodash.custom.js'), source);
|
||||
fs.writeFileSync(path.join(__dirname, 'lodash.custom.min.js'), result);
|
||||
});
|
||||
}
|
||||
else {
|
||||
minify(source, 'lodash.min', function(result) {
|
||||
fs.writeFileSync(path.join(__dirname, 'lodash.min.js'), result);
|
||||
});
|
||||
}
|
||||
}());
|
||||
|
||||
Reference in New Issue
Block a user