⚡

模块系统设计Skill module-systems

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

架构设计 0 次安装 7 次浏览 更新于 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