Skip to content

Commit 371f084

Browse files
committed
feat: merge import maps
1 parent 860b6cf commit 371f084

2 files changed

Lines changed: 255 additions & 20 deletions

File tree

rs-lib/src/lib.rs

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@
33
use indexmap::IndexMap;
44
use serde_json::Map;
55
use serde_json::Value;
6-
use std::cmp::Ordering;
76
use std::collections::HashSet;
87
use std::fmt;
98
use std::fmt::Debug;
109
use thiserror::Error;
1110
use url::Url;
1211

12+
use self::merge::code_unit_compare;
13+
use self::merge::MergeDiagnostic;
14+
1315
#[cfg(feature = "ext")]
1416
pub mod ext;
17+
pub mod merge;
1518
pub mod specifier;
1619

1720
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -22,6 +25,7 @@ pub enum ImportMapDiagnostic {
2225
InvalidAddress(String, String),
2326
InvalidAddressNotString(String, String),
2427
InvalidTopLevelKey(String),
28+
Merge(Box<MergeDiagnostic>),
2529
}
2630

2731
impl fmt::Display for ImportMapDiagnostic {
@@ -58,6 +62,9 @@ impl fmt::Display for ImportMapDiagnostic {
5862
ImportMapDiagnostic::InvalidTopLevelKey(key) => {
5963
write!(f, "Invalid top-level key \"{}\". Only \"imports\" and \"scopes\" can be present.", key)
6064
}
65+
ImportMapDiagnostic::Merge(merge) => {
66+
write!(f, "Due to merge: {merge}")
67+
}
6168
}
6269
}
6370
}
@@ -130,6 +137,7 @@ struct SpecifierMapValue {
130137
raw_key: Option<String>,
131138
/// The raw value if it differs from the actual value.
132139
raw_value: Option<String>,
140+
/// None in case of block by null entry
133141
maybe_address: Option<Url>,
134142
}
135143

@@ -199,6 +207,7 @@ type SpecifierMapInner = IndexMap<String, SpecifierMapValue>;
199207

200208
#[derive(Debug, Clone)]
201209
pub struct SpecifierMap {
210+
#[deprecated = "import map base_url doesn't work with merged import maps"]
202211
base_url: Url,
203212
inner: SpecifierMapInner,
204213
}
@@ -221,6 +230,8 @@ impl SpecifierMap {
221230
})
222231
}
223232

233+
#[deprecated = "specifier map base_url doesn't work with merged import maps"]
234+
#[allow(deprecated)]
224235
pub fn contains(&self, key: &str) -> bool {
225236
if let Ok(key) = normalize_specifier_key(key, &self.base_url) {
226237
self.inner.contains_key(&key)
@@ -229,6 +240,8 @@ impl SpecifierMap {
229240
}
230241
}
231242

243+
#[deprecated = "specifier map base_url doesn't work with merged import maps"]
244+
#[allow(deprecated)]
232245
pub fn append(&mut self, key: String, value: String) -> Result<(), String> {
233246
let start_index = self
234247
.inner
@@ -280,12 +293,9 @@ impl SpecifierMap {
280293

281294
fn sort(&mut self) {
282295
// Sort in longest and alphabetical order.
283-
self.inner.sort_by(|k1, _v1, k2, _v2| match k1.cmp(k2) {
284-
Ordering::Greater => Ordering::Less,
285-
Ordering::Less => Ordering::Greater,
286-
// index map guarantees that there can't be duplicate keys
287-
Ordering::Equal => unreachable!(),
288-
});
296+
self
297+
.inner
298+
.sort_by(|k1, _v1, k2, _v2| code_unit_compare(k1, k2).reverse());
289299
}
290300
}
291301

@@ -318,11 +328,27 @@ pub struct ImportMapWithDiagnostics {
318328
pub diagnostics: Vec<ImportMapDiagnostic>,
319329
}
320330

331+
impl ImportMapWithDiagnostics {
332+
pub fn merge(&mut self, new: ImportMapWithDiagnostics) {
333+
let mut merge_diagnostics = vec![];
334+
merge::merge(&mut self.import_map, new.import_map, &mut merge_diagnostics);
335+
336+
self.diagnostics.extend(
337+
merge_diagnostics
338+
.into_iter()
339+
.map(Box::new)
340+
.map(ImportMapDiagnostic::Merge),
341+
);
342+
// Should diagnostics ignored due to merge be dropped?
343+
self.diagnostics.extend(new.diagnostics);
344+
}
345+
}
346+
321347
#[derive(Default)]
322348
pub struct ImportMapOptions {
323349
/// `(parsed_address, key, maybe_scope) -> new_address`
324350
#[allow(clippy::type_complexity)]
325-
pub address_hook: Option<Box<dyn (Fn(&str, &str, Option<&str>) -> String)>>,
351+
pub address_hook: Option<Box<dyn Fn(&str, &str, Option<&str>) -> String>>,
326352
/// Whether to expand imports in the import map.
327353
///
328354
/// This functionality can be used to modify the import map
@@ -362,6 +388,7 @@ impl ResolveOptions {
362388

363389
#[derive(Debug, Clone, serde::Serialize)]
364390
pub struct ImportMap {
391+
#[deprecated = "specifier map base_url doesn't work with merged import maps"]
365392
#[serde(skip)]
366393
base_url: Url,
367394

@@ -372,15 +399,19 @@ pub struct ImportMap {
372399
impl ImportMap {
373400
pub fn new(base_url: Url) -> Self {
374401
Self {
402+
#[allow(deprecated)]
375403
base_url: base_url.clone(),
376404
imports: SpecifierMap {
405+
#[allow(deprecated)]
377406
base_url,
378407
inner: Default::default(),
379408
},
380409
scopes: Default::default(),
381410
}
382411
}
383412

413+
#[deprecated = "import map base_url doesn't work with merged import maps"]
414+
#[allow(deprecated)]
384415
pub fn base_url(&self) -> &Url {
385416
&self.base_url
386417
}
@@ -507,6 +538,8 @@ impl ImportMap {
507538
})
508539
}
509540

541+
#[deprecated = "import map base_url doesn't work with merged import maps"]
542+
#[allow(deprecated)]
510543
pub fn get_or_append_scope_mut(
511544
&mut self,
512545
key: &str,
@@ -539,6 +572,7 @@ impl ImportMap {
539572
Some(key.to_string())
540573
},
541574
imports: SpecifierMap {
575+
#[allow(deprecated)]
542576
base_url,
543577
inner: Default::default(),
544578
},
@@ -645,6 +679,7 @@ pub fn parse_from_json_with_options(
645679
Ok(ImportMapWithDiagnostics {
646680
diagnostics,
647681
import_map: ImportMap {
682+
#[allow(deprecated)]
648683
base_url,
649684
imports,
650685
scopes,
@@ -674,6 +709,7 @@ pub fn parse_from_value_with_options(
674709
Ok(ImportMapWithDiagnostics {
675710
diagnostics,
676711
import_map: ImportMap {
712+
#[allow(deprecated)]
677713
base_url,
678714
imports,
679715
scopes,
@@ -891,15 +927,12 @@ fn parse_specifier_map(
891927
}
892928

893929
// Sort in longest and alphabetical order.
894-
normalized_map.sort_by(|k1, _v1, k2, _v2| match k1.cmp(k2) {
895-
Ordering::Greater => Ordering::Less,
896-
Ordering::Less => Ordering::Greater,
897-
// JSON guarantees that there can't be duplicate keys
898-
Ordering::Equal => unreachable!(),
899-
});
930+
normalized_map
931+
.sort_by(|k1, _v1, k2, _v2| code_unit_compare(k1, k2).reverse());
900932

901933
SpecifierMap {
902934
inner: normalized_map,
935+
#[allow(deprecated)]
903936
base_url: base_url.clone(),
904937
}
905938
}
@@ -948,12 +981,8 @@ fn parse_scope_map(
948981
}
949982

950983
// Sort in longest and alphabetical order.
951-
normalized_map.sort_by(|k1, _v1, k2, _v2| match k1.cmp(k2) {
952-
Ordering::Greater => Ordering::Less,
953-
Ordering::Less => Ordering::Greater,
954-
// JSON guarantees that there can't be duplicate keys
955-
Ordering::Equal => unreachable!(),
956-
});
984+
normalized_map
985+
.sort_by(|k1, _v1, k2, _v2| code_unit_compare(k1, k2).reverse());
957986

958987
Ok(normalized_map)
959988
}
@@ -1179,6 +1208,7 @@ mod test {
11791208
},
11801209
);
11811210
let specifiers = SpecifierMap {
1211+
#[allow(deprecated)]
11821212
base_url: Url::parse("file:///").unwrap(),
11831213
inner: specifiers,
11841214
};
@@ -1198,6 +1228,7 @@ mod test {
11981228
},
11991229
);
12001230
let specifiers = SpecifierMap {
1231+
#[allow(deprecated)]
12011232
base_url: Url::parse("file:///").unwrap(),
12021233
inner: specifiers,
12031234
};
@@ -1224,6 +1255,7 @@ mod test {
12241255
},
12251256
);
12261257
let specifiers = SpecifierMap {
1258+
#[allow(deprecated)]
12271259
base_url: Url::parse("file:///").unwrap(),
12281260
inner: specifiers,
12291261
};

0 commit comments

Comments
 (0)