# @nx-lang/language-protocol 中文文档

规范地址：https://npmcn.com/package/%40nx-lang/language-protocol/

版本：0\.10\.0
npm 元数据更新时间：2026-11-02T01:25:16.407Z
中文译文更新时间：2026-11-02T01:31:10.386Z
软件包许可：MIT

本文由上游 README 机器翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40nx-lang/language-protocol
原文对照：https://npmcn.com/package/%40nx-lang/language-protocol/?lang=original
项目主页：https://nxlang.org/
源码仓库：https://github.com/nx-lang/nx

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：55.8 kB，7 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=22\.0\.0
- 运行依赖：0 个
- 首次发布：2026-09-15T04:50:36.908Z
- 最新版本发布：2026-11-02T01:25:16.078Z
- 已发布版本数：10（近 12 个月 10 个）

## 中文简介

NX语言查询的独立于传输的请求和回答形状，以及每个客户端实现的NxLanguageService接口。

## 安装

```sh
npm install @nx-lang/language-protocol
```

也可以使用：`pnpm add @nx-lang/language-protocol`、`yarn add @nx-lang/language-protocol`、`bun add @nx-lang/language-protocol`

## README

# @nx-lang / language-protocol

编辑器和NX语言服务之间的契约：语言查询的形状及其 答案，编码双方使用的位置，和 `NxLanguageService` 连接每个客户端 实现满足。类型，一些常量和保护，以及错误类；没有运行时 依赖。

该接口的实现存在于其他地方：

-   `@nx-lang/language-client` -浏览器的HTTP实现，与
-   `@nx-lang/language-http` -一个可挂载的节点处理程序，通过 `@nx-lang/sdk-node`.

编辑器集成，例如 `@nx-lang/monaco` 只依赖于这个包，所以一个http支持的， 工人支持的或进程内服务是可互换的。

## 文档集模型

每个查询都包含将从中得到回答的完整文档集，以及对象的URI 查询的文档是关于：

```ts
interface LanguageQuery {
  documents: { uri: string; source: string; version?: number; identity?: string }[];
  uri: string; // one of documents[].uri
}
```

该服务在查询之间不保留任何内容。两个相同的查询产生相同的答案 在中间被询问，这是让几个服务器实例在没有会话关联的情况下回答的原因。 单文档主机发送它的一个文档；一个主机编辑一组文件中的一个，每个文件都导入 Other发送整个集合，其中编辑的文档包含编辑器未保存的文本，以及 完成包括编辑的文档从同级文档导入的内容。

`version` 是编辑想要的；它在应答中被回显，因此客户端可以丢弃 在发送新版本后到达的应答。 `identity` 是NX解决的工作空间身份 按(`tenant/form.nx`);当省略时，它从URI派生。

## 位置是UTF-16代码单位

一、 `TextPosition` 是零基的 `line` 和一个零基的 `character` 以UTF-16编码单位计算 从一线出发，一路前行 `String.prototype.length` 计数和摩纳哥的方式，codemmirror和 语言服务器协议默认计数。之前的表情符号是两个单位。靶场携带 它的起始和结束位置，在它们旁边， `startByte` 和 `endByte` 抵消到 文档的UTF-8文本，这是语言服务测量的。

```ts
// let s = "😀" + name
//                ^ name starts at character 15 (the emoji is 2 units) and byte 18 (it is 4 bytes)
{ start: { line: 0, character: 15 }, end: { line: 0, character: 19 }, startByte: 18, endByte: 22 }
```

## 查询

定义了五个查询；每个都有一个请求和一个通过JSON往返的回答类型。这个 下面的例子编译在 `test/examples.test.ts`，因此它们不会偏离类型。

### `hover`

```ts
const request: HoverRequest = {
  documents,
  uri: "nx://tenant/form.nx",
  position: { line: 1, character: 3 },
};

const answer: Hover | null = {
  uri: "nx://tenant/form.nx",
  identity: "tenant/form.nx",
  version: 7,
  range: { start: { line: 1, character: 1 }, end: { line: 1, character: 7 }, startByte: 34, endByte: 40 },
  contents: "```nx\n<Button label:string />\n```",
};
```

`contents` 有NX碎片的markdown吗 ` ```nx ` 栅栏。当服务无事可做时 假设答案是 `null`，不是错误。

### `completions`

```ts
const request: CompletionsRequest = {
  documents,
  uri: "nx://tenant/form.nx",
  position: { line: 1, character: 23 },
};

const answer: CompletionList = {
  uri: "nx://tenant/form.nx",
  identity: "tenant/form.nx",
  version: 7,
  items: [{ label: "label", kind: "Property", detail: "label:string", documentation: "The caption." }],
};
```

`kind` 是其中之一 `Keyword`， `Type`， `Declaration`， `Component`， `Property`， `Member`. `documentation` 是 `///` 项目名称的文档，如markdown，当 它没有。

### `diagnostics`

```ts
const request: DiagnosticsRequest = { documents, uri: "nx://tenant/form.nx" };

const answer: DiagnosticReport = {
  documents: [
    { uri: "nx://tenant/ui.nx", identity: "tenant/ui.nx", version: 3, diagnostics: [] },
    {
      uri: "nx://tenant/form.nx",
      identity: "tenant/form.nx",
      version: 7,
      diagnostics: [
        {
          range: { start: { line: 1, character: 8 }, end: { line: 1, character: 13 }, startByte: 41, endByte: 46 },
          severity: "Error",
          code: "type-mismatch",
          message: "Expected string, found int",
          related: [],
        },
      ],
    },
  ],
  workspace: [],
};
```

报告涵盖集合中的每个文档，每个文档一个条目，因此可以设置多文档主机 所有的答案都是一个标记。 `workspace` 保存不属于任何文档的诊断信息， 例如导入既不在集合中也不在库中的模块。 `severity` 是其中之一 `Error`， `Warning`， `Info`， `Hint`.

### `documentSymbols`

```ts
const request: DocumentSymbolsRequest = { documents, uri: "nx://tenant/ui.nx" };

const answer: DocumentSymbol[] = [
  {
    name: "Button",
    kind: "Component",
    range: { start: { line: 0, character: 0 }, end: { line: 0, character: 47 }, startByte: 0, endByte: 47 },
    selectionRange: { start: { line: 0, character: 12 }, end: { line: 0, character: 18 }, startByte: 12, endByte: 18 },
  },
];
```

`kind` 是其中之一 `Function`， `Value`， `TypeAlias`， `Record`， `Action`， `Union`， `Component`， `Element`.

### `sourceTree` (不稳定)

**不稳定:** 答案的形状可能会在任何版本中改变，直到下一个版本提交它。它是 为NX查看器发布，并在此基础上构建结构更改视图。

```ts
const request: SourceTreeRequest = { documents, uri: "nx://tenant/ui.nx" };

const answer: SourceTree = {
  uri: "nx://tenant/ui.nx",
  identity: "tenant/ui.nx",
  version: 3,
  nodes: [
    { role: "declaration", range: range(0, 47), key: "Button", name: "Button", declaration: 0, flags: ["export"] },
    { role: "parameter", range: range(19, 31), parent: 0, key: "Button.label", name: "label" },
    { role: "typeReference", range: range(25, 31), parent: 1, key: "Button.label.type", value: "string" },
    { role: "element", range: range(37, 47), parent: 0, key: "Button.body", name: "button", type: "button" },
  ],
  declarations: [
    { module: "tenant/ui.nx", name: "Button", kind: "function", range: range(0, 47), properties: [{ name: "label", type: "string" }] },
  ],
};
```

（`range(start, end)` 代表 `EditorRange` 这些字节在第0行。)

文档的每个部分都是一个节点，包含未解析的注释和区域，以及每个节点 令牌只属于一个节点：其范围内包含它的最小节点。节点按顺序列出 以父节点的索引开始偏移，每个父节点在其子节点之前。一个节点有一个 `role` （`element`， `attribute`， `literal`， `case`， `operator`， `condition`， `comment`， `unparsed` 和 剩下的 `SourceRole`)，并载有书面内容 `name`， `value` 和 `textType`,它的 用NX拼写 `type` 当类型检查器给它一个时，输入 `declaration` 的指数 它所指的宣言。节点的类型和声明是hover在其中报告的内容。

`key` 节点在文档中的路径是否为 `roleQuestion.value.choices[2].label`: 顶层声明的名称，然后是属性、成员、武器和插槽，以及位置 为项目。对另一个声明或另一个属性的编辑不会改变它，所以有两个版本 的值可以通过键进行比较。键是用于比较是否相等的标识符，而不是指向它的路径 拆分：手臂以其图案或测试来命名(`is Mode.dark`， `when x > 1`)和 通过路径导入，这些路径可以保存点和空格。读取树的结构 `parent`.

`declarations` 列出每个声明一次，一个节点从本文档引用另一个文档 集合或库的：它的模块标识，名称和类型，它在本文档声明时的范围 它、它的文档注释、它的属性按声明顺序排列，首先是继承的属性(每个属性都有它的 类型，它的默认写入，以及它是可选的（内容的还是继承的），它的基，a 组件的状态、联合的情况、别名的类型、值的类型和值的范围。 不存在节点或声明的可选属性，而不是 `null` 当他们不适用时。

请求 `visualizers: {}` (或 `visualizers: { modules: [...] }`，命名进一步可视化 模块（宿主提供的）也解析可视化器声明：每个声明都有一个 带有 `visualizer`，带有标题、id和图标，可选 `preview: { renderer: string }`，它的属性按顺序显示， 对于每个属性或别名，a `format` 和一个 `editor`. `editor` 的编辑器提示 类型: `kind` （`field`， `dropdown` 或者 `segmented`)， `min`， `max`， `step`， `multiline`， `placeholder` 和 `choices`。每个选择的 `value` 类型为 `sourceEdit` `setValue` 值，所以a 客户端传递它，因为它是写选择：

```ts
const sizeProperty: SourcePropertyVisualizer = {
  name: "size",
  editor: {
    max: 96,
    choices: [
      { value: { kind: "number", text: "12" }, label: "sm" },
      { value: { kind: "number", text: "16" }, label: "base" },
    ],
  },
};
```

### `sourceEdit` (不稳定)

**不稳定:** 请求和答案的形状可能会在任何版本中改变，直到下一个版本 向他们承诺。它是为NX查看器的可视化编辑而发布的。

```ts
const request: SourceEditRequest = {
  documents,
  uri: "nx://tenant/ui.nx",
  key: "Button.label.type",
  edit: { kind: "setValue", value: { kind: "string", value: "Save" } },
};

const answer: SourceEditAnswer = { edits: [{ range: range(25, 31), newText: '"Save"' }] };
const refused: SourceEditAnswer = { edits: [], refused: "notEditable" };
```

请求将文档源树的节点命名为 `key` 还有一个变化： `setValue` 使用类型化值(`string`， `number` 作为输入, `boolean`，或者 `case` （通过名称）表示文字或 这是一个完整的值， `setText` 一行文字代表一组文字内容， `remove` 对于作为列表项的属性或元素， `addProperty` 与一个 属性的名称和元素的类型化值，该值将该属性写入元素的 最后一个，在它的布局中，或者 `move` 有一个位置 `to` 对于作为列表项的元素。一个 列表的Item是带括号序列中的元素或元素内容中的元素，而不是 `if` 分支 或者一个 `for` Body，在不包含文本的列表中； `to` 一旦移动，它所占据的位置是否被算作 列表的键数它的项。在将一项写到一行的列表中，一项随其移动或移动 整行，其上方的注释，以及将其与下一项分开的空行 （前一个是最后一个）；在一行的列表中，旁边有空格。其他布局有 拒绝 `notEditable`，和 `to` 在列表之外 `invalidValue`。答案是 `edits` 使 更改：每个范围都在发送时的文档中，没有两个重叠，因此主机将它们一起应用；该服务编写拼写（引号、转义、大括号） 属性的整行)。一个改变，它不能回答没有编辑和 `refused`： `unknownNode`， `notEditable` 或者 `invalidValue`。将文本保留原样的更改回答不编辑和不 拒绝。

### 保留的名字

`definition`， `references`， `rename`， `signatureHelp`， `inlayHints` 和 `semanticTokens` 是 保留。的实现 `unsupported-query` 错误,而 而不是传输失败或错误的回答，这样客户端就可以区分“还没有”和“坏了”。 `isLanguageQueryName` 和 `isReservedLanguageQueryName` 对名称进行分类。

## 服务接口

```ts
interface NxLanguageService {
  hover(request: HoverRequest, signal?: AbortSignal): Promise<Hover | null>;
  completions(request: CompletionsRequest, signal?: AbortSignal): Promise<CompletionList>;
  diagnostics(request: DiagnosticsRequest, signal?: AbortSignal): Promise<DiagnosticReport>;
  documentSymbols(request: DocumentSymbolsRequest, signal?: AbortSignal): Promise<DocumentSymbol[]>;
  sourceTree(request: SourceTreeRequest, signal?: AbortSignal): Promise<SourceTree>; // unstable
  sourceEdit(request: SourceEditRequest, signal?: AbortSignal): Promise<SourceEditAnswer>; // unstable
}
```

取消 `signal` 在应答到达之前，使用一个中止错误拒绝承诺 `isAbortError` 认错了，承诺就永远不会兑现。编辑器集成如下 针对该接口的进程内假例进行了测试，并对HTTP客户端进行了相同的行为 相同的答案。

## 错误

| 类 | 当 |
| --- | --- |
| `UnsupportedQueryError` | 服务识别了查询名称，但不支持查询名称。携带 `query`. |
| `LanguageServiceHttpError` | HTTP实现收到非成功状态。携带 `status`， `url`,一个 `bodyExcerpt`和身体的 `code` 当它是一个错误体时。 |
| `LanguageServiceTimeoutError` | 请求在客户端超时时间内没有得到响应；请求被中止。携带 `timeoutMs`. |

HTTP实现用JSON主体回答失败的查询

```ts
{ error: { code: LanguageServiceErrorCode; message: string; query?: string } }
```

哪里 `code` 是其中之一 `unsupported-query`， `unknown-query`， `method-not-allowed`， `invalid-request`， `payload-too-large`， `internal-error`. `isLanguageServiceErrorBody` 认识到 的形状。

源树调用者可以设置 `visualizers: { includeUnreferencedDeclarations: true }` 包括 加载的可视化器目标和继承的表示元数据，即使入口源没有 直接引用它们。默认情况下将声明表绑定到源树。 未知的预览渲染器id仍然是元数据；主机只激活它们支持的实现。

## 常见问题

### @nx-lang/language-protocol 是什么？

NX语言查询的独立于传输的请求和回答形状，以及每个客户端实现的NxLanguageService接口。

### 如何安装 @nx-lang/language-protocol？

在项目目录运行 npm install @nx-lang/language-protocol，或使用 pnpm add / yarn add / bun add。

### @nx-lang/language-protocol 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @nx-lang/language-protocol 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @nx-lang/language-protocol 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=22\.0\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @nx-lang/language-protocol 可以商用吗？

@nx-lang/language-protocol 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @nx-lang/language-protocol 还在维护吗？

最新版本 0\.10\.0 发布于 2026/11/02（1 天前）；至今共发布 10 个版本，其中过去 12 个月发布了 10 个；首次发布于 2026/09/15。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

