Every time I run the following function, I expect it to output the different paths embedded in my composer.json file and then perform this recursively for each package. However, it just gives me the same result over and over again. Please what am I missing here?
const packageComposer = async (node) => {
node = node ? __dirname : node;
let composer = fs.readFileSync(node + '/composer.json', 'utf8');
let dependencies = Object.keys(JSON.parse(composer).require);
console.log(node + '/composer.json');
dependencies.forEach(key => {
let dependency = key.split('/');
let dir = node + '/vendor/' + dependency[0] + '/' + dependency[1];
if (fs.existsSync(dir)) {
packageComposer(dir);
}
});
}
Composer.json file looks like:
{
"require": {
"php": ">=7.2",
"alek13/slack": "^2.1",
"composer/installers": "^1.7",
"htmlburger/carbon-fields": "^3.3"
}
}
Console output:
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
RangeError: Maximum call stack size exceeded
Exception in PromiseRejectCallback:
/Users/user/Desktop/github/plugin-folder/gulpfile.js:59
}
I was wondering why your console output never shows a path with /vendor in it because your recursive logic intends to create a path that has /vendor in it. Then, I realized, that's because this logic:
node = node ? __dirname : node;
is backwards and will always select __dirname when you pass a value for node. So, every recursive call ends up using the same value for node and thus an infinite loop that eventually overflows the stack.
Instead, you want this:
node = node ? node : __dirname;
The MDN description for the ternary operator is this:
condition ? exprIfTrue : exprIfFalse
Another way to do this is to use default parameters and let the JS engine supply a value when nothing is passed and write is this way:
const packageComposer = async (node = __dirname) => {
...
};
For any further debugging, I might suggest this cleaned up version with logging that lets you follow where it goes:
function packageComposer(node = __dirname) {
// read and parse composer.json using require()
const filename = path.join(node, 'composer.json');
console.log(`About to read ${filename}`);
let composer = require(filename);
const dependencies = Object.keys(composer.require);
console.log("Found dependencies", dependencies);
for (const key of dependencies) {
const pieces = key.split("/");
const dir = path.join(node, 'vendor', dependency[0], dependency[1]);
if (fs.existsSync(dir)) {
console.log(`Calling packageComposer(${dir}) recursively`);
packageComposer(dir);
}
}
}
As I said in my comments, a couple things seem odd here. You do key.split("/") to get the pieces of a key such as "alek13/slack", then you immediately put them back together again to reconstruct "alek13/slack" again. Not sure why you're doing that or what you expect to happen when the keys can't be split and you've got a key like "php" that doesn't contain a "/".