use std::fmt::{Debug, Display};
use std::path::PathBuf;
use super::CodeQLExtractor;
pub const CODEQL_LANGUAGES: [(&str, &str); 16] = [
("actions", "GitHub Actions"),
("c", "C/C++"),
("cpp", "C/C++"),
("c-cpp", "C/C++"),
("csharp", "C#"),
("java", "Java/Kotlin"),
("kotlin", "Java/Kotlin"),
("java-kotlin", "Java/Kotlin"),
("javascript", "Javascript/Typescript"),
("typescript", "Javascript/Typescript"),
("javascript-typescript", "Javascript/Typescript"),
("python", "Python"),
("go", "Go"),
("rust", "Rust"),
("ruby", "Rudy"),
("swift", "Swift"),
];
#[derive(Debug, Clone, Default)]
pub struct CodeQLLanguages {
languages: Vec<CodeQLLanguage>,
}
impl CodeQLLanguages {
pub fn new(languages: Vec<CodeQLLanguage>) -> Self {
CodeQLLanguages { languages }
}
pub fn check(&self, language: impl Into<String>) -> bool {
let language = language.into();
for lang in &self.languages {
if lang.extractor.languages().contains(&language) {
return true;
}
}
false
}
pub fn get_all(&self) -> &Vec<CodeQLLanguage> {
&self.languages
}
pub fn get_languages(&self) -> Vec<CodeQLLanguage> {
self.languages
.iter()
.filter(|l| !l.is_secondary())
.cloned()
.collect()
}
pub fn get_secondary(&self) -> Vec<CodeQLLanguage> {
self.languages
.iter()
.filter(|l| l.is_secondary())
.cloned()
.collect()
}
}
#[derive(Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct CodeQLLanguage {
name: String,
extractor: CodeQLExtractor,
}
impl CodeQLLanguage {
pub fn pretty(&self) -> &str {
if CODEQL_LANGUAGES.iter().any(|(lang, _)| lang == &self.name) {
CODEQL_LANGUAGES
.iter()
.find(|(lang, _)| lang == &self.name)
.unwrap()
.1
} else if !self.extractor.name.is_empty() {
&self.extractor.name
} else {
&self.name
}
}
pub fn language(&self) -> &str {
if !self.extractor.name.is_empty() {
&self.extractor.name
} else {
&self.name
}
}
pub fn is_secondary(&self) -> bool {
matches!(
self.extractor.name.as_str(),
"properties" | "csv" | "yaml" | "xml" | "html"
)
}
}
impl Display for CodeQLLanguage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.pretty())
}
}
impl Debug for CodeQLLanguage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.is_secondary() {
write!(f, "Secondary('{}')", self.pretty())
} else {
write!(f, "Primary('{}')", self.pretty())
}
}
}
impl From<(String, PathBuf)> for CodeQLLanguage {
fn from(value: (String, PathBuf)) -> Self {
CodeQLLanguage {
name: value.0.clone(),
extractor: CodeQLExtractor::load_path(value.1.clone()).unwrap(),
}
}
}
impl From<String> for CodeQLLanguage {
fn from(value: String) -> Self {
CodeQLLanguage {
name: value.clone(),
extractor: CodeQLExtractor::default(),
}
}
}
impl From<&str> for CodeQLLanguage {
fn from(value: &str) -> Self {
CodeQLLanguage {
name: value.to_string(),
extractor: CodeQLExtractor::default(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_languages() {
let language = CodeQLLanguage::from("cpp".to_string());
assert_eq!(language.language(), "cpp");
assert_eq!(language.pretty(), "C/C++");
let language = CodeQLLanguage::from("actions");
assert_eq!(language.language(), "actions");
assert_eq!(language.pretty(), "GitHub Actions");
}
#[test]
fn test_unsupported() {
let language = CodeQLLanguage::from("iac");
assert_eq!(language.language(), "iac");
assert_eq!(language.pretty(), "iac");
}
}