@sinchsmb/mktheme
Version:
Util that allow to make frontend theme from Figma theme export file
149 lines (123 loc) • 5.2 kB
JavaScript
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);