| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 |
2x
2x
2x
2x
29x
2x
40x
455x
40x
8x
40x
2x
4x
2x
2x
| import {
__,
addIndex,
allPass,
ap,
apply,
both,
complement,
equals,
either,
isEmpty,
length,
map,
modulo,
multiply,
nth,
pipe,
replace,
split,
subtract,
sum,
take,
toString,
when,
} from 'ramda'
// CNPJ = String of length 14
// CPF = String of length 11
// ID = CNPJ or CPF
// RAW_ID = ID before special characters cleanup
// DIGIT = Number from 0 to 9
const repeatedNumberRegex = /^(.)\1+$/
const mapIndexed = addIndex(map)
const weightMasks = {
// for cpf
9: [10, 9, 8, 7, 6, 5, 4, 3, 2],
10: [11, 10, 9, 8, 7, 6, 5, 4, 3, 2],
// for cnpj
12: [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2],
13: [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2],
}
// String -> String
const clean = replace(/[^\d]+/g, '')
// [String] -> ID -> Boolean
const hasOnlyOneNumber = subject => repeatedNumberRegex.test(subject)
// ID -> Boolean
const hasValidForm = complement(either(isEmpty, hasOnlyOneNumber))
// [Number] -> ID -> DIGIT
const generateDigitWithMask = mask => pipe(
take(length(mask)),
split(''),
mapIndexed((el, i) => el * mask[i]),
sum,
multiply(__, 10),
modulo(__, 11),
when(
equals(__, 10),
subtract(10, __)
)
)
// Number -> ID -> DIGIT
const digit = index => pipe(
nth(index),
Number
)
// Number -> ID -> Boolean
const validateDigit = index => subject =>
apply(
equals,
ap([
digit(index),
generateDigitWithMask(weightMasks[index], index),
], [subject])
)
// [Number] -> ID -> [Number] -> ID -> Boolean
const validateDigits = pipe(
ap([validateDigit]),
allPass
)
// [Number] -> ID -> Boolean
const validateId = indexes => pipe(
toString,
clean,
both(hasValidForm, validateDigits(indexes))
)
// ID -> Boolean
export const cnpj = validateId([12, 13])
// ID -> Boolean
export const cpf = validateId([9, 10])
|