184 lines
4.5 KiB
Go
184 lines
4.5 KiB
Go
//go:build ignore
|
|
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"cmp"
|
|
"flag"
|
|
"fmt"
|
|
"go/format"
|
|
"go/token"
|
|
"log"
|
|
"maps"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"runtime"
|
|
"slices"
|
|
"strconv"
|
|
"strings"
|
|
"unicode"
|
|
|
|
"github.com/go-json-experiment/json"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/repo"
|
|
)
|
|
|
|
type diagnosticMessage struct {
|
|
Category string `json:"category"`
|
|
Code int `json:"code"`
|
|
ReportsUnnecessary bool `json:"reportsUnnecessary"`
|
|
ReportsDeprecated bool `json:"reportsDeprecated"`
|
|
// spelling error here is [sic] in Strada
|
|
ElidedInCompatibilityPyramid bool `json:"elidedInCompatabilityPyramid"`
|
|
|
|
key string
|
|
}
|
|
|
|
func main() {
|
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
|
|
|
output := flag.String("output", "", "path to the output diagnostics_generated.go file")
|
|
flag.Parse()
|
|
|
|
if *output == "" {
|
|
flag.Usage()
|
|
return
|
|
}
|
|
|
|
rawDiagnosticMessages := readRawMessages(filepath.Join(repo.TypeScriptSubmodulePath, "src", "compiler", "diagnosticMessages.json"))
|
|
|
|
_, filename, _, ok := runtime.Caller(0)
|
|
if !ok {
|
|
panic("could not get current filename")
|
|
}
|
|
filename = filepath.FromSlash(filename) // runtime.Caller always returns forward slashes; https://go.dev/issues/3335, https://go.dev/cl/603275
|
|
|
|
rawExtraMessages := readRawMessages(filepath.Join(filepath.Dir(filename), "extraDiagnosticMessages.json"))
|
|
|
|
maps.Copy(rawDiagnosticMessages, rawExtraMessages)
|
|
diagnosticMessages := slices.Collect(maps.Values(rawDiagnosticMessages))
|
|
|
|
slices.SortFunc(diagnosticMessages, func(a *diagnosticMessage, b *diagnosticMessage) int {
|
|
return cmp.Compare(a.Code, b.Code)
|
|
})
|
|
|
|
var buf bytes.Buffer
|
|
|
|
buf.WriteString("// Code generated by generate.go; DO NOT EDIT.\n")
|
|
buf.WriteString("\n")
|
|
buf.WriteString("package diagnostics\n")
|
|
|
|
for _, m := range diagnosticMessages {
|
|
varName, key := convertPropertyName(m.key, m.Code)
|
|
|
|
fmt.Fprintf(&buf, "var %s = &Message{code: %d, category: Category%s, key: %q, text: %q", varName, m.Code, m.Category, key, m.key)
|
|
|
|
if m.ReportsUnnecessary {
|
|
buf.WriteString(`, reportsUnnecessary: true`)
|
|
}
|
|
if m.ElidedInCompatibilityPyramid {
|
|
buf.WriteString(`, elidedInCompatibilityPyramid: true`)
|
|
}
|
|
if m.ReportsDeprecated {
|
|
buf.WriteString(`, reportsDeprecated: true`)
|
|
}
|
|
|
|
buf.WriteString("}\n\n")
|
|
}
|
|
|
|
formatted, err := format.Source(buf.Bytes())
|
|
if err != nil {
|
|
log.Fatalf("failed to format output: %v", err)
|
|
return
|
|
}
|
|
|
|
if err := os.WriteFile(*output, formatted, 0o666); err != nil {
|
|
log.Fatalf("failed to write output: %v", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func readRawMessages(p string) map[int]*diagnosticMessage {
|
|
file, err := os.Open(p)
|
|
if err != nil {
|
|
log.Fatalf("failed to open file: %v", err)
|
|
return nil
|
|
}
|
|
defer file.Close()
|
|
|
|
var rawMessages map[string]*diagnosticMessage
|
|
if err := json.UnmarshalRead(file, &rawMessages); err != nil {
|
|
log.Fatalf("failed to decode file: %v", err)
|
|
return nil
|
|
}
|
|
|
|
codeToMessage := make(map[int]*diagnosticMessage, len(rawMessages))
|
|
for k, m := range rawMessages {
|
|
m.key = k
|
|
codeToMessage[m.Code] = m
|
|
}
|
|
|
|
return codeToMessage
|
|
}
|
|
|
|
var (
|
|
multipleUnderscoreRegexp = regexp.MustCompile(`_+`)
|
|
leadingUnderscoreUnlessDigitRegexp = regexp.MustCompile(`^_+(\D)`)
|
|
trailingUnderscoreRegexp = regexp.MustCompile(`_$`)
|
|
)
|
|
|
|
func convertPropertyName(origName string, code int) (varName string, key string) {
|
|
var b strings.Builder
|
|
b.Grow(len(origName))
|
|
|
|
for _, r := range origName {
|
|
switch r {
|
|
case '*':
|
|
b.WriteString("_Asterisk")
|
|
case '/':
|
|
b.WriteString("_Slash")
|
|
case ':':
|
|
b.WriteString("_Colon")
|
|
default:
|
|
if !unicode.IsLetter(r) && !unicode.IsDigit(r) {
|
|
b.WriteRune('_')
|
|
} else {
|
|
b.WriteRune(r)
|
|
}
|
|
}
|
|
}
|
|
|
|
varName = b.String()
|
|
// get rid of all multi-underscores
|
|
varName = multipleUnderscoreRegexp.ReplaceAllString(varName, "_")
|
|
// remove any leading underscore, unless it is followed by a number.
|
|
varName = leadingUnderscoreUnlessDigitRegexp.ReplaceAllString(varName, "$1")
|
|
// get rid of all trailing underscores.
|
|
varName = trailingUnderscoreRegexp.ReplaceAllString(varName, "")
|
|
|
|
key = varName
|
|
if len(key) > 100 {
|
|
key = key[:100]
|
|
}
|
|
key = key + "_" + strconv.Itoa(code)
|
|
|
|
if !token.IsExported(varName) {
|
|
var b strings.Builder
|
|
b.Grow(len(varName) + 2)
|
|
if varName[0] == '_' {
|
|
b.WriteString("X")
|
|
} else {
|
|
b.WriteString("X_")
|
|
}
|
|
b.WriteString(varName)
|
|
varName = b.String()
|
|
}
|
|
|
|
if !token.IsIdentifier(varName) || !token.IsExported(varName) {
|
|
log.Fatalf("failed to convert property name to exported identifier: %q", origName)
|
|
}
|
|
|
|
return varName, key
|
|
}
|