|
2 | 2 | ;(function() {
|
3 | 3 | 'use strict';
|
4 | 4 |
|
5 |
| - /** The Node filesystem and path modules */ |
| 5 | + /** Load modules */ |
6 | 6 | var fs = require('fs'),
|
7 |
| - path = require('path'); |
8 |
| - |
9 |
| - /** Load other modules */ |
10 |
| - var lodash = require(path.join(__dirname, 'lodash')), |
| 7 | + path = require('path'), |
| 8 | + vm = require('vm'), |
11 | 9 | minify = require(path.join(__dirname, 'build', 'minify'));
|
12 | 10 |
|
| 11 | + /** Flag used to specify a backbone build */ |
| 12 | + var isBackbone = process.argv.indexOf('backbone') > -1; |
| 13 | + |
| 14 | + /** Flag used to specify a legacy build */ |
| 15 | + var isLegacy = process.argv.indexOf('legacy') > -1; |
| 16 | + |
| 17 | + /** Flag used to specify a mobile build */ |
| 18 | + var isMobile = !isLegacy && process.argv.indexOf('mobile') > -1; |
| 19 | + |
13 | 20 | /** Shortcut used to convert array-like objects to arrays */
|
14 | 21 | var slice = [].slice;
|
15 | 22 |
|
16 | 23 | /** The lodash.js source */
|
17 | 24 | var source = fs.readFileSync(path.join(__dirname, 'lodash.js'), 'utf8');
|
18 | 25 |
|
| 26 | + /** Load customized Lo-Dash module */ |
| 27 | + var lodash = (function() { |
| 28 | + var sandbox = {}; |
| 29 | + |
| 30 | + if (isLegacy) { |
| 31 | + ['isBindFast', 'isKeysFast', 'nativeBind', 'nativeIsArray', 'nativeKeys'].forEach(function(varName) { |
| 32 | + source = replaceVar(source, varName, 'false'); |
| 33 | + }); |
| 34 | + } |
| 35 | + else if (isMobile) { |
| 36 | + source = replaceVar(source, 'isKeysFast', 'false'); |
| 37 | + } |
| 38 | + vm.runInNewContext(source, sandbox); |
| 39 | + return sandbox._; |
| 40 | + }()); |
| 41 | + |
19 | 42 | /** Used to associate aliases with their real names */
|
20 | 43 | var aliasToRealMap = {
|
21 | 44 | 'all': 'every',
|
|
198 | 221 | 'hasDontEnumBug',
|
199 | 222 | 'inLoop',
|
200 | 223 | 'init',
|
| 224 | + 'isKeysFast', |
201 | 225 | 'iteratedObject',
|
202 | 226 | 'loopExp',
|
203 | 227 | 'object',
|
|
233 | 257 | return pair[1];
|
234 | 258 | }, '');
|
235 | 259 |
|
236 |
| - /** Flag used to specify a backbone build */ |
237 |
| - var isBackbone = process.argv.indexOf('backbone') > -1; |
238 |
| - |
239 |
| - /** Flag used to specify a mobile build */ |
240 |
| - var isMobile = process.argv.indexOf('mobile') > -1; |
241 |
| - |
242 | 260 | /*--------------------------------------------------------------------------*/
|
243 | 261 |
|
244 | 262 | /**
|
|
318 | 336 | * @returns {String} Returns the `isArguments` fallback snippet.
|
319 | 337 | */
|
320 | 338 | function getIsArgumentsFallback(source) {
|
321 |
| - return (source.match(/(?: *\/\/.*)*\s*if *\(!(?:lodash\.)?isArguments[^)]+\)[\s\S]+?};?\s*}\n/) || [''])[0]; |
| 339 | + return (source.match(/(?: *\/\/.*)*\s*if *\(!(?:lodash\.)?isArguments[^)]+\)[\s\S]+?};\s*}\n/) || [''])[0]; |
322 | 340 | }
|
323 | 341 |
|
324 | 342 | /**
|
|
465 | 483 | return removeFromCreateIterator(source, varName);
|
466 | 484 | }
|
467 | 485 |
|
| 486 | + /** |
| 487 | + * Searches `source` for a `varName` variable declaration and replaces its |
| 488 | + * assigned value with `varValue`. |
| 489 | + * |
| 490 | + * @private |
| 491 | + * @param {String} source The source to inspect. |
| 492 | + * @param {String} varName The name of the variable to replace. |
| 493 | + * @returns {String} Returns the source with the variable replaced. |
| 494 | + */ |
| 495 | + function replaceVar(source, varName, varValue) { |
| 496 | + // replace a variable that's not part of a declaration list |
| 497 | + source = source.replace(RegExp( |
| 498 | + '(( +)var ' + varName + ' *= *)' + |
| 499 | + '(?:.*?;|(?:Function\\(.+?|.*?[^,])\\n[\\s\\S]+?\\n\\2.+?;)\\n' |
| 500 | + ), '$1' + varValue + ';\n'); |
| 501 | + |
| 502 | + // replace a varaible at the start of middle of a declaration list |
| 503 | + source = source.replace(RegExp('((?:var|\\n) +' + varName + ' *=).+?,'), '$1 ' + varValue + ','); |
| 504 | + |
| 505 | + // replace a variable at the end of a variable declaration list |
| 506 | + source = source.replace(RegExp('(,\\s*' + varName + ' *=).*?;'), '$1 ' + varValue + ';'); |
| 507 | + |
| 508 | + return source; |
| 509 | + } |
| 510 | + |
468 | 511 | /*--------------------------------------------------------------------------*/
|
469 | 512 |
|
470 | 513 | // Backbone build
|
|
574 | 617 | }
|
575 | 618 | if (isRemoved(source, 'bind')) {
|
576 | 619 | source = removeVar(source, 'nativeBind');
|
577 |
| - source = removeVar(source, 'useNativeBind'); |
| 620 | + source = removeVar(source, 'isBindFast'); |
578 | 621 | }
|
579 | 622 | if (isRemoved(source, 'isArray')) {
|
580 | 623 | source = removeVar(source, 'nativeIsArray');
|
581 | 624 | }
|
582 | 625 | if (isRemoved(source, 'keys')) {
|
583 |
| - source = removeVar(source, 'nativeKeys'); |
584 | 626 | source = removeFunction(source, 'shimKeys');
|
585 | 627 | }
|
586 | 628 | if (isRemoved(source, 'clone', 'isObject', 'keys')) {
|
|
637 | 679 | 'RegExp': 'regexpClass',
|
638 | 680 | 'String': 'stringClass'
|
639 | 681 | }, function(value, key) {
|
| 682 | + // if legacy build skip `isArguments` |
| 683 | + if (isLegacy && key == 'Arguments') { |
| 684 | + return; |
| 685 | + } |
640 | 686 | var funcName = 'is' + key,
|
641 | 687 | funcCode = matchFunction(source, funcName);
|
642 | 688 |
|
|
673 | 719 | );
|
674 | 720 |
|
675 | 721 | // tweak `isArguments` fallback
|
676 |
| - snippet = getIsArgumentsFallback(source); |
| 722 | + snippet = !isLegacy && getIsArgumentsFallback(source); |
677 | 723 | if (snippet) {
|
678 | 724 | result = '\n' + snippet.replace(/isArguments/g, 'lodash.$&');
|
679 | 725 | source = source.replace(snippet, result);
|
|
682 | 728 |
|
683 | 729 | /*--------------------------------------------------------------------------*/
|
684 | 730 |
|
| 731 | + if (isLegacy) { |
| 732 | + // replace `_.keys` with `shimKeys` |
| 733 | + if (!isRemoved(source, 'keys')) { |
| 734 | + source = source.replace( |
| 735 | + matchFunction(source, 'keys').replace(/[\s\S]+?var keys *=/, ''), |
| 736 | + matchFunction(source, 'shimKeys').replace(/[\s\S]+?var shimKeys *=/, '') |
| 737 | + ); |
| 738 | + |
| 739 | + source = removeFunction(source, 'shimKeys'); |
| 740 | + } |
| 741 | + // replace `_.isArguments` with fallback |
| 742 | + if (!isRemoved(source, 'isArguments')) { |
| 743 | + source = source.replace( |
| 744 | + matchFunction(source, 'isArguments').replace(/[\s\S]+?var isArguments *=/, ''), |
| 745 | + getIsArgumentsFallback(source).match(/isArguments *=([\s\S]+?) *};/)[1] + ' };\n' |
| 746 | + ); |
| 747 | + |
| 748 | + source = removeIsArgumentsFallback(source); |
| 749 | + } |
| 750 | + |
| 751 | + source = removeFromCreateIterator(source, 'nativeKeys'); |
| 752 | + } |
| 753 | + |
685 | 754 | if (isMobile) {
|
686 | 755 | // inline functions defined with `createIterator`
|
687 | 756 | lodash.functions(lodash).forEach(function(funcName) {
|
|
696 | 765 | source = source.replace(reFunc, '$1' + getFunctionSource(lodash[funcName]) + ';\n');
|
697 | 766 | });
|
698 | 767 |
|
699 |
| - source = removeIsArgumentsFallback(source); |
700 |
| - |
701 |
| - source = removeVar(source, 'iteratorTemplate'); |
702 |
| - |
703 | 768 | // remove JScript [[DontEnum]] fix from `isEqual`
|
704 | 769 | source = source.replace(/(?:\s*\/\/.*\n)*( +)if *\(result *&& *hasDontEnumBug[\s\S]+?\n\1}/, '');
|
705 | 770 |
|
706 | 771 | // remove IE `shift` and `splice` fix
|
707 | 772 | source = source.replace(/(?:\s*\/\/.*\n)*( +)if *\(value.length *=== *0[\s\S]+?\n\1}/, '');
|
708 | 773 |
|
709 |
| - // cleanup code |
710 |
| - source = source.replace(/^ *;\n/gm, ''); |
| 774 | + source = removeVar(source, 'iteratorTemplate'); |
| 775 | + source = removeIsArgumentsFallback(source); |
711 | 776 | }
|
712 | 777 | else {
|
713 | 778 | // inline `iteratorTemplate` template
|
714 | 779 | source = source.replace(/(( +)var iteratorTemplate *= *)[\s\S]+?\n\2.+?;\n/, (function() {
|
715 |
| - var code = getFunctionSource(lodash._iteratorTemplate); |
| 780 | + var snippet = getFunctionSource(lodash._iteratorTemplate); |
716 | 781 |
|
717 | 782 | // expand properties to avoid having to use a with-statement
|
718 | 783 | iteratorOptions.forEach(function(property) {
|
719 |
| - code = code.replace(RegExp('([^\\w.])\\b' + property + '\\b', 'g'), '$1obj.' + property); |
| 784 | + snippet = snippet.replace(RegExp('([^\\w.])\\b' + property + '\\b', 'g'), '$1obj.' + property); |
720 | 785 | });
|
721 | 786 |
|
722 | 787 | // remove unnecessary code
|
723 |
| - code = code |
| 788 | + snippet = snippet |
724 | 789 | .replace(/, *__t,[^;]+|function print[^}]+}/g, '')
|
725 | 790 | .replace(/'(?:\\n|\s)+'/g, "''")
|
726 | 791 | .replace(/__p *\+= *' *';/g, '')
|
|
729 | 794 | .replace(/\(\(__w?t *= *\( *([^)]+) *\)\) *== *null *\? *'' *: *__w?t\)/g, '$1');
|
730 | 795 |
|
731 | 796 | // remove the with-statement
|
732 |
| - code = code.replace(/ *with *\([^)]+\) *{/, '\n').replace(/}}\s*;?\s*}/, '}}\n'); |
| 797 | + snippet = snippet.replace(/ *with *\([^)]+\) *{/, '\n').replace(/}}\s*;?\s*}/, '}}\n'); |
733 | 798 |
|
734 | 799 | // minor cleanup
|
735 |
| - code = code |
| 800 | + snippet = snippet |
736 | 801 | .replace(/obj *\|\| *\(obj *= *\{}\);/, '')
|
737 | 802 | .replace(/var __p;\s*__p/, 'var __p');
|
738 | 803 |
|
739 | 804 | // remove comments, including sourceURLs
|
740 |
| - code = code.replace(/\s*\/\/.*(?:\n|$)/g, ''); |
| 805 | + snippet = snippet.replace(/\s*\/\/.*(?:\n|$)/g, ''); |
741 | 806 |
|
742 |
| - return '$1' + code + ';\n'; |
| 807 | + return '$1' + snippet + ';\n'; |
743 | 808 | }()));
|
744 | 809 | }
|
745 | 810 |
|
|
748 | 813 | // remove pseudo private properties
|
749 | 814 | source = source.replace(/(?:(?:\s*\/\/.*)*\s*lodash\._[^=]+=.+\n)+/g, '\n');
|
750 | 815 |
|
| 816 | + // cleanup code |
| 817 | + source = source.replace(/^ *;\n/gm, ''); |
| 818 | + |
751 | 819 | // begin the minification process
|
752 |
| - if (filterType || isBackbone || isMobile) { |
| 820 | + if (filterType || isBackbone || isLegacy || isMobile) { |
753 | 821 | fs.writeFileSync(path.join(__dirname, 'lodash.custom.js'), source);
|
754 | 822 | minify(source, 'lodash.custom.min', function(result) {
|
755 | 823 | fs.writeFileSync(path.join(__dirname, 'lodash.custom.min.js'), result);
|
|
0 commit comments