Skip to content

Commit

Permalink
Handle Jinja whitespace control syntax
Browse files Browse the repository at this point in the history
It doesn’t exist in the Django flavor.
  • Loading branch information
motet-a committed Sep 6, 2018
1 parent 3040ad0 commit fa60351
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 33 deletions.
36 changes: 28 additions & 8 deletions jinjalint/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def __str__(self):
return '{}:{}'.format(self.line + 1, self.column)


@attr.s
@attr.s(frozen=True)
class Node:
begin = attr.ib() # Location
end = attr.ib() # Location
Expand All @@ -27,7 +27,7 @@ def __str__(self):
class OpeningTag(Node):
name = attr.ib()
attributes = attr.ib() # Interpolated<Attribute>
slash = attr.ib(default=None) # Slash | None
slash = attr.ib(default=None) # Slash | None (`Slash` if self-closing tag)

def __str__(self):
name = str(self.name)
Expand Down Expand Up @@ -123,9 +123,21 @@ class Jinja(Node):
@attr.s(frozen=True)
class JinjaVariable(Jinja):
content = attr.ib() # str
left_plus = attr.ib(default=False)
left_minus = attr.ib(default=False)
right_minus = attr.ib(default=False)

def __str__(self):
return '{{ ' + self.content + ' }}'
return ''.join([
'{{',
'+' if self.left_plus else '',
'-' if self.left_minus else '',
' ',
self.content,
' ',
'-' if self.right_minus else '',
'}}'
])


@attr.s(frozen=True)
Expand All @@ -140,13 +152,21 @@ def __str__(self):
class JinjaTag(Jinja):
name = attr.ib()
content = attr.ib() # str | None
left_plus = attr.ib(default=False)
left_minus = attr.ib(default=False)
right_minus = attr.ib(default=False)

def __str__(self):
s = '{% ' + self.name
if self.content:
s += ' ' + self.content

return s + ' %}'
return ''.join([
'{%',
'+' if self.left_plus else '',
'-' if self.left_minus else '',
(' ' + self.name) if self.name else '',
(' ' + self.content) if self.content else '',
' ',
'-' if self.right_minus else '',
'%}'
])


@attr.s(frozen=True)
Expand Down
64 changes: 43 additions & 21 deletions jinjalint/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,22 @@ def locate(parser):


def _combine_jinja_tag(locations, props):
head, name, content, tail = props
return JinjaTag(
name=name,
content=content,
name=props['name'],
content=props['extra_content'],
left_plus=props['left_plus'],
left_minus=props['left_minus'],
right_minus=props['right_minus'],
**locations,
)


def _combine_jinja_variable(locations, content):
def _combine_jinja_variable(locations, props):
return JinjaVariable(
content=content,
content=props['extra_content'],
left_plus=props['left_plus'],
left_minus=props['left_minus'],
right_minus=props['right_minus'],
**locations,
)

Expand All @@ -105,15 +110,39 @@ def _combine_jinja_comment(locations, text):
)


jinja_variable = (
locate(
P.string('{{')
.skip(whitespace)
.then(until(whitespace + P.string('}}')).concat())
.skip(whitespace + P.string('}}'))
def _combine_jinja_tag_like(locations, props):
return (
locations,
{
'left_plus': props['left_plus'] is not None,
'left_minus': props['left_minus'] is not None,
'name': props['name'],
'extra_content': props['extra_content'],
'right_minus': props['right_minus'] is not None,
}
)
.combine(_combine_jinja_variable)
)


def make_jinja_tag_like_parser(name, ml='{', mr='}'):
"""
Create parsers for Jinja variables and regular Jinja tags.
`name` should be a parser to parse the tag name.
"""
end = whitespace.then(P.string('-').optional()).skip(P.string(mr + '}'))
return locate(P.seq(
left_plus=P.string('{' + ml).then(P.string('+').optional()),
left_minus=P.string('-').optional().skip(whitespace),
name=name.skip(whitespace),
extra_content=until(end).concat(),
right_minus=end
)).combine(_combine_jinja_tag_like)


jinja_variable = make_jinja_tag_like_parser(
P.success(None), '{', '}'
).combine(_combine_jinja_variable)


jinja_comment = (
locate(
Expand All @@ -128,14 +157,7 @@ def _combine_jinja_comment(locations, text):

def make_jinja_tag_parser(name_parser):
return (
locate(
P.seq(
P.string('{%') + whitespace,
name_parser.skip(whitespace),
until(whitespace + P.string('%}')).concat(),
whitespace + P.string('%}'),
)
)
make_jinja_tag_like_parser(name_parser, '%', '%')
.combine(_combine_jinja_tag)
)

Expand Down
37 changes: 33 additions & 4 deletions jinjalint/parse_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,14 @@ def create_node(*args, **kwargs):
kwargs['begin'] = DummyLocation()
kwargs['end'] = DummyLocation()

return node_class(
*args,
**kwargs,
)
try:
return node_class(
*args,
**kwargs,
)
except Exception as error:
print(node_class)
raise error

return create_node

Expand Down Expand Up @@ -350,6 +354,30 @@ def test_jinja_blocks():
assert src == str(jinja.parse(src))


def test_jinja_whitespace_controls():
assert jinja.parse('{%- foo -%}') == JinjaElement(
parts=[
JinjaElementPart(
tag=JinjaTag(
name='foo',
content='',
left_minus=True,
right_minus=True,
),
content=None,
),
],
closing_tag=None,
)

assert str(jinja.parse('{%- foo -%}')) == '{%- foo -%}'
assert str(jinja.parse('{%- foo %}')) == '{%- foo %}'
assert str(jinja.parse('{{- bar -}}')) == '{{- bar -}}'
assert str(jinja.parse('{{ bar -}}')) == '{{ bar -}}'
assert str(jinja.parse('{%+ foo %}')) == '{%+ foo %}'
assert str(jinja.parse('{{+ bar }}')) == '{{+ bar }}'


def test_doctype():
assert content.parse('<!DOCTYPE html>') == Interp('<!DOCTYPE html>')

Expand Down Expand Up @@ -394,6 +422,7 @@ def test():
test_element()
test_self_closing_elements()
test_jinja_blocks()
test_jinja_whitespace_controls()
test_doctype()
test_attrs()
test_optional_container()

0 comments on commit fa60351

Please sign in to comment.