Repository navigation
Conversation
The parser's IntegerValue rule reads an unquoted run of digits that is followed directly by ";" or "," as a number. A value written without a trailing comment, such as the buildConfigurationList or productReference of a target from addTarget(), or the remoteGlobalIDString of a PBXContainerItemProxy from addTargetDependency(), therefore comes back from a write and a parse as a number when its id is all digits. The next write prints it in scientific notation (1.2345678901243459e+23), and the reference names no object. About 1 random id in 60,000 is all digits, so generateUuid() now mints again when it gets one, as it already does on a collision.
Mocks crypto.randomUUID() to return an all-digit UUID and then a normal one, and checks that generateUuid() returns the second.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #196 +/- ##
==========================================
+ Coverage 97.41% 97.42% +0.01%
==========================================
Files 52 52
Lines 11164 11178 +14
==========================================
+ Hits 10875 10890 +15
+ Misses 289 288 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
I tried digging into this issue a little and can confirm seeing the scientific notation in certain cases.
From what I can see, the issue comes from the parser.
For example, if an all-numeric UUID is followed by a comment, it is parsed as a string, but if it ends with a semicolon (;), its would be parsed as a number. This is because of the combination of the IntegerValue and NonTerminator, which you pointed out in the PR description.
I also agree that the underlying issue is the parser itself. But I think the writer, on the other hand, isnt the apart of the root problem. When I reviewed the outputted project.pbxproj file, it appeared correct.
All in all, I believe generating an all-numeric UUID is relatively low. But, I think this PR would mitigate the issue by avoiding all-numeric UUIDs.
There might be a performance hit if regeneration is triggered frequently, but it might be a rare case.
I also want to mention that if a project already contains an all-numeric UUID in the pbxproj file, the parsing issue will still occur. This PR does not resolve the parser. I think a long term goal would be to fix the parser, as you mentioned as one of the options, but would require heavy testing to ensure that the changes doesn't break other areas.
As for this PR, I think its OK
Motivation and Context
generateUuid()builds an id from the first 24 hex characters of a random UUID, so sometimes it generates only decimal digits.The pbxproj grammar reads such an id as a number whenever no comment follows it:
Several references this library writes have no trailing comment:
buildConfigurationListandproductReferenceof a target fromaddTarget();remoteGlobalIDStringof thePBXContainerItemProxyfromaddTargetDependency().When one of those ids is all digits, the first write is still correct. Parsing that file returns the reference as a number, though, and the next write prints it in scientific notation:
The reference then names no object. Any tool that writes a project and later parses and writes it again can hit this. For example, Expo's prebuild re-reads the project it has just written during its entitlements step.
Description
generateUuid()now mints again when the id is all digits, the same way it already does on a collision. Other ids are unaffected.The underlying problem is in the parser and the writer. A project produced by another tool can contain an all-digit id too, and a round trip through this library corrupts that one the same way. A complete fix would be one of these:
Both change how existing projects parse or print. This PR keeps to the minimal change that stops the library from creating such ids. I'm happy to follow up with a parser or writer change if you prefer that approach.
Reproduction
Run from a checkout of this repository:
On
master(940d6db):With this change:
Testing
test/pbxProject.jsgets a new test,should not return an id made only of digits. It mockscrypto.randomUUID()to return an all-digit UUID and then a normal one, and checks thatgenerateUuid()returns the second. Without the fix,generateUuid()returns123456789012434586789012and the test fails.npm test(lint and all 436 tests) passes on Node 22.