1
- use std:: { error :: Error , path:: { Path , PathBuf , Component } , fs, collections:: { HashSet , HashMap } , env} ;
1
+ use std:: { path:: { Path , PathBuf , Component } , fs, collections:: { HashSet , HashMap } , env, borrow :: Cow } ;
2
2
use lazy_static:: lazy_static;
3
3
use radix_trie:: Trie ;
4
- use regex :: Regex ;
5
- use serde:: Deserialize ;
4
+ use fancy_regex :: Regex ;
5
+ use serde:: { Deserialize , Deserializer } ;
6
6
use serde_with:: { serde_as, DefaultOnNull } ;
7
7
use simple_error:: { self , bail, SimpleError } ;
8
8
@@ -12,7 +12,7 @@ enum Resolution {
12
12
}
13
13
14
14
struct PnpResolutionHost {
15
- find_pnp_manifest : Box < dyn Fn ( & Path ) -> Result < Option < Manifest > , Box < dyn Error > > > ,
15
+ find_pnp_manifest : Box < dyn Fn ( & Path ) -> Result < Option < Manifest > , Box < dyn std :: error :: Error > > > ,
16
16
}
17
17
18
18
impl Default for PnpResolutionHost {
@@ -23,19 +23,13 @@ impl Default for PnpResolutionHost {
23
23
}
24
24
}
25
25
26
+ #[ derive( Default ) ]
26
27
struct PnpResolutionConfig {
27
28
builtins : HashSet < String > ,
28
29
host : PnpResolutionHost ,
29
30
}
30
31
31
- impl Default for PnpResolutionConfig {
32
- fn default ( ) -> PnpResolutionConfig {
33
- PnpResolutionConfig {
34
- builtins : HashSet :: new ( ) ,
35
- host : Default :: default ( ) ,
36
- }
37
- }
38
- }
32
+
39
33
40
34
#[ derive( Deserialize ) ]
41
35
struct PackageLocator {
@@ -64,31 +58,59 @@ struct PackageInformation {
64
58
package_dependencies : HashMap < String , Option < PackageDependency > > ,
65
59
}
66
60
61
+ fn strip_slash_escape ( str : & str ) -> String {
62
+ let mut res = String :: default ( ) ;
63
+ res. reserve_exact ( str. len ( ) ) ;
64
+
65
+ let mut iter = str. chars ( ) . peekable ( ) ;
66
+ let mut escaped = false ;
67
+
68
+ while let Some ( c) = iter. next ( ) {
69
+ if !escaped && c == '\\' {
70
+ if iter. peek ( ) == Some ( & '/' ) {
71
+ continue ;
72
+ }
73
+
74
+ escaped = true ;
75
+ }
76
+
77
+ res. push ( c) ;
78
+ escaped = false ;
79
+ }
80
+
81
+ res
82
+ }
83
+
84
+ #[ derive( Debug ) ]
85
+ struct RegexDef ( Regex ) ;
86
+
87
+ impl < ' de > Deserialize < ' de > for RegexDef {
88
+ fn deserialize < D > ( d : D ) -> Result < RegexDef , D :: Error >
89
+ where D : Deserializer < ' de > ,
90
+ {
91
+ let s = <Cow < str > >:: deserialize ( d) ?;
92
+
93
+ match strip_slash_escape ( s. as_ref ( ) ) . parse ( ) {
94
+ Ok ( regex) => Ok ( RegexDef ( regex) ) ,
95
+ Err ( err) => Err ( D :: Error :: custom ( err) ) ,
96
+ }
97
+ }
98
+ }
99
+
67
100
#[ serde_as]
68
101
#[ derive( Deserialize ) ]
69
102
#[ serde( rename_all = "camelCase" ) ]
70
103
struct Manifest {
71
104
enable_top_level_fallback : bool ,
72
105
73
- #[ serde( with = "serde_regex" ) ]
74
- ignore_pattern_data : Option < Regex > ,
106
+ ignore_pattern_data : Option < RegexDef > ,
75
107
76
108
#[ serde( skip_deserializing) ]
77
109
fallback_dependencies : HashMap < String , Option < PackageDependency > > ,
78
110
79
111
#[ serde( skip_deserializing) ]
80
112
location_trie : Trie < PathBuf , PackageLocator > ,
81
113
82
- // dependencyTreeRoots: [{
83
- // name: "@app/monorepo",
84
- // reference: "workspace:.",
85
- // }, {
86
- // name: "@app/website",
87
- // reference: "workspace:website",
88
- // }]
89
- //
90
- dependency_tree_roots : Vec < PackageLocator > ,
91
-
92
114
// fallbackPool: [[
93
115
// "@app/monorepo",
94
116
// "workspace:.",
@@ -149,7 +171,7 @@ fn is_path_specifier(specifier: &str) -> bool {
149
171
static ref RE : Regex = Regex :: new( "^\\ .{0,2}/" ) . unwrap( ) ;
150
172
}
151
173
152
- RE . is_match ( & specifier)
174
+ RE . is_match ( specifier) . unwrap ( )
153
175
}
154
176
155
177
fn parse_bare_identifier ( specifier : & str ) -> Result < ( String , Option < String > ) , SimpleError > {
@@ -187,7 +209,7 @@ fn find_closest_pnp_manifest_path(p: &Path) -> Option<PathBuf> {
187
209
}
188
210
}
189
211
190
- fn load_pnp_manifest ( p : & Path ) -> Result < Manifest , Box < dyn Error > > {
212
+ fn load_pnp_manifest ( p : & Path ) -> Result < Manifest , Box < dyn std :: error :: Error > > {
191
213
let manifest_content = fs:: read_to_string ( p) ?;
192
214
let manifest_dir = p. parent ( )
193
215
. expect ( "Should have a parent directory" ) ;
@@ -196,7 +218,7 @@ fn load_pnp_manifest(p: &Path) -> Result<Manifest, Box<dyn Error>> {
196
218
static ref RE : Regex = Regex :: new( "const\\ s+RAW_RUNTIME_STATE\\ s*=\\ s*'" ) . unwrap( ) ;
197
219
}
198
220
199
- let manifest_match = RE . find ( & manifest_content)
221
+ let manifest_match = RE . find ( & manifest_content) ?
200
222
. expect ( "Should have been able to locate the runtime state payload offset" ) ;
201
223
202
224
let iter = manifest_content. chars ( ) . skip ( manifest_match. end ( ) ) ;
@@ -252,15 +274,15 @@ fn load_pnp_manifest(p: &Path) -> Result<Manifest, Box<dyn Error>> {
252
274
Ok ( manifest)
253
275
}
254
276
255
- fn find_pnp_manifest ( parent : & Path ) -> Result < Option < Manifest > , Box < dyn Error > > {
256
- find_closest_pnp_manifest_path ( parent) . map_or ( Ok ( None ) , |p| Ok ( Some ( load_pnp_manifest ( & * p) ?) ) )
277
+ fn find_pnp_manifest ( parent : & Path ) -> Result < Option < Manifest > , Box < dyn std :: error :: Error > > {
278
+ find_closest_pnp_manifest_path ( parent) . map_or ( Ok ( None ) , |p| Ok ( Some ( load_pnp_manifest ( & p) ?) ) )
257
279
}
258
280
259
281
fn find_locator < ' a > ( manifest : & ' a Manifest , path : & Path ) -> Option < & ' a PackageLocator > {
260
282
manifest. location_trie . get_ancestor_value ( path)
261
283
}
262
284
263
- fn get_package < ' a > ( manifest : & ' a Manifest , locator : & PackageLocator ) -> Result < & ' a PackageInformation , Box < dyn Error > > {
285
+ fn get_package < ' a > ( manifest : & ' a Manifest , locator : & PackageLocator ) -> Result < & ' a PackageInformation , Box < dyn std :: error :: Error > > {
264
286
let references = manifest. package_registry_data . get ( & locator. name )
265
287
. expect ( "Should have an entry in the package registry" ) ;
266
288
@@ -278,24 +300,24 @@ fn is_excluded_from_fallback(manifest: &Manifest, locator: &PackageLocator) -> b
278
300
}
279
301
}
280
302
281
- fn pnp_resolve ( specifier : & str , parent : & Path , config : & PnpResolutionConfig ) -> Result < Resolution , Box < dyn Error > > {
282
- if is_builtin ( & specifier, & config) {
303
+ fn pnp_resolve ( specifier : & str , parent : & Path , config : & PnpResolutionConfig ) -> Result < Resolution , Box < dyn std :: error :: Error > > {
304
+ if is_builtin ( specifier, config) {
283
305
return Ok ( Resolution :: Specifier ( specifier. to_string ( ) ) )
284
306
}
285
307
286
- if is_path_specifier ( & specifier) {
308
+ if is_path_specifier ( specifier) {
287
309
return Ok ( Resolution :: Specifier ( specifier. to_string ( ) ) )
288
310
}
289
311
290
- resolve_to_unqualified ( & specifier, & parent, config)
312
+ resolve_to_unqualified ( specifier, parent, config)
291
313
}
292
314
293
- fn resolve_to_unqualified ( specifier : & str , parent : & Path , config : & PnpResolutionConfig ) -> Result < Resolution , Box < dyn Error > > {
315
+ fn resolve_to_unqualified ( specifier : & str , parent : & Path , config : & PnpResolutionConfig ) -> Result < Resolution , Box < dyn std :: error :: Error > > {
294
316
let ( ident, module_path) = parse_bare_identifier ( specifier) ?;
295
317
296
318
if let Some ( manifest) = ( config. host . find_pnp_manifest ) ( parent) ? {
297
319
if let Some ( parent_locator) = find_locator ( & manifest, parent) {
298
- let parent_pkg = get_package ( & manifest, & parent_locator) ?;
320
+ let parent_pkg = get_package ( & manifest, parent_locator) ?;
299
321
300
322
let mut reference_or_alias: Option < PackageDependency > = None ;
301
323
let mut is_set = false ;
@@ -307,14 +329,10 @@ fn resolve_to_unqualified(specifier: &str, parent: &Path, config: &PnpResolution
307
329
}
308
330
}
309
331
310
- if !is_set {
311
- if manifest. enable_top_level_fallback {
312
- if !is_excluded_from_fallback ( & manifest, & parent_locator) {
313
- if let Some ( fallback_resolution) = manifest. fallback_dependencies . get ( & ident) {
314
- reference_or_alias = fallback_resolution. clone ( ) ;
315
- is_set = true ;
316
- }
317
- }
332
+ if !is_set && manifest. enable_top_level_fallback && !is_excluded_from_fallback ( & manifest, parent_locator) {
333
+ if let Some ( fallback_resolution) = manifest. fallback_dependencies . get ( & ident) {
334
+ reference_or_alias = fallback_resolution. clone ( ) ;
335
+ is_set = true ;
318
336
}
319
337
}
320
338
@@ -324,9 +342,8 @@ fn resolve_to_unqualified(specifier: &str, parent: &Path, config: &PnpResolution
324
342
325
343
if let Some ( resolution) = reference_or_alias {
326
344
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 ( ) } ) ,
329
- _ => bail ! ( "Invalid amount of elements" ) ,
345
+ PackageDependency :: Reference ( reference) => get_package ( & manifest, & PackageLocator { name : ident, reference } ) ,
346
+ PackageDependency :: Alias ( name, reference) => get_package ( & manifest, & PackageLocator { name, reference } ) ,
330
347
} ?;
331
348
332
349
let final_path = dependency_pkg. package_location
@@ -354,7 +371,7 @@ fn main() {
354
371
. expect ( "A specifier must be provided" ) ;
355
372
356
373
let parent = args. next ( )
357
- . map ( |p| PathBuf :: from ( p ) )
374
+ . map ( PathBuf :: from)
358
375
. expect ( "A parent url must be provided" ) ;
359
376
360
377
println ! ( "specifier = {}" , specifier) ;
0 commit comments