@thi.ng/imago 1.3.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2025-07-21T15:28:55Z
3
+ - **Last updated**: 2025-07-26T12:33:06Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -11,6 +11,14 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
11
11
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
12
12
  and/or version bumps of transitive dependencies.
13
13
 
14
+ ## [1.4.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/imago@1.4.0) (2025-07-25)
15
+
16
+ #### 🚀 Features
17
+
18
+ - add support for absolute output paths ([c440e25](https://github.com/thi-ng/umbrella/commit/c440e25))
19
+ - update `formatPath()` to always return abs path
20
+ - simplify `outputProc()` path handling
21
+
14
22
  ## [1.3.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/imago@1.3.0) (2025-07-21)
15
23
 
16
24
  #### 🚀 Features
package/README.md CHANGED
@@ -375,7 +375,7 @@ For Node.js REPL:
375
375
  const imago = await import("@thi.ng/imago");
376
376
  ```
377
377
 
378
- Package sizes (brotli'd, pre-treeshake): ESM: 5.17 KB
378
+ Package sizes (brotli'd, pre-treeshake): ESM: 5.20 KB
379
379
 
380
380
  ## Dependencies
381
381
 
package/ops/output.js CHANGED
@@ -3,18 +3,16 @@ import { isNumber, isPlainObject } from "@thi.ng/checks";
3
3
  import { illegalArgs } from "@thi.ng/errors";
4
4
  import { writeFile, writeJSON } from "@thi.ng/file-io";
5
5
  import { firstNonNullKey } from "@thi.ng/object-utils";
6
- import { join, resolve } from "node:path";
7
6
  import { formatPath } from "../path.js";
8
7
  const outputProc = async (spec, input, ctx) => {
9
8
  const opts = spec;
10
- const outDir = resolve(ctx.opts.outDir || ".");
11
9
  let output = input.clone();
12
10
  if (opts.blurhash) {
13
11
  await __outputBlurHash(opts, output, ctx);
14
12
  return [input, false];
15
13
  }
16
14
  if (opts.raw) {
17
- await __outputRaw(opts, output, ctx, outDir);
15
+ await __outputRaw(opts, output, ctx);
18
16
  return [input, false];
19
17
  }
20
18
  if (ctx.meta.exif && ctx.opts.keepEXIF) {
@@ -73,10 +71,7 @@ const outputProc = async (spec, input, ctx) => {
73
71
  if (format) output = output.toFormat(format);
74
72
  const result = await output.toBuffer();
75
73
  if (opts.path !== void 0) {
76
- const path = join(
77
- outDir,
78
- formatPath(opts.path, ctx, spec, result)
79
- );
74
+ const path = formatPath(opts.path, ctx, spec, result);
80
75
  writeFile(path, result, null, ctx.logger);
81
76
  ctx.outputs[opts.id] = path;
82
77
  } else {
@@ -84,7 +79,7 @@ const outputProc = async (spec, input, ctx) => {
84
79
  }
85
80
  return [input, false];
86
81
  };
87
- const __outputRaw = async (opts, output, ctx, outDir) => {
82
+ const __outputRaw = async (opts, output, ctx) => {
88
83
  const { alpha = false, meta = false } = isPlainObject(opts.raw) ? opts.raw : {};
89
84
  if (alpha) output = output.ensureAlpha();
90
85
  else output = output.removeAlpha();
@@ -93,7 +88,7 @@ const __outputRaw = async (opts, output, ctx, outDir) => {
93
88
  ctx.outputMeta[opts.id] = { ...info, exif: ctx.exif };
94
89
  }
95
90
  if (opts.path !== void 0) {
96
- const path = join(outDir, formatPath(opts.path, ctx, opts, data));
91
+ const path = formatPath(opts.path, ctx, opts, data);
97
92
  writeFile(path, data, null, ctx.logger);
98
93
  ctx.outputs[opts.id] = path;
99
94
  if (meta) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/imago",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
4
4
  "description": "JSON & API-based declarative and extensible image processing trees/pipelines",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -54,7 +54,7 @@
54
54
  "sharp": "^0.34.3"
55
55
  },
56
56
  "devDependencies": {
57
- "@thi.ng/vectors": "^8.4.1",
57
+ "@thi.ng/vectors": "^8.5.1",
58
58
  "@types/node": "^24.0.15",
59
59
  "esbuild": "^0.25.8",
60
60
  "typedoc": "^0.28.7",
@@ -189,5 +189,5 @@
189
189
  "status": "alpha",
190
190
  "year": 2024
191
191
  },
192
- "gitHead": "0c467cd5bdf66531dc159e226d10cb6718426cc1\n"
192
+ "gitHead": "b138ae2fb8567acfe724cc675654878f60d26631\n"
193
193
  }
package/path.d.ts CHANGED
@@ -1,9 +1,13 @@
1
1
  import type { TypedArray } from "@thi.ng/api";
2
2
  import type { ImgProcCtx, OutputSpec } from "./api.js";
3
3
  /**
4
- * Expands/replaces all `{xyz}`-templated identifiers in given file path.
4
+ * Expands/replaces all `{xyz}`-templated identifiers in given file path and
5
+ * makes result an absolute path (if needed).
5
6
  *
6
7
  * @remarks
8
+ * If the input path is not yet absolute, it will be joined with the
9
+ * {@link ImgProcOpts.outDir}.
10
+ *
7
11
  * The following built-in IDs are supported and custom IDs will be looked up via
8
12
  * the {@link ImgProcOpts.pathParts} options provided to {@link processImage}.
9
13
  * Any others will remain as is. Custom IDs take precedence over built-in ones.
package/path.js CHANGED
@@ -12,57 +12,60 @@ import {
12
12
  } from "@thi.ng/date";
13
13
  import { illegalArgs as unsupported } from "@thi.ng/errors";
14
14
  import { createHash } from "node:crypto";
15
- import { basename } from "node:path";
15
+ import { basename, isAbsolute, join, resolve } from "node:path";
16
16
  const _ = void 0;
17
- const formatPath = (path, ctx, spec, buf) => path.replace(/\{(\w+)\}/g, (match, id) => {
18
- const custom = ctx.opts.pathParts?.[id];
19
- if (custom != null) {
20
- return isFunction(custom) ? custom(ctx, spec, buf) : custom;
21
- }
22
- switch (id) {
23
- case "name": {
24
- !path && unsupported(
25
- "cannot format `{name}`, image has no file source"
26
- );
27
- const name = basename(ctx.path);
28
- const idx = name.lastIndexOf(".");
29
- return idx > 0 ? name.substring(0, idx) : name;
17
+ const formatPath = (path, ctx, spec, buf) => {
18
+ path = path.replace(/\{(\w+)\}/g, (match, id) => {
19
+ const custom = ctx.opts.pathParts?.[id];
20
+ if (custom != null) {
21
+ return isFunction(custom) ? custom(ctx, spec, buf) : custom;
30
22
  }
31
- case "sha1":
32
- case "sha224":
33
- case "sha256":
34
- case "sha384":
35
- case "sha512":
36
- return createHash(id).update(buf).digest("hex").substring(0, 8);
37
- case "w":
38
- return String(ctx.size[0]);
39
- case "h":
40
- return String(ctx.size[1]);
41
- case "aspect": {
42
- const [w, h] = ctx.size;
43
- return w > h ? "l" : w < h ? "p" : "sq";
23
+ switch (id) {
24
+ case "name": {
25
+ !path && unsupported(
26
+ "cannot format `{name}`, image has no file source"
27
+ );
28
+ const name = basename(ctx.path);
29
+ const idx = name.lastIndexOf(".");
30
+ return idx > 0 ? name.substring(0, idx) : name;
31
+ }
32
+ case "sha1":
33
+ case "sha224":
34
+ case "sha256":
35
+ case "sha384":
36
+ case "sha512":
37
+ return createHash(id).update(buf).digest("hex").substring(0, 8);
38
+ case "w":
39
+ return String(ctx.size[0]);
40
+ case "h":
41
+ return String(ctx.size[1]);
42
+ case "aspect": {
43
+ const [w, h] = ctx.size;
44
+ return w > h ? "l" : w < h ? "p" : "sq";
45
+ }
46
+ case "date":
47
+ return FMT_yyyyMMdd_ALT(_, true);
48
+ case "time":
49
+ return FMT_HHmmss_ALT(_, true);
50
+ case "year":
51
+ return FMT_yyyy(_, true);
52
+ case "month":
53
+ return FMT_MM(_, true);
54
+ case "week":
55
+ return FMT_ww(_, true);
56
+ case "day":
57
+ return FMT_dd(_, true);
58
+ case "hour":
59
+ return FMT_HH(_, true);
60
+ case "minute":
61
+ return FMT_mm(_, true);
62
+ case "second":
63
+ return FMT_ss(_, true);
44
64
  }
45
- case "date":
46
- return FMT_yyyyMMdd_ALT(_, true);
47
- case "time":
48
- return FMT_HHmmss_ALT(_, true);
49
- case "year":
50
- return FMT_yyyy(_, true);
51
- case "month":
52
- return FMT_MM(_, true);
53
- case "week":
54
- return FMT_ww(_, true);
55
- case "day":
56
- return FMT_dd(_, true);
57
- case "hour":
58
- return FMT_HH(_, true);
59
- case "minute":
60
- return FMT_mm(_, true);
61
- case "second":
62
- return FMT_ss(_, true);
63
- }
64
- return match;
65
- });
65
+ return match;
66
+ });
67
+ return isAbsolute(path) ? path : join(resolve(ctx.opts.outDir || "."), path);
68
+ };
66
69
  export {
67
70
  formatPath
68
71
  };