diff --git a/Sources/Stencil/ForTag.swift b/Sources/Stencil/ForTag.swift index e735457..ac3e298 100644 --- a/Sources/Stencil/ForTag.swift +++ b/Sources/Stencil/ForTag.swift @@ -96,6 +96,10 @@ class ForNode: NodeType { let count = values.count var result = "" + // collect parent loop contexts + let parentLoopContexts = (context["forloop"] as? [String: Any])? + .filter { ($1 as? [String: Any])?["label"] != nil } ?? [:] + for (index, item) in zip(0..., values) { var forContext: [String: Any] = [ "first": index == 0, @@ -106,7 +110,9 @@ class ForNode: NodeType { ] if let label = label { forContext["label"] = label + forContext[label] = forContext } + forContext.merge(parentLoopContexts) { lhs, _ in lhs } var shouldBreak = false result += try context.push(dictionary: ["forloop": forContext]) { diff --git a/Tests/StencilTests/ForNodeSpec.swift b/Tests/StencilTests/ForNodeSpec.swift index ab8def5..9d31b58 100644 --- a/Tests/StencilTests/ForNodeSpec.swift +++ b/Tests/StencilTests/ForNodeSpec.swift @@ -514,6 +514,51 @@ final class ForNodeTests: XCTestCase { try expect(template.render(self.context)).toThrow() } } + + func testAccessLabeled() { + it("can access labeled outer loop context from inner loop") { + let template = Template(templateString: """ + {% outer: for item in 1...2 %}\ + {% for item in items %}\ + {{ forloop.counter }}-{{ forloop.outer.counter }},\ + {% endfor %}---\ + {% endfor %} + """) + try expect(template.render(self.context)) == """ + 1-1,2-1,3-1,---1-2,2-2,3-2,--- + """ + } + + it("can access labeled outer loop from double inner loop") { + let template = Template(templateString: """ + {% outer: for item in 1...2 %}{% for item in 1...2 %}\ + {% for item in items %}\ + {{ forloop.counter }}-{{ forloop.outer.counter }},\ + {% endfor %}---{% endfor %} + {% endfor %} + """) + try expect(template.render(self.context)) == """ + 1-1,2-1,3-1,---1-1,2-1,3-1,--- + 1-2,2-2,3-2,---1-2,2-2,3-2,--- + + """ + } + + it("can access two labeled outer loop contexts from inner loop") { + let template = Template(templateString: """ + {% outer1: for item in 1...2 %}{% outer2: for item in 1...2 %}\ + {% for item in items %}\ + {{ forloop.counter }}-{{ forloop.outer2.counter }}-{{ forloop.outer1.counter }},\ + {% endfor %}---{% endfor %} + {% endfor %} + """) + try expect(template.render(self.context)) == """ + 1-1-1,2-1-1,3-1-1,---1-2-1,2-2-1,3-2-1,--- + 1-1-2,2-1-2,3-1-2,---1-2-2,2-2-2,3-2-2,--- + + """ + } + } } // MARK: - Helpers