-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fixed problems with colon character #363
Conversation
This pull should fixes problems with the colon character when used on pseudo-classes and other new CSS3 cases.
var test1 = source_text.substr(pos, source_text.indexOf(';') + 1); | ||
var test2 = source_text.substr(pos, source_text.indexOf('{') + 1); | ||
|
||
if(test1.length > test2.length) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please match the style of the file: 4 spaces per tab, space between if
keyword and opening paren.
Great, please at least add tests for your fixes (and related inputs). If possible, please translate to python css beautifier as well. |
I don't know how to add tests and I don't know python. I'll fix the formatting problems. With my fix there is an edge case bug that I'm trying to fix on Stackoverflow |
If you can't do the python, that is fine. I can do the translation. However, we're not taking significant changes in this area without tests to demonstrate proper functioning and protect from future regressions. Here is an example of someone adding tests for css-beautify changes. It is easy and straight-forward. |
I must be stupid but I can't understand how the file you have linked me could act as test... |
Add lines to that file (just like in the commit I linked) that follow the pattern: btc("input_css", "expected_output_css");
|
I hope it's ok how I did. |
After writing the tests, you need to run them with As written, the tests are failing with this output:
You'll notice there are extra line breaks after all of the output, and that the pseudo-class selector is still mangled. Also, there are still stylistic anomalies in beautify-css.js. You can run js-beautify on it in-place to resolve these discrepancies: npm -g install js-beautify
js-beautify -jr js/lib/beautify-css.js |
I've not git on my PC, don't know if I can use npm on Windows even. By the way I've noticed that the problem is if the file starts with something that doesn't have colon in it... I'll try to fix this problem. |
|
||
// colon character | ||
btc("#foo : hover{color:purple}","#foo:hover {\n color: purple\n}\n"); | ||
btc(": : selection {\ncolor: #ff0000;}", "::selection {\n color: #ff0000;\n}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These inputs are somewhat nonsensical, as they don't represent valid CSS syntax. It would be clearer if you just asserted properly formatted input (and then omit the second parameter, because it defaults to the first).
btc("#foo:hover {\n color: purple\n}\n");
btc("::selection {\n color: #ff0000;\n}\n");
Note that the second test has an added \n
, which fixes one breaking test. The #foo:hover
case is still breaking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought that the first parameter was the not formatted input and the second one the formatted one. Isn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the input and output are expected to be identical, all the test methods support simply passing one argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My input and output was not identical.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like I said initially, they should be. Who in their right mind writes invalid CSS syntax and then expects it to magically work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get what you mean, but if the beautifier can even remove extra spaces and make the syntax valid I can't see the problem. I didn't added extra code to do it, it's just a side effect of my patch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, yes, I want to take a part in this bikeshed as well!
The tests by themselves are ok — we have weird corner cases and some broken-code-formatting checks in the jsbeautifier code as well. The strong uneasiness I myself feel is that the tests need to clearly cover the proper input first, but currently there are no tests that make sure that the beautifier formats a clean, proper css code as well.
I.e something like this would make the tests much more structured and clear:
// selector support
btc("#foo :hover {...}", "#foo :hover {...}");
...
// handle some garbage as well, just because we can
btc(" : : selection", "::selection")
...and then we might have a separate discussion WHY would we ever want to test the garbage cases and what do we achieve by that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. Although, for the purposes of this bugfix, #foo :hover
is not valid CSS syntax. Pseudo-classes must always be attached to other selectors (some pseudo-elements (doubled colons), however, can be distinct).
I've just written a different patch for this problem, I can't find bugs with this method. The tests should be the same. |
And yet, things are still failing: https://travis-ci.org/einars/js-beautify/jobs/14276649 |
@@ -233,7 +233,19 @@ | |||
insideRule = false; | |||
} else if (ch === ":") { | |||
eatWhitespace(); | |||
output.push(ch, " "); | |||
|
|||
var text_after_pos = source_text.replace(new RegExp("('|\").*('|\")", "gm"), "").substr(pos - 1) + ";", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Running a global replace with a non-reusable regexp on the source content every time a colon is encountered is dramatically bad practice.
This one is a problem of the test, the correct output is the one provided as css_beautify output. Notice the space between the colon and the not.
The problem with the document starting with double dots is a problem that I will fix asap. About bad practice etc: honestly I think that keep the beautifier as-is, with lot of bugs and cases not supported is even worse than have some hack inside the code. But this is your choice. Personally I will use my patch for my projects. There's not a function because would be useless to have a function that is called only one time, just because it's very specific as I've said before. |
About the regex, maybe it could be performed only one time as first action of the beautifier. This would make everything faster and nicer. |
Regex over the entire input once first? Um, no. |
Interestingly, as long as one does not attempt to fix illegal syntax, I was able to accomplish this with far less confusing code: diff --git a/js/lib/beautify-css.js b/js/lib/beautify-css.js
index 8830659..4e23dc6 100644
--- a/js/lib/beautify-css.js
+++ b/js/lib/beautify-css.js
@@ -204,6 +204,7 @@
/*_____________________--------------------_____________________*/
var insideRule = false;
+ var blockLevel = 0;
while (true) {
var isAfterSpace = skipWhitespace();
@@ -226,27 +227,29 @@
} else {
indent();
print["{"](ch);
+ blockLevel += 1;
}
} else if (ch === '}') {
outdent();
print["}"](ch);
insideRule = false;
+ blockLevel -= 1;
} else if (ch === ":") {
eatWhitespace();
-
- var text_after_pos = source_text.replace(new RegExp("('|\").*('|\")", "gm"), "").substr(pos - 1) + ";",
- semicolon = text_after_pos.substr(0, text_after_pos.indexOf(';')).length,
- closed_brace = text_after_pos.substr(0, text_after_pos.indexOf('}')).length,
- open_brace = text_after_pos.substr(0, text_after_pos.indexOf('{')).length,
- test1 = (semicolon > closed_brace) ? closed_brace : semicolon;
-
- if (test1 > open_brace && open_brace !== 0) {
- output.push(ch);
- } else {
+ if (blockLevel) {
+ // 'property: value' delimiter
output.push(ch, " ");
+ insideRule = true;
+ } else {
+ if (peek() === ":") {
+ // pseudo-element
+ next();
+ output.push("::");
+ } else {
+ // pseudo-class
+ output.push(ch);
+ }
}
-
- insideRule = true;
} else if (ch === '"' || ch === '\'') {
output.push(eatString(ch));
} else if (ch === ';') {
diff --git a/js/test/beautify-tests.js b/js/test/beautify-tests.js
index 69c9678..6de0f0b 100755
--- a/js/test/beautify-tests.js
+++ b/js/test/beautify-tests.js
@@ -1760,14 +1760,21 @@ function run_beautifier_tests(test_obj, Urlencoded, js_beautify, html_beautify,
btc("#bla, #foo{color:green}", "#bla, #foo {\n color: green\n}\n");
btc("@media print {.tab{}}", "@media print {\n .tab {}\n}\n");
+ btc("@media print {.tab,.bat{}}", "@media print {\n .tab, .bat {}\n}\n");
+ // btc("@media screen {.tab,.bat:hover {color:red}}", "@media screen {\n .tab, .bat:hover {\n color: red\n }\n}\n");
btc("#bla, #foo{color:black}", "#bla, #foo {\n color: black\n}\n");
-
+
// colon character
- btc("#foo : hover{color:purple}","#foo:hover {\n color: purple\n}\n");
- btc(": : selection {\ncolor: #ff0000;}", "::selection {\n color: #ff0000;\n}");
-
+ btc("#foo:hover {\n color: purple\n}\n");
+ btc("#foo *:hover {\n color: purple\n}\n");
+ btc("::selection {\n color: #ff0000;\n}\n");
+
+ // btc("#foo : hover{color:purple}","#foo:hover {\n color: purple\n}\n");
+ // btc(": : selection {\ncolor: #ff0000;}", "::selection {\n color: #ff0000;\n}");
+
// particular edge case with braces and semicolons inside tags that allows custom text
- btc("a: not(\"foobar\\\";{}omg\"){\ncontent: 'example\\';{} text';\ncontent: \"example\\\";{} text\";}", "a: not(\"foobar\\\";{}omg\") {\n content: 'example\\';{} text';\n content: \"example\\\";{} text\";\n}");
+ btc("a:not(\"foobar\\\";{}omg\"){\ncontent: 'example\\';{} text';\ncontent: \"example\\\";{} text\";}",
+ "a:not(\"foobar\\\";{}omg\") {\n content: 'example\\';{} text';\n content: \"example\\\";{} text\";\n}\n");
return sanitytest;
} With one huge caveatIf you uncomment the commented |
Anyway, some really useful links on this subject: https://developer.mozilla.org/en-US/docs/Web/CSS/Syntax Problems like these almost convince me we should be using a parser like https://github.com/visionmedia/css |
With my patch it doesn't fail, but it adds "tabs" instead of spaces, I really don't know why.
|
Since your tests never passed, I fixed it with a much simpler algorithm that doesn't allow malformed syntax, but does support nesting blocks. Thanks for raising the issue. |
This pull should fixes problems with the colon character when used on pseudo-classes and other new CSS3 cases.
Before this code:
was converted in:
Notice the extra white-spaces added after each colon character.
My fix should have fixed this problem.