diff --git a/apps/scout-extension/pnpm-lock.yaml b/apps/scout-extension/pnpm-lock.yaml index 186d0125..0a16bd7d 100644 --- a/apps/scout-extension/pnpm-lock.yaml +++ b/apps/scout-extension/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.1' +lockfileVersion: '6.0' settings: autoInstallPeers: true @@ -11,6 +11,9 @@ dependencies: toml: specifier: ^3.0.0 version: 3.0.0 + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@16.0.0)(typescript@5.0.4) devDependencies: '@types/command-exists': @@ -58,6 +61,13 @@ devDependencies: packages: + /@cspotcode/source-map-support@0.8.1: + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + dev: false + /@esbuild/android-arm64@0.17.19: resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} engines: {node: '>=12'} @@ -313,6 +323,22 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true + /@jridgewell/resolve-uri@3.1.2: + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + dev: false + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: false + + /@jridgewell/trace-mapping@0.3.9: + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: false + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -339,6 +365,22 @@ packages: engines: {node: '>= 6'} dev: true + /@tsconfig/node10@1.0.11: + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + dev: false + + /@tsconfig/node12@1.0.11: + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + dev: false + + /@tsconfig/node14@1.0.3: + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + dev: false + + /@tsconfig/node16@1.0.4: + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + dev: false + /@types/command-exists@1.2.0: resolution: {integrity: sha512-ugsxEJfsCuqMLSuCD4PIJkp5Uk2z6TCMRCgYVuhRo5cYQY3+1xXTQkSlPtkpGHuvWMjS2KTeVQXxkXRACMbM6A==} dev: true @@ -364,7 +406,6 @@ packages: /@types/node@16.0.0: resolution: {integrity: sha512-TmCW5HoZ2o2/z2EYi109jLqIaPIi9y/lc2LmDCWzuCi35bcaQ+OtUh6nwBiFK7SOu25FAU5+YKdqFZUwtqGSdg==} - dev: true /@types/semver@7.5.0: resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} @@ -524,11 +565,15 @@ packages: acorn: 8.8.2 dev: true + /acorn-walk@8.3.2: + resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + engines: {node: '>=0.4.0'} + dev: false + /acorn@8.8.2: resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} engines: {node: '>=0.4.0'} hasBin: true - dev: true /agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} @@ -573,6 +618,10 @@ packages: picomatch: 2.3.1 dev: true + /arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + dev: false + /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true @@ -679,6 +728,10 @@ packages: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} dev: true + /create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + dev: false + /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -710,6 +763,11 @@ packages: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true + /diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + dev: false + /diff@5.0.0: resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} engines: {node: '>=0.3.1'} @@ -1209,6 +1267,10 @@ packages: yallist: 4.0.0 dev: true + /make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: false + /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1541,6 +1603,37 @@ packages: resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} dev: false + /ts-node@10.9.2(@types/node@16.0.0)(typescript@5.0.4): + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 16.0.0 + acorn: 8.8.2 + acorn-walk: 8.3.2 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.0.4 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: false + /tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true @@ -1571,7 +1664,6 @@ packages: resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} engines: {node: '>=12.20'} hasBin: true - dev: true /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -1583,6 +1675,10 @@ packages: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: true + /v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + dev: false + /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -1650,6 +1746,11 @@ packages: yargs-parser: 20.2.4 dev: true + /yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + dev: false + /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} diff --git a/apps/scout-extension/src/extension.ts b/apps/scout-extension/src/extension.ts index 6022b723..ee737d31 100644 --- a/apps/scout-extension/src/extension.ts +++ b/apps/scout-extension/src/extension.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ import * as vscode from "vscode"; import commandExists from "command-exists"; import toml from "toml"; @@ -5,107 +6,123 @@ import fs from "fs"; import path from "path"; const RUST_ANALYZER_CONFIG = "rust-analyzer.check.overrideCommand"; +const CARGO_TOML = "Cargo.toml"; + +enum BlockchainType { + Ink = "ink", + Soroban = "soroban-sdk", +} + +interface CargoDependencies { + ink?: BlockchainType.Ink; + "soroban-sdk"?: BlockchainType.Soroban; +} + +interface CargoToml { + dependencies?: CargoDependencies; +} export async function activate(_context: vscode.ExtensionContext) { - // Check workspace is an soroban project - const sdk = isProjectSupported(); - if (sdk == false) return; + // Check if the workspace is valid + if (!isWorkspaceValid()) return; - const config = vscode.workspace.getConfiguration(); + // Get the Cargo.toml file and parse it + const cargoToml = await readAndParseCargoToml(); + if (!cargoToml) return; - // Check rust-analyzer is installed + // Check if the Cargo.toml file has the required dependencies + if (!(await hasKnownSdk(cargoToml))) return; + + // Get the worspace configuration and check if rust-analyzer is installed + const config = vscode.workspace.getConfiguration(); if (!config.has(RUST_ANALYZER_CONFIG)) { - console.error("rust-analyzer is not installed"); await vscode.window.showErrorMessage( - "rust-analyzer must be installed in order for scout to work" + "rust-analyzer is not installed. Please install rust-analyzer to continue." ); + return; } - // Check scout is installed + // Check if scout is installed + if (!(await checkAndInstallScout())) return; - if(sdk == "ink") { - console.log("scout-audit") - try { - await commandExists("cargo-scout-audit"); - } catch (err) { - console.error("cargo-scout-audit is not installed"); - await vscode.window.showErrorMessage( - "cargo-scout-audit must be installed in order for scout to work" - ); - return false; - } - - // Update settings to change rust-analyzer config - await config.update(RUST_ANALYZER_CONFIG, [ - "cargo", - "scout-audit", - "-p vscode", - "--", - "--message-format=json", - ]); - } else if(sdk == "soroban-sdk") { - try { - await commandExists("cargo-scout-audit-soroban"); - } catch (err) { - console.error("cargo-scout-audit-soroban is not installed"); - await vscode.window.showErrorMessage( - "cargo-scout-audit-soroban must be installed in order for scout to work" - ); - return false; - } - - // Update settings to change rust-analyzer config - await config.update(RUST_ANALYZER_CONFIG, [ - "cargo", - "scout-audit-soroban", - "--", - "--message-format=json", - ]); - } + // Update settings to change rust-analyzer config + await config.update(RUST_ANALYZER_CONFIG, [ + "cargo", + "scout-audit", + "--", + "--message-format=json", + ]); } export function deactivate() { // unused } -function isProjectSupported(): false|string { - const workspaceFolders = vscode.workspace.workspaceFolders; - if (!workspaceFolders) { - console.log("No workspace is opened."); +async function checkAndInstallScout(): Promise { + const commandName = `cargo-scout-audit`; + try { + await commandExists(commandName); + return true; + } catch (err) { + const userChoice = await vscode.window.showErrorMessage( + `${commandName} not found. Please install it to proceed.`, + "Install", + "Cancel" + ); + if (userChoice === "Install") { + const terminal = vscode.window.createTerminal({ + name: `Install ${commandName}`, + }); + terminal.show(); + terminal.sendText( + `cargo install cargo-dylint dylint-link ${commandName}`, + true + ); + } return false; } +} - // Get the path of the first workspace folder - const cargoTomlPath = path.join(workspaceFolders[0].uri.fsPath, "Cargo.toml"); - if (!fs.existsSync(cargoTomlPath)) { - console.log("Cargo.toml does not exist in the workspace root."); +async function hasKnownSdk(cargoTomlParsed: CargoToml): Promise { + if (!cargoTomlParsed.dependencies) { + await vscode.window.showErrorMessage( + "No dependencies found in Cargo.toml. Please add 'soroban-sdk' or 'ink' as a dependency." + ); return false; } - // Read and parse the Cargo.toml file - const cargoToml = fs.readFileSync(cargoTomlPath, "utf-8"); - let cargoTomlParsed; + if (cargoTomlParsed.dependencies.ink) { + return true; + } else if (cargoTomlParsed.dependencies["soroban-sdk"]) { + return true; + } else { + await vscode.window.showErrorMessage( + "Neither 'soroban-sdk' nor 'ink' crates are direct dependencies in Cargo.toml." + ); + return false; + } +} + +async function readAndParseCargoToml(): Promise { + const workspaceFolders = vscode.workspace.workspaceFolders!; + const cargoTomlPath = path.join(workspaceFolders[0].uri.fsPath, CARGO_TOML); try { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - cargoTomlParsed = toml.parse(cargoToml); + const cargoToml = fs.readFileSync(cargoTomlPath, "utf-8"); + return toml.parse(cargoToml) as CargoToml; } catch (error) { - console.error("Error parsing Cargo.toml:", error); - return false; + await vscode.window.showErrorMessage( + "Failed to parse Cargo.toml: " + String(error) + ); + return null; } +} - // Check if soroban-sdk or ink are a direct dependency +function isWorkspaceValid(): boolean { + const workspaceFolders = vscode.workspace.workspaceFolders; + if (!workspaceFolders) return false; - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if(cargoTomlParsed?.dependencies?.ink) { - console.log("ink crate is a direct dependency in Cargo.toml.") - return "ink"; - } - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if(cargoTomlParsed?.dependencies?.["soroban-sdk"]) { - console.log("soroban-sdk crate is a direct dependency in Cargo.toml.") - return "soroban-sdk"; - } + const cargoTomlPath = path.join(workspaceFolders[0].uri.fsPath, CARGO_TOML); + if (!fs.existsSync(cargoTomlPath)) return false; - console.log("soroban-sdk or ink crates are not a direct dependency in Cargo.toml."); - return false; + return true; }