diff --git a/bin/lts.js b/bin/lts.js index 3752e8c..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(); @@ -102,13 +105,22 @@ 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) { + writeFileSync(Path.resolve(args.html), d3n.html()); +} + +if (args.svg) { + writeFileSync(Path.resolve(args.svg), d3n.svgString()); +} + +if (args.png) { + writeFileSync(Path.resolve(args.png), Svg2png.sync(Buffer.from(d3n.svgString()))); +} 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/lib/index.js b/lib/index.js index ff99db3..fddb9a9 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,9 +1,12 @@ 'use strict'; -const Fs = require('fs'); const D3 = require('d3'); const D3Node = require('d3-node'); const styles = ` +svg { + width: 100%; + height: auto; +} .current { fill: #5fa04e; } @@ -92,7 +95,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 }; @@ -113,6 +116,8 @@ function create (options) { 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})`); @@ -220,19 +225,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; 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",