userland: add archive tools and pinned GoAWK, esbuild, and QuickJS
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
// This API exposes the command-line interface for esbuild. It can be used to
|
||||
// run esbuild from Go without the overhead of creating a child process.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// package main
|
||||
//
|
||||
// import (
|
||||
// "os"
|
||||
//
|
||||
// "github.com/evanw/esbuild/pkg/cli"
|
||||
// )
|
||||
//
|
||||
// func main() {
|
||||
// os.Exit(cli.Run(os.Args[1:]))
|
||||
// }
|
||||
package cli
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/evanw/esbuild/pkg/api"
|
||||
)
|
||||
|
||||
// This function invokes the esbuild CLI. It takes an array of command-line
|
||||
// arguments (excluding the executable argument itself) and returns an exit
|
||||
// code. There are some minor differences between this CLI and the actual
|
||||
// "esbuild" executable such as the lack of auxiliary flags (e.g. "--help" and
|
||||
// "--version") but it is otherwise exactly the same code.
|
||||
func Run(osArgs []string) int {
|
||||
return runImpl(osArgs, []api.Plugin{})
|
||||
}
|
||||
|
||||
// This is similar to "Run()" but also takes an array of plugins to be used
|
||||
// during the build process.
|
||||
func RunWithPlugins(osArgs []string, plugins []api.Plugin) int {
|
||||
return runImpl(osArgs, plugins)
|
||||
}
|
||||
|
||||
// This parses an array of strings into an options object suitable for passing
|
||||
// to "api.Build()". Use this if you need to reuse the same argument parsing
|
||||
// logic as the esbuild CLI.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// options, err := cli.ParseBuildOptions([]string{
|
||||
// "input.js",
|
||||
// "--bundle",
|
||||
// "--minify",
|
||||
// })
|
||||
//
|
||||
// result := api.Build(options)
|
||||
func ParseBuildOptions(osArgs []string) (options api.BuildOptions, err error) {
|
||||
options = newBuildOptions()
|
||||
_, errWithNote := parseOptionsImpl(osArgs, &options, nil, kindExternal)
|
||||
if errWithNote != nil {
|
||||
err = errors.New(errWithNote.Text)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// This parses an array of strings into an options object suitable for passing
|
||||
// to "api.Transform()". Use this if you need to reuse the same argument
|
||||
// parsing logic as the esbuild CLI.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// options, err := cli.ParseTransformOptions([]string{
|
||||
// "--minify",
|
||||
// "--loader=tsx",
|
||||
// "--define:DEBUG=false",
|
||||
// })
|
||||
//
|
||||
// result := api.Transform(input, options)
|
||||
func ParseTransformOptions(osArgs []string) (options api.TransformOptions, err error) {
|
||||
options = newTransformOptions()
|
||||
_, errWithNote := parseOptionsImpl(osArgs, nil, &options, kindExternal)
|
||||
if errWithNote != nil {
|
||||
err = errors.New(errWithNote.Text)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// This parses an array of strings into an options object suitable for passing
|
||||
// to "api.Serve()". The remaining non-serve arguments are returned in another
|
||||
// array to then be passed to "api.ParseBuildOptions()". Use this if you need
|
||||
// to reuse the same argument parsing logic as the esbuild CLI.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// serveOptions, args, err := cli.ParseServeOptions([]string{
|
||||
// "--serve=8000",
|
||||
// })
|
||||
//
|
||||
// buildOptions, err := cli.ParseBuildOptions(args)
|
||||
//
|
||||
// result := api.Serve(serveOptions, buildOptions)
|
||||
func ParseServeOptions(osArgs []string) (options api.ServeOptions, remainingArgs []string, err error) {
|
||||
return parseServeOptionsImpl(osArgs)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,19 @@
|
||||
// This file was automatically generated by "js_table.ts"
|
||||
|
||||
package cli
|
||||
|
||||
import "github.com/evanw/esbuild/pkg/api"
|
||||
|
||||
var validEngines = map[string]api.EngineName{
|
||||
"chrome": api.EngineChrome,
|
||||
"deno": api.EngineDeno,
|
||||
"edge": api.EngineEdge,
|
||||
"firefox": api.EngineFirefox,
|
||||
"hermes": api.EngineHermes,
|
||||
"ie": api.EngineIE,
|
||||
"ios": api.EngineIOS,
|
||||
"node": api.EngineNode,
|
||||
"opera": api.EngineOpera,
|
||||
"rhino": api.EngineRhino,
|
||||
"safari": api.EngineSafari,
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
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"
|
||||
"github.com/evanw/esbuild/internal/resolver"
|
||||
)
|
||||
|
||||
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
|
||||
keyPath := logger.Path{Text: absPath, Namespace: "file"}
|
||||
source := logger.Source{
|
||||
KeyPath: keyPath,
|
||||
PrettyPaths: resolver.MakePrettyPaths(fs, keyPath),
|
||||
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()
|
||||
}
|
||||
Reference in New Issue
Block a user