Skip to content

Commit

Permalink
Merge pull request #103 from vapor/template-kit-gm
Browse files Browse the repository at this point in the history
templatekit 1.0.0 gm updates
  • Loading branch information
tanner0101 authored Apr 10, 2018
2 parents 3e60273 + 58936ce commit 8cc35dc
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 52 deletions.
65 changes: 27 additions & 38 deletions Sources/Leaf/Parser/LeafParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -156,24 +156,23 @@ extension TemplateByteScanner {
case Data(bytes: [.forwardSlash, .forwardSlash]), Data(bytes: [.forwardSlash, .asterisk]):
break
default:
throw TemplateError.parse(reason: "Invalid tag name", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "Invalid tag name", source: makeSource(using: start))
}
}

// Extract the tag params.
let params: [TemplateSyntax]
guard let name = String(data: id, encoding: .utf8) else {
throw TemplateError.parse(reason: "Invalid UTF-8 string", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "Invalid UTF-8 string", source: makeSource(using: start))
}

switch name {
case "for":
try expect(.leftParenthesis)
if peek() == .space {
throw TemplateError.parse(
throw TemplateKitError(identifier: "parse",
reason: "Whitespace not allowed before key in 'for' tag.",
template: makeSource(using: start),
source: .capture()
source: makeSource(using: start)
)
}
let key = try extractIdentifier()
Expand All @@ -182,44 +181,34 @@ extension TemplateByteScanner {
try expect(.n)
try expect(.space)
guard let val = try extractParameter() else {
throw TemplateError.parse(reason: "Parameter required after `in` in for-loop", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "Parameter required after `in` in for-loop", source: makeSource(using: start))
}

switch val.type {
case .identifier, .tag:
break
default:
throw TemplateError.parse(reason: "Identifier or tag required", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "Identifier or tag required", source: makeSource(using: start))
}

if peek(by: -1) == .space {
throw TemplateError.parse(
throw TemplateKitError(identifier: "parse",
reason: "Whitespace not allowed after value in 'for' tag.",
template: makeSource(using: start),
source: .capture()
source: makeSource(using: start)
)
}
try expect(.rightParenthesis)

guard case .identifier(let name) = key.type else {
throw TemplateError.parse(reason: "Invalid key type in for-loop", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "Invalid key type in for-loop", source: makeSource(using: start))
}

guard name.path.count == 1 else {
throw TemplateError.parse(reason: "One key required in for-loop", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "One key required in for-loop", source: makeSource(using: start))
}

guard let data = name.path[0].stringValue.data(using: .utf8) else {
throw TemplateError.parse(reason: "Invalid UTF-8 string", template: makeSource(using: start), source: .capture())
}

let raw = TemplateSyntax(
type: .raw(TemplateRaw(data: data)),
source: key.source
)

let keyConstant = TemplateSyntax(
type: .constant(.string([raw])),
type: .constant(.string(name.path[0].stringValue)),
source: key.source
)

Expand Down Expand Up @@ -285,7 +274,7 @@ extension TemplateByteScanner {
switch name {
case "if":
guard params.count == 1 else {
throw TemplateError.parse(reason: "One parameter required for if tag.", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "One parameter required for if tag.", source: makeSource(using: start))
}

let cond = try TemplateConditional(
Expand All @@ -296,13 +285,13 @@ extension TemplateByteScanner {
type = .conditional(cond)
case "embed":
guard params.count == 1 else {
throw TemplateError.parse(reason: "One parameter required for embed tag.", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "One parameter required for embed tag.", source: makeSource(using: start))
}
let embed = TemplateEmbed(path: params[0])
type = .embed(embed)
case "for":
guard params.count == 2 else {
throw TemplateError.parse(reason: "Two parameters required for for-loop.", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "Two parameters required for for-loop.", source: makeSource(using: start))
}
let iterator = TemplateIterator(key: params[1], data: params[0], body: body ?? [])
type = .iterator(iterator)
Expand Down Expand Up @@ -405,7 +394,7 @@ extension TemplateByteScanner {
try extractSpaces()

guard params.count == 1 else {
throw TemplateError.parse(reason: "One parameter required for else tag.", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "One parameter required for else tag.", source: makeSource(using: start))
}

return try TemplateConditional(
Expand Down Expand Up @@ -581,16 +570,16 @@ extension TemplateByteScanner {

let bytes = data[start.offset..<offset]
guard let string = String(data: bytes, encoding: .utf8) else {
throw TemplateError.parse(reason: "Invalid UTF8 string", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "Invalid UTF8 string", source: makeSource(using: start))
}
if bytes.contains(.period) {
guard let double = Double(string) else {
throw TemplateError.parse(reason: "Invalid double", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "Invalid double", source: makeSource(using: start))
}
return .double(double)
} else {
guard let int = Int(string) else {
throw TemplateError.parse(reason: "Invalid integer", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "Invalid integer", source: makeSource(using: start))
}
return .int(int)
}
Expand All @@ -603,7 +592,7 @@ extension TemplateByteScanner {
let start = makeSourceStart()

guard let byte = peek() else {
throw TemplateError.parse(reason: "Unexpected EOF", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "Unexpected EOF", source: makeSource(using: start))
}

let kind: TemplateSyntaxType
Expand All @@ -617,14 +606,14 @@ extension TemplateByteScanner {
try expect(.quote)
let ast = try LeafParser().parse(scanner: TemplateByteScanner(data: bytes, file: file))
kind = .constant(
.string(ast)
.interpolated(ast)
)
case .exclamation:
try expect(.exclamation)
guard let param = try extractParameter() else {
throw TemplateError.parse(reason: "Parameter required after not `!`", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "Parameter required after not `!`", source: makeSource(using: start))
}
kind = .expression(.prefix(operator: .not, right: param))
kind = .expression(.prefix(op: .not, right: param))
default:
if byte.isDigit || byte == .hyphen {
// constant number
Expand Down Expand Up @@ -652,7 +641,7 @@ extension TemplateByteScanner {

try extractSpaces()

let op: ExpressionInfixOperator?
let op: TemplateExpression.InfixOperator?

if let byte = peek() {
switch byte {
Expand Down Expand Up @@ -700,12 +689,12 @@ extension TemplateByteScanner {
}

guard let right = try extractParameter() else {
throw TemplateError.parse(reason: "Parameter required after infix operator", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "Parameter required after infix operator", source: makeSource(using: start))
}

// FIXME: allow for () grouping and proper PEMDAS
let exp: TemplateSyntaxType = .expression(.infix(
operator: op,
op: op,
left: syntax,
right: right
))
Expand All @@ -729,13 +718,13 @@ extension TemplateByteScanner {
let start = makeSourceStart()

guard let byte = peek() else {
throw TemplateError.parse(reason: "Unexpected EOF", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "Unexpected EOF", source: makeSource(using: start))
}

guard byte == expect else {
let expectedChar = Character(Unicode.Scalar.init(expect))
let char = Character(Unicode.Scalar.init(byte))
throw TemplateError.parse(reason: "Expected '\(expectedChar)' got '\(char)'", template: makeSource(using: start), source: .capture())
throw TemplateKitError(identifier: "parse", reason: "Expected '\(expectedChar)' got '\(char)'", source: makeSource(using: start))
}

try requirePop()
Expand Down
10 changes: 5 additions & 5 deletions Tests/LeafTests/LeafTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ class LeafTests: XCTestCase {
}

let context = Context(categories: [])
let data = try TemplateDataEncoder().encode(context)
let data = try TemplateDataEncoder().testEncode(context)
try XCTAssertEqual(renderer.testRender(template, data), expected)

}
Expand All @@ -348,12 +348,12 @@ class LeafTests: XCTestCase {
}

let context = Stuff(title: "foo")
let data = try TemplateDataEncoder().encode(context)
let data = try TemplateDataEncoder().testEncode(context)
try XCTAssertEqual(renderer.testRender(template, data), expected)
}

func testInvalidForSyntax() throws {
let data = try TemplateDataEncoder().encode(["names": ["foo"]])
let data = try TemplateDataEncoder().testEncode(["names": ["foo"]])
do {
_ = try renderer.testRender("#for( name in names) {}", data)
XCTFail("Whitespace not allowed here")
Expand Down Expand Up @@ -392,7 +392,7 @@ class LeafTests: XCTestCase {
<title>Home</title>
<body><p>bar</p></title>
"""
let data = try TemplateDataEncoder().encode(["foo": "bar"])
let data = try TemplateDataEncoder().testEncode(["foo": "bar"])
try XCTAssertEqual(renderer.testRender(home, data), expected)
}

Expand All @@ -410,7 +410,7 @@ class LeafTests: XCTestCase {
ziz: index=1 last=false first=false
vapor: index=2 last=true first=false
"""
let data = try TemplateDataEncoder().encode([
let data = try TemplateDataEncoder().testEncode([
"names": ["tanner", "ziz", "vapor"]
])
try XCTAssertEqual(renderer.testRender(template, data), expected)
Expand Down
25 changes: 16 additions & 9 deletions Tests/LeafTests/TemplateDataEncoderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ import XCTest
class TemplateDataEncoderTests: XCTestCase {
func testString() {
let data = "hello"
try XCTAssertEqual(TemplateDataEncoder().encode(data), .string(data))
try XCTAssertEqual(TemplateDataEncoder().testEncode(data), .string(data))
}

func testDouble() {
let data: Double = 3.14
try XCTAssertEqual(TemplateDataEncoder().encode(data), .double(data))
try XCTAssertEqual(TemplateDataEncoder().testEncode(data), .double(data))
}

func testDictionary() {
let data: [String: String] = ["string": "hello", "foo": "3.14"]
try XCTAssertEqual(TemplateDataEncoder().encode(data), .dictionary([
try XCTAssertEqual(TemplateDataEncoder().testEncode(data), .dictionary([
"string": .string("hello"),
"foo": .string("3.14")
]))
Expand All @@ -28,7 +28,7 @@ class TemplateDataEncoderTests: XCTestCase {
"a": ["string": "hello", "foo": "3.14"],
"b": ["greeting": "hey", "foo": "3.15"]
]
try XCTAssertEqual(TemplateDataEncoder().encode(data), .dictionary([
try XCTAssertEqual(TemplateDataEncoder().testEncode(data), .dictionary([
"a": .dictionary([
"string": .string("hello"),
"foo": .string("3.14")
Expand All @@ -42,21 +42,21 @@ class TemplateDataEncoderTests: XCTestCase {

func testArray() {
let data: [String] = ["string", "hello", "foo", "3.14"]
try XCTAssertEqual(TemplateDataEncoder().encode(data), .array([
try XCTAssertEqual(TemplateDataEncoder().testEncode(data), .array([
.string("string"), .string("hello"), .string("foo"), .string("3.14")
]))
}

func testNestedArray() {
let data: [[String]] = [["string"], ["hello", "foo"], ["3.14"]]
try XCTAssertEqual(TemplateDataEncoder().encode(data), .array([
try XCTAssertEqual(TemplateDataEncoder().testEncode(data), .array([
.array([.string("string")]), .array([.string("hello"), .string("foo")]), .array([.string("3.14")])
]))
}

func testEncodable() {
struct Hello: Encodable { var hello = "hello" }
try XCTAssertEqual(TemplateDataEncoder().encode(Hello()), .dictionary([
try XCTAssertEqual(TemplateDataEncoder().testEncode(Hello()), .dictionary([
"hello": .string("hello"),
]))
}
Expand All @@ -71,7 +71,7 @@ class TemplateDataEncoderTests: XCTestCase {
var fib: [Int] = [0, 1, 1, 2, 3, 5, 8, 13]
}

try XCTAssertEqual(TemplateDataEncoder().encode(Test()), .dictionary([
try XCTAssertEqual(TemplateDataEncoder().testEncode(Test()), .dictionary([
"string": .string("hello"),
"double": .double(3.14),
"int": .int(42),
Expand All @@ -95,7 +95,7 @@ class TemplateDataEncoderTests: XCTestCase {
}

let sub = Test()
try XCTAssertEqual(TemplateDataEncoder().encode(Test(sub: sub)), .dictionary([
try XCTAssertEqual(TemplateDataEncoder().testEncode(Test(sub: sub)), .dictionary([
"string": .string("hello"),
"double": .double(3.14),
"int": .int(42),
Expand All @@ -122,3 +122,10 @@ class TemplateDataEncoderTests: XCTestCase {
("testNestedEncodable", testNestedEncodable),
]
}


extension TemplateDataEncoder {
func testEncode<E>(_ encodable: E) throws -> TemplateData where E: Encodable {
return try encode(encodable, on: EmbeddedEventLoop()).wait()
}
}

0 comments on commit 8cc35dc

Please sign in to comment.