@arms/rum-harmonyos-plugin
Version:
Alibaba Cloud RUM plugin for HarmonyOS applications
197 lines (196 loc) • 8.14 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AlibabaCloudRumPlugin = AlibabaCloudRumPlugin;
const hvigor_1 = require("@ohos/hvigor");
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
// 插件标识符
const PLUGIN_TAG = "AlibabaCloudRum";
// 获取当前节点信息
const currentNode = (0, hvigor_1.getNode)(__filename);
// 存储文件规则
let filesAndRules = { allFiles: [], replaceRules: [] };
/**
* 创建插件实例
*/
function AlibabaCloudRumPlugin() {
return {
pluginId: 'localAlibabaCloudRumPlugin',
apply: (hvigorNode) => {
// 注册注入任务
hvigorNode.registerTask({
name: 'alibabaCloudRumInjectTask',
run: (context) => {
filesAndRules = performInjection(hvigorNode);
},
postDependencies: ['default@CompileArkTS']
});
// 注册重置任务
hvigorNode.registerTask({
name: 'resetAlibabaCloudRumInjectTask',
run: () => {
revertInjection(filesAndRules.allFiles, filesAndRules.replaceRules);
},
dependencies: ['default@CompileArkTS'],
postDependencies: ['assembleHap']
});
}
};
}
/**
* 执行注入操作
* @param hvigorNode - 当前节点对象
* @returns 文件列表及替换规则
*/
function performInjection(hvigorNode) {
console.log(PLUGIN_TAG, '------------start AlibabaCloudRum -----------------');
if (!hvigorNode?.nodeDir?.filePath) {
return { allFiles: [], replaceRules: [] };
}
const projectRoot = hvigorNode.nodeDir.filePath;
const configFilePath = path_1.default.join(projectRoot, 'alibabaCloudRumConfig.txt');
// 解析配置文件内容
const { filesToProcess, keepFiles } = parseConfigFile(configFilePath, projectRoot);
// 使用插件内部的替换规则
const replaceRules = getInternalReplaceRules();
let processedFiles = [];
// 处理指定目录或文件中的所有文件
processedFiles = getProcessedFiles(filesToProcess, keepFiles, projectRoot);
// 筛选特定类型的文件(如 ts/js/ets)
processedFiles = processedFiles.filter(filePath => /\.(ts|js|ets)$/.test(filePath));
// 对每个筛选出的文件执行替换操作
processedFiles.forEach(filePath => processReplacement(filePath, replaceRules, false));
console.log(PLUGIN_TAG, '------------end AlibabaCloudRum -----------------');
return { allFiles: processedFiles, replaceRules };
}
/**
* 获取插件内部的替换规则
* @returns 固定的替换规则数组
*/
function getInternalReplaceRules() {
return [
{ pattern: escapeRegExp('http.createHttp();'), replacement: 'ALRHttp.createHttp();', imports: ['import {ALRHttp} from \'@alibabacloud_rum/harmony_sdk\';'] },
{ pattern: escapeRegExp('rcp.createSession('), replacement: 'ALRRcp.createSession(', imports: ['import {ALRRcp} from \'@alibabacloud_rum/harmony_sdk\';'] },
{ pattern: escapeRegExp('socket.constructTCPSocketInstance()'), replacement: 'ALRTcpSocket.constructTCPSocketInstance()', imports: ['import { ALRTcpSocket } from \'@alibabacloud_rum/harmony_sdk\';'] },
{ pattern: escapeRegExp('webSocket.createWebSocket()'), replacement: 'ALRWebSocket.createWebSocket()', imports: ['import { ALRWebSocket } from \'@alibabacloud_rum/harmony_sdk\';'] }
];
}
/**
* 执行重置操作
* @param processedFiles - 已处理过的文件列表
* @param rules - 替换规则
*/
function revertInjection(processedFiles, rules) {
console.log(PLUGIN_TAG, '============start reset AlibabaCloudRum =================');
// 如果缺少必要的参数,则打印错误信息并返回
if (!processedFiles || !rules) {
console.error(PLUGIN_TAG, 'ERROR: Missing required parameters for revertInjection.');
return;
}
// 对每个已处理过的文件执行反向替换操作
processedFiles.forEach(filePath => processReplacement(filePath, rules, true));
console.log(PLUGIN_TAG, '============end reset AlibabaCloudRum =================');
}
// 辅助函数
function parseConfigFile(configFilePath, rootDir) {
const filesToProcess = [];
const keepFiles = [];
const lines = fs_1.default.readFileSync(configFilePath, 'utf-8').split('\n');
lines.map(line => line.trim())
.filter(line => line.length > 0 && !line.startsWith('#'))
.forEach(line => {
if (line.startsWith('-hook ')) {
filesToProcess.push(resolvePath(line.substring(6).trim(), rootDir));
}
else if (line.startsWith('-keep ')) {
keepFiles.push(resolvePath(line.substring(6).trim(), rootDir));
}
});
return { filesToProcess, keepFiles };
}
function resolvePath(filePath, rootDir) {
let absPath = path_1.default.isAbsolute(filePath) ? filePath : path_1.default.resolve(rootDir, `.${path_1.default.sep}${filePath}`);
return absPath;
}
function escapeRegExp(string) {
return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');
}
function unescapeRegExp(string) {
return string.replace(/\\([.*+\-?^${}()|[\]\\])/g, '$1');
}
function getProcessedFiles(filesToProcess, keepFiles, projectRoot) {
let processedFiles = [];
if (filesToProcess.length > 0) {
processedFiles = filesToProcess.flatMap(fileOrDir => {
if (fs_1.default.statSync(fileOrDir).isDirectory()) {
return getAllFiles(fileOrDir, keepFiles);
}
else {
return shouldKeep(fileOrDir, keepFiles) ? [] : [fileOrDir];
}
});
}
else {
processedFiles = getAllFiles(projectRoot, keepFiles);
}
return processedFiles;
}
function getAllFiles(dir, keepFiles, fileList = []) {
if (!fs_1.default.existsSync(dir)) {
console.error(PLUGIN_TAG, `ERROR: Directory does not exist: ${dir}`);
return fileList;
}
fs_1.default.readdirSync(dir).forEach(file => {
const filePath = path_1.default.join(dir, file);
if (fs_1.default.statSync(filePath).isDirectory()) {
if (!shouldKeep(filePath, keepFiles)) {
getAllFiles(filePath, keepFiles, fileList);
}
}
else {
if (!shouldKeep(filePath, keepFiles)) {
fileList.push(filePath);
}
}
});
return fileList;
}
function shouldKeep(filePath, keepFiles) {
return keepFiles.some(keepFile => filePath.startsWith(keepFile));
}
function processReplacement(filePath, rules, isReverse) {
let contentLines = fs_1.default.readFileSync(filePath, 'utf-8').split('\n');
let modified = false;
if (isReverse) {
rules.forEach(({ imports }) => {
imports.forEach((importStatement) => {
contentLines = contentLines.filter(line => line.trim() !== importStatement.trim());
});
});
}
rules.forEach(({ pattern, replacement, imports }) => {
const searchPattern = isReverse ? escapeRegExp(replacement) : pattern;
const replaceValue = isReverse ? unescapeRegExp(pattern) : replacement;
const regex = new RegExp(searchPattern, 'g');
contentLines.forEach((line, index) => {
if (line.match(regex)) {
contentLines[index] = line.replace(regex, replaceValue);
modified = true;
}
});
if (!isReverse && modified) {
imports.forEach((statement) => {
if (!contentLines.includes(statement)) {
contentLines.unshift(statement);
}
});
}
});
if (modified) {
fs_1.default.writeFileSync(filePath, contentLines.join('\n'), 'utf-8');
console.warn(PLUGIN_TAG, isReverse ? `File reset: ${filePath}` : `File modified: ${filePath}`);
}
}