diff --git a/Cargo.lock b/Cargo.lock index 164482017..d5b64b7f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", ] diff --git a/crates/typos-cli/Cargo.toml b/crates/typos-cli/Cargo.toml index 0e4124e18..f5ff81371 100644 --- a/crates/typos-cli/Cargo.toml +++ b/crates/typos-cli/Cargo.toml @@ -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" diff --git a/crates/typos-cli/src/bin/typos-cli/args.rs b/crates/typos-cli/src/bin/typos-cli/args.rs index 3541533cf..a1a7f02d9 100644 --- a/crates/typos-cli/src/bin/typos-cli/args.rs +++ b/crates/typos-cli/src/bin/typos-cli/args.rs @@ -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()), } } } diff --git a/crates/typos-cli/src/bin/typos-cli/main.rs b/crates/typos-cli/src/bin/typos-cli/main.rs index 9e9fe316f..f2506306d 100644 --- a/crates/typos-cli/src/bin/typos-cli/main.rs +++ b/crates/typos-cli/src/bin/typos-cli/main.rs @@ -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 { diff --git a/crates/typos-cli/src/bin/typos-cli/report.rs b/crates/typos-cli/src/bin/typos-cli/report.rs index 084155a8e..34a9c4557 100644 --- a/crates/typos-cli/src/bin/typos-cli/report.rs +++ b/crates/typos-cli/src/bin/typos-cli/report.rs @@ -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>, + error: Mutex>, +} + +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> { + 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> { + 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::, _>>(); + + 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, +) -> Result> { + 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, Box> { + 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 { + 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> { + 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::*; diff --git a/crates/typos-cli/src/report.rs b/crates/typos-cli/src/report.rs index 81f4c1fe3..c5800180c 100644 --- a/crates/typos-cli/src/report.rs +++ b/crates/typos-cli/src/report.rs @@ -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)] diff --git a/crates/typos-cli/tests/cmd/help.toml b/crates/typos-cli/tests/cmd/help.toml index 772f09f48..c02facdbb 100644 --- a/crates/typos-cli/tests/cmd/help.toml +++ b/crates/typos-cli/tests/cmd/help.toml @@ -45,7 +45,7 @@ Mode: Output: --format Render style for messages [default: long] [possible values: silent, brief, - long, json] + long, json, sarif] --color Controls when to use color [default: auto] [possible values: auto, always, never] -v, --verbose... Increase logging verbosity diff --git a/crates/typos-cli/tests/cmd/sarif.in/_typos.toml b/crates/typos-cli/tests/cmd/sarif.in/_typos.toml new file mode 100644 index 000000000..30f24e986 --- /dev/null +++ b/crates/typos-cli/tests/cmd/sarif.in/_typos.toml @@ -0,0 +1,4 @@ +[default.extend-words] +invalid = "" +incorrect = "corrected" +different = "size" diff --git a/crates/typos-cli/tests/cmd/sarif.in/bad b/crates/typos-cli/tests/cmd/sarif.in/bad new file mode 100644 index 000000000..85d0a37c1 --- /dev/null +++ b/crates/typos-cli/tests/cmd/sarif.in/bad @@ -0,0 +1,4 @@ +Hello good! +Hello invalid! +Hello incorrect! +Hello different size! diff --git a/crates/typos-cli/tests/cmd/sarif.in/good b/crates/typos-cli/tests/cmd/sarif.in/good new file mode 100644 index 000000000..802992c42 --- /dev/null +++ b/crates/typos-cli/tests/cmd/sarif.in/good @@ -0,0 +1 @@ +Hello world diff --git a/crates/typos-cli/tests/cmd/sarif.in/some-incorrect-file b/crates/typos-cli/tests/cmd/sarif.in/some-incorrect-file new file mode 100644 index 000000000..e69de29bb diff --git a/crates/typos-cli/tests/cmd/sarif.toml b/crates/typos-cli/tests/cmd/sarif.toml new file mode 100644 index 000000000..b5a9a7054 --- /dev/null +++ b/crates/typos-cli/tests/cmd/sarif.toml @@ -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 = "" diff --git a/deny.toml b/deny.toml index b6ecbe9c9..ee5ae89b3 100644 --- a/deny.toml +++ b/deny.toml @@ -87,6 +87,7 @@ allow = [ "MIT", "MIT-0", "Apache-2.0", + "BSD-2-Clause", "BSD-3-Clause", "MPL-2.0", "Unicode-DFS-2016",