Skip to content

Commit 708d61e

Browse files
committed
wip
1 parent b6d1d74 commit 708d61e

File tree

3 files changed

+123
-39
lines changed

3 files changed

+123
-39
lines changed

Cargo.lock

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9+
fancy-regex = "0.11.0"
910
lazy_static = "1.4.0"
1011
radix_trie = "0.2.1"
1112
regex = "1.7.1"

src/main.rs

Lines changed: 96 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
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};
22
use lazy_static::lazy_static;
33
use radix_trie::Trie;
44
use regex::Regex;
55
use serde::Deserialize;
6-
use serde::Deserializer;
7-
use serde_with::{serde_as, DeserializeAs, de::DeserializeAsWrap, OneOrMany};
6+
use serde_with::{serde_as, DefaultOnNull};
87
use simple_error::{self, bail, SimpleError};
98

109
enum Resolution {
@@ -13,19 +12,45 @@ enum Resolution {
1312
}
1413

1514
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+
}
1724
}
1825

1926
struct PnpResolutionConfig {
27+
builtins: HashSet<String>,
2028
host: PnpResolutionHost,
2129
}
2230

31+
impl Default for PnpResolutionConfig {
32+
fn default() -> PnpResolutionConfig {
33+
PnpResolutionConfig {
34+
builtins: HashSet::new(),
35+
host: Default::default(),
36+
}
37+
}
38+
}
39+
2340
#[derive(Deserialize)]
2441
struct PackageLocator {
2542
name: String,
2643
reference: String,
2744
}
2845

46+
#[derive(Clone)]
47+
#[derive(Deserialize)]
48+
#[serde(untagged)]
49+
enum PackageDependency {
50+
Reference(String),
51+
Alias(String, String),
52+
}
53+
2954
#[serde_as]
3055
#[derive(Deserialize)]
3156
#[serde(rename_all = "camelCase")]
@@ -35,14 +60,8 @@ struct PackageInformation {
3560
#[serde(default)]
3661
discard_from_lookup: bool,
3762

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>>,
4665
}
4766

4867
#[serde_as]
@@ -54,6 +73,9 @@ struct Manifest {
5473
#[serde(with = "serde_regex")]
5574
ignore_pattern_data: Option<Regex>,
5675

76+
#[serde(skip_deserializing)]
77+
fallback_dependencies: HashMap<String, Option<PackageDependency>>,
78+
5779
#[serde(skip_deserializing)]
5880
location_trie: Trie<PathBuf, PackageLocator>,
5981

@@ -87,23 +109,50 @@ struct Manifest {
87109
// }]
88110
// }]
89111
// ]
90-
#[serde_as(as = "Vec<(_, Vec<(_, _)>)>")]
112+
#[serde_as(as = "Vec<(DefaultOnNull<_>, Vec<(DefaultOnNull<_>, _)>)>")]
91113
package_registry_data: HashMap<String, HashMap<String, PackageInformation>>,
92114
}
93115

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
96141
}
97142

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 {
99148
lazy_static! {
100149
static ref RE: Regex = Regex::new("^\\.{0,2}/").unwrap();
101150
}
102151

103152
RE.is_match(&specifier)
104153
}
105154

106-
fn parse_bare_identifier(specifier: &String) -> Result<(String, Option<String>), SimpleError> {
155+
fn parse_bare_identifier(specifier: &str) -> Result<(String, Option<String>), SimpleError> {
107156
let mut segments = specifier.splitn(3, '/');
108157
let mut ident_option: Option<String> = None;
109158

@@ -171,14 +220,27 @@ fn load_pnp_manifest(p: &Path) -> Result<Manifest, Box<dyn Error>> {
171220

172221
let mut manifest: Manifest = serde_json::from_str(&json_string.to_owned())?;
173222

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+
174235
for (name, ranges) in manifest.package_registry_data.iter_mut() {
175236
for (reference, info) in ranges.iter_mut() {
176237
if info.discard_from_lookup {
177238
continue;
178239
}
179240

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());
182244

183245
manifest.location_trie.insert(info.package_location.clone(), PackageLocator {
184246
name: name.clone(),
@@ -216,30 +278,26 @@ fn is_excluded_from_fallback(manifest: &Manifest, locator: &PackageLocator) -> b
216278
}
217279
}
218280

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()))
222284
}
223285

224286
if is_path_specifier(&specifier) {
225-
return Ok(Resolution::Specifier(specifier.clone()))
287+
return Ok(Resolution::Specifier(specifier.to_string()))
226288
}
227289

228290
resolve_to_unqualified(&specifier, &parent, config)
229291
}
230292

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>> {
236294
let (ident, module_path) = parse_bare_identifier(specifier)?;
237295

238-
if let Some(manifest) = find_pnp_manifest(parent)? {
296+
if let Some(manifest) = (config.host.find_pnp_manifest)(parent)? {
239297
if let Some(parent_locator) = find_locator(&manifest, parent) {
240298
let parent_pkg = get_package(&manifest, &parent_locator)?;
241299

242-
let mut reference_or_alias: Option<Vec<String>> = None;
300+
let mut reference_or_alias: Option<PackageDependency> = None;
243301
let mut is_set = false;
244302

245303
if !is_set {
@@ -252,8 +310,8 @@ fn resolve_to_unqualified(specifier: &String, parent: &Path, config: &PnpResolut
252310
if !is_set {
253311
if manifest.enable_top_level_fallback {
254312
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();
257315
is_set = true;
258316
}
259317
}
@@ -265,9 +323,9 @@ fn resolve_to_unqualified(specifier: &String, parent: &Path, config: &PnpResolut
265323
}
266324

267325
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() }),
271329
_ => bail!("Invalid amount of elements"),
272330
}?;
273331

@@ -279,10 +337,10 @@ fn resolve_to_unqualified(specifier: &String, parent: &Path, config: &PnpResolut
279337
bail!("Resolution failed: Unsatisfied peer dependency");
280338
}
281339
} else {
282-
Ok(Resolution::Specifier(specifier.clone()))
340+
Ok(Resolution::Specifier(specifier.to_string()))
283341
}
284342
} else {
285-
Ok(Resolution::Specifier(specifier.clone()))
343+
Ok(Resolution::Specifier(specifier.to_string()))
286344
}
287345
}
288346

@@ -303,8 +361,7 @@ fn main() {
303361
println!("parent = {:?}", parent);
304362

305363
let resolution = pnp_resolve(&specifier, &parent, &PnpResolutionConfig {
306-
host: PnpResolutionHost {
307-
},
364+
..Default::default()
308365
});
309366

310367
match resolution {

0 commit comments

Comments
 (0)