npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

graph-sequencer

v2.0.0

Published

Sort items in a graph using a topological sort while resolving cycles with priority groups

Downloads

8,169

Readme

graph-sequencer

Sort items in a graph using a topological sort while resolving cycles with priority groups.

Say you have some sort of graph of dependencies: (using an adjacency list)

let graph = new Map([
  ["task-a", ["task-d"]], // task-a depends on task-d
  ["task-b", ["task-d", "task-a"]],
  ["task-c", ["task-d"]],
  ["task-d", ["task-a"]],
]);

You could run a topological sort on these items, but you'd still end up with cycles:

task-a -> task-d -> task-a

To resolve this you pass "priority groups" to graph-sequencer:

let groups = [
  ["task-d"], // higher priority
  ["task-a", "task-b", "task-c"], // lower priority
];

The result will be a chunked list of items sorted topologically and by the priority groups:

let chunks = [
  ["task-d"],
  ["task-a", "task-c"],
  ["task-b"]
];

You can then run all these items in order with maximum concurrency:

for (let chunk of chunks) {
  await Promise.all(chunk.map(task => exec(task)));
}

However, even with priority groups you can still accidentally create cycles of dependencies in your graph.

graph-sequencer will return a list of the unresolved cycles:

let cycles = [
  ["task-a", "task-b"] // task-a depends on task-b which depends on task-a
];

However, graph-sequencer will still return an "unsafe" set of chunks. When it comes across a cycle, it will add another chunk with the item with the fewest dependencies remaining which will often break cycles.

All together that looks like this:

const graphSequencer = require('graph-sequencer');

graphSequencer({
  graph: new Map([
    ["task-a", ["task-d"]], // task-a depends on task-d
    ["task-b", ["task-d", "task-a"]],
    ["task-c", ["task-d"]],
    ["task-d", ["task-a"]],
  ]);
  groups: [
    ["task-d"], // higher priority
    ["task-a", "task-b", "task-c"], // lower priority
  ],
})
// {
//   safe: true,
//   chunks: [["task-d"], ["task-a", "task-c"], ["task-b"]],
//   cycles: [],
// }