yarn upgrade で更新できない間接的な依存パッケージだけをアップグレードするには

## TL; DR:

yarn v1 の場合、 yarn.lock から当該のパッケージのセクションを削除して `yarn install` すればアップグレードできる。

**2021年9月9日追記：** yarn v2 以降では `yarn up -R パッケージ` でアップグレードできるようになった。

## 困ったこと
GitHub にソースコードをホストしているとある npm パッケージにおいて、 GitHub の Security Alerts が `fstream < 1.0.12` の脆弱性を報告した。

<img width="224" alt="スクリーンショット 2019-06-03 11.25.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/735/ceddfbfa-6cff-8533-1389-e18c090df000.png">

`yarn upgrade fstream` で最新バージョンにアップグレードしようとしたが……

```
$ cd my_npm_pkg

$ yarn upgrade fstream
yarn upgrade v1.16.0
[1/5] 🔍  Validating package.json...
[2/5] 🔍  Resolving packages...
[3/5] 🚚  Fetching packages...
[4/5] 🔗  Linking dependencies...
warning " > react-on-rails@8.0.3" has unmet peer dependency "babel-runtime@>= 6".
[5/5] 🔨  Rebuilding all packages...
success Saved lockfile.
success Saved 0 new dependencies.
✨  Done in 7.07s.

$ git diff
（出力なし）
```

実行しても yarn.lock が変化しない。これは、この npm パッケージが fstream に直接的に依存していないためだった。

## 調査

どのパッケージが fstream に依存しているかは `yarn why fstream` で分かる：

```
$ yarn why fstream
yarn why v1.16.0
[1/4] 🤔  Why do we have the module "fstream"...?
[2/4] 🚚  Initialising dependency graph...
[3/4] 🔍  Finding dependency...
[4/4] 🚡  Calculating file sizes...
=> Found "fstream@1.0.11"
info Reasons this module exists
   - "node-sass#node-gyp" depends on it
   - Hoisted from "node-sass#node-gyp#fstream"
   - Hoisted from "node-sass#node-gyp#tar#fstream"
info Disk size without dependencies: "140KB"
info Disk size with unique dependencies: "416KB"
info Disk size with transitive dependencies: "788KB"
info Number of shared dependencies: 12
✨  Done in 0.70s.
```

元を辿れば、（この npm パッケージが直接的に依存している） node-sass が間接的に fstream を引き入れたようだ。

## 解決策
### 1. node-sass をインストールし直す
`yarn remove node-sass && yarn add -D node-sass` で node-sass をインストールし直せば今回は解決すると思われる。

ただ、こうすると node-sass が依存するパッケージがすべてアップグレードされてしまう。互換性のある semver の範囲内でアップグレードされるとはいえ、一応差分をチェックしないと安心できない。もし今後同様の状況になって、 fstream に依存するパッケージが複数に増えていたら、差分はさらに大きくなることが予想される。可能なら fstream だけアップグレードしたい。

### 2. yarn.lock から fstream を消して `yarn install`
yarn.lock から fstream を消して `yarn install` すればどうかと思い試してみた。

まずは yarn.lock から fstream で始まる行を探し、そのセクションを丸ごと削除する。

```diff
$ git diff
diff --git a/yarn.lock b/yarn.lock
index 3983d00b8b..9a3e1ef0cf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3624,15 +3624,6 @@ fsevents@^1.2.7:
     nan "^2.9.2"
     node-pre-gyp "^0.10.0"

-fstream@^1.0.0, fstream@^1.0.2:
-  version "1.0.11"
-  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
-  dependencies:
-    graceful-fs "^4.1.2"
-    inherits "~2.0.0"
-    mkdirp ">=0.5 0"
-    rimraf "2"
-
 function-bind@^1.0.2, function-bind@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
```

`yarn install` を実行し、 yarn.lock が更新されたか見てみる。

```
$ yarn install
（略）
```

```diff
$ git diff
diff --git a/yarn.lock b/yarn.lock
index 3983d00b8b..3a44640600 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3625,8 +3625,9 @@ fsevents@^1.2.7:
     node-pre-gyp "^0.10.0"

 fstream@^1.0.0, fstream@^1.0.2:
-  version "1.0.11"
-  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
+  version "1.0.12"
+  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
+  integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==
   dependencies:
     graceful-fs "^4.1.2"
     inherits "~2.0.0" 
```

fstream のセクションが復活し、最新バージョンにアップグレードされたことが分かる。

## yarn.lock の一部を書き換えてもいいのか？
yarn の依存解決アルゴリズムを理解しているわけではないが、多分大丈夫だろう。 yarn.lock に書かれているべきパッケージが抜け落ちていれば、 `yarn install` は自動的にパッケージをインストールして yarn.lock に追記すると思われる。 package.json の dependencies に手でパッケージを書き加えてから `yarn install` するのと状況は同じなのだから。

## 備考：環境
- node 10.16.0
- npm 6.9.0
- yarn 1.16.0 (yarn lockfile v1)