From 0b1fc72edbaa7d0986985cdef516363e1de44731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 22:49:41 +0100 Subject: [PATCH 01/40] Add semver dep --- package-lock.json | 70 ++++++++++++++++------------------------------- package.json | 3 +- 2 files changed, 25 insertions(+), 48 deletions(-) diff --git a/package-lock.json b/package-lock.json index e45304ee5..cdb14e482 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,10 @@ "license": "MIT", "devDependencies": { "@types/node": "^14.14.41", + "@types/semver": "^7.7.0", "@types/vscode": "1.68.0", "esbuild": "^0.20.1", - "semver": "^7.3.7", + "semver": "^7.7.2", "typescript": "^4.7.3" }, "engines": { @@ -394,6 +395,13 @@ "integrity": "sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g==", "dev": true }, + "node_modules/@types/semver": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz", + "integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/vscode": { "version": "1.68.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.68.0.tgz", @@ -438,26 +446,12 @@ "@esbuild/win32-x64": "0.20.1" } }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -477,12 +471,6 @@ "engines": { "node": ">=4.2.0" } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true } }, "dependencies": { @@ -653,6 +641,12 @@ "integrity": "sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g==", "dev": true }, + "@types/semver": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz", + "integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==", + "dev": true + }, "@types/vscode": { "version": "1.68.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.68.0.tgz", @@ -690,35 +684,17 @@ "@esbuild/win32-x64": "0.20.1" } }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true }, "typescript": { "version": "4.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true } } } diff --git a/package.json b/package.json index 5f9ae3e91..b54a8d3d4 100644 --- a/package.json +++ b/package.json @@ -255,9 +255,10 @@ }, "devDependencies": { "@types/node": "^14.14.41", + "@types/semver": "^7.7.0", "@types/vscode": "1.68.0", "esbuild": "^0.20.1", - "semver": "^7.3.7", + "semver": "^7.7.2", "typescript": "^4.7.3" } } From 4af5bd7fcc4228d2b79a4bb780058eb30936ddf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 22:50:43 +0100 Subject: [PATCH 02/40] Create async version of utils.findBinary --- server/src/utils.ts | 140 ++++++++++++++++++++++++++++++-------------- 1 file changed, 97 insertions(+), 43 deletions(-) diff --git a/server/src/utils.ts b/server/src/utils.ts index dbb63a526..043051fd1 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -7,7 +7,9 @@ import { ResponseMessage, } from "vscode-languageserver-protocol"; import fs from "fs"; +import fsAsync from "fs/promises"; import * as os from "os"; +import semver from "semver"; import * as codeActions from "./codeActions"; import * as c from "./constants"; @@ -90,6 +92,101 @@ export let findBinary = ( } }; +let findPlatformPath = (projectRootPath: p.DocumentUri | null) => { + if (config.extensionConfiguration.platformPath != null) { + return config.extensionConfiguration.platformPath; + } + + let rescriptDir = lookup.findFilePathFromProjectRoot( + projectRootPath, + path.join("node_modules", "rescript") + ); + if (rescriptDir == null) { + return null; + } + + let platformPath = path.join(rescriptDir, c.platformDir); + + // Binaries have been split into optional platform-specific dependencies + // since v12.0.0-alpha.13 + if (!fs.existsSync(platformPath)) { + platformPath = path.join( + rescriptDir, + "..", + `@rescript/${process.platform}-${process.arch}/bin` + ) + } + + // Workaround for darwinarm64 which has no folder yet in ReScript <= 9.1.4 + if ( + process.platform == "darwin" && + process.arch == "arm64" && + !fs.existsSync(platformPath) + ) { + platformPath = path.join(rescriptDir, process.platform); + } + + return platformPath; +}; + +export let findBscExeBinary = (projectRootPath: p.DocumentUri | null) => + findBinary(findPlatformPath(projectRootPath), c.bscExeName); + +export let findEditorAnalysisBinary = (projectRootPath: p.DocumentUri | null) => + findBinary(findPlatformPath(projectRootPath), c.editorAnalysisName); + +// If ReScript < 12.0.0-alpha.13, then we want `{project_root}/node_modules/rescript/{c.platformDir}/{binary}`. +// Otherwise, we want to dynamically import `{project_root}/node_modules/rescript` and from `binPaths` get the relevant binary. +// We won't know which version is in the project root until we read and parse `{project_root}/node_modules/rescript/package.json` +let findBinaryAsync = async ( + projectRootPath: p.DocumentUri | null, + binary: "bsc.exe" | "rescript-editor-analysis.exe" +) => { + if (config.extensionConfiguration.platformPath != null) { + return path.join(config.extensionConfiguration.platformPath, binary); + } + + const rescriptDir = lookup.findFilePathFromProjectRoot( + projectRootPath, + path.join("node_modules", "rescript") + ); + if (rescriptDir == null) { + return null; + } + + let rescriptVersion = null; + try { + const rescriptPackageJSONPath = path.join(rescriptDir, "package.json"); + const rescriptPackageJSON = JSON.parse(await fsAsync.readFile(rescriptPackageJSONPath, "utf-8")); + rescriptVersion = rescriptPackageJSON.version + } catch (error) { + return null + } + + let binaryPath: string | null = null + if (semver.gte(rescriptVersion, "12.0.0-alpha.13")) { + // TODO: export `binPaths` from `rescript` package so that we don't need to + // copy the logic for figuring out `target`. + const target = `${process.platform}-${process.arch}`; + const targetPackagePath = path.join(rescriptDir, "..", `@rescript/${target}`) + const { binPaths } = await import(targetPackagePath); + + if (binary == "bsc.exe") { + binaryPath = binPaths.bsc_exe + } else if (binary == "rescript-editor-analysis.exe") { + binaryPath = binPaths.rescript_editor_analysis_exe + } + } else { + binaryPath = path.join(rescriptDir, c.platformDir, binary) + } + + if (binaryPath != null && fs.existsSync(binaryPath)) { + return binaryPath + } else { + return null + } +} + type execResult = | { kind: "success"; @@ -723,46 +820,3 @@ export let rangeContainsRange = ( } return true; }; - -let findPlatformPath = (projectRootPath: p.DocumentUri | null) => { - if (config.extensionConfiguration.platformPath != null) { - return config.extensionConfiguration.platformPath; - } - - let rescriptDir = lookup.findFilePathFromProjectRoot( - projectRootPath, - path.join("node_modules", "rescript") - ); - if (rescriptDir == null) { - return null; - } - - let platformPath = path.join(rescriptDir, c.platformDir); - - // Binaries have been split into optional platform-specific dependencies - // since v12.0.0-alpha.13 - if (!fs.existsSync(platformPath)) { - platformPath = path.join( - rescriptDir, - "..", - `@rescript/${process.platform}-${process.arch}/bin` - ) - } - - // Workaround for darwinarm64 which has no folder yet in ReScript <= 9.1.4 - if ( - process.platform == "darwin" && - process.arch == "arm64" && - !fs.existsSync(platformPath) - ) { - platformPath = path.join(rescriptDir, process.platform); - } - - return platformPath; -}; - -export let findBscExeBinary = (projectRootPath: p.DocumentUri | null) => - findBinary(findPlatformPath(projectRootPath), c.bscExeName); - -export let findEditorAnalysisBinary = (projectRootPath: p.DocumentUri | null) => - findBinary(findPlatformPath(projectRootPath), c.editorAnalysisName); From cecf7c41c00f498196e5a6557f7213c683721ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 22:59:21 +0100 Subject: [PATCH 03/40] Make findBscExeBinary and findEditorAnalysisBinary async --- server/src/server.ts | 10 +++++----- server/src/utils.ts | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index d7800c048..3dcfefe8b 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -247,7 +247,7 @@ type clientSentBuildAction = { title: string; projectRootPath: string; }; -let openedFile = (fileUri: string, fileContent: string) => { +let openedFile = async (fileUri: string, fileContent: string) => { let filePath = fileURLToPath(fileUri); stupidFileContentCache.set(filePath, fileContent); @@ -270,8 +270,8 @@ let openedFile = (fileUri: string, fileContent: string) => { namespaceName.kind === "success" ? namespaceName.result : null, rescriptVersion: utils.findReScriptVersionForProjectRoot(projectRootPath), bsbWatcherByEditor: null, - bscBinaryLocation: utils.findBscExeBinary(projectRootPath), - editorAnalysisLocation: utils.findEditorAnalysisBinary(projectRootPath), + bscBinaryLocation: await utils.findBscExeBinary(projectRootPath), + editorAnalysisLocation: await utils.findEditorAnalysisBinary(projectRootPath), hasPromptedToStartBuild: /(\/|\\)node_modules(\/|\\)/.test( projectRootPath ) @@ -1036,7 +1036,7 @@ function openCompiledFile(msg: p.RequestMessage): p.Message { return response; } -function onMessage(msg: p.Message) { +async function onMessage(msg: p.Message) { if (p.Message.isNotification(msg)) { // notification message, aka the client ends it and doesn't want a reply if (!initialized && msg.method !== "exit") { @@ -1052,7 +1052,7 @@ function onMessage(msg: p.Message) { } } else if (msg.method === DidOpenTextDocumentNotification.method) { let params = msg.params as p.DidOpenTextDocumentParams; - openedFile(params.textDocument.uri, params.textDocument.text); + await openedFile(params.textDocument.uri, params.textDocument.text); updateDiagnosticSyntax(params.textDocument.uri, params.textDocument.text); } else if (msg.method === DidChangeTextDocumentNotification.method) { let params = msg.params as p.DidChangeTextDocumentParams; diff --git a/server/src/utils.ts b/server/src/utils.ts index 043051fd1..9eb563807 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -129,12 +129,6 @@ let findPlatformPath = (projectRootPath: p.DocumentUri | null) => { return platformPath; }; -export let findBscExeBinary = (projectRootPath: p.DocumentUri | null) => - findBinary(findPlatformPath(projectRootPath), c.bscExeName); - -export let findEditorAnalysisBinary = (projectRootPath: p.DocumentUri | null) => - findBinary(findPlatformPath(projectRootPath), c.editorAnalysisName); - // If ReScript < 12.0.0-alpha.13, then we want `{project_root}/node_modules/rescript/{c.platformDir}/{binary}`. // Otherwise, we want to dynamically import `{project_root}/node_modules/rescript` and from `binPaths` get the relevant binary. // We won't know which version is in the project root until we read and parse `{project_root}/node_modules/rescript/package.json` @@ -187,6 +181,12 @@ let findBinaryAsync = async ( } } +export let findBscExeBinary = (projectRootPath: p.DocumentUri | null) => + findBinaryAsync(projectRootPath, "bsc.exe"); + +export let findEditorAnalysisBinary = (projectRootPath: p.DocumentUri | null) => + findBinaryAsync(projectRootPath, "rescript-editor-analysis.exe"); + type execResult = | { kind: "success"; From df29b181c53be61a680c01cd6f18177a5ef422bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:03:01 +0100 Subject: [PATCH 04/40] Remove unused constants --- server/src/constants.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/server/src/constants.ts b/server/src/constants.ts index a65bc133a..fcfc08b1d 100644 --- a/server/src/constants.ts +++ b/server/src/constants.ts @@ -7,14 +7,9 @@ export let platformDir = // See https://microsoft.github.io/language-server-protocol/specification Abstract Message // version is fixed to 2.0 export let jsonrpcVersion = "2.0"; -export let platformPath = path.join("rescript", platformDir); -export let nodeModulesPlatformPath = path.join("node_modules", platformPath); + export let bscExeName = "bsc.exe"; export let editorAnalysisName = "rescript-editor-analysis.exe"; -export let bscNativeReScriptPartialPath = path.join( - nodeModulesPlatformPath, - bscExeName -); export let builtinAnalysisDevPath = path.join( path.dirname(__dirname), From f4cde5a0a9b27b95a618b3d95bf157da8fa206f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:13:24 +0100 Subject: [PATCH 05/40] Make utils.runAnalysisAfterSanityCheck async --- server/src/codeActions.ts | 30 ++++++++++++++-------------- server/src/incrementalCompilation.ts | 2 +- server/src/server.ts | 12 +++++------ server/src/utils.ts | 8 ++++---- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/server/src/codeActions.ts b/server/src/codeActions.ts index d790f3616..77d82e3a2 100644 --- a/server/src/codeActions.ts +++ b/server/src/codeActions.ts @@ -141,14 +141,14 @@ let takeUntil = (array: string[], startsWith: string): string[] => { return res; }; -export let findCodeActionsInDiagnosticsMessage = ({ +export let findCodeActionsInDiagnosticsMessage = async ({ diagnostic, diagnosticMessage, file, range, addFoundActionsHere: codeActions, }: findCodeActionsConfig) => { - diagnosticMessage.forEach((line, index, array) => { + for (const [index, line] of diagnosticMessage.entries()) { // Because of how actions work, there can only be one per diagnostic. So, // halt whenever a code action has been found. let codeActionExtractors = [ @@ -166,8 +166,8 @@ export let findCodeActionsInDiagnosticsMessage = ({ let didFindAction = false; try { - didFindAction = extractCodeAction({ - array, + didFindAction = await extractCodeAction({ + array: diagnosticMessage, codeActions, diagnostic, file, @@ -183,7 +183,7 @@ export let findCodeActionsInDiagnosticsMessage = ({ break; } } - }); + } }; interface codeActionExtractorConfig { @@ -196,12 +196,12 @@ interface codeActionExtractorConfig { codeActions: filesCodeActions; } -type codeActionExtractor = (config: codeActionExtractorConfig) => boolean; +type codeActionExtractor = (config: codeActionExtractorConfig) => Promise; // This action extracts hints the compiler emits for misspelled identifiers, and // offers to replace the misspelled name with the correct name suggested by the // compiler. -let didYouMeanAction: codeActionExtractor = ({ +let didYouMeanAction: codeActionExtractor = async ({ codeActions, diagnostic, file, @@ -245,7 +245,7 @@ let didYouMeanAction: codeActionExtractor = ({ }; // This action offers to wrap patterns that aren't option in Some. -let wrapInSome: codeActionExtractor = ({ +let wrapInSome: codeActionExtractor = async ({ codeActions, diagnostic, file, @@ -425,7 +425,7 @@ let handleUndefinedRecordFieldsAction = ({ // being undefined. We then offers an action that inserts all of the record // fields, with an `assert false` dummy value. `assert false` is so applying the // code action actually compiles. -let addUndefinedRecordFieldsV10: codeActionExtractor = ({ +let addUndefinedRecordFieldsV10: codeActionExtractor = async ({ array, codeActions, diagnostic, @@ -459,7 +459,7 @@ let addUndefinedRecordFieldsV10: codeActionExtractor = ({ return false; }; -let addUndefinedRecordFieldsV11: codeActionExtractor = ({ +let addUndefinedRecordFieldsV11: codeActionExtractor = async ({ array, codeActions, diagnostic, @@ -508,7 +508,7 @@ let addUndefinedRecordFieldsV11: codeActionExtractor = ({ // This action detects suggestions of converting between mismatches in types // that the compiler tells us about. -let simpleConversion: codeActionExtractor = ({ +let simpleConversion: codeActionExtractor = async ({ line, codeActions, file, @@ -554,7 +554,7 @@ let simpleConversion: codeActionExtractor = ({ // This action will apply a curried function (essentially inserting a dot in the // correct place). -let applyUncurried: codeActionExtractor = ({ +let applyUncurried: codeActionExtractor = async ({ line, codeActions, file, @@ -608,7 +608,7 @@ let applyUncurried: codeActionExtractor = ({ // This action detects missing cases for exhaustive pattern matches, and offers // to insert dummy branches (using `failwith("TODO")`) for those branches. -let simpleAddMissingCases: codeActionExtractor = ({ +let simpleAddMissingCases: codeActionExtractor = async ({ line, codeActions, file, @@ -629,7 +629,7 @@ let simpleAddMissingCases: codeActionExtractor = ({ let filePath = fileURLToPath(file); - let newSwitchCode = utils.runAnalysisAfterSanityCheck(filePath, [ + let newSwitchCode = await utils.runAnalysisAfterSanityCheck(filePath, [ "codemod", filePath, range.start.line, @@ -665,7 +665,7 @@ let simpleAddMissingCases: codeActionExtractor = ({ // This detects concrete variables or values put in a position which expects an // optional of that same type, and offers to wrap the value/variable in // `Some()`. -let simpleTypeMismatches: codeActionExtractor = ({ +let simpleTypeMismatches: codeActionExtractor = async ({ line, codeActions, file, diff --git a/server/src/incrementalCompilation.ts b/server/src/incrementalCompilation.ts index 2cca64ae8..e1381b640 100644 --- a/server/src/incrementalCompilation.ts +++ b/server/src/incrementalCompilation.ts @@ -644,7 +644,7 @@ async function compileContents( } // Reset compilation status as this compilation finished entry.compilation = null; - const { result, codeActions } = utils.parseCompilerLogOutput( + const { result, codeActions } = await utils.parseCompilerLogOutput( `${stderr}\n#Done()` ); diff --git a/server/src/server.ts b/server/src/server.ts index 3dcfefe8b..69264a7e8 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -102,7 +102,7 @@ let sendUpdatedDiagnostics = () => { result: filesAndErrors, codeActions, linesWithParseErrors, - } = utils.parseCompilerLogOutput(content); + } = await utils.parseCompilerLogOutput(content); if (linesWithParseErrors.length > 0) { let params: p.ShowMessageParams = { @@ -192,7 +192,7 @@ let debug = false; let syncProjectConfigCache = (rootPath: string) => { try { if (debug) console.log("syncing project config cache for " + rootPath); - utils.runAnalysisAfterSanityCheck(rootPath, ["cache-project", rootPath]); + await utils.runAnalysisAfterSanityCheck(rootPath, ["cache-project", rootPath]); if (debug) console.log("OK - synced project config cache for " + rootPath); } catch (e) { if (debug) console.error(e); @@ -202,7 +202,7 @@ let syncProjectConfigCache = (rootPath: string) => { let deleteProjectConfigCache = (rootPath: string) => { try { if (debug) console.log("deleting project config cache for " + rootPath); - utils.runAnalysisAfterSanityCheck(rootPath, ["cache-delete", rootPath]); + await utils.runAnalysisAfterSanityCheck(rootPath, ["cache-delete", rootPath]); if (debug) console.log("OK - deleted project config cache for " + rootPath); } catch (e) { if (debug) console.error(e); @@ -600,7 +600,7 @@ function rename(msg: p.RequestMessage) { let params = msg.params as p.RenameParams; let filePath = fileURLToPath(params.textDocument.uri); let documentChanges: (p.RenameFile | p.TextDocumentEdit)[] | null = - utils.runAnalysisAfterSanityCheck(filePath, [ + await utils.runAnalysisAfterSanityCheck(filePath, [ "rename", filePath, params.position.line, @@ -705,7 +705,7 @@ function completionResolve(msg: p.RequestMessage) { if (item.documentation == null && item.data != null) { const data = item.data as { filePath: string; modulePath: string }; - let result = utils.runAnalysisAfterSanityCheck( + let result = await utils.runAnalysisAfterSanityCheck( data.filePath, ["completionResolve", data.filePath, data.modulePath], true @@ -851,7 +851,7 @@ let updateDiagnosticSyntax = (fileUri: string, fileContent: string) => { let compilerDiagnosticsForFile = getCurrentCompilerDiagnosticsForFile(fileUri); let syntaxDiagnosticsForFile: p.Diagnostic[] = - utils.runAnalysisAfterSanityCheck(filePath, ["diagnosticSyntax", tmpname]); + await utils.runAnalysisAfterSanityCheck(filePath, ["diagnosticSyntax", tmpname]); let notification: p.NotificationMessage = { jsonrpc: c.jsonrpcVersion, diff --git a/server/src/utils.ts b/server/src/utils.ts index 9eb563807..3a3937433 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -283,7 +283,7 @@ if (fs.existsSync(c.builtinAnalysisDevPath)) { builtinBinaryPath = c.builtinAnalysisProdPath; } -export let runAnalysisAfterSanityCheck = ( +export let runAnalysisAfterSanityCheck = async ( filePath: p.DocumentUri, args: Array, projectRequired = false @@ -294,7 +294,7 @@ export let runAnalysisAfterSanityCheck = ( } let rescriptVersion = projectsFiles.get(projectRootPath ?? "")?.rescriptVersion ?? - findReScriptVersion(filePath); + await findReScriptVersion(filePath); let binaryPath = builtinBinaryPath; @@ -366,7 +366,7 @@ export let runAnalysisCommand = ( msg: RequestMessage, projectRequired = true ) => { - let result = runAnalysisAfterSanityCheck(filePath, args, projectRequired); + let result = await runAnalysisAfterSanityCheck(filePath, args, projectRequired); let response: ResponseMessage = { jsonrpc: c.jsonrpcVersion, id: msg.id, @@ -379,7 +379,7 @@ export let getReferencesForPosition = ( filePath: p.DocumentUri, position: p.Position ) => - runAnalysisAfterSanityCheck(filePath, [ + await runAnalysisAfterSanityCheck(filePath, [ "references", filePath, position.line, From d729e3a1ea9a004aef6d169f516b84341a91c587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:19:57 +0100 Subject: [PATCH 06/40] Make parseCompilerLogOutput async --- server/src/utils.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/server/src/utils.ts b/server/src/utils.ts index 3a3937433..bfbbbb6bb 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -237,9 +237,9 @@ export let formatCode = ( } }; -export let findReScriptVersion = ( +export let findReScriptVersion = async ( filePath: p.DocumentUri -): string | undefined => { +): Promise => { let projectRoot = findProjectRootOfFile(filePath); if (projectRoot == null) { return undefined; @@ -260,7 +260,7 @@ export let findReScriptVersion = ( } }; -export function findReScriptVersionForProjectRoot(projectRootPath:string) : string | undefined { +export function findReScriptVersionForProjectRoot(projectRootPath: string) : string | undefined { const bscExe = findBinary(findPlatformPath(projectRootPath), c.bscExeName); if (bscExe == null) { @@ -605,9 +605,9 @@ type parsedCompilerLogResult = { codeActions: codeActions.filesCodeActions; linesWithParseErrors: string[]; }; -export let parseCompilerLogOutput = ( +export let parseCompilerLogOutput = async ( content: string -): parsedCompilerLogResult => { +): Promise => { type parsedDiagnostic = { code: number | undefined; severity: t.DiagnosticSeverity; @@ -752,7 +752,7 @@ export let parseCompilerLogOutput = ( let result: filesDiagnostics = {}; let foundCodeActions: codeActions.filesCodeActions = {}; - parsedDiagnostics.forEach((parsedDiagnostic) => { + for (const parsedDiagnostic of parsedDiagnostics) { let [fileAndRangeLine, ...diagnosticMessage] = parsedDiagnostic.content; let { file, range } = parseFileAndRange(fileAndRangeLine); @@ -771,7 +771,7 @@ export let parseCompilerLogOutput = ( }; // Check for potential code actions - codeActions.findCodeActionsInDiagnosticsMessage({ + await codeActions.findCodeActionsInDiagnosticsMessage({ addFoundActionsHere: foundCodeActions, diagnostic, diagnosticMessage, @@ -780,7 +780,7 @@ export let parseCompilerLogOutput = ( }); result[file].push(diagnostic); - }); + } return { done, From f77e6dd7f8e57325034a83d8195e01233a03609d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:20:27 +0100 Subject: [PATCH 07/40] Make server.sendUpdatedDiagnostics async --- server/src/server.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index 69264a7e8..1cef17052 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -92,8 +92,9 @@ let getCurrentCompilerDiagnosticsForFile = ( return diagnostics ?? []; }; -let sendUpdatedDiagnostics = () => { - projectsFiles.forEach((projectFile, projectRootPath) => { + +let sendUpdatedDiagnostics = async () => { + for (const [projectRootPath, projectFile] of projectsFiles) { let { filesWithDiagnostics } = projectFile; let compilerLogPath = path.join(projectRootPath, c.compilerLogPartialPath); let content = fs.readFileSync(compilerLogPath, { encoding: "utf-8" }); @@ -154,8 +155,9 @@ let sendUpdatedDiagnostics = () => { } }); } - }); + } }; + let deleteProjectDiagnostics = (projectRootPath: string) => { let root = projectsFiles.get(projectRootPath); if (root != null) { @@ -178,6 +180,7 @@ let deleteProjectDiagnostics = (projectRootPath: string) => { } } }; + let sendCompilationFinishedMessage = () => { let notification: p.NotificationMessage = { jsonrpc: c.jsonrpcVersion, @@ -215,7 +218,7 @@ let compilerLogsWatcher = chokidar stabilityThreshold: 1, }, }) - .on("all", (_e, changedPath) => { + .on("all", async (_e, changedPath) => { if (changedPath.includes("build.ninja")) { if (config.extensionConfiguration.cache?.projectConfig?.enable === true) { let projectRoot = utils.findProjectRootOfFile(changedPath); @@ -225,7 +228,7 @@ let compilerLogsWatcher = chokidar } } else { try { - sendUpdatedDiagnostics(); + await sendUpdatedDiagnostics(); sendCompilationFinishedMessage(); if (config.extensionConfiguration.inlayHints?.enable === true) { sendInlayHintsRefresh(); From 461250413f8ed51fb1a6e595b3699f0a0cee81b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:21:48 +0100 Subject: [PATCH 08/40] Make server.syncProjectConfigCache async --- server/src/server.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index 1cef17052..77b49f5e6 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -192,7 +192,7 @@ let sendCompilationFinishedMessage = () => { let debug = false; -let syncProjectConfigCache = (rootPath: string) => { +let syncProjectConfigCache = async (rootPath: string) => { try { if (debug) console.log("syncing project config cache for " + rootPath); await utils.runAnalysisAfterSanityCheck(rootPath, ["cache-project", rootPath]); @@ -223,7 +223,7 @@ let compilerLogsWatcher = chokidar if (config.extensionConfiguration.cache?.projectConfig?.enable === true) { let projectRoot = utils.findProjectRootOfFile(changedPath); if (projectRoot != null) { - syncProjectConfigCache(projectRoot); + await syncProjectConfigCache(projectRoot); } } } else { @@ -289,7 +289,7 @@ let openedFile = async (fileUri: string, fileContent: string) => { compilerLogsWatcher.add( path.join(projectRootPath, c.buildNinjaPartialPath) ); - syncProjectConfigCache(projectRootPath); + await syncProjectConfigCache(projectRootPath); } } let root = projectsFiles.get(projectRootPath)!; From f642b2435009c96cc87877ad84e9a8015f930205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:23:02 +0100 Subject: [PATCH 09/40] Make server.closedFile async --- server/src/server.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index 77b49f5e6..cae4be577 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -202,7 +202,7 @@ let syncProjectConfigCache = async (rootPath: string) => { } }; -let deleteProjectConfigCache = (rootPath: string) => { +let deleteProjectConfigCache = async (rootPath: string) => { try { if (debug) console.log("deleting project config cache for " + rootPath); await utils.runAnalysisAfterSanityCheck(rootPath, ["cache-delete", rootPath]); @@ -350,7 +350,7 @@ let openedFile = async (fileUri: string, fileContent: string) => { } }; -let closedFile = (fileUri: string) => { +let closedFile = async (fileUri: string) => { let filePath = fileURLToPath(fileUri); if (config.extensionConfiguration.incrementalTypechecking?.enable) { @@ -372,7 +372,7 @@ let closedFile = (fileUri: string) => { compilerLogsWatcher.unwatch( path.join(projectRootPath, c.buildNinjaPartialPath) ); - deleteProjectConfigCache(projectRootPath); + await deleteProjectConfigCache(projectRootPath); deleteProjectDiagnostics(projectRootPath); if (root.bsbWatcherByEditor !== null) { root.bsbWatcherByEditor.kill(); @@ -1078,7 +1078,7 @@ async function onMessage(msg: p.Message) { } } else if (msg.method === DidCloseTextDocumentNotification.method) { let params = msg.params as p.DidCloseTextDocumentParams; - closedFile(params.textDocument.uri); + await closedFile(params.textDocument.uri); } else if (msg.method === DidChangeConfigurationNotification.type.method) { // Can't seem to get this notification to trigger, but if it does this will be here and ensure we're synced up at the server. askForAllCurrentConfiguration(); From e94489046981ae946f5f0669efb907651acad029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:24:35 +0100 Subject: [PATCH 10/40] Make server.rename async --- server/src/server.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index cae4be577..b8e661021 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -598,7 +598,7 @@ function prepareRename(msg: p.RequestMessage): p.ResponseMessage { }; } -function rename(msg: p.RequestMessage) { +async function rename(msg: p.RequestMessage) { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename let params = msg.params as p.RenameParams; let filePath = fileURLToPath(params.textDocument.uri); @@ -1234,7 +1234,7 @@ async function onMessage(msg: p.Message) { } else if (msg.method === p.PrepareRenameRequest.method) { send(prepareRename(msg)); } else if (msg.method === p.RenameRequest.method) { - send(rename(msg)); + send(await rename(msg)); } else if (msg.method === p.DocumentSymbolRequest.method) { send(documentSymbol(msg)); } else if (msg.method === p.CompletionRequest.method) { From 8ee099463260d32e76004f44b08d598c71f10b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:25:26 +0100 Subject: [PATCH 11/40] Make server.completionResolve async --- server/src/server.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index b8e661021..7525116a7 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -698,7 +698,7 @@ function completion(msg: p.RequestMessage) { return response; } -function completionResolve(msg: p.RequestMessage) { +async function completionResolve(msg: p.RequestMessage) { const item = msg.params as p.CompletionItem; let response: p.ResponseMessage = { jsonrpc: c.jsonrpcVersion, @@ -1240,7 +1240,7 @@ async function onMessage(msg: p.Message) { } else if (msg.method === p.CompletionRequest.method) { send(completion(msg)); } else if (msg.method === p.CompletionResolveRequest.method) { - send(completionResolve(msg)); + send(await completionResolve(msg)); } else if (msg.method === p.SemanticTokensRequest.method) { send(semanticTokens(msg)); } else if (msg.method === p.CodeActionRequest.method) { From 015adaf25fb86bfc5830c778abcc6f0edd33253c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:25:35 +0100 Subject: [PATCH 12/40] Trim trailing whitespace --- server/src/server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/server.ts b/server/src/server.ts index 7525116a7..428938f48 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -1330,7 +1330,7 @@ onErrorReported((msg) => { let params: p.ShowMessageParams = { type: p.MessageType.Warning, message: `ReScript tooling: Internal error. Something broke. Here's the error message that you can report if you want: - + ${msg} (this message will only be reported once every 15 minutes)`, From 74178cb833810189372e6169d430c71cd779701e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:26:26 +0100 Subject: [PATCH 13/40] Use async allback to child_process.execFile in incrementalCompilation.compileContents --- server/src/incrementalCompilation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/incrementalCompilation.ts b/server/src/incrementalCompilation.ts index e1381b640..991bb9840 100644 --- a/server/src/incrementalCompilation.ts +++ b/server/src/incrementalCompilation.ts @@ -619,7 +619,7 @@ async function compileContents( entry.project.bscBinaryLocation, callArgs, { cwd: entry.project.rootPath }, - (error, _stdout, stderr) => { + async (error, _stdout, stderr) => { if (!error?.killed) { if (debug()) console.log( From f187e08b37f165323c55eb74af473756aa278048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:27:29 +0100 Subject: [PATCH 14/40] Make server.updateDiagnosticSyntax async --- server/src/server.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index 428938f48..75e7638a0 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -836,7 +836,7 @@ function format(msg: p.RequestMessage): Array { } } -let updateDiagnosticSyntax = (fileUri: string, fileContent: string) => { +let updateDiagnosticSyntax = async (fileUri: string, fileContent: string) => { if (config.extensionConfiguration.incrementalTypechecking?.enable) { // The incremental typechecking already sends syntax diagnostics. return; @@ -1056,7 +1056,7 @@ async function onMessage(msg: p.Message) { } else if (msg.method === DidOpenTextDocumentNotification.method) { let params = msg.params as p.DidOpenTextDocumentParams; await openedFile(params.textDocument.uri, params.textDocument.text); - updateDiagnosticSyntax(params.textDocument.uri, params.textDocument.text); + await updateDiagnosticSyntax(params.textDocument.uri, params.textDocument.text); } else if (msg.method === DidChangeTextDocumentNotification.method) { let params = msg.params as p.DidChangeTextDocumentParams; let extName = path.extname(params.textDocument.uri); @@ -1070,7 +1070,7 @@ async function onMessage(msg: p.Message) { params.textDocument.uri, changes[changes.length - 1].text ); - updateDiagnosticSyntax( + await updateDiagnosticSyntax( params.textDocument.uri, changes[changes.length - 1].text ); From 82b7cdb7720ec079c4d5c6046a1f90613262647b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:29:30 +0100 Subject: [PATCH 15/40] Make server.hover async --- server/src/server.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index 75e7638a0..bceffe15e 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -423,13 +423,13 @@ export default function listen(useStdio = false) { } } -function hover(msg: p.RequestMessage) { +async function hover(msg: p.RequestMessage) { let params = msg.params as p.HoverParams; let filePath = fileURLToPath(params.textDocument.uri); let code = getOpenedFileContent(params.textDocument.uri); let tmpname = utils.createFileInTempDir(); fs.writeFileSync(tmpname, code, { encoding: "utf-8" }); - let response = utils.runAnalysisCommand( + let response = await utils.runAnalysisCommand( filePath, [ "hover", @@ -1224,7 +1224,7 @@ async function onMessage(msg: p.Message) { send(response); } } else if (msg.method === p.HoverRequest.method) { - send(hover(msg)); + send(await hover(msg)); } else if (msg.method === p.DefinitionRequest.method) { send(definition(msg)); } else if (msg.method === p.TypeDefinitionRequest.method) { From 943059760f7457223e869cfd356439a94326372e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:30:32 +0100 Subject: [PATCH 16/40] Make server.inlayHint async --- server/src/server.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index bceffe15e..063b68ee6 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -445,11 +445,11 @@ async function hover(msg: p.RequestMessage) { return response; } -function inlayHint(msg: p.RequestMessage) { +async function inlayHint(msg: p.RequestMessage) { const params = msg.params as p.InlayHintParams; const filePath = fileURLToPath(params.textDocument.uri); - const response = utils.runAnalysisCommand( + const response = await utils.runAnalysisCommand( filePath, [ "inlayHint", @@ -1256,7 +1256,7 @@ async function onMessage(msg: p.Message) { let params = msg.params as InlayHintParams; let extName = path.extname(params.textDocument.uri); if (extName === c.resExt) { - send(inlayHint(msg)); + send(await inlayHint(msg)); } } else if (msg.method === p.CodeLensRequest.method) { let params = msg.params as CodeLensParams; From 815085810602b9bab5c84dcf47ba9d17cc957ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:31:31 +0100 Subject: [PATCH 17/40] Make server.codeLens async --- server/src/server.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index 063b68ee6..63060a7b5 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -472,11 +472,11 @@ function sendInlayHintsRefresh() { send(request); } -function codeLens(msg: p.RequestMessage) { +async function codeLens(msg: p.RequestMessage) { const params = msg.params as p.CodeLensParams; const filePath = fileURLToPath(params.textDocument.uri); - const response = utils.runAnalysisCommand( + const response = await utils.runAnalysisCommand( filePath, ["codeLens", filePath], msg @@ -1262,7 +1262,7 @@ async function onMessage(msg: p.Message) { let params = msg.params as CodeLensParams; let extName = path.extname(params.textDocument.uri); if (extName === c.resExt) { - send(codeLens(msg)); + send(await codeLens(msg)); } } else if (msg.method === p.SignatureHelpRequest.method) { let params = msg.params as SignatureHelpParams; From a3b5d14c8d31022960ea90e1c8181dbc0c4f6dad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:32:14 +0100 Subject: [PATCH 18/40] Make server.signatureHelp async --- server/src/server.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index 63060a7b5..30e9f4553 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -493,13 +493,13 @@ function sendCodeLensRefresh() { send(request); } -function signatureHelp(msg: p.RequestMessage) { +async function signatureHelp(msg: p.RequestMessage) { let params = msg.params as p.SignatureHelpParams; let filePath = fileURLToPath(params.textDocument.uri); let code = getOpenedFileContent(params.textDocument.uri); let tmpname = utils.createFileInTempDir(); fs.writeFileSync(tmpname, code, { encoding: "utf-8" }); - let response = utils.runAnalysisCommand( + let response = await utils.runAnalysisCommand( filePath, [ "signatureHelp", @@ -1268,7 +1268,7 @@ async function onMessage(msg: p.Message) { let params = msg.params as SignatureHelpParams; let extName = path.extname(params.textDocument.uri); if (extName === c.resExt) { - send(signatureHelp(msg)); + send(await signatureHelp(msg)); } } else { let response: p.ResponseMessage = { From 9e9058e8472dd24fd147de1d34618cf067171352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:32:57 +0100 Subject: [PATCH 19/40] Make server.definition async --- server/src/server.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index 30e9f4553..d8bcf33f2 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -517,11 +517,11 @@ async function signatureHelp(msg: p.RequestMessage) { return response; } -function definition(msg: p.RequestMessage) { +async function definition(msg: p.RequestMessage) { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition let params = msg.params as p.DefinitionParams; let filePath = fileURLToPath(params.textDocument.uri); - let response = utils.runAnalysisCommand( + let response = await utils.runAnalysisCommand( filePath, ["definition", filePath, params.position.line, params.position.character], msg @@ -1226,7 +1226,7 @@ async function onMessage(msg: p.Message) { } else if (msg.method === p.HoverRequest.method) { send(await hover(msg)); } else if (msg.method === p.DefinitionRequest.method) { - send(definition(msg)); + send(await definition(msg)); } else if (msg.method === p.TypeDefinitionRequest.method) { send(typeDefinition(msg)); } else if (msg.method === p.ReferencesRequest.method) { From f0de0d171af8e71315df262ce3ea9b8e03baff4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:33:32 +0100 Subject: [PATCH 20/40] Make server.typeDefinition async --- server/src/server.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index d8bcf33f2..f62e7d5c0 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -529,11 +529,11 @@ async function definition(msg: p.RequestMessage) { return response; } -function typeDefinition(msg: p.RequestMessage) { +async function typeDefinition(msg: p.RequestMessage) { // https://microsoft.github.io/language-server-protocol/specification/specification-current/#textDocument_typeDefinition let params = msg.params as p.TypeDefinitionParams; let filePath = fileURLToPath(params.textDocument.uri); - let response = utils.runAnalysisCommand( + let response = await utils.runAnalysisCommand( filePath, [ "typeDefinition", @@ -1228,7 +1228,7 @@ async function onMessage(msg: p.Message) { } else if (msg.method === p.DefinitionRequest.method) { send(await definition(msg)); } else if (msg.method === p.TypeDefinitionRequest.method) { - send(typeDefinition(msg)); + send(await typeDefinition(msg)); } else if (msg.method === p.ReferencesRequest.method) { send(references(msg)); } else if (msg.method === p.PrepareRenameRequest.method) { From 743dfcf7c9b86f858393fb6cd2ceb6b8f5377f11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:34:10 +0100 Subject: [PATCH 21/40] Make server.documentSymbol async --- server/src/server.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index f62e7d5c0..8ea36fa83 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -622,7 +622,7 @@ async function rename(msg: p.RequestMessage) { return response; } -function documentSymbol(msg: p.RequestMessage) { +async function documentSymbol(msg: p.RequestMessage) { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol let params = msg.params as p.DocumentSymbolParams; let filePath = fileURLToPath(params.textDocument.uri); @@ -630,7 +630,7 @@ function documentSymbol(msg: p.RequestMessage) { let code = getOpenedFileContent(params.textDocument.uri); let tmpname = utils.createFileInTempDir(extension); fs.writeFileSync(tmpname, code, { encoding: "utf-8" }); - let response = utils.runAnalysisCommand( + let response = await utils.runAnalysisCommand( filePath, ["documentSymbol", tmpname], msg, @@ -1236,7 +1236,7 @@ async function onMessage(msg: p.Message) { } else if (msg.method === p.RenameRequest.method) { send(await rename(msg)); } else if (msg.method === p.DocumentSymbolRequest.method) { - send(documentSymbol(msg)); + send(await documentSymbol(msg)); } else if (msg.method === p.CompletionRequest.method) { send(completion(msg)); } else if (msg.method === p.CompletionResolveRequest.method) { From 490dd3577e5545aed0bafabad766061e966056ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:35:45 +0100 Subject: [PATCH 22/40] Make server.semanticTokens async --- server/src/server.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index 8ea36fa83..f0af953c2 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -658,7 +658,7 @@ function askForAllCurrentConfiguration() { send(req); } -function semanticTokens(msg: p.RequestMessage) { +async function semanticTokens(msg: p.RequestMessage) { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_semanticTokens let params = msg.params as p.SemanticTokensParams; let filePath = fileURLToPath(params.textDocument.uri); @@ -666,7 +666,7 @@ function semanticTokens(msg: p.RequestMessage) { let code = getOpenedFileContent(params.textDocument.uri); let tmpname = utils.createFileInTempDir(extension); fs.writeFileSync(tmpname, code, { encoding: "utf-8" }); - let response = utils.runAnalysisCommand( + let response = await utils.runAnalysisCommand( filePath, ["semanticTokens", tmpname], msg, @@ -1242,7 +1242,7 @@ async function onMessage(msg: p.Message) { } else if (msg.method === p.CompletionResolveRequest.method) { send(await completionResolve(msg)); } else if (msg.method === p.SemanticTokensRequest.method) { - send(semanticTokens(msg)); + send(await semanticTokens(msg)); } else if (msg.method === p.CodeActionRequest.method) { send(codeAction(msg)); } else if (msg.method === p.DocumentFormattingRequest.method) { From 2f85bc5640faa5c302d21f9e4a7df847464a31ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:37:23 +0100 Subject: [PATCH 23/40] Make server.completion async --- server/src/server.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index f0af953c2..041a171a0 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -676,14 +676,14 @@ async function semanticTokens(msg: p.RequestMessage) { return response; } -function completion(msg: p.RequestMessage) { +async function completion(msg: p.RequestMessage) { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion let params = msg.params as p.ReferenceParams; let filePath = fileURLToPath(params.textDocument.uri); let code = getOpenedFileContent(params.textDocument.uri); let tmpname = utils.createFileInTempDir(); fs.writeFileSync(tmpname, code, { encoding: "utf-8" }); - let response = utils.runAnalysisCommand( + let response = await utils.runAnalysisCommand( filePath, [ "completion", @@ -1238,7 +1238,7 @@ async function onMessage(msg: p.Message) { } else if (msg.method === p.DocumentSymbolRequest.method) { send(await documentSymbol(msg)); } else if (msg.method === p.CompletionRequest.method) { - send(completion(msg)); + send(await completion(msg)); } else if (msg.method === p.CompletionResolveRequest.method) { send(await completionResolve(msg)); } else if (msg.method === p.SemanticTokensRequest.method) { From 379a116b92626006a47d3ab79fbf968e7773101b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:38:13 +0100 Subject: [PATCH 24/40] Make server.codeAction async --- server/src/server.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index 041a171a0..bfea64ad4 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -719,7 +719,7 @@ async function completionResolve(msg: p.RequestMessage) { return response; } -function codeAction(msg: p.RequestMessage): p.ResponseMessage { +async function codeAction(msg: p.RequestMessage): Promise { let params = msg.params as p.CodeActionParams; let filePath = fileURLToPath(params.textDocument.uri); let code = getOpenedFileContent(params.textDocument.uri); @@ -741,7 +741,7 @@ function codeAction(msg: p.RequestMessage): p.ResponseMessage { ); fs.writeFileSync(tmpname, code, { encoding: "utf-8" }); - let response = utils.runAnalysisCommand( + let response = await utils.runAnalysisCommand( filePath, [ "codeAction", @@ -1244,7 +1244,7 @@ async function onMessage(msg: p.Message) { } else if (msg.method === p.SemanticTokensRequest.method) { send(await semanticTokens(msg)); } else if (msg.method === p.CodeActionRequest.method) { - send(codeAction(msg)); + send(await codeAction(msg)); } else if (msg.method === p.DocumentFormattingRequest.method) { let responses = format(msg); responses.forEach((response) => send(response)); From 95ca8dac7d5136a300c9e9b5c111a9f20187e2c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:38:43 +0100 Subject: [PATCH 25/40] Make server.createInterface async --- server/src/server.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index bfea64ad4..c0edaec70 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -870,7 +870,7 @@ let updateDiagnosticSyntax = async (fileUri: string, fileContent: string) => { send(notification); }; -function createInterface(msg: p.RequestMessage): p.Message { +async function createInterface(msg: p.RequestMessage): Promise { let params = msg.params as p.TextDocumentIdentifier; let extension = path.extname(params.uri); let filePath = fileURLToPath(params.uri); @@ -952,7 +952,7 @@ function createInterface(msg: p.RequestMessage): p.Message { return response; } - let response = utils.runAnalysisCommand( + let response = await utils.runAnalysisCommand( filePath, ["createInterface", filePath, cmiPath], msg @@ -1249,7 +1249,7 @@ async function onMessage(msg: p.Message) { let responses = format(msg); responses.forEach((response) => send(response)); } else if (msg.method === createInterfaceRequest.method) { - send(createInterface(msg)); + send(await createInterface(msg)); } else if (msg.method === openCompiledFileRequest.method) { send(openCompiledFile(msg)); } else if (msg.method === p.InlayHintRequest.method) { From cbe12399d4def5630e83cfbc3abbc9f97942eba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:40:58 +0100 Subject: [PATCH 26/40] Make utils.runAnalysisCommand async --- server/src/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/utils.ts b/server/src/utils.ts index bfbbbb6bb..e18c18685 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -360,7 +360,7 @@ export let runAnalysisAfterSanityCheck = async ( } }; -export let runAnalysisCommand = ( +export let runAnalysisCommand = async ( filePath: p.DocumentUri, args: Array, msg: RequestMessage, From 28226f59ffc7158dfa41aa480169c6d43c22459c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:41:14 +0100 Subject: [PATCH 27/40] Make utils.getReferencesForPosition async --- server/src/server.ts | 4 ++-- server/src/utils.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index c0edaec70..9c54cbfc5 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -550,7 +550,7 @@ function references(msg: p.RequestMessage) { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references let params = msg.params as p.ReferenceParams; let filePath = fileURLToPath(params.textDocument.uri); - let result: typeof p.ReferencesRequest.type = utils.getReferencesForPosition( + let result: typeof p.ReferencesRequest.type = await utils.getReferencesForPosition( filePath, params.position ); @@ -567,7 +567,7 @@ function prepareRename(msg: p.RequestMessage): p.ResponseMessage { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_prepareRename let params = msg.params as p.PrepareRenameParams; let filePath = fileURLToPath(params.textDocument.uri); - let locations: null | p.Location[] = utils.getReferencesForPosition( + let locations: null | p.Location[] = await utils.getReferencesForPosition( filePath, params.position ); diff --git a/server/src/utils.ts b/server/src/utils.ts index e18c18685..01ed59f83 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -375,7 +375,7 @@ export let runAnalysisCommand = async ( return response; }; -export let getReferencesForPosition = ( +export let getReferencesForPosition = async ( filePath: p.DocumentUri, position: p.Position ) => From 90a573ef6b5102dc9f825fe3dab855f3c390beeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:42:03 +0100 Subject: [PATCH 28/40] Make server.references async --- server/src/server.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index 9c54cbfc5..7fa7c680d 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -546,7 +546,7 @@ async function typeDefinition(msg: p.RequestMessage) { return response; } -function references(msg: p.RequestMessage) { +async function references(msg: p.RequestMessage) { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references let params = msg.params as p.ReferenceParams; let filePath = fileURLToPath(params.textDocument.uri); @@ -1230,7 +1230,7 @@ async function onMessage(msg: p.Message) { } else if (msg.method === p.TypeDefinitionRequest.method) { send(await typeDefinition(msg)); } else if (msg.method === p.ReferencesRequest.method) { - send(references(msg)); + send(await references(msg)); } else if (msg.method === p.PrepareRenameRequest.method) { send(prepareRename(msg)); } else if (msg.method === p.RenameRequest.method) { From 032026eea6ecf23229295b7d778d3762e55d3366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:42:48 +0100 Subject: [PATCH 29/40] Make server.prepareRename async --- server/src/server.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index 7fa7c680d..88cd989b2 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -563,7 +563,7 @@ async function references(msg: p.RequestMessage) { return response; } -function prepareRename(msg: p.RequestMessage): p.ResponseMessage { +async function prepareRename(msg: p.RequestMessage): Promise { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_prepareRename let params = msg.params as p.PrepareRenameParams; let filePath = fileURLToPath(params.textDocument.uri); @@ -1232,7 +1232,7 @@ async function onMessage(msg: p.Message) { } else if (msg.method === p.ReferencesRequest.method) { send(await references(msg)); } else if (msg.method === p.PrepareRenameRequest.method) { - send(prepareRename(msg)); + send(await prepareRename(msg)); } else if (msg.method === p.RenameRequest.method) { send(await rename(msg)); } else if (msg.method === p.DocumentSymbolRequest.method) { From d7bc10a702577180e63151a0d43e9caa7301e447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:45:07 +0100 Subject: [PATCH 30/40] Make utils.findReScriptVersionForProjectRoot async --- server/src/server.ts | 2 +- server/src/utils.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index 88cd989b2..a1ecf388e 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -271,7 +271,7 @@ let openedFile = async (fileUri: string, fileContent: string) => { filesDiagnostics: {}, namespaceName: namespaceName.kind === "success" ? namespaceName.result : null, - rescriptVersion: utils.findReScriptVersionForProjectRoot(projectRootPath), + rescriptVersion: await utils.findReScriptVersionForProjectRoot(projectRootPath), bsbWatcherByEditor: null, bscBinaryLocation: await utils.findBscExeBinary(projectRootPath), editorAnalysisLocation: await utils.findEditorAnalysisBinary(projectRootPath), diff --git a/server/src/utils.ts b/server/src/utils.ts index 01ed59f83..7b2c22c22 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -260,8 +260,8 @@ export let findReScriptVersion = async ( } }; -export function findReScriptVersionForProjectRoot(projectRootPath: string) : string | undefined { - const bscExe = findBinary(findPlatformPath(projectRootPath), c.bscExeName); +export async function findReScriptVersionForProjectRoot(projectRootPath: string): Promise { + const bscExe = await findBscExeBinary(projectRootPath) if (bscExe == null) { return undefined; From a037a23e0433389a8b40e5a5c238a5ad4a2c71d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:48:23 +0100 Subject: [PATCH 31/40] Replace findReScriptVersion(filePath) with findReScriptVersionForProjectRoot(projectRootPath) --- server/src/utils.ts | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/server/src/utils.ts b/server/src/utils.ts index 7b2c22c22..9847b281e 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -237,30 +237,11 @@ export let formatCode = ( } }; -export let findReScriptVersion = async ( - filePath: p.DocumentUri -): Promise => { - let projectRoot = findProjectRootOfFile(filePath); - if (projectRoot == null) { +export async function findReScriptVersionForProjectRoot(projectRootPath: string | null): Promise { + if (projectRootPath == null) { return undefined; } - const bscExe = findBinary(findPlatformPath(projectRoot), c.bscExeName); - - if (bscExe == null) { - return undefined; - } - - try { - let version = childProcess.execSync(`${bscExe} -v`); - return version.toString().replace(/rescript/gi, "").trim(); - } catch (e) { - console.error("rescrip binary failed", e); - return undefined; - } -}; - -export async function findReScriptVersionForProjectRoot(projectRootPath: string): Promise { const bscExe = await findBscExeBinary(projectRootPath) if (bscExe == null) { @@ -294,7 +275,7 @@ export let runAnalysisAfterSanityCheck = async ( } let rescriptVersion = projectsFiles.get(projectRootPath ?? "")?.rescriptVersion ?? - await findReScriptVersion(filePath); + await findReScriptVersionForProjectRoot(projectRootPath) let binaryPath = builtinBinaryPath; From 190696de41e81d9b1969935e6b1d153637c29fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Thu, 15 May 2025 23:51:35 +0100 Subject: [PATCH 32/40] Remove unused utils.findPlatformPath --- server/src/utils.ts | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/server/src/utils.ts b/server/src/utils.ts index 9847b281e..0b0d3075d 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -91,44 +91,6 @@ export let findBinary = ( return null; } }; - -let findPlatformPath = (projectRootPath: p.DocumentUri | null) => { - if (config.extensionConfiguration.platformPath != null) { - return config.extensionConfiguration.platformPath; - } - - let rescriptDir = lookup.findFilePathFromProjectRoot( - projectRootPath, - path.join("node_modules", "rescript") - ); - if (rescriptDir == null) { - return null; - } - - let platformPath = path.join(rescriptDir, c.platformDir); - - // Binaries have been split into optional platform-specific dependencies - // since v12.0.0-alpha.13 - if (!fs.existsSync(platformPath)) { - platformPath = path.join( - rescriptDir, - "..", - `@rescript/${process.platform}-${process.arch}/bin` - ) - } - - // Workaround for darwinarm64 which has no folder yet in ReScript <= 9.1.4 - if ( - process.platform == "darwin" && - process.arch == "arm64" && - !fs.existsSync(platformPath) - ) { - platformPath = path.join(rescriptDir, process.platform); - } - - return platformPath; -}; - // If ReScript < 12.0.0-alpha.13, then we want `{project_root}/node_modules/rescript/{c.platformDir}/{binary}`. // Otherwise, we want to dynamically import `{project_root}/node_modules/rescript` and from `binPaths` get the relevant binary. // We won't know which version is in the project root until we read and parse `{project_root}/node_modules/rescript/package.json` From 2258d8e01175c97979d7706a44590f0a5827912d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Fri, 16 May 2025 00:11:39 +0100 Subject: [PATCH 33/40] Make server.findRescriptBinary async --- server/src/constants.ts | 6 ------ server/src/server.ts | 22 ++++++++++------------ server/src/utils.ts | 28 +++++++++++----------------- 3 files changed, 21 insertions(+), 35 deletions(-) diff --git a/server/src/constants.ts b/server/src/constants.ts index fcfc08b1d..1b5761290 100644 --- a/server/src/constants.ts +++ b/server/src/constants.ts @@ -29,12 +29,6 @@ export let bscBinName = "bsc"; export let nodeModulesBinDir = path.join("node_modules", ".bin"); -// can't use the native bsb/rescript since we might need the watcher -w flag, which is only in the JS wrapper -export let rescriptNodePartialPath = path.join( - nodeModulesBinDir, - rescriptBinName -); - export let bsbLock = ".bsb.lock"; export let bsconfigPartialPath = "bsconfig.json"; export let rescriptJsonPartialPath = "rescript.json"; diff --git a/server/src/server.ts b/server/src/server.ts index a1ecf388e..b1e3c02be 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -56,16 +56,14 @@ let codeActionsFromDiagnostics: codeActions.filesCodeActions = {}; // will be properly defined later depending on the mode (stdio/node-rpc) let send: (msg: p.Message) => void = (_) => {}; -let findRescriptBinary = (projectRootPath: p.DocumentUri | null) => - config.extensionConfiguration.binaryPath == null - ? lookup.findFilePathFromProjectRoot( - projectRootPath, - path.join(c.nodeModulesBinDir, c.rescriptBinName) - ) - : utils.findBinary( - config.extensionConfiguration.binaryPath, - c.rescriptBinName - ); +let findRescriptBinary = async (projectRootPath: p.DocumentUri | null): Promise => { + if (config.extensionConfiguration.binaryPath != null && + fs.existsSync(path.join(config.extensionConfiguration.binaryPath, "rescript"))) { + return path.join(config.extensionConfiguration.binaryPath, "rescript") + } + + return utils.findRescriptBinary(projectRootPath) +} let createInterfaceRequest = new v.RequestType< p.TextDocumentIdentifier, @@ -305,7 +303,7 @@ let openedFile = async (fileUri: string, fileContent: string) => { // TODO: sometime stale .bsb.lock dangling. bsb -w knows .bsb.lock is // stale. Use that logic // TODO: close watcher when lang-server shuts down - if (findRescriptBinary(projectRootPath) != null) { + if (await findRescriptBinary(projectRootPath) != null) { let payload: clientSentBuildAction = { title: c.startBuildAction, projectRootPath: projectRootPath, @@ -1311,7 +1309,7 @@ async function onMessage(msg: p.Message) { // TODO: close watcher when lang-server shuts down. However, by Node's // default, these subprocesses are automatically killed when this // language-server process exits - let rescriptBinaryPath = findRescriptBinary(projectRootPath); + let rescriptBinaryPath = await findRescriptBinary(projectRootPath); if (rescriptBinaryPath != null) { let bsbProcess = utils.runBuildWatcherUsingValidBuildPath( rescriptBinaryPath, diff --git a/server/src/utils.ts b/server/src/utils.ts index 0b0d3075d..31e26dfaa 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -76,27 +76,12 @@ export let findProjectRootOfFile = ( } }; -// Check if binaryName exists inside binaryDirPath and return the joined path. -export let findBinary = ( - binaryDirPath: p.DocumentUri | null, - binaryName: string -): p.DocumentUri | null => { - if (binaryDirPath == null) { - return null; - } - let binaryPath: p.DocumentUri = path.join(binaryDirPath, binaryName); - if (fs.existsSync(binaryPath)) { - return binaryPath; - } else { - return null; - } -}; // If ReScript < 12.0.0-alpha.13, then we want `{project_root}/node_modules/rescript/{c.platformDir}/{binary}`. // Otherwise, we want to dynamically import `{project_root}/node_modules/rescript` and from `binPaths` get the relevant binary. // We won't know which version is in the project root until we read and parse `{project_root}/node_modules/rescript/package.json` let findBinaryAsync = async ( projectRootPath: p.DocumentUri | null, - binary: "bsc.exe" | "rescript-editor-analysis.exe" + binary: "bsc.exe" | "rescript-editor-analysis.exe" | "rescript" ) => { if (config.extensionConfiguration.platformPath != null) { return path.join(config.extensionConfiguration.platformPath, binary); @@ -111,16 +96,22 @@ let findBinaryAsync = async ( } let rescriptVersion = null; + let rescriptJSWrapperPath = null try { const rescriptPackageJSONPath = path.join(rescriptDir, "package.json"); const rescriptPackageJSON = JSON.parse(await fsAsync.readFile(rescriptPackageJSONPath, "utf-8")); rescriptVersion = rescriptPackageJSON.version + rescriptJSWrapperPath = rescriptPackageJSON.bin.rescript } catch (error) { return null } let binaryPath: string | null = null - if (semver.gte(rescriptVersion, "12.0.0-alpha.13")) { + if (binary == "rescript") { + // Can't use the native bsb/rescript since we might need the watcher -w + // flag, which is only in the JS wrapper + binaryPath = path.join(rescriptDir, rescriptJSWrapperPath) + } else if (semver.gte(rescriptVersion, "12.0.0-alpha.13")) { // TODO: export `binPaths` from `rescript` package so that we don't need to // copy the logic for figuring out `target`. const target = `${process.platform}-${process.arch}`; @@ -143,6 +134,9 @@ let findBinaryAsync = async ( } } +export let findRescriptBinary = (projectRootPath: p.DocumentUri | null) => + findBinaryAsync(projectRootPath, "rescript"); + export let findBscExeBinary = (projectRootPath: p.DocumentUri | null) => findBinaryAsync(projectRootPath, "bsc.exe"); From 628dc75596b6d8b3734fc3504b14e0feba944dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Fri, 16 May 2025 00:12:20 +0100 Subject: [PATCH 34/40] Remove unused constant --- server/src/constants.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/server/src/constants.ts b/server/src/constants.ts index 1b5761290..81d883b52 100644 --- a/server/src/constants.ts +++ b/server/src/constants.ts @@ -8,9 +8,7 @@ export let platformDir = // version is fixed to 2.0 export let jsonrpcVersion = "2.0"; -export let bscExeName = "bsc.exe"; export let editorAnalysisName = "rescript-editor-analysis.exe"; - export let builtinAnalysisDevPath = path.join( path.dirname(__dirname), "..", From b3b26bfff5c6d8183b7c7a94fc2c247280b16aa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Fri, 16 May 2025 00:14:47 +0100 Subject: [PATCH 35/40] s/findBinaryAsync/findBinary --- server/src/utils.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/utils.ts b/server/src/utils.ts index 31e26dfaa..570e65262 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -79,7 +79,7 @@ export let findProjectRootOfFile = ( // If ReScript < 12.0.0-alpha.13, then we want `{project_root}/node_modules/rescript/{c.platformDir}/{binary}`. // Otherwise, we want to dynamically import `{project_root}/node_modules/rescript` and from `binPaths` get the relevant binary. // We won't know which version is in the project root until we read and parse `{project_root}/node_modules/rescript/package.json` -let findBinaryAsync = async ( +let findBinary = async ( projectRootPath: p.DocumentUri | null, binary: "bsc.exe" | "rescript-editor-analysis.exe" | "rescript" ) => { @@ -135,13 +135,13 @@ let findBinaryAsync = async ( } export let findRescriptBinary = (projectRootPath: p.DocumentUri | null) => - findBinaryAsync(projectRootPath, "rescript"); + findBinary(projectRootPath, "rescript"); export let findBscExeBinary = (projectRootPath: p.DocumentUri | null) => - findBinaryAsync(projectRootPath, "bsc.exe"); + findBinary(projectRootPath, "bsc.exe"); export let findEditorAnalysisBinary = (projectRootPath: p.DocumentUri | null) => - findBinaryAsync(projectRootPath, "rescript-editor-analysis.exe"); + findBinary(projectRootPath, "rescript-editor-analysis.exe"); type execResult = | { From 40ecf3d1cd7373bcd22fd699bf4e0d4ce7d89976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Fri, 16 May 2025 00:27:47 +0100 Subject: [PATCH 36/40] Fix rescript binary package import path --- server/src/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/utils.ts b/server/src/utils.ts index 570e65262..329d96cc4 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -115,7 +115,7 @@ let findBinary = async ( // TODO: export `binPaths` from `rescript` package so that we don't need to // copy the logic for figuring out `target`. const target = `${process.platform}-${process.arch}`; - const targetPackagePath = path.join(rescriptDir, "..", `@rescript/${target}`) + const targetPackagePath = path.join(rescriptDir, "..", `@rescript/${target}/bin.js`) const { binPaths } = await import(targetPackagePath); if (binary == "bsc.exe") { From da67038fd3b7a3ef74a9c647303bc68d9dc70b93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Sun, 18 May 2025 18:55:43 +0100 Subject: [PATCH 37/40] Move semver dependency from root package.json to server/package.json --- package-lock.json | 20 -------------------- package.json | 1 - server/package-lock.json | 18 ++++++++++++++++++ server/package.json | 1 + 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index cdb14e482..ab2f6d269 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,6 @@ "@types/semver": "^7.7.0", "@types/vscode": "1.68.0", "esbuild": "^0.20.1", - "semver": "^7.7.2", "typescript": "^4.7.3" }, "engines": { @@ -446,19 +445,6 @@ "@esbuild/win32-x64": "0.20.1" } }, - "node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/typescript": { "version": "4.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", @@ -684,12 +670,6 @@ "@esbuild/win32-x64": "0.20.1" } }, - "semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true - }, "typescript": { "version": "4.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", diff --git a/package.json b/package.json index b54a8d3d4..01ed8fbe9 100644 --- a/package.json +++ b/package.json @@ -258,7 +258,6 @@ "@types/semver": "^7.7.0", "@types/vscode": "1.68.0", "esbuild": "^0.20.1", - "semver": "^7.7.2", "typescript": "^4.7.3" } } diff --git a/server/package-lock.json b/server/package-lock.json index 5f0e16fb9..3c411217c 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "chokidar": "^3.5.1", + "semver": "^7.7.2", "vscode-jsonrpc": "^8.0.1", "vscode-languageserver": "^8.0.1", "vscode-languageserver-protocol": "^3.17.1" @@ -175,6 +176,18 @@ "node": ">=8.10.0" } }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -324,6 +337,11 @@ "picomatch": "^2.2.1" } }, + "semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==" + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", diff --git a/server/package.json b/server/package.json index 19a30baa0..0df6affbb 100644 --- a/server/package.json +++ b/server/package.json @@ -31,6 +31,7 @@ }, "dependencies": { "chokidar": "^3.5.1", + "semver": "^7.7.2", "vscode-jsonrpc": "^8.0.1", "vscode-languageserver": "^8.0.1", "vscode-languageserver-protocol": "^3.17.1" From d4cc19db8509a9f0273600fc955a839cfa7b0712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Sun, 18 May 2025 20:12:05 +0100 Subject: [PATCH 38/40] Use semver package for version checks --- server/src/incrementalCompilation.ts | 8 ++++++-- server/src/utils.ts | 11 ++--------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/server/src/incrementalCompilation.ts b/server/src/incrementalCompilation.ts index 991bb9840..926b50342 100644 --- a/server/src/incrementalCompilation.ts +++ b/server/src/incrementalCompilation.ts @@ -6,6 +6,7 @@ import readline from "readline"; import { performance } from "perf_hooks"; import * as p from "vscode-languageserver-protocol"; import * as cp from "node:child_process"; +import semver from "semver"; import config, { send } from "./config"; import * as c from "./constants"; import * as chokidar from "chokidar"; @@ -573,8 +574,11 @@ async function figureOutBscArgs(entry: IncrementallyCompiledFileInfo) { }); callArgs.push("-color", "never"); - if (parseInt(project.rescriptVersion.split(".")[0] ?? "10") >= 11) { - // Only available in v11+ + // Only available in v11+ + if ( + semver.valid(project.rescriptVersion) && + semver.satisfies(project.rescriptVersion as string, ">=11", { includePrerelease: true }) + ) { callArgs.push("-ignore-parse-errors"); } diff --git a/server/src/utils.ts b/server/src/utils.ts index 329d96cc4..fd704a5ba 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -243,15 +243,8 @@ export let runAnalysisAfterSanityCheck = async ( * with the extension itself. */ let shouldUseBuiltinAnalysis = - rescriptVersion?.startsWith("9.") || - rescriptVersion?.startsWith("10.") || - rescriptVersion?.startsWith("11.") || - [ - "12.0.0-alpha.1", - "12.0.0-alpha.2", - "12.0.0-alpha.3", - "12.0.0-alpha.4", - ].includes(rescriptVersion ?? ""); + semver.valid(rescriptVersion) && + semver.lt(rescriptVersion as string, "12.0.0-alpha.5"); if (!shouldUseBuiltinAnalysis && project != null) { binaryPath = project.editorAnalysisLocation; From 22bff6d02b2c3ac35f8a6f86bd169ed16e8d3f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Sun, 18 May 2025 20:53:04 +0100 Subject: [PATCH 39/40] Update typescript from v4.7.3 to v5.8.3 --- .gitignore | 2 ++ package-lock.json | 17 +++++++++-------- package.json | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 432ac9ab6..5dc814def 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ rescript-tools.exe _opam/ _build/ + +*.tsbuildinfo \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ab2f6d269..61c020a42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@types/semver": "^7.7.0", "@types/vscode": "1.68.0", "esbuild": "^0.20.1", - "typescript": "^4.7.3" + "typescript": "^5.8.3" }, "engines": { "vscode": "^1.68.0" @@ -446,16 +446,17 @@ } }, "node_modules/typescript": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", - "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } } }, @@ -671,9 +672,9 @@ } }, "typescript": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", - "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true } } diff --git a/package.json b/package.json index 01ed8fbe9..2ca1b7915 100644 --- a/package.json +++ b/package.json @@ -258,6 +258,6 @@ "@types/semver": "^7.7.0", "@types/vscode": "1.68.0", "esbuild": "^0.20.1", - "typescript": "^4.7.3" + "typescript": "^5.8.3" } } From aa78b009dbb34d8feb7db36b259ec6f8eaa84fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Tue, 20 May 2025 13:23:27 +0100 Subject: [PATCH 40/40] Add CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 792849447..499e89aa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,10 @@ - Fix: JSON from `rescript-code-editor-analysis` was not always escaped properly, which prevented code actions from being available in certain situations https://github.com/rescript-lang/rescript-vscode/pull/1089 +#### :house: Internal + +- Find binary paths asynchronously. On `>=12.0.0-alpha.13` we do this by dynamically importing the `@rescript/{target}` package in the project root. https://github.com/rescript-lang/rescript-vscode/pull/1093 + ## 1.62.0 #### :nail_care: Polish