Repository navigation
fix(linter): keep node-level lint fixes when the fixed document is written - #281
RaphaelFakhri wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
2 issues found across 2 files
Confidence score: 3/5
- In
linter/fix/engine.go, a failed deferred node fix can reserve the conflict key and block later same-rule fixes at that location. Reserve the key only after the fix applies successfully. - In
linter/fix/engine.go, rebuilding the model can drop document-level comments from node-fixed YAML files when they’re written. Preserve and reattach the original document node, or rebuild from a document wrapper.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="linter/fix/engine.go">
<violation number="1" location="linter/fix/engine.go:252">
P2: A deferred node fix reserves its conflict key before it runs, so a failed node fix permanently blocks later same-rule fixes at that location. Reserve the key only after successful application, while preserving conflict handling among pending fixes.</violation>
<violation number="2" location="linter/fix/engine.go:328">
P2: Rebuilding the model discards the original `DocumentNode`, so node-fixed YAML files lose document-level comments when written. Preserve and reattach the original document node, or rebuild from a document wrapper instead of passing only the mapping root.</violation>
</file>
Shadow auto-approve: would not auto-approve because issues were found.
View guided diff | Re-trigger cubic
| } | ||
|
|
||
| config := doc.GetCore().GetConfig() | ||
| *doc = openapi.OpenAPI{} |
There was a problem hiding this comment.
P2: Rebuilding the model discards the original DocumentNode, so node-fixed YAML files lose document-level comments when written. Preserve and reattach the original document node, or rebuild from a document wrapper instead of passing only the mapping root.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At linter/fix/engine.go, line 328:
<comment>Rebuilding the model discards the original `DocumentNode`, so node-fixed YAML files lose document-level comments when written. Preserve and reattach the original document node, or rebuild from a document wrapper instead of passing only the mapping root.</comment>
<file context>
@@ -269,9 +274,67 @@ func (e *Engine) ProcessErrors(ctx context.Context, doc *openapi.OpenAPI, errs [
+ }
+
+ config := doc.GetCore().GetConfig()
+ *doc = openapi.OpenAPI{}
+ doc.InitCache()
+ doc.GetCore().SetConfig(config)
</file context>
| // marshalling syncs the model back over the YAML nodes. | ||
| if nodeFix, ok := fix.(validation.NodeFix); ok && doc.GetRootNode() != nil { | ||
| if key.Line >= 0 { | ||
| modified[key] = true |
There was a problem hiding this comment.
P2: A deferred node fix reserves its conflict key before it runs, so a failed node fix permanently blocks later same-rule fixes at that location. Reserve the key only after successful application, while preserving conflict handling among pending fixes.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At linter/fix/engine.go, line 252:
<comment>A deferred node fix reserves its conflict key before it runs, so a failed node fix permanently blocks later same-rule fixes at that location. Reserve the key only after successful application, while preserving conflict handling among pending fixes.</comment>
<file context>
@@ -241,19 +245,20 @@ func (e *Engine) ProcessErrors(ctx context.Context, doc *openapi.OpenAPI, errs [
+ // marshalling syncs the model back over the YAML nodes.
+ if nodeFix, ok := fix.(validation.NodeFix); ok && doc.GetRootNode() != nil {
+ if key.Line >= 0 {
+ modified[key] = true
}
- } else {
</file context>
Summary
openapi spec lint --fixloses fixes that implementvalidation.NodeFix, becausemarshaller.Marshalsyncs the unchanged model back over the edited YAML nodes. Forstyle-path-trailing-slash, the written document contains both the fixed path and the original path.This change updates
fix.Engine.ProcessErrorsas follows:marshaller.Sync, which keeps the model edits, and then applies the node fixes to that tree.Marshal, and the input format (YAML or JSON) and indentation are preserved.AppliedtoFailed. Exiting interactive mode still applies the fixes that the user already accepted.Testing
TestEngine_NodeFix_SurvivesMarshalunmarshals 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 onmain: the URL edit is reverted and/pets/is written next to/pets.TestEngine_NodeFix_FailureIsReportedcovers a failing deferred node fix.go test ./linter/... ./openapi/linter/... ./validation/...andgo test ./...incmd/openapipass, andgolangci-lint run ./linter/...reports 0 issues.openapi spec lint --fixon the document from the issue now writesurl: https://api.example.com, a single/petspath, andenum: [a, b], for both YAML and JSON input.Fixes #280