Repository URL to install this package:
|
Version:
0.7.0 ▾
|
// (c) Copyright 2023 Supertenant Ltd. - all rights reserved.
// See LICENSE file in project root for license terms.
"use strict";const assert=require("assert"),fs=require("fs"),path=require("path"),CountDownLatch=require("./CountDownLatch");let logger=require("@supertenant/core").logger.getLogger("metrics");exports.setLogger=function(_logger){logger=_logger};class DependencyDistanceCalculator{calculateDistancesFrom(packageJsonPath,callback){this.started=Date.now(),assert.strictEqual(typeof packageJsonPath,"string"),assert.strictEqual(typeof callback,"function"),this.distancesFromRoot={},this.globalCountDownLatchAllPackages=new CountDownLatch(0),this.globalCountDownLatchAllPackages.once("done",()=>{logger.debug(`Calculation of dependency distances took ${Date.now()-this.started} ms.`),callback(this.distancesFromRoot)}),this._calculateDistances(packageJsonPath,1)}_calculateDistances(packageJsonPath,distance){if(!(distance>module.exports.MAX_DEPTH)&&"string"==typeof packageJsonPath){this.globalCountDownLatchAllPackages.countUp(3);try{fs.readFile(packageJsonPath,{encoding:"utf8"},(err,contents)=>{if(err)logger.debug("Failed to calculate transitive distances for some dependencies, could not read package.json file at %s: %s.",packageJsonPath,err.message),this.globalCountDownLatchAllPackages.countDown(3);else{let parsedPackageJson;try{parsedPackageJson=JSON.parse(contents)}catch(parseErr){return logger.debug("Failed to calculate transitive distances for some dependencies, could not parse package.json file at %s: %s",packageJsonPath,parseErr.message),void this.globalCountDownLatchAllPackages.countDown(3)}this._calculateDistancesForOneType(parsedPackageJson.dependencies,distance),this._calculateDistancesForOneType(parsedPackageJson.peerDependencies,distance),this._calculateDistancesForOneType(parsedPackageJson.optionalDependencies,distance)}})}catch(fsReadFileErr){logger.debug("Failed to calculate transitive distances for some dependencies, synchronous error from fs.readFile for %s:",packageJsonPath,fsReadFileErr),this.globalCountDownLatchAllPackages.countDown(3)}}}_calculateDistancesForOneType(dependencies,distance){if(dependencies){var keys=Object.keys(dependencies);if(0===keys.length)this.globalCountDownLatchAllPackages.countDown();else{var localCountDownLatchForThisNode=new CountDownLatch(keys.length);localCountDownLatchForThisNode.once("done",()=>{this.globalCountDownLatchAllPackages.countDown()});for(let i=0;i<keys.length;i++){var dependency=keys[i];this.distancesFromRoot[dependency]?(this.distancesFromRoot[dependency]=Math.min(distance,this.distancesFromRoot[dependency]),localCountDownLatchForThisNode.countDown()):(this.distancesFromRoot[dependency]=distance,this._handleTransitiveDependency(dependency,distance,localCountDownLatchForThisNode))}}}else this.globalCountDownLatchAllPackages.countDown()}_handleTransitiveDependency(dependency,distance,localCountDownLatchForThisNode){let mainModulePath;try{mainModulePath=require.resolve(dependency)}catch(requireResolveErr){logger.debug(`Ignoring failure to resolve the path to dependency ${dependency} for dependency distance calculation.`)}mainModulePath?findPackageJsonFor(path.dirname(mainModulePath),(err,packageJsonPath)=>{err?(localCountDownLatchForThisNode.countDown(),logger.debug(`Ignoring failure to find the package.json file for dependency ${dependency} for dependency distance `+"calculation.",err)):"string"!=typeof packageJsonPath?(localCountDownLatchForThisNode.countDown(),logger.debug(`Ignoring failure to find the package.json file for dependency ${dependency} for dependency distance `+`calculation (package.json path is ${packageJsonPath}/${typeof packageJsonPath}).`)):(this._calculateDistances(packageJsonPath,distance+1),localCountDownLatchForThisNode.countDown())}):(localCountDownLatchForThisNode.countDown(),logger.debug(`No main module path for dependency ${dependency}.`))}}function findPackageJsonFor(dir,callback){const pathToCheck=path.join(dir,"package.json");try{fs.stat(pathToCheck,(err,stats)=>err?"ENOENT"===err.code?searchInParentDir(dir,findPackageJsonFor,callback):process.nextTick(callback,err,null):stats.isFile()?process.nextTick(callback,null,pathToCheck):searchInParentDir(dir,findPackageJsonFor,callback))}catch(fsStatErr){return process.nextTick(callback,fsStatErr,null)}}function searchInParentDir(dir,onParentDir,callback){var parentDir=path.resolve(dir,"..");return dir===parentDir?process.nextTick(callback,null,null):onParentDir(parentDir,callback)}module.exports={DependencyDistanceCalculator:DependencyDistanceCalculator,MAX_DEPTH:15,__moduleRefExportedForTest:module};