UNPKG

@hadss/hmrouter-plugin

Version:

HMRouter Compiler Plugin

257 lines (224 loc) 8.83 kB
/* * 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: [] };