diff --git a/docs/docs/getting-started.mdx b/docs/docs/getting-started.mdx index c74c15ec7..6a5fdee27 100644 --- a/docs/docs/getting-started.mdx +++ b/docs/docs/getting-started.mdx @@ -237,7 +237,6 @@ long. We support [esbuild](https://esbuild.github.io). Install and configure the esbuild plugin [`@mdx-js/esbuild`][mdx-esbuild]. -This plugin has an additional option `allowDangerousRemoteMdx`. [Configure your JSX runtime][jsx] depending on which one you use (React, Preact, Vue, etc.). diff --git a/package-lock.json b/package-lock.json index 13dc15b97..7db511277 100644 --- a/package-lock.json +++ b/package-lock.json @@ -738,14 +738,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@fastify/busboy": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.0.0.tgz", - "integrity": "sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==", - "engines": { - "node": ">=14" - } - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.13", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", @@ -26195,17 +26187,6 @@ "node": ">=0.10.0" } }, - "node_modules/undici": { - "version": "5.26.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.26.4.tgz", - "integrity": "sha512-OG+QOf0fTLtazL9P9X7yqWxQ+Z0395Wk6DSkyTxtaq3wQEjIroVe7Y4asCX/vcCxYpNGMnwz8F0qbRYUoaQVMw==", - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, - "engines": { - "node": ">=14.0" - } - }, "node_modules/undici-types": { "version": "5.25.3", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", @@ -28632,7 +28613,6 @@ "dependencies": { "@mdx-js/mdx": "^2.0.0", "@types/unist": "^3.0.0", - "undici": "^5.0.0", "vfile": "^6.0.0", "vfile-message": "^4.0.0" }, diff --git a/packages/esbuild/lib/index.js b/packages/esbuild/lib/index.js index 12a5f14a7..d6f35bbc8 100644 --- a/packages/esbuild/lib/index.js +++ b/packages/esbuild/lib/index.js @@ -1,5 +1,5 @@ /** - * @typedef {import('@mdx-js/mdx').ProcessorOptions} ProcessorOptions + * @typedef {import('@mdx-js/mdx').CompileOptions} CompileOptions * @typedef {import('esbuild').Message} Message * @typedef {import('esbuild').OnLoadArgs} OnLoadArgs * @typedef {import('esbuild').OnLoadResult} OnLoadResult @@ -10,15 +10,6 @@ */ /** - * @typedef EsbuildOptions - * Extra options. - * @property {boolean | null | undefined} [allowDangerousRemoteMdx=false] - * Whether to allow importing from `http:` and `https:` URLs (`boolean`, - * default: `false`). - * - * When passing `allowDangerousRemoteMdx`, MD(X) *and* JS files can be - * imported from `http:` and `https:` urls. - * * @typedef {Omit & LoadDataFields} LoadData * Data passed to `onload`. * @@ -27,22 +18,10 @@ * @property {PluginData | null | undefined} [pluginData] * Plugin data. * - * @typedef {EsbuildOptions & ProcessorOptions} Options + * @typedef {CompileOptions} Options * Configuration. * - * Options are the same as `compile` from `@mdx-js/mdx` with the addition - * of `allowDangerousRemoteMdx`. - * - * ###### Notes - * - * > ⚠️ **Security**: `allowDangerousRemoteMdx` (intentionally) enabled remote - * > code execution. - * > Make sure you trust your code! - * > See [§ Security][security] for more - * > info. - * - * > 💡 **Experiment**: `allowDangerousRemoteMdx` is an experimental feature - * > that might not work well and might change in minor releases. + * Options are the same as `compile` from `@mdx-js/mdx`. * * @typedef PluginData * Extra data passed. @@ -62,20 +41,14 @@ import assert from 'node:assert' import fs from 'node:fs/promises' import path from 'node:path' -import process from 'node:process' import {createFormatAwareProcessors} from '@mdx-js/mdx/internal-create-format-aware-processors' import {extnamesToRegex} from '@mdx-js/mdx/internal-extnames-to-regex' -import {fetch} from 'undici' import {VFile} from 'vfile' import {VFileMessage} from 'vfile-message' const eol = /\r\n|\r|\n|\u2028|\u2029/g -/** @type {Map} */ -const cache = new Map() const name = '@mdx-js/esbuild' -const p = process -const remoteNamespace = name + '-remote' /** * Create an esbuild plugin to compile MDX to JS. @@ -92,8 +65,7 @@ const remoteNamespace = name + '-remote' * Plugin. */ export function esbuild(options) { - const {allowDangerousRemoteMdx, ...rest} = options || {} - const {extnames, process} = createFormatAwareProcessors(rest) + const {extnames, process} = createFormatAwareProcessors(options || {}) return {name, setup} @@ -104,85 +76,7 @@ export function esbuild(options) { * Nothing. */ function setup(build) { - const filter = extnamesToRegex(extnames) - const filterHttp = new RegExp('^https?:\\/{2}.+' + filter.source) - const http = /^https?:\/{2}/ - const filterHttpOrRelative = /^(https?:\/{2}|.{1,2}\/).*/ - - if (allowDangerousRemoteMdx) { - // Intercept import paths starting with "http:" and "https:" so - // esbuild doesn't attempt to map them to a file system location. - // Tag them with the "http-url" namespace to associate them with - // this plugin. - build.onResolve( - {filter: filterHttp, namespace: 'file'}, - resolveRemoteInLocal - ) - - build.onResolve( - {filter: filterHttpOrRelative, namespace: remoteNamespace}, - resolveInRemote - ) - } - - build.onLoad({filter: /.*/, namespace: remoteNamespace}, onloadremote) - build.onLoad({filter}, onload) - - /** @param {OnResolveArgs} args */ - function resolveRemoteInLocal(args) { - return {namespace: remoteNamespace, path: args.path} - } - - // Intercept all import paths inside downloaded files and resolve them against - // the original URL. All of these - // files will be in the "http-url" namespace. Make sure to keep - // the newly resolved URL in the "http-url" namespace so imports - // inside it will also be resolved as URLs recursively. - /** @param {OnResolveArgs} args */ - function resolveInRemote(args) { - return { - namespace: remoteNamespace, - path: String(new URL(args.path, args.importer)) - } - } - - /** - * @param {OnLoadArgs} data - * Data. - * @returns {Promise} - * Result. - */ - async function onloadremote(data) { - const href = data.path - console.log('%s: downloading `%s`', remoteNamespace, href) - - /** @type {string} */ - let contents - - const cachedContents = cache.get(href) - if (cachedContents) { - contents = cachedContents - } else { - const response = await fetch(href) - contents = await response.text() - cache.set(href, contents) - } - - if (filter.test(href)) { - // Clean search and hash from URL. - const url = new URL(href) - url.hash = '' - url.search = '' - return onload({ - namespace: 'file', - path: url.href, - pluginData: {contents}, - suffix: '' - }) - } - - return {contents, loader: 'js', resolveDir: p.cwd()} - } + build.onLoad({filter: extnamesToRegex(extnames)}, onload) /** * @param {LoadData} data @@ -240,9 +134,7 @@ export function esbuild(options) { return { contents: value || '', errors, - resolveDir: http.test(file.path) - ? p.cwd() - : path.resolve(file.cwd, file.dirname), + resolveDir: path.resolve(file.cwd, file.dirname), warnings } } diff --git a/packages/esbuild/package.json b/packages/esbuild/package.json index beb85e411..f5b4e3af7 100644 --- a/packages/esbuild/package.json +++ b/packages/esbuild/package.json @@ -39,7 +39,6 @@ "dependencies": { "@mdx-js/mdx": "^2.0.0", "@types/unist": "^3.0.0", - "undici": "^5.0.0", "vfile": "^6.0.0", "vfile-message": "^4.0.0" }, diff --git a/packages/esbuild/readme.md b/packages/esbuild/readme.md index 847a7b47c..b89eb9666 100644 --- a/packages/esbuild/readme.md +++ b/packages/esbuild/readme.md @@ -97,64 +97,7 @@ ESBuild plugin ([`Plugin`][esbuild-plugin] from `esbuild`). Configuration (TypeScript type). -Options are the same as [`CompileOptions` from `@mdx-js/mdx`][compile-options] -with the addition of `allowDangerousRemoteMdx`: - -###### Fields - -* `allowDangerousRemoteMdx` (`boolean`, default: `false`) - — whether to allow importing from `http:` and `https:` URLs; - when passing `allowDangerousRemoteMdx`, MD(X) *and* JS files can be imported - from `http:` and `https:` urls; - -###### Notes - -> ⚠️ **Security**: `allowDangerousRemoteMdx` (intentionally) enabled remote -> code execution. -> Make sure you trust your code! -> See [§ Security][security] for more -> info. - -> 💡 **Experiment**: `allowDangerousRemoteMdx` is an experimental feature that -> might not work well and might change in minor releases. - -## Examples - -### Use `allowDangerousRemoteMdx` - -Take this `index.mdx` file: - -```mdx -import Readme from 'https://raw.githubusercontent.com/mdx-js/mdx/main/readme.md' - -Here’s the readme: - - -``` - -…and a module `build.js`: - -```tsx -import mdx from '@mdx-js/esbuild' -import esbuild from 'esbuild' - -await esbuild.build({ - entryPoints: ['index.mdx'], - format: 'esm', - outfile: 'output.js', - plugins: [mdx({allowDangerousRemoteMdx: true, /* Other options… */})] -}) -``` - -…then running that (`node build.js`) and evaluating `output.js` (depends on how -you evaluate React or another framework) would give: - -```tsx -

Here’s the readme:

-

MDX: Markdown for the component era 🚀

-{/* … */} -

MIT © …

-``` +Options are the same as [`CompileOptions` from `@mdx-js/mdx`][compile-options]. ## Types diff --git a/packages/esbuild/test/files/components.js b/packages/esbuild/test/files/components.js deleted file mode 100644 index 0a0d48143..000000000 --- a/packages/esbuild/test/files/components.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react' - -/** - * @param {JSX.IntrinsicElements['span']} props - * Props. - * @returns - * `span` element. - */ -export function Pill(props) { - return React.createElement('span', {...props, style: {color: 'red'}}) -} - -/** - * @param {JSX.IntrinsicElements['div']} props - * Props. - * @returns - * `div` element. - */ -export function Layout(props) { - return React.createElement('div', {...props, style: {color: 'red'}}) -} - -export default Layout diff --git a/packages/esbuild/test/files/md-file.md b/packages/esbuild/test/files/md-file.md deleted file mode 100644 index 637d21052..000000000 --- a/packages/esbuild/test/files/md-file.md +++ /dev/null @@ -1 +0,0 @@ -Some content. diff --git a/packages/esbuild/test/files/mdx-file-importing-markdown.mdx b/packages/esbuild/test/files/mdx-file-importing-markdown.mdx deleted file mode 100644 index 2563edeaf..000000000 --- a/packages/esbuild/test/files/mdx-file-importing-markdown.mdx +++ /dev/null @@ -1,8 +0,0 @@ -import {Pill} from './components.js' -import Content from './md-file.md' - -# heading - -A little pill. - - diff --git a/packages/esbuild/test/index.js b/packages/esbuild/test/index.js index 407b9b940..d517a8f50 100644 --- a/packages/esbuild/test/index.js +++ b/packages/esbuild/test/index.js @@ -539,78 +539,6 @@ test('@mdx-js/esbuild', async function (t) { await fs.rm(jsUrl) } ) - - await t.test( - 'should compile remote markdown files w/ `allowDangerousRemoteMdx`', - async function () { - const mdxUrl = new URL('esbuild.mdx', import.meta.url) - const jsUrl = new URL('esbuild.js', import.meta.url) - - await fs.writeFile( - mdxUrl, - 'import Content from "https://raw.githubusercontent.com/mdx-js/mdx/main/packages/esbuild/test/files/md-file.md"\n\n' - ) - - console.warn('note: the following warning is expected') - await esbuild.build({ - entryPoints: [fileURLToPath(mdxUrl)], - outfile: fileURLToPath(jsUrl), - bundle: true, - define: {'process.env.NODE_ENV': '"development"'}, - format: 'esm', - plugins: [esbuildMdx({allowDangerousRemoteMdx: true})] - }) - console.warn('note: the preceding warning was expected') - - /** @type {MDXModule} */ - const mod = await import(jsUrl.href + '#' + Math.random()) - const Content = mod.default - - assert.equal( - renderToStaticMarkup(React.createElement(Content)), - '

Some content.

' - ) - - await fs.rm(mdxUrl) - await fs.rm(jsUrl) - } - ) - - await t.test( - 'should compile remote MD, MDX, and JS files w/ `allowDangerousRemoteMdx`', - async function () { - const mdxUrl = new URL('esbuild.mdx', import.meta.url) - const jsUrl = new URL('esbuild.js', import.meta.url) - - await fs.writeFile( - mdxUrl, - 'import Content from "https://raw.githubusercontent.com/mdx-js/mdx/main/packages/esbuild/test/files/mdx-file-importing-markdown.mdx"\n\n' - ) - - console.warn('note: the following 3 warnings are expected') - await esbuild.build({ - entryPoints: [fileURLToPath(mdxUrl)], - outfile: fileURLToPath(jsUrl), - bundle: true, - define: {'process.env.NODE_ENV': '"development"'}, - format: 'esm', - plugins: [esbuildMdx({allowDangerousRemoteMdx: true})] - }) - console.warn('note: the preceding 3 warnings were expected') - - /** @type {MDXModule} */ - const mod = await import(jsUrl.href + '#' + Math.random()) - const Content = mod.default - - assert.equal( - renderToStaticMarkup(React.createElement(Content)), - '

heading

\n

A little pill.

\n

Some content.

' - ) - - await fs.rm(mdxUrl) - await fs.rm(jsUrl) - } - ) }) /** diff --git a/packages/node-loader/package.json b/packages/node-loader/package.json index 76554283a..71eb1cdcb 100644 --- a/packages/node-loader/package.json +++ b/packages/node-loader/package.json @@ -1,7 +1,7 @@ { "name": "@mdx-js/node-loader", "version": "2.3.0", - "description": "Experimental Node loader for MDX", + "description": "Node.js loader for MDX", "license": "MIT", "keywords": [ "jsx",