refactor(compilers/openapi): extract the lowering context - #218
Conversation
5d384dc to
d20e419
Compare
|
Force-pushed after a deeper review pass. Two real gaps, both found by mutation rather than by reading, plus two comment fixes. The stack was rebased onto this and every branch re-verified. 1. func (c Ctx) WithAuth(auth map[ir.AuthID]ir.AuthScheme) Ctx { return Ctx{auth: auth} }— discarding the document, its identity and index, and the declared-name index derived at entry — passed the whole suite. All three of the test's assertions were about 2. Neither changes behaviour for any document: the stream over all 163 fixtures is still byte-identical to Also: Considered and declined: reordering |
The immutable context every lowering reads moves to compilers/openapi/internal/lowering as an exported Ctx. It has to move before the schema walk can become a package of its own: the four files that walk schemas reference it 83 times, and it was declared in a file that stays, so an extraction would have needed the new package to import its own importer. Two couplings surfaced with it, both resolved here rather than carried: Ctx held the compiler's public Options, which would have dragged a published type into an internal package for the one field lowering reads. GroupingStrategy moves down to lowering instead, and options.go names it rather than restating it, so openapi.GroupingStrategy, GroupByTags and GroupByPathPrefix keep their exact spelling and their documentation while there stays exactly one declaration of the vocabulary. Options itself, whose shape ir-design §10 fixes, stays where it is. The constructor took the loader's Document for two of its fields. It now takes the document and its identity, so lowering reaches load for the version grammar alone, and a test can build a context without a load — which is what unblocks the six internal tests that reached the unexported schemas field. Each now says what it means through a document that declares those components, and the empty-name case gets a context of its own rather than mutating a shared one. The source index the loader and the lowering must agree on is named at last, as rootSrcIndex, rather than written as a bare 0 at each site. Behaviour is unchanged: the compiler's diagnostic stream over all 163 fixtures is byte-identical to main, and the goldens are untouched.
d20e419 to
ad701ae
Compare
Summary
The immutable context every lowering reads moves out of
compilers/openapiintocompilers/openapi/internal/lowering, as an exportedCtx. This is the prerequisite for #176: the four files that walk schemas reference the context 83 times, and it was declared in a file that stays behind, so extracting them without moving it first would have required the new package to import its own importer.Two couplings surfaced the moment the type moved. Both are resolved here rather than carried forward.
Ctxheld the compiler's publicOptions. Moving it would have dragged a published type into an internal package for the sake of the one field lowering actually reads —Grouping, at a single site.GroupingStrategyand its constants move down toloweringinstead, andoptions.gonames them rather than restating them:openapi.GroupingStrategy,openapi.GroupByTagsandopenapi.GroupByPathPrefixkeep their exact public spelling and their own documentation, while there stays exactly one declaration of the vocabulary. The alternative considered was a second enum inloweringwith a projection function, mirroring howloadOptionsprojects ontoload.Options. That precedent fits abooland not an open-ended enum: two declarations of one strategy set can drift, and a strategy only the public half knew about would fall through to the default with nothing reporting it.Optionsitself, whose shape ir-design §10 fixes, stays where it is.The constructor took the loader's
Document.lowering.Newnow takes(srcIndex, *soa.OpenAPI, ir.SourceInfo, GroupingStrategy), so this package reachesinternal/loadfor the version grammar alone. That is also what lets a test build a context without performing a load — which is what resolves the six internal tests that reached the unexportedschemasfield directly. Each now says what it means through a document that declares those components (docDeclaring), and the empty-name case gets a context of its own instead of mutating a shared one.Along the way the source index the loader and the lowering must agree on is named, as
rootSrcIndex, rather than written as a bare0at each site.Test plan
gofmt,go vet,golangci-lint run(0 issues),go build ./...,./scripts/check-coverage.sh— all pass; coverage 4188/4188 statements, including 100% of the new package from its own tests.mainover all 163 fixtures intestdata/, compared field by field (severity / code / source / pointer / message, in order). Goldens cannot see a diagnostic that moved, was added or was dropped, because none of that changes the IR.main's copy of each of the ten converted files and diffing against this branch leaves exactly two intentional changes:c.Opts.Grouping→c.Grouping, and one comment that named the old constructor.TestParse_ExplicitOptionsandTestGrouping_ByPathPrefixInferred; disagreeing with the loader about the source index reddens the goldens and the conformance corpus.lowering→engineimport and watchingTestImportGraph_LayeringHoldsfail on it.Notes
GroupingStrategybecoming an alias is source-compatible, andOptionsis untouched.docDeclaringnow exists in bothhelpers_test.goand the new package's tests. Duplicating an eight-line test helper is the cost of the package boundary; there is no production API for "pretend this component is declared", which is the point.