diff --git a/CHANGELOG.md b/CHANGELOG.md
index e69e1f177c..69b6742b51 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -319,6 +319,7 @@ Notes: web developers are advised to use [`~` (tilde range)](https://github.com/
by [@lexi-taylor](https://github.com/lexi-taylor)
- Fixed `npm start` may fail subsequently as builds are not fully flushed to `/dist/`, in PR [#5599](https://github.com/microsoft/BotFramework-WebChat/pull/5599), by [@compulim](https://github.com/compulim)
- Fixed published package types containing internal package references, in PR [#5610](https://github.com/microsoft/BotFramework-WebChat/pull/5610), by [@OEvgeny](https://github.com/OEvgeny)
+- Fixed citation links are not properly matched against markdown links, in PR [#5614](https://github.com/microsoft/BotFramework-WebChat/pull/5614), by [@OEvgeny](https://github.com/OEvgeny)
### Removed
diff --git a/__tests__/html2/citation/url.fluent.html b/__tests__/html2/citation/url.fluent.html
new file mode 100644
index 0000000000..628206af79
--- /dev/null
+++ b/__tests__/html2/citation/url.fluent.html
@@ -0,0 +1,10 @@
+
+
+
+ Citation URL (fluent)
+
+
+
+
diff --git a/__tests__/html2/citation/url.fluent.html.snap-1.png b/__tests__/html2/citation/url.fluent.html.snap-1.png
new file mode 100644
index 0000000000..91bb35821b
Binary files /dev/null and b/__tests__/html2/citation/url.fluent.html.snap-1.png differ
diff --git a/__tests__/html2/citation/url.html b/__tests__/html2/citation/url.html
new file mode 100644
index 0000000000..1279961be9
--- /dev/null
+++ b/__tests__/html2/citation/url.html
@@ -0,0 +1,343 @@
+
+
+
+
+ Citation URL
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/__tests__/html2/citation/url.html.snap-1.png b/__tests__/html2/citation/url.html.snap-1.png
new file mode 100644
index 0000000000..04233b7d60
Binary files /dev/null and b/__tests__/html2/citation/url.html.snap-1.png differ
diff --git a/package-lock.json b/package-lock.json
index dee9274e47..e1157a5367 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13202,7 +13202,9 @@
}
},
"node_modules/micromark-util-sanitize-uri": {
- "version": "2.0.0",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz",
+ "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==",
"funding": [
{
"type": "GitHub Sponsors",
@@ -19038,6 +19040,7 @@
"micromark": "4.0.2",
"micromark-extension-gfm": "3.0.0",
"micromark-util-character": "2.1.1",
+ "micromark-util-sanitize-uri": "^2.0.1",
"microsoft-cognitiveservices-speech-sdk": "1.17.0",
"prop-types": "15.8.1",
"punycode": "2.3.1",
diff --git a/packages/bundle/package.json b/packages/bundle/package.json
index e155d31ac3..c7c4259c60 100644
--- a/packages/bundle/package.json
+++ b/packages/bundle/package.json
@@ -188,6 +188,7 @@
"micromark": "4.0.2",
"micromark-extension-gfm": "3.0.0",
"micromark-util-character": "2.1.1",
+ "micromark-util-sanitize-uri": "^2.0.1",
"microsoft-cognitiveservices-speech-sdk": "1.17.0",
"prop-types": "15.8.1",
"punycode": "2.3.1",
@@ -240,8 +241,8 @@
},
"peerDependencies": {
"@types/react": "^16.14.65",
- "react-chain-of-responsibility": "0.4.0-main.c2f17da",
"react": ">= 16.8.6",
+ "react-chain-of-responsibility": "0.4.0-main.c2f17da",
"react-dom": ">= 16.8.6"
}
}
diff --git a/packages/bundle/src/markdown/renderMarkdown.ts b/packages/bundle/src/markdown/renderMarkdown.ts
index 3bb9a182ba..a4c7d49089 100644
--- a/packages/bundle/src/markdown/renderMarkdown.ts
+++ b/packages/bundle/src/markdown/renderMarkdown.ts
@@ -7,6 +7,7 @@ import { onErrorResumeNext } from 'botframework-webchat-core';
import katex from 'katex';
import { micromark } from 'micromark';
import { gfm, gfmHtml } from 'micromark-extension-gfm';
+import { sanitizeUri } from 'micromark-util-sanitize-uri';
import { math, mathHtml } from './mathExtension';
import betterLinkDocumentMod, { BetterLinkDocumentModDecoration } from './private/betterLinkDocumentMod';
@@ -26,7 +27,13 @@ export default function render(
{ markdownRespectCRLF, markdownRenderHTML }: Readonly<{ markdownRespectCRLF: boolean; markdownRenderHTML?: boolean }>,
{ externalLinkAlt }: RenderInit
): string {
- const linkDefinitions = Array.from(iterateLinkDefinitions(markdown));
+ const linkDefinitions = Array.from(iterateLinkDefinitions(markdown)).map(definition =>
+ Object.freeze({
+ ...definition,
+ markupUrl: sanitizeUri(definition.url),
+ parsedUrl: onErrorResumeNext(() => new URL(definition.url))
+ })
+ );
if (markdownRespectCRLF) {
markdown = respectCRLFPre(markdown);
@@ -41,13 +48,11 @@ export default function render(
const ariaLabelSegments: string[] = [textContent];
const classes: Set = new Set();
- const linkDefinition = linkDefinitions.find(({ url }) => url === href);
+ const linkDefinition = linkDefinitions.find(({ url, markupUrl }) => url === href || (href && markupUrl === href));
const protocol = onErrorResumeNext(() => new URL(href).protocol);
if (linkDefinition) {
- ariaLabelSegments.push(
- linkDefinition.title || onErrorResumeNext(() => new URL(linkDefinition.url).host) || linkDefinition.url
- );
+ ariaLabelSegments.push(linkDefinition.title || linkDefinition?.parsedUrl?.host || linkDefinition.url);
// linkDefinition.identifier is uppercase, while linkDefinition.label is as-is.
linkDefinition.label === textContent && classes.add('webchat__render-markdown__pure-identifier');