diff --git a/v2/internal/binding/binding.go b/v2/internal/binding/binding.go index a27d1d038..f972b7179 100755 --- a/v2/internal/binding/binding.go +++ b/v2/internal/binding/binding.go @@ -8,6 +8,7 @@ import ( "path/filepath" "reflect" "runtime" + "sort" "strings" "github.com/wailsapp/wails/v2/internal/typescriptify" @@ -83,7 +84,7 @@ func (b *Bindings) ToJSON() (string, error) { return b.db.ToJSON() } -func (b *Bindings) WriteModels(modelsDir string) error { +func (b *Bindings) GenerateModels() ([]byte, error) { models := map[string]string{} var seen slicer.StringSlicer allStructNames := b.getAllStructNames() @@ -102,15 +103,23 @@ func (b *Bindings) WriteModels(modelsDir string) error { } str, err := w.Convert(nil) if err != nil { - return err + return nil, err } thisPackageCode += str seen.AddSlice(w.GetGeneratedStructs()) models[packageName] = thisPackageCode } + // Sort the package names first to make the output deterministic + sortedPackageNames := make([]string, 0) + for packageName := range models { + sortedPackageNames = append(sortedPackageNames, packageName) + } + sort.Strings(sortedPackageNames) + var modelsData bytes.Buffer - for packageName, modelData := range models { + for _, packageName := range sortedPackageNames { + modelData := models[packageName] if strings.TrimSpace(modelData) == "" { continue } @@ -121,14 +130,22 @@ func (b *Bindings) WriteModels(modelsDir string) error { } modelsData.WriteString("\n}\n\n") } + return modelsData.Bytes(), nil +} +func (b *Bindings) WriteModels(modelsDir string) error { + + modelsData, err := b.GenerateModels() + if err != nil { + return err + } // Don't write if we don't have anything - if len(modelsData.Bytes()) == 0 { + if len(modelsData) == 0 { return nil } filename := filepath.Join(modelsDir, "models.ts") - err := os.WriteFile(filename, modelsData.Bytes(), 0755) + err = os.WriteFile(filename, modelsData, 0755) if err != nil { return err } @@ -147,7 +164,7 @@ func (b *Bindings) AddStructToGenerateTS(packageName string, structName string, // Iterate this struct and add any struct field references structType := reflect.TypeOf(s) - if structType.Kind() == reflect.Ptr { + if hasElements(structType) { structType = structType.Elem() } @@ -169,11 +186,11 @@ func (b *Bindings) AddStructToGenerateTS(packageName string, structName string, s := reflect.Indirect(a).Interface() b.AddStructToGenerateTS(pName, sName, s) } - } else if kind == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct { + } else if hasElements(field.Type) && field.Type.Elem().Kind() == reflect.Struct { if !field.IsExported() { continue } - fqname := field.Type.String() + fqname := field.Type.Elem().String() sName := strings.Split(fqname, ".")[1] pName := getPackageName(fqname) typ := field.Type.Elem() diff --git a/v2/internal/binding/binding_test/binding_escapedname_test.go b/v2/internal/binding/binding_test/binding_escapedname_test.go new file mode 100644 index 000000000..1bf6ce3ad --- /dev/null +++ b/v2/internal/binding/binding_test/binding_escapedname_test.go @@ -0,0 +1,32 @@ +package binding_test + +type EscapedName struct { + Name string `json:"n.a.m.e"` +} + +func (s EscapedName) Get() EscapedName { + return s +} + +var EscapedNameTest = BindingTest{ + name: "EscapedName", + structs: []interface{}{ + &EscapedName{}, + }, + exemptions: nil, + shouldError: false, + want: ` +export namespace binding_test { + export class EscapedName { + "n.a.m.e": string; + static createFrom(source: any = {}) { + return new EscapedName(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this["n.a.m.e"] = source["n.a.m.e"]; + } + } +} +`, +} diff --git a/v2/internal/binding/binding_test/binding_importedmap_test.go b/v2/internal/binding/binding_test/binding_importedmap_test.go new file mode 100644 index 000000000..54fb261a8 --- /dev/null +++ b/v2/internal/binding/binding_test/binding_importedmap_test.go @@ -0,0 +1,94 @@ +package binding_test + +import "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import" + +type ImportedMap struct { + AMapWrapperContainer binding_test_import.AMapWrapper `json:"AMapWrapperContainer"` +} + +func (s ImportedMap) Get() ImportedMap { + return s +} + +var ImportedMapTest = BindingTest{ + name: "ImportedMap", + structs: []interface{}{ + &ImportedMap{}, + }, + exemptions: nil, + shouldError: false, + want: ` +export namespace binding_test { + export class ImportedMap { + AMapWrapperContainer: binding_test_import.AMapWrapper; + static createFrom(source: any = {}) { + return new ImportedMap(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.AMapWrapperContainer = this.convertValues(source["AMapWrapperContainer"], binding_test_import.AMapWrapper); + } + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + if (a.slice) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } +} + +export namespace binding_test_import { + export class AMapWrapper { + AMap: {[key: string]: binding_test_nestedimport.A}; + static createFrom(source: any = {}) { + return new AMapWrapper(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.AMap = this.convertValues(source["AMap"], binding_test_nestedimport.A, true); + } + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + if (a.slice) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } +} + +export namespace binding_test_nestedimport { + export class A { + A: string; + static createFrom(source: any = {}) { + return new A(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.A = source["A"]; + } + } +} +`, +} diff --git a/v2/internal/binding/binding_test/binding_importedslice_test.go b/v2/internal/binding/binding_test/binding_importedslice_test.go new file mode 100644 index 000000000..b4a63689c --- /dev/null +++ b/v2/internal/binding/binding_test/binding_importedslice_test.go @@ -0,0 +1,94 @@ +package binding_test + +import "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import" + +type ImportedSlice struct { + ASliceWrapperContainer binding_test_import.ASliceWrapper `json:"ASliceWrapperContainer"` +} + +func (s ImportedSlice) Get() ImportedSlice { + return s +} + +var ImportedSliceTest = BindingTest{ + name: "ImportedSlice", + structs: []interface{}{ + &ImportedSlice{}, + }, + exemptions: nil, + shouldError: false, + want: ` +export namespace binding_test { + export class ImportedSlice { + ASliceWrapperContainer: binding_test_import.ASliceWrapper; + static createFrom(source: any = {}) { + return new ImportedSlice(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.ASliceWrapperContainer = this.convertValues(source["ASliceWrapperContainer"], binding_test_import.ASliceWrapper); + } + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + if (a.slice) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } +} + +export namespace binding_test_import { + export class ASliceWrapper { + ASlice: binding_test_nestedimport.A[]; + static createFrom(source: any = {}) { + return new ASliceWrapper(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.ASlice = this.convertValues(source["ASlice"], binding_test_nestedimport.A); + } + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + if (a.slice) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } +} + +export namespace binding_test_nestedimport { + export class A { + A: string; + static createFrom(source: any = {}) { + return new A(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.A = source["A"]; + } + } +} +`, +} diff --git a/v2/internal/binding/binding_test/binding_importedstruct_test.go b/v2/internal/binding/binding_test/binding_importedstruct_test.go new file mode 100644 index 000000000..1629be9fa --- /dev/null +++ b/v2/internal/binding/binding_test/binding_importedstruct_test.go @@ -0,0 +1,95 @@ +package binding_test + +import "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import" + +type ImportedStruct struct { + AWrapperContainer binding_test_import.AWrapper `json:"AWrapperContainer"` +} + +func (s ImportedStruct) Get() ImportedStruct { + return s +} + +var ImportedStructTest = BindingTest{ + name: "ImportedStruct", + structs: []interface{}{ + &ImportedStruct{}, + }, + exemptions: nil, + shouldError: false, + want: ` +export namespace binding_test { + export class ImportedStruct { + AWrapperContainer: binding_test_import.AWrapper; + static createFrom(source: any = {}) { + return new ImportedStruct(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.AWrapperContainer = this.convertValues(source["AWrapperContainer"], binding_test_import.AWrapper); + } + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + + if (a.slice) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } +} + +export namespace binding_test_import { + export class AWrapper { + AWrapper: binding_test_nestedimport.A; + static createFrom(source: any = {}) { + return new AWrapper(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.AWrapper = this.convertValues(source["AWrapper"], binding_test_nestedimport.A); + } + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + if (a.slice) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } +} + +export namespace binding_test_nestedimport { + export class A { + A: string; + static createFrom(source: any = {}) { + return new A(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.A = source["A"]; + } + } +} +`, +} diff --git a/v2/internal/binding/binding_test/binding_nestedfield_test.go b/v2/internal/binding/binding_test/binding_nestedfield_test.go new file mode 100644 index 000000000..c2e4fcf9f --- /dev/null +++ b/v2/internal/binding/binding_test/binding_nestedfield_test.go @@ -0,0 +1,63 @@ +package binding_test + +type As struct { + B Bs `json:"b"` +} + +type Bs struct { + Name string `json:"name"` +} + +func (a As) Get() As { + return a +} + +var NestedFieldTest = BindingTest{ + name: "NestedField", + structs: []interface{}{ + &As{}, + }, + exemptions: nil, + shouldError: false, + want: ` +export namespace binding_test { + export class Bs { + name: string; + static createFrom(source: any = {}) { + return new Bs(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.name = source["name"]; + } + } + export class As { + b: Bs; + static createFrom(source: any = {}) { + return new As(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.b = this.convertValues(source["b"], Bs); + } + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + if (a.slice) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } +} +`, +} diff --git a/v2/internal/binding/binding_test/binding_nonstringmapkey_test.go b/v2/internal/binding/binding_test/binding_nonstringmapkey_test.go new file mode 100644 index 000000000..37a61dd29 --- /dev/null +++ b/v2/internal/binding/binding_test/binding_nonstringmapkey_test.go @@ -0,0 +1,32 @@ +package binding_test + +type NonStringMapKey struct { + NumberMap map[uint]any `json:"numberMap"` +} + +func (s NonStringMapKey) Get() NonStringMapKey { + return s +} + +var NonStringMapKeyTest = BindingTest{ + name: "NonStringMapKey", + structs: []interface{}{ + &NonStringMapKey{}, + }, + exemptions: nil, + shouldError: false, + want: ` +export namespace binding_test { + export class NonStringMapKey { + numberMap: {[key: number]: any}; + static createFrom(source: any = {}) { + return new NonStringMapKey(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.numberMap = source["numberMap"]; + } + } +} +`, +} diff --git a/v2/internal/binding/binding_test/binding_singlefield_test.go b/v2/internal/binding/binding_test/binding_singlefield_test.go new file mode 100644 index 000000000..2919ab29e --- /dev/null +++ b/v2/internal/binding/binding_test/binding_singlefield_test.go @@ -0,0 +1,32 @@ +package binding_test + +type SingleField struct { + Name string `json:"name"` +} + +func (s SingleField) Get() SingleField { + return s +} + +var SingleFieldTest = BindingTest{ + name: "SingleField", + structs: []interface{}{ + &SingleField{}, + }, + exemptions: nil, + shouldError: false, + want: ` +export namespace binding_test { + export class SingleField { + name: string; + static createFrom(source: any = {}) { + return new SingleField(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.name = source["name"]; + } + } +} +`, +} diff --git a/v2/internal/binding/binding_test/binding_test.go b/v2/internal/binding/binding_test/binding_test.go new file mode 100644 index 000000000..f41507112 --- /dev/null +++ b/v2/internal/binding/binding_test/binding_test.go @@ -0,0 +1,51 @@ +package binding_test + +import ( + "reflect" + "strings" + "testing" + + "github.com/stretchr/testify/require" + "github.com/wailsapp/wails/v2/internal/binding" + "github.com/wailsapp/wails/v2/internal/logger" +) + +type BindingTest struct { + name string + structs []interface{} + exemptions []interface{} + want string + shouldError bool +} + +func TestBindings_GenerateModels(t *testing.T) { + + tests := []BindingTest{ + EscapedNameTest, + ImportedStructTest, + ImportedSliceTest, + ImportedMapTest, + NestedFieldTest, + NonStringMapKeyTest, + SingleFieldTest, + } + + testLogger := &logger.Logger{} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := binding.NewBindings(testLogger, tt.structs, tt.exemptions, false) + for _, s := range tt.structs { + err := b.Add(s) + require.NoError(t, err) + } + got, err := b.GenerateModels() + if (err != nil) != tt.shouldError { + t.Errorf("GenerateModels() error = %v, shouldError %v", err, tt.shouldError) + return + } + if !reflect.DeepEqual(strings.Fields(string(got)), strings.Fields(tt.want)) { + t.Errorf("GenerateModels() got = %v, want %v", string(got), tt.want) + } + }) + } +} diff --git a/v2/internal/binding/binding_test/binding_test_import/binding_test_import.go b/v2/internal/binding/binding_test/binding_test_import/binding_test_import.go new file mode 100644 index 000000000..6b99d43be --- /dev/null +++ b/v2/internal/binding/binding_test/binding_test_import/binding_test_import.go @@ -0,0 +1,15 @@ +package binding_test_import + +import "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import/binding_test_nestedimport" + +type AWrapper struct { + AWrapper binding_test_nestedimport.A `json:"AWrapper"` +} + +type ASliceWrapper struct { + ASlice []binding_test_nestedimport.A `json:"ASlice"` +} + +type AMapWrapper struct { + AMap map[string]binding_test_nestedimport.A `json:"AMap"` +} diff --git a/v2/internal/binding/binding_test/binding_test_import/binding_test_nestedimport/binding_nestedimport.go b/v2/internal/binding/binding_test/binding_test_import/binding_test_nestedimport/binding_nestedimport.go new file mode 100644 index 000000000..31c70ad3f --- /dev/null +++ b/v2/internal/binding/binding_test/binding_test_import/binding_test_nestedimport/binding_nestedimport.go @@ -0,0 +1,5 @@ +package binding_test_nestedimport + +type A struct { + A string `json:"A"` +} diff --git a/v2/internal/binding/reflect.go b/v2/internal/binding/reflect.go index 6572407f9..deef09ffe 100755 --- a/v2/internal/binding/reflect.go +++ b/v2/internal/binding/reflect.go @@ -165,3 +165,8 @@ func getPackageName(in string) string { result = strings.ReplaceAll(result, "*", "") return result } + +func hasElements(typ reflect.Type) bool { + kind := typ.Kind() + return kind == reflect.Ptr || kind == reflect.Array || kind == reflect.Slice || kind == reflect.Map +} diff --git a/v2/internal/typescriptify/typescriptify.go b/v2/internal/typescriptify/typescriptify.go index 8419801e2..35ee3c100 100644 --- a/v2/internal/typescriptify/typescriptify.go +++ b/v2/internal/typescriptify/typescriptify.go @@ -3,14 +3,16 @@ package typescriptify import ( "bufio" "fmt" - "github.com/leaanthony/slicer" "io/ioutil" "os" "path" "reflect" + "regexp" "strings" "time" + "github.com/leaanthony/slicer" + "github.com/tkrajina/go-reflector/reflector" ) @@ -34,6 +36,7 @@ const ( } return a; }` + jsVariableNameRegex = `^([A-Z]|[a-z]|\$|_)([A-Z]|[a-z]|[0-9]|\$|_)*$` ) // TypeOptions overrides options set by `ts_*` tags. @@ -266,20 +269,34 @@ func (t *typeScriptClassBuilder) AddMapField(fieldName string, field reflect.Str if valueType.Kind() == reflect.Ptr { valueTypeName = valueType.Elem().Name() } + if valueType.Kind() == reflect.Struct && differentNamespaces(t.namespace, valueType) { + valueTypeName = valueType.String() + } strippedFieldName := strings.ReplaceAll(fieldName, "?", "") + isOptional := strings.HasSuffix(fieldName, "?") - keyTypeStr := keyType.Name() - // Key should always be string, no need for this: - // _, isSimple := t.types[keyType.Kind()] - // if !isSimple { - // keyTypeStr = t.prefix + keyType.Name() + t.suffix - // } + keyTypeStr := "" + // Key should always be a JS primitive. JS will read it as a string either way. + if typeStr, isSimple := t.types[keyType.Kind()]; isSimple { + keyTypeStr = typeStr + } else { + keyTypeStr = t.types[reflect.String] + } + var dotField string + if regexp.MustCompile(jsVariableNameRegex).Match([]byte(strippedFieldName)) { + dotField = fmt.Sprintf(".%s", strippedFieldName) + } else { + dotField = fmt.Sprintf(`["%s"]`, strippedFieldName) + if isOptional { + fieldName = fmt.Sprintf(`"%s"?`, strippedFieldName) + } + } t.fields = append(t.fields, fmt.Sprintf("%s%s: {[key: %s]: %s};", t.indent, fieldName, keyTypeStr, valueTypeName)) if valueType.Kind() == reflect.Struct { - t.constructorBody = append(t.constructorBody, fmt.Sprintf("%s%sthis.%s = this.convertValues(source[\"%s\"], %s, true);", t.indent, t.indent, strippedFieldName, strippedFieldName, t.prefix+valueTypeName+t.suffix)) + t.constructorBody = append(t.constructorBody, fmt.Sprintf("%s%sthis%s = this.convertValues(source[\"%s\"], %s, true);", t.indent, t.indent, dotField, strippedFieldName, t.prefix+valueTypeName+t.suffix)) } else { - t.constructorBody = append(t.constructorBody, fmt.Sprintf("%s%sthis.%s = source[\"%s\"];", t.indent, t.indent, strippedFieldName, strippedFieldName)) + t.constructorBody = append(t.constructorBody, fmt.Sprintf("%s%sthis%s = source[\"%s\"];", t.indent, t.indent, dotField, strippedFieldName)) } } @@ -571,11 +588,8 @@ func (t *TypeScriptify) convertType(depth int, typeOf reflect.Type, customCode m return "", nil } t.logf(depth, "Converting type %s", typeOf.String()) - if strings.ContainsRune(typeOf.String(), '.') { - namespace := strings.Split(typeOf.String(), ".")[0] - if namespace != t.Namespace { - return "", nil - } + if differentNamespaces(t.Namespace, typeOf) { + return "", nil } t.alreadyConverted[typeOf.String()] = true @@ -829,17 +843,34 @@ func (t *typeScriptClassBuilder) AddStructField(fieldName string, field reflect. func (t *typeScriptClassBuilder) AddArrayOfStructsField(fieldName string, field reflect.StructField, arrayDepth int) { fieldType := field.Type.Elem().Name() + if differentNamespaces(t.namespace, field.Type.Elem()) { + fieldType = field.Type.Elem().String() + } strippedFieldName := strings.ReplaceAll(fieldName, "?", "") t.addField(fieldName, fmt.Sprint(t.prefix+fieldType+t.suffix, strings.Repeat("[]", arrayDepth)), false) t.addInitializerFieldLine(strippedFieldName, fmt.Sprintf("this.convertValues(source[\"%s\"], %s)", strippedFieldName, t.prefix+fieldType+t.suffix)) } func (t *typeScriptClassBuilder) addInitializerFieldLine(fld, initializer string) { - t.createFromMethodBody = append(t.createFromMethodBody, fmt.Sprint(t.indent, t.indent, "result.", fld, " = ", initializer, ";")) - t.constructorBody = append(t.constructorBody, fmt.Sprint(t.indent, t.indent, "this.", fld, " = ", initializer, ";")) + var dotField string + if regexp.MustCompile(jsVariableNameRegex).Match([]byte(fld)) { + dotField = fmt.Sprintf(".%s", fld) + } else { + dotField = fmt.Sprintf(`["%s"]`, fld) + } + t.createFromMethodBody = append(t.createFromMethodBody, fmt.Sprint(t.indent, t.indent, "result", dotField, " = ", initializer, ";")) + t.constructorBody = append(t.constructorBody, fmt.Sprint(t.indent, t.indent, "this", dotField, " = ", initializer, ";")) } func (t *typeScriptClassBuilder) addField(fld, fldType string, isAnyType bool) { + isOptional := strings.HasSuffix(fld, "?") + strippedFieldName := strings.ReplaceAll(fld, "?", "") + if !regexp.MustCompile(jsVariableNameRegex).Match([]byte(strippedFieldName)) { + fld = fmt.Sprintf(`"%s"`, fld) + if isOptional { + fld += "?" + } + } if isAnyType { t.fields = append(t.fields, fmt.Sprint(t.indent, "// Go type: ", fldType, "\n", t.indent, fld, ": any;")) } else { @@ -860,3 +891,13 @@ func getStructFQN(in string) string { result = strings.ReplaceAll(result, "*", "") return result } + +func differentNamespaces(namespace string, typeOf reflect.Type) bool { + if strings.ContainsRune(typeOf.String(), '.') { + typeNamespace := strings.Split(typeOf.String(), ".")[0] + if namespace != typeNamespace { + return true + } + } + return false +}