diff --git a/change/@rightcapital-date-helpers-8012ed99-a740-438a-9de1-2cb74e9e8536.json b/change/@rightcapital-date-helpers-8012ed99-a740-438a-9de1-2cb74e9e8536.json new file mode 100644 index 0000000..2bf6a42 --- /dev/null +++ b/change/@rightcapital-date-helpers-8012ed99-a740-438a-9de1-2cb74e9e8536.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat(date-helpers): add type assertion for `DateLike` input", + "packageName": "@rightcapital/date-helpers", + "email": "38807139+liby@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/change/@rightcapital-exceptions-171717a8-bdb8-4321-a1d1-0236677e67c3.json b/change/@rightcapital-exceptions-171717a8-bdb8-4321-a1d1-0236677e67c3.json new file mode 100644 index 0000000..d67d885 --- /dev/null +++ b/change/@rightcapital-exceptions-171717a8-bdb8-4321-a1d1-0236677e67c3.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "chore: update TypeScript config", + "packageName": "@rightcapital/exceptions", + "email": "38807139+liby@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/package.json b/package.json index 0bf9c07..36c21fe 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "build": "pnpm run clean && pnpm -r --filter=./packages/** run build", "clean": "pnpm -r --parallel --filter=./packages/** exec tsc --build --clean", "pretest": "pnpm run build", - "test": "jest", + "test": "pnpm run pretest && jest", "lint": "concurrently pnpm:lint:*", "lint:eslint": "eslint --max-warnings=0 .", "lint:prettier": "prettier -c .", diff --git a/packages/date-helpers/__tests__/date-helpers.test.ts b/packages/date-helpers/__tests__/date-helpers.test.ts index e990c79..6b3f9d4 100644 --- a/packages/date-helpers/__tests__/date-helpers.test.ts +++ b/packages/date-helpers/__tests__/date-helpers.test.ts @@ -1,9 +1,65 @@ import { parseISO } from 'date-fns'; import { DateHelpers } from '../src/date-helpers'; +import { InvalidArgumentException } from '@rightcapital/exceptions'; const output = parseISO('2019-10-21'); -describe('DateHelpers', () => { +describe('DateHelpers input validation', () => { + it('parseDateString should throw for unrecognized date formats', () => { + const invalidDateString = 'ABCDE'; + expect(() => DateHelpers.parseDateString(invalidDateString)).toThrowError( + InvalidArgumentException, + ); + }); + + it('parseDateString should throw error for null or undefined input', () => { + // @ts-expect-error - intentionally passing invalid input to test error handling + expect(() => DateHelpers.parseDateString(null)).toThrow( + 'Input cannot be null or undefined.', + ); + + // @ts-expect-error - intentionally passing invalid input to test error handling + expect(() => DateHelpers.parseDateString(undefined)).toThrow( + 'Input cannot be null or undefined.', + ); + }); + + it('formatDateLikeToString should throw InvalidArgumentException for invalid date input', () => { + expect(() => + DateHelpers.formatDateLikeToString( + 'invalid date', + DateHelpers.isoDateFormat, + ), + ).toThrowError(InvalidArgumentException); + }); + + it('formatDateLikeToString should throw InvalidArgumentException for invalid date format', () => { + expect(() => + DateHelpers.formatDateLikeToString(new Date(), 'invalid format'), + ).toThrowError(InvalidArgumentException); + }); + + it('formatDateLikeToString should throw error for null, undefined, or invalid input', () => { + expect(() => + // @ts-expect-error - intentionally passing invalid input to test error handling + DateHelpers.formatDateLikeToString(null, DateHelpers.isoDateFormat), + ).toThrowError(InvalidArgumentException); + expect(() => + // @ts-expect-error - intentionally passing invalid input to test error handling + DateHelpers.formatDateLikeToString(undefined, DateHelpers.isoDateFormat), + ).toThrowError(InvalidArgumentException); + expect(() => + // @ts-expect-error - intentionally passing invalid input to test error handling + DateHelpers.formatDateLikeToString({}, DateHelpers.isoDateFormat), + ).toThrowError(InvalidArgumentException); + expect(() => + // @ts-expect-error - intentionally passing invalid input to test error handling + DateHelpers.formatDateLikeToString(12345, DateHelpers.isoDateFormat), + ).toThrowError(InvalidArgumentException); + }); +}); + +describe('DateHelpers output validation', () => { it('date string to Date object conversion test', () => { expect(DateHelpers.parseDateString('10/21/19')).toStrictEqual(output); }); @@ -35,7 +91,7 @@ describe('DateHelpers', () => { ).toBe('10/21/2019 00:00:00'); }); - it('convertDateToMonthDayYearString should format dates correctly', () => { + it('formatDateLikeToUsLocaleMediumDateString should format dates correctly', () => { expect(DateHelpers.formatDateLikeToUsLocaleMediumDateString(output)).toBe( 'Oct 21, 2019', ); @@ -43,4 +99,14 @@ describe('DateHelpers', () => { DateHelpers.formatDateLikeToUsLocaleMediumDateString('2019-10-21'), ).toBe('Oct 21, 2019'); }); + + it('formatDateLikeToString should return an empty string if the input is an empty string', () => { + const emptyString = ''; + expect( + DateHelpers.formatDateLikeToString( + emptyString, + DateHelpers.isoDateFormat, + ), + ).toBe(emptyString); + }); }); diff --git a/packages/date-helpers/package.json b/packages/date-helpers/package.json index a736855..4c71560 100644 --- a/packages/date-helpers/package.json +++ b/packages/date-helpers/package.json @@ -37,11 +37,9 @@ "date-fns": "2.30.0" }, "peerDependencies": { - "@sentry/browser": "7.x", "date-fns": "^2.29.3" }, "devDependencies": { - "@sentry/browser": "7.74.0", "typedoc": "0.25.2", "typedoc-plugin-markdown": "3.16.0" } diff --git a/packages/date-helpers/src/date-helpers.ts b/packages/date-helpers/src/date-helpers.ts index ee6ec31..7960945 100644 --- a/packages/date-helpers/src/date-helpers.ts +++ b/packages/date-helpers/src/date-helpers.ts @@ -1,5 +1,4 @@ import { InvalidArgumentException } from '@rightcapital/exceptions'; -import { captureException, withScope, Scope } from '@sentry/browser'; import { format, isValid, parse, parseISO } from 'date-fns'; export type DateLike = Date | string; @@ -22,21 +21,25 @@ export class DateHelpers { /** Format for date strings in ISO format, e.g., "2023-12-31" */ public static isoDateFormat = 'yyyy-MM-dd'; - private static ensureValidDateInput(input: unknown): asserts input is DateLike { + private static ensureValidDateInput( + input: unknown, + ): asserts input is DateLike { if (input === null || input === undefined) { - throw new InvalidArgumentException(`Input cannot be null or undefined. Received: ${input}`); + throw new InvalidArgumentException( + `Input cannot be null or undefined. Received: ${input}`, + ); } - + if (input instanceof Date) { return; // It's a valid Date object. } - + if (typeof input === 'string') { return; // It's a valid string. } - + throw new InvalidArgumentException( - `Input must be a Date object or a string. Received: ${typeof input} - ${input}` + `Input must be a Date object or a string. Received: ${typeof input} - ${input}`, ); } @@ -79,17 +82,9 @@ export class DateHelpers { }); if (!isValid(output)) { - withScope((scope: Scope) => { - scope.setLevel('error'); - scope.setExtras({ - input, - }); - captureException( - new InvalidArgumentException( - `Invalid Date: unable to parse date string - ${input}. The input might not match any expected formats or is not a valid date.`, - ), - ); - }); + throw new InvalidArgumentException( + `Invalid Date: unable to parse date string - ${input}. The input might not match any expected formats or is not a valid date.`, + ); } return output; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e1550e8..6f84be5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -72,9 +72,6 @@ importers: specifier: 2.30.0 version: 2.30.0 devDependencies: - '@sentry/browser': - specifier: 7.74.0 - version: 7.74.0 typedoc: specifier: 0.25.2 version: 0.25.2(typescript@5.2.2) @@ -1878,59 +1875,6 @@ packages: prettier: 3.0.3 dev: true - /@sentry-internal/tracing@7.74.0: - resolution: {integrity: sha512-JK6IRGgdtZjswGfaGIHNWIThffhOHzVIIaGmglui+VFIzOsOqePjoxaDV0MEvzafxXZD7eWqGE5RGuZ0n6HFVg==} - engines: {node: '>=8'} - dependencies: - '@sentry/core': 7.74.0 - '@sentry/types': 7.74.0 - '@sentry/utils': 7.74.0 - tslib: 2.6.2 - dev: true - - /@sentry/browser@7.74.0: - resolution: {integrity: sha512-Njr8216Z1dFUcl6NqBOk20dssK9SjoVddY74Xq+Q4p3NfXBG3lkMcACXor7SFoJRZXq8CZWGS13Cc5KwViRw4g==} - engines: {node: '>=8'} - dependencies: - '@sentry-internal/tracing': 7.74.0 - '@sentry/core': 7.74.0 - '@sentry/replay': 7.74.0 - '@sentry/types': 7.74.0 - '@sentry/utils': 7.74.0 - tslib: 2.6.2 - dev: true - - /@sentry/core@7.74.0: - resolution: {integrity: sha512-83NRuqn7nDZkSVBN5yJQqcpXDG4yMYiB7TkYUKrGTzBpRy6KUOrkCdybuKk0oraTIGiGSe5WEwCFySiNgR9FzA==} - engines: {node: '>=8'} - dependencies: - '@sentry/types': 7.74.0 - '@sentry/utils': 7.74.0 - tslib: 2.6.2 - dev: true - - /@sentry/replay@7.74.0: - resolution: {integrity: sha512-GoYa3cHTTFVI/J1cnZ0i4X128mf/JljaswO3PWNTe2k3lSHq/LM5aV0keClRvwM0W8hlix8oOTT06nnenOUmmw==} - engines: {node: '>=12'} - dependencies: - '@sentry/core': 7.74.0 - '@sentry/types': 7.74.0 - '@sentry/utils': 7.74.0 - dev: true - - /@sentry/types@7.74.0: - resolution: {integrity: sha512-rI5eIRbUycWjn6s6o3yAjjWtIvYSxZDdnKv5je2EZINfLKcMPj1dkl6wQd2F4y7gLfD/N6Y0wZYIXC3DUdJQQg==} - engines: {node: '>=8'} - dev: true - - /@sentry/utils@7.74.0: - resolution: {integrity: sha512-k3np8nuTPtx5KDODPtULfFln4UXdE56MZCcF19Jv6Ljxf+YN/Ady1+0Oi3e0XoSvFpWNyWnglauT7M65qCE6kg==} - engines: {node: '>=8'} - dependencies: - '@sentry/types': 7.74.0 - tslib: 2.6.2 - dev: true - /@sinclair/typebox@0.27.8: resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} dev: true