@br-validators/cli 1.7.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # @br-validators/cli
2
2
 
3
- Terminal CLI for all Brazilian document validators in [@br-validators/core](https://www.npmjs.com/package/@br-validators/core).
3
+ [![npm](https://img.shields.io/npm/v/@br-validators/cli)](https://www.npmjs.com/package/@br-validators/cli)
4
+ [![MIT](https://img.shields.io/badge/license-MIT-blue)](https://github.com/AlexandreZanata/br-validators/blob/main/LICENSE)
5
+ [![GitHub release](https://img.shields.io/github/v/release/AlexandreZanata/br-validators)](https://github.com/AlexandreZanata/br-validators/releases)
6
+
7
+ Terminal CLI for all Brazilian document validators in [@br-validators/core](https://www.npmjs.com/package/@br-validators/core) **v1.8.0**.
4
8
 
5
9
  **Repo:** [github.com/AlexandreZanata/br-validators](https://github.com/AlexandreZanata/br-validators)
6
10
 
package/dist/index.js CHANGED
@@ -1559,6 +1559,86 @@ function runPisPasep(action, value, options, io = { stdout: [], stderr: [] }) {
1559
1559
  return runPisPasepCommand(action, input, options, io);
1560
1560
  }
1561
1561
 
1562
+ // src/commands/cnis.ts
1563
+ import {
1564
+ CNIS_OFFICIAL_VALIDATION_URL,
1565
+ formatNit,
1566
+ stripNit,
1567
+ validateNit
1568
+ } from "@br-validators/core";
1569
+ function resolveInput14(value, fileContent) {
1570
+ const input = value ?? fileContent?.trim();
1571
+ if (!input) {
1572
+ return null;
1573
+ }
1574
+ return input;
1575
+ }
1576
+ function printNitValidation(result, options, io = { stdout: [], stderr: [] }) {
1577
+ if (options.json) {
1578
+ io.stdout.push(
1579
+ JSON.stringify(
1580
+ result.ok ? {
1581
+ ok: true,
1582
+ value: result.value,
1583
+ format: result.format,
1584
+ issuer: result.issuer,
1585
+ tipo: result.tipo,
1586
+ ...options.source ? { source: options.source } : {}
1587
+ } : {
1588
+ ok: false,
1589
+ code: result.code,
1590
+ message: result.message
1591
+ },
1592
+ null,
1593
+ 2
1594
+ )
1595
+ );
1596
+ return result.ok ? EXIT.OK : EXIT.INVALID;
1597
+ }
1598
+ if (options.quiet) {
1599
+ return result.ok ? EXIT.OK : EXIT.INVALID;
1600
+ }
1601
+ if (result.ok) {
1602
+ io.stdout.push(`ok: true`);
1603
+ io.stdout.push(`value: ${result.value}`);
1604
+ io.stdout.push(`issuer: ${result.issuer}`);
1605
+ io.stdout.push(`tipo: ${result.tipo}`);
1606
+ if (options.source) {
1607
+ io.stdout.push(`source: ${options.source}`);
1608
+ }
1609
+ return EXIT.OK;
1610
+ }
1611
+ io.stdout.push(`ok: false`);
1612
+ io.stdout.push(`code: ${result.code}`);
1613
+ io.stdout.push(`message: ${result.message}`);
1614
+ return EXIT.INVALID;
1615
+ }
1616
+ function runCnisCommand(action, input, options, io = { stdout: [], stderr: [] }) {
1617
+ const source = options.source ? CNIS_OFFICIAL_VALIDATION_URL : void 0;
1618
+ const validateOptions = options.issuer !== void 0 || options.tipo !== void 0 ? { issuer: options.issuer, tipo: options.tipo } : void 0;
1619
+ switch (action) {
1620
+ case "validate":
1621
+ return printNitValidation(validateNit(input, validateOptions), { json: options.json, quiet: options.quiet, source }, io);
1622
+ case "format":
1623
+ return printFormat(formatNit(input), { json: options.json, quiet: options.quiet }, io);
1624
+ case "strip":
1625
+ return printStrip(stripNit(input), { json: options.json }, io);
1626
+ default: {
1627
+ const _exhaustive = action;
1628
+ io.stderr.push(`Unknown action: ${_exhaustive}`);
1629
+ return EXIT.USAGE;
1630
+ }
1631
+ }
1632
+ }
1633
+ function runCnis(action, value, options, io = { stdout: [], stderr: [] }) {
1634
+ const input = resolveInput14(value, options.file);
1635
+ if (input === null) {
1636
+ io.stderr.push("Missing NIT value. Pass an argument or use --file.");
1637
+ return EXIT.USAGE;
1638
+ }
1639
+ return runCnisCommand(action, input, options, io);
1640
+ }
1641
+
1562
1642
  // src/commands/pix.ts
1563
1643
  import {
1564
1644
  PIX_OFFICIAL_SOURCE_URL,
@@ -1566,7 +1646,7 @@ import {
1566
1646
  formatPixKey,
1567
1647
  validatePixKey
1568
1648
  } from "@br-validators/core";
1569
- function resolveInput14(value, fileContent) {
1649
+ function resolveInput15(value, fileContent) {
1570
1650
  const input = value ?? fileContent?.trim();
1571
1651
  if (!input) {
1572
1652
  return null;
@@ -1641,7 +1721,7 @@ function runPixCommand(action, input, options, io = { stdout: [], stderr: [] })
1641
1721
  }
1642
1722
  }
1643
1723
  function runPix(action, value, options, io = { stdout: [], stderr: [] }) {
1644
- const input = resolveInput14(value, options.file);
1724
+ const input = resolveInput15(value, options.file);
1645
1725
  if (input === null) {
1646
1726
  io.stderr.push("Missing PIX key value. Pass an argument or use --file.");
1647
1727
  return EXIT.USAGE;
@@ -1660,7 +1740,7 @@ import {
1660
1740
  stripLinhaDigitavel,
1661
1741
  validateBoleto
1662
1742
  } from "@br-validators/core";
1663
- function resolveInput15(value, fileContent) {
1743
+ function resolveInput16(value, fileContent) {
1664
1744
  const input = value ?? fileContent?.trim();
1665
1745
  if (!input) {
1666
1746
  return null;
@@ -1795,7 +1875,7 @@ function runBoletoCommand(action, input, options, direction, io = { stdout: [],
1795
1875
  }
1796
1876
  }
1797
1877
  function runBoleto(action, value, options, direction, io = { stdout: [], stderr: [] }) {
1798
- const input = resolveInput15(value, options.file);
1878
+ const input = resolveInput16(value, options.file);
1799
1879
  if (input === null) {
1800
1880
  io.stderr.push("Missing boleto value. Pass an argument or use --file.");
1801
1881
  return EXIT.USAGE;
@@ -1811,7 +1891,7 @@ import {
1811
1891
  stripCartaoCredito,
1812
1892
  validateCartaoCredito
1813
1893
  } from "@br-validators/core";
1814
- function resolveInput16(value, fileContent) {
1894
+ function resolveInput17(value, fileContent) {
1815
1895
  const input = value ?? fileContent?.trim();
1816
1896
  if (!input) {
1817
1897
  return null;
@@ -1887,7 +1967,7 @@ function runCartaoCommand(action, input, options, io = { stdout: [], stderr: []
1887
1967
  }
1888
1968
  }
1889
1969
  function runCartao(action, value, options, io = { stdout: [], stderr: [] }) {
1890
- const input = resolveInput16(value, options.file);
1970
+ const input = resolveInput17(value, options.file);
1891
1971
  if (input === null) {
1892
1972
  io.stderr.push("Missing credit card PAN value. Pass an argument or use --file.");
1893
1973
  return EXIT.USAGE;
@@ -1895,6 +1975,92 @@ function runCartao(action, value, options, io = { stdout: [], stderr: [] }) {
1895
1975
  return runCartaoCommand(action, input, options, io);
1896
1976
  }
1897
1977
 
1978
+ // src/commands/ean.ts
1979
+ import {
1980
+ EAN_OFFICIAL_SOURCE_URL,
1981
+ detectEanFormat,
1982
+ formatEan,
1983
+ stripEan,
1984
+ validateEan
1985
+ } from "@br-validators/core";
1986
+ function resolveInput18(value, fileContent) {
1987
+ const input = value ?? fileContent?.trim();
1988
+ if (!input) {
1989
+ return null;
1990
+ }
1991
+ return input;
1992
+ }
1993
+ function printEanValidation(result, options, io = { stdout: [], stderr: [] }) {
1994
+ if (options.json) {
1995
+ io.stdout.push(
1996
+ JSON.stringify(
1997
+ result.ok ? {
1998
+ ok: true,
1999
+ value: result.value,
2000
+ format: result.format,
2001
+ ...options.source ? { source: options.source } : {}
2002
+ } : {
2003
+ ok: false,
2004
+ code: result.code,
2005
+ message: result.message
2006
+ },
2007
+ null,
2008
+ 2
2009
+ )
2010
+ );
2011
+ return result.ok ? EXIT.OK : EXIT.INVALID;
2012
+ }
2013
+ if (options.quiet) {
2014
+ return result.ok ? EXIT.OK : EXIT.INVALID;
2015
+ }
2016
+ if (result.ok) {
2017
+ io.stdout.push(`valid: yes (${result.format})`);
2018
+ io.stdout.push(`value: ${result.value}`);
2019
+ if (options.source) {
2020
+ io.stdout.push(`source: ${options.source}`);
2021
+ }
2022
+ return EXIT.OK;
2023
+ }
2024
+ io.stderr.push("valid: no");
2025
+ io.stderr.push(`code: ${result.code}`);
2026
+ io.stderr.push(`message: ${result.message}`);
2027
+ return EXIT.INVALID;
2028
+ }
2029
+ function printEanDetect(format, options, io = { stdout: [] }) {
2030
+ if (options.json) {
2031
+ io.stdout.push(JSON.stringify({ format: format ?? "unknown" }, null, 2));
2032
+ } else if (!options.quiet) {
2033
+ io.stdout.push(format ?? "unknown");
2034
+ }
2035
+ return EXIT.OK;
2036
+ }
2037
+ function runEanCommand(action, input, options, io = { stdout: [], stderr: [] }) {
2038
+ const source = options.source ? EAN_OFFICIAL_SOURCE_URL : void 0;
2039
+ switch (action) {
2040
+ case "validate":
2041
+ return printEanValidation(validateEan(input), { json: options.json, quiet: options.quiet, source }, io);
2042
+ case "detect":
2043
+ return printEanDetect(detectEanFormat(input), { json: options.json, quiet: options.quiet }, io);
2044
+ case "format":
2045
+ return printFormat(formatEan(input), { json: options.json, quiet: options.quiet }, io);
2046
+ case "strip":
2047
+ return printStrip(stripEan(input), { json: options.json }, io);
2048
+ default: {
2049
+ const _exhaustive = action;
2050
+ io.stderr.push(`Unknown action: ${_exhaustive}`);
2051
+ return EXIT.USAGE;
2052
+ }
2053
+ }
2054
+ }
2055
+ function runEan(action, value, options, io = { stdout: [], stderr: [] }) {
2056
+ const input = resolveInput18(value, options.file);
2057
+ if (input === null) {
2058
+ io.stderr.push("Missing EAN value. Pass an argument or use --file.");
2059
+ return EXIT.USAGE;
2060
+ }
2061
+ return runEanCommand(action, input, options, io);
2062
+ }
2063
+
1898
2064
  // src/commands/ie.ts
1899
2065
  import {
1900
2066
  formatIeProdutorRural,
@@ -1908,7 +2074,7 @@ import {
1908
2074
  validateIeProdutorRural,
1909
2075
  validateInscricaoEstadual
1910
2076
  } from "@br-validators/core";
1911
- function resolveInput17(value, fileContent) {
2077
+ function resolveInput19(value, fileContent) {
1912
2078
  const input = value ?? fileContent?.trim();
1913
2079
  if (!input) {
1914
2080
  return null;
@@ -2005,7 +2171,7 @@ function runIeCommand(action, input, options, io = { stdout: [], stderr: [] }) {
2005
2171
  }
2006
2172
  }
2007
2173
  function runIe(action, value, options, io = { stdout: [], stderr: [] }) {
2008
- const input = resolveInput17(value, options.file);
2174
+ const input = resolveInput19(value, options.file);
2009
2175
  if (input === null) {
2010
2176
  io.stderr.push("Missing IE value. Pass an argument or use --file.");
2011
2177
  return EXIT.USAGE;
@@ -2015,7 +2181,7 @@ function runIe(action, value, options, io = { stdout: [], stderr: [] }) {
2015
2181
 
2016
2182
  // src/commands/detect.ts
2017
2183
  import { detect } from "@br-validators/core";
2018
- function resolveInput18(value, fileContent) {
2184
+ function resolveInput20(value, fileContent) {
2019
2185
  const input = value ?? fileContent?.trim();
2020
2186
  if (!input) {
2021
2187
  return null;
@@ -2049,7 +2215,7 @@ function printDetect(result, options, io = { stdout: [], stderr: [] }) {
2049
2215
  return EXIT.INVALID;
2050
2216
  }
2051
2217
  function runDetect(value, options, io = { stdout: [], stderr: [] }) {
2052
- const input = resolveInput18(value, options.file);
2218
+ const input = resolveInput20(value, options.file);
2053
2219
  if (input === null) {
2054
2220
  io.stderr.push("Missing value. Pass an argument or use --file.");
2055
2221
  return EXIT.USAGE;
@@ -2074,13 +2240,14 @@ var SANITIZABLE_TYPES = [
2074
2240
  "nfe-chave",
2075
2241
  "boleto",
2076
2242
  "cartao-credito",
2243
+ "ean",
2077
2244
  "inscricao-estadual",
2078
2245
  "inscricao-estadual-produtor-rural"
2079
2246
  ];
2080
2247
  function isSanitizableType(type) {
2081
2248
  return SANITIZABLE_TYPES.includes(type);
2082
2249
  }
2083
- function resolveInput19(value, fileContent) {
2250
+ function resolveInput21(value, fileContent) {
2084
2251
  const input = value ?? fileContent?.trim();
2085
2252
  if (!input) {
2086
2253
  return null;
@@ -2111,7 +2278,7 @@ function runSanitize(type, value, options, io = { stdout: [], stderr: [] }) {
2111
2278
  io.stderr.push(`Unsupported sanitize type: ${type}`);
2112
2279
  return EXIT.USAGE;
2113
2280
  }
2114
- const input = resolveInput19(value, options.file);
2281
+ const input = resolveInput21(value, options.file);
2115
2282
  if (input === null) {
2116
2283
  io.stderr.push("Missing value. Pass an argument or use --file.");
2117
2284
  return EXIT.USAGE;
@@ -2352,6 +2519,29 @@ function handlePisPasepCli(action, value, opts, io = { stdout: [], stderr: [] })
2352
2519
  io
2353
2520
  );
2354
2521
  }
2522
+ function handleCnisCli(action, value, opts, io = { stdout: [], stderr: [] }) {
2523
+ let fileContent;
2524
+ if (opts.file) {
2525
+ const content = readInputFile(opts.file, io);
2526
+ if (content === null) {
2527
+ return EXIT.USAGE;
2528
+ }
2529
+ fileContent = content;
2530
+ }
2531
+ return runCnis(
2532
+ action,
2533
+ value,
2534
+ {
2535
+ json: Boolean(opts.json),
2536
+ quiet: Boolean(opts.quiet),
2537
+ source: Boolean(opts.source),
2538
+ issuer: opts.issuer,
2539
+ tipo: opts.tipo,
2540
+ file: fileContent
2541
+ },
2542
+ io
2543
+ );
2544
+ }
2355
2545
  function handlePixCli(action, value, opts, io = { stdout: [], stderr: [] }) {
2356
2546
  let fileContent;
2357
2547
  if (opts.file) {
@@ -2439,6 +2629,27 @@ function handleCartaoCreditoCli(action, value, opts, io = { stdout: [], stderr:
2439
2629
  io
2440
2630
  );
2441
2631
  }
2632
+ function handleEanCli(action, value, opts, io = { stdout: [], stderr: [] }) {
2633
+ let fileContent;
2634
+ if (opts.file) {
2635
+ const content = readInputFile(opts.file, io);
2636
+ if (content === null) {
2637
+ return EXIT.USAGE;
2638
+ }
2639
+ fileContent = content;
2640
+ }
2641
+ return runEan(
2642
+ action,
2643
+ value,
2644
+ {
2645
+ json: Boolean(opts.json),
2646
+ quiet: Boolean(opts.quiet),
2647
+ source: Boolean(opts.source),
2648
+ file: fileContent
2649
+ },
2650
+ io
2651
+ );
2652
+ }
2442
2653
  function handleRenavamCli(action, value, opts, io = { stdout: [], stderr: [] }) {
2443
2654
  let fileContent;
2444
2655
  if (opts.file) {
@@ -2849,6 +3060,14 @@ function createProgram() {
2849
3060
  writeCliIo(io);
2850
3061
  });
2851
3062
  }
3063
+ const cnis = program.command("cnis").description("CNIS / NIT \u2014 modulo 11 with issuer metadata (INSS vs Caixa)");
3064
+ for (const action of ["validate", "format", "strip"]) {
3065
+ cnis.command(action).description(`${action} a NIT (CNIS worker ID)`).argument("[value]", "NIT value (raw or masked)").option("--json", "JSON output").option("-q, --quiet", "Exit code only").option("--source", "Include official source URL (validate only)").option("--issuer <issuer>", "Override issuer: inss | caixa").option("--tipo <tipo>", "Override tipo: nit | pis | nis").option("-f, --file <path>", "Read value from file").action((value, opts) => {
3066
+ const io = { stdout: [], stderr: [] };
3067
+ process.exitCode = handleCnisCli(action, value, opts, io);
3068
+ writeCliIo(io);
3069
+ });
3070
+ }
2852
3071
  const pix = program.command("pix").description("PIX key \u2014 CPF, CNPJ, email, phone, EVP (Bacen)");
2853
3072
  pix.command("detect").description("detect PIX key type").argument("[value]", "PIX key value").option("--json", "JSON output").option("-q, --quiet", "Exit code only").option("-f, --file <path>", "Read value from file").action((value, opts) => {
2854
3073
  const io = { stdout: [], stderr: [] };
@@ -2912,6 +3131,19 @@ function createProgram() {
2912
3131
  writeCliIo(io);
2913
3132
  });
2914
3133
  }
3134
+ const ean = program.command("ean").description("GS1 EAN-8 / EAN-13 product barcodes \u2014 modulo-10 weights 1/3");
3135
+ ean.command("detect").description("detect EAN format (ean-8 or ean-13)").argument("[value]", "EAN barcode (raw or masked)").option("--json", "JSON output").option("-q, --quiet", "Exit code only").option("-f, --file <path>", "Read value from file").action((value, opts) => {
3136
+ const io = { stdout: [], stderr: [] };
3137
+ process.exitCode = handleEanCli("detect", value, opts, io);
3138
+ writeCliIo(io);
3139
+ });
3140
+ for (const action of ["validate", "format", "strip"]) {
3141
+ ean.command(action).description(`${action} an EAN barcode`).argument("[value]", "EAN barcode (raw or masked)").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) => {
3142
+ const io = { stdout: [], stderr: [] };
3143
+ process.exitCode = handleEanCli(action, value, opts, io);
3144
+ writeCliIo(io);
3145
+ });
3146
+ }
2915
3147
  const ie = program.command("ie").description("Inscri\xE7\xE3o Estadual \u2014 SP, MT, DF (SEFAZ/SINTEGRA check digits)");
2916
3148
  for (const action of ["validate", "format", "strip"]) {
2917
3149
  ie.command(action).description(`${action} an Inscri\xE7\xE3o Estadual`).argument("[value]", "IE value (raw or masked)").requiredOption("--uf <uf>", "State code (27 UFs, e.g. SP, RJ, MG)").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) => {
@@ -1555,6 +1555,86 @@ function runPisPasep(action, value, options, io = { stdout: [], stderr: [] }) {
1555
1555
  return runPisPasepCommand(action, input, options, io);
1556
1556
  }
1557
1557
 
1558
+ // src/commands/cnis.ts
1559
+ import {
1560
+ CNIS_OFFICIAL_VALIDATION_URL,
1561
+ formatNit,
1562
+ stripNit,
1563
+ validateNit
1564
+ } from "@br-validators/core";
1565
+ function resolveInput14(value, fileContent) {
1566
+ const input = value ?? fileContent?.trim();
1567
+ if (!input) {
1568
+ return null;
1569
+ }
1570
+ return input;
1571
+ }
1572
+ function printNitValidation(result, options, io = { stdout: [], stderr: [] }) {
1573
+ if (options.json) {
1574
+ io.stdout.push(
1575
+ JSON.stringify(
1576
+ result.ok ? {
1577
+ ok: true,
1578
+ value: result.value,
1579
+ format: result.format,
1580
+ issuer: result.issuer,
1581
+ tipo: result.tipo,
1582
+ ...options.source ? { source: options.source } : {}
1583
+ } : {
1584
+ ok: false,
1585
+ code: result.code,
1586
+ message: result.message
1587
+ },
1588
+ null,
1589
+ 2
1590
+ )
1591
+ );
1592
+ return result.ok ? EXIT.OK : EXIT.INVALID;
1593
+ }
1594
+ if (options.quiet) {
1595
+ return result.ok ? EXIT.OK : EXIT.INVALID;
1596
+ }
1597
+ if (result.ok) {
1598
+ io.stdout.push(`ok: true`);
1599
+ io.stdout.push(`value: ${result.value}`);
1600
+ io.stdout.push(`issuer: ${result.issuer}`);
1601
+ io.stdout.push(`tipo: ${result.tipo}`);
1602
+ if (options.source) {
1603
+ io.stdout.push(`source: ${options.source}`);
1604
+ }
1605
+ return EXIT.OK;
1606
+ }
1607
+ io.stdout.push(`ok: false`);
1608
+ io.stdout.push(`code: ${result.code}`);
1609
+ io.stdout.push(`message: ${result.message}`);
1610
+ return EXIT.INVALID;
1611
+ }
1612
+ function runCnisCommand(action, input, options, io = { stdout: [], stderr: [] }) {
1613
+ const source = options.source ? CNIS_OFFICIAL_VALIDATION_URL : void 0;
1614
+ const validateOptions = options.issuer !== void 0 || options.tipo !== void 0 ? { issuer: options.issuer, tipo: options.tipo } : void 0;
1615
+ switch (action) {
1616
+ case "validate":
1617
+ return printNitValidation(validateNit(input, validateOptions), { json: options.json, quiet: options.quiet, source }, io);
1618
+ case "format":
1619
+ return printFormat(formatNit(input), { json: options.json, quiet: options.quiet }, io);
1620
+ case "strip":
1621
+ return printStrip(stripNit(input), { json: options.json }, io);
1622
+ default: {
1623
+ const _exhaustive = action;
1624
+ io.stderr.push(`Unknown action: ${_exhaustive}`);
1625
+ return EXIT.USAGE;
1626
+ }
1627
+ }
1628
+ }
1629
+ function runCnis(action, value, options, io = { stdout: [], stderr: [] }) {
1630
+ const input = resolveInput14(value, options.file);
1631
+ if (input === null) {
1632
+ io.stderr.push("Missing NIT value. Pass an argument or use --file.");
1633
+ return EXIT.USAGE;
1634
+ }
1635
+ return runCnisCommand(action, input, options, io);
1636
+ }
1637
+
1558
1638
  // src/commands/pix.ts
1559
1639
  import {
1560
1640
  PIX_OFFICIAL_SOURCE_URL,
@@ -1562,7 +1642,7 @@ import {
1562
1642
  formatPixKey,
1563
1643
  validatePixKey
1564
1644
  } from "@br-validators/core";
1565
- function resolveInput14(value, fileContent) {
1645
+ function resolveInput15(value, fileContent) {
1566
1646
  const input = value ?? fileContent?.trim();
1567
1647
  if (!input) {
1568
1648
  return null;
@@ -1637,7 +1717,7 @@ function runPixCommand(action, input, options, io = { stdout: [], stderr: [] })
1637
1717
  }
1638
1718
  }
1639
1719
  function runPix(action, value, options, io = { stdout: [], stderr: [] }) {
1640
- const input = resolveInput14(value, options.file);
1720
+ const input = resolveInput15(value, options.file);
1641
1721
  if (input === null) {
1642
1722
  io.stderr.push("Missing PIX key value. Pass an argument or use --file.");
1643
1723
  return EXIT.USAGE;
@@ -1656,7 +1736,7 @@ import {
1656
1736
  stripLinhaDigitavel,
1657
1737
  validateBoleto
1658
1738
  } from "@br-validators/core";
1659
- function resolveInput15(value, fileContent) {
1739
+ function resolveInput16(value, fileContent) {
1660
1740
  const input = value ?? fileContent?.trim();
1661
1741
  if (!input) {
1662
1742
  return null;
@@ -1791,7 +1871,7 @@ function runBoletoCommand(action, input, options, direction, io = { stdout: [],
1791
1871
  }
1792
1872
  }
1793
1873
  function runBoleto(action, value, options, direction, io = { stdout: [], stderr: [] }) {
1794
- const input = resolveInput15(value, options.file);
1874
+ const input = resolveInput16(value, options.file);
1795
1875
  if (input === null) {
1796
1876
  io.stderr.push("Missing boleto value. Pass an argument or use --file.");
1797
1877
  return EXIT.USAGE;
@@ -1807,7 +1887,7 @@ import {
1807
1887
  stripCartaoCredito,
1808
1888
  validateCartaoCredito
1809
1889
  } from "@br-validators/core";
1810
- function resolveInput16(value, fileContent) {
1890
+ function resolveInput17(value, fileContent) {
1811
1891
  const input = value ?? fileContent?.trim();
1812
1892
  if (!input) {
1813
1893
  return null;
@@ -1883,7 +1963,7 @@ function runCartaoCommand(action, input, options, io = { stdout: [], stderr: []
1883
1963
  }
1884
1964
  }
1885
1965
  function runCartao(action, value, options, io = { stdout: [], stderr: [] }) {
1886
- const input = resolveInput16(value, options.file);
1966
+ const input = resolveInput17(value, options.file);
1887
1967
  if (input === null) {
1888
1968
  io.stderr.push("Missing credit card PAN value. Pass an argument or use --file.");
1889
1969
  return EXIT.USAGE;
@@ -1891,6 +1971,92 @@ function runCartao(action, value, options, io = { stdout: [], stderr: [] }) {
1891
1971
  return runCartaoCommand(action, input, options, io);
1892
1972
  }
1893
1973
 
1974
+ // src/commands/ean.ts
1975
+ import {
1976
+ EAN_OFFICIAL_SOURCE_URL,
1977
+ detectEanFormat,
1978
+ formatEan,
1979
+ stripEan,
1980
+ validateEan
1981
+ } from "@br-validators/core";
1982
+ function resolveInput18(value, fileContent) {
1983
+ const input = value ?? fileContent?.trim();
1984
+ if (!input) {
1985
+ return null;
1986
+ }
1987
+ return input;
1988
+ }
1989
+ function printEanValidation(result, options, io = { stdout: [], stderr: [] }) {
1990
+ if (options.json) {
1991
+ io.stdout.push(
1992
+ JSON.stringify(
1993
+ result.ok ? {
1994
+ ok: true,
1995
+ value: result.value,
1996
+ format: result.format,
1997
+ ...options.source ? { source: options.source } : {}
1998
+ } : {
1999
+ ok: false,
2000
+ code: result.code,
2001
+ message: result.message
2002
+ },
2003
+ null,
2004
+ 2
2005
+ )
2006
+ );
2007
+ return result.ok ? EXIT.OK : EXIT.INVALID;
2008
+ }
2009
+ if (options.quiet) {
2010
+ return result.ok ? EXIT.OK : EXIT.INVALID;
2011
+ }
2012
+ if (result.ok) {
2013
+ io.stdout.push(`valid: yes (${result.format})`);
2014
+ io.stdout.push(`value: ${result.value}`);
2015
+ if (options.source) {
2016
+ io.stdout.push(`source: ${options.source}`);
2017
+ }
2018
+ return EXIT.OK;
2019
+ }
2020
+ io.stderr.push("valid: no");
2021
+ io.stderr.push(`code: ${result.code}`);
2022
+ io.stderr.push(`message: ${result.message}`);
2023
+ return EXIT.INVALID;
2024
+ }
2025
+ function printEanDetect(format, options, io = { stdout: [] }) {
2026
+ if (options.json) {
2027
+ io.stdout.push(JSON.stringify({ format: format ?? "unknown" }, null, 2));
2028
+ } else if (!options.quiet) {
2029
+ io.stdout.push(format ?? "unknown");
2030
+ }
2031
+ return EXIT.OK;
2032
+ }
2033
+ function runEanCommand(action, input, options, io = { stdout: [], stderr: [] }) {
2034
+ const source = options.source ? EAN_OFFICIAL_SOURCE_URL : void 0;
2035
+ switch (action) {
2036
+ case "validate":
2037
+ return printEanValidation(validateEan(input), { json: options.json, quiet: options.quiet, source }, io);
2038
+ case "detect":
2039
+ return printEanDetect(detectEanFormat(input), { json: options.json, quiet: options.quiet }, io);
2040
+ case "format":
2041
+ return printFormat(formatEan(input), { json: options.json, quiet: options.quiet }, io);
2042
+ case "strip":
2043
+ return printStrip(stripEan(input), { json: options.json }, io);
2044
+ default: {
2045
+ const _exhaustive = action;
2046
+ io.stderr.push(`Unknown action: ${_exhaustive}`);
2047
+ return EXIT.USAGE;
2048
+ }
2049
+ }
2050
+ }
2051
+ function runEan(action, value, options, io = { stdout: [], stderr: [] }) {
2052
+ const input = resolveInput18(value, options.file);
2053
+ if (input === null) {
2054
+ io.stderr.push("Missing EAN value. Pass an argument or use --file.");
2055
+ return EXIT.USAGE;
2056
+ }
2057
+ return runEanCommand(action, input, options, io);
2058
+ }
2059
+
1894
2060
  // src/commands/ie.ts
1895
2061
  import {
1896
2062
  formatIeProdutorRural,
@@ -1904,7 +2070,7 @@ import {
1904
2070
  validateIeProdutorRural,
1905
2071
  validateInscricaoEstadual
1906
2072
  } from "@br-validators/core";
1907
- function resolveInput17(value, fileContent) {
2073
+ function resolveInput19(value, fileContent) {
1908
2074
  const input = value ?? fileContent?.trim();
1909
2075
  if (!input) {
1910
2076
  return null;
@@ -2001,7 +2167,7 @@ function runIeCommand(action, input, options, io = { stdout: [], stderr: [] }) {
2001
2167
  }
2002
2168
  }
2003
2169
  function runIe(action, value, options, io = { stdout: [], stderr: [] }) {
2004
- const input = resolveInput17(value, options.file);
2170
+ const input = resolveInput19(value, options.file);
2005
2171
  if (input === null) {
2006
2172
  io.stderr.push("Missing IE value. Pass an argument or use --file.");
2007
2173
  return EXIT.USAGE;
@@ -2011,7 +2177,7 @@ function runIe(action, value, options, io = { stdout: [], stderr: [] }) {
2011
2177
 
2012
2178
  // src/commands/detect.ts
2013
2179
  import { detect } from "@br-validators/core";
2014
- function resolveInput18(value, fileContent) {
2180
+ function resolveInput20(value, fileContent) {
2015
2181
  const input = value ?? fileContent?.trim();
2016
2182
  if (!input) {
2017
2183
  return null;
@@ -2045,7 +2211,7 @@ function printDetect(result, options, io = { stdout: [], stderr: [] }) {
2045
2211
  return EXIT.INVALID;
2046
2212
  }
2047
2213
  function runDetect(value, options, io = { stdout: [], stderr: [] }) {
2048
- const input = resolveInput18(value, options.file);
2214
+ const input = resolveInput20(value, options.file);
2049
2215
  if (input === null) {
2050
2216
  io.stderr.push("Missing value. Pass an argument or use --file.");
2051
2217
  return EXIT.USAGE;
@@ -2070,13 +2236,14 @@ var SANITIZABLE_TYPES = [
2070
2236
  "nfe-chave",
2071
2237
  "boleto",
2072
2238
  "cartao-credito",
2239
+ "ean",
2073
2240
  "inscricao-estadual",
2074
2241
  "inscricao-estadual-produtor-rural"
2075
2242
  ];
2076
2243
  function isSanitizableType(type) {
2077
2244
  return SANITIZABLE_TYPES.includes(type);
2078
2245
  }
2079
- function resolveInput19(value, fileContent) {
2246
+ function resolveInput21(value, fileContent) {
2080
2247
  const input = value ?? fileContent?.trim();
2081
2248
  if (!input) {
2082
2249
  return null;
@@ -2107,7 +2274,7 @@ function runSanitize(type, value, options, io = { stdout: [], stderr: [] }) {
2107
2274
  io.stderr.push(`Unsupported sanitize type: ${type}`);
2108
2275
  return EXIT.USAGE;
2109
2276
  }
2110
- const input = resolveInput19(value, options.file);
2277
+ const input = resolveInput21(value, options.file);
2111
2278
  if (input === null) {
2112
2279
  io.stderr.push("Missing value. Pass an argument or use --file.");
2113
2280
  return EXIT.USAGE;
@@ -2348,6 +2515,29 @@ function handlePisPasepCli(action, value, opts, io = { stdout: [], stderr: [] })
2348
2515
  io
2349
2516
  );
2350
2517
  }
2518
+ function handleCnisCli(action, value, opts, io = { stdout: [], stderr: [] }) {
2519
+ let fileContent;
2520
+ if (opts.file) {
2521
+ const content = readInputFile(opts.file, io);
2522
+ if (content === null) {
2523
+ return EXIT.USAGE;
2524
+ }
2525
+ fileContent = content;
2526
+ }
2527
+ return runCnis(
2528
+ action,
2529
+ value,
2530
+ {
2531
+ json: Boolean(opts.json),
2532
+ quiet: Boolean(opts.quiet),
2533
+ source: Boolean(opts.source),
2534
+ issuer: opts.issuer,
2535
+ tipo: opts.tipo,
2536
+ file: fileContent
2537
+ },
2538
+ io
2539
+ );
2540
+ }
2351
2541
  function handlePixCli(action, value, opts, io = { stdout: [], stderr: [] }) {
2352
2542
  let fileContent;
2353
2543
  if (opts.file) {
@@ -2435,6 +2625,27 @@ function handleCartaoCreditoCli(action, value, opts, io = { stdout: [], stderr:
2435
2625
  io
2436
2626
  );
2437
2627
  }
2628
+ function handleEanCli(action, value, opts, io = { stdout: [], stderr: [] }) {
2629
+ let fileContent;
2630
+ if (opts.file) {
2631
+ const content = readInputFile(opts.file, io);
2632
+ if (content === null) {
2633
+ return EXIT.USAGE;
2634
+ }
2635
+ fileContent = content;
2636
+ }
2637
+ return runEan(
2638
+ action,
2639
+ value,
2640
+ {
2641
+ json: Boolean(opts.json),
2642
+ quiet: Boolean(opts.quiet),
2643
+ source: Boolean(opts.source),
2644
+ file: fileContent
2645
+ },
2646
+ io
2647
+ );
2648
+ }
2438
2649
  function handleRenavamCli(action, value, opts, io = { stdout: [], stderr: [] }) {
2439
2650
  let fileContent;
2440
2651
  if (opts.file) {
@@ -2810,7 +3021,7 @@ function dispatchArgv(tokens, io) {
2810
3021
  if (tokens.length === 0 || tokens.includes("--help") || tokens.includes("-h")) {
2811
3022
  io.stdout.push("br-validators \u2014 100% open-source Brazilian document validators");
2812
3023
  io.stdout.push("Usage: br-validators <command> ...");
2813
- 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 pix \xB7 boleto \xB7 cartao \xB7 cartao-credito \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");
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");
2814
3025
  return EXIT.OK;
2815
3026
  }
2816
3027
  if (tokens.includes("--version") || tokens.includes("-V")) {
@@ -2888,6 +3099,8 @@ function dispatchArgv(tokens, io) {
2888
3099
  }
2889
3100
  case "pis-pasep":
2890
3101
  return dispatchStandard(rest, opts, io, handlePisPasepCli);
3102
+ case "cnis":
3103
+ return dispatchStandard(rest, opts, io, handleCnisCli);
2891
3104
  case "pix": {
2892
3105
  const action = rest[0];
2893
3106
  if (!action || !PIX_ACTIONS.includes(action)) {
@@ -2928,6 +3141,14 @@ function dispatchArgv(tokens, io) {
2928
3141
  }
2929
3142
  case "cartao-credito":
2930
3143
  return dispatchStandard(rest, opts, io, handleCartaoCreditoCli);
3144
+ case "ean": {
3145
+ const action = rest[0];
3146
+ if (!action || !["detect", "validate", "format", "strip"].includes(action)) {
3147
+ return usage(io, "Expected action: detect | validate | format | strip");
3148
+ }
3149
+ const value = pickValue(rest);
3150
+ return handleEanCli(action, value, opts, io);
3151
+ }
2931
3152
  case "ie":
2932
3153
  return dispatchStandard(
2933
3154
  rest,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@br-validators/cli",
3
- "version": "1.7.0",
3
+ "version": "1.8.1",
4
4
  "description": "CLI for @br-validators/core — CPF, CNPJ, NF-e, IE, PIX, boleto + detect/sanitize/generate",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "commander": "^13.1.0",
48
- "@br-validators/core": "1.7.0"
48
+ "@br-validators/core": "1.8.1"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/node": "^22.15.21",