diff --git a/apps/oxfmt/src/command.rs b/apps/oxfmt/src/command.rs index 265468268e087..dac32b171e31e 100644 --- a/apps/oxfmt/src/command.rs +++ b/apps/oxfmt/src/command.rs @@ -63,6 +63,10 @@ pub struct BasicOptions { /// Ignore Options #[derive(Debug, Clone, Bpaf)] pub struct IgnoreOptions { + /// Path to ignore file(s). Can be specified multiple times. + /// If not specified, .gitignore and .prettierignore in the current directory are used. + #[bpaf(argument("PATH"), many)] + pub ignore_path: Vec, /// Format code in node_modules directory (skipped by default) #[bpaf(switch, hide_usage)] pub with_node_modules: bool, diff --git a/apps/oxfmt/src/format.rs b/apps/oxfmt/src/format.rs index d639427a47143..40fbcc1b50b06 100644 --- a/apps/oxfmt/src/format.rs +++ b/apps/oxfmt/src/format.rs @@ -60,7 +60,12 @@ impl FormatRunner { } }; - let walker = match Walk::build(&cwd, &paths, ignore_options.with_node_modules) { + let walker = match Walk::build( + &cwd, + &paths, + &ignore_options.ignore_path, + ignore_options.with_node_modules, + ) { Ok(walker) => walker, Err(err) => { print_and_flush_stdout( diff --git a/apps/oxfmt/src/walk.rs b/apps/oxfmt/src/walk.rs index a74238bf0da70..6257f0fad7205 100644 --- a/apps/oxfmt/src/walk.rs +++ b/apps/oxfmt/src/walk.rs @@ -16,6 +16,7 @@ impl Walk { pub fn build( cwd: &PathBuf, paths: &[PathBuf], + ignore_paths: &[PathBuf], with_node_modules: bool, ) -> Result { let (target_paths, exclude_patterns) = normalize_paths(cwd, paths); @@ -44,12 +45,12 @@ impl Walk { inner.overrides(overrides); } - // TODO: Support ignoring files - // --ignore-path PATH1 --ignore-path PATH2 - // or default cwd/{.gitignore,.prettierignore} - // if let Some(err) = inner.add_ignore(path) { - // return Err(format!("Failed to add ignore file: {}", err)); - // } + // Handle ignore files + for ignore_path in load_ignore_paths(cwd, ignore_paths) { + if inner.add_ignore(&ignore_path).is_some() { + return Err(format!("Failed to add ignore file: {}", ignore_path.display())); + } + } // NOTE: If return `false` here, it will not be `visit()`ed at all inner.filter_entry(move |entry| { @@ -92,7 +93,10 @@ impl Walk { .hidden(false) // Do not respect `.gitignore` automatically, we handle it manually .ignore(false) + .parents(false) .git_global(false) + .git_ignore(false) + .git_exclude(false) .build_parallel(); Ok(Self { inner }) } @@ -155,6 +159,25 @@ fn normalize_paths(cwd: &Path, input_paths: &[PathBuf]) -> (Vec, Vec Vec { + // If specified, just resolves absolute paths + if !ignore_paths.is_empty() { + return ignore_paths + .iter() + .map(|path| if path.is_absolute() { path.clone() } else { cwd.join(path) }) + .collect(); + } + + // Else, search for default ignore files in cwd + [".gitignore", ".prettierignore"] + .iter() + .filter_map(|file_name| { + let path = cwd.join(file_name); + if path.exists() { Some(path) } else { None } + }) + .collect::>() +} + // --- pub struct WalkEntry { diff --git a/apps/oxfmt/tests/fixtures/ignore_patterns/.prettierignore b/apps/oxfmt/tests/fixtures/ignore_patterns/.prettierignore new file mode 100644 index 0000000000000..6ab72ded3385e --- /dev/null +++ b/apps/oxfmt/tests/fixtures/ignore_patterns/.prettierignore @@ -0,0 +1 @@ +not-formatted/ diff --git a/apps/oxfmt/tests/fixtures/ignore_patterns/custom.ignore b/apps/oxfmt/tests/fixtures/ignore_patterns/custom.ignore new file mode 100644 index 0000000000000..8007d41d5794e --- /dev/null +++ b/apps/oxfmt/tests/fixtures/ignore_patterns/custom.ignore @@ -0,0 +1 @@ +ignored/ diff --git a/apps/oxfmt/tests/fixtures/ignore_patterns/formatted/good.js b/apps/oxfmt/tests/fixtures/ignore_patterns/formatted/good.js new file mode 100644 index 0000000000000..4e6a6de65314d --- /dev/null +++ b/apps/oxfmt/tests/fixtures/ignore_patterns/formatted/good.js @@ -0,0 +1 @@ +class Foo {} diff --git a/apps/oxfmt/tests/fixtures/ignore_patterns/gitignore.txt b/apps/oxfmt/tests/fixtures/ignore_patterns/gitignore.txt new file mode 100644 index 0000000000000..8007d41d5794e --- /dev/null +++ b/apps/oxfmt/tests/fixtures/ignore_patterns/gitignore.txt @@ -0,0 +1 @@ +ignored/ diff --git a/apps/oxfmt/tests/fixtures/ignore_patterns/good.ts b/apps/oxfmt/tests/fixtures/ignore_patterns/good.ts new file mode 100644 index 0000000000000..4e6a6de65314d --- /dev/null +++ b/apps/oxfmt/tests/fixtures/ignore_patterns/good.ts @@ -0,0 +1 @@ +class Foo {} diff --git a/apps/oxfmt/tests/fixtures/ignore_patterns/ignored/should-be-ignored.js b/apps/oxfmt/tests/fixtures/ignore_patterns/ignored/should-be-ignored.js new file mode 100644 index 0000000000000..a969b65721867 --- /dev/null +++ b/apps/oxfmt/tests/fixtures/ignore_patterns/ignored/should-be-ignored.js @@ -0,0 +1 @@ +class Baz { } diff --git a/apps/oxfmt/tests/fixtures/ignore_patterns/ignored/should-be-ignored.ts b/apps/oxfmt/tests/fixtures/ignore_patterns/ignored/should-be-ignored.ts new file mode 100644 index 0000000000000..0cc1f93d0ab2a --- /dev/null +++ b/apps/oxfmt/tests/fixtures/ignore_patterns/ignored/should-be-ignored.ts @@ -0,0 +1 @@ +class Baz2 { } diff --git a/apps/oxfmt/tests/fixtures/ignore_patterns/not-formatted/.prettierignore b/apps/oxfmt/tests/fixtures/ignore_patterns/not-formatted/.prettierignore new file mode 100644 index 0000000000000..7895baf4cb178 --- /dev/null +++ b/apps/oxfmt/tests/fixtures/ignore_patterns/not-formatted/.prettierignore @@ -0,0 +1,3 @@ +# This should be ignored - only cwd/.prettierignore should be used +*.js +*.ts diff --git a/apps/oxfmt/tests/fixtures/ignore_patterns/not-formatted/bad.js b/apps/oxfmt/tests/fixtures/ignore_patterns/not-formatted/bad.js new file mode 100644 index 0000000000000..5372dab32e4e1 --- /dev/null +++ b/apps/oxfmt/tests/fixtures/ignore_patterns/not-formatted/bad.js @@ -0,0 +1 @@ +class Bar { } diff --git a/apps/oxfmt/tests/fixtures/ignore_patterns/not-formatted/bad.ts b/apps/oxfmt/tests/fixtures/ignore_patterns/not-formatted/bad.ts new file mode 100644 index 0000000000000..0c8417c70e2cd --- /dev/null +++ b/apps/oxfmt/tests/fixtures/ignore_patterns/not-formatted/bad.ts @@ -0,0 +1 @@ +class Qux { } diff --git a/apps/oxfmt/tests/mod.rs b/apps/oxfmt/tests/mod.rs index 910302ee90cdf..4ddddbae7e2e8 100644 --- a/apps/oxfmt/tests/mod.rs +++ b/apps/oxfmt/tests/mod.rs @@ -135,3 +135,25 @@ fn exclude_nested_paths_with_dot() { &["--check", "./foo", "!foo/bar"], ]); } + +#[test] +fn ignore_patterns() { + // Test ignore file handling with different configurations + // .prettierignore (cwd) contains: not-formatted/ + // not-formatted/.prettierignore (subdirectory) should be ignored + // gitignore.txt contains: ignored/ + // custom.ignore contains: ignored/ (only) + Tester::new() + .with_cwd(PathBuf::from("tests/fixtures/ignore_patterns")) + .test_and_snapshot_multiple(&[ + // Default: auto-detects only cwd/.prettierignore (ignores not-formatted/ dir) + // Note: not-formatted/.prettierignore exists but should be ignored + &["--check"], + // Explicit: uses gitignore.txt (ignores ignored/ dir, checks not-formatted/) + &["--check", "--ignore-path", "gitignore.txt"], + // Multiple files: ignores both dirs + &["--check", "--ignore-path", "gitignore.txt", "--ignore-path", ".prettierignore"], + // Nonexistent file should error + &["--check", "--ignore-path", "nonexistent.ignore"], + ]); +} diff --git a/apps/oxfmt/tests/snapshots/tests__fixtures__ignore_patterns_--check --check --ignore-path gitignore.txt --check --ignore-path gitignore.txt --ignore-path .prettierignore --check --ignore-path nonexistent.ignore@oxfmt.snap b/apps/oxfmt/tests/snapshots/tests__fixtures__ignore_patterns_--check --check --ignore-path gitignore.txt --check --ignore-path gitignore.txt --ignore-path .prettierignore --check --ignore-path nonexistent.ignore@oxfmt.snap new file mode 100644 index 0000000000000..71e748ca05365 --- /dev/null +++ b/apps/oxfmt/tests/snapshots/tests__fixtures__ignore_patterns_--check --check --ignore-path gitignore.txt --check --ignore-path gitignore.txt --ignore-path .prettierignore --check --ignore-path nonexistent.ignore@oxfmt.snap @@ -0,0 +1,52 @@ +--- +source: apps/oxfmt/tests/tester.rs +--- +########## +arguments: --check +working directory: tests/fixtures/ignore_patterns +---------- +Checking formatting... +ignored/should-be-ignored.js (ms) +ignored/should-be-ignored.ts (ms) + +Format issues found in above 2 files. Run without `--check` to fix. +Finished in ms on 4 files using 1 threads. +---------- +CLI result: FormatMismatch +---------- + +########## +arguments: --check --ignore-path gitignore.txt +working directory: tests/fixtures/ignore_patterns +---------- +Checking formatting... +not-formatted/bad.js (ms) +not-formatted/bad.ts (ms) + +Format issues found in above 2 files. Run without `--check` to fix. +Finished in ms on 4 files using 1 threads. +---------- +CLI result: FormatMismatch +---------- + +########## +arguments: --check --ignore-path gitignore.txt --ignore-path .prettierignore +working directory: tests/fixtures/ignore_patterns +---------- +Checking formatting... + +All matched files use the correct format. +Finished in ms on 2 files using 1 threads. +---------- +CLI result: FormatSucceeded +---------- + +########## +arguments: --check --ignore-path nonexistent.ignore +working directory: tests/fixtures/ignore_patterns +---------- +Failed to parse target paths or ignore settings. +Failed to add ignore file: /tests/fixtures/ignore_patterns/nonexistent.ignore +---------- +CLI result: InvalidOptionConfig +----------