mirror of
https://github.com/hanzoai/esbuild.git
synced 2026-09-24 16:58:50 +00:00
153 lines
4.4 KiB
Go
153 lines
4.4 KiB
Go
package cli
|
|
|
|
// The mangle cache is a JSON file that remembers esbuild's property renaming
|
|
// decisions. It's a flat map where the keys are strings and the values are
|
|
// either strings or the boolean value "false". This is the case both in JSON
|
|
// and in Go (so the "interface{}" values are also either strings or "false").
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"github.com/evanw/esbuild/internal/fs"
|
|
"github.com/evanw/esbuild/internal/helpers"
|
|
"github.com/evanw/esbuild/internal/js_ast"
|
|
"github.com/evanw/esbuild/internal/js_lexer"
|
|
"github.com/evanw/esbuild/internal/js_parser"
|
|
"github.com/evanw/esbuild/internal/logger"
|
|
)
|
|
|
|
func parseMangleCache(osArgs []string, fs fs.FS, absPath string) (map[string]interface{}, []string) {
|
|
// Log problems with the mangle cache to stderr
|
|
log := logger.NewStderrLog(logger.OutputOptionsForArgs(osArgs))
|
|
defer log.Done()
|
|
|
|
// Try to read the existing file
|
|
prettyPath := absPath
|
|
if rel, ok := fs.Rel(fs.Cwd(), absPath); ok {
|
|
prettyPath = rel
|
|
}
|
|
prettyPath = strings.ReplaceAll(prettyPath, "\\", "/")
|
|
bytes, err, originalError := fs.ReadFile(absPath)
|
|
if err != nil {
|
|
// It's ok if it's just missing
|
|
if err == syscall.ENOENT {
|
|
return make(map[string]interface{}), []string{}
|
|
}
|
|
|
|
// Otherwise, report the error
|
|
log.AddError(nil, logger.Range{},
|
|
fmt.Sprintf("Failed to read from mangle cache file %q: %s", prettyPath, originalError.Error()))
|
|
return nil, nil
|
|
}
|
|
|
|
// Use our JSON parser so we get pretty-printed error messages
|
|
source := logger.Source{
|
|
KeyPath: logger.Path{Text: absPath, Namespace: "file"},
|
|
PrettyPath: prettyPath,
|
|
Contents: string(bytes),
|
|
}
|
|
result, ok := js_parser.ParseJSON(log, source, js_parser.JSONOptions{})
|
|
if !ok || log.HasErrors() {
|
|
// Stop if there were any errors so we don't continue and then overwrite this file
|
|
return nil, nil
|
|
}
|
|
tracker := logger.MakeLineColumnTracker(&source)
|
|
|
|
// Validate the top-level object
|
|
root, ok := result.Data.(*js_ast.EObject)
|
|
if !ok {
|
|
log.AddError(&tracker, logger.Range{Loc: result.Loc},
|
|
"Expected a top-level object in mangle cache file")
|
|
return nil, nil
|
|
}
|
|
|
|
mangleCache := make(map[string]interface{}, len(root.Properties))
|
|
order := make([]string, 0, len(root.Properties))
|
|
|
|
for _, property := range root.Properties {
|
|
key := helpers.UTF16ToString(property.Key.Data.(*js_ast.EString).Value)
|
|
order = append(order, key)
|
|
|
|
switch v := property.ValueOrNil.Data.(type) {
|
|
case *js_ast.EBoolean:
|
|
if v.Value {
|
|
log.AddError(&tracker, js_lexer.RangeOfIdentifier(source, property.ValueOrNil.Loc),
|
|
fmt.Sprintf("Expected %q in mangle cache file to map to either a string or false", key))
|
|
} else {
|
|
mangleCache[key] = false
|
|
}
|
|
|
|
case *js_ast.EString:
|
|
mangleCache[key] = helpers.UTF16ToString(v.Value)
|
|
|
|
default:
|
|
log.AddError(&tracker, logger.Range{Loc: property.ValueOrNil.Loc},
|
|
fmt.Sprintf("Expected %q in mangle cache file to map to either a string or false", key))
|
|
}
|
|
}
|
|
|
|
if log.HasErrors() {
|
|
return nil, nil
|
|
}
|
|
return mangleCache, order
|
|
}
|
|
|
|
func printMangleCache(mangleCache map[string]interface{}, originalOrder []string, asciiOnly bool) []byte {
|
|
j := helpers.Joiner{}
|
|
j.AddString("{")
|
|
|
|
// Determine the order to print the keys in
|
|
order := originalOrder
|
|
if len(mangleCache) > len(order) {
|
|
order = make([]string, 0, len(mangleCache))
|
|
if sort.StringsAreSorted(originalOrder) {
|
|
// If they came sorted, keep them sorted
|
|
for key := range mangleCache {
|
|
order = append(order, key)
|
|
}
|
|
sort.Strings(order)
|
|
} else {
|
|
// Otherwise add all new keys to the end, and only sort the new keys
|
|
originalKeys := make(map[string]bool, len(originalOrder))
|
|
for _, key := range originalOrder {
|
|
originalKeys[key] = true
|
|
}
|
|
order = append(order, originalOrder...)
|
|
for key := range mangleCache {
|
|
if !originalKeys[key] {
|
|
order = append(order, key)
|
|
}
|
|
}
|
|
sort.Strings(order[len(originalOrder):])
|
|
}
|
|
}
|
|
|
|
// Print the JSON while preserving the existing order of the keys
|
|
for i, key := range order {
|
|
// Print the key
|
|
if i > 0 {
|
|
j.AddString(",\n ")
|
|
} else {
|
|
j.AddString("\n ")
|
|
}
|
|
j.AddBytes(helpers.QuoteForJSON(key, asciiOnly))
|
|
|
|
// Print the value
|
|
if value := mangleCache[key]; value != false {
|
|
j.AddString(": ")
|
|
j.AddBytes(helpers.QuoteForJSON(value.(string), asciiOnly))
|
|
} else {
|
|
j.AddString(": false")
|
|
}
|
|
}
|
|
|
|
if len(order) > 0 {
|
|
j.AddString("\n")
|
|
}
|
|
j.AddString("}\n")
|
|
return j.Done()
|
|
}
|