refactor(loader): Throw when template not found
This commit is contained in:
14
Sources/Errors.swift
Normal file
14
Sources/Errors.swift
Normal file
@@ -0,0 +1,14 @@
|
||||
public class TemplateDoesNotExist: Error, CustomStringConvertible {
|
||||
let templateNames: [String]
|
||||
let loader: Loader
|
||||
|
||||
public init(templateNames: [String], loader: Loader) {
|
||||
self.templateNames = templateNames
|
||||
self.loader = loader
|
||||
}
|
||||
|
||||
public var description: String {
|
||||
let templates = templateNames.joined(separator: ", ")
|
||||
return "Template named `\(templates)` does not exist in loader \(loader)"
|
||||
}
|
||||
}
|
||||
@@ -27,10 +27,7 @@ class IncludeNode : NodeType {
|
||||
throw TemplateSyntaxError("'\(self.templateName)' could not be resolved as a string")
|
||||
}
|
||||
|
||||
guard let template = try loader.loadTemplate(name: templateName) else {
|
||||
throw TemplateSyntaxError("'\(templateName)' template not found")
|
||||
}
|
||||
|
||||
let template = try loader.loadTemplate(name: templateName)
|
||||
return try template.render(context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,9 +67,7 @@ class ExtendsNode : NodeType {
|
||||
throw TemplateSyntaxError("'\(self.templateName)' could not be resolved as a string")
|
||||
}
|
||||
|
||||
guard let template = try loader.loadTemplate(name: templateName) else {
|
||||
throw TemplateSyntaxError("'\(templateName)' template not found")
|
||||
}
|
||||
let template = try loader.loadTemplate(name: templateName)
|
||||
|
||||
let blockContext: BlockContext
|
||||
if let context = context[BlockContext.contextKey] as? BlockContext {
|
||||
|
||||
101
Sources/Loader.swift
Normal file
101
Sources/Loader.swift
Normal file
@@ -0,0 +1,101 @@
|
||||
import Foundation
|
||||
import PathKit
|
||||
|
||||
|
||||
public protocol Loader {
|
||||
func loadTemplate(name: String) throws -> Template
|
||||
func loadTemplate(names: [String]) throws -> Template
|
||||
}
|
||||
|
||||
|
||||
extension Loader {
|
||||
func loadTemplate(names: [String]) throws -> Template {
|
||||
for name in names {
|
||||
do {
|
||||
return try loadTemplate(name: name)
|
||||
} catch is TemplateDoesNotExist {
|
||||
continue
|
||||
} catch {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
throw TemplateDoesNotExist(templateNames: names, loader: self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// A class for loading a template from disk
|
||||
public class FileSystemLoader: Loader, CustomStringConvertible {
|
||||
public let paths: [Path]
|
||||
|
||||
public init(paths: [Path]) {
|
||||
self.paths = paths
|
||||
}
|
||||
|
||||
public init(bundle: [Bundle]) {
|
||||
self.paths = bundle.map {
|
||||
return Path($0.bundlePath)
|
||||
}
|
||||
}
|
||||
|
||||
public var description: String {
|
||||
return "FileSystemLoader(\(paths))"
|
||||
}
|
||||
|
||||
public func loadTemplate(name: String) throws -> Template {
|
||||
for path in paths {
|
||||
let templatePath = try path.safeJoin(path: Path(name))
|
||||
|
||||
if !templatePath.exists {
|
||||
continue
|
||||
}
|
||||
|
||||
return try Template(path: templatePath)
|
||||
}
|
||||
|
||||
throw TemplateDoesNotExist(templateNames: [name], loader: self)
|
||||
}
|
||||
|
||||
public func loadTemplate(names: [String]) throws -> Template {
|
||||
for path in paths {
|
||||
for templateName in names {
|
||||
let templatePath = try path.safeJoin(path: Path(templateName))
|
||||
|
||||
if templatePath.exists {
|
||||
return try Template(path: templatePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw TemplateDoesNotExist(templateNames: names, loader: self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension Path {
|
||||
func safeJoin(path: Path) throws -> Path {
|
||||
let newPath = self + path
|
||||
|
||||
if !newPath.absolute().description.hasPrefix(absolute().description) {
|
||||
throw SuspiciousFileOperation(basePath: self, path: newPath)
|
||||
}
|
||||
|
||||
return newPath
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SuspiciousFileOperation: Error {
|
||||
let basePath: Path
|
||||
let path: Path
|
||||
|
||||
init(basePath: Path, path: Path) {
|
||||
self.basePath = basePath
|
||||
self.path = path
|
||||
}
|
||||
|
||||
var description: String {
|
||||
return "Path `\(path)` is located outside of base path `\(basePath)`"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user