From 5984151dd0917e40bb636f92fd039bfac0929597 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 7 Jan 2026 18:42:31 +0000 Subject: [PATCH] feat: add daysUntilEOL property for easier EOL tracking - Added `daysUntilEOL` to `NodeVersion` interface and implementation. - Updated documentation in `Readme.md` to include `eolDate` and `daysUntilEOL`. - Added tests for `daysUntilEOL` covering future, past, and unknown EOL dates. - Improved DX by providing a pre-calculated value for EOL countdowns. --- .jules/palette.md | 5 +++++ Readme.md | 2 ++ src/index.test.ts | 54 +++++++++++++++++++++++++++++++++++++++++++---- src/index.ts | 7 +++++- src/types.ts | 6 ++++++ 5 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 .jules/palette.md diff --git a/.jules/palette.md b/.jules/palette.md new file mode 100644 index 00000000..a987ae65 --- /dev/null +++ b/.jules/palette.md @@ -0,0 +1,5 @@ +# Palette's Journal + +## 2024-05-22 - DX is UX for Libraries +**Learning:** For a utility library, "UX" often means Developer Experience (DX). Clear, rich JSDoc comments with `@example` and `@see` links make the library much easier to adopt and debug without leaving the IDE. +**Action:** Always check if public exports have sufficient documentation, including usage examples and external references where applicable. diff --git a/Readme.md b/Readme.md index 4358c2b8..e38aded2 100644 --- a/Readme.md +++ b/Readme.md @@ -91,6 +91,8 @@ const v = getVersion(); | `isLTS` | `boolean` | `true` if the current version is an [LTS release](https://github.com/nodejs/release#release-schedule). | | `ltsName` | `string` | The LTS codename (e.g., 'Iron') or `undefined`. | | `isEOL` | `boolean` | `true` if the current version is past its [End-of-Life date](https://github.com/nodejs/release#end-of-life-releases). | +| `eolDate` | `Date` | The date when this major version becomes End-of-Life. | +| `daysUntilEOL` | `number` | The number of days until the EOL date (negative if passed). | ## Compare Versions diff --git a/src/index.test.ts b/src/index.test.ts index 5d386cbe..4c3b7c25 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -4,8 +4,8 @@ * MIT Licensed */ -import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; import { versions as realVersions } from "node:process"; +import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; import { EOL_DATES, getVersion, version } from "./index.js"; const { mockVersion, mockRelease } = vi.hoisted(() => ({ @@ -104,9 +104,9 @@ describe("node-version", () => { expect(typeof v.build).toBe("string"); }); - test("object should have exactly 16 properties", () => { - expect(Object.keys(version)).toHaveLength(16); - expect(Object.keys(getVersion())).toHaveLength(16); + test("object should have exactly 17 properties", () => { + expect(Object.keys(version)).toHaveLength(17); + expect(Object.keys(getVersion())).toHaveLength(17); }); test("original property should start with v", () => { @@ -329,5 +329,51 @@ describe("node-version", () => { const v = getVersion(); expect(v.eolDate).toBeUndefined(); }); + + test("should return a number for a known EOL date", () => { + // Mock current date to be before EOL + vi.useFakeTimers(); + const mockDate = new Date("2024-01-01T00:00:00Z"); + vi.setSystemTime(mockDate); + mockVersion.node = "20.10.0"; + + const version = getVersion(); + + // Node 20 EOL is 2026-04-30 + const eolDate = new Date("2026-04-30"); + const diffTime = eolDate.getTime() - mockDate.getTime(); + const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); + + expect(version.daysUntilEOL).toBe(diffDays); + expect(version.daysUntilEOL).toBeGreaterThan(0); + + vi.useRealTimers(); + }); + + test("should return negative number for passed EOL date", () => { + // Mock current date to be after EOL + vi.useFakeTimers(); + const mockDate = new Date("2027-01-01T00:00:00Z"); + vi.setSystemTime(mockDate); + mockVersion.node = "20.10.0"; + + const version = getVersion(); + + // Node 20 EOL is 2026-04-30 + const eolDate = new Date("2026-04-30"); + const diffTime = eolDate.getTime() - mockDate.getTime(); + const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); + + expect(version.daysUntilEOL).toBe(diffDays); + expect(version.daysUntilEOL).toBeLessThan(0); + + vi.useRealTimers(); + }); + + test("should have undefined daysUntilEOL for unknown version", () => { + mockVersion.node = "99.0.0"; + const v = getVersion(); + expect(v.daysUntilEOL).toBeUndefined(); + }); }); }); diff --git a/src/index.ts b/src/index.ts index 625ca808..4490499c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -47,6 +47,10 @@ export const getVersion = (): NodeVersion => { const nodeVersionParts = split.map((s) => Number(s) || 0); const major = split[0] || "0"; const eolString = EOL_DATES[major]; + const eolDate = eolString ? new Date(eolString) : undefined; + const daysUntilEOL = eolDate + ? Math.ceil((eolDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24)) + : undefined; /** * Compare the current node version with a target version string. @@ -107,7 +111,8 @@ export const getVersion = (): NodeVersion => { isLTS: !!release.lts, ltsName: String(release.lts || "") || undefined, isEOL: checkEOL(major), - eolDate: eolString ? new Date(eolString) : undefined, + eolDate, + daysUntilEOL, toString: () => `v${nodeVersion}`, }; }; diff --git a/src/types.ts b/src/types.ts index 4de06674..62336478 100644 --- a/src/types.ts +++ b/src/types.ts @@ -93,6 +93,12 @@ export interface NodeVersion { * @see https://github.com/nodejs/release#release-schedule */ eolDate: Date | undefined; + /** + * The number of days until the EOL date. + * Positive if EOL is in the future, negative if in the past. + * Undefined if the EOL date is not known. + */ + daysUntilEOL: number | undefined; /** * Returns the original version string. */