massive update, probably broken
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / no-unused-vars.js
index 63e6e048ef1e462911d0aa4e37961231d0af0b0d..f04818f8e9d5979f2879af8954dfd6207df254ab 100644 (file)
 
 const astUtils = require("./utils/ast-utils");
 
+//------------------------------------------------------------------------------
+// Typedefs
+//------------------------------------------------------------------------------
+
+/**
+ * Bag of data used for formatting the `unusedVar` lint message.
+ * @typedef {Object} UnusedVarMessageData
+ * @property {string} varName The name of the unused var.
+ * @property {'defined'|'assigned a value'} action Description of the vars state.
+ * @property {string} additional Any additional info to be appended at the end.
+ */
+
 //------------------------------------------------------------------------------
 // Rule Definition
 //------------------------------------------------------------------------------
@@ -56,11 +68,16 @@ module.exports = {
                             caughtErrorsIgnorePattern: {
                                 type: "string"
                             }
-                        }
+                        },
+                        additionalProperties: false
                     }
                 ]
             }
-        ]
+        ],
+
+        messages: {
+            unusedVar: "'{{varName}}' is {{action}} but never used{{additional}}."
+        }
     },
 
     create(context) {
@@ -101,12 +118,12 @@ module.exports = {
         }
 
         /**
-         * Generate the warning message about the variable being
-         * defined and unused, including the ignore pattern if configured.
+         * Generates the message data about the variable being defined and unused,
+         * including the ignore pattern if configured.
          * @param {Variable} unusedVar eslint-scope variable object.
-         * @returns {string} The warning message to be used with this unused variable.
+         * @returns {UnusedVarMessageData} The message data to be used with this unused variable.
          */
-        function getDefinedMessage(unusedVar) {
+        function getDefinedMessageData(unusedVar) {
             const defType = unusedVar.defs && unusedVar.defs[0] && unusedVar.defs[0].type;
             let type;
             let pattern;
@@ -122,20 +139,29 @@ module.exports = {
                 pattern = config.varsIgnorePattern.toString();
             }
 
-            const additional = type ? ` Allowed unused ${type} must match ${pattern}.` : "";
+            const additional = type ? `. Allowed unused ${type} must match ${pattern}` : "";
 
-            return `'{{name}}' is defined but never used.${additional}`;
+            return {
+                varName: unusedVar.name,
+                action: "defined",
+                additional
+            };
         }
 
         /**
          * Generate the warning message about the variable being
          * assigned and unused, including the ignore pattern if configured.
-         * @returns {string} The warning message to be used with this unused variable.
+         * @param {Variable} unusedVar eslint-scope variable object.
+         * @returns {UnusedVarMessageData} The message data to be used with this unused variable.
          */
-        function getAssignedMessage() {
-            const additional = config.varsIgnorePattern ? ` Allowed unused vars must match ${config.varsIgnorePattern.toString()}.` : "";
-
-            return `'{{name}}' is assigned a value but never used.${additional}`;
+        function getAssignedMessageData(unusedVar) {
+            const additional = config.varsIgnorePattern ? `. Allowed unused vars must match ${config.varsIgnorePattern.toString()}` : "";
+
+            return {
+                varName: unusedVar.name,
+                action: "assigned a value",
+                additional
+            };
         }
 
         //--------------------------------------------------------------------------
@@ -170,6 +196,17 @@ module.exports = {
 
         }
 
+        /**
+         * Checks whether a node is a sibling of the rest property or not.
+         * @param {ASTNode} node a node to check
+         * @returns {boolean} True if the node is a sibling of the rest property, otherwise false.
+         */
+        function hasRestSibling(node) {
+            return node.type === "Property" &&
+                node.parent.type === "ObjectPattern" &&
+                REST_PROPERTY_TYPE.test(node.parent.properties[node.parent.properties.length - 1].type);
+        }
+
         /**
          * Determines if a variable has a sibling rest property
          * @param {Variable} variable eslint-scope variable object.
@@ -178,16 +215,10 @@ module.exports = {
          */
         function hasRestSpreadSibling(variable) {
             if (config.ignoreRestSiblings) {
-                return variable.defs.some(def => {
-                    const propertyNode = def.name.parent;
-                    const patternNode = propertyNode.parent;
-
-                    return (
-                        propertyNode.type === "Property" &&
-                        patternNode.type === "ObjectPattern" &&
-                        REST_PROPERTY_TYPE.test(patternNode.properties[patternNode.properties.length - 1].type)
-                    );
-                });
+                const hasRestSiblingDefinition = variable.defs.some(def => hasRestSibling(def.name.parent));
+                const hasRestSiblingReference = variable.references.some(ref => hasRestSibling(ref.identifier.parent));
+
+                return hasRestSiblingDefinition || hasRestSiblingReference;
             }
 
             return false;
@@ -282,7 +313,7 @@ module.exports = {
         function getRhsNode(ref, prevRhsNode) {
             const id = ref.identifier;
             const parent = id.parent;
-            const granpa = parent.parent;
+            const grandparent = parent.parent;
             const refScope = ref.from.variableScope;
             const varScope = ref.resolved.scope.variableScope;
             const canBeUsedLater = refScope !== varScope || astUtils.isInLoop(id);
@@ -296,7 +327,7 @@ module.exports = {
             }
 
             if (parent.type === "AssignmentExpression" &&
-                granpa.type === "ExpressionStatement" &&
+                grandparent.type === "ExpressionStatement" &&
                 id === parent.left &&
                 !canBeUsedLater
             ) {
@@ -342,7 +373,7 @@ module.exports = {
 
                             /*
                              * If it encountered statements, this is a complex pattern.
-                             * Since analyzeing complex patterns is hard, this returns `true` to avoid false positive.
+                             * Since analyzing complex patterns is hard, this returns `true` to avoid false positive.
                              */
                             return true;
                         }
@@ -379,6 +410,31 @@ module.exports = {
             );
         }
 
+        /**
+         * Checks whether a given node is unused expression or not.
+         * @param {ASTNode} node The node itself
+         * @returns {boolean} The node is an unused expression.
+         * @private
+         */
+        function isUnusedExpression(node) {
+            const parent = node.parent;
+
+            if (parent.type === "ExpressionStatement") {
+                return true;
+            }
+
+            if (parent.type === "SequenceExpression") {
+                const isLastExpression = parent.expressions[parent.expressions.length - 1] === node;
+
+                if (!isLastExpression) {
+                    return true;
+                }
+                return isUnusedExpression(parent);
+            }
+
+            return false;
+        }
+
         /**
          * Checks whether a given reference is a read to update itself or not.
          * @param {eslint-scope.Reference} ref A reference to check.
@@ -389,23 +445,28 @@ module.exports = {
         function isReadForItself(ref, rhsNode) {
             const id = ref.identifier;
             const parent = id.parent;
-            const granpa = parent.parent;
 
             return ref.isRead() && (
 
                 // self update. e.g. `a += 1`, `a++`
-                (// in RHS of an assignment for itself. e.g. `a = a + 1`
-                    ((
+                (
+                    (
                         parent.type === "AssignmentExpression" &&
-                    granpa.type === "ExpressionStatement" &&
-                    parent.left === id
+                        parent.left === id &&
+                        isUnusedExpression(parent)
                     ) ||
+                    (
+                        parent.type === "UpdateExpression" &&
+                        isUnusedExpression(parent)
+                    )
+                ) ||
+
+                // in RHS of an assignment for itself. e.g. `a = a + 1`
                 (
-                    parent.type === "UpdateExpression" &&
-                    granpa.type === "ExpressionStatement"
-                ) || rhsNode &&
-                isInside(id, rhsNode) &&
-                !isInsideOfStorableFunction(id, rhsNode)))
+                    rhsNode &&
+                    isInside(id, rhsNode) &&
+                    !isInsideOfStorableFunction(id, rhsNode)
+                )
             );
         }
 
@@ -593,12 +654,22 @@ module.exports = {
 
                     // Report the first declaration.
                     if (unusedVar.defs.length > 0) {
+
+                        // report last write reference, https://github.com/eslint/eslint/issues/14324
+                        const writeReferences = unusedVar.references.filter(ref => ref.isWrite() && ref.from.variableScope === unusedVar.scope.variableScope);
+
+                        let referenceToReport;
+
+                        if (writeReferences.length > 0) {
+                            referenceToReport = writeReferences[writeReferences.length - 1];
+                        }
+
                         context.report({
-                            node: unusedVar.identifiers[0],
-                            message: unusedVar.references.some(ref => ref.isWrite())
-                                ? getAssignedMessage()
-                                : getDefinedMessage(unusedVar),
-                            data: unusedVar
+                            node: referenceToReport ? referenceToReport.identifier : unusedVar.identifiers[0],
+                            messageId: "unusedVar",
+                            data: unusedVar.references.some(ref => ref.isWrite())
+                                ? getAssignedMessageData(unusedVar)
+                                : getDefinedMessageData(unusedVar)
                         });
 
                     // If there are no regular declaration, report the first `/*globals*/` comment directive.
@@ -608,8 +679,8 @@ module.exports = {
                         context.report({
                             node: programNode,
                             loc: astUtils.getNameLocationInGlobalDirectiveComment(sourceCode, directiveComment, unusedVar.name),
-                            message: getDefinedMessage(unusedVar),
-                            data: unusedVar
+                            messageId: "unusedVar",
+                            data: getDefinedMessageData(unusedVar)
                         });
                     }
                 }