@br-validators/cli 1.8.3 → 1.10.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.
@@ -1,10 +1,3 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
6
- });
7
-
8
1
  // src/constants.ts
9
2
  var SUPPORTED_TYPES = ["cnpj", "cpf", "cep", "telefone", "cnh", "renavam", "titulo-eleitor", "processo-judicial", "rg", "nfe-chave", "brcode", "placa", "pis-pasep", "pix", "boleto", "cartao", "ie"];
10
3
  var EXIT = {
@@ -16,47 +9,56 @@ var EXIT = {
16
9
  // src/commands/reference-lookup/registry.ts
17
10
  import {
18
11
  CEST_DATA_VERSION,
19
- getCestPorCodigo
12
+ lookupCestPorCodigo
20
13
  } from "@br-validators/core/cest";
21
14
  import {
22
15
  INCOTERMS_DATA_VERSION,
23
- getIncotermPorCodigo
16
+ lookupIncotermPorCodigo
24
17
  } from "@br-validators/core/incoterms";
25
18
  import {
26
19
  MOEDAS_DATA_VERSION,
27
- getMoedaPorCodigo
20
+ lookupMoedaPorCodigo
28
21
  } from "@br-validators/core/moedas";
29
22
  import {
30
23
  NATUREZA_JURIDICA_DATA_VERSION,
31
- getNaturezaJuridicaPorCodigo
24
+ lookupNaturezaJuridicaPorCodigo
32
25
  } from "@br-validators/core/natureza-juridica";
33
- import { NBS_DATA_VERSION, getNbsPorCodigo } from "@br-validators/core/nbs";
26
+ import { NBS_DATA_VERSION, lookupNbsPorCodigo } from "@br-validators/core/nbs";
34
27
  import {
35
28
  PAISES_BACEN_DATA_VERSION,
36
- getPaisPorCodigoBacen
29
+ lookupPaisPorCodigoBacen
37
30
  } from "@br-validators/core/paises-bacen";
38
31
  import {
39
32
  AEROPORTOS_DATA_VERSION,
40
- getAeroportoPorIata,
41
- getAeroportoPorIcao
33
+ lookupAeroportoPorIata,
34
+ lookupAeroportoPorIcao
42
35
  } from "@br-validators/core/aeroportos";
43
- import { PORTOS_DATA_VERSION, getPortoPorCodigo } from "@br-validators/core/portos";
36
+ import { PORTOS_DATA_VERSION, lookupPortoPorCodigo } from "@br-validators/core/portos";
44
37
  import {
45
38
  CNAES_DATA_VERSION,
46
- getCnaePorCodigo
39
+ lookupCnaePorCodigo
47
40
  } from "@br-validators/core/cnaes";
48
41
  import {
49
42
  CFOP_DATA_VERSION,
50
- getCfopPorCodigo
43
+ lookupCfopPorCodigo
51
44
  } from "@br-validators/core/cfop";
52
- import { NCM_DATA_VERSION, getNcmPorCodigo } from "@br-validators/core/ncm";
53
- import { CBO_DATA_VERSION, getCboPorCodigo } from "@br-validators/core/cbo";
45
+ import {
46
+ CSOSN_DATA_VERSION,
47
+ lookupCsosnPorCodigo
48
+ } from "@br-validators/core/csosn";
49
+ import { NCM_DATA_VERSION, lookupNcmPorCodigo } from "@br-validators/core/ncm";
50
+ import { CBO_DATA_VERSION, lookupCboPorCodigo } from "@br-validators/core/cbo";
51
+ import {
52
+ lookupInvalidFormat,
53
+ lookupInvalidInput
54
+ } from "@br-validators/core/lookup";
54
55
  var REFERENCE_LOOKUP_COMMANDS = [
55
56
  "natureza-juridica",
56
57
  "nbs",
57
58
  "cest",
58
59
  "cnae",
59
60
  "cfop",
61
+ "csosn",
60
62
  "ncm",
61
63
  "cbo",
62
64
  "moedas",
@@ -65,16 +67,19 @@ var REFERENCE_LOOKUP_COMMANDS = [
65
67
  "portos",
66
68
  "aeroportos"
67
69
  ];
68
- var REFERENCE_SEARCH_COMMANDS = ["cnae", "cfop", "ncm", "cbo"];
70
+ var REFERENCE_SEARCH_COMMANDS = ["cnae", "cfop", "csosn", "ncm", "cbo"];
69
71
  function lookupAeroporto(input) {
70
72
  const normalized = input.trim().toUpperCase();
73
+ if (normalized.length === 0) {
74
+ return lookupInvalidInput("Airport code is required");
75
+ }
71
76
  if (/^[A-Z0-9]{3}$/.test(normalized)) {
72
- return getAeroportoPorIata(normalized);
77
+ return lookupAeroportoPorIata(normalized);
73
78
  }
74
79
  if (/^[A-Z]{4}$/.test(normalized)) {
75
- return getAeroportoPorIcao(normalized);
80
+ return lookupAeroportoPorIcao(normalized);
76
81
  }
77
- return void 0;
82
+ return lookupInvalidFormat("Airport code must be 3-character IATA or 4-character ICAO");
78
83
  }
79
84
  var REFERENCE_LOOKUP_MODULES = {
80
85
  "natureza-juridica": {
@@ -82,7 +87,7 @@ var REFERENCE_LOOKUP_MODULES = {
82
87
  description: "RFB legal nature codes \u2014 offline lookup",
83
88
  resultKey: "naturezaJuridica",
84
89
  capturadoEm: NATUREZA_JURIDICA_DATA_VERSION.capturadoEm,
85
- lookup: (input) => getNaturezaJuridicaPorCodigo(input),
90
+ lookup: (input) => lookupNaturezaJuridicaPorCodigo(input),
86
91
  formatHuman: (result) => {
87
92
  const row = result;
88
93
  return `${row.codigo} \u2014 ${row.descricao}`;
@@ -93,7 +98,7 @@ var REFERENCE_LOOKUP_MODULES = {
93
98
  description: "NFSe NBS service codes \u2014 offline lookup",
94
99
  resultKey: "nbs",
95
100
  capturadoEm: NBS_DATA_VERSION.capturadoEm,
96
- lookup: (input) => getNbsPorCodigo(input),
101
+ lookup: (input) => lookupNbsPorCodigo(input),
97
102
  formatHuman: (result) => {
98
103
  const row = result;
99
104
  return `${row.codigo} \u2014 ${row.descricao}`;
@@ -104,7 +109,7 @@ var REFERENCE_LOOKUP_MODULES = {
104
109
  description: "CONFAZ CEST ST codes \u2014 offline lookup",
105
110
  resultKey: "cest",
106
111
  capturadoEm: CEST_DATA_VERSION.capturadoEm,
107
- lookup: (input) => getCestPorCodigo(input),
112
+ lookup: (input) => lookupCestPorCodigo(input),
108
113
  formatHuman: (result) => {
109
114
  const row = result;
110
115
  return `${row.codigo} \u2014 ${row.descricao}`;
@@ -115,7 +120,7 @@ var REFERENCE_LOOKUP_MODULES = {
115
120
  description: "IBGE CNAE 2.3 subclasses \u2014 offline lookup",
116
121
  resultKey: "cnae",
117
122
  capturadoEm: CNAES_DATA_VERSION.capturadoEm,
118
- lookup: (input) => getCnaePorCodigo(input),
123
+ lookup: (input) => lookupCnaePorCodigo(input),
119
124
  formatHuman: (result) => {
120
125
  const row = result;
121
126
  return `${row.codigo} \u2014 ${row.descricao}`;
@@ -126,7 +131,18 @@ var REFERENCE_LOOKUP_MODULES = {
126
131
  description: "CONFAZ CFOP fiscal operations \u2014 offline lookup",
127
132
  resultKey: "cfop",
128
133
  capturadoEm: CFOP_DATA_VERSION.capturadoEm,
129
- lookup: (input) => getCfopPorCodigo(input),
134
+ lookup: (input) => lookupCfopPorCodigo(input),
135
+ formatHuman: (result) => {
136
+ const row = result;
137
+ return `${row.codigo} \u2014 ${row.descricao}`;
138
+ }
139
+ },
140
+ csosn: {
141
+ command: "csosn",
142
+ description: "CONFAZ CSOSN Simples Nacional \u2014 offline lookup",
143
+ resultKey: "csosn",
144
+ capturadoEm: CSOSN_DATA_VERSION.capturadoEm,
145
+ lookup: (input) => lookupCsosnPorCodigo(input),
130
146
  formatHuman: (result) => {
131
147
  const row = result;
132
148
  return `${row.codigo} \u2014 ${row.descricao}`;
@@ -137,7 +153,7 @@ var REFERENCE_LOOKUP_MODULES = {
137
153
  description: "Siscomex NCM Mercosur codes \u2014 offline lookup",
138
154
  resultKey: "ncm",
139
155
  capturadoEm: NCM_DATA_VERSION.capturadoEm,
140
- lookup: (input) => getNcmPorCodigo(input),
156
+ lookup: (input) => lookupNcmPorCodigo(input),
141
157
  formatHuman: (result) => {
142
158
  const row = result;
143
159
  return `${row.codigo} \u2014 ${row.descricao}`;
@@ -148,7 +164,7 @@ var REFERENCE_LOOKUP_MODULES = {
148
164
  description: "MTE CBO 2002 occupations \u2014 offline lookup",
149
165
  resultKey: "cbo",
150
166
  capturadoEm: CBO_DATA_VERSION.capturadoEm,
151
- lookup: (input) => getCboPorCodigo(input),
167
+ lookup: (input) => lookupCboPorCodigo(input),
152
168
  formatHuman: (result) => {
153
169
  const row = result;
154
170
  return `${row.codigo} \u2014 ${row.descricao}`;
@@ -159,7 +175,7 @@ var REFERENCE_LOOKUP_MODULES = {
159
175
  description: "ISO 4217 + Bacen PTAX currencies \u2014 offline lookup",
160
176
  resultKey: "moeda",
161
177
  capturadoEm: MOEDAS_DATA_VERSION.capturadoEm,
162
- lookup: (input) => getMoedaPorCodigo(input),
178
+ lookup: (input) => lookupMoedaPorCodigo(input),
163
179
  formatHuman: (result) => {
164
180
  const row = result;
165
181
  const symbol = row.simbolo ?? "\u2014";
@@ -171,7 +187,7 @@ var REFERENCE_LOOKUP_MODULES = {
171
187
  description: "NF-e Bacen country codes \u2014 offline lookup",
172
188
  resultKey: "pais",
173
189
  capturadoEm: PAISES_BACEN_DATA_VERSION.capturadoEm,
174
- lookup: (input) => getPaisPorCodigoBacen(input),
190
+ lookup: (input) => lookupPaisPorCodigoBacen(input),
175
191
  formatHuman: (result) => {
176
192
  const row = result;
177
193
  return `${row.codigo} \u2014 ${row.nome}`;
@@ -182,7 +198,7 @@ var REFERENCE_LOOKUP_MODULES = {
182
198
  description: "ICC Incoterms 2020 \u2014 offline lookup",
183
199
  resultKey: "incoterm",
184
200
  capturadoEm: INCOTERMS_DATA_VERSION.capturadoEm,
185
- lookup: (input) => getIncotermPorCodigo(input),
201
+ lookup: (input) => lookupIncotermPorCodigo(input),
186
202
  formatHuman: (result) => {
187
203
  const row = result;
188
204
  return `${row.codigo} \u2014 ${row.nome} (${row.edicao})`;
@@ -193,7 +209,7 @@ var REFERENCE_LOOKUP_MODULES = {
193
209
  description: "ANTAQ port installations \u2014 offline lookup",
194
210
  resultKey: "porto",
195
211
  capturadoEm: PORTOS_DATA_VERSION.capturadoEm,
196
- lookup: (input) => getPortoPorCodigo(input),
212
+ lookup: (input) => lookupPortoPorCodigo(input),
197
213
  formatHuman: (result) => {
198
214
  const row = result;
199
215
  return `${row.codigo} \u2014 ${row.nome} (${row.uf})`;
@@ -219,15 +235,85 @@ function isReferenceSearchCommand(value) {
219
235
  return REFERENCE_SEARCH_COMMANDS.includes(value);
220
236
  }
221
237
 
238
+ // src/commands/reference-lookup/validate.ts
239
+ import { validateCfop } from "@br-validators/core/cfop";
240
+ import { validateCsosn } from "@br-validators/core/csosn";
241
+ import { validateNcm } from "@br-validators/core/ncm";
242
+ var REFERENCE_VALIDATE_COMMANDS = ["ncm", "cfop", "csosn"];
243
+ var VALIDATORS = {
244
+ ncm: validateNcm,
245
+ cfop: validateCfop,
246
+ csosn: validateCsosn
247
+ };
248
+ var CAPTURED_AT = {
249
+ ncm: "ncm",
250
+ cfop: "cfop",
251
+ csosn: "csosn"
252
+ };
253
+ function emitFailure(result, options, io) {
254
+ if (options.json) {
255
+ io.stdout.push(JSON.stringify({ ok: false, code: result.code, message: result.message }, null, 2));
256
+ return;
257
+ }
258
+ io.stderr.push(result.message);
259
+ }
260
+ function isReferenceValidateCommand(command) {
261
+ return REFERENCE_VALIDATE_COMMANDS.includes(command);
262
+ }
263
+ function runReferenceValidateCommand(command, input, options, io = { stdout: [], stderr: [] }) {
264
+ const trimmed = input.trim();
265
+ if (trimmed.length === 0) {
266
+ io.stderr.push(`Missing code. Pass a value to validate for ${command}.`);
267
+ return EXIT.USAGE;
268
+ }
269
+ const result = VALIDATORS[command](trimmed);
270
+ if (!result.ok) {
271
+ emitFailure(result, options, io);
272
+ return EXIT.INVALID;
273
+ }
274
+ if (options.json) {
275
+ const payload = {
276
+ ok: true,
277
+ value: result.value,
278
+ description: result.description,
279
+ ...result.format !== void 0 ? { format: result.format } : {},
280
+ ...options.verbose ? { module: CAPTURED_AT[command] } : {}
281
+ };
282
+ io.stdout.push(JSON.stringify(payload, null, 2));
283
+ return EXIT.OK;
284
+ }
285
+ const lines = [`${result.value} \u2014 ${result.description}`];
286
+ if (result.format !== void 0) {
287
+ lines.push(`format: ${result.format}`);
288
+ }
289
+ io.stdout.push(lines.join("\n"));
290
+ return EXIT.OK;
291
+ }
292
+ function runReferenceValidate(command, value, options, io = { stdout: [], stderr: [] }) {
293
+ if (!isReferenceValidateCommand(command)) {
294
+ io.stderr.push(`Unknown reference validate command: ${command}`);
295
+ return EXIT.USAGE;
296
+ }
297
+ if (!value?.trim()) {
298
+ io.stderr.push(`Missing code. Usage: br-validators ${command} validate <codigo>`);
299
+ return EXIT.USAGE;
300
+ }
301
+ return runReferenceValidateCommand(command, value.trim(), options, io);
302
+ }
303
+
304
+ // src/handlers.ts
305
+ import { createRequire } from "module";
306
+
222
307
  // src/commands/bancos/list.ts
223
- import { BANCOS_DATA_VERSION as BANCOS_DATA_VERSION2, getBancos } from "@br-validators/core/bancos";
308
+ import { BANCOS_DATA_VERSION as BANCOS_DATA_VERSION2, getAllBancos } from "@br-validators/core/bancos";
224
309
 
225
310
  // src/commands/bancos/lookup.ts
226
311
  import {
227
312
  BANCOS_DATA_VERSION,
228
- getBancoPorCodigo,
229
- getBancoPorIspb
313
+ lookupBancoPorCodigo,
314
+ lookupBancoPorIspb
230
315
  } from "@br-validators/core/bancos";
316
+ import { lookupInvalidFormat as lookupInvalidFormat2 } from "@br-validators/core/lookup";
231
317
  function normalizeBancosLookupInput(raw) {
232
318
  const digits = raw.replace(/\D/g, "");
233
319
  if (digits.length === 8) {
@@ -241,33 +327,36 @@ function normalizeBancosLookupInput(raw) {
241
327
  function lookupBanco(raw) {
242
328
  const normalized = normalizeBancosLookupInput(raw);
243
329
  if (!normalized) {
244
- return void 0;
330
+ return lookupInvalidFormat2(
331
+ "Invalid bank code or ISPB. Use 3-digit COMPE (e.g. 001) or 8-digit ISPB."
332
+ );
245
333
  }
246
- return normalized.kind === "ispb" ? getBancoPorIspb(normalized.value) : getBancoPorCodigo(normalized.value);
334
+ return normalized.kind === "ispb" ? lookupBancoPorIspb(normalized.value) : lookupBancoPorCodigo(normalized.value);
247
335
  }
248
336
  function formatBancoHuman(banco) {
249
337
  return `${banco.codigo} \u2014 ${banco.nome} (ISPB ${banco.ispb})`;
250
338
  }
251
339
  function runBancosLookupCommand(input, options, io = { stdout: [], stderr: [] }) {
252
- const normalized = normalizeBancosLookupInput(input);
253
- if (!normalized) {
254
- io.stderr.push("Invalid bank code or ISPB. Use 3-digit COMPE (e.g. 001) or 8-digit ISPB.");
255
- return EXIT.USAGE;
256
- }
257
- const banco = lookupBanco(input);
258
- if (!banco) {
259
- io.stderr.push(`Bank not found: ${input}`);
260
- return EXIT.INVALID;
340
+ const result = lookupBanco(input);
341
+ if (!result.ok) {
342
+ if (options.json) {
343
+ io.stdout.push(
344
+ JSON.stringify({ ok: false, code: result.code, message: result.message }, null, 2)
345
+ );
346
+ } else {
347
+ io.stderr.push(result.message);
348
+ }
349
+ return normalizeBancosLookupInput(input) === null ? EXIT.USAGE : EXIT.INVALID;
261
350
  }
262
351
  if (options.json) {
263
- const payload = { ok: true, banco };
352
+ const payload = { ok: true, banco: result.value };
264
353
  if (options.verbose) {
265
354
  payload.capturadoEm = BANCOS_DATA_VERSION.capturadoEm;
266
355
  }
267
356
  io.stdout.push(JSON.stringify(payload, null, 2));
268
357
  return EXIT.OK;
269
358
  }
270
- io.stdout.push(formatBancoHuman(banco));
359
+ io.stdout.push(formatBancoHuman(result.value));
271
360
  if (options.verbose) {
272
361
  io.stdout.push(`capturadoEm: ${BANCOS_DATA_VERSION.capturadoEm}`);
273
362
  }
@@ -283,7 +372,7 @@ function runBancosLookup(value, options, io = { stdout: [], stderr: [] }) {
283
372
 
284
373
  // src/commands/bancos/list.ts
285
374
  function sliceBancos(limit) {
286
- const all = getBancos();
375
+ const all = getAllBancos();
287
376
  if (limit === void 0 || !Number.isFinite(limit) || limit <= 0) {
288
377
  return all;
289
378
  }
@@ -316,6 +405,15 @@ function runBancosList(options, io = { stdout: [], stderr: [] }) {
316
405
  }
317
406
 
318
407
  // src/commands/reference-lookup/lookup.ts
408
+ function emitLookupFailure(result, options, io) {
409
+ if (options.json) {
410
+ io.stdout.push(
411
+ JSON.stringify({ ok: false, code: result.code, message: result.message }, null, 2)
412
+ );
413
+ return;
414
+ }
415
+ io.stderr.push(result.message);
416
+ }
319
417
  function runReferenceLookupCommand(command, input, options, io = { stdout: [], stderr: [] }) {
320
418
  const module = REFERENCE_LOOKUP_MODULES[command];
321
419
  const trimmed = input.trim();
@@ -324,20 +422,20 @@ function runReferenceLookupCommand(command, input, options, io = { stdout: [], s
324
422
  return EXIT.USAGE;
325
423
  }
326
424
  const result = module.lookup(trimmed);
327
- if (!result) {
328
- io.stderr.push(`Not found: ${trimmed}`);
425
+ if (!result.ok) {
426
+ emitLookupFailure(result, options, io);
329
427
  return EXIT.INVALID;
330
428
  }
331
429
  if (options.json) {
332
430
  const payload = {
333
431
  ok: true,
334
- [module.resultKey]: result,
432
+ [module.resultKey]: result.value,
335
433
  ...options.verbose ? { capturadoEm: module.capturadoEm } : {}
336
434
  };
337
435
  io.stdout.push(JSON.stringify(payload, null, 2));
338
436
  return EXIT.OK;
339
437
  }
340
- io.stdout.push(module.formatHuman(result));
438
+ io.stdout.push(module.formatHuman(result.value));
341
439
  if (options.verbose) {
342
440
  io.stdout.push(`capturadoEm: ${module.capturadoEm}`);
343
441
  }
@@ -359,6 +457,7 @@ function runReferenceLookup(command, value, options, io = { stdout: [], stderr:
359
457
  import { searchCbo } from "@br-validators/core/cbo";
360
458
  import { searchCnaes } from "@br-validators/core/cnaes";
361
459
  import { searchCfop } from "@br-validators/core/cfop";
460
+ import { searchCsosn } from "@br-validators/core/csosn";
362
461
  import { searchNcm } from "@br-validators/core/ncm";
363
462
  function runSearch(command, query, limit) {
364
463
  switch (command) {
@@ -366,6 +465,8 @@ function runSearch(command, query, limit) {
366
465
  return searchCnaes(query, { limit });
367
466
  case "cfop":
368
467
  return searchCfop(query, { limit });
468
+ case "csosn":
469
+ return searchCsosn(query, { limit });
369
470
  case "ncm":
370
471
  return searchNcm(query, { limit });
371
472
  case "cbo":
@@ -421,11 +522,176 @@ function runReferenceSearch(command, query, options, io = { stdout: [], stderr:
421
522
  return runReferenceSearchCommand(command, query.trim(), options, io);
422
523
  }
423
524
 
525
+ // src/commands/cst/index.ts
526
+ import {
527
+ CST_DATA_VERSION,
528
+ lookupCstCofinsPorCodigo,
529
+ lookupCstIcmsPorCodigo,
530
+ lookupCstIpiPorCodigo,
531
+ lookupCstPisPorCodigo,
532
+ searchCstCofins,
533
+ searchCstIcms,
534
+ searchCstIpi,
535
+ searchCstPis,
536
+ validateCst
537
+ } from "@br-validators/core/cst";
538
+ var CST_TAXES = ["icms", "ipi", "pis", "cofins"];
539
+ function parseCstTax(raw) {
540
+ if (raw === void 0) {
541
+ return null;
542
+ }
543
+ const normalized = raw.trim().toLowerCase();
544
+ if (CST_TAXES.includes(normalized)) {
545
+ return normalized;
546
+ }
547
+ return null;
548
+ }
549
+ function lookupByTax(tax, codigo) {
550
+ switch (tax) {
551
+ case "icms":
552
+ return lookupCstIcmsPorCodigo(codigo);
553
+ case "ipi":
554
+ return lookupCstIpiPorCodigo(codigo);
555
+ case "pis":
556
+ return lookupCstPisPorCodigo(codigo);
557
+ case "cofins":
558
+ return lookupCstCofinsPorCodigo(codigo);
559
+ }
560
+ }
561
+ function searchByTax(tax, query, limit) {
562
+ const options = limit !== void 0 ? { limit } : void 0;
563
+ switch (tax) {
564
+ case "icms":
565
+ return searchCstIcms(query, options);
566
+ case "ipi":
567
+ return searchCstIpi(query, options);
568
+ case "pis":
569
+ return searchCstPis(query, options);
570
+ case "cofins":
571
+ return searchCstCofins(query, options);
572
+ }
573
+ }
574
+ function emitLookupFailure2(result, options, io) {
575
+ if (options.json) {
576
+ io.stdout.push(JSON.stringify({ ok: false, code: result.code, message: result.message }, null, 2));
577
+ return;
578
+ }
579
+ io.stderr.push(result.message);
580
+ }
581
+ function emitValidateFailure(result, options, io) {
582
+ if (options.json) {
583
+ io.stdout.push(JSON.stringify({ ok: false, code: result.code, message: result.message }, null, 2));
584
+ return;
585
+ }
586
+ io.stderr.push(result.message);
587
+ }
588
+ function runCstLookup(codigo, options, io = { stdout: [], stderr: [] }) {
589
+ const tax = parseCstTax(options.tax);
590
+ if (tax === null) {
591
+ io.stderr.push("Missing or invalid --tax. Expected: icms | ipi | pis | cofins");
592
+ return EXIT.USAGE;
593
+ }
594
+ const trimmed = codigo?.trim() ?? "";
595
+ if (trimmed.length === 0) {
596
+ io.stderr.push("Missing code. Usage: br-validators cst lookup <codigo> --tax icms");
597
+ return EXIT.USAGE;
598
+ }
599
+ const result = lookupByTax(tax, trimmed);
600
+ if (!result.ok) {
601
+ emitLookupFailure2(result, options, io);
602
+ return EXIT.INVALID;
603
+ }
604
+ if (options.json) {
605
+ io.stdout.push(
606
+ JSON.stringify(
607
+ {
608
+ ok: true,
609
+ cst: result.value,
610
+ tax,
611
+ ...options.verbose ? { capturadoEm: CST_DATA_VERSION.capturadoEm } : {}
612
+ },
613
+ null,
614
+ 2
615
+ )
616
+ );
617
+ return EXIT.OK;
618
+ }
619
+ io.stdout.push(`${result.value.codigo} \u2014 ${result.value.descricao}`);
620
+ if (options.verbose) {
621
+ io.stdout.push(`tax: ${tax}`);
622
+ io.stdout.push(`capturadoEm: ${CST_DATA_VERSION.capturadoEm}`);
623
+ }
624
+ return EXIT.OK;
625
+ }
626
+ function runCstSearch(query, options, io = { stdout: [], stderr: [] }) {
627
+ const tax = parseCstTax(options.tax);
628
+ if (tax === null) {
629
+ io.stderr.push("Missing or invalid --tax. Expected: icms | ipi | pis | cofins");
630
+ return EXIT.USAGE;
631
+ }
632
+ const trimmed = query?.trim() ?? "";
633
+ if (trimmed.length === 0) {
634
+ io.stderr.push("Missing query. Usage: br-validators cst search <query> --tax icms");
635
+ return EXIT.USAGE;
636
+ }
637
+ const rows = searchByTax(tax, trimmed, options.limit);
638
+ if (options.json) {
639
+ io.stdout.push(JSON.stringify({ ok: true, tax, results: rows }, null, 2));
640
+ return EXIT.OK;
641
+ }
642
+ if (rows.length === 0) {
643
+ io.stdout.push("No matches.");
644
+ return EXIT.OK;
645
+ }
646
+ for (const row of rows) {
647
+ io.stdout.push(`${row.codigo} \u2014 ${row.descricao}`);
648
+ }
649
+ return EXIT.OK;
650
+ }
651
+ function runCstValidate(codigo, options, io = { stdout: [], stderr: [] }) {
652
+ const tax = parseCstTax(options.tax);
653
+ if (tax === null) {
654
+ io.stderr.push("Missing or invalid --tax. Expected: icms | ipi | pis | cofins");
655
+ return EXIT.USAGE;
656
+ }
657
+ const trimmed = codigo?.trim() ?? "";
658
+ if (trimmed.length === 0) {
659
+ io.stderr.push("Missing code. Usage: br-validators cst validate <codigo> --tax icms");
660
+ return EXIT.USAGE;
661
+ }
662
+ const result = validateCst(trimmed, { tax });
663
+ if (!result.ok) {
664
+ emitValidateFailure(result, options, io);
665
+ return EXIT.INVALID;
666
+ }
667
+ if (options.json) {
668
+ io.stdout.push(
669
+ JSON.stringify(
670
+ {
671
+ ok: true,
672
+ tax,
673
+ value: result.value,
674
+ description: result.description
675
+ },
676
+ null,
677
+ 2
678
+ )
679
+ );
680
+ return EXIT.OK;
681
+ }
682
+ io.stdout.push(`${result.value} \u2014 ${result.description}`);
683
+ if (options.verbose) {
684
+ io.stdout.push(`tax: ${tax}`);
685
+ }
686
+ return EXIT.OK;
687
+ }
688
+
424
689
  // src/commands/ibge/lookup.ts
425
690
  import {
426
- getMunicipioPorCodigo,
691
+ lookupMunicipioPorCodigo,
427
692
  IBGE_DATA_VERSION
428
693
  } from "@br-validators/core/ibge";
694
+ import { lookupInvalidFormat as lookupInvalidFormat3 } from "@br-validators/core/lookup";
429
695
  function normalizeIbgeMunicipioCode(raw) {
430
696
  const digits = raw.replace(/\D/g, "");
431
697
  if (digits.length !== 7) {
@@ -433,24 +699,35 @@ function normalizeIbgeMunicipioCode(raw) {
433
699
  }
434
700
  return Number(digits);
435
701
  }
702
+ function lookupMunicipio(raw) {
703
+ const codigo = normalizeIbgeMunicipioCode(raw);
704
+ if (codigo === null) {
705
+ return lookupInvalidFormat3("Invalid IBGE municipality code. Use 7 digits (e.g. 3550308).");
706
+ }
707
+ return lookupMunicipioPorCodigo(codigo);
708
+ }
436
709
  function formatMunicipioHuman(municipio) {
437
710
  return `${municipio.codigo} \u2014 ${municipio.nome} (${municipio.uf})`;
438
711
  }
439
- function runIbgeLookupCommand(input, options, io = { stdout: [], stderr: [] }) {
440
- const codigo = normalizeIbgeMunicipioCode(input);
441
- if (codigo === null) {
442
- io.stderr.push("Invalid IBGE municipality code. Use 7 digits (e.g. 3550308).");
443
- return EXIT.USAGE;
712
+ function emitLookupFailure3(result, options, io) {
713
+ if (options.json) {
714
+ io.stdout.push(
715
+ JSON.stringify({ ok: false, code: result.code, message: result.message }, null, 2)
716
+ );
717
+ return result.code === "INVALID_FORMAT" ? EXIT.USAGE : EXIT.INVALID;
444
718
  }
445
- const municipio = getMunicipioPorCodigo(codigo);
446
- if (!municipio) {
447
- io.stderr.push(`Municipality not found: ${input}`);
448
- return EXIT.INVALID;
719
+ io.stderr.push(result.message);
720
+ return result.code === "INVALID_FORMAT" ? EXIT.USAGE : EXIT.INVALID;
721
+ }
722
+ function runIbgeLookupCommand(input, options, io = { stdout: [], stderr: [] }) {
723
+ const result = lookupMunicipio(input);
724
+ if (!result.ok) {
725
+ return emitLookupFailure3(result, options, io);
449
726
  }
450
727
  if (options.json) {
451
728
  const payload = {
452
729
  ok: true,
453
- municipio
730
+ municipio: result.value
454
731
  };
455
732
  if (options.verbose) {
456
733
  payload.capturadoEm = IBGE_DATA_VERSION.capturadoEm;
@@ -458,7 +735,7 @@ function runIbgeLookupCommand(input, options, io = { stdout: [], stderr: [] }) {
458
735
  io.stdout.push(JSON.stringify(payload, null, 2));
459
736
  return EXIT.OK;
460
737
  }
461
- io.stdout.push(formatMunicipioHuman(municipio));
738
+ io.stdout.push(formatMunicipioHuman(result.value));
462
739
  if (options.verbose) {
463
740
  io.stdout.push(`capturadoEm: ${IBGE_DATA_VERSION.capturadoEm}`);
464
741
  }
@@ -474,8 +751,8 @@ function runIbgeLookup(value, options, io = { stdout: [], stderr: [] }) {
474
751
 
475
752
  // src/commands/ibge/list.ts
476
753
  import {
477
- getEstados,
478
- getMunicipios,
754
+ getAllEstados,
755
+ getAllMunicipios,
479
756
  IBGE_DATA_VERSION as IBGE_DATA_VERSION2
480
757
  } from "@br-validators/core/ibge";
481
758
  function sliceRows(rows, limit) {
@@ -488,7 +765,7 @@ function formatEstadoHuman(estado) {
488
765
  return `${estado.codigo} \u2014 ${estado.sigla} \u2014 ${estado.nome}`;
489
766
  }
490
767
  function runIbgeListEstadosCommand(options, io = { stdout: [], stderr: [] }) {
491
- const estados = sliceRows(getEstados(), options.limit);
768
+ const estados = sliceRows(getAllEstados(), options.limit);
492
769
  if (options.json) {
493
770
  const payload = {
494
771
  ok: true,
@@ -511,7 +788,7 @@ function runIbgeListEstadosCommand(options, io = { stdout: [], stderr: [] }) {
511
788
  }
512
789
  function runIbgeListMunicipiosCommand(options, io = { stdout: [], stderr: [] }) {
513
790
  const uf = options.uf?.trim().toUpperCase();
514
- const municipios = sliceRows(getMunicipios(uf ? { uf } : void 0), options.limit);
791
+ const municipios = sliceRows(getAllMunicipios(uf ? { uf } : void 0), options.limit);
515
792
  if (options.json) {
516
793
  const payload = {
517
794
  ok: true,
@@ -543,7 +820,7 @@ function runIbgeList(target, options, io = { stdout: [], stderr: [] }) {
543
820
  // src/commands/feriados/list.ts
544
821
  import {
545
822
  FERIADOS_DATA_VERSION,
546
- getFeriadosNacionais
823
+ getAllFeriados
547
824
  } from "@br-validators/core/feriados";
548
825
  function resolveYear(year) {
549
826
  if (year !== void 0 && Number.isInteger(year) && year >= 1900 && year <= 2100) {
@@ -556,7 +833,7 @@ function formatFeriadoHuman(feriado) {
556
833
  }
557
834
  function runFeriadosListCommand(options, io = { stdout: [], stderr: [] }) {
558
835
  const year = resolveYear(options.year);
559
- const feriados = getFeriadosNacionais(year);
836
+ const feriados = getAllFeriados(year);
560
837
  if (options.json) {
561
838
  const payload = {
562
839
  ok: true,
@@ -582,13 +859,193 @@ function runFeriadosList(options, io = { stdout: [], stderr: [] }) {
582
859
  return runFeriadosListCommand(options, io);
583
860
  }
584
861
 
862
+ // src/commands/inss/index.ts
863
+ import {
864
+ calcularInssMensal,
865
+ getInssTabelaContribuicao,
866
+ INSS_DATA_VERSION,
867
+ INSS_DEFAULT_ANO
868
+ } from "@br-validators/core/inss";
869
+ function resolveAno(ano) {
870
+ if (ano !== void 0 && Number.isInteger(ano) && ano >= 1900 && ano <= 2100) {
871
+ return ano;
872
+ }
873
+ return INSS_DEFAULT_ANO;
874
+ }
875
+ function formatInssFaixaHuman(faixa) {
876
+ const aliquotaPct = `${String(faixa.aliquota * 100).replace(".", ",")}%`;
877
+ return `Faixa ${String(faixa.faixa)} \u2014 ${faixa.descricao} \u2014 ${aliquotaPct}`;
878
+ }
879
+ function runInssTabelaCommand(options, io = { stdout: [], stderr: [] }) {
880
+ const ano = resolveAno(options.ano);
881
+ const tabela = getInssTabelaContribuicao(ano);
882
+ if (tabela === void 0) {
883
+ io.stderr.push(`INSS contribution table not found for year ${String(ano)}`);
884
+ return EXIT.INVALID;
885
+ }
886
+ if (options.json) {
887
+ const payload = {
888
+ ok: true,
889
+ ano,
890
+ teto: tabela.teto,
891
+ faixas: tabela.faixas
892
+ };
893
+ if (options.verbose) {
894
+ payload.capturadoEm = INSS_DATA_VERSION.capturadoEm;
895
+ }
896
+ io.stdout.push(JSON.stringify(payload, null, 2));
897
+ return EXIT.OK;
898
+ }
899
+ io.stdout.push(`Teto: R$ ${tabela.teto.toFixed(2)}`);
900
+ for (const faixa of tabela.faixas) {
901
+ io.stdout.push(formatInssFaixaHuman(faixa));
902
+ }
903
+ if (options.verbose) {
904
+ io.stdout.push(`capturadoEm: ${INSS_DATA_VERSION.capturadoEm}`);
905
+ }
906
+ return EXIT.OK;
907
+ }
908
+ function runInssCalcCommand(salarioRaw, options, io = { stdout: [], stderr: [] }) {
909
+ const trimmed = salarioRaw.trim().replace(",", ".");
910
+ const salarioContribuicao = Number(trimmed);
911
+ if (!Number.isFinite(salarioContribuicao)) {
912
+ io.stderr.push("Invalid sal\xE1rio de contribui\xE7\xE3o. Pass a numeric value (e.g. 3000).");
913
+ return EXIT.USAGE;
914
+ }
915
+ const ano = resolveAno(options.ano);
916
+ const result = calcularInssMensal(salarioContribuicao, ano);
917
+ if (result === void 0) {
918
+ if (getInssTabelaContribuicao(ano) === void 0) {
919
+ io.stderr.push(`INSS contribution table not found for year ${String(ano)}`);
920
+ return EXIT.INVALID;
921
+ }
922
+ io.stderr.push("Sal\xE1rio de contribui\xE7\xE3o must be a non-negative number");
923
+ return EXIT.INVALID;
924
+ }
925
+ if (options.json) {
926
+ const payload = {
927
+ ok: true,
928
+ ...result,
929
+ ...options.verbose ? { capturadoEm: INSS_DATA_VERSION.capturadoEm } : {}
930
+ };
931
+ io.stdout.push(JSON.stringify(payload, null, 2));
932
+ return EXIT.OK;
933
+ }
934
+ io.stdout.push(
935
+ `INSS ${String(result.ano)} \u2014 sal\xE1rio R$ ${result.salarioContribuicao.toFixed(2)} \u2014 faixa ${String(result.faixa)} \u2014 contribui\xE7\xE3o R$ ${result.contribuicao.toFixed(2)}`
936
+ );
937
+ if (options.verbose) {
938
+ io.stdout.push(`capturadoEm: ${INSS_DATA_VERSION.capturadoEm}`);
939
+ }
940
+ return EXIT.OK;
941
+ }
942
+ function runInssTabela(options, io = { stdout: [], stderr: [] }) {
943
+ return runInssTabelaCommand(options, io);
944
+ }
945
+ function runInssCalc(salario, options, io = { stdout: [], stderr: [] }) {
946
+ if (!salario?.trim()) {
947
+ io.stderr.push("Missing sal\xE1rio de contribui\xE7\xE3o. Usage: br-validators inss calc <salario>");
948
+ return EXIT.USAGE;
949
+ }
950
+ return runInssCalcCommand(salario.trim(), options, io);
951
+ }
952
+
953
+ // src/commands/irpf/index.ts
954
+ import {
955
+ calcularIrpfMensal,
956
+ getIrpfTabelaProgressiva,
957
+ IRPF_DATA_VERSION,
958
+ IRPF_DEFAULT_ANO
959
+ } from "@br-validators/core/irpf";
960
+ function resolveAno2(ano) {
961
+ if (ano !== void 0 && Number.isInteger(ano) && ano >= 1900 && ano <= 2100) {
962
+ return ano;
963
+ }
964
+ return IRPF_DEFAULT_ANO;
965
+ }
966
+ function formatIrpfFaixaHuman(faixa) {
967
+ const aliquotaPct = `${String(faixa.aliquota * 100).replace(".", ",")}%`;
968
+ return `Faixa ${String(faixa.faixa)} \u2014 ${faixa.descricao} \u2014 ${aliquotaPct} \u2014 deduzir R$ ${faixa.parcelaDeduzir.toFixed(2)}`;
969
+ }
970
+ function runIrpfTabelaCommand(options, io = { stdout: [], stderr: [] }) {
971
+ const ano = resolveAno2(options.ano);
972
+ const faixas = getIrpfTabelaProgressiva(ano);
973
+ if (faixas === void 0) {
974
+ io.stderr.push(`IRPF progressive table not found for year ${String(ano)}`);
975
+ return EXIT.INVALID;
976
+ }
977
+ if (options.json) {
978
+ const payload = {
979
+ ok: true,
980
+ ano,
981
+ faixas
982
+ };
983
+ if (options.verbose) {
984
+ payload.capturadoEm = IRPF_DATA_VERSION.capturadoEm;
985
+ }
986
+ io.stdout.push(JSON.stringify(payload, null, 2));
987
+ return EXIT.OK;
988
+ }
989
+ for (const faixa of faixas) {
990
+ io.stdout.push(formatIrpfFaixaHuman(faixa));
991
+ }
992
+ if (options.verbose) {
993
+ io.stdout.push(`capturadoEm: ${IRPF_DATA_VERSION.capturadoEm}`);
994
+ }
995
+ return EXIT.OK;
996
+ }
997
+ function runIrpfCalcCommand(baseRaw, options, io = { stdout: [], stderr: [] }) {
998
+ const trimmed = baseRaw.trim().replace(",", ".");
999
+ const baseCalculo = Number(trimmed);
1000
+ if (!Number.isFinite(baseCalculo)) {
1001
+ io.stderr.push("Invalid base de c\xE1lculo. Pass a numeric value (e.g. 3000).");
1002
+ return EXIT.USAGE;
1003
+ }
1004
+ const ano = resolveAno2(options.ano);
1005
+ const result = calcularIrpfMensal(baseCalculo, ano);
1006
+ if (result === void 0) {
1007
+ if (getIrpfTabelaProgressiva(ano) === void 0) {
1008
+ io.stderr.push(`IRPF progressive table not found for year ${String(ano)}`);
1009
+ return EXIT.INVALID;
1010
+ }
1011
+ io.stderr.push("Base de c\xE1lculo must be a non-negative number");
1012
+ return EXIT.INVALID;
1013
+ }
1014
+ if (options.json) {
1015
+ const payload = {
1016
+ ok: true,
1017
+ ...result,
1018
+ ...options.verbose ? { capturadoEm: IRPF_DATA_VERSION.capturadoEm } : {}
1019
+ };
1020
+ io.stdout.push(JSON.stringify(payload, null, 2));
1021
+ return EXIT.OK;
1022
+ }
1023
+ io.stdout.push(
1024
+ `IRPF ${String(result.ano)} \u2014 base R$ ${result.baseCalculo.toFixed(2)} \u2014 faixa ${String(result.faixa)} \u2014 imposto R$ ${result.imposto.toFixed(2)}`
1025
+ );
1026
+ if (options.verbose) {
1027
+ io.stdout.push(`capturadoEm: ${IRPF_DATA_VERSION.capturadoEm}`);
1028
+ }
1029
+ return EXIT.OK;
1030
+ }
1031
+ function runIrpfTabela(options, io = { stdout: [], stderr: [] }) {
1032
+ return runIrpfTabelaCommand(options, io);
1033
+ }
1034
+ function runIrpfCalc(base, options, io = { stdout: [], stderr: [] }) {
1035
+ if (!base?.trim()) {
1036
+ io.stderr.push("Missing base de c\xE1lculo. Usage: br-validators irpf calc <base>");
1037
+ return EXIT.USAGE;
1038
+ }
1039
+ return runIrpfCalcCommand(base.trim(), options, io);
1040
+ }
1041
+
585
1042
  // src/commands/tse-municipios/lookup.ts
586
1043
  import {
587
1044
  getCodigosTsePorMunicipio,
588
1045
  getMunicipioIbgePorCodigoTse,
589
1046
  TSE_MUNICIPIOS_DATA_VERSION
590
1047
  } from "@br-validators/core/tse-municipios";
591
- import { getMunicipioPorCodigo as getMunicipioPorCodigo2 } from "@br-validators/core/ibge";
1048
+ import { getMunicipioPorCodigo } from "@br-validators/core/ibge";
592
1049
  function normalizeTseInput(raw) {
593
1050
  const digits = raw.replace(/\D/g, "");
594
1051
  if (digits.length === 5) {
@@ -619,11 +1076,11 @@ function lookupTseMunicipio(raw) {
619
1076
  }
620
1077
  function formatTseLookupHuman(result) {
621
1078
  if (result.kind === "tse-to-ibge") {
622
- const municipio2 = getMunicipioPorCodigo2(result.ibgeCodigo);
1079
+ const municipio2 = getMunicipioPorCodigo(result.ibgeCodigo);
623
1080
  const name2 = municipio2 ? `${municipio2.nome} (${municipio2.uf})` : String(result.ibgeCodigo);
624
1081
  return `TSE ${result.codigoTse} \u2192 IBGE ${result.ibgeCodigo} \u2014 ${name2}`;
625
1082
  }
626
- const municipio = getMunicipioPorCodigo2(result.ibgeCodigo);
1083
+ const municipio = getMunicipioPorCodigo(result.ibgeCodigo);
627
1084
  const name = municipio ? `${municipio.nome} (${municipio.uf})` : String(result.ibgeCodigo);
628
1085
  return `IBGE ${result.ibgeCodigo} \u2014 ${name} \u2192 TSE ${result.codigosTse.join(", ")}`;
629
1086
  }
@@ -767,6 +1224,339 @@ function runDddLookup(value, options, io = { stdout: [], stderr: [] }) {
767
1224
  return runDddLookupCommand(value.trim(), options, io);
768
1225
  }
769
1226
 
1227
+ // src/commands/nfe-cuf/lookup.ts
1228
+ import {
1229
+ lookupCufPorCodigo,
1230
+ NFE_CUF_DATA_VERSION
1231
+ } from "@br-validators/core/nfe-cuf";
1232
+ function formatNfeCufHuman(row) {
1233
+ return `cUF ${row.codigo} \u2014 ${row.uf} \u2014 ${row.nome} (IBGE UF ${row.codigoIbge})`;
1234
+ }
1235
+ function runNfeCufLookupCommand(input, options, io = { stdout: [], stderr: [] }) {
1236
+ const trimmed = input.trim();
1237
+ if (trimmed.length === 0) {
1238
+ io.stderr.push("Invalid cUF code. Use 2 digits (e.g. 35).");
1239
+ return EXIT.USAGE;
1240
+ }
1241
+ const result = lookupCufPorCodigo(trimmed);
1242
+ if (!result.ok) {
1243
+ if (options.json) {
1244
+ io.stdout.push(JSON.stringify({ ok: false, code: result.code, message: result.message }, null, 2));
1245
+ return EXIT.INVALID;
1246
+ }
1247
+ io.stderr.push(result.message);
1248
+ return EXIT.INVALID;
1249
+ }
1250
+ if (options.json) {
1251
+ const payload = {
1252
+ ok: true,
1253
+ cuf: result.value
1254
+ };
1255
+ if (options.verbose) {
1256
+ payload.capturadoEm = NFE_CUF_DATA_VERSION.capturadoEm;
1257
+ }
1258
+ io.stdout.push(JSON.stringify(payload, null, 2));
1259
+ return EXIT.OK;
1260
+ }
1261
+ io.stdout.push(formatNfeCufHuman(result.value));
1262
+ if (options.verbose) {
1263
+ io.stdout.push(`capturadoEm: ${NFE_CUF_DATA_VERSION.capturadoEm}`);
1264
+ }
1265
+ return EXIT.OK;
1266
+ }
1267
+ function runNfeCufLookup(value, options, io = { stdout: [], stderr: [] }) {
1268
+ if (!value?.trim()) {
1269
+ io.stderr.push("Missing cUF code. Usage: br-validators nfe-cuf lookup <code>");
1270
+ return EXIT.USAGE;
1271
+ }
1272
+ return runNfeCufLookupCommand(value.trim(), options, io);
1273
+ }
1274
+
1275
+ // src/commands/selic/index.ts
1276
+ import {
1277
+ getSelicMeta,
1278
+ getSelicMetaPorData,
1279
+ SELIC_DATA_VERSION
1280
+ } from "@br-validators/core/selic";
1281
+ function formatSelicMetaHuman(meta) {
1282
+ return `SELIC meta ${meta.dataReferencia} \u2014 ${String(meta.valor)}% a.a.`;
1283
+ }
1284
+ function runSelicCommand(options, io = { stdout: [], stderr: [] }) {
1285
+ const meta = options.date === void 0 || options.date.trim().length === 0 ? getSelicMeta() : getSelicMetaPorData(options.date.trim());
1286
+ if (meta === void 0) {
1287
+ io.stderr.push(
1288
+ options.date ? `SELIC meta not found for date ${options.date}` : "SELIC meta series is empty"
1289
+ );
1290
+ return EXIT.INVALID;
1291
+ }
1292
+ if (options.json) {
1293
+ const payload = {
1294
+ ok: true,
1295
+ meta
1296
+ };
1297
+ if (options.verbose) {
1298
+ payload.capturadoEm = SELIC_DATA_VERSION.capturadoEm;
1299
+ }
1300
+ io.stdout.push(JSON.stringify(payload, null, 2));
1301
+ return EXIT.OK;
1302
+ }
1303
+ io.stdout.push(formatSelicMetaHuman(meta));
1304
+ if (options.verbose) {
1305
+ io.stdout.push(`dataReferencia: ${meta.dataReferencia}`);
1306
+ io.stdout.push(`isStale: ${String(meta.isStale)}`);
1307
+ if (meta.warning !== void 0) {
1308
+ io.stdout.push(`warning: ${meta.warning}`);
1309
+ }
1310
+ io.stdout.push(`capturadoEm: ${SELIC_DATA_VERSION.capturadoEm}`);
1311
+ }
1312
+ return EXIT.OK;
1313
+ }
1314
+
1315
+ // src/commands/iss-municipal/index.ts
1316
+ import {
1317
+ getIssMunicipalPorUf,
1318
+ getIssMunicipalPorUfMunicipio,
1319
+ ISS_MUNICIPAL_DATA_VERSION,
1320
+ ISS_MUNICIPAL_ESTIMATION_WARNING,
1321
+ lookupIssMunicipalPorIbge,
1322
+ searchIssMunicipal
1323
+ } from "@br-validators/core/iss-municipal";
1324
+ function sliceRows2(rows, limit) {
1325
+ if (limit === void 0 || !Number.isFinite(limit) || limit <= 0) {
1326
+ return rows;
1327
+ }
1328
+ return rows.slice(0, limit);
1329
+ }
1330
+ function formatIssMunicipalHuman(row) {
1331
+ return `${row.nome}/${row.uf} \u2014 ISS ${String(row.aliquotaMin)}%\u2013${String(row.aliquotaMax)}%`;
1332
+ }
1333
+ function emitDisclaimer(options, io) {
1334
+ if (options.json) {
1335
+ return;
1336
+ }
1337
+ io.stderr.push(ISS_MUNICIPAL_ESTIMATION_WARNING);
1338
+ }
1339
+ function runIssMunicipalLookup(codigo, options, io = { stdout: [], stderr: [] }) {
1340
+ const trimmed = codigo?.trim() ?? "";
1341
+ if (trimmed.length === 0) {
1342
+ io.stderr.push("Missing IBGE code. Usage: br-validators iss-municipal lookup <codigoIbge>");
1343
+ return EXIT.USAGE;
1344
+ }
1345
+ const result = lookupIssMunicipalPorIbge(trimmed);
1346
+ if (result === void 0) {
1347
+ io.stderr.push(`ISS municipal row not found for IBGE code ${trimmed}`);
1348
+ return EXIT.INVALID;
1349
+ }
1350
+ emitDisclaimer(options, io);
1351
+ if (options.json) {
1352
+ const payload = {
1353
+ ok: true,
1354
+ iss: result
1355
+ };
1356
+ if (options.verbose) {
1357
+ payload.capturadoEm = ISS_MUNICIPAL_DATA_VERSION.capturadoEm;
1358
+ }
1359
+ io.stdout.push(JSON.stringify(payload, null, 2));
1360
+ return EXIT.OK;
1361
+ }
1362
+ io.stdout.push(formatIssMunicipalHuman(result));
1363
+ io.stdout.push(`fonte: ${result.fonte}`);
1364
+ io.stdout.push(`warning: ${result.warning}`);
1365
+ if (options.verbose) {
1366
+ io.stdout.push(`leiUrl: ${result.leiUrl}`);
1367
+ io.stdout.push(`estimativa: ${String(result.estimativa)}`);
1368
+ io.stdout.push(`capturadoEm: ${ISS_MUNICIPAL_DATA_VERSION.capturadoEm}`);
1369
+ }
1370
+ return EXIT.OK;
1371
+ }
1372
+ function runIssMunicipalList(options, io = { stdout: [], stderr: [] }) {
1373
+ const uf = options.uf?.trim() ?? "";
1374
+ if (uf.length === 0) {
1375
+ io.stderr.push("Missing UF. Usage: br-validators iss-municipal list --uf <UF>");
1376
+ return EXIT.USAGE;
1377
+ }
1378
+ const rows = sliceRows2(getIssMunicipalPorUf(uf), options.limit);
1379
+ emitDisclaimer(options, io);
1380
+ if (options.json) {
1381
+ const payload = {
1382
+ ok: true,
1383
+ uf: uf.toUpperCase(),
1384
+ total: rows.length,
1385
+ results: rows
1386
+ };
1387
+ if (options.verbose) {
1388
+ payload.capturadoEm = ISS_MUNICIPAL_DATA_VERSION.capturadoEm;
1389
+ }
1390
+ io.stdout.push(JSON.stringify(payload, null, 2));
1391
+ return EXIT.OK;
1392
+ }
1393
+ if (rows.length === 0) {
1394
+ io.stdout.push(`No ISS municipal rows embedded for UF ${uf.toUpperCase()}.`);
1395
+ return EXIT.OK;
1396
+ }
1397
+ for (const row of rows) {
1398
+ io.stdout.push(formatIssMunicipalHuman(row));
1399
+ }
1400
+ if (options.verbose) {
1401
+ io.stdout.push(`capturadoEm: ${ISS_MUNICIPAL_DATA_VERSION.capturadoEm}`);
1402
+ }
1403
+ return EXIT.OK;
1404
+ }
1405
+ function runIssMunicipalSearch(query, options, io = { stdout: [], stderr: [] }) {
1406
+ const trimmed = query?.trim() ?? "";
1407
+ if (trimmed.length === 0) {
1408
+ io.stderr.push("Missing query. Usage: br-validators iss-municipal search <query>");
1409
+ return EXIT.USAGE;
1410
+ }
1411
+ const rows = searchIssMunicipal(trimmed, {
1412
+ limit: options.limit,
1413
+ ...options.uf !== void 0 && options.uf.trim().length > 0 ? { uf: options.uf } : {}
1414
+ });
1415
+ emitDisclaimer(options, io);
1416
+ if (options.json) {
1417
+ io.stdout.push(JSON.stringify({ ok: true, results: rows }, null, 2));
1418
+ return EXIT.OK;
1419
+ }
1420
+ if (rows.length === 0) {
1421
+ io.stdout.push("No ISS municipal rows matched.");
1422
+ return EXIT.OK;
1423
+ }
1424
+ for (const row of rows) {
1425
+ io.stdout.push(formatIssMunicipalHuman(row));
1426
+ }
1427
+ return EXIT.OK;
1428
+ }
1429
+ function runIssMunicipalResolve(uf, nome, options, io = { stdout: [], stderr: [] }) {
1430
+ const normalizedUf = uf?.trim() ?? "";
1431
+ const normalizedNome = nome?.trim() ?? "";
1432
+ if (normalizedUf.length === 0 || normalizedNome.length === 0) {
1433
+ io.stderr.push("Missing UF or municipality name. Usage: br-validators iss-municipal resolve <uf> <nome>");
1434
+ return EXIT.USAGE;
1435
+ }
1436
+ const result = getIssMunicipalPorUfMunicipio(normalizedUf, normalizedNome);
1437
+ if (result === void 0) {
1438
+ io.stderr.push(`ISS municipal row not found for ${normalizedNome}/${normalizedUf}`);
1439
+ return EXIT.INVALID;
1440
+ }
1441
+ return runIssMunicipalLookup(String(result.codigoIbge), options, io);
1442
+ }
1443
+
1444
+ // src/commands/ptax/lookup.ts
1445
+ import {
1446
+ getPtaxCotacao,
1447
+ PTAX_DATA_VERSION
1448
+ } from "@br-validators/core/ptax";
1449
+ function formatPtaxCotacaoHuman(cotacao) {
1450
+ return `${cotacao.moeda} Fechamento PTAX \u2014 compra ${String(cotacao.cotacaoCompra)} / venda ${String(cotacao.cotacaoVenda)} (${cotacao.dataReferencia})`;
1451
+ }
1452
+ function runPtaxLookupCommand(moeda, data, options, io = { stdout: [], stderr: [] }) {
1453
+ const trimmedMoeda = moeda.trim();
1454
+ if (trimmedMoeda.length === 0) {
1455
+ io.stderr.push("Missing currency code. Pass a 3-letter ISO code (e.g. USD).");
1456
+ return EXIT.USAGE;
1457
+ }
1458
+ const cotacao = data === void 0 || data.trim().length === 0 ? getPtaxCotacao(trimmedMoeda) : getPtaxCotacao(trimmedMoeda, data.trim());
1459
+ if (cotacao === void 0) {
1460
+ io.stderr.push(`PTAX quote not found: ${trimmedMoeda}${data ? ` ${data}` : ""}`);
1461
+ return EXIT.INVALID;
1462
+ }
1463
+ if (options.json) {
1464
+ const payload = {
1465
+ ok: true,
1466
+ cotacao
1467
+ };
1468
+ if (options.verbose) {
1469
+ payload.capturadoEm = PTAX_DATA_VERSION.capturadoEm;
1470
+ }
1471
+ io.stdout.push(JSON.stringify(payload, null, 2));
1472
+ return EXIT.OK;
1473
+ }
1474
+ io.stdout.push(formatPtaxCotacaoHuman(cotacao));
1475
+ if (options.verbose) {
1476
+ io.stdout.push(`dataReferencia: ${cotacao.dataReferencia}`);
1477
+ io.stdout.push(`isStale: ${String(cotacao.isStale)}`);
1478
+ if (cotacao.warning !== void 0) {
1479
+ io.stdout.push(`warning: ${cotacao.warning}`);
1480
+ }
1481
+ io.stdout.push(`capturadoEm: ${PTAX_DATA_VERSION.capturadoEm}`);
1482
+ }
1483
+ return EXIT.OK;
1484
+ }
1485
+ function runPtaxLookup(moeda, data, options, io = { stdout: [], stderr: [] }) {
1486
+ if (!moeda?.trim()) {
1487
+ io.stderr.push("Missing currency code. Usage: ptax lookup <moeda> [data]");
1488
+ return EXIT.USAGE;
1489
+ }
1490
+ return runPtaxLookupCommand(moeda.trim(), data?.trim(), options, io);
1491
+ }
1492
+
1493
+ // src/commands/ptax/historico.ts
1494
+ import {
1495
+ getPtaxHistorico,
1496
+ PTAX_DATA_VERSION as PTAX_DATA_VERSION2
1497
+ } from "@br-validators/core/ptax";
1498
+ function formatPtaxHistoricoHuman(results) {
1499
+ return results.map(
1500
+ (cotacao) => `${cotacao.dataReferencia} \u2014 compra ${String(cotacao.cotacaoCompra)} / venda ${String(cotacao.cotacaoVenda)}`
1501
+ );
1502
+ }
1503
+ function runPtaxHistoricoCommand(moeda, desde, ate, options, io = { stdout: [], stderr: [] }) {
1504
+ const trimmedMoeda = moeda.trim();
1505
+ const trimmedDesde = desde.trim();
1506
+ const trimmedAte = ate.trim();
1507
+ if (trimmedMoeda.length === 0) {
1508
+ io.stderr.push("Missing currency code. Pass a 3-letter ISO code (e.g. USD).");
1509
+ return EXIT.USAGE;
1510
+ }
1511
+ if (trimmedDesde.length === 0 || trimmedAte.length === 0) {
1512
+ io.stderr.push("Missing date range. Pass desde and ate as YYYY-MM-DD.");
1513
+ return EXIT.USAGE;
1514
+ }
1515
+ const results = getPtaxHistorico(trimmedMoeda, { desde: trimmedDesde, ate: trimmedAte });
1516
+ if (results.length === 0) {
1517
+ io.stderr.push(
1518
+ `No PTAX quotes in embed for ${trimmedMoeda} between ${trimmedDesde} and ${trimmedAte}`
1519
+ );
1520
+ return EXIT.INVALID;
1521
+ }
1522
+ if (options.json) {
1523
+ const payload = {
1524
+ ok: true,
1525
+ moeda: trimmedMoeda.toUpperCase(),
1526
+ desde: trimmedDesde,
1527
+ ate: trimmedAte,
1528
+ total: results.length,
1529
+ cotacoes: results
1530
+ };
1531
+ if (options.verbose) {
1532
+ payload.capturadoEm = PTAX_DATA_VERSION2.capturadoEm;
1533
+ payload.janelaDiasUteis = PTAX_DATA_VERSION2.janelaDiasUteis;
1534
+ }
1535
+ io.stdout.push(JSON.stringify(payload, null, 2));
1536
+ return EXIT.OK;
1537
+ }
1538
+ io.stdout.push(`${trimmedMoeda.toUpperCase()} PTAX historico (${String(results.length)} rows)`);
1539
+ for (const line of formatPtaxHistoricoHuman(results)) {
1540
+ io.stdout.push(line);
1541
+ }
1542
+ if (options.verbose) {
1543
+ io.stdout.push(`capturadoEm: ${PTAX_DATA_VERSION2.capturadoEm}`);
1544
+ io.stdout.push(`janelaDiasUteis: ${String(PTAX_DATA_VERSION2.janelaDiasUteis)}`);
1545
+ }
1546
+ return EXIT.OK;
1547
+ }
1548
+ function runPtaxHistorico(moeda, desde, ate, options, io = { stdout: [], stderr: [] }) {
1549
+ if (!moeda?.trim()) {
1550
+ io.stderr.push("Missing currency code. Usage: ptax historico <moeda> <desde> <ate>");
1551
+ return EXIT.USAGE;
1552
+ }
1553
+ if (!desde?.trim() || !ate?.trim()) {
1554
+ io.stderr.push("Missing date range. Usage: ptax historico <moeda> <desde> <ate>");
1555
+ return EXIT.USAGE;
1556
+ }
1557
+ return runPtaxHistoricoCommand(moeda.trim(), desde.trim(), ate.trim(), options, io);
1558
+ }
1559
+
770
1560
  // src/commands/brcode.ts
771
1561
  import {
772
1562
  BRCODE_OFFICIAL_SOURCE_URL,
@@ -2217,13 +3007,103 @@ function runDetect(value, options, io = { stdout: [], stderr: [] }) {
2217
3007
  return EXIT.USAGE;
2218
3008
  }
2219
3009
  const uf = options.uf?.toUpperCase();
2220
- const result = detect(input, uf ? { uf } : {});
2221
- return printDetect(result, options, io);
3010
+ const result = detect(input, uf ? { uf } : {});
3011
+ return printDetect(result, options, io);
3012
+ }
3013
+
3014
+ // src/commands/sanitize.ts
3015
+ import { sanitize } from "@br-validators/core";
3016
+ var SANITIZABLE_TYPES = [
3017
+ "cpf",
3018
+ "cnpj",
3019
+ "cep",
3020
+ "placa",
3021
+ "pis-pasep",
3022
+ "telefone",
3023
+ "cnh",
3024
+ "renavam",
3025
+ "titulo-eleitor",
3026
+ "nfe-chave",
3027
+ "boleto",
3028
+ "cartao-credito",
3029
+ "ean",
3030
+ "inscricao-estadual",
3031
+ "inscricao-estadual-produtor-rural",
3032
+ "pix"
3033
+ ];
3034
+ function isSanitizableType(type) {
3035
+ return SANITIZABLE_TYPES.includes(type);
3036
+ }
3037
+ function resolveInput21(value, fileContent) {
3038
+ const input = value ?? fileContent?.trim();
3039
+ if (!input) {
3040
+ return null;
3041
+ }
3042
+ return input;
3043
+ }
3044
+ function printSanitize(result, options, io = { stdout: [], stderr: [] }) {
3045
+ if (options.json) {
3046
+ io.stdout.push(JSON.stringify(result, null, 2));
3047
+ return result.ok ? EXIT.OK : EXIT.INVALID;
3048
+ }
3049
+ if (options.quiet) {
3050
+ return result.ok ? EXIT.OK : EXIT.INVALID;
3051
+ }
3052
+ if (result.ok) {
3053
+ io.stdout.push("valid: yes");
3054
+ io.stdout.push(`value: ${result.value}`);
3055
+ io.stdout.push(`fixes: ${result.fixes.join(", ")}`);
3056
+ return EXIT.OK;
3057
+ }
3058
+ io.stderr.push("valid: no");
3059
+ io.stderr.push(`code: ${result.code}`);
3060
+ io.stderr.push(`message: ${result.message}`);
3061
+ return EXIT.INVALID;
3062
+ }
3063
+ function runSanitize(type, value, options, io = { stdout: [], stderr: [] }) {
3064
+ if (!isSanitizableType(type)) {
3065
+ io.stderr.push(`Unsupported sanitize type: ${type}`);
3066
+ return EXIT.USAGE;
3067
+ }
3068
+ const input = resolveInput21(value, options.file);
3069
+ if (input === null) {
3070
+ io.stderr.push("Missing value. Pass an argument or use --file.");
3071
+ return EXIT.USAGE;
3072
+ }
3073
+ const uf = options.uf?.toUpperCase();
3074
+ const result = sanitize(input, type, uf ? { uf } : {});
3075
+ return printSanitize(result, options, io);
3076
+ }
3077
+
3078
+ // src/commands/mask.ts
3079
+ import { isMaskableDocumentType, maskRuntime } from "@br-validators/core";
3080
+ function resolveInput22(value, fileContent) {
3081
+ const input = value ?? fileContent?.trim();
3082
+ if (!input) {
3083
+ return null;
3084
+ }
3085
+ return input;
3086
+ }
3087
+ function runMask(type, value, options, io = { stdout: [], stderr: [] }) {
3088
+ if (!isMaskableDocumentType(type)) {
3089
+ io.stderr.push(`Unsupported mask type: ${type}`);
3090
+ return EXIT.USAGE;
3091
+ }
3092
+ const input = resolveInput22(value, options.file);
3093
+ if (input === null) {
3094
+ io.stderr.push("Missing value. Pass an argument or use --file.");
3095
+ return EXIT.USAGE;
3096
+ }
3097
+ const uf = options.uf?.toUpperCase();
3098
+ const result = maskRuntime(type, input, uf ? { uf } : {});
3099
+ return printFormat(result, options, io);
2222
3100
  }
2223
3101
 
2224
- // src/commands/sanitize.ts
2225
- import { sanitize } from "@br-validators/core";
2226
- var SANITIZABLE_TYPES = [
3102
+ // src/commands/compare.ts
3103
+ import { compareRuntime } from "@br-validators/core";
3104
+
3105
+ // src/commands/platform-document-types.ts
3106
+ var PLATFORM_DOCUMENT_TYPES = [
2227
3107
  "cpf",
2228
3108
  "cnpj",
2229
3109
  "cep",
@@ -2233,55 +3113,162 @@ var SANITIZABLE_TYPES = [
2233
3113
  "cnh",
2234
3114
  "renavam",
2235
3115
  "titulo-eleitor",
3116
+ "processo-judicial",
3117
+ "rg",
2236
3118
  "nfe-chave",
2237
3119
  "boleto",
2238
3120
  "cartao-credito",
2239
3121
  "ean",
2240
3122
  "inscricao-estadual",
2241
- "inscricao-estadual-produtor-rural"
3123
+ "inscricao-estadual-produtor-rural",
3124
+ "pix",
3125
+ "brcode"
2242
3126
  ];
2243
- function isSanitizableType(type) {
2244
- return SANITIZABLE_TYPES.includes(type);
3127
+ function isPlatformDocumentType(type) {
3128
+ return PLATFORM_DOCUMENT_TYPES.includes(type);
2245
3129
  }
2246
- function resolveInput21(value, fileContent) {
2247
- const input = value ?? fileContent?.trim();
2248
- if (!input) {
2249
- return null;
3130
+
3131
+ // src/commands/compare.ts
3132
+ function printCompare(result, options, io = { stdout: [], stderr: [] }) {
3133
+ if (options.json) {
3134
+ io.stdout.push(JSON.stringify(result, null, 2));
3135
+ if ("code" in result) {
3136
+ return EXIT.USAGE;
3137
+ }
3138
+ return result.equal ? EXIT.OK : EXIT.INVALID;
2250
3139
  }
2251
- return input;
3140
+ if (options.quiet) {
3141
+ if ("code" in result) {
3142
+ return EXIT.USAGE;
3143
+ }
3144
+ return result.equal ? EXIT.OK : EXIT.INVALID;
3145
+ }
3146
+ if ("code" in result) {
3147
+ io.stderr.push(`code: ${result.code}`);
3148
+ io.stderr.push(`message: ${result.message}`);
3149
+ return EXIT.USAGE;
3150
+ }
3151
+ io.stdout.push(`equal: ${result.equal ? "yes" : "no"}`);
3152
+ return result.equal ? EXIT.OK : EXIT.INVALID;
2252
3153
  }
2253
- function printSanitize(result, options, io = { stdout: [], stderr: [] }) {
3154
+ function runCompare(type, valueA, valueB, options, io = { stdout: [], stderr: [] }) {
3155
+ if (!isPlatformDocumentType(type)) {
3156
+ io.stderr.push(`Unsupported compare type: ${type}`);
3157
+ return EXIT.USAGE;
3158
+ }
3159
+ if (!valueA || !valueB) {
3160
+ io.stderr.push("Missing values. Usage: compare <type> <valueA> <valueB>");
3161
+ return EXIT.USAGE;
3162
+ }
3163
+ const uf = options.uf?.toUpperCase();
3164
+ const platformOptions = uf ? { uf } : {};
3165
+ const result = compareRuntime(valueA, valueB, type, platformOptions);
3166
+ return printCompare(result, options, io);
3167
+ }
3168
+
3169
+ // src/commands/batch.ts
3170
+ import { batch, parseBatchCsv } from "@br-validators/core";
3171
+ function parseBatchLines(raw) {
3172
+ return raw.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
3173
+ }
3174
+ function resolveBatchInputs(options) {
3175
+ if (options.lines === void 0) {
3176
+ return { ok: false, reason: "missing_input" };
3177
+ }
3178
+ let parsed;
3179
+ if (options.col !== void 0) {
3180
+ const csv = parseBatchCsv(options.lines, {
3181
+ col: options.col,
3182
+ delimiter: options.delimiter,
3183
+ skipHeader: options.skipHeader
3184
+ });
3185
+ if (!csv.ok) {
3186
+ return { ok: false, reason: "parse_error", message: csv.message };
3187
+ }
3188
+ parsed = csv.values;
3189
+ } else {
3190
+ parsed = parseBatchLines(options.lines);
3191
+ }
3192
+ if (parsed.length === 0) {
3193
+ return { ok: false, reason: "empty" };
3194
+ }
3195
+ if (options.limit !== void 0 && options.limit > 0) {
3196
+ return { ok: true, values: parsed.slice(0, options.limit) };
3197
+ }
3198
+ return { ok: true, values: parsed };
3199
+ }
3200
+ function printBatch(result, options, io = { stdout: [], stderr: [] }) {
2254
3201
  if (options.json) {
2255
3202
  io.stdout.push(JSON.stringify(result, null, 2));
2256
- return result.ok ? EXIT.OK : EXIT.INVALID;
3203
+ return result.summary.invalid === 0 ? EXIT.OK : EXIT.INVALID;
2257
3204
  }
2258
3205
  if (options.quiet) {
2259
- return result.ok ? EXIT.OK : EXIT.INVALID;
3206
+ return result.summary.invalid === 0 ? EXIT.OK : EXIT.INVALID;
2260
3207
  }
2261
- if (result.ok) {
2262
- io.stdout.push("valid: yes");
2263
- io.stdout.push(`value: ${result.value}`);
2264
- io.stdout.push(`fixes: ${result.fixes.join(", ")}`);
2265
- return EXIT.OK;
3208
+ io.stdout.push(`total: ${String(result.summary.total)}`);
3209
+ io.stdout.push(`valid: ${String(result.summary.valid)}`);
3210
+ io.stdout.push(`invalid: ${String(result.summary.invalid)}`);
3211
+ for (const entry of result.valid) {
3212
+ io.stdout.push(`ok[${String(entry.index)}]: ${entry.value}`);
2266
3213
  }
2267
- io.stderr.push("valid: no");
2268
- io.stderr.push(`code: ${result.code}`);
2269
- io.stderr.push(`message: ${result.message}`);
2270
- return EXIT.INVALID;
3214
+ for (const entry of result.invalid) {
3215
+ io.stderr.push(`fail[${String(entry.index)}]: ${entry.code} \u2014 ${entry.message}`);
3216
+ }
3217
+ return result.summary.invalid === 0 ? EXIT.OK : EXIT.INVALID;
2271
3218
  }
2272
- function runSanitize(type, value, options, io = { stdout: [], stderr: [] }) {
2273
- if (!isSanitizableType(type)) {
2274
- io.stderr.push(`Unsupported sanitize type: ${type}`);
3219
+ function runBatch(type, options, io = { stdout: [], stderr: [] }) {
3220
+ if (!isPlatformDocumentType(type)) {
3221
+ io.stderr.push(`Unsupported batch type: ${type}`);
2275
3222
  return EXIT.USAGE;
2276
3223
  }
2277
- const input = resolveInput21(value, options.file);
2278
- if (input === null) {
2279
- io.stderr.push("Missing value. Pass an argument or use --file.");
3224
+ const resolved = resolveBatchInputs(options);
3225
+ if (!resolved.ok) {
3226
+ if (resolved.reason === "missing_input") {
3227
+ io.stderr.push("Missing input. Pass --file <path> or pipe one value per line on stdin.");
3228
+ } else if (resolved.reason === "empty") {
3229
+ io.stderr.push("No values to validate.");
3230
+ } else {
3231
+ io.stderr.push(resolved.message);
3232
+ }
2280
3233
  return EXIT.USAGE;
2281
3234
  }
2282
3235
  const uf = options.uf?.toUpperCase();
2283
- const result = sanitize(input, type, uf ? { uf } : {});
2284
- return printSanitize(result, options, io);
3236
+ const platformOptions = uf ? { uf } : {};
3237
+ const result = batch(resolved.values, type, platformOptions);
3238
+ return printBatch(result, options, io);
3239
+ }
3240
+
3241
+ // src/commands/diff.ts
3242
+ import { diff } from "@br-validators/core";
3243
+ function printDiff(result, options, io = { stdout: [], stderr: [] }) {
3244
+ if (options.json) {
3245
+ io.stdout.push(JSON.stringify(result, null, 2));
3246
+ return result.changed ? EXIT.INVALID : EXIT.OK;
3247
+ }
3248
+ if (options.quiet) {
3249
+ return result.changed ? EXIT.INVALID : EXIT.OK;
3250
+ }
3251
+ io.stdout.push(`changed: ${result.changed ? "yes" : "no"}`);
3252
+ for (const field of result.fields) {
3253
+ io.stdout.push(`field: ${field.field}`);
3254
+ io.stdout.push(` a: ${field.a}`);
3255
+ io.stdout.push(` b: ${field.b}`);
3256
+ }
3257
+ return result.changed ? EXIT.INVALID : EXIT.OK;
3258
+ }
3259
+ function runDiff(type, valueA, valueB, options, io = { stdout: [], stderr: [] }) {
3260
+ if (!isPlatformDocumentType(type)) {
3261
+ io.stderr.push(`Unsupported diff type: ${type}`);
3262
+ return EXIT.USAGE;
3263
+ }
3264
+ if (!valueA || !valueB) {
3265
+ io.stderr.push("Missing values. Usage: diff <type> <valueA> <valueB>");
3266
+ return EXIT.USAGE;
3267
+ }
3268
+ const uf = options.uf?.toUpperCase();
3269
+ const platformOptions = uf ? { uf } : {};
3270
+ const result = diff(valueA, valueB, type, platformOptions);
3271
+ return printDiff(result, options, io);
2285
3272
  }
2286
3273
 
2287
3274
  // src/commands/generate.ts
@@ -2313,6 +3300,9 @@ function buildGenerateOptions(options) {
2313
3300
  if (options.masked) {
2314
3301
  core.masked = true;
2315
3302
  }
3303
+ if (options.stripped) {
3304
+ core.stripped = true;
3305
+ }
2316
3306
  if (options.seed !== void 0) {
2317
3307
  core.seed = options.seed;
2318
3308
  }
@@ -2356,10 +3346,14 @@ function listSupportedTypes(io = { stdout: [] }) {
2356
3346
  }
2357
3347
 
2358
3348
  // src/handlers.ts
3349
+ var nodeRequire = createRequire(import.meta.url);
3350
+ function readNodeFileSync(path, encoding) {
3351
+ const fs = nodeRequire("node:fs");
3352
+ return fs.readFileSync(path, encoding);
3353
+ }
2359
3354
  function readInputFile(path, io) {
2360
3355
  try {
2361
- const fsModule = __require("fs");
2362
- return fsModule.readFileSync(path, "utf8");
3356
+ return readNodeFileSync(path, "utf8");
2363
3357
  } catch {
2364
3358
  io.stderr.push(`Cannot read file: ${path}`);
2365
3359
  return null;
@@ -2836,6 +3830,93 @@ function handleSanitizeCli(type, value, opts, io = { stdout: [], stderr: [] }) {
2836
3830
  io
2837
3831
  );
2838
3832
  }
3833
+ function handleMaskCli(type, value, opts, io = { stdout: [], stderr: [] }) {
3834
+ let fileContent;
3835
+ if (opts.file) {
3836
+ const content = readInputFile(opts.file, io);
3837
+ if (content === null) {
3838
+ return EXIT.USAGE;
3839
+ }
3840
+ fileContent = content;
3841
+ }
3842
+ return runMask(
3843
+ type,
3844
+ value,
3845
+ {
3846
+ json: Boolean(opts.json),
3847
+ quiet: Boolean(opts.quiet),
3848
+ uf: opts.uf,
3849
+ file: fileContent
3850
+ },
3851
+ io
3852
+ );
3853
+ }
3854
+ function readStdinSync(io) {
3855
+ try {
3856
+ if (process.stdin.isTTY) {
3857
+ return null;
3858
+ }
3859
+ return readNodeFileSync(0, "utf8");
3860
+ } catch {
3861
+ io.stderr.push("Cannot read stdin.");
3862
+ return null;
3863
+ }
3864
+ }
3865
+ function handleCompareCli(type, valueA, valueB, opts, io = { stdout: [], stderr: [] }) {
3866
+ return runCompare(
3867
+ type,
3868
+ valueA,
3869
+ valueB,
3870
+ {
3871
+ json: Boolean(opts.json),
3872
+ quiet: Boolean(opts.quiet),
3873
+ uf: opts.uf
3874
+ },
3875
+ io
3876
+ );
3877
+ }
3878
+ function handleDiffCli(type, valueA, valueB, opts, io = { stdout: [], stderr: [] }) {
3879
+ return runDiff(
3880
+ type,
3881
+ valueA,
3882
+ valueB,
3883
+ {
3884
+ json: Boolean(opts.json),
3885
+ quiet: Boolean(opts.quiet),
3886
+ uf: opts.uf
3887
+ },
3888
+ io
3889
+ );
3890
+ }
3891
+ function handleBatchCli(type, opts, io = { stdout: [], stderr: [] }) {
3892
+ let lines;
3893
+ if (opts.file) {
3894
+ const content = readInputFile(opts.file, io);
3895
+ if (content === null) {
3896
+ return EXIT.USAGE;
3897
+ }
3898
+ lines = content;
3899
+ } else {
3900
+ const stdin = readStdinSync(io);
3901
+ if (stdin !== null) {
3902
+ lines = stdin;
3903
+ }
3904
+ }
3905
+ return runBatch(
3906
+ type,
3907
+ {
3908
+ json: Boolean(opts.json),
3909
+ quiet: Boolean(opts.quiet),
3910
+ uf: opts.uf,
3911
+ lines,
3912
+ limit: opts.limit,
3913
+ col: opts.col,
3914
+ delimiter: opts.delimiter,
3915
+ skipHeader: opts.skipHeader
3916
+ },
3917
+ io
3918
+ );
3919
+ }
2839
3920
  function handleGenerateCli(type, opts, io = { stdout: [], stderr: [] }) {
2840
3921
  return runGenerate(
2841
3922
  type,
@@ -2843,6 +3924,7 @@ function handleGenerateCli(type, opts, io = { stdout: [], stderr: [] }) {
2843
3924
  json: Boolean(opts.json),
2844
3925
  quiet: Boolean(opts.quiet),
2845
3926
  masked: Boolean(opts.masked),
3927
+ stripped: Boolean(opts.stripped),
2846
3928
  format: opts.format,
2847
3929
  seed: opts.seed,
2848
3930
  uf: opts.uf,
@@ -2894,6 +3976,39 @@ function handleReferenceSearchCli(command, query, opts, io = { stdout: [], stder
2894
3976
  io
2895
3977
  );
2896
3978
  }
3979
+ function handleReferenceValidateCli(command, value, opts, io = { stdout: [], stderr: [] }) {
3980
+ return runReferenceValidate(
3981
+ command,
3982
+ value,
3983
+ {
3984
+ json: Boolean(opts.json),
3985
+ verbose: Boolean(opts.verbose)
3986
+ },
3987
+ io
3988
+ );
3989
+ }
3990
+ function handleCstLookupCli(value, opts, io = { stdout: [], stderr: [] }) {
3991
+ return runCstLookup(value, {
3992
+ json: Boolean(opts.json),
3993
+ verbose: Boolean(opts.verbose),
3994
+ tax: opts.tax
3995
+ }, io);
3996
+ }
3997
+ function handleCstSearchCli(query, opts, io = { stdout: [], stderr: [] }) {
3998
+ return runCstSearch(query, {
3999
+ json: Boolean(opts.json),
4000
+ verbose: Boolean(opts.verbose),
4001
+ tax: opts.tax,
4002
+ limit: opts.limit
4003
+ }, io);
4004
+ }
4005
+ function handleCstValidateCli(value, opts, io = { stdout: [], stderr: [] }) {
4006
+ return runCstValidate(value, {
4007
+ json: Boolean(opts.json),
4008
+ verbose: Boolean(opts.verbose),
4009
+ tax: opts.tax
4010
+ }, io);
4011
+ }
2897
4012
  function handleIbgeLookupCli(value, opts, io = { stdout: [], stderr: [] }) {
2898
4013
  return runIbgeLookup(value, { json: Boolean(opts.json), verbose: Boolean(opts.verbose) }, io);
2899
4014
  }
@@ -2912,6 +4027,34 @@ function handleFeriadosListCli(opts, io = { stdout: [], stderr: [] }) {
2912
4027
  year: opts.year
2913
4028
  }, io);
2914
4029
  }
4030
+ function handleInssTabelaCli(opts, io = { stdout: [], stderr: [] }) {
4031
+ return runInssTabela({
4032
+ json: Boolean(opts.json),
4033
+ verbose: Boolean(opts.verbose),
4034
+ ano: opts.year
4035
+ }, io);
4036
+ }
4037
+ function handleInssCalcCli(value, opts, io = { stdout: [], stderr: [] }) {
4038
+ return runInssCalc(value, {
4039
+ json: Boolean(opts.json),
4040
+ verbose: Boolean(opts.verbose),
4041
+ ano: opts.year
4042
+ }, io);
4043
+ }
4044
+ function handleIrpfTabelaCli(opts, io = { stdout: [], stderr: [] }) {
4045
+ return runIrpfTabela({
4046
+ json: Boolean(opts.json),
4047
+ verbose: Boolean(opts.verbose),
4048
+ ano: opts.year
4049
+ }, io);
4050
+ }
4051
+ function handleIrpfCalcCli(value, opts, io = { stdout: [], stderr: [] }) {
4052
+ return runIrpfCalc(value, {
4053
+ json: Boolean(opts.json),
4054
+ verbose: Boolean(opts.verbose),
4055
+ ano: opts.year
4056
+ }, io);
4057
+ }
2915
4058
  function handleTseMunicipiosLookupCli(value, opts, io = { stdout: [], stderr: [] }) {
2916
4059
  return runTseMunicipiosLookup(value, { json: Boolean(opts.json), verbose: Boolean(opts.verbose) }, io);
2917
4060
  }
@@ -2921,6 +4064,50 @@ function handleCepFaixaCli(value, opts, io = { stdout: [], stderr: [] }) {
2921
4064
  function handleDddLookupCli(value, opts, io = { stdout: [], stderr: [] }) {
2922
4065
  return runDddLookup(value, { json: Boolean(opts.json), verbose: Boolean(opts.verbose) }, io);
2923
4066
  }
4067
+ function handleNfeCufLookupCli(value, opts, io = { stdout: [], stderr: [] }) {
4068
+ return runNfeCufLookup(value, { json: Boolean(opts.json), verbose: Boolean(opts.verbose) }, io);
4069
+ }
4070
+ function handleSelicCli(opts, io = { stdout: [], stderr: [] }) {
4071
+ return runSelicCommand({
4072
+ json: Boolean(opts.json),
4073
+ verbose: Boolean(opts.verbose),
4074
+ date: opts.date
4075
+ }, io);
4076
+ }
4077
+ function handleIssMunicipalListCli(opts, io = { stdout: [], stderr: [] }) {
4078
+ return runIssMunicipalList({
4079
+ json: Boolean(opts.json),
4080
+ verbose: Boolean(opts.verbose),
4081
+ uf: opts.uf,
4082
+ limit: opts.limit
4083
+ }, io);
4084
+ }
4085
+ function handleIssMunicipalLookupCli(codigo, opts, io = { stdout: [], stderr: [] }) {
4086
+ return runIssMunicipalLookup(codigo, { json: Boolean(opts.json), verbose: Boolean(opts.verbose) }, io);
4087
+ }
4088
+ function handleIssMunicipalSearchCli(query, opts, io = { stdout: [], stderr: [] }) {
4089
+ return runIssMunicipalSearch(query, {
4090
+ json: Boolean(opts.json),
4091
+ verbose: Boolean(opts.verbose),
4092
+ limit: opts.limit,
4093
+ uf: opts.uf
4094
+ }, io);
4095
+ }
4096
+ function handleIssMunicipalResolveCli(uf, nome, opts, io = { stdout: [], stderr: [] }) {
4097
+ return runIssMunicipalResolve(uf, nome, { json: Boolean(opts.json), verbose: Boolean(opts.verbose) }, io);
4098
+ }
4099
+ function handlePtaxLookupCli(moeda, data, opts, io = { stdout: [], stderr: [] }) {
4100
+ return runPtaxLookup(moeda, data, { json: Boolean(opts.json), verbose: Boolean(opts.verbose) }, io);
4101
+ }
4102
+ function handlePtaxHistoricoCli(moeda, desde, ate, opts, io = { stdout: [], stderr: [] }) {
4103
+ return runPtaxHistorico(
4104
+ moeda,
4105
+ desde,
4106
+ ate,
4107
+ { json: Boolean(opts.json), verbose: Boolean(opts.verbose) },
4108
+ io
4109
+ );
4110
+ }
2924
4111
 
2925
4112
  // src/argv-dispatch.ts
2926
4113
  var STANDARD_ACTIONS = ["validate", "format", "strip"];
@@ -2955,6 +4142,10 @@ function parseArgv(tokens) {
2955
4142
  opts.masked = true;
2956
4143
  continue;
2957
4144
  }
4145
+ if (token === "--stripped") {
4146
+ opts.stripped = true;
4147
+ continue;
4148
+ }
2958
4149
  if (token === "-f" || token === "--file") {
2959
4150
  opts.file = tokens[index + 1];
2960
4151
  index += 1;
@@ -2994,11 +4185,26 @@ function parseArgv(tokens) {
2994
4185
  index += 1;
2995
4186
  continue;
2996
4187
  }
4188
+ if (token === "--tax") {
4189
+ opts.tax = tokens[index + 1];
4190
+ index += 1;
4191
+ continue;
4192
+ }
2997
4193
  if (token === "--year") {
2998
4194
  opts.year = Number(tokens[index + 1]);
2999
4195
  index += 1;
3000
4196
  continue;
3001
4197
  }
4198
+ if (token === "--ano") {
4199
+ opts.year = Number(tokens[index + 1]);
4200
+ index += 1;
4201
+ continue;
4202
+ }
4203
+ if (token === "--date") {
4204
+ opts.date = tokens[index + 1];
4205
+ index += 1;
4206
+ continue;
4207
+ }
3002
4208
  if (token.startsWith("-")) {
3003
4209
  continue;
3004
4210
  }
@@ -3021,7 +4227,7 @@ function dispatchArgv(tokens, io) {
3021
4227
  if (tokens.length === 0 || tokens.includes("--help") || tokens.includes("-h")) {
3022
4228
  io.stdout.push("br-validators \u2014 100% open-source Brazilian document validators");
3023
4229
  io.stdout.push("Usage: br-validators <command> ...");
3024
- io.stdout.push("Commands: list \xB7 cpf \xB7 cnpj \xB7 cep \xB7 telefone \xB7 cnh \xB7 renavam \xB7 titulo-eleitor \xB7 processo-judicial \xB7 rg \xB7 nfe-chave \xB7 brcode \xB7 placa \xB7 pis-pasep \xB7 cnis \xB7 pix \xB7 boleto \xB7 cartao \xB7 cartao-credito \xB7 ean \xB7 ie \xB7 bancos \xB7 ibge \xB7 feriados \xB7 tse-municipios \xB7 ddd \xB7 natureza-juridica \xB7 nbs \xB7 cest \xB7 cnae \xB7 cfop \xB7 ncm \xB7 cbo \xB7 moedas \xB7 paises-bacen \xB7 incoterms \xB7 portos \xB7 aeroportos \xB7 detect \xB7 sanitize \xB7 generate");
4230
+ io.stdout.push("Commands: list \xB7 cpf \xB7 cnpj \xB7 cep \xB7 telefone \xB7 cnh \xB7 renavam \xB7 titulo-eleitor \xB7 processo-judicial \xB7 rg \xB7 nfe-chave \xB7 brcode \xB7 placa \xB7 pis-pasep \xB7 cnis \xB7 pix \xB7 boleto \xB7 cartao \xB7 cartao-credito \xB7 ean \xB7 ie \xB7 bancos \xB7 ibge \xB7 feriados \xB7 inss \xB7 irpf \xB7 tse-municipios \xB7 ddd \xB7 nfe-cuf \xB7 selic \xB7 iss-municipal \xB7 ptax \xB7 cst \xB7 csosn \xB7 natureza-juridica \xB7 nbs \xB7 cest \xB7 cnae \xB7 cfop \xB7 ncm \xB7 cbo \xB7 moedas \xB7 paises-bacen \xB7 incoterms \xB7 portos \xB7 aeroportos \xB7 detect \xB7 sanitize \xB7 mask \xB7 compare \xB7 batch \xB7 diff \xB7 generate");
3025
4231
  return EXIT.OK;
3026
4232
  }
3027
4233
  if (tokens.includes("--version") || tokens.includes("-V")) {
@@ -3199,6 +4405,28 @@ function dispatchArgv(tokens, io) {
3199
4405
  }
3200
4406
  return usage(io, "Expected: feriados list [--year YYYY]");
3201
4407
  }
4408
+ case "inss": {
4409
+ const action = rest[0];
4410
+ if (action === "tabela") {
4411
+ return handleInssTabelaCli(opts, io);
4412
+ }
4413
+ if (action === "calc") {
4414
+ const value = rest.slice(1).join(" ") || void 0;
4415
+ return handleInssCalcCli(value, opts, io);
4416
+ }
4417
+ return usage(io, "Expected: inss tabela [--ano YYYY] | inss calc <salario> [--ano YYYY]");
4418
+ }
4419
+ case "irpf": {
4420
+ const action = rest[0];
4421
+ if (action === "tabela") {
4422
+ return handleIrpfTabelaCli(opts, io);
4423
+ }
4424
+ if (action === "calc") {
4425
+ const value = rest.slice(1).join(" ") || void 0;
4426
+ return handleIrpfCalcCli(value, opts, io);
4427
+ }
4428
+ return usage(io, "Expected: irpf tabela [--ano YYYY] | irpf calc <base> [--ano YYYY]");
4429
+ }
3202
4430
  case "tse-municipios": {
3203
4431
  const action = rest[0];
3204
4432
  if (action === "lookup") {
@@ -3215,10 +4443,99 @@ function dispatchArgv(tokens, io) {
3215
4443
  }
3216
4444
  return usage(io, "Expected: ddd lookup <code>");
3217
4445
  }
4446
+ case "nfe-cuf": {
4447
+ const action = rest[0];
4448
+ if (action === "lookup") {
4449
+ const value = rest.slice(1).join(" ") || void 0;
4450
+ return handleNfeCufLookupCli(value, opts, io);
4451
+ }
4452
+ return usage(io, "Expected: nfe-cuf lookup <code>");
4453
+ }
4454
+ case "selic": {
4455
+ return handleSelicCli(opts, io);
4456
+ }
4457
+ case "iss-municipal": {
4458
+ const action = rest[0];
4459
+ if (action === "lookup") {
4460
+ const value = rest[1];
4461
+ return handleIssMunicipalLookupCli(value, opts, io);
4462
+ }
4463
+ if (action === "list") {
4464
+ return handleIssMunicipalListCli(opts, io);
4465
+ }
4466
+ if (action === "resolve") {
4467
+ const uf = rest[1];
4468
+ const nome = rest.slice(2).join(" ") || void 0;
4469
+ return handleIssMunicipalResolveCli(uf, nome, opts, io);
4470
+ }
4471
+ if (action === "search") {
4472
+ const value = rest.slice(1).join(" ") || void 0;
4473
+ return handleIssMunicipalSearchCli(value, opts, io);
4474
+ }
4475
+ return usage(io, "Expected: iss-municipal lookup|list|resolve|search <args>");
4476
+ }
4477
+ case "ptax": {
4478
+ const action = rest[0];
4479
+ if (action === "lookup") {
4480
+ const moeda = rest[1];
4481
+ const data = rest.slice(2).join(" ") || void 0;
4482
+ return handlePtaxLookupCli(moeda, data, opts, io);
4483
+ }
4484
+ if (action === "historico") {
4485
+ const moeda = rest[1];
4486
+ const desde = rest[2];
4487
+ const ate = rest[3];
4488
+ return handlePtaxHistoricoCli(moeda, desde, ate, opts, io);
4489
+ }
4490
+ return usage(io, "Expected: ptax lookup <moeda> [data] | ptax historico <moeda> <desde> <ate>");
4491
+ }
4492
+ case "cst": {
4493
+ const action = rest[0];
4494
+ if (action === "lookup") {
4495
+ const value = rest.slice(1).join(" ") || void 0;
4496
+ return handleCstLookupCli(value, opts, io);
4497
+ }
4498
+ if (action === "search") {
4499
+ const value = rest.slice(1).join(" ") || void 0;
4500
+ return handleCstSearchCli(value, opts, io);
4501
+ }
4502
+ if (action === "validate") {
4503
+ const value = rest.slice(1).join(" ") || void 0;
4504
+ return handleCstValidateCli(value, opts, io);
4505
+ }
4506
+ return usage(io, "Expected: cst lookup|search|validate <codigo|query> --tax icms|ipi|pis|cofins");
4507
+ }
3218
4508
  case "detect":
3219
4509
  return handleDetectCli(rest.join(" ") || void 0, opts, io);
3220
4510
  case "sanitize":
3221
4511
  return handleSanitizeCli(rest[0] ?? "", rest.slice(1).join(" ") || void 0, opts, io);
4512
+ case "mask":
4513
+ return handleMaskCli(rest[0] ?? "", rest.slice(1).join(" ") || void 0, opts, io);
4514
+ case "compare": {
4515
+ const type = rest[0];
4516
+ const valueA = rest[1];
4517
+ const valueB = rest.slice(2).join(" ") || void 0;
4518
+ if (!type) {
4519
+ return usage(io, "Expected: compare <type> <valueA> <valueB>");
4520
+ }
4521
+ return handleCompareCli(type, valueA, valueB, opts, io);
4522
+ }
4523
+ case "batch": {
4524
+ const type = rest[0];
4525
+ if (!type) {
4526
+ return usage(io, "Expected: batch <type> [--file path]");
4527
+ }
4528
+ return handleBatchCli(type, opts, io);
4529
+ }
4530
+ case "diff": {
4531
+ const type = rest[0];
4532
+ const valueA = rest[1];
4533
+ const valueB = rest.slice(2).join(" ") || void 0;
4534
+ if (!type) {
4535
+ return usage(io, "Expected: diff <type> <valueA> <valueB>");
4536
+ }
4537
+ return handleDiffCli(type, valueA, valueB, opts, io);
4538
+ }
3222
4539
  case "generate":
3223
4540
  return handleGenerateCli(rest[0] ?? "", opts, io);
3224
4541
  default: {
@@ -3232,8 +4549,13 @@ function dispatchArgv(tokens, io) {
3232
4549
  const value = rest.slice(1).join(" ") || void 0;
3233
4550
  return handleReferenceSearchCli(root, value, opts, io);
3234
4551
  }
4552
+ if (action === "validate" && isReferenceValidateCommand(root)) {
4553
+ const value = rest.slice(1).join(" ") || void 0;
4554
+ return handleReferenceValidateCli(root, value, opts, io);
4555
+ }
3235
4556
  const searchHint = isReferenceSearchCommand(root) ? " | search <query>" : "";
3236
- return usage(io, `Expected: ${root} lookup <codigo>${searchHint}`);
4557
+ const validateHint = isReferenceValidateCommand(root) ? " | validate <codigo>" : "";
4558
+ return usage(io, `Expected: ${root} lookup <codigo>${searchHint}${validateHint}`);
3237
4559
  }
3238
4560
  return usage(io, `Unknown command: ${root}`);
3239
4561
  }