Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 85 additions & 58 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,58 +1,85 @@
# StringManipulation Development Guide

## Critical Development Rules
- **ALWAYS run all tests before committing**: `docker-compose run --rm test-all`
- **NEVER force push or use --force with git commands**
- **NEVER ignore test failures or errors**
- **ALWAYS use conventional commit messages** (feat:, fix:, chore:, etc.)
- **NEVER overwrite or amend existing commit messages**

## Build & Testing Commands

### Docker (Recommended - PHP 8.3 with AST extension)
**IMPORTANT**: Always use Docker for testing to ensure consistent environment with PHP 8.3 and AST extension.

- Run all tests: `docker-compose run --rm test-all`
- Run Pest tests: `docker-compose run --rm tests ./vendor/bin/pest`
- Run single test: `docker-compose run --rm tests ./vendor/bin/pest --filter testName`
- Code style check: `docker-compose run --rm test-code-style`
- Static analysis:
- PHPStan: `docker-compose run --rm test-phpstan`
- Psalm: `docker-compose run --rm test-psalm`
- Phan: `docker-compose run --rm test-phan`
- PHP Mess Detector: `docker-compose run --rm test-phpmd`
- Mutation testing: `docker-compose run --rm test-infection`
- Code refactoring: `docker-compose run --rm test-rector`
- Linting: `docker-compose run --rm test-lint`
- Security check: `docker-compose run --rm test-security`

### Local (Requires PHP 8.3+ with AST extension)
- Run all tests: `composer tests`
- Run Pest tests: `./vendor/bin/pest`
- Run single test: `./vendor/bin/pest --filter testName`
- Code style check: `composer test:code-style`
- Static analysis: `composer test:phpstan`, `composer test:psalm`, `composer test:phan`
- Linting: `composer test:lint`
- Mess detection: `composer test:phpmd`

### Code Review
- CodeRabbit review: `coderabbit review --type committed --config .coderabbit.yaml --plain --base main`
- Reviews committed changes against main branch
- Uses project-specific configuration from .coderabbit.yaml
- Plain text output for terminal display
- Note: Can timeout if simout set too low; use 30 minute timeout

## Code Style Guidelines
- PHP version: >=8.3.0
- Strict typing required: `declare(strict_types=1);`
- Namespaces: PSR-4 `MarjovanLier\StringManipulation`
- Classes: Final, static methods preferred
- Class constants: Use typed constants (e.g., `private const array FOO = []`)
- Docblocks: Comprehensive for public methods with @param, @return and @example
- Parameter typing: Always explicit, including return types
- Type hints: Use PHP 8 attributes like `#[SensitiveParameter]` where appropriate
- Null handling: Explicit checks, optional parameters default to empty string
- Documentation: 100% method coverage with examples
- Standards: PSR guidelines with Laravel Pint (preset "per")
- Testing: Pest PHP with complete coverage
- PHPMD: Methods must not exceed 100 lines
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

High-performance PHP 8.3+ string manipulation library with zero production dependencies. Single final class (`StringManipulation`) exposing static methods optimised with pre-computed character mappings for O(1) lookups via `strtr()`.

## Build & Test Commands

**Always use Docker** to ensure consistent PHP 8.3 + AST extension environment.

| Task | Docker | Local |
|------|--------|-------|
| Full pipeline | `docker-compose run --rm test-all` | `composer tests` |
| Pest tests | `docker-compose run --rm tests ./vendor/bin/pest` | `./vendor/bin/pest` |
| Single test | `docker-compose run --rm tests ./vendor/bin/pest --filter testName` | `./vendor/bin/pest --filter testName` |
| Code style check | `docker-compose run --rm test-code-style` | `composer test:code-style` |
| Code style fix | `docker-compose run --rm tests ./vendor/bin/pint` | `composer fix:code-style` |
| PHPStan | `docker-compose run --rm test-phpstan` | `composer test:phpstan` |
| Psalm | `docker-compose run --rm test-psalm` | `composer test:psalm` |
| Phan | `docker-compose run --rm test-phan` | `composer test:phan` |
| PHPMD | `docker-compose run --rm test-phpmd` | `composer test:phpmd` |
| Mutation testing | `docker-compose run --rm test-infection` | `composer test:infection` |
| Rector (dry-run) | `docker-compose run --rm test-rector` | `composer test:rector` |
| Linting | `docker-compose run --rm test-lint` | `composer test:lint` |
| Security check | `docker-compose run --rm test-security` | `composer test:vulnerabilities-check` |

**Run the full pipeline before committing**: `docker-compose run --rm test-all`

## Architecture

```
src/
├── StringManipulation.php # Single final class, all public static methods
├── AccentNormalization.php # Trait: SEARCH_WORDS_MAPPING + ACCENT_MAPPING constants
└── UnicodeMappings.php # Trait: UTF8_ANSI2 constant
```

- **StringManipulation** uses two traits purely as constant containers for pre-computed character mapping arrays
- All methods are static; the class is never instantiated
- Performance comes from `strtr()` with pre-computed array constants (hash table O(1) lookups) and single-pass algorithms
- The traits exist to keep the ~600 lines of mapping data separate from the ~400 lines of logic

### Public API (7 methods)

| Method | Purpose |
|--------|---------|
| `searchWords(?string)` | Normalise strings for database search (lowercase, remove accents/special chars) |
| `nameFix(?string)` | Standardise surnames (handles mc/mac prefixes, van/von/de particles, hyphens) |
| `removeAccents(string)` | Strip diacritics preserving case |
| `utf8Ansi(?string)` | Convert UTF-8 to ANSI equivalents |
| `isValidDate(string, string)` | Validate date string against format with logical checks |
| `strReplace(...)` | Optimised replacement (uses `strtr()` for single-char) |
| `trim(string, string)` | Stricter trim |
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The description "Stricter trim" for the trim method is misleading. The implementation in StringManipulation.php is a simple wrapper around PHP's native trim() function and does not provide any additional strictness. To ensure the documentation is accurate, I recommend updating the purpose to reflect its actual behavior.

Suggested change
| `trim(string, string)` | Stricter trim |
| `trim(string, string)` | Wrapper for PHP's native trim function |


## Static Analysis Levels

All analysers run at their strictest settings:
- **PHPStan**: Level MAX with strict rules, type-perfect, 95%+ type coverage
- **Psalm**: Level 1, taint analysis enabled, 99.95% type coverage
- **Phan**: All strict checking flags enabled, 11 quality plugins
- **PHPMD**: Max 100 lines/method, max 15 public methods/class

## Code Conventions

- `declare(strict_types=1)` on every file
- Final classes, static methods
- Typed constants: `private const array NAME = []`
- Comprehensive docblocks with `@param`, `@return`, `@example` on public methods
- `#[\SensitiveParameter]` attribute on parameters containing personal data
- Code style: Laravel Pint with PER (PHP Evolving Rules) preset
- South African English in documentation (organisation, colour, centre)

## Test Organisation

Tests live in `tests/Unit/` using Pest v4 syntax (`test('...', fn() => expect(...)->toBe(...))`).

Tests are split by method and concern: `NameFixTest`, `NameFixEdgeCasesTest`, `NameFixNegativeFlowTest`, `NameFixSpecialCharactersTest`, etc. Bug regressions get dedicated test files (e.g., `ArrayCombineValidationBugFixTest`, `UppercaseAccentMappingBugFixTest`).

Mutation testing target MSI: 88%.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is a discrepancy between the documented mutation testing target and the actual configuration. This file states the target MSI is 88%, while infection.json.dist sets minMsi to 85. Please update the documentation to match the configuration for consistency.

Suggested change
Mutation testing target MSI: 88%.
Mutation testing target MSI: 85%.


## CI

GitHub Actions runs the test matrix against PHP 8.3, 8.4, and 8.5 with vulnerability scanning (osv-scanner + Enlightn).
Loading