{"id":28402677,"url":"https://github.com/daveray/dorothy","last_synced_at":"2025-10-11T09:08:12.213Z","repository":{"id":55627619,"uuid":"2189008","full_name":"daveray/dorothy","owner":"daveray","description":"Hiccup-style generation of Graphviz graphs in Clojure","archived":false,"fork":false,"pushed_at":"2020-12-17T04:11:51.000Z","size":81,"stargazers_count":248,"open_issues_count":7,"forks_count":25,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-09-05T11:58:45.611Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/daveray.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-08-11T03:24:05.000Z","updated_at":"2025-05-30T18:28:38.000Z","dependencies_parsed_at":"2022-08-15T04:50:37.189Z","dependency_job_id":null,"html_url":"https://github.com/daveray/dorothy","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/daveray/dorothy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daveray%2Fdorothy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daveray%2Fdorothy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daveray%2Fdorothy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daveray%2Fdorothy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/daveray","download_url":"https://codeload.github.com/daveray/dorothy/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daveray%2Fdorothy/sbom","scorecard":{"id":325611,"data":{"date":"2025-08-11","repo":{"name":"github.com/daveray/dorothy","commit":"207570804dfda2162a15b9ee55b5e76ec6e1ecfa"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Code-Review","score":3,"reason":"Found 7/20 approved changesets -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 17 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-18T02:25:42.761Z","repository_id":55627619,"created_at":"2025-08-18T02:25:42.761Z","updated_at":"2025-08-18T02:25:42.761Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279006755,"owners_count":26084176,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-01T15:38:29.607Z","updated_at":"2025-10-11T09:08:12.180Z","avatar_url":"https://github.com/daveray.png","language":"Clojure","funding_links":[],"categories":["Graphviz"],"sub_categories":[],"readme":"# dorothy   [![Travis CI status](https://secure.travis-ci.org/daveray/dorothy.png)](http://travis-ci.org/#!/daveray/dorothy/builds)\n\n[Hiccup-style](https://github.com/weavejester/hiccup) generation of\n[Graphviz](http://www.graphviz.org/) graphs in Clojure and ClojureScript.\n\n*Dorothy is extremely alpha and subject to radical change. [Release Notes Here](https://github.com/daveray/dorothy/wiki)*\n\n## Usage\n\n*Dorothy assumes you have an understanding of Graphviz and DOT. The text below describes the mechanics of Dorothy's DSL, but you'll need to refer to the Graphviz documentation for specifics on node shapes, valid attributes, etc.*\n\n*The Graphviz dot tool executable must be on the system path to render*\n\nDorothy is on Clojars. In Leiningen:\n\n    [dorothy \"x.y.z\"]\n\nA graph consists of a vector of *statements*. The following sections describe the format for all the types of statements. If you're bored, skip ahead to the \"Defining Graphs\" section below.\n\n### Node Statement\nA *node statement* defines a node in the graph. It can take two forms:\n\n    node-id\n\n    [node-id]\n\n    [node-id { attr map }]\n\nwhere `node-id` is a string, number or keyword with optional trailing *port* and *compass-point*. Here are some node statement examples:\n\n    :node0          ; Define a node called \"node0\"\n\n    :node0:port0    ; Define a node called \"node0\" with port \"port0\"\n\n    :node0:port0:sw ; Similarly a node with southwest compass point\n\nthe node's attr map is a map of attributes for the node. For example,\n\n    [:start {:shape :Mdiamond}]\n    ; =\u003e start [shape=Mdiamond];\n\nDorothy will correctly escape and quote node-ids as required by dot.\n\nA node id can also be auto-generated with `(gen-id object)`. For example,\n\n    [(gen-id some-object) {:label (.getText some-object)}]\n\nIt allows you to use arbitrary objects as nodes.\n\n### Edge Statement\nAn *edge statement* defines an edge in the graph. It is expressed as a vector with two or more node-ids followed optional attribute map:\n\n    [node-id0 node-id1 ... node-idN { attr map }]\n    ; =\u003e \"node-id0\" -\u003e \"node-id1\" -\u003e ... -\u003e \"node-idN\" [attrs ...];\n\nIn addition to node ids, an edge statement may also contain subgraphs:\n\n    [:start (subgraph [... subgraph statements ...])]\n\nFor readability, `:\u003e` delimiters may be optionally included in an edge statement:\n\n    [:start :\u003e :middle :\u003e :end]\n\n### Graph Attribute Statement\n\nA *graph attribute* statement sets graph-wide attributes. It is expressed as a single map:\n\n    {:label \"process #1\", :style :filled, :color :lightgrey}\n    ; =\u003e graph [label=\"process #1\",style=filled,color=lightgrey];\n\nalternatively, this can be expressed with the `(graph-attrs)` function like this:\n\n    (graph-attrs {:label \"process #1\", :style :filled, :color :lightgrey})\n    ; =\u003e graph [label=\"process #1\",style=filled,color=lightgrey];\n\n### Node and Edge Attribute Statement\nA *node attribute* or *edge attribute* statement sets node or edge attributes respectively for all nodes and edge statements that follow. It is expressed with `(node-attrs)` and `(edge-attrs)` statements:\n\n    (node-attrs {:style :filled, :color :white})\n    ; =\u003e node [style=filled,color=white];\n\nor:\n\n    (edge-attrs {:color :black})\n    ; =\u003e edge [color=black];\n\n\n## Defining Graphs\nAs mentioned above, a graph consists of a series of statements. These statements are passed to the `graph`, `digraph`, or `subgraph` functions. Each takes an optional set of attributes followed by a vector of statements:\n\n\u003cimg src=\"https://github.com/downloads/daveray/dorothy/dorothy-show2.png\" align=\"right\"/\u003e\n\n    ; From http://www.graphviz.org/content/cluster\n    (digraph [\n      (subgraph :cluster_0 [\n        {:style :filled, :color :lightgrey, :label \"process #1\"}\n        (node-attrs {:style :filled, :color :white})\n\n        [:a0 :\u003e :a1 :\u003e :a2 :\u003e :a3]])\n\n      (subgraph :cluster_1 [\n        {:color :blue, :label \"process #2\"}\n        (node-attrs {:style :filled})\n\n        [:b0 :\u003e :b1 :\u003e :b2 :\u003e :b3]])\n\n      [:start :a0]\n      [:start :b0]\n      [:a1    :b3]\n      [:b2    :a3]\n      [:a3    :a0]\n      [:a3    :end]\n      [:b3    :end]\n\n      [:start {:shape :Mdiamond}]\n      [:end   {:shape :Msquare}]])\n\n\nSimilarly for `(graph)` (undirected graph) and `(subgraph)`. A second form of these functions takes an initial option map, or a string or keyword id for the graph:\n\n    (graph :graph-id ...)\n    ; =\u003e graph \"graph-id\" { ... }\n\n    (digraph { :id :G :strict? true } ...)\n    ; =\u003e strict graph G { ... }\n\n## Generate Graphviz dot format\n\nGiven a graph built with the functions described above, use the `(dot)` function to generate Graphviz DOT output.\n\n    (require '[dorothy.core :as dot])\n    (def g (dot/graph [ ... ]))\n    (dot/dot g)\n    \"graph { ... }\"\n\n## Rendering images (ClojureScript)\n\nDorothy currently doesn't include any facilities for rendering dot-format output to images. However,\nyou can pull in [viz.cljc](https://github.com/jebberjeb/viz.cljc) or\n[viz.js](https://github.com/mdaines/viz.js), both of which will allow you to produce\npng, svg, and other image formats from your dorothy-generated dot-formatted graph content.\n\nWanted: pull requests to implement node equivalents to the rendering functions available for Clojure/JVM\nin the `dorothy.jvm` namespace. **link to github issue here**\n\n## Render images via `graphviz` (Clojure/JVM)\n\nOnce you have DOT language output, you can render it as an image using the `(render)` function:\n\n    (require '[dorothy.jvm :refer (render save! show!)])\n\n    ; This produces a png as an array of bytes\n    (render graph {:format :png})\n\n    ; This produces an SVG string\n    (render graph {:format :svg})\n\n    ; A one-liner with a very simple 4 node digraph.\n    (-\u003e (dot/digraph [ [:a :b :c] [:b :d] ])\n        dot/dot\n        (render {:format :svg}))\n\n*The dot tool executable must be on the system path*\n\nother formats include `:pdf`, `:gif`, etc. The result will be either a java byte array, or String depending on whether the format is binary or not. `(render)` returns a string or a byte array depending on whether the output format is binary or not.\n\nAlternatively, use the `(save!)` function to write to a file or output stream.\n\n    ; A one-liner with a very simple 4 node digraph\n    (-\u003e (dot/digraph [ [:a :b :c] [:b :d] ])\n        dot/dot\n        (save! \"out.png\" {:format :png}))\n\nFinally, for simple tests, use the `(show!)` function to view the result in a simple Swing viewer:\n\n    ; This opens a simple Swing viewer with the graph\n    (show! graph)\n\n    ; A one-liner with a very simple 4 node digraph\n    (-\u003e (dot/digraph [ [:a :b :c] [:b :d] ])\n        dot/dot\n        show!)\n\nwhich shows:\n\n\u003cimg src=\"sample.png\"/\u003e\n\n\n## License\n\nCopyright (C) 2011-2017 Dave Ray and contributors\n\nDistributed under the Eclipse Public License, the same as Clojure.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaveray%2Fdorothy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdaveray%2Fdorothy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaveray%2Fdorothy/lists"}