@azify/cpf-cnpj 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -0
- package/dist/index.d.mts +100 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.js +167 -0
- package/dist/index.mjs +140 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# @azify/cpf-cnpj
|
|
2
|
+
|
|
3
|
+
Validation, formatting, and comparison of CPF/CNPJ, including support for alphanumeric CNPJ (effective Jul/2026).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
npm install @azify/cpf-cnpj
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { cpf, cnpj, taxpayer } from '@azify/cpf-cnpj'
|
|
15
|
+
|
|
16
|
+
cpf.isValid('529.982.247-25') // true
|
|
17
|
+
cpf.isValid('111.111.111-11') // false (invalid check digit)
|
|
18
|
+
cpf.format('52998224725') // '529.982.247-25'
|
|
19
|
+
cpf.format('123') // null (doesn't have 11 digits)
|
|
20
|
+
cpf.compare(a, b) // true | false | null (null if a or b is invalid)
|
|
21
|
+
cpf.clean('529.982.247-25') // '52998224725'
|
|
22
|
+
|
|
23
|
+
cnpj.isValid('11.444.777/0001-61') // true
|
|
24
|
+
cnpj.isValid('AB123CD4501E66') // true (alphanumeric CNPJ)
|
|
25
|
+
cnpj.isValid('11.111.111/1111-11') // false (invalid check digit)
|
|
26
|
+
cnpj.format('11444777000161') // '11.444.777/0001-61'
|
|
27
|
+
cnpj.format('AB123CD4501E66') // 'AB.123.CD4/501E-66'
|
|
28
|
+
cnpj.format('123') // null (doesn't have 14 positions)
|
|
29
|
+
cnpj.compare(a, b) // true | false | null (null if a or b is invalid)
|
|
30
|
+
cnpj.clean('11.444.777/0001-61') // '11444777000161'
|
|
31
|
+
|
|
32
|
+
taxpayer.type('52998224725') // 'cpf' | 'cnpj' | null (null if it's not a valid CPF or CNPJ)
|
|
33
|
+
taxpayer.isValid('invalid') // false
|
|
34
|
+
taxpayer.format('invalid') // null
|
|
35
|
+
taxpayer.compare(a, b) // true | false | null (null if a or b is invalid)
|
|
36
|
+
taxpayer.clean(value) // normalizes CPF or CNPJ (alphanumeric)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### About `null` returns
|
|
40
|
+
|
|
41
|
+
- `format` returns `null` when the value doesn't have the expected length (CPF: 11 digits; CNPJ: 14 positions). It **does not** check the verification digit — a well-formed CPF/CNPJ with an invalid checksum is still formatted (e.g., `cpf.format('00000000000')` returns `'000.000.000-00'`). Use `isValid` when you need to guarantee the document is actually valid.
|
|
42
|
+
- `compare` returns `null` (not `false`) when **either** of the two values is invalid — this lets you distinguish "different documents" from "cannot compare".
|
|
43
|
+
- `taxpayer.type` returns `null` when the value is neither a valid CPF nor a valid CNPJ (it doesn't distinguish "not a CPF" from "not a CNPJ").
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CPF/CNPJ utilities.
|
|
3
|
+
*
|
|
4
|
+
* Exposes the `cpf` / `cnpj` objects (with `isValid`, `format`, `compare`, `clean`),
|
|
5
|
+
* plus a `taxpayer` object for documents of unknown type (`type`, `isValid`, `format`, `compare`,
|
|
6
|
+
* `clean`). CNPJ validation and formatting also support the alphanumeric CNPJ
|
|
7
|
+
* (effective Jul/2026). CPF stays numeric.
|
|
8
|
+
*/
|
|
9
|
+
declare function keepDigits(value: string): string;
|
|
10
|
+
declare function keepAlphanumeric(value: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* @description Validates a CPF (always numeric), including the check digits.
|
|
13
|
+
* @param value - CPF with or without mask
|
|
14
|
+
* @returns true if the CPF is valid
|
|
15
|
+
*/
|
|
16
|
+
declare function isValidCpf(value: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* @description Masks a CPF as `XXX.XXX.XXX-XX`.
|
|
19
|
+
* @param value - CPF with or without mask
|
|
20
|
+
* @returns Masked CPF, or null if it is not a well-formed (11-digit) CPF
|
|
21
|
+
*/
|
|
22
|
+
declare function formatCpf(value: string): string | null;
|
|
23
|
+
/**
|
|
24
|
+
* @description Compares two CPFs, returning null if either is invalid.
|
|
25
|
+
* @param cpf1 - First CPF to compare
|
|
26
|
+
* @param cpf2 - Second CPF to compare
|
|
27
|
+
* @returns true if equal, false if different, null if either CPF is invalid
|
|
28
|
+
*/
|
|
29
|
+
declare function compareCpf(cpf1: string, cpf2: string): boolean | null;
|
|
30
|
+
/**
|
|
31
|
+
* @description Validates a numeric or alphanumeric CNPJ, including the check
|
|
32
|
+
* digits (mod-11 calc with character value = ASCII - 48).
|
|
33
|
+
* @param value - CNPJ with or without mask
|
|
34
|
+
* @returns true if the CNPJ is valid
|
|
35
|
+
*/
|
|
36
|
+
declare function isValidCnpj(value: string): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* @description Masks a numeric or alphanumeric CNPJ as `XX.XXX.XXX/XXXX-XX`.
|
|
39
|
+
* @param value - CNPJ with or without mask
|
|
40
|
+
* @returns Masked CNPJ, or null if it is not a well-formed (14-position) CNPJ
|
|
41
|
+
*/
|
|
42
|
+
declare function formatCnpj(value: string): string | null;
|
|
43
|
+
/**
|
|
44
|
+
* @description Compares two CNPJs, returning null if either is invalid.
|
|
45
|
+
* @param cnpj1 - First CNPJ to compare
|
|
46
|
+
* @param cnpj2 - Second CNPJ to compare
|
|
47
|
+
* @returns true if equal, false if different, null if either CNPJ is invalid
|
|
48
|
+
*/
|
|
49
|
+
declare function compareCnpj(cnpj1: string, cnpj2: string): boolean | null;
|
|
50
|
+
/**
|
|
51
|
+
* @description Compare two CPF or CNPJ
|
|
52
|
+
* @param taxpayer1 - CPF or CNPJ to compare
|
|
53
|
+
* @param taxpayer2 - CPF or CNPJ to compare
|
|
54
|
+
* @returns true if CPF or CNPJ are equal, false if not, null if either is invalid
|
|
55
|
+
*/
|
|
56
|
+
declare function compareTaxpayer(taxpayer1: string, taxpayer2: string): boolean | null;
|
|
57
|
+
/**
|
|
58
|
+
* @description Determines the type of a taxpayer document, validating it.
|
|
59
|
+
*
|
|
60
|
+
* Returns the type in lowercase by convention within this module (and the
|
|
61
|
+
* blacklist subsystem that consumes it). This is intentionally distinct from
|
|
62
|
+
* the uppercase Pix key-type enum (`'CPF' | 'CNPJ' | 'EVP' | ...`), which is a
|
|
63
|
+
* different concept — do not compare the two directly.
|
|
64
|
+
* @param cpfCnpj - CPF or CNPJ to inspect
|
|
65
|
+
* @returns 'cpf' if a valid CPF, 'cnpj' if a valid CNPJ, null if neither
|
|
66
|
+
*/
|
|
67
|
+
declare function getTaxpayerType(cpfCnpj: string): 'cpf' | 'cnpj' | null;
|
|
68
|
+
/**
|
|
69
|
+
* @description Validates a taxpayer document (CPF or CNPJ).
|
|
70
|
+
* @param cpfCnpj - CPF or CNPJ to validate
|
|
71
|
+
* @returns true if it is a valid CPF or CNPJ
|
|
72
|
+
*/
|
|
73
|
+
declare function isValidTaxpayer(cpfCnpj: string): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* @description Format CPF or CNPJ
|
|
76
|
+
* @param cpfCnpj - CPF or CNPJ to format
|
|
77
|
+
* @returns Formatted CPF or CNPJ or null if CPF or CNPJ is invalid
|
|
78
|
+
*/
|
|
79
|
+
declare function formatTaxpayer(cpfCnpj: string): string | null;
|
|
80
|
+
declare const cpf: {
|
|
81
|
+
isValid: typeof isValidCpf;
|
|
82
|
+
format: typeof formatCpf;
|
|
83
|
+
compare: typeof compareCpf;
|
|
84
|
+
clean: typeof keepDigits;
|
|
85
|
+
};
|
|
86
|
+
declare const cnpj: {
|
|
87
|
+
isValid: typeof isValidCnpj;
|
|
88
|
+
format: typeof formatCnpj;
|
|
89
|
+
compare: typeof compareCnpj;
|
|
90
|
+
clean: typeof keepAlphanumeric;
|
|
91
|
+
};
|
|
92
|
+
declare const taxpayer: {
|
|
93
|
+
type: typeof getTaxpayerType;
|
|
94
|
+
isValid: typeof isValidTaxpayer;
|
|
95
|
+
format: typeof formatTaxpayer;
|
|
96
|
+
compare: typeof compareTaxpayer;
|
|
97
|
+
clean: typeof keepAlphanumeric;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export { cnpj, cpf, taxpayer };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CPF/CNPJ utilities.
|
|
3
|
+
*
|
|
4
|
+
* Exposes the `cpf` / `cnpj` objects (with `isValid`, `format`, `compare`, `clean`),
|
|
5
|
+
* plus a `taxpayer` object for documents of unknown type (`type`, `isValid`, `format`, `compare`,
|
|
6
|
+
* `clean`). CNPJ validation and formatting also support the alphanumeric CNPJ
|
|
7
|
+
* (effective Jul/2026). CPF stays numeric.
|
|
8
|
+
*/
|
|
9
|
+
declare function keepDigits(value: string): string;
|
|
10
|
+
declare function keepAlphanumeric(value: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* @description Validates a CPF (always numeric), including the check digits.
|
|
13
|
+
* @param value - CPF with or without mask
|
|
14
|
+
* @returns true if the CPF is valid
|
|
15
|
+
*/
|
|
16
|
+
declare function isValidCpf(value: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* @description Masks a CPF as `XXX.XXX.XXX-XX`.
|
|
19
|
+
* @param value - CPF with or without mask
|
|
20
|
+
* @returns Masked CPF, or null if it is not a well-formed (11-digit) CPF
|
|
21
|
+
*/
|
|
22
|
+
declare function formatCpf(value: string): string | null;
|
|
23
|
+
/**
|
|
24
|
+
* @description Compares two CPFs, returning null if either is invalid.
|
|
25
|
+
* @param cpf1 - First CPF to compare
|
|
26
|
+
* @param cpf2 - Second CPF to compare
|
|
27
|
+
* @returns true if equal, false if different, null if either CPF is invalid
|
|
28
|
+
*/
|
|
29
|
+
declare function compareCpf(cpf1: string, cpf2: string): boolean | null;
|
|
30
|
+
/**
|
|
31
|
+
* @description Validates a numeric or alphanumeric CNPJ, including the check
|
|
32
|
+
* digits (mod-11 calc with character value = ASCII - 48).
|
|
33
|
+
* @param value - CNPJ with or without mask
|
|
34
|
+
* @returns true if the CNPJ is valid
|
|
35
|
+
*/
|
|
36
|
+
declare function isValidCnpj(value: string): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* @description Masks a numeric or alphanumeric CNPJ as `XX.XXX.XXX/XXXX-XX`.
|
|
39
|
+
* @param value - CNPJ with or without mask
|
|
40
|
+
* @returns Masked CNPJ, or null if it is not a well-formed (14-position) CNPJ
|
|
41
|
+
*/
|
|
42
|
+
declare function formatCnpj(value: string): string | null;
|
|
43
|
+
/**
|
|
44
|
+
* @description Compares two CNPJs, returning null if either is invalid.
|
|
45
|
+
* @param cnpj1 - First CNPJ to compare
|
|
46
|
+
* @param cnpj2 - Second CNPJ to compare
|
|
47
|
+
* @returns true if equal, false if different, null if either CNPJ is invalid
|
|
48
|
+
*/
|
|
49
|
+
declare function compareCnpj(cnpj1: string, cnpj2: string): boolean | null;
|
|
50
|
+
/**
|
|
51
|
+
* @description Compare two CPF or CNPJ
|
|
52
|
+
* @param taxpayer1 - CPF or CNPJ to compare
|
|
53
|
+
* @param taxpayer2 - CPF or CNPJ to compare
|
|
54
|
+
* @returns true if CPF or CNPJ are equal, false if not, null if either is invalid
|
|
55
|
+
*/
|
|
56
|
+
declare function compareTaxpayer(taxpayer1: string, taxpayer2: string): boolean | null;
|
|
57
|
+
/**
|
|
58
|
+
* @description Determines the type of a taxpayer document, validating it.
|
|
59
|
+
*
|
|
60
|
+
* Returns the type in lowercase by convention within this module (and the
|
|
61
|
+
* blacklist subsystem that consumes it). This is intentionally distinct from
|
|
62
|
+
* the uppercase Pix key-type enum (`'CPF' | 'CNPJ' | 'EVP' | ...`), which is a
|
|
63
|
+
* different concept — do not compare the two directly.
|
|
64
|
+
* @param cpfCnpj - CPF or CNPJ to inspect
|
|
65
|
+
* @returns 'cpf' if a valid CPF, 'cnpj' if a valid CNPJ, null if neither
|
|
66
|
+
*/
|
|
67
|
+
declare function getTaxpayerType(cpfCnpj: string): 'cpf' | 'cnpj' | null;
|
|
68
|
+
/**
|
|
69
|
+
* @description Validates a taxpayer document (CPF or CNPJ).
|
|
70
|
+
* @param cpfCnpj - CPF or CNPJ to validate
|
|
71
|
+
* @returns true if it is a valid CPF or CNPJ
|
|
72
|
+
*/
|
|
73
|
+
declare function isValidTaxpayer(cpfCnpj: string): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* @description Format CPF or CNPJ
|
|
76
|
+
* @param cpfCnpj - CPF or CNPJ to format
|
|
77
|
+
* @returns Formatted CPF or CNPJ or null if CPF or CNPJ is invalid
|
|
78
|
+
*/
|
|
79
|
+
declare function formatTaxpayer(cpfCnpj: string): string | null;
|
|
80
|
+
declare const cpf: {
|
|
81
|
+
isValid: typeof isValidCpf;
|
|
82
|
+
format: typeof formatCpf;
|
|
83
|
+
compare: typeof compareCpf;
|
|
84
|
+
clean: typeof keepDigits;
|
|
85
|
+
};
|
|
86
|
+
declare const cnpj: {
|
|
87
|
+
isValid: typeof isValidCnpj;
|
|
88
|
+
format: typeof formatCnpj;
|
|
89
|
+
compare: typeof compareCnpj;
|
|
90
|
+
clean: typeof keepAlphanumeric;
|
|
91
|
+
};
|
|
92
|
+
declare const taxpayer: {
|
|
93
|
+
type: typeof getTaxpayerType;
|
|
94
|
+
isValid: typeof isValidTaxpayer;
|
|
95
|
+
format: typeof formatTaxpayer;
|
|
96
|
+
compare: typeof compareTaxpayer;
|
|
97
|
+
clean: typeof keepAlphanumeric;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export { cnpj, cpf, taxpayer };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
cnpj: () => cnpj,
|
|
24
|
+
cpf: () => cpf,
|
|
25
|
+
taxpayer: () => taxpayer
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
function keepDigits(value) {
|
|
29
|
+
return String(value).replace(/\D/g, "");
|
|
30
|
+
}
|
|
31
|
+
function keepAlphanumeric(value) {
|
|
32
|
+
return String(value).toUpperCase().replace(/[^0-9A-Z]/g, "");
|
|
33
|
+
}
|
|
34
|
+
var CPF_LENGTH = 11;
|
|
35
|
+
var CPF_CHECK_DIGITS = 2;
|
|
36
|
+
function cpfCheckDigit(base) {
|
|
37
|
+
const length = base.length;
|
|
38
|
+
const sum = base.split("").reduce((acc, digit, i) => acc + Number(digit) * (length + 1 - i), 0);
|
|
39
|
+
const remainder = sum % 11;
|
|
40
|
+
return remainder < 2 ? 0 : 11 - remainder;
|
|
41
|
+
}
|
|
42
|
+
function isValidCpf(value) {
|
|
43
|
+
if (/[A-Za-z]/.test(String(value))) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
const clean = keepDigits(value);
|
|
47
|
+
if (clean.length !== CPF_LENGTH) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
if (/^(\d)\1{10}$/.test(clean)) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
const baseLength = CPF_LENGTH - CPF_CHECK_DIGITS;
|
|
54
|
+
const base = clean.slice(0, baseLength);
|
|
55
|
+
const dv1 = cpfCheckDigit(base);
|
|
56
|
+
const dv2 = cpfCheckDigit(base + String(dv1));
|
|
57
|
+
return clean.slice(baseLength) === `${dv1}${dv2}`;
|
|
58
|
+
}
|
|
59
|
+
function formatCpf(value) {
|
|
60
|
+
const clean = keepDigits(value);
|
|
61
|
+
if (clean.length !== CPF_LENGTH) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return clean.replace(/^(\d{3})(\d{3})(\d{3})(\d{2})$/, "$1.$2.$3-$4");
|
|
65
|
+
}
|
|
66
|
+
function compareCpf(cpf1, cpf2) {
|
|
67
|
+
if (!isValidCpf(cpf1) || !isValidCpf(cpf2)) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
return keepDigits(cpf1) === keepDigits(cpf2);
|
|
71
|
+
}
|
|
72
|
+
var CNPJ_LENGTH = 14;
|
|
73
|
+
var CNPJ_CHECK_DIGITS = 2;
|
|
74
|
+
var CNPJ_FIRST_DV_WEIGHTS = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
75
|
+
var CNPJ_SECOND_DV_WEIGHTS = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
76
|
+
function cnpjCharValue(char) {
|
|
77
|
+
return char.charCodeAt(0) - 48;
|
|
78
|
+
}
|
|
79
|
+
function cnpjCheckDigit(base, weights) {
|
|
80
|
+
const sum = base.split("").reduce((acc, char, i) => acc + cnpjCharValue(char) * weights[i], 0);
|
|
81
|
+
const remainder = sum % 11;
|
|
82
|
+
return remainder < 2 ? 0 : 11 - remainder;
|
|
83
|
+
}
|
|
84
|
+
function isValidCnpj(value) {
|
|
85
|
+
const clean = keepAlphanumeric(value);
|
|
86
|
+
if (clean.length !== CNPJ_LENGTH || !/^[0-9A-Z]{12}[0-9]{2}$/.test(clean)) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
if (/^(.)\1{13}$/.test(clean)) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
const baseLength = CNPJ_LENGTH - CNPJ_CHECK_DIGITS;
|
|
93
|
+
const base = clean.slice(0, baseLength);
|
|
94
|
+
const dv1 = cnpjCheckDigit(base, CNPJ_FIRST_DV_WEIGHTS);
|
|
95
|
+
const dv2 = cnpjCheckDigit(base + String(dv1), CNPJ_SECOND_DV_WEIGHTS);
|
|
96
|
+
return clean.slice(baseLength) === `${dv1}${dv2}`;
|
|
97
|
+
}
|
|
98
|
+
function formatCnpj(value) {
|
|
99
|
+
const clean = keepAlphanumeric(value);
|
|
100
|
+
if (!/^[0-9A-Z]{12}[0-9]{2}$/.test(clean)) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
return clean.replace(
|
|
104
|
+
/^([0-9A-Z]{2})([0-9A-Z]{3})([0-9A-Z]{3})([0-9A-Z]{4})(\d{2})$/,
|
|
105
|
+
"$1.$2.$3/$4-$5"
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
function compareCnpj(cnpj1, cnpj2) {
|
|
109
|
+
if (!isValidCnpj(cnpj1) || !isValidCnpj(cnpj2)) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
return keepAlphanumeric(cnpj1) === keepAlphanumeric(cnpj2);
|
|
113
|
+
}
|
|
114
|
+
function compareTaxpayer(taxpayer1, taxpayer2) {
|
|
115
|
+
if (!getTaxpayerType(taxpayer1) || !getTaxpayerType(taxpayer2)) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
return keepAlphanumeric(taxpayer1) === keepAlphanumeric(taxpayer2);
|
|
119
|
+
}
|
|
120
|
+
function getTaxpayerType(cpfCnpj) {
|
|
121
|
+
if (isValidCpf(cpfCnpj)) {
|
|
122
|
+
return "cpf";
|
|
123
|
+
}
|
|
124
|
+
if (isValidCnpj(cpfCnpj)) {
|
|
125
|
+
return "cnpj";
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
function isValidTaxpayer(cpfCnpj) {
|
|
130
|
+
return Boolean(getTaxpayerType(cpfCnpj));
|
|
131
|
+
}
|
|
132
|
+
function formatTaxpayer(cpfCnpj) {
|
|
133
|
+
const type = getTaxpayerType(cpfCnpj);
|
|
134
|
+
if (type === "cpf") {
|
|
135
|
+
return formatCpf(cpfCnpj);
|
|
136
|
+
} else if (type === "cnpj") {
|
|
137
|
+
return formatCnpj(cpfCnpj);
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
var cpf = {
|
|
142
|
+
isValid: isValidCpf,
|
|
143
|
+
format: formatCpf,
|
|
144
|
+
compare: compareCpf,
|
|
145
|
+
clean: keepDigits
|
|
146
|
+
};
|
|
147
|
+
var cnpj = {
|
|
148
|
+
isValid: isValidCnpj,
|
|
149
|
+
format: formatCnpj,
|
|
150
|
+
compare: compareCnpj,
|
|
151
|
+
clean: keepAlphanumeric
|
|
152
|
+
};
|
|
153
|
+
var taxpayer = {
|
|
154
|
+
type: getTaxpayerType,
|
|
155
|
+
isValid: isValidTaxpayer,
|
|
156
|
+
format: formatTaxpayer,
|
|
157
|
+
compare: compareTaxpayer,
|
|
158
|
+
// unknown type → alphanumeric is the safe normalization: works for both a
|
|
159
|
+
// numeric CPF and an alphanumeric CNPJ, and their lengths never collide
|
|
160
|
+
clean: keepAlphanumeric
|
|
161
|
+
};
|
|
162
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
163
|
+
0 && (module.exports = {
|
|
164
|
+
cnpj,
|
|
165
|
+
cpf,
|
|
166
|
+
taxpayer
|
|
167
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
function keepDigits(value) {
|
|
3
|
+
return String(value).replace(/\D/g, "");
|
|
4
|
+
}
|
|
5
|
+
function keepAlphanumeric(value) {
|
|
6
|
+
return String(value).toUpperCase().replace(/[^0-9A-Z]/g, "");
|
|
7
|
+
}
|
|
8
|
+
var CPF_LENGTH = 11;
|
|
9
|
+
var CPF_CHECK_DIGITS = 2;
|
|
10
|
+
function cpfCheckDigit(base) {
|
|
11
|
+
const length = base.length;
|
|
12
|
+
const sum = base.split("").reduce((acc, digit, i) => acc + Number(digit) * (length + 1 - i), 0);
|
|
13
|
+
const remainder = sum % 11;
|
|
14
|
+
return remainder < 2 ? 0 : 11 - remainder;
|
|
15
|
+
}
|
|
16
|
+
function isValidCpf(value) {
|
|
17
|
+
if (/[A-Za-z]/.test(String(value))) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
const clean = keepDigits(value);
|
|
21
|
+
if (clean.length !== CPF_LENGTH) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
if (/^(\d)\1{10}$/.test(clean)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
const baseLength = CPF_LENGTH - CPF_CHECK_DIGITS;
|
|
28
|
+
const base = clean.slice(0, baseLength);
|
|
29
|
+
const dv1 = cpfCheckDigit(base);
|
|
30
|
+
const dv2 = cpfCheckDigit(base + String(dv1));
|
|
31
|
+
return clean.slice(baseLength) === `${dv1}${dv2}`;
|
|
32
|
+
}
|
|
33
|
+
function formatCpf(value) {
|
|
34
|
+
const clean = keepDigits(value);
|
|
35
|
+
if (clean.length !== CPF_LENGTH) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
return clean.replace(/^(\d{3})(\d{3})(\d{3})(\d{2})$/, "$1.$2.$3-$4");
|
|
39
|
+
}
|
|
40
|
+
function compareCpf(cpf1, cpf2) {
|
|
41
|
+
if (!isValidCpf(cpf1) || !isValidCpf(cpf2)) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return keepDigits(cpf1) === keepDigits(cpf2);
|
|
45
|
+
}
|
|
46
|
+
var CNPJ_LENGTH = 14;
|
|
47
|
+
var CNPJ_CHECK_DIGITS = 2;
|
|
48
|
+
var CNPJ_FIRST_DV_WEIGHTS = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
49
|
+
var CNPJ_SECOND_DV_WEIGHTS = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
50
|
+
function cnpjCharValue(char) {
|
|
51
|
+
return char.charCodeAt(0) - 48;
|
|
52
|
+
}
|
|
53
|
+
function cnpjCheckDigit(base, weights) {
|
|
54
|
+
const sum = base.split("").reduce((acc, char, i) => acc + cnpjCharValue(char) * weights[i], 0);
|
|
55
|
+
const remainder = sum % 11;
|
|
56
|
+
return remainder < 2 ? 0 : 11 - remainder;
|
|
57
|
+
}
|
|
58
|
+
function isValidCnpj(value) {
|
|
59
|
+
const clean = keepAlphanumeric(value);
|
|
60
|
+
if (clean.length !== CNPJ_LENGTH || !/^[0-9A-Z]{12}[0-9]{2}$/.test(clean)) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
if (/^(.)\1{13}$/.test(clean)) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
const baseLength = CNPJ_LENGTH - CNPJ_CHECK_DIGITS;
|
|
67
|
+
const base = clean.slice(0, baseLength);
|
|
68
|
+
const dv1 = cnpjCheckDigit(base, CNPJ_FIRST_DV_WEIGHTS);
|
|
69
|
+
const dv2 = cnpjCheckDigit(base + String(dv1), CNPJ_SECOND_DV_WEIGHTS);
|
|
70
|
+
return clean.slice(baseLength) === `${dv1}${dv2}`;
|
|
71
|
+
}
|
|
72
|
+
function formatCnpj(value) {
|
|
73
|
+
const clean = keepAlphanumeric(value);
|
|
74
|
+
if (!/^[0-9A-Z]{12}[0-9]{2}$/.test(clean)) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
return clean.replace(
|
|
78
|
+
/^([0-9A-Z]{2})([0-9A-Z]{3})([0-9A-Z]{3})([0-9A-Z]{4})(\d{2})$/,
|
|
79
|
+
"$1.$2.$3/$4-$5"
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
function compareCnpj(cnpj1, cnpj2) {
|
|
83
|
+
if (!isValidCnpj(cnpj1) || !isValidCnpj(cnpj2)) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
return keepAlphanumeric(cnpj1) === keepAlphanumeric(cnpj2);
|
|
87
|
+
}
|
|
88
|
+
function compareTaxpayer(taxpayer1, taxpayer2) {
|
|
89
|
+
if (!getTaxpayerType(taxpayer1) || !getTaxpayerType(taxpayer2)) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
return keepAlphanumeric(taxpayer1) === keepAlphanumeric(taxpayer2);
|
|
93
|
+
}
|
|
94
|
+
function getTaxpayerType(cpfCnpj) {
|
|
95
|
+
if (isValidCpf(cpfCnpj)) {
|
|
96
|
+
return "cpf";
|
|
97
|
+
}
|
|
98
|
+
if (isValidCnpj(cpfCnpj)) {
|
|
99
|
+
return "cnpj";
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
function isValidTaxpayer(cpfCnpj) {
|
|
104
|
+
return Boolean(getTaxpayerType(cpfCnpj));
|
|
105
|
+
}
|
|
106
|
+
function formatTaxpayer(cpfCnpj) {
|
|
107
|
+
const type = getTaxpayerType(cpfCnpj);
|
|
108
|
+
if (type === "cpf") {
|
|
109
|
+
return formatCpf(cpfCnpj);
|
|
110
|
+
} else if (type === "cnpj") {
|
|
111
|
+
return formatCnpj(cpfCnpj);
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
var cpf = {
|
|
116
|
+
isValid: isValidCpf,
|
|
117
|
+
format: formatCpf,
|
|
118
|
+
compare: compareCpf,
|
|
119
|
+
clean: keepDigits
|
|
120
|
+
};
|
|
121
|
+
var cnpj = {
|
|
122
|
+
isValid: isValidCnpj,
|
|
123
|
+
format: formatCnpj,
|
|
124
|
+
compare: compareCnpj,
|
|
125
|
+
clean: keepAlphanumeric
|
|
126
|
+
};
|
|
127
|
+
var taxpayer = {
|
|
128
|
+
type: getTaxpayerType,
|
|
129
|
+
isValid: isValidTaxpayer,
|
|
130
|
+
format: formatTaxpayer,
|
|
131
|
+
compare: compareTaxpayer,
|
|
132
|
+
// unknown type → alphanumeric is the safe normalization: works for both a
|
|
133
|
+
// numeric CPF and an alphanumeric CNPJ, and their lengths never collide
|
|
134
|
+
clean: keepAlphanumeric
|
|
135
|
+
};
|
|
136
|
+
export {
|
|
137
|
+
cnpj,
|
|
138
|
+
cpf,
|
|
139
|
+
taxpayer
|
|
140
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@azify/cpf-cnpj",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CPF/CNPJ validation, formatting and comparison helpers (including alphanumeric CNPJ).",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"author": "Azify",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/azifydev/azify-cpf-cnpj.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/azifydev/azify-cpf-cnpj/issues"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/azifydev/azify-cpf-cnpj#readme",
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"module": "./dist/index.mjs",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.mjs",
|
|
22
|
+
"require": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist"
|
|
27
|
+
],
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "restricted"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
33
|
+
"test": "vitest run",
|
|
34
|
+
"prepublishOnly": "npm run build && npm test"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"tsup": "^8.3.5",
|
|
38
|
+
"typescript": "^5.7.2",
|
|
39
|
+
"vitest": "^2.1.8"
|
|
40
|
+
}
|
|
41
|
+
}
|