Skip to content

Commit 01a187e

Browse files
authored
fix(issue#4348): parse layer nesting syntax (#4349)
* Add fixes for layer at-rule nesting syntax parsing and associated tests.
1 parent 033e3b3 commit 01a187e

File tree

3 files changed

+108
-38
lines changed

3 files changed

+108
-38
lines changed

packages/less/src/less/parser/parser.js

Lines changed: 61 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2048,7 +2048,49 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
20482048
return null;
20492049
}
20502050
},
2051-
2051+
atruleUnknown: function (value, name, hasBlock) {
2052+
value = this.permissiveValue(/^[{;]/);
2053+
hasBlock = (parserInput.currentChar() === '{');
2054+
if (!value) {
2055+
if (!hasBlock && parserInput.currentChar() !== ';') {
2056+
error(''.concat(name, ' rule is missing block or ending semi-colon'));
2057+
}
2058+
}
2059+
else if (!value.value) {
2060+
value = null;
2061+
}
2062+
return [value, hasBlock];
2063+
},
2064+
atruleBlock: function (rules, value, isRooted, isKeywordList) {
2065+
rules = this.blockRuleset();
2066+
parserInput.save();
2067+
if (!rules && !isRooted) {
2068+
value = this.entity();
2069+
rules = this.blockRuleset();
2070+
}
2071+
if (!rules && !isRooted) {
2072+
parserInput.restore();
2073+
var e = [];
2074+
value = this.entity();
2075+
while (parserInput.$char(',')) {
2076+
e.push(value);
2077+
value = this.entity();
2078+
}
2079+
if (value && e.length > 0) {
2080+
e.push(value);
2081+
value = e;
2082+
isKeywordList = true;
2083+
}
2084+
else {
2085+
rules = this.blockRuleset();
2086+
}
2087+
}
2088+
else {
2089+
parserInput.forget();
2090+
}
2091+
2092+
return [rules, value, isKeywordList];
2093+
},
20522094
//
20532095
// A CSS AtRule
20542096
//
@@ -2127,48 +2169,29 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
21272169
error(`expected ${name} expression`);
21282170
}
21292171
} else if (hasUnknown) {
2130-
value = this.permissiveValue(/^[{;]/);
2131-
hasBlock = (parserInput.currentChar() === '{');
2132-
if (!value) {
2133-
if (!hasBlock && parserInput.currentChar() !== ';') {
2134-
error(`${name} rule is missing block or ending semi-colon`);
2135-
}
2136-
}
2137-
else if (!value.value) {
2138-
value = null;
2139-
}
2172+
const unknownPackage = this.atruleUnknown(value, name, hasBlock);
2173+
value = unknownPackage[0];
2174+
hasBlock = unknownPackage[1];
21402175
}
2141-
2176+
21422177
if (hasBlock) {
2143-
rules = this.blockRuleset();
2144-
2145-
parserInput.save();
2146-
2147-
if (!rules && !isRooted) {
2148-
value = this.entity();
2149-
rules = this.blockRuleset();
2150-
}
2178+
let blockPackage = this.atruleBlock(rules, value, isRooted, isKeywordList);
2179+
rules = blockPackage[0];
2180+
value = blockPackage[1];
2181+
isKeywordList = blockPackage[2];
21512182

2152-
if (!rules && !isRooted) {
2183+
if (!rules && !hasUnknown) {
21532184
parserInput.restore();
2154-
2155-
let e = [];
2156-
value = this.entity();
2157-
2158-
while (parserInput.$char(',')) {
2159-
e.push(value);
2160-
value = this.entity();
2185+
name = parserInput.$re(/^@[a-z-]+/);
2186+
const unknownPackage = this.atruleUnknown(value, name, hasBlock);
2187+
value = unknownPackage[0];
2188+
hasBlock = unknownPackage[1];
2189+
if (hasBlock) {
2190+
blockPackage = this.atruleBlock(rules, value, isRooted, isKeywordList);
2191+
rules = blockPackage[0];
2192+
value = blockPackage[1];
2193+
isKeywordList = blockPackage[2];
21612194
}
2162-
2163-
if (value && e.length > 0) {
2164-
e.push(value);
2165-
value = e;
2166-
isKeywordList = true;
2167-
} else {
2168-
rules = this.blockRuleset();
2169-
}
2170-
} else {
2171-
parserInput.forget();
21722195
}
21732196
}
21742197

packages/test-data/css/_main/layer.css

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,25 @@
6969
.parent:hover {
7070
background: lightgray;
7171
}
72+
@layer foo.baz {
73+
.bar {
74+
font-weight: bold;
75+
}
76+
}
77+
@layer framework {
78+
@layer layout {
79+
.container {
80+
display: grid;
81+
gap: 2rem;
82+
}
83+
}
84+
}
85+
@layer framework.layout {
86+
main {
87+
padding: 2rem;
88+
}
89+
p {
90+
margin-block: 1rem;
91+
color: #555;
92+
}
93+
}

packages/test-data/less/_main/layer.less

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,28 @@
8585
background: lightgray;
8686
}
8787
}
88+
89+
@layer foo.baz {
90+
.bar {
91+
font-weight: bold;
92+
}
93+
}
94+
95+
@layer framework {
96+
@layer layout {
97+
.container {
98+
display: grid;
99+
gap: 2rem;
100+
}
101+
}
102+
}
103+
104+
@layer framework.layout {
105+
main {
106+
padding: 2rem;
107+
}
108+
p {
109+
margin-block: 1rem;
110+
color: #555;
111+
}
112+
}

0 commit comments

Comments
 (0)