diff --git a/lib/parsers/index.ts b/lib/parsers/index.ts index dd201742..2c3a564d 100644 --- a/lib/parsers/index.ts +++ b/lib/parsers/index.ts @@ -30,6 +30,7 @@ export interface PkgTree { hasDevDependencies?: boolean; cyclic?: boolean; missingLockFileEntry?: boolean; + size?: number; } export enum DepType { diff --git a/lib/parsers/package-lock-parser.ts b/lib/parsers/package-lock-parser.ts index 25b3ffae..35c0523a 100644 --- a/lib/parsers/package-lock-parser.ts +++ b/lib/parsers/package-lock-parser.ts @@ -75,6 +75,7 @@ export class PackageLockParser implements LockfileParser { dependencies: {}, hasDevDependencies: !_.isEmpty(manifestFile.devDependencies), name: manifestFile.name, + size: 1, version: manifestFile.version || '', }; @@ -104,10 +105,14 @@ export class PackageLockParser implements LockfileParser { } // transform depMap to a map of PkgTrees - const depTrees: {[depPath: string]: PkgTree} = await this.createDepTrees(depMap, depGraph); + const {depTrees, depTreesSizes} = await this.createDepTrees(depMap, depGraph); // get trees for dependencies from manifest file const topLevelDeps: Dep[] = getTopLevelDeps(manifestFile, includeDev); + + // number of dependencies including root one + let treeSize = 1; + for (const dep of topLevelDeps) { // if any of top level dependencies is a part of cycle // it now has a different item in the map @@ -116,9 +121,11 @@ export class PackageLockParser implements LockfileParser { // if the top level dependency is dev, all children are dev depTree.dependencies[dep.name] = dep.dev ? this.setDevDepRec(_.cloneDeep(depTrees[depName])) : depTrees[depName]; + treeSize += depTreesSizes[depName]; await setImmediatePromise(); } else if (/^file:/.test(dep.version)) { depTree.dependencies[dep.name] = createPkgTreeFromDep(dep); + treeSize++; } else { // TODO: also check the package version // for a stricter check @@ -127,8 +134,11 @@ export class PackageLockParser implements LockfileParser { } depTree.dependencies[dep.name] = createPkgTreeFromDep(dep); depTree.dependencies[dep.name].missingLockFileEntry = true; + treeSize++; } } + + depTree.size = treeSize; return depTree; } @@ -280,7 +290,8 @@ export class PackageLockParser implements LockfileParser { // Algorithm is based on dynamic programming technique and tries to build // "more simple" trees and compose them into bigger ones. - private async createDepTrees(depMap: DepMap, depGraph): Promise<{[depPath: string]: PkgTree}> { + private async createDepTrees(depMap: DepMap, depGraph): + Promise<{depTrees: {[depPath: string]: PkgTree}, depTreesSizes: {[depPath: string]: number}}> { // Graph has to be acyclic if (!graphlib.alg.isAcyclic(depGraph)) { @@ -288,6 +299,7 @@ export class PackageLockParser implements LockfileParser { } const depTrees: {[depPath: string]: PkgTree} = {}; + const depTreesSizes: {[depPath: string]: number} = {}; // topological sort guarantees that when we create a pkg-tree for a dep, // all it's sub-trees were already created. This also implies that leaf // packages will be processed first as they have no sub-trees. @@ -296,12 +308,14 @@ export class PackageLockParser implements LockfileParser { while (depOrder.length) { const depKey = depOrder.shift() as string; const dep = depMap[depKey]; + let treeSize = 1; // direction is from the dependency to the package requiring it, so we are // looking for predecessors for (const subDepPath of depGraph.predecessors(depKey)) { const subDep = depTrees[subDepPath]; dep.dependencies[subDep.name] = subDep; + treeSize += depTreesSizes[subDepPath]; } const pkgTree: PkgTree = { depType: dep.depType, @@ -316,12 +330,13 @@ export class PackageLockParser implements LockfileParser { pkgTree.hasDevDependencies = dep.hasDevDependencies; } depTrees[depKey] = pkgTree; + depTreesSizes[depKey] = treeSize; // Since this code doesn't handle any I/O or network, we need to force // event loop to tick while being used in server for request processing await setImmediatePromise(); } - return depTrees; + return {depTrees, depTreesSizes}; } private flattenLockfile(lockfile: PackageLock): DepMap { diff --git a/lib/parsers/yarn-lock-parse.ts b/lib/parsers/yarn-lock-parse.ts index d4dcbbd3..68de56f2 100644 --- a/lib/parsers/yarn-lock-parse.ts +++ b/lib/parsers/yarn-lock-parse.ts @@ -35,6 +35,7 @@ export class YarnLockParser implements LockfileParser { private yarnLockfileParser; private eventLoop: EventLoopSpinner; + private treeSize: number; constructor() { // @yarnpkg/lockfile doesn't work with Node.js < 6 and crashes just after @@ -49,6 +50,9 @@ export class YarnLockParser implements LockfileParser { // processed in ~150ms. Idea is to let those average requests through in one // tick and split only bigger ones. this.eventLoop = new EventLoopSpinner(200); + + // Number of dependencies including root one. + this.treeSize = 1; } public parseLockFile(lockFileContents: string): YarnLock { @@ -76,6 +80,7 @@ export class YarnLockParser implements LockfileParser { dependencies: {}, hasDevDependencies: !_.isEmpty(manifestFile.devDependencies), name: manifestFile.name, + size: 1, version: manifestFile.version || '', }; @@ -93,8 +98,10 @@ export class YarnLockParser implements LockfileParser { depTree.dependencies[dep.name] = await this.buildSubTreeRecursiveFromYarnLock( dep, yarnLock, [], strict); } + this.treeSize++; } + depTree.size = this.treeSize; return depTree; } @@ -138,6 +145,7 @@ export class YarnLockParser implements LockfileParser { }; depSubTree.dependencies[name] = await this.buildSubTreeRecursiveFromYarnLock( newDep, lockFile, [...depPath]); + this.treeSize++; } } diff --git a/test/lib/fixtures/dev-deps-only/expected-tree-empty.json b/test/lib/fixtures/dev-deps-only/expected-tree-empty.json index 20675e1f..97c88182 100644 --- a/test/lib/fixtures/dev-deps-only/expected-tree-empty.json +++ b/test/lib/fixtures/dev-deps-only/expected-tree-empty.json @@ -1,5 +1,6 @@ { "name": "pkg-dev-deps-only", + "size": 1, "version": "0.0.1", "hasDevDependencies": true, "dependencies": {} diff --git a/test/lib/fixtures/dev-deps-only/expected-tree.json b/test/lib/fixtures/dev-deps-only/expected-tree.json index b574f36c..1a771fd3 100644 --- a/test/lib/fixtures/dev-deps-only/expected-tree.json +++ b/test/lib/fixtures/dev-deps-only/expected-tree.json @@ -1,5 +1,6 @@ { "name": "pkg-dev-deps-only", + "size": 3, "version": "0.0.1", "hasDevDependencies": true, "dependencies": { diff --git a/test/lib/fixtures/external-tarball/expected-tree.json b/test/lib/fixtures/external-tarball/expected-tree.json index fe3a01d7..c8ecc389 100644 --- a/test/lib/fixtures/external-tarball/expected-tree.json +++ b/test/lib/fixtures/external-tarball/expected-tree.json @@ -98,5 +98,6 @@ }, "hasDevDependencies": false, "name": "external-tarball", + "size": 16, "version": "" } diff --git a/test/lib/fixtures/file-as-version/expected-tree.json b/test/lib/fixtures/file-as-version/expected-tree.json index 61dadeaa..a4277d6b 100644 --- a/test/lib/fixtures/file-as-version/expected-tree.json +++ b/test/lib/fixtures/file-as-version/expected-tree.json @@ -22,5 +22,6 @@ }, "hasDevDependencies": false, "name": "pkg-dev-deps-only", + "size": 4, "version": "0.0.1" } diff --git a/test/lib/fixtures/git-ssh-url-deps/expected-tree.json b/test/lib/fixtures/git-ssh-url-deps/expected-tree.json index a7fa5b33..f0f3b690 100644 --- a/test/lib/fixtures/git-ssh-url-deps/expected-tree.json +++ b/test/lib/fixtures/git-ssh-url-deps/expected-tree.json @@ -98,5 +98,6 @@ }, "hasDevDependencies": false, "name": "git-ssh-url-deps", + "size": 16, "version": "" } diff --git a/test/lib/fixtures/goof/dep-tree-no-dev-deps-yarn.json b/test/lib/fixtures/goof/dep-tree-no-dev-deps-yarn.json index b0a6bd55..99b80b9e 100644 --- a/test/lib/fixtures/goof/dep-tree-no-dev-deps-yarn.json +++ b/test/lib/fixtures/goof/dep-tree-no-dev-deps-yarn.json @@ -5854,5 +5854,6 @@ }, "hasDevDependencies": true, "name": "goof", - "version": "0.0.3" + "version": "0.0.3", + "size": 914 } diff --git a/test/lib/fixtures/goof/dep-tree-no-dev-deps.json b/test/lib/fixtures/goof/dep-tree-no-dev-deps.json index 4765bbf9..e31bd4ae 100644 --- a/test/lib/fixtures/goof/dep-tree-no-dev-deps.json +++ b/test/lib/fixtures/goof/dep-tree-no-dev-deps.json @@ -1,6 +1,7 @@ { "name": "goof", "version": "0.0.3", + "size": 910, "hasDevDependencies": true, "dependencies": { "adm-zip": { diff --git a/test/lib/fixtures/goof/dep-tree-with-dev-deps-yarn.json b/test/lib/fixtures/goof/dep-tree-with-dev-deps-yarn.json index e42c4626..5022a6a0 100644 --- a/test/lib/fixtures/goof/dep-tree-with-dev-deps-yarn.json +++ b/test/lib/fixtures/goof/dep-tree-with-dev-deps-yarn.json @@ -11450,5 +11450,6 @@ }, "hasDevDependencies": true, "name": "goof", - "version": "0.0.3" + "version": "0.0.3", + "size": 1795 } diff --git a/test/lib/fixtures/goof/dep-tree-with-dev-deps.json b/test/lib/fixtures/goof/dep-tree-with-dev-deps.json index 64b9e6f7..8986d98d 100644 --- a/test/lib/fixtures/goof/dep-tree-with-dev-deps.json +++ b/test/lib/fixtures/goof/dep-tree-with-dev-deps.json @@ -11425,5 +11425,6 @@ }, "hasDevDependencies": true, "name": "goof", - "version": "0.0.3" + "version": "0.0.3", + "size": 1791 } diff --git a/test/lib/fixtures/missing-deps/expected-tree.json b/test/lib/fixtures/missing-deps/expected-tree.json index 440cae04..c17652e9 100644 --- a/test/lib/fixtures/missing-deps/expected-tree.json +++ b/test/lib/fixtures/missing-deps/expected-tree.json @@ -1,5 +1,6 @@ { "name": "pkg-missing-deps", + "size": 1, "version": "1.0.0", "hasDevDependencies": false, "dependencies": {} diff --git a/test/lib/fixtures/out-of-sync-tree/expected-tree.json b/test/lib/fixtures/out-of-sync-tree/expected-tree.json index 64d6247e..6749e9d6 100644 --- a/test/lib/fixtures/out-of-sync-tree/expected-tree.json +++ b/test/lib/fixtures/out-of-sync-tree/expected-tree.json @@ -188,5 +188,6 @@ }, "hasDevDependencies": true, "name": "out-of-sync-small", + "size": 30, "version": "1.0.0" } diff --git a/test/lib/fixtures/out-of-sync/expected-tree.json b/test/lib/fixtures/out-of-sync/expected-tree.json index a26568c4..2c293be9 100644 --- a/test/lib/fixtures/out-of-sync/expected-tree.json +++ b/test/lib/fixtures/out-of-sync/expected-tree.json @@ -38,5 +38,6 @@ }, "hasDevDependencies": true, "name": "trucolor", + "size": 6, "version": "0.7.1" } diff --git a/test/lib/fixtures/package-repeated-in-manifest/expected-tree.json b/test/lib/fixtures/package-repeated-in-manifest/expected-tree.json index e8b225e0..30de291b 100644 --- a/test/lib/fixtures/package-repeated-in-manifest/expected-tree.json +++ b/test/lib/fixtures/package-repeated-in-manifest/expected-tree.json @@ -1,5 +1,6 @@ { "name": "goof", + "size": 17, "version": "0.0.3", "hasDevDependencies": true, "dependencies": {