EN

配置文件

自动生成类型化的 JSON 配置文件,存储用户配置。

更新于

func/config 会为 func 应用自动生成配置文件,并帮助用户屏蔽底层的权限、读写、原子化操作,可用于存储用户信息、默认应用配置等。下面以 ship login 保存用户名和 email 为例。

定义并注册配置

继承 Config(defaults) 创建配置类,再通过 ConfigModule.register() 注册:

src/app.module.ts
import { Module, createApp } from 'func'
import { Config, ConfigFile, ConfigModule } from 'func/config'

@ConfigFile({ maxBytes: 64 * 1024 })
export class ProfileConfig extends Config({
  username: '',
  email: '',
}) {}

@Module({
  imports: [
    ConfigModule.register({
      configs: [ProfileConfig],
    }),
  ],
})
export class AppModule {}

const app = createApp(AppModule, {
  appName: 'ship',
})

void app.bootstrap()

上述代码会自动为用户创建 ~/.ship/config.json 并提供基础 API 支持。在默认设置中,文件名为 config.json,你可以指定覆盖,如有必要,你也可以创建多个配置文件。

func 使用 Node.js 识别到的用户主目录,不依赖当前工作目录。以上例为准,各系统通常会把配置文件保存到:

系统默认位置
macOS/Users/<用户名>/.ship/config.json
Linux/home/<用户名>/.ship/config.json
WindowsC:\Users\<用户名>\.ship\config.json

主目录可能受系统账户和运行环境影响;例如 Linux 的 root 用户通常对应 /root/.ship/profile.json

应用名由 createApp({ appName }) 统一提供,func 只负责收集并透传。Config、Log 等使用应用目录的能力会在各自的 Provider 初始化时验证 appName。应用名和文件名都必须是安全的单个路径片段,不能包含斜杠、反斜杠、空白边界或 ...

读取和更新配置

注册后的配置类可以像普通 Provider 一样注入 Command、Module 或其他 Provider:

src/commands/login.command.ts
import { Command, Handler, Value } from 'func'
import { ProfileConfig } from '../profile.config'

@Command('login')
export class LoginCommand {
  @Value()
  username?: string

  @Value()
  email?: string

  constructor(private readonly config: ProfileConfig) {}

  @Handler()
  login() {
    const username = this.username ?? this.config.get('username')
    const email = this.email ?? this.config.get('email')
    this.config.set('username', username)
    this.config.set('email', email)
    console.log(this.config.getAll())
  }
}

执行 ship login --username alice --email alice@example.com 会更新两个字段;省略其中一个选项时,会从现有配置中读取该字段。这个示例只保存非敏感的用户资料,密码和访问令牌不应直接写入配置文件。

defaults 会把字符串、数字、布尔值、null、数组和嵌套对象映射为对应类型。公开操作包括:

方法行为
get(key)读取一个顶层配置值。
getAll()读取完整配置。
set(key, value)更新一个顶层配置值并写入文件。
reset(key)把一个顶层配置值恢复为默认值。
resetAll()把完整配置恢复为 defaults。

读取结果是副本,修改返回对象不会改变运行时配置。需要保存变更时必须调用 setresetresetAll

文件创建与校验

配置文件在第一次 getgetAllsetresetresetAll 时才创建。写入会先生成临时文件,再替换原文件,避免留下部分写入的 JSON。

读取时只接受 defaults 中已经声明的 key,并检查每个已知值的 JSON 形状:

  • 缺失值使用 defaults 补齐;
  • 未声明的存储字段会被忽略;
  • 类型不匹配、无效 JSON 或非对象根值会产生运行时异常;
  • 失败读取不会自动覆盖原文件。

maxBytes 同时限制读取文件和准备写入的 JSON 大小。一个 Module 可以注册多个配置类,但相同文件路径不能重复注册。

读取写入失败

读取失败是会发生的,这常见于用户手动编辑了配置文件但格式错误,开发者可以捕获此类错误,默认用户可以接收到最终抛出的错误,作为简单的解决方案,我们可以提供 ship config reset 作为重置修复,如果需要进一步的处理细节,则可以在应用中手动使用 try...catch 或是监听全局错误,进行更细致的提示。

写入失败发生于权限不足,这会阻止正常的命令行应用工作流程。除非用户手动编辑了配置文件的权限,否则一般不会发生,不建议为其添加额外的容错逻辑。

API 速查

API用途
Config(defaults)创建从 defaults 推断类型的配置基类。
@ConfigFile({ name, maxBytes? })设置文件名与可选大小限制。
ConfigModule.register({ configs })注册并导出一个或多个配置 Provider。
ConfigInstance描述 get、getAll、set、reset 和 resetAll。
CONFIG_SYSTEM / CONFIG_RUNTIME配置能力的稳定错误码枚举。