diff --git a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-html-tests-without-surprises-1-snap.png b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-html-tests-without-surprises-1-snap.png
new file mode 100644
index 000000000..458ebc6d9
Binary files /dev/null and b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-html-tests-without-surprises-1-snap.png differ
diff --git a/__tests__/browser/markdown.test.js b/__tests__/browser/markdown.test.js
index 31b75892c..5c3536d16 100644
--- a/__tests__/browser/markdown.test.js
+++ b/__tests__/browser/markdown.test.js
@@ -18,6 +18,7 @@ describe('visual regression tests', () => {
//'features',
// 'headings',
'images',
+ 'htmlTests',
// 'lists',
'mdxComponents',
'tables',
diff --git a/__tests__/components/HTMLBlock.test.jsx b/__tests__/components/HTMLBlock.test.jsx
deleted file mode 100644
index 308cae104..000000000
--- a/__tests__/components/HTMLBlock.test.jsx
+++ /dev/null
@@ -1,75 +0,0 @@
-import { render, screen } from '@testing-library/react';
-import React from 'react';
-import { renderToString } from 'react-dom/server';
-import { vi } from 'vitest';
-
-import createHTMLBlock from '../../components/HTMLBlock';
-import { compile, run } from '../../index';
-import createSchema from '../../sanitize.schema';
-
-const HTMLBlock = createHTMLBlock(createSchema(), {});
-
-describe.skip('HTML Block', () => {
- beforeEach(() => {
- global.window = true;
- global.mockFn = vi.fn();
- });
-
- afterEach(() => {
- vi.restoreAllMocks();
- });
-
- it('runs user scripts in compat mode', () => {
- render();
- expect(global.mockFn).toHaveBeenCalledTimes(1);
- });
-
- it("doesn't run user scripts by default", () => {
- render();
- expect(global.mockFn).toHaveBeenCalledTimes(0);
- });
-
- it("doesn't render user scripts by default", () => {
- render();
-
- expect(screen.queryByText('mockFn()')).not.toBeInTheDocument();
- });
-
- it("doesn't render user scripts with weird endings", () => {
- render();
-
- expect(screen.queryByText('mockFn()')).not.toBeInTheDocument();
- });
-
- it("doesn't render user scripts with a malicious string", () => {
- render();
-
- expect(screen.queryByText('mockFn()')).not.toBeInTheDocument();
- });
-
- it("doesn't run scripts on the server (even in compat mode)", () => {
- const html = `
-
Hello World
-
- `;
- const elem = ;
- const view = renderToString(elem);
- expect(elem.props.runScripts).toBe(true);
- expect(view.indexOf('`});
+ expect(global.mockFn).toHaveBeenCalledTimes(1);
+ });
+
+ it("doesn't run user scripts by default", () => {
+ render({``});
+ expect(global.mockFn).toHaveBeenCalledTimes(0);
+ });
+
+ it("doesn't render user scripts by default", () => {
+ render({``});
+ expect(screen.queryByText('mockFn()')).not.toBeInTheDocument();
+ });
+
+ it("doesn't render user scripts with weird endings", () => {
+ render({``});
+ expect(screen.queryByText('mockFn()')).not.toBeInTheDocument();
+ });
+
+ it("doesn't render user scripts with a malicious string", () => {
+ render({`t>mockFn()cript>`});
+ expect(screen.queryByText('mockFn()')).not.toBeInTheDocument();
+ });
+
+ it("doesn't run scripts on the server (even in compat mode)", () => {
+ const html = `
+ Hello World
+
+ `;
+ const elem = {html};
+ const view = renderToString(elem);
+ expect(elem.props.runScripts).toBe(true);
+ expect(view.indexOf('\n\nHello!\n\n',
-})}
-[/block]
-
-[block:parameters]
-${JSON.stringify({
- data: {
- '0-0': "```js Tab Zed\nconsole.log('tab zed');\n```\n```js Tab One\nconsole.log('tab one')\n```",
- '0-1':
- '> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maxime repellat placeat expedita voluptatum fugiat rerum, accusamus eius dolorum sequi eveniet esse, adipisci soluta quia mollitia? Dolorem minus, dolores, rerum, pariatur sit quia eum esse voluptatibus ea veritatis non.',
- '0-2': '',
- 'h-0': 'Hello',
- 'h-1': 'Bonjour',
- 'h-2': 'Willkommen',
- },
- cols: 2,
- rows: 1,
-})}
-[/block]`;
-
- let rdmd;
- let container;
- beforeEach(() => {
- rdmd = markdown.react(tabs, { compatibilityMode: true });
- // eslint-disable-next-line testing-library/no-render-in-setup
- ({ container } = render(rdmd));
- });
-
- it('Should use h1 tags for magic heading blocks.', () => expect(container.querySelectorAll('h1')).toHaveLength(1));
-
- it('Should allow block-level RDMD compoonents in tables.', () => {
- const table = container.querySelector('table');
- expect(table.querySelectorAll('.CodeTabs')).toHaveLength(1);
- expect(table.querySelectorAll('blockquote')).toHaveLength(1);
- });
-});
diff --git a/components/HTMLBlock/index.jsx b/components/HTMLBlock/index.jsx
deleted file mode 100644
index 102a721f2..000000000
--- a/components/HTMLBlock/index.jsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/* eslint-disable no-eval
- */
-const escape = require('lodash.escape');
-const PropTypes = require('prop-types');
-const React = require('react');
-
-const MATCH_SCRIPT_TAGS = /
+ Header 0
+ Paragraph with italics and bold stuff.
+ I am actually a div!
+
+
+
+## JSX
+
+
+
+ Header 1
+ Paragraph with italics and bold stuff.
+
+ Behold, I am blue and indented!
+
+
+
+
+## HTML as a prop
+
+
+
+
+## HTML in template literal
+
+
+ {`
+
+ Header 3
+ Paragraph with italics and bold stuff.
+
+ Behold, I am blue and indented!
+
+ `}
+
+
+
+## JSX in safe mode
+
+
+
+ Header 4
+ Paragraph with italics and bold stuff.
+
+ Behold, I am blue and indented!
+
+
+
+
+## HTML in safe mode
+
+
+{`
+
+ Header 5
+ Paragraph with italics and bold stuff.
+
+ Behold, I am blue and indented!
+
+`}
+
\ No newline at end of file
diff --git a/enums.ts b/enums.ts
index aa398912f..a8e849ef0 100644
--- a/enums.ts
+++ b/enums.ts
@@ -3,4 +3,5 @@ export enum NodeTypes {
emoji = 'emoji',
i = 'i',
image = 'image',
+ htmlBlock = 'html-block',
}
diff --git a/example/docs.ts b/example/docs.ts
index 1d7956eae..20ba4a3d6 100644
--- a/example/docs.ts
+++ b/example/docs.ts
@@ -15,6 +15,8 @@ import gettingStarted from '../docs/getting-started.md';
// @ts-ignore
import headings from '../docs/headings.md';
// @ts-ignore
+import htmlTests from '../docs/html-tests.md';
+// @ts-ignore
import images from '../docs/images.md';
// @ts-ignore
import lists from '../docs/lists.md';
@@ -41,6 +43,7 @@ const fixtures = Object.entries({
features,
gettingStarted,
headings,
+ htmlTests,
images,
lists,
mdxComponents,
diff --git a/index.tsx b/index.tsx
index bb8d8db63..d54c7354d 100644
--- a/index.tsx
+++ b/index.tsx
@@ -47,6 +47,7 @@ const makeUseMDXComponents = (more: RunOpts['components']) => {
...Components,
Variable,
'code-tabs': Components.CodeTabs,
+ 'html-block': Components.HTMLBlock,
img: Components.Image,
table: Components.Table,
};
diff --git a/package-lock.json b/package-lock.json
index 02b78b8cc..849b49002 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -64,7 +64,7 @@
"@types/mdast": "^4.0.3",
"@types/mdx": "^2.0.12",
"@vitejs/plugin-react": "^4.2.1",
- "@vitest/ui": "^1.5.0",
+ "@vitest/ui": "^1.6.0",
"babel-jest": "^29.5.0",
"babel-loader": "^9.1.2",
"browserify-fs": "^1.0.0",
@@ -7532,13 +7532,13 @@
}
},
"node_modules/@vitest/expect": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.0.tgz",
- "integrity": "sha512-0pzuCI6KYi2SIC3LQezmxujU9RK/vwC1U9R0rLuGlNGcOuDWxqWKu6nUdFsX9tH1WU0SXtAxToOsEjeUn1s3hA==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz",
+ "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==",
"dev": true,
"dependencies": {
- "@vitest/spy": "1.5.0",
- "@vitest/utils": "1.5.0",
+ "@vitest/spy": "1.6.0",
+ "@vitest/utils": "1.6.0",
"chai": "^4.3.10"
},
"funding": {
@@ -7546,12 +7546,12 @@
}
},
"node_modules/@vitest/runner": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.0.tgz",
- "integrity": "sha512-7HWwdxXP5yDoe7DTpbif9l6ZmDwCzcSIK38kTSIt6CFEpMjX4EpCgT6wUmS0xTXqMI6E/ONmfgRKmaujpabjZQ==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz",
+ "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==",
"dev": true,
"dependencies": {
- "@vitest/utils": "1.5.0",
+ "@vitest/utils": "1.6.0",
"p-limit": "^5.0.0",
"pathe": "^1.1.1"
},
@@ -7587,9 +7587,9 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.0.tgz",
- "integrity": "sha512-qpv3fSEuNrhAO3FpH6YYRdaECnnRjg9VxbhdtPwPRnzSfHVXnNzzrpX4cJxqiwgRMo7uRMWDFBlsBq4Cr+rO3A==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz",
+ "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==",
"dev": true,
"dependencies": {
"magic-string": "^0.30.5",
@@ -7627,15 +7627,15 @@
}
},
"node_modules/@vitest/snapshot/node_modules/react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
"dev": true
},
"node_modules/@vitest/spy": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.0.tgz",
- "integrity": "sha512-vu6vi6ew5N5MMHJjD5PoakMRKYdmIrNJmyfkhRpQt5d9Ewhw9nZ5Aqynbi3N61bvk9UvZ5UysMT6ayIrZ8GA9w==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz",
+ "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==",
"dev": true,
"dependencies": {
"tinyspy": "^2.2.0"
@@ -7645,12 +7645,12 @@
}
},
"node_modules/@vitest/ui": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-1.5.0.tgz",
- "integrity": "sha512-ETcToK2TzICf/Oartvt19IH7yR4oCs8GrQk5hRhZ5oZFaSdDHTh6o3EdzyxOaY24NZ20cXYYNGjj1se/5vHfFg==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-1.6.0.tgz",
+ "integrity": "sha512-k3Lyo+ONLOgylctiGovRKy7V4+dIN2yxstX3eY5cWFXH6WP+ooVX79YSyi0GagdTQzLmT43BF27T0s6dOIPBXA==",
"dev": true,
"dependencies": {
- "@vitest/utils": "1.5.0",
+ "@vitest/utils": "1.6.0",
"fast-glob": "^3.3.2",
"fflate": "^0.8.1",
"flatted": "^3.2.9",
@@ -7662,13 +7662,13 @@
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
- "vitest": "1.5.0"
+ "vitest": "1.6.0"
}
},
"node_modules/@vitest/utils": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.0.tgz",
- "integrity": "sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz",
+ "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==",
"dev": true,
"dependencies": {
"diff-sequences": "^29.6.3",
@@ -7707,9 +7707,9 @@
}
},
"node_modules/@vitest/utils/node_modules/react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
"dev": true
},
"node_modules/@webassemblyjs/ast": {
@@ -18735,15 +18735,12 @@
}
},
"node_modules/magic-string": {
- "version": "0.30.9",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz",
- "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==",
+ "version": "0.30.10",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz",
+ "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==",
"dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
- },
- "engines": {
- "node": ">=12"
}
},
"node_modules/make-dir": {
@@ -29580,9 +29577,9 @@
}
},
"node_modules/vite-node": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.0.tgz",
- "integrity": "sha512-tV8h6gMj6vPzVCa7l+VGq9lwoJjW8Y79vst8QZZGiuRAfijU+EEWuc0kFpmndQrWhMMhet1jdSF+40KSZUqIIw==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz",
+ "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==",
"dev": true,
"dependencies": {
"cac": "^6.7.14",
@@ -29602,16 +29599,16 @@
}
},
"node_modules/vitest": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.0.tgz",
- "integrity": "sha512-d8UKgR0m2kjdxDWX6911uwxout6GHS0XaGH1cksSIVVG8kRlE7G7aBw7myKQCvDI5dT4j7ZMa+l706BIORMDLw==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz",
+ "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==",
"dev": true,
"dependencies": {
- "@vitest/expect": "1.5.0",
- "@vitest/runner": "1.5.0",
- "@vitest/snapshot": "1.5.0",
- "@vitest/spy": "1.5.0",
- "@vitest/utils": "1.5.0",
+ "@vitest/expect": "1.6.0",
+ "@vitest/runner": "1.6.0",
+ "@vitest/snapshot": "1.6.0",
+ "@vitest/spy": "1.6.0",
+ "@vitest/utils": "1.6.0",
"acorn-walk": "^8.3.2",
"chai": "^4.3.10",
"debug": "^4.3.4",
@@ -29625,7 +29622,7 @@
"tinybench": "^2.5.1",
"tinypool": "^0.8.3",
"vite": "^5.0.0",
- "vite-node": "1.5.0",
+ "vite-node": "1.6.0",
"why-is-node-running": "^2.2.2"
},
"bin": {
@@ -29640,8 +29637,8 @@
"peerDependencies": {
"@edge-runtime/vm": "*",
"@types/node": "^18.0.0 || >=20.0.0",
- "@vitest/browser": "1.5.0",
- "@vitest/ui": "1.5.0",
+ "@vitest/browser": "1.6.0",
+ "@vitest/ui": "1.6.0",
"happy-dom": "*",
"jsdom": "*"
},
diff --git a/package.json b/package.json
index b11a94051..98e58bfb4 100644
--- a/package.json
+++ b/package.json
@@ -86,7 +86,7 @@
"@types/mdast": "^4.0.3",
"@types/mdx": "^2.0.12",
"@vitejs/plugin-react": "^4.2.1",
- "@vitest/ui": "^1.5.0",
+ "@vitest/ui": "^1.6.0",
"babel-jest": "^29.5.0",
"babel-loader": "^9.1.2",
"browserify-fs": "^1.0.0",
diff --git a/processor/compile/html-block.js b/processor/compile/html-block.js
deleted file mode 100644
index 64e393e3c..000000000
--- a/processor/compile/html-block.js
+++ /dev/null
@@ -1,9 +0,0 @@
-module.exports = function () {
- const { Compiler } = this;
- const { visitors } = Compiler.prototype;
-
- visitors['html-block'] = node => {
- const html = node.data.hProperties.html;
- return `[block:html]\n${JSON.stringify({ html }, null, 2)}\n[/block]`;
- };
-};
diff --git a/processor/compile/html-block.ts b/processor/compile/html-block.ts
new file mode 100644
index 000000000..e9f4db9a3
--- /dev/null
+++ b/processor/compile/html-block.ts
@@ -0,0 +1,8 @@
+import { HTMLBlock } from '../../types';
+
+const htmlBlock = (node: HTMLBlock) => {
+ const html = node.data.hProperties.html;
+ return `${JSON.stringify({ html }, null, 2)}`;
+}
+
+export default htmlBlock;
diff --git a/processor/compile/index.ts b/processor/compile/index.ts
index 983543e46..81cbf5377 100644
--- a/processor/compile/index.ts
+++ b/processor/compile/index.ts
@@ -1,6 +1,7 @@
import gemoji from './gemoji';
import codeTabs from './code-tabs';
import image from './image';
+import htmlBlock from './html-block';
import { NodeTypes } from '../../enums';
function compilers() {
@@ -12,9 +13,10 @@ function compilers() {
[NodeTypes.emoji]: gemoji,
[NodeTypes.codeTabs]: codeTabs,
[NodeTypes.image]: image,
+ [NodeTypes.htmlBlock]: htmlBlock,
};
toMarkdownExtensions.push({ extensions: [{ handlers }] });
-}
+};
export default compilers;
diff --git a/types.d.ts b/types.d.ts
index 2fa54c023..f890fc74d 100644
--- a/types.d.ts
+++ b/types.d.ts
@@ -9,6 +9,16 @@ interface CodeTabs extends Parent {
};
}
+interface HTMLBlock extends Parent {
+ type: NodeTypes.htmlBlock;
+ data: Data & {
+ hName: 'html-block';
+ hProperties: {
+ html: string;
+ };
+ };
+}
+
interface Gemoji extends Literal {
type: NodeTypes.emoji;
name: string;