hvp-shared 3.0.1 → 3.2.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/dist/constants/collaborator.constants.d.ts +42 -0
- package/dist/constants/collaborator.constants.js +48 -0
- package/dist/constants/index.d.ts +1 -0
- package/dist/constants/index.js +1 -0
- package/dist/contracts/collaborator/index.d.ts +5 -0
- package/dist/contracts/collaborator/index.js +22 -0
- package/dist/contracts/collaborator/responses.d.ts +106 -0
- package/dist/contracts/collaborator/responses.js +2 -0
- package/dist/contracts/index.d.ts +5 -0
- package/dist/contracts/index.js +21 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types/collaborator-fiscal.types.d.ts +70 -0
- package/dist/types/collaborator-fiscal.types.js +2 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.js +23 -0
- package/dist/validation/address.validation.test.d.ts +1 -0
- package/dist/validation/address.validation.test.js +144 -0
- package/dist/validation/curp.validation.d.ts +30 -0
- package/dist/validation/curp.validation.js +51 -0
- package/dist/validation/curp.validation.test.d.ts +1 -0
- package/dist/validation/curp.validation.test.js +106 -0
- package/dist/validation/email.validation.test.d.ts +1 -0
- package/dist/validation/email.validation.test.js +102 -0
- package/dist/validation/index.d.ts +2 -0
- package/dist/validation/index.js +2 -0
- package/dist/validation/nss.validation.d.ts +25 -0
- package/dist/validation/nss.validation.js +42 -0
- package/dist/validation/nss.validation.test.d.ts +1 -0
- package/dist/validation/nss.validation.test.js +86 -0
- package/dist/validation/phone.validation.test.d.ts +1 -0
- package/dist/validation/phone.validation.test.js +75 -0
- package/dist/validation/rfc.validation.test.d.ts +1 -0
- package/dist/validation/rfc.validation.test.js +97 -0
- package/package.json +1 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collaborator Constants and Enums
|
|
3
|
+
*
|
|
4
|
+
* Shared enums used by both backend and frontend for collaborator management.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Web Application Roles
|
|
8
|
+
*
|
|
9
|
+
* Defines user roles for authorization and access control.
|
|
10
|
+
* Used in JWT tokens, middleware, and UI role-based rendering.
|
|
11
|
+
*/
|
|
12
|
+
export declare enum WebAppRole {
|
|
13
|
+
admin = "Administrador",
|
|
14
|
+
manager = "Gerente",
|
|
15
|
+
collaborator = "Colaborador",
|
|
16
|
+
user = "User",
|
|
17
|
+
guest = "Invitado"
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Educational Degree
|
|
21
|
+
*
|
|
22
|
+
* Academic level of collaborators for HR records.
|
|
23
|
+
*/
|
|
24
|
+
export declare enum Degree {
|
|
25
|
+
HighSchool = "Bachillerato",
|
|
26
|
+
UniversityStudent = "Estudiante universitario",
|
|
27
|
+
BachelorComplete = "Licenciatura completa",
|
|
28
|
+
Graduated = "Titulado",
|
|
29
|
+
Masters = "Maestr\u00EDa",
|
|
30
|
+
Doctorate = "Doctorado",
|
|
31
|
+
Other = "Otros"
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Gender
|
|
35
|
+
*
|
|
36
|
+
* Gender identification for HR and demographic records.
|
|
37
|
+
*/
|
|
38
|
+
export declare enum Gender {
|
|
39
|
+
Male = "Masculino",
|
|
40
|
+
Female = "Femenino",
|
|
41
|
+
Other = "Otro"
|
|
42
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Collaborator Constants and Enums
|
|
4
|
+
*
|
|
5
|
+
* Shared enums used by both backend and frontend for collaborator management.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.Gender = exports.Degree = exports.WebAppRole = void 0;
|
|
9
|
+
/**
|
|
10
|
+
* Web Application Roles
|
|
11
|
+
*
|
|
12
|
+
* Defines user roles for authorization and access control.
|
|
13
|
+
* Used in JWT tokens, middleware, and UI role-based rendering.
|
|
14
|
+
*/
|
|
15
|
+
var WebAppRole;
|
|
16
|
+
(function (WebAppRole) {
|
|
17
|
+
WebAppRole["admin"] = "Administrador";
|
|
18
|
+
WebAppRole["manager"] = "Gerente";
|
|
19
|
+
WebAppRole["collaborator"] = "Colaborador";
|
|
20
|
+
WebAppRole["user"] = "User";
|
|
21
|
+
WebAppRole["guest"] = "Invitado";
|
|
22
|
+
})(WebAppRole || (exports.WebAppRole = WebAppRole = {}));
|
|
23
|
+
/**
|
|
24
|
+
* Educational Degree
|
|
25
|
+
*
|
|
26
|
+
* Academic level of collaborators for HR records.
|
|
27
|
+
*/
|
|
28
|
+
var Degree;
|
|
29
|
+
(function (Degree) {
|
|
30
|
+
Degree["HighSchool"] = "Bachillerato";
|
|
31
|
+
Degree["UniversityStudent"] = "Estudiante universitario";
|
|
32
|
+
Degree["BachelorComplete"] = "Licenciatura completa";
|
|
33
|
+
Degree["Graduated"] = "Titulado";
|
|
34
|
+
Degree["Masters"] = "Maestr\u00EDa";
|
|
35
|
+
Degree["Doctorate"] = "Doctorado";
|
|
36
|
+
Degree["Other"] = "Otros";
|
|
37
|
+
})(Degree || (exports.Degree = Degree = {}));
|
|
38
|
+
/**
|
|
39
|
+
* Gender
|
|
40
|
+
*
|
|
41
|
+
* Gender identification for HR and demographic records.
|
|
42
|
+
*/
|
|
43
|
+
var Gender;
|
|
44
|
+
(function (Gender) {
|
|
45
|
+
Gender["Male"] = "Masculino";
|
|
46
|
+
Gender["Female"] = "Femenino";
|
|
47
|
+
Gender["Other"] = "Otro";
|
|
48
|
+
})(Gender || (exports.Gender = Gender = {}));
|
package/dist/constants/index.js
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Collaborator API Contracts
|
|
4
|
+
* Request and Response types for Collaborator endpoints
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
18
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
__exportStar(require("./responses"), exports);
|
|
22
|
+
// export * from './requests'; // TODO: Create when needed
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { WebAppRole } from '../../constants/collaborator.constants';
|
|
2
|
+
import { AddressValidationProps } from '../../validation/address.validation';
|
|
3
|
+
/**
|
|
4
|
+
* Public Collaborator Response
|
|
5
|
+
*
|
|
6
|
+
* Minimal data for public endpoints (no authentication required).
|
|
7
|
+
* Used for: Public website, service listings, team pages.
|
|
8
|
+
*
|
|
9
|
+
* @example GET /api/collaborators/public
|
|
10
|
+
*/
|
|
11
|
+
export interface PublicCollaboratorResponse {
|
|
12
|
+
id: string;
|
|
13
|
+
col_code: string;
|
|
14
|
+
first_name: string;
|
|
15
|
+
last_name: string;
|
|
16
|
+
photoURL?: string;
|
|
17
|
+
role: WebAppRole;
|
|
18
|
+
isActive: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Collaborator View Response
|
|
22
|
+
*
|
|
23
|
+
* Extended data for authenticated collaborators viewing other collaborators.
|
|
24
|
+
* Excludes sensitive information (fiscal data, salary, banking).
|
|
25
|
+
*
|
|
26
|
+
* Used for: Collaborators viewing team members, scheduling, contact info.
|
|
27
|
+
*
|
|
28
|
+
* @example GET /api/collaborators/:id (authenticated collaborator)
|
|
29
|
+
*/
|
|
30
|
+
export interface CollaboratorViewResponse {
|
|
31
|
+
id: string;
|
|
32
|
+
col_code: string;
|
|
33
|
+
first_name: string;
|
|
34
|
+
last_name: string;
|
|
35
|
+
email?: string;
|
|
36
|
+
phone?: string;
|
|
37
|
+
photoURL?: string;
|
|
38
|
+
birthDate?: Date;
|
|
39
|
+
role: WebAppRole;
|
|
40
|
+
isActive: boolean;
|
|
41
|
+
isDisplayedWeb: boolean;
|
|
42
|
+
isRegistered: boolean;
|
|
43
|
+
job?: string;
|
|
44
|
+
branch?: string;
|
|
45
|
+
hireDate?: Date;
|
|
46
|
+
address?: AddressValidationProps;
|
|
47
|
+
facebook?: string;
|
|
48
|
+
instagram?: string;
|
|
49
|
+
createdAt?: Date;
|
|
50
|
+
updatedAt?: Date;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Admin Collaborator Response
|
|
54
|
+
*
|
|
55
|
+
* Complete data including all sensitive information.
|
|
56
|
+
* Only for admin users.
|
|
57
|
+
*
|
|
58
|
+
* Used for: Admin dashboard, payroll management, HR operations, CFDI generation.
|
|
59
|
+
*
|
|
60
|
+
* @example GET /api/collaborators/:id (admin authenticated)
|
|
61
|
+
*/
|
|
62
|
+
export interface AdminCollaboratorResponse {
|
|
63
|
+
id: string;
|
|
64
|
+
col_code: string;
|
|
65
|
+
first_name: string;
|
|
66
|
+
last_name: string;
|
|
67
|
+
second_last_name?: string;
|
|
68
|
+
email?: string;
|
|
69
|
+
phone?: string;
|
|
70
|
+
photoURL?: string;
|
|
71
|
+
birthDate?: Date;
|
|
72
|
+
role: WebAppRole;
|
|
73
|
+
isActive: boolean;
|
|
74
|
+
isDisplayedWeb: boolean;
|
|
75
|
+
isRegistered: boolean;
|
|
76
|
+
registeredDate?: Date;
|
|
77
|
+
job?: string;
|
|
78
|
+
branch?: string;
|
|
79
|
+
hireDate?: Date;
|
|
80
|
+
endDate?: Date;
|
|
81
|
+
address?: AddressValidationProps;
|
|
82
|
+
facebook?: string;
|
|
83
|
+
instagram?: string;
|
|
84
|
+
rfcCode?: string;
|
|
85
|
+
curp?: string;
|
|
86
|
+
imssNumber?: string;
|
|
87
|
+
useFiscalAddressSameAsMain: boolean;
|
|
88
|
+
fiscalAddress?: AddressValidationProps;
|
|
89
|
+
taxZipCode?: string;
|
|
90
|
+
contractType?: string;
|
|
91
|
+
regimeType?: string;
|
|
92
|
+
fiscalRegime?: string;
|
|
93
|
+
bank?: string;
|
|
94
|
+
bankAccount?: string;
|
|
95
|
+
baseSalary?: number;
|
|
96
|
+
dailySalary?: number;
|
|
97
|
+
accessCode?: string;
|
|
98
|
+
createdBy?: string;
|
|
99
|
+
updatedBy?: string;
|
|
100
|
+
createdAt?: Date;
|
|
101
|
+
updatedAt?: Date;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Union type for all collaborator response types
|
|
105
|
+
*/
|
|
106
|
+
export type CollaboratorResponse = PublicCollaboratorResponse | CollaboratorViewResponse | AdminCollaboratorResponse;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* API Contracts
|
|
4
|
+
* Request and Response types for all API endpoints
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
18
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
__exportStar(require("./collaborator"), exports);
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
21
21
|
exports.debugLog = void 0;
|
|
22
22
|
__exportStar(require("./types"), exports);
|
|
23
23
|
__exportStar(require("./constants"), exports);
|
|
24
|
+
__exportStar(require("./contracts"), exports);
|
|
24
25
|
__exportStar(require("./validation"), exports);
|
|
25
26
|
var debug_logger_1 = require("./utils/debug-logger");
|
|
26
27
|
Object.defineProperty(exports, "debugLog", { enumerable: true, get: function () { return debug_logger_1.debugLog; } });
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { SATContractTypeCode, SATFiscalRegimeCode, SATRegimeTypeCode } from '../constants/sat-catalogs';
|
|
2
|
+
import { AddressValidationProps } from '../validation/address.validation';
|
|
3
|
+
/**
|
|
4
|
+
* Collaborator Fiscal Data
|
|
5
|
+
*
|
|
6
|
+
* Fiscal/tax information required for CFDI payroll stamping in Mexico.
|
|
7
|
+
* These fields are needed to generate compliant electronic payroll invoices (CFDI Nómina).
|
|
8
|
+
*
|
|
9
|
+
* @see SAT CFDI Nómina 4.0 specification
|
|
10
|
+
*/
|
|
11
|
+
export interface CollaboratorFiscalData {
|
|
12
|
+
/**
|
|
13
|
+
* RFC - Registro Federal de Contribuyentes
|
|
14
|
+
* Mexican tax ID (12-13 characters)
|
|
15
|
+
*/
|
|
16
|
+
rfcCode?: string;
|
|
17
|
+
/**
|
|
18
|
+
* CURP - Clave Única de Registro de Población
|
|
19
|
+
* Unique population registry code (18 characters)
|
|
20
|
+
*/
|
|
21
|
+
curp?: string;
|
|
22
|
+
/**
|
|
23
|
+
* NSS/IMSS Number - Número de Seguro Social
|
|
24
|
+
* Mexican social security number (11 digits)
|
|
25
|
+
*/
|
|
26
|
+
imssNumber?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Flag indicating if fiscal address is the same as main address
|
|
29
|
+
* When true, fiscalAddress should be null/undefined
|
|
30
|
+
*/
|
|
31
|
+
useFiscalAddressSameAsMain: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Fiscal address (only when useFiscalAddressSameAsMain is false)
|
|
34
|
+
* Used for tax purposes and CFDI generation
|
|
35
|
+
*/
|
|
36
|
+
fiscalAddress?: AddressValidationProps;
|
|
37
|
+
/**
|
|
38
|
+
* Tax zip code (c_CodigoPostal)
|
|
39
|
+
* Must match SAT catalog
|
|
40
|
+
*/
|
|
41
|
+
taxZipCode?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Contract type (c_TipoContrato)
|
|
44
|
+
* SAT catalog code for employment contract type
|
|
45
|
+
*/
|
|
46
|
+
contractType?: SATContractTypeCode;
|
|
47
|
+
/**
|
|
48
|
+
* Regime type (c_TipoRegimen)
|
|
49
|
+
* SAT catalog code for employment regime
|
|
50
|
+
*/
|
|
51
|
+
regimeType?: SATRegimeTypeCode;
|
|
52
|
+
/**
|
|
53
|
+
* Fiscal regime (c_RegimenFiscal)
|
|
54
|
+
* SAT catalog code for worker's fiscal regime
|
|
55
|
+
*/
|
|
56
|
+
fiscalRegime?: SATFiscalRegimeCode;
|
|
57
|
+
/**
|
|
58
|
+
* Bank name for payroll deposits
|
|
59
|
+
*/
|
|
60
|
+
bank?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Bank account number (CLABE)
|
|
63
|
+
*/
|
|
64
|
+
bankAccount?: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Partial fiscal data for updates
|
|
68
|
+
* All fields optional for partial updates
|
|
69
|
+
*/
|
|
70
|
+
export type PartialCollaboratorFiscalData = Partial<CollaboratorFiscalData>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Type Definitions
|
|
4
|
+
* Shared TypeScript interfaces and types
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
18
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
__exportStar(require("./api-response.types"), exports);
|
|
22
|
+
__exportStar(require("./company-settings.types"), exports);
|
|
23
|
+
__exportStar(require("./collaborator-fiscal.types"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const address_validation_1 = require("./address.validation");
|
|
4
|
+
describe('validateAddress', () => {
|
|
5
|
+
const validAddress = {
|
|
6
|
+
street: 'Calle 10',
|
|
7
|
+
exteriorNumber: '123',
|
|
8
|
+
interiorNumber: 'A',
|
|
9
|
+
neighborhood: 'Centro',
|
|
10
|
+
city: 'Mérida',
|
|
11
|
+
state: 'YUC',
|
|
12
|
+
zipCode: '97000',
|
|
13
|
+
country: 'México'
|
|
14
|
+
};
|
|
15
|
+
describe('valid addresses', () => {
|
|
16
|
+
it('should accept valid complete address', () => {
|
|
17
|
+
const result = (0, address_validation_1.validateAddress)(validAddress);
|
|
18
|
+
expect(result.isValid).toBe(true);
|
|
19
|
+
expect(result.error).toBeUndefined();
|
|
20
|
+
});
|
|
21
|
+
it('should accept address without interior number', () => {
|
|
22
|
+
const { interiorNumber, ...addressWithoutInterior } = validAddress;
|
|
23
|
+
const result = (0, address_validation_1.validateAddress)(addressWithoutInterior);
|
|
24
|
+
expect(result.isValid).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
it('should accept country "Mexico" without accent', () => {
|
|
27
|
+
const result = (0, address_validation_1.validateAddress)({ ...validAddress, country: 'Mexico' });
|
|
28
|
+
expect(result.isValid).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
it('should accept country in uppercase', () => {
|
|
31
|
+
const result = (0, address_validation_1.validateAddress)({ ...validAddress, country: 'MÉXICO' });
|
|
32
|
+
expect(result.isValid).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
it('should accept address with whitespace (trimmed)', () => {
|
|
35
|
+
const result = (0, address_validation_1.validateAddress)({
|
|
36
|
+
...validAddress,
|
|
37
|
+
street: ' Calle 10 ',
|
|
38
|
+
city: ' Mérida '
|
|
39
|
+
});
|
|
40
|
+
expect(result.isValid).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe('required fields', () => {
|
|
44
|
+
it('should reject missing street', () => {
|
|
45
|
+
const result = (0, address_validation_1.validateAddress)({ ...validAddress, street: '' });
|
|
46
|
+
expect(result.isValid).toBe(false);
|
|
47
|
+
expect(result.error).toBe('Calle es requerida');
|
|
48
|
+
});
|
|
49
|
+
it('should reject missing exterior number', () => {
|
|
50
|
+
const result = (0, address_validation_1.validateAddress)({ ...validAddress, exteriorNumber: '' });
|
|
51
|
+
expect(result.isValid).toBe(false);
|
|
52
|
+
expect(result.error).toBe('Número exterior es requerido');
|
|
53
|
+
});
|
|
54
|
+
it('should reject missing neighborhood', () => {
|
|
55
|
+
const result = (0, address_validation_1.validateAddress)({ ...validAddress, neighborhood: '' });
|
|
56
|
+
expect(result.isValid).toBe(false);
|
|
57
|
+
expect(result.error).toBe('Colonia es requerida');
|
|
58
|
+
});
|
|
59
|
+
it('should reject missing city', () => {
|
|
60
|
+
const result = (0, address_validation_1.validateAddress)({ ...validAddress, city: '' });
|
|
61
|
+
expect(result.isValid).toBe(false);
|
|
62
|
+
expect(result.error).toBe('Ciudad es requerida');
|
|
63
|
+
});
|
|
64
|
+
it('should reject missing postal code', () => {
|
|
65
|
+
const result = (0, address_validation_1.validateAddress)({ ...validAddress, zipCode: '' });
|
|
66
|
+
expect(result.isValid).toBe(false);
|
|
67
|
+
expect(result.error).toBe('Código postal es requerido');
|
|
68
|
+
});
|
|
69
|
+
it('should reject missing state', () => {
|
|
70
|
+
const { state, ...addressWithoutState } = validAddress;
|
|
71
|
+
const result = (0, address_validation_1.validateAddress)(addressWithoutState);
|
|
72
|
+
expect(result.isValid).toBe(false);
|
|
73
|
+
expect(result.error).toBe('Estado es requerido');
|
|
74
|
+
});
|
|
75
|
+
it('should reject missing country', () => {
|
|
76
|
+
const result = (0, address_validation_1.validateAddress)({ ...validAddress, country: '' });
|
|
77
|
+
expect(result.isValid).toBe(false);
|
|
78
|
+
expect(result.error).toBe('País es requerido');
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
describe('postal code validation', () => {
|
|
82
|
+
it('should reject postal code with less than 5 digits', () => {
|
|
83
|
+
const result = (0, address_validation_1.validateAddress)({ ...validAddress, zipCode: '9700' });
|
|
84
|
+
expect(result.isValid).toBe(false);
|
|
85
|
+
expect(result.error).toContain('5 dígitos');
|
|
86
|
+
});
|
|
87
|
+
it('should reject postal code with more than 5 digits', () => {
|
|
88
|
+
const result = (0, address_validation_1.validateAddress)({ ...validAddress, zipCode: '970001' });
|
|
89
|
+
expect(result.isValid).toBe(false);
|
|
90
|
+
expect(result.error).toContain('5 dígitos');
|
|
91
|
+
});
|
|
92
|
+
it('should reject postal code with letters', () => {
|
|
93
|
+
const result = (0, address_validation_1.validateAddress)({ ...validAddress, zipCode: '9700A' });
|
|
94
|
+
expect(result.isValid).toBe(false);
|
|
95
|
+
expect(result.error).toContain('5 dígitos');
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe('state code validation', () => {
|
|
99
|
+
it('should accept all valid Mexican state codes', () => {
|
|
100
|
+
// SAT Federal Entity codes (c_Estado) - used for CFDI compliance
|
|
101
|
+
const validStates = [
|
|
102
|
+
'AGU', 'BCN', 'BCS', 'CAM', 'CHP', 'CHH', 'COA', 'COL', 'DIF',
|
|
103
|
+
'DUR', 'GUA', 'GRO', 'HID', 'JAL', 'MEX', 'MIC', 'MOR', 'NAY',
|
|
104
|
+
'NLE', 'OAX', 'PUE', 'QUE', 'ROO', 'SLP', 'SIN', 'SON', 'TAB',
|
|
105
|
+
'TAM', 'TLA', 'VER', 'YUC', 'ZAC'
|
|
106
|
+
];
|
|
107
|
+
validStates.forEach(state => {
|
|
108
|
+
const result = (0, address_validation_1.validateAddress)({ ...validAddress, state: state });
|
|
109
|
+
expect(result.isValid).toBe(true);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
it('should reject invalid state code', () => {
|
|
113
|
+
const result = (0, address_validation_1.validateAddress)({ ...validAddress, state: 'INVALID' });
|
|
114
|
+
expect(result.isValid).toBe(false);
|
|
115
|
+
expect(result.error).toBe('Código de estado inválido');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
describe('country validation', () => {
|
|
119
|
+
it('should reject non-Mexican country', () => {
|
|
120
|
+
const result = (0, address_validation_1.validateAddress)({ ...validAddress, country: 'USA' });
|
|
121
|
+
expect(result.isValid).toBe(false);
|
|
122
|
+
expect(result.error).toContain('México');
|
|
123
|
+
});
|
|
124
|
+
it('should reject other countries', () => {
|
|
125
|
+
const result = (0, address_validation_1.validateAddress)({ ...validAddress, country: 'Canada' });
|
|
126
|
+
expect(result.isValid).toBe(false);
|
|
127
|
+
expect(result.error).toContain('México');
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
describe('POSTAL_CODE_PATTERN', () => {
|
|
132
|
+
it('should match valid 5-digit postal code', () => {
|
|
133
|
+
expect(address_validation_1.POSTAL_CODE_PATTERN.test('97000')).toBe(true);
|
|
134
|
+
});
|
|
135
|
+
it('should match postal code starting with 0', () => {
|
|
136
|
+
expect(address_validation_1.POSTAL_CODE_PATTERN.test('01000')).toBe(true);
|
|
137
|
+
});
|
|
138
|
+
it('should not match 4-digit code', () => {
|
|
139
|
+
expect(address_validation_1.POSTAL_CODE_PATTERN.test('9700')).toBe(false);
|
|
140
|
+
});
|
|
141
|
+
it('should not match 6-digit code', () => {
|
|
142
|
+
expect(address_validation_1.POSTAL_CODE_PATTERN.test('970001')).toBe(false);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ValidationResult } from './rfc.validation';
|
|
2
|
+
/**
|
|
3
|
+
* Validates CURP (Clave Única de Registro de Población) format
|
|
4
|
+
*
|
|
5
|
+
* CURP is the Mexican unique population registry code.
|
|
6
|
+
* Format: 18 characters (e.g., GARC850101HDFRRL09)
|
|
7
|
+
* - 4 letters: surname initial + surname vowel + name initial + name letter
|
|
8
|
+
* - 6 digits: birth date YYMMDD
|
|
9
|
+
* - 1 letter: sex (H/M)
|
|
10
|
+
* - 2 letters: state code
|
|
11
|
+
* - 3 alphanumeric: consonants + check digit
|
|
12
|
+
*
|
|
13
|
+
* Note: This performs basic format validation only.
|
|
14
|
+
*
|
|
15
|
+
* @param value - CURP to validate
|
|
16
|
+
* @returns ValidationResult with isValid flag and optional error message
|
|
17
|
+
*/
|
|
18
|
+
export declare function validateCURP(value: string | null | undefined): ValidationResult;
|
|
19
|
+
/**
|
|
20
|
+
* Normalizes CURP to uppercase and trimmed
|
|
21
|
+
*
|
|
22
|
+
* @param value - CURP to normalize
|
|
23
|
+
* @returns Normalized CURP
|
|
24
|
+
*/
|
|
25
|
+
export declare function normalizeCURP(value: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Regex pattern for CURP validation
|
|
28
|
+
* Can be used directly in form libraries that accept regex
|
|
29
|
+
*/
|
|
30
|
+
export declare const CURP_PATTERN: RegExp;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CURP_PATTERN = void 0;
|
|
4
|
+
exports.validateCURP = validateCURP;
|
|
5
|
+
exports.normalizeCURP = normalizeCURP;
|
|
6
|
+
/**
|
|
7
|
+
* Validates CURP (Clave Única de Registro de Población) format
|
|
8
|
+
*
|
|
9
|
+
* CURP is the Mexican unique population registry code.
|
|
10
|
+
* Format: 18 characters (e.g., GARC850101HDFRRL09)
|
|
11
|
+
* - 4 letters: surname initial + surname vowel + name initial + name letter
|
|
12
|
+
* - 6 digits: birth date YYMMDD
|
|
13
|
+
* - 1 letter: sex (H/M)
|
|
14
|
+
* - 2 letters: state code
|
|
15
|
+
* - 3 alphanumeric: consonants + check digit
|
|
16
|
+
*
|
|
17
|
+
* Note: This performs basic format validation only.
|
|
18
|
+
*
|
|
19
|
+
* @param value - CURP to validate
|
|
20
|
+
* @returns ValidationResult with isValid flag and optional error message
|
|
21
|
+
*/
|
|
22
|
+
function validateCURP(value) {
|
|
23
|
+
if (!value || !value.trim()) {
|
|
24
|
+
return { isValid: false, error: 'CURP es requerido' };
|
|
25
|
+
}
|
|
26
|
+
const normalized = value.toUpperCase().trim();
|
|
27
|
+
// CURP format: 18 alphanumeric characters
|
|
28
|
+
const curpPattern = /^[A-Z]{4}\d{6}[HM][A-Z]{5}[0-9A-Z]\d$/;
|
|
29
|
+
if (!curpPattern.test(normalized)) {
|
|
30
|
+
return { isValid: false, error: 'CURP inválido. Debe tener 18 caracteres (ej: GARC850101HDFRRL09)' };
|
|
31
|
+
}
|
|
32
|
+
// Validate length
|
|
33
|
+
if (normalized.length !== 18) {
|
|
34
|
+
return { isValid: false, error: 'CURP debe tener exactamente 18 caracteres' };
|
|
35
|
+
}
|
|
36
|
+
return { isValid: true };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Normalizes CURP to uppercase and trimmed
|
|
40
|
+
*
|
|
41
|
+
* @param value - CURP to normalize
|
|
42
|
+
* @returns Normalized CURP
|
|
43
|
+
*/
|
|
44
|
+
function normalizeCURP(value) {
|
|
45
|
+
return value.toUpperCase().trim();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Regex pattern for CURP validation
|
|
49
|
+
* Can be used directly in form libraries that accept regex
|
|
50
|
+
*/
|
|
51
|
+
exports.CURP_PATTERN = /^[A-Z]{4}\d{6}[HM][A-Z]{5}[0-9A-Z]\d$/;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const curp_validation_1 = require("./curp.validation");
|
|
4
|
+
describe('validateCURP', () => {
|
|
5
|
+
describe('valid CURPs', () => {
|
|
6
|
+
it('should accept valid CURP with male sex', () => {
|
|
7
|
+
const result = (0, curp_validation_1.validateCURP)('GARC850101HDFRRL09');
|
|
8
|
+
expect(result.isValid).toBe(true);
|
|
9
|
+
expect(result.error).toBeUndefined();
|
|
10
|
+
});
|
|
11
|
+
it('should accept valid CURP with female sex', () => {
|
|
12
|
+
const result = (0, curp_validation_1.validateCURP)('MELR930224MDFRNS08');
|
|
13
|
+
expect(result.isValid).toBe(true);
|
|
14
|
+
expect(result.error).toBeUndefined();
|
|
15
|
+
});
|
|
16
|
+
it('should accept lowercase CURP (normalized)', () => {
|
|
17
|
+
const result = (0, curp_validation_1.validateCURP)('garc850101hdfrrl09');
|
|
18
|
+
expect(result.isValid).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
it('should accept CURP with whitespace (trimmed)', () => {
|
|
21
|
+
const result = (0, curp_validation_1.validateCURP)(' GARC850101HDFRRL09 ');
|
|
22
|
+
expect(result.isValid).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
it('should accept mixed case CURP', () => {
|
|
25
|
+
const result = (0, curp_validation_1.validateCURP)('Garc850101HdfrRL09');
|
|
26
|
+
expect(result.isValid).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
describe('invalid CURPs', () => {
|
|
30
|
+
it('should reject empty string', () => {
|
|
31
|
+
const result = (0, curp_validation_1.validateCURP)('');
|
|
32
|
+
expect(result.isValid).toBe(false);
|
|
33
|
+
expect(result.error).toBe('CURP es requerido');
|
|
34
|
+
});
|
|
35
|
+
it('should reject null', () => {
|
|
36
|
+
const result = (0, curp_validation_1.validateCURP)(null);
|
|
37
|
+
expect(result.isValid).toBe(false);
|
|
38
|
+
expect(result.error).toBe('CURP es requerido');
|
|
39
|
+
});
|
|
40
|
+
it('should reject undefined', () => {
|
|
41
|
+
const result = (0, curp_validation_1.validateCURP)(undefined);
|
|
42
|
+
expect(result.isValid).toBe(false);
|
|
43
|
+
expect(result.error).toBe('CURP es requerido');
|
|
44
|
+
});
|
|
45
|
+
it('should reject whitespace only', () => {
|
|
46
|
+
const result = (0, curp_validation_1.validateCURP)(' ');
|
|
47
|
+
expect(result.isValid).toBe(false);
|
|
48
|
+
expect(result.error).toBe('CURP es requerido');
|
|
49
|
+
});
|
|
50
|
+
it('should reject CURP too short', () => {
|
|
51
|
+
const result = (0, curp_validation_1.validateCURP)('GARC850101HDFRR');
|
|
52
|
+
expect(result.isValid).toBe(false);
|
|
53
|
+
expect(result.error).toContain('CURP inválido');
|
|
54
|
+
});
|
|
55
|
+
it('should reject CURP too long', () => {
|
|
56
|
+
const result = (0, curp_validation_1.validateCURP)('GARC850101HDFRRL099');
|
|
57
|
+
expect(result.isValid).toBe(false);
|
|
58
|
+
expect(result.error).toContain('CURP inválido');
|
|
59
|
+
});
|
|
60
|
+
it('should reject CURP with invalid sex character (not H/M)', () => {
|
|
61
|
+
const result = (0, curp_validation_1.validateCURP)('GARC850101XDFRRL09');
|
|
62
|
+
expect(result.isValid).toBe(false);
|
|
63
|
+
expect(result.error).toContain('CURP inválido');
|
|
64
|
+
});
|
|
65
|
+
it('should reject CURP with invalid characters', () => {
|
|
66
|
+
const result = (0, curp_validation_1.validateCURP)('GARC-850101HDFRRL09');
|
|
67
|
+
expect(result.isValid).toBe(false);
|
|
68
|
+
expect(result.error).toContain('CURP inválido');
|
|
69
|
+
});
|
|
70
|
+
it('should reject CURP with wrong format (all numbers)', () => {
|
|
71
|
+
const result = (0, curp_validation_1.validateCURP)('123456789012345678');
|
|
72
|
+
expect(result.isValid).toBe(false);
|
|
73
|
+
expect(result.error).toContain('CURP inválido');
|
|
74
|
+
});
|
|
75
|
+
it('should reject CURP with invalid date format', () => {
|
|
76
|
+
const result = (0, curp_validation_1.validateCURP)('GARCABCDEFHDFRRL09');
|
|
77
|
+
expect(result.isValid).toBe(false);
|
|
78
|
+
expect(result.error).toContain('CURP inválido');
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe('normalizeCURP', () => {
|
|
83
|
+
it('should convert to uppercase', () => {
|
|
84
|
+
expect((0, curp_validation_1.normalizeCURP)('garc850101hdfrrl09')).toBe('GARC850101HDFRRL09');
|
|
85
|
+
});
|
|
86
|
+
it('should trim whitespace', () => {
|
|
87
|
+
expect((0, curp_validation_1.normalizeCURP)(' GARC850101HDFRRL09 ')).toBe('GARC850101HDFRRL09');
|
|
88
|
+
});
|
|
89
|
+
it('should handle mixed case', () => {
|
|
90
|
+
expect((0, curp_validation_1.normalizeCURP)('Garc850101HdfrRL09')).toBe('GARC850101HDFRRL09');
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
describe('CURP_PATTERN', () => {
|
|
94
|
+
it('should match valid CURP with male sex', () => {
|
|
95
|
+
expect(curp_validation_1.CURP_PATTERN.test('GARC850101HDFRRL09')).toBe(true);
|
|
96
|
+
});
|
|
97
|
+
it('should match valid CURP with female sex', () => {
|
|
98
|
+
expect(curp_validation_1.CURP_PATTERN.test('MELR930224MDFRNS08')).toBe(true);
|
|
99
|
+
});
|
|
100
|
+
it('should not match invalid CURP', () => {
|
|
101
|
+
expect(curp_validation_1.CURP_PATTERN.test('INVALID')).toBe(false);
|
|
102
|
+
});
|
|
103
|
+
it('should not match CURP with invalid sex', () => {
|
|
104
|
+
expect(curp_validation_1.CURP_PATTERN.test('GARC850101XDFRRL09')).toBe(false);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const email_validation_1 = require("./email.validation");
|
|
4
|
+
describe('validateEmail', () => {
|
|
5
|
+
describe('valid emails', () => {
|
|
6
|
+
it('should accept valid email', () => {
|
|
7
|
+
const result = (0, email_validation_1.validateEmail)('test@example.com');
|
|
8
|
+
expect(result.isValid).toBe(true);
|
|
9
|
+
expect(result.error).toBeUndefined();
|
|
10
|
+
});
|
|
11
|
+
it('should accept email with subdomain', () => {
|
|
12
|
+
const result = (0, email_validation_1.validateEmail)('test@mail.example.com');
|
|
13
|
+
expect(result.isValid).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
it('should accept email with numbers', () => {
|
|
16
|
+
const result = (0, email_validation_1.validateEmail)('test123@example.com');
|
|
17
|
+
expect(result.isValid).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
it('should accept email with dots in local part', () => {
|
|
20
|
+
const result = (0, email_validation_1.validateEmail)('test.user@example.com');
|
|
21
|
+
expect(result.isValid).toBe(true);
|
|
22
|
+
});
|
|
23
|
+
it('should accept email with plus sign', () => {
|
|
24
|
+
const result = (0, email_validation_1.validateEmail)('test+tag@example.com');
|
|
25
|
+
expect(result.isValid).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
it('should accept uppercase email (normalized)', () => {
|
|
28
|
+
const result = (0, email_validation_1.validateEmail)('TEST@EXAMPLE.COM');
|
|
29
|
+
expect(result.isValid).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
it('should accept email with whitespace (trimmed)', () => {
|
|
32
|
+
const result = (0, email_validation_1.validateEmail)(' test@example.com ');
|
|
33
|
+
expect(result.isValid).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe('invalid emails', () => {
|
|
37
|
+
it('should reject empty string', () => {
|
|
38
|
+
const result = (0, email_validation_1.validateEmail)('');
|
|
39
|
+
expect(result.isValid).toBe(false);
|
|
40
|
+
expect(result.error).toBe('Email es requerido');
|
|
41
|
+
});
|
|
42
|
+
it('should reject null', () => {
|
|
43
|
+
const result = (0, email_validation_1.validateEmail)(null);
|
|
44
|
+
expect(result.isValid).toBe(false);
|
|
45
|
+
expect(result.error).toBe('Email es requerido');
|
|
46
|
+
});
|
|
47
|
+
it('should reject undefined', () => {
|
|
48
|
+
const result = (0, email_validation_1.validateEmail)(undefined);
|
|
49
|
+
expect(result.isValid).toBe(false);
|
|
50
|
+
expect(result.error).toBe('Email es requerido');
|
|
51
|
+
});
|
|
52
|
+
it('should reject whitespace only', () => {
|
|
53
|
+
const result = (0, email_validation_1.validateEmail)(' ');
|
|
54
|
+
expect(result.isValid).toBe(false);
|
|
55
|
+
expect(result.error).toBe('Email es requerido');
|
|
56
|
+
});
|
|
57
|
+
it('should reject email without @', () => {
|
|
58
|
+
const result = (0, email_validation_1.validateEmail)('testexample.com');
|
|
59
|
+
expect(result.isValid).toBe(false);
|
|
60
|
+
expect(result.error).toBe('Email inválido');
|
|
61
|
+
});
|
|
62
|
+
it('should reject email without domain', () => {
|
|
63
|
+
const result = (0, email_validation_1.validateEmail)('test@');
|
|
64
|
+
expect(result.isValid).toBe(false);
|
|
65
|
+
expect(result.error).toBe('Email inválido');
|
|
66
|
+
});
|
|
67
|
+
it('should reject email without local part', () => {
|
|
68
|
+
const result = (0, email_validation_1.validateEmail)('@example.com');
|
|
69
|
+
expect(result.isValid).toBe(false);
|
|
70
|
+
expect(result.error).toBe('Email inválido');
|
|
71
|
+
});
|
|
72
|
+
it('should reject email without TLD', () => {
|
|
73
|
+
const result = (0, email_validation_1.validateEmail)('test@example');
|
|
74
|
+
expect(result.isValid).toBe(false);
|
|
75
|
+
expect(result.error).toBe('Email inválido');
|
|
76
|
+
});
|
|
77
|
+
it('should reject email with spaces', () => {
|
|
78
|
+
const result = (0, email_validation_1.validateEmail)('test @example.com');
|
|
79
|
+
expect(result.isValid).toBe(false);
|
|
80
|
+
expect(result.error).toBe('Email inválido');
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
describe('normalizeEmail', () => {
|
|
85
|
+
it('should convert to lowercase', () => {
|
|
86
|
+
expect((0, email_validation_1.normalizeEmail)('TEST@EXAMPLE.COM')).toBe('test@example.com');
|
|
87
|
+
});
|
|
88
|
+
it('should trim whitespace', () => {
|
|
89
|
+
expect((0, email_validation_1.normalizeEmail)(' test@example.com ')).toBe('test@example.com');
|
|
90
|
+
});
|
|
91
|
+
it('should handle mixed case', () => {
|
|
92
|
+
expect((0, email_validation_1.normalizeEmail)('Test@Example.Com')).toBe('test@example.com');
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
describe('EMAIL_PATTERN', () => {
|
|
96
|
+
it('should match valid email', () => {
|
|
97
|
+
expect(email_validation_1.EMAIL_PATTERN.test('test@example.com')).toBe(true);
|
|
98
|
+
});
|
|
99
|
+
it('should not match invalid email', () => {
|
|
100
|
+
expect(email_validation_1.EMAIL_PATTERN.test('invalid')).toBe(false);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* Pure, stateless validation logic shared between frontend and backend
|
|
4
4
|
*/
|
|
5
5
|
export * from './rfc.validation';
|
|
6
|
+
export * from './curp.validation';
|
|
7
|
+
export * from './nss.validation';
|
|
6
8
|
export * from './email.validation';
|
|
7
9
|
export * from './phone.validation';
|
|
8
10
|
export * from './address.validation';
|
package/dist/validation/index.js
CHANGED
|
@@ -19,6 +19,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
19
19
|
};
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
21
|
__exportStar(require("./rfc.validation"), exports);
|
|
22
|
+
__exportStar(require("./curp.validation"), exports);
|
|
23
|
+
__exportStar(require("./nss.validation"), exports);
|
|
22
24
|
__exportStar(require("./email.validation"), exports);
|
|
23
25
|
__exportStar(require("./phone.validation"), exports);
|
|
24
26
|
__exportStar(require("./address.validation"), exports);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ValidationResult } from './rfc.validation';
|
|
2
|
+
/**
|
|
3
|
+
* Validates NSS (Número de Seguridad Social) format
|
|
4
|
+
*
|
|
5
|
+
* NSS is the Mexican social security number issued by IMSS.
|
|
6
|
+
* Format: 11 digits (e.g., 12345678901)
|
|
7
|
+
*
|
|
8
|
+
* Note: This performs basic format validation only (11 digits).
|
|
9
|
+
*
|
|
10
|
+
* @param value - NSS to validate
|
|
11
|
+
* @returns ValidationResult with isValid flag and optional error message
|
|
12
|
+
*/
|
|
13
|
+
export declare function validateNSS(value: string | null | undefined): ValidationResult;
|
|
14
|
+
/**
|
|
15
|
+
* Normalizes NSS by trimming whitespace
|
|
16
|
+
*
|
|
17
|
+
* @param value - NSS to normalize
|
|
18
|
+
* @returns Normalized NSS
|
|
19
|
+
*/
|
|
20
|
+
export declare function normalizeNSS(value: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Regex pattern for NSS validation
|
|
23
|
+
* Can be used directly in form libraries that accept regex
|
|
24
|
+
*/
|
|
25
|
+
export declare const NSS_PATTERN: RegExp;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NSS_PATTERN = void 0;
|
|
4
|
+
exports.validateNSS = validateNSS;
|
|
5
|
+
exports.normalizeNSS = normalizeNSS;
|
|
6
|
+
/**
|
|
7
|
+
* Validates NSS (Número de Seguridad Social) format
|
|
8
|
+
*
|
|
9
|
+
* NSS is the Mexican social security number issued by IMSS.
|
|
10
|
+
* Format: 11 digits (e.g., 12345678901)
|
|
11
|
+
*
|
|
12
|
+
* Note: This performs basic format validation only (11 digits).
|
|
13
|
+
*
|
|
14
|
+
* @param value - NSS to validate
|
|
15
|
+
* @returns ValidationResult with isValid flag and optional error message
|
|
16
|
+
*/
|
|
17
|
+
function validateNSS(value) {
|
|
18
|
+
if (!value || !value.trim()) {
|
|
19
|
+
return { isValid: false, error: 'NSS es requerido' };
|
|
20
|
+
}
|
|
21
|
+
const normalized = value.trim();
|
|
22
|
+
// NSS format: exactly 11 digits
|
|
23
|
+
const nssPattern = /^\d{11}$/;
|
|
24
|
+
if (!nssPattern.test(normalized)) {
|
|
25
|
+
return { isValid: false, error: 'NSS inválido. Debe tener exactamente 11 dígitos' };
|
|
26
|
+
}
|
|
27
|
+
return { isValid: true };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Normalizes NSS by trimming whitespace
|
|
31
|
+
*
|
|
32
|
+
* @param value - NSS to normalize
|
|
33
|
+
* @returns Normalized NSS
|
|
34
|
+
*/
|
|
35
|
+
function normalizeNSS(value) {
|
|
36
|
+
return value.trim();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Regex pattern for NSS validation
|
|
40
|
+
* Can be used directly in form libraries that accept regex
|
|
41
|
+
*/
|
|
42
|
+
exports.NSS_PATTERN = /^\d{11}$/;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const nss_validation_1 = require("./nss.validation");
|
|
4
|
+
describe('validateNSS', () => {
|
|
5
|
+
describe('valid NSS', () => {
|
|
6
|
+
it('should accept valid 11-digit NSS', () => {
|
|
7
|
+
const result = (0, nss_validation_1.validateNSS)('12345678901');
|
|
8
|
+
expect(result.isValid).toBe(true);
|
|
9
|
+
expect(result.error).toBeUndefined();
|
|
10
|
+
});
|
|
11
|
+
it('should accept NSS with whitespace (trimmed)', () => {
|
|
12
|
+
const result = (0, nss_validation_1.validateNSS)(' 12345678901 ');
|
|
13
|
+
expect(result.isValid).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
it('should accept another valid NSS', () => {
|
|
16
|
+
const result = (0, nss_validation_1.validateNSS)('98765432109');
|
|
17
|
+
expect(result.isValid).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
describe('invalid NSS', () => {
|
|
21
|
+
it('should reject empty string', () => {
|
|
22
|
+
const result = (0, nss_validation_1.validateNSS)('');
|
|
23
|
+
expect(result.isValid).toBe(false);
|
|
24
|
+
expect(result.error).toBe('NSS es requerido');
|
|
25
|
+
});
|
|
26
|
+
it('should reject null', () => {
|
|
27
|
+
const result = (0, nss_validation_1.validateNSS)(null);
|
|
28
|
+
expect(result.isValid).toBe(false);
|
|
29
|
+
expect(result.error).toBe('NSS es requerido');
|
|
30
|
+
});
|
|
31
|
+
it('should reject undefined', () => {
|
|
32
|
+
const result = (0, nss_validation_1.validateNSS)(undefined);
|
|
33
|
+
expect(result.isValid).toBe(false);
|
|
34
|
+
expect(result.error).toBe('NSS es requerido');
|
|
35
|
+
});
|
|
36
|
+
it('should reject whitespace only', () => {
|
|
37
|
+
const result = (0, nss_validation_1.validateNSS)(' ');
|
|
38
|
+
expect(result.isValid).toBe(false);
|
|
39
|
+
expect(result.error).toBe('NSS es requerido');
|
|
40
|
+
});
|
|
41
|
+
it('should reject NSS too short', () => {
|
|
42
|
+
const result = (0, nss_validation_1.validateNSS)('1234567890');
|
|
43
|
+
expect(result.isValid).toBe(false);
|
|
44
|
+
expect(result.error).toContain('NSS inválido');
|
|
45
|
+
});
|
|
46
|
+
it('should reject NSS too long', () => {
|
|
47
|
+
const result = (0, nss_validation_1.validateNSS)('123456789012');
|
|
48
|
+
expect(result.isValid).toBe(false);
|
|
49
|
+
expect(result.error).toContain('NSS inválido');
|
|
50
|
+
});
|
|
51
|
+
it('should reject NSS with letters', () => {
|
|
52
|
+
const result = (0, nss_validation_1.validateNSS)('1234567890A');
|
|
53
|
+
expect(result.isValid).toBe(false);
|
|
54
|
+
expect(result.error).toContain('NSS inválido');
|
|
55
|
+
});
|
|
56
|
+
it('should reject NSS with special characters', () => {
|
|
57
|
+
const result = (0, nss_validation_1.validateNSS)('12345-67890');
|
|
58
|
+
expect(result.isValid).toBe(false);
|
|
59
|
+
expect(result.error).toContain('NSS inválido');
|
|
60
|
+
});
|
|
61
|
+
it('should reject NSS with spaces in the middle', () => {
|
|
62
|
+
const result = (0, nss_validation_1.validateNSS)('12345 67890');
|
|
63
|
+
expect(result.isValid).toBe(false);
|
|
64
|
+
expect(result.error).toContain('NSS inválido');
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
describe('normalizeNSS', () => {
|
|
69
|
+
it('should trim whitespace', () => {
|
|
70
|
+
expect((0, nss_validation_1.normalizeNSS)(' 12345678901 ')).toBe('12345678901');
|
|
71
|
+
});
|
|
72
|
+
it('should not modify valid NSS', () => {
|
|
73
|
+
expect((0, nss_validation_1.normalizeNSS)('12345678901')).toBe('12345678901');
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe('NSS_PATTERN', () => {
|
|
77
|
+
it('should match valid 11-digit NSS', () => {
|
|
78
|
+
expect(nss_validation_1.NSS_PATTERN.test('12345678901')).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
it('should not match invalid NSS', () => {
|
|
81
|
+
expect(nss_validation_1.NSS_PATTERN.test('INVALID')).toBe(false);
|
|
82
|
+
});
|
|
83
|
+
it('should not match NSS with wrong length', () => {
|
|
84
|
+
expect(nss_validation_1.NSS_PATTERN.test('123456789')).toBe(false);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const phone_validation_1 = require("./phone.validation");
|
|
4
|
+
describe('validatePhone', () => {
|
|
5
|
+
describe('valid phones', () => {
|
|
6
|
+
it('should accept valid 10-digit phone', () => {
|
|
7
|
+
const result = (0, phone_validation_1.validatePhone)('9991234567');
|
|
8
|
+
expect(result.isValid).toBe(true);
|
|
9
|
+
expect(result.error).toBeUndefined();
|
|
10
|
+
});
|
|
11
|
+
it('should accept phone with whitespace (trimmed)', () => {
|
|
12
|
+
const result = (0, phone_validation_1.validatePhone)(' 9991234567 ');
|
|
13
|
+
expect(result.isValid).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
it('should accept undefined (phone is optional)', () => {
|
|
16
|
+
const result = (0, phone_validation_1.validatePhone)(undefined);
|
|
17
|
+
expect(result.isValid).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
it('should accept null (phone is optional)', () => {
|
|
20
|
+
const result = (0, phone_validation_1.validatePhone)(null);
|
|
21
|
+
expect(result.isValid).toBe(true);
|
|
22
|
+
});
|
|
23
|
+
it('should accept empty string (phone is optional)', () => {
|
|
24
|
+
const result = (0, phone_validation_1.validatePhone)('');
|
|
25
|
+
expect(result.isValid).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
it('should accept whitespace only (phone is optional)', () => {
|
|
28
|
+
const result = (0, phone_validation_1.validatePhone)(' ');
|
|
29
|
+
expect(result.isValid).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
describe('invalid phones', () => {
|
|
33
|
+
it('should reject phone with less than 10 digits', () => {
|
|
34
|
+
const result = (0, phone_validation_1.validatePhone)('999123456');
|
|
35
|
+
expect(result.isValid).toBe(false);
|
|
36
|
+
expect(result.error).toContain('10 dígitos');
|
|
37
|
+
});
|
|
38
|
+
it('should reject phone with more than 10 digits', () => {
|
|
39
|
+
const result = (0, phone_validation_1.validatePhone)('99912345678');
|
|
40
|
+
expect(result.isValid).toBe(false);
|
|
41
|
+
expect(result.error).toContain('10 dígitos');
|
|
42
|
+
});
|
|
43
|
+
it('should reject phone with letters', () => {
|
|
44
|
+
const result = (0, phone_validation_1.validatePhone)('999123456a');
|
|
45
|
+
expect(result.isValid).toBe(false);
|
|
46
|
+
expect(result.error).toContain('10 dígitos');
|
|
47
|
+
});
|
|
48
|
+
it('should reject phone with special characters', () => {
|
|
49
|
+
const result = (0, phone_validation_1.validatePhone)('999-123-4567');
|
|
50
|
+
expect(result.isValid).toBe(false);
|
|
51
|
+
expect(result.error).toContain('10 dígitos');
|
|
52
|
+
});
|
|
53
|
+
it('should reject phone with spaces inside', () => {
|
|
54
|
+
const result = (0, phone_validation_1.validatePhone)('999 123 4567');
|
|
55
|
+
expect(result.isValid).toBe(false);
|
|
56
|
+
expect(result.error).toContain('10 dígitos');
|
|
57
|
+
});
|
|
58
|
+
it('should reject phone with parentheses', () => {
|
|
59
|
+
const result = (0, phone_validation_1.validatePhone)('(999)1234567');
|
|
60
|
+
expect(result.isValid).toBe(false);
|
|
61
|
+
expect(result.error).toContain('10 dígitos');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe('PHONE_PATTERN', () => {
|
|
66
|
+
it('should match valid 10-digit phone', () => {
|
|
67
|
+
expect(phone_validation_1.PHONE_PATTERN.test('9991234567')).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
it('should not match invalid phone', () => {
|
|
70
|
+
expect(phone_validation_1.PHONE_PATTERN.test('999-123-4567')).toBe(false);
|
|
71
|
+
});
|
|
72
|
+
it('should not match phone with less than 10 digits', () => {
|
|
73
|
+
expect(phone_validation_1.PHONE_PATTERN.test('999123456')).toBe(false);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const rfc_validation_1 = require("./rfc.validation");
|
|
4
|
+
describe('validateRFC', () => {
|
|
5
|
+
describe('valid RFCs', () => {
|
|
6
|
+
it('should accept valid RFC persona moral (12 chars)', () => {
|
|
7
|
+
const result = (0, rfc_validation_1.validateRFC)('HVP850101AB1');
|
|
8
|
+
expect(result.isValid).toBe(true);
|
|
9
|
+
expect(result.error).toBeUndefined();
|
|
10
|
+
});
|
|
11
|
+
it('should accept valid RFC persona física (13 chars)', () => {
|
|
12
|
+
const result = (0, rfc_validation_1.validateRFC)('GARC850101AB1');
|
|
13
|
+
expect(result.isValid).toBe(true);
|
|
14
|
+
expect(result.error).toBeUndefined();
|
|
15
|
+
});
|
|
16
|
+
it('should accept RFC with Ñ', () => {
|
|
17
|
+
const result = (0, rfc_validation_1.validateRFC)('MÑO850101AB1');
|
|
18
|
+
expect(result.isValid).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
it('should accept RFC with &', () => {
|
|
21
|
+
const result = (0, rfc_validation_1.validateRFC)('M&O850101AB1');
|
|
22
|
+
expect(result.isValid).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
it('should accept lowercase RFC (normalized)', () => {
|
|
25
|
+
const result = (0, rfc_validation_1.validateRFC)('hvp850101ab1');
|
|
26
|
+
expect(result.isValid).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
it('should accept RFC with whitespace (trimmed)', () => {
|
|
29
|
+
const result = (0, rfc_validation_1.validateRFC)(' HVP850101AB1 ');
|
|
30
|
+
expect(result.isValid).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe('invalid RFCs', () => {
|
|
34
|
+
it('should reject empty string', () => {
|
|
35
|
+
const result = (0, rfc_validation_1.validateRFC)('');
|
|
36
|
+
expect(result.isValid).toBe(false);
|
|
37
|
+
expect(result.error).toBe('RFC es requerido');
|
|
38
|
+
});
|
|
39
|
+
it('should reject null', () => {
|
|
40
|
+
const result = (0, rfc_validation_1.validateRFC)(null);
|
|
41
|
+
expect(result.isValid).toBe(false);
|
|
42
|
+
expect(result.error).toBe('RFC es requerido');
|
|
43
|
+
});
|
|
44
|
+
it('should reject undefined', () => {
|
|
45
|
+
const result = (0, rfc_validation_1.validateRFC)(undefined);
|
|
46
|
+
expect(result.isValid).toBe(false);
|
|
47
|
+
expect(result.error).toBe('RFC es requerido');
|
|
48
|
+
});
|
|
49
|
+
it('should reject whitespace only', () => {
|
|
50
|
+
const result = (0, rfc_validation_1.validateRFC)(' ');
|
|
51
|
+
expect(result.isValid).toBe(false);
|
|
52
|
+
expect(result.error).toBe('RFC es requerido');
|
|
53
|
+
});
|
|
54
|
+
it('should reject RFC too short', () => {
|
|
55
|
+
const result = (0, rfc_validation_1.validateRFC)('HVP850101');
|
|
56
|
+
expect(result.isValid).toBe(false);
|
|
57
|
+
expect(result.error).toContain('RFC inválido');
|
|
58
|
+
});
|
|
59
|
+
it('should reject RFC too long', () => {
|
|
60
|
+
const result = (0, rfc_validation_1.validateRFC)('GARC850101AB1X');
|
|
61
|
+
expect(result.isValid).toBe(false);
|
|
62
|
+
expect(result.error).toContain('RFC inválido');
|
|
63
|
+
});
|
|
64
|
+
it('should reject RFC with invalid characters', () => {
|
|
65
|
+
const result = (0, rfc_validation_1.validateRFC)('HVP-850101AB1');
|
|
66
|
+
expect(result.isValid).toBe(false);
|
|
67
|
+
expect(result.error).toContain('RFC inválido');
|
|
68
|
+
});
|
|
69
|
+
it('should reject RFC with wrong format', () => {
|
|
70
|
+
const result = (0, rfc_validation_1.validateRFC)('123456789012');
|
|
71
|
+
expect(result.isValid).toBe(false);
|
|
72
|
+
expect(result.error).toContain('RFC inválido');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe('normalizeRFC', () => {
|
|
77
|
+
it('should convert to uppercase', () => {
|
|
78
|
+
expect((0, rfc_validation_1.normalizeRFC)('hvp850101ab1')).toBe('HVP850101AB1');
|
|
79
|
+
});
|
|
80
|
+
it('should trim whitespace', () => {
|
|
81
|
+
expect((0, rfc_validation_1.normalizeRFC)(' HVP850101AB1 ')).toBe('HVP850101AB1');
|
|
82
|
+
});
|
|
83
|
+
it('should handle mixed case', () => {
|
|
84
|
+
expect((0, rfc_validation_1.normalizeRFC)('HvP850101Ab1')).toBe('HVP850101AB1');
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
describe('RFC_PATTERN', () => {
|
|
88
|
+
it('should match valid RFC persona moral', () => {
|
|
89
|
+
expect(rfc_validation_1.RFC_PATTERN.test('HVP850101AB1')).toBe(true);
|
|
90
|
+
});
|
|
91
|
+
it('should match valid RFC persona física', () => {
|
|
92
|
+
expect(rfc_validation_1.RFC_PATTERN.test('GARC850101AB1')).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
it('should not match invalid RFC', () => {
|
|
95
|
+
expect(rfc_validation_1.RFC_PATTERN.test('INVALID')).toBe(false);
|
|
96
|
+
});
|
|
97
|
+
});
|