forked from robertkrimen/otto
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
141 lines (118 loc) · 3.33 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Command gen-jscore generates go representations of JavaScript core types file.
package main
import (
"embed"
"flag"
"fmt"
"log"
"os"
"os/exec"
"strings"
"text/template"
"gopkg.in/yaml.v3"
)
//go:embed .gen-jscore.yaml
var configData []byte
//go:embed templates/*
var templates embed.FS
// jsType represents JavaScript type to generate.
type jsType struct {
Name string `yaml:"name"`
Core bool `yaml:"core"`
ObjectClass string `yaml:"objectClass"`
ObjectPrototype string `yaml:"objectPrototype"`
Class string `yaml:"class"`
Value string `yaml:"value"`
Properties []property `yaml:"properties"`
Prototype *prototype `yaml:"prototype"`
}
// BlankConstructor is a default fallback returning false for templates.
func (t jsType) BlankConstructor() bool {
return false
}
// prototype represents a JavaScript prototype to generate.
type prototype struct {
Value string `yaml:"value"`
ObjectClass string `yaml:"objectClass"`
Prototype string `yaml:"prototype"`
Properties []property `yaml:"properties"`
}
// Property returns the property with the given name.
func (p prototype) Property(name string) (*property, error) {
for _, prop := range p.Properties {
if prop.Name == name {
return &prop, nil
}
}
return nil, fmt.Errorf("missing property %q", name)
}
// property represents a JavaScript property to generate.
type property struct {
Name string `yaml:"name"`
Call string `yaml:"call"`
Function int `yaml:"function"`
Mode string `yaml:"mode"`
Value string `yaml:"value"`
Kind string `yaml:"kind"`
}
// value represents a JavaScript value to generate a Value creator for.
type value struct {
Name string `yaml:"name"`
Type string `yaml:"type"`
}
// config represents our configuration.
type config struct {
Types []jsType `yaml:"types"`
Log jsType `yaml:"log"`
Values []value `yaml:"values"`
}
// Type returns the type for name.
func (c config) Type(name string) (*jsType, error) {
for _, t := range c.Types {
if t.Name == name {
return &t, nil
}
}
return nil, fmt.Errorf("missing type %q", name)
}
// generate generates the context file writing the output to filename.
func generate(filename string) (err error) {
var cfg config
if err := yaml.Unmarshal(configData, &cfg); err != nil {
return fmt.Errorf("decode config: %w", err)
}
tmpl := template.New("base").Funcs(template.FuncMap{
"ucfirst": ucfirst,
"dict": dict,
"contains": strings.Contains,
})
tmpl, err = tmpl.ParseFS(templates, "templates/*.tmpl")
if err != nil {
return fmt.Errorf("parse templates: %w", err)
}
output, err := os.Create(filename) //nolint: gosec
if err != nil {
return fmt.Errorf("open output: %w", err)
}
defer func() {
if errc := output.Close(); err == nil && errc != nil {
err = errc
}
}()
if err := tmpl.ExecuteTemplate(output, "root.tmpl", cfg); err != nil {
return fmt.Errorf("execute template: %w", err)
}
cmd := exec.Command("gofmt", "-w", filename)
buf, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("format output %q: %w", string(buf), err)
}
return nil
}
func main() {
var filename string
flag.StringVar(&filename, "output", "inline.go", "the filename to write the generated code to")
if err := generate(filename); err != nil {
log.Fatal(err)
}
}