From 951042885bc65ca9069d194edc35ba751f4b0bf5 Mon Sep 17 00:00:00 2001 From: NickSdot Date: Thu, 30 Oct 2025 22:07:39 +0700 Subject: [PATCH] refactor: removed negation operator --- README.md | 19 +++------- src/BladeHtmlAttributesServiceProvider.php | 40 ---------------------- tests/AriaDirectiveTest.php | 23 ++----------- tests/AttrDirectiveTest.php | 8 ----- tests/DataDirectiveTest.php | 8 ----- tests/FlagDirectiveTest.php | 8 ----- 6 files changed, 6 insertions(+), 100 deletions(-) diff --git a/README.md b/README.md index 820e130..90ab285 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,6 @@ The package will auto-register the service provider. ### Behaviour Matrix -**Note:** Rows in **bold** show special operator `=` & `!` behaviour. - | Value | `@attr` | `@data` | `@aria` | `@flag` | |-----------------------|-------------------|------------------------|--------------------|-------------| | `('foo', "bar")` | `foo="bar"` | `data-foo="bar"` | `aria-foo="bar"` | `foo` | @@ -25,7 +23,6 @@ The package will auto-register the service provider. | **`('foo=', true)`** | **`foo="true"`** | **`data-foo="true"`** | `aria-foo="true"` | `foo` | | `('foo', false)` | _(nothing)_ | _(nothing)_ | `aria-foo="false"` | _(nothing)_ | | **`('foo=', false)`** | **`foo="false"`** | **`data-foo="false"`** | `aria-foo="false"` | _(nothing)_ | -| **`('!foo', false)`** | _(throws)_ | _(throws)_ | **_(nothing)_** | _(throws)_ | | `('foo', "0")` | `foo="0"` | `data-foo="0"` | `aria-foo="0"` | _(nothing)_ | | `('foo', 0)` | `foo="0"` | `data-foo="0"` | `aria-foo="0"` | _(nothing)_ | | `('foo', '')` | _(nothing)_ | _(nothing)_ | _(nothing)_ | _(nothing)_ | @@ -35,18 +32,14 @@ The package will auto-register the service provider. | `('foo', null)` | _(nothing)_ | _(nothing)_ | _(nothing)_ | _(nothing)_ | **Gotchas:** -- `@attr` and `@data` allow the `=` suffix (e.g., `@attr('foo=', $value)`) to force values (always render with `="value"`, even for booleans and empty strings) -- `@aria` allows the `!` prefix (e.g., `@aria('!foo', $value)`) to negate false values for removing attribute entirely. +- `@attr` and `@data` allow the `=` suffix (`@attr('foo=', $value)`) to force values (always render with `="value"`, even for booleans and empty strings). The **bold** market rows show the special behaviour. ### Descriptions -- **`@attr`**: By default, `true` renders as a boolean flag (attribute name only), and `false`/empty/whitespace-only/null render nothing. With the force-value operator (`=` suffix like `'foo='`), always renders with values including`"true"`, `"false"`, and empty strings. - +- **`@attr`**: By default, `true` renders as a boolean flag (attribute name only), and `false`/empty/whitespace-only/null render nothing. With the `=` force-value operator (e.g. `'foo='`), always renders with values including`"true"`, + `"false"`, and empty strings. - **`@data`**: Same as `@attr` but automatically prefixes attribute names with `data-`. - -- **`@aria`**: By default, renders all values including `"true"` and `"false"` (never as boolean flags). Never renders empty or whitespace-only strings. With the negation operator (`!` prefix like `'! -foo'`), `false` the attribute is completely removed instead of rendering as `"false"`. - +- **`@aria`**: By default, renders all values including `"true"` and `"false"` (never as boolean flags). Never renders empty or whitespace-only strings. - **`@flag`**: Outputs just the attribute name without a value (boolean flag), for truthy values only. Follows HTML spec for boolean attributes like `disabled`, `checked`, `required` or `data-foo`. ## Examples @@ -99,10 +92,6 @@ foo'`), `false` the attribute is completely removed instead of rendering as `"fa {{-- Before / After --}}
- -{{-- Before / After --}} - -
``` ### `@flag` Directive diff --git a/src/BladeHtmlAttributesServiceProvider.php b/src/BladeHtmlAttributesServiceProvider.php index fd68e00..ba709d9 100644 --- a/src/BladeHtmlAttributesServiceProvider.php +++ b/src/BladeHtmlAttributesServiceProvider.php @@ -53,10 +53,6 @@ protected function compileFlag(string $expression): string [ $attribute, $data ] = array_map('trim', $parts); - if (str_starts_with($attribute, "'!") || str_starts_with($attribute, '"!')) { - throw new ViewCompilationException('The @flag directive does not support negation.'); - } - if (str_ends_with($attribute, "='") || str_ends_with($attribute, '="')) { throw new ViewCompilationException('The @flag directive does not support forced values.'); } @@ -75,10 +71,6 @@ protected function compileAttr(string $expression): string [ $attribute, $data ] = array_map('trim', $parts); - if (str_starts_with($attribute, "'!") || str_starts_with($attribute, '"!')) { - throw new ViewCompilationException('The @attr directive does not support negation.'); - } - $forceValue = str_ends_with($attribute, "='") || str_ends_with($attribute, '="'); if ($forceValue) { @@ -100,10 +92,6 @@ protected function compileData(string $expression): string [ $attribute, $data ] = array_map('trim', $parts); - if (str_starts_with($attribute, "'!") || str_starts_with($attribute, '"!')) { - throw new ViewCompilationException('The @data directive does not support negation.'); - } - $forceValue = str_ends_with($attribute, "='") || str_ends_with($attribute, '="'); if ($forceValue) { @@ -125,12 +113,6 @@ protected function compileAria(string $expression): string [ $attribute, $data ] = array_map('trim', $parts); - $negated = str_starts_with($attribute, "'!") || str_starts_with($attribute, '"!'); - - if ($negated) { - return ""; - } - return ""; } @@ -180,28 +162,6 @@ public static function renderData(string $attribute, string|int|float|bool|null return self::renderCommon($data, 'data-' . $attribute); } - /** @api */ - public static function renderAriaNegated(string $attribute, string|int|float|bool|null $data): string - { - $attribute = 'aria-' . mb_substr($attribute, 1); // remove = operator, add `aria-` prefix - - if (null === $data || false === $data) { - return ''; - } - - if (is_bool($data)) { - return $attribute . '="true"'; - } - - $stringData = (string) $data; - - if ('' === $stringData || '' === mb_trim($stringData)) { - return ''; - } - - return $attribute . '="' . e($stringData) . '"'; - } - /** @api */ public static function renderAria(string $attribute, string|int|float|bool|null $data): string { diff --git a/tests/AriaDirectiveTest.php b/tests/AriaDirectiveTest.php index a4d8676..15059ec 100644 --- a/tests/AriaDirectiveTest.php +++ b/tests/AriaDirectiveTest.php @@ -11,36 +11,17 @@ final class AriaDirectiveTest extends TestCase public function testAriaDirective(): void { $default = "@aria('foo', \$bar)"; - $negated = "@aria('!foo', \$bar)"; $this->assertSame('aria-foo="test"', $this->render($default, [ 'bar' => 'test' ])); - $this->assertSame('aria-foo="test"', $this->render($negated, [ 'bar' => 'test' ])); $this->assertSame('aria-foo="0"', $this->render($default, [ 'bar' => 0 ])); - $this->assertSame('aria-foo="0"', $this->render($negated, [ 'bar' => '0' ])); - $this->assertSame('aria-foo="1"', $this->render($default, [ 'bar' => 1 ])); - $this->assertSame('aria-foo="1"', $this->render($negated, [ 'bar' => '1' ])); - $this->assertSame('aria-foo="8"', $this->render($default, [ 'bar' => 8 ])); - $this->assertSame('aria-foo="8"', $this->render($negated, [ 'bar' => '8' ])); - - // aria never has empty strings - $this->assertSame('', $this->render($default, [ 'bar' => '' ])); - $this->assertSame('', $this->render($negated, [ 'bar' => '' ])); - - // aria never has whitespace-only strings - $this->assertSame('', $this->render($default, [ 'bar' => ' ' ])); - $this->assertSame('', $this->render($negated, [ 'bar' => ' ' ])); - + $this->assertSame('', $this->render($default, [ 'bar' => '' ])); // aria never has empty strings + $this->assertSame('', $this->render($default, [ 'bar' => ' ' ])); // aria never has whitespace-only strings $this->assertSame('', $this->render($default, [ 'bar' => null ])); - $this->assertSame('', $this->render($negated, [ 'bar' => null ])); - $this->assertSame('aria-foo="true"', $this->render($default, [ 'bar' => true ])); - $this->assertSame('aria-foo="true"', $this->render($negated, [ 'bar' => true ])); - $this->assertSame('aria-foo="false"', $this->render($default, [ 'bar' => false ])); - $this->assertSame('', $this->render($negated, [ 'bar' => false ])); $this->assertSame( 'aria-foo="<script>alert('xss')</script>"', diff --git a/tests/AttrDirectiveTest.php b/tests/AttrDirectiveTest.php index f9e167f..17abd55 100644 --- a/tests/AttrDirectiveTest.php +++ b/tests/AttrDirectiveTest.php @@ -77,14 +77,6 @@ public function testAttrDirectiveParameterCount(): void Blade::compileString("@attr('foo')"); } - public function testAttrDirectiveUnsupportedNegation(): void - { - $this->expectException(ViewCompilationException::class); - $this->expectExceptionMessage('The @attr directive does not support negation.'); - - Blade::compileString("@attr('!foo', true)"); - } - /** @param array $data */ protected function render(string $directive, array $data = []): string|false { diff --git a/tests/DataDirectiveTest.php b/tests/DataDirectiveTest.php index 806c210..fa9cc00 100644 --- a/tests/DataDirectiveTest.php +++ b/tests/DataDirectiveTest.php @@ -77,14 +77,6 @@ public function testDataDirectiveParameterCount(): void Blade::compileString("@data('foo')"); } - public function testDataDirectiveUnsupportedNegation(): void - { - $this->expectException(ViewCompilationException::class); - $this->expectExceptionMessage('The @data directive does not support negation.'); - - Blade::compileString("@data('!foo', true)"); - } - /** @param array $data */ protected function render(string $directive, array $data = []): string|false { diff --git a/tests/FlagDirectiveTest.php b/tests/FlagDirectiveTest.php index 5b67e07..c980c09 100644 --- a/tests/FlagDirectiveTest.php +++ b/tests/FlagDirectiveTest.php @@ -61,14 +61,6 @@ public function testFlagDirectiveParameterCount(): void Blade::compileString("@flag('disabled')"); } - public function testFlagDirectiveUnsupportedNegation(): void - { - $this->expectException(ViewCompilationException::class); - $this->expectExceptionMessage('The @flag directive does not support negation.'); - - Blade::compileString("@flag('!foo', true)"); - } - /** @param array $data */ protected function render(string $renderable, array $data = []): string|false {