diff --git a/packages/ansible-language-server/src/ansibleLanguageService.ts b/packages/ansible-language-server/src/ansibleLanguageService.ts index b2bfc05e8..14d616f18 100644 --- a/packages/ansible-language-server/src/ansibleLanguageService.ts +++ b/packages/ansible-language-server/src/ansibleLanguageService.ts @@ -1,4 +1,5 @@ import { + CompletionItem, Connection, DidChangeConfigurationNotification, DidChangeWatchedFilesNotification, @@ -281,21 +282,23 @@ export class AnsibleLanguageService { return null; }); - this.connection.onCompletionResolve(async (completionItem) => { - try { - if (completionItem.data?.documentUri) { - const context = this.workspaceManager.getContext( - completionItem.data?.documentUri, - ); - if (context) { - return await doCompletionResolve(completionItem, context); + this.connection.onCompletionResolve( + async (completionItem: CompletionItem) => { + try { + if (completionItem.data?.documentUri) { + const context = this.workspaceManager.getContext( + completionItem.data?.documentUri, + ); + if (context) { + return await doCompletionResolve(completionItem, context); + } } + } catch (error) { + this.handleError(error, "onCompletionResolve"); } - } catch (error) { - this.handleError(error, "onCompletionResolve"); - } - return completionItem; - }); + return completionItem; + }, + ); this.connection.onDefinition(async (params) => { try { diff --git a/packages/ansible-language-server/src/providers/completionProvider.ts b/packages/ansible-language-server/src/providers/completionProvider.ts index 3009b0596..d17cc868d 100644 --- a/packages/ansible-language-server/src/providers/completionProvider.ts +++ b/packages/ansible-language-server/src/providers/completionProvider.ts @@ -278,7 +278,7 @@ export async function doCompletion( .map((option, index) => { // translate option documentation to CompletionItem const details = getDetails(option.specs); - let priority; + let priority: number; if (isAlias(option)) { priority = priorityMap.aliasOption; } else if (option.specs.required) { @@ -363,7 +363,7 @@ export async function doCompletion( choices.push(defaultChoice); } return choices.map((choice, index) => { - let priority; + let priority: number; if (choice === defaultChoice) { priority = priorityMap.defaultChoice; } else { @@ -616,11 +616,17 @@ function atEndOfLine(document: TextDocument, position: Position): boolean { * @param nodeRange - range of the keyword in the document * @returns boolean true if the key is the first element of the list, else false */ -function firstElementOfList(document: TextDocument, nodeRange: Range): boolean { - const checkNodeRange = { - start: { line: nodeRange.start.line, character: 0 }, - end: nodeRange.start, - }; +function firstElementOfList( + document: TextDocument, + nodeRange: Range | undefined, +): boolean { + let checkNodeRange: Range | undefined = undefined; + if (nodeRange) { + checkNodeRange = { + start: { line: nodeRange.start.line, character: 0 }, + end: nodeRange.start, + } as Range; + } const elementsBeforeKey = document.getText(checkNodeRange).trim(); return elementsBeforeKey === "-"; diff --git a/packages/ansible-language-server/src/providers/validationProvider.ts b/packages/ansible-language-server/src/providers/validationProvider.ts index 09113cb3e..91b8013f3 100644 --- a/packages/ansible-language-server/src/providers/validationProvider.ts +++ b/packages/ansible-language-server/src/providers/validationProvider.ts @@ -25,7 +25,7 @@ export async function doValidate( context?: WorkspaceFolderContext, connection?: Connection, ): Promise> { - let diagnosticsByFile; + let diagnosticsByFile: Map | undefined; if (quick || !context) { // get validation from cache diagnosticsByFile = @@ -34,6 +34,7 @@ export async function doValidate( } else { // full validation with ansible-lint or ansible syntax-check (if ansible-lint is not installed or disabled) + let diagnosticsByFile: Map; const settings = await context.documentSettings.get(textDocument.uri); if (!settings.validation.enabled) { connection?.console.log("Validation disabled"); diff --git a/packages/ansible-language-server/src/services/ansibleInventory.ts b/packages/ansible-language-server/src/services/ansibleInventory.ts index b5f517b8b..224157343 100644 --- a/packages/ansible-language-server/src/services/ansibleInventory.ts +++ b/packages/ansible-language-server/src/services/ansibleInventory.ts @@ -3,6 +3,19 @@ import { WorkspaceFolderContext } from "./workspaceManager"; import { CommandRunner } from "../utils/commandRunner"; import { URI } from "vscode-uri"; +type AnsibleHost = { + host: string; + priority: number; +}; + +type AnsibleHostObject = { + [name: string]: { + hosts?: string[]; + children?: string[]; + }; + _meta: object; +}; +// & { _meta?: never }; /** * Class to extend ansible-inventory executable as a service */ @@ -41,9 +54,11 @@ export class AnsibleInventory { defaultHostListPath, ); - let inventoryHostsObject = []; + let inventoryHostsObject: AnsibleHostObject; try { - inventoryHostsObject = JSON.parse(ansibleInventoryResult.stdout); + inventoryHostsObject = JSON.parse( + ansibleInventoryResult.stdout, + ) as AnsibleHostObject; } catch (error) { this.connection.console.error( `Exception in AnsibleInventory service: ${JSON.stringify(error)}`, @@ -64,7 +79,7 @@ export class AnsibleInventory { * @param hostObj - nested object of hosts * @returns an array of object with host and priority as keys */ -function parseInventoryHosts(hostObj) { +function parseInventoryHosts(hostObj: AnsibleHostObject) { const topLevelGroups = hostObj.all.children.filter( (item: string) => item !== "ungrouped", ); @@ -77,16 +92,16 @@ function parseInventoryHosts(hostObj) { // Set priorities: top level groups (1), other groups (2), ungrouped (3), hosts for groups (4), localhost (5) const topLevelGroupsObjList = topLevelGroups.map((item) => { - return { host: item, priority: 1 }; + return { host: item, priority: 1 } as AnsibleHost; }); const otherGroupsObjList = otherGroups.map((item) => { - return { host: item, priority: 2 }; + return { host: item, priority: 2 } as AnsibleHost; }); const allGroups = [...topLevelGroupsObjList, ...otherGroupsObjList]; - let ungroupedHostsObjList = []; + let ungroupedHostsObjList: AnsibleHost[] = []; if (hostObj.ungrouped) { ungroupedHostsObjList = hostObj.ungrouped.hosts.map((item) => { return { host: item, priority: 3 }; @@ -94,15 +109,15 @@ function parseInventoryHosts(hostObj) { } // Add 'localhost' and 'all' to the inventory list - const localhostObj = { host: "localhost", priority: 5 }; - const allHostObj = { host: "all", priority: 6 }; + const localhostObj = { host: "localhost", priority: 5 } as AnsibleHost; + const allHostObj = { host: "all", priority: 6 } as AnsibleHost; let allHosts = [localhostObj, allHostObj, ...ungroupedHostsObjList]; for (const group of allGroups) { if (hostObj[`${group.host}`] && hostObj[`${group.host}`].hosts) { const hostsObj = hostObj[`${group.host}`].hosts.map((item) => { - return { host: item, priority: 4 }; + return { host: item, priority: 4 } as AnsibleHost; }); allHosts = [...allHosts, ...hostsObj]; } diff --git a/packages/ansible-language-server/src/services/docsLibrary.ts b/packages/ansible-language-server/src/services/docsLibrary.ts index fb9ad48dc..d8c408acd 100644 --- a/packages/ansible-language-server/src/services/docsLibrary.ts +++ b/packages/ansible-language-server/src/services/docsLibrary.ts @@ -127,7 +127,7 @@ export class DocsLibrary { ); // check routing - let moduleRoute; + let moduleRoute: IPluginRoute | undefined; for (const fqcn of candidateFqcns) { moduleRoute = this.getModuleRoute(fqcn); if (moduleRoute) { @@ -137,7 +137,7 @@ export class DocsLibrary { } // find module - let module; + let module: IModuleMetadata; if (moduleRoute && moduleRoute.redirect) { module = this.modules.get(moduleRoute.redirect); } else { diff --git a/packages/ansible-language-server/src/services/executionEnvironment.ts b/packages/ansible-language-server/src/services/executionEnvironment.ts index f74bbdd97..875a3e1c4 100644 --- a/packages/ansible-language-server/src/services/executionEnvironment.ts +++ b/packages/ansible-language-server/src/services/executionEnvironment.ts @@ -2,7 +2,10 @@ import * as child_process from "child_process"; import * as fs from "fs"; import * as path from "path"; import { URI } from "vscode-uri"; -import { Connection } from "vscode-languageserver"; +import { + Connection, + WorkDoneProgressServerReporter, +} from "vscode-languageserver"; import { v4 as uuidv4 } from "uuid"; import { AnsibleConfig } from "./ansibleConfig"; import { ImagePuller } from "../utils/imagePuller"; @@ -88,7 +91,7 @@ export class ExecutionEnvironment { /[^a-z0-9]/gi, "_", )}`; - let progressTracker; + let progressTracker: WorkDoneProgressServerReporter; try { const containerImageIdCommand = `${this._container_engine} images ${this._container_image} --format="{{.ID}}" | head -n 1`; diff --git a/packages/ansible-language-server/src/utils/docsFinder.ts b/packages/ansible-language-server/src/utils/docsFinder.ts index ce4a7dc20..90992b9c7 100644 --- a/packages/ansible-language-server/src/utils/docsFinder.ts +++ b/packages/ansible-language-server/src/utils/docsFinder.ts @@ -20,7 +20,7 @@ export async function findDocumentation( if (!fs.existsSync(dir) || fs.lstatSync(dir).isFile()) { return []; } - let files; + let files: string[]; switch (kind) { case "builtin": files = await globArray([`${dir}/**/*.py`, "!/**/_*.py"]); @@ -90,7 +90,7 @@ export async function findPluginRouting( if (!fs.existsSync(dir) || fs.lstatSync(dir).isFile()) { return pluginRouting; } - let files; + let files: string[]; switch (kind) { case "builtin": files = await globArray([`${dir}/config/ansible_builtin_runtime.yml`]); diff --git a/packages/ansible-language-server/src/utils/docsParser.ts b/packages/ansible-language-server/src/utils/docsParser.ts index 0256dde46..a6951e229 100644 --- a/packages/ansible-language-server/src/utils/docsParser.ts +++ b/packages/ansible-language-server/src/utils/docsParser.ts @@ -247,7 +247,7 @@ export class LazyModuleDocumentation implements IModuleMetadata { if (!this._contents) { this._contents = new Map>(); const contents = fs.readFileSync(this.source, { encoding: "utf8" }); - let m; + let m: RegExpExecArray | null; while ((m = LazyModuleDocumentation.docsRegex.exec(contents)) !== null) { if (m && m.groups && m.groups.name && m.groups.doc && m.groups.pre) { if (m.groups.name === DOCUMENTATION) { diff --git a/packages/ansible-language-server/src/utils/getAnsibleMetaData.ts b/packages/ansible-language-server/src/utils/getAnsibleMetaData.ts index fef235172..4adc23b95 100644 --- a/packages/ansible-language-server/src/utils/getAnsibleMetaData.ts +++ b/packages/ansible-language-server/src/utils/getAnsibleMetaData.ts @@ -40,9 +40,8 @@ export async function getResultsThroughCommandRunner(cmd, arg) { const workingDirectory = URI.parse(context.workspaceFolder.uri).path; const mountPaths = new Set([workingDirectory]); - let result; try { - result = await commandRunner.runCommand( + const result = await commandRunner.runCommand( cmd, arg, workingDirectory, @@ -56,13 +55,14 @@ export async function getResultsThroughCommandRunner(cmd, arg) { return result; } } catch (error) { + const msg = error instanceof Error ? error.message : (error as string); console.log( - `cmd '${cmd} ${arg}' was not executed with the following error: ' ${error.toString()}`, + `cmd '${cmd} ${arg}' was not executed with the following error: ' ${msg}`, ); return undefined; } - return result; + return undefined; } async function getAnsibleInfo() { @@ -76,7 +76,7 @@ async function getAnsibleInfo() { return ansibleInfo; } - let ansibleCoreVersion; + let ansibleCoreVersion: string[]; if (ansibleVersionObjKeys[0].includes(" [")) { ansibleCoreVersion = ansibleVersionObjKeys[0].split(" ["); } else { @@ -136,7 +136,7 @@ async function getPythonInfo() { async function getAnsibleLintInfo() { const ansibleLintInfo = {}; - let ansibleLintVersionResult = await getResultsThroughCommandRunner( + const ansibleLintVersionResult = await getResultsThroughCommandRunner( "ansible-lint", "--version", ); @@ -153,10 +153,12 @@ async function getAnsibleLintInfo() { // ansible-lint version reports if a newer version of the ansible-lint is available or not // along with the current version itself // so the following lines of code are to segregate the two information into to keys - ansibleLintVersionResult = ansibleLintVersionResult.stdout.trim().split("\n"); - const ansibleLintVersion = ansibleLintVersionResult[0]; - const ansibleLintUpgradeStatus = ansibleLintVersionResult[1] - ? ansibleLintVersionResult[1] + const ansibleLintVersionArray = ansibleLintVersionResult.stdout + .trim() + .split("\n"); + const ansibleLintVersion = ansibleLintVersionArray[0]; + const ansibleLintUpgradeStatus = ansibleLintVersionArray[1] + ? ansibleLintVersionArray[1] : undefined; ansibleLintInfo["version"] = ansibleLintVersion @@ -186,7 +188,7 @@ async function getExecutionEnvironmentInfo() { eeInfo["container image ID"] = basicDetails.containerImageId; let eeServiceWorking = false; - let inspectResult; + let inspectResult: unknown; try { inspectResult = JSON.parse( child_process diff --git a/packages/ansible-language-server/src/utils/imagePuller.ts b/packages/ansible-language-server/src/utils/imagePuller.ts index 90264efca..a14f0ea95 100644 --- a/packages/ansible-language-server/src/utils/imagePuller.ts +++ b/packages/ansible-language-server/src/utils/imagePuller.ts @@ -1,5 +1,8 @@ import * as child_process from "child_process"; -import { Connection } from "vscode-languageserver"; +import { + Connection, + WorkDoneProgressServerReporter, +} from "vscode-languageserver"; import { WorkspaceFolderContext } from "../services/workspaceManager"; export class ImagePuller { @@ -35,7 +38,7 @@ export class ImagePuller { const imagePresent = this.checkForImage(); const pullRequired = this.determinePull(imagePresent, imageTag); - let progressTracker; + let progressTracker: WorkDoneProgressServerReporter; if (this.useProgressTracker) { progressTracker = await this.connection.window.createWorkDoneProgress(); } diff --git a/packages/ansible-language-server/src/utils/webUtils.ts b/packages/ansible-language-server/src/utils/webUtils.ts index f95c75d82..b7b4c64b6 100644 --- a/packages/ansible-language-server/src/utils/webUtils.ts +++ b/packages/ansible-language-server/src/utils/webUtils.ts @@ -1,6 +1,6 @@ // partially duplicated from ./src/features/lightspeed/utils/webUtils.ts /* Get base uri in a correct formatted way */ -export function getBaseUri(URL) { +export function getBaseUri(URL: string): string { const baseUri = URL.trim(); return baseUri.endsWith("/") ? baseUri.slice(0, -1) : baseUri; } diff --git a/packages/ansible-language-server/src/utils/yaml.ts b/packages/ansible-language-server/src/utils/yaml.ts index 0c7ef2ec6..bd16be7a8 100644 --- a/packages/ansible-language-server/src/utils/yaml.ts +++ b/packages/ansible-language-server/src/utils/yaml.ts @@ -405,7 +405,7 @@ export async function getPossibleOptionsForPath( const taskParamNode = taskParamPath[taskParamPath.length - 1]; if (!isScalar(taskParamNode)) return null; - let module; + let module: IModuleMetadata | undefined; // Module options can either be directly under module or in 'args' if (taskParamNode.value === "args") { module = await findProvidedModule(taskParamPath, document, docsLibrary); diff --git a/src/extensionConflicts.ts b/src/extensionConflicts.ts index ea7b0c241..9287a5872 100644 --- a/src/extensionConflicts.ts +++ b/src/extensionConflicts.ts @@ -18,7 +18,7 @@ const conflictingIDs = [ const uninstallingIDs = new Set(); // eslint-disable-next-line @typescript-eslint/no-explicit-any -function isExtensionPresent(obj: any): obj is Extension { +function isExtensionPresent(obj: Extension | undefined): boolean { return typeof obj !== "undefined" && !uninstallingIDs.has(obj.id); } @@ -49,6 +49,9 @@ export async function showUninstallConflictsNotification( uninstallingIDs.add(ext.id); } + function getExtName(ext: Extension): string { + return ext?.packageJSON?.["displayName"] ?? ""; + } const uninstallMsg = "Uninstall"; if (!conflictingExts.length) { @@ -57,10 +60,10 @@ export async function showUninstallConflictsNotification( // Gather all the conflicting display names let conflictMsg = ""; if (conflictingExts.length === 1) { - conflictMsg = `${conflictingExts[0].packageJSON.displayName} (${conflictingExts[0].id}) extension is incompatible with redhat.ansible. Please uninstall it.`; + conflictMsg = `${getExtName(conflictingExts[0])} (${conflictingExts[0].id}) extension is incompatible with redhat.ansible. Please uninstall it.`; } else { const extNames: string = conflictingExts - .map((ext) => `${ext.packageJSON.displayName} (${ext.id})`) + .map((ext) => `${getExtName(ext)} (${ext.id})`) .join(", "); conflictMsg = `The ${extNames} extensions are incompatible with redhat.ansible. Please uninstall them.`; }