Fix recursion in legacy CSS theme(…) function

This commit is contained in:
Philipp Spiess 2025-05-09 18:24:47 +02:00
parent 2d139984da
commit 336a7dee0a
3 changed files with 45 additions and 1 deletions

View file

@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
- Nothing yet!
### Fixed
- Fix infinite loop when `theme()` function is called recursively inside `@theme` blocks
## [4.1.6] - 2025-05-09

View file

@ -433,6 +433,27 @@ describe('--theme(…)', () => {
}"
`)
})
test('--theme(…) prevents infinite loops with circular references', async () => {
expect(
await compileCss(css`
@theme {
--font-sans: 'Inter', --theme(--font-sans);
}
.font {
font-family: var(--font-sans);
}
`),
).toMatchInlineSnapshot(`
":root, :host {
--font-sans: "Inter", var(--font-sans);
}
.font {
font-family: var(--font-sans);
}"
`)
})
})
describe('theme(…)', () => {
@ -903,6 +924,19 @@ describe('theme(…)', () => {
}"
`)
})
test('theme(…) prevents infinite loops with circular references', async () => {
await expect(
compileCss(css`
@theme {
--font-sans: 'Inter', theme(fontFamily.sans);
}
.font {
font-family: var(--font-sans);
}
`),
).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Could not resolve value for theme function: \`theme(fontFamily.sans)\`. The resolved value \`'Inter', theme(fontFamily.sans)\` contains a recursive reference to itself.]`)
})
})
describe('with CSS variable syntax', () => {

View file

@ -145,6 +145,14 @@ function legacyTheme(
)
}
// Detect eventual recursive theme function calls.
let regex = new RegExp('theme\\(\\s*[\'\"]?' + path)
if (typeof resolvedValue === 'string' && resolvedValue.match(regex)) {
throw new Error(
`Could not resolve value for theme function: \`theme(${path})\`. The resolved value \`${resolvedValue}\` contains a recursive reference to itself.`,
)
}
return resolvedValue
}