From a174c6cc3957d903cbe67bd332f022364be5d8e7 Mon Sep 17 00:00:00 2001 From: adityaaa-IIT-BHU Date: Tue, 4 Aug 2026 10:52:04 +0900 Subject: [PATCH] fix: require pinHeader pinCount to be a positive integer (#756) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pinCount was a bare z.number(), so fractional, zero, negative and infinite values all parsed. A fractional count is the worst of these: it produces a header whose port count and pad count disagree (pinCount=2.5 gives 2 ports but 3 pads) and nothing reports it. Zero and negative counts failed too, but later and less clearly, as pcb_missing_footprint_error — which points at the footprint when the mistake was the pin count. A count of physical pins is inherently a positive integer. Use z.number().int().positive(), the idiom already used for sampleCount and samplesPerInterval in analogacsweepsimulation.ts, with messages that name the prop. Whole counts parse to the same value as before. --- generated/COMPONENT_TYPES.md | 5 ++++- lib/components/pin-header.ts | 5 ++++- tests/pin-header.test.ts | 31 +++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/generated/COMPONENT_TYPES.md b/generated/COMPONENT_TYPES.md index 58a0e324..c20bedf5 100644 --- a/generated/COMPONENT_TYPES.md +++ b/generated/COMPONENT_TYPES.md @@ -3411,7 +3411,10 @@ export interface PinHeaderProps extends CommonComponentProps { * Schematic height */ export const pinHeaderProps = commonComponentProps.extend({ - pinCount: z.number(), + pinCount: z + .number() + .int("pinCount must be a whole number of pins") + .positive("pinCount must be greater than zero"), pitch: distance.optional(), schFacingDirection: z.enum(["up", "down", "left", "right"]).optional(), gender: z.enum(["male", "female", "unpopulated"]).optional().default("male"), diff --git a/lib/components/pin-header.ts b/lib/components/pin-header.ts index 5c74e304..84d88de1 100644 --- a/lib/components/pin-header.ts +++ b/lib/components/pin-header.ts @@ -123,7 +123,10 @@ export interface PinHeaderProps extends CommonComponentProps { } export const pinHeaderProps = commonComponentProps.extend({ - pinCount: z.number(), + pinCount: z + .number() + .int("pinCount must be a whole number of pins") + .positive("pinCount must be greater than zero"), pitch: distance.optional(), schFacingDirection: z.enum(["up", "down", "left", "right"]).optional(), gender: z.enum(["male", "female", "unpopulated"]).optional().default("male"), diff --git a/tests/pin-header.test.ts b/tests/pin-header.test.ts index 870383f8..469bcac5 100644 --- a/tests/pin-header.test.ts +++ b/tests/pin-header.test.ts @@ -88,6 +88,37 @@ test("should parse pinLabels as record", () => { expect(parsed.pinLabels).toEqual({ 1: "A", 2: "B" }) }) +test("should reject a fractional pinCount", () => { + const parsed = pinHeaderProps.safeParse({ name: "header", pinCount: 2.5 }) + + expect(parsed.success).toBe(false) +}) + +test("should reject a zero or negative pinCount", () => { + expect( + pinHeaderProps.safeParse({ name: "header", pinCount: 0 }).success, + ).toBe(false) + expect( + pinHeaderProps.safeParse({ name: "header", pinCount: -4 }).success, + ).toBe(false) +}) + +test("should reject a non-finite pinCount", () => { + expect( + pinHeaderProps.safeParse({ + name: "header", + pinCount: Number.POSITIVE_INFINITY, + }).success, + ).toBe(false) +}) + +test("should parse whole pinCount values unchanged", () => { + for (const pinCount of [1, 2, 8, 40]) { + const parsed = pinHeaderProps.parse({ name: "header", pinCount }) + expect(parsed.pinCount).toBe(pinCount) + } +}) + test("should snapshot schematic props for pin header", () => { const rawProps: PinHeaderProps = { name: "header",