diff --git a/CHANGELOG.md b/CHANGELOG.md index 044efe02..58a4ed6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ - Fixed rendering `{{ block.super }}` with several levels of inheritance - Fixed checking dictionary values for nil in `default` filter - Fixed comparing string variables with string literals, in Swift 4 string literals became `Substring` and thus couldn't be directly compared to strings. -- Fixed using spaces in filter expression +- Fixed using spaces in filter expressions and variables lists ## 0.10.1 diff --git a/Sources/Tokenizer.swift b/Sources/Tokenizer.swift index 0e4bf1e9..e2812b9a 100644 --- a/Sources/Tokenizer.swift +++ b/Sources/Tokenizer.swift @@ -36,10 +36,37 @@ extension String { components.append(word) } - return components + return smartJoin(components) } } +// joins back components around characters used in variables lists and filters +private func smartJoin(_ components: [String]) -> [String] { + var joinedComponents = components + // convert ["a", "|", "b"] and ["a|", "b"] to ["a|b"] + // do not allow ["a", "|b"] + for char in [",", "|", ":"] { + while let index = joinedComponents.index(of: char) { + if index > 0 { + joinedComponents[index-1] += char + + if joinedComponents.count > index + 1 { + joinedComponents[index-1] += joinedComponents[index+1] + joinedComponents.remove(at: index+1) + } + } + joinedComponents.remove(at: index) + } + while let index = joinedComponents.index(where: { $0.hasSuffix(char) }) { + if joinedComponents.count > index { + joinedComponents[index] += joinedComponents[index+1] + joinedComponents.remove(at: index+1) + } + } + } + return joinedComponents +} + public enum Token : Equatable { /// A token representing a piece of text. diff --git a/Tests/StencilTests/ForNodeSpec.swift b/Tests/StencilTests/ForNodeSpec.swift index 8804f0bf..56df535a 100644 --- a/Tests/StencilTests/ForNodeSpec.swift +++ b/Tests/StencilTests/ForNodeSpec.swift @@ -104,8 +104,8 @@ func testForNode() { try expect(try node.render(context)) == "empty" } - $0.it("can render a filter") { - let templateString = "{% for article in ars|default:articles %}" + + $0.it("can render a filter with spaces") { + let templateString = "{% for article in ars | default: a, b , articles %}" + "- {{ article.title }} by {{ article.author }}.\n" + "{% endfor %}\n" @@ -128,7 +128,7 @@ func testForNode() { } $0.it("can iterate over dictionary") { - let templateString = "{% for key,value in dict %}" + + let templateString = "{% for key, value in dict %}" + "{{ key }}: {{ value }}\n" + "{% endfor %}\n"