-
-
Notifications
You must be signed in to change notification settings - Fork 477
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(linter): split service code into separate modules (#6437)
Refactor in preparation of multi-config/`override` support.
- Loading branch information
Showing
3 changed files
with
175 additions
and
151 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
mod module_cache; | ||
mod runtime; | ||
|
||
use std::{ | ||
path::{Path, PathBuf}, | ||
sync::Arc, | ||
}; | ||
|
||
use oxc_diagnostics::DiagnosticSender; | ||
use rayon::{iter::ParallelBridge, prelude::ParallelIterator}; | ||
|
||
use crate::Linter; | ||
|
||
use module_cache::{CacheState, CacheStateEntry, ModuleMap, ModuleState}; | ||
use runtime::Runtime; | ||
|
||
pub struct LintServiceOptions { | ||
/// Current working directory | ||
cwd: Box<Path>, | ||
|
||
/// All paths to lint | ||
paths: Vec<Box<Path>>, | ||
|
||
/// TypeScript `tsconfig.json` path for reading path alias and project references | ||
tsconfig: Option<PathBuf>, | ||
|
||
cross_module: bool, | ||
} | ||
|
||
impl LintServiceOptions { | ||
#[must_use] | ||
pub fn new<T>(cwd: T, paths: Vec<Box<Path>>) -> Self | ||
where | ||
T: Into<Box<Path>>, | ||
{ | ||
Self { cwd: cwd.into(), paths, tsconfig: None, cross_module: false } | ||
} | ||
|
||
#[inline] | ||
#[must_use] | ||
pub fn with_tsconfig<T>(mut self, tsconfig: T) -> Self | ||
where | ||
T: Into<PathBuf>, | ||
{ | ||
let tsconfig = tsconfig.into(); | ||
// Should this be canonicalized? | ||
let tsconfig = if tsconfig.is_relative() { self.cwd.join(tsconfig) } else { tsconfig }; | ||
debug_assert!(tsconfig.is_file()); | ||
|
||
self.tsconfig = Some(tsconfig); | ||
self | ||
} | ||
|
||
#[inline] | ||
#[must_use] | ||
pub fn with_cross_module(mut self, cross_module: bool) -> Self { | ||
self.cross_module = cross_module; | ||
self | ||
} | ||
|
||
#[inline] | ||
pub fn cwd(&self) -> &Path { | ||
&self.cwd | ||
} | ||
} | ||
|
||
#[derive(Clone)] | ||
pub struct LintService { | ||
runtime: Arc<Runtime>, | ||
} | ||
|
||
impl LintService { | ||
pub fn new(linter: Linter, options: LintServiceOptions) -> Self { | ||
let runtime = Arc::new(Runtime::new(linter, options)); | ||
Self { runtime } | ||
} | ||
|
||
#[cfg(test)] | ||
pub(crate) fn from_linter(linter: Linter, options: LintServiceOptions) -> Self { | ||
let runtime = Arc::new(Runtime::new(linter, options)); | ||
Self { runtime } | ||
} | ||
|
||
pub fn linter(&self) -> &Linter { | ||
&self.runtime.linter | ||
} | ||
|
||
pub fn number_of_dependencies(&self) -> usize { | ||
self.runtime.module_map.len() - self.runtime.paths.len() | ||
} | ||
|
||
/// # Panics | ||
pub fn run(&self, tx_error: &DiagnosticSender) { | ||
self.runtime | ||
.paths | ||
.iter() | ||
.par_bridge() | ||
.for_each_with(&self.runtime, |runtime, path| runtime.process_path(path, tx_error)); | ||
tx_error.send(None).unwrap(); | ||
} | ||
|
||
/// For tests | ||
#[cfg(test)] | ||
pub(crate) fn run_source<'a>( | ||
&self, | ||
allocator: &'a oxc_allocator::Allocator, | ||
source_text: &'a str, | ||
check_syntax_errors: bool, | ||
tx_error: &DiagnosticSender, | ||
) -> Vec<crate::Message<'a>> { | ||
self.runtime | ||
.paths | ||
.iter() | ||
.flat_map(|path| { | ||
let source_type = oxc_span::SourceType::from_path(path).unwrap(); | ||
self.runtime.init_cache_state(path); | ||
self.runtime.process_source( | ||
path, | ||
allocator, | ||
source_text, | ||
source_type, | ||
check_syntax_errors, | ||
tx_error, | ||
) | ||
}) | ||
.collect::<Vec<_>>() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
use std::{ | ||
path::Path, | ||
sync::{Arc, Condvar, Mutex}, | ||
}; | ||
|
||
use dashmap::DashMap; | ||
use oxc_semantic::ModuleRecord; | ||
use rustc_hash::FxHashMap; | ||
|
||
/// `CacheState` and `CacheStateEntry` are used to fix the problem where | ||
/// there is a brief moment when a concurrent fetch can miss the cache. | ||
/// | ||
/// Given `ModuleMap` is a `DashMap`, which conceptually is a `RwLock<HashMap>`. | ||
/// When two requests read the map at the exact same time from different threads, | ||
/// both will miss the cache so both thread will make a request. | ||
/// | ||
/// See the "problem section" in <https://medium.com/@polyglot_factotum/rust-concurrency-patterns-condvars-and-locks-e278f18db74f> | ||
/// and the solution is copied here to fix the issue. | ||
pub(super) type CacheState = Mutex<FxHashMap<Box<Path>, Arc<(Mutex<CacheStateEntry>, Condvar)>>>; | ||
|
||
#[derive(Clone, Copy, Debug, Eq, PartialEq)] | ||
pub(super) enum CacheStateEntry { | ||
ReadyToConstruct, | ||
PendingStore(usize), | ||
} | ||
|
||
/// Keyed by canonicalized path | ||
pub(super) type ModuleMap = DashMap<Box<Path>, ModuleState>; | ||
|
||
#[derive(Clone)] | ||
pub(super) enum ModuleState { | ||
Resolved(Arc<ModuleRecord>), | ||
Ignored, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters