 85bf1341f3
			
		
	
	85bf1341f3
	
	
	
		
			
			Frontend Enhancements: - Complete React TypeScript frontend with modern UI components - Distributed workflows management interface with real-time updates - Socket.IO integration for live agent status monitoring - Agent management dashboard with cluster visualization - Project management interface with metrics and task tracking - Responsive design with proper error handling and loading states Backend Infrastructure: - Distributed coordinator for multi-agent workflow orchestration - Cluster management API with comprehensive agent operations - Enhanced database models for agents and projects - Project service for filesystem-based project discovery - Performance monitoring and metrics collection - Comprehensive API documentation and error handling Documentation: - Complete distributed development guide (README_DISTRIBUTED.md) - Comprehensive development report with architecture insights - System configuration templates and deployment guides The platform now provides a complete web interface for managing the distributed AI cluster with real-time monitoring, workflow orchestration, and agent coordination capabilities. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			591 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			591 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * @fileoverview Rule to require or disallow newlines between statements
 | |
|  * @author Toru Nagashima
 | |
|  * @deprecated in ESLint v8.53.0
 | |
|  */
 | |
| 
 | |
| "use strict";
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Requirements
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| const astUtils = require("./utils/ast-utils");
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Helpers
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| const LT = `[${Array.from(astUtils.LINEBREAKS).join("")}]`;
 | |
| const PADDING_LINE_SEQUENCE = new RegExp(
 | |
|     String.raw`^(\s*?${LT})\s*${LT}(\s*;?)$`,
 | |
|     "u"
 | |
| );
 | |
| const CJS_EXPORT = /^(?:module\s*\.\s*)?exports(?:\s*\.|\s*\[|$)/u;
 | |
| const CJS_IMPORT = /^require\(/u;
 | |
| 
 | |
| /**
 | |
|  * Creates tester which check if a node starts with specific keyword.
 | |
|  * @param {string} keyword The keyword to test.
 | |
|  * @returns {Object} the created tester.
 | |
|  * @private
 | |
|  */
 | |
| function newKeywordTester(keyword) {
 | |
|     return {
 | |
|         test: (node, sourceCode) =>
 | |
|             sourceCode.getFirstToken(node).value === keyword
 | |
|     };
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Creates tester which check if a node starts with specific keyword and spans a single line.
 | |
|  * @param {string} keyword The keyword to test.
 | |
|  * @returns {Object} the created tester.
 | |
|  * @private
 | |
|  */
 | |
| function newSinglelineKeywordTester(keyword) {
 | |
|     return {
 | |
|         test: (node, sourceCode) =>
 | |
|             node.loc.start.line === node.loc.end.line &&
 | |
|             sourceCode.getFirstToken(node).value === keyword
 | |
|     };
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Creates tester which check if a node starts with specific keyword and spans multiple lines.
 | |
|  * @param {string} keyword The keyword to test.
 | |
|  * @returns {Object} the created tester.
 | |
|  * @private
 | |
|  */
 | |
| function newMultilineKeywordTester(keyword) {
 | |
|     return {
 | |
|         test: (node, sourceCode) =>
 | |
|             node.loc.start.line !== node.loc.end.line &&
 | |
|             sourceCode.getFirstToken(node).value === keyword
 | |
|     };
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Creates tester which check if a node is specific type.
 | |
|  * @param {string} type The node type to test.
 | |
|  * @returns {Object} the created tester.
 | |
|  * @private
 | |
|  */
 | |
| function newNodeTypeTester(type) {
 | |
|     return {
 | |
|         test: node =>
 | |
|             node.type === type
 | |
|     };
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Checks the given node is an expression statement of IIFE.
 | |
|  * @param {ASTNode} node The node to check.
 | |
|  * @returns {boolean} `true` if the node is an expression statement of IIFE.
 | |
|  * @private
 | |
|  */
 | |
| function isIIFEStatement(node) {
 | |
|     if (node.type === "ExpressionStatement") {
 | |
|         let call = astUtils.skipChainExpression(node.expression);
 | |
| 
 | |
|         if (call.type === "UnaryExpression") {
 | |
|             call = astUtils.skipChainExpression(call.argument);
 | |
|         }
 | |
|         return call.type === "CallExpression" && astUtils.isFunction(call.callee);
 | |
|     }
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Checks whether the given node is a block-like statement.
 | |
|  * This checks the last token of the node is the closing brace of a block.
 | |
|  * @param {SourceCode} sourceCode The source code to get tokens.
 | |
|  * @param {ASTNode} node The node to check.
 | |
|  * @returns {boolean} `true` if the node is a block-like statement.
 | |
|  * @private
 | |
|  */
 | |
| function isBlockLikeStatement(sourceCode, node) {
 | |
| 
 | |
|     // do-while with a block is a block-like statement.
 | |
|     if (node.type === "DoWhileStatement" && node.body.type === "BlockStatement") {
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * IIFE is a block-like statement specially from
 | |
|      * JSCS#disallowPaddingNewLinesAfterBlocks.
 | |
|      */
 | |
|     if (isIIFEStatement(node)) {
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     // Checks the last token is a closing brace of blocks.
 | |
|     const lastToken = sourceCode.getLastToken(node, astUtils.isNotSemicolonToken);
 | |
|     const belongingNode = lastToken && astUtils.isClosingBraceToken(lastToken)
 | |
|         ? sourceCode.getNodeByRangeIndex(lastToken.range[0])
 | |
|         : null;
 | |
| 
 | |
|     return Boolean(belongingNode) && (
 | |
|         belongingNode.type === "BlockStatement" ||
 | |
|         belongingNode.type === "SwitchStatement"
 | |
|     );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Gets the actual last token.
 | |
|  *
 | |
|  * If a semicolon is semicolon-less style's semicolon, this ignores it.
 | |
|  * For example:
 | |
|  *
 | |
|  *     foo()
 | |
|  *     ;[1, 2, 3].forEach(bar)
 | |
|  * @param {SourceCode} sourceCode The source code to get tokens.
 | |
|  * @param {ASTNode} node The node to get.
 | |
|  * @returns {Token} The actual last token.
 | |
|  * @private
 | |
|  */
 | |
| function getActualLastToken(sourceCode, node) {
 | |
|     const semiToken = sourceCode.getLastToken(node);
 | |
|     const prevToken = sourceCode.getTokenBefore(semiToken);
 | |
|     const nextToken = sourceCode.getTokenAfter(semiToken);
 | |
|     const isSemicolonLessStyle = Boolean(
 | |
|         prevToken &&
 | |
|         nextToken &&
 | |
|         prevToken.range[0] >= node.range[0] &&
 | |
|         astUtils.isSemicolonToken(semiToken) &&
 | |
|         semiToken.loc.start.line !== prevToken.loc.end.line &&
 | |
|         semiToken.loc.end.line === nextToken.loc.start.line
 | |
|     );
 | |
| 
 | |
|     return isSemicolonLessStyle ? prevToken : semiToken;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * This returns the concatenation of the first 2 captured strings.
 | |
|  * @param {string} _ Unused. Whole matched string.
 | |
|  * @param {string} trailingSpaces The trailing spaces of the first line.
 | |
|  * @param {string} indentSpaces The indentation spaces of the last line.
 | |
|  * @returns {string} The concatenation of trailingSpaces and indentSpaces.
 | |
|  * @private
 | |
|  */
 | |
| function replacerToRemovePaddingLines(_, trailingSpaces, indentSpaces) {
 | |
|     return trailingSpaces + indentSpaces;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Check and report statements for `any` configuration.
 | |
|  * It does nothing.
 | |
|  * @returns {void}
 | |
|  * @private
 | |
|  */
 | |
| function verifyForAny() {
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Check and report statements for `never` configuration.
 | |
|  * This autofix removes blank lines between the given 2 statements.
 | |
|  * However, if comments exist between 2 blank lines, it does not remove those
 | |
|  * blank lines automatically.
 | |
|  * @param {RuleContext} context The rule context to report.
 | |
|  * @param {ASTNode} _ Unused. The previous node to check.
 | |
|  * @param {ASTNode} nextNode The next node to check.
 | |
|  * @param {Array<Token[]>} paddingLines The array of token pairs that blank
 | |
|  * lines exist between the pair.
 | |
|  * @returns {void}
 | |
|  * @private
 | |
|  */
 | |
| function verifyForNever(context, _, nextNode, paddingLines) {
 | |
|     if (paddingLines.length === 0) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     context.report({
 | |
|         node: nextNode,
 | |
|         messageId: "unexpectedBlankLine",
 | |
|         fix(fixer) {
 | |
|             if (paddingLines.length >= 2) {
 | |
|                 return null;
 | |
|             }
 | |
| 
 | |
|             const prevToken = paddingLines[0][0];
 | |
|             const nextToken = paddingLines[0][1];
 | |
|             const start = prevToken.range[1];
 | |
|             const end = nextToken.range[0];
 | |
|             const text = context.sourceCode.text
 | |
|                 .slice(start, end)
 | |
|                 .replace(PADDING_LINE_SEQUENCE, replacerToRemovePaddingLines);
 | |
| 
 | |
|             return fixer.replaceTextRange([start, end], text);
 | |
|         }
 | |
|     });
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Check and report statements for `always` configuration.
 | |
|  * This autofix inserts a blank line between the given 2 statements.
 | |
|  * If the `prevNode` has trailing comments, it inserts a blank line after the
 | |
|  * trailing comments.
 | |
|  * @param {RuleContext} context The rule context to report.
 | |
|  * @param {ASTNode} prevNode The previous node to check.
 | |
|  * @param {ASTNode} nextNode The next node to check.
 | |
|  * @param {Array<Token[]>} paddingLines The array of token pairs that blank
 | |
|  * lines exist between the pair.
 | |
|  * @returns {void}
 | |
|  * @private
 | |
|  */
 | |
| function verifyForAlways(context, prevNode, nextNode, paddingLines) {
 | |
|     if (paddingLines.length > 0) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     context.report({
 | |
|         node: nextNode,
 | |
|         messageId: "expectedBlankLine",
 | |
|         fix(fixer) {
 | |
|             const sourceCode = context.sourceCode;
 | |
|             let prevToken = getActualLastToken(sourceCode, prevNode);
 | |
|             const nextToken = sourceCode.getFirstTokenBetween(
 | |
|                 prevToken,
 | |
|                 nextNode,
 | |
|                 {
 | |
|                     includeComments: true,
 | |
| 
 | |
|                     /**
 | |
|                      * Skip the trailing comments of the previous node.
 | |
|                      * This inserts a blank line after the last trailing comment.
 | |
|                      *
 | |
|                      * For example:
 | |
|                      *
 | |
|                      *     foo(); // trailing comment.
 | |
|                      *     // comment.
 | |
|                      *     bar();
 | |
|                      *
 | |
|                      * Get fixed to:
 | |
|                      *
 | |
|                      *     foo(); // trailing comment.
 | |
|                      *
 | |
|                      *     // comment.
 | |
|                      *     bar();
 | |
|                      * @param {Token} token The token to check.
 | |
|                      * @returns {boolean} `true` if the token is not a trailing comment.
 | |
|                      * @private
 | |
|                      */
 | |
|                     filter(token) {
 | |
|                         if (astUtils.isTokenOnSameLine(prevToken, token)) {
 | |
|                             prevToken = token;
 | |
|                             return false;
 | |
|                         }
 | |
|                         return true;
 | |
|                     }
 | |
|                 }
 | |
|             ) || nextNode;
 | |
|             const insertText = astUtils.isTokenOnSameLine(prevToken, nextToken)
 | |
|                 ? "\n\n"
 | |
|                 : "\n";
 | |
| 
 | |
|             return fixer.insertTextAfter(prevToken, insertText);
 | |
|         }
 | |
|     });
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Types of blank lines.
 | |
|  * `any`, `never`, and `always` are defined.
 | |
|  * Those have `verify` method to check and report statements.
 | |
|  * @private
 | |
|  */
 | |
| const PaddingTypes = {
 | |
|     any: { verify: verifyForAny },
 | |
|     never: { verify: verifyForNever },
 | |
|     always: { verify: verifyForAlways }
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Types of statements.
 | |
|  * Those have `test` method to check it matches to the given statement.
 | |
|  * @private
 | |
|  */
 | |
| const StatementTypes = {
 | |
|     "*": { test: () => true },
 | |
|     "block-like": {
 | |
|         test: (node, sourceCode) => isBlockLikeStatement(sourceCode, node)
 | |
|     },
 | |
|     "cjs-export": {
 | |
|         test: (node, sourceCode) =>
 | |
|             node.type === "ExpressionStatement" &&
 | |
|             node.expression.type === "AssignmentExpression" &&
 | |
|             CJS_EXPORT.test(sourceCode.getText(node.expression.left))
 | |
|     },
 | |
|     "cjs-import": {
 | |
|         test: (node, sourceCode) =>
 | |
|             node.type === "VariableDeclaration" &&
 | |
|             node.declarations.length > 0 &&
 | |
|             Boolean(node.declarations[0].init) &&
 | |
|             CJS_IMPORT.test(sourceCode.getText(node.declarations[0].init))
 | |
|     },
 | |
|     directive: {
 | |
|         test: astUtils.isDirective
 | |
|     },
 | |
|     expression: {
 | |
|         test: node => node.type === "ExpressionStatement" && !astUtils.isDirective(node)
 | |
|     },
 | |
|     iife: {
 | |
|         test: isIIFEStatement
 | |
|     },
 | |
|     "multiline-block-like": {
 | |
|         test: (node, sourceCode) =>
 | |
|             node.loc.start.line !== node.loc.end.line &&
 | |
|             isBlockLikeStatement(sourceCode, node)
 | |
|     },
 | |
|     "multiline-expression": {
 | |
|         test: node =>
 | |
|             node.loc.start.line !== node.loc.end.line &&
 | |
|             node.type === "ExpressionStatement" &&
 | |
|             !astUtils.isDirective(node)
 | |
|     },
 | |
| 
 | |
|     "multiline-const": newMultilineKeywordTester("const"),
 | |
|     "multiline-let": newMultilineKeywordTester("let"),
 | |
|     "multiline-var": newMultilineKeywordTester("var"),
 | |
|     "singleline-const": newSinglelineKeywordTester("const"),
 | |
|     "singleline-let": newSinglelineKeywordTester("let"),
 | |
|     "singleline-var": newSinglelineKeywordTester("var"),
 | |
| 
 | |
|     block: newNodeTypeTester("BlockStatement"),
 | |
|     empty: newNodeTypeTester("EmptyStatement"),
 | |
|     function: newNodeTypeTester("FunctionDeclaration"),
 | |
| 
 | |
|     break: newKeywordTester("break"),
 | |
|     case: newKeywordTester("case"),
 | |
|     class: newKeywordTester("class"),
 | |
|     const: newKeywordTester("const"),
 | |
|     continue: newKeywordTester("continue"),
 | |
|     debugger: newKeywordTester("debugger"),
 | |
|     default: newKeywordTester("default"),
 | |
|     do: newKeywordTester("do"),
 | |
|     export: newKeywordTester("export"),
 | |
|     for: newKeywordTester("for"),
 | |
|     if: newKeywordTester("if"),
 | |
|     import: newKeywordTester("import"),
 | |
|     let: newKeywordTester("let"),
 | |
|     return: newKeywordTester("return"),
 | |
|     switch: newKeywordTester("switch"),
 | |
|     throw: newKeywordTester("throw"),
 | |
|     try: newKeywordTester("try"),
 | |
|     var: newKeywordTester("var"),
 | |
|     while: newKeywordTester("while"),
 | |
|     with: newKeywordTester("with")
 | |
| };
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Rule Definition
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| /** @type {import('../shared/types').Rule} */
 | |
| module.exports = {
 | |
|     meta: {
 | |
|         deprecated: true,
 | |
|         replacedBy: [],
 | |
|         type: "layout",
 | |
| 
 | |
|         docs: {
 | |
|             description: "Require or disallow padding lines between statements",
 | |
|             recommended: false,
 | |
|             url: "https://eslint.org/docs/latest/rules/padding-line-between-statements"
 | |
|         },
 | |
| 
 | |
|         fixable: "whitespace",
 | |
| 
 | |
|         schema: {
 | |
|             definitions: {
 | |
|                 paddingType: {
 | |
|                     enum: Object.keys(PaddingTypes)
 | |
|                 },
 | |
|                 statementType: {
 | |
|                     anyOf: [
 | |
|                         { enum: Object.keys(StatementTypes) },
 | |
|                         {
 | |
|                             type: "array",
 | |
|                             items: { enum: Object.keys(StatementTypes) },
 | |
|                             minItems: 1,
 | |
|                             uniqueItems: true
 | |
|                         }
 | |
|                     ]
 | |
|                 }
 | |
|             },
 | |
|             type: "array",
 | |
|             items: {
 | |
|                 type: "object",
 | |
|                 properties: {
 | |
|                     blankLine: { $ref: "#/definitions/paddingType" },
 | |
|                     prev: { $ref: "#/definitions/statementType" },
 | |
|                     next: { $ref: "#/definitions/statementType" }
 | |
|                 },
 | |
|                 additionalProperties: false,
 | |
|                 required: ["blankLine", "prev", "next"]
 | |
|             }
 | |
|         },
 | |
| 
 | |
|         messages: {
 | |
|             unexpectedBlankLine: "Unexpected blank line before this statement.",
 | |
|             expectedBlankLine: "Expected blank line before this statement."
 | |
|         }
 | |
|     },
 | |
| 
 | |
|     create(context) {
 | |
|         const sourceCode = context.sourceCode;
 | |
|         const configureList = context.options || [];
 | |
|         let scopeInfo = null;
 | |
| 
 | |
|         /**
 | |
|          * Processes to enter to new scope.
 | |
|          * This manages the current previous statement.
 | |
|          * @returns {void}
 | |
|          * @private
 | |
|          */
 | |
|         function enterScope() {
 | |
|             scopeInfo = {
 | |
|                 upper: scopeInfo,
 | |
|                 prevNode: null
 | |
|             };
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Processes to exit from the current scope.
 | |
|          * @returns {void}
 | |
|          * @private
 | |
|          */
 | |
|         function exitScope() {
 | |
|             scopeInfo = scopeInfo.upper;
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Checks whether the given node matches the given type.
 | |
|          * @param {ASTNode} node The statement node to check.
 | |
|          * @param {string|string[]} type The statement type to check.
 | |
|          * @returns {boolean} `true` if the statement node matched the type.
 | |
|          * @private
 | |
|          */
 | |
|         function match(node, type) {
 | |
|             let innerStatementNode = node;
 | |
| 
 | |
|             while (innerStatementNode.type === "LabeledStatement") {
 | |
|                 innerStatementNode = innerStatementNode.body;
 | |
|             }
 | |
|             if (Array.isArray(type)) {
 | |
|                 return type.some(match.bind(null, innerStatementNode));
 | |
|             }
 | |
|             return StatementTypes[type].test(innerStatementNode, sourceCode);
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Finds the last matched configure from configureList.
 | |
|          * @param {ASTNode} prevNode The previous statement to match.
 | |
|          * @param {ASTNode} nextNode The current statement to match.
 | |
|          * @returns {Object} The tester of the last matched configure.
 | |
|          * @private
 | |
|          */
 | |
|         function getPaddingType(prevNode, nextNode) {
 | |
|             for (let i = configureList.length - 1; i >= 0; --i) {
 | |
|                 const configure = configureList[i];
 | |
|                 const matched =
 | |
|                     match(prevNode, configure.prev) &&
 | |
|                     match(nextNode, configure.next);
 | |
| 
 | |
|                 if (matched) {
 | |
|                     return PaddingTypes[configure.blankLine];
 | |
|                 }
 | |
|             }
 | |
|             return PaddingTypes.any;
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Gets padding line sequences between the given 2 statements.
 | |
|          * Comments are separators of the padding line sequences.
 | |
|          * @param {ASTNode} prevNode The previous statement to count.
 | |
|          * @param {ASTNode} nextNode The current statement to count.
 | |
|          * @returns {Array<Token[]>} The array of token pairs.
 | |
|          * @private
 | |
|          */
 | |
|         function getPaddingLineSequences(prevNode, nextNode) {
 | |
|             const pairs = [];
 | |
|             let prevToken = getActualLastToken(sourceCode, prevNode);
 | |
| 
 | |
|             if (nextNode.loc.start.line - prevToken.loc.end.line >= 2) {
 | |
|                 do {
 | |
|                     const token = sourceCode.getTokenAfter(
 | |
|                         prevToken,
 | |
|                         { includeComments: true }
 | |
|                     );
 | |
| 
 | |
|                     if (token.loc.start.line - prevToken.loc.end.line >= 2) {
 | |
|                         pairs.push([prevToken, token]);
 | |
|                     }
 | |
|                     prevToken = token;
 | |
| 
 | |
|                 } while (prevToken.range[0] < nextNode.range[0]);
 | |
|             }
 | |
| 
 | |
|             return pairs;
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Verify padding lines between the given node and the previous node.
 | |
|          * @param {ASTNode} node The node to verify.
 | |
|          * @returns {void}
 | |
|          * @private
 | |
|          */
 | |
|         function verify(node) {
 | |
|             const parentType = node.parent.type;
 | |
|             const validParent =
 | |
|                 astUtils.STATEMENT_LIST_PARENTS.has(parentType) ||
 | |
|                 parentType === "SwitchStatement";
 | |
| 
 | |
|             if (!validParent) {
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             // Save this node as the current previous statement.
 | |
|             const prevNode = scopeInfo.prevNode;
 | |
| 
 | |
|             // Verify.
 | |
|             if (prevNode) {
 | |
|                 const type = getPaddingType(prevNode, node);
 | |
|                 const paddingLines = getPaddingLineSequences(prevNode, node);
 | |
| 
 | |
|                 type.verify(context, prevNode, node, paddingLines);
 | |
|             }
 | |
| 
 | |
|             scopeInfo.prevNode = node;
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Verify padding lines between the given node and the previous node.
 | |
|          * Then process to enter to new scope.
 | |
|          * @param {ASTNode} node The node to verify.
 | |
|          * @returns {void}
 | |
|          * @private
 | |
|          */
 | |
|         function verifyThenEnterScope(node) {
 | |
|             verify(node);
 | |
|             enterScope();
 | |
|         }
 | |
| 
 | |
|         return {
 | |
|             Program: enterScope,
 | |
|             BlockStatement: enterScope,
 | |
|             SwitchStatement: enterScope,
 | |
|             StaticBlock: enterScope,
 | |
|             "Program:exit": exitScope,
 | |
|             "BlockStatement:exit": exitScope,
 | |
|             "SwitchStatement:exit": exitScope,
 | |
|             "StaticBlock:exit": exitScope,
 | |
| 
 | |
|             ":statement": verify,
 | |
| 
 | |
|             SwitchCase: verifyThenEnterScope,
 | |
|             "SwitchCase:exit": exitScope
 | |
|         };
 | |
|     }
 | |
| };
 |