From 79b237988ee0d7e7556f7782cce4f3ef7cf2ef16 Mon Sep 17 00:00:00 2001 From: Mickael Jeanroy Date: Mon, 21 Nov 2016 13:38:07 +0100 Subject: [PATCH] feat: use a cache to avoid directory scan if not necessary --- src/license-plugin.js | 41 +++++++++++++++++++++++++++---- test/license-plugin.spec.js | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/src/license-plugin.js b/src/license-plugin.js index 14df8a1f..fecb6026 100644 --- a/src/license-plugin.js +++ b/src/license-plugin.js @@ -43,6 +43,11 @@ class LicensePlugin { this._cwd = process.cwd(); this._dependencies = {}; this._pkg = require(path.join(this._cwd, 'package.json')); + + // This is a cache storing a directory path to associated package. + // This is an improvement to avoid looking for package information for + // already scanned directory. + this._cache = {}; } /** @@ -61,18 +66,44 @@ class LicensePlugin { load(id) { // Look for the `package.json` file let dir = path.parse(id).dir; + let pkg = null; + + const scannedDirs = []; + while (dir && dir !== this._cwd) { - const pkg = path.join(dir, 'package.json'); - const exists = fs.existsSync(pkg); + // Try the cache. + if (_.has(this._cache, dir)) { + pkg = this._cache[dir]; + if (pkg) { + this.addDependency(pkg); + } + + break; + } + scannedDirs.push(dir); + + const pkgPath = path.join(dir, 'package.json'); + const exists = fs.existsSync(pkgPath); if (exists) { - this.addDependency(require(pkg)); + // Read `package.json` file + pkg = require(pkgPath); + + // Add the new dependency to the set of third-party dependencies. + this.addDependency(pkg); + + // We can stop now. break; } - const parent = path.join(dir, '..'); - dir = path.normalize(parent); + // Go up in the directory tree. + dir = path.normalize(path.join(dir, '..')); } + + // Update the cache + _.forEach(scannedDirs, (scannedDir) => { + this._cache[scannedDir] = pkg; + }); } /** diff --git a/test/license-plugin.spec.js b/test/license-plugin.spec.js index ff87736b..6a23457c 100644 --- a/test/license-plugin.spec.js +++ b/test/license-plugin.spec.js @@ -22,7 +22,9 @@ * SOFTWARE. */ +const fs = require('fs'); const path = require('path'); +const _ = require('lodash'); const moment = require('moment'); const LicensePlugin = require('../dist/license-plugin.js'); @@ -69,6 +71,52 @@ describe('LicensePlugin', () => { expect(plugin._dependencies).toEqual({}); }); + it('should load pkg and update cache', () => { + const plugin = new LicensePlugin(); + const fakePackage = path.join(__dirname, 'fixtures', 'fake-package'); + const id = path.join(fakePackage, 'src', 'index.js'); + const pkg = require(path.join(fakePackage, 'package.json')); + + plugin.load(id); + + expect(plugin._dependencies).toEqual({ + 'fake-package': _.pick(pkg, ['name', 'author', 'version', 'description', 'license', 'private']), + }); + + expect(plugin._cache).toEqual({ + [path.join(__dirname, 'fixtures', 'fake-package', 'src')]: pkg, + [path.join(__dirname, 'fixtures', 'fake-package')]: pkg, + }); + }); + + it('should load pkg and put null without package', () => { + const plugin = new LicensePlugin(); + const id = path.join(__dirname, '..', 'src', 'index.js'); + + plugin.load(id); + + expect(plugin._dependencies).toEqual({}); + expect(plugin._cache).toEqual({ + [path.normalize(path.join(__dirname, '..', 'src'))]: null, + }); + }); + + it('should load pkg and use the cache if available', () => { + const plugin = new LicensePlugin(); + const fakePackage = path.join(__dirname, 'fixtures', 'fake-package'); + const id = path.join(fakePackage, 'src', 'index.js'); + + plugin._cache[path.join(fakePackage, 'src')] = null; + plugin._cache[fakePackage] = null; + + spyOn(fs, 'existsSync').and.callThrough(); + + plugin.load(id); + + expect(plugin._dependencies).toEqual({}); + expect(fs.existsSync).not.toHaveBeenCalled(); + }); + it('should add dependency', () => { const plugin = new LicensePlugin(); const pkg = {