@@ -2,11 +2,12 @@ mod error;
22pub mod package;
33mod package_manager;
44
5- use std:: { fs, io} ;
5+ use std:: { collections :: hash_map :: Entry , fs, io} ;
66
77use petgraph:: graph:: { DefaultIx , DiGraph , EdgeIndex , IndexType , NodeIndex } ;
88use rustc_hash:: { FxHashMap as HashMap , FxHashSet as HashSet } ;
99use serde:: { Deserialize , Serialize } ;
10+ use vec1:: smallvec_v1:: SmallVec1 ;
1011use vite_glob:: GlobPatternSet ;
1112use vite_path:: { AbsolutePath , AbsolutePathBuf , RelativePathBuf } ;
1213use vite_str:: Str ;
@@ -104,17 +105,12 @@ pub struct PackageInfo {
104105#[ derive( Default ) ]
105106struct PackageGraphBuilder {
106107 id_and_deps_by_path : HashMap < RelativePathBuf , ( PackageNodeIndex , Vec < ( Str , DependencyType ) > ) > ,
107- // Only for packages with a name
108- name_to_path : HashMap < Str , RelativePathBuf > ,
108+ name_to_path : HashMap < Str , SmallVec1 < [ RelativePathBuf ; 1 ] > > ,
109109 graph : DiGraph < PackageInfo , DependencyType , PackageIx > ,
110110}
111111
112112impl PackageGraphBuilder {
113- fn add_package (
114- & mut self ,
115- package_path : RelativePathBuf ,
116- package_json : PackageJson ,
117- ) -> Result < ( ) , Error > {
113+ fn add_package ( & mut self , package_path : RelativePathBuf , package_json : PackageJson ) {
118114 let deps = package_json. get_workspace_dependencies ( ) . collect :: < Vec < _ > > ( ) ;
119115 let package_name = package_json. name . clone ( ) ;
120116 let id = self . graph . add_node ( PackageInfo { package_json, path : package_path. clone ( ) } ) ;
@@ -123,22 +119,17 @@ impl PackageGraphBuilder {
123119 self . id_and_deps_by_path . insert ( package_path. clone ( ) , ( id, deps) ) ;
124120
125121 // Also maintain name to path mapping for dependency resolution
126- if !package_name. is_empty ( )
127- && let Some ( existing_path) = self . name_to_path . insert ( package_name, package_path)
128- {
129- // Duplicate package name found
130- let existing_id = self . id_and_deps_by_path . get ( & existing_path) . unwrap ( ) . 0 ;
131- let existing_package_info = & self . graph [ existing_id] ;
132- return Err ( Error :: DuplicatedPackageName {
133- name : existing_package_info. package_json . name . clone ( ) ,
134- path1 : existing_package_info. path . clone ( ) ,
135- path2 : self . graph [ id] . path . clone ( ) ,
136- } ) ;
122+ match self . name_to_path . entry ( package_name. clone ( ) ) {
123+ Entry :: Vacant ( entry) => {
124+ entry. insert ( SmallVec1 :: new ( package_path) ) ;
125+ }
126+ Entry :: Occupied ( mut entry) => {
127+ entry. get_mut ( ) . push ( package_path) ;
128+ }
137129 }
138- Ok ( ( ) )
139130 }
140131
141- fn build ( mut self ) -> DiGraph < PackageInfo , DependencyType , PackageIx > {
132+ fn build ( mut self ) -> Result < DiGraph < PackageInfo , DependencyType , PackageIx > , Error > {
142133 for ( id, deps) in self . id_and_deps_by_path . values ( ) {
143134 for ( dep_name, dep_type) in deps {
144135 // Skip dependencies on nameless packages (empty string)
@@ -148,15 +139,22 @@ impl PackageGraphBuilder {
148139 }
149140
150141 // Resolve dependency name to path, then find the node
151- if let Some ( dep_path ) = self . name_to_path . get ( dep_name)
152- && let Some ( ( dep_id, _) ) = self . id_and_deps_by_path . get ( dep_path )
142+ if let Some ( dep_paths ) = self . name_to_path . get ( dep_name)
143+ && let Some ( ( dep_id, _) ) = self . id_and_deps_by_path . get ( dep_paths . first ( ) )
153144 {
145+ if let [ dep_path1, dep_path2, ..] = dep_paths. as_slice ( ) {
146+ return Err ( Error :: DuplicatedPackageName {
147+ name : dep_name. clone ( ) ,
148+ path1 : dep_path1. clone ( ) ,
149+ path2 : dep_path2. clone ( ) ,
150+ } ) ;
151+ }
154152 self . graph . add_edge ( * id, * dep_id, * dep_type) ;
155153 }
156154 // Silently skip if dependency not found - it might be an external package
157155 }
158156 }
159- self . graph
157+ Ok ( self . graph )
160158 }
161159}
162160
@@ -205,9 +203,9 @@ pub fn load_package_graph(
205203 WorkspaceFile :: NonWorkspacePackage ( file) => {
206204 // For non-workspace packages, add the package.json to the graph as a root package
207205 let package_json: PackageJson = serde_json:: from_reader ( file) ?;
208- graph_builder. add_package ( RelativePathBuf :: default ( ) , package_json) ? ;
206+ graph_builder. add_package ( RelativePathBuf :: default ( ) , package_json) ;
209207
210- return Ok ( graph_builder. build ( ) ) ;
208+ return graph_builder. build ( ) ;
211209 }
212210 } ;
213211
@@ -224,15 +222,15 @@ pub fn load_package_graph(
224222 } ;
225223
226224 has_root_package = has_root_package || package_path. as_str ( ) . is_empty ( ) ;
227- graph_builder. add_package ( package_path, package_json) ? ;
225+ graph_builder. add_package ( package_path, package_json) ;
228226 }
229227 // try add the root package anyway if the member globs do not include it.
230228 if !has_root_package {
231229 let package_json_path = workspace_root. path . join ( "package.json" ) ;
232230 match fs:: read ( & package_json_path) {
233231 Ok ( package_json) => {
234232 let package_json: PackageJson = serde_json:: from_slice ( & package_json) ?;
235- graph_builder. add_package ( RelativePathBuf :: default ( ) , package_json) ? ;
233+ graph_builder. add_package ( RelativePathBuf :: default ( ) , package_json) ;
236234 }
237235 Err ( err) => {
238236 if err. kind ( ) != io:: ErrorKind :: NotFound {
@@ -241,7 +239,7 @@ pub fn load_package_graph(
241239 }
242240 }
243241 }
244- Ok ( graph_builder. build ( ) )
242+ graph_builder. build ( )
245243}
246244
247245#[ cfg( test) ]
@@ -537,15 +535,9 @@ mod tests {
537535 } ) ;
538536 fs:: write ( temp_dir_path. join ( "packages/pkg-2/package.json" ) , pkg_2. to_string ( ) ) . unwrap ( ) ;
539537
540- // Should return an error for duplicate package names
538+ // duplicate package names is allowed.
541539 let result = discover_package_graph ( temp_dir_path) ;
542- assert ! ( result. is_err( ) ) ;
543-
544- if let Err ( Error :: DuplicatedPackageName { name, .. } ) = result {
545- assert_eq ! ( name, "duplicate" ) ;
546- } else {
547- panic ! ( "Expected DuplicatedPackageName error, got: {result:?}" ) ;
548- }
540+ assert ! ( result. is_ok( ) ) ;
549541 }
550542
551543 #[ test]
0 commit comments