updated cobra.Command constructor and update structConstructor to use goja.Object.Set
This commit is contained in:
parent
fc311a8d28
commit
21607f0f66
|
@ -14,7 +14,7 @@ const heading = `
|
||||||
// baseBinds
|
// baseBinds
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
declare var $app: core.App
|
declare var $app: pocketbase.PocketBase
|
||||||
|
|
||||||
interface Record extends models.Record{} // merge
|
interface Record extends models.Record{} // merge
|
||||||
declare class Record implements models.Record {
|
declare class Record implements models.Record {
|
||||||
|
@ -41,11 +41,16 @@ declare class SchemaField implements schema.SchemaField {
|
||||||
constructor(data?: Partial<schema.SchemaField>)
|
constructor(data?: Partial<schema.SchemaField>)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Mail extends mailer.Message{} // merge
|
interface MailerMessage extends mailer.Message{} // merge
|
||||||
declare class Mail implements mailer.Message {
|
declare class Mail implements mailer.Message {
|
||||||
constructor(message?: Partial<mailer.Message>)
|
constructor(message?: Partial<mailer.Message>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Command extends cobra.Command{} // merge
|
||||||
|
declare class Mail implements cobra.Command {
|
||||||
|
constructor(cmd?: Partial<cobra.Command>)
|
||||||
|
}
|
||||||
|
|
||||||
interface ValidationError extends ozzo_validation.Error{} // merge
|
interface ValidationError extends ozzo_validation.Error{} // merge
|
||||||
declare class ValidationError implements ozzo_validation.Error {
|
declare class ValidationError implements ozzo_validation.Error {
|
||||||
constructor(code?: number, message?: string)
|
constructor(code?: number, message?: string)
|
||||||
|
@ -270,7 +275,7 @@ func main() {
|
||||||
"github.com/pocketbase/pocketbase/tokens": {"*"},
|
"github.com/pocketbase/pocketbase/tokens": {"*"},
|
||||||
"github.com/pocketbase/pocketbase/apis": {"*"},
|
"github.com/pocketbase/pocketbase/apis": {"*"},
|
||||||
"github.com/pocketbase/pocketbase/forms": {"*"},
|
"github.com/pocketbase/pocketbase/forms": {"*"},
|
||||||
"github.com/pocketbase/pocketbase/core": {"*"},
|
"github.com/pocketbase/pocketbase": {"*"},
|
||||||
},
|
},
|
||||||
FieldNameFormatter: func(s string) string {
|
FieldNameFormatter: func(s string) string {
|
||||||
return mapper.FieldName(nil, reflect.StructField{Name: s})
|
return mapper.FieldName(nil, reflect.StructField{Name: s})
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -18,6 +18,7 @@ package jsvm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -38,6 +39,7 @@ import (
|
||||||
"github.com/pocketbase/pocketbase/tools/mailer"
|
"github.com/pocketbase/pocketbase/tools/mailer"
|
||||||
"github.com/pocketbase/pocketbase/tools/security"
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
"github.com/pocketbase/pocketbase/tools/types"
|
"github.com/pocketbase/pocketbase/tools/types"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func baseBinds(vm *goja.Runtime) {
|
func baseBinds(vm *goja.Runtime) {
|
||||||
|
@ -66,19 +68,6 @@ func baseBinds(vm *goja.Runtime) {
|
||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
|
|
||||||
vm.Set("unmarshal", func(src map[string]any, dest any) (any, error) {
|
|
||||||
raw, err := json.Marshal(src)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.Unmarshal(raw, &dest); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return dest, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
vm.Set("DynamicModel", func(call goja.ConstructorCall) *goja.Object {
|
vm.Set("DynamicModel", func(call goja.ConstructorCall) *goja.Object {
|
||||||
shape, ok := call.Argument(0).Export().(map[string]any)
|
shape, ok := call.Argument(0).Export().(map[string]any)
|
||||||
if !ok || len(shape) == 0 {
|
if !ok || len(shape) == 0 {
|
||||||
|
@ -113,9 +102,7 @@ func baseBinds(vm *goja.Runtime) {
|
||||||
instance = models.NewRecord(collection)
|
instance = models.NewRecord(collection)
|
||||||
data, ok := call.Argument(1).Export().(map[string]any)
|
data, ok := call.Argument(1).Export().(map[string]any)
|
||||||
if ok {
|
if ok {
|
||||||
if raw, err := json.Marshal(data); err == nil {
|
instance.Load(data)
|
||||||
json.Unmarshal(raw, instance)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
instance = &models.Record{}
|
instance = &models.Record{}
|
||||||
|
@ -129,26 +116,31 @@ func baseBinds(vm *goja.Runtime) {
|
||||||
|
|
||||||
vm.Set("Collection", func(call goja.ConstructorCall) *goja.Object {
|
vm.Set("Collection", func(call goja.ConstructorCall) *goja.Object {
|
||||||
instance := &models.Collection{}
|
instance := &models.Collection{}
|
||||||
return structConstructor(vm, call, instance)
|
return structConstructorUnmarshal(vm, call, instance)
|
||||||
})
|
})
|
||||||
|
|
||||||
vm.Set("Admin", func(call goja.ConstructorCall) *goja.Object {
|
vm.Set("Admin", func(call goja.ConstructorCall) *goja.Object {
|
||||||
instance := &models.Admin{}
|
instance := &models.Admin{}
|
||||||
return structConstructor(vm, call, instance)
|
return structConstructorUnmarshal(vm, call, instance)
|
||||||
})
|
})
|
||||||
|
|
||||||
vm.Set("Schema", func(call goja.ConstructorCall) *goja.Object {
|
vm.Set("Schema", func(call goja.ConstructorCall) *goja.Object {
|
||||||
instance := &schema.Schema{}
|
instance := &schema.Schema{}
|
||||||
return structConstructor(vm, call, instance)
|
return structConstructorUnmarshal(vm, call, instance)
|
||||||
})
|
})
|
||||||
|
|
||||||
vm.Set("SchemaField", func(call goja.ConstructorCall) *goja.Object {
|
vm.Set("SchemaField", func(call goja.ConstructorCall) *goja.Object {
|
||||||
instance := &schema.SchemaField{}
|
instance := &schema.SchemaField{}
|
||||||
|
return structConstructorUnmarshal(vm, call, instance)
|
||||||
|
})
|
||||||
|
|
||||||
|
vm.Set("MailerMessage", func(call goja.ConstructorCall) *goja.Object {
|
||||||
|
instance := &mailer.Message{}
|
||||||
return structConstructor(vm, call, instance)
|
return structConstructor(vm, call, instance)
|
||||||
})
|
})
|
||||||
|
|
||||||
vm.Set("Mail", func(call goja.ConstructorCall) *goja.Object {
|
vm.Set("Command", func(call goja.ConstructorCall) *goja.Object {
|
||||||
instance := &mailer.Message{}
|
instance := &cobra.Command{}
|
||||||
return structConstructor(vm, call, instance)
|
return structConstructor(vm, call, instance)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -307,8 +299,8 @@ func apisBinds(vm *goja.Runtime) {
|
||||||
obj.Set("unauthorizedError", apis.NewUnauthorizedError)
|
obj.Set("unauthorizedError", apis.NewUnauthorizedError)
|
||||||
|
|
||||||
vm.Set("Route", func(call goja.ConstructorCall) *goja.Object {
|
vm.Set("Route", func(call goja.ConstructorCall) *goja.Object {
|
||||||
instance := echo.Route{}
|
instance := &echo.Route{}
|
||||||
return structConstructor(vm, call, &instance)
|
return structConstructor(vm, call, instance)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,7 +331,25 @@ func registerFactoryAsConstructor(vm *goja.Runtime, constructorName string, fact
|
||||||
}
|
}
|
||||||
|
|
||||||
// structConstructor wraps the provided struct with a native JS constructor.
|
// structConstructor wraps the provided struct with a native JS constructor.
|
||||||
|
//
|
||||||
|
// If the constructor argument is a map, each entry of the map will be loaded into the wrapped goja.Object.
|
||||||
func structConstructor(vm *goja.Runtime, call goja.ConstructorCall, instance any) *goja.Object {
|
func structConstructor(vm *goja.Runtime, call goja.ConstructorCall, instance any) *goja.Object {
|
||||||
|
data, _ := call.Argument(0).Export().(map[string]any)
|
||||||
|
|
||||||
|
instanceValue := vm.ToValue(instance).(*goja.Object)
|
||||||
|
for k, v := range data {
|
||||||
|
instanceValue.Set(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
instanceValue.SetPrototype(call.This.Prototype())
|
||||||
|
|
||||||
|
return instanceValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// structConstructorUnmarshal wraps the provided struct with a native JS constructor.
|
||||||
|
//
|
||||||
|
// The constructor first argument will be loaded via json.Unmarshal into the instance.
|
||||||
|
func structConstructorUnmarshal(vm *goja.Runtime, call goja.ConstructorCall, instance any) *goja.Object {
|
||||||
if data := call.Argument(0).Export(); data != nil {
|
if data := call.Argument(0).Export(); data != nil {
|
||||||
if raw, err := json.Marshal(data); err == nil {
|
if raw, err := json.Marshal(data); err == nil {
|
||||||
json.Unmarshal(raw, instance)
|
json.Unmarshal(raw, instance)
|
||||||
|
@ -460,3 +470,42 @@ func newDynamicModel(shape map[string]any) any {
|
||||||
|
|
||||||
return elem.Addr().Interface()
|
return elem.Addr().Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadMapFields(data any, instance any) error {
|
||||||
|
if reflect.TypeOf(data).Kind() != reflect.Map {
|
||||||
|
return errors.New("data must be map")
|
||||||
|
}
|
||||||
|
|
||||||
|
if reflect.TypeOf(instance).Kind() != reflect.Pointer {
|
||||||
|
return errors.New("instance must be pointer")
|
||||||
|
}
|
||||||
|
|
||||||
|
iv := reflect.ValueOf(instance).Elem()
|
||||||
|
if iv.Kind() != reflect.Struct {
|
||||||
|
return errors.New("value must be a pointer to a struct/interface")
|
||||||
|
}
|
||||||
|
|
||||||
|
dv := reflect.ValueOf(data)
|
||||||
|
|
||||||
|
for _, k := range dv.MapKeys() {
|
||||||
|
name := strings.Title(k.String()) // @todo reverse mapping
|
||||||
|
field := iv.FieldByName(name)
|
||||||
|
|
||||||
|
if !field.CanSet() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
v := dv.MapIndex(k)
|
||||||
|
|
||||||
|
if !v.CanInterface() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// if v.Type().Kind() == reflect.Func {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// field.Set(reflect.ValueOf(v.Interface()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -27,25 +27,6 @@ func TestBaseBindsCount(t *testing.T) {
|
||||||
testBindsCount(vm, "this", 14, t)
|
testBindsCount(vm, "this", 14, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBaseBindsUnmarshal(t *testing.T) {
|
|
||||||
vm := goja.New()
|
|
||||||
baseBinds(vm)
|
|
||||||
|
|
||||||
v, err := vm.RunString(`unmarshal({ name: "test" }, new Collection())`)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
m, ok := v.Export().(*models.Collection)
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("Expected models.Collection, got %v", m)
|
|
||||||
}
|
|
||||||
|
|
||||||
if m.Name != "test" {
|
|
||||||
t.Fatalf("Expected collection with name %q, got %q", "test", m.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBaseBindsRecord(t *testing.T) {
|
func TestBaseBindsRecord(t *testing.T) {
|
||||||
app, _ := tests.NewTestApp()
|
app, _ := tests.NewTestApp()
|
||||||
defer app.Cleanup()
|
defer app.Cleanup()
|
||||||
|
@ -168,11 +149,11 @@ func TestBaseBindsSchemaField(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBaseBindsMail(t *testing.T) {
|
func TestBaseBindsMailerMessage(t *testing.T) {
|
||||||
vm := goja.New()
|
vm := goja.New()
|
||||||
baseBinds(vm)
|
baseBinds(vm)
|
||||||
|
|
||||||
v, err := vm.RunString(`new Mail({
|
v, err := vm.RunString(`new MailerMessage({
|
||||||
from: {name: "test_from", address: "test_from@example.com"},
|
from: {name: "test_from", address: "test_from@example.com"},
|
||||||
to: [
|
to: [
|
||||||
{name: "test_to1", address: "test_to1@example.com"},
|
{name: "test_to1", address: "test_to1@example.com"},
|
||||||
|
@ -212,6 +193,35 @@ func TestBaseBindsMail(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBaseBindsCommand(t *testing.T) {
|
||||||
|
vm := goja.New()
|
||||||
|
baseBinds(vm)
|
||||||
|
|
||||||
|
_, err := vm.RunString(`
|
||||||
|
let runCalls = 0;
|
||||||
|
|
||||||
|
let cmd = new Command({
|
||||||
|
use: "test",
|
||||||
|
run: (c, args) => {
|
||||||
|
runCalls++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
cmd.run(null, []);
|
||||||
|
|
||||||
|
if (cmd.use != "test") {
|
||||||
|
throw new Error('Expected cmd.use "test", got: ' + cmd.use);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runCalls != 1) {
|
||||||
|
throw new Error('Expected runCalls 1, got: ' + runCalls);
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBaseBindsValidationError(t *testing.T) {
|
func TestBaseBindsValidationError(t *testing.T) {
|
||||||
vm := goja.New()
|
vm := goja.New()
|
||||||
baseBinds(vm)
|
baseBinds(vm)
|
||||||
|
|
Loading…
Reference in New Issue