mirror of
https://github.com/TECHNOFAB11/docsonnet.git
synced 2025-12-15 07:43:55 +01:00
235 lines
4.8 KiB
Go
235 lines
4.8 KiB
Go
|
|
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
|
||
|
|
}
|