import { readFileSync } from 'node:fs'; import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; const root = resolve(dirname(fileURLToPath(import.meta.url)), '..'); const source = readFileSync(resolve(root, 'src/api/resources.ts'), 'utf8'); const routes = readFileSync(resolve(root, 'src/router/routes/modules/platform.ts'), 'utf8'); const searchSource = readFileSync( resolve(root, 'src/views/shared/use-resource-list-search.ts'), 'utf8', ); const listPageSource = readFileSync( resolve(root, 'src/views/shared/CrudListPage.vue'), 'utf8', ); const fieldFormSource = readFileSync( resolve(root, 'src/views/resource/ResourceFieldForm.vue'), 'utf8', ); const contract = JSON.parse( readFileSync(resolve(root, 'src/contracts/gas-resources.json'), 'utf8'), ); const backend = new Map(contract.resources.map((item) => [item.name, item])); const gasSource = source.slice(source.indexOf('const gasOverrides')); const frontendDefinitions = [ ...gasSource.matchAll(/define\('([^']+)',\s*'[^']+',\s*'([^']+)'/g), ].map((match) => ({ name: match[1], mode: match[2] })); const frontendNames = frontendDefinitions.map((item) => item.name); const embeddedResources = new Set(); for (const name of frontendNames) { const item = backend.get(name); if (!item) throw new Error(`前端配置了后端不存在的资源:${name}`); if (item.path !== `/${name}`) throw new Error(`资源路径不一致:${name}`); } for (const item of contract.resources) { if (!frontendNames.includes(item.name)) throw new Error(`缺少后端资源配置:${item.name}`); const frontend = frontendDefinitions.find( (definition) => definition.name === item.name, ); if (frontend?.mode !== item.mode) throw new Error( `资源模式不一致:${item.name},后端=${item.mode},前端=${frontend?.mode}`, ); if (!embeddedResources.has(item.name) && !routes.includes(`'/${item.name}'`)) throw new Error(`缺少后端资源路由:${item.name}`); } const staffSearchFields = backend.get('staff_account')?.searchFields ?? []; if (staffSearchFields.map((field) => field.key).join(',') !== 'username,role_code') throw new Error('工作人员搜索契约必须明确为:用户名、角色'); if ((backend.get('user_address')?.searchFields ?? []).length > 0) throw new Error('不支持模糊搜索的用户地址资源不得公开搜索字段'); if (!searchSource.includes('searchableFields.value.length > 0')) throw new Error('列表搜索必须由资源搜索契约决定是否显示'); if (searchSource.includes('关键字段模糊搜索')) throw new Error('列表搜索不得使用含义不明确的兜底提示'); if (!listPageSource.includes('