format

package
v0.7.0-alpha.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 3, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package format provides the command to auto-format project source code.

Index

Constants

This section is empty.

Variables

View Source
var FormatCmd = &cobra.Command{
	Use: "format [paths...]",
	Example: `  contextvibes product format                  # Format entire project
  contextvibes product format --strict         # Format using strict rules
  contextvibes product format --remove-directives # Remove //nolint comments
  contextvibes product format cmd/factory/scrub # Format specific package`,
	Args: cobra.ArbitraryArgs,
	RunE: func(cmd *cobra.Command, args []string) error {
		presenter := ui.NewPresenter(cmd.OutOrStdout(), cmd.ErrOrStderr())
		ctx := cmd.Context()

		presenter.Summary("Applying code formatting and auto-fixes.")

		cwd, err := os.Getwd()
		if err != nil {
			return fmt.Errorf("failed to get working directory: %w", err)
		}

		gitCfg := git.GitClientConfig{
			Logger:   globals.AppLogger,
			Executor: globals.ExecClient.UnderlyingExecutor(),
		}
		gitClient, err := git.NewClient(ctx, cwd, gitCfg)
		if err != nil {
			presenter.Warning("Could not initialize Git client. Safety checks and smart reporting will be disabled.")
		}

		projType, err := project.Detect(cwd)
		if err != nil {
			return fmt.Errorf("failed to detect project type: %w", err)
		}
		presenter.Info("Detected project type: %s", presenter.Highlight(string(projType)))

		// --- Report Buffer Initialization ---
		var reportBuffer bytes.Buffer
		fmt.Fprintf(&reportBuffer, "# Format Report (%s)\n\n", time.Now().Format(time.RFC3339))
		fmt.Fprintf(&reportBuffer, "> **AI Instruction:** This report details the results of the `format` command. Review the 'Execution Log' for errors. If files are listed under 'Updated File Content', treat that content as the new Ground Truth, superseding previous context. If no files are listed there, no changes were made.\n\n")
		fmt.Fprintf(&reportBuffer, "## Execution Log\n\n")

		var formatErrors []error

		switch projType {
		case project.Go:

			if removeDirectives {

				modified, err := runStripDirectives(ctx, presenter, gitClient, cwd, args)
				if err != nil {
					return err
				}
				if len(modified) > 0 {
					fmt.Fprintf(&reportBuffer, "### Strip Directives\n")
					for _, f := range modified {
						fmt.Fprintf(&reportBuffer, "- Cleaned: %s\n", f)
					}
					fmt.Fprintf(&reportBuffer, "\n")
				}
			}

			presenter.Header("Go Formatting & Lint Fixes")

			if globals.ExecClient.CommandExists("go") {
				out, err := runFormatCommand(ctx, presenter, globals.ExecClient, cwd, "go", []string{"mod", "tidy"})
				logOutput(&reportBuffer, "go mod tidy", out, err)
				if err != nil {
					formatErrors = append(formatErrors, err)
				} else {
					presenter.Success("✓ go mod tidy applied.")
				}
			}

			if globals.ExecClient.CommandExists("goimports") {
				goimportsArgs := []string{"-l", "-w"}
				if len(args) > 0 {
					goimportsArgs = append(goimportsArgs, args...)
				} else {
					goimportsArgs = append(goimportsArgs, ".")
				}

				out, err := runFormatCommand(ctx, presenter, globals.ExecClient, cwd, "goimports", goimportsArgs)
				logOutput(&reportBuffer, "goimports", out, err)

				if err != nil {
					formatErrors = append(formatErrors, err)
				} else {
					if len(out) > 0 {
						lines := strings.SplitSeq(strings.TrimSpace(out), "\n")
						for line := range lines {
							presenter.Detail("Updated: %s", line)
						}
					}
					presenter.Success("✓ goimports applied.")
				}
			} else {
				presenter.Warning("goimports not found. Install 'gotools' for better import management.")
			}

			gofmtArgs := []string{"-l", "-s", "-w"}
			if len(args) > 0 {
				gofmtArgs = append(gofmtArgs, args...)
			} else {
				gofmtArgs = append(gofmtArgs, ".")
			}

			out, err := runFormatCommand(ctx, presenter, globals.ExecClient, cwd, "gofmt", gofmtArgs)
			logOutput(&reportBuffer, "gofmt", out, err)

			if err != nil {
				formatErrors = append(formatErrors, err)
			} else {
				if len(out) > 0 {
					lines := strings.SplitSeq(strings.TrimSpace(out), "\n")
					for line := range lines {
						presenter.Detail("Updated: %s", line)
					}
				}
				presenter.Success("✓ gofmt -s applied.")
			}

			lintArgs := []string{"run", "--fix"}

			if strictMode {
				presenter.Info("Using strict configuration for linter fixes.")
				configBytes, err := config.GetLanguageAsset("go", config.AssetLintStrict)
				if err != nil {
					return fmt.Errorf("failed to load strict config asset: %w", err)
				}

				tmpFile, err := os.CreateTemp(".", ".golangci-strict-*.yml")
				if err != nil {
					return fmt.Errorf("failed to create temp strict config: %w", err)
				}
				defer os.Remove(tmpFile.Name())

				if _, err := tmpFile.Write(configBytes); err != nil {
					return fmt.Errorf("failed to write strict config: %w", err)
				}
				tmpFile.Close()

				lintArgs = append(lintArgs, "-c", tmpFile.Name())
			}

			if len(args) > 0 {
				lintArgs = append(lintArgs, args...)
			}

			lintOut, lintErr := runFormatCommand(ctx, presenter, globals.ExecClient, cwd, "golangci-lint", lintArgs)
			if strictMode {
				lintOut = strings.ReplaceAll(lintOut, ".golangci-strict-*.yml", ".golangci-strict.yml")
			}
			logOutput(&reportBuffer, "golangci-lint", lintOut, lintErr)

			if lintErr != nil {
				presenter.Warning("'golangci-lint --fix' completed but may have found unfixable issues.")
			} else {
				presenter.Success("✓ golangci-lint --fix applied.")
			}

		default:
			presenter.Info("No formatters configured for %s", projType)
		}

		presenter.Newline()
		if len(formatErrors) > 0 {
			return errFormattingFailed
		}

		presenter.Success("All formatting and auto-fixing tools completed.")

		if gitClient != nil {

			statusOut, _, err := gitClient.GetStatusShort(ctx)
			if err == nil && len(statusOut) > 0 {
				dirtyFiles := parseGitStatus(statusOut)

				filesToDump := filterFiles(dirtyFiles, args)

				if len(filesToDump) > 0 {
					fmt.Fprintf(&reportBuffer, "\n## Updated File Content (Ground Truth)\n")
					for _, path := range filesToDump {

						info, err := os.Stat(path)
						if err == nil && !info.IsDir() {
							content, err := os.ReadFile(path)
							if err == nil {
								tools.AppendFileMarkerHeader(&reportBuffer, path)
								reportBuffer.Write(content)
								tools.AppendFileMarkerFooter(&reportBuffer, path)
							}
						}
					}
				}
			}
		}

		if err := tools.WriteBufferToFile("_contextvibes.md", &reportBuffer); err != nil {
			presenter.Error("Failed to write report to _contextvibes.md: %v", err)
		} else {
			presenter.Success("Full context written to %s", presenter.Highlight("_contextvibes.md"))
		}

		return nil
	},
}

FormatCmd represents the format command.

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL