Skip to content

Commit 31c9342

Browse files
authored
Merge pull request #118 from hypercerts-org/prettier-lib
2 parents b086e05 + ca03f57 commit 31c9342

3 files changed

Lines changed: 107 additions & 107 deletions

File tree

.prettierignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
**/cache
1010
**/coverage
1111
**/dist
12-
**/lib
1312
**/node_modules
1413
**/out
1514
**/types

packages/sdk-core/src/lib/crypto.ts

Lines changed: 45 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,34 @@ import { NetworkError, ValidationError } from "../core/errors.js";
99
* Handles deeply nested objects and null values correctly.
1010
*/
1111
export function stableStringify(obj: unknown): string | undefined {
12-
if (obj === undefined || typeof obj === "function" || typeof obj === "symbol") {
13-
return undefined;
14-
}
15-
if (obj === null || typeof obj !== "object") {
16-
return JSON.stringify(obj);
17-
}
12+
if (obj === undefined || typeof obj === "function" || typeof obj === "symbol") {
13+
return undefined;
14+
}
15+
if (obj === null || typeof obj !== "object") {
16+
return JSON.stringify(obj);
17+
}
1818

19-
if (Array.isArray(obj)) {
20-
return JSON.stringify(obj.map((item) => {
21-
const val = stableStringify(item);
22-
return val === undefined ? null : JSON.parse(val);
23-
}));
24-
}
19+
if (Array.isArray(obj)) {
20+
return JSON.stringify(
21+
obj.map((item) => {
22+
const val = stableStringify(item);
23+
return val === undefined ? null : JSON.parse(val);
24+
}),
25+
);
26+
}
2527

26-
const sortedKeys = Object.keys(obj as object).sort();
27-
const sortedObj: Record<string, unknown> = {};
28+
const sortedKeys = Object.keys(obj as object).sort();
29+
const sortedObj: Record<string, unknown> = {};
2830

29-
for (const key of sortedKeys) {
30-
const value = (obj as Record<string, unknown>)[key];
31-
const str = stableStringify(value);
32-
// Skip undefined or non-serializable values
33-
if (str === undefined) continue;
34-
sortedObj[key] = JSON.parse(str);
35-
}
31+
for (const key of sortedKeys) {
32+
const value = (obj as Record<string, unknown>)[key];
33+
const str = stableStringify(value);
34+
// Skip undefined or non-serializable values
35+
if (str === undefined) continue;
36+
sortedObj[key] = JSON.parse(str);
37+
}
3638

37-
return JSON.stringify(sortedObj);
39+
return JSON.stringify(sortedObj);
3840
}
3941

4042
/**
@@ -46,30 +48,30 @@ export function stableStringify(obj: unknown): string | undefined {
4648
* @throws {ValidationError} If content is not serializable (e.g. undefined, function, symbol)
4749
*/
4850
export async function sha256Hash(content: unknown): Promise<string> {
49-
// Use stable stringification to ensure deterministic output
50-
const jsonString = stableStringify(content);
51+
// Use stable stringification to ensure deterministic output
52+
const jsonString = stableStringify(content);
5153

52-
if (jsonString === undefined) {
53-
throw new ValidationError(`Content illegal: not serializable (type: ${typeof content})`);
54-
}
54+
if (jsonString === undefined) {
55+
throw new ValidationError(`Content illegal: not serializable (type: ${typeof content})`);
56+
}
5557

56-
const msgBuffer = new TextEncoder().encode(jsonString);
58+
const msgBuffer = new TextEncoder().encode(jsonString);
5759

58-
if (typeof crypto !== "undefined" && crypto.subtle) {
59-
// Browser / Modern Node.js
60-
const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer);
61-
const hashArray = Array.from(new Uint8Array(hashBuffer));
62-
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
63-
} else {
64-
// Fallback for older environments or specific setups if global crypto isn't available
65-
try {
66-
// Dynamic import to avoid breaking browser builds if bundler doesn't handle it
60+
if (typeof crypto !== "undefined" && crypto.subtle) {
61+
// Browser / Modern Node.js
62+
const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer);
63+
const hashArray = Array.from(new Uint8Array(hashBuffer));
64+
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
65+
} else {
66+
// Fallback for older environments or specific setups if global crypto isn't available
67+
try {
68+
// Dynamic import to avoid breaking browser builds if bundler doesn't handle it
6769

68-
const { createHash } = await import("node:crypto");
69-
const hash = createHash("sha256").update(jsonString).digest("hex");
70-
return hash;
71-
} catch (e) {
72-
throw new NetworkError("SHA-256 hashing not supported in this environment", e);
73-
}
70+
const { createHash } = await import("node:crypto");
71+
const hash = createHash("sha256").update(jsonString).digest("hex");
72+
return hash;
73+
} catch (e) {
74+
throw new NetworkError("SHA-256 hashing not supported in this environment", e);
7475
}
76+
}
7577
}
Lines changed: 62 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,81 @@
1-
21
import { describe, it, expect } from "vitest";
32
import { stableStringify } from "../../src/lib/crypto.js";
43

54
describe("stableStringify", () => {
6-
it("should stringify primitives", () => {
7-
expect(stableStringify(1)).toBe("1");
8-
expect(stableStringify("test")).toBe('"test"');
9-
expect(stableStringify(true)).toBe("true");
10-
expect(stableStringify(null)).toBe("null");
11-
});
5+
it("should stringify primitives", () => {
6+
expect(stableStringify(1)).toBe("1");
7+
expect(stableStringify("test")).toBe('"test"');
8+
expect(stableStringify(true)).toBe("true");
9+
expect(stableStringify(null)).toBe("null");
10+
});
1211

13-
it("should sort object keys", () => {
14-
const obj = { c: 3, a: 1, b: 2 };
15-
expect(stableStringify(obj)).toBe('{"a":1,"b":2,"c":3}');
16-
});
12+
it("should sort object keys", () => {
13+
const obj = { c: 3, a: 1, b: 2 };
14+
expect(stableStringify(obj)).toBe('{"a":1,"b":2,"c":3}');
15+
});
1716

18-
it("should sort nested object keys", () => {
19-
const obj = {
20-
z: { y: 2, x: 1 },
21-
a: { c: 3, b: 4 },
22-
};
23-
expect(stableStringify(obj)).toBe('{"a":{"b":4,"c":3},"z":{"x":1,"y":2}}');
24-
});
17+
it("should sort nested object keys", () => {
18+
const obj = {
19+
z: { y: 2, x: 1 },
20+
a: { c: 3, b: 4 },
21+
};
22+
expect(stableStringify(obj)).toBe('{"a":{"b":4,"c":3},"z":{"x":1,"y":2}}');
23+
});
2524

26-
it("should preserve array order", () => {
27-
const arr = [3, 1, 2];
28-
expect(stableStringify(arr)).toBe("[3,1,2]");
29-
});
25+
it("should preserve array order", () => {
26+
const arr = [3, 1, 2];
27+
expect(stableStringify(arr)).toBe("[3,1,2]");
28+
});
3029

31-
it("should sort objects inside arrays", () => {
32-
const arr = [
33-
{ b: 2, a: 1 },
34-
{ d: 4, c: 3 },
35-
];
36-
expect(stableStringify(arr)).toBe('[{"a":1,"b":2},{"c":3,"d":4}]');
37-
});
30+
it("should sort objects inside arrays", () => {
31+
const arr = [
32+
{ b: 2, a: 1 },
33+
{ d: 4, c: 3 },
34+
];
35+
expect(stableStringify(arr)).toBe('[{"a":1,"b":2},{"c":3,"d":4}]');
36+
});
3837

39-
it("should ignore undefined, functions, and symbols", () => {
40-
const obj = {
41-
a: 1,
42-
b: undefined,
43-
c: () => { },
44-
d: Symbol("test"),
45-
e: 2,
46-
};
47-
expect(stableStringify(obj)).toBe('{"a":1,"e":2}');
48-
});
38+
it("should ignore undefined, functions, and symbols", () => {
39+
const obj = {
40+
a: 1,
41+
b: undefined,
42+
c: () => {},
43+
d: Symbol("test"),
44+
e: 2,
45+
};
46+
expect(stableStringify(obj)).toBe('{"a":1,"e":2}');
47+
});
4948

50-
it("should return undefined for non-serializable top-level inputs", () => {
51-
expect(stableStringify(undefined)).toBeUndefined();
52-
expect(stableStringify(() => { })).toBeUndefined();
53-
expect(stableStringify(Symbol("test"))).toBeUndefined();
54-
});
49+
it("should return undefined for non-serializable top-level inputs", () => {
50+
expect(stableStringify(undefined)).toBeUndefined();
51+
expect(stableStringify(() => {})).toBeUndefined();
52+
expect(stableStringify(Symbol("test"))).toBeUndefined();
53+
});
5554

56-
it("should handle mixed complex structures", () => {
57-
const obj = {
58-
id: 1,
59-
meta: {
60-
tags: ["b", "a"], // Array order preserved
61-
info: { y: 2, x: 1 } // Object keys sorted
62-
}
63-
};
64-
expect(stableStringify(obj)).toBe('{"id":1,"meta":{"info":{"x":1,"y":2},"tags":["b","a"]}}');
65-
});
55+
it("should handle mixed complex structures", () => {
56+
const obj = {
57+
id: 1,
58+
meta: {
59+
tags: ["b", "a"], // Array order preserved
60+
info: { y: 2, x: 1 }, // Object keys sorted
61+
},
62+
};
63+
expect(stableStringify(obj)).toBe('{"id":1,"meta":{"info":{"x":1,"y":2},"tags":["b","a"]}}');
64+
});
6665
});
6766

6867
import { sha256Hash } from "../../src/lib/crypto.js";
6968
import { ValidationError } from "../../src/core/errors.js";
7069

7170
describe("sha256Hash", () => {
72-
it("should throw ValidationError for undefined input", async () => {
73-
await expect(sha256Hash(undefined)).rejects.toThrow(ValidationError);
74-
await expect(sha256Hash(undefined)).rejects.toThrow(/Content illegal: not serializable/);
75-
});
71+
it("should throw ValidationError for undefined input", async () => {
72+
await expect(sha256Hash(undefined)).rejects.toThrow(ValidationError);
73+
await expect(sha256Hash(undefined)).rejects.toThrow(/Content illegal: not serializable/);
74+
});
7675

77-
it("should throw ValidationError for function input", async () => {
78-
const func = () => { };
79-
await expect(sha256Hash(func)).rejects.toThrow(ValidationError);
80-
await expect(sha256Hash(func)).rejects.toThrow(/Content illegal: not serializable/);
81-
});
76+
it("should throw ValidationError for function input", async () => {
77+
const func = () => {};
78+
await expect(sha256Hash(func)).rejects.toThrow(ValidationError);
79+
await expect(sha256Hash(func)).rejects.toThrow(/Content illegal: not serializable/);
80+
});
8281
});

0 commit comments

Comments
 (0)