SIGN IN SIGN UP

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