use super::spec::{DEFAULT_TOOL_TIMEOUT_SECS, LanguageSupport, ToolSpec};
static JVM_VENDORED_DIRS: &[&str] = &["build", ".gradle", "target"];
pub static RUFF: ToolSpec = ToolSpec {
name: "ruff",
command: &["ruff", "check", "--output-format", "json"],
local_paths: &["venv/bin/ruff", ".venv/bin/ruff"],
config_files: &["pyproject.toml", "ruff.toml", ".ruff.toml"],
config_flag: None,
output_format: "json",
diagnostics_stream: "stdout",
timeout_secs: DEFAULT_TOOL_TIMEOUT_SECS,
timeout_context: None,
establishes_compilation: false,
serial_in_repository: false,
accepts_files: true,
};
pub static ESLINT: ToolSpec = ToolSpec {
name: "eslint",
command: &["eslint", "--format", "json"],
local_paths: &["node_modules/.bin/eslint"],
config_files: &[
"eslint.config.js",
"eslint.config.mjs",
"eslint.config.cjs",
".eslintrc",
".eslintrc.js",
".eslintrc.cjs",
".eslintrc.json",
".eslintrc.yml",
".eslintrc.yaml",
],
config_flag: None,
output_format: "json",
diagnostics_stream: "stdout",
timeout_secs: DEFAULT_TOOL_TIMEOUT_SECS,
timeout_context: None,
establishes_compilation: false,
serial_in_repository: false,
accepts_files: true,
};
pub static TSC: ToolSpec = ToolSpec {
name: "tsc",
command: &["tsc", "--noEmit", "--pretty", "false"],
local_paths: &["node_modules/.bin/tsc"],
config_files: &["tsconfig.json"],
config_flag: None,
output_format: "tsc",
diagnostics_stream: "stdout",
timeout_secs: DEFAULT_TOOL_TIMEOUT_SECS,
timeout_context: None,
establishes_compilation: true,
serial_in_repository: false,
accepts_files: false,
};
pub static GOFMT: ToolSpec = ToolSpec {
name: "gofmt",
command: &["gofmt", "-l"],
local_paths: &[],
config_files: &["go.mod"],
config_flag: None,
output_format: "lines",
diagnostics_stream: "stdout",
timeout_secs: DEFAULT_TOOL_TIMEOUT_SECS,
timeout_context: None,
establishes_compilation: false,
serial_in_repository: false,
accepts_files: true,
};
pub static GO_VET: ToolSpec = ToolSpec {
name: "go vet",
command: &["go", "vet"],
local_paths: &[],
config_files: &["go.mod"],
config_flag: None,
output_format: "position",
diagnostics_stream: "stderr",
timeout_secs: DEFAULT_TOOL_TIMEOUT_SECS,
timeout_context: None,
establishes_compilation: true,
serial_in_repository: false,
accepts_files: true,
};
pub static CLIPPY: ToolSpec = ToolSpec {
name: "clippy",
command: &["cargo", "clippy", "--message-format", "json", "--quiet"],
local_paths: &[],
config_files: &["Cargo.toml"],
config_flag: None,
output_format: "cargo",
diagnostics_stream: "stdout",
timeout_secs: 1_800,
timeout_context: Some(", including its Cargo build-lock wait"),
establishes_compilation: true,
serial_in_repository: true,
accepts_files: false,
};
pub static CHECKSTYLE: ToolSpec = ToolSpec {
name: "checkstyle",
command: &["checkstyle", "-f", "sarif"],
local_paths: &[],
config_files: &[
"checkstyle.xml",
".checkstyle.xml",
"config/checkstyle/checkstyle.xml",
"gradle/config/checkstyle/checkstyle.xml",
],
config_flag: Some("-c"),
output_format: "sarif",
diagnostics_stream: "stdout",
timeout_secs: DEFAULT_TOOL_TIMEOUT_SECS,
timeout_context: None,
establishes_compilation: false,
serial_in_repository: false,
accepts_files: true,
};
pub static KTLINT: ToolSpec = ToolSpec {
name: "ktlint",
command: &["ktlint", "--log-level=none", "--reporter=json"],
local_paths: &[],
config_files: &[".editorconfig"],
config_flag: None,
output_format: "ktlint",
diagnostics_stream: "stdout",
timeout_secs: DEFAULT_TOOL_TIMEOUT_SECS,
timeout_context: None,
establishes_compilation: false,
serial_in_repository: false,
accepts_files: true,
};
pub static PYTHON: LanguageSupport = LanguageSupport {
name: "python",
display_name: "Python",
extensions: &[".py"],
tools: &[&RUFF],
conventions: &[
"Follows PEP 8 naming and structure",
"Type hints on public APIs, and correct use of Optional/None",
"Context managers for resources rather than manual cleanup",
"Mutable default arguments, and late-binding closures in loops",
],
vendored_dirs: &["__pycache__", "venv", ".venv", "env", ".tox", ".eggs"],
};
pub static JAVASCRIPT: LanguageSupport = LanguageSupport {
name: "javascript",
display_name: "JavaScript",
extensions: &[".js", ".jsx", ".mjs", ".cjs"],
tools: &[&ESLINT],
conventions: &[
"Unhandled promise rejections and missing await",
"Sequential awaits in a loop where the work is independent",
"var versus let/const, and accidental global scope",
"Equality coercion (== versus ===)",
],
vendored_dirs: &["node_modules", ".next", ".nuxt"],
};
pub static TYPESCRIPT: LanguageSupport = LanguageSupport {
name: "typescript",
display_name: "TypeScript",
extensions: &[".ts", ".tsx", ".mts", ".cts"],
tools: &[&ESLINT, &TSC],
conventions: &[
"`any` where a real type is available, and unsafe casts",
"Unhandled promise rejections and missing await",
"Non-null assertions (!) that hide a genuine null case",
"Sequential awaits in a loop where the work is independent",
],
vendored_dirs: &["node_modules", ".next", ".nuxt"],
};
pub static GO: LanguageSupport = LanguageSupport {
name: "go",
display_name: "Go",
extensions: &[".go"],
tools: &[&GOFMT, &GO_VET],
conventions: &[
"Errors ignored rather than checked and wrapped",
"Goroutine leaks, and writes to a channel nobody reads",
"defer inside a loop, and defer that never runs",
"Data races on shared state without synchronisation",
],
vendored_dirs: &["vendor"],
};
pub static RUST_LANG: LanguageSupport = LanguageSupport {
name: "rust",
display_name: "Rust",
extensions: &[".rs"],
tools: &[&CLIPPY],
conventions: &[
"unwrap/expect on values that can legitimately be None or Err",
"unsafe blocks, and whether their invariants are documented",
"Unnecessary clones and allocations in hot paths",
"Send/Sync correctness for types crossing threads",
],
vendored_dirs: &["target"],
};
pub static JAVA: LanguageSupport = LanguageSupport {
name: "java",
display_name: "Java",
extensions: &[".java"],
tools: &[&CHECKSTYLE],
conventions: &[
"Resources closed on every path, and try-with-resources where it applies",
"Null handling: Optional versus a nullable return, and unchecked dereferences",
"equals/hashCode/compareTo consistency, and mutable state in a shared object",
"Exceptions swallowed or logged and rethrown, losing the original cause",
"Concurrency: unsynchronised shared state, and non-thread-safe fields on a singleton",
],
vendored_dirs: JVM_VENDORED_DIRS,
};
pub static KOTLIN: LanguageSupport = LanguageSupport {
name: "kotlin",
display_name: "Kotlin",
extensions: &[".kt", ".kts"],
tools: &[&KTLINT],
conventions: &[
"Platform types from Java interop dereferenced without a null check",
"runBlocking on a coroutine path, and scopes that outlive their work",
"!! where the null case is real, and lateinit read before assignment",
"data class equality over mutable properties",
],
vendored_dirs: JVM_VENDORED_DIRS,
};
pub static SCALA: LanguageSupport = LanguageSupport {
name: "scala",
display_name: "Scala",
extensions: &[".scala", ".sc"],
tools: &[],
conventions: &[
"Partial functions and non-exhaustive matches",
"Option/Either handling versus get and head on an empty collection",
"Implicits whose resolution is not obvious at the call site",
"Futures without an explicit ExecutionContext, and blocking inside one",
],
vendored_dirs: JVM_VENDORED_DIRS,
};
pub static GROOVY: LanguageSupport = LanguageSupport {
name: "groovy",
display_name: "Groovy",
extensions: &[".groovy", ".gradle"],
tools: &[],
conventions: &[
"Dynamic dispatch where a typed call would fail at compile time",
"Gradle configuration-time work that belongs in a task action",
"Dependency and plugin versions pinned versus floating",
"String interpolation of values that should be escaped",
],
vendored_dirs: JVM_VENDORED_DIRS,
};
pub static ALL_LANGUAGES: &[&LanguageSupport] = &[
&PYTHON,
&JAVASCRIPT,
&TYPESCRIPT,
&GO,
&RUST_LANG,
&JAVA,
&KOTLIN,
&SCALA,
&GROOVY,
];