Skip to content

Commit

Permalink
Support selector separator newline in nested selectors
Browse files Browse the repository at this point in the history
Fixes #666
  • Loading branch information
bitwiseman committed Jun 17, 2015
1 parent 0ff2940 commit 4cbe64a
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 34 deletions.
6 changes: 5 additions & 1 deletion js/lib/beautify-css.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@
/*_____________________--------------------_____________________*/

var insideRule = false;
var insidePropertyValue = false;
var enteringConditionalGroup = false;
var top_ch = '';
var last_top_ch = '';
Expand Down Expand Up @@ -345,6 +346,7 @@
outdent();
print["}"](ch);
insideRule = false;
insidePropertyValue = false;
if (nestedLevel) {
nestedLevel--;
}
Expand All @@ -357,6 +359,7 @@
!(lookBack("&") || foundNestedPseudoClass())) {
// 'property: value' delimiter
// which could be in a conditional group query
insidePropertyValue = true;
output.push(':');
print.singleSpace();
} else {
Expand All @@ -375,6 +378,7 @@
print.preserveSingleSpace();
output.push(eatString(ch));
} else if (ch === ';') {
insidePropertyValue = false;
output.push(ch);
print.newLine();
} else if (ch === '(') { // may be a url
Expand All @@ -400,7 +404,7 @@
} else if (ch === ',') {
output.push(ch);
eatWhitespace();
if (!insideRule && selectorSeparatorNewline && parenLevel < 1) {
if (selectorSeparatorNewline && !insidePropertyValue && parenLevel < 1) {
print.newLine();
} else {
print.singleSpace();
Expand Down
44 changes: 36 additions & 8 deletions js/test/beautify-css-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,42 @@ function run_css_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_bea
//
t('#cboxOverlay {\n\tbackground: url(images/overlay.png) repeat 0 0;\n\topacity: 0.9;\n\tfilter: alpha(opacity = 90);\n}', '#cboxOverlay {\n\tbackground: url(images/overlay.png) repeat 0 0;\n\topacity: 0.9;\n\tfilter: alpha(opacity=90);\n}');

// Selector Separator - (separator = " ", separator1 = " ")
opts.selector_separator_newline = false;
opts.selector_separator = " ";
t('#bla, #foo{color:green}', '#bla, #foo {\n\tcolor: green\n}');
t('@media print {.tab{}}', '@media print {\n\t.tab {}\n}');
t('@media print {.tab,.bat{}}', '@media print {\n\t.tab, .bat {}\n}');
t('#bla, #foo{color:black}', '#bla, #foo {\n\tcolor: black\n}');
t('a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}', 'a:first-child, a:first-child {\n\tcolor: red;\n\tdiv:first-child, div:hover {\n\t\tcolor: black;\n\t}\n}');

// Selector Separator - (separator = " ", separator1 = " ")
opts.selector_separator_newline = false;
opts.selector_separator = " ";
t('#bla, #foo{color:green}', '#bla, #foo {\n\tcolor: green\n}');
t('@media print {.tab{}}', '@media print {\n\t.tab {}\n}');
t('@media print {.tab,.bat{}}', '@media print {\n\t.tab, .bat {}\n}');
t('#bla, #foo{color:black}', '#bla, #foo {\n\tcolor: black\n}');
t('a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}', 'a:first-child, a:first-child {\n\tcolor: red;\n\tdiv:first-child, div:hover {\n\t\tcolor: black;\n\t}\n}');

// Selector Separator - (separator = "\n", separator1 = "\n\t")
opts.selector_separator_newline = true;
opts.selector_separator = " ";
t('#bla, #foo{color:green}', '#bla,\n#foo {\n\tcolor: green\n}');
t('@media print {.tab{}}', '@media print {\n\t.tab {}\n}');
t('@media print {.tab,.bat{}}', '@media print {\n\t.tab,\n\t.bat {}\n}');
t('#bla, #foo{color:black}', '#bla,\n#foo {\n\tcolor: black\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,\n\tdiv:hover {\n\t\tcolor: black;\n\t}\n}');

// Selector Separator - (separator = "\n", separator1 = "\n\t")
opts.selector_separator_newline = true;
opts.selector_separator = " ";
t('#bla, #foo{color:green}', '#bla,\n#foo {\n\tcolor: green\n}');
t('@media print {.tab{}}', '@media print {\n\t.tab {}\n}');
t('@media print {.tab,.bat{}}', '@media print {\n\t.tab,\n\t.bat {}\n}');
t('#bla, #foo{color:black}', '#bla,\n#foo {\n\tcolor: black\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,\n\tdiv:hover {\n\t\tcolor: black;\n\t}\n}');

// Newline Between Rules - (separator = "\n")
opts.newline_between_rules = true;
t('.div {}\n.span {}', '.div {}\n\n.span {}');
Expand Down Expand Up @@ -244,9 +280,6 @@ function run_css_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_bea
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}");
Expand All @@ -269,11 +302,6 @@ function run_css_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_bea
opts.indent_char = ' ';
opts.selector_separator_newline = false;

t("#bla, #foo{color:green}", "#bla, #foo {\n color: green\n}");
t("@media print {.tab{}}", "@media print {\n .tab {}\n}");
t("@media print {.tab,.bat{}}", "@media print {\n .tab, .bat {}\n}");
t("#bla, #foo{color:black}", "#bla, #foo {\n color: black\n}");

// pseudo-classes and pseudo-elements
t("#foo:hover {\n background-image: url([email protected])\n}");
t("#foo *:hover {\n color: purple\n}");
Expand Down
6 changes: 5 additions & 1 deletion python/cssbeautifier/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ def beautify(self):
printer = Printer(self.indentChar, self.indentSize, baseIndentString)

insideRule = False
insidePropertyValue = False
enteringConditionalGroup = False
top_ch = ''
last_top_ch = ''
Expand Down Expand Up @@ -369,6 +370,7 @@ def beautify(self):
printer.outdent()
printer.closeBracket()
insideRule = False
insidePropertyValue = False
if printer.nestedLevel:
printer.nestedLevel -= 1
if self.opts.newline_between_rules and printer.indentLevel == 0:
Expand All @@ -379,6 +381,7 @@ def beautify(self):
not (self.lookBack('&') or self.foundNestedPseudoClass()):
# 'property: value' delimiter
# which could be in a conditional group query
insidePropertyValue = True
printer.push(":")
printer.singleSpace()
else:
Expand All @@ -395,6 +398,7 @@ def beautify(self):
printer.preserveSingleSpace(isAfterSpace)
printer.push(self.eatString(self.ch))
elif self.ch == ';':
insidePropertyValue = False
printer.semicolon()
elif self.ch == '(':
# may be a url
Expand All @@ -418,7 +422,7 @@ def beautify(self):
elif self.ch == ',':
printer.push(self.ch)
self.eatWhitespace()
if not insideRule and self.opts.selector_separator_newline and parenLevel < 1:
if not insidePropertyValue and self.opts.selector_separator_newline and parenLevel < 1:
printer.newLine()
else:
printer.singleSpace()
Expand Down
44 changes: 36 additions & 8 deletions python/cssbeautifier/tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,42 @@ def testGenerated(self):
#
t('#cboxOverlay {\n\tbackground: url(images/overlay.png) repeat 0 0;\n\topacity: 0.9;\n\tfilter: alpha(opacity = 90);\n}', '#cboxOverlay {\n\tbackground: url(images/overlay.png) repeat 0 0;\n\topacity: 0.9;\n\tfilter: alpha(opacity=90);\n}')

# Selector Separator - (separator = " ", separator1 = " ")
self.options.selector_separator_newline = false
self.options.selector_separator = " "
t('#bla, #foo{color:green}', '#bla, #foo {\n\tcolor: green\n}')
t('@media print {.tab{}}', '@media print {\n\t.tab {}\n}')
t('@media print {.tab,.bat{}}', '@media print {\n\t.tab, .bat {}\n}')
t('#bla, #foo{color:black}', '#bla, #foo {\n\tcolor: black\n}')
t('a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}', 'a:first-child, a:first-child {\n\tcolor: red;\n\tdiv:first-child, div:hover {\n\t\tcolor: black;\n\t}\n}')

# Selector Separator - (separator = " ", separator1 = " ")
self.options.selector_separator_newline = false
self.options.selector_separator = " "
t('#bla, #foo{color:green}', '#bla, #foo {\n\tcolor: green\n}')
t('@media print {.tab{}}', '@media print {\n\t.tab {}\n}')
t('@media print {.tab,.bat{}}', '@media print {\n\t.tab, .bat {}\n}')
t('#bla, #foo{color:black}', '#bla, #foo {\n\tcolor: black\n}')
t('a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}', 'a:first-child, a:first-child {\n\tcolor: red;\n\tdiv:first-child, div:hover {\n\t\tcolor: black;\n\t}\n}')

# Selector Separator - (separator = "\n", separator1 = "\n\t")
self.options.selector_separator_newline = true
self.options.selector_separator = " "
t('#bla, #foo{color:green}', '#bla,\n#foo {\n\tcolor: green\n}')
t('@media print {.tab{}}', '@media print {\n\t.tab {}\n}')
t('@media print {.tab,.bat{}}', '@media print {\n\t.tab,\n\t.bat {}\n}')
t('#bla, #foo{color:black}', '#bla,\n#foo {\n\tcolor: black\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,\n\tdiv:hover {\n\t\tcolor: black;\n\t}\n}')

# Selector Separator - (separator = "\n", separator1 = "\n\t")
self.options.selector_separator_newline = true
self.options.selector_separator = " "
t('#bla, #foo{color:green}', '#bla,\n#foo {\n\tcolor: green\n}')
t('@media print {.tab{}}', '@media print {\n\t.tab {}\n}')
t('@media print {.tab,.bat{}}', '@media print {\n\t.tab,\n\t.bat {}\n}')
t('#bla, #foo{color:black}', '#bla,\n#foo {\n\tcolor: black\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,\n\tdiv:hover {\n\t\tcolor: black;\n\t}\n}')

# Newline Between Rules - (separator = "\n")
self.options.newline_between_rules = true
t('.div {}\n.span {}', '.div {}\n\n.span {}')
Expand Down Expand Up @@ -211,11 +247,6 @@ def testOptions(self):
self.options.selector_separator_newline = False
t = self.decodesto

t("#bla, #foo{color:green}", "#bla, #foo {\n color: green\n}")
t("@media print {.tab{}}", "@media print {\n .tab {}\n}")
t("@media print {.tab,.bat{}}", "@media print {\n .tab, .bat {}\n}")
t("#bla, #foo{color:black}", "#bla, #foo {\n color: black\n}")

# pseudo-classes and pseudo-elements
t("#foo:hover {\n background-image: url([email protected])\n}")
t("#foo *:hover {\n color: purple\n}")
Expand Down Expand Up @@ -264,9 +295,6 @@ def testLessCss(self):
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}");
Expand Down
43 changes: 43 additions & 0 deletions test/data/css.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,49 @@ exports.test_data = {
output: '#cboxOverlay {\n\tbackground: url(images/overlay.png) repeat 0 0;\n\topacity: 0.9;\n\tfilter: alpha(opacity=90);\n}'
},
],
}, {
name: 'Selector Separator',
description: '',
matrix: [
{
options: [
{ name: 'selector_separator_newline', value: 'false' },
{ name: 'selector_separator', value: '" "' }
],
separator: ' ',
separator1: ' '
}, {
options: [
{ name: 'selector_separator_newline', value: 'false' },
{ name: 'selector_separator', value: '" "' }
],
// BUG: #713
separator: ' ',
separator1: ' '
}, {
options: [
{ name: 'selector_separator_newline', value: 'true' },
{ name: 'selector_separator', value: '" "' }
],
separator: '\\n',
separator1: '\\n\\t'
}, {
options: [
{ name: 'selector_separator_newline', value: 'true' },
{ name: 'selector_separator', value: '" "' }
],
separator: '\\n',
separator1: '\\n\\t'
}
],
tests: [
{ input: '#bla, #foo{color:green}', output: '#bla,{{separator}}#foo {\n\tcolor: green\n}'},
{ input: '@media print {.tab{}}', output: '@media print {\n\t.tab {}\n}'},
{ input: '@media print {.tab,.bat{}}', output: '@media print {\n\t.tab,{{separator1}}.bat {}\n}'},
{ input: '#bla, #foo{color:black}', output: '#bla,{{separator}}#foo {\n\tcolor: black\n}'},
{ input: 'a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}',
output: 'a:first-child,{{separator}}a:first-child {\n\tcolor: red;\n\tdiv:first-child,{{separator1}}div:hover {\n\t\tcolor: black;\n\t}\n}'}
]
}, {
name: "Newline Between Rules",
description: "",
Expand Down
8 changes: 0 additions & 8 deletions test/template/node-css.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,6 @@ function run_css_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_bea
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}");
Expand All @@ -188,11 +185,6 @@ function run_css_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_bea
opts.indent_char = ' ';
opts.selector_separator_newline = false;

t("#bla, #foo{color:green}", "#bla, #foo {\n color: green\n}");
t("@media print {.tab{}}", "@media print {\n .tab {}\n}");
t("@media print {.tab,.bat{}}", "@media print {\n .tab, .bat {}\n}");
t("#bla, #foo{color:black}", "#bla, #foo {\n color: black\n}");

// pseudo-classes and pseudo-elements
t("#foo:hover {\n background-image: url([email protected])\n}");
t("#foo *:hover {\n color: purple\n}");
Expand Down
8 changes: 0 additions & 8 deletions test/template/python-css.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,6 @@ class CSSBeautifierTest(unittest.TestCase):
self.options.selector_separator_newline = False
t = self.decodesto

t("#bla, #foo{color:green}", "#bla, #foo {\n color: green\n}")
t("@media print {.tab{}}", "@media print {\n .tab {}\n}")
t("@media print {.tab,.bat{}}", "@media print {\n .tab, .bat {}\n}")
t("#bla, #foo{color:black}", "#bla, #foo {\n color: black\n}")

# pseudo-classes and pseudo-elements
t("#foo:hover {\n background-image: url([email protected])\n}")
t("#foo *:hover {\n color: purple\n}")
Expand Down Expand Up @@ -183,9 +178,6 @@ class CSSBeautifierTest(unittest.TestCase):
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}");
Expand Down

0 comments on commit 4cbe64a

Please sign in to comment.