licensebat_core/dependency.rs
1use serde::{Deserialize, Serialize};
2use std::fmt::Debug;
3
4/// Generic and plain dependency without any extra information.
5/// Language agnostic, just holds the name and the version and some other information.
6#[derive(Serialize, Deserialize, Debug, Clone, Eq, Ord, PartialEq, PartialOrd, Default)]
7pub struct Dependency {
8 /// Dependency name
9 pub name: String,
10 /// Dependency version
11 pub version: String,
12 /// True if the dependency is a dev dependency, false otherwise. Null if we cannot determine it.
13 pub is_dev: Option<bool>,
14 /// True if the dependency is an optional dependency, false otherwise. Null if we cannot determine it.
15 pub is_optional: Option<bool>,
16}
17
18impl Dependency {
19 /// Creates a new dependency without dev or optional information.
20 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
21 Self {
22 name: name.into(),
23 version: version.into(),
24 is_dev: None,
25 is_optional: None,
26 }
27 }
28}
29
30/// A dependency that has been retrieved from its source.
31/// The source can be anything, from a third party API (i.e. npm, pub.dev or crates.io APIs) to the file system.
32/// It holds information about licenses, errors while validating...
33#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Default)]
34pub struct RetrievedDependency {
35 /// Dependency name.
36 pub name: String,
37 /// Dependency version.
38 pub version: String,
39 /// Dependency type (npm, dart, rust, go, python...)
40 pub dependency_type: String,
41 /// Url of the dependency if available.
42 #[serde(skip_serializing_if = "Option::is_none")]
43 pub url: Option<String>,
44 /// List of licenses of the dependency.
45 #[serde(skip_serializing_if = "Option::is_none")]
46 pub licenses: Option<Vec<String>>,
47 /// Set to true if the dependency has been validated against the licrc.
48 pub validated: bool,
49 /// Indicates if the license is valid for our project or not according to our .licrc configuration file.
50 pub is_valid: bool,
51 /// Indicates if the dependency has been ignored according to our .licrc configuration file.
52 pub is_ignored: bool,
53 /// Contains information about any error that may have happened during the validation process.
54 #[serde(skip_serializing_if = "Option::is_none")]
55 pub error: Option<String>,
56 /// Comments about the license validation process.
57 #[serde(skip_serializing_if = "Option::is_none")]
58 pub comment: Option<Comment>,
59 /// In cases where the retriever makes some sort of estimate about the license, this field will contain the suggested licenses.
60 pub suggested_licenses: Option<Vec<(String, f32)>>,
61 /// Indicates if the dependency is a dev dependency or not. This can be null if we cannot determine it.
62 #[serde(skip_serializing_if = "Option::is_none")]
63 pub is_dev: Option<bool>,
64 /// Indicates if the dependency is an optional dependency or not. This can be null if we cannot determine it.
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub is_optional: Option<bool>,
67}
68
69impl RetrievedDependency {
70 /// Creates a new `RetrievedDependency` with the given parameters.
71 /// Note that some properties will be automatically set depending on the other ones.
72 /// For example, if the `licenses` parameter is `None`, the `is_valid` property will be set to `false`.
73 /// Use the default method if you just want to create an instance with all the defaults.
74 /// This method it's intended to be used once you have retrieved the dependency from its source (i.e. npm, github, etc).
75 #[allow(clippy::too_many_arguments)]
76 #[must_use]
77 pub fn new(
78 name: String,
79 version: String,
80 dependency_type: String,
81 url: Option<String>,
82 licenses: Option<Vec<String>>,
83 error: Option<String>,
84 comment: Option<Comment>,
85 suggested_licenses: Option<Vec<(String, f32)>>,
86 is_dev: Option<bool>,
87 is_optional: Option<bool>,
88 ) -> Self {
89 let has_licenses = licenses.is_some();
90
91 Self {
92 name,
93 version,
94 dependency_type,
95 url,
96 licenses,
97 validated: false,
98 is_valid: has_licenses && error.is_none(),
99 is_ignored: false,
100 error: error.or_else(|| {
101 if has_licenses {
102 None
103 } else {
104 Some("No License".to_owned())
105 }
106 }),
107 comment: comment.or_else(|| {
108 if has_licenses {
109 None
110 } else {
111 Some(Comment::removable("Consider manually checking this dependency's license. Remember this: https://choosealicense.com/no-permission/ and ignore it if you feel confident about it to avoid this warning."))
112 }
113 }),
114 suggested_licenses,
115 is_dev,
116 is_optional,
117 }
118 }
119}
120
121/// A comment to be added in a [`RetrievedDependency`] once it has been retrieved or validated.
122/// It normally adds information about what went wrong.
123#[derive(Serialize, Deserialize, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Clone)]
124pub struct Comment {
125 /// The comment text.
126 pub text: String,
127 /// If true, the comment won't be shown if the dependency is valid.
128 pub remove_when_valid: bool,
129}
130
131impl Comment {
132 /// Builds a removable comment.
133 /// This basically mean it won't be shown if the dependency is flagged as valid.
134 pub fn removable(text: impl Into<String>) -> Self {
135 Self {
136 text: text.into(),
137 remove_when_valid: true,
138 }
139 }
140
141 /// Builds a non removable comment.
142 /// This comment will be shown no matter if the dependency is valid or not.
143 pub fn non_removable(text: impl Into<String>) -> Self {
144 Self {
145 text: text.into(),
146 remove_when_valid: false,
147 }
148 }
149}