Skip to content

Commit

Permalink
Update beautify-css.js for LESS @var and &: parent reference
Browse files Browse the repository at this point in the history
Fixes #489
Closes #496
  • Loading branch information
guymguym authored and bitwiseman committed Oct 1, 2014
1 parent 56f7441 commit e4d969e
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 20 deletions.
39 changes: 26 additions & 13 deletions js/lib/beautify-css.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
// http://www.w3.org/TR/CSS21/syndata.html#tokenization
// http://www.w3.org/TR/css3-syntax/

(function () {
(function() {
function css_beautify(source_text, options) {
options = options || {};
var indentSize = options.indent_size || 4;
Expand Down Expand Up @@ -103,6 +103,14 @@
return source_text.substring(start, pos + 1);
}

function peekString(endChar) {
var prev_pos = pos;
var str = eatString(endChar);
pos = prev_pos - 1;
next();
return str;
}

function eatWhitespace() {
var start = pos;
while (whiteRe.test(peek())) {
Expand Down Expand Up @@ -164,22 +172,22 @@
}

var print = {};
print["{"] = function (ch) {
print["{"] = function(ch) {
print.singleSpace();
output.push(ch);
print.newLine();
};
print["}"] = function (ch) {
print["}"] = function(ch) {
print.newLine();
output.push(ch);
print.newLine();
};

print._lastCharWhitespace = function () {
print._lastCharWhitespace = function() {
return whiteRe.test(output[output.length - 1]);
};

print.newLine = function (keepWhitespace) {
print.newLine = function(keepWhitespace) {
if (!keepWhitespace) {
while (print._lastCharWhitespace()) {
output.pop();
Expand All @@ -193,7 +201,7 @@
output.push(basebaseIndentString);
}
};
print.singleSpace = function () {
print.singleSpace = function() {
if (output.length && !print._lastCharWhitespace()) {
output.push(' ');
}
Expand Down Expand Up @@ -222,11 +230,14 @@
} else if (ch === '/' && peek() === '/') { // single line comment
output.push(eatComment(true), basebaseIndentString);
} else if (ch === '@') {
// strip trailing space, if present, for hash property checks
var atRule = eatString(" ").replace(/ $/, '');

// pass along the space we found as a separate item
output.push(atRule, ch);
if (isAfterSpace) {
print.singleSpace();
}
output.push(ch);

// strip trailing space, if present, for hash property checks
var atRule = peekString(" ").replace(/\s$/, '');

// might be a nesting at-rule
if (atRule in css_beautify.NESTED_AT_RULE) {
Expand Down Expand Up @@ -261,7 +272,7 @@
}
} else if (ch === ":") {
eatWhitespace();
if (insideRule || enteringConditionalGroup) {
if ((insideRule || enteringConditionalGroup) && !lookBack("&")) {
// 'property: value' delimiter
// which could be in a conditional group query
output.push(ch, " ");
Expand Down Expand Up @@ -362,8 +373,10 @@
/*global define */
if (typeof define === "function" && define.amd) {
// Add support for AMD ( https://github.com/amdjs/amdjs-api/wiki/AMD#defineamd-property- )
define([], function () {
return { css_beautify: css_beautify };
define([], function() {
return {
css_beautify: css_beautify
};
});
} else if (typeof exports !== "undefined") {
// Add support for CommonJS. Just put this file somewhere on your require.paths
Expand Down
26 changes: 26 additions & 0 deletions js/test/beautify-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2291,6 +2291,32 @@ function run_beautifier_tests(test_obj, Urlencoded, js_beautify, html_beautify,
*/
btc("@font-face {\n\tfont-family: 'Bitstream Vera Serif Bold';\n\tsrc: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');\n}\n@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo.png);\n\t}\n\t@media screen and (min-device-pixel-ratio: 2) {\n\t\t@font-face {\n\t\t\tfont-family: 'Helvetica Neue'\n\t\t}\n\t\t#foo:hover {\n\t\t\tbackground-image: url(foo@2x.png);\n\t\t}\n\t}\n}");

// less-css cases
btc('.well{@well-bg:@bg-color;@well-fg:@fg-color;}','.well {\n\t@well-bg: @bg-color;\n\t@well-fg: @fg-color;\n}');
btc('.well {&.active {\nbox-shadow: 0 1px 1px @border-color, 1px 0 1px @border-color;}}',
'.well {\n' +
'\t&.active {\n' +
'\t\tbox-shadow: 0 1px 1px @border-color, 1px 0 1px @border-color;\n' +
'\t}\n' +
'}');
btc('a {\n' +
'\tcolor: blue;\n' +
'\t&:hover {\n' +
'\t\tcolor: green;\n' +
'\t}\n' +
'\t& & &&&.active {\n' +
'\t\tcolor: green;\n' +
'\t}\n' +
'}');

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

// test options
opts.indent_size = 2;
opts.indent_char = ' ';
Expand Down
22 changes: 15 additions & 7 deletions python/cssbeautifier/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,13 @@ def eatString(self, endChar):
break
return self.source_text[start:self.pos] + endChar

def peekString(self, endChar):
start = self.pos
st = self.eatString(endChar)
self.pos = start - 1
self.next()
return st

def eatWhitespace(self):
start = self.pos
while WHITE_RE.search(self.peek()) is not None:
Expand Down Expand Up @@ -252,15 +259,16 @@ def beautify(self):
printer.comment(self.eatComment(True)[0:-1])
printer.newLine()
elif self.ch == '@':
# pass along the space we found as a separate item
if isAfterSpace:
printer.singleSpace()
printer.push(self.ch)

# strip trailing space, if present, for hash property check
atRule = self.eatString(" ")
if(atRule[-1] == " "):
atRule = self.peekString(" ")
if atRule[-1].isspace():
atRule = atRule[:-1]

# pass along the space we found as a separate item
printer.push(atRule)
printer.push(self.ch)

# might be a nesting at-rule
if atRule in self.NESTED_AT_RULE:
printer.nestedLevel += 1
Expand Down Expand Up @@ -290,7 +298,7 @@ def beautify(self):
printer.nestedLevel -= 1
elif self.ch == ":":
self.eatWhitespace()
if insideRule or enteringConditionalGroup:
if (insideRule or enteringConditionalGroup) and not self.lookBack('&'):
# 'property: value' delimiter
# which could be in a conditional group query
printer.push(self.ch)
Expand Down
29 changes: 29 additions & 0 deletions python/cssbeautifier/tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,35 @@ def testOptions(self):
t( "a:not(\"foobar\\\";{}omg\"){\ncontent: 'example\\';{} text';\ncontent: \"example\\\";{} text\";}",
"a:not(\"foobar\\\";{}omg\") {\n content: 'example\\';{} text';\n content: \"example\\\";{} text\";\n}")

def testLessCss(self):
self.resetOptions()
t = self.decodesto

t('.well{@well-bg:@bg-color;@well-fg:@fg-color;}','.well {\n\t@well-bg: @bg-color;\n\t@well-fg: @fg-color;\n}')
t('.well {&.active {\nbox-shadow: 0 1px 1px @border-color, 1px 0 1px @border-color;}}',
'.well {\n' +
'\t&.active {\n' +
'\t\tbox-shadow: 0 1px 1px @border-color, 1px 0 1px @border-color;\n' +
'\t}\n' +
'}')
t('a {\n' +
'\tcolor: blue;\n' +
'\t&:hover {\n' +
'\t\tcolor: green;\n' +
'\t}\n' +
'\t& & &&&.active {\n' +
'\t\tcolor: green;\n' +
'\t}\n' +
'}')

# Not sure if this is sensible
# 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' +
'}');

def decodesto(self, input, expectation=None):
if expectation == None:
expectation = input
Expand Down

0 comments on commit e4d969e

Please sign in to comment.