{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
module Krank.Checkers.Ignore
( IgnoreCommand (..),
filterViolations,
)
where
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as ByteString
import qualified Data.HashMap.Strict as HashM
import qualified Data.List as DataL
import Krank.Types
import PyF (fmt)
import qualified Text.Regex.PCRE.Heavy as RE
data IgnoreCommand = IgnoreLine deriving (Int -> IgnoreCommand -> ShowS
[IgnoreCommand] -> ShowS
IgnoreCommand -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [IgnoreCommand] -> ShowS
$cshowList :: [IgnoreCommand] -> ShowS
show :: IgnoreCommand -> String
$cshow :: IgnoreCommand -> String
showsPrec :: Int -> IgnoreCommand -> ShowS
$cshowsPrec :: Int -> IgnoreCommand -> ShowS
Show, IgnoreCommand -> IgnoreCommand -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: IgnoreCommand -> IgnoreCommand -> Bool
$c/= :: IgnoreCommand -> IgnoreCommand -> Bool
== :: IgnoreCommand -> IgnoreCommand -> Bool
$c== :: IgnoreCommand -> IgnoreCommand -> Bool
Eq)
ignoreRe :: RE.Regex
ignoreRe :: Regex
ignoreRe = [RE.re|krank:ignore-(line)|]
extractIssuesOnALine :: ByteString -> [(Int, IgnoreCommand)]
ByteString
lineContent = forall a b. (a -> b) -> [a] -> [b]
Prelude.map (ByteString, [ByteString]) -> (Int, IgnoreCommand)
f (forall a.
(ConvertibleStrings ByteString a,
ConvertibleStrings a ByteString) =>
Regex -> a -> [(a, [a])]
RE.scan Regex
ignoreRe ByteString
lineContent)
where
f :: (ByteString, [ByteString]) -> (Int, IgnoreCommand)
f (ByteString
match, [ByteString
command]) = (Int
colNo, IgnoreCommand
ignoreCommand)
where
colNo :: Int
colNo = Int
1 forall a. Num a => a -> a -> a
+ ByteString -> Int
ByteString.length (forall a b. (a, b) -> a
fst forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> (ByteString, ByteString)
ByteString.breakSubstring ByteString
match ByteString
lineContent)
ignoreCommand :: IgnoreCommand
ignoreCommand
| ByteString
command forall a. Eq a => a -> a -> Bool
== ByteString
"line" = IgnoreCommand
IgnoreLine
| Bool
otherwise = forall a. HasCallStack => String -> a
error [fmt|Impossible case, update the guard with: {ByteString.unpack command}|]
f (ByteString, [ByteString])
res = forall a. HasCallStack => String -> a
error (String
"Error: impossible match" forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> String
show (ByteString, [ByteString])
res)
extractIgnores ::
FilePath ->
ByteString ->
[Localized IgnoreCommand]
String
filePath ByteString
toCheck = forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat (forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> ByteString -> [Localized IgnoreCommand]
extract [Int
1 ..] (ByteString -> [ByteString]
ByteString.lines ByteString
toCheck))
where
extract :: Int -> ByteString -> [Localized IgnoreCommand]
extract Int
lineNo ByteString
lineContent = forall a b. (a -> b) -> [a] -> [b]
Prelude.map forall {t}. (Int, t) -> Localized t
f (ByteString -> [(Int, IgnoreCommand)]
extractIssuesOnALine ByteString
lineContent)
where
f :: (Int, t) -> Localized t
f (Int
colNo, t
gitIssue) = forall t. SourcePos -> t -> Localized t
Localized (String -> Int -> Int -> SourcePos
SourcePos String
filePath Int
lineNo Int
colNo) t
gitIssue
filterViolations ::
[Violation] ->
FilePath ->
ByteString ->
[Violation]
filterViolations :: [Violation] -> String -> ByteString -> [Violation]
filterViolations [Violation]
violations String
filePath ByteString
content =
forall a. (a -> Bool) -> [a] -> [a]
DataL.filter Violation -> Bool
isNotIgnored [Violation]
violations
where
ignoreCommands :: [Localized IgnoreCommand]
ignoreCommands = String -> ByteString -> [Localized IgnoreCommand]
extractIgnores String
filePath ByteString
content
f :: HashMap Int v -> Localized v -> HashMap Int v
f HashMap Int v
hashMap Localized v
ignoreCommand = forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HashM.insert (SourcePos -> Int
lineNumber forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. Localized t -> SourcePos
getLocation forall a b. (a -> b) -> a -> b
$ Localized v
ignoreCommand) (forall t. Localized t -> t
unLocalized Localized v
ignoreCommand) HashMap Int v
hashMap
ignoreIndex :: HashMap Int IgnoreCommand
ignoreIndex = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl forall {v}. HashMap Int v -> Localized v -> HashMap Int v
f forall k v. HashMap k v
HashM.empty [Localized IgnoreCommand]
ignoreCommands
isIgnored :: Violation -> Bool
isIgnored Violation
violation = forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashM.lookup (SourcePos -> Int
lineNumber forall b c a. (b -> c) -> (a -> b) -> a -> c
. Violation -> SourcePos
location forall a b. (a -> b) -> a -> b
$ Violation
violation) HashMap Int IgnoreCommand
ignoreIndex forall a. Eq a => a -> a -> Bool
== forall a. a -> Maybe a
Just IgnoreCommand
IgnoreLine
isNotIgnored :: Violation -> Bool
isNotIgnored = Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. Violation -> Bool
isIgnored