From c6323f81339b2371305dd8be38a1946be5140683 Mon Sep 17 00:00:00 2001 From: Matt Mayer <152770+matthewmayer@users.noreply.github.com> Date: Fri, 14 Jul 2023 21:11:28 +0100 Subject: [PATCH] refactor(git): don't use Intl (#2222) --- .eslintrc.js | 1 + src/modules/git/index.ts | 82 ++++++++++++++++------------------------ test/git.spec.ts | 34 +---------------- 3 files changed, 34 insertions(+), 83 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 2c6e74ecb16..b46a4a031f9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -32,6 +32,7 @@ module.exports = defineConfig({ eqeqeq: ['error', 'always', { null: 'ignore' }], 'no-else-return': 'error', 'prefer-template': 'error', + 'no-restricted-globals': ['error', 'Intl'], 'deprecation/deprecation': 'error', diff --git a/src/modules/git/index.ts b/src/modules/git/index.ts index 7528d9bb691..26e6e76773a 100644 --- a/src/modules/git/index.ts +++ b/src/modules/git/index.ts @@ -1,30 +1,6 @@ import type { Faker } from '../..'; -import { FakerError } from '../../errors/faker-error'; import { deprecated } from '../../internal/deprecated'; -const GIT_DATE_FORMAT_BASE = Intl?.DateTimeFormat - ? new Intl.DateTimeFormat('en', { - weekday: 'short', - month: 'short', - day: 'numeric', - hour: '2-digit', - hourCycle: 'h24', - minute: '2-digit', - second: '2-digit', - year: 'numeric', - timeZone: 'UTC', - }) - : null; - -const GIT_TIMEZONE_FORMAT = Intl?.NumberFormat - ? new Intl.NumberFormat('en', { - minimumIntegerDigits: 4, - maximumFractionDigits: 0, - useGrouping: false, - signDisplay: 'always', - }) - : null; - /** * Module to generate git related entries. * @@ -70,8 +46,6 @@ export class GitModule { * 'CRLF' = '\r\n' * @param options.refDate The date to use as reference point for the commit. Defaults to `new Date()`. * - * @throws When the environment does not support `Intl.NumberFormat` and `Intl.DateTimeFormat`. - * * @example * faker.git.commitEntry() * // commit fe8c38a965d13d9794eb36918cb24cebe49a45c2 @@ -166,8 +140,6 @@ export class GitModule { * @param options The optional options object. * @param options.refDate The date to use as reference point for the commit. Defaults to `faker.defaultRefDate()`. * - * @throws When the environment does not support `Intl.NumberFormat` and `Intl.DateTimeFormat`. - * * @example * faker.git.commitDate() // 'Mon Nov 7 14:40:58 2022 +0600' * faker.git.commitDate({ refDate: '2020-01-01' }) // 'Tue Dec 31 05:40:59 2019 -0400' @@ -185,28 +157,38 @@ export class GitModule { } = {} ): string { const { refDate = this.faker.defaultRefDate() } = options; - // We check if Intl support is missing rather than if GIT_DATE_FORMAT_BASE/GIT_TIMEZONE_FORMAT is null. This allows us to test the error case in environments that do have Intl support by temporarily removing Intl at runtime. - if (!Intl || !Intl.DateTimeFormat || !Intl.NumberFormat) { - throw new FakerError( - 'This method requires an environment which supports Intl.NumberFormat and Intl.DateTimeFormat' - ); - } - - const dateParts = GIT_DATE_FORMAT_BASE.format( - this.faker.date.recent({ days: 1, refDate }) - ) - .replace(/,/g, '') - .split(' '); - [dateParts[3], dateParts[4]] = [dateParts[4], dateParts[3]]; - - // Timezone offset - dateParts.push( - GIT_TIMEZONE_FORMAT.format( - this.faker.number.int({ min: -11, max: 12 }) * 100 - ) - ); - - return dateParts.join(' '); + // Git uses a non-standard date format for commits by default per https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-log.html + // --date=default is the default format, and is based on ctime(3) output. It shows a single line with three-letter day of the week, three-letter month, day-of-month, hour-minute-seconds in "HH:MM:SS" format, followed by 4-digit year, plus timezone information, unless the local time zone is used, e.g. Thu Jan 1 00:00:00 1970 +0000. + // To avoid relying on the Intl global which may not be available in all environments, we implement a custom date format using built-in Javascript date functions. + const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; + const months = [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ]; + + const date = this.faker.date.recent({ days: 1, refDate }); + const day = days[date.getUTCDay()]; + const month = months[date.getUTCMonth()]; + const dayOfMonth = date.getUTCDate(); + const hours = date.getUTCHours().toString().padStart(2, '0'); + const minutes = date.getUTCMinutes().toString().padStart(2, '0'); + const seconds = date.getUTCSeconds().toString().padStart(2, '0'); + const year = date.getUTCFullYear(); + const timezone = this.faker.number.int({ min: -11, max: 12 }); + const timezoneHours = Math.abs(timezone).toString().padStart(2, '0'); + const timezoneMinutes = '00'; + const timezoneSign = timezone >= 0 ? '+' : '-'; + return `${day} ${month} ${dayOfMonth} ${hours}:${minutes}:${seconds} ${year} ${timezoneSign}${timezoneHours}${timezoneMinutes}`; } /** diff --git a/test/git.spec.ts b/test/git.spec.ts index 5926a0b76f4..4000e71d413 100644 --- a/test/git.spec.ts +++ b/test/git.spec.ts @@ -1,6 +1,6 @@ import validator from 'validator'; import { describe, expect, it } from 'vitest'; -import { faker, FakerError } from '../src'; +import { faker } from '../src'; import { seededTests } from './support/seededRuns'; import { times } from './support/times'; @@ -114,22 +114,6 @@ describe('git', () => { expect(commitEntry).not.contains('\r\n'); }); - - it('should throw if Intl is unavailable', () => { - const backup = globalThis.Intl.DateTimeFormat; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (globalThis as any).Intl.DateTimeFormat = undefined; - - expect(() => { - faker.git.commitEntry(); - }).toThrow( - new FakerError( - 'This method requires an environment which supports Intl.NumberFormat and Intl.DateTimeFormat' - ) - ); - - globalThis.Intl.DateTimeFormat = backup; - }); }); describe('commitMessage', () => { @@ -154,22 +138,6 @@ describe('git', () => { const parts = commitDate.split(' '); expect(parts.length).toBe(6); }); - - it('should throw if Intl is unavailable', () => { - const backup = globalThis.Intl.DateTimeFormat; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (globalThis as any).Intl.DateTimeFormat = undefined; - - expect(() => { - faker.git.commitDate(); - }).toThrow( - new FakerError( - 'This method requires an environment which supports Intl.NumberFormat and Intl.DateTimeFormat' - ) - ); - - globalThis.Intl.DateTimeFormat = backup; - }); }); describe('commitSha', () => {