mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-04 20:17:09 +00:00
feat(verifier): name extractors for diff surfacing
bindExtract accepts an optional name argument; falls back to extractor_N when omitted. The name is stored on extractorState alongside prev/curr value caches that the next change will use to emit per-step diffs.
This commit is contained in:
1 parent
cbef329cdd
commit
1b35e5a6a6
2 files changed
+39
-3
No files matched your search
@@ -10,6 +10,12 @@ import (
|
|||||||
type extractorState struct {
|
type extractorState struct {
|
||||||
getter goja.Callable
|
getter goja.Callable
|
||||||
handle *goja.Object
|
handle *goja.Object
|
||||||
|
name string
|
||||||
|
// prev/curr cache the JSON-encoded extractor values from the prior and
|
||||||
|
// current PushSnapshot, used by ChangedExtractors to surface per-step
|
||||||
|
// diffs in the trace.
|
||||||
|
prev []byte
|
||||||
|
curr []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type formulaState struct {
|
type formulaState struct {
|
||||||
@@ -139,19 +145,29 @@ func (v *Verifier) installRuntimeBindings() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *Verifier) bindExtract(call goja.FunctionCall) goja.Value {
|
func (v *Verifier) bindExtract(call goja.FunctionCall) goja.Value {
|
||||||
if len(call.Arguments) != 1 {
|
if len(call.Arguments) < 1 || len(call.Arguments) > 2 {
|
||||||
panic(v.runtime.NewTypeError("extract requires exactly one argument"))
|
panic(v.runtime.NewTypeError("extract requires (getter) or (getter, name)"))
|
||||||
}
|
}
|
||||||
getter, ok := goja.AssertFunction(call.Arguments[0])
|
getter, ok := goja.AssertFunction(call.Arguments[0])
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(v.runtime.NewTypeError("extract argument must be a function"))
|
panic(v.runtime.NewTypeError("extract argument must be a function"))
|
||||||
}
|
}
|
||||||
|
name := ""
|
||||||
|
if len(call.Arguments) == 2 {
|
||||||
|
arg := call.Arguments[1]
|
||||||
|
if !goja.IsUndefined(arg) && !goja.IsNull(arg) {
|
||||||
|
name = arg.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if name == "" {
|
||||||
|
name = fmt.Sprintf("extractor_%d", len(v.extractors))
|
||||||
|
}
|
||||||
|
|
||||||
handle := v.runtime.NewObject()
|
handle := v.runtime.NewObject()
|
||||||
_ = handle.Set("current", goja.Undefined())
|
_ = handle.Set("current", goja.Undefined())
|
||||||
_ = handle.Set("previous", goja.Undefined())
|
_ = handle.Set("previous", goja.Undefined())
|
||||||
|
|
||||||
v.extractors = append(v.extractors, &extractorState{getter: getter, handle: handle})
|
v.extractors = append(v.extractors, &extractorState{getter: getter, handle: handle, name: name})
|
||||||
return handle
|
return handle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -894,6 +894,26 @@ func TestSelectorStringFromJS_CanonicalGrammar(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestExtract_DefaultsAndNamedNames verifies bindExtract assigns a fallback
|
||||||
|
// `extractor_N` name when no name is supplied and respects an explicit one.
|
||||||
|
func TestExtract_DefaultsAndNamedNames(t *testing.T) {
|
||||||
|
verifier := newVerifier(t)
|
||||||
|
mustLoad(t, verifier, `
|
||||||
|
__sanderling__.extract(state => 1);
|
||||||
|
__sanderling__.extract(state => 2, "ledgerRows");
|
||||||
|
__sanderling__.extract(state => 3);
|
||||||
|
`)
|
||||||
|
if len(verifier.extractors) != 3 {
|
||||||
|
t.Fatalf("extractors registered: got %d, want 3", len(verifier.extractors))
|
||||||
|
}
|
||||||
|
want := []string{"extractor_0", "ledgerRows", "extractor_2"}
|
||||||
|
for i, name := range want {
|
||||||
|
if got := verifier.extractors[i].name; got != name {
|
||||||
|
t.Errorf("extractor %d name: got %q, want %q", i, got, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestSelectorStringFromJS_NullEmpty verifies that nil/undefined args produce
|
// TestSelectorStringFromJS_NullEmpty verifies that nil/undefined args produce
|
||||||
// an empty string instead of "null"/"undefined" garbage.
|
// an empty string instead of "null"/"undefined" garbage.
|
||||||
func TestSelectorStringFromJS_NullEmpty(t *testing.T) {
|
func TestSelectorStringFromJS_NullEmpty(t *testing.T) {
|
||||||
|
|||||||
Reference in new issue
Block a user