diff --git a/ext-src/commands/DetailDocument.ts b/ext-src/commands/DetailDocument.ts index 8065e7b..dd56889 100644 --- a/ext-src/commands/DetailDocument.ts +++ b/ext-src/commands/DetailDocument.ts @@ -16,6 +16,7 @@ export function activateDetailSuggestionCommand(context: vscode.ExtensionContext vuln: Problem; jobId: string; }) => { + const currentWorkSpaceFolder = Utils.getRootFolderName(); const key = `${args.path}@@${args.id}`; const setAnalyzeState = new Analyze(context); const analyzeStateValue = new Analyze(context).get()?.value; @@ -78,6 +79,13 @@ export function activateDetailSuggestionCommand(context: vscode.ExtensionContext type: 'CURRENT_FILE', data: { ...documentMetaData.editor.document }, }); + + getExtensionEventEmitter().fire({ + type: 'CURRENT_PROJECT', + data: { + name: currentWorkSpaceFolder + }, + }); }, 500); await setAnalyzeState.set(copiedAnalyzeValue); diff --git a/ext-src/commands/DiscardSuggestion.ts b/ext-src/commands/DiscardSuggestion.ts index 273cf5e..e5b968e 100644 --- a/ext-src/commands/DiscardSuggestion.ts +++ b/ext-src/commands/DiscardSuggestion.ts @@ -13,7 +13,7 @@ export function activateDiscardCommand(context: vscode.ExtensionContext): void { const command = CONSTANTS.discardSuggestionCommand; const commandHandler = async (args: DiscardCommandHandler) => { - let isDecorationsApplied = false; + const currentWorkSpaceFolder = Utils.getRootFolderName(); const analyzeState = new Analyze(context); const problems = analyzeState.get()?.value; @@ -66,7 +66,7 @@ export function activateDiscardCommand(context: vscode.ExtensionContext): void { } if (isUserOnProblemFile) { - isDecorationsApplied = Utils.decorateCurrentEditorWithHighlights( + Utils.decorateCurrentEditorWithHighlights( results, documentMetaData.editor, ); @@ -87,6 +87,13 @@ export function activateDiscardCommand(context: vscode.ExtensionContext): void { data: { ...documentMetaData.editor.document }, }); + getExtensionEventEmitter().fire({ + type: 'CURRENT_PROJECT', + data: { + name: currentWorkSpaceFolder + }, + }); + await Promise.allSettled([ analyzeState.set(copyProblems), feedbackService.discardSuggestion(payload, session), diff --git a/ext-src/events.ts b/ext-src/events.ts index 31ee0e6..efcb487 100644 --- a/ext-src/events.ts +++ b/ext-src/events.ts @@ -9,6 +9,7 @@ export interface AnalysisEvents { | 'No_Editor_Detected' | 'FIX_SUGGESTION' | 'CURRENT_FILE' + | 'CURRENT_PROJECT' | 'INIT_DATA_UPON_NEW_FILE_OPEN'; data: any; } diff --git a/ext-src/extension.ts b/ext-src/extension.ts index faf8ea6..cb19cce 100644 --- a/ext-src/extension.ts +++ b/ext-src/extension.ts @@ -25,9 +25,8 @@ import { import { Analyze } from './state'; import { Problem } from './types'; -let previousEditor: vscode.TextEditor | undefined = undefined; - export function activate(context: vscode.ExtensionContext): void { + let previousEditor: vscode.TextEditor | undefined = undefined; bootstrapExtensionEventEmitter(); debugChannel.show(true); debugChannel.appendLine('Activating Metabob Extension...'); @@ -129,6 +128,7 @@ export function activate(context: vscode.ExtensionContext): void { context.subscriptions.push( vscode.workspace.onDidSaveTextDocument(document => { let savedDocumentMetaData = Util.extractMetaDataFromDocument(document); + const currentWorkSpaceFolder = Util.getRootFolderName(); if (!savedDocumentMetaData.fileName) return; let fileName: string = savedDocumentMetaData.fileName; @@ -166,11 +166,19 @@ export function activate(context: vscode.ExtensionContext): void { type: 'CURRENT_FILE', data: { ...document }, }); + + extensionEventEmitter.fire({ + type: 'CURRENT_PROJECT', + data: { + name: currentWorkSpaceFolder, + }, + }); }), ); context.subscriptions.push( vscode.workspace.onDidCloseTextDocument(() => { + const currentWorkSpaceFolder = Util.getRootFolderName(); const editor = vscode.window.activeTextEditor; if (!editor || !editor.document) { extensionEventEmitter.fire({ @@ -196,24 +204,48 @@ export function activate(context: vscode.ExtensionContext): void { type: 'CURRENT_FILE', data: { ...editor.document }, }); + extensionEventEmitter.fire({ + type: 'CURRENT_PROJECT', + data: { + name: currentWorkSpaceFolder, + }, + }); } }), ); context.subscriptions.push( vscode.workspace.onDidOpenTextDocument((e: vscode.TextDocument) => { + const currentWorkSpaceFolder = Util.getRootFolderName(); const documentMetaData = Util.extractMetaDataFromDocument(e); - if (!documentMetaData.fileName) return + if (!documentMetaData.fileName) { + debugChannel.appendLine( + 'onDidOpenTextDocument: fileName is undefined. ' + + '\n' + + documentMetaData.relativePath + + '\n' + + documentMetaData.filePath, + ); + return; + } const analyzeState = new Analyze(context); const analyzeValue = analyzeState.get()?.value; - if (!analyzeValue) return; + if (!analyzeValue) { + debugChannel.appendLine('onDidOpenTextDocument: analyzeValue is undefined'); + + return; + } const results: Problem[] | undefined = Util.getCurrentEditorProblems( analyzeValue, documentMetaData.fileName, ); - if (!results) return; + if (!results) { + debugChannel.appendLine('onDidOpenTextDocument: results is undefined'); + + return; + } if (results.length === 0) { extensionEventEmitter.fire({ @@ -233,6 +265,17 @@ export function activate(context: vscode.ExtensionContext): void { type: 'CURRENT_FILE', data: { ...e }, }); + + extensionEventEmitter.fire({ + type: 'CURRENT_PROJECT', + data: { + name: currentWorkSpaceFolder, + }, + }); + debugChannel.appendLine( + 'onDidOpenTextDocument: results have zero length. ' + documentMetaData.fileName, + ); + return; } @@ -259,14 +302,29 @@ export function activate(context: vscode.ExtensionContext): void { type: 'Analysis_Completed', data: { shouldResetRecomendation: true, shouldMoveToAnalyzePage: true, ...analyzeValue }, }); + + extensionEventEmitter.fire({ + type: 'CURRENT_PROJECT', + data: { + name: currentWorkSpaceFolder, + }, + }); }), ); context.subscriptions.push( vscode.window.onDidChangeActiveTextEditor((e: vscode.TextEditor | undefined) => { - if (!e) return; + if (!e) { + debugChannel.appendLine('onDidChangeActiveTextEditor: e is undefined'); + return; + } const { fileName } = Util.extractMetaDataFromDocument(e.document); - if (!fileName) return; + if (!fileName) { + debugChannel.appendLine('onDidChangeActiveTextEditor: fileName is undefined'); + return; + } + + const currentWorkSpaceFolder = Util.getRootFolderName(); if (previousEditor) { previousEditor.setDecorations(decorationType, []); @@ -274,10 +332,16 @@ export function activate(context: vscode.ExtensionContext): void { const analyzeState = new Analyze(context); const analyzeValue = analyzeState.get()?.value; - if (!analyzeValue) return; + if (!analyzeValue) { + debugChannel.appendLine('onDidChangeActiveTextEditor: analyzeValue is undefined'); + return; + } const results: Problem[] | undefined = Util.getCurrentEditorProblems(analyzeValue, fileName); - if (!results) return; + if (!results) { + debugChannel.appendLine('onDidChangeActiveTextEditor: results is undefined'); + return; + } if (results.length === 0) { extensionEventEmitter.fire({ @@ -296,6 +360,19 @@ export function activate(context: vscode.ExtensionContext): void { type: 'CURRENT_FILE', data: { ...e.document }, }); + + extensionEventEmitter.fire({ + type: 'CURRENT_PROJECT', + data: { + name: currentWorkSpaceFolder, + }, + }); + + debugChannel.appendLine( + 'onDidChangeActiveTextEditor: results array has zero length. ' + fileName, + ); + + previousEditor = e; return; } @@ -318,6 +395,13 @@ export function activate(context: vscode.ExtensionContext): void { data: { ...e.document }, }); + extensionEventEmitter.fire({ + type: 'CURRENT_PROJECT', + data: { + name: currentWorkSpaceFolder, + }, + }); + previousEditor = e; }), ); @@ -340,5 +424,4 @@ export function deactivate(): void { debugChannel.dispose(); decorationType.dispose(); disposeExtensionEventEmitter(); - previousEditor = undefined; } diff --git a/ext-src/helpers/HandleDocumentAnalyze.ts b/ext-src/helpers/HandleDocumentAnalyze.ts index 5bf5950..c551fe4 100644 --- a/ext-src/helpers/HandleDocumentAnalyze.ts +++ b/ext-src/helpers/HandleDocumentAnalyze.ts @@ -31,6 +31,7 @@ export const handleDocumentAnalyze = async ( jobId?: string, suppressRateLimitErrors = false, ) => { + const currentWorkSpaceFolder = Util.getRootFolderName(); const editor = vscode.window.activeTextEditor; if (!editor || editor.document.fileName !== metaDataDocument.filePath) { getExtensionEventEmitter().fire({ @@ -38,6 +39,12 @@ export const handleDocumentAnalyze = async ( data: '', }); + getExtensionEventEmitter().fire({ + type: 'CURRENT_PROJECT', + data: { + name: currentWorkSpaceFolder + }, + }); return failedResponseReturn; } @@ -58,6 +65,12 @@ export const handleDocumentAnalyze = async ( type: 'Analysis_Error', data: '', }); + getExtensionEventEmitter().fire({ + type: 'CURRENT_PROJECT', + data: { + name: currentWorkSpaceFolder + }, + }); vscode.window.showErrorMessage(CONSTANTS.analyzeCommandTimeoutMessage); } @@ -67,6 +80,12 @@ export const handleDocumentAnalyze = async ( type: 'Analysis_Error', data: '', }); + getExtensionEventEmitter().fire({ + type: 'CURRENT_PROJECT', + data: { + name: currentWorkSpaceFolder + }, + }); vscode.window.showErrorMessage(CONSTANTS.analyzeCommandErrorMessage); return failedResponseReturn; @@ -83,6 +102,12 @@ export const handleDocumentAnalyze = async ( type: 'Analysis_Error', data: '', }); + getExtensionEventEmitter().fire({ + type: 'CURRENT_PROJECT', + data: { + name: currentWorkSpaceFolder + }, + }); vscode.window.showErrorMessage(CONSTANTS.analyzeCommandErrorMessage); return failedResponseReturn; @@ -115,7 +140,7 @@ export const handleDocumentAnalyze = async ( } return true; }) - .filter((vulnerability) => { + .filter(vulnerability => { const { endLine, startLine } = vulnerability; const range = new vscode.Range( startLine - 1, @@ -124,11 +149,14 @@ export const handleDocumentAnalyze = async ( documentMetaData.editor.document.lineAt(endLine - 1).text.length, ); - const text = documentMetaData.editor.document.getText(range).replace("\n", "").replace("\t", "") + const text = documentMetaData.editor.document + .getText(range) + .replace('\n', '') + .replace('\t', ''); if (text.length === 0 || text === '' || text === ' ') { - return false + return false; } - return true + return true; }) .forEach(problem => { const key = `${problem.path}@@${problem.id}`; @@ -139,6 +167,7 @@ export const handleDocumentAnalyze = async ( isDiscarded: problem.discarded, isEndorsed: problem.endorsed, isViewed: false, + fullFilePath: currentWorkSpaceFolder, }; results[key] = { ...analyzeMetaData }; }); @@ -149,15 +178,23 @@ export const handleDocumentAnalyze = async ( type: 'Analysis_Error', data: '', }); + getExtensionEventEmitter().fire({ + type: 'CURRENT_PROJECT', + data: { + name: currentWorkSpaceFolder + }, + }); vscode.window.showErrorMessage(CONSTANTS.analyzeCommandErrorMessage); return failedResponseReturn; } - Util.decorateCurrentEditorWithHighlights( - problems, - documentMetaData.editor, - ); + const path = problems.map(item => item.path); + + const isUserOnValidEditor = path.includes(documentMetaData.fileName); + if (isUserOnValidEditor) { + Util.decorateCurrentEditorWithHighlights(problems, documentMetaData.editor); + } await analyzeState.set(results); getExtensionEventEmitter().fire({ @@ -165,5 +202,12 @@ export const handleDocumentAnalyze = async ( data: { shouldResetRecomendation: true, shouldMoveToAnalyzePage: true, ...results }, }); + getExtensionEventEmitter().fire({ + type: 'CURRENT_PROJECT', + data: { + name: currentWorkSpaceFolder + }, + }); + return verifiedResponse; }; diff --git a/ext-src/state/Analyze.ts b/ext-src/state/Analyze.ts index b7c51cc..78d72a6 100644 --- a/ext-src/state/Analyze.ts +++ b/ext-src/state/Analyze.ts @@ -1,50 +1,51 @@ -import * as vscode from 'vscode' -import CONSTANTS from '../constants' -import { ExtensionState, ExtensionStateValue } from './Base' +import * as vscode from 'vscode'; +import CONSTANTS from '../constants'; +import { ExtensionState, ExtensionStateValue } from './Base'; export type AnalyseMetaData = { - id: string - path: string - startLine: number - endLine: number - category: string - summary: string - description: string - severity: string - isDiscarded?: boolean + id: string; + path: string; + startLine: number; + endLine: number; + category: string; + summary: string; + description: string; + severity: string; + isDiscarded?: boolean; isEndorsed?: boolean; - isViewed?: boolean -} + isViewed?: boolean; + fullFilePath?: string; +}; export type AnalyzeState = { - [filepathAndProblemId: string]: AnalyseMetaData -} + [filepathAndProblemId: string]: AnalyseMetaData; +}; // Whenever the user Analyze the file, we will store the response of the request in // a store, so user will be able to see decorations upon changing files. export class Analyze extends ExtensionState { constructor(context: vscode.ExtensionContext) { - super(context, CONSTANTS.analyze) + super(context, CONSTANTS.analyze); } get(): ExtensionStateValue | undefined { - return this.context.globalState.get>(this.key) + return this.context.globalState.get>(this.key); } set(value: AnalyzeState): Thenable { - const stateValue = { key: this.key, value } + const stateValue = { key: this.key, value }; - return this.context.globalState.update(this.key, stateValue) + return this.context.globalState.update(this.key, stateValue); } update(callback: (value: AnalyzeState) => AnalyzeState): Thenable { - const currentValue = this.get()?.value ?? {} - const updatedValue = callback(currentValue) + const currentValue = this.get()?.value ?? {}; + const updatedValue = callback(currentValue); - return this.set(updatedValue) + return this.set(updatedValue); } clear(): void { - this.context.globalState.update(this.key, undefined) + this.context.globalState.update(this.key, undefined); } } diff --git a/ext-src/utils.ts b/ext-src/utils.ts index 645ca00..2f967f1 100644 --- a/ext-src/utils.ts +++ b/ext-src/utils.ts @@ -12,6 +12,7 @@ import { import { GenerateDecorations, decorationType } from './helpers'; import CONSTANTS from './constants'; import { AnalyzeState } from './state'; +import debugChannel from './debug'; // Normal Utilities used shared across folders export default class Utils { @@ -130,6 +131,17 @@ export default class Utils { }); } + static getRootFolderName(): string | undefined { + const workspaceFolders = vscode.workspace.workspaceFolders; + + if (workspaceFolders) { + const rootFolder = workspaceFolders[0]; + return rootFolder.name; + } + + return undefined; // No workspace folder + } + static getFileNameFromCurrentEditor(): { fileName: string; editor: vscode.TextEditor diff --git a/src/components/Analyze/ProblemList/index.tsx b/src/components/Analyze/ProblemList/index.tsx index 8e179fc..e0055a8 100644 --- a/src/components/Analyze/ProblemList/index.tsx +++ b/src/components/Analyze/ProblemList/index.tsx @@ -52,17 +52,17 @@ export const ProblemList = ({ - - + + {item.name} - +