From 573b06e245078673c7882ae40e37648fb857ff38 Mon Sep 17 00:00:00 2001 From: Horizontal42 <75383519+Horizontal42@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:04:37 +0300 Subject: [PATCH] reject duplicate ids in addUnit addUnit() overwrote unitsById unconditionally while its own addPhrase calls are first-wins, so an extension reusing an existing id silently corrupted the id->Unit table for anything using that id as a baseUnitId afterwards. Throw instead. --- src/engine/engine.test.ts | 7 +++++++ src/engine/index.ts | 1 + 2 files changed, 8 insertions(+) diff --git a/src/engine/engine.test.ts b/src/engine/engine.test.ts index 29f15e1..febef3a 100644 --- a/src/engine/engine.test.ts +++ b/src/engine/engine.test.ts @@ -335,6 +335,13 @@ describe("extension API", () => { eng.addUnit({ id: "horse", phrases: "horse, horses, hrs", baseUnitId: "meter", format: "hrs", ratio: 2.4 }); expect(calc("2 horses in meters")).toBe("4.8 m"); }); + it("addUnit throws on id collision instead of silently corrupting unitsById", () => { + expect(() => + eng.addUnit({ id: "horse", phrases: "nag", baseUnitId: "meter", format: "nag", ratio: 99 }) + ).toThrow(/horse/); + // the original registration must survive the failed collision + expect(calc("2 horses in meters")).toBe("4.8 m"); + }); it("addFunction (zum from Sample.js)", () => { eng.addFunction({ id: "zum", phrases: "zum" }, (values) => ({ double: values[0].double + values[1].double })); expect(calc("zum(2;3)")).toBe("5"); diff --git a/src/engine/index.ts b/src/engine/index.ts index e507dd9..5d6e82e 100644 --- a/src/engine/index.ts +++ b/src/engine/index.ts @@ -218,6 +218,7 @@ export class SumEngine { addUnit(spec: ExtensionUnitSpec): void { const base = this.reg.unitsById.get(spec.baseUnitId) ?? this.currencyBase(spec.baseUnitId); if (!base) throw new Error(`numi.addUnit: unknown baseUnitId ${spec.baseUnitId}`); + if (this.reg.unitsById.has(spec.id)) throw new Error(`numi.addUnit: id "${spec.id}" is already registered`); const unit: Unit = { id: spec.id, dimension: base.dimension,