mirror of https://github.com/golang/go.git
internal/types/errors: generate Markdown files for compiler errors
This change adds a generator which creates a Markdown file for each compiler error code which includes its associated documentation. The Markdown files will be added to the x/website repository and used to generate short error links on the Go website. Change-Id: Ibabc3388d6ecc7f19151f3931554f72561e30b22 Reviewed-on: https://go-review.googlesource.com/c/go/+/495858 Reviewed-by: Robert Griesemer <gri@google.com> Auto-Submit: Carlos Amedee <carlos@golang.org> Run-TryBot: Carlos Amedee <carlos@golang.org> Reviewed-by: Carlos Amedee <carlos@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
fa50248ce6
commit
626d478d82
|
|
@ -0,0 +1,117 @@
|
||||||
|
//go:build ignore
|
||||||
|
|
||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// generrordocs creates a Markdown file for each (compiler) error code
|
||||||
|
// and its associated documentation.
|
||||||
|
// Note: this program must be run in this directory.
|
||||||
|
// go run generrordocs.go <dir>
|
||||||
|
|
||||||
|
//go:generate go run generrordocs.go errors_markdown
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/importer"
|
||||||
|
"go/parser"
|
||||||
|
"go/token"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
. "go/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) != 2 {
|
||||||
|
log.Fatal("missing argument: generrordocs <dir>")
|
||||||
|
}
|
||||||
|
outDir := os.Args[1]
|
||||||
|
if err := os.MkdirAll(outDir, 0755); err != nil {
|
||||||
|
log.Fatal("unable to create output directory: %s", err)
|
||||||
|
}
|
||||||
|
walkCodes(func(name string, vs *ast.ValueSpec) {
|
||||||
|
// ignore unused errors
|
||||||
|
if name == "_" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Ensure that < are represented correctly when its included in code
|
||||||
|
// blocks. The goldmark Markdown parser converts them to &lt;
|
||||||
|
// when not escaped. It is the only known string with this issue.
|
||||||
|
desc := strings.ReplaceAll(vs.Doc.Text(), "<", `{{raw "<"}}`)
|
||||||
|
e := struct {
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
}{
|
||||||
|
Name: name,
|
||||||
|
Description: fmt.Sprintf("```\n%s```\n", desyc),
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
err := template.Must(template.New("eachError").Parse(markdownTemplate)).Execute(&buf, e)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("template.Must: %s", err)
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(path.Join(outDir, name+".md"), buf.Bytes(), 0660); err != nil {
|
||||||
|
log.Fatalf("os.WriteFile: %s\n", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
log.Printf("output directory: %s\n", outDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
func walkCodes(f func(string, *ast.ValueSpec)) {
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
file, err := parser.ParseFile(fset, "codes.go", nil, parser.ParseComments)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("ParseFile failed: %s", err)
|
||||||
|
}
|
||||||
|
conf := Config{Importer: importer.Default()}
|
||||||
|
info := &Info{
|
||||||
|
Types: make(map[ast.Expr]TypeAndValue),
|
||||||
|
Defs: make(map[*ast.Ident]Object),
|
||||||
|
Uses: make(map[*ast.Ident]Object),
|
||||||
|
}
|
||||||
|
_, err = conf.Check("types", fset, []*ast.File{file}, info)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Check failed: %s", err)
|
||||||
|
}
|
||||||
|
for _, decl := range file.Decls {
|
||||||
|
decl, ok := decl.(*ast.GenDecl)
|
||||||
|
if !ok || decl.Tok != token.CONST {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, spec := range decl.Specs {
|
||||||
|
spec, ok := spec.(*ast.ValueSpec)
|
||||||
|
if !ok || len(spec.Names) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
obj := info.ObjectOf(spec.Names[0])
|
||||||
|
if named, ok := obj.Type().(*Named); ok && named.Obj().Name() == "Code" {
|
||||||
|
if len(spec.Names) != 1 {
|
||||||
|
log.Fatalf("bad Code declaration for %q: got %d names, want exactly 1", spec.Names[0].Name, len(spec.Names))
|
||||||
|
}
|
||||||
|
codename := spec.Names[0].Name
|
||||||
|
f(codename, spec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const markdownTemplate = `---
|
||||||
|
title: {{.Name}}
|
||||||
|
layout: article
|
||||||
|
---
|
||||||
|
<!-- Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
Use of this source code is governed by a BSD-style
|
||||||
|
license that can be found in the LICENSE file. -->
|
||||||
|
|
||||||
|
<!-- Code generated by generrordocs.go; DO NOT EDIT. -->
|
||||||
|
|
||||||
|
{{.Description}}
|
||||||
|
`
|
||||||
Loading…
Reference in New Issue