基于AST的资产路由端点提取新方案

admin 2026-01-07 02:35:17 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 文章提出用AST语义分析替代传统正则匹配提取Node.js前端路由,可精准识别动态与隐藏路由并输出完整端点、参数、中间件及验证规则,显著提升资产收敛效率与攻击面发现能力,附完整Babel提取器代码可直接复现。 综合评分: 88 文章分类: 安全工具,代码审计,应用安全,WEB安全,实战经验


cover_image

基于AST的资产路由端点提取新方案

原创

鉴帷安全

鉴帷安全

2026年1月6日 15:39 湖北

目前市面上大多数都是基于正则匹配的路由提取方案,这对于一些动态路由来说,已经完全不够用了,会有极高的错误率和无法匹配的情况,而基于AST的前端路由提取方案,则能更好的匹配这些动态路由与隐藏路由,我们先来看一个例子。

前置需求

环境:Node.js,babel模块

IDEA:WebStorm

OS:windows,其余系统未测试,出问题自行解决

exmple:

const express = require('express');const router = express.Router();const createRoutes = (versions) => {  versions.forEach(ver => {    router.get(`/v${ver}/:entity`, validate(ver), (req, res) => {      const { entity } = req.params;      const ids = req.query.ids?.split(',').map(Number) || [];      res.json({ entity, version: ver, ids });    });  });};const validate = (version) => (req, res, next) => {  const regex = version >= 2 ? /^[A-Z]\d{3}$/ : /^\w{4,8}$/;  if (!regex.test(req.params.entity)) {    return res.status(400).send('实体格式错误');  }  next();};createRoutes([1, 2]);router.param('entity', (req, res, next, value) => {  req.entity = { raw: value, normalized: value.toLowerCase() };  next();});module.exports = router;

如果我们用正则来匹配路由端点的话,是无法匹配到所有路由的,比如这样:

/\/(v[12])\/:entity/g

对于收敛暴露面和发现更多资产而言,这将遗留很大一部分接口,同时,在正则表达式情况下,需要人工去复核的JS代码中的路由情况,也会增加额外的工作量,而AST技术,基于语义分析,可以很好的提取这些路由API和端点。

const&nbsp;parser = require('@babel/parser');const&nbsp;traverse = require('@babel/traverse').default;const&nbsp;t = require('@babel/types');const&nbsp;generator = require('@babel/generator').default;const&nbsp;fs = require('fs');class&nbsp;AdvancedASTRouteExtractor&nbsp;{&nbsp; &nbsp;&nbsp;constructor() {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.routes = [];&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.middlewares = new Map();&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.routerDeclarations = new Map();&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.functionDefinitions = new Map();&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.imports = new Map();&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.currentFile =&nbsp;null;&nbsp; &nbsp; }&nbsp; &nbsp; parseCode(code, filename =&nbsp;null) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.currentFile = filename;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;ast = parser.parse(code, {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sourceType:&nbsp;'module',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; plugins: [&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'jsx',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'typescript',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'asyncGenerators',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'classProperties',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'decorators-legacy',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'dynamicImport',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'exportDefaultFrom',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'exportNamespaceFrom',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'functionBind',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'functionSent',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'nullishCoalescingOperator',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'numericSeparator',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'objectRestSpread',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'optionalCatchBinding',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'optionalChaining',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'throwExpressions'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ]&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 分阶段分析&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.analyzeImports(ast);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.analyzeFunctionDefinitions(ast);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.analyzeRouterDeclarations(ast);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.analyzeRouteDefinitions(ast);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.analyzeDynamicRoutes(ast);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.resolveDependencies();&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;this.generateCompleteReport();&nbsp; &nbsp; }&nbsp; &nbsp; analyzeImports(ast) {&nbsp; &nbsp; &nbsp; &nbsp; traverse(ast, {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ImportDeclaration: (path) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;source = path.node.source.value;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; path.node.specifiers.forEach(specifier => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isImportDefaultSpecifier(specifier)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.imports.set(specifier.local.name, {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'default',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; source,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name: specifier.local.name&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(t.isImportSpecifier(specifier)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.imports.set(specifier.local.name, {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'named',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; source,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name: specifier.imported.name,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local: specifier.local.name&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; VariableDeclaration: (path) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 处理 require 导入&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; path.node.declarations.forEach(declaration => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isVariableDeclarator(declaration) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isCallExpression(declaration.init) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(declaration.init.callee, { name:&nbsp;'require'&nbsp;})) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;source = declaration.init.arguments[0]?.value;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;varName = declaration.id.name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.imports.set(varName, {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'require',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; source,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name: varName&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; }&nbsp; &nbsp; analyzeFunctionDefinitions(ast) {&nbsp; &nbsp; &nbsp; &nbsp; traverse(ast, {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FunctionDeclaration: (path) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;funcName = path.node.id?.name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(funcName) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.functionDefinitions.set(funcName, {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'function',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; node: path.node,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; params:&nbsp;this.extractFunctionParams(path.node),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; body: path.node.body,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; location: path.node.loc&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; VariableDeclaration: (path) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; path.node.declarations.forEach(declaration => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isVariableDeclarator(declaration) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (t.isArrowFunctionExpression(declaration.init) ||&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isFunctionExpression(declaration.init))) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;funcName = declaration.id.name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;funcNode = declaration.init;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.functionDefinitions.set(funcName, {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type: declaration.init.type ===&nbsp;'ArrowFunctionExpression'&nbsp;?&nbsp;'arrow'&nbsp;:&nbsp;'function',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; node: funcNode,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; params:&nbsp;this.extractFunctionParams(funcNode),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; body: funcNode.body,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; location: funcNode.loc&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; }&nbsp; &nbsp; analyzeRouterDeclarations(ast) {&nbsp; &nbsp; &nbsp; &nbsp; traverse(ast, {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CallExpression: (path) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 查找 const router = express.Router() 或类似&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;node = path.node;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isMemberExpression(node.callee) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (t.isIdentifier(node.callee.object) || t.isCallExpression(node.callee.object)) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(node.callee.property, { name:&nbsp;'Router'&nbsp;})) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 向上查找变量声明&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let parent = path.parentPath;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;while&nbsp;(parent && !t.isVariableDeclaration(parent.node)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; parent = parent.parentPath;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(parent && t.isVariableDeclaration(parent.node)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; parent.node.declarations.forEach(declaration => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isVariableDeclarator(declaration) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; declaration.init&nbsp;=== node &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(declaration.id)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.routerDeclarations.set(declaration.id.name, {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'express',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; node: node,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; location: node.loc&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; }&nbsp; &nbsp; analyzeRouteDefinitions(ast) {&nbsp; &nbsp; &nbsp; &nbsp; traverse(ast, {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CallExpression: (path) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;node = path.node;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 处理 router.METHOD(path, ...handlers)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isMemberExpression(node.callee) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(node.callee.object)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;routerName = node.callee.object.name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(this.routerDeclarations.has(routerName) ||&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.imports.has(routerName) &&&nbsp;this.imports.get(routerName).source ===&nbsp;'express') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;method = node.callee.property.name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;httpMethods = new Set([&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'get',&nbsp;'post',&nbsp;'put',&nbsp;'delete',&nbsp;'patch',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'head',&nbsp;'options',&nbsp;'all',&nbsp;'use'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ]);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(httpMethods.has(method)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.processRouteCall(node, method, routerName, path);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 处理函数调用生成路由,如 createRoutes([1, 2])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isCallExpression(node.callee) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(node.callee)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;funcName = node.callee.name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(this.functionDefinitions.has(funcName)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.processRouteGenerator(node, funcName, path);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; }&nbsp; &nbsp; processRouteCall(node, method, routerName, path) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(node.arguments.length ===&nbsp;0)&nbsp;return;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;pathArg = node.arguments[0];&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;handlers = node.arguments.slice(1);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 提取路径&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;pathInfo =&nbsp;this.extractPathValue(pathArg);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(!pathInfo)&nbsp;return;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 提取中间件信息&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;middlewareInfo =&nbsp;this.extractMiddlewareInfo(handlers);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 提取参数信息&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;paramInfo =&nbsp;this.extractParameterInfo(pathInfo.value);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 分析处理函数&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;handlerAnalysis =&nbsp;this.analyzeRouteHandlers(handlers);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;route = {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; method: method.toUpperCase(),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; path: pathInfo.value,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; originalPath: pathInfo.original,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; router: routerName,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; parameters: paramInfo.pathParams,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; queryParameters: paramInfo.queryParams,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; middleware: middlewareInfo.middlewares,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; handlers: handlerAnalysis,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; validations: middlewareInfo.validations,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; responses: handlerAnalysis.responses,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; location: node.loc,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type: pathInfo.isDynamic ?&nbsp;'dynamic_template'&nbsp;:&nbsp;'static',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; file:&nbsp;this.currentFile&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.routes.push(route);&nbsp; &nbsp; }&nbsp; &nbsp; processRouteGenerator(node, funcName, path) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;funcDef =&nbsp;this.functionDefinitions.get(funcName);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(!funcDef)&nbsp;return;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 分析函数定义,查找路由创建模式&nbsp; &nbsp; &nbsp; &nbsp; traverse(funcDef.node, {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CallExpression: (innerPath) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;innerNode = innerPath.node;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 查找 router.METHOD 调用&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isMemberExpression(innerNode.callee) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(innerNode.callee.object)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;routerName = innerNode.callee.object.name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;method = innerNode.callee.property.name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(this.routerDeclarations.has(routerName)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 检查是否在循环中&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let parentPath = innerPath.parentPath;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let isInLoop =&nbsp;false;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let loopInfo =&nbsp;null;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;while&nbsp;(parentPath) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isForEachStatement(parentPath.node) ||&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isForStatement(parentPath.node) ||&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isWhileStatement(parentPath.node) ||&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isForOfStatement(parentPath.node) ||&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isForInStatement(parentPath.node)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isInLoop =&nbsp;true;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loopInfo =&nbsp;this.analyzeLoop(parentPath.node);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; parentPath = parentPath.parentPath;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(isInLoop) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.processDynamicRouteInLoop(innerNode, method, routerName, loopInfo, node.arguments, path);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }, funcDef.node);&nbsp; &nbsp; }&nbsp; &nbsp; analyzeLoop(loopNode) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isForEachStatement(loopNode)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'forEach',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; array: loopNode.callee.object,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; param: loopNode.params[0]?.name,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; body: loopNode.body&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(t.isForStatement(loopNode)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'for',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;init: loopNode.init,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; test: loopNode.test,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; update: loopNode.update,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; body: loopNode.body&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;null;&nbsp; &nbsp; }&nbsp; &nbsp; processDynamicRouteInLoop(node, method, routerName, loopInfo, generatorArgs, originalPath) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 尝试静态分析循环&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(loopInfo.type ===&nbsp;'forEach') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 分析数组&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;arrayValue =&nbsp;this.evaluateStaticExpression(loopInfo.array, generatorArgs);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(arrayValue && Array.isArray(arrayValue)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; arrayValue.forEach(item => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.processDynamicRouteItem(node, method, routerName, loopInfo.param, item, originalPath);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; processDynamicRouteItem(node, method, routerName, paramName, paramValue, originalArgs) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;pathArg = node.arguments[0];&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;handlers = node.arguments.slice(1);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 替换模板中的变量&nbsp; &nbsp; &nbsp; &nbsp; let resolvedPath =&nbsp;this.extractPathValue(pathArg).value;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(paramName) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; resolvedPath = resolvedPath.replace(`\${${paramName}}`, paramValue);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; resolvedPath = resolvedPath.replace(`\$${paramName}`, paramValue);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;middlewareInfo =&nbsp;this.extractMiddlewareInfo(handlers);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;paramInfo =&nbsp;this.extractParameterInfo(resolvedPath);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;handlerAnalysis =&nbsp;this.analyzeRouteHandlers(handlers);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 替换中间件中的变量引用&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;processedMiddleware =&nbsp;this.processMiddlewareWithParam(middlewareInfo.middlewares, paramName, paramValue);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;route = {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; method: method.toUpperCase(),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; path: resolvedPath,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; originalPath:&nbsp;this.extractPathValue(pathArg).original,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; router: routerName,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; parameters: paramInfo.pathParams,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; queryParameters: paramInfo.queryParams,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; middleware: processedMiddleware,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; handlers: handlerAnalysis,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; validations: middlewareInfo.validations,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; responses: handlerAnalysis.responses,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; location: node.loc,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'generated',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; generator: {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; param: paramName,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value: paramValue,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; source: originalArgs&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; file:&nbsp;this.currentFile&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.routes.push(route);&nbsp; &nbsp; }&nbsp; &nbsp; extractPathValue(node) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isStringLiteral(node)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value: node.value,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; original: `'${node.value}'`,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isDynamic:&nbsp;false&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isTemplateLiteral(node)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;templateValue =&nbsp;this.generateTemplateLiteral(node);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value: templateValue,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; original:&nbsp;this.generateCode(node),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isDynamic: node.expressions.length >&nbsp;0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isBinaryExpression(node) && node.operator&nbsp;===&nbsp;'+') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 拼接的路径&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;left =&nbsp;this.extractPathValue(node.left);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;right =&nbsp;this.extractPathValue(node.right);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(left && right) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value: left.value + right.value,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; original: `${left.original} + ${right.original}`,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isDynamic: left.isDynamic || right.isDynamic&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value:&nbsp;this.generateCode(node),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; original:&nbsp;this.generateCode(node),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isDynamic:&nbsp;true&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; }&nbsp; &nbsp; generateTemplateLiteral(node) {&nbsp; &nbsp; &nbsp; &nbsp; let parts = [];&nbsp; &nbsp; &nbsp; &nbsp; node.quasis.forEach((quasi, index) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; parts.push(quasi.value.raw);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(index < node.expressions.length) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;exprCode =&nbsp;this.generateCode(node.expressions[index]);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; parts.push(`{${exprCode}}`);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;parts.join('');&nbsp; &nbsp; }&nbsp; &nbsp; extractParameterInfo(path) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;pathParams = [];&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;queryParams = new Set();&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 提取路径参数 :param&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;pathParts = path.split('/');&nbsp; &nbsp; &nbsp; &nbsp; pathParts.forEach(part => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(part.startsWith(':')) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pathParams.push({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name: part.substring(1),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'path',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; required:&nbsp;true,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; location:&nbsp;'path',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pattern:&nbsp;null&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pathParams,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; queryParams: Array.from(queryParams).map(name => ({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'query',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; required:&nbsp;false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; location:&nbsp;'query'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }))&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; }&nbsp; &nbsp; extractMiddlewareInfo(handlerNodes) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;middlewares = [];&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;validations = [];&nbsp; &nbsp; &nbsp; &nbsp; handlerNodes.forEach(handler => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isIdentifier(handler)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;handlerName = handler.name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 检查是否是已定义的函数&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(this.functionDefinitions.has(handlerName)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;funcDef =&nbsp;this.functionDefinitions.get(handlerName);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;funcValidations =&nbsp;this.analyzeFunctionValidations(funcDef);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; middlewares.push({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name: handlerName,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'function',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; definition: funcDef,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; validations: funcValidations&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; validations.push(...funcValidations);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; middlewares.push({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name: handlerName,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'unknown'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(t.isCallExpression(handler)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 中间件调用,如 validate(ver)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; middlewares.push({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'call',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; expression:&nbsp;this.generateCode(handler),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; callee:&nbsp;this.generateCode(handler.callee)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(t.isArrowFunctionExpression(handler) ||&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isFunctionExpression(handler)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 内联函数&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;inlineValidations =&nbsp;this.analyzeInlineValidations(handler);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; middlewares.push({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'inline',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; params: handler.params.map(p =>&nbsp;this.generateCode(p)),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; validations: inlineValidations&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; validations.push(...inlineValidations);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{ middlewares, validations };&nbsp; &nbsp; }&nbsp; &nbsp; analyzeFunctionValidations(funcDef) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;validations = [];&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(!funcDef.body || !t.isBlockStatement(funcDef.body)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;validations;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; traverse(funcDef.body, {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IfStatement: (path) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;validation =&nbsp;this.extractValidationFromIf(path.node);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(validation) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; validations.push(validation);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ReturnStatement: (path) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(path.node.argument &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isCallExpression(path.node.argument) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isMemberExpression(path.node.argument.callee) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(path.node.argument.callee.object, { name:&nbsp;'res'&nbsp;})) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 检查是否返回错误响应&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;method = path.node.argument.callee.property.name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(method ===&nbsp;'status'&nbsp;|| method ===&nbsp;'send'&nbsp;|| method ===&nbsp;'json') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; validations.push({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'error_response',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; method: method,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; condition:&nbsp;'unknown',&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; location: path.node.loc&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }, funcDef.body);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;validations;&nbsp; &nbsp; }&nbsp; &nbsp; extractValidationFromIf(ifNode) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;condition = ifNode.test;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;consequent = ifNode.consequent;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 正则测试&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isCallExpression(condition) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isMemberExpression(condition.callee) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isCallExpression(condition.callee.object)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;testCall = condition.callee.object;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isMemberExpression(testCall.callee) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isRegExpLiteral(testCall.callee.object)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;regex = testCall.callee.object.pattern;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;errorMessage =&nbsp;this.extractErrorMessage(consequent);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'regex',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pattern: regex,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; message: errorMessage,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; location: ifNode.loc&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 简单的布尔表达式&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isUnaryExpression(condition) && condition.operator&nbsp;===&nbsp;'!') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;inner&nbsp;= condition.argument;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isCallExpression(inner) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isMemberExpression(inner.callee) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isRegExpLiteral(inner.callee.object)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;regex =&nbsp;inner.callee.object.pattern;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;errorMessage =&nbsp;this.extractErrorMessage(consequent);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'regex',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pattern: regex,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; message: errorMessage,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; location: ifNode.loc&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;null;&nbsp; &nbsp; }&nbsp; &nbsp; extractErrorMessage(consequent) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isBlockStatement(consequent)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;statements = consequent.body;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;(const&nbsp;stmt of statements) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isReturnStatement(stmt) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; stmt.argument &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isCallExpression(stmt.argument) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isMemberExpression(stmt.argument.callee) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(stmt.argument.callee.object, { name:&nbsp;'res'&nbsp;})) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;method = stmt.argument.callee.property.name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;args = stmt.argument.arguments;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(method ===&nbsp;'send'&nbsp;&& args.length >&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;this.extractStringValue(args[0]);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(method ===&nbsp;'status'&nbsp;&&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isCallExpression(stmt.argument.callee.object) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isMemberExpression(stmt.argument.callee.object.callee) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(stmt.argument.callee.object.callee.object, { name:&nbsp;'res'&nbsp;}) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(stmt.argument.callee.object.callee.property, { name:&nbsp;'status'&nbsp;})) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;statusArgs = stmt.argument.callee.object.arguments;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;sendArgs = args;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(sendArgs.length >&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;this.extractStringValue(sendArgs[0]);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;null;&nbsp; &nbsp; }&nbsp; &nbsp; analyzeInlineValidations(funcNode) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;validations = [];&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(!t.isBlockStatement(funcNode.body)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;validations;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; traverse(funcNode.body, {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IfStatement: (path) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;validation =&nbsp;this.extractValidationFromIf(path.node);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(validation) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; validations.push(validation);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }, funcNode.body);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;validations;&nbsp; &nbsp; }&nbsp; &nbsp; analyzeRouteHandlers(handlerNodes) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;handlers = [];&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;responses = [];&nbsp; &nbsp; &nbsp; &nbsp; handlerNodes.forEach((handler, index) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isArrowFunctionExpression(handler) ||&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isFunctionExpression(handler)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;handlerAnalysis =&nbsp;this.analyzeHandler(handler, index);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; handlers.push(handlerAnalysis);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(handlerAnalysis.responses) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; responses.push(...handlerAnalysis.responses);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(t.isIdentifier(handler)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; handlers.push({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'named_middleware',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name: handler.name,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; index: index&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{ handlers, responses };&nbsp; &nbsp; }&nbsp; &nbsp; analyzeHandler(handler, index) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;responses = [];&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;queryParams = new Set();&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;bodyParams = new Set();&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(!t.isBlockStatement(handler.body)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'arrow_function',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; params: handler.params.map(p =>&nbsp;this.generateCode(p)),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; index: index,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; body:&nbsp;this.generateCode(handler.body)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; traverse(handler.body, {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CallExpression: (path) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;node = path.node;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 提取响应&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isMemberExpression(node.callee) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(node.callee.object, { name:&nbsp;'res'&nbsp;})) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;method = node.callee.property.name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(method ===&nbsp;'json') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;data&nbsp;=&nbsp;this.extractResponseData(node.arguments[0]);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; responses.push({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'success',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; method:&nbsp;'json',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;data:&nbsp;data,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; location: node.loc&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(method ===&nbsp;'send') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; responses.push({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'raw',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; method:&nbsp;'send',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; location: node.loc&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(t.isCallExpression(node.callee) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isMemberExpression(node.callee.object) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isCallExpression(node.callee.object.callee) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isMemberExpression(node.callee.object.callee.callee) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(node.callee.object.callee.callee.object, { name:&nbsp;'res'&nbsp;}) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(node.callee.object.callee.callee.property, { name:&nbsp;'status'&nbsp;})) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;statusArg = node.callee.object.callee.arguments[0];&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;method = node.callee.property.name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(method ===&nbsp;'json') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;data&nbsp;=&nbsp;this.extractResponseData(node.arguments[0]);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; responses.push({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'error',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; status: statusArg.value,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; method:&nbsp;'json',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;data:&nbsp;data,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; location: node.loc&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 提取参数使用&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isMemberExpression(node.callee) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isMemberExpression(node.callee.object) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(node.callee.object.object)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;objName = node.callee.object.object.name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;propName = node.callee.object.property.name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;methodName = node.callee.property.name;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(objName ===&nbsp;'req') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(propName ===&nbsp;'query') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 查询参数&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;paramName = methodName;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; queryParams.add(paramName);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(propName ===&nbsp;'params') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 路径参数已在别处处理&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(propName ===&nbsp;'body') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 请求体参数&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bodyParams.add(methodName);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MemberExpression: (path) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;node = path.node;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 提取 req.query.param 访问&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isMemberExpression(node.object) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(node.object.object, { name:&nbsp;'req'&nbsp;}) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(node.object.property, { name:&nbsp;'query'&nbsp;}) &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.isIdentifier(node.property)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; queryParams.add(node.property.name);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }, handler.body);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;'function',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; params: handler.params.map(p => ({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name:&nbsp;this.generateCode(p),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;this.inferParamType(p)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; index: index,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; queryParams: Array.from(queryParams),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bodyParams: Array.from(bodyParams),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; responses: responses,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; body:&nbsp;this.generateCode(handler.body)&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; }&nbsp; &nbsp; extractResponseData(dataNode) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(!dataNode)&nbsp;return&nbsp;null;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isObjectExpression(dataNode)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;result = {};&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dataNode.properties.forEach(prop => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isObjectProperty(prop)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;key = prop.key.name || prop.key.value;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result[key] =&nbsp;this.extractResponseValue(prop.value);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;result;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(t.isIdentifier(dataNode)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{ type:&nbsp;'variable', name: dataNode.name };&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(t.isMemberExpression(dataNode)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{ type:&nbsp;'member', expression:&nbsp;this.generateCode(dataNode) };&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(t.isStringLiteral(dataNode)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;dataNode.value;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(t.isNumericLiteral(dataNode)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;dataNode.value;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{ type:&nbsp;'expression', value:&nbsp;this.generateCode(dataNode) };&nbsp; &nbsp; }&nbsp; &nbsp; extractResponseValue(valueNode) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isStringLiteral(valueNode))&nbsp;return&nbsp;valueNode.value;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isNumericLiteral(valueNode))&nbsp;return&nbsp;valueNode.value;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isBooleanLiteral(valueNode))&nbsp;return&nbsp;valueNode.value;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isNullLiteral(valueNode))&nbsp;return&nbsp;null;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isIdentifier(valueNode))&nbsp;return&nbsp;`$${valueNode.name}`;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isMemberExpression(valueNode))&nbsp;return&nbsp;this.generateCode(valueNode);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isCallExpression(valueNode))&nbsp;return&nbsp;`${this.generateCode(valueNode.callee)}(...)`;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;'unknown';&nbsp; &nbsp; }&nbsp; &nbsp; analyzeDynamicRoutes(ast) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 保留方法&nbsp; &nbsp; }&nbsp; &nbsp; resolveDependencies() {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 解析中间件和函数的依赖关系&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.routes.forEach(route => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; route.middleware.forEach(mw => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(mw.type ===&nbsp;'function'&nbsp;&& mw.definition) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 中间件依赖分析&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; }&nbsp; &nbsp; processMiddlewareWithParam(middlewares, paramName, paramValue) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;middlewares.map(mw => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(mw.validations && mw.validations.length >&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;updatedValidations = mw.validations.map(validation => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(validation.type ===&nbsp;'regex'&nbsp;&& paramName) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 正则依赖&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;regexWithValue = validation.pattern.replace(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new RegExp(`\\$\\{${paramName}\\}`,&nbsp;'g'),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; paramValue&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; );&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...validation,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pattern: regexWithValue,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; resolved:&nbsp;true&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;validation;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...mw,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; validations: updatedValidations&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;mw;&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; }&nbsp; &nbsp; evaluateStaticExpression(node, args = []) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isArrayExpression(node)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;node.elements.map(elem =>&nbsp;this.evaluateStaticExpression(elem, args));&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(t.isNumericLiteral(node)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;node.value;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(t.isStringLiteral(node)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;node.value;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(t.isIdentifier(node)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(args && args.length >&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 实际需要更复杂的参数映射&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;`$${node.name}`;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;node.name;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;null;&nbsp; &nbsp; }&nbsp; &nbsp; extractFunctionParams(funcNode) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;funcNode.params.map(param => ({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name:&nbsp;this.generateCode(param),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type:&nbsp;this.inferParamType(param)&nbsp; &nbsp; &nbsp; &nbsp; }));&nbsp; &nbsp; }&nbsp; &nbsp; inferParamType(paramNode) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isIdentifier(paramNode))&nbsp;return&nbsp;'any';&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isObjectPattern(paramNode))&nbsp;return&nbsp;'object';&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isArrayPattern(paramNode))&nbsp;return&nbsp;'array';&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isRestElement(paramNode))&nbsp;return&nbsp;'rest';&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;'unknown';&nbsp; &nbsp; }&nbsp; &nbsp; extractStringValue(node) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(t.isStringLiteral(node))&nbsp;return&nbsp;node.value;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;null;&nbsp; &nbsp; }&nbsp; &nbsp; generateCode(node) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;generator(node, {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; concise:&nbsp;true,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; retainLines:&nbsp;false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sourceMaps:&nbsp;false&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }).code;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;catch&nbsp;(e) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;'/* code generation error */';&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; generateCompleteReport() {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;summary = {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; totalRoutes:&nbsp;this.routes.length,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; uniquePaths: new Set(this.routes.map(r => r.path)).size,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; methods: {},&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; routerTypes: {},&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; validationCount:&nbsp;0,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; middlewareCount:&nbsp;0,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dynamicRoutes:&nbsp;this.routes.filter(r => r.type !==&nbsp;'static').length,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; staticRoutes:&nbsp;this.routes.filter(r => r.type ===&nbsp;'static').length&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.routes.forEach(route => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; summary.methods[route.method] = (summary.methods[route.method] ||&nbsp;0) +&nbsp;1;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; summary.routerTypes[route.router] = (summary.routerTypes[route.router] ||&nbsp;0) +&nbsp;1;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; summary.validationCount += (route.validations?.length ||&nbsp;0);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; summary.middlewareCount += (route.middleware?.length ||&nbsp;0);&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; metadata: {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; analyzedAt: new Date().toISOString(),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; file:&nbsp;this.currentFile,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; imports: Array.from(this.imports.values()),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; functions: Array.from(this.functionDefinitions.keys()),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; routers: Array.from(this.routerDeclarations.keys())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; summary,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; routes:&nbsp;this.routes.map(route => ({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; method: route.method,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; path: route.path,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; originalDefinition: route.originalPath,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; router: route.router,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type: route.type,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; parameters: route.parameters,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; queryParameters: route.queryParameters,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; middleware: route.middleware.map(mw => ({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name: mw.name || mw.type,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type: mw.type,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; validations: mw.validations || []&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; validations: route.validations || [],&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; responses: route.responses || [],&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; handlers: route.handlers.handlers,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; location: route.location,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; file: route.file&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; analysis: {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; routePatterns:&nbsp;this.extractRoutePatterns(),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; validationPatterns:&nbsp;this.extractValidationPatterns(),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; commonMiddlewares:&nbsp;this.findCommonMiddlewares(),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; parameterUsage:&nbsp;this.analyzeParameterUsage()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; }&nbsp; &nbsp; extractRoutePatterns() {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;patterns = new Map();&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.routes.forEach(route => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;pattern = route.path&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .replace(/:\w+/g,&nbsp;':param')&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .replace(/\/\d+/g,&nbsp;'/:id')&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .replace(/\/[^\/]+\/[^\/]+/g,&nbsp;'/:resource/:id');&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; patterns.set(pattern, (patterns.get(pattern) ||&nbsp;0) +&nbsp;1);&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;Array.from(patterns.entries())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .sort((a, b) => b[1] - a[1])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .map(([pattern, count]) => ({ pattern, count }));&nbsp; &nbsp; }&nbsp; &nbsp; extractValidationPatterns() {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;patterns = [];&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.routes.forEach(route => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; route.validations.forEach(validation => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(validation.type ===&nbsp;'regex') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; patterns.push({&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pattern: validation.pattern,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; message: validation.message,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; routes: [route.path],&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; count:&nbsp;1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;patterns;&nbsp; &nbsp; }&nbsp; &nbsp; findCommonMiddlewares() {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;middlewareCount = new Map();&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.routes.forEach(route => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; route.middleware.forEach(mw => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;key = mw.name || mw.type;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; middlewareCount.set(key, (middlewareCount.get(key) ||&nbsp;0) +&nbsp;1);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;Array.from(middlewareCount.entries())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .sort((a, b) => b[1] - a[1])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .map(([name, count]) => ({ name, count, percentage: (count /&nbsp;this.routes.length *&nbsp;100).toFixed(1) +&nbsp;'%'&nbsp;}));&nbsp; &nbsp; }&nbsp; &nbsp; analyzeParameterUsage() {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;paramUsage = new Map();&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;this.routes.forEach(route => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; route.parameters.forEach(param => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;key = `path:${param.name}`;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; paramUsage.set(key, (paramUsage.get(key) ||&nbsp;0) +&nbsp;1);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; route.queryParameters.forEach(param => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;key = `query:${param.name}`;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; paramUsage.set(key, (paramUsage.get(key) ||&nbsp;0) +&nbsp;1);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;Array.from(paramUsage.entries())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .sort((a, b) => b[1] - a[1])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .map(([param, count]) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;[type, name] = param.split(':');&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;{ type, name, count };&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; }}module.exports = AdvancedASTRouteExtractor;if&nbsp;(require.main === module) {&nbsp; &nbsp;&nbsp;const&nbsp;code = `const&nbsp;express = require('express');const&nbsp;router = express.Router();const&nbsp;createRoutes = (versions) => {&nbsp; versions.forEach(ver => {&nbsp; &nbsp; router.get(\`/v\${ver}/:entity\`, validate(ver), (req, res) => {&nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;{ entity } = req.params;&nbsp; &nbsp; &nbsp;&nbsp;const&nbsp;ids = req.query.ids?.split(',').map(Number) || [];&nbsp; &nbsp; &nbsp; res.json({ entity, version: ver, ids });&nbsp; &nbsp; });&nbsp; });};const&nbsp;validate = (version) => (req, res, next) => {&nbsp;&nbsp;const&nbsp;regex = version >=&nbsp;2&nbsp;? /^[A-Z]\\d{3}\$/ : /^\\w{4,8}\$/;&nbsp;&nbsp;if&nbsp;(!regex.test(req.params.entity)) {&nbsp; &nbsp;&nbsp;return&nbsp;res.status(400).send('实体格式错误');&nbsp; }&nbsp; next();};createRoutes([1,&nbsp;2]);router.param('entity', (req, res, next, value) => {&nbsp; req.entity = { raw: value, normalized: value.toLowerCase() };&nbsp; next();});module.exports = router;`;&nbsp; &nbsp;&nbsp;const&nbsp;extractor = new AdvancedASTRouteExtractor();&nbsp; &nbsp;&nbsp;const&nbsp;result = extractor.parseCode(code,&nbsp;'router.js');&nbsp; &nbsp; console.log('=== AST 路由提取结果 ===');&nbsp; &nbsp; console.log(JSON.stringify(result,&nbsp;null,&nbsp;2));}

解析结果如下:

//=== AST 路由提取结果 ==={&nbsp;&nbsp;"metadata": {&nbsp; &nbsp;&nbsp;"analyzedAt":&nbsp;"2026-01-06T07:12:12.859Z",&nbsp; &nbsp;&nbsp;"file":&nbsp;"router.js",&nbsp; &nbsp;&nbsp;"imports": [&nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"type":&nbsp;"require",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"source":&nbsp;"express",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"name":&nbsp;"express"&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; ],&nbsp; &nbsp;&nbsp;"functions": [&nbsp; &nbsp; &nbsp;&nbsp;"createRoutes",&nbsp; &nbsp; &nbsp;&nbsp;"validate"&nbsp; &nbsp; ],&nbsp; &nbsp;&nbsp;"routers": [&nbsp; &nbsp; &nbsp;&nbsp;"router"&nbsp; &nbsp; ]&nbsp; },&nbsp;&nbsp;"summary": {&nbsp; &nbsp;&nbsp;"totalRoutes":&nbsp;1,&nbsp; &nbsp;&nbsp;"uniquePaths":&nbsp;1,&nbsp; &nbsp;&nbsp;"methods": {&nbsp; &nbsp; &nbsp;&nbsp;"GET":&nbsp;1&nbsp; &nbsp; },&nbsp; &nbsp;&nbsp;"routerTypes": {&nbsp; &nbsp; &nbsp;&nbsp;"router":&nbsp;1&nbsp; &nbsp; },&nbsp; &nbsp;&nbsp;"validationCount":&nbsp;0,&nbsp; &nbsp;&nbsp;"middlewareCount":&nbsp;2,&nbsp; &nbsp;&nbsp;"dynamicRoutes":&nbsp;1,&nbsp; &nbsp;&nbsp;"staticRoutes":&nbsp;0&nbsp; },&nbsp;&nbsp;"routes": [&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp;&nbsp;"method":&nbsp;"GET",&nbsp; &nbsp; &nbsp;&nbsp;"path":&nbsp;"/v{ver}/:entity",&nbsp; &nbsp; &nbsp;&nbsp;"originalDefinition":&nbsp;"`/v${ver}/:entity`",&nbsp; &nbsp; &nbsp;&nbsp;"router":&nbsp;"router",&nbsp; &nbsp; &nbsp;&nbsp;"type":&nbsp;"dynamic_template",&nbsp; &nbsp; &nbsp;&nbsp;"parameters": [&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"name":&nbsp;"entity",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"type":&nbsp;"path",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"required":&nbsp;true,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"location":&nbsp;"path",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"pattern":&nbsp;null&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; ],&nbsp; &nbsp; &nbsp;&nbsp;"queryParameters": [],&nbsp; &nbsp; &nbsp;&nbsp;"middleware": [&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"name":&nbsp;"call",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"type":&nbsp;"call",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"validations": []&nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"name":&nbsp;"inline",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"type":&nbsp;"inline",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"validations": []&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; ],&nbsp; &nbsp; &nbsp;&nbsp;"validations": [],&nbsp; &nbsp; &nbsp;&nbsp;"responses": [&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"type":&nbsp;"success",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"method":&nbsp;"json",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"data": {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"entity":&nbsp;"$entity",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"version":&nbsp;"$ver",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"ids":&nbsp;"$ids"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"location": {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"start": {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"line":&nbsp;9,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"column":&nbsp;6,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"index":&nbsp;307&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"end": {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"line":&nbsp;9,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"column":&nbsp;45,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"index":&nbsp;346&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; ],&nbsp; &nbsp; &nbsp;&nbsp;"handlers": [&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"type":&nbsp;"function",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"params": [&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"name":&nbsp;"req",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"type":&nbsp;"any"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"name":&nbsp;"res",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"type":&nbsp;"any"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ],&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"index":&nbsp;1,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"queryParams": [&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"ids"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ],&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"bodyParams": [],&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"responses": [&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"type":&nbsp;"success",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"method":&nbsp;"json",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"data": {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"entity":&nbsp;"$entity",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"version":&nbsp;"$ver",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"ids":&nbsp;"$ids"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"location": {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"start": {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"line":&nbsp;9,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"column":&nbsp;6,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"index":&nbsp;307&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"end": {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"line":&nbsp;9,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"column":&nbsp;45,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"index":&nbsp;346&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ],&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"body":&nbsp;"{ const { entity } = req.params; const ids = req.query.ids?.split(',').map(Number) || []; res.json({ entity, version: ver, ids }); }"&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; ],&nbsp; &nbsp; &nbsp;&nbsp;"location": {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"start": {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"line":&nbsp;6,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"column":&nbsp;4,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"index":&nbsp;139&nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"end": {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"line":&nbsp;10,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"column":&nbsp;6,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"index":&nbsp;354&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp;&nbsp;"file":&nbsp;"router.js"&nbsp; &nbsp; }&nbsp; ],&nbsp;&nbsp;"analysis": {&nbsp; &nbsp;&nbsp;"routePatterns": [&nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"pattern":&nbsp;"/:resource/:id",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"count":&nbsp;1&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; ],&nbsp; &nbsp;&nbsp;"validationPatterns": [],&nbsp; &nbsp;&nbsp;"commonMiddlewares": [&nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"name":&nbsp;"call",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"count":&nbsp;1,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"percentage":&nbsp;"100.0%"&nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"name":&nbsp;"inline",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"count":&nbsp;1,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"percentage":&nbsp;"100.0%"&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; ],&nbsp; &nbsp;&nbsp;"parameterUsage": [&nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"type":&nbsp;"path",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"name":&nbsp;"entity",&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"count":&nbsp;1&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; ]&nbsp; }}

对比可得,基于语义分析的AST可以获取更多的攻击面,这在安全管理与暴露面收敛都是比基于正则的提取要快且全面的,此篇仅作为思路启发,希望大佬们多指点指点。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:鉴帷安全 鉴帷安全《基于AST的资产路由端点提取新方案》

评论:0   参与:  0