-
-
Notifications
You must be signed in to change notification settings - Fork 216
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into feat-octal-validation
- Loading branch information
Showing
25 changed files
with
613 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { describe, expect, test } from 'vitest'; | ||
import { creditCard } from './creditCard.ts'; | ||
|
||
describe('creditCard', () => { | ||
test('should pass valid cards', () => { | ||
const validate = creditCard(); | ||
|
||
const value1 = '4539 1488 0343 6467'; | ||
expect(validate._parse(value1).output).toBe(value1); | ||
const value2 = '4539 1488 0343 6467'; | ||
expect(validate._parse(value2).output).toBe(value2); | ||
const value3 = '5555 5555 5555 4444'; | ||
expect(validate._parse(value3).output).toBe(value3); | ||
const value4 = '3714 4963 5398 431'; | ||
expect(validate._parse(value4).output).toBe(value4); | ||
const value5 = '3530 1113 3330 0000'; | ||
expect(validate._parse(value5).output).toBe(value5); | ||
const value6 = '4701 3222 1111 1234'; | ||
expect(validate._parse(value6).output).toBe(value6); | ||
const value7 = '4001 9192 5753 7193'; | ||
expect(validate._parse(value7).output).toBe(value7); | ||
const value8 = '4005 5500 0000 0001'; | ||
expect(validate._parse(value8).output).toBe(value8); | ||
const value9 = '3020 4169 3226 43'; | ||
expect(validate._parse(value9).output).toBe(value9); | ||
const value10 = '3021 8047 1965 57'; | ||
expect(validate._parse(value10).output).toBe(value10); | ||
const value11 = '30218047196557'; | ||
expect(validate._parse(value11).output).toBe(value11); | ||
|
||
expect(validate._parse('').issues).toBeTruthy(); | ||
expect(validate._parse('1234 5678 9012 3456').issues).toBeTruthy(); | ||
expect(validate._parse('4532 7597 3454 2975 123').issues).toBeTruthy(); | ||
expect(validate._parse('4532-8940-1234-5678').issues).toBeTruthy(); | ||
expect(validate._parse('3543 0505 5555 5555').issues).toBeTruthy(); | ||
expect(validate._parse('55555 5555 5555 4444').issues).toBeTruthy(); | ||
expect(validate._parse('4111 1111 1111 111').issues).toBeTruthy(); | ||
expect(validate._parse('abcd efgh ijkl mnop').issues).toBeTruthy(); | ||
expect(validate._parse('0000 0000 0000 0000').issues).toBeTruthy(); | ||
}); | ||
|
||
test('should return custom error message', () => { | ||
const error = 'Value is not a valid credit card number!'; | ||
const validate = creditCard(error); | ||
expect(validate._parse('').issues?.[0].message).toBe(error); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import type { BaseValidation, ErrorMessage } from '../../types/index.ts'; | ||
import { actionIssue, actionOutput, isLuhnAlgo } from '../../utils/index.ts'; | ||
|
||
/** | ||
* Credit card validation type. | ||
*/ | ||
export type CreditCardValidation<TInput extends string> = | ||
BaseValidation<TInput> & { | ||
/** | ||
* The validation type. | ||
*/ | ||
type: 'credit_card'; | ||
/** | ||
* The validation function. | ||
*/ | ||
requirement: (input: string) => boolean; | ||
}; | ||
|
||
/** | ||
* Sanitize regex. | ||
*/ | ||
const SANITIZE_REGEX = /[- ]+/gu; | ||
|
||
/** | ||
* Provider regex list. | ||
*/ | ||
const PROVIDER_REGEX_LIST = [ | ||
// American Express | ||
/^3[47]\d{13}$/u, | ||
// Diners Club | ||
/^3(?:0[0-5]|[68]\d)\d{11}$/u, | ||
// Discover | ||
/^6(?:011|5\d{2})\d{12,15}$/u, | ||
// JCB | ||
/^(?:2131|1800|35\d{3})\d{11}$/u, | ||
// Mastercard | ||
/^5[1-5]\d{2}|(222\d|22[3-9]\d|2[3-6]\d{2}|27[01]\d|2720)\d{12}$/u, | ||
// UnionPay | ||
/^(6[27]\d{14}|81\d{14,17})$/u, | ||
// Visa | ||
/^4\d{12}(?:\d{3,6})?$/u, | ||
]; | ||
|
||
/** | ||
* Creates a validation function that validates a [credit card](https://en.wikipedia.org/wiki/Payment_card_number). | ||
* | ||
* @param message The error message. | ||
* | ||
* @returns A validation function. | ||
*/ | ||
export function creditCard<TInput extends string>( | ||
message: ErrorMessage = 'Invalid credit card' | ||
): CreditCardValidation<TInput> { | ||
return { | ||
type: 'credit_card', | ||
async: false, | ||
message, | ||
requirement: (input) => { | ||
// Remove any hyphens and blanks | ||
const sanitized = input.replace(SANITIZE_REGEX, ''); | ||
|
||
// Check if it matches a provider and passes luhn algorithm | ||
return ( | ||
PROVIDER_REGEX_LIST.some((regex) => regex.test(sanitized)) && | ||
isLuhnAlgo(sanitized) | ||
); | ||
}, | ||
_parse(input) { | ||
return !this.requirement(input) | ||
? actionIssue(this.type, this.message, input, this.requirement) | ||
: actionOutput(input); | ||
}, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './creditCard.ts'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
import { describe, expect, test } from 'vitest'; | ||
import { hash } from './hash.ts'; | ||
|
||
describe('hash', () => { | ||
test('should pass only a valid hash string', () => { | ||
const validate = hash(['md5']); | ||
const value1 = 'd41d8cd98f00b204e9800998ecf8427e'; | ||
expect(validate._parse(value1).output).toBe(value1); | ||
|
||
const validate2 = hash(['md4']); | ||
const value2 = 'c93d3bf7a7c4afe94b64e30c2ce39f4f'; | ||
expect(validate2._parse(value2).output).toBe(value2); | ||
|
||
const validate3 = hash(['sha1']); | ||
const value3 = 'd033e22ae348aeb5660fc2140aec35850c4da997'; | ||
expect(validate3._parse(value3).output).toBe(value3); | ||
|
||
const validate4 = hash(['sha256']); | ||
const value4 = | ||
'9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'; | ||
expect(validate4._parse(value4).output).toBe(value4); | ||
|
||
const validate5 = hash(['sha384']); | ||
const value5 = | ||
'38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b'; | ||
expect(validate5._parse(value5).output).toBe(value5); | ||
|
||
const validate6 = hash(['ripemd128']); | ||
const value6 = 'c766f912a89d4ccda88e0cce6a713ef7'; | ||
expect(validate6._parse(value6).output).toBe(value6); | ||
|
||
const validate7 = hash(['ripemd160']); | ||
const value7 = '9c1185a5c5e9fc54612808977ee8f548b2258d31'; | ||
expect(validate7._parse(value7).output).toBe(value7); | ||
|
||
const validate8 = hash(['tiger128']); | ||
const value8 = '7ab383fc29d81f8d0d68e87c69bae5f1'; | ||
expect(validate8._parse(value8).output).toBe(value8); | ||
|
||
const validate9 = hash(['tiger160']); | ||
const value9 = '7ab383fc29d81f8d0d68e87c69bae5f1f18266d7'; | ||
expect(validate9._parse(value9).output).toBe(value9); | ||
|
||
const validate10 = hash(['tiger192']); | ||
const value10 = '4dd00f9e8e8a6a8e3883af1051237c4b47bd2a329b1de1a3'; | ||
expect(validate10._parse(value10).output).toBe(value10); | ||
|
||
const validate11 = hash(['crc32']); | ||
const value11 = '3d08bb77'; | ||
expect(validate11._parse(value11).output).toBe(value11); | ||
|
||
const validate12 = hash(['crc32']); | ||
const value12 = 'd87f7e0c'; | ||
expect(validate12._parse(value12).output).toBe(value12); | ||
|
||
const validate13 = hash(['adler32']); | ||
const value13 = '045d01c1'; | ||
expect(validate13._parse(value13).output).toBe(value13); | ||
|
||
const validate14 = hash(['adler32', 'md5']); | ||
const value14 = '045d01c1'; | ||
expect(validate14._parse(value14).output).toBe(value14); | ||
|
||
const validate15 = hash(['md5', 'sha1', 'sha256']); | ||
const value15 = | ||
'9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'; | ||
expect(validate15._parse(value15).output).toBe(value15); | ||
}); | ||
|
||
test('should reject invalid hash strings', () => { | ||
const validate = hash(['md5']); | ||
|
||
expect(validate._parse('12345').issues).toBeTruthy(); | ||
expect( | ||
validate._parse('zxcvbnmasdfghjkqwertyuiop123456').issues | ||
).toBeTruthy(); | ||
expect( | ||
validate._parse('1234567890abcdef1234567890abcde').issues | ||
).toBeTruthy(); | ||
expect(validate._parse('abcdef&$#').issues).toBeTruthy(); | ||
|
||
const validate2 = hash(['md4']); | ||
expect(validate2._parse('12345').issues).toBeTruthy(); | ||
expect( | ||
validate2._parse('zxcvbnmasdfghjkqwertyuiop123456').issues | ||
).toBeTruthy(); | ||
expect( | ||
validate2._parse('1234567890abcdef1234567890abcde').issues | ||
).toBeTruthy(); | ||
expect(validate2._parse('abcdef&$#').issues).toBeTruthy(); | ||
|
||
const validate3 = hash(['sha1']); | ||
expect(validate3._parse('1234567890abcdef12345').issues).toBeTruthy(); | ||
expect( | ||
validate3._parse('1234567890abcdef1234567890abcdef1234xyz').issues | ||
).toBeTruthy(); | ||
expect( | ||
validate3._parse('1234567890abcdef1234567890abcdef123456789').issues | ||
).toBeTruthy(); | ||
expect(validate3._parse('abcdef&$#').issues).toBeTruthy(); | ||
|
||
const validate4 = hash(['sha256']); | ||
expect( | ||
validate4._parse( | ||
'abcdef1234567890abcdef1234567890abcdef1234567890abcdef123456789' | ||
).issues | ||
).toBeTruthy(); | ||
expect( | ||
validate4._parse( | ||
'abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdefg' | ||
).issues | ||
).toBeTruthy(); | ||
expect( | ||
validate4._parse( | ||
'abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890xyz' | ||
).issues | ||
).toBeTruthy(); | ||
expect(validate4._parse('abcdef&$#').issues).toBeTruthy(); | ||
expect(validate4._parse('abcdef&$#').issues).toBeTruthy(); | ||
|
||
const validate5 = hash(['sha384']); | ||
expect(validate5._parse('abcd').issues).toBeTruthy(); | ||
expect( | ||
validate5._parse( | ||
'abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd' | ||
).issues | ||
).toBeTruthy(); | ||
expect( | ||
validate5._parse( | ||
'abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd123' | ||
).issues | ||
).toBeTruthy(); | ||
expect(validate5._parse('abcdef&$#').issues).toBeTruthy(); | ||
|
||
const validate6 = hash(['sha512']); | ||
expect(validate6._parse('abcdef').issues).toBeTruthy(); | ||
expect( | ||
validate6._parse( | ||
'01de2f2b94f2032e91ecc7bc6f2d5e9c6b74db6ff7b5c56eabfa3b38421a485c3f5f194a5f84e3ac7dc2b3ad4f3c3d8770444010a2336c5e0e16e7a4d58a8f02a' | ||
).issues | ||
).toBeTruthy(); | ||
expect( | ||
validate6._parse( | ||
'01de2f2b94f2032e91ecc7bc6f2d5e9c6b74db6ff7b5c56eabfa3b38421a485c3f5f194a5f84e3ac7dc2b3ad4f3c3d8770444010a2336c5e0e16e7a4d58a8f02g' | ||
).issues | ||
).toBeTruthy(); | ||
expect(validate6._parse('abcdef&$#').issues).toBeTruthy(); | ||
|
||
const validate7 = hash(['crc32']); | ||
expect(validate7._parse('12345').issues).toBeTruthy(); | ||
expect(validate7._parse('3df4b6729').issues).toBeTruthy(); | ||
expect(validate7._parse('3df4b67z').issues).toBeTruthy(); | ||
expect(validate7._parse('3df4b67%').issues).toBeTruthy(); | ||
expect(validate7._parse('abcdef&$#').issues).toBeTruthy(); | ||
|
||
const validate8 = hash(['adler32']); | ||
expect(validate8._parse('12345').issues).toBeTruthy(); | ||
expect(validate8._parse('3df4b6729').issues).toBeTruthy(); | ||
expect(validate8._parse('3df4b67z').issues).toBeTruthy(); | ||
expect(validate8._parse('3df4b67z%$').issues).toBeTruthy(); | ||
expect(validate8._parse('abcdef&$#').issues).toBeTruthy(); | ||
|
||
const validate9 = hash(['md5', 'sha1', 'sha256']); | ||
expect(validate9._parse('12345').issues).toBeTruthy(); | ||
}); | ||
|
||
test('should return custom error message', () => { | ||
const error = 'Value is not a sha1 hash!'; | ||
const validate = hash(['sha1'], error); | ||
expect(validate._parse('sdsds').issues?.[0].message).toBe(error); | ||
}); | ||
}); |
Oops, something went wrong.