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-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 Patch
|
|
|
|
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
|
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 { span :: SourceSpan, termContext :: Text, contextType :: Text, changeType :: Text }
|
2017-01-23 22:12:05 +03:00
|
|
|
| ErrorSummary { error :: Text, span :: SourceSpan }
|
|
|
|
deriving (Generic, Eq, Show)
|
|
|
|
|
|
|
|
instance ToJSON JSONSummary where
|
|
|
|
toJSON JSONSummary{..} = object [ "span" .= span, "termContext" .= termContext, "contextType" .= contextType, "changeType" .= changeType ]
|
|
|
|
toJSON ErrorSummary{..} = object [ "error" .= error, "span" .= span ]
|
|
|
|
|
|
|
|
isErrorSummary :: JSONSummary -> Bool
|
|
|
|
isErrorSummary ErrorSummary{} = True
|
|
|
|
isErrorSummary _ = False
|
2017-01-23 20:16:59 +03:00
|
|
|
|
|
|
|
data DiffInfo = LeafInfo { leafCategory :: Category, termName :: Text, sourceSpan :: SourceSpan }
|
|
|
|
| BranchInfo { branches :: [ DiffInfo ], branchCategory :: Category }
|
|
|
|
| ErrorInfo { errorSpan :: SourceSpan, termName :: Text }
|
|
|
|
| HideInfo -- Hide/Strip from summary output entirely.
|
|
|
|
deriving (Eq, Show)
|
|
|
|
|
|
|
|
data TOCSummary a = TOCSummary {
|
|
|
|
patch :: Patch a,
|
|
|
|
parentAnnotation :: [Either (Category, Text) (Category, Text)]
|
|
|
|
} deriving (Eq, Functor, Show, Generic)
|
|
|
|
|
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
|
|
|
|
2017-01-23 22:12:05 +03:00
|
|
|
diffTOC :: (StringConv leaf Text, DefaultFields fields) => Both SourceBlob -> SyntaxDiff leaf fields -> [JSONSummary]
|
|
|
|
diffTOC blobs diff = tocToJSONSummaries =<< diffToTOCSummaries (source <$> blobs) diff
|
|
|
|
where
|
|
|
|
tocToJSONSummaries :: TOCSummary DiffInfo -> [JSONSummary]
|
|
|
|
tocToJSONSummaries TOCSummary{..} = summaries patch
|
2017-01-23 20:16:59 +03:00
|
|
|
|
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
|
|
|
|
-- diff' = free (Prologue.fst <$> diff)
|
|
|
|
-- annotateWithCategory :: [TOCSummary DiffInfo] -> [TOCSummary DiffInfo]
|
|
|
|
-- annotateWithCategory children = case (beforeTerm diff', afterTerm diff') of
|
|
|
|
-- (_, Just diff'') -> appendSummary (Both.snd sources) diff'' <$> children
|
|
|
|
-- (Just diff'', _) -> appendSummary (Both.fst sources) diff'' <$> children
|
|
|
|
-- (Nothing, Nothing) -> []
|
|
|
|
in case diff of
|
|
|
|
-- Skip comments and leaves since they don't have any changes
|
|
|
|
-- (Free (_ :< syntax)) -> annotateWithCategory (toList syntax >>= snd)
|
|
|
|
(Free (_ :< syntax)) -> toList syntax >>= snd
|
|
|
|
(Pure patch) -> [ TOCSummary (mapPatch (termToDiffInfo beforeSource) (termToDiffInfo afterSource) patch) [] ]
|
|
|
|
where
|
|
|
|
(beforeSource, afterSource) = runJoin sources
|
2017-01-23 20:16:59 +03:00
|
|
|
|
|
|
|
-- If the term is a method/function grab the term type, name, and span here, otherwise grab them up top.
|
2017-01-23 22:12:05 +03:00
|
|
|
summaries :: Patch DiffInfo -> [JSONSummary]
|
2017-01-23 20:16:59 +03:00
|
|
|
summaries = \case
|
2017-01-23 22:12:05 +03:00
|
|
|
(Replace i1 i2) -> zipWith (\a b ->
|
|
|
|
JSONSummary
|
2017-01-23 20:16:59 +03:00
|
|
|
{
|
2017-01-23 22:12:05 +03:00
|
|
|
-- span = SourceSpans $ These (span a) (span b)
|
|
|
|
span = span b
|
|
|
|
, termContext = termContext a <> " -> " <> termContext b
|
|
|
|
, contextType = contextType b
|
|
|
|
, changeType = "replace"
|
|
|
|
}) (toLeafInfos "replace" i1) (toLeafInfos "replace" i2)
|
|
|
|
(Insert info) -> toLeafInfos "insert" info
|
|
|
|
(Delete info) -> toLeafInfos "delete" info
|
|
|
|
|
|
|
|
toLeafInfos :: Text -> DiffInfo -> [JSONSummary]
|
|
|
|
toLeafInfos _ ErrorInfo{..} = pure $ ErrorSummary termName errorSpan
|
|
|
|
toLeafInfos patchType BranchInfo{..} = branches >>= toLeafInfos patchType
|
|
|
|
toLeafInfos _ HideInfo = []
|
|
|
|
toLeafInfos patchType LeafInfo{..} = pure $ JSONSummary sourceSpan termName (show leafCategory) patchType
|
|
|
|
|
|
|
|
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-23 22:12:05 +03:00
|
|
|
toTermName :: forall leaf fields. (StringConv leaf Text, DefaultFields fields) => Source Char -> SyntaxTerm leaf fields -> Text
|
|
|
|
toTermName source = termNameFromSource
|
|
|
|
where
|
|
|
|
termNameFromSource term = termNameFromRange (range term)
|
|
|
|
termNameFromRange range = toText $ Source.slice range source
|
|
|
|
range = characterRange . extract
|