mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-01-29 06:27:49 +00:00
Remove build from this repo to move to lodash-cli.
Former-commit-id: 0f9e802dd744a97494a10537442a28aae40dc72a
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,5 +6,3 @@
|
||||
*.map
|
||||
modularize
|
||||
node_modules
|
||||
vendor/closure-compiler
|
||||
vendor/uglifyjs
|
||||
|
||||
@@ -11,7 +11,6 @@ lodash.js
|
||||
index.js
|
||||
bower.json
|
||||
component.json
|
||||
build
|
||||
doc
|
||||
modularize
|
||||
node_modules
|
||||
|
||||
@@ -8,15 +8,12 @@ env:
|
||||
- TEST_COMMAND="phantomjs ./test/test.js ../dist/lodash.compat.min.js"
|
||||
- TEST_COMMAND="node ./test/test.js ../dist/lodash.js"
|
||||
- TEST_COMMAND="node ./test/test.js ../dist/lodash.min.js"
|
||||
- TEST_COMMAND="node ./test/test-build.js --time-limit 48m"
|
||||
git:
|
||||
depth: 1
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
before_script:
|
||||
- "tar -xzvf vendor/closure-compiler.tar.gz -C vendor"
|
||||
- "tar -xzvf vendor/uglifyjs.tar.gz -C vendor"
|
||||
- "npm install -g istanbul"
|
||||
script:
|
||||
$TEST_COMMAND
|
||||
|
||||
@@ -11,11 +11,9 @@
|
||||
"*.map",
|
||||
"*.md",
|
||||
"*.txt",
|
||||
"build.js",
|
||||
"index.js",
|
||||
"component.json",
|
||||
"package.json",
|
||||
"build",
|
||||
"doc",
|
||||
"node_modules",
|
||||
"perf",
|
||||
|
||||
793
build/minify.js
793
build/minify.js
@@ -1,793 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
;(function() {
|
||||
'use strict';
|
||||
|
||||
/** Load Node.js modules */
|
||||
var cp = require('child_process'),
|
||||
https = require('https'),
|
||||
zlib = require('zlib');
|
||||
|
||||
/** Load other modules */
|
||||
var _ = require('../lodash.js'),
|
||||
preprocess = require('./pre-compile.js'),
|
||||
postprocess = require('./post-compile.js'),
|
||||
tar = require('../vendor/tar/tar.js'),
|
||||
util = require('./util.js');
|
||||
|
||||
/** Module shortcuts */
|
||||
var fs = util.fs,
|
||||
path = util.path;
|
||||
|
||||
/** The Git object ID of `closure-compiler.tar.gz` */
|
||||
var closureId = '9fd5d61c1b706e7505aeb5187941c2c5497e5fd8';
|
||||
|
||||
/** The Git object ID of `uglifyjs.tar.gz` */
|
||||
var uglifyId = '7de2795a3af58d1b293e3b0e83cdbc994f4941dc';
|
||||
|
||||
/** The path of the directory that is the base of the repository */
|
||||
var basePath = fs.realpathSync(path.join(__dirname, '..'));
|
||||
|
||||
/** The path of the `vendor` directory */
|
||||
var vendorPath = path.join(basePath, 'vendor');
|
||||
|
||||
/** The path to the Closure Compiler `.jar` */
|
||||
var closurePath = path.join(vendorPath, 'closure-compiler', 'compiler.jar');
|
||||
|
||||
/** The path to the UglifyJS module */
|
||||
var uglifyPath = path.join(vendorPath, 'uglifyjs', 'tools', 'node.js');
|
||||
|
||||
/** The Closure Compiler command-line options */
|
||||
var closureOptions = ['--warning_level=QUIET'];
|
||||
|
||||
/** The media type for raw blob data */
|
||||
var mediaType = 'application/vnd.github.v3.raw';
|
||||
|
||||
/** Used to detect the Node.js executable in command-line arguments */
|
||||
var reNode = RegExp('(?:^|' + path.sepEscaped + ')node(?:\\.exe)?$', 'i');
|
||||
|
||||
/** Used to reference parts of the blob href */
|
||||
var location = (function() {
|
||||
var host = 'api.github.com',
|
||||
origin = 'https://api.github.com',
|
||||
pathname = '/repos/bestiejs/lodash/git/blobs';
|
||||
|
||||
return {
|
||||
'host': host,
|
||||
'href': origin + pathname,
|
||||
'origin': origin,
|
||||
'pathname': pathname
|
||||
};
|
||||
}());
|
||||
|
||||
/** The Closure Compiler optimization modes */
|
||||
var optimizationModes = {
|
||||
'simple': 'SIMPLE_OPTIMIZATIONS',
|
||||
'advanced': 'ADVANCED_OPTIMIZATIONS'
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Minifies a given Lo-Dash `source` and invokes the `options.onComplete`
|
||||
* callback when finished. The `onComplete` callback is invoked with one
|
||||
* argument; (outputSource).
|
||||
*
|
||||
* @param {string|string[]} [source=''] The source to minify or array of commands.
|
||||
* -o, --output - Write output to a given path/filename.
|
||||
* -s, --silent - Skip status updates normally logged to the console.
|
||||
* -t, --template - Applies template specific minifier options.
|
||||
*
|
||||
* @param {Object} [options={}] The options object.
|
||||
* @param {string} [options.outputPath] Write output to a given path/filename.
|
||||
* @param {boolean} [options.isSilent] Skip status updates normally logged to the console.
|
||||
* @param {boolean} [options.isTemplate] Applies template specific minifier options.
|
||||
* @param {Function} [options.onComplete] The function called once minification has finished.
|
||||
*/
|
||||
function minify(source, options) {
|
||||
// used to specify the source map URL
|
||||
var sourceMapURL;
|
||||
|
||||
// used to specify the default minifer modes
|
||||
var modes = ['simple', 'advanced', 'hybrid'];
|
||||
|
||||
source || (source = '');
|
||||
options || (options = {});
|
||||
|
||||
// juggle arguments
|
||||
if (Array.isArray(source)) {
|
||||
// convert commands to an options object
|
||||
options = source;
|
||||
|
||||
// used to report invalid command-line arguments
|
||||
var invalidArgs = _.reject(options.slice(reNode.test(options[0]) ? 2 : 0), function(value, index, options) {
|
||||
if (/^(?:-o|--output)$/.test(options[index - 1]) ||
|
||||
/^modes=.*$/.test(value)) {
|
||||
return true;
|
||||
}
|
||||
var result = [
|
||||
'-o', '--output',
|
||||
'-p', '--source-map',
|
||||
'-s', '--silent',
|
||||
'-t', '--template'
|
||||
].indexOf(value) > -1;
|
||||
|
||||
if (!result && /^(?:-p|--source-map)$/.test(options[index - 1])) {
|
||||
result = true;
|
||||
sourceMapURL = value;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
// report invalid arguments
|
||||
if (invalidArgs.length) {
|
||||
console.log(
|
||||
'\n' +
|
||||
'Invalid argument' + (invalidArgs.length > 1 ? 's' : '') +
|
||||
' passed: ' + invalidArgs.join(', ')
|
||||
);
|
||||
return;
|
||||
}
|
||||
var filePath = options[options.length - 1],
|
||||
isMapped = _.contains(options, '-p') || _.contains(options, '--source-map'),
|
||||
isSilent = _.contains(options, '-s') || _.contains(options, '--silent'),
|
||||
isTemplate = _.contains(options, '-t') || _.contains(options, '--template'),
|
||||
outputPath = path.join(path.dirname(filePath), path.basename(filePath, '.js') + '.min.js');
|
||||
|
||||
modes = options.reduce(function(result, value) {
|
||||
var match = value.match(/modes=(.*)$/);
|
||||
return match ? match[1].split(/, */) : result;
|
||||
}, modes);
|
||||
|
||||
outputPath = options.reduce(function(result, value, index) {
|
||||
if (/-o|--output/.test(value)) {
|
||||
result = options[index + 1];
|
||||
var dirname = path.dirname(result);
|
||||
fs.mkdirpSync(dirname);
|
||||
result = path.join(fs.realpathSync(dirname), path.basename(result));
|
||||
}
|
||||
return result;
|
||||
}, outputPath);
|
||||
|
||||
options = {
|
||||
'filePath': filePath,
|
||||
'isMapped': isMapped,
|
||||
'isSilent': isSilent,
|
||||
'isTemplate': isTemplate,
|
||||
'modes': modes,
|
||||
'outputPath': outputPath,
|
||||
'sourceMapURL': sourceMapURL
|
||||
};
|
||||
|
||||
source = fs.readFileSync(filePath, 'utf8');
|
||||
}
|
||||
|
||||
modes = options.modes || modes;
|
||||
if (options.isMapped) {
|
||||
modes = modes.filter(function(mode) {
|
||||
return mode != 'hybrid';
|
||||
});
|
||||
}
|
||||
if (options.isTemplate) {
|
||||
modes = modes.filter(function(mode) {
|
||||
return mode != 'advanced';
|
||||
});
|
||||
}
|
||||
options.modes = modes;
|
||||
|
||||
// fetch the Closure Compiler
|
||||
getDependency({
|
||||
'id': 'closure-compiler',
|
||||
'hashId': closureId,
|
||||
'path': vendorPath,
|
||||
'title': 'the Closure Compiler',
|
||||
'onComplete': function(exception) {
|
||||
var error = exception;
|
||||
|
||||
// fetch UglifyJS
|
||||
getDependency({
|
||||
'id': 'uglifyjs',
|
||||
'hashId': uglifyId,
|
||||
'title': 'UglifyJS',
|
||||
'path': vendorPath,
|
||||
'onComplete': function(exception) {
|
||||
error || (error = exception);
|
||||
if (!error) {
|
||||
new Minify(source, options);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The Minify constructor used to keep state of each `minify` invocation.
|
||||
*
|
||||
* @private
|
||||
* @constructor
|
||||
* @param {string} source The source to minify.
|
||||
* @param {Object} options The options object.
|
||||
* outputPath - Write output to a given path/filename.
|
||||
* isSilent - Skip status updates normally logged to the console.
|
||||
* isTemplate - Applies template specific minifier options.
|
||||
* onComplete - The function called once minification has finished.
|
||||
*/
|
||||
function Minify(source, options) {
|
||||
// juggle arguments
|
||||
if (typeof source == 'object' && source) {
|
||||
options = source || options;
|
||||
source = options.source || '';
|
||||
}
|
||||
this.compiled = { 'simple': {}, 'advanced': {} };
|
||||
this.hybrid = { 'simple': {}, 'advanced': {} };
|
||||
this.uglified = {};
|
||||
|
||||
this.filePath = options.filePath;
|
||||
this.isMapped = !!options.isMapped;
|
||||
this.isSilent = !!options.isSilent;
|
||||
this.isTemplate = !!options.isTemplate;
|
||||
this.outputPath = options.outputPath;
|
||||
this.sourceMapURL = options.sourceMapURL;
|
||||
|
||||
var modes = this.modes = options.modes;
|
||||
source = this.source = preprocess(source, options);
|
||||
|
||||
this.onComplete = options.onComplete || function(data) {
|
||||
var outputPath = this.outputPath,
|
||||
sourceMap = data.sourceMap;
|
||||
|
||||
fs.writeFileSync(outputPath, data.source, 'utf8');
|
||||
if (sourceMap) {
|
||||
fs.writeFileSync(getMapPath(outputPath), sourceMap, 'utf8');
|
||||
}
|
||||
};
|
||||
|
||||
// begin the minification process
|
||||
if (_.contains(modes, 'simple')) {
|
||||
closureCompile.call(this, source, 'simple', onClosureSimpleCompile.bind(this));
|
||||
} else if (_.contains(modes, 'advanced')) {
|
||||
onClosureSimpleGzip.call(this);
|
||||
} else {
|
||||
onClosureAdvancedGzip.call(this);
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Fetches a required `.tar.gz` dependency with the given Git object ID from
|
||||
* the Lo-Dash repo on GitHub. The object ID may be obtained by running
|
||||
* `git hash-object path/to/dependency.tar.gz`.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} options The options object.
|
||||
* id - The Git object ID of the `.tar.gz` file.
|
||||
* onComplete - The function called once the extraction has finished.
|
||||
* path - The path of the extraction directory.
|
||||
* title - The dependency's title used in status updates logged to the console.
|
||||
*/
|
||||
function getDependency(options) {
|
||||
options || (options = {});
|
||||
|
||||
var ran,
|
||||
destPath = options.path,
|
||||
hashId = options.hashId,
|
||||
id = options.id,
|
||||
onComplete = options.onComplete,
|
||||
title = options.title;
|
||||
|
||||
// exit early if dependency exists
|
||||
if (fs.existsSync(path.join(destPath, id))) {
|
||||
onComplete();
|
||||
return;
|
||||
}
|
||||
var callback = function(exception) {
|
||||
if (ran) {
|
||||
return;
|
||||
}
|
||||
if (exception) {
|
||||
console.error([
|
||||
'There was a problem installing ' + title + '.',
|
||||
'Try running the command as root, via `sudo`, or manually install by running:',
|
||||
'',
|
||||
"curl -H 'Accept: " + mediaType + "' " + location.href + '/' + hashId + " | tar xvz -C '" + destPath + "'",
|
||||
''
|
||||
].join('\n'));
|
||||
}
|
||||
ran = true;
|
||||
process.removeListener('uncaughtException', callback);
|
||||
onComplete(exception);
|
||||
};
|
||||
|
||||
console.log('Downloading ' + title + '...');
|
||||
process.on('uncaughtException', callback);
|
||||
|
||||
https.get({
|
||||
'host': location.host,
|
||||
'path': location.pathname + '/' + hashId,
|
||||
'headers': {
|
||||
// By default, all GitHub blob API endpoints return a JSON document
|
||||
// containing Base64-encoded blob data. Overriding the `Accept` header
|
||||
// with the GitHub raw media type returns the blob data directly.
|
||||
// See http://developer.github.com/v3/media/.
|
||||
'Accept': mediaType,
|
||||
// As of 2013-04-24, the GitHub API mandates the `User-Agent` header
|
||||
// for all requests.
|
||||
'User-Agent': 'Lo-Dash/' + _.VERSION
|
||||
}
|
||||
}, function(response) {
|
||||
var decompressor = zlib.createUnzip(),
|
||||
parser = new tar.Extract({ 'path': destPath });
|
||||
|
||||
parser.on('end', callback);
|
||||
response.pipe(decompressor).pipe(parser);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Java command-line options used for faster minification by
|
||||
* the Closure Compiler, invoking the `callback` when finished. Subsequent
|
||||
* calls will lazily return the previously retrieved options. The `callback`
|
||||
* is invoked with one argument; (options).
|
||||
*
|
||||
* See https://code.google.com/p/closure-compiler/wiki/FAQ#What_are_the_recommended_Java_VM_command-line_options?.
|
||||
*
|
||||
* @private
|
||||
* @param {Function} callback The function called once the options have been retrieved.
|
||||
*/
|
||||
function getJavaOptions(callback) {
|
||||
var result = [];
|
||||
cp.exec('java -version -client -d32', function(error) {
|
||||
if (!error && process.platform != 'win32') {
|
||||
result.push('-client', '-d32');
|
||||
}
|
||||
getJavaOptions = function(callback) {
|
||||
_.defer(callback, result);
|
||||
};
|
||||
callback(result);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the source map path from the given output path.
|
||||
*
|
||||
* @private
|
||||
* @param {string} outputPath The output path.
|
||||
* @returns {string} Returns the source map path.
|
||||
*/
|
||||
function getMapPath(outputPath) {
|
||||
return path.join(path.dirname(outputPath), path.basename(outputPath, '.js') + '.map');
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Compresses a `source` string using the Closure Compiler. Yields the
|
||||
* minified result, and any exceptions encountered, to a `callback` function.
|
||||
*
|
||||
* @private
|
||||
* @param {string} source The JavaScript source to minify.
|
||||
* @param {string} mode The optimization mode.
|
||||
* @param {Function} callback The function called once the process has completed.
|
||||
*/
|
||||
function closureCompile(source, mode, callback) {
|
||||
var filePath = this.filePath,
|
||||
isAdvanced = mode == 'advanced',
|
||||
isMapped = this.isMapped,
|
||||
isSilent = this.isSilent,
|
||||
isTemplate = this.isTemplate,
|
||||
options = closureOptions.slice(),
|
||||
outputPath = this.outputPath,
|
||||
mapPath = getMapPath(outputPath),
|
||||
sourceMapURL = this.sourceMapURL || path.basename(mapPath);
|
||||
|
||||
// remove copyright header to make other modifications easier
|
||||
var license = (/^(?:\s*\/\/.*\s*|\s*\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/\s*)*/.exec(source) || [''])[0];
|
||||
if (license) {
|
||||
source = source.replace(license, '');
|
||||
}
|
||||
|
||||
var hasIIFE = /^;?\(function[^{]+{/.test(source),
|
||||
isStrict = hasIIFE && /^;?\(function[^{]+{\s*["']use strict["']/.test(source);
|
||||
|
||||
// to avoid stripping the IIFE, convert it to a function call
|
||||
if (hasIIFE && isAdvanced) {
|
||||
source = source
|
||||
.replace(/\(function/, '__iife__$&')
|
||||
.replace(/\(this\)\)([\s;]*(\n\/\/.+)?)$/, ', this)$1');
|
||||
}
|
||||
|
||||
options.push('--compilation_level=' + optimizationModes[mode]);
|
||||
if (isMapped) {
|
||||
options.push('--create_source_map=' + mapPath, '--source_map_format=V3');
|
||||
}
|
||||
if (isTemplate) {
|
||||
options.push('--charset=UTF-8');
|
||||
}
|
||||
|
||||
getJavaOptions(function(javaOptions) {
|
||||
var compiler = cp.spawn('java', javaOptions.concat('-jar', closurePath, options));
|
||||
if (!isSilent) {
|
||||
console.log('Compressing ' + path.basename(outputPath, '.js') + ' using the Closure Compiler (' + mode + ')...');
|
||||
}
|
||||
|
||||
var error = '';
|
||||
compiler.stderr.on('data', function(data) {
|
||||
error += data;
|
||||
});
|
||||
|
||||
var output = '';
|
||||
compiler.stdout.on('data', function(data) {
|
||||
output += data;
|
||||
});
|
||||
|
||||
compiler.on('exit', function(status) {
|
||||
// `status` contains the process exit code
|
||||
if (status) {
|
||||
var exception = new Error(error);
|
||||
exception.status = status;
|
||||
}
|
||||
// restore IIFE and move exposed vars inside the IIFE
|
||||
if (hasIIFE && isAdvanced) {
|
||||
output = output
|
||||
.replace(/__iife__\(/, '(')
|
||||
.replace(/,\s*this\)([\s;]*(\n\/\/.+)?)$/, '(this))$1')
|
||||
.replace(/^((?:var (?:\w+=(?:!0|!1|null)[,;])+)?)([\s\S]*?function[^{]+{)/, '$2$1');
|
||||
}
|
||||
// inject "use strict" directive
|
||||
if (isStrict) {
|
||||
output = output.replace(/^[\s\S]*?function[^{]+{/, '$&"use strict";');
|
||||
}
|
||||
// restore copyright header
|
||||
if (license) {
|
||||
output = license + output;
|
||||
}
|
||||
if (isMapped) {
|
||||
var mapOutput = fs.readFileSync(mapPath, 'utf8');
|
||||
fs.unlinkSync(mapPath);
|
||||
output = output.replace(/[\s;]*$/, '\n//# sourceMappingURL=' + sourceMapURL);
|
||||
|
||||
mapOutput = JSON.parse(mapOutput);
|
||||
mapOutput.file = path.basename(outputPath);
|
||||
mapOutput.sources = [path.basename(filePath)];
|
||||
mapOutput = JSON.stringify(mapOutput, null, 2);
|
||||
}
|
||||
callback(exception, output, mapOutput);
|
||||
});
|
||||
|
||||
// proxy the standard input to the Closure Compiler
|
||||
compiler.stdin.end(source);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses a `source` string using UglifyJS. Yields the result to a
|
||||
* `callback` function. This function is synchronous; the `callback` is used
|
||||
* for symmetry.
|
||||
*
|
||||
* @private
|
||||
* @param {string} source The JavaScript source to minify.
|
||||
* @param {string} label The label to log.
|
||||
* @param {Function} callback The function called once the process has completed.
|
||||
*/
|
||||
function uglify(source, label, callback) {
|
||||
if (!this.isSilent) {
|
||||
console.log('Compressing ' + path.basename(this.outputPath, '.js') + ' using ' + label + '...');
|
||||
}
|
||||
try {
|
||||
var uglifyJS = require(uglifyPath);
|
||||
|
||||
// 1. parse
|
||||
var toplevel = uglifyJS.parse(source);
|
||||
|
||||
// 2. compress
|
||||
// enable unsafe comparisons
|
||||
toplevel.figure_out_scope();
|
||||
toplevel = toplevel.transform(uglifyJS.Compressor({
|
||||
'comparisons': false,
|
||||
'unsafe': true,
|
||||
'unsafe_comps': true,
|
||||
'warnings': false
|
||||
}));
|
||||
|
||||
// 3. mangle
|
||||
// excluding the `define` function exposed by AMD loaders
|
||||
toplevel.figure_out_scope();
|
||||
toplevel.compute_char_frequency();
|
||||
toplevel.mangle_names({
|
||||
'except': ['define']
|
||||
});
|
||||
|
||||
// 4. output
|
||||
// restrict lines to 500 characters for consistency with the Closure Compiler
|
||||
var stream = uglifyJS.OutputStream({
|
||||
'ascii_only': !this.isTemplate,
|
||||
'comments': /^!|@cc_on|@license|@preserve/i,
|
||||
'max_line_len': 500,
|
||||
});
|
||||
|
||||
toplevel.print(stream);
|
||||
}
|
||||
catch(e) {
|
||||
var exception = e;
|
||||
}
|
||||
callback(exception, stream && String(stream));
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* The Closure Compiler callback for simple optimizations.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} [exception] The error object.
|
||||
* @param {string} result The resulting minified source.
|
||||
* @param {string} map The source map output.
|
||||
*/
|
||||
function onClosureSimpleCompile(exception, result, map) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
result = postprocess(result);
|
||||
|
||||
var simple = this.compiled.simple;
|
||||
simple.source = result;
|
||||
simple.sourceMap = map;
|
||||
zlib.gzip(result, onClosureSimpleGzip.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* The Closure Compiler `gzip` callback for simple optimizations.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} [exception] The error object.
|
||||
* @param {Buffer} result The resulting gzipped source.
|
||||
*/
|
||||
function onClosureSimpleGzip(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
if (result != null) {
|
||||
if (!this.isSilent) {
|
||||
console.log('Done. Size: %d bytes.', result.length);
|
||||
}
|
||||
this.compiled.simple.gzip = result;
|
||||
}
|
||||
// compile the source using advanced optimizations
|
||||
if (_.contains(this.modes, 'advanced')) {
|
||||
closureCompile.call(this, this.source, 'advanced', onClosureAdvancedCompile.bind(this));
|
||||
} else {
|
||||
onClosureAdvancedGzip.call(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Closure Compiler callback for advanced optimizations.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} [exception] The error object.
|
||||
* @param {string} result The resulting minified source.
|
||||
* @param {string} map The source map output.
|
||||
*/
|
||||
function onClosureAdvancedCompile(exception, result, map) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
result = postprocess(result);
|
||||
|
||||
var advanced = this.compiled.advanced;
|
||||
advanced.source = result;
|
||||
advanced.sourceMap = map;
|
||||
zlib.gzip(result, onClosureAdvancedGzip.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* The Closure Compiler `gzip` callback for advanced optimizations.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} [exception] The error object.
|
||||
* @param {Buffer} result The resulting gzipped source.
|
||||
*/
|
||||
function onClosureAdvancedGzip(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
if (result != null) {
|
||||
if (!this.isSilent) {
|
||||
console.log('Done. Size: %d bytes.', result.length);
|
||||
}
|
||||
this.compiled.advanced.gzip = result;
|
||||
}
|
||||
// minify the source using UglifyJS
|
||||
if (!this.isMapped) {
|
||||
uglify.call(this, this.source, 'UglifyJS', onUglify.bind(this));
|
||||
} else {
|
||||
onComplete.call(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The UglifyJS callback.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} [exception] The error object.
|
||||
* @param {string} result The resulting minified source.
|
||||
*/
|
||||
function onUglify(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
result = postprocess(result);
|
||||
this.uglified.source = result;
|
||||
zlib.gzip(result, onUglifyGzip.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* The UglifyJS `gzip` callback.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} [exception] The error object.
|
||||
* @param {Buffer} result The resulting gzipped source.
|
||||
*/
|
||||
function onUglifyGzip(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
if (result != null) {
|
||||
if (!this.isSilent) {
|
||||
console.log('Done. Size: %d bytes.', result.length);
|
||||
}
|
||||
this.uglified.gzip = result;
|
||||
}
|
||||
// minify the already Closure Compiler simple optimized source using UglifyJS
|
||||
var modes = this.modes;
|
||||
if (_.contains(modes, 'hybrid')) {
|
||||
if (_.contains(modes, 'simple')) {
|
||||
uglify.call(this, this.compiled.simple.source, 'hybrid (simple)', onSimpleHybrid.bind(this));
|
||||
} else if (_.contains(modes, 'advanced')) {
|
||||
onSimpleHybridGzip.call(this);
|
||||
}
|
||||
} else {
|
||||
onComplete.call(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The hybrid callback for simple optimizations.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} [exception] The error object.
|
||||
* @param {string} result The resulting minified source.
|
||||
*/
|
||||
function onSimpleHybrid(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
result = postprocess(result);
|
||||
this.hybrid.simple.source = result;
|
||||
zlib.gzip(result, onSimpleHybridGzip.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* The hybrid `gzip` callback for simple optimizations.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} [exception] The error object.
|
||||
* @param {Buffer} result The resulting gzipped source.
|
||||
*/
|
||||
function onSimpleHybridGzip(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
if (result != null) {
|
||||
if (!this.isSilent) {
|
||||
console.log('Done. Size: %d bytes.', result.length);
|
||||
}
|
||||
this.hybrid.simple.gzip = result;
|
||||
}
|
||||
// minify the already Closure Compiler advance optimized source using UglifyJS
|
||||
if (_.contains(this.modes, 'advanced')) {
|
||||
uglify.call(this, this.compiled.advanced.source, 'hybrid (advanced)', onAdvancedHybrid.bind(this));
|
||||
} else {
|
||||
onComplete.call(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The hybrid callback for advanced optimizations.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} [exception] The error object.
|
||||
* @param {string} result The resulting minified source.
|
||||
*/
|
||||
function onAdvancedHybrid(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
result = postprocess(result);
|
||||
this.hybrid.advanced.source = result;
|
||||
zlib.gzip(result, onAdvancedHybridGzip.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* The hybrid `gzip` callback for advanced optimizations.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} [exception] The error object.
|
||||
* @param {Buffer} result The resulting gzipped source.
|
||||
*/
|
||||
function onAdvancedHybridGzip(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
if (result != null) {
|
||||
if (!this.isSilent) {
|
||||
console.log('Done. Size: %d bytes.', result.length);
|
||||
}
|
||||
this.hybrid.advanced.gzip = result;
|
||||
}
|
||||
// finish by choosing the smallest compressed file
|
||||
onComplete.call(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* The callback executed after the source is minified and gzipped.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function onComplete() {
|
||||
var compiledSimple = this.compiled.simple,
|
||||
compiledAdvanced = this.compiled.advanced,
|
||||
uglified = this.uglified,
|
||||
hybridSimple = this.hybrid.simple,
|
||||
hybridAdvanced = this.hybrid.advanced;
|
||||
|
||||
var objects = [
|
||||
compiledSimple,
|
||||
compiledAdvanced,
|
||||
uglified,
|
||||
hybridSimple,
|
||||
hybridAdvanced
|
||||
];
|
||||
|
||||
var gzips = objects
|
||||
.map(function(data) { return data.gzip; })
|
||||
.filter(Boolean);
|
||||
|
||||
// select the smallest gzipped file and use its minified counterpart as the
|
||||
// official minified release (ties go to the Closure Compiler)
|
||||
var min = gzips.reduce(function(min, gzip) {
|
||||
var length = gzip.length;
|
||||
return min > length ? length : min;
|
||||
}, Infinity);
|
||||
|
||||
// pass the minified source to the "onComplete" callback
|
||||
objects.some(function(data) {
|
||||
var gzip = data.gzip;
|
||||
if (gzip && gzip.length == min) {
|
||||
data.outputPath = this.outputPath;
|
||||
this.onComplete(data);
|
||||
return true;
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// expose `minify`
|
||||
if (module != require.main) {
|
||||
module.exports = minify;
|
||||
}
|
||||
else {
|
||||
// read the Lo-Dash source file from the first argument if the script
|
||||
// was invoked directly (e.g. `node minify.js source.js`) and write to
|
||||
// `<filename>.min.js`
|
||||
(function() {
|
||||
var options = process.argv;
|
||||
if (options.length < 3) {
|
||||
return;
|
||||
}
|
||||
minify(options);
|
||||
}());
|
||||
}
|
||||
}());
|
||||
@@ -1,117 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
;(function() {
|
||||
'use strict';
|
||||
|
||||
/** Load Node.js modules */
|
||||
var fs = require('fs'),
|
||||
vm = require('vm');
|
||||
|
||||
/** The minimal license/copyright template */
|
||||
var licenseTemplate = [
|
||||
'/**',
|
||||
' * @license',
|
||||
' * Lo-Dash <%= VERSION %> lodash.com/license | Underscore.js 1.5.1 underscorejs.org/LICENSE',
|
||||
' */'
|
||||
].join('\n');
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Post-process a given minified Lo-Dash `source`, preparing it for
|
||||
* deployment.
|
||||
*
|
||||
* @param {string} source The source to process.
|
||||
* @returns {string} Returns the processed source.
|
||||
*/
|
||||
function postprocess(source) {
|
||||
// correct overly aggressive Closure Compiler advanced optimization
|
||||
source = source
|
||||
.replace(/(document[^&]+&&)\s*(?:\w+|!\d)/, '$1!({toString:0}+"")')
|
||||
.replace(/"\t"/g, '"\\t"')
|
||||
.replace(/"[^"]*?\\f[^"]*?"/g,
|
||||
'" \\t\\x0B\\f\\xa0\\ufeff' +
|
||||
'\\n\\r\\u2028\\u2029' +
|
||||
'\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000"'
|
||||
);
|
||||
|
||||
try {
|
||||
var context = vm.createContext({});
|
||||
vm.runInContext(source, context);
|
||||
} catch(e) { }
|
||||
|
||||
['forEach', 'forIn', 'forOwn'].forEach(function(methodName) {
|
||||
var pairs = /[!=]==\s*([a-zA-Z]+)(?!\()|([a-zA-Z]+)\s*[!=]==/.exec((context._ || {})[methodName]),
|
||||
varName = pairs && (pairs[1] || pairs[2]),
|
||||
value = (value = varName && RegExp('\\b' + varName + '\\s*=\\s*!([01])\\b').exec(source)) && !+value[1];
|
||||
|
||||
if (typeof value == 'boolean') {
|
||||
// replace vars for `false` and `true` with boolean literals
|
||||
source = source.replace(RegExp('([!=]==\\s*)' + varName + '\\b(?!\\()|\\b' + varName + '(\\s*[!=]==)', 'g'), function(match, prelude, postlude, at) {
|
||||
// avoid replacing local variables with the same name
|
||||
return RegExp('\\b' + varName + '\\s*(?:,|=[^=])').test(source.slice(at - 10, at))
|
||||
? match
|
||||
: (prelude || '') + value + (postlude || '');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// replace `!1` and `!0` in expressions with `false` and `true` values
|
||||
[/([!=]==)\s*!1\b|(.)!1\s*([!=]==)/g, /([!=]==)\s*!0\b|(.)!0\s*([!=]==)/g].forEach(function(regexp, index) {
|
||||
source = source.replace(regexp, function(match, prelude, chr, postlude) {
|
||||
return (prelude || chr + (/\w/.test(chr) ? ' ' : '')) + !!index + (postlude || '');
|
||||
});
|
||||
});
|
||||
|
||||
// flip `typeof` expressions to help optimize Safari and
|
||||
// correct the AMD module definition for AMD build optimizers
|
||||
// (e.g. from `"number" == typeof x` to `typeof x == "number")
|
||||
source = source.replace(/(\w)?("[^"]+")\s*([!=]=)\s*(typeof(?:\s*\([^)]+\)|\s+[.\w]+(?!\[)))/g, function(match, other, type, equality, expression) {
|
||||
return (other ? other + ' ' : '') + expression + equality + type;
|
||||
});
|
||||
|
||||
// add a space so `define` is detected by the Dojo builder
|
||||
source = source.replace(/(.)(define\()/, function(match, prelude, define) {
|
||||
return prelude + (/^\S/.test(prelude) ? ' ' : '') + define;
|
||||
});
|
||||
|
||||
// add trailing semicolon
|
||||
if (source) {
|
||||
source = source.replace(/[\s;]*?(\s*\/\/.*\s*|\s*\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/\s*)*$/, ';$1');
|
||||
}
|
||||
// exit early if version snippet isn't found
|
||||
var snippet = /VERSION\s*[=:]\s*([\'"])(.*?)\1/.exec(source);
|
||||
if (!snippet) {
|
||||
return source;
|
||||
}
|
||||
// remove copyright header
|
||||
source = source.replace(/^\/\**[\s\S]+?\*\/\n/, '');
|
||||
|
||||
// add new copyright header
|
||||
var version = snippet[2];
|
||||
source = licenseTemplate.replace('<%= VERSION %>', version) + '\n;' + source;
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// expose `postprocess`
|
||||
if (module != require.main) {
|
||||
module.exports = postprocess;
|
||||
}
|
||||
else {
|
||||
// read the Lo-Dash source file from the first argument if the script
|
||||
// was invoked directly (e.g. `node post-compile.js source.js`) and write to
|
||||
// the same file
|
||||
(function() {
|
||||
var options = process.argv;
|
||||
if (options.length < 3) {
|
||||
return;
|
||||
}
|
||||
var filePath = options[options.length - 1],
|
||||
source = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
fs.writeFileSync(filePath, postprocess(source), 'utf8');
|
||||
}());
|
||||
}
|
||||
}());
|
||||
@@ -1,461 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
;(function() {
|
||||
'use strict';
|
||||
|
||||
/** The Node.js filesystem module */
|
||||
var fs = require('fs');
|
||||
|
||||
/** Used to minify variables embedded in compiled strings */
|
||||
var compiledVars = [
|
||||
'args',
|
||||
'argsIndex',
|
||||
'argsLength',
|
||||
'baseCreateCallback',
|
||||
'callback',
|
||||
'className',
|
||||
'collection',
|
||||
'conditions',
|
||||
'ctor',
|
||||
'errorClass',
|
||||
'errorProto',
|
||||
'guard',
|
||||
'hasOwnProperty',
|
||||
'index',
|
||||
'indicatorObject',
|
||||
'isArguments',
|
||||
'isArray',
|
||||
'isProto',
|
||||
'isString',
|
||||
'iterable',
|
||||
'length',
|
||||
'keys',
|
||||
'lodash',
|
||||
'nonEnum',
|
||||
'nonEnumProps',
|
||||
'object',
|
||||
'objectProto',
|
||||
'objectTypes',
|
||||
'ownIndex',
|
||||
'ownProps',
|
||||
'result',
|
||||
'skipErrorProps',
|
||||
'skipProto',
|
||||
'source',
|
||||
'stringClass',
|
||||
'stringProto',
|
||||
'thisArg',
|
||||
'toString'
|
||||
];
|
||||
|
||||
/** Used to minify `iteratorTemplate` data properties */
|
||||
var iteratorOptions = [
|
||||
'args',
|
||||
'array',
|
||||
'bottom',
|
||||
'firstArg',
|
||||
'init',
|
||||
'keys',
|
||||
'loop',
|
||||
'shadowedProps',
|
||||
'top',
|
||||
'useHas'
|
||||
];
|
||||
|
||||
/** Used to minify variables and string values to a single character */
|
||||
var minNames = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
|
||||
minNames.push.apply(minNames, minNames.map(function(value) {
|
||||
return value + value;
|
||||
}));
|
||||
|
||||
/** Used to protect the specified properties from getting minified */
|
||||
var propWhitelist = [
|
||||
'Array',
|
||||
'Boolean',
|
||||
'Date',
|
||||
'Error',
|
||||
'Function',
|
||||
'Math',
|
||||
'Number',
|
||||
'Object',
|
||||
'RegExp',
|
||||
'String',
|
||||
'TypeError',
|
||||
'VERSION',
|
||||
'_',
|
||||
'__bindData__',
|
||||
'__chain__',
|
||||
'__wrapped__',
|
||||
'after',
|
||||
'all',
|
||||
'amd',
|
||||
'any',
|
||||
'argsClass',
|
||||
'argsObject',
|
||||
'array',
|
||||
'assign',
|
||||
'at',
|
||||
'attachEvent',
|
||||
'bind',
|
||||
'bindAll',
|
||||
'bindKey',
|
||||
'cache',
|
||||
'chain',
|
||||
'clearTimeout',
|
||||
'clone',
|
||||
'cloneDeep',
|
||||
'collect',
|
||||
'compact',
|
||||
'compose',
|
||||
'configurable',
|
||||
'contains',
|
||||
'countBy',
|
||||
'createCallback',
|
||||
'criteria',
|
||||
'curry',
|
||||
'debounce',
|
||||
'defaults',
|
||||
'defer',
|
||||
'delay',
|
||||
'detect',
|
||||
'difference',
|
||||
'drop',
|
||||
'each',
|
||||
'enumerable',
|
||||
'enumErrorProps',
|
||||
'enumPrototypes',
|
||||
'environment',
|
||||
'escape',
|
||||
'evaluate',
|
||||
'every',
|
||||
'exports',
|
||||
'extend',
|
||||
'fastBind',
|
||||
'fastKeys',
|
||||
'filter',
|
||||
'find',
|
||||
'findIndex',
|
||||
'findKey',
|
||||
'findLast',
|
||||
'findLastIndex',
|
||||
'findLastKey',
|
||||
'findWhere',
|
||||
'first',
|
||||
'flatten',
|
||||
'foldl',
|
||||
'foldr',
|
||||
'forEach',
|
||||
'forEachRight',
|
||||
'forIn',
|
||||
'forInRight',
|
||||
'forOwn',
|
||||
'forOwnRight',
|
||||
'function',
|
||||
'functions',
|
||||
'global',
|
||||
'groupBy',
|
||||
'has',
|
||||
'head',
|
||||
'identity',
|
||||
'imports',
|
||||
'include',
|
||||
'index',
|
||||
'indexBy',
|
||||
'indexOf',
|
||||
'initial',
|
||||
'inject',
|
||||
'interpolate',
|
||||
'intersection',
|
||||
'invert',
|
||||
'invoke',
|
||||
'isArguments',
|
||||
'isArray',
|
||||
'isBoolean',
|
||||
'isDate',
|
||||
'isElement',
|
||||
'isEmpty',
|
||||
'isEqual',
|
||||
'isEqual',
|
||||
'isFinite',
|
||||
'isFinite',
|
||||
'isFunction',
|
||||
'isNaN',
|
||||
'isNull',
|
||||
'isNumber',
|
||||
'isObject',
|
||||
'isPlainObject',
|
||||
'isRegExp',
|
||||
'isString',
|
||||
'isUndefined',
|
||||
'keys',
|
||||
'last',
|
||||
'lastIndexOf',
|
||||
'leading',
|
||||
'map',
|
||||
'max',
|
||||
'maxWait',
|
||||
'memoize',
|
||||
'merge',
|
||||
'methods',
|
||||
'min',
|
||||
'mixin',
|
||||
'name',
|
||||
'noConflict',
|
||||
'nodeClass',
|
||||
'nonEnumArgs',
|
||||
'nonEnumShadows',
|
||||
'now',
|
||||
'null',
|
||||
'number',
|
||||
'object',
|
||||
'omit',
|
||||
'once',
|
||||
'ownLast',
|
||||
'pairs',
|
||||
'parseInt',
|
||||
'partial',
|
||||
'partialRight',
|
||||
'pick',
|
||||
'pluck',
|
||||
'pull',
|
||||
'random',
|
||||
'range',
|
||||
'reduce',
|
||||
'reduceRight',
|
||||
'reject',
|
||||
'remove',
|
||||
'rest',
|
||||
'result',
|
||||
'runInContext',
|
||||
'sample',
|
||||
'select',
|
||||
'setImmediate',
|
||||
'setTimeout',
|
||||
'shuffle',
|
||||
'size',
|
||||
'some',
|
||||
'sortBy',
|
||||
'sortedIndex',
|
||||
'source',
|
||||
'spliceObjects',
|
||||
'string',
|
||||
'support',
|
||||
'tail',
|
||||
'take',
|
||||
'tap',
|
||||
'template',
|
||||
'templateSettings',
|
||||
'throttle',
|
||||
'times',
|
||||
'toArray',
|
||||
'trailing',
|
||||
'transform',
|
||||
'undefined',
|
||||
'unescape',
|
||||
'unindexedChars',
|
||||
'union',
|
||||
'uniq',
|
||||
'unique',
|
||||
'uniqueId',
|
||||
'unzip',
|
||||
'value',
|
||||
'values',
|
||||
'variable',
|
||||
'where',
|
||||
'window',
|
||||
'without',
|
||||
'wrap',
|
||||
'writable',
|
||||
'zip',
|
||||
'zipObject'
|
||||
];
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Pre-process a given Lo-Dash `source`, preparing it for minification.
|
||||
*
|
||||
* @param {string} [source=''] The source to process.
|
||||
* @param {Object} [options={}] The options object.
|
||||
* @returns {string} Returns the processed source.
|
||||
*/
|
||||
function preprocess(source, options) {
|
||||
source || (source = '');
|
||||
options || (options = {});
|
||||
|
||||
// remove unrecognized JSDoc tags so the Closure Compiler won't complain
|
||||
source = source.replace(/@(?:alias|category)\b.*/g, '');
|
||||
|
||||
if (options.isTemplate) {
|
||||
return source;
|
||||
}
|
||||
|
||||
// remove whitespace from string literals
|
||||
source = source.replace(/^((?:[ "'\w]+:)? *)"[^"\n\\]*?(?:\\.[^"\n\\]*?)*"|'[^'\n\\]*?(?:\\.[^'\n\\]*?)*'/gm, function(string, left) {
|
||||
// clip after an object literal property name or leading spaces
|
||||
if (left) {
|
||||
string = string.slice(left.length);
|
||||
}
|
||||
// avoids removing the '\n' of the `stringEscapes` object
|
||||
string = string.replace(/\[object |delete |else (?!{)|function | in | instanceof |return\s+[\w"']|throw |typeof |use strict|var |@ |(["'])\\n\1|\\\\n|\\n|\s+/g, function(match) {
|
||||
return match == false || match == '\\n' ? '' : match;
|
||||
});
|
||||
// unclip
|
||||
return (left || '') + string;
|
||||
});
|
||||
|
||||
// remove whitespace from `_.template` related regexes
|
||||
source = source.replace(/reEmptyString\w+ *=.+/g, function(match) {
|
||||
return match.replace(/ |\\n/g, '');
|
||||
});
|
||||
|
||||
// remove newline from double-quoted strings in `_.template`
|
||||
source = source
|
||||
.replace('"__p += \'"', '"__p+=\'"')
|
||||
.replace('"\';\n"', '"\';"')
|
||||
|
||||
// remove debug sourceURL use in `_.template`
|
||||
source = source.replace(/(?:\s*\/\/.*\n)* *var sourceURL[^;]+;|\+ *sourceURL/g, '');
|
||||
|
||||
// minify internal properties
|
||||
(function() {
|
||||
var funcNames = [
|
||||
'cacheIndexOf',
|
||||
'cachePush',
|
||||
'compareAscending',
|
||||
'createCache',
|
||||
'getObject',
|
||||
'releaseObject',
|
||||
'sortBy'
|
||||
];
|
||||
|
||||
var props = [
|
||||
'cache',
|
||||
'criteria',
|
||||
'index',
|
||||
'value'
|
||||
];
|
||||
|
||||
// minify other properties used in functions
|
||||
var snippets = source.match(RegExp('^( *)(?:var|function) +(?:' + funcNames.join('|') + ')\\b[\\s\\S]+?\\n\\1}', 'gm'));
|
||||
if (!snippets) {
|
||||
return;
|
||||
}
|
||||
snippets.forEach(function(snippet) {
|
||||
var modified = snippet;
|
||||
props.forEach(function(prop, index) {
|
||||
// use minified names different than those chosen for `iteratorOptions`
|
||||
var minName = minNames[iteratorOptions.length + index],
|
||||
reBracketProp = RegExp("\\['(" + prop + ")'\\]", 'g'),
|
||||
reDotProp = RegExp('\\.' + prop + '\\b', 'g'),
|
||||
rePropColon = RegExp("([^?\\s])\\s*([\"'])?\\b" + prop + "\\2 *:", 'g');
|
||||
|
||||
modified = modified
|
||||
.replace(reBracketProp, "['" + minName + "']")
|
||||
.replace(reDotProp, "['" + minName + "']")
|
||||
.replace(rePropColon, "$1'" + minName + "':");
|
||||
});
|
||||
|
||||
// replace with modified snippet
|
||||
source = source.replace(snippet, function() {
|
||||
return modified;
|
||||
});
|
||||
});
|
||||
}());
|
||||
|
||||
// minify all compilable snippets
|
||||
var snippets = source.match(
|
||||
RegExp([
|
||||
// match the `iteratorTemplate`
|
||||
'^( *)var iteratorTemplate\\b[\\s\\S]+?\\n\\1}',
|
||||
// match methods created by `createIterator` calls
|
||||
'createIterator\\((?:{|[a-zA-Z]+)[\\s\\S]*?\\);\\n',
|
||||
// match variables storing `createIterator` options
|
||||
'^( *)var [a-zA-Z]+IteratorOptions\\b[\\s\\S]+?\\n\\2}',
|
||||
// match `baseUniq`, `cachePush`, `createCache`, `createIterator`, `getObject`, and `releaseObject` functions
|
||||
'^( *)(?:var|function) +(?:baseUniq|cachePush|createCache|createIterator|getObject|releaseObject)\\b[\\s\\S]+?\\n\\3}'
|
||||
].join('|'), 'gm')
|
||||
) || [];
|
||||
|
||||
snippets.forEach(function(snippet, index) {
|
||||
var isFunc = /\bfunction *[ \w]*\(/.test(snippet),
|
||||
isIteratorTemplate = /var iteratorTemplate\b/.test(snippet),
|
||||
modified = snippet;
|
||||
|
||||
// remove unnecessary semicolons in strings
|
||||
modified = modified.replace(/;(?:}["']|(?:\\n|\s)*["']\s*\+\s*["'](?:\\n|\s)*})/g, function(match) {
|
||||
return match.slice(1);
|
||||
});
|
||||
|
||||
// minify snippet variables / arguments
|
||||
compiledVars.forEach(function(varName, index) {
|
||||
var minName = minNames[index];
|
||||
|
||||
modified = modified.replace(/(["'])(?:(?!\1)[^\n\\]|\\.)*\1/g, function(match) {
|
||||
return match.replace(RegExp('([^.])\\b' + varName + '\\b', 'g'), '$1' + minName);
|
||||
});
|
||||
|
||||
// correct `typeof` string values
|
||||
if (/^(?:boolean|function|object|number|string|undefined)$/.test(varName)) {
|
||||
modified = modified.replace(RegExp('(= *)(["\'])' + minName + '\\2|(["\'])' + minName + '\\3( *=)', 'g'), function(match, prelude, preQuote, postQuote, postlude) {
|
||||
return prelude
|
||||
? prelude + preQuote + varName + preQuote
|
||||
: postQuote + varName + postQuote + postlude;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// minify `createIterator` option property names
|
||||
iteratorOptions.forEach(function(property, index) {
|
||||
var minName = minNames[index];
|
||||
|
||||
// minify iterator option variables
|
||||
modified = modified.replace(/(["'])(?:(?!\1)[^\n\\]|\\.)*\1/g, function(match, quote) {
|
||||
return match.replace(RegExp('([^.])\\b' + property + '\\b', 'g'), '$1' + minName)
|
||||
});
|
||||
|
||||
// minify iterator option properties, adding brackets so the Closure Compiler won't mung them
|
||||
modified = modified.replace(RegExp('(["\'])(?:(?!\\1)[^\\n\\\\]|\\\\.)*\\1|\\.' + property + '\\b', 'g'), function(match, quote) {
|
||||
return quote ? match : "['" + minName + "']";
|
||||
});
|
||||
});
|
||||
|
||||
// replace with modified snippet
|
||||
source = source.replace(snippet, function() {
|
||||
return modified;
|
||||
});
|
||||
});
|
||||
|
||||
// add brackets to whitelisted properties so the Closure Compiler won't mung them
|
||||
// http://code.google.com/closure/compiler/docs/api-tutorial3.html#export
|
||||
source = source.replace(RegExp('(["\'])(?:(?!\\1)[^\\n\\\\]|\\\\.)*\\1|\\.(' + propWhitelist.join('|') + ')\\b', 'g'), function(match, quote, prop) {
|
||||
return quote ? match : "['" + prop + "']";
|
||||
});
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// expose `preprocess`
|
||||
if (module != require.main) {
|
||||
module.exports = preprocess;
|
||||
}
|
||||
else {
|
||||
// read the Lo-Dash source file from the first argument if the script
|
||||
// was invoked directly (e.g. `node pre-compile.js source.js`) and write to
|
||||
// the same file
|
||||
(function() {
|
||||
var options = process.argv;
|
||||
if (options.length < 3) {
|
||||
return;
|
||||
}
|
||||
var filePath = options[options.length - 1],
|
||||
isTemplate = options.indexOf('-t') > -1 || options.indexOf('--template') > -1,
|
||||
source = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
fs.writeFileSync(filePath, preprocess(source, {
|
||||
'isTemplate': isTemplate
|
||||
}), 'utf8');
|
||||
}());
|
||||
}
|
||||
}());
|
||||
@@ -1,98 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
;(function() {
|
||||
'use strict';
|
||||
|
||||
/** Load Node.js modules */
|
||||
var fs = require('fs'),
|
||||
path = require('path');
|
||||
|
||||
/** Load other modules */
|
||||
var _ = require('../lodash.js');
|
||||
|
||||
/** Used to indicate if running in Windows */
|
||||
var isWindows = process.platform == 'win32';
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* The path separator.
|
||||
*
|
||||
* @memberOf util.path
|
||||
* @type string
|
||||
*/
|
||||
var sep = path.sep || (isWindows ? '\\' : '/');
|
||||
|
||||
/**
|
||||
* The escaped path separator used for inclusion in RegExp strings.
|
||||
*
|
||||
* @memberOf util.path
|
||||
* @type string
|
||||
*/
|
||||
var sepEscaped = sep.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
|
||||
/** Used to determine if a path is prefixed with a drive letter, dot, or slash */
|
||||
var rePrefixed = RegExp('^(?:' + (isWindows ? '[a-zA-Z]:|' : '') + '\\.?)' + sepEscaped);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Makes the given `dirname` directory, without throwing errors for existing
|
||||
* directories and making parent directories as needed.
|
||||
*
|
||||
* @memberOf util.fs
|
||||
* @param {string} dirname The path of the directory.
|
||||
* @param {number|string} [mode='0777'] The permission mode.
|
||||
*/
|
||||
function mkdirpSync(dirname, mode) {
|
||||
// ensure relative paths are prefixed with `./`
|
||||
if (!rePrefixed.test(dirname)) {
|
||||
dirname = '.' + sep + dirname;
|
||||
}
|
||||
dirname.split(sep).reduce(function(currPath, segment) {
|
||||
currPath += sep + segment;
|
||||
try {
|
||||
currPath = fs.realpathSync(currPath);
|
||||
} catch(e) {
|
||||
fs.mkdirSync(currPath, mode);
|
||||
}
|
||||
return currPath;
|
||||
});
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* The utility object.
|
||||
*
|
||||
* @type Object
|
||||
*/
|
||||
var util = {
|
||||
|
||||
/**
|
||||
* The file system object.
|
||||
*
|
||||
* @memberOf util
|
||||
* @type Object
|
||||
*/
|
||||
'fs': _.defaults(_.cloneDeep(fs), {
|
||||
'existsSync': fs.existsSync || path.existsSync,
|
||||
'mkdirpSync': mkdirpSync
|
||||
}),
|
||||
|
||||
/**
|
||||
* The path object.
|
||||
*
|
||||
* @memberOf util
|
||||
* @type Object
|
||||
*/
|
||||
'path': _.defaults(_.cloneDeep(path), {
|
||||
'sep': sep,
|
||||
'sepEscaped': sepEscaped
|
||||
})
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// expose
|
||||
module.exports = util;
|
||||
}());
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "lodash",
|
||||
"repo": "bestiejs/lodash",
|
||||
"version": "1.3.1",
|
||||
"description": "A low-level utility library delivering consistency, customization, performance, and extra features.",
|
||||
"description": "A utility library delivering consistency, customization, performance, and extras.",
|
||||
"license": "MIT",
|
||||
"scripts": [
|
||||
"index.js",
|
||||
|
||||
15
package.json
15
package.json
@@ -43,18 +43,21 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/bestiejs/lodash.git"
|
||||
},
|
||||
"bin": {
|
||||
"lodash": "./build.js"
|
||||
},
|
||||
"engines": [
|
||||
"node",
|
||||
"rhino"
|
||||
],
|
||||
"files": [
|
||||
"build.js",
|
||||
"LICENSE.txt",
|
||||
"dist/lodash.js",
|
||||
"dist/lodash.min.js",
|
||||
"dist/lodash.backbone.js",
|
||||
"dist/lodash.backbone.min.js",
|
||||
"dist/lodash.compat.js",
|
||||
"dist/lodash.compat.min.js",
|
||||
"dist/lodash.legacy.js",
|
||||
"dist/lodash.legacy.min.js",
|
||||
"dist/lodash.mobile.js",
|
||||
"dist/lodash.mobile.min.js",
|
||||
"dist/lodash.underscore.js",
|
||||
"dist/lodash.underscore.min.js"
|
||||
],
|
||||
@@ -75,12 +78,10 @@
|
||||
"*.map",
|
||||
"*.md",
|
||||
"*.txt",
|
||||
"build.js",
|
||||
"lodash.js",
|
||||
"index.js",
|
||||
"bower.json",
|
||||
"component.json",
|
||||
"build",
|
||||
"doc",
|
||||
"modularize",
|
||||
"node_modules",
|
||||
|
||||
@@ -9,10 +9,6 @@ done
|
||||
echo "Testing in node..."
|
||||
node test.js ../dist/lodash.js && node test.js ../dist/lodash.min.js
|
||||
|
||||
echo ""
|
||||
echo "Testing build..."
|
||||
node test-build.js
|
||||
|
||||
echo ""
|
||||
echo "Testing in a browser..."
|
||||
open index.html
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<ul>
|
||||
<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>
|
||||
</ul>
|
||||
@@ -1 +0,0 @@
|
||||
<% print("Hello " + epithet); %>.
|
||||
@@ -1 +0,0 @@
|
||||
Hello ${ name }!
|
||||
@@ -1 +0,0 @@
|
||||
Hallå {{ name }}!
|
||||
1837
test/test-build.js
1837
test/test-build.js
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user