Comparing version 1.4.0 to 1.5.0
@@ -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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
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
61
2075
2318
1
21
+ Addedmarkdown-extensions@^1.0.0
+ Addedvfile@^4.0.0
+ Addedmarkdown-extensions@1.1.1(transitive)
+ Addedunist-util-position-from-estree@1.1.2(transitive)