diff --git a/server/src/shellcheck/__tests__/index.test.ts b/server/src/shellcheck/__tests__/index.test.ts index c2ad2a698..3e91203bc 100644 --- a/server/src/shellcheck/__tests__/index.test.ts +++ b/server/src/shellcheck/__tests__/index.test.ts @@ -295,4 +295,19 @@ describe('linter', () => { diagnostics: [], }) }) + + it('should handle non-file URI schemes gracefully', async () => { + const shell = ['#!/bin/bash', 'echo "hello"'].join('\n') + + const nonFileUri = 'webdav://example.com/path/to/script.sh' + const document = TextDocument.create(nonFileUri, 'bash', 0, shell) + + const [result] = await getLintingResult({ + document, + sourcePaths: [], + }) + + expect(result.diagnostics).toEqual([]) + expect(result.codeActions).toEqual({}) + }) }) diff --git a/server/src/shellcheck/index.ts b/server/src/shellcheck/index.ts index f0409af8d..4aa7ee15b 100644 --- a/server/src/shellcheck/index.ts +++ b/server/src/shellcheck/index.ts @@ -1,5 +1,5 @@ import { dirname } from 'node:path' -import { fileURLToPath } from 'node:url' +import { fileURLToPath, URL } from 'node:url' import { spawn } from 'child_process' import * as LSP from 'vscode-languageserver/node' @@ -17,6 +17,19 @@ import { } from './types' const DEBOUNCE_MS = 500 + +function safeFileURLToPath(uri: string): string | null { + try { + const url = new URL(uri) + if (url.protocol !== 'file:') { + return null + } + return fileURLToPath(uri) + } catch { + return null + } +} + type LinterOptions = { executablePath: string cwd?: string @@ -91,10 +104,15 @@ export class Linter { return { diagnostics: [], codeActions: {} } } + const documentPath = safeFileURLToPath(document.uri) + const effectiveSourcePaths = documentPath + ? [...sourcePaths, dirname(documentPath)] + : sourcePaths + const result = await this.runShellCheck( documentText, shellName, - [...sourcePaths, dirname(fileURLToPath(document.uri))], + effectiveSourcePaths, additionalShellCheckArguments, )