Resolve annotation sets in setup so the Import menu cannot throw#1762
Merged
Conversation
ImportAnnotations called useAnnotationSets() -- and so inject() -- from inside the `sets` computed. inject() resolves against the current component instance, which outside setup() is only set during render, so the getter worked when the template evaluated it and threw Missing provided object for symbol Symbol(annotationSets): must provideAnnotator() for every other caller. The Import menu's contents are lazy, so the first read of `sets` happens off the render path, and any future watcher, effect or programmatic read of `sets` would hit the same throw. It survives today only by accident of when Vue happens to evaluate it. Hoist the lookup into setup() and close over the resulting ref. The computed keeps its behaviour: clone the provided sets, append 'default', and leave the provided array untouched. Add a regression test that mounts the component with the menu closed -- reproducing the off-render read -- and asserts `sets` resolves. It fails on the previous code with the error above. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
BryonLewis
approved these changes
Jul 16, 2026
BryonLewis
left a comment
Collaborator
There was a problem hiding this comment.
fixed the other issue referenced in the PR description and updated some documentation about node versions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
ImportAnnotationscallsuseAnnotationSets()— and thereforeinject()— from inside thesetscomputed:inject()resolves against the current component instance. Outsidesetup(), Vue 2.7 only sets that during render (core/instance/render.tscallssetCurrentInstance(vm)around_render). So the getter works when the template evaluates it, and throws for every other caller:The Import menu's contents are lazy —
v-menudoesn't render them until opened — so the first read ofsetsalready happens off the render path. Any future watcher, effect, or programmatic read hits the same throw. It survives today only by accident of when Vue happens to evaluate the computed, which is not a property this code controls.This was found while debugging a separate issue: reading
setsfrom a debugger (i.e. outside a render pass) threw the error above on unmodifiedmain.Fix
Hoist the lookup into
setup()and close over the resulting ref. Behaviour is unchanged: clone the provided sets, appenddefault, leave the provided array untouched.Test
Adds
importAnnotationsSets.spec.ts, which mounts the component with the menu closed — reproducing the off-render read — and assertssetsresolves.Verified the test is meaningful rather than vacuous: against the previous code all three cases fail with
Verification
npm test— 609 passing (main's suite plus the 3 new cases)npx eslinton both changed files — cleannpm run build:web— cleanNote for reviewers
npm testrequires Node ≥20 since #1758 bumped vitest to 4 (engines: ^20 || ^22 || >=24); it fails to start on Node 18 withERR_REQUIRE_ESM.client/README.mdstill says "Requires Node 18+" — stale, but out of scope here.There is a second, separate defect in this file that I deliberately did not touch:
const currentSet = ref(defaultSet || 'default')(line ~143) is missing.value.defaultSetis a ref, so it's always truthy andref()passes an existing ref straight through —currentSettherefore aliases the injectedannotationSetref rather than copying its value, and the|| 'default'fallback never applies. Fixing it would change behaviour (theAnnotation Setcombobox is gated oncurrentSet !== '', so it would start rendering where it currently doesn't), so it wants its own PR and a decision about intent.🤖 Generated with Claude Code