@@ -153,6 +153,68 @@ impl PackageManager {
153153 envs : HashMap :: from ( [ ( "PATH" . to_string ( ) , format_path_env ( self . get_bin_prefix ( ) ) ) ] ) ,
154154 }
155155 }
156+
157+ /// Build command arguments for adding packages with workspace support
158+ #[ must_use]
159+ pub fn build_add_args (
160+ & self ,
161+ packages : & [ String ] ,
162+ filters : & [ String ] ,
163+ workspace_root : bool ,
164+ workspace_only : bool ,
165+ extra_args : & [ String ] ,
166+ ) -> Vec < String > {
167+ let mut args = Vec :: new ( ) ;
168+
169+ match self . client {
170+ PackageManagerType :: Pnpm => {
171+ // pnpm: --filter must come before command
172+ for filter in filters {
173+ args. push ( "--filter" . to_string ( ) ) ;
174+ args. push ( filter. clone ( ) ) ;
175+ }
176+ args. push ( "add" . to_string ( ) ) ;
177+ args. extend_from_slice ( packages) ;
178+ if workspace_root {
179+ args. push ( "-w" . to_string ( ) ) ;
180+ }
181+ if workspace_only {
182+ args. push ( "--workspace" . to_string ( ) ) ;
183+ }
184+ args. extend_from_slice ( extra_args) ;
185+ }
186+ PackageManagerType :: Yarn => {
187+ // yarn: workspace <pkg> add
188+ if !filters. is_empty ( ) {
189+ args. push ( "workspace" . to_string ( ) ) ;
190+ args. push ( filters[ 0 ] . clone ( ) ) ;
191+ }
192+ args. push ( "add" . to_string ( ) ) ;
193+ args. extend_from_slice ( packages) ;
194+ if workspace_root {
195+ args. push ( "-W" . to_string ( ) ) ;
196+ }
197+ args. extend_from_slice ( extra_args) ;
198+ }
199+ PackageManagerType :: Npm => {
200+ // npm: install --workspace <pkg>
201+ args. push ( "install" . to_string ( ) ) ;
202+ args. extend_from_slice ( packages) ;
203+ if !filters. is_empty ( ) {
204+ for filter in filters {
205+ args. push ( "--workspace" . to_string ( ) ) ;
206+ args. push ( filter. clone ( ) ) ;
207+ }
208+ }
209+ if workspace_root {
210+ args. push ( "-w" . to_string ( ) ) ;
211+ }
212+ args. extend_from_slice ( extra_args) ;
213+ }
214+ }
215+
216+ args
217+ }
156218}
157219
158220/// The package root directory and its package.json file.
@@ -1611,4 +1673,122 @@ mod tests {
16111673 "pnpmfile.cjs should be detected before yarn.config.cjs"
16121674 ) ;
16131675 }
1676+
1677+ // Tests for build_add_args method
1678+ mod build_add_args_tests {
1679+ use super :: * ;
1680+
1681+ fn create_mock_pm ( pm_type : PackageManagerType ) -> PackageManager {
1682+ let temp_dir = create_temp_dir ( ) ;
1683+ let temp_dir_path = AbsolutePathBuf :: new ( temp_dir. path ( ) . to_path_buf ( ) ) . unwrap ( ) ;
1684+ let install_dir = temp_dir_path. join ( "install" ) ;
1685+
1686+ PackageManager {
1687+ client : pm_type,
1688+ package_name : pm_type. to_string ( ) . into ( ) ,
1689+ version : "1.0.0" . into ( ) ,
1690+ hash : None ,
1691+ bin_name : pm_type. to_string ( ) . into ( ) ,
1692+ workspace_root : temp_dir_path. clone ( ) ,
1693+ install_dir,
1694+ }
1695+ }
1696+
1697+ #[ test]
1698+ fn test_pnpm_basic_add ( ) {
1699+ let pm = create_mock_pm ( PackageManagerType :: Pnpm ) ;
1700+ let args = pm. build_add_args ( & [ "react" . to_string ( ) ] , & [ ] , false , false , & [ ] ) ;
1701+ assert_eq ! ( args, vec![ "add" , "react" ] ) ;
1702+ }
1703+
1704+ #[ test]
1705+ fn test_pnpm_add_with_filter ( ) {
1706+ let pm = create_mock_pm ( PackageManagerType :: Pnpm ) ;
1707+ let args =
1708+ pm. build_add_args ( & [ "react" . to_string ( ) ] , & [ "app" . to_string ( ) ] , false , false , & [ ] ) ;
1709+ assert_eq ! ( args, vec![ "--filter" , "app" , "add" , "react" ] ) ;
1710+ }
1711+
1712+ #[ test]
1713+ fn test_pnpm_add_workspace_root ( ) {
1714+ let pm = create_mock_pm ( PackageManagerType :: Pnpm ) ;
1715+ let args = pm. build_add_args (
1716+ & [ "typescript" . to_string ( ) ] ,
1717+ & [ ] ,
1718+ true ,
1719+ false ,
1720+ & [ "-D" . to_string ( ) ] ,
1721+ ) ;
1722+ assert_eq ! ( args, vec![ "add" , "typescript" , "-w" , "-D" ] ) ;
1723+ }
1724+
1725+ #[ test]
1726+ fn test_pnpm_add_workspace_only ( ) {
1727+ let pm = create_mock_pm ( PackageManagerType :: Pnpm ) ;
1728+ let args = pm. build_add_args (
1729+ & [ "@myorg/utils" . to_string ( ) ] ,
1730+ & [ "app" . to_string ( ) ] ,
1731+ false ,
1732+ true ,
1733+ & [ ] ,
1734+ ) ;
1735+ assert_eq ! ( args, vec![ "--filter" , "app" , "add" , "@myorg/utils" , "--workspace" ] ) ;
1736+ }
1737+
1738+ #[ test]
1739+ fn test_yarn_basic_add ( ) {
1740+ let pm = create_mock_pm ( PackageManagerType :: Yarn ) ;
1741+ let args = pm. build_add_args ( & [ "react" . to_string ( ) ] , & [ ] , false , false , & [ ] ) ;
1742+ assert_eq ! ( args, vec![ "add" , "react" ] ) ;
1743+ }
1744+
1745+ #[ test]
1746+ fn test_yarn_add_with_workspace ( ) {
1747+ let pm = create_mock_pm ( PackageManagerType :: Yarn ) ;
1748+ let args =
1749+ pm. build_add_args ( & [ "react" . to_string ( ) ] , & [ "app" . to_string ( ) ] , false , false , & [ ] ) ;
1750+ assert_eq ! ( args, vec![ "workspace" , "app" , "add" , "react" ] ) ;
1751+ }
1752+
1753+ #[ test]
1754+ fn test_yarn_add_workspace_root ( ) {
1755+ let pm = create_mock_pm ( PackageManagerType :: Yarn ) ;
1756+ let args = pm. build_add_args (
1757+ & [ "typescript" . to_string ( ) ] ,
1758+ & [ ] ,
1759+ true ,
1760+ false ,
1761+ & [ "-D" . to_string ( ) ] ,
1762+ ) ;
1763+ assert_eq ! ( args, vec![ "add" , "typescript" , "-W" , "-D" ] ) ;
1764+ }
1765+
1766+ #[ test]
1767+ fn test_npm_basic_add ( ) {
1768+ let pm = create_mock_pm ( PackageManagerType :: Npm ) ;
1769+ let args = pm. build_add_args ( & [ "react" . to_string ( ) ] , & [ ] , false , false , & [ ] ) ;
1770+ assert_eq ! ( args, vec![ "install" , "react" ] ) ;
1771+ }
1772+
1773+ #[ test]
1774+ fn test_npm_add_with_workspace ( ) {
1775+ let pm = create_mock_pm ( PackageManagerType :: Npm ) ;
1776+ let args =
1777+ pm. build_add_args ( & [ "react" . to_string ( ) ] , & [ "app" . to_string ( ) ] , false , false , & [ ] ) ;
1778+ assert_eq ! ( args, vec![ "install" , "react" , "--workspace" , "app" ] ) ;
1779+ }
1780+
1781+ #[ test]
1782+ fn test_npm_add_multiple_workspaces ( ) {
1783+ let pm = create_mock_pm ( PackageManagerType :: Npm ) ;
1784+ let args = pm. build_add_args (
1785+ & [ "lodash" . to_string ( ) ] ,
1786+ & [ "app" . to_string ( ) , "web" . to_string ( ) ] ,
1787+ false ,
1788+ false ,
1789+ & [ ] ,
1790+ ) ;
1791+ assert_eq ! ( args, vec![ "install" , "lodash" , "--workspace" , "app" , "--workspace" , "web" ] ) ;
1792+ }
1793+ }
16141794}
0 commit comments