Error handling

This commit is contained in:
Darren Burns
2022-02-04 11:43:35 +00:00
parent d50e2e1b0d
commit bb8b4e89d3
7 changed files with 215 additions and 180 deletions

View File

@@ -11,7 +11,7 @@ $animation: offset $animation-speed in_out_cubic;
App > View {
docks: side=left/1;
text: on $animation;
text: on $background;
}
Widget:hover {

View File

@@ -17,6 +17,7 @@ from .transition import Transition
from .types import Edge, Display, Visibility
from .._duration import _duration_as_seconds
from .._easing import EASING
from .._loop import loop_last
from ..geometry import Spacing, SpacingDimensions
from ..layouts.factory import get_layout, LayoutName, MissingLayout, LAYOUT_MAP
@@ -302,20 +303,26 @@ class StylesBuilder:
def process_text(self, name: str, tokens: list[Token], important: bool) -> None:
style_definition = " ".join(token.value for token in tokens)
if tokens and tokens[0].referenced_at:
variable_prefix = f"${tokens[0].referenced_at.name}="
# If every token in the value is a referenced by the same variable,
# we can display the variable name before the style definition.
# TODO: Factor this out to apply it to other properties too.
unique_references = set(t.referenced_by for t in tokens if t.referenced_by)
if tokens and tokens[0].referenced_by and len(unique_references) == 1:
variable_prefix = f"${tokens[0].referenced_by.name}="
else:
variable_prefix = ""
try:
style = Style.parse(style_definition)
self.styles.text = style
except Exception as error:
message = f"property 'text' has invalid value {variable_prefix}{style_definition!r};\n{error}"
message = f"property 'text' has invalid value {variable_prefix}{style_definition!r}; {error}"
self.error(name, tokens[0], message)
if important:
self.styles.important.update(
{"text_style", "text_background", "text_color"}
)
self.styles.text = style
def process_text_color(
self, name: str, tokens: list[Token], important: bool

View File

@@ -19,7 +19,7 @@ from .model import (
)
from .styles import Styles
from .tokenize import tokenize, tokenize_declarations, Token
from .tokenizer import EOFError, ReferencedAt
from .tokenizer import EOFError, ReferencedBy
SELECTOR_MAP: dict[str, tuple[SelectorType, tuple[int, int, int]]] = {
"selector": (SelectorType.TYPE, (0, 0, 1)),
@@ -229,7 +229,8 @@ def substitute_references(tokens: Iterator[Token]) -> Iterable[Token]:
Iterable[Token]: Yields Tokens such that any variable references (tokens where
token.name == "variable_ref") have been replaced with the tokens representing
the value. In other words, an Iterable of Tokens similar to the original input,
but with variables resolved.
but with variables resolved. Substituted tokens will have their referenced_by
attribute populated with information about where the tokens are being substituted to.
"""
variables: dict[str, list[Token]] = defaultdict(list)
while tokens:
@@ -264,7 +265,7 @@ def substitute_references(tokens: Iterator[Token]) -> Iterable[Token]:
ref_length = cell_len(token.value)
for token in reference_tokens:
yield token.ref(
ReferencedAt(
ReferencedBy(
name=ref_name,
location=ref_location,
length=ref_length,
@@ -285,7 +286,7 @@ def substitute_references(tokens: Iterator[Token]) -> Iterable[Token]:
ref_length = cell_len(token.value)
for token in variable_tokens:
yield token.ref(
ReferencedAt(
ReferencedBy(
name=variable_name,
location=ref_location,
length=ref_length,

View File

@@ -1,27 +1,25 @@
from __future__ import annotations
import os
from collections import defaultdict
from operator import itemgetter
import os
from typing import Iterable
import rich.repr
from rich.cells import cell_len
from rich.console import Group, RenderableType
from rich.highlighter import ReprHighlighter
from rich.padding import Padding
from rich.panel import Panel
from rich.syntax import Syntax
from rich.text import Text
from rich.console import Group, RenderableType
from textual._loop import loop_last
from .errors import StylesheetError
from .match import _check_selectors
from .model import RuleSet
from .parse import parse
from .types import Specificity3, Specificity4
from ..dom import DOMNode
from .. import log
class StylesheetParseError(Exception):
@@ -37,7 +35,7 @@ class StylesheetErrors:
self.stylesheet = stylesheet
@classmethod
def _get_snippet(cls, code: str, line_no: int, col_no: int, length: int) -> Panel:
def _get_snippet(cls, code: str, line_no: int) -> Panel:
syntax = Syntax(
code,
lexer="scss",
@@ -55,25 +53,30 @@ class StylesheetErrors:
append = errors.append
for rule in self.stylesheet.rules:
for token, message in rule.errors:
if token.referenced_at:
line_idx, col_idx = token.referenced_at.location
append("")
append(Text(" Error in stylesheet:", style="bold red"))
if token.referenced_by:
line_idx, col_idx = token.referenced_by.location
line_no, col_no = line_idx + 1, col_idx + 1
append(highlighter(f"{token.path or '<unknown>'}:{line_no}"))
append(
self._get_snippet(
token.code, line_no, col_no, token.referenced_at.length + 1
)
highlighter(f" {token.path or '<unknown>'}:{line_no}:{col_no}")
)
append(self._get_snippet(token.code, line_no))
else:
line_idx, col_idx = token.location
line_no, col_no = line_idx + 1, col_idx + 1
append(highlighter(f"{token.path or '<unknown>'}:{line_no}"))
append(
self._get_snippet(
token.code, line_no, col_no, cell_len(token.value) + 1
highlighter(f" {token.path or '<unknown>'}:{line_no}:{col_no}")
)
)
append(Padding(highlighter(Text(message, "red")), pad=(0, 1)))
append(self._get_snippet(token.code, line_no))
final_message = ""
for is_last, message_part in loop_last(message.split(";")):
end = "" if is_last else "\n"
final_message += f"{message_part.strip()};{end}"
append(Padding(highlighter(Text(final_message, "red")), pad=(0, 1)))
append("")
return Group(*errors)
@@ -184,7 +187,6 @@ class Stylesheet:
if __name__ == "__main__":
from rich.traceback import install
install(show_locals=True)

View File

@@ -39,7 +39,7 @@ class Expect:
yield from zip(self.names, self.regexes)
class ReferencedAt(NamedTuple):
class ReferencedBy(NamedTuple):
name: str
location: tuple[int, int]
length: int
@@ -52,16 +52,16 @@ class Token(NamedTuple):
path: str
code: str
location: tuple[int, int]
referenced_at: ReferencedAt | None
referenced_by: ReferencedBy | None
def ref(self, at: ReferencedAt | None) -> "Token":
def ref(self, by: ReferencedBy | None) -> "Token":
return Token(
name=self.name,
value=self.value,
path=self.path,
code=self.code,
location=self.location,
referenced_at=at,
referenced_by=by,
)
def __str__(self) -> str:
@@ -72,7 +72,7 @@ class Token(NamedTuple):
yield "value", self.value
yield "path", self.path
yield "location", self.location
yield "referenced_at", self.referenced_at
yield "referenced_by", self.referenced_by
class Tokenizer:
@@ -107,7 +107,7 @@ class Tokenizer:
break
token = Token(
name, value, self.path, self.code, (line_no, col_no), referenced_at=None
name, value, self.path, self.code, (line_no, col_no), referenced_by=None
)
col_no += len(value)
if col_no >= len(line):

View File

@@ -6,7 +6,7 @@ from textual.css.parse import substitute_references
from textual.css.scalar import Scalar, Unit
from textual.css.stylesheet import Stylesheet, StylesheetParseError
from textual.css.tokenize import tokenize
from textual.css.tokenizer import Token, ReferencedAt
from textual.css.tokenizer import Token, ReferencedBy
from textual.css.transition import Transition
from textual.layouts.dock import DockLayout
@@ -16,38 +16,39 @@ class TestVariableReferenceSubstitution:
css = "$x: 1; #some-widget{border: $x;}"
variables = substitute_references(tokenize(css, ""))
assert list(variables) == [
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_at=None),
Token(name='number', value='1', path='', code=css, location=(0, 4), referenced_at=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 5), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 6), referenced_at=None),
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_by=None),
Token(name='number', value='1', path='', code=css, location=(0, 4), referenced_by=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 5), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 6), referenced_by=None),
Token(name='selector_start_id', value='#some-widget', path='', code=css, location=(0, 7),
referenced_at=None),
Token(name='declaration_set_start', value='{', path='', code=css, location=(0, 19), referenced_at=None),
Token(name='declaration_name', value='border:', path='', code=css, location=(0, 20), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 27), referenced_at=None),
referenced_by=None),
Token(name='declaration_set_start', value='{', path='', code=css, location=(0, 19), referenced_by=None),
Token(name='declaration_name', value='border:', path='', code=css, location=(0, 20), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 27), referenced_by=None),
Token(name='number', value='1', path='', code=css, location=(0, 4),
referenced_at=ReferencedAt(name='x', location=(0, 28), length=2)),
Token(name='declaration_end', value=';', path='', code=css, location=(0, 30), referenced_at=None),
Token(name='declaration_set_end', value='}', path='', code=css, location=(0, 31), referenced_at=None)
referenced_by=ReferencedBy(name='x', location=(0, 28), length=2)),
Token(name='declaration_end', value=';', path='', code=css, location=(0, 30), referenced_by=None),
Token(name='declaration_set_end', value='}', path='', code=css, location=(0, 31), referenced_by=None)
]
def test_simple_reference_no_whitespace(self):
css = "$x:1; #some-widget{border: $x;}"
variables = substitute_references(tokenize(css, ""))
assert list(variables) == [
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_at=None),
Token(name='number', value='1', path='', code=css, location=(0, 3), referenced_at=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 4), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 5), referenced_at=None),
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_by=None),
Token(name='number', value='1', path='', code=css, location=(0, 3), referenced_by=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 4), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 5), referenced_by=None),
Token(name='selector_start_id', value='#some-widget', path='', code=css, location=(0, 6),
referenced_at=None),
Token(name='declaration_set_start', value='{', path='', code=css, location=(0, 18), referenced_at=None),
Token(name='declaration_name', value='border:', path='', code=css, location=(0, 19), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 26), referenced_at=None),
Token(name='number', value='1', path='', code=css, location=(0, 3), referenced_at=ReferencedAt(name='x', location=(0, 27), length=2)),
Token(name='declaration_end', value=';', path='', code=css, location=(0, 29), referenced_at=None),
Token(name='declaration_set_end', value='}', path='', code=css, location=(0, 30), referenced_at=None)
referenced_by=None),
Token(name='declaration_set_start', value='{', path='', code=css, location=(0, 18), referenced_by=None),
Token(name='declaration_name', value='border:', path='', code=css, location=(0, 19), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 26), referenced_by=None),
Token(name='number', value='1', path='', code=css, location=(0, 3),
referenced_by=ReferencedBy(name='x', location=(0, 27), length=2)),
Token(name='declaration_end', value=';', path='', code=css, location=(0, 29), referenced_by=None),
Token(name='declaration_set_end', value='}', path='', code=css, location=(0, 30), referenced_by=None)
]
def test_undefined_variable(self):
@@ -58,69 +59,93 @@ class TestVariableReferenceSubstitution:
def test_transitive_reference(self):
css = "$x: 1\n$y: $x\n.thing { border: $y }"
assert list(substitute_references(tokenize(css, ""))) == [
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_at=None),
Token(name='number', value='1', path='', code=css, location=(0, 4), referenced_at=None),
Token(name='variable_value_end', value='\n', path='', code=css, location=(0, 5), referenced_at=None),
Token(name='variable_name', value='$y:', path='', code=css, location=(1, 0), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 3), referenced_at=None),
Token(name='number', value='1', path='', code=css, location=(0, 4), referenced_at=ReferencedAt(name='x', location=(1, 4), length=2)),
Token(name='variable_value_end', value='\n', path='', code=css, location=(1, 6), referenced_at=None),
Token(name='selector_start_class', value='.thing', path='', code=css, location=(2, 0), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(2, 6), referenced_at=None),
Token(name='declaration_set_start', value='{', path='', code=css, location=(2, 7), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(2, 8), referenced_at=None),
Token(name='declaration_name', value='border:', path='', code=css, location=(2, 9), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(2, 16), referenced_at=None),
Token(name='number', value='1', path='', code=css, location=(0, 4), referenced_at=ReferencedAt(name='y', location=(2, 17), length=2)),
Token(name='whitespace', value=' ', path='', code=css, location=(2, 19), referenced_at=None),
Token(name='declaration_set_end', value='}', path='', code=css, location=(2, 20), referenced_at=None)
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_by=None),
Token(name='number', value='1', path='', code=css, location=(0, 4), referenced_by=None),
Token(name='variable_value_end', value='\n', path='', code=css, location=(0, 5), referenced_by=None),
Token(name='variable_name', value='$y:', path='', code=css, location=(1, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 3), referenced_by=None),
Token(name='number', value='1', path='', code=css, location=(0, 4),
referenced_by=ReferencedBy(name='x', location=(1, 4), length=2)),
Token(name='variable_value_end', value='\n', path='', code=css, location=(1, 6), referenced_by=None),
Token(name='selector_start_class', value='.thing', path='', code=css, location=(2, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(2, 6), referenced_by=None),
Token(name='declaration_set_start', value='{', path='', code=css, location=(2, 7), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(2, 8), referenced_by=None),
Token(name='declaration_name', value='border:', path='', code=css, location=(2, 9), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(2, 16), referenced_by=None),
Token(name='number', value='1', path='', code=css, location=(0, 4),
referenced_by=ReferencedBy(name='y', location=(2, 17), length=2)),
Token(name='whitespace', value=' ', path='', code=css, location=(2, 19), referenced_by=None),
Token(name='declaration_set_end', value='}', path='', code=css, location=(2, 20), referenced_by=None)
]
def test_multi_value_variable(self):
css = "$x: 2 4\n$y: 6 $x 2\n.thing { border: $y }"
assert list(substitute_references(tokenize(css, ""))) == [
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_at=None),
Token(name='number', value='2', path='', code=css, location=(0, 4), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 5), referenced_at=None),
Token(name='number', value='4', path='', code=css, location=(0, 6), referenced_at=None),
Token(name='variable_value_end', value='\n', path='', code=css, location=(0, 7), referenced_at=None),
Token(name='variable_name', value='$y:', path='', code=css, location=(1, 0), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 3), referenced_at=None),
Token(name='number', value='6', path='', code=css, location=(1, 4), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 5), referenced_at=None),
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_by=None),
Token(name='number', value='2', path='', code=css, location=(0, 4), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 5), referenced_by=None),
Token(name='number', value='4', path='', code=css, location=(0, 6), referenced_by=None),
Token(name='variable_value_end', value='\n', path='', code=css, location=(0, 7), referenced_by=None),
Token(name='variable_name', value='$y:', path='', code=css, location=(1, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 3), referenced_by=None),
Token(name='number', value='6', path='', code=css, location=(1, 4), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 5), referenced_by=None),
Token(name='number', value='2', path='', code=css, location=(0, 4),
referenced_at=ReferencedAt(name='x', location=(1, 6), length=2)),
referenced_by=ReferencedBy(name='x', location=(1, 6), length=2)),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 5),
referenced_at=ReferencedAt(name='x', location=(1, 6), length=2)),
referenced_by=ReferencedBy(name='x', location=(1, 6), length=2)),
Token(name='number', value='4', path='', code=css, location=(0, 6),
referenced_at=ReferencedAt(name='x', location=(1, 6), length=2)),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 8), referenced_at=None),
Token(name='number', value='2', path='', code=css, location=(1, 9), referenced_at=None),
Token(name='variable_value_end', value='\n', path='', code=css, location=(1, 10), referenced_at=None),
Token(name='selector_start_class', value='.thing', path='', code=css, location=(2, 0), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(2, 6), referenced_at=None),
Token(name='declaration_set_start', value='{', path='', code=css, location=(2, 7), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(2, 8), referenced_at=None),
Token(name='declaration_name', value='border:', path='', code=css, location=(2, 9), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(2, 16), referenced_at=None),
referenced_by=ReferencedBy(name='x', location=(1, 6), length=2)),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 8), referenced_by=None),
Token(name='number', value='2', path='', code=css, location=(1, 9), referenced_by=None),
Token(name='variable_value_end', value='\n', path='', code=css, location=(1, 10), referenced_by=None),
Token(name='selector_start_class', value='.thing', path='', code=css, location=(2, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(2, 6), referenced_by=None),
Token(name='declaration_set_start', value='{', path='', code=css, location=(2, 7), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(2, 8), referenced_by=None),
Token(name='declaration_name', value='border:', path='', code=css, location=(2, 9), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(2, 16), referenced_by=None),
Token(name='number', value='6', path='', code=css, location=(1, 4),
referenced_at=ReferencedAt(name='y', location=(2, 17), length=2)),
referenced_by=ReferencedBy(name='y', location=(2, 17), length=2)),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 5),
referenced_at=ReferencedAt(name='y', location=(2, 17), length=2)),
referenced_by=ReferencedBy(name='y', location=(2, 17), length=2)),
Token(name='number', value='2', path='', code=css, location=(0, 4),
referenced_at=ReferencedAt(name='y', location=(2, 17), length=2)),
referenced_by=ReferencedBy(name='y', location=(2, 17), length=2)),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 5),
referenced_at=ReferencedAt(name='y', location=(2, 17), length=2)),
referenced_by=ReferencedBy(name='y', location=(2, 17), length=2)),
Token(name='number', value='4', path='', code=css, location=(0, 6),
referenced_at=ReferencedAt(name='y', location=(2, 17), length=2)),
referenced_by=ReferencedBy(name='y', location=(2, 17), length=2)),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 8),
referenced_at=ReferencedAt(name='y', location=(2, 17), length=2)),
referenced_by=ReferencedBy(name='y', location=(2, 17), length=2)),
Token(name='number', value='2', path='', code=css, location=(1, 9),
referenced_at=ReferencedAt(name='y', location=(2, 17), length=2)),
Token(name='whitespace', value=' ', path='', code=css, location=(2, 19), referenced_at=None),
Token(name='declaration_set_end', value='}', path='', code=css, location=(2, 20), referenced_at=None)
referenced_by=ReferencedBy(name='y', location=(2, 17), length=2)),
Token(name='whitespace', value=' ', path='', code=css, location=(2, 19), referenced_by=None),
Token(name='declaration_set_end', value='}', path='', code=css, location=(2, 20), referenced_by=None)
]
def test_variable_used_inside_property_value(self):
css = "$x: red\n.thing { border: on $x; }"
assert list(substitute_references(tokenize(css, ""))) == [
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_by=None),
Token(name='token', value='red', path='', code=css, location=(0, 4), referenced_by=None),
Token(name='variable_value_end', value='\n', path='', code=css, location=(0, 7), referenced_by=None),
Token(name='selector_start_class', value='.thing', path='', code=css, location=(1, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 6), referenced_by=None),
Token(name='declaration_set_start', value='{', path='', code=css, location=(1, 7), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 8), referenced_by=None),
Token(name='declaration_name', value='border:', path='', code=css, location=(1, 9), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 16), referenced_by=None),
Token(name='token', value='on', path='', code=css, location=(1, 17), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 19), referenced_by=None),
Token(name='token', value='red', path='', code=css, location=(0, 4),
referenced_by=ReferencedBy(name='x', location=(1, 20), length=2)),
Token(name='declaration_end', value=';', path='', code=css, location=(1, 22), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 23), referenced_by=None),
Token(name='declaration_set_end', value='}', path='', code=css, location=(1, 24), referenced_by=None)
]

View File

@@ -20,65 +20,65 @@ VALID_VARIABLE_NAMES = [
def test_variable_declaration_valid_names(name):
css = f"${name}: black on red;"
assert list(tokenize(css, "")) == [
Token(name='variable_name', value=f'${name}:', path='', code=css, location=(0, 0), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 14), referenced_at=None),
Token(name='token', value='black', path='', code=css, location=(0, 15), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 20), referenced_at=None),
Token(name='token', value='on', path='', code=css, location=(0, 21), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 23), referenced_at=None),
Token(name='token', value='red', path='', code=css, location=(0, 24), referenced_at=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 27), referenced_at=None),
Token(name='variable_name', value=f'${name}:', path='', code=css, location=(0, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 14), referenced_by=None),
Token(name='token', value='black', path='', code=css, location=(0, 15), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 20), referenced_by=None),
Token(name='token', value='on', path='', code=css, location=(0, 21), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 23), referenced_by=None),
Token(name='token', value='red', path='', code=css, location=(0, 24), referenced_by=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 27), referenced_by=None),
]
def test_variable_declaration_multiple_values():
css = "$x: 2vw\t4% 6s red;"
assert list(tokenize(css, "")) == [
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_at=None),
Token(name='scalar', value='2vw', path='', code=css, location=(0, 4), referenced_at=None),
Token(name='whitespace', value='\t', path='', code=css, location=(0, 7), referenced_at=None),
Token(name='scalar', value='4%', path='', code=css, location=(0, 8), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 10), referenced_at=None),
Token(name='duration', value='6s', path='', code=css, location=(0, 11), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 13), referenced_at=None),
Token(name='token', value='red', path='', code=css, location=(0, 15), referenced_at=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 18), referenced_at=None),
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_by=None),
Token(name='scalar', value='2vw', path='', code=css, location=(0, 4), referenced_by=None),
Token(name='whitespace', value='\t', path='', code=css, location=(0, 7), referenced_by=None),
Token(name='scalar', value='4%', path='', code=css, location=(0, 8), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 10), referenced_by=None),
Token(name='duration', value='6s', path='', code=css, location=(0, 11), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 13), referenced_by=None),
Token(name='token', value='red', path='', code=css, location=(0, 15), referenced_by=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 18), referenced_by=None),
]
def test_variable_declaration_comment_ignored():
css = "$x: red; /* comment */"
assert list(tokenize(css, "")) == [
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_at=None),
Token(name='token', value='red', path='', code=css, location=(0, 4), referenced_at=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 7), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 8), referenced_at=None),
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_by=None),
Token(name='token', value='red', path='', code=css, location=(0, 4), referenced_by=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 7), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 8), referenced_by=None),
]
def test_variable_declaration_comment_interspersed_ignored():
css = "$x: re/* comment */d;"
assert list(tokenize(css, "")) == [
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_at=None),
Token(name='token', value='re', path='', code=css, location=(0, 4), referenced_at=None),
Token(name='token', value='d', path='', code=css, location=(0, 19), referenced_at=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 20), referenced_at=None),
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_by=None),
Token(name='token', value='re', path='', code=css, location=(0, 4), referenced_by=None),
Token(name='token', value='d', path='', code=css, location=(0, 19), referenced_by=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 20), referenced_by=None),
]
def test_variable_declaration_no_semicolon():
css = "$x: 1\n$y: 2"
assert list(tokenize(css, "")) == [
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_at=None),
Token(name='number', value='1', path='', code=css, location=(0, 4), referenced_at=None),
Token(name='variable_value_end', value='\n', path='', code=css, location=(0, 5), referenced_at=None),
Token(name='variable_name', value='$y:', path='', code=css, location=(1, 0), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 3), referenced_at=None),
Token(name='number', value='2', path='', code=css, location=(1, 4), referenced_at=None),
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_by=None),
Token(name='number', value='1', path='', code=css, location=(0, 4), referenced_by=None),
Token(name='variable_value_end', value='\n', path='', code=css, location=(0, 5), referenced_by=None),
Token(name='variable_name', value='$y:', path='', code=css, location=(1, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(1, 3), referenced_by=None),
Token(name='number', value='2', path='', code=css, location=(1, 4), referenced_by=None),
]
@@ -92,68 +92,68 @@ def test_variables_declarations_amongst_rulesets():
css = "$x:1; .thing{text:red;} $y:2;"
tokens = list(tokenize(css, ""))
assert tokens == [
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_at=None),
Token(name='number', value='1', path='', code=css, location=(0, 3), referenced_at=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 4), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 5), referenced_at=None),
Token(name='selector_start_class', value='.thing', path='', code=css, location=(0, 6), referenced_at=None),
Token(name='declaration_set_start', value='{', path='', code=css, location=(0, 12), referenced_at=None),
Token(name='declaration_name', value='text:', path='', code=css, location=(0, 13), referenced_at=None),
Token(name='token', value='red', path='', code=css, location=(0, 18), referenced_at=None),
Token(name='declaration_end', value=';', path='', code=css, location=(0, 21), referenced_at=None),
Token(name='declaration_set_end', value='}', path='', code=css, location=(0, 22), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 23), referenced_at=None),
Token(name='variable_name', value='$y:', path='', code=css, location=(0, 24), referenced_at=None),
Token(name='number', value='2', path='', code=css, location=(0, 27), referenced_at=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 28), referenced_at=None),
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_by=None),
Token(name='number', value='1', path='', code=css, location=(0, 3), referenced_by=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 4), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 5), referenced_by=None),
Token(name='selector_start_class', value='.thing', path='', code=css, location=(0, 6), referenced_by=None),
Token(name='declaration_set_start', value='{', path='', code=css, location=(0, 12), referenced_by=None),
Token(name='declaration_name', value='text:', path='', code=css, location=(0, 13), referenced_by=None),
Token(name='token', value='red', path='', code=css, location=(0, 18), referenced_by=None),
Token(name='declaration_end', value=';', path='', code=css, location=(0, 21), referenced_by=None),
Token(name='declaration_set_end', value='}', path='', code=css, location=(0, 22), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 23), referenced_by=None),
Token(name='variable_name', value='$y:', path='', code=css, location=(0, 24), referenced_by=None),
Token(name='number', value='2', path='', code=css, location=(0, 27), referenced_by=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 28), referenced_by=None),
]
def test_variables_reference_in_rule_declaration_value():
css = ".warn{text: $warning;}"
assert list(tokenize(css, "")) == [
Token(name='selector_start_class', value='.warn', path='', code=css, location=(0, 0), referenced_at=None),
Token(name='declaration_set_start', value='{', path='', code=css, location=(0, 5), referenced_at=None),
Token(name='declaration_name', value='text:', path='', code=css, location=(0, 6), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 11), referenced_at=None),
Token(name='variable_ref', value='$warning', path='', code=css, location=(0, 12), referenced_at=None),
Token(name='declaration_end', value=';', path='', code=css, location=(0, 20), referenced_at=None),
Token(name='declaration_set_end', value='}', path='', code=css, location=(0, 21), referenced_at=None),
Token(name='selector_start_class', value='.warn', path='', code=css, location=(0, 0), referenced_by=None),
Token(name='declaration_set_start', value='{', path='', code=css, location=(0, 5), referenced_by=None),
Token(name='declaration_name', value='text:', path='', code=css, location=(0, 6), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 11), referenced_by=None),
Token(name='variable_ref', value='$warning', path='', code=css, location=(0, 12), referenced_by=None),
Token(name='declaration_end', value=';', path='', code=css, location=(0, 20), referenced_by=None),
Token(name='declaration_set_end', value='}', path='', code=css, location=(0, 21), referenced_by=None),
]
def test_variables_reference_in_rule_declaration_value_multiple():
css = ".card{padding: $pad-y $pad-x;}"
assert list(tokenize(css, "")) == [
Token(name='selector_start_class', value='.card', path='', code=css, location=(0, 0), referenced_at=None),
Token(name='declaration_set_start', value='{', path='', code=css, location=(0, 5), referenced_at=None),
Token(name='declaration_name', value='padding:', path='', code=css, location=(0, 6), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 14), referenced_at=None),
Token(name='variable_ref', value='$pad-y', path='', code=css, location=(0, 15), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 21), referenced_at=None),
Token(name='variable_ref', value='$pad-x', path='', code=css, location=(0, 22), referenced_at=None),
Token(name='declaration_end', value=';', path='', code=css, location=(0, 28), referenced_at=None),
Token(name='declaration_set_end', value='}', path='', code=css, location=(0, 29), referenced_at=None)
Token(name='selector_start_class', value='.card', path='', code=css, location=(0, 0), referenced_by=None),
Token(name='declaration_set_start', value='{', path='', code=css, location=(0, 5), referenced_by=None),
Token(name='declaration_name', value='padding:', path='', code=css, location=(0, 6), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 14), referenced_by=None),
Token(name='variable_ref', value='$pad-y', path='', code=css, location=(0, 15), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 21), referenced_by=None),
Token(name='variable_ref', value='$pad-x', path='', code=css, location=(0, 22), referenced_by=None),
Token(name='declaration_end', value=';', path='', code=css, location=(0, 28), referenced_by=None),
Token(name='declaration_set_end', value='}', path='', code=css, location=(0, 29), referenced_by=None)
]
def test_variables_reference_in_variable_declaration():
css = "$x: $y;"
assert list(tokenize(css, "")) == [
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_at=None),
Token(name='variable_ref', value='$y', path='', code=css, location=(0, 4), referenced_at=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 6), referenced_at=None)
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_by=None),
Token(name='variable_ref', value='$y', path='', code=css, location=(0, 4), referenced_by=None),
Token(name='variable_value_end', value=';', path='', code=css, location=(0, 6), referenced_by=None)
]
def test_variable_references_in_variable_declaration_multiple():
css = "$x: $y $z\n"
assert list(tokenize(css, "")) == [
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_at=None),
Token(name='variable_ref', value='$y', path='', code=css, location=(0, 4), referenced_at=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 6), referenced_at=None),
Token(name='variable_ref', value='$z', path='', code=css, location=(0, 8), referenced_at=None),
Token(name='variable_value_end', value='\n', path='', code=css, location=(0, 10), referenced_at=None)
Token(name='variable_name', value='$x:', path='', code=css, location=(0, 0), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 3), referenced_by=None),
Token(name='variable_ref', value='$y', path='', code=css, location=(0, 4), referenced_by=None),
Token(name='whitespace', value=' ', path='', code=css, location=(0, 6), referenced_by=None),
Token(name='variable_ref', value='$z', path='', code=css, location=(0, 8), referenced_by=None),
Token(name='variable_value_end', value='\n', path='', code=css, location=(0, 10), referenced_by=None)
]