From 4f4188fd12ed48aecba69961bae2464e1a1b2ecd Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Sun, 14 Aug 2016 19:52:38 -0700 Subject: [PATCH] Add StringExpression.asInterpolation. --- lib/src/ast/sass/expression/string.dart | 59 ++++++++++++++++++++++--- lib/src/parser.dart | 10 +++-- lib/src/util/character.dart | 3 ++ 3 files changed, 62 insertions(+), 10 deletions(-) diff --git a/lib/src/ast/sass/expression/string.dart b/lib/src/ast/sass/expression/string.dart index 85c9ffd1..a31786cb 100644 --- a/lib/src/ast/sass/expression/string.dart +++ b/lib/src/ast/sass/expression/string.dart @@ -2,8 +2,11 @@ // MIT-style license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +import 'package:charcode/charcode.dart'; import 'package:source_span/source_span.dart'; +import '../../../interpolation_buffer.dart'; +import '../../../util/character.dart'; import '../../../visitor/sass/expression.dart'; import '../expression.dart'; import 'interpolation.dart'; @@ -18,13 +21,57 @@ class StringExpression implements Expression { FileSpan get span => text.span; - /// Interpolation that, when evaluated, produces the syntax of the string. - /// - /// Unlike [text], his doesn't resolve escapes and does include quotes. - InterpolationExpression get asInterpolation => throw new UnimplementedError(); + StringExpression(this.text); /*=T*/ accept/**/(ExpressionVisitor/**/ visitor) => visitor.visitStringExpression(this); - StringExpression(this.text); -} \ No newline at end of file + /// Interpolation that, when evaluated, produces the syntax of the string. + /// + /// Unlike [text], his doesn't resolve escapes and does include quotes. + InterpolationExpression asInterpolation({bool static: false, int quote}) { + quote ??= _bestQuote(); + var buffer = new InterpolationBuffer()..writeCharCode(quote); + for (var value in text.contents) { + if (value is InterpolationExpression) { + buffer.addInterpolation(value); + } else if (value is String) { + for (var i = 0; i < value.length; i++) { + var codeUnit = value.codeUnitAt(i); + + if (isNewline(codeUnit)) { + buffer.writeCharCode($backslash); + buffer.writeCharCode($a); + var next = i == value.length - 1 ? null : value.codeUnitAt(i + 1); + if (isWhitespace(next) || isHex(next)) buffer.writeCharCode($space); + } else { + if (codeUnit == quote || + codeUnit == $backslash || + (static && + codeUnit == $hash && + i < value.length - 1 && + value.codeUnitAt(i + 1) == $lbrace)) { + buffer.writeCharCode($backslash); + } + buffer.writeCharCode(codeUnit); + } + } + } + } + buffer.writeCharCode(quote); + + return buffer.interpolation(text.span); + } + + int _bestQuote() { + var containsDoubleQuote = false; + for (var value in text.contents) { + for (var i = 0; i < value.length; i++) { + var codeUnit = value.codeUnitAt(i); + if (codeUnit == $single_quote) return $double_quote; + if (codeUnit == $double_quote) containsDoubleQuote = true; + } + } + return containsDoubleQuote ? $single_quote : $double_quote; + } +} diff --git a/lib/src/parser.dart b/lib/src/parser.dart index b269b4ea..c88868d4 100644 --- a/lib/src/parser.dart +++ b/lib/src/parser.dart @@ -640,7 +640,7 @@ class Parser { case $double_quote: case $single_quote: - buffer.addInterpolation(_string().asInterpolation); + buffer.addInterpolation(_string().asInterpolation()); break; case $slash: @@ -701,7 +701,9 @@ class Parser { case $double_quote: case $single_quote: - buffer.addInterpolation(_string(static: static).asInterpolation); + buffer.addInterpolation( + _string(static: static) + .asInterpolation(static: static, quote: next)); wroteNewline = false; break; @@ -807,7 +809,7 @@ class Parser { if (next == null) { break; } else if (next == $underscore || next == $dash || - isAlphabetic(next) || isDigit(next) || next >= 0x0080) { + isAlphanumeric(next) || next >= 0x0080) { buffer.writeCharCode(_scanner.readChar()); } else if (next == $backslash) { buffer.writeCharCode(_escape()); @@ -1279,7 +1281,7 @@ class Parser { if (next == null) { break; } else if (next == $underscore || next == $dash || - isAlphabetic(next) || isDigit(next) || next >= 0x0080) { + isAlphanumeric(next) || next >= 0x0080) { text.writeCharCode(_scanner.readChar()); } else if (next == $backslash) { text.writeCharCode(_escape()); diff --git a/lib/src/util/character.dart b/lib/src/util/character.dart index fbb54365..619c357b 100644 --- a/lib/src/util/character.dart +++ b/lib/src/util/character.dart @@ -10,6 +10,9 @@ bool isWhitespace(int character) => bool isNewline(int character) => character == $lf || character == $cr || character == $ff; +bool isAlphanumeric(int character) => + isAlphabetic(character) || isDigit(character); + bool isAlphabetic(int character) => (character >= $a && character <= $z) || (character >= $A && character <= $Z);