From b4c006086172ad832de48cb1a677153b1d110ef1 Mon Sep 17 00:00:00 2001 From: rolux Date: Sat, 26 May 2012 00:02:28 +0200 Subject: [PATCH] better Ox.minify --- source/Ox/js/JavaScript.js | 135 ++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 60 deletions(-) diff --git a/source/Ox/js/JavaScript.js b/source/Ox/js/JavaScript.js index c56944ee..5ec854a0 100644 --- a/source/Ox/js/JavaScript.js +++ b/source/Ox/js/JavaScript.js @@ -314,8 +314,8 @@ Ox.minify Minifies JavaScript 'for(a in b)\n{c=void 0;}' > Ox.minify('return a; return 0; return "";') 'return a;return 0;return"";' - > Ox.minify('return\na;\nreturn\n0;\nreturn\n"";') - 'return\na;\nreturn\n0;\nreturn\n"";\n' + > Ox.minify('return\na;\nreturn\n0;\nreturn\n\"\";') + 'return\na;return\n0;return\n"";' @*/ Ox.minify = function() { // see https://github.com/douglascrockford/JSMin/blob/master/README @@ -327,71 +327,86 @@ Ox.minify = function() { arguments[1](minify(source)); }); } + function isCommentOrLinebreakOrWhitespace(token) { + return token.type == 'comment' || isLinebreakOrWhitespace(token); + } + function isIdentifierOrNumber(token) { + return Ox.contains([ + 'constant', 'identifier', 'keyword', + 'number', 'method', 'object', 'property' + ], token.type); + } + function isIdentifierOrNumberOrString(token) { + return isIdentifierOrNumber(token) || token.type == 'string'; + } + function isLinebreakOrWhitespace(token) { + return Ox.contains(['linebreak', 'whitespace'], token.type); + } function minify(source) { var tokens = Ox.tokenize(source), - length = tokens.length; - function isIdentifierOrNumber(token) { - return [ - 'constant', 'identifier', 'keyword', - 'number', 'method', 'object', 'property' - ].indexOf(token.type) > -1; + length = tokens.length, + ret = ''; + function getValue(token) { + return source.substr(token.offset, token.length); } - return Ox.filter(Ox.map(tokens, function(token, i) { - var ret = source.substr(token.offset, token.length); - if (token.type == 'comment') { - if (ret[1] == '/') { - // replace line comment with newline - ret = i == length - 1 || tokens[i + 1].type == 'linebreak' - ? null : '\n'; - } else { - // replace block comment with space - ret = i == length - 1 || tokens[i + 1].type == 'whitespace' - ? null : ' '; + tokens.forEach(function(token, i) { + var next, nextToken, previousToken; + if (isLinebreakOrWhitespace(token)) { + previousToken = i == 0 ? null : tokens[i - 1]; + next = i + 1; + while ( + next < length + && isCommentOrLinebreakOrWhitespace(tokens[next]) + ) { + next++; } - } else if (token.type == 'linebreak' || token.type == 'whitespace') { - // remove consecutive linebreaks or whitespace - ret = ret[0]; + nextToken = next == length ? null : tokens[next]; } - if ( - // strip linebreaks, except between two tokens that - // are both either identifier or number or string - // or identifier in brackets or identifier with - // unary operator or array literal or object literal - // - // strip linebreaks, except after "break", "continue", - // "return", "++" or "--", where the linebreak becomes - // a semicolon - token.type == 'linebreak' && ( - i == 0 || i == length - 1 - || ( - !isIdentifierOrNumber(tokens[i - 1]) - && !tokens[i - 1].type == 'string' - && [')', ']', '}', '++', '--'].indexOf( - source.substr(tokens[i - 1].offset, tokens[i - 1].length) - ) == -1 + if (token.type == 'linebreak') { + // replace a linebreak between two tokens that are identifiers + // or numbers or strings or unary operators or grouping + // operators with a single newline, otherwise remove it + if ( + previousToken && nextToken && ( + isIdentifierOrNumberOrString(previousToken) + || Ox.contains([ + '++', '--', ')', ']', '}' + ], getValue(previousToken)) + ) && ( + isIdentifierOrNumberOrString(nextToken) + || Ox.contains([ + '+', '-', '++', '--', '~', '!', '(', '[', '{' + ], getValue(nextToken)) ) - || ( - !isIdentifierOrNumber(tokens[i + 1]) - && ['(', '[', '{', '+', '-', '++', '--'].indexOf( - source.substr(tokens[i + 1].offset, tokens[i + 1].length) - ) == -1 - ) - ) - ) { - ret = null; - } else if ( - // strip whitespace, except between two tokens - // that are both either identifier or number - token.type == 'whitespace' && ( - i == 0 || i == length - 1 - || !isIdentifierOrNumber(tokens[i - 1]) - || !isIdentifierOrNumber(tokens[i + 1]) - ) - ) { - ret = null; + ) { + ret += '\n'; + } + } else if (token.type == 'whitespace') { + // replace whitespace between two tokens that are identifiers or + // numbers, or between a token that ends with "+" or "-" and one + // that begins with "+" or "-", with a single space, otherwise + // remove it + if ( + previousToken && nextToken && (( + isIdentifierOrNumber(previousToken) + && isIdentifierOrNumber(nextToken) + ) || ( + Ox.contains([ + '+', '-', '++', '--' + ], getValue(previousToken)) + && Ox.contains([ + '+', '-', '++', '--' + ], getValue(nextToken)) + )) + ) { + ret += ' '; + } + } else if (token.type != 'comment') { + // remove comments and leave all other tokens untouched + ret += getValue(token); } - return ret; - })).join(''); + }); + return ret; } };