@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.
@@ -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
- if (!valModule.errors) {
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
- let errors = 0;
44
- if (valModule.errors.validation) for (const [sourcePath, validationErrors] of Object.entries(valModule.errors.validation)) {
45
- for (const v of validationErrors) {
46
- if (v.fixes && v.fixes.length > 0) {
47
- var _fixPatch$remainingEr;
48
- const fixPatch = await server.createFixPatch({
49
- projectRoot
50
- }, !!fix, sourcePath, v);
51
- if (fix && fixPatch !== null && fixPatch !== void 0 && fixPatch.patch && (fixPatch === null || fixPatch === void 0 ? void 0 : fixPatch.patch.length) > 0) {
52
- await service.patch(moduleId, fixPatch.patch);
53
- console.log(picocolors__default["default"].green("✔"), "Applied fix for", sourcePath);
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
- for (const fatalError of valModule.errors.fatal || []) {
66
- errors += 1;
67
- console.log(picocolors__default["default"].red("✘"), moduleId, "is invalid:", fatalError.message);
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
- const errors = (await Promise.all(valFiles.map(validateFile))).reduce((a, b) => a + b, 0);
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
- if (!valModule.errors) {
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
- let errors = 0;
44
- if (valModule.errors.validation) for (const [sourcePath, validationErrors] of Object.entries(valModule.errors.validation)) {
45
- for (const v of validationErrors) {
46
- if (v.fixes && v.fixes.length > 0) {
47
- var _fixPatch$remainingEr;
48
- const fixPatch = await server.createFixPatch({
49
- projectRoot
50
- }, !!fix, sourcePath, v);
51
- if (fix && fixPatch !== null && fixPatch !== void 0 && fixPatch.patch && (fixPatch === null || fixPatch === void 0 ? void 0 : fixPatch.patch.length) > 0) {
52
- await service.patch(moduleId, fixPatch.patch);
53
- console.log(picocolors__default["default"].green("✔"), "Applied fix for", sourcePath);
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
- for (const fatalError of valModule.errors.fatal || []) {
66
- errors += 1;
67
- console.log(picocolors__default["default"].red("✘"), moduleId, "is invalid:", fatalError.message);
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
- const errors = (await Promise.all(valFiles.map(validateFile))).reduce((a, b) => a + b, 0);
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
- if (!valModule.errors) {
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
- let errors = 0;
35
- if (valModule.errors.validation) for (const [sourcePath, validationErrors] of Object.entries(valModule.errors.validation)) {
36
- for (const v of validationErrors) {
37
- if (v.fixes && v.fixes.length > 0) {
38
- var _fixPatch$remainingEr;
39
- const fixPatch = await createFixPatch({
40
- projectRoot
41
- }, !!fix, sourcePath, v);
42
- if (fix && fixPatch !== null && fixPatch !== void 0 && fixPatch.patch && (fixPatch === null || fixPatch === void 0 ? void 0 : fixPatch.patch.length) > 0) {
43
- await service.patch(moduleId, fixPatch.patch);
44
- console.log(picocolors.green("✔"), "Applied fix for", sourcePath);
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
- for (const fatalError of valModule.errors.fatal || []) {
57
- errors += 1;
58
- console.log(picocolors.red("✘"), moduleId, "is invalid:", fatalError.message);
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
- const errors = (await Promise.all(valFiles.map(validateFile))).reduce((a, b) => a + b, 0);
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.46.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.46.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
- if (!valModule.errors) {
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 = 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
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
- fixPatch?.remainingErrors?.forEach((e) => {
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
- v.fixes ? picocolors.yellow("⚠") : picocolors.red("✘"),
67
- `Found ${v.fixes ? "fixable " : ""}error in`,
128
+ picocolors.red("✘"),
129
+ "Found error in",
68
130
  `${sourcePath}:`,
69
- e.message
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
- for (const fatalError of valModule.errors.fatal || []) {
84
- errors += 1;
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.red(""),
148
+ picocolors.green(""),
87
149
  moduleId,
88
- "is invalid:",
89
- fatalError.message
150
+ "is valid (",
151
+ Date.now() - start,
152
+ "ms)"
90
153
  );
91
154
  }
92
155
  return errors;
93
156
  }
94
157
  }
95
158
 
96
- const errors = (await Promise.all(valFiles.map(validateFile))).reduce(
97
- (a, b) => a + b,
98
- 0
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("✘"),