Skip to content

Commit

Permalink
WIDL imports and developer experience enhancements (#4)
Browse files Browse the repository at this point in the history
* WIDL imports and developer experience enhancements

* Upgrade to rogchap.com/v8go v0.6.0
  • Loading branch information
pkedy authored May 12, 2021
1 parent 38ae727 commit ad27b0e
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 18 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ require (
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
rogchap.com/v8go v0.5.2-0.20210423120543-491864424893
rogchap.com/v8go v0.6.0
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,5 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
rogchap.com/v8go v0.5.2-0.20210423120543-491864424893 h1:4yu8bXxoh1FkLSp21WRMieH+0xmlkFAczeEUibvQZFQ=
rogchap.com/v8go v0.5.2-0.20210423120543-491864424893/go.mod h1:IitZnaOtWSJadY/7qinKHIEHpxsilMWyLQ+Efdo4n4I=
rogchap.com/v8go v0.6.0 h1:wNn5Iu06+ke7HM511zXTVBBpRNYaauyZoPMTrLsGurU=
rogchap.com/v8go v0.6.0/go.mod h1:IitZnaOtWSJadY/7qinKHIEHpxsilMWyLQ+Efdo4n4I=
83 changes: 78 additions & 5 deletions pkg/commands/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/evanw/esbuild/pkg/api"
"gopkg.in/yaml.v3"
"rogchap.com/v8go"

"github.com/wapc/cli/pkg/js"
)
Expand All @@ -28,8 +29,9 @@ type GenerateCmd struct {
}

type Config struct {
Schema string `json:"schema" yaml:"schema"`
Generates map[string]Target `json:"generates" yaml:"generates"`
Schema string `json:"schema" yaml:"schema"`
Config map[string]interface{} `json:"config,omitempty" yaml:"config,omitempty"`
Generates map[string]Target `json:"generates" yaml:"generates"`
}

type Target struct {
Expand All @@ -43,15 +45,22 @@ const generateTemplate = `import { parse } from "@wapc/widl";
import { Context, Writer } from "@wapc/widl/ast";
import { {{visitorClass}} } from "{{module}}";
function resolver(location, from) {
const source = resolverCallback(location, from);
if (source.startsWith("error: ")) {
throw source.substring(7);
}
return source;
}
export function generate(widl, config) {
const doc = parse(widl);
const doc = parse(widl, resolver);
const context = new Context(config);
const writer = new Writer();
const visitor = new {{visitorClass}}(writer);
doc.accept(context, visitor);
let source = writer.string();
console.log(source);
return source;
}
Expand Down Expand Up @@ -109,6 +118,17 @@ func (c *GenerateCmd) generate(configYAML string) error {
continue
}
}

// Merge global config into target config
if target.Config == nil && config.Config != nil {
target.Config = make(map[string]interface{}, len(config.Config))
}
for k, v := range config.Config {
if _, exists := target.Config[k]; !exists {
target.Config[k] = v
}
}

fmt.Printf("Generating %s...\n", filename)
generateTS := generateTemplate
generateTS = strings.Replace(generateTS, "{{module}}", target.Module, 1)
Expand All @@ -133,7 +153,57 @@ func (c *GenerateCmd) generate(configYAML string) error {

bundle := string(result.OutputFiles[0].Contents)

j, err := js.Compile(bundle)
definitionsDir := filepath.Join(homeDir, "definitions")

resolverCallback := func(info *v8go.FunctionCallbackInfo) *v8go.Value {
iso, err := info.Context().Isolate()
if err != nil {
return nil
}

if len(info.Args()) < 1 {
value, _ := v8go.NewValue(iso, "error: resolve: invalid arguments")
return value
}

location := info.Args()[0].String()

loc := filepath.Join(definitionsDir, filepath.Join(strings.Split(location, "/")...))
if filepath.Ext(loc) != ".widl" {
widlLoc := loc + ".widl"
found := false
stat, err := os.Stat(widlLoc)
if err == nil {
found = !stat.IsDir()
}

if !found {
stat, err := os.Stat(loc)
if err != nil {
value, _ := v8go.NewValue(iso, fmt.Sprintf("error: %v", err))
return value
}
if stat.IsDir() {
loc = filepath.Join(loc, "index.widl")
} else {
loc += ".widl"
}
}
}

data, err := os.ReadFile(loc)
if err != nil {
value, _ := v8go.NewValue(iso, fmt.Sprintf("error: %v", err))
return value
}

value, _ := v8go.NewValue(iso, string(data))
return value
}

j, err := js.Compile(bundle, map[string]v8go.FunctionCallback{
"resolverCallback": resolverCallback,
})
if err != nil {
return err
}
Expand All @@ -144,6 +214,9 @@ func (c *GenerateCmd) generate(configYAML string) error {
}
res, err := j.Invoke("generate", schema, target.Config)
if err != nil {
if jserr, ok := err.(*v8go.JSError); ok {
jserr.Message = strings.TrimPrefix(jserr.Message, "Error: ")
}
return err
}

Expand Down
28 changes: 28 additions & 0 deletions pkg/commands/home.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@ func getHomeDirectory() (string, error) {
return wapcHome, err
}

const tsconfigContents = `{
"compilerOptions": {
"module": "commonjs",
"target": "esnext",
"baseUrl": ".",
"lib": [
"esnext"
],
"outDir": "../dist"
}
}
`

func ensureHomeDirectory() (string, error) {
home, err := homedir.Dir()
if err != nil {
Expand All @@ -42,19 +55,34 @@ func ensureHomeDirectory() (string, error) {
wapcHome := filepath.Join(home, ".wapc")
srcDir := filepath.Join(wapcHome, "src")
templatesDir := filepath.Join(wapcHome, "templates")
definitionsDir := filepath.Join(wapcHome, "definitions")

if _, err := os.Stat(srcDir); os.IsNotExist(err) {
if err = os.MkdirAll(srcDir, 0700); err != nil {
return "", err
}
}

// Create tsconfig.json inside the src directory for editing inside an IDE.
tsconfigJSON := filepath.Join(srcDir, "tsconfig.json")
if _, err := os.Stat(tsconfigJSON); os.IsNotExist(err) {
if err = os.WriteFile(tsconfigJSON, []byte(tsconfigContents), 0644); err != nil {
return "", err
}
}

if _, err := os.Stat(templatesDir); os.IsNotExist(err) {
if err = os.MkdirAll(templatesDir, 0700); err != nil {
return "", err
}
}

if _, err := os.Stat(definitionsDir); os.IsNotExist(err) {
if err = os.MkdirAll(definitionsDir, 0700); err != nil {
return "", err
}
}

return wapcHome, nil
}

Expand Down
47 changes: 39 additions & 8 deletions pkg/commands/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type releaseInfo struct {
Org string
Module string
Tag string
Directory string
ZipURL string
TarballURL string
}
Expand Down Expand Up @@ -56,6 +57,19 @@ func (c *InstallCmd) doRun(ctx *Context, homeDir string) error {

fmt.Printf("Installing %s/%s %s...\n", release.Org, release.Module, release.Tag)

moduleSubDir := release.Module
if release.Org != "" {
moduleSubDir = filepath.Join(release.Org, release.Module)
}

if release.Directory != "" {
return c.installDir(
release.Directory,
homeDir,
moduleSubDir,
)
}

f, err := os.CreateTemp("", "install-*")
if err != nil {
return err
Expand Down Expand Up @@ -118,15 +132,10 @@ func (c *InstallCmd) doRun(ctx *Context, homeDir string) error {
contentsDir := filepath.Join(downloadDir, entry.Name())
readPackage(contentsDir, release)

modulePart := release.Module
if release.Org != "" {
modulePart = filepath.Join(release.Org, release.Module)
}

if err = c.installDir(
contentsDir,
homeDir,
modulePart,
moduleSubDir,
); err != nil {
return err
}
Expand All @@ -137,13 +146,34 @@ func (c *InstallCmd) doRun(ctx *Context, homeDir string) error {
}

func (c *InstallCmd) getReleaseInfo(location, releaseTag string) (*releaseInfo, error) {
if strings.HasPrefix(location, "file:") {
return c.getReleaseInfoFromDirectory(location[5:], releaseTag)
}
if strings.HasPrefix(location, "github.com/") {
return c.getReleaseInfoFromGithub(location[11:], releaseTag)
}

return c.getReleaseInfoFromNPM(location, releaseTag)
}

func (c *InstallCmd) getReleaseInfoFromDirectory(location, releaseTag string) (*releaseInfo, error) {
dir := filepath.Clean(location)
fi, err := os.Stat(dir)
if err != nil {
return nil, err
}
if !fi.IsDir() {
return nil, fmt.Errorf("%s is not a directory", dir)
}
release := releaseInfo{
Directory: dir,
}
if err = readPackage(dir, &release); err != nil {
return nil, err
}
return &release, nil
}

func (c *InstallCmd) getReleaseInfoFromNPM(location, releaseTag string) (*releaseInfo, error) {
type dist struct {
Tarball string `json:"tarball"`
Expand Down Expand Up @@ -258,8 +288,9 @@ func (c *InstallCmd) getReleaseInfoFromGithub(location, releaseTag string) (*rel
}

var extensionDirectories = map[string]struct{}{
"src": {},
"templates": {},
"src": {},
"templates": {},
"definitions": {},
}

func (c *InstallCmd) installDir(src string, dest string, modulePart string) error {
Expand Down
39 changes: 37 additions & 2 deletions pkg/js/js.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,50 @@ type JS struct {
ctx *v8go.Context
}

func Compile(source string) (*JS, error) {
func Compile(source string, globals ...map[string]v8go.FunctionCallback) (*JS, error) {
iso, err := v8go.NewIsolate()
if err != nil {
return nil, err
}
ctx, err := v8go.NewContext(iso)
global, err := v8go.NewObjectTemplate(iso)
if err != nil {
return nil, err
}
console, err := v8go.NewObjectTemplate(iso)
if err != nil {
return nil, err
}
log, err := v8go.NewFunctionTemplate(iso, func(info *v8go.FunctionCallbackInfo) *v8go.Value {
args := make([]interface{}, len(info.Args()))
for i, a := range info.Args() {
args[i] = a
}
fmt.Println(args...)
return nil
})
if err != nil {
return nil, err
}
console.Set("log", log)
global.Set("println", log)
for _, g := range globals {
for name, callback := range g {
funcTemp, err := v8go.NewFunctionTemplate(iso, callback)
if err != nil {
return nil, err
}
global.Set(name, funcTemp)
}
}
ctx, err := v8go.NewContext(iso, global)
if err != nil {
return nil, err
}
consoleObject, err := console.NewInstance(ctx)
if err != nil {
return nil, err
}
ctx.Global().Set("console", consoleObject)
_, err = ctx.RunScript(`var js_exports = {};`, "exports.js")
if err != nil {
return nil, err
Expand Down

0 comments on commit ad27b0e

Please sign in to comment.