9 changed files with 1352 additions and 111 deletions
@ -0,0 +1,280 @@ |
|||||||
|
const { readFileSync, existsSync, readdirSync } = require('fs') |
||||||
|
const { resolve } = require('path') |
||||||
|
const parser = require('@babel/parser') |
||||||
|
const traverse = require('@babel/traverse').default |
||||||
|
|
||||||
|
/** |
||||||
|
* 组件关系分析器 |
||||||
|
* 分析组件之间的层级关系,从子组件追溯到顶级组件 |
||||||
|
*/ |
||||||
|
class ComponentRelationshipAnalyzer { |
||||||
|
constructor() { |
||||||
|
this.componentRelationships = [] |
||||||
|
this.processedComponents = new Set() |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 分析组件关系 |
||||||
|
* @param {Array} routes - 路由数组 |
||||||
|
* @param {Array} apiMappings - API映射数组 |
||||||
|
* @returns {Array} 组件关系列表 |
||||||
|
*/ |
||||||
|
analyzeComponentRelationships(routes, apiMappings) { |
||||||
|
this.componentRelationships = [] |
||||||
|
this.processedComponents.clear() |
||||||
|
|
||||||
|
// 获取所有顶级组件(routes中的组件)
|
||||||
|
const topLevelComponents = routes.map(route => ({ |
||||||
|
component: route.component, |
||||||
|
module: this.getModuleFromRoute(route), |
||||||
|
path: route.path |
||||||
|
})) |
||||||
|
|
||||||
|
// 获取所有触发源组件
|
||||||
|
const triggerSourceComponents = this.extractTriggerSourceComponents(apiMappings) |
||||||
|
|
||||||
|
// 为每个触发源组件分析其与顶级组件的关系
|
||||||
|
triggerSourceComponents.forEach(triggerComponent => { |
||||||
|
this.analyzeComponentToTopLevel(triggerComponent, topLevelComponents) |
||||||
|
}) |
||||||
|
|
||||||
|
return this.componentRelationships |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 从路由中获取模块信息 |
||||||
|
* @param {Object} route - 路由对象 |
||||||
|
* @returns {string} 模块名称 |
||||||
|
*/ |
||||||
|
getModuleFromRoute(route) { |
||||||
|
// 根据路径推断模块
|
||||||
|
if (route.path === '/') return 'core' |
||||||
|
if (route.path.includes('user-management')) return 'user-management' |
||||||
|
if (route.path.includes('role-management')) return 'role-management' |
||||||
|
if (route.path.includes('settings')) return 'system-settings' |
||||||
|
if (route.path.includes('user-profile')) return 'user-management' |
||||||
|
return 'core' |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 提取所有触发源组件 |
||||||
|
* @param {Array} apiMappings - API映射数组 |
||||||
|
* @returns {Array} 触发源组件数组 |
||||||
|
*/ |
||||||
|
extractTriggerSourceComponents(apiMappings) { |
||||||
|
const components = [] |
||||||
|
|
||||||
|
apiMappings.forEach(apiMapping => { |
||||||
|
if (apiMapping.triggerSources) { |
||||||
|
apiMapping.triggerSources.forEach(triggerSource => { |
||||||
|
components.push({ |
||||||
|
component: triggerSource.component, |
||||||
|
module: triggerSource.module, |
||||||
|
triggerName: triggerSource.triggerName, |
||||||
|
triggerType: triggerSource.triggerType, |
||||||
|
apiMethodName: apiMapping.apiMethodName, |
||||||
|
apiModule: apiMapping.module |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
return components |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 分析组件到顶级组件的关系 |
||||||
|
* @param {Object} triggerComponent - 触发源组件 |
||||||
|
* @param {Array} topLevelComponents - 顶级组件数组 |
||||||
|
*/ |
||||||
|
analyzeComponentToTopLevel(triggerComponent, topLevelComponents) { |
||||||
|
const componentKey = `${triggerComponent.module}:${triggerComponent.component}` |
||||||
|
|
||||||
|
// 避免重复处理
|
||||||
|
if (this.processedComponents.has(componentKey)) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
this.processedComponents.add(componentKey) |
||||||
|
|
||||||
|
// 如果触发源组件本身就是顶级组件,直接建立关系
|
||||||
|
const isTopLevel = topLevelComponents.find(top =>
|
||||||
|
top.component === triggerComponent.component && top.module === triggerComponent.module |
||||||
|
) |
||||||
|
|
||||||
|
if (isTopLevel) { |
||||||
|
this.componentRelationships.push({ |
||||||
|
startComponent: triggerComponent.component, |
||||||
|
startModule: triggerComponent.module, |
||||||
|
endComponent: triggerComponent.component, |
||||||
|
endModule: triggerComponent.module, |
||||||
|
relationshipType: 'self', |
||||||
|
path: isTopLevel.path, |
||||||
|
triggerName: triggerComponent.triggerName, |
||||||
|
triggerType: triggerComponent.triggerType, |
||||||
|
apiMethodName: triggerComponent.apiMethodName |
||||||
|
}) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// 查找父组件关系
|
||||||
|
const parentComponents = this.findParentComponents(triggerComponent) |
||||||
|
|
||||||
|
parentComponents.forEach(parent => { |
||||||
|
// 递归查找父组件的父组件,直到找到顶级组件
|
||||||
|
this.findTopLevelAncestors(parent, triggerComponent, topLevelComponents) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 查找组件的父组件 |
||||||
|
* @param {Object} component - 组件信息 |
||||||
|
* @returns {Array} 父组件数组 |
||||||
|
*/ |
||||||
|
findParentComponents(component) { |
||||||
|
const parents = [] |
||||||
|
|
||||||
|
try { |
||||||
|
// 查找所有模块中的组件,看哪些引用了当前组件
|
||||||
|
const modulesPath = resolve(__dirname, '../../src/renderer/modules') |
||||||
|
if (existsSync(modulesPath)) { |
||||||
|
const moduleDirs = readdirSync(modulesPath, { withFileTypes: true }) |
||||||
|
.filter(dirent => dirent.isDirectory()) |
||||||
|
.map(dirent => dirent.name) |
||||||
|
|
||||||
|
moduleDirs.forEach(moduleName => { |
||||||
|
const parentComponents = this.findComponentsInModule(moduleName, component) |
||||||
|
parents.push(...parentComponents) |
||||||
|
}) |
||||||
|
} |
||||||
|
} catch (error) { |
||||||
|
// 静默处理错误
|
||||||
|
} |
||||||
|
|
||||||
|
return parents |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 在指定模块中查找引用目标组件的组件 |
||||||
|
* @param {string} moduleName - 模块名称 |
||||||
|
* @param {Object} targetComponent - 目标组件 |
||||||
|
* @returns {Array} 父组件数组 |
||||||
|
*/ |
||||||
|
findComponentsInModule(moduleName, targetComponent) { |
||||||
|
const parents = [] |
||||||
|
|
||||||
|
try { |
||||||
|
const modulePath = resolve(__dirname, '../../src/renderer/modules', moduleName) |
||||||
|
if (!existsSync(modulePath)) return parents |
||||||
|
|
||||||
|
// 查找views目录
|
||||||
|
const viewsPath = resolve(modulePath, 'views') |
||||||
|
if (existsSync(viewsPath)) { |
||||||
|
const viewFiles = readdirSync(viewsPath).filter(file => file.endsWith('.vue')) |
||||||
|
viewFiles.forEach(file => { |
||||||
|
const componentName = file.replace('.vue', '') |
||||||
|
if (this.componentReferencesTarget(viewsPath, file, targetComponent)) { |
||||||
|
parents.push({ |
||||||
|
component: componentName, |
||||||
|
module: moduleName, |
||||||
|
type: 'view' |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// 查找components目录
|
||||||
|
const componentsPath = resolve(modulePath, 'components') |
||||||
|
if (existsSync(componentsPath)) { |
||||||
|
const componentFiles = readdirSync(componentsPath).filter(file => file.endsWith('.vue')) |
||||||
|
componentFiles.forEach(file => { |
||||||
|
const componentName = file.replace('.vue', '') |
||||||
|
if (this.componentReferencesTarget(componentsPath, file, targetComponent)) { |
||||||
|
parents.push({ |
||||||
|
component: componentName, |
||||||
|
module: moduleName, |
||||||
|
type: 'component' |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} catch (error) { |
||||||
|
// 静默处理错误
|
||||||
|
} |
||||||
|
|
||||||
|
return parents |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 检查组件是否引用了目标组件 |
||||||
|
* @param {string} dirPath - 目录路径 |
||||||
|
* @param {string} fileName - 文件名 |
||||||
|
* @param {Object} targetComponent - 目标组件 |
||||||
|
* @returns {boolean} 是否引用 |
||||||
|
*/ |
||||||
|
componentReferencesTarget(dirPath, fileName, targetComponent) { |
||||||
|
try { |
||||||
|
const filePath = resolve(dirPath, fileName) |
||||||
|
const content = readFileSync(filePath, 'utf-8') |
||||||
|
|
||||||
|
// 检查import语句
|
||||||
|
const importPattern = new RegExp(`import.*${targetComponent.component}.*from`, 'g') |
||||||
|
if (importPattern.test(content)) { |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
// 检查components注册
|
||||||
|
const componentPattern = new RegExp(`${targetComponent.component}\\s*:`, 'g') |
||||||
|
if (componentPattern.test(content)) { |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
// 检查模板中的使用
|
||||||
|
const templatePattern = new RegExp(`<${targetComponent.component}[\\s>]`, 'g') |
||||||
|
if (templatePattern.test(content)) { |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
return false |
||||||
|
} catch (error) { |
||||||
|
return false |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 查找顶级祖先组件 |
||||||
|
* @param {Object} parentComponent - 父组件 |
||||||
|
* @param {Object} originalTrigger - 原始触发组件 |
||||||
|
* @param {Array} topLevelComponents - 顶级组件数组 |
||||||
|
*/ |
||||||
|
findTopLevelAncestors(parentComponent, originalTrigger, topLevelComponents) { |
||||||
|
// 检查父组件是否是顶级组件
|
||||||
|
const isTopLevel = topLevelComponents.find(top =>
|
||||||
|
top.component === parentComponent.component && top.module === parentComponent.module |
||||||
|
) |
||||||
|
|
||||||
|
if (isTopLevel) { |
||||||
|
// 找到顶级组件,建立关系
|
||||||
|
this.componentRelationships.push({ |
||||||
|
startComponent: originalTrigger.component, |
||||||
|
startModule: originalTrigger.module, |
||||||
|
endComponent: parentComponent.component, |
||||||
|
endModule: parentComponent.module, |
||||||
|
relationshipType: 'ancestor', |
||||||
|
path: isTopLevel.path, |
||||||
|
triggerName: originalTrigger.triggerName, |
||||||
|
triggerType: originalTrigger.triggerType, |
||||||
|
apiMethodName: originalTrigger.apiMethodName |
||||||
|
}) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// 继续向上查找
|
||||||
|
const grandParents = this.findParentComponents(parentComponent) |
||||||
|
grandParents.forEach(grandParent => { |
||||||
|
this.findTopLevelAncestors(grandParent, originalTrigger, topLevelComponents) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = ComponentRelationshipAnalyzer |
@ -1,32 +1,376 @@ |
|||||||
// 路由映射数据 - 构建时生成
|
// 路由映射数据 - 构建时生成
|
||||||
export default { |
export default { |
||||||
|
// 路由配置
|
||||||
"routes": [ |
"routes": [ |
||||||
{ |
{ |
||||||
"path": "/", |
"id": 1, |
||||||
"component": "MainLayout", |
"path": "/", |
||||||
"name": "Home", |
"component": "MainLayout", |
||||||
"description": "首页" |
"module": "core" |
||||||
}, |
}, |
||||||
{ |
{ |
||||||
"path": "/user-management", |
"id": 2, |
||||||
"component": "UserManagement", |
"path": "/user-management", |
||||||
"description": "用户管理" |
"name": "UserManagement", |
||||||
}, |
"component": "UserManagement", |
||||||
{ |
"module": "user-management", |
||||||
"path": "/settings", |
"description": "用户管理" |
||||||
"component": "Settings", |
}, |
||||||
"description": "系统设置" |
{ |
||||||
}, |
"id": 3, |
||||||
{ |
"path": "/settings", |
||||||
"path": "/user-profile", |
"name": "Settings", |
||||||
"component": "UserProfile", |
"component": "Settings", |
||||||
"description": "个人资料" |
"module": "system-settings", |
||||||
}, |
"description": "系统设置" |
||||||
{ |
}, |
||||||
"path": "/role-management", |
{ |
||||||
"component": "RoleManagement", |
"id": 4, |
||||||
"description": "角色管理" |
"path": "/user-profile", |
||||||
} |
"name": "UserProfile", |
||||||
], |
"component": "UserProfile", |
||||||
"apiMappings": [] |
"module": "user-management", |
||||||
}; |
"description": "个人资料" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 5, |
||||||
|
"path": "/role-management", |
||||||
|
"name": "RoleManagement", |
||||||
|
"component": "RoleManagement", |
||||||
|
"module": "role-management", |
||||||
|
"description": "角色管理" |
||||||
|
} |
||||||
|
], |
||||||
|
|
||||||
|
// API映射配置
|
||||||
|
"apiMappings": [ |
||||||
|
{ |
||||||
|
"apiMethodName": "createRole", |
||||||
|
"method": "POST", |
||||||
|
"path": "/api/auth/roles", |
||||||
|
"serviceName": "roleService", |
||||||
|
"module": "role-management", |
||||||
|
"triggerSources": [ |
||||||
|
{ |
||||||
|
"id": 1, |
||||||
|
"component": "RoleManagement", |
||||||
|
"module": "role-management", |
||||||
|
"triggerName": "rolemanagement-submit-lhm6fs", |
||||||
|
"triggerType": "button" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"apiMethodName": "updateRole", |
||||||
|
"method": "PUT", |
||||||
|
"path": "/api/auth/roles/{id}", |
||||||
|
"serviceName": "roleService", |
||||||
|
"module": "role-management", |
||||||
|
"triggerSources": [ |
||||||
|
{ |
||||||
|
"id": 2, |
||||||
|
"component": "RoleManagement", |
||||||
|
"module": "role-management", |
||||||
|
"triggerName": "rolemanagement-submit-lhm6fs", |
||||||
|
"triggerType": "button" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 3, |
||||||
|
"component": "PermissionManager", |
||||||
|
"module": "role-management", |
||||||
|
"triggerName": "permissionmanager-button-k7wqyp", |
||||||
|
"triggerType": "button" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"apiMethodName": "deleteRole", |
||||||
|
"method": "DELETE", |
||||||
|
"path": "/api/auth/roles/{id}", |
||||||
|
"serviceName": "roleService", |
||||||
|
"module": "role-management", |
||||||
|
"triggerSources": [ |
||||||
|
{ |
||||||
|
"id": 4, |
||||||
|
"component": "RoleManagement", |
||||||
|
"module": "role-management", |
||||||
|
"triggerName": "rolemanagement-button-0eqx80", |
||||||
|
"triggerType": "button" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"apiMethodName": "assignRolesToUser", |
||||||
|
"method": "POST", |
||||||
|
"path": "/api/auth/roles/users/{userId}/assign", |
||||||
|
"serviceName": "roleService", |
||||||
|
"module": "role-management", |
||||||
|
"triggerSources": [ |
||||||
|
{ |
||||||
|
"id": 5, |
||||||
|
"component": "UserRoleAssignment", |
||||||
|
"module": "role-management", |
||||||
|
"triggerName": "userroleassignment-button-3npmn8", |
||||||
|
"triggerType": "button" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"apiMethodName": "removeRolesFromUser", |
||||||
|
"method": "DELETE", |
||||||
|
"path": "/api/auth/roles/users/{userId}/remove", |
||||||
|
"serviceName": "roleService", |
||||||
|
"module": "role-management", |
||||||
|
"triggerSources": [ |
||||||
|
{ |
||||||
|
"id": 6, |
||||||
|
"component": "UserRoleAssignment", |
||||||
|
"module": "role-management", |
||||||
|
"triggerName": "userroleassignment-button-3npmn8", |
||||||
|
"triggerType": "button" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"apiMethodName": "assignPermissionsToRole", |
||||||
|
"method": "POST", |
||||||
|
"path": "/api/auth/permissions/roles/{roleId}/assign", |
||||||
|
"serviceName": "roleService", |
||||||
|
"module": "role-management", |
||||||
|
"triggerSources": [ |
||||||
|
{ |
||||||
|
"id": 7, |
||||||
|
"component": "RolePermissionAssignment", |
||||||
|
"module": "role-management", |
||||||
|
"triggerName": "rolepermissionassignment-button-7uizm5", |
||||||
|
"triggerType": "button" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 8, |
||||||
|
"component": "RolePermissionAssignment", |
||||||
|
"module": "role-management", |
||||||
|
"triggerName": "rolepermissionassignment-button-a0nyh8", |
||||||
|
"triggerType": "button" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"apiMethodName": "removePermissionsFromRole", |
||||||
|
"method": "DELETE", |
||||||
|
"path": "/api/auth/permissions/roles/{roleId}/remove", |
||||||
|
"serviceName": "roleService", |
||||||
|
"module": "role-management", |
||||||
|
"triggerSources": [ |
||||||
|
{ |
||||||
|
"id": 9, |
||||||
|
"component": "RolePermissionAssignment", |
||||||
|
"module": "role-management", |
||||||
|
"triggerName": "rolepermissionassignment-button-q86qi4", |
||||||
|
"triggerType": "button" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 10, |
||||||
|
"component": "RolePermissionAssignment", |
||||||
|
"module": "role-management", |
||||||
|
"triggerName": "rolepermissionassignment-button-sj6qb7", |
||||||
|
"triggerType": "button" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"apiMethodName": "createUser", |
||||||
|
"method": "POST", |
||||||
|
"path": "/api/auth/admin/users", |
||||||
|
"serviceName": "userService", |
||||||
|
"module": "user-management", |
||||||
|
"triggerSources": [ |
||||||
|
{ |
||||||
|
"id": 11, |
||||||
|
"component": "UserManagement", |
||||||
|
"module": "user-management", |
||||||
|
"triggerName": "usermanagement-submit-fksbqh", |
||||||
|
"triggerType": "button" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"apiMethodName": "updateUser", |
||||||
|
"method": "PUT", |
||||||
|
"path": "/api/auth/admin/users/{id}", |
||||||
|
"serviceName": "userService", |
||||||
|
"module": "user-management", |
||||||
|
"triggerSources": [ |
||||||
|
{ |
||||||
|
"id": 12, |
||||||
|
"component": "UserManagement", |
||||||
|
"module": "user-management", |
||||||
|
"triggerName": "usermanagement-submit-fksbqh", |
||||||
|
"triggerType": "button" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"apiMethodName": "deleteUser", |
||||||
|
"method": "DELETE", |
||||||
|
"path": "/api/auth/admin/users/{id}", |
||||||
|
"serviceName": "userService", |
||||||
|
"module": "user-management", |
||||||
|
"triggerSources": [ |
||||||
|
{ |
||||||
|
"id": 13, |
||||||
|
"component": "UserManagement", |
||||||
|
"module": "user-management", |
||||||
|
"triggerName": "usermanagement-button-tvncrr", |
||||||
|
"triggerType": "button" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"apiMethodName": "changePassword", |
||||||
|
"method": "POST", |
||||||
|
"path": "/api/auth/change-password", |
||||||
|
"serviceName": "userService", |
||||||
|
"module": "user-management", |
||||||
|
"triggerSources": [ |
||||||
|
{ |
||||||
|
"id": 14, |
||||||
|
"component": "PasswordChangeModal", |
||||||
|
"module": "user-management", |
||||||
|
"triggerName": "passwordchangemodal-submit-2p704c", |
||||||
|
"triggerType": "button" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"apiMethodName": "validatePassword", |
||||||
|
"method": "POST", |
||||||
|
"path": "/api/auth/validate-password", |
||||||
|
"serviceName": "userService", |
||||||
|
"module": "user-management", |
||||||
|
"triggerSources": [ |
||||||
|
{ |
||||||
|
"id": 15, |
||||||
|
"component": "PasswordChangeModal", |
||||||
|
"module": "user-management", |
||||||
|
"triggerName": "passwordchangemodal-input-0xe3cd", |
||||||
|
"triggerType": "input" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"apiMethodName": "changePassword", |
||||||
|
"method": "POST", |
||||||
|
"path": "/api/auth/change-password", |
||||||
|
"serviceName": "userService", |
||||||
|
"module": "user-management", |
||||||
|
"triggerSources": [ |
||||||
|
{ |
||||||
|
"id": 16, |
||||||
|
"component": "PasswordChangeModal", |
||||||
|
"module": "user-management", |
||||||
|
"triggerName": "passwordchangemodal-submit-2p704c", |
||||||
|
"triggerType": "button" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
], |
||||||
|
|
||||||
|
// 组件关系配置(简化版)
|
||||||
|
"componentRelationships": [ |
||||||
|
{ |
||||||
|
"triggerSourceId": 1, |
||||||
|
"routeId": 5, |
||||||
|
"relationshipType": "self" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 2, |
||||||
|
"routeId": 5, |
||||||
|
"relationshipType": "self" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 3, |
||||||
|
"routeId": 5, |
||||||
|
"relationshipType": "direct" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 4, |
||||||
|
"routeId": 5, |
||||||
|
"relationshipType": "self" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 5, |
||||||
|
"routeId": 2, |
||||||
|
"relationshipType": "ancestor" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 6, |
||||||
|
"routeId": 2, |
||||||
|
"relationshipType": "ancestor" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 7, |
||||||
|
"routeId": 5, |
||||||
|
"relationshipType": "ancestor" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 8, |
||||||
|
"routeId": 5, |
||||||
|
"relationshipType": "ancestor" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 9, |
||||||
|
"routeId": 5, |
||||||
|
"relationshipType": "ancestor" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 10, |
||||||
|
"routeId": 5, |
||||||
|
"relationshipType": "ancestor" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 11, |
||||||
|
"routeId": 2, |
||||||
|
"relationshipType": "self" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 12, |
||||||
|
"routeId": 2, |
||||||
|
"relationshipType": "self" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 13, |
||||||
|
"routeId": 2, |
||||||
|
"relationshipType": "self" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 14, |
||||||
|
"routeId": 1, |
||||||
|
"relationshipType": "ancestor" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 14, |
||||||
|
"routeId": 4, |
||||||
|
"relationshipType": "ancestor" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 15, |
||||||
|
"routeId": 1, |
||||||
|
"relationshipType": "ancestor" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 15, |
||||||
|
"routeId": 4, |
||||||
|
"relationshipType": "ancestor" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 16, |
||||||
|
"routeId": 1, |
||||||
|
"relationshipType": "ancestor" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"triggerSourceId": 16, |
||||||
|
"routeId": 4, |
||||||
|
"relationshipType": "ancestor" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
Loading…
Reference in new issue