sparkle-design-cli 2.0.7-rc.2 → 2.0.7-rc.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/lib/anti-pattern-rules.js +8 -2
- package/lib/check.js +60 -16
- package/lib/setup.js +1 -1
- package/package.json +1 -1
|
@@ -925,7 +925,7 @@ const ANTI_PATTERN_GROUPS = [
|
|
|
925
925
|
check: {
|
|
926
926
|
description: 'Tailwind デフォルト typography を Sparkle Design コンポーネント内で使わない',
|
|
927
927
|
recommendation:
|
|
928
|
-
'text-sm / text-xs / text-base / font-medium / font-semibold / font-bold は character-* utility
|
|
928
|
+
'text-sm / text-xs / text-base / font-medium / font-semibold / font-bold は character-* utility に置き換えてください。ただし character-* に対応する token が無いサイズ(text-[10px] 等の arbitrary value、あるいは意図的に token 外のサイズを使う場合)は、同一行または直前行に `// sparkle-disable-line tailwind-typography` コメントを付けて例外扱いとして残すこともできます。',
|
|
929
929
|
pattern: /\b(text-(?:xs|sm|base|lg|xl|2xl)|font-(?:medium|semibold|bold|normal|light))\b/g,
|
|
930
930
|
},
|
|
931
931
|
featureSection: lines([
|
|
@@ -937,9 +937,15 @@ const ANTI_PATTERN_GROUPS = [
|
|
|
937
937
|
'',
|
|
938
938
|
'// ❌ Wrong — Tailwind デフォルトの typography を使わない',
|
|
939
939
|
'<span className="text-sm font-medium">テキスト</span>',
|
|
940
|
+
'',
|
|
941
|
+
'// 例外 — character-* に対応するサイズが無い場合は arbitrary value を使うか',
|
|
942
|
+
'// suppress コメントを付けて残す',
|
|
943
|
+
'<span className="text-[10px] text-text-low">12px 未満の極小メタ情報</span>',
|
|
944
|
+
'{/* sparkle-disable-next-line tailwind-typography */}',
|
|
945
|
+
'<span className="text-xs">どうしても text-xs で残したいケース</span>',
|
|
940
946
|
'```',
|
|
941
947
|
'',
|
|
942
|
-
'Sparkle Design コンポーネント内では `character-*-pro` / `character-*-mono` を使用する。Tailwind の `text-
|
|
948
|
+
'Sparkle Design コンポーネント内では `character-*-pro` / `character-*-mono` を使用する。character-1(12px)より小さい指定や、対応 token が無いサイズは Tailwind の arbitrary value (`text-[10px]` 等) で表現するか、`// sparkle-disable-line tailwind-typography` で個別に例外指定する。',
|
|
943
949
|
]),
|
|
944
950
|
jsdocTargets: [],
|
|
945
951
|
},
|
package/lib/check.js
CHANGED
|
@@ -85,8 +85,66 @@ function formatSnippet(text) {
|
|
|
85
85
|
return text.replace(/\s+/g, ' ').trim().slice(0, 120);
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
/**
|
|
89
|
+
* ESLint 風の suppression コメントをサポートする。以下のいずれかが findings
|
|
90
|
+
* と同じ行、または直前行にあれば該当 rule の finding は emit しない:
|
|
91
|
+
*
|
|
92
|
+
* // sparkle-disable-line <rule-id>
|
|
93
|
+
* // sparkle-disable-next-line <rule-id>
|
|
94
|
+
* {/* sparkle-disable-line <rule-id> *\/} (JSX コメント)
|
|
95
|
+
*
|
|
96
|
+
* ユーザーがどうしても character-* に移行できない typography(token に
|
|
97
|
+
* 存在しないサイズなど)や、特定 file だけ例外扱いしたい場合の escape
|
|
98
|
+
* hatch として用意する。ルール ID は複数カンマ区切り可(例:
|
|
99
|
+
* `sparkle-disable-line tailwind-typography, card-padding-override`)。
|
|
100
|
+
*
|
|
101
|
+
* en: ESLint-style suppression comments so specific findings can be opted
|
|
102
|
+
* out when character-* / Sparkle tokens don't map cleanly (e.g. sub-token
|
|
103
|
+
* font sizes). Same-line or previous-line comment is honored.
|
|
104
|
+
*/
|
|
105
|
+
const SUPPRESS_LINE = /(?:\/\/|\/\*|\{\/\*)\s*sparkle-disable-line\s+([A-Za-z0-9,\s_-]+?)\s*(?:\*\/\}?|$)/;
|
|
106
|
+
const SUPPRESS_NEXT_LINE =
|
|
107
|
+
/(?:\/\/|\/\*|\{\/\*)\s*sparkle-disable-next-line\s+([A-Za-z0-9,\s_-]+?)\s*(?:\*\/\}?|$)/;
|
|
108
|
+
|
|
109
|
+
function extractSuppressedRules(source, regex) {
|
|
110
|
+
if (!source) return null;
|
|
111
|
+
const m = source.match(regex);
|
|
112
|
+
if (!m) return null;
|
|
113
|
+
return new Set(
|
|
114
|
+
m[1]
|
|
115
|
+
.split(',')
|
|
116
|
+
.map((id) => id.trim())
|
|
117
|
+
.filter(Boolean)
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function isSuppressed(ruleId, contentLines, lineNumber) {
|
|
122
|
+
// lineNumber は 1-origin
|
|
123
|
+
// en: 1-based line numbers from getLineNumber.
|
|
124
|
+
const current = contentLines[lineNumber - 1] ?? '';
|
|
125
|
+
const previous = contentLines[lineNumber - 2] ?? '';
|
|
126
|
+
const sameLine = extractSuppressedRules(current, SUPPRESS_LINE);
|
|
127
|
+
if (sameLine && sameLine.has(ruleId)) return true;
|
|
128
|
+
const prevLine = extractSuppressedRules(previous, SUPPRESS_NEXT_LINE);
|
|
129
|
+
if (prevLine && prevLine.has(ruleId)) return true;
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
88
133
|
function collectFindings(filePath, content) {
|
|
89
134
|
const findings = [];
|
|
135
|
+
const contentLines = content.split(/\r?\n/);
|
|
136
|
+
const pushFinding = (rule, index, snippet) => {
|
|
137
|
+
const line = getLineNumber(content, index ?? 0);
|
|
138
|
+
if (isSuppressed(rule.id, contentLines, line)) return;
|
|
139
|
+
findings.push({
|
|
140
|
+
filePath,
|
|
141
|
+
id: rule.id,
|
|
142
|
+
description: rule.description,
|
|
143
|
+
recommendation: rule.recommendation,
|
|
144
|
+
line,
|
|
145
|
+
snippet,
|
|
146
|
+
});
|
|
147
|
+
};
|
|
90
148
|
|
|
91
149
|
for (const rule of RULES) {
|
|
92
150
|
if (typeof rule.match === 'function') {
|
|
@@ -94,26 +152,12 @@ function collectFindings(filePath, content) {
|
|
|
94
152
|
// 複雑な照合が必要なルール向けの opt-in API。2-pass 方式などで regex 単体の
|
|
95
153
|
// backtracking リスクを回避したいときに使う。index は content 内の絶対オフセット。
|
|
96
154
|
for (const hit of rule.match(content)) {
|
|
97
|
-
|
|
98
|
-
filePath,
|
|
99
|
-
id: rule.id,
|
|
100
|
-
description: rule.description,
|
|
101
|
-
recommendation: rule.recommendation,
|
|
102
|
-
line: getLineNumber(content, hit.index ?? 0),
|
|
103
|
-
snippet: formatSnippet(hit.text ?? ''),
|
|
104
|
-
});
|
|
155
|
+
pushFinding(rule, hit.index ?? 0, formatSnippet(hit.text ?? ''));
|
|
105
156
|
}
|
|
106
157
|
continue;
|
|
107
158
|
}
|
|
108
159
|
for (const match of content.matchAll(rule.pattern)) {
|
|
109
|
-
|
|
110
|
-
filePath,
|
|
111
|
-
id: rule.id,
|
|
112
|
-
description: rule.description,
|
|
113
|
-
recommendation: rule.recommendation,
|
|
114
|
-
line: getLineNumber(content, match.index ?? 0),
|
|
115
|
-
snippet: formatMatch(match),
|
|
116
|
-
});
|
|
160
|
+
pushFinding(rule, match.index ?? 0, formatMatch(match));
|
|
117
161
|
}
|
|
118
162
|
}
|
|
119
163
|
|
package/lib/setup.js
CHANGED
|
@@ -220,7 +220,7 @@ function buildInstructionBlock(target, assistant) {
|
|
|
220
220
|
' - Sparkle fonts (Google Fonts preconnect + Material Symbols + the configured pro/mono fonts) must be present in the document `<head>`: React layouts via `<SparkleHead />` placed inside `<head>` in the root layout, Vite projects via the managed `<!-- sparkle-design-cli:fonts:start -->` … `end` block in `index.html`.',
|
|
221
221
|
' - Do **not** hand-define `--color-primary-*` or other Sparkle tokens as fallbacks when they look missing. Those come from `sparkle-design.css`; missing values mean the `@import` path is wrong (e.g. `./sparkle-design.css` used when the file lives under `./app/`). Fix the import path, do not duplicate the tokens.',
|
|
222
222
|
' - If you detect any of the above drifted, re-run `npx --yes sparkle-design-cli generate` before hand-editing. The CLI restores the canonical state (correct relative paths, `@source` placement, `index.html` injection).',
|
|
223
|
-
'- **Required**: After creating or modifying any UI component, run `lint:sparkle` before finishing. This catches Sparkle Design anti-patterns.',
|
|
223
|
+
'- **Required**: After creating or modifying any UI component, run `lint:sparkle` before finishing. This catches Sparkle Design anti-patterns. To opt out a specific line from a rule when the Sparkle token does not map cleanly (e.g. sub-12px font sizes for `tailwind-typography`), add `// sparkle-disable-line <rule-id>` on the same line or `// sparkle-disable-next-line <rule-id>` on the line above — but use it sparingly and only when the migration would actually break the design.',
|
|
224
224
|
`- For AI review, prefer \`lint:sparkle:json\` or run \`npx --yes sparkle-design-cli check ${target} --format json\` directly.`,
|
|
225
225
|
'- You must inspect every entry in both `findings` and `manualReviewReminders`. For each entry in `manualReviewReminders`, **echo the reminder ID in your final reply together with a short review note** (e.g. `[badge-tag-semantics] reviewed — Badge is used only for counts, so the usage is fine.`). Silence on a reminder means it was skipped; always state at least a one-line judgment per ID. This is not blocked by the Stop hook (reminders are judgment calls), but reviewers / humans rely on the explicit acknowledgment to trust that each item was actually considered.',
|
|
226
226
|
BLOCK_END,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sparkle-design-cli",
|
|
3
|
-
"version": "2.0.7-rc.
|
|
3
|
+
"version": "2.0.7-rc.3",
|
|
4
4
|
"description": "Sparkle Design CLI — プロジェクトセットアップ、CSS・フォント生成、アンチパターン検査、AI エージェント(Claude Code / Cursor / Codex)向けのガードと hook 設定まで一括で行う sparkle-design 公式 CLI。",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org",
|