Coverage for lintro / tools / core / install_strategies / npm_strategy.py: 94%
34 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
1"""npm/bun install strategy."""
3from __future__ import annotations
5from lintro.enums.install_context import InstallContext, PackageManager
6from lintro.tools.core.install_strategies.base import InstallStrategy
7from lintro.tools.core.install_strategies.brew_names import BREW_FORMULA_NAMES
8from lintro.tools.core.install_strategies.environment import InstallEnvironment
9from lintro.tools.core.install_strategies.registry import register_strategy
12class NpmStrategy(InstallStrategy):
13 """Install strategy for npm/bun-managed JavaScript packages."""
15 def install_type(self) -> str:
16 """Return ``'npm'``."""
17 return "npm"
19 def is_available(self, env: InstallEnvironment) -> bool:
20 """Available if bun, npm, or brew exists."""
21 return (
22 env.has(PackageManager.BUN)
23 or env.has(PackageManager.NPM)
24 or env.has(PackageManager.BREW)
25 )
27 def check_prerequisites(
28 self,
29 env: InstallEnvironment,
30 tool_name: str,
31 ) -> str | None:
32 """Return skip reason if no JS package manager is available.
34 Args:
35 env: The current install environment.
36 tool_name: Canonical tool name.
38 Returns:
39 Skip reason or None.
40 """
41 if env.has(PackageManager.BUN) or env.has(PackageManager.NPM):
42 return None
43 if env.has(PackageManager.BREW) and tool_name in BREW_FORMULA_NAMES:
44 return None
45 return "bun/npm not available (install Node.js first)"
47 def install_hint(
48 self,
49 env: InstallEnvironment,
50 tool_name: str,
51 tool_version: str,
52 install_package: str | None,
53 _install_component: str | None,
54 ) -> str:
55 """Generate npm install hint.
57 Args:
58 env: The current install environment.
59 tool_name: Canonical tool name.
60 tool_version: Expected version.
61 install_package: Package name override.
62 _install_component: Unused for npm.
64 Returns:
65 Shell command string.
66 """
67 pkg = install_package or tool_name
68 brew_pkg = BREW_FORMULA_NAMES.get(tool_name)
69 if (
70 brew_pkg
71 and env.has(PackageManager.BREW)
72 and (
73 _is_homebrew_context(env)
74 or not (env.has(PackageManager.BUN) or env.has(PackageManager.NPM))
75 )
76 ):
77 return f"brew install {brew_pkg}"
78 return f"{_npm_cmd(env)} {pkg}@{tool_version}"
80 def upgrade_hint(
81 self,
82 env: InstallEnvironment,
83 tool_name: str,
84 tool_version: str,
85 install_package: str | None,
86 _install_component: str | None,
87 ) -> str:
88 """Generate npm upgrade hint (npm replaces on install).
90 Args:
91 env: The current install environment.
92 tool_name: Canonical tool name.
93 tool_version: Expected version.
94 install_package: Package name override.
95 _install_component: Unused for npm.
97 Returns:
98 Shell command string.
99 """
100 pkg = install_package or tool_name
101 brew_pkg = BREW_FORMULA_NAMES.get(tool_name)
102 if (
103 brew_pkg
104 and env.has(PackageManager.BREW)
105 and (
106 _is_homebrew_context(env)
107 or not (env.has(PackageManager.BUN) or env.has(PackageManager.NPM))
108 )
109 ):
110 return f"brew upgrade {brew_pkg}"
111 return f"{_npm_cmd(env)} {pkg}@{tool_version}"
114def _npm_cmd(env: InstallEnvironment) -> str:
115 """Return the preferred npm install command prefix."""
116 return "bun add -g" if env.has(PackageManager.BUN) else "npm install -g"
119def _is_homebrew_context(env: InstallEnvironment) -> bool:
120 """Check if the environment is a Homebrew install with brew available."""
121 return env.has(PackageManager.BREW) and env.install_context in (
122 InstallContext.HOMEBREW_FULL,
123 InstallContext.HOMEBREW_BIN,
124 )
127register_strategy(NpmStrategy())