Skip to content

Conversation

@simbig
Copy link
Contributor

@simbig simbig commented Dec 5, 2025

Summary

  • Add abstract CanonicalCapitalizationRule base class for enforcing canonical spelling of terms
  • Add concrete LabIDCapitalizationRule that enforces "Lab ID" spelling
  • Detects wrong variants: LabID, labID, LABID, Labid, labid, Lab-ID, lab-Id, Lab Id, lab id
  • Works on variables, parameters, class methods, class names, and string literals

Architecture

Uses template method pattern:

  • getCanonicalForm() - returns the correct spelling (e.g., "Lab ID")
  • getWrongVariants() - returns array of wrong spellings to detect
  • getErrorIdentifier() - returns PHPStan error identifier

This allows easy creation of new rules for other canonical terms.

Test plan

  • Unit tests for findWrongVariant() method
  • Unit tests for fixCapitalization() method
  • Tests for correct capitalizations passing validation
  • PHPStan passes
  • PHPUnit tests pass

🤖 Generated with Claude Code

Simon Bigelmayr and others added 8 commits December 5, 2025 16:07
…lling

Add abstract CanonicalCapitalizationRule base class that checks:
- Variable names
- Parameter names
- Method names
- Class names
- String literals

Add LabIDCapitalizationRule to enforce "Lab ID" spelling over variants
like LabID, labID, LABID, Labid, Lab-ID, Lab Id, etc.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…ls only

Per coding guidelines: "Unless the circumstances demand otherwise
(all lower, no spaces, ...)" - canonical forms like "Lab ID" with
spaces only apply to user-facing text in string literals, not to
PHP identifiers (variables, methods, classes) where spaces are invalid.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Instead of checking for braces, detect the /* @lang GraphQL */ IDE
annotation which explicitly marks GraphQL query strings. This is more
precise and follows the existing convention in the codebase.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Tests that:
- Wrong capitalizations in strings are detected (LabID -> Lab ID)
- Correct capitalizations are ignored
- GraphQL queries with @lang annotation are skipped
- GraphQL queries without annotation are still checked

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…nRule

Strings that look like valid identifiers (matching ^[a-zA-Z_][a-zA-Z0-9_]*$)
are likely array keys, API field names, or database columns where spaces
are not valid. Skip these to focus on user-facing text.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…ules

Generalize GraphQL annotation check to skip any @lang annotated string
(SQL, GraphQL, RegExp, etc.) since these contain identifiers that cannot
have spaces.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
ReflectionMethod requires setAccessible(true) to invoke protected
methods in PHP < 8.1.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
PHPStan internals (PHPStanTestCase) have compatibility issues with
older PHP versions due to PHPStan/PHP-Parser version conflicts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Simon Bigelmayr and others added 4 commits December 8, 2025 15:30
- Resolve merge conflicts in phpstan.neon and phpstan-test.neon
- Rename CapitalizationOfIDRuleIntegrationTest to IdToIDRuleIntegrationTest
- Simplify LabIDCapitalizationRuleIntegrationTest using data-provider pattern
- Include both ID → ID rules and Lab ID capitalization rule in test config

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@simbig simbig requested a review from spawnia December 8, 2025 15:06
Comment on lines +18 to +20
abstract class CanonicalCapitalizationRule implements Rule
{
abstract protected function getCanonicalForm(): string;
Copy link
Member

Choose a reason for hiding this comment

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

Ich finde es nicht korrekt hier von Capitalization zu sprechen. Würde auch die Überschrift der Guideline abändern, wie wäre es mit Canonical ...:

  • forms
  • spelling
  • ?

Comment on lines +62 to +64
protected function cannotContainSpaces(string $value): bool
{
return ! str_contains($value, ' ');
Copy link
Member

Choose a reason for hiding this comment

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

Diese Heuristik kann schon wild inakkurat sein. Wenn jemand fälschlicherweise Limes2 schreibt wo auch Limes 2 stehen könnte, würde es das nicht fangen.

protected function hasLanguageAnnotation(String_ $node): bool
{
foreach ($node->getComments() as $comment) {
if (Str::contains($comment->getText(), '@lang')) {
Copy link
Member

Choose a reason for hiding this comment

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

Eventuell können wir das hier einschränken auf gewisse Languages. In @lang Markdown wären alle Formen ok.

Comment on lines +90 to +92
public function fixCapitalization(string $value, string $wrongVariant): string
{
return str_replace($wrongVariant, $this->getCanonicalForm(), $value);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
public function fixCapitalization(string $value, string $wrongVariant): string
{
return str_replace($wrongVariant, $this->getCanonicalForm(), $value);
public function fixCapitalization(string $subject, string $wrongVariant): string
{
return str_replace($wrongVariant, $this->getCanonicalForm(), $subject);


public function getNodeType(): string
{
return String_::class;
Copy link
Member

Choose a reason for hiding this comment

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

Fangen wir damit auch alle möglichen Varianten in PHP Strings zu definieren?

yield 'detects wrong capitalization' => [
__DIR__ . '/data/lab-id-capitalization.php',
[
9 => ['String "The LabID is wrong" should use "Lab ID" instead of "LabID", change it to "The Lab ID is wrong".'],
Copy link
Member

Choose a reason for hiding this comment

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

Hier den ganzen String in der Nachricht zu zeigen kann sehr unübersichtlich werden, wenn es sich um lange Multiline-Werte handelt.

Comment on lines +23 to +35
30 => ['String "
{
patient {
labID
}
}
" should use "Lab ID" instead of "labID", change it to "
{
patient {
Lab ID
}
}
".'],
Copy link
Member

Choose a reason for hiding this comment

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

Negativbeispiel, in dem Fall sollte via @lang GraphQL der Wert ausgenommen werden.

Comment on lines +36 to +42
66 => ['String "
SELECT exam_no AS labID
FROM examinations
" should use "Lab ID" instead of "labID", change it to "
SELECT exam_no AS Lab ID
FROM examinations
".'],
Copy link
Member

Choose a reason for hiding this comment

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

Auch Negativbeispiel, @lang SQL sollte auch hier zur Exklusion führen.

Copy link
Member

Choose a reason for hiding this comment

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

Testfälle:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants