diff --git a/OAT.xml b/OAT.xml
index 33d68ae9..21f1fb39 100644
--- a/OAT.xml
+++ b/OAT.xml
@@ -56,8 +56,8 @@ Note:If the text contains special characters, please escape them according to th
-
-
+
+
@@ -65,6 +65,7 @@ Note:If the text contains special characters, please escape them according to th
+
diff --git a/examples/napitutorials/tool/commandLine/docs/guide/INSTRUCTION_ZH.md b/examples/napitutorials/tool/commandLine/docs/guide/INSTRUCTION_ZH.md
index ea0c3ad5..a33b31c5 100644
--- a/examples/napitutorials/tool/commandLine/docs/guide/INSTRUCTION_ZH.md
+++ b/examples/napitutorials/tool/commandLine/docs/guide/INSTRUCTION_ZH.md
@@ -18,13 +18,27 @@ Native生成工具支持两种入口,分别是命令行、IntelliJ插件,使
2.在命令行使用 以下命令运行脚本
```
-node ./tool/commandLine/src/main.js 接口文件路径
+node ./tool/commandLine/src/main.js -f 接口文件路径
```
+其中,参数详情如下:
+
+-f, 待转换的.h文件;
+
+-t, 可选参数,工程目录下测试用例文件Ability.test.ets文件路径,默认路径为.h文件所在工程目录下的
+
+Ability.test.ets文件路径;
+
+-i, 可选参数,工程目录下ts声明文件index.s.ts文件路径,默认路径为.h文件所在工程目录下的
+
+index.d.ts文件路径;
+
+-o, 可选参数,工程目录下生成的.cpp文件所在文件夹路径,若该目录下不存在.cpp文件则会创建test.cpp文件,默认路径为.h所在工程目录./src/main/cpp路径下;
+
例如:
```
-node ./tool/commandLine/src/main.js E:\napi_generator_aboutTest\napi_240329\napi_generator\examples\napitutorials\entry\src\main\cpp\test.h
+node ./tool/commandLine/src/main.js -f E:\napi_generator_aboutTest\napi_240329\napi_generator\examples\napitutorials\entry\src\main\cpp\test.h
```
3.运行成功后命令行会打印出 Generate success,并在./entry/src/main/cpp会生成test.cpp文件,其中是接口napi层模板;在./entry/src/main/cpp/types/libentry/index.d.ts文件中会追加写入生成的ts接口;在./entrysrc/ohosTest/ets/test/Ability.test.ets生成接口测试代码模板。用户根据自身需求在test.cpp中增加业务代码,并在Ability.test.ets中增加合适断言之后,即可连接开发板并运行测试用例测试验证生成napi代码是否正确。例如:
@@ -38,7 +52,7 @@ res = value0 + value1;
在Ability.test.ets文件中增加断言:
```
-expect(result).assertEqual(2.3+3.2)
+expect(result).assertEqual(2+3)
```
连接开发板,运行Ability.test.ets中的测试用例:
diff --git a/examples/napitutorials/tool/commandLine/src/function.json b/examples/napitutorials/tool/commandLine/src/function.json
new file mode 100644
index 00000000..7aabaf2f
--- /dev/null
+++ b/examples/napitutorials/tool/commandLine/src/function.json
@@ -0,0 +1,35 @@
+{
+ "directFunction": {
+ "indexTemplete": "export const %s:(%s) => %s;\n",
+ "cppFuncTemplete": "#include \"napi/native_api.h\"\n[include_replace]\n\n[body_replace]\n\nEXTERN_C_START\nstatic napi_value Init(napi_env env, napi_value exports)\n{\n napi_property_descriptor desc[] = {\n [init_replace]\n};\nnapi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);\nreturn exports;\n}\nEXTERN_C_END\n\nstatic napi_module demoModule = {\n .nm_version = 1,\n .nm_flags = 0,\n .nm_filename = nullptr,\n .nm_register_func = Init,\n .nm_modname = \"entry\",\n .nm_priv = ((void*)0),\n .reserved = { 0 },\n};\n\nextern \"C\" __attribute__((constructor)) void RegisterEntryModule(void)\n{\n napi_module_register(&demoModule);\n}",
+ "cppFuncDetails": {
+ "funcInitTemplete": "{ \"%s\" , nullptr, %s, nullptr, nullptr, nullptr, napi_default, nullptr },",
+ "funcBodyTemplete": "static napi_value [funcName](napi_env env, napi_callback_info info)\n{\n[func_getParam_replace]\n [func_return_replace]\n }\n",
+ "funcGetParamTemplete" : "size_t requireArgc = [param_length];\n size_t argc = [param_length];\n napi_value args[[param_length]] = {nullptr};\n napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);\n [getParam_replace]\n ",
+ "funcReturnTemplete" : "[return_type_define]\n // Todo\n // eg. res = value0 + value1;\n napi_value result;\n [return_replace]\n return result;\n",
+ "paramGenTemplete": " napi_valuetype valuetype%s;\n napi_typeof(env, args[%s], &valuetype%s);\n %s value%s;\n [getParam_replace]",
+ "funcParamType": {
+ "int32_t": "napi_get_value_int32(env, args[%s], &value%s);\n",
+ "int64_t": "napi_get_value_int64(env, args[%s], &value%s);\n",
+ "uint32_t": "napi_get_value_uint32(env, args[%s], &value%s);\n",
+ "int": "",
+ "double": "napi_get_value_double(env, args[%s], &value%s);\n",
+ "bool": "napi_get_value_bool(env, args[%s], &value%s);\n",
+ "string": "char buf[1024];\n size_t results;\n napi_get_value_string_utf8(env, args[%s], buf, 1024, &results);\n value%s = buf;\n"
+ },
+ "funcReturnType": {
+ "int32_t": "napi_create_int32(env, res, &result);\n",
+ "int64_t": "napi_create_int64(env, res, &result);\n",
+ "uint32_t": "napi_create_uint32(env, res, &result);\n",
+ "int": "",
+ "size_t": "",
+ "double": "napi_create_double(env, res, &result);\n",
+ "bool": "napi_get_boolean(env, res, &result);\n",
+ "string": "napi_create_string_utf8(env, res, NAPI_AUTO_LENGTH, &result);\n"
+ }
+ },
+ "abilityTestTemplete": "it('assertContain_[random_number]', 0, () => {\n // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.\n hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');\n\n [func_direct_testCase]\n\n // Defines a variety of assertion methods, which are used to declare expected boolean conditions.\n // 断言 如:expect(result).assertEqual(2+3)\n })\n"
+ },
+ "asyncFunction": {
+ }
+}
\ No newline at end of file
diff --git a/examples/napitutorials/tool/commandLine/src/main.js b/examples/napitutorials/tool/commandLine/src/main.js
index 7975bd15..a08e87a8 100644
--- a/examples/napitutorials/tool/commandLine/src/main.js
+++ b/examples/napitutorials/tool/commandLine/src/main.js
@@ -14,11 +14,47 @@
*/
const fs = require('fs');
const path = require('path')
+const stdio = require("stdio");
const main = require("./TsGen/tsMain");
+let ops = stdio.getopt({
+ // 输入的.h文件路径,必填
+ 'filename': { key: 'f', args: 1, description: ".h file", default: "" },
+ // 可选参数,可设置默认值
+ 'testFilename': { key: 't', args: 1, description: "Ability.test.ets file", default: "" },
+ 'indexFilename': { key: 'i', args: 1, description: "index.d.ts file", default: "" },
+ 'outCppPath': { key: 'o', args: 1, description: ".cpp dir path", default: "" },
+});
+
// 获取命令行参数 .h文件路径
-const filePath = process.argv[2] || '';
-let out = './entry/src/main/cpp/types/libentry/'
+let filePath = ops.filename
+let testFilePath = ops.testFilename
+let tsFilePath = ops.indexFilename
+let cppFilePath = ops.outCppPath
+// 读取文件内容 判断参数是否为空
+if (filePath !== '') {
+ let fileDir = path.resolve(filePath, '..');
+ let indexFile = findIndexDTS(fileDir);
+ // 若用户没有提供路径 则程序提供默认路径
+ if (!tsFilePath) {
+ tsFilePath = indexFile
+ }
+ if (!testFilePath) {
+ let rootPath = path.resolve(indexFile, '..', '..', '..', '..', '..');
+ testFilePath = path.join(rootPath, 'ohosTest/ets/test/Ability.test.ets');
+ }
+ if(!cppFilePath) {
+ let rootPath = path.resolve(indexFile, '..', '..', '..');
+ cppFilePath = path.join(rootPath, 'test.cpp');
+ }
+
+ console.info("filePath: " + filePath)
+ console.info("testFilePath: " + testFilePath)
+ console.info("tsFilePath: " + tsFilePath)
+ console.info("cppFilePath: " + cppFilePath)
+ main.doGenerate(filePath, testFilePath, tsFilePath, cppFilePath);
+}
+
// 这个函数接收一个目录的绝对路径作为参数
function findIndexDTS(currentDir) {
@@ -47,12 +83,3 @@ function findIndexDTS(currentDir) {
console.log('index.d.ts not found in any checked directory.');
return null;
}
-
-// 读取文件内容
-if (filePath !== '') {
- let fileDir = path.resolve(filePath, '..');
- let out = findIndexDTS(fileDir);
- if (out !== null) {
- main.doGenerate(filePath, out);
- }
-}
diff --git a/examples/napitutorials/tool/commandLine/src/napiGen/functionDirect.js b/examples/napitutorials/tool/commandLine/src/napiGen/functionDirect.js
index 8c7158d5..810b00c1 100644
--- a/examples/napitutorials/tool/commandLine/src/napiGen/functionDirect.js
+++ b/examples/napitutorials/tool/commandLine/src/napiGen/functionDirect.js
@@ -12,66 +12,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-// const { paramGenerate } = require("./param_generate");
-// const { returnGenerate } = require("./return_generate");
+
const { NapiLog } = require("../tools/NapiLog");
const util = require('util');
-const path = require('path')
+const path = require('path');
+const fs = require("fs");
const { writeFile } = require("../tools/tool");
const re = require("../tools/re");
const LENGTH = 10;
const TWO_DECIMAL = 2;
-let cppTemplete = `
-#include "napi/native_api.h"
-[include_replace]
-static napi_value [funcName](napi_env env, napi_callback_info info)
-{
-[body_replace]
-}
-
-EXTERN_C_START
-static napi_value Init(napi_env env, napi_value exports)
-{
- napi_property_descriptor desc[] = {
- [init_replace]
-};
-napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
-return exports;
-}
-EXTERN_C_END
-
-static napi_module demoModule = {
- .nm_version = 1,
- .nm_flags = 0,
- .nm_filename = nullptr,
- .nm_register_func = Init,
- .nm_modname = "entry",
- .nm_priv = ((void*)0),
- .reserved = { 0 },
-};
-
-extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
-{
- napi_module_register(&demoModule);
-}`
-
-let bodyTemplete = `
- size_t requireArgc = [param_length];
- size_t argc = [param_length];
- napi_value args[[param_length]] = {nullptr};
- napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
- [getParme_replace]
- [return_type_define]
- // Todo
- // eg. res = value0 + value1;
- napi_value result;
- [return_replace]
- return result;
-`
-
-// 暂不考虑interface情况
-function generateDirectFunction(params, tsFuncName, indexPath) {
+function generateDirectFunction(params, tsFuncName, cppFilePath, directFuncJson) {
let funcInfo = {
"name": "",
"params": [],
@@ -83,16 +34,15 @@ function generateDirectFunction(params, tsFuncName, indexPath) {
for(let i in includes) {
includes_replace += util.format('#include %s\n', includes[i])
}
- // console.info("includes_replace: " + includes_replace)
// 获取注册的方法名字 (只读取了一个方法 当前只支持一个方法的转换)
funcInfo.name = params.functions[0].name
- let funcName_replace = funcInfo.name.substring(0,1).toUpperCase() + funcInfo.name.substring(1,funcInfo.name.length)
- // console.info("funcName_replace: " + funcName_replace)
+ let serialNum = tsFuncName.substring(0,6)
+ let funcName_replace = serialNum + funcInfo.name.substring(0,1).toUpperCase() + funcInfo.name.substring(1,funcInfo.name.length)
// 方法的注册
- let init_replace = util.format('{ "%s" , nullptr, %s, nullptr, nullptr, nullptr, napi_default, nullptr }', tsFuncName, funcName_replace)
- // console.info("init_replace: " + init_replace)
+ let initTemplete = directFuncJson.cppFuncDetails.funcInitTemplete
+ let init_replace = util.format(initTemplete, tsFuncName, funcName_replace)
// 分析方法
funcInfo.retType = params.functions[0].rtnType
@@ -101,76 +51,115 @@ function generateDirectFunction(params, tsFuncName, indexPath) {
let param = createParam(parseParams[i])
funcInfo.params.push(param)
}
+
// 生成
- let paramGenTemplete = `
- napi_valuetype valuetype%s;
- napi_typeof(env, args[%s], &valuetype%s);
- %s value%s;
- [getParam_replace]
- `
+ let paramGenTemplete = directFuncJson.cppFuncDetails.paramGenTemplete
+ let funcParamType = directFuncJson.cppFuncDetails.funcParamType
let paramGenResult = ''
// napi 获取参数
for(let i = 0; i < funcInfo.params.length; i++) {
- let paramGen = util.format(paramGenTemplete, i, i, i, funcInfo.params[i].type, i)
- if (funcInfo.params[i].type === 'double' || funcInfo.params[i].type === 'double_t' || funcInfo.params[i].type === 'float') {
- let getParam = util.format('napi_get_value_double(env, args[%s], &value%s);', i, i)
+ console.info("funcInfo.params[i].type.substring(0,10): " + funcInfo.params[i].type.substring(0,10))
+ let paramType = funcInfo.params[i].type === 'size_t'? 'int64_t': funcInfo.params[i].type
+ let paramGen = util.format(paramGenTemplete, i, i, i, paramType, i)
+ if (funcInfo.params[i].type === 'double') {
+ let getParam = util.format(funcParamType.double, i, i)
paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
paramGenResult += paramGen;
} else if (funcInfo.params[i].type === 'uint32_t') {
- let getParam = util.format('napi_get_value_uint32(env, args[%s], &value%s);', i, i)
+ let getParam = util.format(funcParamType.uint32_t, i, i)
paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
paramGenResult += paramGen;
} else if (funcInfo.params[i].type === 'int32_t') {
- let getParam = util.format('napi_get_value_int32(env, args[%s], &value%s);', i, i)
+ let getParam = util.format(funcParamType.int32_t, i, i)
paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
paramGenResult += paramGen;
- } else if (funcInfo.params[i].type === 'int64_t') {
- let getParam = util.format('napi_get_value_int64_t(env, args[%s], &value%s);', i, i)
+ } else if (funcInfo.params[i].type === 'int64_t' || funcInfo.params[i].type === 'size_t') {
+ let getParam = util.format(funcParamType.int64_t, i, i)
paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
paramGenResult += paramGen;
} else if (funcInfo.params[i].type === 'bool') {
- let getParam = util.format('napi_get_value_bool(env, args[%s], &value%s);', i, i)
+ let getParam = util.format(funcParamType.bool, i, i)
+ paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
+ paramGenResult += paramGen;
+ } else if (funcInfo.params[i].type === 'std::string' || funcInfo.params[i].type.substring(0,10) === 'const char') {
+ let getParam = util.format(funcParamType.string, i, i)
paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
paramGenResult += paramGen;
}
}
- // console.info("paramGenResult: " + paramGenResult)
// 返回值处理
let retGenResult = ''
+ let funcReturnType = directFuncJson.cppFuncDetails.funcReturnType
if (funcInfo.retType === 'uint32_t') {
- retGenResult = 'napi_create_uint32(env, res, &result);'
- } else if (funcInfo.retType === 'double' || funcInfo.retType === 'double_t' || funcInfo.retType === 'float') {
- retGenResult = 'napi_create_double(env, res, &result);'
+ retGenResult = funcReturnType.uint32_t
+ } else if (funcInfo.retType === 'double') {
+ retGenResult = funcReturnType.double
} else if (funcInfo.retType === 'int32_t') {
- retGenResult = 'napi_create_int32(env, res, &result);'
- } else if (funcInfo.retType === 'int64_t') {
- retGenResult = 'napi_create_int64(env, res, &result);'
+ retGenResult = funcReturnType.int32_t
+ } else if (funcInfo.retType === 'int64_t' || funcInfo.retType === 'size_t') {
+ retGenResult = funcReturnType.int64_t
} else if (funcInfo.retType === 'bool') {
- retGenResult = 'napi_get_boolean(env, res, &result);'
+ retGenResult = funcReturnType.bool
+ } else if (funcInfo.retType === 'std::string' || funcInfo.retType.substring(0,10) === 'const char') {
+ retGenResult = funcReturnType.string
}
- // console.info("retGenResult: " + retGenResult)
- let body_replace = replaceAll(bodyTemplete, '[param_length]', funcInfo.params.length)
- body_replace = replaceAll(body_replace, '[getParme_replace]', paramGenResult)
- if(funcInfo.retType !== 'void') {
- body_replace = replaceAll(body_replace, '[return_type_define]', funcInfo.retType + ' res;')
+ let bodyTemplete = directFuncJson.cppFuncDetails.funcBodyTemplete
+ let body_replace = replaceAll(bodyTemplete, '[funcName]', funcName_replace)
+ let funcGetParamTemplete = directFuncJson.cppFuncDetails.funcGetParamTemplete
+ let genParam_replace = replaceAll(funcGetParamTemplete, '[param_length]', funcInfo.params.length)
+ genParam_replace = replaceAll(genParam_replace, '[getParam_replace]', paramGenResult)
+ if (funcInfo.params.length !== 0) {
+ body_replace = replaceAll(body_replace, '[func_getParam_replace]', genParam_replace)
} else {
- body_replace = replaceAll(body_replace, '[return_type_define]', '')
+ body_replace = replaceAll(body_replace, '[func_getParam_replace]', '')
+ }
+ if(funcInfo.retType !== 'void') {
+ let returnType = funcInfo.retType === 'std::string'? 'const char *': funcInfo.retType
+ returnType = returnType === 'size_t'? 'int64_t': returnType
+ let funcReturnTemplete = directFuncJson.cppFuncDetails.funcReturnTemplete
+ let func_return_replace = replaceAll(funcReturnTemplete, '[return_type_define]', returnType + ' res;')
+ func_return_replace = replaceAll(func_return_replace, '[return_replace]', retGenResult)
+ body_replace = replaceAll(body_replace, '[func_return_replace]', func_return_replace)
+ } else {
+ body_replace = replaceAll(body_replace, '[func_return_replace]', '')
}
body_replace = replaceAll(body_replace, '[return_replace]', retGenResult)
- // console.info("body_replace: " + body_replace)
-
- let cppContent = replaceAll(cppTemplete, '[include_replace]', includes_replace)
- cppContent = replaceAll(cppContent, '[funcName]', funcName_replace)
- cppContent = replaceAll(cppContent, '[body_replace]', body_replace)
- cppContent = replaceAll(cppContent, '[init_replace]', init_replace)
- // console.info("Last cppContent: " + cppContent)
// 将内容写入cpp文件
- let rootPath = path.resolve(indexPath, '..', '..', '..');
- let cppFilePath = path.join(rootPath, 'test.cpp');
- // console.info("cppFilePath: " + cppFilePath)
- writeFile(cppFilePath, cppContent)
+ // 先判断cppFilePath是否存在,若存在则追加写入内容
+ if (fs.existsSync(cppFilePath)) {
+ // 读取cpp文件内容
+ const cppFileContent = fs.readFileSync(cppFilePath, 'utf8');
+ let includePosition = cppFileContent.indexOf('#include');
+ let includes = includes_replace.split('\n')
+ let newIncludes = ""
+ for (let i = 0; i < includes.length; i++) {
+ if (cppFileContent.indexOf(includes[i]) < 0) {
+ newIncludes += includes[i] + '\n'
+ }
+ }
+ let newCppFileContent = cppFileContent
+ if (newIncludes !== "") {
+ // 追加写入#include
+ newCppFileContent = newCppFileContent.slice(0, includePosition) + newIncludes + newCppFileContent.slice(includePosition);
+ }
+ // 追加写入方法体
+ let funcPosition = newCppFileContent.indexOf('EXTERN_C_START')
+ newCppFileContent = newCppFileContent.slice(0, funcPosition) + body_replace + newCppFileContent.slice(funcPosition);
+
+ // 追加写入 方法的初始化
+ let initPosition = newCppFileContent.indexOf('napi_property_descriptor desc[] = {') + 'napi_property_descriptor desc[] = {'.length;
+ newCppFileContent = newCppFileContent.slice(0, initPosition) + '\n ' + init_replace + newCppFileContent.slice(initPosition);
+ writeFile(cppFilePath, newCppFileContent)
+ } else {
+ let cppTemplete = directFuncJson.cppFuncTemplete
+ let cppContent = replaceAll(cppTemplete, '[include_replace]', includes_replace)
+ cppContent = replaceAll(cppContent, '[body_replace]', body_replace)
+ cppContent = replaceAll(cppContent, '[init_replace]', init_replace)
+ // 第一次生成
+ writeFile(cppFilePath, cppContent)
+ }
}
function replaceAll(s, sfrom, sto) {
diff --git a/examples/napitutorials/tool/commandLine/src/napiGen/functionDirectTest.js b/examples/napitutorials/tool/commandLine/src/napiGen/functionDirectTest.js
index 1ff1bef3..eb854329 100644
--- a/examples/napitutorials/tool/commandLine/src/napiGen/functionDirectTest.js
+++ b/examples/napitutorials/tool/commandLine/src/napiGen/functionDirectTest.js
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd.
+* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -16,51 +16,11 @@ const { NapiLog } = require("../tools/NapiLog");
const util = require('util');
const { writeFile, generateRandomInteger } = require("../tools/tool");
const path = require('path')
+const fs = require("fs");
const LENGTH = 10;
const TWO_DECIMAL = 2;
-
-let abilityTestTemplete = `
-import hilog from '@ohos.hilog';
-import testNapi from 'libentry.so';
-import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
-
-export default function abilityTest() {
- describe('ActsAbilityTest', () => {
- // Defines a test suite. Two parameters are supported: test suite name and test suite function.
- beforeAll(() => {
- // Presets an action, which is performed only once before all test cases of the test suite start.
- // This API supports only one parameter: preset action function.
- })
- beforeEach(() => {
- // Presets an action, which is performed before each unit test case starts.
- // The number of execution times is the same as the number of test cases defined by **it**.
- // This API supports only one parameter: preset action function.
- })
- afterEach(() => {
- // Presets a clear action, which is performed after each unit test case ends.
- // The number of execution times is the same as the number of test cases defined by **it**.
- // This API supports only one parameter: clear action function.
- })
- afterAll(() => {
- // Presets a clear action, which is performed after all test cases of the test suite end.
- // This API supports only one parameter: clear action function.
- })
- it('assertContain', 0, () => {
- // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
- hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
- let a = 'abc';
- let b = 'b';
-
- [func_direct_testCase]
-
- // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
- expect(a).assertContain(b);
- expect(a).assertEqual(a);
- // 断言 如:expect(result).assertEqual(2+3)
- })
- })
-}
-`
+const SERIAL = 5;
+const MODTWO = 2;
// 随机生成浮点数值
function generateRandomArbitrary(min, max, fixed) {
@@ -77,7 +37,20 @@ function generateRandomBoolValue() {
return randomBool;
}
-function generateFuncTestCase(params, tsFuncName, indexPath) {
+// 随机生成字符串
+function generateRandomString(length) {
+ let result = '';
+ let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+ let charactersLength = characters.length;
+
+ for (let i = 0; i < length; i++) {
+ result += characters.charAt(Math.floor(Math.random() * charactersLength));
+ }
+
+ return result;
+}
+
+function generateFuncTestCase(params, tsFuncName, testFilePath, directFuncJson) {
let funcInfo = {
"name": "",
"params": [],
@@ -92,7 +65,6 @@ function generateFuncTestCase(params, tsFuncName, indexPath) {
funcInfo.retType = params.functions[0].rtnType
let funcParamDefine = ''
let funcParamUse = ''
- // let funcParamExpect = ''
// 判断函数有几个参数,依次给参数赋值
for(let i = 0; i < funcInfo.params.length; i++) {
if (getTestType(funcInfo.params[i].type) === 'int') {
@@ -104,6 +76,9 @@ function generateFuncTestCase(params, tsFuncName, indexPath) {
} else if (getTestType(funcInfo.params[i].type) === 'bool') {
funcParamDefine += util.format('let %s = %s\n', funcInfo.params[i].name, generateRandomBoolValue())
funcParamUse += funcInfo.params[i].name + ', '
+ } else if (getTestType(funcInfo.params[i].type) === 'string') {
+ funcParamDefine += util.format('let %s = "%s"\n', funcInfo.params[i].name, generateRandomString(LENGTH))
+ funcParamUse += funcInfo.params[i].name + ', '
}
}
// 去除调用参数的最后一个','
@@ -114,17 +89,39 @@ function generateFuncTestCase(params, tsFuncName, indexPath) {
// 加 hilog 打印
let hilogContent = util.format('hilog.info(0x0000, "testTag", "Test NAPI %s: ", result);', tsFuncName)
let func_test_replace = funcParamDefine + callFunc + hilogContent
+ let abilityTestTemplete = directFuncJson.abilityTestTemplete
+ // 替换random_number
+ let serialNum = tsFuncName.substring(0,SERIAL)
+ console.info("serialNum: " + serialNum)
let funcTestContent = replaceAll(abilityTestTemplete,'[func_direct_testCase]', func_test_replace)
-
- // let filePath = './entry/src/ohosTest/ets/test/Ability.test.ets'
+ funcTestContent = replaceAll(funcTestContent, '[random_number]', serialNum)
+ //console.info("funcTestContent: " + funcTestContent)
// 将内容写入Ability.test.ets文件
- // __dirname //当前文件的绝对路径
- // ../
- // let relativeFilePath = './entry/src/ohosTest/ets/test/Ability.test.ets'
- let rootPath = path.resolve(indexPath, '..', '..', '..', '..', '..');
- let filePath = path.join(rootPath, 'ohosTest/ets/test/Ability.test.ets');
- // console.info("filePath: " + filePath)
- writeFile(filePath, funcTestContent)
+ // 1.追加写入import模块 写在第一个import之前
+ // 2.追加写入测试用例
+
+ // writeFile(testFilePath, funcTestContent)
+
+ const importContent = "import testNapi from 'libentry.so';"
+ writeTestFile(testFilePath, importContent, funcTestContent)
+}
+
+function writeTestFile(filePath, importContent, funcTestContent) {
+ // 读取原本文件内容
+ const fileContent = fs.readFileSync(filePath, 'utf8');
+ const importPosition = fileContent.indexOf('import ');
+ let newFileContent = fileContent;
+ // 判断是否有该import语句,没有则添加
+ if (fileContent.indexOf(importContent) < 0) {
+ const newImportStatement = importContent + '\n';
+ newFileContent = fileContent.slice(0, importPosition) + newImportStatement + fileContent.slice(importPosition);
+ }
+ // 追加写入测试用例
+ let testCasePosition = newFileContent.lastIndexOf('})\n}')
+ //console.info("testCasePosition: " + testCasePosition)
+ newFileContent = newFileContent.slice(0, testCasePosition) + funcTestContent + newFileContent.slice(testCasePosition);
+
+ writeFile(filePath, newFileContent)
}
function replaceAll(s, sfrom, sto) {
@@ -135,20 +132,23 @@ function replaceAll(s, sfrom, sto) {
}
function getTestType(type) {
- if (type === 'uint32_t' || type === 'int32_t' || type === 'int16_t' || type === 'int64_t' || type === 'int') {
+ if (type === 'uint32_t' || type === 'int32_t' || type === 'int16_t' ||
+ type === 'int64_t' || type === 'int' || type === 'size_t') {
return 'int'
} else if (type === 'double_t' || type === 'double' || type === 'float') {
return 'float'
} else if (type === 'bool') {
return 'bool'
+ } else if (type === 'std::string' || type.substring(0,10) === 'const char') {
+ return 'string'
}
}
function getJsType(type) {
if (type === 'uint32_t' || type === 'int32_t' || type === 'int16_t' || type === 'int64_t' ||
- type === 'int' || type === 'double_t' || type === 'double' || type === 'float') {
+ type === 'int' || type === 'double_t' || type === 'double' || type === 'float' || type === 'size_t') {
return 'number'
- } else if (type === 'const char *' || type === 'std::string') {
+ } else if (type.substring(0,10) === 'const char' || type === 'std::string') {
return 'string'
} else if (type === 'bool') {
return 'boolean'
diff --git a/examples/napitutorials/tool/commandLine/src/tools/Tool.js b/examples/napitutorials/tool/commandLine/src/tools/Tool.js
index f6c518b4..3582e141 100644
--- a/examples/napitutorials/tool/commandLine/src/tools/Tool.js
+++ b/examples/napitutorials/tool/commandLine/src/tools/Tool.js
@@ -13,58 +13,63 @@
* limitations under the License.
*/
const fs = require('fs');
+const MOVE_EIGHTEEN = 18;
+const MOVE_TWELVE = 12;
+const MOVE_SIX = 6;
function utf8ArrayToStr(array) {
- var out, i, len, c;
- var char2, char3;
+ let char2, char3;
- out = "";
- len = array.length;
- i = 0;
+ let outStr = "";
+ let len = array.length;
+ let i = 0;
while (i < len) {
- c = array[i++];
- switch (c >> 4) {
+ let ch = array[i++];
+ switch (ch >> 4) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
- // 0xxxxxxx
- out += String.fromCharCode(c);
- break;
+ // 0xxxxxxx
+ outStr += String.fromCharCode(ch);
+ break;
case 12: case 13:
- // 110x xxxx 10xx xxxx
- char2 = array[i++];
- out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
- break;
+ // 110x xxxx 10xx xxxx
+ char2 = array[i++];
+ outStr += String.fromCharCode(((ch & 0x1F) << 6) | (char2 & 0x3F));
+ break;
case 14:
- // 1110 xxxx 10xx xxxx 10xx xxxx
+ // 1110 xxxx 10xx xxxx 10xx xxxx
char2 = array[i++];
char3 = array[i++];
- out += String.fromCharCode(((c & 0x0F) << 12) |
+ outStr += String.fromCharCode(((ch & 0x0F) << 12) |
((char2 & 0x3F) << 6) |
((char3 & 0x3F) << 0));
break;
}
}
- return out;
+ return outStr;
}
-function stringToUint8Array(string, options = { stream: false }) {
- if (options.stream) {
- throw new Error(`Failed to encode: the 'stream' option is unsupported.`);
+function stringToUint8Array(string, option = { streamBool: false }) {
+ if (option.streamBool) {
+ throw new Error(`Failed to encode: the 'streamBool' option is unsupported.`);
}
- let pos = 0;
const len = string.length;
- let at = 0; // output position
- let tlen = Math.max(32, len + (len >> 1) + 7); // 1.5x size
- let target = new Uint8Array((tlen >> 3) << 3); // ... but at 8 byte offset
+ let position = 0;
+ // output position
+ let atPos = 0;
+ // 1.5x size
+ let tlength = Math.max(32, len + (len >> 1) + 7);
+ // ... but atPos 8 byte offset
+ let target = new Uint8Array((tlength >> 3) << 3);
- while (pos < len) {
- let value = string.charCodeAt(pos++);
+ while (position < len) {
+ let value = string.charCodeAt(position++);
let isContinue = false;
if (value >= 0xd800 && value <= 0xdbff) {
- if (pos < len) {// high surrogate
- const extra = string.charCodeAt(pos);
+ if (position < len) {// high surrogate
+ const extra = string.charCodeAt(position);
if ((extra & 0xfc00) === 0xdc00) {
- ++pos;
+ ++position;
value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000;
}
}
@@ -75,42 +80,42 @@ function stringToUint8Array(string, options = { stream: false }) {
if (!isContinue) {
// expand the buffer if we couldn't write 4 bytes
- if (at + 4 > target.length) {
- tlen += 8; // minimum extra
- tlen *= (1.0 + (pos / string.length) * 2); // take 2x the remaining
- tlen = (tlen >> 3) << 3; // 8 byte offset
+ if (atPos + 4 > target.length) {
+ tlength += 8; // minimum extra
+ tlength *= (1.0 + (position / string.length) * 2); // take 2x the remaining
+ tlength = (tlength >> 3) << 3; // 8 byte offset
- target = uint8Array(tlen, target);
+ target = uint8Array(tlength, target);
}
- let calculateResult = calculate(value, target, at)
+ let calculateResult = calculate(value, target, atPos)
isContinue = calculateResult[0]
target = calculateResult[1]
- at = calculateResult[2]
+ atPos = calculateResult[2]
}
}
- return target.slice(0, at);
+ return target.slice(0, atPos);
}
-function calculate(value, target, at) {
+function calculate(val, target, at) {
let isContinue = false
- if ((value & 0xffffff80) === 0) { // 1-byte
- target[at++] = value; // ASCII
+ if ((val & 0xffffff80) === 0) { // 1-byte
+ target[at++] = val; // ASCII
isContinue = true;
- } else if ((value & 0xfffff800) === 0) { // 2-byte
- target[at++] = ((value >> 6) & 0x1f) | 0xc0;
- } else if ((value & 0xffff0000) === 0) { // 3-byte
- target[at++] = ((value >> 12) & 0x0f) | 0xe0;
- target[at++] = ((value >> 6) & 0x3f) | 0x80;
- } else if ((value & 0xffe00000) === 0) { // 4-byte
- target[at++] = ((value >> 18) & 0x07) | 0xf0;
- target[at++] = ((value >> 12) & 0x3f) | 0x80;
- target[at++] = ((value >> 6) & 0x3f) | 0x80;
+ } else if ((val & 0xffe00000) === 0) { // 4-byte
+ target[at++] = ((val >> MOVE_EIGHTEEN) & 0x07) | 0xf0;
+ target[at++] = ((val >> MOVE_TWELVE) & 0x3f) | 0x80;
+ target[at++] = ((val >> MOVE_SIX) & 0x3f) | 0x80;
+ } else if ((val & 0xffff0000) === 0) { // 3-byte
+ target[at++] = ((val >> MOVE_TWELVE) & 0x0f) | 0xe0;
+ target[at++] = ((val >> MOVE_SIX) & 0x3f) | 0x80;
+ } else if ((val & 0xfffff800) === 0) { // 2-byte
+ target[at++] = ((val >> MOVE_SIX) & 0x1f) | 0xc0;
} else {
isContinue = true;
}
if (!isContinue) {
- target[at++] = (value & 0x3f) | 0x80;
+ target[at++] = (val & 0x3f) | 0x80;
}
return [isContinue, target, at]
}
@@ -135,7 +140,7 @@ function writeFile(fn, str) {
fs.writeFileSync(fn, data);
}
-function appendWriteFile(fn, str) {
+function appendWriteFile(fn, str) {
fs.appendFile(fn, str, 'utf8', err => {
if (err) {
console.error(err);
@@ -151,9 +156,21 @@ function generateRandomInteger(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
+/**
+ * 获取Json文件内容
+ * @returns
+ */
+function getJsonCfg(jsonFilePath) {
+ let jsonCfg = null; // json 配置文件
+ let jsonFile = fs.readFileSync(jsonFilePath, { encoding: "utf8" });
+ jsonCfg = JSON.parse(jsonFile);
+ return jsonCfg;
+}
+
module.exports = {
- readFile,
- writeFile,
- appendWriteFile,
- generateRandomInteger
+ readFile,
+ writeFile,
+ appendWriteFile,
+ generateRandomInteger,
+ getJsonCfg
}
\ No newline at end of file
diff --git a/examples/napitutorials/tool/commandLine/src/tools/re.js b/examples/napitutorials/tool/commandLine/src/tools/re.js
index 55af6e69..61385d14 100644
--- a/examples/napitutorials/tool/commandLine/src/tools/re.js
+++ b/examples/napitutorials/tool/commandLine/src/tools/re.js
@@ -18,15 +18,15 @@ function search(ss, data) {
ss = replaceAll(ss, "\\.", "\\.")
let reg = new RegExp(ss);
let tt = reg.exec(data);
- if (tt == null) return null;
+ if (tt === null || tt === undefined) return null;
let ret = { "regs": [] }
for (let i = 0; i < tt.length; i++) {
let p = data.indexOf(tt[i]);
- if (tt[i] == null) {
- ret["regs"].push([-1, -1])
+ if (tt[i] === null || tt[i] === undefined) {
+ ret.regs.push([-1, -1])
}
else {
- ret["regs"].push([p, p + tt[i].length])
+ ret.regs.push([p, p + tt[i].length])
}
}
@@ -35,7 +35,7 @@ function search(ss, data) {
function match(ss, data) {
let tt = search(ss, data)
- if (tt != null && tt.regs[0][0] == 0) return tt;
+ if ((tt !== null && tt !== undefined) && tt.regs[0][0] === 0) return tt;
return null;
}
diff --git a/examples/napitutorials/tool/commandLine/src/tsGen/tsMain.js b/examples/napitutorials/tool/commandLine/src/tsGen/tsMain.js
index 59a7b5a2..ee85c383 100644
--- a/examples/napitutorials/tool/commandLine/src/tsGen/tsMain.js
+++ b/examples/napitutorials/tool/commandLine/src/tsGen/tsMain.js
@@ -13,12 +13,13 @@
* limitations under the License.
*/
const { NapiLog } = require("../tools/NapiLog");
-const { writeFile, appendWriteFile, generateRandomInteger } = require("../tools/Tool");
+const { writeFile, appendWriteFile, generateRandomInteger, getJsonCfg } = require("../tools/Tool");
const path = require('path')
const re = require("../tools/re");
const fs = require("fs");
const os = require("os");
const util = require('util');
+const readline = require('readline');
const { generateDirectFunction } = require('../napiGen/functionDirect')
const { generateFuncTestCase } = require('../napiGen/functionDirectTest')
@@ -62,7 +63,7 @@ function isStringType(cType) {
}
function isBoolType(cType) {
- if (cType == 'bool') {
+ if (cType === 'bool') {
return true
}
return false
@@ -121,7 +122,6 @@ function getJsTypeFromC(cType, typeInfo) {
}
let jsType = basicC2js(basicCtype)
if (typeInfo.array) {
- // 替换原先的无用format
jsType = util.format("Array<%s>", jsType)
}
return jsType
@@ -176,8 +176,8 @@ function analyzeRootFunction(rootInfo, parseResult) {
let parseFunctions = parseResult.functions
// console.info("parseFunctions: " + JSON.stringify(parseFunctions))
for(var i = 0; i < parseFunctions.length; ++i) {
+ // 普通方法生成模板
let funcInfo = createFuncInfo(parseFunctions[i], false)
-
rootInfo.functions.push(funcInfo)
}
}
@@ -190,52 +190,121 @@ function getTab(tabLv) {
return tab
}
-function genFunction(func, tabLv, needDeclare = false) {
- let tab = getTab(tabLv)
+function genFunction(func, funcJson) {
let funcPrefix = func.isClassFunc ? "" : "function "
let funcParams = ""
for (var i = 0; i < func.params.length; ++i) {
funcParams += i > 0 ? ", " : ""
funcParams += func.params[i].name + ": " + func.params[i].type
}
- let declareStr = needDeclare ? "declare " : ""
+
+ let indexTemplete = funcJson.directFunction.indexTemplete
tsFuncName = 'KH' + generateRandomInteger(MIN_RANDOM, MAX_RANDOM) + '_' + func.name
- return util.format("export const %s:(%s) => %s;\n", tsFuncName, funcParams, func.retType)
+ return util.format(indexTemplete, tsFuncName, funcParams, func.retType)
}
-function genTsContent(rootInfo) {
+function genTsContent(rootInfo, funcJson) {
let tsContent = rootInfo.needCallback ? "import { AsyncCallback, Callback } from './../basic';\n\n" : ""
for(var i = 0; i < rootInfo.functions.length; ++i) {
- tsContent += genFunction(rootInfo.functions[i], 0, true)
+ tsContent += genFunction(rootInfo.functions[i], funcJson)
}
return tsContent
}
-function doGenerate(hFilePath, destDir) {
- let parseResult = parseFileAll(hFilePath)
- // console.info("parseResult: " + JSON.stringify(parseResult))
+function removeMarco(hFilePath, tempFilePath) {
+ // 创建读取文件的流
+ const fileStream = fs.createReadStream(hFilePath);
+ // 创建逐行读取的接口
+ const rl = readline.createInterface({
+ input: fileStream,
+ crlfDelay: Infinity
+ });
+ // 存储处理后的文件内容
+ let processedContent = '';
+ // 逐行读取文件内容并处理
+ rl.on('line', (line) => {
+ let tt = re.match('[A-Z_]+\([A-Za-z_ *]+\)', line)
+ console.info("tt: " + JSON.stringify(tt))
+ if (tt) {
+ console.info("before line: " + line)
+ let removeContent = re.getReg(line, tt.regs[0])
+ line = line.substring(removeContent.length + 1, line.length)
+ let index = line.indexOf(') ')
+ console.info("index: " + index)
+ if (index >= 0) {
+ line = line.substring(0, index) + line.substring(index + 1, line.length)
+ }
+ }
+ processedContent += line + '\n';
+ });
+
+ // 完成读取操作
+ rl.on('close', () => {
+ console.log("processedContent: " + processedContent);
+ writeFile(tempFilePath, processedContent)
+ });
+}
+
+function sleep(ms) {
+ return new Promise(resolve => setTimeout(resolve, ms));
+}
+
+async function doGenerate(hFilePath, testFilePath, tsFilePath, cppFilePath) {
+ let random = generateRandomInteger(MIN_RANDOM, MAX_RANDOM)
+ let tempFileName = '../temp_' + random + '.h'
+ let tempFilePath = path.join(hFilePath, tempFileName)
+ removeMarco(hFilePath, tempFilePath)
+
+ while(!fs.existsSync(tempFilePath)) {
+ await sleep(20); // 延迟 20 毫秒
+ }
+ const fileContent = fs.readFileSync(tempFilePath, 'utf8');
+ console.info("fileContent: " + fileContent)
+
+ let parseResult = parseFileAll(tempFilePath)
+ console.info("parseResult.functions: " + JSON.stringify(parseResult.functions))
+
let rootInfo = {
"functions": [],
"needCallback": false
}
+ // 普通方法生成一个模板模板
analyzeRootFunction(rootInfo, parseResult)
+ // 如果是class生成一个模板
+ // analyzeRootClass()
+
+ // 读取Json文件
+ let funcJsonPath = path.join(__dirname, '../function.json');
+ console.info("funcJsonPath: " + funcJsonPath)
+ let funcJson = getJsonCfg(funcJsonPath);
+
let hfileName = path.basename(hFilePath, ".h")
- let tsFilePath = destDir
- let tsContent = genTsContent(rootInfo)
+ let tsContent = genTsContent(rootInfo, funcJson)
console.info("tsContent: " + tsContent)
appendWriteFile(tsFilePath, '\n' + tsContent)
// 调用napi转换的方法
- generateDirectFunction(parseResult, tsFuncName, destDir)
+ generateDirectFunction(parseResult, tsFuncName, cppFilePath, funcJson.directFunction)
// 生成测试用例
- generateFuncTestCase(parseResult, tsFuncName, destDir)
+ generateFuncTestCase(parseResult, tsFuncName, testFilePath, funcJson.directFunction)
+
+ // 删除生成的中间文件
+ clearTmpFile(tempFilePath)
console.info('Generate success')
}
+function clearTmpFile(filePath) {
+ try {
+ fs.unlinkSync(filePath);
+ } catch (err) {
+ console.error(err);
+ }
+}
+
module.exports = {
doGenerate
}
diff --git a/examples/napitutorials/tool/plugin/docs/guide/DEVELOP_ZH.md b/examples/napitutorials/tool/plugin/docs/guide/DEVELOP_ZH.md
index 929fa344..1ed282a4 100644
--- a/examples/napitutorials/tool/plugin/docs/guide/DEVELOP_ZH.md
+++ b/examples/napitutorials/tool/plugin/docs/guide/DEVELOP_ZH.md
@@ -2,7 +2,7 @@
## 工具代码框架介绍
-native生成工具由由C++语法解释器和代码生成器两部分组成。C++语法解释器解析用户输入的.h文件内容,通过C++语法解析,将文件内容分解为类、方法、入参、成员属性等元素;代码生成器根据从语法解析器得到的这些元素,转换为对应的typescript语法的接口、方法、参数代码,生成.ts文件内容;同时通过语法解析器得到的元素,生成.h文件对应的napi框架代码和接口调用测试代码。
+native生成工具由由C++语法解释器和代码生成器两部分组成。C++语法解释器解析用户输入的.h文件内容,通过C++语法解析,将文件内容分解为类、方法、入参、成员属性等元素;代码生成器根据从语法解析器得到的这些元素,转换为对应的typescript语法的接口、方法、参数代码,生成.ts文件内容;同时通过语法解析器得到的元素,生成.h文件对应的napi框架代码和接口调用测试代码。native生成工具支持命令行和IntelliJ插件,本文主要介绍IntellIJ插件。
## 工具开发
diff --git a/examples/napitutorials/tool/plugin/docs/guide/INSTRUCTION_ZH.md b/examples/napitutorials/tool/plugin/docs/guide/INSTRUCTION_ZH.md
index 280eaacf..0cacb3cd 100644
--- a/examples/napitutorials/tool/plugin/docs/guide/INSTRUCTION_ZH.md
+++ b/examples/napitutorials/tool/plugin/docs/guide/INSTRUCTION_ZH.md
@@ -50,7 +50,7 @@ res = value0 + value1;
在Ability.test.ets文件中增加断言:
```
-expect(result).assertEqual(2.3+3.2)
+expect(result).assertEqual(2+3)
```
连接开发板,运行Ability.test.ets中的测试用例:
diff --git a/examples/napitutorials/tool/plugin/src/com/sk/na/ng/GenDTS.java b/examples/napitutorials/tool/plugin/src/com/sk/na/ng/GenDTS.java
index 8e074177..52384d93 100644
--- a/examples/napitutorials/tool/plugin/src/com/sk/na/ng/GenDTS.java
+++ b/examples/napitutorials/tool/plugin/src/com/sk/na/ng/GenDTS.java
@@ -31,6 +31,8 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.util.regex.Pattern;
+import java.nio.charset.StandardCharsets;
/**
* 项目文件入口
@@ -40,8 +42,9 @@ import java.io.InputStreamReader;
* @version: v1.0.0
* @since 2024-03-29
*/
-public class GenDTS extends AnAction {
- private static final Logger LOG = Logger.getInstance(GenDTS.class);
+public class GenDts extends AnAction {
+ private static final Logger LOG = Logger.getInstance(GenDts.class);
+
private boolean generateSuccess = true;
private String sErrorMessage = "";
@@ -58,10 +61,135 @@ public class GenDTS extends AnAction {
return;
}
String destPath = file.getPath();
- // 异步执行
runFun(destPath);
}
+ @Override
+ public void update(AnActionEvent event) {
+ // 根据所选文件名,判断是否显示生成菜单项
+ VirtualFile file = event.getData(PlatformDataKeys.VIRTUAL_FILE);
+ if (file == null) {
+ event.getPresentation().setEnabledAndVisible(false);
+ } else {
+ event.getPresentation().setEnabledAndVisible(patternFileName(file.getName()));
+ }
+ }
+
+ /**
+ * 正则匹配所选文件名是否符合规范
+ *
+ * @param fileName 文件名
+ * @return boolean 是否匹配
+ */
+ public static boolean patternFileName(String fileName) {
+ String pattern = "(([a-z_A-Z0-9]+).h)";
+ return Pattern.matches(pattern, fileName);
+ }
+
+ /**
+ * 获取生成成功结果文件。
+ *
+ * @param process 进程ID
+ */
+ private void genResultLog(Process process) {
+ BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getErrorStream(),
+ StandardCharsets.UTF_8));
+ BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream(),
+ StandardCharsets.UTF_8));
+ String sErr = getErrorResult(stdError);
+ String sOut;
+ if (TextUtils.isEmpty(sErr)) {
+ sOut = genInputLog(stdInput);
+ if (!generateIsSuccess(sOut)) {
+ sErrorMessage = sOut;
+ }
+ return;
+ }
+ generateSuccess = false;
+ sErrorMessage = sErr;
+ }
+
+ /**
+ * 获取生成文本内容。
+ *
+ * @param stdInput input buff
+ * @return 返回当前输入框内容
+ */
+ private String genInputLog(BufferedReader stdInput) {
+ StringBuilder sOut = new StringBuilder();
+ while (true) {
+ String sTmp;
+ try {
+ if ((sTmp = stdInput.readLine()) == null) {
+ break;
+ }
+ sOut.append(sTmp).append(getNewline());
+ } catch (IOException ioException) {
+ LOG.error(" genResultLog stdInput error" + ioException);
+ }
+ }
+ return sOut.toString();
+ }
+
+ /**
+ * 获取生成失败结果文件。
+ *
+ * @param stdError error buff
+ * @return ErrorResult
+ */
+ private String getErrorResult(BufferedReader stdError) {
+ StringBuilder sErr = new StringBuilder();
+ while (true) {
+ String sTmp;
+ try {
+ if ((sTmp = stdError.readLine()) == null) {
+ break;
+ }
+ sErr.append(sTmp).append(getNewline());
+ } catch (IOException ioException) {
+ LOG.error(" genResultLog stdInput error" + ioException);
+ }
+ }
+ return sErr.toString();
+ }
+
+ /**
+ * 获取换行符
+ *
+ * @return 换行符
+ */
+ public static String getNewline() {
+ return System.getProperty("line.separator");
+ }
+
+ private boolean generateIsSuccess(String sOut) {
+ generateSuccess = sOut.contains("success") || TextUtils.isEmpty(sOut);
+ return generateSuccess;
+ }
+
+ static class StreamConsumer extends Thread {
+ InputStream is;
+
+ StreamConsumer(InputStream is) {
+ super.setName("StreamConsumer");
+ this.is = is;
+ }
+
+ @Override
+ public void run() {
+ try {
+ InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
+ BufferedReader br = new BufferedReader(isr);
+ String line;
+ while ((line = br.readLine()) != null) {
+ LOG.error("StreamConsumer" + line);
+ }
+ } catch (IOException ioException) {
+ LOG.error("StreamConsumer io error" + ioException);
+ }
+ }
+ }
+
private boolean callExtProcess(String command) throws IOException, InterruptedException {
if (TextUtils.isEmpty(command)) {
@@ -69,40 +197,20 @@ public class GenDTS extends AnAction {
return false;
}
Process process = Runtime.getRuntime().exec(command);
-
- // 读取输出流(正常输出)
- new Thread(() -> {
- try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
- String line;
- while ((line = reader.readLine()) != null) {
- System.out.println(line);
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }).start();
-
- // 读取错误流(错误输出)
- new Thread(() -> {
- try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
- String line;
- while ((line = reader.readLine()) != null) {
- System.err.println(line);
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }).start();
-
- // 等待进程结束
- int exitCode = process.waitFor();
- System.out.println("Process exited with code: " + exitCode);
+ genResultLog(process);
+ StreamConsumer errConsumer = new StreamConsumer(process.getErrorStream());
+ StreamConsumer outputConsumer = new StreamConsumer(process.getInputStream());
+ errConsumer.start();
+ outputConsumer.start();
if (!generateSuccess) {
GenNotification.notifyMessage(null, sErrorMessage, "提示", NotificationType.ERROR);
return false;
}
+ errConsumer.join();
+ outputConsumer.join();
+
return true;
}
@@ -129,7 +237,7 @@ public class GenDTS extends AnAction {
if (!file.exists()) {
boolean isNewFile = file.createNewFile();
if (!isNewFile) {
- LOG.info("writeTmpFile createNewFile error");
+ LOG.info("writeTmpFile createNewFile error");
}
}
FileOutputStream fw = new FileOutputStream(file);
@@ -175,6 +283,7 @@ public class GenDTS extends AnAction {
/**
* 生成命令行指令
*
+ * @param hFilePath .h文件路径
* @return 返回命令行执行内容
*/
private String genCommand(String hFilePath) {
@@ -193,13 +302,15 @@ public class GenDTS extends AnAction {
File file = new File(tmpDirFile);
String command = file.toString();
- command += " " + hFilePath;
+ command += " -f " + hFilePath;
+ // 判断用户是否输入了 "-o"+cpp文件路径, "-i"+dts文件路径,"-t"+test文件路径 从界面获取
return command;
}
/**
* 执行主程序入口
*
+ * @param hFilePath .h文件路径
* @return 执行状态
*/
public boolean runFun(String hFilePath) {
diff --git a/examples/napitutorials/tool/plugin/src/com/sk/na/utils/GenNotification.java b/examples/napitutorials/tool/plugin/src/com/sk/na/utils/GenNotification.java
index b02c6aa0..88319030 100644
--- a/examples/napitutorials/tool/plugin/src/com/sk/na/utils/GenNotification.java
+++ b/examples/napitutorials/tool/plugin/src/com/sk/na/utils/GenNotification.java
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,6 +13,7 @@
* limitations under the License.
*/
package com.sk.na.utils;
+
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationGroupManager;
@@ -20,13 +21,14 @@ import com.intellij.notification.NotificationGroup;
import com.intellij.notification.Notifications;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
+
/**
* 通知框
*
- * @author: liulongc digitalchina.com
+ * @author: goujingjing
* @see: tool conversion plug-in
* @version: v1.0.0
- * @since 2022-05-27
+ * @since 2024-04-02
*/
public class GenNotification {