jscpd-rs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +69 -0
- package/Cargo.lock +1323 -0
- package/Cargo.toml +54 -0
- package/LICENSE +21 -0
- package/README.md +372 -0
- package/docs/api-parity.md +49 -0
- package/docs/cloning-plan.md +281 -0
- package/docs/compat-baseline.md +535 -0
- package/docs/format-porting.md +86 -0
- package/docs/junior-task-template.md +62 -0
- package/docs/junior-workflow.md +87 -0
- package/docs/migrating-from-jscpd.md +193 -0
- package/docs/npm-release.md +116 -0
- package/docs/public-benchmark-suite.md +81 -0
- package/docs/release-checklist.md +200 -0
- package/docs/release-decisions.md +103 -0
- package/docs/release-readiness.md +51 -0
- package/docs/upstream-bugs.md +501 -0
- package/docs/upstream-issue-drafts.md +393 -0
- package/docs/user-guide.md +309 -0
- package/examples/dump_oxc_tokens.rs +112 -0
- package/examples/library_api.rs +42 -0
- package/npm/bin/jscpd-rs.js +6 -0
- package/npm/bin/jscpd-server.js +6 -0
- package/npm/lib/run-binary.js +68 -0
- package/npm/scripts/postinstall.js +50 -0
- package/package.json +53 -0
- package/skills/dry-refactoring/SKILL.md +63 -0
- package/skills/jscpd/SKILL.md +85 -0
- package/src/app.rs +512 -0
- package/src/bin/jscpd-server.rs +429 -0
- package/src/blame.rs +130 -0
- package/src/cli/config.rs +543 -0
- package/src/cli/parsing.rs +301 -0
- package/src/cli/tests.rs +543 -0
- package/src/cli.rs +671 -0
- package/src/detector/matching/secondary.rs +387 -0
- package/src/detector/matching.rs +274 -0
- package/src/detector/model.rs +190 -0
- package/src/detector/prepare.rs +71 -0
- package/src/detector/skip_local.rs +40 -0
- package/src/detector/statistics.rs +138 -0
- package/src/detector/store.rs +96 -0
- package/src/detector/tests.rs +238 -0
- package/src/detector.rs +265 -0
- package/src/files/discovery.rs +508 -0
- package/src/files/gitignore.rs +203 -0
- package/src/files/paths.rs +68 -0
- package/src/files/shebang.rs +106 -0
- package/src/files/tests.rs +523 -0
- package/src/files.rs +25 -0
- package/src/formats.rs +570 -0
- package/src/lib.rs +433 -0
- package/src/main.rs +26 -0
- package/src/report/ai.rs +125 -0
- package/src/report/badge.rs +238 -0
- package/src/report/console.rs +180 -0
- package/src/report/console_common.rs +37 -0
- package/src/report/console_full.rs +139 -0
- package/src/report/csv.rs +65 -0
- package/src/report/escape.rs +8 -0
- package/src/report/file_output.rs +28 -0
- package/src/report/html/assets.rs +47 -0
- package/src/report/html.rs +336 -0
- package/src/report/json.rs +119 -0
- package/src/report/markdown.rs +125 -0
- package/src/report/sarif.rs +302 -0
- package/src/report/silent.rs +22 -0
- package/src/report/source.rs +38 -0
- package/src/report/summary.rs +50 -0
- package/src/report/test_support.rs +133 -0
- package/src/report/threshold.rs +76 -0
- package/src/report/xcode.rs +90 -0
- package/src/report/xml.rs +119 -0
- package/src/report.rs +250 -0
- package/src/server/mcp.rs +942 -0
- package/src/server.rs +1081 -0
- package/src/tokenizer/apex.rs +97 -0
- package/src/tokenizer/blocks.rs +532 -0
- package/src/tokenizer/embedded.rs +106 -0
- package/src/tokenizer/generic.rs +511 -0
- package/src/tokenizer/hash.rs +27 -0
- package/src/tokenizer/ignore.rs +33 -0
- package/src/tokenizer/line_index.rs +33 -0
- package/src/tokenizer/markdown.rs +289 -0
- package/src/tokenizer/markup_attrs.rs +289 -0
- package/src/tokenizer/oxc/fallback.rs +275 -0
- package/src/tokenizer/oxc/jsx.rs +168 -0
- package/src/tokenizer/oxc/kind.rs +177 -0
- package/src/tokenizer/oxc/lexical.rs +67 -0
- package/src/tokenizer/oxc.rs +659 -0
- package/src/tokenizer/scan.rs +88 -0
- package/src/tokenizer/tap.rs +150 -0
- package/src/tokenizer/tests.rs +915 -0
- package/src/tokenizer.rs +328 -0
- package/src/verbose.rs +195 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
use super::source::absolute_report_path;
|
|
2
|
+
use crate::cli::Options;
|
|
3
|
+
use crate::detector::{CloneMatch, DetectionResult};
|
|
4
|
+
|
|
5
|
+
pub(super) fn write(result: &DetectionResult, options: &Options) {
|
|
6
|
+
for clone in &result.clones {
|
|
7
|
+
println!("{}", XcodeWarning::from_clone(clone, options));
|
|
8
|
+
}
|
|
9
|
+
println!("Found {} clones.", result.clones.len());
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
struct XcodeWarning {
|
|
13
|
+
message: String,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
impl XcodeWarning {
|
|
17
|
+
fn from_clone(clone: &CloneMatch, options: &Options) -> Self {
|
|
18
|
+
let start_line_a = clone.duplication_a.start.line;
|
|
19
|
+
let end_line_a = clone.duplication_a.end.line;
|
|
20
|
+
let path_a = absolute_report_path(&clone.duplication_a.source_id);
|
|
21
|
+
let path_b = if options.absolute {
|
|
22
|
+
absolute_report_path(&clone.duplication_b.source_id)
|
|
23
|
+
} else {
|
|
24
|
+
clone.duplication_b.source_id.clone()
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
Self {
|
|
28
|
+
message: format!(
|
|
29
|
+
"{}:{}:{}: warning: Found {} lines ({}-{}) duplicated on file {} ({}-{})",
|
|
30
|
+
path_a,
|
|
31
|
+
start_line_a,
|
|
32
|
+
clone.duplication_a.start.column,
|
|
33
|
+
end_line_a.saturating_sub(start_line_a),
|
|
34
|
+
start_line_a,
|
|
35
|
+
end_line_a,
|
|
36
|
+
path_b,
|
|
37
|
+
clone.duplication_b.start.line,
|
|
38
|
+
clone.duplication_b.end.line,
|
|
39
|
+
),
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
impl std::fmt::Display for XcodeWarning {
|
|
45
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
46
|
+
f.write_str(&self.message)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#[cfg(test)]
|
|
51
|
+
mod tests {
|
|
52
|
+
use super::*;
|
|
53
|
+
use crate::report::test_support::make_test_clone;
|
|
54
|
+
|
|
55
|
+
#[test]
|
|
56
|
+
fn xcode_warning_matches_upstream_shape() {
|
|
57
|
+
let options = Options::default();
|
|
58
|
+
let clone = make_test_clone("src/a.js", "src/b.js");
|
|
59
|
+
let warning = XcodeWarning::from_clone(&clone, &options).to_string();
|
|
60
|
+
let expected_prefix = std::env::current_dir()
|
|
61
|
+
.unwrap()
|
|
62
|
+
.join("src/a.js")
|
|
63
|
+
.display()
|
|
64
|
+
.to_string();
|
|
65
|
+
|
|
66
|
+
assert_eq!(
|
|
67
|
+
warning,
|
|
68
|
+
format!(
|
|
69
|
+
"{expected_prefix}:2:3: warning: Found 3 lines (2-5) duplicated on file src/b.js (8-11)"
|
|
70
|
+
)
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
#[test]
|
|
75
|
+
fn xcode_warning_respects_absolute_second_path() {
|
|
76
|
+
let options = Options {
|
|
77
|
+
absolute: true,
|
|
78
|
+
..Options::default()
|
|
79
|
+
};
|
|
80
|
+
let clone = make_test_clone("src/a.js", "src/b.js");
|
|
81
|
+
let warning = XcodeWarning::from_clone(&clone, &options).to_string();
|
|
82
|
+
let expected_second = std::env::current_dir()
|
|
83
|
+
.unwrap()
|
|
84
|
+
.join("src/b.js")
|
|
85
|
+
.display()
|
|
86
|
+
.to_string();
|
|
87
|
+
|
|
88
|
+
assert!(warning.ends_with(&format!("duplicated on file {expected_second} (8-11)")));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
use anyhow::Result;
|
|
2
|
+
|
|
3
|
+
use super::escape::escape_xml;
|
|
4
|
+
use super::file_output::write_file_report;
|
|
5
|
+
use super::source::clone_fragment;
|
|
6
|
+
use crate::cli::Options;
|
|
7
|
+
use crate::detector::{CloneMatch, DetectionResult};
|
|
8
|
+
|
|
9
|
+
pub(super) fn write(result: &DetectionResult, options: &Options) -> Result<()> {
|
|
10
|
+
let xml = XmlReport::from_detection(result).to_string();
|
|
11
|
+
write_file_report(options, "jscpd-report.xml", "XML report", xml)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
struct XmlReport {
|
|
15
|
+
duplications: Vec<XmlDuplication>,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
struct XmlDuplication {
|
|
19
|
+
lines: usize,
|
|
20
|
+
first_file: XmlFile,
|
|
21
|
+
second_file: XmlFile,
|
|
22
|
+
fragment: String,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
struct XmlFile {
|
|
26
|
+
path: String,
|
|
27
|
+
line: usize,
|
|
28
|
+
fragment: String,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
impl XmlReport {
|
|
32
|
+
fn from_detection(result: &DetectionResult) -> Self {
|
|
33
|
+
Self {
|
|
34
|
+
duplications: result
|
|
35
|
+
.clones
|
|
36
|
+
.iter()
|
|
37
|
+
.map(|clone| XmlDuplication::from_clone(clone, result))
|
|
38
|
+
.collect(),
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
impl XmlDuplication {
|
|
44
|
+
fn from_clone(clone: &CloneMatch, result: &DetectionResult) -> Self {
|
|
45
|
+
let first_fragment = clone_fragment(result, &clone.duplication_a);
|
|
46
|
+
let second_fragment = clone_fragment(result, &clone.duplication_b);
|
|
47
|
+
|
|
48
|
+
Self {
|
|
49
|
+
lines: clone
|
|
50
|
+
.duplication_a
|
|
51
|
+
.end
|
|
52
|
+
.line
|
|
53
|
+
.saturating_sub(clone.duplication_a.start.line),
|
|
54
|
+
first_file: XmlFile {
|
|
55
|
+
path: escape_xml(&clone.duplication_a.source_id),
|
|
56
|
+
line: clone.duplication_a.start.line,
|
|
57
|
+
fragment: first_fragment.clone(),
|
|
58
|
+
},
|
|
59
|
+
second_file: XmlFile {
|
|
60
|
+
path: escape_xml(&clone.duplication_b.source_id),
|
|
61
|
+
line: clone.duplication_b.start.line,
|
|
62
|
+
fragment: second_fragment,
|
|
63
|
+
},
|
|
64
|
+
fragment: first_fragment,
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
impl std::fmt::Display for XmlReport {
|
|
70
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
71
|
+
write!(f, r#"<?xml version="1.0" encoding="UTF-8" ?><pmd-cpd>"#)?;
|
|
72
|
+
for duplication in &self.duplications {
|
|
73
|
+
write!(
|
|
74
|
+
f,
|
|
75
|
+
"\n <duplication lines=\"{}\">\n <file path=\"{}\" line=\"{}\">\n <codefragment><![CDATA[{}]]></codefragment>\n </file>\n <file path=\"{}\" line=\"{}\">\n <codefragment><![CDATA[{}]]></codefragment>\n </file>\n <codefragment><![CDATA[{}]]></codefragment>\n </duplication>\n ",
|
|
76
|
+
duplication.lines,
|
|
77
|
+
duplication.first_file.path,
|
|
78
|
+
duplication.first_file.line,
|
|
79
|
+
cdata_fragment(&duplication.first_file.fragment),
|
|
80
|
+
duplication.second_file.path,
|
|
81
|
+
duplication.second_file.line,
|
|
82
|
+
cdata_fragment(&duplication.second_file.fragment),
|
|
83
|
+
cdata_fragment(&duplication.fragment),
|
|
84
|
+
)?;
|
|
85
|
+
}
|
|
86
|
+
write!(f, "</pmd-cpd>")
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
fn cdata_fragment(value: &str) -> String {
|
|
91
|
+
value.replacen("]]>", "CDATA_END", 1)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
#[cfg(test)]
|
|
95
|
+
mod tests {
|
|
96
|
+
use super::*;
|
|
97
|
+
use crate::report::test_support::{make_test_result_with_clone, write_test_report};
|
|
98
|
+
|
|
99
|
+
#[test]
|
|
100
|
+
fn xml_report_matches_upstream_pmd_cpd_shape() {
|
|
101
|
+
let result = make_test_result_with_clone("src/a<&>.js", "src/b.js");
|
|
102
|
+
let xml = XmlReport::from_detection(&result).to_string();
|
|
103
|
+
|
|
104
|
+
assert!(xml.starts_with(r#"<?xml version="1.0" encoding="UTF-8" ?><pmd-cpd>"#));
|
|
105
|
+
assert!(xml.ends_with("</pmd-cpd>"));
|
|
106
|
+
assert!(xml.contains(r#"<duplication lines="3">"#));
|
|
107
|
+
assert!(xml.contains(r#"<file path="src/a<&>.js" line="2">"#));
|
|
108
|
+
assert!(xml.contains("<![CDATA[alpha <beta> CDATA_END\n]]>"));
|
|
109
|
+
assert!(xml.contains(r#"<file path="src/b.js" line="8">"#));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
#[test]
|
|
113
|
+
fn write_reports_writes_xml_report() {
|
|
114
|
+
let xml = write_test_report("xml", "xml-report", &["jscpd-report.xml"]);
|
|
115
|
+
|
|
116
|
+
assert!(xml.contains("<pmd-cpd>"));
|
|
117
|
+
assert!(xml.contains(r#"<file path="src/a.js" line="2">"#));
|
|
118
|
+
}
|
|
119
|
+
}
|
package/src/report.rs
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
use anyhow::{Result, bail};
|
|
2
|
+
|
|
3
|
+
use crate::cli::Options;
|
|
4
|
+
use crate::detector::DetectionResult;
|
|
5
|
+
|
|
6
|
+
mod ai;
|
|
7
|
+
mod badge;
|
|
8
|
+
mod console;
|
|
9
|
+
mod console_common;
|
|
10
|
+
mod console_full;
|
|
11
|
+
mod csv;
|
|
12
|
+
mod escape;
|
|
13
|
+
mod file_output;
|
|
14
|
+
mod html;
|
|
15
|
+
mod json;
|
|
16
|
+
mod markdown;
|
|
17
|
+
mod sarif;
|
|
18
|
+
mod silent;
|
|
19
|
+
mod source;
|
|
20
|
+
mod summary;
|
|
21
|
+
#[cfg(test)]
|
|
22
|
+
mod test_support;
|
|
23
|
+
mod threshold;
|
|
24
|
+
mod xcode;
|
|
25
|
+
mod xml;
|
|
26
|
+
|
|
27
|
+
pub use threshold::ThresholdExceeded;
|
|
28
|
+
|
|
29
|
+
pub fn write_reports(result: &DetectionResult, options: &Options) -> Result<()> {
|
|
30
|
+
for reporter in &options.reporters {
|
|
31
|
+
if options.output_is_bare
|
|
32
|
+
&& let Some(message) = bare_output_error(reporter)
|
|
33
|
+
{
|
|
34
|
+
bail!("{message}");
|
|
35
|
+
}
|
|
36
|
+
match reporter.as_str() {
|
|
37
|
+
"console" if !options.silent => console::write(result, options),
|
|
38
|
+
"consoleFull" => console_full::write(result, options),
|
|
39
|
+
"ai" => ai::write(result, options),
|
|
40
|
+
"json" => json::write(result, options)?,
|
|
41
|
+
"csv" => csv::write(result, options)?,
|
|
42
|
+
"badge" => badge::write(result, options)?,
|
|
43
|
+
"html" => html::write(result, options)?,
|
|
44
|
+
"markdown" => markdown::write(result, options)?,
|
|
45
|
+
"xml" => xml::write(result, options)?,
|
|
46
|
+
"sarif" => sarif::write(result, options)?,
|
|
47
|
+
"xcode" => xcode::write(result, options),
|
|
48
|
+
"silent" => silent::write(result),
|
|
49
|
+
"threshold" => threshold::write(result, options)?,
|
|
50
|
+
_ => {}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
Ok(())
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
pub fn write_unknown_reporter_warnings(options: &Options) {
|
|
57
|
+
for message in unknown_reporter_messages(options) {
|
|
58
|
+
println!("{message}");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
pub fn write_progress(result: &DetectionResult, options: &Options) {
|
|
63
|
+
if !should_write_progress(options) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
print!("{}", progress_output(result, options));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
fn should_write_progress(options: &Options) -> bool {
|
|
70
|
+
!options.silent && !options.reporters.iter().any(|reporter| reporter == "ai")
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
fn progress_output(result: &DetectionResult, options: &Options) -> String {
|
|
74
|
+
let mut output = String::new();
|
|
75
|
+
for clone in &result.clones {
|
|
76
|
+
output.push_str(&console_common::clone_header(clone, options));
|
|
77
|
+
output.push('\n');
|
|
78
|
+
}
|
|
79
|
+
output
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
fn is_builtin_reporter(reporter: &str) -> bool {
|
|
83
|
+
matches!(
|
|
84
|
+
reporter,
|
|
85
|
+
"ai" | "xml"
|
|
86
|
+
| "json"
|
|
87
|
+
| "csv"
|
|
88
|
+
| "markdown"
|
|
89
|
+
| "consoleFull"
|
|
90
|
+
| "html"
|
|
91
|
+
| "console"
|
|
92
|
+
| "silent"
|
|
93
|
+
| "threshold"
|
|
94
|
+
| "xcode"
|
|
95
|
+
| "sarif"
|
|
96
|
+
| "badge"
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
fn bare_output_error(reporter: &str) -> Option<&'static str> {
|
|
101
|
+
match reporter {
|
|
102
|
+
"json" | "csv" | "markdown" | "xml" => Some(
|
|
103
|
+
"TypeError [ERR_INVALID_ARG_TYPE]: The \"path\" argument must be of type string or an instance of Buffer or URL. Received type boolean (true)",
|
|
104
|
+
),
|
|
105
|
+
"sarif" | "badge" | "html" => Some(
|
|
106
|
+
"TypeError [ERR_INVALID_ARG_TYPE]: The \"path\" argument must be of type string. Received type boolean (true)",
|
|
107
|
+
),
|
|
108
|
+
_ => None,
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
fn unknown_reporter_messages(options: &Options) -> Vec<String> {
|
|
113
|
+
options
|
|
114
|
+
.reporters
|
|
115
|
+
.iter()
|
|
116
|
+
.filter(|reporter| !is_builtin_reporter(reporter))
|
|
117
|
+
.flat_map(|reporter| {
|
|
118
|
+
[
|
|
119
|
+
format!(
|
|
120
|
+
"warning: {reporter} not installed (install packages named @jscpd/{reporter}-reporter or jscpd-{reporter}-reporter)"
|
|
121
|
+
),
|
|
122
|
+
format!("Cannot find module 'jscpd-{reporter}-reporter'"),
|
|
123
|
+
]
|
|
124
|
+
})
|
|
125
|
+
.collect()
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
#[cfg(test)]
|
|
129
|
+
mod tests {
|
|
130
|
+
use super::*;
|
|
131
|
+
|
|
132
|
+
#[test]
|
|
133
|
+
fn recognizes_builtin_reporters() {
|
|
134
|
+
for reporter in [
|
|
135
|
+
"ai",
|
|
136
|
+
"xml",
|
|
137
|
+
"json",
|
|
138
|
+
"csv",
|
|
139
|
+
"markdown",
|
|
140
|
+
"consoleFull",
|
|
141
|
+
"html",
|
|
142
|
+
"console",
|
|
143
|
+
"silent",
|
|
144
|
+
"threshold",
|
|
145
|
+
"xcode",
|
|
146
|
+
"sarif",
|
|
147
|
+
"badge",
|
|
148
|
+
] {
|
|
149
|
+
assert!(is_builtin_reporter(reporter), "{reporter}");
|
|
150
|
+
}
|
|
151
|
+
assert!(!is_builtin_reporter("badgezz"));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#[test]
|
|
155
|
+
fn warns_for_unknown_reporters_like_upstream() {
|
|
156
|
+
let options = Options {
|
|
157
|
+
reporters: vec![
|
|
158
|
+
"json".to_string(),
|
|
159
|
+
"badgezz".to_string(),
|
|
160
|
+
"console".to_string(),
|
|
161
|
+
],
|
|
162
|
+
silent: true,
|
|
163
|
+
..Options::default()
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
assert_eq!(
|
|
167
|
+
unknown_reporter_messages(&options),
|
|
168
|
+
vec![
|
|
169
|
+
"warning: badgezz not installed (install packages named @jscpd/badgezz-reporter or jscpd-badgezz-reporter)",
|
|
170
|
+
"Cannot find module 'jscpd-badgezz-reporter'",
|
|
171
|
+
]
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
#[test]
|
|
176
|
+
fn bare_output_fails_for_file_reporters_like_upstream() {
|
|
177
|
+
let result = test_support::make_test_result_with_clone("src/a.js", "src/b.js");
|
|
178
|
+
for (reporter, expected) in [
|
|
179
|
+
(
|
|
180
|
+
"json",
|
|
181
|
+
"TypeError [ERR_INVALID_ARG_TYPE]: The \"path\" argument must be of type string or an instance of Buffer or URL. Received type boolean (true)",
|
|
182
|
+
),
|
|
183
|
+
(
|
|
184
|
+
"sarif",
|
|
185
|
+
"TypeError [ERR_INVALID_ARG_TYPE]: The \"path\" argument must be of type string. Received type boolean (true)",
|
|
186
|
+
),
|
|
187
|
+
] {
|
|
188
|
+
let options = Options {
|
|
189
|
+
reporters: vec![reporter.to_string()],
|
|
190
|
+
output_is_bare: true,
|
|
191
|
+
..Options::default()
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
let error = write_reports(&result, &options).unwrap_err();
|
|
195
|
+
|
|
196
|
+
assert_eq!(error.to_string(), expected, "{reporter}");
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
#[test]
|
|
201
|
+
fn warns_for_duplicate_unknown_reporters_in_order() {
|
|
202
|
+
let options = Options {
|
|
203
|
+
reporters: vec![
|
|
204
|
+
"badgezz".to_string(),
|
|
205
|
+
"myreport".to_string(),
|
|
206
|
+
"badgezz".to_string(),
|
|
207
|
+
],
|
|
208
|
+
silent: true,
|
|
209
|
+
..Options::default()
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
assert_eq!(
|
|
213
|
+
unknown_reporter_messages(&options),
|
|
214
|
+
vec![
|
|
215
|
+
"warning: badgezz not installed (install packages named @jscpd/badgezz-reporter or jscpd-badgezz-reporter)",
|
|
216
|
+
"Cannot find module 'jscpd-badgezz-reporter'",
|
|
217
|
+
"warning: myreport not installed (install packages named @jscpd/myreport-reporter or jscpd-myreport-reporter)",
|
|
218
|
+
"Cannot find module 'jscpd-myreport-reporter'",
|
|
219
|
+
"warning: badgezz not installed (install packages named @jscpd/badgezz-reporter or jscpd-badgezz-reporter)",
|
|
220
|
+
"Cannot find module 'jscpd-badgezz-reporter'",
|
|
221
|
+
]
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
#[test]
|
|
226
|
+
fn progress_prints_clone_headers_when_not_silent_or_ai() {
|
|
227
|
+
let result = test_support::make_test_result_with_clone("src/a.js", "src/b.js");
|
|
228
|
+
let options = Options::default();
|
|
229
|
+
|
|
230
|
+
let output = progress_output(&result, &options);
|
|
231
|
+
|
|
232
|
+
assert!(output.contains("Clone found (javascript):"));
|
|
233
|
+
assert!(output.contains("src/a.js"));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
#[test]
|
|
237
|
+
fn progress_is_suppressed_for_silent_and_ai_reports_like_upstream() {
|
|
238
|
+
let silent = Options {
|
|
239
|
+
silent: true,
|
|
240
|
+
..Options::default()
|
|
241
|
+
};
|
|
242
|
+
let ai = Options {
|
|
243
|
+
reporters: vec!["ai".to_string()],
|
|
244
|
+
..Options::default()
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
assert!(!should_write_progress(&silent));
|
|
248
|
+
assert!(!should_write_progress(&ai));
|
|
249
|
+
}
|
|
250
|
+
}
|