Fix non-deterministic/incorrect serialization of nested target attributes (e.g. SystemCapabilities) (#1639)
* Fix non-deterministic/incorrect serialization of nested target attributes
ProjectAttribute.init(any:) only handled [String], PBXObject, and fell
back to .string("\(value)") for everything else. Nested dictionary
attributes such as target.attributes.SystemCapabilities therefore never
produced the existing .attributeDictionary case, and instead were
serialized as a raw Swift Dictionary interpolated into a string, e.g.:
SystemCapabilities = "[\"com.apple.Push\": [\"enabled\": 1], ...]";
Dictionary.description iterates in the process's random hash-seed
order, so the exact same input could produce a different key order on
every run, producing spurious project.pbxproj diffs. It also isn't a
valid nested plist dictionary, which some tooling flags as needing a
project 'fix'.
This adds a case that maps [String: [String: Any]] values (the shape
SystemCapabilities and similar nested attributes take) to
.attributeDictionary, so they serialize as a proper nested plist
dictionary. PBXProjEncoder already writes dictionary keys in sorted
order, so this also makes the output deterministic across runs.
* Add changelog entry
* Fix test: include MyFramework target dependency in SystemCapabilities test
* Add SystemCapabilities regression test from #1643
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Yonas Kolb <yonaskolb@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Sergey Ospanov <33452977+TblKBA@users.noreply.github.com> I
Ishani Madaan committed
997e572ac6441b33ab360366f64c55b17f54612b
Parent: 314a53b
Committed by GitHub <noreply@github.com>
on 9/13/2026, 2:13:01 PM