1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
use std::cmp::Ordering;
#[derive(Clone, Debug)]
pub enum InstanceState {
Unknown,
Valid(ValidInstance),
Invalid(InvalidInstance),
Suspect(SuspectInstance),
}
impl InstanceState {
#[cfg(test)]
pub fn valid(state: ValidInstance) -> Self {
InstanceState::Valid(state)
}
#[cfg(test)]
pub fn suspect(state: SuspectInstance) -> Self {
InstanceState::Suspect(state)
}
#[cfg(test)]
pub fn fixable(state: FixableInstance) -> Self {
InstanceState::Invalid(InvalidInstance::Fixable(state))
}
#[cfg(test)]
pub fn conflict(state: SemverGroupAndVersionConflict) -> Self {
InstanceState::Invalid(InvalidInstance::Conflict(state))
}
#[cfg(test)]
pub fn unfixable(state: UnfixableInstance) -> Self {
InstanceState::Invalid(InvalidInstance::Unfixable(state))
}
pub fn get_name(&self) -> String {
match self {
InstanceState::Unknown => "Unknown".to_string(),
InstanceState::Valid(variant) => format!("{variant:?}"),
InstanceState::Invalid(variant) => match variant {
InvalidInstance::Fixable(variant) => format!("{variant:?}"),
InvalidInstance::Conflict(variant) => format!("{variant:?}"),
InvalidInstance::Unfixable(variant) => format!("{variant:?}"),
},
InstanceState::Suspect(variant) => format!("{variant:?}"),
}
}
pub fn get_severity(&self) -> u8 {
match self {
InstanceState::Unknown => 0,
InstanceState::Valid(_) => 1,
InstanceState::Invalid(_) => 2,
InstanceState::Suspect(_) => 3,
}
}
pub fn is_valid(&self) -> bool {
matches!(self, InstanceState::Valid(_))
}
pub fn is_invalid(&self) -> bool {
matches!(self, InstanceState::Invalid(_))
}
pub fn is_suspect(&self) -> bool {
matches!(self, InstanceState::Suspect(_))
}
pub fn is_fixable(&self) -> bool {
matches!(self, InstanceState::Invalid(InvalidInstance::Fixable(_)))
}
pub fn is_banned(&self) -> bool {
matches!(self, InstanceState::Invalid(InvalidInstance::Fixable(FixableInstance::IsBanned)))
}
pub fn is_unfixable(&self) -> bool {
matches!(self, InstanceState::Invalid(InvalidInstance::Unfixable(_)))
}
pub fn is_outdated(&self) -> bool {
matches!(
self,
InstanceState::Invalid(InvalidInstance::Fixable(FixableInstance::DiffersToNpmRegistry))
)
}
}
impl PartialEq for InstanceState {
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl Eq for InstanceState {}
impl PartialOrd for InstanceState {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for InstanceState {
fn cmp(&self, other: &Self) -> Ordering {
self.get_severity().cmp(&other.get_severity())
}
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum ValidInstance {
/// - ✓ Instance is configured to be ignored by Synopkg
IsIgnored,
/// - ✓ Instance is a local package and its version is valid
IsLocalAndValid,
/// - ✓ Instance identical to the version of its locally-developed package
/// - ✓ Instance matches its semver group
IsIdenticalToLocal,
/// - ✓ Instance matches the version of its locally-developed package
/// - ✓ Instance matches its semver group
/// - ! Considered a loose match we should highlight
SatisfiesLocal,
/// - ✓ Instance identical to highest/lowest semver in its group
/// - ✓ Instance matches its semver group
IsHighestOrLowestSemver,
/// - ✓ Instance has same semver number as highest/lowest semver in its group
/// - ✓ Instance matches its semver group
/// - ✓ Range preferred by semver group satisfies the highest/lowest semver
/// - ! Considered a loose match we should highlight
SatisfiesHighestOrLowestSemver,
/// - ! No Instances are simple semver
/// - ✓ Instance identical to every other instance in its version group
IsNonSemverButIdentical,
/// - ✓ Instance identical to its pinned version group
/// - ✓ Instance matches its semver group
IsIdenticalToPin,
/// - ✓ Instance matches its same range group
/// - ✓ Instance matches its semver group
SatisfiesSameRangeGroup,
/// - ✓ Instance identical to a matching snapTo instance
/// - ✓ Instance matches its semver group
IsIdenticalToSnapTarget,
/// - ✓ Instance has same semver number as matching snapTo instance
/// - ✓ Instance matches its semver group
/// - ✓ Range preferred by semver group satisfies the matching snapTo instance
/// - ! Considered a loose match we should highlight
SatisfiesSnapTarget,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum InvalidInstance {
Fixable(FixableInstance),
Unfixable(UnfixableInstance),
Conflict(SemverGroupAndVersionConflict),
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum FixableInstance {
/// - ✘ Instance is in a banned version group
IsBanned,
/// - ✘ Instance mismatches the version of its locally-developed package
DiffersToLocal,
/// - ✘ Instance mismatches highest/lowest semver in its group
DiffersToHighestOrLowestSemver,
/// - ✘ Instance is older than highest semver published to the registry
DiffersToNpmRegistry,
/// - ✘ Instance mismatches the matching snapTo instance
DiffersToSnapTarget,
/// - ✘ Instance mismatches its pinned version group
DiffersToPin,
/// - ✓ Instance has same semver number as highest/lowest semver in its group
/// - ✘ Instance mismatches its semver group
/// - ✓ Range preferred by semver group satisfies the highest/lowest semver
/// - ✓ Fixing the semver range satisfy both groups
SemverRangeMismatch,
/// - ✓ Instance has same semver number as its pinned version group
/// - ✓ Instance matches its semver group
/// - ! The semver group requires a range which is different to the pinned
/// version
/// - ! Pinned version wins
PinOverridesSemverRange,
/// - ✓ Instance has same semver number as its pinned version group
/// - ✘ Instance mismatches its semver group
/// - ! The semver group requires a range which is different to the pinned
/// version
/// - ! Pinned version wins
PinOverridesSemverRangeMismatch,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum UnfixableInstance {
/// - ✘ Instance depends on a local package whose package.json version is not
/// exact semver
/// - ? We can't know what the version should be
DependsOnInvalidLocalPackage,
/// - ✘ Instance mismatches others in its group
/// - ✘ One or more Instances are not simple semver
/// - ? We can't know what's right or what isn't
NonSemverMismatch,
/// - ✘ Instance mismatches its same range group
/// - ? Instance has no semver group
/// - ? We can't know what range the user wants and have to ask them
SameRangeMismatch,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum SemverGroupAndVersionConflict {
/// - ✓ Instance has same semver number as highest/lowest semver in its group
/// - ✓ Instance matches its semver group
/// - ✘ Range preferred by semver group will not satisfy the highest/lowest
/// semver
/// - ? We can't know whether the incompatible range matters or not and have
/// to ask
MatchConflictsWithHighestOrLowestSemver,
/// - ✓ Instance has same semver number as highest/lowest semver in its group
/// - ✘ Instance mismatches its semver group
/// - ✘ Range preferred by semver group will not satisfy the highest/lowest
/// semver
/// - ? We can't know whether the incompatible range matters or not and have
/// to ask
MismatchConflictsWithHighestOrLowestSemver,
/// - ✓ Instance has same semver number as the matching snapTo instance
/// - ✓ Instance matches its semver group
/// - ✘ Range preferred by semver group will not satisfy the matching snapTo
/// instance
/// - ? We can't know whether the incompatible range matters or not and have
/// to ask
MatchConflictsWithSnapTarget,
/// - ✓ Instance has same semver number as the matching snapTo instance
/// - ✘ Instance mismatches its semver group
/// - ✘ Range preferred by semver group will not satisfy the matching snapTo
/// instance
/// - ? We can't know whether the incompatible range matters or not and have
/// to ask
MismatchConflictsWithSnapTarget,
/// - ✓ Instance has same semver number as local instance in its group
/// - ✓ Instance matches its semver group
/// - ✘ Range preferred by semver group will not satisfy the local instance
/// - ? We can't know whether the incompatible range matters or not and have
/// to ask
MatchConflictsWithLocal,
/// - ✓ Instance has same semver number as local instance
/// - ✘ Instance mismatches its semver group
/// - ✘ Range preferred by semver group will not satisfy the local instance
/// - ? We can't know whether the incompatible range matters or not and have
/// to ask
MismatchConflictsWithLocal,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum SuspectInstance {
/// - ✘ Local Instance is in a banned version group
/// - ✘ Misconfiguration: Synopkg refuses to change local dependency
/// specifiers
RefuseToBanLocal,
/// - ✘ Local Instance mismatches its pinned version group
/// - ✘ Misconfiguration: Synopkg refuses to change local dependency
/// specifiers
RefuseToPinLocal,
/// - ✘ Local Instance is in a snapped to version group
/// - ✘ An Instance of this dependency was found in the snapped to package
/// - ✘ Misconfiguration: Synopkg refuses to change local dependency
/// specifiers
RefuseToSnapLocal,
/// - ! Local Instance has no version property
/// - ! Not an error on its own unless an instance of it mismatches
InvalidLocalVersion,
/// - ✓ Instance is in a snapped to version group
/// - ✘ An instance of the same dependency was not found in any of the snapped
/// to packages
/// - ! This is a misconfiguration resulting in this instance being orphaned
DependsOnMissingSnapTarget,
}