From 14e9fc8f3fc8182106b1f7e34b98e9d1539051c2 Mon Sep 17 00:00:00 2001 From: sh0rez Date: Tue, 12 May 2020 15:23:24 +0200 Subject: [PATCH] refactor(render): filewriting in render pkg --- fast/main.go | 234 ------------------------------------------ main.go | 29 ++++-- pkg/docsonnet/fast.go | 5 - pkg/docsonnet/load.go | 4 +- pkg/render/fs.go | 32 ++++++ pkg/render/paths.go | 28 ----- pkg/render/render.go | 19 +++- 7 files changed, 67 insertions(+), 284 deletions(-) delete mode 100644 fast/main.go create mode 100644 pkg/render/fs.go delete mode 100644 pkg/render/paths.go diff --git a/fast/main.go b/fast/main.go deleted file mode 100644 index 9bfa25f..0000000 --- a/fast/main.go +++ /dev/null @@ -1,234 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "log" - "path/filepath" - "strings" - "time" - - "github.com/google/go-jsonnet" - "github.com/sh0rez/docsonnet/pkg/docsonnet" - "github.com/sh0rez/docsonnet/pkg/render" -) - -func main() { - data, err := eval() - if err != nil { - log.Fatalln(err) - } - // fmt.Println(string(data)) - - var d DS - if err := json.Unmarshal(data, &d); err != nil { - log.Fatalln(err) - } - - pkg := load(d) - - fmt.Println("render") - res := render.Render(pkg) - for k, v := range res { - fmt.Println(k) - if err := ioutil.WriteFile(filepath.Join("docs", k), []byte(v), 0644); err != nil { - log.Fatalln(err) - } - } -} - -// load docsonnet -// -// Data assumptions: -// - only map[string]interface{} and docsonnet fields -// - docsonnet fields (#...) coming first -func load(d DS) docsonnet.Package { - start := time.Now() - - pkg := d.Package() - fmt.Println("load", pkg.Name) - - pkg.API = make(docsonnet.Fields) - pkg.Sub = make(map[string]docsonnet.Package) - - for k, v := range d { - if k == "#" { - continue - } - - f := v.(map[string]interface{}) - - // docsonnet field - name := strings.TrimPrefix(k, "#") - if strings.HasPrefix(k, "#") { - pkg.API[name] = loadField(name, f, d) - continue - } - - // non-docsonnet - // subpackage? - if _, ok := f["#"]; ok { - p := load(DS(f)) - pkg.Sub[p.Name] = p - continue - } - - // non-annotated nested? - // try to load, but skip when already loaded as annotated above - if nested, ok := loadNested(name, f); ok && !fieldsHas(pkg.API, name) { - pkg.API[name] = *nested - continue - } - } - - fmt.Println("done load", pkg.Name, time.Since(start)) - return pkg -} - -func fieldsHas(f docsonnet.Fields, key string) bool { - _, b := f[key] - return b -} - -func loadNested(name string, msi map[string]interface{}) (*docsonnet.Field, bool) { - out := docsonnet.Object{ - Name: name, - Fields: make(docsonnet.Fields), - } - - ok := false - for k, v := range msi { - f := v.(map[string]interface{}) - n := strings.TrimPrefix(k, "#") - - if !strings.HasPrefix(k, "#") { - if l, ok := loadNested(k, f); ok { - out.Fields[n] = *l - } - continue - } - - ok = true - l := loadField(n, f, msi) - out.Fields[n] = l - } - - if !ok { - return nil, false - } - - return &docsonnet.Field{Object: &out}, true -} - -func loadField(name string, field map[string]interface{}, parent map[string]interface{}) docsonnet.Field { - if ifn, ok := field["function"]; ok { - return loadFn(name, ifn.(map[string]interface{})) - } - - if iobj, ok := field["object"]; ok { - return loadObj(name, iobj.(map[string]interface{}), parent) - } - - panic("docsonnet field lacking {function | object}") -} - -func loadFn(name string, msi map[string]interface{}) docsonnet.Field { - fn := docsonnet.Function{ - Name: name, - Help: msi["help"].(string), - } - if args, ok := msi["args"]; ok { - fn.Args = loadArgs(args.([]interface{})) - } - return docsonnet.Field{Function: &fn} -} - -func loadArgs(is []interface{}) []docsonnet.Argument { - args := make([]docsonnet.Argument, len(is)) - for i := range is { - arg := is[i].(map[string]interface{}) - args[i] = docsonnet.Argument{ - Name: arg["name"].(string), - Type: docsonnet.Type(arg["type"].(string)), - Default: arg["default"], - } - } - return args -} - -func fieldNames(msi map[string]interface{}) []string { - out := make([]string, 0, len(msi)) - for k := range msi { - out = append(out, k) - } - return out -} - -func loadObj(name string, msi map[string]interface{}, parent map[string]interface{}) docsonnet.Field { - obj := docsonnet.Object{ - Name: name, - Help: msi["help"].(string), - Fields: make(docsonnet.Fields), - } - - // look for children in same key without # - var iChilds interface{} - var ok bool - if iChilds, ok = parent[name]; !ok { - fmt.Println("aborting, no", name, strings.Join(fieldNames(parent), ", ")) - return docsonnet.Field{Object: &obj} - } - - childs := iChilds.(map[string]interface{}) - for k, v := range childs { - name := strings.TrimPrefix(k, "#") - f := v.(map[string]interface{}) - if !strings.HasPrefix(k, "#") { - if l, ok := loadNested(k, f); ok { - obj.Fields[name] = *l - } - continue - } - - obj.Fields[name] = loadField(name, f, childs) - } - - return docsonnet.Field{Object: &obj} -} - -type DS map[string]interface{} - -func (d DS) Package() docsonnet.Package { - hash, ok := d["#"] - if !ok { - log.Fatalln("Package declaration missing") - } - - pkg := hash.(map[string]interface{}) - return docsonnet.Package{ - Help: pkg["help"].(string), - Name: pkg["name"].(string), - Import: pkg["import"].(string), - } -} - -func eval() ([]byte, error) { - fmt.Println("eval start") - start := time.Now() - - vm := jsonnet.MakeVM() - vm.Importer(&jsonnet.FileImporter{JPaths: []string{".."}}) - data, err := ioutil.ReadFile("fast.libsonnet") - if err != nil { - return nil, err - } - - out, err := vm.EvaluateSnippet("fast.libsonnet", string(data)) - if err != nil { - return nil, err - } - - fmt.Println("eval:", time.Since(start)) - return []byte(out), nil -} diff --git a/main.go b/main.go index 6ae01ad..51910b5 100644 --- a/main.go +++ b/main.go @@ -1,10 +1,9 @@ package main import ( + "encoding/json" "fmt" - "io/ioutil" "log" - "path/filepath" "github.com/go-clix/cli" @@ -20,19 +19,27 @@ func main() { Short: "Utility to parse and transform Jsonnet code that uses the docsonnet extension", } - output := root.Flags().StringP("output", "o", "docs", "directory to write the .md files to") + dir := root.Flags().StringP("output", "o", "docs", "directory to write the .md files to") + outputMd := root.Flags().Bool("md", true, "render as markdown files") + outputJSON := root.Flags().Bool("json", false, "print loaded docsonnet as JSON") + root.Run = func(cmd *cli.Command, args []string) error { - pkg, err := docsonnet.Load(args[0]) - if err != nil { - return err - } + file := args[0] - data := render.Render(*pkg) - for k, v := range data { - fmt.Println(k) - if err := ioutil.WriteFile(filepath.Join(*output, k), []byte(v), 0644); err != nil { + switch { + case *outputJSON: + model, err := docsonnet.Load(file) + if err != nil { return err } + data, err := json.MarshalIndent(model, "", " ") + if err != nil { + return err + } + + fmt.Println(string(data)) + case *outputMd: + return render.To(file, *dir) } return nil diff --git a/pkg/docsonnet/fast.go b/pkg/docsonnet/fast.go index 56e7b72..2584fb6 100644 --- a/pkg/docsonnet/fast.go +++ b/pkg/docsonnet/fast.go @@ -4,7 +4,6 @@ import ( "fmt" "log" "strings" - "time" ) // load docsonnet @@ -13,10 +12,7 @@ import ( // - only map[string]interface{} and fields // - fields (#...) coming first func fastLoad(d DS) Package { - start := time.Now() - pkg := d.Package() - fmt.Println("load", pkg.Name) pkg.API = make(Fields) pkg.Sub = make(map[string]Package) @@ -51,7 +47,6 @@ func fastLoad(d DS) Package { } } - fmt.Println("done load", pkg.Name, time.Since(start)) return pkg } diff --git a/pkg/docsonnet/load.go b/pkg/docsonnet/load.go index 9853836..cf897f2 100644 --- a/pkg/docsonnet/load.go +++ b/pkg/docsonnet/load.go @@ -33,13 +33,13 @@ func Load(filename string) (*Package, error) { // invoke load.libsonnet vm.ExtCode("main", fmt.Sprintf(`(import "%s")`, filename)) - log.Println("evaluating Jsonnet") + log.Println("Evaluating Jsonnet") data, err := vm.EvaluateSnippet("load.libsonnet", string(load)) if err != nil { return nil, err } - log.Println("parsing result") + log.Println("Transforming result") // parse the result var d DS if err := json.Unmarshal([]byte(data), &d); err != nil { diff --git a/pkg/render/fs.go b/pkg/render/fs.go new file mode 100644 index 0000000..ef93c52 --- /dev/null +++ b/pkg/render/fs.go @@ -0,0 +1,32 @@ +package render + +import ( + "io/ioutil" + "log" + "os" + "path/filepath" + + "github.com/sh0rez/docsonnet/pkg/docsonnet" +) + +func To(api, out string) error { + pkg, err := docsonnet.Load(api) + if err != nil { + return err + } + + if err := os.MkdirAll(out, os.ModePerm); err != nil { + return err + } + + log.Println("Rendering .md files") + data := Render(*pkg) + for k, v := range data { + if err := ioutil.WriteFile(filepath.Join(out, k), []byte(v), 0644); err != nil { + return err + } + } + + log.Printf("Success! Rendered %v packages from '%s' to '%s'", len(data), api, out) + return nil +} diff --git a/pkg/render/paths.go b/pkg/render/paths.go deleted file mode 100644 index 481b1ba..0000000 --- a/pkg/render/paths.go +++ /dev/null @@ -1,28 +0,0 @@ -package render - -import ( - "github.com/sh0rez/docsonnet/pkg/docsonnet" -) - -func Paths(pkg docsonnet.Package) map[string]docsonnet.Package { - p := paths(pkg) - return p -} - -func paths(pkg docsonnet.Package) map[string]docsonnet.Package { - pkgs := make(map[string]docsonnet.Package) - pkgs[pkg.Name+".md"] = pkg - - if len(pkg.Sub) == 0 { - return pkgs - } - - for _, sub := range pkg.Sub { - for k, v := range paths(sub) { - v.Name = pkg.Name + "/" + k - pkgs[pkg.Name+"-"+k] = v - } - } - - return pkgs -} diff --git a/pkg/render/render.go b/pkg/render/render.go index 792d2bf..c337a74 100644 --- a/pkg/render/render.go +++ b/pkg/render/render.go @@ -15,7 +15,6 @@ func Render(pkg docsonnet.Package) map[string]string { } func render(pkg docsonnet.Package, parents []string, root bool) map[string]string { - fmt.Println("render", pkg.Name) link := "/" + strings.Join(append(parents, pkg.Name), "/") if root { link = "/" @@ -27,20 +26,32 @@ func render(pkg docsonnet.Package, parents []string, root bool) map[string]strin "permalink": link, }), md.Headline(1, "package "+pkg.Name), - md.CodeBlock("jsonnet", fmt.Sprintf(`local %s = import "%s"`, pkg.Name, pkg.Import)), - md.Text(pkg.Help), } + if pkg.Import != "" { + elems = append(elems, md.CodeBlock("jsonnet", fmt.Sprintf(`local %s = import "%s"`, pkg.Name, pkg.Import))) + } + elems = append(elems, md.Text(pkg.Help)) if len(pkg.Sub) > 0 { elems = append(elems, md.Headline(2, "Subpackages")) - var items []md.Elem + + keys := make([]string, 0, len(pkg.Sub)) for _, s := range pkg.Sub { + keys = append(keys, s.Name) + } + sort.Strings(keys) + + var items []md.Elem + for _, k := range keys { + s := pkg.Sub[k] + link := strings.Join(append(parents, pkg.Name, s.Name), "-") if root { link = strings.Join(append(parents, s.Name), "-") } items = append(items, md.Link(md.Text(s.Name), link+".md")) } + elems = append(elems, md.List(items...)) }