@jasy/cli 1.0.0-alpha.1 → 1.0.0-alpha.2

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.
@@ -5,9 +5,9 @@ import { describeInvoice } from "../core/detect.js";
5
5
  import { validateInvoiceXml, profileFor } from "../core/validate.js";
6
6
  import { checkPdfA3 } from "../core/pdfa.js";
7
7
  import { findVerapdf, runVeraPdf } from "../core/verapdf.js";
8
- // `jasy validate <file> [-v]` - runs the full local check (EN 16931 business rules + structural
9
- // PDF/A-3) on a ZUGFeRD/XRechnung PDF or raw XML, prints a report, and exits non-zero when invalid
10
- // (so it slots into scripts/CI). Same UI-agnostic core as the TUI.
8
+ // `jasy validate <file> [--json] [-v]` - runs the full local check (EN 16931 business rules +
9
+ // structural PDF/A-3, plus veraPDF when installed) on a ZUGFeRD/XRechnung PDF or raw XML, prints a
10
+ // report (or `--json` for scripts/CI/services), and exits non-zero when invalid. Same core as the TUI.
11
11
  const tty = process.stdout.isTTY;
12
12
  const paint = (code, s) => (tty ? `\x1b[${code}m${s}\x1b[0m` : s);
13
13
  const green = (s) => paint("32", s);
@@ -15,12 +15,19 @@ const red = (s) => paint("31", s);
15
15
  const dim = (s) => paint("2", s);
16
16
  const bold = (s) => paint("1", s);
17
17
  export function validateCommand(args) {
18
- var _a, _b;
18
+ var _a;
19
19
  const file = args.find((a) => !a.startsWith("-"));
20
20
  const verbose = args.includes("-v") || args.includes("--verbose");
21
- if (!file) {
22
- console.error("usage: jasy validate <file.pdf|file.xml> [-v]");
21
+ const json = args.includes("--json");
22
+ const fail = (msg) => {
23
+ if (json)
24
+ console.log(JSON.stringify({ error: msg }));
25
+ else
26
+ console.error(red(`✗ ${msg}`));
23
27
  process.exitCode = 1;
28
+ };
29
+ if (!file) {
30
+ fail("usage: jasy validate <file.pdf|file.xml> [--json] [-v]");
24
31
  return;
25
32
  }
26
33
  const base = (_a = process.env.INIT_CWD) !== null && _a !== void 0 ? _a : process.cwd();
@@ -29,8 +36,7 @@ export function validateCommand(args) {
29
36
  bytes = readFileSync(resolve(base, file));
30
37
  }
31
38
  catch (e) {
32
- console.error(red(`✗ could not read ${file}: ${e.message}`));
33
- process.exitCode = 1;
39
+ fail(`could not read ${file}: ${e.message}`);
34
40
  return;
35
41
  }
36
42
  const read = readInvoice(bytes);
@@ -41,11 +47,67 @@ export function validateCommand(args) {
41
47
  try {
42
48
  rules = validateInvoiceXml(read.xml, profileFor(read.meta));
43
49
  }
44
- catch (_c) {
50
+ catch (_b) {
45
51
  rules = null;
46
52
  }
47
53
  }
48
54
  const pdfa = read.isPdf ? checkPdfA3(bytes) : null;
55
+ // Full ISO 19005 (PDF/A) via veraPDF - only when installed; never blocks, just adds the official seal.
56
+ let vera = null;
57
+ if (read.isPdf && findVerapdf()) {
58
+ try {
59
+ vera = runVeraPdf(resolve(base, file));
60
+ }
61
+ catch (_c) {
62
+ vera = null;
63
+ }
64
+ }
65
+ const ok = (!rules || rules.valid) && (!pdfa || pdfa.ok) && (!vera || vera.ok);
66
+ if (!ok)
67
+ process.exitCode = 1;
68
+ if (json) {
69
+ console.log(JSON.stringify(toJson(file, read, rules, pdfa, vera, ok)));
70
+ return;
71
+ }
72
+ printReport(file, read, rules, pdfa, vera, ok, verbose);
73
+ }
74
+ /** The machine-readable report (`--json`): the exact same data the printed report shows. */
75
+ function toJson(file, read, rules, pdfa, vera, ok) {
76
+ var _a;
77
+ return {
78
+ file: basename(file),
79
+ summary: describeInvoice(read.meta),
80
+ valid: ok,
81
+ businessRules: rules && {
82
+ kind: rules.profile.startsWith("xrechnung") ? "XRechnung" : "EN 16931",
83
+ profile: rules.profile,
84
+ valid: rules.valid,
85
+ errors: rules.errors,
86
+ warnings: rules.warnings,
87
+ },
88
+ pdfA3: pdfa && {
89
+ valid: pdfa.ok,
90
+ passed: pdfa.checks.filter((c) => c.ok).length,
91
+ total: pdfa.checks.length,
92
+ checks: pdfa.checks,
93
+ },
94
+ // null when it isn't a PDF; { available: false } when it is but veraPDF isn't installed.
95
+ veraPdf: read.isPdf
96
+ ? vera
97
+ ? {
98
+ available: true,
99
+ valid: vera.ok,
100
+ profile: vera.profile,
101
+ failedRules: (_a = vera.failedRules) !== null && _a !== void 0 ? _a : vera.failures.length,
102
+ failures: vera.failures,
103
+ }
104
+ : { available: false }
105
+ : null,
106
+ };
107
+ }
108
+ /** The human-readable report (default): a coloured summary line + per-check detail. */
109
+ function printReport(file, read, rules, pdfa, vera, ok, verbose) {
110
+ var _a;
49
111
  const label = (s) => s.padEnd(20);
50
112
  console.log(`\n ${bold(basename(file))} ${dim("·")} ${describeInvoice(read.meta)}\n`);
51
113
  // business rules
@@ -75,18 +137,9 @@ export function validateCommand(args) {
75
137
  else {
76
138
  console.log(` ${label("PDF/A-3 structure")}${dim("n/a (raw XML)")}`);
77
139
  }
78
- // full ISO 19005 (PDF/A) via veraPDF - only when installed; never blocks, just adds the official seal
79
- let vera = null;
80
- if (read.isPdf && findVerapdf()) {
81
- try {
82
- vera = runVeraPdf(resolve(base, file));
83
- }
84
- catch (_d) {
85
- vera = null;
86
- }
87
- }
140
+ // full ISO 19005 (PDF/A) via veraPDF
88
141
  if (vera) {
89
- const n = (_b = vera.failedRules) !== null && _b !== void 0 ? _b : vera.failures.length;
142
+ const n = (_a = vera.failedRules) !== null && _a !== void 0 ? _a : vera.failures.length;
90
143
  console.log(` ${label("PDF/A (veraPDF)")}${vera.ok ? green("✓ compliant") : red(`✗ ${n} failed`)}`);
91
144
  if (!vera.ok)
92
145
  for (const f of vera.failures)
@@ -95,8 +148,5 @@ export function validateCommand(args) {
95
148
  else if (read.isPdf) {
96
149
  console.log(` ${label("PDF/A (veraPDF)")}${dim("n/a - `jasy verapdf --install` for the full ISO check")}`);
97
150
  }
98
- const ok = (!rules || rules.valid) && (!pdfa || pdfa.ok) && (!vera || vera.ok);
99
151
  console.log(`\n → ${ok ? green(bold("VALID")) : red(bold("INVALID"))}\n`);
100
- if (!ok)
101
- process.exitCode = 1;
102
152
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jasy/cli",
3
- "version": "1.0.0-alpha.1",
3
+ "version": "1.0.0-alpha.2",
4
4
  "description": "Interactive terminal to validate, read and export ZUGFeRD / XRechnung e-invoices.",
5
5
  "keywords": [
6
6
  "cli",