UNPKG

@hadss/hmrouter-plugin

Version:

HMRouter Compiler Plugin

345 lines (344 loc) 15.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TaskManager = void 0; const micromatch_1 = __importDefault(require("micromatch")); const constants_1 = require("../../hmrouter_extension/constants"); const PluginError_1 = require("../../hmrouter_extension/error/PluginError"); const extension_1 = require("../extension"); const utils_1 = require("../utils"); const TaskStage_1 = require("./TaskStage"); const annotationConfig = { [constants_1.AnnotationConstants.ANIMATOR_ANNOTATION]: { prefix: constants_1.PrefixConstants.ANIMATOR_PREFIX, propertyName: 'animatorName', resultType: 'HMAnimatorResult', }, [constants_1.AnnotationConstants.INTERCEPTOR_ANNOTATION]: { prefix: constants_1.PrefixConstants.INTERCEPTOR_PREFIX, propertyName: 'interceptorName', resultType: 'HMInterceptorResult', }, [constants_1.AnnotationConstants.LIFECYCLE_ANNOTATION]: { prefix: constants_1.PrefixConstants.LIFECYCLE_PREFIX, propertyName: 'lifecycleName', resultType: 'HMLifecycleResult', }, [constants_1.AnnotationConstants.SERVICE_ANNOTATION]: { prefix: constants_1.PrefixConstants.SERVICE_PREFIX, propertyName: 'serviceName', resultType: 'HMServiceResult', }, [constants_1.AnnotationConstants.SERVICE_PROVIDE_ANNOTATION]: { prefix: constants_1.PrefixConstants.SERVICE_PROVIDE_PREFIX, propertyName: 'serviceName', resultType: 'HMServiceResult', }, }; class TaskManager { constructor(context, moduleExtensions) { this.extensionManager = extension_1.ExtensionManager.getInstance(); this.moduleExtensions = moduleExtensions || []; this.context = context; } executeStage(stage) { switch (stage) { case TaskStage_1.TaskStage.AFTER_ANNOTATION_ANALYSIS: this.executeAnnotationAnalysis(); break; default: this.getExtensions().forEach((extension) => { const methodName = stage.toString(); const extensionMethods = { 'afterInitialize': extension.afterInitialize?.bind(extension), 'afterCodeGeneration': extension.afterCodeGeneration?.bind(extension), 'afterRouterMapBuilding': extension.afterRouterMapBuilding?.bind(extension), 'afterConfigUpdate': extension.afterConfigUpdate?.bind(extension), 'afterObfuscationProcess': extension.afterObfuscationProcess?.bind(extension), 'afterResourceProcess': extension.afterResourceProcess?.bind(extension), 'afterCompletion': extension.afterCompletion?.bind(extension) }; const method = extensionMethods[methodName]; if (method) { method(this.context); } }); break; } } executeAnnotationAnalysis() { this.routerContext = this.context; const extensions = this.getExtensions(); this.routerContext.scanFiles.forEach((file) => { this.routerContext.setCurrentFilePath(file); const sourceFile = utils_1.TsAstUtil.getSourceFile(file); extensions.forEach((extension) => { if (extension.afterAnnotationAnalysis) { extension.afterAnnotationAnalysis(sourceFile, file, this.routerContext); } }); }); this.routerContext.setCurrentFilePath(''); this.generateRouterFilePath(); this.buildRouterMap(); this.validateTemplateData(); } getExtensions() { const globalExtensions = this.extensionManager.getExtensions(); const allExtensions = globalExtensions.concat(this.moduleExtensions); return allExtensions.sort((a, b) => { const aIsHMRouter = a.name?.includes('HMRouter') || false; const bIsHMRouter = b.name?.includes('HMRouter') || false; if (aIsHMRouter && !bIsHMRouter) { return -1; } if (!aIsHMRouter && bIsHMRouter) { return 1; } return 0; }); } validateTemplateData() { const componentNames = new Set(); this.routerContext.getAnalyzeResults().forEach((result) => { if (result.name) { componentNames.add(result.name); } }); const templateComponentNames = new Set(this.routerContext.getTemplateDataMap().keys()); templateComponentNames.forEach((name) => { if (!componentNames.has(name)) { utils_1.Logger.warn(this.routerContext.node.getNodeName(), `Component ${name} has template data but was not found in analyze results.`); } }); } generateRouterFilePath() { this.routerContext.generatedPaths = new Map(); this.routerContext.getAnalyzeResults().forEach((analyzeResult) => { if (analyzeResult.annotation === constants_1.AnnotationConstants.ROUTER_ANNOTATION) { const relativeShortPath = this.routerContext.config.getRelativeShortSourcePath(analyzeResult); const generatedFilePath = this.routerContext.config .getBuilderFilePath(relativeShortPath) .replaceAll(constants_1.FilePathConstants.FILE_SEPARATOR, constants_1.FilePathConstants.DELIMITER); this.buildRouterTemplatePath(analyzeResult); const uniqueKey = `${analyzeResult.name}#${analyzeResult.pageUrl}`; this.routerContext.generatedPaths.set(uniqueKey, generatedFilePath); } }); } buildRouterMap() { this.routerContext.getAnalyzeResults().forEach((result) => { if (!result.sourceFilePath) { throw PluginError_1.PluginError.create(PluginError_1.ErrorCode.ERROR_PAGE_SOURCE_FILE, this.routerContext.config.moduleName, result.sourceFilePath); } let pageSourceFile = this.routerContext.config .getRelativeSourcePath(result.sourceFilePath) .replaceAll(constants_1.FilePathConstants.FILE_SEPARATOR, constants_1.FilePathConstants.DELIMITER); if (result.annotation === constants_1.AnnotationConstants.ROUTER_ANNOTATION) { let pageUrl = result.pageUrl; let uniqueKey = `${result.name}#${pageUrl}`; let builderPath = this.routerContext.generatedPaths.get(uniqueKey) || ''; this.routerContext.routerMap.push({ name: pageUrl, pageSourceFile: builderPath, buildFunction: result.name + 'Builder', customData: result, }); return; } this.useAnnotationConfig(result, pageSourceFile, this.routerContext); }); this.readExistingRouterMap(this.routerContext); } useAnnotationConfig(result, pageSourceFile, context) { const config = annotationConfig[result.annotation]; let nameValue; switch (result.annotation) { case constants_1.AnnotationConstants.ANIMATOR_ANNOTATION: nameValue = result.animatorName; break; case constants_1.AnnotationConstants.INTERCEPTOR_ANNOTATION: nameValue = result.interceptorName; break; case constants_1.AnnotationConstants.LIFECYCLE_ANNOTATION: nameValue = result.lifecycleName; break; case constants_1.AnnotationConstants.SERVICE_ANNOTATION: case constants_1.AnnotationConstants.SERVICE_PROVIDE_ANNOTATION: nameValue = result.serviceName; break; default: nameValue = result.name; break; } const fullName = config.prefix + nameValue; context.routerMap.push({ name: fullName, pageSourceFile: pageSourceFile, buildFunction: '', customData: result, }); } buildRouterTemplatePath(result) { let pageSourceFile = this.routerContext.config .getRelativeSourcePath(result.sourceFilePath) .replaceAll(constants_1.FilePathConstants.FILE_SEPARATOR, constants_1.FilePathConstants.DELIMITER); let tempFilePath = this.matchedPath(pageSourceFile, this.routerContext.config.customPageTemplate, this.routerContext.config.getDefaultTplFilePath()); tempFilePath = this.determineTemplatePath(result, tempFilePath); result.templatePath = tempFilePath; } matchedPath(filePath, customPageTemplate, defaultTplFilePath) { for (const template of customPageTemplate) { if (micromatch_1.default.isMatch(filePath, template.srcPath)) { utils_1.Logger.debug(this.routerContext.node.getNodeName(), `${filePath} detected matching template: ${template.templatePath}`); return utils_1.PluginFileUtil.pathResolve(this.routerContext.config.configDir, template.templatePath); } } return defaultTplFilePath; } readExistingRouterMap(context) { const moduleJsonOpt = context.moduleContext.getModuleJsonOpt(); if (!moduleJsonOpt?.module.routerMap) { utils_1.Logger.info(context.node.getNodeName(), `No routerMap found in the module configuration`); return; } const routerMapFileName = moduleJsonOpt.module.routerMap.split(':')[1]; if (routerMapFileName !== 'hm_router_map') { const routerMapFilePath = context.config.getModuleRouterMapFilePath(routerMapFileName); const routerMapObj = utils_1.PluginFileUtil.readJson5(routerMapFilePath); const systemRouterMap = routerMapObj[constants_1.RouterMapConstants.ROUTER_MAP_KEY]; if (systemRouterMap && systemRouterMap.length > 0) { context.routerMap.unshift(...systemRouterMap); utils_1.Logger.info(context.node.getNodeName(), `System routerMap added to the current routerMap`); } } } determineTemplatePath(analyzeResult, defaultTemplatePath) { const libraryVersion = this.detectLibraryVersion(); utils_1.Logger.debug(this.routerContext.node.getNodeName(), `Library version: ${libraryVersion}`); if (analyzeResult.useNavDst === true) { return utils_1.PluginFileUtil.pathResolve(__dirname, constants_1.FilePathConstants.PARENT_DELIMITER.repeat(3), constants_1.TemplateConstants.CUSTOM_BUILDER_TEMPLATE); } const templateType = this.determineTemplateType(libraryVersion); if (templateType !== 'latest' && libraryVersion) { utils_1.Logger.warn(this.routerContext.node.getNodeName(), `[HMRouter Version Compatibility] Detected library version ${libraryVersion}, ` + `which is below the minimum recommended version ${constants_1.VersionConstants.HMROUTER_MIN_VERSION_FOR_SDK_API}. ` + `Automatically switched to compatible template (${templateType}). ` + `Please upgrade @hadss/hmrouter to ${constants_1.VersionConstants.HMROUTER_MIN_VERSION_FOR_SDK_API} or higher for full feature support.`); } switch (templateType) { case 'v1': return utils_1.PluginFileUtil.pathResolve(__dirname, constants_1.FilePathConstants.PARENT_DELIMITER.repeat(3) + constants_1.TemplateConstants.V1_TEMPLATE); case 'v1_1': return utils_1.PluginFileUtil.pathResolve(__dirname, constants_1.FilePathConstants.PARENT_DELIMITER.repeat(3) + constants_1.TemplateConstants.V1_1_TEMPLATE); case 'latest': default: return defaultTemplatePath; } } determineTemplateType(libraryVersion) { if (!libraryVersion) { return 'v1'; } const currentVersion = this.parseVersion(libraryVersion); const v1_1Version = this.parseVersion(constants_1.VersionConstants.HMROUTER_MIN_VERSION_FOR_NAV_HELPER); const v1_2Version = this.parseVersion(constants_1.VersionConstants.HMROUTER_MIN_VERSION_FOR_SDK_API); if (!currentVersion || !v1_1Version || !v1_2Version) { return 'v1'; } if (this.compareVersions(currentVersion, v1_2Version) >= 0) { return 'latest'; } if (this.compareVersions(currentVersion, v1_1Version) >= 0) { return 'v1_1'; } return 'v1'; } detectLibraryVersion() { let libraryVersion = ''; const possiblePaths = this.getLibraryPossiblePaths(); for (const packagePath of possiblePaths) { libraryVersion = this.detectLibraryVersion2(packagePath); if (libraryVersion) { break; } } return libraryVersion; } detectLibraryVersion2(lockFilePath) { try { if (!utils_1.PluginFileUtil.exist(lockFilePath)) { return ''; } const lockFileData = utils_1.PluginFileUtil.readJson5(lockFilePath); return this.extractHMRouterVersion(lockFileData.packages); } catch (error) { return ''; } } extractHMRouterVersion(packages) { if (!packages) { return ''; } const hmrouterPrefix = `${constants_1.VersionConstants.HMROUTER_ORGANIZATION}/${constants_1.VersionConstants.HMROUTER_LIB_NAME}@`; for (const key of Object.keys(packages)) { if (!key.startsWith(hmrouterPrefix)) { continue; } const packageInfo = packages[key]; if (packageInfo && packageInfo[constants_1.VersionConstants.HMROUTER_VERSION_KEY]) { return packageInfo[constants_1.VersionConstants.HMROUTER_VERSION_KEY] ?? ''; } } return ''; } getLibraryPossiblePaths() { const paths = []; paths.push(utils_1.PluginFileUtil.pathResolve(this.routerContext.config.modulePath, constants_1.FilePathConstants.OH_PACKAGE_LOCK_FILE_NAME)); const projectRoot = utils_1.PluginStore.getInstance().get('projectFilePath'); if (projectRoot && projectRoot !== this.routerContext.config.modulePath) { paths.push(utils_1.PluginFileUtil.pathResolve(projectRoot, constants_1.FilePathConstants.OH_PACKAGE_LOCK_FILE_NAME)); } return paths; } parseVersion(version) { const match = version.match(/^(\d+)\.(\d+)\.(\d+)(-.*)?/); if (!match) { return null; } return { major: parseInt(match[1], 10), minor: parseInt(match[2], 10), patch: parseInt(match[3], 10), preRelease: match[4] || '', }; } compareVersions(v1, v2) { if (v1.major !== v2.major) { return v1.major < v2.major ? -1 : 1; } if (v1.minor !== v2.minor) { return v1.minor < v2.minor ? -1 : 1; } if (v1.patch !== v2.patch) { return v1.patch < v2.patch ? -1 : 1; } if (v1.preRelease && !v2.preRelease) { return -1; } if (!v1.preRelease && v2.preRelease) { return 1; } if (v1.preRelease < v2.preRelease) { return -1; } if (v1.preRelease > v2.preRelease) { return 1; } return 0; } } exports.TaskManager = TaskManager;