Skip to content

Commit 6ee1515

Browse files
committed
Initial commit
0 parents  commit 6ee1515

15 files changed

+1269
-0
lines changed

.editorconfig

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
root = true
2+
3+
[*]
4+
indent_style = space
5+
indent_size = 4
6+
end_of_line = lf
7+
charset = utf-8
8+
trim_trailing_whitespace = true
9+
insert_final_newline = true
10+
11+
[*.{json,remarkrc,eslintrc,sh}]
12+
indent_size = 2
13+
14+
[*.md]
15+
trim_trailing_whitespace = false

.eslintignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
coverage/
2+
example.js
3+
hastscript.js
4+
hastscript.min.js

.eslintrc

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": "eslint:recommended",
3+
"rules": {
4+
"quotes": [2, "single"]
5+
}
6+
}

.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.DS_Store
2+
*.log
3+
coverage/
4+
node_modules/
5+
hastscript.js
6+
hastscript.min.js

.jscs.json

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"excludeFiles": [
3+
"coverage/",
4+
"node_modules/",
5+
"hastscript.js",
6+
"hastscript.min.js"
7+
],
8+
"preset": "yandex",
9+
"requireQuotedKeysInObjects": true,
10+
"disallowQuotedKeysInObjects": false,
11+
"maximumLineLength": {
12+
"value": 79,
13+
"allExcept": [
14+
"regex",
15+
"urlComments"
16+
]
17+
},
18+
"jsDoc": {
19+
"checkAnnotations": "jsdoc3",
20+
"checkParamExistence": true,
21+
"checkParamNames": true,
22+
"checkRedundantAccess": true,
23+
"checkRedundantParams": true,
24+
"checkRedundantReturns": true,
25+
"checkReturnTypes": true,
26+
"checkTypes": "strictNativeCase",
27+
"enforceExistence": true,
28+
"requireHyphenBeforeDescription": true,
29+
"requireNewlineAfterDescription": true,
30+
"requireParamDescription": true,
31+
"requireParamTypes": true,
32+
"requireReturnDescription": true,
33+
"requireReturnTypes": true
34+
}
35+
}

.remarkrc

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"output": true,
3+
"plugins": [
4+
"comment-config",
5+
"github",
6+
"lint",
7+
"usage",
8+
"validate-links"
9+
],
10+
"settings": {
11+
"bullet": "*"
12+
}
13+
}

.travis.yml

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
language: node_js
2+
node_js:
3+
- '0.10'
4+
- '0.11'
5+
- '0.12'
6+
- '4.0'
7+
- '5.0'
8+
- iojs
9+
sudo: false
10+
after_script: npm install codecov.io && cat ./coverage/lcov.info | codecov
11+
deploy:
12+
- provider: npm
13+
14+
api_key:
15+
secure: l2iOveDemDpIVr8+8OFm+3yKUz7ix1r0v6Izy4XHegV/6X5PAFws6PEyDSFZvwhq2ROx8vSxXgDiRykdbIMWQSHYEbF8pF4RZPjIl+qO/Mn+aIqYErHDT8y8/UHfTzVR9ZJhr+3kfdA//Slu1GQUpc2cNahttZ5YCUeeafSEFkf6bNOZSV2/R9zneAnEc6Rdhif4y6TInNKFUsFzn0i5vz0MgS/NCecpsONKpGzK8xXz/yppr6kJGOJDkVi0WVIBnGC9tpu1oITb1rRpl6p+3sKFpc0+QoNNkFPol9SUFIZSNazTfNH2r6TpkGLZP37n28vFiXiurrLUsVZ2fSZMZaJLcNrGUe0GDPEYyVcqDohmMs2fpudCDWBiuumPaPieBGNYVARjSXZs8Fwe4bcp480JxhTdAecD2f506euSpe7q3g7cmuF14cutA51hH6lMZgHuLWS7nE0LZLwO6wtg9q0d1pFHwebxI4j9D/zXeopQ8YzkPSxqIsxZGBj8QnJWlDt0OLSwVKjXPMDr34OjY7I4LQdsiK9ChozaPbYg/WMqILOi7d4iFHE82RxIf71EAyFtvKvFclerqvB0/TwMqiy2vKJgFOikX+6v70oVWPERZ4DOO9rguDztQkSqMCJVN/0HEGVVfSJLEPspCi1CX8cU8f6cFoExJ6PDXMGJOw4=
16+
on:
17+
tags: true
18+
node: '5.0'
19+
- provider: releases
20+
api_key:
21+
secure: Kj34ePmdMrhEkSMMXUrVd1tX/0l9OnAze3cNAjeyKuFn3mSdM9DcXy7TstJb023tJQ57PIX+LDFyZCGe8vubwSfFeULZLBIyaSsaZw6wfZTkobla99f3oWm+1iGhUU7aLbH+31U4k6aEUsU2S/VtPo/TbrW6/P8wzGiWIC2j1OObnZqiB2a0UUlqEGEqsMwv/9tI/EMkx/qYN2/MJJUj1KYORMQcZCI8cv6R2XnSSZ7lHeuOsN67hB/WotZyfrihsFRY0ANT4J94ateiX2E9BFBLFtjQwa8T2JsFh8Q+Ex7otgQIegu+Jum9x8/EAUGtiopgz4PCeWCey2Ri0mywKLIl+ewQvAlX0zNjreBKNpumcPd4UKXCLQHTpPjbNjNzgGyVBT161xipx1PrCgAKlSX2PS3dydLArwOlYnE+EK8xbBCHonLsnyHrm4xSJKZk1ypeNMEd7jaxBbkFlHkvcWselIA6Y4xSjxb9szY8QlDU5oKuNzOtVZrOxHY9IXijP3aub889D4yzbtNc1oBhDFpdiPLbHO0KAo6bOzR4/kDLjm0KEOYHcmZqMDSX+YKwfOOfJEVGKTjekpi1FBoN9in6Y3piJgpkvURjp6tDMYaC9C2dBFGbhKNPNQDLSoMvfBzdemAk8AJjx6tTT9ZdmWCNcP+XjGG2vuNDZEz7sq4=
22+
file:
23+
- "hastscript.js"
24+
- "hastscript.min.js"
25+
on:
26+
tags: true

LICENSE

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
(The MIT License)
2+
3+
Copyright (c) 2016 Titus Wormer <[email protected]>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
'Software'), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

example.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Dependencies:
2+
var h = require('./index.js');
3+
4+
// AST:
5+
var tree = h('.foo#some-id', [
6+
h('span', 'some text'),
7+
h('input', {
8+
'type': 'text',
9+
'value': 'foo'
10+
}),
11+
h('a.alpha', {
12+
'class': 'bravo charlie',
13+
'style': 'color:/*red*/purple',
14+
'download': 'download'
15+
}, ['delta', 'echo'])
16+
]);
17+
18+
// Yields:
19+
console.log('js', require('util').inspect(tree, {'depth': null}));

history.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<!--remark setext-->
2+
3+
<!--lint disable no-multiple-toplevel-headings -->
4+
5+
0.0.0 / 2016-02-24
6+
==================

index.js

+226
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
/**
2+
* @author Titus Wormer
3+
* @copyright 2016 Titus Wormer
4+
* @license MIT
5+
* @module hastscript
6+
* @fileoverview Hyperscript compatible DSL for creating
7+
* virtual HAST trees.
8+
*/
9+
10+
'use strict';
11+
12+
/* eslint-env commonjs */
13+
14+
/*
15+
* Dependencies.
16+
*/
17+
18+
var parseSelector = require('hast-util-parse-selector');
19+
var camelcase = require('camelcase');
20+
var propertyInformation = require('property-information');
21+
var cssDeclarations = require('css-declarations').parse;
22+
var spaces = require('space-separated-tokens').parse;
23+
var commas = require('comma-separated-tokens').parse;
24+
25+
/**
26+
* Parse a (list of) primitives.
27+
*
28+
* @param {Object} info - Information.
29+
* @param {string} name - Property name.
30+
* @param {*} value - Values to parse.
31+
* @return {*} - Parsed `value`.
32+
*/
33+
function parsePrimitive(info, name, value) {
34+
var result = value;
35+
var index;
36+
var length;
37+
38+
if (typeof value === 'object' && 'length' in value) {
39+
length = value.length;
40+
index = -1;
41+
result = [];
42+
43+
while (++index < length) {
44+
result[index] = parsePrimitive(info, name, value[index]);
45+
}
46+
47+
return result;
48+
}
49+
50+
if (info.boolean) {
51+
result = true;
52+
} else if (info.numeric || info.positiveNumeric) {
53+
result = Number(result);
54+
} else if (info.overloadedBoolean) {
55+
/*
56+
* Accept `boolean` and `string`.
57+
*/
58+
59+
if (
60+
typeof result === 'string' &&
61+
(result === '' || value.toLowerCase() === name)
62+
) {
63+
result = true;
64+
}
65+
}
66+
67+
return result;
68+
}
69+
70+
/**
71+
* Add `name` and its `value` to `properties`.
72+
* `properties` can be prefilled by `parseSelector`:
73+
* it can have `id` and `className` properties.
74+
*
75+
* @param {Object} properties - Attributes.
76+
* @param {string} name - Property name.
77+
* @param {*} value - Property value.
78+
*/
79+
function addProperty(properties, name, value) {
80+
var info = propertyInformation(name) || {};
81+
var result = value;
82+
var key;
83+
84+
/*
85+
* Ignore nully and NaN values.
86+
*/
87+
88+
if (value === null || value === undefined || value !== value) {
89+
return;
90+
}
91+
92+
/*
93+
* Handle values.
94+
*/
95+
96+
if (name === 'style') {
97+
/*
98+
* Accept both `string` and `object`.
99+
*/
100+
101+
if (typeof value === 'string') {
102+
result = cssDeclarations(result);
103+
} else {
104+
result = {};
105+
106+
for (key in value) {
107+
result[key] = value[key];
108+
}
109+
}
110+
} else if (info.spaceSeparated) {
111+
/*
112+
* Accept both `string` and `Array`.
113+
*/
114+
115+
result = typeof value === 'string' ? spaces(result) : result;
116+
117+
/*
118+
* Class-names (which can be added both on
119+
* the `selector` and here).
120+
*/
121+
122+
if (name === 'class' && properties.className) {
123+
result = properties.className.concat(result);
124+
}
125+
} else if (info.commaSeparated) {
126+
/*
127+
* Accept both `string` and `Array`.
128+
*/
129+
130+
result = typeof value === 'string' ? commas(result) : result;
131+
}
132+
133+
result = parsePrimitive(info, name, result);
134+
135+
properties[info.propertyName || camelcase(name)] = result;
136+
}
137+
138+
/**
139+
* Add `value` as a child to `nodes`.
140+
*
141+
* @param {Array.<Node>} nodes - List of siblings.
142+
* @param {string|Node|Array.<string|Node>} value - List of
143+
* children or child to add.
144+
*/
145+
function addChild(nodes, value) {
146+
var index;
147+
var length;
148+
149+
if (value === null || value === undefined) {
150+
return;
151+
}
152+
153+
if (typeof value === 'string' || typeof value === 'number') {
154+
value = {
155+
'type': 'text',
156+
'value': String(value)
157+
};
158+
}
159+
160+
if (typeof value === 'object' && 'length' in value) {
161+
index = -1;
162+
length = value.length;
163+
164+
while (++index < length) {
165+
addChild(nodes, value[index]);
166+
}
167+
168+
return;
169+
}
170+
171+
if (typeof value !== 'object' || !('type' in value)) {
172+
throw new Error(
173+
'Expected node, nodes, or string, got `' + value + '`'
174+
);
175+
}
176+
177+
nodes.push(value);
178+
}
179+
180+
/**
181+
* Hyperscript compatible DSL for creating virtual HAST
182+
* trees.
183+
*
184+
* @param {string?} selector - Simple CSS selector to parse.
185+
* @param {Object?} properties - HTML attributes to add.
186+
* @param {string|Array.<string|Node>} children - List of
187+
* children to add.
188+
* @return {Node} - HAST node.
189+
*/
190+
function h(selector, properties, children) {
191+
var node = parseSelector(selector);
192+
var property;
193+
194+
if (
195+
properties &&
196+
!children &&
197+
(
198+
typeof properties === 'string' ||
199+
'length' in properties ||
200+
// Only allow a node at the `properties`
201+
// position when it isn’t an `input`, as those
202+
// use HTML `type` and `value` attributes too
203+
// and are void.
204+
(node.tagName !== 'input' && 'type' in properties)
205+
)
206+
) {
207+
children = properties;
208+
properties = null;
209+
}
210+
211+
if (properties) {
212+
for (property in properties) {
213+
addProperty(node.properties, property, properties[property]);
214+
}
215+
}
216+
217+
addChild(node.children, children);
218+
219+
return node;
220+
}
221+
222+
/*
223+
* Expose.
224+
*/
225+
226+
module.exports = h;

0 commit comments

Comments
 (0)