├── core ├── event-loop.go ├── console.go ├── rts.go └── loader.go ├── test.js ├── go.mod ├── main.go ├── README.md └── go.sum /core/event-loop.go: -------------------------------------------------------------------------------- 1 | package core 2 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | function test() { 2 | console.log('hello world\n'); 3 | return 'Hello Golang~'; 4 | } 5 | 6 | module.exports = { 7 | test: test, 8 | }; 9 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/81120/gode 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/dlclark/regexp2 v1.2.0 // indirect 7 | github.com/dop251/goja v0.0.0-20190912223329-aa89e6a4c733 8 | github.com/go-sourcemap/sourcemap v2.1.2+incompatible // indirect 9 | golang.org/x/text v0.3.2 // indirect 10 | ) 11 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/81120/gode/core" 7 | ) 8 | 9 | func main() { 10 | gode := core.New() 11 | gode.RegisterBuildInModule() 12 | 13 | r := gode.GetRts() 14 | v, err := r.RunString(` 15 | var t = require('./test.js'); 16 | t.test(); 17 | `) 18 | if err != nil { 19 | fmt.Print(err) 20 | } else { 21 | fmt.Println(v) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core/console.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | 6 | js "github.com/dop251/goja" 7 | ) 8 | 9 | func log(call js.FunctionCall) js.Value { 10 | str := call.Argument(0) 11 | fmt.Print(str.String()) 12 | return str 13 | } 14 | 15 | // RegisterConsole register a console.log to runtime 16 | func RegisterConsole(c *Core) { 17 | r := c.GetRts() 18 | o := r.NewObject() 19 | o.Set("log", log) 20 | r.Set("console", o) 21 | } 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gode 2 | 3 | A test project to implement a Node like javascript environment based on goja 4 | 5 | # Example 6 | 7 | ```golang 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | 13 | "github.com/81120/gode/core" 14 | ) 15 | 16 | func main() { 17 | gode := core.New() 18 | gode.RegisterBuildInModule() 19 | 20 | r := gode.GetRts() 21 | v, err := r.RunString(` 22 | var t = require('./test.js'); 23 | t.test(); 24 | `) 25 | if err != nil { 26 | fmt.Print(err) 27 | } else { 28 | fmt.Println(v) 29 | } 30 | } 31 | ``` 32 | -------------------------------------------------------------------------------- /core/rts.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | js "github.com/dop251/goja" 5 | ) 6 | 7 | // Core is the basic struct of gode 8 | type Core struct { 9 | Rts *js.Runtime 10 | Pkg map[string]js.Value 11 | } 12 | 13 | // New create a *Core 14 | func New() *Core { 15 | vm := js.New() 16 | pkg := make(map[string]js.Value) 17 | 18 | return &Core{ 19 | Rts: vm, 20 | Pkg: pkg, 21 | } 22 | } 23 | 24 | // GetRts get the object of javascript runtime 25 | func (c *Core) GetRts() *js.Runtime { 26 | return c.Rts 27 | } 28 | 29 | // RegisterBuildInModule register some build in modules to the runtime 30 | func (c *Core) RegisterBuildInModule() { 31 | RegisterConsole(c) 32 | RegisterLoader(c) 33 | } 34 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk= 2 | github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= 3 | github.com/dop251/goja v0.0.0-20190912223329-aa89e6a4c733 h1:cyNc40Dx5YNEO94idePU8rhVd3dn+sd04Arh0kDBAaw= 4 | github.com/dop251/goja v0.0.0-20190912223329-aa89e6a4c733/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= 5 | github.com/go-sourcemap/sourcemap v2.1.2+incompatible h1:0b/xya7BKGhXuqFESKM4oIiRo9WOt2ebz7KxfreD6ug= 6 | github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= 7 | golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= 8 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 9 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 10 | -------------------------------------------------------------------------------- /core/loader.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "io/ioutil" 5 | "path/filepath" 6 | 7 | js "github.com/dop251/goja" 8 | ) 9 | 10 | func moduleTemplate(c string) string { 11 | return "(function(module, exports) {" + c + "\n})" 12 | } 13 | 14 | func createModule(c *Core) *js.Object { 15 | r := c.GetRts() 16 | m := r.NewObject() 17 | e := r.NewObject() 18 | m.Set("exports", e) 19 | 20 | return m 21 | } 22 | 23 | func compileModule(p string) *js.Program { 24 | code, _ := ioutil.ReadFile(p) 25 | text := moduleTemplate(string(code)) 26 | prg, _ := js.Compile(p, text, false) 27 | 28 | return prg 29 | } 30 | 31 | func loadModule(c *Core, p string) js.Value { 32 | p = filepath.Clean(p) 33 | pkg := c.Pkg[p] 34 | if pkg != nil { 35 | return pkg 36 | } 37 | 38 | prg := compileModule(p) 39 | 40 | r := c.GetRts() 41 | f, _ := r.RunProgram(prg) 42 | g, _ := js.AssertFunction(f) 43 | 44 | m := createModule(c) 45 | jsExports := m.Get("exports") 46 | g(jsExports, m, jsExports) 47 | 48 | return m.Get("exports") 49 | } 50 | 51 | // RegisterLoader register a simple commonjs style loader to runtime 52 | func RegisterLoader(c *Core) { 53 | r := c.GetRts() 54 | 55 | r.Set("require", func(call js.FunctionCall) js.Value { 56 | p := call.Argument(0).String() 57 | return loadModule(c, p) 58 | }) 59 | } 60 | --------------------------------------------------------------------------------