'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 var own = {}.hasOwnProperty function factory(schema, defaultTagName, caseSensitive) { var adjust = caseSensitive ? createAdjustMap(caseSensitive) : null 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 name = node.tagName.toLowerCase() var property node.tagName = adjust && own.call(adjust, name) ? adjust[name] : name 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 nullish 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('; ') } function createAdjustMap(values) { var length = values.length var index = -1 var result = {} var value while (++index < length) { value = values[index] result[value.toLowerCase()] = value } return result }