Dynamic names support (#49)

* Dynamic names support

* Add support for dynamic names in parent tags

* Support all dynamic names spec

* Swift 5.8 compile fix
This commit is contained in:
Adam Fowler
2024-08-28 08:31:06 +01:00
committed by GitHub
parent a010f172c5
commit 01b1f21ed6
5 changed files with 178 additions and 8 deletions

View File

@@ -232,29 +232,55 @@ extension MustacheTemplate {
case ">":
// partial
parser.unsafeAdvance()
// skip whitespace
parser.read(while: \.isWhitespace)
var dynamic = false
if parser.current() == "*" {
parser.unsafeAdvance()
dynamic = true
}
let name = try parsePartialName(&parser, state: state)
if whiteSpaceBefore.count > 0 {
tokens.append(.text(String(whiteSpaceBefore)))
}
if self.isStandalone(&parser, state: state) {
setNewLine = true
tokens.append(.partial(name, indentation: String(whiteSpaceBefore), inherits: nil))
if dynamic {
tokens.append(.dynamicNamePartial(name, indentation: String(whiteSpaceBefore), inherits: nil))
} else {
tokens.append(.partial(name, indentation: String(whiteSpaceBefore), inherits: nil))
}
} else {
tokens.append(.partial(name, indentation: nil, inherits: nil))
if dynamic {
tokens.append(.dynamicNamePartial(name, indentation: nil, inherits: nil))
} else {
tokens.append(.partial(name, indentation: nil, inherits: nil))
}
}
whiteSpaceBefore = ""
case "<":
// partial with inheritance
parser.unsafeAdvance()
let name = try parsePartialName(&parser, state: state)
// skip whitespace
parser.read(while: \.isWhitespace)
let sectionName = try parsePartialName(&parser, state: state)
let name: String
let dynamic: Bool
if sectionName.first == "*" {
dynamic = true
name = String(sectionName.dropFirst())
} else {
dynamic = false
name = sectionName
}
if whiteSpaceBefore.count > 0 {
tokens.append(.text(String(whiteSpaceBefore)))
}
if self.isStandalone(&parser, state: state) {
setNewLine = true
}
let sectionTokens = try parse(&parser, state: state.withInheritancePartial(name))
let sectionTokens = try parse(&parser, state: state.withInheritancePartial(sectionName))
var inherit: [String: MustacheTemplate] = [:]
// parse tokens in section to extract inherited sections
for token in sectionTokens {
@@ -267,7 +293,11 @@ extension MustacheTemplate {
throw Error.illegalTokenInsideInheritSection
}
}
tokens.append(.partial(name, indentation: String(whiteSpaceBefore), inherits: inherit))
if dynamic {
tokens.append(.dynamicNamePartial(name, indentation: String(whiteSpaceBefore), inherits: inherit))
} else {
tokens.append(.partial(name, indentation: String(whiteSpaceBefore), inherits: inherit))
}
whiteSpaceBefore = ""
case "$":
@@ -478,7 +508,7 @@ extension MustacheTemplate {
return state.newLine && self.hasLineFinished(&parser)
}
private static let sectionNameCharsWithoutBrackets = Set<Character>("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_?")
private static let sectionNameChars = Set<Character>("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_?()")
private static let sectionNameCharsWithoutBrackets = Set<Character>("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_?*")
private static let sectionNameChars = Set<Character>("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_?()*")
private static let partialNameChars = Set<Character>("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_()")
}

View File

@@ -101,6 +101,28 @@ extension MustacheTemplate {
return template.render(context: context.withPartial(indented: indentation, inheriting: overrides))
}
case .dynamicNamePartial(let name, let indentation, let overrides):
let child = self.getChild(named: name, transforms: [], context: context)
guard let childName = child as? String else {
return ""
}
if var template = context.library?.getTemplate(named: childName) {
#if DEBUG
if context.reloadPartials {
guard let filename = template.filename else {
preconditionFailure("Can only use reload if template was generated from a file")
}
do {
guard let partialTemplate = try MustacheTemplate(filename: filename) else { return "Cannot find template at \(filename)" }
template = partialTemplate
} catch {
return "\(error)"
}
}
#endif
return template.render(context: context.withPartial(indented: indentation, inheriting: overrides))
}
case .contentType(let contentType):
context = context.withContentType(contentType)

View File

@@ -68,6 +68,7 @@ public struct MustacheTemplate: Sendable {
case blockDefinition(name: String, template: MustacheTemplate)
case blockExpansion(name: String, default: MustacheTemplate, indentation: String?)
case partial(String, indentation: String?, inherits: [String: MustacheTemplate]?)
case dynamicNamePartial(String, indentation: String?, inherits: [String: MustacheTemplate]?)
case contentType(MustacheContentType)
}