文章目录
- VScode插件之get、set函数自动生成
- 插件名称
- 现有功能
- 功能快捷键使用总结
- 与部分插件的get、set生成对比
- 部分实现效果展示
- 部分实现思路
VScode插件之get、set函数自动生成
初次尝试插件的编写开发,这篇博客也是对自己成果的一个记录,如有不足请指正!
插件名称
扩展搜索(持续更新ing):Get Set generate
链接: link
现有功能
该插件主要是针对TS以及JS的get、set函数的自动生成,具体功能如下:
- 针对TS、JS生成传统面向对象方法的set、get函数或ES6存取器的set、get函数;
- 能够识别函数是否重复,避免重复生成函数(缺失get或set函数其中一个会进行补全);
- 能够对修饰符缺失以及’_'缺失的情况进行提示(所以会对代码规范有一定的要求,不符合要求的属性无法生成函数);
- 能够针对单个属性(鼠标选中完整的单个属性信息)、单个文件(文件内所有类包含的属性)以及在快速选择框中选择属性等三种情况生成函数;
- 能够通过配置项确定是否需要生成函数注释,确定代码生成风格为传统面向对象方法或ES6存取器;
注意:
请在保存代码后食用!请根据提示修改属性信息!
功能快捷键使用总结
前面三个为ES6对应的函数生成,后三个为传统面向对象写法的函数生成
功能 | 快捷键 | 命令 |
---|---|---|
单个属性插入函数 | Ctrl + Win + Shift + S | generateGetterSetter |
文件内所有属性插入函数 | Ctrl + Win + Shift + D | generateGetterSetterForAll |
选择属性生成函数 | Ctrl + Alt + G | SelectGSGenerate |
生成函数是否包含注释 | - | ConfigurationExegesis |
是否生成ES6风格函数 | - | ConfigurationES6 |
(如果和自己vscode的快捷键冲突,可以自行更改或使用命令)
使用命令:Ctrl + Shift + P后输入对应命令
更改快捷键:Ctrl + Shift + P后输入对应命令,点击配置键绑定(下图设置符号),根据自己需求更改快捷键
与部分插件的get、set生成对比
插件名称 | 缺点分析 | 优点分析 | 包含功能 |
---|---|---|---|
TypeScript GetSet | 如果函数已存在或部分已存在仍然会进行插入;有一个属性不规范所有代码无法插入;只能生成TS的函数代码; | - | 生成一个类所有属性的get以及set函数;生成一个类所有属性的get或set函数; |
TypeScript Toolbox | 只能插入private修饰的属性;插入所有属性的函数时只能识别第一个类;只能生成TS的函数代码; | 使用正则匹配分析代码插入速度更快; | 生成一个类所有属性的get以及set函数;生成一个属性的get或set函数;生成一个属性的get以及set函数; |
Getter Setter Ultimate | 代码插入位置在所有类最后,如果存在多个类需要手动修改; | - | 生成选中属性的ES6写法的get以及set函数;生成选中属性的传统写法的get以及set函数; |
TypeScript’s Getters and Setters Object Oriented Programming Style | 选中内容不完全时会生成错误信息;只能生成TS的函数代码; | - | 生成选中属性的的get以及set函数; |
部分实现效果展示
(只展示了部分实现效果!!!)
- 针对ES6存取器
-
单个属性插入函数:
-
选择属性生成函数
选择框内选择需要生成对应函数的属性
具体实现效果类似于单个属性插入函数效果,只是插入内容变多啦,不展示了
-
- 针对传统面向对象:
- 文件内所有属性插入函数(展示了部分生成结果)
因为部分属性的函数已存在(如tel),故会进行如下提示:
- 文件内所有属性插入函数(展示了部分生成结果)
- 修改配置:生成函数是否包含注释(默认包含注释)
Ctrl + Shift + P后输入命令ConfigurationExegesis
提示后即修改成功
- 修改配置:是否生成ES6风格函数(默认为ES6写法)
部分实现思路
-
在activate函数中,注册了6个命令,每个命令对应一种生成 getter 和 setter
函数的方式(如单个属性、所有属性、选择属性等)。 -
用户在 VSCode中通过快捷键或命令面板执行相应的命令。根据用户执行的命令,调用对应的函数(如GSGenerateCommandES6、SelectGSGenerateES6等)。
-
在函数执行过程中,通过ClassAnalyzer类获取当前文档中类和属性的相关信息(使用ts-morph库来解析 TypeScript 或JavaScript 文件为 AST)。其中主要通过getPropertyInformation函数获取所需要用到的属性以及函数信息:
-
展示信息获取部分主要实现代码:
sourceFile.getClasses().forEach(classDecl => {
const className = classDecl.getName();
if (className) {
const classInfo: ClassInfo = {
name: className,
position: 0,
properties: [],
propertyTypes: [],
isNonStandard: [],
hasSetter: [],
hasGetter: []
};
// 创建属性名到索引的映射表
const propertyNameToIndexMap = new Map<string, number>();
//将类中属性对应的hasSetter 、hasGetter函数设置为否(即默认均不存在函数)
const propertyCount = classDecl.getProperties().length;
classInfo.hasSetter = new Array(propertyCount).fill(false);
classInfo.hasGetter = new Array(propertyCount).fill(false);
//获取属性相关信息
classDecl.getProperties().forEach((propDecl, index) => {
const propName = propDecl.getName();
const propType = propDecl.getType().getText();
const modifiers = this.getModifiers(propDecl);
!propName.startsWith('_') ? classInfo.isNonStandard.push(2) : 0;
classInfo.isNonStandard.push(modifiers.length <= 0 ? 1 : 0);
let trimmedName = propName.startsWith('_') ? propName.substring(1) : propName;
classInfo.properties.push(trimmedName);
trimmedName = trimmedName.startsWith('#') ? trimmedName.substring(1) : trimmedName;
classInfo.propertyTypes.push(propType);
propertyNameToIndexMap.set(trimmedName, index);
//将函数插入在各个类中最后一个的下方
if (index === propertyCount - 1) {
classInfo.position = propDecl.getEndLineNumber();
}
});
//获取实例对象,判断是否已经生成了getter\setter函数(针对ES6)
const processInstanceMembers = async () => {
await Promise.all(
classDecl.getInstanceMembers().map(async (member) => {
const propertyIndex = propertyNameToIndexMap.get(member.getName());
if (propertyIndex !== undefined && propertyIndex !== -1) {
if (member.getKind() === SyntaxKind.GetAccessor) {
classInfo.hasGetter[propertyIndex] = true;
} else if (member.getKind() === SyntaxKind.SetAccessor) {
classInfo.hasSetter[propertyIndex] = true;
}
}
})
);
};
//获取方法,判断是否生成了传统面向对象写法的set\get函数
const processMethods = async () => {
await Promise.all(
classDecl.getMethods().map(async (methodDecl) => {
const methodName = methodDecl.getName();
// 检查方法名是否符合 set+prop 或 get+prop 的模式
if (methodName.startsWith('set') || methodName.startsWith('get')) {
const propPart = methodName.slice(3); // 去掉前缀 "set" 或 "get"
const lowerCasePropPart = propPart.charAt(0).toLowerCase() + propPart.slice(1);
const propertyIndex = propertyNameToIndexMap.get(lowerCasePropPart);
if (propertyIndex !== undefined && propertyIndex !== -1) {
if (methodName.startsWith('set')) {
classInfo.hasSetter[propertyIndex] = true;
} else {
classInfo.hasGetter[propertyIndex] = true;
}
}
}
})
);
};
}
});
-
根据返回的属性信息和语言类型,生成 getter 和 setter 函数代码,并在生成函数过程中对函数重复情况进行判断提示。
-
如下为生成文件内所有属性的插入实现部分(插入成功后,保存文件):
editor.edit(editBuilder => {
//一个一个属性生成并插入
classList.forEach(classInfo => {
classInfo.properties.forEach((prop, index) => {
const positionEnd = new vscode.Position(classInfo.position, 0);
const getterSetterCode = func.getsetfinalES6(isTS,classInfo.isNonStandard[index], prop, classInfo.propertyTypes[index], classInfo.hasGetter[index],classInfo.hasSetter[index]);
if(getterSetterCode === ''){
vscode.window.showErrorMessage(`The function for this attribute already exists : ${prop} `);
}
else if(getterSetterCode !== '-1')editBuilder.insert(positionEnd, `\n${getterSetterCode}\n`);
})
});
}).then(success => {
if (!success) {
vscode.window.showErrorMessage('Failed to insert getter and setter methods.');
}
else{
document.save();
};
});