diff --git a/README.md b/README.md index 849c49af..f22b7419 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ npm install themer 1. An array of [`ColorSet` objects](#create-custom-colorsets), or string identifiers of [`themer`'s built-in color sets](#themer-color-sets) 2. An array of [`Template` objects](#create-custom-templates), or string identifiers of [`themer`'s built-in templates](#themer-templates) 3. A `RenderOptions` object used to specify the resolution of the outputted wallpaper images +4. (Optional) an `OutputFileTransform` async generator function that transforms the files generated by the provided templates. This function runs between each template's `render` and `renderInstructions` functions. The objects yielded by the generator are `OutputFile`s. diff --git a/cli/src/index.ts b/cli/src/index.ts index 65c66362..99981b51 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -21,4 +21,5 @@ export { allBuiltInTemplates, type BuiltInTemplate, } from './template/all.js'; +export { type OutputFileTransform } from './transform/index.js'; export { themer as default } from './themer.js'; diff --git a/cli/src/themer.spec.ts b/cli/src/themer.spec.ts new file mode 100644 index 00000000..b13594c1 --- /dev/null +++ b/cli/src/themer.spec.ts @@ -0,0 +1,46 @@ +import test from 'ava'; +import template from './fixture/template.js'; +import { themer } from './themer.js'; +import { OutputFileTransform } from './transform/index.js'; +import { basename } from 'node:path'; + +const backupFile: OutputFileTransform = async function* (file) { + yield file; + yield { + ...file, + path: `${file.path}.bak`, + }; +}; + +test('supports file post-processing', async (t) => { + const files = []; + for await (const file of themer( + ['default'], + [template], + { wallpaperSizes: [] }, + backupFile, + )) { + files.push(file); + } + + t.plan(9); + + const expectedPaths = [ + 'Default/Test/themer-default-dark.txt', + 'Default/Test/themer-default-dark.txt.bak', + 'Default/Test/themer-default-light.txt', + 'Default/Test/themer-default-light.txt.bak', + ]; + + const readme = files.find((file) => file.path.endsWith('README.md')); + t.assert(readme, 'No README file in output'); + + for (const path of expectedPaths) { + t.assert( + files.find((file) => file.path === path), + `Output files must contain ${path}`, + ); + const base = basename(path); + t.assert(readme?.content.includes(base), `README must contain ${base}`); + } +}); diff --git a/cli/src/themer.ts b/cli/src/themer.ts index 78a82eda..665e7582 100644 --- a/cli/src/themer.ts +++ b/cli/src/themer.ts @@ -2,11 +2,13 @@ import { ColorSet, prepareColorSet } from './color-set/index.js'; import { BuiltInColorSet, resolveColorSet } from './color-set/all.js'; import type { Template, OutputFile, RenderOptions } from './template/index.js'; import { BuiltInTemplate, resolveTemplate } from './template/all.js'; +import { OutputFileTransform, noopTransform } from './transform/index.js'; export async function* themer( colorSets: (BuiltInColorSet | ColorSet)[], templates: (BuiltInTemplate | Template)[], options: RenderOptions, + transform: OutputFileTransform = noopTransform, ): AsyncGenerator { for (const colorSet of colorSets) { const resolvedColorSet = resolveColorSet(colorSet); @@ -16,13 +18,15 @@ export async function* themer( const rootDir = fullColorSet.name; for (const template of resolvedTemplates) { const templatePaths: string[] = []; - for await (const file of template.render(fullColorSet, options)) { - const path = `${template.name}/${file.path}`; - yield { - ...file, - path: `${rootDir}/${path}`, - }; - templatePaths.push(path); + for await (const renderedFile of template.render(fullColorSet, options)) { + for await (const file of transform(renderedFile)) { + const path = `${template.name}/${file.path}`; + yield { + ...file, + path: `${rootDir}/${path}`, + }; + templatePaths.push(path); + } } instructions.push(`## ${template.name}`); instructions.push( diff --git a/cli/src/transform/index.ts b/cli/src/transform/index.ts new file mode 100644 index 00000000..210e849c --- /dev/null +++ b/cli/src/transform/index.ts @@ -0,0 +1,9 @@ +import { OutputFile } from '../template/index.js'; + +export type OutputFileTransform = ( + file: OutputFile, +) => AsyncGenerator; + +export const noopTransform: OutputFileTransform = async function* (file) { + yield file; +};