1
1
mirror of https://github.com/github/semantic.git synced 2024-12-27 00:44:57 +03:00
semantic/src/Renderer/JSON.hs
2017-01-25 03:09:53 -05:00

156 lines
7.9 KiB
Haskell

{-# LANGUAGE OverloadedStrings, TypeSynonymInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Renderer.JSON (
json
) where
import Prologue hiding (toList)
import Alignment
import Category
import Data.Aeson as A hiding (json)
import Data.Bifunctor.Join
import Data.Record
import qualified Data.Text as T
import Data.These
import Data.Vector as Vector hiding (toList)
import Info
import Renderer
import Source hiding (fromList)
import SplitDiff
import Syntax as S
import Term
import qualified Data.Map as Map
-- | Render a diff to a string representing its JSON.
json :: (ToJSON (Record fields), HasField fields Category, HasField fields Range) => Renderer (Record fields)
json blobs diff = JSONOutput $ Map.fromList [
("rows", toJSON (annotateRows (alignDiff (source <$> blobs) diff))),
("oids", toJSON (oid <$> blobs)),
("paths", toJSON (path <$> blobs)) ]
where annotateRows :: [Join These a] -> [Join These (NumberedLine a)]
annotateRows = fmap (fmap NumberedLine) . numberedRows
-- | A numbered 'a'.
newtype NumberedLine a = NumberedLine (Int, a)
instance (ToJSON leaf, ToJSON (Record fields), HasField fields Category, HasField fields Range) => ToJSON (NumberedLine (SplitSyntaxDiff leaf fields)) where
toJSON (NumberedLine (n, a)) = object (lineFields n a (getRange a))
toEncoding (NumberedLine (n, a)) = pairs $ mconcat (lineFields n a (getRange a))
instance ToJSON Category where
toJSON (Other s) = String s
toJSON s = String . T.pack $ show s
instance ToJSON Range where
toJSON (Range start end) = A.Array . Vector.fromList $ toJSON <$> [ start, end ]
toEncoding (Range start end) = foldable [ start, end ]
instance ToJSON a => ToJSON (Join These a) where
toJSON (Join vs) = A.Array . Vector.fromList $ toJSON <$> these pure pure (\ a b -> [ a, b ]) vs
toEncoding = foldable
instance ToJSON a => ToJSON (Join (,) a) where
toJSON (Join (a, b)) = A.Array . Vector.fromList $ toJSON <$> [ a, b ]
instance (ToJSON leaf, ToJSON (Record fields), HasField fields Category, HasField fields Range) => ToJSON (SplitSyntaxDiff leaf fields) where
toJSON splitDiff = case runFree splitDiff of
(Free (info :< syntax)) -> object (termFields info syntax)
(Pure patch) -> object (patchFields patch)
toEncoding splitDiff = case runFree splitDiff of
(Free (info :< syntax)) -> pairs $ mconcat (termFields info syntax)
(Pure patch) -> pairs $ mconcat (patchFields patch)
instance (ToJSON (Record fields), ToJSON leaf, HasField fields Category, HasField fields Range) => ToJSON (SyntaxTerm leaf fields) where
toJSON term |
(info :< syntax) <- runCofree term = object (termFields info syntax)
toEncoding term |
(info :< syntax) <- runCofree term = pairs $ mconcat (termFields info syntax)
lineFields :: (ToJSON leaf, ToJSON (Record fields), HasField fields Category, HasField fields Range, KeyValue kv) =>
Int ->
SplitSyntaxDiff leaf fields ->
Range ->
[kv]
lineFields n term range = [ "number" .= n
, "terms" .= [ term ]
, "range" .= range
, "hasChanges" .= hasChanges term
]
termFields :: (ToJSON recur, KeyValue kv, HasField fields Category, HasField fields Range) =>
Record fields ->
Syntax leaf recur ->
[kv]
termFields info syntax = "range" .= characterRange info : "category" .= category info : syntaxToTermField syntax
patchFields :: (ToJSON (Record fields), ToJSON leaf, KeyValue kv, HasField fields Category, HasField fields Range) =>
SplitPatch (SyntaxTerm leaf fields) ->
[kv]
patchFields patch = case patch of
SplitInsert term -> fields "insert" term
SplitDelete term -> fields "delete" term
SplitReplace term -> fields "replace" term
where
fields kind term |
(info :< syntax) <- runCofree term = "patch" .= T.pack kind : termFields info syntax
syntaxToTermField :: (ToJSON recur, KeyValue kv) =>
Syntax leaf recur ->
[kv]
syntaxToTermField syntax = case syntax of
Leaf _ -> []
Indexed c -> childrenFields c
Fixed c -> childrenFields c
S.FunctionCall identifier parameters -> [ "identifier" .= identifier ] <> [ "parameters" .= parameters ]
S.Ternary expression cases -> [ "expression" .= expression ] <> [ "cases" .= cases ]
S.AnonymousFunction parameters c -> [ "parameters" .= parameters ] <> childrenFields c
S.Function identifier parameters c -> [ "identifier" .= identifier ] <> [ "parameters" .= parameters ] <> childrenFields c
S.Assignment assignmentId value -> [ "identifier" .= assignmentId ] <> [ "value" .= value ]
S.OperatorAssignment identifier value -> [ "identifier" .= identifier ] <> [ "value" .= value ]
S.MemberAccess identifier value -> [ "identifier" .= identifier ] <> [ "value" .= value ]
S.MethodCall identifier methodIdentifier parameters -> [ "identifier" .= identifier ] <> [ "methodIdentifier" .= methodIdentifier ] <> [ "parameters" .= parameters ]
S.Operator syntaxes -> [ "operatorSyntaxes" .= syntaxes ]
S.VarDecl declaration ty -> [ "declaration" .= declaration ] <> [ "type" .= ty]
S.VarAssignment identifier value -> [ "identifier" .= identifier ] <> [ "value" .= value ]
S.SubscriptAccess identifier property -> [ "identifier" .= identifier ] <> [ "property" .= property ]
S.Switch expression cases -> [ "expression" .= expression ] <> [ "cases" .= cases ]
S.Case expression statements -> [ "expression" .= expression ] <> [ "statements" .= statements ]
S.Object ty keyValuePairs -> [ "type" .= ty ] <> childrenFields keyValuePairs
S.Pair a b -> childrenFields [a, b]
S.Comment _ -> []
S.Commented comments child -> childrenFields (comments <> maybeToList child)
S.ParseError c -> childrenFields c
S.For expressions body -> [ "expressions" .= expressions ] <> [ "body" .= body ]
S.DoWhile expression body -> [ "expression" .= expression ] <> [ "body" .= body ]
S.While expression body -> [ "expression" .= expression ] <> [ "body" .= body ]
S.Return expression -> [ "expression" .= expression ]
S.Throw c -> [ "expression" .= c ]
S.Constructor expression -> [ "expression" .= expression ]
S.Try body catchExpression elseExpression finallyExpression -> [ "body" .= body ] <> [ "catchExpression" .= catchExpression ] <> [ "elseExpression" .= elseExpression ] <> [ "finallyExpression" .= finallyExpression ]
S.Array ty c -> [ "type" .= ty ] <> childrenFields c
S.Class identifier superclass definitions -> [ "identifier" .= identifier ] <> [ "superclass" .= superclass ] <> [ "definitions" .= definitions ]
S.Method identifier ty parameters definitions -> [ "identifier" .= identifier ] <> [ "type" .= ty ] <> [ "parameters" .= parameters ] <> [ "definitions" .= definitions ]
S.If expression clauses -> [ "expression" .= expression ] <> childrenFields clauses
S.Module identifier definitions-> [ "identifier" .= identifier ] <> [ "definitions" .= definitions ]
S.Import identifier statements -> [ "identifier" .= identifier ] <> [ "statements" .= statements ]
S.Export identifier statements -> [ "identifier" .= identifier ] <> [ "statements" .= statements ]
S.Yield expr -> [ "yieldExpression" .= expr ]
S.Negate expr -> [ "negate" .= expr ]
S.Rescue args expressions -> [ "args" .= args ] <> childrenFields expressions
S.Select cases -> childrenFields cases
S.Go cases -> childrenFields cases
S.Defer cases -> childrenFields cases
S.TypeAssertion a b -> childrenFields [a, b]
S.TypeConversion a b -> childrenFields [a, b]
S.Struct ty fields -> [ "type" .= ty ] <> childrenFields fields
S.Break expr -> [ "expression" .= expr ]
S.Continue expr -> [ "expression" .= expr ]
S.BlockStatement c -> childrenFields c
S.ParameterDecl ty field -> [ "type" .= ty ] <> [ "identifier" .= field ]
S.DefaultCase c -> childrenFields c
S.TypeDecl id ty -> [ "type" .= ty ] <> [ "identifier" .= id ]
S.FieldDecl id ty tag -> [ "type" .= ty ] <> [ "identifier" .= id ] <> [ "tag" .= tag]
S.Ty ty -> [ "type" .= ty ]
S.Send channel expr -> [ "channel" .= channel ] <> [ "expression" .= expr ]
where childrenFields c = [ "children" .= c ]