{"id":16003112,"url":"https://github.com/antoine-coulon/digraph-js","last_synced_at":"2025-03-16T07:32:08.189Z","repository":{"id":57685832,"uuid":"461556963","full_name":"antoine-coulon/digraph-js","owner":"antoine-coulon","description":"JavaScript library to make Directed Acyclic Graph construction and traversal easy, including deep circular dependency detection ♽","archived":false,"fork":false,"pushed_at":"2023-07-21T08:41:34.000Z","size":463,"stargazers_count":50,"open_issues_count":1,"forks_count":3,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-03-16T00:01:52.924Z","etag":null,"topics":["graph","javascript","nodejs"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/antoine-coulon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-20T17:07:59.000Z","updated_at":"2025-03-01T13:30:01.000Z","dependencies_parsed_at":"2024-06-19T02:41:54.870Z","dependency_job_id":"c1da50f9-4fe6-4912-963b-11e94d357600","html_url":"https://github.com/antoine-coulon/digraph-js","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antoine-coulon%2Fdigraph-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antoine-coulon%2Fdigraph-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antoine-coulon%2Fdigraph-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antoine-coulon%2Fdigraph-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/antoine-coulon","download_url":"https://codeload.github.com/antoine-coulon/digraph-js/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243841137,"owners_count":20356441,"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","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":["graph","javascript","nodejs"],"created_at":"2024-10-08T10:06:22.765Z","updated_at":"2025-03-16T07:32:07.789Z","avatar_url":"https://github.com/antoine-coulon.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"  \u003cp align=\"center\"\u003e\n\t  \u003cimg alt=\"digraph-js\" src=\"https://user-images.githubusercontent.com/43391199/191079632-ffe879dd-0591-4c9d-aab8-375689130854.png\" width=\"350\"\u003e\n  \u003c/p\u003e\n\nMake Directed Graphs traversal and construction effortless, also includes deep circular dependency detection.\n\n**digraph-js** is a lightweight library allowing you to create a Directed Acyclic Graph data structure with embedded features such as deep cycle dependency detection and graph introspection (find deeply ancestors and successors for any given vertex).\nIt can be used to model complex dependencies systems based on graphs.\n\n✅ Create a graph structure including edges and vertices seamlessly\n\n✅ Traverse graph, using Depth-first or Breadth-first searchs\n\n✅ Deeply find direct/indirect children and parent dependencies of each vertex in the graph (top-to-bottom or bottom-to-top traversals)\n\n✅ Ensure that a given graph is Acyclic by deeply detecting circular dependencies while having the possibility to limit the search depth\n\n✅ Find precisely all vertices involved in cycles and sub-cycles\n\n## Installation\n\n```bash\n$ npm install digraph-js\n```\n\n## How to use it\n\n```js\nimport { DiGraph } from \"digraph-js\";\nimport assert from \"node:assert\";\n\nconst myGraph = new DiGraph();\n\nconst myDependencyA = { id: \"dependencyA\", adjacentTo: [], body: {} };\nconst myDependencyB = { id: \"dependencyB\", adjacentTo: [], body: {} };\nconst myDependencyC = { id: \"dependencyC\", adjacentTo: [], body: {} };\n\n// Add vertices to the graph\nmyGraph.addVertices(myDependencyA, myDependencyB, myDependencyC);\n\n// Link graph vertices: A ---\u003e B link created\nmyGraph.addEdge({ from: myDependencyA.id, to: myDependencyB.id });\n\n// Graph traversels\nmyGraph.addEdge({ from: myDependencyB.id, to: myDependencyC.id });\n// getDeepChildren traverses the graph in a Depth-First Search fashion\nconst deepDependenciesOfA = myGraph.getDeepChildren(\"dependencyA\");\n// deepDependenciesOfA is an iterable structure that can be lazily consumed\nassert.deepEqual([...deepDependenciesOfA], [\"dependencyB\", \"dependencyC\"]);\n\n// Here we voluntarily create a cyclic dependency\nmyGraph.addEdge({ from: myDependencyB.id, to: myDependencyA.id });\n// Detect if the Directed Graph is acyclic (Directed Acyclic Graph)\nassert.equal(myGraph.isAcyclic, false);\nassert.equal(myGraph.hasCycles(), true);\nassert.deepEqual(myGraph.findCycles().cycles, [[\"dependencyA\", \"dependencyB\"]]);\n\n// Limit cycles search or dependency depth\n// Imagine a case where the cycle is created at depth 6\nassert.equal(myGraph.hasCycles({ maxDepth: 5 }), false);\n// Or that you want to get all children of a vertex but with a max depth of 5\n// meaning that you don't want dependencies going over 5 generations\nassert.equal(myGraph.getDeepChildren(\"dependencyA\"), 5);\n\n\n// Traversals\n\n// Lazily pull vertices from the graph \nfor(const vertex of myGraph.traverse({ traversal: \"dfs\" })) {\n  console.log(vertex.id);\n}\n\n// Eagerly pull all the graph vertices at once\nconst graphVertices = myGraph.traverseEager({ traversal: \"dfs\" });\nconsole.log(graphVertices.length);\n```\n\n## You already manipulate Directed Graphs without knowing it\n\n  \u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2dwieqf30481m49trn6b.png\" alt=\"digraph\" /\u003e\n  \u003c/p\u003e\n\nTake for instance the image above with four Vertices each representing a\nJavaScript file.\n\nNow the question is: what are the **relationships** between these files? In all\nprogramming languages, one file might import one or multiple files. Whenever\na file imports another one, an implicit relationship is created.\n\n**_hello.js_**\n\n```js\nexport function sayHello() {}\n```\n\n**_main.js_**\n\n```js\nimport { sayHello } from \"hello.js\";\n```\n\nAs you can see above, **main.js** imports **hello.js** to use the `sayHello`\nfunction. The static import creates an implicit relationship between both files.\nIn the fields of graphs, this relationship can be modeled as a directed edge\nfrom **main.js** to **hello.js** (can be written as **main.js ---\u003e hello.js**)\nWe can also say that main.js **depends on** hello.js.\n\nWe can update the graph with our edges represented:\n\n  \u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://dev-to-uploads.s3.amazonaws.com/uploads/articles/31qbt7u1mhog516uqlwb.png\" alt=\"digraph\" /\u003e\n  \u003c/p\u003e\n\nBasically this graph says that:\n\n- FileA directly depends on FileD and FileB\n- FileA indirectly depends on FileC (through both FileD and FileB)\n- FileD directly depends on FileC\n- FileB directly depends on FileC\n- FileC directly depends on nothing\n\nThis structure may seem simple but can in fact be used to model very complex\nschemas such as:\n\n- **_Static dependencies analysis_** such as cycle dependencies detection\n  (e.g: [ESLint no-cycle plugin](https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-cycle.md))\n- **_Incremental/Affected tasks_** Bundlers/Monorepos tools make extensive use of it (e.g: [NX's affected build/test/lint...](https://nx.dev/using-nx/affected))\n- **_Task orchestration_** using a directed acyclic graph, parallel vs sequential\n  computations can be modeled (e.g: Continuous Integration schemas with stages, jobs, tasks)\n\n## Further exploring with examples which recreate common features:\n\n- [affected builds (NX alike)](https://github.com/antoine-coulon/digraph-js/tree/master/examples/affected-builds)\n- [detect cyclic imports (eslint-plugin-import alike)](https://github.com/antoine-coulon/digraph-js/tree/master/examples/circular-dependencies)\n- Sequential vs Parallel execution =\u003e Work in progress\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantoine-coulon%2Fdigraph-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fantoine-coulon%2Fdigraph-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantoine-coulon%2Fdigraph-js/lists"}