@valbuild/cli 0.97.6 → 0.98.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/src/lsp.ts ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Start the Val language server.
3
+ *
4
+ * Editors normally resolve `@valbuild/language-server` from the project's
5
+ * `node_modules` and launch its `val-language-server` binary directly. This
6
+ * subcommand exists so the server is discoverable from the CLI and easy to
7
+ * start by hand when debugging an editor integration:
8
+ *
9
+ * npx val lsp --stdio
10
+ *
11
+ * The import is dynamic so that `vscode-languageserver` is not loaded on every
12
+ * `val` invocation.
13
+ */
14
+ export async function lsp(): Promise<void> {
15
+ const { main } = await import("@valbuild/language-server");
16
+ // Transport (`--stdio`, `--node-ipc`, `--socket=`) is read from argv by the
17
+ // server itself, so the flags pass straight through.
18
+ main();
19
+ }
@@ -1,100 +1,6 @@
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
- import { createRequire } from "node:module";
8
-
9
- const ValConfigSchema = z.object({
10
- project: z.string().optional(),
11
- root: z.string().optional(),
12
- files: z
13
- .object({
14
- directory: z.string().refine(
15
- (val): val is `/public` | `/public/${string}` =>
16
- (val === "/public" ||
17
- (val.startsWith("/public/") && !val.endsWith("/"))) &&
18
- // Reject path traversal so the directory cannot escape /public
19
- !val
20
- .split("/")
21
- .some((segment) => segment === "." || segment === ".."),
22
- {
23
- message:
24
- "files.directory must start with '/public', must not end with '/' and must not contain '.' or '..' segments",
25
- },
26
- ),
27
- })
28
- .optional(),
29
- gitCommit: z.string().optional(),
30
- gitBranch: z.string().optional(),
31
- defaultTheme: z.union([z.literal("light"), z.literal("dark")]).optional(),
32
- ai: z
33
- .object({
34
- commitMessages: z
35
- .object({
36
- disabled: z.boolean().optional(),
37
- })
38
- .optional(),
39
- })
40
- .optional(),
41
- });
42
-
43
- export async function evalValConfigFile(
44
- projectRoot: string,
45
- configFileName: string,
46
- ): Promise<ValConfig | null> {
47
- const valConfigPath = path.join(projectRoot, configFileName);
48
-
49
- let code: string | null = null;
50
- try {
51
- code = await fs.readFile(valConfigPath, "utf-8");
52
- } catch {
53
- //
54
- }
55
- if (!code) {
56
- return null;
57
- }
58
-
59
- const transpiled = ts.transpileModule(code, {
60
- compilerOptions: {
61
- target: ts.ScriptTarget.ES2020,
62
- module: ts.ModuleKind.CommonJS,
63
- esModuleInterop: true,
64
- },
65
- fileName: valConfigPath,
66
- });
67
-
68
- const projectRootRequire = createRequire(valConfigPath);
69
- const exportsObj = {};
70
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
- const sandbox: Record<string, any> = {
72
- exports: exportsObj,
73
- module: { exports: exportsObj },
74
- require: projectRootRequire, // NOTE: this is a security risk, but this code is running in the users own environment at the CLI level
75
- __filename: valConfigPath,
76
- __dirname: projectRoot,
77
- console,
78
- process,
79
- };
80
- sandbox.global = sandbox;
81
-
82
- const context = vm.createContext(sandbox);
83
- const script = new vm.Script(transpiled.outputText, {
84
- filename: valConfigPath,
85
- });
86
- script.runInContext(context);
87
- const valConfig = sandbox.module.exports.config;
88
- if (!valConfig) {
89
- throw Error(
90
- `Val config file at path: '${valConfigPath}' must export a config object. Got: ${valConfig}`,
91
- );
92
- }
93
- const result = ValConfigSchema.safeParse(valConfig);
94
- if (!result.success) {
95
- throw Error(
96
- `Val config file at path: '${valConfigPath}' has invalid schema: ${result.error.message}`,
97
- );
98
- }
99
- return result.data;
100
- }
1
+ /**
2
+ * Moved to `@valbuild/server` so that the CLI and
3
+ * `@valbuild/language-server` resolve project config through the same code.
4
+ * Re-exported here to keep existing CLI imports working.
5
+ */
6
+ export { evalValConfigFile, findAndEvalValConfigFile } from "@valbuild/server";
package/src/validate.ts CHANGED
@@ -4,7 +4,7 @@ import fs from "fs/promises";
4
4
  import { glob } from "fast-glob";
5
5
  import { DEFAULT_CONTENT_HOST, DEFAULT_VAL_REMOTE_HOST } from "@valbuild/core";
6
6
  import { getSettings, uploadRemoteFile } from "@valbuild/server";
7
- import { evalValConfigFile } from "./utils/evalValConfigFile";
7
+ import { findAndEvalValConfigFile } from "./utils/evalValConfigFile";
8
8
  import { createDefaultValFSHost, runValidation } from "./runValidation";
9
9
  import {
10
10
  sourcePathToCodeFrame,
@@ -49,9 +49,7 @@ export async function validate({
49
49
  // errors found. Re-reads config and val files each call so it always reflects
50
50
  // the latest state on disk (used both for one-shot and watch mode).
51
51
  async function runOnce(): Promise<number> {
52
- const valConfigFile =
53
- (await evalValConfigFile(projectRoot, "val.config.ts")) ||
54
- (await evalValConfigFile(projectRoot, "val.config.js"));
52
+ const valConfigFile = await findAndEvalValConfigFile(projectRoot);
55
53
 
56
54
  const resolvedValConfigFile = valConfigFile
57
55
  ? {