micromark-extension-mdx-jsx

micromark extension to support MDX or MDX.js JSX

Usage no npm install needed!

<script type="module">
  import micromarkExtensionMdxJsx from 'https://cdn.skypack.dev/micromark-extension-mdx-jsx';
</script>

README

micromark-extension-mdx-jsx

Build Coverage Downloads Size Sponsors Backers Chat

micromark extension to support MDX (or MDX.js) JSX.

This package provides the low-level modules for integrating with the micromark tokenizer but has no handling of compiling to HTML: go to a syntax tree instead.

When to use this

This package is already included in xdm and mdx-js/mdx (next).

You should probably use micromark-extension-mdx or micromark-extension-mdxjs instead, which combine this package with other MDX features. Alternatively, if you’re using micromark or mdast-util-from-markdown and you don’t want all of MDX, use this package.

Install

This package is ESM only: Node 12+ is needed to use it and it must be imported instead of required.

npm:

npm install micromark-extension-mdx-jsx

Use

import {micromark} from 'micromark'
import {mdxJsx} from 'micromark-extension-mdx-jsx'

const output = micromark('a <b c d="e" /> f', {extensions: [mdxJsx()]})

console.log(output)

Yields:

<p>a  f</p>

…which is rather useless: go to a syntax tree with mdast-util-from-markdown and mdast-util-mdx-expression instead.

API

This package exports the following identifiers: mdxJsx. There is no default export.

The export map supports the endorsed development condition. Run node --conditions development module.js to get instrumented dev code. Without this condition, production code is loaded.

mdxJsx(options?)

A function that can be called with options that returns an extension for micromark to parse JSX (can be passed in extensions).

options
options.acorn

Acorn parser to use (Acorn, optional).

options.acornOptions

Options to pass to acorn (Object, default: {ecmaVersion: 2020, sourceType: 'module'}). All fields can be set. Positional info (loc, range) is set on ES nodes regardless of acorn options.

options.addResult

Whether to add an estree field to the mdxTextJsx and mdxFlowJsx tokens with the results from acorn (boolean, default: false).

Syntax

This extensions support both MDX and MDX.js. The first is agnostic to the programming language (it could contain attribute expressions and attribute value expressions with Rust or so), the last is specific to JavaScript (in which case attribute expressions must be spread expressions). To turn on gnostic mode, pass acorn.

The syntax of JSX supported here is described in W3C Backus–Naur form with the following additions:

  1. A - B — matches any string that matches A but does not match B.
  2. 'string' — same as "string" but with single quotes.
  3. BREAK — lookahead match for a block break opportunity (either EOF (end of file), U+000A LINE FEED (LF), U+000D CARRIAGE RETURN (CR), or another JSX tag)

The syntax is defined as follows, however, do note that interleaving (mixing) of markdown and MDX is defined elsewhere, and that the constraints are imposed in mdast-util-mdx-jsx.

; Entries
mdxFlow ::= *spaceOrTab element *spaceOrTab BREAK
mdxText ::= element

element ::= selfClosing | closed
selfClosing ::=
  ; constraint: tag MUST be named, MUST NOT be closing, and MUST be self-closing
  tag
closed ::=
  ; constraint: tag MUST NOT be closing and MUST NOT be self-closing
  tag
  *data
  ; constraint: tag MUST be closing, MUST NOT be self-closing, MUST NOT have
  ; attributes, and either both tags MUST have the same name or both tags MUST
  ; be nameless
  tag

data ::= element | text

; constraint: markdown whitespace (spaceOrTab | '\r' | '\n') is NOT
; allowed directly after `<` in order to allow `1 < 3` in markdown.
tag ::=
  '<' *1closing
  *1(*whitespace name *1attributesAfterIdentifier *1closing)
  *whitespace '>'

attributesAfterIdentifier ::=
  1*whitespace (attributesBoolean | attributesValue) |
  *whitespace attributesExpression |
attributesAfterValue ::=
  *whitespace (attributesBoolean | attributesExpression | attributesValue)
attributesBoolean ::= key *1attributesAfterIdentifier
; Note: in gnostic mode the value of the expression must instead be a single valid ES spread
; expression
attributesExpression ::= expression *1attributesAfterValue
attributesValue ::= key initializer *1attributesAfterValue

closing ::= *whitespace '/'

name ::= identifier *1(local | members)
key ::= identifier *1local
local ::= *whitespace ':' *whitespace identifier
members ::= member *member
member ::= *whitespace '.' *whitespace identifier

identifier ::= identifierStart *identifierPart
initializer ::= *whitespace '=' *whitespace value
value ::= doubleQuoted | singleQuoted | expression
; Note: in gnostic mode the value must instead be a single valid ES expression
expression ::= '{' *(expressionText | expression) '}'

doubleQuoted ::= '"' *doubleQuotedText '"'
singleQuoted ::= "'" *singleQuotedText "'"

spaceOrTab ::= ' ' | '\t'
text ::= character - '<' - '{'
whitespace ::= esWhitespace
doubleQuotedText ::= character - '"'
singleQuotedText ::= character - "'"
expressionText ::= character - '{' - '}'
identifierStart ::= esIdentifierStart
identifierPart ::= esIdentifierPart | '-'

; Unicode
; Any unicode code point
character ::=

; ECMAScript
; See “IdentifierStart”: <https://tc39.es/ecma262/#prod-IdentifierStart>
esIdentifierStart ::=
; See “IdentifierPart”: <https://tc39.es/ecma262/#prod-IdentifierPart>
esIdentifierPart ::=
; See “Whitespace”: <https://tc39.es/ecma262/#prod-WhiteSpace>
esWhitespace ::=

Errors

In gnostic mode, expressions are parsed with micromark-extension-mdx-expression, which also throws certain errors.

Unexpected end of file $at, expected $expect

This error occurs for many different reasons if something was opened but not closed (source: micromark-extension-mdx-jsx, rule id: unexpected-eof).

Some examples are:

<
</
<a
<a:
<a.
<a b
<a b:
<a b=
<a b="
<a b='
<a b={
<a/

Unexpected character $at, expected $expect

This error occurs for many different reasons if an unexpected character is seen (source: micromark-extension-mdx-jsx, rule id: unexpected-character).

Some examples are:

<.>
</.>
<a?>
<a:+>
<a./>
<a b!>
<a b:1>
<a b=>
<a/->

Tokens

Many tokens are used:

  • mdxJsxFlowTag for the whole JSX tag (<a>)
  • mdxJsxTextTag ^
  • mdxJsxFlowTagMarker for the tag markers (<, >)
  • mdxJsxTextTagMarker ^
  • mdxJsxFlowTagClosingMarker for the / marking a closing tag (</a>)
  • mdxJsxTextTagClosingMarker ^
  • mdxJsxFlowTagSelfClosingMarker for the / marking a self-closing tag (<a/>)
  • mdxJsxTextTagSelfClosingMarker ^
  • mdxJsxFlowTagName for the whole tag name (a:b in <a:b>)
  • mdxJsxTextTagName ^
  • mdxJsxFlowTagNamePrimary for the first name (a in <a:b>)
  • mdxJsxTextTagNamePrimary ^
  • mdxJsxFlowTagNameMemberMarker for the . marking in members (<a.b>)
  • mdxJsxTextTagNameMemberMarker ^
  • mdxJsxFlowTagNameMember for member names (b in <a:b>)
  • mdxJsxTextTagNameMember ^
  • mdxJsxFlowTagNamePrefixMarker for the : between primary and local (<a:b>)
  • mdxJsxTextTagNamePrefixMarker ^
  • mdxJsxFlowTagNameLocal for the local name (b in <a:b>)
  • mdxJsxTextTagNameLocal ^
  • mdxJsxFlowTagExpressionAttribute for whole expression attributes (<a {...b}>)
  • mdxJsxTextTagExpressionAttribute ^
  • mdxJsxFlowTagExpressionAttributeMarker for {, } in expression attributes
  • mdxJsxTextTagExpressionAttributeMarker ^
  • mdxJsxFlowTagExpressionAttributeValue for chunks of what’s inside expression attributes
  • mdxJsxTextTagExpressionAttributeValue ^
  • mdxJsxFlowTagAttribute for a whole normal attribute (<a b>)
  • mdxJsxTextTagAttribute ^
  • mdxJsxFlowTagAttributeName for the whole name of an attribute (b:c in <a b:c>)
  • mdxJsxTextTagAttributeName ^
  • mdxJsxFlowTagAttributeNamePrimary for the first name of an attribute (b in <a b:c>)
  • mdxJsxTextTagAttributeNamePrimary ^
  • mdxJsxFlowTagAttributeNamePrefixMarker for the : between primary and local (<a b:c>)
  • mdxJsxTextTagAttributeNamePrefixMarker ^
  • mdxJsxFlowTagAttributeNameLocal for the local name of an attribute (c in <a b:c>)
  • mdxJsxTextTagAttributeNameLocal ^
  • mdxJsxFlowTagAttributeInitializerMarker for the = between an attribute name and value
  • mdxJsxTextTagAttributeInitializerMarker ^
  • mdxJsxFlowTagAttributeValueLiteral for a string attribute value (<a b="">)
  • mdxJsxTextTagAttributeValueLiteral ^
  • mdxJsxFlowTagAttributeValueLiteralMarker for the quotes around a string attribute value (" or ')
  • mdxJsxTextTagAttributeValueLiteralMarker ^
  • mdxJsxFlowTagAttributeValueLiteralValue for chunks of what’s inside string attribute values
  • mdxJsxTextTagAttributeValueLiteralValue ^
  • mdxJsxFlowTagAttributeValueExpression for an expression attribute value (<a b={1}>)
  • mdxJsxTextTagAttributeValueExpression ^
  • mdxJsxFlowTagAttributeValueExpressionMarker for the { and } of expression attribute values
  • mdxJsxTextTagAttributeValueExpressionMarker ^
  • mdxJsxFlowTagAttributeValueExpressionValue for chunks of what’s inside expression attribute values
  • mdxJsxTextTagAttributeValueExpressionValue ^

Related

Contribute

See contributing.md in micromark/.github for ways to get started. See support.md for ways to get help.

This project has a code of conduct. By interacting with this repository, organization, or community you agree to abide by its terms.

License

MIT © Titus Wormer