sparkle-design-cli
Version:
Sparkle Design CSS Generator - デザインシステムCSSを設定ファイルから生成するツール
202 lines (171 loc) • 6.61 kB
JavaScript
/**
* フォント管理機能
* sparkle-design.css からフォントimportを抽出し、globals.css に移動する
*/
import fs from 'fs';
import path from 'path';
import { REGEX, COMMENTS, IMPORTS, MESSAGES } from './constants.js';
/**
* sparkle-design.css からフォントの@import文を抽出する
* @param {string} cssContent CSS内容
* @returns {Array<string>} フォントimport文の配列
*/
export function extractFontImports(cssContent) {
const matches = cssContent.match(REGEX.FONT_IMPORT);
return matches || [];
}
/**
* sparkle-design.css からフォントの@import文を削除する
* @param {string} cssContent CSS内容
* @returns {string} フォントimportを削除したCSS
*/
export function removeFontImportsFromCSS(cssContent) {
return cssContent.replace(REGEX.FONT_IMPORT_WITH_COMMENT, '');
}
/**
* フォントimportブロックを生成する
* @param {Array<string>} fontImports フォントimport文の配列
* @returns {string} フォントimportブロック
*/
function createFontImportBlock(fontImports) {
return [COMMENTS.FONT_IMPORT, ...fontImports, ''].join('\n');
}
/**
* sparkle-design.css importブロックを生成する
* @returns {string} sparkle-design.css importブロック
*/
function createSparkleImportBlock() {
return ['', COMMENTS.SPARKLE_IMPORT, IMPORTS.SPARKLE_DESIGN, ''].join('\n');
}
/**
* globals.css の既存のimportを削除する
* @param {string} globalsContent globals.cssの内容
* @returns {string} 既存importを削除したglobals.css
*/
function removeExistingImports(globalsContent) {
let cleaned = globalsContent;
// 既存のフォントimportを削除
cleaned = cleaned.replace(REGEX.EXISTING_FONT_IMPORT_BLOCK, '');
// 既存のsparkle-design.css importを削除
cleaned = cleaned.replace(REGEX.SPARKLE_IMPORT, '');
return cleaned;
}
/**
* Tailwind import の位置を見つける
* @param {string} globalsContent globals.cssの内容
* @returns {{match: string, index: number, afterIndex: number} | null} Tailwind importの情報
*/
function findTailwindImport(globalsContent) {
const tailwindMatch = globalsContent.match(REGEX.TAILWIND_IMPORT);
if (!tailwindMatch) {
return null;
}
const tailwindIndex = globalsContent.indexOf(tailwindMatch[0]);
const afterTailwindIndex = tailwindIndex + tailwindMatch[0].length;
return {
match: tailwindMatch[0],
index: tailwindIndex,
afterIndex: afterTailwindIndex,
};
}
/**
* globals.css を再構築する
* @param {string} globalsContent 元のglobals.cssの内容
* @param {string} fontImportBlock フォントimportブロック
* @param {string} sparkleImportBlock sparkle-design.css importブロック
* @param {Object} tailwindInfo Tailwind importの情報
* @returns {string} 再構築されたglobals.css
*/
function reconstructGlobalsCss(globalsContent, fontImportBlock, sparkleImportBlock, tailwindInfo) {
const beforeTailwind = globalsContent.substring(0, tailwindInfo.index);
const afterTailwind = globalsContent.substring(tailwindInfo.afterIndex);
// フォントimport + Tailwind + sparkle-design.css + 残りのコンテンツ
return (
fontImportBlock +
beforeTailwind +
tailwindInfo.match +
sparkleImportBlock +
afterTailwind.trimStart()
);
}
/**
* globals.css を構造化して管理する
* - フォントimportを先頭に配置
* - Tailwind importを確保
* - sparkle-design.css importをTailwindの後に配置
* @param {Array<string>} fontImports フォントimport文の配列
* @param {string} globalsPath globals.cssのパス
* @returns {boolean} globals.css の更新に成功した場合は true
*/
export function updateGlobalsWithFonts(fontImports, globalsPath) {
if (fontImports.length === 0) {
return false;
}
try {
// 1. globals.css を読み込む
let globalsContent = fs.readFileSync(globalsPath, 'utf8');
// 2. 既存のimportを削除
globalsContent = removeExistingImports(globalsContent);
// 3. Tailwind import の位置を見つける
const tailwindInfo = findTailwindImport(globalsContent);
if (!tailwindInfo) {
console.warn(MESSAGES.TAILWIND_NOT_FOUND);
return false;
}
// 4. importブロックを生成
const fontImportBlock = createFontImportBlock(fontImports);
const sparkleImportBlock = createSparkleImportBlock();
// 5. globals.css を再構築
const reconstructedContent = reconstructGlobalsCss(
globalsContent,
fontImportBlock,
sparkleImportBlock,
tailwindInfo
);
// 6. 更新したglobals.cssを書き込む
fs.writeFileSync(globalsPath, reconstructedContent, 'utf8');
console.log(MESSAGES.GLOBALS_UPDATED(globalsPath));
return true;
} catch (error) {
console.error(MESSAGES.GLOBALS_UPDATE_FAILED(error.message));
// globals.cssの更新は必須ではないので、エラーでも処理を続行
return false;
}
}
/**
* フォント管理の自動処理を実行する
* sparkle-design.css からフォントimportを抽出し、globals.css に移動する
* @param {string} sparkleDesignPath sparkle-design.cssのパス
*/
export function manageFontImports(sparkleDesignPath) {
try {
// 1. globals.cssのパスを推定(sparkle-design.cssと同じディレクトリ)
const globalsPath = path.join(path.dirname(sparkleDesignPath), 'globals.css');
// 2. globals.cssが存在しない場合はスキップ
if (!fs.existsSync(globalsPath)) {
console.log(MESSAGES.GLOBALS_NOT_FOUND);
return;
}
// 3. sparkle-design.css からフォントimportを抽出
const sparkleContent = fs.readFileSync(sparkleDesignPath, 'utf8');
const fontImports = extractFontImports(sparkleContent);
if (fontImports.length === 0) {
console.log(MESSAGES.NO_FONT_IMPORTS);
return;
}
console.log(MESSAGES.FONT_DETECTED(fontImports.length));
// 4. globals.css にフォントimportを追加
const globalsUpdated = updateGlobalsWithFonts(fontImports, globalsPath);
if (!globalsUpdated) {
console.log(MESSAGES.FONT_REMOVE_SKIPPED);
return;
}
// 5. sparkle-design.css からフォントimportを削除
const cleanedSparkleContent = removeFontImportsFromCSS(sparkleContent);
fs.writeFileSync(sparkleDesignPath, cleanedSparkleContent, 'utf8');
console.log(MESSAGES.FONT_REMOVED);
} catch (error) {
console.error(MESSAGES.FONT_MANAGEMENT_ERROR(error.message));
// フォント管理は必須ではないので、エラーでも処理を続行
}
}