From a04d32c38906a308c76b1dabeb1ec1a8337053d6 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Mon, 7 Sep 2026 01:04:08 +0000 Subject: [PATCH] Centralize parser diagnostic translation --- docs/internal/overview.md | 1 + docs/roadmap/remediation.md | 8 +++++++- imports.go | 16 +--------------- parse.go | 37 ++++++++++++++++--------------------- profile.go | 2 +- 5 files changed, 26 insertions(+), 38 deletions(-) diff --git a/docs/internal/overview.md b/docs/internal/overview.md index 30277a7..a4f5653 100644 --- a/docs/internal/overview.md +++ b/docs/internal/overview.md @@ -10,6 +10,7 @@ module and package documentation boundary. Its implemented public primitives are - a parser-independent ordered tree in `internal/document`; - the sole upstream YAML integration in `internal/yaml`, which translates validated input into that owned tree and exposes no parser types outside its boundary; + `parse.go` owns shared translation into detached, ordered public diagnostics; - a private strict composer in `compose.go` that joins only disjoint document-tree definitions, retains ordered claims and composite mapping origins, reports every conflicting location, and never aliases an input tree; diff --git a/docs/roadmap/remediation.md b/docs/roadmap/remediation.md index 74679a3..a80707a 100644 --- a/docs/roadmap/remediation.md +++ b/docs/roadmap/remediation.md @@ -92,7 +92,13 @@ is not required to justify removing provably unread clones. ## Stage 2 — Centralize parser issue translation -Status: pending. +Status: complete. + +Completion: `parserDiagnostics` in `parse.go` now owns detached, canonical +translation for selected, imported, and profile sources. Existing tests cover +safe selected-source errors and imported/profile source attribution, so no +duplicate regression was added. Full offline tests, vet, build, and whitespace +checks passed with Go 1.26.7 on Linux/amd64. Evidence: [parse.go](../../parse.go) translates adapter issues inline, while `importParseDiagnostics` in [imports.go](../../imports.go) repeats the translation diff --git a/imports.go b/imports.go index 89a06e9..0c65425 100644 --- a/imports.go +++ b/imports.go @@ -345,7 +345,7 @@ func (s *importTraversal) visitPath(basePath string, declaration importDeclarati Depth: maxDocumentDepth, Nodes: maxDocumentNodes, }) if len(issues) != 0 { - return importParseDiagnostics(sourceID, issues) + return parserDiagnostics(sourceID, issues) } nodeCount := countInputNodes(root) if s.usedNodes+nodeCount > s.limits.nodes { @@ -625,20 +625,6 @@ func sourceInfos(source *SourceInfo) []SourceInfo { return []SourceInfo{cloneSourceInfo(*source)} } -func importParseDiagnostics(sourceID string, issues []yamladapter.Issue) []Diagnostic { - diagnostics := make([]Diagnostic, len(issues)) - for index, issue := range issues { - diagnostics[index] = Diagnostic{ - Code: Code(issue.Code), Severity: SeverityError, Message: issue.Message, - Primary: &Location{SourceID: sourceID, Line: issue.Line, Column: issue.Column}, - } - for _, related := range issue.Related { - diagnostics[index].Related = append(diagnostics[index].Related, publicLocation(related)) - } - } - return diagnostics -} - func importDiagnostic(code Code, message string, location *Location) Diagnostic { return Diagnostic{Code: code, Severity: SeverityError, Message: message, Primary: cloneLocation(location)} } diff --git a/parse.go b/parse.go index 7b5e788..d18a68b 100644 --- a/parse.go +++ b/parse.go @@ -33,6 +33,21 @@ type parsedSource struct { bytes int64 } +// parserDiagnostics translates adapter issues into detached, ordered public records. +func parserDiagnostics(sourceID string, issues []yamladapter.Issue) []Diagnostic { + diagnostics := make([]Diagnostic, len(issues)) + for index, issue := range issues { + diagnostics[index] = Diagnostic{ + Code: Code(issue.Code), Severity: SeverityError, Message: issue.Message, + Primary: &Location{SourceID: sourceID, Line: issue.Line, Column: issue.Column}, + } + for _, related := range issue.Related { + diagnostics[index].Related = append(diagnostics[index].Related, publicLocation(related)) + } + } + return canonicalDiagnostics(diagnostics) +} + func parseSource(source Source, sourceID string, limits parseLimits) (parsedSource, []Diagnostic) { read, diagnostics := readSource(source, sourceID, limits.source) if len(diagnostics) != 0 || read.info == nil { @@ -41,27 +56,7 @@ func parseSource(source Source, sourceID string, limits parseLimits) (parsedSour root, issues := yamladapter.Parse(bytes.NewReader(read.data), sourceID, limits.document) if len(issues) != 0 { - diagnostics := make([]Diagnostic, len(issues)) - for i, issue := range issues { - diagnostics[i] = Diagnostic{ - Code: Code(issue.Code), - Severity: SeverityError, - Message: issue.Message, - Primary: &Location{ - SourceID: sourceID, - Line: issue.Line, - Column: issue.Column, - }, - } - for _, related := range issue.Related { - diagnostics[i].Related = append(diagnostics[i].Related, Location{ - SourceID: related.SourceID, - Line: related.Line, - Column: related.Column, - }) - } - } - return parsedSource{source: read.info, bytes: int64(len(read.data))}, canonicalDiagnostics(diagnostics) + return parsedSource{source: read.info, bytes: int64(len(read.data))}, parserDiagnostics(sourceID, issues) } return parsedSource{document: root, source: read.info, bytes: int64(len(read.data))}, nil } diff --git a/profile.go b/profile.go index 3c3768e..bb29c49 100644 --- a/profile.go +++ b/profile.go @@ -86,7 +86,7 @@ func loadProfileDocument(source Source, context *FilesystemContext, main parsedS profileRoot, issues := yamladapter.Parse(bytes.NewReader(data), sourceID, yamladapter.Limits{Depth: maxDocumentDepth, Nodes: maxDocumentNodes}) if len(issues) != 0 { _ = root.Close() - return nil, sources, importParseDiagnostics(sourceID, issues) + return nil, sources, parserDiagnostics(sourceID, issues) } nodeCount := countInputNodes(profileRoot) if base.inputNodes+nodeCount > limits.nodes {