eslint-plugin-n
Version:
Additional ESLint's rules for Node.js
896 lines (894 loc) • 33.3 kB
TypeScript
import IdGenerator = require("./id-generator")
export = CodePathState;
/**
* A class which manages state to analyze code paths.
*/
declare class CodePathState {
/**
* Creates a new instance.
* @param {IdGenerator} idGenerator An id generator to generate id for code
* path segments.
* @param {Function} onLooped A callback function to notify looping.
*/
constructor(idGenerator: IdGenerator, onLooped: Function);
/**
* The ID generator to use when creating new segments.
* @type {IdGenerator}
*/
idGenerator: IdGenerator;
/**
* A callback function to call when there is a loop.
* @type {Function}
*/
notifyLooped: Function;
/**
* The root fork context for this state.
* @type {ForkContext}
*/
forkContext: ForkContext;
/**
* Context for logical expressions, conditional expressions, `if` statements,
* and loops.
* @type {ChoiceContext}
*/
choiceContext: ChoiceContext;
/**
* Context for `switch` statements.
* @type {SwitchContext}
*/
switchContext: SwitchContext;
/**
* Context for `try` statements.
* @type {TryContext}
*/
tryContext: TryContext;
/**
* Context for loop statements.
* @type {LoopContext}
*/
loopContext: LoopContext;
/**
* Context for `break` statements.
* @type {BreakContext}
*/
breakContext: BreakContext;
/**
* Context for `ChainExpression` nodes.
* @type {ChainContext}
*/
chainContext: ChainContext;
/**
* An array that tracks the current segments in the state. The array
* starts empty and segments are added with each `onCodePathSegmentStart`
* event and removed with each `onCodePathSegmentEnd` event. Effectively,
* this is tracking the code path segment traversal as the state is
* modified.
* @type {Array<CodePathSegment>}
*/
currentSegments: Array<CodePathSegment>;
/**
* Tracks the starting segment for this path. This value never changes.
* @type {CodePathSegment}
*/
initialSegment: CodePathSegment;
/**
* The final segments of the code path which are either `return` or `throw`.
* This is a union of the segments in `returnedForkContext` and `thrownForkContext`.
* @type {Array<CodePathSegment>}
*/
finalSegments: Array<CodePathSegment>;
/**
* The final segments of the code path which are `return`. These
* segments are also contained in `finalSegments`.
* @type {Array<CodePathSegment>}
*/
returnedForkContext: Array<CodePathSegment>;
/**
* The final segments of the code path which are `throw`. These
* segments are also contained in `finalSegments`.
* @type {Array<CodePathSegment>}
*/
thrownForkContext: Array<CodePathSegment>;
/**
* A passthrough property exposing the current pointer as part of the API.
* @type {CodePathSegment[]}
*/
get headSegments(): CodePathSegment[];
/**
* The parent forking context.
* This is used for the root of new forks.
* @type {ForkContext}
*/
get parentForkContext(): ForkContext;
/**
* Creates and stacks new forking context.
* @param {boolean} forkLeavingPath A flag which shows being in a
* "finally" block.
* @returns {ForkContext} The created context.
*/
pushForkContext(forkLeavingPath: boolean): ForkContext;
/**
* Pops and merges the last forking context.
* @returns {ForkContext} The last context.
*/
popForkContext(): ForkContext;
/**
* Creates a new path.
* @returns {void}
*/
forkPath(): void;
/**
* Creates a bypass path.
* This is used for such as IfStatement which does not have "else" chunk.
* @returns {void}
*/
forkBypassPath(): void;
/**
* 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
* `true` case and the `false` case.
*
* For Example:
*
* if (a || b) {
* foo();
* } else {
* bar();
* }
*
* In this case, `b` is evaluated always in the code path of the `else`
* block, but it's not so in the code path of the `if` block.
* So there are 3 paths.
*
* a -> foo();
* a -> b -> foo();
* a -> b -> bar();
* @param {string} kind A kind string.
* 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 Indicates if the result of the choice
* creates a fork.
* @returns {void}
*/
pushChoiceContext(kind: string, isForkingAsResult: boolean): void;
/**
* Pops the last choice context and finalizes it.
* This is called upon leaving a node that represents a choice.
* @throws {Error} (Unreachable.)
* @returns {ChoiceContext} The popped context.
*/
popChoiceContext(): ChoiceContext;
/**
* Creates a code path segment to represent right-hand operand of a logical
* expression.
* This is called in the preprocessing phase when entering a node.
* @throws {Error} (Unreachable.)
* @returns {void}
*/
makeLogicalRight(): void;
/**
* Makes a code path segment of the `if` block.
* @returns {void}
*/
makeIfConsequent(): void;
/**
* Makes a code path segment of the `else` block.
* @returns {void}
*/
makeIfAlternate(): void;
/**
* Pushes a new `ChainExpression` context to the stack. This method is
* called when entering a `ChainExpression` node. A chain context is used to
* count forking in the optional chain then merge them on the exiting from the
* `ChainExpression` node.
* @returns {void}
*/
pushChainContext(): void;
/**
* 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(): void;
/**
* 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(): void;
/**
* Create a fork.
* This method is called on entering to the `arguments|property` property of each `(Call|Member)Expression` node.
* @returns {void}
*/
makeOptionalRight(): void;
/**
* Creates a context object of SwitchStatement and stacks it.
* @param {boolean} hasCase `true` if the switch statement has one or more
* case parts.
* @param {string|null} label The label text.
* @returns {void}
*/
pushSwitchContext(hasCase: boolean, label: string | null): void;
/**
* Pops the last context of SwitchStatement and finalizes it.
*
* - Disposes all forking stack for `case` and `default`.
* - Creates the next code path segment from `context.brokenForkContext`.
* - If the last `SwitchCase` node is not a `default` part, creates a path
* to the `default` body.
* @returns {void}
*/
popSwitchContext(): void;
/**
* Makes a code path segment for a `SwitchCase` node.
* @param {boolean} isCaseBodyEmpty `true` if the body is empty.
* @param {boolean} isDefaultCase `true` if the body is the default case.
* @returns {void}
*/
makeSwitchCaseBody(isCaseBodyEmpty: boolean, isDefaultCase: boolean): void;
/**
* Creates a context object of TryStatement and stacks it.
* @param {boolean} hasFinalizer `true` if the try statement has a
* `finally` block.
* @returns {void}
*/
pushTryContext(hasFinalizer: boolean): void;
/**
* Pops the last context of TryStatement and finalizes it.
* @returns {void}
*/
popTryContext(): void;
/**
* Makes a code path segment for a `catch` block.
* @returns {void}
*/
makeCatchBlock(): void;
/**
* Makes a code path segment for a `finally` block.
*
* In the `finally` block, parallel paths are created. The parallel paths
* are used as leaving-paths. The leaving-paths are paths from `return`
* statements and `throw` statements in a `try` block or a `catch` block.
* @returns {void}
*/
makeFinallyBlock(): void;
/**
* Makes a code path segment from the first throwable node to the `catch`
* block or the `finally` block.
* @returns {void}
*/
makeFirstThrowablePathInTryBlock(): void;
/**
* Creates a context object of a loop statement and stacks it.
* @param {string} type The type of the node which was triggered. One of
* `WhileStatement`, `DoWhileStatement`, `ForStatement`, `ForInStatement`,
* and `ForStatement`.
* @param {string|null} label A label of the node which was triggered.
* @throws {Error} (Unreachable - unknown type.)
* @returns {void}
*/
pushLoopContext(type: string, label: string | null): void;
/**
* Pops the last context of a loop statement and finalizes it.
* @throws {Error} (Unreachable - unknown type.)
* @returns {void}
*/
popLoopContext(): void;
/**
* Makes a code path segment for the test part of a WhileStatement.
* @param {boolean|undefined} test The test value (only when constant).
* @returns {void}
*/
makeWhileTest(test: boolean | undefined): void;
/**
* Makes a code path segment for the body part of a WhileStatement.
* @returns {void}
*/
makeWhileBody(): void;
/**
* Makes a code path segment for the body part of a DoWhileStatement.
* @returns {void}
*/
makeDoWhileBody(): void;
/**
* Makes a code path segment for the test part of a DoWhileStatement.
* @param {boolean|undefined} test The test value (only when constant).
* @returns {void}
*/
makeDoWhileTest(test: boolean | undefined): void;
/**
* Makes a code path segment for the test part of a ForStatement.
* @param {boolean|undefined} test The test value (only when constant).
* @returns {void}
*/
makeForTest(test: boolean | undefined): void;
/**
* Makes a code path segment for the update part of a ForStatement.
* @returns {void}
*/
makeForUpdate(): void;
/**
* Makes a code path segment for the body part of a ForStatement.
* @returns {void}
*/
makeForBody(): void;
/**
* Makes a code path segment for the left part of a ForInStatement and a
* ForOfStatement.
* @returns {void}
*/
makeForInOfLeft(): void;
/**
* Makes a code path segment for the right part of a ForInStatement and a
* ForOfStatement.
* @returns {void}
*/
makeForInOfRight(): void;
/**
* Makes a code path segment for the body part of a ForInStatement and a
* ForOfStatement.
* @returns {void}
*/
makeForInOfBody(): void;
/**
* Creates new context in which a `break` statement can be used. This occurs inside of a loop,
* labeled statement, or switch statement.
* @param {boolean} breakable Indicates if we are inside a statement where
* `break` without a label will exit the statement.
* @param {string|null} label The label associated with the statement.
* @returns {BreakContext} The new context.
*/
pushBreakContext(breakable: boolean, label: string | null): BreakContext;
/**
* Removes the top item of the break context stack.
* @returns {Object} The removed context.
*/
popBreakContext(): any;
/**
* Makes a path for a `break` statement.
*
* It registers the head segment to a context of `break`.
* It makes new unreachable segment, then it set the head with the segment.
* @param {string|null} label A label of the break statement.
* @returns {void}
*/
makeBreak(label: string | null): void;
/**
* Makes a path for a `continue` statement.
*
* It makes a looping path.
* It makes new unreachable segment, then it set the head with the segment.
* @param {string|null} label A label of the continue statement.
* @returns {void}
*/
makeContinue(label: string | null): void;
/**
* Makes a path for a `return` statement.
*
* It registers the head segment to a context of `return`.
* It makes new unreachable segment, then it set the head with the segment.
* @returns {void}
*/
makeReturn(): void;
/**
* Makes a path for a `throw` statement.
*
* It registers the head segment to a context of `throw`.
* It makes new unreachable segment, then it set the head with the segment.
* @returns {void}
*/
makeThrow(): void;
/**
* Makes the final path.
* @returns {void}
*/
makeFinal(): void;
}
declare namespace CodePathState {
export { LoopContext };
}
import ForkContext = require("./fork-context");
/**
* Represents a choice in the code path.
*
* Choices are created by logical operators such as `&&`, loops, conditionals,
* and `if` statements. This is the point at which the code path has a choice of
* which direction to go.
*
* The result of a choice might be in the left (test) expression of another choice,
* and in that case, may create a new fork. For example, `a || b` is a choice
* but does not create a new fork because the result of the expression is
* not used as the test expression in another expression. In this case,
* `isForkingAsResult` is false. In the expression `a || b || c`, the `a || b`
* expression appears as the test expression for `|| c`, so the
* result of `a || b` creates a fork because execution may or may not
* continue to `|| c`. `isForkingAsResult` for `a || b` in this case is true
* while `isForkingAsResult` for `|| c` is false. (`isForkingAsResult` is always
* false for `if` statements, conditional expressions, and loops.)
*
* All of the choices except one (`??`) operate on a true/false fork, meaning if
* true go one way and if false go the other (tracked by `trueForkContext` and
* `falseForkContext`). The `??` operator doesn't operate on true/false because
* the left expression is evaluated to be nullish or not, so only if nullish do
* we fork to the right expression (tracked by `nullishForkContext`).
*/
declare class ChoiceContext {
/**
* Creates a new instance.
* @param {ChoiceContext} upperContext The previous `ChoiceContext`.
* @param {string} kind The kind of choice. If it's a logical or assignment expression, this
* is `"&&"` or `"||"` or `"??"`; if it's an `if` statement or
* conditional expression, this is `"test"`; otherwise, this is `"loop"`.
* @param {boolean} isForkingAsResult Indicates if the result of the choice
* creates a fork.
* @param {ForkContext} forkContext The containing `ForkContext`.
*/
constructor(upperContext: ChoiceContext, kind: string, isForkingAsResult: boolean, forkContext: ForkContext);
/**
* The previous `ChoiceContext`
* @type {ChoiceContext}
*/
upper: ChoiceContext;
/**
* The kind of choice. If it's a logical or assignment expression, this
* is `"&&"` or `"||"` or `"??"`; if it's an `if` statement or
* conditional expression, this is `"test"`; otherwise, this is `"loop"`.
* @type {string}
*/
kind: string;
/**
* Indicates if the result of the choice forks the code path.
* @type {boolean}
*/
isForkingAsResult: boolean;
/**
* The fork context for the `true` path of the choice.
* @type {ForkContext}
*/
trueForkContext: ForkContext;
/**
* The fork context for the `false` path of the choice.
* @type {ForkContext}
*/
falseForkContext: ForkContext;
/**
* The fork context for when the choice result is `null` or `undefined`.
* @type {ForkContext}
*/
nullishForkContext: ForkContext;
/**
* Indicates if any of `trueForkContext`, `falseForkContext`, or
* `nullishForkContext` have been updated with segments from a child context.
* @type {boolean}
*/
processed: boolean;
}
/**
* Represents the context for any loop.
* @typedef {WhileLoopContext|DoWhileLoopContext|ForLoopContext|ForInLoopContext|ForOfLoopContext} LoopContext
*/
/**
* Represents the context for a `switch` statement.
*/
declare class SwitchContext {
/**
* Creates a new instance.
* @param {SwitchContext} upperContext The previous context.
* @param {boolean} hasCase Indicates if there is at least one `case` statement.
* `default` doesn't count.
*/
constructor(upperContext: SwitchContext, hasCase: boolean);
/**
* The previous context.
* @type {SwitchContext}
*/
upper: SwitchContext;
/**
* Indicates if there is at least one `case` statement. `default` doesn't count.
* @type {boolean}
*/
hasCase: boolean;
/**
* The `default` keyword.
* @type {Array<CodePathSegment>|null}
*/
defaultSegments: Array<CodePathSegment> | null;
/**
* The default case body starting segments.
* @type {Array<CodePathSegment>|null}
*/
defaultBodySegments: Array<CodePathSegment> | null;
/**
* Indicates if a `default` case and is empty exists.
* @type {boolean}
*/
foundEmptyDefault: boolean;
/**
* Indicates that a `default` exists and is the last case.
* @type {boolean}
*/
lastIsDefault: boolean;
/**
* The number of fork contexts created. This is equivalent to the
* number of `case` statements plus a `default` statement (if present).
* @type {number}
*/
forkCount: number;
}
/**
* Represents the context for a `try` statement.
*/
declare class TryContext {
/**
* Creates a new instance.
* @param {TryContext} upperContext The previous context.
* @param {boolean} hasFinalizer Indicates if the `try` statement has a
* `finally` block.
* @param {ForkContext} forkContext The enclosing fork context.
*/
constructor(upperContext: TryContext, hasFinalizer: boolean, forkContext: ForkContext);
/**
* The previous context.
* @type {TryContext}
*/
upper: TryContext;
/**
* Indicates if the `try` statement has a `finally` block.
* @type {boolean}
*/
hasFinalizer: boolean;
/**
* Tracks the traversal position inside of the `try` statement. This is
* used to help determine the context necessary to create paths because
* a `try` statement may or may not have `catch` or `finally` blocks,
* and code paths behave differently in those blocks.
* @type {"try"|"catch"|"finally"}
*/
position: "try" | "catch" | "finally";
/**
* If the `try` statement has a `finally` block, this affects how a
* `return` statement behaves in the `try` block. Without `finally`,
* `return` behaves as usual and doesn't require a fork; with `finally`,
* `return` forks into the `finally` block, so we need a fork context
* to track it.
* @type {ForkContext|null}
*/
returnedForkContext: ForkContext | null;
/**
* When a `throw` occurs inside of a `try` block, the code path forks
* into the `catch` or `finally` blocks, and this fork context tracks
* that path.
* @type {ForkContext}
*/
thrownForkContext: ForkContext;
/**
* Indicates if the last segment in the `try` block is reachable.
* @type {boolean}
*/
lastOfTryIsReachable: boolean;
/**
* Indicates if the last segment in the `catch` block is reachable.
* @type {boolean}
*/
lastOfCatchIsReachable: boolean;
}
/**
* Represents the context for any loop.
*/
type LoopContext = WhileLoopContext | DoWhileLoopContext | ForLoopContext | ForInLoopContext | ForOfLoopContext;
/**
* Represents the context in which a `break` statement can be used.
*
* A `break` statement without a label is only valid in a few places in
* JavaScript: any type of loop or a `switch` statement. Otherwise, `break`
* without a label causes a syntax error. For these contexts, `breakable` is
* set to `true` to indicate that a `break` without a label is valid.
*
* However, a `break` statement with a label is also valid inside of a labeled
* statement. For example, this is valid:
*
* a : {
* break a;
* }
*
* The `breakable` property is set false for labeled statements to indicate
* that `break` without a label is invalid.
*/
declare class BreakContext {
/**
* Creates a new instance.
* @param {BreakContext} upperContext The previous `BreakContext`.
* @param {boolean} breakable Indicates if we are inside a statement where
* `break` without a label will exit the statement.
* @param {string|null} label The label for the statement.
* @param {ForkContext} forkContext The current fork context.
*/
constructor(upperContext: BreakContext, breakable: boolean, label: string | null, forkContext: ForkContext);
/**
* The previous `BreakContext`
* @type {BreakContext}
*/
upper: BreakContext;
/**
* Indicates if we are inside a statement where `break` without a label
* will exit the statement.
* @type {boolean}
*/
breakable: boolean;
/**
* The label associated with the statement.
* @type {string|null}
*/
label: string | null;
/**
* The fork context for the `break`.
* @type {ForkContext}
*/
brokenForkContext: ForkContext;
}
/**
* Represents the context for `ChainExpression` nodes.
*/
declare class ChainContext {
/**
* Creates a new instance.
* @param {ChainContext} upperContext The previous `ChainContext`.
*/
constructor(upperContext: ChainContext);
/**
* The previous `ChainContext`
* @type {ChainContext}
*/
upper: ChainContext;
/**
* The number of choice contexts inside of the `ChainContext`.
* @type {number}
*/
choiceContextCount: number;
}
import CodePathSegment = require("./code-path-segment");
/**
* Represents the context for a `while` loop.
*/
declare class WhileLoopContext extends LoopContextBase {
/**
* Creates a new instance.
* @param {LoopContext|null} upperContext The previous `LoopContext`.
* @param {string|null} label The label for the loop from an enclosing `LabeledStatement`.
* @param {BreakContext} breakContext The context for breaking the loop.
*/
constructor(upperContext: LoopContext | null, label: string | null, breakContext: BreakContext);
/**
* The segments representing the test condition where `continue` will
* jump to. The test condition will typically have just one segment but
* it's possible for there to be more than one.
* @type {Array<CodePathSegment>|null}
*/
continueDestSegments: Array<CodePathSegment> | null;
}
/**
* Represents the context for a `do-while` loop.
*/
declare class DoWhileLoopContext extends LoopContextBase {
/**
* Creates a new instance.
* @param {LoopContext|null} upperContext The previous `LoopContext`.
* @param {string|null} label The label for the loop from an enclosing `LabeledStatement`.
* @param {BreakContext} breakContext The context for breaking the loop.
* @param {ForkContext} forkContext The enclosing fork context.
*/
constructor(upperContext: LoopContext | null, label: string | null, breakContext: BreakContext, forkContext: ForkContext);
/**
* The segments at the start of the loop body. This is the only loop
* where the test comes at the end, so the first iteration always
* happens and we need a reference to the first statements.
* @type {Array<CodePathSegment>|null}
*/
entrySegments: Array<CodePathSegment> | null;
/**
* The fork context to follow when a `continue` is found.
* @type {ForkContext}
*/
continueForkContext: ForkContext;
}
/**
* Represents the context for a `for` loop.
*/
declare class ForLoopContext extends LoopContextBase {
/**
* Creates a new instance.
* @param {LoopContext|null} upperContext The previous `LoopContext`.
* @param {string|null} label The label for the loop from an enclosing `LabeledStatement`.
* @param {BreakContext} breakContext The context for breaking the loop.
*/
constructor(upperContext: LoopContext | null, label: string | null, breakContext: BreakContext);
/**
* The end of the init expression. This may change during the lifetime
* of the instance as we traverse the loop because some loops don't have
* an init expression.
* @type {Array<CodePathSegment>|null}
*/
endOfInitSegments: Array<CodePathSegment> | null;
/**
* The start of the test expression. This may change during the lifetime
* of the instance as we traverse the loop because some loops don't have
* a test expression.
* @type {Array<CodePathSegment>|null}
*/
testSegments: Array<CodePathSegment> | null;
/**
* The end of the test expression. This may change during the lifetime
* of the instance as we traverse the loop because some loops don't have
* a test expression.
* @type {Array<CodePathSegment>|null}
*/
endOfTestSegments: Array<CodePathSegment> | null;
/**
* The start of the update expression. This may change during the lifetime
* of the instance as we traverse the loop because some loops don't have
* an update expression.
* @type {Array<CodePathSegment>|null}
*/
updateSegments: Array<CodePathSegment> | null;
/**
* The end of the update expresion. This may change during the lifetime
* of the instance as we traverse the loop because some loops don't have
* an update expression.
* @type {Array<CodePathSegment>|null}
*/
endOfUpdateSegments: Array<CodePathSegment> | null;
/**
* The segments representing the test condition where `continue` will
* jump to. The test condition will typically have just one segment but
* it's possible for there to be more than one. This may change during the
* lifetime of the instance as we traverse the loop because some loops
* don't have an update expression. When there is an update expression, this
* will end up pointing to that expression; otherwise it will end up pointing
* to the test expression.
* @type {Array<CodePathSegment>|null}
*/
continueDestSegments: Array<CodePathSegment> | null;
}
/**
* Represents the context for a `for-in` loop.
*
* Terminology:
* - "left" means the part of the loop to the left of the `in` keyword. For
* example, in `for (var x in y)`, the left is `var x`.
* - "right" means the part of the loop to the right of the `in` keyword. For
* example, in `for (var x in y)`, the right is `y`.
*/
declare class ForInLoopContext extends LoopContextBase {
/**
* Creates a new instance.
* @param {LoopContext|null} upperContext The previous `LoopContext`.
* @param {string|null} label The label for the loop from an enclosing `LabeledStatement`.
* @param {BreakContext} breakContext The context for breaking the loop.
*/
constructor(upperContext: LoopContext | null, label: string | null, breakContext: BreakContext);
/**
* The segments that came immediately before the start of the loop.
* This allows you to traverse backwards out of the loop into the
* surrounding code. This is necessary to evaluate the right expression
* correctly, as it must be evaluated in the same way as the left
* expression, but the pointer to these segments would otherwise be
* lost if not stored on the instance. Once the right expression has
* been evaluated, this property is no longer used.
* @type {Array<CodePathSegment>|null}
*/
prevSegments: Array<CodePathSegment> | null;
/**
* Segments representing the start of everything to the left of the
* `in` keyword. This can be used to move forward towards
* `endOfLeftSegments`. `leftSegments` and `endOfLeftSegments` are
* effectively the head and tail of a doubly-linked list.
* @type {Array<CodePathSegment>|null}
*/
leftSegments: Array<CodePathSegment> | null;
/**
* Segments representing the end of everything to the left of the
* `in` keyword. This can be used to move backward towards `leftSegments`.
* `leftSegments` and `endOfLeftSegments` are effectively the head
* and tail of a doubly-linked list.
* @type {Array<CodePathSegment>|null}
*/
endOfLeftSegments: Array<CodePathSegment> | null;
/**
* The segments representing the left expression where `continue` will
* jump to. In `for-in` loops, `continue` must always re-execute the
* left expression each time through the loop. This contains the same
* segments as `leftSegments`, but is duplicated here so each loop
* context has the same property pointing to where `continue` should
* end up.
* @type {Array<CodePathSegment>|null}
*/
continueDestSegments: Array<CodePathSegment> | null;
}
/**
* Represents the context for a `for-of` loop.
*/
declare class ForOfLoopContext extends LoopContextBase {
/**
* Creates a new instance.
* @param {LoopContext|null} upperContext The previous `LoopContext`.
* @param {string|null} label The label for the loop from an enclosing `LabeledStatement`.
* @param {BreakContext} breakContext The context for breaking the loop.
*/
constructor(upperContext: LoopContext | null, label: string | null, breakContext: BreakContext);
/**
* The segments that came immediately before the start of the loop.
* This allows you to traverse backwards out of the loop into the
* surrounding code. This is necessary to evaluate the right expression
* correctly, as it must be evaluated in the same way as the left
* expression, but the pointer to these segments would otherwise be
* lost if not stored on the instance. Once the right expression has
* been evaluated, this property is no longer used.
* @type {Array<CodePathSegment>|null}
*/
prevSegments: Array<CodePathSegment> | null;
/**
* Segments representing the start of everything to the left of the
* `of` keyword. This can be used to move forward towards
* `endOfLeftSegments`. `leftSegments` and `endOfLeftSegments` are
* effectively the head and tail of a doubly-linked list.
* @type {Array<CodePathSegment>|null}
*/
leftSegments: Array<CodePathSegment> | null;
/**
* Segments representing the end of everything to the left of the
* `of` keyword. This can be used to move backward towards `leftSegments`.
* `leftSegments` and `endOfLeftSegments` are effectively the head
* and tail of a doubly-linked list.
* @type {Array<CodePathSegment>|null}
*/
endOfLeftSegments: Array<CodePathSegment> | null;
/**
* The segments representing the left expression where `continue` will
* jump to. In `for-in` loops, `continue` must always re-execute the
* left expression each time through the loop. This contains the same
* segments as `leftSegments`, but is duplicated here so each loop
* context has the same property pointing to where `continue` should
* end up.
* @type {Array<CodePathSegment>|null}
*/
continueDestSegments: Array<CodePathSegment> | null;
}
/**
* Base class for all loop contexts.
*/
declare class LoopContextBase {
/**
* Creates a new instance.
* @param {LoopContext|null} upperContext The previous `LoopContext`.
* @param {string} type The AST node's `type` for the loop.
* @param {string|null} label The label for the loop from an enclosing `LabeledStatement`.
* @param {BreakContext} breakContext The context for breaking the loop.
*/
constructor(upperContext: LoopContext | null, type: string, label: string | null, breakContext: BreakContext);
/**
* The previous `LoopContext`.
* @type {LoopContext}
*/
upper: LoopContext;
/**
* The AST node's `type` for the loop.
* @type {string}
*/
type: string;
/**
* The label for the loop from an enclosing `LabeledStatement`.
* @type {string|null}
*/
label: string | null;
/**
* The fork context for when `break` is encountered.
* @type {ForkContext}
*/
brokenForkContext: ForkContext;
}