This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Nette Code Checker is a command-line tool that checks and optionally repairs formal errors in source code. It's distributed as a standalone tool (not a library dependency) and validates multiple file formats including PHP, Latte templates, NEON, JSON, and YAML.
# Check current directory (read-only mode)
php code-checker
# Check and fix files
php code-checker --fix
# Check specific directory
php code-checker -d path/to/check
# Check with strict_types validation
php code-checker --strict-types
# Normalize line endings
php code-checker --eol
# Syntax-only checks (faster)
php code-checker --only-syntax# Run all tests
composer run tester
# or
vendor/bin/tester tests -s -C
# Run single test file
vendor/bin/tester tests/Tasks.latteSyntaxChecker.phpt -s -C
# Run PHPStan static analysis
composer run phpstan
# or
phpstan analyseThe codebase has a simple, task-based architecture:
-
Checker (
src/Checker.php): Main orchestrator that:- Scans directories using file patterns
- Processes each file through registered tasks
- Handles read-only vs fix mode
- Reports errors/warnings/fixes with color-coded output
-
Tasks (
src/Tasks.php): Collection of static validation/fixing methods:- Each task is a static method with signature:
(string &$contents, Result $result): void - Tasks can modify
$contents(for fixers) or just add messages to$result - Tasks are pattern-matched to file types (e.g.,
*.php,*.latte)
- Each task is a static method with signature:
-
Result (
src/Result.php): Accumulates messages from tasks:error(): Critical issues that prevent acceptancewarning(): Non-critical issuesfix(): Issues that were/can be automatically fixed
-
bootstrap.php (
src/bootstrap.php): Entry point that:- Parses command-line arguments
- Registers tasks based on options
- Runs the checker
- Returns appropriate exit codes
Tasks are registered in bootstrap.php with optional file patterns:
// Apply to all files
$checker->addTask([$tasks, 'controlCharactersChecker']);
// Apply only to specific file types
$checker->addTask([$tasks, 'phpSyntaxChecker'], '*.php,*.phpt');
// Conditional registration
if (isset($options['--strict-types'])) {
$checker->addTask([$tasks, 'strictTypesDeclarationChecker'], '*.php,*.phpt');
}Checker tasks (read-only validation):
public static function taskName(string $contents, Result $result): void
{
if (/* check fails */) {
$result->error('Error message', $lineNumber);
}
}Fixer tasks (modify contents):
public static function taskName(string &$contents, Result $result): void
{
$new = /* transform contents */;
if ($new !== $contents) {
$result->fix('description of fix', $lineNumber);
$contents = $new;
}
}The latteSyntaxChecker task demonstrates integration with Nette ecosystem:
- Creates a full Latte engine with all standard extensions (UI, Forms, Cache, Assets)
- Compiles templates to PHP code
- Validates generated PHP using
phpSyntaxChecker - Downgrades "Unexpected tag" errors to warnings (for extensibility)
This is important when modifying: always ensure Latte checker has all necessary extensions registered.
Tests use Nette Tester with .phpt files:
- Each task typically has its own test file:
Tasks.{taskName}.phpt - Use the
test()function wrapper defined intests/bootstrap.php - Tests create
Resultobjects and verify messages/fixes - No test descriptions needed - the test file name indicates what's tested
Example test pattern:
test(function () {
$result = new Result;
Tasks::someChecker('input content', $result);
Assert::same([[Result::Error, 'Expected message', 1]], $result->getMessages());
});The Checker::matchFileName() method supports:
- Comma-separated patterns:
*.php,*.phpt - Negative patterns with
!prefix:!*.sh - Case-insensitive matching via
FNM_CASEFOLD
Tasks use Tasks::offsetToLine() to convert byte offsets to line numbers for error reporting. This is critical for accurate error messages.
In read-only mode:
- Fix-type results are reported as "FOUND" instead of "FIX"
- Files are never modified
- Exit code reflects whether fixes are needed
- Used for CI/validation pipelines
Many PHP tasks use token_get_all() for parsing:
- Wrapped in
@to suppress parse errors (checked separately) - Allows pattern detection without full AST parsing
- Used for: phpDoc validation, escape sequence checking, tab detection
0: Success (no errors)1: Errors found or fixes needed (in read-only mode)2: Exception/fatal error
Core dependencies (all from Nette ecosystem):
nette/command-line: CLI argument parsingnette/utils: String manipulation, file findinglatte/latte: Template syntax validationnette/neon: NEON format validationnette/application,nette/forms,nette/caching,nette/assets: Latte extensions