Repository navigation
[2.x] Add resolveTypePath helper to visitors-core - #1190
Conversation
|
trevor-cortex
left a comment
There was a problem hiding this comment.
Summary
Adds resolveTypePath(source, path, linkables) to @codama/visitors-core: it walks a PathString (config.fees[0]) from the type at the end of source, transparently resolving struct fields / enum variants / definedTypeLinkNodes to their underlying type between segments, and returns the full NodePath of the addressed node. Links are followed through the definition's path so nested links resolve in the defining program, alias cycles are detected via a per-segment Set<DefinedTypeNode>, and failures surface as the new generic CANNOT_RESOLVE_PATH (with nodePath / path / segment context) or the existing LINKED_NODE_NOT_FOUND. parsePath + PathSegment move from @codama/visitors (where they weren't publicly exported) into visitors-core, and @codama/dynamic-parsers replaces its bespoke findDataField with the helper, wrapping CANNOT_RESOLVE_PATH as the cause of DISCRIMINATOR_FIELD_NOT_FOUND and rejecting non-struct-field results (e.g. pair[0]).
The implementation is clean and the semantics are well pinned down by tests (cross-program link following, "last node returned as addressed", per-segment error contexts, dangling links, alias cycles). The dynamic-parsers migration is behaviour-preserving for the previously supported cases and strictly more informative on failure. The types line up: RegisteredTypeNode = EnumVariantTypeNode | StandaloneTypeNode | StructFieldTypeNode in 2.x, so TypePathNode = DefinedTypeLinkNode | RegisteredTypeNode covers exactly the set resolveContainer knows how to unwrap.
Things to address
- Missing changeset.
CONTRIBUTING.mdasks for one on any user-facing change, and this PR has several: a new public export in@codama/visitors-core(resolveTypePath,parsePath,PathSegment,TypePath,TypePathNode), a new error code in@codama/errors, and thecause/tuple-item behaviour change in@codama/dynamic-parsers.visitors-coreanderrorsare in the fixed group so one entry covers both;dynamic-parsersversions independently and probably wants its own line. Happy to approve once that's in. - Import member ordering in
packages/dynamic-parsers/src/discriminators.ts,packages/dynamic-parsers/test/discriminators.test.ts(L6) andpackages/visitors-core/test/resolveTypePath.test.ts(L1):CODAMA_ERROR__CANNOT_RESOLVE_PATHis inserted afterDISCRIMINATOR_*/LINKED_NODE_NOT_FOUNDrather than alphabetically.packages/errors/src/context.tsandmessages.tshave it in the right place. Every other import block in these files is case-insensitively sorted, so I'd expectoxlintto flag this —pnpm lint:fixshould sort it out. (Inline comment on the first occurrence only.)
Non-blocking notes
createPathResolver.rewriteinpackages/visitors/src/updateHelpers.tsstill hand-rolls the same walk (link following vialinkables.getPath,followedDefinedTypescycle set, tuple/array/set indexing). It can't just callresolveTypePathbecause it needs per-segment owner/prefix bookkeeping and must be lenient rather than throw, so I don't think this PR should touch it — but it's now the second copy of the stepping logic. If a third consumer shows up, exposing a per-segment step (resolveContainer+ one segment application) fromresolveTypePath.tswould letrewritereuse it.- Array/set indices aren't bounds-checked against
fixedCountNode([5]on a 2-element array resolves to the item). That matchesrewriteand the README wording ("the item of an array or set"), so I assume it's deliberate; left a one-line docblock nit inline.
Notes for subsequent reviewers
- The
dynamic-parserschange keepscontext.stack.withPath(resolved, …)semantics identical: the oldfindDataFieldalso switched to the linked definition's path when it followed a link, so codec resolution inside the discriminator field's type still happens in the defining program. expectCodamaErrorin the new test file compareserror.contextwithtoStrictEqual, which is sufficient to also assert the error code sinceCodamaErrorstores__codeincontext.parsePathwas only ever exported fromupdateHelpers.ts, not from the@codama/visitorsbarrel, so the move is additive rather than breaking.
4b32d15 to
af31344
Compare
e47ced9 to
a596db4
Compare
af31344 to
910c07c
Compare
a596db4 to
c88cb3a
Compare
910c07c to
79fdfc8
Compare
c88cb3a to
3a6273a
Compare
3a6273a to
68219e1
Compare
1cebd8a to
6c5a99a
Compare
68219e1 to
6196991
Compare
6c5a99a to
2b6c7e2
Compare
6196991 to
dc5006a
Compare
255d061 to
96a40c4
Compare
dc5006a to
3e253c1
Compare
255d061 to
96a40c4
Compare
3e253c1 to
84c1df6
Compare
96a40c4 to
482f178
Compare
84c1df6 to
e61eb74
Compare
482f178 to
03fbdb7
Compare
e61eb74 to
db2faeb
Compare
03fbdb7 to
053d723
Compare
db2faeb to
85168fd
Compare
79f9ef3 to
f5179fa
Compare
85168fd to
b694ad7
Compare
f5179fa to
adec517
Compare
6651ab9 to
c6ff34d
Compare
adec517 to
aedbf44
Compare
aedbf44 to
145c154
Compare

This PR adds
resolveTypePathto@codama/visitors-core, which resolves a path expression such asconfig.fees[0]against a type and returns the fullNodePathof the node it points to.definedTypeLinkNodes along the way resolve to their types, following links through the path of their definitions so subsequent links resolve in the right program. The last node is returned as addressed.CANNOT_RESOLVE_PATHerror, thrown when a segment of a path expression cannot be followed, and throwsLINKED_NODE_NOT_FOUNDfor dangling links.parsePathfrom@codama/visitorsto@codama/visitors-coreand documents both helpers in the README.@codama/dynamic-parsersnow uses it to resolvefieldDiscriminatorNodepaths, attaching theCANNOT_RESOLVE_PATHerror as the cause ofDISCRIMINATOR_FIELD_NOT_FOUND.