# Design Token Lint > Lint Tailwind CSS class names against design system tokens. Enforce semantic spacing and color tokens instead of raw numeric utilities. --- # Changelog > Source: https://takazudomodular.com/pj/zudo-design-token-lint/ja/docs/changelog --- # ガイド > Source: https://takazudomodular.com/pj/zudo-design-token-lint/ja/docs/guide --- # 概要 > Source: https://takazudomodular.com/pj/zudo-design-token-lint/ja/docs/overview --- # リファレンス > Source: https://takazudomodular.com/pj/zudo-design-token-lint/ja/docs/reference --- # 設定 > Source: https://takazudomodular.com/pj/zudo-design-token-lint/ja/docs/guide/configuration プロジェクトルートに `.design-token-lint.json` または `design-token-lint.config.json` ファイルを作成します。リンターは最初に見つかったファイルを読み込み、どちらも存在しない場合は組み込みのデフォルトにフォールバックします。 ## 完全な例 ```json { "prohibited": [ "p-{n}", "px-{n}", "py-{n}", "m-{n}", "gap-{n}", "bg-{color}-{shade}", "text-{color}-{shade}", "border-{color}-{shade}" ], "allowed": ["p-0", "m-0", "gap-0", "p-1px"], "ignore": ["**/*.test.*", "**/*.stories.*"], "patterns": [ "src/**/*.{tsx,jsx,astro}", "components/**/*.{tsx,jsx,astro}" ] } ``` ## フィールド | フィールド | 型 | 説明 | |---|---|---| | `prohibited` | `string[]` | 違反としてフラグを立てるパターン | | `allowed` | `string[]` | 禁止パターンに一致しても常に通す例外 | | `ignore` | `string[]` | 完全にスキップするファイル glob パターン | | `patterns` | `string[]` | スキャン対象の glob パターン(CLI 引数がない場合に使用) | | `suggestionSuffix` | `string` | 違反メッセージのカスタムサフィックス(デフォルトの提案テキストを置き換えます) | すべてのフィールドはオプションで、省略時は組み込みのデフォルトにフォールバックします。 ### `prohibited` フラグを立てるクラス名パターンの配列。各パターンはプレースホルダー構文を使います: - **`{n}`** — `4`、`8`、`0.5`、`16` などの数値に一致。間隔(padding、margin、gap、inset、top/left/right/bottom など)に使用 - **`{color}`** — 標準的な Tailwind カラー名に一致: `slate`、`gray`、`zinc`、`neutral`、`stone`、`red`、`orange`、`amber`、`yellow`、`lime`、`green`、`emerald`、`teal`、`cyan`、`sky`、`blue`、`indigo`、`violet`、`purple`、`fuchsia`、`pink`、`rose` - **`{shade}`** — `50`、`100`、`500`、`950` などの 2〜3 桁のシェード値に一致 例: - `p-{n}` は `p-4`、`p-8`、`p-0.5` に一致 - `bg-{color}-{shade}` は `bg-red-500`、`bg-blue-300` に一致 - `gap-x-{n}` は `gap-x-2`、`gap-x-6` に一致 ### `allowed` 完全一致の許可リスト。この配列にあるクラスは禁止パターンに関係なく常に通ります。`p-0`、`m-0`、`p-1px` のようなエスケープハッチに便利です。 ### `ignore` 完全にスキップするファイル glob パターン。よくあるパターン: ```json { "ignore": [ "**/*.test.*", "**/*.stories.*", "**/*.spec.*" ] } ``` ### `patterns` CLI が明示的なファイル引数なしで呼び出されたときにスキャンするファイル glob パターン。省略時はデフォルトセット(`src/**`、`components/**`、`lib/**`、`app/**`)を使用します。 ### `suggestionSuffix` 違反メッセージの `—` セパレーターの後に付加される文字列で、デフォルトの提案テキストを置き換えます。プロジェクト固有のトークン命名規則を開発者に案内するために使用します。 **デフォルトメッセージ(`suggestionSuffix` なし):** - 間隔: `Numeric spacing "p-4" — use a semantic spacing token or arbitrary value` - カラー: `Default Tailwind color "bg-gray-500" — use a design system color token` **`suggestionSuffix` を設定した場合:** ```json { "suggestionSuffix": "use hgap-*/vgap-* or zd-* tokens" } ``` - 間隔: `Numeric spacing "p-4" — use hgap-*/vgap-* or zd-* tokens` - カラー: `Default Tailwind color "bg-gray-500" — use hgap-*/vgap-* or zd-* tokens` ## 組み込みのデフォルト 設定ファイルが存在しない場合、リンターは以下のデフォルトを使用します: - **Prohibited**: すべての標準的な間隔ユーティリティ(`p-*`、`m-*`、`gap-*`、`inset-*`、`scroll-*`)の数値版、およびすべてのカラーユーティリティ(`bg-*`、`text-*`、`border-*`、`ring-*` など)のデフォルト Tailwind カラーとシェードの組み合わせ - **Allowed**: `p-0`、`m-0`、`gap-0`、`p-1px` - **Ignore**: `**/*.test.*`、`**/*.stories.*` 完全なデフォルトリストは[パッケージの README](https://github.com/Takazudo/zudo-design-token-lint/blob/main/README.md)を参照してください。 ## 自動的に通るクラス これらのクラスは `allowed` に含まれていなくても常に通ります: - **セマンティック間隔トークン**: `p-hgap-sm`、`gap-vgap-xs`、`m-hgap-md`(`hgap-*` または `vgap-*` サフィックスを持つクラス) - **デフォルト以外のカラー**: `bg-surface`、`text-fg`、`bg-zd-black`(標準 Tailwind パレット名ではないカラー名) - **任意値**: `w-[28px]`、`bg-[#123]`、`p-[10px]` - **間隔・色以外のユーティリティ**: `flex`、`grid`、`hidden`、`w-full`、`font-bold` など --- # design-token-lint とは? > Source: https://takazudomodular.com/pj/zudo-design-token-lint/ja/docs/overview/what-is Tailwind CSS は数百もの数値ユーティリティ — `p-1` から `p-96`、`gap-2`、`mt-8` — と、`bg-red-500`、`text-gray-300` のようなシェードを持つデフォルトカラーパレットを提供しています。これらのユーティリティは便利ですが、デザインシステムを完全に無視することを可能にします。開発者はデザイントークンを参照せず、任意のスペーシング値や色を選ぶことができてしまいます。 `@zudolab/design-token-lint` はこれを検出するリンターです。禁止パターンに一致する Tailwind クラス名をソースファイルからスキャンし、違反として報告します — セマンティックな代替案へと開発者を導きます。 ## 問題点 `p-4` を使ったコンポーネントと `p-6` を使ったコンポーネントは見た目が似ていても、共有されたセマンティックな意味を持ちません。これが大きなプロジェクト全体に広がると、場当たり的なスペーシング値が無数に生まれ、デザイントークンではなく Tailwind のパレットから色が選ばれ、一貫性を強制するツールも存在しない状態になります。 デザインシステムは `spacing-md`、`color-surface`、`text-primary` のようなセマンティックなトークンを定義することで、それらの値に契約を与えます。生のユーティリティはその契約を無言で回避します。 詳しい考え方は[メソドロジーのページ](../../reference/methodology/index.md)を参照してください。 ## 仕組み 1. **ファイルのスキャン** — リンターはソースファイル(`.tsx`、`.jsx`、`.astro`、`.vue`、`.html` など)を読み込み、`className`、`class`、`cn()`、`clsx()` などの構文に対してパターンマッチングで Tailwind クラス名を抽出します。 2. **ルールとの照合** — 抽出された各クラスは `.design-token-lint.json` で定義された禁止パターンと照合されます。パターンにはプレースホルダーを使用します: - `{n}` — 任意の Tailwind 数値ステップにマッチ(`p-{n}` は `p-4`、`p-6`、`p-12` などにマッチ) - `{color}` — 任意のデフォルト Tailwind カラー名にマッチ(`bg-{color}-{shade}` は `bg-red-500` にマッチ) - `{shade}` — 数値シェード(`50`〜`950`)にマッチ 3. **違反の報告** — 違反はファイルパス、行番号、クラス名、そして期待されるトークンカテゴリを示す理由文字列とともに報告されます。 ``` src/Button.tsx L12: p-4 — Numeric spacing "p-4" — use semantic token (hgap-*/vgap-*) or arbitrary value src/Card.tsx L7: bg-gray-200 — Default color "bg-gray-200" — use semantic token (bg-surface/bg-muted/...) ``` ## 主な機能 - **CLI ツール** — `npx design-token-lint` でプロジェクトをリント。CI 統合のため違反があればコード `1` で終了 - **設定可能なルール** — `.design-token-lint.json` で禁止パターンと明示的な許可リストを定義 - **パターンプレースホルダー** — `{n}`、`{color}`、`{shade}` により 1 つのルールでユーティリティファミリー全体をカバー - **無視構文** — `// design-token-lint-ignore` で個別行を、`// design-token-lint-ignore-file` でファイル全体を抑制 - **プログラマティック API** — ビルドツールやエディタとの統合のための `lintFile()`、`lintContent()`、`checkClass()` - **ブラウザプレイグラウンド** — インストールなしでパターンとクラスをインタラクティブに試せる ## 技術スタック TypeScript、Node.js 18+。CLI バイナリとインポート可能なライブラリを持つ npm パッケージとして配布。ランタイム依存関係: `chalk`(ターミナルカラー)と `glob`(ファイルスキャン)。Tailwind への依存なし — 内部ではなく文字列パターンマッチングで動作します。 ## インテグレーション ソースファイルで Tailwind クラス名を使用する任意のフレームワーク(React、Vue、Astro、Svelte、またはプレーン HTML)で動作します。以下と統合できます: - **CI/CD** — GitHub Actions や任意のパイプラインのステップとして実行 - **Git フック** — [lefthook](https://github.com/evilmartians/lefthook) または husky でプッシュ前に実行 - **ビルドツール** — Vite プラグイン、webpack ローダー、またはカスタムスクリプトでプログラマティック API を使用 - **エディタ** — プログラマティック API はエディタプラグイン作者をサポート --- # Playground > Source: https://takazudomodular.com/pj/zudo-design-token-lint/ja/docs/playground ブラウザ上でリンターを直接試せます。左側にコードを貼り付け、設定を調整すると、右側に違反が表示されます。 --- # プログラマティック API > Source: https://takazudomodular.com/pj/zudo-design-token-lint/ja/docs/reference/api `@zudolab/design-token-lint` は、ビルドツール、エディタ、またはカスタムツールとの統合のための小さな API をエクスポートしています。 ## インストール ```bash pnpm add @zudolab/design-token-lint ``` ## エクスポート ```ts // ファイル/コンテンツのリント lintFile, lintContent, type LintResult, // 単一クラスのチェック checkClass, checkClassWithConfig, type Violation, // 設定の読み込みとコンパイル loadConfig, compileConfig, compilePattern, setConfig, getConfig, DEFAULT_CONFIG, type LintConfig, type CompiledConfig, type CompiledRule, // クラス抽出 extractClasses, type ExtractedClass, } from '@zudolab/design-token-lint'; ``` ## ファイルとコンテンツのリント ### `lintFile(filePath)` ディスクからファイルを読み込み、違反ごとに 1 エントリの配列を返します。 ```ts const results = await lintFile('src/App.tsx'); for (const r of results) { console.log(`${r.filePath}:${r.line} ${r.className} ${r.reason}`); } ``` `Promise` を返します: ```ts interface LintResult { filePath: string; line: number; className: string; reason: string; } ``` 各エントリは 1 つの違反を表すフラットなレコードです。違反がない場合は空配列が返ります。 ### `lintContent(filePath, content)` 文字列を直接リントします — エディタプラグインやインメモリコンテンツに便利です。`LintResult[]` を返します(上記と同じ形)。 ```ts const results = lintContent('file.tsx', ''); // [ // { filePath: 'file.tsx', line: 1, className: 'p-4', reason: '...' }, // { filePath: 'file.tsx', line: 1, className: 'bg-gray-500', reason: '...' } // ] ``` ## 単一クラスのチェック ### `checkClass(className)` 1 つのクラス名をアクティブな設定に対してチェックします。禁止されている場合は `Violation`、通る場合は `null` を返します。 ```ts const violation = checkClass('p-4'); if (violation) { console.error(violation.reason); // "Numeric spacing \"p-4\" — use semantic token (hgap-*/vgap-*) or arbitrary value" } ``` `Violation | null` を返します: ```ts interface Violation { className: string; reason: string; } ``` ### `checkClassWithConfig(className, compiledConfig)` 上記と同じですが、グローバル設定ではなく明示的なコンパイル済み設定を使用します。 ```ts const config = await loadConfig(process.cwd()); const compiled = compileConfig(config); const violation = checkClassWithConfig('bg-blue-500', compiled); ``` ## 設定の操作 ### `loadConfig(cwd)` ディレクトリから `.design-token-lint.json` または `design-token-lint.config.json` を読み込みます。どちらも存在しない場合は `DEFAULT_CONFIG` にフォールバックします。 ```ts const config = await loadConfig(process.cwd()); ``` ### `compileConfig(config)` プレーンな設定オブジェクトをマッチング用の効率的なルールセットにコンパイルします。 ```ts const compiled = compileConfig({ prohibited: ['p-{n}', 'bg-{color}-{shade}'], allowed: ['p-0'], ignore: [], }); ``` ### `setConfig(compiled)` / `getConfig()` `checkClass()` と `lintFile()` が使用するグローバルなコンパイル済み設定を設定または取得します。 ```ts setConfig(compiled); const active = getConfig(); ``` ### `compilePattern(pattern)` 単一のパターン文字列(`p-{n}` など)を `CompiledRule` にコンパイルします。 ```ts const rule = compilePattern('bg-{color}-{shade}'); // { prefix: 'bg', valuePattern: /^(slate|gray|...)-(\d{2,3})$/, reasonTemplate: '...', isSpacingRule: false } ``` ## クラスの抽出 ### `extractClasses(content)` ソースファイル文字列からすべてのクラス名トークンを行番号付きで抽出します。 ```ts const extracted = extractClasses(''); // [ // { className: 'p-4', line: 1 }, // { className: 'bg-red-500', line: 1 } // ] ``` `ExtractedClass[]` を返します: ```ts interface ExtractedClass { className: string; line: number; } ``` サポートされる構文: - `className="..."` と `class="..."`(JSX/Astro) - `className={'...'}` シングルクォート中括弧 - `` className={`...`} `` テンプレートリテラル(単純なケース) - `class:list={["...", '...']}` Astro class:list 配列 - `cn(...)`、`clsx(...)`、`classNames(...)`、`twMerge(...)` ユーティリティ呼び出し ## 型 ### `LintConfig` ```ts interface LintConfig { prohibited: string[]; allowed: string[]; ignore: string[]; patterns?: string[]; suggestionSuffix?: string; } ``` ### `LintResult` ```ts interface LintResult { filePath: string; line: number; className: string; reason: string; } ``` ### `Violation` ```ts interface Violation { className: string; reason: string; } ``` ## 例: カスタムリンタースクリプト ```ts loadConfig, compileConfig, setConfig, lintFile, } from '@zudolab/design-token-lint'; async function main() { const config = await loadConfig(process.cwd()); setConfig(compileConfig(config)); const files = await glob('src/**/*.{tsx,jsx}'); let totalViolations = 0; for (const file of files) { const results = await lintFile(file); for (const r of results) { console.log(`${r.filePath}:${r.line} ${r.className} ${r.reason}`); totalViolations++; } } process.exit(totalViolations > 0 ? 1 : 0); } main(); ``` --- # CLI > Source: https://takazudomodular.com/pj/zudo-design-token-lint/ja/docs/guide/cli `design-token-lint` CLI はファイルをスキャンして禁止された Tailwind クラス名を検出し、違反を報告します。 ## 基本的な使い方 ```bash # デフォルトパターンをスキャン(config.patterns または組み込みデフォルト) design-token-lint # 特定のファイルまたは glob をスキャン design-token-lint "src/**/*.tsx" "pages/**/*.tsx" # 単一ファイルをスキャン design-token-lint src/App.tsx ``` ## 終了コード | コード | 意味 | |---|---| | `0` | 違反なし(またはマッチしたファイルなし) | | `1` | 違反あり | | `2` | 予期しないエラー(ファイルシステム障害など) | CI で違反があった場合にビルドを失敗させるには終了コード `1` を利用します: ```yaml # .github/workflows/lint.yml - run: pnpm design-token-lint ``` ## 出力フォーマット 違反はファイルごとにグループ化されます。各行は行番号、違反クラス、理由を表示します: ``` Scanning 1 file(s)... src/App.tsx L12: p-4 — Numeric spacing "p-4" — use semantic token (hgap-*/vgap-*) or arbitrary value L12: bg-gray-500 — Default Tailwind color "bg-gray-500" — use design system token (zd-*, p0-p15, semantic) Found 2 violation(s) in 1 file(s). ``` すべての出力は stderr に送られるため、stdout をパイプするスクリプトに干渉しません。 ## ファイルパターン解決 引数なしで呼び出された場合、CLI はこの順序でファイルを解決します: 1. `config.patterns` が設定されていればそれを使用 2. それ以外は組み込みデフォルトを使用: `src/**/*.{tsx,jsx,astro}`、`components/**/*.{tsx,jsx,astro}`、`lib/**/*.{tsx,jsx}`、`app/**/*.{tsx,jsx}` 引数ありで呼び出された場合、各引数はファイルパスまたは glob として扱われます。`ignore` の設定は引き続き適用されます。 ## package.json との統合 便利な呼び出し用にスクリプトを追加: ```json { "scripts": { "lint:tokens": "design-token-lint" } } ``` 実行: ```bash pnpm lint:tokens ``` ## lefthook との統合 [lefthook](https://github.com/evilmartians/lefthook) でプッシュ時に実行: ```yaml # lefthook.yml pre-push: commands: design-token-lint: run: npx design-token-lint ``` ## CI との統合 GitHub Actions ステップを追加: ```yaml - name: Lint design tokens run: pnpm design-token-lint ``` 違反があればコード `1` で終了し、ワークフローが失敗します。 --- # はじめに > Source: https://takazudomodular.com/pj/zudo-design-token-lint/ja/docs/overview/getting-started `@zudolab/design-token-lint` は Tailwind CSS のクラス名をデザインシステムのトークンに対してリントします。`p-4`、`gap-6` のような生の数値ユーティリティや、`bg-gray-500` のようなデフォルトパレットの色を検出し、セマンティックなトークンへの移行を促します。 ## なぜ必要か Tailwind の数値ユーティリティとデフォルトカラーパレットは、コードベース全体に一貫性のなさを簡単に持ち込みます。ある開発者が `p-4` と書き、別の場所で `p-6` と書く — 見た目は似ていても意味的には無関係です。これが大規模なコードベース全体に広がると、デザインの一貫性が崩れていきます。 このリンターはシンプルなルールを強制します: **生の数値とデフォルトパレットの色は禁止**。代わりに意図を表すセマンティックなトークンを使います。水平方向の間隔には `p-hgap-md`、サーフェスには `bg-surface`、基本テキストには `text-fg` といった具合に。 詳しい理由は[メソドロジーのページ](../../reference/methodology/index.md)を参照してください。 ## インストール Tailwind プロジェクトに dev dependency としてインストールします: ```bash pnpm add -D @zudolab/design-token-lint ``` npm / yarn の場合: ```bash npm install --save-dev @zudolab/design-token-lint yarn add --dev @zudolab/design-token-lint ``` ## 最初の実行 引数なしでリンターを実行すると、デフォルトのファイルパターン(`src/`、`components/`、`lib/`、`app/`)をスキャンします: ```bash npx design-token-lint ``` 違反が見つからなかった場合は終了コード `0`、見つかった場合は `1` で終了します — CI での利用に適しています。 ## 最初の設定 プロジェクトルートに `.design-token-lint.json` ファイルを作成してルールをカスタマイズします: ```json { "prohibited": [ "p-{n}", "m-{n}", "gap-{n}", "bg-{color}-{shade}", "text-{color}-{shade}" ], "allowed": ["p-0", "m-0", "gap-0"], "ignore": ["**/*.test.*", "**/*.stories.*"] } ``` すべてのオプションは[設定リファレンス](../../guide/configuration/index.md)を参照してください。 ## 次のステップ - [設定リファレンス](../../guide/configuration/index.md)でプロジェクトに合わせたルール調整 - [CLI の使い方](../../guide/cli/index.md)でコマンドラインオプション - [無視コメント](../../guide/ignore-syntax/index.md)で個別違反の抑制 - [プログラマティック API](../../reference/api/index.md)でビルドツールやエディタとの統合 --- # メソドロジー > Source: https://takazudomodular.com/pj/zudo-design-token-lint/ja/docs/reference/methodology `design-token-lint` は Tailwind CSS でデザインシステムを構築するための特定のアプローチを強制します。このページではその理由を説明します。 ## 問題 Tailwind には数百のユーティリティクラスとデフォルトカラーパレットが付属しています。プロトタイプには最適ですが、スケールすると問題が生じます: 1. **一貫性のなさが静かに忍び寄る。** 開発者がある場所で `p-4`、別の場所で `p-6`、さらに別の場所で `p-3` と書く。どれも間違いではありません。どれもフラグが立ちません。デザインがドリフトしていきます。 2. **リファクタリングのコストが高い。** デザインシステムが変わったとき — 例えば間隔の基本単位を `4px` から `6px` に移行するとき — すべてのハードコードされた `p-4` を監査して場合によっては更新する必要があります。 3. **意図が失われる。** `p-4` は「4 単位のパディング」と言っているだけで、*なぜ* かは何も語りません。カードのパディング? ボタンのインセット? セクションのガター? クラスからは手がかりが得られません。 ## 解決策 生の数値ユーティリティを**セマンティックトークン**に置き換えます: ```diff - + ``` セマンティック版は: - 意図を伝える(`surface`、`fg`、`md`、`sm`) - すべてのコンポーネントに触れることなく中央で再調整できる - 語彙が有限なので一貫性を保ちやすい ## トークンのカテゴリ ### 間隔 `hgap-*`(水平)と `vgap-*`(垂直)サフィックスを使用: ``` p-hgap-sm # 小さな水平パディング m-vgap-lg # 大きな垂直マージン gap-hgap-md # 中程度のギャップ ``` スケール名(`2xs`、`xs`、`sm`、`md`、`lg`、`xl`、`2xl`、...)は Tailwind の設定で定義され、実際のピクセル値にマップされます。 ### カラー 色相ではなく役割を表すセマンティックな名前を使用: ``` bg-surface # あらゆるサーフェス(カード、パネル) bg-surface-alt # 代替サーフェスの濃淡 text-fg # 基本前景 text-muted # 控えめなテキスト border-muted # 微妙なボーダー bg-accent # プライマリアクションカラー ``` またはプロジェクトスコープのトークンを使用: ``` bg-zd-black # プロジェクト固有のパレット text-p7 # プライマリパレットのスロット 7 ``` 正確な名前はデザインシステム次第です — リンターは*デフォルトの Tailwind カラー*(`gray`、`blue`、`red` など)をブロックするだけです。 ## 引き続き動くもの このリンターは Tailwind を禁止しようとしているわけではありません。ほとんどのユーティリティは引き続き動作します: - レイアウト: `flex`、`grid`、`block`、`hidden`、`w-full`、`h-screen` - タイポグラフィ: `font-bold`、`text-lg`、`leading-tight`、`tracking-wide` - エフェクト: `shadow`、`rounded`、`opacity-50`、`transition` - ゼロおよび 1px の間隔: `p-0`、`m-0`、`gap-0`、`p-1px` - 任意値: `w-[28px]`、`bg-[#123]`、`p-[10px]` **生の数値間隔**と**デフォルトパレットの色**のみがフラグされます。 ## エスケープハッチ 本当に生の値が必要な場合があります。次のいずれかを使用します: 1. **任意値**: `p-[14px]` — 明示的で検索可能、レビュアーに見える 2. **無視コメント**: 前の行に `{/* design-token-lint-ignore */}` — [無視構文](../../guide/ignore-syntax/index.md)を参照 3. **許可リスト**: クラスを設定の `allowed` 配列に追加 一度限りのものには任意値を優先してください。繰り返される正当な例外には許可リストを予約してください。 ## 参考資料 このリンターは、より広い [zudo-css-wisdom メソドロジー](https://takazudomodular.com/pj/zudo-css-wisdom/docs/methodology/)(Tailwind CSS で一貫性のあるメンテナンス可能なデザインシステムを構築するためのパターン集)の具体的な強制実装です。理論的背景の全貌についてはそちらを参照してください。 --- # 無視構文 > Source: https://takazudomodular.com/pj/zudo-design-token-lint/ja/docs/guide/ignore-syntax 正当な理由で禁止されたクラスを使う必要がある場合があります — サードパーティ統合、一度限りの実験、または意図的なエスケープハッチなど。無視コメントを使って次の行の違反を抑制します。 ## 構文 違反を含む行の**直前の行**に `design-token-lint-ignore` コメントを配置します。3 つのコメント形式が認識されます: ### JSX/TSX ```tsx {/* design-token-lint-ignore */} ``` ### CSS-in-JS / ブロックコメント ```tsx /* design-token-lint-ignore */ ``` ### 行コメント ```tsx // design-token-lint-ignore ``` ## 動作の仕組み リンターがファイルをスキャンするとき、無視マーカーを記憶します。各違反について、前の行がマークされているかをチェックします。マークされていれば違反は抑制されます。 無視コメントは**次の行のみ**に影響します。それ以降の違反は抑制されません。 ```tsx {/* design-token-lint-ignore */} {/* 抑制される */} {/* 抑制されない */} ``` ## 使うべきとき ### 良い理由 - **サードパーティライブラリの統合** — コンポーネントが props として生の Tailwind クラスを要求する場合 - **生成されたコード** — 修正できない、または修正すべきでない自動生成ファイル - **一時的な回避策** — 理由を説明するコメント付きで ### 悪い理由 - **「セマンティックトークンを追加するのが面倒」** — トークンを追加してください - **広範な使用** — 多数の場所で同じクラスを無視している場合は、設定の `allowed` リストに追加してください - **リンターを完全にサイレンスする** — それは目的に反します ## ファイルレベルの無視 ファイル全体をスキップするには、ファイルのどこかに `design-token-lint-ignore-file` コメントを追加します。リンターはそのファイルの内容に関わらず違反をゼロとして扱います。 ### JSX/TSX ```tsx {/* design-token-lint-ignore-file */} ``` ### CSS-in-JS / ブロックコメント ```tsx /* design-token-lint-ignore-file */ ``` ### 行コメント ```tsx // design-token-lint-ignore-file ``` コメントはファイルの先頭でもファイル内のどこでも配置できます — どちらの場合もファイル全体がスキップされます。 ### ファイルレベルの無視を使うべきとき - **生成されたファイル** — 修正できない、または修正すべきでない自動生成出力(例: アイコンスプライト、Storybook ストーリーファイル、自動生成ラッパー) - **移行中のレガシーファイル** — 大規模なコードベース移行を進める間、一時的にファイルを抑制し、完了したらコメントを削除する - **テストフィクスチャ** — 意図的に生のユーティリティクラスを含むスナップショットやフィクスチャファイル ファイルレベルの無視を、アクティブなソースファイルに対する包括的な抑制として使用することは避けてください。特定の例外には行レベルの無視または `allowed` 設定リストを優先してください。 ## 代替手段 無視コメントに手を伸ばす前に、次を検討してください: 1. **任意値構文**: `p-[14px]` は明示的で無視を必要としません 2. **セマンティックトークン**: 適切なスケールがあれば `p-hgap-md` 3. **設定の許可リスト**: 繰り返される正当な例外であれば `.design-token-lint.json` の `allowed` にクラスを追加 ## 無視の文書化 無視コメントは、レビュアーが注意を払っていないと diff 上で見えなくなります。将来のメンテナーが理解できるよう `why` コメントを追加してください: ```tsx {/* design-token-lint-ignore — サードパーティの Calendar ウィジェットが生の p-4 を要求 */} ``` --- # 使用例 > Source: https://takazudomodular.com/pj/zudo-design-token-lint/ja/docs/guide/examples 実際のプロジェクトで使える設定と使用パターン — 汎用的なプレースホルダーではなく、具体的なトークンを使います。 ## このツールが解決する問題 Tailwind のデフォルトの spacing スケールには30以上の数値ステップがあります(`p-1`、`p-2`、`p-3`、`p-4` … `p-96`)。あらゆる値が有効な状態では、開発者はそれぞれ微妙に異なる値を選んでしまいます: ```tsx // 開発者 A のコンポーネント — p-4 を使用 // 開発者 B のコンポーネント — 「中くらいのパディング」のつもりで p-5 を使用 // 開発者 C のコンポーネント — p-6 を使用 ``` 3つともコンパイルは通ります。UIは少しずつズレていきます。 `design-token-lint` はこれらの数値ユーティリティを検出し、プロジェクト定義のセマンティックトークンのみが使われるようにします。1つのlintルールで、全体のスペーシングが統一されます。 ## 具体的なトークンシステム このページの例では、実際のトークンシステムを使います — このドキュメントサイト自体が使っているものと同じです。 ### スペーシングトークン 単一の数値スケールの代わりに、2つのセマンティック軸を使います: **水平スペーシング**(`hsp-*`)— インラインギャップ、水平方向のパディング: | トークン | 値 | 用途 | | --- | --- | --- | | `hsp-2xs` | 2px | タイトなインラインスペーシング | | `hsp-xs` | 6px | コンパクトなインライン | | `hsp-sm` | 8px | 小さなパディング | | `hsp-md` | 12px | デフォルトのギャップ | | `hsp-lg` | 16px | 標準的なパディング | | `hsp-xl` | 24px | 余裕のあるパディング | | `hsp-2xl` | 32px | 大きなパディング | **垂直スペーシング**(`vsp-*`)— セクションギャップ、垂直方向のパディング: | トークン | 値 | 用途 | | --- | --- | --- | | `vsp-2xs` | 7px | タイトなギャップ | | `vsp-xs` | 14px | 小さなギャップ | | `vsp-sm` | 20px | コンパクトなギャップ | | `vsp-md` | 24px | 標準的なギャップ | | `vsp-lg` | 28px | セクションギャップ | | `vsp-xl` | 40px | 大きなセクションギャップ | | `vsp-2xl` | 56px | ページレベルのギャップ | ### カラートークン パレットのシェードではなく、セマンティックな名前を使います: | トークン | Tailwindクラス | 意味 | | --- | --- | --- | | `surface` | `bg-surface` | カード・サイドバーの背景 | | `muted` | `text-muted` | 二次的な、目立たないテキスト | | `accent` | `bg-accent` | プライマリのインタラクティブカラー | | `accent-hover` | `bg-accent-hover` | アクセントのホバー状態 | | `code-bg` | `bg-code-bg` | インラインコードの背景 | | `code-fg` | `text-code-fg` | インラインコードのテキスト | | `success` | `text-success` | 成功状態 | | `danger` | `text-danger` | エラー・破壊的な操作 | | `warning` | `text-warning` | 注意状態 | | `info` | `text-info` | 情報提供 | これらはグローバルCSSの `@theme` に登録されています — `bg-gray-200` や `bg-blue-600` はそのトークンが存在しないため使用できません。使おうとするとlint違反になります。 ## リンターが検出するもの このトークンシステム用の設定: ```json { "prohibited": [ "p-{n}", "px-{n}", "py-{n}", "pt-{n}", "pr-{n}", "pb-{n}", "pl-{n}", "m-{n}", "mx-{n}", "my-{n}", "mt-{n}", "mr-{n}", "mb-{n}", "ml-{n}", "gap-{n}", "gap-x-{n}", "gap-y-{n}", "space-x-{n}", "space-y-{n}", "bg-{color}-{shade}", "text-{color}-{shade}", "border-{color}-{shade}" ], "allowed": ["p-0", "m-0", "gap-0", "p-px"], "patterns": ["src/**/*.{tsx,jsx,astro}"], "ignore": ["**/*.test.*", "**/*.stories.*"], "suggestionSuffix": "use semantic token (hsp-*/vsp-*) or arbitrary value" } ``` リンターが報告する違反: | クラス | 理由 | 修正 | | --- | --- | --- | | `p-4` | `p-{n}` にマッチ | → `p-hsp-lg`(16px 標準パディング) | | `gap-2` | `gap-{n}` にマッチ | → `gap-hsp-sm`(8px 小さなギャップ) | | `bg-gray-200` | `bg-{color}-{shade}` にマッチ | → `bg-surface`(サーフェス背景) | | `text-gray-500` | `text-{color}-{shade}` にマッチ | → `text-muted`(二次的なテキスト) | | `bg-blue-600` | `bg-{color}-{shade}` にマッチ | → `bg-accent`(プライマリカラー) | ## 修正前後の比較 生の Tailwind を使ったカードコンポーネントと、セマンティックトークンを使った同じコンポーネントを比較します。 ### 修正前 — 生の数値ユーティリティ ```tsx // ArticleCard.tsx — design-token-lint に検出される return ( {title} {excerpt} {tag} ) } ``` リンターが検出するクラス: `p-4`、`bg-gray-100`、`text-gray-900`、`mb-2`、`text-gray-600`、`mb-4`、`gap-2`、`px-3`、`py-1`、`bg-blue-600`。 ### 修正後 — セマンティックトークン ```tsx // ArticleCard.tsx — クリーン return ( {title} {excerpt} {tag} ) } ``` ### セマンティックバージョンが優れている理由 **一元的な変更** — デザインチームがアクセントカラーを変更する場合、1つのCSS変数(`--color-accent`)を更新するだけで、コードベース全体のすべての `bg-accent` が更新されます。`bg-blue-600` の場合は、何百ものファイルをgrepして置換する必要があります。 **意図が伝わる** — `bg-surface` は「これはサーフェスレベルの背景」であることを伝えます。`bg-gray-100` は数値以外何も伝えません。6ヶ月後も、トークン名は意味を持ち続けます。 **ズレが起きない** — `p-hsp-lg` はどこでも同じ値です。`p-4` は、誰かが Tailwind の設定を変更しない限り16pxですが、セマンティックトークンはテーマの上書きに耐えられます。 **強制力がある** — リンターはスタイルガイドの脚注をCIの失敗に変えます。違反はデザインレビューではなく、PRの段階で検出されます。 ## 実際的な設定例 ### タイトトークンプロジェクト(推奨) Tailwind のデフォルトをセマンティックトークンで完全に置き換えたプロジェクト: ```json { "prohibited": [ "p-{n}", "px-{n}", "py-{n}", "pt-{n}", "pr-{n}", "pb-{n}", "pl-{n}", "m-{n}", "mx-{n}", "my-{n}", "mt-{n}", "mr-{n}", "mb-{n}", "ml-{n}", "gap-{n}", "gap-x-{n}", "gap-y-{n}", "space-x-{n}", "space-y-{n}", "bg-{color}-{shade}", "text-{color}-{shade}", "border-{color}-{shade}", "ring-{color}-{shade}" ], "allowed": ["p-0", "m-0", "gap-0", "p-px"], "ignore": [ "**/*.test.*", "**/*.stories.*", "**/vendor/**" ], "patterns": [ "src/**/*.{tsx,jsx,astro}", "components/**/*.{tsx,jsx,astro}" ], "suggestionSuffix": "use semantic token (hsp-*/vsp-*) or arbitrary value" } ``` ### 段階的な移行 生の Tailwind を使った大規模なコードベースがある場合、まずカラーだけ始めて、後でスペーシングを追加します: ```json { "prohibited": [ "bg-{color}-{shade}", "text-{color}-{shade}", "border-{color}-{shade}" ], "allowed": [], "patterns": ["src/**/*.{tsx,jsx}"], "suggestionSuffix": "use a semantic color token instead" } ``` カラーがクリーンになったら、スペーシングパターンを `prohibited` に追加します。 ### Next.js プロジェクト ```json { "prohibited": [ "p-{n}", "m-{n}", "gap-{n}", "bg-{color}-{shade}", "text-{color}-{shade}" ], "allowed": ["p-0", "m-0", "gap-0"], "ignore": [ "**/*.test.*", "**/*.stories.*", ".next/**" ], "patterns": [ "app/**/*.{tsx,jsx}", "components/**/*.{tsx,jsx}", "pages/**/*.{tsx,jsx}" ] } ``` ### Astro プロジェクト ```json { "prohibited": [ "p-{n}", "m-{n}", "gap-{n}", "bg-{color}-{shade}", "text-{color}-{shade}", "border-{color}-{shade}" ], "allowed": ["p-0", "m-0", "gap-0"], "ignore": [ "**/*.test.*", "dist/**", ".astro/**" ], "patterns": [ "src/**/*.{astro,tsx,jsx}" ] } ``` ## 複数パッケージの monorepo モノレポのルートに設定を置き、すべてのパッケージをスキャンします: ```json { "prohibited": [ "p-{n}", "m-{n}", "gap-{n}", "bg-{color}-{shade}", "text-{color}-{shade}" ], "allowed": ["p-0", "m-0", "gap-0"], "ignore": [ "**/node_modules/**", "**/dist/**", "**/*.test.*" ], "patterns": [ "packages/*/src/**/*.{tsx,jsx,astro}", "apps/*/src/**/*.{tsx,jsx,astro}" ] } ``` ## CI 統合 — GitHub Actions 違反があれば CI を失敗させる: ```yaml # .github/workflows/lint.yml name: Lint on: [push, pull_request] jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: node-version: 20 cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm design-token-lint ``` ## Pre-push フック [lefthook](https://github.com/evilmartians/lefthook) でプッシュ前に実行: ```yaml # lefthook.yml pre-push: commands: design-token-lint: run: npx design-token-lint ``` ## カスタムスクリプト プログラマティック API を使ってプロジェクト固有のロジックでリンターを実行: ```ts // scripts/lint-tokens.mjs const config = await loadConfig(process.cwd()); setConfig(compileConfig(config)); const files = await glob('src/**/*.{tsx,jsx}'); let totalViolations = 0; for (const file of files) { const results = await lintFile(file); for (const r of results) { console.log(`${r.filePath}:${r.line} ${r.className} ${r.reason}`); totalViolations++; } } process.exit(totalViolations > 0 ? 1 : 0); ``` ## 正当な例外の無視 生の Tailwind を要求するサードパーティコンポーネントを統合する場合: ```tsx {/* design-token-lint-ignore — ベンダーコンポーネントがリテラル p-4 を要求 */} ``` すべてのコメント形式については[無視構文](../ignore-syntax/index.md)を参照してください。 --- # v0.1.0 > Source: https://takazudomodular.com/pj/zudo-design-token-lint/ja/docs/changelog/v0.1.0 `@zudolab/design-token-lint` の初回リリース。 - CLI: `design-token-lint` ファイル/glob 引数とデフォルトスキャンパターン - `.design-token-lint.json` で禁止パターン、許可例外、無視ファイルを設定可能 - パターンプレースホルダー: `{n}`、`{color}`、`{shade}` - 無視コメント: `{/* design-token-lint-ignore */}` とそのバリアント - プログラマティック API: `lintFile`、`lintContent`、`checkClass`、`extractClasses`、設定読み込みユーティリティ - Tailwind の間隔とカラーユーティリティ用の組み込みデフォルトルール