├── .gitignore
├── test
├── start.js
├── target.js
└── index.js
├── index.js
├── package.json
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | npm-debug.log
--------------------------------------------------------------------------------
/test/start.js:
--------------------------------------------------------------------------------
1 | export default () => (
2 |
6 | )
7 |
--------------------------------------------------------------------------------
/test/target.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _h = require("virtual-dom/h");
8 |
9 | var _h2 = _interopRequireDefault(_h);
10 |
11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12 |
13 | exports.default = function () {
14 | return (0, _h2.default)(
15 | "div",
16 | null,
17 | [(0, _h2.default)(
18 | "p",
19 | null,
20 | "one"
21 | ), (0, _h2.default)(
22 | "p",
23 | null,
24 | "two"
25 | )]
26 | );
27 | };
28 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | var test = require('tape')
2 | var assertTransform = require('assert-transform')
3 |
4 | test('assert that start ends up looking like target', function (t) {
5 | t.plan(1)
6 | assertTransform(
7 | __dirname + '/start.js',
8 | __dirname + '/target.js',
9 | {
10 | presets: ['es2015'],
11 | plugins: [
12 | ['transform-react-jsx', {'pragma': 'h'}],
13 | '../index.js'
14 | ]
15 | }
16 | )
17 | .then(function () {
18 | t.pass('produced contents of target.js')
19 | })
20 | .catch(function (err) {
21 | console.log(err)
22 | t.fail()
23 | })
24 | })
25 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function (babel) {
2 | return {
3 | visitor: {
4 | CallExpression: function (path) {
5 | if (path.node.callee.name === 'h' && path.node.arguments.length > 3) {
6 | var args = path.node.arguments
7 | path.node.arguments = args.slice(0, 2)
8 | path.node.arguments.push(babel.types.arrayExpression(args.slice(2)))
9 | }
10 | },
11 |
12 | JSXOpeningElement: function (path, meta) {
13 | meta.file.set('hasJSX', true)
14 | },
15 |
16 | Program: {
17 | enter: function (path, meta) {
18 | meta.file.set('hasJSX', false)
19 | },
20 |
21 | exit: function (path, meta) {
22 | // if it doesn't have JSX or "h" is already imported, stop here
23 | if (!meta.file.get('hasJSX') || path.scope.hasBinding('h')) {
24 | return
25 | }
26 |
27 | var vdomImportDeclaration = babel.types.importDeclaration([
28 | babel.types.importDefaultSpecifier(babel.types.identifier('h'))
29 | ], babel.types.stringLiteral('virtual-dom/h'))
30 |
31 | path.node.body.unshift(vdomImportDeclaration)
32 | }
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "babel-plugin-h-children-fix",
3 | "description": "Allows use of standard babel JSX tools with virtual-dom/h",
4 | "version": "1.1.0",
5 | "author": "Henrik Joreteg ",
6 | "bugs": "https://github.com/henrikjoreteg/babel-plugin-h-children-fix/issues",
7 | "devDependencies": {
8 | "assert-transform": "git@github.com:walmartreact/assert-transform.git#869b2d4d1bb2d15288f8591024367b41c247d304",
9 | "babel": "^6.3.26",
10 | "babel-plugin-h-children-fix": "^1.0.1",
11 | "babel-plugin-transform-react-jsx": "^6.4.0",
12 | "babel-preset-es2015": "^6.3.13",
13 | "tape": "^4.4.0"
14 | },
15 | "homepage": "https://github.com/henrikjoreteg/babel-plugin-h-children-fix",
16 | "keywords": [
17 | "babel",
18 | "hyperscript",
19 | "plugin",
20 | "virtual-dom"
21 | ],
22 | "license": "MIT",
23 | "main": "index.js",
24 | "repository": {
25 | "type": "git",
26 | "url": "henrikjoreteg/babel-plugin-h-children-fix"
27 | },
28 | "scripts": {
29 | "test": "node test/index.js && standard"
30 | },
31 | "standard": {
32 | "globals": [
33 | "React"
34 | ],
35 | "ignore": [
36 | "/test/target.js"
37 | ]
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # babel-plugin-h-children-fix
2 |
3 | 
4 |
5 | Allows use of standard babel JSX tools with virtual-dom/h
6 |
7 | I wanted to use virtual-dom's ["hyperscript"](https://github.com/Matt-Esch/virtual-dom/blob/master/virtual-hyperscript/README.md) but write it using regular JSX syntax.
8 |
9 | Standard Babel plugins as of 6.0+ have great tools for JSX, including the ability to specify a "pragma" to use instead of `React.createElement` (which is the default). You simply `npm install babel-plugin-transform-react-jsx` and specify the pragma. Docs for [that are here](http://babeljs.io/docs/plugins/transform-react-jsx/).
10 |
11 | I assumed I could just specify `h` as a pragma and be done.
12 |
13 | Only issue is `React.createElement` expects child elements as addtional arguments: `React.createElement('div', null, childOne, childTwo)` while `h` expects `h('div', null, [childOne, childTwo])` (note the last argument is an array of children.
14 |
15 | This is a babel plugin to be ran *after* the "official" one that simply replaces any instance of a "callExpression" that has a name of `h` and has three or more arguments, with a version that gathers the `children` as an array passed as the third argument.
16 |
17 | Note that this is not exensively tested and it's a *naive* and *simple* replacement. Any `h()` call with more than 3 arguments is affected whether it's actually virtual dom's `h` or not.
18 |
19 | That's it!
20 |
21 | ## just kidding! One, tiny little thing...
22 |
23 | It's kind of odd to have to `import h from 'virtual-dom/h'` at the top of a file containing JSX, especially if you then *never actually use it within your file*. So, as of version `1.1.0+` this plugin will also automatically insert that import statement for you if the file contains JSX and doesn't have `h` defined at the module level.
24 |
25 | ## example
26 |
27 | npm install both of them:
28 |
29 | ```
30 | npm install babel-plugin-transform-react-jsx babel-plugin-h-children-fix
31 | ```
32 |
33 | Now if your `.babelrc` file looks like this:
34 |
35 |
36 | ```json
37 | {
38 | "presets": ["es2015"],
39 | "plugins": [
40 | ["transform-react-jsx", {"pragma": "h"}],
41 | "h-children-fix"
42 | ]
43 | }
44 | ```
45 |
46 | The `babel-plugin-transform-react-jsx` firt turns this:
47 |
48 | ```js
49 | export default () => (
50 |
54 | )
55 | ```
56 |
57 | into something roughly like this:
58 |
59 | ```js
60 | export default () => (
61 | h('ul', null, h('li', null, 'one'), h('li', null, 'two'))
62 | )
63 | ```
64 |
65 | and this plugin subsequently turns the above, into:
66 |
67 | ```js
68 | export default () => (
69 | h('ul', null, [
70 | h('li', null, 'one'),
71 | h('li', null, 'two')
72 | ])
73 | )
74 | ```
75 |
76 | ## install
77 |
78 | ```
79 | npm install babel-plugin-h-children-fix
80 | ```
81 |
82 | ## credits
83 |
84 | If you like this follow [@HenrikJoreteg](http://twitter.com/henrikjoreteg) on twitter.
85 |
86 | ## changelog
87 |
88 | - `1.1.0` auto import `h` if not defined, added basic test, now uses standard style and enforcement thereof.
89 | - `1.0.1` doc update
90 | - `1.0.0` initial release
91 |
92 | ## license
93 |
94 | [MIT](http://mit.joreteg.com/)
95 |
96 |
--------------------------------------------------------------------------------