Skip to content

Commit b9b0d28

Browse files
committed
check if we are in a string
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).
1 parent 67586f8 commit b9b0d28

File tree

1 file changed

+37
-3
lines changed

1 file changed

+37
-3
lines changed

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

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import type { DesignSystem } from '../../../../tailwindcss/src/design-system'
33
import { DefaultMap } from '../../../../tailwindcss/src/utils/default-map'
44
import * as version from '../../utils/version'
55

6-
const QUOTES = ['"', "'", '`']
76
const LOGICAL_OPERATORS = ['&&', '||', '?', '===', '==', '!=', '!==', '>', '>=', '<', '<=']
87
const CONDITIONAL_TEMPLATE_SYNTAX = [
98
// Vue
@@ -141,8 +140,8 @@ export function isSafeMigration(
141140
}
142141

143142
// Heuristic: Require the candidate to be inside quotes
144-
let isQuoteBeforeCandidate = QUOTES.some((quote) => currentLineBeforeCandidate.includes(quote))
145-
let isQuoteAfterCandidate = QUOTES.some((quote) => currentLineAfterCandidate.includes(quote))
143+
let isQuoteBeforeCandidate = isMiddleOfString(currentLineBeforeCandidate)
144+
let isQuoteAfterCandidate = isMiddleOfString(currentLineAfterCandidate)
146145
if (!isQuoteBeforeCandidate || !isQuoteAfterCandidate) {
147146
return false
148147
}
@@ -213,3 +212,38 @@ const styleBlockRanges = new DefaultMap((source: string) => {
213212
ranges.push(startTag, endTag)
214213
}
215214
})
215+
216+
const BACKSLASH = 0x5c
217+
const DOUBLE_QUOTE = 0x22
218+
const SINGLE_QUOTE = 0x27
219+
const BACKTICK = 0x60
220+
221+
function isMiddleOfString(line: string): boolean {
222+
let currentQuote: number | null = null
223+
224+
for (let i = 0; i < line.length; i++) {
225+
let char = line.charCodeAt(i)
226+
switch (char) {
227+
// Escaped character, skip the next character
228+
case BACKSLASH:
229+
i++
230+
break
231+
232+
case SINGLE_QUOTE:
233+
case DOUBLE_QUOTE:
234+
case BACKTICK:
235+
// Found matching quote, we are outside of a string
236+
if (currentQuote === char) {
237+
currentQuote = null
238+
}
239+
240+
// Found a quote, we are inside a string
241+
else if (currentQuote === null) {
242+
currentQuote = char
243+
}
244+
break
245+
}
246+
}
247+
248+
return currentQuote !== null
249+
}

0 commit comments

Comments
 (0)