@valbuild/cli 0.15.0 → 0.17.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,8 +97,9 @@ 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
|
37
|
-
service
|
100
|
+
const valReqHandler = server.createRequestHandler(new server.LocalValServer({
|
101
|
+
service,
|
102
|
+
git: await server.safeReadGit(projectRoot)
|
38
103
|
}));
|
39
104
|
const app = express__default["default"]();
|
40
105
|
// TODO: Properly configure CORS
|
@@ -75,12 +140,14 @@ async function main() {
|
|
75
140
|
$ val [command]
|
76
141
|
Commands
|
77
142
|
serve Run val development server
|
143
|
+
validate val-idate val modules
|
78
144
|
|
79
145
|
Options
|
80
146
|
--help Show this message
|
81
147
|
--port [port], -p [port] Set server port (default 4123)
|
82
148
|
--root [root], -r [root] Set project root directory (default process.cwd())
|
83
149
|
--cfg [cfg], -c [cfg] Set path to config relative to root (default ./val.config)
|
150
|
+
--fix [fix] Attempt to fix validation errors
|
84
151
|
`, {
|
85
152
|
flags: {
|
86
153
|
port: {
|
@@ -95,6 +162,9 @@ async function main() {
|
|
95
162
|
cfg: {
|
96
163
|
type: "string",
|
97
164
|
alias: "c"
|
165
|
+
},
|
166
|
+
fix: {
|
167
|
+
type: "boolean"
|
98
168
|
}
|
99
169
|
},
|
100
170
|
hardRejection: false
|
@@ -113,11 +183,18 @@ async function main() {
|
|
113
183
|
port: flags.port,
|
114
184
|
cfg: flags.cfg
|
115
185
|
});
|
186
|
+
case "validate":
|
187
|
+
case "idate":
|
188
|
+
return validate({
|
189
|
+
root: flags.root,
|
190
|
+
cfg: flags.cfg,
|
191
|
+
fix: flags.fix
|
192
|
+
});
|
116
193
|
default:
|
117
194
|
return error(`Unknown command "${input.join(" ")}"`);
|
118
195
|
}
|
119
196
|
}
|
120
197
|
void main().catch(err => {
|
121
|
-
error(err);
|
198
|
+
error(err instanceof Error ? err.message + "\n" + err.stack : typeof err === "object" ? JSON.stringify(err, null, 2) : err);
|
122
199
|
process.exitCode = 1;
|
123
200
|
});
|
@@ -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,8 +97,9 @@ 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
|
37
|
-
service
|
100
|
+
const valReqHandler = server.createRequestHandler(new server.LocalValServer({
|
101
|
+
service,
|
102
|
+
git: await server.safeReadGit(projectRoot)
|
38
103
|
}));
|
39
104
|
const app = express__default["default"]();
|
40
105
|
// TODO: Properly configure CORS
|
@@ -75,12 +140,14 @@ async function main() {
|
|
75
140
|
$ val [command]
|
76
141
|
Commands
|
77
142
|
serve Run val development server
|
143
|
+
validate val-idate val modules
|
78
144
|
|
79
145
|
Options
|
80
146
|
--help Show this message
|
81
147
|
--port [port], -p [port] Set server port (default 4123)
|
82
148
|
--root [root], -r [root] Set project root directory (default process.cwd())
|
83
149
|
--cfg [cfg], -c [cfg] Set path to config relative to root (default ./val.config)
|
150
|
+
--fix [fix] Attempt to fix validation errors
|
84
151
|
`, {
|
85
152
|
flags: {
|
86
153
|
port: {
|
@@ -95,6 +162,9 @@ async function main() {
|
|
95
162
|
cfg: {
|
96
163
|
type: "string",
|
97
164
|
alias: "c"
|
165
|
+
},
|
166
|
+
fix: {
|
167
|
+
type: "boolean"
|
98
168
|
}
|
99
169
|
},
|
100
170
|
hardRejection: false
|
@@ -113,11 +183,18 @@ async function main() {
|
|
113
183
|
port: flags.port,
|
114
184
|
cfg: flags.cfg
|
115
185
|
});
|
186
|
+
case "validate":
|
187
|
+
case "idate":
|
188
|
+
return validate({
|
189
|
+
root: flags.root,
|
190
|
+
cfg: flags.cfg,
|
191
|
+
fix: flags.fix
|
192
|
+
});
|
116
193
|
default:
|
117
194
|
return error(`Unknown command "${input.join(" ")}"`);
|
118
195
|
}
|
119
196
|
}
|
120
197
|
void main().catch(err => {
|
121
|
-
error(err);
|
198
|
+
error(err instanceof Error ? err.message + "\n" + err.stack : typeof err === "object" ? JSON.stringify(err, null, 2) : err);
|
122
199
|
process.exitCode = 1;
|
123
200
|
});
|
@@ -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, safeReadGit } 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,
|
@@ -24,7 +87,8 @@ async function serve({
|
|
24
87
|
valConfigPath: cfg ?? "./val.config"
|
25
88
|
});
|
26
89
|
const valReqHandler = createRequestHandler(new LocalValServer({
|
27
|
-
service
|
90
|
+
service,
|
91
|
+
git: await safeReadGit(projectRoot)
|
28
92
|
}));
|
29
93
|
const app = express();
|
30
94
|
// TODO: Properly configure CORS
|
@@ -65,12 +129,14 @@ async function main() {
|
|
65
129
|
$ val [command]
|
66
130
|
Commands
|
67
131
|
serve Run val development server
|
132
|
+
validate val-idate val modules
|
68
133
|
|
69
134
|
Options
|
70
135
|
--help Show this message
|
71
136
|
--port [port], -p [port] Set server port (default 4123)
|
72
137
|
--root [root], -r [root] Set project root directory (default process.cwd())
|
73
138
|
--cfg [cfg], -c [cfg] Set path to config relative to root (default ./val.config)
|
139
|
+
--fix [fix] Attempt to fix validation errors
|
74
140
|
`, {
|
75
141
|
flags: {
|
76
142
|
port: {
|
@@ -85,6 +151,9 @@ async function main() {
|
|
85
151
|
cfg: {
|
86
152
|
type: "string",
|
87
153
|
alias: "c"
|
154
|
+
},
|
155
|
+
fix: {
|
156
|
+
type: "boolean"
|
88
157
|
}
|
89
158
|
},
|
90
159
|
hardRejection: false
|
@@ -103,11 +172,18 @@ async function main() {
|
|
103
172
|
port: flags.port,
|
104
173
|
cfg: flags.cfg
|
105
174
|
});
|
175
|
+
case "validate":
|
176
|
+
case "idate":
|
177
|
+
return validate({
|
178
|
+
root: flags.root,
|
179
|
+
cfg: flags.cfg,
|
180
|
+
fix: flags.fix
|
181
|
+
});
|
106
182
|
default:
|
107
183
|
return error(`Unknown command "${input.join(" ")}"`);
|
108
184
|
}
|
109
185
|
}
|
110
186
|
void main().catch(err => {
|
111
|
-
error(err);
|
187
|
+
error(err instanceof Error ? err.message + "\n" + err.stack : typeof err === "object" ? JSON.stringify(err, null, 2) : err);
|
112
188
|
process.exitCode = 1;
|
113
189
|
});
|
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.17.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.17.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
@@ -1,11 +1,16 @@
|
|
1
1
|
import path from "path";
|
2
2
|
import meow from "meow";
|
3
|
-
import {
|
3
|
+
import {
|
4
|
+
createRequestHandler,
|
5
|
+
createService,
|
6
|
+
safeReadGit,
|
7
|
+
} from "@valbuild/server";
|
4
8
|
import { error, info } from "./logger";
|
5
9
|
import express from "express";
|
6
10
|
import cors from "cors";
|
7
11
|
import { createServer, Server } from "node:http";
|
8
|
-
import { LocalValServer } from "@valbuild/server
|
12
|
+
import { LocalValServer } from "@valbuild/server";
|
13
|
+
import { validate } from "./validate";
|
9
14
|
|
10
15
|
async function serve({
|
11
16
|
root,
|
@@ -23,6 +28,7 @@ async function serve({
|
|
23
28
|
const valReqHandler = createRequestHandler(
|
24
29
|
new LocalValServer({
|
25
30
|
service,
|
31
|
+
git: await safeReadGit(projectRoot),
|
26
32
|
})
|
27
33
|
);
|
28
34
|
const app = express();
|
@@ -68,12 +74,14 @@ async function main(): Promise<void> {
|
|
68
74
|
$ val [command]
|
69
75
|
Commands
|
70
76
|
serve Run val development server
|
77
|
+
validate val-idate val modules
|
71
78
|
|
72
79
|
Options
|
73
80
|
--help Show this message
|
74
81
|
--port [port], -p [port] Set server port (default 4123)
|
75
82
|
--root [root], -r [root] Set project root directory (default process.cwd())
|
76
83
|
--cfg [cfg], -c [cfg] Set path to config relative to root (default ./val.config)
|
84
|
+
--fix [fix] Attempt to fix validation errors
|
77
85
|
`,
|
78
86
|
{
|
79
87
|
flags: {
|
@@ -90,6 +98,9 @@ async function main(): Promise<void> {
|
|
90
98
|
type: "string",
|
91
99
|
alias: "c",
|
92
100
|
},
|
101
|
+
fix: {
|
102
|
+
type: "boolean",
|
103
|
+
},
|
93
104
|
},
|
94
105
|
hardRejection: false,
|
95
106
|
}
|
@@ -111,12 +122,25 @@ async function main(): Promise<void> {
|
|
111
122
|
port: flags.port,
|
112
123
|
cfg: flags.cfg,
|
113
124
|
});
|
125
|
+
case "validate":
|
126
|
+
case "idate":
|
127
|
+
return validate({
|
128
|
+
root: flags.root,
|
129
|
+
cfg: flags.cfg,
|
130
|
+
fix: flags.fix,
|
131
|
+
});
|
114
132
|
default:
|
115
133
|
return error(`Unknown command "${input.join(" ")}"`);
|
116
134
|
}
|
117
135
|
}
|
118
136
|
|
119
137
|
void main().catch((err) => {
|
120
|
-
error(
|
138
|
+
error(
|
139
|
+
err instanceof Error
|
140
|
+
? err.message + "\n" + err.stack
|
141
|
+
: typeof err === "object"
|
142
|
+
? JSON.stringify(err, null, 2)
|
143
|
+
: err
|
144
|
+
);
|
121
145
|
process.exitCode = 1;
|
122
146
|
});
|
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
|
+
}
|