sparkle-design-cli 2.5.0-beta.1 → 2.5.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +9 -0
- package/README.md +24 -4
- package/bin/sparkle-design.js +92 -13
- package/docs/config.md +27 -2
- package/lib/anti-pattern-rules.js +137 -3
- package/lib/auth.js +302 -0
- package/lib/check.js +25 -4
- package/lib/load-plugins.js +6 -0
- package/lib/path-utils.js +120 -0
- package/lib/rules-report.js +42 -7
- package/lib/stop-hook.js +116 -3
- package/lib/token-migration.js +210 -0
- package/package.json +5 -5
package/CONTRIBUTING.md
CHANGED
|
@@ -27,6 +27,15 @@ npm run sync:anti-pattern-docs # ルールの解説を隣接リポジトリの
|
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
> **`sync:anti-pattern-docs` の注意:** ワークスペース内の隣接リポジトリ(`../sparkle-design` / `../sparkle-design-internal`)のファイルを書き換える横断スクリプトです。両リポジトリが隣にある Sparkle ワークスペース内で実行してください(worktree からは sibling が解決できず落ちます)。**このリポジトリの README は書き換えません** — ルール一覧は `rules` コマンドが出すためです。
|
|
30
|
+
>
|
|
31
|
+
> **共有チェックアウトに向けて実行しないこと。** 隣接リポジトリで誰かが作業中だと、その未コミット変更に自分の生成物が混ざります。実行後に `git checkout -- .` で戻そうとして**他人の変更まで消す事故が実際に起きました**。同期専用の worktree を切り、`SPARKLE_DESIGN_ROOT` / `SPARKLE_DESIGN_INTERNAL_ROOT` でそこを指してください。
|
|
32
|
+
>
|
|
33
|
+
> ```bash
|
|
34
|
+
> git -C ../sparkle-design worktree add .claude/worktrees/docs-sync -b chore/sync-anti-pattern-docs
|
|
35
|
+
> SPARKLE_DESIGN_ROOT=../sparkle-design/.claude/worktrees/docs-sync npm run sync:anti-pattern-docs
|
|
36
|
+
> ```
|
|
37
|
+
>
|
|
38
|
+
> 実行前に対象リポジトリが clean であることを `git status` で確認し、戻すときも**自分が触ったファイルだけを明示的に指定**してください(`git checkout -- <path>`)。
|
|
30
39
|
|
|
31
40
|
## リリース手順(メンテナ向け)
|
|
32
41
|
|
package/README.md
CHANGED
|
@@ -73,6 +73,9 @@ npx sparkle-design-cli check src --format json
|
|
|
73
73
|
|
|
74
74
|
# 現在有効なアンチパターンルールを一覧表示(プラグイン由来のものも含む)
|
|
75
75
|
npx sparkle-design-cli rules
|
|
76
|
+
|
|
77
|
+
# Artifact Registry の npm registry 用トークンを ~/.npmrc に書く(beta)
|
|
78
|
+
npx --yes sparkle-design-cli@beta auth
|
|
76
79
|
```
|
|
77
80
|
|
|
78
81
|
### generate: 基本的な使用方法
|
|
@@ -94,7 +97,7 @@ npx sparkle-design-cli rules
|
|
|
94
97
|
npx sparkle-design-cli generate
|
|
95
98
|
```
|
|
96
99
|
|
|
97
|
-
3. `src/app/sparkle-design.css`
|
|
100
|
+
3. CSS ファイルが生成されます(既定は `src/app/sparkle-design.css`。`extend.globals-path` や `--globals-path` で Tailwind エントリ CSS を明示していて、それが実在する場合はそのディレクトリに出ます)。
|
|
98
101
|
|
|
99
102
|
### generate: コマンドオプション
|
|
100
103
|
|
|
@@ -125,7 +128,7 @@ sparkle-design-cli generate -c ./config/sparkle.admin.json --scope '[data-tenant
|
|
|
125
128
|
|
|
126
129
|
- `-h, --help`: ヘルプメッセージを表示
|
|
127
130
|
- `-c, --config <パス>`: 設定ファイルのパス(デフォルト: `./sparkle.config.json`)
|
|
128
|
-
- `-o, --output <パス>`:
|
|
131
|
+
- `-o, --output <パス>`: 出力ファイルのパス。未指定時は、明示された Tailwind エントリ CSS(`--globals-path` / `extend.globals-path`)が実在すればそのディレクトリ、無ければ `./src/app/sparkle-design.css`
|
|
129
132
|
- `--globals-path <パス>`: Tailwind エントリポイント CSS のパス(デフォルト: 自動検出)。
|
|
130
133
|
**指定したパスが存在しない場合は `--strict` の有無に関わらず常に exit 1**(`sparkle.config.json` の `extend.globals-path` も同様)
|
|
131
134
|
- `--strict`: 以下を warn ではなく **exit 1** に昇格させる(CI 向け。既定は warn + 継続で後方互換を維持):
|
|
@@ -197,6 +200,23 @@ npx sparkle-design-cli rules --format json
|
|
|
197
200
|
|
|
198
201
|
AI エージェントや CI からこの `lint:sparkle` を呼ぶ運用にすると、ガイドラインの注意書きだけに頼らず機械的に検査できます。
|
|
199
202
|
|
|
203
|
+
### auth: Artifact Registry の認証(beta)
|
|
204
|
+
|
|
205
|
+
社内パッケージの配信先を Google Artifact Registry(AR)に移行するための準備です(goodpatch/sparkle-design-internal#261)。Google の資格情報から AR 用のアクセストークンを取得し、ユーザー単位の `~/.npmrc` に書きます。
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
gcloud auth login # 初回のみ(ADC を使う場合は gcloud auth application-default login)
|
|
209
|
+
npx --yes sparkle-design-cli@beta auth # プロジェクトの .npmrc の @goodpatch:registry が対象
|
|
210
|
+
pnpm install
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
- 対象の registry は `--registry <url>`、無ければプロジェクトの `.npmrc`(親ディレクトリも辿る)の `@goodpatch:registry=` です。プロジェクトの `.npmrc` には registry 行だけを置けばよく、そのままコミットできます
|
|
214
|
+
- トークンの取得は ADC → `gcloud auth print-access-token` の順です。どちらも使えなければ `gcloud auth login` を案内して終了します
|
|
215
|
+
- **トークンは約 60 分で失効します。** `pnpm install` が 401 で落ちたら(npm は `npm adduser` を案内しますが、AR では解決しません)もう一度 `auth` を実行してください
|
|
216
|
+
- 同じ registry の行は置き換えるので、何度実行しても `~/.npmrc` に行は積み上がりません。`always-auth` は書きません
|
|
217
|
+
- トークンは Artifact Registry(`<location>-npm.pkg.dev`)以外には書きません。`cloud-platform` スコープの Google トークンなので、ほかのホストに渡すと資格情報の漏えいになるためです
|
|
218
|
+
- トークンを画面に出さず、refresh token などの長期クレデンシャルもコピーしません(gcloud の管理下に置いたまま)
|
|
219
|
+
|
|
200
220
|
### setup: プロジェクトのフルセットアップ
|
|
201
221
|
|
|
202
222
|
`sparkle-design-cli setup` は、Sparkle Design の導入に必要な作業をまとめて行います:
|
|
@@ -274,7 +294,7 @@ npx --yes sparkle-design-cli setup --assistant claude --skip-install --skip-scaf
|
|
|
274
294
|
|
|
275
295
|
## 出力
|
|
276
296
|
|
|
277
|
-
-
|
|
297
|
+
- 既定の出力先: `src/app/sparkle-design.css`(Tailwind エントリ CSS を明示していて実在する場合はそのディレクトリ)
|
|
278
298
|
- カスタム出力先: `-o` オプションで指定可能
|
|
279
299
|
- 実行場所を基準として相対パスで処理されます
|
|
280
300
|
|
|
@@ -283,7 +303,7 @@ npx --yes sparkle-design-cli setup --assistant claude --skip-install --skip-scaf
|
|
|
283
303
|
CLI は **Tailwind エントリ CSS(`@import "tailwindcss"` を含む CSS ファイル)** を自動検出し、以下を 1 回で揃えます:
|
|
284
304
|
|
|
285
305
|
- `sparkle-design.css` の `@import`
|
|
286
|
-
- `@source "
|
|
306
|
+
- `@source "<エントリ CSS から node_modules への相対パス>/sparkle-design/dist"`(v4 が node_modules のクラスを拾うのに必要)。相対パスはエントリ CSS の位置から毎回計算されるので、`src/app/globals.css` なら `../../node_modules/...` になります
|
|
287
307
|
- フォント `<link>` タグ(React 向けは `SparkleHead.tsx`、Vite 向けは `index.html` の managed block に自動注入)
|
|
288
308
|
|
|
289
309
|
CSS 仕様上 `@import` は他の at-rule より前に書く必要があるため、順序も適切に整えます。`@import "tailwindcss"` が欠けている場合は先頭に自動追記されます。
|
package/bin/sparkle-design.js
CHANGED
|
@@ -7,8 +7,17 @@ import { runStopHook } from '../lib/stop-hook.js';
|
|
|
7
7
|
import { PLUGIN_SPEC_MARKDOWN } from '../lib/plugin-api.js';
|
|
8
8
|
import { loadAntiPatternPlugins } from '../lib/load-plugins.js';
|
|
9
9
|
import { runRules } from '../lib/rules-report.js';
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
import { runAuth } from '../lib/auth.js';
|
|
11
|
+
|
|
12
|
+
const SUBCOMMANDS = new Set([
|
|
13
|
+
'generate',
|
|
14
|
+
'check',
|
|
15
|
+
'rules',
|
|
16
|
+
'setup',
|
|
17
|
+
'auth',
|
|
18
|
+
'stop-hook',
|
|
19
|
+
'plugin-spec',
|
|
20
|
+
]);
|
|
12
21
|
|
|
13
22
|
function requireOptionValue(args, index, flags) {
|
|
14
23
|
const value = args[index + 1];
|
|
@@ -146,11 +155,15 @@ function parseSetupOptions(args) {
|
|
|
146
155
|
* and exit 0, handing non-JSON stdout to a caller that asked for JSON.
|
|
147
156
|
*/
|
|
148
157
|
function parseRulesOptions(args) {
|
|
149
|
-
const options = { format: 'text' };
|
|
158
|
+
const options = { format: 'text', help: false };
|
|
150
159
|
const FORMATS = new Set(['text', 'json']);
|
|
151
160
|
|
|
152
161
|
for (let i = 0; i < args.length; i += 1) {
|
|
153
162
|
const arg = args[i];
|
|
163
|
+
if (arg === '-h' || arg === '--help') {
|
|
164
|
+
options.help = true;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
154
167
|
if (arg === '--format') {
|
|
155
168
|
const value = requireOptionValue(args, i, '--format');
|
|
156
169
|
if (!FORMATS.has(value)) {
|
|
@@ -166,6 +179,30 @@ function parseRulesOptions(args) {
|
|
|
166
179
|
return options;
|
|
167
180
|
}
|
|
168
181
|
|
|
182
|
+
/**
|
|
183
|
+
* `auth` のオプション。未知のフラグはその場で失敗させる(他のサブコマンドと同じ)。
|
|
184
|
+
* en: Unknown flags fail fast, same as the other subcommands.
|
|
185
|
+
*/
|
|
186
|
+
function parseAuthOptions(args) {
|
|
187
|
+
const options = { registry: null, help: false };
|
|
188
|
+
|
|
189
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
190
|
+
const arg = args[i];
|
|
191
|
+
if (arg === '-h' || arg === '--help') {
|
|
192
|
+
options.help = true;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (arg === '--registry') {
|
|
196
|
+
options.registry = requireOptionValue(args, i, '--registry');
|
|
197
|
+
i += 1;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
throw new Error(`Unknown option for auth: ${arg}`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return options;
|
|
204
|
+
}
|
|
205
|
+
|
|
169
206
|
function showHelp() {
|
|
170
207
|
console.log(`
|
|
171
208
|
Sparkle Design CLI
|
|
@@ -178,6 +215,7 @@ Commands:
|
|
|
178
215
|
check Sparkle Design のアンチパターンを検査
|
|
179
216
|
rules 現在有効なアンチパターンルールを一覧表示(プラグイン由来のものも含む)
|
|
180
217
|
setup Sparkle Design プロジェクトをセットアップ(パッケージ導入 + 初期ファイル + AI ガード + generate)
|
|
218
|
+
auth Artifact Registry の npm registry 用アクセストークンを ~/.npmrc に書く(beta)
|
|
181
219
|
stop-hook AI assistant の Stop hook 用 internal subcommand(severity=error の findings か、
|
|
182
220
|
実行に失敗して未検査のルールがあるときに exit 2 で 1 度だけ停止をブロック / 再発火は自動回避。
|
|
183
221
|
warning / info はブロックせず件数の要約を stderr に出す)
|
|
@@ -189,7 +227,7 @@ Generate:
|
|
|
189
227
|
sparkle-design-cli generate --output ./styles/design.css
|
|
190
228
|
sparkle-design-cli generate -c ./config/custom.json -o ./dist/styles.css
|
|
191
229
|
|
|
192
|
-
# 単一バンドル内でランタイムにテーマ切替したい場合(--scope。詳細は
|
|
230
|
+
# 単一バンドル内でランタイムにテーマ切替したい場合(--scope。詳細は docs/theming.md 参照)
|
|
193
231
|
sparkle-design-cli generate -c ./config/sparkle.employee.json -o ./src/styles/sparkle-employee.css
|
|
194
232
|
sparkle-design-cli generate -c ./config/sparkle.admin.json --scope '[data-tenant-theme="admin"]' -o ./src/styles/sparkle-admin-scope.css
|
|
195
233
|
|
|
@@ -207,6 +245,10 @@ Plugin spec:
|
|
|
207
245
|
sparkle-design-cli plugin-spec # アンチパターン拡張プラグインの契約仕様を出力
|
|
208
246
|
sparkle-design-cli plugin-spec --list # 現在のプロジェクトで発見されたプラグインを表示
|
|
209
247
|
|
|
248
|
+
Auth (beta):
|
|
249
|
+
sparkle-design-cli auth # プロジェクトの .npmrc の @goodpatch:registry を対象に認証
|
|
250
|
+
sparkle-design-cli auth --registry https://asia-northeast1-npm.pkg.dev/<project>/<repository>/
|
|
251
|
+
|
|
210
252
|
Setup:
|
|
211
253
|
sparkle-design-cli setup # フルセットアップ(推奨・新規導入時)
|
|
212
254
|
sparkle-design-cli setup --assistant claude # Claude 向けガードも同時にセットアップ
|
|
@@ -232,8 +274,7 @@ Generate options:
|
|
|
232
274
|
だけを実値までリテラル化して指定セレクタの中にラップ出力する
|
|
233
275
|
(例: '[data-tenant-theme="admin"]')。-o/--output の指定が必須。
|
|
234
276
|
--strict / --globals-path とは併用不可(グローバル CSS を
|
|
235
|
-
パッチしないため)。詳細は
|
|
236
|
-
切替する場合」を参照
|
|
277
|
+
パッチしないため)。詳細は docs/theming.md の「ケース B」を参照
|
|
237
278
|
|
|
238
279
|
sparkle.config.json の設定フィールド:
|
|
239
280
|
|
|
@@ -241,7 +282,7 @@ sparkle.config.json の設定フィールド:
|
|
|
241
282
|
primary プライマリカラー (必須。blue, red, orange, yellow, purple, green, pink の
|
|
242
283
|
いずれか。未指定、またはそれ以外の値は generate 実行時にエラーになります。
|
|
243
284
|
7色にないブランドカラーを使いたい場合は extend.custom-css で
|
|
244
|
-
--color-primary-* / --color-gray-* を再定義してください。詳細は
|
|
285
|
+
--color-primary-* / --color-gray-* を再定義してください。詳細は docs/config.md を参照)
|
|
245
286
|
font-pro プロポーショナルフォント (Google Fonts の名前)
|
|
246
287
|
font-mono モノスペースフォント (Google Fonts の名前)
|
|
247
288
|
radius 角丸設定 (必須。none, xs, sm, md, lg, xl, 2xl, 3xl のいずれか。
|
|
@@ -272,6 +313,19 @@ Check options:
|
|
|
272
313
|
(warning / info は報告のみで exit code に影響しない)
|
|
273
314
|
--format <text|json> 出力形式 (default: text)
|
|
274
315
|
|
|
316
|
+
Auth options:
|
|
317
|
+
-h, --help このヘルプメッセージを表示
|
|
318
|
+
--registry <url> 対象の registry(default: プロジェクトの .npmrc の @goodpatch:registry)
|
|
319
|
+
|
|
320
|
+
Auth の動作:
|
|
321
|
+
1. Google の資格情報(ADC → gcloud auth print-access-token の順)からアクセストークンを取得
|
|
322
|
+
どちらも無い / 期限切れなら gcloud auth login を案内して終了
|
|
323
|
+
2. ユーザー単位の ~/.npmrc(NPM_CONFIG_USERCONFIG があればそちら)に、同じ registry の行を
|
|
324
|
+
置き換えて書く(プロジェクトの .npmrc は registry 行のみのまま、コミットできる状態を保つ)
|
|
325
|
+
3. 有効期限(約 60 分)を表示する。切れたらもう一度 auth を実行する
|
|
326
|
+
トークンは Artifact Registry(<location>-npm.pkg.dev)にだけ書き、画面には出しません。
|
|
327
|
+
refresh token などの長期クレデンシャルは gcloud の管理下に置いたままで、コピーしません。
|
|
328
|
+
|
|
275
329
|
Setup options:
|
|
276
330
|
-h, --help このヘルプメッセージを表示
|
|
277
331
|
--assistant <name> claude / codex / cursor / generic (default: generic)
|
|
@@ -407,18 +461,43 @@ async function main() {
|
|
|
407
461
|
return;
|
|
408
462
|
}
|
|
409
463
|
|
|
464
|
+
if (command === 'auth') {
|
|
465
|
+
const options = parseAuthOptions(args.slice(1));
|
|
466
|
+
if (options.help) {
|
|
467
|
+
showHelp();
|
|
468
|
+
process.exit(0);
|
|
469
|
+
}
|
|
470
|
+
await runAuth(options);
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
|
|
410
474
|
if (command === 'stop-hook') {
|
|
411
475
|
// setup で各 agent の hook 設定ファイルから呼ばれる internal subcommand。
|
|
412
|
-
//
|
|
413
|
-
//
|
|
414
|
-
//
|
|
415
|
-
|
|
416
|
-
|
|
476
|
+
// 以降の引数はすべて lint 対象 path。setup が書き出す hook は 1 つだが、
|
|
477
|
+
// 利用側が `stop-hook apps/web/app apps/web/components` のように手で複数
|
|
478
|
+
// 並べている実例があり、以前は args[1] しか読まず 2 つ目以降が黙って
|
|
479
|
+
// 未検査になっていた(issue #85)。option flag は未対応なので、`-` 始まりは
|
|
480
|
+
// path として渡さず警告する。
|
|
481
|
+
// en: Forward every positional arg. Previously only the first was used, so
|
|
482
|
+
// extra paths in a hand-written hook command were silently never checked.
|
|
483
|
+
const positional = args.slice(1).filter((arg) => !arg.startsWith('-'));
|
|
484
|
+
const flags = args.slice(1).filter((arg) => arg.startsWith('-'));
|
|
485
|
+
if (flags.length > 0) {
|
|
486
|
+
console.warn(
|
|
487
|
+
`⚠️ stop-hook はオプションを受け付けません。無視します: ${flags.join(' ')} / stop-hook takes target paths only.`
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
const exitCode = await runStopHook(positional);
|
|
417
491
|
process.exit(exitCode);
|
|
418
492
|
}
|
|
419
493
|
|
|
420
494
|
if (command === 'rules') {
|
|
421
|
-
|
|
495
|
+
const options = parseRulesOptions(args.slice(1));
|
|
496
|
+
if (options.help) {
|
|
497
|
+
showHelp();
|
|
498
|
+
process.exit(0);
|
|
499
|
+
}
|
|
500
|
+
await runRules(options);
|
|
422
501
|
return;
|
|
423
502
|
}
|
|
424
503
|
|
package/docs/config.md
CHANGED
|
@@ -34,13 +34,38 @@ Figma プラグインが出力する基本4項目に加えて、プロジェク
|
|
|
34
34
|
}
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
## extend.globals-path
|
|
38
|
+
|
|
39
|
+
Tailwind のエントリポイント CSS(`@import "tailwindcss";` を書いているファイル)のパスです。未指定なら自動検出します。CLI の `--globals-path` でも同じ指定ができ、そちらが優先されます。
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"primary": "blue",
|
|
44
|
+
"extend": {
|
|
45
|
+
"globals-path": "src/styles/app.css"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
指定すると次の 2 つに効きます。
|
|
51
|
+
|
|
52
|
+
| 効き先 | 内容 |
|
|
53
|
+
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
54
|
+
| `@source` と `sparkle-design.css` の import 先 | そのファイルにパッチする(**フォントの `@import` は入りません**。フォント読み込みは `SparkleHead.tsx` 側に移っています) |
|
|
55
|
+
| `generate` の出力先 | `-o/--output` 未指定なら**そのファイルと同じディレクトリ**に `sparkle-design.css` と `SparkleHead.tsx` を出す |
|
|
56
|
+
|
|
57
|
+
後者が重要です。既定の `src/app/` に固定されるのは globals-path を明示していない場合だけなので、`src/index.css` や `src/styles/app.css` 構成のプロジェクトで意図しない `src/app/` ディレクトリが増えることはありません。
|
|
58
|
+
|
|
59
|
+
> [!WARNING]
|
|
60
|
+
> **指定したパスが存在しない場合は `--strict` の有無に関わらず常に exit 1** です。typo に気付かないまま誤ったディレクトリを掘るより、その場で止めるほうが安全なためです。相対パスのみで、`..` を含む traversal や絶対パスは弾かれます。
|
|
61
|
+
|
|
37
62
|
## extend.fonts
|
|
38
63
|
|
|
39
64
|
フォントごとにウェイトを個別指定。`extend.fonts` がない場合は `font-pro` / `font-mono` + デフォルトウェイト `[400, 700]` が使われます。`extend.fonts` が存在しても `fonts.pro` / `fonts.mono` のどちらかが未指定なら、そのスロットのみ `font-pro` / `font-mono` にフォールバックします。同じフォントファミリーが `pro` と `mono` で重複する場合、ウェイトはマージされ import は 1 行に統合されます。
|
|
40
65
|
|
|
41
66
|
## extend.source-packages
|
|
42
67
|
|
|
43
|
-
既知のデザインシステムパッケージ(`sparkle-design` など)は `package.json` から**自動検出**されるので、通常は指定不要です。クライアント固有のパッケージなど自動検出の対象外を追加したいときだけ指定してください。指定分は自動検出分とマージされ、Tailwind エントリ CSS(自動検出)に `@source`
|
|
68
|
+
既知のデザインシステムパッケージ(`sparkle-design` など)は `package.json` から**自動検出**されるので、通常は指定不要です。クライアント固有のパッケージなど自動検出の対象外を追加したいときだけ指定してください。指定分は自動検出分とマージされ、Tailwind エントリ CSS(自動検出)に `@source` ディレクティブとして挿入されます。`@source` をまったく出さないのは、**自動検出がゼロで、かつ `source-packages` キー自体を書いていない**ときだけです(キーがあれば空配列でも既定の `sparkle-design` 1 行が出ます)。
|
|
44
69
|
|
|
45
70
|
## extend.custom-css
|
|
46
71
|
|
|
@@ -50,7 +75,7 @@ Figma プラグインが出力する基本4項目に加えて、プロジェク
|
|
|
50
75
|
|
|
51
76
|
### カスタムブランドカラーを primary にしたい場合
|
|
52
77
|
|
|
53
|
-
`primary` は 7
|
|
78
|
+
`primary` は 7 色のいずれかしか受け付けません([README の「設定オプション」](../README.md#設定オプション) を参照)。7 色にないブランドカラーを使いたい場合は、`primary` は 7 色から見た目が近いものを仮に選んだ上で、`extend.custom-css` で `--color-primary-*` と `--color-gray-*` をブランドカラー基準の値で丸ごと再定義してください。`primary` の選択自体は `custom-css` 側の定義で完全に上書きされるため実質的な意味を持たなくなりますが、フィールドとしては有効な値を入れておく必要があります。
|
|
54
79
|
|
|
55
80
|
```css
|
|
56
81
|
/* custom-tokens.css */
|
|
@@ -4,8 +4,10 @@ import {
|
|
|
4
4
|
buildLegacyCssVarPattern,
|
|
5
5
|
buildLegacyScalePattern,
|
|
6
6
|
buildLegacyTokenPattern,
|
|
7
|
+
buildTailwindPalettePattern,
|
|
7
8
|
resolveLegacyCssVar,
|
|
8
9
|
resolveLegacyUtility,
|
|
10
|
+
resolveTailwindPaletteUtility,
|
|
9
11
|
} from './token-migration.js';
|
|
10
12
|
import { buildSpacingUtilityPattern, pxToStep, resolveSpacingStep } from './spacing-scale.js';
|
|
11
13
|
|
|
@@ -378,7 +380,10 @@ const COMPONENT_ANTI_PATTERN_GROUPS = [
|
|
|
378
380
|
description: 'shadcn/ui 既定 token を Sparkle Design 内へ持ち込まない',
|
|
379
381
|
recommendation:
|
|
380
382
|
'text-muted-foreground / bg-background / border-border などは Sparkle Design token に置き換えてください。',
|
|
381
|
-
|
|
383
|
+
// 新セマンティックトークン(border-border-neutral-* 等)へ前方一致しないよう、
|
|
384
|
+
// 直後にハイフン/単語構成文字が続くケースを除外する
|
|
385
|
+
// en: exclude prefix matches against new semantic tokens (e.g. border-border-neutral-*)
|
|
386
|
+
pattern: /\b(text-muted-foreground|bg-background|border-border)(?![\w-])/g,
|
|
382
387
|
},
|
|
383
388
|
featureSection: lines([
|
|
384
389
|
'### shadcn/ui 由来の class / token をそのまま使わない',
|
|
@@ -1013,8 +1018,17 @@ const COMPONENT_ANTI_PATTERN_GROUPS = [
|
|
|
1013
1018
|
check: {
|
|
1014
1019
|
description: 'Tailwind デフォルト typography を Sparkle Design コンポーネント内で使わない',
|
|
1015
1020
|
recommendation:
|
|
1016
|
-
'text-
|
|
1017
|
-
|
|
1021
|
+
'text-xs 〜 text-9xl / font-medium / font-semibold / font-bold は character-* utility に置き換えてください。ただし character-* に対応する token が無いサイズ(text-[10px] 等の arbitrary value、あるいは意図的に token 外のサイズを使う場合)は、同一行または直前行に `// sparkle-disable-line tailwind-typography` コメントを付けて例外扱いとして残すこともできます。font-medium(500) / font-semibold(600) は character-* に対応する token が無いため、`extend.custom-css` で独自クラスを定義してください(詳細は README の「character-* に無いウェイトを使いたい場合」参照)。',
|
|
1022
|
+
// text-base は旧カラートークンの text-base-50 〜 text-base-900 へ前方一致するため、
|
|
1023
|
+
// shadcn-token と同様に直後のハイフン/単語構成文字を除外する
|
|
1024
|
+
// en: exclude prefix matches such as text-base-900 (legacy color token)
|
|
1025
|
+
//
|
|
1026
|
+
// `2xl` までしか見ておらず text-3xl 以上が漏れていた(issue #84)。見出しほど
|
|
1027
|
+
// 大きいサイズを使うので、抜けていた側のほうが目立つ誤りだった。Tailwind の
|
|
1028
|
+
// 既定スケールは text-9xl まで。
|
|
1029
|
+
// en: Sizes above 2xl were missed entirely; Tailwind's scale goes to 9xl.
|
|
1030
|
+
pattern:
|
|
1031
|
+
/\b(text-(?:xs|sm|base|lg|xl|[2-9]xl)|font-(?:medium|semibold|bold|normal|light))(?![\w-])/g,
|
|
1018
1032
|
},
|
|
1019
1033
|
featureSection: lines([
|
|
1020
1034
|
'### Tailwind デフォルト typography を使わない',
|
|
@@ -1402,6 +1416,70 @@ function migrationMatcher(pattern, resolve, label) {
|
|
|
1402
1416
|
};
|
|
1403
1417
|
}
|
|
1404
1418
|
|
|
1419
|
+
const TAILWIND_PALETTE_PATTERN = buildTailwindPalettePattern();
|
|
1420
|
+
|
|
1421
|
+
/**
|
|
1422
|
+
* そのファイルが Sparkle Design を使っているか判定する材料。
|
|
1423
|
+
*
|
|
1424
|
+
* Tailwind 既定パレットの色は「Sparkle を導入したプロジェクトなのに色だけ移行が
|
|
1425
|
+
* 取り残されている」箇所を拾うためのルールなので、Sparkle と無関係なファイル
|
|
1426
|
+
* (素の React コード、管理用スクリプト、vendored なコード)まで報告すると
|
|
1427
|
+
* ノイズになる(issue #84)。
|
|
1428
|
+
*
|
|
1429
|
+
* 2 つの材料を見る:
|
|
1430
|
+
* 1. Sparkle パッケージからの import — `sparkle-design` / `@goodpatch/sparkle-design-internal`
|
|
1431
|
+
* のほか、`sparkle-design/components/...` のようなサブパスも拾えるよう部分一致にする
|
|
1432
|
+
* 2. `character-*` typography の使用 — Sparkle 固有のユーティリティで、
|
|
1433
|
+
* **これが使われている時点でそのファイルは Sparkle に載っている**。
|
|
1434
|
+
* issue #84 の実例はまさに「typography は character-* に移行済みなのに色だけ
|
|
1435
|
+
* Tailwind 既定パレットのまま」という形で、import 判定だけだと
|
|
1436
|
+
* re-export 経由(`@/components/ui/...`)のファイルを取りこぼす
|
|
1437
|
+
*
|
|
1438
|
+
* en: Gate the rule to files that actually use Sparkle — either an import from a
|
|
1439
|
+
* Sparkle package, or a `character-*` utility (Sparkle-specific, and the exact
|
|
1440
|
+
* signal in issue #84 where typography had migrated but colours had not).
|
|
1441
|
+
*/
|
|
1442
|
+
const SPARKLE_USAGE_PATTERNS = [
|
|
1443
|
+
/\b(?:from|import)\s*\(?\s*['"][^'"]*sparkle-design[^'"]*['"]/,
|
|
1444
|
+
/\brequire\(\s*['"][^'"]*sparkle-design[^'"]*['"]\s*\)/,
|
|
1445
|
+
/(?<![\w-])character-\d/,
|
|
1446
|
+
];
|
|
1447
|
+
|
|
1448
|
+
function usesSparkle(content) {
|
|
1449
|
+
return SPARKLE_USAGE_PATTERNS.some((pattern) => pattern.test(content));
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
/**
|
|
1453
|
+
* Tailwind 既定パレットの色ユーティリティを拾う。
|
|
1454
|
+
*
|
|
1455
|
+
* `shadcn-token` の説明文は Tailwind パレット色(`text-slate-500`)も Wrong として
|
|
1456
|
+
* 示していたのに、実際の `check.pattern` は shadcn 由来の 3 語しか見ていなかった。
|
|
1457
|
+
* 「説明が禁止しているものを検査が拾っていない」状態を解消する(issue #84)。
|
|
1458
|
+
*
|
|
1459
|
+
* 生の hex(`#6b7280`)は**検出しない**。SVG・チャート描画・ユーザー定義色など、
|
|
1460
|
+
* 移行対象ではない動的な用途が大半を占めるため(報告元のプロジェクトでは 43 件中
|
|
1461
|
+
* 32 件がこれ)、ルール化すると偽陽性で埋まる。
|
|
1462
|
+
* en: Raw hex values are intentionally out of scope — most of them are dynamic
|
|
1463
|
+
* (SVG, charts, user-defined colours) and would drown the report in false positives.
|
|
1464
|
+
*
|
|
1465
|
+
* `targets` を指定していないので対象はソースファイルのみ。`legacy-color-token` が
|
|
1466
|
+
* `.css` も見るのに対し、こちらは `@apply` を拾わない。CSS には import が無く、
|
|
1467
|
+
* `usesSparkle` の 2 材料のうち `character-*` しか効かないため、対象に加えると
|
|
1468
|
+
* 「CSS の一部だけ検査される」という説明しにくい半端なカバレッジになる。
|
|
1469
|
+
* **意図的な線引きなので、featureSection と description に明記してある。**
|
|
1470
|
+
* en: Source files only. CSS has no imports, so the Sparkle gate would work only
|
|
1471
|
+
* half the time there — an unexplainable partial coverage. The limitation is
|
|
1472
|
+
* stated in the rule's description and feature section rather than left implicit.
|
|
1473
|
+
*/
|
|
1474
|
+
function tailwindPaletteMatcher(rawContent) {
|
|
1475
|
+
if (!usesSparkle(maskBlockComments(rawContent))) return [];
|
|
1476
|
+
return migrationMatcher(
|
|
1477
|
+
TAILWIND_PALETTE_PATTERN,
|
|
1478
|
+
resolveTailwindPaletteUtility,
|
|
1479
|
+
'Tailwind 既定パレットの色'
|
|
1480
|
+
)(rawContent);
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1405
1483
|
const SPACING_UTILITY_PATTERN = buildSpacingUtilityPattern();
|
|
1406
1484
|
|
|
1407
1485
|
/**
|
|
@@ -1505,6 +1583,61 @@ const TOKEN_MIGRATION_GROUPS = [
|
|
|
1505
1583
|
]),
|
|
1506
1584
|
jsdocTargets: [],
|
|
1507
1585
|
},
|
|
1586
|
+
{
|
|
1587
|
+
id: 'tailwind-palette-color',
|
|
1588
|
+
check: {
|
|
1589
|
+
severity: SEVERITY.WARNING,
|
|
1590
|
+
description:
|
|
1591
|
+
'Tailwind 既定パレットの色ユーティリティを使っています(Sparkle のセマンティックトークンに置き換えます)',
|
|
1592
|
+
recommendation:
|
|
1593
|
+
'text-gray-* / bg-slate-* / border-red-* のような Tailwind 既定パレットの色は、用途別セマンティックトークン(bg- → surface / text- → text / border- → border / fill- → object)に置き換えてください。検査対象はソースファイルのみで、.css の @apply と生の hex 値は見ていません。',
|
|
1594
|
+
match: tailwindPaletteMatcher,
|
|
1595
|
+
},
|
|
1596
|
+
featureSection: lines([
|
|
1597
|
+
'### Tailwind 既定パレットの色をそのまま使わない',
|
|
1598
|
+
'',
|
|
1599
|
+
'```tsx',
|
|
1600
|
+
'// ✅ Correct — 用途別セマンティックトークンを使う',
|
|
1601
|
+
'<main className="bg-surface-base-100">',
|
|
1602
|
+
' <h1 className="character-6-bold-pro text-text-negative-enabled">認証エラー</h1>',
|
|
1603
|
+
'</main>',
|
|
1604
|
+
'',
|
|
1605
|
+
'// ❌ Wrong — Tailwind 既定パレットの色を直接指定する',
|
|
1606
|
+
'<main className="bg-gray-50">',
|
|
1607
|
+
' <h1 className="character-6-bold-pro text-red-600">認証エラー</h1>',
|
|
1608
|
+
'</main>',
|
|
1609
|
+
'```',
|
|
1610
|
+
'',
|
|
1611
|
+
'Sparkle のプリミティブは Tailwind の同名変数をそのまま参照しているため',
|
|
1612
|
+
'(`--color-negative-600: var(--color-red-600)`)、`gray` / `red` / `green` / `yellow` / `blue`',
|
|
1613
|
+
'の 5 系統は**置き換えても値が変わらない**。それ以外(`slate` / `zinc` / `emerald` …)は',
|
|
1614
|
+
'色味が変わるので、移行先は候補として提示するだけで自動変換はしない。',
|
|
1615
|
+
'',
|
|
1616
|
+
'| if(状況) | then(移行先) |',
|
|
1617
|
+
'|---|---|',
|
|
1618
|
+
'| 背景に `bg-gray-100` | `bg-surface-base-100`(ページ地の専用トークン) |',
|
|
1619
|
+
'| 文字色に `text-red-600` | `text-text-negative-enabled` |',
|
|
1620
|
+
'| 枠線に `border-gray-200` | `border-border-neutral-*` |',
|
|
1621
|
+
'| アイコン色に `fill-red-600` | `fill-object-negative-enabled` |',
|
|
1622
|
+
'| `bg-blue-600` | ブランド色なら `surface-primary-*`、状態表示なら `surface-info-*`。**Figma を見て決める** |',
|
|
1623
|
+
'| `text-purple-500` など対応する意味が無い色 | 用途から選び直す。装飾用の面なら `bg-surface-accent-1` 〜 `3` |',
|
|
1624
|
+
'',
|
|
1625
|
+
'`surface-base-*` は `0` / `100` / `200` の 3 段しか無い。`bg-gray-50` のように対応する',
|
|
1626
|
+
'段が無いレベルは `surface-neutral-*` 側に案内される。**移行先は check の出力に従うこと**',
|
|
1627
|
+
'(この表は用途の考え方を示すもので、レベルごとの対応はコマンドが出す)。',
|
|
1628
|
+
'',
|
|
1629
|
+
'`text-neutral-*` は Sparkle の旧セマンティック層と同名なので、このルールではなく',
|
|
1630
|
+
'`legacy-color-token` が扱う(同じ箇所を二重に報告しないため)。',
|
|
1631
|
+
'',
|
|
1632
|
+
'このルールは **Sparkle を使っているファイルにだけ**適用される(Sparkle からの import か',
|
|
1633
|
+
'`character-*` の使用がある場合)。素の React コードや、Sparkle と無関係なユーティリティは対象外。',
|
|
1634
|
+
'',
|
|
1635
|
+
'検査対象は `.js` / `.jsx` / `.ts` / `.tsx` のみで、**`.css` の `@apply` は見ていない**',
|
|
1636
|
+
'(`legacy-color-token` は `.css` も見るので、そちらとは対象範囲が違う)。CSS 側に',
|
|
1637
|
+
'Tailwind 既定パレットの色が残っていないかは手で確認すること。',
|
|
1638
|
+
]),
|
|
1639
|
+
jsdocTargets: [],
|
|
1640
|
+
},
|
|
1508
1641
|
{
|
|
1509
1642
|
id: 'legacy-color-var',
|
|
1510
1643
|
check: {
|
|
@@ -1635,6 +1768,7 @@ const BUILTIN_CHECK_ORDER = [
|
|
|
1635
1768
|
// en: This only orders rule *evaluation*. Report ordering is by severity in
|
|
1636
1769
|
// check.js — don't read this list as a display-order guarantee.
|
|
1637
1770
|
'legacy-color-token',
|
|
1771
|
+
'tailwind-palette-color',
|
|
1638
1772
|
'legacy-color-var',
|
|
1639
1773
|
'deprecated-radius-alias',
|
|
1640
1774
|
'use-figma-spacing-scale',
|