summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEevee (Alex Munroe) <eevee.git@veekun.com>2014-12-10 14:39:35 -0800
committerEevee (Alex Munroe) <eevee.git@veekun.com>2014-12-10 14:39:35 -0800
commit20c74b6796a244f118c2dcb4cf6b7b1e05b6789d (patch)
tree6e05c084e0f0d9c7e9878d147c95ae107b3f692d
parent77a58288ded8506cf8ca161fa2df5d8bd9876ece (diff)
downloadpyscss-20c74b6796a244f118c2dcb4cf6b7b1e05b6789d.tar.gz
Fix parsing of `@if(...)`, where there's no literal space.
-rw-r--r--scss/cssdefs.py10
-rw-r--r--scss/rule.py23
-rw-r--r--scss/tests/files/bugs/if-with-parentheses.css3
-rw-r--r--scss/tests/files/bugs/if-with-parentheses.scss7
4 files changed, 28 insertions, 15 deletions
diff --git a/scss/cssdefs.py b/scss/cssdefs.py
index d94206b..46b6877 100644
--- a/scss/cssdefs.py
+++ b/scss/cssdefs.py
@@ -428,7 +428,7 @@ def determine_encoding(buf):
# ------------------------------------------------------------------------------
-# Bits and pieces of grammar, mostly as regexen
+# Bits and pieces of the official CSS grammar
# These are the only pseudo-elements allowed to be specified with a single
# colon, for backwards compatibility
@@ -443,8 +443,7 @@ CSS2_PSEUDO_ELEMENTS = frozenset((
# or a backslash followed by one to six hex digits and a single optional
# whitespace. Escaped newlines become nothing.
# Ref: http://dev.w3.org/csswg/css-syntax-3/#consume-an-escaped-code-point
-unescape_rx = re.compile(
- r"\\([0-9a-fA-F]{1,6})[\n\t ]?|\\(.)|\\\n", re.DOTALL)
+escape_rx = re.compile(r"(?s)\\([0-9a-fA-F]{1,6})[\n\t ]?|\\(.)|\\\n")
def _unescape_one(match):
@@ -460,9 +459,12 @@ def unescape(string):
"""Given a raw CSS string (i.e. taken directly from CSS source with no
processing), eliminate all backslash escapes.
"""
- return unescape_rx.sub(_unescape_one, string)
+ return escape_rx.sub(_unescape_one, string)
+# ------------------------------------------------------------------------------
+# Ad-hoc regexes specific to pyscss
+
_expr_glob_re = re.compile(r'''
\#\{(.*?)\} # Global Interpolation only
''', re.VERBOSE)
diff --git a/scss/rule.py b/scss/rule.py
index 712f4ba..b8bf8c9 100644
--- a/scss/rule.py
+++ b/scss/rule.py
@@ -2,6 +2,7 @@ from __future__ import absolute_import
from __future__ import print_function
import logging
+import re
from scss.namespace import Namespace
@@ -239,17 +240,17 @@ class BlockHeader(object):
# Minor parsing
if prop.startswith('@'):
- if prop.lower().startswith('@else if '):
- directive = '@else if'
- argument = prop[9:]
- else:
- chunks = prop.split(None, 1)
- if len(chunks) == 2:
- directive, argument = chunks
- else:
- directive, argument = prop, None
- directive = directive.lower()
-
+ # This pattern MUST NOT BE ABLE TO FAIL!
+ # This is slightly more lax than the CSS syntax technically allows,
+ # e.g. identifiers aren't supposed to begin with three hyphens.
+ # But we don't care, and will just spit it back out anyway.
+ m = re.match(
+ u'@(else if|[-_a-zA-Z0-9\U00000080-\U0010FFFF]*)\\b',
+ prop, re.I)
+ directive = m.group(0).lower()
+ argument = prop[len(directive):].strip()
+ if not argument:
+ argument = None
return BlockAtRuleHeader(directive, argument, num_lines)
elif prop.split(None, 1)[0].endswith(':'):
# Syntax is "<scope>: [prop]" -- if the optional prop exists, it
diff --git a/scss/tests/files/bugs/if-with-parentheses.css b/scss/tests/files/bugs/if-with-parentheses.css
new file mode 100644
index 0000000..c342002
--- /dev/null
+++ b/scss/tests/files/bugs/if-with-parentheses.css
@@ -0,0 +1,3 @@
+a:hover {
+ text-decoration: underline;
+}
diff --git a/scss/tests/files/bugs/if-with-parentheses.scss b/scss/tests/files/bugs/if-with-parentheses.scss
new file mode 100644
index 0000000..44bf82e
--- /dev/null
+++ b/scss/tests/files/bugs/if-with-parentheses.scss
@@ -0,0 +1,7 @@
+a {
+ @if(true) {
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+}