From f3a41c457a17fa291b2ef8f8a6d6acdb78195e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Thu, 13 Aug 2026 05:51:00 +0200 Subject: [PATCH] Normalize package --- .gitattributes | 31 ++++----- .gitignore | 11 ++-- .php-cs-fixer.dist.php | 26 +++----- CHANGELOG.md | 18 ++--- LICENSE | 2 +- README.md | 65 ++++++++++++------- composer.json | 20 +++--- docs/{public-api.md => api/index.md} | 7 +- docs/examples.md | 51 ++------------- docs/getting-started.md | 6 +- docs/index.md | 26 +++++--- docs/installation.md | 4 +- .../embedded.md} | 0 docs/{languages.md => languages/index.md} | 58 ++++++++--------- .../adapters.md} | 4 +- .../creating.md} | 2 +- docs/{themes.md => theming/index.md} | 12 ++-- src/Adapter/HighlightJsThemeAdapter.php | 10 +-- src/Adapter/PrismThemeAdapter.php | 4 +- src/Adapter/ReadsThemeFile.php | 4 +- src/Adapter/TextMateThemeAdapter.php | 22 ++++--- src/Embedded/EmbeddedLanguagePlan.php | 5 +- src/Embedded/EmbeddedLanguageRegistry.php | 6 +- src/Embedded/EmbeddedTrigger.php | 5 +- src/Embedded/EmbeddedTriggerType.php | 2 +- src/Exception/LanguageNotFoundException.php | 4 +- src/Exception/ParseException.php | 2 +- src/Highlighter.php | 24 ++++--- src/HighlighterInterface.php | 2 +- src/Language/BashLanguage.php | 10 +-- src/Language/CSharp/CSharpLexer.php | 6 +- src/Language/CSharp/CSharpSemanticParser.php | 4 +- src/Language/CSharp/CSharpState.php | 4 +- src/Language/CSharp/CSharpToken.php | 7 +- src/Language/CSharp/CSharpTokenType.php | 4 +- src/Language/CSharpLanguage.php | 4 +- src/Language/CssLanguage.php | 4 +- src/Language/DiffLanguage.php | 4 +- src/Language/DockerfileLanguage.php | 5 +- src/Language/DotEnvLanguage.php | 4 +- src/Language/EmbeddedLanguageCapable.php | 4 +- src/Language/EmbeddedLanguageContext.php | 15 +++-- src/Language/Go/GoLexer.php | 4 +- src/Language/Go/GoSemanticParser.php | 12 +++- src/Language/Go/GoState.php | 4 +- src/Language/Go/GoToken.php | 7 +- src/Language/Go/GoTokenType.php | 4 +- src/Language/GoLanguage.php | 4 +- src/Language/HtmlLanguage.php | 6 +- src/Language/HttpLanguage.php | 8 ++- src/Language/IniLanguage.php | 4 +- src/Language/Java/JavaLexer.php | 4 +- src/Language/Java/JavaSemanticParser.php | 4 +- src/Language/Java/JavaState.php | 4 +- src/Language/Java/JavaToken.php | 7 +- src/Language/Java/JavaTokenType.php | 4 +- src/Language/JavaLanguage.php | 4 +- src/Language/JavaScript/JavaScriptLexer.php | 4 +- .../JavaScript/JavaScriptSemanticParser.php | 14 ++-- src/Language/JavaScript/JavaScriptState.php | 4 +- src/Language/JavaScript/JavaScriptToken.php | 7 +- .../JavaScript/JavaScriptTokenType.php | 4 +- src/Language/JavaScriptLanguage.php | 6 +- src/Language/JsonLanguage.php | 4 +- src/Language/LanguageInterface.php | 4 +- src/Language/Languages.php | 5 +- src/Language/MakefileLanguage.php | 8 ++- src/Language/MarkdownLanguage.php | 6 +- src/Language/Php/PhpLexer.php | 4 +- src/Language/Php/PhpSemanticParser.php | 14 ++-- src/Language/Php/PhpState.php | 4 +- src/Language/PhpLanguage.php | 6 +- src/Language/Python/PythonLexer.php | 8 ++- src/Language/Python/PythonSemanticParser.php | 4 +- src/Language/Python/PythonState.php | 4 +- src/Language/Python/PythonToken.php | 7 +- src/Language/Python/PythonTokenType.php | 4 +- src/Language/PythonLanguage.php | 4 +- src/Language/Ruby/RubyLexer.php | 16 +++-- src/Language/Ruby/RubySemanticParser.php | 14 ++-- src/Language/Ruby/RubyState.php | 4 +- src/Language/Ruby/RubyToken.php | 7 +- src/Language/Ruby/RubyTokenType.php | 4 +- src/Language/RubyLanguage.php | 4 +- src/Language/Rust/RustLexer.php | 22 ++++--- src/Language/Rust/RustSemanticParser.php | 14 ++-- src/Language/Rust/RustState.php | 4 +- src/Language/Rust/RustToken.php | 7 +- src/Language/Rust/RustTokenType.php | 4 +- src/Language/RustLanguage.php | 4 +- src/Language/ScssLanguage.php | 4 +- src/Language/SqlLanguage.php | 6 +- src/Language/SvgLanguage.php | 4 +- src/Language/Swift/SwiftLexer.php | 10 +-- src/Language/Swift/SwiftSemanticParser.php | 14 ++-- src/Language/Swift/SwiftState.php | 4 +- src/Language/Swift/SwiftToken.php | 7 +- src/Language/Swift/SwiftTokenType.php | 4 +- src/Language/SwiftLanguage.php | 4 +- src/Language/TwigLanguage.php | 4 +- src/Language/TypeScriptLanguage.php | 4 +- src/Language/XmlLanguage.php | 4 +- src/Language/YamlLanguage.php | 4 +- src/Parser/ParsedStream.php | 31 +++++---- src/Parser/ParsedToken.php | 5 +- src/Parser/StreamBuilder.php | 6 +- src/Parser/TokenType.php | 2 +- src/Scope.php | 2 +- src/Theme/AltoTheme.php | 7 +- src/Theme/CupertinoTheme.php | 9 +-- src/Theme/DraculaTheme.php | 6 +- src/Theme/GitHubTheme.php | 9 +-- src/Theme/NoctisTheme.php | 9 +-- src/Theme/PolarTheme.php | 6 +- src/Theme/SolarTheme.php | 9 +-- src/ThemeInterface.php | 2 +- tests/Language/BashLanguageTest.php | 2 +- tests/Language/CSharpLanguageTest.php | 2 +- tests/Language/CssLanguageTest.php | 2 +- tests/Language/DiffLanguageTest.php | 2 +- tests/Language/DockerfileLanguageTest.php | 2 +- tests/Language/DotEnvLanguageTest.php | 2 +- tests/Language/GoLanguageTest.php | 2 +- tests/Language/HtmlLanguageTest.php | 2 +- tests/Language/HttpLanguageTest.php | 2 +- tests/Language/IniLanguageTest.php | 2 +- tests/Language/JavaLanguageTest.php | 2 +- tests/Language/JavaScriptLanguageTest.php | 2 +- tests/Language/JsonLanguageTest.php | 2 +- tests/Language/MakefileLanguageTest.php | 2 +- tests/Language/MarkdownLanguageTest.php | 2 +- tests/Language/PhpLanguageTest.php | 2 +- tests/Language/PythonLanguageTest.php | 2 +- tests/Language/RubyLanguageTest.php | 2 +- tests/Language/RustLanguageTest.php | 2 +- tests/Language/ScssLanguageTest.php | 2 +- tests/Language/SqlLanguageTest.php | 2 +- tests/Language/SvgLanguageTest.php | 2 +- tests/Language/SwiftLanguageTest.php | 2 +- tests/Language/TwigLanguageTest.php | 2 +- tests/Language/TypeScriptLanguageTest.php | 2 +- tests/Language/XmlLanguageTest.php | 2 +- tests/Language/YamlLanguageTest.php | 2 +- tests/LanguageTestCase.php | 26 ++++---- tests/Support/MockHttpStreamWrapper.php | 10 ++- tests/TestCase.php | 2 +- .../Adapter/HighlightJsThemeAdapterTest.php | 4 +- tests/Unit/Adapter/PrismThemeAdapterTest.php | 6 +- .../Unit/Adapter/TextMateThemeAdapterTest.php | 2 +- .../Embedded/EmbeddedLanguagePlanTest.php | 2 +- .../Embedded/EmbeddedLanguageRegistryTest.php | 4 +- tests/Unit/Embedded/EmbeddedTriggerTest.php | 2 +- tests/Unit/ExamplesCatalogTest.php | 10 +-- tests/Unit/Exception/ExceptionTest.php | 2 +- tests/Unit/HighlighterTest.php | 2 +- .../Language/CrossLanguageSemanticTest.php | 4 +- .../Unit/Language/CssLanguageSemanticTest.php | 2 +- .../Language/EmbeddedLanguageContextTest.php | 18 ++--- tests/Unit/Language/EmbeddedLanguageTest.php | 20 +++--- .../Language/HtmlLanguageSemanticTest.php | 2 +- tests/Unit/Language/HttpLanguageTest.php | 8 +-- .../JavaScript/JavaScriptLexerTest.php | 10 +-- .../JavaScriptSemanticParserTest.php | 64 +++++++++--------- .../JavaScriptLanguageSemanticTest.php | 2 +- .../Unit/Language/JavaScriptLanguageTest.php | 2 +- .../Language/JsonLanguageSemanticTest.php | 2 +- tests/Unit/Language/LanguagesTest.php | 4 +- .../Language/MarkdownLanguageSemanticTest.php | 2 +- tests/Unit/Language/Php/PhpLexerTest.php | 6 +- .../Language/Php/PhpSemanticParserTest.php | 28 ++++---- .../Unit/Language/PhpLanguageSemanticTest.php | 2 +- tests/Unit/Language/PhpLanguageTest.php | 2 +- tests/Unit/Language/PythonLanguageTest.php | 2 +- .../Language/SemanticLanguageTestCase.php | 6 +- .../Language/TwigLanguageSemanticTest.php | 2 +- .../Unit/Language/TypeScriptLanguageTest.php | 20 +++--- tests/Unit/Parser/ParsedStreamTest.php | 12 ++-- tests/Unit/Parser/ParsedTokenTest.php | 2 +- tests/Unit/Parser/StreamBuilderTest.php | 2 +- tests/Unit/Parser/TokenTypeTest.php | 2 +- tests/Unit/PygmentsComparisonTest.php | 18 ++--- tests/Unit/ScopeTest.php | 2 +- tests/Unit/Theme/AltoThemeTest.php | 2 +- tests/Unit/Theme/CupertinoThemeTest.php | 2 +- tests/Unit/Theme/DraculaThemeTest.php | 2 +- tests/Unit/Theme/GitHubThemeTest.php | 2 +- tests/Unit/Theme/NoctisThemeTest.php | 2 +- tests/Unit/Theme/PolarThemeTest.php | 2 +- tests/Unit/Theme/SolarThemeTest.php | 2 +- tests/Unit/Theme/ThemeTestCase.php | 6 +- 190 files changed, 756 insertions(+), 629 deletions(-) rename docs/{public-api.md => api/index.md} (92%) rename docs/{embedded-languages.md => languages/embedded.md} (100%) rename docs/{languages.md => languages/index.md} (50%) rename docs/{theme-adapters.md => theming/adapters.md} (95%) rename docs/{creating-a-theme.md => theming/creating.md} (98%) rename docs/{themes.md => theming/index.md} (82%) diff --git a/.gitattributes b/.gitattributes index 3611f27..ac7f4be 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,20 +1,17 @@ * text=auto eol=lf -/.github/ export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore -/.php-cs-fixer.dist.php export-ignore -/phpstan.neon.dist export-ignore -/phpunit.xml.dist export-ignore -/bin/ export-ignore -/docs/ export-ignore -/examples/ export-ignore -/tests/ export-ignore -/tools/ export-ignore +/.gitattributes export-ignore +/.github export-ignore +/.gitignore export-ignore +/.php-cs-fixer.dist.php export-ignore +/bin export-ignore +/docs export-ignore +/examples export-ignore +/phpstan.neon.dist export-ignore +/phpunit.xml.dist export-ignore +/tests export-ignore +/tools export-ignore -/bin/** linguist-vendored -/docs/** linguist-documentation -/examples/** linguist-documentation -/tests/** linguist-vendored -/tests/Language/**/*.html linguist-generated -/tools/** linguist-vendored +/docs/** linguist-documentation +/examples/** linguist-documentation +/tests/Language/** -linguist-detectable diff --git a/.gitignore b/.gitignore index ca4f36b..8346dbb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,8 @@ -/.phpunit.cache/ -/var/ /vendor/ -/.php-cs-fixer.php +/composer.lock +/.phpunit.cache/ +/.phpunit.result.cache /.php-cs-fixer.cache +/coverage/ /coverage.xml -/composer.lock -/phpstan.neon -/phpunit.xml +/clover.xml diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 206df93..507bb58 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -1,34 +1,28 @@ in([ - __DIR__.'/src', - __DIR__.'/tests', - ]) - ->exclude([ - 'Language/php', - ]) -; +$finder = PhpCsFixer\Finder::create() + ->in([__DIR__.'/src', __DIR__.'/tests']) + ->exclude('Language/php'); return (new PhpCsFixer\Config()) - ->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect()) - ->setFinder($finder) ->setRiskyAllowed(true) ->setRules([ - '@PER-CS' => true, - '@Symfony' => true, + '@PER-CS2.0' => true, 'declare_strict_types' => true, 'header_comment' => ['header' => $licence], - 'ordered_imports' => ['sort_algorithm' => 'alpha'], 'no_unused_imports' => true, + 'ordered_imports' => ['imports_order' => ['class', 'function', 'const']], + 'phpdoc_line_span' => ['const' => 'multi', 'property' => 'multi', 'method' => 'multi'], ]) -; + ->setFinder($finder); diff --git a/CHANGELOG.md b/CHANGELOG.md index 71779e6..b4ca654 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,21 +1,11 @@ -# Changelog +# CHANGELOG -All notable changes to this project will be documented in this file. +## [Unreleased] -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +- Rework documentation. ## [1.0.0] - 2026-08-09 -### Added - -- Syntax highlighting -- 27 languages -- Embedded languages -- 12 themes -- External theme adapters -- Line numbers and highlighting -- Zero runtime dependencies -- Guides and examples +- Initial release. [1.0.0]: https://github.com/altophp/code-highlight/releases/tag/v1.0.0 diff --git a/LICENSE b/LICENSE index 3a49d93..dc9b29f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2026-Present Simon André +Copyright (c) 2026-present Simon André Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index ae7e31b..e69a608 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ -# ALTO \ Code Highlight +# ALTO Code Highlight Server-side syntax highlighting for PHP applications, with semantic scopes, embedded languages, and no third-party PHP package dependencies at runtime. -[![CI](https://github.com/altophp/code-highlight/actions/workflows/CI.yml/badge.svg)](https://github.com/altophp/code-highlight/actions/workflows/CI.yml) -[![PHP](https://img.shields.io/badge/PHP-8.4%2B-777BB4?logo=php&logoColor=white)](https://www.php.net/) -[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +  ![PHP Version](https://img.shields.io/badge/PHP-8.4%2B-00B7FF?logoColor=00B7FF&labelColor=050608) +  ![CI](https://img.shields.io/github/actions/workflow/status/altophp/code-highlight/CI.yml?branch=main&label=Tests&labelColor=050608&color=00B7FF) +  [![Packagist](https://img.shields.io/packagist/v/alto/code-highlight?label=Packagist&labelColor=050608&color=00B7FF)](https://packagist.org/packages/alto/code-highlight) +  ![License](https://img.shields.io/github/license/altophp/code-highlight?label=License&labelColor=050608&color=00B7FF) +  [![GitHub Sponsors](https://img.shields.io/github/sponsors/smnandre?logo=githubsponsors&logoColor=00B7FF&label=%20Sponsor&labelColor=050608&color=00B7FF)](https://github.com/sponsors/smnandre) ![PHP highlighted with the Alto Dark theme](docs/assets/examples/alto-dark/php.png) @@ -14,22 +16,22 @@ process, or external service. Its parsers assign semantic scopes, so themes can distinguish a function definition from a call or a type definition from a reference. -## Install +## Installation + +Install ALTO Code Highlight with Composer: ```bash composer require alto/code-highlight ``` -Requirements: - -- PHP 8.4 or later; -- `ext-mbstring`; -- `ext-tokenizer`. +ALTO Code Highlight requires PHP 8.4 or later, Mbstring, and Tokenizer. +Tokenizer is included with PHP; Mbstring is available in most PHP distributions +but must be enabled. See the [installation guide](docs/installation.md) for verification and troubleshooting. -## Quick start +## Quick Start ```php registerLanguage(new MyLanguage()); Registering an existing identifier replaces that parser on the highlighter instance. Theme authors style the generic semantic scopes emitted by parsers; -see [Creating a theme](creating-a-theme.md). +see [Creating a theme](../theming/creating.md). diff --git a/docs/theme-adapters.md b/docs/theming/adapters.md similarity index 95% rename from docs/theme-adapters.md rename to docs/theming/adapters.md index d145fa4..6c377e1 100644 --- a/docs/theme-adapters.md +++ b/docs/theming/adapters.md @@ -112,5 +112,5 @@ Adapters translate style classes only: - source escaping and output structure remain Alto's responsibility; - line numbers still use `alto-line-number` and `alto-highlighted`. -See [Languages](languages.md), [Getting started](getting-started.md), and -[Creating a theme](creating-a-theme.md) for those separate contracts. +See [Languages](../languages/index.md), [Getting started](../getting-started.md), +and [Creating a theme](creating.md) for those separate contracts. diff --git a/docs/creating-a-theme.md b/docs/theming/creating.md similarity index 98% rename from docs/creating-a-theme.md rename to docs/theming/creating.md index 74de2a9..5dee5e0 100644 --- a/docs/creating-a-theme.md +++ b/docs/theming/creating.md @@ -213,5 +213,5 @@ Also review the theme in a browser: - confirm that source text reconstructs exactly after stripping generated markup. -The canonical samples in [Examples](examples.md) provide stable inputs for +The canonical samples in [Examples](../examples.md) provide stable inputs for visual review. diff --git a/docs/themes.md b/docs/theming/index.md similarity index 82% rename from docs/themes.md rename to docs/theming/index.md index 3373c02..4c45d1b 100644 --- a/docs/themes.md +++ b/docs/theming/index.md @@ -61,25 +61,25 @@ The same PHP example rendered with the four primary documentation variants: | Alto Dark | Alto Light | |---|---| -| ![PHP highlighted with Alto Dark](assets/examples/alto-dark/php.png) | ![PHP highlighted with Alto Light](assets/examples/alto-light/php.png) | +| ![PHP highlighted with Alto Dark](../assets/examples/alto-dark/php.png) | ![PHP highlighted with Alto Light](../assets/examples/alto-light/php.png) | | GitHub Dark | GitHub Light | |---|---| -| ![PHP highlighted with GitHub Dark](assets/examples/github-dark/php.png) | ![PHP highlighted with GitHub Light](assets/examples/github-light/php.png) | +| ![PHP highlighted with GitHub Dark](../assets/examples/github-dark/php.png) | ![PHP highlighted with GitHub Light](../assets/examples/github-light/php.png) | The full PHP, Twig, HTML, JavaScript, and CSS matrix is available in -[Examples](examples.md). +[Examples](../examples.md). ## Line numbers and selected lines The highlighter emits structural `alto-line-number` and `alto-highlighted` classes when those options are enabled. Built-in theme stylesheets do not define their layout. Add application CSS for those classes as shown in -[Getting started](getting-started.md#line-numbers-and-selected-lines). +[Getting started](../getting-started.md#line-numbers-and-selected-lines). ## Other theme sources -- Use [theme adapters](theme-adapters.md) for local Highlight.js, Prism, or +- Use [theme adapters](adapters.md) for local Highlight.js, Prism, or TextMate theme files. -- Follow [Creating a theme](creating-a-theme.md) to implement +- Follow [Creating a theme](creating.md) to implement `ThemeInterface` directly. diff --git a/src/Adapter/HighlightJsThemeAdapter.php b/src/Adapter/HighlightJsThemeAdapter.php index 91c4ec3..cb40cf4 100644 --- a/src/Adapter/HighlightJsThemeAdapter.php +++ b/src/Adapter/HighlightJsThemeAdapter.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -222,21 +222,21 @@ private function adaptCssForAlto(string $css): string $css = (string) preg_replace( '/(?fetchCss($cdnUrl); if (null !== $css) { diff --git a/src/Adapter/PrismThemeAdapter.php b/src/Adapter/PrismThemeAdapter.php index 6fbbc78..010ea5f 100644 --- a/src/Adapter/PrismThemeAdapter.php +++ b/src/Adapter/PrismThemeAdapter.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -192,7 +192,7 @@ public function isDark(): bool private function loadFromCdn(string $themeName): string { - $cdnUrl = self::CDN_BASE.'/'.self::PRISM_VERSION.'/themes/prism-'.$themeName.'.min.css'; + $cdnUrl = self::CDN_BASE . '/' . self::PRISM_VERSION . '/themes/prism-' . $themeName . '.min.css'; $css = $this->fetchCss($cdnUrl); if (null !== $css) { diff --git a/src/Adapter/ReadsThemeFile.php b/src/Adapter/ReadsThemeFile.php index 948a364..dac374d 100644 --- a/src/Adapter/ReadsThemeFile.php +++ b/src/Adapter/ReadsThemeFile.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -20,6 +20,8 @@ * the file exists, is a regular file, and is readable before reading. * * @internal + * + * @author Simon André */ trait ReadsThemeFile { diff --git a/src/Adapter/TextMateThemeAdapter.php b/src/Adapter/TextMateThemeAdapter.php index e0e16b0..fd15b32 100644 --- a/src/Adapter/TextMateThemeAdapter.php +++ b/src/Adapter/TextMateThemeAdapter.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -38,7 +38,9 @@ final class TextMateThemeAdapter implements ThemeInterface private bool $isDark; - /** @var array Map of scope value to CSS class name */ + /** + * @var array Map of scope value to CSS class name + */ private array $cssClasses; private string $stylesheet; @@ -153,11 +155,11 @@ private function buildTheme(array $scopeStyles): void $classes = []; foreach (Scope::cases() as $scope) { - $className = 'alto-tm-'.str_replace('.', '-', $scope->value); + $className = 'alto-tm-' . str_replace('.', '-', $scope->value); $classes[$scope->value] = $className; if (isset($scopeStyles[$scope->value])) { - $css[] = '.'.$className.' { '.$scopeStyles[$scope->value].' }'; + $css[] = '.' . $className . ' { ' . $scopeStyles[$scope->value] . ' }'; } } @@ -174,13 +176,13 @@ private function buildCss(array $settings): string if (isset($settings['foreground']) && is_string($settings['foreground'])) { $color = self::sanitizeCssColor($settings['foreground']); if (null !== $color) { - $css[] = 'color: '.$color; + $css[] = 'color: ' . $color; } } if (isset($settings['background']) && is_string($settings['background'])) { $color = self::sanitizeCssColor($settings['background']); if (null !== $color) { - $css[] = 'background-color: '.$color; + $css[] = 'background-color: ' . $color; } } if (isset($settings['fontStyle']) && is_string($settings['fontStyle'])) { @@ -196,7 +198,7 @@ private function buildCss(array $settings): string } } - return implode('; ', $css).';'; + return implode('; ', $css) . ';'; } /** @@ -302,12 +304,12 @@ private function parseDict(\SimpleXMLElement $dict): array $result = []; $children = $dict->children(); for ($i = 0; $i < count($children); $i += 2) { - $key = $children[$i]; + $keyNode = $children[$i] ?? null; $valueNode = $children[$i + 1] ?? null; - if ('key' !== $key->getName() || null === $valueNode) { + if (!$keyNode instanceof \SimpleXMLElement || !$valueNode instanceof \SimpleXMLElement || 'key' !== $keyNode->getName()) { continue; } - $result[(string) $key] = $this->parseNode($valueNode); + $result[(string) $keyNode] = $this->parseNode($valueNode); } return $result; diff --git a/src/Embedded/EmbeddedLanguagePlan.php b/src/Embedded/EmbeddedLanguagePlan.php index a27fadb..5cd515f 100644 --- a/src/Embedded/EmbeddedLanguagePlan.php +++ b/src/Embedded/EmbeddedLanguagePlan.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -26,8 +26,7 @@ final class EmbeddedLanguagePlan private function __construct( public readonly string $hostLanguage, private readonly array $triggers, - ) { - } + ) {} /** * @param list $triggers diff --git a/src/Embedded/EmbeddedLanguageRegistry.php b/src/Embedded/EmbeddedLanguageRegistry.php index 3be09f4..a343252 100644 --- a/src/Embedded/EmbeddedLanguageRegistry.php +++ b/src/Embedded/EmbeddedLanguageRegistry.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -18,7 +18,9 @@ */ final class EmbeddedLanguageRegistry { - /** @var array */ + /** + * @var array + */ private array $plans = []; /** diff --git a/src/Embedded/EmbeddedTrigger.php b/src/Embedded/EmbeddedTrigger.php index 1f184c8..e41d405 100644 --- a/src/Embedded/EmbeddedTrigger.php +++ b/src/Embedded/EmbeddedTrigger.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -27,8 +27,7 @@ private function __construct( public readonly string $targetLanguage, private readonly array $attributeConstraints, private readonly array $options, - ) { - } + ) {} /** * Create a trigger for HTML/SVG tags. diff --git a/src/Embedded/EmbeddedTriggerType.php b/src/Embedded/EmbeddedTriggerType.php index fcd75aa..75cb0be 100644 --- a/src/Embedded/EmbeddedTriggerType.php +++ b/src/Embedded/EmbeddedTriggerType.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/src/Exception/LanguageNotFoundException.php b/src/Exception/LanguageNotFoundException.php index f0c0d9c..03bda4a 100644 --- a/src/Exception/LanguageNotFoundException.php +++ b/src/Exception/LanguageNotFoundException.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -23,7 +23,7 @@ final class LanguageNotFoundException extends \Exception public function __construct(string $language) { parent::__construct( - sprintf('Language "%s" is not supported or could not be found.', $language) + sprintf('Language "%s" is not supported or could not be found.', $language), ); } } diff --git a/src/Exception/ParseException.php b/src/Exception/ParseException.php index 6329b81..fd9e2fa 100644 --- a/src/Exception/ParseException.php +++ b/src/Exception/ParseException.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/src/Highlighter.php b/src/Highlighter.php index 5d3a8b4..676ff0a 100644 --- a/src/Highlighter.php +++ b/src/Highlighter.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -31,12 +31,16 @@ */ final class Highlighter implements HighlighterInterface { - /** @var array */ + /** + * @var array + */ private array $languages = []; private EmbeddedLanguageRegistry $embeddedRegistry; - /** @var array */ + /** + * @var array + */ private array $embeddedLanguageToggles = []; /** @@ -81,7 +85,7 @@ public function highlight( // Handle php-snippet specially if ('php-snippet' === $language) { - $code = 'getIdentifier(); $triggers = array_filter($plan->getTriggers(), function ($trigger) use ($host) { - $key = $host.':'.$trigger->targetLanguage; + $key = $host . ':' . $trigger->targetLanguage; return $this->embeddedLanguageToggles[$key] ?? true; }); @@ -148,7 +152,7 @@ private function parseWithLanguage(LanguageInterface $language, string $code): P // Handle PHP code without opening tag (common in markdown code blocks) $phpTagAdded = false; if ('php' === $identifier && !str_starts_with(ltrim($embeddedCode), 'embeddedLanguageToggles[strtolower($host).':'.strtolower($target)] = $enabled; + $this->embeddedLanguageToggles[strtolower($host) . ':' . strtolower($target)] = $enabled; } /** @@ -218,7 +222,7 @@ private function format( $html = sprintf( '
',
             $this->joinCssClasses($preClasses),
-            $this->formatClassAttribute($codeClasses)
+            $this->formatClassAttribute($codeClasses),
         );
 
         $currentLine = 1;
@@ -275,7 +279,7 @@ private function detectLanguageClass(string $language): ?string
             return null;
         }
 
-        return 'language-'.$language;
+        return 'language-' . $language;
     }
 
     private function detectVendorContainerClass(): ?string
@@ -306,7 +310,7 @@ private function formatClassAttribute(array $classes): string
     {
         $class = $this->joinCssClasses($classes);
 
-        return '' === $class ? '' : ' class="'.$class.'"';
+        return '' === $class ? '' : ' class="' . $class . '"';
     }
 
     /**
diff --git a/src/HighlighterInterface.php b/src/HighlighterInterface.php
index 38fe90f..d24778f 100644
--- a/src/HighlighterInterface.php
+++ b/src/HighlighterInterface.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/src/Language/BashLanguage.php b/src/Language/BashLanguage.php
index c594ee5..f40267e 100644
--- a/src/Language/BashLanguage.php
+++ b/src/Language/BashLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -29,6 +29,8 @@
  * - Context-aware parsing may need implementation
  * - Test coverage should be verified
  * - Comment syntax should be validated
+ *
+ * @author Simon André 
  */
 final class BashLanguage implements LanguageInterface
 {
@@ -188,7 +190,7 @@ private function parseDoubleQuotedString(string $code, int &$position): string
             }
 
             if ('\\' === $code[$position] && $position + 1 < strlen($code)) {
-                $string .= $code[$position].$code[$position + 1];
+                $string .= $code[$position] . $code[$position + 1];
                 $position += 2;
                 continue;
             }
@@ -229,7 +231,7 @@ private function parseHereDoc(string $code, int &$position): string
     {
         $hereDoc = '';
         // Skip <<
-        $hereDoc .= $code[$position].$code[$position + 1];
+        $hereDoc .= $code[$position] . $code[$position + 1];
         $position += 2;
 
         // Skip optional dash
@@ -356,7 +358,7 @@ private function parseCommandSubstitution(string $code, int &$position): string
 
             while ($position < strlen($code) && '`' !== $code[$position]) {
                 if ('\\' === $code[$position] && $position + 1 < strlen($code)) {
-                    $subst .= $code[$position].$code[$position + 1];
+                    $subst .= $code[$position] . $code[$position + 1];
                     $position += 2;
                 } else {
                     $subst .= $code[$position];
diff --git a/src/Language/CSharp/CSharpLexer.php b/src/Language/CSharp/CSharpLexer.php
index 0a77202..f2536c1 100644
--- a/src/Language/CSharp/CSharpLexer.php
+++ b/src/Language/CSharp/CSharpLexer.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -20,6 +20,8 @@
  * Does not assign semantic meaning — that is the SemanticParser's job.
  *
  * @internal
+ *
+ * @author Simon André 
  */
 final class CSharpLexer
 {
@@ -130,7 +132,7 @@ public function tokenize(string $code): array
                 $prefix = substr($code, $position, 2);
                 $position += 2;
                 $string = $this->parseVerbatimString($code, $position);
-                $tokens[] = new CSharpToken($prefix.$string, CSharpTokenType::VerbatimString);
+                $tokens[] = new CSharpToken($prefix . $string, CSharpTokenType::VerbatimString);
                 $position += strlen($string);
                 continue;
             }
diff --git a/src/Language/CSharp/CSharpSemanticParser.php b/src/Language/CSharp/CSharpSemanticParser.php
index ce1c98d..038e90a 100644
--- a/src/Language/CSharp/CSharpSemanticParser.php
+++ b/src/Language/CSharp/CSharpSemanticParser.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -24,6 +24,8 @@
  * references, and handles special scopes based on parser state.
  *
  * @internal
+ *
+ * @author Simon André 
  */
 final class CSharpSemanticParser
 {
diff --git a/src/Language/CSharp/CSharpState.php b/src/Language/CSharp/CSharpState.php
index 36f728e..9009716 100644
--- a/src/Language/CSharp/CSharpState.php
+++ b/src/Language/CSharp/CSharpState.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * Parser state machine states for C# semantic analysis.
+ *
+ * @author Simon André 
  */
 enum CSharpState
 {
diff --git a/src/Language/CSharp/CSharpToken.php b/src/Language/CSharp/CSharpToken.php
index 650f4a2..cb075a7 100644
--- a/src/Language/CSharp/CSharpToken.php
+++ b/src/Language/CSharp/CSharpToken.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,12 +15,13 @@
 
 /**
  * Represents a token produced by the C# lexer.
+ *
+ * @author Simon André 
  */
 final readonly class CSharpToken
 {
     public function __construct(
         public string $text,
         public CSharpTokenType $type,
-    ) {
-    }
+    ) {}
 }
diff --git a/src/Language/CSharp/CSharpTokenType.php b/src/Language/CSharp/CSharpTokenType.php
index e3fc5d5..bea9faa 100644
--- a/src/Language/CSharp/CSharpTokenType.php
+++ b/src/Language/CSharp/CSharpTokenType.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * Token types produced by the C# lexer.
+ *
+ * @author Simon André 
  */
 enum CSharpTokenType
 {
diff --git a/src/Language/CSharpLanguage.php b/src/Language/CSharpLanguage.php
index 6f5f9fe..25635a7 100644
--- a/src/Language/CSharpLanguage.php
+++ b/src/Language/CSharpLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -22,6 +22,8 @@
  *
  * Uses a two-pass parser to semantically distinguish function definitions
  * from calls and class declarations from references.
+ *
+ * @author Simon André 
  */
 final class CSharpLanguage implements LanguageInterface
 {
diff --git a/src/Language/CssLanguage.php b/src/Language/CssLanguage.php
index 17e1be6..9ff5b20 100644
--- a/src/Language/CssLanguage.php
+++ b/src/Language/CssLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -21,6 +21,8 @@
  * CSS language parser.
  *
  * Handles parsing and semantic analysis of CSS code.
+ *
+ * @author Simon André 
  */
 class CssLanguage implements LanguageInterface
 {
diff --git a/src/Language/DiffLanguage.php b/src/Language/DiffLanguage.php
index 6eef62b..5e7eada 100644
--- a/src/Language/DiffLanguage.php
+++ b/src/Language/DiffLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -21,6 +21,8 @@
  * Unified diff format language parser.
  *
  * Handles parsing of diff/patch files with line-by-line scope assignment.
+ *
+ * @author Simon André 
  */
 final class DiffLanguage implements LanguageInterface
 {
diff --git a/src/Language/DockerfileLanguage.php b/src/Language/DockerfileLanguage.php
index 277de88..3287740 100644
--- a/src/Language/DockerfileLanguage.php
+++ b/src/Language/DockerfileLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -17,6 +17,9 @@
 use Alto\Code\Highlight\Parser\ParsedToken;
 use Alto\Code\Highlight\Scope;
 
+/**
+ * @author Simon André 
+ */
 final class DockerfileLanguage implements LanguageInterface
 {
     private const INSTRUCTIONS = [
diff --git a/src/Language/DotEnvLanguage.php b/src/Language/DotEnvLanguage.php
index d270a66..df275fc 100644
--- a/src/Language/DotEnvLanguage.php
+++ b/src/Language/DotEnvLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -26,6 +26,8 @@
  * - KEY=value pairs
  * - Variable references (${VAR} and $VAR)
  * - Quoted strings and boolean/null values
+ *
+ * @author Simon André 
  */
 final class DotEnvLanguage implements LanguageInterface
 {
diff --git a/src/Language/EmbeddedLanguageCapable.php b/src/Language/EmbeddedLanguageCapable.php
index d0abf56..8eca342 100644
--- a/src/Language/EmbeddedLanguageCapable.php
+++ b/src/Language/EmbeddedLanguageCapable.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -18,6 +18,8 @@
 /**
  * Marker interface for languages that can delegate portions of their source
  * to other language parsers (e.g., HTML embedding CSS or JavaScript).
+ *
+ * @author Simon André 
  */
 interface EmbeddedLanguageCapable extends LanguageInterface
 {
diff --git a/src/Language/EmbeddedLanguageContext.php b/src/Language/EmbeddedLanguageContext.php
index 8314b42..652fb7d 100644
--- a/src/Language/EmbeddedLanguageContext.php
+++ b/src/Language/EmbeddedLanguageContext.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -25,12 +25,16 @@
  * - Circular dependency detection (prevents infinite loops)
  * - Error boundaries (graceful fallback on parse failures)
  * - Nesting depth limits (prevents excessive recursion)
+ *
+ * @author Simon André 
  */
 final class EmbeddedLanguageContext
 {
     private const MAX_EMBEDDING_DEPTH = 10;
 
-    /** @var list Stack of currently embedding languages */
+    /**
+     * @var list Stack of currently embedding languages
+     */
     private array $embeddingStack = [];
 
     private int $currentDepth = 0;
@@ -41,8 +45,7 @@ final class EmbeddedLanguageContext
     private function __construct(
         private readonly ?\Closure $resolver,
         private readonly ?EmbeddedLanguagePlan $plan,
-    ) {
-    }
+    ) {}
 
     /**
      * Create a context that disables embedding entirely.
@@ -95,7 +98,7 @@ public function parseEmbedded(string $language, string $code): ParsedStream
         if (in_array($language, $this->embeddingStack, true)) {
             return $this->createFallbackStream(
                 $code,
-                "Circular embedding detected: {$language} is already in the embedding stack"
+                "Circular embedding detected: {$language} is already in the embedding stack",
             );
         }
 
@@ -103,7 +106,7 @@ public function parseEmbedded(string $language, string $code): ParsedStream
         if ($this->currentDepth >= self::MAX_EMBEDDING_DEPTH) {
             return $this->createFallbackStream(
                 $code,
-                'Maximum embedding depth ({self::MAX_EMBEDDING_DEPTH}) exceeded'
+                'Maximum embedding depth ({self::MAX_EMBEDDING_DEPTH}) exceeded',
             );
         }
 
diff --git a/src/Language/Go/GoLexer.php b/src/Language/Go/GoLexer.php
index 132da81..4e81ad4 100644
--- a/src/Language/Go/GoLexer.php
+++ b/src/Language/Go/GoLexer.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -20,6 +20,8 @@
  * Does not assign semantic meaning — that is the SemanticParser's job.
  *
  * @internal
+ *
+ * @author Simon André 
  */
 final class GoLexer
 {
diff --git a/src/Language/Go/GoSemanticParser.php b/src/Language/Go/GoSemanticParser.php
index 1c1fd79..8ff0758 100644
--- a/src/Language/Go/GoSemanticParser.php
+++ b/src/Language/Go/GoSemanticParser.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -24,6 +24,8 @@
  * references, and handles Go's method receiver syntax: func (r *T) Method().
  *
  * @internal
+ *
+ * @author Simon André 
  */
 final class GoSemanticParser
 {
@@ -46,10 +48,14 @@ final class GoSemanticParser
 
     private const array BUILTIN_CONSTANTS = ['iota'];
 
-    /** @var array */
+    /**
+     * @var array
+     */
     private const array DECLARATION_KEYWORDS = ['func', 'type', 'var', 'const', 'import', 'package', 'interface', 'struct', 'chan', 'map'];
 
-    /** @var array */
+    /**
+     * @var array
+     */
     private const array CONTROL_KEYWORDS = ['if', 'else', 'for', 'range', 'switch', 'case', 'default', 'break', 'continue', 'goto', 'fallthrough', 'return', 'select', 'go', 'defer'];
 
     /**
diff --git a/src/Language/Go/GoState.php b/src/Language/Go/GoState.php
index f6b6756..c266af8 100644
--- a/src/Language/Go/GoState.php
+++ b/src/Language/Go/GoState.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * Parser state machine states for Go semantic analysis.
+ *
+ * @author Simon André 
  */
 enum GoState
 {
diff --git a/src/Language/Go/GoToken.php b/src/Language/Go/GoToken.php
index 57f3987..be22f80 100644
--- a/src/Language/Go/GoToken.php
+++ b/src/Language/Go/GoToken.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,12 +15,13 @@
 
 /**
  * Represents a token produced by the Go lexer.
+ *
+ * @author Simon André 
  */
 final readonly class GoToken
 {
     public function __construct(
         public string $text,
         public GoTokenType $type,
-    ) {
-    }
+    ) {}
 }
diff --git a/src/Language/Go/GoTokenType.php b/src/Language/Go/GoTokenType.php
index 1ae2a4e..676c973 100644
--- a/src/Language/Go/GoTokenType.php
+++ b/src/Language/Go/GoTokenType.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * Token types produced by the Go lexer.
+ *
+ * @author Simon André 
  */
 enum GoTokenType
 {
diff --git a/src/Language/GoLanguage.php b/src/Language/GoLanguage.php
index 9448109..51caa61 100644
--- a/src/Language/GoLanguage.php
+++ b/src/Language/GoLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -23,6 +23,8 @@
  * Uses a two-pass parser to semantically distinguish function definitions
  * from calls and type declarations from references, including Go's method
  * receiver syntax: func (r *Receiver) MethodName().
+ *
+ * @author Simon André 
  */
 final class GoLanguage implements LanguageInterface
 {
diff --git a/src/Language/HtmlLanguage.php b/src/Language/HtmlLanguage.php
index 58b079f..61cbb27 100644
--- a/src/Language/HtmlLanguage.php
+++ b/src/Language/HtmlLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -21,6 +21,8 @@
  * HTML language parser.
  *
  * Handles parsing and semantic analysis of HTML code.
+ *
+ * @author Simon André 
  */
 class HtmlLanguage implements EmbeddedLanguageCapable
 {
@@ -275,7 +277,7 @@ private function resolveEmbeddedLanguage(string $tagName, array $attributes, Emb
     private function extractEmbeddedContent(string $code, int &$position, string $tagName): string
     {
         $length = strlen($code);
-        $closingSequence = '
  */
 final class HttpLanguage implements LanguageInterface
 {
@@ -176,7 +178,7 @@ private function parseUrl(string $url, array &$tokens): void
         // Check for full URL with scheme
         if (preg_match('/^(https?):\/\/([^\/:]+)(:\d+)?(\/[^?\#]*)?(\?[^\#]*)?(\#.*)?$/', $url, $matches)) {
             // Scheme
-            $tokens[] = new ParsedToken($matches[1].'://', Scope::Keyword);
+            $tokens[] = new ParsedToken($matches[1] . '://', Scope::Keyword);
 
             // Host
             $tokens[] = new ParsedToken($matches[2], Scope::FunctionCall);
@@ -336,7 +338,7 @@ private function parseContentType(string $value, array &$tokens): void
                     $tokens[] = new ParsedToken($matches[3], Scope::Operator);
                     $tokens[] = new ParsedToken($matches[4], Scope::String);
                 } else {
-                    $tokens[] = new ParsedToken(' '.$part, Scope::String);
+                    $tokens[] = new ParsedToken(' ' . $part, Scope::String);
                 }
             }
         }
diff --git a/src/Language/IniLanguage.php b/src/Language/IniLanguage.php
index 8628561..6a4c717 100644
--- a/src/Language/IniLanguage.php
+++ b/src/Language/IniLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -30,6 +30,8 @@
  * - Boolean/null values: true, false, yes, no, on, off, null, none
  * - Numbers: integers and floats
  * - Environment variable references: ${VAR} or %VAR%
+ *
+ * @author Simon André 
  */
 final class IniLanguage implements LanguageInterface
 {
diff --git a/src/Language/Java/JavaLexer.php b/src/Language/Java/JavaLexer.php
index 160d018..cfecd6b 100644
--- a/src/Language/Java/JavaLexer.php
+++ b/src/Language/Java/JavaLexer.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -20,6 +20,8 @@
  * Does not assign semantic meaning — that is the SemanticParser's job.
  *
  * @internal
+ *
+ * @author Simon André 
  */
 final class JavaLexer
 {
diff --git a/src/Language/Java/JavaSemanticParser.php b/src/Language/Java/JavaSemanticParser.php
index 3ec3386..fe65412 100644
--- a/src/Language/Java/JavaSemanticParser.php
+++ b/src/Language/Java/JavaSemanticParser.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -24,6 +24,8 @@
  * definitions from calls, and tracks semantic context through brace depth.
  *
  * @internal
+ *
+ * @author Simon André 
  */
 final class JavaSemanticParser
 {
diff --git a/src/Language/Java/JavaState.php b/src/Language/Java/JavaState.php
index 6da365f..7e00874 100644
--- a/src/Language/Java/JavaState.php
+++ b/src/Language/Java/JavaState.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * Parser state machine states for Java semantic analysis.
+ *
+ * @author Simon André 
  */
 enum JavaState
 {
diff --git a/src/Language/Java/JavaToken.php b/src/Language/Java/JavaToken.php
index 1431d05..99d40da 100644
--- a/src/Language/Java/JavaToken.php
+++ b/src/Language/Java/JavaToken.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,12 +15,13 @@
 
 /**
  * Represents a token produced by the Java lexer.
+ *
+ * @author Simon André 
  */
 final readonly class JavaToken
 {
     public function __construct(
         public string $text,
         public JavaTokenType $type,
-    ) {
-    }
+    ) {}
 }
diff --git a/src/Language/Java/JavaTokenType.php b/src/Language/Java/JavaTokenType.php
index 3236331..5de48b6 100644
--- a/src/Language/Java/JavaTokenType.php
+++ b/src/Language/Java/JavaTokenType.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * Token types produced by the Java lexer.
+ *
+ * @author Simon André 
  */
 enum JavaTokenType
 {
diff --git a/src/Language/JavaLanguage.php b/src/Language/JavaLanguage.php
index c9bcbf6..221e8cd 100644
--- a/src/Language/JavaLanguage.php
+++ b/src/Language/JavaLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -23,6 +23,8 @@
  * Uses a two-pass parser to semantically distinguish function definitions
  * from calls, type declarations from references, and track context
  * through brace depth for accurate scope assignment.
+ *
+ * @author Simon André 
  */
 final class JavaLanguage implements LanguageInterface
 {
diff --git a/src/Language/JavaScript/JavaScriptLexer.php b/src/Language/JavaScript/JavaScriptLexer.php
index aa1de5f..fab0539 100644
--- a/src/Language/JavaScript/JavaScriptLexer.php
+++ b/src/Language/JavaScript/JavaScriptLexer.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -22,6 +22,8 @@
  * @internal
  *
  * @final Not declared final to allow test doubles, but treat as final in production code
+ *
+ * @author Simon André 
  */
 class JavaScriptLexer
 {
diff --git a/src/Language/JavaScript/JavaScriptSemanticParser.php b/src/Language/JavaScript/JavaScriptSemanticParser.php
index b69a217..faa348d 100644
--- a/src/Language/JavaScript/JavaScriptSemanticParser.php
+++ b/src/Language/JavaScript/JavaScriptSemanticParser.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -26,12 +26,16 @@
  * @internal
  *
  * @final Not declared final to allow test doubles, but treat as final in production code
+ *
+ * @author Simon André 
  */
 class JavaScriptSemanticParser
 {
     private JavaScriptState $state = JavaScriptState::TopLevel;
 
-    /** @var list */
+    /**
+     * @var list
+     */
     private array $stateStack = [];
 
     /**
@@ -240,10 +244,6 @@ private function pushState(JavaScriptState $state): void
 
     private function popState(): void
     {
-        if (!empty($this->stateStack)) {
-            $this->state = array_pop($this->stateStack);
-        } else {
-            $this->state = JavaScriptState::TopLevel;
-        }
+        $this->state = array_pop($this->stateStack) ?? JavaScriptState::TopLevel;
     }
 }
diff --git a/src/Language/JavaScript/JavaScriptState.php b/src/Language/JavaScript/JavaScriptState.php
index ec20c31..3825e0f 100644
--- a/src/Language/JavaScript/JavaScriptState.php
+++ b/src/Language/JavaScript/JavaScriptState.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * Parser state machine for JavaScript semantic analysis.
+ *
+ * @author Simon André 
  */
 enum JavaScriptState
 {
diff --git a/src/Language/JavaScript/JavaScriptToken.php b/src/Language/JavaScript/JavaScriptToken.php
index 5d59240..4002dfc 100644
--- a/src/Language/JavaScript/JavaScriptToken.php
+++ b/src/Language/JavaScript/JavaScriptToken.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,12 +15,13 @@
 
 /**
  * Represents a token from the JavaScript lexer.
+ *
+ * @author Simon André 
  */
 final readonly class JavaScriptToken
 {
     public function __construct(
         public string $text,
         public JavaScriptTokenType $type,
-    ) {
-    }
+    ) {}
 }
diff --git a/src/Language/JavaScript/JavaScriptTokenType.php b/src/Language/JavaScript/JavaScriptTokenType.php
index 170b47c..af546d3 100644
--- a/src/Language/JavaScript/JavaScriptTokenType.php
+++ b/src/Language/JavaScript/JavaScriptTokenType.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * Token types from the JavaScript lexer.
+ *
+ * @author Simon André 
  */
 enum JavaScriptTokenType
 {
diff --git a/src/Language/JavaScriptLanguage.php b/src/Language/JavaScriptLanguage.php
index 363fdbe..dbaecc0 100644
--- a/src/Language/JavaScriptLanguage.php
+++ b/src/Language/JavaScriptLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -27,6 +27,8 @@
  * Uses a two-pass architecture:
  * - Pass 1 (Lexer): Tokenization
  * - Pass 2 (Semantic Parser): Context-aware scope assignment
+ *
+ * @author Simon André 
  */
 class JavaScriptLanguage implements LanguageInterface
 {
@@ -54,7 +56,7 @@ public function parse(string $code): ParsedStream
             // Pass 2: Semantic analysis
             return $this->parser->parse($tokens);
         } catch (\Throwable $e) {
-            throw new ParseException('Failed to parse JavaScript code: '.$e->getMessage());
+            throw new ParseException('Failed to parse JavaScript code: ' . $e->getMessage());
         }
     }
 }
diff --git a/src/Language/JsonLanguage.php b/src/Language/JsonLanguage.php
index 1d936a9..fed1023 100644
--- a/src/Language/JsonLanguage.php
+++ b/src/Language/JsonLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -21,6 +21,8 @@
  * JSON language parser.
  *
  * Handles parsing and semantic analysis of JSON code.
+ *
+ * @author Simon André 
  */
 final class JsonLanguage implements LanguageInterface
 {
diff --git a/src/Language/LanguageInterface.php b/src/Language/LanguageInterface.php
index 96a25ea..ea14939 100644
--- a/src/Language/LanguageInterface.php
+++ b/src/Language/LanguageInterface.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -20,6 +20,8 @@
  *
  * Each supported language implements this interface to provide
  * its own lexing and semantic parsing logic.
+ *
+ * @author Simon André 
  */
 interface LanguageInterface
 {
diff --git a/src/Language/Languages.php b/src/Language/Languages.php
index 683cb0c..cc5b358 100644
--- a/src/Language/Languages.php
+++ b/src/Language/Languages.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -13,6 +13,9 @@
 
 namespace Alto\Code\Highlight\Language;
 
+/**
+ * @author Simon André 
+ */
 final class Languages
 {
     /**
diff --git a/src/Language/MakefileLanguage.php b/src/Language/MakefileLanguage.php
index 8d8deba..246d0bf 100644
--- a/src/Language/MakefileLanguage.php
+++ b/src/Language/MakefileLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -22,6 +22,8 @@
  *
  * Handles Makefile syntax including targets, dependencies, variables,
  * commands, directives, and functions.
+ *
+ * @author Simon André 
  */
 final class MakefileLanguage implements LanguageInterface
 {
@@ -77,7 +79,7 @@ public function parse(string $code): ParsedStream
 
                 // Automatic variables
                 if ('$' === $char && $position + 1 < $length && preg_match('/[@%<^+?*]/', $line[$position + 1])) {
-                    $tokens[] = new ParsedToken($char.$line[$position + 1], Scope::Variable);
+                    $tokens[] = new ParsedToken($char . $line[$position + 1], Scope::Variable);
                     $position += 2;
 
                     continue;
@@ -196,7 +198,7 @@ private function parseVariableReference(string $line, int $position): string
     {
         $openChar = $line[$position + 1];
         $closeChar = '(' === $openChar ? ')' : '}';
-        $varRef = '$'.$openChar;
+        $varRef = '$' . $openChar;
         $position += 2;
         $length = strlen($line);
         $depth = 1;
diff --git a/src/Language/MarkdownLanguage.php b/src/Language/MarkdownLanguage.php
index f2155fe..c94fafa 100644
--- a/src/Language/MarkdownLanguage.php
+++ b/src/Language/MarkdownLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -21,6 +21,8 @@
  * Markdown language parser.
  *
  * Supports CommonMark and GitHub Flavored Markdown.
+ *
+ * @author Simon André 
  */
 final class MarkdownLanguage implements LanguageInterface, EmbeddedLanguageCapable
 {
@@ -188,7 +190,7 @@ private function parseInline(string $text, StreamBuilder $stream): void
             // Bold: **text** or __text__
             if (($position + 1 < $length && '*' === $text[$position] && '*' === $text[$position + 1])
                 || ($position + 1 < $length && '_' === $text[$position] && '_' === $text[$position + 1])) {
-                $delimiter = $text[$position].$text[$position + 1];
+                $delimiter = $text[$position] . $text[$position + 1];
                 $end = strpos($text, $delimiter, $position + 2);
                 if (false !== $end) {
                     $content = substr($text, $position, $end - $position + 2);
diff --git a/src/Language/Php/PhpLexer.php b/src/Language/Php/PhpLexer.php
index 7d8c1d3..12ff160 100644
--- a/src/Language/Php/PhpLexer.php
+++ b/src/Language/Php/PhpLexer.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -25,6 +25,8 @@
  * @internal
  *
  * @final Not declared final to allow test doubles, but treat as final in production code
+ *
+ * @author Simon André 
  */
 class PhpLexer
 {
diff --git a/src/Language/Php/PhpSemanticParser.php b/src/Language/Php/PhpSemanticParser.php
index 3183551..275f157 100644
--- a/src/Language/Php/PhpSemanticParser.php
+++ b/src/Language/Php/PhpSemanticParser.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -29,6 +29,8 @@
  * @internal
  *
  * @final Not declared final to allow test doubles, but treat as final in production code
+ *
+ * @author Simon André 
  */
 class PhpSemanticParser
 {
@@ -60,7 +62,9 @@ class PhpSemanticParser
 
     private PhpState $state = PhpState::TopLevel;
 
-    /** @var list */
+    /**
+     * @var list
+     */
     private array $stateStack = [];
 
     /**
@@ -410,11 +414,7 @@ private function pushState(PhpState $state): void
      */
     private function popState(): void
     {
-        if (!empty($this->stateStack)) {
-            $this->state = array_pop($this->stateStack);
-        } else {
-            $this->state = PhpState::TopLevel;
-        }
+        $this->state = array_pop($this->stateStack) ?? PhpState::TopLevel;
     }
 
     /**
diff --git a/src/Language/Php/PhpState.php b/src/Language/Php/PhpState.php
index 4c5f76c..b001f93 100644
--- a/src/Language/Php/PhpState.php
+++ b/src/Language/Php/PhpState.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -18,6 +18,8 @@
  *
  * The semantic parser maintains a state to track context and determine
  * the semantic meaning of tokens.
+ *
+ * @author Simon André 
  */
 enum PhpState
 {
diff --git a/src/Language/PhpLanguage.php b/src/Language/PhpLanguage.php
index d52655b..52e4153 100644
--- a/src/Language/PhpLanguage.php
+++ b/src/Language/PhpLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -22,6 +22,8 @@
  * PHP language parser.
  *
  * Handles parsing and semantic analysis of PHP code.
+ *
+ * @author Simon André 
  */
 final class PhpLanguage implements LanguageInterface
 {
@@ -49,7 +51,7 @@ public function parse(string $code): ParsedStream
             // Pass 2: Semantic analysis
             return $this->parser->parse($tokens);
         } catch (\Throwable $e) {
-            throw new ParseException('Failed to parse PHP code: '.$e->getMessage());
+            throw new ParseException('Failed to parse PHP code: ' . $e->getMessage());
         }
     }
 }
diff --git a/src/Language/Python/PythonLexer.php b/src/Language/Python/PythonLexer.php
index edae2bd..4f20435 100644
--- a/src/Language/Python/PythonLexer.php
+++ b/src/Language/Python/PythonLexer.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -20,6 +20,8 @@
  * Does not assign semantic meaning — that is the SemanticParser's job.
  *
  * @internal
+ *
+ * @author Simon André 
  */
 final class PythonLexer
 {
@@ -164,11 +166,11 @@ public function tokenize(string $code): array
                     if ($position + 2 < $length && $char === $code[$position + 1] && $char === $code[$position + 2]) {
                         $tripleQuote = substr($code, $position, 3);
                         $string = $this->parseTripleQuotedString($code, $position, $tripleQuote);
-                        $tokens[] = new PythonToken($identifier.$string, PythonTokenType::String);
+                        $tokens[] = new PythonToken($identifier . $string, PythonTokenType::String);
                         $position += strlen($string);
                     } else {
                         $string = $this->parseQuotedString($code, $position, $quote);
-                        $tokens[] = new PythonToken($identifier.$string, PythonTokenType::String);
+                        $tokens[] = new PythonToken($identifier . $string, PythonTokenType::String);
                         $position += strlen($string);
                     }
                 } else {
diff --git a/src/Language/Python/PythonSemanticParser.php b/src/Language/Python/PythonSemanticParser.php
index b863df5..267f06f 100644
--- a/src/Language/Python/PythonSemanticParser.php
+++ b/src/Language/Python/PythonSemanticParser.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -24,6 +24,8 @@
  * references, and handles special variables like 'self'.
  *
  * @internal
+ *
+ * @author Simon André 
  */
 final class PythonSemanticParser
 {
diff --git a/src/Language/Python/PythonState.php b/src/Language/Python/PythonState.php
index c359208..a9cd86a 100644
--- a/src/Language/Python/PythonState.php
+++ b/src/Language/Python/PythonState.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * Parser state machine states for Python semantic analysis.
+ *
+ * @author Simon André 
  */
 enum PythonState
 {
diff --git a/src/Language/Python/PythonToken.php b/src/Language/Python/PythonToken.php
index a578854..7c91950 100644
--- a/src/Language/Python/PythonToken.php
+++ b/src/Language/Python/PythonToken.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,12 +15,13 @@
 
 /**
  * Represents a token produced by the Python lexer.
+ *
+ * @author Simon André 
  */
 final readonly class PythonToken
 {
     public function __construct(
         public string $text,
         public PythonTokenType $type,
-    ) {
-    }
+    ) {}
 }
diff --git a/src/Language/Python/PythonTokenType.php b/src/Language/Python/PythonTokenType.php
index b3e8695..3e1a571 100644
--- a/src/Language/Python/PythonTokenType.php
+++ b/src/Language/Python/PythonTokenType.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * Token types produced by the Python lexer.
+ *
+ * @author Simon André 
  */
 enum PythonTokenType
 {
diff --git a/src/Language/PythonLanguage.php b/src/Language/PythonLanguage.php
index 55f40b7..79078b1 100644
--- a/src/Language/PythonLanguage.php
+++ b/src/Language/PythonLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -22,6 +22,8 @@
  *
  * Uses a two-pass parser to semantically distinguish function definitions
  * from calls and class declarations from references.
+ *
+ * @author Simon André 
  */
 final class PythonLanguage implements LanguageInterface
 {
diff --git a/src/Language/Ruby/RubyLexer.php b/src/Language/Ruby/RubyLexer.php
index be1a3b4..403c1d9 100644
--- a/src/Language/Ruby/RubyLexer.php
+++ b/src/Language/Ruby/RubyLexer.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -22,6 +22,8 @@
  * @internal
  *
  * @final Not declared final to allow test doubles, but treat as final in production code
+ *
+ * @author Simon André 
  */
 class RubyLexer
 {
@@ -207,14 +209,14 @@ public function tokenize(string $code): array
 
             // Multi-character operators
             if ($position + 1 < $length) {
-                $two = $char.$code[$position + 1];
+                $two = $char . $code[$position + 1];
                 if (in_array($two, ['::', '..', '...', '<=', '>=', '==', '!=', '=~', '!~', '&&', '||', '**', '+=', '-=', '*=', '/=', '%=', '**=', '&&=', '||=', '&=', '|=', '^=', '<<=', '>>=', '<<', '>>', '->', '=>', '<=>', '!~'], true)) {
                     // Three-char check
                     if (in_array($two, ['...', '**=', '&&=', '||=', '<<=', '>>='], true)) {
                         // Already 3-char in the list above — handled below
                     }
                     if ($position + 2 < $length) {
-                        $three = $two.$code[$position + 2];
+                        $three = $two . $code[$position + 2];
                         if (in_array($three, ['...', '**=', '&&=', '||=', '<<=', '>>='], true)) {
                             $tokens[] = new RubyToken($three, RubyTokenType::Operator);
                             $position += 3;
@@ -289,7 +291,7 @@ private function parseHeredoc(string $code, int &$position): ?string
         }
 
         // Read to end of current line (the < '>',
             default => $open,
         };
-        $literal .= $type.$open;
+        $literal .= $type . $open;
         ++$position;
 
         $depth = 1;
         while ($position < $length && $depth > 0) {
             $char = $code[$position];
             if ('\\' === $char && $position + 1 < $length) {
-                $literal .= $char.$code[$position + 1];
+                $literal .= $char . $code[$position + 1];
                 $position += 2;
                 continue;
             }
diff --git a/src/Language/Ruby/RubySemanticParser.php b/src/Language/Ruby/RubySemanticParser.php
index 68f602a..229b720 100644
--- a/src/Language/Ruby/RubySemanticParser.php
+++ b/src/Language/Ruby/RubySemanticParser.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -25,6 +25,8 @@
  * @internal
  *
  * @final Not declared final to allow test doubles, but treat as final in production code
+ *
+ * @author Simon André 
  */
 class RubySemanticParser
 {
@@ -39,7 +41,9 @@ class RubySemanticParser
 
     private RubyState $state = RubyState::TopLevel;
 
-    /** @var list */
+    /**
+     * @var list
+     */
     private array $stateStack = [];
 
     /**
@@ -205,10 +209,6 @@ private function pushState(RubyState $state): void
 
     private function popState(): void
     {
-        if (!empty($this->stateStack)) {
-            $this->state = array_pop($this->stateStack);
-        } else {
-            $this->state = RubyState::TopLevel;
-        }
+        $this->state = array_pop($this->stateStack) ?? RubyState::TopLevel;
     }
 }
diff --git a/src/Language/Ruby/RubyState.php b/src/Language/Ruby/RubyState.php
index 137beac..c9ca870 100644
--- a/src/Language/Ruby/RubyState.php
+++ b/src/Language/Ruby/RubyState.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * Parser state machine for Ruby semantic analysis.
+ *
+ * @author Simon André 
  */
 enum RubyState
 {
diff --git a/src/Language/Ruby/RubyToken.php b/src/Language/Ruby/RubyToken.php
index 8ae8ac2..934504a 100644
--- a/src/Language/Ruby/RubyToken.php
+++ b/src/Language/Ruby/RubyToken.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,12 +15,13 @@
 
 /**
  * @internal
+ *
+ * @author Simon André 
  */
 final readonly class RubyToken
 {
     public function __construct(
         public string $text,
         public RubyTokenType $type,
-    ) {
-    }
+    ) {}
 }
diff --git a/src/Language/Ruby/RubyTokenType.php b/src/Language/Ruby/RubyTokenType.php
index d0aa8da..d2a3cb4 100644
--- a/src/Language/Ruby/RubyTokenType.php
+++ b/src/Language/Ruby/RubyTokenType.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * Token types produced by the Ruby lexer.
+ *
+ * @author Simon André 
  */
 enum RubyTokenType
 {
diff --git a/src/Language/RubyLanguage.php b/src/Language/RubyLanguage.php
index 114bdc3..c6b7e64 100644
--- a/src/Language/RubyLanguage.php
+++ b/src/Language/RubyLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -21,6 +21,8 @@
  * Ruby language highlighter.
  *
  * Two-pass semantic highlighter: lexer → semantic parser.
+ *
+ * @author Simon André 
  */
 final class RubyLanguage implements LanguageInterface
 {
diff --git a/src/Language/Rust/RustLexer.php b/src/Language/Rust/RustLexer.php
index d9ad245..dcdd28f 100644
--- a/src/Language/Rust/RustLexer.php
+++ b/src/Language/Rust/RustLexer.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -22,6 +22,8 @@
  * @internal
  *
  * @final Not declared final to allow test doubles, but treat as final in production code
+ *
+ * @author Simon André 
  */
 class RustLexer
 {
@@ -142,7 +144,7 @@ public function tokenize(string $code): array
             if ('b' === $char && $position + 1 < $length && ('"' === $code[$position + 1] || '\'' === $code[$position + 1])) {
                 $quote = $code[$position + 1];
                 if ('"' === $quote) {
-                    $str = 'b'.$this->parseQuotedString($code, $position + 1, '"');
+                    $str = 'b' . $this->parseQuotedString($code, $position + 1, '"');
                     $tokens[] = new RustToken($str, RustTokenType::String);
                     $position += strlen($str);
                     continue;
@@ -180,7 +182,7 @@ public function tokenize(string $code): array
 
                 // Macro invocation: identifier followed by !  (but not !=)
                 if ($position < $length && '!' === $code[$position] && ($position + 1 >= $length || '=' !== $code[$position + 1])) {
-                    $tokens[] = new RustToken($identifier.'!', RustTokenType::Macro);
+                    $tokens[] = new RustToken($identifier . '!', RustTokenType::Macro);
                     ++$position;
                     continue;
                 }
@@ -192,12 +194,12 @@ public function tokenize(string $code): array
 
             // Multi-character operators
             if ($position + 1 < $length) {
-                $two = $char.$code[$position + 1];
+                $two = $char . $code[$position + 1];
 
                 if (in_array($two, ['->', '=>', '::', '..', '&&', '||', '==', '!=', '<=', '>=', '+=', '-=', '*=', '/=', '%=', '&=', '|=', '^=', '<<', '>>', '..='], true)) {
                     // Three-char: ..= <<= >>=
                     if (in_array($two, ['..', '<<', '>>'], true) && $position + 2 < $length && '=' === $code[$position + 2]) {
-                        $tokens[] = new RustToken($two.'=', RustTokenType::Operator);
+                        $tokens[] = new RustToken($two . '=', RustTokenType::Operator);
                         $position += 3;
                         continue;
                     }
@@ -248,10 +250,10 @@ private function parseRawString(string $code, int &$position): ?string
             return null;
         }
 
-        $raw .= str_repeat('#', $hashes).'"';
+        $raw .= str_repeat('#', $hashes) . '"';
         ++$position;
 
-        $closing = '"'.str_repeat('#', $hashes);
+        $closing = '"' . str_repeat('#', $hashes);
         $closingLen = strlen($closing);
 
         while ($position < $length) {
@@ -324,11 +326,11 @@ private function parseLifetimeOrChar(string $code, int $position): RustToken
 
             // If followed by a closing quote, it's a char literal (e.g., 'a')
             if ($i < $length && '\'' === $code[$i] && 1 === strlen($content)) {
-                return new RustToken("'".$content."'", RustTokenType::Char);
+                return new RustToken("'" . $content . "'", RustTokenType::Char);
             }
 
             // Otherwise it's a lifetime: 'ident
-            return new RustToken("'".$content, RustTokenType::Lifetime);
+            return new RustToken("'" . $content, RustTokenType::Lifetime);
         }
 
         // Char literal: '\n', '\t', '\\', '\'' etc. or any single char
@@ -362,7 +364,7 @@ private function parseLifetimeOrChar(string $code, int $position): RustToken
 
         // Single char literal like '+'  or 'x'
         if ($position + 2 < $length && '\'' === $code[$position + 2]) {
-            return new RustToken("'".$next."'", RustTokenType::Char);
+            return new RustToken("'" . $next . "'", RustTokenType::Char);
         }
 
         // Fallback: bare '
diff --git a/src/Language/Rust/RustSemanticParser.php b/src/Language/Rust/RustSemanticParser.php
index ce7dcea..099e6ce 100644
--- a/src/Language/Rust/RustSemanticParser.php
+++ b/src/Language/Rust/RustSemanticParser.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -25,6 +25,8 @@
  * @internal
  *
  * @final Not declared final to allow test doubles, but treat as final in production code
+ *
+ * @author Simon André 
  */
 class RustSemanticParser
 {
@@ -48,7 +50,9 @@ class RustSemanticParser
 
     private RustState $state = RustState::TopLevel;
 
-    /** @var list */
+    /**
+     * @var list
+     */
     private array $stateStack = [];
 
     private int $attributeDepth = 0;
@@ -299,10 +303,6 @@ private function pushState(RustState $state): void
 
     private function popState(): void
     {
-        if (!empty($this->stateStack)) {
-            $this->state = array_pop($this->stateStack);
-        } else {
-            $this->state = RustState::TopLevel;
-        }
+        $this->state = array_pop($this->stateStack) ?? RustState::TopLevel;
     }
 }
diff --git a/src/Language/Rust/RustState.php b/src/Language/Rust/RustState.php
index 321d6a6..72754c3 100644
--- a/src/Language/Rust/RustState.php
+++ b/src/Language/Rust/RustState.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * Parser state machine for Rust semantic analysis.
+ *
+ * @author Simon André 
  */
 enum RustState
 {
diff --git a/src/Language/Rust/RustToken.php b/src/Language/Rust/RustToken.php
index e0f6395..6aab912 100644
--- a/src/Language/Rust/RustToken.php
+++ b/src/Language/Rust/RustToken.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,12 +15,13 @@
 
 /**
  * @internal
+ *
+ * @author Simon André 
  */
 final readonly class RustToken
 {
     public function __construct(
         public string $text,
         public RustTokenType $type,
-    ) {
-    }
+    ) {}
 }
diff --git a/src/Language/Rust/RustTokenType.php b/src/Language/Rust/RustTokenType.php
index 01e3e4f..507efb3 100644
--- a/src/Language/Rust/RustTokenType.php
+++ b/src/Language/Rust/RustTokenType.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * Token types produced by the Rust lexer.
+ *
+ * @author Simon André 
  */
 enum RustTokenType
 {
diff --git a/src/Language/RustLanguage.php b/src/Language/RustLanguage.php
index e789cca..461e071 100644
--- a/src/Language/RustLanguage.php
+++ b/src/Language/RustLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -21,6 +21,8 @@
  * Rust language highlighter.
  *
  * Two-pass semantic highlighter: lexer → semantic parser.
+ *
+ * @author Simon André 
  */
 final class RustLanguage implements LanguageInterface
 {
diff --git a/src/Language/ScssLanguage.php b/src/Language/ScssLanguage.php
index 9fab4f7..05c5481 100644
--- a/src/Language/ScssLanguage.php
+++ b/src/Language/ScssLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -21,6 +21,8 @@
  * SCSS language parser.
  *
  * Extends CSS with SCSS-specific features like variables, nesting, mixins, etc.
+ *
+ * @author Simon André 
  */
 final class ScssLanguage extends CssLanguage
 {
diff --git a/src/Language/SqlLanguage.php b/src/Language/SqlLanguage.php
index 9464ce4..8492754 100644
--- a/src/Language/SqlLanguage.php
+++ b/src/Language/SqlLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -19,6 +19,8 @@
 
 /**
  * SQL language parser.
+ *
+ * @author Simon André 
  */
 final class SqlLanguage implements LanguageInterface
 {
@@ -126,7 +128,7 @@ public function parse(string $code): ParsedStream
                     if ($code[$position] === $quote) {
                         // Handle escaped quote (e.g. "") inside
                         if ($position + 1 < $length && $code[$position + 1] === $quote) {
-                            $identifier .= $quote.$quote;
+                            $identifier .= $quote . $quote;
                             $position += 2;
                             continue;
                         }
diff --git a/src/Language/SvgLanguage.php b/src/Language/SvgLanguage.php
index cd5ae64..484cab0 100644
--- a/src/Language/SvgLanguage.php
+++ b/src/Language/SvgLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * SVG shares the same parsing rules as HTML but exposes a dedicated identifier.
+ *
+ * @author Simon André 
  */
 final class SvgLanguage extends HtmlLanguage
 {
diff --git a/src/Language/Swift/SwiftLexer.php b/src/Language/Swift/SwiftLexer.php
index aaf444b..b47c820 100644
--- a/src/Language/Swift/SwiftLexer.php
+++ b/src/Language/Swift/SwiftLexer.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -22,6 +22,8 @@
  * @internal
  *
  * @final Not declared final to allow test doubles, but treat as final in production code
+ *
+ * @author Simon André 
  */
 class SwiftLexer
 {
@@ -211,7 +213,7 @@ public function tokenize(string $code): array
             }
 
             if ($position + 1 < $length) {
-                $two = $char.$code[$position + 1];
+                $two = $char . $code[$position + 1];
                 if (in_array($two, ['->', '??', '?.', '..', '&&', '||', '==', '!=', '<=', '>=', '+=', '-=', '*=', '/=', '%=', '&=', '|=', '^=', '<<', '>>', '!~', '=~'], true)) {
                     $tokens[] = new SwiftToken($two, SwiftTokenType::Operator);
                     $position += 2;
@@ -255,7 +257,7 @@ private function parseMultilineString(string $code, int &$position): string
             }
 
             if ('\\' === $code[$position] && $position + 1 < $length) {
-                $str .= $code[$position].$code[$position + 1];
+                $str .= $code[$position] . $code[$position + 1];
                 $position += 2;
                 // Skip interpolation content \( ... )
                 if ('(' === $code[$position - 1]) {
@@ -282,7 +284,7 @@ private function parseString(string $code, int &$position): string
 
             if ('\\' === $char && $position + 1 < $length) {
                 $next = $code[$position + 1];
-                $str .= '\\'.$next;
+                $str .= '\\' . $next;
                 $position += 2;
 
                 // \(...) string interpolation — consume the expression as part of the string token
diff --git a/src/Language/Swift/SwiftSemanticParser.php b/src/Language/Swift/SwiftSemanticParser.php
index e56a7ff..7b20b45 100644
--- a/src/Language/Swift/SwiftSemanticParser.php
+++ b/src/Language/Swift/SwiftSemanticParser.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -25,6 +25,8 @@
  * @internal
  *
  * @final Not declared final to allow test doubles, but treat as final in production code
+ *
+ * @author Simon André 
  */
 class SwiftSemanticParser
 {
@@ -49,7 +51,9 @@ class SwiftSemanticParser
 
     private SwiftState $state = SwiftState::TopLevel;
 
-    /** @var list */
+    /**
+     * @var list
+     */
     private array $stateStack = [];
 
     /**
@@ -222,10 +226,6 @@ private function pushState(SwiftState $state): void
 
     private function popState(): void
     {
-        if (!empty($this->stateStack)) {
-            $this->state = array_pop($this->stateStack);
-        } else {
-            $this->state = SwiftState::TopLevel;
-        }
+        $this->state = array_pop($this->stateStack) ?? SwiftState::TopLevel;
     }
 }
diff --git a/src/Language/Swift/SwiftState.php b/src/Language/Swift/SwiftState.php
index 6cb34b8..81c4020 100644
--- a/src/Language/Swift/SwiftState.php
+++ b/src/Language/Swift/SwiftState.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * Parser state machine for Swift semantic analysis.
+ *
+ * @author Simon André 
  */
 enum SwiftState
 {
diff --git a/src/Language/Swift/SwiftToken.php b/src/Language/Swift/SwiftToken.php
index b978b25..5b90acf 100644
--- a/src/Language/Swift/SwiftToken.php
+++ b/src/Language/Swift/SwiftToken.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,12 +15,13 @@
 
 /**
  * @internal
+ *
+ * @author Simon André 
  */
 final readonly class SwiftToken
 {
     public function __construct(
         public string $text,
         public SwiftTokenType $type,
-    ) {
-    }
+    ) {}
 }
diff --git a/src/Language/Swift/SwiftTokenType.php b/src/Language/Swift/SwiftTokenType.php
index 014ee57..4367864 100644
--- a/src/Language/Swift/SwiftTokenType.php
+++ b/src/Language/Swift/SwiftTokenType.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * Token types produced by the Swift lexer.
+ *
+ * @author Simon André 
  */
 enum SwiftTokenType
 {
diff --git a/src/Language/SwiftLanguage.php b/src/Language/SwiftLanguage.php
index 5aaf501..d4a2cb9 100644
--- a/src/Language/SwiftLanguage.php
+++ b/src/Language/SwiftLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -21,6 +21,8 @@
  * Swift language highlighter.
  *
  * Two-pass semantic highlighter: lexer → semantic parser.
+ *
+ * @author Simon André 
  */
 final class SwiftLanguage implements LanguageInterface
 {
diff --git a/src/Language/TwigLanguage.php b/src/Language/TwigLanguage.php
index 39df143..b1ccc2d 100644
--- a/src/Language/TwigLanguage.php
+++ b/src/Language/TwigLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -27,6 +27,8 @@
  *
  * It does not aim to be a full Twig parser, but to capture enough structure for
  * high-quality syntax highlighting.
+ *
+ * @author Simon André 
  */
 final class TwigLanguage implements EmbeddedLanguageCapable
 {
diff --git a/src/Language/TypeScriptLanguage.php b/src/Language/TypeScriptLanguage.php
index 4006378..c45c5b3 100644
--- a/src/Language/TypeScriptLanguage.php
+++ b/src/Language/TypeScriptLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -22,6 +22,8 @@
  *
  * Handles TypeScript-specific syntax including type annotations, interfaces,
  * enums, generics, decorators, and access modifiers.
+ *
+ * @author Simon André 
  */
 final class TypeScriptLanguage extends JavaScriptLanguage
 {
diff --git a/src/Language/XmlLanguage.php b/src/Language/XmlLanguage.php
index 343af93..c796078 100644
--- a/src/Language/XmlLanguage.php
+++ b/src/Language/XmlLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -15,6 +15,8 @@
 
 /**
  * XML shares the same parsing rules as HTML but exposes a dedicated identifier.
+ *
+ * @author Simon André 
  */
 final class XmlLanguage extends HtmlLanguage
 {
diff --git a/src/Language/YamlLanguage.php b/src/Language/YamlLanguage.php
index bcfe069..db72137 100644
--- a/src/Language/YamlLanguage.php
+++ b/src/Language/YamlLanguage.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -21,6 +21,8 @@
  * YAML language parser.
  *
  * Handles parsing and semantic analysis of YAML code.
+ *
+ * @author Simon André 
  */
 final class YamlLanguage implements LanguageInterface
 {
diff --git a/src/Parser/ParsedStream.php b/src/Parser/ParsedStream.php
index ae06d91..d147922 100644
--- a/src/Parser/ParsedStream.php
+++ b/src/Parser/ParsedStream.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -32,8 +32,7 @@
      */
     public function __construct(
         public array $tokens,
-    ) {
-    }
+    ) {}
 
     /**
      * Get all tokens in the stream.
@@ -83,7 +82,7 @@ public function withoutComments(): self
         return new self(
             array_values(array_filter(
                 $this->tokens,
-                static fn (ParsedToken $token): bool => !$token->isComment(),
+                static fn(ParsedToken $token): bool => !$token->isComment(),
             )),
         );
     }
@@ -96,7 +95,7 @@ public function withoutWhitespace(): self
         return new self(
             array_values(array_filter(
                 $this->tokens,
-                static fn (ParsedToken $token): bool => !$token->isWhitespace(),
+                static fn(ParsedToken $token): bool => !$token->isWhitespace(),
             )),
         );
     }
@@ -109,7 +108,7 @@ public function withoutRemovable(): self
         return new self(
             array_values(array_filter(
                 $this->tokens,
-                static fn (ParsedToken $token): bool => !$token->isRemovable(),
+                static fn(ParsedToken $token): bool => !$token->isRemovable(),
             )),
         );
     }
@@ -124,7 +123,7 @@ public function filter(TokenType ...$types): self
         return new self(
             array_values(array_filter(
                 $this->tokens,
-                static fn (ParsedToken $token): bool => in_array($token->type, $types, true),
+                static fn(ParsedToken $token): bool => in_array($token->type, $types, true),
             )),
         );
     }
@@ -139,7 +138,7 @@ public function exclude(TokenType ...$types): self
         return new self(
             array_values(array_filter(
                 $this->tokens,
-                static fn (ParsedToken $token): bool => !in_array($token->type, $types, true),
+                static fn(ParsedToken $token): bool => !in_array($token->type, $types, true),
             )),
         );
     }
@@ -154,7 +153,7 @@ public function filterByScope(Scope ...$scopes): self
         return new self(
             array_values(array_filter(
                 $this->tokens,
-                static fn (ParsedToken $token): bool => in_array($token->scope, $scopes, true),
+                static fn(ParsedToken $token): bool => in_array($token->scope, $scopes, true),
             )),
         );
     }
@@ -169,7 +168,7 @@ public function filterByScope(Scope ...$scopes): self
     public function toString(): string
     {
         return implode('', array_map(
-            static fn (ParsedToken $token): string => $token->text,
+            static fn(ParsedToken $token): string => $token->text,
             $this->tokens,
         ));
     }
@@ -182,7 +181,7 @@ public function toString(): string
     public function texts(): array
     {
         return array_map(
-            static fn (ParsedToken $token): string => $token->text,
+            static fn(ParsedToken $token): string => $token->text,
             $this->tokens,
         );
     }
@@ -195,10 +194,10 @@ public function texts(): array
     public function getStrings(): array
     {
         return array_values(array_map(
-            static fn (ParsedToken $token): string => $token->text,
+            static fn(ParsedToken $token): string => $token->text,
             array_filter(
                 $this->tokens,
-                static fn (ParsedToken $token): bool => $token->isString(),
+                static fn(ParsedToken $token): bool => $token->isString(),
             ),
         ));
     }
@@ -211,10 +210,10 @@ public function getStrings(): array
     public function getComments(): array
     {
         return array_values(array_map(
-            static fn (ParsedToken $token): string => $token->text,
+            static fn(ParsedToken $token): string => $token->text,
             array_filter(
                 $this->tokens,
-                static fn (ParsedToken $token): bool => $token->isComment(),
+                static fn(ParsedToken $token): bool => $token->isComment(),
             ),
         ));
     }
@@ -228,7 +227,7 @@ public function getDefinitions(): array
     {
         return array_values(array_filter(
             $this->tokens,
-            static fn (ParsedToken $token): bool => $token->isDefinition(),
+            static fn(ParsedToken $token): bool => $token->isDefinition(),
         ));
     }
 
diff --git a/src/Parser/ParsedToken.php b/src/Parser/ParsedToken.php
index 3dbecc4..e681206 100644
--- a/src/Parser/ParsedToken.php
+++ b/src/Parser/ParsedToken.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -32,8 +32,7 @@ public function __construct(
         public int $offset = 0,
         public int $line = 1,
         public int $column = 0,
-    ) {
-    }
+    ) {}
 
     /**
      * Get the token's text content.
diff --git a/src/Parser/StreamBuilder.php b/src/Parser/StreamBuilder.php
index 8cdb9f8..a690870 100644
--- a/src/Parser/StreamBuilder.php
+++ b/src/Parser/StreamBuilder.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -25,7 +25,9 @@
  */
 final class StreamBuilder
 {
-    /** @var list */
+    /**
+     * @var list
+     */
     private array $tokens = [];
 
     public function add(string $text, Scope $scope): void
diff --git a/src/Parser/TokenType.php b/src/Parser/TokenType.php
index 064f6d3..a4315c1 100644
--- a/src/Parser/TokenType.php
+++ b/src/Parser/TokenType.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/src/Scope.php b/src/Scope.php
index 51366fa..41f976b 100644
--- a/src/Scope.php
+++ b/src/Scope.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/src/Theme/AltoTheme.php b/src/Theme/AltoTheme.php
index 04bed6f..df840b1 100644
--- a/src/Theme/AltoTheme.php
+++ b/src/Theme/AltoTheme.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -28,8 +28,7 @@ final class AltoTheme implements ThemeInterface
 {
     public function __construct(
         private readonly bool $dark = true,
-    ) {
-    }
+    ) {}
 
     public function getName(): string
     {
@@ -124,7 +123,7 @@ private function prefixed(array $map): array
     {
         $classes = [];
         foreach ($map as [$scope, $suffix]) {
-            $classes[$scope->value] = '' === $suffix ? '' : 'alto-'.$suffix;
+            $classes[$scope->value] = '' === $suffix ? '' : 'alto-' . $suffix;
         }
 
         return $classes;
diff --git a/src/Theme/CupertinoTheme.php b/src/Theme/CupertinoTheme.php
index 974fef3..e02b5aa 100644
--- a/src/Theme/CupertinoTheme.php
+++ b/src/Theme/CupertinoTheme.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -21,13 +21,14 @@
  *
  * An original color palette in the spirit of native macOS code editors,
  * designed for comfort on both dark and light backgrounds.
+ *
+ * @author Simon André 
  */
 final class CupertinoTheme implements ThemeInterface
 {
     public function __construct(
         private readonly bool $dark = true,
-    ) {
-    }
+    ) {}
 
     public function getName(): string
     {
@@ -45,7 +46,7 @@ public function getCssClasses(): array
 
         $classes = [];
         foreach ($this->scopeMap() as [$scope, $suffix]) {
-            $classes[$scope->value] = '' === $suffix ? '' : $prefix.$suffix;
+            $classes[$scope->value] = '' === $suffix ? '' : $prefix . $suffix;
         }
 
         return $classes;
diff --git a/src/Theme/DraculaTheme.php b/src/Theme/DraculaTheme.php
index ae654c5..14d26e6 100644
--- a/src/Theme/DraculaTheme.php
+++ b/src/Theme/DraculaTheme.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -28,6 +28,8 @@
  * Original Dracula color scheme © Zeno Rocha — MIT License
  *
  * @see https://draculatheme.com
+ *
+ * @author Simon André 
  */
 final class DraculaTheme implements ThemeInterface
 {
@@ -105,7 +107,7 @@ private function prefixed(array $map): array
     {
         $classes = [];
         foreach ($map as [$scope, $suffix]) {
-            $classes[$scope->value] = '' === $suffix ? '' : 'dracula-'.$suffix;
+            $classes[$scope->value] = '' === $suffix ? '' : 'dracula-' . $suffix;
         }
 
         return $classes;
diff --git a/src/Theme/GitHubTheme.php b/src/Theme/GitHubTheme.php
index 3e6f2d1..a6632a7 100644
--- a/src/Theme/GitHubTheme.php
+++ b/src/Theme/GitHubTheme.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -28,13 +28,14 @@
  * Color palette © GitHub, Inc. — MIT License
  *
  * @see https://github.com/primer/primitives
+ *
+ * @author Simon André 
  */
 final class GitHubTheme implements ThemeInterface
 {
     public function __construct(
         private readonly bool $dark = true,
-    ) {
-    }
+    ) {}
 
     public function getName(): string
     {
@@ -52,7 +53,7 @@ public function getCssClasses(): array
 
         $classes = [];
         foreach ($this->scopeMap() as [$scope, $suffix]) {
-            $classes[$scope->value] = '' === $suffix ? '' : $prefix.$suffix;
+            $classes[$scope->value] = '' === $suffix ? '' : $prefix . $suffix;
         }
 
         return $classes;
diff --git a/src/Theme/NoctisTheme.php b/src/Theme/NoctisTheme.php
index 7bea17a..339d74f 100644
--- a/src/Theme/NoctisTheme.php
+++ b/src/Theme/NoctisTheme.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -28,13 +28,14 @@
  * Original Noctis color scheme © Liviu Schera — MIT License
  *
  * @see https://github.com/liviuschera/noctis
+ *
+ * @author Simon André 
  */
 final class NoctisTheme implements ThemeInterface
 {
     public function __construct(
         private readonly bool $dark = true,
-    ) {
-    }
+    ) {}
 
     public function getName(): string
     {
@@ -52,7 +53,7 @@ public function getCssClasses(): array
 
         $classes = [];
         foreach ($this->scopeMap() as [$scope, $suffix]) {
-            $classes[$scope->value] = '' === $suffix ? '' : $prefix.$suffix;
+            $classes[$scope->value] = '' === $suffix ? '' : $prefix . $suffix;
         }
 
         return $classes;
diff --git a/src/Theme/PolarTheme.php b/src/Theme/PolarTheme.php
index 9455f92..b765233 100644
--- a/src/Theme/PolarTheme.php
+++ b/src/Theme/PolarTheme.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -28,6 +28,8 @@
  * Original Nord color scheme © Arctic Ice Studio — MIT License
  *
  * @see https://www.nordtheme.com
+ *
+ * @author Simon André 
  */
 final class PolarTheme implements ThemeInterface
 {
@@ -105,7 +107,7 @@ private function prefixed(array $map): array
     {
         $classes = [];
         foreach ($map as [$scope, $suffix]) {
-            $classes[$scope->value] = '' === $suffix ? '' : 'polar-'.$suffix;
+            $classes[$scope->value] = '' === $suffix ? '' : 'polar-' . $suffix;
         }
 
         return $classes;
diff --git a/src/Theme/SolarTheme.php b/src/Theme/SolarTheme.php
index 5ee2901..ccf4cd5 100644
--- a/src/Theme/SolarTheme.php
+++ b/src/Theme/SolarTheme.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -28,13 +28,14 @@
  * Original Solarized color scheme © Ethan Schoonover — MIT License
  *
  * @see https://ethanschoonover.com/solarized
+ *
+ * @author Simon André 
  */
 final class SolarTheme implements ThemeInterface
 {
     public function __construct(
         private readonly bool $dark = false,
-    ) {
-    }
+    ) {}
 
     public function getName(): string
     {
@@ -52,7 +53,7 @@ public function getCssClasses(): array
 
         $classes = [];
         foreach ($this->scopeMap() as [$scope, $suffix]) {
-            $classes[$scope->value] = '' === $suffix ? '' : $prefix.$suffix;
+            $classes[$scope->value] = '' === $suffix ? '' : $prefix . $suffix;
         }
 
         return $classes;
diff --git a/src/ThemeInterface.php b/src/ThemeInterface.php
index 53fb912..7d4d73e 100644
--- a/src/ThemeInterface.php
+++ b/src/ThemeInterface.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/BashLanguageTest.php b/tests/Language/BashLanguageTest.php
index 12ff653..4db7ee0 100644
--- a/tests/Language/BashLanguageTest.php
+++ b/tests/Language/BashLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/CSharpLanguageTest.php b/tests/Language/CSharpLanguageTest.php
index 8d15b60..10be2fd 100644
--- a/tests/Language/CSharpLanguageTest.php
+++ b/tests/Language/CSharpLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/CssLanguageTest.php b/tests/Language/CssLanguageTest.php
index 0a3e85f..d92f5bb 100644
--- a/tests/Language/CssLanguageTest.php
+++ b/tests/Language/CssLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/DiffLanguageTest.php b/tests/Language/DiffLanguageTest.php
index 98d414a..4a7afea 100644
--- a/tests/Language/DiffLanguageTest.php
+++ b/tests/Language/DiffLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/DockerfileLanguageTest.php b/tests/Language/DockerfileLanguageTest.php
index 0b47b46..2edcedc 100644
--- a/tests/Language/DockerfileLanguageTest.php
+++ b/tests/Language/DockerfileLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/DotEnvLanguageTest.php b/tests/Language/DotEnvLanguageTest.php
index f013d90..1c8f83d 100644
--- a/tests/Language/DotEnvLanguageTest.php
+++ b/tests/Language/DotEnvLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/GoLanguageTest.php b/tests/Language/GoLanguageTest.php
index 6dbd84b..18771d0 100644
--- a/tests/Language/GoLanguageTest.php
+++ b/tests/Language/GoLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/HtmlLanguageTest.php b/tests/Language/HtmlLanguageTest.php
index c6ba6be..845815d 100644
--- a/tests/Language/HtmlLanguageTest.php
+++ b/tests/Language/HtmlLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/HttpLanguageTest.php b/tests/Language/HttpLanguageTest.php
index 906c6b4..3e9777a 100644
--- a/tests/Language/HttpLanguageTest.php
+++ b/tests/Language/HttpLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/IniLanguageTest.php b/tests/Language/IniLanguageTest.php
index 003fcc6..9967705 100644
--- a/tests/Language/IniLanguageTest.php
+++ b/tests/Language/IniLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/JavaLanguageTest.php b/tests/Language/JavaLanguageTest.php
index ae178e2..4a6befe 100644
--- a/tests/Language/JavaLanguageTest.php
+++ b/tests/Language/JavaLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/JavaScriptLanguageTest.php b/tests/Language/JavaScriptLanguageTest.php
index 78c0f56..f463570 100644
--- a/tests/Language/JavaScriptLanguageTest.php
+++ b/tests/Language/JavaScriptLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/JsonLanguageTest.php b/tests/Language/JsonLanguageTest.php
index 284f0b3..d75cadc 100644
--- a/tests/Language/JsonLanguageTest.php
+++ b/tests/Language/JsonLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/MakefileLanguageTest.php b/tests/Language/MakefileLanguageTest.php
index 038ab36..5379180 100644
--- a/tests/Language/MakefileLanguageTest.php
+++ b/tests/Language/MakefileLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/MarkdownLanguageTest.php b/tests/Language/MarkdownLanguageTest.php
index a2abd32..1fe40f2 100644
--- a/tests/Language/MarkdownLanguageTest.php
+++ b/tests/Language/MarkdownLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/PhpLanguageTest.php b/tests/Language/PhpLanguageTest.php
index 4ef29c1..3d37d4b 100644
--- a/tests/Language/PhpLanguageTest.php
+++ b/tests/Language/PhpLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/PythonLanguageTest.php b/tests/Language/PythonLanguageTest.php
index 9a9f38f..d63edc8 100644
--- a/tests/Language/PythonLanguageTest.php
+++ b/tests/Language/PythonLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/RubyLanguageTest.php b/tests/Language/RubyLanguageTest.php
index d5ac666..e787ed0 100644
--- a/tests/Language/RubyLanguageTest.php
+++ b/tests/Language/RubyLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/RustLanguageTest.php b/tests/Language/RustLanguageTest.php
index 016f907..d8dd213 100644
--- a/tests/Language/RustLanguageTest.php
+++ b/tests/Language/RustLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/ScssLanguageTest.php b/tests/Language/ScssLanguageTest.php
index 20b48f5..d98e627 100644
--- a/tests/Language/ScssLanguageTest.php
+++ b/tests/Language/ScssLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/SqlLanguageTest.php b/tests/Language/SqlLanguageTest.php
index e043f31..a3906c2 100644
--- a/tests/Language/SqlLanguageTest.php
+++ b/tests/Language/SqlLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/SvgLanguageTest.php b/tests/Language/SvgLanguageTest.php
index 9cd284e..1643682 100644
--- a/tests/Language/SvgLanguageTest.php
+++ b/tests/Language/SvgLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/SwiftLanguageTest.php b/tests/Language/SwiftLanguageTest.php
index 59125e1..da5f546 100644
--- a/tests/Language/SwiftLanguageTest.php
+++ b/tests/Language/SwiftLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/TwigLanguageTest.php b/tests/Language/TwigLanguageTest.php
index 9593da6..231f802 100644
--- a/tests/Language/TwigLanguageTest.php
+++ b/tests/Language/TwigLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/TypeScriptLanguageTest.php b/tests/Language/TypeScriptLanguageTest.php
index d100876..cb4643b 100644
--- a/tests/Language/TypeScriptLanguageTest.php
+++ b/tests/Language/TypeScriptLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/XmlLanguageTest.php b/tests/Language/XmlLanguageTest.php
index 38ce2b1..b297717 100644
--- a/tests/Language/XmlLanguageTest.php
+++ b/tests/Language/XmlLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Language/YamlLanguageTest.php b/tests/Language/YamlLanguageTest.php
index 7f0a466..66bb2f6 100644
--- a/tests/Language/YamlLanguageTest.php
+++ b/tests/Language/YamlLanguageTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/LanguageTestCase.php b/tests/LanguageTestCase.php
index a2ef094..b7d43ee 100644
--- a/tests/LanguageTestCase.php
+++ b/tests/LanguageTestCase.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -75,7 +75,7 @@ protected function setUp(): void
      */
     protected function getFixturesDirectory(): string
     {
-        return __DIR__.'/Language/'.$this->language;
+        return __DIR__ . '/Language/' . $this->language;
     }
 
     /**
@@ -156,7 +156,7 @@ protected function discoverFixtures(): array
      */
     protected function getFixtureCodePath(string $fixture): string
     {
-        return $this->getFixturesDirectory().'/'.$fixture;
+        return $this->getFixturesDirectory() . '/' . $fixture;
     }
 
     /**
@@ -168,7 +168,7 @@ protected function getFixtureCodePath(string $fixture): string
      */
     protected function getFixtureHtmlPath(string $fixture): string
     {
-        return $this->getFixtureCodePath($fixture).'.html';
+        return $this->getFixtureCodePath($fixture) . '.html';
     }
 
     /**
@@ -188,7 +188,7 @@ protected function getEmbeddedLanguages(string $fixture): array
         // Remove extension
         $name = $fixture;
         foreach ($this->getFileExtensions() as $ext) {
-            if (str_ends_with($name, '.'.$ext)) {
+            if (str_ends_with($name, '.' . $ext)) {
                 $name = substr($name, 0, -(strlen($ext) + 1));
                 break;
             }
@@ -281,9 +281,9 @@ protected function testFixture(string $fixture): void
         $this->assertSame(
             $expectedHtml,
             $actualHtml,
-            "HTML output does not match for fixture: {$fixture}\n".
-            "Code file: {$codePath}\n".
-            "Expected HTML: {$htmlPath}"
+            "HTML output does not match for fixture: {$fixture}\n" .
+            "Code file: {$codePath}\n" .
+            "Expected HTML: {$htmlPath}",
         );
     }
 
@@ -322,7 +322,7 @@ public static function fixtureProvider(): array
         }
 
         // Build fixtures directory dynamically
-        $fixturesDir = __DIR__.'/Language/'.$language;
+        $fixturesDir = __DIR__ . '/Language/' . $language;
 
         if (!is_dir($fixturesDir)) {
             return [];
@@ -374,7 +374,7 @@ public static function fixtureProvider(): array
 
         sort($fixtures);
 
-        return array_map(fn ($fixture) => [$fixture], $fixtures);
+        return array_map(fn($fixture) => [$fixture], $fixtures);
     }
 
     /**
@@ -394,12 +394,12 @@ protected function debugFixtureInfo(): void
         $fixtures = $this->discoverFixtures();
 
         echo "\n--- Language: {$this->language} ---\n";
-        echo 'Directory: '.$this->getFixturesDirectory()."\n";
-        echo 'Fixtures found: '.count($fixtures)."\n";
+        echo 'Directory: ' . $this->getFixturesDirectory() . "\n";
+        echo 'Fixtures found: ' . count($fixtures) . "\n";
 
         foreach ($fixtures as $fixture) {
             $embeds = $this->getEmbeddedLanguages($fixture);
-            $embedStr = !empty($embeds) ? ' (+'.implode('+', $embeds).')' : '';
+            $embedStr = !empty($embeds) ? ' (+' . implode('+', $embeds) . ')' : '';
             echo "  • {$fixture}{$embedStr}\n";
         }
     }
diff --git a/tests/Support/MockHttpStreamWrapper.php b/tests/Support/MockHttpStreamWrapper.php
index aa2007d..e00d6a3 100644
--- a/tests/Support/MockHttpStreamWrapper.php
+++ b/tests/Support/MockHttpStreamWrapper.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -24,10 +24,14 @@
  */
 final class MockHttpStreamWrapper
 {
-    /** @var array */
+    /**
+     * @var array
+     */
     private static array $responses = [];
 
-    /** @var resource|null */
+    /**
+     * @var resource|null
+     */
     public $context;
 
     private string $content = '';
diff --git a/tests/TestCase.php b/tests/TestCase.php
index 4d8f05f..1c8961b 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Unit/Adapter/HighlightJsThemeAdapterTest.php b/tests/Unit/Adapter/HighlightJsThemeAdapterTest.php
index 0647840..738a953 100644
--- a/tests/Unit/Adapter/HighlightJsThemeAdapterTest.php
+++ b/tests/Unit/Adapter/HighlightJsThemeAdapterTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -309,7 +309,7 @@ public function testCssClassNamesAreValid(): void
 
     public function testCssClassNamesStartWithHljsPrefix(): void
     {
-        $classes = array_filter($this->makeTheme()->getCssClasses(), static fn (string $class) => '' !== $class);
+        $classes = array_filter($this->makeTheme()->getCssClasses(), static fn(string $class) => '' !== $class);
 
         foreach ($classes as $className) {
             self::assertStringContainsString('hljs', $className);
diff --git a/tests/Unit/Adapter/PrismThemeAdapterTest.php b/tests/Unit/Adapter/PrismThemeAdapterTest.php
index d7569b9..e3b7f7a 100644
--- a/tests/Unit/Adapter/PrismThemeAdapterTest.php
+++ b/tests/Unit/Adapter/PrismThemeAdapterTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -65,7 +65,7 @@ public function testItMapsBasicScopes(): void
 
     public function testItUsesTokenPrefixForNonEmptyClasses(): void
     {
-        $classes = array_filter($this->makeTheme()->getCssClasses(), static fn (string $class) => '' !== $class);
+        $classes = array_filter($this->makeTheme()->getCssClasses(), static fn(string $class) => '' !== $class);
 
         foreach ($classes as $className) {
             self::assertStringContainsString('token', $className);
@@ -301,7 +301,7 @@ public function testCssClassFormatContainsToken(): void
 
     public function testCssClassFormatMatchesPattern(): void
     {
-        foreach (array_filter($this->makeTheme()->getCssClasses(), static fn (string $class) => '' !== $class) as $class) {
+        foreach (array_filter($this->makeTheme()->getCssClasses(), static fn(string $class) => '' !== $class) as $class) {
             self::assertMatchesRegularExpression('/^token\s+[\w-]+$/', $class);
         }
     }
diff --git a/tests/Unit/Adapter/TextMateThemeAdapterTest.php b/tests/Unit/Adapter/TextMateThemeAdapterTest.php
index 3db234c..e53dde8 100644
--- a/tests/Unit/Adapter/TextMateThemeAdapterTest.php
+++ b/tests/Unit/Adapter/TextMateThemeAdapterTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Unit/Embedded/EmbeddedLanguagePlanTest.php b/tests/Unit/Embedded/EmbeddedLanguagePlanTest.php
index 7cd56b0..a0087ab 100644
--- a/tests/Unit/Embedded/EmbeddedLanguagePlanTest.php
+++ b/tests/Unit/Embedded/EmbeddedLanguagePlanTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Unit/Embedded/EmbeddedLanguageRegistryTest.php b/tests/Unit/Embedded/EmbeddedLanguageRegistryTest.php
index ec2dbfc..1eb3009 100644
--- a/tests/Unit/Embedded/EmbeddedLanguageRegistryTest.php
+++ b/tests/Unit/Embedded/EmbeddedLanguageRegistryTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -50,7 +50,7 @@ public function testLoadsPlansFromConfigurationFile(): void
 
     public function testReturnsNullWhenConfigurationFileMissing(): void
     {
-        $registry = new EmbeddedLanguageRegistry(__DIR__.'/does-not-exist.php');
+        $registry = new EmbeddedLanguageRegistry(__DIR__ . '/does-not-exist.php');
 
         self::assertNull($registry->getPlan('html'));
     }
diff --git a/tests/Unit/Embedded/EmbeddedTriggerTest.php b/tests/Unit/Embedded/EmbeddedTriggerTest.php
index 54dd4f3..165ec8a 100644
--- a/tests/Unit/Embedded/EmbeddedTriggerTest.php
+++ b/tests/Unit/Embedded/EmbeddedTriggerTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Unit/ExamplesCatalogTest.php b/tests/Unit/ExamplesCatalogTest.php
index d0e0844..e826922 100644
--- a/tests/Unit/ExamplesCatalogTest.php
+++ b/tests/Unit/ExamplesCatalogTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -24,12 +24,12 @@
 #[CoversNothing]
 final class ExamplesCatalogTest extends TestCase
 {
-    private const string CATALOG_PATH = __DIR__.'/../../examples/catalog.php';
+    private const string CATALOG_PATH = __DIR__ . '/../../examples/catalog.php';
 
     public function testCatalogMatchesDefaultLanguageRegistryExactly(): void
     {
         $registryIdentifiers = array_map(
-            static fn (LanguageInterface $language): string => $language->getIdentifier(),
+            static fn(LanguageInterface $language): string => $language->getIdentifier(),
             Languages::getDefaultLanguages(),
         );
         $catalogIdentifiers = array_column(self::catalog(), 'id');
@@ -59,7 +59,7 @@ public function testCatalogHasUniqueIdentifiersAndExactSchema(): void
     public function testOnlyExpectedLanguagesAreFeatured(): void
     {
         $featured = array_column(
-            array_filter(self::catalog(), static fn (array $entry): bool => $entry['featured']),
+            array_filter(self::catalog(), static fn(array $entry): bool => $entry['featured']),
             'id',
         );
 
@@ -82,7 +82,7 @@ public function testOnlyExpectedLanguagesAreFeatured(): void
     #[DataProvider('catalogProvider')]
     public function testExampleIsReadableFitsShowcaseAndRoundTripsThroughHighlighter(array $entry): void
     {
-        $path = dirname(self::CATALOG_PATH).'/'.$entry['source'];
+        $path = dirname(self::CATALOG_PATH) . '/' . $entry['source'];
 
         self::assertFileExists($path);
         self::assertIsReadable($path);
diff --git a/tests/Unit/Exception/ExceptionTest.php b/tests/Unit/Exception/ExceptionTest.php
index 67811db..e066c6d 100644
--- a/tests/Unit/Exception/ExceptionTest.php
+++ b/tests/Unit/Exception/ExceptionTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Unit/HighlighterTest.php b/tests/Unit/HighlighterTest.php
index dc790cb..cda12b0 100644
--- a/tests/Unit/HighlighterTest.php
+++ b/tests/Unit/HighlighterTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Unit/Language/CrossLanguageSemanticTest.php b/tests/Unit/Language/CrossLanguageSemanticTest.php
index a37e315..37adf37 100644
--- a/tests/Unit/Language/CrossLanguageSemanticTest.php
+++ b/tests/Unit/Language/CrossLanguageSemanticTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -565,7 +565,7 @@ private function getNonWhitespaceTokens(ParsedStream $stream): array
     {
         return array_values(array_filter(
             $stream->getTokens(),
-            static fn (ParsedToken $token): bool => Scope::Whitespace !== $token->getScope(),
+            static fn(ParsedToken $token): bool => Scope::Whitespace !== $token->getScope(),
         ));
     }
 
diff --git a/tests/Unit/Language/CssLanguageSemanticTest.php b/tests/Unit/Language/CssLanguageSemanticTest.php
index 7462bc3..713522f 100644
--- a/tests/Unit/Language/CssLanguageSemanticTest.php
+++ b/tests/Unit/Language/CssLanguageSemanticTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
diff --git a/tests/Unit/Language/EmbeddedLanguageContextTest.php b/tests/Unit/Language/EmbeddedLanguageContextTest.php
index 92222ed..fbfb65d 100644
--- a/tests/Unit/Language/EmbeddedLanguageContextTest.php
+++ b/tests/Unit/Language/EmbeddedLanguageContextTest.php
@@ -5,7 +5,7 @@
 /*
  * This file is part of the ALTO library.
  *
- * © 2026–present Simon André
+ * © 2026-present Simon André
  *
  * For full copyright and license information, please see
  * the LICENSE file distributed with this source code.
@@ -51,7 +51,7 @@ public function testDisabledContextThrowsOnParseEmbedded(): void
 
     public function testFromResolverCreatesContext(): void
     {
-        $resolver = fn (string $lang, string $code) => (new StreamBuilder())->add($code, Scope::String)->build();
+        $resolver = fn(string $lang, string $code) => (new StreamBuilder())->add($code, Scope::String)->build();
 
         $context = EmbeddedLanguageContext::fromResolver($resolver);
 
@@ -60,7 +60,7 @@ public function testFromResolverCreatesContext(): void
 
     public function testFromResolverWithPlan(): void
     {
-        $resolver = fn (string $lang, string $code) => (new StreamBuilder())->add($code, Scope::String)->build();
+        $resolver = fn(string $lang, string $code) => (new StreamBuilder())->add($code, Scope::String)->build();
         $plan = EmbeddedLanguagePlan::forHost('html', [
             EmbeddedTrigger::tag('style', 'css'),
         ]);
@@ -73,7 +73,7 @@ public function testFromResolverWithPlan(): void
 
     public function testSupportsEmbeddingReturnsTrueWithResolver(): void
     {
-        $resolver = fn (string $lang, string $code) => (new StreamBuilder())->add($code, Scope::String)->build();
+        $resolver = fn(string $lang, string $code) => (new StreamBuilder())->add($code, Scope::String)->build();
 
         $context = EmbeddedLanguageContext::fromResolver($resolver);
 
@@ -82,7 +82,7 @@ public function testSupportsEmbeddingReturnsTrueWithResolver(): void
 
     public function testGetPlanReturnsPlan(): void
     {
-        $resolver = fn (string $lang, string $code) => (new StreamBuilder())->add($code, Scope::String)->build();
+        $resolver = fn(string $lang, string $code) => (new StreamBuilder())->add($code, Scope::String)->build();
         $plan = EmbeddedLanguagePlan::forHost('html', []);
 
         $context = EmbeddedLanguageContext::fromResolver($resolver, $plan);
@@ -92,7 +92,7 @@ public function testGetPlanReturnsPlan(): void
 
     public function testGetPlanReturnsNullWhenNoPlan(): void
     {
-        $resolver = fn (string $lang, string $code) => (new StreamBuilder())->add($code, Scope::String)->build();
+        $resolver = fn(string $lang, string $code) => (new StreamBuilder())->add($code, Scope::String)->build();
 
         $context = EmbeddedLanguageContext::fromResolver($resolver);
 
@@ -132,7 +132,7 @@ public function testCircularDependencyDetection(): void
     {
         $resolver = function (string $lang, string $code) {
             // Simulate a circular dependency by trying to parse the same language again
-            $context = EmbeddedLanguageContext::fromResolver(fn ($l, $c) => (new StreamBuilder())->build());
+            $context = EmbeddedLanguageContext::fromResolver(fn($l, $c) => (new StreamBuilder())->build());
             $context->parseEmbedded('html', '
'); return (new StreamBuilder())->add($code, Scope::String)->build(); @@ -155,7 +155,7 @@ public function testCircularDependencyReturnsFallbackStream(): void // On first call, try to parse the same language (circular) if (1 === $callCount) { - $nestedContext = EmbeddedLanguageContext::fromResolver(fn ($l, $c) => (new StreamBuilder())->build()); + $nestedContext = EmbeddedLanguageContext::fromResolver(fn($l, $c) => (new StreamBuilder())->build()); // Manually trigger circular detection by calling with same language $builder = new StreamBuilder(); $builder->add($code, Scope::String); @@ -185,7 +185,7 @@ public function testDepthLimitEnforcement(): void ++$depth; if ($depth < 15) { - $context = EmbeddedLanguageContext::fromResolver(fn ($l, $c) => (new StreamBuilder())->add($c, Scope::String)->build()); + $context = EmbeddedLanguageContext::fromResolver(fn($l, $c) => (new StreamBuilder())->add($c, Scope::String)->build()); $context->parseEmbedded("lang{$depth}", $code); } diff --git a/tests/Unit/Language/EmbeddedLanguageTest.php b/tests/Unit/Language/EmbeddedLanguageTest.php index d78813c..11c9b02 100644 --- a/tests/Unit/Language/EmbeddedLanguageTest.php +++ b/tests/Unit/Language/EmbeddedLanguageTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -41,7 +41,9 @@ final class EmbeddedLanguageTest extends TestCase private EmbeddedLanguageRegistry $registry; - /** @var array */ + /** + * @var array + */ private array $languages; protected function setUp(): void @@ -195,7 +197,7 @@ public function testHtmlWithMultipleEmbeddedLanguages(): void // Should contain CSS tokens $tokens = $stream->getTokens(); - $tokenTexts = array_map(fn (ParsedToken $t) => $t->getText(), $tokens); + $tokenTexts = array_map(fn(ParsedToken $t) => $t->getText(), $tokens); $fullText = implode('', $tokenTexts); self::assertStringContainsString('body', $fullText); @@ -232,8 +234,8 @@ private function createEmbeddingContext(string $hostLanguage): EmbeddedLanguageC $plan = $this->registry->getPlan($hostLanguage); return EmbeddedLanguageContext::fromResolver( - fn (string $languageIdentifier, string $code) => $this->languages[strtolower($languageIdentifier)]->parse($code), - $plan + fn(string $languageIdentifier, string $code) => $this->languages[strtolower($languageIdentifier)]->parse($code), + $plan, ); } @@ -314,7 +316,7 @@ private static function assertEmbeddedTokensMatchStandalone(array $standaloneTok self::assertCount( count($standaloneTokens), $embeddedTokens, - sprintf('%s: Token count mismatch. Standalone: %d, Embedded: %d', $message, count($standaloneTokens), count($embeddedTokens)) + sprintf('%s: Token count mismatch. Standalone: %d, Embedded: %d', $message, count($standaloneTokens), count($embeddedTokens)), ); foreach ($standaloneTokens as $index => $standaloneToken) { @@ -323,7 +325,7 @@ private static function assertEmbeddedTokensMatchStandalone(array $standaloneTok self::assertSame( $standaloneToken->getText(), $embeddedToken->getText(), - sprintf('%s: Token text mismatch at index %d', $message, $index) + sprintf('%s: Token text mismatch at index %d', $message, $index), ); self::assertSame( @@ -335,8 +337,8 @@ private static function assertEmbeddedTokensMatchStandalone(array $standaloneTok $index, $standaloneToken->getText(), $standaloneToken->getScope()->value, - $embeddedToken->getScope()->value - ) + $embeddedToken->getScope()->value, + ), ); } } diff --git a/tests/Unit/Language/HtmlLanguageSemanticTest.php b/tests/Unit/Language/HtmlLanguageSemanticTest.php index 8714ca6..7592edf 100644 --- a/tests/Unit/Language/HtmlLanguageSemanticTest.php +++ b/tests/Unit/Language/HtmlLanguageSemanticTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/Language/HttpLanguageTest.php b/tests/Unit/Language/HttpLanguageTest.php index 253376b..8cc43b3 100644 --- a/tests/Unit/Language/HttpLanguageTest.php +++ b/tests/Unit/Language/HttpLanguageTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -381,14 +381,14 @@ private function assertTokenExists(array $tokens, string $text, Scope $scope): v } $tokenList = array_map( - fn ($t) => sprintf('[%s: %s]', $t->getScope()->value, json_encode($t->getText())), - $tokens + fn($t) => sprintf('[%s: %s]', $t->getScope()->value, json_encode($t->getText())), + $tokens, ); $this->fail(sprintf( 'Token "%s" with scope %s not found. Found: %s', $text, $scope->value, - implode(', ', $tokenList) + implode(', ', $tokenList), )); } } diff --git a/tests/Unit/Language/JavaScript/JavaScriptLexerTest.php b/tests/Unit/Language/JavaScript/JavaScriptLexerTest.php index e790835..9f67915 100644 --- a/tests/Unit/Language/JavaScript/JavaScriptLexerTest.php +++ b/tests/Unit/Language/JavaScript/JavaScriptLexerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -37,7 +37,7 @@ public function testTokenizesKeywords(): void $code = 'const let var function class if else for while return'; $tokens = $this->lexer->tokenize($code); - $keywordTokens = array_filter($tokens, fn ($token) => JavaScriptTokenType::Keyword === $token->type); + $keywordTokens = array_filter($tokens, fn($token) => JavaScriptTokenType::Keyword === $token->type); self::assertCount(10, $keywordTokens); } @@ -58,7 +58,7 @@ public function testTokenizesIdentifiers(): void $code = 'myVar _privateVar $jquery camelCase snake_case'; $tokens = $this->lexer->tokenize($code); - $identifiers = array_filter($tokens, fn ($token) => JavaScriptTokenType::Identifier === $token->type); + $identifiers = array_filter($tokens, fn($token) => JavaScriptTokenType::Identifier === $token->type); self::assertCount(5, $identifiers); self::assertTrue($this->streamContainsToken($tokens, JavaScriptTokenType::Identifier, 'myVar')); @@ -171,7 +171,7 @@ public function testTokenizesPunctuation(): void $code = '(){}[];,.'; $tokens = $this->lexer->tokenize($code); - $punctuation = array_filter($tokens, fn ($token) => JavaScriptTokenType::Punctuation === $token->type); + $punctuation = array_filter($tokens, fn($token) => JavaScriptTokenType::Punctuation === $token->type); self::assertCount(9, $punctuation); } @@ -232,7 +232,7 @@ public function testWhitespacePreservation(): void $code = 'const x = 42;'; $tokens = $this->lexer->tokenize($code); - $whitespaceTokens = array_filter($tokens, fn ($token) => JavaScriptTokenType::Whitespace === $token->type); + $whitespaceTokens = array_filter($tokens, fn($token) => JavaScriptTokenType::Whitespace === $token->type); self::assertNotEmpty($whitespaceTokens); } diff --git a/tests/Unit/Language/JavaScript/JavaScriptSemanticParserTest.php b/tests/Unit/Language/JavaScript/JavaScriptSemanticParserTest.php index 2c22083..335245d 100644 --- a/tests/Unit/Language/JavaScript/JavaScriptSemanticParserTest.php +++ b/tests/Unit/Language/JavaScript/JavaScriptSemanticParserTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -49,61 +49,61 @@ public function testFunctionKeywordIsDeclaration(): void { $stream = $this->parse('function test() {}'); - self::assertTrue($this->streamContainsScope($stream, Scope::KeywordDeclaration, static fn (ParsedToken $token) => 'function' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::KeywordDeclaration, static fn(ParsedToken $token) => 'function' === $token->getText())); } public function testConstLetVarAreDeclarations(): void { $stream = $this->parse('const x = 1; let y = 2; var z = 3;'); - self::assertTrue($this->streamContainsScope($stream, Scope::KeywordDeclaration, static fn (ParsedToken $token) => 'const' === $token->getText())); - self::assertTrue($this->streamContainsScope($stream, Scope::KeywordDeclaration, static fn (ParsedToken $token) => 'let' === $token->getText())); - self::assertTrue($this->streamContainsScope($stream, Scope::KeywordDeclaration, static fn (ParsedToken $token) => 'var' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::KeywordDeclaration, static fn(ParsedToken $token) => 'const' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::KeywordDeclaration, static fn(ParsedToken $token) => 'let' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::KeywordDeclaration, static fn(ParsedToken $token) => 'var' === $token->getText())); } public function testReturnIfWhileAreControl(): void { $stream = $this->parse('if (true) return; while (false) {}'); - self::assertTrue($this->streamContainsScope($stream, Scope::KeywordControl, static fn (ParsedToken $token) => 'if' === $token->getText())); - self::assertTrue($this->streamContainsScope($stream, Scope::KeywordControl, static fn (ParsedToken $token) => 'return' === $token->getText())); - self::assertTrue($this->streamContainsScope($stream, Scope::KeywordControl, static fn (ParsedToken $token) => 'while' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::KeywordControl, static fn(ParsedToken $token) => 'if' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::KeywordControl, static fn(ParsedToken $token) => 'return' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::KeywordControl, static fn(ParsedToken $token) => 'while' === $token->getText())); } public function testNewTypeofAreOperators(): void { $stream = $this->parse('new Object(); typeof x;'); - self::assertTrue($this->streamContainsScope($stream, Scope::KeywordOperator, static fn (ParsedToken $token) => 'new' === $token->getText())); - self::assertTrue($this->streamContainsScope($stream, Scope::KeywordOperator, static fn (ParsedToken $token) => 'typeof' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::KeywordOperator, static fn(ParsedToken $token) => 'new' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::KeywordOperator, static fn(ParsedToken $token) => 'typeof' === $token->getText())); } public function testThisIsVariableThis(): void { $stream = $this->parse('this.method();'); - self::assertTrue($this->streamContainsScope($stream, Scope::VariableThis, static fn (ParsedToken $token) => 'this' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::VariableThis, static fn(ParsedToken $token) => 'this' === $token->getText())); } public function testFunctionDefinitionScope(): void { $stream = $this->parse('function greet(name) { return "Hello"; }'); - self::assertTrue($this->streamContainsScope($stream, Scope::FunctionDefinition, static fn (ParsedToken $token) => 'greet' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::FunctionDefinition, static fn(ParsedToken $token) => 'greet' === $token->getText())); } public function testFunctionCallScope(): void { $stream = $this->parse('console.log("test");'); - self::assertTrue($this->streamContainsScope($stream, Scope::FunctionCall, static fn (ParsedToken $token) => 'log' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::FunctionCall, static fn(ParsedToken $token) => 'log' === $token->getText())); } public function testClassDefinitionScope(): void { $stream = $this->parse('class MyClass {}'); - self::assertTrue($this->streamContainsScope($stream, Scope::TypeDefinition, static fn (ParsedToken $token) => 'MyClass' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::TypeDefinition, static fn(ParsedToken $token) => 'MyClass' === $token->getText())); } public function testDistinguishesFunctionCallFromDefinition(): void @@ -112,12 +112,12 @@ public function testDistinguishesFunctionCallFromDefinition(): void $fooTokens = array_filter( $stream->getTokens(), - static fn (ParsedToken $token) => 'foo' === $token->getText() + static fn(ParsedToken $token) => 'foo' === $token->getText(), ); self::assertCount(2, $fooTokens); - $scopes = array_map(static fn (ParsedToken $token) => $token->getScope(), $fooTokens); + $scopes = array_map(static fn(ParsedToken $token) => $token->getScope(), $fooTokens); self::assertContains(Scope::FunctionDefinition, $scopes); self::assertContains(Scope::FunctionCall, $scopes); @@ -127,30 +127,30 @@ public function testStateTransitions(): void { $stream = $this->parse('class Test {} function method() {}'); - self::assertTrue($this->streamContainsScope($stream, Scope::TypeDefinition, static fn (ParsedToken $token) => 'Test' === $token->getText())); - self::assertTrue($this->streamContainsScope($stream, Scope::FunctionDefinition, static fn (ParsedToken $token) => 'method' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::TypeDefinition, static fn(ParsedToken $token) => 'Test' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::FunctionDefinition, static fn(ParsedToken $token) => 'method' === $token->getText())); } public function testDefaultIdentifierIsVariable(): void { $stream = $this->parse('const x = myVariable;'); - self::assertTrue($this->streamContainsScope($stream, Scope::Variable, static fn (ParsedToken $token) => 'myVariable' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::Variable, static fn(ParsedToken $token) => 'myVariable' === $token->getText())); } public function testImportStatement(): void { $stream = $this->parse('import { Component } from "react";'); - self::assertTrue($this->streamContainsScope($stream, Scope::KeywordDeclaration, static fn (ParsedToken $token) => 'import' === $token->getText())); - self::assertTrue($this->streamContainsScope($stream, Scope::Variable, static fn (ParsedToken $token) => 'Component' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::KeywordDeclaration, static fn(ParsedToken $token) => 'import' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::Variable, static fn(ParsedToken $token) => 'Component' === $token->getText())); } public function testExportStatement(): void { $stream = $this->parse('export const API_KEY = "secret";'); - self::assertTrue($this->streamContainsScope($stream, Scope::KeywordDeclaration, static fn (ParsedToken $token) => 'export' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::KeywordDeclaration, static fn(ParsedToken $token) => 'export' === $token->getText())); } public function testComplexNestedCode(): void @@ -164,9 +164,9 @@ function add(a, b) { JS; $stream = $this->parse($code); - self::assertTrue($this->streamContainsScope($stream, Scope::TypeDefinition, static fn (ParsedToken $token) => 'Calculator' === $token->getText())); - self::assertTrue($this->streamContainsScope($stream, Scope::FunctionDefinition, static fn (ParsedToken $token) => 'add' === $token->getText())); - self::assertTrue($this->streamContainsScope($stream, Scope::FunctionCall, static fn (ParsedToken $token) => 'add' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::TypeDefinition, static fn(ParsedToken $token) => 'Calculator' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::FunctionDefinition, static fn(ParsedToken $token) => 'add' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::FunctionCall, static fn(ParsedToken $token) => 'add' === $token->getText())); } #[DataProvider('scopeProvider')] @@ -176,7 +176,7 @@ public function testDetectsExpectedScope(string $code, Scope $scope, ?callable $ self::assertTrue( $this->streamContainsScope($stream, $scope, $filter), - sprintf('Failed asserting that scope %s exists for code: %s', $scope->value, $code) + sprintf('Failed asserting that scope %s exists for code: %s', $scope->value, $code), ); } @@ -190,14 +190,14 @@ public static function scopeProvider(): array 'comment' => ['// comment', Scope::Comment, null], 'string' => ['"test"', Scope::String, null], 'template literal' => ['`template`', Scope::String, null], - 'template expression' => ['`${x}`', Scope::StringTemplateExpression, static fn (ParsedToken $token) => str_contains($token->getText(), '$')], + 'template expression' => ['`${x}`', Scope::StringTemplateExpression, static fn(ParsedToken $token) => str_contains($token->getText(), '$')], 'regex' => ['/test/', Scope::RegExp, null], 'number' => ['42', Scope::Number, null], 'boolean true' => ['true', Scope::Boolean, null], 'boolean false' => ['false', Scope::Boolean, null], 'null' => ['null', Scope::Null, null], 'undefined' => ['undefined', Scope::Null, null], - 'operator' => ['a + b', Scope::Operator, static fn (ParsedToken $token) => '+' === $token->getText()], + 'operator' => ['a + b', Scope::Operator, static fn(ParsedToken $token) => '+' === $token->getText()], 'punctuation' => ['()', Scope::Punctuation, null], ]; } @@ -206,22 +206,22 @@ public function testArrowFunctionExpression(): void { $stream = $this->parse('const fn = (x) => x * 2;'); - self::assertTrue($this->streamContainsScope($stream, Scope::Operator, static fn (ParsedToken $token) => '=>' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::Operator, static fn(ParsedToken $token) => '=>' === $token->getText())); } public function testLookaheadForFunctionCalls(): void { $stream = $this->parse('doSomething ();'); - self::assertTrue($this->streamContainsScope($stream, Scope::FunctionCall, static fn (ParsedToken $token) => 'doSomething' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::FunctionCall, static fn(ParsedToken $token) => 'doSomething' === $token->getText())); } public function testInstanceofAndDeleteAreOperators(): void { $stream = $this->parse('obj instanceof Class; delete obj.prop;'); - self::assertTrue($this->streamContainsScope($stream, Scope::KeywordOperator, static fn (ParsedToken $token) => 'instanceof' === $token->getText())); - self::assertTrue($this->streamContainsScope($stream, Scope::KeywordOperator, static fn (ParsedToken $token) => 'delete' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::KeywordOperator, static fn(ParsedToken $token) => 'instanceof' === $token->getText())); + self::assertTrue($this->streamContainsScope($stream, Scope::KeywordOperator, static fn(ParsedToken $token) => 'delete' === $token->getText())); } private function parse(string $code): ParsedStream diff --git a/tests/Unit/Language/JavaScriptLanguageSemanticTest.php b/tests/Unit/Language/JavaScriptLanguageSemanticTest.php index 794820d..40ff8f6 100644 --- a/tests/Unit/Language/JavaScriptLanguageSemanticTest.php +++ b/tests/Unit/Language/JavaScriptLanguageSemanticTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/Language/JavaScriptLanguageTest.php b/tests/Unit/Language/JavaScriptLanguageTest.php index 7ed6b22..da05c3e 100644 --- a/tests/Unit/Language/JavaScriptLanguageTest.php +++ b/tests/Unit/Language/JavaScriptLanguageTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/Language/JsonLanguageSemanticTest.php b/tests/Unit/Language/JsonLanguageSemanticTest.php index dee2175..15a4674 100644 --- a/tests/Unit/Language/JsonLanguageSemanticTest.php +++ b/tests/Unit/Language/JsonLanguageSemanticTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/Language/LanguagesTest.php b/tests/Unit/Language/LanguagesTest.php index 61d356e..17c0669 100644 --- a/tests/Unit/Language/LanguagesTest.php +++ b/tests/Unit/Language/LanguagesTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -41,7 +41,7 @@ public function testGetDefaultLanguagesReturnsLanguageInstances(): void public function testGetDefaultLanguagesContainsExpectedLanguages(): void { $languages = Languages::getDefaultLanguages(); - $identifiers = array_map(fn ($l) => $l->getIdentifier(), $languages); + $identifiers = array_map(fn($l) => $l->getIdentifier(), $languages); $this->assertContains('php', $identifiers); $this->assertContains('html', $identifiers); diff --git a/tests/Unit/Language/MarkdownLanguageSemanticTest.php b/tests/Unit/Language/MarkdownLanguageSemanticTest.php index 55304d5..6b5c691 100644 --- a/tests/Unit/Language/MarkdownLanguageSemanticTest.php +++ b/tests/Unit/Language/MarkdownLanguageSemanticTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/Language/Php/PhpLexerTest.php b/tests/Unit/Language/Php/PhpLexerTest.php index 9838095..bc4253f 100644 --- a/tests/Unit/Language/Php/PhpLexerTest.php +++ b/tests/Unit/Language/Php/PhpLexerTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -35,7 +35,7 @@ public function testNormalizesWhitespace(): void $code = "tokenize($code); - $whitespaceTokens = array_values(array_filter($tokens, fn ($token) => T_WHITESPACE === $token->id)); + $whitespaceTokens = array_values(array_filter($tokens, fn($token) => T_WHITESPACE === $token->id)); self::assertNotEmpty($whitespaceTokens); @@ -77,7 +77,7 @@ public function testMergedWhitespaceTokenContainsCombinedText(): void $whitespaceTokens = array_values(array_filter( $tokens, - static fn (\PhpToken $token): bool => T_WHITESPACE === $token->id, + static fn(\PhpToken $token): bool => T_WHITESPACE === $token->id, )); self::assertNotEmpty($whitespaceTokens); diff --git a/tests/Unit/Language/Php/PhpSemanticParserTest.php b/tests/Unit/Language/Php/PhpSemanticParserTest.php index 52beb4c..5e93791 100644 --- a/tests/Unit/Language/Php/PhpSemanticParserTest.php +++ b/tests/Unit/Language/Php/PhpSemanticParserTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -52,7 +52,7 @@ public function testDetectsExpectedScope(string $code, Scope $scope, ?callable $ self::assertTrue( $this->streamContainsScope($stream, $scope, $filter), - sprintf('Failed asserting that scope %s exists for code: %s', $scope->value, $code) + sprintf('Failed asserting that scope %s exists for code: %s', $scope->value, $code), ); } @@ -70,23 +70,23 @@ public static function scopeProvider(): array 'variable' => [' [' [' [' 'MyClass' === $token->getText()], - 'function definition' => [' 'myFunc' === $token->getText()], + 'class definition' => [' 'MyClass' === $token->getText()], + 'function definition' => [' 'myFunc' === $token->getText()], 'trait definition' => [' [' [' [' 'foo' === $token->getText()], - 'if control keyword' => [' 'if' === $token->getText()], - 'while control keyword' => [' 'while' === $token->getText()], - 'for control keyword' => [' 'for' === $token->getText()], - 'foreach control keyword' => [' 'foreach' === $token->getText()], - 'return keyword' => [' 'return' === $token->getText()], - 'new operator keyword' => [' 'new' === $token->getText()], - 'function call' => [' 'strlen' === $token->getText()], - 'user function call' => [' 'myFunc' === $token->getText()], + 'method definition in class' => [' 'foo' === $token->getText()], + 'if control keyword' => [' 'if' === $token->getText()], + 'while control keyword' => [' 'while' === $token->getText()], + 'for control keyword' => [' 'for' === $token->getText()], + 'foreach control keyword' => [' 'foreach' === $token->getText()], + 'return keyword' => [' 'return' === $token->getText()], + 'new operator keyword' => [' 'new' === $token->getText()], + 'function call' => [' 'strlen' === $token->getText()], + 'user function call' => [' 'myFunc' === $token->getText()], 'magic constant __CLASS__' => [' [' [' 'instanceof' === $token->getText()], + 'instanceof operator' => [' 'instanceof' === $token->getText()], 'null constant' => [' [' [' Scope::Whitespace !== $token->getScope(), + static fn(ParsedToken $token): bool => Scope::Whitespace !== $token->getScope(), )); } $actual = array_map( - static fn (ParsedToken $token): array => [$token->getText(), $token->getScope()], + static fn(ParsedToken $token): array => [$token->getText(), $token->getScope()], $tokens, ); diff --git a/tests/Unit/Language/TwigLanguageSemanticTest.php b/tests/Unit/Language/TwigLanguageSemanticTest.php index 35298f8..6a703e7 100644 --- a/tests/Unit/Language/TwigLanguageSemanticTest.php +++ b/tests/Unit/Language/TwigLanguageSemanticTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/Language/TypeScriptLanguageTest.php b/tests/Unit/Language/TypeScriptLanguageTest.php index 8899696..2661cd9 100644 --- a/tests/Unit/Language/TypeScriptLanguageTest.php +++ b/tests/Unit/Language/TypeScriptLanguageTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -338,7 +338,7 @@ public function testParseGenericTypeParameter(): void { $tokens = $this->parse('function fn(x: T) {}'); // T after < should be TypeReference - $tTokens = array_filter($tokens, fn ($t) => 'T' === $t->getText()); + $tTokens = array_filter($tokens, fn($t) => 'T' === $t->getText()); $this->assertNotEmpty($tTokens); } @@ -445,7 +445,7 @@ public function testTypeAssertionNotTriggeredAfterIdentifier(): void // func should not be treated as type assertion $tokens = $this->parse('identity(value)'); // Should not have Meta scope (which is type assertion) - $metaTokens = array_filter($tokens, fn ($t) => Scope::Meta === $t->getScope()); + $metaTokens = array_filter($tokens, fn($t) => Scope::Meta === $t->getScope()); $this->assertEmpty($metaTokens); } @@ -453,7 +453,7 @@ public function testTypeAssertionNotTriggeredAfterParen(): void { $tokens = $this->parse('(value)'); // Should not be type assertion after closing paren - $metaTokens = array_filter($tokens, fn ($t) => Scope::Meta === $t->getScope()); + $metaTokens = array_filter($tokens, fn($t) => Scope::Meta === $t->getScope()); $this->assertEmpty($metaTokens); } @@ -461,7 +461,7 @@ public function testTypeAssertionNotTriggeredAfterBracket(): void { $tokens = $this->parse('arr[0]'); // Should not be type assertion after closing bracket - $metaTokens = array_filter($tokens, fn ($t) => Scope::Meta === $t->getScope()); + $metaTokens = array_filter($tokens, fn($t) => Scope::Meta === $t->getScope()); $this->assertEmpty($metaTokens); } @@ -487,7 +487,7 @@ public function testNotRegexAfterIdentifier(): void { // a / b should be division, not regex $tokens = $this->parse('a / b'); - $regexTokens = array_filter($tokens, fn ($t) => Scope::RegExp === $t->getScope()); + $regexTokens = array_filter($tokens, fn($t) => Scope::RegExp === $t->getScope()); $this->assertEmpty($regexTokens); } @@ -536,7 +536,7 @@ public function testGenericWithComma(): void { $tokens = $this->parse('Map'); // After comma in generics, should recognize type - $numberTokens = array_filter($tokens, fn ($t) => 'number' === $t->getText()); + $numberTokens = array_filter($tokens, fn($t) => 'number' === $t->getText()); $this->assertNotEmpty($numberTokens); } @@ -562,14 +562,14 @@ private function assertTokenExists(array $tokens, string $text, Scope $scope): v } $tokenList = array_map( - fn ($t) => sprintf('[%s: %s]', $t->getScope()->value, $t->getText()), - $tokens + fn($t) => sprintf('[%s: %s]', $t->getScope()->value, $t->getText()), + $tokens, ); $this->fail(sprintf( 'Token "%s" with scope %s not found. Found: %s', $text, $scope->value, - implode(', ', $tokenList) + implode(', ', $tokenList), )); } } diff --git a/tests/Unit/Parser/ParsedStreamTest.php b/tests/Unit/Parser/ParsedStreamTest.php index 03397b8..19b3f7b 100644 --- a/tests/Unit/Parser/ParsedStreamTest.php +++ b/tests/Unit/Parser/ParsedStreamTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -359,7 +359,7 @@ public function testFindReturnsFirstMatchingToken(): void new ParsedToken('three', Scope::String), ]); - $found = $stream->find(fn ($t) => Scope::String === $t->getScope()); + $found = $stream->find(fn($t) => Scope::String === $t->getScope()); $this->assertNotNull($found); $this->assertEquals('one', $found->getText()); @@ -371,7 +371,7 @@ public function testFindReturnsNullWhenNoMatch(): void new ParsedToken('one', Scope::String), ]); - $found = $stream->find(fn ($t) => Scope::Variable === $t->getScope()); + $found = $stream->find(fn($t) => Scope::Variable === $t->getScope()); $this->assertNull($found); } @@ -384,7 +384,7 @@ public function testFindAllReturnsAllMatchingTokens(): void new ParsedToken('three', Scope::String), ]); - $found = $stream->findAll(fn ($t) => Scope::String === $t->getScope()); + $found = $stream->findAll(fn($t) => Scope::String === $t->getScope()); $this->assertCount(2, $found); $this->assertEquals('one', $found[0]->getText()); @@ -397,7 +397,7 @@ public function testFindAllReturnsEmptyArrayWhenNoMatch(): void new ParsedToken('one', Scope::String), ]); - $found = $stream->findAll(fn ($t) => Scope::Variable === $t->getScope()); + $found = $stream->findAll(fn($t) => Scope::Variable === $t->getScope()); $this->assertEmpty($found); } @@ -409,7 +409,7 @@ public function testMapTransformsEachToken(): void new ParsedToken('two', Scope::String), ]); - $mapped = $stream->map(fn ($t) => $t->withScope(Scope::Keyword)); + $mapped = $stream->map(fn($t) => $t->withScope(Scope::Keyword)); $this->assertCount(2, $mapped); $this->assertEquals(Scope::Keyword, $mapped->getTokens()[0]->getScope()); diff --git a/tests/Unit/Parser/ParsedTokenTest.php b/tests/Unit/Parser/ParsedTokenTest.php index 75b35b5..7983bd6 100644 --- a/tests/Unit/Parser/ParsedTokenTest.php +++ b/tests/Unit/Parser/ParsedTokenTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/Parser/StreamBuilderTest.php b/tests/Unit/Parser/StreamBuilderTest.php index b99f23c..041b1ea 100644 --- a/tests/Unit/Parser/StreamBuilderTest.php +++ b/tests/Unit/Parser/StreamBuilderTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/Parser/TokenTypeTest.php b/tests/Unit/Parser/TokenTypeTest.php index 6301e68..0da4105 100644 --- a/tests/Unit/Parser/TokenTypeTest.php +++ b/tests/Unit/Parser/TokenTypeTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/PygmentsComparisonTest.php b/tests/Unit/PygmentsComparisonTest.php index 6f36ae3..3ad7d2d 100644 --- a/tests/Unit/PygmentsComparisonTest.php +++ b/tests/Unit/PygmentsComparisonTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -246,7 +246,7 @@ function greet($name) { public static function setUpBeforeClass(): void { - self::$pygmentsScript = dirname(__DIR__, 2).'/bin/pygments-tokenize'; + self::$pygmentsScript = dirname(__DIR__, 2) . '/bin/pygments-tokenize'; } private static function isPygmentsAvailable(): bool @@ -263,7 +263,7 @@ private static function isPygmentsAvailable(): bool $process = @proc_open( [$cmd, '-c', 'import pygments'], [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], - $pipes + $pipes, ); if (is_resource($process)) { @@ -321,10 +321,10 @@ private static function getPygmentsTokens(string $language, string $code): array $exitCode, self::$pythonCommand, self::$pygmentsScript, - $language + $language, ); } - self::fail('Pygments error: '.$message); + self::fail('Pygments error: ' . $message); } return $result['tokens']; @@ -388,7 +388,7 @@ public static function languageProvider(): array return array_combine( array_keys($samples), - array_map(fn ($lang) => [$lang], array_keys($samples)), + array_map(fn($lang) => [$lang], array_keys($samples)), ); } @@ -437,7 +437,7 @@ public function testKeyTokensMatchPygments(string $language): void } } - $altoTexts = array_map(fn ($t) => trim($t['text']), $altoTokens); + $altoTexts = array_map(fn($t) => trim($t['text']), $altoTokens); $missingFromAlto = []; foreach ($pygmentsMap as $text => $category) { $text = (string) $text; @@ -465,12 +465,12 @@ public function testKeyTokensMatchPygments(string $language): void $errorMessages = []; if (!empty($mismatches)) { - $errorMessages[] = "Category mismatches for '{$language}':\n".implode("\n", $mismatches); + $errorMessages[] = "Category mismatches for '{$language}':\n" . implode("\n", $mismatches); } if (!empty($errorMessages)) { if (!empty($missingFromAlto)) { - $errorMessages[] = "Note: tokens from Pygments not matched in Alto output:\n".implode("\n", $missingFromAlto); + $errorMessages[] = "Note: tokens from Pygments not matched in Alto output:\n" . implode("\n", $missingFromAlto); } self::fail(implode("\n\n", $errorMessages)); diff --git a/tests/Unit/ScopeTest.php b/tests/Unit/ScopeTest.php index dd1cf1a..b0d84e4 100644 --- a/tests/Unit/ScopeTest.php +++ b/tests/Unit/ScopeTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/Theme/AltoThemeTest.php b/tests/Unit/Theme/AltoThemeTest.php index f30bb24..ad3cc32 100644 --- a/tests/Unit/Theme/AltoThemeTest.php +++ b/tests/Unit/Theme/AltoThemeTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/Theme/CupertinoThemeTest.php b/tests/Unit/Theme/CupertinoThemeTest.php index 10855e2..a7c5899 100644 --- a/tests/Unit/Theme/CupertinoThemeTest.php +++ b/tests/Unit/Theme/CupertinoThemeTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/Theme/DraculaThemeTest.php b/tests/Unit/Theme/DraculaThemeTest.php index 7d25cf4..fdd26d2 100644 --- a/tests/Unit/Theme/DraculaThemeTest.php +++ b/tests/Unit/Theme/DraculaThemeTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/Theme/GitHubThemeTest.php b/tests/Unit/Theme/GitHubThemeTest.php index d98d60d..d863a68 100644 --- a/tests/Unit/Theme/GitHubThemeTest.php +++ b/tests/Unit/Theme/GitHubThemeTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/Theme/NoctisThemeTest.php b/tests/Unit/Theme/NoctisThemeTest.php index ff13576..d3f2807 100644 --- a/tests/Unit/Theme/NoctisThemeTest.php +++ b/tests/Unit/Theme/NoctisThemeTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/Theme/PolarThemeTest.php b/tests/Unit/Theme/PolarThemeTest.php index 664e9a9..639107c 100644 --- a/tests/Unit/Theme/PolarThemeTest.php +++ b/tests/Unit/Theme/PolarThemeTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/Theme/SolarThemeTest.php b/tests/Unit/Theme/SolarThemeTest.php index e100465..834c241 100644 --- a/tests/Unit/Theme/SolarThemeTest.php +++ b/tests/Unit/Theme/SolarThemeTest.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. diff --git a/tests/Unit/Theme/ThemeTestCase.php b/tests/Unit/Theme/ThemeTestCase.php index 3dfb145..80df849 100644 --- a/tests/Unit/Theme/ThemeTestCase.php +++ b/tests/Unit/Theme/ThemeTestCase.php @@ -5,7 +5,7 @@ /* * This file is part of the ALTO library. * - * © 2026–present Simon André + * © 2026-present Simon André * * For full copyright and license information, please see * the LICENSE file distributed with this source code. @@ -54,7 +54,7 @@ final public function testStylesheetContainsAllCssClasses( self::assertStringContainsString('.alto-highlight', $stylesheet); foreach (array_unique(array_values($expectedCssClasses)) as $className) { - self::assertStringContainsString('.'.$className, $stylesheet); + self::assertStringContainsString('.' . $className, $stylesheet); } } @@ -126,7 +126,7 @@ final protected static function prefixedExpectedClasses(string $prefix, array $o $classes = []; foreach (self::canonicalScopeTokens() as [$scope, $key, $default]) { $suffix = $overrides[$key] ?? $default; - $classes[$scope->value] = '' === $suffix ? '' : $prefix.$suffix; + $classes[$scope->value] = '' === $suffix ? '' : $prefix . $suffix; } return $classes;