Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

xdm

Package Overview
Dependencies
Maintainers
1
Versions
37
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

xdm - npm Package Compare versions

Comparing version 1.5.1 to 1.6.0

14

lib/core.d.ts

@@ -11,2 +11,3 @@ /**

* @property {'mdx' | 'md'} [format='mdx'] Format of the files to be processed
* @property {'program' | 'function-body'} [outputFormat='program'] Whether to compile to a whole program or a function body.
* @property {string[]} [mdExtensions] Extensions (with `.`) for markdown

@@ -17,5 +18,4 @@ * @property {string[]} [mdxExtensions] Extensions (with `.`) for MDX

* @property {PluggableList} [rehypePlugins] List of rehype (hast, HTML) plugins
* @property {boolean} [_contain=false] Semihidden option
*
* @typedef {Omit<RecmaDocumentOptions & RecmaStringifyOptions & RecmaJsxRewriteOptions, '_contain'>} PluginOptions
* @typedef {Omit<RecmaDocumentOptions & RecmaStringifyOptions & RecmaJsxRewriteOptions, 'outputFormat'>} PluginOptions
* @typedef {BaseProcessorOptions & PluginOptions} ProcessorOptions

@@ -49,2 +49,6 @@ */

/**
* Whether to compile to a whole program or a function body.
*/
outputFormat?: 'program' | 'function-body';
/**
* Extensions (with `.`) for markdown

@@ -69,8 +73,4 @@ */

rehypePlugins?: PluggableList;
/**
* Semihidden option
*/
_contain?: boolean;
};
export type PluginOptions = Omit<RecmaDocumentOptions & RecmaStringifyOptions & RecmaJsxRewriteOptions, '_contain'>;
export type PluginOptions = Omit<RecmaDocumentOptions & RecmaStringifyOptions & RecmaJsxRewriteOptions, 'outputFormat'>;
export type ProcessorOptions = BaseProcessorOptions & PluginOptions;

@@ -24,2 +24,3 @@ import unified from 'unified'

* @property {'mdx' | 'md'} [format='mdx'] Format of the files to be processed
* @property {'program' | 'function-body'} [outputFormat='program'] Whether to compile to a whole program or a function body.
* @property {string[]} [mdExtensions] Extensions (with `.`) for markdown

@@ -30,5 +31,4 @@ * @property {string[]} [mdxExtensions] Extensions (with `.`) for MDX

* @property {PluggableList} [rehypePlugins] List of rehype (hast, HTML) plugins
* @property {boolean} [_contain=false] Semihidden option
*
* @typedef {Omit<RecmaDocumentOptions & RecmaStringifyOptions & RecmaJsxRewriteOptions, '_contain'>} PluginOptions
* @typedef {Omit<RecmaDocumentOptions & RecmaStringifyOptions & RecmaJsxRewriteOptions, 'outputFormat'>} PluginOptions
* @typedef {BaseProcessorOptions & PluginOptions} ProcessorOptions

@@ -49,5 +49,5 @@ */

var {
_contain,
jsx,
format,
outputFormat,
providerImportSource,

@@ -78,7 +78,7 @@ recmaPlugins,

.use(rehypeRecma)
.use(recmaDocument, {...rest, _contain})
.use(recmaDocument, {...rest, outputFormat})
// @ts-ignore recma transformer uses an esast node rather than a unist node
.use(recmaJsxRewrite, {providerImportSource, _contain})
.use(recmaJsxRewrite, {providerImportSource, outputFormat})
// @ts-ignore recma transformer uses an esast node rather than a unist node
.use(jsx ? undefined : recmaJsxBuild, {_contain})
.use(jsx ? undefined : recmaJsxBuild, {outputFormat})
// @ts-ignore recma compiler is seen as a transformer

@@ -85,0 +85,0 @@ .use(recmaStringify, {SourceMapGenerator})

@@ -19,2 +19,5 @@ import vfile from 'vfile'

/**
* @param {import('esbuild').PluginBuild} build
*/
function setup(build) {

@@ -24,18 +27,32 @@ build.onLoad({filter: extnamesToRegex(extnames)}, onload)

/**
* @param {import('esbuild').OnLoadArgs} data
*/
async function onload(data) {
var doc = String(await fs.readFile(data.path))
var file = vfile({contents: doc, path: data.path})
/** @type {import('vfile-message').VFileMessage[]} */
var messages = []
var errors = []
var warnings = []
/** @type {import('vfile').VFileContents} */
var contents
/** @type {import('vfile-message').VFileMessage} */
var message
/** @type {import('unist').Point} */
var start
/** @type {import('unist').Point} */
var end
var list
/** @type {number} */
var length
/** @type {number} */
var lineStart
/** @type {number} */
var lineEnd
/** @type {RegExpExecArray} */
var match
/** @type {number} */
var line
/** @type {number} */
var column

@@ -42,0 +59,0 @@

/**
* @typedef RecmaDocumentOptions
* @property {boolean} [_contain] Semihidden option which here results in failing on imports and adding a top-level return statement instead of an export.
* @property {string} [baseUrl] In `evaluate`, resolve relative import statements (and `export from`s) relative to this URL
* @property {'program' | 'function-body'} [outputFormat='program'] Whether to use either `import` and `export` statements to get the runtime (and optionally provider) and export the content, or get values from `arguments` and return things
* @property {boolean} [useDynamicImport=false] Whether to keep `import` (and `export … from`) statements or compile them to dynamic `import()` instead
* @property {string} [baseUrl] Resolve relative `import` (and `export … from`) relative to this URL
* @property {string} [pragma='React.createElement'] Pragma for JSX (used in classic runtime)

@@ -16,11 +17,15 @@ * @property {string} [pragmaFrag='React.Fragment'] Pragma for JSX fragments (used in classic runtime)

*/
export function recmaDocument(options?: RecmaDocumentOptions): (tree: any, file: any) => void;
export function recmaDocument(options?: RecmaDocumentOptions): (tree: any, file: import('vfile').VFile) => void;
export type RecmaDocumentOptions = {
/**
* Semihidden option which here results in failing on imports and adding a top-level return statement instead of an export.
* Whether to use either `import` and `export` statements to get the runtime (and optionally provider) and export the content, or get values from `arguments` and return things
*/
_contain?: boolean;
outputFormat?: 'program' | 'function-body';
/**
* In `evaluate`, resolve relative import statements (and `export from`s) relative to this URL
* Whether to keep `import` (and `export … from`) statements or compile them to dynamic `import()` instead
*/
useDynamicImport?: boolean;
/**
* Resolve relative `import` (and `export … from`) relative to this URL
*/
baseUrl?: string;

@@ -27,0 +32,0 @@ /**

@@ -9,4 +9,5 @@ import u from 'unist-builder'

* @typedef RecmaDocumentOptions
* @property {boolean} [_contain] Semihidden option which here results in failing on imports and adding a top-level return statement instead of an export.
* @property {string} [baseUrl] In `evaluate`, resolve relative import statements (and `export from`s) relative to this URL
* @property {'program' | 'function-body'} [outputFormat='program'] Whether to use either `import` and `export` statements to get the runtime (and optionally provider) and export the content, or get values from `arguments` and return things
* @property {boolean} [useDynamicImport=false] Whether to keep `import` (and `export … from`) statements or compile them to dynamic `import()` instead
* @property {string} [baseUrl] Resolve relative `import` (and `export … from`) relative to this URL
* @property {string} [pragma='React.createElement'] Pragma for JSX (used in classic runtime)

@@ -26,4 +27,5 @@ * @property {string} [pragmaFrag='React.Fragment'] Pragma for JSX fragments (used in classic runtime)

var {
_contain,
baseUrl,
useDynamicImport,
outputFormat = 'program',
pragma = 'React.createElement',

@@ -38,2 +40,6 @@ pragmaFrag = 'React.Fragment',

/**
* @param {*} tree
* @param {import('vfile').VFile} file
*/
function transform(tree, file) {

@@ -43,2 +49,3 @@ var exportedIdentifiers = []

var pragmas = []
var exportAllCount = 0
var layout

@@ -75,3 +82,3 @@ var content

handleImport(
handleEsm(
u('ImportDeclaration', {

@@ -121,71 +128,55 @@ specifiers: [

// ```js
// export function a() {}
// export {a, b as c}
// export {a, b as c} from 'd'
// ```
else if (child.type === 'ExportNamedDeclaration') {
// ```js
// export {a, b as c} from 'd'
// ```
if (child.source) {
// Remove `default` or `as default`, but not `default as`, specifier.
child.specifiers = child.specifiers.filter(function (specifier) {
if (specifier.exported.name === 'default') {
if (layout) {
file.fail(
'Cannot specify multiple layouts (previous: ' +
stringifyPosition(positionFromEstree(layout)) +
')',
positionFromEstree(child),
'recma-document:duplicate-layout'
)
}
else if (child.type === 'ExportNamedDeclaration' && child.source) {
// Remove `default` or `as default`, but not `default as`, specifier.
child.specifiers = child.specifiers.filter(function (specifier) {
if (specifier.exported.name === 'default') {
if (layout) {
file.fail(
'Cannot specify multiple layouts (previous: ' +
stringifyPosition(positionFromEstree(layout)) +
')',
positionFromEstree(child),
'recma-document:duplicate-layout'
)
}
layout = specifier
layout = specifier
// Make it just an import: `import MDXLayout from '…'`.
handleImport(
create(
specifier,
u('ImportDeclaration', {
specifiers: [
// Default as default / something else as default.
specifier.local.name === 'default'
? u('ImportDefaultSpecifier', {
// Make it just an import: `import MDXLayout from '…'`.
handleEsm(
create(
specifier,
u('ImportDeclaration', {
specifiers: [
// Default as default / something else as default.
specifier.local.name === 'default'
? u('ImportDefaultSpecifier', {
local: u('Identifier', {name: 'MDXLayout'})
})
: create(
specifier.local,
u('ImportSpecifier', {
imported: specifier.local,
local: u('Identifier', {name: 'MDXLayout'})
})
: create(
specifier.local,
u('ImportSpecifier', {
imported: specifier.local,
local: u('Identifier', {name: 'MDXLayout'})
})
)
],
source: create(
child.source,
u('Literal', {value: child.source.value})
)
})
)
)
],
source: create(
child.source,
u('Literal', {value: child.source.value})
)
})
)
)
return false
}
return false
}
return true
})
return true
})
// If there are other things imported, keep it.
if (child.specifiers.length > 0) {
handleExport(child)
}
}
// ```js
// export function a() {}
// export class A {}
// export const a = 1
// export {a, b as c}
// ```
else {
// If there are other things imported, keep it.
if (child.specifiers.length > 0) {
handleExport(child)

@@ -197,3 +188,6 @@ }

// ```
else if (child.type === 'ExportAllDeclaration') {
else if (
child.type === 'ExportNamedDeclaration' ||
child.type === 'ExportAllDeclaration'
) {
handleExport(child)

@@ -204,3 +198,3 @@ } else if (

) {
handleImport(child)
handleEsm(child)
} else if (

@@ -228,15 +222,27 @@ child.type === 'ExpressionStatement' &&

if (_contain) {
exportedIdentifiers.push(['MDXContent', 'default'])
exportedIdentifiers.push(['MDXContent', 'default'])
if (outputFormat === 'function-body') {
replacement.push(
u('ReturnStatement', {
argument: u('ObjectExpression', {
properties: exportedIdentifiers.map((d) => {
return u('Property', {
kind: 'init',
shorthand: typeof d === 'string',
key: u('Identifier', {name: typeof d === 'string' ? d : d[1]}),
value: u('Identifier', {name: typeof d === 'string' ? d : d[0]})
properties: [].concat(
Array.from({length: exportAllCount}).map((d, index) =>
u('SpreadElement', {
argument: u('Identifier', {name: '_exportAll' + (index + 1)})
})
),
exportedIdentifiers.map((d) => {
return u('Property', {
kind: 'init',
shorthand: typeof d === 'string',
key: u('Identifier', {
name: typeof d === 'string' ? d : d[1]
}),
value: u('Identifier', {
name: typeof d === 'string' ? d : d[0]
})
})
})
})
)
})

@@ -255,100 +261,127 @@ })

function handleImport(node) {
if (_contain) {
handleImportExportFrom(node)
} else {
replacement.push(node)
}
}
function handleExport(node) {
var child
if (_contain) {
// ```js
// export function a() {}
// export class A {}
// export const a = 1
// ```
if (node.declaration) {
replacement.push(node.declaration)
if (
node.declaration.type === 'FunctionDeclaration' ||
node.declaration.type === 'ClassDeclaration'
) {
exportedIdentifiers.push(node.declaration.id.name)
// ```js
// export function a() {}
// export class A {}
// export var a = 1
// ```
if (node.declaration) {
if (
node.declaration.type === 'FunctionDeclaration' ||
node.declaration.type === 'ClassDeclaration'
) {
exportedIdentifiers.push(node.declaration.id.name)
} else {
for (child of node.declaration.declarations) {
exportedIdentifiers.push(child.id.name)
}
// Must be a variable declaration: other things can’t be exported with
// ESM.
else {
for (child of node.declaration.declarations) {
exportedIdentifiers.push(child.id.name)
}
}
} else if (node.source) {
handleImportExportFrom(node)
}
}
// ```js
// export {a, b as c}
// export {a, b as c} from 'd'
// ```
if (node.specifiers) {
for (child of node.specifiers) {
exportedIdentifiers.push(
child.local.name === child.exported.name
? child.local.name
: [child.local.name, child.exported.name]
)
}
// ```js
// export {a, b as c}
// export {a, b as c} from 'd'
// ```
if (node.specifiers) {
for (child of node.specifiers) {
exportedIdentifiers.push(child.exported.name)
}
} else {
replacement.push(node)
}
handleEsm(node)
}
function handleImportExportFrom(node) {
function handleEsm(node) {
var value
var replace
var id
var declarations
if (!baseUrl) {
file.fail(
'Cannot use `import` or `export … from` in `evaluateSync` or `evaluate` w/o passing `baseUrl`: use `compile`, `compileSync`, or use `evaluate` and pass a `baseUrl`',
positionFromEstree(child),
'recma-document:contain-export'
)
// Rewrite the source of the `import` / `export … from`.
// See: <https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier>
if (baseUrl && node.source) {
value = node.source.value
try {
// A full valid URL.
value = new URL(value)
} catch {
// Relative: `/example.js`, `./example.js`, and `../example.js`.
if (/^\.{0,2}\//.test(value)) {
value = new URL(value, baseUrl)
}
// Otherwise, it’s a bare specifiers.
// For example `some-package`, `@some-package`, and
// `some-package/path`.
// These are supported in Node and browsers plan to support them
// with import maps (<https://github.com/WICG/import-maps>).
}
node.source = create(node.source, u('Literal', {value}))
}
value = node.source.value
if (outputFormat === 'function-body') {
if (node.source) {
if (!useDynamicImport) {
file.fail(
'Cannot use `import` or `export … from` in `evaluate` (outputting a function body) by default: please set `useDynamicImport: true` (and probably specify a `baseUrl`)',
positionFromEstree(node),
'recma-document:invalid-esm-statement'
)
}
// Relative.
if (/^\.{0,2}\//.test(value)) {
value = new URL(value, baseUrl)
// ```
// import a from 'b'
// //=> const {default: a} = await import('b')
// export {a, b as c} from 'd'
// //=> const {a, c: b} = await import('d')
// export * from 'a'
// //=> const _exportAll0 = await import('a')
// ```
id = node.specifiers
? specifiersToObjectPattern(node.specifiers)
: u('Identifier', {name: '_exportAll' + ++exportAllCount})
replace = u('VariableDeclaration', {
kind: 'const',
declarations: [
u('VariableDeclarator', {
id,
init: u('AwaitExpression', {
argument: create(
node,
u('ImportExpression', {source: node.source})
)
})
})
]
})
} else if (node.declaration) {
replace = node.declaration
} else {
declarations = node.specifiers
.filter(
(specifier) => specifier.local.name !== specifier.exported.name
)
.map((specifier) =>
u('VariableDeclarator', {
id: specifier.exported,
init: specifier.local
})
)
if (declarations.length > 0) {
replace = u('VariableDeclaration', {kind: 'const', declarations})
}
}
// Empty
} else {
// Bare specifiers such as `some-package`, `@some-package`, and
// `some-package/path` will crash here.
// Full URLs pass.
try {
value = new URL(value)
} catch {}
replace = node
}
replacement.push(
u('VariableDeclaration', {
kind: 'const',
declarations: [
u('VariableDeclarator', {
id: specifiersToObjectPattern(node.specifiers),
init: u('AwaitExpression', {
argument: create(
node,
u('ImportExpression', {
source: create(node.source, u('Literal', {value}))
})
)
})
})
]
})
)
if (replace) {
replacement.push(replace)
}
}

@@ -355,0 +388,0 @@ }

@@ -5,3 +5,3 @@ /**

* @typedef RecmaJsxBuildOptions
* @property {boolean} [_contain] Semihidden option which here results in getting the automatic runtime from `arguments[0]` instead of importing it
* @property {'program' | 'function-body'} [outputFormat='program'] Whether to keep the import of the automatic runtime or get it from `arguments[0]` instead
*/

@@ -18,5 +18,5 @@ /**

/**
* Semihidden option which here results in getting the automatic runtime from `arguments[0]` instead of importing it
* Whether to keep the import of the automatic runtime or get it from `arguments[0]` instead
*/
_contain?: boolean;
outputFormat?: 'program' | 'function-body';
};

@@ -9,3 +9,3 @@ import build from 'estree-util-build-jsx'

* @typedef RecmaJsxBuildOptions
* @property {boolean} [_contain] Semihidden option which here results in getting the automatic runtime from `arguments[0]` instead of importing it
* @property {'program' | 'function-body'} [outputFormat='program'] Whether to keep the import of the automatic runtime or get it from `arguments[0]` instead
*/

@@ -20,3 +20,3 @@

export function recmaJsxBuild(options = {}) {
var {_contain} = options
var {outputFormat} = options

@@ -31,6 +31,7 @@ return transform

// In contain mode, replace the import that was just generated, and get
// `jsx`, `jsxs`, and `Fragment` from `arguments[0]` instead.
// When compiling to a function body, replace the import that was just
// generated, and get `jsx`, `jsxs`, and `Fragment` from `arguments[0]`
// instead.
if (
_contain &&
outputFormat === 'function-body' &&
tree.body[0] &&

@@ -37,0 +38,0 @@ tree.body[0].type === 'ImportDeclaration' &&

@@ -5,3 +5,3 @@ /**

* @typedef RecmaJsxRewriteOptions
* @property {boolean} [_contain] Semihidden option which here results in getting `useMDXComponents` from `arguments[0]` instead of importing it
* @property {'program' | 'function-body'} [outputFormat='program'] Whether to use an import statement or `arguments[0]` to get the provider
* @property {string} [providerImportSource] Place to import a provider from

@@ -22,5 +22,5 @@ */

/**
* Semihidden option which here results in getting `useMDXComponents` from `arguments[0]` instead of importing it
* Whether to use an import statement or `arguments[0]` to get the provider
*/
_contain?: boolean;
outputFormat?: 'program' | 'function-body';
/**

@@ -27,0 +27,0 @@ * Place to import a provider from

@@ -1,2 +0,2 @@

import isIdentifierName from 'estree-util-is-identifier-name'
import {name as isIdentifierName} from 'estree-util-is-identifier-name'
import {walk} from 'estree-walker'

@@ -11,3 +11,3 @@ import {analyze} from 'periscopic'

* @typedef RecmaJsxRewriteOptions
* @property {boolean} [_contain] Semihidden option which here results in getting `useMDXComponents` from `arguments[0]` instead of importing it
* @property {'program' | 'function-body'} [outputFormat='program'] Whether to use an import statement or `arguments[0]` to get the provider
* @property {string} [providerImportSource] Place to import a provider from

@@ -26,3 +26,3 @@ */

export function recmaJsxRewrite(options = {}) {
var {providerImportSource, _contain} = options
var {providerImportSource, outputFormat} = options
return transform

@@ -50,4 +50,6 @@

if (importProvider) {
// @ts-ignore to do: figure out why `'init'` is not a string?
tree.body.unshift(createImportProvider(providerImportSource, _contain))
tree.body.unshift(
// @ts-ignore to do: figure out why `'init'` is not a string?
createImportProvider(providerImportSource, outputFormat)
)
}

@@ -91,6 +93,3 @@

// But `foo` and `b-ar` are tag names.
else if (
isIdentifierName.name(name.name) &&
!/^[a-z]/.test(name.name)
) {
else if (isIdentifierName(name.name) && !/^[a-z]/.test(name.name)) {
if (

@@ -304,3 +303,3 @@ !scope.components.includes(name.name) &&

function createImportProvider(providerImportSource, contain) {
function createImportProvider(providerImportSource, outputFormat) {
var specifiers = [

@@ -313,3 +312,3 @@ u('ImportSpecifier', {

if (contain) {
if (outputFormat === 'function-body') {
return u('VariableDeclaration', {

@@ -316,0 +315,0 @@ kind: 'const',

@@ -25,2 +25,9 @@ import visit from 'unist-util-visit'

/**
*
* @param {import('unist').Parent} node
* @param {number} index
* @param {import('unist').Parent} parent
* @returns
*/
function onvisit(node, index, parent) {

@@ -27,0 +34,0 @@ var data

@@ -22,2 +22,9 @@ import u from 'unist-builder'

: u('Identifier', {name: 'default'})
var value = specifier.local
if (specifier.type === 'ExportSpecifier') {
value = key
key = specifier.local
}
return create(

@@ -27,7 +34,7 @@ specifier,

kind: 'init',
shorthand: key.name === specifier.local.name,
shorthand: key.name === value.name,
method: false,
computed: false,
key,
value: specifier.local
value
})

@@ -34,0 +41,0 @@ )

@@ -10,8 +10,5 @@ /**

*
* @typedef {Omit<ProcessorOptions, 'jsx' | 'jsxImportSource' | 'jsxRuntime' | 'pragma' | 'pragmaFrag' | 'pragmaImportSource' | 'providerImportSource' | '_contain'> } EvaluateProcessorOptions
* @typedef {Omit<ProcessorOptions, 'jsx' | 'jsxImportSource' | 'jsxRuntime' | 'pragma' | 'pragmaFrag' | 'pragmaImportSource' | 'providerImportSource' | 'outputFormat'> } EvaluateProcessorOptions
*
* @typedef ExtraOptions
* @property {string} baseUrl URL to resolve imports from (typically: pass `import.meta.url`)
*
* @typedef {EvaluateProcessorOptions & RunnerOptions & ExtraOptions} EvaluateOptions
* @typedef {EvaluateProcessorOptions & RunnerOptions} EvaluateOptions
*/

@@ -47,9 +44,3 @@ /**

};
export type EvaluateProcessorOptions = Omit<ProcessorOptions, 'jsx' | 'jsxImportSource' | 'jsxRuntime' | 'pragma' | 'pragmaFrag' | 'pragmaImportSource' | 'providerImportSource' | '_contain'>;
export type ExtraOptions = {
/**
* URL to resolve imports from (typically: pass `import.meta.url`)
*/
baseUrl: string;
};
export type EvaluateOptions = EvaluateProcessorOptions & RunnerOptions & ExtraOptions;
export type EvaluateProcessorOptions = Omit<ProcessorOptions, 'jsx' | 'jsxImportSource' | 'jsxRuntime' | 'pragma' | 'pragmaFrag' | 'pragmaImportSource' | 'providerImportSource' | 'outputFormat'>;
export type EvaluateOptions = EvaluateProcessorOptions & RunnerOptions;

@@ -10,8 +10,5 @@ /**

*
* @typedef {Omit<ProcessorOptions, 'jsx' | 'jsxImportSource' | 'jsxRuntime' | 'pragma' | 'pragmaFrag' | 'pragmaImportSource' | 'providerImportSource' | '_contain'> } EvaluateProcessorOptions
* @typedef {Omit<ProcessorOptions, 'jsx' | 'jsxImportSource' | 'jsxRuntime' | 'pragma' | 'pragmaFrag' | 'pragmaImportSource' | 'providerImportSource' | 'outputFormat'> } EvaluateProcessorOptions
*
* @typedef ExtraOptions
* @property {string} baseUrl URL to resolve imports from (typically: pass `import.meta.url`)
*
* @typedef {EvaluateProcessorOptions & RunnerOptions & ExtraOptions} EvaluateOptions
* @typedef {EvaluateProcessorOptions & RunnerOptions} EvaluateOptions
*/

@@ -35,3 +32,3 @@

...rest,
_contain: true,
outputFormat: 'function-body',
providerImportSource: useMDXComponents ? '#' : undefined

@@ -38,0 +35,0 @@ },

/**
* Create a file and options from a given `vfileCompatible` and options that
* might container `format: 'detect'`.
* might contain `format: 'detect'`.
*

@@ -5,0 +5,0 @@ * @param {import('vfile').VFileCompatible} vfileCompatible

@@ -6,3 +6,3 @@ import vfile from 'vfile'

* Create a file and options from a given `vfileCompatible` and options that
* might container `format: 'detect'`.
* might contain `format: 'detect'`.
*

@@ -9,0 +9,0 @@ * @param {import('vfile').VFileCompatible} vfileCompatible

{
"name": "xdm",
"version": "1.5.1",
"version": "1.6.0",
"description": "an MDX compiler",

@@ -43,3 +43,3 @@ "license": "MIT",

"estree-util-build-jsx": "^1.1.0",
"estree-util-is-identifier-name": "^1.0.0",
"estree-util-is-identifier-name": "^2.0.0",
"estree-walker": "^3.0.0",

@@ -66,3 +66,3 @@ "hast-util-to-estree": "^1.2.0",

"@emotion/react": "^11.0.0",
"@mdx-js/react": "^2.0.0-next.8",
"@mdx-js/react": "2.0.0-next.8",
"@theme-ui/preset-base": "^0.3.0",

@@ -101,2 +101,3 @@ "@types/babel__core": "^7.0.0",

"theme-ui": "^0.3.0",
"type-coverage": "^2.0.0",
"typescript": "^4.0.0",

@@ -112,3 +113,3 @@ "vue": "^3.0.0",

"prebuild": "rimraf \"*.d.ts\" \"{lib,test}/**/*.d.ts\"",
"build": "tsc",
"build": "tsc && type-coverage",
"test": "npm run format && npm run test-coverage && npm run build",

@@ -197,3 +198,8 @@ "prepublishOnly": "npm run build"

]
},
"typeCoverage": {
"atLeast": 80,
"detail": true,
"strict": true
}
}

@@ -8,3 +8,3 @@ # xdm

**xdm** is an MDX compiler that focussed on two things:
**xdm** is an MDX compiler that focusses on two things:

@@ -17,3 +17,4 @@ 1. Compiling the MDX syntax (markdown + JSX) to JavaScript

maps, ESM only, defaulting to an automatic JSX runtime, no Babel, smallish
browser size, more docs, esbuild and Rollup plugins).
browser size, more docs, import/exports in evaluate, esbuild and Rollup
plugins).

@@ -45,2 +46,5 @@ There are also some cool experimental features in [👩‍🔬 Lab][lab]!

Note: if you’re in CommonJS, you *can* use this, but with a dynamic import
expression: `var xdm = await import('xdm')`.
## Contents

@@ -59,3 +63,2 @@

* [Requiring `.mdx` files directly](#requiring-mdx-files-directly)
* [Imports in `evaluate`](#imports-in-evaluate)
* [MDX syntax](#mdx-syntax)

@@ -100,3 +103,3 @@ * [Markdown](#markdown)

Sometimes the term is used for a runtime/helper library.
**xdm** has **no runtime**.
**xdm** has **no runtime**: it’s not needed!

@@ -131,3 +134,3 @@ Most often the term is used for the format: markdown + JS(X) (there are some

```mdx
export const Thing = () => <>World!</>
export var Thing = () => <>World!</>

@@ -143,3 +146,3 @@ # Hello, <Thing />

export const Thing = () => <>World!</>
export var Thing = () => <>World!</>

@@ -158,6 +161,5 @@ export default function MDXContent() {

***
Now for how to get the actual output.
Add some code in `example.js` to compile `example.mdx` to JavaScript:
To compile `example.mdx` add some code in `example.js`:
```js

@@ -175,3 +177,3 @@ import fs from 'fs/promises'

Now, the *actual* output of running `node example.js` is:
The *actual* output of running `node example.js` is:

@@ -182,3 +184,3 @@ ```js

export const Thing = () => _jsx(_Fragment, {children: 'World!'})
export var Thing = () => _jsx(_Fragment, {children: 'World!'})

@@ -203,3 +205,3 @@ function MDXContent(_props) {

* JSX is compiled away to function calls and an import of React
* JSX is compiled away to function calls and an import of React†
* The content component can be given `{components: {h1: MyComponent}}` to use

@@ -210,2 +212,6 @@ something else for the heading

† **xdm** is not coupled to React.
You can also use it with [Preact](#preact), [Vue](#vue), [Emotion](#emotion),
[Theme UI](#theme-ui), etc.
See [§ MDX content][mdx-content] below on how to use the result.

@@ -301,6 +307,18 @@

List of recma plugins, presets, and pairs.
List of recma plugins.
This is a new ecosystem, currently in beta, to transform
[esast](https://github.com/syntax-tree/esast) (JavaScript) trees.
[esast](https://github.com/syntax-tree/esast) trees (JavaScript).
###### `options.mdExtensions`
List of markdown extensions, with dot (`string[]`, default: `['.md',
'.markdown', '.mdown', '.mkdn', '.mkd', '.mdwn', '.mkdown', '.ron']`).
###### `options.mdxExtensions`
List of MDX extensions, with dot (`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.format`

@@ -342,14 +360,145 @@

###### `options.mdExtensions`
###### `options.outputFormat`
List of markdown extensions, with dot (`Array.<string>`, default: `['.md',
'.markdown', '.mdown', '.mkdn', '.mkd', '.mdwn', '.mkdown', '.ron']`).
Output format to generate (`'program' | 'function-body'`, default: `'program'`).
In most cases `'program'` should be used, as it results in a whole program.
Internally, [`evaluate`][eval] uses `outputFormat: 'function-body'` to compile
to code that can be `eval`ed.
In some cases, you might want to do what `evaluate` does in separate steps
yourself, such as when compiling on the server and running on the client.
###### `options.mdxExtensions`
The `'program'` format will use import statements to import the runtime (and
optionally provider) and use an export statement to yield the `MDXContent`
component.
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]).
The `'function-body'` format will get the runtime (and optionally provider) from
`arguments[0]`, rewrite export statements, and use a return statement to yield
what was exported.
Normally, this output format will throw on `import` (and `export … from`)
statements, but you can support them by setting
[`options.useDynamicImport`][usedynamicimport].
<details>
<summary>Example</summary>
A module `example.js`:
```js
import {compile} from 'xdm'
main('export var no = 3.14\n\n# hi {no}')
async function main(code) {
console.log(String(await compile(code, {outputFormat: 'program'}))) // Default
console.log(String(await compile(code, {outputFormat: 'function-body'})))
}
```
…yields:
```js
import {Fragment as _Fragment, jsx as _jsx} from 'react/jsx-runtime'
export var no = 3.14
function MDXContent(_props) { /* … */ }
export default MDXContent
```
```js
const {Fragment: _Fragment, jsx: _jsx} = arguments[0]
var no = 3.14
function MDXContent(_props) { /* … */ }
return {no, default: MDXContent}
```
</details>
###### `options.useDynamicImport`
Whether to compile to dynamic import expressions (`boolean`, default: `false`).
This option applies when [`options.outputFormat`][outputformat] is
`'function-body'`.
**xdm** can turn import statements (`import x from 'y'`) into dynamic imports
(`const {x} = await import('y')`).
This is useful because import statements only work at the top level of
JavaScript modules, whereas `import()` is available inside function bodies.
When you turn `useDynamicImport` on, you should probably set [`options.baseUrl`][baseurl] too.
<details>
<summary>Example</summary>
Say we have a couple modules:
```js
// meta.js:
export var title = 'World'
// numbers.js:
export var no = 3.14
// example.js:
import {compileSync} from 'xdm'
var code = `import {name} from './meta.js'
export {no} from './numbers.js'
# hi {name}!`
console.log(String(compileSync(code, {outputFormat: 'function-body', useDynamicImport: true})))
```
…now running `node example.js` yields:
```js
const {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0]
const {name} = await import('./meta.js')
const {no} = await import('./numbers.js')
function MDXContent(_props) { /* … */ }
return {no, default: MDXContent}
```
</details>
###### `options.baseUrl`
Resolve relative `import` (and `export … from`) from this URL (`string?`,
example: `import.meta.url`).
Relative specifiers are non-absolute URLs that start with `/`, `./`, or `../`.
For example: `/index.js`, `./folder/file.js`, or `../main.js`.
This option is useful when code will run in a different place.
One example is when `.mdx` files are in path *a* but compiled to path *b* and
imports should run relative the path *b*.
Another example is when evaluating code, whether in Node or a browser.
<details>
<summary>Example</summary>
Say we have a module `example.js`:
```js
import {compile} from 'xdm'
main()
async function main() {
var code = 'export {number} from "./data.js"\n\n# hi'
var baseUrl = 'https://a.full/url' // Typically `import.meta.url`
console.log(String(await compile(code, {baseUrl})))
}
```
…now running `node example.js` yields:
```js
import {Fragment as _Fragment, jsx as _jsx} from 'react/jsx-runtime'
export {number} from 'https://a.full/data.js'
function MDXContent(_props) { /* … */ }
export default MDXContent
```
</details>
###### `options.SourceMapGenerator`

@@ -420,3 +569,3 @@

export const Thing = () => React.createElement(React.Fragment, null, 'World!')
export var Thing = () => React.createElement(React.Fragment, null, 'World!')

@@ -454,4 +603,4 @@ function MDXContent(_props) {

-
-export const Thing = () => React.createElement(React.Fragment, null, 'World!')
+export const Thing = () => <>World!</>
-export var Thing = () => React.createElement(React.Fragment, null, 'World!')
+export var Thing = () => <>World!</>

@@ -478,4 +627,3 @@ function MDXContent(_props) {

JSX runtime to use (`string`, `'automatic'` or `'classic'`, default:
`'automatic'`).
JSX runtime to use (`'automatic' | 'classic'`, default: `'automatic'`).
The classic runtime compiles to calls such as `h('p')`, the automatic runtime

@@ -501,4 +649,4 @@ compiles to `import _jsx from '$importSource/jsx-runtime'\n_jsx('p')`.

-export const Thing = () => _jsx(_Fragment, {children: 'World!'})
+export const Thing = () => React.createElement(React.Fragment, null, 'World!')
-export var Thing = () => _jsx(_Fragment, {children: 'World!'})
+export var Thing = () => React.createElement(React.Fragment, null, 'World!')

@@ -566,4 +714,4 @@ ```

-export const Thing = () => React.createElement(React.Fragment, null, 'World!')
+export const Thing = () => preact.createElement(preact.Fragment, null, 'World!')
-export var Thing = () => React.createElement(React.Fragment, null, 'World!')
+export var Thing = () => preact.createElement(preact.Fragment, null, 'World!')

@@ -629,6 +777,6 @@ ```

Run MDX.
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][].
Compile and run MDX.
☢️ It’s called **evaluate** because it `eval`s JavaScript.
When possible, please use `compile`, write to a file, and then run with Node or
bundle with [esbuild][]/[Rollup][]/[webpack][].
But if you trust your content, `evaluate` can work.

@@ -640,5 +788,5 @@

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]!
Typically, `import` (or `export … from`) do not work here.
They can be compiled to dynamic `import()` by passing
[`options.useDynamicImport`][usedynamicimport].

@@ -656,3 +804,3 @@ ###### `file`

* `jsx*` and `pragma*` options are replaced by `jsx`, `jsxs`, and `Fragment`
* `baseUrl` is an experiment that only works here
* `outputFormat` is set to `function-body`

@@ -695,11 +843,2 @@ ###### `options.jsx`

###### `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

@@ -733,3 +872,3 @@

Run MDX.
Compile and run MDX.
Synchronous version of [`evaluate`][eval].

@@ -754,6 +893,5 @@ When possible please use the async `evaluate`.

[ESM loaders](https://nodejs.org/api/esm.html#esm_loaders) are a very
experimental feature in Node, slated to change.
Still, the feature lets projects “hijack” imports, to do all sorts of fancy
things!
[ESM loaders](https://nodejs.org/api/esm.html#esm_loaders) are an experimental
feature in Node, slated to change.
Still, they let projects “hijack” imports, to do all sorts of fancy things!
**xdm** comes with experimental support for importing `.mdx` files with

@@ -805,4 +943,3 @@ on-the-fly compilation, using `xdm/esm-loader.js`:

is a deprecated feature in Node.
Still, the feature lets projects “hijack” `require` calls, to do all sorts of
fancy things!
Still, it lets projects “hijack” `require` calls to do fancy things.
**xdm** comes with support for requiring `.mdx` files with on-the-fly

@@ -850,54 +987,2 @@ evaluation, using `xdm/register.cjs`:

### 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

@@ -1045,3 +1130,3 @@

export const Local = props => <span style={{color: 'red'}} {...props} />
export var Local = props => <span style={{color: 'red'}} {...props} />

@@ -1056,3 +1141,3 @@ An <External /> component and <Local>a local component</Local>.

import data from './population.js'
export const pi = 3.14
export var pi = 3.14

@@ -1062,9 +1147,7 @@ <MyChart data={data} label={'Something with ' + pi} />

Note that when using [`evaluate`][eval], `import`s are not supported but
`export`s can still be used to define things in MDX (except `export … from`,
which also imports).
Typically, `import` (or `export … from`) do not work here.
They can be compiled to dynamic `import()` by passing
[`options.useDynamicImport`][usedynamicimport].
> 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]!
`export`s do work and they are returned.

@@ -1076,3 +1159,3 @@ ### Expressions

```mdx
export const pi = 3.14
export var pi = 3.14

@@ -1090,2 +1173,5 @@ Two 🍰 is: {pi * 2}

All content (headings, paragraphs, etc) you write are exported as the default
export from a compiled MDX file as a component.
It’s possible to pass components in.

@@ -1101,3 +1187,3 @@ Say we have a `message.mdx` file:

```js
import Message from './message.mdx' // Assumes a bundler is used to compile MDX -> JS.
import Message from './message.mdx' // Assumes an integration is used to compile MDX -> JS.

@@ -1194,2 +1280,7 @@ <Message components={{Planet: () => 'Venus'}} />

esbuild takes care of turning modern JavaScript features into syntax that works
wherever you want it to.
No Babel needed.
See esbuild’s docs for more info.
#### Rollup

@@ -1244,3 +1335,3 @@

List of [`picomatch`][pico] patterns to include and/or exclude
(`string`, `RegExp`, `Array.<string|RegExp>`, default: `[]`).
(`string`, `RegExp`, `(string|RegExp)[]`, default: `[]`).

@@ -1289,3 +1380,3 @@ #### Webpack

See
[#11](https://github.com/wooorm/xdm/issues/11#issuecomment-785043772) for
[GH-11](https://github.com/wooorm/xdm/issues/11#issuecomment-785043772) for
details.

@@ -1404,3 +1495,3 @@

```mdx
export const Box = () => (
export var Box = () => (
<div style={{padding: 20, backgroundColor: 'tomato'}} />

@@ -1444,5 +1535,8 @@ )

module.exports = {
// Support MDX files as pages:
pageExtensions: ['mdx', 'tsx', 'ts', 'jsx', 'js'],
// Support loading `.mdx`:
webpack(config) {
config.module.rules.push({
test: /\.mdx/,
test: /\.mdx$/,
use: [{loader: 'xdm/webpack.cjs', options: {}}]

@@ -1462,6 +1556,7 @@ })

> What about React server components?
> While they are currently very alpha, and not shipping soon, there is an
> What about **React server components**?
>
> While they are currently alpha and not shipping soon, there is an
> [experimental demo](https://wooorm.com/server-components-mdx-demo/)
> combining xdm with RSC.
> combining **xdm** with RSC.

@@ -1473,3 +1568,3 @@ You can set `providerImportSource` to `'@mdx-js/react'` (which has to be

import {MDXProvider} from '@mdx-js/react'
import Post from './post.mdx' // Assumes a bundler is used to compile MDX -> JS.
import Post from './post.mdx' // Assumes an integration is used to compile MDX -> JS.

@@ -1552,3 +1647,3 @@ <MDXProvider components={{em: props => <i {...props} />}}>

import {components, ThemeProvider} from 'theme-ui'
import Post from './post.mdx' // Assumes a bundler is used to compile MDX -> JS.
import Post from './post.mdx' // Assumes an integration is used to compile MDX -> JS.

@@ -1716,3 +1811,3 @@ <ThemeProvider theme={base}>

import SyntaxHighlighter from 'react-syntax-highlighter'
import Post from './example.mdx' // Assumes a bundler is used to compile MDX -> JS.
import Post from './example.mdx' // Assumes an integration is used to compile MDX -> JS.

@@ -1943,4 +2038,4 @@ <Post components={{code}} />

```mdx
export const name = 'World'
export const title = 'Hi, ' + name + '!'
export var name = 'World'
export var title = 'Hi, ' + name + '!'

@@ -1953,3 +2048,3 @@ # {title}

```js
import Post from './post.mdx' // Assumes a bundler is used to compile MDX -> JS.
import Post from './post.mdx' // Assumes an integration is used to compile MDX -> JS.

@@ -2018,93 +2113,6 @@ console.log(Post.title) // Prints 'Hi, World!'

> **Note**: [`remark-mdx-frontmatter`](https://github.com/remcohaszing/remark-mdx-frontmatter)
> implements the following (and a bit more!)
That’s what
[`remark-mdx-frontmatter`](https://github.com/remcohaszing/remark-mdx-frontmatter)
does.
We can write a remark plugin which turns the YAML frontmatter into an ESM export
to solve it:
```js
import fs from 'fs/promises'
import yaml from 'js-yaml'
import remarkFrontmatter from 'remark-frontmatter'
import visit from 'unist-util-visit'
import {compile} from 'xdm'
main()
async function main() {
console.log(
await compile(await fs.readFile('example.mdx'), {
remarkPlugins: [remarkFrontmatter, remarkMdxExportYaml]
})
)
}
function remarkMdxExportYaml() {
return (tree) => {
// Find all YAML nodes.
visit(tree, 'yaml', onyaml)
}
}
function onyaml(node, index, parent) {
// Create an estree from the YAML, that looks like:
// `export const frontmatter = JSON.parse("{…}")`
// It looks a bit complex.
// I like using astexplorer (set to JavaScript and espree) to figure out how
// these things should look.
var estree = {
type: 'Program',
body: [
{
type: 'ExportNamedDeclaration',
declaration: {
type: 'VariableDeclaration',
kind: 'const',
declarations: [
{
type: 'VariableDeclarator',
id: {type: 'Identifier', name: 'frontmatter'},
init: {
type: 'CallExpression',
callee: {
type: 'MemberExpression',
object: {type: 'Identifier', name: 'JSON'},
property: {type: 'Identifier', name: 'parse'}
},
arguments: [
{
type: 'Literal',
value: JSON.stringify(yaml.load(node.value))
}
]
}
}
]
}
}
]
}
// Replace the YAML node with MDX ESM.
// We’re still in markdown, but by defining `data.estree`, we tell xdm to use
// that when we’re in JavaScript!
parent.children[index] = {type: 'mdxjsEsm', value: '', data: {estree}}
}
```
<details>
<summary>Show equivalent JS</summary>
```js
export const frontmatter = JSON.parse('{"title":"Hi, World!"}')
function MDXContent() {
return <h1>{frontmatter.title}</h1>
}
export default MDXContent
```
</details>
## Plugins

@@ -2151,2 +2159,4 @@

* `export`s work in `evaluate`
* Add support for compiling import statements to dynamic import expressions
* Add support for resolving import/export sources

@@ -2169,3 +2179,3 @@ **Input**:

instead)
* Exported things are available from `evaluate`
* Support for import and exports in `evaluate`
* Fix a bug with encoding `"` in attributes

@@ -2177,3 +2187,2 @@

* Add support for `require('./file.mdx')` in Node
* Add support for imports in `evaluate`

@@ -2347,2 +2356,8 @@ ## Architecture

[outputformat]: #optionsoutputformat
[baseurl]: #optionsbaseurl
[usedynamicimport]: #optionsusedynamicimport
[sm]: #optionssourcemapgenerator

@@ -2349,0 +2364,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc