Adjust how "mobile" build is created and add first pass at "legacy" build.

Former-commit-id: 740cc40c21d33353f34796ae6da3bc8ce015ab6c
This commit is contained in:
John-David Dalton
2012-07-08 03:28:18 -04:00
parent 83e3f830e6
commit d49318582f

126
build.js
View File

@@ -2,20 +2,43 @@
;(function() { ;(function() {
'use strict'; 'use strict';
/** The Node filesystem and path modules */ /** Load modules */
var fs = require('fs'), var fs = require('fs'),
path = require('path'); path = require('path'),
vm = require('vm'),
/** Load other modules */
var lodash = require(path.join(__dirname, 'lodash')),
minify = require(path.join(__dirname, 'build', 'minify')); minify = require(path.join(__dirname, 'build', 'minify'));
/** Flag used to specify a backbone build */
var isBackbone = process.argv.indexOf('backbone') > -1;
/** Flag used to specify a legacy build */
var isLegacy = process.argv.indexOf('legacy') > -1;
/** Flag used to specify a mobile build */
var isMobile = !isLegacy && process.argv.indexOf('mobile') > -1;
/** Shortcut used to convert array-like objects to arrays */ /** Shortcut used to convert array-like objects to arrays */
var slice = [].slice; var slice = [].slice;
/** The lodash.js source */ /** The lodash.js source */
var source = fs.readFileSync(path.join(__dirname, 'lodash.js'), 'utf8'); var source = fs.readFileSync(path.join(__dirname, 'lodash.js'), 'utf8');
/** Load customized Lo-Dash module */
var lodash = (function() {
var sandbox = {};
if (isLegacy) {
['isBindFast', 'isKeysFast', 'nativeBind', 'nativeIsArray', 'nativeKeys'].forEach(function(varName) {
source = replaceVar(source, varName, 'false');
});
}
else if (isMobile) {
source = replaceVar(source, 'isKeysFast', 'false');
}
vm.runInNewContext(source, sandbox);
return sandbox._;
}());
/** Used to associate aliases with their real names */ /** Used to associate aliases with their real names */
var aliasToRealMap = { var aliasToRealMap = {
'all': 'every', 'all': 'every',
@@ -198,6 +221,7 @@
'hasDontEnumBug', 'hasDontEnumBug',
'inLoop', 'inLoop',
'init', 'init',
'isKeysFast',
'iteratedObject', 'iteratedObject',
'loopExp', 'loopExp',
'object', 'object',
@@ -233,12 +257,6 @@
return pair[1]; return pair[1];
}, ''); }, '');
/** Flag used to specify a backbone build */
var isBackbone = process.argv.indexOf('backbone') > -1;
/** Flag used to specify a mobile build */
var isMobile = process.argv.indexOf('mobile') > -1;
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/** /**
@@ -318,7 +336,7 @@
* @returns {String} Returns the `isArguments` fallback snippet. * @returns {String} Returns the `isArguments` fallback snippet.
*/ */
function getIsArgumentsFallback(source) { function getIsArgumentsFallback(source) {
return (source.match(/(?: *\/\/.*)*\s*if *\(!(?:lodash\.)?isArguments[^)]+\)[\s\S]+?};?\s*}\n/) || [''])[0]; return (source.match(/(?: *\/\/.*)*\s*if *\(!(?:lodash\.)?isArguments[^)]+\)[\s\S]+?};\s*}\n/) || [''])[0];
} }
/** /**
@@ -465,6 +483,31 @@
return removeFromCreateIterator(source, varName); return removeFromCreateIterator(source, varName);
} }
/**
* Searches `source` for a `varName` variable declaration and replaces its
* assigned value with `varValue`.
*
* @private
* @param {String} source The source to inspect.
* @param {String} varName The name of the variable to replace.
* @returns {String} Returns the source with the variable replaced.
*/
function replaceVar(source, varName, varValue) {
// replace a variable that's not part of a declaration list
source = source.replace(RegExp(
'(( +)var ' + varName + ' *= *)' +
'(?:.*?;|(?:Function\\(.+?|.*?[^,])\\n[\\s\\S]+?\\n\\2.+?;)\\n'
), '$1' + varValue + ';\n');
// replace a varaible at the start of middle of a declaration list
source = source.replace(RegExp('((?:var|\\n) +' + varName + ' *=).+?,'), '$1 ' + varValue + ',');
// replace a variable at the end of a variable declaration list
source = source.replace(RegExp('(,\\s*' + varName + ' *=).*?;'), '$1 ' + varValue + ';');
return source;
}
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
// Backbone build // Backbone build
@@ -574,13 +617,12 @@
} }
if (isRemoved(source, 'bind')) { if (isRemoved(source, 'bind')) {
source = removeVar(source, 'nativeBind'); source = removeVar(source, 'nativeBind');
source = removeVar(source, 'useNativeBind'); source = removeVar(source, 'isBindFast');
} }
if (isRemoved(source, 'isArray')) { if (isRemoved(source, 'isArray')) {
source = removeVar(source, 'nativeIsArray'); source = removeVar(source, 'nativeIsArray');
} }
if (isRemoved(source, 'keys')) { if (isRemoved(source, 'keys')) {
source = removeVar(source, 'nativeKeys');
source = removeFunction(source, 'shimKeys'); source = removeFunction(source, 'shimKeys');
} }
if (isRemoved(source, 'clone', 'isObject', 'keys')) { if (isRemoved(source, 'clone', 'isObject', 'keys')) {
@@ -637,6 +679,10 @@
'RegExp': 'regexpClass', 'RegExp': 'regexpClass',
'String': 'stringClass' 'String': 'stringClass'
}, function(value, key) { }, function(value, key) {
// if legacy build skip `isArguments`
if (isLegacy && key == 'Arguments') {
return;
}
var funcName = 'is' + key, var funcName = 'is' + key,
funcCode = matchFunction(source, funcName); funcCode = matchFunction(source, funcName);
@@ -673,7 +719,7 @@
); );
// tweak `isArguments` fallback // tweak `isArguments` fallback
snippet = getIsArgumentsFallback(source); snippet = !isLegacy && getIsArgumentsFallback(source);
if (snippet) { if (snippet) {
result = '\n' + snippet.replace(/isArguments/g, 'lodash.$&'); result = '\n' + snippet.replace(/isArguments/g, 'lodash.$&');
source = source.replace(snippet, result); source = source.replace(snippet, result);
@@ -682,6 +728,29 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
if (isLegacy) {
// replace `_.keys` with `shimKeys`
if (!isRemoved(source, 'keys')) {
source = source.replace(
matchFunction(source, 'keys').replace(/[\s\S]+?var keys *=/, ''),
matchFunction(source, 'shimKeys').replace(/[\s\S]+?var shimKeys *=/, '')
);
source = removeFunction(source, 'shimKeys');
}
// replace `_.isArguments` with fallback
if (!isRemoved(source, 'isArguments')) {
source = source.replace(
matchFunction(source, 'isArguments').replace(/[\s\S]+?var isArguments *=/, ''),
getIsArgumentsFallback(source).match(/isArguments *=([\s\S]+?) *};/)[1] + ' };\n'
);
source = removeIsArgumentsFallback(source);
}
source = removeFromCreateIterator(source, 'nativeKeys');
}
if (isMobile) { if (isMobile) {
// inline functions defined with `createIterator` // inline functions defined with `createIterator`
lodash.functions(lodash).forEach(function(funcName) { lodash.functions(lodash).forEach(function(funcName) {
@@ -696,31 +765,27 @@
source = source.replace(reFunc, '$1' + getFunctionSource(lodash[funcName]) + ';\n'); source = source.replace(reFunc, '$1' + getFunctionSource(lodash[funcName]) + ';\n');
}); });
source = removeIsArgumentsFallback(source);
source = removeVar(source, 'iteratorTemplate');
// remove JScript [[DontEnum]] fix from `isEqual` // remove JScript [[DontEnum]] fix from `isEqual`
source = source.replace(/(?:\s*\/\/.*\n)*( +)if *\(result *&& *hasDontEnumBug[\s\S]+?\n\1}/, ''); source = source.replace(/(?:\s*\/\/.*\n)*( +)if *\(result *&& *hasDontEnumBug[\s\S]+?\n\1}/, '');
// remove IE `shift` and `splice` fix // remove IE `shift` and `splice` fix
source = source.replace(/(?:\s*\/\/.*\n)*( +)if *\(value.length *=== *0[\s\S]+?\n\1}/, ''); source = source.replace(/(?:\s*\/\/.*\n)*( +)if *\(value.length *=== *0[\s\S]+?\n\1}/, '');
// cleanup code source = removeVar(source, 'iteratorTemplate');
source = source.replace(/^ *;\n/gm, ''); source = removeIsArgumentsFallback(source);
} }
else { else {
// inline `iteratorTemplate` template // inline `iteratorTemplate` template
source = source.replace(/(( +)var iteratorTemplate *= *)[\s\S]+?\n\2.+?;\n/, (function() { source = source.replace(/(( +)var iteratorTemplate *= *)[\s\S]+?\n\2.+?;\n/, (function() {
var code = getFunctionSource(lodash._iteratorTemplate); var snippet = getFunctionSource(lodash._iteratorTemplate);
// expand properties to avoid having to use a with-statement // expand properties to avoid having to use a with-statement
iteratorOptions.forEach(function(property) { iteratorOptions.forEach(function(property) {
code = code.replace(RegExp('([^\\w.])\\b' + property + '\\b', 'g'), '$1obj.' + property); snippet = snippet.replace(RegExp('([^\\w.])\\b' + property + '\\b', 'g'), '$1obj.' + property);
}); });
// remove unnecessary code // remove unnecessary code
code = code snippet = snippet
.replace(/, *__t,[^;]+|function print[^}]+}/g, '') .replace(/, *__t,[^;]+|function print[^}]+}/g, '')
.replace(/'(?:\\n|\s)+'/g, "''") .replace(/'(?:\\n|\s)+'/g, "''")
.replace(/__p *\+= *' *';/g, '') .replace(/__p *\+= *' *';/g, '')
@@ -729,17 +794,17 @@
.replace(/\(\(__w?t *= *\( *([^)]+) *\)\) *== *null *\? *'' *: *__w?t\)/g, '$1'); .replace(/\(\(__w?t *= *\( *([^)]+) *\)\) *== *null *\? *'' *: *__w?t\)/g, '$1');
// remove the with-statement // remove the with-statement
code = code.replace(/ *with *\([^)]+\) *{/, '\n').replace(/}}\s*;?\s*}/, '}}\n'); snippet = snippet.replace(/ *with *\([^)]+\) *{/, '\n').replace(/}}\s*;?\s*}/, '}}\n');
// minor cleanup // minor cleanup
code = code snippet = snippet
.replace(/obj *\|\| *\(obj *= *\{}\);/, '') .replace(/obj *\|\| *\(obj *= *\{}\);/, '')
.replace(/var __p;\s*__p/, 'var __p'); .replace(/var __p;\s*__p/, 'var __p');
// remove comments, including sourceURLs // remove comments, including sourceURLs
code = code.replace(/\s*\/\/.*(?:\n|$)/g, ''); snippet = snippet.replace(/\s*\/\/.*(?:\n|$)/g, '');
return '$1' + code + ';\n'; return '$1' + snippet + ';\n';
}())); }()));
} }
@@ -748,8 +813,11 @@
// remove pseudo private properties // remove pseudo private properties
source = source.replace(/(?:(?:\s*\/\/.*)*\s*lodash\._[^=]+=.+\n)+/g, '\n'); source = source.replace(/(?:(?:\s*\/\/.*)*\s*lodash\._[^=]+=.+\n)+/g, '\n');
// cleanup code
source = source.replace(/^ *;\n/gm, '');
// begin the minification process // begin the minification process
if (filterType || isBackbone || isMobile) { if (filterType || isBackbone || isLegacy || isMobile) {
fs.writeFileSync(path.join(__dirname, 'lodash.custom.js'), source); fs.writeFileSync(path.join(__dirname, 'lodash.custom.js'), source);
minify(source, 'lodash.custom.min', function(result) { minify(source, 'lodash.custom.min', function(result) {
fs.writeFileSync(path.join(__dirname, 'lodash.custom.min.js'), result); fs.writeFileSync(path.join(__dirname, 'lodash.custom.min.js'), result);