fix(for): Support looping dictionaries

This commit is contained in:
Kyle Fuller
2017-04-18 23:26:56 +01:00
parent 6f48fe2d91
commit a8d680b30e
2 changed files with 62 additions and 35 deletions

View File

@@ -1,6 +1,8 @@
import Foundation
class ForNode : NodeType {
let resolvable: Resolvable
let loopVariable:String
let loopVariables: [String]
let nodes:[NodeType]
let emptyNodes: [NodeType]
let `where`: Expression?
@@ -13,7 +15,11 @@ class ForNode : NodeType {
throw TemplateSyntaxError("'for' statements should use the following 'for x in y where condition' `\(token.contents)`.")
}
let loopVariable = components[1]
let loopVariables = components[1].characters
.split(separator: ",")
.map(String.init)
.map { $0.trimmingCharacters(in: CharacterSet.whitespaces) }
let variable = components[3]
var emptyNodes = [NodeType]()
@@ -36,42 +42,52 @@ class ForNode : NodeType {
} else {
`where` = nil
}
return ForNode(resolvable: filter, loopVariable: loopVariable, nodes: forNodes, emptyNodes:emptyNodes, where: `where`)
return ForNode(resolvable: filter, loopVariables: loopVariables, nodes: forNodes, emptyNodes:emptyNodes, where: `where`)
}
init(resolvable: Resolvable, loopVariable:String, nodes:[NodeType], emptyNodes:[NodeType], where: Expression? = nil) {
init(resolvable: Resolvable, loopVariables: [String], nodes:[NodeType], emptyNodes:[NodeType], where: Expression? = nil) {
self.resolvable = resolvable
self.loopVariable = loopVariable
self.loopVariables = loopVariables
self.nodes = nodes
self.emptyNodes = emptyNodes
self.where = `where`
}
func render(_ context: Context) throws -> String {
let values = try resolvable.resolve(context)
let resolved = try resolvable.resolve(context)
if var values = values as? [Any], values.count > 0 {
if let `where` = self.where {
values = try values.filter({ item -> Bool in
return try context.push(dictionary: [loopVariable: item]) { () -> Bool in
try `where`.evaluate(context: context)
}
})
}
if values.count > 0 {
let count = values.count
return try values.enumerated().map { index, item in
let forContext: [String: Any] = [
"first": index == 0,
"last": index == (count - 1),
"counter": index + 1,
]
var values: [Any]
return try context.push(dictionary: [loopVariable: item, "forloop": forContext]) {
if let dictionary = resolved as? [String: Any], !dictionary.isEmpty {
values = Array(dictionary.keys)
} else if let array = resolved as? [Any] {
values = array
} else {
values = []
}
if let `where` = self.where {
values = try values.filter({ item -> Bool in
return try context.push(dictionary: [loopVariables.first!: item]) { () -> Bool in
try `where`.evaluate(context: context)
}
})
}
if !values.isEmpty {
let count = values.count
return try values.enumerated().map { index, item in
let forContext: [String: Any] = [
"first": index == 0,
"last": index == (count - 1),
"counter": index + 1,
]
return try context.push(dictionary: [loopVariables.first!: item, "forloop": forContext]) {
try renderNodes(nodes, context)
}
}.joined(separator: "")
}
}
}.joined(separator: "")
}
return try context.push {