Files
HappyOnigiri-ComfyUI-Meld/check_scripts/check_unused_css.py
T

138 lines
6.1 KiB
Python

import os
import re
import sys
from utils import resolve_search_path
def get_defined_classes(search_path: str) -> dict[str, str]:
defined: dict[str, list[str]] = {}
ignored_classes: dict[str, set[int]] = {}
for root, _, files in os.walk(search_path):
for file in files:
if file.endswith(".css") and not file.endswith(".module.css"):
filepath = os.path.join(root, file)
try:
with open(filepath, encoding="utf-8") as f:
content = f.read()
def comment_replacer(match: re.Match[str]) -> str:
if "unused-css-check-ignore" in match.group(0):
return " /* unused-css-check-ignore */ "
return " " * len(match.group(0))
clean_content = re.sub(r"/\*.*?\*/", comment_replacer, content, flags=re.DOTALL)
ignore_next = False
for match in re.finditer(
r"(/[*]\s*unused-css-check-ignore\s*[*]/|\.meld-[a-zA-Z0-9_-]+|[{};])", clean_content
):
token = match.group(1)
if "unused-css-check-ignore" in token:
ignore_next = True
elif token in ("{", "}", ";"):
ignore_next = False
elif token.startswith(".meld-"):
class_name = token[1:]
if ignore_next:
ignored_classes.setdefault(class_name, set()).add(len(defined.get(class_name, [])))
# Do not reset ignore_next so grouped selectors all get ignored
defined.setdefault(class_name, []).append(filepath)
except OSError as e:
print(f"Error reading {filepath}: {e}")
sys.exit(1)
final_defined: dict[str, str] = {}
for c, occurrences in defined.items():
ignored_indices = ignored_classes.get(c, set())
unignored = [occ for i, occ in enumerate(occurrences) if i not in ignored_indices]
if unignored:
final_defined[c] = unignored[0]
return final_defined
def get_referenced_classes(search_path: str) -> set[str]:
references: set[str] = set()
styles_import_pattern = re.compile(r'import\s+(\w+)\s+from\s+["\'].*\.module\.css["\']')
for root, _, files in os.walk(search_path):
for file in files:
if file.endswith((".tsx", ".ts")):
filepath = os.path.join(root, file)
try:
with open(filepath, encoding="utf-8") as f:
content = f.read()
# 1. Handle CSS Module imports
style_vars = [m.group(1) for m in styles_import_pattern.finditer(content)]
for style_var in style_vars:
style_usage_pattern = re.compile(r"\b" + re.escape(style_var) + r"\.([a-zA-Z0-9_-]+)")
for match in style_usage_pattern.finditer(content):
references.add(match.group(1))
# 2. Extract classes from static strings
static_class_pattern = re.compile(r'className\s*=\s*["\']([^"\']+)["\']')
for match in static_class_pattern.finditer(content):
for cls in match.group(1).split():
references.add(cls)
# 3. Extract classes from template literals
expr_class_pattern = re.compile(r"className\s*=\s*{(.*?)}", re.DOTALL)
for match in expr_class_pattern.finditer(content):
expr = match.group(1)
for str_match in re.finditer(r'(["\'`])(.*?)\1', expr, re.DOTALL):
val = str_match.group(2)
val_clean = re.sub(r"\$\{[^}]+\}", " ", val)
for cls in val_clean.split():
references.add(cls)
# 4. Targeted extraction: search inside className usages
# to properly handle class names inside complex template literals or conditionals
for attr_match in re.finditer(
r'className\s*=\s*({(?:[^{}]|{(?:[^{}]|{[^{}]*})*})*}|(["\'`])[\s\S]*?\2)', content
):
attr_val = attr_match.group(1)
for str_match in re.finditer(r'(["\'`])(.*?)\1', attr_val, flags=re.DOTALL):
val = str_match.group(2)
for cls in re.finditer(r"\b(meld-[a-zA-Z0-9_-]+)\b", val):
references.add(cls.group(1))
except OSError as e:
print(f"Error reading {filepath}: {e}")
sys.exit(1)
return references
def main() -> None:
base_dir, target_dir, search_path = resolve_search_path()
print(f"Checking for unused CSS classes in {target_dir}...")
defined_classes = get_defined_classes(search_path)
referenced_classes = get_referenced_classes(search_path)
unused = []
for cls, filepath in defined_classes.items():
if cls not in referenced_classes:
unused.append((cls, filepath))
if unused:
print("\n[!] Unused CSS classes found:")
for cls, filepath in sorted(unused, key=lambda x: x[1]):
rel_path = os.path.relpath(filepath, base_dir)
print(f" {rel_path}: .{cls}")
print("\nError: Unused CSS classes detected!")
print("Please remove these classes, use them in your files, or add /* unused-css-check-ignore */ before them.")
sys.exit(1)
else:
print("CSS unused classes check passed.")
sys.exit(0)
if __name__ == "__main__":
main()