[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 2\nindent_style = space\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n"
  },
  {
    "path": ".github/workflows/bb.yml",
    "content": "jobs:\n  main:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: unifiedjs/beep-boop-beta@main\n        with:\n          repo-token: ${{secrets.GITHUB_TOKEN}}\nname: bb\non:\n  issues:\n    types: [closed, edited, labeled, opened, reopened, unlabeled]\n  pull_request_target:\n    types: [closed, edited, labeled, opened, reopened, unlabeled]\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "jobs:\n  main:\n    name: ${{matrix.node}}\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-node@v4\n        with:\n          node-version: ${{matrix.node}}\n      - run: npm install\n      - run: npm test\n      - uses: codecov/codecov-action@v5\n    strategy:\n      matrix:\n        node:\n          - lts/hydrogen\n          - node\nname: main\non:\n  - pull_request\n  - push\n"
  },
  {
    "path": ".gitignore",
    "content": "*.d.ts\n*.log\n*.map\n*.tsbuildinfo\n.DS_Store\ncoverage/\nnode_modules/\nreact-markdown.min.js\nyarn.lock\n"
  },
  {
    "path": ".npmrc",
    "content": "ignore-scripts=true\npackage-lock=false\n"
  },
  {
    "path": ".prettierignore",
    "content": "coverage/\n*.md\n"
  },
  {
    "path": "changelog.md",
    "content": "<!--lint disable media-style-->\n\n# Changelog\n\nAll notable changes will be documented in this file.\n\n## 10.0.0 - 2025-02-20\n\n* [`aaaa40b`](https://github.com/remarkjs/react-markdown/commit/aaaa40b)\n  Remove support for `className` prop\n  **migrate**: see “Remove `className`” below\n\n### Remove `className`\n\nThe `className` prop was removed.\nIf you want to add classes to some element that wraps the markdown\nyou can explicitly write that element and add the class to it.\nYou can then choose yourself which tag name to use and whether to add other\nprops.\n\nBefore:\n\n```js\n<Markdown className=\"markdown-body\">{markdown}</Markdown>\n```\n\nAfter:\n\n```js\n<div className=\"markdown-body\">\n  <Markdown>{markdown}</Markdown>\n</div>\n```\n\n## 9.1.0 - 2025-02-20\n\n* [`6ce120e`](https://github.com/remarkjs/react-markdown/commit/6ce120e)\n  Add support for async plugins\n\n## 9.0.3 - 2025-01-06\n\n(same as 9.0.2 but now with d.ts files)\n\n## 9.0.2 - 2025-01-06\n\n* [`b151a90`](https://github.com/remarkjs/react-markdown/commit/b151a90)\n  Fix types for React 19\n* [`6962af7`](https://github.com/remarkjs/react-markdown/commit/6962af7)\n  Add declaration maps\n* [`aa5933b`](https://github.com/remarkjs/react-markdown/commit/aa5933b)\n  Refactor to use `@import` to import types\n\n## 9.0.1 - 2023-11-13\n\n* [`d8e3787`](https://github.com/remarkjs/react-markdown/commit/d8e3787)\n  Fix double encoding in new url transform\n\n## 9.0.0 - 2023-09-27\n\n* [`b67d714`](https://github.com/remarkjs/react-markdown/commit/b67d714)\n  Change to require Node.js 16\\\n  **migrate**: update too\n* [`ec2b134`](https://github.com/remarkjs/react-markdown/commit/ec2b134)\n  Change to require React 18\\\n  **migrate**: update too\n* [`bf5824f`](https://github.com/remarkjs/react-markdown/commit/bf5824f)\n  Change to use `exports`\\\n  **migrate**: don’t use private APIs\n* [`c383a45`](https://github.com/remarkjs/react-markdown/commit/c383a45)\n  Update `@types/hast`, utilities, plugins, etc\\\n  **migrate**: update too\n* [`eca5e6b`](https://github.com/remarkjs/react-markdown/commit/eca5e6b)\n  [`08ead9e`](https://github.com/remarkjs/react-markdown/commit/08ead9e)\n  Replace `transformImageUri`, `transformLinkUri` w/ `urlTransform`\\\n  **migrate**: see “Add `urlTransform`” below\n* [`de29396`](https://github.com/remarkjs/react-markdown/commit/de29396)\n  Remove `linkTarget` option\\\n  **migrate**: see “Remove `linkTarget`” below\n* [`4346276`](https://github.com/remarkjs/react-markdown/commit/4346276)\n  Remove support for passing custom props to components\\\n  **migrate**: see “Remove `includeElementIndex`”, “Remove `rawSourcePos`”,\n  “Remove `sourcePos`”, “Remove extra props passed to certain components”\n  below\n* [`c0dfbd6`](https://github.com/remarkjs/react-markdown/commit/c0dfbd6)\n  Remove UMD bundle from package\\\n  **migrate**: use `esm.sh` or a CDN or so\n* [`e12b5e9`](https://github.com/remarkjs/react-markdown/commit/e12b5e9)\n  Remove `prop-types`\\\n  **migrate**: use TypeScript\n* [`4eb7aa0`](https://github.com/remarkjs/react-markdown/commit/4eb7aa0)\n  Change to throw errors for removed props\\\n  **migrate**: don’t pass options that don’t do things\n* [`8aabf74`](https://github.com/remarkjs/react-markdown/commit/8aabf74)\n  Change to improve error messages\\\n  **migrate**: expect better messages\n\n### Add `urlTransform`\n\nThe `transformImageUri` and `transformLinkUri` were removed.\nHaving two functions is a bit much, particularly because there are more URLs\nyou might want to change (or which might be unsafe so *we* make them safe).\nAnd their name and APIs were a bit weird.\nYou can use the new `urlTransform` prop instead to change all your URLs.\n\n### Remove `linkTarget`\n\nThe `linkTarget` option was removed; you should likely not set targets.\nIf you want to, use\n[`rehype-external-links`](https://github.com/rehypejs/rehype-external-links).\n\n### Remove `includeElementIndex`\n\nThe `includeElementIndex` option was removed, so `index` is never passed to\ncomponents.\nWrite a plugin to pass `index`:\n\n<details>\n<summary>Show example of plugin</summary>\n\n```js\nimport {visit} from 'unist-util-visit'\n\nfunction rehypePluginAddingIndex() {\n  /**\n   * @param {import('hast').Root} tree\n   * @returns {undefined}\n   */\n  return function (tree) {\n    visit(tree, function (node, index) {\n      if (node.type === 'element' && typeof index === 'number') {\n        node.properties.index = index\n      }\n    })\n  }\n}\n```\n\n</details>\n\n### Remove `rawSourcePos`\n\nThe `rawSourcePos` option was removed, so `sourcePos` is never passed to\ncomponents.\nAll components are passed `node`, so you can get `node.position` from them.\n\n### Remove `sourcePos`\n\nThe `sourcePos` option was removed, so `data-sourcepos` is never passed to\nelements.\nWrite a plugin to pass `index`:\n\n<details>\n<summary>Show example of plugin</summary>\n\n```js\nimport {stringifyPosition} from 'unist-util-stringify-position'\nimport {visit} from 'unist-util-visit'\n\nfunction rehypePluginAddingIndex() {\n  /**\n   * @param {import('hast').Root} tree\n   * @returns {undefined}\n   */\n  return function (tree) {\n    visit(tree, function (node) {\n      if (node.type === 'element') {\n        node.properties.dataSourcepos = stringifyPosition(node.position)\n      }\n    })\n  }\n}\n```\n\n</details>\n\n### Remove extra props passed to certain components\n\nWhen overwriting components, these props are no longer passed:\n\n* `inline` on `code`\n  — create a plugin or use `pre` for the block\n* `level` on `h1`, `h2`, `h3`, `h4`, `h5`, `h6`\n  — check `node.tagName` instead\n* `checked` on `li`\n  — check `task-list-item` class or check `props.children`\n* `index` on `li`\n  — create a plugin\n* `ordered` on `li`\n  — create a plugin or check the parent\n* `depth` on `ol`, `ul`\n  — create a plugin\n* `ordered` on `ol`, `ul`\n  — check `node.tagName` instead\n* `isHeader` on `td`, `th`\n  — check `node.tagName` instead\n* `isHeader` on `tr`\n  — create a plugin or check children\n\n## 8.0.7 - 2023-04-12\n\n* [`c289176`](https://github.com/remarkjs/react-markdown/commit/c289176)\n  Fix performance for keys\n  by [**@wooorm**](https://github.com/wooorm)\n  in [#738](https://github.com/remarkjs/react-markdown/pull/738)\n* [`9034dbd`](https://github.com/remarkjs/react-markdown/commit/9034dbd)\n  Fix types in syntax highlight example\n  by [**@dlqqq**](https://github.com/dlqqq)\n  in [#736](https://github.com/remarkjs/react-markdown/pull/736)\n\n**Full Changelog**: <https://github.com/remarkjs/react-markdown/compare/8.0.6...8.0.7>\n\n## 8.0.6 - 2023-03-20\n\n* [`33ab015`](https://github.com/remarkjs/react-markdown/commit/33ab015)\n  Update to TS 5\\\n  by [**@Methuselah96**](https://github.com/Methuselah96)\n  in [#734](https://github.com/remarkjs/react-markdown/issues/734)\n\n## 8.0.5 - 2023-01-17\n\n* [`d640d40`](https://github.com/remarkjs/react-markdown/commit/d640d40)\n  Update to use `node16` module resolution in `tsconfig.json`\\\n  by [**@ChristianMurphy**](https://github.com/ChristianMurphy)\n  in [#723](https://github.com/remarkjs/react-markdown/pull/723)\n* [`402fea3`](https://github.com/remarkjs/react-markdown/commit/402fea3)\n  Fix typo in `plugins` deprecation message\\\n  by [**@marc2332**](https://github.com/marc2332)\n  in [#719](https://github.com/remarkjs/react-markdown/pull/719)\n* [`4f98f73`](https://github.com/remarkjs/react-markdown/commit/4f98f73)\n  Remove deprecated and unneeded `defaultProps`\\\n  by [**@Lepozepo**](https://github.com/Lepozepo)\n  in [#718](https://github.com/remarkjs/react-markdown/pull/718)\n\n## 8.0.4 - 2022-12-01\n\n* [`9b20440`](https://github.com/remarkjs/react-markdown/commit/9b20440)\n  Fix type of `td`, `th` props\\\n  by [**@lucasassisrosa**](https://github.com/lucasassisrosa)\n  in [#714](https://github.com/remarkjs/react-markdown/pull/714)\n* [`cfe075b`](https://github.com/remarkjs/react-markdown/commit/cfe075b)\n  Add clarification of `alt` on `img` in docs\\\n  by [**@cballenar**](https://github.com/cballenar)\n  in [#692](https://github.com/remarkjs/react-markdown/pull/692)\n\n## 8.0.3 - 2022-04-20\n\n* [`a2fb833`](https://github.com/remarkjs/react-markdown/commit/a2fb833)\n  Fix prop types of plugins\\\n  by [**@starpit**](https://github.com/starpit)\n  in [#683](https://github.com/remarkjs/react-markdown/pull/683)\n\n## 8.0.2 - 2022-03-31\n\n* [`2712227`](https://github.com/remarkjs/react-markdown/commit/2712227)\n  Update `react-is`\n* [`704c3c6`](https://github.com/remarkjs/react-markdown/commit/704c3c6)\n  Fix TypeScript bug by adding workaround\\\n  by [**@Methuselah96**](https://github.com/Methuselah96)\n  in [#676](https://github.com/remarkjs/react-markdown/pull/676)\n\n## 8.0.1 - 2022-03-14\n\n* [`c23ecf6`](https://github.com/remarkjs/react-markdown/commit/c23ecf6)\n  Add missing dependency for types\\\n  by [**@Methuselah96**](https://github.com/Methuselah96)\n  in [#675](https://github.com/remarkjs/react-markdown/pull/675)\n\n## 8.0.0 - 2022-01-17\n\n<a name=\"change-plugins-to-remarkplugins\"></a>\n\n* [`cd845c9`](https://github.com/remarkjs/react-markdown/commit/cd845c9)\n  Remove deprecated `plugins` option\\\n  (**migrate by renaming it to `remarkPlugins`**)\n* [`36e4916`](https://github.com/remarkjs/react-markdown/commit/36e4916)\n  Update [`remark-rehype`](https://github.com/remarkjs/remark-rehype),\n  add support for passing it options\\\n  by [**@peolic**](https://github.com/peolic)\n  in [#669](https://github.com/remarkjs/react-markdown/pull/669)\\\n  (**migrate by removing `remark-footnotes` and updating `remark-gfm` if you\n  were using them, otherwise you shouldn’t notice this**)\n\n## 7.1.2 - 2022-01-02\n\n* [`656a4fa`](https://github.com/remarkjs/react-markdown/commit/656a4fa)\n  Fix `ref` in types\\\n  by [**@ChristianMurphy**](https://github.com/ChristianMurphy)\n  in [#668](https://github.com/remarkjs/react-markdown/pull/668)\n\n## 7.1.1 - 2021-11-29\n\n* [`4185f06`](https://github.com/remarkjs/react-markdown/commit/4185f06)\n  Add improved docs\\\n  by [**@wooorm**](https://github.com/wooorm)\n  in [#657](https://github.com/remarkjs/react-markdown/pull/657)\n\n## 7.1.0 - 2021-10-21\n\n* [`7b8a829`](https://github.com/remarkjs/react-markdown/commit/7b8a829)\n  Add support for `SpecialComponents` to be any `ComponentType`\\\n  by [**@Methuselah96**](https://github.com/Methuselah96)\n  in [#640](https://github.com/remarkjs/react-markdown/pull/640)\n* [`a7c26fc`](https://github.com/remarkjs/react-markdown/commit/a7c26fc)\n  Remove warning on whitespace in tables\n\n## 7.0.1 - 2021-08-26\n\n* [`ec387c2`](https://github.com/remarkjs/react-markdown/commit/ec387c2)\n  Add improved type for `linkTarget` as string\n* [`5af6bc7`](https://github.com/remarkjs/react-markdown/commit/5af6bc7)\n  Fix to correctly compile intrinsic types\n\n## 7.0.0 - 2021-08-13\n\nWelcome to version 7.\nThis a major release and therefore contains breaking changes.\n\n### Breaking changes\n\n* [`01b11fe`](https://github.com/remarkjs/react-markdown/commit/01b11fe)\n  [`c613efd`](https://github.com/remarkjs/react-markdown/commit/c613efd)\n  [`a1e1c3f`](https://github.com/remarkjs/react-markdown/commit/a1e1c3f)\n  [`aeee9ac`](https://github.com/remarkjs/react-markdown/commit/aeee9ac)\n  Use ESM\n  (please [read this](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c))\n* [`3dffd6a`](https://github.com/remarkjs/react-markdown/commit/3dffd6a)\n  Update dependencies\n  (upgrade all your plugins and this should go fine)\n\n### Internals\n\n* [`8b5481c`](https://github.com/remarkjs/react-markdown/commit/8b5481c)\n  [`fb1b512`](https://github.com/remarkjs/react-markdown/commit/fb1b512)\n  [`144af79`](https://github.com/remarkjs/react-markdown/commit/144af79)\n  Replace `jest` with `uvu`\n* [`8c572df`](https://github.com/remarkjs/react-markdown/commit/8c572df)\n  Replace `rollup` with `esbuild`\n* [`8737eac`](https://github.com/remarkjs/react-markdown/commit/8737eac)\n  [`28d4c75`](https://github.com/remarkjs/react-markdown/commit/28d4c75)\n  [`b2dd046`](https://github.com/remarkjs/react-markdown/commit/b2dd046)\n  Refactor code-style\n\n## 6.0.3 - 2021-07-30\n\n* [`13367ed`](https://github.com/remarkjs/react-markdown/commit/13367ed)\n  Fix types to include each element w/ its properties\n* [`0a1931a`](https://github.com/remarkjs/react-markdown/commit/0a1931a)\n  Fix to add min version of `property-information`\n\n## 6.0.2 - 2021-05-06\n\n* [`cefc02d`](https://github.com/remarkjs/react-markdown/commit/cefc02d)\n  Add string type for `className`s\n* [`6355e45`](https://github.com/remarkjs/react-markdown/commit/6355e45)\n  Fix to pass `vfile` to plugins\n* [`5cf6e1b`](https://github.com/remarkjs/react-markdown/commit/5cf6e1b)\n  Fix to add warning when non-strings are given as `children`\n\n## 6.0.1 - 2021-04-23\n\n* [`2e956be`](https://github.com/remarkjs/react-markdown/commit/2e956be)\n  Fix whitespace in table elements\n* [`d36048a`](https://github.com/remarkjs/react-markdown/commit/d36048a)\n  Add architecture section to readme\n\n## 6.0.0 - 2021-04-15\n\nWelcome to version 6.\nThis a major release and therefore contains breaking changes.\n\n### Change `renderers` to `components`\n\n`react-markdown` used to let you define components for *markdown* constructs\n(`link`, `delete`, `break`, etc).\nThis proved complex as users didn’t know about those names or markdown\npeculiarities (such as that there are fully formed links *and* link references).\n\nSee [**GH-549**](https://github.com/remarkjs/react-markdown/issues/549) for more\non why this changed.\nSee [**Appendix B: Components** in\n`readme.md`](https://github.com/remarkjs/react-markdown#appendix-b-components)\nfor more on components.\n\n<details>\n<summary>Show example of needed change</summary>\n\nBefore (**broken**):\n\n```js\n<Markdown\n  renderers={{\n    // Use a fancy hr\n    thematicBreak: ({node, ...props}) => <MyFancyRule {...props} />\n  }}\n>{`***`}</Markdown>\n```\n\nNow (**fixed**):\n\n```js\n<Markdown\n  components={{\n    // Use a fancy hr\n    hr: ({node, ...props}) => <MyFancyRule {...props} />\n  }}\n>{`***`}</Markdown>\n```\n\n</details>\n\n<details>\n<summary>Show conversion table</summary>\n\n| Type (`renderers`)                  | Tag names (`components`)                |\n| ----------------------------------- | --------------------------------------- |\n| `blockquote`                        | `blockquote`                            |\n| `break`                             | `br`                                    |\n| `code`, `inlineCode`                | `code`, `pre`**​\\*​**                   |\n| `definition`                        | **†**                                   |\n| `delete`                            | `del`**‡**                              |\n| `emphasis`                          | `em`                                    |\n| `heading`                           | `h1`, `h2`, `h3`, `h4`, `h5`, `h6`**§** |\n| `html`, `parsedHtml`, `virtualHtml` | **‖**                                   |\n| `image`, `imageReference`           | `img`**†**                              |\n| `link`, `linkReference`             | `a`**†**                                |\n| `list`                              | `ol`, `ul`**¶**                         |\n| `listItem`                          | `li`                                    |\n| `paragraph`                         | `p`                                     |\n| `root`                              | **​\\*\\*​**                              |\n| `strong`                            | `strong`                                |\n| `table`                             | `table`**‡**                            |\n| `tableHead`                         | `thead`**‡**                            |\n| `tableBody`                         | `tbody`**‡**                            |\n| `tableRow`                          | `tr`**‡**                               |\n| `tableCell`                         | `td`, `th`**‡**                         |\n| `text`                              |                                         |\n| `thematicBreak`                     | `hr`                                    |\n\n* **​\\*​** It’s possible to differentiate between code based on the `inline`\n  prop.\n  Block code is also wrapped in a `pre`\n* **†** Resource (`[text](url)`) and reference (`[text][id]`) style links and\n  images (and their definitions) are now resolved and treated the same\n* **‡** Available when using\n  [`remark-gfm`](https://github.com/remarkjs/remark-gfm)\n* **§** It’s possible to differentiate between heading based on the `level`\n  prop\n* **‖** When using `rehype-raw` (see below), components for those elements\n  can also be used (for example, `abbr` for\n  `<abbr title=\"HyperText Markup Language\">HTML</abbr>`)\n* **¶** It’s possible to differentiate between lists based on the `ordered`\n  prop\n* **​\\*\\*​** Wrap `ReactMarkdown` in a component instead\n\n</details>\n\n### Add `rehypePlugins`\n\nWe’ve added another plugin system:\n[**rehype**](https://github.com/rehypejs/rehype).\nIt’s similar to remark (what we’re using for markdown) but for HTML.\n\nThere are many rehype plugins.\nSome examples are\n[`@mapbox/rehype-prism`](https://github.com/mapbox/rehype-prism)\n(syntax highlighting with Prism),\n[`rehype-katex`](https://github.com/remarkjs/remark-math/tree/HEAD/packages/rehype-katex)\n(rendering math with KaTeX), or\n[`rehype-autolink-headings`](https://github.com/rehypejs/rehype-autolink-headings)\n(adding links to headings).\n\nSee [List of plugins](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md)\nfor more plugins.\n\n<details>\n<summary>Show example of feature</summary>\n\n```js\nimport rehypeHighlight from 'rehype-highlight'\n\n<Markdown rehypePlugins={[rehypeHighlight]}>{`~~~js\nconsole.log(1)\n~~~`}</Markdown>\n```\n\n</details>\n\n### Remove buggy HTML in markdown parser\n\nIn a lot of cases, you should not use HTML in markdown: it’s most always unsafe.\nAnd it defeats much of the purpose of this project (not relying on\n`dangerouslySetInnerHTML`).\n\n`react-markdown` used to have an opt-in HTML parser with a bunch of bugs.\nAs we now support rehype plugins, we can defer that work to a rehype plugin.\nTo support HTML in markdown with `react-markdown`, use\n[`rehype-raw`](https://github.com/rehypejs/rehype-raw).\nThe `astPlugins` and `allowDangerousHtml` (previously called `escapeHtml`) props\nare no longer needed and were removed.\n\nWhen using `rehype-raw`, you should probably use\n[`rehype-sanitize`](https://github.com/rehypejs/rehype-sanitize)\ntoo.\n\n<details>\n<summary>Show example of needed change</summary>\n\nBefore (**broken**):\n\n```js\nimport MarkdownWithHtml from 'react-markdown/with-html'\n\n<MarkdownWithHtml>{`# Hello, <i>world</i>!`}</MarkdownWithHtml>\n```\n\nNow (**fixed**):\n\n```js\nimport Markdown from 'react-markdown'\nimport rehypeRaw from 'rehype-raw'\nimport rehypeSanitize from 'rehype-sanitize'\n\n<Markdown rehypePlugins={[rehypeRaw, rehypeSanitize]}>{`# Hello, <i>world</i>!`}</Markdown>\n```\n\n</details>\n\n### Change `source` to `children`\n\nInstead of passing a `source` pass `children` instead:\n\n<details>\n<summary>Show example of needed change</summary>\n\nBefore (**broken**):\n\n```js\n<Markdown source=\"some\\nmarkdown\"></Markdown>\n```\n\nNow (**fixed**):\n\n```js\n<Markdown>{`some\nmarkdown`}</Markdown>\n```\n\nOr (**also fixed**):\n\n```js\n<Markdown children={`some\nmarkdown`} />\n```\n\n</details>\n\n### Replace `allowNode`, `allowedTypes`, and `disallowedTypes`\n\nSimilar to the `renderers` to `components` change, the filtering options\nalso changed from being based on markdown names towards being based on HTML\nnames: `allowNode` to `allowElement`, `allowedTypes` to `allowedElements`, and\n`disallowedTypes` to `disallowedElements`.\n\n<details>\n<summary>Show example of needed change</summary>\n\nBefore (**broken**):\n\n```js\n<Markdown\n  // Skip images\n  disallowedTypes={['image']}\n>{`![alt text](./image.url)`}</Markdown>\n```\n\nNow (**fixed**):\n\n```js\n<Markdown\n  // Skip images\n  disallowedElements={['img']}\n>{`![alt text](./image.url)`}</Markdown>\n```\n\n***\n\nBefore (**broken**):\n\n```js\n<Markdown\n  // Skip h1\n  allowNode={(node) => node.type !== 'heading' || node.depth !== 1}\n>{`# main heading`}</Markdown>\n```\n\nNow (**fixed**):\n\n```js\n<Markdown\n  // Skip h1\n  allowElement={(element) => element.tagName !== 'h1'}\n>{`# main heading`}</Markdown>\n```\n\n</details>\n\n### Change `includeNodeIndex` to `includeElementIndex`\n\nSimilar to the `renderers` to `components` change, this option to pass more info\nto components also changed from being based on markdown to being based on HTML.\n\n<details>\n<summary>Show example of needed change</summary>\n\nBefore (**broken**):\n\n```js\n<Markdown\n  includeNodeIndex={true}\n  renderers={{\n    paragraph({node, index, parentChildCount, ...props}) => <MyFancyParagraph {...props} />\n  }}\n>{`Some text`}</Markdown>\n```\n\nNow (**fixed**):\n\n```js\n<Markdown\n  includeElementIndex={true}\n  components={{\n    p({node, index, siblingsCount, ...props}) => <MyFancyParagraph {...props} />\n  }}\n>{`Some text`}</Markdown>\n```\n\n</details>\n\n### Change signature of `transformLinkUri`, `linkTarget`\n\nThe second parameter of these functions (to rewrite `href` on `a` or to define\n`target` on `a`) are now [hast](https://github.com/syntax-tree/hast) (HTML AST)\ninstead of [mdast](https://github.com/syntax-tree/mdast) (markdown AST).\n\n### Change signature of `transformImageUri`\n\nThe second parameter of this function was always `undefined` and the fourth was\nthe `alt` (`string`) on the image.\nThe second parameter is now that `alt`.\n\n### Remove support for React 15, IE11\n\nWe now use ES2015 (such as `Object.assign`) and removed certain hacks to work\nwith React 15 and older.\n\n## 5.0.3 - 2020-10-23\n\n* [`bb0bdde`](https://github.com/remarkjs/react-markdown/commit/bb0bdde)\n  Unlock peer dependency on React to allow v17\n* [`24e42bd`](https://github.com/remarkjs/react-markdown/commit/24e42bd)\n  Fix exception on missing element from `html-to-react`\n* [`3d363e9`](https://github.com/remarkjs/react-markdown/commit/3d363e9)\n  Fix umd browser build\n\n## 5.0.2 - 2020-10-23\n\n* [`4dadaba`](https://github.com/remarkjs/react-markdown/commit/4dadaba)\n  Fix to allow combining `allowedTypes`, `unwrapDisallowed` in types\n\n## 5.0.1 - 2020-10-21\n\n* [`c3dc5ee`](https://github.com/remarkjs/react-markdown/commit/c3dc5ee)\n  Fix to not crash on empty text nodes\n\n## 5.0.0 - 2020-10-19\n\n### BREAKING\n\n#### Maintained by [unified](https://unifiedjs.com)\n\nThis project is now maintained by the unified collective, which also houses the\nunderlying tools used in `react-markdown`: hundreds of projects for working with\nmarkdown and markup related things (including MDX).\nWe have cleaned the project: updated dependencies, improved\ndocs/tests/coverage/types, cleaned the issue tracker, and fixed a couple of\nbugs, but otherwise *much should be the same*.\n\n#### Upgrade `remark-parse`\n\nThe parser used in `react-markdown` has been upgraded to the latest version.\nIt is now 100% CommonMark compliant: that means it works the same as in other\nplaces, such as Discourse, Reddit, Stack Overflow, and GitHub.\nNote that GitHub does extend CommonMark: to match how Markdown works on GitHub,\nuse the [`remark-gfm`](https://github.com/remarkjs/remark-gfm) plugin.\n\n* [`remark-parse@9.0.0`](https://github.com/remarkjs/remark/releases/tag/remark-parse%409.0.0)\n* [`remark-parse@8.0.0`](https://github.com/remarkjs/remark/releases/tag/remark-parse%408.0.0)\n* [`remark-parse@7.0.0`](https://github.com/remarkjs/remark/releases/tag/remark-parse%407.0.0)\n* [`remark-parse@6.0.0`](https://github.com/remarkjs/remark/releases/tag/remark-parse%406.0.0)\n\n#### New serializer property: `node`\n\nA new `node` prop is passed to all non-tag/non-fragment renderers.\nThis contains the raw [mdast](https://github.com/syntax-tree/mdast) AST node,\nwhich opens up a number of interesting possibilities.\nThe breaking change is for renderers which blindly spread their props to an\nunderlying component/tag.\nFor instance:\n\n```js\n<ReactMarkdown renderers={{link: props => <a {...props} />}} … />\n```\n\nShould now be written as:\n\n```js\n<ReactMarkdown renderers={{link: ({node, ...props}) => <a {...props} />}} … />\n```\n\n#### List/list item `tight` property replaced by `spread`\n\nPreviously, the `tight` property would hint as to whether or not list items\nshould be wrapped in paragraphs.\nThis logic has now been replaced by a new `spread` property, which behaves\nslightly differently.\n[Read more](https://github.com/remarkjs/remark/pull/364).\n\n## 4.3.1 - 2020-01-05\n\n### Fixes\n\n* (Typings) Fix incorrect typescript definitions (Peng Guanwen)\n\n## 4.3.0 - 2020-01-02\n\n### Fixes\n\n* (Typings) Add typings for `react-markdown/html-parser` (Peng Guanwen)\n\n## 4.2.2 - 2019-09-03\n\n### Fixes\n\n* (Typings) Inline `RemarkParseOptions` for now (Espen Hovlandsdal)\n\n## 4.2.1 - 2019-09-01\n\n### Fixes\n\n* (Typings) Fix incorrect import - `RemarkParseOptions` (Jakub Chrzanowski)\n\n## 4.2.0 - 2019-09-01\n\n### Added\n\n* Add support for plugins that use AST transformations (Frankie Ali)\n\n### Fixes\n\n* (Typings) Add `parserOptions` to type definitions (Ted Piotrowski)\n* Allow renderer to be any React element type (Nathan Bierema)\n\n## 4.1.0 - 2019-06-24\n\n### Added\n\n* Add prop `parserOptions` to specify options for remark-parse (Kelvin Chan)\n\n## 4.0.9 - 2019-06-22\n\n### Fixes\n\n* (Typings) Make transformLinkUri & transformImageUri actually nullable\n  (Florentin Luca Rieger)\n\n## 4.0.8 - 2019-04-14\n\n### Fixes\n\n* Fix HTML parsing of elements with a single child vs. multiple children\n  (Nicolas Venegas)\n\n## 4.0.7 - 2019-04-14\n\n### Fixes\n\n* Fix matching of replaced non-void elements in HTML parser plugin (Nicolas\n  Venegas)\n* Fix HTML parsing of multiple void elements (Nicolas Venegas)\n* Fix void element children invariant violation (Nicolas Venegas)\n\n## 4.0.6 - 2019-01-04\n\n### Fixes\n\n* Mitigate regex ddos by upgrading html-to-react (Christoph Werner)\n* Update typings to allow arbitrary node types (Jesse Pinho)\n* Readme: Add note about only parsing plugins working (Vincent Tunru)\n\n## 4.0.4 - 2018-11-30\n\n### Changed\n\n* Upgrade dependencies (Espen Hovlandsdal)\n\n## 4.0.3 - 2018-10-11\n\n### Fixes\n\n* Output paragraph element for last item in loose list (Jeremy Moseley)\n\n## 4.0.2 - 2018-10-05\n\n### Fixes\n\n* Fix text rendering in React versions lower than or equal to 15 (Espen\n  Hovlandsdal)\n\n## 4.0.1 - 2018-10-03\n\n### Fixes\n\n* \\[TypeScript] Fix TypeScript index signature for renderers (Linus Unnebäck)\n\n## 4.0.0 - 2018-10-03\n\n### BREAKING\n\n* `text` is now a first-class node + renderer\n  — if you are using `allowedNodes`, it needs to be included in this list.\n  Since it is now a React component, it will be passed an object of props\n  instead of the old approach where a string was passed.\n  `children` will contain the actual text string.\n* On React >= 16.2, if no `className` prop is provided, a fragment will be\n  used instead of a div.\n  To always render a div, pass `'div'` as the `root` renderer.\n* On React >= 16.2, escaped HTML will no longer be rendered with div/span\n  containers\n* The UMD bundle now exports the component as `window.ReactMarkdown` instead\n  of `window.reactMarkdown`\n\n### Added\n\n* HTML parser plugin for full HTML compatibility (Espen Hovlandsdal)\n\n### Fixes\n\n* URI transformer allows uppercase http/https URLs (Liam Kennedy)\n* \\[TypeScript] Strongly type the keys of `renderers` (Linus Unnebäck)\n\n## 3.6.0 - 2018-09-05\n\n### Added\n\n* Add support for passing index info to renderers (Beau Roberts)\n\n## 3.5.0 - 2018-09-03\n\n### Added\n\n* Allow specifying `target` attribute for links (Marshall Smith)\n\n## 3.4.1 - 2018-07-25\n\n### Fixes\n\n* Bump dependency for mdast-add-list-metadata as it was using ES6 features\n  (Espen Hovlandsdal)\n\n## 3.4.0 - 2018-07-25\n\n### Added\n\n* Add more metadata props to list and listItem (André Staltz)\n  * list: `depth`\n  * listItem: `ordered`, `index`\n\n### Fixes\n\n* Make `source` property optional in typescript definition (gRoberts84)\n\n## 3.3.4 - 2018-06-19\n\n### Fixes\n\n* Fix bug where rendering empty link references (`[][]`) would fail (Dennis S)\n\n## 3.3.3 - 2018-06-14\n\n### Fixes\n\n* Fix bug where unwrapping certain disallowed nodes would fail (Petr Gazarov)\n\n## 3.3.2 - 2018-05-07\n\n### Changes\n\n* Add `rawSourcePos` property for passing structured source position info to\n  renderers (Espen Hovlandsdal)\n\n## 3.3.1 - 2018-05-07\n\n### Changes\n\n* Pass properties of unknown nodes directly to renderer (Jesse Pinho)\n* Update TypeScript definition and prop types (ClassicDarkChocolate)\n\n## 3.3.0 - 2018-03-06\n\n### Added\n\n* Add support for fragment renderers (Benjamim Sonntag)\n\n## 3.2.2 - 2018-02-26\n\n### Fixes\n\n* Fix language escaping in code blocks (Espen Hovlandsdal)\n\n## 3.2.1 - 2018-02-21\n\n### Fixes\n\n* Pass the React key into an overridden text renderer (vanchagreen)\n\n## 3.2.0 - 2018-02-12\n\n### Added\n\n* Allow overriding text renderer (Thibaud Courtoison)\n\n## 3.1.5 - 2018-02-03\n\n### Fixes\n\n* Only use first language from code block (Espen Hovlandsdal)\n\n## 3.1.4 - 2017-12-30\n\n### Fixes\n\n* Enable transformImageUri for image references (evoye)\n\n## 3.1.3 - 2017-12-16\n\n### Fixes\n\n* Exclude babel config from npm package (Espen Hovlandsdal)\n\n## 3.1.2 - 2017-12-16\n\n### Fixes\n\n* Fixed partial table exception (Alexander Wong)\n\n## 3.1.1 - 2017-12-11\n\n### Fixes\n\n* Add readOnly property to checkboxes (Phil Rajchgot)\n\n## 3.1.0 - 2017-11-30\n\n### Added\n\n* Support for checkbox lists (Espen Hovlandsdal)\n\n### Fixes\n\n* Better typings (Igor Kamyshev)\n\n## 3.0.1 - 2017-11-21\n\n### Added\n\n* *Experimental* support for plugins (Espen Hovlandsdal)\n\n### Changes\n\n* Provide more arguments to `transformLinkUri`/`transformImageUri` (children,\n  title, alt) (mudrz)\n\n## 3.0.0 - 2017-11-20\n\n### Notes\n\n* **FULL REWRITE**.\n  Changed parser from CommonMark to Markdown.\n  Big, breaking changes.\n  See *BREAKING* below.\n\n### Added\n\n* Table support!\n  * New types: `table`, `tableHead`, `tableBody`, `tableRow`, `tableCell`\n* New type: `delete` (`~~foo~~`)\n* New type: `imageReference`\n* New type: `linkReference`\n* New type: `definition`\n* Hacky, but basic support for React-native rendering of attributeless HTML\n  nodes (`<kbd>`, `<sub>`, etc)\n\n### BREAKING\n\n* Container props removed (`containerTagName`, `containerProps`), override\n  `root` renderer instead\n* `softBreak` option removed.\n  New solution will be added at some point in the future.\n* `escapeHtml` is now TRUE by default\n* `HtmlInline`/`HtmlBlock` are now named `html` (use `isBlock` prop to check\\\n  if inline or block)\n* Renderer names are camelcased and in certain cases, renamed.\n  For instance:\n  * `Emph` => `emphasis`\n  * `Item` => `listItem`\n  * `Code` => `inlineCode`\n  * `CodeBlock` => `code`\n  * `linebreak`/`hardbreak` => `break`\n* All renderers: `literal` prop is now called `value`\\* List renderer: `type`\n  prop is now a boolean named `ordered` (`Bullet` => `false`, `Ordered` =>\n  `true`)\n* `walker` prop removed.\n  Code depending on this will have to be rewritten to use the `astPlugins`\n  prop, which functions differently.\n* `allowNode` has new arguments (node, index, parent)\n  — node has different props, see renderer props\n* `childBefore` and `childAfter` props removed.\n  Use `root` renderer instead.\n* `parserOptions` removed (new parser, so the old options doesn’t make sense\n  anymore)\n\n## 2.5.1 - 2017-11-11\n\n### Changes\n\n* Fix `<br/>` not having a node key (Alex Zaworski)\n\n## 2.5.0 - 2017-04-10\n\n### Changes\n\n* Fix deprecations for React v15.5 (Renée Kooi)\n\n## 2.4.6 - 2017-03-14\n\n### Changes\n\n* Fix too strict TypeScript definition (Rasmus Eneman)\n* Update JSON-loader info in readme to match webpack 2 (Robin Wieruch)\n\n### Added\n\n* Add ability to pass options to the CommonMark parser (Evan Hensleigh)\n\n## 2.4.4 - 2017-01-16\n\n### Changes\n\n* Fixed TypeScript definitions (Kohei Asai)\n\n## 2.4.3 - 2017-01-12\n\n### Added\n\n* Added TypeScript definitions (Ibragimov Ruslan)\n\n## 2.4.2 - 2016-07-09\n\n### Added\n\n* Added UMD-build (`umd/react-markdown.js`) (Espen Hovlandsdal)\n\n## 2.4.1 - 2016-07-09\n\n### Changes\n\n* Update `commonmark-react-renderer`, fixing a bug with missing nodes\n  (Espen Hovlandsdal)\n\n## 2.4.0 - 2016-07-09\n\n### Changes\n\n* Plain DOM-node renderers are now given only their respective props.\n  Fixes warnings when using React >= 15.2 (Espen Hovlandsdal)\n\n### Added\n\n* New `transformImageUri` option allows you to transform URIs for images\n  (Petri Lehtinen)\n\n## 2.3.0 - 2016-06-06\n\n## Added\n\n* The `walker` instance is now passed to the `walker` callback function\n  (Riku Rouvila)\n\n## 2.2.0 - 2016-04-20\n\n* Add `childBefore`/`childAfter` options (Thomas Lindstrøm)\n\n## 2.1.1 - 2016-03-25\n\n* Add `containerProps` option (Thomas Lindstrøm)\n\n## 2.1.0 - 2016-03-12\n\n### Changes\n\n* Join sibling text nodes into one text node (Espen Hovlandsdal)\n\n## 2.0.1 - 2016-02-21\n\n### Changed\n\n* Update `commonmark-react-renderer` dependency to latest version to add keys\n  to all elements and simplify custom renderers\n\n## 2.0.0 - 2016-02-21\n\n### Changed\n\n* **Breaking change**: The renderer now requires Node 0.14 or higher.\n  This is because the renderer uses stateless components internally.\n* **Breaking change**: `allowNode` now receives different properties in the\n  options argument.\n  See `README.md` for more details.\n* **Breaking change**: CommonMark has changed some type names.\n  `Html` is now `HtmlInline`, `Header` is now `Heading` and `HorizontalRule`\n  is now `ThematicBreak`.\n  This affects the `allowedTypes` and `disallowedTypes` options.\n* **Breaking change**: A bug in the `allowedTypes`/`disallowedTypes` and\n  `allowNode` options made them only applicable to certain types.\n  In this version, all types are filtered, as expected.\n* **Breaking change**: Link URIs are now filtered through an XSS-filter by\n  default, prefixing “dangerous” protocols such as `javascript:` with `x-`\n  (eg: `javascript:alert('foo')` turns into `x-javascript:alert('foo')`).\n  This can be overridden with the `transformLinkUri`-option.\n  Pass `null` to disable the feature or a custom function to replace the\n  built-in behaviour.\n\n### Added\n\n* New `renderers` option allows you to customize which React component should\n  be used for rendering given types.\n  See `README.md` for more details.\n  (Espen Hovlandsdal / Guillaume Plique)\n* New `unwrapDisallowed` option allows you to select if the contents of a\n  disallowed node should be “unwrapped” (placed into the disallowed node\n  position).\n  For instance, setting this option to true and disallowing a link would still\n  render the text of the link, instead of the whole link node and all it’s\n  children disappearing.\n  (Espen Hovlandsdal)\n* New `transformLinkUri` option allows you to transform URIs in links.\n  By default, an XSS-filter is used, but you could also use this for use cases\n  like transforming absolute to relative URLs, or similar.\n  (Espen Hovlandsdal)\n\n## 1.2.4 - 2016-01-28\n\n### Changed\n\n* Rolled back dependencies because of breaking changes\n\n## 1.2.3 - 2016-01-24\n\n### Changed\n\n* Updated dependencies for both `commonmark` and `commonmark-react-parser` to\n  work around an embarrassing oversight on my part.\n\n## 1.2.2 - 2016-01-08\n\n### Changed\n\n* Reverted change from 1.2.1 that uses the dist version.\n  Instead, documentation is added that specified the need for `json-loader` to\n  be enabled when using webpack.\n\n## 1.2.1 - 2015-12-29\n\n### Fixed\n\n* Use pre-built (dist version) of commonmark renderer in order to work around\n  JSON-loader dependency.\n\n## 1.2.0 - 2015-12-16\n\n### Added\n\n* Added new `allowNode`-property.\n  See README for details.\n\n## 1.1.4 - 2015-12-14\n\n### Fixed\n\n* Set correct `libraryTarget` to make UMD builds work as expected\n\n## 1.1.3 - 2015-12-14\n\n### Fixed\n\n* Update babel dependencies and run prepublish only as actual prepublish, not\n  install\n\n## 1.1.1 - 2015-11-28\n\n### Fixed\n\n* Fixed issue with React external name in global environment (`react` vs `React`)\n\n## 1.1.0 - 2015-11-22\n\n### Changed\n\n* Add ability to allow/disallow specific node types (`allowedTypes`/`disallowedTypes`)\n\n## 1.0.5 - 2015-10-22\n\n### Changed\n\n* Moved React from dependency to peer dependency.\n"
  },
  {
    "path": "index.js",
    "content": "/**\n * @typedef {import('./lib/index.js').AllowElement} AllowElement\n * @typedef {import('./lib/index.js').Components} Components\n * @typedef {import('./lib/index.js').ExtraProps} ExtraProps\n * @typedef {import('./lib/index.js').HooksOptions} HooksOptions\n * @typedef {import('./lib/index.js').Options} Options\n * @typedef {import('./lib/index.js').UrlTransform} UrlTransform\n */\n\nexport {\n  MarkdownAsync,\n  MarkdownHooks,\n  Markdown as default,\n  defaultUrlTransform\n} from './lib/index.js'\n"
  },
  {
    "path": "lib/index.js",
    "content": "/**\n * @import {Element, Nodes, Parents, Root} from 'hast'\n * @import {Root as MdastRoot} from 'mdast'\n * @import {ComponentType, JSX, ReactElement, ReactNode} from 'react'\n * @import {Options as RemarkRehypeOptions} from 'remark-rehype'\n * @import {BuildVisitor} from 'unist-util-visit'\n * @import {PluggableList, Processor} from 'unified'\n */\n\n/**\n * @callback AllowElement\n *   Filter elements.\n * @param {Readonly<Element>} element\n *   Element to check.\n * @param {number} index\n *   Index of `element` in `parent`.\n * @param {Readonly<Parents> | undefined} parent\n *   Parent of `element`.\n * @returns {boolean | null | undefined}\n *   Whether to allow `element` (default: `false`).\n */\n\n/**\n * @typedef ExtraProps\n *   Extra fields we pass.\n * @property {Element | undefined} [node]\n *   passed when `passNode` is on.\n */\n\n/**\n * @typedef {{\n *   [Key in keyof JSX.IntrinsicElements]?: ComponentType<JSX.IntrinsicElements[Key] & ExtraProps> | keyof JSX.IntrinsicElements\n * }} Components\n *   Map tag names to components.\n */\n\n/**\n * @typedef Deprecation\n *   Deprecation.\n * @property {string} from\n *   Old field.\n * @property {string} id\n *   ID in readme.\n * @property {keyof Options} [to]\n *   New field.\n */\n\n/**\n * @typedef Options\n *   Configuration.\n * @property {AllowElement | null | undefined} [allowElement]\n *   Filter elements (optional);\n *   `allowedElements` / `disallowedElements` is used first.\n * @property {ReadonlyArray<string> | null | undefined} [allowedElements]\n *   Tag names to allow (default: all tag names);\n *   cannot combine w/ `disallowedElements`.\n * @property {string | null | undefined} [children]\n *   Markdown.\n * @property {Components | null | undefined} [components]\n *   Map tag names to components.\n * @property {ReadonlyArray<string> | null | undefined} [disallowedElements]\n *   Tag names to disallow (default: `[]`);\n *   cannot combine w/ `allowedElements`.\n * @property {PluggableList | null | undefined} [rehypePlugins]\n *   List of rehype plugins to use.\n * @property {PluggableList | null | undefined} [remarkPlugins]\n *   List of remark plugins to use.\n * @property {Readonly<RemarkRehypeOptions> | null | undefined} [remarkRehypeOptions]\n *   Options to pass through to `remark-rehype`.\n * @property {boolean | null | undefined} [skipHtml=false]\n *   Ignore HTML in markdown completely (default: `false`).\n * @property {boolean | null | undefined} [unwrapDisallowed=false]\n *   Extract (unwrap) what’s in disallowed elements (default: `false`);\n *   normally when say `strong` is not allowed, it and it’s children are dropped,\n *   with `unwrapDisallowed` the element itself is replaced by its children.\n * @property {UrlTransform | null | undefined} [urlTransform]\n *   Change URLs (default: `defaultUrlTransform`)\n */\n\n/**\n * @typedef HooksOptionsOnly\n *   Configuration specifically for {@linkcode MarkdownHooks}.\n * @property {ReactNode | null | undefined} [fallback]\n *   Content to render while the processor processing the markdown (optional).\n */\n\n/**\n * @typedef {Options & HooksOptionsOnly} HooksOptions\n *   Configuration for {@linkcode MarkdownHooks};\n *   extends the regular {@linkcode Options} with a `fallback` prop.\n */\n\n/**\n * @callback UrlTransform\n *   Transform all URLs.\n * @param {string} url\n *   URL.\n * @param {string} key\n *   Property name (example: `'href'`).\n * @param {Readonly<Element>} node\n *   Node.\n * @returns {string | null | undefined}\n *   Transformed URL (optional).\n */\n\nimport {unreachable} from 'devlop'\nimport {toJsxRuntime} from 'hast-util-to-jsx-runtime'\nimport {urlAttributes} from 'html-url-attributes'\nimport {Fragment, jsx, jsxs} from 'react/jsx-runtime'\nimport {useEffect, useMemo, useState} from 'react'\nimport remarkParse from 'remark-parse'\nimport remarkRehype from 'remark-rehype'\nimport {unified} from 'unified'\nimport {visit} from 'unist-util-visit'\nimport {VFile} from 'vfile'\n\nconst changelog =\n  'https://github.com/remarkjs/react-markdown/blob/main/changelog.md'\n\n/** @type {PluggableList} */\nconst emptyPlugins = []\n/** @type {Readonly<RemarkRehypeOptions>} */\nconst emptyRemarkRehypeOptions = {allowDangerousHtml: true}\nconst safeProtocol = /^(https?|ircs?|mailto|xmpp)$/i\n\n// Mutable because we `delete` any time it’s used and a message is sent.\n/** @type {ReadonlyArray<Readonly<Deprecation>>} */\nconst deprecations = [\n  {from: 'astPlugins', id: 'remove-buggy-html-in-markdown-parser'},\n  {from: 'allowDangerousHtml', id: 'remove-buggy-html-in-markdown-parser'},\n  {\n    from: 'allowNode',\n    id: 'replace-allownode-allowedtypes-and-disallowedtypes',\n    to: 'allowElement'\n  },\n  {\n    from: 'allowedTypes',\n    id: 'replace-allownode-allowedtypes-and-disallowedtypes',\n    to: 'allowedElements'\n  },\n  {from: 'className', id: 'remove-classname'},\n  {\n    from: 'disallowedTypes',\n    id: 'replace-allownode-allowedtypes-and-disallowedtypes',\n    to: 'disallowedElements'\n  },\n  {from: 'escapeHtml', id: 'remove-buggy-html-in-markdown-parser'},\n  {from: 'includeElementIndex', id: '#remove-includeelementindex'},\n  {\n    from: 'includeNodeIndex',\n    id: 'change-includenodeindex-to-includeelementindex'\n  },\n  {from: 'linkTarget', id: 'remove-linktarget'},\n  {from: 'plugins', id: 'change-plugins-to-remarkplugins', to: 'remarkPlugins'},\n  {from: 'rawSourcePos', id: '#remove-rawsourcepos'},\n  {from: 'renderers', id: 'change-renderers-to-components', to: 'components'},\n  {from: 'source', id: 'change-source-to-children', to: 'children'},\n  {from: 'sourcePos', id: '#remove-sourcepos'},\n  {from: 'transformImageUri', id: '#add-urltransform', to: 'urlTransform'},\n  {from: 'transformLinkUri', id: '#add-urltransform', to: 'urlTransform'}\n]\n\n/**\n * Component to render markdown.\n *\n * This is a synchronous component.\n * When using async plugins,\n * see {@linkcode MarkdownAsync} or {@linkcode MarkdownHooks}.\n *\n * @param {Readonly<Options>} options\n *   Props.\n * @returns {ReactElement}\n *   React element.\n */\nexport function Markdown(options) {\n  const processor = createProcessor(options)\n  const file = createFile(options)\n  return post(processor.runSync(processor.parse(file), file), options)\n}\n\n/**\n * Component to render markdown with support for async plugins\n * through async/await.\n *\n * Components returning promises are supported on the server.\n * For async support on the client,\n * see {@linkcode MarkdownHooks}.\n *\n * @param {Readonly<Options>} options\n *   Props.\n * @returns {Promise<ReactElement>}\n *   Promise to a React element.\n */\nexport async function MarkdownAsync(options) {\n  const processor = createProcessor(options)\n  const file = createFile(options)\n  const tree = await processor.run(processor.parse(file), file)\n  return post(tree, options)\n}\n\n/**\n * Component to render markdown with support for async plugins through hooks.\n *\n * This uses `useEffect` and `useState` hooks.\n * Hooks run on the client and do not immediately render something.\n * For async support on the server,\n * see {@linkcode MarkdownAsync}.\n *\n * @param {Readonly<HooksOptions>} options\n *   Props.\n * @returns {ReactNode}\n *   React node.\n */\nexport function MarkdownHooks(options) {\n  const processor = useMemo(\n    function () {\n      return createProcessor(options)\n    },\n    [options.rehypePlugins, options.remarkPlugins, options.remarkRehypeOptions]\n  )\n  const [error, setError] = useState(\n    /** @type {Error | undefined} */ (undefined)\n  )\n  const [tree, setTree] = useState(/** @type {Root | undefined} */ (undefined))\n\n  useEffect(\n    function () {\n      let cancelled = false\n      const file = createFile(options)\n\n      processor.run(processor.parse(file), file, function (error, tree) {\n        if (!cancelled) {\n          setError(error)\n          setTree(tree)\n        }\n      })\n\n      /**\n       * @returns {undefined}\n       *   Nothing.\n       */\n      return function () {\n        cancelled = true\n      }\n    },\n    [options.children, processor]\n  )\n\n  if (error) throw error\n\n  return tree ? post(tree, options) : options.fallback\n}\n\n/**\n * Set up the `unified` processor.\n *\n * @param {Readonly<Options>} options\n *   Props.\n * @returns {Processor<MdastRoot, MdastRoot, Root, undefined, undefined>}\n *   Result.\n */\nfunction createProcessor(options) {\n  const rehypePlugins = options.rehypePlugins || emptyPlugins\n  const remarkPlugins = options.remarkPlugins || emptyPlugins\n  const remarkRehypeOptions = options.remarkRehypeOptions\n    ? {...options.remarkRehypeOptions, ...emptyRemarkRehypeOptions}\n    : emptyRemarkRehypeOptions\n\n  const processor = unified()\n    .use(remarkParse)\n    .use(remarkPlugins)\n    .use(remarkRehype, remarkRehypeOptions)\n    .use(rehypePlugins)\n\n  return processor\n}\n\n/**\n * Set up the virtual file.\n *\n * @param {Readonly<Options>} options\n *   Props.\n * @returns {VFile}\n *   Result.\n */\nfunction createFile(options) {\n  const children = options.children || ''\n  const file = new VFile()\n\n  if (typeof children === 'string') {\n    file.value = children\n  } else {\n    unreachable(\n      'Unexpected value `' +\n        children +\n        '` for `children` prop, expected `string`'\n    )\n  }\n\n  return file\n}\n\n/**\n * Process the result from unified some more.\n *\n * @param {Nodes} tree\n *   Tree.\n * @param {Readonly<Options>} options\n *   Props.\n * @returns {ReactElement}\n *   React element.\n */\nfunction post(tree, options) {\n  const allowedElements = options.allowedElements\n  const allowElement = options.allowElement\n  const components = options.components\n  const disallowedElements = options.disallowedElements\n  const skipHtml = options.skipHtml\n  const unwrapDisallowed = options.unwrapDisallowed\n  const urlTransform = options.urlTransform || defaultUrlTransform\n\n  for (const deprecation of deprecations) {\n    if (Object.hasOwn(options, deprecation.from)) {\n      unreachable(\n        'Unexpected `' +\n          deprecation.from +\n          '` prop, ' +\n          (deprecation.to\n            ? 'use `' + deprecation.to + '` instead'\n            : 'remove it') +\n          ' (see <' +\n          changelog +\n          '#' +\n          deprecation.id +\n          '> for more info)'\n      )\n    }\n  }\n\n  if (allowedElements && disallowedElements) {\n    unreachable(\n      'Unexpected combined `allowedElements` and `disallowedElements`, expected one or the other'\n    )\n  }\n\n  visit(tree, transform)\n\n  return toJsxRuntime(tree, {\n    Fragment,\n    components,\n    ignoreInvalidStyle: true,\n    jsx,\n    jsxs,\n    passKeys: true,\n    passNode: true\n  })\n\n  /** @type {BuildVisitor<Root>} */\n  function transform(node, index, parent) {\n    if (node.type === 'raw' && parent && typeof index === 'number') {\n      if (skipHtml) {\n        parent.children.splice(index, 1)\n      } else {\n        parent.children[index] = {type: 'text', value: node.value}\n      }\n\n      return index\n    }\n\n    if (node.type === 'element') {\n      /** @type {string} */\n      let key\n\n      for (key in urlAttributes) {\n        if (\n          Object.hasOwn(urlAttributes, key) &&\n          Object.hasOwn(node.properties, key)\n        ) {\n          const value = node.properties[key]\n          const test = urlAttributes[key]\n          if (test === null || test.includes(node.tagName)) {\n            node.properties[key] = urlTransform(String(value || ''), key, node)\n          }\n        }\n      }\n    }\n\n    if (node.type === 'element') {\n      let remove = allowedElements\n        ? !allowedElements.includes(node.tagName)\n        : disallowedElements\n          ? disallowedElements.includes(node.tagName)\n          : false\n\n      if (!remove && allowElement && typeof index === 'number') {\n        remove = !allowElement(node, index, parent)\n      }\n\n      if (remove && parent && typeof index === 'number') {\n        if (unwrapDisallowed && node.children) {\n          parent.children.splice(index, 1, ...node.children)\n        } else {\n          parent.children.splice(index, 1)\n        }\n\n        return index\n      }\n    }\n  }\n}\n\n/**\n * Make a URL safe.\n *\n * This follows how GitHub works.\n * It allows the protocols `http`, `https`, `irc`, `ircs`, `mailto`, and `xmpp`,\n * and URLs relative to the current protocol (such as `/something`).\n *\n * @satisfies {UrlTransform}\n * @param {string} value\n *   URL.\n * @returns {string}\n *   Safe URL.\n */\nexport function defaultUrlTransform(value) {\n  // Same as:\n  // <https://github.com/micromark/micromark/blob/929275e/packages/micromark-util-sanitize-uri/dev/index.js#L34>\n  // But without the `encode` part.\n  const colon = value.indexOf(':')\n  const questionMark = value.indexOf('?')\n  const numberSign = value.indexOf('#')\n  const slash = value.indexOf('/')\n\n  if (\n    // If there is no protocol, it’s relative.\n    colon === -1 ||\n    // If the first colon is after a `?`, `#`, or `/`, it’s not a protocol.\n    (slash !== -1 && colon > slash) ||\n    (questionMark !== -1 && colon > questionMark) ||\n    (numberSign !== -1 && colon > numberSign) ||\n    // It is a protocol, it should be allowed.\n    safeProtocol.test(value.slice(0, colon))\n  ) {\n    return value\n  }\n\n  return ''\n}\n"
  },
  {
    "path": "license",
    "content": "The MIT License (MIT)\n\nCopyright (c) Espen Hovlandsdal\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"author\": \"Espen Hovlandsdal <espen@hovlandsdal.com>\",\n  \"bugs\": \"https://github.com/remarkjs/react-markdown/issues\",\n  \"contributors\": [\n    \"Alexander Wallin <office@alexanderwallin.com>\",\n    \"Alexander Wong <admin@alexander-wong.com>\",\n    \"André Staltz <andre@staltz.com>\",\n    \"Angus MacIsaac <angus.macisaac@busbud.com>\",\n    \"Beau Roberts <beau.roberts@autodesk.com>\",\n    \"Charlie Chen <doveccl@live.com>\",\n    \"Christian Murphy <christian.murphy.42@gmail.com>\",\n    \"Christoph Werner <christoph@codepunkt.de>\",\n    \"Danny <dannyharding10@gmail.com>\",\n    \"Dennis S <denis.s@svsg.co>\",\n    \"Espen Hovlandsdal <espen@hovlandsdal.com>\",\n    \"Evan Hensleigh <futuraprime@gmail.com>\",\n    \"Fabian Irsara <info@fabianirsara.com>\",\n    \"Florentin Luca Rieger <florentin.rieger@gmail.com>\",\n    \"Frank <frankieali4@gmail.com>\",\n    \"Igor Kamyshev <garik.novel@gmail.com>\",\n    \"Jack Williams <jsw547@gmail.com>\",\n    \"Jakub Chrzanowski <jakub@chrzanowski.info>\",\n    \"Jeremy Moseley <jeremy@jeremymoseley.net>\",\n    \"Jesse Pinho <jesse@jessepinho.com>\",\n    \"Kelvin Chan <kchan@securitycompass.com>\",\n    \"Kohei Asai <me@axross.io>\",\n    \"Linus Unnebäck <linus@folkdatorn.se>\",\n    \"Marshall Smith <marshall@radialdevgroup.com>\",\n    \"Nathan Bierema <nbierema@gmail.com>\",\n    \"Nicolas Venegas <nvenegas@atlassian.com>\",\n    \"Peng Guanwen <pg999w@outlook.com>\",\n    \"Petr Gazarov <petrgazarov@gmail.com>\",\n    \"Phil Rajchgot <tophil@outlook.com>\",\n    \"Rasmus Eneman <rasmus@eneman.eu>\",\n    \"René Kooi <renee@kooi.me>\",\n    \"Riku Rouvila <riku.rouvila@gmail.com>\",\n    \"Robin Wieruch <wrobin@gmx.net>\",\n    \"Rostyslav Melnychuk <blackswordgc@gmail.com>\",\n    \"Ted Piotrowski <tppiotrowski@gmail.com>\",\n    \"Thibaud Courtoison <do.not.press.enter@gmail.com>\",\n    \"Thomas Lindstrøm <t@hom.as>\",\n    \"Tiago Roldão <focus5.6@gmail.com>\",\n    \"Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)\",\n    \"cerkiewny <mstarzycki@gmail.com>\",\n    \"evoye <rosej@gmx.net>\",\n    \"gRoberts84 <gavin@gav-roberts.co.uk>\",\n    \"mudrz <mudrz@outlook.com>\",\n    \"vanchagreen <vanchagreen@gmail.com>\"\n  ],\n  \"dependencies\": {\n    \"@types/hast\": \"^3.0.0\",\n    \"@types/mdast\": \"^4.0.0\",\n    \"devlop\": \"^1.0.0\",\n    \"hast-util-to-jsx-runtime\": \"^2.0.0\",\n    \"html-url-attributes\": \"^3.0.0\",\n    \"mdast-util-to-hast\": \"^13.0.0\",\n    \"remark-parse\": \"^11.0.0\",\n    \"remark-rehype\": \"^11.0.0\",\n    \"unified\": \"^11.0.0\",\n    \"unist-util-visit\": \"^5.0.0\",\n    \"vfile\": \"^6.0.0\"\n  },\n  \"description\": \"React component to render markdown\",\n  \"devDependencies\": {\n    \"@testing-library/react\": \"^16.0.0\",\n    \"@types/node\": \"^22.0.0\",\n    \"@types/react\": \"^19.0.0\",\n    \"@types/react-dom\": \"^19.0.0\",\n    \"c8\": \"^10.0.0\",\n    \"concat-stream\": \"^2.0.0\",\n    \"esbuild\": \"^0.25.0\",\n    \"eslint-plugin-react\": \"^7.0.0\",\n    \"global-jsdom\": \"^26.0.0\",\n    \"prettier\": \"^3.0.0\",\n    \"react\": \"^19.0.0\",\n    \"react-dom\": \"^19.0.0\",\n    \"rehype-raw\": \"^7.0.0\",\n    \"rehype-starry-night\": \"^2.0.0\",\n    \"remark-cli\": \"^12.0.0\",\n    \"remark-gfm\": \"^4.0.0\",\n    \"remark-preset-wooorm\": \"^11.0.0\",\n    \"remark-toc\": \"^9.0.0\",\n    \"type-coverage\": \"^2.0.0\",\n    \"typescript\": \"^5.0.0\",\n    \"xo\": \"^0.60.0\"\n  },\n  \"exports\": \"./index.js\",\n  \"files\": [\n    \"index.d.ts.map\",\n    \"index.d.ts\",\n    \"index.js\",\n    \"lib/\"\n  ],\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/unified\"\n  },\n  \"keywords\": [\n    \"ast\",\n    \"commonmark\",\n    \"component\",\n    \"gfm\",\n    \"markdown\",\n    \"react\",\n    \"react-component\",\n    \"remark\",\n    \"unified\"\n  ],\n  \"license\": \"MIT\",\n  \"name\": \"react-markdown\",\n  \"peerDependencies\": {\n    \"@types/react\": \">=18\",\n    \"react\": \">=18\"\n  },\n  \"prettier\": {\n    \"bracketSpacing\": false,\n    \"singleQuote\": true,\n    \"semi\": false,\n    \"tabWidth\": 2,\n    \"trailingComma\": \"none\",\n    \"useTabs\": false\n  },\n  \"remarkConfig\": {\n    \"plugins\": [\n      \"remark-preset-wooorm\",\n      [\n        \"remark-lint-no-html\",\n        false\n      ]\n    ]\n  },\n  \"repository\": \"remarkjs/react-markdown\",\n  \"scripts\": {\n    \"build\": \"tsc --build --clean && tsc --build && type-coverage\",\n    \"format\": \"remark --frail --output --quiet -- . && prettier --log-level warn --write -- . && xo --fix\",\n    \"test-api\": \"node --conditions development --experimental-loader=./script/load-jsx.js --no-warnings test.jsx\",\n    \"test-coverage\": \"c8 --100 --exclude script/ --reporter lcov -- npm run test-api\",\n    \"test\": \"npm run build && npm run format && npm run test-coverage\"\n  },\n  \"sideEffects\": false,\n  \"typeCoverage\": {\n    \"atLeast\": 100,\n    \"strict\": true\n  },\n  \"type\": \"module\",\n  \"version\": \"10.1.0\",\n  \"xo\": {\n    \"envs\": [\n      \"shared-node-browser\"\n    ],\n    \"extends\": \"plugin:react/jsx-runtime\",\n    \"overrides\": [\n      {\n        \"files\": [\n          \"**/*.jsx\"\n        ],\n        \"rules\": {\n          \"no-unused-vars\": \"off\"\n        }\n      }\n    ],\n    \"prettier\": true,\n    \"rules\": {\n      \"complexity\": \"off\",\n      \"n/file-extension-in-import\": \"off\",\n      \"unicorn/prevent-abbreviations\": \"off\"\n    }\n  }\n}\n"
  },
  {
    "path": "readme.md",
    "content": "<!--\n  Notes for maintaining this document:\n\n  * update the version of the link for `commonmark-html` once in a while\n-->\n\n# react-markdown\n\n[![Build][badge-build-image]][badge-build-url]\n[![Coverage][badge-coverage-image]][badge-coverage-url]\n[![Downloads][badge-downloads-image]][badge-downloads-url]\n[![Size][badge-size-image]][badge-size-url]\n\nReact component to render markdown.\n\n## Feature highlights\n\n* [x] **[safe][section-security] by default**\n  (no `dangerouslySetInnerHTML` or XSS attacks)\n* [x] **[components][section-components]**\n  (pass your own component to use instead of `<h2>` for `## hi`)\n* [x] **[plugins][section-plugins]**\n  (many plugins you can pick and choose from)\n* [x] **[compliant][section-syntax]**\n  (100% to CommonMark, 100% to GFM with a plugin)\n\n## Contents\n\n* [What is this?](#what-is-this)\n* [When should I use this?](#when-should-i-use-this)\n* [Install](#install)\n* [Use](#use)\n* [API](#api)\n  * [`Markdown`](#markdown)\n  * [`MarkdownAsync`](#markdownasync)\n  * [`MarkdownHooks`](#markdownhooks)\n  * [`defaultUrlTransform(url)`](#defaulturltransformurl)\n  * [`AllowElement`](#allowelement)\n  * [`Components`](#components)\n  * [`ExtraProps`](#extraprops)\n  * [`HooksOptions`](#hooksoptions)\n  * [`Options`](#options)\n  * [`UrlTransform`](#urltransform)\n* [Examples](#examples)\n  * [Use a plugin](#use-a-plugin)\n  * [Use a plugin with options](#use-a-plugin-with-options)\n  * [Use custom components (syntax highlight)](#use-custom-components-syntax-highlight)\n  * [Use remark and rehype plugins (math)](#use-remark-and-rehype-plugins-math)\n* [Plugins](#plugins)\n* [Syntax](#syntax)\n* [Compatibility](#compatibility)\n* [Architecture](#architecture)\n* [Appendix A: HTML in markdown](#appendix-a-html-in-markdown)\n* [Appendix B: Components](#appendix-b-components)\n* [Appendix C: line endings in markdown (and JSX)](#appendix-c-line-endings-in-markdown-and-jsx)\n* [Security](#security)\n* [Related](#related)\n* [Contribute](#contribute)\n* [License](#license)\n\n## What is this?\n\nThis package is a [React][] component that can be given a string of markdown\nthat it’ll safely render to React elements.\nYou can pass plugins to change how markdown is transformed and pass components\nthat will be used instead of normal HTML elements.\n\n* to learn markdown, see this [cheatsheet and tutorial][commonmark-help]\n* to try out `react-markdown`, see [our demo][github-io-react-markdown]\n\n## When should I use this?\n\nThere are other ways to use markdown in React out there so why use this one?\nThe three main reasons are that they often rely on `dangerouslySetInnerHTML`,\nhave bugs with how they handle markdown, or don’t let you swap elements for\ncomponents.\n`react-markdown` builds a virtual DOM, so React only replaces what changed,\nfrom a syntax tree.\nThat’s supported because we use [unified][github-unified],\nspecifically [remark][github-remark] for markdown and [rehype][github-rehype]\nfor HTML,\nwhich are popular tools to transform content with plugins.\n\nThis package focusses on making it easy for beginners to safely use markdown in\nReact.\nWhen you’re familiar with unified, you can use a modern hooks based alternative\n[`react-remark`][github-react-remark] or [`rehype-react`][github-rehype-react]\nmanually.\nIf you instead want to use JavaScript and JSX *inside* markdown files, use\n[MDX][github-mdx].\n\n## Install\n\nThis package is [ESM only][esm].\nIn Node.js (version 16+), install with [npm][npm-install]:\n\n```sh\nnpm install react-markdown\n```\n\nIn Deno with [`esm.sh`][esmsh]:\n\n```js\nimport Markdown from 'https://esm.sh/react-markdown@10'\n```\n\nIn browsers with [`esm.sh`][esmsh]:\n\n```html\n<script type=\"module\">\n  import Markdown from 'https://esm.sh/react-markdown@10?bundle'\n</script>\n```\n\n## Use\n\nA basic hello world:\n\n```js\nimport React from 'react'\nimport {createRoot} from 'react-dom/client'\nimport Markdown from 'react-markdown'\n\nconst markdown = '# Hi, *Pluto*!'\n\ncreateRoot(document.body).render(<Markdown>{markdown}</Markdown>)\n```\n\n<details>\n<summary>Show equivalent JSX</summary>\n\n```js\n<h1>\n  Hi, <em>Pluto</em>!\n</h1>\n```\n\n</details>\n\nHere is an example that shows how to use a plugin\n([`remark-gfm`][github-remark-gfm],\nwhich adds support for footnotes, strikethrough, tables, tasklists and\nURLs directly):\n\n```js\nimport React from 'react'\nimport {createRoot} from 'react-dom/client'\nimport Markdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\n\nconst markdown = `Just a link: www.nasa.gov.`\n\ncreateRoot(document.body).render(\n  <Markdown remarkPlugins={[remarkGfm]}>{markdown}</Markdown>\n)\n```\n\n<details>\n<summary>Show equivalent JSX</summary>\n\n```js\n<p>\n  Just a link: <a href=\"http://www.nasa.gov\">www.nasa.gov</a>.\n</p>\n```\n\n</details>\n\n## API\n\nThis package exports the identifiers\n[`MarkdownAsync`][api-markdown-async],\n[`MarkdownHooks`][api-markdown-hooks],\nand\n[`defaultUrlTransform`][api-default-url-transform].\nThe default export is [`Markdown`][api-markdown].\n\nIt also exports the additional [TypeScript][] types\n[`AllowElement`][api-allow-element],\n[`Components`][api-components],\n[`ExtraProps`][api-extra-props],\n[`HooksOptions`][api-hooks-options],\n[`Options`][api-options],\nand\n[`UrlTransform`][api-url-transform].\n\n### `Markdown`\n\nComponent to render markdown.\n\nThis is a synchronous component.\nWhen using async plugins,\nsee [`MarkdownAsync`][api-markdown-async] or\n[`MarkdownHooks`][api-markdown-hooks].\n\n###### Parameters\n\n* `options` ([`Options`][api-options])\n  — props\n\n###### Returns\n\nReact element (`ReactElement`).\n\n### `MarkdownAsync`\n\nComponent to render markdown with support for async plugins\nthrough async/await.\n\nComponents returning promises are supported on the server.\nFor async support on the client,\nsee [`MarkdownHooks`][api-markdown-hooks].\n\n###### Parameters\n\n* `options` ([`Options`][api-options])\n  — props\n\n###### Returns\n\nPromise to a React element (`Promise<ReactElement>`).\n\n### `MarkdownHooks`\n\nComponent to render markdown with support for async plugins through hooks.\n\nThis uses `useEffect` and `useState` hooks.\nHooks run on the client and do not immediately render something.\nFor async support on the server,\nsee [`MarkdownAsync`][api-markdown-async].\n\n###### Parameters\n\n* `options` ([`Options`][api-options])\n  — props\n\n###### Returns\n\nReact node (`ReactNode`).\n\n### `defaultUrlTransform(url)`\n\nMake a URL safe.\n\nThis follows how GitHub works.\nIt allows the protocols `http`, `https`, `irc`, `ircs`, `mailto`, and `xmpp`,\nand URLs relative to the current protocol (such as `/something`).\n\n###### Parameters\n\n* `url` (`string`)\n  — URL\n\n###### Returns\n\nSafe URL (`string`).\n\n### `AllowElement`\n\nFilter elements (TypeScript type).\n\n###### Parameters\n\n* `node` ([`Element` from `hast`][github-hast-element])\n  — element to check\n* `index` (`number | undefined`)\n  — index of `element` in `parent`\n* `parent` ([`Node` from `hast`][github-hast-nodes])\n  — parent of `element`\n\n###### Returns\n\nWhether to allow `element` (`boolean`, optional).\n\n### `Components`\n\nMap tag names to components (TypeScript type).\n\n###### Type\n\n```ts\nimport type {ExtraProps} from 'react-markdown'\nimport type {ComponentProps, ElementType} from 'react'\n\ntype Components = {\n  [Key in Extract<ElementType, string>]?: ElementType<ComponentProps<Key> & ExtraProps>\n}\n```\n\n### `ExtraProps`\n\nExtra fields we pass to components (TypeScript type).\n\n###### Fields\n\n* `node` ([`Element` from `hast`][github-hast-element], optional)\n  — original node\n\n### `HooksOptions`\n\nConfiguration for [`MarkdownHooks`][api-markdown-hooks] (TypeScript type);\nextends the regular [`Options`][api-options] with a `fallback` prop.\n\n###### Extends\n\n[`Options`][api-options].\n\n###### Fields\n\n* `fallback` (`ReactNode`, optional)\n  — content to render while the processor processing the markdown\n\n### `Options`\n\nConfiguration (TypeScript type).\n\n###### Fields\n\n* `allowElement` ([`AllowElement`][api-allow-element], optional)\n  — filter elements;\n  `allowedElements` / `disallowedElements` is used first\n* `allowedElements` (`Array<string>`, default: all tag names)\n  — tag names to allow;\n  cannot combine w/ `disallowedElements`\n* `children` (`string`, optional)\n  — markdown\n* `components` ([`Components`][api-components], optional)\n  — map tag names to components\n* `disallowedElements` (`Array<string>`, default: `[]`)\n  — tag names to disallow;\n  cannot combine w/ `allowedElements`\n* `rehypePlugins` (`Array<Plugin>`, optional)\n  — list of [rehype plugins][github-rehype-plugins] to use\n* `remarkPlugins` (`Array<Plugin>`, optional)\n  — list of [remark plugins][github-remark-plugins] to use\n* `remarkRehypeOptions`\n  ([`Options` from `remark-rehype`][github-remark-rehype-options],\n  optional)\n  — options to pass through to `remark-rehype`\n* `skipHtml` (`boolean`, default: `false`)\n  — ignore HTML in markdown completely\n* `unwrapDisallowed` (`boolean`, default: `false`)\n  — extract (unwrap) what’s in disallowed elements;\n  normally when say `strong` is not allowed, it and it’s children are dropped,\n  with `unwrapDisallowed` the element itself is replaced by its children\n* `urlTransform` ([`UrlTransform`][api-url-transform], default:\n  [`defaultUrlTransform`][api-default-url-transform])\n  — change URLs\n\n### `UrlTransform`\n\nTransform URLs (TypeScript type).\n\n###### Parameters\n\n* `url` (`string`)\n  — URL\n* `key` (`string`, example: `'href'`)\n  — property name\n* `node` ([`Element` from `hast`][github-hast-element])\n  — element to check\n\n###### Returns\n\nTransformed URL (`string`, optional).\n\n## Examples\n\n### Use a plugin\n\nThis example shows how to use a remark plugin.\nIn this case, [`remark-gfm`][github-remark-gfm],\nwhich adds support for strikethrough, tables, tasklists and URLs directly:\n\n```js\nimport React from 'react'\nimport {createRoot} from 'react-dom/client'\nimport Markdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\n\nconst markdown = `A paragraph with *emphasis* and **strong importance**.\n\n> A block quote with ~strikethrough~ and a URL: https://reactjs.org.\n\n* Lists\n* [ ] todo\n* [x] done\n\nA table:\n\n| a | b |\n| - | - |\n`\n\ncreateRoot(document.body).render(\n  <Markdown remarkPlugins={[remarkGfm]}>{markdown}</Markdown>\n)\n```\n\n<details>\n<summary>Show equivalent JSX</summary>\n\n```js\n<>\n  <p>\n    A paragraph with <em>emphasis</em> and <strong>strong importance</strong>.\n  </p>\n  <blockquote>\n    <p>\n      A block quote with <del>strikethrough</del> and a URL:{' '}\n      <a href=\"https://reactjs.org\">https://reactjs.org</a>.\n    </p>\n  </blockquote>\n  <ul className=\"contains-task-list\">\n    <li>Lists</li>\n    <li className=\"task-list-item\">\n      <input type=\"checkbox\" disabled /> todo\n    </li>\n    <li className=\"task-list-item\">\n      <input type=\"checkbox\" disabled checked /> done\n    </li>\n  </ul>\n  <p>A table:</p>\n  <table>\n    <thead>\n      <tr>\n        <th>a</th>\n        <th>b</th>\n      </tr>\n    </thead>\n  </table>\n</>\n```\n\n</details>\n\n### Use a plugin with options\n\nThis example shows how to use a plugin and give it options.\nTo do that, use an array with the plugin at the first place, and the options\nsecond.\n[`remark-gfm`][github-remark-gfm] has an option to allow only double tildes for\nstrikethrough:\n\n```js\nimport React from 'react'\nimport {createRoot} from 'react-dom/client'\nimport Markdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\n\nconst markdown = 'This ~is not~ strikethrough, but ~~this is~~!'\n\ncreateRoot(document.body).render(\n  <Markdown remarkPlugins={[[remarkGfm, {singleTilde: false}]]}>\n    {markdown}\n  </Markdown>\n)\n```\n\n<details>\n<summary>Show equivalent JSX</summary>\n\n```js\n<p>\n  This ~is not~ strikethrough, but <del>this is</del>!\n</p>\n```\n\n</details>\n\n### Use custom components (syntax highlight)\n\nThis example shows how you can overwrite the normal handling of an element by\npassing a component.\nIn this case, we apply syntax highlighting with the seriously super amazing\n[`react-syntax-highlighter`][github-react-syntax-highlighter] by\n[**@conorhastings**][github-conorhastings]:\n\n<!-- To do: currently broken on actual ESM; let’s find an alternative? -->\n\n```js\nimport React from 'react'\nimport {createRoot} from 'react-dom/client'\nimport Markdown from 'react-markdown'\nimport {Prism as SyntaxHighlighter} from 'react-syntax-highlighter'\nimport {dark} from 'react-syntax-highlighter/dist/esm/styles/prism'\n\n// Did you know you can use tildes instead of backticks for code in markdown? ✨\nconst markdown = `Here is some JavaScript code:\n\n~~~js\nconsole.log('It works!')\n~~~\n`\n\ncreateRoot(document.body).render(\n  <Markdown\n    children={markdown}\n    components={{\n      code(props) {\n        const {children, className, node, ...rest} = props\n        const match = /language-(\\w+)/.exec(className || '')\n        return match ? (\n          <SyntaxHighlighter\n            {...rest}\n            PreTag=\"div\"\n            children={String(children).replace(/\\n$/, '')}\n            language={match[1]}\n            style={dark}\n          />\n        ) : (\n          <code {...rest} className={className}>\n            {children}\n          </code>\n        )\n      }\n    }}\n  />\n)\n```\n\n<details>\n<summary>Show equivalent JSX</summary>\n\n```js\n<>\n  <p>Here is some JavaScript code:</p>\n  <pre>\n    <SyntaxHighlighter language=\"js\" style={dark} PreTag=\"div\" children=\"console.log('It works!')\" />\n  </pre>\n</>\n```\n\n</details>\n\n### Use remark and rehype plugins (math)\n\nThis example shows how a syntax extension\n(through [`remark-math`][github-remark-math])\nis used to support math in markdown, and a transform plugin\n([`rehype-katex`][github-rehype-katex]) to render that math.\n\n```js\nimport React from 'react'\nimport {createRoot} from 'react-dom/client'\nimport Markdown from 'react-markdown'\nimport rehypeKatex from 'rehype-katex'\nimport remarkMath from 'remark-math'\nimport 'katex/dist/katex.min.css' // `rehype-katex` does not import the CSS for you\n\nconst markdown = `The lift coefficient ($C_L$) is a dimensionless coefficient.`\n\ncreateRoot(document.body).render(\n  <Markdown remarkPlugins={[remarkMath]} rehypePlugins={[rehypeKatex]}>\n    {markdown}\n  </Markdown>\n)\n```\n\n<details>\n<summary>Show equivalent JSX</summary>\n\n```js\n<p>\n  The lift coefficient (\n  <span className=\"katex\">\n    <span className=\"katex-mathml\">\n      <math xmlns=\"http://www.w3.org/1998/Math/MathML\">{/* … */}</math>\n    </span>\n    <span className=\"katex-html\" aria-hidden=\"true\">\n      {/* … */}\n    </span>\n  </span>\n  ) is a dimensionless coefficient.\n</p>\n```\n\n</details>\n\n## Plugins\n\nWe use [unified][github-unified],\nspecifically [remark][github-remark] for markdown and\n[rehype][github-rehype] for HTML,\nwhich are tools to transform content with plugins.\nHere are three good ways to find plugins:\n\n* [`awesome-remark`][github-awesome-remark] and\n  [`awesome-rehype`][github-awesome-rehype]\n  — selection of the most awesome projects\n* [List of remark plugins][github-remark-plugins] and\n  [list of rehype plugins][github-rehype-plugins]\n  — list of all plugins\n* [`remark-plugin`][github-topic-remark-plugin] and\n  [`rehype-plugin`][github-topic-rehype-plugin] topics\n  — any tagged repo on GitHub\n\n## Syntax\n\n`react-markdown` follows CommonMark, which standardizes the differences between\nmarkdown implementations, by default.\nSome syntax extensions are supported through plugins.\n\nWe use [`micromark`][github-micromark] under the hood for our parsing.\nSee its documentation for more information on markdown, CommonMark, and\nextensions.\n\n## Compatibility\n\nProjects maintained by the unified collective are compatible with maintained\nversions of Node.js.\n\nWhen we cut a new major release, we drop support for unmaintained versions of\nNode.\nThis means we try to keep the current release line, `react-markdown@10`,\ncompatible with Node.js 16.\n\nThey work in all modern browsers (essentially: everything not IE 11).\nYou can use a bundler (such as esbuild, webpack, or Rollup) to use this package\nin your project, and use its options (or plugins) to add support for legacy\nbrowsers.\n\n## Architecture\n\n<pre><code>                                                           react-markdown\n         +----------------------------------------------------------------------------------------------------------------+\n         |                                                                                                                |\n         |  +----------+        +----------------+        +---------------+       +----------------+       +------------+ |\n         |  |          |        |                |        |               |       |                |       |            | |\n<a href=\"https://commonmark.org\">markdown</a>-+->+  <a href=\"https://github.com/remarkjs/remark\">remark</a>  +-<a href=\"https://github.com/syntax-tree/mdast\">mdast</a>->+ <a href=\"https://github.com/remarkjs/remark/blob/main/doc/plugins.md\">remark plugins</a> +-<a href=\"https://github.com/syntax-tree/mdast\">mdast</a>->+ <a href=\"https://github.com/remarkjs/remark-rehype\">remark-rehype</a> +-<a href=\"https://github.com/syntax-tree/hast\">hast</a>->+ <a href=\"https://github.com/rehypejs/rehype/blob/main/doc/plugins.md\">rehype plugins</a> +-<a href=\"https://github.com/syntax-tree/hast\">hast</a>->+ <a href=\"#appendix-b-components\">components</a> +-+->react elements\n         |  |          |        |                |        |               |       |                |       |            | |\n         |  +----------+        +----------------+        +---------------+       +----------------+       +------------+ |\n         |                                                                                                                |\n         +----------------------------------------------------------------------------------------------------------------+\n</code></pre>\n\nTo understand what this project does, it’s important to first understand what\nunified does: please read through the [`unifiedjs/unified`][github-unified]\nreadme\n(the part until you hit the API section is required reading).\n\n`react-markdown` is a unified pipeline — wrapped so that most folks don’t need\nto directly interact with unified.\nThe processor goes through these steps:\n\n* parse markdown to mdast (markdown syntax tree)\n* transform through remark (markdown ecosystem)\n* transform mdast to hast (HTML syntax tree)\n* transform through rehype (HTML ecosystem)\n* render hast to React with components\n\n## Appendix A: HTML in markdown\n\n`react-markdown` typically escapes HTML (or ignores it, with `skipHtml`)\nbecause it is dangerous and defeats the purpose of this library.\n\nHowever, if you are in a trusted environment (you trust the markdown), and\ncan spare the bundle size (±60kb minzipped), then you can use\n[`rehype-raw`][github-rehype-raw]:\n\n```js\nimport React from 'react'\nimport {createRoot} from 'react-dom/client'\nimport Markdown from 'react-markdown'\nimport rehypeRaw from 'rehype-raw'\n\nconst markdown = `<div class=\"note\">\n\nSome *emphasis* and <strong>strong</strong>!\n\n</div>`\n\ncreateRoot(document.body).render(\n  <Markdown rehypePlugins={[rehypeRaw]}>{markdown}</Markdown>\n)\n```\n\n<details>\n<summary>Show equivalent JSX</summary>\n\n```js\n<div className=\"note\">\n  <p>\n    Some <em>emphasis</em> and <strong>strong</strong>!\n  </p>\n</div>\n```\n\n</details>\n\n**Note**: HTML in markdown is still bound by how [HTML works in\nCommonMark][commonmark-html].\nMake sure to use blank lines around block-level HTML that again contains\nmarkdown!\n\n## Appendix B: Components\n\nYou can also change the things that come from markdown:\n\n```js\n<Markdown\n  components={{\n    // Map `h1` (`# heading`) to use `h2`s.\n    h1: 'h2',\n    // Rewrite `em`s (`*like so*`) to `i` with a red foreground color.\n    em(props) {\n      const {node, ...rest} = props\n      return <i style={{color: 'red'}} {...rest} />\n    }\n  }}\n/>\n```\n\nThe keys in components are HTML equivalents for the things you write with\nmarkdown (such as `h1` for `# heading`).\nNormally, in markdown, those are: `a`, `blockquote`, `br`, `code`, `em`, `h1`,\n`h2`, `h3`, `h4`, `h5`, `h6`, `hr`, `img`, `li`, `ol`, `p`, `pre`, `strong`, and\n`ul`.\nWith [`remark-gfm`][github-remark-gfm],\nyou can also use `del`, `input`, `table`, `tbody`, `td`, `th`, `thead`, and `tr`.\nOther remark or rehype plugins that add support for new constructs will also\nwork with `react-markdown`.\n\nThe props that are passed are what you probably would expect: an `a` (link) will\nget `href` (and `title`) props, and `img` (image) an `src`, `alt` and `title`,\netc.\n\nEvery component will receive a `node`.\nThis is the original [`Element` from `hast`][github-hast-element] element being\nturned into a React element.\n\n## Appendix C: line endings in markdown (and JSX)\n\nYou might have trouble with how line endings work in markdown and JSX.\nWe recommend the following, which solves all line ending problems:\n\n```js\n// If you write actual markdown in your code, put your markdown in a variable;\n// **do not indent markdown**:\nconst markdown = `\n# This is perfect!\n`\n\n// Pass the value as an expression as an only child:\nconst result = <Markdown>{markdown}</Markdown>\n```\n\n👆 That works.\nRead on for what doesn’t and why that is.\n\nYou might try to write markdown directly in your JSX and find that it **does\nnot** work:\n\n```js\n<Markdown>\n  # Hi\n\n  This is **not** a paragraph.\n</Markdown>\n```\n\nThe is because in JSX the whitespace (including line endings) is collapsed to\na single space.\nSo the above example is equivalent to:\n\n```js\n<Markdown> # Hi This is **not** a paragraph. </Markdown>\n```\n\nInstead, to pass markdown to `Markdown`, you can use an expression:\nwith a template literal:\n\n```js\n<Markdown>{`\n# Hi\n\nThis is a paragraph.\n`}</Markdown>\n```\n\nTemplate literals have another potential problem, because they keep whitespace\n(including indentation) inside them.\nThat means that the following **does not** turn into a heading:\n\n```js\n<Markdown>{`\n    # This is **not** a heading, it’s an indented code block\n`}</Markdown>\n```\n\n## Security\n\nUse of `react-markdown` is secure by default.\nOverwriting `urlTransform` to something insecure will open you up to XSS\nvectors.\nFurthermore, the `remarkPlugins`, `rehypePlugins`, and `components` you use may\nbe insecure.\n\nTo make sure the content is completely safe, even after what plugins do,\nuse [`rehype-sanitize`][github-rehype-sanitize].\nIt lets you define your own schema of what is and isn’t allowed.\n\n## Related\n\n* [`MDX`][github-mdx]\n  — JSX *in* markdown\n* [`remark-gfm`][github-remark-gfm]\n  — add support for GitHub flavored markdown support\n* [`react-remark`][github-react-remark]\n  — hook based alternative\n* [`rehype-react`][github-rehype-react]\n  — turn HTML into React elements\n\n## Contribute\n\nSee [`contributing.md`][health-contributing] in [`remarkjs/.github`][health]\nfor ways to get started.\nSee [`support.md`][health-support] for ways to get help.\n\nThis project has a [code of conduct][health-coc].\nBy interacting with this repository, organization, or community you agree to\nabide by its terms.\n\n## License\n\n[MIT][file-license] © [Espen Hovlandsdal][author]\n\n[api-allow-element]: #allowelement\n\n[api-components]: #components\n\n[api-default-url-transform]: #defaulturltransformurl\n\n[api-extra-props]: #extraprops\n\n[api-hooks-options]: #hooksoptions\n\n[api-markdown]: #markdown\n\n[api-markdown-async]: #markdownasync\n\n[api-markdown-hooks]: #markdownhooks\n\n[api-options]: #options\n\n[api-url-transform]: #urltransform\n\n[author]: https://espen.codes/\n\n[badge-build-image]: https://github.com/remarkjs/react-markdown/workflows/main/badge.svg\n\n[badge-build-url]: https://github.com/remarkjs/react-markdown/actions\n\n[badge-coverage-image]: https://img.shields.io/codecov/c/github/remarkjs/react-markdown.svg\n\n[badge-coverage-url]: https://codecov.io/github/remarkjs/react-markdown\n\n[badge-downloads-image]: https://img.shields.io/npm/dm/react-markdown.svg\n\n[badge-downloads-url]: https://www.npmjs.com/package/react-markdown\n\n[badge-size-image]: https://img.shields.io/bundlejs/size/react-markdown\n\n[badge-size-url]: https://bundlejs.com/?q=react-markdown\n\n[commonmark-help]: https://commonmark.org/help/\n\n[commonmark-html]: https://spec.commonmark.org/0.31.2/#html-blocks\n\n[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c\n\n[esmsh]: https://esm.sh\n\n[file-license]: license\n\n[github-awesome-rehype]: https://github.com/rehypejs/awesome-rehype\n\n[github-awesome-remark]: https://github.com/remarkjs/awesome-remark\n\n[github-conorhastings]: https://github.com/conorhastings\n\n[github-hast-element]: https://github.com/syntax-tree/hast#element\n\n[github-hast-nodes]: https://github.com/syntax-tree/hast#nodes\n\n[github-io-react-markdown]: https://remarkjs.github.io/react-markdown/\n\n[github-mdx]: https://github.com/mdx-js/mdx/\n\n[github-micromark]: https://github.com/micromark/micromark\n\n[github-react-remark]: https://github.com/remarkjs/react-remark\n\n[github-react-syntax-highlighter]: https://github.com/react-syntax-highlighter/react-syntax-highlighter\n\n[github-rehype]: https://github.com/rehypejs/rehype\n\n[github-rehype-katex]: https://github.com/remarkjs/remark-math/tree/main/packages/rehype-katex\n\n[github-rehype-plugins]: https://github.com/rehypejs/rehype/blob/main/doc/plugins.md#list-of-plugins\n\n[github-rehype-raw]: https://github.com/rehypejs/rehype-raw\n\n[github-rehype-react]: https://github.com/rehypejs/rehype-react\n\n[github-rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize\n\n[github-remark]: https://github.com/remarkjs/remark\n\n[github-remark-gfm]: https://github.com/remarkjs/remark-gfm\n\n[github-remark-math]: https://github.com/remarkjs/remark-math\n\n[github-remark-plugins]: https://github.com/remarkjs/remark/blob/main/doc/plugins.md#list-of-plugins\n\n[github-remark-rehype-options]: https://github.com/remarkjs/remark-rehype#options\n\n[github-topic-rehype-plugin]: https://github.com/topics/rehype-plugin\n\n[github-topic-remark-plugin]: https://github.com/topics/remark-plugin\n\n[github-unified]: https://github.com/unifiedjs/unified\n\n[health]: https://github.com/remarkjs/.github\n\n[health-coc]: https://github.com/remarkjs/.github/blob/main/code-of-conduct.md\n\n[health-contributing]: https://github.com/remarkjs/.github/blob/main/contributing.md\n\n[health-support]: https://github.com/remarkjs/.github/blob/main/support.md\n\n[npm-install]: https://docs.npmjs.com/cli/install\n\n[react]: http://reactjs.org\n\n[section-components]: #appendix-b-components\n\n[section-plugins]: #plugins\n\n[section-security]: #security\n\n[section-syntax]: #syntax\n\n[typescript]: https://www.typescriptlang.org\n"
  },
  {
    "path": "script/load-jsx.js",
    "content": "import fs from 'node:fs/promises'\nimport {fileURLToPath} from 'node:url'\nimport {transform} from 'esbuild'\n\nconst {getFormat, load, transformSource} = createLoader()\n\nexport {getFormat, load, transformSource}\n\n/**\n * A tiny JSX loader.\n */\nexport function createLoader() {\n  return {load, getFormat, transformSource}\n\n  // Node version 17.\n  /**\n   * @param {string} href\n   * @param {unknown} context\n   * @param {Function} defaultLoad\n   */\n  async function load(href, context, defaultLoad) {\n    const url = new URL(href)\n\n    if (!url.pathname.endsWith('.jsx')) {\n      return defaultLoad(href, context, defaultLoad)\n    }\n\n    const {code, warnings} = await transform(String(await fs.readFile(url)), {\n      format: 'esm',\n      loader: 'jsx',\n      sourcefile: fileURLToPath(url),\n      sourcemap: 'both',\n      target: 'esnext'\n    })\n\n    if (warnings) {\n      for (const warning of warnings) {\n        console.log(warning.location)\n        console.log(warning.text)\n      }\n    }\n\n    return {format: 'module', shortCircuit: true, source: code}\n  }\n\n  // Pre version 17.\n  /**\n   * @param {string} href\n   * @param {unknown} context\n   * @param {Function} defaultGetFormat\n   */\n  function getFormat(href, context, defaultGetFormat) {\n    const url = new URL(href)\n\n    return url.pathname.endsWith('.jsx')\n      ? {format: 'module'}\n      : defaultGetFormat(href, context, defaultGetFormat)\n  }\n\n  /**\n   * @param {Buffer} value\n   * @param {{url: string, [x: string]: unknown}} context\n   * @param {Function} defaultTransformSource\n   */\n  async function transformSource(value, context, defaultTransformSource) {\n    const url = new URL(context.url)\n\n    if (!url.pathname.endsWith('.jsx')) {\n      return defaultTransformSource(value, context, defaultTransformSource)\n    }\n\n    const {code, warnings} = await transform(String(value), {\n      format: context.format === 'module' ? 'esm' : 'cjs',\n      loader: 'jsx',\n      sourcefile: fileURLToPath(url),\n      sourcemap: 'both',\n      target: 'esnext'\n    })\n\n    if (warnings) {\n      for (const warning of warnings) {\n        console.log(warning.location)\n        console.log(warning.text)\n      }\n    }\n\n    return {source: code}\n  }\n}\n"
  },
  {
    "path": "test.jsx",
    "content": "/* @jsxRuntime automatic @jsxImportSource react */\n/**\n * @import {Root} from 'hast'\n * @import {ComponentProps, ReactNode} from 'react'\n * @import {ExtraProps} from 'react-markdown'\n * @import {Plugin} from 'unified'\n */\n\n/**\n * @typedef DeferredPlugin\n *   Deferred plugin.\n * @property {Plugin<[]>} plugin\n *   Plugin.\n * @property {(error: Error) => undefined} reject\n *   Reject the plugin.\n * @property {() => undefined} resolve\n *   Resolve the plugin.\n */\n\nimport assert from 'node:assert/strict'\nimport test from 'node:test'\nimport 'global-jsdom/register'\nimport {render, waitFor} from '@testing-library/react'\nimport concatStream from 'concat-stream'\nimport {Component} from 'react'\nimport {renderToPipeableStream, renderToStaticMarkup} from 'react-dom/server'\nimport Markdown, {MarkdownAsync, MarkdownHooks} from 'react-markdown'\nimport rehypeRaw from 'rehype-raw'\nimport rehypeStarryNight from 'rehype-starry-night'\nimport remarkGfm from 'remark-gfm'\nimport remarkToc from 'remark-toc'\nimport {visit} from 'unist-util-visit'\n\nconst decoder = new TextDecoder()\n\ntest('react-markdown (core)', async function (t) {\n  await t.test('should expose the public api', async function () {\n    assert.deepEqual(Object.keys(await import('react-markdown')).sort(), [\n      'MarkdownAsync',\n      'MarkdownHooks',\n      'default',\n      'defaultUrlTransform'\n    ])\n  })\n})\n\ntest('Markdown', async function (t) {\n  await t.test('should work', function () {\n    assert.equal(renderToStaticMarkup(<Markdown children=\"a\" />), '<p>a</p>')\n  })\n\n  await t.test('should throw w/ `source`', function () {\n    assert.throws(function () {\n      // @ts-expect-error: check how the runtime handles untyped `source`.\n      renderToStaticMarkup(<Markdown source=\"a\" />)\n    }, /Unexpected `source` prop, use `children` instead/)\n  })\n\n  await t.test('should throw w/ non-string children (number)', function () {\n    assert.throws(function () {\n      // @ts-expect-error: check how the runtime handles invalid `children`.\n      renderToStaticMarkup(<Markdown children={1} />)\n    }, /Unexpected value `1` for `children` prop, expected `string`/)\n  })\n\n  await t.test('should throw w/ non-string children (boolean)', function () {\n    assert.throws(function () {\n      // @ts-expect-error: check how the runtime handles invalid `children`.\n      renderToStaticMarkup(<Markdown children={true} />)\n    }, /Unexpected value `true` for `children` prop, expected `string`/)\n  })\n\n  await t.test('should support `null` as children', function () {\n    assert.equal(renderToStaticMarkup(<Markdown children={null} />), '')\n  })\n\n  await t.test('should support `undefined` as children', function () {\n    assert.equal(renderToStaticMarkup(<Markdown children={undefined} />), '')\n  })\n\n  await t.test('should warn w/ `allowDangerousHtml`', function () {\n    assert.throws(function () {\n      // @ts-expect-error: check how the runtime handles deprecated `allowDangerousHtml`.\n      renderToStaticMarkup(<Markdown allowDangerousHtml />)\n    }, /Unexpected `allowDangerousHtml` prop, remove it/)\n  })\n\n  await t.test('should support a block quote', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"> a\" />),\n      '<blockquote>\\n<p>a</p>\\n</blockquote>'\n    )\n  })\n\n  await t.test('should support a break', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children={'a\\\\\\nb'} />),\n      '<p>a<br/>\\nb</p>'\n    )\n  })\n\n  await t.test('should support a code (block, flow; indented)', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"    a\" />),\n      '<pre><code>a\\n</code></pre>'\n    )\n  })\n\n  await t.test('should support a code (block, flow; fenced)', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children={'```js\\na\\n```'} />),\n      '<pre><code class=\"language-js\">a\\n</code></pre>'\n    )\n  })\n\n  await t.test('should support a delete (GFM)', function () {\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown children=\"~a~\" remarkPlugins={[remarkGfm]} />\n      ),\n      '<p><del>a</del></p>'\n    )\n  })\n\n  await t.test('should support an emphasis', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"*a*\" />),\n      '<p><em>a</em></p>'\n    )\n  })\n\n  await t.test('should support a footnote (GFM)', function () {\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown children={'a[^x]\\n\\n[^x]: y'} remarkPlugins={[remarkGfm]} />\n      ),\n      '<p>a<sup><a href=\"#user-content-fn-x\" id=\"user-content-fnref-x\" data-footnote-ref=\"true\" aria-describedby=\"footnote-label\">1</a></sup></p>\\n<section data-footnotes=\"true\" class=\"footnotes\"><h2 class=\"sr-only\" id=\"footnote-label\">Footnotes</h2>\\n<ol>\\n<li id=\"user-content-fn-x\">\\n<p>y <a href=\"#user-content-fnref-x\" data-footnote-backref=\"\" aria-label=\"Back to reference 1\" class=\"data-footnote-backref\">↩</a></p>\\n</li>\\n</ol>\\n</section>'\n    )\n  })\n\n  await t.test('should support a heading', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"# a\" />),\n      '<h1>a</h1>'\n    )\n  })\n\n  await t.test('should support an html (default)', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"<i>a</i>\" />),\n      '<p>&lt;i&gt;a&lt;/i&gt;</p>'\n    )\n  })\n\n  await t.test('should support an html (w/ `rehype-raw`)', function () {\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown children=\"<i>a</i>\" rehypePlugins={[rehypeRaw]} />\n      ),\n      '<p><i>a</i></p>'\n    )\n  })\n\n  await t.test('should support an image', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"![a](b)\" />),\n      // Note: React weirdly adds `rel=\"preload\"`.\n      '<link rel=\"preload\" as=\"image\" href=\"b\"/><p><img src=\"b\" alt=\"a\"/></p>'\n    )\n  })\n\n  await t.test('should support an image w/ a title', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"![a](b (c))\" />),\n      // Note: React weirdly adds `rel=\"preload\"`.\n      '<link rel=\"preload\" as=\"image\" href=\"b\"/><p><img src=\"b\" alt=\"a\" title=\"c\"/></p>'\n    )\n  })\n\n  await t.test('should support an image reference / definition', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children={'![a]\\n\\n[a]: b'} />),\n      // Note: React weirdly adds `rel=\"preload\"`.\n      '<link rel=\"preload\" as=\"image\" href=\"b\"/><p><img src=\"b\" alt=\"a\"/></p>'\n    )\n  })\n\n  await t.test('should support code (text, inline)', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"`a`\" />),\n      '<p><code>a</code></p>'\n    )\n  })\n\n  await t.test('should support a link', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"[a](b)\" />),\n      '<p><a href=\"b\">a</a></p>'\n    )\n  })\n\n  await t.test('should support a link w/ a title', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"[a](b (c))\" />),\n      '<p><a href=\"b\" title=\"c\">a</a></p>'\n    )\n  })\n\n  await t.test('should support a link reference / definition', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children={'[a]\\n\\n[a]: b'} />),\n      '<p><a href=\"b\">a</a></p>'\n    )\n  })\n\n  await t.test('should support prototype poluting identifiers', function () {\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children={\n            '[][__proto__] [][constructor]\\n\\n[__proto__]: a\\n[constructor]: b'\n          }\n        />\n      ),\n      '<p><a href=\"a\"></a> <a href=\"b\"></a></p>'\n    )\n  })\n\n  await t.test('should support duplicate definitions', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children={'[a][]\\n\\n[a]: b\\n[a]: c'} />),\n      '<p><a href=\"b\">a</a></p>'\n    )\n  })\n\n  await t.test('should support a list (unordered) / list item', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"* a\" />),\n      '<ul>\\n<li>a</li>\\n</ul>'\n    )\n  })\n\n  await t.test('should support a list (ordered) / list item', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"1. a\" />),\n      '<ol>\\n<li>a</li>\\n</ol>'\n    )\n  })\n\n  await t.test('should support a paragraph', function () {\n    assert.equal(renderToStaticMarkup(<Markdown children=\"a\" />), '<p>a</p>')\n  })\n\n  await t.test('should support a strong', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"**a**\" />),\n      '<p><strong>a</strong></p>'\n    )\n  })\n\n  await t.test('should support a table (GFM)', function () {\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children={'| a |\\n| - |\\n| b |'}\n          remarkPlugins={[remarkGfm]}\n        />\n      ),\n      '<table><thead><tr><th>a</th></tr></thead><tbody><tr><td>b</td></tr></tbody></table>'\n    )\n  })\n\n  await t.test('should support a table (GFM; w/ align)', function () {\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children={'| a | b | c | d |\\n| :- | :-: | -: | - |'}\n          remarkPlugins={[remarkGfm]}\n        />\n      ),\n      '<table><thead><tr><th style=\"text-align:left\">a</th><th style=\"text-align:center\">b</th><th style=\"text-align:right\">c</th><th>d</th></tr></thead></table>'\n    )\n  })\n\n  await t.test('should support a thematic break', function () {\n    assert.equal(renderToStaticMarkup(<Markdown children=\"***\" />), '<hr/>')\n  })\n\n  await t.test('should support ab absolute path', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"[](/a)\" />),\n      '<p><a href=\"/a\"></a></p>'\n    )\n  })\n\n  await t.test('should support an absolute URL', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"[](http://a.com)\" />),\n      '<p><a href=\"http://a.com\"></a></p>'\n    )\n  })\n\n  await t.test('should support a URL w/ uppercase protocol', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"[](HTTPS://A.COM)\" />),\n      '<p><a href=\"HTTPS://A.COM\"></a></p>'\n    )\n  })\n\n  await t.test('should make a `javascript:` URL safe', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"[](javascript:alert(1))\" />),\n      '<p><a href=\"\"></a></p>'\n    )\n  })\n\n  await t.test('should make a `vbscript:` URL safe', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"[](vbscript:alert(1))\" />),\n      '<p><a href=\"\"></a></p>'\n    )\n  })\n\n  await t.test('should make a `VBSCRIPT:` URL safe', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"[](VBSCRIPT:alert(1))\" />),\n      '<p><a href=\"\"></a></p>'\n    )\n  })\n\n  await t.test('should make a `file:` URL safe', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"[](file:///etc/passwd)\" />),\n      '<p><a href=\"\"></a></p>'\n    )\n  })\n\n  await t.test('should allow an empty URL', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"[]()\" />),\n      '<p><a href=\"\"></a></p>'\n    )\n  })\n\n  await t.test('should support search (`?`) in a URL', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"[](a?javascript:alert(1))\" />),\n      '<p><a href=\"a?javascript:alert(1)\"></a></p>'\n    )\n  })\n\n  await t.test('should support hash (`&`) in a URL', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"[](a?b&c=d)\" />),\n      '<p><a href=\"a?b&amp;c=d\"></a></p>'\n    )\n  })\n\n  await t.test('should support hash (`#`) in a URL', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"[](a#javascript:alert(1))\" />),\n      '<p><a href=\"a#javascript:alert(1)\"></a></p>'\n    )\n  })\n\n  await t.test('should support `urlTransform` (`href` on `a`)', function () {\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children=\"[a](https://b.com 'c')\"\n          urlTransform={function (url, key, node) {\n            assert.equal(url, 'https://b.com')\n            assert.equal(key, 'href')\n            assert.equal(node.tagName, 'a')\n            return ''\n          }}\n        />\n      ),\n      '<p><a href=\"\" title=\"c\">a</a></p>'\n    )\n  })\n\n  await t.test('should support `urlTransform` w/ empty URLs', function () {\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children=\"[]()\"\n          urlTransform={function (url, key, node) {\n            assert.equal(url, '')\n            assert.equal(key, 'href')\n            assert.equal(node.tagName, 'a')\n            return ''\n          }}\n        />\n      ),\n      '<p><a href=\"\"></a></p>'\n    )\n  })\n\n  await t.test('should support `urlTransform` (`src` on `img`)', function () {\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children=\"![a](https://b.com 'c')\"\n          urlTransform={function (url, key, node) {\n            assert.equal(url, 'https://b.com')\n            assert.equal(key, 'src')\n            assert.equal(node.tagName, 'img')\n            return null\n          }}\n        />\n      ),\n      '<p><img alt=\"a\" title=\"c\"/></p>'\n    )\n  })\n\n  await t.test('should support `skipHtml`', function () {\n    const actual = renderToStaticMarkup(\n      <Markdown children=\"a<i>b</i>c\" skipHtml />\n    )\n    assert.equal(actual, '<p>abc</p>')\n  })\n\n  await t.test(\n    'should support `allowedElements` (drop unlisted nodes)',\n    function () {\n      assert.equal(\n        renderToStaticMarkup(\n          <Markdown\n            children={'# *a*\\n* b'}\n            allowedElements={['h1', 'li', 'ul']}\n          />\n        ),\n        '<h1></h1>\\n<ul>\\n<li>b</li>\\n</ul>'\n      )\n    }\n  )\n\n  await t.test('should support `allowedElements` as a function', function () {\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children=\"*a* **b**\"\n          allowElement={function (element) {\n            return element.tagName !== 'em'\n          }}\n        />\n      ),\n      '<p> <strong>b</strong></p>'\n    )\n  })\n  await t.test('should support `disallowedElements`', function () {\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown children={'# *a*\\n* b'} disallowedElements={['em']} />\n      ),\n      '<h1></h1>\\n<ul>\\n<li>b</li>\\n</ul>'\n    )\n  })\n\n  await t.test(\n    'should fail for both `allowedElements` and `disallowedElements`',\n    function () {\n      assert.throws(function () {\n        renderToStaticMarkup(\n          <Markdown\n            children=\"\"\n            allowedElements={['p']}\n            disallowedElements={['a']}\n          />\n        )\n      }, /Unexpected combined `allowedElements` and `disallowedElements`, expected one or the other/)\n    }\n  )\n\n  await t.test(\n    'should support `unwrapDisallowed` w/ `allowedElements`',\n    function () {\n      assert.equal(\n        renderToStaticMarkup(\n          <Markdown\n            children=\"# *a*\"\n            unwrapDisallowed\n            allowedElements={['h1']}\n          />\n        ),\n        '<h1>a</h1>'\n      )\n    }\n  )\n\n  await t.test(\n    'should support `unwrapDisallowed` w/ `disallowedElements`',\n    function () {\n      assert.equal(\n        renderToStaticMarkup(\n          <Markdown\n            children=\"# *a*\"\n            unwrapDisallowed\n            disallowedElements={['em']}\n          />\n        ),\n        '<h1>a</h1>'\n      )\n    }\n  )\n\n  await t.test('should support `remarkRehypeOptions`', function () {\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children={'[^x]\\n\\n[^x]: a\\n\\n'}\n          remarkPlugins={[remarkGfm]}\n          remarkRehypeOptions={{clobberPrefix: 'b-'}}\n        />\n      ),\n      '<p><sup><a href=\"#b-fn-x\" id=\"b-fnref-x\" data-footnote-ref=\"true\" aria-describedby=\"footnote-label\">1</a></sup></p>\\n<section data-footnotes=\"true\" class=\"footnotes\"><h2 class=\"sr-only\" id=\"footnote-label\">Footnotes</h2>\\n<ol>\\n<li id=\"b-fn-x\">\\n<p>a <a href=\"#b-fnref-x\" data-footnote-backref=\"\" aria-label=\"Back to reference 1\" class=\"data-footnote-backref\">↩</a></p>\\n</li>\\n</ol>\\n</section>'\n    )\n  })\n\n  await t.test('should support `components`', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"# a\" components={{h1: 'h2'}} />),\n      '<h2>a</h2>'\n    )\n  })\n\n  await t.test('should support `components` as functions', function () {\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children=\"a\"\n          components={{\n            p(props) {\n              const {node, ...rest} = props\n              assert.deepEqual(rest, {children: 'a'})\n              return <div {...rest} />\n            }\n          }}\n        />\n      ),\n      '<div>a</div>'\n    )\n  })\n\n  await t.test('should fail on an invalid component', function () {\n    assert.throws(function () {\n      renderToStaticMarkup(\n        <Markdown\n          children=\"# a\"\n          components={{\n            // @ts-expect-error: check how the runtime handles an invalid component.\n            h1: 123\n          }}\n        />\n      )\n    }, /Element type is invalid/)\n  })\n\n  await t.test('should support `components` (headings)', function () {\n    let calls = 0\n\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children={'# a\\n## b'}\n          components={{h1: heading, h2: heading}}\n        />\n      ),\n      '<h1>a</h1>\\n<h2>b</h2>'\n    )\n\n    assert.equal(calls, 2)\n\n    /**\n     * @param {ComponentProps<'h1'> & ExtraProps} props\n     */\n    function heading(props) {\n      const {node, ...rest} = props\n      assert(node)\n      assert(node.tagName === 'h1' || node.tagName === 'h2')\n      calls++\n      return <node.tagName {...rest} />\n    }\n  })\n\n  await t.test('should support `components` (code)', function () {\n    let calls = 0\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children={'```\\na\\n```\\n\\n\\tb\\n\\n`c`'}\n          components={{\n            code(props) {\n              const {node, ...rest} = props\n              assert(node)\n              assert(node.tagName === 'code')\n              calls++\n              return <code {...rest} />\n            }\n          }}\n        />\n      ),\n      '<pre><code>a\\n</code></pre>\\n<pre><code>b\\n</code></pre>\\n<p><code>c</code></p>'\n    )\n\n    assert.equal(calls, 3)\n  })\n\n  await t.test('should support `components` (li)', function () {\n    let calls = 0\n\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children={'* [x] a\\n1. b'}\n          components={{\n            li(props) {\n              const {node, ...rest} = props\n              assert(node)\n              assert(node.tagName === 'li')\n              calls++\n              return <li {...rest} />\n            }\n          }}\n          remarkPlugins={[remarkGfm]}\n        />\n      ),\n      '<ul class=\"contains-task-list\">\\n<li class=\"task-list-item\"><input type=\"checkbox\" disabled=\"\" checked=\"\"/> a</li>\\n</ul>\\n<ol>\\n<li>b</li>\\n</ol>'\n    )\n\n    assert.equal(calls, 2)\n  })\n\n  await t.test('should support `components` (ol)', function () {\n    let calls = 0\n\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children=\"1. a\"\n          components={{\n            ol(props) {\n              const {node, ...rest} = props\n              assert(node)\n              assert(node.tagName === 'ol')\n              calls++\n              return <ol {...rest} />\n            }\n          }}\n        />\n      ),\n      '<ol>\\n<li>a</li>\\n</ol>'\n    )\n\n    assert.equal(calls, 1)\n  })\n\n  await t.test('should support `components` (ul)', function () {\n    let calls = 0\n\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children=\"* a\"\n          components={{\n            ul(props) {\n              const {node, ...rest} = props\n              assert(node)\n              assert(node.tagName === 'ul')\n              calls++\n              return <ul {...rest} />\n            }\n          }}\n        />\n      ),\n      '<ul>\\n<li>a</li>\\n</ul>'\n    )\n\n    assert.equal(calls, 1)\n  })\n\n  await t.test('should support `components` (tr)', function () {\n    let calls = 0\n\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children={'|a|\\n|-|\\n|b|'}\n          components={{\n            tr(props) {\n              const {node, ...rest} = props\n              assert(node)\n              assert(node.tagName === 'tr')\n              calls++\n              return <tr {...rest} />\n            }\n          }}\n          remarkPlugins={[remarkGfm]}\n        />\n      ),\n      '<table><thead><tr><th>a</th></tr></thead><tbody><tr><td>b</td></tr></tbody></table>'\n    )\n\n    assert.equal(calls, 2)\n  })\n\n  await t.test('should support `components` (td, th)', function () {\n    let tdCalls = 0\n    let thCalls = 0\n\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children={'|a|\\n|-|\\n|b|'}\n          components={{\n            td(props) {\n              const {node, ...rest} = props\n              assert(node)\n              assert(node.tagName === 'td')\n              tdCalls++\n              return <td {...rest} />\n            },\n            th(props) {\n              const {node, ...rest} = props\n              assert(node)\n              assert(node.tagName === 'th')\n              thCalls++\n              return <th {...rest} />\n            }\n          }}\n          remarkPlugins={[remarkGfm]}\n        />\n      ),\n      '<table><thead><tr><th>a</th></tr></thead><tbody><tr><td>b</td></tr></tbody></table>'\n    )\n\n    assert.equal(tdCalls, 1)\n    assert.equal(thCalls, 1)\n  })\n\n  await t.test('should pass `node` to components', function () {\n    let calls = 0\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children=\"*a*\"\n          components={{\n            em(props) {\n              const {node, ...rest} = props\n              assert.deepEqual(node, {\n                type: 'element',\n                tagName: 'em',\n                properties: {},\n                children: [\n                  {\n                    type: 'text',\n                    value: 'a',\n                    position: {\n                      start: {line: 1, column: 2, offset: 1},\n                      end: {line: 1, column: 3, offset: 2}\n                    }\n                  }\n                ],\n                position: {\n                  start: {line: 1, column: 1, offset: 0},\n                  end: {line: 1, column: 4, offset: 3}\n                }\n              })\n              calls++\n              return <em {...rest} />\n            }\n          }}\n        />\n      ),\n      '<p><em>a</em></p>'\n    )\n\n    assert.equal(calls, 1)\n  })\n\n  await t.test('should support plugins (`remark-gfm`)', function () {\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown children=\"a ~b~ c\" remarkPlugins={[remarkGfm]} />\n      ),\n      '<p>a <del>b</del> c</p>'\n    )\n  })\n\n  await t.test('should support plugins (`remark-toc`)', function () {\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children={'# a\\n## Contents\\n## b\\n### c\\n## d'}\n          remarkPlugins={[remarkToc]}\n        />\n      ),\n      `<h1>a</h1>\n<h2>Contents</h2>\n<ul>\n<li><a href=\"#b\">b</a>\n<ul>\n<li><a href=\"#c\">c</a></li>\n</ul>\n</li>\n<li><a href=\"#d\">d</a></li>\n</ul>\n<h2>b</h2>\n<h3>c</h3>\n<h2>d</h2>`\n    )\n  })\n\n  await t.test('should support aria properties', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"c\" rehypePlugins={[plugin]} />),\n      '<input id=\"a\" aria-describedby=\"b\" required=\"\"/><p>c</p>'\n    )\n\n    function plugin() {\n      /**\n       * @param {Root} tree\n       * @returns {undefined}\n       */\n      return function (tree) {\n        tree.children.unshift({\n          type: 'element',\n          tagName: 'input',\n          properties: {id: 'a', ariaDescribedBy: 'b', required: true},\n          children: []\n        })\n      }\n    }\n  })\n\n  await t.test('should support data properties', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"b\" rehypePlugins={[plugin]} />),\n      '<i data-whatever=\"a\"></i><p>b</p>'\n    )\n\n    function plugin() {\n      /**\n       * @param {Root} tree\n       * @returns {undefined}\n       */\n      return function (tree) {\n        tree.children.unshift({\n          type: 'element',\n          tagName: 'i',\n          properties: {dataWhatever: 'a', dataIgnoreThis: undefined},\n          children: []\n        })\n      }\n    }\n  })\n\n  await t.test('should support comma separated properties', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"c\" rehypePlugins={[plugin]} />),\n      '<i accept=\"a, b\"></i><p>c</p>'\n    )\n\n    function plugin() {\n      /**\n       * @param {Root} tree\n       * @returns {undefined}\n       */\n      return function (tree) {\n        tree.children.unshift({\n          type: 'element',\n          tagName: 'i',\n          properties: {accept: ['a', 'b']},\n          children: []\n        })\n      }\n    }\n  })\n\n  await t.test('should support `style` properties', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"a\" rehypePlugins={[plugin]} />),\n      '<i style=\"color:red;font-weight:bold\"></i><p>a</p>'\n    )\n\n    function plugin() {\n      /**\n       * @param {Root} tree\n       * @returns {undefined}\n       */\n      return function (tree) {\n        tree.children.unshift({\n          type: 'element',\n          tagName: 'i',\n          properties: {style: 'color: red; font-weight: bold'},\n          children: []\n        })\n      }\n    }\n  })\n\n  await t.test(\n    'should support `style` properties w/ vendor prefixes',\n    function () {\n      assert.equal(\n        renderToStaticMarkup(\n          <Markdown children=\"a\" rehypePlugins={[plugin]} />\n        ),\n        '<i style=\"-ms-b:1;-webkit-c:2\"></i><p>a</p>'\n      )\n\n      function plugin() {\n        /**\n         * @param {Root} tree\n         * @returns {undefined}\n         */\n        return function (tree) {\n          tree.children.unshift({\n            type: 'element',\n            tagName: 'i',\n            properties: {style: '-ms-b: 1; -webkit-c: 2'},\n            children: []\n          })\n        }\n      }\n    }\n  )\n\n  await t.test('should support broken `style` properties', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"a\" rehypePlugins={[plugin]} />),\n      '<i></i><p>a</p>'\n    )\n\n    function plugin() {\n      /**\n       * @param {Root} tree\n       * @returns {undefined}\n       */\n      return function (tree) {\n        tree.children.unshift({\n          type: 'element',\n          tagName: 'i',\n          properties: {style: 'broken'},\n          children: []\n        })\n      }\n    }\n  })\n\n  await t.test('should support SVG elements', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"a\" rehypePlugins={[plugin]} />),\n      '<svg viewBox=\"0 0 500 500\" xmlns=\"http://www.w3.org/2000/svg\"><title>SVG `&lt;circle&gt;` element</title><circle cx=\"120\" cy=\"120\" r=\"100\"></circle><path stroke-miterlimit=\"-1\"></path></svg><p>a</p>'\n    )\n\n    function plugin() {\n      /**\n       * @param {Root} tree\n       * @returns {undefined}\n       */\n      return function (tree) {\n        tree.children.unshift({\n          type: 'element',\n          tagName: 'svg',\n          properties: {\n            viewBox: '0 0 500 500',\n            xmlns: 'http://www.w3.org/2000/svg'\n          },\n          children: [\n            {\n              type: 'element',\n              tagName: 'title',\n              properties: {},\n              children: [{type: 'text', value: 'SVG `<circle>` element'}]\n            },\n            {\n              type: 'element',\n              tagName: 'circle',\n              properties: {cx: 120, cy: 120, r: 100},\n              children: []\n            },\n            // `strokeMiterLimit` in hast, `strokeMiterlimit` in React.\n            {\n              type: 'element',\n              tagName: 'path',\n              properties: {strokeMiterLimit: -1},\n              children: []\n            }\n          ]\n        })\n      }\n    }\n  })\n\n  await t.test('should support comments (ignore them)', function () {\n    const input = 'a'\n    const actual = renderToStaticMarkup(\n      <Markdown children={input} rehypePlugins={[plugin]} />\n    )\n    const expected = '<p>a</p>'\n    assert.equal(actual, expected)\n\n    function plugin() {\n      /**\n       * @param {Root} tree\n       * @returns {undefined}\n       */\n      return function (tree) {\n        tree.children.unshift({type: 'comment', value: 'things!'})\n      }\n    }\n  })\n\n  await t.test('should support table cells w/ style', function () {\n    assert.equal(\n      renderToStaticMarkup(\n        <Markdown\n          children={'| a  |\\n| :- |'}\n          remarkPlugins={[remarkGfm]}\n          rehypePlugins={[plugin]}\n        />\n      ),\n      '<table><thead><tr><th style=\"color:red;text-align:left\">a</th></tr></thead></table>'\n    )\n\n    function plugin() {\n      /**\n       * @param {Root} tree\n       * @returns {undefined}\n       */\n      return function (tree) {\n        visit(tree, 'element', function (node) {\n          if (node.tagName === 'th') {\n            node.properties = {...node.properties, style: 'color: red'}\n          }\n        })\n      }\n    }\n  })\n\n  await t.test('should not fail on a plugin replacing `root`', function () {\n    assert.equal(\n      renderToStaticMarkup(<Markdown children=\"a\" rehypePlugins={[plugin]} />),\n      ''\n    )\n\n    function plugin() {\n      /**\n       * @returns {Root}\n       */\n      return function () {\n        // @ts-expect-error: check how non-roots are handled.\n        return {type: 'comment', value: 'things!'}\n      }\n    }\n  })\n})\n\ntest('MarkdownAsync', async function (t) {\n  await t.test('should support `MarkdownAsync` (1)', async function () {\n    assert.throws(function () {\n      renderToStaticMarkup(<MarkdownAsync children={'a'} />)\n    }, /A component suspended while responding to synchronous input/)\n  })\n\n  await t.test('should support `MarkdownAsync` (2)', async function () {\n    return new Promise(function (resolve, reject) {\n      renderToPipeableStream(<MarkdownAsync children={'a'} />)\n        .pipe(\n          concatStream({encoding: 'u8'}, function (data) {\n            assert.equal(decoder.decode(data), '<p>a</p>')\n            resolve()\n          })\n        )\n        .on('error', reject)\n    })\n  })\n\n  await t.test(\n    'should support async plugins w/ `MarkdownAsync` (`rehype-starry-night`)',\n    async function () {\n      return new Promise(function (resolve) {\n        renderToPipeableStream(\n          <MarkdownAsync\n            children={'```js\\nconsole.log(3.14)'}\n            rehypePlugins={[rehypeStarryNight]}\n          />\n        ).pipe(\n          concatStream({encoding: 'u8'}, function (data) {\n            assert.equal(\n              decoder.decode(data),\n              '<pre><code class=\"language-js\"><span class=\"pl-en\">console</span>.<span class=\"pl-c1\">log</span>(<span class=\"pl-c1\">3.14</span>)\\n</code></pre>'\n            )\n            resolve()\n          })\n        )\n      })\n    }\n  )\n})\n\n// Note: hooks are not supported on the “server”.\ntest('MarkdownHooks', async function (t) {\n  await t.test('should support `MarkdownHooks`', async function () {\n    const plugin = deferPlugin()\n    const result = render(\n      <MarkdownHooks children={'a'} rehypePlugins={[plugin.plugin]} />\n    )\n\n    assert.equal(result.container.innerHTML, '')\n\n    plugin.resolve()\n\n    await waitFor(function () {\n      assert.notEqual(result.container.innerHTML, '')\n    })\n\n    assert.equal(result.container.innerHTML, '<p>a</p>')\n  })\n\n  await t.test(\n    'should support async plugins w/ `MarkdownHooks` (`rehype-starry-night`)',\n    async function () {\n      const plugin = deferPlugin()\n      const result = render(\n        <MarkdownHooks\n          children={'```js\\nconsole.log(3.14)'}\n          rehypePlugins={[plugin.plugin, rehypeStarryNight]}\n        />\n      )\n\n      assert.equal(result.container.innerHTML, '')\n\n      plugin.resolve()\n\n      await waitFor(function () {\n        assert.notEqual(result.container.innerHTML, '')\n      })\n\n      assert.equal(\n        result.container.innerHTML,\n        '<pre><code class=\"language-js\"><span class=\"pl-en\">console</span>.<span class=\"pl-c1\">log</span>(<span class=\"pl-c1\">3.14</span>)\\n</code></pre>'\n      )\n    }\n  )\n\n  await t.test('should support `fallback`', async function () {\n    const plugin = deferPlugin()\n    const result = render(\n      <MarkdownHooks\n        children={'a'}\n        fallback=\"Loading\"\n        rehypePlugins={[plugin.plugin]}\n      />\n    )\n\n    assert.equal(result.container.innerHTML, 'Loading')\n\n    plugin.resolve()\n\n    await waitFor(function () {\n      assert.notEqual(result.container.innerHTML, 'Loading')\n    })\n\n    assert.equal(result.container.innerHTML, '<p>a</p>')\n  })\n\n  await t.test('should support plugins that error', async function () {\n    const plugin = deferPlugin()\n    const result = render(\n      <ErrorBoundary>\n        <MarkdownHooks children={'a'} rehypePlugins={[plugin.plugin]} />\n      </ErrorBoundary>\n    )\n\n    assert.equal(result.container.innerHTML, '')\n\n    console.info('\\nNote: the below error (`Error: rejected`) is expected.\\n')\n\n    plugin.reject(new Error('rejected'))\n\n    await waitFor(function () {\n      assert.notEqual(result.container.innerHTML, '')\n    })\n\n    console.info('Note: the above error (`Error: rejected`) was expected.')\n\n    assert.equal(result.container.innerHTML, 'Error: rejected')\n  })\n\n  await t.test('should support rerenders', async function () {\n    const pluginA = deferPlugin()\n    const pluginB = deferPlugin()\n\n    const result = render(\n      <MarkdownHooks children={'a'} rehypePlugins={[pluginA.plugin]} />\n    )\n\n    assert.equal(result.container.innerHTML, '')\n\n    result.rerender(\n      <MarkdownHooks children={'b'} rehypePlugins={[pluginB.plugin]} />\n    )\n\n    assert.equal(result.container.innerHTML, '')\n\n    pluginA.resolve()\n    pluginB.resolve()\n\n    await waitFor(function () {\n      assert.notEqual(result.container.innerHTML, '')\n    })\n\n    assert.equal(result.container.innerHTML, '<p>b</p>')\n  })\n})\n\n/**\n * Create an async unified plugin that waits until a promise is resolved or\n * rejected from the outside.\n *\n * @returns {DeferredPlugin}\n *   Deferred plugin object.\n */\nfunction deferPlugin() {\n  /** @type {(error: Error) => void} */\n  let hoistedReject\n  /** @type {() => void} */\n  let hoistedResolve\n  /** @type {Promise<void>} */\n  const promise = new Promise(function (resolve, reject) {\n    hoistedResolve = resolve\n    hoistedReject = reject\n  })\n\n  return {\n    plugin() {\n      return function () {\n        return promise\n      }\n    },\n    reject(error) {\n      hoistedReject(error)\n    },\n    resolve() {\n      hoistedResolve()\n    }\n  }\n}\n\n/**\n * Basic error boundary.\n */\nclass ErrorBoundary extends Component {\n  /**\n   * @param {Error} error\n   *   Error.\n   * @returns {undefined}\n   *   Nothing.\n   */\n  componentDidCatch(error) {\n    this.setState({error})\n  }\n\n  render() {\n    const props = /** @type {{children: ReactNode}} */ (this.props)\n\n    return this.state.error ? String(this.state.error) : props.children\n  }\n\n  state = {\n    /**\n     * @type {Error | undefined}\n     *   Error.\n     */\n    error: undefined\n  }\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"checkJs\": true,\n    \"customConditions\": [\"development\"],\n    \"declarationMap\": true,\n    \"declaration\": true,\n    \"emitDeclarationOnly\": true,\n    \"exactOptionalPropertyTypes\": true,\n    \"jsx\": \"preserve\",\n    \"lib\": [\"dom\", \"es2022\"],\n    \"module\": \"node16\",\n    \"strict\": true,\n    \"target\": \"es2022\"\n  },\n  \"exclude\": [\"coverage/\", \"node_modules/\"],\n  \"include\": [\"**/*.js\", \"**/*.jsx\"]\n}\n"
  }
]