Skip to content

Commit 2fd7c8d

Browse files
authored
Show warning when using unsupported bare value data type (#17464)
This PR will show a warning if you are using a bare value data type that is not supported. Let's say you want to create a new utility that allows `color` to be a bare value data type like this: ```css @Utility paint-* { paint: --value([color], color); } ``` This means that this would enable new syntax that we don't support yet. E.g.: `paint-#0088cc`. The only supported data types for bare values are: - `number` — `2.5` - `integer` — `2` - `ratio` — `1/2` - `percentage` — `50%` All other data types are not supported in this position. This PR will now show a warning: ~~~ Unsupported bare value data type: "color". Only valid data types are: "number", "integer", "ratio", "percentage". ```css --value([color],color) ^^^^^ ``` ~~~ Once we have better sourcemap / location tracking support, this warning will point to the exact spot, but for now, only a re-print of the AST can be used. If you _do_ want to use other data types, then you will have to use arbitrary value syntax with `[…]` instead. ```css @Utility paint-* { paint: --value([color]); } ``` This will allow for `paint-[#0088cc]` for example. Note: this is not a behavioral change, we already didn't support other data types, but we silently ignored them. This means that we have to do more parsing at runtime when evaluating the utility. With this change, a warning is shown when registering the `@utility`, not when using it.
1 parent 57e55a6 commit 2fd7c8d

File tree

3 files changed

+73
-9
lines changed

3 files changed

+73
-9
lines changed

Diff for: CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
- Nothing yet!
10+
### Fixed
11+
12+
- Show warning when using unsupported bare value data type in `--value(…)` ([#17464](https://github.com/tailwindlabs/tailwindcss/pull/17464))
1113

1214
## [4.1.2] - 2025-04-03
1315

Diff for: packages/tailwindcss/src/utilities.test.ts

+29-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, expect, test } from 'vitest'
1+
import { describe, expect, test, vi } from 'vitest'
22
import { compile } from '.'
33
import { compileCss, optimizeCss, run } from './test-utils/run'
44

@@ -26530,6 +26530,34 @@ describe('custom utilities', () => {
2653026530
expect(await compileCss(input, ['tab-foo'])).toEqual('')
2653126531
})
2653226532

26533+
test('bare values with unsupported data types should result in a warning', async () => {
26534+
let spy = vi.spyOn(console, 'warn').mockImplementation(() => {})
26535+
let input = css`
26536+
@utility paint-* {
26537+
paint: --value([color], color);
26538+
}
26539+
26540+
@tailwind utilities;
26541+
`
26542+
26543+
expect(await compileCss(input, ['paint-#0088cc', 'paint-red'])).toMatchInlineSnapshot(`""`)
26544+
expect(spy.mock.calls).toMatchInlineSnapshot(`
26545+
[
26546+
[
26547+
"Unsupported bare value data type: "color".
26548+
Only valid data types are: "number", "integer", "ratio", "percentage".
26549+
",
26550+
],
26551+
[
26552+
"\`\`\`css
26553+
--value([color],color)
26554+
^^^^^
26555+
\`\`\`",
26556+
],
26557+
]
26558+
`)
26559+
})
26560+
2653326561
test('resolve literal values', async () => {
2653426562
let input = css`
2653526563
@utility tab-* {

Diff for: packages/tailwindcss/src/utilities.ts

+41-7
Original file line numberDiff line numberDiff line change
@@ -5692,6 +5692,16 @@ export function createUtilities(theme: Theme) {
56925692
return utilities
56935693
}
56945694

5695+
// Only allowed bare value data types, to prevent creating new syntax that we
5696+
// typically don't support right now. E.g.: `--value(color)` would allow you to
5697+
// use `text-#0088cc` as a valid utility, which is not what we want.
5698+
export const BARE_VALUE_DATA_TYPES = [
5699+
'number', // 2.5
5700+
'integer', // 8
5701+
'ratio', // 2/3
5702+
'percentage', // 25%
5703+
]
5704+
56955705
export function createCssUtility(node: AtRule) {
56965706
let name = node.params
56975707

@@ -5824,7 +5834,6 @@ export function createCssUtility(node: AtRule) {
58245834
}
58255835
fn.nodes = ValueParser.parse(args.join(','))
58265836

5827-
// Track information for suggestions
58285837
for (let node of fn.nodes) {
58295838
// Track literal values
58305839
if (
@@ -5841,6 +5850,36 @@ export function createCssUtility(node: AtRule) {
58415850
let value = node.value.replace(/-\*.*$/g, '') as `--${string}`
58425851
storage[fn.value].themeKeys.add(value)
58435852
}
5853+
5854+
// Validate bare value data types
5855+
else if (
5856+
node.kind === 'word' &&
5857+
!(node.value[0] === '[' && node.value[node.value.length - 1] === ']') && // Ignore arbitrary values
5858+
!BARE_VALUE_DATA_TYPES.includes(node.value)
5859+
) {
5860+
console.warn(
5861+
`Unsupported bare value data type: "${node.value}".\nOnly valid data types are: ${BARE_VALUE_DATA_TYPES.map((x) => `"${x}"`).join(', ')}.\n`,
5862+
)
5863+
// TODO: Once we properly track the location of the node, we can
5864+
// clean this up in a better way.
5865+
let dataType = node.value
5866+
let copy = structuredClone(fn)
5867+
let sentinelValue = '¶'
5868+
ValueParser.walk(copy.nodes, (node, { replaceWith }) => {
5869+
if (node.kind === 'word' && node.value === dataType) {
5870+
replaceWith({ kind: 'word', value: sentinelValue })
5871+
}
5872+
})
5873+
let underline = '^'.repeat(ValueParser.toCss([node]).length)
5874+
let offset = ValueParser.toCss([copy]).indexOf(sentinelValue)
5875+
let output = [
5876+
'```css',
5877+
ValueParser.toCss([fn]),
5878+
' '.repeat(offset) + underline,
5879+
'```',
5880+
].join('\n')
5881+
console.warn(output)
5882+
}
58445883
}
58455884
})
58465885

@@ -6084,12 +6123,7 @@ function resolveValueFunction(
60846123
// Limit the bare value types, to prevent new syntax that we
60856124
// don't want to support. E.g.: `text-#000` is something we
60866125
// don't want to support, but could be built this way.
6087-
if (
6088-
arg.value !== 'number' &&
6089-
arg.value !== 'integer' &&
6090-
arg.value !== 'ratio' &&
6091-
arg.value !== 'percentage'
6092-
) {
6126+
if (!BARE_VALUE_DATA_TYPES.includes(arg.value)) {
60936127
continue
60946128
}
60956129

0 commit comments

Comments
 (0)