@br-validators/core 0.10.0-alpha.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/LICENSE +21 -0
- package/README.md +91 -0
- package/dist/boleto.d.ts +113 -0
- package/dist/boleto.js +4 -0
- package/dist/boleto.js.map +1 -0
- package/dist/cartao-credito.d.ts +47 -0
- package/dist/cartao-credito.js +4 -0
- package/dist/cartao-credito.js.map +1 -0
- package/dist/cep.d.ts +20 -0
- package/dist/cep.js +7 -0
- package/dist/cep.js.map +1 -0
- package/dist/chunk-54DTXC6V.js +207 -0
- package/dist/chunk-54DTXC6V.js.map +1 -0
- package/dist/chunk-7FOWIH6F.js +20 -0
- package/dist/chunk-7FOWIH6F.js.map +1 -0
- package/dist/chunk-AKJHIJ5E.js +387 -0
- package/dist/chunk-AKJHIJ5E.js.map +1 -0
- package/dist/chunk-B2TDI3YS.js +23 -0
- package/dist/chunk-B2TDI3YS.js.map +1 -0
- package/dist/chunk-DKRM66US.js +35 -0
- package/dist/chunk-DKRM66US.js.map +1 -0
- package/dist/chunk-EB3G4IG6.js +8 -0
- package/dist/chunk-EB3G4IG6.js.map +1 -0
- package/dist/chunk-M66MGLHE.js +156 -0
- package/dist/chunk-M66MGLHE.js.map +1 -0
- package/dist/chunk-OWJ5HN4T.js +91 -0
- package/dist/chunk-OWJ5HN4T.js.map +1 -0
- package/dist/chunk-PBNVKDCF.js +82 -0
- package/dist/chunk-PBNVKDCF.js.map +1 -0
- package/dist/chunk-RMKTJQBB.js +61 -0
- package/dist/chunk-RMKTJQBB.js.map +1 -0
- package/dist/chunk-RZ2JG5PP.js +14 -0
- package/dist/chunk-RZ2JG5PP.js.map +1 -0
- package/dist/chunk-SE33CFGM.js +276 -0
- package/dist/chunk-SE33CFGM.js.map +1 -0
- package/dist/chunk-UCJPSJN5.js +8 -0
- package/dist/chunk-UCJPSJN5.js.map +1 -0
- package/dist/chunk-W6UXVWSR.js +13 -0
- package/dist/chunk-W6UXVWSR.js.map +1 -0
- package/dist/chunk-YY4M2YS6.js +115 -0
- package/dist/chunk-YY4M2YS6.js.map +1 -0
- package/dist/chunk-Z4F75QEC.js +1180 -0
- package/dist/chunk-Z4F75QEC.js.map +1 -0
- package/dist/cnpj.d.ts +37 -0
- package/dist/cnpj.js +7 -0
- package/dist/cnpj.js.map +1 -0
- package/dist/cpf.d.ts +20 -0
- package/dist/cpf.js +7 -0
- package/dist/cpf.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/inscricao-estadual.d.ts +57 -0
- package/dist/inscricao-estadual.js +4 -0
- package/dist/inscricao-estadual.js.map +1 -0
- package/dist/pis-pasep.d.ts +20 -0
- package/dist/pis-pasep.js +5 -0
- package/dist/pis-pasep.js.map +1 -0
- package/dist/pix-DP6jnwpN.d.ts +44 -0
- package/dist/pix.d.ts +11 -0
- package/dist/pix.js +9 -0
- package/dist/pix.js.map +1 -0
- package/dist/placa.d.ts +35 -0
- package/dist/placa.js +7 -0
- package/dist/placa.js.map +1 -0
- package/dist/validation-result-BK4qJuei.d.ts +101 -0
- package/package.json +91 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { validateCnpj, applyCnpjMask, detectCnpjFormat } from './chunk-M66MGLHE.js';
|
|
2
|
+
import { stripCnpj } from './chunk-EB3G4IG6.js';
|
|
3
|
+
import { validateCpf, applyCpfMask } from './chunk-PBNVKDCF.js';
|
|
4
|
+
import { stripCpf } from './chunk-UCJPSJN5.js';
|
|
5
|
+
import { brandPixKey } from './chunk-DKRM66US.js';
|
|
6
|
+
|
|
7
|
+
// src/core/pix/cnpj.ts
|
|
8
|
+
function failure(code, message) {
|
|
9
|
+
return { ok: false, code, message, keyType: "cnpj" };
|
|
10
|
+
}
|
|
11
|
+
function validatePixCnpjKey(input) {
|
|
12
|
+
const trimmed = input.trim();
|
|
13
|
+
if (trimmed.length === 0) {
|
|
14
|
+
return failure("EMPTY_INPUT", "PIX CNPJ key input is empty");
|
|
15
|
+
}
|
|
16
|
+
const result = validateCnpj(trimmed);
|
|
17
|
+
if (!result.ok) {
|
|
18
|
+
return { ok: false, code: result.code, message: result.message, keyType: "cnpj" };
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
ok: true,
|
|
22
|
+
value: brandPixKey(result.value),
|
|
23
|
+
keyType: "cnpj",
|
|
24
|
+
format: result.format
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/core/pix/cpf.ts
|
|
29
|
+
function failure2(code, message) {
|
|
30
|
+
return { ok: false, code, message, keyType: "cpf" };
|
|
31
|
+
}
|
|
32
|
+
function validatePixCpfKey(input) {
|
|
33
|
+
const trimmed = input.trim();
|
|
34
|
+
if (trimmed.length === 0) {
|
|
35
|
+
return failure2("EMPTY_INPUT", "PIX CPF key input is empty");
|
|
36
|
+
}
|
|
37
|
+
const result = validateCpf(trimmed);
|
|
38
|
+
if (!result.ok) {
|
|
39
|
+
return { ok: false, code: result.code, message: result.message, keyType: "cpf" };
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
ok: true,
|
|
43
|
+
value: brandPixKey(result.value),
|
|
44
|
+
keyType: "cpf",
|
|
45
|
+
format: result.format
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/core/pix/constants.ts
|
|
50
|
+
var PIX_EMAIL_MAX_LENGTH = 77;
|
|
51
|
+
var PIX_EMAIL_PATTERN = /^[a-z0-9.!#$'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/;
|
|
52
|
+
var PIX_PHONE_E164_PATTERN = /^\+[1-9]\d{1,14}$/;
|
|
53
|
+
var PIX_PHONE_BR_MOBILE_PATTERN = /^\+55\d{2}9\d{8}$/;
|
|
54
|
+
var PIX_EVP_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
55
|
+
var PIX_CPF_DIGITS_PATTERN = /^[0-9]{11}$/;
|
|
56
|
+
var PIX_GOLDEN_CPF = "12345678909";
|
|
57
|
+
var PIX_GOLDEN_CNPJ_NUMERIC = "11222333000181";
|
|
58
|
+
var PIX_GOLDEN_CNPJ_ALPHANUMERIC = "12ABC34501DE35";
|
|
59
|
+
var PIX_GOLDEN_EMAIL = "pix@bcb.gov.br";
|
|
60
|
+
var PIX_GOLDEN_PHONE = "+5510998765432";
|
|
61
|
+
var PIX_GOLDEN_EVP = "123e4567-e89b-12d3-a456-426655440000";
|
|
62
|
+
var PIX_OFFICIAL_SOURCE_URL = "https://www.bcb.gov.br/content/estabilidadefinanceira/pix/Regulamento_Pix/II_ManualdePadroesparaIniciacaodoPix.pdf";
|
|
63
|
+
var PIX_DICT_API_SOURCE_URL = "https://aprendervalor.bcb.gov.br/content/estabilidadefinanceira/pix/API-DICT_v2-9-0.html";
|
|
64
|
+
|
|
65
|
+
// src/core/pix/detect.ts
|
|
66
|
+
function isCpfShapedInput(input) {
|
|
67
|
+
const trimmed = input.trim();
|
|
68
|
+
const stripped = stripCpf(trimmed);
|
|
69
|
+
if (!PIX_CPF_DIGITS_PATTERN.test(stripped)) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return /^[\d.\-\s]+$/.test(trimmed);
|
|
73
|
+
}
|
|
74
|
+
function isCnpjShapedInput(input) {
|
|
75
|
+
const trimmed = input.trim();
|
|
76
|
+
const stripped = stripCnpj(trimmed);
|
|
77
|
+
if (detectCnpjFormat(stripped) === "unknown") {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
return /^[A-Za-z0-9./\-\s]+$/.test(trimmed);
|
|
81
|
+
}
|
|
82
|
+
function detectPixKeyType(input) {
|
|
83
|
+
const trimmed = input.trim();
|
|
84
|
+
if (trimmed.length === 0) {
|
|
85
|
+
return "unknown";
|
|
86
|
+
}
|
|
87
|
+
if (trimmed.includes("@")) {
|
|
88
|
+
return "email";
|
|
89
|
+
}
|
|
90
|
+
if (trimmed.startsWith("+")) {
|
|
91
|
+
return "phone";
|
|
92
|
+
}
|
|
93
|
+
if (PIX_EVP_PATTERN.test(trimmed)) {
|
|
94
|
+
return "evp";
|
|
95
|
+
}
|
|
96
|
+
if (isCpfShapedInput(trimmed)) {
|
|
97
|
+
return "cpf";
|
|
98
|
+
}
|
|
99
|
+
if (isCnpjShapedInput(trimmed)) {
|
|
100
|
+
return "cnpj";
|
|
101
|
+
}
|
|
102
|
+
return "unknown";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/core/pix/email.ts
|
|
106
|
+
function failure3(code, message) {
|
|
107
|
+
return { ok: false, code, message, keyType: "email" };
|
|
108
|
+
}
|
|
109
|
+
function validatePixEmailKey(input) {
|
|
110
|
+
const trimmed = input.trim();
|
|
111
|
+
if (trimmed.length === 0) {
|
|
112
|
+
return failure3("EMPTY_INPUT", "PIX email key input is empty");
|
|
113
|
+
}
|
|
114
|
+
if (trimmed !== trimmed.toLowerCase()) {
|
|
115
|
+
return failure3("INVALID_CHARACTER", "PIX email key must be lowercase");
|
|
116
|
+
}
|
|
117
|
+
if (trimmed.length > PIX_EMAIL_MAX_LENGTH) {
|
|
118
|
+
return failure3("INVALID_LENGTH", `PIX email key must have at most ${PIX_EMAIL_MAX_LENGTH} characters`);
|
|
119
|
+
}
|
|
120
|
+
if (!trimmed.includes("@") || !PIX_EMAIL_PATTERN.test(trimmed)) {
|
|
121
|
+
return failure3("UNSUPPORTED_FORMAT", "PIX email key format is invalid");
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
ok: true,
|
|
125
|
+
value: brandPixKey(trimmed),
|
|
126
|
+
keyType: "email",
|
|
127
|
+
format: "email"
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// src/core/pix/evp.ts
|
|
132
|
+
function failure4(code, message) {
|
|
133
|
+
return { ok: false, code, message, keyType: "evp" };
|
|
134
|
+
}
|
|
135
|
+
function validatePixEvpKey(input) {
|
|
136
|
+
const trimmed = input.trim();
|
|
137
|
+
if (trimmed.length === 0) {
|
|
138
|
+
return failure4("EMPTY_INPUT", "PIX EVP key input is empty");
|
|
139
|
+
}
|
|
140
|
+
if (trimmed !== trimmed.toLowerCase()) {
|
|
141
|
+
return failure4("INVALID_CHARACTER", "PIX EVP key must be lowercase");
|
|
142
|
+
}
|
|
143
|
+
if (!PIX_EVP_PATTERN.test(trimmed)) {
|
|
144
|
+
return failure4("UNSUPPORTED_FORMAT", "PIX EVP key must be a lowercase UUID with hyphens");
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
ok: true,
|
|
148
|
+
value: brandPixKey(trimmed),
|
|
149
|
+
keyType: "evp",
|
|
150
|
+
format: "evp"
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// src/core/pix/phone.ts
|
|
155
|
+
function failure5(code, message) {
|
|
156
|
+
return { ok: false, code, message, keyType: "phone" };
|
|
157
|
+
}
|
|
158
|
+
function validatePixPhoneKey(input) {
|
|
159
|
+
const trimmed = input.trim();
|
|
160
|
+
if (trimmed.length === 0) {
|
|
161
|
+
return failure5("EMPTY_INPUT", "PIX phone key input is empty");
|
|
162
|
+
}
|
|
163
|
+
if (!trimmed.startsWith("+")) {
|
|
164
|
+
return failure5("INVALID_CHARACTER", "PIX phone key must start with + (E.164)");
|
|
165
|
+
}
|
|
166
|
+
if (!PIX_PHONE_E164_PATTERN.test(trimmed)) {
|
|
167
|
+
return failure5("INVALID_CHARACTER", "PIX phone key contains invalid characters");
|
|
168
|
+
}
|
|
169
|
+
if (!trimmed.startsWith("+55")) {
|
|
170
|
+
return failure5("UNSUPPORTED_FORMAT", "PIX phone key must use Brazilian country code +55");
|
|
171
|
+
}
|
|
172
|
+
if (!PIX_PHONE_BR_MOBILE_PATTERN.test(trimmed)) {
|
|
173
|
+
return failure5("UNSUPPORTED_FORMAT", "PIX phone key must match Brazilian mobile format +55DD9XXXXXXXX");
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
ok: true,
|
|
177
|
+
value: brandPixKey(trimmed),
|
|
178
|
+
keyType: "phone",
|
|
179
|
+
format: "phone"
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// src/core/pix/mask.ts
|
|
184
|
+
function applyPixCpfKeyMask(canonical) {
|
|
185
|
+
return applyCpfMask(canonical);
|
|
186
|
+
}
|
|
187
|
+
function applyPixCnpjKeyMask(canonical) {
|
|
188
|
+
return applyCnpjMask(canonical);
|
|
189
|
+
}
|
|
190
|
+
function applyPixPhoneKeyMask(e164) {
|
|
191
|
+
const match = /^\+55(\d{2})(9\d{4})(\d{4})$/.exec(e164);
|
|
192
|
+
if (!match) {
|
|
193
|
+
throw new Error("PIX phone key must be a validated Brazilian mobile E.164 number");
|
|
194
|
+
}
|
|
195
|
+
return `+55 (${match[1]}) ${match[2]}-${match[3]}`;
|
|
196
|
+
}
|
|
197
|
+
function applyPixEmailKeyMask(email) {
|
|
198
|
+
return email.toLowerCase().trim();
|
|
199
|
+
}
|
|
200
|
+
function applyPixEvpKeyMask(uuid) {
|
|
201
|
+
return uuid.toLowerCase();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// src/core/pix/index.ts
|
|
205
|
+
function failure6(code, message, keyType) {
|
|
206
|
+
return { ok: false, code, message, ...keyType ? { keyType } : {} };
|
|
207
|
+
}
|
|
208
|
+
function validateByType(input, keyType) {
|
|
209
|
+
switch (keyType) {
|
|
210
|
+
case "cpf":
|
|
211
|
+
return validatePixCpfKey(input);
|
|
212
|
+
case "cnpj":
|
|
213
|
+
return validatePixCnpjKey(input);
|
|
214
|
+
case "email":
|
|
215
|
+
return validatePixEmailKey(input);
|
|
216
|
+
case "phone":
|
|
217
|
+
return validatePixPhoneKey(input);
|
|
218
|
+
case "evp":
|
|
219
|
+
return validatePixEvpKey(input);
|
|
220
|
+
default: {
|
|
221
|
+
const _exhaustive = keyType;
|
|
222
|
+
return failure6("UNSUPPORTED_FORMAT", `Unknown PIX key type: ${_exhaustive}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function isValidPixKey(input, options) {
|
|
227
|
+
return validatePixKey(input, options).ok;
|
|
228
|
+
}
|
|
229
|
+
function validatePixKey(input, options) {
|
|
230
|
+
const trimmed = input.trim();
|
|
231
|
+
if (trimmed.length === 0) {
|
|
232
|
+
return failure6("EMPTY_INPUT", "PIX key input is empty");
|
|
233
|
+
}
|
|
234
|
+
const detected = detectPixKeyType(trimmed);
|
|
235
|
+
if (options?.type !== void 0) {
|
|
236
|
+
if (detected !== "unknown" && detected !== options.type) {
|
|
237
|
+
return failure6(
|
|
238
|
+
"UNSUPPORTED_FORMAT",
|
|
239
|
+
`PIX key detected as ${detected} but forced type is ${options.type}`,
|
|
240
|
+
options.type
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
return validateByType(trimmed, options.type);
|
|
244
|
+
}
|
|
245
|
+
if (detected === "unknown") {
|
|
246
|
+
return failure6("UNSUPPORTED_FORMAT", "PIX key type could not be determined");
|
|
247
|
+
}
|
|
248
|
+
return validateByType(trimmed, detected);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// src/format/pix.ts
|
|
252
|
+
function applyPixMask(keyType, value) {
|
|
253
|
+
switch (keyType) {
|
|
254
|
+
case "cpf":
|
|
255
|
+
return applyPixCpfKeyMask(value);
|
|
256
|
+
case "cnpj":
|
|
257
|
+
return applyPixCnpjKeyMask(value);
|
|
258
|
+
case "phone":
|
|
259
|
+
return applyPixPhoneKeyMask(value);
|
|
260
|
+
case "email":
|
|
261
|
+
return applyPixEmailKeyMask(value);
|
|
262
|
+
case "evp":
|
|
263
|
+
return applyPixEvpKeyMask(value);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function formatPixKey(input, options) {
|
|
267
|
+
const result = validatePixKey(input, options);
|
|
268
|
+
if (!result.ok) {
|
|
269
|
+
return { ok: false, code: result.code, message: result.message };
|
|
270
|
+
}
|
|
271
|
+
return { ok: true, formatted: applyPixMask(result.keyType, result.value) };
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export { PIX_DICT_API_SOURCE_URL, PIX_GOLDEN_CNPJ_ALPHANUMERIC, PIX_GOLDEN_CNPJ_NUMERIC, PIX_GOLDEN_CPF, PIX_GOLDEN_EMAIL, PIX_GOLDEN_EVP, PIX_GOLDEN_PHONE, PIX_OFFICIAL_SOURCE_URL, applyPixCnpjKeyMask, applyPixCpfKeyMask, applyPixEmailKeyMask, applyPixEvpKeyMask, applyPixPhoneKeyMask, detectPixKeyType, formatPixKey, isValidPixKey, validatePixCnpjKey, validatePixCpfKey, validatePixEmailKey, validatePixEvpKey, validatePixKey, validatePixPhoneKey };
|
|
275
|
+
//# sourceMappingURL=chunk-SE33CFGM.js.map
|
|
276
|
+
//# sourceMappingURL=chunk-SE33CFGM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/pix/cnpj.ts","../src/core/pix/cpf.ts","../src/core/pix/constants.ts","../src/core/pix/detect.ts","../src/core/pix/email.ts","../src/core/pix/evp.ts","../src/core/pix/phone.ts","../src/core/pix/mask.ts","../src/core/pix/index.ts","../src/format/pix.ts"],"names":["failure"],"mappings":"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","file":"chunk-SE33CFGM.js","sourcesContent":["import { validateCnpj } from '../cnpj/index.js';\nimport type { PixValidationResult } from '../../types/validation-result.js';\nimport { brandPixKey } from '../../types/validation-result.js';\n\ntype FailedResult = Extract<PixValidationResult, { ok: false }>;\n\nfunction failure(code: FailedResult['code'], message: string): FailedResult {\n return { ok: false, code, message, keyType: 'cnpj' };\n}\n\nexport function validatePixCnpjKey(input: string): PixValidationResult {\n const trimmed = input.trim();\n if (trimmed.length === 0) {\n return failure('EMPTY_INPUT', 'PIX CNPJ key input is empty');\n }\n\n const result = validateCnpj(trimmed);\n if (!result.ok) {\n return { ok: false, code: result.code, message: result.message, keyType: 'cnpj' };\n }\n\n return {\n ok: true,\n value: brandPixKey(result.value),\n keyType: 'cnpj',\n format: result.format,\n };\n}\n","import { validateCpf } from '../cpf/index.js';\nimport type { PixValidationResult } from '../../types/validation-result.js';\nimport { brandPixKey } from '../../types/validation-result.js';\n\ntype FailedResult = Extract<PixValidationResult, { ok: false }>;\n\nfunction failure(code: FailedResult['code'], message: string): FailedResult {\n return { ok: false, code, message, keyType: 'cpf' };\n}\n\nexport function validatePixCpfKey(input: string): PixValidationResult {\n const trimmed = input.trim();\n if (trimmed.length === 0) {\n return failure('EMPTY_INPUT', 'PIX CPF key input is empty');\n }\n\n const result = validateCpf(trimmed);\n if (!result.ok) {\n return { ok: false, code: result.code, message: result.message, keyType: 'cpf' };\n }\n\n return {\n ok: true,\n value: brandPixKey(result.value),\n keyType: 'cpf',\n format: result.format,\n };\n}\n","/**\n * PIX key constants — Bacen DICT API + Manual de Iniciação do Pix.\n * @see https://aprendervalor.bcb.gov.br/content/estabilidadefinanceira/pix/API-DICT_v2-9-0.html\n * @see https://www.bcb.gov.br/content/estabilidadefinanceira/pix/Regulamento_Pix/II_ManualdePadroesparaIniciacaodoPix.pdf\n * @see docs/use-cases/UC-005-validate-pix-key.md\n */\nexport const PIX_EMAIL_MAX_LENGTH = 77;\nexport const PIX_EMAIL_PATTERN =\n /^[a-z0-9.!#$'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/;\n\nexport const PIX_PHONE_E164_PATTERN = /^\\+[1-9]\\d{1,14}$/;\nexport const PIX_PHONE_BR_MOBILE_PATTERN = /^\\+55\\d{2}9\\d{8}$/;\n\nexport const PIX_EVP_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;\n\nexport const PIX_CPF_DIGITS_PATTERN = /^[0-9]{11}$/;\n\nexport const PIX_GOLDEN_CPF = '12345678909';\nexport const PIX_GOLDEN_CNPJ_NUMERIC = '11222333000181';\nexport const PIX_GOLDEN_CNPJ_ALPHANUMERIC = '12ABC34501DE35';\nexport const PIX_GOLDEN_EMAIL = 'pix@bcb.gov.br';\nexport const PIX_GOLDEN_PHONE = '+5510998765432';\nexport const PIX_GOLDEN_PHONE_SECONDARY = '+5561912345678';\nexport const PIX_GOLDEN_EVP = '123e4567-e89b-12d3-a456-426655440000';\nexport const PIX_GOLDEN_EMAIL_SECONDARY = 'fulano_da_silva.recebedor@example.com';\n\nexport const PIX_OFFICIAL_SOURCE_URL =\n 'https://www.bcb.gov.br/content/estabilidadefinanceira/pix/Regulamento_Pix/II_ManualdePadroesparaIniciacaodoPix.pdf';\n\nexport const PIX_DICT_API_SOURCE_URL =\n 'https://aprendervalor.bcb.gov.br/content/estabilidadefinanceira/pix/API-DICT_v2-9-0.html';\n","import { stripCnpj } from '../../strip/cnpj.js';\nimport { stripCpf } from '../../strip/cpf.js';\nimport type { PixKeyType } from '../../types/validation-result.js';\nimport { detectCnpjFormat } from '../cnpj/detect.js';\nimport {\n PIX_CPF_DIGITS_PATTERN,\n PIX_EVP_PATTERN,\n} from './constants.js';\n\nexport type DetectedPixKeyType = PixKeyType | 'unknown';\n\nfunction isCpfShapedInput(input: string): boolean {\n const trimmed = input.trim();\n const stripped = stripCpf(trimmed);\n if (!PIX_CPF_DIGITS_PATTERN.test(stripped)) {\n return false;\n }\n return /^[\\d.\\-\\s]+$/.test(trimmed);\n}\n\nfunction isCnpjShapedInput(input: string): boolean {\n const trimmed = input.trim();\n const stripped = stripCnpj(trimmed);\n if (detectCnpjFormat(stripped) === 'unknown') {\n return false;\n }\n return /^[A-Za-z0-9./\\-\\s]+$/.test(trimmed);\n}\n\nexport function detectPixKeyType(input: string): DetectedPixKeyType {\n const trimmed = input.trim();\n if (trimmed.length === 0) {\n return 'unknown';\n }\n\n if (trimmed.includes('@')) {\n return 'email';\n }\n\n if (trimmed.startsWith('+')) {\n return 'phone';\n }\n\n if (PIX_EVP_PATTERN.test(trimmed)) {\n return 'evp';\n }\n\n if (isCpfShapedInput(trimmed)) {\n return 'cpf';\n }\n\n if (isCnpjShapedInput(trimmed)) {\n return 'cnpj';\n }\n\n return 'unknown';\n}\n","import type { PixValidationResult } from '../../types/validation-result.js';\nimport { brandPixKey } from '../../types/validation-result.js';\nimport { PIX_EMAIL_MAX_LENGTH, PIX_EMAIL_PATTERN } from './constants.js';\n\ntype FailedResult = Extract<PixValidationResult, { ok: false }>;\n\nfunction failure(code: FailedResult['code'], message: string): FailedResult {\n return { ok: false, code, message, keyType: 'email' };\n}\n\nexport function validatePixEmailKey(input: string): PixValidationResult {\n const trimmed = input.trim();\n if (trimmed.length === 0) {\n return failure('EMPTY_INPUT', 'PIX email key input is empty');\n }\n\n if (trimmed !== trimmed.toLowerCase()) {\n return failure('INVALID_CHARACTER', 'PIX email key must be lowercase');\n }\n\n if (trimmed.length > PIX_EMAIL_MAX_LENGTH) {\n return failure('INVALID_LENGTH', `PIX email key must have at most ${PIX_EMAIL_MAX_LENGTH} characters`);\n }\n\n if (!trimmed.includes('@') || !PIX_EMAIL_PATTERN.test(trimmed)) {\n return failure('UNSUPPORTED_FORMAT', 'PIX email key format is invalid');\n }\n\n return {\n ok: true,\n value: brandPixKey(trimmed),\n keyType: 'email',\n format: 'email',\n };\n}\n","import type { PixValidationResult } from '../../types/validation-result.js';\nimport { brandPixKey } from '../../types/validation-result.js';\nimport { PIX_EVP_PATTERN } from './constants.js';\n\ntype FailedResult = Extract<PixValidationResult, { ok: false }>;\n\nfunction failure(code: FailedResult['code'], message: string): FailedResult {\n return { ok: false, code, message, keyType: 'evp' };\n}\n\nexport function validatePixEvpKey(input: string): PixValidationResult {\n const trimmed = input.trim();\n if (trimmed.length === 0) {\n return failure('EMPTY_INPUT', 'PIX EVP key input is empty');\n }\n\n if (trimmed !== trimmed.toLowerCase()) {\n return failure('INVALID_CHARACTER', 'PIX EVP key must be lowercase');\n }\n\n if (!PIX_EVP_PATTERN.test(trimmed)) {\n return failure('UNSUPPORTED_FORMAT', 'PIX EVP key must be a lowercase UUID with hyphens');\n }\n\n return {\n ok: true,\n value: brandPixKey(trimmed),\n keyType: 'evp',\n format: 'evp',\n };\n}\n","import type { PixValidationResult } from '../../types/validation-result.js';\nimport { brandPixKey } from '../../types/validation-result.js';\nimport { PIX_PHONE_BR_MOBILE_PATTERN, PIX_PHONE_E164_PATTERN } from './constants.js';\n\ntype FailedResult = Extract<PixValidationResult, { ok: false }>;\n\nfunction failure(code: FailedResult['code'], message: string): FailedResult {\n return { ok: false, code, message, keyType: 'phone' };\n}\n\nexport function validatePixPhoneKey(input: string): PixValidationResult {\n const trimmed = input.trim();\n if (trimmed.length === 0) {\n return failure('EMPTY_INPUT', 'PIX phone key input is empty');\n }\n\n if (!trimmed.startsWith('+')) {\n return failure('INVALID_CHARACTER', 'PIX phone key must start with + (E.164)');\n }\n\n if (!PIX_PHONE_E164_PATTERN.test(trimmed)) {\n return failure('INVALID_CHARACTER', 'PIX phone key contains invalid characters');\n }\n\n if (!trimmed.startsWith('+55')) {\n return failure('UNSUPPORTED_FORMAT', 'PIX phone key must use Brazilian country code +55');\n }\n\n if (!PIX_PHONE_BR_MOBILE_PATTERN.test(trimmed)) {\n return failure('UNSUPPORTED_FORMAT', 'PIX phone key must match Brazilian mobile format +55DD9XXXXXXXX');\n }\n\n return {\n ok: true,\n value: brandPixKey(trimmed),\n keyType: 'phone',\n format: 'phone',\n };\n}\n","/**\n * PIX key display masks — delegates to parent validators where applicable (BR-PIX-001…005).\n * @see docs/use-cases/UC-003-format-document.md\n */\nimport { applyCnpjMask } from '../cnpj/mask.js';\nimport { applyCpfMask } from '../cpf/mask.js';\n\nexport function applyPixCpfKeyMask(canonical: string): string {\n return applyCpfMask(canonical);\n}\n\nexport function applyPixCnpjKeyMask(canonical: string): string {\n return applyCnpjMask(canonical);\n}\n\n/** Brazilian mobile E.164 → +55 (DD) 9XXXX-XXXX display. */\nexport function applyPixPhoneKeyMask(e164: string): string {\n const match = /^\\+55(\\d{2})(9\\d{4})(\\d{4})$/.exec(e164);\n if (!match) {\n throw new Error('PIX phone key must be a validated Brazilian mobile E.164 number');\n }\n return `+55 (${match[1]}) ${match[2]}-${match[3]}`;\n}\n\nexport function applyPixEmailKeyMask(email: string): string {\n return email.toLowerCase().trim();\n}\n\nexport function applyPixEvpKeyMask(uuid: string): string {\n return uuid.toLowerCase();\n}\n","/**\n * PIX key validation — five Bacen types (CPF, CNPJ, email, phone, EVP).\n * @see docs/use-cases/UC-005-validate-pix-key.md\n */\nimport type { PixKeyType, PixValidationResult } from '../../types/validation-result.js';\nimport { validatePixCnpjKey } from './cnpj.js';\nimport { validatePixCpfKey } from './cpf.js';\nimport { detectPixKeyType } from './detect.js';\nimport { validatePixEmailKey } from './email.js';\nimport { validatePixEvpKey } from './evp.js';\nimport { validatePixPhoneKey } from './phone.js';\n\nexport {\n PIX_DICT_API_SOURCE_URL,\n PIX_GOLDEN_CNPJ_ALPHANUMERIC,\n PIX_GOLDEN_CNPJ_NUMERIC,\n PIX_GOLDEN_CPF,\n PIX_GOLDEN_EMAIL,\n PIX_GOLDEN_EMAIL_SECONDARY,\n PIX_GOLDEN_EVP,\n PIX_GOLDEN_PHONE,\n PIX_GOLDEN_PHONE_SECONDARY,\n PIX_OFFICIAL_SOURCE_URL,\n} from './constants.js';\nexport { detectPixKeyType, type DetectedPixKeyType } from './detect.js';\nexport { validatePixCpfKey } from './cpf.js';\nexport { validatePixCnpjKey } from './cnpj.js';\nexport { validatePixEmailKey } from './email.js';\nexport { validatePixPhoneKey } from './phone.js';\nexport { validatePixEvpKey } from './evp.js';\nexport {\n applyPixCnpjKeyMask,\n applyPixCpfKeyMask,\n applyPixEmailKeyMask,\n applyPixEvpKeyMask,\n applyPixPhoneKeyMask,\n} from './mask.js';\n\nexport type ValidatePixKeyOptions = {\n type?: PixKeyType;\n};\n\ntype FailedResult = Extract<PixValidationResult, { ok: false }>;\n\nfunction failure(code: FailedResult['code'], message: string, keyType?: PixKeyType): FailedResult {\n return { ok: false, code, message, ...(keyType ? { keyType } : {}) };\n}\n\nfunction validateByType(input: string, keyType: PixKeyType): PixValidationResult {\n switch (keyType) {\n case 'cpf':\n return validatePixCpfKey(input);\n case 'cnpj':\n return validatePixCnpjKey(input);\n case 'email':\n return validatePixEmailKey(input);\n case 'phone':\n return validatePixPhoneKey(input);\n case 'evp':\n return validatePixEvpKey(input);\n default: {\n const _exhaustive: never = keyType;\n return failure('UNSUPPORTED_FORMAT', `Unknown PIX key type: ${_exhaustive}`);\n }\n }\n}\n\nexport function isValidPixKey(input: string, options?: ValidatePixKeyOptions): boolean {\n return validatePixKey(input, options).ok;\n}\n\nexport function validatePixKey(input: string, options?: ValidatePixKeyOptions): PixValidationResult {\n const trimmed = input.trim();\n if (trimmed.length === 0) {\n return failure('EMPTY_INPUT', 'PIX key input is empty');\n }\n\n const detected = detectPixKeyType(trimmed);\n\n if (options?.type !== undefined) {\n if (detected !== 'unknown' && detected !== options.type) {\n return failure(\n 'UNSUPPORTED_FORMAT',\n `PIX key detected as ${detected} but forced type is ${options.type}`,\n options.type,\n );\n }\n return validateByType(trimmed, options.type);\n }\n\n if (detected === 'unknown') {\n return failure('UNSUPPORTED_FORMAT', 'PIX key type could not be determined');\n }\n\n return validateByType(trimmed, detected);\n}\n","/**\n * Format decorator — strip → validate → apply official mask (UC-003).\n * @see docs/use-cases/UC-003-format-document.md\n * @see docs/VALIDATION-RULES.md BR-GLOBAL-002\n */\nimport type { ValidatePixKeyOptions } from '../core/pix/index.js';\nimport { validatePixKey } from '../core/pix/index.js';\nimport {\n applyPixCnpjKeyMask,\n applyPixCpfKeyMask,\n applyPixEmailKeyMask,\n applyPixEvpKeyMask,\n applyPixPhoneKeyMask,\n} from '../core/pix/mask.js';\nimport type { FormatResult, PixKeyType } from '../types/validation-result.js';\n\nfunction applyPixMask(keyType: PixKeyType, value: string): string {\n switch (keyType) {\n case 'cpf':\n return applyPixCpfKeyMask(value);\n case 'cnpj':\n return applyPixCnpjKeyMask(value);\n case 'phone':\n return applyPixPhoneKeyMask(value);\n case 'email':\n return applyPixEmailKeyMask(value);\n case 'evp':\n return applyPixEvpKeyMask(value);\n }\n}\n\nexport function formatPixKey(input: string, options?: ValidatePixKeyOptions): FormatResult {\n const result = validatePixKey(input, options);\n if (!result.ok) {\n return { ok: false, code: result.code, message: result.message };\n }\n\n return { ok: true, formatted: applyPixMask(result.keyType, result.value) };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/strip/cpf.ts"],"names":[],"mappings":";AAIO,SAAS,SAAS,KAAA,EAAuB;AAC9C,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AAChC","file":"chunk-UCJPSJN5.js","sourcesContent":["/**\n * Strip CPF mask — digits only (BR-CPF-002).\n * @see https://www.gov.br/receitafederal/pt-br/assuntos/cpf\n */\nexport function stripCpf(input: string): string {\n return input.replace(/\\D/g, '');\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// src/strip/cep.ts
|
|
2
|
+
function stripCep(input) {
|
|
3
|
+
return input.replace(/\D/g, "");
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
// src/strip/placa.ts
|
|
7
|
+
function stripPlaca(input) {
|
|
8
|
+
return input.replace(/[^A-Za-z0-9]/g, "").toUpperCase();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export { stripCep, stripPlaca };
|
|
12
|
+
//# sourceMappingURL=chunk-W6UXVWSR.js.map
|
|
13
|
+
//# sourceMappingURL=chunk-W6UXVWSR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/strip/cep.ts","../src/strip/placa.ts"],"names":[],"mappings":";AAIO,SAAS,SAAS,KAAA,EAAuB;AAC9C,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AAChC;;;ACFO,SAAS,WAAW,KAAA,EAAuB;AAChD,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,eAAA,EAAiB,EAAE,EAAE,WAAA,EAAY;AACxD","file":"chunk-W6UXVWSR.js","sourcesContent":["/**\n * Strip CEP mask — digits only (BR-CEP-001).\n * @see https://www.correios.com.br/atendimento/developers/manuais/manual-api-busca-cep\n */\nexport function stripCep(input: string): string {\n return input.replace(/\\D/g, '');\n}\n","/**\n * Strip placa mask — preserve A-Z0-9, uppercase (BR-PLACA-004).\n * @see https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao7292018consolidada.pdf\n */\nexport function stripPlaca(input: string): string {\n return input.replace(/[^A-Za-z0-9]/g, '').toUpperCase();\n}\n"]}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { stripPlaca } from './chunk-W6UXVWSR.js';
|
|
2
|
+
import { brandPlaca } from './chunk-DKRM66US.js';
|
|
3
|
+
|
|
4
|
+
// src/core/placa/constants.ts
|
|
5
|
+
var PLACA_LENGTH = 7;
|
|
6
|
+
var PLACA_LEGACY_PATTERN = /^[A-Z]{3}[0-9]{4}$/;
|
|
7
|
+
var PLACA_MERCOSUL_PATTERN = /^[A-Z]{3}[0-9][A-Z0-9][0-9]{2}$/;
|
|
8
|
+
var PLACA_LEGACY_TO_MERCOSUL_MAP = {
|
|
9
|
+
"0": "A",
|
|
10
|
+
"1": "B",
|
|
11
|
+
"2": "C",
|
|
12
|
+
"3": "D",
|
|
13
|
+
"4": "E",
|
|
14
|
+
"5": "F",
|
|
15
|
+
"6": "G",
|
|
16
|
+
"7": "H",
|
|
17
|
+
"8": "I",
|
|
18
|
+
"9": "J"
|
|
19
|
+
};
|
|
20
|
+
var PLACA_GOLDEN_MERCOSUL = "ABC1D23";
|
|
21
|
+
var PLACA_GOLDEN_LEGACY = "ABC1234";
|
|
22
|
+
var PLACA_GOLDEN_CONVERSION_FROM = "ABC1234";
|
|
23
|
+
var PLACA_GOLDEN_CONVERSION_TO = "ABC1C34";
|
|
24
|
+
var PLACA_OFFICIAL_SOURCE_URL = "https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao7292018consolidada.pdf";
|
|
25
|
+
|
|
26
|
+
// src/core/placa/detect.ts
|
|
27
|
+
function detectPlacaFormat(input) {
|
|
28
|
+
const stripped = stripPlaca(input);
|
|
29
|
+
if (stripped.length !== PLACA_LENGTH) {
|
|
30
|
+
return "unknown";
|
|
31
|
+
}
|
|
32
|
+
if (PLACA_LEGACY_PATTERN.test(stripped)) {
|
|
33
|
+
return "legacy";
|
|
34
|
+
}
|
|
35
|
+
if (PLACA_MERCOSUL_PATTERN.test(stripped)) {
|
|
36
|
+
return "mercosul";
|
|
37
|
+
}
|
|
38
|
+
return "unknown";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/core/placa/legacy.ts
|
|
42
|
+
function isValidPlacaLegacy(input) {
|
|
43
|
+
const stripped = stripPlaca(input);
|
|
44
|
+
return PLACA_LEGACY_PATTERN.test(stripped);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/core/placa/mercosul.ts
|
|
48
|
+
function isValidPlacaMercosul(input) {
|
|
49
|
+
const stripped = stripPlaca(input);
|
|
50
|
+
return PLACA_MERCOSUL_PATTERN.test(stripped);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/core/placa/convert.ts
|
|
54
|
+
function failure(code, message) {
|
|
55
|
+
return { ok: false, code, message };
|
|
56
|
+
}
|
|
57
|
+
function convertPlacaToMercosul(input) {
|
|
58
|
+
const stripped = stripPlaca(input);
|
|
59
|
+
if (stripped.length === 0) {
|
|
60
|
+
return failure("EMPTY_INPUT", "Placa input is empty");
|
|
61
|
+
}
|
|
62
|
+
if (detectPlacaFormat(input) !== "legacy") {
|
|
63
|
+
return failure("UNSUPPORTED_FORMAT", "Conversion requires a valid legacy plate (LLLNNNN)");
|
|
64
|
+
}
|
|
65
|
+
const prefix = stripped.slice(0, 4);
|
|
66
|
+
const mapped = PLACA_LEGACY_TO_MERCOSUL_MAP[stripped.charAt(4)];
|
|
67
|
+
const suffix = stripped.slice(5);
|
|
68
|
+
return { ok: true, formatted: `${prefix}${mapped}${suffix}` };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/core/placa/index.ts
|
|
72
|
+
function failure2(code, message) {
|
|
73
|
+
return { ok: false, code, message };
|
|
74
|
+
}
|
|
75
|
+
function validateStructure(input, stripped) {
|
|
76
|
+
if (stripped.length === 0) {
|
|
77
|
+
return failure2("EMPTY_INPUT", "Placa input is empty");
|
|
78
|
+
}
|
|
79
|
+
const withoutSeparators = input.replace(/[-\s]/g, "");
|
|
80
|
+
if (/[^A-Za-z0-9]/.test(withoutSeparators)) {
|
|
81
|
+
return failure2("INVALID_CHARACTER", "Placa contains invalid characters");
|
|
82
|
+
}
|
|
83
|
+
if (stripped.length !== PLACA_LENGTH) {
|
|
84
|
+
return failure2("INVALID_LENGTH", `Placa must have ${PLACA_LENGTH} characters after normalization`);
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
function isValidPlaca(input) {
|
|
89
|
+
return validatePlaca(input).ok;
|
|
90
|
+
}
|
|
91
|
+
function validatePlaca(input) {
|
|
92
|
+
const stripped = stripPlaca(input);
|
|
93
|
+
const structural = validateStructure(input, stripped);
|
|
94
|
+
if (structural) {
|
|
95
|
+
return structural;
|
|
96
|
+
}
|
|
97
|
+
const format = detectPlacaFormat(input);
|
|
98
|
+
if (format === "unknown") {
|
|
99
|
+
return failure2("UNSUPPORTED_FORMAT", "Placa does not match legacy or Mercosul format");
|
|
100
|
+
}
|
|
101
|
+
return { ok: true, value: brandPlaca(stripped), format };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/format/placa.ts
|
|
105
|
+
function formatPlaca(input) {
|
|
106
|
+
const result = validatePlaca(input);
|
|
107
|
+
if (!result.ok) {
|
|
108
|
+
return { ok: false, code: result.code, message: result.message };
|
|
109
|
+
}
|
|
110
|
+
return { ok: true, formatted: result.value };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export { PLACA_GOLDEN_CONVERSION_FROM, PLACA_GOLDEN_CONVERSION_TO, PLACA_GOLDEN_LEGACY, PLACA_GOLDEN_MERCOSUL, PLACA_OFFICIAL_SOURCE_URL, convertPlacaToMercosul, detectPlacaFormat, formatPlaca, isValidPlaca, isValidPlacaLegacy, isValidPlacaMercosul, validatePlaca };
|
|
114
|
+
//# sourceMappingURL=chunk-YY4M2YS6.js.map
|
|
115
|
+
//# sourceMappingURL=chunk-YY4M2YS6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/placa/constants.ts","../src/core/placa/detect.ts","../src/core/placa/legacy.ts","../src/core/placa/mercosul.ts","../src/core/placa/convert.ts","../src/core/placa/index.ts","../src/format/placa.ts"],"names":["failure"],"mappings":";;;;AAKO,IAAM,YAAA,GAAe,CAAA;AACrB,IAAM,oBAAA,GAAuB,oBAAA;AAC7B,IAAM,sBAAA,GAAyB,iCAAA;AAC/B,IAAM,4BAAA,GAAuD;AAAA,EAClE,GAAA,EAAK,GAAA;AAAA,EACL,GAAA,EAAK,GAAA;AAAA,EACL,GAAA,EAAK,GAAA;AAAA,EACL,GAAA,EAAK,GAAA;AAAA,EACL,GAAA,EAAK,GAAA;AAAA,EACL,GAAA,EAAK,GAAA;AAAA,EACL,GAAA,EAAK,GAAA;AAAA,EACL,GAAA,EAAK,GAAA;AAAA,EACL,GAAA,EAAK,GAAA;AAAA,EACL,GAAA,EAAK;AACP,CAAA;AACO,IAAM,qBAAA,GAAwB;AAC9B,IAAM,mBAAA,GAAsB;AAC5B,IAAM,4BAAA,GAA+B;AACrC,IAAM,0BAAA,GAA6B;AACnC,IAAM,yBAAA,GACX;;;AChBK,SAAS,kBAAkB,KAAA,EAA4B;AAC5D,EAAA,MAAM,QAAA,GAAW,WAAW,KAAK,CAAA;AACjC,EAAA,IAAI,QAAA,CAAS,WAAW,YAAA,EAAc;AACpC,IAAA,OAAO,SAAA;AAAA,EACT;AACA,EAAA,IAAI,oBAAA,CAAqB,IAAA,CAAK,QAAQ,CAAA,EAAG;AACvC,IAAA,OAAO,QAAA;AAAA,EACT;AACA,EAAA,IAAI,sBAAA,CAAuB,IAAA,CAAK,QAAQ,CAAA,EAAG;AACzC,IAAA,OAAO,UAAA;AAAA,EACT;AACA,EAAA,OAAO,SAAA;AACT;;;ACdO,SAAS,mBAAmB,KAAA,EAAwB;AACzD,EAAA,MAAM,QAAA,GAAW,WAAW,KAAK,CAAA;AACjC,EAAA,OAAO,oBAAA,CAAqB,KAAK,QAAQ,CAAA;AAC3C;;;ACHO,SAAS,qBAAqB,KAAA,EAAwB;AAC3D,EAAA,MAAM,QAAA,GAAW,WAAW,KAAK,CAAA;AACjC,EAAA,OAAO,sBAAA,CAAuB,KAAK,QAAQ,CAAA;AAC7C;;;ACCA,SAAS,OAAA,CAAQ,MAA4B,OAAA,EAA+B;AAC1E,EAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,IAAA,EAAM,OAAA,EAAQ;AACpC;AAEO,SAAS,uBAAuB,KAAA,EAA6B;AAClE,EAAA,MAAM,QAAA,GAAW,WAAW,KAAK,CAAA;AACjC,EAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AACzB,IAAA,OAAO,OAAA,CAAQ,eAAe,sBAAsB,CAAA;AAAA,EACtD;AAEA,EAAA,IAAI,iBAAA,CAAkB,KAAK,CAAA,KAAM,QAAA,EAAU;AACzC,IAAA,OAAO,OAAA,CAAQ,sBAAsB,oDAAoD,CAAA;AAAA,EAC3F;AAEA,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA;AAClC,EAAA,MAAM,MAAA,GAAS,4BAAA,CAA6B,QAAA,CAAS,MAAA,CAAO,CAAC,CAAC,CAAA;AAC9D,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,KAAA,CAAM,CAAC,CAAA;AAC/B,EAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,SAAA,EAAW,CAAA,EAAG,MAAM,CAAA,EAAG,MAAM,CAAA,EAAG,MAAM,CAAA,CAAA,EAAG;AAC9D;;;ACJA,SAASA,QAAAA,CAAQ,MAA4B,OAAA,EAA+B;AAC1E,EAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,IAAA,EAAM,OAAA,EAAQ;AACpC;AAEA,SAAS,iBAAA,CAAkB,OAAe,QAAA,EAAuC;AAC/E,EAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AACzB,IAAA,OAAOA,QAAAA,CAAQ,eAAe,sBAAsB,CAAA;AAAA,EACtD;AAEA,EAAA,MAAM,iBAAA,GAAoB,KAAA,CAAM,OAAA,CAAQ,QAAA,EAAU,EAAE,CAAA;AACpD,EAAA,IAAI,cAAA,CAAe,IAAA,CAAK,iBAAiB,CAAA,EAAG;AAC1C,IAAA,OAAOA,QAAAA,CAAQ,qBAAqB,mCAAmC,CAAA;AAAA,EACzE;AAEA,EAAA,IAAI,QAAA,CAAS,WAAW,YAAA,EAAc;AACpC,IAAA,OAAOA,QAAAA,CAAQ,gBAAA,EAAkB,CAAA,gBAAA,EAAmB,YAAY,CAAA,+BAAA,CAAiC,CAAA;AAAA,EACnG;AAEA,EAAA,OAAO,IAAA;AACT;AAEO,SAAS,aAAa,KAAA,EAAwB;AACnD,EAAA,OAAO,aAAA,CAAc,KAAK,CAAA,CAAE,EAAA;AAC9B;AAEO,SAAS,cAAc,KAAA,EAAwC;AACpE,EAAA,MAAM,QAAA,GAAW,WAAW,KAAK,CAAA;AACjC,EAAA,MAAM,UAAA,GAAa,iBAAA,CAAkB,KAAA,EAAO,QAAQ,CAAA;AACpD,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,OAAO,UAAA;AAAA,EACT;AAEA,EAAA,MAAM,MAAA,GAAS,kBAAkB,KAAK,CAAA;AACtC,EAAA,IAAI,WAAW,SAAA,EAAW;AACxB,IAAA,OAAOA,QAAAA,CAAQ,sBAAsB,gDAAgD,CAAA;AAAA,EACvF;AAEA,EAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,OAAO,UAAA,CAAW,QAAQ,GAAG,MAAA,EAAiC;AACnF;;;AC5DO,SAAS,YAAY,KAAA,EAA6B;AACvD,EAAA,MAAM,MAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,IAAI,CAAC,OAAO,EAAA,EAAI;AACd,IAAA,OAAO,EAAE,IAAI,KAAA,EAAO,IAAA,EAAM,OAAO,IAAA,EAAM,OAAA,EAAS,OAAO,OAAA,EAAQ;AAAA,EACjE;AACA,EAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,SAAA,EAAW,OAAO,KAAA,EAAM;AAC7C","file":"chunk-YY4M2YS6.js","sourcesContent":["/**\n * License plate patterns — CONTRAN 729/2018 (legacy + Mercosul).\n * @see https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao7292018consolidada.pdf\n * @see docs/use-cases/UC-004-validate-placa.md — golden vectors ABC1D23, ABC1234\n */\nexport const PLACA_LENGTH = 7;\nexport const PLACA_LEGACY_PATTERN = /^[A-Z]{3}[0-9]{4}$/;\nexport const PLACA_MERCOSUL_PATTERN = /^[A-Z]{3}[0-9][A-Z0-9][0-9]{2}$/;\nexport const PLACA_LEGACY_TO_MERCOSUL_MAP: Record<string, string> = {\n '0': 'A',\n '1': 'B',\n '2': 'C',\n '3': 'D',\n '4': 'E',\n '5': 'F',\n '6': 'G',\n '7': 'H',\n '8': 'I',\n '9': 'J',\n};\nexport const PLACA_GOLDEN_MERCOSUL = 'ABC1D23';\nexport const PLACA_GOLDEN_LEGACY = 'ABC1234';\nexport const PLACA_GOLDEN_CONVERSION_FROM = 'ABC1234';\nexport const PLACA_GOLDEN_CONVERSION_TO = 'ABC1C34';\nexport const PLACA_OFFICIAL_SOURCE_URL =\n 'https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao7292018consolidada.pdf';\n","/**\n * License plate format detection — legacy vs Mercosul (CONTRAN).\n * @see https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao7292018consolidada.pdf\n */\nimport { stripPlaca } from '../../strip/index.js';\nimport { PLACA_LENGTH, PLACA_LEGACY_PATTERN, PLACA_MERCOSUL_PATTERN } from './constants.js';\n\nexport type PlacaFormat = 'legacy' | 'mercosul' | 'unknown';\n\nexport function detectPlacaFormat(input: string): PlacaFormat {\n const stripped = stripPlaca(input);\n if (stripped.length !== PLACA_LENGTH) {\n return 'unknown';\n }\n if (PLACA_LEGACY_PATTERN.test(stripped)) {\n return 'legacy';\n }\n if (PLACA_MERCOSUL_PATTERN.test(stripped)) {\n return 'mercosul';\n }\n return 'unknown';\n}\n","/**\n * License plate — legacy format LLLNNNN (CONTRAN).\n * @see https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao7292018consolidada.pdf\n */\nimport { stripPlaca } from '../../strip/index.js';\nimport { PLACA_LEGACY_PATTERN } from './constants.js';\n\nexport function isValidPlacaLegacy(input: string): boolean {\n const stripped = stripPlaca(input);\n return PLACA_LEGACY_PATTERN.test(stripped);\n}\n","/**\n * License plate — Mercosul format LLLNLNN (CONTRAN).\n * @see https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao7292018consolidada.pdf\n */\nimport { stripPlaca } from '../../strip/index.js';\nimport { PLACA_MERCOSUL_PATTERN } from './constants.js';\n\nexport function isValidPlacaMercosul(input: string): boolean {\n const stripped = stripPlaca(input);\n return PLACA_MERCOSUL_PATTERN.test(stripped);\n}\n","/**\n * Legacy → Mercosul plate conversion (CONTRAN digit-to-letter table).\n * @see https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao7292018consolidada.pdf\n */\nimport type { FormatResult } from '../../types/validation-result.js';\nimport { stripPlaca } from '../../strip/index.js';\nimport { PLACA_LEGACY_TO_MERCOSUL_MAP } from './constants.js';\nimport { detectPlacaFormat } from './detect.js';\n\ntype FailedResult = Extract<FormatResult, { ok: false }>;\n\nfunction failure(code: FailedResult['code'], message: string): FailedResult {\n return { ok: false, code, message };\n}\n\nexport function convertPlacaToMercosul(input: string): FormatResult {\n const stripped = stripPlaca(input);\n if (stripped.length === 0) {\n return failure('EMPTY_INPUT', 'Placa input is empty');\n }\n\n if (detectPlacaFormat(input) !== 'legacy') {\n return failure('UNSUPPORTED_FORMAT', 'Conversion requires a valid legacy plate (LLLNNNN)');\n }\n\n const prefix = stripped.slice(0, 4);\n const mapped = PLACA_LEGACY_TO_MERCOSUL_MAP[stripped.charAt(4)];\n const suffix = stripped.slice(5);\n return { ok: true, formatted: `${prefix}${mapped}${suffix}` };\n}\n","/**\n * License plate validation — legacy (LLLNNNN) + Mercosul (LLLNLNN). CONTRAN 729/2018.\n * @see https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao7292018consolidada.pdf\n * @see docs/use-cases/UC-004-validate-placa.md — golden vectors ABC1D23, ABC1234\n */\nimport { stripPlaca } from '../../strip/index.js';\nimport type { DocumentFormat, Placa, ValidationResult } from '../../types/validation-result.js';\nimport { brandPlaca } from '../../types/validation-result.js';\nimport { detectPlacaFormat } from './detect.js';\nimport { PLACA_LENGTH } from './constants.js';\n\nexport {\n PLACA_GOLDEN_CONVERSION_FROM,\n PLACA_GOLDEN_CONVERSION_TO,\n PLACA_GOLDEN_LEGACY,\n PLACA_GOLDEN_MERCOSUL,\n PLACA_OFFICIAL_SOURCE_URL,\n} from './constants.js';\nexport { detectPlacaFormat, type PlacaFormat } from './detect.js';\nexport { isValidPlacaLegacy } from './legacy.js';\nexport { isValidPlacaMercosul } from './mercosul.js';\nexport { convertPlacaToMercosul } from './convert.js';\n\ntype FailedResult = Extract<ValidationResult, { ok: false }>;\n\nfunction failure(code: FailedResult['code'], message: string): FailedResult {\n return { ok: false, code, message };\n}\n\nfunction validateStructure(input: string, stripped: string): FailedResult | null {\n if (stripped.length === 0) {\n return failure('EMPTY_INPUT', 'Placa input is empty');\n }\n\n const withoutSeparators = input.replace(/[-\\s]/g, '');\n if (/[^A-Za-z0-9]/.test(withoutSeparators)) {\n return failure('INVALID_CHARACTER', 'Placa contains invalid characters');\n }\n\n if (stripped.length !== PLACA_LENGTH) {\n return failure('INVALID_LENGTH', `Placa must have ${PLACA_LENGTH} characters after normalization`);\n }\n\n return null;\n}\n\nexport function isValidPlaca(input: string): boolean {\n return validatePlaca(input).ok;\n}\n\nexport function validatePlaca(input: string): ValidationResult<Placa> {\n const stripped = stripPlaca(input);\n const structural = validateStructure(input, stripped);\n if (structural) {\n return structural;\n }\n\n const format = detectPlacaFormat(input);\n if (format === 'unknown') {\n return failure('UNSUPPORTED_FORMAT', 'Placa does not match legacy or Mercosul format');\n }\n\n return { ok: true, value: brandPlaca(stripped), format: format as DocumentFormat };\n}\n","import { validatePlaca } from '../core/placa/index.js';\nimport type { FormatResult } from '../types/validation-result.js';\n\nexport function formatPlaca(input: string): FormatResult {\n const result = validatePlaca(input);\n if (!result.ok) {\n return { ok: false, code: result.code, message: result.message };\n }\n return { ok: true, formatted: result.value };\n}\n"]}
|