Skip to content

Commit

Permalink
Even fewer cases where we kill LESS/SCSS pseudo-classes
Browse files Browse the repository at this point in the history
Closes #427
  • Loading branch information
bitwiseman committed Oct 3, 2014
1 parent 746e838 commit 18e96c4
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 16 deletions.
28 changes: 24 additions & 4 deletions js/lib/beautify-css.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,21 @@
str;
}

// Nested pseudo-class if we are insideRule
// and the next special character found opens
// a new block
function foundNestedPseudoClass() {
for (var i = pos + 1; i < source_text.length; i++){
var ch = source_text.charAt(i);
if (ch === "{"){
return true;
} else if (ch === ";" || ch === "}" || ch === ")") {
return false;
}
}
return false;
}

// printer
var basebaseIndentString = source_text.match(/^[\t ]*/)[0];
var singleIndent = new Array(indentSize + 1).join(indentCharacter);
Expand Down Expand Up @@ -267,13 +282,12 @@
if (variableOrRule in css_beautify.CONDITIONAL_GROUP_RULE) {
enteringConditionalGroup = true;
}
} else if (variableOrRule.indexOf(':') > 0) {
} else if (': '.indexOf(variableOrRule[variableOrRule.length -1]) >= 0) {
//we have a variable, add it and insert one space before continuing
next();
variableOrRule = eatString(":").replace(/\s$/, '');
variableOrRule = eatString(": ").replace(/\s$/, '');
output.push(variableOrRule);
print.singleSpace();
eatWhitespace();
}
} else if (ch === '{') {
if (peek(true) === '}') {
Expand Down Expand Up @@ -302,12 +316,15 @@
}
} else if (ch === ":") {
eatWhitespace();
if ((insideRule || enteringConditionalGroup) && !lookBack("&")) {
if ((insideRule || enteringConditionalGroup) &&
!(lookBack("&") || foundNestedPseudoClass())) {
// 'property: value' delimiter
// which could be in a conditional group query
output.push(':');
print.singleSpace();
} else {
// sass/less parent reference don't use a space
// sass nested pseudo-class don't use a space
if (peek() === ":") {
// pseudo-element
next();
Expand All @@ -318,6 +335,9 @@
}
}
} else if (ch === '"' || ch === '\'') {
if (isAfterSpace) {
print.singleSpace();
}
output.push(eatString(ch));
} else if (ch === ';') {
output.push(ch);
Expand Down
16 changes: 15 additions & 1 deletion js/test/beautify-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2365,7 +2365,21 @@ function run_beautifier_tests(test_obj, Urlencoded, js_beautify, html_beautify,
'\t\tcolor: green;\n' +
'\t}\n' +
'}');


// import
btc('@import "test";');

// don't break nested pseudo-classes
btc("a:first-child{color:red;div:first-child{color:black;}}",
"a:first-child {\n\tcolor: red;\n\tdiv:first-child {\n\t\tcolor: black;\n\t}\n}");

btc("a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}",
"a:first-child,\na:first-child {\n\tcolor: red;\n\tdiv:first-child, div:hover {\n\t\tcolor: black;\n\t}\n}");

// handle SASS/LESS parent reference
btc("div{&:first-letter {text-transform: uppercase;}}",
"div {\n\t&:first-letter {\n\t\ttext-transform: uppercase;\n\t}\n}");

//nested modifiers (&:hover etc)
btc(".tabs{&:hover{width:10px;}}", ".tabs {\n\t&:hover {\n\t\twidth: 10px;\n\t}\n}");
btc(".tabs{&.big{width:10px;}}", ".tabs {\n\t&.big {\n\t\twidth: 10px;\n\t}\n}");
Expand Down
30 changes: 26 additions & 4 deletions python/cssbeautifier/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,22 @@ def lookBack(self, string):
past = self.source_text[self.pos - len(string):self.pos]
return past.lower() == string

# Nested pseudo-class if we are insideRule
# and the next special character found opens
# a new block
def foundNestedPseudoClass(self):
i = self.pos + 1
while i < len(self.source_text):
ch = self.source_text[i]
if ch == "{":
return True
elif ch == ";" or ch == "}" or ch == ")":
return False
i += 1;

return False


def beautify(self):
m = re.search("^[\t ]*", self.source_text)
baseIndentString = m.group(0)
Expand Down Expand Up @@ -293,13 +309,14 @@ def beautify(self):
printer.nestedLevel += 1
if variableOrRule in self.CONDITIONAL_GROUP_RULE:
enteringConditionalGroup = True
elif ':' in variableOrRule:
elif variableOrRule[-1] in ": ":
# we have a variable, add it and a space after
self.next()
variableOrRule = self.eatString(":")
variableOrRule = self.eatString(": ")
if variableOrRule[-1].isspace():
variableOrRule = variableOrRule[:-1]
printer.push(variableOrRule)
printer.singleSpace();
self.eatWhitespace();


elif self.ch == '{':
Expand All @@ -326,12 +343,15 @@ def beautify(self):
printer.nestedLevel -= 1
elif self.ch == ":":
self.eatWhitespace()
if (insideRule or enteringConditionalGroup) and not self.lookBack('&'):
if (insideRule or enteringConditionalGroup) and \
not (self.lookBack('&') or self.foundNestedPseudoClass()):
# 'property: value' delimiter
# which could be in a conditional group query
printer.push(":")
printer.singleSpace()
else:
# sass/less parent reference don't use a space
# sass nested pseudo-class don't use a space
if self.peek() == ":":
# pseudo-element
self.next()
Expand All @@ -340,6 +360,8 @@ def beautify(self):
# pseudo-element
printer.push(":")
elif self.ch == '"' or self.ch == '\'':
if isAfterSpace:
printer.singleSpace()
printer.push(self.eatString(self.ch))
elif self.ch == ';':
printer.semicolon()
Expand Down
28 changes: 21 additions & 7 deletions python/cssbeautifier/tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ def testBasics(self):
t("@media print {.tab{}}", "@media print {\n\t.tab {}\n}")
t("@media print {.tab{background-image:url(foo@2x.png)}}", "@media print {\n\t.tab {\n\t\tbackground-image: url(foo@2x.png)\n\t}\n}")

t("a:before {\n" +
t("a:before {\n" +
"\tcontent: 'a{color:black;}\"\"\\'\\'\"\\n\\n\\na{color:black}\';\n" +
"}");

# may not eat the space before "["
t('html.js [data-custom="123"] {\n\topacity: 1.00;\n}')
t('html.js *[data-custom="123"] {\n\topacity: 1.00;\n}')
Expand All @@ -63,7 +63,7 @@ def testComments(self):
t("// comment", "// comment");
t(".selector1 {\n\tmargin: 0; /* This is a comment including an url http://domain.com/path/to/file.ext */\n}",
".selector1 {\n\tmargin: 0;\n\t/* This is a comment including an url http://domain.com/path/to/file.ext */\n}")

#single line comment support (less/sass)
t(".tabs{\n// comment\nwidth:10px;\n}", ".tabs {\n\t// comment\n\twidth: 10px;\n}")
t(".tabs{// comment\nwidth:10px;\n}", ".tabs {\n\t// comment\n\twidth: 10px;\n}")
Expand All @@ -86,7 +86,7 @@ def testSeperateSelectors(self):
def testBlockNesting(self):
self.resetOptions()
t = self.decodesto

t("#foo {\n\tbackground-image: url(foo@2x.png);\n\t@font-face {\n\t\tfont-family: 'Bitstream Vera Serif Bold';\n\t\tsrc: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');\n\t}\n}")
t("@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n\t@font-face {\n\t\tfont-family: 'Bitstream Vera Serif Bold';\n\t\tsrc: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');\n\t}\n}")

Expand Down Expand Up @@ -156,13 +156,27 @@ def testLessCss(self):
'}')

# Not sure if this is sensible
# but I believe it is correct to not remove the space in "&: hover".
# but I believe it is correct to not remove the space in "&: hover".
t('a {\n' +
'\t&: hover {\n' +
'\t\tcolor: green;\n' +
'\t}\n' +
'}');


# import
t('@import "test";');

# don't break nested pseudo-classes
t("a:first-child{color:red;div:first-child{color:black;}}",
"a:first-child {\n\tcolor: red;\n\tdiv:first-child {\n\t\tcolor: black;\n\t}\n}");

t("a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}",
"a:first-child,\na:first-child {\n\tcolor: red;\n\tdiv:first-child, div:hover {\n\t\tcolor: black;\n\t}\n}");

# handle SASS/LESS parent reference
t("div{&:first-letter {text-transform: uppercase;}}",
"div {\n\t&:first-letter {\n\t\ttext-transform: uppercase;\n\t}\n}");

# nested modifiers (&:hover etc)
t(".tabs{&:hover{width:10px;}}", ".tabs {\n\t&:hover {\n\t\twidth: 10px;\n\t}\n}")
t(".tabs{&.big{width:10px;}}", ".tabs {\n\t&.big {\n\t\twidth: 10px;\n\t}\n}")
Expand All @@ -188,6 +202,6 @@ def decodesto(self, input, expectation=None):
if not expectation == None:
self.assertMultiLineEqual(
cssbeautifier.beautify(expectation, self.options), expectation)

if __name__ == '__main__':
unittest.main()

0 comments on commit 18e96c4

Please sign in to comment.