-
-
Notifications
You must be signed in to change notification settings - Fork 231
/
value.ts
78 lines (76 loc) · 2.23 KB
/
value.ts
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
import { evalExp } from '../render/syntax'
import { FilterArgs, Filter } from './filter/filter'
import Context from '../context/context'
export default class Value {
private strictFilters: boolean
private initial: string
private filters: Array<Filter> = []
/**
* @param str value string, like: "i have a dream | truncate: 3
*/
constructor (str: string, strictFilters: boolean) {
const tokens = Value.tokenize(str)
this.strictFilters = strictFilters
this.initial = tokens[0]
this.parseFilters(tokens, 1)
}
private parseFilters (tokens: string[], begin: number) {
let i = begin
while (i < tokens.length) {
if (tokens[i] !== '|') {
i++
continue
}
const j = ++i
while (i < tokens.length && tokens[i] !== '|') i++
this.parseFilter(tokens, j, i)
}
}
private parseFilter (tokens: string[], begin: number, end: number) {
const name = tokens[begin]
const args: FilterArgs = []
let argName, argValue
for (let i = begin + 1; i < end + 1; i++) {
if (i === end || tokens[i] === ',') {
if (argName || argValue) {
args.push(argName ? [argName, argValue] : <string>argValue)
}
argValue = argName = undefined
} else if (tokens[i] === ':') {
argName = argValue
argValue = undefined
} else if (argValue === undefined) {
argValue = tokens[i]
}
}
this.filters.push(new Filter(name, args, this.strictFilters))
}
async value (ctx: Context) {
let val = await evalExp(this.initial, ctx)
for (const filter of this.filters) {
val = await filter.render(val, ctx)
}
return val
}
static tokenize (str: string): Array<'|' | ',' | ':' | string> {
const tokens = []
let i = 0
while (i < str.length) {
const ch = str[i]
if (ch === '"' || ch === "'") {
const j = i
for (i += 2; i < str.length && str[i - 1] !== ch; ++i);
tokens.push(str.slice(j, i))
} else if (/\s/.test(ch)) {
i++
} else if (/[|,:]/.test(ch)) {
tokens.push(str[i++])
} else {
const j = i++
for (; i < str.length && !/[|,:\s]/.test(str[i]); ++i);
tokens.push(str.slice(j, i))
}
}
return tokens
}
}