@@ -0,0 +1,11 @@ | |||||
root = true | |||||
[*] | |||||
charset = utf-8 | |||||
end_of_line = lf | |||||
indent_size = 2 | |||||
indent_style = space | |||||
insert_final_newline = true | |||||
max_line_length = 120 | |||||
tab_width = 8 | |||||
trim_trailing_whitespace = true |
@@ -0,0 +1,5 @@ | |||||
*.log | |||||
.DS_Store | |||||
node_modules | |||||
dist | |||||
.idea/ |
@@ -0,0 +1,6 @@ | |||||
{ | |||||
"jsxSingleQuote": false, | |||||
"singleQuote": true, | |||||
"semi": false, | |||||
"trailingComma": "es5" | |||||
} |
@@ -0,0 +1,21 @@ | |||||
MIT License | |||||
Copyright (c) 2020 TheoryOfNekomata | |||||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
of this software and associated documentation files (the "Software"), to deal | |||||
in the Software without restriction, including without limitation the rights | |||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
copies of the Software, and to permit persons to whom the Software is | |||||
furnished to do so, subject to the following conditions: | |||||
The above copyright notice and this permission notice shall be included in all | |||||
copies or substantial portions of the Software. | |||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
SOFTWARE. |
@@ -0,0 +1,7 @@ | |||||
# DateTime Commons | |||||
Useful methods for date/time management. | |||||
## License | |||||
[MIT](./LICENSE) |
@@ -0,0 +1,38 @@ | |||||
{ | |||||
"version": "1.0.0", | |||||
"license": "MIT", | |||||
"main": "dist/index.js", | |||||
"typings": "dist/index.d.ts", | |||||
"files": [ | |||||
"dist", | |||||
"src" | |||||
], | |||||
"engines": { | |||||
"node": ">=10" | |||||
}, | |||||
"scripts": { | |||||
"start": "tsdx watch", | |||||
"build": "tsdx build", | |||||
"test": "tsdx test", | |||||
"lint": "tsdx lint", | |||||
"prepare": "tsdx build" | |||||
}, | |||||
"peerDependencies": { | |||||
"date-fns": "^2.16.1" | |||||
}, | |||||
"husky": { | |||||
"hooks": { | |||||
"pre-commit": "tsdx lint" | |||||
} | |||||
}, | |||||
"name": "@theoryofnekomata/datetime-commons", | |||||
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>", | |||||
"module": "dist/datetime-commons.esm.js", | |||||
"devDependencies": { | |||||
"fast-check": "^2.3.0", | |||||
"husky": "^4.3.0", | |||||
"tsdx": "^0.13.3", | |||||
"tslib": "^2.0.1", | |||||
"typescript": "^4.0.2" | |||||
} | |||||
} |
@@ -0,0 +1,5 @@ | |||||
import mediumDateTime from './mediumDateTime' | |||||
export { | |||||
mediumDateTime | |||||
} |
@@ -0,0 +1,96 @@ | |||||
import * as fc from 'fast-check' | |||||
import mediumDateTime from './mediumDateTime' | |||||
// fast-check arbitraries | |||||
const isInvalidDate = (d: Date) => isNaN(d.getTime()) | |||||
const invalidDateString = () => fc.string().filter(s => isInvalidDate(new Date(s))) | |||||
const validDateString = () => fc.string().filter(s => !isInvalidDate(new Date(s))) | |||||
const invalidDate = () => fc.object().filter(o => !(o as unknown as Date)) | |||||
it('should exist', () => { | |||||
expect(mediumDateTime).toBeDefined() | |||||
}) | |||||
it('should be a callable', () => { | |||||
expect(typeof mediumDateTime).toBe('function') | |||||
}) | |||||
it('should accept a minimum of 1 argument', () => { | |||||
expect(mediumDateTime).toHaveLength(1) | |||||
}) | |||||
describe('on numeric arguments', () => { | |||||
describe('on invalid values', () => { | |||||
it('should throw an error on NaN', () => { | |||||
expect(() => mediumDateTime(NaN)).toThrow(RangeError) | |||||
}) | |||||
}) | |||||
describe('on valid values', () => { | |||||
it('should return a formatted string', () => { | |||||
fc.assert( | |||||
fc.property( | |||||
fc.integer(), | |||||
v => { | |||||
expect(typeof mediumDateTime(v)).toBe('string') | |||||
} | |||||
) | |||||
) | |||||
}) | |||||
}) | |||||
}) | |||||
describe('on string arguments', () => { | |||||
describe('on invalid values', () => { | |||||
it('should throw an error', () => { | |||||
fc.assert( | |||||
fc.property( | |||||
invalidDateString(), | |||||
v => { | |||||
expect(() => mediumDateTime(v)).toThrow(RangeError) | |||||
} | |||||
) | |||||
) | |||||
}) | |||||
}) | |||||
describe('on valid values', () => { | |||||
it('should return a formatted string', () => { | |||||
fc.assert( | |||||
fc.property( | |||||
validDateString(), | |||||
v => { | |||||
expect(typeof mediumDateTime(v)).toBe('string') | |||||
} | |||||
) | |||||
) | |||||
}) | |||||
}) | |||||
}) | |||||
describe('on object arguments', () => { | |||||
describe('on non-datelike values', () => { | |||||
it('should throw an error', () => { | |||||
fc.assert( | |||||
fc.property( | |||||
invalidDate(), | |||||
v => { | |||||
expect(() => mediumDateTime(v)).toThrow(RangeError) | |||||
} | |||||
) | |||||
) | |||||
}) | |||||
}) | |||||
}) | |||||
describe('on non-datelike arguments', () => { | |||||
it('should throw an error', () => { | |||||
fc.assert( | |||||
fc.property( | |||||
fc.anything().filter(v => !['number', 'string', 'object'].includes(typeof v)), | |||||
v => { | |||||
expect(() => mediumDateTime(v)).toThrow(TypeError) | |||||
} | |||||
) | |||||
) | |||||
}) | |||||
}) |
@@ -0,0 +1,32 @@ | |||||
import { format, } from 'date-fns' | |||||
type DateLike = Date | string | number | |||||
type MediumDateTime = (d: unknown) => string | |||||
const mediumDateTime: MediumDateTime = dateRaw => { | |||||
const date = dateRaw as DateLike | |||||
let d: Date | |||||
switch (typeof date!) { | |||||
case 'string': | |||||
d = new Date(date) | |||||
break | |||||
case 'number': | |||||
if (isNaN(date as number)) { | |||||
throw RangeError('Argument cannot be NaN.') | |||||
} | |||||
d = new Date(date) | |||||
break | |||||
case 'object': | |||||
if (date! instanceof Date) { | |||||
d = date | |||||
break | |||||
} | |||||
throw RangeError('Invalid argument format.') | |||||
default: | |||||
throw TypeError('Invalid argument type.') | |||||
} | |||||
return format(d, 'yyyy-MM-dd HH:mm') | |||||
} | |||||
export default mediumDateTime |
@@ -0,0 +1,19 @@ | |||||
{ | |||||
"include": ["src", "types"], | |||||
"compilerOptions": { | |||||
"module": "esnext", | |||||
"lib": ["dom", "esnext"], | |||||
"importHelpers": true, | |||||
"declaration": true, | |||||
"sourceMap": true, | |||||
"rootDir": "./src", | |||||
"strict": true, | |||||
"noUnusedLocals": true, | |||||
"noUnusedParameters": true, | |||||
"noImplicitReturns": true, | |||||
"noFallthroughCasesInSwitch": true, | |||||
"moduleResolution": "node", | |||||
"jsx": "react", | |||||
"esModuleInterop": true | |||||
} | |||||
} |