diff --git a/lib/index.js b/lib/index.js index abe0ec2..414a534 100644 --- a/lib/index.js +++ b/lib/index.js @@ -84,7 +84,6 @@ import {unreachable} from 'devlop' import {toJsxRuntime} from 'hast-util-to-jsx-runtime' import {urlAttributes} from 'html-url-attributes' -import {sanitizeUri} from 'micromark-util-sanitize-uri' // @ts-expect-error: untyped. import {Fragment, jsx, jsxs} from 'react/jsx-runtime' import remarkParse from 'remark-parse' @@ -297,5 +296,26 @@ export function Markdown(options) { * Safe URL. */ export function defaultUrlTransform(value) { - return sanitizeUri(value, safeProtocol) + // Same as: + // + // But without the `encode` part. + const colon = value.indexOf(':') + const questionMark = value.indexOf('?') + const numberSign = value.indexOf('#') + const slash = value.indexOf('/') + + if ( + // If there is no protocol, it’s relative. + colon < 0 || + // If the first colon is after a `?`, `#`, or `/`, it’s not a protocol. + (slash > -1 && colon > slash) || + (questionMark > -1 && colon > questionMark) || + (numberSign > -1 && colon > numberSign) || + // It is a protocol, it should be allowed. + safeProtocol.test(value.slice(0, colon)) + ) { + return value + } + + return '' } diff --git a/package.json b/package.json index 1a21d10..cfdea22 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,6 @@ "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", - "micromark-util-sanitize-uri": "^2.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", diff --git a/test.jsx b/test.jsx index 4d1ba14..f803df9 100644 --- a/test.jsx +++ b/test.jsx @@ -326,6 +326,13 @@ test('react-markdown', async function (t) { ) }) + await t.test('should support hash (`&`) in a URL', function () { + assert.equal( + asHtml(), + '

' + ) + }) + await t.test('should support hash (`#`) in a URL', function () { assert.equal( asHtml(),