Don’t index into strings with the theme(…) function (#19111)

Indexing into a string is only ever going to produce a single character
and is almost guaranteed to be a mistake. The legacy keypath notation is
meant to traverse objects and arrays — not strings.

Fixes #19104
This commit is contained in:
Jordan Pittman 2025-10-13 11:44:33 -04:00 • committed by GitHub
parent 2cba8319ce
commit f945c3d29f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 38 additions and 0 deletions

View file

@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix resolving theme keys when starting with the name of another theme key in JS configs and plugins ([#19097](https://github.com/tailwindlabs/tailwindcss/pull/19097))
- Allow named groups in combination with `not-*`, `has-*`, and `in-*` ([#19100](https://github.com/tailwindlabs/tailwindcss/pull/19100))
- Prevent important utilities from affecting other utilities ([#19110](https://github.com/tailwindlabs/tailwindcss/pull/19110))
- Don’t index into strings with the `theme(…)` function ([#19111](https://github.com/tailwindlabs/tailwindcss/pull/19111))
- Upgrade: Canonicalize utilities containing `0` values ([#19095](https://github.com/tailwindlabs/tailwindcss/pull/19095))
## [4.1.14] - 2025-10-01

View file

@ -1687,3 +1687,35 @@ test('handles setting theme keys to null', async () => {
"
`)
})
test('The theme() function does not try indexing into strings', async () => {
let compiler = await compile(css`
@theme default {
--color-what-50: #f00;
--color-what-950: #f00;
}
@theme {
/*
* The value of this theme variable is > 50 chars because colors.what.50 was previously
* indexing the string: "light-dark(theme(colors.what.950), theme(colors.what.50))"
* because the resolved config contained an object with a "what" key that was that string
*/
--color-what: light-dark(theme(colors.what.950), theme(colors.what.50));
}
@source inline("text-what");
@tailwind utilities;
`)
expect(compiler.build([])).toMatchInlineSnapshot(`
":root, :host {
--color-what: light-dark(#f00, #f00);
}
.text-what {
color: var(--color-what);
}
"
`)
})

View file

@ -233,6 +233,11 @@ function get(obj: any, path: string[]) {
continue
}
// We never want to index into strings
if (typeof obj === 'string') {
return undefined
}
obj = obj[key]
}