🎉 initiate project *astro_rewrite*

This commit is contained in:
sindrekjelsrud 2023-07-19 21:31:30 +02:00
parent ffd4d5e86c
commit 2ba37bfbe3
8658 changed files with 2268794 additions and 2538 deletions

View file

@ -0,0 +1,21 @@
import type {Program} from 'estree'
export {mdxjsEsm, type Options} from './lib/syntax.js'
declare module 'micromark-util-types' {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface Token {
estree?: Program
}
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface TokenTypeMap {
mdxjsEsm: 'mdxjsEsm'
mdxjsEsmData: 'mdxjsEsmData'
}
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface ParseContext {
definedModuleSpecifiers?: string[]
}
}

View file

@ -0,0 +1,2 @@
// Note: more types exposed from `index.d.ts`.
export {mdxjsEsm} from './lib/syntax.js'

View file

@ -0,0 +1,35 @@
/**
* Create an extension for `micromark` to enable MDX ESM syntax.
*
* @param {Options} options
* Configuration (required).
* @returns {Extension}
* Extension for `micromark` that can be passed in `extensions` to enable MDX
* ESM syntax.
*/
export function mdxjsEsm(options: Options): Extension
export type Acorn = import('micromark-util-events-to-acorn').Acorn
export type AcornOptions = import('micromark-util-events-to-acorn').AcornOptions
export type Extension = import('micromark-util-types').Extension
export type State = import('micromark-util-types').State
export type TokenizeContext = import('micromark-util-types').TokenizeContext
export type Tokenizer = import('micromark-util-types').Tokenizer
/**
* Configuration (required).
*/
export type Options = {
/**
* Acorn parser to use (required).
*/
acorn: Acorn
/**
* Configuration for acorn (default: `{ecmaVersion: 2020, locations: true,
* sourceType: 'module'}`).
* all fields except `locations` can be set
*/
acornOptions?: AcornOptions | null | undefined
/**
* Whether to add `estree` fields to tokens with results from acorn.
*/
addResult?: boolean | null | undefined
}

View file

@ -0,0 +1,304 @@
/**
* @typedef {import('micromark-util-events-to-acorn').Acorn} Acorn
* @typedef {import('micromark-util-events-to-acorn').AcornOptions} AcornOptions
* @typedef {import('micromark-util-types').Extension} Extension
* @typedef {import('micromark-util-types').State} State
* @typedef {import('micromark-util-types').TokenizeContext} TokenizeContext
* @typedef {import('micromark-util-types').Tokenizer} Tokenizer
*/
/**
* @typedef Options
* Configuration (required).
* @property {Acorn} acorn
* Acorn parser to use (required).
* @property {AcornOptions | null | undefined} [acornOptions]
* Configuration for acorn (default: `{ecmaVersion: 2020, locations: true,
* sourceType: 'module'}`).
* all fields except `locations` can be set
* @property {boolean | null | undefined} [addResult=false]
* Whether to add `estree` fields to tokens with results from acorn.
*/
import {ok as assert} from 'uvu/assert'
import {blankLine} from 'micromark-core-commonmark'
import {asciiAlpha, markdownLineEnding} from 'micromark-util-character'
import {eventsToAcorn} from 'micromark-util-events-to-acorn'
import {codes} from 'micromark-util-symbol/codes.js'
import {types} from 'micromark-util-symbol/types.js'
import {positionFromEstree} from 'unist-util-position-from-estree'
import {VFileMessage} from 'vfile-message'
const blankLineBefore = {tokenize: tokenizeNextBlank, partial: true}
const allowedAcornTypes = new Set([
'ExportAllDeclaration',
'ExportDefaultDeclaration',
'ExportNamedDeclaration',
'ImportDeclaration'
])
/**
* Create an extension for `micromark` to enable MDX ESM syntax.
*
* @param {Options} options
* Configuration (required).
* @returns {Extension}
* Extension for `micromark` that can be passed in `extensions` to enable MDX
* ESM syntax.
*/
export function mdxjsEsm(options) {
const exportImportConstruct = {tokenize: tokenizeExportImport, concrete: true}
if (!options || !options.acorn || !options.acorn.parse) {
throw new Error('Expected an `acorn` instance passed in as `options.acorn`')
}
const acorn = options.acorn
const acornOptions = Object.assign(
{ecmaVersion: 2020, sourceType: 'module'},
options.acornOptions
)
return {
flow: {
[codes.lowercaseE]: exportImportConstruct,
[codes.lowercaseI]: exportImportConstruct
}
}
/**
* @this {TokenizeContext}
* @type {Tokenizer}
*/
function tokenizeExportImport(effects, ok, nok) {
const self = this
/** @type {Array<string>} */
const definedModuleSpecifiers =
self.parser.definedModuleSpecifiers ||
(self.parser.definedModuleSpecifiers = [])
const eventStart = this.events.length + 1 // Add the main `mdxjsEsm` token
let buffer = ''
return self.interrupt ? nok : start
/**
* Start of MDX ESM.
*
* ```markdown
* > | import a from 'b'
* ^
* ```
*
* @type {State}
*/
function start(code) {
assert(
code === codes.lowercaseE || code === codes.lowercaseI,
'expected `e` or `i`'
)
// Only at the start of a line, not at whitespace or in a container.
if (self.now().column > 1) return nok(code)
effects.enter('mdxjsEsm')
effects.enter('mdxjsEsmData')
effects.consume(code)
// eslint-disable-next-line unicorn/prefer-code-point
buffer += String.fromCharCode(code)
return word
}
/**
* In keyword.
*
* ```markdown
* > | import a from 'b'
* ^^^^^^
* ```
*
* @type {State}
*/
function word(code) {
if (asciiAlpha(code)) {
effects.consume(code)
// @ts-expect-error: definitely a number.
// eslint-disable-next-line unicorn/prefer-code-point
buffer += String.fromCharCode(code)
return word
}
if (
(buffer === 'import' || buffer === 'export') &&
code === codes.space
) {
effects.consume(code)
return inside
}
return nok(code)
}
/**
* In data.
*
* ```markdown
* > | import a from 'b'
* ^
* ```
*
* @type {State}
*/
function inside(code) {
if (code === codes.eof || markdownLineEnding(code)) {
effects.exit('mdxjsEsmData')
return lineStart(code)
}
effects.consume(code)
return inside
}
/**
* At line ending.
*
* ```markdown
* > | import a from 'b'
* ^
* | export {a}
* ```
*
* @type {State}
*/
function lineStart(code) {
if (code === codes.eof) {
return atEnd(code)
}
if (markdownLineEnding(code)) {
return effects.check(blankLineBefore, atEnd, continuationStart)(code)
}
effects.enter('mdxjsEsmData')
return inside(code)
}
/**
* At line ending that continues.
*
* ```markdown
* > | import a from 'b'
* ^
* | export {a}
* ```
*
* @type {State}
*/
function continuationStart(code) {
assert(markdownLineEnding(code))
effects.enter(types.lineEnding)
effects.consume(code)
effects.exit(types.lineEnding)
return lineStart
}
/**
* At end of line (blank or eof).
*
* ```markdown
* > | import a from 'b'
* ^
* ```
*
* @type {State}
*/
function atEnd(code) {
const result = eventsToAcorn(self.events.slice(eventStart), {
acorn,
acornOptions,
prefix:
definedModuleSpecifiers.length > 0
? 'var ' + definedModuleSpecifiers.join(',') + '\n'
: ''
})
if (result.error) {
// Theres an error, which could be solved with more content, and there
// is more content.
if (code !== codes.eof && result.swallow) {
return continuationStart(code)
}
throw new VFileMessage(
'Could not parse import/exports with acorn: ' + String(result.error),
{
line: result.error.loc.line,
column: result.error.loc.column + 1,
offset: result.error.pos
},
'micromark-extension-mdxjs-esm:acorn'
)
}
assert(result.estree, 'expected `estree` to be defined')
// Remove the `VariableDeclaration`.
if (definedModuleSpecifiers.length > 0) {
const declaration = result.estree.body.shift()
assert(declaration)
assert(declaration.type === 'VariableDeclaration')
}
let index = -1
while (++index < result.estree.body.length) {
const node = result.estree.body[index]
if (!allowedAcornTypes.has(node.type)) {
throw new VFileMessage(
'Unexpected `' +
node.type +
'` in code: only import/exports are supported',
positionFromEstree(node),
'micromark-extension-mdxjs-esm:non-esm'
)
}
// Otherwise, when were not interrupting (hacky, because `interrupt` is
// used to parse containers and “sniff” if this is ESM), collect all the
// local values that are imported.
if (node.type === 'ImportDeclaration' && !self.interrupt) {
let index = -1
while (++index < node.specifiers.length) {
const specifier = node.specifiers[index]
definedModuleSpecifiers.push(specifier.local.name)
}
}
}
Object.assign(
effects.exit('mdxjsEsm'),
options.addResult ? {estree: result.estree} : undefined
)
return ok(code)
}
}
}
/** @type {Tokenizer} */
function tokenizeNextBlank(effects, ok, nok) {
return start
/**
* @type {State}
*/
function start(code) {
assert(markdownLineEnding(code))
effects.enter(types.lineEndingBlank)
effects.consume(code)
effects.exit(types.lineEndingBlank)
return effects.attempt(blankLine, ok, nok)
}
}

21
node_modules/micromark-extension-mdxjs-esm/index.d.ts generated vendored Normal file
View file

@ -0,0 +1,21 @@
import type {Program} from 'estree'
export {mdxjsEsm, type Options} from './lib/syntax.js'
declare module 'micromark-util-types' {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface Token {
estree?: Program
}
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface TokenTypeMap {
mdxjsEsm: 'mdxjsEsm'
mdxjsEsmData: 'mdxjsEsmData'
}
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface ParseContext {
definedModuleSpecifiers?: string[]
}
}

2
node_modules/micromark-extension-mdxjs-esm/index.js generated vendored Normal file
View file

@ -0,0 +1,2 @@
// Note: more types exposed from `index.d.ts`.
export {mdxjsEsm} from './lib/syntax.js'

View file

@ -0,0 +1,35 @@
/**
* Create an extension for `micromark` to enable MDX ESM syntax.
*
* @param {Options} options
* Configuration (required).
* @returns {Extension}
* Extension for `micromark` that can be passed in `extensions` to enable MDX
* ESM syntax.
*/
export function mdxjsEsm(options: Options): Extension
export type Acorn = import('micromark-util-events-to-acorn').Acorn
export type AcornOptions = import('micromark-util-events-to-acorn').AcornOptions
export type Extension = import('micromark-util-types').Extension
export type State = import('micromark-util-types').State
export type TokenizeContext = import('micromark-util-types').TokenizeContext
export type Tokenizer = import('micromark-util-types').Tokenizer
/**
* Configuration (required).
*/
export type Options = {
/**
* Acorn parser to use (required).
*/
acorn: Acorn
/**
* Configuration for acorn (default: `{ecmaVersion: 2020, locations: true,
* sourceType: 'module'}`).
* all fields except `locations` can be set
*/
acornOptions?: AcornOptions | null | undefined
/**
* Whether to add `estree` fields to tokens with results from acorn.
*/
addResult?: boolean | null | undefined
}

View file

@ -0,0 +1,279 @@
/**
* @typedef {import('micromark-util-events-to-acorn').Acorn} Acorn
* @typedef {import('micromark-util-events-to-acorn').AcornOptions} AcornOptions
* @typedef {import('micromark-util-types').Extension} Extension
* @typedef {import('micromark-util-types').State} State
* @typedef {import('micromark-util-types').TokenizeContext} TokenizeContext
* @typedef {import('micromark-util-types').Tokenizer} Tokenizer
*/
/**
* @typedef Options
* Configuration (required).
* @property {Acorn} acorn
* Acorn parser to use (required).
* @property {AcornOptions | null | undefined} [acornOptions]
* Configuration for acorn (default: `{ecmaVersion: 2020, locations: true,
* sourceType: 'module'}`).
* all fields except `locations` can be set
* @property {boolean | null | undefined} [addResult=false]
* Whether to add `estree` fields to tokens with results from acorn.
*/
import {blankLine} from 'micromark-core-commonmark'
import {asciiAlpha, markdownLineEnding} from 'micromark-util-character'
import {eventsToAcorn} from 'micromark-util-events-to-acorn'
import {positionFromEstree} from 'unist-util-position-from-estree'
import {VFileMessage} from 'vfile-message'
const blankLineBefore = {
tokenize: tokenizeNextBlank,
partial: true
}
const allowedAcornTypes = new Set([
'ExportAllDeclaration',
'ExportDefaultDeclaration',
'ExportNamedDeclaration',
'ImportDeclaration'
])
/**
* Create an extension for `micromark` to enable MDX ESM syntax.
*
* @param {Options} options
* Configuration (required).
* @returns {Extension}
* Extension for `micromark` that can be passed in `extensions` to enable MDX
* ESM syntax.
*/
export function mdxjsEsm(options) {
const exportImportConstruct = {
tokenize: tokenizeExportImport,
concrete: true
}
if (!options || !options.acorn || !options.acorn.parse) {
throw new Error('Expected an `acorn` instance passed in as `options.acorn`')
}
const acorn = options.acorn
const acornOptions = Object.assign(
{
ecmaVersion: 2020,
sourceType: 'module'
},
options.acornOptions
)
return {
flow: {
[101]: exportImportConstruct,
[105]: exportImportConstruct
}
}
/**
* @this {TokenizeContext}
* @type {Tokenizer}
*/
function tokenizeExportImport(effects, ok, nok) {
const self = this
/** @type {Array<string>} */
const definedModuleSpecifiers =
self.parser.definedModuleSpecifiers ||
(self.parser.definedModuleSpecifiers = [])
const eventStart = this.events.length + 1 // Add the main `mdxjsEsm` token
let buffer = ''
return self.interrupt ? nok : start
/**
* Start of MDX ESM.
*
* ```markdown
* > | import a from 'b'
* ^
* ```
*
* @type {State}
*/
function start(code) {
// Only at the start of a line, not at whitespace or in a container.
if (self.now().column > 1) return nok(code)
effects.enter('mdxjsEsm')
effects.enter('mdxjsEsmData')
effects.consume(code)
// eslint-disable-next-line unicorn/prefer-code-point
buffer += String.fromCharCode(code)
return word
}
/**
* In keyword.
*
* ```markdown
* > | import a from 'b'
* ^^^^^^
* ```
*
* @type {State}
*/
function word(code) {
if (asciiAlpha(code)) {
effects.consume(code)
// @ts-expect-error: definitely a number.
// eslint-disable-next-line unicorn/prefer-code-point
buffer += String.fromCharCode(code)
return word
}
if ((buffer === 'import' || buffer === 'export') && code === 32) {
effects.consume(code)
return inside
}
return nok(code)
}
/**
* In data.
*
* ```markdown
* > | import a from 'b'
* ^
* ```
*
* @type {State}
*/
function inside(code) {
if (code === null || markdownLineEnding(code)) {
effects.exit('mdxjsEsmData')
return lineStart(code)
}
effects.consume(code)
return inside
}
/**
* At line ending.
*
* ```markdown
* > | import a from 'b'
* ^
* | export {a}
* ```
*
* @type {State}
*/
function lineStart(code) {
if (code === null) {
return atEnd(code)
}
if (markdownLineEnding(code)) {
return effects.check(blankLineBefore, atEnd, continuationStart)(code)
}
effects.enter('mdxjsEsmData')
return inside(code)
}
/**
* At line ending that continues.
*
* ```markdown
* > | import a from 'b'
* ^
* | export {a}
* ```
*
* @type {State}
*/
function continuationStart(code) {
effects.enter('lineEnding')
effects.consume(code)
effects.exit('lineEnding')
return lineStart
}
/**
* At end of line (blank or eof).
*
* ```markdown
* > | import a from 'b'
* ^
* ```
*
* @type {State}
*/
function atEnd(code) {
const result = eventsToAcorn(self.events.slice(eventStart), {
acorn,
acornOptions,
prefix:
definedModuleSpecifiers.length > 0
? 'var ' + definedModuleSpecifiers.join(',') + '\n'
: ''
})
if (result.error) {
// Theres an error, which could be solved with more content, and there
// is more content.
if (code !== null && result.swallow) {
return continuationStart(code)
}
throw new VFileMessage(
'Could not parse import/exports with acorn: ' + String(result.error),
{
line: result.error.loc.line,
column: result.error.loc.column + 1,
offset: result.error.pos
},
'micromark-extension-mdxjs-esm:acorn'
)
}
// Remove the `VariableDeclaration`.
if (definedModuleSpecifiers.length > 0) {
const declaration = result.estree.body.shift()
}
let index = -1
while (++index < result.estree.body.length) {
const node = result.estree.body[index]
if (!allowedAcornTypes.has(node.type)) {
throw new VFileMessage(
'Unexpected `' +
node.type +
'` in code: only import/exports are supported',
positionFromEstree(node),
'micromark-extension-mdxjs-esm:non-esm'
)
}
// Otherwise, when were not interrupting (hacky, because `interrupt` is
// used to parse containers and “sniff” if this is ESM), collect all the
// local values that are imported.
if (node.type === 'ImportDeclaration' && !self.interrupt) {
let index = -1
while (++index < node.specifiers.length) {
const specifier = node.specifiers[index]
definedModuleSpecifiers.push(specifier.local.name)
}
}
}
Object.assign(
effects.exit('mdxjsEsm'),
options.addResult
? {
estree: result.estree
}
: undefined
)
return ok(code)
}
}
}
/** @type {Tokenizer} */
function tokenizeNextBlank(effects, ok, nok) {
return start
/**
* @type {State}
*/
function start(code) {
effects.enter('lineEndingBlank')
effects.consume(code)
effects.exit('lineEndingBlank')
return effects.attempt(blankLine, ok, nok)
}
}

22
node_modules/micromark-extension-mdxjs-esm/license generated vendored Normal file
View file

@ -0,0 +1,22 @@
(The MIT License)
Copyright (c) 2020 Titus Wormer <tituswormer@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1 @@
../../../uvu/bin.js

106
node_modules/micromark-extension-mdxjs-esm/package.json generated vendored Normal file
View file

@ -0,0 +1,106 @@
{
"name": "micromark-extension-mdxjs-esm",
"version": "1.0.5",
"description": "micromark extension to support MDX JS import/exports",
"license": "MIT",
"keywords": [
"micromark",
"micromark-extension",
"mdx",
"mdxjs",
"import",
"export",
"js",
"javascript",
"es",
"ecmascript",
"markdown",
"unified"
],
"repository": "micromark/micromark-extension-mdxjs-esm",
"bugs": "https://github.com/micromark/micromark-extension-mdxjs-esm/issues",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
},
"author": "Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)",
"contributors": [
"Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)"
],
"sideEffects": false,
"type": "module",
"main": "index.js",
"types": "index.d.ts",
"files": [
"dev/",
"lib/",
"index.d.ts",
"index.js"
],
"exports": {
"development": "./dev/index.js",
"default": "./index.js"
},
"dependencies": {
"@types/estree": "^1.0.0",
"micromark-core-commonmark": "^1.0.0",
"micromark-util-character": "^1.0.0",
"micromark-util-events-to-acorn": "^1.0.0",
"micromark-util-symbol": "^1.0.0",
"micromark-util-types": "^1.0.0",
"unist-util-position-from-estree": "^1.1.0",
"uvu": "^0.5.0",
"vfile-message": "^3.0.0"
},
"devDependencies": {
"@types/acorn": "^4.0.0",
"@types/node": "^20.0.0",
"acorn": "^8.0.0",
"acorn-jsx": "^5.0.0",
"c8": "^7.0.0",
"micromark": "^3.0.0",
"micromark-build": "^1.0.0",
"prettier": "^2.0.0",
"remark-cli": "^11.0.0",
"remark-preset-wooorm": "^9.0.0",
"type-coverage": "^2.0.0",
"typescript": "^5.0.0",
"xo": "^0.54.0"
},
"scripts": {
"prepack": "npm run build && npm run format",
"build": "tsc --build --clean && tsc --build && type-coverage && micromark-build",
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix",
"test-api-prod": "node --conditions production test/index.js",
"test-api-dev": "node --conditions development test/index.js",
"test-api": "npm run test-api-dev && npm run test-api-prod",
"test-coverage": "c8 --100 --reporter lcov npm run test-api",
"test": "npm run build && npm run format && npm run test-coverage"
},
"prettier": {
"tabWidth": 2,
"useTabs": false,
"singleQuote": true,
"bracketSpacing": false,
"semi": false,
"trailingComma": "none"
},
"xo": {
"prettier": true,
"rules": {
"n/file-extension-in-import": "off",
"unicorn/no-this-assignment": "off"
}
},
"remarkConfig": {
"plugins": [
"preset-wooorm"
]
},
"typeCoverage": {
"atLeast": 100,
"detail": true,
"strict": true,
"ignoreCatch": true
}
}

366
node_modules/micromark-extension-mdxjs-esm/readme.md generated vendored Normal file
View file

@ -0,0 +1,366 @@
# micromark-extension-mdxjs-esm
[![Build][build-badge]][build]
[![Coverage][coverage-badge]][coverage]
[![Downloads][downloads-badge]][downloads]
[![Size][size-badge]][size]
[![Sponsors][sponsors-badge]][collective]
[![Backers][backers-badge]][collective]
[![Chat][chat-badge]][chat]
[micromark][] extension to support [MDX][mdxjs] ESM (`import x from 'y'`).
## Contents
* [What is this?](#what-is-this)
* [When to use this](#when-to-use-this)
* [Install](#install)
* [Use](#use)
* [API](#api)
* [`mdxjsEsm(options)`](#mdxjsesmoptions)
* [`Options`](#options)
* [Authoring](#authoring)
* [Syntax](#syntax)
* [Errors](#errors)
* [Could not parse import/exports with acorn: $error](#could-not-parse-importexports-with-acorn-error)
* [Unexpected `$type` in code: only import/exports are supported](#unexpected-type-in-code-only-importexports-are-supported)
* [Tokens](#tokens)
* [Types](#types)
* [Compatibility](#compatibility)
* [Security](#security)
* [Related](#related)
* [Contribute](#contribute)
* [License](#license)
## What is this?
This package contains an extension that adds support for the ESM syntax enabled
by [MDX][mdxjs] to [`micromark`][micromark].
These extensions are used inside MDX.
It matches how imports and exports work in JavaScript through acorn.
This package is aware of JavaScript syntax.
## When to use this
This project is useful when you want to support ESM in markdown.
You can use this extension when you are working with [`micromark`][micromark].
To support all MDX features, use
[`micromark-extension-mdxjs`][micromark-extension-mdxjs] instead.
When you need a syntax tree, combine this package with
[`mdast-util-mdxjs-esm`][mdast-util-mdxjs-esm].
All these packages are used in [`remark-mdx`][remark-mdx], which focusses on
making it easier to transform content by abstracting these internals away.
When you are using [`mdx-js/mdx`][mdxjs], all of this is already included.
## Install
This package is [ESM only][esm].
In Node.js (version 16+), install with [npm][]:
```sh
npm install micromark-extension-mdxjs-esm
```
In Deno with [`esm.sh`][esmsh]:
```js
import {mdxjsEsm} from 'https://esm.sh/micromark-extension-mdxjs-esm@1'
```
In browsers with [`esm.sh`][esmsh]:
```html
<script type="module">
import {mdxjsEsm} from 'https://esm.sh/micromark-extension-mdxjs-esm@1?bundle'
</script>
```
## Use
```js
import {Parser} from 'acorn'
import acornJsx from 'acorn-jsx'
import {micromark} from 'micromark'
import {mdxjsEsm} from 'micromark-extension-mdxjs-esm'
const acorn = Parser.extend(acornJsx())
const output = micromark('import a from "b"\n\n# c', {
extensions: [mdxjsEsm({acorn})]
})
console.log(output)
```
Yields:
```html
<h1>c</h1>
```
…which is useless: go to a syntax tree with
[`mdast-util-from-markdown`][mdast-util-from-markdown] and
[`mdast-util-mdxjs-esm`][mdast-util-mdxjs-esm] instead.
## API
This package exports the identifier [`mdxjsEsm`][api-mdxjs-esm].
There is no default export.
The export map supports the [`development` condition][development].
Run `node --conditions development module.js` to get instrumented dev code.
Without this condition, production code is loaded.
### `mdxjsEsm(options)`
Create an extension for `micromark` to enable MDX ESM syntax.
###### Parameters
* `options` ([`Options`][api-options], required)
— configuration
###### Returns
Extension for `micromark` that can be passed in `extensions` to enable MDX
ESM syntax ([`Extension`][micromark-extension]).
### `Options`
Configuration (TypeScript type).
###### Fields
* `acorn` ([`Acorn`][acorn], required)
— acorn parser to use
* `acornOptions` ([`AcornOptions`][acorn-options], default:
`{ecmaVersion: 2020, locations: true, sourceType: 'module'}`)
— configuration for acorn; all fields except `locations` can be set
* `addResult` (`boolean`, default: `false`)
— whether to add `estree` fields to tokens with results from acorn
## Authoring
When authoring markdown with ESM, make sure to follow export and import
statements with blank lines before more markdown.
All valid imports and exports are supported, depending on what the given acorn
instance and configuration supports.
When the lowercase strings `export` or `import` are found, followed by a space,
we expect JavaScript.
Otherwise, like normal in markdown, we exit and itll end up as a paragraph.
We continue parsing until we find a blank line.
At that point, we parse with acorn: it if parses, we found our block.
Otherwise, if parsing failed at the last character, we assume its a blank line
in code: we continue on until the next blank line and try again.
Otherwise, the acorn error is thrown.
Some examples of valid export and import statements:
```js
import a from 'b'
import * as a from 'b'
import {a} from 'b'
import {a as b} from 'c'
import a, {b as c} from 'd'
import a, * as b from 'c'
import 'a'
export var a = ''
export const a = ''
export let a = ''
export var a, b
export var a = 'a', b = 'b'
export function a() {}
export class a {}
export var {a} = {}
export var {a: b} = {}
export var [a] = []
export default a = 1
export default function a() {}
export default class a {}
export * from 'a'
export * as a from 'b'
export {a} from 'b'
export {a as b} from 'c'
export {default} from 'b'
export {default as a, b} from 'c'
{/* Blank lines are supported in expressions: */}
export function a() {
return 'b'
}
{/* A blank line must be used after import/exports: this is incorrect! */}
import a from 'b'
## Hello, world!
```
## Syntax
ESM forms with the following BNF:
```bnf
; Restriction: the entire construct must be valid JavaScript.
mdx_esm ::= word ' ' *line *(eol *line)
word ::= 'e' 'x' 'p' 'o' 'r' 't' | 'i' 'm' 'p' 'o' 'r' 't'
```
This construct must be followed by a blank line or eof (end of file).
## Errors
### Could not parse import/exports with acorn: $error
This error occurs if acorn crashes (source: `micromark-extension-mdxjs-esm`,
rule id: `acorn`).
For example:
```js
import 1/1
```
### Unexpected `$type` in code: only import/exports are supported
This error occurs when a non-ESM construct is found (source:
`micromark-extension-mdxjs-esm`, rule id: `non-esm`).
For example:
```js
export var a = 1
var b
```
## Tokens
An `mdxjsEsm` token is used to reflect the block of import/exports in markdown.
It includes:
* `lineEnding` for the `\r`, `\n`, and `\r\n`
* `lineEndingBlank` for the same characters but when after potential
whitespace and another line ending
* `whitespace` for markdown spaces and tabs in blank lines
* `mdxjsEsmData` for any character in a line of `mdxjsEsm`
## Types
This package is fully typed with [TypeScript][].
It exports the additional type [`Options`][api-options].
## Compatibility
Projects maintained by the unified collective are compatible with all maintained
versions of Node.js.
As of now, that is Node.js 16+.
Our projects sometimes work with older versions, but this is not guaranteed.
These extensions work with `micromark` version 3+.
## Security
This package is safe.
## Related
* [`micromark-extension-mdxjs`][micromark-extension-mdxjs]
— support all MDX syntax
* [`mdast-util-mdxjs-esm`][mdast-util-mdxjs-esm]
— support MDX ESM in mdast
* [`remark-mdx`][remark-mdx]
— support all MDX syntax in remark
## Contribute
See [`contributing.md` in `micromark/.github`][contributing] for ways to get
started.
See [`support.md`][support] for ways to get help.
This project has a [code of conduct][coc].
By interacting with this repository, organization, or community you agree to
abide by its terms.
## License
[MIT][license] © [Titus Wormer][author]
<!-- Definitions -->
[build-badge]: https://github.com/micromark/micromark-extension-mdxjs-esm/workflows/main/badge.svg
[build]: https://github.com/micromark/micromark-extension-mdxjs-esm/actions
[coverage-badge]: https://img.shields.io/codecov/c/github/micromark/micromark-extension-mdxjs-esm.svg
[coverage]: https://codecov.io/github/micromark/micromark-extension-mdxjs-esm
[downloads-badge]: https://img.shields.io/npm/dm/micromark-extension-mdxjs-esm.svg
[downloads]: https://www.npmjs.com/package/micromark-extension-mdxjs-esm
[size-badge]: https://img.shields.io/bundlephobia/minzip/micromark-extension-mdxjs-esm.svg
[size]: https://bundlephobia.com/result?p=micromark-extension-mdxjs-esm
[sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg
[backers-badge]: https://opencollective.com/unified/backers/badge.svg
[collective]: https://opencollective.com/unified
[chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg
[chat]: https://github.com/micromark/micromark/discussions
[npm]: https://docs.npmjs.com/cli/install
[esmsh]: https://esm.sh
[license]: license
[author]: https://wooorm.com
[contributing]: https://github.com/micromark/.github/blob/HEAD/contributing.md
[support]: https://github.com/micromark/.github/blob/HEAD/support.md
[coc]: https://github.com/micromark/.github/blob/HEAD/code-of-conduct.md
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[typescript]: https://www.typescriptlang.org
[development]: https://nodejs.org/api/packages.html#packages_resolving_user_conditions
[micromark]: https://github.com/micromark/micromark
[micromark-extension]: https://github.com/micromark/micromark#syntaxextension
[micromark-extension-mdxjs]: https://github.com/micromark/micromark-extension-mdxjs
[mdast-util-mdxjs-esm]: https://github.com/syntax-tree/mdast-util-mdxjs-esm
[mdast-util-from-markdown]: https://github.com/syntax-tree/mdast-util-from-markdown
[remark-mdx]: https://mdxjs.com/packages/remark-mdx/
[mdxjs]: https://mdxjs.com
[acorn]: https://github.com/acornjs/acorn
[acorn-options]: https://github.com/acornjs/acorn/blob/96c721dbf89d0ccc3a8c7f39e69ef2a6a3c04dfa/acorn/dist/acorn.d.ts#L16
[api-mdxjs-esm]: #mdxjsesmoptions
[api-options]: #options