1/* 2* Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd. 3* Licensed under the Apache License, Version 2.0 (the "License"); 4* you may not use this file except in compliance with the License. 5* You may obtain a copy of the License at 6* 7* http://www.apache.org/licenses/LICENSE-2.0 8* 9* Unless required by applicable law or agreed to in writing, software 10* distributed under the License is distributed on an "AS IS" BASIS, 11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12* See the License for the specific language governing permissions and 13* limitations under the License. 14*/ 15 16// The module 'vscode' contains the VS Code extensibility API 17// Import the module and reference it with the alias vscode in your code below 18const vscode = require('vscode'); 19const fs = require('fs'); 20const re = require('./gen/tools/VsPluginRe'); 21const { VsPluginLog } = require('./gen/tools/VsPluginLog'); 22const { detectPlatform, readFile } = require('./gen/tools/VsPluginTool'); 23const path = require('path'); 24let exeFilePath = null; 25const dirCache = {}; 26let globalPanel = null; 27 28let importToolChain = false; 29let extensionIds = []; 30let nextPluginId = null; 31// this method is called when your extension is activated 32// your extension is activated the very first time the command is executed 33 34/** 35 * @param {vscode.ExtensionContext} context 36 */ 37function activate(context) { 38 // Use the console to output diagnostic information (console.log) and errors (console.error) 39 // This line of code will only be executed once when your extension is activated 40 console.log('Congratulations, your extension "ApiScan" is now active!'); 41 let disposable = register(context, 'api_scan'); 42 let disposableMenu = register(context, 'api_scan_menu'); 43 context.subscriptions.push(disposable); 44 context.subscriptions.push(disposableMenu); 45 let platform = detectPlatform(); 46 if (platform === 'win') { 47 exeFilePath = __dirname + '/search-win.exe'; 48 } else if (platform === 'mac') { 49 exeFilePath = __dirname + '/search-macos'; 50 } else if (platform === 'Linux') { 51 exeFilePath = __dirname + '/search-linux'; 52 } 53} 54 55function executorApiscan(name, genDir) { 56 if (genDir === '' || genDir === null || genDir === undefined) { 57 genDir = name; 58 } 59 let command = exeFilePath + ' -d ' + name + ' -o ' + genDir; 60 let exec = require('child_process').exec; 61 exec(command, function (error, stdout, stderr) { 62 VsPluginLog.logInfo('VsPlugin: stdout =' + stdout + ', stderr =' + stderr); 63 if (error || stdout.indexOf('errno') > 0) { 64 vscode.window.showErrorMessage('genError:' + ((error !== null && error !== undefined) ? 65 error : '') + stdout); 66 return VsPluginLog.logError('VsPlugin:' + error + stdout); 67 } 68 vscode.window.showInformationMessage('Api Scan Successfully'); 69 return ''; 70 }); 71} 72 73function exeFileExit() { 74 if (fs.existsSync(exeFilePath)) { 75 return true; 76 } 77 return false; 78} 79 80function register(context, command) { 81 let disposable = vscode.commands.registerCommand(command, function (uri, boolValue, items) { 82 // The code you place here will be executed every time your command is executed 83 // Display a message box to the user 84 globalPanel = vscode.window.createWebviewPanel( 85 'api_scan', // Identifies the type of WebView 86 'Api Scan', // Title of the panel displayed to the user 87 vscode.ViewColumn.Two, // Display the WebView panel in the form of new columns in the editor 88 { 89 enableScripts: true, // Enable or disable JS, default is Enable 90 retainContextWhenHidden: true, // Keep the WebView state when it is hidden to avoid being reset 91 } 92 ); 93 94 checkBoolval(boolValue, items); 95 96 globalPanel.webview.html = getWebviewContent(context, importToolChain); 97 let msg; 98 globalPanel.webview.onDidReceiveMessage(message => { 99 msg = message.msg; 100 if (msg === 'cancel') { 101 globalPanel.dispose(); 102 } 103 else if (msg === 'api_scan') { 104 checkReceiveMsg(message); 105 } else { 106 selectPath(globalPanel, message); 107 } 108 }, undefined, context.subscriptions); 109 // 路径有效性判断 110 if (uri.fsPath !== undefined) { 111 let fn = re.getFileInPath(uri.fsPath); 112 let tt = re.match('[a-zA-Z_0-9]', fn); 113 let result = { 114 msg: 'selectASFilePath', 115 path: tt ? uri.fsPath : '' 116 }; 117 globalPanel.webview.postMessage(result); 118 } 119 }); 120 return disposable; 121} 122 123function checkBoolval(boolValue, items) { 124 if (typeof (boolValue) === 'boolean' && Array.isArray(items)) { 125 if (boolValue === true) { 126 //遍历数组item,查看当前插件id是数组的第几个元素,并拿出下一个元素,并判断当前id是否是最后一个元素并做相应处理 127 getNextPlugin(items, boolValue); 128 } 129 } 130} 131 132function getNextPlugin(items, boolValue) { 133 let myExtensionId = 'kaihong.ApiScan'; 134 for (let i = 0; i < items.length; i++) { 135 if (myExtensionId === items[i] && (i === items.length - 1)) { 136 importToolChain = false; 137 } else if (myExtensionId === items[i] && (i !== items.length - 1)) { 138 importToolChain = boolValue; 139 nextPluginId = items[i + 1]; 140 } 141 extensionIds.push(items[i]); 142 } 143} 144 145function checkReceiveMsg(message) { 146 let name = message.fileNames; 147 let genDir = message.genDir; 148 let buttonName = message.buttonName; 149 name = re.replaceAll(name, ' ', ''); 150 if ('' === name) { 151 vscode.window.showErrorMessage('Please enter the path!'); 152 return; 153 } 154 if (exeFileExit()) { 155 executorApiscan(name, genDir); 156 if (buttonName === 'Next') { 157 startNextPlugin(); 158 } 159 } else { 160 vscode.window.showInformationMessage('Copy executable program to ' + __dirname); 161 } 162} 163 164/** 165* 获取插件执行命令 166*/ 167function nextPluginExeCommand(nextPluginId) { 168 if (nextPluginId === 'kaihong.ApiScan') { 169 return 'api_scan'; 170 } else if (nextPluginId === 'kaihong.gn-gen') { 171 return 'generate_gn'; 172 } else if (nextPluginId === 'kaihong.service-gen') { 173 return 'generate_service'; 174 } else if (nextPluginId === 'kaihong.ts-gen') { 175 return 'generate_ts'; 176 } else if (nextPluginId === 'kaihong.napi-gen') { 177 return 'generate_napi'; 178 } else { 179 return null; 180 } 181} 182 183/** 184* 执行完毕后开启工具链中下一个插件 185*/ 186function startNextPlugin() { 187 const extension = vscode.extensions.getExtension(nextPluginId); 188 if (extension) { 189 let startNextPlugin = nextPluginExeCommand(nextPluginId); 190 try { 191 vscode.commands.executeCommand(startNextPlugin, '', importToolChain, extensionIds); 192 } catch (error) { 193 console.error(error); 194 } 195 } 196} 197 198/** 199* 选择本地目录/文件夹 200*/ 201function selectPath(panel, message) { 202 const options = { 203 canSelectMany: false, //是否可以选择多个 204 canSelectFolders: true, //是否选择文件夹 205 defaultUri:vscode.Uri.file(message.filePath)//默认打开本地路径 206 }; 207 208 return vscode.window.showOpenDialog(options).then(fileUri => { 209 if (fileUri && fileUri[0]) { 210 console.log('Selected file: ' + fileUri[0].fsPath); 211 let filePath = ''; 212 for (let index = 0; index < fileUri.length; index++) { 213 filePath += fileUri[index].fsPath.concat(','); 214 } 215 let result = { 216 msg: message.msg, 217 path: filePath.length > 0 ? filePath.substring(0, filePath.length - 1) : filePath 218 }; 219 panel.webview.postMessage(result); 220 return fileUri[0].fsPath; 221 } else { 222 return ''; 223 } 224 }); 225} 226 227// this method is called when your extension is deactivated 228function deactivate() { } 229 230function getWebviewContent(context, importToolChain) { 231 let data = readFile(__dirname + '/vs_plugin_view.html'); 232 data = getWebViewContent(context, '/vs_plugin_view.html'); 233 let content = data.toString(); 234 if (importToolChain) { 235 content = content.replace('Ok', 'Next'); 236 } 237 return content; 238} 239 240function getWebViewContent(context, templatePath) { 241 const resourcePath = path.join(context.extensionPath, templatePath); 242 const dirPath = path.dirname(resourcePath); 243 let html = fs.readFileSync(resourcePath, 'utf-8'); 244 html = html.replace(/(<link.+?href="|<script.+?src="|<iframe.+?src="|<img.+?src=")(.+?)"/g, (m, $1, $2) => { 245 if ($2.indexOf('https://') < 0) { 246 return $1 + globalPanel.webview.asWebviewUri(vscode.Uri.file(path.resolve(dirPath, $2))) + '"'; 247 } else { 248 return $1 + $2 + '"'; 249 } 250 }); 251 return html; 252} 253 254module.exports = { 255 activate, 256 deactivate 257}; 258