vendor tsgo
This commit is contained in:
217
tools/tsgo/internal/bundled/generate.go
Normal file
217
tools/tsgo/internal/bundled/generate.go
Normal file
@@ -0,0 +1,217 @@
|
||||
//go:build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/microsoft/typescript-go/internal/repo"
|
||||
)
|
||||
|
||||
var (
|
||||
libInputDir = filepath.Join(repo.TypeScriptSubmodulePath(), "src", "lib")
|
||||
copyrightNotice = filepath.Join(repo.TypeScriptSubmodulePath(), "scripts", "CopyrightNotice.txt")
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
|
||||
libs := readLibs()
|
||||
generateLibs(libs)
|
||||
generateLibList(libs)
|
||||
generateEmbedded(libs)
|
||||
}
|
||||
|
||||
type lib struct {
|
||||
target string // target relative to libs dir
|
||||
sources []string // sources relative to src/lib dir
|
||||
}
|
||||
|
||||
func generateLibs(libs []lib) {
|
||||
const outputDir = "libs"
|
||||
|
||||
copyright := readCopyright()
|
||||
|
||||
if err := os.RemoveAll(outputDir); err != nil {
|
||||
log.Fatalf("failed to remove libs directory: %v", err)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(outputDir, 0o755); err != nil {
|
||||
log.Fatalf("failed to create libs directory: %v", err)
|
||||
}
|
||||
|
||||
for _, lib := range libs {
|
||||
var output bytes.Buffer
|
||||
output.Write(copyright)
|
||||
|
||||
for _, source := range lib.sources {
|
||||
sourcePath := filepath.Join(libInputDir, source)
|
||||
b, err := os.ReadFile(sourcePath)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to read %s: %v", sourcePath, err)
|
||||
}
|
||||
|
||||
output.WriteByte('\n')
|
||||
output.Write(removeCRLF(b))
|
||||
}
|
||||
|
||||
outputPath := filepath.Join(outputDir, lib.target)
|
||||
if err := os.WriteFile(outputPath, output.Bytes(), 0o644); err != nil {
|
||||
log.Fatalf("failed to write %s: %v", outputPath, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func generateLibList(libs []lib) {
|
||||
var code bytes.Buffer
|
||||
code.WriteString("// Code generated by generate.go; DO NOT EDIT.\n\n")
|
||||
code.WriteString("package bundled\n\n")
|
||||
|
||||
code.WriteString("// LibNames is the list of all bundled lib files, sorted by name.\n")
|
||||
code.WriteString("// For the list of libs sorted by load order, use [tsoptions.Libs].\n")
|
||||
code.WriteString("var LibNames = []string{\n")
|
||||
for _, lib := range libs {
|
||||
code.WriteString("\t\"" + lib.target + "\",\n")
|
||||
}
|
||||
code.WriteString("}\n")
|
||||
|
||||
writeCode("libs_generated.go", code.Bytes())
|
||||
}
|
||||
|
||||
func generateEmbedded(libs []lib) {
|
||||
libVarNames := make([]string, len(libs))
|
||||
for i, lib := range libs {
|
||||
libVarNames[i] = "libs_" + strings.ReplaceAll(lib.target, ".", "_")
|
||||
}
|
||||
|
||||
var code bytes.Buffer
|
||||
code.WriteString("//go:build !noembed\n\n")
|
||||
code.WriteString("// Code generated by generate.go; DO NOT EDIT.\n\n")
|
||||
code.WriteString("package bundled\n\n")
|
||||
code.WriteString("import (\n")
|
||||
code.WriteString("\"io/fs\"\n\n")
|
||||
code.WriteString("_ \"embed\"\n")
|
||||
code.WriteString(")\n\n")
|
||||
|
||||
code.WriteString("var (\n")
|
||||
for i, lib := range libs {
|
||||
varName := libVarNames[i]
|
||||
code.WriteString("//go:embed libs/" + lib.target + "\n")
|
||||
code.WriteString("" + varName + " string\n")
|
||||
}
|
||||
code.WriteString(")\n\n")
|
||||
|
||||
code.WriteString("var embeddedContents = map[string]string{\n")
|
||||
for i, lib := range libs {
|
||||
varName := libVarNames[i]
|
||||
code.WriteString("\t\"libs/" + lib.target + "\": " + varName + ",\n")
|
||||
}
|
||||
code.WriteString("}\n\n")
|
||||
|
||||
code.WriteString("var libsEntries = []fs.DirEntry{\n")
|
||||
for i, lib := range libs {
|
||||
varName := libVarNames[i]
|
||||
fmt.Fprintf(&code, "\t&fileInfo{name: %q, size: int64(len(%s))},\n", lib.target, varName)
|
||||
}
|
||||
code.WriteString("}\n")
|
||||
|
||||
writeCode("embed_generated.go", code.Bytes())
|
||||
}
|
||||
|
||||
var (
|
||||
// Match escaped characters, double-quoted strings, single-line comments, and multi-line comments.
|
||||
reJSONComments = regexp.MustCompile(`\\.|"(?:\\.|[^"])*"|//.*|/\*[\s\S]*?\*/`)
|
||||
// Match double-quoted strings (to skip) or trailing commas before ] or }.
|
||||
reTrailingComma = regexp.MustCompile(`"(?:\\.|[^"])*"|,\s*([}\]])`)
|
||||
)
|
||||
|
||||
// stripJSONC replaces comments and trailing commas with spaces in JSONC content,
|
||||
// producing valid JSON. The input slice is mutated in place.
|
||||
func stripJSONC(b []byte) {
|
||||
for _, loc := range reJSONComments.FindAllIndex(b, -1) {
|
||||
if b[loc[0]] == '/' {
|
||||
for i := loc[0]; i < loc[1]; i++ {
|
||||
if b[i] != '\n' {
|
||||
b[i] = ' '
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, loc := range reTrailingComma.FindAllSubmatchIndex(b, -1) {
|
||||
// loc[2]:loc[3] is the capture group; -1 means this matched a string, not a comma.
|
||||
if loc[2] < 0 {
|
||||
continue
|
||||
}
|
||||
// Blank the comma (at loc[0]), keep whitespace and closing bracket.
|
||||
b[loc[0]] = ' '
|
||||
}
|
||||
}
|
||||
|
||||
func readLibs() []lib {
|
||||
libsFile := filepath.Join(libInputDir, "libs.json")
|
||||
|
||||
b, err := os.ReadFile(libsFile)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to open libs.json: %v", err)
|
||||
}
|
||||
stripJSONC(b)
|
||||
|
||||
var meta struct {
|
||||
Libs []string `json:"libs"`
|
||||
Paths map[string]string `json:"paths"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(b, &meta); err != nil {
|
||||
log.Fatalf("failed to parse libs.json: %v", err)
|
||||
}
|
||||
|
||||
var libs []lib
|
||||
for _, libName := range meta.Libs {
|
||||
sources := []string{libName + ".d.ts"}
|
||||
var target string
|
||||
if path, ok := meta.Paths[libName]; ok {
|
||||
target = path
|
||||
} else {
|
||||
target = "lib." + libName + ".d.ts"
|
||||
}
|
||||
libs = append(libs, lib{target: target, sources: sources})
|
||||
}
|
||||
|
||||
slices.SortFunc(libs, func(a lib, b lib) int {
|
||||
return strings.Compare(a.target, b.target)
|
||||
})
|
||||
|
||||
return libs
|
||||
}
|
||||
|
||||
func readCopyright() []byte {
|
||||
b, err := os.ReadFile(copyrightNotice)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to read copyright notice: %v", err)
|
||||
}
|
||||
return removeCRLF(b)
|
||||
}
|
||||
|
||||
func removeCRLF(b []byte) []byte {
|
||||
return bytes.ReplaceAll(b, []byte("\r\n"), []byte("\n"))
|
||||
}
|
||||
|
||||
func writeCode(filename string, code []byte) {
|
||||
formatted, err := format.Source(code)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to format source: %v", err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(filename, formatted, 0o644); err != nil {
|
||||
log.Fatalf("failed to write %s: %v", filename, err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user