Understand-Anything React 附录解析:用提示词工程为 React 项目构建知识图谱
【免费下载链接】Understand-AnythingGraphs that teach > graphs that impress. Turn any code into an interactive knowledge graph you can explore, search, and ask questions about. Works with Claude Code, Codex, Cursor, Copilot, Gemini CLI, and more.项目地址: https://gitcode.com/GitHub_Trending/un/Understand-Anything
Understand-Anything 在将代码仓库转化为可交互知识图谱时,通过"框架附录(Framework Addendum)"机制把特定框架的分析约定注入到分析 Agent 的提示词中。本文以插件自带的 React 附录文件 为核心,完整讲解它的文件角色表、边模式、架构层划分与语言要点,并结合插件源码中的框架检测注册表、注入流程与测试用例,说明这份附录是如何从"一段 Markdown 文本"变成图谱产出中的实际节点、边与层的。
框架附录的定位:注入式提示词片段,而非独立提示词
react.md 的开篇就明确了自身的使用边界:
Injected into file-analyzer and architecture-analyzer prompts when React is detected. Do NOT use as a standalone prompt — always appended to the base prompt template.
也就是说,这份附录只在两个 Agent 的提示词中被发现 React 之后动态追加:
file-analyzer(agents/file-analyzer.md)——逐批次分析源文件,产出图谱节点与边;architecture-analyzer(agents/architecture-analyzer.md)——分析目录结构与导入关系,识别架构层并把每个文件节点分配到恰好一个层。
注入流程定义在 SKILL.md 的 Phase 4 中,原文规则为:对 Phase 1 检测到的每个框架,读取./frameworks/<framework-id-lowercase>.md(对 React 即 frameworks/react.md),把其完整内容追加在语言上下文之后;若对应文件不存在则静默跳过。这与 agents/architecture-analyzer.md 中"结合目录树、语言上下文和框架附录来推断层边界(目录结构是层边界的强证据)"的要求相互衔接。
附录之所以能被"按 id 找到文件",靠的是框架配置中的promptSnippetPath字段。React 的配置文件 react.ts 声明了完整的元数据:
export const reactConfig = { id: "react", displayName: "React", languages: ["typescript", "javascript"], detectionKeywords: ["react", "react-dom", "@types/react"], manifestFiles: ["package.json"], promptSnippetPath: "./frameworks/react.md", entryPoints: ["src/App.tsx", "src/App.jsx", "src/index.tsx", "src/main.tsx"], layerHints: { components: "ui", hooks: "service", pages: "ui", contexts: "service", utils: "utility", lib: "service", }, } satisfies FrameworkConfig;各字段的含义可从 types.ts 中的FrameworkConfigSchema(Zod 定义)得到印证:detectionKeywords与manifestFiles用于框架检测,promptSnippetPath必填且非空,entryPoints与layerHints为可选的目录到层的映射提示。
React 是如何被检测出来的
检测逻辑实现在 framework-registry.ts 的detectFrameworks方法中,核心算法分三步:
- 遍历已注册的框架配置,取每个框架声明的
manifestFiles(React 为package.json); - 在传入的 manifest 内容映射中做文件名(basename)匹配,找到
package.json的内容后整体转小写; - 检查
detectionKeywords(react、react-dom、@types/react)是否以小写形式出现在内容中,任一命中即判定检测到 React,且同一框架去重后只出现一次。
framework-registry.test.ts 用真实 JSON 验证了这条链路:
const detected = registry.detectFrameworks({ "package.json": '{"dependencies": {"react": "^18.2.0", "react-dom": "^18.2.0"}}', }); expect(detected).toHaveLength(1); expect(detected[0].id).toBe("react");同文件还覆盖了大小写不敏感、无匹配时返回空数组、重复 manifest 不产生重复结果等边界;config-schema.test.ts 则通过countConfigModules("../languages/frameworks/")校验所有内置框架模块(当前为 10 个)都注册齐全,且每个框架都有非空的promptSnippetPath——这保证了"检测到 React 就能找到 react.md"这一前提在结构上成立。
此外,扫描阶段的 project-scanner.md 也会从package.json的dependencies/devDependencies中提取框架叙事(其已知框架清单中明确包含react),输出frameworks字段(如["React", "Vite", ...])供后续 Phase 使用。两条检测路径(叙事识别 + 注册表关键字匹配)共同为附录注入提供了输入。
Canonical File Roles:文件角色与标签表
附录的第一张表规定了 React 项目中"哪些目录扮演什么角色、应该打什么标签",必须与基础分析规则叠加使用。完整表格如下(继承自原文档):
| 文件 / 模式 | 角色 | 标签 |
|---|---|---|
src/App.tsx | 根应用组件 —— 挂载 providers、路由与顶层布局 | entry-point,ui |
components/*.tsx,components/**/*.tsx | 可复用 UI 组件 | ui |
hooks/*.ts,hooks/*.tsx | 自定义 React Hooks —— 封装可复用的有状态逻辑 | service,utility |
contexts/*.tsx,context/*.tsx | React Context 提供者与消费者 —— 组件树间共享状态 | service,state |
pages/*.tsx,views/*.tsx | 映射到路由的页面级组件 | ui,routing |
utils/*.ts,helpers/*.ts | 纯工具函数 —— 格式化、校验、转换 | utility |
types/*.ts,types/*.d.ts | TypeScript 类型定义与接口 | type-definition |
services/*.ts,api/*.ts | API 客户端函数与数据获取逻辑 | service |
store/*.ts,slices/*.ts | 状态管理(Redux、Zustand 等) | service,state |
constants/*.ts | 应用级常量与枚举 | config |
__tests__/*.tsx,*.test.tsx,*.spec.tsx | 单元与集成测试 | test |
这些标签不是孤立的文字标注:file-analyzer在产出节点时要求每个节点携带 3–5 个小写连字符标签(见 file-analyzer.md 的 Step 1 "Tags" 一节),附录中的角色表正是 React 场景下标签取值的具体依据,例如hooks/目录下的文件会同时带上service与utility,store/与slices/(Redux slice)会带state标记,从而让图谱中的状态管理模块可被单独筛选检索。
Edge Patterns:四类 React 特有边模式
附录的第二部分定义了 React 项目中应当额外寻找的四类边。结合file-analyzer基础模板中的边类型与权重表(contains权重 1.0、depends_on权重 0.6、方向恒为forward,见 file-analyzer.md "Step 3 -- Create Edges" 一节),逐条对应如下:
1. 组件组合(Component composition)—— 当父组件在 JSX return 中渲染子组件时,从父组件到子组件创建contains边。这些边构成组件树的层级结构。
2. Hook 使用(Hook usage)—— 当组件或 hook 导入并调用自定义 hook(useX)时,从使用方到 hook 模块创建depends_on边。附录特别指出:Hooks 是 React 中共享逻辑的主要机制。
3. Context 提供者/消费者(Context provider/consumer)—— 当 Context provider 包裹组件时,从 provider 到 context 定义创建publishes边;当组件调用useContext或使用自定义 context hook 时,从消费方到 context 创建subscribes边。
4. Props 透传链(Props drilling chains)—— 当 props 穿过多个组件层却未被使用时,沿链条创建depends_on边,把耦合深度显式暴露出来。
值得注意的是,基础 Agent 模板并非完全没有 React 规则:file-analyzer.md 末尾的 "Edge Signal Quick Reference" 表中已经内置了四条 React 相关信号(组件渲染子组件 →contains;调用useX→depends_on;Context provider 包裹组件;调用useContext)。从文档结构看,该速查表对 Context 场景采用的是较通用的exports/depends_on映射,而 React 附录则将其细化为语义更精确的publishes/subscribes对——两者叠加使用,使 Context 的"发布-订阅"关系在图谱中可被单独识别,而不是淹没在普通的导出/依赖边中。
边的目标端点遵循模板中严格的节点 ID 约定,例如file:src/components/Card.tsx、function:src/hooks/useAuth.ts:useAuth(格式定义见 file-analyzer.md "Node Types and ID Conventions" 一节)。附录约束的"从父到子、从使用方到被依赖方"的方向,与模板中"所有边direction恒为forward"的规则一致,保证合并脚本可以确定性地去重与归一。
Architectural Layers:React 的六个架构层
附录给出了一份六层的划分表,供architecture-analyzer在检测到 React 项目时套用:
| 层 ID | 层名 | 归属内容 |
|---|---|---|
layer:ui | UI 层 | components/、pages/、views/、布局组件 |
layer:service | 服务层 | hooks/、contexts/、services/、api/、store/ |
layer:types | 类型层 | types/、共享 TypeScript 接口与类型定义 |
layer:utility | 工具层 | utils/、helpers/、纯函数 |
layer:config | 配置层 | App.tsx、路由配置、provider 装配、常量 |
layer:test | 测试层 | __tests__/、*.test.tsx、*.spec.tsx |
这份表与 react.ts 中的layerHints高度一致:components → ui、pages → ui、hooks → service、contexts → service、utils → utility,另加了lib → service的目录提示。layerHints是确定性、目录粒度的快速映射,而附录中的层表则允许architecture-analyzer对"目录名不典型但语义明确"的文件(比如根目录的App.tsx归入layer:config、路由配置文件等)做语义级裁决。
architecture-analyzer.md 的任务定义约束了最终产出形态:识别 3–10 个逻辑架构层,并且每个文件节点必须恰好属于一个层。其工作方式是两阶段的——先写脚本从导入图与文件路径中计算目录分组、节点类型分布、扇入/扇出等结构化模式,再做语义层分配。附录注入后,"目录结构 + 层提示"就成为层边界判定的强证据;SKILL.md 中归一化阶段还会对层结果做补 ID(layer:<kebab-case-name>)、字段改名、悬空节点引用清理等后处理,保证layer:ui这类 ID 与图谱节点集严格对齐。
languageLesson:应在图谱中留痕的五个 React 模式
附录最后一节要求分析器把以下"值得记录的语言级模式"写入languageLesson输出:
- 组合优于继承(Component composition over inheritance):React 倾向于通过 props 和 children 组合组件,而非类继承层级;
- 自定义 hooks 复用逻辑:以
use为前缀的 hook 把有状态逻辑提取为可共享模块,且不改变组件树; - React.memo 性能标记:被
React.memo包裹的组件在 props 不变时跳过重渲染——在图谱中它指示这是一条性能敏感路径; - 受控 vs 非受控组件:受控组件的状态来源于 props;非受控组件通过 refs 管理内部状态;
- Render props 模式:组件接受一个函数作为 children 或 render prop,把渲染决策权委托给使用方。
这些条目是"教育性"的:它们不改变节点与边的产出,而是让生成的知识图谱附带可学习的框架知识,支撑 Understand-Anything "graphs that teach > graphs that impress" 的定位。core 包中存在对应的 language-lesson.ts 生成模块与其测试 language-lesson.test.ts,负责在图谱装配阶段产出这类学习内容;具体生成策略可从该测试文件中进一步查证。
小结:一份 Markdown 如何参与整条流水线
把仓库证据串起来,React 附录的完整生命周期是:project-scanner从 manifest 叙事中识别出 React →FrameworkRegistry.detectFrameworks用package.json关键字匹配确认 → SKILL.md Phase 4 按promptSnippetPath约定读取 frameworks/react.md 全文追加到file-analyzer/architecture-analyzer提示词 → 分析器据此产出带ui/service/state等标签的节点、contains/depends_on/publishes/subscribes边、六个layer:*划分以及languageLesson条目 → 合并与归一化脚本落盘为最终图谱。
对使用者而言,这意味着:如果你在自己的 React 项目中运行 Understand-Anything,目录命名是否贴合附录中的"Canonical File Roles"(components/、hooks/、contexts/、store/等)会直接决定图谱节点标签与层划分的质量;对插件开发者而言,frameworks/ 目录下的django.md、vue.md、spring.md等 10 个附录遵循同一模板,配合 react.ts 式的配置注册,即可按同样机制扩展新的框架支持。
【免费下载链接】Understand-AnythingGraphs that teach > graphs that impress. Turn any code into an interactive knowledge graph you can explore, search, and ask questions about. Works with Claude Code, Codex, Cursor, Copilot, Gemini CLI, and more.项目地址: https://gitcode.com/GitHub_Trending/un/Understand-Anything
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考