diff --git a/eval.go b/eval.go index e689c31..b5be9e4 100644 --- a/eval.go +++ b/eval.go @@ -364,6 +364,14 @@ func (v *evalVisitor) evalMethod(ctx reflect.Value, name string, exprRoot bool) } if !method.IsValid() { + // Special case for "length" for slices, arrays to provide the same behaviour as JavaScript engines + // where the "length" method is implicit. + if name == "length" { + switch ctx.Kind() { + case reflect.Slice, reflect.Array, reflect.String: + return reflect.ValueOf(ctx.Len()), true + } + } return zero, false } diff --git a/eval_test.go b/eval_test.go index 5115cb9..be0adf8 100644 --- a/eval_test.go +++ b/eval_test.go @@ -72,6 +72,27 @@ var evalTests = []Test{ nil, nil, nil, "C", }, + { + "length method on a slice, like with JS engines", + "Length: {{arr.length}}", + map[string]interface{}{"arr": []int{0, 1, 2}}, + nil, nil, nil, + `Length: 3`, + }, + { + "length method on an array, like with JS engines", + "Length: {{arr.length}}", + map[string]interface{}{"arr": [...]int{0, 1, 2, 3}}, + nil, nil, nil, + `Length: 4`, + }, + { + "length method on a string, like with JS engines", + "Length: {{str.length}}", + map[string]interface{}{"str": "abcde"}, + nil, nil, nil, + `Length: 5`, + }, // @todo Test with a "../../path" (depth 2 path) while context is only depth 1 }