Skip to content

Commit b34e439

Browse files
committed
feat(linter): JS custom rules config
1 parent eaf1c42 commit b34e439

File tree

21 files changed

+648
-130
lines changed

21 files changed

+648
-130
lines changed

apps/oxlint/src/lint.rs

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use ignore::{gitignore::Gitignore, overrides::OverrideBuilder};
1313
use oxc_allocator::AllocatorPool;
1414
use oxc_diagnostics::{DiagnosticService, GraphicalReportHandler, OxcDiagnostic};
1515
use oxc_linter::{
16-
AllowWarnDeny, Config, ConfigStore, ConfigStoreBuilder, ExternalLinter, InvalidFilterKind,
17-
LintFilter, LintOptions, LintService, LintServiceOptions, Linter, Oxlintrc,
16+
AllowWarnDeny, Config, ConfigStore, ConfigStoreBuilder, ExternalLinter, ExternalPluginStore,
17+
InvalidFilterKind, LintFilter, LintOptions, LintService, LintServiceOptions, Linter, Oxlintrc,
1818
};
1919
use rustc_hash::{FxHashMap, FxHashSet};
2020
use serde_json::Value;
@@ -178,13 +178,22 @@ impl Runner for LintRunner {
178178
GraphicalReportHandler::new()
179179
};
180180

181+
let mut external_plugin_store = ExternalPluginStore::default();
182+
181183
let search_for_nested_configs = !disable_nested_config &&
182184
// If the `--config` option is explicitly passed, we should not search for nested config files
183185
// as the passed config file takes absolute precedence.
184186
basic_options.config.is_none();
185187

186188
let nested_configs = if search_for_nested_configs {
187-
match Self::get_nested_configs(stdout, &handler, &filters, &paths, external_linter) {
189+
match Self::get_nested_configs(
190+
stdout,
191+
&handler,
192+
&filters,
193+
&paths,
194+
external_linter,
195+
&mut external_plugin_store,
196+
) {
188197
Ok(v) => v,
189198
Err(v) => return v,
190199
}
@@ -203,21 +212,25 @@ impl Runner for LintRunner {
203212
} else {
204213
None
205214
};
206-
let config_builder =
207-
match ConfigStoreBuilder::from_oxlintrc(false, oxlintrc, external_linter) {
208-
Ok(builder) => builder,
209-
Err(e) => {
210-
print_and_flush_stdout(
211-
stdout,
212-
&format!(
213-
"Failed to parse configuration file.\n{}\n",
214-
render_report(&handler, &OxcDiagnostic::error(e.to_string()))
215-
),
216-
);
217-
return CliRunResult::InvalidOptionConfig;
218-
}
215+
let config_builder = match ConfigStoreBuilder::from_oxlintrc(
216+
false,
217+
oxlintrc,
218+
external_linter,
219+
&mut external_plugin_store,
220+
) {
221+
Ok(builder) => builder,
222+
Err(e) => {
223+
print_and_flush_stdout(
224+
stdout,
225+
&format!(
226+
"Failed to parse configuration file.\n{}\n",
227+
render_report(&handler, &OxcDiagnostic::error(e.to_string()))
228+
),
229+
);
230+
return CliRunResult::InvalidOptionConfig;
219231
}
220-
.with_filters(&filters);
232+
}
233+
.with_filters(&filters);
221234

222235
if let Some(basic_config_file) = oxlintrc_for_print {
223236
let config_file = config_builder.resolve_final_config_file(basic_config_file);
@@ -270,10 +283,13 @@ impl Runner for LintRunner {
270283
_ => None,
271284
};
272285

273-
let linter =
274-
Linter::new(LintOptions::default(), ConfigStore::new(lint_config, nested_configs))
275-
.with_fix(fix_options.fix_kind())
276-
.with_report_unused_directives(report_unused_directives);
286+
let linter = Linter::new(
287+
LintOptions::default(),
288+
ConfigStore::new(lint_config, nested_configs, external_plugin_store),
289+
self.external_linter,
290+
)
291+
.with_fix(fix_options.fix_kind())
292+
.with_report_unused_directives(report_unused_directives);
277293

278294
let tsconfig = basic_options.tsconfig;
279295
if let Some(path) = tsconfig.as_ref() {
@@ -406,6 +422,7 @@ impl LintRunner {
406422
filters: &Vec<LintFilter>,
407423
paths: &Vec<Arc<OsStr>>,
408424
external_linter: Option<&ExternalLinter>,
425+
external_plugin_store: &mut ExternalPluginStore,
409426
) -> Result<FxHashMap<PathBuf, Config>, CliRunResult> {
410427
// TODO(perf): benchmark whether or not it is worth it to store the configurations on a
411428
// per-file or per-directory basis, to avoid calling `.parent()` on every path.
@@ -436,8 +453,12 @@ impl LintRunner {
436453
// iterate over each config and build the ConfigStore
437454
for (dir, oxlintrc) in nested_oxlintrc {
438455
// TODO(refactor): clean up all of the error handling in this function
439-
let builder = match ConfigStoreBuilder::from_oxlintrc(false, oxlintrc, external_linter)
440-
{
456+
let builder = match ConfigStoreBuilder::from_oxlintrc(
457+
false,
458+
oxlintrc,
459+
external_linter,
460+
external_plugin_store,
461+
) {
441462
Ok(builder) => builder,
442463
Err(e) => {
443464
print_and_flush_stdout(

crates/oxc_language_server/src/linter/server_linter.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ use rustc_hash::{FxBuildHasher, FxHashMap};
88
use tower_lsp_server::lsp_types::Uri;
99

1010
use oxc_linter::{
11-
AllowWarnDeny, Config, ConfigStore, ConfigStoreBuilder, LintOptions, Linter, Oxlintrc,
11+
AllowWarnDeny, Config, ConfigStore, ConfigStoreBuilder, ExternalPluginStore, LintOptions,
12+
Linter, Oxlintrc,
1213
};
1314
use tower_lsp_server::UriExt;
1415

@@ -49,8 +50,13 @@ impl ServerLinter {
4950
};
5051

5152
// clone because we are returning it for ignore builder
52-
let config_builder =
53-
ConfigStoreBuilder::from_oxlintrc(false, oxlintrc.clone(), None).unwrap_or_default();
53+
let config_builder = ConfigStoreBuilder::from_oxlintrc(
54+
false,
55+
oxlintrc.clone(),
56+
None,
57+
&mut ExternalPluginStore::default(),
58+
)
59+
.unwrap_or_default();
5460

5561
// TODO(refactor): pull this into a shared function, because in oxlint we have the same functionality.
5662
let use_nested_config = options.use_nested_configs();
@@ -83,9 +89,10 @@ impl ServerLinter {
8389
} else {
8490
FxHashMap::default()
8591
},
92+
ExternalPluginStore::default(),
8693
);
8794

88-
let linter = Linter::new(lint_options, config_store);
95+
let linter = Linter::new(lint_options, config_store, None);
8996

9097
let isolated_linter = IsolatedLintHandler::new(
9198
linter,
@@ -125,8 +132,12 @@ impl ServerLinter {
125132
warn!("Skipping invalid config file: {}", file_path.display());
126133
continue;
127134
};
128-
let Ok(config_store_builder) = ConfigStoreBuilder::from_oxlintrc(false, oxlintrc, None)
129-
else {
135+
let Ok(config_store_builder) = ConfigStoreBuilder::from_oxlintrc(
136+
false,
137+
oxlintrc,
138+
None,
139+
&mut ExternalPluginStore::default(),
140+
) else {
130141
warn!("Skipping config (builder failed): {}", file_path.display());
131142
continue;
132143
};

0 commit comments

Comments
 (0)