mirror of
https://github.com/nerdypepper/statix.git
synced 2024-09-11 13:45:32 +03:00
introduce --config flag
This commit is contained in:
parent
4e063b2abc
commit
2b6012a79c
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -520,6 +520,7 @@ dependencies = [
|
||||
"similar 2.1.0",
|
||||
"strip-ansi-escapes",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"vfs",
|
||||
]
|
||||
|
||||
@ -612,6 +613,15 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.6.0"
|
||||
|
@ -23,14 +23,14 @@ thiserror = "1.0.30"
|
||||
similar = "2.1.0"
|
||||
vfs = { path = "../vfs" }
|
||||
lib = { path = "../lib" }
|
||||
|
||||
[dependencies.serde_json]
|
||||
version = "1.0.68"
|
||||
optional = true
|
||||
toml = "0.5.8"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.68"
|
||||
features = [ "derive" ]
|
||||
|
||||
[dependencies.serde_json]
|
||||
version = "1.0.68"
|
||||
optional = true
|
||||
|
||||
[dev-dependencies]
|
||||
@ -38,4 +38,4 @@ insta = "1.8.0"
|
||||
strip-ansi-escapes = "0.1.1"
|
||||
|
||||
[features]
|
||||
json = [ "lib/json-out", "serde_json", "serde" ]
|
||||
json = [ "lib/json-out", "serde_json" ]
|
||||
|
@ -1,8 +1,15 @@
|
||||
use std::{default::Default, fmt, fs, path::PathBuf, str::FromStr};
|
||||
use std::{
|
||||
default::Default,
|
||||
fmt, fs,
|
||||
path::{Path, PathBuf},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use crate::{dirs, err::ConfigErr};
|
||||
use crate::{dirs, err::ConfigErr, utils, LintMap};
|
||||
|
||||
use clap::Parser;
|
||||
use lib::LINTS;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vfs::ReadOnlyVfs;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
@ -43,6 +50,10 @@ pub struct Check {
|
||||
#[clap(short = 'o', long, default_value_t, parse(try_from_str))]
|
||||
pub format: OutFormat,
|
||||
|
||||
/// Path to statix.toml
|
||||
#[clap(short = 'c', long = "config", default_value = ".")]
|
||||
pub conf_path: PathBuf,
|
||||
|
||||
/// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout
|
||||
#[clap(short, long = "stdin")]
|
||||
pub streaming: bool,
|
||||
@ -65,6 +76,10 @@ impl Check {
|
||||
vfs(files.collect::<Vec<_>>())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lints(&self) -> Result<LintMap, ConfigErr> {
|
||||
lints(&self.conf_path)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
@ -85,6 +100,10 @@ pub struct Fix {
|
||||
#[clap(short, long = "dry-run")]
|
||||
pub diff_only: bool,
|
||||
|
||||
/// Path to statix.toml
|
||||
#[clap(short = 'c', long = "config", default_value = ".")]
|
||||
pub conf_path: PathBuf,
|
||||
|
||||
/// Enable "streaming" mode, accept file on stdin, output diagnostics on stdout
|
||||
#[clap(short, long = "stdin")]
|
||||
pub streaming: bool,
|
||||
@ -125,6 +144,10 @@ impl Fix {
|
||||
FixOut::Write
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lints(&self) -> Result<LintMap, ConfigErr> {
|
||||
lints(&self.conf_path)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
@ -181,50 +204,6 @@ pub struct Explain {
|
||||
pub target: u32,
|
||||
}
|
||||
|
||||
fn parse_line_col(src: &str) -> Result<(usize, usize), ConfigErr> {
|
||||
let parts = src.split(',');
|
||||
match parts.collect::<Vec<_>>().as_slice() {
|
||||
[line, col] => {
|
||||
let l = line
|
||||
.parse::<usize>()
|
||||
.map_err(|_| ConfigErr::InvalidPosition(src.to_owned()))?;
|
||||
let c = col
|
||||
.parse::<usize>()
|
||||
.map_err(|_| ConfigErr::InvalidPosition(src.to_owned()))?;
|
||||
Ok((l, c))
|
||||
}
|
||||
_ => Err(ConfigErr::InvalidPosition(src.to_owned())),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_warning_code(src: &str) -> Result<u32, ConfigErr> {
|
||||
let mut char_stream = src.chars();
|
||||
let severity = char_stream
|
||||
.next()
|
||||
.ok_or_else(|| ConfigErr::InvalidWarningCode(src.to_owned()))?
|
||||
.to_ascii_lowercase();
|
||||
match severity {
|
||||
'w' => char_stream
|
||||
.collect::<String>()
|
||||
.parse::<u32>()
|
||||
.map_err(|_| ConfigErr::InvalidWarningCode(src.to_owned())),
|
||||
_ => Ok(0),
|
||||
}
|
||||
}
|
||||
|
||||
fn vfs(files: Vec<PathBuf>) -> Result<ReadOnlyVfs, ConfigErr> {
|
||||
let mut vfs = ReadOnlyVfs::default();
|
||||
for file in files.iter() {
|
||||
if let Ok(data) = fs::read_to_string(&file) {
|
||||
let _id = vfs.alloc_file_id(&file);
|
||||
vfs.set_file_contents(&file, data.as_bytes());
|
||||
} else {
|
||||
println!("{} contains non-utf8 content", file.display());
|
||||
};
|
||||
}
|
||||
Ok(vfs)
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum OutFormat {
|
||||
#[cfg(feature = "json")]
|
||||
@ -269,3 +248,100 @@ impl FromStr for OutFormat {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct ConfFile {
|
||||
disabled: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for ConfFile {
|
||||
fn default() -> Self {
|
||||
let disabled = vec![];
|
||||
Self { disabled }
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfFile {
|
||||
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, ConfigErr> {
|
||||
let path = path.as_ref();
|
||||
let config_file = fs::read_to_string(path).map_err(ConfigErr::InvalidPath)?;
|
||||
toml::de::from_str(&config_file).map_err(|err| {
|
||||
let pos = err.line_col();
|
||||
let msg = if let Some((line, col)) = pos {
|
||||
format!("line {}, col {}", line, col)
|
||||
} else {
|
||||
"unknown".to_string()
|
||||
};
|
||||
ConfigErr::ConfFileParse(msg)
|
||||
})
|
||||
}
|
||||
pub fn discover<P: AsRef<Path>>(path: P) -> Result<Self, ConfigErr> {
|
||||
let cannonical_path = fs::canonicalize(path.as_ref()).map_err(ConfigErr::InvalidPath)?;
|
||||
for p in cannonical_path.ancestors() {
|
||||
let statix_toml_path = p.with_file_name("statix.toml");
|
||||
if statix_toml_path.exists() {
|
||||
return Self::from_path(statix_toml_path);
|
||||
};
|
||||
}
|
||||
Ok(Self::default())
|
||||
}
|
||||
pub fn dump(&self) -> String {
|
||||
toml::ser::to_string_pretty(&self).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_line_col(src: &str) -> Result<(usize, usize), ConfigErr> {
|
||||
let parts = src.split(',');
|
||||
match parts.collect::<Vec<_>>().as_slice() {
|
||||
[line, col] => {
|
||||
let do_parse = |val: &str| {
|
||||
val.parse::<usize>()
|
||||
.map_err(|_| ConfigErr::InvalidPosition(src.to_owned()))
|
||||
};
|
||||
let l = do_parse(line)?;
|
||||
let c = do_parse(col)?;
|
||||
Ok((l, c))
|
||||
}
|
||||
_ => Err(ConfigErr::InvalidPosition(src.to_owned())),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_warning_code(src: &str) -> Result<u32, ConfigErr> {
|
||||
let mut char_stream = src.chars();
|
||||
let severity = char_stream
|
||||
.next()
|
||||
.ok_or_else(|| ConfigErr::InvalidWarningCode(src.to_owned()))?
|
||||
.to_ascii_lowercase();
|
||||
match severity {
|
||||
'w' => char_stream
|
||||
.collect::<String>()
|
||||
.parse::<u32>()
|
||||
.map_err(|_| ConfigErr::InvalidWarningCode(src.to_owned())),
|
||||
_ => Ok(0),
|
||||
}
|
||||
}
|
||||
|
||||
fn vfs(files: Vec<PathBuf>) -> Result<ReadOnlyVfs, ConfigErr> {
|
||||
let mut vfs = ReadOnlyVfs::default();
|
||||
for file in files.iter() {
|
||||
if let Ok(data) = fs::read_to_string(&file) {
|
||||
let _id = vfs.alloc_file_id(&file);
|
||||
vfs.set_file_contents(&file, data.as_bytes());
|
||||
} else {
|
||||
println!("{} contains non-utf8 content", file.display());
|
||||
};
|
||||
}
|
||||
Ok(vfs)
|
||||
}
|
||||
|
||||
fn lints(conf_path: &PathBuf) -> Result<LintMap, ConfigErr> {
|
||||
let config_file = ConfFile::discover(conf_path)?;
|
||||
Ok(utils::lint_map_of(
|
||||
(&*LINTS)
|
||||
.into_iter()
|
||||
.filter(|l| !config_file.disabled.iter().any(|check| check == l.name()))
|
||||
.cloned()
|
||||
.collect::<Vec<_>>()
|
||||
.as_slice(),
|
||||
))
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ pub enum ConfigErr {
|
||||
InvalidPosition(String),
|
||||
#[error("unable to parse `{0}` as warning code")]
|
||||
InvalidWarningCode(String),
|
||||
#[error("unable to parse config file, error at: `{0}`")]
|
||||
ConfFileParse(String),
|
||||
}
|
||||
|
||||
// #[derive(Error, Debug)]
|
||||
|
@ -1,11 +1,10 @@
|
||||
use crate::err::ExplainErr;
|
||||
|
||||
use lib::LINTS;
|
||||
use crate::{err::ExplainErr, utils};
|
||||
|
||||
pub fn explain(code: u32) -> Result<&'static str, ExplainErr> {
|
||||
let lints = utils::lint_map();
|
||||
match code {
|
||||
0 => Ok("syntax error"),
|
||||
_ => LINTS
|
||||
_ => lints
|
||||
.values()
|
||||
.flatten()
|
||||
.find(|l| l.code() == code)
|
||||
|
@ -1,19 +1,21 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::LintMap;
|
||||
|
||||
use rnix::TextRange;
|
||||
|
||||
mod all;
|
||||
use all::all;
|
||||
use all::all_with;
|
||||
|
||||
mod single;
|
||||
use single::single;
|
||||
|
||||
type Source<'a> = Cow<'a, str>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FixResult<'a> {
|
||||
pub src: Source<'a>,
|
||||
pub fixed: Vec<Fixed>,
|
||||
pub lints: &'a LintMap,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -23,10 +25,11 @@ pub struct Fixed {
|
||||
}
|
||||
|
||||
impl<'a> FixResult<'a> {
|
||||
fn empty(src: Source<'a>) -> Self {
|
||||
fn empty(src: Source<'a>, lints: &'a LintMap) -> Self {
|
||||
Self {
|
||||
src,
|
||||
fixed: Vec::new(),
|
||||
lints,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -43,8 +46,9 @@ pub mod main {
|
||||
|
||||
pub fn all(fix_config: FixConfig) -> Result<(), StatixErr> {
|
||||
let vfs = fix_config.vfs()?;
|
||||
let lints = fix_config.lints()?;
|
||||
for entry in vfs.iter() {
|
||||
match (fix_config.out(), super::all(entry.contents)) {
|
||||
match (fix_config.out(), super::all_with(entry.contents, &lints)) {
|
||||
(FixOut::Diff, fix_result) => {
|
||||
let src = fix_result
|
||||
.map(|r| r.src)
|
||||
|
@ -1,18 +1,21 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use lib::{Report, LINTS};
|
||||
use lib::Report;
|
||||
use rnix::{parser::ParseError as RnixParseErr, WalkEvent};
|
||||
|
||||
use crate::fix::{FixResult, Fixed};
|
||||
use crate::{
|
||||
fix::{FixResult, Fixed},
|
||||
LintMap,
|
||||
};
|
||||
|
||||
fn collect_fixes(source: &str) -> Result<Vec<Report>, RnixParseErr> {
|
||||
fn collect_fixes(source: &str, lints: &LintMap) -> Result<Vec<Report>, RnixParseErr> {
|
||||
let parsed = rnix::parse(source).as_result()?;
|
||||
|
||||
Ok(parsed
|
||||
.node()
|
||||
.preorder_with_tokens()
|
||||
.filter_map(|event| match event {
|
||||
WalkEvent::Enter(child) => LINTS.get(&child.kind()).map(|rules| {
|
||||
WalkEvent::Enter(child) => lints.get(&child.kind()).map(|rules| {
|
||||
rules
|
||||
.iter()
|
||||
.filter_map(|rule| rule.validate(&child))
|
||||
@ -54,7 +57,7 @@ fn reorder(mut reports: Vec<Report>) -> Vec<Report> {
|
||||
impl<'a> Iterator for FixResult<'a> {
|
||||
type Item = FixResult<'a>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let all_reports = collect_fixes(&self.src).ok()?;
|
||||
let all_reports = collect_fixes(&self.src, &self.lints).ok()?;
|
||||
if all_reports.is_empty() {
|
||||
return None;
|
||||
}
|
||||
@ -74,13 +77,14 @@ impl<'a> Iterator for FixResult<'a> {
|
||||
Some(FixResult {
|
||||
src: self.src.clone(),
|
||||
fixed,
|
||||
lints: self.lints,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all(src: &str) -> Option<FixResult> {
|
||||
pub fn all_with<'a>(src: &'a str, lints: &'a LintMap) -> Option<FixResult<'a>> {
|
||||
let src = Cow::from(src);
|
||||
let _ = rnix::parse(&src).as_result().ok()?;
|
||||
let initial = FixResult::empty(src);
|
||||
let initial = FixResult::empty(src, lints);
|
||||
initial.into_iter().last()
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
use std::{borrow::Cow, convert::TryFrom};
|
||||
|
||||
use lib::{Report, LINTS};
|
||||
use lib::Report;
|
||||
use rnix::{TextSize, WalkEvent};
|
||||
|
||||
use crate::err::SingleFixErr;
|
||||
use crate::fix::Source;
|
||||
use crate::{err::SingleFixErr, fix::Source, utils};
|
||||
|
||||
pub struct SingleFixResult<'δ> {
|
||||
pub src: Source<'δ>,
|
||||
@ -31,12 +30,13 @@ fn pos_to_byte(line: usize, col: usize, src: &str) -> Result<TextSize, SingleFix
|
||||
fn find(offset: TextSize, src: &str) -> Result<Report, SingleFixErr> {
|
||||
// we don't really need the source to form a completely parsed tree
|
||||
let parsed = rnix::parse(src);
|
||||
let lints = utils::lint_map();
|
||||
|
||||
parsed
|
||||
.node()
|
||||
.preorder_with_tokens()
|
||||
.filter_map(|event| match event {
|
||||
WalkEvent::Enter(child) => LINTS.get(&child.kind()).map(|rules| {
|
||||
WalkEvent::Enter(child) => lints.get(&child.kind()).map(|rules| {
|
||||
rules
|
||||
.iter()
|
||||
.filter_map(|rule| rule.validate(&child))
|
||||
|
@ -5,3 +5,12 @@ pub mod explain;
|
||||
pub mod fix;
|
||||
pub mod lint;
|
||||
pub mod traits;
|
||||
|
||||
mod utils;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use lib::Lint;
|
||||
use rnix::SyntaxKind;
|
||||
|
||||
pub type LintMap = HashMap<SyntaxKind, Vec<&'static Box<dyn Lint>>>;
|
||||
|
@ -1,4 +1,6 @@
|
||||
use lib::{Report, LINTS};
|
||||
use crate::{utils, LintMap};
|
||||
|
||||
use lib::Report;
|
||||
use rnix::WalkEvent;
|
||||
use vfs::{FileId, VfsEntry};
|
||||
|
||||
@ -8,18 +10,17 @@ pub struct LintResult {
|
||||
pub reports: Vec<Report>,
|
||||
}
|
||||
|
||||
pub fn lint(vfs_entry: VfsEntry) -> LintResult {
|
||||
pub fn lint_with(vfs_entry: VfsEntry, lints: &LintMap) -> LintResult {
|
||||
let file_id = vfs_entry.file_id;
|
||||
let source = vfs_entry.contents;
|
||||
let parsed = rnix::parse(source);
|
||||
|
||||
let error_reports = parsed.errors().into_iter().map(Report::from_parse_err);
|
||||
|
||||
let reports = parsed
|
||||
.node()
|
||||
.preorder_with_tokens()
|
||||
.filter_map(|event| match event {
|
||||
WalkEvent::Enter(child) => LINTS.get(&child.kind()).map(|rules| {
|
||||
WalkEvent::Enter(child) => lints.get(&child.kind()).map(|rules| {
|
||||
rules
|
||||
.iter()
|
||||
.filter_map(|rule| rule.validate(&child))
|
||||
@ -34,15 +35,21 @@ pub fn lint(vfs_entry: VfsEntry) -> LintResult {
|
||||
LintResult { file_id, reports }
|
||||
}
|
||||
|
||||
pub fn lint(vfs_entry: VfsEntry) -> LintResult {
|
||||
lint_with(vfs_entry, &utils::lint_map())
|
||||
}
|
||||
|
||||
pub mod main {
|
||||
use std::io;
|
||||
|
||||
use super::lint;
|
||||
use super::lint_with;
|
||||
use crate::{config::Check as CheckConfig, err::StatixErr, traits::WriteDiagnostic};
|
||||
|
||||
pub fn main(check_config: CheckConfig) -> Result<(), StatixErr> {
|
||||
let vfs = check_config.vfs()?;
|
||||
let mut stdout = io::stdout();
|
||||
let lints = check_config.lints()?;
|
||||
let lint = |vfs_entry| lint_with(vfs_entry, &lints);
|
||||
vfs.iter().map(lint).for_each(|r| {
|
||||
stdout.write(&r, &vfs, check_config.format).unwrap();
|
||||
});
|
||||
|
24
bin/src/utils.rs
Normal file
24
bin/src/utils.rs
Normal file
@ -0,0 +1,24 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use lib::{Lint, LINTS};
|
||||
use rnix::SyntaxKind;
|
||||
|
||||
pub fn lint_map_of(
|
||||
lints: &[&'static Box<dyn Lint>],
|
||||
) -> HashMap<SyntaxKind, Vec<&'static Box<dyn Lint>>> {
|
||||
let mut map = HashMap::new();
|
||||
for lint in lints.iter() {
|
||||
let lint = *lint;
|
||||
let matches = lint.match_kind();
|
||||
for m in matches {
|
||||
map.entry(m)
|
||||
.and_modify(|v: &mut Vec<_>| v.push(lint))
|
||||
.or_insert_with(|| vec![lint]);
|
||||
}
|
||||
}
|
||||
map
|
||||
}
|
||||
|
||||
pub fn lint_map() -> HashMap<SyntaxKind, Vec<&'static Box<dyn Lint>>> {
|
||||
lint_map_of(&*LINTS)
|
||||
}
|
@ -97,7 +97,7 @@
|
||||
in
|
||||
pkgs.mkShell {
|
||||
nativeBuildInputs = [
|
||||
pkgs.cargo-watch
|
||||
pkgs.bacon
|
||||
pkgs.cargo-insta
|
||||
rust-analyzer
|
||||
toolchain
|
||||
|
@ -255,31 +255,24 @@ pub trait Lint: Metadata + Explain + Rule + Send + Sync {}
|
||||
///
|
||||
/// See `lints.rs` for usage.
|
||||
#[macro_export]
|
||||
macro_rules! lint_map {
|
||||
macro_rules! lints {
|
||||
($($s:ident),*,) => {
|
||||
lint_map!($($s),*);
|
||||
lints!($($s),*);
|
||||
};
|
||||
($($s:ident),*) => {
|
||||
use ::std::collections::HashMap;
|
||||
use ::rnix::SyntaxKind;
|
||||
$(
|
||||
mod $s;
|
||||
)*
|
||||
::lazy_static::lazy_static! {
|
||||
pub static ref LINTS: HashMap<SyntaxKind, Vec<&'static Box<dyn $crate::Lint>>> = {
|
||||
let mut map = HashMap::new();
|
||||
pub static ref LINTS: Vec<&'static Box<dyn $crate::Lint>> = {
|
||||
let mut v = Vec::new();
|
||||
$(
|
||||
{
|
||||
let temp_lint = &*$s::LINT;
|
||||
let temp_matches = temp_lint.match_kind();
|
||||
for temp_match in temp_matches {
|
||||
map.entry(temp_match)
|
||||
.and_modify(|v: &mut Vec<_>| v.push(temp_lint))
|
||||
.or_insert_with(|| vec![temp_lint]);
|
||||
}
|
||||
v.push(temp_lint);
|
||||
}
|
||||
)*
|
||||
map
|
||||
v
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::lint_map;
|
||||
use crate::lints;
|
||||
|
||||
lint_map! {
|
||||
lints! {
|
||||
bool_comparison,
|
||||
empty_let_in,
|
||||
manual_inherit,
|
||||
|
@ -37,7 +37,7 @@ use rowan::Direction;
|
||||
/// a + b
|
||||
/// ```
|
||||
#[lint(
|
||||
name = "collapsible let in",
|
||||
name = "collapsible_let_in",
|
||||
note = "These let-in expressions are collapsible",
|
||||
code = 6,
|
||||
match_with = SyntaxKind::NODE_LET_IN
|
||||
|
@ -27,7 +27,7 @@ use rnix::{
|
||||
/// e == null
|
||||
/// ```
|
||||
#[lint(
|
||||
name = "deprecated isNull",
|
||||
name = "deprecated_is_null",
|
||||
note = "Found usage of deprecated builtin isNull",
|
||||
code = 13,
|
||||
match_with = SyntaxKind::NODE_APPLY
|
||||
|
@ -26,7 +26,7 @@ use rnix::{
|
||||
/// pkgs.statix
|
||||
/// ```
|
||||
#[lint(
|
||||
name = "empty let-in",
|
||||
name = "empty_let_in",
|
||||
note = "Useless let-in expression",
|
||||
code = 2,
|
||||
match_with = SyntaxKind::NODE_LET_IN
|
||||
|
@ -35,7 +35,7 @@ use rnix::{
|
||||
/// };
|
||||
/// ```
|
||||
#[lint(
|
||||
name = "empty pattern",
|
||||
name = "empty_pattern",
|
||||
note = "Found empty pattern in function argument",
|
||||
code = 10,
|
||||
match_with = SyntaxKind::NODE_PATTERN
|
||||
|
@ -34,7 +34,7 @@ use rnix::{
|
||||
/// map double [ 1 2 3 ]
|
||||
/// ```
|
||||
#[lint(
|
||||
name = "eta reduction",
|
||||
name = "eta_reduction",
|
||||
note = "This function expression is eta reducible",
|
||||
code = 7,
|
||||
match_with = SyntaxKind::NODE_LAMBDA
|
||||
|
@ -36,7 +36,7 @@ use rnix::{
|
||||
/// }.body
|
||||
/// ```
|
||||
#[lint(
|
||||
name = "legacy let syntax",
|
||||
name = "legacy_let_syntax",
|
||||
note = "Using undocumented `let` syntax",
|
||||
code = 5,
|
||||
match_with = SyntaxKind::NODE_LEGACY_LET
|
||||
|
@ -32,7 +32,7 @@ use rnix::{
|
||||
/// { inherit a; b = 3; }
|
||||
/// ```
|
||||
#[lint(
|
||||
name = "manual inherit",
|
||||
name = "manual_inherit",
|
||||
note = "Assignment instead of inherit",
|
||||
code = 3,
|
||||
match_with = SyntaxKind::NODE_KEY_VALUE
|
||||
|
@ -32,7 +32,7 @@ use rnix::{
|
||||
/// null
|
||||
/// ```
|
||||
#[lint(
|
||||
name = "manual inherit from",
|
||||
name = "manual_inherit_from",
|
||||
note = "Assignment instead of inherit from",
|
||||
code = 4,
|
||||
match_with = SyntaxKind::NODE_KEY_VALUE
|
||||
|
@ -27,7 +27,7 @@ use rnix::{
|
||||
/// inputs: inputs.nixpkgs
|
||||
/// ```
|
||||
#[lint(
|
||||
name = "redundant pattern bind",
|
||||
name = "redundant_pattern_bind",
|
||||
note = "Found redundant pattern bind in function argument",
|
||||
code = 11,
|
||||
match_with = SyntaxKind::NODE_PATTERN
|
||||
|
@ -32,7 +32,7 @@ use rnix::{
|
||||
/// pkgs
|
||||
/// ```
|
||||
#[lint(
|
||||
name = "unquoted splice",
|
||||
name = "unquoted_splice",
|
||||
note = "Found unquoted splice expression",
|
||||
code = 9,
|
||||
match_with = SyntaxKind::NODE_DYNAMIC
|
||||
|
@ -38,7 +38,7 @@ use rnix::{types::TypedNode, NodeOrToken, SyntaxElement, SyntaxKind};
|
||||
/// }
|
||||
/// ```
|
||||
#[lint(
|
||||
name = "unquoted uri",
|
||||
name = "unquoted_uri",
|
||||
note = "Found unquoted URI expression",
|
||||
code = 12,
|
||||
match_with = SyntaxKind::TOKEN_URI
|
||||
|
@ -33,7 +33,7 @@ use rnix::{
|
||||
/// 2 + 3
|
||||
/// ```
|
||||
#[lint(
|
||||
name = "useless parens",
|
||||
name = "useless_parens",
|
||||
note = "These parentheses can be omitted",
|
||||
code = 8,
|
||||
match_with = [
|
||||
|
Loading…
Reference in New Issue
Block a user