Disallow multi-selector arbitrary variants (#10655)

* Allow escaping in `splitAtTopLevelOnly`

* Correctly parse arbitrary variants that have multiple selectors

* Explicitly disallow multiple selector arbitrary variants

Now that we parse them correctly we can restrict them to explicitly supporting only a single selector

* Add test to verify that multiple selector arbitrary variants are dropped

* Add test

* Make prettier happy

* Fix CS

* Update changelog
This commit is contained in:
Jordan Pittman 2023-02-22 14:44:54 -05:00 • committed by GitHub
parent d6121f0ede
commit 9bbdd9b10d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 6 deletions

View file

@ -205,17 +205,26 @@ function applyVariant(variant, matches, context) {
// Register arbitrary variants
if (isArbitraryValue(variant) && !context.variantMap.has(variant)) {
let selector = normalize(variant.slice(1, -1))
let sort = context.offsets.recordVariant(variant)
if (!isValidVariantFormatString(selector)) {
let selector = normalize(variant.slice(1, -1))
let selectors = splitAtTopLevelOnly(selector, ',')
// We do not support multiple selectors for arbitrary variants
if (selectors.length > 1) {
return []
}
let fn = parseVariant(selector)
if (!selectors.every(isValidVariantFormatString)) {
return []
}
let sort = context.offsets.recordVariant(variant)
let records = selectors.map((sel, idx) => [
context.offsets.applyParallelOffset(sort, idx),
parseVariant(sel.trim()),
])
context.variantMap.set(variant, [[sort, fn]])
context.variantMap.set(variant, records)
}
if (context.variantMap.has(variant)) {

View file

@ -17,17 +17,24 @@ export function splitAtTopLevelOnly(input, separator) {
let stack = []
let parts = []
let lastPos = 0
let isEscaped = false
for (let idx = 0; idx < input.length; idx++) {
let char = input[idx]
if (stack.length === 0 && char === separator[0]) {
if (stack.length === 0 && char === separator[0] && !isEscaped) {
if (separator.length === 1 || input.slice(idx, idx + separator.length) === separator) {
parts.push(input.slice(lastPos, idx))
lastPos = idx + separator.length
}
}
if (isEscaped) {
isEscaped = false
} else if (char === '\\') {
isEscaped = true
}
if (char === '(' || char === '[' || char === '{') {
stack.push(char)
} else if (