Skip to content

Conversation

RobinMalfait
Copy link
Member

@RobinMalfait RobinMalfait commented Aug 11, 2025

This PR fixes 2 false-positives when running the upgrade tool on a Tailwind CSS v3 project converting it to a Tailwind CSS v4 project.

The issue occurs around migrations with short simple names that have a meaning outside if Tailwind CSS, e.g. blur and outline.

This PR fixes 2 such cases:

  1. The addEventListener case:

    document.addEventListener('blur', handleBlur)

    We do this by special casing the addEventListener( case and making sure the first argument to addEventListener is never migrated.

  2. A JavaScript variable with default value:

    function foo({ foo = "bar", outline = true, baz = "qux" }) {
      // ...
    }

    The bug is relatively subtle here, but it has actually nothing to do with outline itself, but rather the fact that some quote character came before and after it on the same line...

    One of our heuristics for determining if a migration on these small words is safe, is to ensure that the candidate is inside of a string. Since we didn't do any kind of quote balancing, we would consider the outline to be inside of a string, even though it is not.

    So to actually solve this, we do some form of quote balancing to ensure that it's not inside of a string in this case.

Additionally, this PR also introduces a small refactor to the is-safe-migration.test.ts file where we now use a test.each to ensure that failing tests in the middle don't prevent the rest of the tests from running.

Test plan

  1. Added dedicated tests for the cases mentioned in the issue (The npx @tailwindcss/upgrade command accidentally modified variables or event name, when the variables or event name look like classnames #18675).
  2. Added a few more tests with various forms of whitespace.

Fixes: #18675

Use test table such that if a single test fails, all tests after still
execute.
To be a bit more correct and consistent with the `addEventListener`
approach.
Our existing heuristic looked for a quote _somewhere_ before the
candidate and a quote (doesn't need to be the same type of quote)
_somewhere_ after the candidate.

While this is an okay assumption, it also has flaws, because this means
that the `outline` in the following example is considered inside of a
string:

```js
function foo({ a = "", outline = true, b = "" }) {
  //
}
```

With this change, we will do a little bit of parsing and figure out if
we are in a string (by looking at balanced quotes).
@RobinMalfait RobinMalfait requested a review from a team as a code owner August 11, 2025 22:20
const BACKSLASH = 0x5c
const DOUBLE_QUOTE = 0x22
const SINGLE_QUOTE = 0x27
const BACKTICK = 0x60
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we consider that in JS backtick strings can span lines — or just not worry about that unless it comes up?

Copy link
Member Author

Choose a reason for hiding this comment

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

We haven't in the past and nobody had issues with this yet (afaik at least) so I don't think we need to add the additional complexity of this (yet) 🤔

@thecrypticace thecrypticace merged commit 30be24b into main Aug 12, 2025
7 checks passed
@thecrypticace thecrypticace deleted the fix/issue-18675 branch August 12, 2025 13:48
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.

The npx @tailwindcss/upgrade command accidentally modified variables or event name, when the variables or event name look like classnames
2 participants