Skip to content

Commit 995e08e

Browse files
authored
Merge pull request #52 from JS-AK/fix/zip/update-utils
fix: updated zip utils to-byte fn
2 parents 9d9dcbd + bd2f04b commit 995e08e

File tree

5 files changed

+88
-14
lines changed

5 files changed

+88
-14
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@
4444
"lint": "eslint . --ext .ts",
4545
"postbuild:esm": "node scripts/write-esm-package.js",
4646
"postbuild:cjs": "node scripts/write-cjs-package.js",
47-
"test": "vitest run",
47+
"test:unit": "vitest run --config vitest.unit.config.js",
48+
"test:integration": "vitest run --config vitest.integration.config.js",
49+
"test": "npm run test:unit && npm run test:integration",
4850
"test:watch": "vitest",
4951
"test:coverage": "vitest run --coverage"
5052
},

src/lib/zip/utils/to-bytes.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,29 @@ import { Buffer } from "node:buffer";
1515
* @returns {Buffer} - A new Buffer of exactly `len` bytes containing:
1616
* 1. The value's bytes in little-endian order (least significant byte first)
1717
* 2. Zero padding in any remaining higher-order bytes
18-
* @throws {RangeError} - If the value requires more bytes than `len` to represent
19-
* (though this is currently not explicitly checked)
18+
*
19+
* @throws {RangeError} - If the length is not positive or the value is negative.
2020
*/
2121
export function toBytes(value: number, len: number): Buffer {
22-
// Allocate a new Buffer of the requested length, automatically zero-filled
22+
if (len <= 0) throw new RangeError("Length must be a positive integer");
23+
if (value < 0) throw new RangeError("Negative values are not supported");
24+
if (!Number.isSafeInteger(value)) throw new RangeError("Value must be a safe integer");
25+
26+
// Use BigInt to correctly handle 53-bit values
27+
let bigint = BigInt(value);
2328
const buf = Buffer.alloc(len);
2429

25-
// Process each byte position from least significant to most significant
2630
for (let i = 0; i < len; i++) {
27-
// Store the least significant byte of the current value
28-
buf[i] = value & 0xff; // Mask to get bottom 8 bits
31+
// Extract the least significant byte and assign to buffer
32+
buf[i] = Number(bigint & 0xffn);
33+
bigint >>= 8n;
2934

30-
// Right-shift the value by 8 bits to process the next byte
31-
// Note: This uses unsigned right shift (>>> would be signed)
32-
value >>= 8;
33-
34-
// If the loop completes with value != 0, we've overflowed the buffer length,
35-
// but this isn't currently checked/handled
35+
// Stop early if all remaining bits are zero
36+
if (bigint === 0n) break;
3637
}
3738

39+
// If bigint is still non-zero, it means we overflowed the buffer length
40+
if (bigint > 0n) throw new RangeError("Value exceeds the maximum size for the specified length");
41+
3842
return buf;
3943
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { describe, expect, it } from "vitest";
2+
import { toBytes } from "./to-bytes.js";
3+
4+
// Test suite for toBytes function
5+
describe("toBytes", () => {
6+
it("should convert a small number to a 1-byte buffer", () => {
7+
expect(toBytes(42, 1)).toEqual(Buffer.from([42]));
8+
});
9+
10+
it("should convert a small number to a multi-byte buffer with padding", () => {
11+
expect(toBytes(42, 4)).toEqual(Buffer.from([42, 0, 0, 0]));
12+
});
13+
14+
it("should handle multi-byte numbers correctly", () => {
15+
expect(toBytes(4660, 4)).toEqual(Buffer.from([0x34, 0x12, 0, 0]));
16+
expect(toBytes(0x12345678, 4)).toEqual(Buffer.from([0x78, 0x56, 0x34, 0x12]));
17+
});
18+
19+
it("should handle maximum safe integer correctly", () => {
20+
expect(toBytes(Number.MAX_SAFE_INTEGER, 8)).toEqual(Buffer.from([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00]));
21+
});
22+
23+
it("should handle zero correctly", () => {
24+
expect(toBytes(0, 4)).toEqual(Buffer.from([0, 0, 0, 0]));
25+
});
26+
27+
it("should return a zero-filled buffer for zero with a larger length", () => {
28+
expect(toBytes(0, 8)).toEqual(Buffer.alloc(8));
29+
});
30+
31+
it("should throw a RangeError for negative lengths", () => {
32+
expect(() => toBytes(123, -1)).toThrow(RangeError);
33+
});
34+
35+
it("should throw a RangeError for zero length", () => {
36+
expect(() => toBytes(123, 0)).toThrow(RangeError);
37+
});
38+
39+
it("should throw a RangeError for negative values", () => {
40+
expect(() => toBytes(-123, 4)).toThrow(RangeError);
41+
});
42+
43+
it("should throw a RangeError for non-safe integers", () => {
44+
expect(() => toBytes(Number.MAX_SAFE_INTEGER + 1, 8)).toThrow(RangeError);
45+
});
46+
47+
it("should handle maximum value fitting in the given length", () => {
48+
expect(toBytes(255, 1)).toEqual(Buffer.from([0xff]));
49+
expect(toBytes(65535, 2)).toEqual(Buffer.from([0xff, 0xff]));
50+
expect(toBytes(4294967295, 4)).toEqual(Buffer.from([0xff, 0xff, 0xff, 0xff]));
51+
expect(toBytes(Number.MAX_SAFE_INTEGER, 8)).toEqual(Buffer.from([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00]));
52+
});
53+
54+
it("should throw a RangeError if the value exceeds the buffer length", () => {
55+
expect(() => toBytes(256, 1)).toThrow(RangeError);
56+
expect(() => toBytes(65536, 2)).toThrow(RangeError);
57+
expect(() => toBytes(4294967296, 4)).toThrow(RangeError);
58+
expect(() => toBytes(Number.MAX_SAFE_INTEGER + 1, 8)).toThrow(RangeError);
59+
});
60+
});

vitest.integration.config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { defineConfig } from "vitest/config";
2+
3+
export default defineConfig({
4+
test: {
5+
environment: "node",
6+
include: ["src/**/*.integration.spec.ts"],
7+
},
8+
});

vitest.config.js renamed to vitest.unit.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ import { defineConfig } from "vitest/config";
33
export default defineConfig({
44
test: {
55
environment: "node",
6-
include: ["src/**/*.spec.ts"],
6+
include: ["src/**/*.unit.spec.ts"],
77
},
88
});

0 commit comments

Comments
 (0)