Skip to content

Commit 409260b

Browse files
bartvenemanclaude
andauthored
Refactor var() parsing logic for improved clarity (#66)
## Summary Refactored the `collect_var_usages` function to simplify the logic for detecting CSS custom property usages within `var()` functions. The new implementation is more concise and easier to understand while maintaining the same functionality. ## Key Changes - **Simplified var() detection logic**: Replaced nested loops and conditional checks with early returns, reducing cognitive complexity - **Direct property access**: Changed from iterating through `node.children` to directly accessing `first_child` and `next_sibling` properties - **Cleaner fallback detection**: Simplified `has_fallback` detection by checking if `first_sibling` exists rather than iterating through children - **Added test coverage**: Added comprehensive tests for `var()` usages inside `light-dark()` function in both rule test files and utility test file ## Implementation Details The refactored code maintains identical behavior: - Still correctly identifies custom property names (those starting with `--`) - Still detects whether a fallback value is present - Still works with nested functions like `light-dark(var(...), var(...))` - Early return pattern improves readability and reduces nesting depth All existing tests pass, and new tests verify the functionality works correctly with the `light-dark()` CSS function. https://claude.ai/code/session_012pu1Bv9AuopQ9ExG87ZSe5 Co-authored-by: Claude <noreply@anthropic.com>
1 parent bfb2360 commit 409260b

4 files changed

Lines changed: 72 additions & 17 deletions

File tree

src/rules/no-unknown-custom-property/index.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,32 @@ test('should still error when var() uses a property not present in any importFro
399399
)
400400
})
401401

402+
test('should not error when declared properties are used inside light-dark()', async () => {
403+
const config = {
404+
plugins: [plugin],
405+
rules: {
406+
[rule_name]: true,
407+
},
408+
}
409+
410+
const {
411+
results: [{ warnings, errored }],
412+
} = await stylelint.lint({
413+
code: `
414+
:root {
415+
--blue-800: blue;
416+
--blue-700: navy;
417+
}
418+
a {
419+
color: light-dark(var(--blue-800), var(--blue-700));
420+
}`,
421+
config,
422+
})
423+
424+
expect(errored).toBe(false)
425+
expect(warnings).toStrictEqual([])
426+
})
427+
402428
test('should still detect unknown custom property when input.css offsets do not match (Svelte embedded CSS)', async () => {
403429
const css = 'a { color: var(--undefined); }'
404430
const config = {

src/rules/no-unused-custom-properties/index.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,32 @@ test('should still error when a declared property is not used in the current fil
337337
)
338338
})
339339

340+
test('should not error when a declared property is used inside light-dark()', async () => {
341+
const config = {
342+
plugins: [plugin],
343+
rules: {
344+
[rule_name]: true,
345+
},
346+
}
347+
348+
const {
349+
results: [{ warnings, errored }],
350+
} = await stylelint.lint({
351+
code: `
352+
:root {
353+
--blue-800: blue;
354+
--blue-700: navy;
355+
}
356+
a {
357+
color: light-dark(var(--blue-800), var(--blue-700));
358+
}`,
359+
config,
360+
})
361+
362+
expect(errored).toBe(false)
363+
expect(warnings).toStrictEqual([])
364+
})
365+
340366
test('should still detect unused custom property when input.css offsets do not match (Svelte embedded CSS)', async () => {
341367
const css = ':root { --unused: red; }'
342368
const config = {

src/utils/custom-properties.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,16 @@ test('collect_var_usages: finds var() usages across different selectors', () =>
105105
expect(names).toContain('--space-3')
106106
})
107107

108+
test('collect_var_usages: finds var() usages inside light-dark()', () => {
109+
const root = parse('a { color: light-dark(var(--blue-800), var(--blue-700)); }')
110+
const usages = collect_var_usages(root)
111+
expect(usages.length).toBe(2)
112+
const blue_800 = usages.find((u) => u.name === '--blue-800')
113+
const blue_700 = usages.find((u) => u.name === '--blue-700')
114+
expect(blue_800?.has_fallback).toBe(false)
115+
expect(blue_700?.has_fallback).toBe(false)
116+
})
117+
108118
test('collect_var_usages: finds var() usages even when input.css offsets do not match (Svelte embedded CSS)', () => {
109119
// Simulate what happens with Svelte: stylelint extracts CSS from <style>...</style>
110120
// but root.source.input.css may contain the full Svelte file while

src/utils/custom-properties.ts

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,16 @@ export function collect_var_usages(root: Root): VarUsage[] {
3636
const parsed = parse_declaration(decl_source)
3737

3838
walk(parsed, (node) => {
39-
if (node.type === FUNCTION && node.name === 'var') {
40-
let found_name: string | null = null
41-
let has_fallback = false
42-
43-
for (const child of node.children) {
44-
if (found_name === null && child.type === IDENTIFIER && child.text.startsWith('--')) {
45-
found_name = child.text
46-
} else if (found_name !== null) {
47-
has_fallback = true
48-
break
49-
}
50-
}
51-
52-
if (found_name !== null) {
53-
usages.push({ name: found_name, has_fallback, node: declaration })
54-
}
55-
}
39+
if (node.type !== FUNCTION || node.name !== 'var') return
40+
41+
const first = node.first_child
42+
if (first === null || first.type !== IDENTIFIER || !first.text.startsWith('--')) return
43+
44+
usages.push({
45+
name: first.text,
46+
has_fallback: first.next_sibling !== null,
47+
node: declaration,
48+
})
5649
})
5750
})
5851

0 commit comments

Comments
 (0)