chore: Lock down APIs
This commit is contained in:
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
## Master
|
## Master
|
||||||
|
|
||||||
|
### Breaking
|
||||||
|
|
||||||
|
- Many internal classes are no longer private. Some APIs were previously
|
||||||
|
accessible due to earlier versions of Swift requiring the types to be public
|
||||||
|
to be able to test. Now we have access to `@testable` these can correctly be
|
||||||
|
private.
|
||||||
|
|
||||||
### Enhancements
|
### Enhancements
|
||||||
|
|
||||||
- You may now register custom template filters which make use of arguments.
|
- You may now register custom template filters which make use of arguments.
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public class Context {
|
|||||||
self.namespace = namespace
|
self.namespace = namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
open subscript(key: String) -> Any? {
|
public subscript(key: String) -> Any? {
|
||||||
/// Retrieves a variable's value, starting at the current context and going upwards
|
/// Retrieves a variable's value, starting at the current context and going upwards
|
||||||
get {
|
get {
|
||||||
for dictionary in Array(dictionaries.reversed()) {
|
for dictionary in Array(dictionaries.reversed()) {
|
||||||
@@ -47,7 +47,7 @@ public class Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Push a new level onto the context for the duration of the execution of the given closure
|
/// Push a new level onto the context for the duration of the execution of the given closure
|
||||||
open func push<Result>(dictionary: [String: Any]? = nil, closure: (() throws -> Result)) rethrows -> Result {
|
public func push<Result>(dictionary: [String: Any]? = nil, closure: (() throws -> Result)) rethrows -> Result {
|
||||||
push(dictionary)
|
push(dictionary)
|
||||||
defer { _ = pop() }
|
defer { _ = pop() }
|
||||||
return try closure()
|
return try closure()
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
open class ForNode : NodeType {
|
class ForNode : NodeType {
|
||||||
let variable:Variable
|
let variable:Variable
|
||||||
let loopVariable:String
|
let loopVariable:String
|
||||||
let nodes:[NodeType]
|
let nodes:[NodeType]
|
||||||
let emptyNodes: [NodeType]
|
let emptyNodes: [NodeType]
|
||||||
|
|
||||||
open class func parse(_ parser:TokenParser, token:Token) throws -> NodeType {
|
class func parse(_ parser:TokenParser, token:Token) throws -> NodeType {
|
||||||
let components = token.components()
|
let components = token.components()
|
||||||
|
|
||||||
guard components.count == 4 && components[2] == "in" else {
|
guard components.count == 4 && components[2] == "in" else {
|
||||||
@@ -30,14 +30,14 @@ open class ForNode : NodeType {
|
|||||||
return ForNode(variable: variable, loopVariable: loopVariable, nodes: forNodes, emptyNodes:emptyNodes)
|
return ForNode(variable: variable, loopVariable: loopVariable, nodes: forNodes, emptyNodes:emptyNodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(variable:String, loopVariable:String, nodes:[NodeType], emptyNodes:[NodeType]) {
|
init(variable:String, loopVariable:String, nodes:[NodeType], emptyNodes:[NodeType]) {
|
||||||
self.variable = Variable(variable)
|
self.variable = Variable(variable)
|
||||||
self.loopVariable = loopVariable
|
self.loopVariable = loopVariable
|
||||||
self.nodes = nodes
|
self.nodes = nodes
|
||||||
self.emptyNodes = emptyNodes
|
self.emptyNodes = emptyNodes
|
||||||
}
|
}
|
||||||
|
|
||||||
open func render(_ context: Context) throws -> String {
|
func render(_ context: Context) throws -> String {
|
||||||
let values = try variable.resolve(context)
|
let values = try variable.resolve(context)
|
||||||
|
|
||||||
if let values = values as? [Any] , values.count > 0 {
|
if let values = values as? [Any] , values.count > 0 {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
open class IfNode : NodeType {
|
class IfNode : NodeType {
|
||||||
open let variable:Variable
|
let variable:Variable
|
||||||
open let trueNodes:[NodeType]
|
let trueNodes:[NodeType]
|
||||||
open let falseNodes:[NodeType]
|
let falseNodes:[NodeType]
|
||||||
|
|
||||||
open class func parse(_ parser:TokenParser, token:Token) throws -> NodeType {
|
class func parse(_ parser:TokenParser, token:Token) throws -> NodeType {
|
||||||
let components = token.components()
|
let components = token.components()
|
||||||
guard components.count == 2 else {
|
guard components.count == 2 else {
|
||||||
throw TemplateSyntaxError("'if' statements should use the following 'if condition' `\(token.contents)`.")
|
throw TemplateSyntaxError("'if' statements should use the following 'if condition' `\(token.contents)`.")
|
||||||
@@ -26,7 +26,7 @@ open class IfNode : NodeType {
|
|||||||
return IfNode(variable: variable, trueNodes: trueNodes, falseNodes: falseNodes)
|
return IfNode(variable: variable, trueNodes: trueNodes, falseNodes: falseNodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
open class func parse_ifnot(_ parser:TokenParser, token:Token) throws -> NodeType {
|
class func parse_ifnot(_ parser:TokenParser, token:Token) throws -> NodeType {
|
||||||
let components = token.components()
|
let components = token.components()
|
||||||
guard components.count == 2 else {
|
guard components.count == 2 else {
|
||||||
throw TemplateSyntaxError("'ifnot' statements should use the following 'ifnot condition' `\(token.contents)`.")
|
throw TemplateSyntaxError("'ifnot' statements should use the following 'ifnot condition' `\(token.contents)`.")
|
||||||
@@ -49,13 +49,13 @@ open class IfNode : NodeType {
|
|||||||
return IfNode(variable: variable, trueNodes: trueNodes, falseNodes: falseNodes)
|
return IfNode(variable: variable, trueNodes: trueNodes, falseNodes: falseNodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(variable:String, trueNodes:[NodeType], falseNodes:[NodeType]) {
|
init(variable:String, trueNodes:[NodeType], falseNodes:[NodeType]) {
|
||||||
self.variable = Variable(variable)
|
self.variable = Variable(variable)
|
||||||
self.trueNodes = trueNodes
|
self.trueNodes = trueNodes
|
||||||
self.falseNodes = falseNodes
|
self.falseNodes = falseNodes
|
||||||
}
|
}
|
||||||
|
|
||||||
open func render(_ context: Context) throws -> String {
|
func render(_ context: Context) throws -> String {
|
||||||
let result = try variable.resolve(context)
|
let result = try variable.resolve(context)
|
||||||
var truthy = false
|
var truthy = false
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import PathKit
|
import PathKit
|
||||||
|
|
||||||
|
|
||||||
open class IncludeNode : NodeType {
|
class IncludeNode : NodeType {
|
||||||
open let templateName: Variable
|
let templateName: Variable
|
||||||
|
|
||||||
open class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
|
class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
|
||||||
let bits = token.components()
|
let bits = token.components()
|
||||||
|
|
||||||
guard bits.count == 2 else {
|
guard bits.count == 2 else {
|
||||||
@@ -14,11 +14,11 @@ open class IncludeNode : NodeType {
|
|||||||
return IncludeNode(templateName: Variable(bits[1]))
|
return IncludeNode(templateName: Variable(bits[1]))
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(templateName: Variable) {
|
init(templateName: Variable) {
|
||||||
self.templateName = templateName
|
self.templateName = templateName
|
||||||
}
|
}
|
||||||
|
|
||||||
open func render(_ context: Context) throws -> String {
|
func render(_ context: Context) throws -> String {
|
||||||
guard let loader = context["loader"] as? TemplateLoader else {
|
guard let loader = context["loader"] as? TemplateLoader else {
|
||||||
throw TemplateSyntaxError("Template loader not in context")
|
throw TemplateSyntaxError("Template loader not in context")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
public struct Lexer {
|
struct Lexer {
|
||||||
public let templateString: String
|
let templateString: String
|
||||||
|
|
||||||
public init(templateString: String) {
|
init(templateString: String) {
|
||||||
self.templateString = templateString
|
self.templateString = templateString
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ public struct Lexer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an array of tokens from a given template string.
|
/// Returns an array of tokens from a given template string.
|
||||||
public func tokenize() -> [Token] {
|
func tokenize() -> [Token] {
|
||||||
var tokens: [Token] = []
|
var tokens: [Token] = []
|
||||||
|
|
||||||
let scanner = Scanner(templateString)
|
let scanner = Scanner(templateString)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ enum Filter: FilterType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open class Namespace {
|
public class Namespace {
|
||||||
public typealias TagParser = (TokenParser, Token) throws -> NodeType
|
public typealias TagParser = (TokenParser, Token) throws -> NodeType
|
||||||
|
|
||||||
var tags = [String: TagParser]()
|
var tags = [String: TagParser]()
|
||||||
@@ -51,24 +51,24 @@ open class Namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a new template tag
|
/// Registers a new template tag
|
||||||
open func registerTag(_ name: String, parser: @escaping TagParser) {
|
public func registerTag(_ name: String, parser: @escaping TagParser) {
|
||||||
tags[name] = parser
|
tags[name] = parser
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a simple template tag with a name and a handler
|
/// Registers a simple template tag with a name and a handler
|
||||||
open func registerSimpleTag(_ name: String, handler: @escaping (Context) throws -> String) {
|
public func registerSimpleTag(_ name: String, handler: @escaping (Context) throws -> String) {
|
||||||
registerTag(name, parser: { parser, token in
|
registerTag(name, parser: { parser, token in
|
||||||
return SimpleNode(handler: handler)
|
return SimpleNode(handler: handler)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a template filter with the given name
|
/// Registers a template filter with the given name
|
||||||
open func registerFilter(_ name: String, filter: @escaping (Any?) throws -> Any?) {
|
public func registerFilter(_ name: String, filter: @escaping (Any?) throws -> Any?) {
|
||||||
filters[name] = .simple(filter)
|
filters[name] = .simple(filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a template filter with the given name
|
/// Registers a template filter with the given name
|
||||||
open func registerFilter(_ name: String, filter: @escaping (Any?, [Any?]) throws -> Any?) {
|
public func registerFilter(_ name: String, filter: @escaping (Any?, [Any?]) throws -> Any?) {
|
||||||
filters[name] = .arguments(filter)
|
filters[name] = .arguments(filter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,27 +26,27 @@ public func renderNodes(_ nodes:[NodeType], _ context:Context) throws -> String
|
|||||||
return try nodes.map { try $0.render(context) }.joined(separator: "")
|
return try nodes.map { try $0.render(context) }.joined(separator: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
open class SimpleNode : NodeType {
|
public class SimpleNode : NodeType {
|
||||||
let handler:(Context) throws -> String
|
public let handler:(Context) throws -> String
|
||||||
|
|
||||||
public init(handler:@escaping (Context) throws -> String) {
|
public init(handler: @escaping (Context) throws -> String) {
|
||||||
self.handler = handler
|
self.handler = handler
|
||||||
}
|
}
|
||||||
|
|
||||||
open func render(_ context: Context) throws -> String {
|
public func render(_ context: Context) throws -> String {
|
||||||
return try handler(context)
|
return try handler(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open class TextNode : NodeType {
|
public class TextNode : NodeType {
|
||||||
open let text:String
|
public let text:String
|
||||||
|
|
||||||
public init(text:String) {
|
public init(text:String) {
|
||||||
self.text = text
|
self.text = text
|
||||||
}
|
}
|
||||||
|
|
||||||
open func render(_ context:Context) throws -> String {
|
public func render(_ context:Context) throws -> String {
|
||||||
return self.text
|
return self.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,8 +57,8 @@ public protocol Resolvable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open class VariableNode : NodeType {
|
public class VariableNode : NodeType {
|
||||||
open let variable: Resolvable
|
public let variable: Resolvable
|
||||||
|
|
||||||
public init(variable: Resolvable) {
|
public init(variable: Resolvable) {
|
||||||
self.variable = variable
|
self.variable = variable
|
||||||
@@ -68,7 +68,7 @@ open class VariableNode : NodeType {
|
|||||||
self.variable = Variable(variable)
|
self.variable = Variable(variable)
|
||||||
}
|
}
|
||||||
|
|
||||||
open func render(_ context: Context) throws -> String {
|
public func render(_ context: Context) throws -> String {
|
||||||
let result = try variable.resolve(context)
|
let result = try variable.resolve(context)
|
||||||
|
|
||||||
if let result = result as? String {
|
if let result = result as? String {
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
open class NowNode : NodeType {
|
class NowNode : NodeType {
|
||||||
open let format:Variable
|
let format:Variable
|
||||||
|
|
||||||
open class func parse(_ parser:TokenParser, token:Token) throws -> NodeType {
|
class func parse(_ parser:TokenParser, token:Token) throws -> NodeType {
|
||||||
var format:Variable?
|
var format:Variable?
|
||||||
|
|
||||||
let components = token.components()
|
let components = token.components()
|
||||||
@@ -19,11 +19,11 @@ open class NowNode : NodeType {
|
|||||||
return NowNode(format:format)
|
return NowNode(format:format)
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(format:Variable?) {
|
init(format:Variable?) {
|
||||||
self.format = format ?? Variable("\"yyyy-MM-dd 'at' HH:mm\"")
|
self.format = format ?? Variable("\"yyyy-MM-dd 'at' HH:mm\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
open func render(_ context: Context) throws -> String {
|
func render(_ context: Context) throws -> String {
|
||||||
let date = Date()
|
let date = Date()
|
||||||
let format = try self.format.resolve(context)
|
let format = try self.format.resolve(context)
|
||||||
var formatter:DateFormatter?
|
var formatter:DateFormatter?
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public func until(_ tags: [String]) -> ((TokenParser, Token) -> Bool) {
|
|||||||
|
|
||||||
|
|
||||||
/// A class for parsing an array of tokens and converts them into a collection of Node's
|
/// A class for parsing an array of tokens and converts them into a collection of Node's
|
||||||
open class TokenParser {
|
public class TokenParser {
|
||||||
public typealias TagParser = (TokenParser, Token) throws -> NodeType
|
public typealias TagParser = (TokenParser, Token) throws -> NodeType
|
||||||
|
|
||||||
fileprivate var tokens: [Token]
|
fileprivate var tokens: [Token]
|
||||||
@@ -26,11 +26,11 @@ open class TokenParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the given tokens into nodes
|
/// Parse the given tokens into nodes
|
||||||
open func parse() throws -> [NodeType] {
|
public func parse() throws -> [NodeType] {
|
||||||
return try parse(nil)
|
return try parse(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
open func parse(_ parse_until:((_ parser:TokenParser, _ token:Token) -> (Bool))?) throws -> [NodeType] {
|
public func parse(_ parse_until:((_ parser:TokenParser, _ token:Token) -> (Bool))?) throws -> [NodeType] {
|
||||||
var nodes = [NodeType]()
|
var nodes = [NodeType]()
|
||||||
|
|
||||||
while tokens.count > 0 {
|
while tokens.count > 0 {
|
||||||
@@ -64,7 +64,7 @@ open class TokenParser {
|
|||||||
return nodes
|
return nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
open func nextToken() -> Token? {
|
public func nextToken() -> Token? {
|
||||||
if tokens.count > 0 {
|
if tokens.count > 0 {
|
||||||
return tokens.remove(at: 0)
|
return tokens.remove(at: 0)
|
||||||
}
|
}
|
||||||
@@ -72,11 +72,11 @@ open class TokenParser {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
open func prependToken(_ token:Token) {
|
public func prependToken(_ token:Token) {
|
||||||
tokens.insert(token, at: 0)
|
tokens.insert(token, at: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
open func findFilter(_ name: String) throws -> FilterType {
|
public func findFilter(_ name: String) throws -> FilterType {
|
||||||
if let filter = namespace.filters[name] {
|
if let filter = namespace.filters[name] {
|
||||||
return filter
|
return filter
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ let NSFileNoSuchFileError = 4
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// A class representing a template
|
/// A class representing a template
|
||||||
open class Template: ExpressibleByStringLiteral {
|
public class Template: ExpressibleByStringLiteral {
|
||||||
let tokens: [Token]
|
let tokens: [Token]
|
||||||
|
|
||||||
/// Create a template with the given name inside the given bundle
|
/// Create a template with the given name inside the given bundle
|
||||||
@@ -51,7 +51,7 @@ open class Template: ExpressibleByStringLiteral {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Render the given template
|
/// Render the given template
|
||||||
open func render(_ context: Context? = nil) throws -> String {
|
public func render(_ context: Context? = nil) throws -> String {
|
||||||
let context = context ?? Context()
|
let context = context ?? Context()
|
||||||
let parser = TokenParser(tokens: tokens, namespace: context.namespace)
|
let parser = TokenParser(tokens: tokens, namespace: context.namespace)
|
||||||
let nodes = try parser.parse()
|
let nodes = try parser.parse()
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import PathKit
|
|||||||
|
|
||||||
|
|
||||||
// A class for loading a template from disk
|
// A class for loading a template from disk
|
||||||
open class TemplateLoader {
|
public class TemplateLoader {
|
||||||
open let paths: [Path]
|
public let paths: [Path]
|
||||||
|
|
||||||
public init(paths: [Path]) {
|
public init(paths: [Path]) {
|
||||||
self.paths = paths
|
self.paths = paths
|
||||||
@@ -16,11 +16,11 @@ open class TemplateLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open func loadTemplate(_ templateName: String) -> Template? {
|
public func loadTemplate(_ templateName: String) -> Template? {
|
||||||
return loadTemplate([templateName])
|
return loadTemplate([templateName])
|
||||||
}
|
}
|
||||||
|
|
||||||
open func loadTemplate(_ templateNames: [String]) -> Template? {
|
public func loadTemplate(_ templateNames: [String]) -> Template? {
|
||||||
for path in paths {
|
for path in paths {
|
||||||
for templateName in templateNames {
|
for templateName in templateNames {
|
||||||
let templatePath = path + Path(templateName)
|
let templatePath = path + Path(templateName)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Spectre
|
import Spectre
|
||||||
import Stencil
|
@testable import Stencil
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Spectre
|
import Spectre
|
||||||
import Stencil
|
@testable import Stencil
|
||||||
|
|
||||||
|
|
||||||
func testIfNode() {
|
func testIfNode() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Spectre
|
import Spectre
|
||||||
import Stencil
|
@testable import Stencil
|
||||||
import PathKit
|
import PathKit
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Spectre
|
import Spectre
|
||||||
import Stencil
|
@testable import Stencil
|
||||||
|
|
||||||
|
|
||||||
func testLexer() {
|
func testLexer() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import Spectre
|
import Spectre
|
||||||
import Stencil
|
@testable import Stencil
|
||||||
|
|
||||||
|
|
||||||
func testNowNode() {
|
func testNowNode() {
|
||||||
|
|||||||
Reference in New Issue
Block a user