Skip to content

Commit 623cfc3

Browse files
Merge pull request #186 from sebgroup/develop
New release: Removed moment
2 parents 092d451 + 1b71e56 commit 623cfc3

File tree

26 files changed

+583
-303
lines changed

26 files changed

+583
-303
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
# **Frontend tools**
88

9-
A set of frontend utilities that can be used with any javascript application. It's lightweight and intuitive. The only dependency it has is for [momentjs](https://momentjs.com) when using any utility that deals with dates.
9+
A set of frontend utilities that can be used with any javascript application. It's lightweight and intuitive.
1010

1111
## **Installation**
1212

package-lock.json

Lines changed: 253 additions & 142 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"copy": "cp package.json dist/ && cp README.md dist/",
1111
"lint": "tslint -p tsconfig.json",
1212
"build": "npm run clean && npm run lint && npm run test && npm run build:production",
13-
"test": "npm run clean:test && jest --forceExit --detectOpenHandles",
13+
"pretest": "npm run clean:test",
14+
"test": "cross-env NODE_ICU_DATA=node_modules/full-icu jest --forceExit --detectOpenHandles",
1415
"commit": "git-cz",
1516
"semantic-release": "semantic-release",
1617
"sanitize": "package-lock-sanitizer && git add package-lock.json"
@@ -38,22 +39,23 @@
3839
},
3940
"dependencies": {
4041
"@openapitools/openapi-generator-cli": "^1.0.12-4.3.0",
41-
"commander": "^5.0.0",
42-
"moment": "^2.24.0"
42+
"commander": "^5.0.0"
4343
},
4444
"devDependencies": {
45-
"@commitlint/cli": "^9.0.1",
46-
"@commitlint/config-conventional": "^8.3.4",
45+
"@commitlint/cli": "9.1.1",
46+
"@commitlint/config-conventional": "^9.1.2",
4747
"@semantic-release/changelog": "^5.0.1",
4848
"@types/jest": "^26.0.0",
4949
"@types/node": "^14.0.1",
5050
"case-sensitive-paths-webpack-plugin": "^2.3.0",
5151
"commitizen": "^4.0.3",
5252
"copy-webpack-plugin": "^6.0.1",
53+
"cross-env": "^7.0.2",
5354
"cz-conventional-changelog": "^3.0.2",
5455
"dargs": "^7.0.0",
5556
"fibers": "^5.0.0",
56-
"husky": "^4.0.10",
57+
"full-icu": "^1.3.1",
58+
"husky": "^4.2.5",
5759
"jest": "^25.2.4",
5860
"jsdom": "^16.0.0",
5961
"jsdom-global": "^3.0.2",

src/FormValidator/FormValidator.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import moment, { Moment } from "moment";
21
import { isEmpty } from "../isEmpty/isEmpty";
32
import { isPhoneNumber } from "../isPhoneNumber/isPhoneNumber";
43
import { isEmail } from "../isEmail/isEmail";
54
import { deepCopy } from "../deepCopy/deepCopy";
6-
import { clearTime } from "../clearTime/clearTime";
75
import { isStrongPassword } from "../isStrongPassword/isStrongPassword";
6+
import { isValidDate } from "../isValidDate";
7+
import { isDateBefore } from "../isDateBefore";
8+
import { isDateAfter } from "../isDateAfter";
89

910
export type ValidationSpecs = {
1011
minLength?: number;
@@ -198,20 +199,22 @@ export class FormValidator<T> {
198199
private validateField(value: any, type: ValidationType, specs: ValidationSpecs): ModelFieldError {
199200
let fieldError: ModelFieldError = null;
200201
// Don't validate an empty field if it's not required
201-
if (isEmpty(value) && type !== "required") {
202+
const date: Date = new Date(value)
203+
const empty: boolean = isEmpty(value);
204+
if (empty && type !== "required") {
202205
return null;
203206
}
207+
const valid: boolean = isValidDate(date);
204208
switch (type) {
205-
case "required": return isEmpty(value) ? { errorCode: "empty" } : null;
206-
case "isDate": return value instanceof Date ? null : { errorCode: "invalidDate" };
209+
case "required": return empty ? { errorCode: "empty" } : null;
210+
case "isDate": return valid ? null : { errorCode: "invalidDate" };
207211
case "dateRange":
208-
const date: Moment = moment(value);
209-
if (date.isValid()) {
212+
if (valid) {
210213
if (specs.minDate) {
211-
fieldError = moment(clearTime(date.toDate())).isBefore(clearTime(specs.minDate)) ? { errorCode: "beforeMinDate", specs: { minDate: specs.minDate } } : null;
214+
fieldError = isDateBefore(date, specs.minDate) ? { errorCode: "beforeMinDate", specs: { minDate: specs.minDate } } : null;
212215
}
213216
if (!fieldError && specs.maxDate) {
214-
fieldError = moment(clearTime(date.toDate())).isAfter(clearTime(specs.maxDate)) ? { errorCode: "afterMaxDate", specs: { maxDate: specs.maxDate } } : null;
217+
fieldError = isDateAfter(date, specs.maxDate) ? { errorCode: "afterMaxDate", specs: { maxDate: specs.maxDate } } : null;
215218
}
216219
return fieldError;
217220
} else {

src/clearTime/clearTime.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { clearTime } from ".";
2-
import moment from "moment";
32

43
interface TestCase {
54
statement: string;
@@ -8,7 +7,7 @@ interface TestCase {
87
}
98

109
const getNewDateAtMidnight = (date?: string): Date => {
11-
const newDate = date ? new Date(date) : new Date();
10+
const newDate: Date = date ? new Date(date) : new Date();
1211
newDate.setHours(0, 0, 0, 0);
1312
return newDate;
1413
};

src/dateDiff/dateDiff.test.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,35 @@ interface DifferenceDatesTestCase {
44
statement: string;
55
date1: any;
66
date2: any;
7-
range: any;
7+
range?: any;
88
result?: number;
99
isThrowError?: boolean;
10+
isWarn?: boolean;
1011
}
1112

1213
describe("Util: dateDiff", () => {
14+
let consoleWarn: jasmine.Spy;
15+
beforeEach(() => {
16+
consoleWarn = spyOn(global.console, "warn");
17+
})
1318
const testCases: Array<DifferenceDatesTestCase> = [
14-
{ statement: "Should throw error if firstDate is invalid", date1: "abcd", date2: new Date(), range: "m", isThrowError: true},
15-
{ statement: "Should throw error if secondDate is invalid", date1: new Date(), date2: "new Date()", range: "m", isThrowError: true},
16-
{ statement: "Should return 1", date1: new Date("2019-12-11"), date2: new Date("2019-11-11"), range: "Month", result: 1}
19+
{ statement: "Should throw error if firstDate is invalid", date1: "abcd", date2: new Date(), isThrowError: true},
20+
{ statement: "Should throw error if secondDate is invalid", date1: new Date(), date2: "new Date()", isThrowError: true},
21+
{ statement: "Should throw warning if deprecated argument was used", date1: new Date(), date2: new Date(), range: "year", isWarn: true, result: 0 },
22+
{ statement: "Should return 1", date1: new Date("2020-01-01"), date2: new Date("2020-01-02"), result: 1 },
23+
{ statement: "Should return 1", date1: new Date("2020-01-02"), date2: new Date("2020-01-01"), result: -1 }
1724
];
1825
testCases.map((testCase: DifferenceDatesTestCase) => {
1926
test(`- ${testCase.statement} | params: ${JSON.stringify({date1: testCase.date1, date2: testCase.date2, range: testCase.range})}| result: ${testCase.result}`, () => {
2027
if (testCase.isThrowError) {
2128
expect(() => {
22-
dateDiff(testCase.date1, testCase.date2, testCase.range);
29+
dateDiff(testCase.date1, testCase.date2);
2330
}).toThrow();
2431
} else {
2532
expect(dateDiff(testCase.date1, testCase.date2, testCase.range)).toEqual(testCase.result);
33+
if (testCase.isWarn) {
34+
expect(consoleWarn).toHaveBeenCalledTimes(1);
35+
}
2636
}
2737
});
2838
});

src/dateDiff/dateDiff.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
import moment from "moment";
1+
import { isValidDate } from "../isValidDate";
22

33
/**
44
* Compare and returns the dirrence between two dates
55
* @param {Date} firstDate { date} the first date
66
* @param {Date} secondDate { date } second date to compare against
7-
* @param {moment.DurationInputArg2} range {moment.DurationInputArg2} the range example , months , seconds, h, m, y etc
8-
* @returns {number} The difference based on the range type
7+
* @param {any} range DEPRACATED (This argument is depracated)
8+
* @returns {number} The difference in days
99
*/
10-
export function dateDiff(firstDate: Date, secondDate: Date, range: moment.DurationInputArg2): number {
11-
if (!moment(firstDate).isValid() || !moment(secondDate).isValid()) {
12-
throw new Error("from parameter must be of date type");
10+
export function dateDiff(firstDate: Date, secondDate: Date, range?: any): number {
11+
if (range) {
12+
console.warn("The range argument has been depracated. The range \"day\" will be used instead. \nTo compare units less than day use firstDate.getTime() - secondDate.getTime() to get milliseconds");
1313
}
14-
return moment.utc(firstDate).diff(secondDate, range);
14+
if (!isValidDate(firstDate) || !isValidDate(secondDate)) {
15+
throw new Error("both parameters must be of type Date");
16+
}
17+
return Math.ceil((secondDate.getTime() - firstDate.getTime()) / 1000 / 60 / 60 / 24);
1518
}

src/formatDate/formatDate.test.ts

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,59 @@
11
import { formatDate } from ".";
2-
import { FormatDateOptions } from "./formatDate";
32

4-
interface FormatDateTestCase extends FormatDateOptions {
3+
interface FormatDateTestCase {
54
title: string;
65
date: string | Date;
7-
outputFormat: string;
6+
format?: Intl.DateTimeFormatOptions;
7+
locale?: string;
88
result: string;
99
}
1010

11+
const today: Date = new Date();
12+
1113
describe("Util: formatDate", () => {
1214
const testCases: Array<FormatDateTestCase> = [
1315
{
14-
title: "Should return formatted Date",
16+
title: "Should format to Swedish by default",
1517
date: "7-12-1987",
16-
inputFormat: "D-MM-YYYY",
17-
outputFormat: "MM-DD-YYYY",
18-
result: "12-07-1987"
18+
result: "12 juli 1987",
1919
},
2020
{
21-
title: "Should return null when date is invalid",
21+
title: "Should use other locale when passed (en-US)",
22+
date: "7-12-1987",
23+
locale: "en-US",
24+
result: "July 12, 1987",
25+
},
26+
{
27+
title:
28+
"Should return a string of the input if it's an invalid date",
2229
date: "it's a string",
23-
inputFormat: "D-MM-YYYY",
24-
outputFormat: "MM-DD-YYYY",
25-
result: null
30+
result: "it's a string",
2631
},
2732
{
28-
title: "Should return null if date is invalid and invalid output is undefined",
29-
date: null,
30-
inputFormat: "D-MM-YYYY",
31-
outputFormat: "MM-DD-YYYY",
32-
result: null
33+
title:
34+
"Should correctly format ISO string date without passing input or output formats",
35+
date: "2000-01-23T04:56:07.000+00:00",
36+
result: "23 januari 2000",
3337
},
3438
{
35-
title: "Should return formatted Date based on locale",
36-
date: new Date("12-7-1987"),
37-
inputFormat: "D-MM-YYYY",
38-
outputFormat: "YYYY MMM DD",
39-
locale: "sv-SE",
40-
result: "1987 dec 07"
39+
title: "Should accept date object",
40+
date: new Date(),
41+
format: { day: "numeric", month: "numeric", year: "numeric" },
42+
result: today.toLocaleDateString("sv-SE"),
4143
},
4244
{
43-
title: "Should correctly format ISO string date without passing input or output formats",
44-
date: "2000-01-23T04:56:07.000+00:00",
45-
outputFormat: "DD-MM-YYYY",
46-
result: "23-01-2000"
47-
}
45+
title: "Should accept custom format",
46+
date: new Date(),
47+
format: { day: "numeric", month: "numeric" },
48+
result: `${today.getDate()}/${today.getMonth() + 1}`,
49+
},
4850
];
49-
testCases.map((testCase: FormatDateTestCase) => {
50-
it(testCase.title, () => {
51-
expect(formatDate(testCase.date, testCase.outputFormat, { ...testCase })).toEqual(testCase.result);
52-
});
53-
});
54-
55-
it("Should correctly format ISO string date without passing input formats", () => {
56-
const formatted: string = formatDate("2000-01-23T04:56:07.000+00:00", "DD-MM-YYYY");
57-
expect(formatted).toEqual("23-01-2000");
58-
});
51+
testCases.map(
52+
({ title, date, format, locale, result }: FormatDateTestCase) => {
53+
// prettier-ignore
54+
it(`${title} (Sample: ${String(date)} - Returns: ${result})`, () => {
55+
expect(formatDate(date, format, locale)).toEqual(result);
56+
});
57+
}
58+
);
5959
});

src/formatDate/formatDate.ts

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,22 @@
1-
import moment, { Moment, MomentFormatSpecification, LocaleSpecifier } from "moment";
2-
3-
export interface FormatDateOptions {
4-
inputFormat?: MomentFormatSpecification;
5-
locale?: LocaleSpecifier;
6-
}
7-
81
/**
9-
* Reformats any date string to any desired format
10-
* @param date The date string
11-
* @param outputFormat The desired output format
12-
* @param options input format and locale
13-
* @implements momentjs - refer to momentjs documentation to see the different formats supported
14-
* @note
15-
* Having an input format is critial to insure accuracy if you are not dealing with ISO date string.
16-
* Passing `01-10-2019` might be interpreted as `Jan 10` or `Oct 01` based on locale
17-
* @returns The formatted date string
2+
* Date formatter
3+
* @param date The date object or date string
4+
* @param format The output format
5+
* @param locale The locale. Default is `sv-SE`
6+
* @returns The formattted date or the input if it fails to parse it
187
*/
19-
export function formatDate(date: string | Date, outputFormat: string, options?: FormatDateOptions): string {
20-
if (date) {
21-
let momentDate: Moment = moment(date, options?.inputFormat || null);
22-
if (momentDate.isValid()) {
23-
if (options?.locale) {
24-
momentDate = momentDate.locale(options.locale);
25-
}
26-
return momentDate.format(outputFormat).toString();
27-
}
8+
export function formatDate(
9+
date: string | Date,
10+
format: Intl.DateTimeFormatOptions = {
11+
day: "numeric",
12+
month: "long",
13+
year: "numeric",
14+
},
15+
locale: string = "sv-SE"
16+
): string {
17+
const parsedDate: number = Date.parse(date as any);
18+
if (isNaN(parsedDate)) {
19+
return String(date);
2820
}
29-
return null;
21+
return Intl.DateTimeFormat(locale, format).format(new Date(parsedDate));
3022
}

src/isDateAfter/isDateAfter.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import moment from "moment";
2-
import { clearTime } from "../clearTime/clearTime";
1+
import { isValidDate } from "../isValidDate";
32

43
/**
54
* Compare two dates and return true if the first is greater than the second ignoring the time
@@ -8,5 +7,9 @@ import { clearTime } from "../clearTime/clearTime";
87
* @returns {boolean} True if date `a` comes after than date `b`
98
*/
109
export function isDateAfter(a: Date, b: Date): boolean {
11-
return moment(clearTime(a)).isAfter(moment(clearTime(b)));
10+
if (!isValidDate(a) || !isValidDate(b)) {
11+
return a > b;
12+
} else {
13+
return a.getFullYear() > b.getFullYear() || a.getMonth() > b.getMonth() || a.getDate() > b.getDate();
14+
}
1215
}

0 commit comments

Comments
 (0)