 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>
		
			
				
	
	
		
			508 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			508 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * @fileoverview Rule to disallow use of the `RegExp` constructor in favor of regular expression literals
 | |
|  * @author Milos Djermanovic
 | |
|  */
 | |
| 
 | |
| "use strict";
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Requirements
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| const astUtils = require("./utils/ast-utils");
 | |
| const { CALL, CONSTRUCT, ReferenceTracker, findVariable } = require("@eslint-community/eslint-utils");
 | |
| const { RegExpValidator, visitRegExpAST, RegExpParser } = require("@eslint-community/regexpp");
 | |
| const { canTokensBeAdjacent } = require("./utils/ast-utils");
 | |
| const { REGEXPP_LATEST_ECMA_VERSION } = require("./utils/regular-expressions");
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Helpers
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| /**
 | |
|  * Determines whether the given node is a string literal.
 | |
|  * @param {ASTNode} node Node to check.
 | |
|  * @returns {boolean} True if the node is a string literal.
 | |
|  */
 | |
| function isStringLiteral(node) {
 | |
|     return node.type === "Literal" && typeof node.value === "string";
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Determines whether the given node is a regex literal.
 | |
|  * @param {ASTNode} node Node to check.
 | |
|  * @returns {boolean} True if the node is a regex literal.
 | |
|  */
 | |
| function isRegexLiteral(node) {
 | |
|     return node.type === "Literal" && Object.prototype.hasOwnProperty.call(node, "regex");
 | |
| }
 | |
| 
 | |
| const validPrecedingTokens = new Set([
 | |
|     "(",
 | |
|     ";",
 | |
|     "[",
 | |
|     ",",
 | |
|     "=",
 | |
|     "+",
 | |
|     "*",
 | |
|     "-",
 | |
|     "?",
 | |
|     "~",
 | |
|     "%",
 | |
|     "**",
 | |
|     "!",
 | |
|     "typeof",
 | |
|     "instanceof",
 | |
|     "&&",
 | |
|     "||",
 | |
|     "??",
 | |
|     "return",
 | |
|     "...",
 | |
|     "delete",
 | |
|     "void",
 | |
|     "in",
 | |
|     "<",
 | |
|     ">",
 | |
|     "<=",
 | |
|     ">=",
 | |
|     "==",
 | |
|     "===",
 | |
|     "!=",
 | |
|     "!==",
 | |
|     "<<",
 | |
|     ">>",
 | |
|     ">>>",
 | |
|     "&",
 | |
|     "|",
 | |
|     "^",
 | |
|     ":",
 | |
|     "{",
 | |
|     "=>",
 | |
|     "*=",
 | |
|     "<<=",
 | |
|     ">>=",
 | |
|     ">>>=",
 | |
|     "^=",
 | |
|     "|=",
 | |
|     "&=",
 | |
|     "??=",
 | |
|     "||=",
 | |
|     "&&=",
 | |
|     "**=",
 | |
|     "+=",
 | |
|     "-=",
 | |
|     "/=",
 | |
|     "%=",
 | |
|     "/",
 | |
|     "do",
 | |
|     "break",
 | |
|     "continue",
 | |
|     "debugger",
 | |
|     "case",
 | |
|     "throw"
 | |
| ]);
 | |
| 
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Rule Definition
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| /** @type {import('../shared/types').Rule} */
 | |
| module.exports = {
 | |
|     meta: {
 | |
|         type: "suggestion",
 | |
| 
 | |
|         docs: {
 | |
|             description: "Disallow use of the `RegExp` constructor in favor of regular expression literals",
 | |
|             recommended: false,
 | |
|             url: "https://eslint.org/docs/latest/rules/prefer-regex-literals"
 | |
|         },
 | |
| 
 | |
|         hasSuggestions: true,
 | |
| 
 | |
|         schema: [
 | |
|             {
 | |
|                 type: "object",
 | |
|                 properties: {
 | |
|                     disallowRedundantWrapping: {
 | |
|                         type: "boolean",
 | |
|                         default: false
 | |
|                     }
 | |
|                 },
 | |
|                 additionalProperties: false
 | |
|             }
 | |
|         ],
 | |
| 
 | |
|         messages: {
 | |
|             unexpectedRegExp: "Use a regular expression literal instead of the 'RegExp' constructor.",
 | |
|             replaceWithLiteral: "Replace with an equivalent regular expression literal.",
 | |
|             replaceWithLiteralAndFlags: "Replace with an equivalent regular expression literal with flags '{{ flags }}'.",
 | |
|             replaceWithIntendedLiteralAndFlags: "Replace with a regular expression literal with flags '{{ flags }}'.",
 | |
|             unexpectedRedundantRegExp: "Regular expression literal is unnecessarily wrapped within a 'RegExp' constructor.",
 | |
|             unexpectedRedundantRegExpWithFlags: "Use regular expression literal with flags instead of the 'RegExp' constructor."
 | |
|         }
 | |
|     },
 | |
| 
 | |
|     create(context) {
 | |
|         const [{ disallowRedundantWrapping = false } = {}] = context.options;
 | |
|         const sourceCode = context.sourceCode;
 | |
| 
 | |
|         /**
 | |
|          * Determines whether the given identifier node is a reference to a global variable.
 | |
|          * @param {ASTNode} node `Identifier` node to check.
 | |
|          * @returns {boolean} True if the identifier is a reference to a global variable.
 | |
|          */
 | |
|         function isGlobalReference(node) {
 | |
|             const scope = sourceCode.getScope(node);
 | |
|             const variable = findVariable(scope, node);
 | |
| 
 | |
|             return variable !== null && variable.scope.type === "global" && variable.defs.length === 0;
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Determines whether the given node is a String.raw`` tagged template expression
 | |
|          * with a static template literal.
 | |
|          * @param {ASTNode} node Node to check.
 | |
|          * @returns {boolean} True if the node is String.raw`` with a static template.
 | |
|          */
 | |
|         function isStringRawTaggedStaticTemplateLiteral(node) {
 | |
|             return node.type === "TaggedTemplateExpression" &&
 | |
|                 astUtils.isSpecificMemberAccess(node.tag, "String", "raw") &&
 | |
|                 isGlobalReference(astUtils.skipChainExpression(node.tag).object) &&
 | |
|                 astUtils.isStaticTemplateLiteral(node.quasi);
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Gets the value of a string
 | |
|          * @param {ASTNode} node The node to get the string of.
 | |
|          * @returns {string|null} The value of the node.
 | |
|          */
 | |
|         function getStringValue(node) {
 | |
|             if (isStringLiteral(node)) {
 | |
|                 return node.value;
 | |
|             }
 | |
| 
 | |
|             if (astUtils.isStaticTemplateLiteral(node)) {
 | |
|                 return node.quasis[0].value.cooked;
 | |
|             }
 | |
| 
 | |
|             if (isStringRawTaggedStaticTemplateLiteral(node)) {
 | |
|                 return node.quasi.quasis[0].value.raw;
 | |
|             }
 | |
| 
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Determines whether the given node is considered to be a static string by the logic of this rule.
 | |
|          * @param {ASTNode} node Node to check.
 | |
|          * @returns {boolean} True if the node is a static string.
 | |
|          */
 | |
|         function isStaticString(node) {
 | |
|             return isStringLiteral(node) ||
 | |
|                 astUtils.isStaticTemplateLiteral(node) ||
 | |
|                 isStringRawTaggedStaticTemplateLiteral(node);
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Determines whether the relevant arguments of the given are all static string literals.
 | |
|          * @param {ASTNode} node Node to check.
 | |
|          * @returns {boolean} True if all arguments are static strings.
 | |
|          */
 | |
|         function hasOnlyStaticStringArguments(node) {
 | |
|             const args = node.arguments;
 | |
| 
 | |
|             if ((args.length === 1 || args.length === 2) && args.every(isStaticString)) {
 | |
|                 return true;
 | |
|             }
 | |
| 
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Determines whether the arguments of the given node indicate that a regex literal is unnecessarily wrapped.
 | |
|          * @param {ASTNode} node Node to check.
 | |
|          * @returns {boolean} True if the node already contains a regex literal argument.
 | |
|          */
 | |
|         function isUnnecessarilyWrappedRegexLiteral(node) {
 | |
|             const args = node.arguments;
 | |
| 
 | |
|             if (args.length === 1 && isRegexLiteral(args[0])) {
 | |
|                 return true;
 | |
|             }
 | |
| 
 | |
|             if (args.length === 2 && isRegexLiteral(args[0]) && isStaticString(args[1])) {
 | |
|                 return true;
 | |
|             }
 | |
| 
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Returns a ecmaVersion compatible for regexpp.
 | |
|          * @param {number} ecmaVersion The ecmaVersion to convert.
 | |
|          * @returns {import("@eslint-community/regexpp/ecma-versions").EcmaVersion} The resulting ecmaVersion compatible for regexpp.
 | |
|          */
 | |
|         function getRegexppEcmaVersion(ecmaVersion) {
 | |
|             if (ecmaVersion <= 5) {
 | |
|                 return 5;
 | |
|             }
 | |
|             return Math.min(ecmaVersion, REGEXPP_LATEST_ECMA_VERSION);
 | |
|         }
 | |
| 
 | |
|         const regexppEcmaVersion = getRegexppEcmaVersion(context.languageOptions.ecmaVersion);
 | |
| 
 | |
|         /**
 | |
|          * Makes a character escaped or else returns null.
 | |
|          * @param {string} character The character to escape.
 | |
|          * @returns {string} The resulting escaped character.
 | |
|          */
 | |
|         function resolveEscapes(character) {
 | |
|             switch (character) {
 | |
|                 case "\n":
 | |
|                 case "\\\n":
 | |
|                     return "\\n";
 | |
| 
 | |
|                 case "\r":
 | |
|                 case "\\\r":
 | |
|                     return "\\r";
 | |
| 
 | |
|                 case "\t":
 | |
|                 case "\\\t":
 | |
|                     return "\\t";
 | |
| 
 | |
|                 case "\v":
 | |
|                 case "\\\v":
 | |
|                     return "\\v";
 | |
| 
 | |
|                 case "\f":
 | |
|                 case "\\\f":
 | |
|                     return "\\f";
 | |
| 
 | |
|                 case "/":
 | |
|                     return "\\/";
 | |
| 
 | |
|                 default:
 | |
|                     return null;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Checks whether the given regex and flags are valid for the ecma version or not.
 | |
|          * @param {string} pattern The regex pattern to check.
 | |
|          * @param {string | undefined} flags The regex flags to check.
 | |
|          * @returns {boolean} True if the given regex pattern and flags are valid for the ecma version.
 | |
|          */
 | |
|         function isValidRegexForEcmaVersion(pattern, flags) {
 | |
|             const validator = new RegExpValidator({ ecmaVersion: regexppEcmaVersion });
 | |
| 
 | |
|             try {
 | |
|                 validator.validatePattern(pattern, 0, pattern.length, {
 | |
|                     unicode: flags ? flags.includes("u") : false,
 | |
|                     unicodeSets: flags ? flags.includes("v") : false
 | |
|                 });
 | |
|                 if (flags) {
 | |
|                     validator.validateFlags(flags);
 | |
|                 }
 | |
|                 return true;
 | |
|             } catch {
 | |
|                 return false;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Checks whether two given regex flags contain the same flags or not.
 | |
|          * @param {string} flagsA The regex flags.
 | |
|          * @param {string} flagsB The regex flags.
 | |
|          * @returns {boolean} True if two regex flags contain same flags.
 | |
|          */
 | |
|         function areFlagsEqual(flagsA, flagsB) {
 | |
|             return [...flagsA].sort().join("") === [...flagsB].sort().join("");
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /**
 | |
|          * Merges two regex flags.
 | |
|          * @param {string} flagsA The regex flags.
 | |
|          * @param {string} flagsB The regex flags.
 | |
|          * @returns {string} The merged regex flags.
 | |
|          */
 | |
|         function mergeRegexFlags(flagsA, flagsB) {
 | |
|             const flagsSet = new Set([
 | |
|                 ...flagsA,
 | |
|                 ...flagsB
 | |
|             ]);
 | |
| 
 | |
|             return [...flagsSet].join("");
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Checks whether a give node can be fixed to the given regex pattern and flags.
 | |
|          * @param {ASTNode} node The node to check.
 | |
|          * @param {string} pattern The regex pattern to check.
 | |
|          * @param {string} flags The regex flags
 | |
|          * @returns {boolean} True if a node can be fixed to the given regex pattern and flags.
 | |
|          */
 | |
|         function canFixTo(node, pattern, flags) {
 | |
|             const tokenBefore = sourceCode.getTokenBefore(node);
 | |
| 
 | |
|             return sourceCode.getCommentsInside(node).length === 0 &&
 | |
|                 (!tokenBefore || validPrecedingTokens.has(tokenBefore.value)) &&
 | |
|                 isValidRegexForEcmaVersion(pattern, flags);
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Returns a safe output code considering the before and after tokens.
 | |
|          * @param {ASTNode} node The regex node.
 | |
|          * @param {string} newRegExpValue The new regex expression value.
 | |
|          * @returns {string} The output code.
 | |
|          */
 | |
|         function getSafeOutput(node, newRegExpValue) {
 | |
|             const tokenBefore = sourceCode.getTokenBefore(node);
 | |
|             const tokenAfter = sourceCode.getTokenAfter(node);
 | |
| 
 | |
|             return (tokenBefore && !canTokensBeAdjacent(tokenBefore, newRegExpValue) && tokenBefore.range[1] === node.range[0] ? " " : "") +
 | |
|                 newRegExpValue +
 | |
|             (tokenAfter && !canTokensBeAdjacent(newRegExpValue, tokenAfter) && node.range[1] === tokenAfter.range[0] ? " " : "");
 | |
| 
 | |
|         }
 | |
| 
 | |
|         return {
 | |
|             Program(node) {
 | |
|                 const scope = sourceCode.getScope(node);
 | |
|                 const tracker = new ReferenceTracker(scope);
 | |
|                 const traceMap = {
 | |
|                     RegExp: {
 | |
|                         [CALL]: true,
 | |
|                         [CONSTRUCT]: true
 | |
|                     }
 | |
|                 };
 | |
| 
 | |
|                 for (const { node: refNode } of tracker.iterateGlobalReferences(traceMap)) {
 | |
|                     if (disallowRedundantWrapping && isUnnecessarilyWrappedRegexLiteral(refNode)) {
 | |
|                         const regexNode = refNode.arguments[0];
 | |
| 
 | |
|                         if (refNode.arguments.length === 2) {
 | |
|                             const suggests = [];
 | |
| 
 | |
|                             const argFlags = getStringValue(refNode.arguments[1]) || "";
 | |
| 
 | |
|                             if (canFixTo(refNode, regexNode.regex.pattern, argFlags)) {
 | |
|                                 suggests.push({
 | |
|                                     messageId: "replaceWithLiteralAndFlags",
 | |
|                                     pattern: regexNode.regex.pattern,
 | |
|                                     flags: argFlags
 | |
|                                 });
 | |
|                             }
 | |
| 
 | |
|                             const literalFlags = regexNode.regex.flags || "";
 | |
|                             const mergedFlags = mergeRegexFlags(literalFlags, argFlags);
 | |
| 
 | |
|                             if (
 | |
|                                 !areFlagsEqual(mergedFlags, argFlags) &&
 | |
|                                 canFixTo(refNode, regexNode.regex.pattern, mergedFlags)
 | |
|                             ) {
 | |
|                                 suggests.push({
 | |
|                                     messageId: "replaceWithIntendedLiteralAndFlags",
 | |
|                                     pattern: regexNode.regex.pattern,
 | |
|                                     flags: mergedFlags
 | |
|                                 });
 | |
|                             }
 | |
| 
 | |
|                             context.report({
 | |
|                                 node: refNode,
 | |
|                                 messageId: "unexpectedRedundantRegExpWithFlags",
 | |
|                                 suggest: suggests.map(({ flags, pattern, messageId }) => ({
 | |
|                                     messageId,
 | |
|                                     data: {
 | |
|                                         flags
 | |
|                                     },
 | |
|                                     fix(fixer) {
 | |
|                                         return fixer.replaceText(refNode, getSafeOutput(refNode, `/${pattern}/${flags}`));
 | |
|                                     }
 | |
|                                 }))
 | |
|                             });
 | |
|                         } else {
 | |
|                             const outputs = [];
 | |
| 
 | |
|                             if (canFixTo(refNode, regexNode.regex.pattern, regexNode.regex.flags)) {
 | |
|                                 outputs.push(sourceCode.getText(regexNode));
 | |
|                             }
 | |
| 
 | |
| 
 | |
|                             context.report({
 | |
|                                 node: refNode,
 | |
|                                 messageId: "unexpectedRedundantRegExp",
 | |
|                                 suggest: outputs.map(output => ({
 | |
|                                     messageId: "replaceWithLiteral",
 | |
|                                     fix(fixer) {
 | |
|                                         return fixer.replaceText(
 | |
|                                             refNode,
 | |
|                                             getSafeOutput(refNode, output)
 | |
|                                         );
 | |
|                                     }
 | |
|                                 }))
 | |
|                             });
 | |
|                         }
 | |
|                     } else if (hasOnlyStaticStringArguments(refNode)) {
 | |
|                         let regexContent = getStringValue(refNode.arguments[0]);
 | |
|                         let noFix = false;
 | |
|                         let flags;
 | |
| 
 | |
|                         if (refNode.arguments[1]) {
 | |
|                             flags = getStringValue(refNode.arguments[1]);
 | |
|                         }
 | |
| 
 | |
|                         if (!canFixTo(refNode, regexContent, flags)) {
 | |
|                             noFix = true;
 | |
|                         }
 | |
| 
 | |
|                         if (!/^[-a-zA-Z0-9\\[\](){} \t\r\n\v\f!@#$%^&*+^_=/~`.><?,'"|:;]*$/u.test(regexContent)) {
 | |
|                             noFix = true;
 | |
|                         }
 | |
| 
 | |
|                         if (regexContent && !noFix) {
 | |
|                             let charIncrease = 0;
 | |
| 
 | |
|                             const ast = new RegExpParser({ ecmaVersion: regexppEcmaVersion }).parsePattern(regexContent, 0, regexContent.length, {
 | |
|                                 unicode: flags ? flags.includes("u") : false,
 | |
|                                 unicodeSets: flags ? flags.includes("v") : false
 | |
|                             });
 | |
| 
 | |
|                             visitRegExpAST(ast, {
 | |
|                                 onCharacterEnter(characterNode) {
 | |
|                                     const escaped = resolveEscapes(characterNode.raw);
 | |
| 
 | |
|                                     if (escaped) {
 | |
|                                         regexContent =
 | |
|                                             regexContent.slice(0, characterNode.start + charIncrease) +
 | |
|                                             escaped +
 | |
|                                             regexContent.slice(characterNode.end + charIncrease);
 | |
| 
 | |
|                                         if (characterNode.raw.length === 1) {
 | |
|                                             charIncrease += 1;
 | |
|                                         }
 | |
|                                     }
 | |
|                                 }
 | |
|                             });
 | |
|                         }
 | |
| 
 | |
|                         const newRegExpValue = `/${regexContent || "(?:)"}/${flags || ""}`;
 | |
| 
 | |
|                         context.report({
 | |
|                             node: refNode,
 | |
|                             messageId: "unexpectedRegExp",
 | |
|                             suggest: noFix ? [] : [{
 | |
|                                 messageId: "replaceWithLiteral",
 | |
|                                 fix(fixer) {
 | |
|                                     return fixer.replaceText(refNode, getSafeOutput(refNode, newRegExpValue));
 | |
|                                 }
 | |
|                             }]
 | |
|                         });
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         };
 | |
|     }
 | |
| };
 |