diff --git a/.prettierignore b/.prettierignore index b496a5df39020e2c2c692ef25b0f1c662e76c023..4a0c75e84f6562661d0898c8a8a2a91909cf2d8b 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,3 +4,4 @@ out/ assets .DS_Store *.md +/client/src/types/git.d.ts diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 9db69433634ca5b6803e818ce6ae8a5023167994..1e3e6a4771f9e34929acdf2ed7b17e5f22452f95 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -10,6 +10,7 @@ "ms-python.python", "rioj7.commandOnAllFiles", "nsoult.typescript-imports-sort", - "connor4312.esbuild-problem-matchers" + "connor4312.esbuild-problem-matchers", + "ryuta46.multi-command" ] } diff --git a/.vscode/launch.json b/.vscode/launch.json index e9fa0a03ed341ac2870b5e2f8c5ce04b12476c8a..4212f36a61662705a58b094915e03db35416b118 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -27,7 +27,25 @@ "outFiles": ["${workspaceFolder}/out/**/*.js"], // Automatically attach language server child process "autoAttachChildProcesses": true, - "preLaunchTask": "all_watch" + "preLaunchTask": "watch_esbuild" + // "postDebugTask": "terminateTasks" + }, + { + "name": "Run Extension (TSC)", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}", + // Disable other extensions when debugging + "--disable-extensions", + // Specific workspace root directory + "${workspaceRoot}/testRoot" + ], + "outFiles": ["${workspaceFolder}/out/**/*.js"], + // Automatically attach language server child process + "autoAttachChildProcesses": true, + "preLaunchTask": "watch_tsc" // "postDebugTask": "terminateTasks" }, { @@ -40,7 +58,7 @@ "${workspaceRoot}/testRoot" ], "outFiles": ["${workspaceFolder}/client/out/test/**/*.js"], - "preLaunchTask": "all_watch" + "preLaunchTask": "watch_esbuild" } ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 9fc8ab9d196e0885c69170fd8022db676c622fba..8bd40f400bbbac911596f15bbba7f025cbd8722c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,6 +14,10 @@ "typescript.preferences.quoteStyle": "single", // 保存时自动格式化文件 "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.sortImports": "explicit", + "source.removeUnusedImports": "explicit" + }, // 使用 prettier 作为首选格式化工具 "editor.defaultFormatter": "esbenp.prettier-vscode", "[markdown]": { @@ -27,18 +31,25 @@ "appenders", "iscas", "Mulan", + "outdir", "prewatch", "prismjs", - "rvportingtool", "RVCodingAsst", + "rvportingtool", "shiki", "tcse", "Upto" ], + "multiCommand.commands": [ + { + "command": "multiCommand.tsFormat", + "sequence": ["workbench.action.files.save"] + } + ], "commandOnAllFiles.commands": { - "Typescript Import Sort": { - "command": "extension.typescriptImportsSort", - "includeFileExtensions": [".ts"] + "Format Typescript": { + "command": "multiCommand.tsFormat", + "includeFileExtensions": [".ts", ".tsx"] } }, "editor.tabSize": 2, diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 86a70756b37a01dec5198fefa322045e7f7a63c8..bcd758840679302ff5b05468b17351a367aaf003 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -3,31 +3,24 @@ { "version": "2.0.0", "tasks": [ - { - "label": "all_watch", - "dependsOn": ["tsc_watch", "esbuild_watch"], - "group": { - "kind": "build", - "isDefault": true - } - }, { "type": "npm", - "script": "watch_esbuild", - "label": "esbuild_watch", + "script": "watch", + "label": "watch_esbuild", "problemMatcher": "$esbuild-watch", "isBackground": true, "presentation": { "reveal": "always" }, "group": { - "kind": "build" + "kind": "build", + "isDefault": true } }, { "type": "npm", - "script": "watch", - "label": "tsc_watch", + "script": "watch_tsc", + "label": "watch_tsc", "problemMatcher": "$tsc-watch", "isBackground": true, "presentation": { diff --git a/client/package.json b/client/package.json index 3748aabc213658393e593b92896450c748615a37..da197bc53dccc201c142824fce7675f475ff7394 100644 --- a/client/package.json +++ b/client/package.json @@ -13,6 +13,7 @@ "@vscode/l10n": "^0.0.18", "@vscode/webview-ui-toolkit": "^1.4.0", "log4js": "^6.9.1", + "string-format": "^2.0.0", "vscode-languageclient": "^9.0.1" }, "devDependencies": { diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml index b40fa64a21b327db5082fd24f1b48524527cee82..fea8a8f9ce8247d688934b340135d4c3bb58d6b7 100644 --- a/client/pnpm-lock.yaml +++ b/client/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: log4js: specifier: ^6.9.1 version: 6.9.1 + string-format: + specifier: ^2.0.0 + version: 2.0.0 vscode-languageclient: specifier: ^9.0.1 version: 9.0.1 @@ -249,6 +252,9 @@ packages: resolution: {integrity: sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==} engines: {node: '>=8.0'} + string-format@2.0.0: + resolution: {integrity: sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==} + string-width@6.1.0: resolution: {integrity: sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==} engines: {node: '>=16'} @@ -534,6 +540,8 @@ snapshots: transitivePeerDependencies: - supports-color + string-format@2.0.0: {} + string-width@6.1.0: dependencies: eastasianwidth: 0.2.0 diff --git a/client/src/codeScan/codeCommit.ts b/client/src/codeScan/codeCommit.ts new file mode 100644 index 0000000000000000000000000000000000000000..7ac7316311348b74e7e9a327e729b75a97e895c8 --- /dev/null +++ b/client/src/codeScan/codeCommit.ts @@ -0,0 +1,65 @@ +import { exec } from "child_process"; +import * as vscode from "vscode"; + +function runGitCommand(command: string, workspaceRoot: string): Promise { + return new Promise((resolve, reject) => { + exec(command, { cwd: workspaceRoot }, (error, stdout, stderr) => { + if (error) { + console.log(`stdout: ${stdout}; stderr: ${stderr}; error.message: ${error.message}`); + } else { + console.log(`stdout: ${stdout}; stderr: ${stderr}`); + } + resolve(stdout.trim()); + }); + }); +} + +export async function commitToCodeScanBranch(): Promise { + const workspaceRoot = vscode.workspace.workspaceFolders?.[0].uri.fsPath; + console.log(workspaceRoot); + const targetBranch = "codeScan"; + + if (!workspaceRoot) { + vscode.window.showErrorMessage("无法找到工作区目录"); + return undefined; + } + + try { + // 获取当前分支 + const currentBranch = await runGitCommand("git rev-parse --abbrev-ref HEAD", workspaceRoot); + vscode.window.showInformationMessage(`当前分支:${currentBranch}`); + + // 暂存当前工作区的修改 + // await runGitCommand("git stash", workspaceRoot); + await runGitCommand(`git stash`, workspaceRoot); + + await runGitCommand(`git branch ${targetBranch}`, workspaceRoot); + await runGitCommand(`git checkout ${targetBranch}`, workspaceRoot); + + // git checkout source-branch -- . + await runGitCommand(`git checkout ${currentBranch} -- .`, workspaceRoot); + + await runGitCommand(`git stash apply`, workspaceRoot); + + await runGitCommand(`git add -A`, workspaceRoot); + + // 提交修改到目标分支 + await runGitCommand(`git commit -m "commit for scan"`, workspaceRoot); + + // 获取最新提交的哈希值 + const commitHash = await runGitCommand("git log -1 --format=%H", workspaceRoot); + + // 切换回原分支 + await runGitCommand(`git checkout ${currentBranch}`, workspaceRoot); + + await runGitCommand(`git stash pop`, workspaceRoot); + + vscode.window.showInformationMessage( + `修改已提交到分支 ${targetBranch},提交哈希:${commitHash}`, + ); + return commitHash; + } catch (error) { + vscode.window.showErrorMessage(`操作失败: ${error}`); + return undefined; + } +} diff --git a/client/src/codeScan/codeScanManager.ts b/client/src/codeScan/codeScanManager.ts new file mode 100644 index 0000000000000000000000000000000000000000..5882ed40d62c5b3ba2a62499f4a68f6047a6a040 --- /dev/null +++ b/client/src/codeScan/codeScanManager.ts @@ -0,0 +1,230 @@ +/*************************************************************************************** + * Copyright (c) 2023-2024 RVSmartPorting. All rights reserved. + * RVPortingTool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + **************************************************************************************/ + +/*************************************************************************************** + * Code Scan Manager for RVPortingTool VSCode Extension + * + * Author: Lightning Rainstorm + * liccc + * Last Change: Sep 11, 2024 + **************************************************************************************/ + +import * as fs from "fs"; +import * as vscode from "vscode"; +import * as lsp from "vscode-languageclient"; +import { CommandID } from "../../../common/src/types/command"; +import { LSPNotificationID } from "../../../common/src/types/notification"; +import { ReportMgrLoadParams } from "../../../common/src/types/reportManager"; +import { ScanServerConfig } from "../types/codeScan"; +import { GitUtility } from "../utils/git"; +import { ClientLogger } from "../utils/log"; +import { commitToCodeScanBranch } from "./codeCommit"; +import { demoData } from "./demoData"; + +const logger = ClientLogger.getLogger("CodeScanManager"); + +export class CodeScanManager { + private static _instance: CodeScanManager; + + private constructor( + private readonly _context: vscode.ExtensionContext, + private readonly _client: lsp.BaseLanguageClient, + ) {} + + public static getInstance(): CodeScanManager { + if (!this._instance) { + const msg = "CodeScanManager has not been initialized yet"; + logger.error(msg); + throw new Error(msg); + } + return this._instance; + } + + public static init(context: vscode.ExtensionContext, client: lsp.BaseLanguageClient): void { + this._instance = new CodeScanManager(context, client); + + context.subscriptions.push( + // 注册命令 代码扫描:开始扫描 + vscode.commands.registerCommand(CommandID.codeScanStart, async () => { + this._instance.startScan(); + }), + ); + } + + public async startScan(): Promise { + logger.info("Start code scan"); + const server = await this.chooseScanServer(); + + // 检查是否接受扫描服务器的许可协议 + if (!server.acceptedLicense) { + const accepted = await this.showServerLicense(server); + if (!accepted) { + return; + } + } + + // 检查是否已打开存储库 + if (!(await GitUtility.checkIsSCMRepoOpened())) { + vscode.window.showErrorMessage( + vscode.l10n.t("Cannot perform code scan! Please open a repository first"), + ); + return; + } + + // TODO: 当打开的工作区数量多于一个时,让用户选择工作区 + // TODO: 当打开的存储库数量多于一个时,让用户选择存储库 + // TODO: 检查工作区 .vscode/archive.tar.gz 是否可写 + + const commitId = await commitToCodeScanBranch(); + logger.info(`Commit id: ${commitId}. Use this to generate archive and patch`); + + // ======== FOR DEMO USE ONLY ======== + const sleep = (time: number) => { + return new Promise((resolve) => { + setTimeout(() => { + resolve(true); + }, time); + }); + }; + + vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: vscode.l10n.t("Scanning code"), + cancellable: true, + }, + async (progress, token) => { + return new Promise(async (resolve) => { + token.onCancellationRequested(() => { + logger.info("Scan cancelled by user"); + }); + + progress.report({ + message: vscode.l10n.t("Preparing archive..."), + increment: 0, + }); + + const workspace = vscode.workspace.workspaceFolders![0]; + const archivePath = vscode.Uri.joinPath(workspace.uri, ".vscode/archive.tar.gz"); + try { + await GitUtility.createGitArchive(workspace.uri.fsPath, archivePath.fsPath); + } catch (error) { + logger.error(error); + resolve(); + } + + await sleep(200); + + progress.report({ + message: vscode.l10n.t("Uploading archive..."), + increment: 20, + }); + + await sleep(150); + + fs.unlinkSync(archivePath.fsPath); + + progress.report({ + message: vscode.l10n.t("Server analyzing code..."), + increment: 20, + }); + + await sleep(300); + + progress.report({ + message: vscode.l10n.t("Server finalizing report..."), + increment: 20, + }); + + await sleep(100); + + progress.report({ + message: vscode.l10n.t("Downloading report..."), + increment: 20, + }); + + await sleep(150); + + progress.report({ + message: vscode.l10n.t("Loading report..."), + increment: 20, + }); + + await sleep(50); + + // 通知 Language Server 读取报告 + // const reportUri = vscode.Uri.joinPath(workspace.uri, "example-hint.json"); + const reportUri = vscode.Uri.joinPath(workspace.uri, "example2.json"); + this._client.sendNotification(LSPNotificationID.reportMgrSrvLoad, { + workspaceUri: workspace.uri.toString(), + reportUri: reportUri.toString(), + reloadConfirm: false, + }); + + await sleep(50); + + resolve(); + }); + }, + ); + + // ./====== FOR DEMO USE ONLY ======== + } + + /** + * 选择扫描服务器 + * + * @returns 扫描服务器配置 + */ + public async chooseScanServer(): Promise { + return new Promise((resolve) => { + const quickPick = vscode.window.createQuickPick(); + quickPick.items = demoData.scanServers.map( + (server) => + { + label: server.name, + description: server.endpoint, + }, + ); + quickPick.onDidAccept(() => { + const selected = quickPick.selectedItems[0]; + if (selected) { + resolve(demoData.scanServers.find((server) => server.name === selected.label)!); + } + quickPick.dispose(); + }); + quickPick.show(); + }); + } + + public async showServerLicense(server: ScanServerConfig): Promise { + return new Promise((resolve) => { + const licText = demoData.serverLicense; + vscode.window + .showInformationMessage( + licText, + { + modal: true, + }, + vscode.l10n.t("Accept License"), + ) + .then((value) => { + if (value === vscode.l10n.t("Accept License")) { + server.acceptedLicense = true; + resolve(true); + } else { + resolve(false); + } + }); + }); + } +} diff --git a/client/src/codeScan/demoData.ts b/client/src/codeScan/demoData.ts new file mode 100644 index 0000000000000000000000000000000000000000..988e434b40a60b6c989b50742984433d3e97b7c5 --- /dev/null +++ b/client/src/codeScan/demoData.ts @@ -0,0 +1,49 @@ +/*************************************************************************************** + * Copyright (c) 2023-2024 RVSmartPorting. All rights reserved. + * RVPortingTool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + **************************************************************************************/ + +/*************************************************************************************** + * Demo Data of Code Scan Manager for RVPortingTool VSCode Extension + * + * Author: Lightning Rainstorm + * liccc + * Last Change: Sep 11, 2024 + **************************************************************************************/ + +import * as vscode from "vscode"; +import { ScanServerConfig } from "../types/codeScan"; + +export const demoData = { + scanServers: [ + { + name: vscode.l10n.t("RVPortingTool Official Server"), + endpoint: "https://code-scan.rvpt.top/server-1", + userName: "demo", + secretKey: "RVPortingTool", + keepCode: true, + }, + { + name: vscode.l10n.t("Self-deployed Server A"), + endpoint: "https://self-deployed.scan.server", + userName: "demo", + secretKey: "RVPortingTool", + keepCode: true, + }, + ], + + serverLicense: vscode.l10n.t( + "RVPortingTool Official Code Scanning Server License\n\n\ +1. This is a demo server, please do not use it for production.\n\ +2. Your code might be store on this server for a while, please do not store any sensitive information.\n\ +3. This server is provided as-is, without any warranty or liability.\n\ +4. If you have any questions or concerns, please contact us at support@rvpt.top.", + ), +}; diff --git a/client/src/extension.ts b/client/src/extension.ts index b571301c5416be394cea0d96da7c11c923c02099..5a4868243c113d8d98c0d64e556ed8da1e96c1dc 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -14,19 +14,21 @@ * Client Entry for RVPortingTool VSCode Extension * * Author: Lightning Rainstorm - * Last Change: Sep 6, 2024 + * Last Change: Sep 10, 2024 **************************************************************************************/ import * as path from "path"; import * as vscode from "vscode"; -import { ClientLogger } from "./utils/log"; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, } from "vscode-languageclient/node"; +import { CodeScanManager } from "./codeScan/codeScanManager"; import { ReportManagerClient } from "./reportManagerClient"; +import { SidebarHelper } from "./sidebarHelper"; +import { ClientLogger } from "./utils/log"; import { WikiHelper } from "./wikiHelper"; // 全局 Language Client @@ -86,6 +88,12 @@ export async function activate(context: vscode.ExtensionContext) { // 初始化 Wiki Helper WikiHelper.init(context, client); + // 初始化 Sidebar Helper + SidebarHelper.init(context); + + // 初始化 Code Scan Manager + CodeScanManager.init(context, client); + // 启动 Language Client,同时启动 Server // client.start(); } diff --git a/client/src/reportManagerClient.ts b/client/src/reportManagerClient.ts index 00dc93fa4de890f7e04821f0d1a88a4d30da298e..cdef243a5b014373792ceb67380af03bdb840c86 100644 --- a/client/src/reportManagerClient.ts +++ b/client/src/reportManagerClient.ts @@ -14,22 +14,22 @@ * Language Client Report Manager for RVPortingTool VSCode Extension * * Author: Lightning Rainstorm - * Last Change: Sep 6, 2024 + * Last Change: Sep 11, 2024 **************************************************************************************/ -import * as lsp from "vscode-languageclient"; import * as vscode from "vscode"; -import { checkerRules } from "./types/checkerRules"; -import { ClientLogger } from "./utils/log"; +import * as lsp from "vscode-languageclient"; import { CommandID } from "../../common/src/types/command"; import { LSPNotificationID } from "../../common/src/types/notification"; -import { LSPRequestID } from "../../common/src/types/request"; import { ReportMgrLoadError, ReportMgrLoadParams, ReportMgrSaveError, ReportMgrSaveParams, } from "../../common/src/types/reportManager"; +import * as lspRequestTypes from "../../common/src/types/request"; +import { checkerRules } from "./types/checkerRules"; +import { ClientLogger } from "./utils/log"; import path = require("path"); /** 模块日志记录器 */ @@ -37,6 +37,8 @@ const logger = ClientLogger.getLogger("reportMgrClient"); /** 代码问题报告管理器(客户端) */ export class ReportManagerClient { + private static _instance: ReportManagerClient; + /** LSP 客户端 */ private _client: lsp.BaseLanguageClient; @@ -44,25 +46,37 @@ export class ReportManagerClient { this._client = client; } + public static getInstance() { + if (!this._instance) { + const msg = "ReportManagerClient has not been initialized yet"; + logger.error(msg); + throw new Error(msg); + } + return this._instance; + } + public static init( context: vscode.ExtensionContext, client: lsp.BaseLanguageClient, ): ReportManagerClient { - const manager = new ReportManagerClient(client); + this._instance = new ReportManagerClient(client); // 注册模块所定义命令 context.subscriptions.push( // 选择工作区,并从本地文件读入报告 - vscode.commands.registerCommand(CommandID.reportMgrLoadFromFile, () => { - manager.chooseReportWorkspace((workspace) => { + vscode.commands.registerCommand(CommandID.reportMgrImportReport, () => { + this._instance.chooseReportWorkspace((workspace) => { if (workspace !== undefined) { - manager.loadReportToWorkspace(LSPNotificationID.reportMgrLoadFromFile, workspace); + this._instance.loadReportToWorkspace( + LSPNotificationID.reportMgrCliImportReport, + workspace, + ); } }); }), // 导出报告(用户选择工作区) - vscode.commands.registerCommand(CommandID.reportMgrExport, () => { + vscode.commands.registerCommand(CommandID.reportMgrExportReport, () => { const diagCollection = vscode.languages.createDiagnosticCollection("test"); const docUri = vscode.Uri.parse( "file:///m%3A/Projects/RISC-V/rv-vsc-plugin/testRoot/TestPoisonArea.c", @@ -76,61 +90,76 @@ export class ReportManagerClient { source: "test1234", }, ]); - manager.exportReport(); + this._instance.exportReport(); }), // 保存所有报告(缓存到工作区) vscode.commands.registerCommand(CommandID.reportMgrSaveAllReportsCache, () => { - manager.saveAllReportsCache(); + this._instance.saveAllReportsCache(); + }), + + // 卸载所有报告 + vscode.commands.registerCommand(CommandID.reportMgrUnloadAllReport, () => { + this._instance.unloadAllReport(); + }), + + // 清除所有报告 + vscode.commands.registerCommand(CommandID.reportMgrClearAllReport, () => { + this._instance.clearAllReport(); }), ); // 注册模块所属回调方法 // 注册请求:获取报告信息 - client.onRequest(LSPRequestID.reportMgrGetRuleInfo, async (ruleId: string) => { + client.onRequest(lspRequestTypes.LSPRequestID.reportMgrGetRuleInfo, async (ruleId: string) => { return checkerRules.get(ruleId); }); // 注册通知:报告读取错误 - client.onNotification(LSPNotificationID.reportMgrLoadError, (data) => { - manager.onLoadError(data); + client.onNotification(LSPNotificationID.reportMgrCliLoadError, (data) => { + this._instance.onLoadError(data); }); // 注册通知:报告替换确认 - client.onNotification(LSPNotificationID.reportMgrReloadConfirm, (data) => { - manager.onReloadConfirm(data); + client.onNotification(LSPNotificationID.reportMgrCliReloadConfirm, (data) => { + this._instance.onReloadConfirm(data); }); // 注册通知:报告加载完成 - client.onNotification(LSPNotificationID.reportMgrLoadFinished, (data) => { - manager.onLoadFinished(data); + client.onNotification(LSPNotificationID.reportMgrCliLoadFinished, (data) => { + this._instance.onLoadFinished(data); }); // 注册通知:报告加载完成,但缓存到工作区失败 - client.onNotification(LSPNotificationID.reportMgrLoadFinishedWithSaveError, () => { - manager.onLoadFinishedWithSaveError(); + client.onNotification(LSPNotificationID.reportMgrCliLoadFinishedWithSaveError, () => { + this._instance.onLoadFinishedWithSaveError(); }); // 注册通知:报告保存成功 - client.onNotification(LSPNotificationID.reportMgrSaveFinished, (data) => { - manager.onSaveFinished(data); + client.onNotification(LSPNotificationID.reportMgrCliSaveFinished, (data) => { + this._instance.onSaveFinished(data); }); // 注册通知:保存全部报告(缓存到工作区)成功 - client.onNotification(LSPNotificationID.reportMgrSaveCacheAllFinished, (data) => { - manager.onSaveAllCacheFinished(data); + client.onNotification(LSPNotificationID.reportMgrCliSaveCacheAllFinished, (data) => { + this._instance.onSaveAllCacheFinished(data); }); // 注册通知:报告保存失败 - client.onNotification(LSPNotificationID.reportMgrSaveError, (data) => { - manager.onSaveError(data); + client.onNotification(LSPNotificationID.reportMgrCliSaveError, (data) => { + this._instance.onSaveError(data); + }); + + // 注册通知:报告卸载 + client.onNotification(LSPNotificationID.reportMgrCliUnloadFinished, () => { + this._instance.onUnload(); }); // 发送通知:加载报告 JSON Schema const schemaPath = context.asAbsolutePath("resources/report_schema.json"); - client.sendNotification(LSPNotificationID.reportMgrLoadSchema, schemaPath); + client.sendNotification(LSPNotificationID.reportMgrSrvLoadSchema, schemaPath); - return manager; + return this._instance; } /** @@ -170,6 +199,9 @@ export class ReportManagerClient { ), vscode.l10n.t("Confirm"), ); + + // 刷新侧边栏状态 + vscode.commands.executeCommand(CommandID.sidebarViewRefreshState); } /** @@ -199,7 +231,7 @@ Your operations will be lost if you don't export the report manually after worki vscode.window.showWarningMessage(message, messageOptions, ...nextOptions).then((value) => { if (value === optionConfirm) { data.reloadConfirm = true; - this._client.sendNotification(LSPNotificationID.reportMgrLoad, data); + this._client.sendNotification(LSPNotificationID.reportMgrSrvLoad, data); } }); } @@ -240,11 +272,18 @@ Your operations will be lost if you don't export the report manually after worki } vscode.window.showErrorMessage(message, messageOptions, ...nextOptions).then((value) => { if (value === optionRetry) { - this._client.sendNotification(LSPNotificationID.reportMgrLoad, loadParams); + this._client.sendNotification(LSPNotificationID.reportMgrSrvLoad, loadParams); } }); } + /** + * 报告卸载 + */ + public onUnload() { + vscode.commands.executeCommand(CommandID.sidebarViewRefreshState); + } + /** * 导入报告前选择工作区 * @@ -276,6 +315,34 @@ Your operations will be lost if you don't export the report manually after worki .then(callback); } + /** + * 检查已打开的任何工作区是否包含报告 + */ + public async checkAnyWorkspaceHasReport(callback: (res: boolean) => void) { + const wsFolders = vscode.workspace.workspaceFolders; + if (!wsFolders) { + callback(false); + return; + } + let hasReport = false; + for (const wsFolder of wsFolders) { + const res = await this._client.sendRequest( + lspRequestTypes.LSPRequestID.reportMgrGetWorkspaceMeta, + { + workspaceUri: wsFolder.uri.toString(), + }, + ); + if (res.reportMeta) { + callback(true); + hasReport = true; + break; + } + } + if (!hasReport) { + callback(false); + } + } + /** * 导出报告(用户选择工作区) */ @@ -305,7 +372,7 @@ Your operations will be lost if you don't export the report manually after worki }) .then((uri) => { if (uri) { - this._client.sendNotification(LSPNotificationID.reportMgrSave, { + this._client.sendNotification(LSPNotificationID.reportMgrSrvSave, { workspaceUri: workspaceUri.toString(), reportUri: uri.toString(), replaceConfirm: true, // 保存框选择时会提示是否替换 @@ -320,7 +387,77 @@ Your operations will be lost if you don't export the report manually after worki * 保存所有报告(缓存到工作区) */ public saveAllReportsCache() { - this._client.sendNotification(LSPNotificationID.reportMgrSaveCacheAll); + this._client.sendNotification(LSPNotificationID.reportMgrSrvSaveCacheAll); + } + + /** + * 卸载所有报告(暂时性卸载,要求用户确认) + */ + public unloadAllReport() { + const message = vscode.l10n.t("Report unload confirm"); + const messageOptions: vscode.MessageOptions = { + detail: vscode.l10n.t( + "Are you sure to temporarily unload all loaded reports? The reports will be automatically load next time after reloading or restarting Workspace/VSCode.", + ), + modal: true, + }; + const nextOptions: string[] = []; + const optionConfirm = vscode.l10n.t("Confirm"); + nextOptions.push(optionConfirm); + vscode.window.showInformationMessage(message, messageOptions, ...nextOptions).then((value) => { + if (value === optionConfirm) { + this._doUnloadAllReport(); + } + }); + } + + /** + * 卸载所有报告 + */ + private _doUnloadAllReport() { + const wsFolders = vscode.workspace.workspaceFolders; + if (!wsFolders) { + // 未获取到工作区文件夹 + logger.warn("workspace folders not found when unload all report"); + return; + } + const wsFoldersUri = wsFolders.map((wsFolder) => wsFolder.uri.toString()); + this._client.sendNotification(LSPNotificationID.reportMgrSrvUnload, wsFoldersUri); + } + + /** + * 清除所有报告(要求用户确认) + */ + public clearAllReport() { + const message = vscode.l10n.t("Report clear confirm"); + const messageOptions: vscode.MessageOptions = { + detail: vscode.l10n.t( + "Are you sure to clear all loaded reports? This operation will remove it from workspace cache too!", + ), + modal: true, + }; + const nextOptions: string[] = []; + const optionConfirm = vscode.l10n.t("Confirm"); + nextOptions.push(optionConfirm); + vscode.window.showWarningMessage(message, messageOptions, ...nextOptions).then((value) => { + if (value === optionConfirm) { + this._doClearAllReport(); + } + }); + } + + /** + * 清除所有报告 + */ + private _doClearAllReport() { + const wsFolders = vscode.workspace.workspaceFolders; + if (!wsFolders) { + // 未获取到工作区文件夹 + logger.warn("workspace folders not found when clear all report"); + return; + } + const wsFoldersUri = wsFolders.map((wsFolder) => wsFolder.uri.toString()); + this._client.sendNotification(LSPNotificationID.reportMgrSrvClear, wsFoldersUri); } /** @@ -377,9 +514,9 @@ Your operations will be lost if you don't export the report manually after worki data?: any, ) { // 根据 notificationId 判断导入方式(本地或在线) - if (notificationId === LSPNotificationID.reportMgrLoadFromFile) { - this.loadFromFileToWorkspace(workspace); - } else if (notificationId === LSPNotificationID.reportMgrLoadFromServer) { + if (notificationId === LSPNotificationID.reportMgrCliImportReport) { + this.importReportToWorkspace(workspace); + } else if (notificationId === LSPNotificationID.reportMgrCliLoadFromServer) { this.loadFromServerToWorkspace(workspace, data); } else { logger.error("loadReportToWorkspace: invalid notificationID: ".concat(notificationId)); @@ -393,7 +530,7 @@ Your operations will be lost if you don't export the report manually after worki * @param workspace 工作区文件夹 * @param data 额外导入参数 */ - private loadFromFileToWorkspace(workspace: vscode.WorkspaceFolder) { + private importReportToWorkspace(workspace: vscode.WorkspaceFolder) { const fileFilters: { [name: string]: string[] } = {}; fileFilters[vscode.l10n.t("Code Scan Report")] = ["json"]; vscode.window @@ -404,11 +541,11 @@ Your operations will be lost if you don't export the report manually after worki }) .then((uri) => { if (uri === undefined || uri.length < 1) { - logger.debug("loadFromFileToWorkspace: no uri"); + logger.debug("importReportToWorkspace: no uri"); return; } // 通知 Language Server 读取报告 - this._client.sendNotification(LSPNotificationID.reportMgrLoad, { + this._client.sendNotification(LSPNotificationID.reportMgrSrvLoad, { workspaceUri: workspace.uri.toString(), reportUri: uri[0].toString(), reloadConfirm: false, diff --git a/client/src/sidebarHelper.ts b/client/src/sidebarHelper.ts new file mode 100644 index 0000000000000000000000000000000000000000..0fd366887278142a7011a71b5048c74b3e8b9320 --- /dev/null +++ b/client/src/sidebarHelper.ts @@ -0,0 +1,49 @@ +/*************************************************************************************** + * Copyright (c) 2023-2024 RVSmartPorting. All rights reserved. + * RVPortingTool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + **************************************************************************************/ + +/*************************************************************************************** + * (Client) Sidebar Helper for RVPortingTool VSCode Extension + * + * Author: Lightning Rainstorm + * Last Change: Sep 10, 2024 + **************************************************************************************/ + +import * as vscode from "vscode"; +import { CommandID } from "../../common/src/types/command"; +import { SidebarViewProvider } from "./sidebarView/sidebarViewProvider"; +import { ClientLogger } from "./utils/log"; + +const logger = ClientLogger.getLogger("WikiHelper"); + +export class SidebarHelper { + private constructor() {} + + public static init(context: vscode.ExtensionContext): SidebarHelper { + const manager = new SidebarHelper(); + const sidebarViewProvider = new SidebarViewProvider(context.extensionUri); + + context.subscriptions.push( + // 注册 SidebarViewProvider + vscode.window.registerWebviewViewProvider(SidebarViewProvider.viewType, sidebarViewProvider, { + webviewOptions: { + retainContextWhenHidden: true, + }, + }), + + // 注册侧边栏刷新命令 + vscode.commands.registerCommand(CommandID.sidebarViewRefreshState, () => { + sidebarViewProvider.controller?.refreshState(); + }), + ); + return manager; + } +} diff --git a/client/src/sidebarView/sidebarViewController.ts b/client/src/sidebarView/sidebarViewController.ts new file mode 100644 index 0000000000000000000000000000000000000000..0f8043477f996cd2cbbce256e0aecb3986ae0e76 --- /dev/null +++ b/client/src/sidebarView/sidebarViewController.ts @@ -0,0 +1,151 @@ +/*************************************************************************************** + * Copyright (c) 2023-2024 RVSmartPorting. All rights reserved. + * RVPortingTool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + **************************************************************************************/ + +/*************************************************************************************** + * (Client) Sidebar View Controller for RVPortingTool VSCode Extension + * + * Author: Lightning Rainstorm + * Last Change: Sep 11, 2024 + **************************************************************************************/ + +import * as vscode from "vscode"; +import { CommandID } from "../../../common/src/types/command"; +import * as viewTypes from "../../../common/src/types/sidebarView"; +import { ReportManagerClient } from "../reportManagerClient"; +import { GitUtility } from "../utils/git"; +import { ClientLogger } from "../utils/log"; +import strFormat = require("string-format"); + +const logger: ClientLogger = ClientLogger.getLogger("client.SidebarViewController"); + +export class SidebarViewController { + public constructor( + private readonly _extensionUri: vscode.Uri, + private readonly _view: vscode.WebviewView, + ) { + this._view.webview.onDidReceiveMessage((message: any) => { + this.onDidReceiveMessage(message); + }); + this._view.onDidChangeVisibility(() => { + this.onDidChangeVisibility(); + }); + } + + public refreshState(): void { + logger.info(`Refreshing state`); + // 刷新 SCM 状态 + this._checkIsSCMRepoOpened(); + + // 刷新扫描报告状态 + this._checkReportState(); + } + + public onDidChangeVisibility(): void { + if (this._view?.visible) { + // WebView 变为可见,刷新所有状态 + this.refreshState(); + } else { + // WebView 变为不可见 + } + } + + /** + * 检查已打开的任何工作区是否包含代码扫描报告 + * + * 根据包含与否向 sidebarView 发送对应消息 + */ + private _checkReportState(): void { + const reportMgr = ReportManagerClient.getInstance(); + reportMgr.checkAnyWorkspaceHasReport((res) => { + if (res) { + // 已有加载了扫描报告的工作区 + logger.info(`Workspace has report`); + this._view?.webview.postMessage({ + type: "CodeHasReportMsg", + content: "Has report", + }); + } else { + // 尚无加载了扫描报告的工作区 + logger.info(`Workspace has no report`); + this._view?.webview.postMessage({ + type: "CodeNoReportMsg", + content: "No report", + }); + } + }); + } + + /** + * 检测当前是否已打开 Git 存储库 + * + * 根据存储库打开或关闭状态向 sidebarView 发送对应消息 + */ + private async _checkIsSCMRepoOpened(): Promise { + const openedMsg = { + type: "CodeOpenedRepoMsg", + content: "Git repo is opened", + }; + const closedMsg = { + type: "CodeClosedRepoMsg", + content: "Git repo is closed", + }; + const gitApi = await GitUtility.getGitAPI(); + if (!gitApi) { + logger.info(`Git extension not available`); + this._view?.webview.postMessage(closedMsg); + return; + } + // 注册回调事件 + gitApi.onDidOpenRepository((_) => { + logger.info(`onDidOpenRepository triggered`); + this._view?.webview.postMessage(openedMsg); + }); + gitApi.onDidCloseRepository((_) => { + logger.info(`onDidCloseRepository triggered`); + this._view?.webview.postMessage(closedMsg); + }); + + // 主动检查一次 + if (await GitUtility.checkIsSCMRepoOpened()) { + logger.info(`checkIsSCMRepoOpened returned true`); + this._view?.webview.postMessage(openedMsg); + } else { + logger.info(`checkIsSCMRepoOpened returned false`); + this._view?.webview.postMessage(closedMsg); + } + } + + public onDidReceiveMessage(message: any) { + if (viewTypes.SidebarViewMsgUtil.isViewLoadedMsg(message)) { + // WebView 加载完毕,触发一次状态刷新 + this.refreshState(); + } else if (viewTypes.SidebarViewMsgUtil.isUserOpenSCMMsg(message)) { + // WebView 请求打开 SCM + vscode.commands.executeCommand("workbench.view.scm"); + } else if (viewTypes.SidebarViewMsgUtil.isUserImportReportMsg(message)) { + // WebView 请求导入报告 + vscode.commands.executeCommand(CommandID.reportMgrImportReport); + } else if (viewTypes.SidebarViewMsgUtil.isUserExportReportMsg(message)) { + // WebView 请求导出报告 + vscode.commands.executeCommand(CommandID.reportMgrExportReport); + } else if (viewTypes.SidebarViewMsgUtil.isUserUnloadReportMsg(message)) { + // WebView 请求卸载报告 + vscode.commands.executeCommand(CommandID.reportMgrUnloadAllReport); + } else if (viewTypes.SidebarViewMsgUtil.isUserClearReportMsg(message)) { + // WebView 请求清除报告 + vscode.commands.executeCommand(CommandID.reportMgrClearAllReport); + } else if (viewTypes.SidebarViewMsgUtil.isUserStartScanMsg(message)) { + // WebView 请求开始扫描 + vscode.commands.executeCommand(CommandID.codeScanStart); + } + } +} diff --git a/client/src/sidebarView/sidebarViewProvider.ts b/client/src/sidebarView/sidebarViewProvider.ts new file mode 100644 index 0000000000000000000000000000000000000000..62fed1d8bc7d6fe66022d5765b07bc7532f3bfee --- /dev/null +++ b/client/src/sidebarView/sidebarViewProvider.ts @@ -0,0 +1,137 @@ +/*************************************************************************************** + * Copyright (c) 2023-2024 RVSmartPorting. All rights reserved. + * RVPortingTool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + **************************************************************************************/ + +/*************************************************************************************** + * (Client) Sidebar View Provider for RVPortingTool VSCode Extension + * + * Author: Lightning Rainstorm + * Last Change: Sep 11, 2024 + **************************************************************************************/ + +import * as vscode from "vscode"; +import * as viewTypes from "../../../common/src/types/sidebarView"; +import { SidebarViewController } from "./sidebarViewController"; +import strFormat = require("string-format"); + +export class SidebarViewProvider implements vscode.WebviewViewProvider { + public static readonly viewType = "rvCodingAsst.view.sidebar"; + + private _view?: vscode.WebviewView; + private _context?: vscode.WebviewViewResolveContext; + public controller?: SidebarViewController; + + constructor(private readonly _extensionUri: vscode.Uri) {} + + public resolveWebviewView( + webviewView: vscode.WebviewView, + context: vscode.WebviewViewResolveContext, + token: vscode.CancellationToken, + ): void | Thenable { + this._view = webviewView; + this._context = context; + this._view.webview.options = { + enableScripts: true, + localResourceRoots: [this._extensionUri], + enableCommandUris: true, + }; + this._view.webview.html = this._getHtmlForWebview(webviewView.webview); + + // 初始化 Controller + this.controller = new SidebarViewController(this._extensionUri, this._view); + } + + private _getHtmlForWebview(webview: vscode.Webview): string { + // Use a nonce to only allow a specific script to be run. + const nonce = getNonce(); + const elementsJsUri = webview.asWebviewUri( + vscode.Uri.joinPath(this._extensionUri, "out/elements.bundled.js"), + ); + const indexJsUri = webview.asWebviewUri( + vscode.Uri.joinPath(this._extensionUri, "out/sidebarView/index.js"), + ); + const openScmA = `` + vscode.l10n.t("open a repository") + ``; + return ` + + + + + + + RVPortingTool + + + +
+

${vscode.l10n.t("Welcome to RVPortingTool: Make RISC-V Porting Easier!")}

+
+
+

${strFormat(vscode.l10n.t("Please {0} to scan code"), openScmA)}

+
+ + + + + + + + `; + } +} + +function getNonce() { + let text = ""; + const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + for (let i = 0; i < 32; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; +} diff --git a/client/src/test/completion.test.ts b/client/src/test/completion.test.ts index a4f3b2e7871ff23dfd7c3600ffec6430b3ce54ab..f21828468853f1fda21d7aef069d7a65eb857ce7 100644 --- a/client/src/test/completion.test.ts +++ b/client/src/test/completion.test.ts @@ -30,7 +30,7 @@ suite("Should do completion", () => { async function testCompletion( docUri: vscode.Uri, position: vscode.Position, - expectedCompletionList: vscode.CompletionList + expectedCompletionList: vscode.CompletionList, ) { await activate(docUri); @@ -38,7 +38,7 @@ async function testCompletion( const actualCompletionList = (await vscode.commands.executeCommand( "vscode.executeCompletionItemProvider", docUri, - position + position, )) as vscode.CompletionList; assert.ok(actualCompletionList.items.length >= 2); diff --git a/client/src/test/suite/index.ts b/client/src/test/suite/index.ts index 36adc578ecffad18fe29533b8e0f568a150c4d00..367c5dd5cbb6d91eab713e5c565c481b3854f676 100644 --- a/client/src/test/suite/index.ts +++ b/client/src/test/suite/index.ts @@ -18,9 +18,9 @@ * Last Change: Sep 6, 2024 **************************************************************************************/ -import * as path from "path"; -import * as Mocha from "mocha"; import { glob } from "glob"; +import * as Mocha from "mocha"; +import * as path from "path"; export function run(): Promise { // Create the mocha test diff --git a/client/src/types/codeScan.ts b/client/src/types/codeScan.ts new file mode 100644 index 0000000000000000000000000000000000000000..138cf8288421693a446086e5b207b57c5fc92577 --- /dev/null +++ b/client/src/types/codeScan.ts @@ -0,0 +1,42 @@ +/*************************************************************************************** + * Copyright (c) 2023-2024 RVSmartPorting. All rights reserved. + * RVPortingTool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + **************************************************************************************/ + +/*************************************************************************************** + * Code Scan Data Definition for RVPortingTool VSCode Extension + * + * Author: Lightning Rainstorm + * liccc + * Last Change: Sep 11, 2024 + **************************************************************************************/ + +/** + * 代码扫描服务器配置 + */ +export interface ScanServerConfig { + /** 代码扫描服务器名称 */ + name: string; + + /** 代码扫描服务器 API 地址 */ + endpoint: string; + + /** 代码扫描服务器 用户名 */ + userName: string; + + /** 代码扫描服务器 Secret */ + secretKey: string; + + /** 代码扫描服务器 隐私设置:是否已同意协议 */ + acceptedLicense?: boolean; + + /** 代码扫描服务器 隐私设置:是否保留代码 */ + keepCode?: boolean; +} diff --git a/client/src/types/git.d.ts b/client/src/types/git.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..63b8fe0f1f371c7c54045a35c5a58a6cde177c07 --- /dev/null +++ b/client/src/types/git.d.ts @@ -0,0 +1,423 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { CancellationToken, Command, Disposable, Event, ProviderResult, Uri } from "vscode"; +export { ProviderResult } from "vscode"; + +export interface Git { + readonly path: string; +} + +export interface InputBox { + value: string; +} + +export const enum ForcePushMode { + Force, + ForceWithLease, + ForceWithLeaseIfIncludes, +} + +export const enum RefType { + Head, + RemoteHead, + Tag, +} + +export interface Ref { + readonly type: RefType; + readonly name?: string; + readonly commit?: string; + readonly remote?: string; +} + +export interface UpstreamRef { + readonly remote: string; + readonly name: string; + readonly commit?: string; +} + +export interface Branch extends Ref { + readonly upstream?: UpstreamRef; + readonly ahead?: number; + readonly behind?: number; +} + +export interface CommitShortStat { + readonly files: number; + readonly insertions: number; + readonly deletions: number; +} + +export interface Commit { + readonly hash: string; + readonly message: string; + readonly parents: string[]; + readonly authorDate?: Date; + readonly authorName?: string; + readonly authorEmail?: string; + readonly commitDate?: Date; + readonly shortStat?: CommitShortStat; +} + +export interface Submodule { + readonly name: string; + readonly path: string; + readonly url: string; +} + +export interface Remote { + readonly name: string; + readonly fetchUrl?: string; + readonly pushUrl?: string; + readonly isReadOnly: boolean; +} + +export const enum Status { + INDEX_MODIFIED, + INDEX_ADDED, + INDEX_DELETED, + INDEX_RENAMED, + INDEX_COPIED, + + MODIFIED, + DELETED, + UNTRACKED, + IGNORED, + INTENT_TO_ADD, + INTENT_TO_RENAME, + TYPE_CHANGED, + + ADDED_BY_US, + ADDED_BY_THEM, + DELETED_BY_US, + DELETED_BY_THEM, + BOTH_ADDED, + BOTH_DELETED, + BOTH_MODIFIED, +} + +export interface Change { + /** + * Returns either `originalUri` or `renameUri`, depending + * on whether this change is a rename change. When + * in doubt always use `uri` over the other two alternatives. + */ + readonly uri: Uri; + readonly originalUri: Uri; + readonly renameUri: Uri | undefined; + readonly status: Status; +} + +export interface RepositoryState { + readonly HEAD: Branch | undefined; + readonly refs: Ref[]; + readonly remotes: Remote[]; + readonly submodules: Submodule[]; + readonly rebaseCommit: Commit | undefined; + + readonly mergeChanges: Change[]; + readonly indexChanges: Change[]; + readonly workingTreeChanges: Change[]; + readonly untrackedChanges: Change[]; + + readonly onDidChange: Event; +} + +export interface RepositoryUIState { + readonly selected: boolean; + readonly onDidChange: Event; +} + +/** + * Log options. + */ +export interface LogOptions { + /** Max number of log entries to retrieve. If not specified, the default is 32. */ + readonly maxEntries?: number; + readonly path?: string; + /** A commit range, such as "0a47c67f0fb52dd11562af48658bc1dff1d75a38..0bb4bdea78e1db44d728fd6894720071e303304f" */ + readonly range?: string; + readonly reverse?: boolean; + readonly sortByAuthorDate?: boolean; + readonly shortStats?: boolean; + readonly author?: string; + readonly refNames?: string[]; + readonly maxParents?: number; + readonly skip?: number; +} + +export interface CommitOptions { + all?: boolean | "tracked"; + amend?: boolean; + signoff?: boolean; + signCommit?: boolean; + empty?: boolean; + noVerify?: boolean; + requireUserConfig?: boolean; + useEditor?: boolean; + verbose?: boolean; + /** + * string - execute the specified command after the commit operation + * undefined - execute the command specified in git.postCommitCommand + * after the commit operation + * null - do not execute any command after the commit operation + */ + postCommitCommand?: string | null; +} + +export interface FetchOptions { + remote?: string; + ref?: string; + all?: boolean; + prune?: boolean; + depth?: number; +} + +export interface InitOptions { + defaultBranch?: string; +} + +export interface RefQuery { + readonly contains?: string; + readonly count?: number; + readonly pattern?: string; + readonly sort?: "alphabetically" | "committerdate"; +} + +export interface BranchQuery extends RefQuery { + readonly remote?: boolean; +} + +export interface Repository { + readonly rootUri: Uri; + readonly inputBox: InputBox; + readonly state: RepositoryState; + readonly ui: RepositoryUIState; + + readonly onDidCommit: Event; + + getConfigs(): Promise<{ key: string; value: string }[]>; + getConfig(key: string): Promise; + setConfig(key: string, value: string): Promise; + getGlobalConfig(key: string): Promise; + + getObjectDetails( + treeish: string, + path: string + ): Promise<{ mode: string; object: string; size: number }>; + detectObjectType(object: string): Promise<{ mimetype: string; encoding?: string }>; + buffer(ref: string, path: string): Promise; + show(ref: string, path: string): Promise; + getCommit(ref: string): Promise; + + add(paths: string[]): Promise; + revert(paths: string[]): Promise; + clean(paths: string[]): Promise; + + apply(patch: string, reverse?: boolean): Promise; + diff(cached?: boolean): Promise; + diffWithHEAD(): Promise; + diffWithHEAD(path: string): Promise; + diffWith(ref: string): Promise; + diffWith(ref: string, path: string): Promise; + diffIndexWithHEAD(): Promise; + diffIndexWithHEAD(path: string): Promise; + diffIndexWith(ref: string): Promise; + diffIndexWith(ref: string, path: string): Promise; + diffBlobs(object1: string, object2: string): Promise; + diffBetween(ref1: string, ref2: string): Promise; + diffBetween(ref1: string, ref2: string, path: string): Promise; + + hashObject(data: string): Promise; + + createBranch(name: string, checkout: boolean, ref?: string): Promise; + deleteBranch(name: string, force?: boolean): Promise; + getBranch(name: string): Promise; + getBranches(query: BranchQuery, cancellationToken?: CancellationToken): Promise; + getBranchBase(name: string): Promise; + setBranchUpstream(name: string, upstream: string): Promise; + + checkIgnore(paths: string[]): Promise>; + + getRefs(query: RefQuery, cancellationToken?: CancellationToken): Promise; + + getMergeBase(ref1: string, ref2: string): Promise; + + tag(name: string, upstream: string): Promise; + deleteTag(name: string): Promise; + + status(): Promise; + checkout(treeish: string): Promise; + + addRemote(name: string, url: string): Promise; + removeRemote(name: string): Promise; + renameRemote(name: string, newName: string): Promise; + + fetch(options?: FetchOptions): Promise; + fetch(remote?: string, ref?: string, depth?: number): Promise; + pull(unshallow?: boolean): Promise; + push( + remoteName?: string, + branchName?: string, + setUpstream?: boolean, + force?: ForcePushMode + ): Promise; + + blame(path: string): Promise; + log(options?: LogOptions): Promise; + + commit(message: string, opts?: CommitOptions): Promise; + merge(ref: string): Promise; + mergeAbort(): Promise; +} + +export interface RemoteSource { + readonly name: string; + readonly description?: string; + readonly url: string | string[]; +} + +export interface RemoteSourceProvider { + readonly name: string; + readonly icon?: string; // codicon name + readonly supportsQuery?: boolean; + getRemoteSources(query?: string): ProviderResult; + getBranches?(url: string): ProviderResult; + publishRepository?(repository: Repository): Promise; +} + +export interface RemoteSourcePublisher { + readonly name: string; + readonly icon?: string; // codicon name + publishRepository(repository: Repository): Promise; +} + +export interface Credentials { + readonly username: string; + readonly password: string; +} + +export interface CredentialsProvider { + getCredentials(host: Uri): ProviderResult; +} + +export interface PostCommitCommandsProvider { + getCommands(repository: Repository): Command[]; +} + +export interface PushErrorHandler { + handlePushError( + repository: Repository, + remote: Remote, + refspec: string, + error: Error & { gitErrorCode: GitErrorCodes } + ): Promise; +} + +export interface BranchProtection { + readonly remote: string; + readonly rules: BranchProtectionRule[]; +} + +export interface BranchProtectionRule { + readonly include?: string[]; + readonly exclude?: string[]; +} + +export interface BranchProtectionProvider { + onDidChangeBranchProtection: Event; + provideBranchProtection(): BranchProtection[]; +} + +export type APIState = "uninitialized" | "initialized"; + +export interface PublishEvent { + repository: Repository; + branch?: string; +} + +export interface API { + readonly state: APIState; + readonly onDidChangeState: Event; + readonly onDidPublish: Event; + readonly git: Git; + readonly repositories: Repository[]; + readonly onDidOpenRepository: Event; + readonly onDidCloseRepository: Event; + + toGitUri(uri: Uri, ref: string): Uri; + getRepository(uri: Uri): Repository | null; + init(root: Uri, options?: InitOptions): Promise; + openRepository(root: Uri): Promise; + + registerRemoteSourcePublisher(publisher: RemoteSourcePublisher): Disposable; + registerRemoteSourceProvider(provider: RemoteSourceProvider): Disposable; + registerCredentialsProvider(provider: CredentialsProvider): Disposable; + registerPostCommitCommandsProvider(provider: PostCommitCommandsProvider): Disposable; + registerPushErrorHandler(handler: PushErrorHandler): Disposable; + registerBranchProtectionProvider(root: Uri, provider: BranchProtectionProvider): Disposable; +} + +export interface GitExtension { + readonly enabled: boolean; + readonly onDidChangeEnablement: Event; + + /** + * Returns a specific API version. + * + * Throws error if git extension is disabled. You can listen to the + * [GitExtension.onDidChangeEnablement](#GitExtension.onDidChangeEnablement) event + * to know when the extension becomes enabled/disabled. + * + * @param version Version number. + * @returns API instance + */ + getAPI(version: 1): API; +} + +export const enum GitErrorCodes { + BadConfigFile = "BadConfigFile", + AuthenticationFailed = "AuthenticationFailed", + NoUserNameConfigured = "NoUserNameConfigured", + NoUserEmailConfigured = "NoUserEmailConfigured", + NoRemoteRepositorySpecified = "NoRemoteRepositorySpecified", + NotAGitRepository = "NotAGitRepository", + NotAtRepositoryRoot = "NotAtRepositoryRoot", + Conflict = "Conflict", + StashConflict = "StashConflict", + UnmergedChanges = "UnmergedChanges", + PushRejected = "PushRejected", + ForcePushWithLeaseRejected = "ForcePushWithLeaseRejected", + ForcePushWithLeaseIfIncludesRejected = "ForcePushWithLeaseIfIncludesRejected", + RemoteConnectionError = "RemoteConnectionError", + DirtyWorkTree = "DirtyWorkTree", + CantOpenResource = "CantOpenResource", + GitNotFound = "GitNotFound", + CantCreatePipe = "CantCreatePipe", + PermissionDenied = "PermissionDenied", + CantAccessRemote = "CantAccessRemote", + RepositoryNotFound = "RepositoryNotFound", + RepositoryIsLocked = "RepositoryIsLocked", + BranchNotFullyMerged = "BranchNotFullyMerged", + NoRemoteReference = "NoRemoteReference", + InvalidBranchName = "InvalidBranchName", + BranchAlreadyExists = "BranchAlreadyExists", + NoLocalChanges = "NoLocalChanges", + NoStashFound = "NoStashFound", + LocalChangesOverwritten = "LocalChangesOverwritten", + NoUpstreamBranch = "NoUpstreamBranch", + IsInSubmodule = "IsInSubmodule", + WrongCase = "WrongCase", + CantLockRef = "CantLockRef", + CantRebaseMultipleBranches = "CantRebaseMultipleBranches", + PatchDoesNotApply = "PatchDoesNotApply", + NoPathFound = "NoPathFound", + UnknownPath = "UnknownPath", + EmptyCommitMessage = "EmptyCommitMessage", + BranchFastForwardRejected = "BranchFastForwardRejected", + BranchNotYetBorn = "BranchNotYetBorn", + TagConflict = "TagConflict", +} diff --git a/client/src/utils/git.ts b/client/src/utils/git.ts new file mode 100644 index 0000000000000000000000000000000000000000..c2cb9925772d4e151717f59889befa31ef6f6e48 --- /dev/null +++ b/client/src/utils/git.ts @@ -0,0 +1,120 @@ +/*************************************************************************************** + * Copyright (c) 2023-2024 RVSmartPorting. All rights reserved. + * RVPortingTool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + **************************************************************************************/ + +/*************************************************************************************** + * Git Extension Utilities for RVPortingTool VSCode Extension + * + * Author: Lightning Rainstorm + * liccc + * Last Change: Sep 12, 2024 + **************************************************************************************/ + +import * as child_process from "child_process"; +import * as vscode from "vscode"; +import * as gitTypes from "../types/git"; +import { ClientLogger } from "../utils/log"; + +const logger = ClientLogger.getLogger("GitUtility"); + +export class GitUtility { + /** + * 获取 Git 插件 API + */ + public static async getGitAPI(): Promise { + return new Promise(async (resolve) => { + const gitExtension = vscode.extensions.getExtension("vscode.git"); + + // 获取插件对象失败 + if (!gitExtension) { + logger.error(`Failed to acquire git extension`); + vscode.window.showErrorMessage( + vscode.l10n.t( + "Failed to communicate with Git extension. RVPortingTool requires Git extension to work properly.", + ), + ); + resolve(null); + return; + } + + // 调用 exports 前必须检查 Git 插件是否激活,若未激活需先激活 + if (!gitExtension.isActive) { + logger.info(`Activating git extension...`); + await gitExtension.activate(); + } + + // 检查 Git 插件初始化状态 + const gitApi: gitTypes.API = gitExtension.exports.getAPI(1); + if (gitApi.state === "uninitialized") { + // Git 插件尚未初始化,注册回调函数等待完成初始化 + gitApi.onDidChangeState((state) => { + if (state === "initialized") { + logger.info(`Git extension initialized`); + resolve(gitApi); + } + }); + } else { + resolve(gitApi); + } + }); + } + /** + * 检测当前是否已打开 Git 存储库 + * + * 根据存储库打开或关闭状态向 sidebarView 发送对应消息 + */ + public static async checkIsSCMRepoOpened(): Promise { + return new Promise(async (resolve) => { + // 获取 Git API + const gitApi = await this.getGitAPI(); + if (!gitApi) { + resolve(false); + return; + } + + // 通过 Git API 检查存储库数量 + if (gitApi.repositories.length > 0) { + logger.info(`${gitApi.repositories.length} git repositories available`); + resolve(true); + } else { + logger.info(`No git repository available`); + resolve(false); + } + }); + } + + public static async createGitArchive(repoFsPath: string, archiveFsPath: string): Promise { + return new Promise(async (resolve, reject) => { + const gitApi = await GitUtility.getGitAPI(); + const gitExecPath = gitApi?.git.path; + const gitExecParams = ["archive", "-o", '"' + archiveFsPath + '"', "--format=tar.gz", "HEAD"]; + + // Use Node.js child_process to execute git archive command + child_process.exec( + `"${gitExecPath}" ${gitExecParams.join(" ")}`, + { + cwd: repoFsPath, + encoding: "utf-8", + }, + (err, stdout, stderr) => { + if (err) { + vscode.window.showErrorMessage( + vscode.l10n.t("Failed to create git archive: {0}", err.message), + ); + reject(err); + } + logger.info("Archive created successfully"); + resolve(); + }, + ); + }); + } +} diff --git a/client/src/utils/log.ts b/client/src/utils/log.ts index 1dff08d36e03871aa2230312378c8390b3a5f301..444d0c18f16c0f8b9c91c930498e9c98bf182051 100644 --- a/client/src/utils/log.ts +++ b/client/src/utils/log.ts @@ -18,8 +18,8 @@ **************************************************************************************/ import * as log4js from "log4js"; -import * as lsp from "vscode-languageclient"; import * as vscode from "vscode"; +import * as lsp from "vscode-languageclient"; /** Log levels */ export type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal"; diff --git a/client/src/wikiHelper.ts b/client/src/wikiHelper.ts index 50b544613861e0d772d3e524ebd1e323643d070e..c74a45313f21b967974206abcc22f71feb9c047f 100644 --- a/client/src/wikiHelper.ts +++ b/client/src/wikiHelper.ts @@ -17,10 +17,10 @@ * Last Change: Sep 6, 2024 **************************************************************************************/ -import * as lsp from "vscode-languageclient/node"; import * as vscode from "vscode"; -import { ClientLogger } from "./utils/log"; +import * as lsp from "vscode-languageclient/node"; import { CommandID } from "../../common/src/types/command"; +import { ClientLogger } from "./utils/log"; import { WikiViewProvider } from "./wikiView/wikiViewProvider"; const logger = ClientLogger.getLogger("WikiHelper"); @@ -53,7 +53,7 @@ export class WikiHelper { wikiViewProvider.showRule(uri.query); } }, - }) + }), ); return manager; } diff --git a/client/src/wikiView/wikiViewProvider.ts b/client/src/wikiView/wikiViewProvider.ts index 86bbad868b34d28fdfc517e1cb3f9e1d6a991a2f..e471ff1be1384b1f5de8d3d7e6e2604c1bd275bc 100644 --- a/client/src/wikiView/wikiViewProvider.ts +++ b/client/src/wikiView/wikiViewProvider.ts @@ -19,12 +19,8 @@ import * as fs from "fs"; import * as vscode from "vscode"; +import { WikiViewApplyMarkdownMsg, WikiViewMsgUtil } from "../../../common/src/types/wikiView"; import { checkerRules } from "../types/checkerRules"; -import { - WikiViewApplyMarkdownMsg, - WikiViewLoadedMsg, - WikiViewMsgUtil, -} from "../../../common/src/types/wikiView"; export class WikiViewProvider implements vscode.WebviewViewProvider { public static readonly viewType = "rvCodingAsst.view.wiki"; @@ -38,7 +34,7 @@ export class WikiViewProvider implements vscode.WebviewViewProvider { public resolveWebviewView( webviewView: vscode.WebviewView, context: vscode.WebviewViewResolveContext, - token: vscode.CancellationToken + token: vscode.CancellationToken, ): void | Thenable { this._view = webviewView; webviewView.webview.options = { @@ -68,7 +64,7 @@ export class WikiViewProvider implements vscode.WebviewViewProvider { const ruleMDPath = vscode.Uri.joinPath( this._extensionUri, "resources/wiki/checkerRules/", - ruleId.toUpperCase() + ".md" + ruleId.toUpperCase() + ".md", ); try { this._mdContent = fs.readFileSync(ruleMDPath.fsPath, { @@ -79,8 +75,8 @@ export class WikiViewProvider implements vscode.WebviewViewProvider { vscode.l10n.t( "Failed to load rule details of {0}{1}", ruleId, - checkerRules.has(ruleId) ? ": ".concat(checkerRules.get(ruleId)!.desc) : "" - ) + checkerRules.has(ruleId) ? ": ".concat(checkerRules.get(ruleId)!.desc) : "", + ), ); return; } @@ -99,13 +95,13 @@ export class WikiViewProvider implements vscode.WebviewViewProvider { // Use a nonce to only allow a specific script to be run. const nonce = getNonce(); const prismCSSUri = webview.asWebviewUri( - vscode.Uri.joinPath(this._extensionUri, "resources/prism.css") + vscode.Uri.joinPath(this._extensionUri, "resources/prism.css"), ); const prismJSUri = webview.asWebviewUri( - vscode.Uri.joinPath(this._extensionUri, "resources/prism.js") + vscode.Uri.joinPath(this._extensionUri, "resources/prism.js"), ); const scriptUri = webview.asWebviewUri( - vscode.Uri.joinPath(this._extensionUri, "out/wikiView/main.js") + vscode.Uri.joinPath(this._extensionUri, "out/wikiView/main.js"), ); let bodyHtml = "

" + vscode.l10n.t("No Wiki pages have been opened yet.") + "

"; diff --git a/client/tsconfig.json b/client/tsconfig.json index 92bb76733caa6e68ab95d691c3163a6fe06719ac..a6ed6196e82a520e2bf4caf6d09e387fc43de6e3 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -4,7 +4,7 @@ "module": "commonjs", "target": "es2020", "lib": ["es2020"], - "outDir": "out", + "outDir": "../out", "rootDir": "..", "sourceMap": true, "strict": true, diff --git a/common/package.json b/common/package.json index 6711952d9a4f9a8866fa283c9753f3771d8c7e79..cbafb6747bc849d7d48c28f5434a99d96d251198 100644 --- a/common/package.json +++ b/common/package.json @@ -9,7 +9,8 @@ "dependencies": { "vscode-languageclient": "^9.0.1", "vscode-languageserver": "^9.0.1", - "vscode-languageserver-textdocument": "^1.0.12" + "vscode-languageserver-textdocument": "^1.0.12", + "vscode-uri": "^3.0.8" }, "devDependencies": { "@types/vscode": "^1.93.0", diff --git a/common/pnpm-lock.yaml b/common/pnpm-lock.yaml index c5fcaa965db698814e77f13d87532d0465ac43b9..08299039b4345a89b104924a98809984c9b7ac8a 100644 --- a/common/pnpm-lock.yaml +++ b/common/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: vscode-languageserver-textdocument: specifier: ^1.0.12 version: 1.0.12 + vscode-uri: + specifier: ^3.0.8 + version: 3.0.8 devDependencies: '@types/vscode': specifier: ^1.93.0 @@ -223,6 +226,9 @@ packages: resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} hasBin: true + vscode-uri@3.0.8: + resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + snapshots: '@types/vscode@1.93.0': {} @@ -427,3 +433,5 @@ snapshots: vscode-languageserver@9.0.1: dependencies: vscode-languageserver-protocol: 3.17.5 + + vscode-uri@3.0.8: {} diff --git a/common/src/types/command.ts b/common/src/types/command.ts index 71e4274027447f923a9b69a8dac85bfd7d647cb8..681114f15231421489d1b8c3e0f08aa976cc55d1 100644 --- a/common/src/types/command.ts +++ b/common/src/types/command.ts @@ -14,7 +14,7 @@ * Command ID Definition for RVPortingTool VSCode Extension * * Author: Lightning Rainstorm - * Last Change: Sep 6, 2024 + * Last Change: Sep 11, 2024 **************************************************************************************/ /** Command ID 定义 */ @@ -23,14 +23,26 @@ export class CommandID { public static reportMgrTest = "rvCodingAsst.reportManager.testCommand"; /** 报告管理:加载代码扫描报告文件 */ - public static reportMgrLoadFromFile = "rvCodingAsst.reportManager.loadFromFile"; + public static reportMgrImportReport = "rvCodingAsst.reportManager.importReport"; + + /** 报告管理:导出报告(用户选择工作区) */ + public static reportMgrExportReport = "rvCodingAsst.reportManager.exportReport"; + + /** 报告管理:卸载所有报告 */ + public static reportMgrUnloadAllReport = "rvCodingAsst.reportManager.unloadAllReport"; + + /** 报告管理:清除所有报告 */ + public static reportMgrClearAllReport = "rvCodingAsst.reportManager.clearAllReport"; /** 报告管理:保存所有报告(缓存到工作区) */ public static reportMgrSaveAllReportsCache = "rvCodingAsst.reportManager.saveAllReportsCache"; - /** 报告管理:导出报告(用户选择工作区) */ - public static reportMgrExport = "rvCodingAsst.reportManager.exportReport"; - /** Wiki 助手:打开 Wiki 页面 */ public static wikiHelperOpenRule = "rvCodingAsst.wikiHelper.openRule"; + + /** 侧边栏:刷新状态 */ + public static sidebarViewRefreshState = "rvCodingAsst.sidebarHelper.refreshState"; + + /** 代码扫描:开始扫描 */ + public static codeScanStart = "rvCodingAsst.codeScan.start"; } diff --git a/common/src/types/notification.ts b/common/src/types/notification.ts index 1f4cd29e3fff390f0b81bec7acde35a1ff3303a0..8d3eb57c6d8cdac284f64be5ab8c5d1a81483849 100644 --- a/common/src/types/notification.ts +++ b/common/src/types/notification.ts @@ -14,48 +14,64 @@ * Language Client/Server Notification ID Definition for RVPortingTool VSCode Extension * * Author: Lightning Rainstorm - * Last Change: Sep 6, 2024 + * Last Change: Sep 11, 2024 + * + * Note: 通知 ID 命名规则 + * - 前缀:模块名+消息接收方,如 reportMgrCli、reportMgrSrv + * - 后缀:事件名 **************************************************************************************/ /** LSP 通知 ID 定义 */ export class LSPNotificationID { /** 报告管理:加载报告 JSON Schema */ - public static reportMgrLoadSchema = "rvCodingAsst.reportManager.loadSchema"; + public static reportMgrSrvLoadSchema = "rvCodingAsst.reportManager.notify.server.loadSchema"; /** 报告管理:加载报告 */ - public static reportMgrLoad = "rvCodingAsst.reportManager.load"; + public static reportMgrSrvLoad = "rvCodingAsst.reportManager.notify.server.load"; /** 报告管理:加载本地文件报告 */ - public static reportMgrLoadFromFile = "rvCodingAsst.reportManager.loadFromFile"; + public static reportMgrCliImportReport = "rvCodingAsst.reportManager.notify.client.importReport"; /** 报告管理:加载服务器上的报告 */ - public static reportMgrLoadFromServer = "rvCodingAsst.reportManager.loadFromServer"; + public static reportMgrCliLoadFromServer = + "rvCodingAsst.reportManager.notify.client.loadFromServer"; /** 报告管理:加载报告完成 */ - public static reportMgrLoadFinished = "rvCodingAsst.reportManager.loadFinished"; + public static reportMgrCliLoadFinished = "rvCodingAsst.reportManager.notify.client.loadFinished"; /** 报告管理:加载报告完成,但缓存到工作区失败 */ - public static reportMgrLoadFinishedWithSaveError = - "rvCodingAsst.reportManager.loadFinishedWithSaveError"; + public static reportMgrCliLoadFinishedWithSaveError = + "rvCodingAsst.reportManager.notify.client.loadFinishedWithSaveError"; /** 报告管理:加载报告失败 */ - public static reportMgrLoadError = "rvCodingAsst.reportManager.loadError"; + public static reportMgrCliLoadError = "rvCodingAsst.reportManager.loadError"; /** 报告管理:保存报告 */ - public static reportMgrSave = "rvCodingAsst.reportManager.save"; + public static reportMgrSrvSave = "rvCodingAsst.reportManager.notify.server.save"; /** 报告管理:保存所有报告(缓存到工作区) */ - public static reportMgrSaveCacheAll = "rvCodingAsst.reportManager.saveCacheAll"; + public static reportMgrSrvSaveCacheAll = "rvCodingAsst.reportManager.notify.server.saveCacheAll"; /** 报告管理:保存所有报告(缓存到工作区) */ - public static reportMgrSaveCacheAllFinished = "rvCodingAsst.reportManager.saveCacheAllFinished"; + public static reportMgrCliSaveCacheAllFinished = + "rvCodingAsst.reportManager.notify.client.saveCacheAllFinished"; /** 报告管理:保存报告成功 */ - public static reportMgrSaveFinished = "rvCodingAsst.reportManager.saveFinished"; + public static reportMgrCliSaveFinished = "rvCodingAsst.reportManager.notify.client.saveFinished"; /** 报告管理:保存报告失败 */ - public static reportMgrSaveError = "rvCodingAsst.reportManager.saveError"; + public static reportMgrCliSaveError = "rvCodingAsst.reportManager.notify.client.saveError"; /** 报告管理:重新加载报告到指定工作区 */ - public static reportMgrReloadConfirm = "rvCodingAsst.reportManager.reloadConfirm"; + public static reportMgrCliReloadConfirm = + "rvCodingAsst.reportManager.notify.client.reloadConfirm"; + + /** 报告管理:卸载指定工作区的报告 */ + public static reportMgrSrvUnload = "rvCodingAsst.reportManager.notify.server.unload"; + + /** 报告管理:卸载报告完成 */ + static reportMgrCliUnloadFinished = "rvCodingAsst.reportManager.notify.client.unloadFinished"; + + /** 报告管理:清除指定工作区的报告 */ + public static reportMgrSrvClear = "rvCodingAsst.reportManager.notify.server.clearAllReport"; } diff --git a/common/src/types/report.ts b/common/src/types/report.ts index ddb0c36bdd0b3f6741ab3a998436f49527eec7de..31fa9fd19c7644eefa45afa48f753fece16e2c56 100644 --- a/common/src/types/report.ts +++ b/common/src/types/report.ts @@ -19,17 +19,14 @@ /** 代码问题状态 */ export enum IProblemState { - /** 问题状态:无关 */ - unrelated = 0, + /** 问题状态:未解决 */ + todo = 0, - /** 问题状态:正常 */ - default = 1, - - /** 问题状态:待验证 */ - verify = 2, + /** 问题状态:已修改 */ + modified = 1, /** 问题状态:已解决 */ - solved = 3, + done = 2, } /** 代码问题类型 */ @@ -102,6 +99,15 @@ export interface SourceRange { _unified?: boolean; } +/** 修复信息 */ +export interface IProblemFixInfo { + /** 修复区域 */ + fixRange: SourceRange; + + /** 修复内容 */ + fixContent: string; +} + /** 代码问题数据 */ export interface IProblemData { /** 文件或目录相对路径 */ @@ -136,6 +142,9 @@ export interface IProblem { /** 问题信息 */ data: IProblemData[]; + + /** 修复信息 */ + fixInfo?: IProblemFixInfo; } /** RVPortingTool 代码扫描报告 */ @@ -143,6 +152,9 @@ export interface IReport { /** 报告版本号 */ version: number; + /** 报告 commit ID */ + commitId: string; + /** 报告最后更新毫秒时间戳 */ timestamp: number; diff --git a/common/src/types/reportMeta.ts b/common/src/types/reportMeta.ts new file mode 100644 index 0000000000000000000000000000000000000000..e5e925c4f6ba1b75623ee06472dd9d70c557fb15 --- /dev/null +++ b/common/src/types/reportMeta.ts @@ -0,0 +1,46 @@ +/*************************************************************************************** + * Copyright (c) 2023-2024 RVSmartPorting. All rights reserved. + * RVPortingTool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + **************************************************************************************/ + +/*************************************************************************************** + * Language Server Report Meta Data Model for RVPortingTool VSCode Extension + * + * Author: Lightning Rainstorm + * Last Change: Sep 6, 2024 + **************************************************************************************/ + +import { URI } from "vscode-uri"; +import { IReport } from "./report"; + +/** 代码扫描报告元数据类 */ + +export class ReportMeta { + public workspaceUri: URI; + + /** 工作区是否可缓存报告 */ + public cacheSavable?: boolean; + + /** 代码扫描报告原始数据 */ + public reportData: IReport; + + /** 代码扫描报告最后更新时间 */ + public lastUpdTimestamp: number; + + /** 代码扫描报告最后保存时间,-1 表示未保存过 */ + public lastSaveTimestamp: number; + + constructor(workspaceUri: URI, reportData: IReport) { + this.workspaceUri = workspaceUri; + this.reportData = reportData; + this.lastUpdTimestamp = reportData.timestamp ? reportData.timestamp : new Date().getTime(); + this.lastSaveTimestamp = -1; + } +} diff --git a/common/src/types/request.ts b/common/src/types/request.ts index 5963a3c2bd286c3164e2f8bf8b866c08bdbeb001..e9061e2edc60be5e484394cfbbe810e7870c611e 100644 --- a/common/src/types/request.ts +++ b/common/src/types/request.ts @@ -14,11 +14,28 @@ * Language Client/Server Request/Response ID Definition for RVPortingTool VSCode Extension * * Author: Lightning Rainstorm - * Last Change: Sep 6, 2024 + * Last Change: Sep 11, 2024 **************************************************************************************/ +import { ReportMeta } from "./reportMeta"; + +/** 获取当前工作区报告元数据:请求参数 */ +export interface ReportMgrGetWorkspaceMetaRequest { + /** 工作区 Uri */ + workspaceUri: string; +} + +/** 获取当前工作区报告元数据:响应结构 */ +export interface ReportMgrGetWorkspaceMetaResponse { + /** 报告元数据 */ + reportMeta: ReportMeta; +} + /** LSP 请求/响应 ID 定义 */ export class LSPRequestID { /** 报告管理:获取报告规则信息 */ public static reportMgrGetRuleInfo = "rvCodingAsst.reportManager.getRuleInfo"; + + /** 报告管理:获取当前工作区报告元数据 */ + public static reportMgrGetWorkspaceMeta = "rvCodingAsst.reportManager.reportMgrGetWorkspaceMeta"; } diff --git a/common/src/types/sidebarView.ts b/common/src/types/sidebarView.ts new file mode 100644 index 0000000000000000000000000000000000000000..c56585e87d4acc1d258b17211305fb710712924f --- /dev/null +++ b/common/src/types/sidebarView.ts @@ -0,0 +1,152 @@ +/*************************************************************************************** + * Copyright (c) 2023-2024 RVSmartPorting. All rights reserved. + * RVPortingTool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + **************************************************************************************/ + +/*************************************************************************************** + * Client Sidebar View WebView Type Definition for RVPortingTool VSCode Extension + * + * Author: Lightning Rainstorm + * Last Change: Sep 11, 2024 + * + * Note: 消息命名规则: + * - ViewXXXMsg: 视图相关消息 + * - CodeXXXMsg: VSCode 端发出的相关消息 + * - UserXXXMsg: 用户操作发出的相关消息 + **************************************************************************************/ + +export class SidebarViewState { + /* 当前代码扫描任务 ID */ + taskId?: string; +} + +/** SidebarView 加载完毕消息 */ +export interface ViewLoadedMsg { + /** type */ + type: "ViewLoadedMsg"; +} + +/** User: 打开存储库消息 */ +export interface UserOpenSCMMsg { + /** type */ + type: "UserOpenSCMMsg"; +} + +/** Code: 已打开存储库消息 */ +export interface CodeOpenedRepoMsg { + /** type */ + type: "CodeOpenedRepoMsg"; +} + +/** Code: 已关闭存储库消息 */ +export interface CodeClosedRepoMsg { + /** type */ + type: "CodeClosedRepoMsg"; +} + +/** User: 导入扫描报告消息 */ +export interface UserImportReportMsg { + /** type */ + type: "UserImportReportMsg"; +} + +/** User: 导出扫描报告消息 */ +export interface UserExportReportMsg { + /** type */ + type: "UserExportReportMsg"; +} + +/** User: 卸载扫描报告消息 */ +export interface UserUnloadReportMsg { + /** type */ + type: "UserUnloadReportMsg"; +} + +/** User: 清除扫描报告消息 */ +export interface UserClearReportMsg { + /** type */ + type: "UserClearReportMsg"; +} + +/** Code: 有扫描报告消息 */ +export interface CodeHasReportMsg { + /** type */ + type: "CodeHasReportMsg"; +} + +/** SidebarView 无扫描报告消息 */ +export interface CodeNoReportMsg { + /** type */ + type: "CodeNoReportMsg"; +} + +/** SidebarView 用户开始扫描消息 */ +export interface UserStartScanMsg { + /** type */ + type: "UserStartScanMsg"; +} + +/** SidebarView 消息类型检查辅助类 */ +export class SidebarViewMsgUtil { + /** 判断是否为 SidebarView 加载完毕消息 */ + public static isViewLoadedMsg(msg: any): msg is ViewLoadedMsg { + return msg.type === "ViewLoadedMsg"; + } + + /** 判断是否为 SidebarView 打开文件夹消息 */ + public static isUserOpenSCMMsg(msg: any): msg is UserOpenSCMMsg { + return msg.type === "UserOpenSCMMsg"; + } + + /** 判断是否为 SidebarView 已打开存储库消息 */ + public static isCodeOpenedRepoMsg(msg: any): msg is CodeOpenedRepoMsg { + return msg.type === "CodeOpenedRepoMsg"; + } + + /** 判断是否为 SidebarView 已关闭存储库消息 */ + public static isCodeClosedRepoMsg(msg: any): msg is CodeClosedRepoMsg { + return msg.type === "CodeClosedRepoMsg"; + } + + /** 判断是否为 SidebarView 导入扫描报告消息 */ + public static isUserImportReportMsg(msg: any): msg is UserImportReportMsg { + return msg.type === "UserImportReportMsg"; + } + + /** 判断是否为 SidebarView 导出扫描报告消息 */ + public static isUserExportReportMsg(msg: any): msg is UserExportReportMsg { + return msg.type === "UserExportReportMsg"; + } + + /** 判断是否为 SidebarView 卸载扫描报告消息 */ + public static isUserUnloadReportMsg(msg: any): msg is UserUnloadReportMsg { + return msg.type === "UserUnloadReportMsg"; + } + + /** 判断是否为 SidebarView 清除扫描报告消息 */ + public static isUserClearReportMsg(msg: any): msg is UserClearReportMsg { + return msg.type === "UserClearReportMsg"; + } + + /** 判断是否为 SidebarView 有扫描报告消息 */ + public static isCodeHasReportMsg(msg: any): msg is CodeHasReportMsg { + return msg.type === "CodeHasReportMsg"; + } + + /** 判断是否为 SidebarView 无扫描报告消息 */ + public static isCodeNoReportMsg(msg: any): msg is CodeNoReportMsg { + return msg.type === "CodeNoReportMsg"; + } + + /** 判断是否为 SidebarView 用户开始扫描消息 */ + public static isUserStartScanMsg(msg: any): msg is UserStartScanMsg { + return msg.type === "UserStartScanMsg"; + } +} diff --git a/common/src/utils/sourceRangeUtils.ts b/common/src/utils/sourceRangeUtils.ts index 51dc9124632406c69eb468e466cb38f5f7985411..9ed3d081b414f977478d22f2c6608ef93aeb7525 100644 --- a/common/src/utils/sourceRangeUtils.ts +++ b/common/src/utils/sourceRangeUtils.ts @@ -65,7 +65,7 @@ export class SourceRangeUtils { public static getIntersect( baseRange: SourceRange, range: SourceRange, - ignoreFilePath?: boolean + ignoreFilePath?: boolean, ): SourceRange | undefined { if (!ignoreFilePath && baseRange.filePath !== range.filePath) { return undefined; diff --git a/common/tsconfig.json b/common/tsconfig.json index b0a84f988b678149534e2de283e90c8791728c8b..5cfcf71645e2d28315453ddaae661298447fc268 100644 --- a/common/tsconfig.json +++ b/common/tsconfig.json @@ -1,10 +1,9 @@ { "compilerOptions": { - "composite": true, - "module": "commonjs", + "module": "Node16", "target": "es2020", "lib": ["es2020"], - "outDir": "out", + "outDir": "../out", "rootDir": "..", "sourceMap": true, "strict": true, diff --git a/esbuild.js b/esbuild.mjs similarity index 46% rename from esbuild.js rename to esbuild.mjs index 46a4d008d8f74d34d435177393567eebb44344ab..6347481705dbf7ce2a8b4ce760d86adc12494365 100644 --- a/esbuild.js +++ b/esbuild.mjs @@ -14,12 +14,12 @@ * ESBuild Script for RVPortingTool VSCode Extension * * Author: Lightning Rainstorm - * Last Change: Sep 10, 2024 + * Last Change: Sep 11, 2024 **************************************************************************************/ -const { build } = require("esbuild"); -const { copy } = require("esbuild-plugin-copy"); -const { glob } = require("glob"); +import { build, context } from "esbuild"; +import { copy } from "esbuild-plugin-copy"; +import { glob } from "glob"; //@ts-check /** @typedef {import('esbuild').BuildOptions} BuildOptions **/ @@ -34,13 +34,13 @@ const esbuildProblemMatcherPlugin = { setup(build) { build.onStart(() => { console.log("[watch] build started"); + console.log(`The outdir is: ${build.initialOptions.outdir}`); }); build.onEnd((result) => { result.errors.forEach(({ text, location }) => { console.error(`✘ [ERROR] ${text}`); console.error(` ${location.file}:${location.line}:${location.column}:`); }); - console.log("[watch] build finished"); }); }, @@ -53,74 +53,79 @@ const baseConfig = { sourcemap: process.env.NODE_ENV !== "production", }; -/** @type BuildOptions */ -const watchConfig = { - plugins: [ - /* add to the end of plugins array */ - esbuildProblemMatcherPlugin, - ], -}; - -/** @type BuildOptions */ -const wikiViewConfig = { - ...baseConfig, - target: "es2020", - format: "esm", - entryPoints: ["./webview/src/wikiView/main.ts"], - outdir: "./out/wikiView", - plugins: [ - // Copy webview css and ttf files to `out` directory unaltered - copy({ - resolveFrom: "cwd", - assets: { - from: ["./webview/src/wikiView/*.css", "./webview/src/wikiView/*.ttf"], - to: ["./out/wikiView"], - }, - }), - ], -}; - -/** @type BuildOptions */ -const clientConfig = { - ...baseConfig, - target: "es2020", - platform: "node", - format: "cjs", - external: ["vscode"], - entryPoints: ["./client/src/extension.ts"], - outdir: "./out", - plugins: [ - // Copy vscode-elements bundled.js to `out` directory - copy({ - resolveFrom: "cwd", - assets: { - from: "./node_modules/@vscode-elements/elements/dist/bundled.js", - to: "./out/elements.bundled.js", - }, - }), - ], -}; - -/** @type BuildOptions */ -const serverConfig = { - ...baseConfig, - target: "es2020", - platform: "node", - format: "cjs", - external: ["vscode"], - entryPoints: ["./server/src/server.ts"], - outdir: "./out/server", -}; - -/** @type BuildOptions */ -const commonConfig = { - ...baseConfig, - target: "es2020", - platform: "node", - format: "cjs", - external: ["vscode"], - entryPoints: glob.globSync("./common/src/**/*.ts"), - outdir: "./out/common", +/** @type Object */ +const buildConfigs = { + wikiView: { + ...baseConfig, + target: "es2020", + format: "esm", + entryPoints: ["./webview/src/wikiView/main.ts"], + outdir: "./out/wikiView", + plugins: [ + // Copy webview static files to `out` directory + copy({ + resolveFrom: "cwd", + assets: { + from: ["./webview/src/wikiView/*.html", "./webview/src/wikiView/*.css"], + to: ["./out/wikiView"], + }, + }), + ], + }, + sidebarView: { + ...baseConfig, + target: "es2020", + format: "esm", + entryPoints: ["./webview/src/sidebarView/index.ts"], + outdir: "./out/sidebarView", + plugins: [ + // Copy webview static files to `out` directory + copy({ + resolveFrom: "cwd", + assets: { + from: ["./webview/src/sidebarView/*.html", "./webview/src/sidebarView/*.css"], + to: ["./out/sidebarView"], + }, + }), + ], + }, + common: { + ...baseConfig, + target: "es2020", + platform: "node", + format: "cjs", + external: ["vscode"], + entryPoints: glob.globSync("./common/src/**/*.ts"), + outdir: "./out/common", + }, + client: { + ...baseConfig, + target: "es2020", + platform: "node", + format: "cjs", + external: ["vscode"], + entryPoints: ["./client/src/extension.ts"], + outdir: "./out", + plugins: [ + // Copy vscode-elements bundled.js to `out` directory + copy({ + resolveFrom: "cwd", + assets: { + from: "./node_modules/@vscode-elements/elements/dist/bundled.js", + to: "./out/elements.bundled.js", + }, + }), + ], + }, + server: { + ...baseConfig, + target: "es2020", + platform: "node", + format: "cjs", + external: ["vscode"], + entryPoints: ["./server/src/server.ts"], + outdir: "./out/server", + }, }; // Build script @@ -128,31 +133,22 @@ const commonConfig = { const args = process.argv.slice(2); try { if (args.includes("--watch")) { - // Build and watch webview code console.log("[watch] build started"); - await build({ - ...wikiViewConfig, - ...watchConfig, - }); - await build({ - ...clientConfig, - ...watchConfig, - }); - await build({ - ...serverConfig, - ...watchConfig, - }); - await build({ - ...commonConfig, - ...watchConfig, - }); + for (const [name, buildConfig] of Object.entries(buildConfigs)) { + if (buildConfig.plugins) { + buildConfig.plugins.push(esbuildProblemMatcherPlugin); + } else { + buildConfig.plugins = [esbuildProblemMatcherPlugin]; + } + const ctx = await context(buildConfig); + ctx.watch(); + } console.log("[watch] build finished"); } else { - // Build webview code - await build(wikiViewConfig); - await build(clientConfig); - await build(serverConfig); - await build(commonConfig); + for (const [name, buildConfig] of Object.entries(buildConfigs)) { + console.log(`[build] building ${name}...`); + await build(buildConfig); + } console.log("build complete"); } } catch (err) { diff --git a/l10n/bundle.l10n.json b/l10n/bundle.l10n.json index 6580b8be49d24cb094615a025aaa6fdf6aaa19c8..f515695c9bc8be47fad69ada996161b89a800330 100644 --- a/l10n/bundle.l10n.json +++ b/l10n/bundle.l10n.json @@ -1,14 +1,24 @@ { "ARM": "ARM", "ARM architecture-related macro": "ARM architecture-related macro", + "Accept License": "Accept License", "Architecture judgement macro statement block": "Architecture judgement macro statement block", "Architecture-related built-in function": "Architecture-related built-in function", "Architecture-related built-in macro statement block": "Architecture-related built-in macro statement block", "Architecture-related macro in requirements": "Architecture-related macro in requirements", "Architecture-related pre-defined macro from compiler": "Architecture-related pre-defined macro from compiler", + "Are you sure to clear all loaded reports? This operation will remove it from workspace cache too!": "Are you sure to clear all loaded reports? This operation will remove it from workspace cache too!", + "Are you sure to temporarily unload all loaded reports? The reports will be automatically load next time after reloading or restarting Workspace/VSCode.": "Are you sure to temporarily unload all loaded reports? The reports will be automatically load next time after reloading or restarting Workspace/VSCode.", "C/C++": "C/C++", + "Cannot perform code scan! Please open a repository first": "Cannot perform code scan! Please open a repository first", + "Clear Code Check Report": "Clear Code Check Report", "Code Scan Report": "Code Scan Report", "Confirm": "Confirm", + "Detected repository, you can scan code now": "Detected repository, you can scan code now", + "Downloading report...": "Downloading report...", + "Export Code Check Report": "Export Code Check Report", + "Failed to communicate with Git extension. RVPortingTool requires Git extension to work properly.": "Failed to communicate with Git extension. RVPortingTool requires Git extension to work properly.", + "Failed to create git archive: {0}": "Failed to create git archive: {0}", "Failed to load report": "Failed to load report", "Failed to load report: {0}: {1}": "Failed to load report: {0}: {1}", "Failed to load rule details of {0}{1}": "Failed to load rule details of {0}{1}", @@ -16,30 +26,46 @@ "Feature is not supported yet": "Feature is not supported yet", "File does not exists": "File does not exists", "Finished loading code check report! The report was updated at: {0}": "Finished loading code check report! The report was updated at: {0}", - "Finished loading code check report, but failed to save to workspace. Your operations will be lost if you don't export the report manually after working.": "Finished loading code check report, but failed to save to workspace. Your operations will be lost if you don't export the report manually after working.", + "Finished loading code check report, but failed to save to workspace. \nYour operations will be lost if you don't export the report manually after working.": "Finished loading code check report, but failed to save to workspace. \nYour operations will be lost if you don't export the report manually after working.", "Finished saving all {0} workspaces' report cache": "Finished saving all {0} workspaces' report cache", "Finished saving report to: {0}": "Finished saving report to: {0}", "Format Error": "Format Error", "Function multi-versioning": "Function multi-versioning", + "Import Code Check Report": "Import Code Check Report", "Inline architecture-related shell script": "Inline architecture-related shell script", "Inline assembly": "Inline assembly", + "Loading report...": "Loading report...", "Network error": "Network error", "No Wiki pages have been opened yet.": "No Wiki pages have been opened yet.", "Please choose a workspace for displaying report": "Please choose a workspace for displaying report", "Please choose code scanning report file": "Please choose code scanning report file", "Please open a folder as workspace before loading report": "Please open a folder as workspace before loading report", + "Please {0} to scan code": "Please {0} to scan code", + "Preparing archive...": "Preparing archive...", + "RVPortingTool Official Code Scanning Server License\n\n\r\n1. This is a demo server, please do not use it for production.\n\r\n2. Your code might be store on this server for a while, please do not store any sensitive information.\n\r\n3. This server is provided as-is, without any warranty or liability.\n\r\n4. If you have any questions or concerns, please contact us at support@rvpt.top.": "RVPortingTool Official Code Scanning Server License\n\n\r\n1. This is a demo server, please do not use it for production.\n\r\n2. Your code might be store on this server for a while, please do not store any sensitive information.\n\r\n3. This server is provided as-is, without any warranty or liability.\n\r\n4. If you have any questions or concerns, please contact us at support@rvpt.top.", + "RVPortingTool Official Server": "RVPortingTool Official Server", + "Report clear confirm": "Report clear confirm", "Report reloading confirm": "Report reloading confirm", + "Report unload confirm": "Report unload confirm", "Retry": "Retry", "Right-shift operation on signed integer": "Right-shift operation on signed integer", "Save": "Save", "Save Code Scan Report As...": "Save Code Scan Report As...", "Save as...": "Save as...", + "Scanning code": "Scanning code", + "Self-deployed Server A": "Self-deployed Server A", + "Server analyzing code...": "Server analyzing code...", + "Server finalizing report...": "Server finalizing report...", "Suspected ARM architecture-related macro": "Suspected ARM architecture-related macro", "Suspected architecture-related enum type": "Suspected architecture-related enum type", "Suspected architecture-related macro": "Suspected architecture-related macro", "The report for following workspace(s) are failed to save\n": "The report for following workspace(s) are failed to save\n", "The workspace already contains report data! Would you like to override it?": "The workspace already contains report data! Would you like to override it?", "Unknown reason": "Unknown reason", + "Unload Code Check Report": "Unload Code Check Report", + "Upload and Scan Source Code": "Upload and Scan Source Code", + "Uploading archive...": "Uploading archive...", + "Welcome to RVPortingTool: Make RISC-V Porting Easier!": "Welcome to RVPortingTool: Make RISC-V Porting Easier!", "X86": "X86", "X86 architecture-specified macro": "X86 architecture-specified macro", "X86 architecture-specified system call": "X86 architecture-specified system call", @@ -56,10 +82,11 @@ "keyword": "keyword", "macro": "macro", "multi-versioning": "multi-versioning", + "open a repository": "open a repository", "requirement": "requirement", "rpmbuild": "rpmbuild", "rpmspec": "rpmspec", "shifting": "shifting", "signed integer": "signed integer", "system call": "system call" -} +} \ No newline at end of file diff --git a/l10n/bundle.l10n.zh-cn.json b/l10n/bundle.l10n.zh-cn.json index 765a5d42fe2cf0184d995a26d59d63534665a02d..540a86943e61d1546a571fa2432158ded2fcf8dd 100644 --- a/l10n/bundle.l10n.zh-cn.json +++ b/l10n/bundle.l10n.zh-cn.json @@ -1,14 +1,24 @@ { "ARM": "ARM", "ARM architecture-related macro": "ARM 架构特有宏", + "Accept License": "接受许可协议", "Architecture judgement macro statement block": "架构判断宏语句块", "Architecture-related built-in function": "架构相关 builtin 函数", "Architecture-related built-in macro statement block": "架构相关内置宏语句块", "Architecture-related macro in requirements": "依赖项名称出现架构相关内置宏", "Architecture-related pre-defined macro from compiler": "编译器架构相关预定义宏", + "Are you sure to clear all loaded reports? This operation will remove it from workspace cache too!": "您确定要清除所有已加载的报告吗?此操作会同时将报告从工作区缓存中删除!", + "Are you sure to temporarily unload all loaded reports? The reports will be automatically load next time after reloading or restarting Workspace/VSCode.": "您确定要临时卸载所有已加载的报告吗?下次重新加载或重启 工作区/VSCode 时,报告将自动加载。", "C/C++": "C/C++", + "Cannot perform code scan! Please open a repository first": "无法执行代码检查!请先打开一个存储库", + "Clear Code Check Report": "清除代码扫描报告", "Code Scan Report": "代码扫描报告", "Confirm": "确认", + "Detected repository, you can scan code now": "已检测到存储库,可使用代码扫描功能", + "Downloading report...": "正在下载报告...", + "Export Code Check Report": "导出代码扫描报告", + "Failed to communicate with Git extension. RVPortingTool requires Git extension to work properly.": "无法与 Git 扩展通信。睿迁工具需要使用 Git 扩展才能正常工作。", + "Failed to create git archive: {0}": "创建源代码归档包失败: {0}", "Failed to load report": "加载报告失败", "Failed to load report: {0}: {1}": "加载报告失败: {0}: {1}", "Failed to load rule details of {0}{1}": "加载检查规则【{0}{1}】详细信息失败", @@ -16,30 +26,46 @@ "Feature is not supported yet": "该功能尚未支持", "File does not exists": "文件不存在", "Finished loading code check report! The report was updated at: {0}": "代码检查报告加载成功!该报告最后修改于:{0}", - "Finished loading code check report, but failed to save to workspace. Your operations will be lost if you don't export the report manually after working.": "代码扫描报告加载成功,但无法自动保存到工作区。如果您在工作结束时不手动导出报告,您的相关操作可能会丢失。", + "Finished loading code check report, but failed to save to workspace. \nYour operations will be lost if you don't export the report manually after working.": "代码检查报告加载成功,但无法保存到工作区。\n如果完成工作后没有手动导出报告,您的操作将会丢失。", "Finished saving all {0} workspaces' report cache": "已成功缓存 {0} 个工作区上的报告数据", "Finished saving report to: {0}": "报告已成功保存到:{0}", "Format Error": "文件格式错误", "Function multi-versioning": "多版本函数", + "Import Code Check Report": "导入代码扫描报告", "Inline architecture-related shell script": "内嵌架构相关 Shell 脚本", "Inline assembly": "内联汇编", + "Loading report...": "正在加载报告...", "Network error": "网络错误", "No Wiki pages have been opened yet.": "目前未打开任何 Wiki 页面。", "Please choose a workspace for displaying report": "请选择报告对应的工作区", "Please choose code scanning report file": "请选择代码扫描报告文件", "Please open a folder as workspace before loading report": "加载报告前请先打开一个工作区", + "Please {0} to scan code": "请 {0} 以使用代码扫描功能", + "Preparing archive...": "正在创建源代码归档包...", + "RVPortingTool Official Code Scanning Server License\n\n\r\n1. This is a demo server, please do not use it for production.\n\r\n2. Your code might be store on this server for a while, please do not store any sensitive information.\n\r\n3. This server is provided as-is, without any warranty or liability.\n\r\n4. If you have any questions or concerns, please contact us at support@rvpt.top.": "RVPortingTool Official Code Scanning Server License\n\n\r\n1. This is a demo server, please do not use it for production.\n\r\n2. Your code might be store on this server for a while, please do not store any sensitive information.\n\r\n3. This server is provided as-is, without any warranty or liability.\n\r\n4. If you have any questions or concerns, please contact us at support@rvpt.top.", + "RVPortingTool Official Server": "睿迁官方服务器", + "Report clear confirm": "请确认是否清除所有报告", "Report reloading confirm": "请确认是否重新加载报告数据", + "Report unload confirm": "请确认是否卸载所有报告", "Retry": "重试", "Right-shift operation on signed integer": "有符号数的右移运算", "Save": "保存", "Save Code Scan Report As...": "将代码扫描报告另存为...", "Save as...": "将报告另存为...", + "Scanning code": "扫描代码", + "Self-deployed Server A": "私有化部署服务器测试", + "Server analyzing code...": "服务端正在分析代码...", + "Server finalizing report...": "服务端正在生成报告...", "Suspected ARM architecture-related macro": "疑似 ARM 架构特有宏", "Suspected architecture-related enum type": "疑似架构相关枚举类型", "Suspected architecture-related macro": "疑似架构相关宏", "The report for following workspace(s) are failed to save\n": "以下工作区的报告保存失败:\n", "The workspace already contains report data! Would you like to override it?": "工作区已存在报告数据!请确认是否替换?", "Unknown reason": "未知原因", + "Unload Code Check Report": "卸载代码扫描报告", + "Upload and Scan Source Code": "上传并扫描源码", + "Uploading archive...": "正在上传源代码归档包...", + "Welcome to RVPortingTool: Make RISC-V Porting Easier!": "欢迎使用睿迁工具:让 RISC-V 移植更简单!", "X86": "X86", "X86 architecture-specified macro": "X86 架构特有宏", "X86 architecture-specified system call": "架构特有系统调用", @@ -56,6 +82,7 @@ "keyword": "关键词", "macro": "宏", "multi-versioning": "多版本函数", + "open a repository": "打开一个存储库", "requirement": "依赖", "rpmbuild": "rpmbuild", "rpmspec": "rpmspec", diff --git a/package.json b/package.json index ccc16a48e680127d71999fc0a35ade433c6904de..229ad5efba90b68c706e3cca0dce6d909d34c430 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "displayName": "RVPortingTool", "publisher": "tcse-iscas", "engines": { - "vscode": "^1.75.0" + "vscode": "^1.93.0" }, "categories": [ "Other" @@ -62,13 +62,21 @@ }, "commands": [ { - "command": "rvCodingAsst.reportManager.loadFromFile", - "title": "%rvCodingAsst.command.reportManager.loadFromFile%" + "command": "rvCodingAsst.reportManager.importReport", + "title": "%rvCodingAsst.command.reportManager.importReport%" }, { "command": "rvCodingAsst.reportManager.exportReport", "title": "%rvCodingAsst.command.reportManager.exportReport%" }, + { + "command": "rvCodingAsst.reportManager.unloadAllReport", + "title": "%rvCodingAsst.command.reportManager.unloadAllReport%" + }, + { + "command": "rvCodingAsst.reportManager.clearAllReport", + "title": "%rvCodingAsst.command.reportManager.clearAllReport%" + }, { "command": "rvCodingAsst.reportManager.saveAllReportsCache", "title": "%rvCodingAsst.command.reportManager.saveAllReportsCache%" @@ -76,6 +84,14 @@ { "command": "rvCodingAsst.wikiHelper.openRule", "title": "%rvCodingAsst.command.wikiHelper.openRule%" + }, + { + "command": "rvCodingAsst.sidebarHelper.refreshState", + "title": "%rvCodingAsst.command.sidebarHelper.refreshState%" + }, + { + "command": "rvCodingAsst.codeScan.start", + "title": "%rvCodingAsst.command.codeScan.start%" } ], "viewsContainers": { @@ -88,7 +104,7 @@ ], "activitybar": [ { - "id": "rvCodingAsst-suggestion-container", + "id": "rvCodingAsst-sidebar-container", "title": "%rvCodingAsst.viewContainers.activitybar.title%", "icon": "resources/dep.svg" } @@ -104,13 +120,12 @@ "contextualTitle": "%rvCodingAsst.view.wiki.contextualTitle%" } ], - "rvCodingAsst-suggestion-container": [ + "rvCodingAsst-sidebar-container": [ { - "id": "rvCodingAsst.view.suggestion", - "name": "%rvCodingAsst.view.suggestion.name%", + "id": "rvCodingAsst.view.sidebar", + "name": "%rvCodingAsst.view.sidebar.name%", "type": "webview", - "icon": "resources/dep.svg", - "contextualTitle": "%rvCodingAsst.view.suggestion.contextualTitle%" + "icon": "resources/dep.svg" } ] } @@ -119,15 +134,15 @@ "postinstall": "cd client && pnpm install && cd ../server && pnpm install && cd ../common && pnpm install && cd ../webview && pnpm install && cd ..", "vscode:prepublish": "pnpm run compile", "precompile": "typescript-json-schema common/src/types/report.ts IReport --required -o resources/report_schema.json", - "compile": "tsc -b && node esbuild.js", + "compile": "node esbuild.mjs", "prewatch": "typescript-json-schema common/src/types/report.ts IReport --required -o resources/report_schema.json", - "watch": "tsc -b -w", - "watch_esbuild": "node esbuild.js --watch", + "watch": "node esbuild.mjs --watch", "clean": "tsc -b --clean", "pretest": "pnpm run compile && pnpm run lint", "lint": "eslint", "test": "node ./client/out/src/test/runTest", - "extract_l10n": "pnpm vscode-l10n-dev export -o ./l10n ./client/src ./common/src && python ./scripts/merge_l10n.py" + "extract_l10n": "pnpm vscode-l10n-dev export -o ./l10n ./client/src ./common/src && python ./scripts/merge_l10n.py", + "package": "vsce package --no-dependencies" }, "devDependencies": { "@types/glob": "^8.1.0", @@ -139,6 +154,7 @@ "@typescript-eslint/parser": "^8.5.0", "@vscode/l10n-dev": "^0.0.35", "@vscode/test-electron": "^2.4.1", + "@vscode/vsce": "^3.1.0", "esbuild": "^0.23.1", "esbuild-plugin-copy": "^2.1.1", "eslint": "^9.10.0", diff --git a/package.nls.json b/package.nls.json index dcff2a93fcb26c06cd2aa8009062f2b78fabbd5a..55dc4471c085e7a2d3c6e3b425b4abeecc9fa233 100644 --- a/package.nls.json +++ b/package.nls.json @@ -3,14 +3,17 @@ "rvCodingAsst.config.maxNumberOfProblems": "Controls the maximum number of problems produced by the server.", "rvCodingAsst.config.logLevel": "Controls the log level of RVPortingTool.", "rvCodingAsst.config.trace.server": "Set to trace to log the communication between VS Code and the language server.", - "rvCodingAsst.command.reportManager.loadFromFile": "RVPortingTool: Load Code Check Report", + "rvCodingAsst.command.reportManager.importReport": "RVPortingTool: Load Code Check Report", "rvCodingAsst.command.reportManager.saveAllReportsCache": "RVPortingTool: Save All Reports Cache to Workspace", "rvCodingAsst.command.reportManager.exportReport": "RVPortingTool: Export report to file", + "rvCodingAsst.command.reportManager.unloadAllReport": "RVPortingTool: Unload All Reports", + "rvCodingAsst.command.reportManager.clearAllReport": "RVPortingTool: Clear All Reports", "rvCodingAsst.command.wikiHelper.openRule": "RVPortingTool: Open Rule Definition in Wiki", + "rvCodingAsst.command.sidebarHelper.refreshState": "RVPortingTool: Refresh Sidebar View State", "rvCodingAsst.viewContainers.panel.title": "RVPortingTool", "rvCodingAsst.viewContainers.activitybar.title": "RVPortingTool", "rvCodingAsst.view.wiki.name": "RV Porting Wiki", "rvCodingAsst.view.wiki.contextualTitle": "RVPortingTool", - "rvCodingAsst.view.suggestion.name": "Suggestion", - "rvCodingAsst.view.suggestion.contextualTitle": "RVPortingTool" + "rvCodingAsst.view.sidebar.name": "RVPortingTool", + "rvCodingAsst.command.codeScan.start": "RVPortingTool: Start Code Scan" } diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json index 385ab17afbabec8314393e6161a2f17b89e0b03f..14070ef4ee022f4d465a06c8dea228953ae34f4e 100644 --- a/package.nls.zh-cn.json +++ b/package.nls.zh-cn.json @@ -3,14 +3,17 @@ "rvCodingAsst.config.maxNumberOfProblems": "问题显示最大数量", "rvCodingAsst.config.logLevel": "插件日志级别", "rvCodingAsst.config.trace.server": "插件语言服务器日志级别", - "rvCodingAsst.command.reportManager.loadFromFile": "RVPortingTool: 加载代码扫描报告", + "rvCodingAsst.command.reportManager.importReport": "RVPortingTool: 加载代码扫描报告", "rvCodingAsst.command.reportManager.saveAllReportsCache": "RVPortingTool: 保存所有报告 (缓存到工作区)", "rvCodingAsst.command.reportManager.exportReport": "RVPortingTool: 导出报告文件", + "rvCodingAsst.command.reportManager.unloadAllReport": "RVPortingTool: 卸载所有报告", + "rvCodingAsst.command.reportManager.clearAllReport": "RVPortingTool: 清除所有报告", "rvCodingAsst.command.wikiHelper.openRule": "RVPortingTool: 在 Wiki 中打开规则定义", + "rvCodingAsst.command.sidebarHelper.refreshState": "RVPortingTool: 刷新侧边栏状态", "rvCodingAsst.viewContainers.panel.title": "RVPortingTool", "rvCodingAsst.viewContainers.activitybar.title": "RVPortingTool", "rvCodingAsst.view.wiki.name": "迁移知识库", "rvCodingAsst.view.wiki.contextualTitle": "RVPortingTool", - "rvCodingAsst.view.suggestion.name": "修改建议", - "rvCodingAsst.view.suggestion.contextualTitle": "RVPortingTool" + "rvCodingAsst.view.sidebar.name": "睿迁助手", + "rvCodingAsst.command.codeScan.start": "RVPortingTool: 开始扫描" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ce3afdb27a28e5c7a6b6eda0dc4f6c0a77d82e9e..214b602d1e2767439ce3e5ca101791eb470d185b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -42,6 +42,9 @@ importers: '@vscode/test-electron': specifier: ^2.4.1 version: 2.4.1 + '@vscode/vsce': + specifier: ^3.1.0 + version: 3.1.0 esbuild: specifier: ^0.23.1 version: 0.23.1 @@ -80,6 +83,10 @@ packages: resolution: {integrity: sha512-ozTDPBVUDR5eOnMIwhggbnVmOrka4fXCs8n8mvUo4WLLc38kki6bAOByDoVZZPz/pZy2jMt2kwfpvy/UjALj6w==} engines: {node: '>=18.0.0'} + '@azure/abort-controller@1.1.0': + resolution: {integrity: sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==} + engines: {node: '>=12.0.0'} + '@azure/abort-controller@2.1.2': resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==} engines: {node: '>=18.0.0'} @@ -88,6 +95,10 @@ packages: resolution: {integrity: sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==} engines: {node: '>=18.0.0'} + '@azure/core-client@1.9.2': + resolution: {integrity: sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==} + engines: {node: '>=18.0.0'} + '@azure/core-rest-pipeline@1.16.3': resolution: {integrity: sha512-VxLk4AHLyqcHsfKe4MZ6IQ+D+ShuByy+RfStKfSjxJoL3WBWq17VNmrz8aT8etKzqc2nAeIyLxScjpzsS4fz8w==} engines: {node: '>=18.0.0'} @@ -100,10 +111,26 @@ packages: resolution: {integrity: sha512-l1Qrqhi4x1aekkV+OlcqsJa4AnAkj5p0JV8omgwjaV9OAbP41lvrMvs+CptfetKkeEaGRGSzby7sjPZEX7+kkQ==} engines: {node: '>=18.0.0'} + '@azure/identity@4.4.1': + resolution: {integrity: sha512-DwnG4cKFEM7S3T+9u05NstXU/HN0dk45kPOinUyNKsn5VWwpXd9sbPKEg6kgJzGbm1lMuhx9o31PVbCtM5sfBA==} + engines: {node: '>=18.0.0'} + '@azure/logger@1.1.4': resolution: {integrity: sha512-4IXXzcCdLdlXuCG+8UKEwLA1T1NHqUfanhXYHiQTn+6sfWCZXduqbtXDGceg3Ce5QxTGo7EqmbV6Bi+aqKuClQ==} engines: {node: '>=18.0.0'} + '@azure/msal-browser@3.23.0': + resolution: {integrity: sha512-+QgdMvaeEpdtgRTD7AHHq9aw8uga7mXVHV1KshO1RQ2uI5B55xJ4aEpGlg/ga3H+0arEVcRfT4ZVmX7QLXiCVw==} + engines: {node: '>=0.8.0'} + + '@azure/msal-common@14.14.2': + resolution: {integrity: sha512-XV0P5kSNwDwCA/SjIxTe9mEAsKB0NqGNSuaVrkCCE2lAyBr/D6YtD80Vkdp4tjWnPFwjzkwldjr1xU/facOJog==} + engines: {node: '>=0.8.0'} + + '@azure/msal-node@2.13.1': + resolution: {integrity: sha512-sijfzPNorKt6+9g1/miHwhj6Iapff4mPQx1azmmZExgzUROqWTM1o3ACyxDja0g47VpowFy/sxTM/WsuCyXTiw==} + engines: {node: '>=16'} + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -433,6 +460,59 @@ packages: resolution: {integrity: sha512-Gc6EdaLANdktQ1t+zozoBVRynfIsMKMc94Svu1QreOBC8y76x4tvaK32TljrLi1LI2+PK58sDVbL7ALdqf3VRQ==} engines: {node: '>=16'} + '@vscode/vsce-sign-alpine-arm64@2.0.2': + resolution: {integrity: sha512-E80YvqhtZCLUv3YAf9+tIbbqoinWLCO/B3j03yQPbjT3ZIHCliKZlsy1peNc4XNZ5uIb87Jn0HWx/ZbPXviuAQ==} + cpu: [arm64] + os: [alpine] + + '@vscode/vsce-sign-alpine-x64@2.0.2': + resolution: {integrity: sha512-n1WC15MSMvTaeJ5KjWCzo0nzjydwxLyoHiMJHu1Ov0VWTZiddasmOQHekA47tFRycnt4FsQrlkSCTdgHppn6bw==} + cpu: [x64] + os: [alpine] + + '@vscode/vsce-sign-darwin-arm64@2.0.2': + resolution: {integrity: sha512-rz8F4pMcxPj8fjKAJIfkUT8ycG9CjIp888VY/6pq6cuI2qEzQ0+b5p3xb74CJnBbSC0p2eRVoe+WgNCAxCLtzQ==} + cpu: [arm64] + os: [darwin] + + '@vscode/vsce-sign-darwin-x64@2.0.2': + resolution: {integrity: sha512-MCjPrQ5MY/QVoZ6n0D92jcRb7eYvxAujG/AH2yM6lI0BspvJQxp0o9s5oiAM9r32r9tkLpiy5s2icsbwefAQIw==} + cpu: [x64] + os: [darwin] + + '@vscode/vsce-sign-linux-arm64@2.0.2': + resolution: {integrity: sha512-Ybeu7cA6+/koxszsORXX0OJk9N0GgfHq70Wqi4vv2iJCZvBrOWwcIrxKjvFtwyDgdeQzgPheH5nhLVl5eQy7WA==} + cpu: [arm64] + os: [linux] + + '@vscode/vsce-sign-linux-arm@2.0.2': + resolution: {integrity: sha512-Fkb5jpbfhZKVw3xwR6t7WYfwKZktVGNXdg1m08uEx1anO0oUPUkoQRsNm4QniL3hmfw0ijg00YA6TrxCRkPVOQ==} + cpu: [arm] + os: [linux] + + '@vscode/vsce-sign-linux-x64@2.0.2': + resolution: {integrity: sha512-NsPPFVtLaTlVJKOiTnO8Cl78LZNWy0Q8iAg+LlBiCDEgC12Gt4WXOSs2pmcIjDYzj2kY4NwdeN1mBTaujYZaPg==} + cpu: [x64] + os: [linux] + + '@vscode/vsce-sign-win32-arm64@2.0.2': + resolution: {integrity: sha512-wPs848ymZ3Ny+Y1Qlyi7mcT6VSigG89FWQnp2qRYCyMhdJxOpA4lDwxzlpL8fG6xC8GjQjGDkwbkWUcCobvksQ==} + cpu: [arm64] + os: [win32] + + '@vscode/vsce-sign-win32-x64@2.0.2': + resolution: {integrity: sha512-pAiRN6qSAhDM5SVOIxgx+2xnoVUePHbRNC7OD2aOR3WltTKxxF25OfpK8h8UQ7A0BuRkSgREbB59DBlFk4iAeg==} + cpu: [x64] + os: [win32] + + '@vscode/vsce-sign@2.0.4': + resolution: {integrity: sha512-0uL32egStKYfy60IqnynAChMTbL0oqpqk0Ew0YHiIb+fayuGZWADuIPHWUcY1GCnAA+VgchOPDMxnc2R3XGWEA==} + + '@vscode/vsce@3.1.0': + resolution: {integrity: sha512-fwdfp1Ol+bZtlSGkpcd/nztfo6+SVsTOMWjZ/+a88lVtUn7gXNbSu7dbniecl5mz4vINl+oaVDVtVdGbJDApmw==} + engines: {node: '>= 20'} + hasBin: true + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -466,6 +546,10 @@ packages: resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} engines: {node: '>=12'} + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -488,6 +572,12 @@ packages: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + azure-devops-node-api@12.5.0: + resolution: {integrity: sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -498,6 +588,9 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + bl@5.1.0: resolution: {integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==} @@ -517,9 +610,22 @@ packages: browser-stdout@1.3.1: resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -528,6 +634,10 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -536,10 +646,20 @@ packages: resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.0.0: + resolution: {integrity: sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==} + engines: {node: '>=18.17'} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + cli-cursor@4.0.0: resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -555,13 +675,31 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + cockatiel@3.2.1: + resolution: {integrity: sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==} + engines: {node: '>=16'} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@6.2.1: + resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} + engines: {node: '>= 6'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -595,6 +733,14 @@ packages: resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} engines: {node: '>=10'} + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -602,6 +748,22 @@ packages: resolution: {integrity: sha512-jZRrDmBKjmGcqMFEUJ14FjMJwm05Qaked+1vxaALRtF0UAl7lPU8OLWXFxvoeg3jbQM249VPFVn8g2znaQkEtA==} engines: {node: '>=4.0.0'} + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + detect-libc@2.0.3: + resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} + engines: {node: '>=8'} + diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} @@ -630,6 +792,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + emoji-regex@10.4.0: resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} @@ -639,10 +804,24 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + encoding-sniffer@0.2.0: + resolution: {integrity: sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==} + + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + esbuild-plugin-copy@2.1.1: resolution: {integrity: sha512-Bk66jpevTcV8KMFzZI1P7MZKZ+uDcrZm2G2egZ2jNIvVnivDpodZI+/KnpL3Jnap0PBdIHU7HwFGB8r+vV5CVw==} peerDependencies: @@ -657,6 +836,10 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -706,6 +889,14 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -722,6 +913,9 @@ packages: fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -749,6 +943,13 @@ packages: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} + form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} @@ -761,14 +962,24 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + get-stdin@7.0.0: resolution: {integrity: sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==} engines: {node: '>=8'} + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -803,20 +1014,49 @@ packages: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} + gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + + has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + hosted-git-info@4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + + htmlparser2@9.1.0: + resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} + http-proxy-agent@7.0.2: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} @@ -825,6 +1065,10 @@ packages: resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} engines: {node: '>= 14'} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -850,10 +1094,18 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -890,6 +1142,10 @@ packages: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} engines: {node: '>=12'} + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -916,15 +1172,41 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + jsonwebtoken@9.0.2: + resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + engines: {node: '>=12', npm: '>=6'} + jszip@3.10.1: resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + jwa@1.4.1: + resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==} + + jwa@2.0.0: + resolution: {integrity: sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==} + + jws@3.2.2: + resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} + + jws@4.0.0: + resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} + + keytar@7.9.0: + resolution: {integrity: sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -948,9 +1230,30 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + + lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + + lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + + lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} @@ -966,6 +1269,10 @@ packages: resolution: {integrity: sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==} engines: {node: 20 || >=22} + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} @@ -984,10 +1291,27 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + minimatch@10.0.1: resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} engines: {node: 20 || >=22} @@ -1003,10 +1327,16 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + mocha@10.7.3: resolution: {integrity: sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==} engines: {node: '>= 14.0.0'} @@ -1015,9 +1345,22 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mute-stream@0.0.8: + resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + + napi-build-utils@1.0.2: + resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + node-abi@3.67.0: + resolution: {integrity: sha512-bLn/fU/ALVBE9wj+p4Y21ZJWYFjUXLXPi/IewyLZkx3ApxKDNBWCKdReeKOtD8dWpOdDCeMyLh6ZewzcLsG2Nw==} + engines: {node: '>=10'} + + node-addon-api@4.3.0: + resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} + node-html-markdown@1.3.0: resolution: {integrity: sha512-OeFi3QwC/cPjvVKZ114tzzu+YoR+v9UXW5RwSXGUqGb0qCl0DvP406tzdL7SFn8pZrMyzXoisfG2zcuF9+zw4g==} engines: {node: '>=10.0.0'} @@ -1032,6 +1375,10 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + object-inspect@1.13.2: + resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} + engines: {node: '>= 0.4'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -1039,6 +1386,10 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -1065,6 +1416,18 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-semver@1.1.1: + resolution: {integrity: sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==} + + parse5-htmlparser2-tree-adapter@7.0.0: + resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + + parse5@7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + path-equal@1.2.5: resolution: {integrity: sha512-i73IctDr3F2W+bsOWDyyVm/lqsXO47aY9nsFZUjTT/aljSbkxHxxCoyZ9UUrM8jK0JVod+An+rl48RCsvWM+9g==} @@ -1092,10 +1455,18 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + prebuild-install@7.1.2: + resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} + engines: {node: '>=10'} + hasBin: true + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -1112,6 +1483,9 @@ packages: resolution: {integrity: sha512-ISYMOKY8+f+PmiXMFw2y6KLY74LBrv/8ml/VjjoVEV2k+MS+OJZz7ydciK5ntJwxPrKQPTU1+oXq9Mx2b0zEzg==} hasBin: true + pump@3.0.1: + resolution: {integrity: sha512-2ynnAmUu45oUSq51AQbeugLkMSKaz8FqVpZ6ykTqzOVkzXe8u/ezkGsYrFJqKZx+D9cVxoDrSbR7CeAwxFa5cQ==} + punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} @@ -1120,12 +1494,24 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + engines: {node: '>=0.6'} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + read@1.0.7: + resolution: {integrity: sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==} + engines: {node: '>=0.8'} + readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -1170,9 +1556,16 @@ packages: resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} engines: {node: '>=10'} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sax@1.4.1: resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + semver@7.6.3: resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} @@ -1181,6 +1574,10 @@ packages: serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} @@ -1192,6 +1589,10 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -1199,6 +1600,12 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -1207,6 +1614,10 @@ packages: resolution: {integrity: sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + stoppable@1.1.0: + resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} + engines: {node: '>=4', npm: '>=6'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -1233,10 +1644,18 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -1245,9 +1664,20 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} + tar-fs@2.1.1: + resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + tmp@0.2.3: + resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} + engines: {node: '>=14.14'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -1275,10 +1705,20 @@ packages: tslib@2.7.0: resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + tunnel@0.0.6: + resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} + engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + typed-rest-client@1.8.11: + resolution: {integrity: sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==} + typescript-json-schema@0.65.1: resolution: {integrity: sha512-tuGH7ff2jPaUYi6as3lHyHcKpSmXIqN7/mu50x3HlYn0EHzLpmt3nplZ7EuhUkO0eqDRc9GqWNkfjgBPIS9kxg==} hasBin: true @@ -1296,12 +1736,19 @@ packages: uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + underscore@1.13.7: + resolution: {integrity: sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==} + undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} undici-types@6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + undici@6.19.8: + resolution: {integrity: sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==} + engines: {node: '>=18.17'} + universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -1309,15 +1756,30 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + url-join@4.0.1: + resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} web-tree-sitter@0.20.8: resolution: {integrity: sha512-weOVgZ3aAARgdnb220GqYuh7+rZU0Ka9k9yfKtGAzEYMa6GgiCzW9JjQRJyCJakvibQW+dfjJdihjInKuuCAUQ==} + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -1353,6 +1815,9 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} @@ -1373,6 +1838,12 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + + yazl@2.5.1: + resolution: {integrity: sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==} + yn@3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} @@ -1404,6 +1875,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@azure/abort-controller@1.1.0': + dependencies: + tslib: 2.7.0 + '@azure/abort-controller@2.1.2': dependencies: tslib: 2.7.0 @@ -1414,6 +1889,18 @@ snapshots: '@azure/core-util': 1.9.2 tslib: 2.7.0 + '@azure/core-client@1.9.2': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.7.2 + '@azure/core-rest-pipeline': 1.16.3 + '@azure/core-tracing': 1.1.2 + '@azure/core-util': 1.9.2 + '@azure/logger': 1.1.4 + tslib: 2.7.0 + transitivePeerDependencies: + - supports-color + '@azure/core-rest-pipeline@1.16.3': dependencies: '@azure/abort-controller': 2.1.2 @@ -1436,10 +1923,41 @@ snapshots: '@azure/abort-controller': 2.1.2 tslib: 2.7.0 + '@azure/identity@4.4.1': + dependencies: + '@azure/abort-controller': 1.1.0 + '@azure/core-auth': 1.7.2 + '@azure/core-client': 1.9.2 + '@azure/core-rest-pipeline': 1.16.3 + '@azure/core-tracing': 1.1.2 + '@azure/core-util': 1.9.2 + '@azure/logger': 1.1.4 + '@azure/msal-browser': 3.23.0 + '@azure/msal-node': 2.13.1 + events: 3.3.0 + jws: 4.0.0 + open: 8.4.2 + stoppable: 1.1.0 + tslib: 2.7.0 + transitivePeerDependencies: + - supports-color + '@azure/logger@1.1.4': dependencies: tslib: 2.7.0 + '@azure/msal-browser@3.23.0': + dependencies: + '@azure/msal-common': 14.14.2 + + '@azure/msal-common@14.14.2': {} + + '@azure/msal-node@2.13.1': + dependencies: + '@azure/msal-common': 14.14.2 + jsonwebtoken: 9.0.2 + uuid: 8.3.2 + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 @@ -1739,6 +2257,76 @@ snapshots: transitivePeerDependencies: - supports-color + '@vscode/vsce-sign-alpine-arm64@2.0.2': + optional: true + + '@vscode/vsce-sign-alpine-x64@2.0.2': + optional: true + + '@vscode/vsce-sign-darwin-arm64@2.0.2': + optional: true + + '@vscode/vsce-sign-darwin-x64@2.0.2': + optional: true + + '@vscode/vsce-sign-linux-arm64@2.0.2': + optional: true + + '@vscode/vsce-sign-linux-arm@2.0.2': + optional: true + + '@vscode/vsce-sign-linux-x64@2.0.2': + optional: true + + '@vscode/vsce-sign-win32-arm64@2.0.2': + optional: true + + '@vscode/vsce-sign-win32-x64@2.0.2': + optional: true + + '@vscode/vsce-sign@2.0.4': + optionalDependencies: + '@vscode/vsce-sign-alpine-arm64': 2.0.2 + '@vscode/vsce-sign-alpine-x64': 2.0.2 + '@vscode/vsce-sign-darwin-arm64': 2.0.2 + '@vscode/vsce-sign-darwin-x64': 2.0.2 + '@vscode/vsce-sign-linux-arm': 2.0.2 + '@vscode/vsce-sign-linux-arm64': 2.0.2 + '@vscode/vsce-sign-linux-x64': 2.0.2 + '@vscode/vsce-sign-win32-arm64': 2.0.2 + '@vscode/vsce-sign-win32-x64': 2.0.2 + + '@vscode/vsce@3.1.0': + dependencies: + '@azure/identity': 4.4.1 + '@vscode/vsce-sign': 2.0.4 + azure-devops-node-api: 12.5.0 + chalk: 2.4.2 + cheerio: 1.0.0 + cockatiel: 3.2.1 + commander: 6.2.1 + form-data: 4.0.0 + glob: 11.0.0 + hosted-git-info: 4.1.0 + jsonc-parser: 3.3.1 + leven: 3.1.0 + markdown-it: 14.1.0 + mime: 1.6.0 + minimatch: 3.1.2 + parse-semver: 1.1.1 + read: 1.0.7 + semver: 7.6.3 + tmp: 0.2.3 + typed-rest-client: 1.8.11 + url-join: 4.0.1 + xml2js: 0.5.0 + yauzl: 2.10.0 + yazl: 2.5.1 + optionalDependencies: + keytar: 7.9.0 + transitivePeerDependencies: + - supports-color + acorn-jsx@5.3.2(acorn@8.12.1): dependencies: acorn: 8.12.1 @@ -1768,6 +2356,10 @@ snapshots: ansi-regex@6.1.0: {} + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -1785,12 +2377,26 @@ snapshots: array-union@2.1.0: {} + asynckit@0.4.0: {} + + azure-devops-node-api@12.5.0: + dependencies: + tunnel: 0.0.6 + typed-rest-client: 1.8.11 + balanced-match@1.0.2: {} base64-js@1.5.1: {} binary-extensions@2.3.0: {} + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + optional: true + bl@5.1.0: dependencies: buffer: 6.0.3 @@ -1814,15 +2420,39 @@ snapshots: browser-stdout@1.3.1: {} + buffer-crc32@0.2.13: {} + + buffer-equal-constant-time@1.0.1: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + optional: true + buffer@6.0.3: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 + call-bind@1.0.7: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + callsites@3.1.0: {} camelcase@6.3.0: {} + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -1830,6 +2460,29 @@ snapshots: chalk@5.3.0: {} + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.1.0 + css-what: 6.1.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.1.0 + + cheerio@1.0.0: + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.1.0 + encoding-sniffer: 0.2.0 + htmlparser2: 9.1.0 + parse5: 7.1.2 + parse5-htmlparser2-tree-adapter: 7.0.0 + parse5-parser-stream: 7.1.2 + undici: 6.19.8 + whatwg-mimetype: 4.0.0 + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -1842,6 +2495,9 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + chownr@1.1.4: + optional: true + cli-cursor@4.0.0: dependencies: restore-cursor: 4.0.0 @@ -1860,12 +2516,26 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + cockatiel@3.2.1: {} + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + color-convert@2.0.1: dependencies: color-name: 1.1.4 + color-name@1.1.3: {} + color-name@1.1.4: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@6.2.1: {} + concat-map@0.0.1: {} core-util-is@1.0.3: {} @@ -1896,10 +2566,31 @@ snapshots: decamelize@4.0.0: {} + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + optional: true + + deep-extend@0.6.0: + optional: true + deep-is@0.1.4: {} deepmerge-json@1.5.0: {} + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + + define-lazy-prop@2.0.0: {} + + delayed-stream@1.0.0: {} + + detect-libc@2.0.3: + optional: true + diff@4.0.2: {} diff@5.2.0: {} @@ -1928,14 +2619,34 @@ snapshots: eastasianwidth@0.2.0: {} + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + emoji-regex@10.4.0: {} emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} + encoding-sniffer@0.2.0: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 + optional: true + entities@4.5.0: {} + es-define-property@1.0.0: + dependencies: + get-intrinsic: 1.2.4 + + es-errors@1.3.0: {} + esbuild-plugin-copy@2.1.1(esbuild@0.23.1): dependencies: chalk: 4.1.2 @@ -1973,6 +2684,8 @@ snapshots: escalade@3.2.0: {} + escape-string-regexp@1.0.5: {} + escape-string-regexp@4.0.0: {} eslint-plugin-license-header@0.6.1: @@ -2045,6 +2758,11 @@ snapshots: esutils@2.0.3: {} + events@3.3.0: {} + + expand-template@2.0.3: + optional: true + fast-deep-equal@3.1.3: {} fast-glob@3.3.2: @@ -2063,6 +2781,10 @@ snapshots: dependencies: reusify: 1.0.4 + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -2090,6 +2812,15 @@ snapshots: cross-spawn: 7.0.3 signal-exit: 4.1.0 + form-data@4.0.0: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + fs-constants@1.0.0: + optional: true + fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 @@ -2101,10 +2832,23 @@ snapshots: fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + get-caller-file@2.0.5: {} + get-intrinsic@1.2.4: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + get-stdin@7.0.0: {} + github-from-package@0.0.0: + optional: true + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -2159,14 +2903,43 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 + gopd@1.0.1: + dependencies: + get-intrinsic: 1.2.4 + graceful-fs@4.2.11: {} graphemer@1.4.0: {} + has-flag@3.0.0: {} + has-flag@4.0.0: {} + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.0 + + has-proto@1.0.3: {} + + has-symbols@1.0.3: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + he@1.2.0: {} + hosted-git-info@4.1.0: + dependencies: + lru-cache: 6.0.0 + + htmlparser2@9.1.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.1.0 + entities: 4.5.0 + http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.1 @@ -2181,6 +2954,10 @@ snapshots: transitivePeerDependencies: - supports-color + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + ieee754@1.2.1: {} ignore@5.3.2: {} @@ -2201,10 +2978,15 @@ snapshots: inherits@2.0.4: {} + ini@1.3.8: + optional: true + is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 + is-docker@2.2.1: {} + is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} @@ -2225,6 +3007,10 @@ snapshots: is-unicode-supported@1.3.0: {} + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + isarray@1.0.0: {} isexe@2.0.0: {} @@ -2251,12 +3037,27 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} + jsonc-parser@3.3.1: {} + jsonfile@6.1.0: dependencies: universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 + jsonwebtoken@9.0.2: + dependencies: + jws: 3.2.2 + lodash.includes: 4.3.0 + lodash.isboolean: 3.0.3 + lodash.isinteger: 4.0.4 + lodash.isnumber: 3.0.3 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.once: 4.1.1 + ms: 2.1.3 + semver: 7.6.3 + jszip@3.10.1: dependencies: lie: 3.3.0 @@ -2264,10 +3065,40 @@ snapshots: readable-stream: 2.3.8 setimmediate: 1.0.5 + jwa@1.4.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jwa@2.0.0: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@3.2.2: + dependencies: + jwa: 1.4.1 + safe-buffer: 5.2.1 + + jws@4.0.0: + dependencies: + jwa: 2.0.0 + safe-buffer: 5.2.1 + + keytar@7.9.0: + dependencies: + node-addon-api: 4.3.0 + prebuild-install: 7.1.2 + optional: true + keyv@4.5.4: dependencies: json-buffer: 3.0.1 + leven@3.1.0: {} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -2301,8 +3132,22 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash.includes@4.3.0: {} + + lodash.isboolean@3.0.3: {} + + lodash.isinteger@4.0.4: {} + + lodash.isnumber@3.0.3: {} + + lodash.isplainobject@4.0.6: {} + + lodash.isstring@4.0.1: {} + lodash.merge@4.6.2: {} + lodash.once@4.1.1: {} + log-symbols@4.1.0: dependencies: chalk: 4.1.2 @@ -2317,6 +3162,10 @@ snapshots: lru-cache@11.0.1: {} + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + make-error@1.3.6: {} markdown-it@14.1.0: @@ -2337,8 +3186,19 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@1.6.0: {} + mimic-fn@2.1.0: {} + mimic-response@3.1.0: + optional: true + minimatch@10.0.1: dependencies: brace-expansion: 2.0.1 @@ -2355,8 +3215,14 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minimist@1.2.8: + optional: true + minipass@7.1.2: {} + mkdirp-classic@0.5.3: + optional: true + mocha@10.7.3: dependencies: ansi-colors: 4.1.3 @@ -2382,8 +3248,21 @@ snapshots: ms@2.1.3: {} + mute-stream@0.0.8: {} + + napi-build-utils@1.0.2: + optional: true + natural-compare@1.4.0: {} + node-abi@3.67.0: + dependencies: + semver: 7.6.3 + optional: true + + node-addon-api@4.3.0: + optional: true + node-html-markdown@1.3.0: dependencies: node-html-parser: 6.1.13 @@ -2399,6 +3278,8 @@ snapshots: dependencies: boolbase: 1.0.0 + object-inspect@1.13.2: {} + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -2407,6 +3288,12 @@ snapshots: dependencies: mimic-fn: 2.1.0 + open@8.4.2: + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -2444,6 +3331,23 @@ snapshots: dependencies: callsites: 3.1.0 + parse-semver@1.1.1: + dependencies: + semver: 5.7.2 + + parse5-htmlparser2-tree-adapter@7.0.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.1.2 + + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.1.2 + + parse5@7.1.2: + dependencies: + entities: 4.5.0 + path-equal@1.2.5: {} path-exists@4.0.0: {} @@ -2464,8 +3368,26 @@ snapshots: path-type@4.0.0: {} + pend@1.2.0: {} + picomatch@2.3.1: {} + prebuild-install@7.1.2: + dependencies: + detect-libc: 2.0.3 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 1.0.2 + node-abi: 3.67.0 + pump: 3.0.1 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.1 + tunnel-agent: 0.6.0 + optional: true + prelude-ls@1.2.1: {} prettier@3.3.3: {} @@ -2479,16 +3401,38 @@ snapshots: typescript: 4.9.5 yargs: 17.7.2 + pump@3.0.1: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + optional: true + punycode.js@2.3.1: {} punycode@2.3.1: {} + qs@6.13.0: + dependencies: + side-channel: 1.0.6 + queue-microtask@1.2.3: {} randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + optional: true + + read@1.0.7: + dependencies: + mute-stream: 0.0.8 + readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -2532,14 +3476,27 @@ snapshots: safe-stable-stringify@2.5.0: {} + safer-buffer@2.1.2: {} + sax@1.4.1: {} + semver@5.7.2: {} + semver@7.6.3: {} serialize-javascript@6.0.2: dependencies: randombytes: 2.1.0 + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + setimmediate@1.0.5: {} shebang-command@2.0.0: @@ -2548,16 +3505,35 @@ snapshots: shebang-regex@3.0.0: {} + side-channel@1.0.6: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.2 + signal-exit@3.0.7: {} signal-exit@4.1.0: {} + simple-concat@1.0.1: + optional: true + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + optional: true + slash@3.0.0: {} stdin-discarder@0.1.0: dependencies: bl: 5.1.0 + stoppable@1.1.0: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -2592,8 +3568,15 @@ snapshots: dependencies: ansi-regex: 6.1.0 + strip-json-comments@2.0.1: + optional: true + strip-json-comments@3.1.1: {} + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -2602,8 +3585,27 @@ snapshots: dependencies: has-flag: 4.0.0 + tar-fs@2.1.1: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.1 + tar-stream: 2.2.0 + optional: true + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + optional: true + text-table@0.2.0: {} + tmp@0.2.3: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -2632,10 +3634,23 @@ snapshots: tslib@2.7.0: {} + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + optional: true + + tunnel@0.0.6: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 + typed-rest-client@1.8.11: + dependencies: + qs: 6.13.0 + tunnel: 0.0.6 + underscore: 1.13.7 + typescript-json-schema@0.65.1: dependencies: '@types/json-schema': 7.0.15 @@ -2656,22 +3671,36 @@ snapshots: uc.micro@2.1.0: {} + underscore@1.13.7: {} + undici-types@5.26.5: {} undici-types@6.19.8: {} + undici@6.19.8: {} + universalify@2.0.1: {} uri-js@4.4.1: dependencies: punycode: 2.3.1 + url-join@4.0.1: {} + util-deprecate@1.0.2: {} + uuid@8.3.2: {} + v8-compile-cache-lib@3.0.1: {} web-tree-sitter@0.20.8: {} + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + which@2.0.2: dependencies: isexe: 2.0.0 @@ -2703,6 +3732,8 @@ snapshots: y18n@5.0.8: {} + yallist@4.0.0: {} + yargs-parser@20.2.9: {} yargs-parser@21.1.1: {} @@ -2734,6 +3765,15 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + + yazl@2.5.1: + dependencies: + buffer-crc32: 0.2.13 + yn@3.1.1: {} yocto-queue@0.1.0: {} diff --git a/server/src/compareWithCommit.ts b/server/src/compareWithCommit.ts new file mode 100644 index 0000000000000000000000000000000000000000..efa43bf75b217dd97ee9acc97f4109b6ee656278 --- /dev/null +++ b/server/src/compareWithCommit.ts @@ -0,0 +1,166 @@ +import { exec } from "child_process"; + +function runCommand(command: string, workspaceRoot: string): Promise { + return new Promise((resolve, reject) => { + exec(command, { cwd: workspaceRoot }, (error, stdout, stderr) => { + if (error) { + console.log(`stdout: ${stdout}; stderr: ${stderr}; error.message: ${error.message}`); + } else { + console.log(`stdout: ${stdout}; stderr: ${stderr}`); + } + resolve(stdout.trim()); + }); + }); +} + +interface Change { + originalLineFrom: number; + originalLineTo: number; + originalColFrom: number; + originalColTo: number; + newLineFrom: number; + newLineTo: number; + newColFrom: number; + newColTo: number; +} + +export async function compareFileWithCommit( + filePath: string, + commitId: string, + workspaceUri: string, +) { + const stdout = await runCommand( + `git diff -U0 --word-diff=porcelain ${commitId} -- ${filePath}`, + workspaceUri, + ); + console.log("Running:", `git diff -U0 --word-diff=porcelain ${commitId} -- ${filePath}`); + // 解析 diff 信息 + const changes = parseGitDiff(stdout); + console.log("Changes:", changes); + return changes; +} + +function parseGitDiff( + diffOutput: string, +): [Map, Set, Map>] { + const lineOffset = new Map(); + const colOffset = new Map>(); + const deletedLines = new Set(); + const lines = diffOutput.split("\n"); + let i = 0; + + while (i < lines.length) { + const line = lines[i++]; + + if ( + line.startsWith("diff --git") || + line.startsWith("index") || + line.startsWith("---") || + line.startsWith("+++") + ) { + i++; + continue; + } + + // 检查是否为 hunk 头部 + const hunkHeaderRegex = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/; + const hunkHeaderMatch = line.match(hunkHeaderRegex); + + if (hunkHeaderMatch) { + const originalStartLine = parseInt(hunkHeaderMatch[1], 10); + const originalLineCount = hunkHeaderMatch[2] ? parseInt(hunkHeaderMatch[2], 10) : 1; + const newStartLine = parseInt(hunkHeaderMatch[3], 10); + const newLineCount = hunkHeaderMatch[4] ? parseInt(hunkHeaderMatch[4], 10) : 1; + + if (originalLineCount === 0) { + lineOffset.set(originalStartLine + 1, newStartLine + newLineCount - originalStartLine - 1); + } else if (newLineCount === 0) { + lineOffset.set( + originalStartLine + originalLineCount, + newStartLine + 1 - originalStartLine - originalLineCount, + ); + for (let j = originalStartLine; j < originalStartLine + originalLineCount; j++) { + deletedLines.add(j); + } + } else { + lineOffset.set(originalStartLine, newStartLine - originalStartLine); + } + + if (originalLineCount !== 0 && newLineCount !== 0) { + colOffset.set(originalStartLine, new Map()); + // console.assert(originalLineCount === newLineCount, "Line count mismatch"); + let lineNum = 0; + let colIndex = 0; + while ((lineNum < originalLineCount || lineNum < newLineCount) && i < lines.length) { + let lineContent = lines[i++]; + if (lineContent.startsWith("~")) { + lineNum += 1; + colIndex = 0; + } else if (lineContent.startsWith("-")) { + const originalItemLength = lineContent.length - 1; + const nextLine = lines[i++]; + if (nextLine.startsWith("+")) { + const newItemLength = nextLine.length - 1; + colOffset + .get(originalStartLine) + ?.set(colIndex + 1, newItemLength - originalItemLength); + colIndex += originalItemLength; + } else { + colOffset.get(originalStartLine)?.set(colIndex + 1, -originalItemLength); + } + } else { + colIndex += lineContent.length - 1; + } + } + if (!colOffset.get(originalStartLine)?.has(0)) { + colOffset.get(originalStartLine)?.set(0, 0); + } + } + } + } + + if (!lineOffset.has(0)) { + lineOffset.set(0, 0); + } + return [lineOffset, deletedLines, colOffset]; +} + +function compareLines( + originalLine: string, + newLine: string, + originalLineNum: number, + newLineNum: number, +): Change { + // 简单比较两个字符串,找到变化的位置 + let startIndex = 0; + while ( + startIndex < originalLine.length && + startIndex < newLine.length && + originalLine[startIndex] === newLine[startIndex] + ) { + startIndex++; + } + + let originalEndIndex = originalLine.length - 1; + let newEndIndex = newLine.length - 1; + while ( + originalEndIndex >= startIndex && + newEndIndex >= startIndex && + originalLine[originalEndIndex] === newLine[newEndIndex] + ) { + originalEndIndex--; + newEndIndex--; + } + + const change: Change = { + originalLineFrom: originalLineNum, + originalLineTo: originalLineNum, + originalColFrom: startIndex + 1, + originalColTo: originalEndIndex + 2, + newLineFrom: newLineNum, + newLineTo: newLineNum, + newColFrom: startIndex + 1, + newColTo: newEndIndex + 2, + }; + return change; +} diff --git a/server/src/docCacheManager.ts b/server/src/docCacheManager.ts index 0e4007a3c7aa3575c804ab3facfda11f660f357c..7df405950998ffb805bdff7d001a8a35e6b569be 100644 --- a/server/src/docCacheManager.ts +++ b/server/src/docCacheManager.ts @@ -17,10 +17,9 @@ * Last Change: Sep 6, 2024 **************************************************************************************/ +import { TextDocument, TextDocumentContentChangeEvent } from "vscode-languageserver-textdocument"; import * as lsp from "vscode-languageserver/node"; import { ServerLogger } from "./utils/log"; -import { TextDocument, TextDocumentContentChangeEvent } from "vscode-languageserver-textdocument"; -import { TextDocumentChangeEvent } from "vscode"; const logger = ServerLogger.getLogger("DocumentsCacheManager"); @@ -97,13 +96,13 @@ export class DocumentsCacheManager { document.uri, document.languageId, document.version, - document.getText() + document.getText(), ); } public update( docUri: string, - updEvent?: TextDocumentContentChangeEvent | TextDocumentContentChangeEvent[] + updEvent?: TextDocumentContentChangeEvent | TextDocumentContentChangeEvent[], ) { docUri = docUri.toString(); let doc = this._cacheMap.get(docUri); diff --git a/server/src/docSettingManager.ts b/server/src/docSettingManager.ts index c574c116c54485793a3d8ae0c377b06089c89cab..96461866103cbc453964b19adbc361482d546823 100644 --- a/server/src/docSettingManager.ts +++ b/server/src/docSettingManager.ts @@ -17,10 +17,10 @@ * Last Change: Sep 6, 2024 **************************************************************************************/ +import { TextDocument } from "vscode-languageserver-textdocument"; import * as lsp from "vscode-languageserver/node"; import { ClientCapabilities } from "./types/clientCapabilities"; import { ServerLogger } from "./utils/log"; -import { TextDocument } from "vscode-languageserver-textdocument"; /** Logger */ const logger = ServerLogger.getLogger("documentsSettingManager"); @@ -64,7 +64,7 @@ export class DocumentsSettingManager { documents: lsp.TextDocuments, clientCapabilities: ClientCapabilities, sectionName: string, - defaultSettings: T + defaultSettings: T, ) { this._connection = connection; this._documents = documents; @@ -94,14 +94,14 @@ export class DocumentsSettingManager { documents: lsp.TextDocuments, clientCapabilities: ClientCapabilities, sectionName: string, - defaultSettings: T + defaultSettings: T, ): DocumentsSettingManager { this._instance = new DocumentsSettingManager( connection, documents, clientCapabilities, sectionName, - defaultSettings + defaultSettings, ); logger.debug("init: finished"); return this._instance; diff --git a/server/src/reportManager.ts b/server/src/reportManager.ts index cb0a8499ed7006ca122becbc666b74901f1686fc..8f384ce66e1afab18acf0bbb227a932a900ecd88 100644 --- a/server/src/reportManager.ts +++ b/server/src/reportManager.ts @@ -18,20 +18,22 @@ * Last Change: Sep 11, 2024 **************************************************************************************/ +import Ajv, * as ajv from "ajv"; import * as fs from "fs"; import * as mkdirp from "mkdirp"; -import { IReport } from "../../common/src/types/report"; -import { ReportMeta } from "./types/reportMeta"; +import * as lsp from "vscode-languageserver"; +import { URI } from "vscode-uri"; +import { IProblem, IReport } from "../../common/src/types/report"; import { ReportMgrLoadError, ReportMgrLoadErrorType, + ReportMgrLoadParams, ReportMgrSaveError, + ReportMgrSaveParams, } from "../../common/src/types/reportManager"; -import { ReportMgrLoadParams, ReportMgrSaveParams } from "../../common/src/types/reportManager"; +import { ReportMeta } from "../../common/src/types/reportMeta"; +import { TextDocChangeParams } from "./reportTransformer"; import { ServerLogger } from "./utils/log"; -import { TextDocChangeParams, updateReportByTextDocumentChange } from "./reportTransformer"; -import { URI } from "vscode-uri"; -import Ajv, * as ajv from "ajv"; import path = require("path"); import strFormat = require("string-format"); @@ -50,9 +52,80 @@ export class ReportManager { * key 为工作区的 Uri 文本 */ private _reportMetaMap: Map; + private _diagnosticPDataMap: Map; constructor() { this._reportMetaMap = new Map(); + this._diagnosticPDataMap = new Map(); + } + + /** + * 添加报告 + * + * @param connection LSP 连接 + * @param diagnostics 诊断信息列表 + * @param pData 诊断信息列表对应的问题数据 + * @param reportUri 报告 Uri + * @param version 报告版本 + */ + public async addDiagnostics( + connection: lsp.Connection, + diagnostics: lsp.Diagnostic[], + reportProblems: IProblem[], + reportUri: string, + version: number, + ): Promise { + if (diagnostics.length !== reportProblems.length) { + logger.error("addDiagnostics: diagnostics and pData length not equal"); + return; + } + for (let i = 0; i < diagnostics.length; i++) { + this._diagnosticPDataMap.set( + this.generateDiagnosticKey(diagnostics[i], reportUri), + reportProblems[i], + ); + } + await connection.sendDiagnostics({ + uri: reportUri, + version: version, + diagnostics: diagnostics, + }); + } + + public async clearDiagnostics(connection: lsp.Connection, reportUri: string): Promise { + const currentDiagnostics = await connection.sendRequest("diagnostics", { + uri: reportUri, + }); + for (const diagnostic of currentDiagnostics) { + this._diagnosticPDataMap.delete(this.generateDiagnosticKey(diagnostic, reportUri)); + } + await connection.sendDiagnostics({ + uri: reportUri, + version: 1, + diagnostics: [], + }); + } + + private generateDiagnosticKey(diagnostic: lsp.Diagnostic, uri: string): string { + // 获取诊断的必要信息 + const range = diagnostic.range; + const startLine = range.start.line; + const startChar = range.start.character; + const endLine = range.end.line; + const endChar = range.end.character; + const code = diagnostic.code || ""; // 有些诊断可能没有 code + const source = diagnostic.source || ""; // 有些诊断可能没有 source + const message = diagnostic.message || ""; // 有些诊断可能没有 message + + // 生成唯一键 + const key = `${uri}:${startLine}:${startChar}:${endLine}:${endChar}:${code}:${source}:${message}`; + + // 返回生成的键 + return key; + } + + public getReportProblem(diagnostic: lsp.Diagnostic, uri: string): IProblem | undefined { + return this._diagnosticPDataMap.get(this.generateDiagnosticKey(diagnostic, uri)); } /** @@ -94,7 +167,7 @@ export class ReportManager { } // 尝试读取报告对象 - const reportObj = this.loadFromFile(reportUri.fsPath); + const reportObj = this.importReport(reportUri.fsPath); if (typeof reportObj === "string") { // 返回值为字符串,表示读取失败 logger.error(strFormat("loadReport: {0}: {1}", reportObj, reportUri.toString())); @@ -155,7 +228,7 @@ export class ReportManager { }; // 尝试读取报告对象 - const reportObj = this.loadFromFile(cachePath); + const reportObj = this.importReport(cachePath); if (typeof reportObj === "string") { // 返回值为字符串,表示读取失败 if (reportObj !== "fileNotExists") { @@ -288,6 +361,7 @@ export class ReportManager { * @param workspaceUri 工作区路径 */ public unloadReport(workspaceUri: string): ReportMgrSaveError | undefined { + logger.info(`unloading report for: ${workspaceUri}`); const currentMeta = this._reportMetaMap.get(workspaceUri); if (currentMeta) { const res = this.saveReportCache(currentMeta); @@ -298,7 +372,22 @@ export class ReportManager { return res; } this._reportMetaMap.delete(workspaceUri); - logger.info("unloadReport: ".concat(workspaceUri)); + logger.info("unloaded report for workspace: ".concat(workspaceUri)); + } + return; + } + + /** + * 清除报告数据 + * + * @param workspaceUri 工作区路径 + */ + public clearReport(workspaceUri: string) { + logger.info(`Clearing report for: ${workspaceUri}`); + const cacheUri = URI.file(this.getReportCachePath(workspaceUri)); + if (fs.existsSync(cacheUri.fsPath)) { + fs.unlinkSync(cacheUri.fsPath); + this._reportMetaMap.delete(workspaceUri); } return; } @@ -378,7 +467,7 @@ export class ReportManager { * @param filePath 本地文件路径 * @returns */ - private loadFromFile(filePath: string): IReport | ReportMgrLoadErrorType { + private importReport(filePath: string): IReport | ReportMgrLoadErrorType { if (fs.existsSync(filePath)) { const reportObj = JSON.parse( fs.readFileSync(filePath, { @@ -410,6 +499,6 @@ export class ReportManager { */ public applyChanges(reportMeta: ReportMeta, change: TextDocChangeParams) { // TODO: Report transform - updateReportByTextDocumentChange(reportMeta, change); + // updateReportByTextDocumentChange(reportMeta, change); } } diff --git a/server/src/reportManagerServer.ts b/server/src/reportManagerServer.ts index bd4adc8f3e4b10cc32b6262c3e1d12137e94ee37..0dd21b51f0e9c47cb1e8c1336ee68eaf0070e047 100644 --- a/server/src/reportManagerServer.ts +++ b/server/src/reportManagerServer.ts @@ -15,25 +15,26 @@ * * Author: Lightning Rainstorm * liccc - * Last Change: Sep 6, 2024 + * Last Change: Sep 11, 2024 **************************************************************************************/ +import { CodeAction, CodeActionKind, TextDocumentSyncKind } from "vscode-languageserver"; +import { TextDocument } from "vscode-languageserver-textdocument"; import * as lsp from "vscode-languageserver/node"; -import { ClientCapabilities } from "./types/clientCapabilities"; -import { DocumentsSettingManager } from "./docSettingManager"; +import { URI } from "vscode-uri"; +import { RVCodingAsstConfig } from "../../common/src/types/extConfig"; import { LSPNotificationID } from "../../common/src/types/notification"; -import { refreshDocumentDiagnostics as refreshDocumentDiagnostics } from "./reportToDiagnostic"; -import { ReportManager } from "./reportManager"; import { ReportMgrLoadParams, ReportMgrSaveError, ReportMgrSaveParams, } from "../../common/src/types/reportManager"; -import { RVCodingAsstConfig } from "../../common/src/types/extConfig"; +import * as reqTypes from "../../common/src/types/request"; +import { DocumentsSettingManager } from "./docSettingManager"; +import { ReportManager } from "./reportManager"; +import { refreshDocumentDiagnostics } from "./reportToDiagnostic"; +import { ClientCapabilities } from "./types/clientCapabilities"; import { ServerLogger } from "./utils/log"; -import { TextDocChangeParams } from "./reportTransformer"; -import { TextDocument } from "vscode-languageserver-textdocument"; -import { URI } from "vscode-uri"; import strFormat = require("string-format"); const logger = ServerLogger.getLogger("reportMgrServer"); @@ -58,7 +59,7 @@ export class ReportManagerServer { private constructor( connection: lsp.Connection, documents: lsp.TextDocuments, - clientCapabilities: ClientCapabilities + clientCapabilities: ClientCapabilities, ) { this._connection = connection; this._documents = documents; @@ -70,7 +71,7 @@ export class ReportManagerServer { public static init( connection: lsp.Connection, documents: lsp.TextDocuments, - clientCapabilities: ClientCapabilities + clientCapabilities: ClientCapabilities, ): ReportManagerServer { const manager = new ReportManagerServer(connection, documents, clientCapabilities); @@ -87,25 +88,45 @@ export class ReportManagerServer { } // 监听通知:读取报告数据 - connection.onNotification(LSPNotificationID.reportMgrLoad, (data) => { + connection.onNotification(LSPNotificationID.reportMgrSrvLoad, (data) => { manager.onLoadNotification(data); }); // 监听通知:读取报告 JSON Schema - connection.onNotification(LSPNotificationID.reportMgrLoadSchema, (data) => { + connection.onNotification(LSPNotificationID.reportMgrSrvLoadSchema, (data) => { manager.onLoadSchema(data); }); // 监听通知:保存报告 - connection.onNotification(LSPNotificationID.reportMgrSave, (data) => { + connection.onNotification(LSPNotificationID.reportMgrSrvSave, (data) => { manager.onSaveReport(data); }); // 监听通知:保存所有报告(缓存到工作区) - connection.onNotification(LSPNotificationID.reportMgrSaveCacheAll, () => { + connection.onNotification(LSPNotificationID.reportMgrSrvSaveCacheAll, () => { manager.onSaveCacheAll(); }); + // 监听通知:卸载指定工作区的报告 + connection.onNotification(LSPNotificationID.reportMgrSrvUnload, (data: lsp.URI | lsp.URI[]) => { + manager.unloadWorkspacesReport(data); + }); + + // 监听通知:清除指定工作区的报告 + connection.onNotification(LSPNotificationID.reportMgrSrvClear, (data: lsp.URI | lsp.URI[]) => { + manager.clearWorkspacesReport(data); + }); + + // 监听请求:获取指定工作区的代码扫描报告元数据 + connection.onRequest( + reqTypes.LSPRequestID.reportMgrGetWorkspaceMeta, + (req: reqTypes.ReportMgrGetWorkspaceMetaRequest) => { + return { + reportMeta: manager._reportManager.getReportMeta(req.workspaceUri), + }; + }, + ); + // 监听文档:内容修改变化 documents.onDidChangeContent((e) => { if (manager._currDocument !== e.document) { @@ -115,6 +136,14 @@ export class ReportManagerServer { manager.refreshDiagnostics(e.document); }); + documents.onDidSave((e) => { + if (manager._currDocument !== e.document) { + manager._currDocument = e.document; + logger.debug("documents.onDidSave: ".concat(e.document.uri)); + } + manager.refreshDiagnostics(e.document); + }); + // 加载已有 Workspace 下缓存的报告 connection.workspace.getWorkspaceFolders().then((workspaces) => { workspaces?.forEach((workspace) => { @@ -122,6 +151,72 @@ export class ReportManagerServer { }); manager.refreshDiagnostics(); }); + + connection.onInitialize((params) => { + return { + capabilities: { + textDocumentSync: TextDocumentSyncKind.Full, + codeActionProvider: { + codeActionKinds: [CodeActionKind.QuickFix], + }, + }, + }; + }); + // 监听 CodeAction + connection.onCodeAction((params) => { + const actions: CodeAction[] = []; + for (const diagnostic of params.context.diagnostics) { + const problem = manager._reportManager.getReportProblem( + diagnostic, + params.textDocument.uri, + ); + if (problem === undefined) { + logger.error("onCodeAction: can't find problem by diagnostic"); + continue; + } + if (problem.fixInfo === undefined) { + logger.info("onCodeAction: problem has no fix info"); + continue; + } + const fix = { + title: "RvScan", + kind: CodeActionKind.QuickFix, + diagnostics: [diagnostic], + edit: { + changes: { + [params.textDocument.uri]: [ + { + range: { + start: { + line: problem.fixInfo.fixRange.lineFrom - 1, + character: problem.fixInfo.fixRange.colFrom, + }, + end: { + line: problem.fixInfo.fixRange.lineUpto! - 1, + character: problem.fixInfo.fixRange.colUpto, + }, + }, + newText: problem.fixInfo.fixContent, + }, + ], + }, + command: { + title: "RvScan", + command: "refreshDiagnostics", + arguments: [params.textDocument.uri], + }, + }, + }; + actions.push(fix); + } + return actions; + }); + + connection.onRequest("refreshDiagnostics", (uri: string) => { + // 重新发送原来的诊断信息 + manager.refreshDiagnostics(manager._documents.get(uri)); + }); + return manager; } @@ -167,33 +262,33 @@ export class ReportManagerServer { */ public onLoadNotification(data: ReportMgrLoadParams) { logger.info( - strFormat("Loading into workspace folder [{0}]: {1}", data.workspaceUri, data.reportUri) + strFormat("Loading into workspace folder [{0}]: {1}", data.workspaceUri, data.reportUri), ); // 检查当前是否已有报告 if (!data.reloadConfirm && this._reportManager.getReport(data.workspaceUri)) { // 工作区已有报告,通知客户端确认重新载入报告 logger.info("onLoadNotification: already has report data, asking for reload confirm"); - this._connection.sendNotification(LSPNotificationID.reportMgrReloadConfirm, data); + this._connection.sendNotification(LSPNotificationID.reportMgrCliReloadConfirm, data); return; } // 读取报告 const res = this._reportManager.loadReport(data); if (ReportManager.isReport(res)) { // 通知客户端读取完成 - this._connection.sendNotification(LSPNotificationID.reportMgrLoadFinished, res.timestamp); + this._connection.sendNotification(LSPNotificationID.reportMgrCliLoadFinished, res.timestamp); // 刷新诊断信息 this.refreshDiagnostics(); } else if (res.reason === "saveCacheError") { // 通知客户端读取完成,但缓存出错 - this._connection.sendNotification(LSPNotificationID.reportMgrLoadFinishedWithSaveError); + this._connection.sendNotification(LSPNotificationID.reportMgrCliLoadFinishedWithSaveError); // 刷新诊断信息 this.refreshDiagnostics(); } else { logger.error( - strFormat("onLoadNotification: Load failed ({0}): {1}", res.reason, data.reportUri) + strFormat("onLoadNotification: Load failed ({0}): {1}", res.reason, data.reportUri), ); - this._connection.sendNotification(LSPNotificationID.reportMgrLoadError, res); + this._connection.sendNotification(LSPNotificationID.reportMgrCliLoadError, res); } } @@ -214,8 +309,8 @@ export class ReportManagerServer { strFormat( "onDidChangeWorkspaceFolders: added {0}, removed {0} workspace folders", addCnt.toString(), - remCnt.toString() - ) + remCnt.toString(), + ), ); } @@ -229,10 +324,10 @@ export class ReportManagerServer { if (res && !ReportManager.isReport(res)) { if (res.reason === "saveCacheError") { // 加载缓存的报告时无法写回,弹警告窗 - this._connection.sendNotification(LSPNotificationID.reportMgrLoadFinishedWithSaveError); + this._connection.sendNotification(LSPNotificationID.reportMgrCliLoadFinishedWithSaveError); } else if (res.reason !== "fileNotExists") { // 加载缓存的报告时出现文件不存在以外的错误,弹窗报错 - this._connection.sendNotification(LSPNotificationID.reportMgrLoadError, res); + this._connection.sendNotification(LSPNotificationID.reportMgrCliLoadError, res); } } } @@ -245,9 +340,9 @@ export class ReportManagerServer { public onSaveReport(data: ReportMgrSaveParams) { const res = this._reportManager.saveReport(data); if (res) { - this._connection.sendNotification(LSPNotificationID.reportMgrSaveError, res); + this._connection.sendNotification(LSPNotificationID.reportMgrCliSaveError, res); } else { - this._connection.sendNotification(LSPNotificationID.reportMgrSaveFinished, data); + this._connection.sendNotification(LSPNotificationID.reportMgrCliSaveFinished, data); } } @@ -267,11 +362,11 @@ export class ReportManagerServer { } }); if (failedArr.length > 0) { - this._connection.sendNotification(LSPNotificationID.reportMgrSaveError, failedArr); + this._connection.sendNotification(LSPNotificationID.reportMgrCliSaveError, failedArr); } else if (workspaces && workspaces.length > 0) { this._connection.sendNotification( - LSPNotificationID.reportMgrSaveCacheAllFinished, - workspaces.length + LSPNotificationID.reportMgrCliSaveCacheAllFinished, + workspaces.length, ); } }); @@ -282,23 +377,56 @@ export class ReportManagerServer { * * @param workspace 工作区路径 */ - public unloadWorkspacesReport(workspace: lsp.WorkspaceFolder | lsp.WorkspaceFolder[]) { - let workspaces: lsp.WorkspaceFolder[] = []; - const failedArr: lsp.WorkspaceFolder[] = []; + public unloadWorkspacesReport( + workspace: lsp.WorkspaceFolder | lsp.WorkspaceFolder[] | lsp.URI | lsp.URI[], + ) { + let workspaces: lsp.URI[] = []; + const failedArr: lsp.URI[] = []; if (Array.isArray(workspace)) { - workspaces.concat(workspace); + workspaces = workspace.map((w) => (lsp.URI.is(w) ? w : w.uri)); } else { - workspaces.push(workspace); + workspaces.push(lsp.URI.is(workspace) ? workspace : workspace.uri); } for (let folder of workspaces) { - const res = this._reportManager.unloadReport(folder.uri.toString()); + const res = this._reportManager.unloadReport(folder.toString()); if (res) { failedArr.push(folder); } } if (failedArr.length > 0) { - this._connection.sendNotification(LSPNotificationID.reportMgrSaveError, failedArr); + this._connection.sendNotification(LSPNotificationID.reportMgrCliSaveError, failedArr); + } + // 刷新诊断,并通知客户端报告已卸载 + this.refreshDiagnostics(); + this._connection.sendNotification(LSPNotificationID.reportMgrCliUnloadFinished); + return failedArr.length; + } + + /** + * 清除指定工作区的报告数据 + * + * @param workspace 工作区路径 + */ + public clearWorkspacesReport( + workspace: lsp.WorkspaceFolder | lsp.WorkspaceFolder[] | lsp.URI | lsp.URI[], + ) { + let workspaces: lsp.URI[] = []; + const failedArr: lsp.URI[] = []; + if (Array.isArray(workspace)) { + workspaces = workspace.map((w) => (lsp.URI.is(w) ? w : w.uri)); + } else { + workspaces.push(lsp.URI.is(workspace) ? workspace : workspace.uri); + } + for (let folder of workspaces) { + try { + this._reportManager.clearReport(folder.toString()); + } catch (e) { + failedArr.push(folder); + } } + // 刷新诊断,并通知客户端报告已卸载 + this.refreshDiagnostics(); + this._connection.sendNotification(LSPNotificationID.reportMgrCliUnloadFinished); return failedArr.length; } @@ -310,7 +438,7 @@ export class ReportManagerServer { const docUris = this._documents.all(); if (docUris.length > 0) { logger.info( - strFormat("refreshDiagnostics: refreshing on all {0} files", docUris.length.toString()) + strFormat("refreshDiagnostics: refreshing on all {0} files", docUris.length.toString()), ); docUris.forEach((doc) => this.refreshDiagnostics(doc)); } @@ -319,6 +447,8 @@ export class ReportManagerServer { const docUri = textDocument.uri; const reportMeta = this._reportManager.getReportMeta(docUri); if (!reportMeta) { + // 清空当前所有报告 + this._reportManager.clearReport(docUri); return; } const settings = @@ -330,7 +460,8 @@ export class ReportManagerServer { this._clientCapabilities.hasDiagnosticRelatedInformationCapability, settings, textDocument, - reportMeta + reportMeta, + this._reportManager, ); } } diff --git a/server/src/reportToDiagnostic.ts b/server/src/reportToDiagnostic.ts index 25fe5c682ce2c41c08555a966f251b75031ffe66..df066782e693c4a1a5c68126a68c8c61f61b6add 100644 --- a/server/src/reportToDiagnostic.ts +++ b/server/src/reportToDiagnostic.ts @@ -19,11 +19,14 @@ import * as lsp from "vscode-languageserver"; import * as TextDoc from "vscode-languageserver-textdocument"; +import { URI } from "vscode-uri"; import { CommandID } from "../../common/src/types/command"; -import { LSPRequestID } from "../../common/src/types/request"; -import { ReportMeta } from "./types/reportMeta"; import { RVCodingAsstConfig } from "../../common/src/types/extConfig"; -import { URI } from "vscode-uri"; +import { IProblemState, SourceRange } from "../../common/src/types/report"; +import { ReportMeta } from "../../common/src/types/reportMeta"; +import { LSPRequestID } from "../../common/src/types/request"; +import { compareFileWithCommit } from "./compareWithCommit"; +import { ReportManager } from "./reportManager"; import path = require("path"); interface RuleInfo { @@ -39,12 +42,65 @@ export interface DiagnosticCodeExternal { export type DiagnosticCode = string | number | DiagnosticCodeExternal | undefined; +function findLowestValue(map: Map, key: number): number { + let lowestKey = 0; + + for (let k of map.keys()) { + if (k <= key && k > lowestKey) { + lowestKey = k; + } + } + return map.get(lowestKey) ?? 0; +} + +function calculateNewSourceRange( + srcRange: SourceRange, + changes: [Map, Set, Map>], +): SourceRange { + const [lineOffset, deletedLines, colOffset] = changes; + let originalLineFrom = srcRange.lineFrom; + let originalLineTo = srcRange.lineUpto; + const newSrcRange = { ...srcRange }; + + if (originalLineFrom in deletedLines) { + while (originalLineFrom in deletedLines) { + originalLineFrom--; + } + const newLineFrom = originalLineFrom + findLowestValue(lineOffset, originalLineFrom); + newSrcRange.lineFrom = newLineFrom; + newSrcRange.colFrom = 9999999; + } else { + newSrcRange.lineFrom = originalLineFrom + findLowestValue(lineOffset, originalLineFrom); + if (srcRange.colFrom !== undefined) + if (colOffset.has(originalLineFrom)) + newSrcRange.colFrom = + srcRange.colFrom! + findLowestValue(colOffset.get(originalLineFrom)!, srcRange.colFrom!); + } + if (originalLineTo !== undefined) { + if (originalLineTo in deletedLines) { + while (originalLineTo in deletedLines) { + originalLineTo--; + } + const newLineUpto = originalLineTo + findLowestValue(lineOffset, originalLineTo); + newSrcRange.lineUpto = newLineUpto; + newSrcRange.colUpto = 9999999; + } else { + newSrcRange.lineUpto = originalLineTo + findLowestValue(lineOffset, originalLineTo); + if (srcRange.colUpto !== undefined && colOffset.has(originalLineTo)) + newSrcRange.colUpto = + srcRange.colUpto! + findLowestValue(colOffset.get(originalLineTo)!, srcRange.colUpto!); + } + } + return newSrcRange; +} + export async function refreshDocumentDiagnostics( connection: lsp.Connection, hasDiagRelInfoCapability: boolean, extConfig: RVCodingAsstConfig, document: TextDoc.TextDocument, - reportMeta: ReportMeta + reportMeta: ReportMeta, + reportManager: ReportManager, ) { const workspaceUri = reportMeta.workspaceUri; const docUri: URI = URI.parse(document.uri); @@ -52,6 +108,7 @@ export async function refreshDocumentDiagnostics( const workspaceRootPath = workspaceUri.fsPath; const problems = reportMeta.reportData.problems; + const diagProblems = []; // 所有诊断数据 const diags: lsp.Diagnostic[] = []; @@ -73,10 +130,24 @@ export async function refreshDocumentDiagnostics( // 对于源码级问题,problem.data 每一个元素视为一个诊断 for (let pbData of problem.data) { i++; - const srcRange = pbData.srcRange; - if (!srcRange || srcRange.hidden) { + const originalSrcRange = pbData.srcRange; + if (!originalSrcRange) { continue; } + + const changes = await compareFileWithCommit( + docUri.fsPath, + reportMeta.reportData.commitId, + workspaceUri.fsPath, + ); + + let srcRange = undefined; + if (!changes) { + srcRange = originalSrcRange; + } else { + srcRange = calculateNewSourceRange(originalSrcRange, changes); + } + const fileUri = URI.file(path.resolve(workspaceRootPath, srcRange.filePath)); if (fileUri.toString() !== docUri.toString()) { continue; @@ -99,8 +170,8 @@ export async function refreshDocumentDiagnostics( lsp.Position.create(srcRange.lineFrom - 1, srcRange.colFrom ? srcRange.colFrom : 0), lsp.Position.create( srcRange.lineUpto ? srcRange.lineUpto - 1 : srcRange.lineFrom - 1, - srcRange.colUpto ? srcRange.colUpto : 999999 - ) + srcRange.colUpto ? srcRange.colUpto : 999999, + ), ); if (mainDiag) { @@ -108,36 +179,51 @@ export async function refreshDocumentDiagnostics( lsp.DiagnosticRelatedInformation.create( lsp.Location.create( URI.file(path.resolve(workspaceRootPath, srcRange.filePath)).toString(), - lspRange + lspRange, ), - srcRange.comment ? srcRange.comment : "See also:" - ) + srcRange.comment ? srcRange.comment : "See also:", + ), ); } else if (i === 1) { + let desc = ruleInfo ? ruleInfo.desc : ""; + if (desc.length > 0 && pbData.desc && pbData.desc.length > 0) { + desc += ": "; + } + desc += pbData.desc; + + let stateMsg = "[无状态]"; + if (problem.state === IProblemState.todo) stateMsg = "[💥未解决]"; + else if (problem.state === IProblemState.modified) stateMsg = "[❓已修改]"; + else if (problem.state === IProblemState.done) stateMsg = "[✅已解决]"; + + desc = stateMsg + " " + desc; mainDiag = lsp.Diagnostic.create( lspRange, - ruleInfo ? ruleInfo.desc : pbData.desc, + desc, srcRange.level ? srcRange.level : problem.level, ({ target: "vscode://tcse-iscas.rvportingtool/".concat( CommandID.wikiHelperOpenRule, "?", - problem.ruleId + problem.ruleId, ), value: problem.ruleId, }) as string, problem.checkerId, - [] + [], ); + diagProblems.push(problem); } } if (mainDiag) { diags.push(mainDiag); } } - await connection.sendDiagnostics({ - uri: docUri.toString(), - version: reportMeta.reportData.version, - diagnostics: diags, - }); + reportManager.addDiagnostics( + connection, + diags, + diagProblems, + docUri.toString(), + reportMeta.reportData.version, + ); } diff --git a/server/src/reportTransformer.ts b/server/src/reportTransformer.ts index 9397b112c20b5c29b4436ab867aa71012169167e..60647931d7e36ea3726a7de64e97d0fcc2a52368 100644 --- a/server/src/reportTransformer.ts +++ b/server/src/reportTransformer.ts @@ -17,13 +17,12 @@ * Last Change: Sep 6, 2024 **************************************************************************************/ -import * as LSPTypes from "vscode-languageserver-types"; import * as TextDoc from "vscode-languageserver-textdocument"; +import * as LSPTypes from "vscode-languageserver-types"; +import { ReportMeta } from "../../common/src/types/reportMeta"; +import { SourceRangeUtils } from "../../common/src/utils/sourceRangeUtils"; import { DocumentsCacheManager } from "./docCacheManager"; -import { ReportMeta } from "./types/reportMeta"; import { ServerLogger } from "./utils/log"; -import { SourceRange } from "../../common/src/types/report"; -import { SourceRangeUtils } from "../../common/src/utils/sourceRangeUtils"; export interface TextDocChangeParams { document: TextDoc.TextDocument; @@ -34,7 +33,7 @@ const logger = ServerLogger.getLogger("reportTransformer"); export function updateReportByTextDocumentChange( reportMeta: ReportMeta, - params: TextDocChangeParams + params: TextDocChangeParams, ) { const docUri = params.document.uri.toString(); diff --git a/server/src/server.ts b/server/src/server.ts index 101254b96f13d9997f05cf93791f2d4cec6ed069..e9dc0b00020c26e3c13475fdf5e68ca62621c6c0 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -17,14 +17,14 @@ * Last Change: Sep 6, 2024 **************************************************************************************/ +import { TextDocument } from "vscode-languageserver-textdocument"; import * as lsp from "vscode-languageserver/node"; -import { ClientCapabilities } from "./types/clientCapabilities"; +import { RVCodingAsstConfig } from "../../common/src/types/extConfig"; import { DocumentsCacheManager } from "./docCacheManager"; import { DocumentsSettingManager } from "./docSettingManager"; import { ReportManagerServer } from "./reportManagerServer"; -import { RVCodingAsstConfig } from "../../common/src/types/extConfig"; +import { ClientCapabilities } from "./types/clientCapabilities"; import { ServerLogger } from "./utils/log"; -import { TextDocument } from "vscode-languageserver-textdocument"; // Language Server 与客户端的全局连接 const connection = lsp.createConnection(lsp.ProposedFeatures.all); @@ -69,6 +69,7 @@ connection.onInitialize((params: lsp.InitializeParams) => { // completionProvider: { // resolveProvider: true, // }, + codeActionProvider: true, }, }; if (clientCapabilities.hasWorkspaceFolderCapability) { diff --git a/server/src/types/reportMeta.ts b/server/src/types/reportMeta.ts index 3404c6ca0bf854047f280913356e94aaa78ee1a2..1209c8a55b17decb760caba7f3dbd800ff720094 100644 --- a/server/src/types/reportMeta.ts +++ b/server/src/types/reportMeta.ts @@ -17,8 +17,8 @@ * Last Change: Sep 6, 2024 **************************************************************************************/ -import { IReport } from "../../../common/src/types/report"; import { URI } from "vscode-uri"; +import { IReport } from "../../../common/src/types/report"; /** 代码扫描报告元数据类 */ diff --git a/server/tsconfig.json b/server/tsconfig.json index 92bb76733caa6e68ab95d691c3163a6fe06719ac..ed98fdc8c11f372f6cf5cf78dc4052b64ae9b88d 100644 --- a/server/tsconfig.json +++ b/server/tsconfig.json @@ -4,13 +4,13 @@ "module": "commonjs", "target": "es2020", "lib": ["es2020"], - "outDir": "out", + "outDir": "../out", "rootDir": "..", "sourceMap": true, "strict": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true }, - "include": ["src", "../common/src"], + "include": ["./src", "../common/src"], "exclude": ["node_modules", ".vscode-test"] } diff --git a/testRoot/.gitignore b/testRoot/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..8feace68e4ed1a48e7f12b875d561b4c1bc8a0d9 --- /dev/null +++ b/testRoot/.gitignore @@ -0,0 +1 @@ +rvCodingAsst_report.json \ No newline at end of file diff --git a/testRoot/.vscode/settings.json b/testRoot/.vscode/settings.json index a8c9f23ad7d6388315eac6a3a17179230831ff66..4fbd1b89b31c0477f5d1e4a3be3c78d6a40ab7e9 100644 --- a/testRoot/.vscode/settings.json +++ b/testRoot/.vscode/settings.json @@ -1,4 +1,5 @@ { "rvportingtool.logLevel": "verbose", - "rvportingtool.trace.server": "verbose" + "rvportingtool.trace.server": "verbose", + "C_Cpp.errorSquiggles": "disabled" } diff --git a/testRoot/example-hint.json b/testRoot/example-hint.json new file mode 100644 index 0000000000000000000000000000000000000000..03ebe3d7668a49913734e29d10a471a6ea1ead85 --- /dev/null +++ b/testRoot/example-hint.json @@ -0,0 +1,366 @@ +{ + "version": 1, + "timestamp": 1725170530000, + "problems": [ + { + "id": "000001", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0003", + "level": 4, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 7, + "colFrom": 12, + "lineUpto": 7, + "colUpto": 20, + "comment": "__i386__" + } + } + ] + }, + { + "id": "000002", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0003", + "level": 4, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 7, + "colFrom": 32, + "lineUpto": 7, + "colUpto": 42, + "comment": "__x86_64__" + } + } + ] + }, + { + "id": "000003", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0003", + "level": 4, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 7, + "colFrom": 54, + "lineUpto": 7, + "colUpto": 60, + "comment": "__i386" + } + } + ] + }, + { + "id": "000004", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0003", + "level": 4, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 8, + "colFrom": 12, + "lineUpto": 8, + "colUpto": 20, + "comment": "__x86_64" + } + } + ] + }, + { + "id": "000005", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0003", + "level": 4, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 8, + "colFrom": 32, + "lineUpto": 8, + "colUpto": 39, + "comment": "_M_IX86" + } + } + ] + }, + { + "id": "000006", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0003", + "level": 4, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 8, + "colFrom": 51, + "lineUpto": 8, + "colUpto": 59, + "comment": "_M_IX86" + } + } + ] + }, + { + "id": "000007", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0003", + "level": 4, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 9, + "colFrom": 10, + "lineUpto": 9, + "colUpto": 22, + "comment": "RETURN_INSTR" + } + }, + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 7, + "colFrom": 12, + "lineUpto": 7, + "colUpto": 20, + "comment": "在 X86 架构特有宏下定义: __i386__" + } + }, + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 7, + "colFrom": 32, + "lineUpto": 7, + "colUpto": 42, + "comment": "在 X86 架构特有宏下定义: __x86_64__" + } + }, + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 7, + "colFrom": 54, + "lineUpto": 7, + "colUpto": 60, + "comment": "在 X86 架构特有宏下定义: __i386" + } + }, + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 8, + "colFrom": 12, + "lineUpto": 8, + "colUpto": 20, + "comment": "在 X86 架构特有宏下定义: __x86_64" + } + }, + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 8, + "colFrom": 32, + "lineUpto": 8, + "colUpto": 39, + "comment": "在 X86 架构特有宏下定义: _M_IX86" + } + }, + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 8, + "colFrom": 51, + "lineUpto": 8, + "colUpto": 59, + "comment": "在 X86 架构特有宏下定义: _M_IX86" + } + } + ] + }, + { + "id": "000008", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0001", + "level": 4, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 11, + "colFrom": 14, + "lineUpto": 11, + "colUpto": 21, + "comment": "__arm__" + } + } + ] + }, + { + "id": "000009", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0001", + "level": 4, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 11, + "colFrom": 33, + "lineUpto": 11, + "colUpto": 39, + "comment": "_M_ARM" + } + } + ] + }, + { + "id": "000010", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0002", + "level": 4, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 12, + "colFrom": 10, + "lineUpto": 12, + "colUpto": 22, + "comment": "_M_ARM" + } + }, + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 11, + "colFrom": 14, + "lineUpto": 11, + "colUpto": 21, + "comment": "在 ARM 架构特有宏下定义: __arm__" + } + }, + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 11, + "colFrom": 33, + "lineUpto": 11, + "colUpto": 39, + "comment": "在 ARM 架构特有宏下定义: _M_ARM" + } + } + ] + }, + { + "id": "000011", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0008", + "level": 2, + "data": [ + { + "path": "example2.c", + "desc": "缺少针对 RISC-V 架构的分支条件", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 14, + "colFrom": 0, + "lineUpto": 14, + "colUpto": 6, + "comment": "缺少针对 RISC-V 架构的分支条件" + } + } + ] + }, + { + "id": "000012", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0005", + "level": 1, + "data": [ + { + "path": "example2.c", + "desc": "未受架构特有宏保护的内联汇编代码", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 18, + "colFrom": 0, + "lineUpto": 22, + "colUpto": 37, + "comment": "未受架构特有宏保护的内联汇编代码" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/testRoot/example2.c b/testRoot/example2.c new file mode 100644 index 0000000000000000000000000000000000000000..b65b9ad00a53b0e05aa01b8a23f305628b2e08b0 --- /dev/null +++ b/testRoot/example2.c @@ -0,0 +1,24 @@ +/* This program assumes that a whole number of return instructions fit into + * 32 bits, and that 32-bit alignment is sufficient for a branch destination. + * For architectures where this is not true, fiddling with RETURN_INSTR_TYPE + * can be enough. + */ + +#if defined __i38Changes6__ || defined __x86_64__ || defined __i386 || \ + defined __x86_64 || defined _M_IX86 || defined _M_AMD64 +# define RETURN_INSTR 0xC3C3C3C3 /* ret; ret; ret; ret */ + +#elif defined __arm__ || defined _M_ARM +# define RETURN_INSTR 0xE12FFF1E /* bx lr */ + +#endif + +// Macro `TEST_MACRO` is architecture-irrelevant +#ifndef TEST_MACRO +asm ("mov eax, 1"); +__asm ( "mov ebx, 0ffh" ); +__asm__ volatile ("mov eax, 5\n" + "add eax, 6\n" + "mov result, eax"); +#endif + diff --git a/testRoot/example2.json b/testRoot/example2.json new file mode 100644 index 0000000000000000000000000000000000000000..af21bd0d24a10b08f915c119c4bfca4e7612c942 --- /dev/null +++ b/testRoot/example2.json @@ -0,0 +1,377 @@ +{ + "version": 1, + "timestamp": 1725170530000, + "commitId": "cc8bfe6e407e01f274a82604f2647e70d28f4768", + "problems": [ + { + "id": "000001", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0003", + "level": 3, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 7, + "colFrom": 12, + "lineUpto": 7, + "colUpto": 20, + "comment": "__i386__" + } + } + ] + }, + { + "id": "000002", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0003", + "level": 3, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 7, + "colFrom": 32, + "lineUpto": 7, + "colUpto": 42, + "comment": "__x86_64__" + } + } + ] + }, + { + "id": "000003", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0003", + "level": 3, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 7, + "colFrom": 54, + "lineUpto": 7, + "colUpto": 60, + "comment": "__i386" + } + } + ] + }, + { + "id": "000004", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0003", + "level": 3, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 8, + "colFrom": 12, + "lineUpto": 8, + "colUpto": 20, + "comment": "__x86_64" + } + } + ] + }, + { + "id": "000005", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0003", + "level": 3, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 8, + "colFrom": 32, + "lineUpto": 8, + "colUpto": 39, + "comment": "_M_IX86" + } + } + ] + }, + { + "id": "000006", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0003", + "level": 3, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 8, + "colFrom": 51, + "lineUpto": 8, + "colUpto": 59, + "comment": "_M_IX86" + } + } + ] + }, + { + "id": "000007", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0003", + "level": 3, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 9, + "colFrom": 10, + "lineUpto": 9, + "colUpto": 22, + "comment": "RETURN_INSTR" + } + }, + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 7, + "colFrom": 12, + "lineUpto": 7, + "colUpto": 20, + "comment": "在 X86 架构特有宏下定义: __i386__" + } + }, + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 7, + "colFrom": 32, + "lineUpto": 7, + "colUpto": 42, + "comment": "在 X86 架构特有宏下定义: __x86_64__" + } + }, + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 7, + "colFrom": 54, + "lineUpto": 7, + "colUpto": 60, + "comment": "在 X86 架构特有宏下定义: __i386" + } + }, + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 8, + "colFrom": 12, + "lineUpto": 8, + "colUpto": 20, + "comment": "在 X86 架构特有宏下定义: __x86_64" + } + }, + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 8, + "colFrom": 32, + "lineUpto": 8, + "colUpto": 39, + "comment": "在 X86 架构特有宏下定义: _M_IX86" + } + }, + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 8, + "colFrom": 51, + "lineUpto": 8, + "colUpto": 59, + "comment": "在 X86 架构特有宏下定义: _M_IX86" + } + } + ] + }, + { + "id": "000008", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0001", + "level": 3, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 11, + "colFrom": 14, + "lineUpto": 11, + "colUpto": 21, + "comment": "__arm__" + } + } + ] + }, + { + "id": "000009", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0001", + "level": 3, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 11, + "colFrom": 33, + "lineUpto": 11, + "colUpto": 39, + "comment": "_M_ARM" + } + } + ] + }, + { + "id": "000010", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0002", + "level": 3, + "data": [ + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 12, + "colFrom": 10, + "lineUpto": 12, + "colUpto": 22, + "comment": "_M_ARM" + } + }, + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 11, + "colFrom": 14, + "lineUpto": 11, + "colUpto": 21, + "comment": "在 ARM 架构特有宏下定义: __arm__" + } + }, + { + "path": "example2.c", + "desc": "", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 11, + "colFrom": 33, + "lineUpto": 11, + "colUpto": 39, + "comment": "在 ARM 架构特有宏下定义: _M_ARM" + } + } + ] + }, + { + "id": "000011", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0008", + "level": 2, + "data": [ + { + "path": "example2.c", + "desc": "缺少针对 RISC-V 架构的分支条件", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 14, + "colFrom": 0, + "lineUpto": 14, + "colUpto": 6, + "comment": "缺少针对 RISC-V 架构的分支条件" + } + } + ] + }, + { + "id": "000012", + "state": 0, + "checkerId": "c_cxx", + "type": "source", + "ruleId": "CC-0005", + "level": 1, + "data": [ + { + "path": "example2.c", + "desc": "未受架构特有宏保护的内联汇编代码", + "srcRange": { + "filePath": "example2.c", + "lineFrom": 18, + "colFrom": 0, + "lineUpto": 22, + "colUpto": 37, + "comment": "未受架构特有宏保护的内联汇编代码" + } + } + ], + "fixInfo": { + "fixRange": { + "filePath": "example2.c", + "lineFrom": 18, + "colFrom": 0, + "lineUpto": 22, + "colUpto": 37 + }, + "fixContent": "FIXED CONTENT\nFIXED CONTENT\nFIXED CONTENT\nFIXED CONTENT\nFIXED CONTENT\nFIXED CONTENT\nFIXED CONTENT\nFIXED CONTENT\nFIXED CONTENT\nFIXED CONTENT\nFIXED CONTENT\nFIXED CONTENT\n" + } + } + ] +} \ No newline at end of file diff --git a/webview/src/sidebarView/index.ts b/webview/src/sidebarView/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..e6e2c7bebe6aeee63001f439abc3a79cfedc5a21 --- /dev/null +++ b/webview/src/sidebarView/index.ts @@ -0,0 +1,136 @@ +/*************************************************************************************** + * Copyright (c) 2023-2024 RVSmartPorting. All rights reserved. + * RVPortingTool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + **************************************************************************************/ + +/*************************************************************************************** + * Client Sidebar View WebView Script for RVPortingTool VSCode Extension + * + * Author: Lightning Rainstorm + * Last Change: Sep 11, 2024 + **************************************************************************************/ + +import * as viewTypes from "../../../common/src/types/sidebarView"; + +(() => { + const vscode = acquireVsCodeApi(); + + /** CSS Class 与对应的点击回调事件表 */ + const onClickMap: Map void> = new Map(); + + const initOnClickMap = () => { + // cmd-open-scm: 跳转到 SCM 插件界面 + onClickMap.set("cmd-open-scm", () => { + vscode.postMessage({ + type: "UserOpenSCMMsg", + }); + }); + + // cmd-import-report: 加载代码扫描报告 + onClickMap.set("cmd-import-report", () => { + vscode.postMessage({ + type: "UserImportReportMsg", + }); + }); + + // cmd-export-report: 导出代码扫描报告 + onClickMap.set("cmd-export-report", () => { + vscode.postMessage({ + type: "UserExportReportMsg", + }); + }); + + // cmd-unload-report: 卸载代码扫描报告 + onClickMap.set("cmd-unload-report", () => { + vscode.postMessage({ + type: "UserUnloadReportMsg", + }); + }); + + // cmd-clear-report: 清除代码扫描报告 + onClickMap.set("cmd-clear-report", () => { + vscode.postMessage({ + type: "UserClearReportMsg", + }); + }); + + // cmd-start-scan: 开始代码扫描 + onClickMap.set("cmd-start-scan", () => { + vscode.postMessage({ + type: "UserStartScanMsg", + }); + }); + }; + + const showUIElements = (clsNames: string[]) => { + for (const clsName of clsNames) { + for (const elem of document.getElementsByClassName(clsName)) { + elem.classList.remove("hidden"); + } + } + }; + + const hideUIElements = (clsNames: string[]) => { + for (const clsName of clsNames) { + for (const elem of document.getElementsByClassName(clsName)) { + elem.classList.add("hidden"); + } + } + }; + + // SidebarView 加载完毕,发送消息 + window.addEventListener("load", () => { + console.debug("SidebarView Initialized, state: ", JSON.stringify(vscode.getState())); + vscode.postMessage({ + type: "ViewLoadedMsg", + }); + }); + + // 全局消息响应 + window.addEventListener("message", (ev) => { + const message = ev.data; + console.info("SidebarView received message: ", message); + if (viewTypes.SidebarViewMsgUtil.isCodeOpenedRepoMsg(message)) { + // 已打开 SCM Repo + hideUIElements(["ui-no-repo"]); + showUIElements(["ui-has-repo"]); + return; + } + if (viewTypes.SidebarViewMsgUtil.isCodeClosedRepoMsg(message)) { + // 已关闭 SCM Repo + hideUIElements(["ui-has-repo"]); + showUIElements(["ui-no-repo"]); + return; + } + if (viewTypes.SidebarViewMsgUtil.isCodeNoReportMsg(message)) { + // 没有代码扫描报告 + hideUIElements(["ui-has-report"]); + showUIElements(["ui-no-report"]); + return; + } + if (viewTypes.SidebarViewMsgUtil.isCodeHasReportMsg(message)) { + // 有代码扫描报告 + hideUIElements(["ui-no-report"]); + showUIElements(["ui-has-report"]); + return; + } + }); + + // 注册所有点击回调事件 + initOnClickMap(); + for (const [clsName, onClick] of onClickMap) { + for (const elem of document.getElementsByClassName(clsName)) { + elem.addEventListener("click", () => { + console.debug(`Triggered onClick event: ${clsName}`); + onClick(); + }); + } + } +})(); diff --git a/webview/src/wikiView/initUI.ts b/webview/src/wikiView/initUI.ts index 5e933ede89222dc38b1b75a0d34a13baf5c27d50..a9047ef66692ebde6df07fcf3f274fafa4a20f76 100644 --- a/webview/src/wikiView/initUI.ts +++ b/webview/src/wikiView/initUI.ts @@ -18,8 +18,6 @@ **************************************************************************************/ import { - Checkbox, - DataGrid, provideVSCodeDesignSystem, vsCodeBadge, vsCodeButton, @@ -62,6 +60,6 @@ export function initUI() { vsCodeRadioGroup(), vsCodeTag(), vsCodeTextArea(), - vsCodeTextField() + vsCodeTextField(), ); } diff --git a/webview/src/wikiView/main.ts b/webview/src/wikiView/main.ts index 659d08d5aeae4477f7767170bfde172d799ef4f5..43a34844ea050069cd1ae91fe0181891749bf409 100644 --- a/webview/src/wikiView/main.ts +++ b/webview/src/wikiView/main.ts @@ -17,9 +17,9 @@ * Last Change: Sep 6, 2024 **************************************************************************************/ -import { initMDTransformer } from "./mdTransformer"; -import { initUI } from "./initUI"; import { WikiViewLoadedMsg } from "../../../common/src/types/wikiView"; +import { initUI } from "./initUI"; +import { initMDTransformer } from "./mdTransformer"; import { WikiViewState } from "./state"; const vscode = acquireVsCodeApi(); diff --git a/webview/tsconfig.json b/webview/tsconfig.json index c2857bd2ddc2fa351434dc1bbdd88c6ce8f826c7..d6bd23dbadd9c748a986edd0cc0db75b84bd6798 100644 --- a/webview/tsconfig.json +++ b/webview/tsconfig.json @@ -3,7 +3,7 @@ "composite": true, "target": "ES2020", "lib": ["ES2020", "DOM", "DOM.Iterable"], - "outDir": "out", + "outDir": "../out", "rootDir": "..", "sourceMap": true, "strict": true,