packages feed

dataflow 0.5.4.0 → 0.6.0.0

raw patch · 12 files changed

+331/−180 lines, 12 filesdep +parsecnew-component:exe:dataflowPVP ok

version bump matches the API change (PVP)

Dependencies added: parsec

API changes (from Hackage documentation)

+ DataFlow.Core: instance Eq Diagram
+ DataFlow.Core: instance Show Diagram
+ DataFlow.Reader: readDiagram :: String -> String -> Either ParseError Diagram
+ DataFlow.Reader: readDiagramFile :: FilePath -> IO (Either ParseError Diagram)

Files

README.md view
@@ -5,9 +5,7 @@ ## Getting Started  ```-cabal sandbox init-cabal configure --enable-tests-cabal install --only-dependencies --enable-tests+cabal install dataflow@0.6.0.0 ```  ## Usage@@ -16,60 +14,60 @@  The objects supported by DataFlow is: -* `TrustBoundary`-* `InputOutput`-* `Function`-* `Database`-* `Flow`--These are composed in a `Diagram` to get something printable.+* `boundary`+* `io`+* `function`+* `database`+* `->` -For more on Haskell data types, see [the Hackage site](https://hackage.haskell.org/package/dataflow).+These are composed in a `diagram` to get something printable.  ## Example -```haskell-module Main where--import DataFlow.Core-import DataFlow.Graphviz.Renderer-import DataFlow.DFD--main :: IO ()-main = putStr $ renderGraphviz $ asDFD  $-  Diagram (Just "Webapp") [-    TrustBoundary "browser" "Browser" [-      Function "client" "Client"-    ],-    TrustBoundary "aws" "Amazon AWS" [-      Function "server" "Web Server",-      Database "logs" "Logs"-    ],-    InputOutput "analytics" "Google Analytics",--    Flow "client" "server" "Request /" "",-    Flow "server" "logs" "Log" "User IP",-    Flow "server" "client" "Response" "User Profile",+```+diagram 'Webapp' {+  boundary 'Browser' {+    function client 'Client'+  }+  boundary 'Amazon AWS' {+    function server 'Web Server'+    database logs 'Logs'+  }+  io analytics 'Google<br/>Analytics' -    Flow "client" "analytics" "Log" "Page Navigation"-  ]+  client -> server 'Request /' ''+  server -> logs 'Log' 'User IP'+  server -> client 'Response' 'User Profile'+  client -> analytics 'Log' 'Page Navigation'+} ```  Then generate your output with dot.  ```bash-runhaskell example.hs | dot -Tsvg > example.svg+dataflow dfd webapp.flow | dot -Tsvg > webapp.svg ```  That should generate something like the following.  ![Example Output](https://rawgit.com/owickstrom/dataflow/master/examples/webapp.svg) +## Build++```+cabal sandbox init+cabal configure --enable-tests+cabal install --only-dependencies --enable-tests+```+ ## Building the Examples  ```bash make -C examples ```+## Haskell Docs++See [the Hackage site](https://hackage.haskell.org/package/dataflow).  ## Release 
+ cli/Main.hs view
@@ -0,0 +1,26 @@+module Main where++import System.Environment+import DataFlow.Core+import DataFlow.Reader+import DataFlow.DFD+import DataFlow.Graphviz.Renderer++data Command = DFD | Lint++usage :: String+usage = "Usage: dataflow (dfd|lint) FILE"++dfd :: FilePath -> IO ()+dfd path = do+  res <- readDiagramFile path+  case res of+    (Left err) -> print err+    (Right diagram) -> putStr $ renderGraphviz $ asDFD diagram++main :: IO ()+main = do+  args <- getArgs+  case args of+    ["dfd", path] -> dfd path+    _ -> fail usage
dataflow.cabal view
@@ -1,5 +1,5 @@ name:                dataflow-version:             0.5.4.0+version:             0.6.0.0 synopsis:            Generate Graphviz documents from a Haskell representation. description:         Outputs .dot files that can be processed by the dot                      command. Currently it only supports the DFD output format@@ -17,9 +17,9 @@ build-type:          Simple extra-source-files:  README.md,                      LICENSE,-                     examples/webapp.hs,+                     examples/webapp.flow,                      examples/webapp.svg,-                     examples/legend.hs,+                     examples/legend.flow,                      examples/legend.svg,                      examples/Makefile cabal-version:       >=1.10@@ -31,6 +31,7 @@ library   exposed-modules:     DataFlow.Core,+    DataFlow.Reader,     DataFlow.Graphviz,     DataFlow.Graphviz.EdgeNormalization,     DataFlow.Graphviz.Renderer,@@ -38,8 +39,17 @@   build-depends:     base >=4 && <4.8,     mtl >=2.2,-    containers >= 0.4+    containers >= 0.4,+    parsec   hs-source-dirs:      src+  default-language:    Haskell2010++executable dataflow+  main-is: Main.hs+  build-depends:+    base >=4 && <4.8,+    dataflow+  hs-source-dirs:      cli   default-language:    Haskell2010  test-suite spec
examples/Makefile view
@@ -1,9 +1,13 @@-SOURCES=$(shell find *.hs)-TARGETS=$(SOURCES:%.hs=%.svg)+SOURCES=$(shell find *.flow)+TARGETS=$(SOURCES:%.flow=%.svg)+DATAFLOW=../dist/build/DataFlow/dataflow -%.svg: %.hs+$(DATAFLOW):+	cd .. && cabal build++%.svg: %.flow $(DATAFLOW) 	@echo "$< -> $@"-	@runhaskell -i../src $< | dot -Tsvg > $@+	@$(DATAFLOW) dfd $< | dot -Nfontname=Courier -Efontname=Courier -Tsvg > $@  svg: $(TARGETS) 
+ examples/legend.flow view
@@ -0,0 +1,11 @@+diagram '' {+  boundary 'boundary' {+    function f 'function'+    database d 'database'+    io i 'io'+  }++  f -> d 'Data' 'Description'+  i -> f '' 'Description'+  f -> i 'Data' ''+}
− examples/legend.hs
@@ -1,19 +0,0 @@-module Main where--import DataFlow.Core-import DataFlow.Graphviz.Renderer-import DataFlow.DFD--main :: IO ()-main = putStr $ renderGraphviz $ asDFD $-  Diagram Nothing [-    TrustBoundary "trust" "TrustBoundary" [-      Function "function" "Function",-      Database "database" "Database",-      InputOutput "io" "InputOutput"-    ],-    Flow "function" "io" "Flow" "",-    Flow "io" "function" "Flow" "(backwards)",-    Flow "function" "database" "Flow" ""-  ]-
examples/legend.svg view
@@ -3,53 +3,52 @@  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <!-- Generated by graphviz version 2.38.0 (20140413.2041)  -->-<!-- Title: Untitled Pages: 1 -->-<svg width="406pt" height="308pt"- viewBox="0.00 0.00 406.00 308.32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 304.316)">-<title>Untitled</title>-<polygon fill="white" stroke="none" points="-4,4 -4,-304.316 402,-304.316 402,4 -4,4"/>-<g id="clust1" class="cluster"><title>cluster_trust</title>-<polygon fill="none" stroke="#595959" stroke-dasharray="5,2" points="8,-8 8,-292.316 390,-292.316 390,-8 8,-8"/>-<text text-anchor="start" x="166.393" y="-281.316" font-family="Arial" font-style="italic" font-size="10.00" fill="#595959">TrustBoundary</text>+<!-- Pages: 1 -->+<svg width="313pt" height="357pt"+ viewBox="0.00 0.00 313.00 356.62" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 352.624)">+<polygon fill="white" stroke="none" points="-4,4 -4,-352.624 309,-352.624 309,4 -4,4"/>+<g id="clust1" class="cluster"><title>cluster_boundary</title>+<polygon fill="none" stroke="#595959" stroke-dasharray="5,2" points="8,-8 8,-340.624 297,-340.624 297,-8 8,-8"/>+<text text-anchor="start" x="131.65" y="-329.624" font-family="Arial" font-style="italic" font-size="10.00" fill="#595959">boundary</text> </g>-<!-- function -->-<g id="node1" class="node"><title>function</title>-<ellipse fill="none" stroke="black" cx="208" cy="-217.908" rx="46.8172" ry="46.8172"/>-<text text-anchor="start" x="181.152" y="-215.758" font-family="Arial" font-weight="bold" font-size="14.00">Function</text>+<!-- f -->+<g id="node1" class="node"><title>f</title>+<ellipse fill="none" stroke="black" cx="155" cy="-166.562" rx="52.6248" ry="52.6248"/>+<text text-anchor="start" x="121.395" y="-163.362" font-family="Courier,monospace" font-weight="bold" font-size="14.00">function</text> </g>-<!-- database -->-<g id="node2" class="node"><title>database</title>-<text text-anchor="start" x="58.5347" y="-62.3" font-family="Arial" font-weight="bold" font-size="14.00">Database</text>-<polyline fill="none" stroke="black" points="53.5,-51.5 122.5,-51.5 "/>-<polyline fill="none" stroke="black" points="122.5,-77.5 53.5,-77.5 "/>+<!-- i -->+<g id="node3" class="node"><title>i</title>+<polygon fill="none" stroke="black" stroke-width="2" points="179,-56 139,-56 139,-16 179,-16 179,-56"/>+<text text-anchor="start" x="150.599" y="-32.8" font-family="Courier,monospace" font-weight="bold" font-size="14.00">io</text> </g>-<!-- function&#45;&gt;database -->-<g id="edge3" class="edge"><title>function&#45;&gt;database</title>-<path fill="none" stroke="black" d="M169.293,-191.395C155.216,-180.751 139.998,-167.488 128.664,-153 114.295,-134.632 103.528,-110.364 96.6951,-92.0459"/>-<polygon fill="black" stroke="black" points="99.9655,-90.7966 93.3059,-82.5564 93.3733,-93.151 99.9655,-90.7966"/>-<text text-anchor="start" x="129" y="-140.299" font-family="Arial" font-weight="bold" font-size="12.00" fill="#3184e4">(3) </text>-<text text-anchor="start" x="147" y="-140.299" font-family="Arial" font-weight="bold" font-size="12.00">Flow</text>+<!-- f&#45;&gt;i -->+<g id="edge2" class="edge"><title>f&#45;&gt;i</title>+<path fill="none" stroke="black" d="M109.247,-140.496C83.3903,-122.922 59.1313,-98.3119 74.9893,-74 86.8169,-55.8669 109.748,-46.5597 128.668,-41.8175"/>+<polygon fill="black" stroke="black" points="129.651,-45.1851 138.67,-39.6256 128.153,-38.3474 129.651,-45.1851"/>+<text text-anchor="start" x="92.603" y="-87.4" font-family="Courier,monospace" font-weight="bold" font-size="12.00" fill="#3184e4">(2) </text>+<text text-anchor="start" x="74" y="-77" font-family="Courier,monospace" font-size="10.00">Description</text> </g>-<!-- io -->-<g id="node3" class="node"><title>io</title>-<polygon fill="none" stroke="black" stroke-width="2" points="337.5,-113 240.5,-113 240.5,-16 337.5,-16 337.5,-113"/>-<text text-anchor="start" x="252.917" y="-62.3" font-family="Arial" font-weight="bold" font-size="14.00">InputOutput</text>+<!-- f&#45;&gt;i -->+<g id="edge3" class="edge"><title>f&#45;&gt;i</title>+<path fill="none" stroke="black" d="M156.92,-103.866C157.459,-86.521 158.007,-68.9241 158.405,-56.1386"/>+<polygon fill="black" stroke="black" points="153.417,-103.908 156.604,-114.012 160.413,-104.126 153.417,-103.908"/>+<text text-anchor="start" x="157" y="-82.4" font-family="Courier,monospace" font-weight="bold" font-size="12.00" fill="#3184e4">(3) </text>+<text text-anchor="start" x="185.805" y="-82.4" font-family="Courier,monospace" font-weight="bold" font-size="12.00">Data</text> </g>-<!-- function&#45;&gt;io -->-<g id="edge1" class="edge"><title>function&#45;&gt;io</title>-<path fill="none" stroke="black" d="M191.196,-174.107C188.156,-159.768 187.808,-144.107 194.664,-131 202.93,-115.197 216.936,-102.441 231.662,-92.5323"/>-<polygon fill="black" stroke="black" points="233.794,-95.3258 240.378,-87.0254 230.054,-89.408 233.794,-95.3258"/>-<text text-anchor="start" x="195" y="-140.299" font-family="Arial" font-weight="bold" font-size="12.00" fill="#3184e4">(1) </text>-<text text-anchor="start" x="213" y="-140.299" font-family="Arial" font-weight="bold" font-size="12.00">Flow</text>+<!-- d -->+<g id="node2" class="node"><title>d</title>+<text text-anchor="start" x="121.895" y="-291.925" font-family="Courier,monospace" font-weight="bold" font-size="14.00">database</text>+<polyline fill="none" stroke="black" points="116.5,-283.125 193.5,-283.125 "/>+<polyline fill="none" stroke="black" points="193.5,-307.125 116.5,-307.125 "/> </g>-<!-- function&#45;&gt;io -->-<g id="edge2" class="edge"><title>function&#45;&gt;io</title>-<path fill="none" stroke="black" d="M241.242,-170.972C245.053,-165.037 248.737,-158.952 252,-153 258.898,-140.418 265.381,-126.282 270.934,-113.101"/>-<polygon fill="black" stroke="black" points="238.183,-169.252 235.599,-179.527 244.027,-173.106 238.183,-169.252"/>-<text text-anchor="start" x="267.561" y="-144.4" font-family="Arial" font-weight="bold" font-size="12.00" fill="#3184e4">(2) </text>-<text text-anchor="start" x="285.561" y="-144.4" font-family="Arial" font-weight="bold" font-size="12.00">Flow</text>-<text text-anchor="start" x="262" y="-134" font-family="Arial" font-size="10.00">(backwards)</text>+<!-- d&#45;&gt;f -->+<g id="edge1" class="edge"><title>d&#45;&gt;f</title>+<path fill="none" stroke="black" d="M155,-277.056C155,-264.647 155,-247.026 155,-229.538"/>+<polygon fill="black" stroke="black" points="158.5,-229.297 155,-219.297 151.5,-229.297 158.5,-229.297"/>+<text text-anchor="start" x="159.201" y="-250.525" font-family="Courier,monospace" font-weight="bold" font-size="12.00" fill="#3184e4">(1) </text>+<text text-anchor="start" x="188.005" y="-250.525" font-family="Courier,monospace" font-weight="bold" font-size="12.00">Data</text>+<text text-anchor="start" x="155" y="-240.125" font-family="Courier,monospace" font-size="10.00">Description</text> </g> </g> </svg>
+ examples/webapp.flow view
@@ -0,0 +1,15 @@+diagram 'Webapp' {+  boundary 'Browser' {+    function client 'Client'+  }+  boundary 'Amazon AWS' {+    function server 'Web Server'+    database logs 'Logs'+  }+  io analytics 'Google<br/>Analytics'++  client -> server 'Request /' ''+  server -> logs 'Log' 'User IP'+  server -> client 'Response' 'User Profile'+  analytics <- client 'Log' 'Page Navigation'+}
− examples/webapp.hs
@@ -1,24 +0,0 @@-module Main where--import DataFlow.Core-import DataFlow.Graphviz.Renderer-import DataFlow.DFD--main :: IO ()-main = putStr $ renderGraphviz $ asDFD  $-  Diagram (Just "Webapp") [-    TrustBoundary "browser" "Browser" [-      Function "client" "Client"-    ],-    TrustBoundary "aws" "Amazon AWS" [-      Function "server" "Web Server",-      Database "logs" "Logs"-    ],-    InputOutput "analytics" "Google<br/>Analytics",--    Flow "client" "server" "Request /" "",-    Flow "server" "logs" "Log" "User IP",-    Flow "server" "client" "Response" "User Profile",--    Flow "client" "analytics" "Log" "Page Navigation"-  ]
examples/webapp.svg view
@@ -4,72 +4,72 @@ <!-- Generated by graphviz version 2.38.0 (20140413.2041)  --> <!-- Title: Webapp Pages: 1 -->-<svg width="364pt" height="450pt"- viewBox="0.00 0.00 364.30 450.40" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 446.4)">+<svg width="410pt" height="470pt"+ viewBox="0.00 0.00 409.97 470.25" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 466.246)"> <title>Webapp</title>-<polygon fill="white" stroke="none" points="-4,4 -4,-446.4 360.298,-446.4 360.298,4 -4,4"/>-<text text-anchor="start" x="141.084" y="-423.4" font-family="Arial" font-weight="bold" font-size="20.00">Webapp</text>+<polygon fill="white" stroke="none" points="-4,4 -4,-466.246 405.972,-466.246 405.972,4 -4,4"/>+<text text-anchor="start" x="163.92" y="-443.246" font-family="Arial" font-weight="bold" font-size="20.00">Webapp</text> <g id="clust1" class="cluster"><title>cluster_browser</title>-<polygon fill="none" stroke="#595959" stroke-dasharray="5,2" points="124.298,-298.185 124.298,-403.402 210.298,-403.402 210.298,-298.185 124.298,-298.185"/>-<text text-anchor="start" x="148.961" y="-392.402" font-family="Arial" font-style="italic" font-size="10.00" fill="#595959">Browser</text>+<polygon fill="none" stroke="#595959" stroke-dasharray="5,2" points="139.472,-8 139.472,-127.396 239.472,-127.396 239.472,-8 139.472,-8"/>+<text text-anchor="start" x="171.134" y="-116.396" font-family="Arial" font-style="italic" font-size="10.00" fill="#595959">Browser</text> </g>-<g id="clust2" class="cluster"><title>cluster_aws</title>-<polygon fill="none" stroke="#595959" stroke-dasharray="5,2" points="75.2982,-8 75.2982,-258.185 211.298,-258.185 211.298,-8 75.2982,-8"/>-<text text-anchor="start" x="112.639" y="-247.185" font-family="Arial" font-style="italic" font-size="10.00" fill="#595959">Amazon AWS</text>+<g id="clust2" class="cluster"><title>cluster_amazonaws</title>+<polygon fill="none" stroke="#595959" stroke-dasharray="5,2" points="22.4718,-167.396 22.4718,-423.248 164.472,-423.248 164.472,-167.396 22.4718,-167.396"/>+<text text-anchor="start" x="62.8126" y="-412.248" font-family="Arial" font-style="italic" font-size="10.00" fill="#595959">Amazon AWS</text> </g> <!-- client --> <g id="node1" class="node"><title>client</title>-<ellipse fill="none" stroke="black" cx="167.298" cy="-341.044" rx="34.7182" ry="34.7182"/>-<text text-anchor="start" x="149.402" y="-338.893" font-family="Arial" font-weight="bold" font-size="14.00">Client</text>+<ellipse fill="none" stroke="black" cx="189.472" cy="-57.9485" rx="41.897" ry="41.897"/>+<text text-anchor="start" x="164.268" y="-54.7485" font-family="Courier,monospace" font-weight="bold" font-size="14.00">Client</text> </g> <!-- server --> <g id="node2" class="node"><title>server</title>-<ellipse fill="none" stroke="black" cx="143.298" cy="-170.343" rx="60.1865" ry="60.1865"/>-<text text-anchor="start" x="106.47" y="-168.192" font-family="Arial" font-weight="bold" font-size="14.00">Web Server</text>-</g>-<!-- client&#45;&gt;server -->-<g id="edge1" class="edge"><title>client&#45;&gt;server</title>-<path fill="none" stroke="black" d="M132.239,-339.791C94.5448,-337.407 36.2297,-327.148 7.93494,-288.185 -19.1714,-250.859 30.7957,-217.498 77.4951,-196.076"/>-<polygon fill="black" stroke="black" points="79.0523,-199.214 86.7676,-191.953 76.2082,-192.817 79.0523,-199.214"/>-<text text-anchor="start" x="8.29822" y="-275.484" font-family="Arial" font-weight="bold" font-size="12.00" fill="#3184e4">(1) </text>-<text text-anchor="start" x="26.2982" y="-275.484" font-family="Arial" font-weight="bold" font-size="12.00">Request /</text>-</g>-<!-- client&#45;&gt;server -->-<g id="edge3" class="edge"><title>client&#45;&gt;server</title>-<path fill="none" stroke="black" d="M156.033,-297.404C155.38,-294.295 154.78,-291.199 154.263,-288.185 151.076,-269.61 148.761,-249.204 147.103,-230.715"/>-<polygon fill="black" stroke="black" points="152.647,-298.299 158.261,-307.284 159.475,-296.759 152.647,-298.299"/>-<text text-anchor="start" x="154.298" y="-279.585" font-family="Arial" font-weight="bold" font-size="12.00" fill="#3184e4">(3) </text>-<text text-anchor="start" x="172.298" y="-279.585" font-family="Arial" font-weight="bold" font-size="12.00">Response</text>-<text text-anchor="start" x="164.198" y="-269.185" font-family="Arial" font-size="10.00">User Profile</text>+<ellipse fill="none" stroke="black" cx="93.4718" cy="-238.572" rx="63.353" ry="63.353"/>+<text text-anchor="start" x="51.4649" y="-235.372" font-family="Courier,monospace" font-weight="bold" font-size="14.00">Web Server</text> </g>-<!-- analytics -->-<g id="node4" class="node"><title>analytics</title>-<polygon fill="none" stroke="black" stroke-width="2" points="356.298,-210.343 276.298,-210.343 276.298,-130.343 356.298,-130.343 356.298,-210.343"/>-<text text-anchor="start" x="293.726" y="-174.143" font-family="Arial" font-weight="bold" font-size="14.00">Google</text>-<text text-anchor="start" x="288.288" y="-160.143" font-family="Arial" font-weight="bold" font-size="14.00">Analytics</text>+<!-- server&#45;&gt;client -->+<g id="edge1" class="edge"><title>server&#45;&gt;client</title>+<path fill="none" stroke="black" d="M38.7491,-206.273C12.0359,-186.823 -11.0623,-160.767 5.85655,-135.396 34.9435,-91.7784 94.114,-73.0083 137.453,-64.9548"/>+<polygon fill="black" stroke="black" points="138.286,-68.363 147.548,-63.2173 137.099,-61.4645 138.286,-68.363"/>+<text text-anchor="start" x="6.47178" y="-143.796" font-family="Courier,monospace" font-weight="bold" font-size="12.00" fill="#3184e4">(1) </text>+<text text-anchor="start" x="35.2765" y="-143.796" font-family="Courier,monospace" font-weight="bold" font-size="12.00">Request /</text> </g>-<!-- client&#45;&gt;analytics -->-<g id="edge4" class="edge"><title>client&#45;&gt;analytics</title>-<path fill="none" stroke="black" d="M196.993,-322.619C211.093,-313.472 227.595,-301.419 240.298,-288.185 259.899,-267.764 277.455,-241.61 290.743,-219.226"/>-<polygon fill="black" stroke="black" points="293.797,-220.937 295.803,-210.534 287.747,-217.415 293.797,-220.937"/>-<text text-anchor="start" x="275.979" y="-279.585" font-family="Arial" font-weight="bold" font-size="12.00" fill="#3184e4">(4) </text>-<text text-anchor="start" x="293.979" y="-279.585" font-family="Arial" font-weight="bold" font-size="12.00">Log</text>-<text text-anchor="start" x="258.298" y="-269.185" font-family="Arial" font-size="10.00">Page Navigation</text>+<!-- server&#45;&gt;client -->+<g id="edge3" class="edge"><title>server&#45;&gt;client</title>+<path fill="none" stroke="black" d="M127.976,-173.372C142.103,-147.086 157.928,-117.641 169.986,-95.2041"/>+<polygon fill="black" stroke="black" points="124.709,-172.056 123.058,-182.522 130.875,-175.37 124.709,-172.056"/>+<text text-anchor="start" x="147.472" y="-148.796" font-family="Courier,monospace" font-weight="bold" font-size="12.00" fill="#3184e4">(3) </text>+<text text-anchor="start" x="176.276" y="-148.796" font-family="Courier,monospace" font-weight="bold" font-size="12.00">Response</text>+<text text-anchor="start" x="154.673" y="-138.396" font-family="Courier,monospace" font-size="10.00">User Profile</text> </g> <!-- logs --> <g id="node3" class="node"><title>logs</title>-<text text-anchor="start" x="140.119" y="-31.8" font-family="Arial" font-weight="bold" font-size="14.00">Logs</text>-<polyline fill="none" stroke="black" points="135.298,-21 175.298,-21 "/>-<polyline fill="none" stroke="black" points="175.298,-47 135.298,-47 "/>+<text text-anchor="start" x="86.169" y="-374.548" font-family="Courier,monospace" font-weight="bold" font-size="14.00">Logs</text>+<polyline fill="none" stroke="black" points="80.9718,-365.748 123.972,-365.748 "/>+<polyline fill="none" stroke="black" points="123.972,-389.748 80.9718,-389.748 "/> </g>-<!-- server&#45;&gt;logs -->-<g id="edge2" class="edge"><title>server&#45;&gt;logs</title>-<path fill="none" stroke="black" d="M148.597,-110.027C150.083,-93.3881 151.627,-76.0972 152.858,-62.3138"/>-<polygon fill="black" stroke="black" points="156.368,-62.3631 153.772,-52.0913 149.396,-61.7403 156.368,-62.3631"/>-<text text-anchor="start" x="152.298" y="-83.4" font-family="Arial" font-weight="bold" font-size="12.00" fill="#3184e4">(2) </text>-<text text-anchor="start" x="170.298" y="-83.4" font-family="Arial" font-weight="bold" font-size="12.00">Log</text>-<text text-anchor="start" x="154.639" y="-73" font-family="Arial" font-size="10.00">User IP</text>+<!-- logs&#45;&gt;server -->+<g id="edge2" class="edge"><title>logs&#45;&gt;server</title>+<path fill="none" stroke="black" d="M101.35,-359.652C100.547,-347.405 99.4043,-329.994 98.2381,-312.219"/>+<polygon fill="black" stroke="black" points="101.698,-311.497 97.5511,-301.748 94.7134,-311.956 101.698,-311.497"/>+<text text-anchor="start" x="100.472" y="-333.148" font-family="Courier,monospace" font-weight="bold" font-size="12.00" fill="#3184e4">(2) </text>+<text text-anchor="start" x="129.276" y="-333.148" font-family="Courier,monospace" font-weight="bold" font-size="12.00">Log</text>+<text text-anchor="start" x="104.672" y="-322.748" font-family="Courier,monospace" font-size="10.00">User IP</text>+</g>+<!-- analytics -->+<g id="node4" class="node"><title>analytics</title>+<polygon fill="none" stroke="black" stroke-width="2" points="401.972,-288.072 302.972,-288.072 302.972,-189.072 401.972,-189.072 401.972,-288.072"/>+<text text-anchor="start" x="327.768" y="-242.372" font-family="Courier,monospace" font-weight="bold" font-size="14.00">Google</text>+<text text-anchor="start" x="315.166" y="-228.372" font-family="Courier,monospace" font-weight="bold" font-size="14.00">Analytics</text>+</g>+<!-- analytics&#45;&gt;client -->+<g id="edge4" class="edge"><title>analytics&#45;&gt;client</title>+<path fill="none" stroke="black" d="M307.931,-188.763C281.593,-159.9 248.722,-123.878 224.292,-97.1064"/>+<polygon fill="black" stroke="black" points="226.645,-94.4922 217.319,-89.4647 221.474,-99.2107 226.645,-94.4922"/>+<text text-anchor="start" x="296.275" y="-148.796" font-family="Courier,monospace" font-weight="bold" font-size="12.00" fill="#3184e4">(4) </text>+<text text-anchor="start" x="325.08" y="-148.796" font-family="Courier,monospace" font-weight="bold" font-size="12.00">Log</text>+<text text-anchor="start" x="276.472" y="-138.396" font-family="Courier,monospace" font-size="10.00">Page Navigation</text> </g> </g> </svg>
src/DataFlow/Core.hs view
@@ -17,7 +17,7 @@ type Description = String  -- | The top level diagram.-data Diagram = Diagram (Maybe Name) [Object]+data Diagram = Diagram (Maybe Name) [Object] deriving (Eq, Show)  -- | An object in a diagram. data Object =
+ src/DataFlow/Reader.hs view
@@ -0,0 +1,131 @@+module DataFlow.Reader (readDiagram, readDiagramFile) where++import Text.ParserCombinators.Parsec+import Data.Char+import DataFlow.Core++nameToID :: String -> String+nameToID = filter isLetter . map toLower++identifier :: Parser ID+identifier = do+  first <- letter+  rest <-  many (letter <|> digit <|> char '_')+  return $ first : rest++quoted :: Parser ID+quoted = do+  -- TODO: Handle escaped characters.+  _ <- char '\''+  s <- many (noneOf "'")+  _ <- char '\''+  return s++skipWhitespace :: Parser ()+skipWhitespace = skipMany $ space <|> newline++skipWhitespace1 :: Parser ()+skipWhitespace1 = skipMany $ space <|> newline++inBraces :: Parser t -> Parser t+inBraces inside = do+  skipWhitespace+  _ <- char '{'+  skipWhitespace+  c <- inside+  skipWhitespace+  _ <- char '}'+  skipWhitespace+  return c++idAndNameObject :: String -> (ID -> ID -> t) -> Parser t+idAndNameObject keyword f = do+  _ <- string keyword+  skipMany1 space+  id' <- identifier+  skipMany1 space+  name <- quoted+  skipWhitespace1+  return $ f id' name++function :: Parser Object+function = idAndNameObject "function" Function++database :: Parser Object+database = idAndNameObject "database" Database++io :: Parser Object+io = idAndNameObject "io" InputOutput++data FlowType = Back | Forward++arrow :: Parser FlowType+arrow = do+  s <- string "->" <|> string "--" <|> string "<-"+  case s of+    "->" -> return Forward+    "<-" -> return Back+    _ -> fail "Invalid flow statement"++flow :: Parser Object+flow = do+  i1 <- identifier+  skipMany1 space+  a <- arrow+  skipMany1 space+  i2 <- identifier+  skipMany1 space+  data' <- quoted+  skipMany1 space+  desc <- quoted+  skipWhitespace1+  case a of+    Back -> return $ Flow i2 i1 data' desc+    Forward -> return $ Flow i1 i2 data' desc++boundary :: Parser Object+boundary = do+  _ <- string "boundary"+  skipMany1 space+  name <- quoted+  let id' = nameToID name+  skipMany1 space+  objs <- inBraces objects+  skipWhitespace1+  return $ TrustBoundary id' name objs++object :: Parser Object+object =+  try boundary+  <|> try function+  <|> try database+  <|> try io+  <|> flow++objects :: Parser [Object]+objects = object `sepBy` many (space <|> newline)++namedDiagram :: Parser Diagram+namedDiagram = do+  _ <- string "diagram"+  skipMany1 space+  name <- quoted+  skipMany1 space+  objs <- inBraces objects+  return $ Diagram (Just name) objs++unnamedDiagram :: Parser Diagram+unnamedDiagram = do+  _ <- string "diagram"+  skipMany1 space+  objs <- inBraces objects+  return $ Diagram Nothing objs++diagram :: Parser Diagram+diagram = try unnamedDiagram <|> namedDiagram++readDiagram :: String -> String ->  Either ParseError Diagram+readDiagram = parse diagram++readDiagramFile :: FilePath -> IO (Either ParseError Diagram)+readDiagramFile = parseFromFile diagram