added parent context to ErrorReporterContext and handling errors in include and extend nodes
This commit is contained in:
@@ -48,7 +48,6 @@ public struct Environment {
|
||||
return try template.render(context)
|
||||
} catch {
|
||||
try errorReporter.report(error: error)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,4 +55,19 @@ public struct Environment {
|
||||
return errorReporter.context?.template
|
||||
}
|
||||
|
||||
|
||||
public func pushTemplate<Result>(_ template: Template, token: Token, closure: (() throws -> Result)) rethrows -> Result {
|
||||
let errorReporterContext = errorReporter.context
|
||||
defer { errorReporter.context = errorReporterContext }
|
||||
errorReporter.context = ErrorReporterContext(
|
||||
template: template,
|
||||
parent: errorReporterContext != nil ? (errorReporterContext!, token) : nil
|
||||
)
|
||||
do {
|
||||
return try closure()
|
||||
} catch {
|
||||
try errorReporter.report(error: error)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,26 +35,31 @@ public struct TemplateSyntaxError : Error, Equatable, CustomStringConvertible {
|
||||
public class ErrorReporterContext {
|
||||
public let template: Template
|
||||
|
||||
public init(template: Template) {
|
||||
public typealias ParentContext = (context: ErrorReporterContext, token: Token)
|
||||
public let parent: ParentContext?
|
||||
|
||||
public init(template: Template, parent: ParentContext? = nil) {
|
||||
self.template = template
|
||||
self.parent = parent
|
||||
}
|
||||
}
|
||||
|
||||
public protocol ErrorReporter: class {
|
||||
var context: ErrorReporterContext! { get set }
|
||||
func report(error: Error) throws
|
||||
func report(error: Error) throws -> Never
|
||||
func contextAwareError(_ error: TemplateSyntaxError, context: ErrorReporterContext) -> Error?
|
||||
}
|
||||
|
||||
open class SimpleErrorReporter: ErrorReporter {
|
||||
public var context: ErrorReporterContext!
|
||||
|
||||
open func report(error: Error) throws {
|
||||
open func report(error: Error) throws -> Never {
|
||||
guard let syntaxError = error as? TemplateSyntaxError else { throw error }
|
||||
guard let context = context else { throw error }
|
||||
throw contextAwareError(syntaxError, context: context) ?? error
|
||||
}
|
||||
|
||||
// TODO: add stack trace using parent context
|
||||
open func contextAwareError(_ error: TemplateSyntaxError, context: ErrorReporterContext) -> Error? {
|
||||
guard let lexeme = error.lexeme, lexeme.range != .unknown else { return nil }
|
||||
let templateName = context.template.name.map({ "\($0):" }) ?? ""
|
||||
|
||||
@@ -3,6 +3,7 @@ import PathKit
|
||||
|
||||
class IncludeNode : NodeType {
|
||||
let templateName: Variable
|
||||
let token: Token
|
||||
|
||||
class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
|
||||
let bits = token.components()
|
||||
@@ -11,11 +12,12 @@ class IncludeNode : NodeType {
|
||||
throw TemplateSyntaxError("'include' tag takes one argument, the template file to be included")
|
||||
}
|
||||
|
||||
return IncludeNode(templateName: Variable(bits[1]))
|
||||
return IncludeNode(templateName: Variable(bits[1]), token: token)
|
||||
}
|
||||
|
||||
init(templateName: Variable) {
|
||||
init(templateName: Variable, token: Token) {
|
||||
self.templateName = templateName
|
||||
self.token = token
|
||||
}
|
||||
|
||||
func render(_ context: Context) throws -> String {
|
||||
@@ -25,8 +27,10 @@ class IncludeNode : NodeType {
|
||||
|
||||
let template = try context.environment.loadTemplate(name: templateName)
|
||||
|
||||
return try context.push {
|
||||
return try template.render(context)
|
||||
return try context.environment.pushTemplate(template, token: token) {
|
||||
try context.push {
|
||||
return try template.render(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ extension Collection {
|
||||
class ExtendsNode : NodeType {
|
||||
let templateName: Variable
|
||||
let blocks: [String:BlockNode]
|
||||
let token: Token
|
||||
|
||||
class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
|
||||
let bits = token.components()
|
||||
@@ -72,12 +73,13 @@ class ExtendsNode : NodeType {
|
||||
return dict
|
||||
}
|
||||
|
||||
return ExtendsNode(templateName: Variable(bits[1]), blocks: nodes)
|
||||
return ExtendsNode(templateName: Variable(bits[1]), blocks: nodes, token: token)
|
||||
}
|
||||
|
||||
init(templateName: Variable, blocks: [String: BlockNode]) {
|
||||
init(templateName: Variable, blocks: [String: BlockNode], token: Token) {
|
||||
self.templateName = templateName
|
||||
self.blocks = blocks
|
||||
self.token = token
|
||||
}
|
||||
|
||||
func render(_ context: Context) throws -> String {
|
||||
@@ -98,8 +100,10 @@ class ExtendsNode : NodeType {
|
||||
blockContext = BlockContext(blocks: blocks)
|
||||
}
|
||||
|
||||
return try context.push(dictionary: [BlockContext.contextKey: blockContext]) {
|
||||
return try template.render(context)
|
||||
return try context.environment.pushTemplate(template, token: token) {
|
||||
try context.push(dictionary: [BlockContext.contextKey: blockContext]) {
|
||||
return try template.render(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user