{"_id":"graph-cycles","_rev":"3290291","name":"graph-cycles","description":"Analyze a graph to find cyclic loops","dist-tags":{"latest":"3.0.0"},"maintainers":[{"name":"grantila","email":""}],"time":{"modified":"2024-05-23T06:48:22.000Z","created":"2021-04-01T23:11:49.072Z","3.0.0":"2023-02-02T21:47:38.411Z","2.0.1":"2021-12-18T09:08:15.313Z","2.0.0":"2021-09-13T07:37:17.080Z","1.2.1":"2021-04-11T09:47:00.295Z","1.2.0":"2021-04-11T09:26:58.035Z","1.1.0":"2021-04-01T23:14:18.066Z","1.0.0":"2021-04-01T23:11:49.072Z"},"users":{},"author":{"name":"Gustaf Räntilä"},"repository":{"type":"git","url":"git+https://github.com/grantila/graph-cycles.git"},"versions":{"3.0.0":{"name":"graph-cycles","version":"3.0.0","description":"Analyze a graph to find cyclic loops","author":{"name":"Gustaf Räntilä"},"license":"MIT","bugs":{"url":"https://github.com/grantila/graph-cycles/issues"},"homepage":"https://github.com/grantila/graph-cycles#readme","main":"./dist/index.js","exports":"./dist/index.js","types":"./dist/index.d.ts","type":"module","sideEffects":false,"engines":{"node":"^14.13.1 || >=16.0.0"},"scripts":{"build":"rimraf dist && tsc -p tsconfig.prod.json","test":"NODE_OPTIONS=--experimental-vm-modules jest --coverage","cz":"git-cz"},"repository":{"type":"git","url":"git+https://github.com/grantila/graph-cycles.git"},"keywords":["graph","cyclic","cycles","loops","recursive"],"devDependencies":{"@babel/preset-env":"^7.20.2","@babel/preset-typescript":"^7.18.6","@types/jest":"^29.4.0","@types/node":"^18.11.18","cz-conventional-changelog":"^3.3.0","jest":"^29.4.1","rimraf":"^4.1.2","ts-jest-resolver":"^2.0.0","ts-node":"^10.9.1","typescript":"^4.9.5"},"config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"dependencies":{"fast-string-compare":"^3.0.0","rotated-array-set":"^3.0.0","short-tree":"^3.0.0"},"jest":{"resolver":"ts-jest-resolver","testEnvironment":"node","coverageReporters":["lcov","text","html"],"extensionsToTreatAsEsm":[".ts"]},"packageManager":"yarn@3.2.4","gitHead":"0be9ffe404d92724d395f8b85fdf09db310e8bbe","_id":"graph-cycles@3.0.0","_nodeVersion":"18.13.0","_npmVersion":"8.19.3","dist":{"shasum":"368283d32ef97d4d385eac245d2ad0c3947601c0","size":6596,"noattachment":false,"key":"/graph-cycles/-/graph-cycles-3.0.0.tgz","tarball":"http://registry.cnpm.dingdandao.com/graph-cycles/download/graph-cycles-3.0.0.tgz"},"_npmUser":{"name":"grantila","email":"g.rantila@gmail.com"},"directories":{},"maintainers":[{"name":"grantila","email":""}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-cycles_3.0.0_1675374458236_0.5051489699200451"},"_hasShrinkwrap":false,"_cnpmcore_publish_time":"2023-02-02T21:47:38.411Z","publish_time":1675374458411,"_cnpm_publish_time":1675374458411},"2.0.1":{"name":"graph-cycles","version":"2.0.1","description":"Analyze a graph to find cyclic loops","author":{"name":"Gustaf Räntilä"},"license":"MIT","bugs":{"url":"https://github.com/grantila/graph-cycles/issues"},"homepage":"https://github.com/grantila/graph-cycles#readme","main":"./dist/index.js","exports":"./dist/index.js","types":"./dist/index.d.ts","type":"module","sideEffects":false,"engines":{"node":"^12.20.0 || ^14.13.1 || >=16.0.0"},"scripts":{"build":"rimraf dist && tsc -p tsconfig.prod.json","test":"NODE_OPTIONS=--experimental-vm-modules jest --coverage","cz":"git-cz"},"repository":{"type":"git","url":"git+https://github.com/grantila/graph-cycles.git"},"keywords":["graph","cyclic","cycles","loops","recursive"],"devDependencies":{"@babel/preset-env":"^7.16.5","@babel/preset-typescript":"^7.16.5","@types/jest":"^27.0.3","@types/node":"^16.9.1","cz-conventional-changelog":"^3.1.0","jest":"^27.4.5","rimraf":"^3.0.1","ts-jest-resolver":"^2.0.0","ts-node":"^10.4.0","typescript":"^4.5.4"},"config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"dependencies":{"fast-string-compare":"^2.0.0","rotated-array-set":"^2.0.0","short-tree":"^2.0.0"},"jest":{"resolver":"ts-jest-resolver","testEnvironment":"node","coverageReporters":["lcov","text","html"],"extensionsToTreatAsEsm":[".ts"]},"gitHead":"b0b63d3230c990134ceb1b660ed3ec24526db971","_id":"graph-cycles@2.0.1","_nodeVersion":"14.18.2","_npmVersion":"6.14.15","dist":{"shasum":"e7da51ad4d3f263f054fa0cf018aec8732326b98","size":6715,"noattachment":false,"key":"/graph-cycles/-/graph-cycles-2.0.1.tgz","tarball":"http://registry.cnpm.dingdandao.com/graph-cycles/download/graph-cycles-2.0.1.tgz"},"_npmUser":{"name":"grantila","email":"g.rantila@gmail.com"},"directories":{},"maintainers":[{"name":"grantila","email":""}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-cycles_2.0.1_1639818495172_0.5364626329732904"},"_hasShrinkwrap":false,"publish_time":1639818495313,"_cnpm_publish_time":1639818495313,"_cnpmcore_publish_time":"2021-12-18T09:08:36.136Z"},"2.0.0":{"name":"graph-cycles","version":"2.0.0","description":"Analyze a graph to find cyclic loops","author":{"name":"Gustaf Räntilä"},"license":"MIT","bugs":{"url":"https://github.com/grantila/graph-cycles/issues"},"homepage":"https://github.com/grantila/graph-cycles#readme","main":"./dist/index.js","exports":"./dist/index.js","types":"./dist/index.d.ts","type":"module","sideEffects":false,"engines":{"node":"^12.20.0 || ^14.13.1 || >=16.0.0"},"scripts":{"build":"rimraf dist && tsc -p tsconfig.prod.json","test":"NODE_OPTIONS=--experimental-vm-modules jest --coverage","cz":"git-cz"},"repository":{"type":"git","url":"git+https://github.com/grantila/graph-cycles.git"},"keywords":["graph","cyclic","cycles","loops","recursive"],"devDependencies":{"@babel/preset-env":"^7.15.6","@babel/preset-typescript":"^7.15.0","@types/jest":"^27.0.1","@types/node":"^16.9.1","cz-conventional-changelog":"^3.1.0","jest":"^27.1.1","rimraf":"^3.0.1","ts-node":"^10.2.1","typescript":"^4.4.3"},"config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"dependencies":{"fast-string-compare":"^2.0.0","rotated-array-set":"^2.0.0","short-tree":"^2.0.0"},"jest":{"testEnvironment":"node","coverageReporters":["lcov","text","html"],"extensionsToTreatAsEsm":[".ts"]},"gitHead":"bee313bb3f40a693d969299675b4c8b164f5a4bf","_id":"graph-cycles@2.0.0","_nodeVersion":"14.17.6","_npmVersion":"6.14.15","dist":{"shasum":"e008466990d6c13a198bd98e33579c429bbedfdc","size":6690,"noattachment":false,"key":"/graph-cycles/-/graph-cycles-2.0.0.tgz","tarball":"http://registry.cnpm.dingdandao.com/graph-cycles/download/graph-cycles-2.0.0.tgz"},"_npmUser":{"name":"grantila","email":"g.rantila@gmail.com"},"directories":{},"maintainers":[{"name":"grantila","email":""}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-cycles_2.0.0_1631518636929_0.6090950282689398"},"_hasShrinkwrap":false,"publish_time":1631518637080,"_cnpm_publish_time":1631518637080,"_cnpmcore_publish_time":"2021-12-16T23:40:42.482Z"},"1.2.1":{"name":"graph-cycles","version":"1.2.1","description":"Analyze a graph to find cyclic loops","author":{"name":"Gustaf Räntilä"},"license":"MIT","bugs":{"url":"https://github.com/grantila/graph-cycles/issues"},"homepage":"https://github.com/grantila/graph-cycles#readme","main":"./dist/index.js","types":"./dist/index.d.ts","directories":{},"engines":{"node":">=12"},"scripts":{"build":"rimraf dist && tsc -p tsconfig.prod.json","test":"jest --coverage","cz":"git-cz"},"repository":{"type":"git","url":"git+https://github.com/grantila/graph-cycles.git"},"keywords":["graph","cyclic","cycles","loops","recursive"],"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.31","cz-conventional-changelog":"^3.1.0","jest":"^26.6.3","rimraf":"^3.0.1","ts-jest":"^26.5.2","ts-node":"^9.1.1","typescript":"^4.2.2"},"config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"dependencies":{"fast-string-compare":"^1.0.0","rotated-array-set":"^1.0.0","short-tree":"^1.0.0"},"gitHead":"3fe39404c6f305afdec535b9d7d42d8395031e1b","_id":"graph-cycles@1.2.1","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"shasum":"a92652826e7cb800efe1a3bf4e3e069b2d7b2407","size":6854,"noattachment":false,"key":"/graph-cycles/-/graph-cycles-1.2.1.tgz","tarball":"http://registry.cnpm.dingdandao.com/graph-cycles/download/graph-cycles-1.2.1.tgz"},"_npmUser":{"name":"grantila","email":"g.rantila@gmail.com"},"maintainers":[{"name":"grantila","email":""}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-cycles_1.2.1_1618134420145_0.07700657470341565"},"_hasShrinkwrap":false,"publish_time":1618134420295,"_cnpm_publish_time":1618134420295,"_cnpmcore_publish_time":"2021-12-16T23:40:42.766Z"},"1.2.0":{"name":"graph-cycles","version":"1.2.0","description":"Analyze a graph to find cyclic loops","author":{"name":"Gustaf Räntilä"},"license":"MIT","bugs":{"url":"https://github.com/grantila/graph-cycles/issues"},"homepage":"https://github.com/grantila/graph-cycles#readme","main":"./dist/index.js","types":"./dist/index.d.ts","directories":{},"engines":{"node":">=12"},"scripts":{"build":"rimraf dist && tsc -p tsconfig.prod.json","test":"jest --coverage","cz":"git-cz"},"repository":{"type":"git","url":"git+https://github.com/grantila/graph-cycles.git"},"keywords":["graph","cyclic","cycles","loops","recursive"],"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.31","cz-conventional-changelog":"^3.1.0","jest":"^26.6.3","rimraf":"^3.0.1","ts-jest":"^26.5.2","ts-node":"^9.1.1","typescript":"^4.2.2"},"config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"dependencies":{"fast-string-compare":"^1.0.0","rotated-array-set":"^1.0.0","short-tree":"^1.0.0"},"gitHead":"7e9759365aaf7b410a090454c25b477df50f0418","_id":"graph-cycles@1.2.0","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"shasum":"9568febb1aa30d56c4f108c317775fc7c0847b58","size":6822,"noattachment":false,"key":"/graph-cycles/-/graph-cycles-1.2.0.tgz","tarball":"http://registry.cnpm.dingdandao.com/graph-cycles/download/graph-cycles-1.2.0.tgz"},"_npmUser":{"name":"grantila","email":"g.rantila@gmail.com"},"maintainers":[{"name":"grantila","email":""}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-cycles_1.2.0_1618133217812_0.7718047869418716"},"_hasShrinkwrap":false,"publish_time":1618133218035,"_cnpm_publish_time":1618133218035,"_cnpmcore_publish_time":"2021-12-16T23:40:43.034Z"},"1.1.0":{"name":"graph-cycles","version":"1.1.0","description":"Analyze a graph to find cyclic loops","author":{"name":"Gustaf Räntilä"},"license":"MIT","bugs":{"url":"https://github.com/grantila/graph-cycles/issues"},"homepage":"https://github.com/grantila/graph-cycles#readme","main":"./dist/index.js","types":"./dist/index.d.ts","directories":{},"engines":{"node":">=12"},"scripts":{"build":"rimraf dist && tsc -p tsconfig.prod.json","test":"jest --coverage","cz":"git-cz"},"repository":{"type":"git","url":"git+https://github.com/grantila/graph-cycles.git"},"keywords":["graph","cyclic","cycles","loops","recursive"],"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.31","cz-conventional-changelog":"^3.1.0","jest":"^26.6.3","rimraf":"^3.0.1","ts-jest":"^26.5.2","ts-node":"^9.1.1","typescript":"^4.2.2"},"config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"dependencies":{"rotated-array-set":"^1.0.0","short-tree":"^1.0.0"},"gitHead":"46f15c403321ddf49438a8d422001c6b95f5c802","_id":"graph-cycles@1.1.0","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"shasum":"73db9164d4d1329ff027064973b512e47adf75d6","size":5594,"noattachment":false,"key":"/graph-cycles/-/graph-cycles-1.1.0.tgz","tarball":"http://registry.cnpm.dingdandao.com/graph-cycles/download/graph-cycles-1.1.0.tgz"},"_npmUser":{"name":"grantila","email":"g.rantila@gmail.com"},"maintainers":[{"name":"grantila","email":""}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-cycles_1.1.0_1617318857915_0.19643692080591735"},"_hasShrinkwrap":false,"publish_time":1617318858066,"_cnpm_publish_time":1617318858066,"_cnpmcore_publish_time":"2021-12-16T23:40:43.233Z"},"1.0.0":{"name":"graph-cycles","version":"1.0.0","description":"Analyze a graph to find cyclic loops","author":{"name":"Gustaf Räntilä"},"license":"MIT","bugs":{"url":"https://github.com/grantila/graph-cycles/issues"},"homepage":"https://github.com/grantila/graph-cycles#readme","main":"./dist/index.js","types":"./dist/index.d.ts","directories":{},"engines":{"node":">=12"},"scripts":{"build":"rimraf dist && tsc -p tsconfig.prod.json","test":"jest --coverage","cz":"git-cz"},"repository":{"type":"git","url":"git+https://github.com/grantila/graph-cycles.git"},"keywords":["graph","cyclic","cycles","loops","recursive"],"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.31","cz-conventional-changelog":"^3.1.0","jest":"^26.6.3","rimraf":"^3.0.1","ts-jest":"^26.5.2","ts-node":"^9.1.1","typescript":"^4.2.2"},"config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"dependencies":{"rotated-array-set":"^1.0.0","short-tree":"^1.0.0"},"gitHead":"f44c5b6d3f5a651eedf064b015761e7f37602cf5","_id":"graph-cycles@1.0.0","_nodeVersion":"14.16.0","_npmVersion":"6.14.11","dist":{"shasum":"69107ca9cdc94d9170ef497f76b881a08675c58d","size":4831,"noattachment":false,"key":"/graph-cycles/-/graph-cycles-1.0.0.tgz","tarball":"http://registry.cnpm.dingdandao.com/graph-cycles/download/graph-cycles-1.0.0.tgz"},"_npmUser":{"name":"grantila","email":"g.rantila@gmail.com"},"maintainers":[{"name":"grantila","email":""}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/graph-cycles_1.0.0_1617318708890_0.8597264007545304"},"_hasShrinkwrap":false,"publish_time":1617318709072,"_cnpm_publish_time":1617318709072,"_cnpmcore_publish_time":"2021-12-16T23:40:43.416Z"}},"readme":"[![npm version][npm-image]][npm-url]\n[![downloads][downloads-image]][npm-url]\n[![build status][build-image]][build-url]\n[![coverage status][coverage-image]][coverage-url]\n[![Node.JS version][node-version]][node-url]\n\n\n# graph-cycles\n\nAnalyze a graph to find cyclic loops, entrypoints to them and dependencies of them.\n\nThis package provides two analysis functions, `analyzeGraph` and `analyzeGraphFast`. Beware of the former for very large graphs, especially with massive cyclicity, it can run out of memory or crash your Node process (if you run in Node). If in doubt, or if an in-depth analysis isn't necessary, choose the fast method.\n\n\n## Versions\n\n * Since v2 this is a [pure ESM][pure-esm] package, and requires Node.js >=12.20. It cannot be used from CommonJS.\n * Since v3 requires Node.js >= 14.13.1.\n\n\n## Example\n\nConsider the following graph:\n\n```ts\nconst graph = [\n    [ 'a', [ 'b', 'c' ] ],\n    [ 'b', [ 'c', 'j' ] ],\n    [ 'c', [ 'd' ] ],\n    [ 'd', [ 'e', 'h' ] ],\n    [ 'e', [ 'f', 'g' ] ],\n    [ 'f', [ 'd', 'j' ] ],\n    [ 'g', [ 'g', 'h' ] ],\n    [ 'h', [ 'i' ] ],\n    [ 'i', [ 'c' ] ],\n    [ 'j', [ ']' ] ],\n    [ 'k', [ 'l' ] ],\n    [ 'l', [ ']' ] ],\n    [ 'x', [ 'y' ] ],\n    [ 'z', [ 'x', 'y' ] ],\n];\n```\n\nIn this example, node `a` points to `b` and `c`; `b` points to `c` and `j`, etc. This can be drawn as:\n\n<!-- ←→↑↓ ⬊⬈⬉⬋ -->\n\n```\n// These will be found to be cyclic:\na → { b c }\nb → { c j }\nc → { d }\nd → { e h }\ne → { f g }\nf → { d k }\ng → { g h }\nh → { i }\ni → { c }\nj → { }\nk → { l }\nl → { }\nm → { l }\n// These will be found not to be cyclic (and not returned by the analysis):\nx → { y }\nz → { x y }\n\nCyclic cluster:\n                  ⬈ ⬊\n    j   i ← h ← g ← ⬋       m\n    ↑   ↓   ↑   ↑           ↓\na → b → c → d → e → f → k → l\n ⬊ ___ ⬈     ⬉ ___ ⬋\n\nNon-cyclic cluster:\nz → x → y\n ⬊ ___ ⬈\n```\n\nThis example shows a few cycles.\n\nIn the full analysis (`analyzeGraph`), the last entry of a cycle always point to the first entry, and is excluded in the cycle array. Cycles are only returned once with an arbitrary node as a starting point. The returned object contains all unique cycles, all entrypoints (node paths *into* a cycle), and then all individual nodes being cyclic. `j`, `k` and `l` are not cyclic, but are a dependencies of cyclic nodes. `m` is not cyclic either, but depends on a node which cyclic nodes also depend on.\n\n\n# API\n\n`analyzeGraph` and `analyzeGraphFast` take a list of `[ from, [ ...to ] ]` pairs and return the graph analysis.\n\n\n## Full analysis mode\n\n```ts\nimport { analyzeGraph } from 'graph-cycles'\n\nconst analysis = analyzeGraph( graph ); // <graph> from above\n\nconst { cycles, entrypoints, dependencies, dependents, all } = analysis;\n```\n\nThe result object is on the form:\n\n```ts\ninterface FullAnalysisResult {\n    cycles: Array< Array< string > >;\n    entrypoints: Array< Array< string > >;\n    dependencies: Array< string >;\n    dependents: Array< string >;\n    all: Array< string >;\n}\n```\n\nwhere `cycles` is an array of the cyclic loops, `entrypoints` the entrypoints (or entrypoint *paths*) which lead to a cyclic loop, `dependencies` is the nodes cyclic nodes *depend on*, and `dependents` are non-cyclic nodes depending on dependencies also dependent on by cyclic nodes. And `all` is all individual nodes which either lead to a cyclic loop (entrypoints) or are in one (excluding dependencies and dependents). `all` is all nodes *being* cyclic or *leading up to* cycles.\n\nFor the example above, the result would be:\n\n```ts\n{\n    cycles: [\n        [ 'g' ], // g cycles itself\n        [ 'c', 'd', 'h', 'i' ], // and then back to c...\n        [ 'c', 'd', 'e', 'g', 'h', 'i' ],\n        [ 'd', 'e', 'f' ],\n    ],\n    entrypoints: [\n        [ 'a' ],\n        [ 'b' ],\n    ],\n    dependencies: [ 'j', 'k', 'l' ],\n    dependents: [ 'm' ],\n    all: [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' ] // excl dependencies\n}\n```\n\n## Fast analysis mode\n\n```ts\nimport { analyzeGraphFast } from 'graph-cycles'\n\nconst analysis = analyzeGraphFast( graph ); // <graph> from above\n\nconst { cyclic, dependencies, dependents } = analysis;\n```\n\nThe result object is on the form:\n\n```ts\ninterface FastAnalysisResult\n{\n    cyclic: Array< string >;\n    dependencies: Array< string >;\n    dependents: Array< string >;\n}\n```\n\nIn the fast mode (`analyzeGraphFast`), entrypoints and cycles are merged into `cycles` and there's no concept of individual (unique) cycles; instead `cyclic` is an array of all cyclic (or *leading up to* cyclic) nodes. This is the same as `all` in the full analysis mode.\n\nFor the example above, the result would be:\n\n```ts\n{\n    cyclic: [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' ],\n    dependencies: [ 'j', 'k', 'l' ],\n    dependents: [ 'm' ]\n}\n```\n\n\n## Utilities\n\nThe package exports two helper functions `sortFullAnalysisResult`, `sortFastAnalysisResult` which take a result object (of type `FullAnalysisResult` or `FastAnalysisResult`) and return a new one with all values sorted. This helps when writing tests where both the *received* and *expected* values can be sorted deterministically. The sort order is deterministic but not respecting locale, as it's using [`fast-string-compare`](https://github.com/grantila/fast-string-compare) to be fast.\n\nExample:\n\n```ts\nimport { analyzeGraphFast, sortFastAnalysisResult } from 'graph-cycles'\n\nconst analysis = sortFastAnalysisResult( analyzeGraphFast( graph ) );\n\n// analysis can now be used for e.g. snapshots - its content is \"stable\"\n```\n\n\n\n[npm-image]: https://img.shields.io/npm/v/graph-cycles.svg\n[npm-url]: https://npmjs.org/package/graph-cycles\n[downloads-image]: https://img.shields.io/npm/dm/graph-cycles.svg\n[build-image]: https://img.shields.io/github/actions/workflow/status/grantila/graph-cycles/master.yml?branch=master\n[build-url]: https://github.com/grantila/graph-cycles/actions?query=workflow%3AMaster\n[coverage-image]: https://coveralls.io/repos/github/grantila/graph-cycles/badge.svg?branch=master\n[coverage-url]: https://coveralls.io/github/grantila/graph-cycles?branch=master\n[node-version]: https://img.shields.io/node/v/graph-cycles\n[node-url]: https://nodejs.org/en/\n[pure-esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c\n","_attachments":{},"homepage":"https://github.com/grantila/graph-cycles#readme","bugs":{"url":"https://github.com/grantila/graph-cycles/issues"},"license":"MIT"}