diff --git a/.c8rc.json b/.c8rc.json
new file mode 100644
index 0000000..51d1e5e
--- /dev/null
+++ b/.c8rc.json
@@ -0,0 +1,4 @@
+{
+ "100": true,
+ "reporter": ["html", "lcov", "text"]
+}
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..2e84a5d
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,13 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_size = 2
+indent_style = space
+insert_final_newline = true
+max_line_length = 100
+trim_trailing_whitespace = true
+
+[COMMIT_EDITMSG]
+max_line_length = 72
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..a21bee8
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1 @@
+*.jsx
diff --git a/.eslintrc.yaml b/.eslintrc.yaml
new file mode 100644
index 0000000..062a2d6
--- /dev/null
+++ b/.eslintrc.yaml
@@ -0,0 +1,6 @@
+root: true
+extends:
+ - remcohaszing
+rules:
+ no-param-reassign: off
+ import/no-extraneous-dependencies: off
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
new file mode 100644
index 0000000..47debe7
--- /dev/null
+++ b/.github/workflows/ci.yaml
@@ -0,0 +1,79 @@
+name: ci
+
+on:
+ pull_request:
+ push:
+ branches: [main]
+ tags: ['*']
+
+jobs:
+ eslint:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ - run: npm ci
+ - run: npx eslint .
+
+ pack:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ - run: npm ci
+ - run: npm pack
+ - uses: actions/upload-artifact@v4
+ with:
+ name: package
+ path: '*.tgz'
+
+ test:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ node-version:
+ - 18
+ - 20
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: ${{ matrix.node-version }}
+ - run: npm install --global npm@latest
+ - run: npm ci
+ - run: npm test
+ - uses: codecov/codecov-action@v4
+ if: ${{ matrix.node-version == 20 }}
+
+ prettier:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ - run: npm ci
+ - run: npx prettier --check .
+
+ release:
+ runs-on: ubuntu-latest
+ needs:
+ - eslint
+ - test
+ - pack
+ - prettier
+ if: startsWith(github.ref, 'refs/tags/')
+ steps:
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ registry-url: https://registry.npmjs.org
+ - uses: actions/download-artifact@v4
+ with: { name: package }
+ - run: npm publish *.tgz --access public
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..30b9ac7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+coverage/
+dist/
+node_modules/
+*.tsbuildinfo
+*.log
+*.tgz
diff --git a/.prettierrc.yaml b/.prettierrc.yaml
new file mode 100644
index 0000000..b3732ec
--- /dev/null
+++ b/.prettierrc.yaml
@@ -0,0 +1,4 @@
+proseWrap: always
+semi: false
+singleQuote: true
+trailingComma: none
diff --git a/.remarkignore b/.remarkignore
new file mode 100644
index 0000000..67fc140
--- /dev/null
+++ b/.remarkignore
@@ -0,0 +1 @@
+fixtures/
diff --git a/.remarkrc.yaml b/.remarkrc.yaml
new file mode 100644
index 0000000..101cb46
--- /dev/null
+++ b/.remarkrc.yaml
@@ -0,0 +1,2 @@
+plugins:
+ - remark-preset-remcohaszing
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..1d4316d
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,18 @@
+# MIT License
+
+Copyright © 2024 Remco Haszing
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the “Software”), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial
+portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f55b52b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,109 @@
+# rehype-mdx-import-media
+
+[![github actions](https://github.com/remcohaszing/rehype-mdx-import-media/actions/workflows/ci.yaml/badge.svg)](https://github.com/remcohaszing/rehype-mdx-import-media/actions/workflows/ci.yaml)
+[![codecov](https://codecov.io/gh/remcohaszing/rehype-mdx-import-media/branch/main/graph/badge.svg)](https://codecov.io/gh/remcohaszing/rehype-mdx-import-media)
+[![npm version](https://img.shields.io/npm/v/rehype-mdx-import-media)](https://www.npmjs.com/package/rehype-mdx-import-media)
+[![npm downloads](https://img.shields.io/npm/dm/rehype-mdx-import-media)](https://www.npmjs.com/package/rehype-mdx-import-media)
+
+An [MDX](https://mdxjs.com) [rehype](https://github.com/rehypejs/rehype) plugin for turning media
+paths into imports.
+
+## Table of Contents
+
+- [Installation](#installation)
+- [Usage](#usage)
+- [API](#api)
+ - [Options](#options)
+- [Compatibility](#compatibility)
+- [License](#license)
+
+## Installation
+
+```sh
+npm install rehype-mdx-import-media
+```
+
+## Usage
+
+This plugin takes HTML elements that refer to media content, and turns them into MDX expressions
+that use imports. This allows bundlers to resolve media you referenced from your code. Note that JSX
+elements are **not** HTML elements, so they are not processed. HTML elements can come from:
+
+- Markdown syntax in MDX files, such as images.
+- HTML in files parsed using the `md` [format](https://mdxjs.com/packages/mdx/#processoroptions)
+ when using [`rehype-raw`](https://github.com/rehypejs/rehype-raw)
+- Custom remark / rehype plugins.
+
+If this plugin finds an attribute to process, it transforms the
+[hast](https://github.com/syntax-tree/hast) [`element`](https://github.com/syntax-tree/hast#element)
+nodes into an
+[`mdxJsxFlowElement`](https://github.com/syntax-tree/mdast-util-mdx-jsx#mdxjsxflowelementhast) node.
+This may prevent other rehype plugins from further processing. To avoid this, put
+`rehype-mdx-import-media` after any other rehype plugins
+
+For example, given a file named `example.mdx` with the following contents:
+
+```mdx
+![](./image.png)
+```
+
+The following script:
+
+```js
+import { compile } from '@mdx-js/mdx'
+import rehypeMdxImportMedia from 'rehype-mdx-import-media'
+import { read } from 'to-vfile'
+
+const { value } = await compile(await read('example.mdx'), {
+ jsx: true,
+ rehypePlugins: [rehypeMdxImportMedia]
+})
+console.log(value)
+```
+
+Roughly yields:
+
+```jsx
+import _rehypeMdxImportMedia0 from './image.png'
+
+export default function MDXContent() {
+ return (
+
+
+
+ )
+}
+```
+
+## API
+
+The default export is a [rehype](https://github.com/rehypejs/rehype) plugin.
+
+### Options
+
+- `attributes` (`object`): HTML element attributes that should be processed. The key is the HTML
+ element tag name. The value is a list of attribute names to process. The default attributes are:
+ - [`audio[src]`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio#src)
+ - [`embed[src]`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/embed#src)
+ - [`img[src]`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#src)
+ - [`img[srcset]`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#srcset)
+ - [`object[data]`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/object#data)
+ - [`source[src]`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source#src)
+ - [`source[srcset]`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source#srcset)
+ - [`track[src]`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/track#src)
+ - [`video[poster]`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#poster)
+ - [`video[src]`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#src)
+- `elementAttributeNameCase` (`'html' | 'react'`): The casing to use for attribute names. This
+ should match the elementAttributeNameCase value passed to MDX. (Default: `'react'`)
+- `resolve` (`boolean`): By default imports are resolved relative to the markdown file. This matches
+ default markdown behaviour. If this is set to false, this behaviour is removed and URLs are no
+ longer processed. This allows to import images from `node_modules`. If this is disabled, local
+ images can still be imported by prepending the path with `./.`. (Default: `true`).
+
+## Compatibility
+
+This project is compatible with MDX 3 and Node.js 18 or greater.
+
+## License
+
+[MIT](LICENSE.md) © [Remco Haszing](https://github.com/remcohaszing)
diff --git a/fixtures/alt/expected.jsx b/fixtures/alt/expected.jsx
new file mode 100644
index 0000000..5cc474d
--- /dev/null
+++ b/fixtures/alt/expected.jsx
@@ -0,0 +1,25 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+import _rehypeMdxImportMedia0 from './image.png'
+function _createMdxContent(props) {
+ const _components = {
+ img: 'img',
+ p: 'p',
+ ...props.components
+ }
+ return (
+ <_components.p>
+ <_components.img src={_rehypeMdxImportMedia0} alt="Alt text" />
+
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/alt/input.md b/fixtures/alt/input.md
new file mode 100644
index 0000000..dda1ad9
--- /dev/null
+++ b/fixtures/alt/input.md
@@ -0,0 +1 @@
+![Alt text](image.png)
diff --git a/fixtures/alt/options.json b/fixtures/alt/options.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/fixtures/alt/options.json
@@ -0,0 +1 @@
+{}
diff --git a/fixtures/custom-attributes/expected.jsx b/fixtures/custom-attributes/expected.jsx
new file mode 100644
index 0000000..9ac15bc
--- /dev/null
+++ b/fixtures/custom-attributes/expected.jsx
@@ -0,0 +1,30 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+import _rehypeMdxImportMedia0 from './script.js'
+function _createMdxContent(props) {
+ const _components = {
+ img: 'img',
+ p: 'p',
+ script: 'script',
+ ...props.components
+ }
+ return (
+ <>
+ <_components.p>
+ <_components.img src="./hello.png" alt="" />
+
+ {'\n'}
+ <_components.script src={_rehypeMdxImportMedia0} />
+ >
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/custom-attributes/input.md b/fixtures/custom-attributes/input.md
new file mode 100644
index 0000000..7d56858
--- /dev/null
+++ b/fixtures/custom-attributes/input.md
@@ -0,0 +1,3 @@
+![](./hello.png)
+
+
diff --git a/fixtures/custom-attributes/options.json b/fixtures/custom-attributes/options.json
new file mode 100644
index 0000000..939d895
--- /dev/null
+++ b/fixtures/custom-attributes/options.json
@@ -0,0 +1,5 @@
+{
+ "attributes": {
+ "script": "src"
+ }
+}
diff --git a/fixtures/duplicate/expected.jsx b/fixtures/duplicate/expected.jsx
new file mode 100644
index 0000000..ebaff61
--- /dev/null
+++ b/fixtures/duplicate/expected.jsx
@@ -0,0 +1,40 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+import _rehypeMdxImportMedia0 from './image.png'
+import _rehypeMdxImportMedia1 from './image.jpg'
+function _createMdxContent(props) {
+ const _components = {
+ img: 'img',
+ p: 'p',
+ ...props.components
+ }
+ return (
+ <>
+ <_components.p>
+ <_components.img src={_rehypeMdxImportMedia0} alt="" />
+
+ {'\n'}
+ <_components.p>
+ <_components.img src={_rehypeMdxImportMedia0} alt="" />
+
+ {'\n'}
+ <_components.p>
+ <_components.img src={_rehypeMdxImportMedia1} alt="" />
+
+ {'\n'}
+ <_components.p>
+ <_components.img src={_rehypeMdxImportMedia1} alt="" />
+
+ >
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/duplicate/input.md b/fixtures/duplicate/input.md
new file mode 100644
index 0000000..78e82e8
--- /dev/null
+++ b/fixtures/duplicate/input.md
@@ -0,0 +1,7 @@
+![](image.png)
+
+![](image.png)
+
+![](image.jpg)
+
+![](image.jpg)
diff --git a/fixtures/duplicate/options.json b/fixtures/duplicate/options.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/fixtures/duplicate/options.json
@@ -0,0 +1 @@
+{}
diff --git a/fixtures/external-http/expected.jsx b/fixtures/external-http/expected.jsx
new file mode 100644
index 0000000..50ecfd0
--- /dev/null
+++ b/fixtures/external-http/expected.jsx
@@ -0,0 +1,24 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+function _createMdxContent(props) {
+ const _components = {
+ img: 'img',
+ p: 'p',
+ ...props.components
+ }
+ return (
+ <_components.p>
+ <_components.img src="http://mdx-logo.now.sh" alt="" />
+
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/external-http/input.md b/fixtures/external-http/input.md
new file mode 100644
index 0000000..ccee328
--- /dev/null
+++ b/fixtures/external-http/input.md
@@ -0,0 +1 @@
+![](http://mdx-logo.now.sh)
diff --git a/fixtures/external-http/options.json b/fixtures/external-http/options.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/fixtures/external-http/options.json
@@ -0,0 +1 @@
+{}
diff --git a/fixtures/external-https/expected.jsx b/fixtures/external-https/expected.jsx
new file mode 100644
index 0000000..9dbc87d
--- /dev/null
+++ b/fixtures/external-https/expected.jsx
@@ -0,0 +1,24 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+function _createMdxContent(props) {
+ const _components = {
+ img: 'img',
+ p: 'p',
+ ...props.components
+ }
+ return (
+ <_components.p>
+ <_components.img src="https://mdx-logo.now.sh" alt="" />
+
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/external-https/input.md b/fixtures/external-https/input.md
new file mode 100644
index 0000000..5791e18
--- /dev/null
+++ b/fixtures/external-https/input.md
@@ -0,0 +1 @@
+![](https://mdx-logo.now.sh)
diff --git a/fixtures/external-https/options.json b/fixtures/external-https/options.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/fixtures/external-https/options.json
@@ -0,0 +1 @@
+{}
diff --git a/fixtures/external-without-protocol/expected.jsx b/fixtures/external-without-protocol/expected.jsx
new file mode 100644
index 0000000..3d367e0
--- /dev/null
+++ b/fixtures/external-without-protocol/expected.jsx
@@ -0,0 +1,24 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+function _createMdxContent(props) {
+ const _components = {
+ img: 'img',
+ p: 'p',
+ ...props.components
+ }
+ return (
+ <_components.p>
+ <_components.img src="//mdx-logo.now.sh" alt="" />
+
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/external-without-protocol/input.md b/fixtures/external-without-protocol/input.md
new file mode 100644
index 0000000..338b0ea
--- /dev/null
+++ b/fixtures/external-without-protocol/input.md
@@ -0,0 +1 @@
+![](//mdx-logo.now.sh)
diff --git a/fixtures/external-without-protocol/options.json b/fixtures/external-without-protocol/options.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/fixtures/external-without-protocol/options.json
@@ -0,0 +1 @@
+{}
diff --git a/fixtures/html/expected.jsx b/fixtures/html/expected.jsx
new file mode 100644
index 0000000..738a060
--- /dev/null
+++ b/fixtures/html/expected.jsx
@@ -0,0 +1,39 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+import _rehypeMdxImportMedia0 from './image.png'
+import _rehypeMdxImportMedia1 from './other-image.png'
+function _createMdxContent(props) {
+ const _components = {
+ img: 'img',
+ picture: 'picture',
+ video: 'video',
+ ...props.components
+ }
+ return (
+ <>
+ <_components.img
+ srcSet={`${_rehypeMdxImportMedia0} 2x,${_rehypeMdxImportMedia0} 640w 480h,${_rehypeMdxImportMedia1}`}
+ />
+ {'\n'}
+ <_components.picture>
+ {'\n '}
+ <_components.img
+ srcSet={`${_rehypeMdxImportMedia0} 2x,${_rehypeMdxImportMedia0} 640w 480h,${_rehypeMdxImportMedia1}`}
+ />
+ {'\n'}
+
+ {'\n'}
+ <_components.video>{'\n'}
+ >
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/html/input.md b/fixtures/html/input.md
new file mode 100644
index 0000000..b80c197
--- /dev/null
+++ b/fixtures/html/input.md
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/fixtures/html/options.json b/fixtures/html/options.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/fixtures/html/options.json
@@ -0,0 +1 @@
+{}
diff --git a/fixtures/inline/expected.jsx b/fixtures/inline/expected.jsx
new file mode 100644
index 0000000..14c5c79
--- /dev/null
+++ b/fixtures/inline/expected.jsx
@@ -0,0 +1,27 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+import _rehypeMdxImportMedia0 from './image.png'
+function _createMdxContent(props) {
+ const _components = {
+ img: 'img',
+ p: 'p',
+ ...props.components
+ }
+ return (
+ <_components.p>
+ {'This is an inline image: '}
+ <_components.img src={_rehypeMdxImportMedia0} alt="" />
+ {'. See?'}
+
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/inline/input.md b/fixtures/inline/input.md
new file mode 100644
index 0000000..67ad1c6
--- /dev/null
+++ b/fixtures/inline/input.md
@@ -0,0 +1 @@
+This is an inline image: ![](image.png). See?
diff --git a/fixtures/inline/options.json b/fixtures/inline/options.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/fixtures/inline/options.json
@@ -0,0 +1 @@
+{}
diff --git a/fixtures/link/expected.jsx b/fixtures/link/expected.jsx
new file mode 100644
index 0000000..c4af3ce
--- /dev/null
+++ b/fixtures/link/expected.jsx
@@ -0,0 +1,28 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+import _rehypeMdxImportMedia0 from './image.png'
+function _createMdxContent(props) {
+ const _components = {
+ a: 'a',
+ img: 'img',
+ p: 'p',
+ ...props.components
+ }
+ return (
+ <_components.p>
+ <_components.a href="https://example.com">
+ <_components.img src={_rehypeMdxImportMedia0} alt="" />
+
+
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/link/input.md b/fixtures/link/input.md
new file mode 100644
index 0000000..325572b
--- /dev/null
+++ b/fixtures/link/input.md
@@ -0,0 +1 @@
+[![](image.png)](https://example.com)
diff --git a/fixtures/link/options.json b/fixtures/link/options.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/fixtures/link/options.json
@@ -0,0 +1 @@
+{}
diff --git a/fixtures/multiple/expected.jsx b/fixtures/multiple/expected.jsx
new file mode 100644
index 0000000..b7484f6
--- /dev/null
+++ b/fixtures/multiple/expected.jsx
@@ -0,0 +1,42 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+import _rehypeMdxImportMedia0 from './image.gif'
+import _rehypeMdxImportMedia1 from './image.jpg'
+import _rehypeMdxImportMedia2 from './image.png'
+import _rehypeMdxImportMedia3 from './image.svg'
+function _createMdxContent(props) {
+ const _components = {
+ img: 'img',
+ p: 'p',
+ ...props.components
+ }
+ return (
+ <>
+ <_components.p>
+ <_components.img src={_rehypeMdxImportMedia0} alt="" />
+
+ {'\n'}
+ <_components.p>
+ <_components.img src={_rehypeMdxImportMedia1} alt="" />
+
+ {'\n'}
+ <_components.p>
+ <_components.img src={_rehypeMdxImportMedia2} alt="" />
+
+ {'\n'}
+ <_components.p>
+ <_components.img src={_rehypeMdxImportMedia3} alt="" />
+
+ >
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/multiple/input.md b/fixtures/multiple/input.md
new file mode 100644
index 0000000..5bd7acc
--- /dev/null
+++ b/fixtures/multiple/input.md
@@ -0,0 +1,7 @@
+![](image.gif)
+
+![](image.jpg)
+
+![](image.png)
+
+![](image.svg)
diff --git a/fixtures/multiple/options.json b/fixtures/multiple/options.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/fixtures/multiple/options.json
@@ -0,0 +1 @@
+{}
diff --git a/fixtures/node-modules/expected.jsx b/fixtures/node-modules/expected.jsx
new file mode 100644
index 0000000..875bf26
--- /dev/null
+++ b/fixtures/node-modules/expected.jsx
@@ -0,0 +1,25 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+import _rehypeMdxImportMedia0 from '@browser-logos/chrome/chrome.png'
+function _createMdxContent(props) {
+ const _components = {
+ img: 'img',
+ p: 'p',
+ ...props.components
+ }
+ return (
+ <_components.p>
+ <_components.img src={_rehypeMdxImportMedia0} alt="" />
+
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/node-modules/input.md b/fixtures/node-modules/input.md
new file mode 100644
index 0000000..97a7dd3
--- /dev/null
+++ b/fixtures/node-modules/input.md
@@ -0,0 +1 @@
+![](@browser-logos/chrome/chrome.png)
diff --git a/fixtures/node-modules/options.json b/fixtures/node-modules/options.json
new file mode 100644
index 0000000..ac43285
--- /dev/null
+++ b/fixtures/node-modules/options.json
@@ -0,0 +1,3 @@
+{
+ "resolve": false
+}
diff --git a/fixtures/relative-grandparent/expected.jsx b/fixtures/relative-grandparent/expected.jsx
new file mode 100644
index 0000000..70111e2
--- /dev/null
+++ b/fixtures/relative-grandparent/expected.jsx
@@ -0,0 +1,25 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+import _rehypeMdxImportMedia0 from '../../image.png'
+function _createMdxContent(props) {
+ const _components = {
+ img: 'img',
+ p: 'p',
+ ...props.components
+ }
+ return (
+ <_components.p>
+ <_components.img src={_rehypeMdxImportMedia0} alt="" />
+
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/relative-grandparent/input.md b/fixtures/relative-grandparent/input.md
new file mode 100644
index 0000000..e99be5b
--- /dev/null
+++ b/fixtures/relative-grandparent/input.md
@@ -0,0 +1 @@
+![](../../image.png)
diff --git a/fixtures/relative-grandparent/options.json b/fixtures/relative-grandparent/options.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/fixtures/relative-grandparent/options.json
@@ -0,0 +1 @@
+{}
diff --git a/fixtures/relative-parent/expected.jsx b/fixtures/relative-parent/expected.jsx
new file mode 100644
index 0000000..f6f9064
--- /dev/null
+++ b/fixtures/relative-parent/expected.jsx
@@ -0,0 +1,25 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+import _rehypeMdxImportMedia0 from '../image.png'
+function _createMdxContent(props) {
+ const _components = {
+ img: 'img',
+ p: 'p',
+ ...props.components
+ }
+ return (
+ <_components.p>
+ <_components.img src={_rehypeMdxImportMedia0} alt="" />
+
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/relative-parent/input.md b/fixtures/relative-parent/input.md
new file mode 100644
index 0000000..9f12971
--- /dev/null
+++ b/fixtures/relative-parent/input.md
@@ -0,0 +1 @@
+![](../image.png)
diff --git a/fixtures/relative-parent/options.json b/fixtures/relative-parent/options.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/fixtures/relative-parent/options.json
@@ -0,0 +1 @@
+{}
diff --git a/fixtures/relative-sibling/expected.jsx b/fixtures/relative-sibling/expected.jsx
new file mode 100644
index 0000000..9b765d8
--- /dev/null
+++ b/fixtures/relative-sibling/expected.jsx
@@ -0,0 +1,25 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+import _rehypeMdxImportMedia0 from './image.png'
+function _createMdxContent(props) {
+ const _components = {
+ img: 'img',
+ p: 'p',
+ ...props.components
+ }
+ return (
+ <_components.p>
+ <_components.img src={_rehypeMdxImportMedia0} alt="" />
+
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/relative-sibling/input.md b/fixtures/relative-sibling/input.md
new file mode 100644
index 0000000..863eca9
--- /dev/null
+++ b/fixtures/relative-sibling/input.md
@@ -0,0 +1 @@
+![](./image.png)
diff --git a/fixtures/relative-sibling/options.json b/fixtures/relative-sibling/options.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/fixtures/relative-sibling/options.json
@@ -0,0 +1 @@
+{}
diff --git a/fixtures/relative-simple/expected.jsx b/fixtures/relative-simple/expected.jsx
new file mode 100644
index 0000000..9b765d8
--- /dev/null
+++ b/fixtures/relative-simple/expected.jsx
@@ -0,0 +1,25 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+import _rehypeMdxImportMedia0 from './image.png'
+function _createMdxContent(props) {
+ const _components = {
+ img: 'img',
+ p: 'p',
+ ...props.components
+ }
+ return (
+ <_components.p>
+ <_components.img src={_rehypeMdxImportMedia0} alt="" />
+
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/relative-simple/input.md b/fixtures/relative-simple/input.md
new file mode 100644
index 0000000..2b364b2
--- /dev/null
+++ b/fixtures/relative-simple/input.md
@@ -0,0 +1 @@
+![](image.png)
diff --git a/fixtures/relative-simple/options.json b/fixtures/relative-simple/options.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/fixtures/relative-simple/options.json
@@ -0,0 +1 @@
+{}
diff --git a/fixtures/root/expected.jsx b/fixtures/root/expected.jsx
new file mode 100644
index 0000000..2125c55
--- /dev/null
+++ b/fixtures/root/expected.jsx
@@ -0,0 +1,24 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+function _createMdxContent(props) {
+ const _components = {
+ img: 'img',
+ p: 'p',
+ ...props.components
+ }
+ return (
+ <_components.p>
+ <_components.img src="/image.png" alt="" />
+
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/root/input.md b/fixtures/root/input.md
new file mode 100644
index 0000000..69223cd
--- /dev/null
+++ b/fixtures/root/input.md
@@ -0,0 +1 @@
+![](/image.png)
diff --git a/fixtures/root/options.json b/fixtures/root/options.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/fixtures/root/options.json
@@ -0,0 +1 @@
+{}
diff --git a/fixtures/srcset/expected.jsx b/fixtures/srcset/expected.jsx
new file mode 100644
index 0000000..9d670a9
--- /dev/null
+++ b/fixtures/srcset/expected.jsx
@@ -0,0 +1,84 @@
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/
+import _rehypeMdxImportMedia0 from './image.png'
+import _rehypeMdxImportMedia1 from './other-image.png'
+import _rehypeMdxImportMedia2 from './sound.mp3'
+import _rehypeMdxImportMedia3 from './video.mp4'
+import _rehypeMdxImportMedia4 from './image.jpg'
+import _rehypeMdxImportMedia5 from './video.webm'
+import _rehypeMdxImportMedia6 from './video.mpg'
+import _rehypeMdxImportMedia7 from './video.png'
+import _rehypeMdxImportMedia8 from './video.vtt'
+function _createMdxContent(props) {
+ const _components = {
+ audio: 'audio',
+ embed: 'embed',
+ img: 'img',
+ object: 'object',
+ p: 'p',
+ picture: 'picture',
+ source: 'source',
+ track: 'track',
+ video: 'video',
+ ...props.components
+ }
+ return (
+ <>
+ <_components.img
+ srcSet={`${_rehypeMdxImportMedia0} 2x,${_rehypeMdxImportMedia0} 640w 480h,${_rehypeMdxImportMedia1}`}
+ />
+ {'\n'}
+ <_components.img
+ srcSet={`${_rehypeMdxImportMedia0} 2x,${_rehypeMdxImportMedia0},${_rehypeMdxImportMedia1} 640w 480h`}
+ />
+ {'\n'}
+ <_components.img srcSet="https://example.com/image.png" />
+ {'\n'}
+ <_components.p>
+ <_components.audio src={_rehypeMdxImportMedia2} />
+
+ {'\n'}
+ <_components.p>
+ <_components.embed src={_rehypeMdxImportMedia3} type="video/webm" />
+
+ {'\n'}
+ <_components.p>
+ <_components.object src="video.pdf" type="application/pdf" />
+
+ {'\n'}
+ <_components.picture>
+ {'\n '}
+ <_components.source srcSet={`${_rehypeMdxImportMedia0}`} />
+ {'\n '}
+ <_components.source srcSet={`${_rehypeMdxImportMedia4}`} />
+ {'\n '}
+ <_components.img src={_rehypeMdxImportMedia4} />
+ {'\n'}
+
+ {'\n'}
+ <_components.video>
+ {'\n '}
+ <_components.source src={_rehypeMdxImportMedia5} type="video/webm" />
+ {'\n '}
+ <_components.source src={_rehypeMdxImportMedia6} type="video/mp4" />
+ {'\n'}
+
+ {'\n'}
+ <_components.video src={_rehypeMdxImportMedia5} poster={_rehypeMdxImportMedia7}>
+ {'\n '}
+ <_components.track kind="captions" srcLang="en" src={_rehypeMdxImportMedia8} />
+ {'\n'}
+
+ >
+ )
+}
+export default function MDXContent(props = {}) {
+ const { wrapper: MDXLayout } = props.components || {}
+ return MDXLayout ? (
+
+ <_createMdxContent {...props} />
+
+ ) : (
+ _createMdxContent(props)
+ )
+}
diff --git a/fixtures/srcset/input.md b/fixtures/srcset/input.md
new file mode 100644
index 0000000..894eb64
--- /dev/null
+++ b/fixtures/srcset/input.md
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+