@valbuild/cli 0.73.0 → 0.73.1

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.
@@ -9,6 +9,9 @@ var fastGlob = require('fast-glob');
9
9
  var picocolors = require('picocolors');
10
10
  var eslint = require('eslint');
11
11
  var fs = require('fs/promises');
12
+ var vm = require('node:vm');
13
+ var ts = require('typescript');
14
+ var z = require('zod');
12
15
  var fs$1 = require('fs');
13
16
 
14
17
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
@@ -36,12 +39,82 @@ var chalk__default = /*#__PURE__*/_interopDefault(chalk);
36
39
  var path__default = /*#__PURE__*/_interopDefault(path);
37
40
  var picocolors__default = /*#__PURE__*/_interopDefault(picocolors);
38
41
  var fs__default = /*#__PURE__*/_interopDefault(fs);
42
+ var vm__default = /*#__PURE__*/_interopDefault(vm);
43
+ var ts__default = /*#__PURE__*/_interopDefault(ts);
44
+ var z__default = /*#__PURE__*/_interopDefault(z);
39
45
  var fs__default$1 = /*#__PURE__*/_interopDefault(fs$1);
40
46
 
41
47
  function error(message) {
42
48
  console.error(chalk__default["default"].red("❌Error: ") + message);
43
49
  }
44
50
 
51
+ const ValConfigSchema = z__default["default"].object({
52
+ project: z__default["default"].string().optional(),
53
+ root: z__default["default"].string().optional(),
54
+ files: z__default["default"].object({
55
+ directory: z__default["default"].string().refine(val => val.startsWith("/public/val"), {
56
+ message: "files.directory must start with '/public/val'"
57
+ })
58
+ }).optional(),
59
+ gitCommit: z__default["default"].string().optional(),
60
+ gitBranch: z__default["default"].string().optional(),
61
+ defaultTheme: z__default["default"].union([z__default["default"].literal("light"), z__default["default"].literal("dark")]).optional(),
62
+ ai: z__default["default"].object({
63
+ commitMessages: z__default["default"].object({
64
+ disabled: z__default["default"].boolean().optional()
65
+ }).optional()
66
+ }).optional()
67
+ });
68
+ async function evalValConfigFile(projectRoot, configFileName) {
69
+ const valConfigPath = path__default["default"].join(projectRoot, configFileName);
70
+ let code = null;
71
+ try {
72
+ code = await fs__default["default"].readFile(valConfigPath, "utf-8");
73
+ } catch (err) {
74
+ //
75
+ }
76
+ if (!code) {
77
+ return null;
78
+ }
79
+ const transpiled = ts__default["default"].transpileModule(code, {
80
+ compilerOptions: {
81
+ target: ts__default["default"].ScriptTarget.ES2020,
82
+ module: ts__default["default"].ModuleKind.CommonJS,
83
+ esModuleInterop: true
84
+ },
85
+ fileName: valConfigPath
86
+ });
87
+ const exportsObj = {};
88
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
89
+ const sandbox = {
90
+ exports: exportsObj,
91
+ module: {
92
+ exports: exportsObj
93
+ },
94
+ require,
95
+ // NOTE: this is a security risk, but this code is running in the users own environment at the CLI level
96
+ __filename: valConfigPath,
97
+ __dirname: path__default["default"].dirname(valConfigPath),
98
+ console,
99
+ process
100
+ };
101
+ sandbox.global = sandbox;
102
+ const context = vm__default["default"].createContext(sandbox);
103
+ const script = new vm__default["default"].Script(transpiled.outputText, {
104
+ filename: valConfigPath
105
+ });
106
+ script.runInContext(context);
107
+ const valConfig = sandbox.module.exports.config;
108
+ if (!valConfig) {
109
+ throw Error(`Val config file at path: '${valConfigPath}' must export a config object. Got: ${valConfig}`);
110
+ }
111
+ const result = ValConfigSchema.safeParse(valConfig);
112
+ if (!result.success) {
113
+ throw Error(`Val config file at path: '${valConfigPath}' has invalid schema: ${result.error.message}`);
114
+ }
115
+ return result.data;
116
+ }
117
+
45
118
  async function validate({
46
119
  root,
47
120
  fix,
@@ -53,6 +126,8 @@ async function validate({
53
126
  cwd: projectRoot,
54
127
  ignore: false
55
128
  });
129
+ const valConfigFile = (await evalValConfigFile(projectRoot, "val.config.ts")) || (await evalValConfigFile(projectRoot, "val.config.js"));
130
+ console.log(picocolors__default["default"].greenBright(`Validating project${valConfigFile !== null && valConfigFile !== void 0 && valConfigFile.project ? ` '${picocolors__default["default"].inverse(valConfigFile === null || valConfigFile === void 0 ? void 0 : valConfigFile.project)}'` : ""}...`));
56
131
  const service = await server.createService(projectRoot, {});
57
132
  const checkKeyIsValid = async (key, sourcePath) => {
58
133
  const [moduleFilePath, modulePath] = core.Internal.splitModuleFilePathAndModulePath(sourcePath);
@@ -120,7 +195,7 @@ async function validate({
120
195
  });
121
196
  console.log(errors === 0 ? picocolors__default["default"].green("✔") : picocolors__default["default"].red("✘"), "ESlint complete", lintFiles.length, "files");
122
197
  }
123
- console.log("Validating...", valFiles.length, "files");
198
+ console.log(picocolors__default["default"].greenBright(`Found ${valFiles.length} files...`));
124
199
  let publicProjectId;
125
200
  let didFix = false; // TODO: ugly
126
201
  async function validateFile(file) {
@@ -208,7 +283,6 @@ async function validate({
208
283
  if (valModule.source && valModule.schema) {
209
284
  const resolvedRemoteFileAtSourcePath = core.Internal.resolvePath(modulePath, valModule.source, valModule.schema);
210
285
  let filePath = null;
211
- console.log(sourcePath, resolvedRemoteFileAtSourcePath.source);
212
286
  try {
213
287
  var _resolvedRemoteFileAt;
214
288
  filePath = path__default["default"].join(projectRoot, // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -263,31 +337,7 @@ async function validate({
263
337
  if (!publicProjectId || !remoteFileBuckets) {
264
338
  let projectName = process.env.VAL_PROJECT;
265
339
  if (!projectName) {
266
- try {
267
- var _require;
268
- // eslint-disable-next-line @typescript-eslint/no-var-requires
269
- projectName = (_require = require(`${root}/val.config`)) === null || _require === void 0 || (_require = _require.config) === null || _require === void 0 ? void 0 : _require.project;
270
- } catch {
271
- // ignore
272
- }
273
- }
274
- if (!projectName) {
275
- try {
276
- var _require2;
277
- // eslint-disable-next-line @typescript-eslint/no-var-requires
278
- projectName = (_require2 = require(`${root}/val.config.ts`)) === null || _require2 === void 0 || (_require2 = _require2.config) === null || _require2 === void 0 ? void 0 : _require2.project;
279
- } catch {
280
- // ignore
281
- }
282
- }
283
- if (!projectName) {
284
- try {
285
- var _require3;
286
- // eslint-disable-next-line @typescript-eslint/no-var-requires
287
- projectName = (_require3 = require(`${root}/val.config.js`)) === null || _require3 === void 0 || (_require3 = _require3.config) === null || _require3 === void 0 ? void 0 : _require3.project;
288
- } catch {
289
- // ignore
290
- }
340
+ projectName = valConfigFile === null || valConfigFile === void 0 ? void 0 : valConfigFile.project;
291
341
  }
292
342
  if (!projectName) {
293
343
  console.log(picocolors__default["default"].red("✘"), "Project name not found. Set VAL_PROJECT environment variable or add project name to val.config");
@@ -9,6 +9,9 @@ var fastGlob = require('fast-glob');
9
9
  var picocolors = require('picocolors');
10
10
  var eslint = require('eslint');
11
11
  var fs = require('fs/promises');
12
+ var vm = require('node:vm');
13
+ var ts = require('typescript');
14
+ var z = require('zod');
12
15
  var fs$1 = require('fs');
13
16
 
14
17
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
@@ -36,12 +39,82 @@ var chalk__default = /*#__PURE__*/_interopDefault(chalk);
36
39
  var path__default = /*#__PURE__*/_interopDefault(path);
37
40
  var picocolors__default = /*#__PURE__*/_interopDefault(picocolors);
38
41
  var fs__default = /*#__PURE__*/_interopDefault(fs);
42
+ var vm__default = /*#__PURE__*/_interopDefault(vm);
43
+ var ts__default = /*#__PURE__*/_interopDefault(ts);
44
+ var z__default = /*#__PURE__*/_interopDefault(z);
39
45
  var fs__default$1 = /*#__PURE__*/_interopDefault(fs$1);
40
46
 
41
47
  function error(message) {
42
48
  console.error(chalk__default["default"].red("❌Error: ") + message);
43
49
  }
44
50
 
51
+ const ValConfigSchema = z__default["default"].object({
52
+ project: z__default["default"].string().optional(),
53
+ root: z__default["default"].string().optional(),
54
+ files: z__default["default"].object({
55
+ directory: z__default["default"].string().refine(val => val.startsWith("/public/val"), {
56
+ message: "files.directory must start with '/public/val'"
57
+ })
58
+ }).optional(),
59
+ gitCommit: z__default["default"].string().optional(),
60
+ gitBranch: z__default["default"].string().optional(),
61
+ defaultTheme: z__default["default"].union([z__default["default"].literal("light"), z__default["default"].literal("dark")]).optional(),
62
+ ai: z__default["default"].object({
63
+ commitMessages: z__default["default"].object({
64
+ disabled: z__default["default"].boolean().optional()
65
+ }).optional()
66
+ }).optional()
67
+ });
68
+ async function evalValConfigFile(projectRoot, configFileName) {
69
+ const valConfigPath = path__default["default"].join(projectRoot, configFileName);
70
+ let code = null;
71
+ try {
72
+ code = await fs__default["default"].readFile(valConfigPath, "utf-8");
73
+ } catch (err) {
74
+ //
75
+ }
76
+ if (!code) {
77
+ return null;
78
+ }
79
+ const transpiled = ts__default["default"].transpileModule(code, {
80
+ compilerOptions: {
81
+ target: ts__default["default"].ScriptTarget.ES2020,
82
+ module: ts__default["default"].ModuleKind.CommonJS,
83
+ esModuleInterop: true
84
+ },
85
+ fileName: valConfigPath
86
+ });
87
+ const exportsObj = {};
88
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
89
+ const sandbox = {
90
+ exports: exportsObj,
91
+ module: {
92
+ exports: exportsObj
93
+ },
94
+ require,
95
+ // NOTE: this is a security risk, but this code is running in the users own environment at the CLI level
96
+ __filename: valConfigPath,
97
+ __dirname: path__default["default"].dirname(valConfigPath),
98
+ console,
99
+ process
100
+ };
101
+ sandbox.global = sandbox;
102
+ const context = vm__default["default"].createContext(sandbox);
103
+ const script = new vm__default["default"].Script(transpiled.outputText, {
104
+ filename: valConfigPath
105
+ });
106
+ script.runInContext(context);
107
+ const valConfig = sandbox.module.exports.config;
108
+ if (!valConfig) {
109
+ throw Error(`Val config file at path: '${valConfigPath}' must export a config object. Got: ${valConfig}`);
110
+ }
111
+ const result = ValConfigSchema.safeParse(valConfig);
112
+ if (!result.success) {
113
+ throw Error(`Val config file at path: '${valConfigPath}' has invalid schema: ${result.error.message}`);
114
+ }
115
+ return result.data;
116
+ }
117
+
45
118
  async function validate({
46
119
  root,
47
120
  fix,
@@ -53,6 +126,8 @@ async function validate({
53
126
  cwd: projectRoot,
54
127
  ignore: false
55
128
  });
129
+ const valConfigFile = (await evalValConfigFile(projectRoot, "val.config.ts")) || (await evalValConfigFile(projectRoot, "val.config.js"));
130
+ console.log(picocolors__default["default"].greenBright(`Validating project${valConfigFile !== null && valConfigFile !== void 0 && valConfigFile.project ? ` '${picocolors__default["default"].inverse(valConfigFile === null || valConfigFile === void 0 ? void 0 : valConfigFile.project)}'` : ""}...`));
56
131
  const service = await server.createService(projectRoot, {});
57
132
  const checkKeyIsValid = async (key, sourcePath) => {
58
133
  const [moduleFilePath, modulePath] = core.Internal.splitModuleFilePathAndModulePath(sourcePath);
@@ -120,7 +195,7 @@ async function validate({
120
195
  });
121
196
  console.log(errors === 0 ? picocolors__default["default"].green("✔") : picocolors__default["default"].red("✘"), "ESlint complete", lintFiles.length, "files");
122
197
  }
123
- console.log("Validating...", valFiles.length, "files");
198
+ console.log(picocolors__default["default"].greenBright(`Found ${valFiles.length} files...`));
124
199
  let publicProjectId;
125
200
  let didFix = false; // TODO: ugly
126
201
  async function validateFile(file) {
@@ -208,7 +283,6 @@ async function validate({
208
283
  if (valModule.source && valModule.schema) {
209
284
  const resolvedRemoteFileAtSourcePath = core.Internal.resolvePath(modulePath, valModule.source, valModule.schema);
210
285
  let filePath = null;
211
- console.log(sourcePath, resolvedRemoteFileAtSourcePath.source);
212
286
  try {
213
287
  var _resolvedRemoteFileAt;
214
288
  filePath = path__default["default"].join(projectRoot, // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -263,31 +337,7 @@ async function validate({
263
337
  if (!publicProjectId || !remoteFileBuckets) {
264
338
  let projectName = process.env.VAL_PROJECT;
265
339
  if (!projectName) {
266
- try {
267
- var _require;
268
- // eslint-disable-next-line @typescript-eslint/no-var-requires
269
- projectName = (_require = require(`${root}/val.config`)) === null || _require === void 0 || (_require = _require.config) === null || _require === void 0 ? void 0 : _require.project;
270
- } catch {
271
- // ignore
272
- }
273
- }
274
- if (!projectName) {
275
- try {
276
- var _require2;
277
- // eslint-disable-next-line @typescript-eslint/no-var-requires
278
- projectName = (_require2 = require(`${root}/val.config.ts`)) === null || _require2 === void 0 || (_require2 = _require2.config) === null || _require2 === void 0 ? void 0 : _require2.project;
279
- } catch {
280
- // ignore
281
- }
282
- }
283
- if (!projectName) {
284
- try {
285
- var _require3;
286
- // eslint-disable-next-line @typescript-eslint/no-var-requires
287
- projectName = (_require3 = require(`${root}/val.config.js`)) === null || _require3 === void 0 || (_require3 = _require3.config) === null || _require3 === void 0 ? void 0 : _require3.project;
288
- } catch {
289
- // ignore
290
- }
340
+ projectName = valConfigFile === null || valConfigFile === void 0 ? void 0 : valConfigFile.project;
291
341
  }
292
342
  if (!projectName) {
293
343
  console.log(picocolors__default["default"].red("✘"), "Project name not found. Set VAL_PROJECT environment variable or add project name to val.config");
@@ -7,12 +7,82 @@ import { glob } from 'fast-glob';
7
7
  import picocolors from 'picocolors';
8
8
  import { ESLint } from 'eslint';
9
9
  import fs from 'fs/promises';
10
+ import vm from 'node:vm';
11
+ import ts from 'typescript';
12
+ import z from 'zod';
10
13
  import fs$1 from 'fs';
11
14
 
12
15
  function error(message) {
13
16
  console.error(chalk.red("❌Error: ") + message);
14
17
  }
15
18
 
19
+ const ValConfigSchema = z.object({
20
+ project: z.string().optional(),
21
+ root: z.string().optional(),
22
+ files: z.object({
23
+ directory: z.string().refine(val => val.startsWith("/public/val"), {
24
+ message: "files.directory must start with '/public/val'"
25
+ })
26
+ }).optional(),
27
+ gitCommit: z.string().optional(),
28
+ gitBranch: z.string().optional(),
29
+ defaultTheme: z.union([z.literal("light"), z.literal("dark")]).optional(),
30
+ ai: z.object({
31
+ commitMessages: z.object({
32
+ disabled: z.boolean().optional()
33
+ }).optional()
34
+ }).optional()
35
+ });
36
+ async function evalValConfigFile(projectRoot, configFileName) {
37
+ const valConfigPath = path.join(projectRoot, configFileName);
38
+ let code = null;
39
+ try {
40
+ code = await fs.readFile(valConfigPath, "utf-8");
41
+ } catch (err) {
42
+ //
43
+ }
44
+ if (!code) {
45
+ return null;
46
+ }
47
+ const transpiled = ts.transpileModule(code, {
48
+ compilerOptions: {
49
+ target: ts.ScriptTarget.ES2020,
50
+ module: ts.ModuleKind.CommonJS,
51
+ esModuleInterop: true
52
+ },
53
+ fileName: valConfigPath
54
+ });
55
+ const exportsObj = {};
56
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
+ const sandbox = {
58
+ exports: exportsObj,
59
+ module: {
60
+ exports: exportsObj
61
+ },
62
+ require,
63
+ // NOTE: this is a security risk, but this code is running in the users own environment at the CLI level
64
+ __filename: valConfigPath,
65
+ __dirname: path.dirname(valConfigPath),
66
+ console,
67
+ process
68
+ };
69
+ sandbox.global = sandbox;
70
+ const context = vm.createContext(sandbox);
71
+ const script = new vm.Script(transpiled.outputText, {
72
+ filename: valConfigPath
73
+ });
74
+ script.runInContext(context);
75
+ const valConfig = sandbox.module.exports.config;
76
+ if (!valConfig) {
77
+ throw Error(`Val config file at path: '${valConfigPath}' must export a config object. Got: ${valConfig}`);
78
+ }
79
+ const result = ValConfigSchema.safeParse(valConfig);
80
+ if (!result.success) {
81
+ throw Error(`Val config file at path: '${valConfigPath}' has invalid schema: ${result.error.message}`);
82
+ }
83
+ return result.data;
84
+ }
85
+
16
86
  async function validate({
17
87
  root,
18
88
  fix,
@@ -24,6 +94,8 @@ async function validate({
24
94
  cwd: projectRoot,
25
95
  ignore: false
26
96
  });
97
+ const valConfigFile = (await evalValConfigFile(projectRoot, "val.config.ts")) || (await evalValConfigFile(projectRoot, "val.config.js"));
98
+ console.log(picocolors.greenBright(`Validating project${valConfigFile !== null && valConfigFile !== void 0 && valConfigFile.project ? ` '${picocolors.inverse(valConfigFile === null || valConfigFile === void 0 ? void 0 : valConfigFile.project)}'` : ""}...`));
27
99
  const service = await createService(projectRoot, {});
28
100
  const checkKeyIsValid = async (key, sourcePath) => {
29
101
  const [moduleFilePath, modulePath] = Internal.splitModuleFilePathAndModulePath(sourcePath);
@@ -91,7 +163,7 @@ async function validate({
91
163
  });
92
164
  console.log(errors === 0 ? picocolors.green("✔") : picocolors.red("✘"), "ESlint complete", lintFiles.length, "files");
93
165
  }
94
- console.log("Validating...", valFiles.length, "files");
166
+ console.log(picocolors.greenBright(`Found ${valFiles.length} files...`));
95
167
  let publicProjectId;
96
168
  let didFix = false; // TODO: ugly
97
169
  async function validateFile(file) {
@@ -179,7 +251,6 @@ async function validate({
179
251
  if (valModule.source && valModule.schema) {
180
252
  const resolvedRemoteFileAtSourcePath = Internal.resolvePath(modulePath, valModule.source, valModule.schema);
181
253
  let filePath = null;
182
- console.log(sourcePath, resolvedRemoteFileAtSourcePath.source);
183
254
  try {
184
255
  var _resolvedRemoteFileAt;
185
256
  filePath = path.join(projectRoot, // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -234,31 +305,7 @@ async function validate({
234
305
  if (!publicProjectId || !remoteFileBuckets) {
235
306
  let projectName = process.env.VAL_PROJECT;
236
307
  if (!projectName) {
237
- try {
238
- var _require;
239
- // eslint-disable-next-line @typescript-eslint/no-var-requires
240
- projectName = (_require = require(`${root}/val.config`)) === null || _require === void 0 || (_require = _require.config) === null || _require === void 0 ? void 0 : _require.project;
241
- } catch {
242
- // ignore
243
- }
244
- }
245
- if (!projectName) {
246
- try {
247
- var _require2;
248
- // eslint-disable-next-line @typescript-eslint/no-var-requires
249
- projectName = (_require2 = require(`${root}/val.config.ts`)) === null || _require2 === void 0 || (_require2 = _require2.config) === null || _require2 === void 0 ? void 0 : _require2.project;
250
- } catch {
251
- // ignore
252
- }
253
- }
254
- if (!projectName) {
255
- try {
256
- var _require3;
257
- // eslint-disable-next-line @typescript-eslint/no-var-requires
258
- projectName = (_require3 = require(`${root}/val.config.js`)) === null || _require3 === void 0 || (_require3 = _require3.config) === null || _require3 === void 0 ? void 0 : _require3.project;
259
- } catch {
260
- // ignore
261
- }
308
+ projectName = valConfigFile === null || valConfigFile === void 0 ? void 0 : valConfigFile.project;
262
309
  }
263
310
  if (!projectName) {
264
311
  console.log(picocolors.red("✘"), "Project name not found. Set VAL_PROJECT environment variable or add project name to val.config");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@valbuild/cli",
3
3
  "private": false,
4
- "version": "0.73.0",
4
+ "version": "0.73.1",
5
5
  "description": "Val CLI tools",
6
6
  "bin": {
7
7
  "val": "./bin.js"
@@ -18,9 +18,9 @@
18
18
  "typecheck": "tsc --noEmit"
19
19
  },
20
20
  "dependencies": {
21
- "@valbuild/core": "~0.73.0",
22
- "@valbuild/server": "~0.73.0",
23
- "@valbuild/eslint-plugin": "~0.73.0",
21
+ "@valbuild/core": "~0.73.1",
22
+ "@valbuild/server": "~0.73.1",
23
+ "@valbuild/eslint-plugin": "~0.73.1",
24
24
  "eslint": "^8.31.0",
25
25
  "@inquirer/confirm": "^2.0.15",
26
26
  "@inquirer/prompts": "^3.0.2",
@@ -34,7 +34,8 @@
34
34
  "zod": "^3.22.4"
35
35
  },
36
36
  "peerDependencies": {
37
- "prettier": "*"
37
+ "prettier": "*",
38
+ "typescript": ">=5.0.0"
38
39
  },
39
40
  "preconstruct": {
40
41
  "entrypoints": [
@@ -0,0 +1,90 @@
1
+ import path from "path";
2
+ import fs from "fs/promises";
3
+ import vm from "node:vm";
4
+ import ts from "typescript"; // TODO: make this dependency optional (only required if the file is val.config.ts not val.config.js)
5
+ import z from "zod";
6
+ import { ValConfig } from "@valbuild/core";
7
+
8
+ const ValConfigSchema = z.object({
9
+ project: z.string().optional(),
10
+ root: z.string().optional(),
11
+ files: z
12
+ .object({
13
+ directory: z
14
+ .string()
15
+ .refine((val): val is `/public/val` => val.startsWith("/public/val"), {
16
+ message: "files.directory must start with '/public/val'",
17
+ }),
18
+ })
19
+ .optional(),
20
+ gitCommit: z.string().optional(),
21
+ gitBranch: z.string().optional(),
22
+ defaultTheme: z.union([z.literal("light"), z.literal("dark")]).optional(),
23
+ ai: z
24
+ .object({
25
+ commitMessages: z
26
+ .object({
27
+ disabled: z.boolean().optional(),
28
+ })
29
+ .optional(),
30
+ })
31
+ .optional(),
32
+ });
33
+
34
+ export async function evalValConfigFile(
35
+ projectRoot: string,
36
+ configFileName: string,
37
+ ): Promise<ValConfig | null> {
38
+ const valConfigPath = path.join(projectRoot, configFileName);
39
+
40
+ let code: string | null = null;
41
+ try {
42
+ code = await fs.readFile(valConfigPath, "utf-8");
43
+ } catch (err) {
44
+ //
45
+ }
46
+ if (!code) {
47
+ return null;
48
+ }
49
+
50
+ const transpiled = ts.transpileModule(code, {
51
+ compilerOptions: {
52
+ target: ts.ScriptTarget.ES2020,
53
+ module: ts.ModuleKind.CommonJS,
54
+ esModuleInterop: true,
55
+ },
56
+ fileName: valConfigPath,
57
+ });
58
+
59
+ const exportsObj = {};
60
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
+ const sandbox: Record<string, any> = {
62
+ exports: exportsObj,
63
+ module: { exports: exportsObj },
64
+ require, // NOTE: this is a security risk, but this code is running in the users own environment at the CLI level
65
+ __filename: valConfigPath,
66
+ __dirname: path.dirname(valConfigPath),
67
+ console,
68
+ process,
69
+ };
70
+ sandbox.global = sandbox;
71
+
72
+ const context = vm.createContext(sandbox);
73
+ const script = new vm.Script(transpiled.outputText, {
74
+ filename: valConfigPath,
75
+ });
76
+ script.runInContext(context);
77
+ const valConfig = sandbox.module.exports.config;
78
+ if (!valConfig) {
79
+ throw Error(
80
+ `Val config file at path: '${valConfigPath}' must export a config object. Got: ${valConfig}`,
81
+ );
82
+ }
83
+ const result = ValConfigSchema.safeParse(valConfig);
84
+ if (!result.success) {
85
+ throw Error(
86
+ `Val config file at path: '${valConfigPath}' has invalid schema: ${result.error.message}`,
87
+ );
88
+ }
89
+ return result.data;
90
+ }
package/src/validate.ts CHANGED
@@ -22,6 +22,7 @@ import { glob } from "fast-glob";
22
22
  import picocolors from "picocolors";
23
23
  import { ESLint } from "eslint";
24
24
  import fs from "fs/promises";
25
+ import { evalValConfigFile } from "./utils/evalValConfigFile";
25
26
 
26
27
  export async function validate({
27
28
  root,
@@ -38,6 +39,14 @@ export async function validate({
38
39
  cwd: projectRoot,
39
40
  ignore: false,
40
41
  });
42
+ const valConfigFile =
43
+ (await evalValConfigFile(projectRoot, "val.config.ts")) ||
44
+ (await evalValConfigFile(projectRoot, "val.config.js"));
45
+ console.log(
46
+ picocolors.greenBright(
47
+ `Validating project${valConfigFile?.project ? ` '${picocolors.inverse(valConfigFile?.project)}'` : ""}...`,
48
+ ),
49
+ );
41
50
  const service = await createService(projectRoot, {});
42
51
  const checkKeyIsValid = async (
43
52
  key: string,
@@ -130,8 +139,7 @@ export async function validate({
130
139
  "files",
131
140
  );
132
141
  }
133
- console.log("Validating...", valFiles.length, "files");
134
-
142
+ console.log(picocolors.greenBright(`Found ${valFiles.length} files...`));
135
143
  let publicProjectId: string | undefined;
136
144
  let didFix = false; // TODO: ugly
137
145
  async function validateFile(file: string): Promise<number> {
@@ -287,10 +295,6 @@ export async function validate({
287
295
  valModule.schema,
288
296
  );
289
297
  let filePath: string | null = null;
290
- console.log(
291
- sourcePath,
292
- resolvedRemoteFileAtSourcePath.source,
293
- );
294
298
  try {
295
299
  filePath = path.join(
296
300
  projectRoot,
@@ -383,31 +387,7 @@ export async function validate({
383
387
  if (!publicProjectId || !remoteFileBuckets) {
384
388
  let projectName = process.env.VAL_PROJECT;
385
389
  if (!projectName) {
386
- try {
387
- // eslint-disable-next-line @typescript-eslint/no-var-requires
388
- projectName = require(`${root}/val.config`)?.config
389
- ?.project;
390
- } catch {
391
- // ignore
392
- }
393
- }
394
- if (!projectName) {
395
- try {
396
- // eslint-disable-next-line @typescript-eslint/no-var-requires
397
- projectName = require(`${root}/val.config.ts`)?.config
398
- ?.project;
399
- } catch {
400
- // ignore
401
- }
402
- }
403
- if (!projectName) {
404
- try {
405
- // eslint-disable-next-line @typescript-eslint/no-var-requires
406
- projectName = require(`${root}/val.config.js`)?.config
407
- ?.project;
408
- } catch {
409
- // ignore
410
- }
390
+ projectName = valConfigFile?.project;
411
391
  }
412
392
  if (!projectName) {
413
393
  console.log(