Skip to content

Commit

Permalink
feat(linter): support read env from eslintrc (#2130)
Browse files Browse the repository at this point in the history
  • Loading branch information
fi3ework authored Jan 26, 2024
1 parent e5719e9 commit ee5b968
Show file tree
Hide file tree
Showing 21 changed files with 2,237 additions and 94 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"env": {
"browser": true
},
"rules": {
"no-undef": "error"
}
}
5 changes: 5 additions & 0 deletions crates/oxc_cli/fixtures/eslintrc_env/eslintrc_no_env.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"no-undef": "error"
}
}
1 change: 1 addition & 0 deletions crates/oxc_cli/fixtures/eslintrc_env/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('')
23 changes: 23 additions & 0 deletions crates/oxc_cli/src/lint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,29 @@ mod test {
assert_eq!(result.number_of_errors, 0);
}

#[test]
fn eslintrc_no_env() {
let args =
&["-c", "fixtures/eslintrc_env/eslintrc_no_env.json", "fixtures/eslintrc_env/test.js"];
let result = test(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 1);
assert_eq!(result.number_of_errors, 0);
}

#[test]
fn eslintrc_with_env() {
let args = &[
"-c",
"fixtures/eslintrc_env/eslintrc_env_browser.json",
"fixtures/eslintrc_env/test.js",
];
let result = test(args);
assert_eq!(result.number_of_files, 1);
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 0);
}

#[test]
fn no_empty_allow_empty_catch() {
let args = &[
Expand Down
32 changes: 28 additions & 4 deletions crates/oxc_linter/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use oxc_diagnostics::{Error, FailedToOpenFileError, Report};
use rustc_hash::{FxHashMap, FxHashSet};
use serde_json::Value;

use crate::{rules::RuleEnum, settings::Nextjs, AllowWarnDeny, JsxA11y, LintSettings};
use crate::{rules::RuleEnum, settings::Nextjs, AllowWarnDeny, Env, JsxA11y, LintSettings};

use self::errors::{
FailedToParseConfigError, FailedToParseConfigJsonError, FailedToParseJsonc,
Expand All @@ -15,6 +15,7 @@ use self::errors::{
pub struct ESLintConfig {
rules: Vec<ESLintRuleConfig>,
settings: LintSettings,
env: Env,
}

#[derive(Debug)]
Expand All @@ -30,11 +31,12 @@ impl ESLintConfig {
let json = Self::read_json(path)?;
let rules = parse_rules(&json)?;
let settings = parse_settings_from_root(&json);
Ok(Self { rules, settings })
let env = parse_env_from_root(&json);
Ok(Self { rules, settings, env })
}

pub fn settings(self) -> LintSettings {
self.settings
pub fn properties(self) -> (LintSettings, Env) {
(self.settings, self.env)
}

fn read_json(path: &Path) -> Result<serde_json::Value, Error> {
Expand Down Expand Up @@ -201,6 +203,28 @@ pub fn parse_settings(setting_value: &Value) -> LintSettings {
LintSettings::default()
}

fn parse_env_from_root(root_json: &Value) -> Env {
let Value::Object(root_object) = root_json else { return Env::default() };

let Some(env_value) = root_object.get("env") else { return Env::default() };

let env_object = match env_value {
Value::Object(env_object) => env_object,
_ => return Env::default(),
};

let mut result = vec![];
for (k, v) in env_object {
if let Value::Bool(v) = v {
if *v {
result.push(String::from(k));
}
}
}

Env::new(result)
}

fn parse_rule_name(name: &str) -> (&str, &str) {
if let Some((category, name)) = name.split_once('/') {
let category = category.trim_start_matches('@');
Expand Down
27 changes: 26 additions & 1 deletion crates/oxc_linter/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use oxc_span::SourceType;
use crate::{
disable_directives::{DisableDirectives, DisableDirectivesBuilder},
fixer::{Fix, Message},
AstNode, LintSettings,
javascript_globals::GLOBALS,
AstNode, Env, LintSettings,
};

pub struct LintContext<'a> {
Expand All @@ -26,6 +27,8 @@ pub struct LintContext<'a> {
file_path: Box<Path>,

settings: Arc<LintSettings>,

env: Arc<Env>,
}

impl<'a> LintContext<'a> {
Expand All @@ -40,6 +43,7 @@ impl<'a> LintContext<'a> {
current_rule_name: "",
file_path,
settings: Arc::new(LintSettings::default()),
env: Arc::new(Env::default()),
}
}

Expand All @@ -55,6 +59,12 @@ impl<'a> LintContext<'a> {
self
}

#[must_use]
pub fn with_env(mut self, env: &Arc<Env>) -> Self {
self.env = Arc::clone(env);
self
}

pub fn semantic(&self) -> &Rc<Semantic<'a>> {
&self.semantic
}
Expand All @@ -79,6 +89,21 @@ impl<'a> LintContext<'a> {
&self.file_path
}

pub fn envs(&self) -> &Env {
&self.env
}

pub fn env_contains_var(&self, var: &str) -> bool {
for env in self.env.iter() {
let env = GLOBALS.get(env).unwrap_or(&GLOBALS["builtin"]);
if env.get(var).is_some() {
return true;
}
}

false
}

#[inline]
pub fn with_rule_name(&mut self, name: &'static str) {
self.current_rule_name = name;
Expand Down
25 changes: 25 additions & 0 deletions crates/oxc_linter/src/env.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use std::{self, ops::Deref};

#[derive(Debug, Clone)]
pub struct Env(Vec<String>);

impl Env {
pub fn new(env: Vec<String>) -> Self {
Self(env)
}
}

/// The `env` field from ESLint config
impl Default for Env {
fn default() -> Self {
Self(vec!["builtin".to_string()])
}
}

impl Deref for Env {
type Target = Vec<String>;

fn deref(&self) -> &Self::Target {
&self.0
}
}
74 changes: 0 additions & 74 deletions crates/oxc_linter/src/globals.rs
Original file line number Diff line number Diff line change
@@ -1,79 +1,5 @@
//! [Globals](https://github.com/sindresorhus/globals/blob/main/globals.json)
//! Each global is given a value of true or false.
//! A value of true indicates that the variable may be overwritten.
//! A value of false indicates that the variable should be considered read-only.

use phf::{phf_map, phf_set, Map};

pub const BUILTINS: Map<&'static str, bool> = phf_map! {
"AggregateError" => false,
"Array" => false,
"ArrayBuffer" => false,
"Atomics" => false,
"BigInt" => false,
"BigInt64Array" => false,
"BigUint64Array" => false,
"Boolean" => false,
"constructor" => false,
"DataView" => false,
"Date" => false,
"decodeURI" => false,
"decodeURIComponent" => false,
"encodeURI" => false,
"encodeURIComponent" => false,
"Error" => false,
"escape" => false,
"eval" => false,
"EvalError" => false,
"FinalizationRegistry" => false,
"Float32Array" => false,
"Float64Array" => false,
"Function" => false,
"globalThis" => false,
"hasOwnProperty" => false,
"Infinity" => false,
"Int16Array" => false,
"Int32Array" => false,
"Int8Array" => false,
"isFinite" => false,
"isNaN" => false,
"isPrototypeOf" => false,
"JSON" => false,
"Map" => false,
"Math" => false,
"NaN" => false,
"Number" => false,
"Object" => false,
"parseFloat" => false,
"parseInt" => false,
"Promise" => false,
"propertyIsEnumerable" => false,
"Proxy" => false,
"RangeError" => false,
"ReferenceError" => false,
"Reflect" => false,
"RegExp" => false,
"Set" => false,
"SharedArrayBuffer" => false,
"String" => false,
"Symbol" => false,
"Diagnostic" => false,
"toLocaleString" => false,
"toString" => false,
"TypeError" => false,
"Uint16Array" => false,
"Uint32Array" => false,
"Uint8Array" => false,
"Uint8ClampedArray" => false,
"undefined" => false,
"unescape" => false,
"URIError" => false,
"valueOf" => false,
"WeakMap" => false,
"WeakRef" => false,
"WeakSet" => false
};

pub const PRE_DEFINE_VAR: Map<&'static str, bool> = phf_map! {
"undefined" => false,
"Infinity" => false,
Expand Down
Loading

0 comments on commit ee5b968

Please sign in to comment.