Skip to content

Instantly share code, notes, and snippets.

@morulus
Last active September 12, 2019 16:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save morulus/3c8bc7a424304fe6be64bf5f7a4a3485 to your computer and use it in GitHub Desktop.
Save morulus/3c8bc7a424304fe6be64bf5f7a4a3485 to your computer and use it in GitHub Desktop.
Sort npm packages according to their dependencies
/* Under MIT License, Vladimir Kalmykov 2019 */
// I'm not sure this is the best solution, but it works and finds cyclical dependencies
// Any suggestions? Leave comments.
/**
* @param packages Array of package.json
* @return Array of names
*/
function sortAccordingToDepends(packages) {
const names = packages.map(pkg => pkg.name);
const result = [];
let iterationCount = 0;
const handlePackage = (pkg, parents = []) => {
if (parents.includes(pkg.name)) {
console.warn(`Circular dependency detected in the package "${pkg.name}" derived by "${parents.join("\" > \"")}"`);
result.push(pkg.name);
return;
}
if (!result.includes(pkg.name)) {
const keys = Object.keys(pkg.dependencies || {});
if (keys.length > 0) {
const left = keys.filter(name => names.includes(name) && !result.includes(name));
if (left.length === 0) {
result.push(pkg.name);
} else {
left.forEach(leftName => handlePackage(
packages.find(p => p.name === leftName),
parents.concat([ pkg.name ])
));
}
} else {
result.push(pkg.name);
}
}
};
while (result.length < packages.length) {
if (iterationCount === 100) {
/* Find circular dependencies */
const leftPackages = packages
.map(pkg => pkg.name)
.filter(name => !result.includes(name));
throw new Error(`Circular dependency detected in packages ${leftPackages.join(", ")}`);
}
iterationCount++;
for (let i = 0; i < packages.length; i++) {
handlePackage(packages[i]);
}
}
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment