From a821a4be17a4ce705d449826e861a9419e19b7f2 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 28 Sep 2026 14:55:56 +0800 Subject: [PATCH] fix(link): isolate per-link target overrides --- src/core/render/compiler.js | 3 +-- src/core/render/compiler/link.js | 7 +++---- test/integration/render.test.js | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/core/render/compiler.js b/src/core/render/compiler.js index d77a15364..a0b5bbf8f 100644 --- a/src/core/render/compiler.js +++ b/src/core/render/compiler.js @@ -160,7 +160,7 @@ export class Compiler { _initRenderer() { const renderer = new marked.Renderer(); - const { linkTarget, linkRel, router, contentBase } = this; + const { linkTarget, router, contentBase } = this; // Supports mermaid const origin = {}; @@ -179,7 +179,6 @@ export class Compiler { renderer, router, linkTarget, - linkRel, compiler: this, }); origin.paragraph = paragraphCompiler({ renderer }); diff --git a/src/core/render/compiler/link.js b/src/core/render/compiler/link.js index 6c017adcf..93e042bfb 100644 --- a/src/core/render/compiler/link.js +++ b/src/core/render/compiler/link.js @@ -4,8 +4,7 @@ import { isAbsolutePath } from '../../router/util.js'; export const linkCompiler = ({ renderer, router, - linkTarget, - linkRel, + linkTarget: defaultLinkTarget, compiler, }) => (renderer.link = function ({ href, title = '', tokens }) { @@ -16,8 +15,8 @@ export const linkCompiler = ({ const isNotCompilable = compiler._matchNotCompileLink(href); const isMailto = href.startsWith('mailto:'); - linkTarget = config.target || linkTarget; - linkRel = + const linkTarget = config.target || defaultLinkTarget; + const linkRel = linkTarget === '_blank' ? compiler.config.externalLinkRel || 'noopener' : ''; diff --git a/test/integration/render.test.js b/test/integration/render.test.js index bb49c98e2..e3989ed72 100644 --- a/test/integration/render.test.js +++ b/test/integration/render.test.js @@ -352,6 +352,21 @@ Text

" ); }); + test.each([ + 'https://example.org/first', + '/first', + 'mailto:first@example.org', + ])('does not leak a target override from %s into later links', href => { + const container = document.createElement('div'); + container.innerHTML = window.marked( + `[First](${href} ':target=_self')\n\n[Second](https://example.org/second)`, + ); + + const secondLink = container.querySelectorAll('a')[1]; + expect(secondLink.target).toBe('_blank'); + expect(secondLink.rel).toBe('noopener'); + }); + test('target for relative path', async function () { const output = window.marked("[alt text](/url ':target=_blank')");