Skip to content
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

CSS insideNonNestedAtRule generic variable #2147

Merged
merged 14 commits into from
Jun 1, 2023
82 changes: 52 additions & 30 deletions js/src/css/beautifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,18 @@ function Beautifier(source_text, options) {

// https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
this.NESTED_AT_RULE = {
"@page": true,
"@font-face": true,
"@keyframes": true,
"page": true,
"font-face": true,
"keyframes": true,
// also in CONDITIONAL_GROUP_RULE below
"@media": true,
"@supports": true,
"@document": true
"media": true,
"supports": true,
"document": true
};
this.CONDITIONAL_GROUP_RULE = {
"@media": true,
"@supports": true,
"@document": true
"media": true,
"supports": true,
"document": true
};
this.NON_SEMICOLON_NEWLINE_PROPERTY = [
"grid-template-areas",
Expand Down Expand Up @@ -193,8 +193,7 @@ Beautifier.prototype.beautify = function() {
// label { content: blue }
var insidePropertyValue = false;
var enteringConditionalGroup = false;
var insideAtExtend = false;
var insideAtImport = false;
var insideNonNestedAtRule = false;
var insideScssMap = false;
var topCharacter = this._ch;
var insideNonSemiColonValues = false;
Expand Down Expand Up @@ -249,10 +248,32 @@ Beautifier.prototype.beautify = function() {

// Ensures any new lines following the comment are preserved
this.eatWhitespace(true);
} else if (this._ch === '@' || this._ch === '$') {
} else if (this._ch === '$') {
this.preserveSingleSpace(isAfterSpace);

// deal with less propery mixins @{...}
this.print_string(this._ch);

// strip trailing space, if present, for hash property checks
var variable = this._input.peekUntilAfter(/[: ,;{}()[\]\/='"]/g);

if (variable.match(/[ :]$/)) {
// we have a variable or pseudo-class, add it and insert one space before continuing
variable = this.eatString(": ").replace(/\s$/, '');
this.print_string(variable);
this._output.space_before_token = true;
}

variable = variable.replace(/\s$/, '');

// might be sass variable
if (parenLevel === 0 && variable.indexOf(':') !== -1) {
insidePropertyValue = true;
this.indent();
}
} else if (this._ch === '@') {
this.preserveSingleSpace(isAfterSpace);

// deal with less property mixins @{...}
if (this._input.peek() === '{') {
this.print_string(this._ch + this.eatString('}'));
} else {
Expand All @@ -270,22 +291,21 @@ Beautifier.prototype.beautify = function() {

variableOrRule = variableOrRule.replace(/\s$/, '');

if (variableOrRule === 'extend') {
insideAtExtend = true;
} else if (variableOrRule === 'import') {
insideAtImport = true;
}
// might be less variable
if (parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
insidePropertyValue = true;
this.indent();

// might be a nesting at-rule
if (variableOrRule in this.NESTED_AT_RULE) {
// might be a nesting at-rule
} else if (variableOrRule in this.NESTED_AT_RULE) {
this._nestedLevel += 1;
if (variableOrRule in this.CONDITIONAL_GROUP_RULE) {
enteringConditionalGroup = true;
}
// might be less variable
} else if (!insideRule && parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
insidePropertyValue = true;
this.indent();

// might be a non-nested at-rule
} else if (parenLevel === 0 && !insidePropertyValue) {
insideNonNestedAtRule = true;
}
}
} else if (this._ch === '#' && this._input.peek() === '{') {
Expand All @@ -297,6 +317,9 @@ Beautifier.prototype.beautify = function() {
this.outdent();
}

// non nested at rule becomes nested
insideNonNestedAtRule = false;

// when entering conditional groups, only rulesets are allowed
if (enteringConditionalGroup) {
enteringConditionalGroup = false;
Expand Down Expand Up @@ -337,8 +360,7 @@ Beautifier.prototype.beautify = function() {
if (previous_ch === '{') {
this._output.trim(true);
}
insideAtImport = false;
insideAtExtend = false;

if (insidePropertyValue) {
this.outdent();
insidePropertyValue = false;
Expand Down Expand Up @@ -372,9 +394,10 @@ Beautifier.prototype.beautify = function() {
}
}

if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideAtExtend && parenLevel === 0) {
if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideNonNestedAtRule && parenLevel === 0) {
// 'property: value' delimiter
// which could be in a conditional group query

this.print_string(':');
if (!insidePropertyValue) {
insidePropertyValue = true;
Expand Down Expand Up @@ -411,8 +434,7 @@ Beautifier.prototype.beautify = function() {
this.outdent();
insidePropertyValue = false;
}
insideAtExtend = false;
insideAtImport = false;
insideNonNestedAtRule = false;
this.print_string(this._ch);
this.eatWhitespace(true);

Expand Down Expand Up @@ -477,7 +499,7 @@ Beautifier.prototype.beautify = function() {
} else if (this._ch === ',') {
this.print_string(this._ch);
this.eatWhitespace(true);
if (this._options.selector_separator_newline && (!insidePropertyValue || insideScssMap) && parenLevel === 0 && !insideAtImport && !insideAtExtend) {
if (this._options.selector_separator_newline && (!insidePropertyValue || insideScssMap) && parenLevel === 0 && !insideNonNestedAtRule) {
this._output.add_new_line();
} else {
this._output.space_before_token = true;
Expand Down
17 changes: 17 additions & 0 deletions test/data/css/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -1995,6 +1995,23 @@ exports.test_data = {
unchanged: 'p {\n color: blue;\n}'
}]
}, {
name: "Issue #2012, #2147",
description: "Avoid whitespace between first colon and next character in non nested at-rules",
options: [],
tests: [{
unchanged: '@extend .btn-blue:hover;'
}, {
unchanged: '@import url("chrome://communicator/skin/");'
}, {
unchanged: '@apply w-4 lg:w-10 space-y-3 lg:space-x-12;'
}, {
unchanged: [
'h3 {',
' @apply flex flex-col lg:flex-row space-y-3 lg:space-x-12 items-start;',
'}'
]
}]
}, {

}
]
Expand Down