Skip to content

Commit d60c2d8

Browse files
committed
feat: more to test with
1 parent 57a0afb commit d60c2d8

15 files changed

Lines changed: 3060 additions & 82 deletions

File tree

.cursor/rules/run-tests.mdc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ description:
33
globs:
44
alwaysApply: true
55
---
6-
Tests can be run with `bun run test`, which will use vitest's test runner. You can also run vitest directly using `bunx vitest run`.
6+
Tests can be run directly using `bunx vitest run`.

.cursor/rules/verify-assumptions.mdc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ description:
33
globs:
44
alwaysApply: true
55
---
6-
When working with the AST, always add comments to verify your assumptions before making changes. Even though I'm very familiar with the AST, I am sometimes surprised by the structure.
6+
When working with the PostCSS AST, always add comments to verify your assumptions before making changes. It may not be what you expect!

bun.lock

Lines changed: 64 additions & 53 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/checker.ts

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -92,28 +92,90 @@ export const check = (root: PostCSS.Root, detailedApproval: ApprovalFunction) =>
9292
};
9393

9494
root.walkRules((rule) => {
95-
// Determine context once per rule for efficiency.
96-
let display = '';
97-
rule.walkDecls(/^display$/i, (d) => {
98-
display = d.value.toLowerCase();
99-
});
100-
101-
const isFlex = display === 'flex' || display === 'inline-flex';
102-
const isGrid = display === 'grid' || display === 'inline-grid';
103-
const isBlock = display === 'block' || display === 'inline-block';
104-
10595
for (const node of rule.nodes) {
10696
if (node.type === 'decl') {
10797
const decl = node;
98+
99+
if (!decl.parent) {
100+
continue;
101+
}
102+
103+
// Determine context for *this* declaration
104+
let display = '';
105+
// 1. Check the declaration's own rule
106+
decl.parent.walkDecls(/^display$/i, (d) => {
107+
display = d.value.trim().toLowerCase();
108+
});
109+
110+
// 2. Check the parent rule, if one exists (for nesting before plugins)
111+
if (!display && decl.parent.parent && decl.parent.parent.type === 'rule') {
112+
const nestedRule = decl.parent as PostCSS.Rule;
113+
// Only inherit context for pseudo-classes, not for pseudo-elements or child selectors.
114+
if (nestedRule.selector.startsWith('&:') && !nestedRule.selector.startsWith('&::')) {
115+
(decl.parent.parent as PostCSS.Rule).walkDecls(/^display$/i, (d) => {
116+
display = d.value.trim().toLowerCase();
117+
});
118+
}
119+
}
120+
121+
const flexDisplayValues = [
122+
'flex',
123+
'inline-flex',
124+
'-webkit-flex',
125+
'-moz-box',
126+
'-ms-flexbox',
127+
'-webkit-box',
128+
];
129+
const isFlex = flexDisplayValues.includes(display);
130+
const isGrid = display === 'grid' || display === 'inline-grid';
131+
const isBlock = display === 'block' || display === 'inline-block';
132+
108133
const prop = decl.prop.toLowerCase();
109-
const value = decl.value.toLowerCase().trim();
134+
const { unprefixed: unprefixedProp } = getPrefixed(prop);
135+
const value = decl.value.trim().toLowerCase();
136+
const baselineValues = ['baseline', 'first baseline', 'last baseline'];
110137

111-
if (prop === 'anchor-scope') {
138+
if (unprefixedProp === 'align-content') {
139+
if (isFlex) {
140+
if (baselineValues.includes(value)) {
141+
approve(decl, 'properties.align-content.flex_context.baseline');
142+
}
143+
if (value === 'last baseline') {
144+
approve(decl, 'properties.align-content.flex_context.last_baseline');
145+
}
146+
if (value === 'baseline' || value === 'first baseline') {
147+
approve(decl, 'properties.align-content.flex_context.first_baseline');
148+
}
149+
if (['start', 'end'].includes(value)) {
150+
approve(decl, 'properties.align-content.flex_context.start_end');
151+
}
152+
if (value === 'space-evenly') {
153+
approve(decl, 'properties.align-content.flex_context.space-evenly');
154+
}
155+
}
156+
if (isBlock) {
157+
approve(decl, 'properties.align-content.block_context');
158+
}
159+
if (isGrid) {
160+
if (baselineValues.includes(value)) {
161+
approve(decl, 'properties.align-content.grid_context.baseline');
162+
}
163+
}
164+
}
165+
166+
if (unprefixedProp === 'anchor-scope') {
112167
approve(decl, 'properties.anchor-scope');
113168
if (value === 'all') {
114169
approve(decl, 'properties.anchor-scope.all');
115170
}
116171
}
172+
173+
if (unprefixedProp === 'accent-color') {
174+
approve(decl, 'properties.accent-color');
175+
if (value === 'auto') {
176+
approve(decl, 'properties.accent-color.auto');
177+
}
178+
}
117179
}
118180
}
119181
});
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
/* AUTO_GENERATED: true */
2+
3+
/*
4+
feature: properties.accent-color.auto
5+
docs: https://developer.mozilla.org/docs/Web/CSS/accent-color
6+
spec: https://drafts.csswg.org/css-ui/#widget-accent
7+
*/
8+
9+
import { testRule } from 'lib/testRule';
10+
11+
/**
12+
* Tests the basic detection of `accent-color: auto` on a standard input checkbox.
13+
*/
14+
testRule({
15+
featureId: 'properties.accent-color.auto',
16+
description: 'should detect `accent-color: auto` on an input element',
17+
code: `
18+
input[type="checkbox"] { accent-color: auto; }
19+
`,
20+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 1 },
21+
});
22+
23+
/**
24+
* Tests the detection of `accent-color: auto` on a standard input radio button.
25+
*/
26+
testRule({
27+
featureId: 'properties.accent-color.auto',
28+
description: 'should detect `accent-color: auto` on a radio input',
29+
code: `
30+
input[type="radio"] { accent-color: auto; }
31+
`,
32+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 1 },
33+
});
34+
35+
/**
36+
* Tests the detection of `accent-color: auto` on a progress element.
37+
*/
38+
testRule({
39+
featureId: 'properties.accent-color.auto',
40+
description: 'should detect `accent-color: auto` on a progress element',
41+
code: `
42+
progress { accent-color: auto; }
43+
`,
44+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 1 },
45+
});
46+
47+
/**
48+
* Tests `accent-color: auto` when it's part of a rule with other properties.
49+
*/
50+
testRule({
51+
featureId: 'properties.accent-color.auto',
52+
description: 'should detect `accent-color: auto` alongside other declarations',
53+
code: `
54+
input { color: blue; accent-color: auto; border: 1px solid black; }
55+
`,
56+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 1 },
57+
});
58+
59+
/**
60+
* Ensures that `accent-color` with a specific color value (e.g., `red`) is not flagged as `accent-color: auto`.
61+
*/
62+
testRule({
63+
featureId: 'properties.accent-color.auto',
64+
description: 'should not flag `accent-color` with a color value',
65+
code: `
66+
input[type="checkbox"] { accent-color: red; }
67+
`,
68+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 0 },
69+
});
70+
71+
/**
72+
* Tests `accent-color` with the `initial` keyword. This should not be flagged as `auto`.
73+
*/
74+
testRule({
75+
featureId: 'properties.accent-color.auto',
76+
description: 'should not flag `accent-color: initial`',
77+
code: `
78+
input { accent-color: initial; }
79+
`,
80+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 0 },
81+
});
82+
83+
/**
84+
* Tests `accent-color` with a CSS variable. Since `auto` is a specific value, `var()` should not be flagged.
85+
*/
86+
testRule({
87+
featureId: 'properties.accent-color.auto',
88+
description: 'should not flag `accent-color` with `var()`',
89+
code: `
90+
input { --accent: auto; accent-color: var(--accent); }
91+
`,
92+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 0 },
93+
});
94+
95+
/**
96+
* Checks if multiple occurrences of `accent-color: auto` are correctly counted.
97+
*/
98+
testRule({
99+
featureId: 'properties.accent-color.auto',
100+
description: 'should detect multiple instances of `accent-color: auto`',
101+
code: `
102+
input { accent-color: auto; } div { accent-color: auto; }
103+
`,
104+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 2 },
105+
});
106+
107+
/**
108+
* Tests `accent-color: auto` inside a `@supports` rule that exactly matches the property and value, ensuring it's not flagged.
109+
*/
110+
testRule({
111+
featureId: 'properties.accent-color.auto',
112+
description: 'should not flag `accent-color: auto` when guarded by `@supports`',
113+
code: `
114+
@supports (accent-color: auto) { input { accent-color: auto; } }
115+
`,
116+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 0 },
117+
});
118+
119+
/**
120+
* Tests `accent-color: auto` inside a `@supports` rule that checks for the same property but a different value, ensuring it is flagged.
121+
*/
122+
testRule({
123+
featureId: 'properties.accent-color.auto',
124+
description: 'should flag `accent-color: auto` when `@supports` checks for a different value',
125+
code: `
126+
@supports (accent-color: red) { input { accent-color: auto; } }
127+
`,
128+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 1 },
129+
});
130+
131+
/**
132+
* Tests `accent-color: auto` inside a `@supports` rule that checks for a different property, ensuring it is flagged.
133+
*/
134+
testRule({
135+
featureId: 'properties.accent-color.auto',
136+
description: 'should flag `accent-color: auto` when `@supports` checks for a different property',
137+
code: `
138+
@supports (display: flex) { input { accent-color: auto; } }
139+
`,
140+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 1 },
141+
});
142+
143+
/**
144+
* Tests `accent-color: auto` in a nested rule using a pseudo-class (e.g., `:hover`), which is considered the same context.
145+
*/
146+
testRule({
147+
featureId: 'properties.accent-color.auto',
148+
description: 'should detect `accent-color: auto` in a nested pseudo-class rule',
149+
code: `
150+
.foo { accent-color: auto; &:hover { accent-color: auto; } }
151+
`,
152+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 2 },
153+
});
154+
155+
/**
156+
* Tests `accent-color: auto` in a nested rule using a child selector (e.g., `& .bar`), which is considered a new element and different context.
157+
*/
158+
testRule({
159+
featureId: 'properties.accent-color.auto',
160+
description: 'should detect `accent-color: auto` in a nested child selector rule',
161+
code: `
162+
.foo { accent-color: auto; & .bar { accent-color: auto; } }
163+
`,
164+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 2 },
165+
});
166+
167+
/**
168+
* Tests `accent-color: auto` in a nested rule using a pseudo-element (e.g., `&::before`), which is considered a new element and different context.
169+
*/
170+
testRule({
171+
featureId: 'properties.accent-color.auto',
172+
description: 'should detect `accent-color: auto` in a nested pseudo-element rule',
173+
code: `
174+
.foo { accent-color: auto; &::before { accent-color: auto; } }
175+
`,
176+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 2 },
177+
});
178+
179+
/**
180+
* Tests `accent-color: auto` with different whitespace around the value.
181+
*/
182+
testRule({
183+
featureId: 'properties.accent-color.auto',
184+
description: 'should detect `accent-color: auto` with varying whitespace',
185+
code: `
186+
input { accent-color:auto; } div { accent-color: auto ; }
187+
`,
188+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 2 },
189+
});
190+
191+
/**
192+
* Ensures that `accent-color: auto` declarations within comments are ignored.
193+
*/
194+
testRule({
195+
featureId: 'properties.accent-color.auto',
196+
description: 'should not flag `accent-color: auto` inside a CSS comment',
197+
code: `
198+
/* input { accent-color: auto; } */
199+
`,
200+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 0 },
201+
});
202+
203+
/**
204+
* Ensures that the rule does nothing when `accent-color` is not used at all.
205+
*/
206+
testRule({
207+
featureId: 'properties.accent-color.auto',
208+
description: 'should not flag when `accent-color` is not present',
209+
code: `
210+
div { color: blue; }
211+
`,
212+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 0 },
213+
});
214+
215+
/**
216+
* Tests a scenario with two instances of `accent-color: auto` to ensure both are reported.
217+
*/
218+
testRule({
219+
featureId: 'properties.accent-color.auto',
220+
description: 'should have two warnings for two distinct usages',
221+
code: `
222+
a { accent-color: auto; } b { accent-color: auto; }
223+
`,
224+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 2 },
225+
});
226+
227+
/**
228+
* Tests that the checker is case-insensitive for property and value names.
229+
*/
230+
testRule({
231+
featureId: 'properties.accent-color.auto',
232+
description: 'should detect `ACCENT-COLOR: AUTO` (case-insensitive)',
233+
code: `
234+
input { ACCENT-COLOR: AUTO; }
235+
`,
236+
featureCount: { '-webkit-': 0, '-moz-': 0, '-ms-': 0, '-o-': 0, unprefixed: 1 },
237+
});

0 commit comments

Comments
 (0)