Skip to content

Commit

Permalink
Warn about using protected tokens like Y or D
Browse files Browse the repository at this point in the history
Added warning about using protected tokens like `Y` or `D` without passing a corresponding option
  • Loading branch information
kossnocorp committed Jan 5, 2024
1 parent 5a043dc commit a576d6e
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 55 deletions.
41 changes: 17 additions & 24 deletions src/_lib/protectedTokens/index.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,27 @@
const protectedDayOfYearTokens = ["D", "DD"];
const protectedWeekYearTokens = ["YY", "YYYY"];
const dayOfYearTokenRE = /^D+$/;
const weekYearTokenRE = /^Y+$/;

export function isProtectedDayOfYearToken(token: string): boolean {
return protectedDayOfYearTokens.indexOf(token) !== -1;
const throwTokens = ["D", "DD", "YY", "YYYY"];

export function isProtectedDayOfYearToken(token: string) {
return dayOfYearTokenRE.test(token);
}

export function isProtectedWeekYearToken(token: string): boolean {
return protectedWeekYearTokens.indexOf(token) !== -1;
export function isProtectedWeekYearToken(token: string) {
return weekYearTokenRE.test(token);
}

export function throwProtectedError(
export function warnOrThrowProtectedError(
token: string,
format: string,
input: string,
): void {
if (token === "YYYY") {
throw new RangeError(
`Use \`yyyy\` instead of \`YYYY\` (in \`${format}\`) for formatting years to the input \`${input}\`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md`,
);
} else if (token === "YY") {
throw new RangeError(
`Use \`yy\` instead of \`YY\` (in \`${format}\`) for formatting years to the input \`${input}\`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md`,
);
} else if (token === "D") {
throw new RangeError(
`Use \`d\` instead of \`D\` (in \`${format}\`) for formatting days of the month to the input \`${input}\`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md`,
);
} else if (token === "DD") {
throw new RangeError(
`Use \`dd\` instead of \`DD\` (in \`${format}\`) for formatting days of the month to the input \`${input}\`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md`,
);
}
const _message = message(token, format, input);
console.warn(_message);
if (throwTokens.includes(token)) throw new RangeError(_message);
}

function message(token: string, format: string, input: string) {
const subject = token[0] === "Y" ? "years" : "days of the month";
return `Use \`${token.toLowerCase()}\` instead of \`${token}\` (in \`${format}\`) for formatting ${subject} to the input \`${input}\`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md`;
}
6 changes: 3 additions & 3 deletions src/format/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { longFormatters } from "../_lib/format/longFormatters/index.js";
import {
isProtectedDayOfYearToken,
isProtectedWeekYearToken,
throwProtectedError,
warnOrThrowProtectedError,
} from "../_lib/protectedTokens/index.js";

// This RegExp consists of three parts separated by `|`:
Expand Down Expand Up @@ -398,13 +398,13 @@ export function format<DateType extends Date>(
!options?.useAdditionalWeekYearTokens &&
isProtectedWeekYearToken(substring)
) {
throwProtectedError(substring, formatStr, String(date));
warnOrThrowProtectedError(substring, formatStr, String(date));
}
if (
!options?.useAdditionalDayOfYearTokens &&
isProtectedDayOfYearToken(substring)
) {
throwProtectedError(substring, formatStr, String(date));
warnOrThrowProtectedError(substring, formatStr, String(date));
}
return formatter(
originalDate,
Expand Down
186 changes: 161 additions & 25 deletions src/format/test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
/* eslint-env mocha */

import assert from "assert";
import { describe, it } from "vitest";
import {
type SpyInstance,
afterEach,
beforeEach,
describe,
expect,
it,
vi,
} from "vitest";
import sinon from "sinon";
import { format } from "./index.js";

Expand Down Expand Up @@ -764,12 +772,7 @@ describe("format", () => {

describe("useAdditionalWeekYearTokens and useAdditionalDayOfYearTokens options", () => {
it("throws an error if D token is used", () => {
try {
format.bind(null, date, "yyyy-MM-D");
} catch (e) {
assert(e instanceof RangeError);
assert(e.message.startsWith("Use `d` instead of `D`"));
}
expect(() => format(date, "yyyy-MM-D")).toThrow("Use `d` instead of `D`");
});

it("allows D token if useAdditionalDayOfYearTokens is set to true", () => {
Expand All @@ -780,12 +783,9 @@ describe("format", () => {
});

it("throws an error if DD token is used", () => {
try {
format.bind(null, date, "yyyy-MM-DD");
} catch (e) {
assert(e instanceof RangeError);
assert(e.message.startsWith("Use `dd` instead of `DD`"));
}
expect(() => format(date, "yyyy-MM-DD")).toThrow(
"Use `dd` instead of `DD`",
);
});

it("allows DD token if useAdditionalDayOfYearTokens is set to true", () => {
Expand All @@ -796,12 +796,9 @@ describe("format", () => {
});

it("throws an error if YY token is used", () => {
try {
format.bind(null, date, "YY-MM-dd");
} catch (e) {
assert(e instanceof RangeError);
assert(e.message.startsWith("Use `yy` instead of `YY`"));
}
expect(() => format(date, "YY-MM-dd")).toThrow(
"Use `yy` instead of `YY`",
);
});

it("allows YY token if useAdditionalWeekYearTokens is set to true", () => {
Expand All @@ -812,12 +809,9 @@ describe("format", () => {
});

it("throws an error if YYYY token is used", () => {
try {
format.bind(null, date, "YYYY-MM-dd");
} catch (e) {
assert(e instanceof RangeError);
assert(e.message.startsWith("Use `yyyy` instead of `YYYY`"));
}
expect(() => format(date, "YYYY-MM-dd")).toThrow(
"Use `yyyy` instead of `YYYY`",
);
});

it("allows YYYY token if useAdditionalWeekYearTokens is set to true", () => {
Expand All @@ -826,5 +820,147 @@ describe("format", () => {
});
assert.deepStrictEqual(result, "1986-04-04");
});

describe("console.warn", () => {
let warn: SpyInstance;

beforeEach(() => {
warn = vi.spyOn(console, "warn").mockImplementation(() => undefined);
});

afterEach(() => {
warn.mockRestore();
});

it('warns if "D" token is used', () => {
try {
format(date, "yyyy-MM-D");
} catch (_) {
// Ignore the error
}
expect(warn).toBeCalledWith(
"Use `d` instead of `D` (in `yyyy-MM-D`) for formatting days of the month to the input `" +
date +
"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md",
);
});

it('warns if "DD" token is used', () => {
try {
format(date, "yyyy-MM-DD");
} catch (_) {
// Ignore the error
}
expect(warn).toBeCalledWith(
"Use `dd` instead of `DD` (in `yyyy-MM-DD`) for formatting days of the month to the input `" +
date +
"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md",
);
});

it('warns if "DDD" token is used', () => {
try {
format(date, "yyyy-MM-DDD");
} catch (_) {
// Ignore the error
}
expect(warn).toBeCalledWith(
"Use `ddd` instead of `DDD` (in `yyyy-MM-DDD`) for formatting days of the month to the input `" +
date +
"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md",
);
});

it('warns if "DDDD" token is used', () => {
try {
format(date, "yyyy-MM-DDDD");
} catch (_) {
// Ignore the error
}
expect(warn).toBeCalledWith(
"Use `dddd` instead of `DDDD` (in `yyyy-MM-DDDD`) for formatting days of the month to the input `" +
date +
"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md",
);
});

it('warns if "DDDDD" token is used', () => {
try {
format(date, "yyyy-MM-DDDDD");
} catch (_) {
// Ignore the error
}
expect(warn).toBeCalledWith(
"Use `ddddd` instead of `DDDDD` (in `yyyy-MM-DDDDD`) for formatting days of the month to the input `" +
date +
"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md",
);
});

it('warns if "Y" token is used', () => {
try {
format(date, "Y-MM-dd");
} catch (_) {
// Ignore the error
}
expect(warn).toBeCalledWith(
"Use `y` instead of `Y` (in `Y-MM-dd`) for formatting years to the input `" +
date +
"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md",
);
});

it('warns if "YY" token is used', () => {
try {
format(date, "YY-MM-dd");
} catch (_) {
// Ignore the error
}
expect(warn).toBeCalledWith(
"Use `yy` instead of `YY` (in `YY-MM-dd`) for formatting years to the input `" +
date +
"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md",
);
});

it('warns if "YYY" token is used', () => {
try {
format(date, "YYY-MM-dd");
} catch (_) {
// Ignore the error
}
expect(warn).toBeCalledWith(
"Use `yyy` instead of `YYY` (in `YYY-MM-dd`) for formatting years to the input `" +
date +
"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md",
);
});

it('warns if "YYYY" token is used', () => {
try {
format(date, "YYYY-MM-dd");
} catch (_) {
// Ignore the error
}
expect(warn).toBeCalledWith(
"Use `yyyy` instead of `YYYY` (in `YYYY-MM-dd`) for formatting years to the input `" +
date +
"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md",
);
});

it('warns if "YYYYY" token is used', () => {
try {
format(date, "YYYYY-MM-dd");
} catch (_) {
// Ignore the error
}
expect(warn).toBeCalledWith(
"Use `yyyyy` instead of `YYYYY` (in `YYYYY-MM-dd`) for formatting years to the input `" +
date +
"`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md",
);
});
});
});
});
6 changes: 3 additions & 3 deletions src/parse/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { longFormatters } from "../_lib/format/longFormatters/index.js";
import {
isProtectedDayOfYearToken,
isProtectedWeekYearToken,
throwProtectedError,
warnOrThrowProtectedError,
} from "../_lib/protectedTokens/index.js";
import { parsers } from "./_lib/parsers/index.js";
import type { Setter } from "./_lib/Setter.js";
Expand Down Expand Up @@ -409,13 +409,13 @@ export function parse<DateType extends Date>(
!options?.useAdditionalWeekYearTokens &&
isProtectedWeekYearToken(token)
) {
throwProtectedError(token, formatStr, dateStr);
warnOrThrowProtectedError(token, formatStr, dateStr);
}
if (
!options?.useAdditionalDayOfYearTokens &&
isProtectedDayOfYearToken(token)
) {
throwProtectedError(token, formatStr, dateStr);
warnOrThrowProtectedError(token, formatStr, dateStr);
}

const firstCharacter = token[0];
Expand Down

0 comments on commit a576d6e

Please sign in to comment.