Repository: tclindner/npm-package-json-lint
Pull request #45 (2017-08-09 02:45:06)

Config alternatives


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f35b0aa..a95a0a3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,15 @@ This project adheres to [Semantic Versioning](http://semver.org/).
 
 ### Removed
 
+## [2.7.0] - 2017-08-08
+### Added
+- The ability to pass config using:
+  1. a `npmPackageJsonLintConfig` property in `package.json`
+  2. a `.npmpackagejsonlintrc` file in the current working directory
+  3. a `npmpackagejsonlint.config.js` file that exports a config object in the current working directory.
+  4. a global `.npmpackagejsonlintrc` file in the root of your user directory
+  5. a global `npmpackagejsonlint.config.js` file that exports a config object in the root of your user directory
+
 ## [2.6.0] - 2017-07-30
 ### Changed
 - Bumped dependencies
diff --git a/README.md b/README.md
index fb180c8..064db4b 100755
--- a/README.md
+++ b/README.md
@@ -66,9 +66,12 @@ Run a specific rule, require-author, set severity to warning on a file relative
 Run using the config in `.npmpackagejsonlintrc` on a file relative to the current working directory.
 `pjl-cli -f "../relative-path/package.json" -c "./.npmpackagejsonlintrc"`
 
-Run using the default config on a file relative to the current working directory
+Run on file relative to the current working directory. npm-package-json-lint attempts to find config. See lookup order below.
 `pjl-cli -f "../relative-path/package.json"`
 
+Run on file in the current working directory. npm-package-json-lint attempts to find config. See lookup order below.
+`pjl-cli`
+
 ## Lint Rules
 
 npm-package-json-lint has a configurable set of rules. Please see the [wiki](https://github.com/tclindner/npm-package-json-lint/wiki) for a full list of available rules. By default no rules are enabled. If you would like to use npm-package-json-lint's default ruleset, please see [npm-package-json-lint-config-default](https://github.com/tclindner/npm-package-json-lint-config-default).
@@ -80,7 +83,13 @@ Each rule contains the following properties:
   3. Message - example: author is required
   4. Rule Type - example: required
 
-As mentioned in the "Commands and configuration" section there are two ways to specify rule sets. The first is using `--rule` to specify a given rule. This will run npm-package-json-lint with just this rule. The second is using `--rules-file` to specify a JSON file, named [`.npmpackagejsonlintrc`](https://github.com/tclindner/npm-package-json-lint/wiki/npm-package-json-lint-rc), to run a set of rules. If neither of the options above are specified then npm-package-json-lint looks for a global [`.npmpackagejsonlintrc`](https://github.com/tclindner/npm-package-json-lint/wiki/npm-package-json-lint-rc) file in the root of your user directory.
+As mentioned in the "Commands and configuration" section there are two ways to specify rule sets. The first is using `--rule` to specify a given rule. This will run npm-package-json-lint with just this rule. The second is providing a configuration object. As of v2.7.0, there are multiple ways to provide a [configuration object](https://github.com/tclindner/npm-package-json-lint/wiki/configuration).
+
+  1. Adding a `--rules-file` to the command to specify a JSON file. This file is typically named [`.npmpackagejsonlintrc`](https://github.com/tclindner/npm-package-json-lint/wiki/npm-package-json-lint-rc); however, you may optionally add a .json extension if you prefer.
+  2. Add a `npmPackageJsonLintConfig` property in `package.json` file
+  3. Add a `npmpackagejsonlint.config.js` file that exports a config object in the current working directory.
+  4. Add a global `.npmpackagejsonlintrc.json` file in the root of your user directory
+  5. Add a global `npmpackagejsonlint.config.js` file that exports a config object in the root of your user directory
 
 ### Configuring rules
 
diff --git a/package.json b/package.json
index 137050b..9fb3a65 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "npm-package-json-lint",
-  "version": "2.6.0",
+  "version": "2.7.0",
   "description": "CLI app for linting package.json files.",
   "keywords": [
     "lint",
@@ -31,10 +31,10 @@
     "eslint": "eslint . --format=node_modules/eslint-formatter-pretty",
     "lint": "npm run eslint",
     "test": "mocha tests/unit --recursive",
-    "coverage": "nyc --extension .js --check-coverage --lines 99 --branches 97 --functions 98 npm test"
+    "coverage": "nyc --extension .js --check-coverage --lines 99 --branches 97 --functions 96 npm test"
   },
   "dependencies": {
-    "chalk": "^2.0.1",
+    "chalk": "^2.1.0",
     "commander": "^2.11.0",
     "in-array": "^0.1.2",
     "is-plain-obj": "^1.1.0",
@@ -45,14 +45,14 @@
     "validator": "^8.0.0"
   },
   "devDependencies": {
-    "chai": "^4.1.0",
-    "eslint": "^4.3.0",
-    "eslint-config-tc": "^2.0.0",
+    "chai": "^4.1.1",
+    "eslint": "^4.4.1",
+    "eslint-config-tc": "^2.1.0",
     "eslint-formatter-pretty": "^1.1.0",
     "figures": "^2.0.0",
-    "mocha": "^3.4.2",
+    "mocha": "^3.5.0",
     "nyc": "^11.1.0",
-    "sinon": "^2.4.1"
+    "sinon": "^3.1.0"
   },
   "engines": {
     "node": ">=4.2.0",
diff --git a/src/Config.js b/src/Config.js
index d2622d6..ef0cfe2 100755
--- a/src/Config.js
+++ b/src/Config.js
@@ -2,17 +2,20 @@
 
 /* eslint class-methods-use-this: 'off' */
 
+const fs = require('fs');
 const inArray = require('in-array');
 const Parser = require('./Parser');
 const path = require('path');
+const userHome = require('user-home');
 
 class Config {
 
   /**
    * Constructor
    * @param  {Object|String} passedConfigParam Object or string with desired configuration
+   * @param  {Object}        packageJsonData   User's package.json data
    */
-  constructor(passedConfigParam) {
+  constructor(passedConfigParam, packageJsonData) {
     this.arrayRules = [
       'valid-values-author',
       'valid-values-private',
@@ -23,6 +26,9 @@ class Config {
     ];
 
     this.passedConfigParam = passedConfigParam;
+    this.packageJsonData = packageJsonData;
+    this.rcFileName = '.npmpackagejsonlintrc';
+    this.configFileName = 'npmpackagejsonlint.config.js';
   }
 
   /**
@@ -30,22 +36,44 @@ class Config {
    * @return {Object} Config object
    */
   get() {
-    if (this._isConfigPassed(this.passedConfigParam)) {
-      const passedConfig = this._getPassedConfig(this.passedConfigParam);
-      let extendsConfig = {};
+    const userConfig = this._getUserConfig();
 
-      if (passedConfig.hasOwnProperty('extends')) {
-        extendsConfig = this._getExtendsConfig(passedConfig.extends);
-      }
+    this._validateConfig(userConfig);
 
-      if (!passedConfig.hasOwnProperty('rules')) {
-        return Object.assign({}, extendsConfig);
-      }
+    let extendsConfig = {};
+
+    if (userConfig.hasOwnProperty('extends')) {
+      extendsConfig = this._getExtendsConfig(userConfig.extends);
+    }
+
+    if (!userConfig.hasOwnProperty('rules')) {
+      return Object.assign({}, extendsConfig);
+    }
+
+    return Object.assign({}, extendsConfig, userConfig.rules);
+  }
 
-      return Object.assign({}, extendsConfig, passedConfig.rules);
+  /**
+   * Get users config with multiple fallbacks
+   *
+   * @returns {Object} Users config
+   */
+  _getUserConfig() {
+    if (this._isConfigPassed(this.passedConfigParam)) {
+      return this._getPassedConfig(this.passedConfigParam);
+    } else if (this.packageJsonData.hasOwnProperty('npmPackageJsonLintConfig')) {
+      return this.packageJsonData.npmPackageJsonLintConfig;
+    } else if (this._isConfigFileExist(this._getRelativeConfigFilePth(this.rcFileName))) {
+      return this._loadRcFile(this._getRelativeConfigFilePth(this.rcFileName));
+    } else if (this._isConfigFileExist(this._getRelativeConfigFilePth(this.configFileName))) {
+      return this._loadConfigFile(this._getRelativeConfigFilePth(this.configFileName));
+    } else if (this._isConfigFileExist(this._getUsrHmConfigFilePath(this.rcFileName))) {
+      return this._loadRcFile(this._getUsrHmConfigFilePath(this.rcFileName));
+    } else if (this._isConfigFileExist(this._getUsrHmConfigFilePath(this.configFileName))) {
+      return this._loadConfigFile(this._getUsrHmConfigFilePath(this.configFileName));
     }
 
-    throw new Error('No configuration passed');
+    throw new Error('No configuration found');
   }
 
   /**
@@ -73,11 +101,7 @@ class Config {
         configFile = path.join(process.cwd(), passedConfig);
       }
 
-      const rcFileObj = parser.parse(configFile);
-
-      this._validateConfig(rcFileObj);
-
-      return rcFileObj;
+      return parser.parse(configFile);
     }
 
     return passedConfig;
@@ -104,6 +128,57 @@ class Config {
     return configObj.rules;
   }
 
+  /**
+   * Gets relative config file path
+   *
+   * @param  {String}  fileName Name of the file
+   * @return {String}  File path of the config file
+   */
+  _getRelativeConfigFilePth(fileName) {
+    return path.join(process.cwd(), fileName);
+  }
+
+  /**
+   * Gets userhome directory config file path
+   *
+   * @param  {String}  fileName Name of the file
+   * @return {String}  File path of the config file
+   */
+  _getUsrHmConfigFilePath(fileName) {
+    return path.join(userHome, fileName);
+  }
+
+  /**
+   * Checks if a .npmpackagejsonlintrc.json file exists
+   *
+   * @param  {String}  filePath Path of the file
+   * @return {Boolean} true if it exists, false if not
+   */
+  _isConfigFileExist(filePath) {
+    return fs.existsSync(filePath);
+  }
+
+  /**
+   * Gets configuration from a extends config module
+   * @param  {String} filePath  File path of config file
+   * @return {Object}           Configuration object
+   */
+  _loadRcFile(filePath) {
+    const parser = new Parser();
+
+    return parser.parse(filePath);
+  }
+
+  /**
+   * Checks if a .npmpackagejsonlintrc.json file exists
+   *
+   * @param  {String}  filePath File path of config file
+   * @return {Boolean} true if it exists, false if not
+   */
+  _loadConfigFile(filePath) {
+    return require(filePath);
+  }
+
   /**
    * Loads extends config module
    * @param  {String} moduleName  Name of the configuration module
diff --git a/src/NpmPackageJsonLint.js b/src/NpmPackageJsonLint.js
index 24b4a15..6e5b174 100755
--- a/src/NpmPackageJsonLint.js
+++ b/src/NpmPackageJsonLint.js
@@ -92,7 +92,7 @@ class NpmPackageJsonLint {
    * @return {Object}                 Configuration object for the run
    */
   _getConfig(config) {
-    const configObj = new Config(config);
+    const configObj = new Config(config, this.packageJsonData);
 
     return configObj.get();
   }


Test patch:
diff --git a/tests/fixtures/configJavaScriptFile/npmpackagejsonlint.config.js b/tests/fixtures/configJavaScriptFile/npmpackagejsonlint.config.js
new file mode 100644
index 0000000..6da856f
--- /dev/null
+++ b/tests/fixtures/configJavaScriptFile/npmpackagejsonlint.config.js
@@ -0,0 +1,28 @@
+'use strict';
+
+module.exports = {
+  rules: {
+    'require-author': 'error',
+    'require-description': 'error',
+    'require-devDependencies': 'error',
+    'require-homepage': 'error',
+    'require-keywords': 'error',
+    'require-license': 'warning',
+    'require-name': 'error',
+    'require-repository': 'error',
+    'require-scripts': 'error',
+    'require-version': 'error',
+    'description-type': 'error',
+    'devDependencies-type': 'error',
+    'homepage-type': 'error',
+    'keywords-type': 'error',
+    'name-type': 'error',
+    'repository-type': 'error',
+    'version-type': 'error',
+    'valid-values-author': ['error', [
+      'Thomas Lindner'
+    ]],
+    'name-format': 'error',
+    'version-format': 'error'
+  }
+};
diff --git a/tests/fixtures/configJavaScriptFile/package.json b/tests/fixtures/configJavaScriptFile/package.json
new file mode 100644
index 0000000..ad17e2a
--- /dev/null
+++ b/tests/fixtures/configJavaScriptFile/package.json
@@ -0,0 +1,17 @@
+{
+  "name": "npm-package-json-lint",
+  "version": "0.1.0",
+  "description": "CLI app for linting package.json files.",
+  "keywords": [
+    "lint"
+  ],
+  "homepage": "https://github.com/tclindner/npm-package-json-lint",
+  "author": "Thomas Lindner",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/tclindner/npm-package-json-lint"
+  },
+  "devDependencies": {
+    "mocha": "^2.4.5"
+  }
+}
diff --git a/tests/fixtures/packageJsonProperty/package.json b/tests/fixtures/packageJsonProperty/package.json
new file mode 100644
index 0000000..0877705
--- /dev/null
+++ b/tests/fixtures/packageJsonProperty/package.json
@@ -0,0 +1,43 @@
+{
+  "name": "npm-package-json-lint",
+  "version": "0.1.0",
+  "description": "CLI app for linting package.json files.",
+  "keywords": [
+    "lint"
+  ],
+  "homepage": "https://github.com/tclindner/npm-package-json-lint",
+  "author": "Thomas Lindner",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/tclindner/npm-package-json-lint"
+  },
+  "devDependencies": {
+    "mocha": "^2.4.5"
+  },
+  "npmPackageJsonLintConfig": {
+    "rules": {
+      "require-author": "error",
+      "require-description": "error",
+      "require-devDependencies": "error",
+      "require-homepage": "error",
+      "require-keywords": "error",
+      "require-license": "warning",
+      "require-name": "error",
+      "require-repository": "error",
+      "require-scripts": "error",
+      "require-version": "error",
+      "description-type": "error",
+      "devDependencies-type": "error",
+      "homepage-type": "error",
+      "keywords-type": "error",
+      "name-type": "error",
+      "repository-type": "error",
+      "version-type": "error",
+      "valid-values-author": ["error", [
+        "Thomas Lindner"
+      ]],
+      "name-format": "error",
+      "version-format": "error"
+    }
+  }
+}
diff --git a/tests/unit/Config.test.js b/tests/unit/Config.test.js
index 756051f..5bb943c 100755
--- a/tests/unit/Config.test.js
+++ b/tests/unit/Config.test.js
@@ -1,5 +1,7 @@
 'use strict';
 
+/* eslint max-lines: 'off', id-length: 'off' */
+
 const fs = require('fs');
 const path = require('path');
 const chai = require('chai');
@@ -9,17 +11,6 @@ const Config = require('./../../src/Config');
 const should = chai.should();
 
 describe('Config Unit Tests', function() {
-  context('when an empty object is passed', function() {
-    it('the default config object should be returned', function() {
-      const passedConfig = {};
-      const config = new Config(passedConfig);
-
-      (function() {
-        config.get(passedConfig);
-      }).should.throw('No configuration passed');
-    });
-  });
-
   context('Tests for when a filepath is passed', function() {
     let spy;
 
@@ -39,7 +30,7 @@ describe('Config Unit Tests', function() {
     context('when a relative path string to a .npmpackagejsonlintrc file is passed', function() {
       it('the config object should return the parsed JSON as an object', function() {
         const passedConfig = './.npmpackagejsonlintrc';
-        const config = new Config(passedConfig);
+        const config = new Config(passedConfig, {});
         const expectedConfigObj = {
           'version-type': 'error'
         };
@@ -54,7 +45,7 @@ describe('Config Unit Tests', function() {
     context('when an absolute path string to a .npmpackagejsonlintrc file is passed', function() {
       it('the config object should return the parsed JSON as an object', function() {
         const passedConfig = '/Users/awesomeUser/.npmpackagejsonlintrc';
-        const config = new Config(passedConfig);
+        const config = new Config(passedConfig, {});
         const expectedConfigObj = {
           'version-type': 'error'
         };
@@ -85,7 +76,7 @@ describe('Config Unit Tests', function() {
     context('when a config object is passed with an extends node', function() {
       it('the extends config and rules node should be merged', function() {
         const passedConfig = './.npmpackagejsonlintrc';
-        const config = new Config(passedConfig);
+        const config = new Config(passedConfig, {});
         const stubbedGetExtendCfgModule = sinon.stub(config, '_getExtendsConfigModule');
         const extendsObj = {
           rules: {
@@ -110,7 +101,7 @@ describe('Config Unit Tests', function() {
 
       it('and they both contain the same rule the main rules node should take precedence', function() {
         const passedConfig = './.npmpackagejsonlintrc';
-        const config = new Config(passedConfig);
+        const config = new Config(passedConfig, {});
         const stubbedGetExtendCfgModule = sinon.stub(config, '_getExtendsConfigModule');
         const extendsObj = {
           rules: {
@@ -140,7 +131,7 @@ describe('Config Unit Tests', function() {
             'version-type': 'warning'
           }
         };
-        const config = new Config(passedConfig);
+        const config = new Config(passedConfig, {});
         const extendsObj = {
           rules: {
             'version-type': 'warning'
@@ -165,7 +156,7 @@ describe('Config Unit Tests', function() {
         const passedConfig = {
           'extends': 'npm-package-json-lint-config-tc'
         };
-        const config = new Config(passedConfig);
+        const config = new Config(passedConfig, {});
         const extendsObj = {
           rules: {
             'version-type': 'warning'
@@ -197,7 +188,7 @@ describe('Config Unit Tests', function() {
             'valid-values-private': ['warning', [true, false]]
           }
         };
-        const config = new Config(rcFileObj);
+        const config = new Config(rcFileObj, {});
         const expectedConfigObj = {
           'require-author': 'error',
           'require-version': 'warning',
@@ -210,6 +201,184 @@ describe('Config Unit Tests', function() {
     });
   });
 
+  context('_getUserConfig tests', function() {
+    context('when config is passed', function() {
+      it('the passed config should be returned', function() {
+        const rulesObj = {
+          rules: {
+            'require-author': 'error',
+            'require-version': 'warning',
+            'valid-values-author': ['error', ['Thomas', 'Lindner', 'Thomas Lindner']],
+            'valid-values-private': ['warning', [true, false]]
+          }
+        };
+        const config = new Config(rulesObj, {});
+        const stubIsConfigPassed = sinon.stub(config, '_isConfigPassed').returns(true);
+        const stubGetPassedConfig = sinon.stub(config, '_getPassedConfig').returns(rulesObj);
+
+        config._getUserConfig().should.eql(rulesObj);
+
+        config._isConfigPassed.restore();
+        config._getPassedConfig.restore();
+      });
+    });
+
+    context('when config is passed in the package.json file', function() {
+      it('the config should be returned', function() {
+        const calledZeroTimes = 0;
+        const rulesObj = {
+          rules: {
+            'require-author': 'error',
+            'require-version': 'warning',
+            'valid-values-author': ['error', ['Thomas', 'Lindner', 'Thomas Lindner']],
+            'valid-values-private': ['warning', [true, false]]
+          }
+        };
+        const pkgJson = {
+          npmPackageJsonLintConfig: rulesObj
+        };
+        const config = new Config({}, pkgJson);
+        const stubIsConfigPassed = sinon.stub(config, '_isConfigPassed').returns(false);
+        const spyGetPassedConfig = sinon.spy(config, '_getPassedConfig');
+
+        config._getUserConfig().should.eql(rulesObj);
+        spyGetPassedConfig.callCount.should.eql(calledZeroTimes);
+
+        config._isConfigPassed.restore();
+        config._getPassedConfig.restore();
+      });
+    });
+
+    context('when _isConfigFileExist is true', function() {
+      it('the config should be returned', function() {
+        const calledZeroTimes = 0;
+        const rulesObj = {
+          rules: {
+            'require-author': 'error',
+            'require-version': 'warning',
+            'valid-values-author': ['error', ['Thomas', 'Lindner', 'Thomas Lindner']],
+            'valid-values-private': ['warning', [true, false]]
+          }
+        };
+        const config = new Config(rulesObj, {});
+        const stubIsConfigPassed = sinon.stub(config, '_isConfigPassed').returns(false);
+        const spyGetPassedConfig = sinon.spy(config, '_getPassedConfig');
+        const stubGetRelativeConfigFilePath = sinon.stub(config, '_getRelativeConfigFilePth').returns('/home/user/project/.npmpackagejsonlintrc.json');
+        const stubIsConfigFileExist = sinon.stub(config, '_isConfigFileExist').returns(true);
+        const stubLoadConfigFile = sinon.stub(config, '_loadRcFile').returns(rulesObj);
+
+        config._getUserConfig().should.eql(rulesObj);
+        spyGetPassedConfig.callCount.should.eql(calledZeroTimes);
+
+        config._isConfigPassed.restore();
+        config._getPassedConfig.restore();
+        config._getRelativeConfigFilePth.restore();
+        config._isConfigFileExist.restore();
+        config._loadRcFile.restore();
+      });
+    });
+
+    context('when _loadRcFile is true', function() {
+      it('the passed config should be returned', function() {
+        const calledZeroTimes = 0;
+        const rulesObj = {
+          rules: {
+            'require-author': 'error',
+            'require-version': 'warning',
+            'valid-values-author': ['error', ['Thomas', 'Lindner', 'Thomas Lindner']],
+            'valid-values-private': ['warning', [true, false]]
+          }
+        };
+        const config = new Config(rulesObj, {});
+        const stubIsConfigPassed = sinon.stub(config, '_isConfigPassed').returns(false);
+        const spyGetPassedConfig = sinon.spy(config, '_getPassedConfig');
+        const stubGetRelativeConfigFilePath = sinon.stub(config, '_getRelativeConfigFilePth').returns('/home/user/project/.npmpackagejsonlintrc.json');
+        const stubIsConfigFileExist = sinon.stub(config, '_isConfigFileExist')
+          .onFirstCall()
+          .returns(false)
+          .onSecondCall()
+          .returns(true);
+        const spyLoadRcFile = sinon.spy(config, '_loadRcFile');
+        const stubGetUserHomeConfigFilePath = sinon.stub(config, '_getUsrHmConfigFilePath').returns('/home/user/project/npmpackagejsonlint.config.js');
+        const stubLoadConfigFile = sinon.stub(config, '_loadConfigFile').returns(rulesObj);
+
+        config._getUserConfig().should.eql(rulesObj);
+        spyGetPassedConfig.callCount.should.eql(calledZeroTimes);
+        spyLoadRcFile.callCount.should.eql(calledZeroTimes);
+
+        config._isConfigPassed.restore();
+        config._getPassedConfig.restore();
+        config._getRelativeConfigFilePth.restore();
+        config._isConfigFileExist.restore();
+        config._loadRcFile.restore();
+        config._loadConfigFile.restore();
+        config._getUsrHmConfigFilePath.restore();
+      });
+    });
+
+    context('when config is passed', function() {
+      it('the passed config should be returned', function() {
+        const calledZeroTimes = 0;
+        const rulesObj = {
+          rules: {
+            'require-author': 'error',
+            'require-version': 'warning',
+            'valid-values-author': ['error', ['Thomas', 'Lindner', 'Thomas Lindner']],
+            'valid-values-private': ['warning', [true, false]]
+          }
+        };
+        const config = new Config(rulesObj, {});
+        const stubIsConfigPassed = sinon.stub(config, '_isConfigPassed').returns(false);
+        const spyGetPassedConfig = sinon.spy(config, '_getPassedConfig');
+        const stubGetRelativeConfigFilePath = sinon.stub(config, '_getRelativeConfigFilePth').returns('/home/user/project/.npmpackagejsonlintrc.json');
+        const stubIsConfigFileExist = sinon.stub(config, '_isConfigFileExist').returns(false);
+        const stubGetUserHomeConfigFilePath = sinon.stub(config, '_getUsrHmConfigFilePath').returns('/home/user/project/npmpackagejsonlint.config.js');
+        const spyLoadConfigFile = sinon.spy(config, '_loadConfigFile');
+
+        (function() {
+          config._getUserConfig();
+        }).should.throw('No configuration found');
+        spyGetPassedConfig.callCount.should.eql(calledZeroTimes);
+        spyLoadConfigFile.callCount.should.eql(calledZeroTimes);
+
+        config._isConfigPassed.restore();
+        config._getPassedConfig.restore();
+        config._getRelativeConfigFilePth.restore();
+        config._isConfigFileExist.restore();
+        config._loadConfigFile.restore();
+        config._getUsrHmConfigFilePath.restore();
+      });
+    });
+  });
+
+  context('_getRelativeConfigFilePth tests', function() {
+    context('when config is passed', function() {
+      it('the passed config should be returned', function() {
+        const cwd = '/home/user/project/';
+        const fileName = '.npmpackagejsonfilerc.json';
+        const config = new Config({}, {});
+        const stubIsConfigPassed = sinon.stub(process, 'cwd').returns(cwd);
+
+        config._getRelativeConfigFilePth(fileName).should.eql(`${cwd}${fileName}`);
+
+        process.cwd.restore();
+      });
+    });
+  });
+
+  context('_isConfigFileExist tests', function() {
+    context('when config is passed', function() {
+      it('the passed config should be returned', function() {
+        const config = new Config({}, {});
+        const stubIsConfigPassed = sinon.stub(fs, 'existsSync').returns(true);
+
+        config._isConfigFileExist('filePath').should.be.true;
+
+        fs.existsSync.restore();
+      });
+    });
+  });
+
   context('_validateRulesConfig tests', function() {
     context('when a valid npmpackagejsonlintrc file object is passed', function() {
       it('true should be returned', function() {
diff --git a/tests/unit/cli.test.js b/tests/unit/cli.test.js
index 3619956..7133563 100755
--- a/tests/unit/cli.test.js
+++ b/tests/unit/cli.test.js
@@ -224,4 +224,36 @@ ${figures.warning} require-scripts - node: scripts - scripts is required
       cli.stdout.toString().should.equal(expected);
     });
   });
+
+  context('when the cli has the config as a package.json property', function() {
+    it('and one error, one warning is expected', function() {
+      const cli = spawnSync('./../../../src/cli.js', [], {cwd: 'tests/fixtures/packageJsonProperty/'});
+      const expected = `1 error
+${figures.cross} require-scripts - node: scripts - scripts is required
+
+1 warning
+${figures.warning} require-license - node: license - license is required
+
+./package.json check complete
+`;
+
+      cli.stdout.toString().should.equal(expected);
+    });
+  });
+
+  context('when the cli has the config as a JavaScript export', function() {
+    it('and one error, one warning is expected', function() {
+      const cli = spawnSync('./../../../src/cli.js', [], {cwd: 'tests/fixtures/configJavaScriptFile/'});
+      const expected = `1 error
+${figures.cross} require-scripts - node: scripts - scripts is required
+
+1 warning
+${figures.warning} require-license - node: license - license is required
+
+./package.json check complete
+`;
+
+      cli.stdout.toString().should.equal(expected);
+    });
+  });
 });