跳至主要内容

导入完成和智能注册表

语言服务器支持 URL 的完成。

本地导入完成

当尝试导入相对模块说明符(以 ./../ 开头的说明符)时,将为 Deno 认为可以运行的目录和文件提供导入完成(以扩展名 .ts.js.tsx.jsx.mjs 结尾)。

工作区导入完成

当尝试导入未配置为注册表的远程 URL(见下文)时,扩展将提供已成为工作区一部分的远程模块。

模块注册表完成

支持它的模块注册表可以配置为自动完成。这提供了一种方便的方法,可以在 IDE 的“舒适”环境中探索模块注册表。

自动发现

默认情况下,Deno 语言服务器将尝试确定服务器是否支持完成建议。如果主机/来源尚未明确配置,它将检查服务器,如果它支持完成建议,您将被提示选择是否启用它。

您应该只为信任的注册表启用此功能,因为远程服务器可能会提供针对模块的建议,这些模块试图让您运行不受信任的代码。

配置

用于配置自动完成注册表的设置

  • deno.suggest.imports.autoDiscover - 如果启用,当语言服务器发现一个未明确配置的新来源时,它将检查该来源是否支持导入自动完成,并提示您启用或禁用它。默认情况下为 true

  • deno.suggest.imports.hosts - 这些是配置为提供导入自动完成的来源。目标主机需要支持 Deno 导入自动完成(详见下文)。该值是一个对象,其中键是主机,值是启用或禁用。例如

    {
    "deno.suggest.imports.hosts": {
    "https://deno.land": true
    }
    }

它是如何工作的?

在扩展和语言服务器启动时,Deno 将尝试从任何已配置且启用的主机中获取 /.well-known/deno-import-intellisense.json。此文件提供了以高度可配置的方式形成模块说明符自动完成所需的数据(这意味着您无需绑定到任何特定模块注册表即可获得丰富的编辑体验)。

当您构建或编辑模块说明符时,Deno 将根据 JSON 配置文件中配置的内容,从主机获取 URL 的其他部分。

当您完成模块说明符时,如果它尚未在本地缓存,Deno 将尝试从注册表获取已完成的说明符。

它适用于所有远程模块吗?

不,因为扩展和 Deno 需要了解如何查找模块。配置文件提供了一种高度灵活的方式,允许用户描述如何构建 URL,包括支持语义版本控制(如果模块注册表支持)。

注册表对导入自动完成的支持

为了支持 Deno 语言服务器发现注册表,注册表需要提供以下内容

  • 一个模式定义文件。此文件需要位于 /.well-known/deno-import-intellisense.json。此文件提供 Deno 语言服务器 *查询* 注册表并构建导入说明符所需的配置。
  • 一系列 API 端点,提供用于完成导入说明符的值。

配置模式

模式定义的 JSON 响应需要是一个包含两个必填属性的对象

  • "version" - 一个数字,必须等于 12
  • "registries" - 一个注册表对象的数组,定义了此注册表的模块说明符的构建方式。

有一个 JSON 模式文档定义了此模式,作为 CLI 源代码的一部分提供。

虽然 v2 比 v1 支持更多功能,但它们以非破坏性的方式引入,语言服务器会自动处理 v1 或 v2 版本,无论 "version" 键中提供了哪个版本,因此从技术上讲,注册表可以声称自己是 v1 但使用所有 v2 功能。但是,不建议这样做,因为虽然目前没有专门支持 v2 功能的代码分支,但这并不意味着将来不会为了支持 *v3* 或其他版本而出现这样的分支。

注册表

在配置模式中,"registries" 属性是一个注册表数组,它们是包含两个必填属性的对象

  • "schema" - 一个字符串,它是一个类似 Express 的路径匹配表达式,定义了注册表上 URL 的构建方式。语法直接基于 path-to-regexp。例如,如果以下内容是注册表上 URL 的说明符

    https://example.com/[email protected]/mod.ts

    模式值可能类似于以下内容

    {
    "version": 1,
    "registries": [
    {
    "schema": "/:package([a-z0-9_]*)@:version?/:path*"
    }
    ]
    }
  • "variables" - 对于在模式中定义的键,需要定义一个相应的变量,它通知语言服务器从模块说明符的该部分获取完成。

变量

在配置模式中,"variables" 属性是一个变量定义数组,它们是包含两个必填属性的对象

  • "key" - 一个字符串,与 "schema" 属性中的变量键名说明符匹配。

  • "documentation" - 一个可选的 URL,语言服务器可以从中获取单个变量条目的文档。变量可以被替换以构建最终的 URL。带有单括号格式的变量,例如 ${variable},将被添加为从字符串中匹配出来的,而带有双括号格式的变量,例如 ${{variable}},将被百分比编码为 URI 组件部分。

  • "url" - 一个 URL,语言服务器可以从中获取变量的补全。变量可以被替换以构建 URL。带有单括号格式的变量,例如 ${variable},将被添加为从字符串中匹配出来的,而带有双括号格式的变量,例如 ${{variable}},将被百分比编码为 URI 组件部分。如果变量包含 "key" 的值,那么语言服务器将支持对部分模块的增量请求,允许服务器在用户键入变量值的一部分时提供补全。如果 URL 不是完全限定的,则将使用模式文件的 URL 作为基准。在我们上面的示例中,我们有三个变量,因此我们的变量定义可能如下所示

    {
    "version": 1,
    "registries": [
    {
    "schema": "/:package([a-z0-9_]*)@:version?/:path*",
    "variables": [
    {
    "key": "package",
    "documentation": "https://api.example.com/docs/packages/${package}",
    "url": "https://api.example.com/packages/${package}"
    },
    {
    "key": "version",
    "url": "https://api.example.com/packages/${package}/versions"
    },
    {
    "key": "path",
    "documentation": "https://api.example.com/docs/packages/${package}/${{version}}/paths/${path}",
    "url": "https://api.example.com/packages/${package}/${{version}}/paths/${path}"
    }
    ]
    }
    ]
    }

URL 端点

每个 URL 端点的响应需要是一个 JSON 文档,该文档是一个字符串数组或一个补全列表

interface CompletionList {
/** The list (or partial list) of completion items. */
items: string[];
/** If the list is a partial list, and further queries to the endpoint will
* change the items, set `isIncomplete` to `true`. */
isIncomplete?: boolean;
/** If one of the items in the list should be preselected (the default
* suggestion), then set the value of `preselect` to the value of the item. */
preselect?: string;
}

扩展我们上面的示例,URL https://api.example.com/packages 预计会返回类似以下内容

[
"a_package",
"another_package",
"my_awesome_package"
]

或者类似以下内容

{
"items": [
"a_package",
"another_package",
"my_awesome_package"
],
"isIncomplete": false,
"preselect": "a_package"
}

https://api.example.com/packages/a_package/versions 的查询将返回类似以下内容

[
"v1.0.0",
"v1.0.1",
"v1.1.0",
"v2.0.0"
]

或者

{
"items": [
"v1.0.0",
"v1.0.1",
"v1.1.0",
"v2.0.0"
],
"preselect": "v2.0.0"
}

https://api.example.com/packages/a_package/versions/v1.0.0/paths 的查询将返回类似以下内容

[
"a.ts",
"b/c.js",
"d/e.ts"
]

或者

{
"items": [
"a.ts",
"b/c.js",
"d/e.ts"
],
"isIncomplete": true,
"preselect": "a.ts"
}

多部分变量和文件夹

导航大型文件列表对于用户来说可能是一个挑战。使用注册表 V2,语言服务器对返回的项目有一些特殊处理,以便更容易地完成对子文件夹中文件的路径。

当返回的项目以 / 结尾时,语言服务器将将其呈现给客户端作为“文件夹”,这将在客户端中表示。因此,希望提供对以下文件夹结构的子导航的注册表

examples/
└─┬─ first.ts
└─ second.ts
sub-mod/
└─┬─ mod.ts
└─ tests.ts
mod.ts

假设有一个类似于 /:package([a-z0-9_]*)@:version?/:path* 的模式,并且有一个针对 path 的 API 端点,例如 https://api.example.com/packages/${package}/${{version}}/${path},那么希望对 /packages/pkg/1.0.0/ 的路径进行响应。

{
"items": [
"examples/",
"sub-mod/",
"mod.ts"
],
"isIncomplete": true
}

对于 /packages/pkg/1.0.0/examples/ 的路径,则希望进行以下响应。

{
"items": [
"examples/first.ts",
"examples/second.ts"
],
"isIncomplete": true
}

这将允许用户在 IDE 中选择 examples 文件夹,然后获取文件夹中内容的列表,从而更轻松地浏览文件结构。

文档端点

文档端点应返回一个文档对象,其中包含与请求实体相关的任何文档。

interface Documentation {
kind: "markdown" | "plaintext";
value: string;
}

为了扩展上面的示例,对 https://api.example.com/packages/a_package 的查询将返回类似于以下内容。

{
"kind": "markdown",
"value": "some _markdown_ `documentation` here..."
}

模式验证

当语言服务器启动(或扩展的配置发生更改)时,语言服务器将尝试获取并验证配置中域主机指定符的模式配置。

验证尝试确保所有定义的注册表都是有效的,注册表中包含的变量在变量中指定,并且没有定义不在模式中包含的额外变量。如果验证失败,注册表将不会启用,错误将记录到 vscode 中的 Deno 语言服务器输出中。

如果您是注册表维护者,需要帮助、建议或在设置注册表以进行自动完成方面需要帮助,请随时打开一个 问题,我们将尽力提供帮助。

已知注册表

以下是已知支持该方案的注册表列表。您只需将域添加到 deno.suggest.imports.hosts 并将值设置为 true 即可。

  • https://deno.land/ - 包含第三方 /x/ 注册表和 /std/ 库注册表。
  • https://nest.land/ - 基于区块链的 Deno 模块注册表。
  • https://crux.land/ - 用于永久托管小型脚本的免费开源注册表。