router-register-plugin
Version:
鸿蒙ZRouter动态路由框架页面模板化插件
260 lines (225 loc) • 10.8 kB
text/typescript
import {logger} from "./logger";
import {AnalyzerParam, PageInfo, PluginConfig, ScanFileParam} from "../models/model";
import fs from "node:fs";
import JSON5 from "json5";
import path from "node:path";
import Constants from "../models/constants";
import {isNotEmpty} from "./string";
import {Analyzer} from "../analyzer";
import Handlebars from "handlebars";
import {FileUtil, HvigorNode} from "@ohos/hvigor";
import {readdirSync} from "fs";
/**
* @author: HZWei
* @date: 2024/12/5
* @desc:
*/
class FileHelper {
static findFirstLevelDirs(directory: string, targetDirNames: string[]): string[] {
if (!directory) return [];
const r: string[] = []
if (FileUtil.isDictionary(directory)) {
const files = fs.readdirSync(directory)
files.forEach(file => {
const fullPath = path.join(directory, file);
// 检查目录名匹配targetDirNames中的任一元素
if (targetDirNames.some(target => fullPath.includes(target))) {
r.push(fullPath)
}
});
}
return r;
}
static deleteDirFile(directory: string, excludes?: string[]) {
try {
function deleteDir(dirOrPath: string) {
const exclude = excludes?.find(item => dirOrPath.includes(item));
if (exclude) return;
if (fs.existsSync(dirOrPath)) fs.unlinkSync(dirOrPath);
}
if (!fs.existsSync(directory)) return false
if (FileUtil.isFile(directory)) {
deleteDir(directory)
return true
}
const files = fs.readdirSync(directory)
files.forEach(file => {
const filePath = path.join(directory, file);
if (FileUtil.isDictionary(filePath)){
FileHelper.deleteDirFile(filePath, excludes)
}else {
deleteDir(filePath)
}
});
return true
} catch (err) {
logger("删除异常:", err)
return false
}
}
static isModule(importPath: string) {
try {
const isRelativePath = importPath.startsWith('./') || importPath.startsWith('../');
return !isRelativePath
} catch (err) {
logger("isModule err: ", err)
}
return false
}
static getImportAbsolutePathByOHPackage(pathOrModuleName: string, analyzerParam: AnalyzerParam, param: ScanFileParam) {
logger("getImportAbsolutePathByOHPackage start: ", pathOrModuleName, analyzerParam);
let absolutePath
if (FileHelper.isModule(pathOrModuleName)) {
const json = FileHelper.getOhPackageJSON5(analyzerParam.modDir)
const dependencies = json.dependencies || {}
const targetMod: {
name: string,
srcPath: string
} | undefined = Object.keys(dependencies).map(key => {
if (key.toLowerCase() == pathOrModuleName) {
let srcPath: string = dependencies[key].toString().split(':')[1].trim();
return {name: key, srcPath};
}
}).find(item => item !== undefined)
if (targetMod != undefined && targetMod.srcPath != undefined) {
const targetModAbsolutePath = path.resolve(analyzerParam.modDir, targetMod.srcPath)
logger("getImportAbsolutePathByOHPackage module: ", targetMod.srcPath, targetModAbsolutePath)
const indexPath = path.join(targetModAbsolutePath, "Index.ets")
param.indexModuleName = targetMod.name
param.moduleSrcPath = targetMod.srcPath
param.actionType = Constants.TYPE_FIND_MODULE_INDEX_PATH
let analyzer = new Analyzer(AnalyzerParam.create(indexPath, analyzerParam.modName, analyzerParam.modDir), param)
analyzer.start()
if (isNotEmpty(analyzer.fileParam?.absolutePath)) {
absolutePath = analyzer.fileParam?.absolutePath
logger("getImportAbsolutePathByOHPackage index: ", absolutePath)
} else {
absolutePath = FileHelper.getImportAbsolutePathByBuildProfile(pathOrModuleName, analyzerParam, param)
}
} else {
absolutePath = FileHelper.getImportAbsolutePathByBuildProfile(pathOrModuleName, analyzerParam, param)
}
} else {
const filePath = path.resolve(path.dirname(analyzerParam.scanFilePath), pathOrModuleName)
logger("getImportAbsolutePathByOHPackage path: ", filePath)
absolutePath = filePath
}
logger("getImportAbsolutePathByOHPackage end: ", absolutePath)
return absolutePath
}
static getImportAbsolutePathByBuildProfile(pathOrModuleName: string, analyzerParam: AnalyzerParam, param: ScanFileParam) {
let absolutePath
try {
if (FileHelper.isModule(pathOrModuleName)) {
// 在build-profile.json5文件中查找出模块的相对路径
const data = fs.readFileSync(`${process.cwd()}/build-profile.json5`, {encoding: "utf8"})
const json = JSON5.parse(data)
const modules = json.modules || []
const targetMod: {
name: string,
srcPath: string
} = modules.find((item: {
name: string,
srcPath: string
}) => item.name.toLowerCase() == pathOrModuleName || pathOrModuleName.startsWith(item.name.toLowerCase()))
if (targetMod != null) {
const modPath = path.resolve(process.cwd(), targetMod.srcPath)
logger("getImportAbsolutePathByBuildProfile module: ", targetMod.name, targetMod.srcPath, modPath)
// 1、先在index.ets文件中查找出相对路径
const indexPath = path.join(modPath, "Index.ets")
param.indexModuleName = targetMod.name
param.moduleSrcPath = targetMod.srcPath
param.actionType = Constants.TYPE_FIND_MODULE_INDEX_PATH
let analyzer = new Analyzer(AnalyzerParam.create(indexPath, analyzerParam.modName, analyzerParam.modDir), param)
analyzer.start()
if (isNotEmpty(analyzer.fileParam?.absolutePath)) {
absolutePath = analyzer.fileParam?.absolutePath
logger("getImportAbsolutePathByBuildProfile index: ", absolutePath)
} else {
// 2、如果在Index.ets文件中没有命中,可能在Index文件中没有直接导出,是通过直接导入的方式
absolutePath = modPath + pathOrModuleName.replace(targetMod.name.toLowerCase(), "")
logger("getImportAbsolutePathByBuildProfile other: ", absolutePath)
}
}
} else {
const filePath = path.resolve(path.dirname(analyzerParam.scanFilePath), pathOrModuleName)
logger("getImportAbsolutePath path: ", filePath)
absolutePath = filePath
}
} catch (e) {
logger("getImportAbsolutePath err: ", e)
} finally {
absolutePath = absolutePath ?? path.resolve(path.dirname(analyzerParam.scanFilePath), pathOrModuleName)
}
return absolutePath
}
static getTemplateContent(templateRelativePath: string, pageList: Array<PageInfo>) {
// 模板路径是在离线包内的,因此路径也是相对离线包而言的
const templatePath = path.resolve(__dirname, templateRelativePath);
logger('generateServiceFile template path: ', templatePath)
const source = fs.readFileSync(templatePath, 'utf8')
const template = Handlebars.compile(source)
const content = {pageList: pageList, zRouterPath: pageList[0].zRouterPath}
return template(content)
}
static findZRouterModuleName(node: HvigorNode) {
const modDir = node.getNodePath()
let counter = 0
function findZRouterPath(json: any) {
const dependencies = json.dependencies || {}
let path = ""
Object.keys(dependencies).forEach((key) => {
if (Constants.Z_ROUTER_PATHS.includes(key.toLowerCase())) {
path = key
}
})
if (isNotEmpty(path)) {
return path
} else {
counter++
if (counter > 3) return undefined
return findZRouterPath(FileHelper.getOhPackageJSON5(modDir))
}
}
return findZRouterPath(process.cwd()) || Constants.Z_ROUTER_PATHS[0]
}
static getOhPackageJSON5(ohAbsDirPath: string) {
const data = fs.readFileSync(`${ohAbsDirPath}/oh-package.json5`, {encoding: "utf8"})
return JSON5.parse(data)
}
static getAllValidPaths(dirs: string[]) {
return dirs.filter((dir) => fs.existsSync(dir))
}
static getFilesInDir(...dirPaths: string[]) {
let files = new Array<string>()
function find(currentDir: string) {
if (fs.existsSync(currentDir)) {
const contents = readdirSync(currentDir, {withFileTypes: true})
contents.forEach((value, index) => {
// 文件目录路径 + 文件名称 = 文件路径
const filePath = path.join(currentDir, value.name)
if (value.isDirectory()) {
find(filePath)
} else if (value.isFile() && value.name.endsWith(Constants.ETS_SUFFIX)) {
files.push(filePath)
}
})
}
}
dirPaths.forEach((path) => {
find(path)
})
logger(files)
return files
}
static insertContentToFile(filePath: string, content: string) {
if (!fs.existsSync(filePath)) return;
const data = fs.readFileSync(filePath, {encoding: "utf8"})
if (data.includes(content.trim())) {
return;
}
const newData = `${content}\n` + data;
fs.writeFileSync(filePath, newData, {encoding: "utf8"})
}
}
export default FileHelper;