模块系统设计 module-systems

模块系统设计专家技能,专注于编程语言的模块化架构实现。提供完整的模块系统解决方案,包括模块解析算法、依赖管理、可见性控制、命名空间管理和循环依赖处理。支持ES6、CommonJS、Rust、ML等多种模块风格,实现高效的模块加载和依赖解析。适用于编译器开发、语言设计、构建工具开发等场景。

架构设计 0 次安装 0 次浏览 更新于 2/25/2026

名称: 模块系统 描述: 设计模块系统的专家技能,包括解析算法、导入/导出机制、可见性控制、命名空间管理和循环依赖处理。 允许工具: 读取、写入、编辑、Bash、Glob、Grep

模块系统技能

为编程语言设计和实现模块系统,支持解析、加载、可见性和依赖管理。

能力

  • 设计模块/导入/导出语法
  • 实现模块解析算法
  • 处理循环模块依赖
  • 实现可见性/访问控制
  • 设计命名空间管理系统
  • 支持模块别名和重新导出
  • 实现惰性/按需模块加载
  • 设计包/箱系统集成

使用场景

在以下情况下调用此技能:

  • 为新语言设计模块系统
  • 实现模块解析算法
  • 处理复杂依赖图
  • 构建可见性和访问控制系统
  • 与包管理器集成

输入参数

参数 类型 必填 描述
模块风格 字符串 风格 (es6, commonjs, rust, ml)
解析策略 字符串 解析方式 (node, rust, python, custom)
功能特性 数组 要实施的功能
循环处理 字符串 如何处理循环 (error, lazy, tarjan)
可见性 对象 可见性模型配置

功能选项

{
  "功能特性": [
    "导入-导出",
    "重新导出",
    "命名空间别名",
    "选择性导入",
    "默认导出",
    "惰性加载",
    "循环检测",
    "可见性控制",
    "内联模块",
    "包集成"
  ]
}

输出结构

模块系统/
├── 语法/
│   ├── 导入.语法              # 导入语句语法
│   ├── 导出.语法              # 导出语句语法
│   └── 模块声明.语法         # 模块声明语法
├── 解析/
│   ├── 解析器.ts                 # 主解析算法
│   ├── 模块图.ts             # 依赖图
│   ├── 路径解析器.ts            # 路径解析
│   └── 缓存.ts                    # 模块缓存
├── 加载/
│   ├── 加载器.ts                   # 模块加载器
│   ├── 惰性加载器.ts              # 惰性加载支持
│   └── 并行加载器.ts          # 并行加载
├── 可见性/
│   ├── 访问控制.ts           # 可见性检查
│   └── 命名空间.ts                # 命名空间管理
├── 分析/
│   ├── 循环检测器.ts           # 循环依赖检测
│   └── 依赖分析器.ts      # 依赖分析
└── 测试/
    ├── 解析测试.ts
    ├── 循环测试.ts
    └── 可见性测试.ts

模块系统类型

ES6风格模块

// 导入语法
import 默认导出 from '模块';
import { 命名导出, 另一个 as 别名 } from '模块';
import * as 命名空间 from '模块';

// 导出语法
export const 值 = 42;
export function 函数() {}
export default class 我的类 {}
export { 名称, 其他 as 重命名 };
export * from '其他模块';

// 实现
interface ES模块 {
  默认导出?: any;
  命名导出: Map<string, any>;
  重新导出: 重新导出[];
}

interface 导入标识符 {
  类型: 'default' | 'named' | 'namespace';
  导入的: string;
  本地的: string;
}

Rust风格模块

// 模块声明
mod 我的模块;           // 从文件加载
mod 内联 { ... }       // 内联模块

// Use语句
use crate::模块::项目;
use super::父级::*;
use self::子级::事物;
use 外部箱::某物;

// 可见性
pub struct 公开;
pub(crate) struct 箱内可见;
pub(super) struct 父级可见;
struct 私有;  // 默认

// 实现
interface Rust模块 {
  名称: string;
  路径: 模块路径;
  可见性: 可见性;
  项目: Map<string, 模块项目>;
  子模块: Map<string, Rust模块>;
}

类型 可见性 =
  | { 类型: 'private' }
  | { 类型: 'public' }
  | { 类型: 'restricted'; 路径: 模块路径 };

ML风格模块

(* 模块签名 *)
module type 栈 = sig
  type 'a t
  val 空 : 'a t
  val 推入 : 'a -> 'a t -> 'a t
  val 弹出 : 'a t -> ('a * 'a t) option
end

(* 模块实现 *)
module 列表栈 : 栈 = struct
  type 'a t = 'a list
  let 空 = []
  let 推入 x s = x :: s
  let 弹出 = function
    | [] -> None
    | x :: xs -> Some (x, xs)
end

(* 函子 *)
module 制作集合 (排序: 排序) : 集合 = struct
  (* ... 使用排序.比较的实现 *)
end

解析算法

Node.js风格解析

interface Node解析器 {
  解析模块(标识符: string, 来源: string): string | null;
}

function node解析(标识符: string, 来源目录: string): string | null {
  // 1. 如果是核心模块,直接返回
  if (是核心模块(标识符)) return 标识符;

  // 2. 如果以'/'或'./'开头,解析相对路径
  if (标识符.startsWith('/') || 标识符.startsWith('./') ||
      标识符.startsWith('../')) {
    return 解析相对路径(标识符, 来源目录);
  }

  // 3. 否则,向上遍历node_modules
  let 目录 = 来源目录;
  while (目录 !== '/') {
    const 候选 = path.join(目录, 'node_modules', 标识符);
    const 解析结果 = 解析包(候选);
    if (解析结果) return 解析结果;
    目录 = path.dirname(目录);
  }

  return null;
}

function 解析包(包路径: string): string | null {
  // 检查package.json的exports/main
  const 包配置 = 读取包配置(包路径);
  if (包配置?.exports) {
    return 解析导出(包路径, 包配置.exports);
  }
  if (包配置?.main) {
    return path.join(包路径, 包配置.main);
  }
  // 默认使用index.js
  return path.join(包路径, 'index.js');
}

Rust风格解析

interface Rust解析器 {
  解析Use(use路径: Use路径, 当前模块: 模块路径): 解析项目;
}

function rust解析(use路径: Use路径, 当前: 模块路径): 解析项目 {
  const [第一个, ...其余] = use路径.段;

  // 确定起始点
  let 起始模块: Rust模块;
  if (第一个 === 'crate') {
    起始模块 = 获取箱根();
  } else if (第一个 === 'super') {
    起始模块 = 获取父模块(当前);
  } else if (第一个 === 'self') {
    起始模块 = 获取当前模块(当前);
  } else if (是外部箱(第一个)) {
    起始模块 = 获取外部箱(第一个);
  } else {
    // 从当前模块作用域开始
    起始模块 = 获取当前模块(当前);
    其余.unshift(第一个);
  }

  // 解析路径段
  let 当前项目: 模块项目 = 起始模块;
  for (const 段 of 其余) {
    当前项目 = 解析段(当前项目, 段);
    检查可见性(当前项目, 当前);
  }

  return 当前项目;
}

循环依赖处理

// Tarjan算法用于SCC检测
function 查找循环(图: 模块图): 模块循环[] {
  const 索引 = new Map<模块, number>();
  const 低链接 = new Map<模块, number>();
  const 在栈上 = new Set<模块>();
  const 栈: 模块[] = [];
  const 强连通分量: 模块[][] = [];
  let 当前索引 = 0;

  function 强连接(模块: 模块): void {
    索引.set(模块, 当前索引);
    低链接.set(模块, 当前索引);
    当前索引++;
    栈.push(模块);
    在栈上.add(模块);

    for (const 依赖 of 模块.依赖项) {
      if (!索引.has(依赖)) {
        强连接(依赖);
        低链接.set(模块, Math.min(低链接.get(模块)!, 低链接.get(依赖)!));
      } else if (在栈上.has(依赖)) {
        低链接.set(模块, Math.min(低链接.get(模块)!, 索引.get(依赖)!));
      }
    }

    if (低链接.get(模块) === 索引.get(模块)) {
      const 强连通分量: 模块[] = [];
      let w: 模块;
      do {
        w = 栈.pop()!;
        在栈上.delete(w);
        强连通分量.push(w);
      } while (w !== 模块);
      if (强连通分量.length > 1) {
        强连通分量.push(强连通分量);
      }
    }
  }

  for (const 模块 of 图.模块) {
    if (!索引.has(模块)) {
      强连接(模块);
    }
  }

  return 强连通分量.map(模块 => ({ 模块, 边: 查找循环边(模块) }));
}

可见性控制

interface 可见性检查器 {
  可访问(项目: 模块项目, 来自模块: 模块路径): boolean;
}

function 检查可见性(
  项目: 模块项目,
  来自模块: 模块路径,
  项目模块: 模块路径
): boolean {
  switch (项目.可见性.类型) {
    case 'public':
      return true;

    case 'private':
      return 是相同模块(来自模块, 项目模块);

    case 'crate':
      return 是相同箱(来自模块, 项目模块);

    case 'super':
      return 是父级或相同(获取父级(项目模块), 来自模块);

    case 'restricted':
      return 是后代(来自模块, 项目.可见性.路径);

    default:
      return false;
  }
}

惰性加载

interface 惰性模块 {
  路径: string;
  已加载: boolean;
  导出: Map<string, any> | null;
  加载中: Promise<void> | null;
}

class 惰性模块加载器 {
  private 模块 = new Map<string, 惰性模块>();

  async 导入(标识符: string): Promise<any> {
    const 解析结果 = this.解析(标识符);
    let 模块 = this.模块.get(解析结果);

    if (!模块) {
      模块 = {
        路径: 解析结果,
        已加载: false,
        导出: null,
        加载中: null
      };
      this.模块.set(解析结果, 模块);
    }

    if (模块.已加载) {
      return 模块.导出;
    }

    if (模块.加载中) {
      await 模块.加载中;
      return 模块.导出;
    }

    模块.加载中 = this.加载模块(模块);
    await 模块.加载中;
    return 模块.导出;
  }

  private async 加载模块(模块: 惰性模块): Promise<void> {
    const 源代码 = await 读取文件(模块.路径);
    const 编译结果 = 编译(源代码);
    模块.导出 = await 执行(编译结果);
    模块.已加载 = true;
  }
}

工作流程

  1. 设计模块语法 - 导入、导出、模块声明
  2. 实现解析 - 路径解析算法
  3. 构建依赖图 - 跟踪模块依赖
  4. 检测循环 - 查找并报告循环依赖
  5. 实现可见性 - 访问控制检查
  6. 添加惰性加载 - 按需模块加载
  7. 集成包管理 - 包管理器支持
  8. 生成测试 - 解析、循环、可见性

最佳实践

  • 解析与加载的清晰分离
  • 已解析模块的高效缓存
  • 信息丰富的循环检测错误消息
  • 一致的可见性语义
  • 支持同步和异步加载
  • IDE支持的增量解析

参考资料

目标流程

  • 模块系统设计.js
  • 语义分析.js
  • 解释器实现.js
  • LSP服务器实现.js