check-rule-mate 0.5.3 → 0.5.4
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 +33 -1
- package/bin/verify-templates.js +226 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -58,6 +58,7 @@ This separation makes the system flexible, scalable, and easy to maintain.
|
|
|
58
58
|
- i18n-ready error messages
|
|
59
59
|
- Framework-agnostic (frontend or backend)
|
|
60
60
|
- Auto documentation (automatic generated by a CLI command)
|
|
61
|
+
- Template checker (automatic checked by a CLI command)
|
|
61
62
|
|
|
62
63
|
## Table of Contents
|
|
63
64
|
|
|
@@ -69,6 +70,7 @@ This separation makes the system flexible, scalable, and easy to maintain.
|
|
|
69
70
|
- [Basic Usage](#Basic-Usage)
|
|
70
71
|
- [Lifecycle Hooks](#Lifecycle-Hooks)
|
|
71
72
|
- [Auto documentation](#Auto-Documentation)
|
|
73
|
+
- [Auto Checker for Templates](#Auto-Checker-for-Templates)
|
|
72
74
|
- [Defining Validation](#Defining-Validation)
|
|
73
75
|
- [1. Schema](#Defining-a-Schema-What-to-validate)
|
|
74
76
|
- [2. Rules](#Defining-Rules-How-to-validate)
|
|
@@ -291,11 +293,41 @@ await validator.validate();
|
|
|
291
293
|
To use that it is simple, you only need to run this command:
|
|
292
294
|
|
|
293
295
|
```bash
|
|
294
|
-
npx check-rule-mate-auto-docs --rules rules
|
|
296
|
+
npx check-rule-mate-auto-docs --rules {rules path} --schemas {schemas path} --errors {errors path} --out file.html
|
|
295
297
|
```
|
|
296
298
|
|
|
297
299
|
This will generate a HTML file containing the rules, schemas and errors.
|
|
298
300
|
|
|
301
|
+
### Auto Checker for Templates
|
|
302
|
+
You can **auto check** if your template it is working properly with all necessary properties or have something missing.
|
|
303
|
+
|
|
304
|
+
It is works with: `Schemas`, `Rules` and `Errors`
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
npx check-rule-mate-verify-templates --rules {rules path} --schemas {schemas path} --errors {errors path}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
If everything it is **working properly** this should be your message:
|
|
311
|
+
```bash
|
|
312
|
+
✔ Schemas loaded: 4
|
|
313
|
+
✔ Rules loaded: 6
|
|
314
|
+
✔ Errors loaded: 6
|
|
315
|
+
|
|
316
|
+
✔ No issues found
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Else if some error was found could be something like that:
|
|
320
|
+
```bash
|
|
321
|
+
✔ Schemas loaded: 4
|
|
322
|
+
✔ Rules loaded: 6
|
|
323
|
+
✔ Errors loaded: 6
|
|
324
|
+
|
|
325
|
+
❌ Validation failed
|
|
326
|
+
|
|
327
|
+
❌ Schema "contactUs.json" → field "phone" references rule "cellphone" which does not exist
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
|
|
299
331
|
## Defining Validation
|
|
300
332
|
|
|
301
333
|
### Defining a Schema (What to validate)
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// import fs from 'fs';
|
|
4
|
+
// import path from 'path';
|
|
5
|
+
// import process from 'process';
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const process = require('process');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* ---------------------------
|
|
13
|
+
* Utils
|
|
14
|
+
* ---------------------------
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
function readJSONFilesFromDir(dirPath) {
|
|
18
|
+
if (!fs.existsSync(dirPath)) {
|
|
19
|
+
throw new Error(`Directory not found: ${dirPath}`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const files = fs.readdirSync(dirPath).filter(f => f.endsWith('.json'));
|
|
23
|
+
|
|
24
|
+
const data = {};
|
|
25
|
+
for (const file of files) {
|
|
26
|
+
const fullPath = path.join(dirPath, file);
|
|
27
|
+
const content = JSON.parse(fs.readFileSync(fullPath, 'utf-8'));
|
|
28
|
+
data[file] = content;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return data;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function parseRuleName(ruleName) {
|
|
35
|
+
const [base, modifier] = ruleName.split('--');
|
|
36
|
+
return { base, modifier };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function error(msg) {
|
|
40
|
+
return { type: 'error', message: msg };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function warning(msg) {
|
|
44
|
+
return { type: 'warning', message: msg };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* ---------------------------
|
|
49
|
+
* Core Validators
|
|
50
|
+
* ---------------------------
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
function validateSchemas({ schemas, rules }) {
|
|
54
|
+
const issues = [];
|
|
55
|
+
|
|
56
|
+
for (const [schemaFile, schema] of Object.entries(schemas)) {
|
|
57
|
+
for (const [field, config] of Object.entries(schema)) {
|
|
58
|
+
if (!config.rule) continue;
|
|
59
|
+
|
|
60
|
+
const { base, modifier } = parseRuleName(config.rule);
|
|
61
|
+
|
|
62
|
+
if (!rules[base]) {
|
|
63
|
+
issues.push(
|
|
64
|
+
error(
|
|
65
|
+
`Schema "${schemaFile}" → field "${field}" references rule "${base}" which does not exist`
|
|
66
|
+
)
|
|
67
|
+
);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (modifier) {
|
|
72
|
+
if (!rules[base].modifier || !rules[base].modifier[modifier]) {
|
|
73
|
+
issues.push(
|
|
74
|
+
error(
|
|
75
|
+
`Schema "${schemaFile}" → field "${field}" references modifier "${modifier}" on rule "${base}" which does not exist`
|
|
76
|
+
)
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return issues;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function validateRuleErrors({ rules, errors }) {
|
|
87
|
+
const issues = [];
|
|
88
|
+
|
|
89
|
+
for (const [ruleName, rule] of Object.entries(rules)) {
|
|
90
|
+
const checkErrorMap = (errorMap, context) => {
|
|
91
|
+
if (!errorMap) return;
|
|
92
|
+
|
|
93
|
+
for (const errorKey of Object.values(errorMap)) {
|
|
94
|
+
const [namespace, key] = errorKey.split('.');
|
|
95
|
+
if (!errors[namespace] || !errors[namespace][key]) {
|
|
96
|
+
issues.push(
|
|
97
|
+
error(
|
|
98
|
+
`Rule "${ruleName}"${context} references error key "${errorKey}" which does not exist`
|
|
99
|
+
)
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
checkErrorMap(rule.error, '');
|
|
106
|
+
|
|
107
|
+
if (rule.modifier) {
|
|
108
|
+
for (const [modifierName, modifier] of Object.entries(rule.modifier)) {
|
|
109
|
+
checkErrorMap(modifier.error, ` (modifier "${modifierName}")`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return issues;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function findUnusedErrors({ rules, errors }) {
|
|
118
|
+
const issues = [];
|
|
119
|
+
const usedErrors = new Set();
|
|
120
|
+
|
|
121
|
+
const collectErrors = errorMap => {
|
|
122
|
+
if (!errorMap) return;
|
|
123
|
+
Object.values(errorMap).forEach(e => usedErrors.add(e));
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
for (const rule of Object.values(rules)) {
|
|
127
|
+
collectErrors(rule.error);
|
|
128
|
+
if (rule.modifier) {
|
|
129
|
+
Object.values(rule.modifier).forEach(m => collectErrors(m.error));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
for (const [namespace, keys] of Object.entries(errors)) {
|
|
134
|
+
for (const key of Object.keys(keys)) {
|
|
135
|
+
const fullKey = `${namespace}.${key}`;
|
|
136
|
+
if (!usedErrors.has(fullKey)) {
|
|
137
|
+
issues.push(
|
|
138
|
+
warning(`Unused error message detected: "${fullKey}"`)
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return issues;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* ---------------------------
|
|
149
|
+
* CLI Argument Parsing
|
|
150
|
+
* ---------------------------
|
|
151
|
+
*/
|
|
152
|
+
|
|
153
|
+
function parseArgs() {
|
|
154
|
+
const args = process.argv.slice(2);
|
|
155
|
+
const options = {};
|
|
156
|
+
|
|
157
|
+
for (let i = 0; i < args.length; i++) {
|
|
158
|
+
if (args[i].startsWith('--')) {
|
|
159
|
+
const key = args[i].replace('--', '');
|
|
160
|
+
options[key] = args[i + 1];
|
|
161
|
+
i++;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return options;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* ---------------------------
|
|
170
|
+
* Runner
|
|
171
|
+
* ---------------------------
|
|
172
|
+
*/
|
|
173
|
+
|
|
174
|
+
async function runVerify() {
|
|
175
|
+
try {
|
|
176
|
+
const args = parseArgs();
|
|
177
|
+
|
|
178
|
+
if (!args.schemas || !args.rules || !args.errors) {
|
|
179
|
+
console.error(
|
|
180
|
+
'Usage: check-rule-mate-verify-templates --schemas <path> --rules <path> --errors <path>'
|
|
181
|
+
);
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const schemas = readJSONFilesFromDir(args.schemas);
|
|
186
|
+
const rulesRaw = readJSONFilesFromDir(args.rules);
|
|
187
|
+
const errorsRaw = readJSONFilesFromDir(args.errors);
|
|
188
|
+
|
|
189
|
+
// Merge all rule files into one object
|
|
190
|
+
const rules = Object.assign({}, ...Object.values(rulesRaw));
|
|
191
|
+
const errors = Object.assign({}, ...Object.values(errorsRaw));
|
|
192
|
+
|
|
193
|
+
let issues = [];
|
|
194
|
+
|
|
195
|
+
issues.push(...validateSchemas({ schemas, rules }));
|
|
196
|
+
issues.push(...validateRuleErrors({ rules, errors }));
|
|
197
|
+
issues.push(...findUnusedErrors({ rules, errors }));
|
|
198
|
+
|
|
199
|
+
const hasErrors = issues.some(i => i.type === 'error');
|
|
200
|
+
|
|
201
|
+
console.log('✔ Schemas loaded:', Object.keys(schemas).length);
|
|
202
|
+
console.log('✔ Rules loaded:', Object.keys(rules).length);
|
|
203
|
+
console.log('✔ Errors loaded:', Object.keys(errors).length);
|
|
204
|
+
console.log('');
|
|
205
|
+
|
|
206
|
+
if (issues.length === 0) {
|
|
207
|
+
console.log('✔ No issues found');
|
|
208
|
+
process.exit(0);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
console.log(hasErrors ? '❌ Validation failed' : '⚠️ Validation warnings');
|
|
212
|
+
console.log('');
|
|
213
|
+
|
|
214
|
+
for (const issue of issues) {
|
|
215
|
+
const prefix = issue.type === 'error' ? '❌' : '⚠️';
|
|
216
|
+
console.log(`${prefix} ${issue.message}`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
process.exit(hasErrors ? 1 : 0);
|
|
220
|
+
} catch (err) {
|
|
221
|
+
console.error('Fatal error:', err.message);
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
runVerify();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "check-rule-mate",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./dist/main.cjs.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"check rule mate"
|
|
19
19
|
],
|
|
20
20
|
"bin": {
|
|
21
|
-
"check-rule-mate-auto-docs": "./bin/generate-docs.js"
|
|
21
|
+
"check-rule-mate-auto-docs": "./bin/generate-docs.js",
|
|
22
|
+
"check-rule-mate-verify-templates": "./bin/verify-templates.js"
|
|
22
23
|
},
|
|
23
24
|
"scripts": {
|
|
24
25
|
"start": "node ./examples/vanilla/src/index.js",
|