-
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Related to wooorm/property-information#6. Related to GH-6. Related to GH-4.
- Loading branch information
Showing
7 changed files
with
917 additions
and
450 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
'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, children) { | ||
var node = parseSelector(selector, defaultTagName) | ||
var property | ||
|
||
if (!children && properties && isChildren(properties, node)) { | ||
children = 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 (value === null || value === undefined) { | ||
return | ||
} | ||
|
||
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('; ') | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
'use strict' | ||
|
||
var schema = require('property-information/html') | ||
var factory = require('./factory') | ||
|
||
var html = factory(schema, 'div') | ||
html.displayName = 'html' | ||
|
||
module.exports = html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,180 +1,3 @@ | ||
'use strict' | ||
|
||
var parseSelector = require('hast-util-parse-selector') | ||
var camelcase = require('camelcase') | ||
var propertyInformation = require('property-information') | ||
var spaces = require('space-separated-tokens').parse | ||
var commas = require('comma-separated-tokens').parse | ||
|
||
module.exports = h | ||
|
||
/* Hyperscript compatible DSL for creating virtual HAST | ||
* trees. */ | ||
function h(selector, properties, children) { | ||
var node = parseSelector(selector) | ||
var property | ||
|
||
if ( | ||
properties && | ||
!children && | ||
(typeof properties === 'string' || | ||
'length' in properties || | ||
isNode(node.tagName, properties)) | ||
) { | ||
children = 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 | ||
} | ||
|
||
/* Check if `value` is a valid child node of `tagName`. */ | ||
function isNode(tagName, value) { | ||
var type = value.type | ||
|
||
if (typeof type === 'string') { | ||
type = type.toLowerCase() | ||
} | ||
|
||
if (tagName === 'input' || !type || typeof type !== 'string') { | ||
return false | ||
} | ||
|
||
if (typeof value.children === 'object' && 'length' in value.children) { | ||
return true | ||
} | ||
|
||
if (tagName === 'button') { | ||
return ( | ||
type !== 'menu' && | ||
type !== 'submit' && | ||
type !== 'reset' && | ||
type !== 'button' | ||
) | ||
} | ||
|
||
return 'value' in value | ||
} | ||
|
||
/* Add `value` as a child to `nodes`. */ | ||
function addChild(nodes, value) { | ||
var index | ||
var length | ||
|
||
if (value === null || value === undefined) { | ||
return | ||
} | ||
|
||
if (typeof value === 'string' || typeof value === 'number') { | ||
value = {type: 'text', value: String(value)} | ||
} | ||
|
||
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) | ||
} | ||
|
||
/* Add `name` and its `value` to `properties`. `properties` can | ||
* be prefilled by `parseSelector`: it can have `id` and `className` | ||
* properties. */ | ||
function addProperty(properties, name, value) { | ||
var info = propertyInformation(name) || {} | ||
var result = value | ||
var key | ||
|
||
/* Ignore nully and NaN values. */ | ||
if (value === null || value === undefined || value !== value) { | ||
return | ||
} | ||
|
||
/* Handle values. */ | ||
if (name === 'style') { | ||
/* Accept `object`. */ | ||
if (typeof value !== 'string') { | ||
result = [] | ||
|
||
for (key in value) { | ||
result.push([key, value[key]].join(': ')) | ||
} | ||
|
||
result = result.join('; ') | ||
} | ||
} else if (info.spaceSeparated) { | ||
/* Accept both `string` and `Array`. */ | ||
result = typeof value === 'string' ? spaces(result) : result | ||
|
||
/* Class-names (which can be added both on | ||
* the `selector` and here). */ | ||
if (name === 'class' && properties.className) { | ||
result = properties.className.concat(result) | ||
} | ||
} else if (info.commaSeparated) { | ||
/* Accept both `string` and `Array`. */ | ||
result = typeof value === 'string' ? commas(result) : result | ||
} | ||
|
||
result = parsePrimitive(info, name, result) | ||
|
||
properties[info.propertyName || camelcase(name)] = result | ||
} | ||
|
||
/* Parse a (list of) primitives. */ | ||
function parsePrimitive(info, name, value) { | ||
var result = value | ||
var index | ||
var length | ||
|
||
if (typeof value === 'object' && 'length' in value) { | ||
length = value.length | ||
index = -1 | ||
result = [] | ||
|
||
while (++index < length) { | ||
result[index] = parsePrimitive(info, name, value[index]) | ||
} | ||
|
||
return result | ||
} | ||
|
||
if (info.numeric || info.positiveNumeric) { | ||
if (!isNaN(result) && result !== '') { | ||
result = Number(result) | ||
} | ||
} else if (info.boolean || info.overloadedBoolean) { | ||
/* Accept `boolean` and `string`. */ | ||
if ( | ||
typeof result === 'string' && | ||
(result === '' || value.toLowerCase() === name) | ||
) { | ||
result = true | ||
} | ||
} | ||
|
||
return result | ||
} | ||
module.exports = require('./html') |
Oops, something went wrong.