-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
122 lines (106 loc) · 3.06 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
function render(a) {
return arguments.length < 2 ? _render(a)
: Array.prototype.map.call(arguments, _render, this).join("");
};
function canConcatenate(tester) {
// empty string must be okay here.
return tester === String(tester) || (tester && isNumber(tester));
}
function isNumber(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
function isInvalidTagName(tester) {
return !tester || tester !== String(tester) || isNumber(tester[0]);
}
function json_btoa(x) {
const json = JSON.stringify(x);
try {
return btoa(json);
} catch (e) {
return Buffer.from(json).toString("base64");
}
}
function renderAttributeValue(val) {
return Array.isArray(val) ? val.join(" ")
: canConcatenate(val) ? val
: json_btoa(JSON.stringify(val));
}
function renderAttribute([k, v]) {
return v === true
? k
: v ? [k, "=", "\"", renderAttributeValue(v), "\""].join("")
: "";
}
function renderAttributes(form) {
const attrs = form === Object(form)
? Object.entries(form).map(renderAttribute).filter(x => x)
: "";
return attrs.length
? [" ", attrs.join(" ")].join("")
: "";
}
function renderRest(form) {
return Array.isArray(form) && form.length
? _render(form)
: canConcatenate(form) ? form
: "";
}
function renderSecondPosition(form, selfClosing) {
const closer = selfClosing ? "" : ">";
const rest = renderRest(form);
return (
rest
? [closer, rest]
: [renderAttributes(form), closer]
).join("");
}
function renderElement(a, selfClosing) {
return [
a.map(function(form, i) {
return i < 1
? "<" + form
: i === 1
? renderSecondPosition(form, selfClosing)
: renderRest(form, selfClosing);
}).join(""),
!selfClosing ? "</" + a[0] + ">" : " />"
].join("");
}
class InvalidTagName extends Error {
constructor(x) {
super(...arguments);
this.name = "InvalidTagName";
this.message = `${
JSON.stringify(x[0])
} (having type "${typeof x[0]}") is not a valid tag name. Context: ${
JSON.stringify(x)
}`;
}
static throw() {
throw new InvalidTagName(...arguments);
}
}
function _render (a) {
return canConcatenate(a) ? a
: !Array.isArray(a) ? ""
: Array.isArray(a[0]) ? a.map(_render, this).join("")
: isInvalidTagName(a[0])
? InvalidTagName.throw(a)
: (function(last) {
return renderElement(
a,
a.length > 2 ? false
: typeof last === "undefined" ? false
: Array.isArray(last) ? false
: !canConcatenate(last)
);
})(a.length > 1 && a[a.length - 1]);
}
module.exports = Object.create(null, {
render: {value: render},
renderElement: {value: renderElement},
renderAttributes: {value: renderAttributes},
renderAttribute: {value: renderAttribute},
renderAttributeValue: {value: renderAttributeValue},
isNumber: {value: isNumber}
});