1
1
mirror of https://github.com/github/semantic.git synced 2024-12-26 16:33:03 +03:00
semantic/src/Renderer/TOC.hs

190 lines
7.9 KiB
Haskell
Raw Normal View History

2017-01-23 20:16:59 +03:00
{-# LANGUAGE ScopedTypeVariables #-}
2017-01-23 19:22:51 +03:00
module Renderer.TOC where
2017-01-23 22:12:05 +03:00
import Category as C
import Data.Aeson
import Data.Functor.Both hiding (fst, snd)
2017-01-24 00:59:47 +03:00
import qualified Data.Functor.Both as Both
2017-01-23 19:22:51 +03:00
import Data.Record
2017-01-23 22:12:05 +03:00
import Diff
2017-01-23 19:22:51 +03:00
import Info
2017-01-23 22:12:05 +03:00
import Prologue
import qualified Data.List as List
import qualified Data.Map as Map hiding (null)
import Renderer
2017-01-23 20:16:59 +03:00
import Source
2017-01-23 22:12:05 +03:00
import Syntax as S
import Term
import Patch
2017-01-24 20:13:59 +03:00
import Unsafe (unsafeHead)
2017-01-23 20:16:59 +03:00
{-
TOCSummary (Patch DiffInfo) [Identifiable (Category, Text), Annotatable]
{
"changes": [
{ FilePath: [ {SourceSpan, TermContext, TermType, ChangeType} ] }
],
"errors": [
{ FilePath: [ {SourceSpan, ErrorText } ] }
]
}
2017-01-23 22:12:05 +03:00
Example: https://github.com/github/github/pull/50259/files
* app/controllers/application_controller/feature_flags_dependency.rb
* enable_feature_flags (method)
* app/models/linked_account_collection.rb
* remove (method)
* app/models/repository.rb
* filtered_by (method)
* app/models/tenant/mismatch_check.rb
+ report_tenant_mismatch? (method)
+ report_tenant_mismatch (method)
* app/models/user.rb
* recently_updated_member_repos (method)
* lib/github/config.rb
+ report_tenant_mismatch_enabled? (method)
2017-01-23 20:16:59 +03:00
-}
data JSONSummary = JSONSummary { info :: Summarizable }
| ErrorSummary { error :: Text, errorSpan :: SourceSpan }
2017-01-23 22:12:05 +03:00
deriving (Generic, Eq, Show)
instance ToJSON JSONSummary where
toJSON JSONSummary{..} = object $ case info of
InSummarizable{..} -> [ "changeType" .= ("modified" :: Text), "category" .= (show parentCategory :: Text), "term" .= parentTermName, "sourceSpan" .= parentSourceSpan ]
Summarizable{..} -> [ "changeType" .= summarizableChangeType, "category" .= (show summarizableCategory :: Text), "term" .= summarizableTermName, "sourceSpan" .= summarizableSourceSpan ]
NotSummarizable -> panic "NotSummarizable should have been pruned"
toJSON ErrorSummary{..} = object [ "error" .= error, "span" .= errorSpan ]
2017-01-23 22:12:05 +03:00
isErrorSummary :: JSONSummary -> Bool
2017-01-23 22:12:05 +03:00
isErrorSummary ErrorSummary{} = True
isErrorSummary _ = False
2017-01-23 20:16:59 +03:00
data DiffInfo = LeafInfo { leafCategory :: Category, termName :: Text, leafSourceSpan :: SourceSpan }
2017-01-23 20:16:59 +03:00
| BranchInfo { branches :: [ DiffInfo ], branchCategory :: Category }
| ErrorInfo { infoSpan :: SourceSpan, termName :: Text }
2017-01-23 20:16:59 +03:00
| HideInfo -- Hide/Strip from summary output entirely.
deriving (Eq, Show)
data TOCSummary a = TOCSummary {
patch :: Patch a,
parentInfo :: Summarizable
} deriving (Eq, Functor, Show, Generic)
2017-01-23 20:16:59 +03:00
data Summarizable = Summarizable { summarizableCategory :: Category, summarizableTermName :: Text, summarizableSourceSpan :: SourceSpan, summarizableChangeType :: Text }
| InSummarizable { parentCategory :: Category, parentTermName :: Text, parentSourceSpan :: SourceSpan }
| NotSummarizable
deriving (Eq, Show)
data SummarizableTerm a = SummarizableTerm a | NotSummarizableTerm a
2017-01-23 22:12:05 +03:00
toc :: (DefaultFields fields) => Renderer (Record fields)
toc blobs diff = TOCOutput $ Map.fromList [
("changes", changes),
("errors", errors)
]
where
changes = if null changes' then mempty else Map.singleton summaryKey (toJSON <$> changes')
errors = if null errors' then mempty else Map.singleton summaryKey (toJSON <$> errors')
(errors', changes') = List.partition isErrorSummary summaries
summaryKey = toSummaryKey (path <$> blobs)
summaries = diffTOC blobs diff
2017-01-23 20:16:59 +03:00
diffTOC :: (StringConv leaf Text, DefaultFields fields) => Both SourceBlob -> SyntaxDiff leaf fields -> [JSONSummary]
diffTOC blobs diff = toJSONSummaries =<< removeDupes (diffToTOCSummaries (source <$> blobs) diff)
2017-01-23 22:12:05 +03:00
where
2017-01-24 20:13:59 +03:00
removeDupes :: [TOCSummary DiffInfo] -> [TOCSummary DiffInfo]
removeDupes [] = []
2017-01-24 20:13:59 +03:00
removeDupes xs = (fmap unsafeHead . List.groupBy (\a b -> parentInfo a == parentInfo b)) xs
2017-01-23 22:12:05 +03:00
diffToTOCSummaries :: (StringConv leaf Text, DefaultFields fields) => Both (Source Char) -> SyntaxDiff leaf fields -> [TOCSummary DiffInfo]
diffToTOCSummaries sources = para $ \diff ->
let
2017-01-24 00:59:47 +03:00
diff' = free (Prologue.fst <$> diff)
patch' = mapPatch (termToDiffInfo beforeSource) (termToDiffInfo afterSource)
2017-01-23 22:12:05 +03:00
(beforeSource, afterSource) = runJoin sources
in case diff of
(Free (_ :< syntax)) -> mapToInSummarizable sources diff' (toList syntax >>= snd)
(Pure patch) -> toTOCSummaries (patch' patch)
-- Mark which leaves are summarizable.
toTOCSummaries :: Patch DiffInfo -> [TOCSummary DiffInfo]
2017-01-24 23:58:17 +03:00
toTOCSummaries patch = case afterOrBefore patch of
Just diffInfo -> toTOCSummaries' diffInfo
Nothing -> panic "No diff"
where
toTOCSummaries' = \case
ErrorInfo{..} -> pure $ TOCSummary patch NotSummarizable
BranchInfo{..} -> branches >>= toTOCSummaries'
HideInfo{} -> []
LeafInfo{..} -> pure . TOCSummary patch $ case leafCategory of
2017-01-25 00:00:25 +03:00
C.Function -> Summarizable leafCategory termName leafSourceSpan (patchType patch)
C.Method -> Summarizable leafCategory termName leafSourceSpan (patchType patch)
_ -> NotSummarizable
mapToInSummarizable :: DefaultFields fields => Both (Source Char) -> SyntaxDiff leaf fields -> [TOCSummary DiffInfo] -> [TOCSummary DiffInfo]
mapToInSummarizable sources diff children = case (beforeTerm diff, afterTerm diff) of
(_, Just diff') -> mapToInSummarizable' (Both.snd sources) diff' <$> children
(Just diff', _) -> mapToInSummarizable' (Both.fst sources) diff' <$> children
(Nothing, Nothing) -> []
where
mapToInSummarizable' :: DefaultFields fields => Source Char -> SyntaxTerm leaf fields -> TOCSummary DiffInfo -> TOCSummary DiffInfo
mapToInSummarizable' source term summary =
case (parentInfo summary, summarizable term) of
(NotSummarizable, SummarizableTerm _) ->
summary { parentInfo = InSummarizable (category (extract term)) (toTermName source term) (Info.sourceSpan (extract term)) }
(_, _) -> summary
summarizable :: ComonadCofree (Syntax t) w => w a -> SummarizableTerm (w a)
summarizable term = go (unwrap term) term
where go = \case
S.Method{} -> SummarizableTerm
S.Function{} -> SummarizableTerm
_ -> NotSummarizableTerm
toJSONSummaries :: TOCSummary DiffInfo -> [JSONSummary]
2017-01-24 23:58:17 +03:00
toJSONSummaries TOCSummary{..} = case afterOrBefore patch of
Just diffInfo -> toJSONSummaries' diffInfo
Nothing -> panic "No diff"
where
toJSONSummaries' = \case
ErrorInfo{..} -> pure $ ErrorSummary termName infoSpan
BranchInfo{..} -> branches >>= toJSONSummaries'
HideInfo -> []
LeafInfo{..} -> case parentInfo of
NotSummarizable -> []
_ -> pure $ JSONSummary parentInfo
2017-01-23 22:12:05 +03:00
termToDiffInfo :: (StringConv leaf Text, DefaultFields fields) => Source Char -> SyntaxTerm leaf fields -> DiffInfo
termToDiffInfo blob term = case unwrap term of
S.Indexed children -> BranchInfo (termToDiffInfo' <$> children) (category $ extract term)
S.Fixed children -> BranchInfo (termToDiffInfo' <$> children) (category $ extract term)
S.AnonymousFunction _ _ -> LeafInfo C.AnonymousFunction (toTermName' term) (getField $ extract term)
S.Comment _ -> HideInfo
S.Commented cs leaf -> BranchInfo (termToDiffInfo' <$> cs <> maybeToList leaf) (category $ extract term)
S.Error _ -> ErrorInfo (getField $ extract term) (toTermName' term)
_ -> toLeafInfo term
where toTermName' = toTermName blob
termToDiffInfo' = termToDiffInfo blob
toLeafInfo term = LeafInfo (category $ extract term) (toTermName' term) (getField $ extract term)
2017-01-23 19:22:51 +03:00
2017-01-24 00:59:47 +03:00
toTermName :: forall leaf fields. DefaultFields fields => Source Char -> SyntaxTerm leaf fields -> Text
toTermName source term = case unwrap term of
S.Function identifier _ _ -> toTermName' identifier
2017-01-24 22:18:59 +03:00
S.Method identifier _ _ _ -> toTermName' identifier
_ -> termNameFromSource term
2017-01-23 22:12:05 +03:00
where
toTermName' = toTermName source
2017-01-23 22:12:05 +03:00
termNameFromSource term = termNameFromRange (range term)
termNameFromRange range = toText $ Source.slice range source
range = characterRange . extract