diff --git a/crates/rome_diagnostics_categories/src/categories.rs b/crates/rome_diagnostics_categories/src/categories.rs index 122a1ce801d..8253ea37c1e 100644 --- a/crates/rome_diagnostics_categories/src/categories.rs +++ b/crates/rome_diagnostics_categories/src/categories.rs @@ -87,6 +87,7 @@ define_dategories! { "lint/nursery/noPrecisionLoss": "https://docs.rome.tools/lint/rules/noPrecisionLoss", "lint/nursery/noStringCaseMismatch": "https://docs.rome.tools/lint/rules/noStringCaseMismatch", "lint/nursery/noUnsafeFinally": "https://docs.rome.tools/lint/rules/noUnsafeFinally", + "lint/nursery/noVar": "https://docs.rome.tools/lint/rules/noVar", "lint/nursery/useCamelCase": "https://docs.rome.tools/lint/rules/useCamelCase", "lint/nursery/useConst":"https://docs.rome.tools/lint/rules/useConst", "lint/nursery/useExhaustiveDependencies": "https://docs.rome.tools/lint/rules/useExhaustiveDependencies", diff --git a/crates/rome_js_analyze/src/control_flow.rs b/crates/rome_js_analyze/src/control_flow.rs index 93f7161fb7a..d48712a9515 100644 --- a/crates/rome_js_analyze/src/control_flow.rs +++ b/crates/rome_js_analyze/src/control_flow.rs @@ -7,3 +7,4 @@ mod nodes; mod visitor; pub(crate) use self::visitor::make_visitor; +pub(crate) use self::visitor::JsAnyControlFlowRoot; diff --git a/crates/rome_js_analyze/src/control_flow/visitor.rs b/crates/rome_js_analyze/src/control_flow/visitor.rs index bee27fbd8b0..ddfb715545b 100644 --- a/crates/rome_js_analyze/src/control_flow/visitor.rs +++ b/crates/rome_js_analyze/src/control_flow/visitor.rs @@ -156,7 +156,7 @@ pub(super) struct FunctionVisitor { } declare_node_union! { - JsAnyControlFlowRoot = JsModule + pub(crate) JsAnyControlFlowRoot = JsModule | JsScript | JsAnyFunction | JsGetterObjectMember diff --git a/crates/rome_js_analyze/src/semantic_analyzers/nursery.rs b/crates/rome_js_analyze/src/semantic_analyzers/nursery.rs index 4fb985da48e..f1747ae207f 100644 --- a/crates/rome_js_analyze/src/semantic_analyzers/nursery.rs +++ b/crates/rome_js_analyze/src/semantic_analyzers/nursery.rs @@ -2,7 +2,8 @@ use rome_analyze::declare_group; mod no_const_assign; +mod no_var; mod use_camel_case; mod use_const; mod use_exhaustive_dependencies; -declare_group! { pub (crate) Nursery { name : "nursery" , rules : [self :: no_const_assign :: NoConstAssign , self :: use_camel_case :: UseCamelCase , self :: use_const :: UseConst , self :: use_exhaustive_dependencies :: UseExhaustiveDependencies ,] } } +declare_group! { pub (crate) Nursery { name : "nursery" , rules : [self :: no_const_assign :: NoConstAssign , self :: no_var :: NoVar , self :: use_camel_case :: UseCamelCase , self :: use_const :: UseConst , self :: use_exhaustive_dependencies :: UseExhaustiveDependencies ,] } } diff --git a/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_var.rs b/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_var.rs new file mode 100644 index 00000000000..7e21988ff42 --- /dev/null +++ b/crates/rome_js_analyze/src/semantic_analyzers/nursery/no_var.rs @@ -0,0 +1,101 @@ +use crate::{control_flow::JsAnyControlFlowRoot, semantic_services::Semantic, JsRuleAction}; +use rome_analyze::{context::RuleContext, declare_rule, ActionCategory, Rule, RuleDiagnostic}; +use rome_console::markup; +use rome_diagnostics::Applicability; +use rome_js_factory::make; +use rome_js_syntax::{JsModule, JsScript, JsSyntaxKind}; + +use rome_rowan::{AstNode, BatchMutationExt}; + +use super::use_const::{ConstBindings, VariableDeclaration}; + +declare_rule! { + /// Disallow the use of `var` + /// + /// ECMAScript 6 allows programmers to create variables with block scope instead of function scope using the let and const keywords. Block scope is common in many other programming languages and helps programmers avoid mistakes. + /// + /// Source: https://eslint.org/docs/latest/rules/no-var + /// + /// ## Examples + /// + /// ### Invalid + /// + /// ```js,expect_diagnostic + /// var foo = 1; + /// ``` + /// + /// ### Valid + /// + /// ```js + /// const foo = 1; + /// let bar = 1; + ///``` + pub(crate) NoVar { + version: "11.0.0", + name: "noVar", + recommended: false, + } +} + +impl Rule for NoVar { + type Query = Semantic; + type State = (); + type Signals = Option; + type Options = (); + + fn run(ctx: &RuleContext) -> Self::Signals { + let declaration = ctx.query(); + declaration.is_var().then_some(()) + } + + fn diagnostic(ctx: &RuleContext, _state: &Self::State) -> Option { + let declaration = ctx.query(); + let var_scope = declaration + .syntax() + .ancestors() + .find(|x| JsAnyControlFlowRoot::can_cast(x.kind()))?; + let contextual_note = if JsScript::can_cast(var_scope.kind()) { + markup! { + "A variable declared with ""var"" in the global scope pollutes the global object." + } + } else if JsModule::can_cast(var_scope.kind()) { + markup! { + "A variable declared with ""var"" is accessible in the whole module. Thus, the variable can be accessed before its initialization and outside the block where it is declared." + } + } else { + markup! { + "A variable declared with ""var"" is accessible in the whole body of the function. Thus, the variable can be accessed before its initialization and outside the block where it is declared." + } + }; + Some(RuleDiagnostic::new( + rule_category!(), + declaration.range(), + markup! { + "Use ""let"" or ""const"" instead of ""var""." + }, + ).note(contextual_note).note( + markup! { + "See ""MDN web docs"" for more details." + } + )) + } + + fn action(ctx: &RuleContext, _: &Self::State) -> Option { + let declaration = ctx.query(); + let model = ctx.model(); + let maybe_const = ConstBindings::new(declaration, model)?; + let replacing_token_kind = if maybe_const.can_fix { + JsSyntaxKind::CONST_KW + } else { + JsSyntaxKind::LET_KW + }; + let mut mutation = ctx.root().begin(); + mutation.replace_token(declaration.kind_token()?, make::token(replacing_token_kind)); + Some(JsRuleAction { + category: ActionCategory::QuickFix, + applicability: Applicability::MaybeIncorrect, + message: markup! { "Use '"{replacing_token_kind.to_string()?}"' instead." }.to_owned(), + mutation, + }) + } +} diff --git a/crates/rome_js_analyze/src/semantic_analyzers/nursery/use_const.rs b/crates/rome_js_analyze/src/semantic_analyzers/nursery/use_const.rs index a55ad4f9d23..36c44d380d7 100644 --- a/crates/rome_js_analyze/src/semantic_analyzers/nursery/use_const.rs +++ b/crates/rome_js_analyze/src/semantic_analyzers/nursery/use_const.rs @@ -70,8 +70,8 @@ declare_node_union! { } pub(crate) struct ConstBindings { - can_be_const: Vec, - can_fix: bool, + pub can_be_const: Vec, + pub can_fix: bool, } enum ConstCheckResult { @@ -141,7 +141,7 @@ impl Rule for UseConst { } impl ConstBindings { - fn new(declaration: &VariableDeclaration, model: &SemanticModel) -> Option { + pub fn new(declaration: &VariableDeclaration, model: &SemanticModel) -> Option { let mut state = Self { can_be_const: Vec::new(), can_fix: true, @@ -208,7 +208,7 @@ fn check_binding_can_be_const( } impl VariableDeclaration { - fn for_each_declarator(&self, f: impl FnMut(JsVariableDeclarator)) { + pub fn for_each_declarator(&self, f: impl FnMut(JsVariableDeclarator)) { match self { VariableDeclaration::JsVariableDeclaration(x) => x .declarators() @@ -221,7 +221,7 @@ impl VariableDeclaration { } } - fn for_each_binding(&self, mut f: impl FnMut(JsIdentifierBinding, &JsVariableDeclarator)) { + pub fn for_each_binding(&self, mut f: impl FnMut(JsIdentifierBinding, &JsVariableDeclarator)) { self.for_each_declarator(|declarator| { if let Ok(pattern) = declarator.id() { with_binding_pat_identifiers(pattern, &mut |binding| { @@ -232,19 +232,26 @@ impl VariableDeclaration { }); } - fn kind_token(&self) -> Option { + pub fn kind_token(&self) -> Option { match self { Self::JsVariableDeclaration(x) => x.kind().ok(), Self::JsForVariableDeclaration(x) => x.kind_token().ok(), } } - fn is_let(&self) -> bool { + pub fn is_let(&self) -> bool { match self { Self::JsVariableDeclaration(it) => it.is_let(), Self::JsForVariableDeclaration(it) => it.is_let(), } } + + pub fn is_var(&self) -> bool { + match self { + Self::JsVariableDeclaration(it) => it.is_var(), + Self::JsForVariableDeclaration(it) => it.is_var(), + } + } } /// Visit [JsIdentifierBinding] in the given [JsAnyBindingPattern]. diff --git a/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidFunctions.js b/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidFunctions.js new file mode 100644 index 00000000000..217256af2a0 --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidFunctions.js @@ -0,0 +1,9 @@ +export function f(x) { + if(x) { + // assign 'y' + var /* @type number */ y /*: number */ = 2*x; + // assign 'y' to 'x' + x = y; + } + return x; +} \ No newline at end of file diff --git a/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidFunctions.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidFunctions.js.snap new file mode 100644 index 00000000000..a95878ceb2e --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidFunctions.js.snap @@ -0,0 +1,48 @@ +--- +source: crates/rome_js_analyze/tests/spec_tests.rs +assertion_line: 73 +expression: invalidFunctions.js +--- +# Input +```js +export function f(x) { + if(x) { + // assign 'y' + var /* @type number */ y /*: number */ = 2*x; + // assign 'y' to 'x' + x = y; + } + return x; +} +``` + +# Diagnostics +``` +invalidFunctions.js:4:9 lint/nursery/noVar FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use let or const instead of var. + + 2 │ if(x) { + 3 │ // assign 'y' + > 4 │ var /* @type number */ y /*: number */ = 2*x; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 5 │ // assign 'y' to 'x' + 6 │ x = y; + + i A variable declared with var is accessible in the whole body of the function. Thus, the variable can be accessed before its initialization and outside the block where it is declared. + + i See MDN web docs for more details. + + i Suggested fix: Use 'const' instead. + + 2 2 │ if(x) { + 3 3 │ // assign 'y' + 4 │ - ········var·/*·@type·number·*/·y·/*:·number·*/·=·2*x; + 4 │ + ········const·/*·@type·number·*/·y·/*:·number·*/·=·2*x; + 5 5 │ // assign 'y' to 'x' + 6 6 │ x = y; + + +``` + + diff --git a/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidModule.js b/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidModule.js new file mode 100644 index 00000000000..329fcb095cc --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidModule.js @@ -0,0 +1,2 @@ +var x = 1; +export const y = x; \ No newline at end of file diff --git a/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidModule.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidModule.js.snap new file mode 100644 index 00000000000..4168e509c97 --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidModule.js.snap @@ -0,0 +1,35 @@ +--- +source: crates/rome_js_analyze/tests/spec_tests.rs +assertion_line: 73 +expression: invalidModule.js +--- +# Input +```js +var x = 1; +export const y = x; +``` + +# Diagnostics +``` +invalidModule.js:1:1 lint/nursery/noVar FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use let or const instead of var. + + > 1 │ var x = 1; + │ ^^^^^^^^^ + 2 │ export const y = x; + + i A variable declared with var is accessible in the whole module. Thus, the variable can be accessed before its initialization and outside the block where it is declared. + + i See MDN web docs for more details. + + i Suggested fix: Use 'const' instead. + + 1 │ - var·x·=·1; + 1 │ + const·x·=·1; + 2 2 │ export const y = x; + + +``` + + diff --git a/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidScript.jsonc b/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidScript.jsonc new file mode 100644 index 00000000000..b7bf836046b --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidScript.jsonc @@ -0,0 +1,7 @@ +[ + "var x = 1; foo(x);", + "for (var i in [1,2,3]) { foo(i); }", + "for (var x of [1,2,3]) { foo(x); }", + "var [x = -1, y] = [1,2]; y = 0;", + "var {a: x = -1, b: y} = {a:1,b:2}; y = 0;" +] diff --git a/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidScript.jsonc.snap b/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidScript.jsonc.snap new file mode 100644 index 00000000000..8ddc541ad6d --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noVar/invalidScript.jsonc.snap @@ -0,0 +1,136 @@ +--- +source: crates/rome_js_analyze/tests/spec_tests.rs +assertion_line: 73 +expression: invalidScript.jsonc +--- +# Input +```js +var x = 1; foo(x); +``` + +# Diagnostics +``` +invalidScript.jsonc:1:1 lint/nursery/noVar FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use let or const instead of var. + + > 1 │ var x = 1; foo(x); + │ ^^^^^^^^^ + + i A variable declared with var in the global scope pollutes the global object. + + i See MDN web docs for more details. + + i Suggested fix: Use 'const' instead. + + - var·x·=·1;·foo(x); + + const·x·=·1;·foo(x); + + +``` + +# Input +```js +for (var i in [1,2,3]) { foo(i); } +``` + +# Diagnostics +``` +invalidScript.jsonc:1:6 lint/nursery/noVar FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use let or const instead of var. + + > 1 │ for (var i in [1,2,3]) { foo(i); } + │ ^^^^^ + + i A variable declared with var in the global scope pollutes the global object. + + i See MDN web docs for more details. + + i Suggested fix: Use 'const' instead. + + - for·(var·i·in·[1,2,3])·{·foo(i);·} + + for·(const·i·in·[1,2,3])·{·foo(i);·} + + +``` + +# Input +```js +for (var x of [1,2,3]) { foo(x); } +``` + +# Diagnostics +``` +invalidScript.jsonc:1:6 lint/nursery/noVar FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use let or const instead of var. + + > 1 │ for (var x of [1,2,3]) { foo(x); } + │ ^^^^^ + + i A variable declared with var in the global scope pollutes the global object. + + i See MDN web docs for more details. + + i Suggested fix: Use 'const' instead. + + - for·(var·x·of·[1,2,3])·{·foo(x);·} + + for·(const·x·of·[1,2,3])·{·foo(x);·} + + +``` + +# Input +```js +var [x = -1, y] = [1,2]; y = 0; +``` + +# Diagnostics +``` +invalidScript.jsonc:1:1 lint/nursery/noVar FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use let or const instead of var. + + > 1 │ var [x = -1, y] = [1,2]; y = 0; + │ ^^^^^^^^^^^^^^^^^^^^^^^ + + i A variable declared with var in the global scope pollutes the global object. + + i See MDN web docs for more details. + + i Suggested fix: Use 'let' instead. + + - var·[x·=·-1,·y]·=·[1,2];·y·=·0; + + let·[x·=·-1,·y]·=·[1,2];·y·=·0; + + +``` + +# Input +```js +var {a: x = -1, b: y} = {a:1,b:2}; y = 0; +``` + +# Diagnostics +``` +invalidScript.jsonc:1:1 lint/nursery/noVar FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Use let or const instead of var. + + > 1 │ var {a: x = -1, b: y} = {a:1,b:2}; y = 0; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + i A variable declared with var in the global scope pollutes the global object. + + i See MDN web docs for more details. + + i Suggested fix: Use 'let' instead. + + - var·{a:·x·=·-1,·b:·y}·=·{a:1,b:2};·y·=·0; + + let·{a:·x·=·-1,·b:·y}·=·{a:1,b:2};·y·=·0; + + +``` + + diff --git a/crates/rome_js_analyze/tests/specs/nursery/noVar/valid.jsonc b/crates/rome_js_analyze/tests/specs/nursery/noVar/valid.jsonc new file mode 100644 index 00000000000..496e574f325 --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noVar/valid.jsonc @@ -0,0 +1,7 @@ +[ + "function f() { const x = 1; return x; }", + "let x = 0;", + "const x = 0;", + "for (let x of xs) {}", + "for (const x of xs) {}" +] diff --git a/crates/rome_js_analyze/tests/specs/nursery/noVar/valid.jsonc.snap b/crates/rome_js_analyze/tests/specs/nursery/noVar/valid.jsonc.snap new file mode 100644 index 00000000000..e5e792fd97a --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noVar/valid.jsonc.snap @@ -0,0 +1,31 @@ +--- +source: crates/rome_js_analyze/tests/spec_tests.rs +assertion_line: 73 +expression: valid.jsonc +--- +# Input +```js +function f() { const x = 1; return x; } +``` + +# Input +```js +let x = 0; +``` + +# Input +```js +const x = 0; +``` + +# Input +```js +for (let x of xs) {} +``` + +# Input +```js +for (const x of xs) {} +``` + + diff --git a/crates/rome_service/src/configuration/linter/rules.rs b/crates/rome_service/src/configuration/linter/rules.rs index a91998af3a9..cf8468ee1ea 100644 --- a/crates/rome_service/src/configuration/linter/rules.rs +++ b/crates/rome_service/src/configuration/linter/rules.rs @@ -753,6 +753,8 @@ struct NurserySchema { no_string_case_mismatch: Option, #[doc = "Disallow control flow statements in finally blocks."] no_unsafe_finally: Option, + #[doc = "Disallow the use of var"] + no_var: Option, #[doc = "Enforce camel case naming convention."] use_camel_case: Option, #[doc = "Require const declarations for variables that are never reassigned after declared."] @@ -768,7 +770,7 @@ struct NurserySchema { } impl Nursery { const CATEGORY_NAME: &'static str = "nursery"; - pub(crate) const CATEGORY_RULES: [&'static str; 18] = [ + pub(crate) const CATEGORY_RULES: [&'static str; 19] = [ "noAccessKey", "noBannedTypes", "noConditionalAssignment", @@ -781,6 +783,7 @@ impl Nursery { "noPrecisionLoss", "noStringCaseMismatch", "noUnsafeFinally", + "noVar", "useCamelCase", "useConst", "useExhaustiveDependencies", diff --git a/editors/vscode/configuration_schema.json b/editors/vscode/configuration_schema.json index c595abe1e14..62c18ce8683 100644 --- a/editors/vscode/configuration_schema.json +++ b/editors/vscode/configuration_schema.json @@ -885,6 +885,17 @@ } ] }, + "noVar": { + "description": "Disallow the use of var", + "anyOf": [ + { + "$ref": "#/definitions/RuleConfiguration" + }, + { + "type": "null" + } + ] + }, "recommended": { "description": "It enables the recommended rules for this group", "type": [ diff --git a/npm/backend-jsonrpc/src/workspace.ts b/npm/backend-jsonrpc/src/workspace.ts index e92481a05cc..d41ade197fa 100644 --- a/npm/backend-jsonrpc/src/workspace.ts +++ b/npm/backend-jsonrpc/src/workspace.ts @@ -395,6 +395,10 @@ export interface Nursery { * Disallow control flow statements in finally blocks. */ noUnsafeFinally?: RuleConfiguration; + /** + * Disallow the use of var + */ + noVar?: RuleConfiguration; /** * It enables the recommended rules for this group */ @@ -639,6 +643,7 @@ export type Category = | "lint/nursery/noPrecisionLoss" | "lint/nursery/noStringCaseMismatch" | "lint/nursery/noUnsafeFinally" + | "lint/nursery/noVar" | "lint/nursery/useCamelCase" | "lint/nursery/useConst" | "lint/nursery/useExhaustiveDependencies" diff --git a/npm/rome/configuration_schema.json b/npm/rome/configuration_schema.json index c595abe1e14..62c18ce8683 100644 --- a/npm/rome/configuration_schema.json +++ b/npm/rome/configuration_schema.json @@ -885,6 +885,17 @@ } ] }, + "noVar": { + "description": "Disallow the use of var", + "anyOf": [ + { + "$ref": "#/definitions/RuleConfiguration" + }, + { + "type": "null" + } + ] + }, "recommended": { "description": "It enables the recommended rules for this group", "type": [ diff --git a/website/src/pages/lint/rules/index.mdx b/website/src/pages/lint/rules/index.mdx index 5595bab3b8b..432842b606a 100644 --- a/website/src/pages/lint/rules/index.mdx +++ b/website/src/pages/lint/rules/index.mdx @@ -517,6 +517,12 @@ Disallow comparison of expressions modifying the string case with non-compliant Disallow control flow statements in finally blocks.
+

+ noVar +

+Disallow the use of var +
+

useCamelCase

diff --git a/website/src/pages/lint/rules/noVar.md b/website/src/pages/lint/rules/noVar.md new file mode 100644 index 00000000000..e8bf87b8204 --- /dev/null +++ b/website/src/pages/lint/rules/noVar.md @@ -0,0 +1,48 @@ +--- +title: Lint Rule noVar +parent: lint/rules/index +--- + +# noVar (since v11.0.0) + +Disallow the use of `var` + +ECMAScript 6 allows programmers to create variables with block scope instead of function scope using the let and const keywords. Block scope is common in many other programming languages and helps programmers avoid mistakes. + +Source: https://eslint.org/docs/latest/rules/no-var + +## Examples + +### Invalid + +```jsx +var foo = 1; +``` + +
nursery/noVar.js:1:1 lint/nursery/noVar  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+   Use let or const instead of var.
+  
+  > 1 │ var foo = 1;
+   ^^^^^^^^^^^
+    2 │ 
+  
+   A variable declared with var is accessible in the whole module. Thus, the variable can be accessed before its initialization and outside the block where it is declared.
+  
+   See MDN web docs for more details.
+  
+   Suggested fix: Use 'const' instead.
+  
+    1  - var·foo·=·1;
+      1+ const·foo·=·1;
+    2 2  
+  
+
+ +### Valid + +```jsx +const foo = 1; +let bar = 1; +``` +