Skip to content

Instantly share code, notes, and snippets.

@bergie
Created March 27, 2018 10:11
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 bergie/b111eaff14baf1b149c12c0b777aece3 to your computer and use it in GitHub Desktop.
Save bergie/b111eaff14baf1b149c12c0b777aece3 to your computer and use it in GitHub Desktop.
Find unused components and modules in a FBP project
const fbpManifest = require('fbp-manifest');
const fbpGraph = require('fbp-graph');
const path = require('path');
const showError = (err) => {
console.error(err);
process.exit(1);
};
const baseDir = process.cwd();
const mainGraph = 'main';
const findComponent = (name, modules) => {
return new Promise((resolve, reject) => {
let [library, component] = name.split('/');
if (!component) {
component = library;
library = '';
}
const matchingModules = modules.filter((m) => {
if (!library) {
return true;
}
return (m.name === library);
});
let matched = null;
let matchedWithLoader = null;
matchingModules.forEach((m) => {
if (m.noflo && m.noflo.loader) {
matchedWithLoader = {
name: component,
elementary: true,
dynamic: true,
};
}
m.components.forEach((c) => {
if (c.name === component) {
matched = c;
}
});
});
if (!matched) {
if (matchedWithLoader) {
resolve(matchedWithLoader);
return;
}
reject(new Error(`Component ${name} not found`));
return;
}
resolve(matched);
});
};
const findDependencies = (component, componentUsage, moduleUsage, modules, checked) => {
return new Promise((resolve, reject) => {
if (checked.indexOf(component.name) !== -1) {
resolve();
return;
}
checked.push(component.name);
fbpGraph.graph.loadFile(component.source, (err, graph) => {
if (err) {
reject(err);
return;
}
Promise.all(graph.nodes.map((n) => {
const [module] = n.component.split('/');
if (!moduleUsage[module]) {
moduleUsage[module] = 0;
}
moduleUsage[module] += 1;
if (!componentUsage[n.component]) {
componentUsage[n.component] = 0;
}
componentUsage[n.component] += 1;
return findComponent(n.component, modules)
.then((c) => {
if (c.elementary) {
return Promise.resolve();
}
return findDependencies(c, componentUsage, moduleUsage, modules, checked);
});
}))
.then(resolve, reject);
});
return;
});
};
fbpManifest.list.list(baseDir, {
discover: true,
recursive: true,
runtimes: ['noflo'],
}, (err, modules) => {
if (err) {
showError(err);
return;
}
// Keep track of all components in use
const moduleUsage = {};
const componentUsage = {};
modules.forEach((m) => {
moduleUsage[m.name] = 0;
m.components.forEach((c) => {
componentUsage[`${m.name}/${c.name}`] = 0;
// Convert paths to absolute
c.path = path.resolve(baseDir, m.base, c.path);
c.source = path.resolve(baseDir, m.base, c.source);
});
});
// Find graphs in current project
const currentModules = modules.filter((m) => m.base === '');
const currentGraphs = [];
currentModules.forEach((m) => {
m.components.forEach((c) => {
if (c.elementary) {
return;
}
currentGraphs.push(c);
});
});
findComponent(mainGraph, modules)
.then((main) => {
componentUsage[`${currentModules[0].name}/${main.name}`] = 1;
return main;
})
.then((main) => findDependencies(main, componentUsage, moduleUsage, modules, []))
.then(() => {
console.log('Unused components:');
Object.keys(componentUsage).forEach((name) => {
if (componentUsage[name] > 0) {
return;
}
const [library, component] = name.split('/');
if (library && library !== currentModules[0].name) {
return;
}
console.log(`${name}`);
});
console.log('\n');
console.log('Unused modules:');
Object.keys(moduleUsage).forEach((name) => {
if (moduleUsage[name] > 0) {
return;
}
console.log(`${name}`);
});
}, showError);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment