Skip to content

Commit

Permalink
Merge branch 'main' into no-useless-call
Browse files Browse the repository at this point in the history
  • Loading branch information
Sysix authored Jan 31, 2025
2 parents 5a58bea + 2b83b71 commit 4cc62fb
Show file tree
Hide file tree
Showing 45 changed files with 1,796 additions and 1,031 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions apps/oxlint/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ oxc_linter = { workspace = true }
oxc_span = { workspace = true }

bpaf = { workspace = true, features = ["autocomplete", "bright-color", "derive"] }
cow-utils = { workspace = true }
ignore = { workspace = true, features = ["simd-accel"] }
miette = { workspace = true }
rayon = { workspace = true }
Expand Down
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"ignorePatterns": [
"*.js"
]
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"plugins": [],
"rules": {
"eslint/no-nested-ternary": "off"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"plugins": [
"unicorn"
],
"rules": {
"unicorn/no-nested-ternary": "off"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log(bar ? baz : qux === quxx ? bing : bam);
176 changes: 146 additions & 30 deletions apps/oxlint/src/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use std::{
time::Instant,
};

use ignore::gitignore::Gitignore;
use cow_utils::CowUtils;
use ignore::{gitignore::Gitignore, overrides::OverrideBuilder};
use oxc_diagnostics::{DiagnosticService, GraphicalReportHandler};
use oxc_linter::{
loader::LINT_PARTIAL_LOADER_EXT, AllowWarnDeny, ConfigStoreBuilder, InvalidFilterKind,
Expand Down Expand Up @@ -61,29 +62,6 @@ impl Runner for LintRunner {
let provided_path_count = paths.len();
let now = Instant::now();

// The ignore crate whitelists explicit paths, but priority
// should be given to the ignore file. Many users lint
// automatically and pass a list of changed files explicitly.
// To accommodate this, unless `--no-ignore` is passed,
// pre-filter the paths.
if !paths.is_empty() && !ignore_options.no_ignore {
let (ignore, _err) = Gitignore::new(&ignore_options.ignore_path);
paths.retain(|p| if p.is_dir() { true } else { !ignore.matched(p, false).is_ignore() });
}

// Append cwd to all paths
paths = paths.into_iter().map(|x| self.cwd.join(x)).collect();

if paths.is_empty() {
// If explicit paths were provided, but all have been
// filtered, return early.
if provided_path_count > 0 {
return CliRunResult::LintNoFilesFound;
}

paths.push(self.cwd.clone());
}

let filter = match Self::get_filters(filter) {
Ok(filter) => filter,
Err((result, message)) => {
Expand Down Expand Up @@ -114,11 +92,79 @@ impl Runner for LintRunner {
}

let mut oxlintrc = config_search_result.unwrap();
let oxlint_wd = oxlintrc.path.parent().unwrap_or(&self.cwd).to_path_buf();
let mut override_builder = None;

if !ignore_options.no_ignore {
let mut builder = OverrideBuilder::new(&self.cwd);

if !ignore_options.ignore_pattern.is_empty() {
for pattern in &ignore_options.ignore_pattern {
// Meaning of ignore pattern is reversed
// <https://docs.rs/ignore/latest/ignore/overrides/struct.OverrideBuilder.html#method.add>
let pattern = format!("!{pattern}");
builder.add(&pattern).unwrap();
}
}
if !oxlintrc.ignore_patterns.is_empty() {
let oxlint_wd = oxlintrc.path.parent().unwrap_or(&self.cwd).to_path_buf();
oxlintrc.ignore_patterns =
Self::adjust_ignore_patterns(&self.cwd, &oxlint_wd, oxlintrc.ignore_patterns);
for pattern in &oxlintrc.ignore_patterns {
let pattern = format!("!{pattern}");
builder.add(&pattern).unwrap();
}
}

let builder = builder.build().unwrap();

// The ignore crate whitelists explicit paths, but priority
// should be given to the ignore file. Many users lint
// automatically and pass a list of changed files explicitly.
// To accommodate this, unless `--no-ignore` is passed,
// pre-filter the paths.
if !paths.is_empty() {
let (ignore, _err) = Gitignore::new(&ignore_options.ignore_path);

paths.retain_mut(|p| {
// Append cwd to all paths
let mut path = self.cwd.join(&p);

std::mem::swap(p, &mut path);

if path.is_dir() {
true
} else {
!(builder.matched(p, false).is_ignore()
|| ignore.matched(path, false).is_ignore())
}
});
}

override_builder = Some(builder);
}

if paths.is_empty() {
// If explicit paths were provided, but all have been
// filtered, return early.
if provided_path_count > 0 {
if let Some(end) = output_formatter.lint_command_info(&LintCommandInfo {
number_of_files: 0,
number_of_rules: 0,
threads_count: rayon::current_num_threads(),
start_time: now.elapsed(),
}) {
stdout.write_all(end.as_bytes()).or_else(Self::check_for_writer_error).unwrap();
stdout.flush().unwrap();
};

let paths = Walk::new(&oxlint_wd, &paths, &ignore_options, &oxlintrc.ignore_patterns)
.with_extensions(Extensions(extensions))
.paths();
return CliRunResult::LintNoFilesFound;
}

paths.push(self.cwd.clone());
}

let walker = Walk::new(&paths, &ignore_options, override_builder);
let paths = walker.with_extensions(Extensions(extensions)).paths();

let number_of_files = paths.len();

Expand Down Expand Up @@ -209,7 +255,8 @@ impl Runner for LintRunner {
} else {
let path = if path.is_relative() { options.cwd().join(path) } else { path.clone() };
stdout.write_all(format!(
"The tsconfig file {path:?} does not exist, Please provide a valid tsconfig file.\n",
"The tsconfig file {:?} does not exist, Please provide a valid tsconfig file.\n",
path.to_string_lossy().cow_replace('\\', "/")
).as_bytes()).or_else(Self::check_for_writer_error).unwrap();
stdout.flush().unwrap();

Expand Down Expand Up @@ -342,11 +389,35 @@ impl LintRunner {
Err(error)
}
}

fn adjust_ignore_patterns(
base: &PathBuf,
path: &PathBuf,
ignore_patterns: Vec<String>,
) -> Vec<String> {
if base == path {
ignore_patterns
} else {
let relative_ignore_path =
path.strip_prefix(base).map_or_else(|_| PathBuf::from("."), Path::to_path_buf);

ignore_patterns
.into_iter()
.map(|pattern| {
let prefix_len = pattern.chars().take_while(|&c| c == '!').count();
let (prefix, pattern) = pattern.split_at(prefix_len);

let adjusted_path = relative_ignore_path.join(pattern);
format!("{prefix}{}", adjusted_path.to_string_lossy().cow_replace('\\', "/"))
})
.collect()
}
}
}

#[cfg(test)]
mod test {
use std::fs;
use std::{fs, path::PathBuf};

use super::LintRunner;
use crate::tester::Tester;
Expand Down Expand Up @@ -684,6 +755,15 @@ mod test {
Tester::new().test_and_snapshot(args);
}

#[test]
fn test_ignore_patterns() {
let args = &["-c", "./test/eslintrc.json", "--ignore-pattern", "*.ts", "."];

Tester::new()
.with_cwd("fixtures/config_ignore_patterns/with_oxlintrc".into())
.test_and_snapshot(args);
}

#[test]
fn test_config_ignore_patterns_extension() {
let args = &[
Expand All @@ -695,6 +775,17 @@ mod test {
Tester::new().test_and_snapshot(args);
}

#[test]
fn test_config_ignore_patterns_special_extension() {
let args = &[
"-c",
"fixtures/config_ignore_patterns/ignore_extension/eslintrc.json",
"fixtures/config_ignore_patterns/ignore_extension/main.js",
];

Tester::new().test_and_snapshot(args);
}

#[test]
fn test_config_ignore_patterns_directory() {
let args = &["-c", "eslintrc.json"];
Expand Down Expand Up @@ -732,4 +823,29 @@ mod test {
.with_cwd("fixtures/eslint_and_typescript_alias_rules".into())
.test_and_snapshot_multiple(&[args_1, args_2]);
}

#[test]
fn test_disable_eslint_and_unicorn_alias_rules() {
// Issue: <https://github.com/oxc-project/oxc/issues/8485>
let args_1 = &["-c", ".oxlintrc-eslint.json", "test.js"];
let args_2 = &["-c", ".oxlintrc-unicorn.json", "test.js"];
Tester::new()
.with_cwd("fixtures/disable_eslint_and_unicorn_alias_rules".into())
.test_and_snapshot_multiple(&[args_1, args_2]);
}

#[test]
fn test_adjust_ignore_patterns() {
let base = PathBuf::from("/project/root");
let path = PathBuf::from("/project/root/src");
let ignore_patterns =
vec![String::from("target"), String::from("!dist"), String::from("!!dist")];

let adjusted_patterns = LintRunner::adjust_ignore_patterns(&base, &path, ignore_patterns);

assert_eq!(
adjusted_patterns,
vec![String::from("src/target"), String::from("!src/dist"), String::from("!!src/dist")]
);
}
}
1 change: 1 addition & 0 deletions ...es__issue_7566__tests__main.js [email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ source: apps/oxlint/src/tester.rs
arguments: --ignore-path fixtures/issue_7566/.oxlintignore fixtures/issue_7566/tests/main.js fixtures/issue_7566/tests/function/main.js
working directory:
----------
Finished in <variable>ms on 0 files with 0 rules using 1 threads.
----------
CLI result: LintNoFilesFound
----------
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ source: apps/oxlint/src/tester.rs
arguments: --ignore-path fixtures/linter/.customignore fixtures/linter/nan.js
working directory:
----------
Finished in <variable>ms on 0 files with 0 rules using 1 threads.
----------
CLI result: LintNoFilesFound
----------
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
source: apps/oxlint/src/tester.rs
---
##########
arguments: -c fixtures/config_ignore_patterns/ignore_extension/eslintrc.json fixtures/config_ignore_patterns/ignore_extension/main.js
working directory:
----------
Finished in <variable>ms on 0 files with 0 rules using 1 threads.
----------
CLI result: LintNoFilesFound
----------
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
source: apps/oxlint/src/tester.rs
---
##########
arguments: -c ./test/eslintrc.json --ignore-pattern *.ts .
working directory: fixtures/config_ignore_patterns/with_oxlintrc
----------

! ]8;;https://oxc.rs/docs/guide/usage/linter/rules/unicorn/no-empty-file.html\eslint-plugin-unicorn(no-empty-file)]8;;\: Empty files are not allowed.
,-[main.js:1:1]
`----
help: Delete this file or add some code to it.
Found 1 warning and 0 errors.
Finished in <variable>ms on 1 file with 97 rules using 1 threads.
----------
CLI result: LintSucceeded
----------
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
source: apps/oxlint/src/tester.rs
---
##########
arguments: -c .oxlintrc-eslint.json test.js
working directory: fixtures/disable_eslint_and_unicorn_alias_rules
----------
Found 0 warnings and 0 errors.
Finished in <variable>ms on 1 file with 48 rules using 1 threads.
----------
CLI result: LintSucceeded
----------

##########
arguments: -c .oxlintrc-unicorn.json test.js
working directory: fixtures/disable_eslint_and_unicorn_alias_rules
----------
Found 0 warnings and 0 errors.
Finished in <variable>ms on 1 file with 61 rules using 1 threads.
----------
CLI result: LintSucceeded
----------
11 changes: 5 additions & 6 deletions apps/oxlint/src/tester.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use crate::cli::{lint_command, LintRunner};
#[cfg(test)]
use crate::runner::Runner;
#[cfg(test)]
use cow_utils::CowUtils;
#[cfg(test)]
use regex::Regex;
#[cfg(test)]
use std::{env, path::PathBuf};
Expand Down Expand Up @@ -78,10 +80,8 @@ impl Tester {

// do not output the current working directory, each machine has a different one
let cwd_string = current_cwd.to_str().unwrap();
#[allow(clippy::disallowed_methods)]
let cwd_string = cwd_string.replace('\\', "/");
#[allow(clippy::disallowed_methods)]
let output_string = output_string.replace(&cwd_string, "<cwd>");
let cwd_string = cwd_string.cow_replace('\\', "/").to_string(); // for windows
let output_string = output_string.cow_replace(&cwd_string, "<cwd>");

let full_args_list =
multiple_args.iter().map(|args| args.join(" ")).collect::<Vec<String>>().join(" ");
Expand All @@ -90,8 +90,7 @@ impl Tester {

// windows can not handle filenames with *
// allow replace instead of cow_replace. It only test
#[allow(clippy::disallowed_methods)]
let snapshot_file_name = snapshot_file_name.replace('*', "_");
let snapshot_file_name = snapshot_file_name.cow_replace('*', "_").to_string();
settings.bind(|| {
insta::assert_snapshot!(snapshot_file_name, output_string);
});
Expand Down
Loading

0 comments on commit 4cc62fb

Please sign in to comment.