UNPKG

themer

Version:

Customizable theme creator for editors, terminals, wallpaper, and more.

123 lines 5.32 kB
#!/usr/bin/env node import Color from 'color'; import { Command } from 'commander'; import flatten from 'lodash/flatten.js'; import { parse } from 'yaml'; import { mkdir, readFile, writeFile } from 'node:fs/promises'; import { dirname, join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import themer, { allBuiltInColorSetIdentifiers, allBuiltInTemplateIdentifiers, } from './index.js'; const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'package.json'); const { version, description } = JSON.parse((await readFile(packageJsonPath)).toString('utf8')); const program = new Command(); program .name('themer') .description(description) .version(version, '-v, --version', 'display the current version') .option('-c, --color-set <built-in color set name or file path...>', 'the color set(s) to render', 'default') .option('-t, --template <built-in template name or file path...>', 'the theme template(s) to render', '*') .option('-s, --size <wallpaper resolution...>', 'resolution to render in pixels, in the format [width]x[height]', '2880x1800') .option('-o, --output <path>', 'the output directory', 'themer-output'); program.parse(); const options = program.opts(); const expandedColorSets = flatten((typeof options['colorSet'] === 'string' ? [options['colorSet']] : options['colorSet']).map((value) => value === '*' ? allBuiltInColorSetIdentifiers : value)); function isBuiltInColorSet(value) { return allBuiltInColorSetIdentifiers.includes(value); } console.log('resolving color set(s)...'); const resolvedColorSets = await Promise.all(expandedColorSets.map(async (value) => { if (isBuiltInColorSet(value)) return value; else { const absolutePath = resolve(value); console.log(`loading color set ${value} (path: ${absolutePath})...`); try { return (await import(absolutePath)).default; } catch { console.log(`color set ${absolutePath} does not appear to be a themer color set JavaScript file...`); } try { const content = await readFile(absolutePath, 'utf8'); const base16 = parse(content); const variant = { shade0: `#${base16.base00}`, shade1: `#${base16.base01}`, shade2: `#${base16.base02}`, shade3: `#${base16.base03}`, shade4: `#${base16.base04}`, shade5: `#${base16.base05}`, shade6: `#${base16.base06}`, shade7: `#${base16.base07}`, accent0: `#${base16.base08}`, accent1: `#${base16.base09}`, accent2: `#${base16.base0A}`, accent3: `#${base16.base0B}`, accent4: `#${base16.base0C}`, accent5: `#${base16.base0D}`, accent6: `#${base16.base0E}`, accent7: `#${base16.base0F}`, }; const isDark = Color(variant.shade0).luminosity() < Color(variant.shade7).luminosity(); const colors = { name: base16.scheme, variants: isDark ? { dark: variant } : { light: variant }, }; return colors; } catch (e) { console.error(e.message); console.log(`color set ${absolutePath} does not appear to be a base16 theme...`); } console.error(`...unable to load color set ${value}`); process.exit(1); } })); const expandedTemplates = flatten((typeof options['template'] === 'string' ? [options['template']] : options['template']).map((value) => value === '*' ? allBuiltInTemplateIdentifiers : value)); function isBuiltInTemplate(value) { return allBuiltInTemplateIdentifiers.includes(value); } const resolvedTemplates = await Promise.all(expandedTemplates.map(async (value) => { if (isBuiltInTemplate(value)) return value; else { const absolutePath = resolve(value); console.log(`loading template ${value} (path: ${absolutePath})...`); try { return (await import(absolutePath)).default; } catch { console.log(`template ${absolutePath} does not appear to be a themer template file...`); } } console.error(`...unable to resolve template: ${value}`); process.exit(1); })); function isTuplePair(arr) { return arr.length === 2; } const resolvedResolutions = (typeof options['size'] === 'string' ? [options['size']] : options['size']).map((opt) => { const dimensions = opt.split('x').map((n) => parseInt(n)); if (isTuplePair(dimensions) && dimensions.every((n) => !isNaN(n))) { const [w, h] = dimensions; return { w, h }; } console.error(`...size option doesn't appear to be a valid WxH resolution specifier: ${opt}`); process.exit(1); }); const renderOptions = { wallpaperSizes: resolvedResolutions, }; for await (const file of themer(resolvedColorSets, resolvedTemplates, renderOptions)) { const path = join(options['output'], file.path); console.log(`writing ${path}...`); await mkdir(dirname(path), { recursive: true }); await writeFile(path, file.content); } console.log('done!'); //# sourceMappingURL=bin.js.map