using Microsoft.SqlServer.TransactSql.ScriptDom;
using SQLLinter.Common;
using SQLLinter.Common.Helpers;
using System.Text.RegularExpressions;
namespace SQLLinter.Infrastructure.Rules;
///
/// Ожидается наличие BEGIN - END в блоке IF
///
public class ConditionalBeginEndRule : BaseRuleVisitor, IRule
{
private readonly Regex IsWhiteSpaceOrSemiColon = new Regex(@"\s|;", RegexOptions.Compiled);
public override string Text => "Ожидается наличие BEGIN - END в блоке IF";
public override void Visit(IfStatement node)
{
if (node.ThenStatement != null && node.ThenStatement is not BeginEndBlockStatement)
{
if (node.ThenStatement.StartLine != node.StartLine || node.ScriptTokenStream.Where(t => t.Offset <= node.ThenStatement.StartOffset + node.ThenStatement.FragmentLength).Max(t => t.Line) != node.StartLine)
{
AddViolation(node.ThenStatement);
}
}
if (node.ElseStatement != null && node.ElseStatement is not BeginEndBlockStatement && node.ElseStatement is not IfStatement)
{
if (node.ElseStatement.StartLine != node.StartLine || node.ScriptTokenStream.Where(t => t.Offset <= node.ElseStatement.StartOffset + node.ElseStatement.FragmentLength).Max(t => t.Line) != node.StartLine)
{
AddViolation(node.ElseStatement);
}
}
}
public override void FixViolation(List fileLines, IRuleViolation ruleViolation, FileLineActions actions)
{
var ifNode = FixHelpers.FindViolatingNode(fileLines, ruleViolation);
TSqlStatement statement;
if (ifNode == null)
{
(statement, ifNode) = FindElse(fileLines, ruleViolation);
}
else
{
statement = ifNode.ThenStatement;
}
var stream = statement.ScriptTokenStream;
var indent = FixHelpers.GetIndent(fileLines, ifNode);
var beingLine = stream[statement.FirstTokenIndex].Line - 1;
var ifNodeLastToken = stream[statement.LastTokenIndex];
var endLine = stream[statement.LastTokenIndex].Line;
if (statement.StartLine == ifNodeLastToken.Line)
{
var index = statement.LastTokenIndex;
actions.InsertInLine(statement.StartLine - 1, stream[index].Column, " END");
actions.InsertInLine(statement.StartLine - 1, statement.StartColumn - 1, "BEGIN ");
}
else
{
actions.Insert(endLine, $"{indent}END");
actions.Insert(beingLine, $"{indent}BEGIN");
}
static (TSqlStatement, IfStatement) FindElse(List fileLines, IRuleViolation ruleViolation)
{
return FixHelpers.FindViolatingNode(
fileLines, ruleViolation, x => x.ElseStatement);
}
}
}