@bgord/bun 0.22.0 → 0.22.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.
Files changed (38) hide show
  1. package/dist/image-alpha-noop.adapter.d.ts +5 -0
  2. package/dist/image-alpha-noop.adapter.d.ts.map +1 -0
  3. package/dist/image-alpha-noop.adapter.js +6 -0
  4. package/dist/image-alpha-noop.adapter.js.map +1 -0
  5. package/dist/image-alpha-sharp.adapter.d.ts +5 -0
  6. package/dist/image-alpha-sharp.adapter.d.ts.map +1 -0
  7. package/dist/image-alpha-sharp.adapter.js +83 -0
  8. package/dist/image-alpha-sharp.adapter.js.map +1 -0
  9. package/dist/image-alpha.port.d.ts +24 -0
  10. package/dist/image-alpha.port.d.ts.map +1 -0
  11. package/dist/image-alpha.port.js +2 -0
  12. package/dist/image-alpha.port.js.map +1 -0
  13. package/dist/image-processor-noop.adapter.d.ts +6 -0
  14. package/dist/image-processor-noop.adapter.d.ts.map +1 -0
  15. package/dist/image-processor-noop.adapter.js +8 -0
  16. package/dist/image-processor-noop.adapter.js.map +1 -0
  17. package/dist/image-processor-sharp.adapter.d.ts +7 -0
  18. package/dist/image-processor-sharp.adapter.d.ts.map +1 -0
  19. package/dist/image-processor-sharp.adapter.js +96 -0
  20. package/dist/image-processor-sharp.adapter.js.map +1 -0
  21. package/dist/image-processor.port.d.ts +30 -0
  22. package/dist/image-processor.port.d.ts.map +1 -0
  23. package/dist/image-processor.port.js +2 -0
  24. package/dist/image-processor.port.js.map +1 -0
  25. package/dist/index.d.ts +6 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +6 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/tsconfig.tsbuildinfo +1 -1
  30. package/package.json +1 -1
  31. package/readme.md +6 -0
  32. package/src/image-alpha-noop.adapter.ts +7 -0
  33. package/src/image-alpha-sharp.adapter.ts +28 -0
  34. package/src/image-alpha.port.ts +22 -0
  35. package/src/image-processor-noop.adapter.ts +10 -0
  36. package/src/image-processor-sharp.adapter.ts +49 -0
  37. package/src/image-processor.port.ts +28 -0
  38. package/src/index.ts +6 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bgord/bun",
3
- "version": "0.22.0",
3
+ "version": "0.22.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "author": "Bartosz Gordon",
package/readme.md CHANGED
@@ -62,6 +62,9 @@ src/
62
62
  ├── healthcheck.service.ts
63
63
  ├── http-logger.middleware.ts
64
64
  ├── i18n.service.ts
65
+ ├── image-alpha-noop.adapter.ts
66
+ ├── image-alpha-sharp.adapter.ts
67
+ ├── image-alpha.port.ts
65
68
  ├── image-blur-noop.adapter.ts
66
69
  ├── image-blur-sharp.adapter.ts
67
70
  ├── image-blur.port.ts
@@ -77,6 +80,9 @@ src/
77
80
  ├── image-info-noop.adapter.ts
78
81
  ├── image-info-sharp.adapter.ts
79
82
  ├── image-info.port.ts
83
+ ├── image-processor-noop.adapter.ts
84
+ ├── image-processor-sharp.adapter.ts
85
+ ├── image-processor.port.ts
80
86
  ├── image-resizer-noop.adapter.ts
81
87
  ├── image-resizer-sharp.adapter.ts
82
88
  ├── image-resizer.port.ts
@@ -0,0 +1,7 @@
1
+ import type { ImageAlphaPort, ImageAlphaStrategy } from "./image-alpha.port";
2
+
3
+ export class ImageAlphaNoopAdapter implements ImageAlphaPort {
4
+ async flatten(recipe: ImageAlphaStrategy) {
5
+ return recipe.strategy === "output_path" ? recipe.output : recipe.input;
6
+ }
7
+ }
@@ -0,0 +1,28 @@
1
+ import fs from "node:fs/promises";
2
+ import sharp from "sharp";
3
+ import type { ImageAlphaPort, ImageAlphaStrategy } from "./image-alpha.port";
4
+
5
+ export class ImageAlphaSharpAdapter implements ImageAlphaPort {
6
+ async flatten(recipe: ImageAlphaStrategy) {
7
+ const final = recipe.strategy === "output_path" ? recipe.output : recipe.input;
8
+
9
+ const filename = final.getFilename();
10
+ const temporary = final.withFilename(filename.withSuffix("-flattened"));
11
+
12
+ const extension = String(final.getFilename().getExtension());
13
+ const format = (extension === "jpg" ? "jpeg" : extension) as keyof sharp.FormatEnum;
14
+
15
+ const pipeline = sharp(recipe.input.get());
16
+ using _sharp_ = { [Symbol.dispose]: () => pipeline.destroy() };
17
+
18
+ await pipeline
19
+ .rotate()
20
+ .flatten({ background: recipe.background })
21
+ .toFormat(format)
22
+ .toFile(temporary.get());
23
+
24
+ await fs.rename(temporary.get(), final.get());
25
+
26
+ return final;
27
+ }
28
+ }
@@ -0,0 +1,22 @@
1
+ import type * as tools from "@bgord/tools";
2
+
3
+ type ImageAlphaBackground = string | { r: number; g: number; b: number; alpha?: number };
4
+
5
+ type ImageAlphaOutputPathStrategy = {
6
+ strategy: "output_path";
7
+ input: tools.FilePathRelative | tools.FilePathAbsolute;
8
+ output: tools.FilePathRelative | tools.FilePathAbsolute;
9
+ background: ImageAlphaBackground;
10
+ };
11
+
12
+ type ImageAlphaInPlaceStrategy = {
13
+ strategy: "in_place";
14
+ input: tools.FilePathRelative | tools.FilePathAbsolute;
15
+ background: ImageAlphaBackground;
16
+ };
17
+
18
+ export type ImageAlphaStrategy = ImageAlphaInPlaceStrategy | ImageAlphaOutputPathStrategy;
19
+
20
+ export interface ImageAlphaPort {
21
+ flatten(recipe: ImageAlphaStrategy): Promise<tools.FilePathRelative | tools.FilePathAbsolute>;
22
+ }
@@ -0,0 +1,10 @@
1
+ import type * as tools from "@bgord/tools";
2
+ import type { ImageProcessorPort, ImageProcessorStrategy } from "./image-processor.port";
3
+
4
+ export class ImageProcessorNoopAdapter implements ImageProcessorPort {
5
+ async process(recipe: ImageProcessorStrategy): Promise<tools.FilePathRelative | tools.FilePathAbsolute> {
6
+ return recipe.strategy === "output_path"
7
+ ? recipe.output
8
+ : recipe.input.withFilename(recipe.input.getFilename().withExtension(recipe.to));
9
+ }
10
+ }
@@ -0,0 +1,49 @@
1
+ import fs from "node:fs/promises";
2
+ import type * as tools from "@bgord/tools";
3
+ import sharp from "sharp";
4
+ import type { ImageProcessorPort, ImageProcessorStrategy } from "./image-processor.port";
5
+
6
+ export class ImageProcessorSharpAdapter implements ImageProcessorPort {
7
+ private static readonly DEFAULT_QUALITY = 85;
8
+
9
+ async process(recipe: ImageProcessorStrategy): Promise<tools.FilePathRelative | tools.FilePathAbsolute> {
10
+ const final =
11
+ recipe.strategy === "output_path"
12
+ ? recipe.output
13
+ : recipe.input.withFilename(recipe.input.getFilename().withExtension(recipe.to));
14
+
15
+ const temporary = final.withFilename(final.getFilename().withSuffix("-processed"));
16
+
17
+ const finalExtension = final.getFilename().getExtension();
18
+ const encoder = (finalExtension === "jpg" ? "jpeg" : finalExtension) as keyof sharp.FormatEnum;
19
+
20
+ const quality = recipe.quality ?? ImageProcessorSharpAdapter.DEFAULT_QUALITY;
21
+
22
+ const pipeline = sharp(recipe.input.get());
23
+ using _sharp_ = { [Symbol.dispose]: () => pipeline.destroy() };
24
+
25
+ let processor = pipeline.rotate();
26
+
27
+ if (recipe.background) {
28
+ processor = processor.flatten({ background: recipe.background as any });
29
+ }
30
+
31
+ processor = processor.resize({
32
+ width: recipe.maxSide,
33
+ height: recipe.maxSide,
34
+ fit: "inside",
35
+ withoutEnlargement: true,
36
+ });
37
+
38
+ processor = processor.toFormat(encoder, { quality });
39
+
40
+ await processor.toFile(temporary.get());
41
+ await fs.rename(temporary.get(), final.get());
42
+
43
+ if (recipe.strategy === "in_place" && final.get() !== recipe.input.get()) {
44
+ await fs.unlink(recipe.input.get());
45
+ }
46
+
47
+ return final;
48
+ }
49
+ }
@@ -0,0 +1,28 @@
1
+ import type * as tools from "@bgord/tools";
2
+
3
+ type ImageBackground = string | { r: number; g: number; b: number; alpha?: number };
4
+
5
+ type ImageProcessorOutputPathStrategy = {
6
+ strategy: "output_path";
7
+ input: tools.FilePathRelative | tools.FilePathAbsolute;
8
+ output: tools.FilePathRelative | tools.FilePathAbsolute;
9
+ maxSide: number;
10
+ to: tools.ExtensionType;
11
+ quality?: number;
12
+ background?: ImageBackground;
13
+ };
14
+
15
+ type ImageProcessorInPlaceStrategy = {
16
+ strategy: "in_place";
17
+ input: tools.FilePathRelative | tools.FilePathAbsolute;
18
+ maxSide: number;
19
+ to: tools.ExtensionType;
20
+ quality?: number;
21
+ background?: ImageBackground;
22
+ };
23
+
24
+ export type ImageProcessorStrategy = ImageProcessorInPlaceStrategy | ImageProcessorOutputPathStrategy;
25
+
26
+ export interface ImageProcessorPort {
27
+ process(recipe: ImageProcessorStrategy): Promise<tools.FilePathRelative | tools.FilePathAbsolute>;
28
+ }
package/src/index.ts CHANGED
@@ -35,6 +35,9 @@ export * from "./gzip.service";
35
35
  export * from "./healthcheck.service";
36
36
  export * from "./http-logger.middleware";
37
37
  export * from "./i18n.service";
38
+ export * from "./image-alpha.port";
39
+ export * from "./image-alpha-noop.adapter";
40
+ export * from "./image-alpha-sharp.adapter";
38
41
  export * from "./image-blur.port";
39
42
  export * from "./image-blur-noop.adapter";
40
43
  export * from "./image-blur-sharp.adapter";
@@ -50,6 +53,9 @@ export * from "./image-formatter-sharp.adapter";
50
53
  export * from "./image-info.port";
51
54
  export * from "./image-info-noop.adapter";
52
55
  export * from "./image-info-sharp.adapter";
56
+ export * from "./image-processor.port";
57
+ export * from "./image-processor-noop.adapter";
58
+ export * from "./image-processor-sharp.adapter";
53
59
  export * from "./image-resizer.port";
54
60
  export * from "./image-resizer-noop.adapter";
55
61
  export * from "./image-resizer-sharp.adapter";