Remove HB prefix, make Parser private (#26)
This commit is contained in:
14
README.md
14
README.md
@@ -8,7 +8,7 @@ While Hummingbird Mustache has been designed to be used with the Hummingbird ser
|
|||||||
|
|
||||||
Load your templates from the filesystem
|
Load your templates from the filesystem
|
||||||
```swift
|
```swift
|
||||||
let library = HBMustacheLibrary("folder/my/templates/are/in")
|
let library = MustacheLibrary("folder/my/templates/are/in")
|
||||||
```
|
```
|
||||||
This will look for all the files with the extension ".mustache" in the specified folder and subfolders and attempt to load them. Each file is registed with the name of the file (with subfolder, if inside a subfolder) minus the "mustache" extension.
|
This will look for all the files with the extension ".mustache" in the specified folder and subfolders and attempt to load them. Each file is registed with the name of the file (with subfolder, if inside a subfolder) minus the "mustache" extension.
|
||||||
|
|
||||||
@@ -20,23 +20,23 @@ let output = library.render(object, withTemplate: "myTemplate")
|
|||||||
|
|
||||||
### Using with Hummingbird
|
### Using with Hummingbird
|
||||||
|
|
||||||
HummingbirdMustache doesn't have any integration with Hummingbird as I wanted to keep the library dependency free. But if you are going to use the library with Hummingbird it is recommended you extend `HBApplication` to store an instance of your library.
|
HummingbirdMustache doesn't have any integration with Hummingbird as I wanted to keep the library dependency free. But if you are going to use the library with Hummingbird it is recommended you extend `Application` to store an instance of your library.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
extension HBApplication {
|
extension Application {
|
||||||
var mustache: HBMustacheLibrary {
|
var mustache: MustacheLibrary {
|
||||||
get { self.extensions.get(\.mustache) }
|
get { self.extensions.get(\.mustache) }
|
||||||
set { self.extensions.set(\.mustache, value: newValue) }
|
set { self.extensions.set(\.mustache, value: newValue) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension HBRequest {
|
extension Request {
|
||||||
var mustache: HBMustacheLibrary { self.application.mustache }
|
var mustache: MustacheLibrary { self.application.mustache }
|
||||||
}
|
}
|
||||||
// load mustache templates from templates folder
|
// load mustache templates from templates folder
|
||||||
application.mustache = try .init(directory: "templates")
|
application.mustache = try .init(directory: "templates")
|
||||||
```
|
```
|
||||||
You can now access your mustache templates via `HBRequest` eg `HBRequest.mustache.render(obj, withTemplate: "myTemplate")`
|
You can now access your mustache templates via `Request` eg `Request.mustache.render(obj, withTemplate: "myTemplate")`
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
|
|||||||
@@ -13,20 +13,20 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// Protocol for content types
|
/// Protocol for content types
|
||||||
public protocol HBMustacheContentType: Sendable {
|
public protocol MustacheContentType: Sendable {
|
||||||
/// escape text for this content type eg for HTML replace "<" with "<"
|
/// escape text for this content type eg for HTML replace "<" with "<"
|
||||||
func escapeText(_ text: String) -> String
|
func escapeText(_ text: String) -> String
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Text content type where no character is escaped
|
/// Text content type where no character is escaped
|
||||||
struct HBTextContentType: HBMustacheContentType {
|
struct TextContentType: MustacheContentType {
|
||||||
func escapeText(_ text: String) -> String {
|
func escapeText(_ text: String) -> String {
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// HTML content where text is escaped for HTML output
|
/// HTML content where text is escaped for HTML output
|
||||||
struct HBHTMLContentType: HBMustacheContentType {
|
struct HTMLContentType: MustacheContentType {
|
||||||
func escapeText(_ text: String) -> String {
|
func escapeText(_ text: String) -> String {
|
||||||
return text.htmlEscape()
|
return text.htmlEscape()
|
||||||
}
|
}
|
||||||
@@ -36,9 +36,9 @@ struct HBHTMLContentType: HBMustacheContentType {
|
|||||||
///
|
///
|
||||||
/// The string is read from the "CONTENT_TYPE" pragma `{{% CONTENT_TYPE: type}}`. Replace type with
|
/// The string is read from the "CONTENT_TYPE" pragma `{{% CONTENT_TYPE: type}}`. Replace type with
|
||||||
/// the content type required. The default available types are `TEXT` and `HTML`. You can register your own
|
/// the content type required. The default available types are `TEXT` and `HTML`. You can register your own
|
||||||
/// with `HBMustacheContentTypes.register`.
|
/// with `MustacheContentTypes.register`.
|
||||||
public enum HBMustacheContentTypes {
|
public enum MustacheContentTypes {
|
||||||
static func get(_ name: String) -> HBMustacheContentType? {
|
static func get(_ name: String) -> MustacheContentType? {
|
||||||
return self.types[name]
|
return self.types[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,12 +46,12 @@ public enum HBMustacheContentTypes {
|
|||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - contentType: Content type
|
/// - contentType: Content type
|
||||||
/// - name: String to identify it
|
/// - name: String to identify it
|
||||||
public static func register(_ contentType: HBMustacheContentType, named name: String) {
|
public static func register(_ contentType: MustacheContentType, named name: String) {
|
||||||
self.types[name] = contentType
|
self.types[name] = contentType
|
||||||
}
|
}
|
||||||
|
|
||||||
static var types: [String: HBMustacheContentType] = [
|
static var types: [String: MustacheContentType] = [
|
||||||
"HTML": HBHTMLContentType(),
|
"HTML": HTMLContentType(),
|
||||||
"TEXT": HBTextContentType(),
|
"TEXT": TextContentType(),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,31 +13,31 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// Context while rendering mustache tokens
|
/// Context while rendering mustache tokens
|
||||||
struct HBMustacheContext {
|
struct MustacheContext {
|
||||||
let stack: [Any]
|
let stack: [Any]
|
||||||
let sequenceContext: HBMustacheSequenceContext?
|
let sequenceContext: MustacheSequenceContext?
|
||||||
let indentation: String?
|
let indentation: String?
|
||||||
let inherited: [String: HBMustacheTemplate]?
|
let inherited: [String: MustacheTemplate]?
|
||||||
let contentType: HBMustacheContentType
|
let contentType: MustacheContentType
|
||||||
let library: HBMustacheLibrary?
|
let library: MustacheLibrary?
|
||||||
|
|
||||||
/// initialize context with a single objectt
|
/// initialize context with a single objectt
|
||||||
init(_ object: Any, library: HBMustacheLibrary? = nil) {
|
init(_ object: Any, library: MustacheLibrary? = nil) {
|
||||||
self.stack = [object]
|
self.stack = [object]
|
||||||
self.sequenceContext = nil
|
self.sequenceContext = nil
|
||||||
self.indentation = nil
|
self.indentation = nil
|
||||||
self.inherited = nil
|
self.inherited = nil
|
||||||
self.contentType = HBHTMLContentType()
|
self.contentType = HTMLContentType()
|
||||||
self.library = library
|
self.library = library
|
||||||
}
|
}
|
||||||
|
|
||||||
private init(
|
private init(
|
||||||
stack: [Any],
|
stack: [Any],
|
||||||
sequenceContext: HBMustacheSequenceContext?,
|
sequenceContext: MustacheSequenceContext?,
|
||||||
indentation: String?,
|
indentation: String?,
|
||||||
inherited: [String: HBMustacheTemplate]?,
|
inherited: [String: MustacheTemplate]?,
|
||||||
contentType: HBMustacheContentType,
|
contentType: MustacheContentType,
|
||||||
library: HBMustacheLibrary? = nil
|
library: MustacheLibrary? = nil
|
||||||
) {
|
) {
|
||||||
self.stack = stack
|
self.stack = stack
|
||||||
self.sequenceContext = sequenceContext
|
self.sequenceContext = sequenceContext
|
||||||
@@ -48,7 +48,7 @@ struct HBMustacheContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// return context with object add to stack
|
/// return context with object add to stack
|
||||||
func withObject(_ object: Any) -> HBMustacheContext {
|
func withObject(_ object: Any) -> MustacheContext {
|
||||||
var stack = self.stack
|
var stack = self.stack
|
||||||
stack.append(object)
|
stack.append(object)
|
||||||
return .init(
|
return .init(
|
||||||
@@ -62,13 +62,13 @@ struct HBMustacheContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// return context with indent and parameter information for invoking a partial
|
/// return context with indent and parameter information for invoking a partial
|
||||||
func withPartial(indented: String?, inheriting: [String: HBMustacheTemplate]?) -> HBMustacheContext {
|
func withPartial(indented: String?, inheriting: [String: MustacheTemplate]?) -> MustacheContext {
|
||||||
let indentation: String? = if let indented {
|
let indentation: String? = if let indented {
|
||||||
(self.indentation ?? "") + indented
|
(self.indentation ?? "") + indented
|
||||||
} else {
|
} else {
|
||||||
self.indentation
|
self.indentation
|
||||||
}
|
}
|
||||||
let inherits: [String: HBMustacheTemplate]? = if let inheriting {
|
let inherits: [String: MustacheTemplate]? = if let inheriting {
|
||||||
if let originalInherits = self.inherited {
|
if let originalInherits = self.inherited {
|
||||||
originalInherits.merging(inheriting) { value, _ in value }
|
originalInherits.merging(inheriting) { value, _ in value }
|
||||||
} else {
|
} else {
|
||||||
@@ -82,13 +82,13 @@ struct HBMustacheContext {
|
|||||||
sequenceContext: nil,
|
sequenceContext: nil,
|
||||||
indentation: indentation,
|
indentation: indentation,
|
||||||
inherited: inherits,
|
inherited: inherits,
|
||||||
contentType: HBHTMLContentType(),
|
contentType: HTMLContentType(),
|
||||||
library: self.library
|
library: self.library
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// return context with sequence info and sequence element added to stack
|
/// return context with sequence info and sequence element added to stack
|
||||||
func withSequence(_ object: Any, sequenceContext: HBMustacheSequenceContext) -> HBMustacheContext {
|
func withSequence(_ object: Any, sequenceContext: MustacheSequenceContext) -> MustacheContext {
|
||||||
var stack = self.stack
|
var stack = self.stack
|
||||||
stack.append(object)
|
stack.append(object)
|
||||||
return .init(
|
return .init(
|
||||||
@@ -102,7 +102,7 @@ struct HBMustacheContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// return context with sequence info and sequence element added to stack
|
/// return context with sequence info and sequence element added to stack
|
||||||
func withContentType(_ contentType: HBMustacheContentType) -> HBMustacheContext {
|
func withContentType(_ contentType: MustacheContentType) -> MustacheContext {
|
||||||
return .init(
|
return .init(
|
||||||
stack: self.stack,
|
stack: self.stack,
|
||||||
sequenceContext: self.sequenceContext,
|
sequenceContext: self.sequenceContext,
|
||||||
|
|||||||
@@ -16,23 +16,23 @@ import Foundation
|
|||||||
|
|
||||||
/// Allow object to override standard hummingbird type rendering which uses
|
/// Allow object to override standard hummingbird type rendering which uses
|
||||||
/// `String(describing)`.
|
/// `String(describing)`.
|
||||||
public protocol HBMustacheCustomRenderable {
|
public protocol MustacheCustomRenderable {
|
||||||
/// Custom rendered version of object
|
/// Custom rendered version of object
|
||||||
var renderText: String { get }
|
var renderText: String { get }
|
||||||
/// Whether the object is a null object. Used when scoping sections
|
/// Whether the object is a null object. Used when scoping sections
|
||||||
var isNull: Bool { get }
|
var isNull: Bool { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
extension HBMustacheCustomRenderable {
|
extension MustacheCustomRenderable {
|
||||||
/// default version returning the standard rendering
|
/// default version returning the standard rendering
|
||||||
var renderText: String { String(describing: self) }
|
var renderText: String { String(describing: self) }
|
||||||
/// default version returning false
|
/// default version returning false
|
||||||
var isNull: Bool { false }
|
var isNull: Bool { false }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extend NSNull to conform to `HBMustacheCustomRenderable` to avoid outputting `<null>` and returning
|
/// Extend NSNull to conform to `MustacheCustomRenderable` to avoid outputting `<null>` and returning
|
||||||
/// a valid response for `isNull`
|
/// a valid response for `isNull`
|
||||||
extension NSNull: HBMustacheCustomRenderable {
|
extension NSNull: MustacheCustomRenderable {
|
||||||
public var renderText: String { "" }
|
public var renderText: String { "" }
|
||||||
public var isNull: Bool { true }
|
public var isNull: Bool { true }
|
||||||
}
|
}
|
||||||
|
|||||||
38
Sources/HummingbirdMustache/Deprecations.swift
Normal file
38
Sources/HummingbirdMustache/Deprecations.swift
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This source file is part of the Hummingbird server framework project
|
||||||
|
//
|
||||||
|
// Copyright (c) 2024 the Hummingbird authors
|
||||||
|
// Licensed under Apache License v2.0
|
||||||
|
//
|
||||||
|
// See LICENSE.txt for license information
|
||||||
|
// See hummingbird/CONTRIBUTORS.txt for the list of Hummingbird authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// Below is a list of deprecated symbols with the "HB" prefix. These are available
|
||||||
|
// temporarily to ease transition from the old symbols that included the "HB"
|
||||||
|
// prefix to the new ones.
|
||||||
|
//
|
||||||
|
// This file will be removed before we do a 2.0 release
|
||||||
|
|
||||||
|
@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheContentType")
|
||||||
|
public typealias HBMustacheContentType = MustacheContentType
|
||||||
|
@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheContentTypes")
|
||||||
|
public typealias HBMustacheContentTypes = MustacheContentTypes
|
||||||
|
@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheCustomRenderable")
|
||||||
|
public typealias HBMustacheCustomRenderable = MustacheCustomRenderable
|
||||||
|
@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheLambda")
|
||||||
|
public typealias HBMustacheLambda = MustacheLambda
|
||||||
|
@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheLibrary")
|
||||||
|
public typealias HBMustacheLibrary = MustacheLibrary
|
||||||
|
@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheParent")
|
||||||
|
public typealias HBMustacheParent = MustacheParent
|
||||||
|
@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheParserContext")
|
||||||
|
public typealias HBMustacheParserContext = MustacheParserContext
|
||||||
|
@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheTemplate")
|
||||||
|
public typealias HBMustacheTemplate = MustacheTemplate
|
||||||
|
@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheTransformable")
|
||||||
|
public typealias HBMustacheTransformable = MustacheTransformable
|
||||||
@@ -21,30 +21,30 @@
|
|||||||
/// ```
|
/// ```
|
||||||
/// struct Object {
|
/// struct Object {
|
||||||
/// let name: String
|
/// let name: String
|
||||||
/// let wrapped: HBMustacheLambda
|
/// let wrapped: MustacheLambda
|
||||||
/// }
|
/// }
|
||||||
/// let willy = Object(name: "Willy", wrapped: .init({ object, template in
|
/// let willy = Object(name: "Willy", wrapped: .init({ object, template in
|
||||||
/// return "<b>\(template.render(object))</b>"
|
/// return "<b>\(template.render(object))</b>"
|
||||||
/// }))
|
/// }))
|
||||||
/// let mustache = "{{#wrapped}}{{name}} is awesome.{{/wrapped}}"
|
/// let mustache = "{{#wrapped}}{{name}} is awesome.{{/wrapped}}"
|
||||||
/// let template = try HBMustacheTemplate(string: mustache)
|
/// let template = try MustacheTemplate(string: mustache)
|
||||||
/// let output = template.render(willy)
|
/// let output = template.render(willy)
|
||||||
/// print(output) // <b>Willy is awesome</b>
|
/// print(output) // <b>Willy is awesome</b>
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
public struct HBMustacheLambda {
|
public struct MustacheLambda {
|
||||||
/// lambda callback
|
/// lambda callback
|
||||||
public typealias Callback = (Any, HBMustacheTemplate) -> String
|
public typealias Callback = (Any, MustacheTemplate) -> String
|
||||||
|
|
||||||
let callback: Callback
|
let callback: Callback
|
||||||
|
|
||||||
/// Initialize `HBMustacheLambda`
|
/// Initialize `MustacheLambda`
|
||||||
/// - Parameter cb: function to be called by lambda
|
/// - Parameter cb: function to be called by lambda
|
||||||
public init(_ cb: @escaping Callback) {
|
public init(_ cb: @escaping Callback) {
|
||||||
self.callback = cb
|
self.callback = cb
|
||||||
}
|
}
|
||||||
|
|
||||||
internal func run(_ object: Any, _ template: HBMustacheTemplate) -> String {
|
internal func run(_ object: Any, _ template: MustacheTemplate) -> String {
|
||||||
return self.callback(object, template)
|
return self.callback(object, template)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,9 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension HBMustacheLibrary {
|
extension MustacheLibrary {
|
||||||
/// Load templates from a folder
|
/// Load templates from a folder
|
||||||
static func loadTemplates(from directory: String, withExtension extension: String = "mustache") async throws -> [String: HBMustacheTemplate] {
|
static func loadTemplates(from directory: String, withExtension extension: String = "mustache") async throws -> [String: MustacheTemplate] {
|
||||||
var directory = directory
|
var directory = directory
|
||||||
if !directory.hasSuffix("/") {
|
if !directory.hasSuffix("/") {
|
||||||
directory += "/"
|
directory += "/"
|
||||||
@@ -24,15 +24,15 @@ extension HBMustacheLibrary {
|
|||||||
let extWithDot = ".\(`extension`)"
|
let extWithDot = ".\(`extension`)"
|
||||||
let fs = FileManager()
|
let fs = FileManager()
|
||||||
guard let enumerator = fs.enumerator(atPath: directory) else { return [:] }
|
guard let enumerator = fs.enumerator(atPath: directory) else { return [:] }
|
||||||
var templates: [String: HBMustacheTemplate] = [:]
|
var templates: [String: MustacheTemplate] = [:]
|
||||||
for case let path as String in enumerator {
|
for case let path as String in enumerator {
|
||||||
guard path.hasSuffix(extWithDot) else { continue }
|
guard path.hasSuffix(extWithDot) else { continue }
|
||||||
guard let data = fs.contents(atPath: directory + path) else { continue }
|
guard let data = fs.contents(atPath: directory + path) else { continue }
|
||||||
let string = String(decoding: data, as: Unicode.UTF8.self)
|
let string = String(decoding: data, as: Unicode.UTF8.self)
|
||||||
var template: HBMustacheTemplate
|
var template: MustacheTemplate
|
||||||
do {
|
do {
|
||||||
template = try HBMustacheTemplate(string: string)
|
template = try MustacheTemplate(string: string)
|
||||||
} catch let error as HBMustacheTemplate.ParserError {
|
} catch let error as MustacheTemplate.ParserError {
|
||||||
throw ParserError(filename: path, context: error.context, error: error.error)
|
throw ParserError(filename: path, context: error.context, error: error.error)
|
||||||
}
|
}
|
||||||
// drop ".mustache" from path to get name
|
// drop ".mustache" from path to get name
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
/// ```
|
/// ```
|
||||||
/// {{#sequence}}{{>entry}}{{/sequence}}
|
/// {{#sequence}}{{>entry}}{{/sequence}}
|
||||||
/// ```
|
/// ```
|
||||||
public struct HBMustacheLibrary: Sendable {
|
public struct MustacheLibrary: Sendable {
|
||||||
/// Initialize empty library
|
/// Initialize empty library
|
||||||
public init() {
|
public init() {
|
||||||
self.templates = [:]
|
self.templates = [:]
|
||||||
@@ -30,7 +30,7 @@ public struct HBMustacheLibrary: Sendable {
|
|||||||
/// the folder is recursive and templates in subfolders will be registered with the name `subfolder/template`.
|
/// the folder is recursive and templates in subfolders will be registered with the name `subfolder/template`.
|
||||||
/// - Parameter directory: Directory to look for mustache templates
|
/// - Parameter directory: Directory to look for mustache templates
|
||||||
/// - Parameter extension: Extension of files to look for
|
/// - Parameter extension: Extension of files to look for
|
||||||
public init(templates: [String: HBMustacheTemplate]) {
|
public init(templates: [String: MustacheTemplate]) {
|
||||||
self.templates = templates
|
self.templates = templates
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ public struct HBMustacheLibrary: Sendable {
|
|||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - template: Template
|
/// - template: Template
|
||||||
/// - name: Name of template
|
/// - name: Name of template
|
||||||
public mutating func register(_ template: HBMustacheTemplate, named name: String) {
|
public mutating func register(_ template: MustacheTemplate, named name: String) {
|
||||||
self.templates[name] = template
|
self.templates[name] = template
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,14 +57,14 @@ public struct HBMustacheLibrary: Sendable {
|
|||||||
/// - mustache: Mustache text
|
/// - mustache: Mustache text
|
||||||
/// - name: Name of template
|
/// - name: Name of template
|
||||||
public mutating func register(_ mustache: String, named name: String) throws {
|
public mutating func register(_ mustache: String, named name: String) throws {
|
||||||
let template = try HBMustacheTemplate(string: mustache)
|
let template = try MustacheTemplate(string: mustache)
|
||||||
self.templates[name] = template
|
self.templates[name] = template
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return template registed with name
|
/// Return template registed with name
|
||||||
/// - Parameter name: name to search for
|
/// - Parameter name: name to search for
|
||||||
/// - Returns: Template
|
/// - Returns: Template
|
||||||
public func getTemplate(named name: String) -> HBMustacheTemplate? {
|
public func getTemplate(named name: String) -> MustacheTemplate? {
|
||||||
self.templates[name]
|
self.templates[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,10 +83,10 @@ public struct HBMustacheLibrary: Sendable {
|
|||||||
/// File error occurred in
|
/// File error occurred in
|
||||||
public let filename: String
|
public let filename: String
|
||||||
/// Context (line, linenumber and column number)
|
/// Context (line, linenumber and column number)
|
||||||
public let context: HBParser.Context
|
public let context: MustacheParserContext
|
||||||
/// Actual error that occurred
|
/// Actual error that occurred
|
||||||
public let error: Error
|
public let error: Error
|
||||||
}
|
}
|
||||||
|
|
||||||
private var templates: [String: HBMustacheTemplate]
|
private var templates: [String: MustacheTemplate]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,12 @@
|
|||||||
|
|
||||||
/// Protocol for object that has a custom method for accessing their children, instead
|
/// Protocol for object that has a custom method for accessing their children, instead
|
||||||
/// of using Mirror
|
/// of using Mirror
|
||||||
public protocol HBMustacheParent {
|
public protocol MustacheParent {
|
||||||
func child(named: String) -> Any?
|
func child(named: String) -> Any?
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extend dictionary where the key is a string so that it uses the key values to access
|
/// Extend dictionary where the key is a string so that it uses the key values to access
|
||||||
/// it values
|
/// it values
|
||||||
extension Dictionary: HBMustacheParent where Key == String {
|
extension Dictionary: MustacheParent where Key == String {
|
||||||
public func child(named: String) -> Any? { return self[named] }
|
public func child(named: String) -> Any? { return self[named] }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
/// Reader object for parsing String buffers
|
/// Reader object for parsing String buffers
|
||||||
public struct HBParser {
|
struct Parser {
|
||||||
enum Error: Swift.Error {
|
enum Error: Swift.Error {
|
||||||
case overflow
|
case overflow
|
||||||
}
|
}
|
||||||
@@ -42,12 +42,12 @@ public struct HBParser {
|
|||||||
private(set) var position: String.Index
|
private(set) var position: String.Index
|
||||||
}
|
}
|
||||||
|
|
||||||
extension HBParser {
|
extension Parser {
|
||||||
/// Return current character
|
/// Return current character
|
||||||
/// - Throws: .overflow
|
/// - Throws: .overflow
|
||||||
/// - Returns: Current character
|
/// - Returns: Current character
|
||||||
mutating func character() throws -> Character {
|
mutating func character() throws -> Character {
|
||||||
guard !self.reachedEnd() else { throw HBParser.Error.overflow }
|
guard !self.reachedEnd() else { throw Parser.Error.overflow }
|
||||||
let c = unsafeCurrent()
|
let c = unsafeCurrent()
|
||||||
unsafeAdvance()
|
unsafeAdvance()
|
||||||
return c
|
return c
|
||||||
@@ -93,7 +93,7 @@ extension HBParser {
|
|||||||
/// - Throws: .overflow
|
/// - Throws: .overflow
|
||||||
/// - Returns: The string read from the buffer
|
/// - Returns: The string read from the buffer
|
||||||
mutating func read(count: Int) throws -> Substring {
|
mutating func read(count: Int) throws -> Substring {
|
||||||
guard self.buffer.distance(from: self.position, to: self.buffer.endIndex) >= count else { throw HBParser.Error.overflow }
|
guard self.buffer.distance(from: self.position, to: self.buffer.endIndex) >= count else { throw Parser.Error.overflow }
|
||||||
let end = self.buffer.index(self.position, offsetBy: count)
|
let end = self.buffer.index(self.position, offsetBy: count)
|
||||||
let subString = self.buffer[self.position..<end]
|
let subString = self.buffer[self.position..<end]
|
||||||
unsafeAdvance(by: count)
|
unsafeAdvance(by: count)
|
||||||
@@ -114,7 +114,7 @@ extension HBParser {
|
|||||||
}
|
}
|
||||||
if throwOnOverflow {
|
if throwOnOverflow {
|
||||||
unsafeSetPosition(startIndex)
|
unsafeSetPosition(startIndex)
|
||||||
throw HBParser.Error.overflow
|
throw Parser.Error.overflow
|
||||||
}
|
}
|
||||||
return self.buffer[startIndex..<self.position]
|
return self.buffer[startIndex..<self.position]
|
||||||
}
|
}
|
||||||
@@ -170,7 +170,7 @@ extension HBParser {
|
|||||||
}
|
}
|
||||||
if throwOnOverflow {
|
if throwOnOverflow {
|
||||||
unsafeSetPosition(startIndex)
|
unsafeSetPosition(startIndex)
|
||||||
throw HBParser.Error.overflow
|
throw Parser.Error.overflow
|
||||||
}
|
}
|
||||||
return self.buffer[startIndex..<self.position]
|
return self.buffer[startIndex..<self.position]
|
||||||
}
|
}
|
||||||
@@ -287,16 +287,16 @@ extension HBParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension HBParser {
|
|
||||||
/// context used in parser error
|
/// context used in parser error
|
||||||
public struct Context {
|
public struct MustacheParserContext {
|
||||||
public let line: String
|
public let line: String
|
||||||
public let lineNumber: Int
|
public let lineNumber: Int
|
||||||
public let columnNumber: Int
|
public let columnNumber: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Parser {
|
||||||
/// Return context of current position (line, lineNumber, columnNumber)
|
/// Return context of current position (line, lineNumber, columnNumber)
|
||||||
func getContext() -> Context {
|
func getContext() -> MustacheParserContext {
|
||||||
var parser = self
|
var parser = self
|
||||||
var columnNumber = 0
|
var columnNumber = 0
|
||||||
while !parser.atStart() {
|
while !parser.atStart() {
|
||||||
@@ -316,12 +316,12 @@ extension HBParser {
|
|||||||
let textBefore = buffer[buffer.startIndex..<self.position]
|
let textBefore = buffer[buffer.startIndex..<self.position]
|
||||||
let lineNumber = textBefore.filter(\.isNewline).count
|
let lineNumber = textBefore.filter(\.isNewline).count
|
||||||
|
|
||||||
return Context(line: String(line), lineNumber: lineNumber + 1, columnNumber: columnNumber + 1)
|
return MustacheParserContext(line: String(line), lineNumber: lineNumber + 1, columnNumber: columnNumber + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Public versions of internal functions which include tests for overflow
|
/// versions of internal functions which include tests for overflow
|
||||||
extension HBParser {
|
extension Parser {
|
||||||
/// Return the character at the current position
|
/// Return the character at the current position
|
||||||
/// - Throws: .overflow
|
/// - Throws: .overflow
|
||||||
/// - Returns: Character
|
/// - Returns: Character
|
||||||
@@ -333,14 +333,14 @@ extension HBParser {
|
|||||||
/// Move forward one character
|
/// Move forward one character
|
||||||
/// - Throws: .overflow
|
/// - Throws: .overflow
|
||||||
mutating func advance() throws {
|
mutating func advance() throws {
|
||||||
guard !self.reachedEnd() else { throw HBParser.Error.overflow }
|
guard !self.reachedEnd() else { throw Parser.Error.overflow }
|
||||||
return unsafeAdvance()
|
return unsafeAdvance()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move back one character
|
/// Move back one character
|
||||||
/// - Throws: .overflow
|
/// - Throws: .overflow
|
||||||
mutating func retreat() throws {
|
mutating func retreat() throws {
|
||||||
guard self.position != self.buffer.startIndex else { throw HBParser.Error.overflow }
|
guard self.position != self.buffer.startIndex else { throw Parser.Error.overflow }
|
||||||
return unsafeRetreat()
|
return unsafeRetreat()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,7 +348,7 @@ extension HBParser {
|
|||||||
/// - Parameter amount: number of characters to move forward
|
/// - Parameter amount: number of characters to move forward
|
||||||
/// - Throws: .overflow
|
/// - Throws: .overflow
|
||||||
mutating func advance(by amount: Int) throws {
|
mutating func advance(by amount: Int) throws {
|
||||||
guard self.buffer.distance(from: self.position, to: self.buffer.endIndex) >= amount else { throw HBParser.Error.overflow }
|
guard self.buffer.distance(from: self.position, to: self.buffer.endIndex) >= amount else { throw Parser.Error.overflow }
|
||||||
return unsafeAdvance(by: amount)
|
return unsafeAdvance(by: amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,18 +356,18 @@ extension HBParser {
|
|||||||
/// - Parameter amount: number of characters to move back
|
/// - Parameter amount: number of characters to move back
|
||||||
/// - Throws: .overflow
|
/// - Throws: .overflow
|
||||||
mutating func retreat(by amount: Int) throws {
|
mutating func retreat(by amount: Int) throws {
|
||||||
guard self.buffer.distance(from: self.buffer.startIndex, to: self.position) >= amount else { throw HBParser.Error.overflow }
|
guard self.buffer.distance(from: self.buffer.startIndex, to: self.position) >= amount else { throw Parser.Error.overflow }
|
||||||
return unsafeRetreat(by: amount)
|
return unsafeRetreat(by: amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
mutating func setPosition(_ position: String.Index) throws {
|
mutating func setPosition(_ position: String.Index) throws {
|
||||||
guard position <= self.buffer.endIndex else { throw HBParser.Error.overflow }
|
guard position <= self.buffer.endIndex else { throw Parser.Error.overflow }
|
||||||
unsafeSetPosition(position)
|
unsafeSetPosition(position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// unsafe versions without checks
|
// unsafe versions without checks
|
||||||
extension HBParser {
|
extension Parser {
|
||||||
func unsafeCurrent() -> Character {
|
func unsafeCurrent() -> Character {
|
||||||
return self.buffer[self.position]
|
return self.buffer[self.position]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,18 +13,18 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// Protocol for objects that can be rendered as a sequence in Mustache
|
/// Protocol for objects that can be rendered as a sequence in Mustache
|
||||||
protocol HBMustacheSequence {
|
protocol MustacheSequence {
|
||||||
/// Render section using template
|
/// Render section using template
|
||||||
func renderSection(with template: HBMustacheTemplate, context: HBMustacheContext) -> String
|
func renderSection(with template: MustacheTemplate, context: MustacheContext) -> String
|
||||||
/// Render inverted section using template
|
/// Render inverted section using template
|
||||||
func renderInvertedSection(with template: HBMustacheTemplate, context: HBMustacheContext) -> String
|
func renderInvertedSection(with template: MustacheTemplate, context: MustacheContext) -> String
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Sequence {
|
extension Sequence {
|
||||||
/// Render section using template
|
/// Render section using template
|
||||||
func renderSection(with template: HBMustacheTemplate, context: HBMustacheContext) -> String {
|
func renderSection(with template: MustacheTemplate, context: MustacheContext) -> String {
|
||||||
var string = ""
|
var string = ""
|
||||||
var sequenceContext = HBMustacheSequenceContext(first: true)
|
var sequenceContext = MustacheSequenceContext(first: true)
|
||||||
|
|
||||||
var iterator = makeIterator()
|
var iterator = makeIterator()
|
||||||
guard var currentObject = iterator.next() else { return "" }
|
guard var currentObject = iterator.next() else { return "" }
|
||||||
@@ -43,7 +43,7 @@ extension Sequence {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Render inverted section using template
|
/// Render inverted section using template
|
||||||
func renderInvertedSection(with template: HBMustacheTemplate, context: HBMustacheContext) -> String {
|
func renderInvertedSection(with template: MustacheTemplate, context: MustacheContext) -> String {
|
||||||
var iterator = makeIterator()
|
var iterator = makeIterator()
|
||||||
if iterator.next() == nil {
|
if iterator.next() == nil {
|
||||||
return template.render(context: context.withObject(self))
|
return template.render(context: context.withObject(self))
|
||||||
@@ -52,6 +52,6 @@ extension Sequence {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Array: HBMustacheSequence {}
|
extension Array: MustacheSequence {}
|
||||||
extension Set: HBMustacheSequence {}
|
extension Set: MustacheSequence {}
|
||||||
extension ReversedCollection: HBMustacheSequence {}
|
extension ReversedCollection: MustacheSequence {}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// Context that current object inside a sequence is being rendered in. Only relevant when rendering a sequence
|
/// Context that current object inside a sequence is being rendered in. Only relevant when rendering a sequence
|
||||||
struct HBMustacheSequenceContext: HBMustacheTransformable {
|
struct MustacheSequenceContext: MustacheTransformable {
|
||||||
var first: Bool
|
var first: Bool
|
||||||
var last: Bool
|
var last: Bool
|
||||||
var index: Int
|
var index: Int
|
||||||
@@ -24,7 +24,7 @@ struct HBMustacheSequenceContext: HBMustacheTransformable {
|
|||||||
self.index = 0
|
self.index = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transform `HBMustacheContext`. These are available when processing elements
|
/// Transform `MustacheContext`. These are available when processing elements
|
||||||
/// of a sequence.
|
/// of a sequence.
|
||||||
///
|
///
|
||||||
/// Format your mustache as follows to accept them. They look like a function without any arguments
|
/// Format your mustache as follows to accept them. They look like a function without any arguments
|
||||||
|
|||||||
@@ -12,14 +12,14 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
extension HBMustacheTemplate {
|
extension MustacheTemplate {
|
||||||
/// Error return by `HBMustacheTemplate.parse`. Includes information about where error occurred
|
/// Error return by `MustacheTemplate.parse`. Includes information about where error occurred
|
||||||
public struct ParserError: Swift.Error {
|
public struct ParserError: Swift.Error {
|
||||||
public let context: HBParser.Context
|
public let context: MustacheParserContext
|
||||||
public let error: Swift.Error
|
public let error: Swift.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error generated by `HBMustacheTemplate.parse`
|
/// Error generated by `MustacheTemplate.parse`
|
||||||
public enum Error: Swift.Error {
|
public enum Error: Swift.Error {
|
||||||
/// the end section does not match the name of the start section
|
/// the end section does not match the name of the start section
|
||||||
case sectionCloseNameIncorrect
|
case sectionCloseNameIncorrect
|
||||||
@@ -72,7 +72,7 @@ extension HBMustacheTemplate {
|
|||||||
|
|
||||||
/// parse mustache text to generate a list of tokens
|
/// parse mustache text to generate a list of tokens
|
||||||
static func parse(_ string: String) throws -> [Token] {
|
static func parse(_ string: String) throws -> [Token] {
|
||||||
var parser = HBParser(string)
|
var parser = Parser(string)
|
||||||
do {
|
do {
|
||||||
return try self.parse(&parser, state: .init())
|
return try self.parse(&parser, state: .init())
|
||||||
} catch {
|
} catch {
|
||||||
@@ -81,7 +81,7 @@ extension HBMustacheTemplate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// parse section in mustache text
|
/// parse section in mustache text
|
||||||
static func parse(_ parser: inout HBParser, state: ParserState) throws -> [Token] {
|
static func parse(_ parser: inout Parser, state: ParserState) throws -> [Token] {
|
||||||
var tokens: [Token] = []
|
var tokens: [Token] = []
|
||||||
var state = state
|
var state = state
|
||||||
var whiteSpaceBefore: Substring = ""
|
var whiteSpaceBefore: Substring = ""
|
||||||
@@ -122,7 +122,7 @@ extension HBMustacheTemplate {
|
|||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
}
|
}
|
||||||
let sectionTokens = try parse(&parser, state: state.withSectionName(name, transform: transform))
|
let sectionTokens = try parse(&parser, state: state.withSectionName(name, transform: transform))
|
||||||
tokens.append(.section(name: name, transform: transform, template: HBMustacheTemplate(sectionTokens)))
|
tokens.append(.section(name: name, transform: transform, template: MustacheTemplate(sectionTokens)))
|
||||||
|
|
||||||
case "^":
|
case "^":
|
||||||
// inverted section
|
// inverted section
|
||||||
@@ -135,7 +135,7 @@ extension HBMustacheTemplate {
|
|||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
}
|
}
|
||||||
let sectionTokens = try parse(&parser, state: state.withSectionName(name, transform: transform))
|
let sectionTokens = try parse(&parser, state: state.withSectionName(name, transform: transform))
|
||||||
tokens.append(.invertedSection(name: name, transform: transform, template: HBMustacheTemplate(sectionTokens)))
|
tokens.append(.invertedSection(name: name, transform: transform, template: MustacheTemplate(sectionTokens)))
|
||||||
|
|
||||||
case "$":
|
case "$":
|
||||||
// inherited section
|
// inherited section
|
||||||
@@ -150,7 +150,7 @@ extension HBMustacheTemplate {
|
|||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
}
|
}
|
||||||
let sectionTokens = try parse(&parser, state: state.withSectionName(name, transform: transform))
|
let sectionTokens = try parse(&parser, state: state.withSectionName(name, transform: transform))
|
||||||
tokens.append(.inheritedSection(name: name, template: HBMustacheTemplate(sectionTokens)))
|
tokens.append(.inheritedSection(name: name, template: MustacheTemplate(sectionTokens)))
|
||||||
|
|
||||||
case "/":
|
case "/":
|
||||||
// end of section
|
// end of section
|
||||||
@@ -224,7 +224,7 @@ extension HBMustacheTemplate {
|
|||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
}
|
}
|
||||||
let sectionTokens = try parse(&parser, state: state.withSectionName(name))
|
let sectionTokens = try parse(&parser, state: state.withSectionName(name))
|
||||||
var inherit: [String: HBMustacheTemplate] = [:]
|
var inherit: [String: MustacheTemplate] = [:]
|
||||||
// parse tokens in section to extract inherited sections
|
// parse tokens in section to extract inherited sections
|
||||||
for token in sectionTokens {
|
for token in sectionTokens {
|
||||||
switch token {
|
switch token {
|
||||||
@@ -271,7 +271,7 @@ extension HBMustacheTemplate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// read until we hit either the start delimiter of a tag or a newline
|
/// read until we hit either the start delimiter of a tag or a newline
|
||||||
static func readUntilDelimiterOrNewline(_ parser: inout HBParser, state: ParserState) throws -> String {
|
static func readUntilDelimiterOrNewline(_ parser: inout Parser, state: ParserState) throws -> String {
|
||||||
var untilSet: Set<Character> = ["\n", "\r\n"]
|
var untilSet: Set<Character> = ["\n", "\r\n"]
|
||||||
guard let delimiterFirstChar = state.startDelimiter.first else { return "" }
|
guard let delimiterFirstChar = state.startDelimiter.first else { return "" }
|
||||||
var totalText = ""
|
var totalText = ""
|
||||||
@@ -296,14 +296,14 @@ extension HBMustacheTemplate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// parse variable name
|
/// parse variable name
|
||||||
static func parseName(_ parser: inout HBParser, state: ParserState) throws -> (String, String?) {
|
static func parseName(_ parser: inout Parser, state: ParserState) throws -> (String, String?) {
|
||||||
parser.read(while: \.isWhitespace)
|
parser.read(while: \.isWhitespace)
|
||||||
let text = String(parser.read(while: self.sectionNameChars))
|
let text = String(parser.read(while: self.sectionNameChars))
|
||||||
parser.read(while: \.isWhitespace)
|
parser.read(while: \.isWhitespace)
|
||||||
guard try parser.read(string: state.endDelimiter) else { throw Error.unfinishedName }
|
guard try parser.read(string: state.endDelimiter) else { throw Error.unfinishedName }
|
||||||
|
|
||||||
// does the name include brackets. If so this is a transform call
|
// does the name include brackets. If so this is a transform call
|
||||||
var nameParser = HBParser(String(text))
|
var nameParser = Parser(String(text))
|
||||||
let string = nameParser.read(while: self.sectionNameCharsWithoutBrackets)
|
let string = nameParser.read(while: self.sectionNameCharsWithoutBrackets)
|
||||||
if nameParser.reachedEnd() {
|
if nameParser.reachedEnd() {
|
||||||
return (text, nil)
|
return (text, nil)
|
||||||
@@ -320,7 +320,7 @@ extension HBMustacheTemplate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// parse partial name
|
/// parse partial name
|
||||||
static func parsePartialName(_ parser: inout HBParser, state: ParserState) throws -> String {
|
static func parsePartialName(_ parser: inout Parser, state: ParserState) throws -> String {
|
||||||
parser.read(while: \.isWhitespace)
|
parser.read(while: \.isWhitespace)
|
||||||
let text = String(parser.read(while: self.sectionNameChars))
|
let text = String(parser.read(while: self.sectionNameChars))
|
||||||
parser.read(while: \.isWhitespace)
|
parser.read(while: \.isWhitespace)
|
||||||
@@ -328,12 +328,12 @@ extension HBMustacheTemplate {
|
|||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
static func parseComment(_ parser: inout HBParser, state: ParserState) throws -> String {
|
static func parseComment(_ parser: inout Parser, state: ParserState) throws -> String {
|
||||||
let text = try parser.read(untilString: state.endDelimiter, throwOnOverflow: true, skipToEnd: true)
|
let text = try parser.read(untilString: state.endDelimiter, throwOnOverflow: true, skipToEnd: true)
|
||||||
return String(text)
|
return String(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func parserSetDelimiter(_ parser: inout HBParser, state: ParserState) throws -> ParserState {
|
static func parserSetDelimiter(_ parser: inout Parser, state: ParserState) throws -> ParserState {
|
||||||
let startDelimiter: Substring
|
let startDelimiter: Substring
|
||||||
let endDelimiter: Substring
|
let endDelimiter: Substring
|
||||||
|
|
||||||
@@ -352,7 +352,7 @@ extension HBMustacheTemplate {
|
|||||||
return state.withDelimiters(start: String(startDelimiter), end: String(endDelimiter))
|
return state.withDelimiters(start: String(startDelimiter), end: String(endDelimiter))
|
||||||
}
|
}
|
||||||
|
|
||||||
static func readConfigVariable(_ parser: inout HBParser, state: ParserState) throws -> Token? {
|
static func readConfigVariable(_ parser: inout Parser, state: ParserState) throws -> Token? {
|
||||||
let variable: Substring
|
let variable: Substring
|
||||||
let value: Substring
|
let value: Substring
|
||||||
|
|
||||||
@@ -374,14 +374,14 @@ extension HBMustacheTemplate {
|
|||||||
|
|
||||||
switch variable {
|
switch variable {
|
||||||
case "CONTENT_TYPE":
|
case "CONTENT_TYPE":
|
||||||
guard let contentType = HBMustacheContentTypes.get(String(value)) else { throw Error.unrecognisedConfigVariable }
|
guard let contentType = MustacheContentTypes.get(String(value)) else { throw Error.unrecognisedConfigVariable }
|
||||||
return .contentType(contentType)
|
return .contentType(contentType)
|
||||||
default:
|
default:
|
||||||
throw Error.unrecognisedConfigVariable
|
throw Error.unrecognisedConfigVariable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func hasLineFinished(_ parser: inout HBParser) -> Bool {
|
static func hasLineFinished(_ parser: inout Parser) -> Bool {
|
||||||
var parser2 = parser
|
var parser2 = parser
|
||||||
if parser.reachedEnd() { return true }
|
if parser.reachedEnd() { return true }
|
||||||
parser2.read(while: Set(" \t"))
|
parser2.read(while: Set(" \t"))
|
||||||
@@ -393,7 +393,7 @@ extension HBMustacheTemplate {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
static func isStandalone(_ parser: inout HBParser, state: ParserState) -> Bool {
|
static func isStandalone(_ parser: inout Parser, state: ParserState) -> Bool {
|
||||||
return state.newLine && self.hasLineFinished(&parser)
|
return state.newLine && self.hasLineFinished(&parser)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,14 +14,14 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension HBMustacheTemplate {
|
extension MustacheTemplate {
|
||||||
/// Render template using object
|
/// Render template using object
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - stack: Object
|
/// - stack: Object
|
||||||
/// - context: Context that render is occurring in. Contains information about position in sequence
|
/// - context: Context that render is occurring in. Contains information about position in sequence
|
||||||
/// - indentation: indentation of partial
|
/// - indentation: indentation of partial
|
||||||
/// - Returns: Rendered text
|
/// - Returns: Rendered text
|
||||||
func render(context: HBMustacheContext) -> String {
|
func render(context: MustacheContext) -> String {
|
||||||
var string = ""
|
var string = ""
|
||||||
var context = context
|
var context = context
|
||||||
|
|
||||||
@@ -42,15 +42,15 @@ extension HBMustacheTemplate {
|
|||||||
return string
|
return string
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderToken(_ token: Token, context: inout HBMustacheContext) -> String {
|
func renderToken(_ token: Token, context: inout MustacheContext) -> String {
|
||||||
switch token {
|
switch token {
|
||||||
case .text(let text):
|
case .text(let text):
|
||||||
return text
|
return text
|
||||||
case .variable(let variable, let transform):
|
case .variable(let variable, let transform):
|
||||||
if let child = getChild(named: variable, transform: transform, context: context) {
|
if let child = getChild(named: variable, transform: transform, context: context) {
|
||||||
if let template = child as? HBMustacheTemplate {
|
if let template = child as? MustacheTemplate {
|
||||||
return template.render(context: context)
|
return template.render(context: context)
|
||||||
} else if let renderable = child as? HBMustacheCustomRenderable {
|
} else if let renderable = child as? MustacheCustomRenderable {
|
||||||
return context.contentType.escapeText(renderable.renderText)
|
return context.contentType.escapeText(renderable.renderText)
|
||||||
} else {
|
} else {
|
||||||
return context.contentType.escapeText(String(describing: child))
|
return context.contentType.escapeText(String(describing: child))
|
||||||
@@ -58,7 +58,7 @@ extension HBMustacheTemplate {
|
|||||||
}
|
}
|
||||||
case .unescapedVariable(let variable, let transform):
|
case .unescapedVariable(let variable, let transform):
|
||||||
if let child = getChild(named: variable, transform: transform, context: context) {
|
if let child = getChild(named: variable, transform: transform, context: context) {
|
||||||
if let renderable = child as? HBMustacheCustomRenderable {
|
if let renderable = child as? MustacheCustomRenderable {
|
||||||
return renderable.renderText
|
return renderable.renderText
|
||||||
} else {
|
} else {
|
||||||
return String(describing: child)
|
return String(describing: child)
|
||||||
@@ -96,15 +96,15 @@ extension HBMustacheTemplate {
|
|||||||
/// - parent: Current object being rendered
|
/// - parent: Current object being rendered
|
||||||
/// - template: Template to render with
|
/// - template: Template to render with
|
||||||
/// - Returns: Rendered text
|
/// - Returns: Rendered text
|
||||||
func renderSection(_ child: Any?, with template: HBMustacheTemplate, context: HBMustacheContext) -> String {
|
func renderSection(_ child: Any?, with template: MustacheTemplate, context: MustacheContext) -> String {
|
||||||
switch child {
|
switch child {
|
||||||
case let array as HBMustacheSequence:
|
case let array as MustacheSequence:
|
||||||
return array.renderSection(with: template, context: context)
|
return array.renderSection(with: template, context: context)
|
||||||
case let bool as Bool:
|
case let bool as Bool:
|
||||||
return bool ? template.render(context: context) : ""
|
return bool ? template.render(context: context) : ""
|
||||||
case let lambda as HBMustacheLambda:
|
case let lambda as MustacheLambda:
|
||||||
return lambda.run(context.stack.last!, template)
|
return lambda.run(context.stack.last!, template)
|
||||||
case let null as HBMustacheCustomRenderable where null.isNull == true:
|
case let null as MustacheCustomRenderable where null.isNull == true:
|
||||||
return ""
|
return ""
|
||||||
case .some(let value):
|
case .some(let value):
|
||||||
return template.render(context: context.withObject(value))
|
return template.render(context: context.withObject(value))
|
||||||
@@ -119,13 +119,13 @@ extension HBMustacheTemplate {
|
|||||||
/// - parent: Current object being rendered
|
/// - parent: Current object being rendered
|
||||||
/// - template: Template to render with
|
/// - template: Template to render with
|
||||||
/// - Returns: Rendered text
|
/// - Returns: Rendered text
|
||||||
func renderInvertedSection(_ child: Any?, with template: HBMustacheTemplate, context: HBMustacheContext) -> String {
|
func renderInvertedSection(_ child: Any?, with template: MustacheTemplate, context: MustacheContext) -> String {
|
||||||
switch child {
|
switch child {
|
||||||
case let array as HBMustacheSequence:
|
case let array as MustacheSequence:
|
||||||
return array.renderInvertedSection(with: template, context: context)
|
return array.renderInvertedSection(with: template, context: context)
|
||||||
case let bool as Bool:
|
case let bool as Bool:
|
||||||
return bool ? "" : template.render(context: context)
|
return bool ? "" : template.render(context: context)
|
||||||
case let null as HBMustacheCustomRenderable where null.isNull == true:
|
case let null as MustacheCustomRenderable where null.isNull == true:
|
||||||
return template.render(context: context)
|
return template.render(context: context)
|
||||||
case .some:
|
case .some:
|
||||||
return ""
|
return ""
|
||||||
@@ -135,9 +135,9 @@ extension HBMustacheTemplate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get child object from variable name
|
/// Get child object from variable name
|
||||||
func getChild(named name: String, transform: String?, context: HBMustacheContext) -> Any? {
|
func getChild(named name: String, transform: String?, context: MustacheContext) -> Any? {
|
||||||
func _getImmediateChild(named name: String, from object: Any) -> Any? {
|
func _getImmediateChild(named name: String, from object: Any) -> Any? {
|
||||||
if let customBox = object as? HBMustacheParent {
|
if let customBox = object as? MustacheParent {
|
||||||
return customBox.child(named: name)
|
return customBox.child(named: name)
|
||||||
} else {
|
} else {
|
||||||
let mirror = Mirror(reflecting: object)
|
let mirror = Mirror(reflecting: object)
|
||||||
@@ -183,7 +183,7 @@ extension HBMustacheTemplate {
|
|||||||
// if we want to run a transform and the current child can have transforms applied to it then
|
// if we want to run a transform and the current child can have transforms applied to it then
|
||||||
// run transform on the current child
|
// run transform on the current child
|
||||||
if let transform {
|
if let transform {
|
||||||
if let runnable = child as? HBMustacheTransformable {
|
if let runnable = child as? MustacheTransformable {
|
||||||
return runnable.transform(transform)
|
return runnable.transform(transform)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -13,10 +13,10 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// Class holding Mustache template
|
/// Class holding Mustache template
|
||||||
public struct HBMustacheTemplate: Sendable {
|
public struct MustacheTemplate: Sendable {
|
||||||
/// Initialize template
|
/// Initialize template
|
||||||
/// - Parameter string: Template text
|
/// - Parameter string: Template text
|
||||||
/// - Throws: HBMustacheTemplate.Error
|
/// - Throws: MustacheTemplate.Error
|
||||||
public init(string: String) throws {
|
public init(string: String) throws {
|
||||||
self.tokens = try Self.parse(string)
|
self.tokens = try Self.parse(string)
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ public struct HBMustacheTemplate: Sendable {
|
|||||||
/// Render object using this template
|
/// Render object using this template
|
||||||
/// - Parameter object: Object to render
|
/// - Parameter object: Object to render
|
||||||
/// - Returns: Rendered text
|
/// - Returns: Rendered text
|
||||||
public func render(_ object: Any, library: HBMustacheLibrary? = nil) -> String {
|
public func render(_ object: Any, library: MustacheLibrary? = nil) -> String {
|
||||||
self.render(context: .init(object, library: library))
|
self.render(context: .init(object, library: library))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,11 +36,11 @@ public struct HBMustacheTemplate: Sendable {
|
|||||||
case text(String)
|
case text(String)
|
||||||
case variable(name: String, transform: String? = nil)
|
case variable(name: String, transform: String? = nil)
|
||||||
case unescapedVariable(name: String, transform: String? = nil)
|
case unescapedVariable(name: String, transform: String? = nil)
|
||||||
case section(name: String, transform: String? = nil, template: HBMustacheTemplate)
|
case section(name: String, transform: String? = nil, template: MustacheTemplate)
|
||||||
case invertedSection(name: String, transform: String? = nil, template: HBMustacheTemplate)
|
case invertedSection(name: String, transform: String? = nil, template: MustacheTemplate)
|
||||||
case inheritedSection(name: String, template: HBMustacheTemplate)
|
case inheritedSection(name: String, template: MustacheTemplate)
|
||||||
case partial(String, indentation: String?, inherits: [String: HBMustacheTemplate]?)
|
case partial(String, indentation: String?, inherits: [String: MustacheTemplate]?)
|
||||||
case contentType(HBMustacheContentType)
|
case contentType(MustacheContentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
var tokens: [Token]
|
var tokens: [Token]
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
/// ```
|
/// ```
|
||||||
/// {{#reversed(sequence)}}{{.}}{{\reversed(sequence)}}
|
/// {{#reversed(sequence)}}{{.}}{{\reversed(sequence)}}
|
||||||
/// ```
|
/// ```
|
||||||
public protocol HBMustacheTransformable {
|
public protocol MustacheTransformable {
|
||||||
func transform(_ name: String) -> Any?
|
func transform(_ name: String) -> Any?
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,15 +55,15 @@ public extension StringProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension String: HBMustacheTransformable {}
|
extension String: MustacheTransformable {}
|
||||||
extension Substring: HBMustacheTransformable {}
|
extension Substring: MustacheTransformable {}
|
||||||
|
|
||||||
/// Protocol for sequence that can be sorted
|
/// Protocol for sequence that can be sorted
|
||||||
private protocol HBComparableSequence {
|
private protocol ComparableSequence {
|
||||||
func comparableTransform(_ name: String) -> Any?
|
func comparableTransform(_ name: String) -> Any?
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Array: HBMustacheTransformable {
|
extension Array: MustacheTransformable {
|
||||||
/// Transform Array.
|
/// Transform Array.
|
||||||
///
|
///
|
||||||
/// Transforms available are `first`, `last`, `reversed`, `count` and for arrays
|
/// Transforms available are `first`, `last`, `reversed`, `count` and for arrays
|
||||||
@@ -83,7 +83,7 @@ extension Array: HBMustacheTransformable {
|
|||||||
case "empty":
|
case "empty":
|
||||||
return isEmpty
|
return isEmpty
|
||||||
default:
|
default:
|
||||||
if let comparableSeq = self as? HBComparableSequence {
|
if let comparableSeq = self as? ComparableSequence {
|
||||||
return comparableSeq.comparableTransform(name)
|
return comparableSeq.comparableTransform(name)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -91,7 +91,7 @@ extension Array: HBMustacheTransformable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Array: HBComparableSequence where Element: Comparable {
|
extension Array: ComparableSequence where Element: Comparable {
|
||||||
func comparableTransform(_ name: String) -> Any? {
|
func comparableTransform(_ name: String) -> Any? {
|
||||||
switch name {
|
switch name {
|
||||||
case "sorted":
|
case "sorted":
|
||||||
@@ -102,7 +102,7 @@ extension Array: HBComparableSequence where Element: Comparable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Dictionary: HBMustacheTransformable {
|
extension Dictionary: MustacheTransformable {
|
||||||
/// Transform Dictionary
|
/// Transform Dictionary
|
||||||
///
|
///
|
||||||
/// Transforms available are `count`, `enumerated` and for dictionaries
|
/// Transforms available are `count`, `enumerated` and for dictionaries
|
||||||
@@ -118,7 +118,7 @@ extension Dictionary: HBMustacheTransformable {
|
|||||||
case "enumerated":
|
case "enumerated":
|
||||||
return map { (key: $0.key, value: $0.value) }
|
return map { (key: $0.key, value: $0.value) }
|
||||||
default:
|
default:
|
||||||
if let comparableSeq = self as? HBComparableSequence {
|
if let comparableSeq = self as? ComparableSequence {
|
||||||
return comparableSeq.comparableTransform(name)
|
return comparableSeq.comparableTransform(name)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -126,7 +126,7 @@ extension Dictionary: HBMustacheTransformable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Dictionary: HBComparableSequence where Key: Comparable {
|
extension Dictionary: ComparableSequence where Key: Comparable {
|
||||||
func comparableTransform(_ name: String) -> Any? {
|
func comparableTransform(_ name: String) -> Any? {
|
||||||
switch name {
|
switch name {
|
||||||
case "sorted":
|
case "sorted":
|
||||||
@@ -161,13 +161,13 @@ public extension FixedWidthInteger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Int: HBMustacheTransformable {}
|
extension Int: MustacheTransformable {}
|
||||||
extension Int8: HBMustacheTransformable {}
|
extension Int8: MustacheTransformable {}
|
||||||
extension Int16: HBMustacheTransformable {}
|
extension Int16: MustacheTransformable {}
|
||||||
extension Int32: HBMustacheTransformable {}
|
extension Int32: MustacheTransformable {}
|
||||||
extension Int64: HBMustacheTransformable {}
|
extension Int64: MustacheTransformable {}
|
||||||
extension UInt: HBMustacheTransformable {}
|
extension UInt: MustacheTransformable {}
|
||||||
extension UInt8: HBMustacheTransformable {}
|
extension UInt8: MustacheTransformable {}
|
||||||
extension UInt16: HBMustacheTransformable {}
|
extension UInt16: MustacheTransformable {}
|
||||||
extension UInt32: HBMustacheTransformable {}
|
extension UInt32: MustacheTransformable {}
|
||||||
extension UInt64: HBMustacheTransformable {}
|
extension UInt64: MustacheTransformable {}
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ import XCTest
|
|||||||
|
|
||||||
final class ErrorTests: XCTestCase {
|
final class ErrorTests: XCTestCase {
|
||||||
func testSectionCloseNameIncorrect() {
|
func testSectionCloseNameIncorrect() {
|
||||||
XCTAssertThrowsError(try HBMustacheTemplate(string: """
|
XCTAssertThrowsError(try MustacheTemplate(string: """
|
||||||
{{#test}}
|
{{#test}}
|
||||||
{{.}}
|
{{.}}
|
||||||
{{/test2}}
|
{{/test2}}
|
||||||
""")) { error in
|
""")) { error in
|
||||||
switch error {
|
switch error {
|
||||||
case let error as HBMustacheTemplate.ParserError:
|
case let error as MustacheTemplate.ParserError:
|
||||||
XCTAssertEqual(error.error as? HBMustacheTemplate.Error, .sectionCloseNameIncorrect)
|
XCTAssertEqual(error.error as? MustacheTemplate.Error, .sectionCloseNameIncorrect)
|
||||||
XCTAssertEqual(error.context.line, "{{/test2}}")
|
XCTAssertEqual(error.context.line, "{{/test2}}")
|
||||||
XCTAssertEqual(error.context.lineNumber, 3)
|
XCTAssertEqual(error.context.lineNumber, 3)
|
||||||
XCTAssertEqual(error.context.columnNumber, 4)
|
XCTAssertEqual(error.context.columnNumber, 4)
|
||||||
@@ -36,14 +36,14 @@ final class ErrorTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testUnfinishedName() {
|
func testUnfinishedName() {
|
||||||
XCTAssertThrowsError(try HBMustacheTemplate(string: """
|
XCTAssertThrowsError(try MustacheTemplate(string: """
|
||||||
{{#test}}
|
{{#test}}
|
||||||
{{name}
|
{{name}
|
||||||
{{/test2}}
|
{{/test2}}
|
||||||
""")) { error in
|
""")) { error in
|
||||||
switch error {
|
switch error {
|
||||||
case let error as HBMustacheTemplate.ParserError:
|
case let error as MustacheTemplate.ParserError:
|
||||||
XCTAssertEqual(error.error as? HBMustacheTemplate.Error, .unfinishedName)
|
XCTAssertEqual(error.error as? MustacheTemplate.Error, .unfinishedName)
|
||||||
XCTAssertEqual(error.context.line, "{{name}")
|
XCTAssertEqual(error.context.line, "{{name}")
|
||||||
XCTAssertEqual(error.context.lineNumber, 2)
|
XCTAssertEqual(error.context.lineNumber, 2)
|
||||||
XCTAssertEqual(error.context.columnNumber, 7)
|
XCTAssertEqual(error.context.columnNumber, 7)
|
||||||
@@ -55,13 +55,13 @@ final class ErrorTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testExpectedSectionEnd() {
|
func testExpectedSectionEnd() {
|
||||||
XCTAssertThrowsError(try HBMustacheTemplate(string: """
|
XCTAssertThrowsError(try MustacheTemplate(string: """
|
||||||
{{#test}}
|
{{#test}}
|
||||||
{{.}}
|
{{.}}
|
||||||
""")) { error in
|
""")) { error in
|
||||||
switch error {
|
switch error {
|
||||||
case let error as HBMustacheTemplate.ParserError:
|
case let error as MustacheTemplate.ParserError:
|
||||||
XCTAssertEqual(error.error as? HBMustacheTemplate.Error, .expectedSectionEnd)
|
XCTAssertEqual(error.error as? MustacheTemplate.Error, .expectedSectionEnd)
|
||||||
XCTAssertEqual(error.context.line, "{{.}}")
|
XCTAssertEqual(error.context.line, "{{.}}")
|
||||||
XCTAssertEqual(error.context.lineNumber, 2)
|
XCTAssertEqual(error.context.lineNumber, 2)
|
||||||
XCTAssertEqual(error.context.columnNumber, 6)
|
XCTAssertEqual(error.context.columnNumber, 6)
|
||||||
@@ -73,14 +73,14 @@ final class ErrorTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testInvalidSetDelimiter() {
|
func testInvalidSetDelimiter() {
|
||||||
XCTAssertThrowsError(try HBMustacheTemplate(string: """
|
XCTAssertThrowsError(try MustacheTemplate(string: """
|
||||||
{{=<% %>=}}
|
{{=<% %>=}}
|
||||||
<%.%>
|
<%.%>
|
||||||
<%={{}}=%>
|
<%={{}}=%>
|
||||||
""")) { error in
|
""")) { error in
|
||||||
switch error {
|
switch error {
|
||||||
case let error as HBMustacheTemplate.ParserError:
|
case let error as MustacheTemplate.ParserError:
|
||||||
XCTAssertEqual(error.error as? HBMustacheTemplate.Error, .invalidSetDelimiter)
|
XCTAssertEqual(error.error as? MustacheTemplate.Error, .invalidSetDelimiter)
|
||||||
XCTAssertEqual(error.context.line, "<%={{}}=%>")
|
XCTAssertEqual(error.context.line, "<%={{}}=%>")
|
||||||
XCTAssertEqual(error.context.lineNumber, 3)
|
XCTAssertEqual(error.context.lineNumber, 3)
|
||||||
XCTAssertEqual(error.context.columnNumber, 4)
|
XCTAssertEqual(error.context.columnNumber, 4)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ final class LibraryTests: XCTestCase {
|
|||||||
try mustache.write(to: URL(fileURLWithPath: "templates/test.mustache"))
|
try mustache.write(to: URL(fileURLWithPath: "templates/test.mustache"))
|
||||||
defer { XCTAssertNoThrow(try fs.removeItem(atPath: "templates/test.mustache")) }
|
defer { XCTAssertNoThrow(try fs.removeItem(atPath: "templates/test.mustache")) }
|
||||||
|
|
||||||
let library = try await HBMustacheLibrary(directory: "./templates")
|
let library = try await MustacheLibrary(directory: "./templates")
|
||||||
let object = ["value": ["value1", "value2"]]
|
let object = ["value": ["value1", "value2"]]
|
||||||
XCTAssertEqual(library.render(object, withTemplate: "test"), "<test><value>value1</value><value>value2</value></test>")
|
XCTAssertEqual(library.render(object, withTemplate: "test"), "<test><value>value1</value><value>value2</value></test>")
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ final class LibraryTests: XCTestCase {
|
|||||||
XCTAssertNoThrow(try fs.removeItem(atPath: "templates"))
|
XCTAssertNoThrow(try fs.removeItem(atPath: "templates"))
|
||||||
}
|
}
|
||||||
|
|
||||||
let library = try await HBMustacheLibrary(directory: "./templates")
|
let library = try await MustacheLibrary(directory: "./templates")
|
||||||
let object = ["value": ["value1", "value2"]]
|
let object = ["value": ["value1", "value2"]]
|
||||||
XCTAssertEqual(library.render(object, withTemplate: "test"), "<test><value>value1</value><value>value2</value></test>")
|
XCTAssertEqual(library.render(object, withTemplate: "test"), "<test><value>value1</value><value>value2</value></test>")
|
||||||
}
|
}
|
||||||
@@ -63,8 +63,8 @@ final class LibraryTests: XCTestCase {
|
|||||||
defer { XCTAssertNoThrow(try fs.removeItem(atPath: "templates/error.mustache")) }
|
defer { XCTAssertNoThrow(try fs.removeItem(atPath: "templates/error.mustache")) }
|
||||||
|
|
||||||
do {
|
do {
|
||||||
_ = try await HBMustacheLibrary(directory: "./templates")
|
_ = try await MustacheLibrary(directory: "./templates")
|
||||||
} catch let parserError as HBMustacheLibrary.ParserError {
|
} catch let parserError as MustacheLibrary.ParserError {
|
||||||
XCTAssertEqual(parserError.filename, "error.mustache")
|
XCTAssertEqual(parserError.filename, "error.mustache")
|
||||||
XCTAssertEqual(parserError.context.line, "{{{name}}")
|
XCTAssertEqual(parserError.context.line, "{{{name}}")
|
||||||
XCTAssertEqual(parserError.context.lineNumber, 2)
|
XCTAssertEqual(parserError.context.lineNumber, 2)
|
||||||
|
|||||||
@@ -18,17 +18,17 @@ import XCTest
|
|||||||
final class PartialTests: XCTestCase {
|
final class PartialTests: XCTestCase {
|
||||||
/// Testing partials
|
/// Testing partials
|
||||||
func testMustacheManualExample9() throws {
|
func testMustacheManualExample9() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
<h2>Names</h2>
|
<h2>Names</h2>
|
||||||
{{#names}}
|
{{#names}}
|
||||||
{{> user}}
|
{{> user}}
|
||||||
{{/names}}
|
{{/names}}
|
||||||
""")
|
""")
|
||||||
let template2 = try HBMustacheTemplate(string: """
|
let template2 = try MustacheTemplate(string: """
|
||||||
<strong>{{.}}</strong>
|
<strong>{{.}}</strong>
|
||||||
|
|
||||||
""")
|
""")
|
||||||
let library = HBMustacheLibrary(templates: ["base": template, "user": template2])
|
let library = MustacheLibrary(templates: ["base": template, "user": template2])
|
||||||
|
|
||||||
let object: [String: Any] = ["names": ["john", "adam", "claire"]]
|
let object: [String: Any] = ["names": ["john", "adam", "claire"]]
|
||||||
XCTAssertEqual(library.render(object, withTemplate: "base"), """
|
XCTAssertEqual(library.render(object, withTemplate: "base"), """
|
||||||
@@ -43,7 +43,7 @@ final class PartialTests: XCTestCase {
|
|||||||
/// Test where last line of partial generates no content. It should not add a
|
/// Test where last line of partial generates no content. It should not add a
|
||||||
/// tab either
|
/// tab either
|
||||||
func testPartialEmptyLineTabbing() throws {
|
func testPartialEmptyLineTabbing() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
<h2>Names</h2>
|
<h2>Names</h2>
|
||||||
{{#names}}
|
{{#names}}
|
||||||
{{> user}}
|
{{> user}}
|
||||||
@@ -51,7 +51,7 @@ final class PartialTests: XCTestCase {
|
|||||||
Text after
|
Text after
|
||||||
|
|
||||||
""")
|
""")
|
||||||
let template2 = try HBMustacheTemplate(string: """
|
let template2 = try MustacheTemplate(string: """
|
||||||
{{^empty(.)}}
|
{{^empty(.)}}
|
||||||
<strong>{{.}}</strong>
|
<strong>{{.}}</strong>
|
||||||
{{/empty(.)}}
|
{{/empty(.)}}
|
||||||
@@ -60,9 +60,9 @@ final class PartialTests: XCTestCase {
|
|||||||
{{/empty(.)}}
|
{{/empty(.)}}
|
||||||
|
|
||||||
""")
|
""")
|
||||||
var library = HBMustacheLibrary()
|
var library = MustacheLibrary()
|
||||||
library.register(template, named: "base")
|
library.register(template, named: "base")
|
||||||
library.register(template2, named: "user") // , withTemplate: String)// = HBMustacheLibrary(templates: ["base": template, "user": template2])
|
library.register(template2, named: "user") // , withTemplate: String)// = MustacheLibrary(templates: ["base": template, "user": template2])
|
||||||
|
|
||||||
let object: [String: Any] = ["names": ["john", "adam", "claire"]]
|
let object: [String: Any] = ["names": ["john", "adam", "claire"]]
|
||||||
XCTAssertEqual(library.render(object, withTemplate: "base"), """
|
XCTAssertEqual(library.render(object, withTemplate: "base"), """
|
||||||
@@ -77,16 +77,16 @@ final class PartialTests: XCTestCase {
|
|||||||
|
|
||||||
/// Testing dynamic partials
|
/// Testing dynamic partials
|
||||||
func testDynamicPartials() throws {
|
func testDynamicPartials() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
<h2>Names</h2>
|
<h2>Names</h2>
|
||||||
{{partial}}
|
{{partial}}
|
||||||
""")
|
""")
|
||||||
let template2 = try HBMustacheTemplate(string: """
|
let template2 = try MustacheTemplate(string: """
|
||||||
{{#names}}
|
{{#names}}
|
||||||
<strong>{{.}}</strong>
|
<strong>{{.}}</strong>
|
||||||
{{/names}}
|
{{/names}}
|
||||||
""")
|
""")
|
||||||
let library = HBMustacheLibrary(templates: ["base": template])
|
let library = MustacheLibrary(templates: ["base": template])
|
||||||
|
|
||||||
let object: [String: Any] = ["names": ["john", "adam", "claire"], "partial": template2]
|
let object: [String: Any] = ["names": ["john", "adam", "claire"], "partial": template2]
|
||||||
XCTAssertEqual(library.render(object, withTemplate: "base"), """
|
XCTAssertEqual(library.render(object, withTemplate: "base"), """
|
||||||
@@ -100,7 +100,7 @@ final class PartialTests: XCTestCase {
|
|||||||
|
|
||||||
/// test inheritance
|
/// test inheritance
|
||||||
func testInheritance() throws {
|
func testInheritance() throws {
|
||||||
var library = HBMustacheLibrary()
|
var library = MustacheLibrary()
|
||||||
try library.register(
|
try library.register(
|
||||||
"""
|
"""
|
||||||
<head>
|
<head>
|
||||||
|
|||||||
@@ -68,17 +68,17 @@ final class MustacheSpecTests: XCTestCase {
|
|||||||
func run() throws {
|
func run() throws {
|
||||||
// print("Test: \(self.name)")
|
// print("Test: \(self.name)")
|
||||||
if let partials = self.partials {
|
if let partials = self.partials {
|
||||||
let template = try HBMustacheTemplate(string: self.template)
|
let template = try MustacheTemplate(string: self.template)
|
||||||
var templates: [String: HBMustacheTemplate] = ["__test__": template]
|
var templates: [String: MustacheTemplate] = ["__test__": template]
|
||||||
for (key, value) in partials {
|
for (key, value) in partials {
|
||||||
let template = try HBMustacheTemplate(string: value)
|
let template = try MustacheTemplate(string: value)
|
||||||
templates[key] = template
|
templates[key] = template
|
||||||
}
|
}
|
||||||
let library = HBMustacheLibrary(templates: templates)
|
let library = MustacheLibrary(templates: templates)
|
||||||
let result = library.render(self.data.value, withTemplate: "__test__")
|
let result = library.render(self.data.value, withTemplate: "__test__")
|
||||||
self.XCTAssertSpecEqual(result, self)
|
self.XCTAssertSpecEqual(result, self)
|
||||||
} else {
|
} else {
|
||||||
let template = try HBMustacheTemplate(string: self.template)
|
let template = try MustacheTemplate(string: self.template)
|
||||||
let result = template.render(self.data.value)
|
let result = template.render(self.data.value)
|
||||||
self.XCTAssertSpecEqual(result, self)
|
self.XCTAssertSpecEqual(result, self)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,55 +17,55 @@ import XCTest
|
|||||||
|
|
||||||
final class TemplateParserTests: XCTestCase {
|
final class TemplateParserTests: XCTestCase {
|
||||||
func testText() throws {
|
func testText() throws {
|
||||||
let template = try HBMustacheTemplate(string: "test template")
|
let template = try MustacheTemplate(string: "test template")
|
||||||
XCTAssertEqual(template.tokens, [.text("test template")])
|
XCTAssertEqual(template.tokens, [.text("test template")])
|
||||||
}
|
}
|
||||||
|
|
||||||
func testVariable() throws {
|
func testVariable() throws {
|
||||||
let template = try HBMustacheTemplate(string: "test {{variable}}")
|
let template = try MustacheTemplate(string: "test {{variable}}")
|
||||||
XCTAssertEqual(template.tokens, [.text("test "), .variable(name: "variable")])
|
XCTAssertEqual(template.tokens, [.text("test "), .variable(name: "variable")])
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSection() throws {
|
func testSection() throws {
|
||||||
let template = try HBMustacheTemplate(string: "test {{#section}}text{{/section}}")
|
let template = try MustacheTemplate(string: "test {{#section}}text{{/section}}")
|
||||||
XCTAssertEqual(template.tokens, [.text("test "), .section(name: "section", template: .init([.text("text")]))])
|
XCTAssertEqual(template.tokens, [.text("test "), .section(name: "section", template: .init([.text("text")]))])
|
||||||
}
|
}
|
||||||
|
|
||||||
func testInvertedSection() throws {
|
func testInvertedSection() throws {
|
||||||
let template = try HBMustacheTemplate(string: "test {{^section}}text{{/section}}")
|
let template = try MustacheTemplate(string: "test {{^section}}text{{/section}}")
|
||||||
XCTAssertEqual(template.tokens, [.text("test "), .invertedSection(name: "section", template: .init([.text("text")]))])
|
XCTAssertEqual(template.tokens, [.text("test "), .invertedSection(name: "section", template: .init([.text("text")]))])
|
||||||
}
|
}
|
||||||
|
|
||||||
func testComment() throws {
|
func testComment() throws {
|
||||||
let template = try HBMustacheTemplate(string: "test {{!section}}")
|
let template = try MustacheTemplate(string: "test {{!section}}")
|
||||||
XCTAssertEqual(template.tokens, [.text("test ")])
|
XCTAssertEqual(template.tokens, [.text("test ")])
|
||||||
}
|
}
|
||||||
|
|
||||||
func testWhitespace() throws {
|
func testWhitespace() throws {
|
||||||
let template = try HBMustacheTemplate(string: "{{ section }}")
|
let template = try MustacheTemplate(string: "{{ section }}")
|
||||||
XCTAssertEqual(template.tokens, [.variable(name: "section")])
|
XCTAssertEqual(template.tokens, [.variable(name: "section")])
|
||||||
}
|
}
|
||||||
|
|
||||||
func testContentType() throws {
|
func testContentType() throws {
|
||||||
let template = try HBMustacheTemplate(string: "{{% CONTENT_TYPE:TEXT}}")
|
let template = try MustacheTemplate(string: "{{% CONTENT_TYPE:TEXT}}")
|
||||||
let template1 = try HBMustacheTemplate(string: "{{% CONTENT_TYPE:TEXT }}")
|
let template1 = try MustacheTemplate(string: "{{% CONTENT_TYPE:TEXT }}")
|
||||||
let template2 = try HBMustacheTemplate(string: "{{% CONTENT_TYPE: TEXT}}")
|
let template2 = try MustacheTemplate(string: "{{% CONTENT_TYPE: TEXT}}")
|
||||||
let template3 = try HBMustacheTemplate(string: "{{%CONTENT_TYPE:TEXT}}")
|
let template3 = try MustacheTemplate(string: "{{%CONTENT_TYPE:TEXT}}")
|
||||||
XCTAssertEqual(template.tokens, [.contentType(HBTextContentType())])
|
XCTAssertEqual(template.tokens, [.contentType(TextContentType())])
|
||||||
XCTAssertEqual(template1.tokens, [.contentType(HBTextContentType())])
|
XCTAssertEqual(template1.tokens, [.contentType(TextContentType())])
|
||||||
XCTAssertEqual(template2.tokens, [.contentType(HBTextContentType())])
|
XCTAssertEqual(template2.tokens, [.contentType(TextContentType())])
|
||||||
XCTAssertEqual(template3.tokens, [.contentType(HBTextContentType())])
|
XCTAssertEqual(template3.tokens, [.contentType(TextContentType())])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension HBMustacheTemplate: Equatable {
|
extension MustacheTemplate: Equatable {
|
||||||
public static func == (lhs: HBMustacheTemplate, rhs: HBMustacheTemplate) -> Bool {
|
public static func == (lhs: MustacheTemplate, rhs: MustacheTemplate) -> Bool {
|
||||||
lhs.tokens == rhs.tokens
|
lhs.tokens == rhs.tokens
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension HBMustacheTemplate.Token: Equatable {
|
extension MustacheTemplate.Token: Equatable {
|
||||||
public static func == (lhs: HBMustacheTemplate.Token, rhs: HBMustacheTemplate.Token) -> Bool {
|
public static func == (lhs: MustacheTemplate.Token, rhs: MustacheTemplate.Token) -> Bool {
|
||||||
switch (lhs, rhs) {
|
switch (lhs, rhs) {
|
||||||
case (.text(let lhs), .text(let rhs)):
|
case (.text(let lhs), .text(let rhs)):
|
||||||
return lhs == rhs
|
return lhs == rhs
|
||||||
|
|||||||
@@ -17,50 +17,50 @@ import XCTest
|
|||||||
|
|
||||||
final class TemplateRendererTests: XCTestCase {
|
final class TemplateRendererTests: XCTestCase {
|
||||||
func testText() throws {
|
func testText() throws {
|
||||||
let template = try HBMustacheTemplate(string: "test text")
|
let template = try MustacheTemplate(string: "test text")
|
||||||
XCTAssertEqual(template.render("test"), "test text")
|
XCTAssertEqual(template.render("test"), "test text")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStringVariable() throws {
|
func testStringVariable() throws {
|
||||||
let template = try HBMustacheTemplate(string: "test {{.}}")
|
let template = try MustacheTemplate(string: "test {{.}}")
|
||||||
XCTAssertEqual(template.render("text"), "test text")
|
XCTAssertEqual(template.render("text"), "test text")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testIntegerVariable() throws {
|
func testIntegerVariable() throws {
|
||||||
let template = try HBMustacheTemplate(string: "test {{.}}")
|
let template = try MustacheTemplate(string: "test {{.}}")
|
||||||
XCTAssertEqual(template.render(101), "test 101")
|
XCTAssertEqual(template.render(101), "test 101")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDictionary() throws {
|
func testDictionary() throws {
|
||||||
let template = try HBMustacheTemplate(string: "test {{value}} {{bool}}")
|
let template = try MustacheTemplate(string: "test {{value}} {{bool}}")
|
||||||
XCTAssertEqual(template.render(["value": "test2", "bool": true]), "test test2 true")
|
XCTAssertEqual(template.render(["value": "test2", "bool": true]), "test test2 true")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testArraySection() throws {
|
func testArraySection() throws {
|
||||||
let template = try HBMustacheTemplate(string: "test {{#value}}*{{.}}{{/value}}")
|
let template = try MustacheTemplate(string: "test {{#value}}*{{.}}{{/value}}")
|
||||||
XCTAssertEqual(template.render(["value": ["test2", "bool"]]), "test *test2*bool")
|
XCTAssertEqual(template.render(["value": ["test2", "bool"]]), "test *test2*bool")
|
||||||
XCTAssertEqual(template.render(["value": ["test2"]]), "test *test2")
|
XCTAssertEqual(template.render(["value": ["test2"]]), "test *test2")
|
||||||
XCTAssertEqual(template.render(["value": []]), "test ")
|
XCTAssertEqual(template.render(["value": []]), "test ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testBooleanSection() throws {
|
func testBooleanSection() throws {
|
||||||
let template = try HBMustacheTemplate(string: "test {{#.}}Yep{{/.}}")
|
let template = try MustacheTemplate(string: "test {{#.}}Yep{{/.}}")
|
||||||
XCTAssertEqual(template.render(true), "test Yep")
|
XCTAssertEqual(template.render(true), "test Yep")
|
||||||
XCTAssertEqual(template.render(false), "test ")
|
XCTAssertEqual(template.render(false), "test ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testIntegerSection() throws {
|
func testIntegerSection() throws {
|
||||||
let template = try HBMustacheTemplate(string: "test {{#.}}{{.}}{{/.}}")
|
let template = try MustacheTemplate(string: "test {{#.}}{{.}}{{/.}}")
|
||||||
XCTAssertEqual(template.render(23), "test 23")
|
XCTAssertEqual(template.render(23), "test 23")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStringSection() throws {
|
func testStringSection() throws {
|
||||||
let template = try HBMustacheTemplate(string: "test {{#.}}{{.}}{{/.}}")
|
let template = try MustacheTemplate(string: "test {{#.}}{{.}}{{/.}}")
|
||||||
XCTAssertEqual(template.render("Hello"), "test Hello")
|
XCTAssertEqual(template.render("Hello"), "test Hello")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testInvertedSection() throws {
|
func testInvertedSection() throws {
|
||||||
let template = try HBMustacheTemplate(string: "test {{^.}}Inverted{{/.}}")
|
let template = try MustacheTemplate(string: "test {{^.}}Inverted{{/.}}")
|
||||||
XCTAssertEqual(template.render(true), "test ")
|
XCTAssertEqual(template.render(true), "test ")
|
||||||
XCTAssertEqual(template.render(false), "test Inverted")
|
XCTAssertEqual(template.render(false), "test Inverted")
|
||||||
}
|
}
|
||||||
@@ -69,7 +69,7 @@ final class TemplateRendererTests: XCTestCase {
|
|||||||
struct Test {
|
struct Test {
|
||||||
let string: String
|
let string: String
|
||||||
}
|
}
|
||||||
let template = try HBMustacheTemplate(string: "test {{string}}")
|
let template = try MustacheTemplate(string: "test {{string}}")
|
||||||
XCTAssertEqual(template.render(Test(string: "string")), "test string")
|
XCTAssertEqual(template.render(Test(string: "string")), "test string")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ final class TemplateRendererTests: XCTestCase {
|
|||||||
struct Test {
|
struct Test {
|
||||||
let string: String?
|
let string: String?
|
||||||
}
|
}
|
||||||
let template = try HBMustacheTemplate(string: "test {{string}}")
|
let template = try MustacheTemplate(string: "test {{string}}")
|
||||||
XCTAssertEqual(template.render(Test(string: "string")), "test string")
|
XCTAssertEqual(template.render(Test(string: "string")), "test string")
|
||||||
XCTAssertEqual(template.render(Test(string: nil)), "test ")
|
XCTAssertEqual(template.render(Test(string: nil)), "test ")
|
||||||
}
|
}
|
||||||
@@ -86,10 +86,10 @@ final class TemplateRendererTests: XCTestCase {
|
|||||||
struct Test {
|
struct Test {
|
||||||
let string: String?
|
let string: String?
|
||||||
}
|
}
|
||||||
let template = try HBMustacheTemplate(string: "test {{#string}}*{{.}}{{/string}}")
|
let template = try MustacheTemplate(string: "test {{#string}}*{{.}}{{/string}}")
|
||||||
XCTAssertEqual(template.render(Test(string: "string")), "test *string")
|
XCTAssertEqual(template.render(Test(string: "string")), "test *string")
|
||||||
XCTAssertEqual(template.render(Test(string: nil)), "test ")
|
XCTAssertEqual(template.render(Test(string: nil)), "test ")
|
||||||
let template2 = try HBMustacheTemplate(string: "test {{^string}}*{{/string}}")
|
let template2 = try MustacheTemplate(string: "test {{^string}}*{{/string}}")
|
||||||
XCTAssertEqual(template2.render(Test(string: "string")), "test ")
|
XCTAssertEqual(template2.render(Test(string: "string")), "test ")
|
||||||
XCTAssertEqual(template2.render(Test(string: nil)), "test *")
|
XCTAssertEqual(template2.render(Test(string: nil)), "test *")
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,7 @@ final class TemplateRendererTests: XCTestCase {
|
|||||||
struct Test {
|
struct Test {
|
||||||
let string: String?
|
let string: String?
|
||||||
}
|
}
|
||||||
let template = try HBMustacheTemplate(string: "test {{#.}}{{string}}{{/.}}")
|
let template = try MustacheTemplate(string: "test {{#.}}{{string}}{{/.}}")
|
||||||
XCTAssertEqual(template.render([Test(string: "string")]), "test string")
|
XCTAssertEqual(template.render([Test(string: "string")]), "test string")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ final class TemplateRendererTests: XCTestCase {
|
|||||||
struct Test {
|
struct Test {
|
||||||
let string: String?
|
let string: String?
|
||||||
}
|
}
|
||||||
let template = try HBMustacheTemplate(string: "test {{#.}}{{#string}}*{{.}}{{/string}}{{/.}}")
|
let template = try MustacheTemplate(string: "test {{#.}}{{#string}}*{{.}}{{/string}}{{/.}}")
|
||||||
XCTAssertEqual(template.render([Test(string: "string")]), "test *string")
|
XCTAssertEqual(template.render([Test(string: "string")]), "test *string")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,20 +118,20 @@ final class TemplateRendererTests: XCTestCase {
|
|||||||
let test: SubTest
|
let test: SubTest
|
||||||
}
|
}
|
||||||
|
|
||||||
let template = try HBMustacheTemplate(string: "test {{test.string}}")
|
let template = try MustacheTemplate(string: "test {{test.string}}")
|
||||||
XCTAssertEqual(template.render(Test(test: .init(string: "sub"))), "test sub")
|
XCTAssertEqual(template.render(Test(test: .init(string: "sub"))), "test sub")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testTextEscaping() throws {
|
func testTextEscaping() throws {
|
||||||
let template1 = try HBMustacheTemplate(string: "{{% CONTENT_TYPE:TEXT}}{{.}}")
|
let template1 = try MustacheTemplate(string: "{{% CONTENT_TYPE:TEXT}}{{.}}")
|
||||||
XCTAssertEqual(template1.render("<>"), "<>")
|
XCTAssertEqual(template1.render("<>"), "<>")
|
||||||
let template2 = try HBMustacheTemplate(string: "{{% CONTENT_TYPE:HTML}}{{.}}")
|
let template2 = try MustacheTemplate(string: "{{% CONTENT_TYPE:HTML}}{{.}}")
|
||||||
XCTAssertEqual(template2.render("<>"), "<>")
|
XCTAssertEqual(template2.render("<>"), "<>")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStopClimbingStack() throws {
|
func testStopClimbingStack() throws {
|
||||||
let template1 = try HBMustacheTemplate(string: "{{#test}}{{name}}{{/test}}")
|
let template1 = try MustacheTemplate(string: "{{#test}}{{name}}{{/test}}")
|
||||||
let template2 = try HBMustacheTemplate(string: "{{#test}}{{.name}}{{/test}}")
|
let template2 = try MustacheTemplate(string: "{{#test}}{{.name}}{{/test}}")
|
||||||
let object: [String: Any] = ["test": [:], "name": "John"]
|
let object: [String: Any] = ["test": [:], "name": "John"]
|
||||||
let object2: [String: Any] = ["test": ["name": "Jane"], "name": "John"]
|
let object2: [String: Any] = ["test": ["name": "Jane"], "name": "John"]
|
||||||
XCTAssertEqual(template1.render(object), "John")
|
XCTAssertEqual(template1.render(object), "John")
|
||||||
@@ -141,7 +141,7 @@ final class TemplateRendererTests: XCTestCase {
|
|||||||
|
|
||||||
/// variables
|
/// variables
|
||||||
func testMustacheManualExample1() throws {
|
func testMustacheManualExample1() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
Hello {{name}}
|
Hello {{name}}
|
||||||
You have just won {{value}} dollars!
|
You have just won {{value}} dollars!
|
||||||
{{#in_ca}}
|
{{#in_ca}}
|
||||||
@@ -159,7 +159,7 @@ final class TemplateRendererTests: XCTestCase {
|
|||||||
|
|
||||||
/// test esacped and unescaped text
|
/// test esacped and unescaped text
|
||||||
func testMustacheManualExample2() throws {
|
func testMustacheManualExample2() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
*{{name}}
|
*{{name}}
|
||||||
*{{age}}
|
*{{age}}
|
||||||
*{{company}}
|
*{{company}}
|
||||||
@@ -176,7 +176,7 @@ final class TemplateRendererTests: XCTestCase {
|
|||||||
|
|
||||||
/// test boolean
|
/// test boolean
|
||||||
func testMustacheManualExample3() throws {
|
func testMustacheManualExample3() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
Shown.
|
Shown.
|
||||||
{{#person}}
|
{{#person}}
|
||||||
Never shown!
|
Never shown!
|
||||||
@@ -191,7 +191,7 @@ final class TemplateRendererTests: XCTestCase {
|
|||||||
|
|
||||||
/// test non-empty lists
|
/// test non-empty lists
|
||||||
func testMustacheManualExample4() throws {
|
func testMustacheManualExample4() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{#repo}}
|
{{#repo}}
|
||||||
<b>{{name}}</b>
|
<b>{{name}}</b>
|
||||||
{{/repo}}
|
{{/repo}}
|
||||||
@@ -207,13 +207,13 @@ final class TemplateRendererTests: XCTestCase {
|
|||||||
|
|
||||||
/// test lambdas
|
/// test lambdas
|
||||||
func testMustacheManualExample5() throws {
|
func testMustacheManualExample5() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{#wrapped}}{{name}} is awesome.{{/wrapped}}
|
{{#wrapped}}{{name}} is awesome.{{/wrapped}}
|
||||||
""")
|
""")
|
||||||
func wrapped(object: Any, template: HBMustacheTemplate) -> String {
|
func wrapped(object: Any, template: MustacheTemplate) -> String {
|
||||||
return "<b>\(template.render(object))</b>"
|
return "<b>\(template.render(object))</b>"
|
||||||
}
|
}
|
||||||
let object: [String: Any] = ["name": "Willy", "wrapped": HBMustacheLambda(wrapped)]
|
let object: [String: Any] = ["name": "Willy", "wrapped": MustacheLambda(wrapped)]
|
||||||
XCTAssertEqual(template.render(object), """
|
XCTAssertEqual(template.render(object), """
|
||||||
<b>Willy is awesome.</b>
|
<b>Willy is awesome.</b>
|
||||||
""")
|
""")
|
||||||
@@ -221,7 +221,7 @@ final class TemplateRendererTests: XCTestCase {
|
|||||||
|
|
||||||
/// test setting context object
|
/// test setting context object
|
||||||
func testMustacheManualExample6() throws {
|
func testMustacheManualExample6() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{#person?}}
|
{{#person?}}
|
||||||
Hi {{name}}!
|
Hi {{name}}!
|
||||||
{{/person?}}
|
{{/person?}}
|
||||||
@@ -235,7 +235,7 @@ final class TemplateRendererTests: XCTestCase {
|
|||||||
|
|
||||||
/// test inverted sections
|
/// test inverted sections
|
||||||
func testMustacheManualExample7() throws {
|
func testMustacheManualExample7() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{#repo}}
|
{{#repo}}
|
||||||
<b>{{name}}</b>
|
<b>{{name}}</b>
|
||||||
{{/repo}}
|
{{/repo}}
|
||||||
@@ -252,7 +252,7 @@ final class TemplateRendererTests: XCTestCase {
|
|||||||
|
|
||||||
/// test comments
|
/// test comments
|
||||||
func testMustacheManualExample8() throws {
|
func testMustacheManualExample8() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
<h1>Today{{! ignore me }}.</h1>
|
<h1>Today{{! ignore me }}.</h1>
|
||||||
""")
|
""")
|
||||||
let object: [String: Any] = ["repo": []]
|
let object: [String: Any] = ["repo": []]
|
||||||
@@ -261,12 +261,12 @@ final class TemplateRendererTests: XCTestCase {
|
|||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// test HBMustacheCustomRenderable
|
/// test MustacheCustomRenderable
|
||||||
func testCustomRenderable() throws {
|
func testCustomRenderable() throws {
|
||||||
let template = try HBMustacheTemplate(string: "{{.}}")
|
let template = try MustacheTemplate(string: "{{.}}")
|
||||||
let template1 = try HBMustacheTemplate(string: "{{#.}}not null{{/.}}")
|
let template1 = try MustacheTemplate(string: "{{#.}}not null{{/.}}")
|
||||||
let template2 = try HBMustacheTemplate(string: "{{^.}}null{{/.}}")
|
let template2 = try MustacheTemplate(string: "{{^.}}null{{/.}}")
|
||||||
struct Object: HBMustacheCustomRenderable {
|
struct Object: MustacheCustomRenderable {
|
||||||
let value: String
|
let value: String
|
||||||
|
|
||||||
var renderText: String { self.value.uppercased() }
|
var renderText: String { self.value.uppercased() }
|
||||||
@@ -282,7 +282,7 @@ final class TemplateRendererTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testPerformance() throws {
|
func testPerformance() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{#repo}}
|
{{#repo}}
|
||||||
<b>{{name}}</b>
|
<b>{{name}}</b>
|
||||||
{{/repo}}
|
{{/repo}}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import XCTest
|
|||||||
|
|
||||||
final class TransformTests: XCTestCase {
|
final class TransformTests: XCTestCase {
|
||||||
func testLowercased() throws {
|
func testLowercased() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{ lowercased(name) }}
|
{{ lowercased(name) }}
|
||||||
""")
|
""")
|
||||||
let object: [String: Any] = ["name": "Test"]
|
let object: [String: Any] = ["name": "Test"]
|
||||||
@@ -25,7 +25,7 @@ final class TransformTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testUppercased() throws {
|
func testUppercased() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{ uppercased(name) }}
|
{{ uppercased(name) }}
|
||||||
""")
|
""")
|
||||||
let object: [String: Any] = ["name": "Test"]
|
let object: [String: Any] = ["name": "Test"]
|
||||||
@@ -33,7 +33,7 @@ final class TransformTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testNewline() throws {
|
func testNewline() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{#repo}}
|
{{#repo}}
|
||||||
<b>{{name}}</b>
|
<b>{{name}}</b>
|
||||||
{{/repo}}
|
{{/repo}}
|
||||||
@@ -49,7 +49,7 @@ final class TransformTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testFirstLast() throws {
|
func testFirstLast() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{#repo}}
|
{{#repo}}
|
||||||
<b>{{#first()}}first: {{/first()}}{{#last()}}last: {{/last()}}{{ name }}</b>
|
<b>{{#first()}}first: {{/first()}}{{#last()}}last: {{/last()}}{{ name }}</b>
|
||||||
{{/repo}}
|
{{/repo}}
|
||||||
@@ -65,7 +65,7 @@ final class TransformTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testIndex() throws {
|
func testIndex() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{#repo}}
|
{{#repo}}
|
||||||
<b>{{#index()}}{{plusone(.)}}{{/index()}}) {{ name }}</b>
|
<b>{{#index()}}{{plusone(.)}}{{/index()}}) {{ name }}</b>
|
||||||
{{/repo}}
|
{{/repo}}
|
||||||
@@ -81,7 +81,7 @@ final class TransformTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testEvenOdd() throws {
|
func testEvenOdd() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{#repo}}
|
{{#repo}}
|
||||||
<b>{{index()}}) {{#even()}}even {{/even()}}{{#odd()}}odd {{/odd()}}{{ name }}</b>
|
<b>{{index()}}) {{#even()}}even {{/even()}}{{#odd()}}odd {{/odd()}}{{ name }}</b>
|
||||||
{{/repo}}
|
{{/repo}}
|
||||||
@@ -97,7 +97,7 @@ final class TransformTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testReversed() throws {
|
func testReversed() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{#reversed(repo)}}
|
{{#reversed(repo)}}
|
||||||
<b>{{ name }}</b>
|
<b>{{ name }}</b>
|
||||||
{{/reversed(repo)}}
|
{{/reversed(repo)}}
|
||||||
@@ -113,7 +113,7 @@ final class TransformTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testArrayIndex() throws {
|
func testArrayIndex() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{#repo}}
|
{{#repo}}
|
||||||
<b>{{ index() }}) {{ name }}</b>
|
<b>{{ index() }}) {{ name }}</b>
|
||||||
{{/repo}}
|
{{/repo}}
|
||||||
@@ -128,7 +128,7 @@ final class TransformTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testArraySorted() throws {
|
func testArraySorted() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{#sorted(repo)}}
|
{{#sorted(repo)}}
|
||||||
<b>{{ index() }}) {{ . }}</b>
|
<b>{{ index() }}) {{ . }}</b>
|
||||||
{{/sorted(repo)}}
|
{{/sorted(repo)}}
|
||||||
@@ -143,7 +143,7 @@ final class TransformTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testDictionaryEmpty() throws {
|
func testDictionaryEmpty() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{#empty(array)}}Array{{/empty(array)}}{{#empty(dictionary)}}Dictionary{{/empty(dictionary)}}
|
{{#empty(array)}}Array{{/empty(array)}}{{#empty(dictionary)}}Dictionary{{/empty(dictionary)}}
|
||||||
""")
|
""")
|
||||||
let object: [String: Any] = ["array": [], "dictionary": [:]]
|
let object: [String: Any] = ["array": [], "dictionary": [:]]
|
||||||
@@ -152,12 +152,12 @@ final class TransformTests: XCTestCase {
|
|||||||
|
|
||||||
func testListOutput() throws {
|
func testListOutput() throws {
|
||||||
let object = [1, 2, 3, 4]
|
let object = [1, 2, 3, 4]
|
||||||
let template = try HBMustacheTemplate(string: "{{#.}}{{.}}{{^last()}}, {{/last()}}{{/.}}")
|
let template = try MustacheTemplate(string: "{{#.}}{{.}}{{^last()}}, {{/last()}}{{/.}}")
|
||||||
XCTAssertEqual(template.render(object), "1, 2, 3, 4")
|
XCTAssertEqual(template.render(object), "1, 2, 3, 4")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDictionaryEnumerated() throws {
|
func testDictionaryEnumerated() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{#enumerated(.)}}<b>{{ key }} = {{ value }}</b>{{/enumerated(.)}}
|
{{#enumerated(.)}}<b>{{ key }} = {{ value }}</b>{{/enumerated(.)}}
|
||||||
""")
|
""")
|
||||||
let object: [String: Any] = ["one": 1, "two": 2]
|
let object: [String: Any] = ["one": 1, "two": 2]
|
||||||
@@ -166,7 +166,7 @@ final class TransformTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testDictionarySortedByKey() throws {
|
func testDictionarySortedByKey() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try MustacheTemplate(string: """
|
||||||
{{#sorted(.)}}<b>{{ key }} = {{ value }}</b>{{/sorted(.)}}
|
{{#sorted(.)}}<b>{{ key }} = {{ value }}</b>{{/sorted(.)}}
|
||||||
""")
|
""")
|
||||||
let object: [String: Any] = ["one": 1, "two": 2, "three": 3]
|
let object: [String: Any] = ["one": 1, "two": 2, "three": 3]
|
||||||
|
|||||||
@@ -2,17 +2,17 @@
|
|||||||
|
|
||||||
The library doesn't provide a lambda implementation but it does provide something akin to the lambda feature.
|
The library doesn't provide a lambda implementation but it does provide something akin to the lambda feature.
|
||||||
|
|
||||||
Add a `HBMustacheLambda` to the object you want to be rendered and it can be used in a similar way to lambdas are used in Mustache. When you create a section referencing the lambda the contents of the section are passed as a template along with the current object to the lamdba function. This is slightly different from the standard implementation where the unprocessed text is passed to the lambda.
|
Add a `MustacheLambda` to the object you want to be rendered and it can be used in a similar way to lambdas are used in Mustache. When you create a section referencing the lambda the contents of the section are passed as a template along with the current object to the lamdba function. This is slightly different from the standard implementation where the unprocessed text is passed to the lambda.
|
||||||
|
|
||||||
Given the object `person` defined below
|
Given the object `person` defined below
|
||||||
```swift
|
```swift
|
||||||
struct Person {
|
struct Person {
|
||||||
let name: String
|
let name: String
|
||||||
let wrapped: HBMustacheLambda
|
let wrapped: MustacheLambda
|
||||||
}
|
}
|
||||||
let person = Person(
|
let person = Person(
|
||||||
name: "John",
|
name: "John",
|
||||||
wrapped: HBMustacheLambda { object, template in
|
wrapped: MustacheLambda { object, template in
|
||||||
return "<b>\(template.render(object))</b>"
|
return "<b>\(template.render(object))</b>"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -21,7 +21,7 @@ let person = Person(
|
|||||||
and the following mustache template
|
and the following mustache template
|
||||||
```swift
|
```swift
|
||||||
let mustache = "{{#wrapped}}{{name}} is awesome.{{/wrapped}}"
|
let mustache = "{{#wrapped}}{{name}} is awesome.{{/wrapped}}"
|
||||||
let template = try HBMustacheTemplate(string: mustache)
|
let template = try MustacheTemplate(string: mustache)
|
||||||
```
|
```
|
||||||
Then `template.render(person)` will output
|
Then `template.render(person)` will output
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -52,9 +52,9 @@ The following sequence context transforms are available
|
|||||||
|
|
||||||
## Custom transforms
|
## Custom transforms
|
||||||
|
|
||||||
You can add transforms to your own objects. Conform the object to `HBMustacheTransformable` and provide an implementation of the function `transform`. eg
|
You can add transforms to your own objects. Conform the object to `MustacheTransformable` and provide an implementation of the function `transform`. eg
|
||||||
```swift
|
```swift
|
||||||
struct Object: HBMustacheTransformable {
|
struct Object: MustacheTransformable {
|
||||||
let either: Bool
|
let either: Bool
|
||||||
let or: Bool
|
let or: Bool
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user