Repository: eslint/eslint (js)

Issue:
Remove dependency to user-home
/cc @platinumazure 

[user-home dependency](https://github.com/sindresorhus/user-home), seems unnecessary since it can be replaced by a call to the NodeJS [os.homedir()](https://nodejs.org/api/os.html#os_os_homedir). Specifically

* [user-home](https://github.com/sindresorhus/user-home) simply wraps [os-homedir](https://github.com/sindresorhus/os-homedir/blob/master/index.js).
* os-homedir [delegates](https://github.com/sindresorhus/os-homedir/blob/master/index.js#L24) to Node JS [os.homedir()](https://nodejs.org/api/os.html#os_os_homedir) if it exists, which should always exist for NodeJS versions that ESLint cares about (it was added at v2.3.0)

Pull request:
Chore: Remove dependency to user-home (fixes #8604)
**What is the purpose of this pull request? (put an "X" next to item)**

[ ] Documentation update
[ ] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/bug-report.md))
[ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-proposal.md))
[ ] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-change-proposal.md))
[ ] Add autofixing to a rule
[ ] Add a CLI option
[ ] Add something to the core
[x] Other, please explain:

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (http://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

**What changes did you make? (Give an overview)**
Module user-home dependency replaced with core module os.homedir().

**Is there anything you'd like reviewers to focus on?**
I had little trouble with mocking os.pathname(), can you check if is it correct, please?



Patch:
diff --git a/docs/developer-guide/shareable-configs.md b/docs/developer-guide/shareable-configs.md
index 10a9231c7..23d6a3fef 100644
--- a/docs/developer-guide/shareable-configs.md
+++ b/docs/developer-guide/shareable-configs.md
@@ -4,7 +4,11 @@ The configuration that you have in your `.eslintrc` file is an important part of
 
 ## Creating a Shareable Config
 
-Shareable configs are simply npm packages that export a configuration object. To start, [create a Node.js module](https://docs.npmjs.com/getting-started/creating-node-modules) like you normally would. Make sure the module name begins with `eslint-config-`, such as `eslint-config-myconfig`. Create a new `index.js` file and export an object containing your settings:
+Shareable configs are simply npm packages that export a configuration object. To start, [create a Node.js module](https://docs.npmjs.com/getting-started/creating-node-modules) like you normally would. Make sure the module name begins with `eslint-config-`, such as `eslint-config-myconfig`.
+
+npm [scoped modules](https://docs.npmjs.com/misc/scope) are also supported, by naming or prefixing the module with `@scope/eslint-config`, such as `@scope/eslint-config` or `@scope/eslint-config-myconfig`.
+
+Create a new `index.js` file and export an object containing your settings:
 
 ```js
 module.exports = {
@@ -66,6 +70,35 @@ You can also omit the `eslint-config-` and it will be automatically assumed by E
 }
 ```
 
+### npm scoped modules
+
+npm [scoped modules](https://docs.npmjs.com/misc/scope) are also supported in a number of ways.
+
+
+By using the module name:
+
+```json
+{
+    "extends": "@scope/eslint-config"
+}
+```
+
+You can also omit the `eslint-config` and it will be automatically assumed by ESLint:
+
+```json
+{
+    "extends": "@scope"
+}
+```
+
+The module name can also be customized, just note that when using [scoped modules](https://docs.npmjs.com/misc/scope) it is not possible to omit the `eslint-config-` prefix. Doing so would result in package naming conflicts, and thus in resolution errors in most of cases. For example a package named `@scope/eslint-config-myconfig` vs `@scope/my-config`, since both are valid scoped package names, the configuration should be specified as:
+
+```json
+{
+    "extends": "@scope/eslint-config-myconfig"
+}
+```
+
 You can override settings from the shareable config by adding them directly into your `.eslintrc` file.
 
 ## Sharing Multiple Configs
@@ -90,6 +123,14 @@ Then, assuming you're using the package name `eslint-config-myconfig`, you can a
 }
 ```
 
+When using [scoped modules](https://docs.npmjs.com/misc/scope) it is not possible to omit the `eslint-config` namespace. Doing so would result in resolution errors as explained above. Assuming the package name is `@scope/eslint-config`, the additional config can be accessed as:
+
+```json
+{
+    "extends": "@scope/eslint-config/my-special-config"
+}
+```
+
 Note that you can leave off the `.js` from the filename. In this way, you can add as many additional configs to your package as you'd like.
 
 **Important:** We strongly recommend always including a default config for your plugin to avoid errors.
diff --git a/lib/config.js b/lib/config.js
index 0c36d5e1b..81baef608 100644
--- a/lib/config.js
+++ b/lib/config.js
@@ -10,11 +10,11 @@
 //------------------------------------------------------------------------------
 
 const path = require("path"),
+    os = require("os"),
     ConfigOps = require("./config/config-ops"),
     ConfigFile = require("./config/config-file"),
     Plugins = require("./config/plugins"),
     FileFinder = require("./file-finder"),
-    userHome = require("user-home"),
     isResolvable = require("is-resolvable"),
     pathIsInside = require("path-is-inside");
 
@@ -24,7 +24,7 @@ const debug = require("debug")("eslint:config");
 // Constants
 //------------------------------------------------------------------------------
 
-const PERSONAL_CONFIG_DIR = userHome || null;
+const PERSONAL_CONFIG_DIR = os.homedir() || null;
 
 //------------------------------------------------------------------------------
 // Helpers
@@ -79,6 +79,7 @@ function getPersonalConfig(configContext) {
     let config;
 
     if (PERSONAL_CONFIG_DIR) {
+
         const filename = ConfigFile.getFilenameForDirectory(PERSONAL_CONFIG_DIR);
 
         if (filename) {
diff --git a/package.json b/package.json
index ec10a6911..78a49ed5c 100644
--- a/package.json
+++ b/package.json
@@ -65,8 +65,7 @@
     "require-uncached": "^1.0.3",
     "strip-json-comments": "~2.0.1",
     "table": "^4.0.1",
-    "text-table": "~0.2.0",
-    "user-home": "^2.0.0"
+    "text-table": "~0.2.0"
   },
   "devDependencies": {
     "babel-polyfill": "^6.23.0",


Test patch:
diff --git a/tests/lib/config.js b/tests/lib/config.js
index d1b2eaea3..4df756d90 100644
--- a/tests/lib/config.js
+++ b/tests/lib/config.js
@@ -117,6 +117,17 @@ describe("Config", () => {
             .returns(fakeCWDPath);
     }
 
+    /**
+     * Mocks the current user's home path
+     * @param {string} fakeUserHomePath - fake user's home path
+     * @returns {void}
+     * @private
+     */
+    function mockOsHomedir(fakeUserHomePath) {
+        sandbox.stub(os, "homedir")
+            .returns(fakeUserHomePath);
+    }
+
     // copy into clean area so as not to get "infected" by this project's .eslintrc files
     before(() => {
         fixtureDir = `${os.tmpdir()}/eslint/fixtures`;
@@ -269,7 +280,8 @@ describe("Config", () => {
             const configPath = path.resolve(__dirname, "..", "fixtures", "configurations", "foobaz", ".eslintrc");
             const homePath = "does-not-exist";
 
-            const StubbedConfig = proxyquire("../../lib/config", { "user-home": homePath });
+            mockOsHomedir(homePath);
+            const StubbedConfig = proxyquire("../../lib/config", {});
 
             const configHelper = new StubbedConfig({ cwd: process.cwd() }, linter);
 
@@ -831,7 +843,8 @@ describe("Config", () => {
                     homePath = getFakeFixturePath("personal-config", "home-folder"),
                     filePath = getFakeFixturePath("personal-config", "project-without-config", "foo.js");
 
-                const StubbedConfig = proxyquire("../../lib/config", { "user-home": homePath });
+                mockOsHomedir(homePath);
+                const StubbedConfig = proxyquire("../../lib/config", {});
 
                 mockPersonalConfigFileSystem();
                 mockCWDResponse(projectPath);
@@ -856,7 +869,8 @@ describe("Config", () => {
                     homePath = getFakeFixturePath("personal-config", "home-folder"),
                     filePath = getFakeFixturePath("personal-config", "home-folder", "project", "foo.js");
 
-                const StubbedConfig = proxyquire("../../lib/config", { "user-home": homePath });
+                mockOsHomedir(homePath);
+                const StubbedConfig = proxyquire("../../lib/config", {});
 
                 mockPersonalConfigFileSystem();
                 mockCWDResponse(projectPath);
@@ -882,7 +896,8 @@ describe("Config", () => {
                     homePath = getFakeFixturePath("personal-config", "home-folder"),
                     filePath = getFakeFixturePath("personal-config", "project-without-config", "foo.js");
 
-                const StubbedConfig = proxyquire("../../lib/config", { "user-home": homePath });
+                mockOsHomedir(homePath);
+                const StubbedConfig = proxyquire("../../lib/config", {});
 
                 mockPersonalConfigFileSystem();
                 mockCWDResponse(projectPath);
@@ -906,7 +921,8 @@ describe("Config", () => {
                 const projectPath = getFakeFixturePath("personal-config", "project-with-config"),
                     filePath = getFakeFixturePath("personal-config", "project-with-config", "subfolder", "foo.js");
 
-                const StubbedConfig = proxyquire("../../lib/config", { "user-home": projectPath });
+                mockOsHomedir(projectPath);
+                const StubbedConfig = proxyquire("../../lib/config", {});
 
                 mockPersonalConfigFileSystem();
                 mockCWDResponse(projectPath);
@@ -969,7 +985,8 @@ describe("Config", () => {
                     homePath = getFakeFixturePath("personal-config", "folder-does-not-exist"),
                     filePath = getFakeFixturePath("personal-config", "project-without-config", "foo.js");
 
-                const StubbedConfig = proxyquire("../../lib/config", { "user-home": homePath });
+                mockOsHomedir(homePath);
+                const StubbedConfig = proxyquire("../../lib/config", {});
 
                 mockPersonalConfigFileSystem();
                 mockCWDResponse(projectPath);
@@ -986,7 +1003,8 @@ describe("Config", () => {
                     homePath = getFakeFixturePath("personal-config", "home-folder-with-packagejson"),
                     filePath = getFakeFixturePath("personal-config", "project-without-config", "foo.js");
 
-                const StubbedConfig = proxyquire("../../lib/config", { "user-home": homePath });
+                mockOsHomedir(homePath);
+                const StubbedConfig = proxyquire("../../lib/config", {});
 
                 mockPersonalConfigFileSystem();
                 mockCWDResponse(projectPath);
@@ -1003,7 +1021,8 @@ describe("Config", () => {
                     homePath = getFakeFixturePath("personal-config", "folder-does-not-exist"),
                     filePath = getFakeFixturePath("personal-config", "project-without-config", "foo.js");
 
-                const StubbedConfig = proxyquire("../../lib/config", { "user-home": homePath });
+                mockOsHomedir(homePath);
+                const StubbedConfig = proxyquire("../../lib/config", {});
 
                 mockPersonalConfigFileSystem();
                 mockCWDResponse(projectPath);
@@ -1023,7 +1042,8 @@ describe("Config", () => {
                     homePath = getFakeFixturePath("personal-config", "folder-does-not-exist"),
                     filePath = getFakeFixturePath("personal-config", "project-without-config", "foo.js");
 
-                const StubbedConfig = proxyquire("../../lib/config", { "user-home": homePath });
+                mockOsHomedir(homePath);
+                const StubbedConfig = proxyquire("../../lib/config", {});
 
                 mockPersonalConfigFileSystem();
                 mockCWDResponse(projectPath);
@@ -1043,7 +1063,8 @@ describe("Config", () => {
                     homePath = getFakeFixturePath("personal-config", "folder-does-not-exist"),
                     filePath = getFakeFixturePath("personal-config", "project-without-config", "foo.js");
 
-                const StubbedConfig = proxyquire("../../lib/config", { "user-home": homePath });
+                mockOsHomedir(homePath);
+                const StubbedConfig = proxyquire("../../lib/config", {});
 
                 mockPersonalConfigFileSystem();
                 mockCWDResponse(projectPath);
diff --git a/tests/lib/config/config-file.js b/tests/lib/config/config-file.js
index 3c0256365..a8f6046d2 100644
--- a/tests/lib/config/config-file.js
+++ b/tests/lib/config/config-file.js
@@ -13,14 +13,15 @@ const assert = require("chai").assert,
     sinon = require("sinon"),
     path = require("path"),
     fs = require("fs"),
+    os = require("os"),
     yaml = require("js-yaml"),
-    userHome = require("user-home"),
     shell = require("shelljs"),
     environments = require("../../../conf/environments"),
     ConfigFile = require("../../../lib/config/config-file"),
     Linter = require("../../../lib/linter"),
     Config = require("../../../lib/config");
 
+const userHome = os.homedir();
 const temp = require("temp").track();
 const proxyquire = require("proxyquire").noCallThru().noPreserveCache();
 const configContext = new Config({}, new Linter());