"use strict";
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const astUtils = require("./utils/ast-utils");
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+/**
+ * Determines whether the given node is in a statement list.
+ * @param {ASTNode} node node to check
+ * @returns {boolean} `true` if the given node is in a statement list
+ */
+function isInStatementList(node) {
+ return astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type);
+}
+
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
+/** @type {import('../shared/types').Rule} */
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "enforce variables to be declared either together or separately in functions",
- category: "Stylistic Issues",
recommended: false,
url: "https://eslint.org/docs/rules/one-var"
},
/**
* Determines the current scope (function or block)
- * @param {string} statementType node.kind, one of: "var", "let", or "const"
+ * @param {string} statementType node.kind, one of: "var", "let", or "const"
* @returns {Object} The scope associated with statementType
*/
function getCurrentScope(statementType) {
/**
* Fixer to join VariableDeclaration's into a single declaration
- * @param {VariableDeclarator[]} declarations The `VariableDeclaration` to join
- * @returns {Function} The fixer function
+ * @param {VariableDeclarator[]} declarations The `VariableDeclaration` to join
+ * @returns {Function} The fixer function
*/
function joinDeclarations(declarations) {
const declaration = declarations[0];
/**
* Fixer to split a VariableDeclaration into individual declarations
- * @param {VariableDeclaration} declaration The `VariableDeclaration` to split
- * @returns {Function} The fixer function
+ * @param {VariableDeclaration} declaration The `VariableDeclaration` to split
+ * @returns {Function|null} The fixer function
*/
function splitDeclarations(declaration) {
+ const { parent } = declaration;
+
+ // don't autofix code such as: if (foo) var x, y;
+ if (!isInStatementList(parent.type === "ExportNamedDeclaration" ? parent : declaration)) {
+ return null;
+ }
+
return fixer => declaration.declarations.map(declarator => {
const tokenAfterDeclarator = sourceCode.getTokenAfter(declarator);
return null;
}
+ const exportPlacement = declaration.parent.type === "ExportNamedDeclaration" ? "export " : "";
+
/*
* `var x,y`
* tokenAfterDeclarator ^^ afterComma
*/
if (afterComma.range[0] === tokenAfterDeclarator.range[1]) {
- return fixer.replaceText(tokenAfterDeclarator, `; ${declaration.kind} `);
+ return fixer.replaceText(tokenAfterDeclarator, `; ${exportPlacement}${declaration.kind} `);
}
/*
return fixer.replaceTextRange(
[tokenAfterDeclarator.range[0], lastComment.range[0]],
- `;${sourceCode.text.slice(tokenAfterDeclarator.range[1], lastComment.range[0])}${declaration.kind} `
+ `;${sourceCode.text.slice(tokenAfterDeclarator.range[1], lastComment.range[0])}${exportPlacement}${declaration.kind} `
);
}
- return fixer.replaceText(tokenAfterDeclarator, `; ${declaration.kind}`);
+ return fixer.replaceText(tokenAfterDeclarator, `; ${exportPlacement}${declaration.kind}`);
}).filter(x => x);
}
FunctionDeclaration: startFunction,
FunctionExpression: startFunction,
ArrowFunctionExpression: startFunction,
+ StaticBlock: startFunction, // StaticBlock creates a new scope for `var` variables
+
BlockStatement: startBlock,
ForStatement: startBlock,
ForInStatement: startBlock,
"ForInStatement:exit": endBlock,
"SwitchStatement:exit": endBlock,
"BlockStatement:exit": endBlock,
+
"Program:exit": endFunction,
"FunctionDeclaration:exit": endFunction,
"FunctionExpression:exit": endFunction,
- "ArrowFunctionExpression:exit": endFunction
+ "ArrowFunctionExpression:exit": endFunction,
+ "StaticBlock:exit": endFunction
};
}