Skip to content

Commit

Permalink
feat(imago): add support for custom path part replacements
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Feb 22, 2024
1 parent 60f4081 commit b0419e1
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 9 deletions.
16 changes: 15 additions & 1 deletion packages/imago/src/api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Keys } from "@thi.ng/api";
import type { Fn3, Keys, TypedArray } from "@thi.ng/api";
import type { ILogger } from "@thi.ng/logger";
import type {
AvifOptions,
Expand Down Expand Up @@ -201,6 +201,20 @@ export interface ImgProcOpts {
* Base directory for {@link output} steps
*/
outDir: string;
/**
* An object with custom output path replacements for {@link formatPath}. If
* a given replacement value is a function, it will be called with the
* current {@link ImgProcCtx}, the current {@link OutputSpec} (e.g. to
* obtain configured options) and the already serialized image as buffer.
*
* @remarks
* Replacement IDs in this object will take precedence over built-in
* replacement IDs, e.g. allowing to override `name`, `date` etc.
*/
pathParts: Record<
string,
Fn3<ImgProcCtx, OutputSpec, Buffer | TypedArray, string> | string
>;
}

export interface ImgProcCtx {
Expand Down
19 changes: 14 additions & 5 deletions packages/imago/src/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ import { FMT_HHmmss_ALT, FMT_yyyyMMdd_ALT } from "@thi.ng/date";
import { illegalArgs as unsupported } from "@thi.ng/errors";
import { createHash } from "node:crypto";
import { basename } from "node:path";
import type { ImgProcCtx } from "./api.js";
import type { ImgProcCtx, OutputSpec } from "./api.js";
import { isFunction } from "@thi.ng/checks";

/**
* Expands/replaces all `{xyz}`-templated identifiers in given file path.
*
* @remarks
* The following IDs are supported. Any others will remain as is.
* The following built-in IDs are supported and custom IDs will be looked up via
* the {@link ImgProcOpts.pathParts} options provided to {@link processImage}.
* Any others will remain as is. Custom IDs take precedence over built-in ones.
*
* - date: yyyyMMdd
* - time: HHmmss
Expand All @@ -19,15 +22,21 @@ import type { ImgProcCtx } from "./api.js";
* - h: current height
*
* @param path
* @param buf
* @param ctx
* @param spec
* @param buf
*/
export const formatPath = (
path: string,
buf: Buffer | TypedArray,
ctx: ImgProcCtx
ctx: ImgProcCtx,
spec: OutputSpec,
buf: Buffer | TypedArray
) =>
path.replace(/\{(\w+)\}/g, (match, id) => {
const custom = ctx.opts.pathParts?.[id];
if (custom != null) {
return isFunction(custom) ? custom(ctx, spec, buf) : custom;
}
switch (id) {
case "name": {
!path &&
Expand Down
12 changes: 9 additions & 3 deletions packages/imago/src/proc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export const processImage = async (
ensureSize(meta);
const ctx: ImgProcCtx = {
path: isString(src) ? src : parentCtx?.path,
logger: opts?.logger || LOGGER,
logger: opts.logger || LOGGER,
size: [meta.width!, meta.height!],
channels: meta.channels!,
meta,
Expand Down Expand Up @@ -310,7 +310,10 @@ export const process = defmulti<
const { data, info } = await output
.raw()
.toBuffer({ resolveWithObject: true });
const path = join(outDir, formatPath(opts.path, data, ctx));
const path = join(
outDir,
formatPath(opts.path, ctx, <OutputSpec>spec, data)
);
writeFile(path, data, null, ctx.logger);
if (meta) {
writeJSON(
Expand Down Expand Up @@ -355,7 +358,10 @@ export const process = defmulti<
if (format) output = output.toFormat(<any>format);
const result = await output.toBuffer();
writeFile(
join(outDir, formatPath(opts.path, result, ctx)),
join(
outDir,
formatPath(opts.path, ctx, <OutputSpec>spec, result)
),
result,
null,
ctx.logger
Expand Down

0 comments on commit b0419e1

Please sign in to comment.