diff --git a/CHANGELOG.md b/CHANGELOG.md index 29b95e89..c3930fd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +## Main + +##### Breaking + +* Change the `sortKeys` options to a `keySort` function. + [Kevin Barrett](https://github.com/kevboh) + +##### Enhancements + +* None. + +##### Bug Fixes + +* None. + ## 4.0.6 ##### Breaking diff --git a/Sources/Yams/Emitter.swift b/Sources/Yams/Emitter.swift index e7c4f5f6..9d7ac189 100644 --- a/Sources/Yams/Emitter.swift +++ b/Sources/Yams/Emitter.swift @@ -11,6 +11,10 @@ import CYaml #endif import Foundation +/// A sort predicate applied to two `Node`s. Return `true` when the first node should be ordered +/// before the second. +public typealias NodeSort = (Node, Node) throws -> Bool + /// Produce a YAML string from objects. /// /// - parameter objects: Sequence of Objects. @@ -22,7 +26,7 @@ import Foundation /// - parameter explicitStart: Explicit document start `---`. /// - parameter explicitEnd: Explicit document end `...`. /// - parameter version: YAML version directive. -/// - parameter sortKeys: Whether or not to sort Mapping keys in lexicographic order. +/// - parameter keySort: Sort function to apply to Mapping keys, or `nil` to not sort. /// /// - returns: YAML string. /// @@ -37,7 +41,7 @@ public func dump( explicitStart: Bool = false, explicitEnd: Bool = false, version: (major: Int, minor: Int)? = nil, - sortKeys: Bool = false) throws -> String + keySort: NodeSort? = nil) throws -> String where Objects: Sequence { func representable(from object: Any) throws -> NodeRepresentable { if let representable = object as? NodeRepresentable { @@ -56,7 +60,7 @@ public func dump( explicitStart: explicitStart, explicitEnd: explicitEnd, version: version, - sortKeys: sortKeys + keySort: keySort ) } @@ -71,7 +75,7 @@ public func dump( /// - parameter explicitStart: Explicit document start `---`. /// - parameter explicitEnd: Explicit document end `...`. /// - parameter version: YAML version directive. -/// - parameter sortKeys: Whether or not to sort Mapping keys in lexicographic order. +/// - parameter keySort: Sort function to apply to Mapping keys, or `nil` to not sort. /// /// - returns: YAML string. /// @@ -86,7 +90,7 @@ public func dump( explicitStart: Bool = false, explicitEnd: Bool = false, version: (major: Int, minor: Int)? = nil, - sortKeys: Bool = false) throws -> String { + keySort: NodeSort? = nil) throws -> String { return try serialize( node: object.represented(), canonical: canonical, @@ -97,7 +101,7 @@ public func dump( explicitStart: explicitStart, explicitEnd: explicitEnd, version: version, - sortKeys: sortKeys + keySort: keySort ) } @@ -112,7 +116,7 @@ public func dump( /// - parameter explicitStart: Explicit document start `---`. /// - parameter explicitEnd: Explicit document end `...`. /// - parameter version: YAML version directive. -/// - parameter sortKeys: Whether or not to sort Mapping keys in lexicographic order. +/// - parameter keySort: Sort function to apply to Mapping keys, or `nil` to not sort. /// /// - returns: YAML string. /// @@ -127,7 +131,7 @@ public func serialize( explicitStart: Bool = false, explicitEnd: Bool = false, version: (major: Int, minor: Int)? = nil, - sortKeys: Bool = false) throws -> String + keySort: NodeSort? = nil) throws -> String where Nodes: Sequence, Nodes.Iterator.Element == Node { let emitter = Emitter( canonical: canonical, @@ -138,7 +142,7 @@ public func serialize( explicitStart: explicitStart, explicitEnd: explicitEnd, version: version, - sortKeys: sortKeys + keySort: keySort ) try emitter.open() try nodes.forEach(emitter.serialize) @@ -157,7 +161,7 @@ public func serialize( /// - parameter explicitStart: Explicit document start `---`. /// - parameter explicitEnd: Explicit document end `...`. /// - parameter version: YAML version directive. -/// - parameter sortKeys: Whether or not to sort Mapping keys in lexicographic order. +/// - parameter keySort: Sort function to apply to Mapping keys, or `nil` to not sort. /// /// - returns: YAML string. /// @@ -172,7 +176,7 @@ public func serialize( explicitStart: Bool = false, explicitEnd: Bool = false, version: (major: Int, minor: Int)? = nil, - sortKeys: Bool = false) throws -> String { + keySort: NodeSort? = nil) throws -> String { return try serialize( nodes: [node], canonical: canonical, @@ -183,7 +187,7 @@ public func serialize( explicitStart: explicitStart, explicitEnd: explicitEnd, version: version, - sortKeys: sortKeys + keySort: keySort ) } @@ -223,7 +227,7 @@ public final class Emitter { public var version: (major: Int, minor: Int)? /// Set if emitter should sort keys in lexicographic order. - public var sortKeys: Bool = false + public var keySort: NodeSort? = nil } /// Configuration options to use when emitting YAML. @@ -244,7 +248,7 @@ public final class Emitter { /// - parameter explicitStart: Explicit document start `---`. /// - parameter explicitEnd: Explicit document end `...`. /// - parameter version: The `%YAML` directive value or nil. - /// - parameter sortKeys: Set if emitter should sort keys in lexicographic order. + /// - parameter keySort: Sort function to apply to Mapping keys, or `nil` to not sort. public init(canonical: Bool = false, indent: Int = 0, width: Int = 0, @@ -253,7 +257,7 @@ public final class Emitter { explicitStart: Bool = false, explicitEnd: Bool = false, version: (major: Int, minor: Int)? = nil, - sortKeys: Bool = false) { + keySort: NodeSort? = nil) { options = Options(canonical: canonical, indent: indent, width: width, @@ -262,7 +266,7 @@ public final class Emitter { explicitStart: explicitStart, explicitEnd: explicitEnd, version: version, - sortKeys: sortKeys) + keySort: keySort) // configure emitter yaml_emitter_initialize(&emitter) yaml_emitter_set_output(&self.emitter, { pointer, buffer, size in @@ -378,17 +382,17 @@ extension Emitter.Options { /// - parameter explicitStart: Explicit document start `---`. /// - parameter explicitEnd: Explicit document end `...`. /// - parameter version: The `%YAML` directive value or nil. - /// - parameter sortKeys: Set if emitter should sort keys in lexicographic order. + /// - parameter keySort: Sort function to apply to Mapping keys, or `nil` to not sort. public init(canonical: Bool = false, indent: Int = 0, width: Int = 0, allowUnicode: Bool = false, lineBreak: Emitter.LineBreak = .ln, version: (major: Int, minor: Int)? = nil, - sortKeys: Bool = false) { + keySort: NodeSort? = nil) { self.canonical = canonical self.indent = indent self.width = width self.allowUnicode = allowUnicode self.lineBreak = lineBreak self.version = version - self.sortKeys = sortKeys + self.keySort = keySort } } @@ -462,8 +466,8 @@ extension Emitter { mappingStyle) } try emit(&event) - if options.sortKeys { - try mapping.keys.sorted().forEach { + if let sort = options.keySort { + try mapping.keys.sorted(by: sort).forEach { try self.serializeNode($0) try self.serializeNode(mapping[$0]!) // swiftlint:disable:this force_unwrapping } diff --git a/Sources/Yams/Encoder.swift b/Sources/Yams/Encoder.swift index 42f5aa42..f6fe329d 100644 --- a/Sources/Yams/Encoder.swift +++ b/Sources/Yams/Encoder.swift @@ -284,5 +284,5 @@ private func serialize(node: Node, options: Emitter.Options) throws -> String { explicitStart: options.explicitStart, explicitEnd: options.explicitEnd, version: options.version, - sortKeys: options.sortKeys) + keySort: options.keySort) } diff --git a/Tests/YamsTests/EmitterTests.swift b/Tests/YamsTests/EmitterTests.swift index f5c174df..d79d5900 100644 --- a/Tests/YamsTests/EmitterTests.swift +++ b/Tests/YamsTests/EmitterTests.swift @@ -140,7 +140,7 @@ class EmitterTests: XCTestCase { let yaml = try Yams.serialize(node: node) let expected = "key3: value3\nkey2: value2\nkey1: value1\n" XCTAssertEqual(yaml, expected) - let yamlSorted = try Yams.serialize(node: node, sortKeys: true) + let yamlSorted = try Yams.serialize(node: node, keySort: <) let expectedSorted = "key1: value1\nkey2: value2\nkey3: value3\n" XCTAssertEqual(yamlSorted, expectedSorted) } diff --git a/Tests/YamsTests/EncoderTests.swift b/Tests/YamsTests/EncoderTests.swift index 83b39f14..8f0d802d 100644 --- a/Tests/YamsTests/EncoderTests.swift +++ b/Tests/YamsTests/EncoderTests.swift @@ -68,7 +68,7 @@ class EncoderTests: XCTestCase { // swiftlint:disable:this type_body_length func testEncodingTopLevelStructuredSingleClass() { // Mapping is a class which encodes as a dictionary through a single value container. let mapping = Mapping.testValue - _testRoundTrip(of: mapping, with: YAMLEncoder.Options(sortKeys: true), expectedYAML: """ + _testRoundTrip(of: mapping, with: YAMLEncoder.Options(keySort: <), expectedYAML: """ Apple: http://apple.com localhost: http://127.0.0.1