Comparing version
@@ -1,1 +0,1 @@ | ||
export { esbuild as default } from "./lib/esbuild.js"; | ||
export { esbuild as default } from "./lib/integration/esbuild.js"; |
@@ -1,1 +0,1 @@ | ||
export {esbuild as default} from './lib/esbuild.js' | ||
export {esbuild as default} from './lib/integration/esbuild.js' |
@@ -1,58 +0,5 @@ | ||
// Ideas: | ||
// | ||
// This ESM loader does not accept options. | ||
// This importantly means `jsxImportSource`, `providerImportSource`, or | ||
// `{remark,rehype,recma}Plugins` can’t be changed. | ||
// | ||
// I see two potential solutions: | ||
// | ||
// 1. Options could be passed in as strings to the loader like so: | ||
// | ||
// ```sh | ||
// node --experimental-loader=xdm/esm-loader.js?jsxImportSource=preact example.js | ||
// ``` | ||
// | ||
// Which is then parsed here through `process.execArgv`, which for the above | ||
// yields: | ||
// | ||
// ```sh | ||
// ['--experimental-loader=xdm/esm-loader.js?jsxImportSource=preact'] | ||
// ``` | ||
// | ||
// This is less neat for plugins. | ||
// 2. This module could also export a `createEsmLoader(options)`, | ||
// which builds the needed `getFormat` / `transformSource`, and could then | ||
// be used like so, in my `my-loader.js`: | ||
// | ||
// ```js | ||
// import {createEsmLoader} from 'mdx/esm-loader.js' | ||
// export const {getFormat, transformSource} from createEsmLoader(options) | ||
// ``` | ||
// | ||
// Uses as: | ||
// | ||
// ```sh | ||
// node --experimental-loader=./my-loader.js example.js | ||
// ``` | ||
import {createLoader} from './lib/integration/node.js' | ||
import {compile} from './index.js' | ||
var {getFormat, transformSource} = createLoader() | ||
var extension = '.mdx' | ||
export function getFormat(url, context, defaultGetFormat) { | ||
return url.endsWith(extension) | ||
? {format: 'module'} | ||
: defaultGetFormat(url, context, defaultGetFormat) | ||
} | ||
export async function transformSource(source, context, defaultTransformSource) { | ||
return context.url.endsWith(extension) | ||
? { | ||
source: String( | ||
await compile({contents: source, path: context.url}) | ||
).replace(/\/jsx-runtime(?=["'])/g, '$&.js') | ||
} | ||
: // For some reason, on Erbium, c8 is missing the following two lines. | ||
/* c8 ignore next 2 */ | ||
defaultTransformSource(source, context, defaultTransformSource) | ||
} | ||
export {getFormat, transformSource, createLoader} |
@@ -1,2 +0,4 @@ | ||
export { compile, compileSync, createProcessor } from "./lib/core.js"; | ||
export { createProcessor } from "./lib/core.js"; | ||
export { nodeTypes } from "./lib/node-types.js"; | ||
export { compile, compileSync } from "./lib/compile.js"; | ||
export { evaluate, evaluateSync } from "./lib/evaluate.js"; |
@@ -1,2 +0,4 @@ | ||
export {compile, compileSync, createProcessor} from './lib/core.js' | ||
export {createProcessor} from './lib/core.js' | ||
export {compile, compileSync} from './lib/compile.js' | ||
export {evaluate, evaluateSync} from './lib/evaluate.js' | ||
export {nodeTypes} from './lib/node-types.js' |
/** | ||
* @typedef {import("vfile").VFileCompatible} VFileCompatible | ||
* @typedef {import("vfile").VFile} VFile | ||
* @typedef {import("unified").Processor} Processor | ||
* @typedef {import("unified").PluggableList} PluggableList | ||
* @typedef {import("./recma-document").RecmaDocumentOptions} RecmaDocumentOptions | ||
* @typedef {import("./recma-stringify").RecmaStringifyOptions} RecmaStringifyOptions | ||
* @typedef {import("./recma-jsx-rewrite").RecmaJsxRewriteOptions} RecmaJsxRewriteOptions | ||
* @typedef {import('unified').Processor} Processor | ||
* @typedef {import('unified').PluggableList} PluggableList | ||
* @typedef {import('./plugin/recma-document').RecmaDocumentOptions} RecmaDocumentOptions | ||
* @typedef {import('./plugin/recma-stringify').RecmaStringifyOptions} RecmaStringifyOptions | ||
* @typedef {import('./plugin/recma-jsx-rewrite').RecmaJsxRewriteOptions} RecmaJsxRewriteOptions | ||
* | ||
* @typedef BaseProcessorOptions | ||
* @property {boolean} [jsx=false] Whether to keep JSX | ||
* @property {'mdx' | 'md'} [format='mdx'] Format of the files to be processed | ||
* @property {string[]} [mdExtensions] Extensions (with `.`) for markdown | ||
* @property {string[]} [mdxExtensions] Extensions (with `.`) for MDX | ||
* @property {PluggableList} [recmaPlugins] List of recma (esast, JavaScript) plugins | ||
@@ -17,21 +18,6 @@ * @property {PluggableList} [remarkPlugins] List of remark (mdast, markdown) plugins | ||
* | ||
* @typedef {Omit<RecmaDocumentOptions & RecmaStringifyOptions & RecmaJsxRewriteOptions & BaseProcessorOptions, "contain"> } ProcessorOptions | ||
* @typedef {Omit<RecmaDocumentOptions & RecmaStringifyOptions & RecmaJsxRewriteOptions, '_contain'>} PluginOptions | ||
* @typedef {BaseProcessorOptions & PluginOptions} ProcessorOptions | ||
*/ | ||
/** | ||
* Compile MDX to JS. | ||
* | ||
* @param {VFileCompatible} file MDX document to parse (`string`, `Buffer`, `vfile`, anything that can be given to `vfile`) | ||
* @param {ProcessorOptions} [options] | ||
* @return {Promise<VFile>} | ||
*/ | ||
export function compile(file: VFileCompatible, options?: ProcessorOptions): Promise<VFile>; | ||
/** | ||
* Synchronously compile MDX to JS. | ||
* | ||
* @param {VFileCompatible} file MDX document to parse (`string`, `Buffer`, `vfile`, anything that can be given to `vfile`) | ||
* @param {ProcessorOptions} [options] | ||
* @return {VFile} | ||
*/ | ||
export function compileSync(file: VFileCompatible, options?: ProcessorOptions): VFile; | ||
/** | ||
* Pipeline to: | ||
@@ -47,9 +33,7 @@ * | ||
export function createProcessor(options?: ProcessorOptions): Processor; | ||
export type VFileCompatible = import("vfile").VFileCompatible; | ||
export type VFile = import("vfile").VFile; | ||
export type Processor = import("unified").Processor; | ||
export type PluggableList = import("unified").PluggableList; | ||
export type RecmaDocumentOptions = import("./recma-document").RecmaDocumentOptions; | ||
export type RecmaStringifyOptions = import("./recma-stringify").RecmaStringifyOptions; | ||
export type RecmaJsxRewriteOptions = import("./recma-jsx-rewrite").RecmaJsxRewriteOptions; | ||
export type Processor = import('unified').Processor; | ||
export type PluggableList = import('unified').PluggableList; | ||
export type RecmaDocumentOptions = import('./plugin/recma-document').RecmaDocumentOptions; | ||
export type RecmaStringifyOptions = import('./plugin/recma-stringify').RecmaStringifyOptions; | ||
export type RecmaJsxRewriteOptions = import('./plugin/recma-jsx-rewrite').RecmaJsxRewriteOptions; | ||
export type BaseProcessorOptions = { | ||
@@ -61,2 +45,14 @@ /** | ||
/** | ||
* Format of the files to be processed | ||
*/ | ||
format?: 'mdx' | 'md'; | ||
/** | ||
* Extensions (with `.`) for markdown | ||
*/ | ||
mdExtensions?: string[]; | ||
/** | ||
* Extensions (with `.`) for MDX | ||
*/ | ||
mdxExtensions?: string[]; | ||
/** | ||
* List of recma (esast, JavaScript) plugins | ||
@@ -78,2 +74,3 @@ */ | ||
}; | ||
export type ProcessorOptions = Omit<RecmaDocumentOptions & RecmaStringifyOptions & RecmaJsxRewriteOptions & BaseProcessorOptions, "contain">; | ||
export type PluginOptions = Omit<RecmaDocumentOptions & RecmaStringifyOptions & RecmaJsxRewriteOptions, '_contain'>; | ||
export type ProcessorOptions = BaseProcessorOptions & PluginOptions; |
import unified from 'unified' | ||
import remarkParse from 'remark-parse' | ||
import remarkRehype from 'remark-rehype' | ||
import {recmaJsxBuild} from './recma-jsx-build.js' | ||
import {recmaDocument} from './recma-document.js' | ||
import {recmaJsxRewrite} from './recma-jsx-rewrite.js' | ||
import {recmaStringify} from './recma-stringify.js' | ||
import {rehypeMarkAndUnravel} from './rehype-mark-and-unravel.js' | ||
import {rehypeRecma} from './rehype-recma.js' | ||
import {remarkMdx} from './remark-mdx.js' | ||
import {recmaJsxBuild} from './plugin/recma-jsx-build.js' | ||
import {recmaDocument} from './plugin/recma-document.js' | ||
import {recmaJsxRewrite} from './plugin/recma-jsx-rewrite.js' | ||
import {recmaStringify} from './plugin/recma-stringify.js' | ||
import {rehypeMarkAndUnravel} from './plugin/rehype-mark-and-unravel.js' | ||
import {rehypeRecma} from './plugin/rehype-recma.js' | ||
import {rehypeRemoveRaw} from './plugin/rehype-remove-raw.js' | ||
import {remarkMdx} from './plugin/remark-mdx.js' | ||
import {nodeTypes} from './node-types.js' | ||
/** | ||
* @typedef {import("vfile").VFileCompatible} VFileCompatible | ||
* @typedef {import("vfile").VFile} VFile | ||
* @typedef {import("unified").Processor} Processor | ||
* @typedef {import("unified").PluggableList} PluggableList | ||
* @typedef {import("./recma-document").RecmaDocumentOptions} RecmaDocumentOptions | ||
* @typedef {import("./recma-stringify").RecmaStringifyOptions} RecmaStringifyOptions | ||
* @typedef {import("./recma-jsx-rewrite").RecmaJsxRewriteOptions} RecmaJsxRewriteOptions | ||
* @typedef {import('unified').Processor} Processor | ||
* @typedef {import('unified').PluggableList} PluggableList | ||
* @typedef {import('./plugin/recma-document').RecmaDocumentOptions} RecmaDocumentOptions | ||
* @typedef {import('./plugin/recma-stringify').RecmaStringifyOptions} RecmaStringifyOptions | ||
* @typedef {import('./plugin/recma-jsx-rewrite').RecmaJsxRewriteOptions} RecmaJsxRewriteOptions | ||
* | ||
* @typedef BaseProcessorOptions | ||
* @property {boolean} [jsx=false] Whether to keep JSX | ||
* @property {'mdx' | 'md'} [format='mdx'] Format of the files to be processed | ||
* @property {string[]} [mdExtensions] Extensions (with `.`) for markdown | ||
* @property {string[]} [mdxExtensions] Extensions (with `.`) for MDX | ||
* @property {PluggableList} [recmaPlugins] List of recma (esast, JavaScript) plugins | ||
@@ -28,28 +31,7 @@ * @property {PluggableList} [remarkPlugins] List of remark (mdast, markdown) plugins | ||
* | ||
* @typedef {Omit<RecmaDocumentOptions & RecmaStringifyOptions & RecmaJsxRewriteOptions & BaseProcessorOptions, "contain"> } ProcessorOptions | ||
* @typedef {Omit<RecmaDocumentOptions & RecmaStringifyOptions & RecmaJsxRewriteOptions, '_contain'>} PluginOptions | ||
* @typedef {BaseProcessorOptions & PluginOptions} ProcessorOptions | ||
*/ | ||
/** | ||
* Compile MDX to JS. | ||
* | ||
* @param {VFileCompatible} file MDX document to parse (`string`, `Buffer`, `vfile`, anything that can be given to `vfile`) | ||
* @param {ProcessorOptions} [options] | ||
* @return {Promise<VFile>} | ||
*/ | ||
export function compile(file, options) { | ||
return createProcessor(options).process(file) | ||
} | ||
/** | ||
* Synchronously compile MDX to JS. | ||
* | ||
* @param {VFileCompatible} file MDX document to parse (`string`, `Buffer`, `vfile`, anything that can be given to `vfile`) | ||
* @param {ProcessorOptions} [options] | ||
* @return {VFile} | ||
*/ | ||
export function compileSync(file, options) { | ||
return createProcessor(options).processSync(file) | ||
} | ||
/** | ||
* Pipeline to: | ||
@@ -66,4 +48,5 @@ * | ||
var { | ||
_contain: contain, | ||
_contain, | ||
jsx, | ||
format, | ||
providerImportSource, | ||
@@ -74,29 +57,27 @@ recmaPlugins, | ||
SourceMapGenerator, | ||
...otherOptions | ||
...rest | ||
} = options | ||
// @ts-ignore Sure the types prohibit it but what if someone does it anyway? | ||
if (format === 'detect') { | ||
throw new Error( | ||
"Incorrect `format: 'detect'`: `createProcessor` can support either `md` or `mdx`; it does not support detecting the format" | ||
) | ||
} | ||
return ( | ||
unified() | ||
.use(remarkParse) | ||
.use(remarkMdx) | ||
.use(format === 'md' ? undefined : remarkMdx) | ||
.use(remarkPlugins) | ||
.use(remarkRehype, { | ||
// List of node types made by `mdast-util-mdx`, which have to be passed | ||
// through untouched from the mdast tree to the hast tree. | ||
passThrough: [ | ||
'mdxFlowExpression', | ||
'mdxJsxFlowElement', | ||
'mdxJsxTextElement', | ||
'mdxTextExpression', | ||
'mdxjsEsm' | ||
] | ||
}) | ||
.use(remarkRehype, {allowDangerousHtml: true, passThrough: nodeTypes}) | ||
.use(rehypeMarkAndUnravel) | ||
.use(rehypePlugins) | ||
.use(format === 'md' ? rehypeRemoveRaw : undefined) | ||
.use(rehypeRecma) | ||
.use(recmaDocument, {...otherOptions, contain}) | ||
.use(recmaDocument, {...rest, _contain}) | ||
// @ts-ignore recma transformer uses an esast node rather than a unist node | ||
.use(recmaJsxRewrite, {providerImportSource, contain}) | ||
.use(recmaJsxRewrite, {providerImportSource, _contain}) | ||
// @ts-ignore recma transformer uses an esast node rather than a unist node | ||
.use(jsx ? undefined : recmaJsxBuild, {contain}) | ||
.use(jsx ? undefined : recmaJsxBuild, {_contain}) | ||
// @ts-ignore recma compiler is seen as a transformer | ||
@@ -103,0 +84,0 @@ .use(recmaStringify, {SourceMapGenerator}) |
/** | ||
* @typedef {import("vfile").VFileCompatible} VFileCompatible | ||
* @typedef {import('./core.js').BaseProcessorOptions} BaseProcessorOptions | ||
* @typedef {import('vfile').VFileCompatible} VFileCompatible | ||
* @typedef {import('./util/resolve-evaluate-options.js').EvaluateOptions} EvaluateOptions | ||
* | ||
* @typedef RunnerOptions | ||
* @property {*} Fragment Symbol to use for fragments | ||
* @property {*} jsx Function to generate an element with static children | ||
* @property {*} jsxs Function to generate an element with dynamic children | ||
* @property {*} [useMDXComponents] Function to get `MDXComponents` from context | ||
* | ||
* @typedef {Omit<BaseProcessorOptions, "jsx" | "_contain"> } ProcessorOptions | ||
* @typedef {ProcessorOptions & RunnerOptions} ProcessorAndRunnerOptions | ||
* | ||
* @typedef {{ [name: string]: any }} ComponentMap | ||
* @typedef {{ [props: string]: any, components?: ComponentMap }} MDXContentProps | ||
* @typedef {{ [exports: string]: unknown, default: (props: MDXContentProps) => any }} ExportMap | ||
* @typedef {{[name: string]: any}} ComponentMap | ||
* @typedef {{[props: string]: any, components?: ComponentMap}} MDXContentProps | ||
* @typedef {{[exports: string]: unknown, default: (props: MDXContentProps) => any}} ExportMap | ||
*/ | ||
@@ -21,37 +12,17 @@ /** | ||
* | ||
* @param {VFileCompatible} file MDX document to parse (`string`, `Buffer`, `vfile`, anything that can be given to `vfile`) | ||
* @param {ProcessorAndRunnerOptions} options | ||
* @param {VFileCompatible} vfileCompatible MDX document to parse (`string`, `Buffer`, `vfile`, anything that can be given to `vfile`) | ||
* @param {EvaluateOptions} evaluateOptions | ||
* @return {Promise<ExportMap>} | ||
*/ | ||
export function evaluate(file: VFileCompatible, options: ProcessorAndRunnerOptions): Promise<ExportMap>; | ||
export function evaluate(vfileCompatible: VFileCompatible, evaluateOptions: EvaluateOptions): Promise<ExportMap>; | ||
/** | ||
* Synchronously evaluate MDX. | ||
* | ||
* @param {VFileCompatible} file MDX document to parse (`string`, `Buffer`, `vfile`, anything that can be given to `vfile`) | ||
* @param {ProcessorAndRunnerOptions} options | ||
* @param {VFileCompatible} vfileCompatible MDX document to parse (`string`, `Buffer`, `vfile`, anything that can be given to `vfile`) | ||
* @param {EvaluateOptions} evaluateOptions | ||
* @return {ExportMap} | ||
*/ | ||
export function evaluateSync(file: VFileCompatible, options: ProcessorAndRunnerOptions): ExportMap; | ||
export type VFileCompatible = import("vfile").VFileCompatible; | ||
export type BaseProcessorOptions = import('./core.js').BaseProcessorOptions; | ||
export type RunnerOptions = { | ||
/** | ||
* Symbol to use for fragments | ||
*/ | ||
Fragment: any; | ||
/** | ||
* Function to generate an element with static children | ||
*/ | ||
jsx: any; | ||
/** | ||
* Function to generate an element with dynamic children | ||
*/ | ||
jsxs: any; | ||
/** | ||
* Function to get `MDXComponents` from context | ||
*/ | ||
useMDXComponents?: any; | ||
}; | ||
export type ProcessorOptions = Omit<BaseProcessorOptions, "jsx" | "_contain">; | ||
export type ProcessorAndRunnerOptions = ProcessorOptions & RunnerOptions; | ||
export function evaluateSync(vfileCompatible: VFileCompatible, evaluateOptions: EvaluateOptions): ExportMap; | ||
export type VFileCompatible = import('vfile').VFileCompatible; | ||
export type EvaluateOptions = import('./util/resolve-evaluate-options.js').EvaluateOptions; | ||
export type ComponentMap = { | ||
@@ -58,0 +29,0 @@ [name: string]: any; |
@@ -1,19 +0,12 @@ | ||
import {compile, compileSync} from './core.js' | ||
import {compile, compileSync} from './compile.js' | ||
import {run, runSync} from './run.js' | ||
import {resolveEvaluateOptions} from './util/resolve-evaluate-options.js' | ||
/** | ||
* @typedef {import("vfile").VFileCompatible} VFileCompatible | ||
* @typedef {import('./core.js').BaseProcessorOptions} BaseProcessorOptions | ||
* @typedef {import('vfile').VFileCompatible} VFileCompatible | ||
* @typedef {import('./util/resolve-evaluate-options.js').EvaluateOptions} EvaluateOptions | ||
* | ||
* @typedef RunnerOptions | ||
* @property {*} Fragment Symbol to use for fragments | ||
* @property {*} jsx Function to generate an element with static children | ||
* @property {*} jsxs Function to generate an element with dynamic children | ||
* @property {*} [useMDXComponents] Function to get `MDXComponents` from context | ||
* | ||
* @typedef {Omit<BaseProcessorOptions, "jsx" | "_contain"> } ProcessorOptions | ||
* @typedef {ProcessorOptions & RunnerOptions} ProcessorAndRunnerOptions | ||
* | ||
* @typedef {{ [name: string]: any }} ComponentMap | ||
* @typedef {{ [props: string]: any, components?: ComponentMap }} MDXContentProps | ||
* @typedef {{ [exports: string]: unknown, default: (props: MDXContentProps) => any }} ExportMap | ||
* @typedef {{[name: string]: any}} ComponentMap | ||
* @typedef {{[props: string]: any, components?: ComponentMap}} MDXContentProps | ||
* @typedef {{[exports: string]: unknown, default: (props: MDXContentProps) => any}} ExportMap | ||
*/ | ||
@@ -24,12 +17,11 @@ | ||
* | ||
* @param {VFileCompatible} file MDX document to parse (`string`, `Buffer`, `vfile`, anything that can be given to `vfile`) | ||
* @param {ProcessorAndRunnerOptions} options | ||
* @param {VFileCompatible} vfileCompatible MDX document to parse (`string`, `Buffer`, `vfile`, anything that can be given to `vfile`) | ||
* @param {EvaluateOptions} evaluateOptions | ||
* @return {Promise<ExportMap>} | ||
*/ | ||
export async function evaluate(file, options) { | ||
var config = split(options) | ||
// What is this? | ||
// V8 on Node 12 can’t handle `eval` for collecting coverage, apparently… | ||
export async function evaluate(vfileCompatible, evaluateOptions) { | ||
var {compiletime, runtime} = resolveEvaluateOptions(evaluateOptions) | ||
// V8 on Erbium. | ||
/* c8 ignore next 2 */ | ||
return new Function(String(await compile(file, config.compile)))(config.run) | ||
return run(await compile(vfileCompatible, compiletime), runtime) | ||
} | ||
@@ -40,41 +32,9 @@ | ||
* | ||
* @param {VFileCompatible} file MDX document to parse (`string`, `Buffer`, `vfile`, anything that can be given to `vfile`) | ||
* @param {ProcessorAndRunnerOptions} options | ||
* @param {VFileCompatible} vfileCompatible MDX document to parse (`string`, `Buffer`, `vfile`, anything that can be given to `vfile`) | ||
* @param {EvaluateOptions} evaluateOptions | ||
* @return {ExportMap} | ||
*/ | ||
export function evaluateSync(file, options) { | ||
var config = split(options) | ||
return new Function(String(compileSync(file, config.compile)))(config.run) | ||
export function evaluateSync(vfileCompatible, evaluateOptions) { | ||
var {compiletime, runtime} = resolveEvaluateOptions(evaluateOptions) | ||
return runSync(compileSync(vfileCompatible, compiletime), runtime) | ||
} | ||
/** | ||
* Split processor/compiler options from runner options. | ||
* | ||
* @param {ProcessorAndRunnerOptions} options | ||
*/ | ||
function split(options) { | ||
var { | ||
Fragment, | ||
jsx, | ||
jsxs, | ||
recmaPlugins, | ||
rehypePlugins, | ||
remarkPlugins, | ||
useMDXComponents | ||
} = options || {} | ||
if (!Fragment) throw new Error('Expected `Fragment` given to `evaluate`') | ||
if (!jsx) throw new Error('Expected `jsx` given to `evaluate`') | ||
if (!jsxs) throw new Error('Expected `jsxs` given to `evaluate`') | ||
return { | ||
compile: { | ||
_contain: true, | ||
providerImportSource: useMDXComponents ? '#' : undefined, | ||
recmaPlugins, | ||
rehypePlugins, | ||
remarkPlugins | ||
}, | ||
run: {Fragment, jsx, jsxs, useMDXComponents} | ||
} | ||
} |
@@ -1,1 +0,7 @@ | ||
export function create(template: any, node: any): any; | ||
/** | ||
* @template {import('estree').Node} N | ||
* @param {import('estree').Node} template | ||
* @param {N} node | ||
* @returns {N} | ||
*/ | ||
export function create<N extends import("estree").Node>(template: import('estree').Node, node: N): N; |
@@ -0,1 +1,7 @@ | ||
/** | ||
* @template {import('estree').Node} N | ||
* @param {import('estree').Node} template | ||
* @param {N} node | ||
* @returns {N} | ||
*/ | ||
export function create(template, node) { | ||
@@ -2,0 +8,0 @@ var fields = ['start', 'end', 'loc', 'range', 'comments'] |
{ | ||
"name": "xdm", | ||
"version": "1.4.0", | ||
"version": "1.5.0", | ||
"description": "an MDX compiler", | ||
@@ -47,2 +47,3 @@ "license": "MIT", | ||
"loader-utils": "^2.0.0", | ||
"markdown-extensions": "^1.0.0", | ||
"mdast-util-mdx": "^0.1.0", | ||
@@ -56,4 +57,6 @@ "micromark-extension-mdxjs": "^0.3.0", | ||
"unist-builder": "^2.0.0", | ||
"unist-util-position-from-estree": "^1.0.0", | ||
"unist-util-stringify-position": "^2.0.0", | ||
"unist-util-visit": "^2.0.0" | ||
"unist-util-visit": "^2.0.0", | ||
"vfile": "^4.0.0" | ||
}, | ||
@@ -67,3 +70,2 @@ "devDependencies": { | ||
"@types/babel__core": "^7.0.0", | ||
"@types/babel__parser": "^7.0.0", | ||
"@types/node": "^14.0.0", | ||
@@ -88,2 +90,3 @@ "@types/react": "^17.0.0", | ||
"rehype-katex": "^4.0.0", | ||
"rehype-raw": "^5.1.0", | ||
"remark-cli": "^9.0.0", | ||
@@ -107,4 +110,4 @@ "remark-footnotes": "^3.0.0", | ||
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", | ||
"test-api": "node --experimental-loader=./esm-loader.js test/index.js && node test/register.cjs", | ||
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node --experimental-modules --experimental-loader=./esm-loader.js test/index.js", | ||
"test-api": "node --no-warnings --experimental-loader=./esm-loader.js test/index.js && node test/register.cjs", | ||
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node --no-warnings --experimental-loader=./esm-loader.js test/index.js", | ||
"prebuild": "rimraf \"*.d.ts\" \"{lib,test}/**/*.d.ts\"", | ||
@@ -155,3 +158,3 @@ "build": "tsc", | ||
"files": [ | ||
"lib/evaluate.js" | ||
"lib/run.js" | ||
], | ||
@@ -172,3 +175,3 @@ "rules": { | ||
"files": [ | ||
"lib/esbuild.js" | ||
"lib/integration/esbuild.js" | ||
], | ||
@@ -175,0 +178,0 @@ "rules": { |
254
readme.md
@@ -18,3 +18,3 @@ # xdm | ||
There are also some cool experimental features in [👩🔬 lab][lab]! | ||
There are also some cool experimental features in [👩🔬 Lab][lab]! | ||
@@ -54,5 +54,6 @@ ## Install | ||
* [`createProcessor(options)`](#createprocessoroptions) | ||
* [👩🔬 lab](#-lab) | ||
* [👩🔬 Lab](#-lab) | ||
* [Importing `.mdx` files directly](#importing-mdx-files-directly) | ||
* [Requiring `.mdx` files directly](#requiring-mdx-files-directly) | ||
* [Imports in `evaluate`](#imports-in-evaluate) | ||
* [MDX syntax](#mdx-syntax) | ||
@@ -79,2 +80,3 @@ * [Markdown](#markdown) | ||
* [Frontmatter](#frontmatter) | ||
* [Plugins](#plugins) | ||
* [Differences from `@mdx-js/mdx`](#differences-from-mdx-jsmdx) | ||
@@ -220,3 +222,3 @@ * [Architecture](#architecture) | ||
There is also `xdm/esm-loader.js` and `xdm/register.cjs`, see [👩🔬 lab][lab] | ||
There is also `xdm/esm-loader.js` and `xdm/register.cjs`, see [👩🔬 Lab][lab] | ||
for more info. | ||
@@ -295,2 +297,50 @@ | ||
###### `options.format` | ||
Format the file is in (`'detect' | 'mdx' | 'md'`, default: `'detect'`). | ||
* `'detect'` — use `'markdown'` for files with an extension in `mdExtensions` | ||
and `'mdx'` otherwise | ||
* `'mdx'` — treat file as [MDX][mdx-syntax] | ||
* `'md'` — treat file as plain vanilla markdown | ||
The format cannot be detected if a file is passed without a path or extension: | ||
`mdx` will be assumed. | ||
So pass a full vfile (with `path`) or an object with a path. | ||
<details> | ||
<summary>Example</summary> | ||
```js | ||
compile({contents: '…'}) // Seen as MDX | ||
compile({contents: '…'}, {format: 'md'}) // Seen as markdown | ||
compile({contents: '…', path: 'readme.md'}) // Seen as markdown | ||
// Please do not use `.md` for MDX as other tools won’t know how to handle it. | ||
compile({contents: '…', path: 'readme.md'}, {format: 'mdx'}) // Seen as MDX | ||
compile({contents: '…', path: 'readme.md'}, {mdExtensions: []}) // Seen as MDX | ||
``` | ||
</details> | ||
This option mostly affects [esbuild][] and [Rollup][] plugins, and the | ||
experimental ESM loader + register hook (see [👩🔬 Lab][lab]), because in those | ||
it affects *which* files are “registered”: | ||
* `format: 'mdx'` registers the extensions in `options.mdxExtensions` | ||
* `format: 'md'` registers the extensions in `options.mdExtensions` | ||
* `format: 'detect'` registers both lists of extensions | ||
###### `options.mdExtensions` | ||
List of markdown extensions, with dot (`Array.<string>`, default: `['.md', | ||
'.markdown', '.mdown', '.mkdn', '.mkd', '.mdwn', '.mkdown', '.ron']`). | ||
###### `options.mdxExtensions` | ||
List of MDX extensions, with dot (`Array.<string>`, default: `['.mdx']`). | ||
Has no effect in `compile` or `evaluate`, but does affect [esbuild][], | ||
[Rollup][], and the experimental ESM loader + register hook (see [👩🔬 | ||
Lab][lab]). | ||
###### `options.SourceMapGenerator` | ||
@@ -566,9 +616,15 @@ | ||
Run MDX. | ||
This does not support imports and it’s called **evaluate** because it `eval`s | ||
JavaScript. | ||
It’s called **evaluate** because it `eval`s JavaScript. | ||
To get the full power of MDX it’s suggested to use `compile`, write to a file, | ||
and then run with Node or bundle with [esbuild][]/[Rollup][]/[webpack][]. | ||
But if you trust your content and know that it doesn’t contain imports, | ||
`evaluate` can work. | ||
But if you trust your content, `evaluate` can work. | ||
`evaluate` wraps code in an [`AsyncFunction`][async-function], `evaluateSync` | ||
uses a normal [`Function`][function]. | ||
That means that `evaluate` also supports top-level await. | ||
Typically, `import` (or `export … from`) does not work. | ||
But there is experimental support if a `baseUrl` is passed. | ||
See [Imports in `evaluate`](#imports-in-evaluate) in [👩🔬 Lab][lab]! | ||
###### `file` | ||
@@ -578,2 +634,11 @@ | ||
###### `options` | ||
Most options are the same as [`compile`][compile], with the following | ||
exceptions: | ||
* `providerImportSource` is replaced by `useMDXComponents` | ||
* `jsx*` and `pragma*` options are replaced by `jsx`, `jsxs`, and `Fragment` | ||
* `baseUrl` is an experiment that only works here | ||
###### `options.jsx` | ||
@@ -599,10 +664,2 @@ | ||
###### `options.remarkPlugins` | ||
###### `options.rehypePlugins` | ||
###### `options.recmaPlugins` | ||
Same as for [`compile`][compile]. | ||
###### `options.useMDXComponents` | ||
@@ -624,2 +681,11 @@ | ||
###### `options.baseUrl` | ||
Where to resolve relative imports from (`string?`, example: `import.meta.url`). | ||
If one is set, `import` (and `export … from`) can be handled. | ||
Otherwise, they crash. | ||
Experimental! | ||
See [Imports in `evaluate`](#imports-in-evaluate) in [👩🔬 Lab][lab]! | ||
###### Returns | ||
@@ -663,4 +729,7 @@ | ||
## 👩🔬 lab | ||
Note that `format: 'detect'` does not work here: only `'md'` or `'mdx'` are | ||
allowed (and `'mdx'` is the default). | ||
## 👩🔬 Lab | ||
This section describes experimental features! | ||
@@ -701,4 +770,18 @@ These do not adhere to semver and could break at any time! | ||
Currently, no options are supported. | ||
To pass options, you can make your own loader, such as this `my-loader.js`: | ||
```js | ||
import {createLoader} from 'xdm/esm-loader.js' | ||
var {getFormat, transformSource} = createLoader(/* Options… */) | ||
export {getFormat, transformSource} | ||
``` | ||
Which can then be used with `node --experimental-loader=./my-loader.js`. | ||
Node itself does not yet support multiple loaders, but it is possible to combine | ||
multiple loaders with | ||
[`@node-loader/core`](https://github.com/node-loader/node-loader-core). | ||
### Requiring `.mdx` files directly | ||
@@ -736,7 +819,70 @@ | ||
Currently, no options are supported. | ||
To pass options, you can make your own hook, such as this `my-hook.cjs`: | ||
The register hook uses [`evaluate`][eval]. | ||
That means `import` (and `export … from`) are not supported in `.mdx` files. | ||
```js | ||
'use strict' | ||
var register = require('xdm/lib/integration/require.cjs') | ||
register({/* Options… */}) | ||
``` | ||
Which can then be used with `node -r ./my-hook.js`. | ||
The register hook uses [`evaluateSync`][eval]. | ||
That means `import` (and `export … from`) are not supported when requiring | ||
`.mdx` files. | ||
### Imports in `evaluate` | ||
`evaluate` wraps code in an [`AsyncFunction`][async-function], which means that | ||
it also supports top-level await. | ||
So, as a follow up, **xdm** can turn import statements (`import {x} from 'y'`) | ||
into import expressions (`const {x} = await import('y')`). | ||
There’s one catch: where to import from? | ||
You must pass a `baseUrl` to [`evaluate`][eval]. | ||
Typically, you should use `import.meta.url`. | ||
Say we have a module `data.js`: | ||
```js | ||
export var number = 3.14 | ||
``` | ||
And our module `example.js` looks as follows: | ||
```js | ||
import * as runtime from 'react/jsx-runtime.js' | ||
import {evaluate} from 'xdm' | ||
main() | ||
async function main() { | ||
var baseUrl = 'https://a.full/url' // Typically `import.meta.url` | ||
var {number} = await evaluate( | ||
'export {number} from "./data.js"', | ||
{...runtime, baseUrl} | ||
) | ||
console.log(number) | ||
} | ||
``` | ||
<details> | ||
<summary>Show ± evaluated JS</summary> | ||
```js | ||
;(async function (_runtime) { | ||
const {number} = await import('https://a.full/data.js') | ||
function MDXContent(_props) { /* … */ } | ||
return {number, default: MDXContent} | ||
})(runtime) | ||
``` | ||
</details> | ||
## MDX syntax | ||
@@ -815,2 +961,5 @@ | ||
There are also a couple specific remark/rehype/recma plugins that work with | ||
xdm: see [plugins][]. | ||
#### Caveats | ||
@@ -901,2 +1050,6 @@ | ||
> There is experimental support for `import` (and `export … from`) in `evaluate` | ||
> if a `baseUrl` is passed. | ||
> See [Imports in `evaluate`](#imports-in-evaluate) in [👩🔬 Lab][lab]! | ||
### Expressions | ||
@@ -992,4 +1145,3 @@ | ||
The layout can also be imported and *then* exported with an `export … from` (but | ||
not when using [`evaluate`][eval]): | ||
The layout can also be imported and *then* exported with an `export … from`: | ||
@@ -1068,6 +1220,2 @@ ```js | ||
###### `options.extensions` | ||
List of extensions to support (`Array.<string>`, default: `['.mdx']`). | ||
###### `options.include` | ||
@@ -1291,2 +1439,8 @@ | ||
Works out of the box. | ||
> What about React server components? | ||
> While they are currently very alpha, and not shipping soon, there is an | ||
> [experimental demo](https://wooorm.com/server-components-mdx-demo/) | ||
> combining xdm with RSC. | ||
You can set `providerImportSource` to `'@mdx-js/react'` (which has to be | ||
@@ -1837,2 +1991,5 @@ installed) to support context-based components passing. | ||
> **Note**: [`remark-mdx-frontmatter`](https://github.com/remcohaszing/remark-mdx-frontmatter) | ||
> implements the following (and a bit more!) | ||
We can write a remark plugin which turns the YAML frontmatter into an ESM export | ||
@@ -1926,2 +2083,25 @@ to solve it: | ||
## Plugins | ||
xdm has several extension points: | ||
* Components and a layout (wrapper) can be defined internally or passed at | ||
runtime (see [§ MDX content][mdx-content]) | ||
* Plugins can hook into several stages of compilation ([remark | ||
plugins][remark-plugins], [rehype plugins][rehype-plugins], and the new | ||
recma plugins) | ||
There are also a few of these extensions made specifically for MDX: | ||
###### Components | ||
None yet! | ||
###### Plugins | ||
* [`remark-mdx-images`](https://github.com/remcohaszing/remark-mdx-images) | ||
— change image sources to JavaScript imports | ||
* [`remark-mdx-frontmatter`](https://github.com/remcohaszing/remark-mdx-frontmatter) | ||
— change frontmatter (YAML) metadata to exports | ||
## Differences from `@mdx-js/mdx` | ||
@@ -1944,3 +2124,10 @@ | ||
* No runtime at all | ||
* `export`s work in `evaluate` | ||
**Input**: | ||
* ± same as `main` branch of `@mdx-js/mdx` | ||
* Fix JSX tags to prevent `<p><h1 /></p>` | ||
* Plain markdown can be loaded (`format: 'md'`) | ||
**Output**: | ||
@@ -1959,6 +2146,7 @@ | ||
**Input**: | ||
**Experiments**: | ||
* ± same as `main` branch of `@mdx-js/mdx` | ||
* Fix JSX tags to prevent `<p><h1 /></p>` | ||
* Add support for `import Content from './file.mdx'` in Node | ||
* Add support for `require('./file.mdx')` in Node | ||
* Add support for imports in `evaluate` | ||
@@ -1974,3 +2162,3 @@ ## Architecture | ||
about unified: | ||
[`core.js#L76-L102`](https://github.com/wooorm/xdm/blob/main/lib/core.js#L76-L102). | ||
[`core.js#L76-L102`](https://github.com/wooorm/xdm/blob/main/lib/core.js#L58-L84). | ||
The processor goes through these steps: | ||
@@ -2117,2 +2305,6 @@ | ||
[async-function]: https://developer.mozilla.org/docs/JavaScript/Reference/Global_Objects/AsyncFunction | ||
[function]: https://developer.mozilla.org/docs/JavaScript/Reference/Global_Objects/Function | ||
[compile]: #compilefile-options | ||
@@ -2140,2 +2332,4 @@ | ||
[plugins]: #plugins | ||
[micromark]: https://github.com/micromark/micromark | ||
@@ -2142,0 +2336,0 @@ |
@@ -1,1 +0,1 @@ | ||
export { rollup as default } from "./lib/rollup.js"; | ||
export { rollup as default } from "./lib/integration/rollup.js"; |
@@ -1,1 +0,1 @@ | ||
export {rollup as default} from './lib/rollup.js' | ||
export {rollup as default} from './lib/integration/rollup.js' |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
139443
17.87%61
52.5%2075
21.84%2318
9.13%1
-50%21
16.67%+ Added
+ Added
+ Added
+ Added