dsh-import-graph
v0.1.0
Published
Dependency graph for DeepSeek Harness: build_graph (parse JS/TS import & require edges), find_cycles (circular dependency detection), orphan_files (files neither imported by nor importing others). Heuristic resolution, zero runtime dependencies, read-only
Maintainers
Readme
dsh-import-graph
DeepSeek Harness 的依赖图工具箱:build_graph 解析 JS/TS 源码的 import / require 依赖构建图,find_cycles 检测循环依赖,orphan_files 找出不被任何本地文件引用也不引用别人的孤立源码。只读、零运行时依赖,启发式解析而非完整 AST。
- 源码:https://github.com/geeklei/dsh-plugins/tree/main/dsh-import-graph
- npm:https://www.npmjs.com/package/dsh-import-graph
功能说明
「这个模块删掉会影响谁?」、「A 和 B 是不是循环依赖?」、「仓库里哪些文件其实没人用了?」——单看文件列表回答不了这些问题,要看文件之间的依赖关系。
本插件用启发式扫描给出三档信息,帮你把模块边界和依赖健康状况摸清楚:
- 依赖图(
build_graph):递归扫描目录里的 JS/TS 家族源码,解析import/require/export...from/ 动态import(),构建「文件 → 它依赖的文件」的边,并统计入度 / 出度与孤立文件。 - 循环依赖(
find_cycles):在依赖图上用深度优先找环(A→B→C→A)。循环依赖常导致初始化顺序问题、命名空间污染、难以安全拆分,是代码质量的常见隐患。 - 孤立文件(
orphan_files):找出无入边(不被任何本地文件引用)且无出边(也不引用任何本地文件)的源码。这类文件可能是废弃模块、被动态加载/注册调用的入口,也可能是移出模块边界的遗留。
解析是启发式的:只解析以 ./ ../ 开头的相对引用(npm 包 / 别名 / 内置模块不计为本地边),用「字符串 / 注释剥离 + 正则」近似识别语句,不是完整 AST,个别边界可能不精确,但用于结构判断足够。
安装
npm install dsh-import-graph安装后在 cordis.patch.yml 中加入:
- insert:
- id: import-graph
name: "dsh-import-graph"使用说明
build_graph
解析目录(或单个文件)的依赖关系,输出依赖边与出入度统计。path 传目录或文件;exclude 逗号分隔排除子串;show_edges 控制列出多少条边。
扫描路径:./src(排除 node_modules)
代码文件 6 个;依赖边 7 条;孤立文件 1 个
依赖边(前 5 / 共 7条):
1. src/a.js → src/b.js
2. src/a.js → src/util.js
3. src/b.js → src/c.js
4. src/cycle1.js → src/cycle2.js
5. src/cycle2.js → src/cycle1.js
孤立文件(无入边且无出边,共 1):
- src/e.js
说明:依赖解析为启发式(字符串/注释剥离 + 正则),非完整 AST;npm 包与内置模块不计入本地边。参数:path(必填);exclude;max_files(默认 500);max_size(默认 10240 KB);show_edges(默认 20);max_chars。
用户:这个 src 目录里文件都互相依赖谁,画个清单
助手:调用
build_graph,path=src、exclude=node_modules,输出依赖边与孤立文件
用户:删掉 util.js 会影响哪些文件
助手:调用
build_graph,看 util.js 的入边(谁依赖它)
find_cycles
在依赖图上检测循环依赖,每个环输出一条 A→B→C→A 链路。同一个环即使多次出现在栈中也只输出一次(按规范化键去重)。
扫描路径:./src;代码文件 6 个
发现循环依赖 1 个(前 1):
1. src/cycle1.js → src/cycle2.js → src/cycle1.js
提示:打破循环可先分析环中各边,常从「依赖最轻/最稳定」的节点切断。参数:path(必填);exclude;max_files / max_size;top(默认 5);max_chars。
用户:这个模块有循环依赖吗,是哪几处
助手:调用
find_cycles,path=src,列出所有环
orphan_files
找出既不被任何本地文件引用、也不引用任何本地文件的孤立源码。
扫描路径:./src;代码文件 6 个
孤立文件(无入边且无出边,共 1):
1. src/e.js
说明:仅统计本地相对依赖;若文件经动态加载/插件注册/构建工具引用,可能为误报。参数:path(必填);exclude;max_files / max_size;top(默认 5);max_chars。
用户:仓库里哪些文件其实没人用了
助手:调用
orphan_files,path=src,列出孤立文件
典型场景
- 删除前影响面评估:删 / 移动一个文件前,
build_graph看它的入边(谁依赖它),避免删了炸一片。 - 循环依赖治理:
find_cycles全量找出环,逐条分析切断点,配合重构把 A↔B 拆成单向依赖。 - 废弃代码清理:
orphan_files定位「无入无出」的文件,确认后清理或标记废弃。 - 模块边界梳理:新接手一个库,先
build_graph整体依赖图,理解核心 / 外围模块。 - 重构验证:拆分模块后重跑
build_graph,确认环数量下降、依赖方向变清晰。 - 文档生成辅助:把
build_graph的边列表喂给绘图工具,生成依赖可视化。 - CI 门禁:对核心目录跑
find_cycles,出现环即告警,防止循环依赖回流。
安全边界
- 只读:三个工具都不写入、不修改、不删除文件;只读取源码做文本扫描。
- 不访问网络:依赖解析全部在本地完成,无任何外部请求,也不外发源码。
- 不执行代码:只做文本扫描与字符串 / 注释剥离,不
eval、不运行被测代码。 - 跳过无关内容:默认跳过
node_modules/.git/dist/build/coverage与隐藏目录;二进制与超过max_size的文件不解析;max_files限流。 - 启发式结论,非权威:只解析相对引用,npm 包 / 别名 / 内置模块不计为本地边;字符串 / 注释剥离用正则近似,个别边界可能误识别。结果用于结构判断,不应作为唯一裁决依据。
- 动态加载误报:经
import()变量路径、插件注册、构建工具字符串引用加载的文件可能被漏报为孤立,orphan_files已提示此风险。
其他插件集成说明
| 协作插件 | 集成方式 | |---|---| | dsh-code-metrics | import-graph 看依赖影响面,metrics 看体量 / 复杂度,互补定位重构目标 | | dsh-code-check | 有环或孤立文件时用 code-check 检查相关文件的具体 lint 问题 | | dsh-deps-audit | import-graph 管本地模块依赖,deps-audit 管 lock 文件里的外部依赖,双层治理 | | dsh-template-render | 用模板把依赖边列表渲染成 Markdown / 报告 | | dsh-chart-ascii | 把各模块出入度画成条形图,直观对比依赖热度 | | dsh-test-report | 拆环 / 清孤立后跑测试,确认没有回归 |
版本说明
- 0.1.0(2026-10-08):初始版本。
build_graph:递归扫描目录,解析import/require/export...from/ 动态import(),构建依赖边 + 出入度统计 + 孤立文件;默认跳过常见噪声目录find_cycles:DFS 环检测,按规范化键去重,输出 A→B→C→A 链路orphan_files:找出无入边且无出边的孤立源码- 说明符解析:相对引用补齐扩展名(js/jsx/mjs/cjs/ts/tsx)与目录 index;裸说明符(npm 包 / 别名 / 内置)不计为本地边
- 字符串 / 模板 / 注释先剥离再做关键字识别,避免误匹配
- 只读、二进制拒绝、多层上限
RoadMap
v0.2(计划)
- 增加
influence:给定一个文件,输出它的下游影响面(直接 / 间接依赖它的文件) - 支持解析别名(如
@/~/)与 tsconfig paths,把别名映射到真实相对路径 - 输出可选
format=json,便于脚本消费依赖图
v0.3(展望)
- 增加
subgraph:只导出某模块为根的子图,聚焦局部依赖 - 增加环的「切断建议」:按入度 / 稳定度给每环推荐切边
- 支持更多语言(Python import、Go import)的相对依赖解析
FAQ
Q:为什么 npm 包(如 react)不算依赖边?
只解析以 ./ ../ 开头的相对引用,因为 npm 包 / 别名 / 内置模块解析需要 node_modules 与配置,超出本插件的只读、零依赖边界。所以边表示「本地文件之间的结构关系」。
Q:import './util' 没有扩展名怎么解析?
启发式尝试补齐扩展名:依次试 .js .jsx .mjs .cjs .ts .tsx,若指向目录则试 index.js 等。优先取第一个在扫描文件集合中命中的。
Q:循环依赖检测准吗? DFS 环检测是标准的、准确的(给定正确的边)。边本身来自启发式解析,个别复杂 import 形态可能漏一条边,从而漏掉对应环;识别出的环都是真实存在的。
Q:同一个环为什么不会重复输出? 一个环从不同节点进入栈会出现多次。本插件把环「旋转到最小起点」并规范化成唯一键去重,每个环只输出一次。
Q:孤立文件一定是废弃代码吗?
不一定。可能被 import() 变量路径、插件注册、构建工具的字符串引用动态调用。orphan_files 只报告「无入无出」,是否删除需结合业务判断。
Q:为什么跳过 node_modules?
node_modules 数量大、多为第三方,解析无意义且拖慢。dist / build / coverage 同理。需要分析这些目录时用 exclude 反向指定即可(默认名单可整体绕过,但一般不推荐)。
Q:会执行我的代码吗?
不会。只读文本扫描 + 字符串 / 注释剥离 + 正则识别,不 eval、不加载、不运行任何被测文件。
Q:目录很大会不会卡?
max_files(默认 500)限流扫描数量,max_size(默认 10240 KB)跳过超大文件,二进制文件不解析。
源码与发布地址
- 源码:https://github.com/geeklei/dsh-plugins/tree/main/dsh-import-graph
- npm:https://www.npmjs.com/package/dsh-import-graph
许可证
MIT
