@@ -5,15 +5,16 @@ use std::path::{Path, PathBuf};
55
66use super :: ruborist_context:: Context ;
77use crate :: helper:: workspace:: find_workspaces;
8+ use crate :: util:: git_resolver:: { resolve_git_spec, resolve_github_spec} ;
89use crate :: util:: json:: { load_package_json_from_path, load_package_lock_json_from_path} ;
910use crate :: util:: logger:: { finish_progress_bar, start_progress_bar} ;
1011use crate :: util:: save_type:: { PackageAction , SaveType } ;
1112use crate :: util:: user_config:: get_legacy_peer_deps;
12- use crate :: util:: { cloner:: clone_package, downloader:: download_to_cache } ;
13+ use crate :: util:: { cloner:: clone_package, downloader:: resolve_cache_path } ;
1314use utoo_ruborist:: lock:: { LockPackage , PackageLock } ;
1415use utoo_ruborist:: manifest:: PackageJson ;
1516use utoo_ruborist:: registry:: resolve_package;
16- use utoo_ruborist:: util :: parse_package_spec ;
17+ use utoo_ruborist:: spec :: { PackageSpec , parse_cli_spec } ;
1718
1819use super :: workspace:: find_workspace_path;
1920
@@ -168,13 +169,10 @@ pub async fn update_package_json(
168169 for ( name, version, version_spec) in package_specs {
169170 match action {
170171 PackageAction :: Add => {
171- let version_to_write = match version_spec {
172- spec if spec. is_empty ( ) || spec == "*" || spec == "latest" => {
173- format ! ( "^{version}" )
174- }
175- spec => spec. to_string ( ) ,
176- } ;
177- deps_obj. insert ( name, Value :: String ( version_to_write) ) ;
172+ deps_obj. insert (
173+ name,
174+ Value :: String ( format_save_spec ( & version_spec, & version) ) ,
175+ ) ;
178176 }
179177 PackageAction :: Remove => {
180178 deps_obj. remove ( & name) ;
@@ -193,12 +191,44 @@ pub async fn update_package_json(
193191 Ok ( ( ) )
194192}
195193
194+ /// Format a version spec for writing into package.json.
195+ ///
196+ /// Git/non-registry specs are written as-is (e.g. the resolved URL with pinned commit).
197+ /// Wildcard specs (`*`, `latest`, empty) are pinned to `^<resolved_version>`.
198+ /// Everything else (semver ranges, exact versions) passes through unchanged.
199+ fn format_save_spec ( version_spec : & str , resolved_version : & str ) -> String {
200+ if version_spec. starts_with ( "git+" ) || version_spec. starts_with ( "git://" ) {
201+ return version_spec. to_string ( ) ;
202+ }
203+ match version_spec {
204+ "" | "*" | "latest" => format ! ( "^{resolved_version}" ) ,
205+ _ => version_spec. to_string ( ) ,
206+ }
207+ }
208+
196209pub async fn resolve_package_spec ( spec : & str ) -> Result < ( String , String , String ) > {
197- let ( name, version_spec) = parse_package_spec ( spec) ;
198- let resolved = resolve_package ( & Context :: registry ( ) , name, version_spec)
199- . await
200- . map_err ( |e| anyhow ! ( "{}" , e) ) ?;
201- Ok ( ( name. to_string ( ) , resolved. version , version_spec. to_string ( ) ) )
210+ let parsed = parse_cli_spec ( spec) ;
211+ match parsed {
212+ PackageSpec :: Registry { name, version_spec } => {
213+ let resolved = resolve_package ( & Context :: registry ( ) , & name, & version_spec)
214+ . await
215+ . map_err ( |e| anyhow ! ( "{}" , e) ) ?;
216+ Ok ( ( name, resolved. version , version_spec) )
217+ }
218+ PackageSpec :: Git { url, commit_ish } => {
219+ let resolved = resolve_git_spec ( & url, commit_ish. as_deref ( ) ) . await ?;
220+ Ok ( ( resolved. name , resolved. version , resolved. resolved_url ) )
221+ }
222+ PackageSpec :: GitHub {
223+ owner,
224+ repo,
225+ commit_ish,
226+ } => {
227+ let resolved = resolve_github_spec ( & owner, & repo, commit_ish. as_deref ( ) ) . await ?;
228+ Ok ( ( resolved. name , resolved. version , resolved. resolved_url ) )
229+ }
230+ _ => Err ( anyhow ! ( "Unsupported package spec type: {}" , spec) ) ,
231+ }
202232}
203233
204234pub async fn prepare_global_package_json ( npm_spec : & str , prefix : Option < & str > ) -> Result < PathBuf > {
@@ -238,7 +268,7 @@ pub async fn prepare_global_package_json(npm_spec: &str, prefix: Option<&str>) -
238268 . ok_or_else ( || anyhow ! ( "Failed to get tarball URL from manifest" ) ) ?;
239269
240270 // Download and extract package to cache
241- let cache_path = download_to_cache ( & name, & resolved. version , tarball_url)
271+ let cache_path = resolve_cache_path ( & name, & resolved. version , tarball_url)
242272 . await
243273 . ok_or_else ( || anyhow ! ( "Failed to download package {name}" ) ) ?;
244274
0 commit comments