Browse Source

Improve autolink

The current regex doesn't support URLs ending with a `/` even though they are valid.

This changes the regex to use the more robust one from Visual Studio Code.
Thibault Derousseaux 5 years ago
parent
commit
756267a049
2 changed files with 21 additions and 11 deletions
  1. 18 11
      packages/rendermime/src/renderers.ts
  2. 3 0
      tests/test-rendermime/src/factories.spec.ts

+ 18 - 11
packages/rendermime/src/renderers.ts

@@ -475,18 +475,25 @@ export namespace renderSVG {
  * @returns The content where all URLs have been replaced with corresponding links.
  */
 function autolink(content: string): string {
-  return content.replace(
-    // Same pattern as in classic notebook with word boundaries (\b).
-    /\b((https?|ftp)(:[^'"<>\s]+))\b/g,
-    url => {
-      const a = document.createElement('a');
-      a.href = url;
-      a.textContent = url;
-      a.rel = 'noopener';
-      a.target = '_blank';
-      return a.outerHTML;
-    }
+  // Taken from Visual Studio Code:
+  // https://github.com/microsoft/vscode/blob/9f709d170b06e991502153f281ec3c012add2e42/src/vs/workbench/contrib/debug/browser/linkDetector.ts#L17-L18
+  const controlCodes = '\\u0000-\\u0020\\u007f-\\u009f';
+  const webLinkRegex = new RegExp(
+    '(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}:\\/\\/|data:|www\\.)[^\\s' +
+      controlCodes +
+      '"]{2,}[^\\s' +
+      controlCodes +
+      '"\')}\\],:;.!?]',
+    'ug'
   );
+  return content.replace(webLinkRegex, url => {
+    const a = document.createElement('a');
+    a.href = url;
+    a.textContent = url;
+    a.rel = 'noopener';
+    a.target = '_blank';
+    return a.outerHTML;
+  });
 }
 
 /**

+ 3 - 0
tests/test-rendermime/src/factories.spec.ts

@@ -104,8 +104,11 @@ describe('rendermime/factories', () => {
       it('should autolink URLs', async () => {
         const f = textRendererFactory;
         const urls = [
+          'https://example.com',
+          'https://example.com/',
           'https://example.com#anchor',
           'http://localhost:9090/app',
+          'http://localhost:9090/app/',
           'http://127.0.0.1/test?query=string'
         ];
         await Promise.all(