Cleanup build.js

Former-commit-id: 6a4502883d7431f5dcedbf7f7d3bfb871ce1c0f4
This commit is contained in:
John-David Dalton
2012-09-09 22:28:42 -07:00
parent 5e04c7f827
commit 1796ce324b

293
build.js
View File

@@ -15,7 +15,7 @@
/** Shortcut used to convert array-like objects to arrays */ /** Shortcut used to convert array-like objects to arrays */
var slice = [].slice; var slice = [].slice;
/** Shorcut to the `stdout` object */ /** Shortcut to the `stdout` object */
var stdout = process.stdout; var stdout = process.stdout;
/** Used to associate aliases with their real names */ /** Used to associate aliases with their real names */
@@ -270,7 +270,7 @@
} }
/** /**
* Logs the help message to the console. * Writes the help message to standard output.
* *
* @private * @private
*/ */
@@ -295,7 +295,7 @@
'', '',
' Options:', ' Options:',
'', '',
' -c , --stdout Write output to standard output', ' -c, --stdout Write output to standard output',
' -h, --help Display help information', ' -h, --help Display help information',
' -o, --output Write output to a given path/filename', ' -o, --output Write output to a given path/filename',
' -s, --silent Skip status updates normally logged to the console', ' -s, --silent Skip status updates normally logged to the console',
@@ -308,11 +308,11 @@
* Gets the aliases associated with a given function name. * Gets the aliases associated with a given function name.
* *
* @private * @private
* @param {String} funcName The name of the function to get aliases for. * @param {String} methodName The name of the method to get aliases for.
* @returns {Array} Returns an array of aliases. * @returns {Array} Returns an array of aliases.
*/ */
function getAliases(funcName) { function getAliases(methodName) {
return realToAliasMap[funcName] || []; return realToAliasMap[methodName] || [];
} }
/** /**
@@ -327,17 +327,17 @@
} }
/** /**
* Gets an array of depenants for a function by a given name. * Gets an array of depenants for a method by a given name.
* *
* @private * @private
* @param {String} funcName The name of the function to query. * @param {String} methodName The name of the method to query.
* @returns {Array} Returns an array of function dependants. * @returns {Array} Returns an array of method dependants.
*/ */
function getDependants(funcName) { function getDependants(methodName) {
// iterate over `dependencyMap`, adding the names of functions that // iterate over the `dependencyMap`, adding the names of methods that
// have `funcName` as a dependency // have `methodName` as a dependency
return _.reduce(dependencyMap, function(result, dependencies, otherName) { return _.reduce(dependencyMap, function(result, dependencies, otherName) {
if (_.contains(dependencies, funcName)) { if (_.contains(dependencies, methodName)) {
result.push(otherName); result.push(otherName);
} }
return result; return result;
@@ -345,21 +345,21 @@
} }
/** /**
* Gets an array of dependencies for a given function name. If passed an array * Gets an array of dependencies for a given method name. If passed an array
* of dependencies it will return an array containing the given dependencies * of dependencies it will return an array containing the given dependencies
* plus any additional detected sub-dependencies. * plus any additional detected sub-dependencies.
* *
* @private * @private
* @param {Array|String} funcName A single function name or array of * @param {Array|String} methodName A single method name or array of
* dependencies to query. * dependencies to query.
* @returns {Array} Returns an array of function dependencies. * @returns {Array} Returns an array of method dependencies.
*/ */
function getDependencies(funcName) { function getDependencies(methodName) {
var dependencies = Array.isArray(funcName) ? funcName : dependencyMap[funcName]; var dependencies = Array.isArray(methodName) ? methodName : dependencyMap[methodName];
if (!dependencies) { if (!dependencies) {
return []; return [];
} }
// recursively accumulate the dependencies of the `funcName` function, and // recursively accumulate the dependencies of the `methodName` function, and
// the dependencies of its dependencies, and so on. // the dependencies of its dependencies, and so on.
return _.uniq(dependencies.reduce(function(result, otherName) { return _.uniq(dependencies.reduce(function(result, otherName) {
result.push.apply(result, getDependencies(otherName).concat(otherName)); result.push.apply(result, getDependencies(otherName).concat(otherName));
@@ -377,7 +377,7 @@
function getFunctionSource(func) { function getFunctionSource(func) {
var source = func.source || (func + ''); var source = func.source || (func + '');
// all leading whitespace // format leading whitespace
return source.replace(/\n(?:.*)/g, function(match, index) { return source.replace(/\n(?:.*)/g, function(match, index) {
match = match.slice(1); match = match.slice(1);
return ( return (
@@ -398,14 +398,14 @@
} }
/** /**
* Gets the real name, not alias, of a given function name. * Gets the real name, not alias, of a given method name.
* *
* @private * @private
* @param {String} funcName The name of the function to resolve. * @param {String} methodName The name of the method to resolve.
* @returns {String} Returns the real name. * @returns {String} Returns the real method name.
*/ */
function getRealName(funcName) { function getRealName(methodName) {
return aliasToRealMap[funcName] || funcName; return aliasToRealMap[methodName] || methodName;
} }
/** /**
@@ -656,18 +656,6 @@
.replace(/\s*.+?\.useStrict *=.+/, ''); .replace(/\s*.+?\.useStrict *=.+/, '');
} }
/**
* Post-process the minified source.
*
* @private
* @param {String} source The minified source to process.
* @returns {String} The modified source.
*/
function postMinify(source) {
// correct overly aggressive Closure Compiler minification
return source.replace(/prototype\s*=\s*{\s*valueOf\s*:\s*1\s*}/, 'prototype={valueOf:1,y:1}');
}
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/** /**
@@ -683,6 +671,56 @@
// the debug version of `source` // the debug version of `source`
var debugSource; var debugSource;
// used to report invalid command-line arguments
var invalidArgs = _.reject(options.slice(options[0] == 'node' ? 2 : 0), function(value, index, options) {
if (/^(?:-o|--output)$/.test(options[index - 1]) ||
/^(?:category|exclude|exports|include)=.*$/.test(value)) {
return true;
}
return [
'backbone',
'csp',
'legacy',
'mobile',
'strict',
'underscore',
'-c', '--stdout',
'-h', '--help',
'-o', '--output',
'-s', '--silent',
'-V', '--version'
].indexOf(value) > -1;
});
// report invalid arguments
if (invalidArgs.length) {
console.log(
'\n' +
'Invalid argument' + (invalidArgs.length > 1 ? 's' : '') +
' passed: ' + invalidArgs.join(', ')
);
displayHelp();
return;
}
// display help message
if (_.find(options, function(arg) {
return /^(?:-h|--help)$/.test(arg);
})) {
displayHelp();
return;
}
// display `lodash.VERSION`
if (_.find(options, function(arg) {
return /^(?:-V|--version)$/.test(arg);
})) {
console.log(_.VERSION);
return;
}
/*------------------------------------------------------------------------*/
// collections of method names to exclude or include // collections of method names to exclude or include
var excludeMethods = [], var excludeMethods = [],
includeMethods = []; includeMethods = [];
@@ -748,32 +786,6 @@
return pair[1]; return pair[1];
}, ''); }, '');
// used to report invalid command-line arguments
var invalidArgs = _.reject(options.slice(options[0] == 'node' ? 2 : 0), function(value, index, options) {
if (/^(?:-o|--output)$/.test(options[index - 1]) ||
/^(?:category|exclude|exports|include)=.*$/.test(value)) {
return true;
}
return [
'backbone',
'csp',
'legacy',
'mobile',
'strict',
'underscore',
'-c', '--stdout',
'-h', '--help',
'-o', '--output',
'-s', '--silent',
'-V', '--version'
].indexOf(value) > -1;
});
// used to specify the output path for built files
var outputPath = options.reduce(function(result, value, index) {
return result || (/^(?:-o|--output)$/.test(value) ? options[index + 1] : result);
}, '');
// load customized Lo-Dash module // load customized Lo-Dash module
var lodash = (function() { var lodash = (function() {
var context = vm.createContext({ var context = vm.createContext({
@@ -841,38 +853,12 @@
return context._; return context._;
}()); }());
// report invalid arguments
if (invalidArgs.length) {
console.log(
'\n' +
'Invalid argument' + (invalidArgs.length > 1 ? 's' : '') +
' passed: ' + invalidArgs.join(', ')
);
displayHelp();
return;
}
// display help message
if (_.find(options, function(arg) {
return /^(?:-h|--help)$/.test(arg);
})) {
displayHelp();
return;
}
// display `lodash.VERSION`
if (_.find(options, function(arg) {
return /^(?:-V|--version)$/.test(arg);
})) {
console.log(_.VERSION);
return;
}
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
// don't expose `_.forIn` or `_.forOwn` if `isUnderscore` is `true` unless // customize for Backbone and Underscore builds
// requested by `include`
if (isUnderscore) { if (isUnderscore) {
// don't expose `_.forIn` or `_.forOwn` if `isUnderscore` is `true` unless
// requested by `include`
if (includeMethods.indexOf('forIn') == -1) { if (includeMethods.indexOf('forIn') == -1) {
source = source.replace(/ *lodash\.forIn *=.+\n/, ''); source = source.replace(/ *lodash\.forIn *=.+\n/, '');
} }
@@ -881,7 +867,7 @@
} }
} }
// add methods required by Backbone or Underscore // include methods required by Backbone and Underscore builds
[ [
{ 'flag': isBackbone, 'methodNames': backboneDependencies }, { 'flag': isBackbone, 'methodNames': backboneDependencies },
{ 'flag': isUnderscore, 'methodNames': underscoreMethods } { 'flag': isUnderscore, 'methodNames': underscoreMethods }
@@ -914,7 +900,7 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
// add category methods // include methods by category
options.some(function(value) { options.some(function(value) {
var categories = value.match(/^category=(.*)$/); var categories = value.match(/^category=(.*)$/);
if (!categories) { if (!categories) {
@@ -922,8 +908,8 @@
} }
// resolve method names belonging to each category // resolve method names belonging to each category
var categoryMethods = categories[1].split(/, */).reduce(function(result, category) { var categoryMethods = categories[1].split(/, */).reduce(function(result, category) {
return result.concat(allMethods.filter(function(funcName) { return result.concat(allMethods.filter(function(methodName) {
return RegExp('@category ' + category + '\\b', 'i').test(matchFunction(source, funcName)); return RegExp('@category ' + category + '\\b', 'i').test(matchFunction(source, methodName));
})); }));
}, []); }, []);
@@ -945,7 +931,7 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
// custom build // remove methods from the build
(function() { (function() {
// exit early if "exclude" or "include" options aren't specified // exit early if "exclude" or "include" options aren't specified
if (!filterType) { if (!filterType) {
@@ -953,8 +939,8 @@
} }
if (filterType == 'exclude') { if (filterType == 'exclude') {
// remove methods that are named in `excludeMethods` and their dependants // remove methods that are named in `excludeMethods` and their dependants
excludeMethods.forEach(function(funcName) { excludeMethods.forEach(function(methodName) {
getDependants(funcName).concat(funcName).forEach(function(otherName) { getDependants(methodName).concat(methodName).forEach(function(otherName) {
source = removeFunction(source, otherName); source = removeFunction(source, otherName);
}); });
}); });
@@ -964,18 +950,12 @@
includeMethods = getDependencies(includeMethods); includeMethods = getDependencies(includeMethods);
// remove methods that aren't named in `includeMethods` // remove methods that aren't named in `includeMethods`
_.each(allMethods, function(otherName) { allMethods.forEach(function(otherName) {
if (!_.contains(includeMethods, otherName)) { if (!_.contains(includeMethods, otherName)) {
source = removeFunction(source, otherName); source = removeFunction(source, otherName);
} }
}); });
} }
// remove `isArguments` fallback before `isArguments` is transformed by
// other parts of the build process
if (isRemoved(source, 'isArguments')) {
source = removeIsArgumentsFallback(source);
}
}()); }());
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
@@ -989,10 +969,15 @@
RegExp("{(\\\\n' *\\+\\s*.*?\\+\\n\\s*' *)}(?:\\\\n)?' *\\+", 'g'), "$1;\\n'+" RegExp("{(\\\\n' *\\+\\s*.*?\\+\\n\\s*' *)}(?:\\\\n)?' *\\+", 'g'), "$1;\\n'+"
); );
// remove `isArguments` fallback before `isArguments` is transformed by
// other parts of the build process
if (isRemoved(source, 'isArguments')) {
source = removeIsArgumentsFallback(source);
}
// DRY out isType functions // DRY out isType functions
(function() { (function() {
var iteratorName = _.find(['forEach', 'forOwn'], function(funcName) { var iteratorName = _.find(['forEach', 'forOwn'], function(methodName) {
return !isRemoved(source, funcName); return !isRemoved(source, methodName);
}); });
// skip this optimization if there are no iteration methods to use // skip this optimization if there are no iteration methods to use
@@ -1009,7 +994,8 @@
'Number': 'numberClass', 'Number': 'numberClass',
'RegExp': 'regexpClass', 'RegExp': 'regexpClass',
'String': 'stringClass' 'String': 'stringClass'
}, function(value, key) { },
function(value, key) {
if (!isUnderscore && key == 'Arguments') { if (!isUnderscore && key == 'Arguments') {
return; return;
} }
@@ -1051,12 +1037,12 @@
source = removeVar(source, varName); source = removeVar(source, varName);
}); });
['bind', 'isArray'].forEach(function(funcName) { ['bind', 'isArray'].forEach(function(methodName) {
var snippet = matchFunction(source, funcName), var snippet = matchFunction(source, methodName),
modified = snippet; modified = snippet;
// remove native `Function#bind` branch in `_.bind` // remove native `Function#bind` branch in `_.bind`
if (funcName == 'bind') { if (methodName == 'bind') {
modified = modified.replace(/(?:\s*\/\/.*)*\s*else if *\(isBindFast[^}]+}/, ''); modified = modified.replace(/(?:\s*\/\/.*)*\s*else if *\(isBindFast[^}]+}/, '');
} }
// remove native `Array.isArray` branch in `_.isArray` // remove native `Array.isArray` branch in `_.isArray`
@@ -1091,16 +1077,16 @@
if (isMobile) { if (isMobile) {
// inline all functions defined with `createIterator` // inline all functions defined with `createIterator`
_.functions(lodash).forEach(function(funcName) { _.functions(lodash).forEach(function(methodName) {
// match `funcName` with pseudo private `_` prefixes removed to allow matching `shimKeys` // match `methodName` with pseudo private `_` prefixes removed to allow matching `shimKeys`
var reFunc = RegExp('(\\bvar ' + funcName.replace(/^_/, '') + ' *= *)createIterator\\(((?:{|[a-zA-Z])[\\s\\S]+?)\\);\\n'); var reFunc = RegExp('(\\bvar ' + methodName.replace(/^_/, '') + ' *= *)createIterator\\(((?:{|[a-zA-Z])[\\s\\S]+?)\\);\\n');
// skip if not defined with `createIterator` // skip if not defined with `createIterator`
if (!reFunc.test(source)) { if (!reFunc.test(source)) {
return; return;
} }
// extract, format, and inject the compiled function's source code // extract, format, and inject the compiled function's source code
source = source.replace(reFunc, '$1' + getFunctionSource(lodash[funcName]) + ';\n'); source = source.replace(reFunc, '$1' + getFunctionSource(lodash[methodName]) + ';\n');
}); });
// replace `callee` in `_.merge` with `merge` // replace `callee` in `_.merge` with `merge`
@@ -1175,6 +1161,7 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
// customize how the `LoDash` function is exported
if (exportsOptions.indexOf('amd') == -1) { if (exportsOptions.indexOf('amd') == -1) {
source = source.replace(/(?: *\/\/.*\n)*( +)if *\(typeof +define[\s\S]+?else /, '$1'); source = source.replace(/(?: *\/\/.*\n)*( +)if *\(typeof +define[\s\S]+?else /, '$1');
} }
@@ -1276,50 +1263,46 @@
source = source.replace(/ *\(function\(\) *{[\s\S]+?}\(1\)\);/, ''); source = source.replace(/ *\(function\(\) *{[\s\S]+?}\(1\)\);/, '');
} }
/*------------------------------------------------------------------------*/
debugSource = cleanupSource(debugSource); debugSource = cleanupSource(debugSource);
source = cleanupSource(source); source = cleanupSource(source);
/*------------------------------------------------------------------------*/
// used to specify creating a custom build
var isCustom = !_.isEqual(exportsOptions, exportsAll) || filterType || isBackbone || isLegacy || isMobile || isStrict || isUnderscore;
// used to specify the output path for builds
var outputPath = options.reduce(function(result, value, index) {
return result || (/^(?:-o|--output)$/.test(value) ? options[index + 1] : result);
}, '');
// used to name temporary files created in `dist/`
var workingName = 'lodash' + (isCustom ? '.custom' : '') + '.min';
// output debug build
if (isCustom && !outputPath && !isStdOut) {
callback(debugSource, path.join(cwd, 'lodash.custom.js'));
}
// begin the minification process // begin the minification process
if (!_.isEqual(exportsOptions, exportsAll) || filterType || isBackbone || isLegacy || isMobile || isStrict || isUnderscore) { minify(source, {
// output debug build 'silent': isSilent,
if (!outputPath && !isStdOut) { 'workingName': workingName,
callback(debugSource, path.join(cwd, 'lodash.custom.js')); 'onComplete': function(source) {
// correct overly aggressive Closure Compiler minification
source = source.replace(/prototype\s*=\s*{\s*valueOf\s*:\s*1\s*}/, 'prototype={valueOf:1,y:1}');
// inject "use strict" directive
if (isStrict) {
source = source.replace(/^(\/\*![\s\S]+?\*\/\n;\(function[^)]+\){)([^'"])/, '$1"use strict";$2');
}
if (isStdOut) {
stdout.write(source);
callback(source);
} else {
callback(source, outputPath || path.join(cwd, workingName + '.js'));
}
} }
minify(source, { });
'silent': isSilent,
'workingName': 'lodash.custom.min',
'onComplete': function(source) {
if (isStrict) {
// inject "use strict" directive
source = source.replace(/^(\/\*![\s\S]+?\*\/\n;\(function[^)]+\){)([^'"])/, '$1"use strict";$2');
}
source = postMinify(source);
if (isStdOut) {
stdout.write(source);
callback(source);
} else {
callback(source, outputPath || path.join(cwd, 'lodash.custom.min.js'));
}
}
});
}
else {
minify(source, {
'silent': isSilent,
'workingName': 'lodash.min',
'onComplete': function(source) {
source = postMinify(source);
if (isStdOut) {
stdout.write(source);
callback(source);
} else {
callback(source, outputPath || path.join(cwd, 'lodash.min.js'));
}
}
});
}
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/