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 an option for encoding scalars with newlines to Emitter.Options #406

Merged
merged 6 commits into from
Apr 7, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 25 additions & 11 deletions Sources/Yams/Emitter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ public func dump<Objects>(
version: (major: Int, minor: Int)? = nil,
sortKeys: Bool = false,
sequenceStyle: Node.Sequence.Style = .any,
mappingStyle: Node.Mapping.Style = .any) throws -> String
mappingStyle: Node.Mapping.Style = .any,
newLineScalarStyle: Node.Scalar.Style = .any) throws -> String
where Objects: Sequence {
func representable(from object: Any) throws -> NodeRepresentable {
if let representable = object as? NodeRepresentable {
Expand All @@ -62,7 +63,8 @@ public func dump<Objects>(
version: version,
sortKeys: sortKeys,
sequenceStyle: sequenceStyle,
mappingStyle: mappingStyle
mappingStyle: mappingStyle,
newLineScalarStyle: newLineScalarStyle
)
}

Expand Down Expand Up @@ -96,7 +98,8 @@ public func dump(
version: (major: Int, minor: Int)? = nil,
sortKeys: Bool = false,
sequenceStyle: Node.Sequence.Style = .any,
mappingStyle: Node.Mapping.Style = .any) throws -> String {
mappingStyle: Node.Mapping.Style = .any,
newLineScalarStyle: Node.Scalar.Style = .any) throws -> String {
return try serialize(
node: object.represented(),
canonical: canonical,
Expand All @@ -109,7 +112,8 @@ public func dump(
version: version,
sortKeys: sortKeys,
sequenceStyle: sequenceStyle,
mappingStyle: mappingStyle
mappingStyle: mappingStyle,
newLineScalarStyle: newLineScalarStyle
)
}

Expand Down Expand Up @@ -143,7 +147,8 @@ public func serialize<Nodes>(
version: (major: Int, minor: Int)? = nil,
sortKeys: Bool = false,
sequenceStyle: Node.Sequence.Style = .any,
mappingStyle: Node.Mapping.Style = .any) throws -> String
mappingStyle: Node.Mapping.Style = .any,
newLineScalarStyle: Node.Scalar.Style = .any) throws -> String
where Nodes: Sequence, Nodes.Iterator.Element == Node {
let emitter = Emitter(
canonical: canonical,
Expand All @@ -156,7 +161,8 @@ public func serialize<Nodes>(
version: version,
sortKeys: sortKeys,
sequenceStyle: sequenceStyle,
mappingStyle: mappingStyle
mappingStyle: mappingStyle,
newLineScalarStyle: newLineScalarStyle
)
try emitter.open()
try nodes.forEach(emitter.serialize)
Expand Down Expand Up @@ -194,7 +200,8 @@ public func serialize(
version: (major: Int, minor: Int)? = nil,
sortKeys: Bool = false,
sequenceStyle: Node.Sequence.Style = .any,
mappingStyle: Node.Mapping.Style = .any) throws -> String {
mappingStyle: Node.Mapping.Style = .any,
newLineScalarStyle: Node.Scalar.Style = .any) throws -> String {
return try serialize(
nodes: [node],
canonical: canonical,
Expand All @@ -207,7 +214,8 @@ public func serialize(
version: version,
sortKeys: sortKeys,
sequenceStyle: sequenceStyle,
mappingStyle: mappingStyle
mappingStyle: mappingStyle,
newLineScalarStyle: newLineScalarStyle
)
}

Expand Down Expand Up @@ -254,6 +262,9 @@ public final class Emitter {

/// Set the style for mappings (dictionaries)
public var mappingStyle: Node.Mapping.Style = .any

/// Set the style for scalars that include newlines
public var newLineScalarStyle: Node.Scalar.Style = .any
}

/// Configuration options to use when emitting YAML.
Expand Down Expand Up @@ -287,7 +298,8 @@ public final class Emitter {
version: (major: Int, minor: Int)? = nil,
sortKeys: Bool = false,
sequenceStyle: Node.Sequence.Style = .any,
mappingStyle: Node.Mapping.Style = .any) {
mappingStyle: Node.Mapping.Style = .any,
newLineScalarStyle: Node.Scalar.Style = .any) {
options = Options(canonical: canonical,
indent: indent,
width: width,
Expand All @@ -298,7 +310,8 @@ public final class Emitter {
version: version,
sortKeys: sortKeys,
sequenceStyle: sequenceStyle,
mappingStyle: mappingStyle)
mappingStyle: mappingStyle,
newLineScalarStyle: newLineScalarStyle)
// configure emitter
yaml_emitter_initialize(&emitter)
yaml_emitter_set_output(&self.emitter, { pointer, buffer, size in
Expand Down Expand Up @@ -420,7 +433,7 @@ extension Emitter.Options {
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, sequenceStyle: Node.Sequence.Style = .any,
mappingStyle: Node.Mapping.Style = .any) {
mappingStyle: Node.Mapping.Style = .any, newLineScalarStyle: Node.Scalar.Style = .any) {
self.canonical = canonical
self.indent = indent
self.width = width
Expand All @@ -430,6 +443,7 @@ extension Emitter.Options {
self.sortKeys = sortKeys
self.sequenceStyle = sequenceStyle
self.mappingStyle = mappingStyle
self.newLineScalarStyle = newLineScalarStyle
}
}

Expand Down
16 changes: 12 additions & 4 deletions Sources/Yams/Encoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class YAMLEncoder {
public func encode<T: Swift.Encodable>(_ value: T, userInfo: [CodingUserInfoKey: Any] = [:]) throws -> String {
do {
let encoder = _Encoder(userInfo: userInfo, sequenceStyle: options.sequenceStyle,
mappingStyle: options.mappingStyle)
mappingStyle: options.mappingStyle, newlineScalarStyle: options.newLineScalarStyle)
var container = encoder.singleValueContainer()
try container.encode(value)
return try serialize(node: encoder.node, options: options)
Expand All @@ -49,11 +49,12 @@ private class _Encoder: Swift.Encoder {
var node: Node = .unused

init(userInfo: [CodingUserInfoKey: Any] = [:], codingPath: [CodingKey] = [], sequenceStyle: Node.Sequence.Style,
mappingStyle: Node.Mapping.Style) {
mappingStyle: Node.Mapping.Style, newlineScalarStyle: Node.Scalar.Style) {
self.userInfo = userInfo
self.codingPath = codingPath
self.sequenceStyle = sequenceStyle
self.mappingStyle = mappingStyle
self.newlineScalarStyle = newlineScalarStyle
}

// MARK: - Swift.Encoder Methods
Expand All @@ -62,6 +63,7 @@ private class _Encoder: Swift.Encoder {
let userInfo: [CodingUserInfoKey: Any]
let sequenceStyle: Node.Sequence.Style
let mappingStyle: Node.Mapping.Style
let newlineScalarStyle: Node.Scalar.Style

func container<Key>(keyedBy type: Key.Type) -> KeyedEncodingContainer<Key> {
if canEncodeNewValue {
Expand Down Expand Up @@ -124,14 +126,14 @@ private class _ReferencingEncoder: _Encoder {
self.encoder = encoder
reference = .mapping(key.stringValue)
super.init(userInfo: encoder.userInfo, codingPath: encoder.codingPath + [key],
sequenceStyle: encoder.sequenceStyle, mappingStyle: encoder.mappingStyle)
sequenceStyle: encoder.sequenceStyle, mappingStyle: encoder.mappingStyle, newlineScalarStyle: encoder.newlineScalarStyle)
}

init(referencing encoder: _Encoder, at index: Int) {
self.encoder = encoder
reference = .sequence(index)
super.init(userInfo: encoder.userInfo, codingPath: encoder.codingPath + [_YAMLCodingKey(index: index)],
sequenceStyle: encoder.sequenceStyle, mappingStyle: encoder.mappingStyle)
sequenceStyle: encoder.sequenceStyle, mappingStyle: encoder.mappingStyle, newlineScalarStyle: encoder.newlineScalarStyle)
}

deinit {
Expand Down Expand Up @@ -218,12 +220,18 @@ extension _Encoder: SingleValueEncodingContainer {
func encode<T>(_ value: T) throws where T: YAMLEncodable {
assertCanEncodeNewValue()
node = value.box()
if let stringValue = value as? (any StringProtocol), stringValue.contains("\n") {
node.scalar?.style = newlineScalarStyle
}
}

func encode<T>(_ value: T) throws where T: Encodable {
assertCanEncodeNewValue()
if let encodable = value as? YAMLEncodable {
node = encodable.box()
if let stringValue = value as? (any StringProtocol), stringValue.contains("\n") {
node.scalar?.style = newlineScalarStyle
}
} else {
try value.encode(to: self)
}
Expand Down
21 changes: 21 additions & 0 deletions Tests/YamsTests/EncoderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,27 @@ class EncoderTests: XCTestCase { // swiftlint:disable:this type_body_length
_testRoundTrip(of: OptionalTopLevelWrapper(url), expectedYAML: expectedYAML)
}

func testNewlinesInString() throws {
let expectedYamlLiteral = """
name: |-
This name
Has new lines
email: test@test.test

"""
let expectedYamlFolded = """
name: >-
This name

Has new lines
email: test@test.test

"""
let person = Person(name: "This name\nHas new lines", email: "test@test.test")
_testRoundTrip(of: person, with: .init(newLineScalarStyle: .literal), expectedYAML: expectedYamlLiteral)
_testRoundTrip(of: person, with: .init(newLineScalarStyle: .folded), expectedYAML: expectedYamlFolded)
}

func testNumberInString() throws {
_testDecode(of: String.self, from: "'10'", expectedValue: "10")
_testDecode(of: String.self, from: "'10.5'", expectedValue: "10.5")
Expand Down