├── .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 |
3 |

one

4 |

two

5 |
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 | ![](https://img.shields.io/npm/dm/babel-plugin-h-children-fix.svg)![](https://img.shields.io/npm/v/babel-plugin-h-children-fix.svg)![](https://img.shields.io/npm/l/babel-plugin-h-children-fix.svg) 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 | --------------------------------------------------------------------------------