@@ -37,11 +37,25 @@ export class JsonVisitor extends BaseVisitor {
3737 }
3838
3939 objectItem ( ctx : any ) {
40+ // Object keys must always be strings, even if they're numeric
41+ const key = this . visitIdentifierAsString ( ctx . identifier ) ;
4042 return {
41- [ this . visit ( ctx . identifier ) ] : this . visit ( ctx . value ) ,
43+ [ key ] : this . visit ( ctx . value ) ,
4244 } ;
4345 }
4446
47+ /** Visit an identifier and ensure the result is always a string (used for object keys) */
48+ visitIdentifierAsString ( identifierCtx : any ) {
49+ // Extract the actual context - identifierCtx is an array with a single item containing children
50+ const ctx = identifierCtx [ 0 ] ?. children || identifierCtx ;
51+ if ( ctx . QuotedString ) {
52+ return ctx . QuotedString [ 0 ] . payload ?? ctx . QuotedString [ 0 ] . image ;
53+ } else if ( ctx . StringLiteral ) {
54+ return ctx . StringLiteral [ 0 ] . payload ?? ctx . StringLiteral [ 0 ] . image ;
55+ }
56+ throw new Error ( "unhandled identifier: " + JSON . stringify ( identifierCtx ) ) ;
57+ }
58+
4559 identifier ( ctx : any ) {
4660 if ( ctx . QuotedString ) {
4761 return ctx . QuotedString [ 0 ] . payload ?? ctx . QuotedString [ 0 ] . image ;
@@ -71,7 +85,19 @@ function parseType(literal: string): number | string {
7185 if ( / ^ 0 \d + $ / . test ( literal ) ) {
7286 return literal ;
7387 }
74-
88+
89+ // Handle integers - check if they're safe to convert
90+ if ( / ^ \d + $ / . test ( literal ) ) {
91+ const num = parseInt ( literal , 10 ) ;
92+ // Only convert to number if it's within JavaScript's safe integer range
93+ // Xcode UUIDs are often 24 characters which exceed MAX_SAFE_INTEGER
94+ if ( ! isNaN ( num ) && Number . isSafeInteger ( num ) ) {
95+ return num ;
96+ }
97+ // Preserve as string if too large
98+ return literal ;
99+ }
100+
75101 // Handle decimal numbers but preserve trailing zeros
76102 if ( / ^ [ + - ] ? ( [ 0 - 9 ] + \. ? [ 0 - 9 ] * | \. [ 0 - 9 ] + ) $ / . test ( literal ) ) {
77103 if ( / 0 $ / . test ( literal ) ) {
@@ -80,12 +106,6 @@ function parseType(literal: string): number | string {
80106 const num = parseFloat ( literal ) ;
81107 if ( ! isNaN ( num ) ) return num ;
82108 }
83-
84- // Handle integers
85- if ( / ^ \d + $ / . test ( literal ) ) {
86- const num = parseInt ( literal , 10 ) ;
87- if ( ! isNaN ( num ) ) return num ;
88- }
89-
109+
90110 return literal ;
91111}
0 commit comments