-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
125 lines (103 loc) · 2.83 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
122
123
124
125
/**
* Expose the compile function
*/
exports = module.exports = compile;
/**
* Expose the interpolate function
*/
exports.interpolate = interpolate;
/**
* Interpolate a string without a compilation step
*
* THIS IS NOT RECOMMENDED FOR PRODUCTION USE
*
* @param {String} string
* @param {Object?} params
* @param {Object?} opts
*/
function interpolate(string, params, opts) {
return compile(string, opts)(params).join('');
};
/**
* Compile a string into an interpolate function
*
* @param {String} string
* @param {Object?} opts
* @return {Function}
*/
function compile(string, opts) {
opts = opts || {};
var open = escapeRegex(opts.open || '%{');
var close = opts.close || '}';
var char = close.charAt(0);
var re = new RegExp('(' + escapeRegex(open) + ' *[^' + escapeRegex(char) + ']+ *' + escapeRegex(close) + ')', 'g');
var params = 'params';
var fallback = opts.fallback ?
' || ' + JSON.stringify(opts.fallback) :
'';
var rawParts = string.split(re);
var parts = [], paramsObj = {};
for (var i = 0, l = rawParts.length, part, prop; i < l; i++) {
part = rawParts[i];
// skip the blank parts
if (!part) continue;
// it's normal text
if (part.indexOf(open) !== 0 && part.indexOf(close) !== part.length - close.length) {
parts.push(JSON.stringify(part));
continue;
}
// it's a interpolation part
part = part.slice(open.length, -close.length);
prop = formatProperty(part, params);
part = prop[1] || part;
paramsObj[part] = (paramsObj[part] || 0) + 1;
parts.push(prop[0] + fallback);
}
var body = 'function(' + params + '){' + params + ' = ' + params + ' || {};return [' + parts.join(', ') + '];}';
var fn = (new Function('exec', 'return ' + body))(exec);
fn.params = paramsObj;
return fn;
}
/**
* Execute a function for a block
*
* @param {String} name
* @param {String} contents
* @param {Object} params
* @return {Any}
*/
function exec(name, contents, params) {
var fn = params[name];
var type = typeof fn;
if (type === 'function') return fn(contents, params);
return type === 'undefined' ? contents : fn;
}
/**
* Escape any reserved regex characters
*
* @param {String} str
* @return {String}
*/
function escapeRegex(str) {
return str.replace(/[\^\-\]\\]/g, function(c) {
return '\\' + c;
});
}
/**
* Format a property accessor
*
* @param {String} prop
* @param {String} params
* @return {String}
*/
var re = /^[\w\d]+$/;
function formatProperty(prop, params) {
if (!re.test(prop)) {
var parts = prop.split(/ *: */);
if (parts.length === 1) return [params + '[' + JSON.stringify(prop) + ']'];
return ['exec("' + parts[0] + '", "' + parts[1] + '", ' + params + ')', parts[0]];
}
var int = parseInt(prop, 10);
if (isNaN(int)) return [params + '.' + prop];
return [params + '[' + prop + ']'];
}