/
Extension.swift
100 lines (84 loc) · 3.19 KB
/
Extension.swift
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
open class Extension {
typealias TagParser = (TokenParser, Token) throws -> NodeType
var tags = [String: TagParser]()
var filters = [String: Filter]()
public init() {
}
/// Registers a new template tag
public func registerTag(_ name: String, parser: @escaping (TokenParser, Token) throws -> NodeType) {
tags[name] = parser
}
/// Registers a simple template tag with a name and a handler
public func registerSimpleTag(_ name: String, handler: @escaping (Context) throws -> String) {
registerTag(name, parser: { parser, token in
return SimpleNode(token: token, handler: handler)
})
}
/// Registers boolean filter with it's negative counterpart
public func registerFilter(name: String, negativeFilterName: String, filter: @escaping (Any?) throws -> Bool?) {
filters[name] = .simple(filter)
filters[negativeFilterName] = .simple {
guard let result = try filter($0) else { return nil }
return !result
}
}
/// Registers a template filter with the given name
public func registerFilter(_ name: String, filter: @escaping (Any?) throws -> Any?) {
filters[name] = .simple(filter)
}
/// Registers a template filter with the given name
public func registerFilter(_ name: String, filter: @escaping (Any?, [Any?]) throws -> Any?) {
filters[name] = .arguments({ value, args, _ in try filter(value, args) })
}
/// Registers a template filter with the given name
public func registerFilter(_ name: String, filter: @escaping (Any?, [Any?], Context) throws -> Any?) {
filters[name] = .arguments(filter)
}
}
class DefaultExtension: Extension {
override init() {
super.init()
registerDefaultTags()
registerDefaultFilters()
}
fileprivate func registerDefaultTags() {
registerTag("for", parser: ForNode.parse)
registerTag("if", parser: IfNode.parse)
registerTag("ifnot", parser: IfNode.parse_ifnot)
#if !os(Linux)
registerTag("now", parser: NowNode.parse)
#endif
registerTag("include", parser: IncludeNode.parse)
registerTag("extends", parser: ExtendsNode.parse)
registerTag("block", parser: BlockNode.parse)
registerTag("filter", parser: FilterNode.parse)
}
fileprivate func registerDefaultFilters() {
registerFilter("default", filter: defaultFilter)
registerFilter("capitalize", filter: capitalise)
registerFilter("uppercase", filter: uppercase)
registerFilter("lowercase", filter: lowercase)
registerFilter("join", filter: joinFilter)
registerFilter("split", filter: splitFilter)
registerFilter("indent", filter: indentFilter)
registerFilter("filter", filter: filterFilter)
}
}
protocol FilterType {
func invoke(value: Any?, arguments: [Any?], context: Context) throws -> Any?
}
enum Filter: FilterType {
case simple(((Any?) throws -> Any?))
case arguments(((Any?, [Any?], Context) throws -> Any?))
func invoke(value: Any?, arguments: [Any?], context: Context) throws -> Any? {
switch self {
case let .simple(filter):
if !arguments.isEmpty {
throw TemplateSyntaxError("cannot invoke filter with an argument")
}
return try filter(value)
case let .arguments(filter):
return try filter(value, arguments, context)
}
}
}