From 639cf2888c6ebefad103c582556d1ec3d4aeba5f Mon Sep 17 00:00:00 2001 From: Daniel Puckowski Date: Tue, 10 Dec 2024 18:33:16 -0500 Subject: [PATCH 1/4] fix(issue:3622) resolve rigid parenthesis parsing * Fix issue #3622 by resolving rigid parethensis parsing issues. --- packages/less/src/less/parser/parser.js | 29 ++++++---------- packages/less/src/less/tree/index.js | 3 +- packages/less/src/less/tree/list-paren.js | 21 ++++++++++++ packages/test-data/css/_main/selectors.css | 21 ++++++++++++ packages/test-data/less/_main/selectors.less | 36 ++++++++++++++++++++ 5 files changed, 91 insertions(+), 19 deletions(-) create mode 100644 packages/less/src/less/tree/list-paren.js diff --git a/packages/less/src/less/parser/parser.js b/packages/less/src/less/parser/parser.js index b87b4d762..3a27f4f16 100644 --- a/packages/less/src/less/parser/parser.js +++ b/packages/less/src/less/parser/parser.js @@ -5,7 +5,6 @@ import getParserInput from './parser-input'; import * as utils from '../utils'; import functionRegistry from '../functions/function-registry'; import { ContainerSyntaxOptions, MediaSyntaxOptions } from '../tree/atrule-syntax'; -import Selector from '../tree/selector'; import Anonymous from '../tree/anonymous'; // @@ -1314,24 +1313,18 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) { if (!e) { parserInput.save(); if (parserInput.$char('(')) { - if ((v = this.selector(false))) { - let selectors = []; - while (parserInput.$char(',')) { - selectors.push(v); - selectors.push(new Anonymous(',')); - v = this.selector(false); - } - selectors.push(v); - - if (parserInput.$char(')')) { - if (selectors.length > 1) { - e = new (tree.Paren)(new Selector(selectors)); - } else { - e = new(tree.Paren)(v); - } - parserInput.forget(); + let vSelectors = []; + while ((v = this.selector(false)) && parserInput.$char(',')) { + vSelectors.push(v); + vSelectors.push(new Anonymous(',')); + } + vSelectors.push(v); + + if (v && parserInput.$char(')')) { + if (vSelectors.length === 1) { + e = new (tree.Paren)(vSelectors[0]); } else { - parserInput.restore('Missing closing \')\''); + e = new (tree.ListParen)(vSelectors); } } else { parserInput.restore('Missing closing \')\''); diff --git a/packages/less/src/less/tree/index.js b/packages/less/src/less/tree/index.js index 1d4fbfdd7..74b89d6da 100644 --- a/packages/less/src/less/tree/index.js +++ b/packages/less/src/less/tree/index.js @@ -38,6 +38,7 @@ import NamespaceValue from './namespace-value'; // mixins import MixinCall from './mixin-call'; import MixinDefinition from './mixin-definition'; +import ListParen from './list-paren'; export default { Node, Color, AtRule, DetachedRuleset, Operation, @@ -47,7 +48,7 @@ export default { Comment, Anonymous, Value, JavaScript, Assignment, Condition, Paren, Media, Container, QueryInParens, UnicodeDescriptor, Negative, Extend, VariableCall, - NamespaceValue, + NamespaceValue, ListParen, mixin: { Call: MixinCall, Definition: MixinDefinition diff --git a/packages/less/src/less/tree/list-paren.js b/packages/less/src/less/tree/list-paren.js new file mode 100644 index 000000000..5600cc3ef --- /dev/null +++ b/packages/less/src/less/tree/list-paren.js @@ -0,0 +1,21 @@ +import Node from './node'; + +const ListParen = function(node) { + this.value = node; +}; + +ListParen.prototype = Object.assign(new Node(), { + type: 'ListParen', + + genCSS(context, output) { + output.add('('); + this.value.forEach(val => val.genCSS(context, output)); + output.add(')'); + }, + + eval(context) { + return new ListParen(this.value.map(val => val.eval(context))); + } +}); + +export default ListParen; diff --git a/packages/test-data/css/_main/selectors.css b/packages/test-data/css/_main/selectors.css index 92c8b824f..164abfb48 100644 --- a/packages/test-data/css/_main/selectors.css +++ b/packages/test-data/css/_main/selectors.css @@ -189,3 +189,24 @@ a:is(.b, :is(.c)) { a:is(.b, :is(.c), :has(div)) { color: red; } +@-moz-document domain("example.com") { + :is( + [a1], + [a2] + ):is( [a3], [a4]:not( :is([a5],[a6])):is( [a7]:not(:is([a8],[a9])), [b1]:not(:is([b2],[b3]))):is( + [b4],[b5] + ), [b6], [b7]) { + color: red; + } +} +@-moz-document domain("example.com") { + :is([foo], [bar], [baz]) { + color: red; + } +} +:is(.color-1, .focus-color-1:focus, .hover-color-1:hover) { + color: red !important; +} +:is(.color-2, .focus-color-2:focus, .hover-color-2:hover) { + color: green !important; +} diff --git a/packages/test-data/less/_main/selectors.less b/packages/test-data/less/_main/selectors.less index c976380a8..055cdb1b2 100644 --- a/packages/test-data/less/_main/selectors.less +++ b/packages/test-data/less/_main/selectors.less @@ -208,3 +208,39 @@ a:is(.b, :is(.c)) { a:is(.b, :is(.c), :has(div)) { color: red; } + +@-moz-document domain("example.com") { + :is( + [a1], + [a2] + ):is( + [a3], + [a4]:not( + :is([a5],[a6]) + ):is( + [a7]:not(:is([a8],[a9])), + [b1]:not(:is([b2],[b3])) + ):is( + [b4],[b5] + ), + [b6], + [b7] + ) { + color: red; } + +} + +@-moz-document domain("example.com") { + :is([foo], [bar] /* :is(a, b) */, [baz]) { + color: red; } +} + +@color: red green; + +each(@color, { + :is(.color-@{key}, + .focus-color-@{key}:focus, + .hover-color-@{key}:hover) { + color: @value !important; + } +}); From 6d17982004c46074529073af1228c2929c606fdd Mon Sep 17 00:00:00 2001 From: Daniel Puckowski Date: Wed, 11 Dec 2024 16:21:12 -0500 Subject: [PATCH 2/4] fix(isse:3622) improve logic for issue #3622 * Improve logic for different scenarios for issue #3622. --- packages/less/src/less/parser/parser.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/less/src/less/parser/parser.js b/packages/less/src/less/parser/parser.js index 3a27f4f16..9c6e50e2e 100644 --- a/packages/less/src/less/parser/parser.js +++ b/packages/less/src/less/parser/parser.js @@ -1320,14 +1320,18 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) { } vSelectors.push(v); - if (v && parserInput.$char(')')) { - if (vSelectors.length === 1) { - e = new (tree.Paren)(vSelectors[0]); + if (v) { + if (parserInput.$char(')')) { + if (vSelectors.length === 1) { + e = new (tree.Paren)(vSelectors[0]); + } else { + e = new (tree.ListParen)(vSelectors); + } } else { - e = new (tree.ListParen)(vSelectors); + parserInput.restore('Missing closing \')\''); } } else { - parserInput.restore('Missing closing \')\''); + parserInput.restore('Could not find valid selector'); } } else { parserInput.forget(); From afc55574e55532776192d3dd5127c6a8d73184e6 Mon Sep 17 00:00:00 2001 From: Daniel Puckowski Date: Wed, 11 Dec 2024 16:23:16 -0500 Subject: [PATCH 3/4] refactor: cleanup unused code for issue #3622 * Refactor and cleanup unused code for issue #3622. --- packages/less/src/less/parser/parser.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/less/src/less/parser/parser.js b/packages/less/src/less/parser/parser.js index 9c6e50e2e..6df9d61a1 100644 --- a/packages/less/src/less/parser/parser.js +++ b/packages/less/src/less/parser/parser.js @@ -1410,9 +1410,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) { } else { if (allExtends) { error('Extend can only be used at the end of selector'); } c = parserInput.currentChar(); - if (Array.isArray(e)){ - e.forEach(ele => elements.push(ele)); - } if (elements) { + if (elements) { elements.push(e); } else { elements = [ e ]; From 77a275f55447e87ee2f3068fd285d44c56b40732 Mon Sep 17 00:00:00 2001 From: Daniel Puckowski Date: Wed, 11 Dec 2024 16:26:19 -0500 Subject: [PATCH 4/4] fix(issue:3622) add incorrectly removed code back * Fix for issue #3622. Add incorrectly removed code back in for merge. --- packages/less/src/less/parser/parser.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/less/src/less/parser/parser.js b/packages/less/src/less/parser/parser.js index 6df9d61a1..9c6e50e2e 100644 --- a/packages/less/src/less/parser/parser.js +++ b/packages/less/src/less/parser/parser.js @@ -1410,7 +1410,9 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) { } else { if (allExtends) { error('Extend can only be used at the end of selector'); } c = parserInput.currentChar(); - if (elements) { + if (Array.isArray(e)){ + e.forEach(ele => elements.push(ele)); + } if (elements) { elements.push(e); } else { elements = [ e ];