From 5f6277f9f318c6a475b13308cd8feb15aaf39a87 Mon Sep 17 00:00:00 2001 From: EmberIsReal Date: Sun, 2 Nov 2025 09:05:22 +0300 Subject: [PATCH 01/12] chore: fix typo in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ffcf18f..848ff26 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ The library is type-safe, supports immutable flag operations, and provides human npm install bitwise-flag # npm yarn add bitwise-flag # yarn pnpm add bitwise-flag # pnpm -ban add bitwise-flag # bun +bun add bitwise-flag # bun ``` --- From e501c83f1aeeab0b3a672bbf755eab3237a8b369 Mon Sep 17 00:00:00 2001 From: EmberIsReal Date: Sun, 2 Nov 2025 10:52:58 +0300 Subject: [PATCH 02/12] tests: add unit tests --- lib/Flag.test.ts | 192 +++++++++++++++++++++++++++++++++++++++ lib/FlagRegistry.test.ts | 155 +++++++++++++++++++++++++++++++ package.json | 3 +- tsconfig.json | 5 +- 4 files changed, 353 insertions(+), 2 deletions(-) create mode 100644 lib/Flag.test.ts create mode 100644 lib/FlagRegistry.test.ts diff --git a/lib/Flag.test.ts b/lib/Flag.test.ts new file mode 100644 index 0000000..51c9440 --- /dev/null +++ b/lib/Flag.test.ts @@ -0,0 +1,192 @@ +import { describe, expect, it } from "bun:test"; + +import { Flag } from "./Flag"; +import { FlagsRegistry } from "./FlagRegistry"; + +describe("Flag", () => { + const flagKeys = [ + "__FLAG_A__", // 1 bit + "__FLAG_B__", // 2 bits + "__FLAG_C__", // 4 bits + "__FLAG_D__", // 8 bits + ] as const; + const registry = FlagsRegistry.from(...flagKeys); + + describe("constructor()", () => { + it("should create flag with valid value", () => { + // __FLAG_A__ | __FLAG_D__ = 1 | 8 = 9 + const flag = new Flag(registry, 9n); + + expect(flag.value).toBe(9n); + }); + + it("should throw error for negative value", () => { + expect(() => { + new Flag(registry, -1n); + }).toThrow("Flag value cannot be negative: -1"); + }); + + it("should throw error for value with unknown flags", () => { + // only defined flags or theirs combinations + + expect(() => { + new Flag(registry, 16n); + }).toThrow("Flag value contains unknown flags"); + }); + }); + + describe("isEmpty()", () => { + it("should return true for empty flag", () => { + const emptyFlag = registry.empty(); + + expect(emptyFlag.isEmpty()).toBeTrue(); + }); + + it("should return false for non-empty flag", () => { + const nonEmptyFlag = registry.combine("__FLAG_A__", "__FLAG_C__"); + + expect(nonEmptyFlag.isEmpty()).toBeFalse(); + }); + }); + + describe("has()", () => { + const flagAD = registry.combine("__FLAG_A__", "__FLAG_D__"); + + it("should return true for set flags", () => { + expect(flagAD.has("__FLAG_A__")).toBeTrue(); + expect(flagAD.has("__FLAG_D__")).toBeTrue(); + }); + + it("should return false for unset flags", () => { + expect(flagAD.has("__FLAG_B__")).toBeFalse(); + expect(flagAD.has("__FLAG_C__")).toBeFalse(); + }); + + it("should return false for non-existent flag", () => { + // @ts-expect-error this flag is not exist + expect(flagAD.has("__NON_EXISTENT_FLAG__")).toBeFalse(); + }); + }); + + describe("add()", () => { + const flagB = registry.combine("__FLAG_B__"); + + it("should add flag to existing combination", () => { + const flagAB = flagB.add("__FLAG_A__"); + + expect(flagAB.value).toBe(3n); + expect(flagAB.has("__FLAG_A__")).toBeTrue(); + expect(flagAB.has("__FLAG_B__")).toBeTrue(); + }); + + it("should return same instance if flag already exists", () => { + const sameFlag = flagB.add("__FLAG_B__"); + + expect(flagB).toBe(sameFlag); + }); + + it("should throw error when adding non-existent flag", () => { + expect(() => { + // @ts-expect-error this flag is not exist + flagB.add("__NON_EXISTENT_FLAG__"); + }).toThrow("Flag with key __NON_EXISTENT_FLAG__ is not found."); + }); + + it("should be immutable - original flag unchanged", () => { + const originalValue = flagB.value; + flagB.add("__FLAG_C__"); + + expect(flagB.value).toBe(originalValue); + expect(flagB.has("__FLAG_C__")).toBeFalse(); + }); + }); + + describe("remove()", () => { + const flagBC = registry.combine("__FLAG_B__", "__FLAG_C__"); + + it("should remove flag from combination", () => { + const flagC = flagBC.remove("__FLAG_B__"); + + expect(flagC.value).toBe(4n); + expect(flagC.has("__FLAG_C__")).toBeTrue(); + expect(flagC.has("__FLAG_B__")).toBeFalse(); + }); + + it("should return same instance if flag not present", () => { + const sameFlag = flagBC.remove("__FLAG_D__"); + + expect(flagBC).toBe(sameFlag); + }); + + it("should throw error when removing non-existent flag", () => { + expect(() => { + // @ts-expect-error this flag is not exist + flagBC.remove("__NON_EXISTENT_FLAG__"); + }).toThrow("Flag with key __NON_EXISTENT_FLAG__ is not found."); + }); + + it("should be immutable - original flag unchanged", () => { + const originalValue = flagBC.value; + flagBC.remove("__FLAG_B__"); + + expect(flagBC.value).toBe(originalValue); + expect(flagBC.has("__FLAG_B__")).toBeTrue(); + }); + }); + + describe("toString()", () => { + it("should return correct string representation for empty flag", () => { + const emptyFlag = registry.empty(); + + expect(emptyFlag.toString()).toBe("Flag(EMPTY_FLAG: 0)"); + }); + + it("should return correct string representation for single flag", () => { + const flagA = registry.combine("__FLAG_A__"); + + expect(flagA.toString()).toBe("Flag([__FLAG_A__]: 1)"); + }); + + it("should return correct string representation for multiple flags", () => { + const flagAB = registry.combine("__FLAG_A__", "__FLAG_B__"); + + expect(flagAB.toString()).toBe("Flag([__FLAG_A__+__FLAG_B__]: 3)"); + }); + }); + + describe("alias", () => { + it("should return EMPTY_FLAG for empty flag", () => { + const emptyFlag = registry.empty(); + + expect(emptyFlag.alias).toBe("EMPTY_FLAG"); + }); + + it("should return formatted string for single flag", () => { + const flagA = registry.combine("__FLAG_A__"); + + expect(flagA.alias).toBe("[__FLAG_A__]"); + }); + + it("should return formatted string for multiple flags", () => { + const flagBD = registry.combine("__FLAG_B__", "__FLAG_D__"); + + expect(flagBD.alias).toBe("[__FLAG_B__+__FLAG_D__]"); + }); + + it("should cache the alias value", () => { + const flagACD = registry.combine( + "__FLAG_A__", + "__FLAG_C__", + "__FLAG_D__" + ); + + // @ts-expect-error access to a private field, before caching + expect(flagACD._alias).toBeNull(); + + flagACD.alias; + + // @ts-expect-error access to a private field, after caching + expect(flagACD._alias).toBe(flagACD.alias); + }); + }); +}); diff --git a/lib/FlagRegistry.test.ts b/lib/FlagRegistry.test.ts new file mode 100644 index 0000000..e780c63 --- /dev/null +++ b/lib/FlagRegistry.test.ts @@ -0,0 +1,155 @@ +import { beforeEach, describe, expect, it } from "bun:test"; + +import { FlagsRegistry } from "./FlagRegistry"; + +describe("FlagRegistry", () => { + let registry: FlagsRegistry; + + const flagKeys = [ + "__FLAG_A__", // 1 bit + "__FLAG_B__", // 2 bits + "__FLAG_C__", // 4 bits + "__FLAG_D__", // 8 bits + ] as const; + + type FlagKeysArray = typeof flagKeys; + type FlagKeysType = FlagKeysArray[number]; + + beforeEach(() => { + registry = FlagsRegistry.from(...flagKeys); + }); + + it("should handle many flags without bit overflow", () => { + const manyFlags = Array.from({ length: 100 }, (_, i) => `__FLAG_${i}__`); + const registry = FlagsRegistry.from(...manyFlags); + + // should be able to combine all flags + const allFlags = registry.combine(...manyFlags); + + // each flag should be set + manyFlags.forEach((flag) => { + expect(allFlags.has(flag)).toBe(true); + }); + }); + + it("should work with empty registry", () => { + const emptyRegistry = FlagsRegistry.from(); + + expect(Array.from(emptyRegistry.keys())).toEqual([]); + expect(emptyRegistry.empty().isEmpty()).toBe(true); + + // combining no flags should work + const emptyFlag = emptyRegistry.combine(); + expect(emptyFlag.isEmpty()).toBe(true); + }); + + describe("static from()", () => { + it("should create registry with unique flags", () => { + const registry = FlagsRegistry.from("A", "B", "C", "A"); + const keys = Array.from(registry.keys()); + + expect(keys).toEqual(["A", "B", "C"]); + }); + + it("should assign correct bit values to flags", () => { + const registry = FlagsRegistry.from( + "__FLAG_1__", + "__FLAG_2__", + "__FLAG_3__" + ); + + expect(registry.get("__FLAG_1__")).toBe(1n); + expect(registry.get("__FLAG_2__")).toBe(2n); + expect(registry.get("__FLAG_3__")).toBe(4n); + }); + }); + + describe("get()", () => { + it("should return correct value for existing flag", () => { + expect(registry.get("__FLAG_A__")).toBe(1n); + expect(registry.get("__FLAG_B__")).toBe(2n); + expect(registry.get("__FLAG_C__")).toBe(4n); + expect(registry.get("__FLAG_D__")).toBe(8n); + }); + + it("should return undefined for non-existent flag", () => { + // @ts-expect-error this flag is not exist + expect(registry.get("__NON_EXISTENT_FLAG__")).toBeUndefined(); + }); + + it("should combine flags correctly", () => { + const emptyFlag = registry.combine(); + const flagA = registry.combine("__FLAG_A__"); + const flagBC = registry.combine("__FLAG_B__", "__FLAG_C__"); + const flagDAB = registry.combine( + "__FLAG_D__", + "__FLAG_A__", + "__FLAG_B__" + ); + const flagABCD = registry.combine( + "__FLAG_A__", + "__FLAG_B__", + "__FLAG_C__", + "__FLAG_D__" + ); + + expect(emptyFlag.value).toBe(0n); + expect(flagA.value).toBe(1n); + expect(flagBC.value).toBe(6n); + expect(flagDAB.value).toBe(11n); + expect(flagABCD.value).toBe(15n); + }); + + it("should throw error when combining non-existent flag", () => { + expect(() => { + registry.combine( + "__FLAG_A__", + "__FLAG_B__", + // @ts-expect-error this flag is not exist + "__NON_EXISTENT_FLAG__", + "__FLAG_D__" + ); + }).toThrow("Flag with key __NON_EXISTENT_FLAG__ is not found."); + }); + }); + + describe("empty()", () => { + it("should return empty flag", () => { + const emptyFlag = registry.empty(); + + expect(emptyFlag.value).toBe(0n); + expect(emptyFlag.isEmpty()).toBe(true); + }); + }); + + describe("iterators", () => { + describe("keys()", () => { + it("should return all flag names", () => { + const keys = Array.from(registry.keys()) as unknown as FlagKeysArray; + + expect(keys).toEqual(flagKeys); + }); + }); + + describe("values()", () => { + it("should return all flag values", () => { + const values = Array.from(registry.values()); + + expect(values).toEqual([1n, 2n, 4n, 8n]); + }); + }); + + describe("entries()", () => { + it("should return all key-value pairs", () => { + const entries = Array.from(registry.entries()); + + expect(entries).toEqual([ + ["__FLAG_A__", 1n], + ["__FLAG_B__", 2n], + ["__FLAG_C__", 4n], + ["__FLAG_D__", 8n], + ]); + }); + }); + }); +}); diff --git a/package.json b/package.json index 9270f61..e3eb3d4 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,8 @@ }, "author": "Ember", "scripts": { - "build": "bunup" + "build": "bunup", + "tests": "bun test" }, "devDependencies": { "@types/bun": "^1.3.1", diff --git a/tsconfig.json b/tsconfig.json index 1192eb8..bd24074 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,5 +22,8 @@ "noUnusedLocals": false, "noUnusedParameters": false, "noPropertyAccessFromIndexSignature": false, - } + }, + "exclude": [ + "./lib/**/*.test.ts" + ] } \ No newline at end of file From b285de091023154943a43584204c20052d6014b1 Mon Sep 17 00:00:00 2001 From: EmberIsReal Date: Sun, 2 Nov 2025 11:01:38 +0300 Subject: [PATCH 03/12] fix(Flag): change checking flag presence order --- lib/Flag.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Flag.ts b/lib/Flag.ts index 553eb10..1131e8b 100644 --- a/lib/Flag.ts +++ b/lib/Flag.ts @@ -51,14 +51,14 @@ export class Flag implements IFlag { } remove(flagName: TFlags): IFlag { - if (!this.has(flagName)) return this; - const value = this.context.get(flagName); if (!value) { throw new Error(`Flag with key ${String(flagName)} is not found.`); } + if (!this.has(flagName)) return this; + const extractedValue = this.value & ~value; return new Flag(this.context, extractedValue); From 7caf8de95921e827d10e2b3ada9ff63a6b00456a Mon Sep 17 00:00:00 2001 From: EmberIsReal Date: Sun, 2 Nov 2025 11:19:45 +0300 Subject: [PATCH 04/12] fix(FlagRegistry): change combine's return type --- lib/FlagRegistry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FlagRegistry.ts b/lib/FlagRegistry.ts index ee51e5c..184ff7c 100644 --- a/lib/FlagRegistry.ts +++ b/lib/FlagRegistry.ts @@ -39,7 +39,7 @@ export class FlagsRegistry return new Flag(this, 0n); } - combine(...flagKeys: TFlags[]): Flag { + combine(...flagKeys: TFlags[]): IFlag { const value = flagKeys.reduce((acc, key) => { const flagValue = this.get(key); From e643db70c87c8f0ca88f456de423bce0b493042a Mon Sep 17 00:00:00 2001 From: EmberIsReal Date: Sun, 2 Nov 2025 11:20:06 +0300 Subject: [PATCH 05/12] fix(IFlag): add alias property --- lib/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/types.ts b/lib/types.ts index b89f804..0bd30c5 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -2,6 +2,7 @@ export type FlagKey = string; export interface IFlag { readonly value: bigint; + readonly alias: string; isEmpty(): boolean; has(flagName: TFlags): boolean; From 4600b08d96bed40cec8098f14ba3f602ba7c8e93 Mon Sep 17 00:00:00 2001 From: EmberIsReal Date: Sun, 2 Nov 2025 11:21:24 +0300 Subject: [PATCH 06/12] chore: upgrade to 1.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e3eb3d4..91e0d65 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bitwise-flag", - "version": "1.0.0", + "version": "1.0.1", "type": "module", "license": "MIT", "files": [ From 2386fe88ff9c6b29d61e3b0764758ea87380c3ed Mon Sep 17 00:00:00 2001 From: EmberIsReal Date: Sun, 2 Nov 2025 14:56:08 +0300 Subject: [PATCH 07/12] feat(Flag): add bulk operations --- README.md | 4 ++-- lib/Flag.test.ts | 35 +++++++++++++++++++++++------------ lib/Flag.ts | 36 ++++++++++++++++++++++-------------- lib/types.ts | 4 ++-- 4 files changed, 49 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 848ff26..0f81c87 100644 --- a/README.md +++ b/README.md @@ -106,8 +106,8 @@ Represents a bitwise combination of flags from a registry. All operations are im |--------|-------------|------------|---------|--------| | `isEmpty()` | Checks if no flags are set. | None. | `boolean` | None. | | `has(flagName: TFlags)` | Tests if a specific flag is set in this combination. | `flagName`: The flag key. | `boolean` | None. | -| `add(flagName: TFlags)` | Adds a flag to the combination (idempotent if already set). Returns a new `Flag`. | `flagName`: The flag key. | `Flag` | `Error` if the key is not registered. | -| `remove(flagName: TFlags)` | Removes a flag from the combination (idempotent if not set). Returns a new `Flag`. | `flagName`: The flag key. | `Flag` | `Error` if the key is not registered. | +| `add(...flagNames: TFlags[])` | Adds flags to the combination (idempotent if already set). Returns `IFlag`. | `flagNames`: The flag keys. | `IFlag` | `Error` if the key is not registered. | +| `remove(...flagNames: TFlags[])` | Removes flags from the combination (idempotent if not set). Returns `IFlag`. | `flagNames`: The flag keys. | `IFlag` | `Error` if the key is not registered. | | `toString()` | Returns a string representation including the alias and raw value. | None. | `string` | None. | | `alias` (getter) | Computed human-readable alias (e.g., `"[READ+WRITE]"` or `"EMPTY_FLAG"`) | None. | `string` | None. | diff --git a/lib/Flag.test.ts b/lib/Flag.test.ts index 51c9440..43dcee6 100644 --- a/lib/Flag.test.ts +++ b/lib/Flag.test.ts @@ -79,6 +79,16 @@ describe("Flag", () => { expect(flagAB.has("__FLAG_B__")).toBeTrue(); }); + it("should add multiple flags to existing combination", () => { + const flagBCD = flagB.add("__FLAG_C__", "__FLAG_D__"); + + // __FLAG_B__ | __FLAG_C__ | __FLAG_D__ = 2 | 4 | 8 = 14 + expect(flagBCD.value).toBe(14n); + expect(flagBCD.has("__FLAG_B__")).toBeTrue(); + expect(flagBCD.has("__FLAG_C__")).toBeTrue(); + expect(flagBCD.has("__FLAG_D__")).toBeTrue(); + }); + it("should return same instance if flag already exists", () => { const sameFlag = flagB.add("__FLAG_B__"); @@ -102,35 +112,36 @@ describe("Flag", () => { }); describe("remove()", () => { - const flagBC = registry.combine("__FLAG_B__", "__FLAG_C__"); + const flagBCD = registry.combine("__FLAG_B__", "__FLAG_C__", "__FLAG_D__"); it("should remove flag from combination", () => { - const flagC = flagBC.remove("__FLAG_B__"); + const flagCD = flagBCD.remove("__FLAG_B__"); - expect(flagC.value).toBe(4n); - expect(flagC.has("__FLAG_C__")).toBeTrue(); - expect(flagC.has("__FLAG_B__")).toBeFalse(); + // __FLAG_C__ | __FLAG_D__ = 4 | 8 = 12 + expect(flagCD.value).toBe(12n); + expect(flagCD.has("__FLAG_C__")).toBeTrue(); + expect(flagCD.has("__FLAG_B__")).toBeFalse(); }); it("should return same instance if flag not present", () => { - const sameFlag = flagBC.remove("__FLAG_D__"); + const sameFlag = flagBCD.remove("__FLAG_A__"); - expect(flagBC).toBe(sameFlag); + expect(flagBCD).toBe(sameFlag); }); it("should throw error when removing non-existent flag", () => { expect(() => { // @ts-expect-error this flag is not exist - flagBC.remove("__NON_EXISTENT_FLAG__"); + flagBCD.remove("__NON_EXISTENT_FLAG__"); }).toThrow("Flag with key __NON_EXISTENT_FLAG__ is not found."); }); it("should be immutable - original flag unchanged", () => { - const originalValue = flagBC.value; - flagBC.remove("__FLAG_B__"); + const originalValue = flagBCD.value; + flagBCD.remove("__FLAG_B__"); - expect(flagBC.value).toBe(originalValue); - expect(flagBC.has("__FLAG_B__")).toBeTrue(); + expect(flagBCD.value).toBe(originalValue); + expect(flagBCD.has("__FLAG_B__")).toBeTrue(); }); }); diff --git a/lib/Flag.ts b/lib/Flag.ts index 1131e8b..32f872a 100644 --- a/lib/Flag.ts +++ b/lib/Flag.ts @@ -36,30 +36,38 @@ export class Flag implements IFlag { return !!(this.value & value); } - add(flagName: TFlags): IFlag { - if (this.has(flagName)) return this; + add(...flagNames: TFlags[]): IFlag { + const combinedValue = flagNames.reduce((acc, name) => { + if (this.has(name)) return acc; - const value = this.context.get(flagName); + const value = this.context.get(name); - if (!value) { - throw new Error(`Flag with key ${String(flagName)} is not found.`); - } + if (!value) { + throw new Error(`Flag with key ${String(name)} is not found.`); + } + + return acc | value; + }, this.value); - const combinedValue = this.value | value; + if (combinedValue === this.value) return this; return new Flag(this.context, combinedValue); } - remove(flagName: TFlags): IFlag { - const value = this.context.get(flagName); + remove(...flagNames: TFlags[]): IFlag { + const extractedValue = flagNames.reduce((acc, name) => { + const value = this.context.get(name); - if (!value) { - throw new Error(`Flag with key ${String(flagName)} is not found.`); - } + if (!value) { + throw new Error(`Flag with key ${String(name)} is not found.`); + } + + if (!this.has(name)) return acc; - if (!this.has(flagName)) return this; + return acc & ~value; + }, this.value); - const extractedValue = this.value & ~value; + if (extractedValue === this.value) return this; return new Flag(this.context, extractedValue); } diff --git a/lib/types.ts b/lib/types.ts index 0bd30c5..f711b7a 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -7,8 +7,8 @@ export interface IFlag { isEmpty(): boolean; has(flagName: TFlags): boolean; - add(flagName: TFlags): IFlag; - remove(flagName: TFlags): IFlag; + add(...flagNames: TFlags[]): IFlag; + remove(...flagNames: TFlags[]): IFlag; toString(): string; } From 47b2f6435f0ee727a8fca518fdfc92e5139e4c41 Mon Sep 17 00:00:00 2001 From: EmberIsReal Date: Mon, 3 Nov 2025 11:43:52 +0300 Subject: [PATCH 08/12] feat(FlagRegistry): add parse method --- lib/FlagRegistry.test.ts | 64 ++++++++++++++++++++++++++++++++++++++++ lib/FlagRegistry.ts | 17 +++++++++++ lib/types.ts | 4 +++ 3 files changed, 85 insertions(+) diff --git a/lib/FlagRegistry.test.ts b/lib/FlagRegistry.test.ts index e780c63..389d52d 100644 --- a/lib/FlagRegistry.test.ts +++ b/lib/FlagRegistry.test.ts @@ -122,6 +122,70 @@ describe("FlagRegistry", () => { }); }); + describe("parse", () => { + it("should parse number values", () => { + const flagA = registry.parse(1); // decimal + const flagCD = registry.parse(0b1100); // binary + const flagBC = registry.parse(0x6); // hex + const flagBCD = registry.parse(0o16); // octal + + expect(flagA.has("__FLAG_A__")).toBeTrue(); + + expect(flagCD.has("__FLAG_C__")).toBeTrue(); + expect(flagCD.has("__FLAG_D__")).toBeTrue(); + + expect(flagBC.has("__FLAG_B__")).toBeTrue(); + expect(flagBC.has("__FLAG_C__")).toBeTrue(); + + expect(flagBCD.has("__FLAG_B__")).toBeTrue(); + expect(flagBCD.has("__FLAG_C__")).toBeTrue(); + expect(flagBCD.has("__FLAG_D__")).toBeTrue(); + }); + + it("should parse bigint values", () => { + const flagA = registry.parse(1n); // decimal + const flagCD = registry.parse(0b1100n); // binary + const flagBC = registry.parse(0x6n); // hex + const flagBCD = registry.parse(0o16n); // octal + + expect(flagA.has("__FLAG_A__")).toBeTrue(); + + expect(flagCD.has("__FLAG_C__")).toBeTrue(); + expect(flagCD.has("__FLAG_D__")).toBeTrue(); + + expect(flagBC.has("__FLAG_B__")).toBeTrue(); + expect(flagBC.has("__FLAG_C__")).toBeTrue(); + + expect(flagBCD.has("__FLAG_B__")).toBeTrue(); + expect(flagBCD.has("__FLAG_C__")).toBeTrue(); + expect(flagBCD.has("__FLAG_D__")).toBeTrue(); + }); + + it("should parse string values", () => { + const flagA = registry.parse("1", 10); // decimal + const flagCD = registry.parse("1100", 2); // binary + const flagBC = registry.parse("6", 16); // hex + const flagBCD = registry.parse("16", 8); // octal + const flagACD = registry.parse("111", 3); // any other radix from 2 to 32 (ex.: ternary) + + expect(flagA.has("__FLAG_A__")).toBeTrue(); + + expect(flagCD.has("__FLAG_C__")).toBeTrue(); + expect(flagCD.has("__FLAG_D__")).toBeTrue(); + + expect(flagBC.has("__FLAG_B__")).toBeTrue(); + expect(flagBC.has("__FLAG_C__")).toBeTrue(); + + expect(flagBCD.has("__FLAG_B__")).toBeTrue(); + expect(flagBCD.has("__FLAG_C__")).toBeTrue(); + expect(flagBCD.has("__FLAG_D__")).toBeTrue(); + + expect(flagACD.has("__FLAG_A__")).toBeTrue(); + expect(flagACD.has("__FLAG_C__")).toBeTrue(); + expect(flagACD.has("__FLAG_D__")).toBeTrue(); + }); + }); + describe("iterators", () => { describe("keys()", () => { it("should return all flag names", () => { diff --git a/lib/FlagRegistry.ts b/lib/FlagRegistry.ts index 184ff7c..433d367 100644 --- a/lib/FlagRegistry.ts +++ b/lib/FlagRegistry.ts @@ -39,6 +39,23 @@ export class FlagsRegistry return new Flag(this, 0n); } + parse(value: number): IFlag; + parse(value: bigint): IFlag; + parse(value: string, radix?: number): IFlag; + parse(value: string | number | bigint, radix?: number): IFlag { + if (typeof value === "bigint") return new Flag(this, value); + + if (typeof value === "number") return new Flag(this, BigInt(value)); + + const parsedValue = parseInt(value, radix); + + if (isNaN(parsedValue)) { + throw new Error(`Cannot parse value ${value} with radix ${radix ?? 10}.`); + } + + return new Flag(this, BigInt(parsedValue)); + } + combine(...flagKeys: TFlags[]): IFlag { const value = flagKeys.reduce((acc, key) => { const flagValue = this.get(key); diff --git a/lib/types.ts b/lib/types.ts index f711b7a..1c39b4f 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -22,4 +22,8 @@ export interface IFlagsRegistry { entries(): MapIterator<[TFlags, bigint]>; empty(): IFlag; + + parse(value: number): IFlag; + parse(value: bigint): IFlag; + parse(value: string, radix?: number): IFlag; } From 94083218f0dae614673b11ddb59023a2871900af Mon Sep 17 00:00:00 2001 From: EmberIsReal Date: Mon, 3 Nov 2025 12:53:24 +0300 Subject: [PATCH 09/12] chore: update README.md for 1.1.0 --- README.md | 80 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 0f81c87..42443eb 100644 --- a/README.md +++ b/README.md @@ -16,39 +16,48 @@ bun add bitwise-flag # bun ``` --- + ### How to use + ```ts import { FlagsRegistry } from "bitwise-flag"; // create a flag registry const permissionRegistry = FlagsRegistry.from("READ", "WRITE", "EXECUTE"); -// create an empty flag +// create an empty flag const noPermissions = permissionRegistry.empty(); console.log(noPermissions.isEmpty()); // true console.log(noPermissions.toString()); // Flag(EMPTY_FLAG: 0) // combine flags to create a new flag -const readWrite = permissionsRegistry.combine('READ', 'WRITE'); +const readWrite = permissionsRegistry.combine("READ", "WRITE"); console.log(readWrite.toString()); // Flag([READ+WRITE]: 3) +// parse numeric values to create flags +const fromNumber = permissionRegistry.parse(5); // READ + EXECUTE +const fromHex = permissionRegistry.parse("3", 16); // READ + WRITE +const fromBinary = permissionRegistry.parse("101", 2); // READ + EXECUTE + // check for flags -const userPermissions = permissionsRegistry.combine('READ', 'EXECUTE'); +const userPermissions = permissionsRegistry.combine("READ", "EXECUTE"); -console.log(userPermissions.has('READ')); // true -console.log(userPermissions.has('WRITE')); // false -console.log(userPermissions.has('EXECUTE')); // true +console.log(userPermissions.has("READ")); // true +console.log(userPermissions.has("WRITE")); // false +console.log(userPermissions.has("EXECUTE")); // true ``` ### Flag opeations + Flag's instances are immutable. Thats means all operations return new instances. For example: + ```ts const readWrite = permissionsRegistry.combine("READ", "WRITE"); // add execute flag const fullPermissions = readWrite.add("EXECUTE"); console.log(readWrite.has("EXECUTE")); // false -console.log(fullPermissions.has("EXECUTE")) // true +console.log(fullPermissions.has("EXECUTE")); // true // remove read flag const read = readWrite.remove("WRITE"); @@ -56,7 +65,6 @@ console.log(readWrite.has("WRITE")); // true console.log(read.has("WRITE")); // false ``` - ## API Reference ### Class: `FlagsRegistry` @@ -65,29 +73,32 @@ Manages a collection of flag keys and their corresponding bitmask values. Use th #### Static Methods -| Method | Description | Parameters | Returns | Throws | -|--------|-------------|------------|---------|--------| -| `FlagsRegistry.from(...flagKeys: TFlags[])` | Creates a new registry instance from an array of flag keys. Automatically deduplicates keys and assigns sequential bit positions (starting from bit 0). | `flagKeys`: Array of string keys. | `FlagsRegistry` | None. | +| Method | Description | Parameters | Returns | Throws | +| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ----------------------- | ------ | +| `FlagsRegistry.from(...flagKeys: TFlags[])` | Creates a new registry instance from an array of flag keys. Automatically deduplicates keys and assigns sequential bit positions (starting from bit 0). | `flagKeys`: Array of string keys. | `FlagsRegistry` | None. | **Example:** + ```typescript -const registry = FlagsRegistry.from('READ', 'WRITE', 'READ'); // Deduplicates 'READ' +const registry = FlagsRegistry.from("READ", "WRITE", "READ"); // Deduplicates 'READ' ``` #### Instance Methods -| Method | Description | Parameters | Returns | Throws | -|--------|-------------|------------|---------|--------| -| `keys()` | Returns an iterator over all flag keys. | None. | `MapIterator` | None. | -| `values()` | Returns an iterator over all bit values. | None. | `MapIterator` | None. | -| `entries()` | Returns an iterator over key-bit pairs. | None. | `MapIterator<[TFlags, bigint]>` | None. | -| `get(flagName: TFlags)` | Retrieves the bitmask value for a specific flag key. | `flagName`: The flag key. | `bigint \| undefined` | None. | -| `empty()` | Creates an empty flag instance (value `0n`). | None. | `Flag` | None. | -| `combine(...flagKeys: TFlags[])` | Combines the specified flag keys into a new `Flag` instance by bitwise OR-ing their values. | `flagKeys`: Array of flag keys to combine. | `Flag` | `Error` if any key is not registered. | +| Method | Description | Parameters | Returns | Throws | +| ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------- | ---------------------------------------- | +| `keys()` | Returns an iterator over all flag keys. | None. | `MapIterator` | None. | +| `values()` | Returns an iterator over all bit values. | None. | `MapIterator` | None. | +| `entries()` | Returns an iterator over key-bit pairs. | None. | `MapIterator<[TFlags, bigint]>` | None. | +| `get(flagName: TFlags)` | Retrieves the bitmask value for a specific flag key. | `flagName`: The flag key. | `bigint \| undefined` | None. | +| `empty()` | Creates an empty flag instance (value `0n`). | None. | `IFlag` | None. | +| `parse(value: string \| number \| bigint, radix?: string)` | Creates a flag from a value. If value is string, do **NOT** use prefixes like: `0x` or `0b`, like in JS. | `value` - source value; `radix` - base of value. Use if `value` is string. By default, equals to 10. | `IFlag` | `Error` if string value can't be parsed. | +| `combine(...flagKeys: TFlags[])` | Combines the specified flag keys into a new `Flag` instance by bitwise OR-ing their values. | `flagKeys`: Array of flag keys to combine. | `IFlag` | `Error` if any key is not registered. | **Example:** + ```typescript -const combined = registry.combine('READ', 'WRITE'); // Value: 3n (0b11) +const combined = registry.combine("READ", "WRITE"); // Value: 3n (0b11) ``` ### Class: `Flag` @@ -96,26 +107,27 @@ Represents a bitwise combination of flags from a registry. All operations are im #### Properties -| Property | Description | Type | -|----------|-------------|------| -| `value` | The raw `BigInt` representing the combined bitmask. Read-only. | `bigint` | +| Property | Description | Type | +| -------- | -------------------------------------------------------------- | -------- | +| `value` | The raw `BigInt` representing the combined bitmask. Read-only. | `bigint` | #### Methods -| Method | Description | Parameters | Returns | Throws | -|--------|-------------|------------|---------|--------| -| `isEmpty()` | Checks if no flags are set. | None. | `boolean` | None. | -| `has(flagName: TFlags)` | Tests if a specific flag is set in this combination. | `flagName`: The flag key. | `boolean` | None. | -| `add(...flagNames: TFlags[])` | Adds flags to the combination (idempotent if already set). Returns `IFlag`. | `flagNames`: The flag keys. | `IFlag` | `Error` if the key is not registered. | +| Method | Description | Parameters | Returns | Throws | +| -------------------------------- | ---------------------------------------------------------------------------- | --------------------------- | --------------- | ------------------------------------- | +| `isEmpty()` | Checks if no flags are set. | None. | `boolean` | None. | +| `has(flagName: TFlags)` | Tests if a specific flag is set in this combination. | `flagName`: The flag key. | `boolean` | None. | +| `add(...flagNames: TFlags[])` | Adds flags to the combination (idempotent if already set). Returns `IFlag`. | `flagNames`: The flag keys. | `IFlag` | `Error` if the key is not registered. | | `remove(...flagNames: TFlags[])` | Removes flags from the combination (idempotent if not set). Returns `IFlag`. | `flagNames`: The flag keys. | `IFlag` | `Error` if the key is not registered. | -| `toString()` | Returns a string representation including the alias and raw value. | None. | `string` | None. | -| `alias` (getter) | Computed human-readable alias (e.g., `"[READ+WRITE]"` or `"EMPTY_FLAG"`) | None. | `string` | None. | +| `toString()` | Returns a string representation including the alias and raw value. | None. | `string` | None. | +| `alias` (getter) | Computed human-readable alias (e.g., `"[READ+WRITE]"` or `"EMPTY_FLAG"`) | None. | `string` | None. | **Validation Note:** The constructor (internal) validates that the value only uses known bits from the registry and is non-negative. Unknown bits or negative values throw an `Error`. **Example:** + ```typescript -const flag = registry.combine('READ'); -console.log(flag.has('READ')); // true -console.log(flag.add('WRITE').alias); // "[READ+WRITE]" +const flag = registry.combine("READ"); +console.log(flag.has("READ")); // true +console.log(flag.add("WRITE").alias); // "[READ+WRITE]" ``` From 615f0fc158b44799d0e057115cd5b51edd25c974 Mon Sep 17 00:00:00 2001 From: EmberIsReal Date: Mon, 3 Nov 2025 12:54:39 +0300 Subject: [PATCH 10/12] chore: set repository --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index 91e0d65..1b62063 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,10 @@ "./LICENSE.md", "dist" ], + "repository": { + "type": "git", + "url": "https://github.com/ThatsEmbarrassing/bitwise-flag" + }, "main": "./dist/index.cjs", "module": "./dist/index.js", "types": "./dist/index.d.ts", From d1ed4ecd57f32f34e3a6ae23477928a4b6d25ab5 Mon Sep 17 00:00:00 2001 From: EmberIsReal Date: Mon, 3 Nov 2025 12:55:02 +0300 Subject: [PATCH 11/12] chore: upgrade to 1.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1b62063..61a7a4c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bitwise-flag", - "version": "1.0.1", + "version": "1.1.0", "type": "module", "license": "MIT", "files": [ From b260d2562d3ab46487c7157098ff4d559c657c6b Mon Sep 17 00:00:00 2001 From: EmberIsReal Date: Mon, 3 Nov 2025 14:12:40 +0300 Subject: [PATCH 12/12] style: add eslint --- bun.lock | 246 +++++++++++++++++++++++++++++++++++++++++++++- eslint.config.mjs | 28 ++++++ package.json | 12 ++- 3 files changed, 282 insertions(+), 4 deletions(-) create mode 100644 eslint.config.mjs diff --git a/bun.lock b/bun.lock index 5cf0bcd..50307c2 100644 --- a/bun.lock +++ b/bun.lock @@ -4,11 +4,15 @@ "": { "name": "sandbox", "devDependencies": { + "@eslint/js": "^9.39.0", + "@stylistic/eslint-plugin": "^5.5.0", "@types/bun": "^1.3.1", "bunup": "^0.15.13", + "eslint": "^9.39.0", + "typescript-eslint": "^8.46.2", }, "peerDependencies": { - "typescript": "^5.0.0", + "typescript": "^5.9.3", }, }, }, @@ -31,8 +35,40 @@ "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="], + + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], + + "@eslint/config-array": ["@eslint/config-array@0.21.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA=="], + + "@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="], + + "@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="], + + "@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="], + + "@eslint/js": ["@eslint/js@9.39.0", "", {}, "sha512-BIhe0sW91JGPiaF1mOuPy5v8NflqfjIcDNpC+LbW9f609WVRX1rArrhi6Z2ymvrAry9jw+5POTj4t2t62o8Bmw=="], + + "@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], + + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="], + + "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], + + "@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="], + + "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], + + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.0.7", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@tybys/wasm-util": "^0.10.1" } }, "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw=="], + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + "@oxc-minify/binding-android-arm64": ["@oxc-minify/binding-android-arm64@0.93.0", "", { "os": "android", "cpu": "arm64" }, "sha512-N3j/JoK4hXwQbnyOJoEltM8MEkddWV3XtfYimO6jsMjr5R6QdauKaSVeQHO/lSezB7SFkrMPqr6X7tBfghHiXA=="], "@oxc-minify/binding-darwin-arm64": ["@oxc-minify/binding-darwin-arm64@0.93.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-kLJJe7uBE+a9ql6eLGAtJ1g1LuEXi4aHbsiu342wGe+wRieSPi/Cx0aeDsQjdetwK5mqJWjWS2FO/n03jiw+IQ=="], @@ -131,26 +167,156 @@ "@oxc-transform/binding-win32-x64-msvc": ["@oxc-transform/binding-win32-x64-msvc@0.93.0", "", { "os": "win32", "cpu": "x64" }, "sha512-6QN3DEaEw3eWioWEFRgNsTvYq8czYSnpkjB2za+/WdLN0g5FzOl2ZEfNiPrBWIPnSmjUmDWtWVWcSjwY7fX5/Q=="], + "@stylistic/eslint-plugin": ["@stylistic/eslint-plugin@5.5.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.0", "@typescript-eslint/types": "^8.46.1", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "estraverse": "^5.3.0", "picomatch": "^4.0.3" }, "peerDependencies": { "eslint": ">=9.0.0" } }, "sha512-IeZF+8H0ns6prg4VrkhgL+yrvDXWDH2cKchrbh80ejG9dQgZWp10epHMbgRuQvgchLII/lfh6Xn3lu6+6L86Hw=="], + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], "@types/bun": ["@types/bun@1.3.1", "", { "dependencies": { "bun-types": "1.3.1" } }, "sha512-4jNMk2/K9YJtfqwoAa28c8wK+T7nvJFOjxI4h/7sORWcypRNxBpr+TPNaCfVWq70tLCJsqoFwcf0oI0JU/fvMQ=="], + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], + "@types/node": ["@types/node@24.9.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA=="], "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.46.2", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/type-utils": "8.46.2", "@typescript-eslint/utils": "8.46.2", "@typescript-eslint/visitor-keys": "8.46.2", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.46.2", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w=="], + + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.46.2", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/types": "8.46.2", "@typescript-eslint/typescript-estree": "8.46.2", "@typescript-eslint/visitor-keys": "8.46.2", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g=="], + + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.46.2", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.46.2", "@typescript-eslint/types": "^8.46.2", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg=="], + + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.46.2", "", { "dependencies": { "@typescript-eslint/types": "8.46.2", "@typescript-eslint/visitor-keys": "8.46.2" } }, "sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA=="], + + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.46.2", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag=="], + + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.46.2", "", { "dependencies": { "@typescript-eslint/types": "8.46.2", "@typescript-eslint/typescript-estree": "8.46.2", "@typescript-eslint/utils": "8.46.2", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA=="], + + "@typescript-eslint/types": ["@typescript-eslint/types@8.46.2", "", {}, "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ=="], + + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.46.2", "", { "dependencies": { "@typescript-eslint/project-service": "8.46.2", "@typescript-eslint/tsconfig-utils": "8.46.2", "@typescript-eslint/types": "8.46.2", "@typescript-eslint/visitor-keys": "8.46.2", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ=="], + + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.46.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/types": "8.46.2", "@typescript-eslint/typescript-estree": "8.46.2" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg=="], + + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.46.2", "", { "dependencies": { "@typescript-eslint/types": "8.46.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w=="], + + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + + "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + "bun-types": ["bun-types@1.3.1", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-NMrcy7smratanWJ2mMXdpatalovtxVggkj11bScuWuiOoXTiKIu2eVS1/7qbyI/4yHedtsn175n4Sm4JcdHLXw=="], "bunup": ["bunup@0.15.13", "", { "dependencies": { "@bunup/dts": "^0.14.36", "@bunup/shared": "0.15.7", "chokidar": "^4.0.3", "coffi": "^0.1.37", "lightningcss": "^1.30.2", "picocolors": "^1.1.1", "tinyexec": "^1.0.1", "tree-kill": "^1.2.2", "zlye": "^0.4.4" }, "peerDependencies": { "typescript": "latest" }, "optionalPeers": ["typescript"], "bin": { "bunup": "dist/cli/index.js" } }, "sha512-i3kHvNkkT4aELlDoFVrwVwwJaKYqrWSbU+MikkRuH8W5A9bhGBtp1beeJ0Umxleas2u3rMiK+cfFbo5ouYs8eA=="], + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], "coffi": ["coffi@0.1.37", "", { "dependencies": { "strip-json-comments": "^5.0.3" } }, "sha512-ewO5Xis7sw7g54yI/3lJ/nNV90Er4ZnENeDORZjrs58T70MmwKFLZgevraNCz+RmB4KDKsYT1ui1wDB36iPWqQ=="], + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + + "eslint": ["eslint@9.39.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.0", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-iy2GE3MHrYTL5lrCtMZ0X1KLEKKUjmK0kzwcnefhR66txcEmXZD2YWgR5GNdcEwkNx3a0siYkSvl0vIC+Svjmg=="], + + "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], + + "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], + + "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], + + "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], + + "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], + + "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], + + "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], + + "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], + + "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], + + "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], + + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + + "globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], + + "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + + "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], + + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], + + "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], + + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], + + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + + "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], + "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="], "lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="], @@ -175,32 +341,110 @@ "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="], + "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], + + "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], + + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], + + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], + "oxc-minify": ["oxc-minify@0.93.0", "", { "optionalDependencies": { "@oxc-minify/binding-android-arm64": "0.93.0", "@oxc-minify/binding-darwin-arm64": "0.93.0", "@oxc-minify/binding-darwin-x64": "0.93.0", "@oxc-minify/binding-freebsd-x64": "0.93.0", "@oxc-minify/binding-linux-arm-gnueabihf": "0.93.0", "@oxc-minify/binding-linux-arm-musleabihf": "0.93.0", "@oxc-minify/binding-linux-arm64-gnu": "0.93.0", "@oxc-minify/binding-linux-arm64-musl": "0.93.0", "@oxc-minify/binding-linux-riscv64-gnu": "0.93.0", "@oxc-minify/binding-linux-s390x-gnu": "0.93.0", "@oxc-minify/binding-linux-x64-gnu": "0.93.0", "@oxc-minify/binding-linux-x64-musl": "0.93.0", "@oxc-minify/binding-wasm32-wasi": "0.93.0", "@oxc-minify/binding-win32-arm64-msvc": "0.93.0", "@oxc-minify/binding-win32-x64-msvc": "0.93.0" } }, "sha512-pwMjOGN/I+cfLVkSmECcVHROKwECNVAXCT5h/29S4f0aArIUh3CQnix1yYy7MTQ3yThNuGANjjE9jWJyT43Vbw=="], "oxc-resolver": ["oxc-resolver@11.12.0", "", { "optionalDependencies": { "@oxc-resolver/binding-android-arm-eabi": "11.12.0", "@oxc-resolver/binding-android-arm64": "11.12.0", "@oxc-resolver/binding-darwin-arm64": "11.12.0", "@oxc-resolver/binding-darwin-x64": "11.12.0", "@oxc-resolver/binding-freebsd-x64": "11.12.0", "@oxc-resolver/binding-linux-arm-gnueabihf": "11.12.0", "@oxc-resolver/binding-linux-arm-musleabihf": "11.12.0", "@oxc-resolver/binding-linux-arm64-gnu": "11.12.0", "@oxc-resolver/binding-linux-arm64-musl": "11.12.0", "@oxc-resolver/binding-linux-ppc64-gnu": "11.12.0", "@oxc-resolver/binding-linux-riscv64-gnu": "11.12.0", "@oxc-resolver/binding-linux-riscv64-musl": "11.12.0", "@oxc-resolver/binding-linux-s390x-gnu": "11.12.0", "@oxc-resolver/binding-linux-x64-gnu": "11.12.0", "@oxc-resolver/binding-linux-x64-musl": "11.12.0", "@oxc-resolver/binding-wasm32-wasi": "11.12.0", "@oxc-resolver/binding-win32-arm64-msvc": "11.12.0", "@oxc-resolver/binding-win32-ia32-msvc": "11.12.0", "@oxc-resolver/binding-win32-x64-msvc": "11.12.0" } }, "sha512-zmS2q2txiB+hS2u0aiIwmvITIJN8c8ThlWoWB762Wx5nUw8WBlttp0rzt8nnuP1cGIq9YJ7sGxfsgokm+SQk5Q=="], "oxc-transform": ["oxc-transform@0.93.0", "", { "optionalDependencies": { "@oxc-transform/binding-android-arm64": "0.93.0", "@oxc-transform/binding-darwin-arm64": "0.93.0", "@oxc-transform/binding-darwin-x64": "0.93.0", "@oxc-transform/binding-freebsd-x64": "0.93.0", "@oxc-transform/binding-linux-arm-gnueabihf": "0.93.0", "@oxc-transform/binding-linux-arm-musleabihf": "0.93.0", "@oxc-transform/binding-linux-arm64-gnu": "0.93.0", "@oxc-transform/binding-linux-arm64-musl": "0.93.0", "@oxc-transform/binding-linux-riscv64-gnu": "0.93.0", "@oxc-transform/binding-linux-s390x-gnu": "0.93.0", "@oxc-transform/binding-linux-x64-gnu": "0.93.0", "@oxc-transform/binding-linux-x64-musl": "0.93.0", "@oxc-transform/binding-wasm32-wasi": "0.93.0", "@oxc-transform/binding-win32-arm64-msvc": "0.93.0", "@oxc-transform/binding-win32-x64-msvc": "0.93.0" } }, "sha512-QCwM2nMAWf4hEBehLVA2apllxdmmWLb5M0in9HwC2boaaFbP0QntbLy4hfRZGur2KKyEBErZbH9S5NYX8eHslg=="], + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + + "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], + + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], + + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], + + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], "strip-json-comments": ["strip-json-comments@5.0.3", "", {}, "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw=="], + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "tinyexec": ["tinyexec@1.0.1", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="], + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], + "ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="], + "ts-import-resolver": ["ts-import-resolver@0.1.23", "", { "peerDependencies": { "typescript": ">=4.5.0" }, "optionalPeers": ["typescript"] }, "sha512-282pgr6j6aOvP3P2I6XugDxdBobkpdMmdbWjRjGl5gjPI1p0+oTNGDh1t924t75kRlyIkF65DiwhSIUysmyHQA=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "typescript-eslint": ["typescript-eslint@8.46.2", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.46.2", "@typescript-eslint/parser": "8.46.2", "@typescript-eslint/typescript-estree": "8.46.2", "@typescript-eslint/utils": "8.46.2" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-vbw8bOmiuYNdzzV3lsiWv6sRwjyuKJMQqWulBOU7M0RrxedXledX8G8kBbQeiOYDnTfiXz0Y4081E1QMNB6iQg=="], + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], + + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + "zlye": ["zlye@0.4.4", "", { "dependencies": { "picocolors": "^1.1.1" }, "peerDependencies": { "typescript": ">=4.5.0" }, "optionalPeers": ["typescript"] }, "sha512-fwpeC841X3ElOLYRMKXbwX29pitNrsm6nRNvEhDMrRXDl3BhR2i03Bkr0GNrpyYgZJuEzUsBylXAYzgGPXXOCQ=="], + + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + + "@eslint/eslintrc/strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + + "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + + "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], } } diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..95512ff --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,28 @@ +import eslint from "@eslint/js"; + +import { defineConfig, globalIgnores } from "eslint/config"; +import tseslint from "typescript-eslint"; + +import stylistic from "@stylistic/eslint-plugin"; + +export default defineConfig( + eslint.configs.recommended, + tseslint.configs.recommended, + { + plugins: { + "@stylistic": stylistic, + }, + rules: { + "no-unused-vars": "off", + "@stylistic/quotes": ["error", "double"], + "@stylistic/always-multiline": ["error", "always-multiline"], + "@typescript-eslint/consistent-type-imports": "error", + "@typescript-eslint/no-unused-vars": [ + "error", + { varsIgnorePattern: "_", argsIgnorePattern: "_" }, + ], + }, + }, + globalIgnores(["dist/**/*"], "Ignore build directory"), + globalIgnores(["**/*.test.*"], "Ignore test files") +); diff --git a/package.json b/package.json index 61a7a4c..cd13b03 100644 --- a/package.json +++ b/package.json @@ -33,13 +33,19 @@ "author": "Ember", "scripts": { "build": "bunup", - "tests": "bun test" + "tests": "bun test", + "lint": "eslint", + "lint:fix": "eslint --fix" }, "devDependencies": { + "@eslint/js": "^9.39.0", + "@stylistic/eslint-plugin": "^5.5.0", "@types/bun": "^1.3.1", - "bunup": "^0.15.13" + "bunup": "^0.15.13", + "eslint": "^9.39.0", + "typescript-eslint": "^8.46.2" }, "peerDependencies": { - "typescript": "^5.0.0" + "typescript": "^5.9.3" } }