From f95e19206e2d1108e84736dca008389d4d5a6b6b Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Mon, 8 Aug 2022 11:18:41 +0100 Subject: [PATCH] Use special set of chars for partial filename (#18) --- .../HummingbirdMustache/Template+Parser.swift | 22 +++++++++++++------ .../LibraryTests.swift | 18 +++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/Sources/HummingbirdMustache/Template+Parser.swift b/Sources/HummingbirdMustache/Template+Parser.swift index ec7b782..b8634af 100644 --- a/Sources/HummingbirdMustache/Template+Parser.swift +++ b/Sources/HummingbirdMustache/Template+Parser.swift @@ -199,7 +199,7 @@ extension HBMustacheTemplate { case ">": // partial parser.unsafeAdvance() - let (name, _) = try parseName(&parser, state: state) + let name = try parsePartialName(&parser, state: state) if whiteSpaceBefore.count > 0 { tokens.append(.text(String(whiteSpaceBefore))) } @@ -214,9 +214,7 @@ extension HBMustacheTemplate { case "<": // partial with inheritance parser.unsafeAdvance() - let (name, transform) = try parseName(&parser, state: state) - // ERROR: can't have transform applied to inherited sections - guard transform == nil else { throw Error.transformAppliedToInheritanceSection } + let name = try parsePartialName(&parser, state: state) var indent: String? if self.isStandalone(&parser, state: state) { setNewLine = true @@ -225,7 +223,7 @@ extension HBMustacheTemplate { tokens.append(.text(indent!)) whiteSpaceBefore = "" } - let sectionTokens = try parse(&parser, state: state.withSectionName(name, transform: transform)) + let sectionTokens = try parse(&parser, state: state.withSectionName(name)) var inherit: [String: HBMustacheTemplate] = [:] // parse tokens in section to extract inherited sections for token in sectionTokens { @@ -321,6 +319,15 @@ extension HBMustacheTemplate { } } + /// parse partial name + static func parsePartialName(_ parser: inout HBParser, state: ParserState) throws -> String { + parser.read(while: \.isWhitespace) + let text = String(parser.read(while: self.sectionNameChars)) + parser.read(while: \.isWhitespace) + guard try parser.read(string: state.endDelimiter) else { throw Error.unfinishedName } + return text + } + static func parseComment(_ parser: inout HBParser, state: ParserState) throws -> String { let text = try parser.read(untilString: state.endDelimiter, throwOnOverflow: true, skipToEnd: true) return String(text) @@ -390,6 +397,7 @@ extension HBMustacheTemplate { return state.newLine && self.hasLineFinished(&parser) } - private static let sectionNameCharsWithoutBrackets = Set("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._?") - private static let sectionNameChars = Set("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._?()") + private static let sectionNameCharsWithoutBrackets = Set("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_?") + private static let sectionNameChars = Set("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_?()") + private static let partialNameChars = Set("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_()") } diff --git a/Tests/HummingbirdMustacheTests/LibraryTests.swift b/Tests/HummingbirdMustacheTests/LibraryTests.swift index 94c3795..8f4cee5 100644 --- a/Tests/HummingbirdMustacheTests/LibraryTests.swift +++ b/Tests/HummingbirdMustacheTests/LibraryTests.swift @@ -29,6 +29,24 @@ final class LibraryTests: XCTestCase { XCTAssertEqual(library.render(object, withTemplate: "test"), "value1value2") } + func testPartial() throws { + let fs = FileManager() + try? fs.createDirectory(atPath: "templates", withIntermediateDirectories: false) + let mustache = Data("{{#value}}{{.}}{{/value}}".utf8) + try mustache.write(to: URL(fileURLWithPath: "templates/test-partial.mustache")) + let mustache2 = Data("{{>test-partial}}".utf8) + try mustache2.write(to: URL(fileURLWithPath: "templates/test.mustache")) + defer { + XCTAssertNoThrow(try fs.removeItem(atPath: "templates/test-partial.mustache")) + XCTAssertNoThrow(try fs.removeItem(atPath: "templates/test.mustache")) + XCTAssertNoThrow(try fs.removeItem(atPath: "templates")) + } + + let library = try HBMustacheLibrary(directory: "./templates") + let object = ["value": ["value1", "value2"]] + XCTAssertEqual(library.render(object, withTemplate: "test"), "value1value2") + } + func testLibraryParserError() throws { let fs = FileManager() try? fs.createDirectory(atPath: "templates", withIntermediateDirectories: false)