From b619eec53d9e38c34a22fa730aa37ea9fb3f2d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guilherme=20Ara=C3=BAjo?= Date: Thu, 8 Jan 2026 21:01:14 -0300 Subject: [PATCH 1/6] Remove fs calls from library --- bin/lts.js | 21 +++++++++++++++++---- lib/index.js | 14 +------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/bin/lts.js b/bin/lts.js index 3752e8c..90ce4ae 100644 --- a/bin/lts.js +++ b/bin/lts.js @@ -102,13 +102,26 @@ const options = { data: require(args.data), queryStart: new Date(args.start), queryEnd: new Date(args.end), - html: args.html ? Path.resolve(args.html) : null, - svg: args.svg ? Path.resolve(args.svg) : null, - png: args.png ? Path.resolve(args.png) : null, animate: args.animate, excludeMain: args.excludeMain, projectName: args.projectName, currentDateMarker: args.currentDateMarker }; -Lib.create(options); +const d3n = Lib.create(options); + +if (args.html) { + const Fs = require('fs'); + Fs.writeFileSync(Path.resolve(args.html), d3n.html()); +} + +if (args.svg) { + const Fs = require('fs'); + Fs.writeFileSync(Path.resolve(args.svg), d3n.svgString()); +} + +if (args.png) { + const Fs = require('fs'); + const Svg2png = require('svg2png'); + Fs.writeFileSync(Path.resolve(args.png), Svg2png.sync(Buffer.from(d3n.svgString()))); +} diff --git a/lib/index.js b/lib/index.js index ff99db3..b128a5e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -220,19 +220,7 @@ function create (options) { return +(calculateWidth(data) >= min); }); - if (typeof html === 'string') { - Fs.writeFileSync(html, d3n.html()); - } - - if (typeof svgFile === 'string') { - Fs.writeFileSync(svgFile, d3n.svgString()); - } - - if (typeof png === 'string') { - const Svg2png = require('svg2png'); // Load this lazily. - - Fs.writeFileSync(png, Svg2png.sync(Buffer.from(d3n.svgString()))); - } + return d3n; } module.exports.create = create; From 818e52ebcee6b9c64d9761b39249742b3adc8b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guilherme=20Ara=C3=BAjo?= Date: Thu, 8 Jan 2026 21:18:32 -0300 Subject: [PATCH 2/6] Responsive svg --- lib/index.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index b128a5e..d770439 100644 --- a/lib/index.js +++ b/lib/index.js @@ -4,6 +4,10 @@ const D3 = require('d3'); const D3Node = require('d3-node'); const styles = ` +svg { + width: 100%; + height: auto; +} .current { fill: #5fa04e; } @@ -111,8 +115,8 @@ function create (options) { .tickFormat(D3.timeFormat('%b %Y')); const yAxis = D3.axisRight(yScale).tickSize(width); const svg = d3n.createSVG() - .attr('width', width + margin.left + margin.right) - .attr('height', height + margin.top + margin.bottom) + .attr('viewBox', `0 0 ${width + margin.left + margin.right} ${height + margin.top + margin.bottom}`) + .attr('preserveAspectRatio', 'xMinYMin meet') .append('g') .attr('id', 'bar-container') .attr('transform', `translate(${margin.left}, ${margin.top})`); From 07bc0a5152899df510d8066af2210574ba8ddf44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guilherme=20Ara=C3=BAjo?= Date: Thu, 8 Jan 2026 21:25:45 -0300 Subject: [PATCH 3/6] Remove unused parameters --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index d770439..b35060c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -96,7 +96,7 @@ function parseInput (data, queryStart, queryEnd, excludeMain, projectName) { function create (options) { - const { queryStart, queryEnd, html, svg: svgFile, png, animate, excludeMain, projectName, margin: marginInput, currentDateMarker } = options; + const { queryStart, queryEnd, animate, excludeMain, projectName, margin: marginInput, currentDateMarker } = options; const data = parseInput(options.data, queryStart, queryEnd, excludeMain, projectName); const d3n = new D3Node({ svgStyles: styles, d3Module: D3 }); const margin = marginInput || { top: 30, right: 30, bottom: 30, left: 110 }; From f52ebc8052d12925450e20c840c07219c0a3a93c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guilherme=20Ara=C3=BAjo?= Date: Thu, 8 Jan 2026 21:35:39 -0300 Subject: [PATCH 4/6] Fix png width and height --- lib/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/index.js b/lib/index.js index b35060c..f183858 100644 --- a/lib/index.js +++ b/lib/index.js @@ -115,6 +115,8 @@ function create (options) { .tickFormat(D3.timeFormat('%b %Y')); const yAxis = D3.axisRight(yScale).tickSize(width); const svg = d3n.createSVG() + .attr('width', width + margin.left + margin.right) + .attr('height', height + margin.top + margin.bottom) .attr('viewBox', `0 0 ${width + margin.left + margin.right} ${height + margin.top + margin.bottom}`) .attr('preserveAspectRatio', 'xMinYMin meet') .append('g') From 2f03004964eb1e8c1c643b7900551d07cf0bac58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guilherme=20Ara=C3=BAjo?= Date: Thu, 8 Jan 2026 21:44:32 -0300 Subject: [PATCH 5/6] Add ts definitions --- lib/index.d.ts | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 60 insertions(+) create mode 100644 lib/index.d.ts diff --git a/lib/index.d.ts b/lib/index.d.ts new file mode 100644 index 0000000..6bee342 --- /dev/null +++ b/lib/index.d.ts @@ -0,0 +1,59 @@ +import { JSDOM } from "d3-node"; + +export interface VersionData { + /** Start date of the version */ + start: string; + /** LTS start date */ + lts?: string; + /** Maintenance start date */ + maintenance?: string; + /** End of life date */ + end: string; + /** Codename */ + codename?: string; +} + +export interface ScheduleData { + [version: string]: VersionData; +} + +export interface Margin { + top: number; + right: number; + bottom: number; + left: number; +} + +export interface CreateOptions { + /** The schedule data object with version keys */ + data: ScheduleData; + /** Start date for the chart query range */ + queryStart: Date; + /** End date for the chart query range */ + queryEnd: Date; + /** Whether to animate the bars (default: false) */ + animate?: boolean; + /** Whether to exclude the "Main" row (default: false) */ + excludeMain?: boolean; + /** Project name to prefix version labels */ + projectName: string; + /** Chart margins (default: { top: 30, right: 30, bottom: 30, left: 110 }) */ + margin?: Margin; + /** Color for the current date marker line (e.g., 'red', '#ff0000') */ + currentDateMarker?: string; +} + +export interface D3NodeResult { + /** Get the SVG element */ + svgString(): string; + /** Get the HTML string */ + html(): string; +} + +/** + * Creates an D3 chart representing the Node.js LTS schedule + * + * @param options - Configuration options for the chart + * @returns A D3Node instance + */ +export function create(options: CreateOptions): D3NodeResult; diff --git a/package.json b/package.json index 7829b90..a4520c8 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "2.0.0", "description": "Generate the Node.js LTS schedule", "main": "lib/index.js", + "types": "lib/index.d.ts", "homepage": "https://github.com/nodejs/lts-schedule", "repository": { "type": "git", From 4b9760ba4dae542b5be1836fed8b5fa2f1c7e66b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guilherme=20Ara=C3=BAjo?= Date: Fri, 16 Jan 2026 12:21:24 -0300 Subject: [PATCH 6/6] Review --- bin/lts.js | 13 ++++++------- lib/index.js | 1 - 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/bin/lts.js b/bin/lts.js index 90ce4ae..3cc9f5d 100644 --- a/bin/lts.js +++ b/bin/lts.js @@ -3,6 +3,9 @@ const Path = require('path'); const Bossy = require('bossy'); const Lib = require('../lib'); +const { writeFileSync } = require('node:fs'); +const Svg2png = require('svg2png'); + const now = new Date(); const oneYearFromNow = new Date(); @@ -111,17 +114,13 @@ const options = { const d3n = Lib.create(options); if (args.html) { - const Fs = require('fs'); - Fs.writeFileSync(Path.resolve(args.html), d3n.html()); + writeFileSync(Path.resolve(args.html), d3n.html()); } if (args.svg) { - const Fs = require('fs'); - Fs.writeFileSync(Path.resolve(args.svg), d3n.svgString()); + writeFileSync(Path.resolve(args.svg), d3n.svgString()); } if (args.png) { - const Fs = require('fs'); - const Svg2png = require('svg2png'); - Fs.writeFileSync(Path.resolve(args.png), Svg2png.sync(Buffer.from(d3n.svgString()))); + writeFileSync(Path.resolve(args.png), Svg2png.sync(Buffer.from(d3n.svgString()))); } diff --git a/lib/index.js b/lib/index.js index f183858..fddb9a9 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,5 +1,4 @@ 'use strict'; -const Fs = require('fs'); const D3 = require('d3'); const D3Node = require('d3-node');