|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +**Nette Command Line** is a lightweight PHP library providing two focused utilities: |
| 8 | +- `Parser`: Command-line argument and option parsing with help text extraction |
| 9 | +- `Console`: Terminal color output with intelligent capability detection |
| 10 | + |
| 11 | +**Key characteristics:** |
| 12 | +- Zero runtime dependencies (PHP 8.2-8.5 only) |
| 13 | +- Minimal codebase (~518 LOC total) |
| 14 | +- Part of the Nette Framework ecosystem |
| 15 | +- Triple-licensed: BSD-3-Clause, GPL-2.0-only, GPL-3.0-only |
| 16 | + |
| 17 | +## Essential Commands |
| 18 | + |
| 19 | +### Development Setup |
| 20 | +```bash |
| 21 | +composer install # Install dev dependencies |
| 22 | +``` |
| 23 | + |
| 24 | +### Testing |
| 25 | +```bash |
| 26 | +composer run tester # Run all tests with simple output |
| 27 | +vendor/bin/tester tests -s # Same as above |
| 28 | +vendor/bin/tester tests -s # Run with code coverage |
| 29 | +vendor/bin/tester tests/Parser.phpt -s # Run specific test file |
| 30 | +``` |
| 31 | + |
| 32 | +### Code Quality |
| 33 | +```bash |
| 34 | +composer run phpstan # Run PHPStan static analysis (level 5) |
| 35 | +``` |
| 36 | + |
| 37 | +### CI/CD Information |
| 38 | +- Tests run on PHP 8.2, 8.3, 8.4, 8.5 via GitHub Actions |
| 39 | +- Coding style checked via Nette Code Checker and Coding Standard |
| 40 | +- PHPStan runs on master branch (informative only) |
| 41 | + |
| 42 | +## Architecture |
| 43 | + |
| 44 | +### Four-Class Design |
| 45 | + |
| 46 | +**Parser (`src/CommandLine/Parser.php` - 368 lines)** |
| 47 | +- Parses command-line arguments using help text or fluent API |
| 48 | +- Two approaches: `addFromHelp()` for help-text-driven definitions, or fluent `addSwitch()`/`addOption()`/`addArgument()` methods |
| 49 | +- Supports: flags, arguments, aliases, default values, enums, file paths, custom normalizers |
| 50 | +- Modern PascalCase constants (e.g., `Parser::Argument`, `Parser::Optional`) |
| 51 | +- Deprecated UPPERCASE constants maintained for backward compatibility |
| 52 | + |
| 53 | +**Console (`src/CommandLine/Console.php` - 89 lines)** |
| 54 | +- ANSI color output with automatic terminal capability detection |
| 55 | +- Respects `NO_COLOR` environment variable (https://no-color.org) |
| 56 | +- Detects Windows VT100 support and TTY environments |
| 57 | +- 16 named colors with foreground/background combinations |
| 58 | + |
| 59 | +**Option (`src/CommandLine/Option.php` - 39 lines)** |
| 60 | +- `final readonly class` representing a single option or positional argument configuration |
| 61 | +- Properties: `name`, `type`, `alias`, `fallback`, `repeatable`, `enum`, `normalizer` |
| 62 | +- Auto-computed `positional` property based on `-` prefix |
| 63 | + |
| 64 | +**ValueType (`src/CommandLine/ValueType.php` - 22 lines)** |
| 65 | +- Enum describing value requirement for options/arguments: |
| 66 | + - `None` - switch without value (e.g., `--verbose`) |
| 67 | + - `Required` - value must be provided (e.g., `--output <file>`) |
| 68 | + - `Optional` - value can be omitted (e.g., `--format [type]`) |
| 69 | + |
| 70 | +### Key Design Patterns |
| 71 | + |
| 72 | +**Help Text as Schema:** |
| 73 | +The `addFromHelp()` method extracts option definitions from formatted help text: |
| 74 | + |
| 75 | +```php |
| 76 | +$parser = new Parser; |
| 77 | +$parser->addFromHelp(' |
| 78 | + -p, --param=<value> Parameter description (default: 123) |
| 79 | + --verbose Enable verbose mode |
| 80 | +'); |
| 81 | +``` |
| 82 | + |
| 83 | +The help text format drives the parser configuration - options, arguments, defaults, and enums are all extracted from the help string structure. |
| 84 | + |
| 85 | +**Fluent API:** |
| 86 | +For more control, use `addSwitch()`, `addOption()`, and `addArgument()` methods: |
| 87 | + |
| 88 | +```php |
| 89 | +$parser = new Parser; |
| 90 | +$parser |
| 91 | + ->addSwitch('--verbose', '-v') |
| 92 | + ->addOption('--output', '-o') |
| 93 | + ->addOption('--format', '-f', optionalValue: true, fallback: 'json', enum: ['json', 'xml', 'csv']) |
| 94 | + ->addArgument('input', optional: false); |
| 95 | +``` |
| 96 | + |
| 97 | +**Early-Exit Options with `parseOnly()`:** |
| 98 | +For options like `--help` or `--version` that should work without providing required arguments: |
| 99 | + |
| 100 | +```php |
| 101 | +$parser = new Parser; |
| 102 | +$parser |
| 103 | + ->addSwitch('--help', '-h') |
| 104 | + ->addArgument('input'); // required |
| 105 | + |
| 106 | +// Check --help before full validation |
| 107 | +if ($parser->parseOnly(['--help'])['--help']) { |
| 108 | + $parser->help(); |
| 109 | + exit; |
| 110 | +} |
| 111 | + |
| 112 | +$args = $parser->parse(); // full parsing with validation |
| 113 | +``` |
| 114 | + |
| 115 | +The `parseOnly()` method parses only specified options, ignoring everything else. No validation, no exceptions. |
| 116 | + |
| 117 | +**Option Configuration Array:** |
| 118 | +When using `addFromHelp()`, additional options can be passed via second parameter: |
| 119 | +- `Parser::Argument` - requires a value |
| 120 | +- `Parser::Optional` - value is optional |
| 121 | +- `Parser::Repeatable` - can be specified multiple times |
| 122 | +- `Parser::Enum` - restricted to specific values |
| 123 | +- `Parser::RealPath` - validates file path existence |
| 124 | +- `Parser::Normalizer` - custom transformation function |
| 125 | +- `Parser::Default` - default value when not specified |
| 126 | + |
| 127 | +## Coding Standards |
| 128 | + |
| 129 | +### Nette Framework Conventions |
| 130 | +- Every file: `declare(strict_types=1)` at the top |
| 131 | +- Tab indentation (not spaces) |
| 132 | +- Comprehensive type hints on all parameters and return values |
| 133 | +- PSR-12 inspired with Nette-specific modifications |
| 134 | +- Minimal but clear documentation |
| 135 | + |
| 136 | +### Naming Conventions |
| 137 | +- PascalCase for class constants (modern style, e.g., `Parser::Optional`) |
| 138 | +- camelCase for methods and properties |
| 139 | +- Deprecated UPPERCASE constants aliased to PascalCase equivalents |
| 140 | + |
| 141 | +### Documentation Style |
| 142 | +- Classes: Brief description without unnecessary verbosity (e.g., "Stupid command line arguments parser") |
| 143 | +- Methods: Document when adding value beyond type signatures |
| 144 | +- Properties: Inline `@var` annotations for complex types |
| 145 | + |
| 146 | +## Testing with Nette Tester |
| 147 | + |
| 148 | +### Test File Structure |
| 149 | +Files use `.phpt` extension and follow this pattern: |
| 150 | + |
| 151 | +```php |
| 152 | +<?php |
| 153 | + |
| 154 | +declare(strict_types=1); |
| 155 | + |
| 156 | +use Nette\CommandLine\Parser; |
| 157 | +use Tester\Assert; |
| 158 | + |
| 159 | +require __DIR__ . '/bootstrap.php'; |
| 160 | + |
| 161 | + |
| 162 | +test('description of what is tested', function () { |
| 163 | + $cmd = new Parser('...'); |
| 164 | + Assert::same(['expected'], $cmd->parse(['input'])); |
| 165 | +}); |
| 166 | + |
| 167 | + |
| 168 | +test('another test case', function () { |
| 169 | + // Test implementation |
| 170 | +}); |
| 171 | +``` |
| 172 | + |
| 173 | +### Testing Patterns |
| 174 | +- Use `test()` function for each test case with clear descriptions |
| 175 | +- No comments before `test()` calls - the description parameter serves this purpose |
| 176 | +- Group related tests in the same file |
| 177 | +- Use `Assert::same()` for exact equality checks |
| 178 | +- Use `Assert::exception()` for exception testing |
| 179 | + |
| 180 | +### Bootstrap Setup |
| 181 | +All tests require `require __DIR__ . '/bootstrap.php';` which: |
| 182 | +- Loads Composer autoloader |
| 183 | +- Configures Tester environment |
| 184 | +- Sets up test functions |
| 185 | + |
| 186 | +## Version Management |
| 187 | + |
| 188 | +**Current branch:** master (1.9-dev) |
| 189 | +**PHP Support:** 8.2 minimum, tested through 8.5 |
| 190 | +**Branch alias:** dev-master → 1.9-dev |
| 191 | + |
| 192 | +### Backward Compatibility |
| 193 | +- Deprecated constants maintained with `@deprecated` annotations |
| 194 | +- Old UPPERCASE constants aliased to new PascalCase versions |
| 195 | +- Breaking changes noted in commit messages with "(BC break)" |
| 196 | + |
| 197 | +## Common Development Scenarios |
| 198 | + |
| 199 | +### Adding Parser Features |
| 200 | +When extending the Parser class: |
| 201 | +1. Add new constants in PascalCase format |
| 202 | +2. Create UPPERCASE deprecated aliases if replacing old names |
| 203 | +3. Update help text regex in constructor if needed |
| 204 | +4. Add comprehensive tests in `tests/Parser.phpt` |
| 205 | +5. Consider enum validation and normalizer patterns |
| 206 | + |
| 207 | +### Console Color Additions |
| 208 | +When modifying Console output: |
| 209 | +1. Respect `$this->useColors` flag |
| 210 | +2. Return plain strings when colors disabled |
| 211 | +3. Test with `NO_COLOR` environment variable |
| 212 | +4. Consider cross-platform compatibility (Windows VT100) |
| 213 | + |
| 214 | +### Test Writing |
| 215 | +1. Create or extend `.phpt` files in `tests/` directory |
| 216 | +2. Use descriptive test names in `test()` function |
| 217 | +3. Cover both success and error cases |
| 218 | +4. Test edge cases (empty input, missing values, invalid formats) |
| 219 | + |
| 220 | +## Dependencies and Tooling |
| 221 | + |
| 222 | +**Runtime:** None (PHP 8.2+ only) |
| 223 | + |
| 224 | +**Development:** |
| 225 | +- `nette/tester` ^2.5 - Testing framework |
| 226 | +- `tracy/tracy` ^2.9 - Debugging and error handling |
| 227 | +- `phpstan/phpstan-nette` ^2.0 - Static analysis with Nette-specific rules |
| 228 | + |
| 229 | +**Autoloading:** |
| 230 | +- PSR-4: `Nette\` → `src/` |
| 231 | +- Classmap fallback for `src/` directory |
0 commit comments