# pattern_scanner


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

## Data Structures

Define data structures for pattern scanning:

------------------------------------------------------------------------

### ClsPattern

``` python

def ClsPattern(
    line_number:int, full_expression:str, css_classes:List, context:str, uses_combine_classes:bool
)->None:

```

*Represents a cls= pattern found in code.*

## AST Pattern Finder

Use Python’s AST to find cls= patterns in code:

------------------------------------------------------------------------

### ClsPatternVisitor

``` python

def ClsPatternVisitor(
    source_lines:List, # Source code lines for extracting context around patterns
):

```

*AST visitor to find cls= patterns in Python code.*

## Pattern Scanning Functions

Main functions to scan code for patterns:

------------------------------------------------------------------------

### scan_python_code

``` python

def scan_python_code(
    code:str, # Python source code as a string
)->List: # List of ClsPattern objects found in the code

```

*Scan Python code for cls= patterns.*

## Enhanced CSS Class Extraction

More sophisticated extraction handling different patterns:

------------------------------------------------------------------------

### extract_css_classes_from_node

``` python

def extract_css_classes_from_node(
    node:AST, # AST node to extract CSS classes from
)->List: # List of CSS class strings found in the node

```

*Recursively extract CSS classes from an AST node. Handles various
patterns including combine_classes calls.*

## Testing Pattern Extraction

Let’s test with the example code from your description:

``` python
# Test with your example code
test_code = '''
from fasthtml.common import Div, Header, Nav, Main, Article, Aside, Footer, Img, Button, H1, H2, P

# Flexbox centered navigation
nav = Nav(
    Div("Logo", cls="font-bold"),
    Div(
        "Home", "About", "Contact",
        cls=combine_classes("flex", gap(4))
    ),
    Button("Sign In"),
    cls=combine_classes(
        "flex", 
        justify.between, 
        items.center, 
        "px-6", 
        "py-4", "items-center"
    )
)
'''

# Scan the code
patterns = scan_python_code(test_code)

# Display results
print(f"Found {len(patterns)} cls= patterns:\n")
for i, pattern in enumerate(patterns, 1):
    print(f"Pattern {i}:")
    print(f"  Line: {pattern.line_number}")
    print(f"  Expression: {pattern.full_expression}")
    print(f"  Uses combine_classes: {pattern.uses_combine_classes}")
    print(f"  CSS Classes: {pattern.css_classes}")
    print(f"  Context: {pattern.context}")
    print()
```

    Found 3 cls= patterns:

    Pattern 1:
      Line: 12
      Expression: combine_classes('flex', justify.between, items.center, 'px-6', 'py-4', 'items-center')
      Uses combine_classes: True
      CSS Classes: ['flex', 'px-6', 'py-4', 'items-center']
      Context: cls=combine_classes(

    Pattern 2:
      Line: 6
      Expression: 'font-bold'
      Uses combine_classes: False
      CSS Classes: ['font-bold']
      Context: Div("Logo", cls="font-bold"),

    Pattern 3:
      Line: 9
      Expression: combine_classes('flex', gap(4))
      Uses combine_classes: True
      CSS Classes: ['flex']
      Context: cls=combine_classes("flex", gap(4))

``` python
# Test with various patterns
test_cases = '''
# Simple string
div1 = Div(cls="flex items-center justify-between")

# Multiple classes in one string
div2 = Div(cls="bg-blue-500 text-white px-4 py-2 rounded-lg")

# String concatenation
div3 = Div(cls="flex " + "items-center")

# Empty cls
div4 = Div(cls="")

# combine_classes with mixed content
div5 = Div(cls=combine_classes(
    "absolute",
    "top-0",
    p(4),  # This is already using the library
    "bg-white"
))
'''

patterns = scan_python_code(test_cases)
print(f"Found {len(patterns)} patterns in test cases:\n")

for i, pattern in enumerate(patterns, 1):
    print(f"Pattern {i}: Line {pattern.line_number}")
    print(f"  CSS Classes: {pattern.css_classes}")
    print(f"  Expression: {pattern.full_expression}")
    print()
```

    Found 5 patterns in test cases:

    Pattern 1: Line 3
      CSS Classes: ['flex', 'items-center', 'justify-between']
      Expression: 'flex items-center justify-between'

    Pattern 2: Line 6
      CSS Classes: ['bg-blue-500', 'text-white', 'px-4', 'py-2', 'rounded-lg']
      Expression: 'bg-blue-500 text-white px-4 py-2 rounded-lg'

    Pattern 3: Line 9
      CSS Classes: ['flex', 'items-center']
      Expression: 'flex ' + 'items-center'

    Pattern 4: Line 12
      CSS Classes: []
      Expression: ''

    Pattern 5: Line 15
      CSS Classes: ['absolute', 'top-0', 'bg-white']
      Expression: combine_classes('absolute', 'top-0', p(4), 'bg-white')

## Display Utilities

Functions to display scan results:

------------------------------------------------------------------------

### display_patterns

``` python

def display_patterns(
    patterns:List, # List of ClsPattern objects to display
    show_context:bool=True, # Whether to show the code context
):

```

*Display found patterns in a formatted way.*

------------------------------------------------------------------------

### get_unique_css_classes

``` python

def get_unique_css_classes(
    patterns:List, # List of ClsPattern objects
)->Set: # Set of unique CSS class strings

```

*Extract all unique CSS classes from a list of patterns.*

``` python
# Test the display function with the original example
patterns = scan_python_code(test_code)
display_patterns(patterns)
```

    Found 3 cls= patterns:

    Pattern 1 (Line 12):
      Context: cls=combine_classes(
      Expression: combine_classes('flex', justify.between, items.center, 'px-6', 'py-4', 'items-center')
      ✓ Uses combine_classes
      CSS Classes (4):
        - flex
        - px-6
        - py-4
        - items-center

    Pattern 2 (Line 6):
      Context: Div("Logo", cls="font-bold"),
      Expression: 'font-bold'
      CSS Classes (1):
        - font-bold

    Pattern 3 (Line 9):
      Context: cls=combine_classes("flex", gap(4))
      Expression: combine_classes('flex', gap(4))
      ✓ Uses combine_classes
      CSS Classes (1):
        - flex

``` python
# Test extracting unique classes
all_patterns = scan_python_code(test_code) + scan_python_code(test_cases)
unique_classes = get_unique_css_classes(all_patterns)

print(f"Total unique CSS classes found: {len(unique_classes)}")
print("\nUnique classes:")
unique_classes
```

    Total unique CSS classes found: 14

    Unique classes:

    {'absolute',
     'bg-blue-500',
     'bg-white',
     'flex',
     'font-bold',
     'items-center',
     'justify-between',
     'px-4',
     'px-6',
     'py-2',
     'py-4',
     'rounded-lg',
     'text-white',
     'top-0'}

## Assertion Pattern Extraction

Extract patterns from test assertion statements:

------------------------------------------------------------------------

### AssertionPattern

``` python

def AssertionPattern(
    css_class:str, factory_expression:str, module_name:str, example_name:str
)->None:

```

*Represents a pattern extracted from a test assertion.*

------------------------------------------------------------------------

### get_available_css_classes

``` python

def get_available_css_classes(
    assertion_patterns:List, # List of assertion patterns from test examples
)->Set: # Set of unique CSS class strings available in the library

```

*Extract all unique CSS classes from assertion patterns. This handles
multi-class assertion strings by splitting them.*

------------------------------------------------------------------------

### extract_assertion_patterns

``` python

def extract_assertion_patterns(
    source_code:str, # Source code of the test function
    module_name:str, # Name of the module containing the test
    example_name:str, # Name of the test function
)->List: # List of AssertionPattern objects

```

*Extract assertion patterns from test example source code.*

------------------------------------------------------------------------

### collect_all_assertion_patterns

``` python

def collect_all_assertion_patterns(
    
)->List: # List of AssertionPattern objects from all modules

```

*Collect assertion patterns from all test examples in the library.*

``` python
assertion_patterns = collect_all_assertion_patterns()
assertion_classes = get_available_css_classes(assertion_patterns)
list(assertion_classes)[:20]
```

    ['snap-mandatory',
     'break-normal',
     '-hue-rotate-60',
     'shadow-zinc-500',
     'select-all',
     'transition-none',
     '-mask-linear-180',
     'inset-ring-green-500',
     'opacity-95',
     'col-span-full',
     'text-6xl',
     'decoration-yellow-500',
     'inset-ring-green-950',
     'drop-shadow-black',
     'row-start-2',
     'fill-white',
     'align-top',
     'rounded-s-lg',
     '-mask-linear-45',
     'p-0']

## Pattern Matching

Functions to match extracted CSS classes against available library
classes:

------------------------------------------------------------------------

### CSSClassMatch

``` python

def CSSClassMatch(
    css_class:str, match_type:MatchType, matched_pattern:Optional=None, similar_classes:List=None,
    suggested_replacement:Optional=None
)->None:

```

*Represents a match result for a CSS class.*

------------------------------------------------------------------------

### MatchType

``` python

def MatchType(
    args:VAR_POSITIONAL, kwds:VAR_KEYWORD
):

```

*Type of match found for a CSS class.*

------------------------------------------------------------------------

### tokenize_css_class

``` python

def tokenize_css_class(
    css_class:str, # CSS class string (e.g., "bg-blue-500" or "hover:text-white")
)->List: # List of tokens (e.g., ["bg", "blue", "500"] or ["hover:text", "white"])

```

*Tokenize a CSS class by splitting on hyphens. Handles modifiers
(hover:, focus:, etc.) separately.*

------------------------------------------------------------------------

### find_pattern_matches

``` python

def find_pattern_matches(
    css_class:str, # CSS class to match (e.g., "px-8" or "hover:text-white")
    available_classes:Set, # Set of available CSS classes from the library
)->Tuple: # Tuple of (matched_pattern, similar_classes) - matched_pattern: Pattern prefix that matches (e.g., "px" for "px-8") - similar_classes: List of similar classes with the same pattern

```

*Find pattern matches for a CSS class by progressively reducing tokens.*

------------------------------------------------------------------------

### match_css_class

``` python

def match_css_class(
    css_class:str, # CSS class to match
    available_classes:Set, # Set of available CSS classes from the library
)->CSSClassMatch: # CSSClassMatch object with match details

```

*Match a CSS class against available library classes.*

------------------------------------------------------------------------

### match_css_classes

``` python

def match_css_classes(
    css_classes:List, # List of CSS classes to match
    available_classes:Set, # Set of available CSS classes from the library
)->Dict: # Dictionary mapping CSS classes to their match results

```

*Match multiple CSS classes against available library classes.*

------------------------------------------------------------------------

### display_match_results

``` python

def display_match_results(
    matches:Dict, # Dictionary of CSS classes to their match results
):

```

*Display match results in a formatted way.*

------------------------------------------------------------------------

### analyze_code_patterns

``` python

def analyze_code_patterns(
    code:str, # Python source code to analyze
)->Dict: # Dictionary with analysis results including patterns found and suggestions

```

*Analyze Python code for replaceable CSS patterns.*

------------------------------------------------------------------------

### display_code_analysis

``` python

def display_code_analysis(
    code:str, # Python source code to analyze
):

```

*Analyze and display replaceable patterns in Python code.*

## Migration Suggestions

Functions to provide migration suggestions based on test examples:

------------------------------------------------------------------------

### find_assertion_for_class

``` python

def find_assertion_for_class(
    css_class:str, # The CSS class to find (e.g., "px-6")
    assertion_patterns:List, # List of all assertion patterns from tests
)->Optional: # AssertionPattern if found, None otherwise

```

*Find the assertion pattern that demonstrates how to use a specific CSS
class. Prioritizes exact single-class matches over multi-class
assertions.*

------------------------------------------------------------------------

### find_pattern_examples

``` python

def find_pattern_examples(
    pattern_prefix:str, # Pattern prefix to match (e.g., "px" for px-* pattern)
    assertion_patterns:List, # List of all assertion patterns from tests
)->List: # List of AssertionPattern objects that match the pattern

```

*Find assertion examples that match a pattern prefix.*

------------------------------------------------------------------------

### get_migration_suggestions

``` python

def get_migration_suggestions(
    matches:Dict, # Dictionary of CSS class matches
    assertion_patterns:List, # List of all assertion patterns from tests
    config:Optional=None, # Optional configuration
)->Dict: # Dictionary mapping CSS classes to their migration suggestions

```

*Generate migration suggestions for matched CSS classes.*

------------------------------------------------------------------------

### display_migration_suggestions

``` python

def display_migration_suggestions(
    code:str, # Python source code to analyze
):

```

*Analyze code and display migration suggestions.*

------------------------------------------------------------------------

### analyze_and_suggest

``` python

def analyze_and_suggest(
    code:str, # Python source code to analyze
):

```

*Perform complete analysis of code with migration suggestions.*

## Testing Pattern Matching

Test the matching logic with various CSS classes:

``` python
# Test updated tokenization
print("Testing updated tokenization:")
test_classes = [
    "flex", 
    "px-6", 
    "bg-blue-500", 
    "-mt-4", 
    "hover:text-white",
    "lg:grid-cols-4",
    "focus:ring-2",
    "hover:bg-blue-600"
]
for cls in test_classes:
    tokens = tokenize_css_class(cls)
    print(f"  {cls:<20} → {tokens}")
```

    Testing updated tokenization:
      flex                 → ['flex']
      px-6                 → ['px', '6']
      bg-blue-500          → ['bg', 'blue', '500']
      -mt-4                → ['-mt', '4']
      hover:text-white     → ['hover:', 'text', 'white']
      lg:grid-cols-4       → ['lg:', 'grid', 'cols', '4']
      focus:ring-2         → ['focus:', 'ring', '2']
      hover:bg-blue-600    → ['hover:', 'bg', 'blue', '600']

``` python
# Get available classes from assertions
assertion_patterns = collect_all_assertion_patterns()
available_classes = get_available_css_classes(assertion_patterns)

# Test with the example from the original test code
test_css_classes = ["flex", "font-bold", "items-center", "px-6", "py-4"]

print("\nTesting CSS class matching:")
print("=" * 60)

for css_class in test_css_classes:
    match_result = match_css_class(css_class, available_classes)
    
    print(f"\nClass: '{css_class}'")
    print(f"  Match Type: {match_result.match_type.value}")
    
    if match_result.match_type == MatchType.EXACT:
        print(f"  ✓ Exact match found")
    elif match_result.match_type == MatchType.PATTERN:
        print(f"  ~ Pattern match: '{match_result.matched_pattern}-*'")
        print(f"  Similar classes: {match_result.similar_classes[:3]}...")
    else:
        print(f"  ✗ No match found")
```


    Testing CSS class matching:
    ============================================================

    Class: 'flex'
      Match Type: exact
      ✓ Exact match found

    Class: 'font-bold'
      Match Type: exact
      ✓ Exact match found

    Class: 'items-center'
      Match Type: exact
      ✓ Exact match found

    Class: 'px-6'
      Match Type: exact
      ✓ Exact match found

    Class: 'py-4'
      Match Type: exact
      ✓ Exact match found

``` python
# Test with more diverse CSS classes
print("\nTesting with additional CSS classes:")
print("=" * 60)

additional_test_classes = [
    # Should be exact matches
    "block", "absolute", "flex",
    # Should be pattern matches
    "px-8", "py-12", "mt-16", "gap-10", 
    # Should be no match
    "font-bold", "text-blue-600", "hover:bg-gray-100",
    # Edge cases
    "-mx-4", "w-1/3", "lg:grid-cols-4"
]

for css_class in additional_test_classes:
    match_result = match_css_class(css_class, available_classes)
    
    status = "✓" if match_result.match_type == MatchType.EXACT else \
             "~" if match_result.match_type == MatchType.PATTERN else "✗"
    
    print(f"{status} {css_class:<20} → {match_result.match_type.value:<10}", end="")
    
    if match_result.matched_pattern:
        print(f" (pattern: {match_result.matched_pattern})")
    else:
        print()
```


    Testing with additional CSS classes:
    ============================================================
    ✓ block                → exact     
    ✓ absolute             → exact     
    ✓ flex                 → exact     
    ✓ px-8                 → exact     
    ~ py-12                → pattern    (pattern: py)
    ~ mt-16                → pattern    (pattern: mt)
    ~ gap-10               → pattern    (pattern: gap)
    ✓ font-bold            → exact     
    ~ text-blue-600        → pattern    (pattern: text-blue)
    ✗ hover:bg-gray-100    → no_match  
    ~ -mx-4                → pattern    (pattern: -mx)
    ~ w-1/3                → pattern    (pattern: w)
    ✓ lg:grid-cols-4       → exact     

``` python
# Test batch matching with the original example
print("\nBatch matching for original example:")
print("=" * 60)

# Extract unique CSS classes from the test code
patterns = scan_python_code(test_code)
unique_classes_in_code = get_unique_css_classes(patterns)

# Match all classes
matches = match_css_classes(list(unique_classes_in_code), available_classes)

# Display results
display_match_results(matches)
```


    Batch matching for original example:
    ============================================================
    CSS Class Analysis Results:
    ============================================================

    ✓ Exact Matches (5):
      - flex
      - font-bold
      - items-center
      - px-6
      - py-4

    Summary: 5/5 classes are potentially replaceable

``` python
# Test complete code analysis
print("Complete Code Analysis:")
print()
display_code_analysis(test_code)
```

    Complete Code Analysis:

    Code Analysis Report
    ============================================================
    Total cls= patterns found: 3
    Unique CSS classes: 5

    Replaceable Classes: 5/5
      - Exact matches: 5
      - Pattern matches: 0
      - No matches: 0

    CSS Class Analysis Results:
    ============================================================

    ✓ Exact Matches (5):
      - flex
      - font-bold
      - items-center
      - px-6
      - py-4

    Summary: 5/5 classes are potentially replaceable

    Patterns by Line:
    ------------------------------------------------------------
    Line 12: ✓ combine_classes('flex', justify.between, items.center, 'px-6', 'py-4', 'items-center')
             ↳ Already uses combine_classes
    Line 6: ✓ 'font-bold'
    Line 9: ✓ combine_classes('flex', gap(4))
             ↳ Already uses combine_classes

``` python
# Test with a more complex example
complex_example = '''
from fasthtml.common import Div, Button, Section

# Hero section with various utilities
hero = Section(
    Div(
        "Welcome to our site",
        cls="text-6xl font-bold text-gray-900 mb-4"
    ),
    Div(
        "Build amazing things with FastHTML",
        cls="text-xl text-gray-600 mb-8"
    ),
    Button(
        "Get Started",
        cls="px-8 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
    ),
    cls="flex flex-col items-center justify-center min-h-screen px-4"
)
'''

print("\n\nComplex Example Analysis:")
print()
display_code_analysis(complex_example)
```



    Complex Example Analysis:

    Code Analysis Report
    ============================================================
    Total cls= patterns found: 4
    Unique CSS classes: 19

    Replaceable Classes: 18/19
      - Exact matches: 12
      - Pattern matches: 6
      - No matches: 1

    CSS Class Analysis Results:
    ============================================================

    ✓ Exact Matches (12):
      - flex
      - flex-col
      - font-bold
      - items-center
      - justify-center
      - mb-4
      - min-h-screen
      - px-8
      - rounded-lg
      - text-6xl
      - text-white
      - text-xl

    ~ Pattern Matches (6):
      - bg-blue-600 → matches pattern 'bg-blue-*'
        Examples: bg-blue-300, bg-blue-300/75, bg-blue-500
      - mb-8 → matches pattern 'mb-*'
        Examples: mb-4
      - px-4 → matches pattern 'px-*'
        Examples: px-6, px-8
      - py-3 → matches pattern 'py-*'
        Examples: py-4, py-8
      - text-gray-600 → matches pattern 'text-gray-*'
        Examples: text-gray-500
      - text-gray-900 → matches pattern 'text-gray-*'
        Examples: text-gray-500

    ✗ No Matches (1):
      - hover:bg-blue-700

    Summary: 18/19 classes are potentially replaceable

    Patterns by Line:
    ------------------------------------------------------------
    Line 18: ✓ 'flex flex-col items-center justify-center min-h-screen px-4'
    Line 8: ✓ 'text-6xl font-bold text-gray-900 mb-4'
    Line 12: ✓ 'text-xl text-gray-600 mb-8'
    Line 16: ✓ 'px-8 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700'

``` python
# Test migration suggestions with original example
print("Migration Suggestions for Original Example:")
print()
display_migration_suggestions(test_code)
```

    Migration Suggestions for Original Example:

    Migration Suggestions
    ============================================================

    ✓ flex:
      → View example: cjm-tailwind-explore example flexbox_and_grid display

    ✓ font-bold:
      → View example: cjm-tailwind-explore example typography font_weight

    ✓ items-center:
      → View example: cjm-tailwind-explore example flexbox_and_grid align

    ✓ px-6:
      → View example: cjm-tailwind-explore example spacing helper
      → View helper: cjm-tailwind-explore helper spacing pad

    ✓ py-4:
      → View example: cjm-tailwind-explore example spacing helper
      → View helper: cjm-tailwind-explore helper spacing pad

``` python
# Test with complex example
print("\n\nMigration Suggestions for Complex Example:")
print()
display_migration_suggestions(complex_example)
```



    Migration Suggestions for Complex Example:

    Migration Suggestions
    ============================================================

    ~ bg-blue-600:
      → Pattern example 1: cjm-tailwind-explore example backgrounds color
      → Pattern example 2: cjm-tailwind-explore example backgrounds opacity

    ✓ flex:
      → View example: cjm-tailwind-explore example flexbox_and_grid display

    ✓ flex-col:
      → View example: cjm-tailwind-explore example flexbox_and_grid direction

    ✓ font-bold:
      → View example: cjm-tailwind-explore example typography font_weight

    ✓ items-center:
      → View example: cjm-tailwind-explore example flexbox_and_grid align

    ✓ justify-center:
      → View example: cjm-tailwind-explore example flexbox_and_grid justify

    ✓ mb-4:
      → View example: cjm-tailwind-explore example spacing margin_directional

    ~ mb-8:
      → Pattern example 1: cjm-tailwind-explore example spacing margin_directional

    ✓ min-h-screen:
      → View example: cjm-tailwind-explore example sizing min_height

    ~ px-4:
      → Pattern example 1: cjm-tailwind-explore example spacing directional
      → Pattern example 2: cjm-tailwind-explore example spacing helper

    ✓ px-8:
      → View example: cjm-tailwind-explore example spacing directional

    ~ py-3:
      → Pattern example 1: cjm-tailwind-explore example spacing directional
      → Pattern example 2: cjm-tailwind-explore example spacing helper

    ✓ rounded-lg:
      → View example: cjm-tailwind-explore example borders radius

    ✓ text-6xl:
      → View example: cjm-tailwind-explore example typography font_size

    ~ text-gray-600:
      → Pattern example 1: cjm-tailwind-explore example typography text_color

    ~ text-gray-900:
      → Pattern example 1: cjm-tailwind-explore example typography text_color

    ✓ text-white:
      → View example: cjm-tailwind-explore example typography text_color

    ✓ text-xl:
      → View example: cjm-tailwind-explore example typography font_size

``` python
# Test analysis and migration suggestions with original example
print("Analysis & Migration Suggestions for Original Example:")
print()
analyze_and_suggest(test_code)
```

    Analysis & Migration Suggestions for Original Example:

    Code Analysis Report
    ============================================================
    Total cls= patterns found: 3
    Unique CSS classes: 5

    Replaceable Classes: 5/5
      - Exact matches: 5
      - Pattern matches: 0
      - No matches: 0

    CSS Class Analysis Results:
    ============================================================

    ✓ Exact Matches (5):
      - flex
      - font-bold
      - items-center
      - px-6
      - py-4

    Summary: 5/5 classes are potentially replaceable

    Patterns by Line:
    ------------------------------------------------------------
    Line 12: ✓ combine_classes('flex', justify.between, items.center, 'px-6', 'py-4', 'items-center')
             ↳ Already uses combine_classes
    Line 6: ✓ 'font-bold'
    Line 9: ✓ combine_classes('flex', gap(4))
             ↳ Already uses combine_classes


    Migration Suggestions
    ============================================================

    ✓ flex:
      → View example: cjm-tailwind-explore example flexbox_and_grid display

    ✓ font-bold:
      → View example: cjm-tailwind-explore example typography font_weight

    ✓ items-center:
      → View example: cjm-tailwind-explore example flexbox_and_grid align

    ✓ px-6:
      → View example: cjm-tailwind-explore example spacing helper
      → View helper: cjm-tailwind-explore helper spacing pad

    ✓ py-4:
      → View example: cjm-tailwind-explore example spacing helper
      → View helper: cjm-tailwind-explore helper spacing pad

## File Input Support

Functions to scan Python files and Jupyter notebooks:

------------------------------------------------------------------------

### scan_python_file

``` python

def scan_python_file(
    file_path:str, # Path to the Python file
)->List: # List of ClsPattern objects found in the file

```

*Scan a Python file for cls= patterns.*

------------------------------------------------------------------------

### scan_jupyter_notebook

``` python

def scan_jupyter_notebook(
    notebook_path:str, # Path to the Jupyter notebook (.ipynb)
)->List: # List of ClsPattern objects found in the notebook

```

*Scan a Jupyter notebook for cls= patterns.*

------------------------------------------------------------------------

### detect_input_type

``` python

def detect_input_type(
    input_source:str, # Code string or file path
)->InputType: # InputType enum value

```

*Detect the type of input based on the source string.*

------------------------------------------------------------------------

### InputType

``` python

def InputType(
    args:VAR_POSITIONAL, kwds:VAR_KEYWORD
):

```

*Type of input being scanned.*

------------------------------------------------------------------------

### scan_input

``` python

def scan_input(
    input_source:str, # Code string, Python file path, or notebook path
    input_type:Optional=None, # Optional explicit input type. If None, will auto-detect.
)->List: # List of ClsPattern objects found

```

*Scan various input types for cls= patterns.*

------------------------------------------------------------------------

### analyze_input

``` python

def analyze_input(
    input_source:str, # Code string, Python file path, or notebook path
    input_type:Optional=None, # Optional explicit input type. If None, will auto-detect.
)->Dict: # Dictionary with analysis results

```

*Analyze any input type for replaceable CSS patterns.*

------------------------------------------------------------------------

### display_input_analysis

``` python

def display_input_analysis(
    input_source:str, # Code string, Python file path, or notebook path
    input_type:Optional=None, # Optional explicit input type. If None, will auto-detect.
):

```

*Analyze and display replaceable patterns from any input type.*

------------------------------------------------------------------------

### analyze_and_suggest_input

``` python

def analyze_and_suggest_input(
    input_source:str, # Code string, Python file path, or notebook path
    input_type:Optional=None, # Optional explicit input type. If None, will auto-detect.
):

```

*Perform complete analysis with migration suggestions for any input
type.*

## Testing File Input Support

Test the unified interface with different input types:

``` python
# Test auto-detection of input types
test_inputs = [
    'print("hello")',  # Code string
    'example.py',      # Python file
    'notebook.ipynb',  # Jupyter notebook
    '/path/to/file.py',  # Full path
    'Some("code", cls="flex")'  # Code with cls
]

print("Testing input type detection:")
for inp in test_inputs:
    detected = detect_input_type(inp)
    print(f"  '{inp}' → {detected.value}")
```

    Testing input type detection:
      'print("hello")' → code
      'example.py' → python_file
      'notebook.ipynb' → notebook
      '/path/to/file.py' → python_file
      'Some("code", cls="flex")' → code

``` python
# Test unified scanning interface with code string
print("Testing unified scan_input with code string:")
print("=" * 60)

test_code_unified = '''
from fasthtml.common import Div

card = Div(
    Div("Title", cls="text-2xl font-semibold mb-4"),
    Div("Content", cls="text-gray-700"),
    cls="p-6 bg-white rounded-lg shadow-md"
)
'''

patterns = scan_input(test_code_unified)
print(f"Found {len(patterns)} patterns")
for pattern in patterns:
    print(f"  Line {pattern.line_number}: {pattern.css_classes}")
```

``` python
# Create a temporary Python file for testing
import tempfile

test_py_content = '''
from fasthtml.common import *

def create_navbar():
    return Nav(
        Div("Logo", cls="font-bold text-xl"),
        Ul(
            Li("Home", cls="px-4 py-2"),
            Li("About", cls="px-4 py-2"),
            Li("Contact", cls="px-4 py-2"),
            cls="flex gap-4"
        ),
        cls="flex justify-between items-center p-4 bg-gray-100"
    )
'''

# Write to temporary file
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
    f.write(test_py_content)
    temp_py_file = f.name

print(f"Testing Python file scanning:")
print(f"Temporary file: {temp_py_file}")
print("=" * 60)

# Scan the Python file
patterns = scan_input(temp_py_file)
print(f"Found {len(patterns)} patterns")
for pattern in patterns:
    print(f"  Line {pattern.line_number}: {pattern.css_classes}")

# Clean up
import os
os.unlink(temp_py_file)
```

    Testing Python file scanning:
    Temporary file: /tmp/tmpee2b37ob.py
    ============================================================
    Found 6 patterns
      Line 13: ['flex', 'justify-between', 'items-center', 'p-4', 'bg-gray-100']
      Line 6: ['font-bold', 'text-xl']
      Line 11: ['flex', 'gap-4']
      Line 8: ['px-4', 'py-2']
      Line 9: ['px-4', 'py-2']
      Line 10: ['px-4', 'py-2']

``` python
# Test complete analysis with code string
print("\nTesting complete analysis with display_input_analysis:")
print()
display_input_analysis(test_code)
```


    Testing complete analysis with display_input_analysis:

    Pattern Analysis Report
    ============================================================
    Input Type: code
    Source: 
    from fasthtml.common import Div, Header, Nav, Mai...
    Total cls= patterns found: 3
    Unique CSS classes: 5

    Replaceable Classes: 5/5
      - Exact matches: 5
      - Pattern matches: 0
      - No matches: 0

    CSS Class Analysis Results:
    ============================================================

    ✓ Exact Matches (5):
      - flex
      - font-bold
      - items-center
      - px-6
      - py-4

    Summary: 5/5 classes are potentially replaceable

    Patterns by Location:
    ------------------------------------------------------------
    Line 12: ✓ combine_classes('flex', justify.between, items.center, 'px-6', 'py-4', 'items-center')
             ↳ Already uses combine_classes
    Line 6: ✓ 'font-bold'
    Line 9: ✓ combine_classes('flex', gap(4))
             ↳ Already uses combine_classes

``` python
# Test with suggestions
print("\nTesting analysis with suggestions:")
print()
analyze_and_suggest_input(test_code_unified)
```


    Testing analysis with suggestions:

    Pattern Analysis Report
    ============================================================
    Input Type: code
    Source: 
    from fasthtml.common import Div, Card

    card = Car...
    Total cls= patterns found: 3
    Unique CSS classes: 8

    Replaceable Classes: 8/8
      - Exact matches: 6
      - Pattern matches: 2
      - No matches: 0

    CSS Class Analysis Results:
    ============================================================

    ✓ Exact Matches (6):
      - bg-white
      - font-semibold
      - mb-4
      - rounded-lg
      - shadow-md
      - text-2xl

    ~ Pattern Matches (2):
      - p-6 → matches pattern 'p-*'
        Examples: p-0, p-2.5, p-4
      - text-gray-700 → matches pattern 'text-gray-*'
        Examples: text-gray-500

    Summary: 8/8 classes are potentially replaceable

    Patterns by Location:
    ------------------------------------------------------------
    Line 7: ✓ 'p-6 bg-white rounded-lg shadow-md'
    Line 5: ✓ 'text-2xl font-semibold mb-4'
    Line 6: ✓ 'text-gray-700'


    Migration Suggestions
    ============================================================

    ✓ bg-white:
      → View example: cjm-tailwind-explore example backgrounds color

    ✓ font-semibold:
      → View example: cjm-tailwind-explore example typography font_weight

    ✓ mb-4:
      → View example: cjm-tailwind-explore example spacing margin_directional

    ~ p-6:
      → Pattern example 1: cjm-tailwind-explore example spacing basic
      → Pattern example 2: cjm-tailwind-explore example spacing helper

    ✓ rounded-lg:
      → View example: cjm-tailwind-explore example borders radius

    ✓ shadow-md:
      → View example: cjm-tailwind-explore example effects shadow_size

    ✓ text-2xl:
      → View example: cjm-tailwind-explore example typography font_size

    ~ text-gray-700:
      → Pattern example 1: cjm-tailwind-explore example typography text_color

## Export
