388 lines
9.4 KiB
Go
388 lines
9.4 KiB
Go
package axscript
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/dop251/goja"
|
|
)
|
|
|
|
/// Command
|
|
|
|
type jsCommandBuilder struct {
|
|
engine *ScriptEngine
|
|
command CommandDef
|
|
}
|
|
|
|
func newJsCommandBuilder(engine *ScriptEngine, name, description, example, message string) *jsCommandBuilder {
|
|
return &jsCommandBuilder{
|
|
engine: engine,
|
|
command: CommandDef{
|
|
Name: name,
|
|
Description: description,
|
|
Example: example,
|
|
Message: message,
|
|
},
|
|
}
|
|
}
|
|
|
|
func (b *jsCommandBuilder) AddArgBool(call goja.FunctionCall) goja.Value {
|
|
flag := call.Argument(0).String()
|
|
arg := ArgumentDef{
|
|
Type: ArgTypeBool,
|
|
Flag: true,
|
|
Mark: flag,
|
|
}
|
|
|
|
if len(call.Arguments) > 1 {
|
|
arg.Description = call.Argument(1).String()
|
|
}
|
|
if len(call.Arguments) > 2 && !goja.IsUndefined(call.Argument(2)) && !goja.IsNull(call.Argument(2)) {
|
|
arg.DefaultUsed = true
|
|
arg.DefaultValue = call.Argument(2).Export()
|
|
}
|
|
|
|
b.command.Args = append(b.command.Args, arg)
|
|
return goja.Undefined()
|
|
}
|
|
|
|
func (b *jsCommandBuilder) AddArgInt(call goja.FunctionCall) goja.Value {
|
|
name := call.Argument(0).String()
|
|
arg := ArgumentDef{
|
|
Type: ArgTypeInt,
|
|
Name: name,
|
|
}
|
|
|
|
if len(call.Arguments) > 1 {
|
|
v := call.Argument(1)
|
|
if v.ExportType() != nil && v.ExportType().Kind().String() == "bool" {
|
|
arg.Required = v.ToBoolean()
|
|
if len(call.Arguments) > 2 {
|
|
arg.Description = call.Argument(2).String()
|
|
}
|
|
} else {
|
|
arg.Required = true
|
|
arg.Description = v.String()
|
|
if len(call.Arguments) > 2 && !goja.IsUndefined(call.Argument(2)) && !goja.IsNull(call.Argument(2)) {
|
|
arg.DefaultUsed = true
|
|
arg.DefaultValue = call.Argument(2).Export()
|
|
}
|
|
}
|
|
}
|
|
|
|
b.command.Args = append(b.command.Args, arg)
|
|
return goja.Undefined()
|
|
}
|
|
|
|
func (b *jsCommandBuilder) AddArgFlagInt(call goja.FunctionCall) goja.Value {
|
|
flag := call.Argument(0).String()
|
|
name := call.Argument(1).String()
|
|
arg := ArgumentDef{
|
|
Type: ArgTypeInt,
|
|
Name: name,
|
|
Flag: true,
|
|
Mark: flag,
|
|
}
|
|
|
|
if len(call.Arguments) > 2 {
|
|
v := call.Argument(2)
|
|
if v.ExportType() != nil && v.ExportType().Kind().String() == "bool" {
|
|
arg.Required = v.ToBoolean()
|
|
if len(call.Arguments) > 3 {
|
|
arg.Description = call.Argument(3).String()
|
|
}
|
|
} else {
|
|
arg.Required = true
|
|
arg.Description = v.String()
|
|
if len(call.Arguments) > 3 && !goja.IsUndefined(call.Argument(3)) && !goja.IsNull(call.Argument(3)) {
|
|
arg.DefaultUsed = true
|
|
arg.DefaultValue = call.Argument(3).Export()
|
|
}
|
|
}
|
|
}
|
|
|
|
b.command.Args = append(b.command.Args, arg)
|
|
return goja.Undefined()
|
|
}
|
|
|
|
func (b *jsCommandBuilder) AddArgString(call goja.FunctionCall) goja.Value {
|
|
name := call.Argument(0).String()
|
|
arg := ArgumentDef{
|
|
Type: ArgTypeString,
|
|
Name: name,
|
|
Required: true,
|
|
}
|
|
|
|
if len(call.Arguments) > 1 {
|
|
v := call.Argument(1)
|
|
if v.ExportType() != nil && v.ExportType().Kind().String() == "bool" {
|
|
arg.Required = v.ToBoolean()
|
|
if len(call.Arguments) > 2 {
|
|
arg.Description = call.Argument(2).String()
|
|
}
|
|
} else {
|
|
arg.Description = v.String()
|
|
if len(call.Arguments) > 2 && !goja.IsUndefined(call.Argument(2)) && !goja.IsNull(call.Argument(2)) {
|
|
arg.DefaultUsed = true
|
|
arg.DefaultValue = call.Argument(2).Export()
|
|
}
|
|
}
|
|
}
|
|
|
|
b.command.Args = append(b.command.Args, arg)
|
|
return goja.Undefined()
|
|
}
|
|
|
|
func (b *jsCommandBuilder) AddArgFlagString(call goja.FunctionCall) goja.Value {
|
|
flag := call.Argument(0).String()
|
|
name := call.Argument(1).String()
|
|
arg := ArgumentDef{
|
|
Type: ArgTypeString,
|
|
Name: name,
|
|
Flag: true,
|
|
Mark: flag,
|
|
}
|
|
|
|
if len(call.Arguments) > 2 {
|
|
v := call.Argument(2)
|
|
if v.ExportType() != nil && v.ExportType().Kind().String() == "bool" {
|
|
arg.Required = v.ToBoolean()
|
|
if len(call.Arguments) > 3 {
|
|
arg.Description = call.Argument(3).String()
|
|
}
|
|
} else {
|
|
arg.Required = true
|
|
arg.Description = v.String()
|
|
if len(call.Arguments) > 3 && !goja.IsUndefined(call.Argument(3)) && !goja.IsNull(call.Argument(3)) {
|
|
arg.DefaultUsed = true
|
|
arg.DefaultValue = call.Argument(3).Export()
|
|
}
|
|
}
|
|
}
|
|
|
|
b.command.Args = append(b.command.Args, arg)
|
|
return goja.Undefined()
|
|
}
|
|
|
|
func (b *jsCommandBuilder) AddArgFile(call goja.FunctionCall) goja.Value {
|
|
name := call.Argument(0).String()
|
|
required := false
|
|
description := ""
|
|
if len(call.Arguments) > 1 {
|
|
required = call.Argument(1).ToBoolean()
|
|
}
|
|
if len(call.Arguments) > 2 {
|
|
description = call.Argument(2).String()
|
|
}
|
|
|
|
arg := ArgumentDef{
|
|
Type: ArgTypeFile,
|
|
Name: name,
|
|
Required: required,
|
|
Description: description,
|
|
}
|
|
b.command.Args = append(b.command.Args, arg)
|
|
return goja.Undefined()
|
|
}
|
|
|
|
func (b *jsCommandBuilder) AddArgFlagFile(call goja.FunctionCall) goja.Value {
|
|
flag := call.Argument(0).String()
|
|
name := call.Argument(1).String()
|
|
required := false
|
|
description := ""
|
|
if len(call.Arguments) > 2 {
|
|
required = call.Argument(2).ToBoolean()
|
|
}
|
|
if len(call.Arguments) > 3 {
|
|
description = call.Argument(3).String()
|
|
}
|
|
|
|
arg := ArgumentDef{
|
|
Type: ArgTypeFile,
|
|
Name: name,
|
|
Required: required,
|
|
Flag: true,
|
|
Mark: flag,
|
|
Description: description,
|
|
}
|
|
b.command.Args = append(b.command.Args, arg)
|
|
return goja.Undefined()
|
|
}
|
|
|
|
func (b *jsCommandBuilder) AddSubCommands(call goja.FunctionCall) goja.Value {
|
|
val := call.Argument(0)
|
|
if goja.IsUndefined(val) || goja.IsNull(val) {
|
|
return goja.Undefined()
|
|
}
|
|
|
|
rt := b.engine.runtime
|
|
obj := val.ToObject(rt)
|
|
|
|
if isArray, _ := isJsArray(rt, obj); isArray {
|
|
length := obj.Get("length").ToInteger()
|
|
for i := int64(0); i < length; i++ {
|
|
item := obj.Get(fmt.Sprintf("%d", i))
|
|
if sub := extractCommandBuilder(item); sub != nil {
|
|
b.command.Subcommands = append(b.command.Subcommands, sub.command)
|
|
}
|
|
}
|
|
} else {
|
|
if sub := extractCommandBuilder(val); sub != nil {
|
|
b.command.Subcommands = append(b.command.Subcommands, sub.command)
|
|
}
|
|
}
|
|
|
|
return goja.Undefined()
|
|
}
|
|
|
|
func (b *jsCommandBuilder) SetPreHook(call goja.FunctionCall) goja.Value {
|
|
fn, ok := goja.AssertFunction(call.Argument(0))
|
|
if !ok {
|
|
panic(b.engine.runtime.NewTypeError("setPreHook: argument is not a function"))
|
|
}
|
|
b.command.HasPreHook = true
|
|
b.command.PreHookFunc = fn
|
|
return goja.Undefined()
|
|
}
|
|
|
|
/// CommandGroup
|
|
|
|
type jsCommandGroupBuilder struct {
|
|
engine *ScriptEngine
|
|
name string
|
|
description string
|
|
commands []CommandDef
|
|
}
|
|
|
|
// /---
|
|
func newJsCommandGroupBuilder(engine *ScriptEngine) *jsCommandGroupBuilder {
|
|
return &jsCommandGroupBuilder{
|
|
engine: engine,
|
|
}
|
|
}
|
|
|
|
// /---
|
|
func (g *jsCommandGroupBuilder) SetParams(call goja.FunctionCall) goja.Value {
|
|
g.name = call.Argument(0).String()
|
|
|
|
val := call.Argument(1)
|
|
if goja.IsUndefined(val) || goja.IsNull(val) {
|
|
return goja.Undefined()
|
|
}
|
|
|
|
rt := g.engine.runtime
|
|
obj := val.ToObject(rt)
|
|
if isArr, _ := isJsArray(rt, obj); !isArr {
|
|
panic(rt.NewTypeError("setParams: second argument must be an array"))
|
|
}
|
|
|
|
length := obj.Get("length").ToInteger()
|
|
for i := int64(0); i < length; i++ {
|
|
item := obj.Get(fmt.Sprintf("%d", i))
|
|
if sub := extractCommandBuilder(item); sub != nil {
|
|
g.commands = append(g.commands, sub.command)
|
|
}
|
|
}
|
|
|
|
return goja.Undefined()
|
|
}
|
|
|
|
func (g *jsCommandGroupBuilder) SetParamsFromValue(name string, val goja.Value) {
|
|
g.name = name
|
|
if goja.IsUndefined(val) || goja.IsNull(val) {
|
|
return
|
|
}
|
|
rt := g.engine.runtime
|
|
obj := val.ToObject(rt)
|
|
lengthVal := obj.Get("length")
|
|
if lengthVal == nil || goja.IsUndefined(lengthVal) {
|
|
return
|
|
}
|
|
length := lengthVal.ToInteger()
|
|
for i := int64(0); i < length; i++ {
|
|
item := obj.Get(fmt.Sprintf("%d", i))
|
|
if sub := extractCommandBuilder(item); sub != nil {
|
|
g.commands = append(g.commands, sub.command)
|
|
}
|
|
}
|
|
}
|
|
|
|
// /---
|
|
func (g *jsCommandGroupBuilder) Add(call goja.FunctionCall) goja.Value {
|
|
val := call.Argument(0)
|
|
if goja.IsUndefined(val) || goja.IsNull(val) {
|
|
return goja.Undefined()
|
|
}
|
|
|
|
rt := g.engine.runtime
|
|
obj := val.ToObject(rt)
|
|
if isArr, _ := isJsArray(rt, obj); isArr {
|
|
length := obj.Get("length").ToInteger()
|
|
for i := int64(0); i < length; i++ {
|
|
item := obj.Get(fmt.Sprintf("%d", i))
|
|
if sub := extractCommandBuilder(item); sub != nil {
|
|
g.commands = append(g.commands, sub.command)
|
|
}
|
|
}
|
|
} else {
|
|
if sub := extractCommandBuilder(val); sub != nil {
|
|
g.commands = append(g.commands, sub.command)
|
|
}
|
|
}
|
|
|
|
return goja.Undefined()
|
|
}
|
|
|
|
func (g *jsCommandGroupBuilder) ToCommandGroup(scriptName string) CommandGroup {
|
|
return CommandGroup{
|
|
GroupName: g.name,
|
|
GroupDescription: g.description,
|
|
ScriptName: scriptName,
|
|
Commands: g.commands,
|
|
}
|
|
}
|
|
|
|
/// Helpers
|
|
|
|
func isJsArray(rt *goja.Runtime, obj *goja.Object) (bool, error) {
|
|
arrayConstructor := rt.Get("Array")
|
|
if arrayConstructor == nil {
|
|
return false, nil
|
|
}
|
|
isArrayFn, ok := goja.AssertFunction(arrayConstructor.ToObject(rt).Get("isArray"))
|
|
if !ok {
|
|
return false, nil
|
|
}
|
|
result, err := isArrayFn(goja.Undefined(), obj)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return result.ToBoolean(), nil
|
|
}
|
|
|
|
func extractCommandBuilder(val goja.Value) *jsCommandBuilder {
|
|
if goja.IsUndefined(val) || goja.IsNull(val) {
|
|
return nil
|
|
}
|
|
exported := val.Export()
|
|
if cb, ok := exported.(*jsCommandBuilder); ok {
|
|
return cb
|
|
}
|
|
if m, ok := exported.(map[string]interface{}); ok {
|
|
if builderVal, exists := m["__builder"]; exists {
|
|
if cb, ok2 := builderVal.(*jsCommandBuilder); ok2 {
|
|
return cb
|
|
}
|
|
}
|
|
}
|
|
obj := val.ToObject(nil)
|
|
if obj != nil {
|
|
builderVal := obj.Get("__builder")
|
|
if builderVal != nil && !goja.IsUndefined(builderVal) && !goja.IsNull(builderVal) {
|
|
if cb, ok := builderVal.Export().(*jsCommandBuilder); ok {
|
|
return cb
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|