Skip to content

Commit e432d1f

Browse files
committed
Report invalid selectors
1 parent 03fb261 commit e432d1f

File tree

2 files changed

+50
-20
lines changed

2 files changed

+50
-20
lines changed

src/utils.ts

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -80,23 +80,27 @@ export function splitCommaList(list: List<CssNode>) {
8080
export function getSelectors(rule: SelectorList | undefined) {
8181
if (!rule) return [];
8282

83-
return (rule.children as List<CssTreeSelector>)
84-
.map((selector) => {
85-
let pseudoElementPart: string | undefined;
86-
87-
if (selector.children.last?.type === 'PseudoElementSelector') {
88-
selector = clone(selector) as CssTreeSelector;
89-
pseudoElementPart = generateCSS(selector.children.last!);
90-
selector.children.pop();
91-
}
92-
93-
const elementPart = generateCSS(selector);
94-
95-
return {
96-
selector: elementPart + (pseudoElementPart ?? ''),
97-
elementPart,
98-
pseudoElementPart,
99-
} satisfies Selector;
100-
})
101-
.toArray();
83+
try {
84+
return (rule.children as List<CssTreeSelector>)
85+
.map((selector) => {
86+
let pseudoElementPart: string | undefined;
87+
88+
if (selector.children.last?.type === 'PseudoElementSelector') {
89+
selector = clone(selector) as CssTreeSelector;
90+
pseudoElementPart = generateCSS(selector.children.last!);
91+
selector.children.pop();
92+
}
93+
94+
const elementPart = generateCSS(selector);
95+
96+
return {
97+
selector: elementPart + (pseudoElementPart ?? ''),
98+
elementPart,
99+
pseudoElementPart,
100+
} satisfies Selector;
101+
})
102+
.toArray();
103+
} catch {
104+
throw new Error(`Invalid CSS. Can't parse selector "${generateCSS(rule)}"`);
105+
}
102106
}

tests/unit/utils.test.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import type * as csstree from 'css-tree';
22

3-
import { getAST, splitCommaList } from '../../src/utils.js';
3+
import { getAST, getSelectors,splitCommaList } from '../../src/utils.js';
4+
5+
const getSelectorList = (cssText: string) => {
6+
const stylesheet = getAST(cssText) as csstree.StyleSheet;
7+
return (stylesheet.children.first as csstree.Rule)
8+
.prelude as csstree.SelectorList;
9+
};
410

511
describe('splitCommaList', () => {
612
it('works', () => {
@@ -20,3 +26,23 @@ describe('splitCommaList', () => {
2026
]);
2127
});
2228
});
29+
describe('getSelectors', () => {
30+
it('includes invalid rule in error', () => {
31+
const selectorList = getSelectorList('.w-[10]{color: red}');
32+
33+
expect(() => getSelectors(selectorList)).toThrowError(
34+
'Invalid CSS. Can\'t parse selector ".w-[10]"',
35+
);
36+
});
37+
it('parses valid selector with pseudoclass', () => {
38+
const selectorList = getSelectorList('.a::before{color: red}');
39+
const selectors = getSelectors(selectorList);
40+
expect(selectors).toEqual([
41+
{
42+
selector: '.a::before',
43+
elementPart: '.a',
44+
pseudoElementPart: '::before',
45+
},
46+
]);
47+
});
48+
});

0 commit comments

Comments
 (0)