From 8f6c0e4203e0696f4abb535522e91017c0169db1 Mon Sep 17 00:00:00 2001 From: "Carsten Csiky (csicar)" Date: Thu, 23 Apr 2020 01:23:58 +0200 Subject: [PATCH 1/5] Initial implementation --- README.md | 40 +++++--- spago.dhall | 34 +++---- src/Data/DotLang.purs | 62 ++++++++---- src/Data/DotLang/Attr.purs | 64 ++++++++++++- src/Data/DotLang/Attr/Edge.purs | 120 ++++++++++------------- src/Data/DotLang/Attr/Node.purs | 163 ++++++++++++++++++++------------ src/Data/DotLang/Class.purs | 15 +++ test/Main.purs | 51 +++++----- 8 files changed, 337 insertions(+), 212 deletions(-) diff --git a/README.md b/README.md index c85e0bc..1a21c0f 100644 --- a/README.md +++ b/README.md @@ -6,31 +6,45 @@ documentation can be found on [pursuit](https://pursuit.purescript.org/packages/ define your model like this: ```purescript -DiGraph [ - node "a" [ Shape Diamond, Style Filled, Node.FillColor red ], - node "b" [], - "a" ==> "b", - "a" =*> "d" $ [ Edge.FillColor red ], - Subgraph [ - node "d" [] +import Data.DotLang.Attr.Global as Global +import Data.DotLang.Attr.Node +import Data.DotLang.Attr.Edge +import Data.DotLang.Attr +import Data.DotLang.Class (toText) +import Color.Scheme.MaterialDesign (red) + + +graph = DiGraph + [ global [ Global.RankDir FromLeft ] + , node "a" [ shape Node.Diamond, style Filled, fillColor red ] + , node "b" [] + , "a" ==> "b" + , "a" =*> "d" $ [ fillColor red ] + , Subgraph + [ node "d" [] + ] ] -] ``` can be rendered using `toText` to: ``` digraph { - a [shape=diamond, style=filled, fillcolor="#f44336"]; - b []; - a -> b; - a -> d [fillcolor="#f44336"]; - subgraph { + rankdir=LR; + a [fillcolor="#f44336", shape=diamond, style=filled]; + b []; + a -> b; + a -> d [fillcolor="#f44336"]; + subgraph { d []; } } ``` +Which looks like this, when rendered with graphviz: + +![example.svg](example.svg) + ### Installation #### Spago diff --git a/spago.dhall b/spago.dhall index 141c059..84fd7b6 100644 --- a/spago.dhall +++ b/spago.dhall @@ -1,21 +1,17 @@ -{ name = - "dotlang" -, license = - "MIT" -, repository = - "https://github.com/csicar/purescript-dotlang.git" +{ name = "dotlang" +, license = "MIT" +, repository = "https://github.com/csicar/purescript-dotlang.git" , dependencies = - [ "colors" - , "console" - , "effect" - , "generics-rep" - , "prelude" - , "psci-support" - , "strings" - , "test-unit" - ] -, packages = - ./packages.dhall -, sources = - [ "src/**/*.purs", "test/**/*.purs" ] + [ "colors" + , "console" + , "effect" + , "generics-rep" + , "heterogeneous" + , "prelude" + , "psci-support" + , "strings" + , "test-unit" + ] +, packages = ./packages.dhall +, sources = [ "src/**/*.purs", "test/**/*.purs" ] } diff --git a/src/Data/DotLang.purs b/src/Data/DotLang.purs index dc6c7e7..4af4c44 100644 --- a/src/Data/DotLang.purs +++ b/src/Data/DotLang.purs @@ -1,17 +1,23 @@ module Data.DotLang where +import Prelude +import Color (Color, toHexString) +import Data.Array (foldr, null) +import Data.DotLang.Attr (Attribute, attributesToText, label) +import Data.DotLang.Attr.Edge (EdgeAttributes, defaultEdgeAttributes) import Data.DotLang.Attr.Edge as Edge -import Data.DotLang.Attr.Node as Node import Data.DotLang.Attr.Global as Global +import Data.DotLang.Attr.Node (NodeAtributes, defaultNodeAttributes) +import Data.DotLang.Attr.Node as Node import Data.DotLang.Class (class DotLang, toText) import Data.Generic.Rep (class Generic) import Data.Generic.Rep.Show (genericShow) import Data.String (joinWith) -import Data.Array (null) import Prelude (class Show, ($), (<$>), (<>)) -- | type alias for a Nodes Name -type Id = String +type Id + = String -- | Dot-Node -- | example : @@ -19,8 +25,8 @@ type Id = String -- | Node "e" [Margin 3, Label "some label"] -- | ``` -- | is turned into: `e [margin=3, label="some label"];` -data Node = Node Id (Array Node.Attr) - +data Node + = Node Id { | NodeAtributes () } -- | get a nodes id -- | example: @@ -33,7 +39,7 @@ nodeId (Node id _) = id -- | change Nodes id to a new one; keeing the old id as the label -- | example: `mapNodeId (\a -> a+"!") (Node "e" []) == Node "e!" [Label "e"]` changeNodeId :: (Id -> Id) -> Node -> Node -changeNodeId f (Node id attr) = Node (f id) $ attr <> [Node.label id] +changeNodeId f (Node id attr) = Node (f id) $ (label id attr) derive instance genericNode :: Generic Node _ @@ -41,8 +47,7 @@ instance showNode :: Show Node where show = genericShow instance nodeDotLang :: DotLang Node where - toText (Node id attrs) = id <> " [" <> joinWith ", " (toText <$> attrs) <> "]" - + toText (Node id attrs) = id <> " [" <> joinWith ", " (attributesToText attrs) <> "]" data EdgeType = Forward @@ -51,7 +56,8 @@ data EdgeType derive instance genericEdgeType :: Generic EdgeType _ -instance showEdgeType :: Show EdgeType where show = genericShow +instance showEdgeType :: Show EdgeType where + show = genericShow instance dotLangEdgeType :: DotLang EdgeType where toText Forward = "->" @@ -61,7 +67,8 @@ instance dotLangEdgeType :: DotLang EdgeType where -- | egde from id to id -- | `toText $ Edge Forward "a" "b" []` == `a -> b []` -- | EdgeType determines the direction of the arrow -data Edge = Edge EdgeType Id Id (Array Edge.Attr) +data Edge + = Edge EdgeType Id Id { | EdgeAttributes () } derive instance genericEdge :: Generic Edge _ @@ -71,7 +78,9 @@ instance showEdge :: Show Edge where instance dotLangEdge :: DotLang Edge where toText (Edge e id id2 attrs) = id <> " " <> (toText e) <> " " <> id2 <> attrText where - attrText = if null attrs then "" else " [" <> joinWith ", " (toText <$> attrs) <> "]" + attrText = case attributesToText attrs of + [] -> "" + textAttributes -> " [" <> joinWith ", " textAttributes <> "]" -- | definition in a graph data Definition @@ -80,6 +89,12 @@ data Definition | EdgeDef Edge | Subgraph (Array Definition) + +derive instance genericDefinition :: Generic Definition _ + +instance showDefinition :: Show Definition where + show a = genericShow a + -- | -- | ```purescript -- | global [ Global.RankDir Global.FromLeft ] -- ∷ Definition @@ -93,8 +108,8 @@ global = Global -- | node "a" [] -- ∷ Definition -- | ``` -- | node as a part of a definition -node :: Id → Array Node.Attr → Definition -node id attrs = NodeDef $ Node id attrs +node :: Id → Array (Attribute { | NodeAtributes () }) → Definition +node id attrs = NodeDef $ Node id (foldr ($) defaultNodeAttributes $ attrs) -- | -- | ```purescript @@ -102,22 +117,22 @@ node id attrs = NodeDef $ Node id attrs -- | ``` -- | edge as a part of a definition. -- | `==>` and `=*>` can also be used for that purpose. -edge :: EdgeType → Id → Id → Array Edge.Attr → Definition -edge t id id2 attrs = EdgeDef $ Edge t id id2 attrs +edge :: EdgeType → Id → Id → Array (Attribute { | EdgeAttributes () }) → Definition +edge t id id2 attrs = EdgeDef $ Edge t id id2 (foldr ($) defaultEdgeAttributes $ attrs) -forwardEdgeWithAttrs ∷ Id → Id → Array Edge.Attr → Definition +forwardEdgeWithAttrs ∷ Id → Id → Array (Attribute { | EdgeAttributes () }) → Definition forwardEdgeWithAttrs = edge Forward forwardEdge :: Id → Id → Definition forwardEdge l r = forwardEdgeWithAttrs l r [] -backwardEdgeWithAttrs ∷ Id → Id → Array Edge.Attr → Definition +backwardEdgeWithAttrs ∷ Id → Id → Array (Attribute { | EdgeAttributes () }) → Definition backwardEdgeWithAttrs = edge Backward backwardEdge ∷ Id → Id → Definition backwardEdge l r = backwardEdgeWithAttrs l r [] -normalEdgeWithAttrs ∷ Id → Id → Array Edge.Attr → Definition +normalEdgeWithAttrs ∷ Id → Id → Array (Attribute { | EdgeAttributes () }) → Definition normalEdgeWithAttrs = edge NoDir normalEdge ∷ Id → Id → Definition @@ -129,6 +144,7 @@ normalEdge l r = normalEdgeWithAttrs l r [] -- | ``` -- | Forward edge as as a definition infix 5 forwardEdge as ==> + -- | -- | ```purescript -- | "a" =*> "b" $ [ Edge.FillColor red ] @@ -136,24 +152,28 @@ infix 5 forwardEdge as ==> -- | ``` -- | Forward edge with attributes as a definition infix 5 forwardEdgeWithAttrs as =*> + -- | -- | ```purescript -- | "a" <== "b" -- :: Definition -- | ``` -- | Backward edge as a definition infix 5 backwardEdge as <== + -- | -- | ```purescript -- | "a" <*= "b" $ [ Edge.FillColor red ] -- | ``` -- | Backward edge with attributes as a definition infix 5 backwardEdgeWithAttrs as <*= + -- | -- | ```purescript -- | "a" -==- "b" -- | ``` -- | Normal edge as definition infix 5 normalEdge as -==- + -- | -- | ```purescript -- | "a" =*= "b" $ [ Edge.FillColor red ] @@ -172,6 +192,10 @@ data Graph = Graph (Array Definition) | DiGraph (Array Definition) +derive instance genericGraph :: Generic Graph _ + +instance showGraph :: Show Graph where + show = genericShow instance graphDotLang :: DotLang Graph where toText (Graph defs) = "graph {" <> (joinWith "" $ toText <$> defs) <> "}" @@ -185,5 +209,3 @@ graphFromElements n e = DiGraph $ (NodeDef <$> n) <> (EdgeDef <$> e) -- | `a` is a type that can be represented by a Dot-Graph class GraphRepr a where toGraph :: a -> Graph - - diff --git a/src/Data/DotLang/Attr.purs b/src/Data/DotLang/Attr.purs index a8ba0d9..8d420c8 100644 --- a/src/Data/DotLang/Attr.purs +++ b/src/Data/DotLang/Attr.purs @@ -2,9 +2,15 @@ module Data.DotLang.Attr where import Prelude -import Data.DotLang.Class (class DotLang) +import Data.DotLang.Class (class DotLang, class DotLangValue) +import Data.DotLang.Class (class DotLang, class DotLangValue, toValue) import Data.Generic.Rep (class Generic) +import Data.Generic.Rep.Eq (genericEq) import Data.Generic.Rep.Show (genericShow) +import Data.Maybe (Maybe(..)) +import Data.Symbol (class IsSymbol, SProxy, reflectSymbol) +import Heterogeneous.Folding (class FoldingWithIndex, class HFoldlWithIndex, hfoldlWithIndex) +import Prim.RowList (class RowToList) data FillStyle = Filled @@ -12,6 +18,7 @@ data FillStyle | Invis derive instance genericFillStyle :: Generic FillStyle _ +instance eqFillStyle :: Eq FillStyle where eq = genericEq instance showFillStyle :: Show FillStyle where show = genericShow @@ -21,3 +28,58 @@ instance fillStyleDotLang :: DotLang FillStyle where toText Dotted = "dotted" toText Invis = "invis" +instance fillstyle :: DotLangValue FillStyle where + toValue Filled = "filled" + toValue Dotted = "dotted" + toValue Invis = "invis" + + +data LabelValue + = TextLabel String + | HtmlLabel String + +derive instance genericLabel :: Generic LabelValue _ + +instance showLabel :: Show LabelValue where + show = genericShow + +instance labelValue :: DotLangValue LabelValue where + toValue (TextLabel t) = show t + toValue (HtmlLabel t) = show t + +-- | +-- | ```purescript +-- | htmlLabel "
Label
" -- :: Attr +-- | ``` +-- | htmlLabel as a part of an attribute of a node. +htmlLabel :: ∀ r. String -> Attribute { label :: Maybe LabelValue | r } +htmlLabel text = _ { label = Just $ HtmlLabel text } + +-- | +-- | ```purescript +-- | textLabel "..." -- :: Attr +-- | ``` +-- | label as a part of an attribute of a node. +label :: ∀ r. String -> Attribute { label :: Maybe LabelValue | r } +label text = _ { label = Just $ TextLabel text } + + +type Attribute r + = r -> r + +data FoldToDotLang + = FoldToDotLang + +instance foldAttribtues ∷ + (IsSymbol sym, DotLangValue a) => + FoldingWithIndex FoldToDotLang (SProxy sym) (Array String) (Maybe a) (Array String) where + foldingWithIndex _ _ acc Nothing = acc + foldingWithIndex _ key acc (Just value) = acc <> [ reflectSymbol key <> "=" <> toValue value ] + +attributesToText :: + ∀ r rl. + RowToList r rl => + HFoldlWithIndex FoldToDotLang (Array String) { | r } (Array String) => + { | r } -> + (Array String) +attributesToText r = hfoldlWithIndex FoldToDotLang ([] :: Array String) r diff --git a/src/Data/DotLang/Attr/Edge.purs b/src/Data/DotLang/Attr/Edge.purs index 4bfc7ee..a66e633 100644 --- a/src/Data/DotLang/Attr/Edge.purs +++ b/src/Data/DotLang/Attr/Edge.purs @@ -1,21 +1,12 @@ module Data.DotLang.Attr.Edge where import Prelude - -import Color (Color, toHexString) -import Data.DotLang.Attr (FillStyle) -import Data.DotLang.Class (class DotLang, toText) +import Color (Color) +import Data.DotLang.Attr (FillStyle, Attribute, LabelValue) +import Data.DotLang.Class (class DotLangValue) import Data.Generic.Rep (class Generic) import Data.Generic.Rep.Show (genericShow) - -data LabelValue - = TextLabel String - | HtmlLabel String - -derive instance genericLabel :: Generic LabelValue _ - -instance showLabel :: Show LabelValue where - show = genericShow +import Data.Maybe (Maybe(..)) data ArrowHeadStyle = Normal @@ -43,65 +34,50 @@ derive instance genericArrowHeadStyle :: Generic ArrowHeadStyle _ instance showArrowHeadStyle :: Show ArrowHeadStyle where show = genericShow -instance arrowHeadStyle :: DotLang ArrowHeadStyle where - toText Normal = "normal" - toText Inv = "inv" - toText Dot = "dot" - toText InvDot = "invdot" - toText ODot = "odot" - toText InvODot = "invodot" - toText None = "none" - toText Tee = "tee" - toText Empty = "empty" - toText InvEmpty = "invempty" - toText Diamond = "diamond" - toText ODiamond = "odiamond" - toText EDiamond = "ediamond" - toText Crow = "crow" - toText Box = "box" - toText OBox = "obox" - toText Open = "open" - toText HalfOpen = "halfopen" - toText Vee = "vee" - -data Attr - = Color Color - | FontColor Color - | FontSize Int - | Label LabelValue - | Style FillStyle - | FillColor Color - | PenWidth Number - | ArrowHead ArrowHeadStyle - -derive instance genericAttr :: Generic Attr _ - -instance showAttr :: Show Attr where - show = genericShow +instance arrowHeadStyleValue :: DotLangValue ArrowHeadStyle where + toValue Normal = "normal" + toValue Inv = "inv" + toValue Dot = "dot" + toValue InvDot = "invdot" + toValue ODot = "odot" + toValue InvODot = "invodot" + toValue None = "none" + toValue Tee = "tee" + toValue Empty = "empty" + toValue InvEmpty = "invempty" + toValue Diamond = "diamond" + toValue ODiamond = "odiamond" + toValue EDiamond = "ediamond" + toValue Crow = "crow" + toValue Box = "box" + toValue OBox = "obox" + toValue Open = "open" + toValue HalfOpen = "halfopen" + toValue Vee = "vee" -instance attrDotLang :: DotLang Attr where - toText (Color s) = "color=\"" <> toHexString s <> "\"" - toText (FontColor s) = "fontcolor=\"" <> toHexString s <> "\"" - toText (FontSize i) = "fontsize="<> show i - toText (Style f) = "style="<> toText f - toText (Label (TextLabel t)) = "label=" <> show t - toText (Label (HtmlLabel t)) = "label=" <> t - toText (FillColor c) = "fillcolor=\"" <> toHexString c <> "\"" - toText (PenWidth i) = "penwidth="<> show i - toText (ArrowHead s) = "arrowhead=" <> toText s +arrowHead :: ∀ r. ArrowHeadStyle -> Attribute { arrowhead :: Maybe ArrowHeadStyle | r } +arrowHead v = _ { arrowhead = Just v } --- | --- | ```purescript --- | htmlLabel "
Label
" -- :: Attr --- | ``` --- | htmlLabel as a part of an attribute of an edge. -htmlLabel :: String -> Attr -htmlLabel = HtmlLabel >>> Label +type EdgeAttributes r + = ( color :: Maybe Color + , fontcolor :: Maybe Color + , fontsize :: Maybe Int + , label :: Maybe LabelValue + , style :: Maybe FillStyle + , fillcolor :: Maybe Color + , penwidth :: Maybe Number + , arrowhead :: Maybe ArrowHeadStyle + | r + ) --- | --- | ```purescript --- | label "..." -- :: Attr --- | ``` --- | label as a part of an attribute of an edge. -label :: String -> Attr -label = TextLabel >>> Label +defaultEdgeAttributes :: Record (EdgeAttributes ()) +defaultEdgeAttributes = + { color: Nothing + , fontcolor: Nothing + , fontsize: Nothing + , label: Nothing + , style: Nothing + , fillcolor: Nothing + , penwidth: Nothing + , arrowhead: Nothing + } diff --git a/src/Data/DotLang/Attr/Node.purs b/src/Data/DotLang/Attr/Node.purs index 1bd7df8..ed08568 100644 --- a/src/Data/DotLang/Attr/Node.purs +++ b/src/Data/DotLang/Attr/Node.purs @@ -1,64 +1,117 @@ module Data.DotLang.Attr.Node where import Prelude - import Color (Color, toHexString) -import Data.DotLang.Attr (FillStyle) -import Data.DotLang.Class (class DotLang, toText) +import Data.DotLang.Attr (Attribute, FillStyle, LabelValue) +import Data.DotLang.Class (class DotLang, class DotLangValue, toText, toValue) import Data.Generic.Rep (class Generic) import Data.Generic.Rep.Show (genericShow) +import Data.Maybe (Maybe(..)) +import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol) +import Heterogeneous.Folding (class FoldingWithIndex, class HFoldlWithIndex, hfoldlWithIndex) +import Prim.RowList (class RowToList) -data LabelValue - = TextLabel String - | HtmlLabel String - -derive instance genericLabel :: Generic LabelValue _ - -instance showLabel :: Show LabelValue where - show = genericShow +type NodeAtributes r + = ( color :: Maybe Color + , margin :: Maybe Int + , fontColor :: Maybe Color + , fontSize :: Maybe Int + , width :: Maybe Int + , label :: Maybe LabelValue + , shape :: Maybe ShapeType + , style :: Maybe FillStyle + , fillcolor :: Maybe Color + , penWidth :: Maybe Number + | r + ) -data Attr - = Color Color - | Margin Int - | FontColor Color - | FontSize Int - | Width Int - | Label LabelValue - | Shape ShapeType - | Style FillStyle - | FillColor Color - | PenWidth Number +defaultNodeAttributes :: Record (NodeAtributes ()) +defaultNodeAttributes = + { color: Nothing + , margin: Nothing + , fontColor: Nothing + , fontSize: Nothing + , width: Nothing + , label: Nothing + , shape: Nothing + , style: Nothing + , fillcolor: Nothing + , penWidth: Nothing + } -derive instance genericAttr :: Generic Attr _ +instance shapeType :: DotLangValue ShapeType where + toValue = toText -instance showAttr :: Show Attr where - show = genericShow +style :: ∀ r. FillStyle -> Attribute { style :: Maybe FillStyle | r } +style v = _ { style = Just v } -instance attrDotLang :: DotLang Attr where - toText (Margin i) = "margin="<> show i - toText (Color s) = "color=\"" <> toHexString s <> "\"" - toText (FontColor s) = "fontcolor=\"" <> toHexString s <> "\"" - toText (FontSize i) = "fontsize="<> show i - toText (Width i) = "width="<> show i - toText (Shape t) = "shape="<> toText t - toText (Style f) = "style="<> toText f - toText (Label (TextLabel t)) = "label=" <> show t - toText (Label (HtmlLabel t)) = "label=" <> t - toText (FillColor c) = "fillcolor=\"" <> toHexString c <> "\"" - toText (PenWidth i) = "penwidth="<> show i +fillColor :: ∀ r. Color -> Attribute { fillcolor :: Maybe Color | r } +fillColor v = _ { fillcolor = Just v } -- | possible node shapes data ShapeType - = Box | Polygon | Ellipse | Oval | Circle | Point | Egg - | Triangle | Plaintext | Plain | Diamond | Trapezium | Parallelogram - | House | Pentagon | Hexagon | Septagon | Octagon | Doublecircle - | Doubleoctagon | Tripleoctagon | Invtriangle | Invtrapezium - | Invhouse | Mdiamond | Msquare | Mcircle | Rect | Rectangle | Square - | Star | None | Underline | Cylinder | Note | Tab | Folder | Box3d - | Component | Promoter | Cds | Terminator | Utr | Primersite | Restrictionsite - | Fivepoverhang | Threepoverhang | Noverhang | Assembly | Signature - | Insulator | Ribosite | Rnastab | Proteasesite | Proteinstab | Rpromoter - | Rarrow | Larrow | Lpromoter + = Box + | Polygon + | Ellipse + | Oval + | Circle + | Point + | Egg + | Triangle + | Plaintext + | Plain + | Diamond + | Trapezium + | Parallelogram + | House + | Pentagon + | Hexagon + | Septagon + | Octagon + | Doublecircle + | Doubleoctagon + | Tripleoctagon + | Invtriangle + | Invtrapezium + | Invhouse + | Mdiamond + | Msquare + | Mcircle + | Rect + | Rectangle + | Square + | Star + | None + | Underline + | Cylinder + | Note + | Tab + | Folder + | Box3d + | Component + | Promoter + | Cds + | Terminator + | Utr + | Primersite + | Restrictionsite + | Fivepoverhang + | Threepoverhang + | Noverhang + | Assembly + | Signature + | Insulator + | Ribosite + | Rnastab + | Proteasesite + | Proteinstab + | Rpromoter + | Rarrow + | Larrow + | Lpromoter + +shape :: ∀ r. ShapeType -> Attribute { shape :: Maybe ShapeType | r } +shape v = _ { shape = Just v } derive instance genericShapeType :: Generic ShapeType _ @@ -125,19 +178,3 @@ instance dotLangShape :: DotLang ShapeType where toText Rarrow = "Rarrow" toText Larrow = "Larrow" toText Lpromoter = "Lpromoter" - --- | --- | ```purescript --- | htmlLabel "
Label
" -- :: Attr --- | ``` --- | htmlLabel as a part of an attribute of a node. -htmlLabel :: String -> Attr -htmlLabel = HtmlLabel >>> Label - --- | --- | ```purescript --- | textLabel "..." -- :: Attr --- | ``` --- | label as a part of an attribute of a node. -label :: String -> Attr -label = TextLabel >>> Label diff --git a/src/Data/DotLang/Class.purs b/src/Data/DotLang/Class.purs index fafb72d..ab03b1a 100644 --- a/src/Data/DotLang/Class.purs +++ b/src/Data/DotLang/Class.purs @@ -1,5 +1,20 @@ module Data.DotLang.Class where +import Prelude +import Color (Color, toHexString) + -- | `a` is a type that has a representation in the dot language class DotLang a where toText :: a -> String + +class DotLangValue a where + toValue :: a -> String + +instance color :: DotLangValue Color where + toValue v = "\"" <> toHexString v <> "\"" + +instance int :: DotLangValue Int where + toValue = show + +instance number :: DotLangValue Number where + toValue = show \ No newline at end of file diff --git a/test/Main.purs b/test/Main.purs index e231063..553f4fc 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -1,15 +1,15 @@ module Test.Main where import Prelude - import Color.Scheme.MaterialDesign (red) -import Data.DotLang (Definition(..), Graph(..), Edge(..), EdgeType(..), global, node, (==>), (=*>)) +import Data.DotLang (Definition(..), Edge(..), EdgeType(..), Graph(..), edge, global, node, (=*>), (==>)) import Data.DotLang.Attr (FillStyle(..)) +import Data.DotLang.Attr.Edge (arrowHead) import Data.DotLang.Attr.Edge as Edge -import Data.DotLang.Attr.Node (Attr(..), ShapeType(..)) -import Data.DotLang.Attr.Node as Node import Data.DotLang.Attr.Global (RankDirValue(..)) import Data.DotLang.Attr.Global as Global +import Data.DotLang.Attr.Node (shape, style, fillColor, ShapeType(..)) +import Data.DotLang.Attr.Node as Node import Data.DotLang.Class (toText) import Effect (Effect) import Test.Unit (suite, test) @@ -17,23 +17,26 @@ import Test.Unit.Assert (equal) import Test.Unit.Main (runTest) main ∷ Effect Unit -main = runTest do - suite "DotLang" do - test "basic test" do - let - g = DiGraph [ - global [ Global.RankDir FromLeft ], - node "a" [ Shape Diamond, Style Filled, Node.FillColor red ], - node "b" [], - "a" ==> "b", - "a" =*> "d" $ [ Edge.FillColor red ], - Subgraph [ - node "d" [] - ] - ] - equal "digraph {rankdir=LR; a [shape=diamond, style=filled, fillcolor=\"#f44336\"]; b []; a -> b; a -> d [fillcolor=\"#f44336\"]; subgraph { d []; }}" (toText g) - test "examples from documentation" do - equal (toText $ Edge Forward "a" "b" []) "a -> b" - equal (toText $ "a" =*> "b" $ [ Edge.FillColor red ]) "a -> b [fillcolor=\"#f44336\"]; " - test "ArrowHead" $ do - equal (toText $ "a" =*> "b" $ [ Edge.ArrowHead Edge.None ]) "a -> b [arrowhead=none]; " +main = + runTest do + suite "DotLang" do + test "basic test" do + let + g = + DiGraph + [ global [ Global.RankDir FromLeft ] + , node "a" [ shape Diamond, style Filled, fillColor red ] + , node "b" [] + , "a" ==> "b" + , "a" =*> "d" $ [ fillColor red ] + , Subgraph + [ node "d" [] + ] + ] + equal "digraph {rankdir=LR; a [fillcolor=\"#f44336\", shape=diamond, style=filled]; b []; a -> b; a -> d [fillcolor=\"#f44336\"]; subgraph { d []; }}" (toText g) + test "examples from documentation" do + equal "a -> b; " (toText $ edge Forward "a" "b" []) + equal "a -> b [fillcolor=\"#f44336\"]; " (toText $ "a" =*> "b" $ [ fillColor red ]) + test "ArrowHead" + $ do + equal (toText $ "a" =*> "b" $ [ arrowHead Edge.None ]) "a -> b [arrowhead=none]; " From e3764dae3f28e7a2c5becbdc94fe1d60496abb75 Mon Sep 17 00:00:00 2001 From: "Carsten Csiky (csicar)" Date: Thu, 23 Apr 2020 10:19:12 +0200 Subject: [PATCH 2/5] Add example image --- example.svg | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 example.svg diff --git a/example.svg b/example.svg new file mode 100644 index 0000000..f6ace02 --- /dev/null +++ b/example.svg @@ -0,0 +1,41 @@ + + + + + + +%0 + + + +a + +a + + + +b + +b + + + +a->b + + + + + +d + +d + + + +a->d + + + + + \ No newline at end of file From d7fcfe425803d4fc7dddfc360c2ec0053359fbd7 Mon Sep 17 00:00:00 2001 From: "Carsten Csiky (csicar)" Date: Thu, 23 Apr 2020 23:30:24 +0200 Subject: [PATCH 3/5] Cleanup and complete use of record style --- src/Data/DotLang.purs | 34 +++--- src/Data/DotLang/Attr.purs | 51 --------- src/Data/DotLang/Attr/Common.purs | 104 +++++++++++++++++ src/Data/DotLang/Attr/Edge.purs | 37 +++--- src/Data/DotLang/Attr/Global.purs | 70 +++++++----- src/Data/DotLang/Attr/Node.purs | 182 +++++++++++++----------------- test/Main.purs | 12 +- 7 files changed, 260 insertions(+), 230 deletions(-) create mode 100644 src/Data/DotLang/Attr/Common.purs diff --git a/src/Data/DotLang.purs b/src/Data/DotLang.purs index 4af4c44..1d28635 100644 --- a/src/Data/DotLang.purs +++ b/src/Data/DotLang.purs @@ -3,16 +3,17 @@ module Data.DotLang where import Prelude import Color (Color, toHexString) import Data.Array (foldr, null) -import Data.DotLang.Attr (Attribute, attributesToText, label) -import Data.DotLang.Attr.Edge (EdgeAttributes, defaultEdgeAttributes) +import Data.DotLang.Attr (Attribute, attributesToText) +import Data.DotLang.Attr.Common (label) +import Data.DotLang.Attr.Common as Gloabl import Data.DotLang.Attr.Edge as Edge import Data.DotLang.Attr.Global as Global -import Data.DotLang.Attr.Node (NodeAtributes, defaultNodeAttributes) import Data.DotLang.Attr.Node as Node import Data.DotLang.Class (class DotLang, toText) import Data.Generic.Rep (class Generic) import Data.Generic.Rep.Show (genericShow) import Data.String (joinWith) +import Data.Symbol (SProxy(..)) import Prelude (class Show, ($), (<$>), (<>)) -- | type alias for a Nodes Name @@ -26,7 +27,7 @@ type Id -- | ``` -- | is turned into: `e [margin=3, label="some label"];` data Node - = Node Id { | NodeAtributes () } + = Node Id { | Node.Attributes } -- | get a nodes id -- | example: @@ -68,7 +69,7 @@ instance dotLangEdgeType :: DotLang EdgeType where -- | `toText $ Edge Forward "a" "b" []` == `a -> b []` -- | EdgeType determines the direction of the arrow data Edge - = Edge EdgeType Id Id { | EdgeAttributes () } + = Edge EdgeType Id Id { | Edge.Attributes } derive instance genericEdge :: Generic Edge _ @@ -84,12 +85,11 @@ instance dotLangEdge :: DotLang Edge where -- | definition in a graph data Definition - = Global (Array Global.Attr) + = Global { | Global.Attributes } | NodeDef Node | EdgeDef Edge | Subgraph (Array Definition) - derive instance genericDefinition :: Generic Definition _ instance showDefinition :: Show Definition where @@ -100,16 +100,16 @@ instance showDefinition :: Show Definition where -- | global [ Global.RankDir Global.FromLeft ] -- ∷ Definition -- | ``` -- | global as a part of a definition -global :: Array Global.Attr -> Definition -global = Global +global :: Array (Attribute { | Global.Attributes }) -> Definition +global = (foldr ($) Global.defaultAttributes) >>> Global -- | -- | ```purescript -- | node "a" [] -- ∷ Definition -- | ``` -- | node as a part of a definition -node :: Id → Array (Attribute { | NodeAtributes () }) → Definition -node id attrs = NodeDef $ Node id (foldr ($) defaultNodeAttributes $ attrs) +node :: Id → Array (Attribute { | Node.Attributes }) → Definition +node id attrs = NodeDef $ Node id (foldr ($) Node.defaultAttributes $ attrs) -- | -- | ```purescript @@ -117,22 +117,22 @@ node id attrs = NodeDef $ Node id (foldr ($) defaultNodeAttributes $ attrs) -- | ``` -- | edge as a part of a definition. -- | `==>` and `=*>` can also be used for that purpose. -edge :: EdgeType → Id → Id → Array (Attribute { | EdgeAttributes () }) → Definition -edge t id id2 attrs = EdgeDef $ Edge t id id2 (foldr ($) defaultEdgeAttributes $ attrs) +edge :: EdgeType → Id → Id → Array (Attribute { | Edge.Attributes }) → Definition +edge t id id2 attrs = EdgeDef $ Edge t id id2 (foldr ($) Edge.defaultAttributes $ attrs) -forwardEdgeWithAttrs ∷ Id → Id → Array (Attribute { | EdgeAttributes () }) → Definition +forwardEdgeWithAttrs ∷ Id → Id → Array (Attribute { | Edge.Attributes }) → Definition forwardEdgeWithAttrs = edge Forward forwardEdge :: Id → Id → Definition forwardEdge l r = forwardEdgeWithAttrs l r [] -backwardEdgeWithAttrs ∷ Id → Id → Array (Attribute { | EdgeAttributes () }) → Definition +backwardEdgeWithAttrs ∷ Id → Id → Array (Attribute { | Edge.Attributes }) → Definition backwardEdgeWithAttrs = edge Backward backwardEdge ∷ Id → Id → Definition backwardEdge l r = backwardEdgeWithAttrs l r [] -normalEdgeWithAttrs ∷ Id → Id → Array (Attribute { | EdgeAttributes () }) → Definition +normalEdgeWithAttrs ∷ Id → Id → Array (Attribute { | Edge.Attributes }) → Definition normalEdgeWithAttrs = edge NoDir normalEdge ∷ Id → Id → Definition @@ -182,7 +182,7 @@ infix 5 normalEdge as -==- infix 5 normalEdgeWithAttrs as =*= instance definitionDotlang :: DotLang Definition where - toText (Global attrs) = joinWith "; " (toText <$> attrs) <> "; " + toText (Global attrs) = joinWith "; " (attributesToText attrs) <> "; " toText (NodeDef n) = toText n <> "; " toText (EdgeDef e) = toText e <> "; " toText (Subgraph defs) = "subgraph { " <> (joinWith "" $ toText <$> defs) <> "}" diff --git a/src/Data/DotLang/Attr.purs b/src/Data/DotLang/Attr.purs index 8d420c8..40cdd4f 100644 --- a/src/Data/DotLang/Attr.purs +++ b/src/Data/DotLang/Attr.purs @@ -12,57 +12,6 @@ import Data.Symbol (class IsSymbol, SProxy, reflectSymbol) import Heterogeneous.Folding (class FoldingWithIndex, class HFoldlWithIndex, hfoldlWithIndex) import Prim.RowList (class RowToList) -data FillStyle - = Filled - | Dotted - | Invis - -derive instance genericFillStyle :: Generic FillStyle _ -instance eqFillStyle :: Eq FillStyle where eq = genericEq - -instance showFillStyle :: Show FillStyle where - show = genericShow - -instance fillStyleDotLang :: DotLang FillStyle where - toText Filled = "filled" - toText Dotted = "dotted" - toText Invis = "invis" - -instance fillstyle :: DotLangValue FillStyle where - toValue Filled = "filled" - toValue Dotted = "dotted" - toValue Invis = "invis" - - -data LabelValue - = TextLabel String - | HtmlLabel String - -derive instance genericLabel :: Generic LabelValue _ - -instance showLabel :: Show LabelValue where - show = genericShow - -instance labelValue :: DotLangValue LabelValue where - toValue (TextLabel t) = show t - toValue (HtmlLabel t) = show t - --- | --- | ```purescript --- | htmlLabel "
Label
" -- :: Attr --- | ``` --- | htmlLabel as a part of an attribute of a node. -htmlLabel :: ∀ r. String -> Attribute { label :: Maybe LabelValue | r } -htmlLabel text = _ { label = Just $ HtmlLabel text } - --- | --- | ```purescript --- | textLabel "..." -- :: Attr --- | ``` --- | label as a part of an attribute of a node. -label :: ∀ r. String -> Attribute { label :: Maybe LabelValue | r } -label text = _ { label = Just $ TextLabel text } - type Attribute r = r -> r diff --git a/src/Data/DotLang/Attr/Common.purs b/src/Data/DotLang/Attr/Common.purs new file mode 100644 index 0000000..199cd31 --- /dev/null +++ b/src/Data/DotLang/Attr/Common.purs @@ -0,0 +1,104 @@ +module Data.DotLang.Attr.Common where + +import Prelude + +import Color (Color) +import Data.DotLang.Attr (Attribute) +import Data.DotLang.Class (class DotLangValue) +import Data.Generic.Rep (class Generic) +import Data.Generic.Rep.Eq (genericEq) +import Data.Generic.Rep.Show (genericShow) +import Data.Maybe (Maybe(..)) + +type Attributes r + = ( color :: Maybe Color + , fontColor :: Maybe Color + , fontSize :: Maybe Int + , label :: Maybe LabelValue + , style :: Maybe FillStyle + , fillcolor :: Maybe Color + , penWidth :: Maybe Number + | r + ) + +defaultAttributes :: { | Attributes () } +defaultAttributes = + { color: Nothing + , fontColor: Nothing + , fontSize: Nothing + , label: Nothing + , style: Nothing + , fillcolor: Nothing + , penWidth: Nothing + } + + +color :: ∀ r. Color -> Attribute { | Attributes r } +color v = _ { color = Just v } + + +fontColor :: ∀ r. Color -> Attribute { | Attributes r } +fontColor v = _ { fontColor = Just v } + + +fontSize :: ∀ r. Int -> Attribute { | Attributes r } +fontSize v = _ { fontSize = Just v } + + +style :: ∀ r. FillStyle -> Attribute { | Attributes r } +style v = _ { style = Just v } + +fillColor :: ∀ r. Color -> Attribute { | Attributes r } +fillColor v = _ { fillcolor = Just v } + + +penWidth :: ∀ r. Number -> Attribute { | Attributes r } +penWidth v = _ { penWidth = Just v } + + +-- | +-- | ```purescript +-- | htmlLabel "
Label
" -- :: Attribute .. +-- | ``` +-- | htmlLabel as a part of an attribute of a node. +htmlLabel :: ∀ r. String -> Attribute { | Attributes r } +htmlLabel text = _ { label = Just $ HtmlLabel text } + +-- | +-- | ```purescript +-- | textLabel "..." -- :: Attribute ... +-- | ``` +-- | label as a part of an attribute of a node. +label :: ∀ r. String -> Attribute { | Attributes r } +label text = _ { label = Just $ TextLabel text } + +data FillStyle + = Filled + | Dotted + | Invis + +derive instance genericFillStyle :: Generic FillStyle _ +instance eqFillStyle :: Eq FillStyle where eq = genericEq + +instance showFillStyle :: Show FillStyle where + show = genericShow + +instance fillstyle :: DotLangValue FillStyle where + toValue Filled = "filled" + toValue Dotted = "dotted" + toValue Invis = "invis" + + +data LabelValue + = TextLabel String + | HtmlLabel String + +derive instance genericLabel :: Generic LabelValue _ + +instance showLabel :: Show LabelValue where + show = genericShow + +instance labelValue :: DotLangValue LabelValue where + toValue (TextLabel t) = show t + toValue (HtmlLabel t) = show t + diff --git a/src/Data/DotLang/Attr/Edge.purs b/src/Data/DotLang/Attr/Edge.purs index a66e633..b20d49f 100644 --- a/src/Data/DotLang/Attr/Edge.purs +++ b/src/Data/DotLang/Attr/Edge.purs @@ -1,12 +1,13 @@ module Data.DotLang.Attr.Edge where import Prelude -import Color (Color) -import Data.DotLang.Attr (FillStyle, Attribute, LabelValue) +import Data.DotLang.Attr (Attribute) +import Data.DotLang.Attr.Common as Common import Data.DotLang.Class (class DotLangValue) import Data.Generic.Rep (class Generic) import Data.Generic.Rep.Show (genericShow) import Data.Maybe (Maybe(..)) +import Record as Record data ArrowHeadStyle = Normal @@ -58,26 +59,14 @@ instance arrowHeadStyleValue :: DotLangValue ArrowHeadStyle where arrowHead :: ∀ r. ArrowHeadStyle -> Attribute { arrowhead :: Maybe ArrowHeadStyle | r } arrowHead v = _ { arrowhead = Just v } -type EdgeAttributes r - = ( color :: Maybe Color - , fontcolor :: Maybe Color - , fontsize :: Maybe Int - , label :: Maybe LabelValue - , style :: Maybe FillStyle - , fillcolor :: Maybe Color - , penwidth :: Maybe Number - , arrowhead :: Maybe ArrowHeadStyle - | r - ) +type Attributes + = Common.Attributes + ( arrowhead :: Maybe ArrowHeadStyle + ) -defaultEdgeAttributes :: Record (EdgeAttributes ()) -defaultEdgeAttributes = - { color: Nothing - , fontcolor: Nothing - , fontsize: Nothing - , label: Nothing - , style: Nothing - , fillcolor: Nothing - , penwidth: Nothing - , arrowhead: Nothing - } +defaultAttributes :: Record Attributes +defaultAttributes = + Common.defaultAttributes + `Record.disjointUnion` + { arrowhead: Nothing + } diff --git a/src/Data/DotLang/Attr/Global.purs b/src/Data/DotLang/Attr/Global.purs index 0db342d..ea91627 100644 --- a/src/Data/DotLang/Attr/Global.purs +++ b/src/Data/DotLang/Attr/Global.purs @@ -1,10 +1,25 @@ module Data.DotLang.Attr.Global where import Prelude - -import Data.DotLang.Class (class DotLang, toText) +import Data.DotLang.Attr (Attribute, attributesToText) +import Data.DotLang.Class (class DotLangValue, toValue) import Data.Generic.Rep (class Generic) import Data.Generic.Rep.Show (genericShow) +import Data.Maybe (Maybe(..)) + +type Attributes + = ( rankDir :: Maybe RankDirValue + , pageDir :: Maybe PageDirValue + ) + +defaultAttributes :: { | Attributes } +defaultAttributes = { rankDir: Nothing, pageDir: Nothing } + +rankDir :: RankDirValue -> Attribute { | Attributes } +rankDir v = _ { rankDir = Just v } + +pageDir :: PageDirValue -> Attribute { | Attributes } +pageDir v = _ { pageDir = Just v } data RankDirValue = FromTop @@ -17,40 +32,35 @@ derive instance genericRankDirVal :: Generic RankDirValue _ instance showRankDirValue :: Show RankDirValue where show = genericShow -instance rankDirValueDotLang :: DotLang RankDirValue where - toText FromTop = "TB" - toText FromLeft = "LR" - toText FromBottom = "BT" - toText FromRight = "RL" +instance rankDirValueDotLangValue :: DotLangValue RankDirValue where + toValue FromTop = "TB" + toValue FromLeft = "LR" + toValue FromBottom = "BT" + toValue FromRight = "RL" -- | Upper-case first character is major order; -- | lower-case second character is minor order. -data PageDirValue = Bl | Br | Tl | Tr | Rb | Rt | Lb | Lt +data PageDirValue + = Bl + | Br + | Tl + | Tr + | Rb + | Rt + | Lb + | Lt derive instance genericPageDirValue :: Generic PageDirValue _ instance showPageDirValue :: Show PageDirValue where show = genericShow -instance pageDirValueDotLang :: DotLang PageDirValue where - toText Bl = "BL" - toText Br = "BR" - toText Tl = "TL" - toText Tr = "TR" - toText Rb = "RB" - toText Rt = "RT" - toText Lb = "LB" - toText Lt = "LT" - -data Attr - = RankDir RankDirValue - | PageDir PageDirValue - -derive instance genericAttr :: Generic Attr _ - -instance showAttr :: Show Attr where - show = genericShow - -instance attrDotLang :: DotLang Attr where - toText (RankDir dir) = "rankdir=" <> toText dir - toText (PageDir dir) = "pagedir=" <> toText dir +instance pageDirValueDotLangValue :: DotLangValue PageDirValue where + toValue Bl = "BL" + toValue Br = "BR" + toValue Tl = "TL" + toValue Tr = "TR" + toValue Rb = "RB" + toValue Rt = "RT" + toValue Lb = "LB" + toValue Lt = "LT" diff --git a/src/Data/DotLang/Attr/Node.purs b/src/Data/DotLang/Attr/Node.purs index ed08568..ac6dd3a 100644 --- a/src/Data/DotLang/Attr/Node.purs +++ b/src/Data/DotLang/Attr/Node.purs @@ -1,52 +1,30 @@ module Data.DotLang.Attr.Node where -import Prelude -import Color (Color, toHexString) -import Data.DotLang.Attr (Attribute, FillStyle, LabelValue) -import Data.DotLang.Class (class DotLang, class DotLangValue, toText, toValue) +import Prelude (class Show) +import Color (Color) +import Data.DotLang.Attr (Attribute) +import Data.DotLang.Attr.Common as Common +import Data.DotLang.Class (class DotLang, class DotLangValue, toText) import Data.Generic.Rep (class Generic) import Data.Generic.Rep.Show (genericShow) import Data.Maybe (Maybe(..)) -import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol) -import Heterogeneous.Folding (class FoldingWithIndex, class HFoldlWithIndex, hfoldlWithIndex) -import Prim.RowList (class RowToList) +import Record as Record -type NodeAtributes r - = ( color :: Maybe Color - , margin :: Maybe Int - , fontColor :: Maybe Color - , fontSize :: Maybe Int - , width :: Maybe Int - , label :: Maybe LabelValue - , shape :: Maybe ShapeType - , style :: Maybe FillStyle - , fillcolor :: Maybe Color - , penWidth :: Maybe Number - | r - ) +type Attributes + = Common.Attributes + ( margin :: Maybe Int + , width :: Maybe Int + , shape :: Maybe ShapeType + ) -defaultNodeAttributes :: Record (NodeAtributes ()) -defaultNodeAttributes = - { color: Nothing - , margin: Nothing - , fontColor: Nothing - , fontSize: Nothing - , width: Nothing - , label: Nothing - , shape: Nothing - , style: Nothing - , fillcolor: Nothing - , penWidth: Nothing - } - -instance shapeType :: DotLangValue ShapeType where - toValue = toText - -style :: ∀ r. FillStyle -> Attribute { style :: Maybe FillStyle | r } -style v = _ { style = Just v } - -fillColor :: ∀ r. Color -> Attribute { fillcolor :: Maybe Color | r } -fillColor v = _ { fillcolor = Just v } +defaultAttributes :: { | Attributes } +defaultAttributes = + Common.defaultAttributes + `Record.disjointUnion` + { margin: Nothing + , width: Nothing + , shape: Nothing + } -- | possible node shapes data ShapeType @@ -118,63 +96,63 @@ derive instance genericShapeType :: Generic ShapeType _ instance showShapeType :: Show ShapeType where show = genericShow -instance dotLangShape :: DotLang ShapeType where - toText Box = "box" - toText Polygon = "polygon" - toText Ellipse = "ellipse" - toText Oval = "oval" - toText Circle = "circle" - toText Point = "point" - toText Egg = "egg" - toText Triangle = "triangle" - toText Plaintext = "plaintext" - toText Plain = "plain" - toText Diamond = "diamond" - toText Trapezium = "trapezium" - toText Parallelogram = "parallelogram" - toText House = "house" - toText Pentagon = "pentagon" - toText Hexagon = "hexagon" - toText Septagon = "septagon" - toText Octagon = "octagon" - toText Doublecircle = "doublecircle" - toText Doubleoctagon = "doubleoctagon" - toText Tripleoctagon = "tripleoctagon" - toText Invtriangle = "invtriangle" - toText Invtrapezium = "invtrapezium" - toText Invhouse = "invhouse" - toText Mdiamond = "mdiamond" - toText Msquare = "msquare" - toText Mcircle = "mcircle" - toText Rect = "rect" - toText Rectangle = "rectangle" - toText Square = "square" - toText Star = "star" - toText None = "none" - toText Underline = "underline" - toText Cylinder = "cylinder" - toText Note = "note" - toText Tab = "tab" - toText Folder = "folder" - toText Box3d = "box3d" - toText Component = "component" - toText Promoter = "promoter" - toText Cds = "cds" - toText Terminator = "terminator" - toText Utr = "utr" - toText Primersite = "primersite" - toText Restrictionsite = "restrictionsite" - toText Fivepoverhang = "fivepoverhang" - toText Threepoverhang = "threepoverhang" - toText Noverhang = "noverhang" - toText Assembly = "assembly" - toText Signature = "signature" - toText Insulator = "insulator" - toText Ribosite = "ribosite" - toText Rnastab = "rnastab" - toText Proteasesite = "proteasesite" - toText Proteinstab = "proteinstab" - toText Rpromoter = "rpromoter" - toText Rarrow = "Rarrow" - toText Larrow = "Larrow" - toText Lpromoter = "Lpromoter" +instance dotLangShape :: DotLangValue ShapeType where + toValue Box = "box" + toValue Polygon = "polygon" + toValue Ellipse = "ellipse" + toValue Oval = "oval" + toValue Circle = "circle" + toValue Point = "point" + toValue Egg = "egg" + toValue Triangle = "triangle" + toValue Plaintext = "plaintext" + toValue Plain = "plain" + toValue Diamond = "diamond" + toValue Trapezium = "trapezium" + toValue Parallelogram = "parallelogram" + toValue House = "house" + toValue Pentagon = "pentagon" + toValue Hexagon = "hexagon" + toValue Septagon = "septagon" + toValue Octagon = "octagon" + toValue Doublecircle = "doublecircle" + toValue Doubleoctagon = "doubleoctagon" + toValue Tripleoctagon = "tripleoctagon" + toValue Invtriangle = "invtriangle" + toValue Invtrapezium = "invtrapezium" + toValue Invhouse = "invhouse" + toValue Mdiamond = "mdiamond" + toValue Msquare = "msquare" + toValue Mcircle = "mcircle" + toValue Rect = "rect" + toValue Rectangle = "rectangle" + toValue Square = "square" + toValue Star = "star" + toValue None = "none" + toValue Underline = "underline" + toValue Cylinder = "cylinder" + toValue Note = "note" + toValue Tab = "tab" + toValue Folder = "folder" + toValue Box3d = "box3d" + toValue Component = "component" + toValue Promoter = "promoter" + toValue Cds = "cds" + toValue Terminator = "terminator" + toValue Utr = "utr" + toValue Primersite = "primersite" + toValue Restrictionsite = "restrictionsite" + toValue Fivepoverhang = "fivepoverhang" + toValue Threepoverhang = "threepoverhang" + toValue Noverhang = "noverhang" + toValue Assembly = "assembly" + toValue Signature = "signature" + toValue Insulator = "insulator" + toValue Ribosite = "ribosite" + toValue Rnastab = "rnastab" + toValue Proteasesite = "proteasesite" + toValue Proteinstab = "proteinstab" + toValue Rpromoter = "rpromoter" + toValue Rarrow = "Rarrow" + toValue Larrow = "Larrow" + toValue Lpromoter = "Lpromoter" diff --git a/test/Main.purs b/test/Main.purs index 553f4fc..ea7afcc 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -1,14 +1,14 @@ module Test.Main where import Prelude + import Color.Scheme.MaterialDesign (red) import Data.DotLang (Definition(..), Edge(..), EdgeType(..), Graph(..), edge, global, node, (=*>), (==>)) -import Data.DotLang.Attr (FillStyle(..)) +import Data.DotLang.Attr.Common (FillStyle(..), fillColor, style) import Data.DotLang.Attr.Edge (arrowHead) import Data.DotLang.Attr.Edge as Edge -import Data.DotLang.Attr.Global (RankDirValue(..)) -import Data.DotLang.Attr.Global as Global -import Data.DotLang.Attr.Node (shape, style, fillColor, ShapeType(..)) +import Data.DotLang.Attr.Global (RankDirValue(..), rankDir) +import Data.DotLang.Attr.Node (shape) import Data.DotLang.Attr.Node as Node import Data.DotLang.Class (toText) import Effect (Effect) @@ -24,8 +24,8 @@ main = let g = DiGraph - [ global [ Global.RankDir FromLeft ] - , node "a" [ shape Diamond, style Filled, fillColor red ] + [ global [ rankDir FromLeft ] + , node "a" [ shape Node.Diamond, style Filled, fillColor red ] , node "b" [] , "a" ==> "b" , "a" =*> "d" $ [ fillColor red ] From 0a689c612a4e5d7e29aa62694c9e7fd851167df4 Mon Sep 17 00:00:00 2001 From: "Carsten Csiky (csicar)" Date: Fri, 24 Apr 2020 00:06:40 +0200 Subject: [PATCH 4/5] Fix camelcasing --- src/Data/DotLang.purs | 1 + src/Data/DotLang/Attr.purs | 8 ++------ src/Data/DotLang/Attr/Common.purs | 12 ++++++------ src/Data/DotLang/Attr/Global.purs | 10 +++++----- src/Data/DotLang/Attr/Node.purs | 18 ++++++++++++------ test/Main.purs | 2 +- 6 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/Data/DotLang.purs b/src/Data/DotLang.purs index 1d28635..05bd448 100644 --- a/src/Data/DotLang.purs +++ b/src/Data/DotLang.purs @@ -1,6 +1,7 @@ module Data.DotLang where import Prelude + import Color (Color, toHexString) import Data.Array (foldr, null) import Data.DotLang.Attr (Attribute, attributesToText) diff --git a/src/Data/DotLang/Attr.purs b/src/Data/DotLang/Attr.purs index 40cdd4f..e3364e2 100644 --- a/src/Data/DotLang/Attr.purs +++ b/src/Data/DotLang/Attr.purs @@ -1,12 +1,8 @@ -module Data.DotLang.Attr where +module Data.DotLang.Attr (Attribute, attributesToText, FoldToDotLang()) where import Prelude -import Data.DotLang.Class (class DotLang, class DotLangValue) -import Data.DotLang.Class (class DotLang, class DotLangValue, toValue) -import Data.Generic.Rep (class Generic) -import Data.Generic.Rep.Eq (genericEq) -import Data.Generic.Rep.Show (genericShow) +import Data.DotLang.Class (class DotLangValue, toValue) import Data.Maybe (Maybe(..)) import Data.Symbol (class IsSymbol, SProxy, reflectSymbol) import Heterogeneous.Folding (class FoldingWithIndex, class HFoldlWithIndex, hfoldlWithIndex) diff --git a/src/Data/DotLang/Attr/Common.purs b/src/Data/DotLang/Attr/Common.purs index 199cd31..4d3b5e7 100644 --- a/src/Data/DotLang/Attr/Common.purs +++ b/src/Data/DotLang/Attr/Common.purs @@ -12,8 +12,8 @@ import Data.Maybe (Maybe(..)) type Attributes r = ( color :: Maybe Color - , fontColor :: Maybe Color - , fontSize :: Maybe Int + , fontcolor :: Maybe Color + , fontsize :: Maybe Int , label :: Maybe LabelValue , style :: Maybe FillStyle , fillcolor :: Maybe Color @@ -24,8 +24,8 @@ type Attributes r defaultAttributes :: { | Attributes () } defaultAttributes = { color: Nothing - , fontColor: Nothing - , fontSize: Nothing + , fontcolor: Nothing + , fontsize: Nothing , label: Nothing , style: Nothing , fillcolor: Nothing @@ -38,11 +38,11 @@ color v = _ { color = Just v } fontColor :: ∀ r. Color -> Attribute { | Attributes r } -fontColor v = _ { fontColor = Just v } +fontColor v = _ { fontcolor = Just v } fontSize :: ∀ r. Int -> Attribute { | Attributes r } -fontSize v = _ { fontSize = Just v } +fontSize v = _ { fontsize = Just v } style :: ∀ r. FillStyle -> Attribute { | Attributes r } diff --git a/src/Data/DotLang/Attr/Global.purs b/src/Data/DotLang/Attr/Global.purs index ea91627..2a4a536 100644 --- a/src/Data/DotLang/Attr/Global.purs +++ b/src/Data/DotLang/Attr/Global.purs @@ -8,18 +8,18 @@ import Data.Generic.Rep.Show (genericShow) import Data.Maybe (Maybe(..)) type Attributes - = ( rankDir :: Maybe RankDirValue - , pageDir :: Maybe PageDirValue + = ( rankdir :: Maybe RankDirValue + , pagedir :: Maybe PageDirValue ) defaultAttributes :: { | Attributes } -defaultAttributes = { rankDir: Nothing, pageDir: Nothing } +defaultAttributes = { rankdir: Nothing, pagedir: Nothing } rankDir :: RankDirValue -> Attribute { | Attributes } -rankDir v = _ { rankDir = Just v } +rankDir v = _ { rankdir = Just v } pageDir :: PageDirValue -> Attribute { | Attributes } -pageDir v = _ { pageDir = Just v } +pageDir v = _ { pagedir = Just v } data RankDirValue = FromTop diff --git a/src/Data/DotLang/Attr/Node.purs b/src/Data/DotLang/Attr/Node.purs index ac6dd3a..ed81a58 100644 --- a/src/Data/DotLang/Attr/Node.purs +++ b/src/Data/DotLang/Attr/Node.purs @@ -1,10 +1,10 @@ -module Data.DotLang.Attr.Node where +module Data.DotLang.Attr.Node (module Export, shape, ShapeType(..), margin, width, Attributes, defaultAttributes) where import Prelude (class Show) -import Color (Color) import Data.DotLang.Attr (Attribute) +import Data.DotLang.Attr.Common (FillStyle(..), LabelValue(..), color, fillColor, fontColor, fontSize, htmlLabel, label, penWidth, style) as Export import Data.DotLang.Attr.Common as Common -import Data.DotLang.Class (class DotLang, class DotLangValue, toText) +import Data.DotLang.Class (class DotLangValue) import Data.Generic.Rep (class Generic) import Data.Generic.Rep.Show (genericShow) import Data.Maybe (Maybe(..)) @@ -26,6 +26,15 @@ defaultAttributes = , shape: Nothing } +shape :: ShapeType -> Attribute { | Attributes } +shape v = _ { shape = Just v } + +margin :: Int -> Attribute { | Attributes } +margin v = _ { margin = Just v } + +width :: Int -> Attribute { | Attributes } +width v = _ { width = Just v } + -- | possible node shapes data ShapeType = Box @@ -88,9 +97,6 @@ data ShapeType | Larrow | Lpromoter -shape :: ∀ r. ShapeType -> Attribute { shape :: Maybe ShapeType | r } -shape v = _ { shape = Just v } - derive instance genericShapeType :: Generic ShapeType _ instance showShapeType :: Show ShapeType where diff --git a/test/Main.purs b/test/Main.purs index ea7afcc..4a04437 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -6,10 +6,10 @@ import Color.Scheme.MaterialDesign (red) import Data.DotLang (Definition(..), Edge(..), EdgeType(..), Graph(..), edge, global, node, (=*>), (==>)) import Data.DotLang.Attr.Common (FillStyle(..), fillColor, style) import Data.DotLang.Attr.Edge (arrowHead) -import Data.DotLang.Attr.Edge as Edge import Data.DotLang.Attr.Global (RankDirValue(..), rankDir) import Data.DotLang.Attr.Node (shape) import Data.DotLang.Attr.Node as Node +import Data.DotLang.Attr.Edge as Edge import Data.DotLang.Class (toText) import Effect (Effect) import Test.Unit (suite, test) From 90a6d72fea6befeeafde4bce6322c432d96a756c Mon Sep 17 00:00:00 2001 From: "Carsten Csiky (csicar)" Date: Fri, 24 Apr 2020 00:19:30 +0200 Subject: [PATCH 5/5] Update docs --- README.md | 14 +++++++++++++- src/Data/DotLang.purs | 16 ++++++++-------- src/Data/DotLang/Attr/Edge.purs | 5 +++-- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 1a21c0f..b97a321 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ import Color.Scheme.MaterialDesign (red) graph = DiGraph - [ global [ Global.RankDir FromLeft ] + [ global [ rankDir FromLeft ] , node "a" [ shape Node.Diamond, style Filled, fillColor red ] , node "b" [] , "a" ==> "b" @@ -82,6 +82,18 @@ bower i purescript-dotlang Changelog ========= +v4.0.0 +------ + +Breaking Changes: + +- dotlang now internally represents attributes as a record. To **migrate**: + - replace calls to Attribute constructors with their lower-case counter-part: + E.g. `FontColor` with calls to `fontColor` + - replace calls to `Node`, `Edge` and `Global` with `node`, `edge` and `global` +- to avoid name collisions, `Edge.Diamond :: ArrowHead` was renamed to `Edge.FDiamond` + + v3.0.0 ------ diff --git a/src/Data/DotLang.purs b/src/Data/DotLang.purs index 05bd448..e0f084b 100644 --- a/src/Data/DotLang.purs +++ b/src/Data/DotLang.purs @@ -24,7 +24,7 @@ type Id -- | Dot-Node -- | example : -- | ```purescript --- | Node "e" [Margin 3, Label "some label"] +-- | node "e" [margin 3, label "some label"] -- | ``` -- | is turned into: `e [margin=3, label="some label"];` data Node @@ -33,13 +33,13 @@ data Node -- | get a nodes id -- | example: -- | ```purescript --- | nodeId (Node "e" [Label "foo"]) == "e" +-- | nodeId (node "e" [label "foo"]) == "e" -- | ``` nodeId :: Node -> Id nodeId (Node id _) = id -- | change Nodes id to a new one; keeing the old id as the label --- | example: `mapNodeId (\a -> a+"!") (Node "e" []) == Node "e!" [Label "e"]` +-- | example: `mapNodeId (\a -> a+"!") (node "e" []) == node "e!" [label "e"]` changeNodeId :: (Id -> Id) -> Node -> Node changeNodeId f (Node id attr) = Node (f id) $ (label id attr) @@ -67,7 +67,7 @@ instance dotLangEdgeType :: DotLang EdgeType where toText NoDir = "--" -- | egde from id to id --- | `toText $ Edge Forward "a" "b" []` == `a -> b []` +-- | `toText $ edge Forward "a" "b" []` == `a -> b []` -- | EdgeType determines the direction of the arrow data Edge = Edge EdgeType Id Id { | Edge.Attributes } @@ -98,7 +98,7 @@ instance showDefinition :: Show Definition where -- | -- | ```purescript --- | global [ Global.RankDir Global.FromLeft ] -- ∷ Definition +-- | global [ Global.rankDir Global.FromLeft ] -- ∷ Definition -- | ``` -- | global as a part of a definition global :: Array (Attribute { | Global.Attributes }) -> Definition @@ -148,7 +148,7 @@ infix 5 forwardEdge as ==> -- | -- | ```purescript --- | "a" =*> "b" $ [ Edge.FillColor red ] +-- | "a" =*> "b" $ [ fillColor red ] -- | -- toText will be: a -> b [fillcolor="#f44336"]; -- | ``` -- | Forward edge with attributes as a definition @@ -163,7 +163,7 @@ infix 5 backwardEdge as <== -- | -- | ```purescript --- | "a" <*= "b" $ [ Edge.FillColor red ] +-- | "a" <*= "b" $ [ fillColor red ] -- | ``` -- | Backward edge with attributes as a definition infix 5 backwardEdgeWithAttrs as <*= @@ -177,7 +177,7 @@ infix 5 normalEdge as -==- -- | -- | ```purescript --- | "a" =*= "b" $ [ Edge.FillColor red ] +-- | "a" =*= "b" $ [ fillColor red ] -- | ``` -- | Normal edge with attibutes infix 5 normalEdgeWithAttrs as =*= diff --git a/src/Data/DotLang/Attr/Edge.purs b/src/Data/DotLang/Attr/Edge.purs index b20d49f..fc99974 100644 --- a/src/Data/DotLang/Attr/Edge.purs +++ b/src/Data/DotLang/Attr/Edge.purs @@ -9,6 +9,7 @@ import Data.Generic.Rep.Show (genericShow) import Data.Maybe (Maybe(..)) import Record as Record +--| https://www.graphviz.org/doc/info/attrs.html#k:arrowType data ArrowHeadStyle = Normal | Inv @@ -20,7 +21,7 @@ data ArrowHeadStyle | Tee | Empty | InvEmpty - | Diamond + | FDiamond | ODiamond | EDiamond | Crow @@ -46,7 +47,7 @@ instance arrowHeadStyleValue :: DotLangValue ArrowHeadStyle where toValue Tee = "tee" toValue Empty = "empty" toValue InvEmpty = "invempty" - toValue Diamond = "diamond" + toValue FDiamond = "diamond" toValue ODiamond = "odiamond" toValue EDiamond = "ediamond" toValue Crow = "crow"