UNPKG

@sinchsmb/mktheme

Version:

Util that allow to make frontend theme from Figma theme export file

149 lines (123 loc) 5.2 kB
#!/usr/bin/env node const fs = require('fs'); const path = require('path'); const { hideBin } = require('yargs/helpers'); const yargs = require('yargs/yargs'); const { resolveLinks, mergeThemes, toHiveTheme, normalizeValues } = require('./utils'); const colorBlue = '\x1b[34m'; const colorBlueEnd = '\x1b[89m\x1b[0m'; const colorGreen = '\x1b[32m'; const colorGreenEnd = '\x1b[89m\x1b[0m'; const colorYellow = '\x1b[33m'; const colorYellowEnd = '\x1b[89m\x1b[0m'; const colorRed = '\x1b[31m'; const colorRedEnd = '\x1b[89m\x1b[0m'; const colorWhite = '\x1b[37m'; const colorWhiteEnd = '\x1b[89m\x1b[0m'; const bold = '\x1b[1m'; const boldEnd = '\x1b[22m\x1b[0m'; const argv = yargs(hideBin(process.argv)) .command('$0 <output_file>') .usage(`USAGE: ${colorWhite}$0 -f figma_theme_file.json -t theme_name output_file.json${colorWhiteEnd}`) .example( '$0 -f figma.json -t SinchTheme sinch.json', 'Extract Sinch theme from figma.json file to sinch.json file', ) .option('base-theme', { alias: 'b', type: 'string', description: 'Name of theme that should be used as base', default: 'BaseTheme', }) .option('figma', { alias: 'f', type: 'string', description: 'JSON file exported from Figma that contains Figma tokens', demandOption: true, }) .option('theme', { alias: 't', type: 'string', description: 'Name of theme that should be extracted', demandOption: true, }) .option('silent', { alias: 's', type: 'boolean', description: "Don't print any message in console", }) .positional('output_file.json', { type: 'string', description: 'The result JSON file', }) .help('h') .alias('h', 'help') .epilog('Hive UI-Kit 2022').argv; const { figma: figmaThemeFile, theme, 'base-theme': baseTheme, output_file: outputFile, silent } = argv; function writeToConsole(messagePrefix, message) { if (silent) { return; } process.stdout.write(`${messagePrefix}${message}\n`); } const printToConsole = { info: (message) => writeToConsole(`${bold}${colorBlue}INFO${colorBlueEnd}${boldEnd} `, message), success: (message) => writeToConsole(`${bold}${colorGreen}SUCCESS${colorGreenEnd}${boldEnd} `, message), warning: (message) => writeToConsole(`${bold}${colorYellow}WARNING${colorYellowEnd}${boldEnd} `, message), error: (message) => writeToConsole(`${bold}${colorRed}ERROR${colorRedEnd}${boldEnd} `, message), debug: (message) => writeToConsole('', message), }; const tokensFilePath = path.isAbsolute(figmaThemeFile) ? figmaThemeFile : path.join(process.cwd(), figmaThemeFile); printToConsole.info(`Loading Figma Tokens JSON from ${colorWhite}${tokensFilePath}${colorWhiteEnd} ...`); let figmaJsonData = fs.readFileSync(tokensFilePath, 'utf-8'); printToConsole.success(`File with ${figmaJsonData.length} symbols has been loaded`); printToConsole.info(`Parsing Figma Tokens JSON file ...`); const figmaJson = JSON.parse(figmaJsonData); printToConsole.info(`Resolving links ...`); figmaJsonData = resolveLinks(figmaJson); printToConsole.success(`Figma Tokens JSON parsing has been finished`); printToConsole.info(`Figma Tokens JSON contains the following themes:`); Object.keys(figmaJson).forEach((name) => { const isBase = name === baseTheme ? ' (base)' : ''; const isTarget = name === theme ? ' (target)' : ''; printToConsole.debug(` - ${name}${isBase}${isTarget}`); }); printToConsole.info(`Reading base theme ${colorWhite}${baseTheme}${colorWhiteEnd} ...`); if (!figmaJson[baseTheme]) { printToConsole.error(''); throw new Error( `Base theme ${colorWhite}${baseTheme}${colorWhiteEnd} is not found in ${colorWhite}${figmaThemeFile}${colorWhiteEnd}\nAvailable themes:\n - ${Object.keys( figmaJson, ).join('\n - ')}.`, ); } const baseThemeJson = figmaJson[baseTheme]; printToConsole.info(`Reading target theme ${colorWhite}${theme}${colorWhiteEnd} ...`); if (!figmaJson[theme]) { printToConsole.error(''); throw new Error( `Theme ${colorWhite}${theme}${colorWhiteEnd} is not found in ${colorWhite}${figmaThemeFile}${colorWhiteEnd}\nAvailable themes:\n - ${Object.keys( figmaJson, ).join('\n - ')}`, ); } const themeJson = figmaJson[theme]; printToConsole.info( `Mering the base theme ${colorWhite}${baseTheme}${colorWhiteEnd} with the target theme ${colorWhite}${theme}${colorWhiteEnd} ...`, ); let themeTokens = mergeThemes(baseThemeJson, themeJson); printToConsole.info(`Resolving links ...`); themeTokens = resolveLinks(themeTokens); printToConsole.info(`Normalizing values ...`); themeTokens = normalizeValues(themeTokens); printToConsole.info(`Generating result theme JSON ...`); const resultTheme = toHiveTheme(themeTokens); const resultThemeJsonString = JSON.stringify(resultTheme, ' ', 2); const resultFilePath = path.isAbsolute(outputFile) ? outputFile : path.join(process.cwd(), outputFile); fs.writeFileSync(resultFilePath, resultThemeJsonString + '\n', 'utf-8'); printToConsole.success( `The theme file for ${colorWhite}${theme}${colorWhiteEnd} based on ${colorWhite}${baseTheme}${colorWhiteEnd} has been generated and saved at ${colorWhite}${resultFilePath}${colorWhiteEnd}`, ); process.exit(0);