Skip to content

Commit 5293089

Browse files
committed
feat(core): write a new specifier parser
Closes #261
1 parent c3f5298 commit 5293089

30 files changed

+1701
-1066
lines changed

src/context.rs

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use {
66
package_json::{FormatMismatch, FormatMismatchVariant, PackageJson},
77
packages::Packages,
88
semver_group::SemverGroup,
9+
specifier::basic_semver::BasicSemver,
910
version_group::VersionGroup,
1011
},
1112
std::{cell::RefCell, collections::HashMap, rc::Rc},
@@ -17,6 +18,8 @@ pub struct Context {
1718
pub config: Config,
1819
/// Every instance in the project
1920
pub instances: Vec<Rc<Instance>>,
21+
/// Index of every local package with a valid name and version
22+
pub local_versions: HashMap<String, BasicSemver>,
2023
/// Every package.json in the project
2124
pub packages: Packages,
2225
/// All semver groups
@@ -30,28 +33,39 @@ impl Context {
3033
let mut instances = vec![];
3134
let dependency_groups = config.rcfile.get_dependency_groups(&packages);
3235
let semver_groups = config.rcfile.get_semver_groups(&packages);
33-
let version_groups = config.rcfile.get_version_groups(&packages);
36+
let mut version_groups = config.rcfile.get_version_groups(&packages);
37+
let local_versions = packages.get_local_versions();
3438

35-
packages.get_all_instances(&config, |instance| {
36-
let instance = Rc::new(instance);
37-
instances.push(Rc::clone(&instance));
38-
if let Some(dependency_group) = dependency_groups.iter().find(|alias| alias.can_add(&instance)) {
39-
instance.set_internal_name(&dependency_group.label);
39+
packages.get_all_instances(&config, |mut descriptor| {
40+
let dependency_group = dependency_groups.iter().find(|alias| alias.can_add(&descriptor));
41+
42+
if let Some(group) = dependency_group {
43+
descriptor.internal_name = group.label.clone();
4044
}
41-
if let Some(semver_group) = semver_groups.iter().find(|semver_group| semver_group.selector.can_add(&instance)) {
42-
instance.set_semver_group(semver_group);
45+
46+
if let Some(cli_group) = &config.cli.filter {
47+
descriptor.matches_cli_filter = cli_group.can_add(&descriptor);
4348
}
44-
if let Some(version_group) = version_groups
45-
.iter()
46-
.find(|version_group| version_group.selector.can_add(&instance))
47-
{
48-
version_group.add_instance(instance, &config.cli.filter);
49+
50+
let semver_group = semver_groups.iter().find(|group| group.selector.can_add(&descriptor));
51+
let version_group = version_groups.iter_mut().find(|group| group.selector.can_add(&descriptor));
52+
let instance = Rc::new(Instance::new(descriptor));
53+
54+
instances.push(Rc::clone(&instance));
55+
56+
if let Some(group) = semver_group {
57+
instance.set_semver_group(group);
58+
}
59+
60+
if let Some(group) = version_group {
61+
group.add_instance(instance);
4962
}
5063
});
5164

5265
Self {
5366
config,
5467
instances,
68+
local_versions,
5569
packages,
5670
semver_groups,
5771
version_groups,

src/dependency.rs

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use {
33
instance::Instance,
44
instance_state::InstanceState,
55
package_json::PackageJson,
6-
specifier::{orderable::IsOrderable, semver::Semver, simple_semver::SimpleSemver, Specifier},
6+
specifier::{semver_range::SemverRange, Specifier},
77
version_group::VersionGroupVariant,
88
},
99
itertools::Itertools,
@@ -26,9 +26,9 @@ pub struct Dependency {
2626
/// If this dependency is a local package, this is the local instance.
2727
pub local_instance: RefCell<Option<Rc<Instance>>>,
2828
/// Does every instance match the filter options provided via the CLI?
29-
pub matches_cli_filter: RefCell<bool>,
29+
pub matches_cli_filter: bool,
3030
/// The name of the dependency
31-
pub name_internal: String,
31+
pub internal_name: String,
3232
/// The version to pin all instances to when variant is `Pinned`
3333
pub pinned_specifier: Option<Specifier>,
3434
/// package.json files developed in the monorepo when variant is `SnappedTo`
@@ -39,7 +39,7 @@ pub struct Dependency {
3939

4040
impl Dependency {
4141
pub fn new(
42-
name_internal: String,
42+
internal_name: String,
4343
variant: VersionGroupVariant,
4444
pinned_specifier: Option<Specifier>,
4545
snapped_to_packages: Option<Vec<Rc<RefCell<PackageJson>>>>,
@@ -48,8 +48,8 @@ impl Dependency {
4848
expected: RefCell::new(None),
4949
instances: RefCell::new(vec![]),
5050
local_instance: RefCell::new(None),
51-
matches_cli_filter: RefCell::new(false),
52-
name_internal,
51+
matches_cli_filter: true,
52+
internal_name,
5353
pinned_specifier,
5454
snapped_to_packages,
5555
variant,
@@ -68,7 +68,7 @@ impl Dependency {
6868
.instances
6969
.borrow()
7070
.iter()
71-
.map(|instance| instance.actual_specifier.clone())
71+
.map(|instance| instance.descriptor.specifier.clone())
7272
.collect();
7373
set.into_iter().collect()
7474
}
@@ -95,8 +95,8 @@ impl Dependency {
9595
pub fn get_instances_by_specifier(&self) -> BTreeMap<String, Vec<Rc<Instance>>> {
9696
let mut map = BTreeMap::new();
9797
for instance in self.instances.borrow().iter() {
98-
let specifier = instance.actual_specifier.unwrap();
99-
map.entry(specifier).or_insert_with(Vec::new).push(Rc::clone(instance));
98+
let raw = instance.descriptor.specifier.get_raw();
99+
map.entry(raw).or_insert_with(Vec::new).push(Rc::clone(instance));
100100
}
101101
map
102102
}
@@ -111,30 +111,32 @@ impl Dependency {
111111
.local_instance
112112
.borrow()
113113
.as_ref()
114-
.map(|instance| instance.actual_specifier.clone())
114+
.map(|instance| instance.descriptor.specifier.clone())
115115
}
116116

117117
pub fn has_local_instance(&self) -> bool {
118118
self.local_instance.borrow().is_some()
119119
}
120120

121121
pub fn has_local_instance_with_invalid_specifier(&self) -> bool {
122-
self.has_local_instance()
123-
&& !matches!(
124-
self.get_local_specifier().unwrap(),
125-
Specifier::Semver(Semver::Simple(SimpleSemver::Exact(_)))
126-
)
122+
self.get_local_specifier().is_some_and(|local| {
123+
if let Specifier::BasicSemver(semver) = local {
124+
!matches!(semver.range_variant, SemverRange::Exact)
125+
} else {
126+
true
127+
}
128+
})
127129
}
128130

129131
/// Does every instance in this group have a specifier which is exactly the
130132
/// same?
131133
pub fn every_specifier_is_already_identical(&self) -> bool {
132-
if let Some(first_actual) = self.instances.borrow().first().map(|instance| &instance.actual_specifier) {
134+
if let Some(first_actual) = self.instances.borrow().first().map(|instance| &instance.descriptor.specifier) {
133135
self
134136
.instances
135137
.borrow()
136138
.iter()
137-
.all(|instance| instance.actual_specifier == *first_actual)
139+
.all(|instance| instance.descriptor.specifier == *first_actual)
138140
} else {
139141
false
140142
}
@@ -148,15 +150,13 @@ impl Dependency {
148150
.instances
149151
.borrow()
150152
.iter()
151-
.filter(|instance| instance.actual_specifier.is_simple_semver())
152-
.map(|instance| instance.actual_specifier.clone())
153+
.filter(|instance| instance.descriptor.specifier.is_basic_semver())
154+
.map(|instance| instance.descriptor.specifier.clone())
153155
.fold(None, |preferred, specifier| match preferred {
154156
None => Some(specifier),
155157
Some(preferred) => {
156-
let a = specifier.get_orderable();
157-
let b = preferred.get_orderable();
158-
if a.cmp(&b) == preferred_order {
159-
Some(specifier.clone())
158+
if specifier.cmp(&preferred) == preferred_order {
159+
Some(specifier)
160160
} else {
161161
Some(preferred)
162162
}
@@ -175,10 +175,10 @@ impl Dependency {
175175
pub fn get_snapped_to_specifier(&self, every_instance_in_the_project: &[Rc<Instance>]) -> Option<Specifier> {
176176
if let Some(snapped_to_packages) = &self.snapped_to_packages {
177177
for instance in every_instance_in_the_project {
178-
if *instance.name_internal.borrow() == *self.name_internal {
178+
if *instance.internal_name == *self.internal_name {
179179
for snapped_to_package in snapped_to_packages {
180180
if instance.package.borrow().name == snapped_to_package.borrow().name {
181-
return Some(instance.actual_specifier.clone());
181+
return Some(instance.descriptor.specifier.clone());
182182
}
183183
}
184184
}
@@ -203,13 +203,13 @@ impl Dependency {
203203
if matches!(*b.state.borrow(), InstanceState::Valid(_)) && !matches!(*a.state.borrow(), InstanceState::Valid(_)) {
204204
return Ordering::Greater;
205205
}
206-
if matches!(&a.actual_specifier, Specifier::None) {
206+
if matches!(&a.descriptor.specifier, Specifier::None) {
207207
return Ordering::Greater;
208208
}
209-
if matches!(&b.actual_specifier, Specifier::None) {
209+
if matches!(&b.descriptor.specifier, Specifier::None) {
210210
return Ordering::Less;
211211
}
212-
let specifier_order = b.actual_specifier.unwrap().cmp(&a.actual_specifier.unwrap());
212+
let specifier_order = b.descriptor.specifier.cmp(&a.descriptor.specifier);
213213
if matches!(specifier_order, Ordering::Equal) {
214214
a.package.borrow().name.cmp(&b.package.borrow().name)
215215
} else {

src/effects/fix.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use {
1111
/// Run the fix command side effects
1212
pub fn run(ctx: Context) -> Context {
1313
let ui = Ui { ctx: &ctx };
14-
let has_cli_filter = ctx.config.cli.filter.is_some();
1514
let running_multiple_commands = ctx.config.cli.inspect_mismatches && ctx.config.cli.inspect_formatting;
1615

1716
if ctx.config.cli.inspect_mismatches {
@@ -24,9 +23,9 @@ pub fn run(ctx: Context) -> Context {
2423
let mut suspect = 0;
2524

2625
ctx.instances.iter().for_each(|instance| {
27-
let name_internal = &instance.name_internal.borrow();
26+
let internal_name = &instance.internal_name;
2827

29-
if has_cli_filter && !*instance.matches_cli_filter.borrow() {
28+
if !instance.matches_cli_filter {
3029
return;
3130
}
3231

@@ -47,17 +46,17 @@ pub fn run(ctx: Context) -> Context {
4746
match variant {
4847
FixableInstance::IsBanned => instance.remove(),
4948
_ => {
50-
let actual = instance.actual_specifier.unwrap().red();
49+
let actual = instance.descriptor.specifier.get_raw().red();
5150
let arrow = ui.dim_right_arrow();
52-
let expected = instance.expected_specifier.borrow().as_ref().unwrap().unwrap().green();
53-
info!("{name_internal} {actual} {arrow} {expected} {location} {state_link}");
51+
let expected = instance.expected_specifier.borrow().as_ref().unwrap().get_raw().green();
52+
info!("{internal_name} {actual} {arrow} {expected} {location} {state_link}");
5453
instance.package.borrow().copy_expected_specifier(instance);
5554
}
5655
}
5756
}
5857
InvalidInstance::Conflict(_) | InvalidInstance::Unfixable(_) => {
5958
unfixable += 1;
60-
warn!("Unfixable: {name_internal} {location} {state_link}");
59+
warn!("Unfixable: {internal_name} {location} {state_link}");
6160
}
6261
},
6362
InstanceState::Suspect(variant) => match variant {
@@ -67,7 +66,7 @@ pub fn run(ctx: Context) -> Context {
6766
| SuspectInstance::RefuseToSnapLocal
6867
| SuspectInstance::InvalidLocalVersion => {
6968
suspect += 1;
70-
warn!("Suspect: {name_internal} {location} {state_link}");
69+
warn!("Suspect: {internal_name} {location} {state_link}");
7170
}
7271
},
7372
}

src/effects/lint.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,14 @@ use crate::{context::Context, effects::ui::Ui, instance_state::InstanceState, ve
33
/// Run the lint command side effects
44
pub fn run(ctx: Context) -> Context {
55
let ui = Ui { ctx: &ctx };
6-
let has_cli_filter = ctx.config.cli.filter.is_some();
76
let running_multiple_commands = ctx.config.cli.inspect_mismatches && ctx.config.cli.inspect_formatting;
87

98
if ctx.config.cli.inspect_mismatches {
109
if running_multiple_commands {
1110
ui.print_command_header("SEMVER RANGES AND VERSION MISMATCHES");
1211
}
1312
ctx.version_groups.iter().for_each(|group| {
14-
if has_cli_filter && !*group.matches_cli_filter.borrow() {
13+
if !group.matches_cli_filter {
1514
return;
1615
}
1716
ui.print_group_header(group);
@@ -25,13 +24,13 @@ pub fn run(ctx: Context) -> Context {
2524
return;
2625
}
2726
group.for_each_dependency(&ctx.config.cli.sort, |dependency| {
28-
if has_cli_filter && !*dependency.matches_cli_filter.borrow() {
27+
if !dependency.matches_cli_filter {
2928
return;
3029
}
3130
ui.print_dependency(dependency, &group.variant);
3231
dependency.for_each_instance(|instance| {
3332
if !matches!(*instance.state.borrow(), InstanceState::Valid(_)) || ctx.config.cli.show_instances {
34-
if has_cli_filter && !*instance.matches_cli_filter.borrow() {
33+
if !instance.matches_cli_filter {
3534
return;
3635
}
3736
ui.print_instance(instance, &group.variant);

src/effects/ui.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ impl Ui<'_> {
6868
};
6969
let instances_len = dependency.instances.borrow().len();
7070
let count = self.count_column(instances_len);
71-
let name = &dependency.name_internal;
71+
let name = &dependency.internal_name;
7272
let name = if self.ctx.config.cli.show_hints && dependency.local_instance.borrow().is_some() {
7373
let local_hint = "(local)".blue();
7474
format!("{name} {local_hint}").normal()
@@ -79,7 +79,7 @@ impl Ui<'_> {
7979
.expected
8080
.borrow()
8181
.clone()
82-
.map(|expected| expected.unwrap())
82+
.map(|expected| expected.get_raw())
8383
.unwrap_or("".to_string())
8484
.dimmed();
8585

@@ -241,7 +241,12 @@ impl Ui<'_> {
241241
} else {
242242
state_link
243243
};
244-
let actual = instance.actual_specifier.unwrap();
244+
let actual = instance.descriptor.specifier.get_raw();
245+
let actual = if actual.is_empty() {
246+
"VERSION_IS_MISSING".yellow()
247+
} else {
248+
actual.normal()
249+
};
245250
let location = self.instance_location(instance).dimmed();
246251
match &state {
247252
InstanceState::Valid(variant) => {
@@ -311,7 +316,7 @@ impl Ui<'_> {
311316
FixableInstance::SemverRangeMismatch => {
312317
let arrow = self.dim_right_arrow();
313318
let expected = instance.get_specifier_with_preferred_semver_range();
314-
let expected = expected.unwrap().unwrap();
319+
let expected = expected.unwrap().get_raw();
315320
let expected = expected.green();
316321
info!(" {icon} {actual} {arrow} {expected} {location} {state_link}");
317322
}

0 commit comments

Comments
 (0)