Skip to content

[refactor] Extract install()'s per-file-type handling into installTargets.ts - #106

Merged
kmturley merged 1 commit into
fix/install-transactional-rollbackfrom
refactor/install-target-strategies
Jul 31, 2026
Merged

[refactor] Extract install()'s per-file-type handling into installTargets.ts#106
kmturley merged 1 commit into
fix/install-transactional-rollbackfrom
refactor/install-target-strategies

Conversation

@kmturley

Copy link
Copy Markdown
Member

Summary

Stacked on #105 - this PR's base branch is fix/install-transactional-rollback, not main, since this refactor directly builds on that PR's installedDirs rollback-tracking structure (each extracted function returns the directories it populated, which install() 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/.dmg found 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).
  • Moves each destination into its own function in new src/helpers/installTargets.ts (installInstallerFile, installArchiveFile dispatching to installSamplerArchive/installEmbeddedInstallers/installPluginFormats/installFlatDirectory), each taking an explicit params object and returning the directories it populated under typeDir. ManagerLocal.install() now just calls one of two entry points and folds the result into its rollback-tracking installedDirs Set, instead of inlining installedDirs.add(dirTarget) at each of five call sites.
  • One verified, intentional behavior simplification (not a silent change): the pre-refactor code selected a formatDir from presetFormatDir/projectFormatDir when this.type was Presets/Projects, but that value was only ever read inside the this.type === RegistryType.Plugins branch - mutually exclusive with type being Presets/Projects for a single ManagerLocal instance. Those two reassignment branches could never actually be reached; formatDir was always pluginFormatDir at the point of use. Simplified installPluginFormats to just use pluginFormatDir directly, and dropped the now-fully-unused presetFormatDir/projectFormatDir imports.
  • Added tests/helpers/installTargets.test.ts with 6 new unit tests, one per destination, mocking only archiveExtract (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

  • New unit tests in 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, raising installTargets.ts coverage to ~80% from these alone.
  • All of ManagerLocal.test.ts's existing install()/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

@kmturley
kmturley force-pushed the fix/install-transactional-rollback branch from 0ddc520 to 193a674 Compare July 31, 2026 05:25
…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
kmturley force-pushed the refactor/install-target-strategies branch from e9517ec to aaf9bbb Compare July 31, 2026 05:27
@kmturley
kmturley merged commit 62a0113 into fix/install-transactional-rollback Jul 31, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant