🤖

stylelint開発ガイドープラグイン

に公開

内容の目的

本内容は、stylelint開発ガイドープラグイン を翻訳し、個人活用のために整理しています。

プラグインの作成

プラグインとは、カスタムルールまたはその集合体のことです。特定のメソドロジーやツールセットをサポートしたり、非標準構文・機能を対象としたり、特定のユースケース向けに設計されることがあります。

カスタムルールは、以下のような Stylelint のルール規約 に準拠することを推奨します:

  • 名前付け
  • オプション
  • メッセージ
  • テスト
  • ドキュメント
  • メタデータ
  • 構文特有のパーサー

プラグインの構造

次のサンプルは、セレクタに "foo" を含むことを禁止するプラグインです:

import stylelint from "stylelint";

const {
  createPlugin,
  utils: { report, ruleMessages, validateOptions }
} = stylelint;

const ruleName = "foo-org/selector-no-foo";

const messages = ruleMessages(ruleName, {
  rejected: (selector) => `Unexpected "foo" within selector "${selector}"`
});

const meta = {
  url: "https://github.com/foo-org/stylelint-selector-no-foo/blob/main/README.md"
};

/** @type {import('stylelint').Rule} */
const ruleFunction = (primary, secondaryOptions, context) => {
  return (root, result) => {
    const validOptions = validateOptions(result, ruleName, {
      actual: primary,
      possible: [true]
    });

    if (!validOptions) return;

    root.walkRules((ruleNode) => {
      const { selector } = ruleNode;

      if (!selector.includes("foo")) return;

      report({
        result,
        ruleName,
        message: messages.rejected(selector),
        node: ruleNode,
        word: selector
      });
    });
  };
};

ruleFunction.ruleName = ruleName;
ruleFunction.messages = messages;
ruleFunction.meta = meta;

export default createPlugin(ruleName, ruleFunction);

@type の JSDoc アノテーションを使うことで、TypeScript の補完と型チェックが可能になります。

使用例:

{
  "plugins": ["@foo-org/stylelint-selector-no-foo"],
  "rules": {
    "foo-org/selector-no-foo": true
  }
}
$ echo '.foo {}' | stylelint --stdin-filename=test.css

test.css
 1:1  ✖  Unexpected "foo" within selector ".foo"  foo-org/selector-no-foo

1 problem (1 error, 0 warnings)

プラグインのルール名は、 your-namespace/your-rule-name のように名前空間付きである必要があります。そうすることで、組み込みルールとの衝突を避けられます。ルールが1つだけであったり適切な名前空間が思いつかない場合は、plugin/my-rule を使うこともできます。設定ファイルに記載するため、ルール名と名前空間は必ずドキュメントに記載しましょう。

stylelint.createPlugin(ruleName, ruleFunction) を使用して、他のルールと一貫した方法でプラグインを構築できます。

標準の設定フォーマットに対応するためには、ruleFunction は以下の2つの引数を受け取る必要があります:

  • プライマリオプション
  • (任意で)セカンダリオプションのオブジェクト

オートフィックスに対応する場合は、meta.fixable = true を設定してください。

ruleFunction は、2つの引数(PostCSS の Root ノードと LazyResult)を受け取る関数を返す必要があります。これは実質的に PostCSS プラグイン として動作します。

PostCSS API について学んでおくと良いでしょう。

非同期ルール

Promise を扱う場合、非同期関数としてルールを書くことができます:

const ruleFunction = (primary, secondaryOptions) => {
  return async (root, result) => {
    // オプションを検証...

    // 禁止語句を非同期で読み込む
    const disallowedWords = await import("./disallowed-words.js");

    // AST ノードを走査...

    // 問題がある語句を検出した場合は警告を出す...
  };
};

テスト

以下のどちらかを使用できます:

どちらも testRule 関数を提供しており、ルールのスキーマに基づいて効率的にテストできます。

例:

import { testRule } from "stylelint-test-rule-node";
import plugin from "./index.js";

const {
  rule: { messages, ruleName }
} = plugin;

testRule({
  plugins: [plugin],
  ruleName,
  config: true,
  fix: true,
  accept: [
    { code: ".a {}" },
    { code: ".b {}" }
  ],
  reject: [
    {
      code: ".foo {}",
      fixed: ".safe {}",
      message: messages.rejected(".foo"),
      line: 1,
      column: 1,
      endLine: 1,
      endColumn: 8
    }
  ]
});

より多くのテスト手法は Awesome Stylelint にあります。

より高度な解析や構文以上の検査を行う場合は、stylelint.lint() を直接使うこともできます。

stylelint.utils

Stylelint は便利なユーティリティ関数も提供しています。内部ユーティリティをコピーして使っても構いませんが、直接インポートは非推奨です。将来変更や削除の可能性があります。

stylelint.utils.report()

ルールが検出した問題を、Stylelint の出力に追加します。無効範囲(disabled ranges)なども考慮されるため、必ずこの関数を使いましょう。

stylelint.utils.ruleMessages()

Stylelint 標準ルールのフォーマットに合うようにメッセージを整形します。

stylelint.utils.validateOptions()

ルールのオプションが妥当かどうかを検証します。

stylelint.utils.checkAgainstRule()

自作ルール内で、他の Stylelint ルールを呼び出して CSS をチェックできます。既存ルールの機能を上書き・拡張したい場合に有効です。

非同期関数である点に注意してください。

stylelint.rules

すべての組み込みルールは stylelint.rules 経由でアクセス可能です。これにより、既存ルールの上に独自ロジックを組み立てることができます。

プライマリオプションに配列を許容する

ルールが配列を受け入れる場合、ruleFunction.primaryOptionArray = true を設定する必要があります。

ピア依存関係

プラグインの package.json には peerDependencies として Stylelint のバージョンを明示する必要があります。

{
  "peerDependencies": {
    "stylelint": "^14.0.0 || ^15.0.0"
  }
}

複数ルールを提供するプラグインパック

1 つのモジュールで複数のルールを提供する場合は、プラグインオブジェクトの配列をエクスポートしてください。

プラグインと構成の共有

  • プラグインは stylelint-plugin キーワードを package.json に記載してください。
  • プラグイン構成(ルールセット)を共有する場合は stylelint-config を使用します。

目次に戻る

Discussion