@@ -19,10 +19,6 @@ namespace MetaObjects;
1919/// </summary>
2020public static class SerializerJson
2121{
22- // Java int range — used for distinguishing int vs long attr subtypes.
23- private const long JavaIntMax = 2_147_483_647L ;
24- private const long JavaIntMin = - 2_147_483_648L ;
25-
2622 // ---------------------------------------------------------------------------
2723 // Public API
2824 // ---------------------------------------------------------------------------
@@ -34,7 +30,7 @@ public static class SerializerJson
3430 /// </summary>
3531 public static string CanonicalSerialize ( MetaData model )
3632 {
37- var nodeObj = SerializeNode ( model , inlineAttrs : true , effective : false ) ;
33+ var nodeObj = SerializeNode ( model , effective : false ) ;
3834 var sorted = SortAttrKeys ( nodeObj ) ! ;
3935 return Stringify ( sorted ) + "\n " ;
4036 }
@@ -47,7 +43,7 @@ public static string CanonicalSerialize(MetaData model)
4743 /// </summary>
4844 public static string CanonicalSerializeEffective ( MetaData model )
4945 {
50- var nodeObj = SerializeNode ( model , inlineAttrs : true , effective : true ) ;
46+ var nodeObj = SerializeNode ( model , effective : true ) ;
5147 var sorted = SortAttrKeys ( nodeObj ) ! ;
5248 return Stringify ( sorted ) + "\n " ;
5349 }
@@ -68,28 +64,6 @@ private static string Stringify(JsonNode node)
6864 return node . ToJsonString ( JsonOpts ) ;
6965 }
7066
71- // ---------------------------------------------------------------------------
72- // Infer attr subType from a runtime AttrValue (for child-node form)
73- // ---------------------------------------------------------------------------
74-
75- private static string InferAttrSubType ( object ? value )
76- {
77- return value switch
78- {
79- IReadOnlyList < string > => Constants . ATTR_SUBTYPE_STRINGARRAY ,
80- bool => Constants . ATTR_SUBTYPE_BOOLEAN ,
81- long l => ( l >= JavaIntMin && l <= JavaIntMax )
82- ? Constants . ATTR_SUBTYPE_INT
83- : Constants . ATTR_SUBTYPE_LONG ,
84- double d => Number . IsIntegerDouble ( d )
85- ? ( ( long ) d >= JavaIntMin && ( long ) d <= JavaIntMax
86- ? Constants . ATTR_SUBTYPE_INT
87- : Constants . ATTR_SUBTYPE_LONG )
88- : Constants . ATTR_SUBTYPE_DOUBLE ,
89- _ => Constants . ATTR_SUBTYPE_STRING ,
90- } ;
91- }
92-
9367 // ---------------------------------------------------------------------------
9468 // Build the fused "type.subType" wrapper key
9569 // ---------------------------------------------------------------------------
@@ -101,15 +75,15 @@ private static string FusedKey(string type, string subType)
10175 // Serialize a single node → { "<type>.<subType>": { ...body } }
10276 // ---------------------------------------------------------------------------
10377
104- private static JsonObject SerializeNode ( MetaData model , bool inlineAttrs , bool effective )
78+ private static JsonObject SerializeNode ( MetaData model , bool effective )
10579 {
106- var inner = SerializeNodeInner ( model , inlineAttrs , effective ) ;
80+ var inner = SerializeNodeInner ( model , effective ) ;
10781 var wrapper = new JsonObject ( ) ;
10882 wrapper . Add ( FusedKey ( model . Type , model . SubType ) , inner ) ;
10983 return wrapper ;
11084 }
11185
112- private static JsonObject SerializeNodeInner ( MetaData model , bool inlineAttrs , bool effective )
86+ private static JsonObject SerializeNodeInner ( MetaData model , bool effective )
11387 {
11488 // Canonical body-key order:
11589 // 1. name 2. package 3. extends 4. abstract
@@ -150,58 +124,23 @@ private static JsonObject SerializeNodeInner(MetaData model, bool inlineAttrs, b
150124 var childList = effective ? model . Children ( ) : model . OwnChildren ( ) ;
151125 var attrMap = effective ? model . Attrs ( ) : model . OwnAttrs ( ) ;
152126
153- // Walk children: structural children recurse; attr children emit either as
154- // inline @-attrs or as child {"attr.*": {...}} nodes.
155- var emittedAsChild = new HashSet < string > ( StringComparer . Ordinal ) ;
127+ // Walk children: structural children recurse. Attrs are ALWAYS emitted
128+ // inline as @-attrs (never as child {"attr.*": {...}} nodes), so attr-typed
129+ // children are skipped here — the C# parser dual-stores each attr both as a
130+ // child node and as a parent attr (Parser.cs:950-951), and the inline loop
131+ // below emits it from attrMap.
156132 var serializedChildren = new JsonArray ( ) ;
157133
158134 foreach ( var child in childList )
159135 {
160- if ( child . Type != Constants . TYPE_ATTR )
161- {
162- serializedChildren . Add ( SerializeNode ( child , inlineAttrs , effective ) ) ;
163- continue ;
164- }
165-
166- // Emit attr as child node form
167- var attrName = child . Name ;
168- var attrValue = child . OwnAttr ( Constants . RESERVED_KEY_VALUE ) ;
169- var attrSubType = child . SubType != Constants . SUBTYPE_BASE
170- ? child . SubType
171- : InferAttrSubType ( attrValue ?? "" ) ;
172-
173- var attrBody = new JsonObject
174- {
175- { Constants . RESERVED_KEY_NAME , JsonValue . Create ( attrName ) } ,
176- { Constants . RESERVED_KEY_VALUE , AttrValueToJsonNode ( attrValue ) } ,
177- } ;
178- var attrWrapper = new JsonObject ( ) ;
179- attrWrapper . Add ( FusedKey ( Constants . TYPE_ATTR , attrSubType ) , attrBody ) ;
180- serializedChildren . Add ( attrWrapper ) ;
181- emittedAsChild . Add ( attrName ) ;
136+ if ( child . Type == Constants . TYPE_ATTR ) continue ;
137+ serializedChildren . Add ( SerializeNode ( child , effective ) ) ;
182138 }
183139
184- // Inline @-attrs: emit attrs NOT already emitted as child nodes .
140+ // Inline @-attrs — always emitted as @name; attrs have no child form .
185141 foreach ( var ( attrName , attrValue ) in attrMap )
186142 {
187- if ( emittedAsChild . Contains ( attrName ) ) continue ;
188-
189- if ( inlineAttrs )
190- {
191- obj . Add ( $ "{ Constants . ATTR_PREFIX } { attrName } ", AttrValueToJsonNode ( attrValue ) ) ;
192- }
193- else
194- {
195- var subType = InferAttrSubType ( attrValue ) ;
196- var attrBody = new JsonObject
197- {
198- { Constants . RESERVED_KEY_NAME , JsonValue . Create ( attrName ) } ,
199- { Constants . RESERVED_KEY_VALUE , AttrValueToJsonNode ( attrValue ) } ,
200- } ;
201- var attrWrapper = new JsonObject ( ) ;
202- attrWrapper . Add ( FusedKey ( Constants . TYPE_ATTR , subType ) , attrBody ) ;
203- serializedChildren . Add ( attrWrapper ) ;
204- }
143+ obj . Add ( $ "{ Constants . ATTR_PREFIX } { attrName } ", AttrValueToJsonNode ( attrValue ) ) ;
205144 }
206145
207146 // children — emit only if non-empty
0 commit comments