菜单

命令处理

相关源文件

本文档解释了 Deno 如何处理命令行界面 (CLI) 的命令,详细介绍了从初始命令解析到执行特定子命令(如 runtestfmt)的执行流程。

有关命令处理完成后模块加载的信息,请参阅 模块加载和解析

命令处理流程概述

Deno 的命令处理始于用户通过命令和参数调用 CLI。该过程包括通过 flags_from_vec 解析命令行参数,解析配置,通过 run_subcommand 分派到相应的子命令处理程序,并处理任何产生的错误。

高级命令处理流程

来源: cli/main.rs453-513 cli/main.rs515-555 cli/main.rs111-368

命令行参数解析

当 Deno 启动时,它会收集命令行参数,并将它们传递给标志解析系统。这些参数被转换为一个结构化的 Flags 对象,其中包含已识别的子命令及其特定选项。

标志解析与配置

标志解析系统同时处理全局标志(如 --log-level--unstable-*)和子命令特定标志(如 deno run--watch)。Flags 结构包含一个 DenoSubcommand 枚举变体,该变体决定将调用哪个命令处理程序。

来源: cli/main.rs515-555 cli/args/flags.rs647-691 cli/args/flags.rs468-502

子命令识别与分派

Deno 支持许多子命令,每个子命令都由 DenoSubcommand 枚举中的一个变体表示。解析参数后,Deno 识别要运行的子命令,并通过 run_subcommand 将执行分派到相应的处理程序。

子命令分派机制

每个子命令都通过 spawn_subcommand 函数在自己的异步任务中执行,该函数将命令处理程序包装在 deno_core::unsync::spawn 中,并使用 .boxed_local() 来防止在调试模式下的 Windows 上发生堆栈溢出。

来源: cli/main.rs102-109 cli/main.rs111-368 cli/args/flags.rs468-502

Worker 创建和配置

对于大多数需要执行 JavaScript/TypeScript 代码的子命令(如 runtesteval),Deno 会创建一个 worker 环境。这包括使用 CliFactory 创建服务,然后使用 CliMainWorkerFactory 创建一个 CliMainWorker

通过工厂模式创建 Worker

CliMainWorker 包装了一个 LibMainWorker,而 LibMainWorker 又包装了运行时 MainWorker。这种分层方法允许在利用共享库和运行时组件的同时,实现 CLI 特定的功能。

来源: cli/factory.rs314-353 cli/worker.rs314-324 cli/worker.rs68-285

命令执行示例:deno run

让我们来看一下当用户运行 deno run script.ts 这样的命令时会发生什么。

  1. CLI 参数被解析,并使用 Run 子命令创建了一个 Flags 对象。
  2. run_subcommand 函数将执行分派到 Run 子命令的相应处理程序。
  3. 处理程序使用 CliFactory 来创建服务和 Worker。
  4. Worker 执行主模块并运行事件循环。

deno run 的详细执行流程

来源: cli/main.rs225-294 cli/worker.rs84-160 cli/factory.rs500-567

错误处理

Deno 为命令执行提供了一个强大的错误处理机制。如果命令失败,错误会在退出并返回适当的退出代码之前进行格式化并显示给用户。

对于 JavaScript 错误,Deno 提供详细的堆栈跟踪,以帮助开发人员识别和修复其代码中的问题。

来源: cli/main.rs404-422 runtime/fmt_errors.rs

主入口点

Deno CLI 的入口点是 cli/main.rs 中的 main 函数。它负责设置环境、处理 panic hook、处理参数并启动相应的子命令。

main() → resolve_flags_and_init() → run_subcommand() → [specific subcommand handler]

run_subcommand 函数是一个中心分派点,它根据识别出的子命令将执行路由到相应的处理程序。

来源: cli/main.rs432-465 cli/main.rs109-350

支持的子命令

Deno 支持各种子命令,每个子命令都有其特定的行为和标志。 cli/args/flags.rs 中的 DenoSubcommand 枚举定义了所有支持的子命令。

子命令描述处理程序模块
run执行 JavaScript/TypeScript 程序tools::run
test运行测试tools::test
fmt格式化源文件tools::fmt
lintLint 源文件tools::lint
compile将脚本编译成独立的自包含可执行文件tools::compile
repl打开交互式 Read-Eval-Print-Looptools::repl
install将脚本安装为可执行文件tools::installer
uninstall卸载先前安装的脚本tools::installer
cache缓存依赖项tools::installer
info显示有关缓存的信息或与源文件相关的信息tools::info
eval评估代码片段tools::run
task运行配置文件中定义的任务tools::task
adddeno.json 添加依赖项tools::pm
removedeno.json 中移除依赖项tools::pm
outdated检查过期的依赖项tools::pm
publish将包发布到 JSRtools::publish

来源: cli/args/flags.rs453-486 cli/main.rs109-350

生命周期事件

在命令执行过程中,Deno 向 JavaScript 环境分派各种生命周期事件,以通知其执行状态。

  1. load - 加载主模块后分派。
  2. beforeunload - 在程序退出前分派,允许取消。
  3. unload - 程序即将退出时分派。
  4. process.beforeexit - Node.js 兼容事件,在程序退出前触发。
  5. process.exit - Node.js 兼容事件,在程序退出时触发。

来源: cli/worker.rs84-160 runtime/worker.rs976-1062

结论

Deno 的命令处理系统是一个结构良好的管道,它处理用户输入,分派到相应的处理程序,创建隔离的执行环境,并管理脚本执行的生命周期。通过了解这个系统,开发人员可以更好地利用 Deno 的功能并为其代码库做出贡献。