Skip to content

Commit d06ef4a

Browse files
authored
Merge branch 'master' into native-object-spread
2 parents a36ec12 + 8c3b084 commit d06ef4a

File tree

2 files changed

+89
-20
lines changed

2 files changed

+89
-20
lines changed

packages/babel-plugin-transform-jsx-to-htm/index.mjs

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -87,23 +87,33 @@ export default function jsxToHtmBabelPlugin({ types: t }, options = {}) {
8787
}));
8888
buffer = '';
8989
}
90+
91+
const FRAGMENT_EXPR = dottedIdentifier('React.Fragment');
92+
93+
function isFragmentName(node) {
94+
return t.isNodesEquivalent(FRAGMENT_EXPR, node);
95+
}
9096

91-
function getName(node) {
92-
switch (node.type) {
93-
case 'JSXMemberExpression':
94-
return `${node.object.name}.${node.property.name}`
95-
96-
default:
97-
return node.name;
97+
function isComponentName(node) {
98+
return !t.isIdentifier(node) || node.name.match(/^[$_A-Z]/);
99+
}
100+
101+
function getNameExpr(node) {
102+
if (!t.isJSXMemberExpression(node)) {
103+
return t.identifier(node.name);
98104
}
105+
return t.memberExpression(
106+
getNameExpr(node.object),
107+
t.identifier(node.property.name)
108+
);
99109
}
100110

101111
function processChildren(node, name, isFragment) {
102112
const children = t.react.buildChildren(node);
103113
if (children && children.length !== 0) {
104114
if (!isFragment) {
105115
raw('>');
106-
}
116+
}
107117
for (let i = 0; i < children.length; i++) {
108118
let child = children[i];
109119
if (t.isStringLiteral(child)) {
@@ -119,17 +129,17 @@ export default function jsxToHtmBabelPlugin({ types: t }, options = {}) {
119129
}
120130

121131
if (!isFragment) {
122-
if (name.match(/(^[$_A-Z]|\.)/)) {
132+
if (isComponentName(name)) {
123133
raw('</');
124-
expr(t.identifier(name));
134+
expr(name);
125135
raw('>');
126136
}
127137
else {
128138
raw('</');
129-
raw(name);
139+
raw(name.name);
130140
raw('>');
131141
}
132-
}
142+
}
133143
}
134144
else if (!isFragment) {
135145
raw('/>');
@@ -138,17 +148,17 @@ export default function jsxToHtmBabelPlugin({ types: t }, options = {}) {
138148

139149
function processNode(node, path, isRoot) {
140150
const open = node.openingElement;
141-
const name = getName(open.name);
142-
const isFragment = name === 'React.Fragment';
143-
151+
const name = getNameExpr(open.name);
152+
const isFragment = isFragmentName(name);
153+
144154
if (!isFragment) {
145-
if (name.match(/(^[$_A-Z]|\.)/)) {
155+
if (isComponentName(name)) {
146156
raw('<');
147-
expr(t.identifier(name));
157+
expr(name);
148158
}
149159
else {
150160
raw('<');
151-
raw(name);
161+
raw(name.name);
152162
}
153163

154164
if (open.attributes) {
@@ -198,12 +208,13 @@ export default function jsxToHtmBabelPlugin({ types: t }, options = {}) {
198208
expressions.length = 0;
199209

200210
if (isFragment) {
201-
processChildren(path.node, '', true);
211+
processChildren(path.node, null, true);
202212
commit();
203213
const template = t.templateLiteral(quasis, expressions);
204214
const replacement = t.taggedTemplateExpression(tag, template);
205215
path.replaceWith(replacement);
206-
} else {
216+
}
217+
else {
207218
processNode(path.node, path, true);
208219
}
209220

test/babel-transform-jsx.test.mjs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,22 @@ describe('babel-plugin-transform-jsx-to-htm', () => {
6767
expect(
6868
compile('(<div>a</div>);')
6969
).toBe('html`<div>a</div>`;');
70+
71+
expect(
72+
compile('(<div$ />);')
73+
).toBe('html`<div$/>`;');
74+
75+
expect(
76+
compile('(<div$>a</div$>);')
77+
).toBe('html`<div$>a</div$>`;');
78+
79+
expect(
80+
compile('(<div_ />);')
81+
).toBe('html`<div_/>`;');
82+
83+
expect(
84+
compile('(<div_>a</div_>);')
85+
).toBe('html`<div_>a</div_>`;');
7086
});
7187

7288
test('single component element', () => {
@@ -77,6 +93,48 @@ describe('babel-plugin-transform-jsx-to-htm', () => {
7793
expect(
7894
compile('(<Foo>a</Foo>);')
7995
).toBe('html`<${Foo}>a</${Foo}>`;');
96+
97+
expect(
98+
compile('(<$ />);')
99+
).toBe('html`<${$}/>`;');
100+
101+
expect(
102+
compile('(<$>a</$>);')
103+
).toBe('html`<${$}>a</${$}>`;');
104+
105+
expect(
106+
compile('(<_ />);')
107+
).toBe('html`<${_}/>`;');
108+
109+
expect(
110+
compile('(<_>a</_>);')
111+
).toBe('html`<${_}>a</${_}>`;');
112+
113+
expect(
114+
compile('(<_foo />);')
115+
).toBe('html`<${_foo}/>`;');
116+
117+
expect(
118+
compile('(<_foo>a</_foo>);')
119+
).toBe('html`<${_foo}>a</${_foo}>`;');
120+
121+
expect(
122+
compile('(<$foo />);')
123+
).toBe('html`<${$foo}/>`;');
124+
125+
expect(
126+
compile('(<$foo>a</$foo>);')
127+
).toBe('html`<${$foo}>a</${$foo}>`;');
128+
});
129+
130+
test('dotted component element', () => {
131+
expect(
132+
compile('(<a.b.c />);')
133+
).toBe('html`<${a.b.c}/>`;');
134+
135+
expect(
136+
compile('(<a.b.c>a</a.b.c>);')
137+
).toBe('html`<${a.b.c}>a</${a.b.c}>`;');
80138
});
81139

82140
test('static text', () => {

0 commit comments

Comments
 (0)