1
- use std:: { error:: Error , path:: { Path , PathBuf } , fs, collections:: { HashSet , HashMap } , env} ;
1
+ use std:: { error:: Error , path:: { Path , PathBuf , Component } , fs, collections:: { HashSet , HashMap } , env} ;
2
2
use lazy_static:: lazy_static;
3
3
use radix_trie:: Trie ;
4
4
use regex:: Regex ;
5
5
use serde:: Deserialize ;
6
- use serde:: Deserializer ;
7
- use serde_with:: { serde_as, DeserializeAs , de:: DeserializeAsWrap , OneOrMany } ;
6
+ use serde_with:: { serde_as, DefaultOnNull } ;
8
7
use simple_error:: { self , bail, SimpleError } ;
9
8
10
9
enum Resolution {
@@ -13,19 +12,45 @@ enum Resolution {
13
12
}
14
13
15
14
struct PnpResolutionHost {
16
- // find_pnp_manifest: Box<dyn FnMut()>,
15
+ find_pnp_manifest : Box < dyn Fn ( & Path ) -> Result < Option < Manifest > , Box < dyn Error > > > ,
16
+ }
17
+
18
+ impl Default for PnpResolutionHost {
19
+ fn default ( ) -> PnpResolutionHost {
20
+ PnpResolutionHost {
21
+ find_pnp_manifest : Box :: new ( find_pnp_manifest) ,
22
+ }
23
+ }
17
24
}
18
25
19
26
struct PnpResolutionConfig {
27
+ builtins : HashSet < String > ,
20
28
host : PnpResolutionHost ,
21
29
}
22
30
31
+ impl Default for PnpResolutionConfig {
32
+ fn default ( ) -> PnpResolutionConfig {
33
+ PnpResolutionConfig {
34
+ builtins : HashSet :: new ( ) ,
35
+ host : Default :: default ( ) ,
36
+ }
37
+ }
38
+ }
39
+
23
40
#[ derive( Deserialize ) ]
24
41
struct PackageLocator {
25
42
name : String ,
26
43
reference : String ,
27
44
}
28
45
46
+ #[ derive( Clone ) ]
47
+ #[ derive( Deserialize ) ]
48
+ #[ serde( untagged) ]
49
+ enum PackageDependency {
50
+ Reference ( String ) ,
51
+ Alias ( String , String ) ,
52
+ }
53
+
29
54
#[ serde_as]
30
55
#[ derive( Deserialize ) ]
31
56
#[ serde( rename_all = "camelCase" ) ]
@@ -35,14 +60,8 @@ struct PackageInformation {
35
60
#[ serde( default ) ]
36
61
discard_from_lookup : bool ,
37
62
38
- #[ serde_as( as = "Vec<(_, Option<OneOrMany<_>>)>" ) ]
39
- package_dependencies : HashMap < String , Option < Vec < String > > > ,
40
- }
41
-
42
- fn deserialize_maybe_null_string < ' de , D > ( deserializer : D ) -> Result < String , D :: Error > where D : Deserializer < ' de > {
43
- let buf = String :: deserialize ( deserializer) ?;
44
-
45
- Ok ( buf)
63
+ #[ serde_as( as = "Vec<(_, Option<_>)>" ) ]
64
+ package_dependencies : HashMap < String , Option < PackageDependency > > ,
46
65
}
47
66
48
67
#[ serde_as]
@@ -54,6 +73,9 @@ struct Manifest {
54
73
#[ serde( with = "serde_regex" ) ]
55
74
ignore_pattern_data : Option < Regex > ,
56
75
76
+ #[ serde( skip_deserializing) ]
77
+ fallback_dependencies : HashMap < String , Option < PackageDependency > > ,
78
+
57
79
#[ serde( skip_deserializing) ]
58
80
location_trie : Trie < PathBuf , PackageLocator > ,
59
81
@@ -87,23 +109,50 @@ struct Manifest {
87
109
// }]
88
110
// }]
89
111
// ]
90
- #[ serde_as( as = "Vec<(_ , Vec<(_ , _)>)>" ) ]
112
+ #[ serde_as( as = "Vec<(DefaultOnNull<_> , Vec<(DefaultOnNull<_> , _)>)>" ) ]
91
113
package_registry_data : HashMap < String , HashMap < String , PackageInformation > > ,
92
114
}
93
115
94
- fn is_node_builtin ( specifier : & String ) -> bool {
95
- specifier. starts_with ( "node:" )
116
+ fn normalize_path ( path : & Path ) -> PathBuf {
117
+ let mut components = path. components ( ) . peekable ( ) ;
118
+ let mut ret = if let Some ( c @ Component :: Prefix ( ..) ) = components. peek ( ) . cloned ( ) {
119
+ components. next ( ) ;
120
+ PathBuf :: from ( c. as_os_str ( ) )
121
+ } else {
122
+ PathBuf :: new ( )
123
+ } ;
124
+
125
+ for component in components {
126
+ match component {
127
+ Component :: Prefix ( ..) => unreachable ! ( ) ,
128
+ Component :: RootDir => {
129
+ ret. push ( component. as_os_str ( ) ) ;
130
+ }
131
+ Component :: CurDir => { }
132
+ Component :: ParentDir => {
133
+ ret. pop ( ) ;
134
+ }
135
+ Component :: Normal ( c) => {
136
+ ret. push ( c) ;
137
+ }
138
+ }
139
+ }
140
+ ret
96
141
}
97
142
98
- fn is_path_specifier ( specifier : & String ) -> bool {
143
+ fn is_builtin ( specifier : & str , config : & PnpResolutionConfig ) -> bool {
144
+ config. builtins . contains ( specifier)
145
+ }
146
+
147
+ fn is_path_specifier ( specifier : & str ) -> bool {
99
148
lazy_static ! {
100
149
static ref RE : Regex = Regex :: new( "^\\ .{0,2}/" ) . unwrap( ) ;
101
150
}
102
151
103
152
RE . is_match ( & specifier)
104
153
}
105
154
106
- fn parse_bare_identifier ( specifier : & String ) -> Result < ( String , Option < String > ) , SimpleError > {
155
+ fn parse_bare_identifier ( specifier : & str ) -> Result < ( String , Option < String > ) , SimpleError > {
107
156
let mut segments = specifier. splitn ( 3 , '/' ) ;
108
157
let mut ident_option: Option < String > = None ;
109
158
@@ -171,14 +220,27 @@ fn load_pnp_manifest(p: &Path) -> Result<Manifest, Box<dyn Error>> {
171
220
172
221
let mut manifest: Manifest = serde_json:: from_str ( & json_string. to_owned ( ) ) ?;
173
222
223
+ for locator in manifest. fallback_pool . iter ( ) {
224
+ let info = manifest. package_registry_data
225
+ . get ( & locator. name )
226
+ . expect ( "Assertion failed: The locator should be registered" )
227
+ . get ( & locator. reference )
228
+ . expect ( "Assertion failed: The locator should be registered" ) ;
229
+
230
+ for ( name, dependency) in info. package_dependencies . iter ( ) {
231
+ manifest. fallback_dependencies . insert ( name. clone ( ) , dependency. clone ( ) ) ;
232
+ }
233
+ }
234
+
174
235
for ( name, ranges) in manifest. package_registry_data . iter_mut ( ) {
175
236
for ( reference, info) in ranges. iter_mut ( ) {
176
237
if info. discard_from_lookup {
177
238
continue ;
178
239
}
179
240
180
- info. package_location = manifest_dir
181
- . join ( info. package_location . clone ( ) ) ;
241
+ info. package_location = normalize_path ( manifest_dir
242
+ . join ( info. package_location . clone ( ) )
243
+ . as_path ( ) ) ;
182
244
183
245
manifest. location_trie . insert ( info. package_location . clone ( ) , PackageLocator {
184
246
name : name. clone ( ) ,
@@ -216,30 +278,26 @@ fn is_excluded_from_fallback(manifest: &Manifest, locator: &PackageLocator) -> b
216
278
}
217
279
}
218
280
219
- fn pnp_resolve ( specifier : & String , parent : & Path , config : & PnpResolutionConfig ) -> Result < Resolution , Box < dyn Error > > {
220
- if is_node_builtin ( & specifier) {
221
- return Ok ( Resolution :: Specifier ( specifier. clone ( ) ) )
281
+ fn pnp_resolve ( specifier : & str , parent : & Path , config : & PnpResolutionConfig ) -> Result < Resolution , Box < dyn Error > > {
282
+ if is_builtin ( & specifier, & config ) {
283
+ return Ok ( Resolution :: Specifier ( specifier. to_string ( ) ) )
222
284
}
223
285
224
286
if is_path_specifier ( & specifier) {
225
- return Ok ( Resolution :: Specifier ( specifier. clone ( ) ) )
287
+ return Ok ( Resolution :: Specifier ( specifier. to_string ( ) ) )
226
288
}
227
289
228
290
resolve_to_unqualified ( & specifier, & parent, config)
229
291
}
230
292
231
- fn get_dependency_from_fallback ( manifest : & Manifest , ident : & String ) -> Option < Vec < String > > {
232
- None
233
- }
234
-
235
- fn resolve_to_unqualified ( specifier : & String , parent : & Path , config : & PnpResolutionConfig ) -> Result < Resolution , Box < dyn Error > > {
293
+ fn resolve_to_unqualified ( specifier : & str , parent : & Path , config : & PnpResolutionConfig ) -> Result < Resolution , Box < dyn Error > > {
236
294
let ( ident, module_path) = parse_bare_identifier ( specifier) ?;
237
295
238
- if let Some ( manifest) = find_pnp_manifest ( parent) ? {
296
+ if let Some ( manifest) = ( config . host . find_pnp_manifest ) ( parent) ? {
239
297
if let Some ( parent_locator) = find_locator ( & manifest, parent) {
240
298
let parent_pkg = get_package ( & manifest, & parent_locator) ?;
241
299
242
- let mut reference_or_alias: Option < Vec < String > > = None ;
300
+ let mut reference_or_alias: Option < PackageDependency > = None ;
243
301
let mut is_set = false ;
244
302
245
303
if !is_set {
@@ -252,8 +310,8 @@ fn resolve_to_unqualified(specifier: &String, parent: &Path, config: &PnpResolut
252
310
if !is_set {
253
311
if manifest. enable_top_level_fallback {
254
312
if !is_excluded_from_fallback ( & manifest, & parent_locator) {
255
- if let Some ( fallback_resolution) = get_dependency_from_fallback ( & manifest, & ident) {
256
- reference_or_alias = Some ( fallback_resolution) ;
313
+ if let Some ( fallback_resolution) = manifest. fallback_dependencies . get ( & ident) {
314
+ reference_or_alias = fallback_resolution. clone ( ) ;
257
315
is_set = true ;
258
316
}
259
317
}
@@ -265,9 +323,9 @@ fn resolve_to_unqualified(specifier: &String, parent: &Path, config: &PnpResolut
265
323
}
266
324
267
325
if let Some ( resolution) = reference_or_alias {
268
- let dependency_pkg = match resolution. as_slice ( ) {
269
- [ reference] => get_package ( & manifest, & PackageLocator { name : ident, reference : reference. clone ( ) } ) ,
270
- [ name, reference] => get_package ( & manifest, & PackageLocator { name : name. clone ( ) , reference : reference. clone ( ) } ) ,
326
+ let dependency_pkg = match resolution {
327
+ PackageDependency :: Reference ( reference) => get_package ( & manifest, & PackageLocator { name : ident, reference : reference. clone ( ) } ) ,
328
+ PackageDependency :: Alias ( name, reference) => get_package ( & manifest, & PackageLocator { name : name. clone ( ) , reference : reference. clone ( ) } ) ,
271
329
_ => bail ! ( "Invalid amount of elements" ) ,
272
330
} ?;
273
331
@@ -279,10 +337,10 @@ fn resolve_to_unqualified(specifier: &String, parent: &Path, config: &PnpResolut
279
337
bail ! ( "Resolution failed: Unsatisfied peer dependency" ) ;
280
338
}
281
339
} else {
282
- Ok ( Resolution :: Specifier ( specifier. clone ( ) ) )
340
+ Ok ( Resolution :: Specifier ( specifier. to_string ( ) ) )
283
341
}
284
342
} else {
285
- Ok ( Resolution :: Specifier ( specifier. clone ( ) ) )
343
+ Ok ( Resolution :: Specifier ( specifier. to_string ( ) ) )
286
344
}
287
345
}
288
346
@@ -303,8 +361,7 @@ fn main() {
303
361
println ! ( "parent = {:?}" , parent) ;
304
362
305
363
let resolution = pnp_resolve ( & specifier, & parent, & PnpResolutionConfig {
306
- host : PnpResolutionHost {
307
- } ,
364
+ ..Default :: default ( )
308
365
} ) ;
309
366
310
367
match resolution {
0 commit comments