sparkle-design-cli 2.3.0 → 2.3.1

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.
Files changed (2) hide show
  1. package/lib/load-plugins.js +42 -15
  2. package/package.json +1 -1
@@ -61,7 +61,12 @@ function extractPluginEntry(pkg) {
61
61
  }
62
62
 
63
63
  /**
64
- * Discover and load anti-pattern plugins from the consumer's package.json deps.
64
+ * Discover and load anti-pattern plugins from the consumer's package.json deps, plus
65
+ * a self-reference path: if the consumer's own package.json declares
66
+ * `sparkleCli.antiPatterns`, that entry is loaded too (packageName is recorded as the
67
+ * consumer's own `name`, or `"(self)"` if unnamed). This lets a library check its own
68
+ * source against the anti-patterns it defines for its consumers, without needing to
69
+ * list itself in its own dependencies.
65
70
  *
66
71
  * Returns an object of the shape:
67
72
  * {
@@ -92,18 +97,8 @@ export async function loadAntiPatternPlugins({ cwd = process.cwd() } = {}) {
92
97
  const groups = [];
93
98
  const reminders = [];
94
99
 
95
- for (const depName of depNames) {
96
- const depPkgPath = resolvePluginPackageJson(depName, cwd);
97
- if (!depPkgPath) continue;
98
-
99
- const depPkg = readJsonSafe(depPkgPath);
100
- if (!depPkg) continue;
101
-
102
- const entry = extractPluginEntry(depPkg);
103
- if (!entry) continue;
104
-
105
- const resolvedFile = path.resolve(path.dirname(depPkgPath), entry);
106
- const record = { packageName: depName, entry, resolvedFile, status: 'loaded' };
100
+ const loadEntry = async (packageName, entry, resolvedFile) => {
101
+ const record = { packageName, entry, resolvedFile, status: 'loaded' };
107
102
 
108
103
  try {
109
104
  if (!fs.existsSync(resolvedFile)) {
@@ -115,7 +110,7 @@ export async function loadAntiPatternPlugins({ cwd = process.cwd() } = {}) {
115
110
  // plain object を export する plugin にも同じ厳しさを適用したい。
116
111
  // en: Share shape validation with `defineAntiPatternPlugin` so plugins that skip
117
112
  // the helper are still rejected at load time.
118
- validatePluginShape(candidate, `${depName} (${entry})`);
113
+ validatePluginShape(candidate, `${packageName} (${entry})`);
119
114
  groups.push(...candidate.groups);
120
115
  record.groupIds = candidate.groups.map((group) => group.id);
121
116
  if (Array.isArray(candidate.manualReviewReminders)) {
@@ -125,11 +120,43 @@ export async function loadAntiPatternPlugins({ cwd = process.cwd() } = {}) {
125
120
  record.status = 'error';
126
121
  record.error = error?.message ?? String(error);
127
122
  console.warn(
128
- `⚠️ sparkle-design-cli: failed to load anti-pattern plugin from ${depName} (entry: ${entry}, error: ${record.error})`
123
+ `⚠️ sparkle-design-cli: failed to load anti-pattern plugin from ${packageName} (entry: ${entry}, error: ${record.error})`
129
124
  );
130
125
  }
131
126
 
132
127
  discovered.push(record);
128
+ };
129
+
130
+ // 自己参照パス: consumer 自身が sparkleCli.antiPatterns を宣言しているケース
131
+ // (自分自身のソースに対して check を実行する場合、自分自身は自分の dependencies には
132
+ // 現れないため、依存パッケージ経由の discovery だけでは見つからない)。
133
+ // en: Self-reference path — a package checking its own source won't list itself in
134
+ // its own dependencies, so dependency-based discovery alone would miss it.
135
+ const selfEntry = extractPluginEntry(consumerPkg);
136
+ if (selfEntry) {
137
+ const resolvedFile = path.resolve(cwd, selfEntry);
138
+ await loadEntry(consumerPkg.name || '(self)', selfEntry, resolvedFile);
139
+ }
140
+
141
+ for (const depName of depNames) {
142
+ // 自分自身の名前を自分の dependencies に含むケース(workspace の self-link 等)では、
143
+ // 上の自己参照パスと重複してロードされてしまうためスキップする。
144
+ // en: Skip the consumer's own name if it also appears in its own dependencies (e.g. a
145
+ // workspace self-link) — otherwise the self-reference path above and this loop would
146
+ // load the same plugin entry twice.
147
+ if (depName === consumerPkg.name) continue;
148
+
149
+ const depPkgPath = resolvePluginPackageJson(depName, cwd);
150
+ if (!depPkgPath) continue;
151
+
152
+ const depPkg = readJsonSafe(depPkgPath);
153
+ if (!depPkg) continue;
154
+
155
+ const entry = extractPluginEntry(depPkg);
156
+ if (!entry) continue;
157
+
158
+ const resolvedFile = path.resolve(path.dirname(depPkgPath), entry);
159
+ await loadEntry(depName, entry, resolvedFile);
133
160
  }
134
161
 
135
162
  return { groups, reminders, discovered };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sparkle-design-cli",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
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",