@br-validators/cli 0.11.0-alpha.0 → 0.12.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.
Files changed (2) hide show
  1. package/dist/index.js +583 -21
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  } from "@br-validators/core";
15
15
 
16
16
  // src/constants.ts
17
- var SUPPORTED_TYPES = ["cnpj", "cpf", "cep", "telefone", "brcode", "placa", "pis-pasep", "pix", "boleto", "cartao", "ie"];
17
+ var SUPPORTED_TYPES = ["cnpj", "cpf", "cep", "telefone", "cnh", "renavam", "titulo-eleitor", "nfe-chave", "brcode", "placa", "pis-pasep", "pix", "boleto", "cartao", "ie"];
18
18
  var EXIT = {
19
19
  OK: 0,
20
20
  INVALID: 1,
@@ -136,6 +136,46 @@ function printValidation(result, options, io = { stdout: [], stderr: [] }) {
136
136
  io.stderr.push(`message: ${result.message}`);
137
137
  return EXIT.INVALID;
138
138
  }
139
+ function printNfeChaveValidation(result, options, io = { stdout: [], stderr: [] }) {
140
+ if (options.json) {
141
+ io.stdout.push(
142
+ JSON.stringify(
143
+ result.ok ? {
144
+ ok: true,
145
+ value: result.value,
146
+ format: result.format,
147
+ parsed: result.parsed,
148
+ ...result.uf ? { uf: result.uf } : {},
149
+ ...options.source ? { source: options.source } : {}
150
+ } : { ok: false, code: result.code, message: result.message },
151
+ null,
152
+ 2
153
+ )
154
+ );
155
+ return result.ok ? EXIT.OK : EXIT.INVALID;
156
+ }
157
+ if (options.quiet) {
158
+ return result.ok ? EXIT.OK : EXIT.INVALID;
159
+ }
160
+ if (result.ok) {
161
+ io.stdout.push(`valid: yes (${result.format})`);
162
+ io.stdout.push(`value: ${result.value}`);
163
+ io.stdout.push(`cUF: ${result.parsed.cUF}`);
164
+ io.stdout.push(`cnpj: ${result.parsed.cnpj}`);
165
+ io.stdout.push(`mod: ${result.parsed.mod}`);
166
+ if (result.uf) {
167
+ io.stdout.push(`uf: ${result.uf}`);
168
+ }
169
+ if (options.source) {
170
+ io.stdout.push(`source: ${options.source}`);
171
+ }
172
+ return EXIT.OK;
173
+ }
174
+ io.stderr.push("valid: no");
175
+ io.stderr.push(`code: ${result.code}`);
176
+ io.stderr.push(`message: ${result.message}`);
177
+ return EXIT.INVALID;
178
+ }
139
179
  function printFormat(result, options, io = { stdout: [], stderr: [] }) {
140
180
  if (options.json) {
141
181
  io.stdout.push(JSON.stringify(result, null, 2));
@@ -267,6 +307,165 @@ function runTelefone(action, value, options, io = { stdout: [], stderr: [] }) {
267
307
  return runTelefoneCommand(action, input, options, io);
268
308
  }
269
309
 
310
+ // src/commands/cnh.ts
311
+ import {
312
+ CNH_OFFICIAL_SOURCE_URL,
313
+ formatCnh,
314
+ stripCnh,
315
+ validateCnh
316
+ } from "@br-validators/core";
317
+ function resolveInput4(value, fileContent) {
318
+ const input = value ?? fileContent?.trim();
319
+ if (!input) {
320
+ return null;
321
+ }
322
+ return input;
323
+ }
324
+ function runCnhCommand(action, input, options, io = { stdout: [], stderr: [] }) {
325
+ const source = options.source ? CNH_OFFICIAL_SOURCE_URL : void 0;
326
+ switch (action) {
327
+ case "validate":
328
+ return printValidation(validateCnh(input), { json: options.json, quiet: options.quiet, source }, io);
329
+ case "format":
330
+ return printFormat(formatCnh(input), { json: options.json, quiet: options.quiet }, io);
331
+ case "strip":
332
+ return printStrip(stripCnh(input), { json: options.json }, io);
333
+ default: {
334
+ const _exhaustive = action;
335
+ io.stderr.push(`Unknown action: ${_exhaustive}`);
336
+ return EXIT.USAGE;
337
+ }
338
+ }
339
+ }
340
+ function runCnh(action, value, options, io = { stdout: [], stderr: [] }) {
341
+ const input = resolveInput4(value, options.file);
342
+ if (input === null) {
343
+ io.stderr.push("Missing CNH value. Pass an argument or use --file.");
344
+ return EXIT.USAGE;
345
+ }
346
+ return runCnhCommand(action, input, options, io);
347
+ }
348
+
349
+ // src/commands/renavam.ts
350
+ import {
351
+ RENAVAM_OFFICIAL_SOURCE_URL,
352
+ formatRenavam,
353
+ stripRenavam,
354
+ validateRenavam
355
+ } from "@br-validators/core";
356
+ function resolveInput5(value, fileContent) {
357
+ const input = value ?? fileContent?.trim();
358
+ if (!input) {
359
+ return null;
360
+ }
361
+ return input;
362
+ }
363
+ function runRenavamCommand(action, input, options, io = { stdout: [], stderr: [] }) {
364
+ const source = options.source ? RENAVAM_OFFICIAL_SOURCE_URL : void 0;
365
+ switch (action) {
366
+ case "validate":
367
+ return printValidation(validateRenavam(input), { json: options.json, quiet: options.quiet, source }, io);
368
+ case "format":
369
+ return printFormat(formatRenavam(input), { json: options.json, quiet: options.quiet }, io);
370
+ case "strip":
371
+ return printStrip(stripRenavam(input), { json: options.json }, io);
372
+ default: {
373
+ const _exhaustive = action;
374
+ io.stderr.push(`Unknown action: ${_exhaustive}`);
375
+ return EXIT.USAGE;
376
+ }
377
+ }
378
+ }
379
+ function runRenavam(action, value, options, io = { stdout: [], stderr: [] }) {
380
+ const input = resolveInput5(value, options.file);
381
+ if (input === null) {
382
+ io.stderr.push("Missing RENAVAM value. Pass an argument or use --file.");
383
+ return EXIT.USAGE;
384
+ }
385
+ return runRenavamCommand(action, input, options, io);
386
+ }
387
+
388
+ // src/commands/titulo-eleitor.ts
389
+ import {
390
+ TITULO_ELEITOR_OFFICIAL_SOURCE_URL,
391
+ formatTituloEleitor,
392
+ stripTituloEleitor,
393
+ validateTituloEleitor
394
+ } from "@br-validators/core";
395
+ function resolveInput6(value, fileContent) {
396
+ const input = value ?? fileContent?.trim();
397
+ if (!input) {
398
+ return null;
399
+ }
400
+ return input;
401
+ }
402
+ function runTituloEleitorCommand(action, input, options, io = { stdout: [], stderr: [] }) {
403
+ const source = options.source ? TITULO_ELEITOR_OFFICIAL_SOURCE_URL : void 0;
404
+ switch (action) {
405
+ case "validate":
406
+ return printValidation(validateTituloEleitor(input), { json: options.json, quiet: options.quiet, source }, io);
407
+ case "format":
408
+ return printFormat(formatTituloEleitor(input), { json: options.json, quiet: options.quiet }, io);
409
+ case "strip":
410
+ return printStrip(stripTituloEleitor(input), { json: options.json }, io);
411
+ default: {
412
+ const _exhaustive = action;
413
+ io.stderr.push(`Unknown action: ${_exhaustive}`);
414
+ return EXIT.USAGE;
415
+ }
416
+ }
417
+ }
418
+ function runTituloEleitor(action, value, options, io = { stdout: [], stderr: [] }) {
419
+ const input = resolveInput6(value, options.file);
420
+ if (input === null) {
421
+ io.stderr.push("Missing T\xEDtulo de Eleitor value. Pass an argument or use --file.");
422
+ return EXIT.USAGE;
423
+ }
424
+ return runTituloEleitorCommand(action, input, options, io);
425
+ }
426
+
427
+ // src/commands/nfe-chave.ts
428
+ import {
429
+ NFE_CHAVE_OFFICIAL_SOURCE_URL,
430
+ formatNfeChave,
431
+ parseNfeChave,
432
+ stripNfeChave,
433
+ validateNfeChave
434
+ } from "@br-validators/core";
435
+ function resolveInput7(value, fileContent) {
436
+ const input = value ?? fileContent?.trim();
437
+ if (!input) {
438
+ return null;
439
+ }
440
+ return input;
441
+ }
442
+ function runNfeChaveCommand(action, input, options, io = { stdout: [], stderr: [] }) {
443
+ const source = options.source ? NFE_CHAVE_OFFICIAL_SOURCE_URL : void 0;
444
+ switch (action) {
445
+ case "validate":
446
+ return printValidation(validateNfeChave(input), { json: options.json, quiet: options.quiet, source }, io);
447
+ case "parse":
448
+ return printNfeChaveValidation(parseNfeChave(input), { json: options.json, quiet: options.quiet, source }, io);
449
+ case "format":
450
+ return printFormat(formatNfeChave(input), { json: options.json, quiet: options.quiet }, io);
451
+ case "strip":
452
+ return printStrip(stripNfeChave(input), { json: options.json }, io);
453
+ default: {
454
+ const _exhaustive = action;
455
+ io.stderr.push(`Unknown action: ${_exhaustive}`);
456
+ return EXIT.USAGE;
457
+ }
458
+ }
459
+ }
460
+ function runNfeChave(action, value, options, io = { stdout: [], stderr: [] }) {
461
+ const input = resolveInput7(value, options.file);
462
+ if (input === null) {
463
+ io.stderr.push("Missing NF-e chave de acesso value. Pass an argument or use --file.");
464
+ return EXIT.USAGE;
465
+ }
466
+ return runNfeChaveCommand(action, input, options, io);
467
+ }
468
+
270
469
  // src/commands/cnpj.ts
271
470
  import {
272
471
  CNPJ_OFFICIAL_SOURCE_URL,
@@ -274,7 +473,7 @@ import {
274
473
  stripCnpj,
275
474
  validateCnpj
276
475
  } from "@br-validators/core";
277
- function resolveInput4(value, fileContent) {
476
+ function resolveInput8(value, fileContent) {
278
477
  const input = value ?? fileContent?.trim();
279
478
  if (!input) {
280
479
  return null;
@@ -298,7 +497,7 @@ function runCnpjCommand(action, input, options, io = { stdout: [], stderr: [] })
298
497
  }
299
498
  }
300
499
  function runCnpj(action, value, options, io = { stdout: [], stderr: [] }) {
301
- const input = resolveInput4(value, options.file);
500
+ const input = resolveInput8(value, options.file);
302
501
  if (input === null) {
303
502
  io.stderr.push("Missing CNPJ value. Pass an argument or use --file.");
304
503
  return EXIT.USAGE;
@@ -313,7 +512,7 @@ import {
313
512
  stripCpf,
314
513
  validateCpf
315
514
  } from "@br-validators/core";
316
- function resolveInput5(value, fileContent) {
515
+ function resolveInput9(value, fileContent) {
317
516
  const input = value ?? fileContent?.trim();
318
517
  if (!input) {
319
518
  return null;
@@ -337,7 +536,7 @@ function runCpfCommand(action, input, options, io = { stdout: [], stderr: [] })
337
536
  }
338
537
  }
339
538
  function runCpf(action, value, options, io = { stdout: [], stderr: [] }) {
340
- const input = resolveInput5(value, options.file);
539
+ const input = resolveInput9(value, options.file);
341
540
  if (input === null) {
342
541
  io.stderr.push("Missing CPF value. Pass an argument or use --file.");
343
542
  return EXIT.USAGE;
@@ -353,7 +552,7 @@ import {
353
552
  stripPlaca,
354
553
  validatePlaca
355
554
  } from "@br-validators/core";
356
- function resolveInput6(value, fileContent) {
555
+ function resolveInput10(value, fileContent) {
357
556
  const input = value ?? fileContent?.trim();
358
557
  if (!input) {
359
558
  return null;
@@ -379,7 +578,7 @@ function runPlacaCommand(action, input, options, io = { stdout: [], stderr: [] }
379
578
  }
380
579
  }
381
580
  function runPlaca(action, value, options, io = { stdout: [], stderr: [] }) {
382
- const input = resolveInput6(value, options.file);
581
+ const input = resolveInput10(value, options.file);
383
582
  if (input === null) {
384
583
  io.stderr.push("Missing placa value. Pass an argument or use --file.");
385
584
  return EXIT.USAGE;
@@ -394,7 +593,7 @@ import {
394
593
  stripPisPasep,
395
594
  validatePisPasep
396
595
  } from "@br-validators/core";
397
- function resolveInput7(value, fileContent) {
596
+ function resolveInput11(value, fileContent) {
398
597
  const input = value ?? fileContent?.trim();
399
598
  if (!input) {
400
599
  return null;
@@ -418,7 +617,7 @@ function runPisPasepCommand(action, input, options, io = { stdout: [], stderr: [
418
617
  }
419
618
  }
420
619
  function runPisPasep(action, value, options, io = { stdout: [], stderr: [] }) {
421
- const input = resolveInput7(value, options.file);
620
+ const input = resolveInput11(value, options.file);
422
621
  if (input === null) {
423
622
  io.stderr.push("Missing PIS/PASEP value. Pass an argument or use --file.");
424
623
  return EXIT.USAGE;
@@ -433,7 +632,7 @@ import {
433
632
  formatPixKey,
434
633
  validatePixKey
435
634
  } from "@br-validators/core";
436
- function resolveInput8(value, fileContent) {
635
+ function resolveInput12(value, fileContent) {
437
636
  const input = value ?? fileContent?.trim();
438
637
  if (!input) {
439
638
  return null;
@@ -508,7 +707,7 @@ function runPixCommand(action, input, options, io = { stdout: [], stderr: [] })
508
707
  }
509
708
  }
510
709
  function runPix(action, value, options, io = { stdout: [], stderr: [] }) {
511
- const input = resolveInput8(value, options.file);
710
+ const input = resolveInput12(value, options.file);
512
711
  if (input === null) {
513
712
  io.stderr.push("Missing PIX key value. Pass an argument or use --file.");
514
713
  return EXIT.USAGE;
@@ -527,7 +726,7 @@ import {
527
726
  stripLinhaDigitavel,
528
727
  validateBoleto
529
728
  } from "@br-validators/core";
530
- function resolveInput9(value, fileContent) {
729
+ function resolveInput13(value, fileContent) {
531
730
  const input = value ?? fileContent?.trim();
532
731
  if (!input) {
533
732
  return null;
@@ -651,7 +850,7 @@ function runBoletoCommand(action, input, options, direction, io = { stdout: [],
651
850
  }
652
851
  }
653
852
  function runBoleto(action, value, options, direction, io = { stdout: [], stderr: [] }) {
654
- const input = resolveInput9(value, options.file);
853
+ const input = resolveInput13(value, options.file);
655
854
  if (input === null) {
656
855
  io.stderr.push("Missing boleto value. Pass an argument or use --file.");
657
856
  return EXIT.USAGE;
@@ -667,7 +866,7 @@ import {
667
866
  stripCartaoCredito,
668
867
  validateCartaoCredito
669
868
  } from "@br-validators/core";
670
- function resolveInput10(value, fileContent) {
869
+ function resolveInput14(value, fileContent) {
671
870
  const input = value ?? fileContent?.trim();
672
871
  if (!input) {
673
872
  return null;
@@ -743,7 +942,7 @@ function runCartaoCommand(action, input, options, io = { stdout: [], stderr: []
743
942
  }
744
943
  }
745
944
  function runCartao(action, value, options, io = { stdout: [], stderr: [] }) {
746
- const input = resolveInput10(value, options.file);
945
+ const input = resolveInput14(value, options.file);
747
946
  if (input === null) {
748
947
  io.stderr.push("Missing credit card PAN value. Pass an argument or use --file.");
749
948
  return EXIT.USAGE;
@@ -753,13 +952,18 @@ function runCartao(action, value, options, io = { stdout: [], stderr: [] }) {
753
952
 
754
953
  // src/commands/ie.ts
755
954
  import {
955
+ formatIeProdutorRural,
756
956
  formatInscricaoEstadual,
757
957
  getIeOfficialSourceUrl,
958
+ getIeProdutorRuralOfficialSourceUrl,
758
959
  IE_SUPPORTED_UFS,
960
+ isSpRuralIeInput,
961
+ stripIeSpRural,
759
962
  stripInscricaoEstadual,
963
+ validateIeProdutorRural,
760
964
  validateInscricaoEstadual
761
965
  } from "@br-validators/core";
762
- function resolveInput11(value, fileContent) {
966
+ function resolveInput15(value, fileContent) {
763
967
  const input = value ?? fileContent?.trim();
764
968
  if (!input) {
765
969
  return null;
@@ -776,6 +980,9 @@ function resolveUf(uf) {
776
980
  }
777
981
  return null;
778
982
  }
983
+ function isSpRuralRoute(uf, input) {
984
+ return uf === "SP" && isSpRuralIeInput(input);
985
+ }
779
986
  function printIeValidation(result, options, io = { stdout: [], stderr: [] }) {
780
987
  if (options.json) {
781
988
  io.stdout.push(
@@ -785,6 +992,7 @@ function printIeValidation(result, options, io = { stdout: [], stderr: [] }) {
785
992
  value: result.value,
786
993
  uf: result.uf,
787
994
  format: result.format,
995
+ ...options.rural ? { produtorRural: true } : {},
788
996
  ...options.source ? { source: options.source } : {}
789
997
  } : {
790
998
  ok: false,
@@ -803,6 +1011,9 @@ function printIeValidation(result, options, io = { stdout: [], stderr: [] }) {
803
1011
  }
804
1012
  if (result.ok) {
805
1013
  io.stdout.push(`valid: yes (${result.uf})`);
1014
+ if (options.rural) {
1015
+ io.stdout.push("kind: produtor-rural");
1016
+ }
806
1017
  io.stdout.push(`value: ${result.value}`);
807
1018
  io.stdout.push(`format: ${result.format}`);
808
1019
  if (options.source) {
@@ -824,14 +1035,23 @@ function runIeCommand(action, input, options, io = { stdout: [], stderr: [] }) {
824
1035
  io.stderr.push(`Missing or invalid --uf. Use one of: ${IE_SUPPORTED_UFS.join(", ")}.`);
825
1036
  return EXIT.USAGE;
826
1037
  }
827
- const source = options.source ? getIeOfficialSourceUrl(uf) : void 0;
1038
+ const rural = isSpRuralRoute(uf, input);
1039
+ const source = options.source ? rural ? getIeProdutorRuralOfficialSourceUrl() : getIeOfficialSourceUrl(uf) : void 0;
828
1040
  switch (action) {
829
1041
  case "validate":
830
- return printIeValidation(validateInscricaoEstadual(input, { uf }), { json: options.json, quiet: options.quiet, source }, io);
1042
+ return printIeValidation(
1043
+ rural ? validateIeProdutorRural(uf, input) : validateInscricaoEstadual(input, { uf }),
1044
+ { json: options.json, quiet: options.quiet, source, rural },
1045
+ io
1046
+ );
831
1047
  case "format":
832
- return printFormat(formatInscricaoEstadual(input, { uf }), { json: options.json, quiet: options.quiet }, io);
1048
+ return printFormat(
1049
+ rural ? formatIeProdutorRural(input) : formatInscricaoEstadual(input, { uf }),
1050
+ { json: options.json, quiet: options.quiet },
1051
+ io
1052
+ );
833
1053
  case "strip":
834
- return printStrip(stripInscricaoEstadual(input), { json: options.json }, io);
1054
+ return printStrip(rural ? stripIeSpRural(input) : stripInscricaoEstadual(input), { json: options.json }, io);
835
1055
  default: {
836
1056
  const _exhaustive = action;
837
1057
  io.stderr.push(`Unknown action: ${_exhaustive}`);
@@ -840,7 +1060,7 @@ function runIeCommand(action, input, options, io = { stdout: [], stderr: [] }) {
840
1060
  }
841
1061
  }
842
1062
  function runIe(action, value, options, io = { stdout: [], stderr: [] }) {
843
- const input = resolveInput11(value, options.file);
1063
+ const input = resolveInput15(value, options.file);
844
1064
  if (input === null) {
845
1065
  io.stderr.push("Missing IE value. Pass an argument or use --file.");
846
1066
  return EXIT.USAGE;
@@ -848,6 +1068,163 @@ function runIe(action, value, options, io = { stdout: [], stderr: [] }) {
848
1068
  return runIeCommand(action, input, options, io);
849
1069
  }
850
1070
 
1071
+ // src/commands/detect.ts
1072
+ import { detect } from "@br-validators/core";
1073
+ function resolveInput16(value, fileContent) {
1074
+ const input = value ?? fileContent?.trim();
1075
+ if (!input) {
1076
+ return null;
1077
+ }
1078
+ return input;
1079
+ }
1080
+ function printDetect(result, options, io = { stdout: [], stderr: [] }) {
1081
+ if (options.json) {
1082
+ io.stdout.push(JSON.stringify(result, null, 2));
1083
+ return result.ok ? EXIT.OK : EXIT.INVALID;
1084
+ }
1085
+ if (options.quiet) {
1086
+ return result.ok ? EXIT.OK : EXIT.INVALID;
1087
+ }
1088
+ if (result.ok) {
1089
+ io.stdout.push(`type: ${result.type}`);
1090
+ io.stdout.push("valid: yes");
1091
+ io.stdout.push(`value: ${result.value}`);
1092
+ if (result.format) {
1093
+ io.stdout.push(`format: ${result.format}`);
1094
+ }
1095
+ if (result.meta) {
1096
+ io.stdout.push(`meta: ${JSON.stringify(result.meta)}`);
1097
+ }
1098
+ return EXIT.OK;
1099
+ }
1100
+ io.stderr.push(`type: ${result.type}`);
1101
+ io.stderr.push("valid: no");
1102
+ io.stderr.push(`code: ${result.code}`);
1103
+ io.stderr.push(`message: ${result.message}`);
1104
+ return EXIT.INVALID;
1105
+ }
1106
+ function runDetect(value, options, io = { stdout: [], stderr: [] }) {
1107
+ const input = resolveInput16(value, options.file);
1108
+ if (input === null) {
1109
+ io.stderr.push("Missing value. Pass an argument or use --file.");
1110
+ return EXIT.USAGE;
1111
+ }
1112
+ const uf = options.uf?.toUpperCase();
1113
+ const result = detect(input, uf ? { uf } : {});
1114
+ return printDetect(result, options, io);
1115
+ }
1116
+
1117
+ // src/commands/sanitize.ts
1118
+ import { sanitize } from "@br-validators/core";
1119
+ var SANITIZABLE_TYPES = [
1120
+ "cpf",
1121
+ "cnpj",
1122
+ "cep",
1123
+ "placa",
1124
+ "pis-pasep",
1125
+ "telefone",
1126
+ "cnh",
1127
+ "renavam",
1128
+ "titulo-eleitor",
1129
+ "nfe-chave",
1130
+ "boleto",
1131
+ "cartao-credito",
1132
+ "inscricao-estadual",
1133
+ "inscricao-estadual-produtor-rural"
1134
+ ];
1135
+ function isSanitizableType(type) {
1136
+ return SANITIZABLE_TYPES.includes(type);
1137
+ }
1138
+ function resolveInput17(value, fileContent) {
1139
+ const input = value ?? fileContent?.trim();
1140
+ if (!input) {
1141
+ return null;
1142
+ }
1143
+ return input;
1144
+ }
1145
+ function printSanitize(result, options, io = { stdout: [], stderr: [] }) {
1146
+ if (options.json) {
1147
+ io.stdout.push(JSON.stringify(result, null, 2));
1148
+ return result.ok ? EXIT.OK : EXIT.INVALID;
1149
+ }
1150
+ if (options.quiet) {
1151
+ return result.ok ? EXIT.OK : EXIT.INVALID;
1152
+ }
1153
+ if (result.ok) {
1154
+ io.stdout.push("valid: yes");
1155
+ io.stdout.push(`value: ${result.value}`);
1156
+ io.stdout.push(`fixes: ${result.fixes.join(", ")}`);
1157
+ return EXIT.OK;
1158
+ }
1159
+ io.stderr.push("valid: no");
1160
+ io.stderr.push(`code: ${result.code}`);
1161
+ io.stderr.push(`message: ${result.message}`);
1162
+ return EXIT.INVALID;
1163
+ }
1164
+ function runSanitize(type, value, options, io = { stdout: [], stderr: [] }) {
1165
+ if (!isSanitizableType(type)) {
1166
+ io.stderr.push(`Unsupported sanitize type: ${type}`);
1167
+ return EXIT.USAGE;
1168
+ }
1169
+ const input = resolveInput17(value, options.file);
1170
+ if (input === null) {
1171
+ io.stderr.push("Missing value. Pass an argument or use --file.");
1172
+ return EXIT.USAGE;
1173
+ }
1174
+ const uf = options.uf?.toUpperCase();
1175
+ const result = sanitize(input, type, uf ? { uf } : {});
1176
+ return printSanitize(result, options, io);
1177
+ }
1178
+
1179
+ // src/commands/generate.ts
1180
+ import { generate } from "@br-validators/core";
1181
+ var GENERATABLE_TYPES = [
1182
+ "cpf",
1183
+ "cnpj",
1184
+ "cep",
1185
+ "placa",
1186
+ "pis-pasep",
1187
+ "renavam",
1188
+ "cnh",
1189
+ "telefone",
1190
+ "cartao-credito"
1191
+ ];
1192
+ function isGeneratableType(type) {
1193
+ return GENERATABLE_TYPES.includes(type);
1194
+ }
1195
+ function buildGenerateOptions(options) {
1196
+ const core = {};
1197
+ if (options.masked) {
1198
+ core.masked = true;
1199
+ }
1200
+ if (options.seed !== void 0) {
1201
+ core.seed = options.seed;
1202
+ }
1203
+ if (options.format) {
1204
+ core.format = options.format;
1205
+ }
1206
+ return core;
1207
+ }
1208
+ function printGenerate(value, options, io = { stdout: [], stderr: [] }) {
1209
+ if (options.json) {
1210
+ io.stdout.push(JSON.stringify({ ok: true, value }, null, 2));
1211
+ return EXIT.OK;
1212
+ }
1213
+ if (options.quiet) {
1214
+ return EXIT.OK;
1215
+ }
1216
+ io.stdout.push(value);
1217
+ return EXIT.OK;
1218
+ }
1219
+ function runGenerate(type, options, io = { stdout: [], stderr: [] }) {
1220
+ if (!isGeneratableType(type)) {
1221
+ io.stderr.push(`Unsupported generate type: ${type}`);
1222
+ return EXIT.USAGE;
1223
+ }
1224
+ const value = generate(type, buildGenerateOptions(options));
1225
+ return printGenerate(value, options, io);
1226
+ }
1227
+
851
1228
  // src/commands/list.ts
852
1229
  function listSupportedTypes(io = { stdout: [] }) {
853
1230
  for (const type of SUPPORTED_TYPES) {
@@ -952,6 +1329,27 @@ function handleTelefoneCli(action, value, opts, io = { stdout: [], stderr: [] })
952
1329
  io
953
1330
  );
954
1331
  }
1332
+ function handleCnhCli(action, value, opts, io = { stdout: [], stderr: [] }) {
1333
+ let fileContent;
1334
+ if (opts.file) {
1335
+ const content = readInputFile(opts.file, io);
1336
+ if (content === null) {
1337
+ return EXIT.USAGE;
1338
+ }
1339
+ fileContent = content;
1340
+ }
1341
+ return runCnh(
1342
+ action,
1343
+ value,
1344
+ {
1345
+ json: Boolean(opts.json),
1346
+ quiet: Boolean(opts.quiet),
1347
+ source: Boolean(opts.source),
1348
+ file: fileContent
1349
+ },
1350
+ io
1351
+ );
1352
+ }
955
1353
  function handlePlacaCli(action, value, opts, io = { stdout: [], stderr: [] }) {
956
1354
  let fileContent;
957
1355
  if (opts.file) {
@@ -1081,6 +1479,69 @@ function handleCartaoCreditoCli(action, value, opts, io = { stdout: [], stderr:
1081
1479
  io
1082
1480
  );
1083
1481
  }
1482
+ function handleRenavamCli(action, value, opts, io = { stdout: [], stderr: [] }) {
1483
+ let fileContent;
1484
+ if (opts.file) {
1485
+ const content = readInputFile(opts.file, io);
1486
+ if (content === null) {
1487
+ return EXIT.USAGE;
1488
+ }
1489
+ fileContent = content;
1490
+ }
1491
+ return runRenavam(
1492
+ action,
1493
+ value,
1494
+ {
1495
+ json: Boolean(opts.json),
1496
+ quiet: Boolean(opts.quiet),
1497
+ source: Boolean(opts.source),
1498
+ file: fileContent
1499
+ },
1500
+ io
1501
+ );
1502
+ }
1503
+ function handleTituloEleitorCli(action, value, opts, io = { stdout: [], stderr: [] }) {
1504
+ let fileContent;
1505
+ if (opts.file) {
1506
+ const content = readInputFile(opts.file, io);
1507
+ if (content === null) {
1508
+ return EXIT.USAGE;
1509
+ }
1510
+ fileContent = content;
1511
+ }
1512
+ return runTituloEleitor(
1513
+ action,
1514
+ value,
1515
+ {
1516
+ json: Boolean(opts.json),
1517
+ quiet: Boolean(opts.quiet),
1518
+ source: Boolean(opts.source),
1519
+ file: fileContent
1520
+ },
1521
+ io
1522
+ );
1523
+ }
1524
+ function handleNfeChaveCli(action, value, opts, io = { stdout: [], stderr: [] }) {
1525
+ let fileContent;
1526
+ if (opts.file) {
1527
+ const content = readInputFile(opts.file, io);
1528
+ if (content === null) {
1529
+ return EXIT.USAGE;
1530
+ }
1531
+ fileContent = content;
1532
+ }
1533
+ return runNfeChave(
1534
+ action,
1535
+ value,
1536
+ {
1537
+ json: Boolean(opts.json),
1538
+ quiet: Boolean(opts.quiet),
1539
+ source: Boolean(opts.source),
1540
+ file: fileContent
1541
+ },
1542
+ io
1543
+ );
1544
+ }
1084
1545
  function handleBrCodeCli(action, value, opts, io = { stdout: [], stderr: [] }) {
1085
1546
  let fileContent;
1086
1547
  if (opts.file) {
@@ -1124,6 +1585,60 @@ function handleIeCli(action, value, opts, io = { stdout: [], stderr: [] }) {
1124
1585
  io
1125
1586
  );
1126
1587
  }
1588
+ function handleDetectCli(value, opts, io = { stdout: [], stderr: [] }) {
1589
+ let fileContent;
1590
+ if (opts.file) {
1591
+ const content = readInputFile(opts.file, io);
1592
+ if (content === null) {
1593
+ return EXIT.USAGE;
1594
+ }
1595
+ fileContent = content;
1596
+ }
1597
+ return runDetect(
1598
+ value,
1599
+ {
1600
+ json: Boolean(opts.json),
1601
+ quiet: Boolean(opts.quiet),
1602
+ uf: opts.uf,
1603
+ file: fileContent
1604
+ },
1605
+ io
1606
+ );
1607
+ }
1608
+ function handleSanitizeCli(type, value, opts, io = { stdout: [], stderr: [] }) {
1609
+ let fileContent;
1610
+ if (opts.file) {
1611
+ const content = readInputFile(opts.file, io);
1612
+ if (content === null) {
1613
+ return EXIT.USAGE;
1614
+ }
1615
+ fileContent = content;
1616
+ }
1617
+ return runSanitize(
1618
+ type,
1619
+ value,
1620
+ {
1621
+ json: Boolean(opts.json),
1622
+ quiet: Boolean(opts.quiet),
1623
+ uf: opts.uf,
1624
+ file: fileContent
1625
+ },
1626
+ io
1627
+ );
1628
+ }
1629
+ function handleGenerateCli(type, opts, io = { stdout: [], stderr: [] }) {
1630
+ return runGenerate(
1631
+ type,
1632
+ {
1633
+ json: Boolean(opts.json),
1634
+ quiet: Boolean(opts.quiet),
1635
+ masked: Boolean(opts.masked),
1636
+ format: opts.format,
1637
+ seed: opts.seed
1638
+ },
1639
+ io
1640
+ );
1641
+ }
1127
1642
  function writeCliIo(io) {
1128
1643
  for (const line of io.stdout) console.log(line);
1129
1644
  for (const line of io.stderr) console.error(line);
@@ -1170,6 +1685,38 @@ function createProgram() {
1170
1685
  writeCliIo(io);
1171
1686
  });
1172
1687
  }
1688
+ const cnh = program.command("cnh").description("CNH \u2014 Registro Nacional, 11 contiguous digits (CONTRAN / SENATRAN)");
1689
+ for (const action of ["validate", "format", "strip"]) {
1690
+ cnh.command(action).description(`${action} a CNH`).argument("[value]", "CNH value (11 digits or decorated input)").option("--json", "JSON output").option("-q, --quiet", "Exit code only").option("--source", "Include official source URL (validate only)").option("-f, --file <path>", "Read value from file").action((value, opts) => {
1691
+ const io = { stdout: [], stderr: [] };
1692
+ process.exitCode = handleCnhCli(action, value, opts, io);
1693
+ writeCliIo(io);
1694
+ });
1695
+ }
1696
+ const renavam = program.command("renavam").description("RENAVAM \u2014 11-digit vehicle registry code (DENATRAN / SENATRAN)");
1697
+ for (const action of ["validate", "format", "strip"]) {
1698
+ renavam.command(action).description(`${action} a RENAVAM`).argument("[value]", "RENAVAM value (11 digits or optional dash before DV)").option("--json", "JSON output").option("-q, --quiet", "Exit code only").option("--source", "Include official source URL (validate only)").option("-f, --file <path>", "Read value from file").action((value, opts) => {
1699
+ const io = { stdout: [], stderr: [] };
1700
+ process.exitCode = handleRenavamCli(action, value, opts, io);
1701
+ writeCliIo(io);
1702
+ });
1703
+ }
1704
+ const tituloEleitor = program.command("titulo-eleitor").description("T\xEDtulo de Eleitor \u2014 12-digit voter registration (TSE / Wikipedia PT algorithm)");
1705
+ for (const action of ["validate", "format", "strip"]) {
1706
+ tituloEleitor.command(action).description(`${action} a T\xEDtulo de Eleitor`).argument("[value]", "T\xEDtulo de Eleitor value (12 or 13 digits, spaces allowed)").option("--json", "JSON output").option("-q, --quiet", "Exit code only").option("--source", "Include official source URL (validate only)").option("-f, --file <path>", "Read value from file").action((value, opts) => {
1707
+ const io = { stdout: [], stderr: [] };
1708
+ process.exitCode = handleTituloEleitorCli(action, value, opts, io);
1709
+ writeCliIo(io);
1710
+ });
1711
+ }
1712
+ const nfeChave = program.command("nfe-chave").description("NF-e / NFC-e chave de acesso \u2014 44 digits (SEFAZ MOC \xA72.2.6)");
1713
+ for (const action of ["validate", "parse", "format", "strip"]) {
1714
+ nfeChave.command(action).description(`${action} an NF-e chave de acesso`).argument("[value]", "Chave de acesso (44 digits, spaces allowed)").option("--json", "JSON output").option("-q, --quiet", "Exit code only").option("--source", "Include official source URL (validate/parse only)").option("-f, --file <path>", "Read value from file").action((value, opts) => {
1715
+ const io = { stdout: [], stderr: [] };
1716
+ process.exitCode = handleNfeChaveCli(action, value, opts, io);
1717
+ writeCliIo(io);
1718
+ });
1719
+ }
1173
1720
  const brcode = program.command("brcode").description("BR Code \u2014 PIX QR payload (Bacen EMV TLV)");
1174
1721
  for (const action of ["parse", "validate"]) {
1175
1722
  brcode.command(action).description(`${action} a BR Code payload`).argument("[value]", "BR Code payload (Pix Copia e Cola)").option("--json", "JSON output").option("-q, --quiet", "Exit code only").option("--source", "Include official source URL").option("-f, --file <path>", "Read value from file").action((value, opts) => {
@@ -1265,6 +1812,21 @@ function createProgram() {
1265
1812
  writeCliIo(io);
1266
1813
  });
1267
1814
  }
1815
+ program.command("detect").description("Detect document type from raw input").argument("[value]", "Raw value to classify").option("--uf <uf>", "State code for Inscri\xE7\xE3o Estadual detection").option("--json", "JSON output").option("-q, --quiet", "Exit code only").option("-f, --file <path>", "Read value from file").action((value, opts) => {
1816
+ const io = { stdout: [], stderr: [] };
1817
+ process.exitCode = handleDetectCli(value, opts, io);
1818
+ writeCliIo(io);
1819
+ });
1820
+ program.command("sanitize <type> [value]").description("Sanitize messy input then validate").option("--uf <uf>", "State code (required for inscricao-estadual)").option("--json", "JSON output").option("-q, --quiet", "Exit code only").option("-f, --file <path>", "Read value from file").action((type, value, opts) => {
1821
+ const io = { stdout: [], stderr: [] };
1822
+ process.exitCode = handleSanitizeCli(type, value, opts, io);
1823
+ writeCliIo(io);
1824
+ });
1825
+ program.command("generate <type>").description("Generate synthetic valid test document").option("--json", "JSON output").option("-q, --quiet", "Exit code only").option("--masked", "Return masked/formatted output").option("--format <format>", "Format variant (numeric, alphanumeric, legacy, mercosul, celular, fixo)").option("--seed <number>", "Deterministic PRNG seed", (v) => Number(v)).action((type, opts) => {
1826
+ const io = { stdout: [], stderr: [] };
1827
+ process.exitCode = handleGenerateCli(type, opts, io);
1828
+ writeCliIo(io);
1829
+ });
1268
1830
  return program;
1269
1831
  }
1270
1832
  function run(argv) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@br-validators/cli",
3
- "version": "0.11.0-alpha.0",
3
+ "version": "0.12.0-alpha.0",
4
4
  "description": "Terminal CLI for Brazilian document validation — CPF, CNPJ, CEP, IE, PIX, boleto, and more",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -29,7 +29,7 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "commander": "^13.1.0",
32
- "@br-validators/core": "0.11.0-alpha.0"
32
+ "@br-validators/core": "0.12.0-alpha.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/node": "^22.15.21",