Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add prettyPrintIndentation property on XMLEncoder #186

Merged
merged 3 commits into from May 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/tasks.json
Expand Up @@ -6,7 +6,7 @@
{
"label": "swift test",
"type": "shell",
"command": "swift test"
"command": "swift test --parallel"
}
]
}
6 changes: 6 additions & 0 deletions Dangerfile.swift
Expand Up @@ -6,3 +6,9 @@
import Danger

SwiftLint.lint(inline: true, configFile: ".swiftlint.yml", strict: true)

let danger = Danger()

print("Calling SwiftFormat...")

danger.utils.exec("swiftformat", arguments: ["."])
48 changes: 32 additions & 16 deletions Sources/XMLCoder/Auxiliaries/XMLCoderElement.swift
Expand Up @@ -122,25 +122,30 @@ struct XMLCoderElement: Equatable {
return KeyedBox(elements: elements, attributes: attributes)
}

func toXMLString(with header: XMLHeader? = nil,
formatting: XMLEncoder.OutputFormatting) -> String {
func toXMLString(
with header: XMLHeader? = nil,
formatting: XMLEncoder.OutputFormatting,
indentation: XMLEncoder.PrettyPrintIndentation
) -> String {
if let header = header, let headerXML = header.toXML() {
return headerXML + _toXMLString(formatting: formatting)
return headerXML + _toXMLString(formatting, indentation)
}
return _toXMLString(formatting: formatting)
return _toXMLString(formatting, indentation)
}

private func formatUnsortedXMLElements(
_ string: inout String,
_ level: Int,
_ formatting: XMLEncoder.OutputFormatting,
_ indentation: XMLEncoder.PrettyPrintIndentation,
_ prettyPrinted: Bool
) {
formatXMLElements(
from: elements,
into: &string,
at: level,
formatting: formatting,
indentation: indentation,
prettyPrinted: prettyPrinted
)
}
Expand All @@ -149,6 +154,7 @@ struct XMLCoderElement: Equatable {
for element: XMLCoderElement,
at level: Int,
formatting: XMLEncoder.OutputFormatting,
indentation: XMLEncoder.PrettyPrintIndentation,
prettyPrinted: Bool
) -> String {
if let stringValue = element.stringValue {
Expand All @@ -160,9 +166,7 @@ struct XMLCoderElement: Equatable {
}

var string = ""
string += element._toXMLString(
indented: level + 1, formatting: formatting
)
string += element._toXMLString(indented: level + 1, formatting, indentation)
string += prettyPrinted ? "\n" : ""
return string
}
Expand All @@ -171,12 +175,14 @@ struct XMLCoderElement: Equatable {
_ string: inout String,
_ level: Int,
_ formatting: XMLEncoder.OutputFormatting,
_ indentation: XMLEncoder.PrettyPrintIndentation,
_ prettyPrinted: Bool
) {
formatXMLElements(from: elements.sorted { $0.key < $1.key },
into: &string,
at: level,
formatting: formatting,
indentation: indentation,
prettyPrinted: prettyPrinted)
}

Expand All @@ -198,12 +204,14 @@ struct XMLCoderElement: Equatable {
into string: inout String,
at level: Int,
formatting: XMLEncoder.OutputFormatting,
indentation: XMLEncoder.PrettyPrintIndentation,
prettyPrinted: Bool
) {
for element in elements {
string += elementString(for: element,
at: level,
formatting: formatting,
indentation: indentation,
prettyPrinted: prettyPrinted && !containsTextNodes)
}
}
Expand Down Expand Up @@ -231,30 +239,38 @@ struct XMLCoderElement: Equatable {

private func formatXMLElements(
_ formatting: XMLEncoder.OutputFormatting,
_ indentation: XMLEncoder.PrettyPrintIndentation,
_ string: inout String,
_ level: Int,
_ prettyPrinted: Bool
) {
if formatting.contains(.sortedKeys) {
formatSortedXMLElements(
&string, level, formatting, prettyPrinted
&string, level, formatting, indentation, prettyPrinted
)
return
}
formatUnsortedXMLElements(
&string, level, formatting, prettyPrinted
&string, level, formatting, indentation, prettyPrinted
)
}

private func _toXMLString(
indented level: Int = 0,
formatting: XMLEncoder.OutputFormatting
_ formatting: XMLEncoder.OutputFormatting,
_ indentation: XMLEncoder.PrettyPrintIndentation
) -> String {
let prettyPrinted = formatting.contains(.prettyPrinted)
let indentation = String(
repeating: " ", count: (prettyPrinted ? level : 0) * 4
)
var string = indentation
let prefix: String
switch indentation {
case let .spaces(count) where prettyPrinted:
prefix = String(repeating: " ", count: level * count)
case let .tabs(count) where prettyPrinted:
prefix = String(repeating: "\t", count: level * count)
default:
prefix = ""
}
var string = prefix

if !key.isEmpty {
string += "<\(key)"
Expand All @@ -267,9 +283,9 @@ struct XMLCoderElement: Equatable {
if !key.isEmpty {
string += prettyPrintElements ? ">\n" : ">"
}
formatXMLElements(formatting, &string, level, prettyPrintElements)
formatXMLElements(formatting, indentation, &string, level, prettyPrintElements)

if prettyPrintElements { string += indentation }
if prettyPrintElements { string += prefix }
if !key.isEmpty {
string += "</\(key)>"
}
Expand Down
16 changes: 14 additions & 2 deletions Sources/XMLCoder/Encoder/XMLEncoder.swift
Expand Up @@ -33,6 +33,12 @@ open class XMLEncoder {
public static let sortedKeys = OutputFormatting(rawValue: 1 << 1)
}

/// The identation to use when XML is pretty-printed.
public enum PrettyPrintIndentation {
case spaces(Int)
case tabs(Int)
}

/// A node's encoding type
public enum NodeEncoding {
case attribute
Expand Down Expand Up @@ -264,6 +270,9 @@ open class XMLEncoder {
/// The output format to produce. Defaults to `[]`.
open var outputFormatting: OutputFormatting = []

/// The indentation to use when XML is printed. Defaults to `.spaces(4)`.
open var prettyPrintIndentation: PrettyPrintIndentation = .spaces(4)

/// The strategy to use in encoding dates. Defaults to `.deferredToDate`.
open var dateEncodingStrategy: DateEncodingStrategy = .deferredToDate

Expand Down Expand Up @@ -373,8 +382,11 @@ open class XMLEncoder {
))
}

return element.toXMLString(with: header, formatting: outputFormatting)
.data(using: .utf8, allowLossyConversion: true)!
return element.toXMLString(
with: header,
formatting: outputFormatting,
indentation: prettyPrintIndentation
).data(using: .utf8, allowLossyConversion: true)!
}

// MARK: - TopLevelEncoder
Expand Down
78 changes: 78 additions & 0 deletions Tests/XMLCoderTests/PrettyPrintTest.swift
@@ -0,0 +1,78 @@
// Copyright (c) 2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT

import XCTest
import XMLCoder

private struct TopContainer: Encodable {
let nested: NestedContainer
}

private struct NestedContainer: Encodable {
let values: [String]
}

final class PrettyPrintTest: XCTestCase {
private let testContainer = TopContainer(nested: NestedContainer(values: ["foor", "bar"]))

func testDefaultIndentation() throws {
let encoder = XMLEncoder()
encoder.outputFormatting = [.prettyPrinted]

let encoded = try encoder.encode(testContainer)

XCTAssertEqual(
String(data: encoded, encoding: .utf8)!,
"""
<TopContainer>
<nested>
<values>foor</values>
<values>bar</values>
</nested>
</TopContainer>
"""
)
}

func testSpaces() throws {
let encoder = XMLEncoder()
encoder.outputFormatting = [.prettyPrinted]
encoder.prettyPrintIndentation = .spaces(3)

let encoded = try encoder.encode(testContainer)

XCTAssertEqual(
String(data: encoded, encoding: .utf8)!,
"""
<TopContainer>
<nested>
<values>foor</values>
<values>bar</values>
</nested>
</TopContainer>
"""
)
}

func testTabs() throws {
let encoder = XMLEncoder()
encoder.outputFormatting = [.prettyPrinted]
encoder.prettyPrintIndentation = .tabs(2)

let encoded = try encoder.encode(testContainer)

XCTAssertEqual(
String(data: encoded, encoding: .utf8)!,
"""
<TopContainer>
\t\t<nested>
\t\t\t\t<values>foor</values>
\t\t\t\t<values>bar</values>
\t\t</nested>
</TopContainer>
"""
)
}
}
13 changes: 13 additions & 0 deletions Tests/XMLCoderTests/XCTestManifests.swift
Expand Up @@ -125,6 +125,7 @@ extension CDATATest {
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__CDATATest = [
("testCDataTypes", testCDataTypes),
("testXML", testXML),
]
}
Expand Down Expand Up @@ -585,6 +586,17 @@ extension PlantTest {
]
}

extension PrettyPrintTest {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__PrettyPrintTest = [
("testDefaultIndentation", testDefaultIndentation),
("testSpaces", testSpaces),
("testTabs", testTabs),
]
}

extension QuoteDecodingTest {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
Expand Down Expand Up @@ -898,6 +910,7 @@ public func __allTests() -> [XCTestCaseEntry] {
testCase(NullTests.__allTests__NullTests),
testCase(OptionalTests.__allTests__OptionalTests),
testCase(PlantTest.__allTests__PlantTest),
testCase(PrettyPrintTest.__allTests__PrettyPrintTest),
testCase(QuoteDecodingTest.__allTests__QuoteDecodingTest),
testCase(RJITest.__allTests__RJITest),
testCase(RelationshipsTest.__allTests__RelationshipsTest),
Expand Down