Skip to content

Commit

Permalink
Add support for the automatic dev runtime
Browse files Browse the repository at this point in the history
Closes GH-2.
Related-to: mdx-js/mdx#2035.

Reviewed-by: Titus Wormer <tituswormer@gmail.com>
  • Loading branch information
remcohaszing authored May 18, 2022
1 parent a35318a commit c346fbf
Show file tree
Hide file tree
Showing 3 changed files with 343 additions and 22 deletions.
113 changes: 91 additions & 22 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const regex = /@(jsx|jsxFrag|jsxImportSource|jsxRuntime)\s+(\S+)/g
* @typedef {import('estree-jsx').Comment} Comment
* @typedef {import('estree-jsx').Expression} Expression
* @typedef {import('estree-jsx').Pattern} Pattern
* @typedef {import('estree-jsx').ObjectExpression} ObjectExpression
* @typedef {import('estree-jsx').Property} Property
* @typedef {import('estree-jsx').ImportSpecifier} ImportSpecifier
* @typedef {import('estree-jsx').SpreadElement} SpreadElement
Expand Down Expand Up @@ -35,6 +36,8 @@ const regex = /@(jsx|jsxFrag|jsxImportSource|jsxRuntime)\s+(\S+)/g
* @property {string} [importSource='react']
* @property {string} [pragma='React.createElement']
* @property {string} [pragmaFrag='React.Fragment']
* @property {boolean} [development=false]
* @property {string} [filePath]
*/

/**
Expand All @@ -55,7 +58,7 @@ export function buildJsx(tree, options = {}) {
let automatic = options.runtime === 'automatic'
/** @type {Annotations} */
const annotations = {}
/** @type {{fragment?: boolean, jsx?: boolean, jsxs?: boolean}} */
/** @type {{fragment?: boolean, jsx?: boolean, jsxs?: boolean, jsxDEV?: boolean}} */
const imports = {}

walk(tree, {
Expand Down Expand Up @@ -139,6 +142,14 @@ export function buildJsx(tree, options = {}) {
})
}

if (imports.jsxDEV) {
specifiers.push({
type: 'ImportSpecifier',
imported: {type: 'Identifier', name: 'jsxDEV'},
local: {type: 'Identifier', name: '_jsxDEV'}
})
}

if (specifiers.length > 0) {
node.body.unshift({
type: 'ImportDeclaration',
Expand All @@ -148,7 +159,8 @@ export function buildJsx(tree, options = {}) {
value:
(annotations.jsxImportSource ||
options.importSource ||
'react') + '/jsx-runtime'
'react') +
(options.development ? '/jsx-dev-runtime' : '/jsx-runtime')
}
})
}
Expand Down Expand Up @@ -267,19 +279,21 @@ export function buildJsx(tree, options = {}) {
)
}

if (automatic && children.length > 0) {
fields.push({
type: 'Property',
key: {type: 'Identifier', name: 'children'},
value:
children.length > 1
? {type: 'ArrayExpression', elements: children}
: children[0],
kind: 'init',
method: false,
shorthand: false,
computed: false
})
if (automatic) {
if (children.length > 0) {
fields.push({
type: 'Property',
key: {type: 'Identifier', name: 'children'},
value:
children.length > 1
? {type: 'ArrayExpression', elements: children}
: children[0],
kind: 'init',
method: false,
shorthand: false,
computed: false
})
}
} else {
parameters = children
}
Expand Down Expand Up @@ -310,19 +324,74 @@ export function buildJsx(tree, options = {}) {
}

if (automatic) {
if (children.length > 1) {
parameters.push(props || {type: 'ObjectExpression', properties: []})

if (key) {
parameters.push(key)
} else if (options.development) {
parameters.push({type: 'Identifier', name: 'undefined'})
}

const isStaticChildren = children.length > 1

if (options.development) {
imports.jsxDEV = true
callee = {
type: 'Identifier',
name: '_jsxDEV'
}
parameters.push({type: 'Literal', value: isStaticChildren})

/** @type {ObjectExpression} */
const source = {
type: 'ObjectExpression',
properties: [
{
type: 'Property',
method: false,
shorthand: false,
computed: false,
kind: 'init',
key: {type: 'Identifier', name: 'fileName'},
value: {
type: 'Literal',
value: options.filePath || '<source.js>'
}
}
]
}

if (node.loc) {
source.properties.push(
{
type: 'Property',
method: false,
shorthand: false,
computed: false,
kind: 'init',
key: {type: 'Identifier', name: 'lineNumber'},
value: {type: 'Literal', value: node.loc.start.line}
},
{
type: 'Property',
method: false,
shorthand: false,
computed: false,
kind: 'init',
key: {type: 'Identifier', name: 'columnNumber'},
value: {type: 'Literal', value: node.loc.start.column + 1}
}
)
}

parameters.push(source, {type: 'ThisExpression'})
} else if (isStaticChildren) {
imports.jsxs = true
callee = {type: 'Identifier', name: '_jsxs'}
} else {
imports.jsx = true
callee = {type: 'Identifier', name: '_jsx'}
}

parameters.push(props || {type: 'ObjectExpression', properties: []})

if (key) {
parameters.push(key)
}
}
// Classic.
else {
Expand Down
13 changes: 13 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,19 @@ runtime is automatic (`string`, default: `'react'`).
Comment: `@jsxImportSource theSource`.
Note that `/jsx-runtime` is appended to this provided source.

##### `options.development`

Add location info on where a component originated from (`boolean`, default:
`false`).
This helps debugging but adds a lot of code that you don’t want in production.
Only used in the automatic runtime.

###### `options.filePath`

File path to the original source file (`string`, example: `'path/to/file.js'`).
Used in the location info when using the automatic runtime with
`development: true`.

###### `options.pragma`

Identifier or member expression to call when the effective runtime is classic
Expand Down
Loading

0 comments on commit c346fbf

Please sign in to comment.