@hadss/hmrouter-plugin
Version:
HMRouter Compiler Plugin
257 lines (224 loc) • 8.83 kB
text/typescript
/*
* Copyright (c) 2024 Huawei Device 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 { appTasks } from '@ohos/hvigor-ohos-plugin';
import {
BaseAnalyzeResult,
ExtensionContext,
Logger,
PluginExtension,
registerPluginExtension
} from '@hadss/hmrouter-plugin';
import { ClassDeclaration, Expression, PropertyAssignment, SourceFile, SyntaxKind } from 'ts-morph';
interface RouterInfo {
name: string;
pageSourceFile: string;
buildFunction: string;
customData: Record<string, any>;
}
interface MyExtensionContext extends ExtensionContext {
customPages?: RouterInfo[];
routerMap: RouterInfo[];
}
interface MyAnalyzeResult extends BaseAnalyzeResult {
[key: string]: any;
}
// 示例1: RouterParam注解分析器
export class RouterParamAnalyzer {
readonly name = 'RouterParamAnalyzer';
analyze(sourceFile: SourceFile, filePath: string, context: MyExtensionContext): void {
Logger.debug('', `开始分析RouterParam注解: ${filePath}`);
// 获取所有ExpressionStatement以获取struct关键字后面的组件名称
const viewNameArr = sourceFile
.getChildrenOfKind(SyntaxKind.ExpressionStatement)
.map((node) => node.getText())
.filter((text) => text !== 'struct');
// 解析结构体声明中的RouterParam注解
sourceFile.getChildrenOfKind(SyntaxKind.MissingDeclaration).forEach((node, index) => {
node.getChildrenOfKind(SyntaxKind.Decorator).forEach((decorator) => {
if (decorator.getName() === "RouterParam") {
// 解析RouterParam注解的参数
const result: MyAnalyzeResult = {
name: viewNameArr[index],
annotation: decorator.getName(),
sourceFilePath: filePath
};
// 解析装饰器参数
decorator.getArguments().forEach((arg) => {
const objLiteral = arg.asKind(SyntaxKind.ObjectLiteralExpression);
if (objLiteral) {
objLiteral.getProperties().forEach((prop) => {
if (prop.getKind() === SyntaxKind.PropertyAssignment) {
const propertyAssignment = prop as PropertyAssignment;
const propertyName = propertyAssignment.getName();
const initializer = propertyAssignment.getInitializer();
if (initializer) {
// 将解析结果添加到result对象
result[propertyName] = this.parsePrimitiveValue(initializer);
}
}
});
}
});
// 如果需要后续保存到路由表中请调用addAnalyzeResults添加分析结果
// context.addAnalyzeResults(result);
// 为组件添加模板数据,用于代码生成
context.addTemplateData(result.name, {
paramType: result['paramType'] || 'default',
isCustomParam: true,
customParams: result['params'] || [],
sourceFile: filePath
});
Logger.debug('', `发现RouterParam注解: ${result.name}`);
}
});
});
}
private parsePrimitiveValue(value: Expression): any {
let propertyValue;
switch (value.getKind()) {
case SyntaxKind.StringLiteral:
propertyValue = value.asKind(SyntaxKind.StringLiteral)?.getLiteralValue();
break;
case SyntaxKind.NumericLiteral:
propertyValue = value.asKind(SyntaxKind.NumericLiteral)?.getLiteralValue();
break;
case SyntaxKind.TrueKeyword:
propertyValue = true;
break;
case SyntaxKind.FalseKeyword:
propertyValue = false;
break;
case SyntaxKind.ArrayLiteralExpression:
propertyValue = value
.asKind(SyntaxKind.ArrayLiteralExpression)
?.getElements()
.map((item) => {
if (item.getKind() === SyntaxKind.StringLiteral) {
return item.asKind(SyntaxKind.StringLiteral)?.getLiteralValue();
}
return null;
})
.filter(item => item !== null);
break;
}
return propertyValue;
}
}
// 示例2: CustomPage注解分析器
export class CustomPageAnalyzer {
readonly name = 'CustomPageAnalyzer';
analyze(sourceFile: SourceFile, filePath: string, context: MyExtensionContext): void {
Logger.debug('', `开始分析CustomPage注解: ${filePath}`);
// 分析使用@CustomPage注解的类
sourceFile.getClasses().forEach((cls: ClassDeclaration) => {
cls.getDecorators().forEach(decorator => {
if (decorator.getName() === 'CustomPage') {
const className = cls.getName() || '';
// 创建分析结果
const result: MyAnalyzeResult = {
name: className,
annotation: 'CustomPage',
sourceFilePath: filePath
};
// 解析装饰器参数
decorator.getArguments().forEach((arg) => {
const objLiteral = arg.asKind(SyntaxKind.ObjectLiteralExpression);
if (objLiteral) {
objLiteral.getProperties().forEach((prop) => {
if (prop.getKind() === SyntaxKind.PropertyAssignment) {
const propertyAssignment = prop as PropertyAssignment;
const propertyName = propertyAssignment.getName();
const initializer = propertyAssignment.getInitializer();
if (initializer && initializer.getKind() === SyntaxKind.StringLiteral) {
result[propertyName] = initializer.asKind(SyntaxKind.StringLiteral)?.getLiteralValue();
}
}
});
}
});
// 添加分析结果
context.addAnalyzeResults(result);
// 存储自定义页面路径信息
const customPages = context.customPages || [];
customPages.push(result);
context.customPages = customPages;
Logger.debug('', `发现CustomPage注解: ${className}, pageUrl: ${result['pageUrl']}`);
}
});
});
}
}
// 插件扩展类
export class CustomPluginExtension extends PluginExtension<MyExtensionContext> {
get name(): string {
return 'CustomPluginExtension';
}
// 提供注解分析器
afterAnnotationAnalysis(sourceFile: SourceFile, filePath: string, context: MyExtensionContext): void {
const analyzers = [new RouterParamAnalyzer(), new CustomPageAnalyzer()];
for (const analyzer of analyzers) {
analyzer.analyze(sourceFile, filePath, context);
}
}
// 代码生成阶段,可以使用RouterParam注解分析结果
afterCodeGeneration(context: MyExtensionContext): void {
// 获取所有模板数据
const templateDataMap = context.getTemplateDataMap();
// 示例: 输出找到的RouterParam数据
for (const [componentName, templateData] of templateDataMap.entries()) {
if (templateData.isCustomParam) {
Logger.info(
this.name,
`组件 ${componentName} 将使用自定义参数类型: ${templateData.paramType}`
);
// 实际场景可以在此生成额外的代码
}
}
}
// 路由表构建阶段,将CustomPage注解分析结果添加到路由表
afterRouterMapBuilding(context: MyExtensionContext): void {
// 从私有存储获取CustomPage分析结果
const customPages = context.customPages || [];
// 将CustomPage添加到路由表
for (const page of customPages) {
const pageUrl = page.customData['pageUrl'];
if (pageUrl) {
// 检查路由表中是否已存在该路径
const existingRoute = context.routerMap.find(route => route.customData.pageUrl === pageUrl);
if (!existingRoute) {
// 创建新的路由项并添加到路由表
context.routerMap.push({
name: pageUrl,
buildFunction: page.name,
pageSourceFile: page.pageSourceFile,
customData: {
...page.customData,
}
});
Logger.info(
this.name,
`添加自定义页面到路由表: ${pageUrl} -> ${page.name}`
);
}
}
}
}
}
// 注册扩展
registerPluginExtension(new CustomPluginExtension());
export default {
system: appTasks,
plugins: []
};