diff --git a/.version b/.version index e31a3431a..c46f26d3e 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -0.2.707 \ No newline at end of file +0.2.708 \ No newline at end of file diff --git a/cmd/templ/fmtcmd/main.go b/cmd/templ/fmtcmd/main.go index e460f2e02..524274021 100644 --- a/cmd/templ/fmtcmd/main.go +++ b/cmd/templ/fmtcmd/main.go @@ -11,7 +11,6 @@ import ( "time" "github.com/a-h/templ/cmd/templ/processor" - "github.com/a-h/templ/cmd/templ/sloghandler" parser "github.com/a-h/templ/parser/v2" "github.com/natefinch/atomic" ) @@ -19,37 +18,19 @@ import ( type Arguments struct { ToStdout bool Files []string - LogLevel string WorkerCount int } -func Run(w io.Writer, args Arguments) (err error) { +func Run(log *slog.Logger, stdin io.Reader, stdout io.Writer, args Arguments) (err error) { // If no files are provided, read from stdin and write to stdout. if len(args.Files) == 0 { - return format(writeToStdout, readFromStdin) - } - - level := slog.LevelInfo.Level() - switch args.LogLevel { - case "debug": - level = slog.LevelDebug.Level() - case "warn": - level = slog.LevelWarn.Level() - case "error": - level = slog.LevelError.Level() - } - log := slog.New(sloghandler.NewHandler(w, &slog.HandlerOptions{ - AddSource: args.LogLevel == "debug", - Level: level, - })) - if args.ToStdout { - log = slog.New(slog.NewTextHandler(io.Discard, &slog.HandlerOptions{})) + return format(writeToWriter(stdout), readFromReader(stdin)) } process := func(fileName string) error { read := readFromFile(fileName) write := writeToFile if args.ToStdout { - write = writeToStdout + write = writeToWriter(stdout) } return format(write, read) } @@ -101,12 +82,14 @@ func (f *Formatter) Run() (err error) { type reader func() (fileName, src string, err error) -func readFromStdin() (fileName, src string, err error) { - b, err := io.ReadAll(os.Stdin) - if err != nil { - return "", "", fmt.Errorf("failed to read stdin: %w", err) +func readFromReader(r io.Reader) func() (fileName, src string, err error) { + return func() (fileName, src string, err error) { + b, err := io.ReadAll(r) + if err != nil { + return "", "", fmt.Errorf("failed to read stdin: %w", err) + } + return "stdin.templ", string(b), nil } - return "stdin.templ", string(b), nil } func readFromFile(name string) reader { @@ -123,11 +106,13 @@ type writer func(fileName, tgt string) error var mu sync.Mutex -func writeToStdout(fileName, tgt string) error { - mu.Lock() - defer mu.Unlock() - _, err := os.Stdout.Write([]byte(tgt)) - return err +func writeToWriter(w io.Writer) func(fileName, tgt string) error { + return func(fileName, tgt string) error { + mu.Lock() + defer mu.Unlock() + _, err := w.Write([]byte(tgt)) + return err + } } func writeToFile(fileName, tgt string) error { diff --git a/cmd/templ/generatecmd/cmd.go b/cmd/templ/generatecmd/cmd.go index 2d5122361..dbbd2ccbe 100644 --- a/cmd/templ/generatecmd/cmd.go +++ b/cmd/templ/generatecmd/cmd.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "io" "log/slog" "net/http" "net/url" @@ -55,9 +54,14 @@ func (cmd Generate) Run(ctx context.Context) (err error) { if cmd.Args.Watch && cmd.Args.FileName != "" { return fmt.Errorf("cannot watch a single file, remove the -f or -watch flag") } - if cmd.Args.FileName == "" && cmd.Args.ToStdout { + writingToWriter := cmd.Args.FileWriter != nil + if cmd.Args.FileName == "" && writingToWriter { return fmt.Errorf("only a single file can be output to stdout, add the -f flag to specify the file to generate code for") } + // Default to writing to files. + if cmd.Args.FileWriter == nil { + cmd.Args.FileWriter = FileWriter + } if cmd.Args.PPROFPort > 0 { go func() { _ = http.ListenAndServe(fmt.Sprintf("localhost:%d", cmd.Args.PPROFPort), nil) @@ -81,10 +85,6 @@ func (cmd Generate) Run(ctx context.Context) (err error) { opts = append(opts, generator.WithTimestamp(time.Now())) } - if cmd.Args.ToStdout { - cmd.Log = slog.New(slog.NewTextHandler(io.Discard, &slog.HandlerOptions{})) - } - // Check the version of the templ module. if err := modcheck.Check(cmd.Args.Path); err != nil { cmd.Log.Warn("templ version check: " + err.Error()) @@ -97,7 +97,7 @@ func (cmd Generate) Run(ctx context.Context) (err error) { opts, cmd.Args.GenerateSourceMapVisualisations, cmd.Args.KeepOrphanedFiles, - cmd.Args.ToStdout, + cmd.Args.FileWriter, ) // If we're processing a single file, don't bother setting up the channels/multithreaing. @@ -182,7 +182,7 @@ func (cmd Generate) Run(ctx context.Context) (err error) { opts, cmd.Args.GenerateSourceMapVisualisations, cmd.Args.KeepOrphanedFiles, - cmd.Args.ToStdout, + cmd.Args.FileWriter, ) errorCount.Store(0) if err := watcher.WalkFiles(ctx, cmd.Args.Path, events); err != nil { diff --git a/cmd/templ/generatecmd/eventhandler.go b/cmd/templ/generatecmd/eventhandler.go index e3d2da2d4..945989acc 100644 --- a/cmd/templ/generatecmd/eventhandler.go +++ b/cmd/templ/generatecmd/eventhandler.go @@ -9,6 +9,7 @@ import ( "go/format" "go/scanner" "go/token" + "io" "log/slog" "os" "path" @@ -23,6 +24,19 @@ import ( "github.com/fsnotify/fsnotify" ) +type FileWriterFunc func(name string, contents []byte) error + +func FileWriter(fileName string, contents []byte) error { + return os.WriteFile(fileName, contents, 0o644) +} + +func WriterFileWriter(w io.Writer) FileWriterFunc { + return func(_ string, contents []byte) error { + _, err := w.Write(contents) + return err + } +} + func NewFSEventHandler( log *slog.Logger, dir string, @@ -30,7 +44,7 @@ func NewFSEventHandler( genOpts []generator.GenerateOpt, genSourceMapVis bool, keepOrphanedFiles bool, - toStdout bool, + fileWriter FileWriterFunc, ) *FSEventHandler { if !path.IsAbs(dir) { dir, _ = filepath.Abs(dir) @@ -48,10 +62,7 @@ func NewFSEventHandler( genSourceMapVis: genSourceMapVis, DevMode: devMode, keepOrphanedFiles: keepOrphanedFiles, - writer: writeToFile, - } - if toStdout { - fseh.writer = writeToStdout + writer: fileWriter, } if devMode { fseh.genOpts = append(fseh.genOpts, generator.WithExtractStrings()) @@ -77,15 +88,6 @@ type FSEventHandler struct { writer func(string, []byte) error } -func writeToFile(fileName string, contents []byte) error { - return os.WriteFile(fileName, contents, 0o644) -} - -func writeToStdout(_ string, contents []byte) error { - _, err := os.Stdout.Write(contents) - return err -} - func (h *FSEventHandler) HandleEvent(ctx context.Context, event fsnotify.Event) (goUpdated, textUpdated bool, err error) { // Handle _templ.go files. if !event.Has(fsnotify.Remove) && strings.HasSuffix(event.Name, "_templ.go") { @@ -223,8 +225,8 @@ func (h *FSEventHandler) generate(ctx context.Context, fileName string) (goUpdat formattedGoCode, err := format.Source(b.Bytes()) if err != nil { - err = remapErrorList(err, sourceMap, fileName, targetFileName) - return false, false, nil, fmt.Errorf("%s source formatting error %w", fileName, err) + err = remapErrorList(err, sourceMap, fileName) + return false, false, nil, fmt.Errorf("% source formatting error %w", fileName, err) } // Hash output, and write out the file if the goCodeHash has changed. @@ -262,7 +264,7 @@ func (h *FSEventHandler) generate(ctx context.Context, fileName string) (goUpdat // Takes an error from the formatter and attempts to convert the positions reported in the target file to their positions // in the source file. -func remapErrorList(err error, sourceMap *parser.SourceMap, fileName string, targetFileName string) error { +func remapErrorList(err error, sourceMap *parser.SourceMap, fileName string) error { list, ok := err.(scanner.ErrorList) if !ok || len(list) == 0 { return err diff --git a/cmd/templ/generatecmd/main.go b/cmd/templ/generatecmd/main.go index e4e302d54..d72121790 100644 --- a/cmd/templ/generatecmd/main.go +++ b/cmd/templ/generatecmd/main.go @@ -3,17 +3,14 @@ package generatecmd import ( "context" _ "embed" - "io" "log/slog" _ "net/http/pprof" - - "github.com/a-h/templ/cmd/templ/sloghandler" ) type Arguments struct { FileName string - ToStdout bool + FileWriter FileWriterFunc Path string Watch bool OpenBrowser bool @@ -26,25 +23,11 @@ type Arguments struct { GenerateSourceMapVisualisations bool IncludeVersion bool IncludeTimestamp bool - LogLevel string // PPROFPort is the port to run the pprof server on. PPROFPort int KeepOrphanedFiles bool } -func Run(ctx context.Context, w io.Writer, args Arguments) (err error) { - level := slog.LevelInfo.Level() - switch args.LogLevel { - case "debug": - level = slog.LevelDebug.Level() - case "warn": - level = slog.LevelWarn.Level() - case "error": - level = slog.LevelError.Level() - } - log := slog.New(sloghandler.NewHandler(w, &slog.HandlerOptions{ - AddSource: args.LogLevel == "debug", - Level: level, - })) +func Run(ctx context.Context, log *slog.Logger, args Arguments) (err error) { return NewGenerate(log, args).Run(ctx) } diff --git a/cmd/templ/generatecmd/test-eventhandler/eventhandler_test.go b/cmd/templ/generatecmd/test-eventhandler/eventhandler_test.go index c41bd8b73..2cc39a540 100644 --- a/cmd/templ/generatecmd/test-eventhandler/eventhandler_test.go +++ b/cmd/templ/generatecmd/test-eventhandler/eventhandler_test.go @@ -42,7 +42,8 @@ func TestErrorLocationMapping(t *testing.T) { } slog := slog.New(slog.NewTextHandler(io.Discard, &slog.HandlerOptions{})) - fseh := generatecmd.NewFSEventHandler(slog, ".", false, []generator.GenerateOpt{}, false, false, true) + var fw generatecmd.FileWriterFunc + fseh := generatecmd.NewFSEventHandler(slog, ".", false, []generator.GenerateOpt{}, false, false, fw) for _, test := range tests { // The raw files cannot end in .templ because they will cause the generator to fail. Instead, // we create a tmp file that ends in .templ only for the duration of the test. diff --git a/cmd/templ/generatecmd/testwatch/generate_test.go b/cmd/templ/generatecmd/testwatch/generate_test.go index 8c34a3e04..b97437767 100644 --- a/cmd/templ/generatecmd/testwatch/generate_test.go +++ b/cmd/templ/generatecmd/testwatch/generate_test.go @@ -6,6 +6,8 @@ import ( "context" "embed" "fmt" + "io" + "log/slog" "net" "net/http" "os" @@ -368,16 +370,23 @@ func Setup(gzipEncoding bool) (args TestArgs, teardown func(t *testing.T), err e command += " -gzip true" } - cmdErr = generatecmd.Run(ctx, os.Stdout, generatecmd.Arguments{ - Path: appDir, - Watch: true, - Command: command, - ProxyBind: proxyBind, - ProxyPort: proxyPort, - Proxy: args.AppURL, - IncludeVersion: false, - IncludeTimestamp: false, - KeepOrphanedFiles: false, + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + + cmdErr = generatecmd.Run(ctx, log, generatecmd.Arguments{ + Path: appDir, + Watch: true, + OpenBrowser: false, + Command: command, + ProxyBind: proxyBind, + ProxyPort: proxyPort, + Proxy: args.AppURL, + NotifyProxy: false, + WorkerCount: 0, + GenerateSourceMapVisualisations: false, + IncludeVersion: false, + IncludeTimestamp: false, + PPROFPort: 0, + KeepOrphanedFiles: false, }) }() @@ -460,8 +469,10 @@ func TestGenerateReturnsErrors(t *testing.T) { t.Errorf("failed to replace text in file: %v", err) } + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + // Run. - err = generatecmd.Run(context.Background(), os.Stdout, generatecmd.Arguments{ + err = generatecmd.Run(context.Background(), log, generatecmd.Arguments{ Path: appDir, Watch: false, IncludeVersion: false, diff --git a/cmd/templ/lspcmd/main.go b/cmd/templ/lspcmd/main.go index 402630732..de244becc 100644 --- a/cmd/templ/lspcmd/main.go +++ b/cmd/templ/lspcmd/main.go @@ -29,7 +29,7 @@ type Arguments struct { HTTPDebug string } -func Run(w io.Writer, args Arguments) (err error) { +func Run(stdin io.Reader, stdout, stderr io.Writer, args Arguments) (err error) { ctx := context.Background() ctx, cancel := context.WithCancel(ctx) signalChan := make(chan os.Signal, 1) @@ -61,14 +61,14 @@ func Run(w io.Writer, args Arguments) (err error) { } log, err = cfg.Build() if err != nil { - _, _ = fmt.Fprintf(w, "failed to create logger: %v\n", err) + _, _ = fmt.Fprintf(stderr, "failed to create logger: %v\n", err) os.Exit(1) } } defer func() { _ = log.Sync() }() - templStream := jsonrpc2.NewStream(newStdRwc(log, "templStream", w, os.Stdin)) + templStream := jsonrpc2.NewStream(newStdRwc(log, "templStream", stdout, stdin)) return run(ctx, log, templStream, args) } diff --git a/cmd/templ/main.go b/cmd/templ/main.go index 070baf410..72a675a14 100644 --- a/cmd/templ/main.go +++ b/cmd/templ/main.go @@ -5,6 +5,7 @@ import ( "flag" "fmt" "io" + "log/slog" "os" "os/signal" "runtime" @@ -13,11 +14,12 @@ import ( "github.com/a-h/templ/cmd/templ/fmtcmd" "github.com/a-h/templ/cmd/templ/generatecmd" "github.com/a-h/templ/cmd/templ/lspcmd" + "github.com/a-h/templ/cmd/templ/sloghandler" "github.com/fatih/color" ) func main() { - code := run(os.Stdout, os.Args) + code := run(os.Stdin, os.Stdout, os.Stderr, os.Args) if code != 0 { os.Exit(code) } @@ -36,27 +38,46 @@ commands: version Prints the version ` -func run(w io.Writer, args []string) (code int) { +func run(stdin io.Reader, stdout, stderr io.Writer, args []string) (code int) { if len(args) < 2 { - fmt.Fprint(w, usageText) - return 0 + fmt.Fprint(stderr, usageText) + return 64 // EX_USAGE } switch args[1] { case "generate": - return generateCmd(w, args[2:]) + return generateCmd(stdout, stderr, args[2:]) case "fmt": - return fmtCmd(w, args[2:]) + return fmtCmd(stdin, stdout, stderr, args[2:]) case "lsp": - return lspCmd(w, args[2:]) - case "version": - fmt.Fprintln(w, templ.Version()) + return lspCmd(stdin, stdout, stderr, args[2:]) + case "version", "--version": + fmt.Fprintln(stdout, templ.Version()) return 0 - case "--version": - fmt.Fprintln(w, templ.Version()) + case "help", "-help", "--help", "-h": + fmt.Fprint(stdout, usageText) return 0 } - fmt.Fprint(w, usageText) - return 0 + fmt.Fprint(stderr, usageText) + return 64 // EX_USAGE +} + +func newLogger(logLevel string, verbose bool, stderr io.Writer) *slog.Logger { + if verbose { + logLevel = "debug" + } + level := slog.LevelInfo.Level() + switch logLevel { + case "debug": + level = slog.LevelDebug.Level() + case "warn": + level = slog.LevelWarn.Level() + case "error": + level = slog.LevelError.Level() + } + return slog.New(sloghandler.NewHandler(stderr, &slog.HandlerOptions{ + AddSource: logLevel == "debug", + Level: level, + })) } const generateUsageText = `usage: templ generate [...] @@ -117,9 +138,8 @@ Examples: templ generate -watch ` -func generateCmd(w io.Writer, args []string) (code int) { +func generateCmd(stdout, stderr io.Writer, args []string) (code int) { cmd := flag.NewFlagSet("generate", flag.ExitOnError) - cmd.SetOutput(w) fileNameFlag := cmd.String("f", "", "") pathFlag := cmd.String("path", ".", "") toStdoutFlag := cmd.Bool("stdout", false, "") @@ -140,28 +160,35 @@ func generateCmd(w io.Writer, args []string) (code int) { logLevelFlag := cmd.String("log-level", "info", "") helpFlag := cmd.Bool("help", false, "") err := cmd.Parse(args) - if err != nil || *helpFlag { - fmt.Fprint(w, generateUsageText) + if err != nil { + fmt.Fprint(stderr, generateUsageText) + return 64 // EX_USAGE + } + if *helpFlag { + fmt.Fprint(stdout, generateUsageText) return } - logLevel := *logLevelFlag - if *verboseFlag { - logLevel = "debug" - } + log := newLogger(*logLevelFlag, *verboseFlag, stderr) ctx, cancel := context.WithCancel(context.Background()) signalChan := make(chan os.Signal, 1) signal.Notify(signalChan, os.Interrupt) go func() { <-signalChan - fmt.Fprintln(w, "Stopping...") + fmt.Fprintln(stderr, "Stopping...") cancel() }() - err = generatecmd.Run(ctx, w, generatecmd.Arguments{ + + var fw generatecmd.FileWriterFunc + if *toStdoutFlag { + fw = generatecmd.WriterFileWriter(stdout) + } + + err = generatecmd.Run(ctx, log, generatecmd.Arguments{ FileName: *fileNameFlag, Path: *pathFlag, - ToStdout: *toStdoutFlag, + FileWriter: fw, Watch: *watchFlag, OpenBrowser: *openBrowserFlag, Command: *cmdFlag, @@ -173,13 +200,12 @@ func generateCmd(w io.Writer, args []string) (code int) { GenerateSourceMapVisualisations: *sourceMapVisualisationsFlag, IncludeVersion: *includeVersionFlag, IncludeTimestamp: *includeTimestampFlag, - LogLevel: logLevel, PPROFPort: *pprofPortFlag, KeepOrphanedFiles: *keepOrphanedFilesFlag, }) if err != nil { - color.New(color.FgRed).Fprint(w, "(✗) ") - fmt.Fprintln(w, "Command failed: "+err.Error()) + color.New(color.FgRed).Fprint(stderr, "(✗) ") + fmt.Fprintln(stderr, "Command failed: "+err.Error()) return 1 } return 0 @@ -212,33 +238,28 @@ Args: Print help and exit. ` -func fmtCmd(w io.Writer, args []string) (code int) { +func fmtCmd(stdin io.Reader, stdout, stderr io.Writer, args []string) (code int) { cmd := flag.NewFlagSet("fmt", flag.ExitOnError) - cmd.SetOutput(w) - cmd.Usage = func() { - fmt.Fprint(w, fmtUsageText) - } helpFlag := cmd.Bool("help", false, "") workerCountFlag := cmd.Int("w", runtime.NumCPU(), "") verboseFlag := cmd.Bool("v", false, "") logLevelFlag := cmd.String("log-level", "info", "") - stdout := cmd.Bool("stdout", false, "") - + stdoutFlag := cmd.Bool("stdout", false, "") err := cmd.Parse(args) - if err != nil || *helpFlag { - cmd.Usage() + if err != nil { + fmt.Fprint(stderr, fmtUsageText) + return 64 // EX_USAGE + } + if *helpFlag { + fmt.Fprint(stdout, fmtUsageText) return } - logLevel := *logLevelFlag - if *verboseFlag { - logLevel = "debug" - } + log := newLogger(*logLevelFlag, *verboseFlag, stderr) - err = fmtcmd.Run(w, fmtcmd.Arguments{ - ToStdout: *stdout, + err = fmtcmd.Run(log, stdin, stdout, fmtcmd.Arguments{ + ToStdout: *stdoutFlag, Files: cmd.Args(), - LogLevel: logLevel, WorkerCount: *workerCountFlag, }) if err != nil { @@ -266,29 +287,33 @@ Args: Enable http debug server by setting a listen address (e.g. localhost:7474) ` -func lspCmd(w io.Writer, args []string) (code int) { +func lspCmd(stdin io.Reader, stdout, stderr io.Writer, args []string) (code int) { cmd := flag.NewFlagSet("lsp", flag.ExitOnError) - cmd.SetOutput(w) - log := cmd.String("log", "", "") + logFlag := cmd.String("log", "", "") goplsLog := cmd.String("goplsLog", "", "") goplsRPCTrace := cmd.Bool("goplsRPCTrace", false, "") helpFlag := cmd.Bool("help", false, "") pprofFlag := cmd.Bool("pprof", false, "") httpDebugFlag := cmd.String("http", "", "") err := cmd.Parse(args) - if err != nil || *helpFlag { - fmt.Fprint(w, lspUsageText) + if err != nil { + fmt.Fprint(stderr, lspUsageText) + return 64 // EX_USAGE + } + if *helpFlag { + fmt.Fprint(stdout, lspUsageText) return } - err = lspcmd.Run(w, lspcmd.Arguments{ - Log: *log, + + err = lspcmd.Run(stdin, stdout, stderr, lspcmd.Arguments{ + Log: *logFlag, GoplsLog: *goplsLog, GoplsRPCTrace: *goplsRPCTrace, PPROF: *pprofFlag, HTTPDebug: *httpDebugFlag, }) if err != nil { - fmt.Fprintln(w, err.Error()) + fmt.Fprintln(stderr, err.Error()) return 1 } return 0 diff --git a/cmd/templ/main_test.go b/cmd/templ/main_test.go index c0914ab0e..b9fb0dc12 100644 --- a/cmd/templ/main_test.go +++ b/cmd/templ/main_test.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "strings" "testing" "github.com/a-h/templ" @@ -10,75 +11,85 @@ import ( func TestMain(t *testing.T) { tests := []struct { - name string - args []string - expected string - expectedCode int + name string + args []string + expectedStdout string + expectedStderr string + expectedCode int }{ { - name: "no args prints usage", - args: []string{}, - expected: usageText, - expectedCode: 0, + name: "no args prints usage", + args: []string{}, + expectedStderr: usageText, + expectedCode: 64, // EX_USAGE }, { - name: `"templ help" prints help`, - args: []string{"templ", "help"}, - expected: usageText, - expectedCode: 0, + name: `"templ help" prints help`, + args: []string{"templ", "help"}, + expectedStdout: usageText, + expectedCode: 0, }, { - name: `"templ --help" prints help`, - args: []string{"templ", "--help"}, - expected: usageText, - expectedCode: 0, + name: `"templ --help" prints help`, + args: []string{"templ", "--help"}, + expectedStdout: usageText, + expectedCode: 0, }, { - name: `"templ version" prints version`, - args: []string{"templ", "version"}, - expected: templ.Version() + "\n", - expectedCode: 0, + name: `"templ version" prints version`, + args: []string{"templ", "version"}, + expectedStdout: templ.Version() + "\n", + expectedCode: 0, }, { - name: `"templ --version" prints version`, - args: []string{"templ", "--version"}, - expected: templ.Version() + "\n", - expectedCode: 0, + name: `"templ --version" prints version`, + args: []string{"templ", "--version"}, + expectedStdout: templ.Version() + "\n", + expectedCode: 0, }, { - name: `"templ fmt --help" prints usage`, - args: []string{"templ", "fmt", "--help"}, - expected: fmtUsageText, - expectedCode: 0, + name: `"templ fmt --help" prints usage`, + args: []string{"templ", "fmt", "--help"}, + expectedStdout: fmtUsageText, + expectedCode: 0, }, { - name: `"templ generate --help" prints usage`, - args: []string{"templ", "generate", "--help"}, - expected: generateUsageText, - expectedCode: 0, + name: `"templ generate --help" prints usage`, + args: []string{"templ", "generate", "--help"}, + expectedStdout: generateUsageText, + expectedCode: 0, }, { - name: `"templ lsp --help" prints usage`, - args: []string{"templ", "lsp", "--help"}, - expected: lspUsageText, - expectedCode: 0, + name: `"templ lsp --help" prints usage`, + args: []string{"templ", "lsp", "--help"}, + expectedStdout: lspUsageText, + expectedCode: 0, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - actual := bytes.NewBuffer(nil) - actualCode := run(actual, test.args) + stdin := strings.NewReader("") + stdout := bytes.NewBuffer(nil) + stderr := bytes.NewBuffer(nil) + actualCode := run(stdin, stdout, stderr, test.args) if actualCode != test.expectedCode { t.Errorf("expected code %v, got %v", test.expectedCode, actualCode) } - if diff := cmp.Diff(test.expected, actual.String()); diff != "" { + if diff := cmp.Diff(test.expectedStdout, stdout.String()); diff != "" { t.Error(diff) - t.Error("expected:") - t.Error(test.expected) - t.Error("actual:") - t.Error(actual.String()) + t.Error("expected stdout:") + t.Error(test.expectedStdout) + t.Error("actual stdout:") + t.Error(stdout.String()) + } + if diff := cmp.Diff(test.expectedStderr, stderr.String()); diff != "" { + t.Error(diff) + t.Error("expected stderr:") + t.Error(test.expectedStderr) + t.Error("actual stderr:") + t.Error(stderr.String()) } }) } diff --git a/cmd/templ/processor/processor.go b/cmd/templ/processor/processor.go index ab9552415..c628f29ef 100644 --- a/cmd/templ/processor/processor.go +++ b/cmd/templ/processor/processor.go @@ -42,7 +42,7 @@ func shouldSkipDir(dir string) bool { } func FindTemplates(srcPath string, output chan<- string) (err error) { - return filepath.Walk(srcPath, func(currentPath string, info fs.FileInfo, err error) error { + return filepath.WalkDir(srcPath, func(currentPath string, info fs.DirEntry, err error) error { if err != nil { return err } diff --git a/docs/docs/07-project-structure/01-project-structure.md b/docs/docs/07-project-structure/01-project-structure.md index 2ce307321..286214e44 100644 --- a/docs/docs/07-project-structure/01-project-structure.md +++ b/docs/docs/07-project-structure/01-project-structure.md @@ -226,7 +226,7 @@ import ( ) func main() { - log := slog.New(slog.NewJSONHandler(os.Stdout)) + log := slog.New(slog.NewJSONHandler(os.Stderr)) s, err := db.NewCountStore(os.Getenv("TABLE_NAME"), os.Getenv("AWS_REGION")) if err != nil { log.Error("failed to create store", slog.Any("error", err)) diff --git a/docs/docs/08-hosting-and-deployment/01-hosting-on-aws-lambda.md b/docs/docs/08-hosting-and-deployment/01-hosting-on-aws-lambda.md index 6a9f66c42..79aa42378 100644 --- a/docs/docs/08-hosting-and-deployment/01-hosting-on-aws-lambda.md +++ b/docs/docs/08-hosting-and-deployment/01-hosting-on-aws-lambda.md @@ -28,7 +28,7 @@ import ( func main() { // Create handlers. - log := slog.New(slog.NewJSONHandler(os.Stdout)) + log := slog.New(slog.NewJSONHandler(os.Stderr)) s, err := db.NewCountStore(os.Getenv("TABLE_NAME"), os.Getenv("AWS_REGION")) if err != nil { log.Error("failed to create store", slog.Any("error", err)) diff --git a/examples/content-security-policy/main.go b/examples/content-security-policy/main.go index 47a75e2cc..977a368e3 100644 --- a/examples/content-security-policy/main.go +++ b/examples/content-security-policy/main.go @@ -13,7 +13,7 @@ import ( ) func main() { - log := slog.New(slog.NewJSONHandler(os.Stdout, nil)) + log := slog.New(slog.NewJSONHandler(os.Stderr, nil)) // Create HTTP routes. mux := http.NewServeMux() diff --git a/examples/counter/lambda/main.go b/examples/counter/lambda/main.go index 7f57aba2c..861f5a37b 100644 --- a/examples/counter/lambda/main.go +++ b/examples/counter/lambda/main.go @@ -13,7 +13,7 @@ import ( func main() { // Create handlers. - log := slog.New(slog.NewJSONHandler(os.Stdout)) + log := slog.New(slog.NewJSONHandler(os.Stderr)) s, err := db.NewCountStore(os.Getenv("TABLE_NAME"), os.Getenv("AWS_REGION")) if err != nil { log.Error("failed to create store", slog.Any("error", err)) diff --git a/examples/counter/main.go b/examples/counter/main.go index 048b8e550..455df25b4 100644 --- a/examples/counter/main.go +++ b/examples/counter/main.go @@ -14,7 +14,7 @@ import ( ) func main() { - log := slog.New(slog.NewJSONHandler(os.Stdout)) + log := slog.New(slog.NewJSONHandler(os.Stderr)) s, err := db.NewCountStore(os.Getenv("TABLE_NAME"), os.Getenv("AWS_REGION")) if err != nil { log.Error("failed to create store", slog.Any("error", err))