95 lines
3.3 KiB
C#
95 lines
3.3 KiB
C#
using Microsoft.SqlServer.TransactSql.ScriptDom;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace SQLLinter.Common.Helpers;
|
|
|
|
public static class FixHelpers
|
|
{
|
|
public class FindViolatingNodeVisitor<T> : TSqlFragmentVisitor where T : TSqlFragment
|
|
{
|
|
private readonly Func<T, bool> Where;
|
|
|
|
public List<T> Nodes = new List<T>();
|
|
|
|
public FindViolatingNodeVisitor(Func<T, bool> where = null)
|
|
{
|
|
Where = where;
|
|
}
|
|
|
|
public override void Visit(TSqlFragment node)
|
|
{
|
|
if (node is T val && (Where == null || Where(val)))
|
|
{
|
|
Nodes.Add(val);
|
|
}
|
|
|
|
base.Visit(node);
|
|
}
|
|
}
|
|
|
|
public static (TReturn, TFind) FindViolatingNode<TFind, TReturn>(List<string> fileLines, IRuleViolation ruleViolation, Func<TFind, TReturn> getFragment) where TFind : TSqlFragment where TReturn : TSqlFragment
|
|
{
|
|
TFind val = FindNodes<TFind>(fileLines).FirstOrDefault(delegate (TFind x)
|
|
{
|
|
TReturn val2 = getFragment(x);
|
|
return val2?.StartLine == ruleViolation.Line && val2?.StartColumn == ruleViolation.Column;
|
|
});
|
|
return (getFragment(val), val);
|
|
}
|
|
|
|
public static List<T> FindNodes<T>(List<string> fileLines, Func<T, bool> where = null) where T : TSqlFragment
|
|
{
|
|
using StringReader input = new StringReader(string.Join("\n", fileLines));
|
|
IList<ParseError> errors;
|
|
TSqlFragment tSqlFragment = new TSql150Parser(initialQuotedIdentifiers: true, SqlEngineType.All).Parse(input, out errors);
|
|
if (errors != null && errors.Any())
|
|
{
|
|
throw new Exception("Parsing failed. " + string.Join(". ", errors.Select((ParseError x) => x.Message)));
|
|
}
|
|
|
|
FindViolatingNodeVisitor<T> findViolatingNodeVisitor = new FindViolatingNodeVisitor<T>(where);
|
|
tSqlFragment.Accept(findViolatingNodeVisitor);
|
|
return findViolatingNodeVisitor.Nodes;
|
|
}
|
|
|
|
public static List<T> FindNodes<T>(TSqlFragment statement, Func<T, bool> where = null) where T : TSqlFragment
|
|
{
|
|
FindViolatingNodeVisitor<T> findViolatingNodeVisitor = new FindViolatingNodeVisitor<T>(where);
|
|
statement.Accept(findViolatingNodeVisitor);
|
|
return findViolatingNodeVisitor.Nodes;
|
|
}
|
|
|
|
public static T FindViolatingNode<T>(List<string> fileLines, IRuleViolation ruleViolation) where T : TSqlFragment
|
|
{
|
|
return FindViolatingNode(fileLines, ruleViolation, (T x) => x).Item1;
|
|
}
|
|
|
|
public static string GetIndent(List<string> fileLines, IRuleViolation ruleViolation)
|
|
{
|
|
return GetIndent(fileLines[ruleViolation.Line - 1]);
|
|
}
|
|
|
|
public static string GetIndent(List<string> fileLines, TSqlStatement statement)
|
|
{
|
|
return GetIndent(fileLines[statement.StartLine - 1]);
|
|
}
|
|
|
|
public static string GetString(TSqlFragment fragment)
|
|
{
|
|
return string.Join(string.Empty, from x in fragment.ScriptTokenStream.Where((TSqlParserToken x, int i) => i >= fragment.FirstTokenIndex && i <= fragment.LastTokenIndex)
|
|
select x.Text);
|
|
}
|
|
|
|
private static string GetIndent(string ifLine)
|
|
{
|
|
Match match = new Regex("^\\s+").Match(ifLine);
|
|
string result = string.Empty;
|
|
if (match.Success)
|
|
{
|
|
result = match.Value;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|