• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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');
24var exeFilePath = null;
25var globalPanel = null;
26
27var importToolChain = false;
28var extensionIds = [];
29var nextPluginId = null;
30// this method is called when your extension is activated
31// your extension is activated the very first time the command is executed
32
33/**
34 * @param {vscode.ExtensionContext} context
35 */
36function activate(context) {
37	// Use the console to output diagnostic information (console.log) and errors (console.error)
38	// This line of code will only be executed once when your extension is activated
39	console.log('Congratulations, your extension "napi-gen" is now active!');
40	let disposable = register(context, 'generate_napi');
41	let disposableMenu = register(context, 'generate_napi_menu');
42	context.subscriptions.push(disposable);
43	context.subscriptions.push(disposableMenu);
44	var platform = detectPlatform();
45	if (platform == 'win') {
46		exeFilePath = __dirname + "/napi_generator-win.exe";
47	} else if (platform == 'mac') {
48		exeFilePath = __dirname + "/napi_generator-macos";
49	} else if (platform == 'Linux') {
50		exeFilePath = __dirname + "/napi_generator-linux";
51	}
52}
53
54function executor(name, genDir, mode,numberType, importIsCheck) {
55	var exec = require('child_process').exec;
56	exec(genCommand(name, genDir, mode,numberType, importIsCheck), function (error, stdout, stderr) {
57		VsPluginLog.logInfo('VsPlugin: stdout =' + stdout + ", stderr =" + stderr);
58		if (error || stdout.indexOf("success") < 0) {
59			vscode.window.showErrorMessage("genError:" + (error != null ? error : "") + stdout);
60			return VsPluginLog.logError("VsPlugin:" + error + stdout);
61		}
62		vscode.window.showInformationMessage("Generated successfully");
63	});
64}
65
66function genCommand(name, genDir, mode,numberType, importIsCheck) {
67	var genFileMode = mode == 0 ? " -f " : " -d ";
68	if (genDir == ""){
69		return exeFilePath + genFileMode + name;
70	}
71	return exeFilePath + genFileMode + name + " -o " + genDir + " -n " + numberType + " -i " + importIsCheck;
72}
73
74function exeFileExit() {
75	if (fs.existsSync(exeFilePath)) {
76		return true;
77	}
78	return false;
79}
80
81function register(context, command) {
82	let disposable = vscode.commands.registerCommand(command, function (uri, boolValue, items) {
83		// The code you place here will be executed every time your command is executed
84		// Display a message box to the user
85		globalPanel = vscode.window.createWebviewPanel(
86			'generate', // Identifies the type of WebView
87			'Generate Napi Frame', // Title of the panel displayed to the user
88			vscode.ViewColumn.Two, // Display the WebView panel in the form of new columns in the editor
89			{
90				enableScripts: true, // Enable or disable JS, default is Enable
91				retainContextWhenHidden: true, // Keep the WebView state when it is hidden to avoid being reset
92			}
93		);
94
95		if (typeof(boolValue) == 'boolean' && Array.isArray(items)) {
96			if (boolValue == true) {
97				//遍历数组item,查看当前插件id是数组的第几个元素,并拿出下一个元素,并判断当前id是否是最后一个元素并做相应处理
98				let myExtensionId = 'kaihong.napi-gen';
99				for (let i = 0; i < items.length; i++) {
100					if (myExtensionId == items[i] && (i == items.length - 1)) {
101						importToolChain = false;
102					} else if (myExtensionId == items[i] && (i != items.length - 1)) {
103						importToolChain = boolValue;
104						nextPluginId = items[i + 1];
105					}
106					extensionIds.push(items[i]);
107				}
108			}
109		}
110		globalPanel.webview.html = getWebviewContent(context, importToolChain);
111		let msg;
112		globalPanel.webview.onDidReceiveMessage(message => {
113			msg = message.msg;
114			if (msg == "cancel") {
115				globalPanel.dispose();
116			} else if(msg == "param") {
117				checkReceiveMsg(message);
118			} else {
119				selectPath(globalPanel, message);
120			}
121		}, undefined, context.subscriptions);
122		let fn = re.getFileInPath(uri.fsPath);
123		let tt = re.match("((@ohos\.)*[a-zA-Z_0-9]+.d.ts)", fn);
124		var result = {
125			msg: "selectInterPath",
126			path: tt ? uri.fsPath : ""
127			}
128	    globalPanel.webview.postMessage(result);
129	});
130	return disposable;
131}
132
133function checkReceiveMsg(message) {
134	let mode = message.mode;
135	let name = message.fileNames;
136	let genDir = message.genDir;
137	let numberType = message.numberType;
138	let importIsCheck = message.importIsCheck;
139	let buttonName = message.buttonName;
140	checkMode(name, genDir, mode, numberType, importIsCheck);
141	if (buttonName == 'Next') {
142		startNextPlugin();
143	}
144}
145
146/**
147* 获取插件执行命令
148*/
149function nextPluginExeCommand(nextPluginId) {
150    if (nextPluginId == "kaihong.ApiScan") {
151		return 'api_scan';
152	} else if (nextPluginId == "kaihong.gn-gen") {
153		return 'generate_gn';
154	} else if (nextPluginId == "kaihong.service-gen") {
155		return 'generate_service';
156	} else if (nextPluginId == "kaihong.ts-gen") {
157		return 'generate_ts';
158	} else if (nextPluginId == "kaihong.napi-gen") {
159		return 'generate_napi';
160	}
161	else {
162		return null;
163	}
164}
165
166/**
167* 执行完毕后开启工具链中下一个插件
168*/
169function startNextPlugin() {
170	const extension = vscode.extensions.getExtension(nextPluginId);
171	if (extension) {
172		let startNextPlugin = nextPluginExeCommand(nextPluginId);
173		try {
174			vscode.commands.executeCommand(startNextPlugin, '', importToolChain, extensionIds);
175		} catch (error) {
176			console.error(error)
177		}
178	}
179}
180
181/**
182* 选择本地目录/文件夹
183*/
184 function selectPath(panel, message) {
185	let msg = message.msg;
186	let mode = 1;
187	if (message.mode != undefined) {
188		mode = message.mode;
189	}
190	const options = {
191		canSelectMany: mode == 0 ? true : false,//是否可以选择多个
192		openLabel: mode == 0 ? '选择文件' : '选择文件夹',//打开选择的右下角按钮label
193		canSelectFiles: mode == 0 ? true : false,//是否选择文件
194		canSelectFolders: mode == 0 ? false : true,//是否选择文件夹
195		defaultUri:vscode.Uri.file(''),//默认打开本地路径
196		// 文件过滤选项,在文件夹选择模式下不可设置此配置,否则ubuntu系统下无法选择文件夹
197		filters: mode == 1 ? {} : { 'Text files': ['d.ts'] }
198
199	};
200
201	return vscode.window.showOpenDialog(options).then(fileUri => {
202	   if (fileUri && fileUri[0]) {
203		   console.log('Selected file: ' + fileUri[0].fsPath);
204		   let filePath = "";
205		   for (let index = 0; index < fileUri.length; index++) {
206				filePath += fileUri[index].fsPath.concat(",");
207		   }
208		   var result = {
209				msg: message.msg,
210				path: filePath.length > 0 ? filePath.substring(0, filePath.length - 1) : filePath
211				}
212		   panel.webview.postMessage(result);
213		   return fileUri[0].fsPath
214	   }
215   });
216}
217
218function checkMode(name, genDir, mode,numberType, importIsCheck) {
219	name = re.replaceAll(name, " ", "");
220	if ("" == name) {
221		vscode.window.showErrorMessage("Please enter the path!");
222		return;
223	}
224	if (mode == 0) {
225		if (name.indexOf(".") < 0) {
226			vscode.window.showErrorMessage("Please enter the correct file path!");
227			return;
228		}
229	} else {
230		if (name.indexOf(".") > 0 || !fs.lstatSync(name).isDirectory()) {
231			vscode.window.showErrorMessage("Please enter the correct folder folder!");
232			return;
233		}
234	}
235	if (exeFileExit()) {
236		executor(name, genDir, mode,numberType, importIsCheck);
237	} else {
238		vscode.window.showInformationMessage("Copy executable program to " + __dirname);
239	}
240}
241
242// this method is called when your extension is deactivated
243function deactivate() { }
244
245function getWebviewContent(context, importToolChain) {
246	let data = readFile(__dirname + '/vs_plugin_view.html');
247	data = getWebViewContent(context, '/vs_plugin_view.html');
248	let content = data.toString();
249	if (importToolChain) {
250		content = content.replace('Ok', 'Next');
251	}
252	return content;
253}
254
255function getWebViewContent(context, templatePath) {
256    const resourcePath = path.join(context.extensionPath, templatePath);
257    const dirPath = path.dirname(resourcePath);
258    let html = fs.readFileSync(resourcePath, 'utf-8');
259    html = html.replace(/(<link.+?href="|<script.+?src="|<iframe.+?src="|<img.+?src=")(.+?)"/g, (m, $1, $2) => {
260        if ($2.indexOf("https://") < 0) {
261            return $1 + globalPanel.webview.asWebviewUri(vscode.Uri.file(path.resolve(dirPath, $2))) + '"';
262        } else {
263            return $1 + $2+'"';
264        }
265    });
266    return html;
267}
268
269module.exports = {
270	activate,
271	deactivate
272}