#!/usr/bin/env bash # audit-css-collisions.sh — Find duplicate class selectors across kernel CSS files # Outputs a JSON collision report to stdout. # Usage: bash scripts/audit-css-collisions.sh [css-dir] set -euo pipefail CSS_DIR="${1:-src/css}" # Extract class selectors from CSS files and track their file + line declare -A SEEN # selector -> "file:line file:line ..." for f in "$CSS_DIR"/*.css; do [ -f "$f" ] || continue lineno=0 while IFS= read -r line; do lineno=$((lineno + 1)) # Extract class selectors (e.g. .foo-bar, .foo__bar--baz) # Skip lines that are comments, inside @keyframes, or @media queries [[ "$line" =~ ^[[:space:]]*/\* ]] && continue [[ "$line" =~ ^[[:space:]]*@keyframes ]] && continue # Match class selectors at the start of a rule while [[ "$line" =~ \.([a-zA-Z_][a-zA-Z0-9_-]*) ]]; do cls=".${BASH_REMATCH[1]}" entry="$(basename "$f"):$lineno" if [ -n "${SEEN[$cls]:-}" ]; then SEEN[$cls]="${SEEN[$cls]} $entry" else SEEN[$cls]="$entry" fi # Remove the matched portion to find more classes on the same line line="${line#*${BASH_REMATCH[0]}}" done done < "$f" done # Build JSON: only emit selectors defined in more than one file echo "[" first=true for cls in "${!SEEN[@]}"; do locations="${SEEN[$cls]}" # Get unique files files=() for loc in $locations; do file="${loc%%:*}" found=false for f in "${files[@]:-}"; do [ "$f" = "$file" ] && found=true && break done $found || files+=("$file") done # Only report if defined in 2+ different files [ ${#files[@]} -lt 2 ] && continue if $first; then first=false; else echo ","; fi # Build locations array locs_json="" for loc in $locations; do [ -n "$locs_json" ] && locs_json="$locs_json, " locs_json="$locs_json\"$loc\"" done files_json="" for f in "${files[@]}"; do [ -n "$files_json" ] && files_json="$files_json, " files_json="$files_json\"$f\"" done printf ' {"selector": "%s", "files": [%s], "locations": [%s]}' "$cls" "$files_json" "$locs_json" done echo "" echo "]"