sparkle-design-cli 1.1.8 → 1.2.0

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.
@@ -1,124 +1,36 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import fs from 'fs';
4
- import path from 'path';
5
- import { fileURLToPath } from 'url';
6
- import { oklch } from 'culori';
7
-
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
-
11
- /**
12
- * sparkle.config.jsonを読み込む
13
- */
14
- function loadConfig(configPath = null) {
15
- // カスタムパスが指定されていない場合は実行場所のsparkle.config.jsonを探す
16
- const defaultConfigPath = path.resolve(process.cwd(), 'sparkle.config.json');
17
- const resolvedConfigPath = configPath ? path.resolve(configPath) : defaultConfigPath;
18
-
19
- try {
20
- const configContent = fs.readFileSync(resolvedConfigPath, 'utf8');
21
- const config = JSON.parse(configContent);
22
- console.log('✅ sparkle.config.json を読み込みました:', resolvedConfigPath);
23
- console.log(' 設定内容:', config);
24
- return config;
25
- } catch (error) {
26
- console.error('❌ sparkle.config.json の読み込みに失敗しました:', error.message);
27
- console.error('設定ファイルパス:', resolvedConfigPath);
28
- console.error('設定ファイルは専用プラグインから生成するか、手動で作成してください');
29
- process.exit(1);
30
- }
31
- }
32
-
33
- /**
34
- * CSSテンプレートを読み込む
35
- */
36
- function loadTemplate() {
37
- const templatePath = path.join(
38
- __dirname,
39
- '..',
40
- 'templates',
41
- 'sparkle-variables',
42
- 'sparkle-design.template.css'
43
- );
44
-
45
- try {
46
- const templateContent = fs.readFileSync(templatePath, 'utf8');
47
- console.log('✅ CSSテンプレートを読み込みました');
48
- return templateContent;
49
- } catch (error) {
50
- console.error('❌ CSSテンプレートの読み込みに失敗しました:', error.message);
51
- console.error('テンプレートファイルが存在することを確認してください:', templatePath);
52
- process.exit(1);
53
- }
54
- }
55
-
56
- /**
57
- * 色定義(colors.json)を読み込む
58
- */
59
- function loadColors() {
60
- const colorsPath = path.join(__dirname, '..', 'templates', 'sparkle-variables', 'colors.json');
61
-
62
- try {
63
- const colorsContent = fs.readFileSync(colorsPath, 'utf8');
64
- const colors = JSON.parse(colorsContent);
65
- console.log('✅ colors.json を読み込みました');
66
- return colors;
67
- } catch (error) {
68
- console.error('❌ colors.json の読み込みに失敗しました:', error.message);
69
- process.exit(1);
70
- }
71
- }
72
-
73
3
  /**
74
- * gray.jsonを読み込む
4
+ * Sparkle Design CSS Generator
5
+ * メインの CSS 生成処理
75
6
  */
76
- function loadGrayMapping() {
77
- const grayJsonPath = path.join(__dirname, '..', 'templates', 'sparkle-variables', 'gray.json');
78
-
79
- try {
80
- const grayContent = fs.readFileSync(grayJsonPath, 'utf8');
81
- const grayMapping = JSON.parse(grayContent);
82
- console.log('✅ gray.json を読み込みました');
83
- return grayMapping;
84
- } catch (error) {
85
- console.error('❌ gray.json の読み込みに失敗しました:', error.message);
86
- process.exit(1);
87
- }
88
- }
89
7
 
90
- /**
91
- * radius.csvを読み込む
92
- */
93
- function loadRadiusMapping() {
94
- const radiusCsvPath = path.join(__dirname, '..', 'templates', 'sparkle-variables', 'radius.csv');
95
-
96
- try {
97
- const csvContent = fs.readFileSync(radiusCsvPath, 'utf8');
98
- const lines = csvContent.trim().split('\n');
99
- const headers = lines[0].split(',');
100
- const radiusMapping = {};
101
-
102
- for (let i = 1; i < lines.length; i++) {
103
- const values = lines[i].split(',');
104
- const name = values[0];
105
- radiusMapping[name] = {};
106
-
107
- for (let j = 1; j < headers.length; j++) {
108
- radiusMapping[name][headers[j]] = values[j];
109
- }
110
- }
111
-
112
- console.log('✅ radius.csv を読み込みました');
113
- return radiusMapping;
114
- } catch (error) {
115
- console.error('❌ radius.csv の読み込みに失敗しました:', error.message);
116
- process.exit(1);
117
- }
118
- }
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import { REGEX, PATHS, MESSAGES } from './constants.js';
11
+ import {
12
+ loadConfig,
13
+ loadTemplate,
14
+ loadColors,
15
+ loadGrayMapping,
16
+ loadRadiusMapping,
17
+ } from './file-loader.js';
18
+ import { generateColorTokens, hexToRgba, hexToOklch } from './color-utils.js';
19
+ import {
20
+ manageFontImports,
21
+ extractFontImports,
22
+ removeFontImportsFromCSS,
23
+ updateGlobalsWithFonts,
24
+ } from './font-manager.js';
119
25
 
120
26
  /**
121
27
  * テンプレート変数を設定値で置換する
28
+ * @param {string} template CSSテンプレート
29
+ * @param {Object} config 設定オブジェクト
30
+ * @param {Object} grayMapping グレーマッピング
31
+ * @param {Object} radiusMapping Radiusマッピング
32
+ * @param {Object} colors 色定義
33
+ * @returns {string} 処理済みのCSS
122
34
  */
123
35
  function processTemplate(template, config, grayMapping, radiusMapping, colors) {
124
36
  let processedCSS = template;
@@ -126,7 +38,7 @@ function processTemplate(template, config, grayMapping, radiusMapping, colors) {
126
38
  // 1. 色のトークンを生成して置換
127
39
  const colorTokens = generateColorTokens(colors, grayMapping, config.primary);
128
40
  // プレースホルダーを色のトークンで置換(改行を含む)
129
- processedCSS = processedCSS.replace(/\s*\/\* \{\{COLOR_TOKENS\}\} \*\/\s*/, `\n${colorTokens}\n`);
41
+ processedCSS = processedCSS.replace(REGEX.COLOR_TOKENS_PLACEHOLDER, `\n${colorTokens}\n`);
130
42
 
131
43
  // 2. 基本的な設定値による置換
132
44
  Object.entries(config).forEach(([key, value]) => {
@@ -149,150 +61,32 @@ function processTemplate(template, config, grayMapping, radiusMapping, colors) {
149
61
  Object.entries(radiusValues).forEach(([semanticName, radiusValue]) => {
150
62
  if (semanticName === 'round') return; // roundは特別扱い
151
63
 
152
- const semanticPattern = new RegExp(
153
- `--radius-${semanticName}:\\s*var\\(--radius-[^)]+\\)`,
154
- 'g'
155
- );
64
+ const semanticPattern = REGEX.RADIUS_SEMANTIC_PATTERN(semanticName);
156
65
  processedCSS = processedCSS.replace(
157
66
  semanticPattern,
158
67
  `--radius-${semanticName}: var(--radius-${radiusValue})`
159
68
  );
160
69
  });
161
70
 
162
- console.log(`✅ ${config.radius}に対応するradius設定を適用しました`);
71
+ console.log(MESSAGES.RADIUS_APPLIED(config.radius));
163
72
  }
164
73
 
165
- console.log('✅ テンプレートを設定値で処理しました');
74
+ console.log(MESSAGES.TEMPLATE_PROCESSED);
166
75
  return processedCSS;
167
76
  }
168
77
 
169
- /**
170
- * 16進数カラーをrgba形式に変換
171
- */
172
- function hexToRgba(hex) {
173
- // #を削除
174
- hex = hex.replace('#', '');
175
-
176
- // 3桁の場合は6桁に拡張
177
- if (hex.length === 3) {
178
- hex = hex
179
- .split('')
180
- .map((char) => char + char)
181
- .join('');
182
- }
183
-
184
- const r = parseInt(hex.substring(0, 2), 16);
185
- const g = parseInt(hex.substring(2, 4), 16);
186
- const b = parseInt(hex.substring(4, 6), 16);
187
-
188
- return `rgba(${r}, ${g}, ${b}, 1)`;
189
- }
190
-
191
- /**
192
- * 16進数カラーをOKLCH形式に変換
193
- * @param {string} hex 16進数のカラーコード(#付きまたは無し)
194
- * @returns {string} OKLCH形式の文字列
195
- */
196
- function hexToOklch(hex) {
197
- // #を削除
198
- const cleanHex = hex.replace('#', '');
199
-
200
- // 3桁の場合は6桁に、4桁の場合は8桁に拡張
201
- let fullHex = cleanHex;
202
- if (cleanHex.length === 3 || cleanHex.length === 4) {
203
- fullHex = cleanHex
204
- .split('')
205
- .map((char) => char + char)
206
- .join('');
207
- }
208
-
209
- // culoriを使用してHEXからOKLCHに変換
210
- const oklchColor = oklch(`#${fullHex}`);
211
-
212
- if (!oklchColor) {
213
- console.warn(`⚠️ 色の変換に失敗しました: ${hex}`);
214
- return `oklch(0 0 0)`;
215
- }
216
-
217
- // 精度を調整して出力
218
- const l = Math.round((oklchColor.l || 0) * 10000) / 10000;
219
- const c = Math.round((oklchColor.c || 0) * 10000) / 10000;
220
- const h = oklchColor.h ? Math.round(oklchColor.h * 10) / 10 : 0;
221
-
222
- // アルファ値がある場合(1未満の場合のみ出力に追加)
223
- if (oklchColor.alpha !== undefined && oklchColor.alpha < 1) {
224
- const a = Math.round(oklchColor.alpha * 10000) / 10000;
225
- return `oklch(${l} ${c} ${h} / ${a})`;
226
- }
227
-
228
- return `oklch(${l} ${c} ${h})`;
229
- }
230
-
231
- /**
232
- * 色のトークンを生成する
233
- * @param {Object} colors colors.jsonから読み込んだ色の定義
234
- * @param {Object} grayMapping gray.jsonから読み込んだグレーの定義
235
- * @param {string} primaryColor プライマリカラーの名前
236
- * @returns {string} 色のトークンのCSS文字列
237
- */
238
- function generateColorTokens(colors, grayMapping, primaryColor) {
239
- const colorTokens = [];
240
-
241
- // 通常の色トークンを生成
242
- Object.entries(colors).forEach(([colorName, colorValues]) => {
243
- if (typeof colorValues === 'object' && colorValues !== null) {
244
- Object.entries(colorValues).forEach(([level, hexValue]) => {
245
- const oklchValue = hexToOklch(hexValue);
246
- colorTokens.push(` --color-${colorName}-${level}: ${oklchValue};`);
247
- });
248
- } else if (typeof colorValues === 'string') {
249
- // black, white, web-focusなどの単色
250
- const oklchValue = hexToOklch(colorValues);
251
- colorTokens.push(` --color-${colorName}: ${oklchValue};`);
252
- }
253
- });
254
-
255
- // グレーの色トークンを生成(プライマリカラーに基づく)
256
- if (primaryColor && grayMapping[primaryColor]) {
257
- const grayColors = grayMapping[primaryColor];
258
- Object.entries(grayColors).forEach(([key, hexValue]) => {
259
- const grayLevel =
260
- key === '0'
261
- ? '50'
262
- : key === '1'
263
- ? '100'
264
- : key === '2'
265
- ? '200'
266
- : key === '3'
267
- ? '300'
268
- : key === '4'
269
- ? '400'
270
- : key === '5'
271
- ? '500'
272
- : key === '6'
273
- ? '600'
274
- : key === '7'
275
- ? '700'
276
- : key === '8'
277
- ? '800'
278
- : key === '9'
279
- ? '900'
280
- : key;
281
-
282
- const oklchValue = hexToOklch(hexValue);
283
- colorTokens.push(` --color-gray-${grayLevel}: ${oklchValue};`);
284
- });
285
- }
286
-
287
- return colorTokens.join('\n');
288
- }
289
-
290
78
  /**
291
79
  * 生成されたCSSをファイルに書き出す
80
+ * @param {string} cssContent CSS内容
81
+ * @param {string|null} outputPath カスタム出力パス(オプション)
292
82
  */
293
83
  function writeCSS(cssContent, outputPath = null) {
294
84
  // カスタムパスが指定されていない場合は実行場所からsrc/appディレクトリに出力
295
- const defaultOutputPath = path.resolve(process.cwd(), 'src', 'app', 'sparkle-design.css');
85
+ const defaultOutputPath = path.resolve(
86
+ process.cwd(),
87
+ ...PATHS.DEFAULT_OUTPUT_DIR,
88
+ 'sparkle-design.css'
89
+ );
296
90
  const resolvedOutputPath = outputPath ? path.resolve(outputPath) : defaultOutputPath;
297
91
 
298
92
  try {
@@ -303,18 +97,20 @@ function writeCSS(cssContent, outputPath = null) {
303
97
  }
304
98
 
305
99
  fs.writeFileSync(resolvedOutputPath, cssContent, 'utf8');
306
- console.log('✅ sparkle-design.css を生成しました:', resolvedOutputPath);
100
+ console.log(MESSAGES.CSS_GENERATED(resolvedOutputPath));
307
101
  } catch (error) {
308
- console.error('❌ CSSファイルの書き出しに失敗しました:', error.message);
102
+ console.error(MESSAGES.CSS_WRITE_FAILED(error.message));
309
103
  process.exit(1);
310
104
  }
311
105
  }
312
106
 
313
107
  /**
314
108
  * メイン処理
109
+ * @param {string|null} configPath カスタム設定ファイルのパス(オプション)
110
+ * @param {string|null} outputPath カスタム出力パス(オプション)
315
111
  */
316
112
  export function generateCSS(configPath = null, outputPath = null) {
317
- console.log('🚀 Sparkle Design CSS Generator を開始します...\n');
113
+ console.log(MESSAGES.START);
318
114
 
319
115
  // 1. 設定ファイルを読み込み
320
116
  const config = loadConfig(configPath);
@@ -331,9 +127,19 @@ export function generateCSS(configPath = null, outputPath = null) {
331
127
  const processedCSS = processTemplate(template, config, grayMapping, radiusMapping, colors);
332
128
 
333
129
  // 5. CSSファイルを書き出し
130
+ const defaultOutputPath = path.resolve(
131
+ process.cwd(),
132
+ ...PATHS.DEFAULT_OUTPUT_DIR,
133
+ 'sparkle-design.css'
134
+ );
135
+ const resolvedOutputPath = outputPath ? path.resolve(outputPath) : defaultOutputPath;
334
136
  writeCSS(processedCSS, outputPath);
335
137
 
336
- console.log('\n🎉 CSS生成が完了しました!');
138
+ // 6. フォント管理の自動処理を実行
139
+ console.log(MESSAGES.FONT_MANAGEMENT_START);
140
+ manageFontImports(resolvedOutputPath);
141
+
142
+ console.log(MESSAGES.SUCCESS);
337
143
  }
338
144
 
339
145
  // スクリプトが直接実行された場合のみメイン処理を実行
@@ -341,15 +147,24 @@ if (import.meta.url === `file://${process.argv[1]}`) {
341
147
  generateCSS();
342
148
  }
343
149
 
150
+ // テスト用エクスポート
344
151
  export {
152
+ // メイン関数
153
+ processTemplate,
154
+ writeCSS,
155
+ // ファイル読み込み
345
156
  loadConfig,
346
157
  loadTemplate,
347
158
  loadColors,
348
159
  loadGrayMapping,
349
160
  loadRadiusMapping,
350
- processTemplate,
351
- writeCSS,
161
+ // カラー変換
352
162
  hexToRgba,
353
163
  hexToOklch,
354
164
  generateColorTokens,
165
+ // フォント管理
166
+ extractFontImports,
167
+ removeFontImportsFromCSS,
168
+ updateGlobalsWithFonts,
169
+ manageFontImports,
355
170
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sparkle-design-cli",
3
- "version": "1.1.8",
3
+ "version": "1.2.0",
4
4
  "description": "Sparkle Design CSS Generator - デザインシステムCSSを設定ファイルから生成するツール",
5
5
  "main": "lib/generate-css.js",
6
6
  "type": "module",