hdr-canvas 0.0.12 → 0.1.0

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/dist/index.d.ts CHANGED
@@ -6,6 +6,8 @@ import { ColorTypes } from 'colorjs.io';
6
6
  type HDRHTMLCanvasOptionsType = "mode";
7
7
  type HDRHTMLCanvasOptions = { [key in HDRHTMLCanvasOptionsType]?: string };
8
8
 
9
+ type HDRImageDataArray = ImageDataArray | Float16Array | Uint16Array;
10
+
9
11
  interface HDRHTMLCanvasElement extends HTMLCanvasElement {
10
12
  configureHighDynamicRange(options: HDRHTMLCanvasOptions): void;
11
13
  _getContext(contextId: string, options?: object): RenderingContext | null;
@@ -13,45 +15,91 @@ interface HDRHTMLCanvasElement extends HTMLCanvasElement {
13
15
 
14
16
  interface HDRImageData {
15
17
  readonly colorSpace: PredefinedColorSpace;
16
- readonly data: Uint8ClampedArray | Uint16Array;
18
+ readonly data: HDRImageDataArray | Uint16Array;
17
19
  readonly height: number;
18
20
  readonly width: number;
19
21
  }
20
22
 
21
23
  // See https://github.com/w3c/ColorWeb-CG/blob/main/hdr_html_canvas_element.md
22
- // "rec2100-display-linear" is left out beacause of mapping issues
24
+ // "rec2100-display-linear" is left out because of mapping issues
23
25
  type HDRPredefinedColorSpace = "display-p3" | "srgb" | "rec2100-hlg" | "rec2100-pq";
24
26
 
25
- type Uint16ImagePixelCallback = (red: number, green: number, blue: number, alpha: number) => Uint16Array;
26
- declare class Uint16Image {
27
- height: number;
28
- width: number;
29
- data: Uint16Array;
27
+ //enum HDRPredefinedColorSpace {"display-p3", "srgb", "rec2100-hlg", "rec2100-pq", "rec2100-display-linear"};
28
+
29
+ /**
30
+ * A callback function that receives the red, green, blue, and alpha values of a pixel
31
+ * and returns a new `Float16Array` with the modified values.
32
+ *
33
+ * @callback HDRImagePixelCallback
34
+ * @param {number} red - The red channel value (0-65535).
35
+ * @param {number} green - The green channel value (0-65535).
36
+ * @param {number} blue - The blue channel value (0-65535).
37
+ * @param {number} alpha - The alpha channel value (0-65535).
38
+ * @returns {ImageDataArray} A new `Float16Array` containing the four channel values.
39
+ */
40
+ type HDRImagePixelCallback = (red: number, green: number, blue: number, alpha: number) => HDRImageDataArray;
41
+
42
+ interface CanvasRenderingContext2DHDR extends CanvasRenderingContext2D {}
43
+
44
+ declare abstract class HDRImage {
30
45
  static DEFAULT_COLORSPACE: HDRPredefinedColorSpace;
31
46
  static SDR_MULTIPLIER: number;
32
47
  static COLORSPACES: Record<HDRPredefinedColorSpace, ColorTypes>;
48
+ data: HDRImageDataArray;
49
+ height: number;
50
+ width: number;
51
+ constructor(width: number, height: number);
52
+ static fromImageData(imageData: HDRImageData | ImageData): HDRImage;
53
+ static fromImageDataArray(width: number, height: number, imageDataArray: Uint8ClampedArray | Uint8ClampedArray<ArrayBufferLike>): HDRImage;
54
+ static loadSDRImageData(url: URL): Promise<ImageData | undefined>;
55
+ getPixel(w: number, h: number): HDRImageDataArray;
56
+ setPixel(w: number, h: number, px: number[]): void;
57
+ abstract setImageData(imageData: HDRImageData | ImageData): void;
58
+ abstract getImageData(): ImageData | null;
59
+ abstract fill(color: number[]): this | undefined;
60
+ abstract pixelCallback(fn: HDRImagePixelCallback): void;
61
+ clone(): this;
62
+ }
63
+
64
+ declare class Uint16Image extends HDRImage {
65
+ data: Uint16Array;
33
66
  colorSpace: HDRPredefinedColorSpace;
34
67
  constructor(width: number, height: number, colorspace?: string);
35
- fill(color: number[]): Uint16Image | undefined;
36
- getPixel(w: number, h: number): Uint16Array;
37
- setPixel(w: number, h: number, px: number[]): void;
68
+ fill(color: number[]): this | undefined;
38
69
  static scaleUint8ToUint16(val: number): number;
39
70
  getImageData(): ImageData | null;
40
71
  static convertPixelToRec2100_hlg(pixel: Uint8ClampedArray): Uint16Array;
41
72
  static convertArrayToRec2100_hlg(data: Uint8ClampedArray): Uint16Array;
42
- pixelCallback(fn: Uint16ImagePixelCallback): void;
43
- static loadSDRImageData(url: URL): Promise<HDRImageData | undefined>;
73
+ pixelCallback(fn: HDRImagePixelCallback): void;
44
74
  static fromImageData(imageData: HDRImageData): Uint16Image;
45
75
  static fromURL(url: URL): Promise<Uint16Image | undefined>;
46
76
  setImageData(imageData: HDRImageData): void;
47
- clone(): Uint16Image;
77
+ }
78
+
79
+ declare class Float16Image extends HDRImage {
80
+ data: Float16Array;
81
+ static DEFAULT_PIXELFORMAT: ImageDataPixelFormat;
82
+ colorSpace: HDRPredefinedColorSpace;
83
+ pixelFormat: ImageDataPixelFormat;
84
+ constructor(width: number, height: number, colorspace?: string, pixelFormat?: string);
85
+ fill(color: number[]): this | undefined;
86
+ static scaleUint8ToFloat16(val: number): number;
87
+ getImageData(): ImageData | null;
88
+ static convertPixelToRec2100_hlg(pixel: Uint8ClampedArray): Float16Array;
89
+ static convertArrayToRec2100_hlg(data: Uint8ClampedArray): Float16Array;
90
+ pixelCallback(fn: HDRImagePixelCallback): void;
91
+ static fromImageData(imageData: HDRImageData): Float16Image;
92
+ static fromImageDataArray(width: number, height: number, imageDataArray: Uint8ClampedArray | Uint8ClampedArray<ArrayBufferLike>): Float16Image;
93
+ static fromURL(url: URL): Promise<Float16Image | undefined>;
94
+ setImageData(imageData: HDRImageData): void;
95
+ clone(): this;
48
96
  }
49
97
 
50
98
  declare function checkHDR(): boolean;
51
99
  declare function checkHDRCanvas(): boolean;
52
100
 
53
- declare function initHDRCanvas(canvas: HDRHTMLCanvasElement): RenderingContext | null;
101
+ declare function initHDRCanvas(canvas: HDRHTMLCanvasElement): CanvasRenderingContext2DHDR | null;
54
102
  declare function defaultGetContextHDR(): void;
55
103
  declare function resetGetContext(): void;
56
104
 
57
- export { Uint16Image, checkHDR, checkHDRCanvas, defaultGetContextHDR, initHDRCanvas, resetGetContext };
105
+ export { Float16Image, HDRImage, Uint16Image, checkHDR, checkHDRCanvas, defaultGetContextHDR, initHDRCanvas, resetGetContext };
@@ -0,0 +1,47 @@
1
+ # `hdr-canvas` 0.1.0
2
+
3
+ # Introduction
4
+
5
+ Since the last release many areas of handling HDR contet in the browser have evolved.
6
+ Most notably is certainly the introduction of the `Float16Array` in the `ImageData` construtor:
7
+
8
+ - The [WhatWG spec](https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#imagedataarray), [MDN](https://developer.mozilla.org/en-US/docs/Web/API/ImageData/ImageData#syntax) and [BCD]([new ImageData(new Float16Array(4), 1, 1, {pixelFormat:"rgba-float16"})](https://github.com/mdn/browser-compat-data/issues/27547)) have been updated accordingly. You can test your own browser using `new ImageData(new Float16Array(4), 1, 1, {pixelFormat:"rgba-float16"})`.
9
+ - Still open in [Firefox](https://bugzil.la/1958830)
10
+ - Hidden behind flag in [Safari](https://webkit.org/b/291196)
11
+ - Chromium has implemented it starting with [137](https://source.chromium.org/chromium/chromium/src/+/refs/tags/137.0.7104.0:third_party/blink/renderer/core/html/canvas/image_data.idl): \*\*The `ImageData` constructor only acceppts `Float16Array` instead of `Uint16Array`. This makes older versions of this modue obsolute, since they targeted the chromium specific solution.
12
+ - If Safari enables it by default it will be also in the [Typescript DOM types](https://github.com/microsoft/TypeScript-DOM-lib-generator/issues/2107)
13
+
14
+ As [@reitowo](https://github.com/reitowo) pointed out, there has been a change to the `getContext("2d")` method. The key `pixelFormat` has been replaced by `colorType`.
15
+
16
+ In parallel threre have been changes to the UltraHDR image format, especially te encoding of gain map matadata. While this used to be don in XMP it's now done according to ISO 21496-1. This ihas been adopted by Google and Apple in newer OS versions like Android 15 and iOS 18 to avoid cross-platform fragmentation. The [UltraHDR Library](https://github.com/google/libultrahdr) has already changed to ussin the [ISO format as default](https://github.com/google/libultrahdr/blob/main/docs/building.md).
17
+
18
+ Currently the ThreeJS UHDR loader doesn't know how to handle this change, see [mrdoob/three.js#32293](https://github.com/mrdoob/three.js/issues/32293).
19
+
20
+ # Key Changes & New Features
21
+
22
+ - Better support for official Web-APIs
23
+ - Use `Float16Array` instead of `Uint16Array`
24
+ - Use the correct option for initializing 2D canvas context
25
+
26
+ ## Improved Documentation
27
+
28
+ The documentation have been greatly improved, there is now also a [site](https://cmahnke.github.io/hdr-canvas/) including the examples and API docs.
29
+
30
+ ## Examples
31
+
32
+ The examples fro the blog are now part of this repository:
33
+
34
+ - [`tests/site/assets/ts/hdr-three.js.ts`](tests/site/assets/ts/hdr-three.js.ts) - Three JS with HDR texture
35
+ - [`tests/site/assets/ts/image-slider.ts`](tests/site/assets/ts/image-slider.ts) - Generated HDR content
36
+ - [`tests/site/assets/ts/main.ts`](tests/site/assets/ts/main.ts) - feature detection
37
+
38
+ These example are also avalable on the new [documentation site](https://cmahnke.github.io/hdr-canvas/)
39
+
40
+ ## Advocacy
41
+
42
+ Since the changes by the WhatWG weren't picked up already there had to be some Issues in the relevant repos to be raised.
43
+
44
+ - [mdn/content#40639](https://github.com/mdn/content/issues/40639)
45
+ - [mdn/browser-compat-data#27547](https://github.com/mdn/browser-compat-data/issues/27547)
46
+ - [microsoft/TypeScript-DOM-lib-generator#2107](https://github.com/microsoft/TypeScript-DOM-lib-generator/issues/2107)
47
+ - [mrdoob/three.js#32293](https://github.com/mrdoob/three.js/issues/32293).
package/package.json CHANGED
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "name": "hdr-canvas",
3
- "version": "0.0.12",
3
+ "version": "0.1.0",
4
4
  "description": "HDR capable HTML canvas",
5
5
  "main": "dist/hdr-canvas.cjs",
6
6
  "module": "dist/hdr-canvas.js",
7
7
  "type": "module",
8
8
  "exports": {
9
9
  ".": {
10
+ "types": "./dist/index.d.ts",
10
11
  "import": "./dist/hdr-canvas.js",
11
- "require": "./dist/hdr-canvas.cjs"
12
+ "default": "./dist/hdr-canvas.js"
12
13
  },
13
- "./three": "./three/*"
14
+ "./three/*": "./three/*"
14
15
  },
15
16
  "files": [
16
17
  "dist/hdr-canvas.d.ts",
@@ -18,23 +19,39 @@
18
19
  "dist/hdr-canvas.js.map",
19
20
  "dist/hdr-canvas.min.js",
20
21
  "dist/hdr-canvas.min.js.map",
21
- "dist/hdr-canvas.cjs",
22
- "dist/hdr-canvas.cjs.map",
23
22
  "dist/hdr-canvas.umd.js",
24
23
  "dist/hdr-canvas.umd.js.map",
25
24
  "dist/index.d.ts",
26
25
  "dist/@types",
27
26
  "three",
28
- "src"
27
+ "src",
28
+ "docs",
29
+ "scripts",
30
+ "patches",
31
+ "rollup.config.mjs",
32
+ "tsconfig.json",
33
+ "README",
34
+ "LICENCE"
29
35
  ],
30
36
  "types": "dist/index.d.ts",
37
+ "engines": {
38
+ "node": ">=24",
39
+ "deno": ">=1.43",
40
+ "bun": ">=1.1.23"
41
+ },
31
42
  "scripts": {
32
- "test": "echo \"Error: no test specified\" && exit 1",
33
- "lint": "eslint . -c eslint.config.mjs --report-unused-disable-directives",
43
+ "lint": "npm run eslint && npm run stylelint",
44
+ "eslint": "eslint . -c eslint.config.mjs --report-unused-disable-directives",
45
+ "stylelint": "stylelint -c tests/site/stylelint.config.js 'tests/**/*.scss'",
46
+ "knip": "knip",
34
47
  "tsc": "tsc",
35
48
  "build": "rimraf ./dist ./build && tsc && rollup --config",
49
+ "dev": "npm run jsdoc && vite -c tests/site/vite.config.js",
50
+ "site": "npm run jsdoc && vite -c tests/site/vite.config.js build",
36
51
  "clean": "rimraf ./dist ./build",
37
- "format": "prettier . --check"
52
+ "format": "prettier . --check",
53
+ "jsdoc": "jsdoc -c jsdoc.config.json -r .",
54
+ "test": "vitest --config tests/site/vite.config.js"
38
55
  },
39
56
  "repository": {
40
57
  "type": "git",
@@ -53,20 +70,41 @@
53
70
  },
54
71
  "homepage": "https://github.com/cmahnke/hdr-canvas#readme",
55
72
  "devDependencies": {
56
- "@eslint/js": "^9.15.0",
57
- "@rollup/plugin-node-resolve": "^15.3.0",
73
+ "@eslint/js": "^9.39.1",
74
+ "@eslint/markdown": "^7.5.1",
75
+ "@fontsource-utils/scss": "^0.2.2",
76
+ "@fontsource-variable/league-spartan": "^5.2.8",
77
+ "@rollup/plugin-node-resolve": "^16.0.3",
58
78
  "@rollup/plugin-terser": "^0.4.4",
59
- "@rollup/plugin-typescript": "^12.1.1",
60
- "@types/eslint__js": "^8.42.3",
61
- "eslint": "^9.15.0",
62
- "prettier": "^3.3.3",
63
- "rimraf": "^6.0.1",
64
- "rollup": "^4.27.3",
65
- "rollup-plugin-dts": "^6.1.1",
66
- "three": "^0.170.0",
79
+ "@rollup/plugin-typescript": "^12.3.0",
80
+ "@napi-rs/canvas": "^0.1.82",
81
+ "@types/jsdom": "^27.0.0",
82
+ "@types/semver": "^7.7.1",
83
+ "@types/three": "^0.181.0",
84
+ "@typescript-eslint/parser": "^8.46.4",
85
+ "@typescript/lib-dom": "npm:@types/web@^0.0.294",
86
+ "better-docs": "^2.7.3",
87
+ "eslint": "^9.39.1",
88
+ "file-url": "^4.0.0",
89
+ "globals": "^16.5.0",
90
+ "jsdoc": "^4.0.5",
91
+ "jsdom": "^27.2.0",
92
+ "knip": "^5.69.1",
93
+ "pkg-types": "^2.3.0",
94
+ "prettier": "^3.6.2",
95
+ "rimraf": "^6.1.0",
96
+ "rollup": "^4.53.2",
97
+ "rollup-plugin-dts": "^6.2.3",
98
+ "sass": "^1.94.0",
99
+ "semver": "^7.7.3",
100
+ "stylelint": "^16.25.0",
101
+ "stylelint-config-standard-scss": "^16.0.0",
102
+ "three": "^0.181.1",
67
103
  "tslib": "^2.8.1",
68
- "typescript": "^5.6.3",
69
- "typescript-eslint": "^8.15.0"
104
+ "typescript": "^5.9.3",
105
+ "typescript-eslint": "^8.46.4",
106
+ "vite": "^7.2.2",
107
+ "vitest": "^4.0.9"
70
108
  },
71
109
  "dependencies": {
72
110
  "colorjs.io": "^0.5.2"
@@ -0,0 +1,46 @@
1
+ diff --git a/node_modules/@typescript/dom-lib-generator/inputfiles/overridingTypes.jsonc b/node_modules/@typescript/dom-lib-generator/inputfiles/overridingTypes.jsonc
2
+ index 7c11453..c7f0bbb 100644
3
+ --- a/node_modules/@typescript/dom-lib-generator/inputfiles/overridingTypes.jsonc
4
+ +++ b/node_modules/@typescript/dom-lib-generator/inputfiles/overridingTypes.jsonc
5
+ @@ -4035,6 +4035,23 @@
6
+ }
7
+ ]
8
+ },
9
+ + {
10
+ + "name": "ImageDataArray",
11
+ + "typeParameters": [
12
+ + {
13
+ + "name": "ArrayBuffer"
14
+ + }
15
+ + ],
16
+ + "type": [
17
+ + {
18
+ + "type": "Uint8ClampedArray"
19
+ + },
20
+ + {
21
+ + "type": "Float16Array"
22
+ + }
23
+ + ],
24
+ + "overrideType": "Uint8ClampedArray<ArrayBuffer> | Float16Array<ArrayBuffer>"
25
+ + },
26
+ {
27
+ "name": "ReadableStreamReader",
28
+ "typeParameters": [
29
+ diff --git a/node_modules/@typescript/dom-lib-generator/inputfiles/removedTypes.jsonc b/node_modules/@typescript/dom-lib-generator/inputfiles/removedTypes.jsonc
30
+ index 8089030..d93ee40 100644
31
+ --- a/node_modules/@typescript/dom-lib-generator/inputfiles/removedTypes.jsonc
32
+ +++ b/node_modules/@typescript/dom-lib-generator/inputfiles/removedTypes.jsonc
33
+ @@ -410,13 +410,6 @@
34
+ }
35
+ }
36
+ },
37
+ - "ImageDataSettings": {
38
+ - "members": {
39
+ - "member": {
40
+ - "pixelFormat": null // Blink experimental only as of 2025-04
41
+ - }
42
+ - }
43
+ - },
44
+ "IntersectionObserverInit": {
45
+ "members": {
46
+ "member": {
@@ -0,0 +1,55 @@
1
+ import typescript from "@rollup/plugin-typescript";
2
+ import { dts } from "rollup-plugin-dts";
3
+ import { nodeResolve } from "@rollup/plugin-node-resolve";
4
+ import terser from "@rollup/plugin-terser";
5
+
6
+ // External configs
7
+ import typescriptOptions from "./tsconfig.json" with { type: "json" };
8
+
9
+ const config = [
10
+ {
11
+ input: "src/index.ts",
12
+ output: [
13
+ {
14
+ file: "dist/hdr-canvas.js",
15
+ format: "es",
16
+ sourcemap: true
17
+ },
18
+ {
19
+ file: "dist/hdr-canvas.umd.js",
20
+ format: "umd",
21
+ name: "HDRCanvas",
22
+ sourcemap: true
23
+ }
24
+ ],
25
+ external: ["three" /*, "colorjs.io" */],
26
+ plugins: [typescript(typescriptOptions), nodeResolve()]
27
+ },
28
+ {
29
+ input: "src/index.ts",
30
+ output: {
31
+ file: "dist/hdr-canvas.min.js",
32
+ format: "iife",
33
+ name: "HDRCanvas",
34
+ sourcemap: true
35
+ },
36
+ external: ["three"],
37
+ plugins: [typescript(typescriptOptions), nodeResolve(), terser()]
38
+ },
39
+ {
40
+ input: "src/index.ts",
41
+ output: [
42
+ {
43
+ file: "dist/@types/hdr-canvas.d.ts",
44
+ format: "es"
45
+ },
46
+ {
47
+ file: "dist/index.d.ts",
48
+ format: "es"
49
+ }
50
+ ],
51
+ plugins: [dts()]
52
+ }
53
+ ];
54
+
55
+ export default config;
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ npm ci
6
+ npm run lint
7
+ npm run format
8
+ npx tsc -b --verbose
9
+ npx rollup --config
10
+ npx prettier --check .
11
+ npm run build
12
+ npm run site
@@ -0,0 +1,175 @@
1
+ import { existsSync, rmSync, readFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import git from "isomorphic-git";
4
+ import http from "isomorphic-git/http/node";
5
+ import * as fs from "node:fs";
6
+ import yargs from "yargs";
7
+ import { hideBin } from "yargs/helpers";
8
+
9
+ const argv = yargs(hideBin(process.argv))
10
+ .option("directory", {
11
+ alias: "d",
12
+ type: "string",
13
+ default: process.cwd(),
14
+ description: "The root directory containing the .gitmodules file."
15
+ })
16
+ .option("force", {
17
+ alias: "f",
18
+ type: "boolean",
19
+ default: false,
20
+ description: "Force a clean checkout by removing existing directories."
21
+ })
22
+ .option("verbose", {
23
+ alias: "v",
24
+ type: "boolean",
25
+ default: false,
26
+ description: "Show verbose output during the cloning process."
27
+ })
28
+ .option("list", {
29
+ alias: "l",
30
+ type: "boolean",
31
+ default: false,
32
+ description: "List submodules and their directories in a table."
33
+ })
34
+ .option("clean", {
35
+ alias: "c",
36
+ type: "boolean",
37
+ default: false,
38
+ description: "Remove all directories listed in the .gitmodules file."
39
+ })
40
+ .option("timeout", {
41
+ alias: "t",
42
+ type: "number",
43
+ default: 120000, // Default timeout of 120 seconds (120000ms)
44
+ description: "Set the timeout for git operations in milliseconds."
45
+ })
46
+ .check((argv) => {
47
+ const actionFlags = [argv.list, argv.clean];
48
+ const trueFlags = actionFlags.filter((flag) => flag === true);
49
+ if (trueFlags.length > 1) {
50
+ throw new Error("Please use only one of the action flags: --list or --clean.");
51
+ }
52
+ return true;
53
+ })
54
+ .help()
55
+ .alias("help", "h").argv;
56
+
57
+ function getSubmoduleEntries(dir) {
58
+ const gitmodulesPath = resolve(dir, ".gitmodules");
59
+ if (!existsSync(gitmodulesPath)) {
60
+ console.error(`Error: No .gitmodules file found in the specified directory: ${dir}`);
61
+ process.exit(1);
62
+ }
63
+
64
+ const gitmodulesContent = readFileSync(gitmodulesPath, "utf8");
65
+ const submoduleEntries = gitmodulesContent.split("\n\n").filter((entry) => entry.trim().startsWith("[submodule"));
66
+ if (submoduleEntries.length === 0) {
67
+ console.log("No submodules found in .gitmodules file. Exiting.");
68
+ process.exit(0);
69
+ }
70
+
71
+ const submodules = [];
72
+ for (const entry of submoduleEntries) {
73
+ const lines = entry.split("\n").map((line) => line.trim());
74
+ let pathValue, urlValue;
75
+ for (const line of lines) {
76
+ if (line.startsWith("path =")) {
77
+ pathValue = line.split("=")[1].trim();
78
+ } else if (line.startsWith("url =")) {
79
+ urlValue = line.split("=")[1].trim();
80
+ }
81
+ }
82
+ if (pathValue && urlValue) {
83
+ submodules.push({ path: pathValue, url: urlValue });
84
+ }
85
+ }
86
+ return submodules;
87
+ }
88
+
89
+ function printTable(data) {
90
+ const table = [
91
+ ["URL", "Path"],
92
+ ["---", "---"]
93
+ ];
94
+ data.forEach((sub) => {
95
+ table.push([`\`${sub.url}\``, `\`${sub.path}\``]);
96
+ });
97
+
98
+ const maxCols = [0, 0];
99
+ table.forEach((row) => {
100
+ maxCols[0] = Math.max(maxCols[0], row[0].length);
101
+ maxCols[1] = Math.max(maxCols[1], row[1].length);
102
+ });
103
+
104
+ table.forEach((row) => {
105
+ const formattedRow = `| ${row[0].padEnd(maxCols[0])} | ${row[1].padEnd(maxCols[1])} |`;
106
+ console.log(formattedRow);
107
+ });
108
+ }
109
+
110
+ async function main() {
111
+ const dir = resolve(argv.directory);
112
+ const submodules = getSubmoduleEntries(dir);
113
+
114
+ if (argv.list) {
115
+ console.log("Submodules in .gitmodules:");
116
+ printTable(submodules);
117
+ return;
118
+ }
119
+
120
+ if (argv.clean) {
121
+ console.log("Removing submodule directories...");
122
+ for (const sub of submodules) {
123
+ const submoduleDir = resolve(dir, sub.path);
124
+ if (existsSync(submoduleDir)) {
125
+ console.log(`Removing directory: ${submoduleDir}`);
126
+ rmSync(submoduleDir, { recursive: true, force: true });
127
+ } else {
128
+ console.log(`Directory not found, skipping: ${submoduleDir}`);
129
+ }
130
+ }
131
+ console.log("Clean operation complete.");
132
+ return;
133
+ }
134
+
135
+ for (const sub of submodules) {
136
+ const submoduleDir = resolve(dir, sub.path);
137
+
138
+ if (argv.verbose) {
139
+ console.log(`Processing submodule:`);
140
+ console.log(` URL: ${sub.url}`);
141
+ console.log(` Path: ${submoduleDir}`);
142
+ } else {
143
+ console.log(`Cloning submodule from ${sub.url} into ${submoduleDir}...`);
144
+ }
145
+
146
+ try {
147
+ if (argv.force && existsSync(submoduleDir)) {
148
+ if (argv.verbose) {
149
+ console.log(`Force flag enabled. Removing existing directory: ${submoduleDir}`);
150
+ }
151
+ rmSync(submoduleDir, { recursive: true, force: true });
152
+ } else if (existsSync(submoduleDir)) {
153
+ if (argv.verbose) {
154
+ console.log(`Directory ${submoduleDir} already exists. Skipping clone.`);
155
+ }
156
+ continue;
157
+ }
158
+
159
+ await git.clone({
160
+ fs: fs,
161
+ http: { ...http, timeout: argv.timeout },
162
+ dir: submoduleDir,
163
+ url: sub.url,
164
+ singleBranch: true,
165
+ depth: 1
166
+ });
167
+
168
+ console.log(`Successfully cloned submodule into ${submoduleDir}.`);
169
+ } catch (error) {
170
+ console.error(`Error cloning submodule into ${submoduleDir}:`, error.message);
171
+ }
172
+ }
173
+ }
174
+
175
+ main();