mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Error handling
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user