diff --git a/crates/oxide/src/scanner/mod.rs b/crates/oxide/src/scanner/mod.rs index ec6aea642481..ea914cb6f5b9 100644 --- a/crates/oxide/src/scanner/mod.rs +++ b/crates/oxide/src/scanner/mod.rs @@ -553,11 +553,17 @@ where a }) .into_iter() - .map(|s| unsafe { String::from_utf8_unchecked(s.to_vec()) }) + .filter_map(|s| match String::from_utf8(s.to_vec()) { + Ok(s) => Some(s), + Err(_e) => { + // Optionally log or handle invalid UTF-8 here + // eprintln!("Skipped invalid UTF-8 candidate, error: {:?}", _e); + None + } + }) .collect(); - // SAFETY: Unstable sort is faster and in this scenario it's also safe because we are - // guaranteed to have unique candidates. + // Unstable sort is performant & remains correct with unique candidates result.par_sort_unstable(); result diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts b/packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts index fa7ee7f4a1c5..6f57358e3836 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.ts @@ -1,4 +1,5 @@ import { parseCandidate } from '../../../../tailwindcss/src/candidate' +import { parse as parseHtml } from 'node-html-parser' import type { DesignSystem } from '../../../../tailwindcss/src/design-system' import { DefaultMap } from '../../../../tailwindcss/src/utils/default-map' import * as version from '../../utils/version' @@ -187,31 +188,24 @@ export function isSafeMigration( return true } -// Assumptions: -// - All `` tag -// - All `` -// - No nested `', offset) - if (endTag === -1) return ranges - offset = endTag + 1 - - ranges.push(startTag, endTag) + const ranges: number[] = [] + try { + const root = parseHtml(source, { lowerCaseTagName: false, comment: false, blockTextElements: { style: true } }) + const styleNodes = root.querySelectorAll('style') + styleNodes.forEach(node => { + const nodeHtml = node.toString() + const start = typeof node.range === 'object' && node.range !== null + ? node.range[0] + : source.indexOf(nodeHtml) + const end = start + nodeHtml.length + ranges.push(start, end) + }) + } catch (_) { + // fallback: do nothing if parser fails } + return ranges }) const BACKSLASH = 0x5c