deno.com
本页内容

语言服务器集成

提示

如果您正在寻找如何将 Deno 的 LSP 与各种编辑器结合使用的信息,请访问设置您的环境页面

Deno CLI 内置了语言服务器,可以提供智能编辑体验,并能方便地访问 Deno 内置的其他工具。对于大多数用户而言,使用语言服务器的方式是通过编辑器,例如Visual Studio Code其他编辑器

本页面旨在为那些创建与语言服务器集成或为 Deno 提供智能集成包注册表的人员提供信息。

Deno 语言服务器提供了 语言服务器协议 的服务器实现,该实现专门为提供 Deno 视角的代码视图而量身定制。它已集成到命令行中,可以通过 lsp 子命令启动。

结构 Jump to heading

语言服务器启动时,会创建一个 LanguageServer 实例,该实例保存了语言服务器的所有状态。它还定义了客户端通过语言服务器 RPC 协议调用的所有方法。

设置 Jump to heading

语言服务器支持工作区中的多项设置

  • deno.enable
  • deno.enablePaths
  • deno.cache
  • deno.certificateStores
  • deno.config
  • deno.importMap
  • deno.internalDebug
  • deno.codeLens.implementations
  • deno.codeLens.references
  • deno.codeLens.referencesAllFunctions
  • deno.codeLens.test
  • deno.suggest.completeFunctionCalls
  • deno.suggest.names
  • deno.suggest.paths
  • deno.suggest.autoImports
  • deno.suggest.imports.autoDiscover
  • deno.suggest.imports.hosts
  • deno.lint
  • deno.tlsCertificate
  • deno.unsafelyIgnoreCertificateErrors
  • deno.unstable

语言服务器还支持基于每个资源进行设置。

  • deno.enable
  • deno.enablePaths
  • deno.codeLens.test

Deno 在语言服务器进程的多个点分析这些设置。首先,当客户端发出 initialize 请求时,initializationOptions 将被视为表示 deno 选项命名空间的对象。例如,以下值将为该语言服务器实例启用 Deno 的不稳定 API。

{
  "enable": true,
  "unstable": true
}

当语言服务器收到 workspace/didChangeConfiguration 通知时,它将评估客户端是否表明其具有 workspaceConfiguration 功能。如果具备,它将发送一个 workspace/configuration 请求,该请求将包含对工作区配置以及语言服务器当前跟踪的所有 URI 配置的请求。

如果客户端具有 workspaceConfiguration 功能,语言服务器将在收到 textDocument/didOpen 通知时发送该 URI 的配置请求,以获取资源特定的设置。

如果客户端不具备 workspaceConfiguration 功能,语言服务器将假定工作区设置适用于所有资源。

命令 Jump to heading

语言服务器可能会向客户端发出多条命令,客户端应实现这些命令。

.cache Jump to heading

当一个未缓存的模块说明符被导入到模块中时,deno.cache 会作为解析代码操作发送。它将带有一个参数,该参数包含要缓存的已解析说明符字符串。

showReferences Jump to heading

deno.showReferences 作为某些 CodeLens 上的命令发送,用于显示引用的位置。参数包含作为命令主题的说明符、目标的起始位置以及要显示的引用位置。

test Jump to heading

deno.test 作为测试 CodeLens 的一部分发送,客户端应根据参数(即包含测试的说明符和用于筛选测试的测试名称)运行测试。

请求 Jump to heading

LSP 目前支持以下自定义请求。客户端应实现这些请求,以便拥有一个与 Deno 良好集成的、功能齐全的客户端。

/cache Jump to heading

deno/cache 将指示 Deno 尝试缓存模块及其所有依赖项。如果只传递了 referrer,则将加载模块说明符的所有依赖项。如果 uris 中有值,则只缓存这些 uris

它期望以下参数:

interface CacheParams {
  referrer: TextDocumentIdentifier;
  uris: TextDocumentIdentifier[];
}

performance Jump to heading

deno/performance 请求返回 Deno 内部检测的计时平均值。它不期望任何参数。

reloadImportRegistries Jump to heading

deno/reloadImportRegistries 重新加载来自导入注册表的任何缓存响应。它不期望任何参数。

virtualTextDocument Jump to heading

deno/virtualTextDocument 从 LSP 请求一个虚拟文本文档,这是一个只读文档,可以在客户端中显示。这允许客户端访问 Deno 缓存中的文档,例如远程模块和 Deno 内置的 TypeScript 库文件。Deno 语言服务器将把所有内部文件编码在自定义方案 deno: 下,因此客户端应将所有针对 deno: 方案的请求路由回 deno/virtualTextDocument API。

它还支持一个特殊的 URL deno:/status.md,该 URL 提供一个 Markdown 格式的文本文档,其中包含有关 LSP 状态的详细信息,供用户显示。

它期望以下参数:

interface VirtualTextDocumentParams {
  textDocument: TextDocumentIdentifier;
}

task Jump to heading

deno/task 请求返回可用的 Deno 任务,详见 task_runner。它不期望任何参数。

通知 Jump to heading

当前有一个从服务器发送到客户端的自定义通知:deno/registryState。当 deno.suggest.imports.autoDiscovertrue 且要添加到文档的导入源未在 deno.suggest.imports.hosts 中明确设置时,将检查该源并向客户端发送状态通知。

收到通知时,如果参数 suggestiontrue,客户端应向用户提供启用该源并将其添加到 deno.suggest.imports.hosts 配置中的选项。如果 suggestionfalse,客户端应将其添加到配置中并设为 false,以阻止语言服务器尝试检测是否支持建议。

该通知的参数是:

interface RegistryStatusNotificationParams {
  origin: string;
  suggestions: boolean;
}

语言 ID Jump to heading

语言服务器支持以下文本文档语言 ID 的诊断和格式化:

  • "javascript"
  • "javascriptreact"
  • "jsx" 非标准,与 javascriptreact 相同
  • "typescript"
  • "typescriptreact"
  • "tsx" 非标准,与 typescriptreact 相同

语言服务器仅支持以下语言 ID 的格式化:

  • "json"
  • "jsonc"
  • "markdown"

测试 Jump to heading

Deno 语言服务器支持一组自定义 API 以启用测试功能。这些 API 旨在提供信息以启用 VS Code 的测试 API,但也可供其他语言服务器客户端使用以提供类似的界面。

客户端和服务器都应支持实验性的 testingApi 功能。

interface ClientCapabilities {
  experimental?: {
    testingApi: boolean;
  };
}
interface ServerCapabilities {
  experimental?: {
    testingApi: boolean;
  };
}

当支持测试 API 的 Deno 版本遇到支持该功能的客户端时,它将初始化处理测试检测的代码,并开始提供启用该功能的通知。

另请注意,当测试 API 功能启用时,测试 CodeLens 将不再发送给客户端。

测试设置 Jump to heading

有些特定设置会改变语言服务器的行为:

  • deno.testing.args - 一个字符串数组,在执行测试时将作为参数提供。这与 deno test 子命令的工作方式相同。
  • deno.testing.enable - 一个二进制标志,用于启用或禁用测试服务器。

测试通知 Jump to heading

服务器将在特定条件下向客户端发送通知。

deno/testModule Jump to heading

当服务器发现包含测试的模块时,它将通过发送 deno/testModule 通知以及 TestModuleParams 的有效负载来通知客户端。

Deno 的结构如下:

  • 一个模块可以包含 n 个测试。
  • 一个测试可以包含 n 个步骤。
  • 一个步骤可以包含 n 个步骤。

当 Deno 对测试模块进行静态分析时,它会尝试识别任何测试和测试步骤。由于 Deno 中声明测试的动态方式,它们并非总是能被静态识别,而只能在模块执行时被识别。此通知旨在在更新客户端时处理这两种情况。当测试被静态发现时,通知的 kind 将是 "replace";当测试或步骤在执行时发现时,通知的 kind 将是 "insert"

当测试文档在编辑器中被编辑,并且从客户端收到 textDocument/didChange 通知时,服务器端将执行这些更改的静态分析,如果测试已更改,客户端将收到通知。

当客户端收到 "replace" 通知时,它可以安全地“替换”测试模块表示;而当收到 "insert" 时,它应递归地尝试添加到现有表示中。

对于测试模块,textDocument.uri 应作为任何表示的唯一 ID(因为它指向唯一模块的字符串 URL)。TestData 项包含一个唯一的 id 字符串。此 id 字符串是服务器为测试跟踪的识别信息的 SHA-256 哈希值。

interface TestData {
  /** The unique ID for this test/step. */
  id: string;

  /** The display label for the test/step. */
  label: string;

  /** Any test steps that are associated with this test/step */
  steps?: TestData[];

  /** The range of the owning text document that applies to the test. */
  range?: Range;
}

interface TestModuleParams {
  /** The text document identifier that the tests are related to. */
  textDocument: TextDocumentIdentifier;

  /** A indication if tests described are _newly_ discovered and should be
   * _inserted_ or if the tests associated are a replacement for any existing
   * tests. */
  kind: "insert" | "replace";

  /** The text label for the test module. */
  label: string;

  /** An array of tests that are owned by this test module. */
  tests: TestData[];
}

deno/testModuleDelete Jump to heading

当服务器正在监视的测试模块被删除时,服务器将发出 deno/testModuleDelete 通知。收到通知后,客户端应删除该测试模块及其所有子测试和测试步骤的表示。

interface TestModuleDeleteParams {
  /** The text document identifier that has been removed. */
  textDocument: TextDocumentIdentifier;
}

deno/testRunProgress Jump to heading

当客户端请求deno/testRun时,服务器将通过 deno/testRunProgress 通知支持该测试运行的进度。

客户端应处理这些消息并更新任何 UI 表示。

状态更改由 TestRunProgressParams.message.kind 属性表示。状态包括:

  • "enqueued" - 测试或测试步骤已排队等待测试。
  • "skipped" - 测试或测试步骤被跳过。当 Deno 测试的 ignore 选项设置为 true 时发生。
  • "started" - 测试或测试步骤已开始。
  • "passed" - 测试或测试步骤已通过。
  • "failed" - 测试或测试步骤已失败。这旨在表示测试框架而非测试本身的错误,但 Deno 目前不支持这种区分。
  • "errored" - 测试或测试步骤发生错误。有关错误的附加信息将在 .message.messages 属性中。
  • "end" - 测试运行已结束。
interface TestIdentifier {
  /** The test module the message is related to. */
  textDocument: TextDocumentIdentifier;

  /** The optional ID of the test. If not present, then the message applies to
   * all tests in the test module. */
  id?: string;

  /** The optional ID of the step. If not present, then the message only applies
   * to the test. */
  stepId?: string;
}

interface TestMessage {
  /** The content of the message. */
  message: MarkupContent;

  /** An optional string which represents the expected output. */
  expectedOutput?: string;

  /** An optional string which represents the actual output. */
  actualOutput?: string;

  /** An optional location related to the message. */
  location?: Location;
}

interface TestEnqueuedStartedSkipped {
  /** The state change that has occurred to a specific test or test step.
   *
   * - `"enqueued"` - the test is now enqueued to be tested
   * - `"started"` - the test has started
   * - `"skipped"` - the test was skipped
   */
  type: "enqueued" | "started" | "skipped";

  /** The test or test step relating to the state change. */
  test: TestIdentifier;
}

interface TestFailedErrored {
  /** The state change that has occurred to a specific test or test step.
   *
   * - `"failed"` - The test failed to run properly, versus the test erroring.
   *   currently the Deno language server does not support this.
   * - `"errored"` - The test errored.
   */
  type: "failed" | "errored";

  /** The test or test step relating to the state change. */
  test: TestIdentifier;

  /** Messages related to the state change. */
  messages: TestMessage[];

  /** An optional duration, in milliseconds from the start to the current
   * state. */
  duration?: number;
}

interface TestPassed {
  /** The state change that has occurred to a specific test or test step. */
  type: "passed";

  /** The test or test step relating to the state change. */
  test: TestIdentifier;

  /** An optional duration, in milliseconds from the start to the current
   * state. */
  duration?: number;
}

interface TestOutput {
  /** The test or test step has output information / logged information. */
  type: "output";

  /** The value of the output. */
  value: string;

  /** The associated test or test step if there was one. */
  test?: TestIdentifier;

  /** An optional location associated with the output. */
  location?: Location;
}

interface TestEnd {
  /** The test run has ended. */
  type: "end";
}

type TestRunProgressMessage =
  | TestEnqueuedStartedSkipped
  | TestFailedErrored
  | TestPassed
  | TestOutput
  | TestEnd;

interface TestRunProgressParams {
  /** The test run ID that the progress message applies to. */
  id: number;

  /** The message*/
  message: TestRunProgressMessage;
}

测试请求 Jump to heading

服务器处理两种不同的请求:

deno/testRun Jump to heading

为请求语言服务器执行一组测试,客户端会发送一个 deno/testRun 请求,其中包含用于将来响应客户端的测试运行 ID、测试运行类型以及要包含或排除的任何测试模块或测试。

目前 Deno 仅支持 "run" 类型的测试运行。"debug""coverage" 计划在未来得到支持。

当没有包含任何测试模块或测试时,意味着应执行所有已发现的测试模块和测试。当包含一个测试模块但未指定任何测试 ID 时,则意味着应包含该测试模块内的所有测试。一旦所有测试都被识别,任何被排除的测试都将被移除,并且解析后的测试集将以 "enqueued" 状态返回到响应中。

由于测试步骤的声明和运行具有动态性,因此无法通过此 API 包含或排除测试步骤。

interface TestRunRequestParams {
  /** The id of the test run to be used for future messages. */
  id: number;

  /** The run kind. Currently Deno only supports `"run"` */
  kind: "run" | "coverage" | "debug";

  /** Test modules or tests to exclude from the test run. */
  exclude?: TestIdentifier[];

  /** Test modules or tests to include in the test run. */
  include?: TestIdentifier[];
}

interface EnqueuedTestModule {
  /** The test module the enqueued test IDs relate to */
  textDocument: TextDocumentIdentifier;

  /** The test IDs which are now enqueued for testing */
  ids: string[];
}

interface TestRunResponseParams {
  /** Test modules and test IDs that are now enqueued for testing. */
  enqueued: EnqueuedTestModule[];
}

deno/testRunCancel Jump to heading

如果客户端希望取消当前正在运行的测试,它会发送一个 deno/testRunCancel 请求,其中包含要取消的测试 ID。返回的响应将是一个布尔值:如果测试被取消,则为 true;如果无法取消,则为 false。在测试取消过程中,仍将发送相应的测试进度通知。

interface TestRunCancelParams {
  /** The test id to be cancelled. */
  id: number;
}

您找到所需内容了吗?

隐私政策