1use crate::BackendDependency;
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7#[non_exhaustive]
8pub enum SourceLanguage {
9 TypeScript,
11 Python,
13}
14
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17#[non_exhaustive]
18pub enum ApiNamespace {
19 Json,
21 Regex,
23 Random,
25 Http,
27 DateTime,
29 Url,
31}
32
33#[derive(Clone, Copy, Debug, Eq, PartialEq)]
35#[non_exhaustive]
36pub enum ReceiverKind {
37 FreeFunction,
39 Namespace,
41 Instance,
43}
44
45#[derive(Clone, Copy, Debug, Eq, PartialEq)]
47#[non_exhaustive]
48pub enum ApiShape {
49 Call,
51 Constructor,
53 Property,
55}
56
57#[derive(Clone, Copy, Debug, Eq, PartialEq)]
59#[non_exhaustive]
60pub enum ArgShape {
61 OneValue,
63 OneString,
65 TwoStrings,
67 TwoInts,
69 OneNumber,
71 None,
73}
74
75#[derive(Clone, Copy, Debug, Eq, PartialEq)]
77#[non_exhaustive]
78pub enum ReturnShape {
79 Bool,
81 String,
83 Float,
85 Int,
87 Contextual,
89}
90
91#[derive(Clone, Copy, Debug, Eq, PartialEq)]
93#[non_exhaustive]
94pub enum EffectKind {
95 Pure,
97 Random,
99 Io,
101}
102
103#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
105#[non_exhaustive]
106pub enum RuleId {
107 TsJsonStringify,
109 TsJsonParse,
111 TsRegExpTest,
113 TsMathRandom,
115 TsFetch,
117 TsDateNow,
119 TsDateToIsoString,
121 TsUrlField,
123 TsStructuredClone,
125 TsPromiseStatic,
127 TsPrimitiveCast,
129 TsSymbol,
131 TsMathNumeric,
133 TsNumberPredicate,
135 TsNumberParseFloat,
137 TsNumberParseInt,
139 TsObjectStatic,
141 TsArrayStatic,
143 TsBufferStatic,
146 TsMapHas,
148 TsMapGet,
150 TsMapMutation,
152 TsMapProjection,
154 TsSetHas,
156 TsSetMutation,
158 TsSetProjection,
160 PyJsonDumps,
162 PyJsonLoads,
164 PyReSearch,
166 PyReMatch,
168 PyReFullMatch,
170 PyRandomRandom,
172 PyRandomRandInt,
174 PyRandomChoice,
176 PyRequestsGet,
178 PyDateTimeNow,
180 PyDateTimeFromTimestamp,
182 PyUrlparseField,
184}
185
186impl RuleId {
187 #[must_use]
189 pub const fn backend_dependency(self) -> Option<BackendDependency> {
190 match self {
191 Self::TsJsonStringify | Self::TsJsonParse | Self::PyJsonDumps | Self::PyJsonLoads => {
192 Some(BackendDependency::SerdeJson)
193 }
194 Self::TsRegExpTest | Self::PyReSearch | Self::PyReMatch | Self::PyReFullMatch => {
195 Some(BackendDependency::Regex)
196 }
197 Self::TsMathRandom
198 | Self::PyRandomRandom
199 | Self::PyRandomRandInt
200 | Self::PyRandomChoice => Some(BackendDependency::Rand),
201 Self::TsFetch | Self::PyRequestsGet => Some(BackendDependency::Reqwest),
202 Self::TsDateNow
203 | Self::TsDateToIsoString
204 | Self::PyDateTimeNow
205 | Self::PyDateTimeFromTimestamp => Some(BackendDependency::Chrono),
206 Self::TsUrlField | Self::PyUrlparseField => Some(BackendDependency::Url),
207 Self::TsStructuredClone
208 | Self::TsPromiseStatic
209 | Self::TsPrimitiveCast
210 | Self::TsSymbol
211 | Self::TsMathNumeric
212 | Self::TsNumberPredicate
213 | Self::TsNumberParseFloat
214 | Self::TsNumberParseInt
215 | Self::TsObjectStatic
216 | Self::TsArrayStatic
217 | Self::TsBufferStatic
218 | Self::TsMapHas
219 | Self::TsMapGet
220 | Self::TsMapMutation
221 | Self::TsMapProjection
222 | Self::TsSetHas
223 | Self::TsSetMutation
224 | Self::TsSetProjection => None,
225 }
226 }
227
228 #[must_use]
230 pub const fn source_api(self) -> &'static str {
231 match self {
232 Self::TsJsonStringify => "JSON.stringify",
233 Self::TsJsonParse => "JSON.parse",
234 Self::TsRegExpTest => "RegExp.test",
235 Self::TsMathRandom => "Math.random",
236 Self::TsFetch => "fetch",
237 Self::TsDateNow => "Date.now",
238 Self::TsDateToIsoString => "Date.toISOString",
239 Self::TsUrlField => "URL field access",
240 Self::TsStructuredClone => "structuredClone",
241 Self::TsPromiseStatic => "Promise static method",
242 Self::TsPrimitiveCast => "primitive conversion",
243 Self::TsSymbol => "Symbol",
244 Self::TsMathNumeric => "Math numeric method",
245 Self::TsNumberPredicate => "Number predicate",
246 Self::TsNumberParseFloat => "Number.parseFloat",
247 Self::TsNumberParseInt => "Number.parseInt",
248 Self::TsObjectStatic => "Object static method",
249 Self::TsArrayStatic => "Array static method",
250 Self::TsBufferStatic => "Buffer static method",
251 Self::TsMapHas => "Map.has",
252 Self::TsMapGet => "Map.get",
253 Self::TsMapMutation => "Map mutation method",
254 Self::TsMapProjection => "Map projection method",
255 Self::TsSetHas => "Set.has",
256 Self::TsSetMutation => "Set mutation method",
257 Self::TsSetProjection => "Set projection method",
258 Self::PyJsonDumps => "json.dumps",
259 Self::PyJsonLoads => "json.loads",
260 Self::PyReSearch => "re.search",
261 Self::PyReMatch => "re.match",
262 Self::PyReFullMatch => "re.fullmatch",
263 Self::PyRandomRandom => "random.random",
264 Self::PyRandomRandInt => "random.randint",
265 Self::PyRandomChoice => "random.choice",
266 Self::PyRequestsGet => "requests.get",
267 Self::PyDateTimeNow => "datetime.datetime.now",
268 Self::PyDateTimeFromTimestamp => "datetime.datetime.fromtimestamp",
269 Self::PyUrlparseField => "urllib.parse.urlparse field access",
270 }
271 }
272}
273
274#[cfg(test)]
275mod tests {
276 use super::*;
277
278 #[test]
281 fn dependency_backed_date_and_url_rules_report_metadata() {
282 let cases = [
283 (RuleId::TsDateNow, BackendDependency::Chrono, "Date.now"),
284 (
285 RuleId::TsDateToIsoString,
286 BackendDependency::Chrono,
287 "Date.toISOString",
288 ),
289 (
290 RuleId::PyDateTimeNow,
291 BackendDependency::Chrono,
292 "datetime.datetime.now",
293 ),
294 (
295 RuleId::PyDateTimeFromTimestamp,
296 BackendDependency::Chrono,
297 "datetime.datetime.fromtimestamp",
298 ),
299 (
300 RuleId::TsUrlField,
301 BackendDependency::Url,
302 "URL field access",
303 ),
304 (
305 RuleId::PyUrlparseField,
306 BackendDependency::Url,
307 "urllib.parse.urlparse field access",
308 ),
309 ];
310
311 for (rule, dependency, source_api) in cases {
312 assert_eq!(rule.backend_dependency(), Some(dependency));
313 assert_eq!(rule.source_api(), source_api);
314 }
315 }
316}