From 17d996820738a94c342106e4bd31a6a137bf8def Mon Sep 17 00:00:00 2001 From: toothlessdev Date: Thu, 22 Jan 2026 02:01:21 +0900 Subject: [PATCH 1/9] =?UTF-8?q?feature:=20sha256=20=ED=95=B4=EC=8B=9C=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=B0=8F=20stableStringify=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/utils/__tests__/stableStringify.test.ts | 17 +++++++++++++++++ packages/patchlogr-core/src/utils/createHash.ts | 5 +++++ .../patchlogr-core/src/utils/stableStringify.ts | 3 +++ 3 files changed, 25 insertions(+) create mode 100644 packages/patchlogr-core/src/utils/__tests__/stableStringify.test.ts create mode 100644 packages/patchlogr-core/src/utils/createHash.ts create mode 100644 packages/patchlogr-core/src/utils/stableStringify.ts diff --git a/packages/patchlogr-core/src/utils/__tests__/stableStringify.test.ts b/packages/patchlogr-core/src/utils/__tests__/stableStringify.test.ts new file mode 100644 index 0000000..9703db0 --- /dev/null +++ b/packages/patchlogr-core/src/utils/__tests__/stableStringify.test.ts @@ -0,0 +1,17 @@ +import { describe, test, expect } from "vitest"; +import { stableStringify } from "../stableStringify"; + +describe("stableStringify", () => { + test("should stringify json", () => { + expect(stableStringify({ a: 1, b: 2, c: 3 })).toBe( + '{"a":1,"b":2,"c":3}', + ); + }); + + test("should stringify json in a stable order", () => { + const obj1 = { a: 1, b: 2 }; + const obj2 = { b: 2, a: 1 }; + + expect(stableStringify(obj1)).toBe(stableStringify(obj2)); + }); +}); diff --git a/packages/patchlogr-core/src/utils/createHash.ts b/packages/patchlogr-core/src/utils/createHash.ts new file mode 100644 index 0000000..ad7e27b --- /dev/null +++ b/packages/patchlogr-core/src/utils/createHash.ts @@ -0,0 +1,5 @@ +import crypto from "crypto"; + +export function createSHA256Hash(data: string) { + return crypto.createHash("sha256").update(data).digest("hex"); +} diff --git a/packages/patchlogr-core/src/utils/stableStringify.ts b/packages/patchlogr-core/src/utils/stableStringify.ts new file mode 100644 index 0000000..0268d09 --- /dev/null +++ b/packages/patchlogr-core/src/utils/stableStringify.ts @@ -0,0 +1,3 @@ +export function stableStringify(obj: Record) { + return JSON.stringify(obj, Object.keys(obj).sort()); +} From 59e05228320b78ee3ff25ca62f2f548f3ba3d193 Mon Sep 17 00:00:00 2001 From: toothlessdev Date: Thu, 22 Jan 2026 02:01:38 +0900 Subject: [PATCH 2/9] =?UTF-8?q?chore:=20@types/node=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/patchlogr-core/package.json | 2 +- yarn.lock | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/patchlogr-core/package.json b/packages/patchlogr-core/package.json index f3278a9..3e59ca5 100644 --- a/packages/patchlogr-core/package.json +++ b/packages/patchlogr-core/package.json @@ -4,7 +4,6 @@ "publishConfig": { "access": "public" }, - "type": "module", "main": "./dist/index.cjs", "module": "./dist/index.js", "types": "./dist/index.d.ts", @@ -31,6 +30,7 @@ "@patchlogr/types": "workspace:^" }, "devDependencies": { + "@types/node": "^25.0.9", "esbuild": "^0.27.2", "openapi-types": "^12.1.3", "typescript": "^5.9.3", diff --git a/yarn.lock b/yarn.lock index 3f3c5a7..84eb7f6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -424,6 +424,7 @@ __metadata: "@apidevtools/swagger-parser": "npm:^12.1.0" "@patchlogr/oas": "workspace:^" "@patchlogr/types": "workspace:^" + "@types/node": "npm:^25.0.9" esbuild: "npm:^0.27.2" openapi-types: "npm:^12.1.3" typescript: "npm:^5.9.3" From 84b7030a7c3f1786fd52fe68c04f46eae4aa13c2 Mon Sep 17 00:00:00 2001 From: toothlessdev Date: Thu, 22 Jan 2026 02:01:57 +0900 Subject: [PATCH 3/9] =?UTF-8?q?feature:=20tag[0]=20=EA=B8=B0=EB=B0=98=20?= =?UTF-8?q?=ED=8C=8C=ED=8B=B0=EC=85=94=EB=8B=9D=20=EC=A0=84=EB=9E=B5=20?= =?UTF-8?q?=EB=8F=84=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__tests__/partitionByTag.test.ts | 69 +++++++++++++++++++ .../patchlogr-core/src/partition/partition.ts | 14 ++++ .../src/partition/partitionByTag.ts | 28 ++++++++ 3 files changed, 111 insertions(+) create mode 100644 packages/patchlogr-core/src/partition/__tests__/partitionByTag.test.ts create mode 100644 packages/patchlogr-core/src/partition/partition.ts create mode 100644 packages/patchlogr-core/src/partition/partitionByTag.ts diff --git a/packages/patchlogr-core/src/partition/__tests__/partitionByTag.test.ts b/packages/patchlogr-core/src/partition/__tests__/partitionByTag.test.ts new file mode 100644 index 0000000..4d35880 --- /dev/null +++ b/packages/patchlogr-core/src/partition/__tests__/partitionByTag.test.ts @@ -0,0 +1,69 @@ +import type { CanonicalSpec } from "@patchlogr/types"; +import { describe, expect, test } from "vitest"; +import { partitionByTag } from "../partitionByTag"; + +describe("partitionByTag", () => { + test("should group by first tag", () => { + const spec: CanonicalSpec = { + operations: { + "GET /user": { + key: "GET /user", + doc: { tags: ["user"] }, + method: "GET", + path: "/user", + request: { params: [] }, + responses: {}, + }, + "GET /user/{userId}": { + key: "GET /user/{userId}", + doc: { tags: ["user"] }, + method: "GET", + path: "/user/{userId}", + request: { params: [] }, + responses: {}, + }, + }, + }; + + const partitions = partitionByTag(spec).partitions; + expect(partitions).toHaveLength(1); + expect(partitions.get("user")).toHaveLength(2); + expect(partitions.get("user")?.[0]?.operationKey).toBe("GET /user"); + expect(partitions.get("user")?.[1]?.operationKey).toBe( + "GET /user/{userId}", + ); + }); + + test("should group by multiple tags", () => { + const spec: CanonicalSpec = { + operations: { + "GET /user": { + key: "GET /user", + doc: { tags: ["user"] }, + method: "GET", + path: "/user", + request: { params: [] }, + responses: {}, + }, + "POST /auth/login": { + key: "POST /auth/login", + doc: { tags: ["auth"] }, + method: "POST", + path: "/auth/login", + request: { params: [] }, + responses: {}, + }, + }, + }; + + const partitions = partitionByTag(spec).partitions; + + expect(partitions).toHaveLength(2); + expect(partitions.get("user")).toHaveLength(1); + expect(partitions.get("auth")).toHaveLength(1); + expect(partitions.get("user")?.[0]?.operationKey).toBe("GET /user"); + expect(partitions.get("auth")?.[0]?.operationKey).toBe( + "POST /auth/login", + ); + }); +}); diff --git a/packages/patchlogr-core/src/partition/partition.ts b/packages/patchlogr-core/src/partition/partition.ts new file mode 100644 index 0000000..42b2b03 --- /dev/null +++ b/packages/patchlogr-core/src/partition/partition.ts @@ -0,0 +1,14 @@ +export type PartitionManifest = { + key: string; + hash: string; +}; + +export type Partition = { + hash: string; + operationKey: string; +}; + +export type PartitionedSpec = { + metadata: Record; + partitions: Map; +}; diff --git a/packages/patchlogr-core/src/partition/partitionByTag.ts b/packages/patchlogr-core/src/partition/partitionByTag.ts new file mode 100644 index 0000000..864875e --- /dev/null +++ b/packages/patchlogr-core/src/partition/partitionByTag.ts @@ -0,0 +1,28 @@ +import type { CanonicalSpec } from "@patchlogr/types"; +import type { Partition, PartitionedSpec } from "./partition"; + +import { createSHA256Hash } from "../utils/createHash"; +import { stableStringify } from "../utils/stableStringify"; + +const DEFAULT_TAG = "__DEFAULT__"; + +export function partitionByTag(spec: CanonicalSpec): PartitionedSpec { + const partitions = new Map(); + + Object.entries(spec.operations).forEach(([key, operation]) => { + const tag = operation.doc?.tags?.[0] || DEFAULT_TAG; + const hash = createSHA256Hash(stableStringify(operation)); + + if (!partitions.has(tag)) + partitions.set(tag, [{ hash, operationKey: key }]); + else partitions.get(tag)?.push({ hash, operationKey: key }); + }); + + return { + metadata: { + ...spec.info, + ...spec.security, + }, + partitions, + }; +} From d9d894853a2c25700215f53c8892c84a3c0e01ed Mon Sep 17 00:00:00 2001 From: toothlessdev Date: Thu, 22 Jan 2026 02:11:44 +0900 Subject: [PATCH 4/9] =?UTF-8?q?feature:=20HttpMethod=20=EA=B8=B0=EB=B0=98?= =?UTF-8?q?=20=ED=8C=8C=ED=8B=B0=EC=85=94=EB=8B=9D=20=EC=A0=84=EB=9E=B5=20?= =?UTF-8?q?=EB=8F=84=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__tests__/partitionByMethod.test.ts | 69 +++++++++++++++++++ .../src/partition/partitionByMethod.ts | 26 +++++++ 2 files changed, 95 insertions(+) create mode 100644 packages/patchlogr-core/src/partition/__tests__/partitionByMethod.test.ts create mode 100644 packages/patchlogr-core/src/partition/partitionByMethod.ts diff --git a/packages/patchlogr-core/src/partition/__tests__/partitionByMethod.test.ts b/packages/patchlogr-core/src/partition/__tests__/partitionByMethod.test.ts new file mode 100644 index 0000000..b352499 --- /dev/null +++ b/packages/patchlogr-core/src/partition/__tests__/partitionByMethod.test.ts @@ -0,0 +1,69 @@ +import type { CanonicalSpec } from "@patchlogr/types"; +import { describe, expect, test } from "vitest"; +import { partitionByMethod } from "../partitionByMethod"; + +describe("partitionByMethod", () => { + test("should group by first tag", () => { + const spec: CanonicalSpec = { + operations: { + "GET /user": { + key: "GET /user", + doc: { tags: ["user"] }, + method: "GET", + path: "/user", + request: { params: [] }, + responses: {}, + }, + "GET /user/{userId}": { + key: "GET /user/{userId}", + doc: { tags: ["user"] }, + method: "GET", + path: "/user/{userId}", + request: { params: [] }, + responses: {}, + }, + }, + }; + + const partitions = partitionByMethod(spec).partitions; + expect(partitions).toHaveLength(1); + expect(partitions.get("GET")).toHaveLength(2); + expect(partitions.get("GET")?.[0]?.operationKey).toBe("GET /user"); + expect(partitions.get("GET")?.[1]?.operationKey).toBe( + "GET /user/{userId}", + ); + }); + + test("should group by multiple tags", () => { + const spec: CanonicalSpec = { + operations: { + "GET /user": { + key: "GET /user", + doc: { tags: ["user"] }, + method: "GET", + path: "/user", + request: { params: [] }, + responses: {}, + }, + "POST /auth/login": { + key: "POST /auth/login", + doc: { tags: ["auth"] }, + method: "POST", + path: "/auth/login", + request: { params: [] }, + responses: {}, + }, + }, + }; + + const partitions = partitionByMethod(spec).partitions; + + expect(partitions).toHaveLength(2); + expect(partitions.get("GET")).toHaveLength(1); + expect(partitions.get("POST")).toHaveLength(1); + expect(partitions.get("GET")?.[0]?.operationKey).toBe("GET /user"); + expect(partitions.get("POST")?.[0]?.operationKey).toBe( + "POST /auth/login", + ); + }); +}); diff --git a/packages/patchlogr-core/src/partition/partitionByMethod.ts b/packages/patchlogr-core/src/partition/partitionByMethod.ts new file mode 100644 index 0000000..67524f6 --- /dev/null +++ b/packages/patchlogr-core/src/partition/partitionByMethod.ts @@ -0,0 +1,26 @@ +import type { CanonicalSpec, HTTPMethod } from "@patchlogr/types"; +import type { Partition, PartitionedSpec } from "./partition"; + +import { createSHA256Hash } from "../utils/createHash"; +import { stableStringify } from "../utils/stableStringify"; + +export function partitionByMethod(spec: CanonicalSpec): PartitionedSpec { + const partitions = new Map(); + + Object.entries(spec.operations).forEach(([key, operation]) => { + const hash = createSHA256Hash(stableStringify(operation)); + + if (!partitions.has(operation.method)) + partitions.set(operation.method, [{ hash, operationKey: key }]); + else + partitions.get(operation.method)?.push({ hash, operationKey: key }); + }); + + return { + metadata: { + ...spec.info, + ...spec.security, + }, + partitions, + }; +} From 0ab4958c5bc4e125f6ba073df7b5f07380c96384 Mon Sep 17 00:00:00 2001 From: toothlessdev Date: Thu, 22 Jan 2026 02:21:44 +0900 Subject: [PATCH 5/9] =?UTF-8?q?fix:=20=EC=A4=91=EC=B2=A9=EB=90=9C=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=20=EB=B0=8F=20=EB=B0=B0=EC=97=B4=EB=8F=84=20?= =?UTF-8?q?=EC=A0=95=EB=A0=AC=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/utils/stableStringify.ts | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/patchlogr-core/src/utils/stableStringify.ts b/packages/patchlogr-core/src/utils/stableStringify.ts index 0268d09..f9143b3 100644 --- a/packages/patchlogr-core/src/utils/stableStringify.ts +++ b/packages/patchlogr-core/src/utils/stableStringify.ts @@ -1,3 +1,26 @@ -export function stableStringify(obj: Record) { - return JSON.stringify(obj, Object.keys(obj).sort()); +export function stableStringify(obj: Record): string { + return JSON.stringify(sortObjectKeys(obj)); +} + +function sortObjectKeys(value: unknown): unknown { + if (value === null || value === undefined) { + return value; + } + + if (Array.isArray(value)) { + return value.map(sortObjectKeys); + } + + if (typeof value === "object") { + const sortedObj: Record = {}; + const keys = Object.keys(value).sort(); + + for (const key of keys) { + sortedObj[key] = sortObjectKeys(value[key]); + } + + return sortedObj; + } + + return value; } From 5c0899202154632bd841641e46834071a4dd05ae Mon Sep 17 00:00:00 2001 From: toothlessdev Date: Thu, 22 Jan 2026 02:22:17 +0900 Subject: [PATCH 6/9] =?UTF-8?q?test:=20=EB=AC=B8=EC=9E=90=EC=97=B4=20?= =?UTF-8?q?=EB=8C=80=EC=8B=A0=20JSON.stringify=20=EA=B2=B0=EA=B3=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=8C=80=EC=B2=B4=ED=95=98=EC=97=AC=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EA=B0=80=EB=8F=85=EC=84=B1=20=ED=96=A5?= =?UTF-8?q?=EC=83=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../utils/__tests__/stableStringify.test.ts | 99 ++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/packages/patchlogr-core/src/utils/__tests__/stableStringify.test.ts b/packages/patchlogr-core/src/utils/__tests__/stableStringify.test.ts index 9703db0..1395438 100644 --- a/packages/patchlogr-core/src/utils/__tests__/stableStringify.test.ts +++ b/packages/patchlogr-core/src/utils/__tests__/stableStringify.test.ts @@ -4,7 +4,7 @@ import { stableStringify } from "../stableStringify"; describe("stableStringify", () => { test("should stringify json", () => { expect(stableStringify({ a: 1, b: 2, c: 3 })).toBe( - '{"a":1,"b":2,"c":3}', + JSON.stringify({ a: 1, b: 2, c: 3 }), ); }); @@ -14,4 +14,101 @@ describe("stableStringify", () => { expect(stableStringify(obj1)).toBe(stableStringify(obj2)); }); + + test("should stringify nested objects with stable key order", () => { + const obj1 = { a: 1, nested: { x: 10, y: 20 } }; + const obj2 = { nested: { y: 20, x: 10 }, a: 1 }; + + expect(stableStringify(obj1)).toBe(stableStringify(obj2)); + }); + + test("should stringify deeply nested objects with stable key order", () => { + const obj1 = { + level1: { + level2: { + c: 3, + b: 2, + a: 1, + }, + }, + }; + const obj2 = { + level1: { + level2: { + a: 1, + b: 2, + c: 3, + }, + }, + }; + + expect(stableStringify(obj1)).toBe(stableStringify(obj2)); + }); + + test("should stringify arrays containing objects with stable key order", () => { + const obj1 = { + items: [ + { z: 3, y: 2, x: 1 }, + { c: "c", b: "b", a: "a" }, + ], + }; + const obj2 = { + items: [ + { x: 1, y: 2, z: 3 }, + { a: "a", b: "b", c: "c" }, + ], + }; + + expect(stableStringify(obj1)).toBe(stableStringify(obj2)); + }); + + test("should handle null and primitive values correctly", () => { + const obj1 = { b: null, a: 1, c: "string", d: true }; + const obj2 = { d: true, c: "string", a: 1, b: null }; + + expect(stableStringify(obj1)).toBe(stableStringify(obj2)); + }); + + test("should produce deterministic output for canonical spec hashing", () => { + const spec1 = { + operationId: "getUser", + responses: { + "200": { + schema: { + type: "object", + properties: { name: {}, id: {} }, + }, + }, + }, + parameters: [{ name: "id", in: "path", required: true }], + }; + const spec2 = { + parameters: [{ required: true, in: "path", name: "id" }], + responses: { + "200": { + schema: { + properties: { id: {}, name: {} }, + type: "object", + }, + }, + }, + operationId: "getUser", + }; + + expect(stableStringify(spec1)).toBe(stableStringify(spec2)); + }); + + test("should output nested object keys in sorted order", () => { + const obj = { b: 2, a: { z: 1, y: 2 } }; + const result = stableStringify(obj); + + expect(result).toBe(JSON.stringify({ a: { y: 2, z: 1 }, b: 2 })); + }); + + test("should sort keys in arrays of objects", () => { + const obj = { items: [{ b: 1, a: 2 }] }; + const result = stableStringify(obj); + + expect(result).toBe(JSON.stringify({ items: [{ a: 2, b: 1 }] })); + }); }); From ff37785071d9245b50f3f765c0a78e9cd7fb959e Mon Sep 17 00:00:00 2001 From: toothlessdev Date: Thu, 22 Jan 2026 02:22:53 +0900 Subject: [PATCH 7/9] =?UTF-8?q?test:=20=EC=9E=98=EB=AA=BB=EB=90=9C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/partition/__tests__/partitionByMethod.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/patchlogr-core/src/partition/__tests__/partitionByMethod.test.ts b/packages/patchlogr-core/src/partition/__tests__/partitionByMethod.test.ts index b352499..294ebba 100644 --- a/packages/patchlogr-core/src/partition/__tests__/partitionByMethod.test.ts +++ b/packages/patchlogr-core/src/partition/__tests__/partitionByMethod.test.ts @@ -3,7 +3,7 @@ import { describe, expect, test } from "vitest"; import { partitionByMethod } from "../partitionByMethod"; describe("partitionByMethod", () => { - test("should group by first tag", () => { + test("should group by HTTPMethod", () => { const spec: CanonicalSpec = { operations: { "GET /user": { @@ -34,7 +34,7 @@ describe("partitionByMethod", () => { ); }); - test("should group by multiple tags", () => { + test("should group by multiple HTTPMethods", () => { const spec: CanonicalSpec = { operations: { "GET /user": { From f3bffb188e7fd606dadba0f0ef429500f1c34d74 Mon Sep 17 00:00:00 2001 From: toothlessdev Date: Thu, 22 Jan 2026 02:25:11 +0900 Subject: [PATCH 8/9] =?UTF-8?q?test:=20tag=20=EA=B0=80=20=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=EC=83=81=ED=99=A9=EC=9D=BC=EB=95=8C=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__tests__/partitionByTag.test.ts | 25 ++++++++++++++++++- .../src/partition/partitionByTag.ts | 2 +- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/patchlogr-core/src/partition/__tests__/partitionByTag.test.ts b/packages/patchlogr-core/src/partition/__tests__/partitionByTag.test.ts index 4d35880..d546346 100644 --- a/packages/patchlogr-core/src/partition/__tests__/partitionByTag.test.ts +++ b/packages/patchlogr-core/src/partition/__tests__/partitionByTag.test.ts @@ -1,6 +1,6 @@ import type { CanonicalSpec } from "@patchlogr/types"; import { describe, expect, test } from "vitest"; -import { partitionByTag } from "../partitionByTag"; +import { DEFAULT_TAG, partitionByTag } from "../partitionByTag"; describe("partitionByTag", () => { test("should group by first tag", () => { @@ -66,4 +66,27 @@ describe("partitionByTag", () => { "POST /auth/login", ); }); + + test("should group into default tag if tag not exists", () => { + const spec: CanonicalSpec = { + operations: { + "GET /user": { + key: "GET /user", + doc: { tags: [] }, + method: "GET", + path: "/user", + request: { params: [] }, + responses: {}, + }, + }, + }; + + const partitions = partitionByTag(spec).partitions; + + expect(partitions).toHaveLength(1); + expect(partitions.get(DEFAULT_TAG)).toHaveLength(1); + expect(partitions.get(DEFAULT_TAG)?.[0]?.operationKey).toBe( + "GET /user", + ); + }); }); diff --git a/packages/patchlogr-core/src/partition/partitionByTag.ts b/packages/patchlogr-core/src/partition/partitionByTag.ts index 864875e..da5c6b4 100644 --- a/packages/patchlogr-core/src/partition/partitionByTag.ts +++ b/packages/patchlogr-core/src/partition/partitionByTag.ts @@ -4,7 +4,7 @@ import type { Partition, PartitionedSpec } from "./partition"; import { createSHA256Hash } from "../utils/createHash"; import { stableStringify } from "../utils/stableStringify"; -const DEFAULT_TAG = "__DEFAULT__"; +export const DEFAULT_TAG = "__DEFAULT__"; export function partitionByTag(spec: CanonicalSpec): PartitionedSpec { const partitions = new Map(); From dc6ab814b38fb792779d714fbdaf2f2e923545ba Mon Sep 17 00:00:00 2001 From: toothlessdev Date: Thu, 22 Jan 2026 02:27:16 +0900 Subject: [PATCH 9/9] =?UTF-8?q?test:=20sha256=20=ED=95=B4=EC=8B=B1?= =?UTF-8?q?=EC=97=90=20=EB=8C=80=ED=95=9C=20deterministic=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/utils/__tests__/createHash.test.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 packages/patchlogr-core/src/utils/__tests__/createHash.test.ts diff --git a/packages/patchlogr-core/src/utils/__tests__/createHash.test.ts b/packages/patchlogr-core/src/utils/__tests__/createHash.test.ts new file mode 100644 index 0000000..de4fa42 --- /dev/null +++ b/packages/patchlogr-core/src/utils/__tests__/createHash.test.ts @@ -0,0 +1,11 @@ +import { describe, test, expect } from "vitest"; +import { createSHA256Hash } from "../createHash"; + +describe("createHash", () => { + describe("createSHA256Hash", () => { + test("sha256 must be deterministic", () => { + const hash = createSHA256Hash("test"); + expect(hash).toBe(createSHA256Hash("test")); + }); + }); +});