{"version":3,"sources":["../src/utils/files.ts","../src/utils/regex.ts","../src/core/scanner.ts"],"names":["path","glob","readFile","stat"],"mappings":"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","file":"scanner.cjs","sourcesContent":["/**\n * File utilities for Classpresso\n */\n\nimport { readFile, writeFile, stat, copyFile } from 'fs/promises';\nimport { glob } from 'glob';\nimport path from 'path';\nimport type { FileStats } from '../types/index.js';\n\n/**\n * Default file patterns to scan in build output\n *\n * These patterns support all major frameworks when pointing to their build directories:\n * - Next.js: --dir .next\n * - Astro: --dir dist\n * - Nuxt: --dir .output\n * - SvelteKit: --dir build (or .svelte-kit)\n * - Remix: --dir build\n * - Solid Start: --dir .output (or dist)\n * - Qwik: --dir dist\n * - Angular: --dir dist/[project-name]\n * - Gatsby: --dir public\n * - Vite/Vue/React: --dir dist\n * - Ember: --dir dist\n * - VitePress: --dir .vitepress/dist\n * - Docusaurus: --dir build\n * - Eleventy (11ty): --dir _site\n * - Hugo: --dir public\n * - Parcel: --dir dist\n * - Preact: --dir build (or dist)\n * - Gridsome: --dir dist\n * - RedwoodJS: --dir web/dist\n * - Webpack: --dir dist\n */\nexport const DEFAULT_PATTERNS = [\n  // === Next.js (.next directory) ===\n  // Client-side chunks\n  'static/chunks/**/*.js',\n  'static/css/**/*.css',\n  // Server components (Next.js App Router)\n  'server/app/**/*.js',\n  'server/app/**/*.html',\n  'server/app/**/*.rsc',\n  // Server chunks (contains Client Component code used for hydration)\n  'server/chunks/**/*.js',\n  // Standalone build (Next.js output: 'standalone')\n  'standalone/.next/static/chunks/**/*.js',\n  'standalone/.next/static/css/**/*.css',\n  'standalone/.next/server/app/**/*.js',\n  'standalone/.next/server/app/**/*.html',\n  'standalone/.next/server/app/**/*.rsc',\n  'standalone/.next/server/chunks/**/*.js',\n\n  // === Nuxt (.output directory) ===\n  'public/**/*.html',\n  'public/**/*.js',\n  'public/**/*.css',\n  'public/_nuxt/**/*.js',\n  'public/_nuxt/**/*.css',\n  'server/**/*.mjs',\n  'server/chunks/**/*.mjs',\n\n  // === SvelteKit (build directory) ===\n  // Static adapter output\n  '**/*.html',\n  '_app/**/*.js',\n  '_app/**/*.css',\n  // Node adapter output\n  'client/**/*.js',\n  'client/**/*.css',\n  'server/**/*.js',\n\n  // === Astro (dist directory) ===\n  '_astro/**/*.js',\n  '_astro/**/*.css',\n  // SSR/Hybrid build - Client assets\n  'client/_astro/**/*.js',\n  'client/_astro/**/*.css',\n\n  // === Remix (build directory) ===\n  'client/**/*.js',\n  'client/**/*.css',\n  'server/**/*.js',\n\n  // === Solid Start (.output or dist directory) ===\n  'public/**/*.html',\n  'public/**/*.js',\n  'public/**/*.css',\n  '_build/**/*.js',\n  '_build/**/*.css',\n\n  // === Qwik (dist directory) ===\n  'build/**/*.js',\n  'build/**/*.css',\n  'q-*.js',\n\n  // === Angular (dist/[project] directory) ===\n  // Angular 17+ uses browser subdirectory\n  'browser/**/*.js',\n  'browser/**/*.css',\n  'browser/**/*.html',\n  // Legacy Angular output\n  '*.js',\n  '*.css',\n  '*.html',\n\n  // === Gatsby (public directory) ===\n  'page-data/**/*.json',\n  '*.js',\n  '*.css',\n  '*.html',\n\n  // === Vite/Vue/React generic (dist directory) ===\n  'assets/**/*.js',\n  'assets/**/*.css',\n  'index.html',\n\n  // === Ember (dist directory) ===\n  'assets/**/*.js',\n  'assets/**/*.css',\n  '*.html',\n\n  // === VitePress (.vitepress/dist directory) ===\n  'assets/**/*.js',\n  'assets/**/*.css',\n  '**/*.html',\n\n  // === Docusaurus (build directory) ===\n  'assets/**/*.js',\n  'assets/**/*.css',\n  '**/*.html',\n\n  // === Eleventy/11ty (_site directory) ===\n  '**/*.html',\n  '**/*.js',\n  '**/*.css',\n\n  // === Hugo (public directory) ===\n  '**/*.html',\n  '**/*.js',\n  '**/*.css',\n\n  // === Parcel (dist directory) ===\n  '*.html',\n  '*.js',\n  '*.css',\n\n  // === Preact (build directory) ===\n  'bundle.js',\n  'bundle.*.js',\n  '*.css',\n  '*.html',\n\n  // === Gridsome (dist directory) ===\n  'assets/**/*.js',\n  'assets/**/*.css',\n  '**/*.html',\n\n  // === RedwoodJS (web/dist directory) ===\n  'static/**/*.js',\n  'static/**/*.css',\n  '*.html',\n\n  // === Webpack generic (dist directory) ===\n  '*.js',\n  '*.css',\n  '*.html',\n  'js/**/*.js',\n  'css/**/*.css',\n];\n\n/**\n * Find files matching patterns in a build directory\n */\nexport async function findFiles(\n  buildDir: string,\n  patterns: string[]\n): Promise<string[]> {\n  // Create full patterns and deduplicate\n  const globPatterns = [...new Set(patterns.map(p => path.join(buildDir, p)))];\n\n  // Use windowsPathsNoEscape for Windows compatibility\n  const allFiles = await glob(globPatterns, {\n    nodir: true,\n    windowsPathsNoEscape: true\n  });\n\n  // Remove duplicates (in case patterns overlap)\n  return [...new Set(allFiles)];\n}\n\n/**\n * Read file content as string\n */\nexport async function readFileContent(filePath: string): Promise<string> {\n  return readFile(filePath, 'utf-8');\n}\n\n/**\n * Write content to file\n */\nexport async function writeFileContent(\n  filePath: string,\n  content: string\n): Promise<void> {\n  await writeFile(filePath, content, 'utf-8');\n}\n\n/**\n * Get file size in bytes\n */\nexport async function getFileSize(filePath: string): Promise<number> {\n  const stats = await stat(filePath);\n  return stats.size;\n}\n\n/**\n * Create a backup of a file\n */\nexport async function backupFile(filePath: string): Promise<string> {\n  const backupPath = `${filePath}.classpresso-backup`;\n  await copyFile(filePath, backupPath);\n  return backupPath;\n}\n\n/**\n * Get file stats for a list of files\n */\nexport async function getFileStats(filePaths: string[]): Promise<FileStats[]> {\n  const stats: FileStats[] = [];\n\n  for (const filePath of filePaths) {\n    try {\n      const size = await getFileSize(filePath);\n      stats.push({\n        path: filePath,\n        originalSize: size,\n        modified: false,\n      });\n    } catch {\n      // Skip files that can't be read\n    }\n  }\n\n  return stats;\n}\n\n/**\n * Check if a file is a JavaScript file\n */\nexport function isJSFile(filePath: string): boolean {\n  return /\\.(js|mjs|cjs)$/.test(filePath);\n}\n\n/**\n * Check if a file is a CSS file\n */\nexport function isCSSFile(filePath: string): boolean {\n  return /\\.css$/.test(filePath);\n}\n\n/**\n * Check if a file is an HTML file\n */\nexport function isHTMLFile(filePath: string): boolean {\n  return /\\.(html|htm)$/.test(filePath);\n}\n\n/**\n * Check if a file is an RSC payload\n */\nexport function isRSCFile(filePath: string): boolean {\n  return /\\.rsc$/.test(filePath);\n}\n\n/**\n * Check if a file matches any exclusion pattern\n * Patterns can be glob-style (e.g., \"**\\/Demo*\", \"**\\/ClassTester*\")\n */\nexport function shouldExcludeFile(filePath: string, excludePatterns: string[]): boolean {\n  if (!excludePatterns || excludePatterns.length === 0) {\n    return false;\n  }\n\n  // Normalize path for consistent matching\n  const normalizedPath = filePath.replace(/\\\\/g, '/');\n\n  for (const pattern of excludePatterns) {\n    // Convert glob pattern to regex\n    // Support: ** (any path), * (any chars), ? (single char)\n    const regexPattern = pattern\n      .replace(/\\\\/g, '/')\n      .replace(/\\*\\*/g, '{{DOUBLESTAR}}')\n      .replace(/\\*/g, '[^/]*')\n      .replace(/\\?/g, '.')\n      .replace(/{{DOUBLESTAR}}/g, '.*');\n\n    const regex = new RegExp(regexPattern);\n    if (regex.test(normalizedPath)) {\n      return true;\n    }\n  }\n\n  return false;\n}\n\n/**\n * Filter files to exclude those matching exclusion patterns\n */\nexport function filterExcludedFiles(files: string[], excludePatterns: string[]): string[] {\n  if (!excludePatterns || excludePatterns.length === 0) {\n    return files;\n  }\n\n  return files.filter(filePath => !shouldExcludeFile(filePath, excludePatterns));\n}\n","/**\n * Regex utilities for Classpresso\n */\n\n/**\n * Escape special regex characters in a string\n */\nexport function escapeRegex(str: string): string {\n  return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Patterns to match className in various contexts\n */\nexport const CLASS_PATTERNS = {\n  // JSX: className=\"...\"\n  jsxDouble: /className\\s*=\\s*\"([^\"]+)\"/g,\n\n  // JSX: className='...'\n  jsxSingle: /className\\s*=\\s*'([^']+)'/g,\n\n  // React createElement: className:\"...\"\n  createElementDouble: /className\\s*:\\s*\"([^\"]+)\"/g,\n\n  // React createElement: className:'...'\n  createElementSingle: /className\\s*:\\s*'([^']+)'/g,\n\n  // Minified: \"className\",\"...\"\n  minifiedComma: /\"className\"\\s*,\\s*\"([^\"]+)\"/g,\n\n  // HTML: class=\"...\"\n  htmlDouble: /\\bclass\\s*=\\s*\"([^\"]+)\"/g,\n\n  // HTML: class='...'\n  htmlSingle: /\\bclass\\s*=\\s*'([^']+)'/g,\n\n  // HTML entity encoded: class=&quot;...&quot;\n  htmlEntityDouble: /\\bclass=&quot;([^&]+)&quot;/g,\n\n  // HTML entity encoded: class=&#34;...&#34; (numeric entity)\n  htmlNumericDouble: /\\bclass=&#34;([^&]+)&#34;/g,\n\n  // RSC payload: \\\"className\\\":\\\"...\\\" (escaped JSON in Next.js RSC payloads)\n  rscPayload: /\\\\\"className\\\\\"\\s*:\\s*\\\\\"([^\"\\\\]+)\\\\\"/g,\n\n  // Vue/Quasar createElement: class:\"...\" (Vue uses 'class' not 'className')\n  vueCreateElementDouble: /\\bclass\\s*:\\s*\"([^\"]+)\"/g,\n\n  // Vue/Quasar createElement: class:'...'\n  vueCreateElementSingle: /\\bclass\\s*:\\s*'([^']+)'/g,\n\n  // JSX: className=`...` (static template literal, no dynamic expressions)\n  jsxBacktick: /className\\s*=\\s*`([^`$]+)`/g,\n\n  // React createElement: className:`...` (static template literal, no dynamic expressions)\n  createElementBacktick: /className\\s*:\\s*`([^`$]+)`/g,\n};\n\n/**\n * All patterns combined for extraction\n */\nexport const ALL_CLASS_PATTERNS = [\n  CLASS_PATTERNS.jsxDouble,\n  CLASS_PATTERNS.jsxSingle,\n  CLASS_PATTERNS.createElementDouble,\n  CLASS_PATTERNS.createElementSingle,\n  CLASS_PATTERNS.minifiedComma,\n  CLASS_PATTERNS.htmlDouble,\n  CLASS_PATTERNS.htmlSingle,\n  CLASS_PATTERNS.htmlEntityDouble,\n  CLASS_PATTERNS.htmlNumericDouble,\n  CLASS_PATTERNS.rscPayload,\n  CLASS_PATTERNS.vueCreateElementDouble,\n  CLASS_PATTERNS.vueCreateElementSingle,\n  CLASS_PATTERNS.jsxBacktick,\n  CLASS_PATTERNS.createElementBacktick,\n];\n\n/**\n * Check if a class string contains dynamic expressions\n */\nexport function isDynamicClassString(classString: string): boolean {\n  // Template literal expression\n  if (classString.includes('${')) return true;\n\n  // Ternary operator (likely dynamic)\n  if (/\\s*\\?\\s*/.test(classString) && classString.includes(':')) return true;\n\n  // Function call\n  if (/\\w+\\s*\\(/.test(classString)) return true;\n\n  // Variable reference (camelCase or UPPER_CASE that's not a valid class)\n  if (/^[a-z][a-zA-Z0-9]*$/.test(classString) && !classString.includes('-')) return true;\n\n  return false;\n}\n\n/**\n * Patterns to extract the static base portion of template literal class names\n * These capture the static classes before the ${...} dynamic expression\n */\nexport const DYNAMIC_BASE_PATTERNS = [\n  // className:`base classes ${...}`\n  /className\\s*:\\s*`([^`$]+)\\s*\\$\\{/g,\n  // className=`base classes ${...}` (JSX)\n  /className\\s*=\\s*`([^`$]+)\\s*\\$\\{/g,\n  // class:`base classes ${...}` (rare but possible)\n  /\\bclass\\s*:\\s*`([^`$]+)\\s*\\$\\{/g,\n];\n\n/**\n * Patterns to extract the static base portion of .concat() calls\n * Minified React often uses \"\".concat(\"base\", \" \", variant) for className\n * These are treated as dynamic and should be skipped\n */\nexport const CONCAT_BASE_PATTERNS = [\n  // className:\"\".concat(\"base classes\",...) - the base before concat\n  /className\\s*:\\s*\"\"\\s*\\.concat\\s*\\(\\s*\"([^\"]+)\"/g,\n  // className:''.concat('base classes',...)\n  /className\\s*:\\s*''\\s*\\.concat\\s*\\(\\s*'([^']+)'/g,\n];\n\n/**\n * Extract static base patterns from .concat() calls\n * Returns the static class portion from the first concat argument\n */\nexport function extractConcatBaseStrings(content: string): string[] {\n  const results: string[] = [];\n\n  for (const pattern of CONCAT_BASE_PATTERNS) {\n    pattern.lastIndex = 0;\n    let match;\n    while ((match = pattern.exec(content)) !== null) {\n      const baseString = match[1]?.trim();\n      if (baseString && baseString.length > 0) {\n        results.push(baseString);\n      }\n    }\n  }\n\n  return results;\n}\n\n/**\n * Extract static base patterns from template literals with dynamic expressions\n * Returns the static class portion before ${...}\n */\nexport function extractDynamicBaseStrings(\n  content: string\n): string[] {\n  const results: string[] = [];\n\n  for (const pattern of DYNAMIC_BASE_PATTERNS) {\n    pattern.lastIndex = 0;\n    let match;\n    while ((match = pattern.exec(content)) !== null) {\n      const baseString = match[1]?.trim();\n      if (baseString && baseString.length > 0) {\n        results.push(baseString);\n      }\n    }\n  }\n\n  return results;\n}\n\n/**\n * Create a replacement pattern for a class string\n */\nexport function createReplacementPatterns(original: string): RegExp[] {\n  const escaped = escapeRegex(original);\n\n  return [\n    new RegExp(`(className\\\\s*=\\\\s*)\"${escaped}\"`, 'g'),\n    new RegExp(`(className\\\\s*=\\\\s*)'${escaped}'`, 'g'),\n    new RegExp(`(className\\\\s*:\\\\s*)\"${escaped}\"`, 'g'),\n    new RegExp(`(className\\\\s*:\\\\s*)'${escaped}'`, 'g'),\n    new RegExp(`(\"className\"\\\\s*,\\\\s*)\"${escaped}\"`, 'g'),\n    new RegExp(`(class\\\\s*=\\\\s*)\"${escaped}\"`, 'g'),\n    new RegExp(`(class\\\\s*=\\\\s*)'${escaped}'`, 'g'),\n    // HTML entity encoded quotes\n    new RegExp(`(class=&quot;)${escaped}(&quot;)`, 'g'),\n    new RegExp(`(class=&#34;)${escaped}(&#34;)`, 'g'),\n    // Vue/Quasar class: syntax\n    new RegExp(`(\\\\bclass\\\\s*:\\\\s*)\"${escaped}\"`, 'g'),\n    new RegExp(`(\\\\bclass\\\\s*:\\\\s*)'${escaped}'`, 'g'),\n    // Static template literals\n    new RegExp(`(className\\\\s*=\\\\s*)\\`${escaped}\\``, 'g'),\n    new RegExp(`(className\\\\s*:\\\\s*)\\`${escaped}\\``, 'g'),\n  ];\n}\n","/**\n * Scanner - Extracts className patterns from build output\n */\n\nimport type {\n  ClasspressoConfig,\n  ClassOccurrence,\n  FileLocation,\n  ScanResult,\n  FileStats,\n  DynamicBasePattern,\n  SourceFileType,\n} from '../types/index.js';\nimport {\n  findFiles,\n  readFileContent,\n  getFileSize,\n  isJSFile,\n  isHTMLFile,\n  isRSCFile,\n  DEFAULT_PATTERNS,\n  filterExcludedFiles,\n} from '../utils/files.js';\nimport { ALL_CLASS_PATTERNS, isDynamicClassString, extractDynamicBaseStrings, extractConcatBaseStrings } from '../utils/regex.js';\n\n/**\n * Determine the source file type\n */\nfunction getSourceFileType(filePath: string): SourceFileType {\n  if (isHTMLFile(filePath)) return 'html';\n  if (isRSCFile(filePath)) return 'rsc';\n  return 'js';\n}\n\n/**\n * Check if pattern A's classes are a proper subset of pattern B's classes.\n * A is a proper subset of B if all classes in A are in B, and B has more classes.\n */\nexport function isProperSubset(classesA: string[], classesB: string[]): boolean {\n  if (classesA.length >= classesB.length) return false;\n\n  const setB = new Set(classesB);\n  return classesA.every(cls => setB.has(cls));\n}\n\n/**\n * Detect patterns that appear in JS but are subsets of HTML patterns.\n * These are likely className props that get merged with component classes.\n */\nexport function detectMergeablePatterns(\n  occurrences: Map<string, ClassOccurrence>\n): Set<string> {\n  const mergeablePatterns = new Set<string>();\n\n  // Get all JS-only patterns and HTML patterns\n  const jsPatterns: ClassOccurrence[] = [];\n  const htmlPatterns: ClassOccurrence[] = [];\n\n  for (const [, occurrence] of occurrences) {\n    if (occurrence.sourceTypes.has('js')) {\n      jsPatterns.push(occurrence);\n    }\n    if (occurrence.sourceTypes.has('html') || occurrence.sourceTypes.has('rsc')) {\n      htmlPatterns.push(occurrence);\n    }\n  }\n\n  // For each JS pattern, check if it's a subset of any HTML pattern\n  for (const jsPattern of jsPatterns) {\n    for (const htmlPattern of htmlPatterns) {\n      if (isProperSubset(jsPattern.classes, htmlPattern.classes)) {\n        // This JS pattern's classes appear as part of a larger HTML pattern\n        // It's likely a className prop that gets merged\n        mergeablePatterns.add(jsPattern.normalizedKey);\n        break;\n      }\n    }\n  }\n\n  return mergeablePatterns;\n}\n\n/**\n * Check if any class in a list contains a dynamic library prefix.\n * These are classes generated at runtime by libraries like lucide-react, heroicons, etc.\n */\nexport function containsDynamicPrefix(\n  classes: string[],\n  dynamicPrefixes: string[]\n): boolean {\n  for (const cls of classes) {\n    for (const prefix of dynamicPrefixes) {\n      // For prefixes ending with '-' (e.g., \"fa-\", \"icon-\"), just check startsWith\n      if (prefix.endsWith('-')) {\n        if (cls.startsWith(prefix)) {\n          return true;\n        }\n      } else {\n        // For prefixes without '-' (e.g., \"lucide\", \"fas\", \"far\", \"fab\"),\n        // match exact or followed by '-' to avoid false positives\n        // e.g., \"fab\" matches \"fab\" or \"fab-icon\", but not \"fabric\"\n        if (cls === prefix || cls.startsWith(prefix + '-')) {\n          return true;\n        }\n      }\n    }\n  }\n  return false;\n}\n\n/**\n * Check if a class occurrence is safe for SSR hydration.\n * A pattern is hydration-safe if it appears in BOTH:\n * - Server context (html or rsc)\n * - Client context (js)\n *\n * If a pattern only appears in one context, transforming it would cause\n * React hydration mismatches.\n */\nexport function isHydrationSafe(occurrence: ClassOccurrence): boolean {\n  const hasServerContext = occurrence.sourceTypes.has('html') || occurrence.sourceTypes.has('rsc');\n  const hasClientContext = occurrence.sourceTypes.has('js');\n\n  // Must appear in both server and client contexts to be safe\n  return hasServerContext && hasClientContext;\n}\n\n/**\n * Returns true for classes whose CSS rule cannot be expressed as flat declarations\n * on a single-class selector — i.e., classes that require a media query wrapper,\n * an @container wrapper, or a combinator child selector to function correctly.\n *\n * Consolidating these into a plain `.cp-xxx { ... }` rule silently drops the\n * wrapping context, producing a visually broken build with no warning.\n *\n * Detected categories:\n *  - Any variant prefix:    md:, hover:, dark:, focus:, group-hover:, data-[x]:, etc.\n *  - Container queries:     @sm, @md, @[800px], etc.\n *  - Combinator utilities:  space-x-*, space-y-*, divide-x-*, divide-y-*\n */\nexport function isNonFlattenableClass(className: string): boolean {\n  // Variant prefixes — any colon in the class name means it needs a wrapper\n  if (className.includes(':')) return true;\n  // Container queries\n  if (className.startsWith('@')) return true;\n  // Combinator utilities that generate child selectors like `.space-y-6 > :not(:last-child)`\n  if (/^space-[xy]/.test(className)) return true;\n  if (/^divide-[xy]/.test(className)) return true;\n  return false;\n}\n\n/**\n * Check if a class should be excluded based on config\n */\nexport function shouldExcludeClass(\n  className: string,\n  exclude: ClasspressoConfig['exclude']\n): boolean {\n  // Check prefix patterns\n  if (exclude.prefixes) {\n    for (const prefix of exclude.prefixes) {\n      if (className.startsWith(prefix)) return true;\n    }\n  }\n\n  // Check suffix patterns\n  if (exclude.suffixes) {\n    for (const suffix of exclude.suffixes) {\n      if (className.endsWith(suffix)) return true;\n    }\n  }\n\n  // Check exact matches\n  if (exclude.classes) {\n    if (exclude.classes.includes(className)) return true;\n  }\n\n  // Check regex patterns\n  if (exclude.patterns) {\n    for (const pattern of exclude.patterns) {\n      if (pattern.test(className)) return true;\n    }\n  }\n\n  return false;\n}\n\n/**\n * Normalize a class string for consistent comparison\n * - Splits into individual classes\n * - Removes excluded classes\n * - Sorts alphabetically\n * - Joins back together\n */\nexport function normalizeClassString(\n  classString: string,\n  exclude: ClasspressoConfig['exclude'],\n  excludeNonFlattenable: boolean = false\n): { normalized: string; classes: string[]; excludedClasses: string[] } {\n  const allClasses = classString.split(/\\s+/).filter(Boolean);\n  const includedClasses: string[] = [];\n  const excludedClasses: string[] = [];\n\n  for (const cls of allClasses) {\n    if (shouldExcludeClass(cls, exclude) || (excludeNonFlattenable && isNonFlattenableClass(cls))) {\n      excludedClasses.push(cls);\n    } else {\n      includedClasses.push(cls);\n    }\n  }\n\n  // Sort for consistent comparison\n  const sorted = [...includedClasses].sort();\n  return {\n    normalized: sorted.join(' '),\n    classes: includedClasses,\n    excludedClasses,\n  };\n}\n\n/**\n * Extract class strings from file content\n */\nexport function extractClassStrings(\n  content: string,\n  filePath: string\n): Array<{ classString: string; location: FileLocation }> {\n  const results: Array<{ classString: string; location: FileLocation }> = [];\n  const seen = new Set<string>();\n\n  for (const pattern of ALL_CLASS_PATTERNS) {\n    // Reset regex lastIndex\n    pattern.lastIndex = 0;\n\n    let match;\n    while ((match = pattern.exec(content)) !== null) {\n      const classString = match[1];\n\n      // Skip empty strings\n      if (!classString || !classString.trim()) continue;\n\n      // Skip dynamic expressions\n      if (isDynamicClassString(classString)) continue;\n\n      // Skip if already seen at this exact position (same file and character offset)\n      // This allows duplicate strings in the same file (e.g., bundled components)\n      // while avoiding double-counting from overlapping regex patterns\n      const key = `${filePath}:${match.index}:${classString}`;\n      if (seen.has(key)) continue;\n      seen.add(key);\n\n      // Calculate approximate line number\n      const beforeMatch = content.substring(0, match.index);\n      const line = (beforeMatch.match(/\\n/g) || []).length + 1;\n\n      results.push({\n        classString: classString.trim(),\n        location: {\n          filePath,\n          line,\n        },\n      });\n    }\n  }\n\n  return results;\n}\n\n/**\n * Scan build directory for className patterns\n */\nexport async function scanBuildOutput(\n  config: ClasspressoConfig\n): Promise<ScanResult> {\n  const occurrences = new Map<string, ClassOccurrence>();\n  const dynamicBasePatterns = new Map<string, DynamicBasePattern>();\n  const fileStats: FileStats[] = [];\n  const errors: string[] = [];\n\n  // Find all files to scan\n  const patterns = config.include.length > 0 ? config.include : DEFAULT_PATTERNS;\n  const allFiles = await findFiles(config.buildDir, patterns);\n\n  // Filter out excluded files\n  const files = filterExcludedFiles(allFiles, config.exclude.files || []);\n\n  if (config.verbose) {\n    console.log(`Found ${allFiles.length} files, scanning ${files.length} (${allFiles.length - files.length} excluded)`);\n  }\n\n  for (const filePath of files) {\n    try {\n      // Skip non-relevant file types\n      if (!isJSFile(filePath) && !isHTMLFile(filePath) && !isRSCFile(filePath)) {\n        continue;\n      }\n\n      const content = await readFileContent(filePath);\n      const size = await getFileSize(filePath);\n\n      fileStats.push({\n        path: filePath,\n        originalSize: size,\n        modified: false,\n      });\n\n      // Extract dynamic base patterns from JS files (for hydration safety)\n      // These include template literals with ${} and .concat() calls\n      if (isJSFile(filePath)) {\n        // Get bases from template literals: className:`base ${dynamic}`\n        const dynamicBases = extractDynamicBaseStrings(content);\n        // Get bases from concat calls: className:\"\".concat(\"base\", variant)\n        const concatBases = extractConcatBaseStrings(content);\n\n        // Combine all dynamic bases\n        const allDynamicBases = [...dynamicBases, ...concatBases];\n\n        for (const baseString of allDynamicBases) {\n          const { normalized, classes } = normalizeClassString(baseString, config.exclude, config.excludeNonFlattenableClasses);\n\n          // Skip if too few classes\n          if (classes.length < config.minClasses) continue;\n\n          const location: FileLocation = { filePath };\n\n          if (dynamicBasePatterns.has(normalized)) {\n            dynamicBasePatterns.get(normalized)!.locations.push(location);\n          } else {\n            dynamicBasePatterns.set(normalized, {\n              baseClasses: classes,\n              normalizedKey: normalized,\n              locations: [location],\n            });\n          }\n        }\n      }\n\n      const classStrings = extractClassStrings(content, filePath);\n      const sourceType = getSourceFileType(filePath);\n\n      for (const { classString, location } of classStrings) {\n        const { normalized, classes, excludedClasses } = normalizeClassString(\n          classString,\n          config.exclude,\n          config.excludeNonFlattenableClasses\n        );\n\n        // Skip if all classes were excluded\n        if (classes.length === 0) continue;\n\n        // Skip single classes (no benefit to consolidate)\n        if (classes.length < config.minClasses) continue;\n\n        // Skip patterns containing dynamic library prefixes (e.g., lucide-react, heroicons)\n        // These are generated at runtime and transforming them causes hydration mismatches\n        if (config.excludeDynamicPatterns && containsDynamicPrefix(classes, config.dynamicPrefixes)) {\n          continue;\n        }\n\n        if (occurrences.has(normalized)) {\n          const existing = occurrences.get(normalized)!;\n          existing.count++;\n          existing.locations.push(location);\n          existing.sourceTypes.add(sourceType);\n        } else {\n          occurrences.set(normalized, {\n            classString,\n            normalizedKey: normalized,\n            count: 1,\n            locations: [location],\n            classes,\n            excludedClasses,\n            sourceTypes: new Set([sourceType]),\n          });\n        }\n      }\n    } catch (err) {\n      errors.push(`Error scanning ${filePath}: ${err}`);\n    }\n  }\n\n  // Detect patterns that are likely className props that get merged\n  const mergeablePatterns = detectMergeablePatterns(occurrences);\n\n  if (config.verbose && mergeablePatterns.size > 0) {\n    console.log(`Found ${mergeablePatterns.size} patterns that appear to be merged className props`);\n  }\n\n  return {\n    occurrences,\n    files: fileStats,\n    errors,\n    dynamicBasePatterns,\n    mergeablePatterns,\n  };\n}\n"]}