diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c87fe72..5f009cbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,15 @@ [Yonas Kolb](https://github.com/yonaskolb) [#394](https://github.com/stencilproject/Stencil/pull/214) +- Adds support for using spaces in filter expression + [Ilya Puchka](https://github.com/yonaskolb) + [#178](https://github.com/stencilproject/Stencil/pull/178) + ### Bug Fixes - Fixed using quote as a filter parameter + [Ilya Puchka](https://github.com/yonaskolb) + [#210](https://github.com/stencilproject/Stencil/pull/210) ## 0.11.0 (2018-04-04) diff --git a/Sources/ForTag.swift b/Sources/ForTag.swift index cb96657d..4d7eff27 100644 --- a/Sources/ForTag.swift +++ b/Sources/ForTag.swift @@ -24,7 +24,7 @@ class ForNode : NodeType { let loopVariables = components[1].characters .split(separator: ",") .map(String.init) - .map { $0.trimmingCharacters(in: CharacterSet.whitespaces) } + .map { $0.trim(character: " ") } var emptyNodes = [NodeType]() diff --git a/Sources/Tokenizer.swift b/Sources/Tokenizer.swift index 81680f2d..bb3320b0 100644 --- a/Sources/Tokenizer.swift +++ b/Sources/Tokenizer.swift @@ -10,6 +10,21 @@ extension String { var singleQuoteCount = 0 var doubleQuoteCount = 0 + let specialCharacters = ",|:" + func appendWord(_ word: String) { + if components.count > 0 { + if let precedingChar = components.last?.characters.last, specialCharacters.characters.contains(precedingChar) { + components[components.count-1] += word + } else if specialCharacters.contains(word) { + components[components.count-1] += word + } else { + components.append(word) + } + } else { + components.append(word) + } + } + for character in self.characters { if character == "'" { singleQuoteCount += 1 } else if character == "\"" { doubleQuoteCount += 1 } @@ -19,7 +34,7 @@ extension String { if separate != separator { word.append(separate) } else if (singleQuoteCount % 2 == 0 || doubleQuoteCount % 2 == 0) && !word.isEmpty { - components.append(word) + appendWord(word) word = "" } @@ -33,7 +48,7 @@ extension String { } if !word.isEmpty { - components.append(word) + appendWord(word) } return components diff --git a/Sources/Variable.swift b/Sources/Variable.swift index 9563c89b..b3570219 100644 --- a/Sources/Variable.swift +++ b/Sources/Variable.swift @@ -209,11 +209,11 @@ extension Dictionary : Normalizable { func parseFilterComponents(token: String) -> (String, [Variable]) { var components = token.smartSplit(separator: ":") - let name = components.removeFirst() + let name = components.removeFirst().trim(character: " ") let variables = components .joined(separator: ":") .smartSplit(separator: ",") - .map { Variable($0) } + .map { Variable($0.trim(character: " ")) } return (name, variables) } diff --git a/Tests/StencilTests/FilterSpec.swift b/Tests/StencilTests/FilterSpec.swift index 5224c121..f8de1b87 100644 --- a/Tests/StencilTests/FilterSpec.swift +++ b/Tests/StencilTests/FilterSpec.swift @@ -78,9 +78,9 @@ func testFilter() { } $0.it("allows whitespace in expression") { - let template = Template(templateString: "{{ name | uppercase }}") - let result = try template.render(Context(dictionary: ["name": "kyle"])) - try expect(result) == "KYLE" + let template = Template(templateString: "{{ value | join : \", \" }}") + let result = try template.render(Context(dictionary: ["value": ["One", "Two"]])) + try expect(result) == "One, Two" } $0.it("throws when you pass arguments to simple filter") { diff --git a/Tests/StencilTests/ForNodeSpec.swift b/Tests/StencilTests/ForNodeSpec.swift index a8b90dfd..4bb3fca4 100644 --- a/Tests/StencilTests/ForNodeSpec.swift +++ b/Tests/StencilTests/ForNodeSpec.swift @@ -111,8 +111,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" @@ -182,7 +182,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 }}," + "{% endfor %}"