eslint-plugin-strict-dependenciesを使ってみる

:::note
## 概要
[eslint-plugin-strict-dependencies](https://github.com/knowledge-work/eslint-plugin-strict-dependencies)は
- `module`,`allowReferenceFrom`の設定を個別に指定することでpackage-privateは実現できます！
- 以下を再調査します
    - ルールの`allowSameModule`,`excludeTypeImportChecks`
    - オプションの`pathIndexMap`
:::

# 1. 背景 🖼️
TypeScirptではexport宣言した変数や関数は全てのファイルからimportできてしまいます。
しかし、モジュール内に処理をまとめすぎると肥大化してしまいます 😢

package-privateが実現できれば外部のディレクトリからimportを制限できたり、モジュール管理がしやすくなると思います。

この記事でeslint-plugin-strict-dependenciesについて触れてはいます。
使い込んでみたいと思い今回細かく調査します！ 🕵️

https://qiita.com/yamatai12/items/f954e7282444b2b4273b

:::note
ESLint,typescript-eslintの設定はこちらで紹介していますのでご覧ください！
[Eslintとtypescript-eslintを手動で設定してみる](https://qiita.com/yamatai12/items/d48fa55bddbfb3c1dc7d)
:::

# 2. eslint-plugin-strict-dependenciesとは 🤔

https://github.com/knowledge-work/eslint-plugin-strict-dependencies

カスタムモジュールの依存関係のルールを定義するためのESLintプラグインです。

# 3. eslint-plugin-strict-dependenciesの設定 🚧

## install
```terminal
npm install eslint-plugin-strict-dependencies --save-dev
```

## 設定ファイルの修正
- strictDependenciesをimport
- pluginとruleを追加

```js:eslint.config.js
import typescriptEslintParser from "@typescript-eslint/parser";
import js from "@eslint/js";
import tseslint from 'typescript-eslint';
import strictDependencies from 'eslint-plugin-strict-dependencies';

export default [
    {languageOptions: {
        parser: typescriptEslintParser,
        parserOptions: {
          project: true,
          sourceType: "module",
        },
      }
    },
    js.configs.recommended,
    ...tseslint.configs.recommended,
    {
        plugins: {
          "strict-dependencies": strictDependencies,
        },
    },
   {
       rules: {
        "strict-dependencies/strict-dependencies": [
          "error",[
          {
              "module": "sub",// importされるmoduleのパス
              "allowReferenceFrom": ["sub"],// import可能なmoduleのパス
          },
          ]
        ]
       }
   }
];

```

# 4. エラーになるか試す 🚨
```terminal
.
├── call.ts
├── eslint.config.js
├── node_modules
├── package-lock.json
├── package.json
├── sub
│   ├── call.ts
│   └── called.ts
└── tsconfig.json
```

```call.ts
import { called } from "sub/called";
```
`sub`ディレクトリの外にある、`call.ts`が`sub/called.ts`の`called`をimportします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405182/41f248f6-1bc5-17a4-9cbc-e12becfe7f39.png)

エラーが表示されました！ 🚨

# 5. その他ルール 👮
## `targetMembers`
importを制限する対象を指定することが可能です。
指定しない場合は全てのexportされた宣言が対象になります。

```js:eslint.config.js
rules: {
        "strict-dependencies/strict-dependencies": [
          "error",[{
            "module": "sub",// importされるmoduleのパス
            "allowReferenceFrom": ["sub"],// import可能なmoduleのパス
            "targetMembers":["cae"] // caeという宣言されたものを対象にする
          },]
        ]
       }
```

`cae`という宣言は存在しないので、subディレクトリ配下のモジュールの宣言は全てimport可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405182/4b4a11c9-3b61-9b84-dbab-3f3f45c23e0a.png)

`call.ts`から`sub/called`の`called`をimportできました。

## `allowSameModule`
同じディレクトリにある他のファイルからインポートできるかを指定します。
```js:eslint.config.js
rules: {
        "strict-dependencies/strict-dependencies": [
          "error",[{
            "module": "sub",// importされるmoduleのパス
            "allowReferenceFrom": ["sub"],// import可能なmoduleのパス
            "allowSameModule": false
          },]
        ]
       }
```

:::note
`true`にしても同一ディレクトリ内でimportができてしまいましたのでまた調査します。。 😇
:::

## `excludeTypeImportChecks`
型のインポートには柔軟性を持たせたい場合に使うそうです。
`import type { SampleType } from 'called'`
`import { SampleType } from 'called'`
どちらの記述でも許可されます。

:::note
`false`にしてもどちらの記述でも許可されてしまいましたのでまた調査します。。 😇
:::

# 6. オプション ⚙️
## `resolveRelativeImport`
importのパスで相対パスを解決するかどうかです。
defaultは`false`です。

```js:eslint.config.js
rules: {
        "strict-dependencies/strict-dependencies": [
          "error",[{
            "excludeTypeImportChecks": true,
            "module": "sub",// importされるmoduleのパス
            "allowReferenceFrom": ["sub"],// import可能なmoduleのパス
          },
          {
          "resolveRelativeImport": false
          }
        ]
        ]
       }
```

相対パスで書くとlintの対象外になります（デフォルトでもです）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405182/475655a9-d3bd-3264-1b24-ce362c281036.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405182/fbe7ca76-ea49-e635-07ea-412bdc9cabc1.png)

## `pathIndexMap`
eslint-plugin-strict-dependenciesでは、tsconfigで指定されたパスに基づいてパスエイリアスの解決が行われます。

デフォルトでは、インデックス番号0の値が使用されます、任意のインデックス番号の値を使用するオプションを指定することができます。

```tsconfig.json
{
  "compilerOptions": {
      "paths": {
          "*": ["aaa/*", "bbb/*"]
      }
    },
}
```

`pathIndexMap = { "*": 1 }`にすると "bbb/*" が指定されるそうです。



:::note
`pathIndexMap`を`0`,`1`どちらにしても許可されてしまいましたのでまた調査します。。 😇
:::

# 最後に
- 以下を再調査します
    - ルールの`allowSameModule`,`excludeTypeImportChecks`
    - オプションの`pathIndexMap`
- `module`,`allowReferenceFrom`の設定を個別に指定することでpackage-privateは実現できます！

# 他にも依存関係の管理に関する記事を書いています 💪

https://qiita.com/yamatai12/items/fce4104e273981f78807

https://qiita.com/yamatai12/items/b91f785ecd3091833c01

本記事を読んで頂き、ありがとうございました。
いいねいただけると記事執筆の励みになりますので、参考になったと思われた方は是非よろしくお願い致します🙏