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: [] };
}
}