Created
July 3, 2025 23:02
-
-
Save Saad5400/032e0ee566812449e08e0aa84cf5fc24 to your computer and use it in GitHub Desktop.
A script to rename all the static "left" and "right" classes to logical "start" and "end"
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Script: rename-tailwind-static-to-logical.sh | |
# Purpose: Renames Tailwind CSS static direction classes (e.g., left-*, right-*, pl-*, pr-*) to logical direction classes (e.g., start-*, end-*, ps-*, pe-*) and | |
# replaces matching w-* h-* pairs (e.g., w-4 h-4 or h-4 w-4) with size-* (e.g., size-4) in project files. | |
# Supports Tailwind CSS v4.0+ logical properties and size utilities for RTL compatibility and concise styling. | |
# | |
# Usage: | |
# 1. Save this script as `rename-tailwind-static-to-logical.sh`. | |
# 2. Make it executable: | |
# chmod +x rename-tailwind-static-to-logical.sh | |
# 3. Run in dry-run mode to preview changes (no files modified): | |
# ./rename-tailwind-static-to-logical.sh [directory] true | |
# Example: ./rename-tailwind-static-to-logical.sh src true | |
# 4. Run to apply changes: | |
# ./rename-tailwind-static-to-logical.sh [directory] | |
# Example: ./rename-tailwind-static-to-logical.sh src | |
# | |
# Notes: | |
# - Default directory is `src` if not specified. | |
# - Processes files with extensions: html, js, jsx, ts, tsx, vue, svelte, astro. | |
# - Excludes node_modules, dist, and build directories. | |
# - Always back up your project or use version control before running. | |
# - Test in RTL mode (<html dir="rtl">) to verify logical properties. | |
# - For dynamic classes (e.g., pl-${size} or w-${size}), update logic manually. | |
# - On macOS, install GNU sed for better compatibility: brew install gnu-sed | |
# - Handles w-N h-N or h-N w-N pairs with matching values (e.g., w-4 h-4 → size-4). | |
# Define the directory to search for files (default: src) | |
SEARCH_DIR="${1:-src}" | |
# Dry-run option (set to true for preview, false to apply changes) | |
DRY_RUN="${2:-false}" | |
# Define file extensions to process | |
FILE_EXTENSIONS="html,js,jsx,ts,tsx,vue,svelte,astro" | |
# Definereplacement mappings for static to logical classes | |
declare -A DIRECTION_REPLACEMENTS=( | |
["\\bleft-([0-9]+|auto|full)\\b"]="start-\1" | |
["\\bright-([0-9]+|auto|full)\\b"]="end-\1" | |
["\\bpl-([0-9]+|auto)\\b"]="ps-\1" | |
["\\bpr-([0-9]+|auto)\\b"]="pe-\1" | |
["\\bml-([0-9]+|auto)\\b"]="ms-\1" | |
["\\bmr-([0-9]+|auto)\\b"]="me-\1" | |
["\\bborder-l-([0-9]+)\\b"]="border-s-\1" | |
["\\bborder-r-([0-9]+)\\b"]="border-e-\1" | |
["\\btext-left\\b"]="text-start" | |
["\\btext-right\\b"]="text-end" | |
["\\bfloat-left\\b"]="float-start" | |
["\\bfloat-right\\b"]="float-end" | |
["\\bclear-left\\b"]="clear-start" | |
["\\bclear-right\\b"]="clear-end" | |
) | |
# Define patterns for w-* and h-* to size-* replacements | |
# Matches w-N h-N or h-N w-N where N is the same value (e.g., w-4 h-4 or h-4 w-4) | |
declare -A SIZE_REPLACEMENTS=( | |
["\\bw-([0-9]+|auto|full)\\b.*\\bh-\1\\b"]="size-\1" | |
["\\bh-([0-9]+|auto|full)\\b.*\\bw-\1\\b"]="size-\1" | |
) | |
# Check if SEARCH_DIR exists | |
if [ ! -d "$SEARCH_DIR" ]; then | |
echo "Error: Directory $SEARCH_DIR does not exist." | |
exit 1 | |
fi | |
# Detect sed version (GNU or BSD) | |
SED=$(command -v sed) | |
if [[ "$OSTYPE" == "darwin"* ]]; then | |
# macOS: Use -E for extended regex | |
SED_FLAG="-E" | |
else | |
# Linux: Use -r for extended regex | |
SED_FLAG="-r" | |
fi | |
# Find files with specified extensions, excluding node_modules, dist, and build | |
FILES=$(find "$SEARCH_DIR" -type f \( -name "*.html" -o -name "*.js" -o -name "*.jsx" -o -name "*.ts" -o -name "*.tsx" -o -name "*.vue" -o -name "*.svelte" -o -name "*.astro" \) ! -path "*/node_modules/*" ! -path "*/dist/*" ! -path "*/build/*") | |
# Check if any files were found | |
if [ -z "$FILES" ]; then | |
echo "No files found with extensions: $FILE_EXTENSIONS" | |
exit 0 | |
fi | |
# Process each file | |
for FILE in $FILES; do | |
MODIFIED=false | |
# Create a temporary file | |
TEMP_FILE=$(mktemp) | |
# Copy original file to temp | |
cp "$FILE" "$TEMP_FILE" | |
# First pass: Apply direction replacements | |
for PATTERN in "${!DIRECTION_REPLACEMENTS[@]}"; do | |
REPLACEMENT="${DIRECTION_REPLACEMENTS[$PATTERN]}" | |
if grep -Eq "$PATTERN" "$FILE"; then | |
$SED $SED_FLAG "s/$PATTERN/$REPLACEMENT/g" "$TEMP_FILE" > "${TEMP_FILE}.tmp" 2>/dev/null | |
if [ $? -eq 0 ]; then | |
mv "${TEMP_FILE}.tmp" "$TEMP_FILE" | |
MODIFIED=true | |
else | |
echo "Error: Failed to apply direction replacement for pattern '$PATTERN' in $FILE" | |
rm "${TEMP_FILE}.tmp" 2>/dev/null | |
rm "$TEMP_FILE" 2>/dev/null | |
continue | |
fi | |
fi | |
done | |
# Second pass: Apply size replacements | |
for PATTERN in "${!SIZE_REPLACEMENTS[@]}"; do | |
REPLACEMENT="${SIZE_REPLACEMENTS[$PATTERN]}" | |
if grep -Eq "$PATTERN" "$FILE"; then | |
$SED $SED_FLAG "s/$PATTERN/$REPLACEMENT/g" "$TEMP_FILE" > "${TEMP_FILE}.tmp" 2>/dev/null | |
if [ $? -eq 0 ]; then | |
mv "${TEMP_FILE}.tmp" "$TEMP_FILE" | |
MODIFIED=true | |
else | |
echo "Error: Failed to apply size replacement for pattern '$PATTERN' in $FILE" | |
rm "${TEMP_FILE}.tmp" 2>/dev/null | |
rm "$TEMP_FILE" 2>/dev/null | |
continue | |
fi | |
fi | |
done | |
# If dry-run, show diff and skip writing | |
if [ "$DRY_RUN" = "true" ]; then | |
if [ "$MODIFIED" = "true" ]; then | |
echo "Changes for $FILE:" | |
diff -u "$FILE" "$TEMP_FILE" || true | |
fi | |
rm "$TEMP_FILE" 2>/dev/null | |
# If not dry-run and modified, overwrite original | |
elif [ "$MODIFIED" = "true" ]; then | |
mv "$TEMP_FILE" "$FILE" | |
echo "Updated: $FILE" | |
else | |
rm "$TEMP_FILE" 2>/dev/null | |
fi | |
done | |
echo "Class renaming complete." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment