refactor(compilers/openapi): rehome reference-entry resolution - #220
Conversation
478adbb to
ce19845
Compare
aebbca3 to
6e3f3a0
Compare
ce19845 to
6d672bd
Compare
6e3f3a0 to
41b0d99
Compare
6d672bd to
cb7362d
Compare
41b0d99 to
aeeb25d
Compare
|
Force-pushed after a deeper review pass.
Nothing about the constraint promises that tolerance, and The other three tests in this PR were mutation-checked too: inventing an object for an unresolved reference, dropping the use-site pointer on a cross-document chain, and raising |
cb7362d to
435ed4d
Compare
aeeb25d to
1295c79
Compare
435ed4d to
c3ba2fd
Compare
1295c79 to
2353f67
Compare
c3ba2fd to
3262829
Compare
2353f67 to
22f2234
Compare
The generic walk over speakeasy's Referenced* aliases — what a reference-or-inline entry stands for, and which declaration it resolves to — moves from operations.go into internal/resolve, as Object and ObjectAt. It is reference resolution, and internal/resolve is the package that answers what a $ref names, so this is where it belonged already. Leaving it in operations.go also blocks the operation extraction (#175): auth.go resolves security schemes through it and stays behind, so a package built around operations.go would be imported by a file it imports. The move removes a dependency rather than adding one. ObjectAt read exactly one thing from the lowering context — the reference scope — so it now takes that scope directly, and this package still reaches nothing that lowers. The hop bound stays unexported. Only a real compile can build a chain long enough to cross it, so the test that holds the walk to the bound has to say "one hop past" rather than restate the number — it reaches the constant through export_test.go, which keeps a value no production caller reads out of the package's API. Two doc comments are corrected on the way: one named cycles.go, which no longer exists — that refusal lives in internal/scan — and one described the alternative as "one resolveX per aliased type" using a name the package no longer has. Behaviour is unchanged: the compiler's diagnostic stream over all 163 fixtures is byte-identical to main. Object's nil guard is held by a fixture of its own. Every speakeasy alias tolerates a nil receiver, so the test listing all eight passes with or without the guard — it pins the behaviour and not the branch. An entry whose getters do dereference their receiver tells the two apart, which is what the guard is for, since nothing about the constraint promises that tolerance and the resolved-object fallback two lines down already declines to rely on it.
22f2234 to
8671a77
Compare
|
Rebased onto the new
Everything else probed clean:
|
Stacked on #219, which is stacked on #218. Review those first; this PR's diff against #219 is the change under review.
Summary
The generic walk over speakeasy's
Referenced*aliases — what a reference-or-inline entry stands for, and which declaration it resolves to — moves out ofoperations.goand intointernal/resolve, asresolve.Objectandresolve.ObjectAt.Two reasons, and the second is why it happens now:
internal/resolveis the package whose whole job is answering what a$refnames. It was inoperations.goonly because path items were the first thing to need it.auth.goresolves security schemes through it and does not move with the operation walk, so a package built aroundoperations.gowould end up imported by a file it imports. Pulling the helpers below both breaks that before it forms.The move removes a dependency rather than adding one.
resolveRefAttook a wholelowering.Ctxand read exactly one thing from it —c.RefScope().ObjectAttakes thatScopedirectly, sointernal/resolvestill reaches nothing that lowers, and its allowlist gains only thereferencespackage the interface is written in terms of.MaxRefChainis exported with them. Only a real compile can build a chain long enough to cross the bound — the resolution info each hop reads is built by speakeasy's resolver, not by any value a test can construct — so the test that holds the walk to that bound has to be able to say "one hop past it" without restating the number, which is the thingCLAUDE.mdasks not to maintain by hand.Two doc comments are corrected on the way, both stale before this PR: one named
cycles.go, which no longer exists (that refusal lives ininternal/scan), and one described the alternative as "oneresolveXper aliased type", using a name the package has not had for some time.Test plan
gofmt,go vet,golangci-lint run(0 issues),go build ./...,./scripts/check-coverage.sh— all pass; 4188/4188 statements, including 100% ofinternal/resolvefrom its own tests.mainover all 163 fixtures.ObjectAtbehaviour tests now live ininternal/resolve, renamed to follow the function. They drive whole documents through the compiler rather than callingObjectAtdirectly, which is not a shortcut — a chain of component aliases only exists once the resolver has built each hop's resolution info — so they live inpackage resolve_test, the only place that may import the compiler.Object's fallback from the inline object to the resolved one was reached only incidentally, by an unrelated auth fixture with a dangling$ref. It now has a direct test: an entry that is a$refto a component the document does not declare has no object, and must answer nil rather than a zero value the caller would lower as though it were written.Test/Fuzz/Benchmarknames before and after: five are renames, one (TestResolvers_NilInputs) split into the two things it was checking, and two are new. Net 623 → 625.Notes
paramKey's half of the oldTestResolvers_NilInputsstayed incompilers/openapiand got a name and a comment of its own: a nil parameter cannot key anything, and answering with the zero key would merge every such entry onto one another.