From fc9c937e67e8123ddcafab564e6277e6d5f95e33 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 24 Nov 2012 01:34:00 -0600 Subject: [PATCH] Simplify `iteratorTemplate` and support for minifying double quoted strings in source. Former-commit-id: d18cbd6dc380001fe3617f6891c84a794a13c8d1 --- build.js | 12 ++++++------ build/pre-compile.js | 19 ++++++++++++------- lodash.js | 42 +++++++++++++++++++----------------------- 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/build.js b/build.js index f1195c40a..7bf2904b5 100755 --- a/build.js +++ b/build.js @@ -731,7 +731,7 @@ // remove optimized branch in `iteratorTemplate` source = source.replace(getIteratorTemplate(source), function(match) { - return match.replace(/(?: *\/\/.*\n)* *'( *)<% *if *\(isKeysFast[\s\S]+?'\1<% *} *else *\{ *%>.+\n([\s\S]+?) *'\1<% *} *%>.+/, "'\\n' +\n$2"); + return match.replace(/(?: *\/\/.*\n)* *["']( *)<% *if *\(isKeysFast[\s\S]+?["']\1<% *} *else *\{ *%>.+\n([\s\S]+?) *["']\1<% *} *%>.+/, "'\\n' +\n$2"); }); // remove data object property assignment in `createIterator` @@ -896,7 +896,7 @@ } // replace `useStrict` branch in `iteratorTemplate` with hard-coded option source = source.replace(getIteratorTemplate(source), function(match) { - return match.replace(/(?: *\/\/.*\n)*(\s*)' *<%.+?useStrict.+/, value ? "$1'\\'use strict\\';\\n' +" : ''); + return match.replace(/(?: *\/\/.*\n)*(\s*)["'] *<%.+?useStrict.+/, value ? '$1"\'use strict\';\\n" +' : ''); }); return source; @@ -1386,8 +1386,8 @@ " source = 'with (' + variable + ' || {}) {\\n' + source + '\\n}\\n';", ' }', " source = 'function(' + variable + ') {\\n' +", - " 'var __t, __p = \\'\\', __j = Array.prototype.join;\\n' +", - " 'function print() { __p += __j.call(arguments, \\'\\') }\\n' +", + ' "var __t, __p = \'\', __j = Array.prototype.join;\\n" +', + ' "function print() { __p += __j.call(arguments, \'\') }\\n" +', ' source +', " 'return __p\\n}';", '', @@ -1525,7 +1525,7 @@ // remove `prototype` [[Enumerable]] fix from `iteratorTemplate` source = source.replace(getIteratorTemplate(source), function(match) { return match - .replace(/(?: *\/\/.*\n)* *' *(?:<% *)?if *\(!hasDontEnumBug *(?:&&|\))[\s\S]+?<% *} *(?:%>|').+/g, '') + .replace(/(?: *\/\/.*\n)* *["'] *(?:<% *)?if *\(!hasDontEnumBug *(?:&&|\))[\s\S]+?<% *} *(?:%>|["']).+/g, '') .replace(/!hasDontEnumBug *\|\|/g, ''); }); } @@ -1933,7 +1933,7 @@ 'onComplete': function(source) { // inject "use strict" directive if (isStrict) { - source = source.replace(/^([\s\S]*?function[^{]+{)([^'"])/, '$1"use strict";$2'); + source = source.replace(/^([\s\S]*?function[^{]+{)([^"'])/, '$1"use strict";$2'); } if (isCustom) { source = addCommandsToHeader(source, options); diff --git a/build/pre-compile.js b/build/pre-compile.js index bdef9f42c..5efbc498f 100644 --- a/build/pre-compile.js +++ b/build/pre-compile.js @@ -236,9 +236,17 @@ source = source.replace("result[length]['value']", 'result[length].value'); // remove whitespace from string literals - source = source.replace(/'(?:(?=(\\?))\1.)*?'/g, function(string) { + source = source.replace(/^ *"(?:(?=(\\?))\1.)*?"|'(?:(?=(\\?))\2.)*?'/gm, function(string) { // avoids removing the '\n' of the `stringEscapes` object - return string.replace(/\[object |delete |else |function | in |return\s+[\w']|throw |typeof |use strict|var |@ |'\\n'|\\\\n|\\n|\s+/g, function(match) { + return string.replace(/\[object |delete |else |function | in |return\s+[\w"']|throw |typeof |use strict|var |@ |(["'])\\n\1|\\\\n|\\n|\s+/g, function(match) { + return match == false || match == '\\n' ? '' : match; + }); + }); + + // remove whitespace from string literals in double quotes + source = source.replace(/^ *"(?:(?=(\\?))\1.)*?"/g, function(string) { + // avoids removing the '\n' of the `stringEscapes` object + return string.replace(reWhitespace, function(match) { return match == false || match == '\\n' ? '' : match; }); }); @@ -256,11 +264,8 @@ // 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'", "'){'") + .replace('"__p += \'"', '"__p+=\'"') + .replace('"\';\n"', '"\';"') // remove `useSourceURL` variable source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *try *\{(?:\s*\/\/.*)*\n *var useSourceURL[\s\S]+?catch[^}]+}\n/, ''); diff --git a/lodash.js b/lodash.js index 54f1580fe..b98960a1f 100644 --- a/lodash.js +++ b/lodash.js @@ -351,10 +351,10 @@ */ var iteratorTemplate = template( // conditional strict mode - '<% if (obj.useStrict) { %>\'use strict\';\n<% } %>' + + "<% if (obj.useStrict) { %>'use strict';\n<% } %>" + // the `iteratee` may be reassigned by the `top` snippet - 'var index, value, iteratee = <%= firstArg %>, ' + + 'var index, iteratee = <%= firstArg %>, ' + // assign the `result` variable an initial value 'result = <%= firstArg %>;\n' + // exit early if the first argument is falsey @@ -365,18 +365,17 @@ // array-like iteration: '<% if (arrayLoop) { %>' + 'var length = iteratee.length; index = -1;\n' + - 'if (typeof length == \'number\') {' + + "if (typeof length == 'number') {" + // add support for accessing string characters by index if needed ' <% if (noCharByIndex) { %>\n' + ' if (isString(iteratee)) {\n' + - ' iteratee = iteratee.split(\'\')\n' + + " iteratee = iteratee.split('')\n" + ' }' + ' <% } %>\n' + // iterate over the array-like value ' while (++index < length) {\n' + - ' value = iteratee[index];\n' + ' <%= arrayLoop %>\n' + ' }\n' + '}\n' + @@ -388,7 +387,7 @@ ' var length = iteratee.length; index = -1;\n' + ' if (length && isArguments(iteratee)) {\n' + ' while (++index < length) {\n' + - ' value = iteratee[index += \'\'];\n' + + " index += '';\n" + ' <%= objectLoop %>\n' + ' }\n' + ' } else {' + @@ -401,8 +400,8 @@ // the the `prototype` property of functions regardless of its // [[Enumerable]] value. ' <% if (!hasDontEnumBug) { %>\n' + - ' var skipProto = typeof iteratee == \'function\' && \n' + - ' propertyIsEnumerable.call(iteratee, \'prototype\');\n' + + " var skipProto = typeof iteratee == 'function' && \n" + + " propertyIsEnumerable.call(iteratee, 'prototype');\n" + ' <% } %>' + // iterate own properties using `Object.keys` if it's fast @@ -412,8 +411,7 @@ ' length = ownProps.length;\n\n' + ' while (++ownIndex < length) {\n' + ' index = ownProps[ownIndex];\n' + - ' <% if (!hasDontEnumBug) { %>if (!(skipProto && index == \'prototype\')) {\n <% } %>' + - ' value = iteratee[index];\n' + + " <% if (!hasDontEnumBug) { %>if (!(skipProto && index == 'prototype')) {\n <% } %>" + ' <%= objectLoop %>\n' + ' <% if (!hasDontEnumBug) { %>}\n<% } %>' + ' }' + @@ -422,12 +420,11 @@ ' <% } else { %>\n' + ' for (index in iteratee) {<%' + ' if (!hasDontEnumBug || useHas) { %>\n if (<%' + - ' if (!hasDontEnumBug) { %>!(skipProto && index == \'prototype\')<% }' + + " if (!hasDontEnumBug) { %>!(skipProto && index == 'prototype')<% }" + ' if (!hasDontEnumBug && useHas) { %> && <% }' + ' if (useHas) { %>hasOwnProperty.call(iteratee, index)<% }' + ' %>) {' + ' <% } %>\n' + - ' value = iteratee[index];\n' + ' <%= objectLoop %>;' + ' <% if (!hasDontEnumBug || useHas) { %>\n }<% } %>\n' + ' }' + @@ -440,12 +437,11 @@ ' <% if (hasDontEnumBug) { %>\n\n' + ' var ctor = iteratee.constructor;\n' + ' <% for (var k = 0; k < 7; k++) { %>\n' + - ' index = \'<%= shadowed[k] %>\';\n' + + " index = '<%= shadowed[k] %>';\n" + ' if (<%' + - ' if (shadowed[k] == \'constructor\') {' + + " if (shadowed[k] == 'constructor') {" + ' %>!(ctor && ctor.prototype === iteratee) && <%' + ' } %>hasOwnProperty.call(iteratee, index)) {\n' + - ' value = iteratee[index];\n' + ' <%= objectLoop %>\n' + ' }' + ' <% } %>' + @@ -462,9 +458,9 @@ var assignIteratorOptions = { 'args': 'object, source, guard', 'top': - 'for (var argsIndex = 1, argsLength = typeof guard == \'number\' ? 2 : arguments.length; argsIndex < argsLength; argsIndex++) {\n' + + "for (var argsIndex = 1, argsLength = typeof guard == 'number' ? 2 : arguments.length; argsIndex < argsLength; argsIndex++) {\n" + ' if ((iteratee = arguments[argsIndex])) {', - 'objectLoop': 'result[index] = value', + 'objectLoop': 'result[index] = iteratee[index]', 'bottom': ' }\n}' }; @@ -474,8 +470,8 @@ var forEachIteratorOptions = { 'args': 'collection, callback, thisArg', 'top': 'callback = createCallback(callback, thisArg)', - 'arrayLoop': 'if (callback(value, index, collection) === false) return result', - 'objectLoop': 'if (callback(value, index, collection) === false) return result' + 'arrayLoop': 'if (callback(iteratee[index], index, collection) === false) return result', + 'objectLoop': 'if (callback(iteratee[index], index, collection) === false) return result' }; /** Reusable iterator options for `forIn` and `forOwn` */ @@ -3629,7 +3625,7 @@ * @example * * _.escape('Moe, Larry & Curly'); - * // => "Moe, Larry & Curly" + * // => 'Moe, Larry & Curly' */ function escape(string) { return string == null ? '' : (string + '').replace(reUnescapedHtml, escapeHtmlChar); @@ -3917,10 +3913,10 @@ // frame code as the function body source = 'function(' + variable + ') {\n' + (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') + - 'var __t, __p = \'\', __e = _.escape' + + "var __t, __p = '', __e = _.escape" + (isEvaluating ? ', __j = Array.prototype.join;\n' + - 'function print() { __p += __j.call(arguments, \'\') }\n' + "function print() { __p += __j.call(arguments, '') }\n" : (hasVariable ? '' : ', __d = ' + variable + '.' + variable + ' || ' + variable) + ';\n' ) + source + @@ -3996,7 +3992,7 @@ * @example * * _.unescape('Moe, Larry & Curly'); - * // => "Moe, Larry & Curly" + * // => 'Moe, Larry & Curly' */ function unescape(string) { return string == null ? '' : (string + '').replace(reEscapedHtml, unescapeHtmlChar);