Skip to content

Commit c346fbf

Browse files
authored
Add support for the automatic dev runtime
Closes GH-2. Related-to: mdx-js/mdx#2035. Reviewed-by: Titus Wormer <tituswormer@gmail.com>
1 parent a35318a commit c346fbf

File tree

3 files changed

+343
-22
lines changed

3 files changed

+343
-22
lines changed

index.js

Lines changed: 91 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const regex = /@(jsx|jsxFrag|jsxImportSource|jsxRuntime)\s+(\S+)/g
88
* @typedef {import('estree-jsx').Comment} Comment
99
* @typedef {import('estree-jsx').Expression} Expression
1010
* @typedef {import('estree-jsx').Pattern} Pattern
11+
* @typedef {import('estree-jsx').ObjectExpression} ObjectExpression
1112
* @typedef {import('estree-jsx').Property} Property
1213
* @typedef {import('estree-jsx').ImportSpecifier} ImportSpecifier
1314
* @typedef {import('estree-jsx').SpreadElement} SpreadElement
@@ -35,6 +36,8 @@ const regex = /@(jsx|jsxFrag|jsxImportSource|jsxRuntime)\s+(\S+)/g
3536
* @property {string} [importSource='react']
3637
* @property {string} [pragma='React.createElement']
3738
* @property {string} [pragmaFrag='React.Fragment']
39+
* @property {boolean} [development=false]
40+
* @property {string} [filePath]
3841
*/
3942

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

6164
walk(tree, {
@@ -139,6 +142,14 @@ export function buildJsx(tree, options = {}) {
139142
})
140143
}
141144

145+
if (imports.jsxDEV) {
146+
specifiers.push({
147+
type: 'ImportSpecifier',
148+
imported: {type: 'Identifier', name: 'jsxDEV'},
149+
local: {type: 'Identifier', name: '_jsxDEV'}
150+
})
151+
}
152+
142153
if (specifiers.length > 0) {
143154
node.body.unshift({
144155
type: 'ImportDeclaration',
@@ -148,7 +159,8 @@ export function buildJsx(tree, options = {}) {
148159
value:
149160
(annotations.jsxImportSource ||
150161
options.importSource ||
151-
'react') + '/jsx-runtime'
162+
'react') +
163+
(options.development ? '/jsx-dev-runtime' : '/jsx-runtime')
152164
}
153165
})
154166
}
@@ -267,19 +279,21 @@ export function buildJsx(tree, options = {}) {
267279
)
268280
}
269281

270-
if (automatic && children.length > 0) {
271-
fields.push({
272-
type: 'Property',
273-
key: {type: 'Identifier', name: 'children'},
274-
value:
275-
children.length > 1
276-
? {type: 'ArrayExpression', elements: children}
277-
: children[0],
278-
kind: 'init',
279-
method: false,
280-
shorthand: false,
281-
computed: false
282-
})
282+
if (automatic) {
283+
if (children.length > 0) {
284+
fields.push({
285+
type: 'Property',
286+
key: {type: 'Identifier', name: 'children'},
287+
value:
288+
children.length > 1
289+
? {type: 'ArrayExpression', elements: children}
290+
: children[0],
291+
kind: 'init',
292+
method: false,
293+
shorthand: false,
294+
computed: false
295+
})
296+
}
283297
} else {
284298
parameters = children
285299
}
@@ -310,19 +324,74 @@ export function buildJsx(tree, options = {}) {
310324
}
311325

312326
if (automatic) {
313-
if (children.length > 1) {
327+
parameters.push(props || {type: 'ObjectExpression', properties: []})
328+
329+
if (key) {
330+
parameters.push(key)
331+
} else if (options.development) {
332+
parameters.push({type: 'Identifier', name: 'undefined'})
333+
}
334+
335+
const isStaticChildren = children.length > 1
336+
337+
if (options.development) {
338+
imports.jsxDEV = true
339+
callee = {
340+
type: 'Identifier',
341+
name: '_jsxDEV'
342+
}
343+
parameters.push({type: 'Literal', value: isStaticChildren})
344+
345+
/** @type {ObjectExpression} */
346+
const source = {
347+
type: 'ObjectExpression',
348+
properties: [
349+
{
350+
type: 'Property',
351+
method: false,
352+
shorthand: false,
353+
computed: false,
354+
kind: 'init',
355+
key: {type: 'Identifier', name: 'fileName'},
356+
value: {
357+
type: 'Literal',
358+
value: options.filePath || '<source.js>'
359+
}
360+
}
361+
]
362+
}
363+
364+
if (node.loc) {
365+
source.properties.push(
366+
{
367+
type: 'Property',
368+
method: false,
369+
shorthand: false,
370+
computed: false,
371+
kind: 'init',
372+
key: {type: 'Identifier', name: 'lineNumber'},
373+
value: {type: 'Literal', value: node.loc.start.line}
374+
},
375+
{
376+
type: 'Property',
377+
method: false,
378+
shorthand: false,
379+
computed: false,
380+
kind: 'init',
381+
key: {type: 'Identifier', name: 'columnNumber'},
382+
value: {type: 'Literal', value: node.loc.start.column + 1}
383+
}
384+
)
385+
}
386+
387+
parameters.push(source, {type: 'ThisExpression'})
388+
} else if (isStaticChildren) {
314389
imports.jsxs = true
315390
callee = {type: 'Identifier', name: '_jsxs'}
316391
} else {
317392
imports.jsx = true
318393
callee = {type: 'Identifier', name: '_jsx'}
319394
}
320-
321-
parameters.push(props || {type: 'ObjectExpression', properties: []})
322-
323-
if (key) {
324-
parameters.push(key)
325-
}
326395
}
327396
// Classic.
328397
else {

readme.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,19 @@ runtime is automatic (`string`, default: `'react'`).
113113
Comment: `@jsxImportSource theSource`.
114114
Note that `/jsx-runtime` is appended to this provided source.
115115

116+
##### `options.development`
117+
118+
Add location info on where a component originated from (`boolean`, default:
119+
`false`).
120+
This helps debugging but adds a lot of code that you don’t want in production.
121+
Only used in the automatic runtime.
122+
123+
###### `options.filePath`
124+
125+
File path to the original source file (`string`, example: `'path/to/file.js'`).
126+
Used in the location info when using the automatic runtime with
127+
`development: true`.
128+
116129
###### `options.pragma`
117130

118131
Identifier or member expression to call when the effective runtime is classic

0 commit comments

Comments
 (0)