Skip to content

Commit

Permalink
Support loading external color sets and templates
Browse files Browse the repository at this point in the history
  • Loading branch information
mjswensen committed Feb 19, 2023
1 parent e4a93ef commit 2475c28
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 3 deletions.
111 changes: 111 additions & 0 deletions cli/src/bin.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import test from 'ava';
import flattenDeep from 'lodash/flattenDeep.js';
import { spawn } from 'node:child_process';
import { rm, stat } from 'node:fs/promises';
import { join } from 'node:path';
import type { BuiltInColorSet, BuiltInTemplate } from './index.js';

const TEST_OUTPUT_DIR = 'bin-test';

test.afterEach.always('clean up test output', async () => {
await rm(TEST_OUTPUT_DIR, { force: true, recursive: true });
});

async function run(
colorSetParams: (BuiltInColorSet | string)[],
templateParams: (BuiltInTemplate | string)[],
): Promise<void> {
return new Promise((resolve, reject) => {
const cp = spawn(
'node',
flattenDeep([
'./dist/bin.js',
colorSetParams.map((param) => ['--color-set', param]),
...templateParams.map((param) => ['--template', param]),
['--output', TEST_OUTPUT_DIR],
]),
);
cp.on('error', reject);
cp.on('exit', (code) => {
if (code === 0) resolve();
else reject();
});
});
}

test.serial('basic CLI', async (t) => {
await t.notThrowsAsync(async () => {
await run(['default'], ['slack']);
await stat(
join(
TEST_OUTPUT_DIR,
'Default',
'Slack sidebar',
'themer-default-dark.txt',
),
);
await stat(join(TEST_OUTPUT_DIR, 'Default', 'README.md'));
});
});

test.serial('multiple color sets', async (t) => {
await t.notThrowsAsync(async () => {
await run(['default', 'green-as-a-whistle'], ['slack']);
await stat(join(TEST_OUTPUT_DIR, 'Default', 'README.md'));
await stat(join(TEST_OUTPUT_DIR, 'Green as a Whistle', 'README.md'));
});
});

test.serial('multiple templates', async (t) => {
await t.notThrowsAsync(async () => {
await run(['default'], ['slack', 'alfred']);
await stat(
join(
TEST_OUTPUT_DIR,
'Default',
'Slack sidebar',
'themer-default-dark.txt',
),
);
await stat(
join(
TEST_OUTPUT_DIR,
'Default',
'Alfred',
'themer-default-dark.alfredappearance',
),
);
});
});

test.serial('load color set from file', async (t) => {
await t.notThrowsAsync(async () => {
await run([join('dist', 'fixture', 'color-set.js')], ['slack']);
await stat(
join(TEST_OUTPUT_DIR, 'Test', 'Slack sidebar', 'themer-test-dark.txt'),
);
});
});

test.serial('load template from file', async (t) => {
await t.notThrowsAsync(async () => {
await run(['default'], [join('dist', 'fixture', 'template.js')]);
await stat(
join(TEST_OUTPUT_DIR, 'Default', 'Test', 'themer-default-dark.txt'),
);
});
});

test.serial.only('load base16 file', async (t) => {
await t.notThrowsAsync(async () => {
await run([join('src', 'fixture', 'base16.yaml')], ['slack']);
await stat(
join(
TEST_OUTPUT_DIR,
'base16',
'Slack sidebar',
'themer-base-16-dark.txt',
),
);
});
});
69 changes: 66 additions & 3 deletions cli/src/bin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
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';
Expand Down Expand Up @@ -56,10 +58,59 @@ function isBuiltInColorSet(value: string): value is BuiltInColorSet {
return allBuiltInColorSetIdentfiers.includes(value as BuiltInColorSet);
}

console.log('resolving color set(s)...');

const resolvedColorSets: (BuiltInColorSet | ColorSet)[] = await Promise.all(
expandedColorSets.map((value: string) => {
expandedColorSets.map(async (value: string) => {
if (isBuiltInColorSet(value)) return value;
throw new Error(`Unable to resolve color set: ${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: ColorSet = {
name: base16.scheme,
variants: isDark ? { dark: variant } : { light: variant },
};
return colors;
} catch (e: any) {
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);
}
}),
);

Expand All @@ -79,7 +130,19 @@ function isBuiltInTemplate(value: string): value is BuiltInTemplate {
const resolvedTemplates: (BuiltInTemplate | Template)[] = await Promise.all(
expandedTemplates.map(async (value) => {
if (isBuiltInTemplate(value)) return value;
throw new Error(`Unable to resolve template: ${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);
}),
);

Expand Down
18 changes: 18 additions & 0 deletions cli/src/fixture/base16.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
scheme: 'base16'
author: 'Themer (https://themer.dev)'
base00: '000000'
base01: 'ffffff'
base02: 'ffffff'
base03: 'ffffff'
base04: 'ffffff'
base05: 'ffffff'
base06: 'ffffff'
base07: 'ffffff'
base08: 'ffffff'
base09: 'ffffff'
base0A: 'ffffff'
base0B: 'ffffff'
base0C: 'ffffff'
base0D: 'ffffff'
base0E: 'ffffff'
base0F: 'ffffff'
21 changes: 21 additions & 0 deletions cli/src/fixture/color-set.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { ColorSet } from '../color-set';

const colors: ColorSet = {
name: 'Test',
variants: {
dark: {
shade0: '#000000',
shade7: '#ffffff',
accent0: '#ffffff',
accent1: '#ffffff',
accent2: '#ffffff',
accent3: '#ffffff',
accent4: '#ffffff',
accent5: '#ffffff',
accent6: '#ffffff',
accent7: '#ffffff',
},
},
};

export default colors;
15 changes: 15 additions & 0 deletions cli/src/fixture/template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { Template } from '../index.js';
import { colorSetToVariants } from '../color-set/index.js';

const template: Template = {
name: 'Test',
render: async function* (colorSet) {
yield* colorSetToVariants(colorSet).map(({ title }) => ({
path: `${title.kebab}.txt`,
content: Buffer.from(title.human, 'utf8'),
}));
},
renderInstructions: (paths) => paths.join('\n'),
};

export default template;

0 comments on commit 2475c28

Please sign in to comment.