Skip to content

Commit 28abffb

Browse files
committed
v0.5.0 -- distribution files
1 parent c300337 commit 28abffb

File tree

7 files changed

+416
-2
lines changed

7 files changed

+416
-2
lines changed

babel/index.js

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
var CACHE = {};
2+
var TEMPLATE = document.createElement('template');
3+
var reg = /(\$_h\[\d+\])/g;
4+
function html(statics) {
5+
var tpl = CACHE[statics] || (CACHE[statics] = build(statics));
6+
return tpl(this, arguments);
7+
}
8+
9+
function build(statics) {
10+
var str = statics[0], i = 1;
11+
while (i < statics.length) {
12+
str += '$_h[' + i + ']' + statics[i++];
13+
}
14+
TEMPLATE.innerHTML = str.replace(/<(?:(\/)\/|(\/?)(\$_h\[\d+\]))/g, '<$1$2c c@=$3').replace(/<([\w:-]+)(\s[^<>]*?)?\/>/gi, '<$1$2></$1>').trim();
15+
return Function('h', '$_h', 'return ' + walk((TEMPLATE.content || TEMPLATE).firstChild));
16+
}
17+
18+
function walk(n) {
19+
if (n.nodeType !== 1) {
20+
if (n.nodeType === 3 && n.data)
21+
{ return field(n.data, ','); }
22+
return 'null';
23+
}
24+
var nodeName = "\"" + (n.localName) + "\"", str = '{', sub = '', end = '}';
25+
for (var i = 0;i < n.attributes.length; i++) {
26+
var ref = n.attributes[i];
27+
var name = ref.name;
28+
var value = ref.value;
29+
if (name == 'c@') {
30+
nodeName = value;
31+
continue;
32+
}
33+
if (name.substring(0, 3) === '...') {
34+
end = '})';
35+
str = 'Object.assign(' + str + '},' + name.substring(3) + ',{';
36+
sub = '';
37+
continue;
38+
}
39+
str += sub + "\"" + (name.replace(/:(\w)/g, upper)) + "\":" + (value ? field(value, '+') : true);
40+
sub = ',';
41+
}
42+
str = 'h(' + nodeName + ',' + str + end;
43+
var child = n.firstChild;
44+
while (child) {
45+
str += ',' + walk(child);
46+
child = child.nextSibling;
47+
}
48+
return str + ')';
49+
}
50+
51+
function upper(s, i) {
52+
return i.toUpperCase();
53+
}
54+
55+
function field(value, sep) {
56+
var matches = value.match(reg);
57+
var strValue = JSON.stringify(value);
58+
if (matches != null) {
59+
if (matches[0] === value)
60+
{ return value; }
61+
strValue = strValue.replace(reg, ("\"" + sep + "$1" + sep + "\"")).replace(/"[+,]"/g, '');
62+
if (sep === ',')
63+
{ strValue = "[" + strValue + "]"; }
64+
}
65+
return strValue;
66+
}
67+
68+
var currentExpressions;
69+
function htmBabelPlugin(ref, options) {
70+
var t = ref.types;
71+
if ( options === void 0 ) options = {};
72+
73+
var pragma = options.pragma === false ? false : dottedIdentifier(options.pragma || 'h');
74+
var inlineVNodes = options.monomorphic || pragma === false;
75+
function dottedIdentifier(keypath) {
76+
var path = keypath.split('.');
77+
var out;
78+
for (var i = 0;i < path.length; i++) {
79+
var ident = propertyName(path[i]);
80+
out = i === 0 ? ident : t.memberExpression(out, ident);
81+
}
82+
return out;
83+
}
84+
85+
function patternStringToRegExp(str) {
86+
var parts = str.split('/').slice(1);
87+
var end = parts.pop() || '';
88+
return new RegExp(parts.join('/'), end);
89+
}
90+
91+
function propertyName(key) {
92+
if (key.match(/(^\d|[^a-z0-9_$])/i))
93+
{ return t.stringLiteral(key); }
94+
return t.identifier(key);
95+
}
96+
97+
function stringValue(str) {
98+
if (options.monomorphic) {
99+
return t.objectExpression([t.objectProperty(propertyName('type'), t.numericLiteral(3)),
100+
t.objectProperty(propertyName('tag'), t.nullLiteral()),t.objectProperty(propertyName('props'), t.nullLiteral()),
101+
t.objectProperty(propertyName('children'), t.nullLiteral()),t.objectProperty(propertyName('text'), t.stringLiteral(str))]);
102+
}
103+
return t.stringLiteral(str);
104+
}
105+
106+
function createVNode(tag, props, children) {
107+
if (inlineVNodes) {
108+
return t.objectExpression([options.monomorphic && t.objectProperty(propertyName('type'), t.numericLiteral(1)),
109+
t.objectProperty(propertyName('tag'), tag),t.objectProperty(propertyName('props'), props),
110+
t.objectProperty(propertyName('children'), children),options.monomorphic && t.objectProperty(propertyName('text'), t.nullLiteral())].filter(Boolean));
111+
}
112+
return t.callExpression(pragma, [tag,props,children]);
113+
}
114+
115+
var isVNode = t.isCallExpression;
116+
if (inlineVNodes) {
117+
isVNode = (function (node) {
118+
if (!t.isObjectExpression(node))
119+
{ return false; }
120+
return node.properties[0].value.value !== 3;
121+
});
122+
}
123+
function mapChildren(child, index, children) {
124+
if (typeof child === 'string' && child.trim().length === 0 || child == null) {
125+
if (index === 0 || index === children.length - 1)
126+
{ return null; }
127+
}
128+
if (typeof child === 'string' && isVNode(children[index - 1]) && isVNode(children[index + 1])) {
129+
child = child.trim();
130+
}
131+
if (typeof child === 'string') {
132+
return stringValue(child);
133+
}
134+
return child;
135+
}
136+
137+
function h(tag, props) {
138+
var children = [], len = arguments.length - 2;
139+
while ( len-- > 0 ) children[ len ] = arguments[ len + 2 ];
140+
141+
if (typeof tag === 'string') {
142+
var matches = tag.match(/\$\$\$_h_\[(\d+)\]/);
143+
if (matches)
144+
{ tag = currentExpressions[matches[1]]; }
145+
else
146+
{ tag = t.stringLiteral(tag); }
147+
}
148+
var propsNode = t.objectExpression(Object.keys(props).map(function (key) {
149+
var value = props[key];
150+
if (typeof value === 'string') {
151+
var tokenizer = /\$\$\$_h_\[(\d+)\]/g;
152+
var token, lhs, root, index = 0, lastIndex = 0;
153+
var append = function (expr) {
154+
if (lhs)
155+
{ expr = t.binaryExpression('+', lhs, expr); }
156+
root = (lhs = expr);
157+
};
158+
while (token = tokenizer.exec(value)) {
159+
append(t.stringLiteral(value.substring(index, token.index)));
160+
append(currentExpressions[token[1]]);
161+
index = token.index;
162+
lastIndex = tokenizer.lastIndex;
163+
}
164+
if (lastIndex < value.length) {
165+
append(t.stringLiteral(value.substring(lastIndex)));
166+
}
167+
value = root;
168+
} else if (typeof value === 'boolean') {
169+
value = t.booleanLiteral(value);
170+
}
171+
return t.objectProperty(propertyName(key), value);
172+
}));
173+
if (Array.isArray(children)) {
174+
children = t.arrayExpression(children.map(mapChildren).filter(Boolean));
175+
}
176+
return createVNode(tag, propsNode, children);
177+
}
178+
179+
var html$$1 = html.bind(h);
180+
var htmlName = options.tag || 'html';
181+
return {
182+
name: 'htm',
183+
visitor: {
184+
TaggedTemplateExpression: function TaggedTemplateExpression(path) {
185+
var tag = path.node.tag.name;
186+
if (htmlName[0] === '/' ? patternStringToRegExp(htmlName).test(tag) : tag === htmlName) {
187+
var statics = path.node.quasi.quasis.map(function (e) { return e.value.raw; });
188+
var expr = path.node.quasi.expressions;
189+
currentExpressions = expr;
190+
path.replaceWith(html$$1.apply(void 0, [ statics ].concat( expr.map(function (p, i) { return ("$$$_h_[" + i + "]"); }) )));
191+
}
192+
}
193+
}
194+
};
195+
}
196+
197+
module.exports = htmBabelPlugin;

0 commit comments

Comments
 (0)