@@ -18,7 +18,8 @@ package debug
18
18
import (
19
19
"context"
20
20
"encoding/json"
21
- "regexp"
21
+ "slices"
22
+ "strconv"
22
23
"strings"
23
24
24
25
"github.com/arduino/arduino-cli/arduino"
@@ -210,33 +211,89 @@ func getDebugProperties(req *rpc.GetDebugConfigRequest, pme *packagemanager.Expl
210
211
// my.indexed.array.2=third
211
212
//
212
213
// into the corresponding JSON arrays.
214
+ // If a value should be converted into a JSON type different from string, the value
215
+ // may be prefiex with "[boolean]", "[number]", or "[object]":
216
+ //
217
+ // my.stringValue=a string
218
+ // my.booleanValue=[boolean]true
219
+ // my.numericValue=[number]20
213
220
func convertToJsonMap (in * properties.Map ) string {
214
- // XXX: Maybe this method could be a good candidate for propertis.Map?
215
-
216
- // Find the values that should be kept as is, and the indexed arrays
217
- // that should be later converted into arrays.
218
- arraysKeys := map [string ]bool {}
219
- stringKeys := []string {}
220
- trailingNumberMatcher := regexp .MustCompile (`^(.*)\.[0-9]+$` )
221
- for _ , k := range in .Keys () {
222
- match := trailingNumberMatcher .FindAllStringSubmatch (k , - 1 )
223
- if len (match ) > 0 && len (match [0 ]) > 1 {
224
- arraysKeys [match [0 ][1 ]] = true
225
- } else {
226
- stringKeys = append (stringKeys , k )
221
+ data , _ := json .MarshalIndent (convertToRawInterface (in ), "" , " " )
222
+ return string (data )
223
+ }
224
+
225
+ func allNumerics (in []string ) bool {
226
+ for _ , i := range in {
227
+ for _ , c := range i {
228
+ if c < '0' || c > '9' {
229
+ return false
230
+ }
227
231
}
228
232
}
233
+ return true
234
+ }
229
235
230
- // Compose a map that can be later marshaled into JSON keeping
231
- // the arrays where they are expected to be.
232
- res := map [string ]any {}
233
- for _ , k := range stringKeys {
234
- res [k ] = in .Get (k )
236
+ func convertToRawInterface (in * properties.Map ) any {
237
+ subtrees := in .FirstLevelOf ()
238
+ keys := in .FirstLevelKeys ()
239
+
240
+ if allNumerics (keys ) {
241
+ // Compose an array
242
+ res := []any {}
243
+ slices .SortFunc (keys , func (x , y string ) int {
244
+ nx , _ := strconv .Atoi (x )
245
+ ny , _ := strconv .Atoi (y )
246
+ return nx - ny
247
+ })
248
+ for _ , k := range keys {
249
+ switch {
250
+ case subtrees [k ] != nil :
251
+ res = append (res , convertToRawInterface (subtrees [k ]))
252
+ default :
253
+ res = append (res , convertToRawValue (in .Get (k )))
254
+ }
255
+ }
256
+ return res
235
257
}
236
- for k := range arraysKeys {
237
- res [k ] = in .ExtractSubIndexLists (k )
258
+
259
+ // Compose an object
260
+ res := map [string ]any {}
261
+ for _ , k := range keys {
262
+ switch {
263
+ case subtrees [k ] != nil :
264
+ res [k ] = convertToRawInterface (subtrees [k ])
265
+ default :
266
+ res [k ] = convertToRawValue (in .Get (k ))
267
+ }
238
268
}
269
+ return res
270
+ }
239
271
240
- data , _ := json .MarshalIndent (res , "" , " " )
241
- return string (data )
272
+ func convertToRawValue (v string ) any {
273
+ switch {
274
+ case strings .HasPrefix (v , "[boolean]" ):
275
+ v = strings .TrimSpace (strings .TrimPrefix (v , "[boolean]" ))
276
+ if strings .EqualFold (v , "true" ) {
277
+ return true
278
+ } else if strings .EqualFold (v , "false" ) {
279
+ return false
280
+ }
281
+ case strings .HasPrefix (v , "[number]" ):
282
+ v = strings .TrimPrefix (v , "[number]" )
283
+ if i , err := strconv .Atoi (v ); err == nil {
284
+ return i
285
+ } else if f , err := strconv .ParseFloat (v , 64 ); err == nil {
286
+ return f
287
+ }
288
+ case strings .HasPrefix (v , "[object]" ):
289
+ v = strings .TrimPrefix (v , "[object]" )
290
+ var o interface {}
291
+ if err := json .Unmarshal ([]byte (v ), & o ); err == nil {
292
+ return o
293
+ }
294
+ case strings .HasPrefix (v , "[string]" ):
295
+ v = strings .TrimPrefix (v , "[string]" )
296
+ }
297
+ // default or conversion error, return string as is
298
+ return v
242
299
}
0 commit comments