From 41b22ecd60839f69e614bdc3dfea99e5782c44c6 Mon Sep 17 00:00:00 2001 From: Liran Tal Date: Wed, 17 Jul 2024 14:50:46 +0300 Subject: [PATCH 1/2] feat: remove moment dependency the moment dependency accounts for 59% of the bundle size of snyk-to-html pacakge and only used for a simple (and predefined?) formatting option. source: https://bundlephobia.com/package/snyk-to-html@2.5.1 --- package.json | 1 - src/lib/dateutil.ts | 50 +++++++++++++++++++++++++++++++++++++++++ src/lib/snyk-to-html.ts | 10 +++++---- 3 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 src/lib/dateutil.ts diff --git a/package.json b/package.json index 9c694d4..2838bf2 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "lodash.isempty": "^4.4.0", "lodash.orderby": "^4.6.0", "marked": "^4.0.12", - "moment": "^2.29.4", "source-map-support": "^0.5.16", "uglify-js": "^3.15.1" }, diff --git a/src/lib/dateutil.ts b/src/lib/dateutil.ts new file mode 100644 index 0000000..c459927 --- /dev/null +++ b/src/lib/dateutil.ts @@ -0,0 +1,50 @@ +export function formatDateTime(date, format): string { + if (!date) { + date = new Date(); + } + const day = date.getUTCDate(); + const ordinalSuffix = getOrdinalSuffix(day); + const dayWithSuffix = `${day}${ordinalSuffix}`; + + const hours = date.getUTCHours(); + const minutes = date.getUTCMinutes(); + const seconds = date.getUTCSeconds(); + const ampm = hours >= 12 ? 'pm' : 'am'; + const formattedHours = hours % 12 || 12; + + const monthNames = [ + "January", "February", "March", "April", + "May", "June", "July", "August", + "September", "October", "November", "December" + ]; + + const replacements = { + 'MMMM': monthNames[date.getUTCMonth()], + 'Do': dayWithSuffix, + 'YYYY': date.getUTCFullYear(), + 'h': formattedHours, + 'mm': minutes.toString().padStart(2, '0'), + 'ss': seconds.toString().padStart(2, '0'), + 'a': ampm, + 'z': 'UTC', + 'Z': '+00:00' + }; + + return format.replace(/MMMM|Do|YYYY|h|mm|ss|a|z|Z/g, (match) => replacements[match]); +} + +function getOrdinalSuffix(day) { + if (day > 3 && day < 21) { + return 'th'; + } + switch (day % 10) { + case 1: + return 'st'; + case 2: + return 'nd'; + case 3: + return 'rd'; + default: + return 'th'; + } +} \ No newline at end of file diff --git a/src/lib/snyk-to-html.ts b/src/lib/snyk-to-html.ts index 2b525b2..1b9040a 100755 --- a/src/lib/snyk-to-html.ts +++ b/src/lib/snyk-to-html.ts @@ -7,12 +7,14 @@ import * as debugModule from 'debug'; import fs = require('fs'); import Handlebars = require('handlebars'); import marked = require('marked'); -import moment = require('moment'); import path = require('path'); import { addIssueDataToPatch, getUpgrades, severityMap, IacProjectType } from './vuln'; import { processSourceCode, } from './codeutil'; +import { + formatDateTime +} from './dateutil'; const debug = debugModule('snyk-to-html'); @@ -99,7 +101,7 @@ class SnykToHtml { export { SnykToHtml }; function metadataForVuln(vuln: any) { - let {cveSpaced, cveLineBreaks} = concatenateCVEs(vuln) + const {cveSpaced, cveLineBreaks} = concatenateCVEs(vuln) return { id: vuln.id, @@ -127,7 +129,7 @@ function concatenateCVEs(vuln: any) { if (vuln.identifiers) { vuln.identifiers.CVE.forEach(function(c) { - let cveLink = `${c}` + const cveLink = `${c}` cveSpaced += `${cveLink} ` cveLineBreaks += `${cveLink}
` }) @@ -381,7 +383,7 @@ async function readInputFromStdin(): Promise { // handlebar helpers const hh = { markdown: marked.parse, - moment: (date, format) => moment.utc(date).format(format), + moment: (date, format) => formatDateTime(date, format), count: data => data && data.length, dump: (data, spacer) => JSON.stringify(data, null, spacer || null), // block helpers From 85243fc6cef140f3e6f6376eb5ef260a10abe31f Mon Sep 17 00:00:00 2001 From: Trombitas Sandor Date: Fri, 9 Aug 2024 16:15:23 +0300 Subject: [PATCH 2/2] test: add test for dateutil --- test/dateutil.test.ts | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 test/dateutil.test.ts diff --git a/test/dateutil.test.ts b/test/dateutil.test.ts new file mode 100644 index 0000000..29a2cd1 --- /dev/null +++ b/test/dateutil.test.ts @@ -0,0 +1,56 @@ +import tap from 'tap'; +import { formatDateTime } from '../src/lib/dateutil'; + +tap.test('formatDateTime', async (t) => { + t.test('formats date with default format', async (t) => { + const date = new Date('2023-04-15T14:30:45Z'); + t.equal( + formatDateTime(date, 'MMMM Do, YYYY h:mm:ss a z'), + 'April 15th, 2023 2:30:45 pm UTC', + ); + t.end(); + }); + + t.test('handles different months', async (t) => { + const date = new Date('2023-01-01T00:00:00Z'); + t.equal(formatDateTime(date, 'MMMM Do, YYYY'), 'January 1st, 2023'); + t.end(); + }); + + t.test('handles ordinal suffixes correctly', async (t) => { + t.equal(formatDateTime(new Date('2023-05-01T00:00:00Z'), 'Do'), '1st'); + t.equal(formatDateTime(new Date('2023-05-02T00:00:00Z'), 'Do'), '2nd'); + t.equal(formatDateTime(new Date('2023-05-03T00:00:00Z'), 'Do'), '3rd'); + t.equal(formatDateTime(new Date('2023-05-04T00:00:00Z'), 'Do'), '4th'); + t.equal(formatDateTime(new Date('2023-05-11T00:00:00Z'), 'Do'), '11th'); + t.equal(formatDateTime(new Date('2023-05-21T00:00:00Z'), 'Do'), '21st'); + t.end(); + }); + + t.test('formats time correctly', async (t) => { + const date = new Date('2023-04-15T23:59:59Z'); + t.equal(formatDateTime(date, 'h:mm:ss a'), '11:59:59 pm'); + t.end(); + }); + + t.test('handles midnight correctly', async (t) => { + const date = new Date('2023-04-15T00:00:00Z'); + t.equal(formatDateTime(date, 'h:mm:ss a'), '12:00:00 am'); + t.end(); + }); + + t.test('includes timezone information', async (t) => { + const date = new Date('2023-04-15T14:30:45Z'); + t.equal(formatDateTime(date, 'z Z'), 'UTC +00:00'); + t.end(); + }); + + t.test('uses current date when no date is provided', async (t) => { + const now = new Date(); + const formatted = formatDateTime(null, 'YYYY'); + t.equal(formatted, now.getUTCFullYear().toString()); + t.end(); + }); + + t.end(); +});