support bridge and makeTS
This commit is contained in:
		
							parent
							
								
									e9c25edc20
								
							
						
					
					
						commit
						31df7db22d
					
				
							
								
								
									
										2
									
								
								args.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								args.go
									
									
									
									
									
								
							| @ -25,7 +25,7 @@ type Obj struct { | ||||
| 
 | ||||
| func GetLogger(vm *goja.Runtime) *log.Logger { | ||||
| 	var logger *log.Logger | ||||
| 	if vm.GoData["logger"] != nil { | ||||
| 	if vm != nil && vm.GoData != nil && vm.GoData["logger"] != nil { | ||||
| 		if logger1, ok := vm.GoData["logger"].(*log.Logger); ok { | ||||
| 			logger = logger1 | ||||
| 		} | ||||
|  | ||||
							
								
								
									
										255
									
								
								bridge.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								bridge.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,255 @@ | ||||
| package gojs | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 
 | ||||
| 	"apigo.cc/gojs/goja" | ||||
| 	"github.com/ssgo/u" | ||||
| ) | ||||
| 
 | ||||
| func ToJS(in any) any { | ||||
| 	return go2js(in, 0) | ||||
| } | ||||
| 
 | ||||
| func ToMap(in any) Map { | ||||
| 	jsValue := go2js(in, 0) | ||||
| 	if mapValue, ok := jsValue.(Map); ok { | ||||
| 		return mapValue | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func go2js(in any, n int) any { | ||||
| 	if n > 100 { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	var v reflect.Value | ||||
| 	if inV, ok := in.(reflect.Value); ok { | ||||
| 		v = inV | ||||
| 	} else { | ||||
| 		v = reflect.ValueOf(in) | ||||
| 	} | ||||
| 	for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { | ||||
| 		if v.IsNil() { | ||||
| 			return nil | ||||
| 		} | ||||
| 		v = v.Elem() | ||||
| 	} | ||||
| 	if (v.Kind() == reflect.Slice || v.Kind() == reflect.Map || v.Kind() == reflect.Func) && v.IsNil() { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if v.Kind() == reflect.Struct { | ||||
| 		v = reflect.ValueOf(MakeMap(in)) | ||||
| 	} | ||||
| 	switch v.Kind() { | ||||
| 	case reflect.Slice: | ||||
| 		if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 { | ||||
| 			arr := make([]any, v.Len()) | ||||
| 			for i := 0; i < v.Len(); i++ { | ||||
| 				o := go2js(v.Index(i), n+1) | ||||
| 				arr[i] = o | ||||
| 			} | ||||
| 			return arr | ||||
| 		} else { | ||||
| 			return in | ||||
| 		} | ||||
| 	case reflect.Map: | ||||
| 		o := map[string]any{} | ||||
| 		for _, k2 := range v.MapKeys() { | ||||
| 			k2s := u.String(u.FinalValue(k2).Interface()) | ||||
| 			if len(k2s) > 0 && k2s[0] != '_' { | ||||
| 				v2 := go2js(v.MapIndex(k2), n+1) | ||||
| 				o[k2s] = v2 | ||||
| 			} | ||||
| 		} | ||||
| 		return o | ||||
| 	case reflect.Func: | ||||
| 		// skip goja supported functions | ||||
| 		switch v.Type().String() { | ||||
| 		case "func(goja.FunctionCall) goja.Value": | ||||
| 			return in | ||||
| 		case "func(goja.FunctionCall, *goja.Runtime) goja.Value": | ||||
| 			return in | ||||
| 		case "func(goja.ConstructorCall) *goja.Object": | ||||
| 			return in | ||||
| 		case "func(goja.ConstructorCall, *goja.Runtime) *goja.Object": | ||||
| 			return in | ||||
| 		} | ||||
| 
 | ||||
| 		t := v.Type() | ||||
| 		return func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { | ||||
| 			needArgs := make([]reflect.Type, 0) | ||||
| 			realArgs := make([]reflect.Value, t.NumIn()) | ||||
| 			needArgsIndex := map[int]int{} | ||||
| 			for i := 0; i < t.NumIn(); i++ { | ||||
| 				inTypeString := t.In(i).String() | ||||
| 
 | ||||
| 				if inTypeString == "*goja.Runtime" { | ||||
| 					realArgs[i] = reflect.ValueOf(vm) | ||||
| 					continue | ||||
| 				} else if inTypeString == "goja.Value" { | ||||
| 					realArgs[i] = reflect.ValueOf(argsIn.This) | ||||
| 					continue | ||||
| 				} | ||||
| 				if !realArgs[i].IsValid() { | ||||
| 					needArgs = append(needArgs, t.In(i)) | ||||
| 					needArgsIndex[len(needArgsIndex)] = i | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			for i, needArgType := range needArgs { | ||||
| 				var argValue reflect.Value | ||||
| 				isLastVariadicArg := false | ||||
| 				realNeedArgType := needArgType | ||||
| 				if needArgType.Kind() == reflect.Ptr { | ||||
| 					realNeedArgType = needArgType.Elem() | ||||
| 				} | ||||
| 
 | ||||
| 				if v.Type().IsVariadic() && needArgsIndex[i] == len(realArgs)-1 { | ||||
| 					// 可变参数函数的最后一个使用成员类型 | ||||
| 					isLastVariadicArg = true | ||||
| 					argValue = reflect.New(needArgType.Elem()) | ||||
| 				} else { | ||||
| 					argValue = reflect.New(needArgType) | ||||
| 				} | ||||
| 				if i > len(argsIn.Arguments)-1 { | ||||
| 					if !isLastVariadicArg && needArgType.Kind() != reflect.Interface && needArgType.Kind() != reflect.Ptr { | ||||
| 						panic(vm.NewGoError(fmt.Errorf("no enough args, need %d, given %d", len(needArgs), len(argsIn.Arguments)))) | ||||
| 					} | ||||
| 					realArgs[needArgsIndex[i]] = reflect.ValueOf(argValue.Interface()).Elem() | ||||
| 				} else if realNeedArgType.Kind() == reflect.Func { | ||||
| 					jsFunc, ok := goja.AssertFunction(argsIn.Arguments[i]) | ||||
| 					if !ok { | ||||
| 						panic(vm.NewGoError(fmt.Errorf("%s not a function", argsIn.Arguments[i].ExportType().String()))) | ||||
| 					} | ||||
| 
 | ||||
| 					funcType := realNeedArgType | ||||
| 					argValue = reflect.MakeFunc(funcType, func(goArgs []reflect.Value) []reflect.Value { | ||||
| 						ins := make([]goja.Value, 0) | ||||
| 						j := 0 | ||||
| 						for i := 0; i < len(goArgs); i++ { | ||||
| 							if j >= funcType.NumIn() { | ||||
| 								break | ||||
| 							} | ||||
| 							var jV any | ||||
| 							if funcType.IsVariadic() && j == funcType.NumIn()-1 && funcType.In(j).Kind() == reflect.Slice { | ||||
| 								jV = reflect.New(funcType.In(j).Elem()).Interface() | ||||
| 							} else { | ||||
| 								jV = reflect.New(funcType.In(j)).Interface() | ||||
| 								j++ | ||||
| 							} | ||||
| 							u.Convert(goArgs[i].Interface(), jV) | ||||
| 							// ins = append(ins, MakeJsValue(vm, reflect.ValueOf(jV).Elem(), false)) | ||||
| 							ins = append(ins, vm.ToValue(jV)) | ||||
| 						} | ||||
| 
 | ||||
| 						outs := make([]reflect.Value, 0) | ||||
| 						jsResult, err := jsFunc(argsIn.This, ins...) | ||||
| 
 | ||||
| 						if funcType.NumOut() == 1 { | ||||
| 							// 只有一个返回值 | ||||
| 							if funcType.Out(0).String() != "error" { | ||||
| 								out0P := reflect.New(funcType.Out(0)).Interface() | ||||
| 								u.Convert(jsResult.Export(), out0P) | ||||
| 								outs = append(outs, reflect.ValueOf(out0P).Elem()) | ||||
| 							} else { | ||||
| 								if err == nil { | ||||
| 									outs = append(outs, reflect.New(funcType.Out(0)).Elem()) | ||||
| 								} else { | ||||
| 									outs = append(outs, reflect.ValueOf(err)) | ||||
| 								} | ||||
| 							} | ||||
| 						} else if funcType.NumOut() > 1 { | ||||
| 							// 以数组形式返回多个值 | ||||
| 							rArr := make([]any, 0) | ||||
| 							if err == nil { | ||||
| 								if jsResult.ExportType().Kind() == reflect.Slice && jsResult.ExportType().Elem().Kind() != reflect.Uint8 { | ||||
| 									vm.ForOf(jsResult, func(v goja.Value) bool { | ||||
| 										rArr = append(rArr, v.Export()) | ||||
| 										return true | ||||
| 									}) | ||||
| 								} | ||||
| 							} | ||||
| 							k := 0 | ||||
| 							for j := 0; j < funcType.NumOut(); j++ { | ||||
| 								if funcType.Out(j).String() != "error" { | ||||
| 									if k < len(rArr) { | ||||
| 										out0P := reflect.New(funcType.Out(j)).Interface() | ||||
| 										u.Convert(rArr[k], out0P) | ||||
| 										k++ | ||||
| 										outs = append(outs, reflect.ValueOf(out0P).Elem()) | ||||
| 									} else { | ||||
| 										outs = append(outs, reflect.New(funcType.Out(j)).Elem()) | ||||
| 									} | ||||
| 								} else { | ||||
| 									if err == nil { | ||||
| 										outs = append(outs, reflect.New(funcType.Out(j)).Elem()) | ||||
| 									} else { | ||||
| 										outs = append(outs, reflect.ValueOf(err)) | ||||
| 									} | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 						return outs | ||||
| 					}) | ||||
| 					if needArgType.Kind() == reflect.Ptr { | ||||
| 						argValueP := reflect.New(realNeedArgType) | ||||
| 						argValueP.Elem().Set(argValue) | ||||
| 						realArgs[needArgsIndex[i]] = argValueP | ||||
| 					} else { | ||||
| 						realArgs[needArgsIndex[i]] = argValue | ||||
| 					} | ||||
| 				} else { | ||||
| 					argValueP := argValue.Interface() | ||||
| 					u.Convert(argsIn.Arguments[i].Export(), argValueP) | ||||
| 					argValue = reflect.ValueOf(argValueP).Elem() | ||||
| 					realArgs[needArgsIndex[i]] = argValue | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// 处理可变参数 | ||||
| 			if len(argsIn.Arguments) > len(needArgs) { | ||||
| 				lastArgType := needArgs[len(needArgs)-1] | ||||
| 				if lastArgType.Kind() == reflect.Slice && lastArgType.Elem().Kind() != reflect.Uint8 { | ||||
| 					for i := len(needArgs); i < len(argsIn.Arguments); i++ { | ||||
| 						argValue := reflect.New(lastArgType.Elem()).Interface() | ||||
| 						u.Convert(argsIn.Arguments[i].Export(), argValue) | ||||
| 						realArgs = append(realArgs, reflect.ValueOf(argValue).Elem()) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			outValues := v.Call(realArgs) | ||||
| 
 | ||||
| 			outs := make([]any, 0) | ||||
| 			for _, outValue := range outValues { | ||||
| 				if outValue.Type().String() == "error" { | ||||
| 					if !outValue.IsNil() { | ||||
| 						// 抛出异常 | ||||
| 						if err, ok := outValue.Interface().(error); ok { | ||||
| 							panic(vm.NewGoError(err)) | ||||
| 						} else { | ||||
| 							panic(vm.NewGoError(errors.New(u.String(outValue.Interface())))) | ||||
| 						} | ||||
| 					} | ||||
| 					// 忽略error参数 | ||||
| 					continue | ||||
| 				} | ||||
| 				outs = append(outs, outValue.Interface()) | ||||
| 			} | ||||
| 			if len(outs) == 1 { | ||||
| 				return vm.ToValue(outs[0]) | ||||
| 			} else if len(outs) > 1 { | ||||
| 				return vm.ToValue(outs) | ||||
| 			} else { | ||||
| 				return vm.ToValue(nil) | ||||
| 			} | ||||
| 		} | ||||
| 	case reflect.Invalid: | ||||
| 		return nil | ||||
| 	default: | ||||
| 		return in | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										12
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								go.mod
									
									
									
									
									
								
							| @ -8,15 +8,15 @@ require ( | ||||
| 	github.com/google/pprof v0.0.0-20230207041349-798e818bf904 | ||||
| 	github.com/ssgo/log v1.7.7 | ||||
| 	github.com/ssgo/tool v0.4.27 | ||||
| 	github.com/ssgo/u v1.7.9 | ||||
| 	golang.org/x/net v0.30.0 | ||||
| 	golang.org/x/text v0.19.0 | ||||
| 	github.com/ssgo/u v1.7.11 | ||||
| 	golang.org/x/net v0.31.0 | ||||
| 	golang.org/x/text v0.20.0 | ||||
| ) | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/fsnotify/fsnotify v1.7.0 // indirect | ||||
| 	github.com/ssgo/config v1.7.7 // indirect | ||||
| 	github.com/fsnotify/fsnotify v1.8.0 // indirect | ||||
| 	github.com/ssgo/config v1.7.9 // indirect | ||||
| 	github.com/ssgo/standard v1.7.7 // indirect | ||||
| 	golang.org/x/sys v0.26.0 // indirect | ||||
| 	golang.org/x/sys v0.27.0 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||
| ) | ||||
|  | ||||
							
								
								
									
										494
									
								
								makeTS.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										494
									
								
								makeTS.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,494 @@ | ||||
| package gojs | ||||
| 
 | ||||
| import ( | ||||
| 	"reflect" | ||||
| 	"regexp" | ||||
| 	"runtime" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/ssgo/u" | ||||
| ) | ||||
| 
 | ||||
| type ArgInfo struct { | ||||
| 	index       int | ||||
| 	isVariadic  bool | ||||
| 	isOutArg    bool | ||||
| 	isFunc      bool | ||||
| 	isSkip      bool | ||||
| 	isOptional  bool | ||||
| 	funcInArgs  []ArgInfo | ||||
| 	funcOutArgs []ArgInfo | ||||
| 	Name        string | ||||
| 	Type        string | ||||
| } | ||||
| 
 | ||||
| var numberMatcher = regexp.MustCompile("[a-z0-9]*(int|float)[a-z0-9]*") | ||||
| var mapMatcher = regexp.MustCompile("map\\[(\\w+)](\\w+)") | ||||
| 
 | ||||
| func makeArgTypeString(argType string) string { | ||||
| 	if strings.Contains(argType, "interface {}") { | ||||
| 		argType = strings.ReplaceAll(argType, "interface {}", "any") | ||||
| 	} | ||||
| 	if strings.HasPrefix(argType, "*") { | ||||
| 		argType = argType[1:] | ||||
| 	} | ||||
| 	if strings.HasPrefix(argType, "[]") { | ||||
| 		argType = argType[2:] + "[]" | ||||
| 	} | ||||
| 	if strings.Contains(argType, "int") || strings.Contains(argType, "float") { | ||||
| 		argType = numberMatcher.ReplaceAllString(argType, "number") | ||||
| 	} | ||||
| 	if strings.Contains(argType, "bool") { | ||||
| 		argType = strings.ReplaceAll(argType, "bool", "boolean") | ||||
| 	} | ||||
| 	if strings.Contains(argType, "booleanean") { | ||||
| 		argType = strings.ReplaceAll(argType, "booleanean", "boolean") | ||||
| 	} | ||||
| 	if strings.HasPrefix(argType, "map[") { | ||||
| 		argType = mapMatcher.ReplaceAllString(argType, "Map<$1, $2>") | ||||
| 	} | ||||
| 	//if strings.ContainsRune(argType, '.') { | ||||
| 	//	argType = argType[strings.LastIndexByte(argType, '.')+1:] | ||||
| 	//} | ||||
| 	if strings.HasPrefix(argType, "<-") { | ||||
| 		argType = "any" | ||||
| 	} | ||||
| 	if argType == "" { | ||||
| 		argType = "void" | ||||
| 	} | ||||
| 	return argType | ||||
| } | ||||
| 
 | ||||
| func (argInfo *ArgInfo) String() string { | ||||
| 	argType := argInfo.Type | ||||
| 	if argInfo.isFunc { | ||||
| 		argType = "(" + makeInArgsString(argInfo.funcInArgs) + ") => " + makeOutArgsString(argInfo.funcOutArgs) | ||||
| 	} else { | ||||
| 		argType = makeArgTypeString(argType) | ||||
| 	} | ||||
| 	if argInfo.isOutArg { | ||||
| 		return argType | ||||
| 	} else { | ||||
| 		argName := argInfo.Name | ||||
| 		if argName == "" { | ||||
| 			argName = "arg" + u.String(argInfo.index+1) | ||||
| 		} | ||||
| 		if argInfo.isVariadic { | ||||
| 			argName = "..." + argName | ||||
| 		} | ||||
| 		return argName + u.StringIf(argInfo.isOptional, "?: ", ": ") + argType | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func makeInArgs(args []ArgInfo) []string { | ||||
| 	arr := make([]string, 0) | ||||
| 	for _, arg := range args { | ||||
| 		if !arg.isSkip { | ||||
| 			arr = append(arr, arg.String()) | ||||
| 		} | ||||
| 	} | ||||
| 	return arr | ||||
| } | ||||
| 
 | ||||
| func makeInArgsString(args []ArgInfo) string { | ||||
| 	return strings.Join(makeInArgs(args), ", ") | ||||
| } | ||||
| 
 | ||||
| func makeOutArgsString(args []ArgInfo) string { | ||||
| 	arr := makeInArgs(args) | ||||
| 	if len(arr) == 0 { | ||||
| 		return "void" | ||||
| 	} else if len(arr) == 1 { | ||||
| 		return arr[0] | ||||
| 	} else { | ||||
| 		return "[" + strings.Join(arr, ", ") + "]" | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func makeFuncArgsNames(v reflect.Value, inArgs []ArgInfo, isMethod bool) { | ||||
| 	var fp *runtime.Func | ||||
| 	if v.IsValid() { | ||||
| 		fp = runtime.FuncForPC(v.Pointer()) | ||||
| 	} else { | ||||
| 		// no name for Interface | ||||
| 		return | ||||
| 	} | ||||
| 	file, lineNo := fp.FileLine(fp.Entry()) | ||||
| 	if file != "<autogenerated>" && u.FileExists(file) { | ||||
| 		lines, _ := u.ReadFileLines(file) | ||||
| 		if len(lines) >= lineNo { | ||||
| 			line := lines[lineNo-1] | ||||
| 			if !strings.Contains(line, "func") && lineNo-2 >= 0 && strings.Contains(lines[lineNo-2], "func") { | ||||
| 				line = lines[lineNo-2] | ||||
| 			} | ||||
| 			line = strings.ReplaceAll(line, "interface{}", "any") | ||||
| 			pos := strings.Index(line, "func") | ||||
| 			if pos != -1 { | ||||
| 				line = strings.TrimSpace(line[pos+4:]) | ||||
| 				if isMethod { | ||||
| 					// skip method this arg | ||||
| 					pos = strings.Index(line, "(") | ||||
| 					if pos != -1 { | ||||
| 						line = strings.TrimSpace(line[pos+1:]) | ||||
| 						makeFuncArgsName(line, inArgs[1:]) | ||||
| 					} | ||||
| 				} else { | ||||
| 					makeFuncArgsName(line, inArgs) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func makeFuncArgsName(line string, inArgs []ArgInfo) { | ||||
| 	pos := strings.Index(line, "(") | ||||
| 	if pos != -1 { | ||||
| 		line = strings.TrimSpace(line[pos+1:]) | ||||
| 		for i := 0; i < len(inArgs); i++ { | ||||
| 			// find param name | ||||
| 			pos = strings.Index(line, " ") | ||||
| 			// support combined args a, b string | ||||
| 			pos1 := strings.Index(line, ",") | ||||
| 			if pos1 != -1 && pos1 < pos { | ||||
| 				inArgs[i].Name = line[0:pos1] | ||||
| 				line = strings.TrimSpace(line[pos1+1:]) | ||||
| 				continue | ||||
| 			} | ||||
| 			if pos != -1 { | ||||
| 				inArgs[i].Name = line[0:pos] | ||||
| 				line = strings.TrimSpace(line[pos+1:]) | ||||
| 			} | ||||
| 			// skip inline func | ||||
| 			if strings.HasPrefix(line, "func") { | ||||
| 				line = strings.TrimSpace(line[4:]) | ||||
| 				leftQuotes := 0 | ||||
| 				quoteStarted := false | ||||
| 				for pos = 0; pos < len(line); pos++ { | ||||
| 					if line[pos] == '(' { | ||||
| 						leftQuotes++ | ||||
| 						quoteStarted = true | ||||
| 						continue | ||||
| 					} | ||||
| 					if quoteStarted && line[pos] == ')' { | ||||
| 						leftQuotes-- | ||||
| 					} | ||||
| 					if quoteStarted && leftQuotes == 0 { | ||||
| 						break | ||||
| 					} | ||||
| 				} | ||||
| 				makeFuncArgsName(line, inArgs[i].funcInArgs) | ||||
| 				line = strings.TrimSpace(line[pos+1:]) | ||||
| 			} | ||||
| 			// skip , | ||||
| 			pos = strings.Index(line, ",") | ||||
| 			if pos != -1 { | ||||
| 				line = strings.TrimSpace(line[pos+1:]) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func fixFieldElemType(argType string) string { | ||||
| 	if strings.HasPrefix(argType, "Map<") { | ||||
| 		argType = "Object/*" + argType + "*/" | ||||
| 	} | ||||
| 	return argType | ||||
| } | ||||
| 
 | ||||
| func makeFieldElemType(t reflect.Type, existsClasses *map[string]string, sameClassIndex *map[string]int, classes *[]string, isSkip bool) string { | ||||
| 	originT := t | ||||
| 	if t.Kind() == reflect.Pointer { | ||||
| 		t = t.Elem() | ||||
| 	} | ||||
| 	if t.Kind() == reflect.Map { | ||||
| 		if t.Elem().Kind() == reflect.Struct && !isSkip { | ||||
| 			makeClass(t.Elem(), existsClasses, sameClassIndex, classes) | ||||
| 		} | ||||
| 		et := t.Elem() | ||||
| 		if et.Kind() == reflect.Pointer { | ||||
| 			et = et.Elem() | ||||
| 		} | ||||
| 		if et.Kind() == reflect.Struct || et.Kind() == reflect.Map || (et.Kind() == reflect.Slice && et.Elem().Kind() != reflect.Uint8) { | ||||
| 			return "Map<" + makeArgTypeString(t.Key().String()) + ", " + makeFieldElemType(t.Elem(), existsClasses, sameClassIndex, classes, isSkip) + ">" | ||||
| 		} | ||||
| 		return "Object" | ||||
| 	} else if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { | ||||
| 		if t.Elem().Kind() == reflect.Struct && !isSkip { | ||||
| 			makeClass(t.Elem(), existsClasses, sameClassIndex, classes) | ||||
| 		} | ||||
| 		return "Array<" + makeFieldElemType(t.Elem(), existsClasses, sameClassIndex, classes, isSkip) + ">" | ||||
| 	} else if t.Kind() == reflect.Struct { | ||||
| 		if !isSkip { | ||||
| 			makeClass(originT, existsClasses, sameClassIndex, classes) | ||||
| 		} | ||||
| 		return makeArgTypeString(getFixedClassName(t.String(), existsClasses)) | ||||
| 		//return makeArgTypeString(strings.ReplaceAll(t.String(), ".", "_")) | ||||
| 	} else if t.Kind() == reflect.Interface { | ||||
| 		if !isSkip { | ||||
| 			makeClass(originT, existsClasses, sameClassIndex, classes) | ||||
| 		} | ||||
| 		return makeArgTypeString(getFixedClassName(t.String(), existsClasses)) | ||||
| 	} else if t.Kind() == reflect.Func { | ||||
| 		inArgs, outArgs := makeFuncInOutArgs(t, existsClasses, sameClassIndex, classes) | ||||
| 		//makeFuncArgsNames(reflect.MakeFunc(t, func(args []reflect.Value) (results []reflect.Value) { | ||||
| 		//	return nil | ||||
| 		//}), inArgs, false) | ||||
| 		return "(" + makeInArgsString(inArgs) + ") => " + makeOutArgsString(outArgs) | ||||
| 	} else { | ||||
| 		return makeArgTypeString(getFixedTypeName(t)) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func getFixedClassName(className string, existsClasses *map[string]string) string { | ||||
| 	if (*existsClasses)[className] != "" { | ||||
| 		return (*existsClasses)[className] | ||||
| 	} | ||||
| 	return strings.ReplaceAll(className, ".", "_") | ||||
| } | ||||
| 
 | ||||
| func getFixedTypeName(t reflect.Type) string { | ||||
| 	if t.String() != t.Kind().String() && !strings.HasPrefix(t.String(), "[]") { | ||||
| 		if t.Kind().String() == "slice" { | ||||
| 			return "[]any" | ||||
| 		} | ||||
| 		if t.Kind().String() == "chan" { | ||||
| 			return "any" | ||||
| 		} | ||||
| 		if t.Kind().String() == "func" { | ||||
| 			return "()=>void" | ||||
| 		} | ||||
| 		//fmt.Println(">>>>>", u.BYellow(t.String()), u.BYellow(t.String()), u.BYellow(t.Kind().String())) | ||||
| 		return makeArgTypeString(t.Kind().String()) | ||||
| 	} else { | ||||
| 		return makeArgTypeString(t.String()) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func makeClass(t reflect.Type, existsClasses *map[string]string, sameClassIndex *map[string]int, classes *[]string) { | ||||
| 	originT := t | ||||
| 	if t.Kind() == reflect.Pointer { | ||||
| 		t = t.Elem() | ||||
| 	} | ||||
| 	if t.Name() == "" { | ||||
| 		return | ||||
| 	} | ||||
| 	fullTypeName := t.String() | ||||
| 	useTypeName := t.Name() | ||||
| 	if (*existsClasses)[fullTypeName] == "" { | ||||
| 		(*sameClassIndex)[useTypeName]++ | ||||
| 		if (*sameClassIndex)[useTypeName] > 1 { | ||||
| 			useTypeName += u.String((*sameClassIndex)[useTypeName]) | ||||
| 		} | ||||
| 		(*existsClasses)[fullTypeName] = useTypeName | ||||
| 		classItems := make([]string, 0) | ||||
| 		implements := make([]string, 0) | ||||
| 		if t.Kind() != reflect.Interface { | ||||
| 			for i := 0; i < t.NumField(); i++ { | ||||
| 				if !t.Field(i).IsExported() { | ||||
| 					continue | ||||
| 				} | ||||
| 				ft := t.Field(i).Type | ||||
| 				if ft.Kind() == reflect.Pointer { | ||||
| 					ft = ft.Elem() | ||||
| 				} | ||||
| 				ftStr := fixFieldElemType(makeFieldElemType(ft, existsClasses, sameClassIndex, classes, false)) | ||||
| 				if t.Field(i).Anonymous { | ||||
| 					implements = append(implements, ftStr) | ||||
| 					continue | ||||
| 				} | ||||
| 				classItems = append(classItems, "  "+u.GetLowerName(t.Field(i).Name)+": "+ftStr) | ||||
| 			} | ||||
| 		} | ||||
| 		if originT.Kind() != reflect.Pointer { | ||||
| 			originT = reflect.New(originT).Type() | ||||
| 		} | ||||
| 		for i := 0; i < originT.NumMethod(); i++ { | ||||
| 			if !originT.Method(i).IsExported() { | ||||
| 				continue | ||||
| 			} | ||||
| 			if methodInParent(originT.Method(i), t) { | ||||
| 				continue | ||||
| 			} | ||||
| 			inArgs, outArgs := makeFuncInOutArgs(originT.Method(i).Type, existsClasses, sameClassIndex, classes) | ||||
| 			if len(inArgs) > 0 { | ||||
| 				inArgs[0].isSkip = true | ||||
| 			} | ||||
| 			//fmt.Println(">>>>>", u.BYellow(originT.Method(i))) | ||||
| 			makeFuncArgsNames(originT.Method(i).Func, inArgs, true) | ||||
| 			classItems = append(classItems, "  "+u.GetLowerName(originT.Method(i).Name)+"("+makeInArgsString(inArgs)+"): "+makeOutArgsString(outArgs)) | ||||
| 		} | ||||
| 		for i := 0; i < t.NumMethod(); i++ { | ||||
| 			if !t.Method(i).IsExported() { | ||||
| 				continue | ||||
| 			} | ||||
| 			if methodInParent(t.Method(i), t) { | ||||
| 				continue | ||||
| 			} | ||||
| 			inArgs, outArgs := makeFuncInOutArgs(t.Method(i).Type, existsClasses, sameClassIndex, classes) | ||||
| 			if len(inArgs) > 0 { | ||||
| 				inArgs[0].isSkip = true | ||||
| 			} | ||||
| 			//fmt.Println(">>>>>", u.BYellow(t.Method(i))) | ||||
| 			makeFuncArgsNames(t.Method(i).Func, inArgs, true) | ||||
| 			classItems = append(classItems, "  "+u.GetLowerName(t.Method(i).Name)+"("+makeInArgsString(inArgs)+"): "+makeOutArgsString(outArgs)) | ||||
| 		} | ||||
| 		implementsStr := "" | ||||
| 		if len(implements) > 0 { | ||||
| 			implementsStr = " extends " + strings.Join(implements, ", ") | ||||
| 		} | ||||
| 		newClass := append([]string{}, "interface "+useTypeName+implementsStr+" {") | ||||
| 		newClass = append(newClass, classItems...) | ||||
| 		newClass = append(newClass, "}") | ||||
| 		*classes = append(*classes, strings.Join(newClass, "\n")) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func methodInParent(method reflect.Method, childType reflect.Type) bool { | ||||
| 	for i := 0; i < childType.NumField(); i++ { | ||||
| 		field := childType.Field(i) | ||||
| 		if field.Anonymous { | ||||
| 			parentType := field.Type | ||||
| 			parentTypeP := field.Type | ||||
| 			if field.Type.Kind() != reflect.Ptr { | ||||
| 				parentTypeP = reflect.New(field.Type).Type() | ||||
| 			} else { | ||||
| 				parentType = field.Type.Elem() | ||||
| 			} | ||||
| 			if _, exists := parentType.MethodByName(method.Name); exists { | ||||
| 				return true | ||||
| 			} | ||||
| 			if _, exists := parentTypeP.MethodByName(method.Name); exists { | ||||
| 				return true | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func makeFuncInOutArgs(t reflect.Type, existsClasses *map[string]string, sameClassIndex *map[string]int, classes *[]string) (inArgs []ArgInfo, outArgs []ArgInfo) { | ||||
| 	inArgs = make([]ArgInfo, t.NumIn()) | ||||
| 	outArgs = make([]ArgInfo, t.NumOut()) | ||||
| 	isOptional := true | ||||
| 	for i := t.NumIn() - 1; i >= 0; i-- { | ||||
| 		arg := t.In(i) | ||||
| 		isSkip := false | ||||
| 		if arg.String() == "*goja.Runtime" { | ||||
| 			isSkip = true | ||||
| 		} | ||||
| 		if arg.String() == "goja.Value" { | ||||
| 			isSkip = true | ||||
| 		} | ||||
| 		if isOptional && arg.Kind() != reflect.Pointer { | ||||
| 			isOptional = false | ||||
| 		} | ||||
| 		argInfo := ArgInfo{ | ||||
| 			index:      i, | ||||
| 			isOutArg:   false, | ||||
| 			isFunc:     false, | ||||
| 			isSkip:     isSkip, | ||||
| 			isOptional: isOptional, | ||||
| 			isVariadic: t.IsVariadic() && i == t.NumIn()-1, | ||||
| 			Name:       "", | ||||
| 			Type:       fixFieldElemType(makeFieldElemType(arg, existsClasses, sameClassIndex, classes, isSkip)), | ||||
| 		} | ||||
| 		//originArg := arg | ||||
| 		//if arg.Kind() == reflect.Pointer { | ||||
| 		//	arg = arg.Elem() | ||||
| 		//} | ||||
| 		if arg.Kind() == reflect.Func { | ||||
| 			argInfo.isFunc = true | ||||
| 			argInfo.funcInArgs, argInfo.funcOutArgs = makeFuncInOutArgs(arg, existsClasses, sameClassIndex, classes) | ||||
| 		} | ||||
| 		//if !argInfo.isSkip && arg.Kind() == reflect.Struct { | ||||
| 		//	makeClass(originArg, existsClasses, sameClassIndex, classes) | ||||
| 		//} | ||||
| 		inArgs[i] = argInfo | ||||
| 	} | ||||
| 	for i := t.NumOut() - 1; i >= 0; i-- { | ||||
| 		arg := t.Out(i) | ||||
| 		isSkip := false | ||||
| 		if arg.String() == "error" { | ||||
| 			isSkip = true | ||||
| 		} | ||||
| 		if arg.String() == "goja.Value" { | ||||
| 			isSkip = true | ||||
| 		} | ||||
| 		argInfo := ArgInfo{ | ||||
| 			index:      i, | ||||
| 			isOutArg:   true, | ||||
| 			isFunc:     false, | ||||
| 			isSkip:     isSkip, | ||||
| 			isVariadic: false, | ||||
| 			Name:       "", | ||||
| 			Type:       fixFieldElemType(makeFieldElemType(arg, existsClasses, sameClassIndex, classes, isSkip)), | ||||
| 		} | ||||
| 
 | ||||
| 		//originArg := arg | ||||
| 		//if arg.Kind() == reflect.Pointer { | ||||
| 		//	arg = arg.Elem() | ||||
| 		//} | ||||
| 		//if !argInfo.isSkip && arg.Kind() == reflect.Struct { | ||||
| 		//	makeClass(originArg, existsClasses, sameClassIndex, classes) | ||||
| 		//} | ||||
| 		outArgs[i] = argInfo | ||||
| 	} | ||||
| 	return inArgs, outArgs | ||||
| } | ||||
| 
 | ||||
| func findObject(v reflect.Value, level int, existsClasses *map[string]string, sameClassIndex *map[string]int) (codes []string, classes []string) { | ||||
| 	codes = make([]string, 0) | ||||
| 	classes = make([]string, 0) | ||||
| 	if v.Kind() == reflect.Interface { | ||||
| 		v = v.Elem() | ||||
| 	} | ||||
| 	originT := v.Type() | ||||
| 	v = u.FinalValue(v) | ||||
| 	t := originT | ||||
| 	if t.Kind() == reflect.Pointer { | ||||
| 		t = t.Elem() | ||||
| 	} | ||||
| 	indent := strings.Repeat("  ", level) | ||||
| 	if t.Kind() == reflect.Map { | ||||
| 		codes = append(codes, "{") | ||||
| 		for _, k := range v.MapKeys() { | ||||
| 			codes2, classes2 := findObject(v.MapIndex(k), level+1, existsClasses, sameClassIndex) | ||||
| 			classes = append(classes, classes2...) | ||||
| 			codes = append(codes, indent+"  \""+k.String()+"\": "+strings.Join(codes2, "\n")+",") | ||||
| 		} | ||||
| 		codes = append(codes, indent+"}") | ||||
| 	} else if t.Kind() == reflect.Struct { | ||||
| 		makeClass(originT, existsClasses, sameClassIndex, &classes) | ||||
| 		codes = append(codes, "(null as any) as "+getFixedClassName(t.String(), existsClasses)) | ||||
| 	} else if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { | ||||
| 		codes = append(codes, "[") | ||||
| 		for i := 0; i < v.Len(); i++ { | ||||
| 			codes2, classes2 := findObject(v.Index(i), level+1, existsClasses, sameClassIndex) | ||||
| 			classes = append(classes, classes2...) | ||||
| 			codes = append(codes, indent+"  "+strings.Join(codes2, "\n")+",") | ||||
| 		} | ||||
| 		codes = append(codes, indent+"]") | ||||
| 	} else if t.Kind() == reflect.Func { | ||||
| 		inArgs, outArgs := makeFuncInOutArgs(t, existsClasses, sameClassIndex, &classes) | ||||
| 		makeFuncArgsNames(v, inArgs, false) | ||||
| 		codes = append(codes, "function ("+makeInArgsString(inArgs)+"): "+makeOutArgsString(outArgs)+" {return null as any}") | ||||
| 	} else { | ||||
| 		codes = append(codes, u.Json(v.Interface())) | ||||
| 	} | ||||
| 	return codes, classes | ||||
| } | ||||
| 
 | ||||
| func MakeTSCode(objects any) string { | ||||
| 	existsClasses := make(map[string]string) | ||||
| 	sameClassIndex := make(map[string]int) | ||||
| 	codes, classes := findObject(reflect.ValueOf(objects), 0, &existsClasses, &sameClassIndex) | ||||
| 	interfaceExports := make([]string, 0) | ||||
| 	for _, existsClassName := range existsClasses { | ||||
| 		interfaceExports = append(interfaceExports, existsClassName) | ||||
| 	} | ||||
| 	a := make([]string, 0) | ||||
| 	if len(interfaceExports) > 0 { | ||||
| 		a = append(a, strings.Join(classes, "\n\n")) | ||||
| 	} | ||||
| 	a = append(a, "export default "+strings.Join(codes, "\n")) | ||||
| 	return strings.Join(a, "\n") | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Star
						Star