Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
80a90e0
hoist regex
RobinMalfait Sep 26, 2025
33dd0f8
remove async
RobinMalfait Sep 30, 2025
a62d857
tmp: annotate migrations
RobinMalfait Sep 30, 2025
c82bc30
move `printCandidate` normalization tests to core
RobinMalfait Sep 30, 2025
8c6fe35
expose `canonicalizeCandidates` on the design system
RobinMalfait Sep 26, 2025
5d6ea74
canonicalize candidates at the end of upgrading your project
RobinMalfait Sep 30, 2025
44352e8
move `migrate-bg-gradient` to core
RobinMalfait Sep 30, 2025
afa3216
move `migrate-theme-to-var` to core
RobinMalfait Sep 30, 2025
852e288
cache the converter
RobinMalfait Sep 30, 2025
4c722c0
only prefix variable that are not in `--theme(…)`
RobinMalfait Sep 30, 2025
4bf93bf
move types to core
RobinMalfait Sep 30, 2025
5de55bd
move dimensions to core
RobinMalfait Sep 30, 2025
2c9a2c7
move signatures to core
RobinMalfait Sep 30, 2025
34cb8b8
ensure `canonicalizeCandidates` returns a unique list
RobinMalfait Sep 30, 2025
0c3d48e
move `migrate-arbitrary-utilities` to core
RobinMalfait Sep 30, 2025
f088459
move `migrate-bare-utilities` to core
RobinMalfait Sep 30, 2025
ae5909c
move `migrate-deprecated-utilities` to core
RobinMalfait Sep 30, 2025
e5352d3
move `replaceObject` to core
RobinMalfait Sep 30, 2025
2863c60
move `migrate-arbitrary-variants` to core
RobinMalfait Sep 30, 2025
0eaf373
move `migrate-drop-unnecessary-data-types` to core
RobinMalfait Sep 30, 2025
683ffc5
move `migrate-arbitrary-value-to-bare-value` to core
RobinMalfait Sep 30, 2025
1c02690
move `migrate-optimize-modifier` to core
RobinMalfait Sep 30, 2025
760aef8
remove `!` from test case
RobinMalfait Oct 2, 2025
d5ba933
handle `&` and `*` in selector parser as standalone selector
RobinMalfait Oct 3, 2025
80029cd
move parts of `migrate-modernize-arbitrary-values` to core
RobinMalfait Oct 3, 2025
02ba94f
ensure we canonicalize at the end
RobinMalfait Oct 3, 2025
c956b08
big refactor
RobinMalfait Oct 3, 2025
c281426
drop unnecessary calls
RobinMalfait Oct 4, 2025
368eb80
only stringify the value when something changed
RobinMalfait Oct 4, 2025
55cbbaf
remove migration annotations
RobinMalfait Oct 4, 2025
e7ce1ad
move `selector-parser` from `./src/compat` to just `./src`
RobinMalfait Oct 5, 2025
705476c
add attribute selector parser
RobinMalfait Oct 5, 2025
226ae47
use dedicated `AttributeSelectorParser`
RobinMalfait Oct 5, 2025
4441c44
remove intellisense features from `@tailwindcss/browser`
RobinMalfait Oct 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions packages/tailwindcss/src/compat/selector-parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,34 @@ describe('parse', () => {
},
])
})

it('parses nesting selector before attribute selector', () => {
expect(parse('&[data-foo]')).toEqual([
{ kind: 'selector', value: '&' },
{ kind: 'selector', value: '[data-foo]' },
])
})

it('parses nesting selector after an attribute selector', () => {
expect(parse('[data-foo]&')).toEqual([
{ kind: 'selector', value: '[data-foo]' },
{ kind: 'selector', value: '&' },
])
})

it('parses universal selector before attribute selector', () => {
expect(parse('*[data-foo]')).toEqual([
{ kind: 'selector', value: '*' },
{ kind: 'selector', value: '[data-foo]' },
])
})

it('parses universal selector after an attribute selector', () => {
expect(parse('[data-foo]*')).toEqual([
{ kind: 'selector', value: '[data-foo]' },
{ kind: 'selector', value: '*' },
])
})
})

describe('toCss', () => {
Expand Down
33 changes: 29 additions & 4 deletions packages/tailwindcss/src/compat/selector-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ const SINGLE_QUOTE = 0x27
const SPACE = 0x20
const TAB = 0x09
const TILDE = 0x7e
const AMPERSAND = 0x26
const ASTERISK = 0x2a

export function parse(input: string) {
input = input.replaceAll('\r\n', '\n')
Expand Down Expand Up @@ -369,7 +371,7 @@ export function parse(input: string) {
ast.push(node)
}
}
buffer = String.fromCharCode(currentChar)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking we did this in purpose for perf reasons but it might not actually make a difference compared to everything else.

buffer = input[i]
break
}

Expand Down Expand Up @@ -443,17 +445,40 @@ export function parse(input: string) {
break
}

// Nesting `&` is always a new selector.
// Universal `*` is always a new selector.
case AMPERSAND:
case ASTERISK: {
// 1. Handle everything before the combinator as a selector
if (buffer.length > 0) {
let node = selector(buffer)
if (parent) {
parent.nodes.push(node)
} else {
ast.push(node)
}
buffer = ''
}

// 2. Handle the `&` or `*` as a selector on its own
if (parent) {
parent.nodes.push(selector(input[i]))
} else {
ast.push(selector(input[i]))
}
break
}

// Escaped characters.
case BACKSLASH: {
let nextChar = input.charCodeAt(i + 1)
buffer += String.fromCharCode(currentChar) + String.fromCharCode(nextChar)
buffer += input[i] + input[i + 1]
i += 1
break
}

// Everything else will be collected in the buffer
default: {
buffer += String.fromCharCode(currentChar)
buffer += input[i]
}
}
}
Expand Down