mirror of
https://github.com/crate-ci/typos.git
synced 2024-12-22 07:32:18 -05:00
parent
32b96444b9
commit
63908449a7
13 changed files with 611 additions and 36 deletions
213
Cargo.lock
generated
213
Cargo.lock
generated
|
@ -2,6 +2,16 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "Inflector"
|
||||
version = "0.11.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.21.0"
|
||||
|
@ -123,7 +133,7 @@ checksum = "edf3ee19dbc0a46d740f6f0926bde8c50f02bdbc7b536842da28f6ac56513a8b"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -208,7 +218,7 @@ dependencies = [
|
|||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim 0.11.0",
|
||||
"strsim",
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
|
@ -221,7 +231,7 @@ dependencies = [
|
|||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -338,9 +348,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.3"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
|
||||
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
|
@ -348,27 +358,58 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.3"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
|
||||
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim 0.10.0",
|
||||
"syn",
|
||||
"strsim",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.3"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
||||
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
|
||||
dependencies = [
|
||||
"derive_builder_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_core"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_macro"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
|
||||
dependencies = [
|
||||
"derive_builder_core",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -388,7 +429,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.90",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
|
@ -401,7 +442,7 @@ dependencies = [
|
|||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -447,7 +488,7 @@ checksum = "7bdb5411188f7f878a17964798c1264b6b0a9f915bd39b20bf99193c923e1b4e"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -500,7 +541,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -727,6 +768,12 @@ dependencies = [
|
|||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.149"
|
||||
|
@ -857,7 +904,7 @@ dependencies = [
|
|||
"phf_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.90",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
|
@ -899,6 +946,16 @@ dependencies = [
|
|||
"termtree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-exit"
|
||||
version = "2.0.2"
|
||||
|
@ -1021,6 +1078,12 @@ dependencies = [
|
|||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
|
@ -1036,6 +1099,33 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schemafy_core"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bec29dddcfe60f92f3c0d422707b8b56473983ef0481df8d5236ed3ab8fdf24"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schemafy_lib"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af3d87f1df246a9b7e2bfd1f4ee5f88e48b11ef9cfc62e63f0dead255b1a6f5f"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"schemafy_core",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"syn 1.0.109",
|
||||
"uriparse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
|
@ -1051,6 +1141,26 @@ dependencies = [
|
|||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-sarif"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a38c5e5bbaa10cc256774ea394ad62968c31c0e3c3265f65221e02c87dd1a914"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"derive_builder",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"schemafy_lib",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"syn 2.0.90",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.215"
|
||||
|
@ -1059,7 +1169,7 @@ checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1156,15 +1266,39 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
|||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.0"
|
||||
name = "strum"
|
||||
version = "0.26.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
|
@ -1206,6 +1340,26 @@ version = "0.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.8"
|
||||
|
@ -1317,6 +1471,7 @@ dependencies = [
|
|||
"proc-exit",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde-sarif",
|
||||
"serde_json",
|
||||
"serde_regex",
|
||||
"snapbox",
|
||||
|
@ -1433,6 +1588,16 @@ version = "0.2.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||
|
||||
[[package]]
|
||||
name = "uriparse"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
|
@ -1702,5 +1867,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
|
|
@ -76,6 +76,7 @@ colorchoice-clap = "1.0.3"
|
|||
serde_regex = "1.1.0"
|
||||
regex = "1.10.4"
|
||||
encoding_rs = "0.8.34"
|
||||
serde-sarif = "0.5.0"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_fs = "1.1"
|
||||
|
|
|
@ -10,6 +10,7 @@ pub(crate) enum Format {
|
|||
#[default]
|
||||
Long,
|
||||
Json,
|
||||
Sarif,
|
||||
}
|
||||
|
||||
impl Format {
|
||||
|
@ -19,6 +20,7 @@ impl Format {
|
|||
Format::Brief => Box::new(crate::report::PrintBrief),
|
||||
Format::Long => Box::new(crate::report::PrintLong),
|
||||
Format::Json => Box::new(crate::report::PrintJson),
|
||||
Format::Sarif => Box::new(crate::report::PrintSarif::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ mod report;
|
|||
|
||||
use proc_exit::prelude::*;
|
||||
|
||||
use typos_cli::report::Report;
|
||||
|
||||
fn main() {
|
||||
human_panic::setup_panic!();
|
||||
let result = run();
|
||||
|
@ -187,6 +189,13 @@ fn run_checks(args: &args::Args) -> proc_exit::ExitResult {
|
|||
None => None,
|
||||
};
|
||||
|
||||
// HACK: Diff doesn't handle mixing content
|
||||
let global_reporter = if args.diff {
|
||||
Box::new(report::PrintSilent)
|
||||
} else {
|
||||
args.format.reporter()
|
||||
};
|
||||
|
||||
// Note: file_list and args.path are mutually exclusive, enforced by clap
|
||||
'path: for path in file_list.as_ref().unwrap_or(&args.path) {
|
||||
// Note paths are passed through stdin, `-` is treated like a normal path
|
||||
|
@ -272,14 +281,8 @@ fn run_checks(args: &args::Args) -> proc_exit::ExitResult {
|
|||
});
|
||||
}
|
||||
|
||||
// HACK: Diff doesn't handle mixing content
|
||||
let output_reporter = if args.diff {
|
||||
Box::new(report::PrintSilent)
|
||||
} else {
|
||||
args.format.reporter()
|
||||
};
|
||||
let status_reporter = report::MessageStatus::new(output_reporter.as_ref());
|
||||
let reporter: &dyn typos_cli::report::Report = &status_reporter;
|
||||
let status_reporter = report::MessageStatus::new(global_reporter.as_ref());
|
||||
let reporter: &dyn Report = &status_reporter;
|
||||
|
||||
let selected_checks: &dyn typos_cli::file::FileChecker = if args.files {
|
||||
&typos_cli::file::FoundFiles
|
||||
|
@ -333,6 +336,11 @@ fn run_checks(args: &args::Args) -> proc_exit::ExitResult {
|
|||
}
|
||||
}
|
||||
|
||||
if let Err(err) = global_reporter.generate_final_result() {
|
||||
errors_found = true;
|
||||
log::error!("could not render end-report: {}", err);
|
||||
}
|
||||
|
||||
if errors_found {
|
||||
proc_exit::Code::FAILURE.ok()
|
||||
} else if typos_found {
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
#![allow(clippy::needless_update)]
|
||||
|
||||
use std::io::Write as _;
|
||||
use std::sync::atomic;
|
||||
use std::sync::{atomic, Mutex};
|
||||
|
||||
use anstream::stdout;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use serde_sarif::sarif;
|
||||
use serde_sarif::sarif::{
|
||||
ArtifactChangeBuilder, ArtifactContentBuilder, FixBuilder, ReplacementBuilder,
|
||||
};
|
||||
use typos_cli::report::{Context, Message, Report, Typo};
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
const ERROR: anstyle::Style = anstyle::AnsiColor::BrightRed.on_default();
|
||||
const INFO: anstyle::Style = anstyle::AnsiColor::BrightBlue.on_default();
|
||||
|
@ -46,6 +49,10 @@ impl Report for MessageStatus<'_> {
|
|||
}
|
||||
self.reporter.report(msg)
|
||||
}
|
||||
|
||||
fn generate_final_result(&self) -> Result<(), std::io::Error> {
|
||||
self.reporter.generate_final_result()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
@ -280,6 +287,230 @@ impl Report for PrintJson {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct PrintSarif {
|
||||
results: Mutex<Vec<sarif::Result>>,
|
||||
error: Mutex<Vec<String>>,
|
||||
}
|
||||
|
||||
impl Default for PrintSarif {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
results: Mutex::new(Vec::new()),
|
||||
error: Mutex::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Report for PrintSarif {
|
||||
fn report(&self, msg: Message<'_>) -> Result<(), std::io::Error> {
|
||||
self.report_sarif(msg).map_err(sarif_error_mapper)
|
||||
}
|
||||
|
||||
fn generate_final_result(&self) -> Result<(), std::io::Error> {
|
||||
self.generate_final_result().map_err(sarif_error_mapper)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrintSarif {
|
||||
fn report_sarif(&self, msg: Message<'_>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
match &msg {
|
||||
Message::Typo(msg) => {
|
||||
if msg.corrections.is_valid() {
|
||||
return Ok(());
|
||||
}
|
||||
let message = type_to_sarif_message(msg).unwrap();
|
||||
let location = typo_to_sarif_location(msg)?;
|
||||
|
||||
let fix =
|
||||
typo_to_sarif_fix(message.clone(), msg.corrections.clone(), location.clone())?;
|
||||
let result = typo_to_sarif_result(message, location, fix)?;
|
||||
|
||||
self.results.lock().unwrap().push(result);
|
||||
}
|
||||
Message::Error(msg) => {
|
||||
self.error.lock().unwrap().push(msg.msg.clone());
|
||||
}
|
||||
Message::BinaryFile(_) => {}
|
||||
Message::Parse(_) | Message::FileType(_) | Message::File(_) => {}
|
||||
_ => unimplemented!("New message {:?}", msg),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_final_result(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut sarif_builder = sarif::SarifBuilder::default();
|
||||
sarif_builder
|
||||
.version(sarif::Version::V2_1_0.to_string())
|
||||
.schema(sarif::SCHEMA_URL);
|
||||
|
||||
let tool = sarif::ToolBuilder::default()
|
||||
.driver(
|
||||
sarif::ToolComponentBuilder::default()
|
||||
.name("typos")
|
||||
.information_uri(env!("CARGO_PKG_REPOSITORY"))
|
||||
.build()?,
|
||||
)
|
||||
.build()?;
|
||||
|
||||
let mut run_builder = sarif::RunBuilder::default();
|
||||
run_builder
|
||||
.tool(tool)
|
||||
.column_kind(sarif::ResultColumnKind::UnicodeCodePoints.to_string())
|
||||
.results(self.results.lock().unwrap().clone());
|
||||
|
||||
if !self.error.lock().unwrap().is_empty() {
|
||||
let invocations = self
|
||||
.error
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|x| {
|
||||
sarif::InvocationBuilder::default()
|
||||
.process_start_failure_message(x.clone())
|
||||
.build()
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>();
|
||||
|
||||
if let Err(e) = invocations {
|
||||
return Err(e.into());
|
||||
}
|
||||
|
||||
run_builder.invocations(invocations.unwrap());
|
||||
}
|
||||
|
||||
let run = run_builder.build()?;
|
||||
sarif_builder.runs(vec![run]);
|
||||
|
||||
let sarif = sarif_builder.build()?;
|
||||
|
||||
serde_json::to_writer_pretty(stdout().lock(), &sarif)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn sarif_error_mapper(error: impl std::fmt::Display) -> std::io::Error {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!("failed to generate SARIF output: {error}"),
|
||||
)
|
||||
}
|
||||
|
||||
fn typo_to_sarif_result(
|
||||
message: String,
|
||||
location: sarif::Location,
|
||||
fix: Option<sarif::Fix>,
|
||||
) -> Result<sarif::Result, Box<dyn std::error::Error>> {
|
||||
let mut result = sarif::ResultBuilder::default()
|
||||
.level(sarif::ResultLevel::Error.to_string())
|
||||
.message(sarif::MessageBuilder::default().markdown(message).build()?)
|
||||
.locations(vec![location])
|
||||
.build()?;
|
||||
if let Some(fix) = fix {
|
||||
result.fixes = Some(vec![fix]);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn typo_to_sarif_fix(
|
||||
message: String,
|
||||
correct: typos::Status<'_>,
|
||||
location: sarif::Location,
|
||||
) -> Result<Option<sarif::Fix>, Box<dyn std::error::Error>> {
|
||||
let physical_location = location.physical_location.unwrap();
|
||||
let Some(region) = physical_location.region else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let mut replacements = vec![];
|
||||
|
||||
match correct {
|
||||
typos::Status::Corrections(corrections) => {
|
||||
for correction in corrections.iter() {
|
||||
replacements.push(
|
||||
ReplacementBuilder::default()
|
||||
.deleted_region(region.clone())
|
||||
.inserted_content(
|
||||
ArtifactContentBuilder::default()
|
||||
.text(correction.clone())
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.build()
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => return Ok(None),
|
||||
}
|
||||
|
||||
let change = ArtifactChangeBuilder::default()
|
||||
.artifact_location(physical_location.artifact_location.unwrap())
|
||||
.replacements(replacements)
|
||||
.build()?;
|
||||
|
||||
let fix = FixBuilder::default()
|
||||
.description(sarif::MessageBuilder::default().markdown(message).build()?)
|
||||
.artifact_changes(vec![change])
|
||||
.build()?;
|
||||
|
||||
Ok(Some(fix))
|
||||
}
|
||||
|
||||
fn type_to_sarif_message(msg: &Typo<'_>) -> Option<String> {
|
||||
match &msg.corrections {
|
||||
typos::Status::Valid => None,
|
||||
typos::Status::Invalid => Some(format!("`{}` is disallowed", msg.typo)),
|
||||
typos::Status::Corrections(corrections) => Some(format!(
|
||||
"`{}` should be {}",
|
||||
msg.typo,
|
||||
itertools::join(corrections.iter().map(|s| format!("`{s}`")), ", ",)
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn typo_to_sarif_location(msg: &Typo<'_>) -> Result<sarif::Location, Box<dyn std::error::Error>> {
|
||||
let path = match &msg.context {
|
||||
Some(Context::File(ctx)) => ctx.path,
|
||||
Some(Context::Path(ctx)) => ctx.path,
|
||||
None => std::path::Path::new(""),
|
||||
_ => unimplemented!("New context {:?}", msg),
|
||||
};
|
||||
|
||||
let artifact = sarif::ArtifactLocationBuilder::default()
|
||||
.uri(
|
||||
path.display()
|
||||
.to_string()
|
||||
.replace(std::path::MAIN_SEPARATOR, "/"),
|
||||
)
|
||||
.build()?;
|
||||
let mut physical = sarif::PhysicalLocationBuilder::default();
|
||||
physical.artifact_location(artifact);
|
||||
|
||||
if let Some(Context::File(context)) = &msg.context {
|
||||
let start = String::from_utf8_lossy(&msg.buffer[0..msg.byte_offset]);
|
||||
let column_start = start.chars().count() + 1;
|
||||
let column_end = msg.typo.chars().count() + column_start;
|
||||
let line_num = context.line_num;
|
||||
|
||||
physical.region(
|
||||
sarif::RegionBuilder::default()
|
||||
.start_line(line_num as i64)
|
||||
.end_line(line_num as i64)
|
||||
.start_column(column_start as i64)
|
||||
.end_column(column_end as i64)
|
||||
.build()?,
|
||||
);
|
||||
}
|
||||
|
||||
let location = sarif::LocationBuilder::default()
|
||||
.physical_location(physical.build()?)
|
||||
.build()?;
|
||||
Ok(location)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -4,6 +4,10 @@ use std::borrow::Cow;
|
|||
|
||||
pub trait Report: Send + Sync {
|
||||
fn report(&self, msg: Message<'_>) -> Result<(), std::io::Error>;
|
||||
|
||||
fn generate_final_result(&self) -> Result<(), std::io::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, serde::Serialize, derive_more::From)]
|
||||
|
|
|
@ -45,7 +45,7 @@ Mode:
|
|||
|
||||
Output:
|
||||
--format <FORMAT> Render style for messages [default: long] [possible values: silent, brief,
|
||||
long, json]
|
||||
long, json, sarif]
|
||||
--color <WHEN> Controls when to use color [default: auto] [possible values: auto, always,
|
||||
never]
|
||||
-v, --verbose... Increase logging verbosity
|
||||
|
|
4
crates/typos-cli/tests/cmd/sarif.in/_typos.toml
Normal file
4
crates/typos-cli/tests/cmd/sarif.in/_typos.toml
Normal file
|
@ -0,0 +1,4 @@
|
|||
[default.extend-words]
|
||||
invalid = ""
|
||||
incorrect = "corrected"
|
||||
different = "size"
|
4
crates/typos-cli/tests/cmd/sarif.in/bad
Normal file
4
crates/typos-cli/tests/cmd/sarif.in/bad
Normal file
|
@ -0,0 +1,4 @@
|
|||
Hello good!
|
||||
Hello invalid!
|
||||
Hello incorrect!
|
||||
Hello different size!
|
1
crates/typos-cli/tests/cmd/sarif.in/good
Normal file
1
crates/typos-cli/tests/cmd/sarif.in/good
Normal file
|
@ -0,0 +1 @@
|
|||
Hello world
|
0
crates/typos-cli/tests/cmd/sarif.in/some-incorrect-file
Normal file
0
crates/typos-cli/tests/cmd/sarif.in/some-incorrect-file
Normal file
154
crates/typos-cli/tests/cmd/sarif.toml
Normal file
154
crates/typos-cli/tests/cmd/sarif.toml
Normal file
|
@ -0,0 +1,154 @@
|
|||
bin.name = "typos"
|
||||
args = "--format sarif --sort"
|
||||
status.code = 2
|
||||
stdout = '''
|
||||
{
|
||||
"$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json",
|
||||
"runs": [
|
||||
{
|
||||
"columnKind": "unicodeCodePoints",
|
||||
"results": [
|
||||
{
|
||||
"level": "error",
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "./bad"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 14,
|
||||
"endLine": 2,
|
||||
"startColumn": 7,
|
||||
"startLine": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"message": {
|
||||
"markdown": "`invalid` is disallowed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fixes": [
|
||||
{
|
||||
"artifactChanges": [
|
||||
{
|
||||
"artifactLocation": {
|
||||
"uri": "./bad"
|
||||
},
|
||||
"replacements": [
|
||||
{
|
||||
"deletedRegion": {
|
||||
"endColumn": 16,
|
||||
"endLine": 3,
|
||||
"startColumn": 7,
|
||||
"startLine": 3
|
||||
},
|
||||
"insertedContent": {
|
||||
"text": "corrected"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"description": {
|
||||
"markdown": "`incorrect` should be `corrected`"
|
||||
}
|
||||
}
|
||||
],
|
||||
"level": "error",
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "./bad"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 16,
|
||||
"endLine": 3,
|
||||
"startColumn": 7,
|
||||
"startLine": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"message": {
|
||||
"markdown": "`incorrect` should be `corrected`"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fixes": [
|
||||
{
|
||||
"artifactChanges": [
|
||||
{
|
||||
"artifactLocation": {
|
||||
"uri": "./bad"
|
||||
},
|
||||
"replacements": [
|
||||
{
|
||||
"deletedRegion": {
|
||||
"endColumn": 16,
|
||||
"endLine": 4,
|
||||
"startColumn": 7,
|
||||
"startLine": 4
|
||||
},
|
||||
"insertedContent": {
|
||||
"text": "size"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"description": {
|
||||
"markdown": "`different` should be `size`"
|
||||
}
|
||||
}
|
||||
],
|
||||
"level": "error",
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "./bad"
|
||||
},
|
||||
"region": {
|
||||
"endColumn": 16,
|
||||
"endLine": 4,
|
||||
"startColumn": 7,
|
||||
"startLine": 4
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"message": {
|
||||
"markdown": "`different` should be `size`"
|
||||
}
|
||||
},
|
||||
{
|
||||
"level": "error",
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "./some-incorrect-file"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"message": {
|
||||
"markdown": "`incorrect` should be `corrected`"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tool": {
|
||||
"driver": {
|
||||
"informationUri": "https://github.com/crate-ci/typos",
|
||||
"name": "typos"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": "2.1.0"
|
||||
}'''
|
||||
stderr = ""
|
|
@ -87,6 +87,7 @@ allow = [
|
|||
"MIT",
|
||||
"MIT-0",
|
||||
"Apache-2.0",
|
||||
"BSD-2-Clause",
|
||||
"BSD-3-Clause",
|
||||
"MPL-2.0",
|
||||
"Unicode-DFS-2016",
|
||||
|
|
Loading…
Reference in a new issue