/** * DSS Extract Command * * Extract tokens or components from Figma. */ import chalk from 'chalk'; import ora from 'ora'; import { writeFileSync, existsSync, mkdirSync } from 'fs'; import { join } from 'path'; import { getConfig, getProjectRoot } from '../lib/config.js'; import { getApiClient } from '../lib/api.js'; import { isServerRunning } from '../lib/server.js'; interface ExtractOptions { format: string; output?: string; fileKey?: string; } export async function extractCommand( type: string, options: ExtractOptions ): Promise { const validTypes = ['tokens', 'components', 'styles', 'all']; if (!validTypes.includes(type)) { console.log(chalk.red(` Invalid type: ${type}`)); console.log(chalk.dim(` Valid types: ${validTypes.join(', ')}`)); process.exit(1); } const config = getConfig(); const cwd = getProjectRoot(); // Check if server is running if (!isServerRunning(cwd)) { console.log(chalk.yellow(' DSS server is not running')); console.log(chalk.dim(' Start it with: dss start')); process.exit(1); } const fileKey = options.fileKey || config.figmaFileKey; if (!fileKey) { console.log(chalk.red(' No Figma file key configured')); console.log(chalk.dim(' Set it with: dss config --set figmaFileKey=YOUR_KEY')); process.exit(1); } const outputDir = options.output || join(cwd, '.dss', 'output'); if (!existsSync(outputDir)) { mkdirSync(outputDir, { recursive: true }); } const api = getApiClient({ port: config.port }); if (type === 'tokens' || type === 'all') { await extractTokens(api, fileKey, options.format, outputDir); } if (type === 'components' || type === 'all') { await extractComponents(api, fileKey, outputDir); } if (type === 'styles' || type === 'all') { await extractStyles(api, fileKey, outputDir); } } async function extractTokens( api: ReturnType, fileKey: string, format: string, outputDir: string ): Promise { const spinner = ora('Extracting tokens...').start(); try { const result = await api.extractTokens(fileKey, format || 'json'); const filename = format === 'css' ? 'tokens.css' : format === 'scss' ? '_tokens.scss' : format === 'ts' ? 'tokens.ts' : 'tokens.json'; const outputPath = join(outputDir, filename); writeFileSync(outputPath, result.formatted_output); spinner.succeed(`Extracted ${result.tokens_count} tokens`); console.log(chalk.dim(` Output: ${outputPath}`)); } catch (error) { spinner.fail('Failed to extract tokens'); console.error(chalk.red(` ${(error as Error).message}`)); } } async function extractComponents( api: ReturnType, fileKey: string, outputDir: string ): Promise { const spinner = ora('Extracting components...').start(); try { const result = await api.extractComponents(fileKey); const outputPath = join(outputDir, 'components.json'); writeFileSync(outputPath, JSON.stringify(result.components, null, 2)); spinner.succeed(`Extracted ${result.components_count} components`); console.log(chalk.dim(` Output: ${outputPath}`)); // Show component summary console.log(''); result.components.forEach(comp => { console.log(chalk.dim(` - ${comp.name}`)); if (comp.variants?.length) { console.log(chalk.dim(` Variants: ${comp.variants.join(', ')}`)); } }); } catch (error) { spinner.fail('Failed to extract components'); console.error(chalk.red(` ${(error as Error).message}`)); } } async function extractStyles( api: ReturnType, fileKey: string, outputDir: string ): Promise { const spinner = ora('Extracting styles...').start(); try { // Note: This would need a corresponding API endpoint // For now, we'll extract tokens which include style information const result = await api.extractTokens(fileKey, 'json'); const outputPath = join(outputDir, 'styles.json'); writeFileSync(outputPath, JSON.stringify(result.tokens, null, 2)); spinner.succeed(`Extracted styles`); console.log(chalk.dim(` Output: ${outputPath}`)); } catch (error) { spinner.fail('Failed to extract styles'); console.error(chalk.red(` ${(error as Error).message}`)); } }