Skip to content

Commit 917fc90

Browse files
authored
Merge branch 'master' into megamix
2 parents a9154f0 + 434c58e commit 917fc90

File tree

4 files changed

+98
-62
lines changed

4 files changed

+98
-62
lines changed

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@
6868
"@babel/core": "^7.2.2",
6969
"@babel/preset-env": "^7.1.6",
7070
"babel-jest": "^24.1.0",
71-
"babel-plugin-jsx-pragmatic": "^1.0.2",
7271
"babel-preset-env": "^1.7.0",
7372
"eslint": "^5.2.0",
7473
"eslint-config-developit": "^1.1.1",

packages/babel-plugin-transform-jsx-to-htm/README.md

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# babel-plugin-transform-jsx-to-htm
22

3-
This plugin converts JSX into Tagged Templates that work with things like [htm] and [lit-html].
3+
This plugin converts JSX into Tagged Templates that work with [htm].
44

55
```js
66
// INPUT:
@@ -32,45 +32,42 @@ The following options are available:
3232

3333
| Option | Type | Default | Description
3434
|--------|---------|----------|------------
35-
| `tag` | String | `"html"` | The "tag" function to prefix [Tagged Templates] with.<br> _Useful when [Auto-importing a tag function](#auto-importing-the-tag)._
36-
| `html` | Boolean | `false` | `true` outputs HTML-like templates for use with [lit-html].<br> _The is default XML-like, with self-closing tags._
35+
| `tag` | String | `"html"` | The "tag" function to prefix [Tagged Templates] with.
36+
| `import` | `false`\|String\|Object | `false` | Auto-import a tag function, off by default.<br>_See [Auto-importing a tag function](#auto-importing-the-tag) for an example._
3737

3838
Options are passed to a Babel plugin using a nested Array:
3939

4040
```js
4141
"plugins": [
4242
["babel-plugin-transform-jsx-to-htm", {
43-
"tag": "$$html",
44-
"html": true
43+
"tag": "$$html"
4544
}]
4645
]
4746
```
4847

4948
## Auto-importing the tag
5049

51-
Want to automatically import `html` into any file that uses JSX? It works the same as with JSX!
52-
Just use [babel-plugin-jsx-pragmatic]:
50+
Want to automatically import `html` into any file that uses JSX?
51+
Just use the `import` option:
5352

5453
```js
5554
"plugins": [
56-
["babel-plugin-jsx-pragmatic", {
57-
// the module to import:
58-
"module": "lit-html",
59-
// a named export to use from that module:
60-
"export": "html",
61-
// what to call it locally: (should match your "tag" option)
62-
"import": "$$html"
63-
}],
6455
["babel-plugin-transform-jsx-to-htm", {
65-
"tag": "$$html"
56+
"tag": "$$html",
57+
"import": {
58+
// the module to import:
59+
"module": "htm/preact",
60+
// a named export to use from that module:
61+
"export": "html"
62+
}
6663
}]
6764
]
6865
```
6966

7067
The above will produce files that look like:
7168

7269
```js
73-
import { html as $$html } from 'lit-html';
70+
import { html as $$html } from 'htm/preact';
7471

7572
export default $$html`<h1>hello</h1>`
7673
```
@@ -80,5 +77,3 @@ export default $$html`<h1>hello</h1>`
8077
Apache 2
8178

8279
[htm]: https://github.com/developit/htm
83-
[lit-html]: https://github.com/polymer/lit-html
84-
[babel-plugin-jsx-pragmatic]: https://github.com/jmm/babel-plugin-jsx-pragmatic

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

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,35 @@ import jsx from '@babel/plugin-syntax-jsx';
44
* @param {Babel} babel
55
* @param {object} [options]
66
* @param {string} [options.tag='html'] The tagged template "tag" function name to produce.
7-
* @param {string} [options.html=false] If `true`, output HTML-like instead of XML-like (no self-closing tags, etc).
7+
* @param {string | boolean | object} [options.import=false] Import the tag automatically
88
*/
99
export default function jsxToHtmBabelPlugin({ types: t }, options = {}) {
10-
const tag = dottedIdentifier(options.tag || 'html');
11-
const htmlOutput = !!options.html;
10+
const tagString = options.tag || 'html';
11+
const tag = dottedIdentifier(tagString);
12+
const importDeclaration = tagImport(options.import || false);
13+
14+
function tagImport(imp) {
15+
if (imp === false) {
16+
return null;
17+
}
18+
const tagRoot = t.identifier(tagString.split('.')[0]);
19+
const { module, export: export_ } = typeof imp !== 'string' ? imp : {
20+
module: imp,
21+
export: null
22+
};
23+
24+
let specifier;
25+
if (export_ === '*') {
26+
specifier = t.importNamespaceSpecifier(tagRoot);
27+
}
28+
else if (export_ === 'default') {
29+
specifier = t.importDefaultSpecifier(tagRoot);
30+
}
31+
else {
32+
specifier = t.importSpecifier(tagRoot, export_ ? t.identifier(export_) : tagRoot);
33+
}
34+
return t.importDeclaration([specifier], t.stringLiteral(module));
35+
}
1236

1337
function dottedIdentifier(keypath) {
1438
const path = keypath.split('.');
@@ -104,7 +128,7 @@ export default function jsxToHtmBabelPlugin({ types: t }, options = {}) {
104128
}
105129

106130
const children = t.react.buildChildren(node);
107-
if (htmlOutput || children && children.length !== 0) {
131+
if (children && children.length !== 0) {
108132
raw('>');
109133
for (let i = 0; i < children.length; i++) {
110134
let child = children[i];
@@ -147,7 +171,15 @@ export default function jsxToHtmBabelPlugin({ types: t }, options = {}) {
147171
name: 'transform-jsx-to-htm',
148172
inherits: jsx,
149173
visitor: {
150-
JSXElement(path) {
174+
Program: {
175+
exit(path, state) {
176+
if (state.get('jsxElement') && importDeclaration) {
177+
path.unshiftContainer('body', importDeclaration);
178+
}
179+
}
180+
},
181+
182+
JSXElement(path, state) {
151183
let quasisBefore = quasis.slice();
152184
let expressionsBefore = expressions.slice();
153185
let bufferBefore = buffer;
@@ -161,6 +193,8 @@ export default function jsxToHtmBabelPlugin({ types: t }, options = {}) {
161193
quasis = quasisBefore;
162194
expressions = expressionsBefore;
163195
buffer = bufferBefore;
196+
197+
state.set('jsxElement', true);
164198
}
165199
}
166200
};

test/babel-transform-jsx.test.mjs

Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ function compile(code, { plugins = [], ...options } = {}) {
55
return transform(code, {
66
babelrc: false,
77
configFile: false,
8-
sourceType: 'script',
8+
sourceType: 'module',
99
plugins: [
1010
...plugins,
1111
[transformJsxToHtmPlugin, options]
@@ -14,6 +14,50 @@ function compile(code, { plugins = [], ...options } = {}) {
1414
}
1515

1616
describe('babel-plugin-transform-jsx-to-htm', () => {
17+
describe('import', () => {
18+
test('import shortcut', () => {
19+
expect(
20+
compile(`(<div />);`, { import: 'htm/preact' })
21+
).toBe('import { html } from "htm/preact";\nhtml`<div/>`;');
22+
});
23+
24+
test('import shortcut, dotted tag', () => {
25+
expect(
26+
compile(`(<div />);`, { tag: 'html.bound', import: 'htm/preact' })
27+
).toBe('import { html } from "htm/preact";\nhtml.bound`<div/>`;');
28+
});
29+
30+
test('named import', () => {
31+
expect(
32+
compile(`(<div />);`, { import: { module: 'htm/preact', export: '$html' } })
33+
).toBe('import { $html as html } from "htm/preact";\nhtml`<div/>`;');
34+
});
35+
36+
test('named import, dotted tag', () => {
37+
expect(
38+
compile(`(<div />);`, { tag: 'html.bound', import: { module: 'htm/preact', export: '$html' } })
39+
).toBe('import { $html as html } from "htm/preact";\nhtml.bound`<div/>`;');
40+
});
41+
42+
test('default import', () => {
43+
expect(
44+
compile(`(<div />);`, { import: { module: 'htm/preact', export: 'default' } })
45+
).toBe('import html from "htm/preact";\nhtml`<div/>`;');
46+
});
47+
48+
test('namespace import', () => {
49+
expect(
50+
compile(`(<div />);`, { import: { module: 'htm/preact', export: '*' } })
51+
).toBe('import * as html from "htm/preact";\nhtml`<div/>`;');
52+
});
53+
54+
test('no import without JSX', () => {
55+
expect(
56+
compile(`false;`, { import: 'htm/preact' })
57+
).toBe('false;');
58+
});
59+
});
60+
1761
describe('elements and text', () => {
1862
test('single named element', () => {
1963
expect(
@@ -57,22 +101,6 @@ describe('babel-plugin-transform-jsx-to-htm', () => {
57101
});
58102
});
59103

60-
describe('options.html = true', () => {
61-
test('use explicit end tags instead of self-closing', () => {
62-
expect(
63-
compile('(<div />);', { html: true })
64-
).toBe('html`<div></div>`;');
65-
66-
expect(
67-
compile('(<div a />);', { html: true })
68-
).toBe('html`<div a></div>`;');
69-
70-
expect(
71-
compile('(<a>b</a>);', { html: true })
72-
).toBe('html`<a>b</a>`;');
73-
});
74-
});
75-
76104
describe('props', () => {
77105
test('static values', () => {
78106
expect(
@@ -159,24 +187,4 @@ describe('babel-plugin-transform-jsx-to-htm', () => {
159187
).toBe('html`<div/>`;');
160188
});
161189
});
162-
163-
describe('integration with babel-plugin-jsx-pragmatic', () => {
164-
test('JSX is still identified and import added', () => {
165-
expect(
166-
compile('const Foo = props => <div>hello</div>;', {
167-
tag: '$$html',
168-
plugins: [
169-
['babel-plugin-jsx-pragmatic', {
170-
// module to import:
171-
module: 'lit-html',
172-
// the name of the export to use:
173-
export: 'html',
174-
// whatever you specified for the "tag" option:
175-
import: '$$html'
176-
}]
177-
]
178-
})
179-
).toBe('import { html as $$html } from "lit-html";\n\nconst Foo = props => $$html`<div>hello</div>`;');
180-
});
181-
});
182190
});

0 commit comments

Comments
 (0)