agent_patch
runs/2026-02-28__13-38-10__gpt-5-3-codex/flux-pr-817/flux-pr-817.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/agent-logs/agent.patch
21304 bytes
diff --git a/app/v2/pkg/engine/argumenttemplate/argument_template.go b/app/v2/pkg/engine/argumenttemplate/argument_template.go
new file mode 100644
index 0000000..dade16d
--- /dev/null
+++ b/app/v2/pkg/engine/argumenttemplate/argument_template.go
@@ -0,0 +1,170 @@
+package argumenttemplate
+
+import (
+ "fmt"
+ "regexp"
+ "strings"
+
+ "github.com/wundergraph/graphql-go-tools/v2/pkg/ast"
+)
+
+var argumentTemplateRegex = regexp.MustCompile(`{{\s*args((?:\.[a-zA-Z0-9_]+)+)\s*}}`)
+
+type Match struct {
+ Start int
+ End int
+ Path []string
+}
+
+type ResolvedMatch struct {
+ Match
+ VariablePath []string
+ VariableTypeRef int
+}
+
+func Parse(value string) []Match {
+ indices := argumentTemplateRegex.FindAllStringSubmatchIndex(value, -1)
+ if len(indices) == 0 {
+ return nil
+ }
+
+ out := make([]Match, 0, len(indices))
+ for _, idx := range indices {
+ // idx contains full match [0:2] and first submatch [2:4]
+ if len(idx) < 4 {
+ continue
+ }
+ path := value[idx[2]:idx[3]]
+ if len(path) < 2 {
+ continue
+ }
+ out = append(out, Match{
+ Start: idx[0],
+ End: idx[1],
+ Path: strings.Split(path[1:], "."),
+ })
+ }
+ return out
+}
+
+func Resolve(operation, definition *ast.Document, operationDefinitionRef, fieldRef int, value string) ([]ResolvedMatch, error) {
+ matches := Parse(value)
+ if len(matches) == 0 {
+ return nil, nil
+ }
+
+ out := make([]ResolvedMatch, 0, len(matches))
+ for _, match := range matches {
+ argumentName := match.Path[0]
+ argumentRef, ok := operation.FieldArgument(fieldRef, []byte(argumentName))
+ if !ok {
+ return nil, fmt.Errorf(`field argument "%s" is not defined`, argumentName)
+ }
+
+ argumentValue := operation.ArgumentValue(argumentRef)
+ if argumentValue.Kind != ast.ValueKindVariable {
+ return nil, fmt.Errorf(`expected argument "%s" kind to be "ValueKindVariable" but received "%s"`, argumentName, argumentValue.Kind)
+ }
+
+ variableNameBytes := operation.VariableValueNameBytes(argumentValue.Ref)
+ variableDefinitionRef, ok := operation.VariableDefinitionByNameAndOperation(operationDefinitionRef, variableNameBytes)
+ if !ok {
+ return nil, fmt.Errorf(`expected definition to exist for variable "%s"`, variableNameBytes)
+ }
+
+ variableTypeRef := operation.VariableDefinitions[variableDefinitionRef].Type
+ if err := validateArgumentPath(definition, operation, variableTypeRef, match.Path[1:]); err != nil {
+ return nil, fmt.Errorf(`invalid argument template path "%s": %w`, strings.Join(match.Path, "."), err)
+ }
+
+ variablePath := append([]string{string(variableNameBytes)}, match.Path[1:]...)
+ out = append(out, ResolvedMatch{
+ Match: match,
+ VariablePath: variablePath,
+ VariableTypeRef: variableTypeRef,
+ })
+ }
+
+ return out, nil
+}
+
+func validateArgumentPath(definition, typeDoc *ast.Document, typeRef int, nestedPath []string) error {
+ if len(nestedPath) == 0 {
+ if !isLeafType(definition, typeDoc, typeRef) {
+ return fmt.Errorf("template must resolve to a leaf input type")
+ }
+ return nil
+ }
+
+ currentTypeDoc := typeDoc
+ currentTypeRef := typeRef
+
+ for _, segment := range nestedPath {
+ if currentTypeDoc.TypeIsList(currentTypeRef) {
+ return fmt.Errorf("cannot select nested field %q on list type %q", segment, currentTypeDoc.ResolveTypeNameString(currentTypeRef))
+ }
+
+ typeName := currentTypeDoc.ResolveTypeNameString(currentTypeRef)
+ node, ok := definition.Index.FirstNodeByNameStr(typeName)
+ if !ok {
+ return fmt.Errorf("type %q not found in schema", typeName)
+ }
+ if node.Kind != ast.NodeKindInputObjectTypeDefinition {
+ return fmt.Errorf("cannot select nested field %q on non-input-object type %q", segment, typeName)
+ }
+
+ fieldRef := definition.InputObjectTypeDefinitionInputValueDefinitionByName(node.Ref, []byte(segment))
+ if fieldRef == -1 {
+ return fmt.Errorf("field %q not found on input object %q", segment, typeName)
+ }
+
+ currentTypeDoc = definition
+ currentTypeRef = definition.InputValueDefinitions[fieldRef].Type
+ }
+
+ if !isLeafType(definition, currentTypeDoc, currentTypeRef) {
+ return fmt.Errorf("template must resolve to a leaf input type")
+ }
+
+ return nil
+}
+
+func isLeafType(definition, typeDoc *ast.Document, typeRef int) bool {
+ typeName := typeDoc.ResolveTypeNameString(typeRef)
+ node, ok := definition.Index.FirstNodeByNameStr(typeName)
+ if !ok {
+ return false
+ }
+
+ return node.Kind == ast.NodeKindScalarTypeDefinition || node.Kind == ast.NodeKindEnumTypeDefinition
+}
+
+func ValidateNATSSubject(subject string, allowWildcards bool) error {
+ if subject == "" {
+ return fmt.Errorf("subject must not be empty")
+ }
+ if strings.ContainsAny(subject, " \t\r\n") {
+ return fmt.Errorf("subject must not contain whitespace")
+ }
+
+ tokens := strings.Split(subject, ".")
+ for i, token := range tokens {
+ if token == "" {
+ return fmt.Errorf("subject token at index %d must not be empty", i)
+ }
+ if strings.ContainsAny(token, "*>") {
+ if !allowWildcards {
+ return fmt.Errorf("subject token %q contains wildcard", token)
+ }
+ if token == "*" {
+ continue
+ }
+ if token == ">" && i == len(tokens)-1 {
+ continue
+ }
+ return fmt.Errorf("subject token %q has invalid wildcard usage", token)
+ }
+ }
+
+ return nil
+}
diff --git a/app/v2/pkg/engine/argumenttemplate/argument_template_test.go b/app/v2/pkg/engine/argumenttemplate/argument_template_test.go
new file mode 100644
index 0000000..f0d743a
--- /dev/null
+++ b/app/v2/pkg/engine/argumenttemplate/argument_template_test.go
@@ -0,0 +1,78 @@
+package argumenttemplate
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "github.com/wundergraph/graphql-go-tools/v2/pkg/ast"
+ "github.com/wundergraph/graphql-go-tools/v2/pkg/asttransform"
+ "github.com/wundergraph/graphql-go-tools/v2/pkg/internal/unsafeparser"
+)
+
+func TestResolve(t *testing.T) {
+ definition := unsafeparser.ParseGraphqlDocumentString(`
+ type Query {
+ user(id: ID!, input: UserInput!): String!
+ }
+
+ input UserInput {
+ id: ID!
+ nested: UserNestedInput!
+ }
+
+ input UserNestedInput {
+ name: String!
+ }
+ `)
+ require.NoError(t, asttransform.MergeDefinitionWithBaseSchema(&definition))
+
+ operation := unsafeparser.ParseGraphqlDocumentString(`
+ query UserQuery($id: ID!, $input: UserInput!) {
+ user(id: $id, input: $input)
+ }
+ `)
+
+ operationDefinitionRef, fieldRef := operationAndFieldRef(t, &operation)
+
+ t.Run("resolves multiple templates", func(t *testing.T) {
+ resolved, err := Resolve(&operation, &definition, operationDefinitionRef, fieldRef, "prefix.{{ args.id }}.{{ args.input.id }}")
+ require.NoError(t, err)
+ require.Len(t, resolved, 2)
+ require.Equal(t, []string{"id"}, resolved[0].Path)
+ require.Equal(t, []string{"id"}, resolved[0].VariablePath)
+ require.Equal(t, []string{"input", "id"}, resolved[1].Path)
+ require.Equal(t, []string{"input", "id"}, resolved[1].VariablePath)
+ })
+
+ t.Run("fails when nested segment does not exist", func(t *testing.T) {
+ _, err := Resolve(&operation, &definition, operationDefinitionRef, fieldRef, "{{ args.input.unknown }}")
+ require.Error(t, err)
+ require.ErrorContains(t, err, `field "unknown" not found`)
+ })
+
+ t.Run("fails when path ends on non-leaf type", func(t *testing.T) {
+ _, err := Resolve(&operation, &definition, operationDefinitionRef, fieldRef, "{{ args.input }}")
+ require.Error(t, err)
+ require.ErrorContains(t, err, "leaf input type")
+ })
+}
+
+func TestValidateNATSSubject(t *testing.T) {
+ require.NoError(t, ValidateNATSSubject("events.user.123", false))
+ require.NoError(t, ValidateNATSSubject("events.*.>", true))
+ require.Error(t, ValidateNATSSubject("events..123", false))
+ require.Error(t, ValidateNATSSubject("events.user.>", false))
+}
+
+func operationAndFieldRef(t *testing.T, operation *ast.Document) (int, int) {
+ t.Helper()
+
+ require.NotEmpty(t, operation.OperationDefinitions)
+ operationDefinitionRef := 0
+ selectionSetRef := operation.OperationDefinitions[operationDefinitionRef].SelectionSet
+ require.NotEmpty(t, operation.SelectionSets[selectionSetRef].SelectionRefs)
+ selectionRef := operation.SelectionSets[selectionSetRef].SelectionRefs[0]
+ require.Equal(t, ast.SelectionKindField, operation.Selections[selectionRef].Kind)
+
+ return operationDefinitionRef, operation.Selections[selectionRef].Ref
+}
diff --git a/tmp/agent-patch-flux-pr-817.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/datasource/pubsub_datasource/nats_event_manager.go b/app/v2/pkg/engine/datasource/pubsub_datasource/nats_event_manager.go
index 1cb2914..773019e 100644
--- a/tmp/agent-patch-flux-pr-817.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/datasource/pubsub_datasource/nats_event_manager.go
+++ b/app/v2/pkg/engine/datasource/pubsub_datasource/nats_event_manager.go
@@ -3,7 +3,9 @@ package pubsub_datasource
import (
"encoding/json"
"fmt"
- "github.com/wundergraph/graphql-go-tools/v2/pkg/ast"
+ "strings"
+
+ "github.com/wundergraph/graphql-go-tools/v2/pkg/engine/argumenttemplate"
"github.com/wundergraph/graphql-go-tools/v2/pkg/engine/plan"
"github.com/wundergraph/graphql-go-tools/v2/pkg/engine/resolve"
"slices"
@@ -35,37 +37,50 @@ type NatsEventManager struct {
}
func (p *NatsEventManager) extractEventSubject(ref int, subject string) (string, error) {
- matches := eventSubjectRegex.FindAllStringSubmatch(subject, -1)
- if len(matches) != 1 || len(matches[0]) != 2 {
- return "", fmt.Errorf("expected subject to match regex")
- }
- argumentName := matches[0][1]
- // We need to find the argument in the operation
- argumentRef, ok := p.visitor.Operation.FieldArgument(ref, []byte(argumentName))
- if !ok {
- return "", fmt.Errorf("argument \"%s\" is not defined", argumentName)
- }
- argumentValue := p.visitor.Operation.ArgumentValue(argumentRef)
- if argumentValue.Kind != ast.ValueKindVariable {
- return "", fmt.Errorf("expected argument \"%s\" kind to be \"ValueKindVariable\" but received \"%s\"", argumentName, argumentValue.Kind)
- }
- variableName := p.visitor.Operation.VariableValueNameBytes(argumentValue.Ref)
- variableDefinition, ok := p.visitor.Operation.VariableDefinitionByNameAndOperation(p.visitor.Walker.Ancestors[0].Ref, variableName)
- if !ok {
- return "", fmt.Errorf("expected definition to exist for variable \"%s\"", variableName)
- }
- variableTypeRef := p.visitor.Operation.VariableDefinitions[variableDefinition].Type
- renderer, err := resolve.NewPlainVariableRendererWithValidationFromTypeRef(p.visitor.Operation, p.visitor.Definition, variableTypeRef, string(variableName))
+ matches, err := argumenttemplate.Resolve(
+ p.visitor.Operation,
+ p.visitor.Definition,
+ p.visitor.Walker.Ancestors[0].Ref,
+ ref,
+ subject,
+ )
if err != nil {
return "", err
}
- contextVariable := &resolve.ContextVariable{
- Path: []string{string(variableName)},
- Renderer: renderer,
+
+ result := subject
+ if len(matches) > 0 {
+ var output strings.Builder
+ output.Grow(len(subject))
+ cursor := 0
+ for _, match := range matches {
+ output.WriteString(subject[cursor:match.Start])
+ renderer, err := resolve.NewPlainVariableRendererWithValidationFromTypeRef(
+ p.visitor.Operation,
+ p.visitor.Definition,
+ match.VariableTypeRef,
+ match.VariablePath...,
+ )
+ if err != nil {
+ return "", err
+ }
+ contextVariable := &resolve.ContextVariable{
+ Path: match.VariablePath,
+ Renderer: renderer,
+ }
+ variablePlaceHolder, _ := p.variables.AddVariable(contextVariable) // $$0$$
+ output.WriteString(variablePlaceHolder)
+ cursor = match.End
+ }
+ output.WriteString(subject[cursor:])
+ result = output.String()
+ }
+
+ allowWildcards := p.eventMetadata.Type == EventTypeSubscribe
+ if err := argumenttemplate.ValidateNATSSubject(result, allowWildcards); err != nil {
+ return "", err
}
- // We need to replace the template literal with the variable placeholder (and reuse if it already exists)
- variablePlaceHolder, _ := p.variables.AddVariable(contextVariable) // $$0$$
- return eventSubjectRegex.ReplaceAllLiteralString(subject, variablePlaceHolder), nil
+ return result, nil
}
func (p *NatsEventManager) eventDataBytes(ref int) ([]byte, error) {
diff --git a/tmp/agent-patch-flux-pr-817.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/datasource/pubsub_datasource/pubsub_datasource.go b/app/v2/pkg/engine/datasource/pubsub_datasource/pubsub_datasource.go
index 02b05d3..4c62615 100644
--- a/tmp/agent-patch-flux-pr-817.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/datasource/pubsub_datasource/pubsub_datasource.go
+++ b/app/v2/pkg/engine/datasource/pubsub_datasource/pubsub_datasource.go
@@ -5,7 +5,6 @@ import (
"context"
"encoding/json"
"fmt"
- "regexp"
"strings"
"github.com/jensneuse/abstractlogger"
@@ -23,8 +22,6 @@ const (
EventTypeSubscribe EventType = "subscribe"
)
-var eventSubjectRegex = regexp.MustCompile(`{{ args.([a-zA-Z0-9_]+) }}`)
-
func EventTypeFromString(s string) (EventType, error) {
et := EventType(strings.ToLower(s))
switch et {
diff --git a/tmp/agent-patch-flux-pr-817.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/datasource/pubsub_datasource/pubsub_datasource_test.go b/app/v2/pkg/engine/datasource/pubsub_datasource/pubsub_datasource_test.go
index 2c817b1..f700092 100644
--- a/tmp/agent-patch-flux-pr-817.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/datasource/pubsub_datasource/pubsub_datasource_test.go
+++ b/app/v2/pkg/engine/datasource/pubsub_datasource/pubsub_datasource_test.go
@@ -44,6 +44,7 @@ func TestPubSub(t *testing.T) {
type Subscription {
helloSubscription(id: String!): String! @eventsSubscribe(subjects: ["helloSubscription.{{ args.id }}"])
subscriptionWithMultipleSubjects(firstId: String!, secondId: String!): String! @eventsSubscribe(subjects: ["firstSubscription.{{ args.firstId }}", "secondSubscription.{{ args.secondId }}"])
+ subscriptionWithMultipleTemplatesInSingleSubject(firstId: String!, secondId: String!): String! @eventsSubscribe(subjects: ["combined.{{ args.firstId }}.{{ args.secondId }}"])
}`
dataSourceCustomConfig := Configuration{
@@ -92,6 +93,17 @@ func TestPubSub(t *testing.T) {
Subjects: []string{"firstSubscription.{{ args.firstId }}", "secondSubscription.{{ args.secondId }}"},
},
},
+ {
+ Metadata: &EventMetadata{
+ ProviderID: "default",
+ FieldName: "subscriptionWithMultipleTemplatesInSingleSubject",
+ Type: EventTypeSubscribe,
+ TypeName: "Subscription",
+ },
+ Configuration: &NatsEventConfiguration{
+ Subjects: []string{"combined.{{ args.firstId }}.{{ args.secondId }}"},
+ },
+ },
},
}
@@ -116,6 +128,10 @@ func TestPubSub(t *testing.T) {
TypeName: "Subscription",
FieldNames: []string{"subscriptionWithMultipleSubjects"},
},
+ {
+ TypeName: "Subscription",
+ FieldNames: []string{"subscriptionWithMultipleTemplatesInSingleSubject"},
+ },
},
},
dataSourceCustomConfig,
@@ -171,6 +187,20 @@ func TestPubSub(t *testing.T) {
},
},
},
+ {
+ TypeName: "Subscription",
+ FieldName: "subscriptionWithMultipleTemplatesInSingleSubject",
+ Arguments: []plan.ArgumentConfiguration{
+ {
+ Name: "firstId",
+ SourceType: plan.FieldArgumentSource,
+ },
+ {
+ Name: "secondId",
+ SourceType: plan.FieldArgumentSource,
+ },
+ },
+ },
},
DisableResolveFieldPositions: true,
}
@@ -332,4 +362,45 @@ func TestPubSub(t *testing.T) {
}
datasourcetesting.RunTest(schema, operation, operationName, expect, planConfig)(t)
})
+
+ t.Run("subscription with multiple templates in a single subject", func(t *testing.T) {
+ const operation = "subscription SubscriptionWithMultipleTemplatesInSingleSubject { subscriptionWithMultipleTemplatesInSingleSubject(firstId: 11, secondId: 23) }"
+ const operationName = `SubscriptionWithMultipleTemplatesInSingleSubject`
+ expect := &plan.SubscriptionResponsePlan{
+ Response: &resolve.GraphQLSubscription{
+ Trigger: resolve.GraphQLSubscriptionTrigger{
+ Input: []byte(`{"providerId":"default","subjects":["combined.$$0$$.$$1$$"]}`),
+ Variables: resolve.Variables{
+ &resolve.ContextVariable{
+ Path: []string{"a"},
+ Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string"]}`),
+ },
+ &resolve.ContextVariable{
+ Path: []string{"b"},
+ Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string"]}`),
+ },
+ },
+ Source: &NatsSubscriptionSource{
+ pubSub: &testPubsub{},
+ },
+ PostProcessing: resolve.PostProcessingConfiguration{
+ MergePath: []string{"subscriptionWithMultipleTemplatesInSingleSubject"},
+ },
+ },
+ Response: &resolve.GraphQLResponse{
+ Data: &resolve.Object{
+ Fields: []*resolve.Field{
+ {
+ Name: []byte("subscriptionWithMultipleTemplatesInSingleSubject"),
+ Value: &resolve.String{
+ Path: []string{"subscriptionWithMultipleTemplatesInSingleSubject"},
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+ datasourcetesting.RunTest(schema, operation, operationName, expect, planConfig)(t)
+ })
}
diff --git a/tmp/agent-patch-flux-pr-817.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/configuration_visitor.go b/app/v2/pkg/engine/plan/configuration_visitor.go
index b5e2ed1..ea3aafc 100644
--- a/tmp/agent-patch-flux-pr-817.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/configuration_visitor.go
+++ b/app/v2/pkg/engine/plan/configuration_visitor.go
@@ -3,7 +3,6 @@ package plan
import (
"bytes"
"fmt"
- "regexp"
"slices"
"strings"
@@ -12,6 +11,7 @@ import (
"github.com/wundergraph/graphql-go-tools/v2/pkg/ast"
"github.com/wundergraph/graphql-go-tools/v2/pkg/astvisitor"
+ "github.com/wundergraph/graphql-go-tools/v2/pkg/engine/argumenttemplate"
"github.com/wundergraph/graphql-go-tools/v2/pkg/engine/resolve"
)
@@ -870,13 +870,6 @@ func (c *configurationVisitor) buildSubscriptionFilterCondition(condition Subscr
return filter
}
-var (
- // subscriptionFieldFilterRegex is used to extract the variable name from the subscription filter condition
- // e.g. {{ args.id }} -> id
- // e.g. {{ args.input.id }} -> input.id
- subscriptionFieldFilterRegex = regexp.MustCompile(`{{\s*args((?:\.[a-zA-Z0-9_]+)+)\s*}}`)
-)
-
// ContainsTemplateString checks if the value contains a template string
func ContainsTemplateString(value []byte) bool {
return bytes.Contains(value, []byte("{{"))
@@ -887,7 +880,11 @@ func (c *configurationVisitor) buildSubscriptionFieldFilter(condition *Subscript
filter.FieldPath = condition.FieldPath
filter.Values = make([]resolve.InputTemplate, len(condition.Values))
for i, value := range condition.Values {
- matches := subscriptionFieldFilterRegex.FindAllStringSubmatchIndex(value, -1)
+ parsedMatches := argumenttemplate.Parse(value)
+ if len(parsedMatches) > 1 {
+ return nil
+ }
+ matches, err := argumenttemplate.Resolve(c.operation, c.definition, c.walker.Ancestors[0].Ref, c.fieldRef, value)
if len(matches) == 0 {
filter.Values[i].Segments = []resolve.TemplateSegment{
{
@@ -897,26 +894,15 @@ func (c *configurationVisitor) buildSubscriptionFieldFilter(condition *Subscript
}
continue
}
- if len(matches) == 1 && len(matches[0]) == 4 {
- prefix := value[:matches[0][0]]
+ if err != nil {
+ c.walker.StopWithInternalErr(err)
+ return nil
+ }
+ if len(matches) == 1 {
+ match := matches[0]
+ prefix := value[:match.Start]
hasPrefix := len(prefix) > 0
- // the path begins with ".", so ignore the first empty string element with trailing [1:]
- argumentPath := strings.Split(value[matches[0][2]:matches[0][3]][1:], ".")
- argumentName := argumentPath[0]
- argumentRef, ok := c.operation.FieldArgument(c.fieldRef, []byte(argumentName))
- if !ok {
- c.walker.StopWithInternalErr(fmt.Errorf(`field argument "%s" is not defined`, argumentName))
- return nil
- }
- argumentValue := c.operation.ArgumentValue(argumentRef)
- if argumentValue.Kind != ast.ValueKindVariable {
- c.walker.StopWithInternalErr(fmt.Errorf(`expected argument "%s" kind to be "ValueKindVariable" but received "%s"`, argumentName, argumentValue.Kind))
- return nil
- }
- variableName := c.operation.VariableValueNameString(argumentValue.Ref)
- // the variable path should be the variable name, e.g., "a", and then the 2nd element from the path onwards
- variablePath := append([]string{variableName}, argumentPath[1:]...)
- suffix := value[matches[0][1]:]
+ suffix := value[match.End:]
hasSuffix := len(suffix) > 0
size := 1
if hasPrefix {
@@ -938,7 +924,7 @@ func (c *configurationVisitor) buildSubscriptionFieldFilter(condition *Subscript
SegmentType: resolve.VariableSegmentType,
VariableKind: resolve.ContextVariableKind,
Renderer: resolve.NewPlainVariableRenderer(),
- VariableSourcePath: variablePath,
+ VariableSourcePath: match.VariablePath,
}
if hasSuffix {
filter.Values[i].Segments[idx+1] = resolve.TemplateSegment{