diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 7cddf30..434025a 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -8,16 +8,12 @@ concurrency: jobs: validate: - runs-on: macOS-latest + runs-on: ubuntu-latest timeout-minutes: 15 steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 1 - - name: Install Dependencies - run: | - brew install mint - mint install NickLockwood/SwiftFormat@0.53.10 --no-link - name: run script run: ./scripts/validate.sh diff --git a/.swift-format b/.swift-format new file mode 100644 index 0000000..bb3dcff --- /dev/null +++ b/.swift-format @@ -0,0 +1,63 @@ +{ + "version" : 1, + "indentation" : { + "spaces" : 4 + }, + "tabWidth" : 4, + "fileScopedDeclarationPrivacy" : { + "accessLevel" : "private" + }, + "spacesAroundRangeFormationOperators" : false, + "indentConditionalCompilationBlocks" : false, + "indentSwitchCaseLabels" : false, + "lineBreakAroundMultilineExpressionChainComponents" : false, + "lineBreakBeforeControlFlowKeywords" : false, + "lineBreakBeforeEachArgument" : true, + "lineBreakBeforeEachGenericRequirement" : true, + "lineLength" : 150, + "maximumBlankLines" : 1, + "respectsExistingLineBreaks" : true, + "prioritizeKeepingFunctionOutputTogether" : true, + "multiElementCollectionTrailingCommas" : true, + "rules" : { + "AllPublicDeclarationsHaveDocumentation" : false, + "AlwaysUseLiteralForEmptyCollectionInit" : false, + "AlwaysUseLowerCamelCase" : false, + "AmbiguousTrailingClosureOverload" : true, + "BeginDocumentationCommentWithOneLineSummary" : false, + "DoNotUseSemicolons" : true, + "DontRepeatTypeInStaticProperties" : true, + "FileScopedDeclarationPrivacy" : true, + "FullyIndirectEnum" : true, + "GroupNumericLiterals" : true, + "IdentifiersMustBeASCII" : true, + "NeverForceUnwrap" : false, + "NeverUseForceTry" : false, + "NeverUseImplicitlyUnwrappedOptionals" : false, + "NoAccessLevelOnExtensionDeclaration" : true, + "NoAssignmentInExpressions" : true, + "NoBlockComments" : true, + "NoCasesWithOnlyFallthrough" : true, + "NoEmptyTrailingClosureParentheses" : true, + "NoLabelsInCasePatterns" : true, + "NoLeadingUnderscores" : false, + "NoParensAroundConditions" : true, + "NoVoidReturnOnFunctionSignature" : true, + "OmitExplicitReturns" : true, + "OneCasePerLine" : true, + "OneVariableDeclarationPerLine" : true, + "OnlyOneTrailingClosureArgument" : true, + "OrderedImports" : true, + "ReplaceForEachWithForLoop" : true, + "ReturnVoidInsteadOfEmptyTuple" : true, + "UseEarlyExits" : false, + "UseExplicitNilCheckInConditions" : false, + "UseLetInEveryBoundCaseVariable" : false, + "UseShorthandTypeNames" : true, + "UseSingleLinePropertyGetter" : false, + "UseSynthesizedInitializer" : false, + "UseTripleSlashForDocumentationComments" : true, + "UseWhereClausesInForLoops" : false, + "ValidateDocumentationComments" : false + } +} diff --git a/.swiftformat b/.swiftformat deleted file mode 100644 index 14fb33f..0000000 --- a/.swiftformat +++ /dev/null @@ -1,26 +0,0 @@ -# Minimum swiftformat version ---minversion 0.53.10 - -# Swift version ---swiftversion 5.9 - -# file options ---exclude .build - -# rules ---disable redundantReturn, extensionAccessControl, typeSugar, conditionalAssignment, preferForLoop, redundantInternal, redundantStaticSelf - -# format options ---ifdef no-indent ---nospaceoperators ...,..< ---patternlet inline ---self insert ---stripunusedargs unnamed-only - -#--maxwidth 150 ---wraparguments before-first ---wrapparameters before-first ---wrapcollections before-first - -#file header -# --header "//===----------------------------------------------------------------------===//\n//\n// This source file is part of the Hummingbird server framework project\n//\n// Copyright (c) {created.year}-{year} the Hummingbird authors\n// Licensed under Apache License v2.0\n//\n// See LICENSE.txt for license information\n// See hummingbird/CONTRIBUTORS.txt for the list of Hummingbird authors\n//\n// SPDX-License-Identifier: Apache-2.0\n//\n//===----------------------------------------------------------------------===//" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 14b9831..8f5de31 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,4 +28,4 @@ The main development branch of the repository is `main`. ### Formatting -We use Nick Lockwood's SwiftFormat for formatting code. PRs will not be accepted if they haven't be formatted. The current version of SwiftFormat we are using is v0.53.10. +We use Apple's swift-format for formatting code. PRs will not be accepted if they haven't be formatted. \ No newline at end of file diff --git a/Package.swift b/Package.swift index b82f3be..8ea8bdf 100644 --- a/Package.swift +++ b/Package.swift @@ -7,7 +7,7 @@ let package = Package( name: "swift-mustache", platforms: [.macOS(.v10_15), .iOS(.v13), .tvOS(.v13), .watchOS(.v6)], products: [ - .library(name: "Mustache", targets: ["Mustache"]), + .library(name: "Mustache", targets: ["Mustache"]) ], dependencies: [], targets: [ diff --git a/Sources/Mustache/ContentType.swift b/Sources/Mustache/ContentType.swift index 96a159c..a0fae50 100644 --- a/Sources/Mustache/ContentType.swift +++ b/Sources/Mustache/ContentType.swift @@ -21,14 +21,14 @@ public protocol MustacheContentType: Sendable { /// Text content type where no character is escaped struct TextContentType: MustacheContentType { func escapeText(_ text: String) -> String { - return text + text } } /// HTML content where text is escaped for HTML output struct HTMLContentType: MustacheContentType { func escapeText(_ text: String) -> String { - return text.htmlEscape() + text.htmlEscape() } } @@ -39,7 +39,7 @@ struct HTMLContentType: MustacheContentType { /// with `MustacheContentTypes.register`. public enum MustacheContentTypes { static func get(_ name: String) -> MustacheContentType? { - return self.types[name] + self.types[name] } /// Register new content type diff --git a/Sources/Mustache/Context.swift b/Sources/Mustache/Context.swift index 21fe557..0783f0c 100644 --- a/Sources/Mustache/Context.swift +++ b/Sources/Mustache/Context.swift @@ -131,7 +131,7 @@ struct MustacheContext { /// return context with sequence info and sequence element added to stack func withContentType(_ contentType: MustacheContentType) -> MustacheContext { - return .init( + .init( stack: self.stack, sequenceContext: self.sequenceContext, indentation: self.indentation, diff --git a/Sources/Mustache/Lambda.swift b/Sources/Mustache/Lambda.swift index 86396f5..c236ed0 100644 --- a/Sources/Mustache/Lambda.swift +++ b/Sources/Mustache/Lambda.swift @@ -50,6 +50,6 @@ public struct MustacheLambda { } internal func callAsFunction(_ s: String) -> Any? { - return self.callback(s) + self.callback(s) } } diff --git a/Sources/Mustache/Parent.swift b/Sources/Mustache/Parent.swift index a542fd1..3b396ec 100644 --- a/Sources/Mustache/Parent.swift +++ b/Sources/Mustache/Parent.swift @@ -21,5 +21,5 @@ public protocol MustacheParent { /// Extend dictionary where the key is a string so that it uses the key values to access /// it values extension Dictionary: MustacheParent where Key == String { - public func child(named: String) -> Any? { return self[named] } + public func child(named: String) -> Any? { self[named] } } diff --git a/Sources/Mustache/Parser.swift b/Sources/Mustache/Parser.swift index a2c110e..790e987 100644 --- a/Sources/Mustache/Parser.swift +++ b/Sources/Mustache/Parser.swift @@ -38,7 +38,7 @@ struct Parser { self.position = string.startIndex } - var buffer: String { return self._storage.buffer } + var buffer: String { self._storage.buffer } private(set) var position: String.Index } @@ -59,7 +59,10 @@ extension Parser { /// - Returns: If current character was the one we expected mutating func read(_ char: Character) throws -> Bool { let c = try character() - guard c == char else { unsafeRetreat(); return false } + guard c == char else { + unsafeRetreat() + return false + } return true } @@ -84,7 +87,10 @@ extension Parser { /// - Returns: If current character is in character set mutating func read(_ characterSet: Set) throws -> Bool { let c = try character() - guard characterSet.contains(c) else { unsafeRetreat(); return false } + guard characterSet.contains(c) else { + unsafeRetreat() + return false + } return true } @@ -236,7 +242,7 @@ extension Parser { @discardableResult mutating func read(while: Character) -> Int { var count = 0 while !self.reachedEnd(), - unsafeCurrent() == `while` + unsafeCurrent() == `while` { unsafeAdvance() count += 1 @@ -250,7 +256,7 @@ extension Parser { @discardableResult mutating func read(while keyPath: KeyPath) -> Substring { let startIndex = self.position while !self.reachedEnd(), - unsafeCurrent()[keyPath: keyPath] + unsafeCurrent()[keyPath: keyPath] { unsafeAdvance() } @@ -263,7 +269,7 @@ extension Parser { @discardableResult mutating func read(while cb: (Character) -> Bool) -> Substring { let startIndex = self.position while !self.reachedEnd(), - cb(unsafeCurrent()) + cb(unsafeCurrent()) { unsafeAdvance() } @@ -276,7 +282,7 @@ extension Parser { @discardableResult mutating func read(while characterSet: Set) -> Substring { let startIndex = self.position while !self.reachedEnd(), - characterSet.contains(unsafeCurrent()) + characterSet.contains(unsafeCurrent()) { unsafeAdvance() } @@ -286,13 +292,13 @@ extension Parser { /// Return whether we have reached the end of the buffer /// - Returns: Have we reached the end func reachedEnd() -> Bool { - return self.position == self.buffer.endIndex + self.position == self.buffer.endIndex } /// Return whether we are at the start of the buffer /// - Returns: Are we are the start func atStart() -> Bool { - return self.position == self.buffer.startIndex + self.position == self.buffer.startIndex } } @@ -378,7 +384,7 @@ extension Parser { // unsafe versions without checks extension Parser { func unsafeCurrent() -> Character { - return self.buffer[self.position] + self.buffer[self.position] } mutating func unsafeAdvance() { diff --git a/Sources/Mustache/Template+Parser.swift b/Sources/Mustache/Template+Parser.swift index e6517e3..3aaed19 100644 --- a/Sources/Mustache/Template+Parser.swift +++ b/Sources/Mustache/Template+Parser.swift @@ -327,7 +327,8 @@ extension MustacheTemplate { } if self.isStandalone(&parser, state: state) { setNewLine = true - } else if whiteSpaceBefore.count > 0 {} + } else if whiteSpaceBefore.count > 0 { + } let sectionTemplate = try parse(&parser, state: state.withSectionName(name, newLine: setNewLine)) tokens.append(.blockExpansion(name: name, default: sectionTemplate, indentation: String(whiteSpaceBefore))) whiteSpaceBefore = "" @@ -415,7 +416,7 @@ extension MustacheTemplate { nameParser.unsafeAdvance() // We need to have a `)` for each transform that we've parsed guard nameParser.read(while: ")") + 1 == existing.count, - nameParser.reachedEnd() + nameParser.reachedEnd() else { throw Error.unfinishedName } @@ -512,7 +513,7 @@ extension MustacheTemplate { } static func isStandalone(_ parser: inout Parser, state: ParserState) -> Bool { - return state.newLine && self.hasLineFinished(&parser) + state.newLine && self.hasLineFinished(&parser) } private static let sectionNameCharsWithoutBrackets = Set("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_?*") diff --git a/Sources/Mustache/Template+Render.swift b/Sources/Mustache/Template+Render.swift index 4dd5c7b..e0b476b 100644 --- a/Sources/Mustache/Template+Render.swift +++ b/Sources/Mustache/Template+Render.swift @@ -285,7 +285,7 @@ extension MustacheTemplate { // run transform on the current child for transform in transforms.reversed() { if let runnable = child as? MustacheTransformable, - let transformed = runnable.transform(transform) + let transformed = runnable.transform(transform) { child = transformed continue diff --git a/Sources/Mustache/Transform.swift b/Sources/Mustache/Transform.swift index a6f8f85..4e5ea1e 100644 --- a/Sources/Mustache/Transform.swift +++ b/Sources/Mustache/Transform.swift @@ -31,13 +31,13 @@ public protocol MustacheTransformable { func transform(_ name: String) -> Any? } -public extension StringProtocol { +extension StringProtocol { /// Transform String/Substring /// /// Transforms available are `capitalized`, `lowercased`, `uppercased` and `reversed` /// - Parameter name: transform name /// - Returns: Result - func transform(_ name: String) -> Any? { + public func transform(_ name: String) -> Any? { switch name { case "empty": return isEmpty @@ -209,13 +209,13 @@ extension Dictionary: ComparableSequence where Key: Comparable { } } -public extension FixedWidthInteger { +extension FixedWidthInteger { /// Transform FixedWidthInteger /// /// Transforms available are `plusone`, `minusone`, `odd`, `even` /// - Parameter name: transform name /// - Returns: Result - func transform(_ name: String) -> Any? { + public func transform(_ name: String) -> Any? { switch name { case "equalzero": return self == 0 diff --git a/Tests/MustacheTests/ErrorTests.swift b/Tests/MustacheTests/ErrorTests.swift index 42ccb4b..a9bb51c 100644 --- a/Tests/MustacheTests/ErrorTests.swift +++ b/Tests/MustacheTests/ErrorTests.swift @@ -17,11 +17,15 @@ import XCTest final class ErrorTests: XCTestCase { func testSectionCloseNameIncorrect() { - XCTAssertThrowsError(try MustacheTemplate(string: """ - {{#test}} - {{.}} - {{/test2}} - """)) { error in + XCTAssertThrowsError( + try MustacheTemplate( + string: """ + {{#test}} + {{.}} + {{/test2}} + """ + ) + ) { error in switch error { case let error as MustacheTemplate.ParserError: XCTAssertEqual(error.error as? MustacheTemplate.Error, .sectionCloseNameIncorrect) @@ -36,11 +40,15 @@ final class ErrorTests: XCTestCase { } func testUnfinishedName() { - XCTAssertThrowsError(try MustacheTemplate(string: """ - {{#test}} - {{name} - {{/test2}} - """)) { error in + XCTAssertThrowsError( + try MustacheTemplate( + string: """ + {{#test}} + {{name} + {{/test2}} + """ + ) + ) { error in switch error { case let error as MustacheTemplate.ParserError: XCTAssertEqual(error.error as? MustacheTemplate.Error, .unfinishedName) @@ -55,10 +63,14 @@ final class ErrorTests: XCTestCase { } func testExpectedSectionEnd() { - XCTAssertThrowsError(try MustacheTemplate(string: """ - {{#test}} - {{.}} - """)) { error in + XCTAssertThrowsError( + try MustacheTemplate( + string: """ + {{#test}} + {{.}} + """ + ) + ) { error in switch error { case let error as MustacheTemplate.ParserError: XCTAssertEqual(error.error as? MustacheTemplate.Error, .expectedSectionEnd) @@ -73,11 +85,15 @@ final class ErrorTests: XCTestCase { } func testInvalidSetDelimiter() { - XCTAssertThrowsError(try MustacheTemplate(string: """ - {{=<% %>=}} - <%.%> - <%={{}}=%> - """)) { error in + XCTAssertThrowsError( + try MustacheTemplate( + string: """ + {{=<% %>=}} + <%.%> + <%={{}}=%> + """ + ) + ) { error in switch error { case let error as MustacheTemplate.ParserError: XCTAssertEqual(error.error as? MustacheTemplate.Error, .invalidSetDelimiter) diff --git a/Tests/MustacheTests/LibraryTests.swift b/Tests/MustacheTests/LibraryTests.swift index c2cc38f..7c9f370 100644 --- a/Tests/MustacheTests/LibraryTests.swift +++ b/Tests/MustacheTests/LibraryTests.swift @@ -12,9 +12,10 @@ // //===----------------------------------------------------------------------===// -@testable import Mustache import XCTest +@testable import Mustache + final class LibraryTests: XCTestCase { func testDirectoryLoad() async throws { let fs = FileManager() @@ -54,11 +55,13 @@ final class LibraryTests: XCTestCase { let mustache = Data("{{#value}}{{.}}{{/value}}".utf8) try mustache.write(to: URL(fileURLWithPath: "templates/test.mustache")) defer { XCTAssertNoThrow(try fs.removeItem(atPath: "templates/test.mustache")) } - let mustache2 = Data(""" - {{#test}} - {{{name}} - {{/test2}} - """.utf8) + let mustache2 = Data( + """ + {{#test}} + {{{name}} + {{/test2}} + """.utf8 + ) try mustache2.write(to: URL(fileURLWithPath: "templates/error.mustache")) defer { XCTAssertNoThrow(try fs.removeItem(atPath: "templates/error.mustache")) } diff --git a/Tests/MustacheTests/PartialTests.swift b/Tests/MustacheTests/PartialTests.swift index c8496c6..4d33abf 100644 --- a/Tests/MustacheTests/PartialTests.swift +++ b/Tests/MustacheTests/PartialTests.swift @@ -12,120 +12,156 @@ // //===----------------------------------------------------------------------===// -@testable import Mustache import XCTest +@testable import Mustache + final class PartialTests: XCTestCase { /// Testing partials func testMustacheManualExample9() throws { - let template = try MustacheTemplate(string: """ -

Names

- {{#names}} - {{> user}} - {{/names}} - """) - let template2 = try MustacheTemplate(string: """ - {{.}} + let template = try MustacheTemplate( + string: """ +

Names

+ {{#names}} + {{> user}} + {{/names}} + """ + ) + let template2 = try MustacheTemplate( + string: """ + {{.}} - """) + """ + ) let library = MustacheLibrary(templates: ["base": template, "user": template2]) let object: [String: Any] = ["names": ["john", "adam", "claire"]] - XCTAssertEqual(library.render(object, withTemplate: "base"), """ -

Names

- john - adam - claire + XCTAssertEqual( + library.render(object, withTemplate: "base"), + """ +

Names

+ john + adam + claire - """) + """ + ) } /// Test where last line of partial generates no content. It should not add a /// tab either func testPartialEmptyLineTabbing() throws { - let template = try MustacheTemplate(string: """ -

Names

- {{#names}} - {{> user}} - {{/names}} - Text after + let template = try MustacheTemplate( + string: """ +

Names

+ {{#names}} + {{> user}} + {{/names}} + Text after - """) - let template2 = try MustacheTemplate(string: """ - {{^empty(.)}} - {{.}} - {{/empty(.)}} - {{#empty(.)}} - empty - {{/empty(.)}} + """ + ) + let template2 = try MustacheTemplate( + string: """ + {{^empty(.)}} + {{.}} + {{/empty(.)}} + {{#empty(.)}} + empty + {{/empty(.)}} - """) + """ + ) var library = MustacheLibrary() library.register(template, named: "base") library.register(template2, named: "user") let object: [String: Any] = ["names": ["john", "adam", "claire"]] - XCTAssertEqual(library.render(object, withTemplate: "base"), """ -

Names

- john - adam - claire - Text after + XCTAssertEqual( + library.render(object, withTemplate: "base"), + """ +

Names

+ john + adam + claire + Text after - """) + """ + ) } func testTrailingNewLines() throws { - let template1 = try MustacheTemplate(string: """ - {{> withNewLine }} - >> {{> withNewLine }} - [ {{> withNewLine }} ] - """) - let template2 = try MustacheTemplate(string: """ - {{> withoutNewLine }} - >> {{> withoutNewLine }} - [ {{> withoutNewLine }} ] - """) - let withNewLine = try MustacheTemplate(string: """ - {{#things}}{{.}}, {{/things}} + let template1 = try MustacheTemplate( + string: """ + {{> withNewLine }} + >> {{> withNewLine }} + [ {{> withNewLine }} ] + """ + ) + let template2 = try MustacheTemplate( + string: """ + {{> withoutNewLine }} + >> {{> withoutNewLine }} + [ {{> withoutNewLine }} ] + """ + ) + let withNewLine = try MustacheTemplate( + string: """ + {{#things}}{{.}}, {{/things}} - """) + """ + ) let withoutNewLine = try MustacheTemplate(string: "{{#things}}{{.}}, {{/things}}") - let library = MustacheLibrary(templates: ["base1": template1, "base2": template2, "withNewLine": withNewLine, "withoutNewLine": withoutNewLine]) + let library = MustacheLibrary(templates: [ + "base1": template1, "base2": template2, "withNewLine": withNewLine, "withoutNewLine": withoutNewLine, + ]) let object = ["things": [1, 2, 3, 4, 5]] - XCTAssertEqual(library.render(object, withTemplate: "base1"), """ - 1, 2, 3, 4, 5, - >> 1, 2, 3, 4, 5, + XCTAssertEqual( + library.render(object, withTemplate: "base1"), + """ + 1, 2, 3, 4, 5, + >> 1, 2, 3, 4, 5, - [ 1, 2, 3, 4, 5, - ] - """) - XCTAssertEqual(library.render(object, withTemplate: "base2"), """ - 1, 2, 3, 4, 5, >> 1, 2, 3, 4, 5, - [ 1, 2, 3, 4, 5, ] - """) + [ 1, 2, 3, 4, 5, + ] + """ + ) + XCTAssertEqual( + library.render(object, withTemplate: "base2"), + """ + 1, 2, 3, 4, 5, >> 1, 2, 3, 4, 5, + [ 1, 2, 3, 4, 5, ] + """ + ) } /// Testing dynamic partials func testDynamicPartials() throws { - let template = try MustacheTemplate(string: """ -

Names

- {{partial}} - """) - let template2 = try MustacheTemplate(string: """ - {{#names}} - {{.}} - {{/names}} - """) + let template = try MustacheTemplate( + string: """ +

Names

+ {{partial}} + """ + ) + let template2 = try MustacheTemplate( + string: """ + {{#names}} + {{.}} + {{/names}} + """ + ) let library = MustacheLibrary(templates: ["base": template]) let object: [String: Any] = ["names": ["john", "adam", "claire"], "partial": template2] - XCTAssertEqual(library.render(object, withTemplate: "base"), """ -

Names

- john - adam - claire + XCTAssertEqual( + library.render(object, withTemplate: "base"), + """ +

Names

+ john + adam + claire - """) + """ + ) } /// test inheritance @@ -163,15 +199,18 @@ final class PartialTests: XCTestCase { """, named: "mypage" ) - XCTAssertEqual(library.render({}, withTemplate: "mypage")!, """ - - - My page title - -

Hello world

- + XCTAssertEqual( + library.render({}, withTemplate: "mypage")!, + """ + + + My page title + +

Hello world

+ - """) + """ + ) } func testInheritanceIndentation() throws { @@ -194,11 +233,14 @@ final class PartialTests: XCTestCase { """, named: "template" ) - XCTAssertEqual(library.render({}, withTemplate: "template"), """ - Hi, - one - two + XCTAssertEqual( + library.render({}, withTemplate: "template"), + """ + Hi, + one + two - """) + """ + ) } } diff --git a/Tests/MustacheTests/SpecTests.swift b/Tests/MustacheTests/SpecTests.swift index 122a463..d93a580 100644 --- a/Tests/MustacheTests/SpecTests.swift +++ b/Tests/MustacheTests/SpecTests.swift @@ -50,7 +50,8 @@ extension AnyDecodable { self.init(dictionary.mapValues { $0.value }) } else { throw DecodingError.dataCorruptedError( - in: container, debugDescription: "AnyDecodable value cannot be decoded" + in: container, + debugDescription: "AnyDecodable value cannot be decoded" ) } } @@ -102,7 +103,8 @@ final class MustacheSpecTests: XCTestCase { \(result ?? "nil") expected: \(test.expected) - """) + """ + ) } } } @@ -113,7 +115,8 @@ final class MustacheSpecTests: XCTestCase { func testSpec(name: String, ignoring: [String] = []) async throws { let url = URL( - string: "https://raw.githubusercontent.com/mustache/spec/master/specs/\(name).json")! + string: "https://raw.githubusercontent.com/mustache/spec/master/specs/\(name).json" + )! try await testSpec(url: url, ignoring: ignoring) } @@ -135,7 +138,8 @@ final class MustacheSpecTests: XCTestCase { func testSpec(name: String, only: [String]) async throws { let url = URL( - string: "https://raw.githubusercontent.com/mustache/spec/master/specs/\(name).json")! + string: "https://raw.githubusercontent.com/mustache/spec/master/specs/\(name).json" + )! try await testSpec(url: url, only: only) } @@ -161,7 +165,12 @@ final class MustacheSpecTests: XCTestCase { "Interpolation": MustacheLambda { "world" }, "Interpolation - Expansion": MustacheLambda { "{{planet}}" }, "Interpolation - Alternate Delimiters": MustacheLambda { "|planet| => {{planet}}" }, - "Interpolation - Multiple Calls": MustacheLambda { return MustacheLambda { g += 1; return g }}, + "Interpolation - Multiple Calls": MustacheLambda { + return MustacheLambda { + g += 1 + return g + } + }, "Escaping": MustacheLambda { ">" }, "Section": MustacheLambda { text in text == "{{x}}" ? "yes" : "no" }, "Section - Expansion": MustacheLambda { text in text + "{{planet}}" + text }, diff --git a/Tests/MustacheTests/TemplateParserTests.swift b/Tests/MustacheTests/TemplateParserTests.swift index 1561fce..9e022c4 100644 --- a/Tests/MustacheTests/TemplateParserTests.swift +++ b/Tests/MustacheTests/TemplateParserTests.swift @@ -12,9 +12,10 @@ // //===----------------------------------------------------------------------===// -@testable import Mustache import XCTest +@testable import Mustache + final class TemplateParserTests: XCTestCase { func testText() throws { let template = try MustacheTemplate(string: "test template") diff --git a/Tests/MustacheTests/TemplateRendererTests.swift b/Tests/MustacheTests/TemplateRendererTests.swift index eb233b7..14c3436 100644 --- a/Tests/MustacheTests/TemplateRendererTests.swift +++ b/Tests/MustacheTests/TemplateRendererTests.swift @@ -141,81 +141,103 @@ final class TemplateRendererTests: XCTestCase { /// variables func testMustacheManualVariables() throws { - let template = try MustacheTemplate(string: """ - Hello {{name}} - You have just won {{value}} dollars! - {{#in_ca}} - Well, {{taxed_value}} dollars, after taxes. - {{/in_ca}} - """) + let template = try MustacheTemplate( + string: """ + Hello {{name}} + You have just won {{value}} dollars! + {{#in_ca}} + Well, {{taxed_value}} dollars, after taxes. + {{/in_ca}} + """ + ) let object: [String: Any] = ["name": "Chris", "value": 10000, "taxed_value": 10000 - (10000 * 0.4), "in_ca": true] - XCTAssertEqual(template.render(object), """ - Hello Chris - You have just won 10000 dollars! - Well, 6000.0 dollars, after taxes. + XCTAssertEqual( + template.render(object), + """ + Hello Chris + You have just won 10000 dollars! + Well, 6000.0 dollars, after taxes. - """) + """ + ) } /// test escaped and unescaped text func testMustacheManualEscapedText() throws { - let template = try MustacheTemplate(string: """ - *{{name}} - *{{age}} - *{{company}} - *{{{company}}} - """) + let template = try MustacheTemplate( + string: """ + *{{name}} + *{{age}} + *{{company}} + *{{{company}}} + """ + ) let object: [String: Any] = ["name": "Chris", "company": "GitHub"] - XCTAssertEqual(template.render(object), """ - *Chris - * - *<b>GitHub</b> - *GitHub - """) + XCTAssertEqual( + template.render(object), + """ + *Chris + * + *<b>GitHub</b> + *GitHub + """ + ) } /// test dotted names func test_MustacheManualDottedNames() throws { - let template = try MustacheTemplate(string: """ - * {{client.name}} - * {{age}} - * {{client.company.name}} - * {{{company.name}}} - """) + let template = try MustacheTemplate( + string: """ + * {{client.name}} + * {{age}} + * {{client.company.name}} + * {{{company.name}}} + """ + ) let object: [String: Any] = [ "client": ( name: "Chris & Friends", age: 50 ), "company": [ - "name": "GitHub", + "name": "GitHub" ], ] - XCTAssertEqual(template.render(object), """ - * Chris & Friends - * - * - * GitHub - """) + XCTAssertEqual( + template.render(object), + """ + * Chris & Friends + * + * + * GitHub + """ + ) } /// test implicit operator func testMustacheManualImplicitOperator() throws { - let template = try MustacheTemplate(string: """ - * {{.}} - """) + let template = try MustacheTemplate( + string: """ + * {{.}} + """ + ) let object = "Hello!" - XCTAssertEqual(template.render(object), """ - * Hello! - """) + XCTAssertEqual( + template.render(object), + """ + * Hello! + """ + ) } /// test lambda func test_MustacheManualLambda() throws { - let template = try MustacheTemplate(string: """ - * {{time.hour}} - * {{today}} - """) + let template = try MustacheTemplate( + string: """ + * {{time.hour}} + * {{today}} + """ + ) let object: [String: Any] = [ "year": 1970, "month": 1, @@ -231,113 +253,151 @@ final class TemplateRendererTests: XCTestCase { return "{{year}}-{{month}}-{{day}}" }, ] - XCTAssertEqual(template.render(object), """ - * 0 - * 1970-1-1 - """) + XCTAssertEqual( + template.render(object), + """ + * 0 + * 1970-1-1 + """ + ) } /// test boolean func testMustacheManualSectionFalse() throws { - let template = try MustacheTemplate(string: """ - Shown. - {{#person}} - Never shown! - {{/person}} - """) + let template = try MustacheTemplate( + string: """ + Shown. + {{#person}} + Never shown! + {{/person}} + """ + ) let object: [String: Any] = ["person": false] - XCTAssertEqual(template.render(object), """ - Shown. + XCTAssertEqual( + template.render(object), + """ + Shown. - """) + """ + ) } /// test non-empty lists func testMustacheManualSectionList() throws { - let template = try MustacheTemplate(string: """ - {{#repo}} - {{name}} - {{/repo}} - """) + let template = try MustacheTemplate( + string: """ + {{#repo}} + {{name}} + {{/repo}} + """ + ) let object: [String: Any] = ["repo": [["name": "resque"], ["name": "hub"], ["name": "rip"]]] - XCTAssertEqual(template.render(object), """ - resque - hub - rip + XCTAssertEqual( + template.render(object), + """ + resque + hub + rip - """) + """ + ) } /// test non-empty lists func testMustacheManualSectionList2() throws { - let template = try MustacheTemplate(string: """ - {{#repo}} - {{.}} - {{/repo}} - """) + let template = try MustacheTemplate( + string: """ + {{#repo}} + {{.}} + {{/repo}} + """ + ) let object: [String: Any] = ["repo": ["resque", "hub", "rip"]] - XCTAssertEqual(template.render(object), """ - resque - hub - rip + XCTAssertEqual( + template.render(object), + """ + resque + hub + rip - """) + """ + ) } /// test lambdas func testMustacheManualSectionLambda() throws { - let template = try MustacheTemplate(string: """ - {{#wrapped}}{{name}} is awesome.{{/wrapped}} - """) + let template = try MustacheTemplate( + string: """ + {{#wrapped}}{{name}} is awesome.{{/wrapped}} + """ + ) func wrapped(_ s: String) -> Any? { - return "\(s)" + "\(s)" } let object: [String: Any] = ["name": "Willy", "wrapped": MustacheLambda(wrapped)] - XCTAssertEqual(template.render(object), """ - Willy is awesome. - """) + XCTAssertEqual( + template.render(object), + """ + Willy is awesome. + """ + ) } /// test setting context object func testMustacheManualContextObject() throws { - let template = try MustacheTemplate(string: """ - {{#person?}} - Hi {{name}}! - {{/person?}} - """) + let template = try MustacheTemplate( + string: """ + {{#person?}} + Hi {{name}}! + {{/person?}} + """ + ) let object: [String: Any] = ["person?": ["name": "Jon"]] - XCTAssertEqual(template.render(object), """ - Hi Jon! + XCTAssertEqual( + template.render(object), + """ + Hi Jon! - """) + """ + ) } /// test inverted sections func testMustacheManualInvertedSection() throws { - let template = try MustacheTemplate(string: """ - {{#repo}} - {{name}} - {{/repo}} - {{^repo}} - No repos :( - {{/repo}} - """) + let template = try MustacheTemplate( + string: """ + {{#repo}} + {{name}} + {{/repo}} + {{^repo}} + No repos :( + {{/repo}} + """ + ) let object: [String: Any] = ["repo": []] - XCTAssertEqual(template.render(object), """ - No repos :( + XCTAssertEqual( + template.render(object), + """ + No repos :( - """) + """ + ) } /// test comments func testMustacheManualComment() throws { - let template = try MustacheTemplate(string: """ -

Today{{! ignore me }}.

- """) + let template = try MustacheTemplate( + string: """ +

Today{{! ignore me }}.

+ """ + ) let object: [String: Any] = ["repo": []] - XCTAssertEqual(template.render(object), """ -

Today.

- """) + XCTAssertEqual( + template.render(object), + """ +

Today.

+ """ + ) } /// test dynamic names @@ -357,18 +417,23 @@ final class TemplateRendererTests: XCTestCase { /// test block with defaults func testMustacheManualBlocksWithDefaults() throws { - let template = try MustacheTemplate(string: """ -

{{$title}}The News of Today{{/title}}

- {{$body}} -

Nothing special happened.

- {{/body}} + let template = try MustacheTemplate( + string: """ +

{{$title}}The News of Today{{/title}}

+ {{$body}} +

Nothing special happened.

+ {{/body}} - """) - XCTAssertEqual(template.render([]), """ -

The News of Today

-

Nothing special happened.

+ """ + ) + XCTAssertEqual( + template.render([]), + """ +

The News of Today

+

Nothing special happened.

- """) + """ + ) } func testMustacheManualParents() throws { @@ -405,7 +470,7 @@ final class TemplateRendererTests: XCTestCase { "headlines": [ "A pug's handler grew mustaches.", "What an exciting day!", - ], + ] ] XCTAssertEqual( library.render(object, withTemplate: "main"), @@ -474,11 +539,13 @@ final class TemplateRendererTests: XCTestCase { } func testPerformance() throws { - let template = try MustacheTemplate(string: """ - {{#repo}} - {{name}} - {{/repo}} - """) + let template = try MustacheTemplate( + string: """ + {{#repo}} + {{name}} + {{/repo}} + """ + ) let object: [String: Any] = ["repo": [["name": "resque"], ["name": "hub"], ["name": "rip"]]] let date = Date() for _ in 1...10000 { diff --git a/Tests/MustacheTests/TransformTests.swift b/Tests/MustacheTests/TransformTests.swift index 6736cbe..6c990ea 100644 --- a/Tests/MustacheTests/TransformTests.swift +++ b/Tests/MustacheTests/TransformTests.swift @@ -17,177 +17,233 @@ import XCTest final class TransformTests: XCTestCase { func testLowercased() throws { - let template = try MustacheTemplate(string: """ - {{ lowercased(name) }} - """) + let template = try MustacheTemplate( + string: """ + {{ lowercased(name) }} + """ + ) let object: [String: Any] = ["name": "Test"] XCTAssertEqual(template.render(object), "test") } func testUppercased() throws { - let template = try MustacheTemplate(string: """ - {{ uppercased(name) }} - """) + let template = try MustacheTemplate( + string: """ + {{ uppercased(name) }} + """ + ) let object: [String: Any] = ["name": "Test"] XCTAssertEqual(template.render(object), "TEST") } func testNewline() throws { - let template = try MustacheTemplate(string: """ - {{#repo}} - {{name}} - {{/repo}} + let template = try MustacheTemplate( + string: """ + {{#repo}} + {{name}} + {{/repo}} - """) + """ + ) let object: [String: Any] = ["repo": [["name": "resque"], ["name": "hub"], ["name": "rip"]]] - XCTAssertEqual(template.render(object), """ - resque - hub - rip + XCTAssertEqual( + template.render(object), + """ + resque + hub + rip - """) + """ + ) } func testFirstLast() throws { - let template = try MustacheTemplate(string: """ - {{#repo}} - {{#first()}}first: {{/first()}}{{#last()}}last: {{/last()}}{{ name }} - {{/repo}} + let template = try MustacheTemplate( + string: """ + {{#repo}} + {{#first()}}first: {{/first()}}{{#last()}}last: {{/last()}}{{ name }} + {{/repo}} - """) + """ + ) let object: [String: Any] = ["repo": [["name": "resque"], ["name": "hub"], ["name": "rip"]]] - XCTAssertEqual(template.render(object), """ - first: resque - hub - last: rip + XCTAssertEqual( + template.render(object), + """ + first: resque + hub + last: rip - """) + """ + ) } func testIndex() throws { - let template = try MustacheTemplate(string: """ - {{#repo}} - {{#index()}}{{plusone(.)}}{{/index()}}) {{ name }} - {{/repo}} + let template = try MustacheTemplate( + string: """ + {{#repo}} + {{#index()}}{{plusone(.)}}{{/index()}}) {{ name }} + {{/repo}} - """) + """ + ) let object: [String: Any] = ["repo": [["name": "resque"], ["name": "hub"], ["name": "rip"]]] - XCTAssertEqual(template.render(object), """ - 1) resque - 2) hub - 3) rip + XCTAssertEqual( + template.render(object), + """ + 1) resque + 2) hub + 3) rip - """) + """ + ) } func testDoubleSequenceTransformWorks() throws { - let template = try MustacheTemplate(string: """ - {{#repo}} - {{count(reversed(numbers))}} - {{/repo}} + let template = try MustacheTemplate( + string: """ + {{#repo}} + {{count(reversed(numbers))}} + {{/repo}} - """) + """ + ) let object: [String: Any] = ["repo": ["numbers": [1, 2, 3]]] - XCTAssertEqual(template.render(object), """ - 3 + XCTAssertEqual( + template.render(object), + """ + 3 - """) + """ + ) } func testMultipleTransformWorks() throws { - let template = try MustacheTemplate(string: """ - {{#repo}} - {{minusone(plusone(last(reversed(numbers))))}} - {{/repo}} + let template = try MustacheTemplate( + string: """ + {{#repo}} + {{minusone(plusone(last(reversed(numbers))))}} + {{/repo}} - """) + """ + ) let object: [String: Any] = ["repo": ["numbers": [5, 4, 3]]] - XCTAssertEqual(template.render(object), """ - 5 + XCTAssertEqual( + template.render(object), + """ + 5 - """) + """ + ) } func testNestedTransformWorks() throws { - let template = try MustacheTemplate(string: """ - {{#repo}} - {{#uppercased(string)}}{{reversed(.)}}{{/uppercased(string)}} - {{/repo}} + let template = try MustacheTemplate( + string: """ + {{#repo}} + {{#uppercased(string)}}{{reversed(.)}}{{/uppercased(string)}} + {{/repo}} - """) + """ + ) let object: [String: Any] = ["repo": ["string": "a123a"]] - XCTAssertEqual(template.render(object), """ - A321A + XCTAssertEqual( + template.render(object), + """ + A321A - """) + """ + ) } func testEvenOdd() throws { - let template = try MustacheTemplate(string: """ - {{#repo}} - {{index()}}) {{#even()}}even {{/even()}}{{#odd()}}odd {{/odd()}}{{ name }} - {{/repo}} + let template = try MustacheTemplate( + string: """ + {{#repo}} + {{index()}}) {{#even()}}even {{/even()}}{{#odd()}}odd {{/odd()}}{{ name }} + {{/repo}} - """) + """ + ) let object: [String: Any] = ["repo": [["name": "resque"], ["name": "hub"], ["name": "rip"]]] - XCTAssertEqual(template.render(object), """ - 0) even resque - 1) odd hub - 2) even rip + XCTAssertEqual( + template.render(object), + """ + 0) even resque + 1) odd hub + 2) even rip - """) + """ + ) } func testReversed() throws { - let template = try MustacheTemplate(string: """ - {{#reversed(repo)}} - {{ name }} - {{/reversed(repo)}} + let template = try MustacheTemplate( + string: """ + {{#reversed(repo)}} + {{ name }} + {{/reversed(repo)}} - """) + """ + ) let object: [String: Any] = ["repo": [["name": "resque"], ["name": "hub"], ["name": "rip"]]] - XCTAssertEqual(template.render(object), """ - rip - hub - resque + XCTAssertEqual( + template.render(object), + """ + rip + hub + resque - """) + """ + ) } func testArrayIndex() throws { - let template = try MustacheTemplate(string: """ - {{#repo}} - {{ index() }}) {{ name }} - {{/repo}} - """) + let template = try MustacheTemplate( + string: """ + {{#repo}} + {{ index() }}) {{ name }} + {{/repo}} + """ + ) let object: [String: Any] = ["repo": [["name": "resque"], ["name": "hub"], ["name": "rip"]]] - XCTAssertEqual(template.render(object), """ - 0) resque - 1) hub - 2) rip + XCTAssertEqual( + template.render(object), + """ + 0) resque + 1) hub + 2) rip - """) + """ + ) } func testArraySorted() throws { - let template = try MustacheTemplate(string: """ - {{#sorted(repo)}} - {{ index() }}) {{ . }} - {{/sorted(repo)}} - """) + let template = try MustacheTemplate( + string: """ + {{#sorted(repo)}} + {{ index() }}) {{ . }} + {{/sorted(repo)}} + """ + ) let object: [String: Any] = ["repo": ["resque", "hub", "rip"]] - XCTAssertEqual(template.render(object), """ - 0) hub - 1) resque - 2) rip + XCTAssertEqual( + template.render(object), + """ + 0) hub + 1) resque + 2) rip - """) + """ + ) } func testDictionaryEmpty() throws { - let template = try MustacheTemplate(string: """ - {{#empty(array)}}Array{{/empty(array)}}{{#empty(dictionary)}}Dictionary{{/empty(dictionary)}} - """) + let template = try MustacheTemplate( + string: """ + {{#empty(array)}}Array{{/empty(array)}}{{#empty(dictionary)}}Dictionary{{/empty(dictionary)}} + """ + ) let object: [String: Any] = ["array": [], "dictionary": [:]] XCTAssertEqual(template.render(object), "ArrayDictionary") } @@ -199,18 +255,22 @@ final class TransformTests: XCTestCase { } func testDictionaryEnumerated() throws { - let template = try MustacheTemplate(string: """ - {{#enumerated(.)}}{{ key }} = {{ value }}{{/enumerated(.)}} - """) + let template = try MustacheTemplate( + string: """ + {{#enumerated(.)}}{{ key }} = {{ value }}{{/enumerated(.)}} + """ + ) let object: [String: Any] = ["one": 1, "two": 2] let result = template.render(object) XCTAssertTrue(result == "one = 1two = 2" || result == "two = 2one = 1") } func testDictionarySortedByKey() throws { - let template = try MustacheTemplate(string: """ - {{#sorted(.)}}{{ key }} = {{ value }}{{/sorted(.)}} - """) + let template = try MustacheTemplate( + string: """ + {{#sorted(.)}}{{ key }} = {{ value }}{{/sorted(.)}} + """ + ) let object: [String: Any] = ["one": 1, "two": 2, "three": 3] let result = template.render(object) XCTAssertEqual(result, "one = 1three = 3two = 2") diff --git a/scripts/validate.sh b/scripts/validate.sh index bb67406..f949949 100755 --- a/scripts/validate.sh +++ b/scripts/validate.sh @@ -31,8 +31,6 @@ SWIFT_FORMAT_VERSION=0.53.10 set -eu here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -which swiftformat > /dev/null 2>&1 || (echo "swiftformat not installed. You can install it using 'brew install swiftformat'" ; exit -1) - function replace_acceptable_years() { # this needs to replace all acceptable forms with 'YEARS' sed -e 's/20[12][0-9]-20[12][0-9]/YEARS/' -e 's/20[12][0-9]/YEARS/' -e '/^#!/ d' @@ -40,13 +38,9 @@ function replace_acceptable_years() { printf "=> Checking format... " FIRST_OUT="$(git status --porcelain)" -if [[ -n "${CI-""}" ]]; then - printf "(using v$(mint run NickLockwood/SwiftFormat@"$SWIFT_FORMAT_VERSION" --version)) " - mint run NickLockwood/SwiftFormat@"$SWIFT_FORMAT_VERSION" . > /dev/null 2>&1 -else - printf "(using v$(swiftformat --version)) " - swiftformat . > /dev/null 2>&1 -fi +git ls-files -z '*.swift' | xargs -0 swift format format --parallel --in-place +git diff --exit-code '*.swift' + SECOND_OUT="$(git status --porcelain)" if [[ "$FIRST_OUT" != "$SECOND_OUT" ]]; then printf "\033[0;31mformatting issues!\033[0m\n" @@ -55,10 +49,11 @@ if [[ "$FIRST_OUT" != "$SECOND_OUT" ]]; then else printf "\033[0;32mokay.\033[0m\n" fi -exit printf "=> Checking license headers... " tmp=$(mktemp /tmp/.soto-core-sanity_XXXXXX) +exit 0 + for language in swift-or-c; do declare -a matching_files declare -a exceptions @@ -66,18 +61,18 @@ for language in swift-or-c; do matching_files=( -name '*' ) case "$language" in swift-or-c) - exceptions=( -path '*Sources/INIParser/*' -o -path '*Sources/CSotoExpat/*' -o -path '*Benchmark/.build/*' -o -name Package.swift) + exceptions=( -path '*/Benchmarks/.build/*' -o -name Package.swift) matching_files=( -name '*.swift' -o -name '*.c' -o -name '*.h' ) cat > "$tmp" <<"EOF" //===----------------------------------------------------------------------===// // -// This source file is part of the Hummingbird open source project +// This source file is part of the Hummingbird server framework project // // Copyright (c) YEARS the Hummingbird authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information -// See CONTRIBUTORS.txt for the list of Hummingbird authors +// See hummingbird/CONTRIBUTORS.txt for the list of Hummingbird authors // // SPDX-License-Identifier: Apache-2.0 // @@ -89,13 +84,13 @@ EOF cat > "$tmp" <<"EOF" ##===----------------------------------------------------------------------===## ## -## This source file is part of the Hummingbird open source project +## This source file is part of the Hummingbird server framework project ## ## Copyright (c) YEARS the Hummingbird authors ## Licensed under Apache License v2.0 ## ## See LICENSE.txt for license information -## See CONTRIBUTORS.txt for the list of Hummingbird authors +## See hummingbird/CONTRIBUTORS.txt for the list of Hummingbird authors ## ## SPDX-License-Identifier: Apache-2.0 ##