// IMPORTANT:
// Madge needs the Graphviz software to generate the SVG graphs.
//
// On Windows, download it here: https://graphviz.gitlab.io/download/, then add the path to the "bin" folder to your PATH variable or specify the path to the bin folder in the "madgeOptions" object below.
// On Linux, run "sudo apt-get install graphviz"
// On Mac, run "brew install graphviz || port install graphviz"
//
// To add files to be included in the graphing process, add them to the "otherFiles" array below (path is relative to project root).
// Before running this script by using "node dev/madge", make sure all dev dependencies are installed by running the command "npm i --save-dev"
const madgeOptions = {
// graphVizPath: "C:/Users/fes/Desktop/Graphviz/bin" // set to null to use the path inside the PATH environment variable
graphVizPath: null
};
const otherFiles = [
"./JokeAPI.js"
];
const madge = require("madge");
const fs = require("fs-extra");
const settings = require("../settings");
var fileList = [];
var firstIframePos = {url: "./madge/JokeAPI.html", name: "./JokeAPI"};
let isWindows = process.platform == "win32";
if(isWindows && !process.env.PATH.toLowerCase().includes("graphviz") && madgeOptions.graphVizPath == null)
{
console.log("\x1b[31m\x1b[1m\nMadge needs the GraphViz software to generate the SVG graphs. Please download it (https://graphviz.gitlab.io/download/) and add it to your PATH environment variable.\nAlso make sure the path to it contains the word \"Graphviz\"\x1b[0m");
process.exit(1);
}
const generateForOther = () => {
let iterCount = 0;
return new Promise((resolve, reject) => {
otherFiles.forEach(file => {
if(!file.endsWith(".js"))
{
iterCount++;
return;
}
let filename = file.replace(/\.js/g, "");
try
{
madge(`${file}`, madgeOptions)
.then((res) => res.svg())
.then((output) => {
iterCount++;
fs.writeFileSync(`./dev/madge/${filename}.html`, output.toString());
if(iterCount == otherFiles.length)
resolve();
});
fileList.push(`
${filename}.js`);
}
catch(err)
{
reject(err);
}
});
});
}
const generateForSrc = () => {
let iterCount = 0;
let srcFiles = fs.readdirSync("./src");
return new Promise((resolve, reject) => {
srcFiles.forEach(file => {
if(!file.endsWith(".js"))
{
iterCount++;
return;
}
let filename = file.replace(/\.js/g, "");
try
{
madge(`./src/${file}`, madgeOptions)
.then((res) => res.svg())
.then((output) => {
iterCount++;
fs.writeFileSync(`./dev/madge/src-${filename}.html`, output.toString());
if(iterCount == srcFiles.length)
resolve();
});
fileList.push(`src/${filename}.js`);
}
catch(err)
{
reject(err);
}
});
});
}
const generateForEndpoints = () => {
let iterCount = 0;
let endpointFiles = fs.readdirSync("./endpoints");
return new Promise((resolve, reject) => {
endpointFiles.forEach(file => {
if(!file.endsWith(".js"))
{
iterCount++;
return;
}
let filename = file.replace(/\.js/g, "");
try
{
madge(`./endpoints/${file}`, madgeOptions)
.then((res) => res.svg())
.then((output) => {
iterCount++;
fs.writeFileSync(`./dev/madge/endpoints-${filename}.html`, output.toString());
if(iterCount == endpointFiles.length)
resolve();
});
fileList.push(`endpoints/${filename}.js`);
}
catch(err)
{
reject(err);
}
});
});
}
const generateForTools = () => {
let iterCount = 0;
let toolFiles = fs.readdirSync("./tools");
return new Promise((resolve, reject) => {
toolFiles.forEach(file => {
if(!file.endsWith(".js"))
{
iterCount++;
return;
}
let filename = file.replace(/\.js/g, "");
try
{
madge(`./tools/${file}`, madgeOptions)
.then((res) => res.svg())
.then((output) => {
iterCount++;
fs.writeFileSync(`./dev/madge/tools-${filename}.html`, output.toString());
if(iterCount == toolFiles.length)
resolve();
});
fileList.push(`tools/${filename}.js`);
}
catch(err)
{
reject(err);
}
});
});
}
const generateForClasses = () => {
let iterCount = 0;
let classesFiles = fs.readdirSync("./src/classes");
return new Promise((resolve, reject) => {
classesFiles.forEach(file => {
if(!file.endsWith(".js"))
{
iterCount++;
return;
}
let filename = file.replace(/\.js/g, "");
try
{
madge(`./src/classes/${file}`, madgeOptions)
.then((res) => res.svg())
.then((output) => {
iterCount++;
fs.writeFileSync(`./dev/madge/classes-${filename}.html`, output.toString());
if(iterCount == classesFiles.length)
resolve();
});
fileList.push(`classes/${filename}.js`);
}
catch(err)
{
reject(err);
}
});
});
}
const generateForTests = () => {
let iterCount = 0;
let testsFiles = fs.readdirSync("./tests");
return new Promise((resolve, reject) => {
testsFiles.forEach(file => {
if(!file.endsWith(".js") || file == "template.js")
{
iterCount++;
return;
}
let filename = file.replace(/\.js/g, "");
try
{
madge(`./tests/${file}`, madgeOptions)
.then((res) => res.svg())
.then((output) => {
iterCount++;
fs.writeFileSync(`./dev/madge/tests-${filename}.html`, output.toString());
if(iterCount == testsFiles.length)
resolve();
});
fileList.push(`tests/${filename}.js`);
}
catch(err)
{
reject(err);
}
});
});
}
const writeIndex = () => {
let index = getIndex();
fs.writeFileSync("./dev/dependency-graph.html", index);
console.log(`\n\n\x1b[32m\x1b[1mSuccessfully generated dependency graphs for ${fileList.length} files.\n\x1b[0m`);
process.exit(0);
}
const getIndex = () => `\
${settings.info.name} Dependency Graph
${fileList.join("\n\t\t\t\t\t")}
Blue has dependencies.
Green has no dependencies.
Red has circular dependencies.
`;
async function exec()
{
try
{
if(!fs.existsSync("./dev/madge"))
fs.mkdirSync("./dev/madge");
await generateForOther();
process.stdout.write(".");
await generateForSrc();
process.stdout.write(".");
await generateForEndpoints();
process.stdout.write(".");
await generateForTools();
process.stdout.write(".");
await generateForClasses();
process.stdout.write(".");
await generateForTests();
process.stdout.write(".");
writeIndex();
process.stdout.write(".\n");
}
catch(err)
{
console.log(`\n\n\x1b[31m\x1b[1mError while generating dependency graphs:\n\x1b[0m${err}\n`);
process.exit(1);
}
}
exec();