diff --git a/src/html/util/unicode.ts b/src/html/util/unicode.ts index 3087de54..c69142b9 100644 --- a/src/html/util/unicode.ts +++ b/src/html/util/unicode.ts @@ -45,6 +45,7 @@ export const LATIN_SMALL_Z = 0x7A export const LEFT_CURLY_BRACKET = 0x7B // { export const RIGHT_CURLY_BRACKET = 0x7D // } export const NULL_REPLACEMENT = 0xFFFD +export const COMMA = 0x2C /** * Check whether the code point is a whitespace. diff --git a/src/style/index.ts b/src/style/index.ts index da81c040..140bc998 100644 --- a/src/style/index.ts +++ b/src/style/index.ts @@ -121,6 +121,7 @@ function parseStyle( quote, openingParenOffset, comments, + defaultValue, } of iterateVBind(code, cssOptions)) { insertComments( document, @@ -201,6 +202,32 @@ function parseStyle( ), ) } + if (defaultValue.length) { + afterTokens.unshift( + createSimpleToken( + "Punctuator", + locationCalculator.getOffsetWithGap( + defaultValue[0].range[0], + ), + locationCalculator.getOffsetWithGap( + defaultValue[0].range[1], + ), + ",", + locationCalculator, + ), + createSimpleToken( + "HTMLRawText", + locationCalculator.getOffsetWithGap( + defaultValue[1].range[0], + ), + locationCalculator.getOffsetWithGap( + defaultValue[1].range[1], + ), + defaultValue[1].value, + locationCalculator, + ), + ) + } const beforeLast = beforeTokens[beforeTokens.length - 1] replaceAndSplitTokens( document, @@ -287,6 +314,7 @@ type VBindLocations = { quote: '"' | "'" | null openingParenOffset: number comments: CSSCommentToken[] + defaultValue: CSSToken[] } /** @@ -317,6 +345,7 @@ function* iterateVBind( quote: arg.quote, openingParenOffset: openingParen.openingParen.range[0], comments: [...openingParen.comments, ...arg.comments], + defaultValue: arg.defaultValue, } } } @@ -350,6 +379,7 @@ function parseVBindArg(tokenizer: CSSTokenScanner): { quote: '"' | "'" | null closingParen: CSSPunctuatorToken comments: CSSCommentToken[] + defaultValue: CSSToken[] } | null { const tokensBuffer: CSSToken[] = [] const comments: CSSCommentToken[] = [] @@ -370,14 +400,25 @@ function parseVBindArg(tokenizer: CSSTokenScanner): { quote: quotedToken.quote, closingParen: token, comments, + defaultValue: [], } } const startToken = tokensBuffer[0] || token + const commaToken = tokens.find( + (tk) => + tk.type === CSSTokenType.Punctuator && tk.value === ",", + ) return { - exprRange: [startToken.range[0], token.range[0]], + exprRange: [ + startToken.range[0], + (commaToken || token).range[0], + ], quote: null, closingParen: token, comments: [], + defaultValue: commaToken + ? tokens.slice(tokens.indexOf(commaToken)) + : [], } } diff --git a/src/style/tokenizer.ts b/src/style/tokenizer.ts index b01e9a38..dfe455c5 100644 --- a/src/style/tokenizer.ts +++ b/src/style/tokenizer.ts @@ -19,6 +19,7 @@ import { SEMICOLON, LEFT_SQUARE_BRACKET, RIGHT_SQUARE_BRACKET, + COMMA, } from "../html/util/unicode" export const enum CSSTokenType { @@ -315,6 +316,7 @@ export class CSSTokenizer { function isPunctuator(cp: number): boolean { return ( + cp === COMMA || cp === COLON || cp === SEMICOLON || // Brackets diff --git a/test/fixtures/document-fragment/style-variables-with-default-value/document-fragment.json b/test/fixtures/document-fragment/style-variables-with-default-value/document-fragment.json new file mode 100644 index 00000000..6adfa645 --- /dev/null +++ b/test/fixtures/document-fragment/style-variables-with-default-value/document-fragment.json @@ -0,0 +1,561 @@ +{ + "type": "VDocumentFragment", + "range": [ + 0, + 62 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 6, + "column": 0 + } + }, + "children": [ + { + "type": "VElement", + "range": [ + 0, + 61 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 5, + "column": 8 + } + }, + "name": "style", + "rawName": "style", + "namespace": "http://www.w3.org/1999/xhtml", + "startTag": { + "type": "VStartTag", + "range": [ + 0, + 7 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 7 + } + }, + "selfClosing": false, + "attributes": [] + }, + "children": [ + { + "type": "VText", + "range": [ + 7, + 28 + ], + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 3, + "column": 11 + } + }, + "value": "\n .text{\n color: " + }, + { + "type": "VExpressionContainer", + "range": [ + 28, + 47 + ], + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 3, + "column": 30 + } + }, + "expression": { + "type": "Identifier", + "start": 35, + "end": 40, + "loc": { + "start": { + "line": 3, + "column": 18 + }, + "end": { + "line": 3, + "column": 23 + } + }, + "range": [ + 35, + 40 + ], + "name": "color" + }, + "references": [ + { + "id": { + "type": "Identifier", + "start": 35, + "end": 40, + "loc": { + "start": { + "line": 3, + "column": 18 + }, + "end": { + "line": 3, + "column": 23 + } + }, + "range": [ + 35, + 40 + ], + "name": "color" + }, + "mode": "r" + } + ] + }, + { + "type": "VText", + "range": [ + 47, + 53 + ], + "loc": { + "start": { + "line": 3, + "column": 30 + }, + "end": { + "line": 5, + "column": 0 + } + }, + "value": ";\n }\n" + } + ], + "endTag": { + "type": "VEndTag", + "range": [ + 53, + 61 + ], + "loc": { + "start": { + "line": 5, + "column": 0 + }, + "end": { + "line": 5, + "column": 8 + } + } + }, + "variables": [], + "style": true + }, + { + "type": "VText", + "range": [ + 61, + 62 + ], + "loc": { + "start": { + "line": 5, + "column": 8 + }, + "end": { + "line": 6, + "column": 0 + } + }, + "value": "\n" + } + ], + "tokens": [ + { + "type": "HTMLTagOpen", + "range": [ + 0, + 6 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "value": "style" + }, + { + "type": "HTMLTagClose", + "range": [ + 6, + 7 + ], + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 7 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 7, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 2, + "column": 2 + } + }, + "value": "\n " + }, + { + "type": "HTMLRawText", + "range": [ + 10, + 16 + ], + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 8 + } + }, + "value": ".text{" + }, + { + "type": "HTMLWhitespace", + "range": [ + 16, + 21 + ], + "loc": { + "start": { + "line": 2, + "column": 8 + }, + "end": { + "line": 3, + "column": 4 + } + }, + "value": "\n " + }, + { + "type": "HTMLRawText", + "range": [ + 21, + 27 + ], + "loc": { + "start": { + "line": 3, + "column": 4 + }, + "end": { + "line": 3, + "column": 10 + } + }, + "value": "color:" + }, + { + "type": "HTMLWhitespace", + "range": [ + 27, + 28 + ], + "loc": { + "start": { + "line": 3, + "column": 10 + }, + "end": { + "line": 3, + "column": 11 + } + }, + "value": " " + }, + { + "type": "HTMLRawText", + "range": [ + 28, + 34 + ], + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 3, + "column": 17 + } + }, + "value": "v-bind" + }, + { + "type": "Punctuator", + "range": [ + 34, + 35 + ], + "loc": { + "start": { + "line": 3, + "column": 17 + }, + "end": { + "line": 3, + "column": 18 + } + }, + "value": "(" + }, + { + "type": "Identifier", + "value": "color", + "start": 35, + "end": 40, + "loc": { + "start": { + "line": 3, + "column": 18 + }, + "end": { + "line": 3, + "column": 23 + } + }, + "range": [ + 35, + 40 + ] + }, + { + "type": "Punctuator", + "range": [ + 40, + 41 + ], + "loc": { + "start": { + "line": 3, + "column": 23 + }, + "end": { + "line": 3, + "column": 24 + } + }, + "value": "," + }, + { + "type": "HTMLRawText", + "range": [ + 42, + 46 + ], + "loc": { + "start": { + "line": 3, + "column": 25 + }, + "end": { + "line": 3, + "column": 29 + } + }, + "value": "blue" + }, + { + "type": "Punctuator", + "range": [ + 46, + 47 + ], + "loc": { + "start": { + "line": 3, + "column": 29 + }, + "end": { + "line": 3, + "column": 30 + } + }, + "value": ")" + }, + { + "type": "HTMLRawText", + "range": [ + 47, + 48 + ], + "loc": { + "start": { + "line": 3, + "column": 30 + }, + "end": { + "line": 3, + "column": 31 + } + }, + "value": ";" + }, + { + "type": "HTMLWhitespace", + "range": [ + 48, + 51 + ], + "loc": { + "start": { + "line": 3, + "column": 31 + }, + "end": { + "line": 4, + "column": 2 + } + }, + "value": "\n " + }, + { + "type": "HTMLRawText", + "range": [ + 51, + 52 + ], + "loc": { + "start": { + "line": 4, + "column": 2 + }, + "end": { + "line": 4, + "column": 3 + } + }, + "value": "}" + }, + { + "type": "HTMLWhitespace", + "range": [ + 52, + 53 + ], + "loc": { + "start": { + "line": 4, + "column": 3 + }, + "end": { + "line": 5, + "column": 0 + } + }, + "value": "\n" + }, + { + "type": "HTMLEndTagOpen", + "range": [ + 53, + 60 + ], + "loc": { + "start": { + "line": 5, + "column": 0 + }, + "end": { + "line": 5, + "column": 7 + } + }, + "value": "style" + }, + { + "type": "HTMLTagClose", + "range": [ + 60, + 61 + ], + "loc": { + "start": { + "line": 5, + "column": 7 + }, + "end": { + "line": 5, + "column": 8 + } + }, + "value": "" + }, + { + "type": "HTMLWhitespace", + "range": [ + 61, + 62 + ], + "loc": { + "start": { + "line": 5, + "column": 8 + }, + "end": { + "line": 6, + "column": 0 + } + }, + "value": "\n" + } + ], + "comments": [], + "errors": [] +} \ No newline at end of file diff --git a/test/fixtures/document-fragment/style-variables-with-default-value/source.vue b/test/fixtures/document-fragment/style-variables-with-default-value/source.vue new file mode 100644 index 00000000..8daa0a3e --- /dev/null +++ b/test/fixtures/document-fragment/style-variables-with-default-value/source.vue @@ -0,0 +1,5 @@ + diff --git a/test/fixtures/document-fragment/style-variables-with-default-value/token-ranges.json b/test/fixtures/document-fragment/style-variables-with-default-value/token-ranges.json new file mode 100644 index 00000000..4efd3679 --- /dev/null +++ b/test/fixtures/document-fragment/style-variables-with-default-value/token-ranges.json @@ -0,0 +1,22 @@ +[ + "", + "\n ", + ".text{", + "\n ", + "color:", + " ", + "v-bind", + "(", + "color", + ",", + "blue", + ")", + ";", + "\n ", + "}", + "\n", + "", + "\n" +] \ No newline at end of file diff --git a/test/fixtures/document-fragment/style-variables-with-default-value/tree.json b/test/fixtures/document-fragment/style-variables-with-default-value/tree.json new file mode 100644 index 00000000..3cce7e83 --- /dev/null +++ b/test/fixtures/document-fragment/style-variables-with-default-value/tree.json @@ -0,0 +1,50 @@ +[ + { + "type": "VDocumentFragment", + "text": "\n", + "children": [ + { + "type": "VElement", + "text": "", + "children": [ + { + "type": "VStartTag", + "text": "", + "children": [] + } + ] + }, + { + "type": "VText", + "text": "\n", + "children": [] + } + ] + } +] \ No newline at end of file