]> git.proxmox.com Git - pve-eslint.git/blobdiff - eslint/lib/linter/code-path-analysis/code-path-state.js
import 7.12.1 upstream release
[pve-eslint.git] / eslint / lib / linter / code-path-analysis / code-path-state.js
index 9e760601a0f744202ee19c4ff2d3b3f4094a7555..f75e60e28a807e40ad1e0cc31ed85c1bd1f85d59 100644 (file)
@@ -234,6 +234,7 @@ class CodePathState {
         this.tryContext = null;
         this.loopContext = null;
         this.breakContext = null;
+        this.chainContext = null;
 
         this.currentSegments = [];
         this.initialSegment = this.forkContext.head[0];
@@ -316,7 +317,7 @@ class CodePathState {
     //--------------------------------------------------------------------------
 
     /**
-     * Creates a context for ConditionalExpression, LogicalExpression,
+     * Creates a context for ConditionalExpression, LogicalExpression, AssignmentExpression (logical assignments only),
      * IfStatement, WhileStatement, DoWhileStatement, or ForStatement.
      *
      * LogicalExpressions have cases that it goes different paths between the
@@ -338,7 +339,7 @@ class CodePathState {
      *     a -> b -> foo();
      *     a -> b -> bar();
      * @param {string} kind A kind string.
-     *   If the new context is LogicalExpression's, this is `"&&"` or `"||"`.
+     *   If the new context is LogicalExpression's or AssignmentExpression's, this is `"&&"` or `"||"` or `"??"`.
      *   If it's IfStatement's or ConditionalExpression's, this is `"test"`.
      *   Otherwise, this is `"loop"`.
      * @param {boolean} isForkingAsResult A flag that shows that goes different
@@ -555,6 +556,64 @@ class CodePathState {
         );
     }
 
+    //--------------------------------------------------------------------------
+    // ChainExpression
+    //--------------------------------------------------------------------------
+
+    /**
+     * Push a new `ChainExpression` context to the stack.
+     * This method is called on entering to each `ChainExpression` node.
+     * This context is used to count forking in the optional chain then merge them on the exiting from the `ChainExpression` node.
+     * @returns {void}
+     */
+    pushChainContext() {
+        this.chainContext = {
+            upper: this.chainContext,
+            countChoiceContexts: 0
+        };
+    }
+
+    /**
+     * Pop a `ChainExpression` context from the stack.
+     * This method is called on exiting from each `ChainExpression` node.
+     * This merges all forks of the last optional chaining.
+     * @returns {void}
+     */
+    popChainContext() {
+        const context = this.chainContext;
+
+        this.chainContext = context.upper;
+
+        // pop all choice contexts of this.
+        for (let i = context.countChoiceContexts; i > 0; --i) {
+            this.popChoiceContext();
+        }
+    }
+
+    /**
+     * Create a choice context for optional access.
+     * This method is called on entering to each `(Call|Member)Expression[optional=true]` node.
+     * This creates a choice context as similar to `LogicalExpression[operator="??"]` node.
+     * @returns {void}
+     */
+    makeOptionalNode() {
+        if (this.chainContext) {
+            this.chainContext.countChoiceContexts += 1;
+            this.pushChoiceContext("??", false);
+        }
+    }
+
+    /**
+     * Create a fork.
+     * This method is called on entering to the `arguments|property` property of each `(Call|Member)Expression` node.
+     * @returns {void}
+     */
+    makeOptionalRight() {
+        if (this.chainContext) {
+            this.makeLogicalRight();
+        }
+    }
+
     //--------------------------------------------------------------------------
     // SwitchStatement
     //--------------------------------------------------------------------------