...
1
2
3
4
5
6
7
8
9
10
11
12
13
14 package main
15
16 import (
17 "bytes"
18 "fmt"
19 "go/ast"
20 "go/importer"
21 "go/parser"
22 "go/token"
23 "log"
24 "os"
25 "path"
26 "strings"
27 "text/template"
28
29 . "go/types"
30 )
31
32 func main() {
33 if len(os.Args) != 2 {
34 log.Fatal("missing argument: generrordocs <dir>")
35 }
36 outDir := os.Args[1]
37 if err := os.MkdirAll(outDir, 0755); err != nil {
38 log.Fatal("unable to create output directory: %s", err)
39 }
40 walkCodes(func(name string, vs *ast.ValueSpec) {
41
42 if name == "_" {
43 return
44 }
45
46
47
48 desc := strings.ReplaceAll(vs.Doc.Text(), "<", `{{raw "<"}}`)
49 e := struct {
50 Name string
51 Description string
52 }{
53 Name: name,
54 Description: fmt.Sprintf("```\n%s```\n", desyc),
55 }
56 var buf bytes.Buffer
57 err := template.Must(template.New("eachError").Parse(markdownTemplate)).Execute(&buf, e)
58 if err != nil {
59 log.Fatalf("template.Must: %s", err)
60 }
61 if err := os.WriteFile(path.Join(outDir, name+".md"), buf.Bytes(), 0660); err != nil {
62 log.Fatalf("os.WriteFile: %s\n", err)
63 }
64 })
65 log.Printf("output directory: %s\n", outDir)
66 }
67
68 func walkCodes(f func(string, *ast.ValueSpec)) {
69 fset := token.NewFileSet()
70 file, err := parser.ParseFile(fset, "codes.go", nil, parser.ParseComments)
71 if err != nil {
72 log.Fatalf("ParseFile failed: %s", err)
73 }
74 conf := Config{Importer: importer.Default()}
75 info := &Info{
76 Types: make(map[ast.Expr]TypeAndValue),
77 Defs: make(map[*ast.Ident]Object),
78 Uses: make(map[*ast.Ident]Object),
79 }
80 _, err = conf.Check("types", fset, []*ast.File{file}, info)
81 if err != nil {
82 log.Fatalf("Check failed: %s", err)
83 }
84 for _, decl := range file.Decls {
85 decl, ok := decl.(*ast.GenDecl)
86 if !ok || decl.Tok != token.CONST {
87 continue
88 }
89 for _, spec := range decl.Specs {
90 spec, ok := spec.(*ast.ValueSpec)
91 if !ok || len(spec.Names) == 0 {
92 continue
93 }
94 obj := info.ObjectOf(spec.Names[0])
95 if named, ok := obj.Type().(*Named); ok && named.Obj().Name() == "Code" {
96 if len(spec.Names) != 1 {
97 log.Fatalf("bad Code declaration for %q: got %d names, want exactly 1", spec.Names[0].Name, len(spec.Names))
98 }
99 codename := spec.Names[0].Name
100 f(codename, spec)
101 }
102 }
103 }
104 }
105
106 const markdownTemplate = `---
107 title: {{.Name}}
108 layout: article
109 ---
110 <!-- Copyright 2023 The Go Authors. All rights reserved.
111 Use of this source code is governed by a BSD-style
112 license that can be found in the LICENSE file. -->
113
114 <!-- Code generated by generrordocs.go; DO NOT EDIT. -->
115
116 {{.Description}}
117 `
118
View as plain text