'use strict' var find = require('property-information/find') var normalize = require('property-information/normalize') var parseSelector = require('hast-util-parse-selector') var spaces = require('space-separated-tokens').parse var commas = require('comma-separated-tokens').parse module.exports = factory function factory(schema, defaultTagName) { return h /* Hyperscript compatible DSL for creating virtual HAST trees. */ function h(selector, properties) { var node = parseSelector(selector, defaultTagName) var children = Array.prototype.slice.call(arguments, 2) var property if (properties && isChildren(properties, node)) { children.unshift(properties) properties = null } if (properties) { for (property in properties) { addProperty(node.properties, property, properties[property]) } } addChild(node.children, children) if (node.tagName === 'template') { node.content = {type: 'root', children: node.children} node.children = [] } return node } function addProperty(properties, key, value) { var info var property var result /* Ignore nully and NaN values. */ if (value === null || value === undefined || value !== value) { return } info = find(schema, key) property = info.property result = value /* Handle list values. */ if (typeof result === 'string') { if (info.spaceSeparated) { result = spaces(result) } else if (info.commaSeparated) { result = commas(result) } else if (info.commaOrSpaceSeparated) { result = spaces(commas(result).join(' ')) } } /* Accept `object` on style. */ if (property === 'style' && typeof value !== 'string') { result = style(result) } /* Class-names (which can be added both on the `selector` and here). */ if (property === 'className' && properties.className) { result = properties.className.concat(result) } properties[property] = parsePrimitives(info, property, result) } } function isChildren(value, node) { return ( typeof value === 'string' || 'length' in value || isNode(node.tagName, value) ) } function isNode(tagName, value) { var type = value.type if (tagName === 'input' || !type || typeof type !== 'string') { return false } if (typeof value.children === 'object' && 'length' in value.children) { return true } type = type.toLowerCase() if (tagName === 'button') { return ( type !== 'menu' && type !== 'submit' && type !== 'reset' && type !== 'button' ) } return 'value' in value } function addChild(nodes, value) { var index var length if (typeof value === 'string' || typeof value === 'number') { nodes.push({type: 'text', value: String(value)}) return } if (typeof value === 'object' && 'length' in value) { index = -1 length = value.length while (++index < length) { addChild(nodes, value[index]) } return } if (typeof value !== 'object' || !('type' in value)) { throw new Error('Expected node, nodes, or string, got `' + value + '`') } nodes.push(value) } /* Parse a (list of) primitives. */ function parsePrimitives(info, name, value) { var index var length var result if (typeof value !== 'object' || !('length' in value)) { return parsePrimitive(info, name, value) } length = value.length index = -1 result = [] while (++index < length) { result[index] = parsePrimitive(info, name, value[index]) } return result } /* Parse a single primitives. */ function parsePrimitive(info, name, value) { var result = value if (info.number || info.positiveNumber) { if (!isNaN(result) && result !== '') { result = Number(result) } } else if (info.boolean || info.overloadedBoolean) { /* Accept `boolean` and `string`. */ if ( typeof result === 'string' && (result === '' || normalize(value) === normalize(name)) ) { result = true } } return result } function style(value) { var result = [] var key for (key in value) { result.push([key, value[key]].join(': ')) } return result.join('; ') }