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 typeRegex = /export\s+(interface|class)\s+(\w+)/g; let match; while ((match = typeRegex.exec(content)) !== null) { const typeKind = match[1]; // 'interface' 或 'class' const typeName = match[2]; // 类型名称 tableNames.push(typeName); // 解析字段定义 const fieldDefinitions = parseTypeFields(content, typeName); // 生成CREATE TABLE SQL语句 const sqlStatement = `static readonly CREATE_${typeName.toUpperCase()}_TABLE = 'CREATE TABLE IF NOT EXISTS ${typeName} (${fieldDefinitions})';`; sqlStatements.push(sqlStatement); console.log(`Found ${typeKind}: ${typeName}`); } } catch (readError) { console.error(`Error reading file ${file}:`, readError); } } }); // 添加解析接口字段的辅助函数 function parseTypeFields(content: string, typeName: string): string { // 使用正则表达式查找 interface 或 class 定义,允许中间有多个空格 const classRegex = new RegExp(`export\\s+class\\s+${typeName}`, 'g'); const interfaceRegex = new RegExp(`export\\s+interface\\s+${typeName}`, 'g'); const classMatch = classRegex.exec(content); const interfaceMatch = interfaceRegex.exec(content); let typeStart = -1; if (classMatch) { typeStart = classMatch.index; } else if (interfaceMatch) { typeStart = interfaceMatch.index; } console.log('开始解析类型体内容:'); console.log('typeStart内容:', typeStart); if (typeStart === -1) { return 'ID INTEGER PRIMARY KEY AUTOINCREMENT'; } // 后续逻辑保持不变... const openBrace = content.indexOf('{', typeStart); const closeBrace = content.indexOf('}', openBrace); if (openBrace === -1 || closeBrace === -1) { console.log('openBrace和closeBrace内容:', openBrace,closeBrace); return 'ID INTEGER PRIMARY KEY AUTOINCREMENT'; } const typeBody = content.substring(openBrace + 1, closeBrace); const lines = typeBody.split('\n'); const fields: string[] = []; let hasPrimaryKey = false; // 改进字段解析逻辑 lines.forEach(line => { const trimmedLine = line.trim(); // 使用更宽松的正则表达式,支持多种格式 // 匹配格式: fieldName?: type; 或 fieldName: type; (允许前后空格) const fieldMatch = trimmedLine.match(/^(\w+)(\??)\s*:\s*([^;]+?)\s*(?:;|$)/); if (fieldMatch) { const fieldName = fieldMatch[1]; const isOptional = fieldMatch[2] === '?'; const fieldType = fieldMatch[3].trim(); console.log(`解析字段: ${fieldName}, 可选: ${isOptional}, 类型: ${fieldType}`); // 调试信息 // 根据TypeScript类型映射到SQLite类型 let sqliteType = 'TEXT'; const normalizedFieldType = fieldType.toLowerCase(); if (normalizedFieldType.includes('number') || normalizedFieldType.includes('int') || normalizedFieldType.includes('float')) { sqliteType = 'INTEGER'; } else if (normalizedFieldType.includes('boolean')) { sqliteType = 'INTEGER'; } else if (normalizedFieldType.includes('date')) { sqliteType = 'TEXT'; } // 检查是否为主键字段 if (fieldName.toLowerCase() === 'id') { fields.push(`${fieldName} INTEGER PRIMARY KEY AUTOINCREMENT`); hasPrimaryKey = true; } else { // 处理可选字段 const nullable = isOptional ? '' : ' 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文件 // 更新RDBSql.ts文件的改进逻辑 const rdbSqlPath = path.join(currentDir, 'src', 'main', 'ets', 'rdb', 'sqls', 'RDBSql.ts'); if (fs.existsSync(rdbSqlPath)) { let content = fs.readFileSync(rdbSqlPath, 'utf8'); // 解析现有rDbSql对象中的属性 const existingProperties: Map = new Map(); const propertyRegex = /(\w+):\s*'([^']+)'/g; let match; while ((match = propertyRegex.exec(content)) !== null) { existingProperties.set(match[1], match[2]); } // 构建SQL语句对象属性 if (sqlStatements.length > 0) { const sqlProperties: string[] = []; // 首先保留现有的属性(用于手动添加的SQL) existingProperties.forEach((value, key) => { // 检查是否是自动生成的CREATE_*_TABLE属性 if (!key.startsWith('CREATE_') || !key.endsWith('_TABLE')) { sqlProperties.push(` ${key}: '${value}'`); } }); // 添加或更新基于类定义生成的SQL属性 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}`; fs.writeFileSync(rdbSqlPath, newContent, 'utf8'); console.log('RDBSql.ts文件已更新,保留了手动添加的SQL语句'); } } 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. */ }