@@ -4,12 +4,16 @@ import (
44 "encoding/json"
55 "fmt"
66 "os"
7+ "regexp"
78 "strconv"
89 "strings"
910
1011 "yapi.run/cli/internal/vars"
1112)
1213
14+ // arrayIndexPattern matches path segments with array indices like "tracks[0]" or "items[123]"
15+ var arrayIndexPattern = regexp .MustCompile (`^(.+?)\[(\d+)\]$` )
16+
1317// StepResult holds the output of a single chain step.
1418type StepResult struct {
1519 BodyRaw string
@@ -142,18 +146,9 @@ func (c *ChainContext) resolveChainVar(key string) (string, error) {
142146}
143147
144148func jsonPathLookup (data any , path []string ) (string , error ) {
145- current := data
146- for i , key := range path {
147- switch v := current .(type ) {
148- case map [string ]any :
149- val , ok := v [key ]
150- if ! ok {
151- return "" , fmt .Errorf ("key '%s' not found at path '%s'" , key , strings .Join (path [:i + 1 ], "." ))
152- }
153- current = val
154- default :
155- return "" , fmt .Errorf ("path segment '%s' is not an object" , strings .Join (path [:i ], "." ))
156- }
149+ current , err := jsonPathLookupRaw (data , path )
150+ if err != nil {
151+ return "" , err
157152 }
158153 // Convert final value to string
159154 switch v := current .(type ) {
@@ -235,19 +230,46 @@ func (c *ChainContext) ResolveVariableRaw(input string) (any, bool) {
235230 return val , true
236231}
237232
238- // jsonPathLookupRaw returns the raw typed value at the given path
233+ // jsonPathLookupRaw returns the raw typed value at the given path.
234+ // Supports array indexing like "tracks[0]" or "items[2]".
239235func jsonPathLookupRaw (data any , path []string ) (any , error ) {
240236 current := data
241- for i , key := range path {
242- switch v := current .(type ) {
243- case map [string ]any :
244- val , ok := v [key ]
237+ for i , segment := range path {
238+ // Check if segment contains array index like "tracks[0]"
239+ if match := arrayIndexPattern .FindStringSubmatch (segment ); match != nil {
240+ key := match [1 ]
241+ idx , _ := strconv .Atoi (match [2 ]) // regex guarantees valid int
242+
243+ // First, access the map key
244+ m , ok := current .(map [string ]any )
245+ if ! ok {
246+ return nil , fmt .Errorf ("path segment '%s' is not an object" , strings .Join (path [:i ], "." ))
247+ }
248+ val , ok := m [key ]
249+ if ! ok {
250+ return nil , fmt .Errorf ("key '%s' not found at path '%s'" , key , strings .Join (path [:i ], "." )+ "." + key )
251+ }
252+
253+ // Then, access the array index
254+ arr , ok := val .([]any )
255+ if ! ok {
256+ return nil , fmt .Errorf ("'%s' is not an array" , key )
257+ }
258+ if idx < 0 || idx >= len (arr ) {
259+ return nil , fmt .Errorf ("index %d out of bounds for array '%s' (length %d)" , idx , key , len (arr ))
260+ }
261+ current = arr [idx ]
262+ } else {
263+ // Regular map key access
264+ m , ok := current .(map [string ]any )
265+ if ! ok {
266+ return nil , fmt .Errorf ("path segment '%s' is not an object" , strings .Join (path [:i ], "." ))
267+ }
268+ val , ok := m [segment ]
245269 if ! ok {
246- return nil , fmt .Errorf ("key '%s' not found at path '%s'" , key , strings .Join (path [:i + 1 ], "." ))
270+ return nil , fmt .Errorf ("key '%s' not found at path '%s'" , segment , strings .Join (path [:i + 1 ], "." ))
247271 }
248272 current = val
249- default :
250- return nil , fmt .Errorf ("path segment '%s' is not an object" , strings .Join (path [:i ], "." ))
251273 }
252274 }
253275 return current , nil
0 commit comments