add vs plugin code

Signed-off-by: gou-jingjing <goujingjing@kaihong.com>
This commit is contained in:
gou-jingjing 2024-10-21 17:50:44 +08:00
parent 88b086ee8e
commit 303e29a735
6 changed files with 708 additions and 0 deletions

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2022 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
*
* 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,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { parse } from 'path';
export function search(ss: any, data: any) {
ss = replaceAll(ss, '\\.', '\\.');
let reg = new RegExp(ss);
let tt = reg.exec(data);
if (tt === null || tt === undefined) {
return null;
}
//let ret = { 'regs': [] };
let ret: { regs: number[][] } = { regs: [] };
for (let i = 0; i < tt.length; i++) {
let p = data.indexOf(tt[i]);
if (tt[i] === null || tt[i] === undefined) {
ret.regs.push([-1, -1]);
}
else {
ret.regs.push([p, p + tt[i].length]);
}
}
return ret;
}
export function match(ss: string, data: string) {
let tt = search(ss, data);
if (tt !== null && tt !== undefined && tt.regs[0][0] === 0) {
return tt;
}
return null;
}
export function removeReg(data: string, reg: any[]) {
return data.substring(0, reg[0]) + data.substring(reg[1], data.length);
}
export function getReg(data: string, reg: any[]) {
return data.substring(reg[0], reg[1]);
}
export function getFileInPath(tpath: string) {
return parse(tpath).base;
}
export function getPathInPath(tpath: string) {
return parse(tpath).dir;
}
export function all(sfrom: string | RegExp) {
return new RegExp(sfrom, 'g');
}
export function replaceAll(ss: string, sfrom: string, sto: string) {
return ss.replace(all(sfrom), sto);
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2022 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
*
* 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,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export function replaceAll(s: string, sfrom: string, sto: any) {
while (s.indexOf(sfrom) >= 0) {
s = s.replace(sfrom, sto);
}
return s;
}
export function getTab(tabLv: number) {
let tab = '';
for (let i = 0; i < tabLv; ++i) {
tab += ' ';
}
return tab;
}
export function removeComments(text: string): string {
// 移除单行注释
const singleLineRegex = /\/\/.*$/gm;
// 移除多行注释
const multiLineRegex = /\/\*[\s\S]*?\*\//gm;
// 替换单行注释为空
let noComments = text.replace(singleLineRegex, '');
// 替换多行注释为空
noComments = noComments.replace(multiLineRegex, '');
return noComments;
}
// 随机生成整数
export function generateRandomInteger(min: number, max: number) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// 去除字符串前面的空格
export function removeTab(str: string) {
str = replaceAll(str, '\r\n', '');
str = replaceAll(str, '\r', '');
str = replaceAll(str, '\n', '');
while (str[0] === ' ') {
str = str.replace(' ' , '')
}
return str;
}

View File

@ -0,0 +1,74 @@
export interface FileTemp {
name: string;
content: string;
}
export interface DirTemp {
name: string;
files: FileTemp[];
dirs: DirTemp[];
}
export interface ParamObj {
type: string;
name: string;
}
export interface FuncObj {
name: string;
returns: string;
parameters: ParamObj[];
}
export interface ParseObj {
funcs: FuncObj[];
}
export interface ServiceRootInfo {
serviceName: string,
funcs: FuncObj[],
serviceId: string,
versionTag: string,
}
export interface HdfRootInfo {
driverName: string; // driverName即为文件名字
funcs: FuncObj[];
versionTag: string; // 默认4.1
}
export interface FuncTransferMap {
fromType: string;
tranferContent: string[];
}
// h2dtscpp
export interface DtscppRootInfo {
funcs: FuncObj[];
rawFilePath: string;
fileName: string;
}
export interface FuncInfo {
name: string,
params: ParamObj[],
retType: string,
genName: string,
}
// 保存 typedefine int cJSON_bool
export interface TypeList {
typeName: string; // cJSON_bool
typeBody: string; // int
}
export interface InterfaceBody {
params: ParamObj[];
funcs: FuncObj[];
}
// 保存 typedefine struct cJSON { int a; double b; string c;}
export interface InterfaceList {
interfaceName: string;
interfaceBody: InterfaceBody;
}

View File

@ -0,0 +1,188 @@
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
import * as path from 'path';
import * as ts from 'typescript';
import { parseHeaderFile } from './parsec';
import { DtscppRootInfo } from './datatype';
import { parseTsFile } from './parsets';
import { genServiceFile } from './gensa';
import { genDtsFile } from './gendts';
import { genHdfFile } from './genhdf';
import { genDtsCppFile } from './gendtscpp';
import fs = require('fs');
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
// Use the console to output diagnostic information (console.log) and errors (console.error)
// This line of code will only be executed once when your extension is activated
console.log('Congratulations, your extension "helloworld-sample" is now active!');
vscode.window.showInformationMessage('Congratulations, your extension "helloworld-sample" is now active!');
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
const h2sa3_2 = vscode.commands.registerCommand('extension.h2sa3-2', async (uri) => {
// The code you place here will be executed every time your command is executed
vscode.window.showInformationMessage('extension.h2sa3-2!');
if (uri && uri.fsPath) {
vscode.window.showInformationMessage('extension.h2sa3-2: h path: ' + uri.fsPath);
let testContent = 'test vs plugin;'
let paths = path.dirname(uri.fsPath);
let filePath = path.join(paths, 'test222.txt');
fs.writeFileSync(filePath, testContent);
// parse
let funDescList = await parseHeaderFile(uri.fsPath);
console.log('parse header file res: ', funDescList);
console.log('parse header file jsonstr: ', JSON.stringify(funDescList));
// generator
let out = path.dirname(uri.fsPath);
let serviceName = path.basename(uri.fsPath, '.h');
let rootInfo = {
serviceName: serviceName,
funcs: funDescList.funcs,
serviceId: '19000',
versionTag: '3.2'
};
genServiceFile(rootInfo, out);
vscode.window.showInformationMessage('h2sa3_2 end!');
console.info('h2sa3_2 end!')
}
// Display a message box to the user
vscode.window.showInformationMessage('h2sa3_2!');
});
context.subscriptions.push(h2sa3_2);
const h2sa4_1 = vscode.commands.registerCommand('extension.h2sa4-1', async (uri) => {
// The code you place here will be executed every time your command is executed
if (uri && uri.fsPath) {
// parse
let funDescList = await parseHeaderFile(uri.fsPath);
console.log('parse header file res: ', funDescList);
console.log('parse header file jsonstr: ', JSON.stringify(funDescList));
// generator
let out = path.dirname(uri.fsPath);
let serviceName = path.basename(uri.fsPath, '.h');
let rootInfo = {
serviceName: serviceName,
funcs: funDescList.funcs,
serviceId: '19000',
versionTag: '4.1'
};
genServiceFile(rootInfo, out);
console.info('h2sa4_1 end!')
}
// Display a message box to the user
vscode.window.showInformationMessage('h2sa4_1!');
});
context.subscriptions.push(h2sa4_1);
const h2hdf4_1 = vscode.commands.registerCommand('extension.h2hdf4-1', async (uri) => {
// The code you place here will be executed every time your command is executed
if (uri && uri.fsPath) {
// analyze
let funDescList = await parseHeaderFile(uri.fsPath);
console.log('parse header file res: ', funDescList);
console.log('parse header file jsonstr: ', JSON.stringify(funDescList));
// generator
let out = path.dirname(uri.fsPath);
let driverName = path.basename(uri.fsPath, '.h').toLocaleLowerCase();
let rootInfo = {
driverName: driverName,
funcs: funDescList.funcs,
versionTag: '4.1'
};
genHdfFile(rootInfo, out);
console.info('h2hdf4_1 end!')
}
// Display a message box to the user
vscode.window.showInformationMessage('h2hdf4_1!');
});
context.subscriptions.push(h2hdf4_1);
const h2dts = vscode.commands.registerCommand('extension.h2dts', async (uri) => {
// The code you place here will be executed every time your command is executed
if (uri && uri.fsPath) {
// parse
let funDescList = await parseHeaderFile(uri.fsPath);
console.log('parse header file res: ', funDescList);
console.log('parse header file jsonstr: ', JSON.stringify(funDescList));
let fileName = path.basename(uri.fsPath, '.h');
let rootInfo: DtscppRootInfo = {
funcs: funDescList.funcs,
rawFilePath: uri.fsPath, // e://xxx.h
fileName: fileName // xxx
};
// generator
let out = path.dirname(uri.fsPath);
genDtsFile(rootInfo, out);
}
// Display a message box to the user
vscode.window.showInformationMessage('h2dts!');
});
context.subscriptions.push(h2dts);
const h2dtscpp = vscode.commands.registerCommand('extension.h2dtscpp', async (uri) => {
// The code you place here will be executed every time your command is executed
if (uri && uri.fsPath) {
// let rawContent = fs.readFileSync(uri.fsPath);
// parse
let funDescList = await parseHeaderFile(uri.fsPath);
let fileName = path.basename(uri.fsPath, '.h');
console.log('parse header file res: ', funDescList);
console.log('parse header file jsonstr: ', JSON.stringify(funDescList));
let rootInfo: DtscppRootInfo = {
funcs: funDescList.funcs,
rawFilePath: uri.fsPath, // e://xxx.h
fileName: fileName // xxx
};
// generator
let out = path.dirname(uri.fsPath);
genDtsCppFile(rootInfo, out);
}
// Display a message box to the user
vscode.window.showInformationMessage('h2dtscpp!');
});
context.subscriptions.push(h2dtscpp);
const dts2cpp = vscode.commands.registerCommand('extension.dts2cpp', (uri) => {
// The code you place here will be executed every time your command is executed
console.log('uri is : ' + uri.fsPath );
if (uri && uri.fsPath) {
const extname = path.extname(uri.fsPath);
const filename = path.basename(uri.fsPath);
console.log('get filename ' );
if (filename.endsWith('.d.ts')) {
// Display a message box to the user
// parseTsFile(uri.fsPath)
let res = parseTsFile(uri.fsPath);
console.info("res: " + JSON.stringify(res));
vscode.window.showInformationMessage('dts2cpp!');
} else {
console.log('not dts uri is : ' + uri.fsPath );
// Display a message box to the user
vscode.window.showInformationMessage(`${uri.fsPath} is not a .d.ts file!`);
}
// generator
}
});
context.subscriptions.push(dts2cpp);
}

View File

@ -0,0 +1,94 @@
import * as vscode from 'vscode';
import * as path from 'path';
import * as ts from 'typescript';
import { ParamObj, FuncObj, ParseObj } from './datatype'
import fs = require('fs');
export function parseHeaderFile(filePath: string): Promise<ParseObj> {
return new Promise((resolve, reject) => {
let parseRes: ParseObj = { funcs: [] };
// 读取文件内容
fs.readFile(filePath, 'utf8', (err: NodeJS.ErrnoException | null, data: string) => {
if (err) {
vscode.window.showErrorMessage(`Error reading file: ${err.message}`);
reject(err);
return;
}
// 使用正则表达式提取函数定义
const functionRegex1 = /([a-zA-Z_]\w*\s+)+([*a-zA-Z_]\w+)\s*\(([^)]*)\)\s*(?={|;)/g;
const functionRegex2 = /(\w+\s*\(.*?\)\s+)(\w+)\s*\((.*?)\);\s*/g;
let functions = data.match(functionRegex1) || [];
if (functions.length <= 0) {
console.info("use functionRegex2");
functions = data.match(functionRegex2) || [];
}
const functionDetails: (FuncObj | null)[] = functions.map(func => {
// 函数解析逻辑...
// 普通类型的函数识别
if (func.trim().startsWith('typedef')) {
func = func.replace('typedef', '');
}
let parts = func.trim().match(/([a-zA-Z_]\w+)\s+\(*([*a-zA-Z_]\w+)\)*\s*\(([^)]*)\)/);
if (!parts) {
console.info("use regex2");
parts = func.trim().match(/(\w+\s*\(.*?\)\s+)(\w+)\s*\((.*?)\);\s*/);
}
if (parts) {
let index = 1;
let returnType = parts[index].trim();
let functionName = parts[index + 1].trim();
let paramList = parts[index + 2].split(',');
if (parts[index].trim() === 'typedef') {
console.info("typedef -------------", parts);
returnType = parts[index + 1].trim();
functionName = parts[index + 2].trim();
paramList = parts[index + 3].split(',');
}
let paramResList = [];
for (let i=0; i<paramList.length; i++) {
let paramItem = paramList[i].trim();
let lastTabIndex = paramItem.lastIndexOf(' ');
let paramType = paramItem.substring(0, lastTabIndex).trim();
let paramName = paramItem.substring(lastTabIndex, paramItem.length).trim();
paramResList.push({
name: paramName,
type: paramType,
})
}
console.info(`ret: ${returnType} func: ${functionName} params:(${paramResList.map(ditem => {
return ' type: ' + ditem.type + ', ' + 'name: ' + ditem.name;
})})`)
let funcRes: FuncObj = {
name: functionName,
returns: returnType,
parameters: paramResList
}
return funcRes;
}
return null;
})
.filter(detail => detail !== null);
if (functionDetails.length > 0) {
parseRes.funcs = [...functionDetails.filter((funcItem) : funcItem is FuncObj => funcItem !== null)];
const message = functionDetails.map(detail =>
`Function: ${detail!.name},
Return Type: ${detail!.returns},
Parameters: (${detail!.parameters.map(ditem => {
return ' type: ' + ditem.type + ', ' + 'name: ' + ditem.name;
})})`
).join('\n');
console.info(` return parseRes: ${JSON.stringify(parseRes)}`);
vscode.window.showInformationMessage(message);
resolve(parseRes);
} else {
vscode.window.showInformationMessage('No functions found.');
}
});
});
}

View File

@ -0,0 +1,221 @@
import * as vscode from 'vscode';
import * as path from 'path';
import * as ts from 'typescript';
import { json } from 'stream/consumers';
import internal = require('stream');
const fs = require('fs');
interface TypeArguments {
pos: number;
members: [];
}
interface NameObj {
pos: number;
escapedText: string;
}
interface TypeObj {
pos: number;
escapedText: string;
}
interface MemberObj {
pos: number;
name: NameObj;
type: TypeObj;
}
export interface ParamItem {
type: string;
name: string;
}
export interface TypeItem {
name: string;
subItemList: ParamItem[];
}
export interface EnumItem {
name: string;
subItemList: string[];
}
export interface FuncItem {
name: string;
returns: string;
parameters: ParamItem[];
}
export interface ClassObj {
name: string;
funcs: FuncItem[];
}
export interface ParseObj {
classList: ClassObj[];
enumList: EnumItem[];
typeList: TypeItem[];
}
let gchecker: ts.TypeChecker;
function getTypeAliasSubtypes(typeAlias: ts.TypeAliasDeclaration, list: ParamItem[]) {
// 检查类型是否为类型节点
const typeNode = typeAlias.type;
// console.log('getTypeAliasSubtypes');
try {
if (ts.isUnionTypeNode(typeNode)) {
// 如果是联合类型Union Type遍历它的子类型
console.log('isUnionTypeNode');
return typeNode.types.map(type => JSON.stringify(type.getText()));
} else if (ts.isIntersectionTypeNode(typeNode)) {
// 如果是交叉类型Intersection Type遍历它的子类型
console.log('isIntersectionTypeNode');
return typeNode.types.map(type => JSON.stringify(type.decorators));
} else if (ts.isTypeLiteralNode(typeNode)) {
// 如果是类型字面量Type Literal遍历它的属性
console.log('isTypeLiteralNode');
return typeNode.members.map(member => {
let nameStr = JSON.stringify(member.name);
let nameObj = JSON.parse(nameStr);
let propType = gchecker.getTypeAtLocation(member);
let typeStr = gchecker.typeToString(propType);
let kindStr = typeStr;
list.push({
type: kindStr,
name: nameObj.escapedText,
})
return `(${nameObj.escapedText}:${kindStr})`;
});
}
// 处理其他类型
return [JSON.stringify(typeNode)];
} catch (error) {
console.error('Error processing node:', error);
}
return [];
}
export function parseTsFile(filePath: string): ParseObj {
let parseRes: ParseObj = {
classList: [],
enumList: [],
typeList: [],
}
function visitor(node: ts.Node) {
if (ts.isClassDeclaration(node) && node.name) {
console.log(`Class: ${node.name.text}, ${node.members}`);
let classItem: ClassObj = {
name: node.name.text,
funcs: [],
};
try {
node.members.forEach(member => {
// console.log(`Member: ${JSON.stringify(member)}`)
if (ts.isMethodDeclaration(member) && member.name) {
const methodstr = member.name ? JSON.stringify(member.name) : 'noname';
const methodObject = JSON.parse(methodstr);
const methodName = methodObject.escapedText;
console.log(`memberName: ${methodName} `);
let returnStr = 'void';
if (member.type) {
let returnObjStr = JSON.stringify(member.type);
// console.log(`returnObjStr: ${returnObjStr} `);
let returnObj = JSON.parse(returnObjStr);
if (returnObj.typeName) {
let returnNameStr = JSON.stringify(returnObj.typeName);
let returnName = JSON.parse(returnNameStr).escapedText;
let returnArgsStr = JSON.stringify(returnObj.typeArguments);
let returnArgsObj = JSON.parse(returnArgsStr);
const returnArgs = returnArgsObj.map((argItem: TypeArguments) => {
let argStr = argItem.members.map((memItem: MemberObj) => {
let memNameStr = '';
let memTypeStr = 'void';
if (memItem.name) {
memNameStr = memItem.name.escapedText;
}
if (memItem.type) {
memTypeStr = memItem.type.escapedText ? memItem.type.escapedText : 'any';
}
return `${memNameStr}: ${memTypeStr}`;
}).join(', ');
return argStr;
})
returnStr = `${returnName} <${returnArgs}>`
};
}
let paramResList: ParamItem[] = [];
const params = member.parameters.map(param => {
// `${param.name}: ${param.type ? param.type : 'any'}`
let paramObjStr = JSON.stringify(param.name);
let paramStr = JSON.parse(paramObjStr).escapedText;
let paramTypeStr: string = 'any';
if (param.type) {
let paramTypeObjStr = JSON.stringify(param.type);
// console.log(`paramTypeObjStr: ${paramTypeObjStr} }`);
if (JSON.parse(paramTypeObjStr).typeName) {
paramTypeStr = JSON.parse(paramTypeObjStr).typeName.escapedText;
}
}
paramResList.push({
name: paramStr,
type: paramTypeStr,
})
return `${paramStr}: ${paramTypeStr}`
}).join(', ');
console.log(` Method: ${methodName}, Return Type: ${returnStr}, Parameters: ${params}`);
classItem.funcs.push({
name: methodName,
returns: returnStr,
parameters: paramResList,
});
parseRes.classList.push(classItem);
}
});
} catch (error) {
console.error('Error processing node:', error);
}
} else if (ts.isEnumDeclaration(node) && node.name) {
try {
console.log(`Enum: ${node.name.text}`);
let enumItem: EnumItem = {
name: node.name.text,
subItemList: [],
};
// console.log(`Enum: ${node.name.text}, ${node.members.length}`);
node.members.forEach(member => {
const memJsonStr = JSON.stringify(member.name);
const memJsonObj = JSON.parse(memJsonStr);
// console.log(`Member: ${memJsonObj.escapedText}`)
enumItem.subItemList.push(memJsonObj.escapedText);
})
parseRes.enumList.push(enumItem);
} catch (error) {
console.error('Error processing node:', error);
}
} else if (ts.isTypeAliasDeclaration(node) && node.name) {
console.log(`Type: ${node.name.text}`);
let typeItem: TypeItem = {
name: node.name.text,
subItemList: [],
};
// console.log(`Type: ${node.name.text}, ${node.typeParameters} ${typeof(node.type)}`);
const subtypes = getTypeAliasSubtypes(node, typeItem.subItemList);
parseRes.typeList.push(typeItem);
console.log(`subtypes : ${subtypes}`);
}
ts.forEachChild(node, visitor);
}
const sourceCode = fs.readFileSync(filePath, 'utf8');
const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest);
const program = ts.createProgram([filePath], {});
gchecker = program.getTypeChecker();
ts.forEachChild(sourceFile, visitor);
return parseRes;
}