11use super :: build_types:: * ;
22use super :: namespaces;
33use super :: packages;
4+ use crate :: build:: packages:: DependencySymLink :: { NoSymlink , Symlink } ;
45use crate :: config;
56use crate :: helpers;
67use crate :: helpers:: StrippedVerbatimPath ;
@@ -39,13 +40,22 @@ impl Namespace {
3940 }
4041}
4142
43+ #[ derive( Debug , Clone ) ]
44+ pub enum DependencySymLink {
45+ NoSymlink ,
46+ Symlink ( PathBuf ) ,
47+ }
48+
4249#[ derive( Debug , Clone ) ]
4350struct Dependency {
4451 name : String ,
4552 config : config:: Config ,
4653 path : PathBuf ,
4754 is_pinned : bool ,
4855 dependencies : Vec < Dependency > ,
56+ // Track if the original dependency path actually a symbolic link.
57+ // We need to know this to later assert if a package is local or not.
58+ sym_link : DependencySymLink ,
4959}
5060
5161#[ derive( Debug , Clone ) ]
@@ -254,7 +264,7 @@ pub fn read_dependency(
254264 parent_path : & Path ,
255265 project_root : & Path ,
256266 workspace_root : & Option < PathBuf > ,
257- ) -> Result < PathBuf , String > {
267+ ) -> Result < ( PathBuf , DependencySymLink ) , String > {
258268 let path_from_parent = PathBuf :: from ( helpers:: package_path ( parent_path, package_name) ) ;
259269 let path_from_project_root = PathBuf :: from ( helpers:: package_path ( project_root, package_name) ) ;
260270 let maybe_path_from_workspace_root = workspace_root
@@ -277,6 +287,17 @@ pub fn read_dependency(
277287 ) ) ,
278288 } ?;
279289
290+ // There could be a symbolic link because the package.json has:
291+ // "dependencies": {
292+ // "my-package": "link:my-package",
293+ // }
294+ // In this case, there will be a link from node_modules/my-package to a local path.
295+ let symlink = match fs:: symlink_metadata ( & path) . map ( |m| m. file_type ( ) . is_symlink ( ) ) {
296+ Err ( _) => NoSymlink ,
297+ Ok ( false ) => NoSymlink ,
298+ Ok ( true ) => Symlink ( path. clone ( ) ) ,
299+ } ;
300+
280301 let canonical_path = match path
281302 . canonicalize ( )
282303 . map ( StrippedVerbatimPath :: to_stripped_verbatim_path)
@@ -290,7 +311,7 @@ pub fn read_dependency(
290311 ) ) ,
291312 } ?;
292313
293- Ok ( canonical_path)
314+ Ok ( ( canonical_path, symlink ) )
294315}
295316
296317/// # Make Package
@@ -331,7 +352,7 @@ fn read_dependencies(
331352 // Read all config files in parallel instead of blocking
332353 . par_iter ( )
333354 . map ( |package_name| {
334- let ( config, canonical_path) =
355+ let ( config, canonical_path, sym_link ) =
335356 match read_dependency ( package_name, parent_path, project_root, & workspace_root) {
336357 Err ( error) => {
337358 if show_progress {
@@ -350,9 +371,9 @@ fn read_dependencies(
350371
351372 std:: process:: exit ( 2 )
352373 }
353- Ok ( canonical_path) => {
374+ Ok ( ( canonical_path, sym_link ) ) => {
354375 match read_config ( & canonical_path) {
355- Ok ( config) => ( config, canonical_path) ,
376+ Ok ( config) => ( config, canonical_path, sym_link ) ,
356377 Err ( error) => {
357378 let parent_path_str = parent_path. to_string_lossy ( ) ;
358379 log:: error!(
@@ -386,6 +407,7 @@ fn read_dependencies(
386407 path : canonical_path,
387408 is_pinned,
388409 dependencies,
410+ sym_link
389411 }
390412 } )
391413 . collect ( )
@@ -416,7 +438,13 @@ pub fn read_package_name(package_dir: &Path) -> Result<String> {
416438 . ok_or_else ( || anyhow ! ( "No name field found in package.json" ) )
417439}
418440
419- fn make_package ( config : config:: Config , package_path : & Path , is_pinned_dep : bool , is_root : bool ) -> Package {
441+ fn make_package (
442+ config : config:: Config ,
443+ package_path : & Path ,
444+ is_pinned_dep : bool ,
445+ is_root : bool ,
446+ is_local_dep : bool ,
447+ ) -> Package {
420448 let source_folders = match config. sources . to_owned ( ) {
421449 Some ( config:: OneOrMore :: Single ( source) ) => get_source_dirs ( source, None ) ,
422450 Some ( config:: OneOrMore :: Multiple ( sources) ) => {
@@ -469,7 +497,7 @@ This inconsistency will cause issues with package resolution.\n",
469497 . expect ( "Could not canonicalize" ) ,
470498 dirs : None ,
471499 is_pinned_dep,
472- is_local_dep : !package_path . components ( ) . any ( |c| c . as_os_str ( ) == "node_modules" ) ,
500+ is_local_dep,
473501 is_root,
474502 }
475503}
@@ -484,7 +512,7 @@ fn read_packages(
484512
485513 // Store all packages and completely deduplicate them
486514 let mut map: AHashMap < String , Package > = AHashMap :: new ( ) ;
487- let root_package = make_package ( root_config. to_owned ( ) , project_root, false , true ) ;
515+ let root_package = make_package ( root_config. to_owned ( ) , project_root, false , true , true ) ;
488516 map. insert ( root_package. name . to_string ( ) , root_package) ;
489517
490518 let mut registered_dependencies_set: AHashSet < String > = AHashSet :: new ( ) ;
@@ -499,7 +527,13 @@ fn read_packages(
499527 ) ) ;
500528 dependencies. iter ( ) . for_each ( |d| {
501529 if !map. contains_key ( & d. name ) {
502- let package = make_package ( d. config . to_owned ( ) , & d. path , d. is_pinned , false ) ;
530+ let is_local_dep = match & d. sym_link {
531+ NoSymlink => !d. path . components ( ) . any ( |c| c. as_os_str ( ) == "node_modules" ) ,
532+ Symlink ( original_path) => !original_path
533+ . components ( )
534+ . any ( |c| c. as_os_str ( ) == "node_modules" ) ,
535+ } ;
536+ let package = make_package ( d. config . to_owned ( ) , & d. path , d. is_pinned , false , is_local_dep) ;
503537 map. insert ( d. name . to_string ( ) , package) ;
504538 }
505539 } ) ;
0 commit comments