├── .github ├── dependabot.yml └── workflows │ └── tests.yml ├── .gitignore ├── .npmignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── axe.png ├── example.js ├── factory.js ├── index.js ├── package.json └── test.js /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Basic dependabot.yml file with 2 | # minimum configuration for two package managers 3 | 4 | version: 2 5 | updates: 6 | # Enable version updates for npm 7 | - package-ecosystem: "npm" 8 | # Look for `package.json` and `lock` files in the `root` directory 9 | directory: "/" 10 | # Check the npm registry for updates every day (weekdays) 11 | schedule: 12 | interval: "daily" 13 | # Enable updates to github actions 14 | - package-ecosystem: "github-actions" 15 | directory: "/" 16 | schedule: 17 | interval: "daily" 18 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | test: 11 | runs-on: ${{ matrix.os }} 12 | 13 | strategy: 14 | matrix: 15 | os: [ubuntu-latest] 16 | node: [16, 18] 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Use Node.js ${{ matrix.node }} 21 | uses: actions/setup-node@v4 22 | with: 23 | node-version: ${{ matrix.node }} 24 | - run: npm i 25 | - run: npm test 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | axe.png 2 | example.js 3 | test.js 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [2.0.1](https://github.com/ungoldman/hyperaxe/compare/v2.0.0...v2.0.1) (2022-05-08) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * **engines:** set min node to 12 ([e61d87b](https://github.com/ungoldman/hyperaxe/commit/e61d87bdf0e41c29cd814ffd99739a946578fe99)) 11 | 12 | 13 | # [2.0.0](https://github.com/ungoldman/hyperaxe/compare/v1.3.0...v2.0.0) (2022-03-17) 14 | 15 | ### Breaking Changes 16 | - dropped support for all node versions below 12 17 | - currently supported versions: node 12, 14, 16 18 | 19 | ### Misc 20 | - docs: update badges, rm tap-spec 21 | - ci: use gh actions 22 | - rm .travis.yml 23 | - lint: standard@16 24 | - deps(dev): standard@16, standard-version@9, tape@5, rm tap-spec 25 | - add .gitignore 26 | - chore(deps-dev): bump standard-version from 7.1.0 to 8.0.1 (#12) 27 | - Add innerHTML documentation and upgrade deps (#10) 28 | 29 | 30 | # [1.3.0](https://github.com/ungoldman/hyperaxe/compare/v1.2.0...v1.3.0) (2018-10-05) 31 | 32 | 33 | ### Features 34 | 35 | * split out and document factory functions ([#8](https://github.com/ungoldman/hyperaxe/issues/8)) ([b477afe](https://github.com/ungoldman/hyperaxe/commit/b477afe)) 36 | 37 | 38 | 39 | 40 | # [1.2.0](https://github.com/ungoldman/hyperaxe/compare/v1.1.1...v1.2.0) (2018-10-03) 41 | 42 | 43 | ### Features 44 | 45 | * add getFactory method for cached factories ([#5](https://github.com/ungoldman/hyperaxe/issues/5)) ([4d6ff78](https://github.com/ungoldman/hyperaxe/commit/4d6ff78)) 46 | 47 | 48 | 49 | 50 | ## [1.1.1](https://github.com/ungoldman/hyperaxe/compare/v1.1.0...v1.1.1) (2018-02-28) 51 | 52 | 53 | 54 | 55 | # [1.1.0](https://github.com/ungoldman/hyperaxe/compare/v1.0.2...v1.1.0) (2018-02-27) 56 | 57 | 58 | ### Features 59 | 60 | * export createFactory function ([#2](https://github.com/ungoldman/hyperaxe/issues/2)) ([a7b237d](https://github.com/ungoldman/hyperaxe/commit/a7b237d)) 61 | 62 | 63 | 64 | 65 | ## [1.0.2](https://github.com/ungoldman/hyperaxe/compare/v1.0.1...v1.0.2) (2018-02-23) 66 | 67 | 68 | ### Bug Fixes 69 | 70 | * simplify kid slicing factory ([b6c6b70](https://github.com/ungoldman/hyperaxe/commit/b6c6b70)) 71 | 72 | 73 | 74 | 75 | ## [1.0.1](https://github.com/ungoldman/hyperaxe/compare/v1.0.0...v1.0.1) (2018-02-21) 76 | 77 | 78 | ### Bug Fixes 79 | 80 | * **deps:** remove is-plain-object ([129ee34](https://github.com/ungoldman/hyperaxe/commit/129ee34)) 81 | 82 | 83 | 84 | 85 | # 1.0.0 (2018-02-17) 86 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | ## Code of Conduct 4 | 5 | This project is intended to be a safe, welcoming space for collaboration. All contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. Thank you for being kind to each other! 6 | 7 | ## Contributions welcome! 8 | 9 | **Before spending lots of time on something, ask for feedback on your idea first!** 10 | 11 | Please search [issues](../../issues/) and [pull requests](../../pulls/) before adding something new! This helps avoid duplicating efforts and conversations. 12 | 13 | This project welcomes any kind of contribution! Here are a few suggestions: 14 | 15 | - **Ideas**: participate in an issue thread or start your own to have your voice heard. 16 | - **Writing**: contribute your expertise in an area by helping expand the included content. 17 | - **Copy editing**: fix typos, clarify language, and generally improve the quality of the content. 18 | - **Formatting**: help keep content easy to read with consistent formatting. 19 | - **Code**: help maintain and improve the project codebase. 20 | 21 | ## Code Style 22 | 23 | [![standard][standard-image]][standard-url] 24 | 25 | This repository uses [`standard`][standard-url] to maintain code style and consistency, and to avoid style arguments. 26 | 27 | [standard-image]: https://cdn.rawgit.com/feross/standard/master/badge.svg 28 | [standard-url]: https://github.com/feross/standard 29 | [semistandard-image]: https://cdn.rawgit.com/flet/semistandard/master/badge.svg 30 | [semistandard-url]: https://github.com/Flet/semistandard 31 | 32 | ## Project Governance 33 | 34 | **This is an [OPEN Open Source Project](http://openopensource.org/).** 35 | 36 | Individuals making significant and valuable contributions are given commit access to the project to contribute as they see fit. This project is more like an open wiki than a standard guarded open source project. 37 | 38 | ### Rules 39 | 40 | There are a few basic ground rules for collaborators: 41 | 42 | 1. **No `--force` pushes** or modifying the Git history in any way. 43 | 1. **Non-master branches** ought to be used for ongoing work. 44 | 1. **External API changes and significant modifications** ought to be subject to an **internal pull request** to solicit feedback from other contributors. 45 | 1. Internal pull requests to solicit feedback are *encouraged* for any other non-trivial contribution but left to the discretion of the contributor. 46 | 1. Contributors should attempt to adhere to the prevailing code style. 47 | 48 | ### Releases 49 | 50 | Declaring formal releases remains the prerogative of the project maintainer. 51 | 52 | ### Changes to this arrangement 53 | 54 | This is an experiment and feedback is welcome! This document may also be subject to pull requests or changes by contributors where you believe you have something valuable to add or change. 55 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # [ISC License](https://spdx.org/licenses/ISC) 2 | 3 | Copyright (c) 2018, Nate Goldman (https://ungoldman.com/) 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | HyperAxe 4 | 5 | # HyperAxe 6 | 7 | An enchanted [hyperscript](https://github.com/hyperhype/hyperscript) weapon. 8 | 9 | [![npm][npm-image]][npm-url] 10 | [![build][build-image]][build-url] 11 | [![downloads][downloads-image]][npm-url] 12 | 13 | [npm-image]: https://img.shields.io/npm/v/hyperaxe.svg 14 | [npm-url]: https://www.npmjs.com/package/hyperaxe 15 | [build-image]: https://github.com/ungoldman/hyperaxe/actions/workflows/tests.yml/badge.svg 16 | [build-url]: https://github.com/ungoldman/hyperaxe/actions/workflows/tests.yml 17 | [downloads-image]: https://img.shields.io/npm/dm/hyperaxe.svg 18 | 19 |
20 | 21 | ```sh 22 | npm install hyperaxe 23 | ``` 24 | 25 | ```js 26 | const { body, h1 } = require('hyperaxe') 27 | 28 | body( 29 | h1('hello world') 30 | ) 31 | // =>

hello world

32 | ``` 33 | 34 | ## Usage 35 | 36 | Exports all [HTML tags](https://ghub.io/html-tags). 37 | 38 | ```js 39 | const { a, img, video } = require('hyperaxe') 40 | 41 | a({ href: '#' }, 'click') 42 | // click 43 | 44 | img({ src: 'cats.gif', alt: 'lolcats' }) 45 | // lolcats 46 | 47 | video({ src: 'dogs.mp4', autoplay: true }) 48 | // 49 | ``` 50 | 51 | Default export accepts a tag and returns an element factory. 52 | 53 | ```js 54 | const x = require('hyperaxe') 55 | const p = x('p') 56 | 57 | p('over 9000') 58 | //

over 9000

59 | ``` 60 | 61 | CSS shorthand works too. 62 | 63 | ```js 64 | const x = require('hyperaxe') 65 | const horse = x('.horse.with-hands') 66 | 67 | horse('neigh') 68 | //
neigh
69 | ``` 70 | 71 | Makes creating custom components easy. 72 | 73 | ```js 74 | const x = require('hyperaxe') 75 | 76 | const siteNav = (...links) => x('nav.site')( 77 | links.map(link => 78 | x('a.link')({ href: link.href }, link.text) 79 | ) 80 | ) 81 | 82 | x.body( 83 | siteNav( 84 | { href: '#apps', text: 'apps' }, 85 | { href: '#games', text: 'games' } 86 | ) 87 | ) 88 | // 89 | // 93 | // 94 | ``` 95 | 96 | ## Example 97 | 98 | Here's a counter increment example using [`nanochoo`](https://github.com/heyitsmeuralex/nanochoo): 99 | 100 | ```js 101 | const { body, button, h1 } = require('hyperaxe') 102 | const nano = require('nanochoo') 103 | 104 | const app = nano() 105 | 106 | app.use(store) 107 | app.view(view) 108 | app.mount('body') 109 | 110 | function view (state, emit) { 111 | return body( 112 | h1(`count is ${state.count}`), 113 | button({ onclick }, 'Increment') 114 | ) 115 | 116 | function onclick () { 117 | emit('increment', 1) 118 | } 119 | } 120 | 121 | function store (state, emitter) { 122 | state.count = 0 123 | 124 | emitter.on('increment', function (count) { 125 | state.count += count 126 | emitter.emit('render') 127 | }) 128 | } 129 | ``` 130 | 131 | ## API 132 | 133 | ### `hyperaxe` 134 | 135 | ```js 136 | hyperaxe(tag) => ([props], [...children]) => HTMLElement 137 | ``` 138 | 139 | - `tag` _string_ - valid HTML tag name or CSS shorthand (required) 140 | - `props` _object_ - HTML attributes (optional) 141 | - `children` _node, string, number, array_ - child nodes or primitives (optional) 142 | 143 | Returns a function that creates HTML elements. 144 | 145 | The factory is [variadic](https://en.wikipedia.org/wiki/Variadic_function), so any number of children are accepted. 146 | 147 | ```js 148 | x('.variadic')( 149 | x('h1')('hi'), 150 | x('h2')('hello'), 151 | x('h3')('hey'), 152 | x('h4')('howdy') 153 | ) 154 | ``` 155 | 156 | Arrays of children also work. 157 | 158 | ```js 159 | const kids = [ 160 | x('p')('Once upon a time,'), 161 | x('p')('there was a variadic function,'), 162 | x('p')('that also accepted arrays.') 163 | ] 164 | 165 | x('.arrays')(kids) 166 | ``` 167 | 168 | In a browser context, the object returned by the factory is an [`HTMLElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement) object. In a server (node) context, the object returned is an instance of [`html-element`](https://github.com/1N50MN14/html-element). In both contexts, the stringified HTML is accessible via the [`outerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML) attribute. 169 | 170 | ### `hyperaxe[tag]` 171 | 172 | All [HTML tags](https://ghub.io/html-tags) are attached to `hyperaxe` as keys. 173 | 174 | They return the same function as described above, with the `tag` argument prefilled. 175 | 176 | Think of it as a kind of [partial application](https://en.wikipedia.org/wiki/Partial_application). 177 | 178 | The main motivation for doing this is convenience. 179 | 180 | ```js 181 | const { p } = require('hyperaxe') 182 | 183 | p('this is convenient') 184 | ``` 185 | 186 | You can pass raw HTML by setting the `innerHTML` property of an element. 187 | 188 | ```javascript 189 | const { div } = require('hyperaxe') 190 | 191 | div({ innerHTML: '

Raw HTML!' }) 192 | ``` 193 | 194 | ### `hyperaxe.createFactory(h)` 195 | 196 | Creates a `hyperaxe` element factory for a given hyperscript implementation (`h`). 197 | 198 | If you use another implementation than `hyperscript` proper, you can exclude that dependency by using `require('hyperaxe/factory')`. For the time being, no other implementations are tested though, so wield at your own peril! 199 | 200 | ### `hyperaxe.getFactory(h)` 201 | 202 | Same as `createFactory`, except it only creates a new factory on the first call and returns a cached version after that. 203 | 204 | ## Enchantments 205 | 206 | - Summons DOM nodes. 207 | - +1 vs. virtual DOM nodes. 208 | - Grants [Haste](http://engl393-dnd5th.wikia.com/wiki/Haste). 209 | 210 | ## Dependencies 211 | 212 | - [html-tags](https://ghub.io/html-tags): List of standard HTML tags. 213 | - [hyperscript](https://ghub.io/hyperscript): Create HyperText with JavaScript, on client or server. 214 | 215 | ## Dev Dependencies 216 | 217 | - [standard](https://ghub.io/standard): JavaScript Standard Style. 218 | - [standard-version](https://ghub.io/standard-version): Replacement for `npm version` with automatic CHANGELOG generation. 219 | - [tape](https://ghub.io/tape): tap-producing test harness for node and browsers. 220 | 221 | ## See Also 222 | 223 | This library's approach and API are heavily inspired by [reaxe](https://github.com/jxnblk/reaxe). 224 | 225 | ## Contributing 226 | 227 | Contributors welcome! Please read the [contributing guidelines](CONTRIBUTING.md) before getting started. 228 | 229 | ## License 230 | 231 | [ISC](LICENSE.md) 232 | 233 | Axe image is from [emojidex](https://emojidex.com/emoji/axe). 234 | -------------------------------------------------------------------------------- /axe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ungoldman/hyperaxe/8bcaae635ac0f4a9cd0248c6ed66f0a23ecadfe8/axe.png -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | const { body, button, h1 } = require('./') 2 | 3 | const state = { count: 0 } 4 | 5 | function view () { 6 | return body( 7 | h1(`count is ${state.count}`), 8 | button({ onclick }, 'Increment') 9 | ) 10 | } 11 | 12 | function onclick () { 13 | state.count++ 14 | render() 15 | } 16 | 17 | function render () { 18 | document.body.replaceWith(view()) 19 | } 20 | 21 | render() 22 | -------------------------------------------------------------------------------- /factory.js: -------------------------------------------------------------------------------- 1 | const tags = require('html-tags') 2 | let instances 3 | 4 | /** 5 | * Returns an element factory using the given createElement function. 6 | * Adapted from `lib/create-x.js` in jxnblk's https://github.com/jxnblk/reaxe. 7 | * Only tested with hyperscript. Not guaranteed to work with anything else. 8 | * 9 | * @param {Function} fn - createElement function 10 | * @return {Function} - factory function with all HTML tag factories attached 11 | */ 12 | function createFactory (fn) { 13 | function factory (tag) { 14 | return function (props) { 15 | return isObject(props) 16 | ? fn(tag, props, sliceKids(arguments, 1)) 17 | : fn(tag, sliceKids(arguments)) 18 | } 19 | } 20 | 21 | tags.forEach(function (tag) { 22 | factory[tag] = factory(tag) 23 | }) 24 | 25 | return factory 26 | } 27 | 28 | /** 29 | * Return an element factory function, either by creating a new one or by 30 | * getting a cached version 31 | * 32 | * @param {Function} fn - createElement function 33 | * @return {Function} - factory function with all HTML tag factories attached 34 | */ 35 | function getFactory (fn) { 36 | if (!instances) { 37 | instances = new Map() 38 | } 39 | 40 | let factory = instances.get(fn) 41 | if (factory) { 42 | return factory 43 | } 44 | 45 | factory = createFactory(fn) 46 | instances.set(fn, factory) 47 | return factory 48 | } 49 | 50 | /** 51 | * Turns arguments into an array, optionally slicing off a portion. 52 | * @param {array} args - arguments object (array-like) 53 | * @param {number} num - optional integer for Array.slice 54 | * @return {array} - array of arguments 55 | */ 56 | function sliceKids (args, num) { 57 | const arr = Array.prototype.slice.call(args, num) 58 | return arr 59 | } 60 | 61 | function isObject (val) { 62 | return val != null && 63 | typeof val === 'object' && 64 | Array.isArray(val) === false 65 | } 66 | 67 | module.exports.createFactory = createFactory 68 | module.exports.getFactory = getFactory 69 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { createFactory, getFactory } = require('./factory') 2 | const h = require('hyperscript') 3 | 4 | module.exports = createFactory(h) 5 | module.exports.createFactory = createFactory 6 | module.exports.getFactory = getFactory 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hyperaxe", 3 | "description": "Enchanted hyperscript weapon.", 4 | "version": "2.0.1", 5 | "author": "Nate Goldman (https://ungoldman.com/)", 6 | "bugs": { 7 | "url": "https://github.com/ungoldman/hyperaxe/issues" 8 | }, 9 | "dependencies": { 10 | "html-tags": "^3.0.0", 11 | "hyperscript": "^2.0.2" 12 | }, 13 | "devDependencies": { 14 | "standard": "^17.0.0", 15 | "standard-version": "^9.3.2", 16 | "tap-arc": "^1.0.2", 17 | "tape": "^5.5.2" 18 | }, 19 | "engines": { 20 | "node": ">=12" 21 | }, 22 | "homepage": "https://github.com/ungoldman/hyperaxe#readme", 23 | "keywords": [ 24 | "dom", 25 | "factory", 26 | "html", 27 | "hyperscript", 28 | "sugar" 29 | ], 30 | "license": "ISC", 31 | "main": "index.js", 32 | "repository": { 33 | "type": "git", 34 | "url": "git+https://github.com/ungoldman/hyperaxe.git" 35 | }, 36 | "scripts": { 37 | "example": "npx budo --open example.js", 38 | "postrelease": "git push --tags && npm publish", 39 | "prerelease": "git fetch --tags && npm test", 40 | "release": "standard-version", 41 | "test": "standard && tape test.js | tap-arc" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const x = require('./') 2 | const test = require('tape') 3 | const tags = require('html-tags') 4 | 5 | test('factory function signature', t => { 6 | t.plan(5) 7 | 8 | t.equal(typeof x, 'function', 'factory function exists') 9 | t.equal(typeof x('p'), 'function', 'factory produces function') 10 | 11 | const h = x('p')('hello') 12 | 13 | t.equal(typeof h, 'object', 'tag function produces object') 14 | t.equal(h.nodeName, 'p', 'tag object has correct nodeName') 15 | t.equal(h.childNodes[0].value, 'hello', 'tag object has text node') 16 | }) 17 | 18 | test('all tags', function (t) { 19 | t.plan(tags.length) 20 | tags.forEach(function (tag) { 21 | t.equal(typeof x[tag], 'function', tag + ' method exists') 22 | }) 23 | }) 24 | 25 | test('complex nested arrays', function (t) { 26 | const h = x.div({ id: 'kidz' }, 'I ', ['am ', ['a ', [x.em('very'), ' ', ['nested ', 'bunch ']]], 'of '], x.strong('kids'), '.') 27 | t.equal(h.outerHTML, '

I am a very nested bunch of kids.
', 'the kids are alright') 28 | t.end() 29 | }) 30 | 31 | test('examples: HTML tags', t => { 32 | t.plan(3) 33 | 34 | const { a, img, video } = x 35 | 36 | t.equal( 37 | a({ href: '#' }, 'click').outerHTML, 38 | 'click' 39 | ) 40 | t.equal( 41 | img({ src: 'cats.gif', alt: 'lolcats' }).outerHTML, 42 | 'lolcats' 43 | ) 44 | t.equal( 45 | video({ src: 'dogs.mp4', autoplay: true }).outerHTML, 46 | '' 47 | ) 48 | }) 49 | 50 | test('examples: element factory', t => { 51 | t.plan(1) 52 | 53 | const p = x('p') 54 | 55 | t.equal( 56 | p('over 9000').outerHTML, 57 | '

over 9000

' 58 | ) 59 | }) 60 | 61 | test('examples: css shorthand', t => { 62 | t.plan(1) 63 | 64 | const horse = x('.horse.with-hands') 65 | 66 | t.equal( 67 | horse('neigh').outerHTML, 68 | '
neigh
' 69 | ) 70 | }) 71 | 72 | test('examples: custom components', t => { 73 | t.plan(1) 74 | 75 | const siteNav = (...links) => x('nav.site')( 76 | links.map(link => 77 | x('a.link')({ href: link.href }, link.text) 78 | ) 79 | ) 80 | 81 | t.equal( 82 | x.body( 83 | siteNav( 84 | { href: '#apps', text: 'apps' }, 85 | { href: '#games', text: 'games' } 86 | ) 87 | ).outerHTML, 88 | '' 89 | ) 90 | }) 91 | 92 | test('examples: variadic', t => { 93 | t.plan(1) 94 | 95 | t.equal( 96 | x('.variadic')( 97 | x('h1')('hi'), 98 | x('h2')('hello'), 99 | x('h3')('hey'), 100 | x('h4')('howdy') 101 | ).outerHTML, 102 | '

hi

hello

hey

howdy

' 103 | ) 104 | }) 105 | 106 | test('examples: arrays', t => { 107 | t.plan(1) 108 | 109 | const kids = [ 110 | x('p')('Once upon a time,'), 111 | x('p')('there was a variadic function,'), 112 | x('p')('that also accepted arrays.') 113 | ] 114 | 115 | t.equal( 116 | x('.arrays')(kids).outerHTML, 117 | '

Once upon a time,

there was a variadic function,

that also accepted arrays.

' 118 | ) 119 | }) 120 | 121 | test('getFactory: cached createFactory', t => { 122 | t.plan(1) 123 | 124 | const h = require('hyperscript') 125 | const y = x.getFactory(h) 126 | const z = x.getFactory(h) 127 | 128 | t.ok(y === z) 129 | }) 130 | --------------------------------------------------------------------------------