From 5efc19c422c10a8744e02280d642690ab2976ff7 Mon Sep 17 00:00:00 2001 From: Evan Wallace Date: Thu, 11 Jun 2020 13:50:31 -0700 Subject: [PATCH] move go documentation to godoc --- README.md | 2 +- docs/go-api.md | 129 ----------------------------- pkg/api/api.go | 79 ++++++++++++++++++ pkg/cli/cli.go | 155 ++++++++++++++--------------------- pkg/cli/{args.go => impl.go} | 110 ++++++++++++++++++++++--- 5 files changed, 238 insertions(+), 237 deletions(-) delete mode 100644 docs/go-api.md rename pkg/cli/{args.go => impl.go} (74%) diff --git a/README.md b/README.md index d810b76e9bc..bf6f828001c 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ This is a JavaScript bundler and minifier. It packages up JavaScript and TypeScr ## Documentation * [JavaScript API documentation](docs/js-api.md) -* [Go API documentation](docs/go-api.md) +* [Go API documentation](https://godoc.org/github.com/evanw/esbuild/pkg/api) * [Architecture documentation](docs/architecture.md) * [中文文档](http://docs.breword.com/evanw-esbuild/) diff --git a/docs/go-api.md b/docs/go-api.md deleted file mode 100644 index 4abddd58aa0..00000000000 --- a/docs/go-api.md +++ /dev/null @@ -1,129 +0,0 @@ -# Go API Documentation - -There are two Go modules meant for public use: the [API module](#api-module) and the [CLI module](#cli-module). Note that the Go code under the [`internal`](../internal) directory is not meant to be depended upon (it sometimes changes in backwards-incompatible ways). - -## API Module - -Install: `go get github.com/evanw/esbuild/pkg/api` - -### `func Build(options BuildOptions) BuildResult` - -This function runs an end-to-end build operation. It takes an array of file paths as entry points, parses them and all of their dependencies, and returns the output files to write to the file system. The available options roughly correspond to esbuild's command-line flags. See [pkg/api/api.go](../pkg/api/api.go) for the complete list of options. - -Example usage: - -```go -package main - -import ( - "fmt" - "io/ioutil" - - "github.com/evanw/esbuild/pkg/api" -) - -func main() { - result := api.Build(api.BuildOptions{ - EntryPoints: []string{"input.js"}, - Outfile: "output.js", - Bundle: true, - }) - - fmt.Printf("%d errors and %d warnings\n", - len(result.Errors), len(result.Warnings)) - - for _, out := range result.OutputFiles { - ioutil.WriteFile(out.Path, out.Contents, 0644) - } -} -``` - -### `func Transform(input string, options TransformOptions) TransformResult` - -This function transforms a string of source code into JavaScript. It can be used to minify JavaScript, convert TypeScript/JSX to JavaScript, or convert newer JavaScript to older JavaScript. The available options roughly correspond to esbuild's command-line flags. See [pkg/api/api.go](../pkg/api/api.go) for the complete list of options. - -Example usage: - -```go -package main - -import ( - "fmt" - "os" - - "github.com/evanw/esbuild/pkg/api" -) - -func main() { - jsx := ` - import * as React from 'react' - import * as ReactDOM from 'react-dom' - - ReactDOM.render( -

Hello, world!

, - document.getElementById('root') - ); - ` - - result := api.Transform(jsx, api.TransformOptions{ - Loader: api.LoaderJSX, - }) - - fmt.Printf("%d errors and %d warnings\n", - len(result.Errors), len(result.Warnings)) - - os.Stdout.Write(result.JS) -} -``` - -## CLI Module - -Install: `go get github.com/evanw/esbuild/pkg/cli` - -### `func Run(osArgs []string) int` - -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. This could be useful if you need to wrap esbuild's CLI using Go code and want to compile everything into a single executable. - -Example usage: - -```go -package main - -import ( - "os" - - "github.com/evanw/esbuild/pkg/cli" -) - -func main() { - os.Exit(cli.Run(os.Args[1:])) -} -``` - -### `func ParseBuildOptions(osArgs []string) (api.BuildOptions, error)` - -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: - -```go -options, err := cli.ParseBuildOptions([]string{ - "--bundle", "--minify", "--format=esm"}) -if err != nil { - log.Fatal(err) -} -``` - -### `func ParseTransformOptions(osArgs []string) (api.TransformOptions, error)` - -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: - -```go -options, err := cli.ParseTransformOptions([]string{ - "--minify", "--loader=tsx", "--define:DEBUG=false"}) -if err != nil { - log.Fatal(err) -} -``` diff --git a/pkg/api/api.go b/pkg/api/api.go index 70888e412ac..f5490ce8393 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -1,3 +1,82 @@ +// This API exposes esbuild's two main operations: building and transforming. +// It's intended for integrating esbuild into other tools as a library. +// +// If you are just trying to run esbuild from Go without the overhead of +// creating a child process, there is also an API for the command-line +// interface itself: https://godoc.org/github.com/evanw/esbuild/pkg/cli. +// +// Build API +// +// This function runs an end-to-end build operation. It takes an array of file +// paths as entry points, parses them and all of their dependencies, and +// returns the output files to write to the file system. The available options +// roughly correspond to esbuild's command-line flags. +// +// Example usage: +// +// package main +// +// import ( +// "fmt" +// "io/ioutil" +// +// "github.com/evanw/esbuild/pkg/api" +// ) +// +// func main() { +// result := api.Build(api.BuildOptions{ +// EntryPoints: []string{"input.js"}, +// Outfile: "output.js", +// Bundle: true, +// }) +// +// fmt.Printf("%d errors and %d warnings\n", +// len(result.Errors), len(result.Warnings)) +// +// for _, out := range result.OutputFiles { +// ioutil.WriteFile(out.Path, out.Contents, 0644) +// } +// } +// +// Transform API +// +// This function transforms a string of source code into JavaScript. It can be +// used to minify JavaScript, convert TypeScript/JSX to JavaScript, or convert +// newer JavaScript to older JavaScript. The available options roughly +// correspond to esbuild's command-line flags. +// +// Example usage: +// +// package main +// +// import ( +// "fmt" +// "os" +// +// "github.com/evanw/esbuild/pkg/api" +// ) +// +// func main() { +// jsx := ` +// import * as React from 'react' +// import * as ReactDOM from 'react-dom' +// +// ReactDOM.render( +//

Hello, world!

, +// document.getElementById('root') +// ); +// ` +// +// result := api.Transform(jsx, api.TransformOptions{ +// Loader: api.LoaderJSX, +// }) +// +// fmt.Printf("%d errors and %d warnings\n", +// len(result.Errors), len(result.Warnings)) +// +// os.Stdout.Write(result.JS) +// } +// package api type SourceMap uint8 diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index ac561782459..4be92e90433 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -1,106 +1,71 @@ +// 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 ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strings" - - "github.com/evanw/esbuild/internal/logging" "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 { - buildOptions, transformOptions, err := parseOptionsForRun(osArgs) - - switch { - case buildOptions != nil: - // Run the build and stop if there were errors - result := api.Build(*buildOptions) - if len(result.Errors) > 0 { - return 1 - } - - // Special-case writing to stdout - if buildOptions.Outfile == "" && buildOptions.Outdir == "" { - if len(result.OutputFiles) != 1 { - logging.PrintErrorToStderr(osArgs, fmt.Sprintf( - "Internal error: did not expect to generate %d files when writing to stdout", len(result.OutputFiles))) - } else if _, err := os.Stdout.Write(result.OutputFiles[0].Contents); err != nil { - logging.PrintErrorToStderr(osArgs, fmt.Sprintf( - "Failed to write to stdout: %s", err.Error())) - } - } else { - for _, outputFile := range result.OutputFiles { - if err := os.MkdirAll(filepath.Dir(outputFile.Path), 0755); err != nil { - result.Errors = append(result.Errors, api.Message{Text: fmt.Sprintf( - "Failed to create output directory: %s", err.Error())}) - } else if err := ioutil.WriteFile(outputFile.Path, outputFile.Contents, 0644); err != nil { - logging.PrintErrorToStderr(osArgs, fmt.Sprintf( - "Failed to write to output file: %s", err.Error())) - } - } - } - - case transformOptions != nil: - // Read the input from stdin - bytes, err := ioutil.ReadAll(os.Stdin) - if err != nil { - logging.PrintErrorToStderr(osArgs, fmt.Sprintf( - "Could not read from stdin: %s", err.Error())) - return 1 - } - - // Run the transform and stop if there were errors - result := api.Transform(string(bytes), *transformOptions) - if len(result.Errors) > 0 { - return 1 - } - - // Write the output to stdout - os.Stdout.Write(result.JS) - - case err != nil: - logging.PrintErrorToStderr(osArgs, err.Error()) - return 1 - } - - return 0 + return runImpl(osArgs) } -// This returns either BuildOptions, TransformOptions, or an error -func parseOptionsForRun(osArgs []string) (*api.BuildOptions, *api.TransformOptions, error) { - // If there's an entry point, then we're building - for _, arg := range osArgs { - if !strings.HasPrefix(arg, "-") { - options := newBuildOptions() - - // Apply defaults appropriate for the CLI - options.ErrorLimit = 10 - options.LogLevel = api.LogLevelInfo - - err := parseOptionsImpl(osArgs, &options, nil) - if err != nil { - return nil, nil, err - } - return &options, nil, nil - } - } - - // Otherwise, we're transforming - options := newTransformOptions() - - // Apply defaults appropriate for the CLI - options.ErrorLimit = 10 - options.LogLevel = api.LogLevelInfo +// 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() + err = parseOptionsImpl(osArgs, &options, nil) + return +} - err := parseOptionsImpl(osArgs, nil, &options) - if err != nil { - return nil, nil, err - } - if options.Sourcemap != api.SourceMapNone && options.Sourcemap != api.SourceMapInline { - return nil, nil, fmt.Errorf("Must use \"inline\" source map when transforming stdin") - } - return nil, &options, nil +// 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() + err = parseOptionsImpl(osArgs, nil, &options) + return } diff --git a/pkg/cli/args.go b/pkg/cli/impl.go similarity index 74% rename from pkg/cli/args.go rename to pkg/cli/impl.go index b9e4d3e09ae..2ddd2e34faa 100644 --- a/pkg/cli/args.go +++ b/pkg/cli/impl.go @@ -2,9 +2,13 @@ package cli import ( "fmt" + "io/ioutil" + "os" + "path/filepath" "strconv" "strings" + "github.com/evanw/esbuild/internal/logging" "github.com/evanw/esbuild/pkg/api" ) @@ -21,18 +25,6 @@ func newTransformOptions() api.TransformOptions { } } -func ParseBuildOptions(osArgs []string) (options api.BuildOptions, err error) { - options = newBuildOptions() - err = parseOptionsImpl(osArgs, &options, nil) - return -} - -func ParseTransformOptions(osArgs []string) (options api.TransformOptions, err error) { - options = newTransformOptions() - err = parseOptionsImpl(osArgs, nil, &options) - return -} - func parseOptionsImpl(osArgs []string, buildOpts *api.BuildOptions, transformOpts *api.TransformOptions) error { hasBareSourceMapFlag := false @@ -322,3 +314,97 @@ func parseLoader(text string) (api.Loader, error) { "js, jsx, ts, tsx, json, text, base64, dataurl, file)", text) } } + +// This returns either BuildOptions, TransformOptions, or an error +func parseOptionsForRun(osArgs []string) (*api.BuildOptions, *api.TransformOptions, error) { + // If there's an entry point, then we're building + for _, arg := range osArgs { + if !strings.HasPrefix(arg, "-") { + options := newBuildOptions() + + // Apply defaults appropriate for the CLI + options.ErrorLimit = 10 + options.LogLevel = api.LogLevelInfo + + err := parseOptionsImpl(osArgs, &options, nil) + if err != nil { + return nil, nil, err + } + return &options, nil, nil + } + } + + // Otherwise, we're transforming + options := newTransformOptions() + + // Apply defaults appropriate for the CLI + options.ErrorLimit = 10 + options.LogLevel = api.LogLevelInfo + + err := parseOptionsImpl(osArgs, nil, &options) + if err != nil { + return nil, nil, err + } + if options.Sourcemap != api.SourceMapNone && options.Sourcemap != api.SourceMapInline { + return nil, nil, fmt.Errorf("Must use \"inline\" source map when transforming stdin") + } + return nil, &options, nil +} + +func runImpl(osArgs []string) int { + buildOptions, transformOptions, err := parseOptionsForRun(osArgs) + + switch { + case buildOptions != nil: + // Run the build and stop if there were errors + result := api.Build(*buildOptions) + if len(result.Errors) > 0 { + return 1 + } + + // Special-case writing to stdout + if buildOptions.Outfile == "" && buildOptions.Outdir == "" { + if len(result.OutputFiles) != 1 { + logging.PrintErrorToStderr(osArgs, fmt.Sprintf( + "Internal error: did not expect to generate %d files when writing to stdout", len(result.OutputFiles))) + } else if _, err := os.Stdout.Write(result.OutputFiles[0].Contents); err != nil { + logging.PrintErrorToStderr(osArgs, fmt.Sprintf( + "Failed to write to stdout: %s", err.Error())) + } + } else { + for _, outputFile := range result.OutputFiles { + if err := os.MkdirAll(filepath.Dir(outputFile.Path), 0755); err != nil { + result.Errors = append(result.Errors, api.Message{Text: fmt.Sprintf( + "Failed to create output directory: %s", err.Error())}) + } else if err := ioutil.WriteFile(outputFile.Path, outputFile.Contents, 0644); err != nil { + logging.PrintErrorToStderr(osArgs, fmt.Sprintf( + "Failed to write to output file: %s", err.Error())) + } + } + } + + case transformOptions != nil: + // Read the input from stdin + bytes, err := ioutil.ReadAll(os.Stdin) + if err != nil { + logging.PrintErrorToStderr(osArgs, fmt.Sprintf( + "Could not read from stdin: %s", err.Error())) + return 1 + } + + // Run the transform and stop if there were errors + result := api.Transform(string(bytes), *transformOptions) + if len(result.Errors) > 0 { + return 1 + } + + // Write the output to stdout + os.Stdout.Write(result.JS) + + case err != nil: + logging.PrintErrorToStderr(osArgs, err.Error()) + return 1 + } + + return 0 +}