Skip to content

Commit

Permalink
Adds uncluttering dumped YAML manifest from nil entries. (#858)
Browse files Browse the repository at this point in the history
* Adds uncluttering dumped YAML manifest from `nil` entries.

* Uses required type of a dictionary

* Update CHANGELOG.md

Co-authored-by: Maciej Piotrowski <maciej.piotrowski@allegro.pl>
  • Loading branch information
maciejpiotrowski89 and maciejpiotrowski89 authored May 11, 2020
1 parent 98275e9 commit 4d6e63e
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 2 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
- Add an ability to set an order of groups with `options.groupOrdering` [#613](https://github.com/yonaskolb/XcodeGen/pull/613) @Beniamiiin
- Add `staticBinary` linkType for Carthage dependency [#847](https://github.com/yonaskolb/XcodeGen/pull/847) @d-date
- Add the ability to output a dependency graph in graphviz format [#852](https://github.com/yonaskolb/XcodeGen/pull/852) @jeffctown
- Adds uncluttering the project manifest dumped to YAML from empty values [#858](https://github.com/yonaskolb/XcodeGen/pull/858) @paciej00



#### Fixed
- Fixed issue when linking and embeding static frameworks: they should be linked and NOT embed. [#820](https://github.com/yonaskolb/XcodeGen/pull/820) @acecilia
Expand All @@ -18,7 +21,7 @@
- Set `preActions` and `postActions` on the `build` action of a TargetScheme instead of the other actions. [#823](https://github.com/yonaskolb/XcodeGen/pull/823) @brentleyjones
- Prevent test targets from being set as a scheme's launch action [#835](https://github.com/yonaskolb/XcodeGen/pull/835) @brentleyjones
- Implicitly include bundles in the Copy Bundle Resources build phase. [#838](https://github.com/yonaskolb/XcodeGen/pull/838) @skirchmeier
- Fixed dumping a project manifest which contains an array of project references @paciej00
- Fixed dumping a project manifest which contains an array of project references [#840](https://github.com/yonaskolb/XcodeGen/pull/840) @paciej00
- Generate correct PBXTargetDependency for external targets. [#843](https://github.com/yonaskolb/XcodeGen/pull/843) @ileitch
- Fix linking of multiple products from the same Swift Package [#830](https://github.com/yonaskolb/XcodeGen/pull/830) @toshi0383
- Don't deduplicate files in `include` with different path but same name. [#849](https://github.com/yonaskolb/XcodeGen/pull/849) @akkyie
Expand Down
9 changes: 9 additions & 0 deletions Sources/ProjectSpec/Array+Extension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
extension Array where Element == [String: Any?] {
func removingEmptyArraysDictionariesAndNils() -> [[String: Any]] {
var new: [[String: Any]] = []
forEach { element in
new.append(element.removingEmptyArraysDictionariesAndNils())
}
return new
}
}
33 changes: 33 additions & 0 deletions Sources/ProjectSpec/Dictionary+Extension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
extension Dictionary where Key == String, Value == Any? {
func removingEmptyArraysDictionariesAndNils() -> [String: Any] {
var new: [String: Any] = [:]
filter(outNil).forEach { pair in
let value: Any
if let array = pair.value as? [[String: Any?]] {
value = array.removingEmptyArraysDictionariesAndNils()
} else if let dictionary = pair.value as? [String: Any?] {
value = dictionary.removingEmptyArraysDictionariesAndNils()
} else {
value = pair.value! // nil is filtered out :)
}
new[pair.key] = value
}
return new
.filter(outEmptyArrays)
.filter(outEmptyDictionaries)
}

func outEmptyArrays(_ pair: (key: String, value: Any)) -> Bool {
guard let array = pair.value as? [Any] else { return true }
return !array.isEmpty
}

func outEmptyDictionaries(_ pair: (key: String, value: Any)) -> Bool {
guard let dictionary = pair.value as? [String: Any] else { return true }
return !dictionary.isEmpty
}

func outNil(_ pair: (key: String, value: Any?)) -> Bool {
return pair.value != nil
}
}
3 changes: 2 additions & 1 deletion Sources/ProjectSpec/Yaml.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public func loadYamlDictionary(path: Path) throws -> [String: Any] {
}

public func dumpYamlDictionary(_ dictionary: [String: Any], path: Path) throws {
let string: String = try Yams.dump(object: dictionary)
let uncluttered = (dictionary as [String: Any?]).removingEmptyArraysDictionariesAndNils()
let string: String = try Yams.dump(object: uncluttered)
try path.write(string)
}
130 changes: 130 additions & 0 deletions Tests/ProjectSpecTests/Dictionary+Extension_Tests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
@testable import ProjectSpec
import XCTest

final class DictionaryExtensionTests: XCTestCase {
func testRemovingNil_ShouldReturnNewDictionaryWithoutOptionalValues() {
// Arrange
let input: [String: Any?] = inputDictionary
let expected: [String: Any] = outputDictionary
XCTAssertNotEqual(input as NSDictionary, expected as NSDictionary)

// Act
let sut: [String: Any] = input.removingEmptyArraysDictionariesAndNils()

// Assert
XCTAssertEqual(sut as NSDictionary, expected as NSDictionary)
}
}

extension DictionaryExtensionTests {
var inputDictionary: [String: Any?] {
let inner1: [String: Any?] = [
"inner1": "value1",
"inner2": Optional("value2"),
"inner3": nil,
"inner4": Optional([1, 2, 3])
]
let inner2: [String: Any?] = [
"inner1": "value1",
"inner2": Optional("value2"),
"inner3": inner1,
"inner4": [1, 2, 3]
]
let inner3: [String: Any?] = [
"inner1": "value1",
"inner2": Optional("value2"),
"inner3": Optional(inner1),
"inner4": [1, 2, 3],
"inner5": inner2
]
let inner4: [String: Any?] = [
"inner1": inner1,
"inner2": inner2,
"inner3": inner3,
"inner4": Optional("value4"),
"inner5": nil
]

let inner6: [String: Any?] = [
"inner1": "value1",
"inner2": "value2",
"inner3": [inner1, inner1, inner1]
]

let input: [String: Any?] = [
"inner1": "value1",
"inner2": Optional("value2"),
"inner3": nil,
"inner4": inner4,
"inner5": [],
"inner6": inner6,
"inner7": [:]
]

return input
}

var outputDictionary: [String: Any] {
let expected: [String: Any] = [
"inner1": "value1",
"inner2": "value2",
"inner4": [
"inner1": [
"inner1": "value1",
"inner2": "value2",
"inner4": [1, 2, 3]
],
"inner2": [
"inner1": "value1",
"inner2": "value2",
"inner3": [
"inner1": "value1",
"inner2": "value2",
"inner4": [1, 2, 3]
],
"inner4": [1, 2, 3]
],
"inner3": [
"inner1": "value1",
"inner2": "value2",
"inner3": [
"inner1": "value1",
"inner2": "value2",
"inner4": [1, 2, 3]
],
"inner4": [1, 2, 3],
"inner5": [
"inner1": "value1",
"inner2": "value2",
"inner3": [
"inner1": "value1",
"inner2": "value2",
"inner4": [1, 2, 3]
],
"inner4": [1, 2, 3]
]
],
"inner4": "value4"
],
"inner6": [
"inner1": "value1",
"inner2": "value2",
"inner3": [[
"inner1": "value1",
"inner2": "value2",
"inner4": [1, 2, 3]
], [
"inner1": "value1",
"inner2": "value2",
"inner4": [1, 2, 3]
], [
"inner1": "value1",
"inner2": "value2",
"inner4": [1, 2, 3]
]]
]
]

return expected
}
}

0 comments on commit 4d6e63e

Please sign in to comment.