Skip to content

Commit 55a2318

Browse files
authored
Merge pull request #1145 from nojaf/pass-rescript-runtime-to-analysis
Pass RESCRIPT_RUNTIME env to analysis process
2 parents 7e10e03 + 1271e0d commit 55a2318

File tree

4 files changed

+139
-58
lines changed

4 files changed

+139
-58
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
- Paste as JSON.t or ReScript JSX in VSCode. https://github.com/rescript-lang/rescript-vscode/pull/1141
1818

19+
#### :bug: Bug fix
20+
21+
- Pass RESCRIPT_RUNTIME to analysis process. https://github.com/rescript-lang/rescript-vscode/pull/1145
22+
1923
## 1.66.0
2024

2125
#### :bug: Bug fix

server/src/bsc-args/rewatch.ts

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ import {
88
IncrementallyCompiledFileInfo,
99
} from "../incrementalCompilation";
1010
import type { projectFiles } from "../projectFiles";
11-
import config from "../config";
12-
import { findRescriptRuntimesInProject } from "../find-runtime";
1311
import { jsonrpcVersion } from "../constants";
1412

1513
export type RewatchCompilerArgs = {
@@ -20,39 +18,7 @@ export type RewatchCompilerArgs = {
2018
async function getRuntimePath(
2119
entry: IncrementallyCompiledFileInfo,
2220
): Promise<string | null> {
23-
let rescriptRuntime: string | null =
24-
config.extensionConfiguration.runtimePath ?? null;
25-
26-
if (rescriptRuntime !== null) {
27-
if (debug()) {
28-
console.log(
29-
`Using configured runtime path as RESCRIPT_RUNTIME: ${rescriptRuntime}`,
30-
);
31-
}
32-
return rescriptRuntime;
33-
}
34-
35-
const rescriptRuntimes = await findRescriptRuntimesInProject(
36-
entry.project.workspaceRootPath,
37-
);
38-
39-
if (debug()) {
40-
if (rescriptRuntimes.length === 0) {
41-
console.log(
42-
`Did not find @rescript/runtime directory for ${entry.project.workspaceRootPath}`,
43-
);
44-
} else if (rescriptRuntimes.length > 1) {
45-
console.warn(
46-
`Found multiple @rescript/runtime directories, using the first one as RESCRIPT_RUNTIME: ${rescriptRuntimes.join(", ")}`,
47-
);
48-
} else {
49-
console.log(
50-
`Found @rescript/runtime directory: ${rescriptRuntimes.join(", ")}`,
51-
);
52-
}
53-
}
54-
55-
return rescriptRuntimes.at(0) ?? null;
21+
return utils.getRuntimePathFromWorkspaceRoot(entry.project.workspaceRootPath);
5622
}
5723

5824
export async function getRewatchBscArgs(

server/src/incrementalCompilation.ts

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -262,33 +262,30 @@ function triggerIncrementalCompilationOfFile(
262262
return;
263263
}
264264

265-
const projectRewatchLockfiles = [
266-
...Array.from(workspaceFolders).map((w) =>
267-
path.resolve(w, c.rewatchLockPartialPath),
268-
),
269-
...Array.from(workspaceFolders).map((w) =>
270-
path.resolve(w, c.rescriptLockPartialPath),
271-
),
272-
path.resolve(projectRootPath, c.rewatchLockPartialPath),
273-
path.resolve(projectRootPath, c.rescriptLockPartialPath),
274-
];
275-
276-
let foundRewatchLockfileInProjectRoot = false;
277-
if (projectRewatchLockfiles.some((lockFile) => fs.existsSync(lockFile))) {
278-
foundRewatchLockfileInProjectRoot = true;
279-
} else if (debug()) {
265+
// computeWorkspaceRootPathFromLockfile returns null if lockfile found (local package) or if no parent found
266+
const computedWorkspaceRoot =
267+
utils.computeWorkspaceRootPathFromLockfile(projectRootPath);
268+
// If null, it means either a lockfile was found (local package) or no parent project root exists
269+
// In both cases, we default to projectRootPath
270+
const workspaceRootPath = computedWorkspaceRoot ?? projectRootPath;
271+
272+
// Determine if lockfile was found for debug logging
273+
// If computedWorkspaceRoot is null and projectRootPath is not null, check if parent exists
274+
const foundRewatchLockfileInProjectRoot =
275+
computedWorkspaceRoot == null &&
276+
projectRootPath != null &&
277+
utils.findProjectRootOfFile(projectRootPath, true) != null;
278+
279+
if (foundRewatchLockfileInProjectRoot && debug()) {
280280
console.log(
281-
`Did not find ${projectRewatchLockfiles.join(" or ")} in project root, assuming bsb`,
281+
`Found rewatch/rescript lockfile in project root, treating as local package in workspace`,
282+
);
283+
} else if (!foundRewatchLockfileInProjectRoot && debug()) {
284+
console.log(
285+
`Did not find rewatch/rescript lockfile in project root, assuming bsb`,
282286
);
283287
}
284288

285-
// if we find a rewatch.lock in the project root, it's a compilation of a local package
286-
// in the workspace.
287-
const workspaceRootPath =
288-
projectRootPath && !foundRewatchLockfileInProjectRoot
289-
? utils.findProjectRootOfFile(projectRootPath, true)
290-
: null;
291-
292289
const bscBinaryLocation = project.bscBinaryLocation;
293290
if (bscBinaryLocation == null) {
294291
if (debug())

server/src/utils.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ import * as lookup from "./lookup";
1717
import { reportError } from "./errorReporter";
1818
import config from "./config";
1919
import { filesDiagnostics, projectsFiles } from "./projectFiles";
20+
import { workspaceFolders } from "./server";
21+
import { rewatchLockPartialPath, rescriptLockPartialPath } from "./constants";
22+
import { findRescriptRuntimesInProject } from "./find-runtime";
2023

2124
let tempFilePrefix = "rescript_format_file_" + process.pid + "_";
2225
let tempFileId = 0;
@@ -301,6 +304,12 @@ export let runAnalysisAfterSanityCheck = async (
301304
binaryPath = builtinBinaryPath;
302305
}
303306

307+
let runtime: string | undefined = undefined;
308+
if (semver.gt(rescriptVersion as string, "12.0.0-rc.1")) {
309+
const runtimePath = await getRuntimePathFromProjectRoot(projectRootPath);
310+
runtime = runtimePath ?? undefined;
311+
}
312+
304313
let options: childProcess.ExecFileSyncOptions = {
305314
cwd: projectRootPath || undefined,
306315
maxBuffer: Infinity,
@@ -315,6 +324,7 @@ export let runAnalysisAfterSanityCheck = async (
315324
config.extensionConfiguration.cache?.projectConfig?.enable === true
316325
? "true"
317326
: undefined,
327+
RESCRIPT_RUNTIME: runtime,
318328
},
319329
};
320330

@@ -372,6 +382,110 @@ export const toCamelCase = (text: string): string => {
372382
.replace(/(\s|-)+/g, "");
373383
};
374384

385+
/**
386+
* Computes the workspace root path from a project root path by checking for rewatch/rescript lockfiles.
387+
* In a monorepo, this finds the parent project root that contains the workspace.
388+
* If a rewatch/rescript lockfile is found in the project root, it's a local package
389+
* in the workspace, so we return null (which will default to projectRootPath).
390+
*/
391+
export function computeWorkspaceRootPathFromLockfile(
392+
projectRootPath: string | null,
393+
): string | null {
394+
if (projectRootPath == null) {
395+
return null;
396+
}
397+
398+
const projectRewatchLockfiles = [
399+
...Array.from(workspaceFolders).map((w) =>
400+
path.resolve(w, rewatchLockPartialPath),
401+
),
402+
...Array.from(workspaceFolders).map((w) =>
403+
path.resolve(w, rescriptLockPartialPath),
404+
),
405+
path.resolve(projectRootPath, rewatchLockPartialPath),
406+
path.resolve(projectRootPath, rescriptLockPartialPath),
407+
];
408+
409+
const foundRewatchLockfileInProjectRoot = projectRewatchLockfiles.some(
410+
(lockFile) => fs.existsSync(lockFile),
411+
);
412+
413+
// if we find a rewatch.lock in the project root, it's a compilation of a local package
414+
// in the workspace.
415+
return !foundRewatchLockfileInProjectRoot
416+
? findProjectRootOfFile(projectRootPath, true)
417+
: null;
418+
}
419+
420+
// Shared cache: key is either workspace root path or project root path
421+
const runtimePathCache = new Map<string, string | null>();
422+
423+
/**
424+
* Gets the runtime path from a workspace root path.
425+
* This function is cached per workspace root path.
426+
*/
427+
export async function getRuntimePathFromWorkspaceRoot(
428+
workspaceRootPath: string,
429+
): Promise<string | null> {
430+
// Check cache first
431+
if (runtimePathCache.has(workspaceRootPath)) {
432+
return runtimePathCache.get(workspaceRootPath)!;
433+
}
434+
435+
// Compute and cache
436+
let rescriptRuntime: string | null =
437+
config.extensionConfiguration.runtimePath ?? null;
438+
439+
if (rescriptRuntime !== null) {
440+
runtimePathCache.set(workspaceRootPath, rescriptRuntime);
441+
return rescriptRuntime;
442+
}
443+
444+
const rescriptRuntimes =
445+
await findRescriptRuntimesInProject(workspaceRootPath);
446+
447+
const result = rescriptRuntimes.at(0) ?? null;
448+
runtimePathCache.set(workspaceRootPath, result);
449+
return result;
450+
}
451+
452+
/**
453+
* Gets the runtime path from a project root path.
454+
* Computes the workspace root path and then resolves the runtime.
455+
* This function is cached per project root path.
456+
*/
457+
export async function getRuntimePathFromProjectRoot(
458+
projectRootPath: string | null,
459+
): Promise<string | null> {
460+
if (projectRootPath == null) {
461+
return null;
462+
}
463+
464+
// Check cache first (keyed by projectRootPath)
465+
if (runtimePathCache.has(projectRootPath)) {
466+
return runtimePathCache.get(projectRootPath)!;
467+
}
468+
469+
// Compute workspace root and resolve runtime
470+
const workspaceRootPath =
471+
computeWorkspaceRootPathFromLockfile(projectRootPath) ?? projectRootPath;
472+
473+
// Check cache again with workspace root (might have been cached from a previous call)
474+
if (runtimePathCache.has(workspaceRootPath)) {
475+
const result = runtimePathCache.get(workspaceRootPath)!;
476+
// Cache it under projectRootPath too for faster lookup next time
477+
runtimePathCache.set(projectRootPath, result);
478+
return result;
479+
}
480+
481+
// Compute and cache
482+
const result = await getRuntimePathFromWorkspaceRoot(workspaceRootPath);
483+
// Cache it under both keys
484+
runtimePathCache.set(workspaceRootPath, result);
485+
runtimePathCache.set(projectRootPath, result);
486+
return result;
487+
}
488+
375489
export const getNamespaceNameFromConfigFile = (
376490
projDir: p.DocumentUri,
377491
): execResult => {

0 commit comments

Comments
 (0)