fix(linter): keep node-level lint fixes when the fixed document is written

RA
3d ago
+191-11

Summary

openapi spec lint --fix loses fixes that implement validation.NodeFix, because marshaller.Marshal syncs the unchanged model back over the edited YAML nodes. For style-path-trailing-slash, the written document contains both the fixed path and the original path.

This change updates fix.Engine.ProcessErrors as follows:

  • Model fixes run first, in the same location order as before.
  • Node fixes are deferred. The engine syncs the model to the node tree with marshaller.Sync, which keeps the model edits, and then applies the node fixes to that tree.
  • The engine rebuilds the document model from the edited nodes and keeps the original document config. The edits then survive Marshal, and the input format (YAML or JSON) and indentation are preserved.
  • A node fix that fails moves from Applied to Failed. Exiting interactive mode still applies the fixes that the user already accepted.

Testing

  • TestEngine_NodeFix_SurvivesMarshal unmarshals a real document, applies one model fix and two node fixes (a value edit and a path key rename), marshals the document, and checks the exact output. It fails on main: the URL edit is reverted and /pets/ is written next to /pets.
  • TestEngine_NodeFix_FailureIsReported covers a failing deferred node fix.
  • go test ./linter/... ./openapi/linter/... ./validation/... and go test ./... in cmd/openapi pass, and golangci-lint run ./linter/... reports 0 issues.
  • Manual check: openapi spec lint --fix on the document from the issue now writes url: https://api.example.com, a single /pets path, and enum: [a, b], for both YAML and JSON input.

Fixes #280