sparkle-design-cli 2.0.7-beta.1 → 2.0.7-beta.2
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/bin/sparkle-design.js +12 -1
- package/lib/constants.js +5 -1
- package/lib/font-manager.js +75 -28
- package/lib/generate-css.js +44 -15
- package/lib/setup.js +26 -4
- package/package.json +1 -1
package/bin/sparkle-design.js
CHANGED
|
@@ -19,6 +19,7 @@ function parseGenerateOptions(args) {
|
|
|
19
19
|
configPath: null,
|
|
20
20
|
outputPath: null,
|
|
21
21
|
globalsPath: null,
|
|
22
|
+
strict: false,
|
|
22
23
|
help: false,
|
|
23
24
|
};
|
|
24
25
|
|
|
@@ -36,6 +37,8 @@ function parseGenerateOptions(args) {
|
|
|
36
37
|
} else if (arg === '--globals-path') {
|
|
37
38
|
options.globalsPath = requireOptionValue(args, i, '--globals-path');
|
|
38
39
|
i += 1;
|
|
40
|
+
} else if (arg === '--strict') {
|
|
41
|
+
options.strict = true;
|
|
39
42
|
} else {
|
|
40
43
|
throw new Error(`Unknown option for generate: ${arg}`);
|
|
41
44
|
}
|
|
@@ -86,6 +89,7 @@ function parseSetupOptions(args) {
|
|
|
86
89
|
skipInstall: false,
|
|
87
90
|
skipScaffold: false,
|
|
88
91
|
skipGenerate: false,
|
|
92
|
+
strict: false,
|
|
89
93
|
help: false,
|
|
90
94
|
};
|
|
91
95
|
|
|
@@ -113,6 +117,8 @@ function parseSetupOptions(args) {
|
|
|
113
117
|
options.skipScaffold = true;
|
|
114
118
|
} else if (arg === '--skip-generate') {
|
|
115
119
|
options.skipGenerate = true;
|
|
120
|
+
} else if (arg === '--strict') {
|
|
121
|
+
options.strict = true;
|
|
116
122
|
} else {
|
|
117
123
|
throw new Error(`Unknown option for setup: ${arg}`);
|
|
118
124
|
}
|
|
@@ -161,6 +167,8 @@ Generate options:
|
|
|
161
167
|
-c, --config <path> 設定ファイルのパス (default: ./sparkle.config.json)
|
|
162
168
|
-o, --output <path> 出力ファイルのパス (default: ./src/app/sparkle-design.css)
|
|
163
169
|
--globals-path <path> Tailwind エントリポイント CSS のパス (default: 自動検出)
|
|
170
|
+
--strict globals.css への @source 注入等が失敗したら exit 1
|
|
171
|
+
(CI 向け。既定は warn + 継続で後方互換を維持)
|
|
164
172
|
|
|
165
173
|
sparkle.config.json の設定フィールド:
|
|
166
174
|
|
|
@@ -204,6 +212,7 @@ Setup options:
|
|
|
204
212
|
--skip-install パッケージインストール(sparkle-design, tailwindcss)をスキップ
|
|
205
213
|
--skip-scaffold 初期ファイル(sparkle.config.json, postcss.config, エントリ CSS)生成をスキップ
|
|
206
214
|
--skip-generate generate 実行をスキップ
|
|
215
|
+
--strict generate の失敗を exit 1 に昇格(CI 向け)
|
|
207
216
|
|
|
208
217
|
Setup の動作:
|
|
209
218
|
1. パッケージマネージャー検出(pnpm / npm / yarn / bun)
|
|
@@ -257,7 +266,9 @@ function main() {
|
|
|
257
266
|
process.exit(0);
|
|
258
267
|
}
|
|
259
268
|
|
|
260
|
-
generateCSS(options.configPath, options.outputPath, options.globalsPath
|
|
269
|
+
generateCSS(options.configPath, options.outputPath, options.globalsPath, {
|
|
270
|
+
strict: options.strict,
|
|
271
|
+
});
|
|
261
272
|
return;
|
|
262
273
|
}
|
|
263
274
|
|
package/lib/constants.js
CHANGED
|
@@ -170,7 +170,11 @@ export const MESSAGES = {
|
|
|
170
170
|
FONT_REMOVE_SKIPPED: 'ℹ️ globals.css の更新に失敗したため、フォントimport削除をスキップします。',
|
|
171
171
|
|
|
172
172
|
// 警告メッセージ
|
|
173
|
-
|
|
173
|
+
// 指定された globals.css に Tailwind import が無いと @source / sparkle-design.css
|
|
174
|
+
// の挿入ができないため、どのファイルに何を書けばよいかを示す actionable なメッセージにする。
|
|
175
|
+
// en: Make the warning actionable — tell the user which file to edit and what to add.
|
|
176
|
+
TAILWIND_NOT_FOUND: (path) =>
|
|
177
|
+
`⚠️ ${path} に Tailwind import が見つかりません。ファイル先頭に \`@import "tailwindcss";\` を追記してください。`,
|
|
174
178
|
GLOBALS_UPDATE_FAILED: (error) => `⚠️ globals.css の更新に失敗しました: ${error}`,
|
|
175
179
|
FONT_MANAGEMENT_ERROR: (error) => `⚠️ フォント管理処理でエラーが発生しました: ${error}`,
|
|
176
180
|
COLOR_CONVERSION_FAILED: (hex) => `⚠️ 色の変換に失敗しました: ${hex}`,
|
package/lib/font-manager.js
CHANGED
|
@@ -190,18 +190,20 @@ function reconstructGlobalsCss(globalsContent, sparkleImportBlock, tailwindInfo)
|
|
|
190
190
|
* - sparkle-design.css importをTailwindの後に配置
|
|
191
191
|
* - 自動検出した sourcePackages から @source ディレクティブを挿入
|
|
192
192
|
*
|
|
193
|
-
* **v2.0.7-beta.
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
* patch されるようにした。
|
|
193
|
+
* **v2.0.7-beta.2**: 戻り値を真偽値から `{ status, reason }` の状態付きに変更。
|
|
194
|
+
* 呼び出し側が「作業不要でスキップ」「失敗したがデフォルトは warn 継続」を
|
|
195
|
+
* 区別できるようにし、`--strict` モードで失敗を exit code に反映できるよう
|
|
196
|
+
* にした(#31)。`skipped` は後方互換のため `false` に、`updated` は `true`
|
|
197
|
+
* に toBoolean で扱える想定。
|
|
199
198
|
*
|
|
200
199
|
* @param {Array<string>} fontImports フォントimport文の配列
|
|
201
200
|
* @param {string} globalsPath globals.cssのパス
|
|
202
201
|
* @param {Array<string>|null} sourcePackages 追加パッケージ名の配列(null の場合は @source を生成しない)
|
|
203
202
|
* @param {string|null} customCssPath custom-css ファイルの相対パス
|
|
204
|
-
* @returns {
|
|
203
|
+
* @returns {{ status: 'skipped' | 'updated' | 'failed', reason?: string }}
|
|
204
|
+
* skipped: 触る理由がない (fonts/sourcePackages/customCss すべて空)
|
|
205
|
+
* updated: globals.css を正常に書き換えた
|
|
206
|
+
* failed: 書き換え対象だったが失敗した (TAILWIND_IMPORT 欠落、write 失敗等)
|
|
205
207
|
*/
|
|
206
208
|
export function updateGlobalsWithFonts(
|
|
207
209
|
fontImports,
|
|
@@ -217,7 +219,7 @@ export function updateGlobalsWithFonts(
|
|
|
217
219
|
// 理由がないので skip。
|
|
218
220
|
// en: Nothing to inject, so leave globals.css alone.
|
|
219
221
|
if (!hasFonts && !hasSourcePackages && !hasCustomCss) {
|
|
220
|
-
return
|
|
222
|
+
return { status: 'skipped', reason: 'no-work' };
|
|
221
223
|
}
|
|
222
224
|
|
|
223
225
|
try {
|
|
@@ -230,8 +232,12 @@ export function updateGlobalsWithFonts(
|
|
|
230
232
|
// 3. Tailwind import の位置を見つける
|
|
231
233
|
const tailwindInfo = findTailwindImport(globalsContent);
|
|
232
234
|
if (!tailwindInfo) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
+
// 表示はプロジェクト相対パスにする。絶対パスだと「どのファイルをいじるのか」
|
|
236
|
+
// が一目で分かりにくく、リポジトリ間で絶対パスが変わるので diff も読みにくい。
|
|
237
|
+
// en: Show the project-relative path so it's obvious which file to edit.
|
|
238
|
+
const displayPath = path.relative(process.cwd(), globalsPath) || globalsPath;
|
|
239
|
+
console.warn(MESSAGES.TAILWIND_NOT_FOUND(displayPath));
|
|
240
|
+
return { status: 'failed', reason: 'tailwind-import-missing' };
|
|
235
241
|
}
|
|
236
242
|
|
|
237
243
|
// 4. importブロックを生成(フォント @import は SparkleHead に移行したため生成しない)
|
|
@@ -247,11 +253,10 @@ export function updateGlobalsWithFonts(
|
|
|
247
253
|
// 6. 更新したglobals.cssを書き込む
|
|
248
254
|
fs.writeFileSync(globalsPath, reconstructedContent, 'utf8');
|
|
249
255
|
console.log(MESSAGES.GLOBALS_UPDATED(globalsPath));
|
|
250
|
-
return
|
|
256
|
+
return { status: 'updated' };
|
|
251
257
|
} catch (error) {
|
|
252
258
|
console.error(MESSAGES.GLOBALS_UPDATE_FAILED(error.message));
|
|
253
|
-
|
|
254
|
-
return false;
|
|
259
|
+
return { status: 'failed', reason: `write-error: ${error.code ?? error.message}` };
|
|
255
260
|
}
|
|
256
261
|
}
|
|
257
262
|
|
|
@@ -355,8 +360,17 @@ function resolveGlobalsPath(sparkleDesignPath, explicitGlobalsPath = null) {
|
|
|
355
360
|
if (fs.existsSync(resolved)) {
|
|
356
361
|
return { path: resolved, source: 'explicit' };
|
|
357
362
|
}
|
|
358
|
-
|
|
359
|
-
|
|
363
|
+
// 明示指定は settings bug / typo なので silent warn ではなく throw に
|
|
364
|
+
// 昇格させる。--strict の有無に関わらず呼び出し元で伝播させたいので、
|
|
365
|
+
// error.code を付けて上流で識別できるようにする。
|
|
366
|
+
// en: An explicit --globals-path value that doesn't exist is almost
|
|
367
|
+
// always a typo. We tag the error so manageFontImports's catch knows
|
|
368
|
+
// to re-throw regardless of strict mode.
|
|
369
|
+
const err = new Error(
|
|
370
|
+
`指定された globals パスが見つかりません: ${explicitGlobalsPath} (cwd 基準で解決: ${resolved})`
|
|
371
|
+
);
|
|
372
|
+
err.code = 'E_EXPLICIT_GLOBALS_PATH_NOT_FOUND';
|
|
373
|
+
throw err;
|
|
360
374
|
}
|
|
361
375
|
|
|
362
376
|
// 1. 自動検出: sparkle-design.css と同じディレクトリで @import "tailwindcss" を含む
|
|
@@ -420,24 +434,54 @@ function resolveGlobalsPath(sparkleDesignPath, explicitGlobalsPath = null) {
|
|
|
420
434
|
/**
|
|
421
435
|
* フォント管理の自動処理を実行する
|
|
422
436
|
* sparkle-design.css からフォントimportを抽出し、Tailwind エントリポイント CSS に @source 等を挿入する
|
|
437
|
+
*
|
|
438
|
+
* **v2.0.7-beta.2**: 戻り値を `{ status, reason? }` に変更し、呼び出し側が
|
|
439
|
+
* 「作業不要のスキップ」「作業すべき状態だが失敗」を区別できるようにした
|
|
440
|
+
* (#31)。`options.strict` が true のとき、`status === 'failed'` になる状態は
|
|
441
|
+
* throw に昇格させて `bin/sparkle-design.js` の outer catch で exit 1 に
|
|
442
|
+
* 繋げる。
|
|
443
|
+
*
|
|
423
444
|
* @param {string} sparkleDesignPath sparkle-design.cssのパス
|
|
424
445
|
* @param {Array<string>|null} sourcePackages 追加パッケージ名の配列(null の場合は @source を生成しない)
|
|
425
446
|
* @param {string|null} customCssPath custom-css ファイルの相対パス
|
|
426
447
|
* @param {string|null} globalsPathOverride 明示的に指定された globals パス
|
|
448
|
+
* @param {{ strict?: boolean }} [options] strict=true のとき失敗を throw する
|
|
449
|
+
* @returns {{ status: 'skipped' | 'updated' | 'failed', reason?: string }}
|
|
427
450
|
*/
|
|
428
451
|
export function manageFontImports(
|
|
429
452
|
sparkleDesignPath,
|
|
430
453
|
sourcePackages = null,
|
|
431
454
|
customCssPath = null,
|
|
432
|
-
globalsPathOverride = null
|
|
455
|
+
globalsPathOverride = null,
|
|
456
|
+
options = {}
|
|
433
457
|
) {
|
|
458
|
+
const strict = Boolean(options.strict);
|
|
459
|
+
const hasWork =
|
|
460
|
+
(sourcePackages !== null && sourcePackages !== undefined) || Boolean(customCssPath);
|
|
461
|
+
|
|
462
|
+
const raiseOrReturn = (result) => {
|
|
463
|
+
if (strict && result.status === 'failed') {
|
|
464
|
+
throw new Error(
|
|
465
|
+
`globals.css の更新に失敗しました (${result.reason ?? 'unknown'})。--strict モードでは exit 1 で終了します。`
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
return result;
|
|
469
|
+
};
|
|
470
|
+
|
|
434
471
|
try {
|
|
435
472
|
// 1. globals パスを解決
|
|
436
473
|
const resolved = resolveGlobalsPath(sparkleDesignPath, globalsPathOverride);
|
|
437
474
|
|
|
438
475
|
if (!resolved) {
|
|
476
|
+
// 作業すべき状態(sourcePackages 等あり)で entry CSS が見つからないのは
|
|
477
|
+
// 事実上の不具合。strict なら throw、非 strict なら従来どおり情報ログ。
|
|
478
|
+
// en: With work queued, missing entry CSS is effectively a misconfiguration.
|
|
479
|
+
if (hasWork) {
|
|
480
|
+
console.warn(MESSAGES.GLOBALS_NOT_FOUND);
|
|
481
|
+
return raiseOrReturn({ status: 'failed', reason: 'entry-css-not-found' });
|
|
482
|
+
}
|
|
439
483
|
console.log(MESSAGES.GLOBALS_NOT_FOUND);
|
|
440
|
-
return;
|
|
484
|
+
return { status: 'skipped', reason: 'entry-css-not-found-no-work' };
|
|
441
485
|
}
|
|
442
486
|
|
|
443
487
|
const globalsPath = resolved.path;
|
|
@@ -460,17 +504,13 @@ export function manageFontImports(
|
|
|
460
504
|
}
|
|
461
505
|
|
|
462
506
|
// 4. globals.css に import / @source を追加
|
|
463
|
-
const
|
|
464
|
-
fontImports,
|
|
465
|
-
globalsPath,
|
|
466
|
-
sourcePackages,
|
|
467
|
-
customCssPath
|
|
468
|
-
);
|
|
507
|
+
const result = updateGlobalsWithFonts(fontImports, globalsPath, sourcePackages, customCssPath);
|
|
469
508
|
|
|
470
|
-
if (
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
509
|
+
if (result.status === 'skipped') {
|
|
510
|
+
return result;
|
|
511
|
+
}
|
|
512
|
+
if (result.status === 'failed') {
|
|
513
|
+
return raiseOrReturn(result);
|
|
474
514
|
}
|
|
475
515
|
|
|
476
516
|
// 5. fonts が sparkle-design.css 側に残っていれば削除(globals 側に移動済みの前提)
|
|
@@ -480,8 +520,15 @@ export function manageFontImports(
|
|
|
480
520
|
fs.writeFileSync(sparkleDesignPath, cleanedSparkleContent, 'utf8');
|
|
481
521
|
console.log(MESSAGES.FONT_REMOVED);
|
|
482
522
|
}
|
|
523
|
+
return result;
|
|
483
524
|
} catch (error) {
|
|
484
525
|
console.error(MESSAGES.FONT_MANAGEMENT_ERROR(error.message));
|
|
485
|
-
//
|
|
526
|
+
// strict モード、または明示指定された globals path の not-found は
|
|
527
|
+
// ユーザーが必ず気付くべきなので非 strict でも再 throw する。
|
|
528
|
+
// en: Always re-throw explicit --globals-path typos; respect strict for the rest.
|
|
529
|
+
if (strict || error.code === 'E_EXPLICIT_GLOBALS_PATH_NOT_FOUND') {
|
|
530
|
+
throw error;
|
|
531
|
+
}
|
|
532
|
+
return { status: 'failed', reason: `manage-error: ${error.code ?? error.message}` };
|
|
486
533
|
}
|
|
487
534
|
}
|
package/lib/generate-css.js
CHANGED
|
@@ -68,7 +68,7 @@ function dedupeFontImports(cssContent) {
|
|
|
68
68
|
|
|
69
69
|
return cssContent
|
|
70
70
|
.split('\n')
|
|
71
|
-
.filter(line => {
|
|
71
|
+
.filter((line) => {
|
|
72
72
|
if (!line.includes('fonts.googleapis.com')) {
|
|
73
73
|
return true;
|
|
74
74
|
}
|
|
@@ -96,7 +96,7 @@ function normalizeFontsEntry(entry) {
|
|
|
96
96
|
return [{ family: entry, weights: FONT_DEFAULTS.WEIGHTS }];
|
|
97
97
|
}
|
|
98
98
|
if (Array.isArray(entry)) {
|
|
99
|
-
return entry.map(item => {
|
|
99
|
+
return entry.map((item) => {
|
|
100
100
|
if (typeof item === 'string') {
|
|
101
101
|
return { family: item, weights: FONT_DEFAULTS.WEIGHTS };
|
|
102
102
|
}
|
|
@@ -132,7 +132,7 @@ function resolveFontConfig(config) {
|
|
|
132
132
|
* @returns {string} CSS font-family 値(例: 'Montserrat', 'Noto Sans JP', sans-serif)
|
|
133
133
|
*/
|
|
134
134
|
function generateFontFamilyValue(fonts, genericFamily) {
|
|
135
|
-
const quoted = fonts.map(f => `'${f.family}'`);
|
|
135
|
+
const quoted = fonts.map((f) => `'${f.family}'`);
|
|
136
136
|
return [...quoted, genericFamily].join(', ');
|
|
137
137
|
}
|
|
138
138
|
|
|
@@ -169,9 +169,10 @@ function generateMergedFontImports(allFonts) {
|
|
|
169
169
|
* @returns {string} フォント import ブロック
|
|
170
170
|
*/
|
|
171
171
|
function generateFontImportsBlock(configOrResolved) {
|
|
172
|
-
const { pro, mono } =
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
const { pro, mono } =
|
|
173
|
+
configOrResolved.pro && configOrResolved.mono
|
|
174
|
+
? configOrResolved
|
|
175
|
+
: resolveFontConfig(configOrResolved);
|
|
175
176
|
|
|
176
177
|
const imports = [
|
|
177
178
|
FONT_DEFAULTS.MATERIAL_SYMBOLS_IMPORT,
|
|
@@ -206,7 +207,7 @@ function generateSparkleHeadContent(resolvedFonts) {
|
|
|
206
207
|
` <link rel="preconnect" href="${FONT_DOMAINS.GOOGLEAPIS}" />`,
|
|
207
208
|
` <link rel="preconnect" href="${FONT_DOMAINS.GSTATIC}" crossOrigin="anonymous" />`,
|
|
208
209
|
` <link rel="stylesheet" href="${materialSymbolsUrl}" />`,
|
|
209
|
-
...fontUrls.map(url => ` <link rel="stylesheet" href="${url}" />`),
|
|
210
|
+
...fontUrls.map((url) => ` <link rel="stylesheet" href="${url}" />`),
|
|
210
211
|
];
|
|
211
212
|
|
|
212
213
|
return `/**
|
|
@@ -289,7 +290,15 @@ function processTemplate(template, config, grayMapping, radiusMapping, colors) {
|
|
|
289
290
|
// 5. 基本的な設定値による置換(オブジェクト・配列・拡張フィールドはスキップ)
|
|
290
291
|
Object.entries(config).forEach(([key, value]) => {
|
|
291
292
|
// 配列・オブジェクト・拡張フィールドはスキップ
|
|
292
|
-
if (
|
|
293
|
+
if (
|
|
294
|
+
Array.isArray(value) ||
|
|
295
|
+
(typeof value === 'object' && value !== null) ||
|
|
296
|
+
key === 'custom-css' ||
|
|
297
|
+
key === 'fonts' ||
|
|
298
|
+
key === 'extend' ||
|
|
299
|
+
key === 'source-packages' ||
|
|
300
|
+
key === 'globals-path'
|
|
301
|
+
) {
|
|
293
302
|
return;
|
|
294
303
|
}
|
|
295
304
|
// 通常のプレースホルダー(CSS用 - スペースはそのまま)
|
|
@@ -336,9 +345,7 @@ function processTemplate(template, config, grayMapping, radiusMapping, colors) {
|
|
|
336
345
|
// `sparkle-design` は CLI 側のデフォルトパッケージなのでリストには加えず「存在判定」にだけ使う。
|
|
337
346
|
// en: Known design-system packages to auto-detect. `sparkle-design` is the CLI's
|
|
338
347
|
// default source package, so it only acts as an "enables @source" signal.
|
|
339
|
-
const KNOWN_DESIGN_SYSTEM_PACKAGES = [
|
|
340
|
-
'@goodpatch/sparkle-design-internal',
|
|
341
|
-
];
|
|
348
|
+
const KNOWN_DESIGN_SYSTEM_PACKAGES = ['@goodpatch/sparkle-design-internal'];
|
|
342
349
|
|
|
343
350
|
/**
|
|
344
351
|
* package.json の dependencies / devDependencies から既知のデザインシステムパッケージを検出する。
|
|
@@ -394,8 +401,17 @@ function writeCSS(cssContent, outputPath = null) {
|
|
|
394
401
|
* メイン処理
|
|
395
402
|
* @param {string|null} configPath カスタム設定ファイルのパス(オプション)
|
|
396
403
|
* @param {string|null} outputPath カスタム出力パス(オプション)
|
|
404
|
+
* @param {string|null} globalsPath 明示指定の globals.css パス(オプション)
|
|
405
|
+
* @param {{ strict?: boolean }} [options] strict=true のとき、
|
|
406
|
+
* globals.css パッチ失敗などを throw に昇格させる(exit 1 に繋げるため)
|
|
407
|
+
* @returns {{ globalsResult: { status: 'skipped'|'updated'|'failed', reason?: string } }}
|
|
397
408
|
*/
|
|
398
|
-
export function generateCSS(
|
|
409
|
+
export function generateCSS(
|
|
410
|
+
configPath = null,
|
|
411
|
+
outputPath = null,
|
|
412
|
+
globalsPath = null,
|
|
413
|
+
options = {}
|
|
414
|
+
) {
|
|
399
415
|
console.log(MESSAGES.START);
|
|
400
416
|
|
|
401
417
|
// 1. 設定ファイルを読み込み
|
|
@@ -413,7 +429,13 @@ export function generateCSS(configPath = null, outputPath = null, globalsPath =
|
|
|
413
429
|
const radiusMapping = loadRadiusMapping();
|
|
414
430
|
|
|
415
431
|
// 5. テンプレートを設定値で処理(resolvedFonts も返す)
|
|
416
|
-
const { css: processedCSS, resolvedFonts } = processTemplate(
|
|
432
|
+
const { css: processedCSS, resolvedFonts } = processTemplate(
|
|
433
|
+
template,
|
|
434
|
+
config,
|
|
435
|
+
grayMapping,
|
|
436
|
+
radiusMapping,
|
|
437
|
+
colors
|
|
438
|
+
);
|
|
417
439
|
|
|
418
440
|
// 6. CSSファイルを書き出し
|
|
419
441
|
const defaultOutputPath = path.resolve(
|
|
@@ -437,16 +459,23 @@ export function generateCSS(configPath = null, outputPath = null, globalsPath =
|
|
|
437
459
|
// with explicit config entries. If neither surfaces anything, @source is skipped.
|
|
438
460
|
console.log(MESSAGES.FONT_MANAGEMENT_START);
|
|
439
461
|
const detectedPackages = detectSourcePackagesFromPackageJson();
|
|
440
|
-
const explicitPackages = 'source-packages' in config ?
|
|
462
|
+
const explicitPackages = 'source-packages' in config ? config['source-packages'] || [] : null;
|
|
441
463
|
const sourcePackages =
|
|
442
464
|
detectedPackages !== null || explicitPackages !== null
|
|
443
465
|
? [...new Set([...(detectedPackages ?? []), ...(explicitPackages ?? [])])]
|
|
444
466
|
: null;
|
|
445
467
|
const customCssPath = config['custom-css'] || null;
|
|
446
468
|
const globalsPathOverride = globalsPath || config['globals-path'] || null;
|
|
447
|
-
|
|
469
|
+
const globalsResult = manageFontImports(
|
|
470
|
+
resolvedOutputPath,
|
|
471
|
+
sourcePackages,
|
|
472
|
+
customCssPath,
|
|
473
|
+
globalsPathOverride,
|
|
474
|
+
{ strict: Boolean(options.strict) }
|
|
475
|
+
);
|
|
448
476
|
|
|
449
477
|
console.log(MESSAGES.SUCCESS);
|
|
478
|
+
return { globalsResult };
|
|
450
479
|
}
|
|
451
480
|
|
|
452
481
|
// スクリプトが直接実行された場合のみメイン処理を実行
|
package/lib/setup.js
CHANGED
|
@@ -456,13 +456,31 @@ function runAssistantGuard(cwd, packageJsonPath, options, assistantConfig) {
|
|
|
456
456
|
};
|
|
457
457
|
}
|
|
458
458
|
|
|
459
|
-
function runGenerate({ skipGenerate, dryRun }) {
|
|
459
|
+
function runGenerate({ skipGenerate, dryRun, strict }) {
|
|
460
|
+
// --skip-generate / --dry-run と --strict が同時指定された場合、strict チェックを
|
|
461
|
+
// 走らせる対象 (generate) そのものがスキップされるため strict は事実上無意味。
|
|
462
|
+
// サイレントに無効化するとユーザーが CI で気付けないので警告を出す。
|
|
463
|
+
// en: --strict has no effect if generate is skipped — warn the user rather
|
|
464
|
+
// than silently no-op, which would mask CI misconfiguration.
|
|
465
|
+
if (strict && (skipGenerate || dryRun)) {
|
|
466
|
+
console.warn(
|
|
467
|
+
'⚠️ --strict は generate の失敗のみ検出します。--skip-generate / --dry-run と併用した場合は strict チェックは走りません。'
|
|
468
|
+
);
|
|
469
|
+
}
|
|
460
470
|
if (skipGenerate || dryRun) return { skipped: true, ran: false };
|
|
461
471
|
try {
|
|
462
472
|
console.log('🎨 sparkle-design.css を生成中...');
|
|
463
|
-
generateCSS();
|
|
464
|
-
return { skipped: false, ran: true };
|
|
473
|
+
const result = generateCSS(null, null, null, { strict: Boolean(strict) });
|
|
474
|
+
return { skipped: false, ran: true, globalsResult: result?.globalsResult };
|
|
465
475
|
} catch (error) {
|
|
476
|
+
// strict モード、または sparkle.config.json の `globals-path` typo などの
|
|
477
|
+
// 明示指定 not-found は、非 strict でもユーザーが必ず気付くべきなので
|
|
478
|
+
// 再 throw する(#33 の挙動を setup 経由でも保つ)。
|
|
479
|
+
// en: Always re-throw explicit --globals-path typos so `setup` surfaces
|
|
480
|
+
// them via exit code, matching the behaviour of `generate` directly.
|
|
481
|
+
if (strict || error.code === 'E_EXPLICIT_GLOBALS_PATH_NOT_FOUND') {
|
|
482
|
+
throw error;
|
|
483
|
+
}
|
|
466
484
|
console.warn(`⚠️ generate 実行をスキップしました: ${error.message}`);
|
|
467
485
|
return { skipped: false, ran: false, error: error.message };
|
|
468
486
|
}
|
|
@@ -493,7 +511,11 @@ export function setupAssistant(options = {}) {
|
|
|
493
511
|
{ ...options, assistant, dryRun },
|
|
494
512
|
assistantConfig
|
|
495
513
|
);
|
|
496
|
-
const generate = runGenerate({
|
|
514
|
+
const generate = runGenerate({
|
|
515
|
+
skipGenerate: Boolean(options.skipGenerate),
|
|
516
|
+
dryRun,
|
|
517
|
+
strict: Boolean(options.strict),
|
|
518
|
+
});
|
|
497
519
|
|
|
498
520
|
const summary = {
|
|
499
521
|
assistant,
|