diff --git a/src/components/Widgets/Markdown/serializers/__tests__/remarkAllowHtmlEntities.spec.js b/src/components/Widgets/Markdown/serializers/__tests__/remarkAllowHtmlEntities.spec.js
new file mode 100644
index 00000000..a7eed4c4
--- /dev/null
+++ b/src/components/Widgets/Markdown/serializers/__tests__/remarkAllowHtmlEntities.spec.js
@@ -0,0 +1,24 @@
+import unified from 'unified';
+import markdownToRemark from 'remark-parse';
+import remarkAllowHtmlEntities from '../remarkAllowHtmlEntities';
+
+const process = markdown => {
+ const mdast = unified().use(markdownToRemark).use(remarkAllowHtmlEntities).parse(markdown);
+
+ /**
+ * The MDAST will look like:
+ *
+ * { type: 'root', children: [
+ * { type: 'paragraph', children: [
+ * // results here
+ * ]}
+ * ]}
+ */
+ return mdast.children[0].children[0].value;
+};
+
+describe('remarkAllowHtmlEntities', () => {
+ it('should not decode HTML entities', () => {
+ expect(process('<div>')).toEqual('<div>');
+ });
+});
diff --git a/src/components/Widgets/Markdown/serializers/__tests__/slate.spec.js b/src/components/Widgets/Markdown/serializers/__tests__/slate.spec.js
index b602eca1..fd3bda41 100644
--- a/src/components/Widgets/Markdown/serializers/__tests__/slate.spec.js
+++ b/src/components/Widgets/Markdown/serializers/__tests__/slate.spec.js
@@ -8,7 +8,7 @@ describe('slate', () => {
expect(process('a\n')).toEqual('a\n');
});
- xit('should not decode encoded html entities in inline code', () => {
+ it('should not decode encoded html entities in inline code', () => {
expect(process('<div>
')).toEqual('<div>
\n');
});
diff --git a/src/components/Widgets/Markdown/serializers/index.js b/src/components/Widgets/Markdown/serializers/index.js
index 19e2a0e9..5b00150d 100644
--- a/src/components/Widgets/Markdown/serializers/index.js
+++ b/src/components/Widgets/Markdown/serializers/index.js
@@ -18,6 +18,7 @@ import remarkImagesToText from './remarkImagesToText';
import remarkShortcodes from './remarkShortcodes';
import remarkEscapeMarkdownEntities from './remarkEscapeMarkdownEntities';
import remarkStripTrailingBreaks from './remarkStripTrailingBreaks';
+import remarkAllowHtmlEntities from './remarkAllowHtmlEntities';
import slateToRemark from './slateRemark';
import registry from '../../../../lib/registry';
@@ -66,6 +67,7 @@ export const markdownToRemark = markdown => {
const parsed = unified()
.use(markdownToRemarkPlugin, { fences: true, commonmark: true })
.use(markdownToRemarkRemoveTokenizers, { inlineTokenizers: ['url'] })
+ .use(remarkAllowHtmlEntities)
.parse(markdown);
/**
diff --git a/src/components/Widgets/Markdown/serializers/remarkAllowHtmlEntities.js b/src/components/Widgets/Markdown/serializers/remarkAllowHtmlEntities.js
new file mode 100644
index 00000000..62e4d3be
--- /dev/null
+++ b/src/components/Widgets/Markdown/serializers/remarkAllowHtmlEntities.js
@@ -0,0 +1,59 @@
+export default function remarkAllowHtmlEntities() {
+ this.Parser.prototype.inlineTokenizers.text = text;
+
+ /**
+ * This is a port of the `remark-parse` text tokenizer, adapted to exclude
+ * HTML entity decoding.
+ */
+ function text(eat, value, silent) {
+ var self = this;
+ var methods;
+ var tokenizers;
+ var index;
+ var length;
+ var subvalue;
+ var position;
+ var tokenizer;
+ var name;
+ var min;
+ var now;
+
+ /* istanbul ignore if - never used (yet) */
+ if (silent) {
+ return true;
+ }
+
+ methods = self.inlineMethods;
+ length = methods.length;
+ tokenizers = self.inlineTokenizers;
+ index = -1;
+ min = value.length;
+
+ while (++index < length) {
+ name = methods[index];
+
+ if (name === 'text' || !tokenizers[name]) {
+ continue;
+ }
+
+ tokenizer = tokenizers[name].locator;
+
+ if (!tokenizer) {
+ eat.file.fail('Missing locator: `' + name + '`');
+ }
+
+ position = tokenizer.call(self, value, 1);
+
+ if (position !== -1 && position < min) {
+ min = position;
+ }
+ }
+
+ subvalue = value.slice(0, min);
+
+ eat(subvalue)({
+ type: 'text',
+ value: subvalue,
+ });
+ }
+};