# 模块系统

> 

本文档收敛 Dujie 的模块、导入导出、路径规则和入口相关约束。

## 模块

- 一个源文件就是一个模块
- 模块身份由文件路径决定
- 当前唯一合法源文件扩展名是 `.dj`

第一阶段不引入额外的模块声明语法。

## 导入

`import` 只用于导入其他模块已导出的顶层符号。

当前支持的形态：

```dj
import { foo, bar } from "./utils.dj"
import { foo as my_foo } from "./utils.dj"
```

### 导入源

当前支持两类导入源：

<steps level="4">

#### 本地相对路径

#### 注册表模块

</steps>

#### 本地相对路径

例如：

```dj
import { button } from "../components/button.dj"
```

规则：

- 必须是静态字符串
- 必须显式写扩展名
- 按当前文件所在目录做相对解析

#### 注册表导入

例如：

```dj
import { button } from "registry:ui/button.dj"
```

规则：

- 必须是静态字符串
- 必须显式写扩展名
- 不走本地相对路径解析
- 版本、缓存、锁定等规则交给注册表和构建系统处理

### 当前不支持

- 动态导入
- `import *`
- 默认导入
- 混合默认导入与具名导入
- 根路径别名
- 目录索引魔法
- 自动补全扩展名

## 导出

当前仅支持导出顶层：

- `func`
- `struct`

例如：

```dj
export func add(x: int, y: int) -> int {
    x + y
}

export struct Person {
    name: string,
}
```

当前不支持：

- 导出局部变量
- 导出表达式结果
- `export { foo, bar }`
- `export * from ...`

## 可见性

- 不写 `export` 的顶层符号默认模块私有
- 其他模块只能访问被 `export` 的符号
- 模块内部可直接访问本模块私有顶层符号

## 名称规则

- 导入名称进入当前模块顶层命名空间
- 导入后名称冲突是编译错误
- 可以使用 `as` 改名避开冲突

## 路径解析错误

以下情况属于编译错误：

- 导入路径非法
- 导入路径无法解析
- 同一路径不能唯一解析
- 循环导入

## `main` 与模块入口

`main` 是入口相关的保留名字，但模块是否被当作应用入口，由构建或运行系统决定，不由 `export` 决定。

模块级约束：

- `main` 必须是模块顶层 `func`
- 一个模块内最多只能有一个 `main`
- `main` 不需要 `export`
- `main` 不能与其他顶层符号重名
- `main` 不能是泛型函数
- 普通库模块可以没有 `main`

语言层不再单独限制 `main` 的参数形状：

- 只要参数声明本身符合 Dujie 普通函数规则即可
- 位置参数、具名参数、`opt<T>` 参数、默认值都可以用于 `main`

`main` 的渲染语义和入口适配规则见《渲染内建》。
