Skip to content

Commit bf8263d

Browse files
feat(playground): Allow specifying a JSON string as the linter config (#11710)
When creating bug reports it would be helpful to have a link to a reproduction that just worked in the browser. By adding the ability to config Oxlint here, simple reproductions can be done within the Playground and URLs shared from it. This would be a lot better if the `config` was a JSON object instead of a string, but I don't know how to do that only on the Rust side. An option would be to keep the Rust side a string, but on the browser side allow it to be an object. Whenever the object changes, we serialize that to a string before sending it to the Rust side. If there's interest in this, then I think I can make this change in the playground repo. Example config and screenshots below. ```json "linter": {}, ``` ![image](https://github.com/user-attachments/assets/177cdb75-4a45-4c21-bf8b-2e7f46af56df) ```json "linter": { "config": "{\"plugins\":[\"typescript\"],\"categories\":{\"correctness\":\"error\"},\"rules\":{\"no-debugger\":\"warn\"}}" }, ``` ![image](https://github.com/user-attachments/assets/7a0843c3-d5e3-4002-bb93-964ddcd0629a)
1 parent 4fbe4b1 commit bf8263d

File tree

4 files changed

+33
-8
lines changed

4 files changed

+33
-8
lines changed

crates/oxc_linter/src/config/oxlintrc.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,20 @@ impl Oxlintrc {
149149
Ok(config)
150150
}
151151

152+
/// # Errors
153+
///
154+
/// * Parse Failure
155+
pub fn from_string(json_string: &str) -> Result<Self, OxcDiagnostic> {
156+
let json = serde_json::from_str::<serde_json::Value>(json_string)
157+
.unwrap_or(serde_json::Value::Null);
158+
159+
let config = Self::deserialize(&json).map_err(|err| {
160+
OxcDiagnostic::error(format!("Failed to parse config with error {err:?}"))
161+
})?;
162+
163+
Ok(config)
164+
}
165+
152166
/// Merges two [Oxlintrc] files together
153167
/// [Self] takes priority over `other`
154168
#[must_use]

napi/playground/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export interface OxcControlFlowOptions {
6969
}
7070

7171
export interface OxcLinterOptions {
72-
72+
config?: string
7373
}
7474

7575
export interface OxcMinifierOptions {

napi/playground/src/lib.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ use oxc::{
2929
};
3030
use oxc_formatter::{FormatOptions, Formatter};
3131
use oxc_index::Idx;
32-
use oxc_linter::{ConfigStore, ConfigStoreBuilder, LintOptions, Linter, ModuleRecord};
32+
use oxc_linter::{ConfigStore, ConfigStoreBuilder, LintOptions, Linter, ModuleRecord, Oxlintrc};
3333
use oxc_napi::{Comment, OxcError, convert_utf8_to_utf16};
3434

35-
use crate::options::{OxcOptions, OxcRunOptions};
35+
use crate::options::{OxcLinterOptions, OxcOptions, OxcRunOptions};
3636

3737
mod options;
3838

@@ -94,7 +94,7 @@ impl Oxc {
9494
} = options;
9595
let run_options = run_options.unwrap_or_default();
9696
let parser_options = parser_options.unwrap_or_default();
97-
let _linter_options = linter_options.unwrap_or_default();
97+
let linter_options = linter_options.unwrap_or_default();
9898
let minifier_options = minifier_options.unwrap_or_default();
9999
let codegen_options = codegen_options.unwrap_or_default();
100100
let transform_options = transform_options.unwrap_or_default();
@@ -151,7 +151,7 @@ impl Oxc {
151151
}
152152

153153
let linter_module_record = Arc::new(ModuleRecord::new(&path, &module_record, &semantic));
154-
self.run_linter(&run_options, &path, &program, &linter_module_record);
154+
self.run_linter(&run_options, &linter_options, &path, &program, &linter_module_record);
155155

156156
self.run_formatter(&run_options, &source_text, source_type);
157157

@@ -277,6 +277,7 @@ impl Oxc {
277277
fn run_linter(
278278
&mut self,
279279
run_options: &OxcRunOptions,
280+
linter_options: &OxcLinterOptions,
280281
path: &Path,
281282
program: &Program,
282283
module_record: &Arc<ModuleRecord>,
@@ -285,7 +286,16 @@ impl Oxc {
285286
if run_options.lint.unwrap_or_default() && self.diagnostics.is_empty() {
286287
let semantic_ret = SemanticBuilder::new().with_cfg(true).build(program);
287288
let semantic = Rc::new(semantic_ret.semantic);
288-
let lint_config = ConfigStoreBuilder::default().build();
289+
let lint_config = if linter_options.config.is_some() {
290+
let oxlintrc =
291+
Oxlintrc::from_string(&linter_options.config.as_ref().unwrap().to_string())
292+
.unwrap_or_default();
293+
let config_builder =
294+
ConfigStoreBuilder::from_oxlintrc(false, oxlintrc).unwrap_or_default();
295+
config_builder.build()
296+
} else {
297+
ConfigStoreBuilder::default().build()
298+
};
289299
let linter_ret = Linter::new(
290300
LintOptions::default(),
291301
ConfigStore::new(lint_config, FxHashMap::default()),

napi/playground/src/options.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ pub struct OxcParserOptions {
3838

3939
#[napi(object)]
4040
#[derive(Default)]
41-
#[expect(clippy::empty_structs_with_brackets)]
42-
pub struct OxcLinterOptions {}
41+
pub struct OxcLinterOptions {
42+
pub config: Option<String>,
43+
}
4344

4445
#[napi(object)]
4546
#[derive(Default)]

0 commit comments

Comments
 (0)