babel-plugin-htm
Advanced tools
Comparing version 1.0.1 to 2.0.0
@@ -1,152 +0,171 @@ | ||
var jsdom = require('jsdom'); | ||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } | ||
var before = global.document; | ||
global.document = new jsdom.JSDOM().window.document; | ||
var htm = require('htm'); | ||
global.document = before; | ||
var currentExpressions; | ||
var htm = _interopDefault(require('htm')); | ||
/** | ||
* @param {Babel} babel | ||
* @param {object} options | ||
* @param {string} [options.pragma=h] JSX/hyperscript pragma. | ||
* @param {string} [options.tag=html] The tagged template "tag" function name to process. | ||
* @param {boolean} [options.monomorphic=false] Output monomorphic inline objects instead of using String literals. | ||
* @param {boolean} [options.useBuiltIns=false] Use the native Object.assign instead of trying to polyfill it. | ||
* @param {boolean} [options.variableArity=true] If `false`, always passes exactly 3 arguments to the pragma function. | ||
*/ | ||
function htmBabelPlugin(ref, options) { | ||
var t = ref.types; | ||
if ( options === void 0 ) options = {}; | ||
var t = ref.types; | ||
if ( options === void 0 ) options = {}; | ||
var pragma = options.pragma === false ? false : dottedIdentifier(options.pragma || 'h'); | ||
var inlineVNodes = options.monomorphic || pragma === false; | ||
function dottedIdentifier(keypath) { | ||
var path = keypath.split('.'); | ||
var out; | ||
for (var i = 0;i < path.length; i++) { | ||
var ident = propertyName(path[i]); | ||
out = i === 0 ? ident : t.memberExpression(out, ident); | ||
} | ||
return out; | ||
var pragma = options.pragma === false ? false : dottedIdentifier(options.pragma || 'h'); | ||
var useBuiltIns = options.useBuiltIns; | ||
var inlineVNodes = options.monomorphic || pragma === false; | ||
function dottedIdentifier(keypath) { | ||
var path = keypath.split('.'); | ||
var out; | ||
for (var i = 0; i < path.length; i++) { | ||
var ident = propertyName(path[i]); | ||
out = i === 0 ? ident : t.memberExpression(out, ident); | ||
} | ||
function patternStringToRegExp(str) { | ||
var parts = str.split('/').slice(1); | ||
var end = parts.pop() || ''; | ||
return new RegExp(parts.join('/'), end); | ||
return out; | ||
} | ||
function patternStringToRegExp(str) { | ||
var parts = str.split('/').slice(1); | ||
var end = parts.pop() || ''; | ||
return new RegExp(parts.join('/'), end); | ||
} | ||
function propertyName(key) { | ||
if (key.match(/(^\d|[^a-z0-9_$])/i)) { return t.stringLiteral(key); } | ||
return t.identifier(key); | ||
} | ||
function stringValue(str) { | ||
if (options.monomorphic) { | ||
return t.objectExpression([t.objectProperty(propertyName('type'), t.numericLiteral(3)), t.objectProperty(propertyName('tag'), t.nullLiteral()), t.objectProperty(propertyName('props'), t.nullLiteral()), t.objectProperty(propertyName('children'), t.nullLiteral()), t.objectProperty(propertyName('text'), t.stringLiteral(str))]); | ||
} | ||
function propertyName(key) { | ||
if (key.match(/(^\d|[^a-z0-9_$])/i)) | ||
{ return t.stringLiteral(key); } | ||
return t.identifier(key); | ||
return t.stringLiteral(str); | ||
} | ||
function createVNode(tag, props, children) { | ||
// Never pass children=[[]]. | ||
if (children.elements.length === 1 && t.isArrayExpression(children.elements[0]) && children.elements[0].elements.length === 0) { | ||
children = children.elements[0]; | ||
} | ||
function stringValue(str) { | ||
if (options.monomorphic) { | ||
return t.objectExpression([t.objectProperty(propertyName('type'), t.numericLiteral(3)), | ||
t.objectProperty(propertyName('tag'), t.nullLiteral()),t.objectProperty(propertyName('props'), t.nullLiteral()), | ||
t.objectProperty(propertyName('children'), t.nullLiteral()),t.objectProperty(propertyName('text'), t.stringLiteral(str))]); | ||
} | ||
return t.stringLiteral(str); | ||
if (inlineVNodes) { | ||
return t.objectExpression([options.monomorphic && t.objectProperty(propertyName('type'), t.numericLiteral(1)), t.objectProperty(propertyName('tag'), tag), t.objectProperty(propertyName('props'), props), t.objectProperty(propertyName('children'), children), options.monomorphic && t.objectProperty(propertyName('text'), t.nullLiteral())].filter(Boolean)); | ||
} // Passing `{variableArity:false}` always produces `h(tag, props, children)` - where `children` is always an Array. | ||
// Otherwise, the default is `h(tag, props, ...children)`. | ||
if (options.variableArity !== false) { | ||
children = children.elements; | ||
} | ||
function createVNode(tag, props, children) { | ||
if (inlineVNodes) { | ||
return t.objectExpression([options.monomorphic && t.objectProperty(propertyName('type'), t.numericLiteral(1)), | ||
t.objectProperty(propertyName('tag'), tag),t.objectProperty(propertyName('props'), props), | ||
t.objectProperty(propertyName('children'), children),options.monomorphic && t.objectProperty(propertyName('text'), t.nullLiteral())].filter(Boolean)); | ||
} | ||
return t.callExpression(pragma, [tag,props,children]); | ||
return t.callExpression(pragma, [tag, props].concat(children)); | ||
} | ||
function spreadNode(args, state) { | ||
// 'Object.assign({}, x)', can be collapsed to 'x'. | ||
if (args.length === 2 && !t.isNode(args[0]) && Object.keys(args[0]).length === 0) { | ||
return propsNode(args[1]); | ||
} | ||
var isVNode = t.isCallExpression; | ||
if (inlineVNodes) { | ||
isVNode = (function (node) { | ||
if (!t.isObjectExpression(node)) | ||
{ return false; } | ||
return node.properties[0].value.value !== 3; | ||
}); | ||
var helper = useBuiltIns ? dottedIdentifier('Object.assign') : state.addHelper('extends'); | ||
return t.callExpression(helper, args.map(propsNode)); | ||
} | ||
function propsNode(props) { | ||
if (props == null) { return t.nullLiteral(); } | ||
return t.isNode(props) ? props : t.objectExpression(Object.keys(props).map(function (key) { | ||
var value = props[key]; | ||
if (typeof value === 'string') { | ||
value = t.stringLiteral(value); | ||
} else if (typeof value === 'boolean') { | ||
value = t.booleanLiteral(value); | ||
} | ||
return t.objectProperty(propertyName(key), value); | ||
})); | ||
} | ||
function transform(node, state) { | ||
if (node === undefined) { return t.identifier('undefined'); } | ||
if (node == null) { return t.nullLiteral(); } | ||
var tag = node.tag; | ||
var props = node.props; | ||
var children = node.children; | ||
function childMapper(child) { | ||
if (typeof child === 'string') { | ||
return stringValue(child); | ||
} | ||
return t.isNode(child) ? child : transform(child, state); | ||
} | ||
function childMapper(child, index, children) { | ||
if (typeof child === 'string' && child.trim().length === 0 || child == null) { | ||
if (index === 0 || index === children.length - 1) | ||
{ return null; } | ||
} | ||
if (typeof child === 'string' && isVNode(children[index - 1]) && isVNode(children[index + 1])) { | ||
child = child.trim(); | ||
} | ||
if (typeof child === 'string') { | ||
var matches = child.match(/\$\$\$_h_\[(\d+)\]/); | ||
if (matches) | ||
{ return currentExpressions[matches[1]]; } | ||
return stringValue(child); | ||
} | ||
return child; | ||
var newTag = typeof tag === 'string' ? t.stringLiteral(tag) : tag; | ||
var newProps = !Array.isArray(props) ? propsNode(props) : spreadNode(props, state); | ||
var newChildren = t.arrayExpression(children.map(childMapper)); | ||
return createVNode(newTag, newProps, newChildren); | ||
} | ||
function h(tag, props) { | ||
var children = [], len = arguments.length - 2; | ||
while ( len-- > 0 ) children[ len ] = arguments[ len + 2 ]; | ||
return { | ||
tag: tag, | ||
props: props, | ||
children: children | ||
}; | ||
} | ||
var html = htm.bind(h); | ||
function treeify(statics, expr) { | ||
var assign = Object.assign; | ||
try { | ||
Object.assign = function () { | ||
var objs = [], len = arguments.length; | ||
while ( len-- ) objs[ len ] = arguments[ len ]; | ||
return objs; | ||
}; | ||
return html.apply(void 0, [ statics ].concat( expr )); | ||
} finally { | ||
Object.assign = assign; | ||
} | ||
function h(tag, props) { | ||
var arguments$1 = arguments; | ||
} // The tagged template tag function name we're looking for. | ||
// This is static because it's generally assigned via htm.bind(h), | ||
// which could be imported from elsewhere, making tracking impossible. | ||
if (typeof tag === 'string') { | ||
var matches = tag.match(/\$\$\$_h_\[(\d+)\]/); | ||
if (matches) | ||
{ tag = currentExpressions[matches[1]]; } | ||
else | ||
{ tag = t.stringLiteral(tag); } | ||
var htmlName = options.tag || 'html'; | ||
return { | ||
name: 'htm', | ||
visitor: { | ||
TaggedTemplateExpression: function TaggedTemplateExpression(path, state) { | ||
var tag = path.node.tag.name; | ||
if (htmlName[0] === '/' ? patternStringToRegExp(htmlName).test(tag) : tag === htmlName) { | ||
var statics = path.node.quasi.quasis.map(function (e) { return e.value.raw; }); | ||
var expr = path.node.quasi.expressions; | ||
var tree = treeify(statics, expr); | ||
path.replaceWith(transform(tree, state)); | ||
} | ||
var propsNode = t.objectExpression(Object.keys(props).map(function (key) { | ||
var value = props[key]; | ||
if (typeof value === 'string') { | ||
var tokenizer = /\$\$\$_h_\[(\d+)\]/g; | ||
var token, lhs, root, index = 0, lastIndex = 0; | ||
var append = function (expr) { | ||
if (lhs) | ||
{ expr = t.binaryExpression('+', lhs, expr); } | ||
root = (lhs = expr); | ||
}; | ||
while (token = tokenizer.exec(value)) { | ||
append(t.stringLiteral(value.substring(index, token.index))); | ||
append(currentExpressions[token[1]]); | ||
index = token.index; | ||
lastIndex = tokenizer.lastIndex; | ||
} | ||
if (lastIndex < value.length) { | ||
append(t.stringLiteral(value.substring(lastIndex))); | ||
} | ||
value = root; | ||
} else if (typeof value === 'boolean') { | ||
value = t.booleanLiteral(value); | ||
} | ||
return t.objectProperty(propertyName(key), value); | ||
})); | ||
var children = []; | ||
if (arguments.length > 2) { | ||
var stack = []; | ||
for (var i = arguments.length;i-- > 2; ) | ||
{ stack.push(arguments$1[i]); } | ||
while (stack.length) { | ||
var child = stack.pop(); | ||
if (Array.isArray(child)) { | ||
for (var i$1 = child.length;i$1--; ) | ||
{ stack.push(child[i$1]); } | ||
} else if (child != null) { | ||
children.push(child); | ||
} | ||
} | ||
children = children.map(childMapper).filter(Boolean); | ||
} | ||
children = t.arrayExpression(children); | ||
return createVNode(tag, propsNode, children); | ||
} | ||
} | ||
var html = htm.bind(h); | ||
var htmlName = options.tag || 'html'; | ||
return { | ||
name: 'htm', | ||
visitor: { | ||
TaggedTemplateExpression: function TaggedTemplateExpression(path) { | ||
var tag = path.node.tag.name; | ||
if (htmlName[0] === '/' ? patternStringToRegExp(htmlName).test(tag) : tag === htmlName) { | ||
var statics = path.node.quasi.quasis.map(function (e) { return e.value.raw; }); | ||
var expr = path.node.quasi.expressions; | ||
currentExpressions = expr; | ||
path.replaceWith(html.apply(void 0, [ statics ].concat( expr.map(function (p, i) { return ("$$$_h_[" + i + "]"); }) ))); | ||
} | ||
} | ||
} | ||
}; | ||
}; | ||
} | ||
module.exports = htmBabelPlugin; |
{ | ||
"name": "babel-plugin-htm", | ||
"version": "1.0.1", | ||
"version": "2.0.0", | ||
"description": "Babel plugin to compile htm's Tagged Template syntax to hyperscript or inline VNodes.", | ||
@@ -12,4 +12,3 @@ "main": "dist/babel-plugin-htm.js", | ||
"files": [ | ||
"dist", | ||
"index.mjs" | ||
"dist" | ||
], | ||
@@ -32,10 +31,9 @@ "repository": "developit/htm", | ||
"license": "Apache-2.0", | ||
"homepage": "https://github.com/developit/htm/packages/babel-plugin-htm", | ||
"homepage": "https://github.com/developit/htm/tree/master/packages/babel-plugin-htm", | ||
"dependencies": { | ||
"htm": "^1.0.0", | ||
"jsdom": "^11.12.0" | ||
"htm": "^2.0.0" | ||
}, | ||
"devDependencies": { | ||
"microbundle": "^0.6.0" | ||
"microbundle": "^0.8.3" | ||
} | ||
} |
@@ -32,2 +32,29 @@ # `babel-plugin-htm` | ||
### `tag=html` | ||
By default, `babel-plugin-htm` will process all Tagged Templates with a tag function named `html`. To use a different name, use the `tag` option in your Babel configuration: | ||
```js | ||
{"plugins":[ | ||
["babel-plugin-htm", { | ||
"tag": "myCustomHtmlFunction" | ||
}] | ||
]} | ||
``` | ||
### `useBuiltIns=false` | ||
`babel-plugin-htm` transforms prop spreads (`<a ...${b}>`) into `Object.assign()` calls. For browser support reasons, Babel's standard `_extends` helper is used by default. To use native `Object.assign` directly, pass `{useBuiltIns:true}`. | ||
### `variableArity=true` | ||
By default, `babel-plugin-htm` transpiles to the same output as JSX would, which assumes a target function of the form `h(type, props, ...children)`. If, for the purposes of optimization or simplification, you would like all calls to `h()` to be passed exactly 3 arguments, specify `{variableArity:false}` in your Babel config: | ||
```js | ||
html`<div />` // h('div', null, []) | ||
html`<div a />` // h('div', { a: true }, []) | ||
html`<div>b</div>` // h('div', null, ['b']) | ||
html`<div a>b</div>` // h('div', { a: true }, ['b']) | ||
``` | ||
### `pragma=false` _(experimental)_ | ||
@@ -53,3 +80,3 @@ | ||
{ type: 1, tag:"div", props:{ id: "foo" }, text: null, children:[ | ||
{ type: 3, tag: null, props: null, text "hello ", children: null }, | ||
{ type: 3, tag: null, props: null, text: "hello ", children: null }, | ||
you | ||
@@ -56,0 +83,0 @@ ] } |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
1
0
87
15059
4
271
1
+ Addedhtm@2.2.1(transitive)
- Removedjsdom@^11.12.0
- Removedabab@2.0.6(transitive)
- Removedacorn@5.7.46.4.2(transitive)
- Removedacorn-globals@4.3.4(transitive)
- Removedacorn-walk@6.2.0(transitive)
- Removedajv@6.12.6(transitive)
- Removedarray-equal@1.0.2(transitive)
- Removedasn1@0.2.6(transitive)
- Removedassert-plus@1.0.0(transitive)
- Removedasync-limiter@1.0.1(transitive)
- Removedasynckit@0.4.0(transitive)
- Removedaws-sign2@0.7.0(transitive)
- Removedaws4@1.13.2(transitive)
- Removedbcrypt-pbkdf@1.0.2(transitive)
- Removedbrowser-process-hrtime@1.0.0(transitive)
- Removedcaseless@0.12.0(transitive)
- Removedcombined-stream@1.0.8(transitive)
- Removedcore-util-is@1.0.2(transitive)
- Removedcssom@0.3.8(transitive)
- Removedcssstyle@1.4.0(transitive)
- Removeddashdash@1.14.1(transitive)
- Removeddata-urls@1.1.0(transitive)
- Removeddeep-is@0.1.4(transitive)
- Removeddelayed-stream@1.0.0(transitive)
- Removeddomexception@1.0.1(transitive)
- Removedecc-jsbn@0.1.2(transitive)
- Removedescodegen@1.14.3(transitive)
- Removedesprima@4.0.1(transitive)
- Removedestraverse@4.3.0(transitive)
- Removedesutils@2.0.3(transitive)
- Removedextend@3.0.2(transitive)
- Removedextsprintf@1.3.0(transitive)
- Removedfast-deep-equal@3.1.3(transitive)
- Removedfast-json-stable-stringify@2.1.0(transitive)
- Removedfast-levenshtein@2.0.6(transitive)
- Removedforever-agent@0.6.1(transitive)
- Removedform-data@2.3.3(transitive)
- Removedgetpass@0.1.7(transitive)
- Removedhar-schema@2.0.0(transitive)
- Removedhar-validator@5.1.5(transitive)
- Removedhtm@1.0.1(transitive)
- Removedhtml-encoding-sniffer@1.0.2(transitive)
- Removedhttp-signature@1.2.0(transitive)
- Removediconv-lite@0.4.24(transitive)
- Removedis-typedarray@1.0.0(transitive)
- Removedisstream@0.1.2(transitive)
- Removedjsbn@0.1.1(transitive)
- Removedjsdom@11.12.0(transitive)
- Removedjson-schema@0.4.0(transitive)
- Removedjson-schema-traverse@0.4.1(transitive)
- Removedjson-stringify-safe@5.0.1(transitive)
- Removedjsprim@1.4.2(transitive)
- Removedleft-pad@1.3.0(transitive)
- Removedlevn@0.3.0(transitive)
- Removedlodash@4.17.21(transitive)
- Removedlodash.sortby@4.7.0(transitive)
- Removedmime-db@1.52.0(transitive)
- Removedmime-types@2.1.35(transitive)
- Removednwsapi@2.2.16(transitive)
- Removedoauth-sign@0.9.0(transitive)
- Removedoptionator@0.8.3(transitive)
- Removedparse5@4.0.0(transitive)
- Removedperformance-now@2.1.0(transitive)
- Removedpn@1.1.0(transitive)
- Removedprelude-ls@1.1.2(transitive)
- Removedpsl@1.15.0(transitive)
- Removedpunycode@2.3.1(transitive)
- Removedqs@6.5.3(transitive)
- Removedrequest@2.88.2(transitive)
- Removedrequest-promise-core@1.1.4(transitive)
- Removedrequest-promise-native@1.0.9(transitive)
- Removedsafe-buffer@5.2.1(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedsax@1.4.1(transitive)
- Removedsource-map@0.6.1(transitive)
- Removedsshpk@1.18.0(transitive)
- Removedstealthy-require@1.1.1(transitive)
- Removedsymbol-tree@3.2.4(transitive)
- Removedtough-cookie@2.5.0(transitive)
- Removedtr46@1.0.1(transitive)
- Removedtunnel-agent@0.6.0(transitive)
- Removedtweetnacl@0.14.5(transitive)
- Removedtype-check@0.3.2(transitive)
- Removeduri-js@4.4.1(transitive)
- Removeduuid@3.4.0(transitive)
- Removedverror@1.10.0(transitive)
- Removedw3c-hr-time@1.0.2(transitive)
- Removedwebidl-conversions@4.0.2(transitive)
- Removedwhatwg-encoding@1.0.5(transitive)
- Removedwhatwg-mimetype@2.3.0(transitive)
- Removedwhatwg-url@6.5.07.1.0(transitive)
- Removedword-wrap@1.2.5(transitive)
- Removedws@5.2.4(transitive)
- Removedxml-name-validator@3.0.0(transitive)
Updatedhtm@^2.0.0