From 35349a643320bc96996c3318a8374ac0bd7f1cb9 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowicz Date: Sat, 2 Sep 2017 20:01:43 +0200 Subject: [PATCH] Fixes #965 - edge case in parsing comment endings. This is an edge case when a comment is closed twice leading to the second end marker leaking to the next token. --- History.md | 1 + lib/tokenizer/tokenize.js | 7 +++- test/tokenizer/tokenize-test.js | 74 +++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 50d7f84d5..67ffe34e9 100644 --- a/History.md +++ b/History.md @@ -11,6 +11,7 @@ * Fixed issue [#959](https://github.com/jakubpawlowicz/clean-css/issues/959) - regression in shortening long hex values. * Fixed issue [#960](https://github.com/jakubpawlowicz/clean-css/issues/960) - better explanation of `efficiency` stat. +* Fixed issue [#965](https://github.com/jakubpawlowicz/clean-css/issues/965) - edge case in parsing comment endings. [4.1.7 / 2017-07-14](https://github.com/jakubpawlowicz/clean-css/compare/v4.1.6...v4.1.7) ================== diff --git a/lib/tokenizer/tokenize.js b/lib/tokenizer/tokenize.js index f2d4ae843..8ad55d592 100644 --- a/lib/tokenizer/tokenize.js +++ b/lib/tokenizer/tokenize.js @@ -101,6 +101,7 @@ function intoTokens(source, externalContext, internalContext, isNested) { var wasCommentStart = false; var isCommentEnd; var wasCommentEnd = false; + var isCommentEndMarker; var isEscaped; var wasEscaped = false; var isRaw = false; @@ -117,7 +118,8 @@ function intoTokens(source, externalContext, internalContext, isNested) { isNewLineNix = character == Marker.NEW_LINE_NIX; isNewLineWin = character == Marker.NEW_LINE_NIX && source[position.index - 1] == Marker.NEW_LINE_WIN; isCommentStart = !wasCommentEnd && level != Level.COMMENT && !isQuoted && character == Marker.ASTERISK && source[position.index - 1] == Marker.FORWARD_SLASH; - isCommentEnd = !wasCommentStart && level == Level.COMMENT && character == Marker.FORWARD_SLASH && source[position.index - 1] == Marker.ASTERISK; + isCommentEndMarker = !wasCommentStart && !isQuoted && character == Marker.FORWARD_SLASH && source[position.index - 1] == Marker.ASTERISK; + isCommentEnd = level == Level.COMMENT && isCommentEndMarker; metadata = buffer.length === 0 ? [position.line, position.column, position.source] : @@ -182,6 +184,9 @@ function intoTokens(source, externalContext, internalContext, isNested) { level = levels.pop(); metadata = metadatas.pop() || null; buffer = buffers.pop() || []; + } else if (isCommentEndMarker && source[position.index + 1] != Marker.ASTERISK) { + externalContext.warnings.push('Unexpected \'*/\' at ' + formatPosition([position.line, position.column, position.source]) + '.'); + buffer = []; } else if (character == Marker.SINGLE_QUOTE && !isQuoted) { // single quotation start, e.g. a[href^='https<-- levels.push(level); diff --git a/test/tokenizer/tokenize-test.js b/test/tokenizer/tokenize-test.js index cd38c6067..f277a30b5 100644 --- a/test/tokenizer/tokenize-test.js +++ b/test/tokenizer/tokenize-test.js @@ -1015,6 +1015,80 @@ vows.describe(tokenize) ] ] ], + 'two comments one inside another and two rules': [ + '.block-1{color:red;/* comment 1 /* comment 2 */ */}.block-2{color:blue}', + [ + [ + 'rule', + [ + [ + 'rule-scope', + '.block-1', + [ + [1, 0, undefined] + ] + ] + ], + [ + [ + 'property', + [ + 'property-name', + 'color', + [ + [1, 9, undefined] + ] + ], + [ + 'property-value', + 'red', + [ + [1, 15, undefined] + ] + ] + ], + [ + 'comment', + '/* comment 1 /* comment 2 */', + [ + [1, 19, undefined] + ] + ] + ] + ], + [ + 'rule', + [ + [ + 'rule-scope', + '.block-2', + [ + [1, 51, undefined] + ] + ] + ], + [ + [ + 'property', + [ + 'property-name', + 'color', + [ + [1, 60, undefined] + ] + ], + [ + 'property-value', + 'blue', + [ + [1, 66, undefined] + ] + ] + ] + ] + ] + ] + ], 'rule wrapped between comments': [ '/* comment 1 */div/* comment 2 */{color:red}', [