@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.
- package/dist/commands/validate.js +73 -23
- package/package.json +1 -1
|
@@ -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 +
|
|
9
|
-
// PDF/A-3) on a ZUGFeRD/XRechnung PDF or raw XML, prints a
|
|
10
|
-
// (
|
|
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
|
|
18
|
+
var _a;
|
|
19
19
|
const file = args.find((a) => !a.startsWith("-"));
|
|
20
20
|
const verbose = args.includes("-v") || args.includes("--verbose");
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
|
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 = (
|
|
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
|
}
|