pub mod content;
pub mod file_path;
pub mod package;
pub mod project;
pub mod runner;
use camino::Utf8Path;
use guppy::PackageId;
use std::{borrow::Cow, fmt};
pub trait Linter: Send + Sync + fmt::Debug {
fn name(&self) -> &'static str;
}
trait LintContext<'l> {
fn kind(&self) -> LintKind<'l>;
fn source(&self, name: &'static str) -> LintSource<'l> {
LintSource::new(name, self.kind())
}
}
pub struct LintFormatter<'l, 'a> {
source: LintSource<'l>,
messages: &'a mut Vec<(LintSource<'l>, LintMessage)>,
}
impl<'l, 'a> LintFormatter<'l, 'a> {
pub fn new(
source: LintSource<'l>,
messages: &'a mut Vec<(LintSource<'l>, LintMessage)>,
) -> Self {
Self { source, messages }
}
pub fn write(&mut self, level: LintLevel, message: impl Into<Cow<'static, str>>) {
self.messages
.push((self.source, LintMessage::new(level, message)));
}
pub fn write_kind(
&mut self,
kind: LintKind<'l>,
level: LintLevel,
message: impl Into<Cow<'static, str>>,
) {
self.messages.push((
LintSource::new(self.source.name(), kind),
LintMessage::new(level, message),
));
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RunStatus<'l> {
Executed,
Skipped(SkipReason<'l>),
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum SkipReason<'l> {
NonUtf8Content,
UnsupportedExtension(Option<&'l str>),
UnsupportedFile(&'l Utf8Path),
UnsupportedPackage(&'l PackageId),
GlobExemption(&'l str),
}
#[derive(Debug)]
pub struct LintMessage {
level: LintLevel,
message: Cow<'static, str>,
}
impl LintMessage {
pub fn new(level: LintLevel, message: impl Into<Cow<'static, str>>) -> Self {
Self {
level,
message: message.into(),
}
}
pub fn level(&self) -> LintLevel {
self.level
}
pub fn message(&self) -> &str {
&self.message
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[allow(dead_code)]
#[non_exhaustive]
pub enum LintLevel {
Error,
Warning,
}
impl fmt::Display for LintLevel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
LintLevel::Error => write!(f, "ERROR"),
LintLevel::Warning => write!(f, "WARNING"),
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct LintSource<'l> {
name: &'static str,
kind: LintKind<'l>,
}
impl<'l> LintSource<'l> {
fn new(name: &'static str, kind: LintKind<'l>) -> Self {
Self { name, kind }
}
pub fn name(&self) -> &'static str {
self.name
}
pub fn kind(&self) -> LintKind<'l> {
self.kind
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum LintKind<'l> {
Project,
Package {
name: &'l str,
workspace_path: &'l Utf8Path,
},
FilePath(&'l Utf8Path),
Content(&'l Utf8Path),
}
impl<'l> fmt::Display for LintKind<'l> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
LintKind::Project => write!(f, "project"),
LintKind::Package {
name,
workspace_path,
} => write!(f, "package '{}' (at {})", name, workspace_path),
LintKind::FilePath(path) => write!(f, "file path {}", path),
LintKind::Content(path) => write!(f, "content {}", path),
}
}
}
pub mod prelude {
pub use super::{
content::{ContentContext, ContentLinter},
file_path::{FilePathContext, FilePathLinter},
package::{PackageContext, PackageLinter},
project::{ProjectContext, ProjectLinter},
runner::{LintEngine, LintEngineConfig, LintResults},
LintFormatter, LintKind, LintLevel, LintMessage, LintSource, Linter, RunStatus, SkipReason,
};
pub use x_core::{Result, SystemError};
}