@valbuild/cli 0.46.0 → 0.47.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.
- package/cli/dist/valbuild-cli-cli.cjs.dev.js +63 -24
- package/cli/dist/valbuild-cli-cli.cjs.prod.js +63 -24
- package/cli/dist/valbuild-cli-cli.esm.js +62 -24
- package/package.json +4 -2
- package/src/validate.ts +108 -45
@@ -6,6 +6,8 @@ var path = require('path');
|
|
6
6
|
var server = require('@valbuild/server');
|
7
7
|
var fastGlob = require('fast-glob');
|
8
8
|
var picocolors = require('picocolors');
|
9
|
+
var eslint = require('eslint');
|
10
|
+
var fs = require('fs/promises');
|
9
11
|
|
10
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
11
13
|
|
@@ -13,6 +15,7 @@ var meow__default = /*#__PURE__*/_interopDefault(meow);
|
|
13
15
|
var chalk__default = /*#__PURE__*/_interopDefault(chalk);
|
14
16
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
15
17
|
var picocolors__default = /*#__PURE__*/_interopDefault(picocolors);
|
18
|
+
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
16
19
|
|
17
20
|
function error(...message) {
|
18
21
|
console.error(chalk__default["default"].red(...message));
|
@@ -24,6 +27,11 @@ async function validate({
|
|
24
27
|
fix
|
25
28
|
}) {
|
26
29
|
const projectRoot = root ? path__default["default"].resolve(root) : process.cwd();
|
30
|
+
const eslint$1 = new eslint.ESLint({
|
31
|
+
cwd: projectRoot,
|
32
|
+
ignore: false,
|
33
|
+
useEslintrc: true
|
34
|
+
});
|
27
35
|
const service = await server.createService(projectRoot, {
|
28
36
|
valConfigPath: cfg ?? "./val.config"
|
29
37
|
});
|
@@ -32,44 +40,75 @@ async function validate({
|
|
32
40
|
cwd: projectRoot
|
33
41
|
});
|
34
42
|
console.log(picocolors__default["default"].green("✔"), "Validating", valFiles.length, "files");
|
43
|
+
const eslintResults = await eslint$1.lintFiles(valFiles);
|
44
|
+
const eslintResultsByFile = eslintResults.reduce((acc, result) => ({
|
45
|
+
...acc,
|
46
|
+
[result.filePath.replaceAll(`${projectRoot}/`, "")]: result
|
47
|
+
}), {});
|
35
48
|
async function validateFile(file) {
|
36
49
|
const moduleId = `/${file}`.replace(/(\.val\.(ts|js))$/, ""); // TODO: check if this always works? (Windows?)
|
37
50
|
const start = Date.now();
|
38
51
|
const valModule = await service.get(moduleId, "");
|
39
|
-
|
52
|
+
const fileContent = await fs__default["default"].readFile(path__default["default"].join(projectRoot, file), "utf-8");
|
53
|
+
const eslintResult = eslintResultsByFile === null || eslintResultsByFile === void 0 ? void 0 : eslintResultsByFile[file];
|
54
|
+
eslintResult === null || eslintResult === void 0 || eslintResult.messages.forEach(m => {
|
55
|
+
// display surrounding code
|
56
|
+
const lines = fileContent.split("\n");
|
57
|
+
const line = lines[m.line - 1];
|
58
|
+
const lineBefore = lines[m.line - 2];
|
59
|
+
const lineAfter = lines[m.line];
|
60
|
+
const isError = m.severity >= 2;
|
61
|
+
console.log(isError ? picocolors__default["default"].red("✘") : picocolors__default["default"].yellow("⚠"), isError ? "Found eslint error:" : "Found eslint warning:", `${moduleId}:${m.line}:${m.column}\n`, m.message);
|
62
|
+
lineBefore && console.log(picocolors__default["default"].gray(" " + (m.line - 1) + " |"), lineBefore);
|
63
|
+
line && console.log(picocolors__default["default"].gray(" " + m.line + " |"), line);
|
64
|
+
// adds ^ below the relevant line:
|
65
|
+
line && console.log(picocolors__default["default"].gray(" " + " ".repeat(m.line.toString().length) + " |"), " ".repeat(m.column - 1) + (m.endColumn ? (isError ? picocolors__default["default"].red("^") : picocolors__default["default"].yellow("^")).repeat(m.endColumn - m.column - 1) : ""));
|
66
|
+
lineAfter && console.log(picocolors__default["default"].gray(" " + (m.line + 1) + " |"), lineAfter);
|
67
|
+
});
|
68
|
+
if (!valModule.errors && (eslintResult === null || eslintResult === void 0 ? void 0 : eslintResult.errorCount) === 0) {
|
40
69
|
console.log(picocolors__default["default"].green("✔"), moduleId, "is valid (", Date.now() - start, "ms)");
|
41
70
|
return 0;
|
42
71
|
} else {
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
const
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
72
|
+
var _eslintResultsByFile$;
|
73
|
+
let errors = (eslintResultsByFile === null || eslintResultsByFile === void 0 || (_eslintResultsByFile$ = eslintResultsByFile[file]) === null || _eslintResultsByFile$ === void 0 ? void 0 : _eslintResultsByFile$.messages.reduce((prev, m) => m.severity >= 2 ? prev + 1 : prev, 0)) || 0;
|
74
|
+
if (valModule.errors) {
|
75
|
+
if (valModule.errors.validation) {
|
76
|
+
for (const [sourcePath, validationErrors] of Object.entries(valModule.errors.validation)) {
|
77
|
+
for (const v of validationErrors) {
|
78
|
+
if (v.fixes && v.fixes.length > 0) {
|
79
|
+
var _fixPatch$remainingEr;
|
80
|
+
const fixPatch = await server.createFixPatch({
|
81
|
+
projectRoot
|
82
|
+
}, !!fix, sourcePath, v);
|
83
|
+
if (fix && fixPatch !== null && fixPatch !== void 0 && fixPatch.patch && (fixPatch === null || fixPatch === void 0 ? void 0 : fixPatch.patch.length) > 0) {
|
84
|
+
await service.patch(moduleId, fixPatch.patch);
|
85
|
+
console.log(picocolors__default["default"].green("✔"), "Applied fix for", sourcePath);
|
86
|
+
}
|
87
|
+
fixPatch === null || fixPatch === void 0 || (_fixPatch$remainingEr = fixPatch.remainingErrors) === null || _fixPatch$remainingEr === void 0 || _fixPatch$remainingEr.forEach(e => {
|
88
|
+
errors += 1;
|
89
|
+
console.log(v.fixes ? picocolors__default["default"].yellow("⚠") : picocolors__default["default"].red("✘"), `Found ${v.fixes ? "fixable " : ""}error in`, `${sourcePath}:`, e.message);
|
90
|
+
});
|
91
|
+
} else {
|
92
|
+
errors += 1;
|
93
|
+
console.log(picocolors__default["default"].red("✘"), "Found error in", `${sourcePath}:`, v.message);
|
94
|
+
}
|
54
95
|
}
|
55
|
-
fixPatch === null || fixPatch === void 0 || (_fixPatch$remainingEr = fixPatch.remainingErrors) === null || _fixPatch$remainingEr === void 0 || _fixPatch$remainingEr.forEach(e => {
|
56
|
-
errors += 1;
|
57
|
-
console.log(v.fixes ? picocolors__default["default"].yellow("⚠") : picocolors__default["default"].red("✘"), `Found ${v.fixes ? "fixable " : ""}error in`, `${sourcePath}:`, e.message);
|
58
|
-
});
|
59
|
-
} else {
|
60
|
-
errors += 1;
|
61
|
-
console.log(picocolors__default["default"].red("✘"), "Found error in", `${sourcePath}:`, v.message);
|
62
96
|
}
|
63
97
|
}
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
98
|
+
for (const fatalError of valModule.errors.fatal || []) {
|
99
|
+
errors += 1;
|
100
|
+
console.log(picocolors__default["default"].red("✘"), moduleId, "is invalid:", fatalError.message);
|
101
|
+
}
|
102
|
+
} else {
|
103
|
+
console.log(picocolors__default["default"].green("✔"), moduleId, "is valid (", Date.now() - start, "ms)");
|
68
104
|
}
|
69
105
|
return errors;
|
70
106
|
}
|
71
107
|
}
|
72
|
-
|
108
|
+
let errors = 0;
|
109
|
+
for (const file of valFiles) {
|
110
|
+
errors += await validateFile(file);
|
111
|
+
}
|
73
112
|
if (errors > 0) {
|
74
113
|
console.log(picocolors__default["default"].red("✘"), "Found", errors, "validation error" + (errors > 1 ? "s" : ""));
|
75
114
|
process.exit(1);
|
@@ -6,6 +6,8 @@ var path = require('path');
|
|
6
6
|
var server = require('@valbuild/server');
|
7
7
|
var fastGlob = require('fast-glob');
|
8
8
|
var picocolors = require('picocolors');
|
9
|
+
var eslint = require('eslint');
|
10
|
+
var fs = require('fs/promises');
|
9
11
|
|
10
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
11
13
|
|
@@ -13,6 +15,7 @@ var meow__default = /*#__PURE__*/_interopDefault(meow);
|
|
13
15
|
var chalk__default = /*#__PURE__*/_interopDefault(chalk);
|
14
16
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
15
17
|
var picocolors__default = /*#__PURE__*/_interopDefault(picocolors);
|
18
|
+
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
16
19
|
|
17
20
|
function error(...message) {
|
18
21
|
console.error(chalk__default["default"].red(...message));
|
@@ -24,6 +27,11 @@ async function validate({
|
|
24
27
|
fix
|
25
28
|
}) {
|
26
29
|
const projectRoot = root ? path__default["default"].resolve(root) : process.cwd();
|
30
|
+
const eslint$1 = new eslint.ESLint({
|
31
|
+
cwd: projectRoot,
|
32
|
+
ignore: false,
|
33
|
+
useEslintrc: true
|
34
|
+
});
|
27
35
|
const service = await server.createService(projectRoot, {
|
28
36
|
valConfigPath: cfg ?? "./val.config"
|
29
37
|
});
|
@@ -32,44 +40,75 @@ async function validate({
|
|
32
40
|
cwd: projectRoot
|
33
41
|
});
|
34
42
|
console.log(picocolors__default["default"].green("✔"), "Validating", valFiles.length, "files");
|
43
|
+
const eslintResults = await eslint$1.lintFiles(valFiles);
|
44
|
+
const eslintResultsByFile = eslintResults.reduce((acc, result) => ({
|
45
|
+
...acc,
|
46
|
+
[result.filePath.replaceAll(`${projectRoot}/`, "")]: result
|
47
|
+
}), {});
|
35
48
|
async function validateFile(file) {
|
36
49
|
const moduleId = `/${file}`.replace(/(\.val\.(ts|js))$/, ""); // TODO: check if this always works? (Windows?)
|
37
50
|
const start = Date.now();
|
38
51
|
const valModule = await service.get(moduleId, "");
|
39
|
-
|
52
|
+
const fileContent = await fs__default["default"].readFile(path__default["default"].join(projectRoot, file), "utf-8");
|
53
|
+
const eslintResult = eslintResultsByFile === null || eslintResultsByFile === void 0 ? void 0 : eslintResultsByFile[file];
|
54
|
+
eslintResult === null || eslintResult === void 0 || eslintResult.messages.forEach(m => {
|
55
|
+
// display surrounding code
|
56
|
+
const lines = fileContent.split("\n");
|
57
|
+
const line = lines[m.line - 1];
|
58
|
+
const lineBefore = lines[m.line - 2];
|
59
|
+
const lineAfter = lines[m.line];
|
60
|
+
const isError = m.severity >= 2;
|
61
|
+
console.log(isError ? picocolors__default["default"].red("✘") : picocolors__default["default"].yellow("⚠"), isError ? "Found eslint error:" : "Found eslint warning:", `${moduleId}:${m.line}:${m.column}\n`, m.message);
|
62
|
+
lineBefore && console.log(picocolors__default["default"].gray(" " + (m.line - 1) + " |"), lineBefore);
|
63
|
+
line && console.log(picocolors__default["default"].gray(" " + m.line + " |"), line);
|
64
|
+
// adds ^ below the relevant line:
|
65
|
+
line && console.log(picocolors__default["default"].gray(" " + " ".repeat(m.line.toString().length) + " |"), " ".repeat(m.column - 1) + (m.endColumn ? (isError ? picocolors__default["default"].red("^") : picocolors__default["default"].yellow("^")).repeat(m.endColumn - m.column - 1) : ""));
|
66
|
+
lineAfter && console.log(picocolors__default["default"].gray(" " + (m.line + 1) + " |"), lineAfter);
|
67
|
+
});
|
68
|
+
if (!valModule.errors && (eslintResult === null || eslintResult === void 0 ? void 0 : eslintResult.errorCount) === 0) {
|
40
69
|
console.log(picocolors__default["default"].green("✔"), moduleId, "is valid (", Date.now() - start, "ms)");
|
41
70
|
return 0;
|
42
71
|
} else {
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
const
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
72
|
+
var _eslintResultsByFile$;
|
73
|
+
let errors = (eslintResultsByFile === null || eslintResultsByFile === void 0 || (_eslintResultsByFile$ = eslintResultsByFile[file]) === null || _eslintResultsByFile$ === void 0 ? void 0 : _eslintResultsByFile$.messages.reduce((prev, m) => m.severity >= 2 ? prev + 1 : prev, 0)) || 0;
|
74
|
+
if (valModule.errors) {
|
75
|
+
if (valModule.errors.validation) {
|
76
|
+
for (const [sourcePath, validationErrors] of Object.entries(valModule.errors.validation)) {
|
77
|
+
for (const v of validationErrors) {
|
78
|
+
if (v.fixes && v.fixes.length > 0) {
|
79
|
+
var _fixPatch$remainingEr;
|
80
|
+
const fixPatch = await server.createFixPatch({
|
81
|
+
projectRoot
|
82
|
+
}, !!fix, sourcePath, v);
|
83
|
+
if (fix && fixPatch !== null && fixPatch !== void 0 && fixPatch.patch && (fixPatch === null || fixPatch === void 0 ? void 0 : fixPatch.patch.length) > 0) {
|
84
|
+
await service.patch(moduleId, fixPatch.patch);
|
85
|
+
console.log(picocolors__default["default"].green("✔"), "Applied fix for", sourcePath);
|
86
|
+
}
|
87
|
+
fixPatch === null || fixPatch === void 0 || (_fixPatch$remainingEr = fixPatch.remainingErrors) === null || _fixPatch$remainingEr === void 0 || _fixPatch$remainingEr.forEach(e => {
|
88
|
+
errors += 1;
|
89
|
+
console.log(v.fixes ? picocolors__default["default"].yellow("⚠") : picocolors__default["default"].red("✘"), `Found ${v.fixes ? "fixable " : ""}error in`, `${sourcePath}:`, e.message);
|
90
|
+
});
|
91
|
+
} else {
|
92
|
+
errors += 1;
|
93
|
+
console.log(picocolors__default["default"].red("✘"), "Found error in", `${sourcePath}:`, v.message);
|
94
|
+
}
|
54
95
|
}
|
55
|
-
fixPatch === null || fixPatch === void 0 || (_fixPatch$remainingEr = fixPatch.remainingErrors) === null || _fixPatch$remainingEr === void 0 || _fixPatch$remainingEr.forEach(e => {
|
56
|
-
errors += 1;
|
57
|
-
console.log(v.fixes ? picocolors__default["default"].yellow("⚠") : picocolors__default["default"].red("✘"), `Found ${v.fixes ? "fixable " : ""}error in`, `${sourcePath}:`, e.message);
|
58
|
-
});
|
59
|
-
} else {
|
60
|
-
errors += 1;
|
61
|
-
console.log(picocolors__default["default"].red("✘"), "Found error in", `${sourcePath}:`, v.message);
|
62
96
|
}
|
63
97
|
}
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
98
|
+
for (const fatalError of valModule.errors.fatal || []) {
|
99
|
+
errors += 1;
|
100
|
+
console.log(picocolors__default["default"].red("✘"), moduleId, "is invalid:", fatalError.message);
|
101
|
+
}
|
102
|
+
} else {
|
103
|
+
console.log(picocolors__default["default"].green("✔"), moduleId, "is valid (", Date.now() - start, "ms)");
|
68
104
|
}
|
69
105
|
return errors;
|
70
106
|
}
|
71
107
|
}
|
72
|
-
|
108
|
+
let errors = 0;
|
109
|
+
for (const file of valFiles) {
|
110
|
+
errors += await validateFile(file);
|
111
|
+
}
|
73
112
|
if (errors > 0) {
|
74
113
|
console.log(picocolors__default["default"].red("✘"), "Found", errors, "validation error" + (errors > 1 ? "s" : ""));
|
75
114
|
process.exit(1);
|
@@ -4,6 +4,8 @@ import path from 'path';
|
|
4
4
|
import { createService, createFixPatch } from '@valbuild/server';
|
5
5
|
import { glob } from 'fast-glob';
|
6
6
|
import picocolors from 'picocolors';
|
7
|
+
import { ESLint } from 'eslint';
|
8
|
+
import fs from 'fs/promises';
|
7
9
|
|
8
10
|
function error(...message) {
|
9
11
|
console.error(chalk.red(...message));
|
@@ -15,6 +17,11 @@ async function validate({
|
|
15
17
|
fix
|
16
18
|
}) {
|
17
19
|
const projectRoot = root ? path.resolve(root) : process.cwd();
|
20
|
+
const eslint = new ESLint({
|
21
|
+
cwd: projectRoot,
|
22
|
+
ignore: false,
|
23
|
+
useEslintrc: true
|
24
|
+
});
|
18
25
|
const service = await createService(projectRoot, {
|
19
26
|
valConfigPath: cfg ?? "./val.config"
|
20
27
|
});
|
@@ -23,44 +30,75 @@ async function validate({
|
|
23
30
|
cwd: projectRoot
|
24
31
|
});
|
25
32
|
console.log(picocolors.green("✔"), "Validating", valFiles.length, "files");
|
33
|
+
const eslintResults = await eslint.lintFiles(valFiles);
|
34
|
+
const eslintResultsByFile = eslintResults.reduce((acc, result) => ({
|
35
|
+
...acc,
|
36
|
+
[result.filePath.replaceAll(`${projectRoot}/`, "")]: result
|
37
|
+
}), {});
|
26
38
|
async function validateFile(file) {
|
27
39
|
const moduleId = `/${file}`.replace(/(\.val\.(ts|js))$/, ""); // TODO: check if this always works? (Windows?)
|
28
40
|
const start = Date.now();
|
29
41
|
const valModule = await service.get(moduleId, "");
|
30
|
-
|
42
|
+
const fileContent = await fs.readFile(path.join(projectRoot, file), "utf-8");
|
43
|
+
const eslintResult = eslintResultsByFile === null || eslintResultsByFile === void 0 ? void 0 : eslintResultsByFile[file];
|
44
|
+
eslintResult === null || eslintResult === void 0 || eslintResult.messages.forEach(m => {
|
45
|
+
// display surrounding code
|
46
|
+
const lines = fileContent.split("\n");
|
47
|
+
const line = lines[m.line - 1];
|
48
|
+
const lineBefore = lines[m.line - 2];
|
49
|
+
const lineAfter = lines[m.line];
|
50
|
+
const isError = m.severity >= 2;
|
51
|
+
console.log(isError ? picocolors.red("✘") : picocolors.yellow("⚠"), isError ? "Found eslint error:" : "Found eslint warning:", `${moduleId}:${m.line}:${m.column}\n`, m.message);
|
52
|
+
lineBefore && console.log(picocolors.gray(" " + (m.line - 1) + " |"), lineBefore);
|
53
|
+
line && console.log(picocolors.gray(" " + m.line + " |"), line);
|
54
|
+
// adds ^ below the relevant line:
|
55
|
+
line && console.log(picocolors.gray(" " + " ".repeat(m.line.toString().length) + " |"), " ".repeat(m.column - 1) + (m.endColumn ? (isError ? picocolors.red("^") : picocolors.yellow("^")).repeat(m.endColumn - m.column - 1) : ""));
|
56
|
+
lineAfter && console.log(picocolors.gray(" " + (m.line + 1) + " |"), lineAfter);
|
57
|
+
});
|
58
|
+
if (!valModule.errors && (eslintResult === null || eslintResult === void 0 ? void 0 : eslintResult.errorCount) === 0) {
|
31
59
|
console.log(picocolors.green("✔"), moduleId, "is valid (", Date.now() - start, "ms)");
|
32
60
|
return 0;
|
33
61
|
} else {
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
const
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
62
|
+
var _eslintResultsByFile$;
|
63
|
+
let errors = (eslintResultsByFile === null || eslintResultsByFile === void 0 || (_eslintResultsByFile$ = eslintResultsByFile[file]) === null || _eslintResultsByFile$ === void 0 ? void 0 : _eslintResultsByFile$.messages.reduce((prev, m) => m.severity >= 2 ? prev + 1 : prev, 0)) || 0;
|
64
|
+
if (valModule.errors) {
|
65
|
+
if (valModule.errors.validation) {
|
66
|
+
for (const [sourcePath, validationErrors] of Object.entries(valModule.errors.validation)) {
|
67
|
+
for (const v of validationErrors) {
|
68
|
+
if (v.fixes && v.fixes.length > 0) {
|
69
|
+
var _fixPatch$remainingEr;
|
70
|
+
const fixPatch = await createFixPatch({
|
71
|
+
projectRoot
|
72
|
+
}, !!fix, sourcePath, v);
|
73
|
+
if (fix && fixPatch !== null && fixPatch !== void 0 && fixPatch.patch && (fixPatch === null || fixPatch === void 0 ? void 0 : fixPatch.patch.length) > 0) {
|
74
|
+
await service.patch(moduleId, fixPatch.patch);
|
75
|
+
console.log(picocolors.green("✔"), "Applied fix for", sourcePath);
|
76
|
+
}
|
77
|
+
fixPatch === null || fixPatch === void 0 || (_fixPatch$remainingEr = fixPatch.remainingErrors) === null || _fixPatch$remainingEr === void 0 || _fixPatch$remainingEr.forEach(e => {
|
78
|
+
errors += 1;
|
79
|
+
console.log(v.fixes ? picocolors.yellow("⚠") : picocolors.red("✘"), `Found ${v.fixes ? "fixable " : ""}error in`, `${sourcePath}:`, e.message);
|
80
|
+
});
|
81
|
+
} else {
|
82
|
+
errors += 1;
|
83
|
+
console.log(picocolors.red("✘"), "Found error in", `${sourcePath}:`, v.message);
|
84
|
+
}
|
45
85
|
}
|
46
|
-
fixPatch === null || fixPatch === void 0 || (_fixPatch$remainingEr = fixPatch.remainingErrors) === null || _fixPatch$remainingEr === void 0 || _fixPatch$remainingEr.forEach(e => {
|
47
|
-
errors += 1;
|
48
|
-
console.log(v.fixes ? picocolors.yellow("⚠") : picocolors.red("✘"), `Found ${v.fixes ? "fixable " : ""}error in`, `${sourcePath}:`, e.message);
|
49
|
-
});
|
50
|
-
} else {
|
51
|
-
errors += 1;
|
52
|
-
console.log(picocolors.red("✘"), "Found error in", `${sourcePath}:`, v.message);
|
53
86
|
}
|
54
87
|
}
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
88
|
+
for (const fatalError of valModule.errors.fatal || []) {
|
89
|
+
errors += 1;
|
90
|
+
console.log(picocolors.red("✘"), moduleId, "is invalid:", fatalError.message);
|
91
|
+
}
|
92
|
+
} else {
|
93
|
+
console.log(picocolors.green("✔"), moduleId, "is valid (", Date.now() - start, "ms)");
|
59
94
|
}
|
60
95
|
return errors;
|
61
96
|
}
|
62
97
|
}
|
63
|
-
|
98
|
+
let errors = 0;
|
99
|
+
for (const file of valFiles) {
|
100
|
+
errors += await validateFile(file);
|
101
|
+
}
|
64
102
|
if (errors > 0) {
|
65
103
|
console.log(picocolors.red("✘"), "Found", errors, "validation error" + (errors > 1 ? "s" : ""));
|
66
104
|
process.exit(1);
|
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.47.0",
|
5
5
|
"description": "Val CLI tools",
|
6
6
|
"bin": {
|
7
7
|
"val": "./bin.js"
|
@@ -17,7 +17,9 @@
|
|
17
17
|
"typecheck": "tsc --noEmit"
|
18
18
|
},
|
19
19
|
"dependencies": {
|
20
|
-
"@valbuild/server": "~0.
|
20
|
+
"@valbuild/server": "~0.47.0",
|
21
|
+
"@valbuild/eslint-plugin": "~0.47.0",
|
22
|
+
"eslint": "^8.31.0",
|
21
23
|
"chalk": "^4.1.2",
|
22
24
|
"cors": "^2.8.5",
|
23
25
|
"express": "^4.18.2",
|
package/src/validate.ts
CHANGED
@@ -3,6 +3,8 @@ import { createFixPatch, createService } from "@valbuild/server";
|
|
3
3
|
import { ModuleId, ModulePath, SourcePath } from "@valbuild/core";
|
4
4
|
import { glob } from "fast-glob";
|
5
5
|
import picocolors from "picocolors";
|
6
|
+
import { ESLint } from "eslint";
|
7
|
+
import fs from "fs/promises";
|
6
8
|
|
7
9
|
export async function validate({
|
8
10
|
root,
|
@@ -14,6 +16,11 @@ export async function validate({
|
|
14
16
|
fix?: boolean;
|
15
17
|
}) {
|
16
18
|
const projectRoot = root ? path.resolve(root) : process.cwd();
|
19
|
+
const eslint = new ESLint({
|
20
|
+
cwd: projectRoot,
|
21
|
+
ignore: false,
|
22
|
+
useEslintrc: true,
|
23
|
+
});
|
17
24
|
const service = await createService(projectRoot, {
|
18
25
|
valConfigPath: cfg ?? "./val.config",
|
19
26
|
});
|
@@ -23,13 +30,54 @@ export async function validate({
|
|
23
30
|
cwd: projectRoot,
|
24
31
|
});
|
25
32
|
console.log(picocolors.green("✔"), "Validating", valFiles.length, "files");
|
26
|
-
|
33
|
+
const eslintResults = await eslint.lintFiles(valFiles);
|
34
|
+
const eslintResultsByFile = eslintResults.reduce(
|
35
|
+
(acc, result) => ({
|
36
|
+
...acc,
|
37
|
+
[result.filePath.replaceAll(`${projectRoot}/`, "")]: result,
|
38
|
+
}),
|
39
|
+
{} as Record<string, ESLint.LintResult>
|
40
|
+
);
|
27
41
|
async function validateFile(file: string): Promise<number> {
|
28
42
|
const moduleId = `/${file}`.replace(/(\.val\.(ts|js))$/, "") as ModuleId; // TODO: check if this always works? (Windows?)
|
29
43
|
const start = Date.now();
|
30
44
|
const valModule = await service.get(moduleId, "" as ModulePath);
|
31
|
-
|
32
|
-
|
45
|
+
const fileContent = await fs.readFile(
|
46
|
+
path.join(projectRoot, file),
|
47
|
+
"utf-8"
|
48
|
+
);
|
49
|
+
const eslintResult = eslintResultsByFile?.[file];
|
50
|
+
eslintResult?.messages.forEach((m) => {
|
51
|
+
// display surrounding code
|
52
|
+
const lines = fileContent.split("\n");
|
53
|
+
const line = lines[m.line - 1];
|
54
|
+
const lineBefore = lines[m.line - 2];
|
55
|
+
const lineAfter = lines[m.line];
|
56
|
+
const isError = m.severity >= 2;
|
57
|
+
console.log(
|
58
|
+
isError ? picocolors.red("✘") : picocolors.yellow("⚠"),
|
59
|
+
isError ? "Found eslint error:" : "Found eslint warning:",
|
60
|
+
`${moduleId}:${m.line}:${m.column}\n`,
|
61
|
+
m.message
|
62
|
+
);
|
63
|
+
lineBefore &&
|
64
|
+
console.log(picocolors.gray(" " + (m.line - 1) + " |"), lineBefore);
|
65
|
+
line && console.log(picocolors.gray(" " + m.line + " |"), line);
|
66
|
+
// adds ^ below the relevant line:
|
67
|
+
line &&
|
68
|
+
console.log(
|
69
|
+
picocolors.gray(" " + " ".repeat(m.line.toString().length) + " |"),
|
70
|
+
" ".repeat(m.column - 1) +
|
71
|
+
(m.endColumn
|
72
|
+
? (isError ? picocolors.red("^") : picocolors.yellow("^")).repeat(
|
73
|
+
m.endColumn - m.column - 1
|
74
|
+
)
|
75
|
+
: "")
|
76
|
+
);
|
77
|
+
lineAfter &&
|
78
|
+
console.log(picocolors.gray(" " + (m.line + 1) + " |"), lineAfter);
|
79
|
+
});
|
80
|
+
if (!valModule.errors && eslintResult?.errorCount === 0) {
|
33
81
|
console.log(
|
34
82
|
picocolors.green("✔"),
|
35
83
|
moduleId,
|
@@ -39,64 +87,79 @@ export async function validate({
|
|
39
87
|
);
|
40
88
|
return 0;
|
41
89
|
} else {
|
42
|
-
let errors =
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
)
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
"Applied fix for",
|
60
|
-
sourcePath
|
90
|
+
let errors =
|
91
|
+
eslintResultsByFile?.[file]?.messages.reduce(
|
92
|
+
(prev, m) => (m.severity >= 2 ? prev + 1 : prev),
|
93
|
+
0
|
94
|
+
) || 0;
|
95
|
+
if (valModule.errors) {
|
96
|
+
if (valModule.errors.validation) {
|
97
|
+
for (const [sourcePath, validationErrors] of Object.entries(
|
98
|
+
valModule.errors.validation
|
99
|
+
)) {
|
100
|
+
for (const v of validationErrors) {
|
101
|
+
if (v.fixes && v.fixes.length > 0) {
|
102
|
+
const fixPatch = await createFixPatch(
|
103
|
+
{ projectRoot },
|
104
|
+
!!fix,
|
105
|
+
sourcePath as SourcePath,
|
106
|
+
v
|
61
107
|
);
|
62
|
-
|
63
|
-
|
108
|
+
if (fix && fixPatch?.patch && fixPatch?.patch.length > 0) {
|
109
|
+
await service.patch(moduleId, fixPatch.patch);
|
110
|
+
console.log(
|
111
|
+
picocolors.green("✔"),
|
112
|
+
"Applied fix for",
|
113
|
+
sourcePath
|
114
|
+
);
|
115
|
+
}
|
116
|
+
fixPatch?.remainingErrors?.forEach((e) => {
|
117
|
+
errors += 1;
|
118
|
+
console.log(
|
119
|
+
v.fixes ? picocolors.yellow("⚠") : picocolors.red("✘"),
|
120
|
+
`Found ${v.fixes ? "fixable " : ""}error in`,
|
121
|
+
`${sourcePath}:`,
|
122
|
+
e.message
|
123
|
+
);
|
124
|
+
});
|
125
|
+
} else {
|
64
126
|
errors += 1;
|
65
127
|
console.log(
|
66
|
-
|
67
|
-
|
128
|
+
picocolors.red("✘"),
|
129
|
+
"Found error in",
|
68
130
|
`${sourcePath}:`,
|
69
|
-
|
131
|
+
v.message
|
70
132
|
);
|
71
|
-
}
|
72
|
-
} else {
|
73
|
-
errors += 1;
|
74
|
-
console.log(
|
75
|
-
picocolors.red("✘"),
|
76
|
-
"Found error in",
|
77
|
-
`${sourcePath}:`,
|
78
|
-
v.message
|
79
|
-
);
|
133
|
+
}
|
80
134
|
}
|
81
135
|
}
|
82
136
|
}
|
83
|
-
|
84
|
-
|
137
|
+
for (const fatalError of valModule.errors.fatal || []) {
|
138
|
+
errors += 1;
|
139
|
+
console.log(
|
140
|
+
picocolors.red("✘"),
|
141
|
+
moduleId,
|
142
|
+
"is invalid:",
|
143
|
+
fatalError.message
|
144
|
+
);
|
145
|
+
}
|
146
|
+
} else {
|
85
147
|
console.log(
|
86
|
-
picocolors.
|
148
|
+
picocolors.green("✔"),
|
87
149
|
moduleId,
|
88
|
-
"is
|
89
|
-
|
150
|
+
"is valid (",
|
151
|
+
Date.now() - start,
|
152
|
+
"ms)"
|
90
153
|
);
|
91
154
|
}
|
92
155
|
return errors;
|
93
156
|
}
|
94
157
|
}
|
95
158
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
159
|
+
let errors = 0;
|
160
|
+
for (const file of valFiles) {
|
161
|
+
errors += await validateFile(file);
|
162
|
+
}
|
100
163
|
if (errors > 0) {
|
101
164
|
console.log(
|
102
165
|
picocolors.red("✘"),
|