diff --git a/lib/handlers/element.js b/lib/handlers/element.js index f0718a2..ad04dd6 100644 --- a/lib/handlers/element.js +++ b/lib/handlers/element.js @@ -65,9 +65,10 @@ export function element(node, state) { continue } - prop = info.space - ? hastToReact[info.property] || info.property - : info.attribute + prop = + !state.preserveHtmlProp && info.space + ? hastToReact[info.property] || info.property + : info.attribute if (Array.isArray(value)) { // Accept `array`. diff --git a/lib/state.js b/lib/state.js index 9d19f59..01d6f95 100644 --- a/lib/state.js +++ b/lib/state.js @@ -57,11 +57,17 @@ * it. * @property {Record | null | undefined} [handlers={}] * Custom handlers. + * @property {boolean} [preserveHtmlProp=false] + * Whether to produce JSX props using HTML-style naming, e.g. `xlink:href` + * instead of `xlinkHref`. * * @typedef State * Info passed around about the current state. * @property {Schema} schema * Current schema. + * @property {boolean} preserveHtmlProp + * Whether to produce JSX props using HTML-style naming, e.g. `xlink:href` + * instead of `xlinkHref`. * @property {Array} comments * List of estree comments. * @property {Array} esm @@ -117,6 +123,7 @@ export function createState(options) { return { // Current space. schema: options.space === 'svg' ? svg : html, + preserveHtmlProp: Boolean(options.preserveHtmlProp), // Results. comments: [], esm: [], @@ -220,6 +227,7 @@ function all(parent) { * Nothing. */ function inherit(from, to) { + // @ts-expect-error Test data field only const left = from.data /** @type {Record | undefined} */ let right diff --git a/readme.md b/readme.md index 69101dc..79894b7 100644 --- a/readme.md +++ b/readme.md @@ -232,6 +232,11 @@ Object mapping node types to functions handling the corresponding nodes Merged into the defaults. See [`Handle`][handle]. +###### `preserveHtmlProp` + +Whether to produce JSX props using HTML-style naming, e.g. `xlink:href` instead +of `xlinkHref` (`boolean`, default: `false`). + ### `Space` Namespace (TypeScript type). diff --git a/test.js b/test.js index 0871377..82aab91 100644 --- a/test.js +++ b/test.js @@ -480,6 +480,12 @@ test('toEstree', () => { 'should support SVG w/ an explicit `space`' ) + assert.deepEqual( + toEstree(s('x', {xlinkHref: '#test'}), {preserveHtmlProp: true}), + acornClean(acornParse('')), + 'should support SVG w/ namespaced attribute' + ) + assert.deepEqual( toEstree({ type: 'element', @@ -840,7 +846,6 @@ test('integration (micromark-extension-mdxjs, mdast-util-mdx)', () => { const hast = toHast(mdast, {passThrough}) - // @ts-expect-error: hush. if (clean && hast) visit(hast, passThrough, acornClean) // @ts-expect-error: it’s a node. @@ -923,9 +928,9 @@ test('integration (@babel/plugin-transform-react-jsx, react)', () => { assert.deepEqual( transform('# Hi {"!"}', {runtime: 'automatic'}), [ - 'import { Fragment as _Fragment } from "react/jsx-runtime";', 'import { jsx as _jsx } from "react/jsx-runtime";', 'import { jsxs as _jsxs } from "react/jsx-runtime";', + 'import { Fragment as _Fragment } from "react/jsx-runtime";', '/*#__PURE__*/_jsx(_Fragment, {', ' children: /*#__PURE__*/_jsxs("h1", {', ' children: ["Hi ", /*#__PURE__*/_jsx(Icon, {}), " ", "!"]', @@ -937,7 +942,7 @@ test('integration (@babel/plugin-transform-react-jsx, react)', () => { assert.deepEqual( transform('# Hi {"!"}', {pragma: 'a', pragmaFrag: 'b'}), - 'a("b", null, a("h1", null, "Hi ", a(Icon, null), " ", "!"));', + 'a(b, null, a("h1", null, "Hi ", a(Icon, null), " ", "!"));', 'should integrate w/ `@babel/plugin-transform-react-jsx` (pragma, pragmaFrag)' ) @@ -948,9 +953,9 @@ test('integration (@babel/plugin-transform-react-jsx, react)', () => { ), [ 'import /* a */a from "b";', - 'import { Fragment as _Fragment } from "react/jsx-runtime";', 'import { jsx as _jsx } from "react/jsx-runtime";', 'import { jsxs as _jsxs } from "react/jsx-runtime";', + 'import { Fragment as _Fragment } from "react/jsx-runtime";', '/*#__PURE__*/_jsx(_Fragment, {', ' children: /*#__PURE__*/_jsxs("h1", {', ' children: [" ", /*#__PURE__*/_jsx("x", {', @@ -1074,7 +1079,6 @@ test('integration (@vue/babel-plugin-jsx, Vue 3)', () => { function acornClean(node) { node.sourceType = 'module' - // @ts-expect-error acorn walk(node, {enter}) return JSON.parse(JSON.stringify(node))