@valbuild/cli 0.14.0 → 0.16.0
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.
@@ -7,7 +7,8 @@ var chalk = require('chalk');
|
|
7
7
|
var express = require('express');
|
8
8
|
var cors = require('cors');
|
9
9
|
var node_http = require('node:http');
|
10
|
-
var
|
10
|
+
var fastGlob = require('fast-glob');
|
11
|
+
var picocolors = require('picocolors');
|
11
12
|
|
12
13
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
13
14
|
|
@@ -16,6 +17,7 @@ var meow__default = /*#__PURE__*/_interopDefault(meow);
|
|
16
17
|
var chalk__default = /*#__PURE__*/_interopDefault(chalk);
|
17
18
|
var express__default = /*#__PURE__*/_interopDefault(express);
|
18
19
|
var cors__default = /*#__PURE__*/_interopDefault(cors);
|
20
|
+
var picocolors__default = /*#__PURE__*/_interopDefault(picocolors);
|
19
21
|
|
20
22
|
function error(...message) {
|
21
23
|
console.error(chalk__default["default"].red(...message));
|
@@ -24,6 +26,68 @@ function info(...message) {
|
|
24
26
|
console.log(...message);
|
25
27
|
}
|
26
28
|
|
29
|
+
async function validate({
|
30
|
+
root,
|
31
|
+
cfg,
|
32
|
+
fix
|
33
|
+
}) {
|
34
|
+
const projectRoot = root ? path__default["default"].resolve(root) : process.cwd();
|
35
|
+
const service = await server.createService(projectRoot, {
|
36
|
+
valConfigPath: cfg ?? "./val.config"
|
37
|
+
});
|
38
|
+
const valFiles = await fastGlob.glob("**/*.val.{js,ts}", {
|
39
|
+
ignore: ["node_modules/**"],
|
40
|
+
cwd: projectRoot
|
41
|
+
});
|
42
|
+
console.log(picocolors__default["default"].green("✔"), "Validating", valFiles.length, "files");
|
43
|
+
async function validateFile(file) {
|
44
|
+
const moduleId = `/${file}`.replace(/(\.val\.(ts|js))$/, ""); // TODO: check if this always works? (Windows?)
|
45
|
+
const start = Date.now();
|
46
|
+
const valModule = await service.get(moduleId, "");
|
47
|
+
if (!valModule.errors) {
|
48
|
+
console.log(picocolors__default["default"].green("✔"), moduleId, "is valid (", Date.now() - start, "ms)");
|
49
|
+
return 0;
|
50
|
+
} else {
|
51
|
+
let errors = 0;
|
52
|
+
if (valModule.errors.validation) for (const [sourcePath, validationErrors] of Object.entries(valModule.errors.validation)) {
|
53
|
+
for (const v of validationErrors) {
|
54
|
+
if (v.fixes && v.fixes.length > 0) {
|
55
|
+
var _fixPatch$remainingEr;
|
56
|
+
const fixPatch = await server.createFixPatch({
|
57
|
+
projectRoot
|
58
|
+
}, !!fix, sourcePath, v);
|
59
|
+
if (fix && fixPatch !== null && fixPatch !== void 0 && fixPatch.patch && (fixPatch === null || fixPatch === void 0 ? void 0 : fixPatch.patch.length) > 0) {
|
60
|
+
await service.patch(moduleId, fixPatch.patch);
|
61
|
+
console.log(picocolors__default["default"].green("✔"), "Applied fix for", sourcePath);
|
62
|
+
}
|
63
|
+
fixPatch === null || fixPatch === void 0 ? void 0 : (_fixPatch$remainingEr = fixPatch.remainingErrors) === null || _fixPatch$remainingEr === void 0 ? void 0 : _fixPatch$remainingEr.forEach(e => {
|
64
|
+
errors += 1;
|
65
|
+
console.log(v.fixes ? picocolors__default["default"].yellow("⚠") : picocolors__default["default"].red("✘"), `Found ${v.fixes ? "fixable " : ""}error in`, `${sourcePath}:`, e.message);
|
66
|
+
});
|
67
|
+
} else {
|
68
|
+
errors += 1;
|
69
|
+
console.log(picocolors__default["default"].red("✘"), "Found error in", `${sourcePath}:`, v.message);
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
73
|
+
for (const fatalError of valModule.errors.fatal || []) {
|
74
|
+
errors += 1;
|
75
|
+
console.log(picocolors__default["default"].red("✘"), moduleId, "is invalid:", fatalError.message);
|
76
|
+
}
|
77
|
+
return errors;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
const errors = (await Promise.all(valFiles.map(validateFile))).reduce((a, b) => a + b, 0);
|
81
|
+
if (errors > 0) {
|
82
|
+
console.log(picocolors__default["default"].red("✘"), "Found", errors, "validation error" + (errors > 1 ? "s" : ""));
|
83
|
+
process.exit(1);
|
84
|
+
} else {
|
85
|
+
console.log(picocolors__default["default"].green("✔"), "No validation errors found");
|
86
|
+
}
|
87
|
+
service.dispose();
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
|
27
91
|
async function serve({
|
28
92
|
root,
|
29
93
|
port,
|
@@ -33,7 +97,7 @@ async function serve({
|
|
33
97
|
const service = await server.createService(projectRoot, {
|
34
98
|
valConfigPath: cfg ?? "./val.config"
|
35
99
|
});
|
36
|
-
const valReqHandler = server.createRequestHandler(new
|
100
|
+
const valReqHandler = server.createRequestHandler(new server.LocalValServer({
|
37
101
|
service
|
38
102
|
}));
|
39
103
|
const app = express__default["default"]();
|
@@ -75,12 +139,14 @@ async function main() {
|
|
75
139
|
$ val [command]
|
76
140
|
Commands
|
77
141
|
serve Run val development server
|
142
|
+
validate val-idate val modules
|
78
143
|
|
79
144
|
Options
|
80
145
|
--help Show this message
|
81
146
|
--port [port], -p [port] Set server port (default 4123)
|
82
147
|
--root [root], -r [root] Set project root directory (default process.cwd())
|
83
148
|
--cfg [cfg], -c [cfg] Set path to config relative to root (default ./val.config)
|
149
|
+
--fix [fix] Attempt to fix validation errors
|
84
150
|
`, {
|
85
151
|
flags: {
|
86
152
|
port: {
|
@@ -95,6 +161,9 @@ async function main() {
|
|
95
161
|
cfg: {
|
96
162
|
type: "string",
|
97
163
|
alias: "c"
|
164
|
+
},
|
165
|
+
fix: {
|
166
|
+
type: "boolean"
|
98
167
|
}
|
99
168
|
},
|
100
169
|
hardRejection: false
|
@@ -113,11 +182,18 @@ async function main() {
|
|
113
182
|
port: flags.port,
|
114
183
|
cfg: flags.cfg
|
115
184
|
});
|
185
|
+
case "validate":
|
186
|
+
case "idate":
|
187
|
+
return validate({
|
188
|
+
root: flags.root,
|
189
|
+
cfg: flags.cfg,
|
190
|
+
fix: flags.fix
|
191
|
+
});
|
116
192
|
default:
|
117
193
|
return error(`Unknown command "${input.join(" ")}"`);
|
118
194
|
}
|
119
195
|
}
|
120
196
|
void main().catch(err => {
|
121
|
-
error(err);
|
197
|
+
error(err instanceof Error ? err.message + "\n" + err.stack : typeof err === "object" ? JSON.stringify(err, null, 2) : err);
|
122
198
|
process.exitCode = 1;
|
123
199
|
});
|
@@ -7,7 +7,8 @@ var chalk = require('chalk');
|
|
7
7
|
var express = require('express');
|
8
8
|
var cors = require('cors');
|
9
9
|
var node_http = require('node:http');
|
10
|
-
var
|
10
|
+
var fastGlob = require('fast-glob');
|
11
|
+
var picocolors = require('picocolors');
|
11
12
|
|
12
13
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
13
14
|
|
@@ -16,6 +17,7 @@ var meow__default = /*#__PURE__*/_interopDefault(meow);
|
|
16
17
|
var chalk__default = /*#__PURE__*/_interopDefault(chalk);
|
17
18
|
var express__default = /*#__PURE__*/_interopDefault(express);
|
18
19
|
var cors__default = /*#__PURE__*/_interopDefault(cors);
|
20
|
+
var picocolors__default = /*#__PURE__*/_interopDefault(picocolors);
|
19
21
|
|
20
22
|
function error(...message) {
|
21
23
|
console.error(chalk__default["default"].red(...message));
|
@@ -24,6 +26,68 @@ function info(...message) {
|
|
24
26
|
console.log(...message);
|
25
27
|
}
|
26
28
|
|
29
|
+
async function validate({
|
30
|
+
root,
|
31
|
+
cfg,
|
32
|
+
fix
|
33
|
+
}) {
|
34
|
+
const projectRoot = root ? path__default["default"].resolve(root) : process.cwd();
|
35
|
+
const service = await server.createService(projectRoot, {
|
36
|
+
valConfigPath: cfg ?? "./val.config"
|
37
|
+
});
|
38
|
+
const valFiles = await fastGlob.glob("**/*.val.{js,ts}", {
|
39
|
+
ignore: ["node_modules/**"],
|
40
|
+
cwd: projectRoot
|
41
|
+
});
|
42
|
+
console.log(picocolors__default["default"].green("✔"), "Validating", valFiles.length, "files");
|
43
|
+
async function validateFile(file) {
|
44
|
+
const moduleId = `/${file}`.replace(/(\.val\.(ts|js))$/, ""); // TODO: check if this always works? (Windows?)
|
45
|
+
const start = Date.now();
|
46
|
+
const valModule = await service.get(moduleId, "");
|
47
|
+
if (!valModule.errors) {
|
48
|
+
console.log(picocolors__default["default"].green("✔"), moduleId, "is valid (", Date.now() - start, "ms)");
|
49
|
+
return 0;
|
50
|
+
} else {
|
51
|
+
let errors = 0;
|
52
|
+
if (valModule.errors.validation) for (const [sourcePath, validationErrors] of Object.entries(valModule.errors.validation)) {
|
53
|
+
for (const v of validationErrors) {
|
54
|
+
if (v.fixes && v.fixes.length > 0) {
|
55
|
+
var _fixPatch$remainingEr;
|
56
|
+
const fixPatch = await server.createFixPatch({
|
57
|
+
projectRoot
|
58
|
+
}, !!fix, sourcePath, v);
|
59
|
+
if (fix && fixPatch !== null && fixPatch !== void 0 && fixPatch.patch && (fixPatch === null || fixPatch === void 0 ? void 0 : fixPatch.patch.length) > 0) {
|
60
|
+
await service.patch(moduleId, fixPatch.patch);
|
61
|
+
console.log(picocolors__default["default"].green("✔"), "Applied fix for", sourcePath);
|
62
|
+
}
|
63
|
+
fixPatch === null || fixPatch === void 0 ? void 0 : (_fixPatch$remainingEr = fixPatch.remainingErrors) === null || _fixPatch$remainingEr === void 0 ? void 0 : _fixPatch$remainingEr.forEach(e => {
|
64
|
+
errors += 1;
|
65
|
+
console.log(v.fixes ? picocolors__default["default"].yellow("⚠") : picocolors__default["default"].red("✘"), `Found ${v.fixes ? "fixable " : ""}error in`, `${sourcePath}:`, e.message);
|
66
|
+
});
|
67
|
+
} else {
|
68
|
+
errors += 1;
|
69
|
+
console.log(picocolors__default["default"].red("✘"), "Found error in", `${sourcePath}:`, v.message);
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
73
|
+
for (const fatalError of valModule.errors.fatal || []) {
|
74
|
+
errors += 1;
|
75
|
+
console.log(picocolors__default["default"].red("✘"), moduleId, "is invalid:", fatalError.message);
|
76
|
+
}
|
77
|
+
return errors;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
const errors = (await Promise.all(valFiles.map(validateFile))).reduce((a, b) => a + b, 0);
|
81
|
+
if (errors > 0) {
|
82
|
+
console.log(picocolors__default["default"].red("✘"), "Found", errors, "validation error" + (errors > 1 ? "s" : ""));
|
83
|
+
process.exit(1);
|
84
|
+
} else {
|
85
|
+
console.log(picocolors__default["default"].green("✔"), "No validation errors found");
|
86
|
+
}
|
87
|
+
service.dispose();
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
|
27
91
|
async function serve({
|
28
92
|
root,
|
29
93
|
port,
|
@@ -33,7 +97,7 @@ async function serve({
|
|
33
97
|
const service = await server.createService(projectRoot, {
|
34
98
|
valConfigPath: cfg ?? "./val.config"
|
35
99
|
});
|
36
|
-
const valReqHandler = server.createRequestHandler(new
|
100
|
+
const valReqHandler = server.createRequestHandler(new server.LocalValServer({
|
37
101
|
service
|
38
102
|
}));
|
39
103
|
const app = express__default["default"]();
|
@@ -75,12 +139,14 @@ async function main() {
|
|
75
139
|
$ val [command]
|
76
140
|
Commands
|
77
141
|
serve Run val development server
|
142
|
+
validate val-idate val modules
|
78
143
|
|
79
144
|
Options
|
80
145
|
--help Show this message
|
81
146
|
--port [port], -p [port] Set server port (default 4123)
|
82
147
|
--root [root], -r [root] Set project root directory (default process.cwd())
|
83
148
|
--cfg [cfg], -c [cfg] Set path to config relative to root (default ./val.config)
|
149
|
+
--fix [fix] Attempt to fix validation errors
|
84
150
|
`, {
|
85
151
|
flags: {
|
86
152
|
port: {
|
@@ -95,6 +161,9 @@ async function main() {
|
|
95
161
|
cfg: {
|
96
162
|
type: "string",
|
97
163
|
alias: "c"
|
164
|
+
},
|
165
|
+
fix: {
|
166
|
+
type: "boolean"
|
98
167
|
}
|
99
168
|
},
|
100
169
|
hardRejection: false
|
@@ -113,11 +182,18 @@ async function main() {
|
|
113
182
|
port: flags.port,
|
114
183
|
cfg: flags.cfg
|
115
184
|
});
|
185
|
+
case "validate":
|
186
|
+
case "idate":
|
187
|
+
return validate({
|
188
|
+
root: flags.root,
|
189
|
+
cfg: flags.cfg,
|
190
|
+
fix: flags.fix
|
191
|
+
});
|
116
192
|
default:
|
117
193
|
return error(`Unknown command "${input.join(" ")}"`);
|
118
194
|
}
|
119
195
|
}
|
120
196
|
void main().catch(err => {
|
121
|
-
error(err);
|
197
|
+
error(err instanceof Error ? err.message + "\n" + err.stack : typeof err === "object" ? JSON.stringify(err, null, 2) : err);
|
122
198
|
process.exitCode = 1;
|
123
199
|
});
|
@@ -1,11 +1,12 @@
|
|
1
1
|
import path from 'path';
|
2
2
|
import meow from 'meow';
|
3
|
-
import { createService, createRequestHandler } from '@valbuild/server';
|
3
|
+
import { createService, createFixPatch, createRequestHandler, LocalValServer } from '@valbuild/server';
|
4
4
|
import chalk from 'chalk';
|
5
5
|
import express from 'express';
|
6
6
|
import cors from 'cors';
|
7
7
|
import { createServer } from 'node:http';
|
8
|
-
import {
|
8
|
+
import { glob } from 'fast-glob';
|
9
|
+
import picocolors from 'picocolors';
|
9
10
|
|
10
11
|
function error(...message) {
|
11
12
|
console.error(chalk.red(...message));
|
@@ -14,6 +15,68 @@ function info(...message) {
|
|
14
15
|
console.log(...message);
|
15
16
|
}
|
16
17
|
|
18
|
+
async function validate({
|
19
|
+
root,
|
20
|
+
cfg,
|
21
|
+
fix
|
22
|
+
}) {
|
23
|
+
const projectRoot = root ? path.resolve(root) : process.cwd();
|
24
|
+
const service = await createService(projectRoot, {
|
25
|
+
valConfigPath: cfg ?? "./val.config"
|
26
|
+
});
|
27
|
+
const valFiles = await glob("**/*.val.{js,ts}", {
|
28
|
+
ignore: ["node_modules/**"],
|
29
|
+
cwd: projectRoot
|
30
|
+
});
|
31
|
+
console.log(picocolors.green("✔"), "Validating", valFiles.length, "files");
|
32
|
+
async function validateFile(file) {
|
33
|
+
const moduleId = `/${file}`.replace(/(\.val\.(ts|js))$/, ""); // TODO: check if this always works? (Windows?)
|
34
|
+
const start = Date.now();
|
35
|
+
const valModule = await service.get(moduleId, "");
|
36
|
+
if (!valModule.errors) {
|
37
|
+
console.log(picocolors.green("✔"), moduleId, "is valid (", Date.now() - start, "ms)");
|
38
|
+
return 0;
|
39
|
+
} else {
|
40
|
+
let errors = 0;
|
41
|
+
if (valModule.errors.validation) for (const [sourcePath, validationErrors] of Object.entries(valModule.errors.validation)) {
|
42
|
+
for (const v of validationErrors) {
|
43
|
+
if (v.fixes && v.fixes.length > 0) {
|
44
|
+
var _fixPatch$remainingEr;
|
45
|
+
const fixPatch = await createFixPatch({
|
46
|
+
projectRoot
|
47
|
+
}, !!fix, sourcePath, v);
|
48
|
+
if (fix && fixPatch !== null && fixPatch !== void 0 && fixPatch.patch && (fixPatch === null || fixPatch === void 0 ? void 0 : fixPatch.patch.length) > 0) {
|
49
|
+
await service.patch(moduleId, fixPatch.patch);
|
50
|
+
console.log(picocolors.green("✔"), "Applied fix for", sourcePath);
|
51
|
+
}
|
52
|
+
fixPatch === null || fixPatch === void 0 ? void 0 : (_fixPatch$remainingEr = fixPatch.remainingErrors) === null || _fixPatch$remainingEr === void 0 ? void 0 : _fixPatch$remainingEr.forEach(e => {
|
53
|
+
errors += 1;
|
54
|
+
console.log(v.fixes ? picocolors.yellow("⚠") : picocolors.red("✘"), `Found ${v.fixes ? "fixable " : ""}error in`, `${sourcePath}:`, e.message);
|
55
|
+
});
|
56
|
+
} else {
|
57
|
+
errors += 1;
|
58
|
+
console.log(picocolors.red("✘"), "Found error in", `${sourcePath}:`, v.message);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
for (const fatalError of valModule.errors.fatal || []) {
|
63
|
+
errors += 1;
|
64
|
+
console.log(picocolors.red("✘"), moduleId, "is invalid:", fatalError.message);
|
65
|
+
}
|
66
|
+
return errors;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
const errors = (await Promise.all(valFiles.map(validateFile))).reduce((a, b) => a + b, 0);
|
70
|
+
if (errors > 0) {
|
71
|
+
console.log(picocolors.red("✘"), "Found", errors, "validation error" + (errors > 1 ? "s" : ""));
|
72
|
+
process.exit(1);
|
73
|
+
} else {
|
74
|
+
console.log(picocolors.green("✔"), "No validation errors found");
|
75
|
+
}
|
76
|
+
service.dispose();
|
77
|
+
return;
|
78
|
+
}
|
79
|
+
|
17
80
|
async function serve({
|
18
81
|
root,
|
19
82
|
port,
|
@@ -65,12 +128,14 @@ async function main() {
|
|
65
128
|
$ val [command]
|
66
129
|
Commands
|
67
130
|
serve Run val development server
|
131
|
+
validate val-idate val modules
|
68
132
|
|
69
133
|
Options
|
70
134
|
--help Show this message
|
71
135
|
--port [port], -p [port] Set server port (default 4123)
|
72
136
|
--root [root], -r [root] Set project root directory (default process.cwd())
|
73
137
|
--cfg [cfg], -c [cfg] Set path to config relative to root (default ./val.config)
|
138
|
+
--fix [fix] Attempt to fix validation errors
|
74
139
|
`, {
|
75
140
|
flags: {
|
76
141
|
port: {
|
@@ -85,6 +150,9 @@ async function main() {
|
|
85
150
|
cfg: {
|
86
151
|
type: "string",
|
87
152
|
alias: "c"
|
153
|
+
},
|
154
|
+
fix: {
|
155
|
+
type: "boolean"
|
88
156
|
}
|
89
157
|
},
|
90
158
|
hardRejection: false
|
@@ -103,11 +171,18 @@ async function main() {
|
|
103
171
|
port: flags.port,
|
104
172
|
cfg: flags.cfg
|
105
173
|
});
|
174
|
+
case "validate":
|
175
|
+
case "idate":
|
176
|
+
return validate({
|
177
|
+
root: flags.root,
|
178
|
+
cfg: flags.cfg,
|
179
|
+
fix: flags.fix
|
180
|
+
});
|
106
181
|
default:
|
107
182
|
return error(`Unknown command "${input.join(" ")}"`);
|
108
183
|
}
|
109
184
|
}
|
110
185
|
void main().catch(err => {
|
111
|
-
error(err);
|
186
|
+
error(err instanceof Error ? err.message + "\n" + err.stack : typeof err === "object" ? JSON.stringify(err, null, 2) : err);
|
112
187
|
process.exitCode = 1;
|
113
188
|
});
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@valbuild/cli",
|
3
3
|
"private": false,
|
4
|
-
"version": "0.
|
4
|
+
"version": "0.16.0",
|
5
5
|
"description": "Val CLI tools",
|
6
6
|
"bin": {
|
7
7
|
"val": "./bin.js"
|
@@ -17,11 +17,13 @@
|
|
17
17
|
"typecheck": "tsc --noEmit"
|
18
18
|
},
|
19
19
|
"dependencies": {
|
20
|
-
"@valbuild/server": "~0.
|
20
|
+
"@valbuild/server": "~0.16.0",
|
21
21
|
"chalk": "^4.1.2",
|
22
22
|
"cors": "^2.8.5",
|
23
23
|
"express": "^4.18.2",
|
24
|
-
"
|
24
|
+
"fast-glob": "^3.3.1",
|
25
|
+
"meow": "^9.0.0",
|
26
|
+
"picocolors": "^1.0.0"
|
25
27
|
},
|
26
28
|
"preconstruct": {
|
27
29
|
"entrypoints": [
|
package/src/cli.ts
CHANGED
@@ -5,7 +5,8 @@ import { error, info } from "./logger";
|
|
5
5
|
import express from "express";
|
6
6
|
import cors from "cors";
|
7
7
|
import { createServer, Server } from "node:http";
|
8
|
-
import { LocalValServer } from "@valbuild/server
|
8
|
+
import { LocalValServer } from "@valbuild/server";
|
9
|
+
import { validate } from "./validate";
|
9
10
|
|
10
11
|
async function serve({
|
11
12
|
root,
|
@@ -68,12 +69,14 @@ async function main(): Promise<void> {
|
|
68
69
|
$ val [command]
|
69
70
|
Commands
|
70
71
|
serve Run val development server
|
72
|
+
validate val-idate val modules
|
71
73
|
|
72
74
|
Options
|
73
75
|
--help Show this message
|
74
76
|
--port [port], -p [port] Set server port (default 4123)
|
75
77
|
--root [root], -r [root] Set project root directory (default process.cwd())
|
76
78
|
--cfg [cfg], -c [cfg] Set path to config relative to root (default ./val.config)
|
79
|
+
--fix [fix] Attempt to fix validation errors
|
77
80
|
`,
|
78
81
|
{
|
79
82
|
flags: {
|
@@ -90,6 +93,9 @@ async function main(): Promise<void> {
|
|
90
93
|
type: "string",
|
91
94
|
alias: "c",
|
92
95
|
},
|
96
|
+
fix: {
|
97
|
+
type: "boolean",
|
98
|
+
},
|
93
99
|
},
|
94
100
|
hardRejection: false,
|
95
101
|
}
|
@@ -111,12 +117,25 @@ async function main(): Promise<void> {
|
|
111
117
|
port: flags.port,
|
112
118
|
cfg: flags.cfg,
|
113
119
|
});
|
120
|
+
case "validate":
|
121
|
+
case "idate":
|
122
|
+
return validate({
|
123
|
+
root: flags.root,
|
124
|
+
cfg: flags.cfg,
|
125
|
+
fix: flags.fix,
|
126
|
+
});
|
114
127
|
default:
|
115
128
|
return error(`Unknown command "${input.join(" ")}"`);
|
116
129
|
}
|
117
130
|
}
|
118
131
|
|
119
132
|
void main().catch((err) => {
|
120
|
-
error(
|
133
|
+
error(
|
134
|
+
err instanceof Error
|
135
|
+
? err.message + "\n" + err.stack
|
136
|
+
: typeof err === "object"
|
137
|
+
? JSON.stringify(err, null, 2)
|
138
|
+
: err
|
139
|
+
);
|
121
140
|
process.exitCode = 1;
|
122
141
|
});
|
package/src/validate.ts
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
import path from "path";
|
2
|
+
import { createFixPatch, createService } from "@valbuild/server";
|
3
|
+
import { ModuleId, ModulePath, SourcePath } from "@valbuild/core";
|
4
|
+
import { glob } from "fast-glob";
|
5
|
+
import picocolors from "picocolors";
|
6
|
+
|
7
|
+
export async function validate({
|
8
|
+
root,
|
9
|
+
cfg,
|
10
|
+
fix,
|
11
|
+
}: {
|
12
|
+
root?: string;
|
13
|
+
cfg?: string;
|
14
|
+
fix?: boolean;
|
15
|
+
}) {
|
16
|
+
const projectRoot = root ? path.resolve(root) : process.cwd();
|
17
|
+
const service = await createService(projectRoot, {
|
18
|
+
valConfigPath: cfg ?? "./val.config",
|
19
|
+
});
|
20
|
+
|
21
|
+
const valFiles: string[] = await glob("**/*.val.{js,ts}", {
|
22
|
+
ignore: ["node_modules/**"],
|
23
|
+
cwd: projectRoot,
|
24
|
+
});
|
25
|
+
console.log(picocolors.green("✔"), "Validating", valFiles.length, "files");
|
26
|
+
|
27
|
+
async function validateFile(file: string): Promise<number> {
|
28
|
+
const moduleId = `/${file}`.replace(/(\.val\.(ts|js))$/, "") as ModuleId; // TODO: check if this always works? (Windows?)
|
29
|
+
const start = Date.now();
|
30
|
+
const valModule = await service.get(moduleId, "" as ModulePath);
|
31
|
+
|
32
|
+
if (!valModule.errors) {
|
33
|
+
console.log(
|
34
|
+
picocolors.green("✔"),
|
35
|
+
moduleId,
|
36
|
+
"is valid (",
|
37
|
+
Date.now() - start,
|
38
|
+
"ms)"
|
39
|
+
);
|
40
|
+
return 0;
|
41
|
+
} else {
|
42
|
+
let errors = 0;
|
43
|
+
if (valModule.errors.validation)
|
44
|
+
for (const [sourcePath, validationErrors] of Object.entries(
|
45
|
+
valModule.errors.validation
|
46
|
+
)) {
|
47
|
+
for (const v of validationErrors) {
|
48
|
+
if (v.fixes && v.fixes.length > 0) {
|
49
|
+
const fixPatch = await createFixPatch(
|
50
|
+
{ projectRoot },
|
51
|
+
!!fix,
|
52
|
+
sourcePath as SourcePath,
|
53
|
+
v
|
54
|
+
);
|
55
|
+
if (fix && fixPatch?.patch && fixPatch?.patch.length > 0) {
|
56
|
+
await service.patch(moduleId, fixPatch.patch);
|
57
|
+
console.log(
|
58
|
+
picocolors.green("✔"),
|
59
|
+
"Applied fix for",
|
60
|
+
sourcePath
|
61
|
+
);
|
62
|
+
}
|
63
|
+
fixPatch?.remainingErrors?.forEach((e) => {
|
64
|
+
errors += 1;
|
65
|
+
console.log(
|
66
|
+
v.fixes ? picocolors.yellow("⚠") : picocolors.red("✘"),
|
67
|
+
`Found ${v.fixes ? "fixable " : ""}error in`,
|
68
|
+
`${sourcePath}:`,
|
69
|
+
e.message
|
70
|
+
);
|
71
|
+
});
|
72
|
+
} else {
|
73
|
+
errors += 1;
|
74
|
+
console.log(
|
75
|
+
picocolors.red("✘"),
|
76
|
+
"Found error in",
|
77
|
+
`${sourcePath}:`,
|
78
|
+
v.message
|
79
|
+
);
|
80
|
+
}
|
81
|
+
}
|
82
|
+
}
|
83
|
+
for (const fatalError of valModule.errors.fatal || []) {
|
84
|
+
errors += 1;
|
85
|
+
console.log(
|
86
|
+
picocolors.red("✘"),
|
87
|
+
moduleId,
|
88
|
+
"is invalid:",
|
89
|
+
fatalError.message
|
90
|
+
);
|
91
|
+
}
|
92
|
+
return errors;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
const errors = (await Promise.all(valFiles.map(validateFile))).reduce(
|
97
|
+
(a, b) => a + b,
|
98
|
+
0
|
99
|
+
);
|
100
|
+
if (errors > 0) {
|
101
|
+
console.log(
|
102
|
+
picocolors.red("✘"),
|
103
|
+
"Found",
|
104
|
+
errors,
|
105
|
+
"validation error" + (errors > 1 ? "s" : "")
|
106
|
+
);
|
107
|
+
process.exit(1);
|
108
|
+
} else {
|
109
|
+
console.log(picocolors.green("✔"), "No validation errors found");
|
110
|
+
}
|
111
|
+
|
112
|
+
service.dispose();
|
113
|
+
return;
|
114
|
+
}
|