-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest-data.js
135 lines (129 loc) · 3.74 KB
/
test-data.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#! /usr/bin/env node
import chalk from "chalk";
import { Command } from "commander";
import fs from "fs";
import { sep as localPathSeparator } from "path";
import path from "path/posix";
import { getJSONsRecursively } from "./utils/getFilesRecursively.js";
// Define CLI
const program = new Command()
.summary("validate data for Pf2ools")
.description(
"Validates a file or directory of files against the Pf2ools schema. Only JSON files will be tested.",
)
.argument("<paths...>", "File or directory paths to test")
.option("-a, --all", `Test all files ${chalk.dim("(default: break at first validation failure)")}`)
.option("-b, --bundle", "Test data-bundle files rather than data files")
.option(
"-B, --anybundle",
`Test 'any data'-bundle files, a looser superset of data-bundles that aren't valid for the Pf2ools App ${chalk.dim("(note: overrides --bundle)")}`,
)
.option("-e, --error", "Print only the validation status of failing files")
.option("-r, --recurse", "Recursively test files in directories")
.option(
"-s, --summary",
`Suppress printing of validation status for all files and only summarise results ${chalk.dim(
"(note: implies --all)",
)}`,
)
.parse(process.argv);
// Load and validate arguments
const opts = program.opts();
if (opts.summary) opts.all = true;
let files = [];
for (const arg of program.args) {
const argClean = path.join(...arg.toString().split(localPathSeparator));
let filePoint;
try {
filePoint = fs.statSync(argClean);
} catch {
program.error(chalk.red(`"${argClean}" not found`), {
exitCode: 1,
code: "invalid.path",
});
}
if (filePoint.isDirectory()) {
if (opts.recurse) {
files = files.concat(getJSONsRecursively(argClean));
} else {
files = files.concat(
fs
.readdirSync(argClean)
.filter((file) => path.extname(file) === ".json")
.map((file) => path.join(argClean, file)),
);
}
} else if (path.extname(argClean) !== ".json") {
program.error(chalk.red(`"${argClean}" is not a JSON file`), {
exitCode: 1,
code: "invalid.file",
});
} else {
files.push(argClean);
}
}
if (!files.length) {
console.log(chalk.blue("No JSON files to test"));
process.exit();
}
// Set test function
import { data } from "../_dist/zod/_data.js";
import { bundle, anyBundle } from "../_dist/zod/_bundle.js";
let schema;
if (opts.anybundle) schema = anyBundle;
else if (opts.bundle) schema = bundle;
else schema = data;
function validate(schema, test) {
const result = schema.safeParse(test);
if (result.success) return { success: true };
return { success: false, error: result.error.issues };
}
// Validate files
const failed = `\t${chalk.red("[Failed]")} `;
const passed = `\t${chalk.green("[Passed]")} `;
let failCount = 0;
for (const file of files) {
let testJSON;
try {
testJSON = JSON.parse(fs.readFileSync(file, { encoding: "utf8" }));
} catch {
console.error(failed + file);
if (opts.all) {
failCount++;
continue;
} else {
program.error(`"${file}" contains improper JSON syntax`, {
exitCode: 1,
code: "improper.file",
});
}
}
const validationResult = validate(schema, testJSON);
if (validationResult.success) {
if (!opts.error && !opts.summary) console.log(chalk.dim(passed + file));
} else {
console.log(failed + file);
if (!opts.all) throw validationResult.error;
failCount++;
}
}
// Summarise
if (opts.summary || files.length > 1) {
if (failCount === 0) {
console.log(
chalk.green(`All ${chalk.bold(files.length)} file${files.length !== 1 ? "s" : ""} passed validation.`),
);
} else {
program.error(
chalk.red(
`${chalk.bold(failCount)} file${failCount !== 1 ? "s" : ""} (${
Math.round((1000 * failCount) / files.length) / 10
}%) failed validation.`,
),
{
exitCode: 1,
code: "validation.failure",
},
);
}
}