[refactor] Extract install()'s per-file-type handling into installTargets.ts - #106
Merged
kmturley merged 1 commit intoJul 31, 2026
Conversation
kmturley
force-pushed
the
fix/install-transactional-rollback
branch
from
July 31, 2026 05:25
0ddc520 to
193a674
Compare
…gets.ts install() was a ~200-line method mixing download/hash/elevation orchestration with the logic for where each installed file's final destination is (installer marker dir, Sampler move, embedded .pkg/.dmg, format-sorted plugin files, flat app/preset/project move) - impossible to unit-test any one destination without exercising the whole pipeline. Move each destination into its own function in helpers/installTargets.ts, each taking an explicit params object and returning the directories it populated (which install() now just adds to its rollback-tracking Set from #105, rather than inlining `installedDirs.add(dirTarget)` at each of five call sites). Behavior-preserving except for one verified dead branch: the pre-refactor code selected `formatDir` from presetFormatDir/projectFormatDir when `this.type` was Presets/Projects, but that value was only ever read inside the `this.type === Plugins` branch - mutually exclusive with type being Presets/Projects for a single ManagerLocal instance - so those two branches could never actually be reached. Simplified to just pluginFormatDir directly. Added direct unit tests for each extracted destination in installTargets.test.ts (mocking only archiveExtract, not the full download/hash/elevation path) - install()'s own integration tests are unchanged and still pass, confirming the extraction didn't alter behavior.
kmturley
force-pushed
the
refactor/install-target-strategies
branch
from
July 31, 2026 05:27
e9517ec to
aaf9bbb
Compare
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.
Summary
Stacked on #105 - this PR's base branch is
fix/install-transactional-rollback, notmain, since this refactor directly builds on that PR'sinstalledDirsrollback-tracking structure (each extracted function returns the directories it populated, whichinstall()now just folds into that Set). The diff below is only this PR's own changes; merge #105 first, then this one.ManagerLocal.install()was a ~200-line method mixing download/hash/elevation orchestration with the logic for where each installed file's final destination is: an installer marker directory, a Sampler's whole-directory move, an embedded.pkg/.dmgfound inside an archive, format-sorted plugin files, or a flat app/preset/project move. None of these five destinations could be unit-tested without exercising the whole pipeline (real download, real hash check, real elevation branching).src/helpers/installTargets.ts(installInstallerFile,installArchiveFiledispatching toinstallSamplerArchive/installEmbeddedInstallers/installPluginFormats/installFlatDirectory), each taking an explicit params object and returning the directories it populated undertypeDir.ManagerLocal.install()now just calls one of two entry points and folds the result into its rollback-trackinginstalledDirsSet, instead of inlininginstalledDirs.add(dirTarget)at each of five call sites.formatDirfrompresetFormatDir/projectFormatDirwhenthis.typewasPresets/Projects, but that value was only ever read inside thethis.type === RegistryType.Pluginsbranch - mutually exclusive withtypebeingPresets/Projectsfor a singleManagerLocalinstance. Those two reassignment branches could never actually be reached;formatDirwas alwayspluginFormatDirat the point of use. SimplifiedinstallPluginFormatsto just usepluginFormatDirdirectly, and dropped the now-fully-unusedpresetFormatDir/projectFormatDirimports.tests/helpers/installTargets.test.tswith 6 new unit tests, one per destination, mocking onlyarchiveExtract(never the download/hash/elevation path) - proving each destination is now independently testable, which was the actual point of the extraction.This is item 4 of the architectural review in
review.md(Structural Warning #4).Test plan
installTargets.test.ts: installer marker dir, Sampler move, embedded.pkg/.dmg, plugin format sorting (including the "no compatible files" throw), flat directory move + exec-permission handling - 6/6 pass, raisinginstallTargets.tscoverage to ~80% from these alone.ManagerLocal.test.ts's existinginstall()/uninstall()integration tests (including the new rollback regression test from [fix] Roll back partially-installed files when install() fails partway through #105) pass unchanged, confirming the extraction preserved behavior.npm run check(format, lint, build, test): 214/214 tests, 18/18 files pass.🤖 Generated with Claude Code