Browse Source

Added support for non-struct anonymous fields. Excluded unexported fields and methods from FieldNameMapper. Fixes #26.

Dmitry Panov 8 years ago
parent
commit
c67fd92e12
2 changed files with 56 additions and 15 deletions
  1. 17 15
      object_goreflect.go
  2. 39 0
      object_goreflect_test.go

+ 17 - 15
object_goreflect.go

@@ -415,13 +415,11 @@ func (r *Runtime) buildFieldInfo(t reflect.Type, index []int, info *reflectTypeI
 	n := t.NumField()
 	for i := 0; i < n; i++ {
 		field := t.Field(i)
-		var name string
-		if r.fieldNameMapper == nil {
-			name = field.Name
-			if !ast.IsExported(name) {
-				continue
-			}
-		} else {
+		name := field.Name
+		if !ast.IsExported(name) {
+			continue
+		}
+		if r.fieldNameMapper != nil {
 			name = r.fieldNameMapper.FieldName(t, field)
 			if name == "" {
 				continue
@@ -445,7 +443,13 @@ func (r *Runtime) buildFieldInfo(t reflect.Type, index []int, info *reflectTypeI
 			Anonymous: field.Anonymous,
 		}
 		if field.Anonymous {
-			r.buildFieldInfo(field.Type, idx, info)
+			typ := field.Type
+			for typ.Kind() == reflect.Ptr {
+				typ = typ.Elem()
+			}
+			if typ.Kind() == reflect.Struct {
+				r.buildFieldInfo(typ, idx, info)
+			}
 		}
 	}
 }
@@ -464,13 +468,11 @@ func (r *Runtime) buildTypeInfo(t reflect.Type) (info *reflectTypeInfo) {
 	info.MethodNames = make([]string, 0, n)
 	for i := 0; i < n; i++ {
 		method := t.Method(i)
-		var name string
-		if r.fieldNameMapper == nil {
-			name = method.Name
-			if !ast.IsExported(name) {
-				continue
-			}
-		} else {
+		name := method.Name
+		if !ast.IsExported(name) {
+			continue
+		}
+		if r.fieldNameMapper != nil {
 			name = r.fieldNameMapper.MethodName(t, method)
 			if name == "" {
 				continue

+ 39 - 0
object_goreflect_test.go

@@ -2,6 +2,7 @@ package goja
 
 import (
 	"reflect"
+	"strings"
 	"testing"
 )
 
@@ -546,6 +547,44 @@ func TestGoReflectCustomNaming(t *testing.T) {
 	})
 }
 
+type fieldNameMapper1 struct{}
+
+func (fieldNameMapper1) FieldName(t reflect.Type, f reflect.StructField) string {
+	return strings.ToLower(f.Name)
+}
+
+func (fieldNameMapper1) MethodName(t reflect.Type, m reflect.Method) string {
+	return m.Name
+}
+
+func TestNonStructAnonFields(t *testing.T) {
+	type Test1 struct {
+		M bool
+	}
+	type test3 []int
+	type Test4 []int
+	type Test2 struct {
+		test3
+		Test4
+		*Test1
+	}
+
+	const SCRIPT = `
+	JSON.stringify(a);
+	a.m && a.test3 === undefined && a.test4.length === 2
+	`
+	vm := New()
+	vm.SetFieldNameMapper(fieldNameMapper1{})
+	vm.Set("a", &Test2{Test1: &Test1{M: true}, Test4: []int{1, 2}})
+	v, err := vm.RunString(SCRIPT)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !v.StrictEquals(valueTrue) {
+		t.Fatalf("Unexepected result: %v", v)
+	}
+}
+
 func BenchmarkGoReflectGet(b *testing.B) {
 	type parent struct {
 		field, Test1, Test2, Test3, Test4, Test5, Test string