# Meta Analysis

Template introspection functions for analyzing template dependencies and variable usage. Useful for dependency tracking, caching systems, and development tools.

## Capabilities

### Variable Analysis

Analyze templates to find all variables that will be looked up from the context at runtime.

```python { .api }
def find_undeclared_variables(ast):
    """
    Returns a set of all variables in the AST that will be looked up from
    the context at runtime.
    
    Because at compile time it's not known which variables will be used
    depending on the path the execution takes at runtime, all variables
    are returned.
    
    Parameters:
        ast: Template AST node from Environment.parse()
        
    Returns:
        set: Set of variable names that will be looked up from context
        
    Raises:
        TemplateAssertionError: During compilation if template is invalid
    """
```

### Template Dependency Analysis

Find all templates referenced by extends, includes, and imports in a template.

```python { .api }
def find_referenced_templates(ast):
    """
    Finds all the referenced templates from the AST.
    
    Returns an iterator over all the hardcoded template extensions, inclusions
    and imports. If dynamic inheritance or inclusion is used, None will be
    yielded for those entries.
    
    Parameters:
        ast: Template AST node from Environment.parse()
        
    Yields:
        str or None: Template names found, or None for dynamic references
    """
```

## Usage Examples

### Finding Undeclared Variables

```python
from jinja2 import Environment, meta

env = Environment()

# Simple template with variables
template_source = '{{ user.name }} has {{ count }} items'
ast = env.parse(template_source)
variables = meta.find_undeclared_variables(ast)
print(variables)  # {'user', 'count'}

# Template with loops and conditions
template_source = '''
{% for item in items %}
    {{ item.name }} - {{ item.price }}
{% endfor %}
{% if total > 100 %}
    Discount: {{ discount }}
{% endif %}
'''
ast = env.parse(template_source)
variables = meta.find_undeclared_variables(ast)
print(variables)  # {'items', 'total', 'discount'}
```

### Finding Template Dependencies

```python
from jinja2 import Environment, meta

env = Environment()

# Template with static dependencies
template_source = '''
{% extends "base.html" %}
{% include "header.html" %}
{% from "macros.html" import button %}
'''
ast = env.parse(template_source)
dependencies = list(meta.find_referenced_templates(ast))
print(dependencies)  # ['base.html', 'header.html', 'macros.html']

# Template with dynamic dependencies
template_source = '''
{% extends layout_template %}
{% include "static.html" %}
{% include dynamic_include %}
'''
ast = env.parse(template_source)
dependencies = list(meta.find_referenced_templates(ast))
print(dependencies)  # [None, 'static.html', None]
```

### Dependency Tracking System

```python
from jinja2 import Environment, meta
import os

def analyze_template_dependencies(template_path):
    """Analyze a template file and return its variable and template dependencies."""
    env = Environment()
    
    with open(template_path) as f:
        source = f.read()
    
    ast = env.parse(source)
    
    # Find variables needed from context
    variables = meta.find_undeclared_variables(ast)
    
    # Find referenced templates
    templates = [t for t in meta.find_referenced_templates(ast) if t is not None]
    
    return {
        'variables': variables,
        'templates': templates,
        'has_dynamic_dependencies': None in meta.find_referenced_templates(ast)
    }

# Example usage
dependencies = analyze_template_dependencies('templates/user_profile.html')
print(f"Variables needed: {dependencies['variables']}")
print(f"Template dependencies: {dependencies['templates']}")
print(f"Has dynamic deps: {dependencies['has_dynamic_dependencies']}")
```

### Template Variable Validation

```python
from jinja2 import Environment, meta

def validate_template_context(template_source, provided_context):
    """Validate that all required variables are provided in context."""
    env = Environment()
    ast = env.parse(template_source)
    required_vars = meta.find_undeclared_variables(ast)
    
    missing_vars = required_vars - set(provided_context.keys())
    
    if missing_vars:
        raise ValueError(f"Missing required variables: {missing_vars}")
    
    return True

# Example usage
template = "Hello {{ name }}, you have {{ count }} messages"
context = {"name": "Alice", "count": 5}

try:
    validate_template_context(template, context)
    print("All variables provided!")
except ValueError as e:
    print(f"Validation error: {e}")
```

### Build System Integration

```python
from jinja2 import Environment, meta
import os
from pathlib import Path

def get_template_dependency_graph(template_dir):
    """Build dependency graph for all templates in a directory."""
    env = Environment()
    dependency_graph = {}
    
    for template_file in Path(template_dir).glob('**/*.html'):
        template_path = str(template_file.relative_to(template_dir))
        
        with open(template_file) as f:
            source = f.read()
        
        ast = env.parse(source)
        dependencies = [
            dep for dep in meta.find_referenced_templates(ast) 
            if dep is not None
        ]
        
        dependency_graph[template_path] = dependencies
    
    return dependency_graph

# Example usage for build system
deps = get_template_dependency_graph('templates/')
for template, dependencies in deps.items():
    print(f"{template} depends on: {dependencies}")
```

## Import Pattern

```python
from jinja2 import meta

# Access meta functions through the meta module
variables = meta.find_undeclared_variables(ast)
templates = meta.find_referenced_templates(ast)
```