From adae4b2a1d26e7d50e66f992983bee85deeab605 Mon Sep 17 00:00:00 2001 From: Titus Wormer Date: Sat, 15 Jan 2022 12:01:42 +0100 Subject: [PATCH 1/3] Remove `console.log` --- test/core.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/core.js b/test/core.js index b17c304..535c710 100644 --- a/test/core.js +++ b/test/core.js @@ -540,7 +540,6 @@ export default function Layout({children}) { ) t.fail() } catch (/** @type {unknown} */ error) { - console.log(error) const exception = /** @type {Error} */ (error) t.match( exception.message, From 0c6d8acadbe504050a3d376abf362722fa32ee0b Mon Sep 17 00:00:00 2001 From: Nyi Nyi Lwin Date: Tue, 18 Jan 2022 15:52:08 +0630 Subject: [PATCH 2/3] Fix generated JSX for custom elements Related to: ddcebdb. Related to: remarkjs/remark-math#72. Closes GH-106. Co-authored-by: Titus Wormer --- lib/plugin/recma-jsx-rewrite.js | 9 ++- .../estree-util-to-id-or-member-expression.js | 65 ++++++++++++++++--- package.json | 1 + test/core.js | 20 ++++++ 4 files changed, 80 insertions(+), 15 deletions(-) diff --git a/lib/plugin/recma-jsx-rewrite.js b/lib/plugin/recma-jsx-rewrite.js index 27f2ec3..5a615dc 100644 --- a/lib/plugin/recma-jsx-rewrite.js +++ b/lib/plugin/recma-jsx-rewrite.js @@ -175,11 +175,10 @@ export function recmaJsxRewrite(options = {}) { fnScope.tags.push(id) } - node.openingElement.name = { - type: 'JSXMemberExpression', - object: {type: 'JSXIdentifier', name: '_components'}, - property: name - } + node.openingElement.name = toJsxIdOrMemberExpression([ + '_components', + id + ]) if (node.closingElement) { node.closingElement.name = toJsxIdOrMemberExpression([ diff --git a/lib/util/estree-util-to-id-or-member-expression.js b/lib/util/estree-util-to-id-or-member-expression.js index 0d26845..15719ae 100644 --- a/lib/util/estree-util-to-id-or-member-expression.js +++ b/lib/util/estree-util-to-id-or-member-expression.js @@ -6,23 +6,35 @@ * @typedef {import('estree-jsx').JSXMemberExpression} JSXMemberExpression */ -import {name as isIdentifierName} from 'estree-util-is-identifier-name' +import { + start as esStart, + cont as esCont, + name as isIdentifierName +} from 'estree-util-is-identifier-name' export const toIdOrMemberExpression = toIdOrMemberExpressionFactory( 'Identifier', - 'MemberExpression' + 'MemberExpression', + isIdentifierName ) export const toJsxIdOrMemberExpression = // @ts-expect-error: fine /** @type {(ids: Array) => JSXIdentifier|JSXMemberExpression)} */ - (toIdOrMemberExpressionFactory('JSXIdentifier', 'JSXMemberExpression')) + ( + toIdOrMemberExpressionFactory( + 'JSXIdentifier', + 'JSXMemberExpression', + isJsxIdentifierName + ) + ) /** - * @param {string} [idType] - * @param {string} [memberType] + * @param {string} idType + * @param {string} memberType + * @param {(value: string) => boolean} isIdentifier */ -function toIdOrMemberExpressionFactory(idType, memberType) { +function toIdOrMemberExpressionFactory(idType, memberType, isIdentifier) { return toIdOrMemberExpression /** * @param {Array} ids @@ -35,12 +47,19 @@ function toIdOrMemberExpressionFactory(idType, memberType) { while (++index < ids.length) { const name = ids[index] + const valid = typeof name === 'string' && isIdentifier(name) + + // A value of `asd.123` could be turned into `asd['123']` in the JS form, + // but JSX does not have a form for it, so throw. + /* c8 ignore next 3 */ + if (idType === 'JSXIdentifier' && !valid) { + throw new Error('Cannot turn `' + name + '` into a JSX identifier') + } + /** @type {Identifier|Literal} */ // @ts-expect-error: JSX is fine. - const id = - typeof name === 'string' && isIdentifierName(name) - ? {type: idType, name} - : {type: 'Literal', value: name} + const id = valid ? {type: idType, name} : {type: 'Literal', value: name} + // @ts-expect-error: JSX is fine. object = object ? { @@ -62,3 +81,29 @@ function toIdOrMemberExpressionFactory(idType, memberType) { return object } } + +/** + * Checks if the given string is a valid JSX identifier name. + * @param {string} name + */ +function isJsxIdentifierName(name) { + let index = -1 + + while (++index < name.length) { + // We currently receive valid input, but this catches bugs and is needed + // when externalized. + /* c8 ignore next */ + if (!(index ? jsxCont : esStart)(name.charCodeAt(index))) return false + } + + // `false` if `name` is empty. + return index > 0 +} + +/** + * Checks if the given character code can continue a JSX identifier. + * @param {number} code + */ +function jsxCont(code) { + return code === 45 /* `-` */ || esCont(code) +} diff --git a/package.json b/package.json index b46c3da..bcf0345 100644 --- a/package.json +++ b/package.json @@ -138,6 +138,7 @@ "prettier": true, "rules": { "unicorn/no-await-expression-member": "off", + "unicorn/prefer-code-point": "off", "capitalized-comments": "off", "complexity": "off", "max-depth": "off", diff --git a/test/core.js b/test/core.js index 535c710..1b1b730 100644 --- a/test/core.js +++ b/test/core.js @@ -824,6 +824,26 @@ test('jsx', async (t) => { 'should serialize fragments, expressions' ) + t.equal( + String(compileSync('{}', {jsx: true})), + [ + '/*@jsxRuntime automatic @jsxImportSource react*/', + 'function MDXContent(props = {}) {', + ' let {wrapper: MDXLayout} = props.components || ({});', + ' return MDXLayout ? <_createMdxContent /> : _createMdxContent();', + ' function _createMdxContent() {', + ' let _components = Object.assign({', + ' "a-b": "a-b"', + ' }, props.components);', + ' return <>{<_components.a-b>};', + ' }', + '}', + 'export default MDXContent;', + '' + ].join('\n'), + 'should serialize custom elements inside expressions' + ) + t.equal( String(compileSync('Hello {props.name}', {jsx: true})), [ From 94fc1df7a017ae7ed4f61c92c43478ce6295382c Mon Sep 17 00:00:00 2001 From: Titus Wormer Date: Tue, 18 Jan 2022 10:23:34 +0100 Subject: [PATCH 3/3] 3.3.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bcf0345..49eaa69 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xdm", - "version": "3.3.2", + "version": "3.3.3", "description": "an MDX compiler", "license": "MIT", "keywords": [