@terrazzo/cli
Version:
CLI for managing design tokens using the Design Tokens Community Group (DTCG) standard and generating code for any platform via plugins.
93 lines • 4.32 kB
JavaScript
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { build, parse } from '@terrazzo/parser';
import chokidar from 'chokidar';
import pc from 'picocolors';
import yamlToMomoa from 'yaml-to-momoa';
import { DEFAULT_TOKENS_PATH, GREEN_CHECK, cwd, loadTokens, printError, printSuccess, resolveConfig, } from './shared.js';
/** tz build */
export async function buildCmd({ config, configPath, flags, logger }) {
try {
const startTime = performance.now();
if (!Array.isArray(config.plugins) || !config.plugins.length) {
logger.error({
group: 'config',
message: `No plugins defined! Add some in ${configPath || 'terrazzo.config.js'}`,
});
}
// first build
let rawSchemas = await loadTokens(config.tokens, { logger });
if (!rawSchemas) {
logger.error({
group: 'config',
message: `Error loading ${path.relative(fileURLToPath(cwd), fileURLToPath(config.tokens[0] || DEFAULT_TOKENS_PATH))}`,
});
return;
}
let { tokens, sources } = await parse(rawSchemas, { config, logger, yamlToMomoa });
let result = await build(tokens, { sources, config, logger });
writeFiles(result, { config, logger });
// --watch (handle rebuild)
if (flags.watch) {
const dt = new Intl.DateTimeFormat('en-us', {
hour: '2-digit',
minute: '2-digit',
});
async function rebuild({ messageBefore, messageAfter } = {}) {
try {
if (messageBefore) {
logger.info({ group: 'plugin', label: 'watch', message: messageBefore });
}
rawSchemas = await loadTokens(config.tokens, { logger });
if (!rawSchemas) {
throw new Error(`Error loading ${path.relative(fileURLToPath(cwd), fileURLToPath(config.tokens[0] || DEFAULT_TOKENS_PATH))}`);
}
const parseResult = await parse(rawSchemas, { config, logger, yamlToMomoa });
tokens = parseResult.tokens;
sources = parseResult.sources;
result = await build(tokens, { sources, config, logger });
if (messageAfter) {
logger.info({ group: 'plugin', label: 'watch', message: messageAfter });
}
writeFiles(result, { config, logger });
}
catch (err) {
console.error(pc.red(`✗ ${err.message || err}`));
// don’t exit! we’re watching, so continue as long as possible
}
}
const tokenWatcher = chokidar.watch(config.tokens.map((filename) => fileURLToPath(filename)));
tokenWatcher.on('change', async (filename) => {
await rebuild({
messageBefore: `${pc.dim(dt.format(new Date()))} ${pc.green('tz')}} ${pc.yellow(filename)} updated ${GREEN_CHECK}`,
});
});
const configWatcher = chokidar.watch(resolveConfig(configPath));
configWatcher.on('change', async () => {
await rebuild({
messageBefore: `${pc.dim(dt.format(new Date()))} ${pc.green('tz')} ${pc.yellow('Config updated. Reloading…')}`,
});
});
// keep process occupied
await new Promise(() => { });
}
else {
printSuccess(`${Object.keys(tokens).length} token${Object.keys(tokens).length !== 1 ? 's' : ''} built`, startTime);
}
}
catch (err) {
printError(err.message);
process.exit(1);
}
}
/** Write files */
export function writeFiles(result, { config, logger }) {
for (const { filename, contents } of result.outputFiles) {
const output = new URL(filename, config.outDir);
fs.mkdirSync(new URL('.', output), { recursive: true });
fs.writeFileSync(output, contents);
logger.debug({ group: 'parser', label: 'buildEnd', message: `Wrote file ${fileURLToPath(output)}` });
}
}
//# sourceMappingURL=build.js.map