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}