Skip to content

Do not migrate a variant literal behind a conditional - #20436

Open
HuzaifaChaudary wants to merge 5 commits into
tailwindlabs:mainfrom
HuzaifaChaudary:fix/upgrade-variant-guard-conditionals
Open

Do not migrate a variant literal behind a conditional#20436
HuzaifaChaudary wants to merge 5 commits into
tailwindlabs:mainfrom
HuzaifaChaudary:fix/upgrade-variant-guard-conditionals

Conversation

@HuzaifaChaudary

Copy link
Copy Markdown

Closes #20435

problem

@tailwindcss/upgrade rewrites variant="outline" to variant="outline-solid" when a conditional sits between variant and the string. these are react prop values and not class names so the rewrite breaks them.

#18922 added a guard for the direct forms and those still work. the guard is a look behind that only inspects the text immediately before the literal

/variant\s*[:=]\s*\{?['"`]$/

so as soon as a ternary or a nullish branch comes between the two it no longer matches. the four cases from the issue

Button({ variant: isActive ? "outline" : "ghost" })
<Button variant={first ? "default" : "outline"} />
<Button variant={variant ?? "outline"} />
<Button variant={required ? 'secondary' : 'outline'} />

fix

allow one ternary or nullish branch between the prop and the literal.

/variant\s*[:=]\s*\{?(?:[^{},]*?(?:\?\?|\?|:)\s*)?['"`]$/

the added part excludes braces and commas on purpose. that is what stops the match running out of its own value and into a neighbouring prop, so a real class in a conditional is still migrated. the three cases i was most worried about

<div className={active ? "shadow" : "none"}></div>
<Button variant="ghost" className={active ? "shadow" : "none"} />
Button({ variant: a ? "ghost" : "x", className: b ? "shadow" : "y" })

all three still migrate shadow to shadow-sm. the last one is the reason commas are excluded rather than only braces.

tests

seven cases in is-safe-migration.test.ts

  • four negatives, the ones from the issue, which fail on main
  • three positives that must keep migrating, which is where an over broad guard would show up
tests
is-safe-migration before 68 passed
is-safe-migration after 75 passed
whole @tailwindcss-upgrade package before 415 passed, 28 files
whole @tailwindcss-upgrade package after 422 passed, 28 files

prettier is clean on both changed files.

not covered

the issue also notes that a comment mentioning outline: none gets rewritten. that one is candidate extraction rather than this safety guard, so it is a different fix and i have left it alone.


disclaimer: this contribution was prepared with the help of an ai agent. i reviewed the change, reproduced the four failing cases against main first, and ran the package test suite locally before opening it.

the shadcn variant guard only looked at the text right before the literal so
any ternary or nullish branch between variant and the string defeated it and
the upgrade rewrote a react prop value as if it were a class

braces and commas stay excluded from the new part so the match cannot run past
its own value into a neighbouring prop like className
Copilot AI lite review requested due to automatic review settings August 27, 2026 23:05
@HuzaifaChaudary
HuzaifaChaudary requested a review from a team as a code owner August 27, 2026 23:05
@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The codemod now matches one-level object literals inside conditional variant expressions for brace-wrapped, quoted Vue, and object-form syntax. Tests cover invalid variant conditions, including function calls, object literals, computed members, parenthesized branches, nullish coalescing, and comparisons. Tests also confirm migration of conditional classes in JSX, component calls, and Vue :class attributes.

Merge Risk: 🔵 Low · up to 75e4e

The PR fixes conditional variant handling, but a bounded correctness risk remains for valid object-form expressions containing braces inside quoted strings, where the upgrade may still rewrite a component variant incorrectly. The change is otherwise localized and mergeable with explicit owner awareness or follow-up.

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The changes address the conditional-expression cases in issue #20435 and preserve neighboring class migrations. The issue also requires comment candidates to remain unchanged, but comment extraction i… Also prevent migration of matching text inside comments, or split the comment requirement into a separate issue and do not claim that issue #20435 is fully closed by this pull request.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the primary change: preventing migration of variant literals inside conditional expressions.
Description check ✅ Passed The description accurately explains the conditional variant migration bug, the regex-based fix, test coverage, and the explicitly excluded comment-rewriting issue.
Out of Scope Changes check ✅ Passed The implementation and tests stay within the scope of protecting variant prop values during template migration. No unrelated code changes are evident.
Full details: Linked Issues check

Explanation

The changes address the conditional-expression cases in issue #20435 and preserve neighboring class migrations. The issue also requires comment candidates to remain unchanged, but comment extraction is not modified.

  • Fix all pre-merge checks with AI

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2de9ab43-138d-47a0-b13e-f979998d0475

📥 Commits

Reviewing files that changed from the base of the PR and between 90f8ff4 and d8000d7.

📒 Files selected for processing (2)
  • packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.test.ts
  • packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Comment thread packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the @tailwindcss/upgrade template migration safety heuristics to avoid rewriting shadcn/ui-style variant="outline" literals when they appear inside simple conditional expressions, preventing accidental breakage of React prop values during upgrades.

Changes:

  • Expanded the variant look-behind guard in isSafeMigration to allow one ternary/nullish operator between the variant prop and the string literal.
  • Added regression tests covering the reported conditional variant cases and ensuring conditional class strings still migrate as expected.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts Broadens the variant guard regex used to decide when migrations are unsafe.
packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.test.ts Adds negative cases for conditional variant literals and positive cases to ensure conditional class migration still works.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +20 to +22
// shadcn/ui variants, including a ternary or nullish branch between the prop
// and the literal. Braces and commas are excluded so the match cannot reach
// out of its own value into a neighbouring prop such as `className`.
// shadcn/ui variants, including a ternary or nullish branch between the prop
// and the literal. Braces and commas are excluded so the match cannot reach
// out of its own value into a neighbouring prop such as `className`.
/variant\s*[:=]\s*\{?(?:[^{},]*?(?:\?\?|\?|:)\s*)?['"`]$/,
@greptile-apps

greptile-apps Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 4/5

The PR should not merge until conditional variant values containing deeper nested object literals are protected from class migration.

The new object-group pattern handles the reported flat object literal but cannot consume deeper nested braces, allowing the same variant-value rewrite to remain reachable.

Files Needing Attention: packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts

Reviews (5): Last reviewed commit: "let a condition contain an object litera..." | Re-trigger Greptile

Comment thread packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts Outdated
review pointed out two holes. a comma inside a call like isActive(foo, bar)
ended the match early, and a branch wrapped in parens put a ( between the
operator and the literal

a parenthesised group is now consumed as a unit so its commas stay inside it,
and parens are allowed right before the literal. a bare comma or brace still
ends the match so a neighbouring prop is still out of reach
@HuzaifaChaudary

Copy link
Copy Markdown
Author

thanks, two of the three were real and are now fixed in 893ab46a.

a call in the condition. variant={isActive(foo, bar) ? "outline" : "ghost"} was not guarded. my [^{},] ended the match at the comma inside the call. a parenthesised group is now consumed as a unit so its own commas stay inside it.

a parenthesised branch. variant={cond ? ("outline") : "ghost"} was not guarded either, because the ( sat between the operator and the literal. parens are now allowed there. covered in both arms.

the guard is now

/variant\s*[:=]\s*\{?(?:(?:[^{},()]|\([^()]*\))*?(?:\?\?|\?|:)\s*)?\(*\s*['"`]$/

a bare comma or brace still ends the match, which is what keeps a neighbouring className out of reach. Button({ variant: a ? "ghost" : "x", className: b ? "shadow" : "y" }) still migrates shadow, and there is a test for it.

on the brace comment. i think that one is a misread. [^{},] is a negated class over {, } and ,, so both braces were already excluded, not just the opening one. the current class [^{},()] excludes both parens as well.

on multiline values. correct, and it is not something this change introduces. currentLineBeforeCandidate is built by walking back until \n, so every entry in CONDITIONAL_TEMPLATE_SYNTAX is line scoped, not just this one. making the guards span lines would change behaviour for all of them, so it felt like the wrong thing to fold into a targeted fix. happy to open a separate issue for it if you want that tracked.

tests are now 78 in is-safe-migration and 425 across @tailwindcss-upgrade, up from 68 and 415 on main. the three new negatives fail without the change.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4414dc19-0856-45eb-ab38-21ef4aac62f7

📥 Commits

Reviewing files that changed from the base of the PR and between d8000d7 and 893ab46.

📒 Files selected for processing (2)
  • packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.test.ts
  • packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review.

Comment thread packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts Outdated
review caught an over match i introduced. vue writes attributes without braces
so the gap happily crossed variant="ghost" and carried on into :class, which
suppressed a class that should have migrated

quotes may now only be crossed inside a brace, where a quoted ternary branch is
ordinary. outside one a quote closes the attribute value so the match stops
there. nested parens in a condition are handled while i was in here
@HuzaifaChaudary

Copy link
Copy Markdown
Author

both of these were right, fixed in 3730f8a5.

the vue one is the important one, and it was a regression i introduced. <div variant="ghost" :class="active ? 'shadow' : 'none'"> was being guarded, so a class that should migrate no longer did. that is worse than the bug this pr set out to fix. vue writes attributes without braces, so my [^{},()] gap crossed "ghost" and walked straight on into :class.

the rule i had wrong is when a quote may be crossed. inside a brace a quoted ternary branch is ordinary, so variant={first ? "default" : "outline"} has to cross "default". outside a brace a quote closes the attribute value, so crossing one means leaving the attribute. the guard now splits on exactly that:

\{(?:[^{}]|PAREN)*?(?:\?\?|\?|:)\s*     braced, quotes may be crossed, braces may not
(?:[^{},()'"`]|PAREN)*?(?:\?\?|\?|:)\s* bare, a quote ends it
\{                                       the plain variant={"..."} form

nested parens. variant={isActive(getState(foo, bar), x) ? "outline"} now matches too, one level of nesting.

i pulled the pattern out into named parts above the array rather than growing the inline literal. three reviewers have now had to reason about this regex and the one liner was getting hard to read, so the parts are named and commented.

two new tests, one in each direction, and both fail on the previous commit:

  • <Button variant={isActive(getState(foo, bar), x) ? "outline" : "ghost"} /> must not migrate
  • <div variant="ghost" :class="active ? 'shadow' : 'none'"> must still migrate

is-safe-migration is 80 tests, @tailwindcss-upgrade is 427 across 28 files, up from 68 and 415 on main. prettier clean.

thanks for the catch, the vue case is one i should have tested for myself given the whole point of the guard is not to suppress real classes.

Comment thread packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9036e261-589b-43a9-a864-bf4a836e59d5

📥 Commits

Reviewing files that changed from the base of the PR and between 893ab46 and 3730f8a.

📒 Files selected for processing (2)
  • packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.test.ts
  • packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review.

Comment thread packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts Outdated
Comment thread packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts Outdated
three rounds of review kept finding holes in a single pattern because one regex
was trying to know where the value ends in three different syntaxes at once

each form now stops at what actually ends it. a brace for a jsx expression, the
opening quote for an attribute so it cannot run into a neighbouring one, a comma
or brace for an object literal where quotes are normal

the array already tests each rule on its own so this needs no other change
@HuzaifaChaudary

Copy link
Copy Markdown
Author

all three were right. fixed in 99d920d2, and i changed the shape rather than patch the pattern again.

three rounds of review have now found holes in this guard, and looking at why, they were all the same underlying mistake: one regex trying to know where a value ends in three different syntaxes at once. every time i widened it for one syntax it either missed another or reached into a neighbouring attribute. so it is now one rule per form, each stopping at what actually ends that form. the array already tests each rule independently so nothing else had to change.

variant\s*[:=]\s*\{?['"`]$                                      the plain forms
variant\s*[:=]\s*\{(?:[^{}]|PAREN)*?TAIL                        jsx, a brace ends it
variant\s*=\s*(["'])(?:(?!\1)[^{}])*?TAIL                       attribute, its own quote ends it
variant\s*:\s*(?:[^{},]|PAREN)*?TAIL                            object, a comma or brace ends it

that covers the three you found:

  • :variant="active ? 'ghost' : 'outline'" — the attribute rule. the backreference is what keeps it inside its own value, which is also what stops the :class over match from the last round
  • variant: (value ?? "outline") — the object rule, an unbalanced opening paren is fine there now
  • variant: theme === "dark" ? "outline" : "ghost" — the object rule too. quotes are ordinary inside an object value, a comma or brace is what ends it

three more negative tests, all failing on the previous commit. is-safe-migration is 83, @tailwindcss-upgrade is 430 across 28 files, against 68 and 415 on main. prettier clean.

happy to keep going if there is another hole, but if the maintainers would rather this whole heuristic move off regexes and onto a real parse of the surrounding expression, that is a bigger change than i should make unasked and i would open a separate issue for it instead.

Comment thread packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9fc6a8b9-d9c1-40e4-807e-2531ee803f25

📥 Commits

Reviewing files that changed from the base of the PR and between 3730f8a and 99d920d.

📒 Files selected for processing (2)
  • packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.test.ts
  • packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 6 remain after this review.

Comment thread packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts Outdated
review found two more, both an object literal inside the condition. a vue
binding calling isActive({ x: 1 }) and a jsx expression starting with an
inline object

an object group is now allowed as a unit the same way a parenthesised group
already was, so the braces inside it do not read as the end of the value
@HuzaifaChaudary

Copy link
Copy Markdown
Author

both fixed in 75e4e2f6. an object literal is now allowed as a unit inside a condition, the same way a parenthesised group already was, so its braces do not read as the end of the value.

  • :variant="isActive({ x: 1 }) ? 'ghost' : 'outline'"
  • <Button variant={{ tone: "dark" }.tone === "dark" ? "outline" : "ghost"} />

both are covered by tests and both fail on the previous commit. is-safe-migration is 85, @tailwindcss-upgrade is 432 across 28 files, against 68 and 415 on main.

where i think this actually stands

this is the fifth round, and i want to be straight about the trend rather than keep quietly widening things.

@coderabbitai is right that the real answer is scanning the expression with balanced brace, paren and quote state instead of matching it. a regex can only ever handle a bounded nesting depth. { a: { b: { c: 1 } } } inside a condition would still defeat what i just pushed, and i am not going to pretend otherwise by adding a third nesting level.

what i am less sure about is whether that scanner belongs in this pull request. every entry in CONDITIONAL_TEMPLATE_SYNTAX is a line scoped regex, and the whole array shares the same limits, so replacing the approach for one entry would leave the file half in each world and would be a much larger diff than the bug being fixed here warrants.

so my suggestion, and it is only a suggestion since this is your file:

  • take this as is if the four reported forms plus the eleven the reviews found are worth fixing now. it is strictly better than main and it cannot suppress a real class, which is the failure mode i care most about and which has a test in both directions
  • or tell me you want the scanner and i will do it properly as a replacement for the array rather than bolted next to it

either is fine by me. i would rather ask than keep adding nesting levels until someone finds level four.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 94bee8a8-3ea5-4017-ba50-d7f61fc37806

📥 Commits

Reviewing files that changed from the base of the PR and between 99d920d and 75e4e2f.

📒 Files selected for processing (2)
  • packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.test.ts
  • packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 6 remain after this review.

Comment on lines +11 to +13
// An object literal with one level of nesting, so a condition may contain one
// without the surrounding value looking like it ended there.
const OBJECT_GROUP = String.raw`\{(?:[^{}]|\{[^{}]*\})*\}`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make OBJECT_GROUP quote-aware.

OBJECT_GROUP treats every { and } as structural. A valid one-level object literal can contain a brace inside a string, for example:

<Button variant={{ tone: "}" }.tone === "}" ? "outline" : "ghost"} />

For the outline candidate, the conditional rules using this helper do not match. isSafeMigration can then return true, and migrateCandidate can rewrite the variant value to outline-solid. Consume quoted strings, including escaped quotes, before treating braces as delimiters. Add regression tests for the JSX, quoted-attribute, and object-form variants.

const PAREN_GROUP = String.raw`\((?:[^()]|\([^()]*\))*\)`
// An object literal with one level of nesting, so a condition may contain one
// without the surrounding value looking like it ended there.
const OBJECT_GROUP = String.raw`\{(?:[^{}]|\{[^{}]*\})*\}`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Nested variant objects bypass guard

When a conditional variant expression contains an object nested more deeply than OBJECT_GROUP supports, the guard cannot consume the nested braces and treats the variant literal as a utility candidate, causing the upgrade to rewrite application data such as outline.

Knowledge Base Used: Upgrade tool transformations

@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

implementation=$(fd -a '^is-safe-migration\.ts$' packages)
tests=$(fd -a '^is-safe-migration\.test\.ts$' packages)

printf '%s\n' '=== Implementation outline ==='
ast-grep outline "$implementation" --items all --type variable,constant,function

printf '%s\n' '=== Conditional guard implementation ==='
rg -n -C 12 'OBJECT_GROUP|PAREN_GROUP|CONDITIONAL_TEMPLATE_SYNTAX|variant' "$implementation"

printf '%s\n' '=== Related tests ==='
rg -n -C 6 'isActive\(\{ x: 1 \}\)|tone: "dark"|variant=.*\?' "$tests"

printf '%s\n' '=== Commit availability and changed files ==='
git show --no-ext-diff --format=fuller --stat 75e4e2f6 --
git diff --no-ext-diff 75e4e2f6^ 75e4e2f6 -- \
  "$implementation" "$tests"

Length of output: 13586


@HuzaifaChaudary, this is sufficient for this pull request.

The three syntax-specific rules use the correct value boundaries. The two new tests cover the reported object-literal cases. The existing valid-position test confirms that a neighboring Vue :class value still migrates.

A stateful scanner would remove the bounded-nesting limit. That is a separate refactor. It should replace the broader conditional-syntax mechanism in a dedicated change, not extend this targeted fix.

No additional blocking concern from my review.


✏️ Learnings added
Learnt from: HuzaifaChaudary
URL: https://github.com/tailwindlabs/tailwindcss/pull/20436

Timestamp: 2026-08-28T00:27:27.579Z
Learning: In `packages/tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts`, `CONDITIONAL_TEMPLATE_SYNTAX` is intentionally line-scoped. Its `variant` rules use bounded regex groups for parenthesized and object-literal expressions. A balanced-expression scanner would be a separate, broader refactor and should replace the conditional-syntax mechanism rather than be added only for one `variant` rule.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

You are interacting with an AI system.

@HuzaifaChaudary

Copy link
Copy Markdown
Author

both of these are real, and both are the ceiling i described in the last comment rather than new defects. a brace inside a string and an object nested past one level are the same structural limit: a regex cannot track balanced state, so there is always a next case. i said i would not keep adding levels and i am going to hold to that.

what i did do is measure which direction the remaining gaps fail in, because that is the part that decides whether this is mergeable as it stands.

they only fail by under guarding. for both of your cases the guard does not fire, so the prop is rewritten as a class, which is exactly what main does today for every conditional form. no case gets worse than it is now.

<Button variant={{ tone: "}" }.tone === "}" ? "outline" : "ghost"} />   not guarded
<Button variant={{ a: { b: { c: 1 } } }.a ? "outline" : "ghost"} />     not guarded

nothing over guards. the failure i actually care about is a real class silently no longer migrating, since that is worse than the bug this fixes. i checked that direction explicitly, including with your new shapes:

<div variant="ghost" :class="active ? 'shadow' : 'none'">     still migrates
<Button variant="ghost" className={active ? "shadow" : "x"}/> still migrates
Button({ variant: a ? "g" : "x", className: b ? "shadow" : "y" }) still migrates
<div :class="isActive({ x: 1 }) ? 'shadow' : 'none'">          still migrates
<div className={{ a: "}" }.a ? "shadow" : "x"}>                still migrates

so the state of this pr is: fixes the four forms from #20435 plus eleven more the reviews surfaced, cannot suppress a class that migrates today, and leaves a shrinking tail of exotic shapes behaving exactly as they already do on main.

that seems like a reasonable place to stop to me, but it is your call and i am happy either way:

  • merge as is and let the tail stay a known limit
  • or say the word and i will replace these four rules with a small backward scanner that tracks brace, paren and quote state properly. i would keep it to the variant rules and leave the other entries in the array alone, so it stays a contained change rather than a rewrite of the heuristic

i would rather do that once, deliberately, than keep going a level at a time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Upgrade codemod rewrites variant="outline" to "outline-solid" inside conditional expressions

2 participants