diff --git a/packages/core/src/parser/model/BrowserParserCss.ts b/packages/core/src/parser/model/BrowserParserCss.ts index a7c16dcc1..459acee2e 100644 --- a/packages/core/src/parser/model/BrowserParserCss.ts +++ b/packages/core/src/parser/model/BrowserParserCss.ts @@ -66,25 +66,28 @@ export const parseSelector = (str = '') => { const result: string[][] = []; const sels = str.split(','); - for (var i = 0, len = sels.length; i < len; i++) { - var sel = sels[i].trim(); - - // Will accept only concatenated classes and last - // class might be with state (eg. :hover), nothing else. - // Can also accept SINGLE ID selectors, eg. `#myid`, `#myid:hover` - // Composed are not valid: `#myid.some-class`, `#myid.some-class:hover` - if (/^(\.{1}[\w\-]+)+(:{1,2}[\w\-()]+)?$/gi.test(sel) || /^(#{1}[\w\-]+){1}(:{1,2}[\w\-()]+)?$/gi.test(sel)) { - var cls = sel.split('.').filter(Boolean); - result.push(cls); + // Will accept only concatenated classes and last + // class might be with state (eg. :hover) complex state (:hover:not(.active)) + // as long as the state does not contain commas. + // Can also accept SINGLE ID selectors, eg. `#myid`, `#myid:hover` + // Composed are not valid: `#myid.some-class`, `#myid.some-class:hover + + const checkForClass = /^(\.[\w\-]+)+((:{1,2}[\w\-]+)(\([^)]*\))?)*$/; + + const checkForId = /^#[\w\-]+((:{1,2}[\w\-]+)(\([^)]*\))?)*$/; + + for (let i = 0; i < sels.length; i++) { + const sel = sels[i].trim(); + + if (checkForClass.test(sel) || checkForId.test(sel)) { + const parts = sel.split(/\.(?![^()]*\))/).filter(Boolean); + result.push(parts); } else { add.push(sel); } } - return { - result, - add, - }; + return { result, add }; }; /** diff --git a/packages/core/test/specs/parser/model/ParserCss.ts b/packages/core/test/specs/parser/model/ParserCss.ts index c72919b13..576e6e8df 100644 --- a/packages/core/test/specs/parser/model/ParserCss.ts +++ b/packages/core/test/specs/parser/model/ParserCss.ts @@ -63,6 +63,12 @@ describe('ParserCss', () => { var result = [['test4', 'test5:hover']]; expect(parseSelector(str).result).toEqual(result); }); + + test('Parse selectors with complex state', () => { + var str = '.test1. test2, .test2>test3, .test4.test5:hover:not(.active.some-class)'; + var result = [['test4', 'test5:hover:not(.active.some-class)']]; + expect(parseSelector(str).result).toEqual(result); + }); }); test('Parse simple rule', () => {