11/**
2- * @typedef {import('@mdx-js/mdx').ProcessorOptions } ProcessorOptions
2+ * @typedef {import('@mdx-js/mdx').CompileOptions } CompileOptions
33 * @typedef {import('esbuild').Message } Message
44 * @typedef {import('esbuild').OnLoadArgs } OnLoadArgs
55 * @typedef {import('esbuild').OnLoadResult } OnLoadResult
1010 */
1111
1212/**
13- * @typedef EsbuildOptions
14- * Extra options.
15- * @property {boolean | null | undefined } [allowDangerousRemoteMdx=false]
16- * Whether to allow importing from `http:` and `https:` URLs (`boolean`,
17- * default: `false`).
18- *
19- * When passing `allowDangerousRemoteMdx`, MD(X) *and* JS files can be
20- * imported from `http:` and `https:` urls.
21- *
2213 * @typedef {Omit<OnLoadArgs, 'pluginData'> & LoadDataFields } LoadData
2314 * Data passed to `onload`.
2415 *
2718 * @property {PluginData | null | undefined } [pluginData]
2819 * Plugin data.
2920 *
30- * @typedef {EsbuildOptions & ProcessorOptions } Options
21+ * @typedef {CompileOptions } Options
3122 * Configuration.
3223 *
33- * Options are the same as `compile` from `@mdx-js/mdx` with the addition
34- * of `allowDangerousRemoteMdx`.
35- *
36- * ###### Notes
37- *
38- * > ⚠️ **Security**: `allowDangerousRemoteMdx` (intentionally) enabled remote
39- * > code execution.
40- * > Make sure you trust your code!
41- * > See [§ Security][security] for more
42- * > info.
43- *
44- * > 💡 **Experiment**: `allowDangerousRemoteMdx` is an experimental feature
45- * > that might not work well and might change in minor releases.
24+ * Options are the same as `compile` from `@mdx-js/mdx`.
4625 *
4726 * @typedef PluginData
4827 * Extra data passed.
6241import assert from 'node:assert'
6342import fs from 'node:fs/promises'
6443import path from 'node:path'
65- import process from 'node:process'
6644import { createFormatAwareProcessors } from '@mdx-js/mdx/internal-create-format-aware-processors'
6745import { extnamesToRegex } from '@mdx-js/mdx/internal-extnames-to-regex'
68- import { fetch } from 'undici'
6946import { VFile } from 'vfile'
7047import { VFileMessage } from 'vfile-message'
7148
7249const eol = / \r \n | \r | \n | \u2028 | \u2029 / g
7350
74- /** @type {Map<string, string> } */
75- const cache = new Map ( )
7651const name = '@mdx-js/esbuild'
77- const p = process
78- const remoteNamespace = name + '-remote'
7952
8053/**
8154 * Create an esbuild plugin to compile MDX to JS.
@@ -92,8 +65,7 @@ const remoteNamespace = name + '-remote'
9265 * Plugin.
9366 */
9467export function esbuild ( options ) {
95- const { allowDangerousRemoteMdx, ...rest } = options || { }
96- const { extnames, process} = createFormatAwareProcessors ( rest )
68+ const { extnames, process} = createFormatAwareProcessors ( options || { } )
9769
9870 return { name, setup}
9971
@@ -104,85 +76,7 @@ export function esbuild(options) {
10476 * Nothing.
10577 */
10678 function setup ( build ) {
107- const filter = extnamesToRegex ( extnames )
108- const filterHttp = new RegExp ( '^https?:\\/{2}.+' + filter . source )
109- const http = / ^ h t t p s ? : \/ { 2 } /
110- const filterHttpOrRelative = / ^ ( h t t p s ? : \/ { 2 } | .{ 1 , 2 } \/ ) .* /
111-
112- if ( allowDangerousRemoteMdx ) {
113- // Intercept import paths starting with "http:" and "https:" so
114- // esbuild doesn't attempt to map them to a file system location.
115- // Tag them with the "http-url" namespace to associate them with
116- // this plugin.
117- build . onResolve (
118- { filter : filterHttp , namespace : 'file' } ,
119- resolveRemoteInLocal
120- )
121-
122- build . onResolve (
123- { filter : filterHttpOrRelative , namespace : remoteNamespace } ,
124- resolveInRemote
125- )
126- }
127-
128- build . onLoad ( { filter : / .* / , namespace : remoteNamespace } , onloadremote )
129- build . onLoad ( { filter} , onload )
130-
131- /** @param {OnResolveArgs } args */
132- function resolveRemoteInLocal ( args ) {
133- return { namespace : remoteNamespace , path : args . path }
134- }
135-
136- // Intercept all import paths inside downloaded files and resolve them against
137- // the original URL. All of these
138- // files will be in the "http-url" namespace. Make sure to keep
139- // the newly resolved URL in the "http-url" namespace so imports
140- // inside it will also be resolved as URLs recursively.
141- /** @param {OnResolveArgs } args */
142- function resolveInRemote ( args ) {
143- return {
144- namespace : remoteNamespace ,
145- path : String ( new URL ( args . path , args . importer ) )
146- }
147- }
148-
149- /**
150- * @param {OnLoadArgs } data
151- * Data.
152- * @returns {Promise<OnLoadResult> }
153- * Result.
154- */
155- async function onloadremote ( data ) {
156- const href = data . path
157- console . log ( '%s: downloading `%s`' , remoteNamespace , href )
158-
159- /** @type {string } */
160- let contents
161-
162- const cachedContents = cache . get ( href )
163- if ( cachedContents ) {
164- contents = cachedContents
165- } else {
166- const response = await fetch ( href )
167- contents = await response . text ( )
168- cache . set ( href , contents )
169- }
170-
171- if ( filter . test ( href ) ) {
172- // Clean search and hash from URL.
173- const url = new URL ( href )
174- url . hash = ''
175- url . search = ''
176- return onload ( {
177- namespace : 'file' ,
178- path : url . href ,
179- pluginData : { contents} ,
180- suffix : ''
181- } )
182- }
183-
184- return { contents, loader : 'js' , resolveDir : p . cwd ( ) }
185- }
79+ build . onLoad ( { filter : extnamesToRegex ( extnames ) } , onload )
18680
18781 /**
18882 * @param {LoadData } data
@@ -240,9 +134,7 @@ export function esbuild(options) {
240134 return {
241135 contents : value || '' ,
242136 errors,
243- resolveDir : http . test ( file . path )
244- ? p . cwd ( )
245- : path . resolve ( file . cwd , file . dirname ) ,
137+ resolveDir : path . resolve ( file . cwd , file . dirname ) ,
246138 warnings
247139 }
248140 }
0 commit comments