本文へスキップ

ルールの作成

ルールの作成、拡張、デバッグにご協力ください!

ルールの追加

コードへのコントリビュートの準備をする必要があります。コードへのコントリビュート

ルールの定義

ルールは次の条件を満たす必要があります。

  • 標準CSS構文のみを対象とする
  • 一般的な用途に役立つこと。特殊なパターンに限定されないこと

そして、次のものを備えている必要があります。

  • 明確な最終状態
  • 他のルールと重複しない、単一の目的

その名前は2つの部分に分割されます。

  • ルールが適用される対象、例:at-rule
  • ルールがチェックする内容、例:disallowed-list

ソース全体に適用される場合を除き、最初の部分は存在しません。

テストの作成

次のパターンすべてに対してテストケースを追加する必要があります。

  • 問題とみなされるもの
  • 問題とみなされないもの

次のものを使用する必要があります。

  • 省略記号を使用しない、現実的なCSS
  • 可能な限り最小限のコードを使用すること、例:セレクタをターゲットにする場合は空のルールを使用する
  • 空のルールには{}を使用し、{ }は使用しない
  • デフォルトではaタイプのセレクタ
  • デフォルトでは@media atルール
  • デフォルトではcolorプロパティ
  • デフォルトではred
  • デフォルトでは(min-)widthメディア機能
  • 名前にはfoobarbazを使用する。例:.foo#bar--baz

次の点に注意する必要があります。

  • テスト全体で列と行の位置を変える
  • 警告が2つあるテストを少なくとも1つ含める
  • 非標準構文は、ルール自体ではなく、isStandardSyntax*ユーティリティでテストする

見落としがちなエッジケース

ルールがどのように処理するかを自問する必要があります。

  • 変数(例:var(--custom-property))?
  • CSS文字列(例:content: "anything goes";)?
  • CSSコメント(例:/* anything goes */)?
  • 空の関数(例:var())?
  • url()関数(データURIを含む)(例:url(anything/goes.jpg))?
  • ベンダープレフィックス(例:@-webkit-keyframes name {})?
  • 大文字と小文字の区別(例:@KEYFRAMES name {})?
  • 擬似クラスと擬似要素の組み合わせ(例:a:hover::before)?
  • ネスト(例:& a {}を解決するか、そのままチェックするか)?
  • 空白と句読点(例:rgb(0,0,0)rgb(0, 0, 0)の比較)?

ルールの記述

ルールを作成する際には、次の点に注意する必要があります。

  • デフォルトでルールを厳格にする
  • ルールをより柔軟にするために、セカンダリオプションであるignoreを追加する
  • SCSSなどの言語拡張に固有のコードを含めない

次のものを使用する必要があります。

  • PostCSS API
  • 構成要素固有のパーサー
  • ユーティリティ関数

PostCSS API

PostCSS APIを使用して、CSS構文ツリーをナビゲートして分析します。ノードをループ処理するためにforEachを使用するのではなく、walkイテレータ(例:walkDecls)を使用することをお勧めします。

ノードに対して配列メソッド(例:findsomefilterなど)を使用する場合は、他のプロパティにアクセスしようとする前に、ノードのtypeプロパティを明示的にチェックする必要があります。例:

const hasProperty = nodes.find(
({ type, prop }) => type === "decl" && prop === propertyName
);

PostCSS ASTから生の文字列にアクセスする場合は、node.raw()ではなくnode.rawsを使用します。

構成要素固有のパーサー

ルールによっては、次のものを使用することもお勧めします。

正規表現やindexOf検索(常に最もパフォーマンスの高い方法ではない場合でも)を使用する代わりに、これらのパーサーを使用することには大きな利点があります。

ユーティリティ関数

Stylelintには、既存のルールで使用されているユーティリティ関数もあり、あなたにも役立つかもしれません。利用可能な機能を把握するために、それらを確認してください。(そして、一般的に役立つと思われる新しい関数があれば、リストに追加しましょう!)

次のものを使用します。

  • 無効なオプションについてユーザーに警告するためにvalidateOptions()ユーティリティ
  • 非標準構文を無視するためにisStandardSyntax*ユーティリティ

オプションの追加

各ルールは、プライマリオプションとオプションのセカンダリオプションを受け入れることができます。

未使用の機能でツールを汚染することを避けるために、要求されたユースケースに対処する場合にのみ、ルールにオプションを追加してください。

プライマリ

すべてのルールにはプライマリオプションが必要です。例:

  • "font-weight-notation": "numeric"では、プライマリオプションは"numeric"です。
  • "selector-max-type": [2, { "ignoreTypes": ["custom"] }]では、プライマリオプションは2です。

明示的なプライマリオプションを促すようにルールに名前が付けられています。例:font-weight-notation: "numeric"|"named-where-possible"ではなくfont-weight-numeric: "always"|"never"font-weight-named: "never"は常に数値であることを暗示していますが、font-weight-notation: "numeric"はそれを明示的にしています。

セカンダリ

一部のルールでは、エッジケースに対処するために追加の柔軟性が必要です。これらは、オプションのセカンダリオプションオブジェクトを使用できます。例:

  • "font-weight-notation": "numeric"には、セカンダリオプションオブジェクトはありません。
  • "selector-max-type": [2, { "ignore": ["descendant] }]では、セカンダリオプションオブジェクトは{ "ignore": ["descendant] }です。

最も一般的なセカンダリオプションは"ignore": []"except": []です。

キーワード"ignore""except"

"ignore""except"オプションは、事前に定義されたキーワードオプションの配列を受け入れます。例:["relative", "first-nested", "descendant"]

  • "ignore"は特定のパターンをスキップします。
  • "except"は、特定のパターンに対してプライマリオプションを反転します。
ユーザー定義の"ignore*"

一部のルールは、無視するもののユーザー定義リストを受け入れます。これは、"ignore<Things>": []の形式を取ります。例:"ignoreAtRules": []

ignore*オプションを使用すると、設定レベルで非標準構文を無視できます。例:

  • CSS Modulesで導入された:global:local擬似クラス
  • SCSSで導入された@debug@extend atルール

方法論と言語拡張は急速に出入りするため、このアプローチにより、コードベースが廃止されたもののコードで乱雑になるのを防ぎます。

ルールがプライマリオプションとして配列を受け入れることができる場合、ルール関数にプロパティprimaryOptionArray = trueを設定して、これを指定する必要があります。例:

function rule(primary, secondary) {
return (root, result) => {
/* .. */
};
}

rule.primaryOptionArray = true;

module.exports = rule;

ここに1つの注意点があります。ルールがプライマリオプション配列を受け入れる場合、プライマリオプションオブジェクトも受け入れることはできません。可能であれば、ルールがプライマリオプション配列を受け入れるようにしたい場合は、さまざまなデータ構造を許可する代わりに、配列を唯一の可能性にする必要があります。

問題メッセージの追加

次の形式で問題メッセージを追加します。

  • "[何か]を[あるコンテキストで]期待していました"
  • "[何か]を[あるコンテキストで]予期していませんでした"

ルールに自動修正機能がある場合は、次のものを使用します。

  • 短い文字列の場合は'「未修正」が「修正済み」であることが期待されていました'
  • 長い文字列の場合は'「プライマリ」...表記が期待されていました'

自動修正の追加

ルールによっては、PostCSS APIを使用してPostCSS AST(抽象構文ツリー)を変更することで、ルールの問題を自動的に修正できる場合があります。

ルールにmeta.fixable = trueを設定します。

const meta = {
url: /* .. */,
+ fixable: true,
};

ルールパラメータにcontext変数を追加します。

-function rule(primary, secondary) {
+function rule(primary, secondary, context) {
return (root, result) => {
/* .. */
};
}

contextは、3つのプロパティを持つ可能性のあるオブジェクトです。

  • configurationComment(文字列):/* stylelint-disable */のような設定コメントの前に付ける文字列。
  • fix(ブール値):trueの場合、ルールは自動修正を適用できます。
  • newline(文字列):現在lintされているファイルで使用されている改行。

context.fixtrueの場合、PostCSS APIを使用してrootを変更し、report()が呼び出される前に早期に返します。

if (context.fix) {
// Apply fixes using PostCSS API
return; // Return and don't report a problem
}

report(/* .. */);

READMEの記述

各ルールには、次の形式のREADMEが付属しています。

  1. ルール名。
  2. 1行の説明。
  3. プロトタイプのコード例。
  4. 拡張説明(必要に応じて)。
  5. オプション。
  6. 問題とみなされるパターン例(各オプション値について)。
  7. 問題とみなされないパターン例(各オプション値について)。
  8. オプションのオプション(該当する場合)。

1行の説明は、次の形式です。

  • noルールの場合、「許可しない…」
  • maxルールの場合、「制限する…」
  • "always""never"オプションを受け入れるルールの場合、「要求する…」
  • その他すべての場合、「指定する…」

次の点に注意する必要があります。

  • テストから例を選択します。
  • 例とオプションには標準CSS構文のみを使用します。
  • エッジケースを示すのではなく、ルールの意図を伝えるために、可能な限り最小限の例を追加します。
  • cssコードフェンスの前に<!-- prettier-ignore -->を使用してください。
  • ルールを参照する際は、「このルール」を使用してください(例:「このルールは…を無視します」)。
  • プロトタイプコード例内の矢印を、強調表示された構成の先頭に揃えてください。
  • プロトタイプコード例内のテキストを、できるだけ左側に揃えてください。

例えば

 @media screen and (min-width: 768px) {}
/** ↑ ↑
* These names and values */

他のルールのREADMEを参照して、より一般的なパターンを理解してください。

ルールの接続

最後のステップは、以下の箇所に新しいルールの参照を追加することです。

ルールへのオプションの追加

次の点に注意する必要があります。

  1. コードの寄稿の準備をするコード寄稿
  2. オプションをテストするための新しい単体テストを追加します。
  3. 新しいオプションを許可するようにルールの検証を変更します。
  4. テストがパスするように、ルールに(できるだけ少ない)ロジックを追加します。
  5. 新しいオプションに関するドキュメントを追加します。

ルールのバグの修正

次の点に注意する必要があります。

  1. コードの寄稿の準備をするコード寄稿
  2. バグを示す失敗する単体テストを作成します。
  3. 新しいテストがパスするまで、ルールを調整します。

ルールの非推奨化

ルールの非推奨化は頻繁には行われません。行う場合は、以下の手順に従う必要があります。

  1. 常にアクセスできるように、GitHubウェブサイト上のルールのREADMEの特定のバージョンにstylelintReferenceリンクをポイントします。
  2. rule.meta = { deprecated: true }のように、ルールを非推奨としてマークする適切なメタデータを追加します。

ルールの性能の向上

有効な設定を使用して、任意のルールでベンチマークを実行できます。

npm run benchmark-rule -- ruleName ruleOptions [ruleContext]

ruleOptions引数が文字列またはブール値以外の場合は、引用符で囲まれた有効なJSONである必要があります。

npm run benchmark-rule -- value-keyword-case lower
npm run benchmark-rule -- value-keyword-case '["lower", {"camelCaseSvgKeywords": true}]'

ruleContext引数が指定されている場合、同じ手順が適用されます。

npm run benchmark-rule -- value-keyword-case '["lower", {"camelCaseSvgKeywords": true}]' '{"fix": true}'

このスクリプトは、BootstrapのCSS(CDNから)を読み込み、設定されたルールで実行します。

次のような簡単な統計情報を表示します。

Warnings: 1441
Mean: 74.17598357142856 ms
Deviation: 16.63969674310928 ms

新しいルールを作成する場合や既存のルールをリファクタリングする場合は、これらの測定値を使用してコードの効率性を判断してください。

Stylelintルールは、コアロジックを何度も繰り返す可能性があります(例:大規模なCSSコードベースのすべての宣言のすべての値ノードをチェックする)。そのため、パフォーマンスに注意を払い、改善できることを行う価値があります!

ルールの性能向上は、簡単なプロジェクトを探している場合に貢献するのに最適な方法です。 ルールを選択し、速度を向上させることができるものがないか確認してみてください。

プルリクエストにベンチマーク測定値を含めてください!