Skip to content

Commit

Permalink
Added the option to throw when a variable used in the template is not…
Browse files Browse the repository at this point in the history
… found in the context
  • Loading branch information
acecilia committed Dec 26, 2019
1 parent 5b2d5dc commit 6f6a983
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ _None_
, i.e. `myfilter = "uppercase"` and then use it to invoke this filter with `{{ string|filter:myfilter }}`.
[Ilya Puchka](https://github.com/ilyapuchka)
[#203](https://github.com/stencilproject/Stencil/pull/203)
- Added option to throw when a variable used in a template could not be resolved.
[Andres Cecilia Luque](https://github.com/acecilia)
[#289](https://github.com/stencilproject/Stencil/pull/289)

### Deprecations

Expand Down
3 changes: 3 additions & 0 deletions Sources/Environment.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
public struct Environment {
public let templateClass: Template.Type
public var extensions: [Extension]
public let throwOnUnresolvedVariable: Bool

public var loader: Loader?

public init(loader: Loader? = nil,
extensions: [Extension] = [],
throwOnUnresolvedVariable: Bool = false,
templateClass: Template.Type = Template.self) {

self.templateClass = templateClass
self.loader = loader
self.extensions = extensions + [DefaultExtension()]
self.throwOnUnresolvedVariable = throwOnUnresolvedVariable
}

public func loadTemplate(name: String) throws -> Template {
Expand Down
8 changes: 7 additions & 1 deletion Sources/Variable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,16 @@ class FilterExpression: Resolvable {
func resolve(_ context: Context) throws -> Any? {
let result = try variable.resolve(context)

return try filters.reduce(result) { value, filter in
let filteredResult = try filters.reduce(result) { value, filter in
let arguments = try filter.1.map { try $0.resolve(context) }
return try filter.0.invoke(value: value, arguments: arguments, context: context)
}

if filteredResult == nil, context.environment.throwOnUnresolvedVariable {
throw TemplateSyntaxError("Variable '\(variable.variable)' could not be resolved")
}

return filteredResult
}
}

Expand Down
18 changes: 17 additions & 1 deletion Tests/StencilTests/EnvironmentSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,23 @@ final class EnvironmentTests: XCTestCase {
}
}

func testUnresolvedVariable() {
self.template = Template(templateString: "Hello {{ name }}")

it("can render a variable not defined in the context and throwing is disabled") {
self.environment = Environment()
let result = try self.environment.render(template: self.template, context: [:])
try expect(result) == "Hello "
}

it("throws when a variable is not defined in the context and throwing is enabled") {
self.environment = Environment(throwOnUnresolvedVariable: true)
try self.expectError(context: [:], reason: "Variable 'name' could not be resolved", token: "name")
}
}

private func expectError(
context: [String: Any] = ["names": ["Bob", "Alice"], "name": "Bob"],
reason: String,
token: String,
file: String = #file,
Expand All @@ -192,7 +208,7 @@ final class EnvironmentTests: XCTestCase {
let expectedError = expectedSyntaxError(token: token, template: template, description: reason)

let error = try expect(
self.environment.render(template: self.template, context: ["names": ["Bob", "Alice"], "name": "Bob"]),
self.environment.render(template: self.template, context: context),
file: file,
line: line,
function: function
Expand Down

0 comments on commit 6f6a983

Please sign in to comment.