|
1 | 1 | use std::{ |
2 | | - env, fs, |
| 2 | + env, |
| 3 | + ffi::OsStr, |
| 4 | + fs, |
3 | 5 | io::{ErrorKind, Write}, |
4 | 6 | path::{Path, PathBuf, absolute}, |
| 7 | + sync::Arc, |
5 | 8 | time::Instant, |
6 | 9 | }; |
7 | 10 |
|
@@ -166,71 +169,16 @@ impl Runner for LintRunner { |
166 | 169 | let paths = walker.paths(); |
167 | 170 | let number_of_files = paths.len(); |
168 | 171 |
|
169 | | - // TODO(perf): benchmark whether or not it is worth it to store the configurations on a |
170 | | - // per-file or per-directory basis, to avoid calling `.parent()` on every path. |
171 | | - let mut nested_oxlintrc = FxHashMap::<&Path, Oxlintrc>::default(); |
172 | | - let mut nested_configs = FxHashMap::<PathBuf, ConfigStore>::default(); |
173 | | - |
174 | 172 | let handler = GraphicalReportHandler::new(); |
175 | 173 |
|
176 | | - if search_for_nested_configs { |
177 | | - // get all of the unique directories among the paths to use for search for |
178 | | - // oxlint config files in those directories and their ancestors |
179 | | - // e.g. `/some/file.js` will check `/some` and `/` |
180 | | - // `/some/other/file.js` will check `/some/other`, `/some`, and `/` |
181 | | - let mut directories = FxHashSet::default(); |
182 | | - for path in &paths { |
183 | | - let path = Path::new(path); |
184 | | - // Start from the file's parent directory and walk up the tree |
185 | | - let mut current = path.parent(); |
186 | | - while let Some(dir) = current { |
187 | | - // NOTE: Initial benchmarking showed that it was faster to iterate over the directories twice |
188 | | - // rather than constructing the configs in one iteration. It's worth re-benchmarking that though. |
189 | | - directories.insert(dir); |
190 | | - current = dir.parent(); |
191 | | - } |
| 174 | + let nested_configs = if search_for_nested_configs { |
| 175 | + match Self::get_nested_configs(stdout, &handler, &filters, &paths) { |
| 176 | + Ok(v) => v, |
| 177 | + Err(v) => return v, |
192 | 178 | } |
193 | | - for directory in directories { |
194 | | - if let Ok(config) = Self::find_oxlint_config_in_directory(directory) { |
195 | | - nested_oxlintrc.insert(directory, config); |
196 | | - } |
197 | | - } |
198 | | - |
199 | | - // iterate over each config and build the ConfigStore |
200 | | - for (dir, oxlintrc) in nested_oxlintrc { |
201 | | - // TODO(refactor): clean up all of the error handling in this function |
202 | | - let builder = match ConfigStoreBuilder::from_oxlintrc(false, oxlintrc) { |
203 | | - Ok(builder) => builder, |
204 | | - Err(e) => { |
205 | | - print_and_flush_stdout( |
206 | | - stdout, |
207 | | - &format!( |
208 | | - "Failed to parse configuration file.\n{}\n", |
209 | | - render_report(&handler, &OxcDiagnostic::error(e.to_string())) |
210 | | - ), |
211 | | - ); |
212 | | - |
213 | | - return CliRunResult::InvalidOptionConfig; |
214 | | - } |
215 | | - } |
216 | | - .with_filters(&filters); |
217 | | - |
218 | | - match builder.build() { |
219 | | - Ok(config) => nested_configs.insert(dir.to_path_buf(), config), |
220 | | - Err(diagnostic) => { |
221 | | - print_and_flush_stdout( |
222 | | - stdout, |
223 | | - &format!( |
224 | | - "Failed to parse configuration file.\n{}\n", |
225 | | - render_report(&handler, &diagnostic) |
226 | | - ), |
227 | | - ); |
228 | | - |
229 | | - return CliRunResult::InvalidOptionConfig; |
230 | | - } |
231 | | - }; |
232 | | - } |
233 | | - } |
| 179 | + } else { |
| 180 | + FxHashMap::default() |
| 181 | + }; |
234 | 182 |
|
235 | 183 | enable_plugins.apply_overrides(&mut oxlintrc.plugins); |
236 | 184 |
|
@@ -447,6 +395,76 @@ impl LintRunner { |
447 | 395 | Ok(filters) |
448 | 396 | } |
449 | 397 |
|
| 398 | + fn get_nested_configs( |
| 399 | + stdout: &mut dyn Write, |
| 400 | + handler: &GraphicalReportHandler, |
| 401 | + filters: &Vec<LintFilter>, |
| 402 | + paths: &Vec<Arc<OsStr>>, |
| 403 | + ) -> Result<FxHashMap<PathBuf, ConfigStore>, CliRunResult> { |
| 404 | + // TODO(perf): benchmark whether or not it is worth it to store the configurations on a |
| 405 | + // per-file or per-directory basis, to avoid calling `.parent()` on every path. |
| 406 | + let mut nested_oxlintrc = FxHashMap::<&Path, Oxlintrc>::default(); |
| 407 | + let mut nested_configs = FxHashMap::<PathBuf, ConfigStore>::default(); |
| 408 | + // get all of the unique directories among the paths to use for search for |
| 409 | + // oxlint config files in those directories and their ancestors |
| 410 | + // e.g. `/some/file.js` will check `/some` and `/` |
| 411 | + // `/some/other/file.js` will check `/some/other`, `/some`, and `/` |
| 412 | + let mut directories = FxHashSet::default(); |
| 413 | + for path in paths { |
| 414 | + let path = Path::new(path); |
| 415 | + // Start from the file's parent directory and walk up the tree |
| 416 | + let mut current = path.parent(); |
| 417 | + while let Some(dir) = current { |
| 418 | + // NOTE: Initial benchmarking showed that it was faster to iterate over the directories twice |
| 419 | + // rather than constructing the configs in one iteration. It's worth re-benchmarking that though. |
| 420 | + directories.insert(dir); |
| 421 | + current = dir.parent(); |
| 422 | + } |
| 423 | + } |
| 424 | + for directory in directories { |
| 425 | + if let Ok(config) = Self::find_oxlint_config_in_directory(directory) { |
| 426 | + nested_oxlintrc.insert(directory, config); |
| 427 | + } |
| 428 | + } |
| 429 | + |
| 430 | + // iterate over each config and build the ConfigStore |
| 431 | + for (dir, oxlintrc) in nested_oxlintrc { |
| 432 | + // TODO(refactor): clean up all of the error handling in this function |
| 433 | + let builder = match ConfigStoreBuilder::from_oxlintrc(false, oxlintrc) { |
| 434 | + Ok(builder) => builder, |
| 435 | + Err(e) => { |
| 436 | + print_and_flush_stdout( |
| 437 | + stdout, |
| 438 | + &format!( |
| 439 | + "Failed to parse configuration file.\n{}\n", |
| 440 | + render_report(handler, &OxcDiagnostic::error(e.to_string())) |
| 441 | + ), |
| 442 | + ); |
| 443 | + |
| 444 | + return Err(CliRunResult::InvalidOptionConfig); |
| 445 | + } |
| 446 | + } |
| 447 | + .with_filters(filters); |
| 448 | + |
| 449 | + match builder.build() { |
| 450 | + Ok(config) => nested_configs.insert(dir.to_path_buf(), config), |
| 451 | + Err(diagnostic) => { |
| 452 | + print_and_flush_stdout( |
| 453 | + stdout, |
| 454 | + &format!( |
| 455 | + "Failed to parse configuration file.\n{}\n", |
| 456 | + render_report(handler, &diagnostic) |
| 457 | + ), |
| 458 | + ); |
| 459 | + |
| 460 | + return Err(CliRunResult::InvalidOptionConfig); |
| 461 | + } |
| 462 | + }; |
| 463 | + } |
| 464 | + |
| 465 | + Ok(nested_configs) |
| 466 | + } |
| 467 | + |
450 | 468 | // finds the oxlint config |
451 | 469 | // when config is provided, but not found, an String with the formatted error is returned, else the oxlintrc config file is returned |
452 | 470 | // when no config is provided, it will search for the default file names in the current working directory |
|
0 commit comments