private expr2ruleset()

in web-app/src/app/routes/alert/alert-setting/alert-setting.component.ts [587:720]


  private expr2ruleset(expr: string): RuleSet {
    if (!expr || !expr.trim()) {
      return { condition: 'and', rules: [] };
    }

    try {
      console.log('Parsing expression:', expr);

      // Helper function: find operator position considering brackets
      const findOperator = (str: string): { operator: string; position: number } | null => {
        let bracketCount = 0;
        let i = 0;

        while (i < str.length) {
          const char = str[i];

          if (char === '(') bracketCount++;
          else if (char === ')') bracketCount--;

          // Only look for operators at bracket level 0
          if (bracketCount === 0) {
            if (str.substring(i).startsWith(' and ')) {
              return { operator: 'and', position: i };
            }
            if (str.substring(i).startsWith(' or ')) {
              return { operator: 'or', position: i };
            }
          }
          i++;
        }
        return null;
      };

      // Helper function: validate and extract bracket content
      const extractBracketContent = (str: string): string | null => {
        if (!str.startsWith('(') || !str.endsWith(')')) return null;

        let bracketCount = 0;
        for (let i = 0; i < str.length; i++) {
          if (str[i] === '(') bracketCount++;
          if (str[i] === ')') bracketCount--;
          if (bracketCount < 0) return null;
        }
        return bracketCount === 0 ? str.slice(1, -1) : null;
      };

      // Helper function: parse expression recursively
      const parseExpr = (str: string): RuleSet | Rule | null => {
        str = str.trim();
        if (!str) return null;

        console.log('Parsing sub-expression:', str);

        // Try to parse as a single rule first
        const rule = this.parseExprToRule(str);
        if (rule) {
          console.log('Parsed as rule:', rule);
          return rule;
        }

        // Look for top-level AND/OR
        const operatorInfo = findOperator(str);
        if (operatorInfo) {
          const { operator, position } = operatorInfo;
          const left = str.substring(0, position).trim();
          const right = str.substring(position + (operator === 'and' ? 5 : 4)).trim();

          console.log(`Found ${operator} operator, splitting:`, { left, right });

          const ruleset: RuleSet = {
            condition: operator,
            rules: []
          };

          const leftResult = parseExpr(left);
          const rightResult = parseExpr(right);

          if (leftResult) {
            console.log('Adding left result:', leftResult);
            ruleset.rules.push(leftResult);
          }
          if (rightResult) {
            console.log('Adding right result:', rightResult);
            ruleset.rules.push(rightResult);
          }

          return ruleset;
        }

        // If no top-level operator found, try parsing bracketed content
        const bracketContent = extractBracketContent(str);
        if (bracketContent) {
          console.log('Found bracketed content:', bracketContent);
          const result = parseExpr(bracketContent);
          if (result) {
            // If it's already a RuleSet, keep the structure
            if ('condition' in result) {
              console.log('Returning nested ruleset:', result);
              return result;
            } else {
              // Create a new RuleSet for single rule to maintain bracket structure
              console.log('Creating ruleset for bracketed rule:', result);
              return {
                condition: 'and',
                rules: [result]
              };
            }
          }
        }

        return null;
      };

      const result = parseExpr(expr);
      if (!result) {
        console.warn('Failed to parse expression, returning empty ruleset');
        return { condition: 'and', rules: [] };
      }

      if ('condition' in result) {
        console.log('Final ruleset:', result);
        return result;
      } else {
        console.log('Creating final ruleset for single rule:', result);
        return {
          condition: 'and',
          rules: [result]
        };
      }
    } catch (e) {
      console.error('Failed to parse expression:', e);
      return { condition: 'and', rules: [] };
    }
  }