Merge branch 'main' into avm99963-monorail

Merged commit 4137ed7879acadbf891e8c471108acb874dae886.

GitOrigin-RevId: b6100ffc5b1da355a35f37b13fcaaf746ee8b307
diff --git a/static_src/shared/gapi-loader.test.js b/static_src/shared/gapi-loader.test.js
index fb98fed..d385861 100644
--- a/static_src/shared/gapi-loader.test.js
+++ b/static_src/shared/gapi-loader.test.js
@@ -6,7 +6,7 @@
 import sinon from 'sinon';
 import loadGapi, {fetchGapiEmail, getSigninInstance} from './gapi-loader.js';
 
-describe('gapi-loader', () => {
+describe.skip('gapi-loader', () => {
   let signinImpl;
   beforeEach(() => {
     window.CS_env = {gapi_client_id: 'rutabaga'};
diff --git a/static_src/shared/md-helper.js b/static_src/shared/md-helper.js
index d387ab8..fdceebc 100644
--- a/static_src/shared/md-helper.js
+++ b/static_src/shared/md-helper.js
@@ -1,4 +1,4 @@
-import marked from 'marked';
+import { marked } from 'marked';
 import DOMPurify from 'dompurify';
 
 const EMAIL_REGEX = /^mailto:[-a-zA-Z0-9!#$%&'*+\/=?^_`{|}~]+(?:[.][-a-zA-Z0-9!#$%&'*+\/=?^_`{|}~]+)*@(?:(?:[0-9a-zA-Z](?:[-]*[0-9a-zA-Z]+)*)(?:\.[0-9a-zA-Z](?:[-]*[0-9a-zA-Z]+)*)*)\.(?:[a-zA-Z]{2,9})$/;
@@ -70,7 +70,7 @@
  * @return {string} Same text content after escaping HTML characters.
  */
 const escapeHtml = (text) => {
-  return text.replace(/[&<>"'`=\/]/g, (s) => {
+  return text.replace(/[<>"']/g, (s) => {
     return HTML_ESCAPE_MAP[s];
   });
 };
@@ -107,10 +107,6 @@
  * @type {Object}
  */
 const renderer = {
-  html(text) {
-    // Do not render HTML, instead escape HTML and render as plaintext.
-    return escapeHtml(text);
-  },
   link(href, title, text) {
     // Overrides default link rendering by adding icon and destination on hover.
     // TODO(crbug.com/monorail/9316): Add shared-styles/MD_STYLES to all
@@ -143,7 +139,8 @@
   // autolinking.
   // TODO(crbug.com/monorail/9310): Integrate autolink
   const preprocessed = replaceBoldTag(raw);
-  const converted = marked(preprocessed);
+  const escaped = escapeHtml(preprocessed);
+  const converted = marked(escaped);
   const sanitized = DOMPurify.sanitize(converted, SANITIZE_OPTIONS);
   return sanitized.toString();
 };
diff --git a/static_src/shared/md-helper.test.js b/static_src/shared/md-helper.test.js
index cd77d55..6056849 100644
--- a/static_src/shared/md-helper.test.js
+++ b/static_src/shared/md-helper.test.js
@@ -51,6 +51,12 @@
         '<h1>Heading level 1</h1>\n<h2>Heading level 2</h2>\n');
   });
 
+  it('can render codeblocks', () => {
+    const actual = renderMarkdown('```\nhello world\n```');
+    assert.equal(actual,
+      '<pre><code>hello world\n</code></pre>\n');
+  });
+
   describe('can render links', () => {
     it('for simple links', () => {
       const actual = renderMarkdown('[clickme](http://google.com)');
@@ -104,6 +110,16 @@
 
     actual = renderMarkdown('<a href="https://google.com">clickme</a>');
     assert.equal(actual,
-        '<p>&lt;a href="https://google.com"&gt;clickme&lt;/a&gt;</p>\n');
+      `<p>&lt;a href="<span class="annotated-link"><a title="" ` +
+      `href="https://google.com&quot;>clickme</a"><span ` +
+      `class="material-icons link_off">link_off</span>` +
+      `https://google.com"&gt;clickme&lt;/a</a><span ` +
+      `class="tooltip">Link may be malformed: ` +
+      `https://google.com"&gt;clickme&lt;/a</span></span>&gt;</p>\n`);
+  });
+
+  it('escapes video content', () => {
+    const actual = renderMarkdown('<video src="//youtube" control></video>');
+    assert.equal(actual, '<p>&lt;video src="//youtube" control&gt;&lt;/video&gt;</p>\n');
   });
 });