# DatAlive 设计器静态依赖分析方案 (Static Dependency Analysis) ## 1. 方案背景 在低代码平台(如 DatAlive)的架构设计中,实体间(如组件、交互、查询等)的动态变量关联是一个核心能力。为了提供超越简单模板语法(如 `{{variables.token}}`)的极致灵活性,本设计器在底层架构上全面拥抱了 **“基于纯函数的动态求值逃生舱”(Dynamic Expression / Code Escape Hatch)**。 通过允许用户编写原生的 JavaScript/TypeScript 函数片段(即 Schema 中的 `DynamicExpression` 接口,如 `RestRequestByCode`、`ActionParamsByCode` 以及 `props` 的动态求值),平台能够支撑极其复杂的循环、数据转换与条件判断。 然而,这种黑盒化的代码片段如果缺乏平台级的管控,将导致设计器丧失“无用变量剔除”、“变量重命名级联更新”、“依赖关系拓扑图谱”等企业级的高级可视化工程能力。 因此,平台必须在**设计器外壳(Editor Shell)**的底层引入**静态依赖分析(Static Dependency Analysis)**机制,将用户编写的代码从“黑盒字符串”转化为平台可理解的“语法树模型”。 --- ## 2. 数据结构设计基石(二元联合类型) 为了保持 Schema 的极致纯净并支撑未来的 AST 解析,所有支持动态求值的字段(如 `Action` 的 `params`、`Query` 的 `request` 等)均采用了 `fixed`(纯静态)与 `code`(动态求值)的二元联合类型设计: ```typescript // 统一的参数联合类型示例 (ActionParams) export type ActionParams = ActionParamsByFixed | ActionParamsByCode; export interface ActionParamsByFixed { type: 'fixed'; /** * 纯静态配置字典。 * 专用于设计器右侧属性面板上的简单固定值输入表单。 */ payload: Record; } export interface ActionParamsByCode extends DynamicExpression { // 继承自 DynamicExpression // type: 'code'; // code: string; (纯函数体字符串) } ``` **分析边界**:设计器的依赖分析引擎**仅需要**拦截并解析那些 `type === 'code'` 的节点,而对于 `fixed` 节点,由于其结构是强类型的字典,引擎可以直接通过对象遍历提取依赖(如遇到特定的标识符),大幅降低了全局解析的性能开销。 --- ## 3. 静态依赖分析的核心实现路径 (Toolchain Pipeline) 在获取到 Schema 中的 `code` 字符串后,设计器工具链需按以下管线执行依赖分析: ### 3.1 引入轻量级 AST 解析器 在设计器编译层引入标准的 AST 解析器(如 `@babel/parser` 或 `acorn`)。当用户在代码编辑器(如 Monaco Editor)中完成 `code` 编写并失去焦点或保存时,立即触发异步解析。 ### 3.2 标识符与上下文提取 (Identifier Extraction) 遍历生成的抽象语法树(AST),重点拦截对上下文对象(`context`)的成员访问表达式(`MemberExpression`)。 - **静态属性访问**:例如 `context.variables.currentUser`,AST 会明确暴露出 `variables` 和 `currentUser` 节点。 - **解构赋值分析**:例如 `const { variables } = context; return variables.token;`,通过作用域(Scope)和绑定(Binding)分析追踪其真实来源。 ### 3.3 构建全局依赖图谱 (Dependency Graph) 将提取出的依赖特征(如“依赖了变量 `token`”、“依赖了查询 `getUser`”)提炼为元数据(Metadata)。这部分元数据: - **缓存在设计器的内存 Store 中**:用于在左侧“变量管理面板”中实时显示该变量被多少个组件引用,或在用户尝试删除某变量时弹出“该变量正被 3 个组件使用,确认删除?”的拦截警告。 - **持久化隔离**:这部分图谱数据**绝生存**于纯净的 Schema 数据库中,它仅作为设计态的辅助元数据。 ### 3.4 变量重构与级联更新 (Refactoring & Cascading) 当用户在全局变量面板中修改变量的 `key`(例如将 `token` 修改为 `accessToken`)时: 1. **精准定位**:通过依赖图谱瞬间定位到所有使用了该变量的 `DynamicExpression` 节点。 2. **智能重写**:利用 AST 转换工具(如 `@babel/traverse` 或 `jscodeshift`),将对应的 `MemberExpression` 节点属性名静默修改为新名称。 3. **重新生成代码**:通过 `@babel/generator` 将修改后的 AST 重新序列化为代码字符串,更新回 Schema Store 触发保存。 --- ## 4. 工程权衡与边界处理 (Trade-offs & Edge Cases) ### 4.1 性能考量 在浏览器中高频运行 AST 解析器会带来极大的性能开销。 - **策略**:AST 解析引擎应被放置在 **Web Worker** 中异步执行,绝对避免阻塞设计器的主线程(UI 线程);同时配合防抖(Debounce)机制,仅在用户结束连续输入后触发全量分析。 ### 4.2 动态键名的分析盲区 (Analysis Blind Spots) 对于高度动态的代码,静态分析存在天然的盲区: - **场景**:例如 `const key = 'user' + 'Id'; return context.variables[key];`。 - **策略**:平台不承诺对计算属性(Computed Properties)和极度动态拼接的键名提供精准追踪。当 AST 遇到动态 `MemberExpression` 且无法推断其字面量时,设计器界面可以抛出警告级别的提示(Warning),告知实施人员:**“该动态依赖无法被设计器的重命名或剔除引擎接管,若修改上游变量名,需您自行维护此处的代码一致性。”** --- ## 5. 总结 本方案确立了 DatAlive **“基于纯函数的动态求值逃生舱”** 结合 **“底层 AST 静态分析工具链”** 的工程路线。 它在赋予高级实施人员图灵完备的极客灵活性的同时,通过外围的解析引擎完美补齐了低代码平台在复杂逻辑下的重构与依赖管理能力。这是实现企业级低代码平台(Pro-Code 与 Low-Code 深度融合)不可或缺的架构护城河。