|
| 1 | +#!/usr/bin/env python3 |
| 2 | +""" |
| 3 | +Extract homepage-specific CSS from styles.css. |
| 4 | +This script identifies CSS rules that are only used in the homepage (index.html) |
| 5 | +and not in other pages (detail pages, skill pages). |
| 6 | +""" |
| 7 | + |
| 8 | +import re |
| 9 | +from pathlib import Path |
| 10 | + |
| 11 | +# Define paths |
| 12 | +PORTAL_DIR = Path("/Users/mdeachaval/labs/machaval/mulesoft/anypoint-public-api-specs/portal") |
| 13 | +STYLES_CSS = Path("/Users/mdeachaval/labs/machaval/mulesoft/anypoint-public-api-specs/scripts/portal_generator/assets/styles.css") |
| 14 | + |
| 15 | +def extract_classes_from_html(html_path): |
| 16 | + """Extract all CSS classes from an HTML file.""" |
| 17 | + classes = set() |
| 18 | + with open(html_path, 'r', encoding='utf-8') as f: |
| 19 | + content = f.read() |
| 20 | + # Find all class attributes |
| 21 | + class_matches = re.findall(r'class="([^"]*)"', content) |
| 22 | + for match in class_matches: |
| 23 | + # Split multiple classes |
| 24 | + classes.update(match.split()) |
| 25 | + return classes |
| 26 | + |
| 27 | +def get_css_selector_classes(selector): |
| 28 | + """Extract class names from a CSS selector.""" |
| 29 | + # Remove pseudo-classes and pseudo-elements |
| 30 | + selector = re.sub(r'::[a-z-]+', '', selector) |
| 31 | + selector = re.sub(r':[a-z-]+(\([^)]*\))?', '', selector) |
| 32 | + |
| 33 | + # Extract classes (.classname) |
| 34 | + classes = re.findall(r'\.([a-zA-Z0-9_-]+)', selector) |
| 35 | + return set(classes) |
| 36 | + |
| 37 | +def parse_css_rules(css_content): |
| 38 | + """Parse CSS and return list of (selector, rule_content) tuples.""" |
| 39 | + rules = [] |
| 40 | + |
| 41 | + # Remove comments |
| 42 | + css_content = re.sub(r'/\*.*?\*/', '', css_content, flags=re.DOTALL) |
| 43 | + |
| 44 | + # Find all CSS rules (selector { properties }) |
| 45 | + # This regex matches selectors and their corresponding rule blocks |
| 46 | + pattern = r'([^{}]+)\{([^{}]*)\}' |
| 47 | + matches = re.finditer(pattern, css_content) |
| 48 | + |
| 49 | + for match in matches: |
| 50 | + selector = match.group(1).strip() |
| 51 | + properties = match.group(2).strip() |
| 52 | + |
| 53 | + # Skip empty rules |
| 54 | + if not properties: |
| 55 | + continue |
| 56 | + |
| 57 | + # Skip @-rules (media queries, keyframes, etc.) |
| 58 | + if selector.startswith('@'): |
| 59 | + continue |
| 60 | + |
| 61 | + rules.append((selector, properties)) |
| 62 | + |
| 63 | + return rules |
| 64 | + |
| 65 | +def main(): |
| 66 | + print("Analyzing HTML files...") |
| 67 | + |
| 68 | + # Get classes from homepage template |
| 69 | + homepage_template = Path("/Users/mdeachaval/labs/machaval/mulesoft/anypoint-public-api-specs/scripts/portal_generator/templates/homepage.html") |
| 70 | + homepage_classes = extract_classes_from_html(homepage_template) |
| 71 | + print(f"Found {len(homepage_classes)} unique classes in homepage template") |
| 72 | + |
| 73 | + # Get classes from all other template files (detail pages, skills, operations, etc.) |
| 74 | + templates_dir = Path("/Users/mdeachaval/labs/machaval/mulesoft/anypoint-public-api-specs/scripts/portal_generator/templates") |
| 75 | + detail_classes = set() |
| 76 | + for html_file in templates_dir.rglob("*.html"): |
| 77 | + if html_file.name != "homepage.html": |
| 78 | + detail_classes.update(extract_classes_from_html(html_file)) |
| 79 | + |
| 80 | + print(f"Found {len(detail_classes)} unique classes in non-homepage templates") |
| 81 | + |
| 82 | + # Find homepage-only classes |
| 83 | + homepage_only = homepage_classes - detail_classes |
| 84 | + print(f"Found {len(homepage_only)} classes used ONLY in homepage") |
| 85 | + print(f"\nHomepage-only classes:") |
| 86 | + for cls in sorted(homepage_only): |
| 87 | + print(f" .{cls}") |
| 88 | + |
| 89 | + # Read CSS file |
| 90 | + print(f"\nReading {STYLES_CSS}...") |
| 91 | + with open(STYLES_CSS, 'r', encoding='utf-8') as f: |
| 92 | + css_content = f.read() |
| 93 | + |
| 94 | + # Parse CSS rules |
| 95 | + css_rules = parse_css_rules(css_content) |
| 96 | + print(f"Found {len(css_rules)} CSS rules") |
| 97 | + |
| 98 | + # Find rules that ONLY use homepage-only classes |
| 99 | + homepage_only_rules = [] |
| 100 | + for selector, properties in css_rules: |
| 101 | + selector_classes = get_css_selector_classes(selector) |
| 102 | + |
| 103 | + # If selector has classes and ALL of them are homepage-only |
| 104 | + if selector_classes and selector_classes.issubset(homepage_only): |
| 105 | + homepage_only_rules.append((selector, properties)) |
| 106 | + |
| 107 | + print(f"\nFound {len(homepage_only_rules)} rules that use ONLY homepage-specific classes") |
| 108 | + |
| 109 | + # Generate homepage-specific CSS |
| 110 | + homepage_css = "/* Homepage-specific styles */\n" |
| 111 | + homepage_css += "/* This file contains CSS rules used ONLY in index.html */\n\n" |
| 112 | + |
| 113 | + for selector, properties in homepage_only_rules: |
| 114 | + # Clean up properties - normalize whitespace |
| 115 | + props_lines = [line.strip() for line in properties.split('\n') if line.strip()] |
| 116 | + formatted_props = '\n '.join(props_lines) |
| 117 | + homepage_css += f"{selector} {{\n {formatted_props}\n}}\n\n" |
| 118 | + |
| 119 | + # Write to homepage.css |
| 120 | + output_path = STYLES_CSS.parent / "homepage.css" |
| 121 | + with open(output_path, 'w', encoding='utf-8') as f: |
| 122 | + f.write(homepage_css) |
| 123 | + |
| 124 | + print(f"\nWrote homepage-specific CSS to: {output_path}") |
| 125 | + print(f"Total rules extracted: {len(homepage_only_rules)}") |
| 126 | + |
| 127 | +if __name__ == "__main__": |
| 128 | + main() |
0 commit comments