ESLintカスタムルール: Vueコンポーネントの`components`プロパティをソートする

Vue.jsアプリケーションの開発において、コードの一貫性と可読性を高めるために、ESLintカスタムルールを導入して`components`オプション内のコンポーネント定義をアルファベット順に強制することができます。このルールは、コンポーネントの定義順序が誤っている場合に警告を発し、自動修正も提供します。

1. カスタムESLintルールの定義

まず、ESLintカスタムルールファイルを作成します。例えば、`your-rules/sort-vue-components.js`というファイル名で保存します。

module.exports = {
  meta: {
    type: 'suggestion',
    docs: {
      description: 'Vueコンポーネントの`components`オプション内のプロパティをアルファベット順にソートします。',
      category: 'Stylistic Issues',
      recommended: false,
    },
    fixable: 'code', // 自動修正可能
    schema: [], // ルールにオプションはなし
  },
  create(context) {
    return {
      // デフォルトエクスポートを監視
      ExportDefaultDeclaration(node) {
        if (node.declaration.type !== 'ObjectExpression') {
          return; // オブジェクトリテラルではない場合は処理しない
        }

        const componentProps = node.declaration.properties;
        const componentsOptionNode = componentProps.find(
          prop => prop.key.type === 'Identifier' && prop.key.name === 'components'
        );

        // 'components'プロパティが存在しないか、オブジェクトではない場合は処理しない
        if (!componentsOptionNode || componentsOptionNode.value.type !== 'ObjectExpression') {
          return;
        }

        const componentEntries = componentsOptionNode.value.properties;
        if (componentEntries.length < 2) {
          return; // 1つ以下のコンポーネント定義はソートの必要がない
        }

        // 現在の定義を名前でソート
        const sortedEntries = [...componentEntries].sort((a, b) =>
          a.key.name.localeCompare(b.key.name)
        );

        // 現在の順序とソートされた順序を比較
        for (let i = 0; i < componentEntries.length; i++) {
          if (componentEntries[i] !== sortedEntries[i]) {
            const currentComponentName = componentEntries[i].key.name;
            const expectedComponentName = sortedEntries[i].key.name;

            context.report({
              node: componentEntries[i],
              message: `コンポーネントの定義はアルファベット順にソートされるべきです。'${currentComponentName}'は'${expectedComponentName}'の位置に来るべきです。`,
              fix(fixer) {
                const sourceCode = context.getSourceCode();
                const sortedText = sortedEntries
                  .map(entry => sourceCode.getText(entry))
                  .join(',\n');

                // 'components'オブジェクトの中身全体を置き換える
                const startOffset = componentsOptionNode.value.range[0] + 1; // 開始ブレース '{' の直後
                const endOffset = componentsOptionNode.value.range[1] - 1;   // 終了ブレース '}' の直前
                return fixer.replaceTextRange([startOffset, endOffset], sortedText);
              },
            });
            // 最初の不順な項目を報告したら、残りの項目は同じ自動修正で対処されるため、ここで処理を終了
            break;
          }
        }
      },
    };
  },
};

このルールは以下の動作を実行します。

  1. ファイル内のデフォルトエクスポートの抽象構文木(AST)ノードである`ExportDefaultDeclaration`を監視します。
  2. デフォルトエクスポートがオブジェクトリテラルであることを確認します。
  3. そのオブジェクト内で`components`という名前のプロパティを検索します。
  4. `components`プロパティが存在し、それがオブジェクトリテラルである場合、その中のコンポーネント定義をアルファベット順にチェックします。
  5. もし定義順序が正しくない場合、ESLintは問題を報告し、自動修正機能を提供して正しい順序に並べ替えます。

2. .eslintrc.jsでのカスタムルールの利用

次に、プロジェクトの`.eslintrc.js`ファイルに上記のカスタムルールを参照する設定を追加します。これにより、ESLintがVueコンポーネントファイルでこのルールを適用するようになります。

module.exports = {
  root: true,
  env: {
    node: true,
  },
  parserOptions: {
    ecmaVersion: 2020,
    sourceType: 'module',
  },
  // 他のESLint設定 (例えば、extendsやpluginsなど)
  // extends: [
  //   'eslint:recommended',
  //   'plugin:vue/vue3-recommended',
  //   // ...
  // ],
  // plugins: [
  //   'vue',
  //   // ...
  // ],
  
  rules: {
    // 他のプロジェクト固有のルール
    // 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    // ...
  },
  
  overrides: [
    {
      // .vueファイルにのみこのルールを適用
      files: ['*.vue'],
      // Vueプラグインを利用している場合、プロセッサを指定することでスクリプトブロックをESLintが解析できるようになります。
      // processor: require('eslint-plugin-vue').processors['.vue'],
      rules: {
        // カスタムルールを 'error' レベルで適用
        'custom-rules/vue-component-sort': require('./your-rules/sort-vue-components.js'),
      },
    },
  ],
};

この設定では、`overrides`セクションを使用して、特定のファイル(ここでは`*.vue`ファイル)にのみカスタムルール`custom-rules/vue-component-sort`を適用しています。`require('./your-rules/sort-vue-components.js')`でカスタムルールファイルを指定し、ESLintがそれをロードできるようにします。

タグ: ESLint vue.js Custom Rules javascript AST

10月30日 11:18 投稿