2026-04-06 00:20:51 -05:00

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
}