mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-03 02:27:48 +00:00
173 lines
4.2 KiB
Go
173 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"go/ast"
|
|
"go/doc"
|
|
"go/format"
|
|
"go/token"
|
|
"log"
|
|
"os"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// Result holds the extracted documentation for a single target.
|
|
type Result struct {
|
|
Target Target
|
|
Pkg *doc.Package
|
|
Fset *token.FileSet
|
|
}
|
|
|
|
// JSON-serializable API types.
|
|
|
|
type PackageAPI struct {
|
|
Target string `json:"target"`
|
|
Package string `json:"package"`
|
|
Doc string `json:"doc,omitempty"`
|
|
Constants []APIValue `json:"constants,omitempty"`
|
|
Variables []APIValue `json:"variables,omitempty"`
|
|
Types []APIType `json:"types,omitempty"`
|
|
Functions []APIFunc `json:"functions,omitempty"`
|
|
}
|
|
|
|
type APIValue struct {
|
|
Doc string `json:"doc,omitempty"`
|
|
Names []string `json:"names"`
|
|
Decl string `json:"decl"`
|
|
}
|
|
|
|
type APIType struct {
|
|
Doc string `json:"doc,omitempty"`
|
|
Name string `json:"name"`
|
|
Decl string `json:"decl"`
|
|
Constants []APIValue `json:"constants,omitempty"`
|
|
Variables []APIValue `json:"variables,omitempty"`
|
|
Functions []APIFunc `json:"functions,omitempty"`
|
|
Methods []APIFunc `json:"methods,omitempty"`
|
|
}
|
|
|
|
type APIFunc struct {
|
|
Doc string `json:"doc,omitempty"`
|
|
Name string `json:"name"`
|
|
Decl string `json:"decl"`
|
|
Recv string `json:"recv,omitempty"`
|
|
}
|
|
|
|
func formatNode(fset *token.FileSet, node ast.Node) string {
|
|
var buf bytes.Buffer
|
|
format.Node(&buf, fset, node)
|
|
return buf.String()
|
|
}
|
|
|
|
func convertValues(fset *token.FileSet, vals []*doc.Value) []APIValue {
|
|
out := make([]APIValue, 0, len(vals))
|
|
for _, v := range vals {
|
|
out = append(out, APIValue{
|
|
Doc: v.Doc,
|
|
Names: v.Names,
|
|
Decl: formatNode(fset, v.Decl),
|
|
})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func convertFuncs(fset *token.FileSet, funcs []*doc.Func) []APIFunc {
|
|
out := make([]APIFunc, 0, len(funcs))
|
|
for _, f := range funcs {
|
|
out = append(out, APIFunc{
|
|
Doc: f.Doc,
|
|
Name: f.Name,
|
|
Decl: formatNode(fset, f.Decl),
|
|
Recv: f.Recv,
|
|
})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func convertPackage(targetName string, pkg *doc.Package, fset *token.FileSet) *PackageAPI {
|
|
api := &PackageAPI{
|
|
Target: targetName,
|
|
Package: pkg.Name,
|
|
Doc: pkg.Doc,
|
|
Constants: convertValues(fset, pkg.Consts),
|
|
Variables: convertValues(fset, pkg.Vars),
|
|
Functions: convertFuncs(fset, pkg.Funcs),
|
|
}
|
|
for _, t := range pkg.Types {
|
|
api.Types = append(api.Types, APIType{
|
|
Doc: t.Doc,
|
|
Name: t.Name,
|
|
Decl: formatNode(fset, t.Decl),
|
|
Constants: convertValues(fset, t.Consts),
|
|
Variables: convertValues(fset, t.Vars),
|
|
Functions: convertFuncs(fset, t.Funcs),
|
|
Methods: convertFuncs(fset, t.Methods),
|
|
})
|
|
}
|
|
return api
|
|
}
|
|
|
|
func main() {
|
|
jsonOutput := flag.Bool("json", false, "output JSON to stdout")
|
|
httpAddr := flag.String("http", "", "serve HTTP documentation (e.g. :8080)")
|
|
allDecls := flag.Bool("all", false, "include unexported identifiers")
|
|
includeBase := flag.Bool("base", false, "include base/parent targets")
|
|
flag.Parse()
|
|
|
|
args := flag.Args()
|
|
if len(args) < 2 {
|
|
fmt.Fprintf(os.Stderr, "usage: tgdoc [flags] <targets-dir> <package-dir>\n")
|
|
fmt.Fprintf(os.Stderr, "\nexample: tgdoc -http :8080 ./targets ./src/machine\n")
|
|
fmt.Fprintf(os.Stderr, "\nFlags:\n")
|
|
flag.PrintDefaults()
|
|
os.Exit(1)
|
|
}
|
|
|
|
targetsDir := args[0]
|
|
pkgDir := args[1]
|
|
|
|
if *httpAddr != "" && !strings.Contains(*httpAddr, ":") {
|
|
fmt.Fprintf(os.Stderr, "error: -http value %q doesn't look like an address (expected e.g. :8080)\n", *httpAddr)
|
|
os.Exit(1)
|
|
}
|
|
|
|
targets, err := LoadTargets(targetsDir, *includeBase)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
var results []Result
|
|
for _, t := range targets {
|
|
pkg, fset, err := ExtractDocs(t, pkgDir, *allDecls)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "warning: %s: %v\n", t.Name, err)
|
|
continue
|
|
}
|
|
results = append(results, Result{t, pkg, fset})
|
|
}
|
|
|
|
sort.Slice(results, func(i, j int) bool { return results[i].Target.Name < results[j].Target.Name })
|
|
|
|
if *httpAddr != "" {
|
|
serve(*httpAddr, results)
|
|
return
|
|
}
|
|
|
|
// Default: JSON output.
|
|
_ = jsonOutput
|
|
apis := make([]*PackageAPI, 0, len(results))
|
|
for _, r := range results {
|
|
apis = append(apis, convertPackage(r.Target.Name, r.Pkg, r.Fset))
|
|
}
|
|
|
|
enc := json.NewEncoder(os.Stdout)
|
|
enc.SetIndent("", " ")
|
|
if err := enc.Encode(apis); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|