This repository has been archived by the owner on Jul 21, 2022. It is now read-only.
/
lt.js
106 lines (92 loc) · 3.44 KB
/
lt.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
!function () {
var _isArray = Array.isArray || function(obj) {
return Object.prototype.toString.call(obj) === '[object Array]'
}
// print value
function print(value, escape) {
return typeof value === 'undefined'
? '' // placeholder
: ( escape && /[&"<>]/.test(value += '') )
// escape HTML chars http://www.w3.org/TR/html4/charset.html#h-5.3.2
? value.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>')
: value
}
// get defined value from context stack
function get(scope, depth) {
scope = scope
.replace(/\s/g, '') // clear space
.replace(/^(\.\.\/)+/, function (all, one) {
depth -= all.length / one.length // parent path
return ''
})
if (depth < 0) return "undefined" // out of context
if (scope === '.') return "s" +depth // this
var scopeParts = scope.split('.')
var code = ''
while (depth > 0) {
var scopeSegment = scopeParts[0]
// parent context searching
code += "typeof s" +depth +"." +scopeSegment +" !== 'undefined' ? "
// nested path context searching
for (var i=1, len=scopeParts.length; i<len; i++) {
code += "typeof s" +depth +"." +scopeSegment +" === 'undefined' ? undefined : "
scopeSegment += "." +scopeParts[i]
}
code += "s" +depth +"." +scopeSegment +" : "
depth--
}
var scopeSegment = scopeParts[0]
// parent context searching
// code += "typeof s" +depth +"." +scopeSegment +" !== 'undefined' ? "
// nested path context searching
for (var i=1, len=scopeParts.length; i<len; i++) {
code += "typeof s" +depth +"." +scopeSegment +" === 'undefined' ? undefined : "
scopeSegment += "." +scopeParts[i]
}
code += "s" +depth +"." +scopeSegment // +" : "
return code
}
// core
function compile(source) {
var inverted = 0, depth = 0 // context stack depth
var compiled = new Function("s0", "print", "_isArray", "var tmp, out = '" +source
.replace(/\\/g, "\\\\") // escape \
.replace(/'/g, "\\'") // escape '
.replace(/\{\{([\^#/!&]?)([^{\n]+?)\}\}/g, function (a, flag, scope) { // block
switch (flag) {
case '^': // if not
inverted++
return "'; tmp = " +get(scope, depth)
+ " ; if (!tmp || (_isArray(tmp) && tmp.length === 0)) { out += '"
case '#': // if/each/TODO lambdas/TODO helper
return "'; tmp = " +get(scope, depth)
+ " ; var list" +depth +" = tmp ? _isArray(tmp) ? tmp : [tmp] : []"
+ " ; for (var i" +depth +"=0, len" +depth +"=list" +depth +".length"
+ " ; i" +depth +"<len" +depth +"; i" +depth +"++)"
+ " { var s" +(depth+1) +" = list" +depth +"[i" +depth++ +"]; out += '"
case '/': // close
inverted > 0 ? inverted-- : depth--
return "'} out += '"
case '!': // comments
return ""
//case '>': // TODO partials
case '&': // print noescape
return "' +print(" +get(scope, depth) +", false) +'"
default : // print escape
return "' +print(" +get(scope, depth) +", true) +'"
}
})
.replace(/\n/g, "\\n") // escape CR
.replace(/\r/g, "\\r") // escape LF
+"'; return out")
var render = function (data) {
return compiled(data, print, _isArray)
}
return render.render = render // render api
}
compile.compile = compile // compile api
// export
if (typeof define === 'function' && define.amd) define(function () { return compile })
else if (typeof module === 'object' && module.exports) module.exports = compile
else this.lt = compile
}()