123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451 |
- #!/usr/bin/env node
- ;(function() {
- 'use strict';
- /** The Node filesystem module */
- var fs = require('fs');
- /** Used to minify variables embedded in compiled strings */
- var compiledVars = [
- 'argsIndex',
- 'argsLength',
- 'callback',
- 'collection',
- 'concat',
- 'ctor',
- 'hasOwnProperty',
- 'identity',
- 'index',
- 'iteratee',
- 'iteratorBind',
- 'length',
- 'nativeKeys',
- 'object',
- 'ownIndex',
- 'ownProps',
- 'prop',
- 'propertyIsEnumerable',
- 'propIndex',
- 'props',
- 'result',
- 'skipProto',
- 'slice',
- 'stringClass',
- 'thisArg',
- 'toString',
- 'value',
- // lesser used variables
- 'accumulator',
- 'args',
- 'arrayLikeClasses',
- 'ArrayProto',
- 'bind',
- 'callee',
- 'className',
- 'compareAscending',
- 'data',
- 'forIn',
- 'found',
- 'funcs',
- 'indexOf',
- 'indicator',
- 'isArguments',
- 'isArr',
- 'isArray',
- 'isFunc',
- 'isFunction',
- 'isPlainObject',
- 'methodName',
- 'noaccum',
- 'objectClass',
- 'objectTypes',
- 'pass',
- 'properties',
- 'property',
- 'propsLength',
- 'recursive',
- 'source',
- 'sources',
- 'stackLength',
- 'target',
- 'valueProp',
- 'values'
- ];
- /** Used to minify `compileIterator` option properties */
- var iteratorOptions = [
- 'args',
- 'array',
- 'arrayBranch',
- 'beforeLoop',
- 'bottom',
- 'exit',
- 'firstArg',
- 'hasDontEnumBug',
- 'inLoop',
- 'init',
- 'isKeysFast',
- 'object',
- 'objectBranch',
- 'noArgsEnum',
- 'noCharByIndex',
- 'shadowed',
- 'top',
- 'useHas',
- 'useStrict'
- ];
- /** 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 = [
- '_',
- '__chain__',
- '__proto__',
- '__wrapped__',
- 'after',
- 'all',
- 'amd',
- 'any',
- 'attachEvent',
- 'bind',
- 'bindAll',
- 'chain',
- 'clearTimeout',
- 'clone',
- 'clones',
- 'collect',
- 'compact',
- 'compose',
- 'contains',
- 'countBy',
- 'criteria',
- 'debounce',
- 'defaults',
- 'defer',
- 'delay',
- 'detect',
- 'difference',
- 'drop',
- 'each',
- 'environment',
- 'escape',
- 'evaluate',
- 'every',
- 'exports',
- 'extend',
- 'filter',
- 'find',
- 'first',
- 'flatten',
- 'foldl',
- 'foldr',
- 'forEach',
- 'forIn',
- 'forOwn',
- 'functions',
- 'groupBy',
- 'has',
- 'head',
- 'identity',
- 'include',
- 'index',
- 'indexOf',
- 'initial',
- 'inject',
- 'interpolate',
- 'intersection',
- 'invert',
- 'invoke',
- 'isArguments',
- 'isArray',
- 'isBoolean',
- 'isDate',
- 'isElement',
- 'isEmpty',
- 'isEqual',
- 'isEqual',
- 'isFinite',
- 'isFinite',
- 'isFunction',
- 'isNaN',
- 'isNull',
- 'isNumber',
- 'isObject',
- 'isRegExp',
- 'isString',
- 'isUndefined',
- 'keys',
- 'last',
- 'lastIndexOf',
- 'map',
- 'max',
- 'memoize',
- 'merge',
- 'methods',
- 'min',
- 'mixin',
- 'noConflict',
- 'object',
- 'omit',
- 'once',
- 'opera',
- 'pairs',
- 'partial',
- 'pick',
- 'pluck',
- 'random',
- 'range',
- 'reduce',
- 'reduceRight',
- 'reject',
- 'rest',
- 'result',
- 'select',
- 'setTimeout',
- 'shuffle',
- 'size',
- 'some',
- 'sortBy',
- 'sortedIndex',
- 'source',
- 'sources',
- 'stackA',
- 'stackB',
- 'tail',
- 'take',
- 'tap',
- 'template',
- 'templateSettings',
- 'throttle',
- 'times',
- 'toArray',
- 'unescape',
- 'union',
- 'uniq',
- 'unique',
- 'uniqueId',
- 'value',
- 'values',
- 'variable',
- 'VERSION',
- 'where',
- 'without',
- 'wrap',
- 'zip',
- // properties used by underscore.js
- '_chain',
- '_wrapped'
- ];
- /*--------------------------------------------------------------------------*/
- /**
- * Pre-process a given Lo-Dash `source`, preparing it for minification.
- *
- * @param {String} source The source to process.
- * @returns {String} Returns the processed source.
- */
- function preprocess(source) {
- // remove copyright to add later in post-compile.js
- source = source.replace(/\/\*![\s\S]+?\*\//, '');
- // remove unrecognized JSDoc tags so Closure Compiler won't complain
- source = source.replace(/@(?:alias|category)\b.*/g, '');
- // add brackets to whitelisted properties so Closure Compiler won't mung them
- // http://code.google.com/closure/compiler/docs/api-tutorial3.html#export
- source = source.replace(RegExp('\\.(' + propWhitelist.join('|') + ')\\b', 'g'), "['$1']");
- // remove brackets from `_.escape()` in `_.template`
- source = source.replace(/__e *= *_\['escape']/g, '__e=_.escape');
- // remove brackets from `_.escape()` in underscore.js `_.template`
- source = source.replace(/_\['escape'\]\(__t'/g, '_.escape(__t');
- // remove brackets from `collection.indexOf` in `_.contains`
- source = source.replace("collection['indexOf'](target)", 'collection.indexOf(target)');
- // remove brackets from `result[length].value` in `_.sortBy`
- source = source.replace("result[length]['value']", 'result[length].value');
- // remove whitespace from string literals
- source = source.replace(/'(?:(?=(\\?))\1.)*?'/g, function(string) {
- // avoids removing the '\n' of the `stringEscapes` object
- return string.replace(/\[object |delete |else if|function | in |return\s+[\w']|throw |typeof |use strict|var |@ |'\\n'|\\\\n|\\n|\s+/g, function(match) {
- return match == false || match == '\\n' ? '' : match;
- });
- });
- // add newline to `+"__p+='"` in underscore.js `_.template`
- source = source.replace(/\+"__p\+='"/g, '+"\\n__p+=\'"');
- // remove whitespace from `_.template` related regexes
- source = source.replace(/(?:reDelimiterCode\w+|reEmptyString\w+|reInsertVariable) *=.+/g, function(match) {
- return match.replace(/ |\\n/g, '');
- });
- // remove newline from double-quoted strings in `_.template`
- source = source
- .replace('"\';\\n__with ("', '"\';__with("')
- .replace('"\\n}__\\n__p += \'"', '"}____p+=\'"')
- .replace('"__p = \'"', '"__p=\'"')
- .replace('"\';\\n"', '"\';"')
- .replace("') {\\n'", "'){'")
- // remove `useSourceURL` variable
- source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *try *\{(?:\s*\/\/.*)*\n *var useSourceURL[\s\S]+?catch[^}]+}\n/, '');
- // remove debug sourceURL use in `_.template`
- source = source.replace(/(?:\s*\/\/.*\n)* *if *\(useSourceURL[^}]+}/, '');
- // minify internal properties used by 'compareAscending', `_.clone`, `_.isEqual`, `_.merge`, and `_.sortBy`
- (function() {
- var properties = ['clones', 'criteria', 'index', 'sources', 'thorough', 'value', 'values'],
- snippets = source.match(/( +)(?:function (?:clone|compareAscending|isEqual)|var merge|var sortBy)\b[\s\S]+?\n\1}/g);
- if (!snippets) {
- return;
- }
- snippets.forEach(function(snippet) {
- var modified = snippet,
- isCompilable = /(?:var merge|var sortBy)\b/.test(modified),
- isInlined = !/\bcreateIterator\b/.test(modified);
- // minify properties
- properties.forEach(function(property, index) {
- var reBracketProp = RegExp("\\['(" + property + ")'\\]", 'g'),
- reDotProp = RegExp('\\.' + property + '\\b', 'g'),
- rePropColon = RegExp("([^?\\s])\\s*([\"'])?\\b" + property + "\\2 *:", 'g');
- if (isCompilable) {
- // add quotes around properties in the inlined `_.merge` and `_.sortBy`
- // of the mobile build so Closure Compiler won't mung them
- if (isInlined) {
- modified = modified
- .replace(reBracketProp, "['" + minNames[index] + "']")
- .replace(reDotProp, "['" + minNames[index] + "']")
- .replace(rePropColon, "$1'" + minNames[index] + "':");
- }
- else {
- modified = modified
- .replace(reBracketProp, '.' + minNames[index])
- .replace(reDotProp, '.' + minNames[index])
- .replace(rePropColon, '$1' + minNames[index] + ':');
- }
- }
- else {
- modified = modified
- .replace(reBracketProp, "['" + minNames[index] + "']")
- .replace(reDotProp, '.' + minNames[index])
- .replace(rePropColon, "$1'" + minNames[index] + "':")
- // correct `value.source` in regexp branch of `_.clone`
- if (property == 'source') {
- modified = modified.replace("value['" + minNames[index] + "']", "value['source']");
- }
- }
- });
- // replace with modified snippet
- source = source.replace(snippet, 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 the the `createIterator` function
- '( +)function createIterator\\b[\\s\\S]+?\\n\\3}'
- ].join('|'), 'g')
- );
- // exit early if no compilable snippets
- if (!snippets) {
- return source;
- }
- snippets.forEach(function(snippet, index) {
- var isCreateIterator = /function createIterator\b/.test(snippet),
- isIteratorTemplate = /var iteratorTemplate\b/.test(snippet),
- modified = snippet;
- // add brackets to whitelisted properties so Closure Compiler won't mung them
- modified = modified.replace(RegExp('\\.(' + iteratorOptions.join('|') + ')\\b', 'g'), "['$1']");
- if (isCreateIterator) {
- // replace with modified snippet early and clip snippet to the `factory`
- // call so other arguments aren't minified
- source = source.replace(snippet, modified);
- snippet = modified = modified.replace(/factory\([\s\S]+$/, '');
- }
- // minify snippet variables / arguments
- compiledVars.forEach(function(variable, index) {
- // ensure properties in compiled strings aren't minified
- modified = modified.replace(RegExp('([^.]\\b)' + variable + '\\b(?!\' *[\\]:])', 'g'), '$1' + minNames[index]);
- // correct `typeof x == 'object'`
- if (variable == 'object') {
- modified = modified.replace(RegExp("(typeof [^']+')" + minNames[index] + "'", 'g'), "$1object'");
- }
- });
- // minify `createIterator` option property names
- iteratorOptions.forEach(function(property, index) {
- if (isIteratorTemplate) {
- // minify property names as interpolated template variables
- modified = modified.replace(RegExp('\\b' + property + '\\b', 'g'), minNames[index]);
- }
- else {
- if (property == 'array' || property == 'object') {
- // minify "array" and "object" sub property names
- modified = modified.replace(RegExp("'" + property + "'( *[\\]:])", 'g'), "'" + minNames[index] + "'$1");
- }
- else {
- // minify property name strings
- modified = modified.replace(RegExp("'" + property + "'", 'g'), "'" + minNames[index] + "'");
- // minify property names in regexes and accessors
- if (isCreateIterator) {
- modified = modified.replace(RegExp('([\\.|/])' + property + '\\b' , 'g'), '$1' + minNames[index]);
- }
- }
- }
- });
- // replace with modified snippet
- source = source.replace(snippet, modified);
- });
- 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 source = fs.readFileSync(process.argv[2], 'utf8');
- fs.writeFileSync(process.argv[2], preprocess(source), 'utf8');
- }());
- }
- }());
|