Skip to content

Repository files navigation

Drupal Theme Inspector

CI License: MIT Python 3.12

A command-line tool that statically analyzes Drupal 10 / 11 themes and generates a detailed, scored quality report — with concrete suggestions for fixing every issue it finds.

$ theme-inspector analyze themes/custom/olivero_child

╭──────────────── Drupal Theme Inspector — Olivero Child ─────────────────╮
│ 78/100  (Grade C)                                                        │
│ 42 files scanned                                                         │
│ 1 critical   4 warning   6 info                                          │
╰───────────────────────────────────────────────────────────────────────╯

Why

Reviewing a Drupal theme by hand — checking *.info.yml fields, hunting for deprecated drupal_get_path() calls, spotting stray {{ dump() }} left in a template, verifying every asset a *.libraries.yml file references actually exists — is repetitive and easy to get wrong. Drupal Theme Inspector automates that review and turns it into a single, shareable score.

Features

# Feature
1 Detects and parses theme metadata from *.info.yml
2 Validates required/recommended *.info.yml fields
3 Detects deprecated Drupal PHP/YAML syntax
4 Checks Twig templates (debug statements, |raw, naming, inline styles)
5 Detects missing or undeclared libraries and assets
6 Checks CSS/JS file organization
7 Analyzes overall file/directory structure
8 Generates HTML and Markdown reports
9 Produces a 0–100 quality score with a letter grade
10 Suggests concrete improvements for every issue

Installation

Requires Python 3.12+.

pip install drupal-theme-inspector

Or, from source:

git clone https://github.com/example/drupal-theme-inspector.git
cd drupal-theme-inspector
pip install -e .

Usage

# Analyze a theme and print a report to the terminal
theme-inspector analyze path/to/theme

# Also write HTML and/or Markdown reports
theme-inspector analyze path/to/theme --html report.html --markdown report.md

# Only print the summary panel, skip the detailed tables
theme-inspector analyze path/to/theme --quiet

# CI mode: exit non-zero if the score is below a threshold
theme-inspector analyze path/to/theme --fail-under 80

theme-inspector --version

Screenshots

Terminal output (Rich):

╭──────────────── Drupal Theme Inspector — Sample Theme ──────────────────╮
│ 61/100  (Grade D)                                                        │
│ 9 files scanned                                                          │
│ 2 critical   3 warning   2 info                                          │
╰───────────────────────────────────────────────────────────────────────╯
                                    twig
┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Severity ┃ Location                       ┃ Message                ┃ Suggestion                    ┃
┡━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ critical │ templates/node--BAD-Name...:2 │ Debug statement left…  │ Remove dump() calls before…  │
└──────────┴────────────────────────────────┴────────────────────────┴───────────────────────────────┘

HTML report: a self-contained, dependency-free HTML file with a score card and per-category issue tables — open report.html in any browser (see examples/ for a generated sample).

Markdown report: the same content as GitHub-flavored Markdown tables, ideal for pasting into a pull request description.

Generate your own copies with: theme-inspector analyze examples/sample_theme --html docs/example-report.html --markdown docs/example-report.md

Pre-generated copies for the bundled examples/sample_theme fixture are checked into docs/example-report.html and docs/example-report.md.

Programmatic usage

from drupal_theme_inspector.core.scanner import ThemeScanner

result = ThemeScanner("path/to/theme").scan()
print(result.score, result.grade)
for issue in result.issues:
    print(issue.severity, issue.category, issue.message)

Scoring

Every theme starts at a perfect 100. Each issue deducts points based on its severity:

Severity Points deducted Meaning
🔴 critical 12 Broken or deprecated in a way that will error, or ship a bug
🟡 warning 5 Works today but goes against current best practice
🔵 info 1 Style / polish suggestion

See core/scorer.py for the full (deliberately simple) implementation.

Architecture

src/drupal_theme_inspector/
├── analyzers/     # One module per check: info_yml, deprecated, twig,
│                  # libraries, assets, structure. Each returns list[Issue].
├── core/          # models.py (Issue, ThemeInfo, AnalysisResult),
│                  # scanner.py (orchestrates analyzers), scorer.py
├── reports/       # html_report.py, markdown_report.py
├── utils/         # console.py — Rich terminal rendering
└── cli.py         # Typer application

Adding a new check means writing one new analyzer function that returns list[Issue] and wiring it into ThemeScanner.scan() — the scorer and both report renderers work generically over Issue objects and need no changes. See docs/architecture.md and CONTRIBUTING.md for details.

Development

pip install -e ".[dev]"
pytest                 # run tests with coverage
ruff check src tests   # lint
mypy                   # type-check

License

MIT

About

No description, website, or topics provided.

Resources

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages