From 44ba952f4b62069b5d415bebe94323f1978456d5 Mon Sep 17 00:00:00 2001 From: Armando Andini Date: Tue, 6 Sep 2022 11:28:23 -0300 Subject: [PATCH] feat: diagnostic for hardhat error 411 - library not installed --- .../convertHardhatErrorToDiagnostic.ts | 64 ++++++++++++------- server/src/types.ts | 35 ++++------ .../convertHardhatErrorToDiagnostic.ts | 41 +++++++++++- 3 files changed, 93 insertions(+), 47 deletions(-) diff --git a/server/src/services/validation/convertHardhatErrorToDiagnostic.ts b/server/src/services/validation/convertHardhatErrorToDiagnostic.ts index 09920b11..5c8f3432 100644 --- a/server/src/services/validation/convertHardhatErrorToDiagnostic.ts +++ b/server/src/services/validation/convertHardhatErrorToDiagnostic.ts @@ -1,37 +1,57 @@ import { Diagnostic, DiagnosticSeverity, Range } from "@common/types"; import { TextDocument } from "vscode-languageserver-textdocument"; -import type { HardhatError, HardhatImportLineError } from "../../types"; +import type { + HardhatError, + HardhatImportFileError, + HardhatImportLibraryError, +} from "../../types"; -export const IMPORT_LINE_ERROR_CODES = [404, 405, 406, 407, 408, 409]; +export const IMPORT_FILE_ERROR_CODES = [404, 405, 406, 407, 408, 409]; +export const IMPORT_LIBRARY_ERROR_CODES = [411]; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function isHardhatImportLineError(error: any): error is HardhatImportLineError { - if (error.errorDescriptor === undefined) { - return false; - } +function isHardhatImportFileError( + error: HardhatError +): error is HardhatImportFileError { + const errorCode = error?.errorDescriptor?.number; + + return IMPORT_FILE_ERROR_CODES.includes(errorCode); +} - const errorCode = error.errorDescriptor.number; +function isHardhatImportLibraryError( + error: HardhatError +): error is HardhatImportLibraryError { + const errorCode = error?.errorDescriptor?.number; - return IMPORT_LINE_ERROR_CODES.includes(errorCode); + return IMPORT_LIBRARY_ERROR_CODES.includes(errorCode); +} + +function getImportString(err: HardhatError) { + if (isHardhatImportFileError(err)) { + return err.messageArguments.imported; + } else if (isHardhatImportLibraryError(err)) { + return err.messageArguments.library; + } else { + return null; + } } export function convertHardhatErrorToDiagnostic( document: TextDocument, err: HardhatError ): Diagnostic | null { - if (!isHardhatImportLineError(err)) { - return null; - } + const importString = getImportString(err); - return resolveImportLineError(document, err, err.errorDescriptor.title); + if (importString === null) return null; + + return resolveImportError(document, err, importString); } -function resolveImportLineError( +function resolveImportError( document: TextDocument, - err: HardhatImportLineError, - message: string + err: HardhatError, + importString: string ) { - const range = findRangeForImport(document, err); + const range = findRangeForImport(document, importString); if (!range) { return null; @@ -41,24 +61,22 @@ function resolveImportLineError( severity: DiagnosticSeverity.Error, code: err.errorDescriptor.number, source: "hardhat", - message, + message: err.errorDescriptor.title, range, }; } function findRangeForImport( document: TextDocument, - err: HardhatImportLineError + importString: string ): Range | null { - const imported = err.messageArguments.imported; - - const startIndex = document.getText().indexOf(imported); + const startIndex = document.getText().indexOf(importString); if (startIndex === -1) { return null; } - const endIndex = startIndex + imported.length; + const endIndex = startIndex + importString.length; return { start: document.positionAt(startIndex), diff --git a/server/src/types.ts b/server/src/types.ts index f80079c7..8bd33e50 100644 --- a/server/src/types.ts +++ b/server/src/types.ts @@ -159,23 +159,26 @@ export interface WorkerState { logger: WorkerLogger; } -export type ImportLineErrorCode = 404 | 405 | 406 | 407 | 408 | 409; +export interface HardhatImportFileError extends HardhatError { + messageArguments: { + imported: string; + }; +} -export interface HardhatImportLineError { - name: "HardhatError"; - errorDescriptor: { - number: number; - message: string; - title: string; - description: string; - shouldBeReported: boolean; +export interface HardhatImportLibraryError extends HardhatError { + messageArguments: { + library: string; }; +} + +export interface HardhatSourceImportError extends HardhatError { messageArguments: { imported: string; + from: string; }; } -export interface UnknownHardhatError { +export interface HardhatError { name: "HardhatError"; errorDescriptor: { number: number; @@ -187,18 +190,6 @@ export interface UnknownHardhatError { messageArguments?: unknown; } -export interface HardhatSourceImportError extends UnknownHardhatError { - messageArguments: { - imported: string; - from: string; - }; -} - -export type HardhatError = - | UnknownHardhatError - | HardhatImportLineError - | HardhatSourceImportError; - export interface ValidateCommand { type: "VALIDATE"; jobId: number; diff --git a/server/test/services/validation/convertHardhatErrorToDiagnostic.ts b/server/test/services/validation/convertHardhatErrorToDiagnostic.ts index b55bbeb9..337b7a6b 100644 --- a/server/test/services/validation/convertHardhatErrorToDiagnostic.ts +++ b/server/test/services/validation/convertHardhatErrorToDiagnostic.ts @@ -4,7 +4,11 @@ import { Diagnostic, Range, } from "@common/types"; -import { convertHardhatErrorToDiagnostic } from "@services/validation/convertHardhatErrorToDiagnostic"; +import { + convertHardhatErrorToDiagnostic, + IMPORT_FILE_ERROR_CODES, + IMPORT_LIBRARY_ERROR_CODES, +} from "@services/validation/convertHardhatErrorToDiagnostic"; import { assert } from "chai"; interface ErrorDescription { @@ -173,6 +177,32 @@ Hardhat's compiler is case sensitive to ensure projects are portable across diff }); }); + describe("411 - Invalid import: missing library", () => { + it("should convert to a diagnostic", () => { + const errorDescription = + "A Solidity file is trying to import another which belongs to a library that is not installed.\n \nTry installing the library using npm."; + + assertConversionToDiagnostic( + "@foo/Bar.sol", + { + number: 411, + message: + "The library %library%, imported from %from%, is not installed. Try installing it using npm.", + title: "Invalid import: library not installed", + description: errorDescription, + shouldBeReported: false, + }, + { + message: "Invalid import: library not installed", + range: { + start: { line: 0, character: 8 }, + end: { line: 0, character: 20 }, + }, + } + ); + }); + }); + describe("unhandled - an unknown hardhat error", () => { const fileText = ` //SPDX-License-Identifier: Unlicense @@ -285,12 +315,19 @@ function assertConversionToDiagnostic( const document = TextDocument.create(exampleUri, "solidity", 0, fileText); + let messageArguments = {}; + if (IMPORT_FILE_ERROR_CODES.includes(errorDescription.number)) { + messageArguments = { imported: importLine }; + } else if (IMPORT_LIBRARY_ERROR_CODES.includes(errorDescription.number)) { + messageArguments = { library: importLine }; + } + const diagnostic: Diagnostic | null = convertHardhatErrorToDiagnostic( document, { name: "HardhatError", errorDescriptor: errorDescription, - messageArguments: { imported: importLine }, + messageArguments, } );