import { appTasks } from '@ohos/hvigor-ohos-plugin'; import { HvigorPlugin, HvigorNode } from '@ohos/hvigor'; import fs from 'fs'; import path from 'path'; function customPlugin(): HvigorPlugin { return { pluginId: 'customPlugin', apply(node: HvigorNode) { try { // console.log('node', JSON.stringify(node)) // 根据node对象结构获取项目路径 const projectPath = node.nodeDir.filePath; console.log('目标路径:', projectPath); // 获取所有子模块 const modules = node.allSubNodes.filter(subNode => subNode.node.classKind === 'module'); console.log('模块数量:', modules.length); // 打印每个模块的路径 const modulePaths = []; modules.forEach((module, index) => { try { // 从module.node._nodePath获取模块路径 const modulePath = module.node._nodePath; if (modulePath) { console.log(`模块 ${index + 1} 路径:`, modulePath); modulePaths.push(modulePath); } else { console.log(`模块 ${index + 1} 路径: 无法获取路径`); } } catch (error) { console.error(`获取模块 ${index + 1} 路径时出错:`, error); } }); // 遍历并处理所有模块 modulePaths.forEach((modulePath, index) => { console.log(`处理模块 ${index + 1}:`, modulePath); processModule(modulePath, projectPath); }); } catch (error) { console.error('Error in custom plugin:', error); } } } function processModule(modulePath: string, projectPath: string) { try { // 构建pages目录路径 (基于模块路径) const pagesPath = path.join(modulePath, 'src', 'main', 'ets', 'pages'); console.log('pages路径:', pagesPath); // 构建profile目录路径 (基于模块路径) const rawfilePath = path.join(modulePath, 'src', 'main', 'resources', 'base', 'profile'); console.log('profile路径:', rawfilePath); // 确保profile目录存在 if (!fs.existsSync(rawfilePath)) { fs.mkdirSync(rawfilePath, { recursive: true }); } // router_map.json文件路径 const routerMapPath = path.join(rawfilePath, 'router_map.json'); // module.json5文件路径 const moduleJsonPath = path.join(modulePath, 'src', 'main', 'module.json5'); // 初始化routerMap let routerMap = { routerMap: [] }; // 如果router_map.json文件已存在,则读取现有内容 if (fs.existsSync(routerMapPath)) { try { const existingContent = fs.readFileSync(routerMapPath, 'utf8'); routerMap = JSON.parse(existingContent); console.log('读取现有的router_map.json文件'); } catch (error) { console.error('读取router_map.json文件出错:', error); } } // 检查pages目录是否存在 if (fs.existsSync(pagesPath)) { // 读取目录内容 const files = fs.readdirSync(pagesPath); console.log(`Found ${files.length} files/directories in pages folder:`); // 遍历并处理每个文件 files.forEach((file, index) => { const fullPath = path.join(pagesPath, file); const stat = fs.statSync(fullPath); const type = stat.isDirectory() ? '[DIR]' : '[FILE]'; console.log(`${index + 1}. ${type} ${file}`); // 如果是文件,读取文件内容 if (!stat.isDirectory() && file.endsWith('.ets')) { try { const content = fs.readFileSync(fullPath, 'utf8'); // console.log(`Content of ${file}:`); // console.log(content); // 检查是否有@RouterPage修饰器 if (content.includes('@RouterPage')) { // 生成Builder函数名(去掉Page后缀,加上Builder后缀) const fileNameWithoutExtension = file.replace('.ets', ''); const builderName = fileNameWithoutExtension.replace(/Page$/, '') + 'Builder'; // 检查是否已经存在Builder函数 const builderRegex = new RegExp(`@Builder\\s+function\\s+${builderName}\\s*\\(\\)`, 'g'); if (!builderRegex.test(content)) { // 构造新的内容,在文件末尾添加Builder函数 const structName = fileNameWithoutExtension; // 假设struct名称与文件名相同 const builderFunction = `\n@Builder\nfunction ${builderName}() {\n ${structName}()\n}\n`; const newContent = content + builderFunction; // 写入文件 fs.writeFileSync(fullPath, newContent, 'utf8'); console.log(`Added ${builderName} function to ${file}`); } else { console.log(`Builder function ${builderName} already exists in ${file}`); } // 添加到routerMap中 const pageEntry = { name: fileNameWithoutExtension, pageSourceFile: `src/main/ets/pages/${file}`, buildFunction: builderName }; // 检查是否已存在该条目 const existingIndex = routerMap.routerMap.findIndex(item => item.name === fileNameWithoutExtension); if (existingIndex >= 0) { // 更新现有条目 routerMap.routerMap[existingIndex] = pageEntry; } else { // 添加新条目 routerMap.routerMap.push(pageEntry); } } console.log('----------------------------------------'); } catch (readError) { console.error(`Error reading file ${file}:`, readError); } } }); // 将routerMap写入router_map.json文件 try { fs.writeFileSync(routerMapPath, JSON.stringify(routerMap, null, 2), 'utf8'); console.log('router_map.json文件已更新'); } catch (writeError) { console.error('写入router_map.json文件出错:', writeError); } // 更新module.json5文件,添加routerMap字段 try { if (fs.existsSync(moduleJsonPath)) { const moduleJsonContent = fs.readFileSync(moduleJsonPath, 'utf8'); // 使用正则表达式在"module": {后添加routerMap字段 if (moduleJsonContent.includes('"module"')) { // 检查是否已经存在routerMap字段 if (!moduleJsonContent.includes('"routerMap"')) { // 在"module": {后添加routerMap字段 const updatedContent = moduleJsonContent.replace( /("module"\s*:\s*{)/, '$1\n "routerMap": "$profile:router_map",' ); fs.writeFileSync(moduleJsonPath, updatedContent, 'utf8'); console.log('module.json5文件已更新,添加了routerMap字段'); } else { console.log('module.json5中已存在routerMap字段'); } } else { console.log('module.json5中未找到"module"字段'); } } else { console.log('module.json5文件不存在'); } } catch (error) { console.error('更新module.json5文件出错:', error); } } else { console.log('Pages directory not found'); } } catch (error) { console.error(`处理模块 ${modulePath} 时出错:`, error); } } } function rDBPlugin(): HvigorPlugin { return { pluginId: 'customPlugin', apply(node: HvigorNode) { try { // 根据node对象结构获取项目路径 const projectPath = node.nodeDir.filePath; console.log('目标路径:', projectPath); // 获取所有子模块 const modules = node.allSubNodes.filter(subNode => subNode.node.classKind === 'module'); console.log('模块数量:', modules.length); // 打印每个模块的路径 const modulePaths = []; modules.forEach((module, index) => { try { // 从module.node._nodePath获取模块路径 const modulePath = module.node._nodePath; if (modulePath) { console.log(`模块 ${index + 1} 路径:`, modulePath); modulePaths.push(modulePath); if (modulePath.includes('basic')) { processTables(modulePath) } } else { console.log(`模块 ${index + 1} 路径: 无法获取路径`); } } catch (error) { console.error(`获取模块 ${index + 1} 路径时出错:`, error); } }); // 遍历并处理所有模块 // modulePaths.forEach((modulePath, index) => { // console.log(`处理模块 ${index + 1}:`, modulePath); // processTables(); // 处理tables目录的逻辑 // }); // processTables(modulePaths[]) } catch (error) { console.error('Error in custom plugin:', error); } } } function processTables(currentDir:string) { try { // 构建tables目录路径 const tablesPath = path.join(currentDir, 'src', 'main', 'ets', 'rdb', 'tables'); console.log('tables路径:', tablesPath); // 检查tables目录是否存在 if (fs.existsSync(tablesPath)) { // 读取目录内容 const files = fs.readdirSync(tablesPath); console.log(`Found ${files.length} files/directories in tables folder:`); const tableNames: string[] = []; const sqlStatements: string[] = []; // 替换原有的字段处理逻辑 files.forEach((file, index) => { const fullPath = path.join(tablesPath, file); const stat = fs.statSync(fullPath); const type = stat.isDirectory() ? '[DIR]' : '[FILE]'; console.log(`${index + 1}. ${type} ${file}`); // 如果是文件,读取文件内容 if (!stat.isDirectory() && file.endsWith('.ets')) { try { const content = fs.readFileSync(fullPath, 'utf8'); // 使用正则表达式匹配interface名称 const interfaceRegex = /export\s+interface\s+(\w+)/g; let match; while ((match = interfaceRegex.exec(content)) !== null) { const interfaceName = match[1]; tableNames.push(interfaceName); // 解析接口属性并生成字段 const fieldDefinitions = parseInterfaceFields(content, interfaceName); // 生成CREATE TABLE SQL语句(包含字段) const sqlStatement = `static readonly CREATE_${interfaceName.toUpperCase()}_TABLE = 'CREATE TABLE IF NOT EXISTS ${interfaceName} (${fieldDefinitions})';`; sqlStatements.push(sqlStatement); console.log(`Found interface: ${interfaceName}`); } } catch (readError) { console.error(`Error reading file ${file}:`, readError); } } }); // 添加解析接口字段的辅助函数 function parseInterfaceFields(content: string, interfaceName: string): string { // 查找接口定义区域 const interfaceStart = content.indexOf(`export interface ${interfaceName}`); if (interfaceStart === -1) { return 'ID INTEGER PRIMARY KEY AUTOINCREMENT'; } const openBrace = content.indexOf('{', interfaceStart); const closeBrace = content.indexOf('}', openBrace); if (openBrace === -1 || closeBrace === -1) { return 'ID INTEGER PRIMARY KEY AUTOINCREMENT'; } const interfaceBody = content.substring(openBrace + 1, closeBrace); const lines = interfaceBody.split('\n'); const fields: string[] = []; let hasPrimaryKey = false; lines.forEach(line => { const fieldMatch = line.trim().match(/^(\w+)\??\s*:\s*(.+?);?$/); if (fieldMatch) { const fieldName = fieldMatch[1]; const fieldType = fieldMatch[2].trim(); // 根据TypeScript类型映射到SQLite类型 let sqliteType = 'TEXT'; if (fieldType.includes('number') || fieldType.includes('Number')) { sqliteType = 'INTEGER'; } else if (fieldType.includes('boolean') || fieldType.includes('Boolean')) { sqliteType = 'INTEGER'; } else if (fieldType.includes('Date')) { sqliteType = 'TEXT'; } // 检查是否为主键字段(约定以id命名的字段作为主键) if (fieldName.toLowerCase() === 'id') { fields.push(`${fieldName} INTEGER PRIMARY KEY AUTOINCREMENT`); hasPrimaryKey = true; } else { // 处理可选字段 const nullable = line.trim().includes('?') ? '' : ' NOT NULL'; fields.push(`${fieldName} ${sqliteType}${nullable}`); } } }); // 如果没有定义主键,则添加默认主键 if (!hasPrimaryKey) { fields.unshift('ID INTEGER PRIMARY KEY AUTOINCREMENT'); } return fields.join(', '); } // 更新RelationalStoreUtils.ets文件中的tables数组 const relationalStorePath = path.join(currentDir, 'src', 'main', 'ets', 'rdb', 'utils', 'RelationalStoreUtis.ets'); if (fs.existsSync(relationalStorePath)) { let content = fs.readFileSync(relationalStorePath, 'utf8'); // 更新tables数组 if (tableNames.length > 0) { const tablesArray = `private static tables: string[] = [${tableNames.map(name => `'${name}'`).join(', ')}]`; const updatedContent = content.replace(/private static tables: string\[\] = \[[^\]]*\]/, tablesArray); fs.writeFileSync(relationalStorePath, updatedContent, 'utf8'); console.log('RelationalStoreUtis.ets文件已更新'); } } // 替换原有的更新RDBSql.ets文件的代码块 // 更新RDBSql.ts文件 const rdbSqlPath = path.join(currentDir, 'src', 'main', 'ets', 'rdb', 'sqls', 'RDBSql.ts'); if (fs.existsSync(rdbSqlPath)) { let content = fs.readFileSync(rdbSqlPath, 'utf8'); // 构建SQL语句对象属性 if (sqlStatements.length > 0) { // 提取属性名和值 const sqlProperties: string[] = []; sqlStatements.forEach(statement => { // 从 static readonly CREATE_USER_TABLE = 'CREATE TABLE...' 提取属性 const propertyName = statement.split('=')[0].trim().replace('static readonly ', ''); const propertyValue = statement.split('=')[1].trim().slice(1, -2); // 去掉引号和分号 sqlProperties.push(` ${propertyName}: '${propertyValue}'`); }); // 构建新的对象内容 const newContent = `export const rDbSql = {\n${sqlProperties.join(',\n')}\n}`; fs.writeFileSync(rdbSqlPath, newContent, 'utf8'); console.log('RDBSql.ts文件已更新为对象形式'); } } else { // 如果文件不存在,创建新文件 if (sqlStatements.length > 0) { const sqlProperties: string[] = []; sqlStatements.forEach(statement => { const propertyName = statement.split('=')[0].trim().replace('static readonly ', ''); const propertyValue = statement.split('=')[1].trim().slice(1, -2); sqlProperties.push(` ${propertyName}: '${propertyValue}'`); }); const newContent = `export const rDbSql = {\n${sqlProperties.join(',\n')}\n}`; // 确保目录存在 const dirPath = path.dirname(rdbSqlPath); if (!fs.existsSync(dirPath)) { fs.mkdirSync(dirPath, { recursive: true }); } fs.writeFileSync(rdbSqlPath, newContent, 'utf8'); console.log('RDBSql.ts文件已创建并初始化为对象形式'); } } console.log('----------------------------------------'); } else { console.log('Tables directory not found'); } } catch (error) { console.error(`处理tables目录时出错:`, error); } } } export default { system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ plugins: [ customPlugin(), // 应用自定义Plugin rDBPlugin() ] /* Custom plugin to extend the functionality of Hvigor. */ }