# Identifier

## Description

Identifier 模块用于提供围绕逻辑标识（logical identifier）进行生成、判断、断言、比较与序列化的基础能力，并统一收纳与通用唯一标识符（UUID, Universally Unique Identifier）相关的格式校验与生成语义。

它关注的是“系统如何稳定表达身份与标识”，而不是某个业务系统的编号规则、数据库主键策略或外部协议字段约定。

## For Understanding

理解 Identifier 模块时，应先把逻辑身份与标识格式区分开。这里同时承载两类彼此相关、但层次不同的能力：

- `Id` 用于表达库内部的逻辑身份，是一种不透明的运行时标识值。
- `UUID` 用于表达广泛使用的通用标识字符串格式，适合在系统边界做校验、断言、版本读取和字符串生成。

把这两类能力放在同一个模块中，核心原因不是它们实现方式相同，而是它们都服务于“谁是谁、一个标识是否合法、一个标识如何被稳定生成和传递”这一共同问题域。相对地，随机字符串本身更偏向随机输入生成，不再属于这个边界。

这个模块不适合承载数据库自增键、雪花算法、业务编码规则、分布式全局编号体系或任何需要额外持久化与跨系统一致性承诺的标识模型。若未来出现这类需求，应按更明确的问题域继续建模，而不是直接膨胀当前模块。

## For Using

当你需要在系统中稳定表达身份语义，或在边界层处理 UUID 一类的通用标识字符串时，可以使用这个模块。它适合放在跨模块协作、基础设施边界、日志关联、资源索引和接口参数校验等场景中。

当前公共能力大致可以按以下几类理解：

- 逻辑身份生成：用于创建新的 `Id`，或基于同一种子复用同一个运行时标识实例。
- 逻辑身份判断与比较：用于判断一个值是否为 `Id`，以及区分“同一个实例”和“同一个内部标识值”。
- 逻辑身份序列化：用于把 `Id` 转换为适合日志、调试和展示的字符串形式。
- UUID 校验与断言：用于在外部输入进入系统前确认其格式是否合法。
- UUID 生成：用于生成 UUID v4 与 UUID v7 字符串，以满足常规唯一性和近似时间有序标识场景。

更合理的接入方式，是在边界层尽早决定你需要的是“内部逻辑身份”还是“外部通用标识字符串”。两者虽然都属于 Identifier，但不应相互混用。

## For Contributing

贡献 Identifier 模块时，应优先判断新增能力是否真的在澄清标识语义，而不是借“编号”或“随机”名义引入其它问题域。这里应长期承载的是逻辑身份模型与通用标识格式模型，而不是各种临时编码技巧的集合。

在扩展时，应优先遵守以下边界：

- `Id` 应继续保持为不透明的逻辑身份值，不要让调用方依赖其内部结构。
- UUID 相关能力应围绕格式判断、断言、版本提取和生成展开，不要混入业务编号规则。
- 如果某个能力的重点已经变成“随机文本如何生成”，应优先考虑 Random 模块，而不是继续放入 Identifier。
- 如果某个能力需要更强的持久化、安全性或跨系统一致性承诺，应在更具体的问题域中单独建模。

### JSDoc 注释格式要求

- 每个公开导出的目标（类型、函数、变量、类等）都应包含 JSDoc 注释，让人在不跳转实现的情况下就能理解用途。
- JSDoc 注释第一行应为清晰且简洁的描述，该描述优先使用中文（英文也可以）。
- 如果描述后还有其他内容，应在描述后加一个空行。
- 如果有示例，应使用 `@example` 标签，后接三重反引号代码块（不带语言标识）。
- 如果有示例，应包含多个场景，展示不同用法，尤其要覆盖常见组合方式或边界输入。
- 如果有示例，应使用注释格式说明每个场景：`// Expect: <result>`。
- 如果有示例，应将结果赋值给 `example1`、`example2` 之类的变量，以保持示例易读。
- 如果有示例，`// Expect: <result>` 应该位于 `example1`、`example2` 之前，以保持示例的逻辑清晰。
- 如果有示例，应优先使用确定性示例；避免断言精确的随机输出。
- 如果函数返回结构化字符串，应展示其预期格式特征。
- 如果有参考资料，应将 `@see` 放在 `@example` 代码块之后，并用一个空行分隔。

### 实现规范要求

- 不同程序元素之间使用一个空行分隔，保持结构清楚。这里的程序元素，通常指函数、类型、常量，以及直接服务于它们的辅助元素。
- 某程序元素独占的辅助元素与该程序元素本身视为一个整体，不要在它们之间添加空行。
- 程序元素的辅助元素应该放置在该程序元素的上方，以保持阅读时的逻辑顺序。
- 若辅助元素被多个程序元素共享，则应将其视为独立的程序元素，放在这些程序元素中第一个相关目标的上方，并与后续程序元素之间保留一个空行。
- 辅助元素也应该像其它程序元素一样，保持清晰的命名和适当的注释，以便在需要阅读实现细节时能够快速理解它们的作用和使用方式。
- 辅助元素的命名必须以前缀 `internal` 开头（或 `Internal`，大小写不敏感）。
- 辅助元素永远不要公开导出。
- 被模块内多个不同文件中的程序元素共享的辅助元素，应该放在一个单独的文件中，例如 `./src/identifier/internal.ts`；若当前没有必要，不必为了形式强行拆分。
- 模块内可以包含子模块。只有当某个子目录表达一个稳定、可单独理解、且可能被父模块重导出的子问题域时，才应将其视为子模块。
- 子模块包含多个文件时，应该为其单独创建子文件夹，并为其创建单独的 Barrel 文件；父模块的 Barrel 文件再重导出子模块的 Barrel 文件。
- 子模块不需要有自己的 `README.md`。
- 子模块可以有自己的 `internal.ts` 文件，多个子模块共享的辅助元素应该放在父模块的 `internal.ts` 文件中，单个子模块共享的辅助元素应该放在该子模块的 `internal.ts` 文件中。
- 对模块依赖关系的要求（通常是不循环依赖或不反向依赖）与对 DRY 的要求可能产生冲突。此时，若复用的代码数量不大，可以适当牺牲 DRY，复制粘贴并保留必要的注释说明；若复用的代码数量较大，则可以将其抽象到新的文件或子模块中，如 `common.ts`，并在需要的地方导入使用。
- 实现应继续保证逻辑身份语义与标识字符串语义都通过稳定公共入口暴露，而不是通过内部形状或偶然路径被外部依赖。

### 导出策略要求

- 保持内部辅助项和内部符号为私有，不要让外部接入依赖临时性的内部结构。
- 每个模块都应有一个用于重导出所有公共 API 的 Barrel 文件。
- Barrel 文件应命名为 `index.ts`，放在模块目录根部，并且所有公共 API 都应从该文件导出。
- 新增公共能力时，应优先检查它是否表达稳定、清楚且值得长期维护的标识语义，而不是某段实现细节的便捷暴露；仅在确认需要长期对外承诺时再加入 Barrel 导出。

### 测试要求

- 若程序元素是函数，则只为该函数编写一个测试，如果该函数需要测试多个用例，应放在同一个测试中。
- 若程序元素是类，则至少要为该类的每一个方法编写一个测试，如果该方法需要测试多个用例，应放在同一个测试中。
- 若程序元素是类，除了为该类的每一个方法编写至少一个测试之外，还可以为该类编写任意多个测试，以覆盖该类的不同使用场景或边界情况。
- 若编写测试时需要用到辅助元素（Mock 或 Spy 等），可以在测试文件中直接定义这些辅助元素。若辅助元素较为简单，则可以直接放在每一个测试内部，优先保证每个测试的独立性，而不是追求极致 DRY；若辅助元素较为复杂或需要在多个测试中复用，则可以放在测试文件顶部，供该测试文件中的所有测试使用。
- 测试顺序应与源文件中被测试目标的原始顺序保持一致。
- 若该模块不需要测试，必须在说明文件中明确说明该模块不需要测试，并说明理由。一般来说，只有在该模块没有可执行的公共函数、只承载类型层表达，或其语义已被上层模块的测试完整覆盖且重复测试几乎不再带来额外价值时，才适合这样处理。
- 模块的单元测试文件目录是 `./tests/unit/identifier`，若模块包含子模块，则子模块的单元测试文件目录为 `./tests/unit/identifier/<sub-module-name>`。
- 测试应重点覆盖带种子与不带种子的 `Id` 生成语义、`Id` 的比较与序列化，以及 UUID 的格式校验、版本读取和不同生成路径的结果特征。
