@@ -39,7 +39,7 @@ func defaultFilter(value: Any?, arguments: [Any?]) -> Any? {
39
39
40
40
func joinFilter( value: Any ? , arguments: [ Any ? ] ) throws -> Any ? {
41
41
guard arguments. count < 2 else {
42
- throw TemplateSyntaxError ( " 'join' filter takes a single argument " )
42
+ throw TemplateSyntaxError ( " 'join' filter takes at most one argument " )
43
43
}
44
44
45
45
let separator = stringify ( arguments. first ?? " " )
@@ -55,7 +55,7 @@ func joinFilter(value: Any?, arguments: [Any?]) throws -> Any? {
55
55
56
56
func splitFilter( value: Any ? , arguments: [ Any ? ] ) throws -> Any ? {
57
57
guard arguments. count < 2 else {
58
- throw TemplateSyntaxError ( " 'split' filter takes a single argument " )
58
+ throw TemplateSyntaxError ( " 'split' filter takes at most one argument " )
59
59
}
60
60
61
61
let separator = stringify ( arguments. first ?? " " )
@@ -111,3 +111,67 @@ func indent(_ content: String, indentation: String, indentFirst: Bool) -> String
111
111
return result. joined ( separator: " \n " )
112
112
}
113
113
114
+ func mapFilter( value: Any ? , arguments: [ Any ? ] , context: Context ) throws -> Any ? {
115
+ guard arguments. count >= 1 && arguments. count <= 2 else {
116
+ throw TemplateSyntaxError ( " 'map' filter takes one or two arguments " )
117
+ }
118
+
119
+ let attribute = stringify ( arguments [ 0 ] )
120
+ let variable = Variable ( " map_item. \( attribute) " )
121
+ let defaultValue = arguments. count == 2 ? arguments [ 1 ] : nil
122
+
123
+ let resolveVariable = { ( item: Any ) throws -> Any in
124
+ let result = try context. push ( dictionary: [ " map_item " : item] ) {
125
+ try variable. resolve ( context)
126
+ }
127
+ if let result = result { return result }
128
+ else if let defaultValue = defaultValue { return defaultValue }
129
+ else { return result as Any }
130
+ }
131
+
132
+
133
+ if let array = value as? [ Any ] {
134
+ return try array. map ( resolveVariable)
135
+ } else {
136
+ return try resolveVariable ( value as Any )
137
+ }
138
+ }
139
+
140
+ func compactFilter( value: Any ? , arguments: [ Any ? ] , context: Context ) throws -> Any ? {
141
+ guard arguments. count <= 1 else {
142
+ throw TemplateSyntaxError ( " 'compact' filter takes at most one argument " )
143
+ }
144
+
145
+ guard var array = value as? [ Any ? ] else { return value }
146
+
147
+ if arguments. count == 1 {
148
+ guard let mapped = try mapFilter ( value: array, arguments: arguments, context: context) as? [ Any ? ] else {
149
+ return value
150
+ }
151
+ array = mapped
152
+ }
153
+
154
+ return array. flatMap ( { item -> Any ? in
155
+ if let unwrapped = item, String ( describing: unwrapped) != " nil " { return unwrapped }
156
+ else { return nil }
157
+ } )
158
+ }
159
+
160
+ func filterEachFilter( value: Any ? , arguments: [ Any ? ] , context: Context ) throws -> Any ? {
161
+ guard arguments. count == 1 else {
162
+ throw TemplateSyntaxError ( " 'filterEach' filter takes one argument " )
163
+ }
164
+
165
+ let attribute = stringify ( arguments [ 0 ] )
166
+ let expr = try context. environment. compileExpression ( components: Token . block ( value: attribute) . components ( ) )
167
+
168
+ if let array = value as? [ Any ] {
169
+ return try array. filter {
170
+ try context. push ( dictionary: [ " $0 " : $0] ) {
171
+ try expr. evaluate ( context: context)
172
+ }
173
+ }
174
+ }
175
+
176
+ return value
177
+ }
0 commit comments