Repository: thephpleague/commonmark (php)

Issue:
LinkRenderer always adding `rel="noopener noreferrer"` when opening in new window
### Version(s) affected

2.4.0

### Description

When an external link is set to open in a new window, the `noopener` and `noreferrer` values are being added, even though my config has disabled them.

### How to reproduce

Here is my setup

```php
        $config = [
            'external_link' => [
                'internal_hosts' => ['my-internal-domain.com'],
                'open_in_new_window' => true,
                'nofollow' => '',
                'noopener' => '',
                'noreferrer' => '',
            ],
        ];

        $converter = new GithubFlavoredMarkdownConverter($config);
        $converter->getEnvironment()->addExtension(new ExternalLinkExtension());

        $converter->getEnvironment()->addRenderer(FencedCode::class, new FencedCodeRenderer());
        $converter->getEnvironment()->addRenderer(IndentedCode::class, new IndentedCodeRenderer());
```

Markdown input:
```
This is an external link [Google](https://google.com/).
```

HTML output:
```
<a target="_blank" href="https://google.com/" rel="noopener noreferrer">Google</a>
```

Expected output:
```
<a target="_blank" href="https://goggle.com/">Google</a>
```

Pull request:
Fix ExternalLinkProcessor not fully disabling the `rel` attribute
Fixes #992 


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9c43dbf0..c71083ed 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,10 @@ Updates should follow the [Keep a CHANGELOG](https://keepachangelog.com/) princi
 
 ## [Unreleased][unreleased]
 
+### Fixed
+
+- Fixed `ExternalLinkProcessor` not fully disabling the `rel` attribute when configured to do so (#992)
+
 ## [2.4.0] - 2023-03-24
 
 ### Added
diff --git a/src/Extension/ExternalLink/ExternalLinkProcessor.php b/src/Extension/ExternalLink/ExternalLinkProcessor.php
index 0f185207..4a0aa890 100644
--- a/src/Extension/ExternalLink/ExternalLinkProcessor.php
+++ b/src/Extension/ExternalLink/ExternalLinkProcessor.php
@@ -90,6 +90,11 @@ final class ExternalLinkProcessor
                     $link->data->append('attributes/rel', $type);
             }
         }
+
+        // No rel attributes? Mark the attribute as 'false' so LinkRenderer doesn't add defaults
+        if (! $link->data->has('attributes/rel')) {
+            $link->data->set('attributes/rel', false);
+        }
     }
 
     /**


Test patch:
diff --git a/tests/functional/Extension/ExternalLink/ExternalLinkExtensionTest.php b/tests/functional/Extension/ExternalLink/ExternalLinkExtensionTest.php
index ff84714c..1a103f3e 100644
--- a/tests/functional/Extension/ExternalLink/ExternalLinkExtensionTest.php
+++ b/tests/functional/Extension/ExternalLink/ExternalLinkExtensionTest.php
@@ -13,6 +13,7 @@ declare(strict_types=1);
 
 namespace League\CommonMark\Tests\Functional\Extension\ExternalLink;
 
+use League\CommonMark\CommonMarkConverter;
 use League\CommonMark\Environment\Environment;
 use League\CommonMark\Environment\EnvironmentInterface;
 use League\CommonMark\Extension\Autolink\AutolinkExtension;
@@ -65,4 +66,25 @@ final class ExternalLinkExtensionTest extends TestCase
 
         yield 'Register Autolink extension first' => [$environment2];
     }
+
+    public function testExtensionWithRelAttrsDisabled(): void
+    {
+        $config = [
+            'external_link' => [
+                'internal_hosts' => ['my-internal-domain.com'],
+                'open_in_new_window' => true,
+                'nofollow' => '',
+                'noopener' => '',
+                'noreferrer' => '',
+            ],
+        ];
+
+        $converter = new CommonMarkConverter($config);
+        $converter->getEnvironment()->addExtension(new ExternalLinkExtension());
+
+        $input        = 'This is an external link [Google](https://google.com/).';
+        $expectedHtml = '<p>This is an external link <a target="_blank" href="https://google.com/">Google</a>.</p>';
+
+        $this->assertSame($expectedHtml, \rtrim($converter->convert($input)->getContent()));
+    }
 }