Skip to content

Factor the internal packages - #168

Merged
crhntr merged 92 commits into
mainfrom
refactor/internal-factoring
Sep 29, 2026
Merged

crhntr merged 92 commits into
mainfrom
refactor/internal-factoring

Conversation

@crhntr

@crhntr crhntr commented Sep 29, 2026

Copy link
Copy Markdown
Member

Refactors internal/ for the next round of features. The CLI, the generated output and every integration test are unchanged: nothing under cmd/ changes and no snapshot archive changes.

Dependencies

  • load no longer imports generate or analysis. One load.PackageWithReceiver replaces GenerateSource and RoutesSource.
  • analysis no longer imports pflag or generate. NewModule takes a callback over analysis's own PackageConfig and is split into listing the module, scanning for headers, and building each package's info.
  • A new standard-library-only package, internal/header, owns the generated-file header comment: Format, Parse and Scan. cli writes it, analysis reads it, and generate.FileArguments (which ignored one of its two parameters) is gone.
  • generate has no go/types import outside tests. source.StringType covers its one use.
  • mutation no longer reaches generate and analysis through load.

Structure

The largest files are split by concept, moving whole declarations and changing nothing inside them: generate/routes.go, muxt/definition.go, muxt/call.go and cli/commands.go. A fingerprint of every top-level declaration was identical before and after.

Code that repeated itself is shared: the two route-function builders in generate, the template-data method boilerplate, the variable-declaration builders, the strconv builder families in astgen, the two result-shape classifiers in muxt, and the list-command helpers in cli. Dead code is removed: asterr, unused asteval and astgen helpers, and the redundant parts of several checks.

Complexity

Before After
Functions with cyclomatic complexity 12 or more 42 2, both in the test-only loadtest helper
Duplicated statement sequences of 60 or more nodes about 20 2

The largest were appendParseArgumentStatements (35), analysis.NewModule (28), resolveCall (25), walkTemplateCommands (24) and newArgumentFromIdentifier (23); all are now under 10.

Tests

Aggregated statement coverage across internal/ goes from 82.9% to 92.8%: cli 68% to 93%, muxt 85% to 94%, fakeserver 0% to 92%, and the astgen builders are covered directly. Gremlins now leaves no surviving mutant in changed code in muxt, generate, analysis, astgen, header or fakeserver. Where a mutant was equivalent, the code was simplified instead. The cli survivors are the version checks that depend on real build info.

Behavior changes

Small, each in its own commit:

  • A previously generated file whose header arguments fail to parse is now left alone instead of being deleted as an orphan, as the warning it logs already said. The warning now goes to the command's stderr. A stale file generated with a flag that no longer exists is therefore not cleaned up automatically.
  • header.Scan accepts headers with \r\n line endings. generate.FileArguments rejected them and analysis accepted them.
  • appendParseArgumentStatements returns an error for an argument expression that is neither an identifier nor a call. Resolution already rejects those, so it cannot be reached today.

FuzzCalculateIdentifiers fails on the base commit too, for two templates on / whose handlers are create and Create (both get the identifier Create). This PR does not change it.

Reviewing

The 92 commits are ordered: deletions, dependency changes, move-only splits, per-package refactors with their tests, then complexity and mutation follow-ups. Reading them in order is easier than the combined diff.

🤖 Generated with Claude Code

Nothing outside the deleted files referenced them.

Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
Only asteval imported it, and that use is gone.

Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
Removes HTTPHeader, IterateGenDecl, IterateValueSpecs, IterateFieldTypes,
FieldIndex and TimeParseCall, and the test that only covered
IterateFieldTypes.

Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
The two differed only in the directory. Callers compute it, so load no
longer imports generate or analysis.

Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
cli writes it with header.Format; generate's FileArguments becomes
header.Scan and analysis reads the two lines with header.Parse.

Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
NewModule now asks a callback over analysis' own types to parse header
arguments, so analysis no longer imports pflag or generate. The flag
parsing and defaulting move to cli.

Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
Only internal/muxt calls them. Definition.IsSignalsCallback stays exported:
the unexported name is taken by a helper that wraps it.

Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports
Move-only: declarations keep their text and move to handler_statements.go,
parse_arguments.go, parse_scalar.go and parse_form.go.

Assisted-by: Claude:claude-sonnet-5-5 gofumpt goimports
Move-only: declarations keep their text and move to
definition_duplicates.go, handler_expression.go, response_state.go and
redirect.go.

Assisted-by: Claude:claude-sonnet-5-5 gofumpt goimports
Move-only: declarations keep their text and move to argument.go,
argument_bind.go, body_wrappers.go and result_shape.go. call.go keeps call
resolution.

Assisted-by: Claude:claude-sonnet-5-5 gofumpt goimports
Move-only: declarations keep their text and move to generate_command.go,
analysis_commands.go, mutation_command.go, module_commands.go, flags.go,
flag_names.go and output.go. commands.go keeps Commands, runners and the
root and version commands.

Assisted-by: Claude:claude-sonnet-5-5 gofumpt goimports
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
…erdictOf

Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
… struct

Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
…tate checks

Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
Assisted-by: Claude:claude-sonnet-5-5 gopls gofumpt goimports staticcheck gremlins
@crhntr
crhntr merged commit 4d52bb8 into main Sep 29, 2026
2 checks passed
@crhntr
crhntr deleted the refactor/internal-factoring branch September 29, 2026 22:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant