diff --git a/src/vscode_plugin/src/gen/gencpp.ts b/src/vscode_plugin/src/gen/gencpp.ts index 71fcf8b7dda3d15b85b7203d73caa62b00e06cbc..52328ed708c0d120425308ca7c8e0d910f0e2ced 100644 --- a/src/vscode_plugin/src/gen/gencpp.ts +++ b/src/vscode_plugin/src/gen/gencpp.ts @@ -13,12 +13,20 @@ * limitations under the License. */ -import { FuncInfo, InterfaceList, TypeList } from "./datatype"; +import { DirTemp, FuncInfo, FuncObj, GenInfo, InterfaceList, TypeList } from "./datatype"; import { getInterfaceBody, getTypeBody } from "./gendts"; -import { boolIn, boolRet, doubleIn, doubleRet, funcGetParamTemplate, int32tIn, int32tRet, int64tIn, int64tRet, - napiFuncCppTemplate, napiFuncRetTemplate, objectRet, objectTosetRet, paramGenTemplate, stringIn, stringRet, - uint32tIn, uint32tRet } from "../template/func_template"; +import { + boolIn, boolRet, doubleIn, doubleRet, funcGetParamTemplate, int32tIn, int32tRet, int64tIn, int64tRet, + napiFuncCppTemplate, napiFuncHTemplate, napiFuncInitTemplate, napiFuncRetTemplate, objectRet, objectTosetRet, + paramGenTemplate, stringIn, stringRet, + uint32tIn, uint32tRet +} from "../template/func_template"; import { replaceAll } from "../common/tool"; +import { cppout, dts2cpp_cppdir } from "../template/dtscpp/dtscppdir"; +import * as path from 'path'; +import * as fs from 'fs'; +import { h2NapiInKey, h2NapiOutKey } from "../template/dtscpp/dts2cpp_key"; +import { napiCppTemplate } from "../template/dtscpp/dtscpp_napicpp_template"; interface RetObjInfo { objName: string; @@ -213,4 +221,258 @@ export function getRetTypeContent(retTypeTemplate: string, returnName: string, r retGenResult += setRetProperty; } return retGenResult; -} \ No newline at end of file +} + + +// ------------------------------ gencpp ----------------------------- +const fileHandlers: { [key: string]: Function } = { + '[fileName]init.cpp': genInitCppFile, + '[fileName]napi.h': genNapiHFile, + '[fileName]napi.cpp': genNapiCppFile, + '[fileName]common.h': genCommonHFile, + '[fileName]common.cpp': genCommonCppFile, + '[fileName].h': genCommonFile, + 'readme.md': genCommonFile +}; + +// 通过类型值映射模板,比如:uint32_t返回值 -> uint32tRet -> napi_create_uint32 +export function transCkey2NapiOutkey(key: string) { + // 数组 map set iterator tuple pair 等都当作objectOut处理 + for (const keyItem of h2NapiOutKey) { + for (const str of keyItem.keys) { + if (key.includes(str)) { + return keyItem.value; + } + } + } + let replaceKeyList = ['enum', 'struct', 'union']; + for (const rkey of replaceKeyList) { + key = key.replace(rkey, '').trim(); + } + // 其他的全部当作object处理, 如typeDef/enum/struct/union/class等,当作objectOut处理,返回objectRet + return objectRet; +} + +// 通过类型值映射模板,比如:uint32_t输入 -> uint32tIn -> napi_get_value_uint32 +export function transCkey2NapiInkey(key: string) { + for (const keyItem of h2NapiInKey) { + for (const str of keyItem.keys) { + if (key.includes(str)) { + return keyItem.value; + } + } + } + let replaceKeyList = ['enum', 'struct', 'union']; + for (const rkey of replaceKeyList) { + key = key.replace(rkey, '').trim(); + } + // 其他的全部当作object处理, 如typeDef/enum/struct/union/class等, 此时不需要做任何处理,因此返回空 + return ''; + +} + +// 把这些东西分成一个个文件,根据文件内容来生成 +export function genCommonFile(rootInfo: GenInfo, filePath: string, + fileContent: string) { + fs.writeFileSync(filePath, fileContent); +} +// 生成Init的文件 + +export function genInitCppFile(rootInfo: GenInfo, filePath: string, + fileContent: string) { + let napiInitContent = ''; + if (rootInfo.parseObj && rootInfo.parseObj.funcs) { + rootInfo.parseObj.funcs.forEach(func => { + let funcName = func.name; + napiInitContent += replaceAll(napiFuncInitTemplate, + '[func_name_replace]', funcName); + }); + } + // 写文件 + fileContent = replaceAll(fileContent, '[fileName]', rootInfo.fileName); + fileContent = replaceAll(fileContent, '[init_replace]', napiInitContent); + fs.writeFileSync(filePath, fileContent); +} + +// 生成common.h文件,这个读模板直接生成 +export function genCommonHFile(rootInfo: GenInfo, filePath: string, + fileContent: string) { + let upperFileName = rootInfo.fileName.toLocaleUpperCase(); + fileContent = replaceAll(fileContent, '[fileName]', rootInfo.fileName); + fileContent = replaceAll(fileContent, '[upper_filename]', upperFileName); + fs.writeFileSync(filePath, fileContent); +} +// 生成common.cpp文件,读模板直接生成 +export function genCommonCppFile(rootInfo: GenInfo, filePath: string, fileContent: string) { + fileContent = replaceAll(fileContent, '[fileName]', rootInfo.fileName); + fs.writeFileSync(filePath, fileContent); +} + +// 生成napi.h文件 +export function genNapiHFile(rootInfo: GenInfo, filePath: string, + fileContent: string) { + let napiHContent = ''; + if (rootInfo.parseObj && rootInfo.parseObj.funcs) { + rootInfo.parseObj.funcs.forEach(func => { + let funcParams = ''; + for (let i = 0; i < func.parameters.length; ++i) { + funcParams += i > 0 ? ', ' : ''; + funcParams += func.parameters[i].name + ': ' + func.parameters[i].type; + } + let rawFileName = path.basename(rootInfo.rawFilePath); + let hContent = replaceAll(napiFuncHTemplate, '[file_introduce_replace]', rawFileName); + hContent = replaceAll(hContent, '[input_introduce_replace]', funcParams === '' ? 'void' : funcParams); + hContent = replaceAll(hContent, '[func_name_replace]', func.name); + hContent = replaceAll(hContent, '[func_param_replace]', funcParams); + hContent = replaceAll(hContent, '[func_return_replace]', + func.returns === '' ? 'void' : func.returns); + napiHContent += hContent; + }); + } + let upperFileName = rootInfo.fileName.toLocaleUpperCase(); + fileContent = replaceAll(fileContent, '[fileName]', rootInfo.fileName); + fileContent = replaceAll(fileContent, '[upper_filename]', upperFileName); + fileContent = replaceAll(fileContent, '[func_declare_replace]', napiHContent); + fs.writeFileSync(filePath, fileContent); +} + +// 生成napi.cpp文件 +export function genNapiCppFile(rootInfo: GenInfo, filePath: string, + fileContent: string) { + let napiCppContent = ''; + if (rootInfo.parseObj && rootInfo.parseObj.funcs) { + rootInfo.parseObj.funcs.forEach(funcInfo => { + // 替换每个方法主体 + let hFileName = path.basename(rootInfo.rawFilePath); + let bodyReplace = replaceAll(napiFuncCppTemplate, '[func_name_replace]', + funcInfo.name); + bodyReplace = replaceAll(bodyReplace, '[get_error_msg_tag]', + funcInfo.name); + bodyReplace = replaceAll(bodyReplace, '[file_introduce_replace]', + hFileName); + // 生成方法注释 + let funcInfoParams = funcInfo.parameters.length > 0 ? '' : 'void'; + let funcInfoParamTemp = '[paramName]: [paramType]; '; + for (let i = 0; i < funcInfo.parameters.length; i++) { + let funcInfoParamReplace = replaceAll(funcInfoParamTemp, '[paramName]', + funcInfo.parameters[i].name); + funcInfoParamReplace = replaceAll(funcInfoParamReplace, '[paramType]', + funcInfo.parameters[i].type); + funcInfoParams += funcInfoParamReplace; + } + bodyReplace = replaceAll(bodyReplace, '[input_introduce_replace]', + funcInfoParams === '' ? 'void' : funcInfoParams); + bodyReplace = replaceAll(bodyReplace, '[output_introduce_replace]', + funcInfo.returns); + // 方法参数的处理,解析参数类型,生成napi的参数处理代码 + let paramGenResult = getCppParamGen(funcInfo); + bodyReplace = replaceAll(bodyReplace, '[func_getParam_replace]', + paramGenResult); + // 方法返回值的处理,解析返回值类型,生成napi的返回值处理代码 + let returnGenResult = genCppReturnGen(funcInfo); + bodyReplace = replaceAll(bodyReplace, '[func_return_replace]', + returnGenResult); + // 组合一个个方法 + napiCppContent += bodyReplace; + }); + + // 生成xxxNapi.cpp文件 + fileContent = replaceAll(fileContent, '[fileName]', rootInfo.fileName); + fileContent = replaceAll(fileContent, '[func_content_replace]', napiCppContent); + fs.writeFileSync(filePath, fileContent); + } + + fileContent = replaceAll(fileContent, '[fileName]', rootInfo.fileName); + fileContent = replaceAll(fileContent, '[func_content_replace]', napiCppContent); + fs.writeFileSync(filePath, fileContent); +} + +// 方法输入参数的处理,只处理基本类型,像数组/map/set/class/struct等都全部当作 +// object,且不做处理 +export function getCppParamGen(funcInfo: FuncObj): string { + // 处理输入的参数,生成napi的参数处理代码 + if (funcInfo.parameters.length === 0) { + return '// no input params'; + } + let paramGenResult = ''; + for (let i = 0; i < funcInfo.parameters.length; ++i) { + let getParamInTemplate = transCkey2NapiInkey(funcInfo.parameters[i].type); + // 如果getParamInTemplate是空,则默认是对象输入,不做任何处理 + if (getParamInTemplate === '') { + paramGenResult = '// Todo: handle object input'; + continue; + } + let getParam = replaceAll(getParamInTemplate, '[param_index_replace]', + 'PARAMS' + i); + getParam = replaceAll(getParam, '[param_name_replace]', + funcInfo.parameters[i].name); + let paramGen = replaceAll(paramGenTemplate, '[param_index_replace]', + 'PARAMS' + i); + paramGen = replaceAll(paramGen, '[param_name_replace]', + funcInfo.parameters[i].name); + paramGen = replaceAll(paramGen, '[getParam_replace]', getParam); + paramGenResult += paramGen; + } + let genParamReplace = replaceAll(funcGetParamTemplate, '[param_length]', + 'PARAMS' + funcInfo.parameters.length); + genParamReplace = replaceAll(genParamReplace, '[func_name_replace]', + funcInfo.name); + genParamReplace = replaceAll(genParamReplace, '[getAllParam_replace]', + paramGenResult); + return genParamReplace +} + +// 方法返回值的处理 +export function genCppReturnGen(funcInfo: FuncObj): string { + // 如果函数返回值是空,直接返回NULL + if (funcInfo.returns === 'void') { + return ' return NULL;\n'; + } + let returnName = funcInfo.name + 'Out'; + let funcReturnReplace = replaceAll(napiFuncRetTemplate, '[return_name]', + returnName); + let retGenResult = transCkey2NapiOutkey(funcInfo.returns); + retGenResult = replaceAll(retGenResult, '[return_name_replace]', returnName); + funcReturnReplace = replaceAll(funcReturnReplace, '[func_name_replace]', + funcInfo.name); + funcReturnReplace = replaceAll(funcReturnReplace, '[return_replace]', + retGenResult); + return funcReturnReplace; +} + +export function genDir(dirItem: DirTemp, rootInfo: GenInfo, out: string) { + let dirPath = path.join(out, dirItem.name); + let lowerFileName = rootInfo.fileName.toLocaleLowerCase(); + // 创建目录 + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath, { recursive: true }); + } + // 遍历生成当前目录文件 + dirItem.files.forEach(file => { + let fileName = file.name.replace('[fileName]', lowerFileName); + let filePath = path.join(dirPath, fileName); + // 将content写入文件, 这里的content是模板,需要replace里面的部分内容 + if (!fs.existsSync(filePath)) { + // 拿到每个文件并且根据文件生成内容并写入 + const handler = fileHandlers[file.name]; + if (handler) { + // 调用对应的生成文件方法 + handler(rootInfo, filePath, file.content); + } + } + }) + // 遍历子目录,生成子目录的文件 + dirItem.dirs.forEach(subDir => { + genDir(subDir, rootInfo, dirPath); + }) +} + +// gen h and cpp file. +export function genHCppFile(rootInfo: GenInfo, out: string) { + if (out === undefined || out === null || out.trim() === '') { + out = path.dirname(rootInfo.rawFilePath); + } + genDir(dts2cpp_cppdir, rootInfo, out); +} + + diff --git a/src/vscode_plugin/src/gen/gendts.ts b/src/vscode_plugin/src/gen/gendts.ts index 5e88a7e60aa8efd331864a5dfb81b35ab2a42e65..618bb545ec29cdd52819161346cb35aa086b0c97 100644 --- a/src/vscode_plugin/src/gen/gendts.ts +++ b/src/vscode_plugin/src/gen/gendts.ts @@ -14,7 +14,7 @@ */ import fs = require('fs'); import { DtscppRootInfo, FuncObj, InterfaceBody, ParamObj, FuncInfo, GenInfo, InterfaceList, TypeList } from './datatype'; -import { dts2cpp_key } from '../template/dtscpp/dts2cpp_key'; +import { cpp2DtsKey } from '../template/dtscpp/dts2cpp_key'; import path = require('path'); import { Logger } from '../common/log'; @@ -22,7 +22,7 @@ import { generateRandomInteger, removeComments, removeTab, replaceAll } from '.. import util = require('util'); import re = require('../common/re'); import { dtsFuncTemplate } from '../template/func_template'; - +const DTS = '.d.ts'; export function genTsFunction(func: FuncInfo, rawFileName: string) { let funcParams = ''; @@ -528,7 +528,7 @@ export function getDtsUnions(rootInfo: GenInfo) { return out; } -export function genDtsFile(rootInfo: GenInfo) { +export function genDtsFile(rootInfo: GenInfo, out: string) { // gen enums let fileContent = getDtsEnum(rootInfo); // gen functions @@ -540,9 +540,14 @@ export function genDtsFile(rootInfo: GenInfo) { // gen union fileContent += getDtsUnions(rootInfo); - let dtsFileName = rootInfo.fileName + '.d.ts'; - let dirPath = path.dirname(rootInfo.rawFilePath); - let outPath = path.join(dirPath, dtsFileName); + let dtsFileName = rootInfo.fileName + DTS; + let outPath = '' + if (out === undefined || out === null || out.trim() === '') { + let dirPath = path.dirname(rootInfo.rawFilePath); + outPath = path.join(dirPath, dtsFileName); + } else { + outPath = path.join(out, dtsFileName); + } fs.writeFileSync(outPath, fileContent); Logger.getInstance().info('generate success!') return outPath; diff --git a/src/vscode_plugin/src/gen/gendtscpp.ts b/src/vscode_plugin/src/gen/gendtscpp.ts index 7df239c8a472d5f461fbb528fb42f8771aad2a91..a642f6f18d29211d9a0059a1e57f5915f3268564 100644 --- a/src/vscode_plugin/src/gen/gendtscpp.ts +++ b/src/vscode_plugin/src/gen/gendtscpp.ts @@ -13,15 +13,15 @@ * limitations under the License. */ -import { DirTemp, DtscppRootInfo, FuncInfo, InterfaceList, TypeList, ParamObj, ParseObj, ClassObj, FuncObj } from "./datatype"; +import { DirTemp, DtscppRootInfo, FuncInfo, InterfaceList, TypeList, ParamObj, ParseObj, ClassObj, FuncObj, GenInfo } from "./datatype"; import { replaceAll } from "../common/tool"; import fs = require('fs'); import path = require("path"); import { napiFuncHTemplate, napiFuncInitTemplate } from "../template/func_template"; import { cppout, dtscppout } from "../template/dtscpp/dtscppdir"; -import { analyzeRootFunction, genDtsInterface, genTsFunction } from "./gendts"; -import { generateDirectFunction } from "./gencpp"; -import { generateFuncTestCase } from "./gentest"; +import { analyzeRootFunction, genDtsFile, genDtsInterface, genTsFunction } from "./gendts"; +import { generateDirectFunction, genHCppFile } from "./gencpp"; +import { genAbilitytestFile, generateFuncTestCase } from "./gentest"; import { Logger } from "../common/log"; import { tsTransferType } from "../template/functypemap_template"; @@ -259,3 +259,31 @@ export function createFuncParam(params: ParamObj) { cppParam.type = getCTypeFromJS(params.type); return cppParam; } + +// -----------------------h2dtscpp------------------------ +export function createDir(path: string) { + if (!fs.existsSync(path)) { + fs.mkdirSync(path); + } +} +export function genDtscppFromH(rootInfo: GenInfo) { + // 生成dts文件: 这里将文件生成在 cpp/types目录下,该路径是ndk工程中的dts文件的默 + // 认路径 + let outDir = path.dirname(rootInfo.rawFilePath); + let dtsOutPath = path.join(outDir, 'cpp'); + createDir(dtsOutPath); + dtsOutPath = path.join(dtsOutPath, 'types'); + createDir(dtsOutPath); + genDtsFile(rootInfo, dtsOutPath); + // 生成.cpp和.h文件 + genHCppFile(rootInfo, outDir); + // 生成Ability.test.ets文件:这里将文件生成在 test/ets目录下,该路径是ndk工程中 + // 的test文件的默认路径 + let testOutPath = path.join(outDir, 'test'); + createDir(testOutPath); + testOutPath = path.join(testOutPath, 'ets'); + createDir(testOutPath); + genAbilitytestFile(rootInfo, testOutPath); + console.log('h2dtscpp success!') +} +// -------------------dts2cpp------------------------todo diff --git a/src/vscode_plugin/src/gen/gentest.ts b/src/vscode_plugin/src/gen/gentest.ts index a78ec5db9b5109a9087306e45311d1b93d5a5c24..075bbf058fdf0530329d573a38bd167bd1debe4b 100644 --- a/src/vscode_plugin/src/gen/gentest.ts +++ b/src/vscode_plugin/src/gen/gentest.ts @@ -15,12 +15,14 @@ import util = require('util'); import { replaceAll } from "../common/tool"; -import { FuncInfo, InterfaceList, ParamObj, TypeList } from "./datatype"; +import { FuncInfo, GenInfo, InterfaceList, ParamObj, TypeList } from "./datatype"; import { getInterfaceBody, getTypeBody, transTskey2Ckey } from './gendts'; import { testAbilityFuncTemplate } from "../template/func_template"; import { Logger } from '../common/log'; -import { dts2cpp_key } from '../template/dtscpp/dts2cpp_key'; - +import { cpp2DtsKey, dts2TestValue } from '../template/dtscpp/dts2cpp_key'; +import * as path from 'path'; +import * as fs from 'fs'; +import { testFirstGenTemplate } from '../template/dtscpp/dtscpp_testfirstgen_template'; const INTVALUE = 5; const FLOATVALUE = 2.5; @@ -197,4 +199,88 @@ export function getJsType(type: string) { } } return 'testNapi.' + type.replace('*', '').trim(); +} + +// ----------------------- gentest ------------------------ +// 用H文件为源文件生成Ability.test.ets文件 +export function genAbilitytestFile(rootInfo: GenInfo, out: string) { + if (out === undefined || out === null || out.trim() === '') { + out = path.dirname(rootInfo.rawFilePath); + } + let testContent = '' + if (rootInfo.parseObj && rootInfo.parseObj.funcs) { + rootInfo.parseObj.funcs.forEach(funcInfo => { + let callFunc = ''; // 调用函数内容 + let hilogContent = ''; // hilog内容 + let funcParamDefine = ''; // 函数参数定义并初始化 + let funcParamUse = ''; // 函数参数使用 + let funcInfoParams = ''; // 注释 + let funcInfoParamTemp = '[paramName]: [paramType]; '; + // 遍历方法参数,给参数赋初始值,生成注释和参数使用内容 + // 1. 先将所有type转换为ts的type + for (let i = 0; i < funcInfo.parameters.length; ++i) { + // 注释 + let funcInfoParamReplace = replaceAll(funcInfoParamTemp, '[paramName]', + funcInfo.parameters[i].name); + funcInfoParamReplace = replaceAll(funcInfoParamReplace, '[paramType]', + funcInfo.parameters[i].type); + funcInfoParams += funcInfoParamReplace; + // 参数定义并初始化 + const param = funcInfo.parameters[i]; + let paramType = transTskey2Ckey(param.type); + let testValue = '\'Please give an any value.\''; // any类型咋赋值? + dts2TestValue.forEach(item => { + if (item.key === paramType) { + testValue = item.value; + } + }) + funcParamDefine += util.format('let %s: %s = %s;\n ', + funcInfo.parameters[i].name, paramType, testValue); + funcParamUse += funcInfo.parameters[i].name + ', '; + // 如果是最后一个参数,去掉最后的逗号和空格 + if (funcInfo.parameters.length === i + 1) { + funcParamUse = funcParamUse.slice(0, -2); // 去掉最后一个逗号和空格 + } + } + // 返回值 + let returnType = transTskey2Ckey(funcInfo.returns); + if (returnType === 'void') { + callFunc = util.format('testNapi.%s(%s)\n ', funcInfo.name, + funcParamUse); + } else { + callFunc = util.format('let result: %s = testNapi.%s(%s)\n ', + returnType, funcInfo.name, funcParamUse); + hilogContent = util.format( + 'hilog.info(0x0000, "testTag", "Test NAPI %s: ", JSON.stringify(result));\n ',funcInfo.name); + } + let funcTestReplace = funcParamDefine + callFunc + hilogContent; + let rawFileName = path.basename(rootInfo.rawFilePath); + // 替换test_case_name + let funcTestContent = replaceAll(testAbilityFuncTemplate, + '[func_direct_testCase]', funcTestReplace); + funcTestContent = replaceAll(funcTestContent, '[test_case_name]', + funcInfo.name); + funcTestContent = replaceAll(funcTestContent, '[file_introduce_replace]', + rawFileName); + funcTestContent = replaceAll(funcTestContent, '[func_introduce_replace]', + funcInfo.name); + funcTestContent = replaceAll(funcTestContent, + '[input_introduce_replace]', funcInfoParams === '' ? 'void' : funcInfoParams); + funcTestContent = replaceAll(funcTestContent, '[func_return_replace]', + funcInfo.returns); + testContent += funcTestContent; + }); + + let fileContent = replaceAll(testFirstGenTemplate.content, + '[testAbilityFunctions]', testContent); + // 将文件写入out文件夹 + if (!fs.existsSync(out)) { + fs.mkdirSync(out, { recursive: true }); + } + let lowerFileName = rootInfo.fileName.toLocaleLowerCase(); + let fileName = testFirstGenTemplate.name.replace('[fileName]', + lowerFileName); + let filePath = path.join(out, fileName); + fs.writeFileSync(filePath, fileContent); + } } \ No newline at end of file diff --git a/src/vscode_plugin/src/model/h2dtscppmod.ts b/src/vscode_plugin/src/model/h2dtscppmod.ts index 4cc0cc354d0521f5eab8e8d02cce7fbe8384fa16..8fa18ef7ab5811e5090b6524af5c9266b4b1151a 100644 --- a/src/vscode_plugin/src/model/h2dtscppmod.ts +++ b/src/vscode_plugin/src/model/h2dtscppmod.ts @@ -51,23 +51,30 @@ export class H2dtscppMod extends IModel { try { if (this.uri) { // analyze - let funDescList = await parseHeaderFile(this.uri.fsPath); + let parseRes = await parseHeaderFile(this.uri.fsPath); let fileName = path.basename(this.uri.fsPath, '.h'); - Logger.getInstance().debug('parse header file res: ' + funDescList); - Logger.getInstance().debug('parse header file jsonstr: ' + JSON.stringify(funDescList)); + Logger.getInstance().debug('parse header file res: ' + parseRes); + Logger.getInstance().debug('parse header file jsonstr: ' + JSON.stringify(parseRes)); // progress.report({ increment: 50, message: PARSE_COMPLETE }); this.emmitEventForKey(EVENT_PROGRESS, 50, PARSE_COMPLETE); - - let rootInfo: DtscppRootInfo = { - funcs: funDescList.funcs, - rawFilePath: this.uri.fsPath, - fileName: fileName // xxx + + // let rootInfo: DtscppRootInfo = { + // funcs: funDescList.funcs, + // rawFilePath: this.uri.fsPath, + // fileName: fileName // xxx + // }; + + let rootInfo: GenInfo = { + parseObj: parseRes, + rawFilePath: this.uri.fsPath, // e://xxx.h + fileName: path.basename(this.uri.fsPath, '.h') // xxx }; // generator let out = path.dirname(this.uri.fsPath); - genDtsCppFile(rootInfo, out); + // genDtsCppFile(rootInfo, out); + gendtscppFromH(rootInfo); // progress.report({ increment: 100, message: GEN_COMPLETE + out }); this.emmitEventForKey(EVENT_PROGRESS, 100, PARSE_COMPLETE + out); diff --git a/src/vscode_plugin/src/model/h2dtsmod.ts b/src/vscode_plugin/src/model/h2dtsmod.ts index 851541bdb200a92c122b1bf469551c25023d77b9..5f5ad9d2970d17d044049f973471ea9e9ba81412 100644 --- a/src/vscode_plugin/src/model/h2dtsmod.ts +++ b/src/vscode_plugin/src/model/h2dtsmod.ts @@ -60,7 +60,7 @@ export class H2dtsMod extends IModel { fileName: path.basename(this.uri.fsPath, '.h') // xxx }; // generator - let outPath = genDtsFile(rootInfo); + let outPath = genDtsFile(rootInfo, ''); this.emmitEventForKey(EVENT_PROGRESS, 100, PARSE_COMPLETE); } else { Logger.getInstance().error('parse header file error with undefine uri.'); diff --git a/src/vscode_plugin/src/template/dtscpp/dts2cpp_key.ts b/src/vscode_plugin/src/template/dtscpp/dts2cpp_key.ts index 8b4e81404190bfb304f0307ced3e39e09ea51eea..677c9e880371dd6fbb9c6dacc316dcf97c16ab7b 100644 --- a/src/vscode_plugin/src/template/dtscpp/dts2cpp_key.ts +++ b/src/vscode_plugin/src/template/dtscpp/dts2cpp_key.ts @@ -13,7 +13,26 @@ * limitations under the License. */ -export let dts2cpp_key = [ +import { + boolIn, + boolRet, + callbackIn, + doubleIn, + doubleRet, + int32tIn, + int32tRet, + int64tIn, + int64tRet, + objectRet, + stringIn, + stringInUtf16, + stringRet, + stringRetUtf16, + uint32tIn, + uint32tRet +} from "../func_template" + +export let cpp2DtsKey = [ { keys: ['char', 'string'], value: 'string' @@ -30,4 +49,144 @@ export let dts2cpp_key = [ keys: ['void'], value: 'void' } -] \ No newline at end of file +] + +export let h2NapiInKey = [ + { + // 如包含这些字眼,则默认是ObjectIn, 此时框架不做任何处理,由用户自己处理 + keys: ['iterator', 'vector', 'list', 'map', 'array', 'set', 'stack', 'queue', 'deque', 'tuple', 'pair'], + value: '' + }, + { + keys: ['std::function'], + value: callbackIn + }, + { + keys: ['uint32_t', 'size_t', 'uint8_t', 'uint16_t', 'uint64_t', 'unsigned '], + value: uint32tIn + }, + { + keys: ['int64_t', 'long'], + value: int64tIn + }, + { + keys: ['double', 'float'], + value: doubleIn + }, + { + keys: ['char', 'string', 'char8_t'], + value: stringIn + }, + { + keys: ['wchar_t', 'char16_t', 'char32_t'], + value: stringInUtf16 + }, + { + keys: ['bool'], + value: boolIn + }, + { + keys: ['int', 'int32_t', 'short'], + value: int32tIn + } +] + + +export let h2NapiOutKey = [ + { + // 如包含这些字眼,则默认是ObjectOut + keys: ['iterator', 'vector', 'list', 'map', 'array', 'set', 'stack', 'queue', 'deque', 'tuple', 'pair'], + value: objectRet + }, + { + keys: ['uint32_t', 'size_t', 'uint8_t', 'uint16_t', 'uint64_t', 'unsigned '], + value: uint32tRet + }, + { + keys: ['int64_t', 'long'], + value: int64tRet + }, + { + keys: ['double', 'float'], + value: doubleRet + }, + { + keys: ['char', 'string', 'char8_t'], + value: stringRet + }, + { + keys: ['wchar_t', 'char16_t', 'char32_t'], + value: stringRetUtf16 + }, + { + keys: ['bool'], + value: boolRet + }, + { + keys: ['int', 'int32_t', 'short'], + value: int32tRet + } +] + +export let dts2TestValue = [ + { + key: 'number', + value: '1' + }, + { + key: 'string', + value: '"hello"' + }, + { + key: 'boolean', + value: 'true' + }, + { + key: 'Array', + value: '[1,2]' + }, + { + key: 'Array', + value: '["hello","world"]' + }, + { + key: 'Array', + value: '[true,false]' + }, + { + key: 'Map', + value: 'new Map([[0,0],[1,1]])' + }, + { + key: 'Map', + value: 'new Map([[0,"0"],[1,"1"]])' + }, + { + key: 'Map', + value: 'new Map([[0,true],[1,false]])' + }, + { + key: 'Map', + value: 'new Map([["key1","b"],["key2","d"]])' + }, + { + key: 'Map', + value: 'new Map([["key1",false],["key2",true]])' + }, + { + key: 'Map', + value: 'new Map([["key1",0],["key2",1]])' + }, + { + key: 'Set', + value: 'new Set([0,1])' + }, + { + key: 'Set', + value: 'new Set(["a","b"])' + }, + { + key: 'Set', + value: 'new Set([true,false])' + } +] diff --git a/src/vscode_plugin/src/template/func_template.ts b/src/vscode_plugin/src/template/func_template.ts index fc6dab68d88e07147f601a94b95914462ed0f539..be082ac13981abe0c2ebff6506c01409ddcd9c30 100644 --- a/src/vscode_plugin/src/template/func_template.ts +++ b/src/vscode_plugin/src/template/func_template.ts @@ -72,7 +72,7 @@ export let napiFuncInitTemplate = `// [NAPI_GEN]:方法注册后,js方法与nati `; // napi方法定义 -export let napiFuncHTemplate = `/* [NAPI_GEN]:对应[file_introduce_replace]中:[func_introduce_replace]的napi方法, +export let napiFuncHTemplate = `/* [NAPI_GEN]:对应[file_introduce_replace]中:[func_name_replace]的napi方法, * 输入:[input_introduce_replace] * 输出:[func_return_replace] */ @@ -80,7 +80,7 @@ napi_value [func_name_replace](napi_env env, napi_callback_info info); `; // napi方法体实现 -export let napiFuncCppTemplate = `/* [NAPI_GEN]:对应[file_introduce_replace]中:[func_introduce_replace]的napi方法, +export let napiFuncCppTemplate = `/* [NAPI_GEN]:对应[file_introduce_replace]中:[func_name_replace]的napi方法, * 输入:[input_introduce_replace] * 输出:[output_introduce_replace] */ @@ -134,7 +134,7 @@ if (status != napi_ok) { export let stringRet = `napi_value [return_name_replace]Out; /* [NAPI_GEN]: 返回值是字符串时,napi_create_string_utf8用于在原生代码中创建一个新的js字符串。这个函数会根据提供的UTF-8编码的字符串创建一个等价的js字符串 * env: 当前环境的句柄 - * str: 指向以null结尾的UTF-8编码的C字符串的指针,这里以[return_name_replace]举例,用户可根据需求修改 + * str: 指向以null结尾的UTF-8编码的C字符串的指针,这里以"[return_name_replace]"举例,用户可根据需求修改 * length: 字符串的长度,可以是具体的字节数,或者使用特殊的值NAPI_AUTO_LENGTH来让函数自己计算长度(假定字符串以null结尾) * result: 指向napi_value的指针,函数执行成功后这个指针将指向新创建的js字符串 */ @@ -146,6 +146,21 @@ if (status != napi_ok) { } `; +export let stringRetUtf16 = `napi_value [return_name_replace]Out; +/* [NAPI_GEN]: 返回值是字符串时,napi_create_string_utf16用于在原生代码中创建一个新的js字符串。这个函数会根据提供的UTF-16编码的字符串创建一个等价的js字符串 + * env: 当前环境的句柄 + * str: 指向以null结尾的UTF-8编码的C字符串的指针,这里以"[return_name_replace]"举例,用户可根据需求修改 + * length: 字符串的长度,可以是具体的字节数,或者使用特殊的值NAPI_AUTO_LENGTH来让函数自己计算长度(假定字符串以null结尾) + * result: 指向napi_value的指针,函数执行成功后这个指针将指向新创建的js字符串 + */ +status = napi_create_string_utf16(env, u"[return_name_replace]", NAPI_AUTO_LENGTH, &[return_name_replace]Out); +if (status != napi_ok) { + /*错误处理*/ + getErrMessage(status, env, extended_error_info, "napi_create_string_utf16", tag); + return nullptr; +} +`; + export let int64tRet = ` napi_value [return_name_replace]Out; /* [NAPI_GEN]: 返回值是int64类型时,napi_create_int64创建一个包含64位整数(int64_t)的js数值对象 * env: 当前环境的句柄 @@ -301,6 +316,31 @@ if (status != napi_ok) { // delete[] [param_name_replace]In; // remember to delete memory `; +export let stringInUtf16 = `size_t strSize[param_index_replace] = 0; +/* [NAPI_GEN]: napi_get_value_string_utf16用于将Js字符串转换为UTF-16编码的C字符串 + * env: N-API环境的句柄,表示当前的上下文 + * value: 要转换的JavaScript字符串 + * buf: 用于存储结果的字符数组的指针 + * bufsize: 缓冲区大小,以字节为单位 + * result: 转换后的字符串的字节长度(不包括空终止符)。若干buf是NULL,则返回所需的缓冲区大小(包括空终止符) + */ +/* [NAPI_GEN]: buf参数是NULL时,用于获取所需缓冲区大小*/ +status = napi_get_value_string_utf16(env, args[[param_index_replace]], NULL, 0, &strSize[param_index_replace]); +if (status != napi_ok) { + getErrMessage(status, env, extended_error_info, "get value string", tag); + return nullptr; +} +char16_t *[param_name_replace]In = new char16_t[strSize[param_index_replace] + 1]; +/* [NAPI_GEN]: 用于获取字符串*/ +status = napi_get_value_string_utf16(env, args[[param_index_replace]], [param_name_replace]In, strSize[param_index_replace] + 1, &strSize[param_index_replace]); +if (status != napi_ok) { + getErrMessage(status, env, extended_error_info, "get value string", tag); + delete[] [param_name_replace]In; + return nullptr; +} +// delete[] [param_name_replace]In; // remember to delete memory +`; + export let int64tIn = `int64_t [param_name_replace]In = 0; /* [NAPI_GEN]: napi_get_value_int64将一个 napi_value 类型的 js 布尔值转换成一个 C 语言的 int64_t 类型的数值 * env: N-API环境的句柄,表示当前的上下文 @@ -354,8 +394,23 @@ if (status != napi_ok) { } `; +export let callbackIn = ` + napi_value argv; + // Todo:创建要传递给回调函数的参数 + napi_value result; + /** + * env: napi_env 类型的环境变量 + * this_arg: 指向 JavaScript 对象的指针,表示回调函数中的 this 值。如果不需要传递 this 值,则可以设置为 nullptr。 + * func: 指向 JavaScript 回调函数的指针。 + * argc: 传递给回调函数的参数数量。 + * argv: 一个 napi_value 类型的数组,用于存储要传递给回调函数的参数。 + * result: 指向返回值的指针。如果回调函数没有返回值,则可以设置为 nullptr。 + */ + napi_call_function(env, nullptr, args[[param_index_replace]], 1, &argv, &result); +`; + // napi testAbility需要生成的方法模板 -export let testAbilityFuncTemplate = ` /* [NAPI_GEN]:对应[file_introduce_replace]中:[func_introduce_replace]方法的dts接口测试用例 +export let testAbilityFuncTemplate = ` /* [NAPI_GEN]:对应[file_introduce_replace]中:[func_name_replace]方法的dts接口测试用例 * 方法输入: [input_introduce_replace] * 方法输出: [func_return_replace] */