# @apollo/core-schema 中文文档

规范地址：https://npmcn.com/package/%40apollo/core-schema/

版本：0\.3\.0
npm 元数据更新时间：2026-01-22T17:29:56.240Z
中文译文更新时间：2026-11-06T11:03:08.714Z
软件包许可：MIT

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

原始 npm 页面：https://www.npmjs.com/package/%40apollo/core-schema
原文对照：https://npmcn.com/package/%40apollo/core-schema/?lang=original
项目主页：https://github.com/apollographql/core-schema-js#readme
源码仓库：https://github.com/apollographql/core-schema-js

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

- 包体积（解压后）：702 kB，132 个文件
- 模块格式：CommonJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=12\.13\.0
- 运行依赖：1 个
- peer 依赖：graphql ^15 \|\| ^16
- 首次发布：2021-08-13T14:57:10.001Z
- 最新版本发布：2022-04-08T00:43:09.293Z
- 近 30 天下载量：43293（2026-10-07 至 2026-11-05，npm 官方下载统计）
- 已发布版本数：7（近 12 个月 0 个）

## 中文简介

阿波罗核心Schema处理库

## 安装

```sh
npm install @apollo/core-schema
```

也可以使用：`pnpm add @apollo/core-schema`、`yarn add @apollo/core-schema`、`bun add @apollo/core-schema`

## README

# @ apollo/ core-schema

_处理核心图案的字典库_

通过 npm 安装 :

```sh
npm install @apollo/core-schema
```

从源创建:

```sh
npm install
npm test
```

# 快点

## 分析一个方案

```typescript
import { Schema, gql } from '@apollo/core-schema'

const schema = Schema.basic(gql`${"example.graphql"}
  @link(url: "https://specs.apollo.dev/federation/v1.0")
  @link(url: "https://specs.apollo.dev/inaccessible/v0.1")

  type User @inaccessible {
    id: ID!
  }
`);

expect([...schema]).toMatchInlineSnapshot(`
  Array [
    <>[GraphQL request] 👉@link(url: "https://specs.apollo.dev/federation/v1.0"),
    <#User>[GraphQL request] 👉type User @inaccessible {,
  ]
`);

expect([...schema.scope]).toMatchInlineSnapshot()

expect([...schema.refs]).toMatchInlineSnapshot(`
  Array [
    <>[example.graphql] 👉@link(url: "https://specs.apollo.dev/federation/v1.0"),
    <https://specs.apollo.dev/link/v1.0#@>[example.graphql] 👉@link(url: "https://specs.apollo.dev/federation/v1.0"),
    <https://specs.apollo.dev/link/v1.0#@>[example.graphql] 👉@link(url: "https://specs.apollo.dev/inaccessible/v0.1"),
    <#User>[example.graphql] 👉type User @inaccessible {,
    <https://specs.apollo.dev/inaccessible/v0.1#@>[example.graphql] type User 👉@inaccessible {,
    <#ID>[example.graphql] id: 👉ID!,
  ]
`);
```

## 按其全球图表位置查找指令

```typescript
import {Schema, Defs, GRef, directives} from '@apollo/core-schema'

const schema = Schema.basic(gql `
  extend schema
    @link(url: "https://spec.example.io/hidden/v1.0", as: "private")

  type Product
  type Admin @private
  type User
`)

const HIDDEN = GRef.rootDirective('https://spec.example.io/hidden/v1.0')
function *hiddenDefs(defs: Defs) {
  for (const def of defs) {
    for (const directive of directives(def)) {
      if (directive.gref === HIDDEN) {
        yield def
        break
      }
    }
  }
}

expect([...hiddenDefs(schema)].map(def => def.name))
  .toEqual(['Admin'])
```

## 在核心图中查找名称

得到一个 `Schema` 从文档中 `Schema.from` 接下来 通过查询文档名称 `schema.scope`数字 :

```typescript
import {Schema, GRef, ref} from '@apollo/core-schema'

const doc = Schema.from(gql `
  extend schema
    @link(url: "https://specs.apollo.dev/link/v1.0")
    @link(url: "https://example.com/someSpec/v1.0")
    @link(url: "https://spec.example.io/another/v1.0", as: "renamed")
`)
expect(doc.scope.lookup('@link')).toBe(
  GRef.rootDirective('https://specs.apollo.dev/link/v1.0')
)
expect(doc.scope.lookup('renamed__Type'))).toBe(
  GRef.named('Type', "https://spec.example.io/another/v1.0")
)
```

## 构建含有隐含范围的文档

用一套内建文件来解释文档往往有用 链接已经存在于范围.

`Scope.from` 第二次辩论,所谓的 `frame`改为: 启用此功能:

```typescript
const SUBGRAPH_BUILTINS = Schema.from(gql `
  extend schema
    @link(url: "https://specs.apollo.dev/link/v1.0")
    @link(url: "https://specs.apollo.dev/federation/v1.0",
          import: "@key @requires @provides @external")
`)

function subgraph(document: DocumentNode) {
  return Schema.from(document, SUBGRAPH_BUILTINS)
}

subgraph(gql `
  # @key in the next line will be linked to:
  #
  #   https://specs.apollo.dev/federation/v1.0#@key
  type User @key(field: "id") {
    id: ID!
  }
`)

subgraph(gql `
  # this will shadow the built-in link to @key:
  extend schema @link(url: "https://specs.apollo.dev/federation/v2.0",
    import: "@key")

  # @key in the next line will be linked to:
  #
  #   https://specs.apollo.dev/federation/v2.0#@key
  type User @key(field: "id") {
    id: ID!
  }`)
```

## 在文档的链接上显示

```typescript
function linksFed2(doc: Schema) {
  for (const link of doc.scope) {
    if (link.gref.graph.satisfies(LinkUrl.from("https://specs.apollo.dev/federation/v2.0"))) {
      // child links federation 2.0
      return true
    }  
  }
  return false
}

expect(
  linksFed2(Schema.basicFrom(gql `
    extend schema @link(url: "https://specs.apollo.dev/federation/v2.0")
  `))
).toBe(true)

expect(
  linksFed2(Schema.basicFrom(gql `
    extend schema @link(url: "https://specs.apollo.dev/federation/v1.9")
  `))
).toBe(false)

expect(
  linksFed2(Schema.basicFrom(gql ``))
).toBe(false)
```

## 文档中的名称标准化

您也许想要在文档中扫描指令, 而不必担心用户是否重新命名了它们 .

页:1 `schema.standardize(...urls)` 方法可以帮助:

```typescript
const subgraph = Schema.basic(gql `
  @link(url: "https://specs.apollo.dev/federation/v2.0",
        # what weird naming choices!
        import: """
          @key      (as @fkey)
          @requires (as @frequires)
          @provides (as @fprovides)
          @tag      (as @ftag)
        """)

  type User @fkey(fields: "id") {
    id: ID! @ftag(name: "hi") @tag(name: "my tag")
  }

  # note: this is our *own* @tag directive, which looks
  # just like but means something different than
  # federation's @tag:
  directive @tag(name: string) on FIELD_DEFINITION
`);

expect(
  raw(
    // standardize takes LinkUrls and ensures that all references to that schema
    // are prefixed with its standard name
    subgraph.standardize("https://specs.apollo.dev/federation/v2.0").print()
  )
).toMatchInlineSnapshot(`
  extend schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/id/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.0")

  type User @federation__key(fields: "id") {
    id: ID! @federation__tag(name: "hi") @tag(name: "my tag")
  }

  directive @tag(name: string) on FIELD_DEFINITION
`);
```

# 动机

此库是用来帮助您阅读和操作核心计划 .

## 背景情况

[核心计划](https://specs.apollo.dev/core/v0.2) 可相互参考元素.

例如,这个计划参考federation 2.0并使用 `@key` 其指令:

```graphql
extend schema
  @link(url: "https://specs.apollo.dev/federation/v2.0")

type User @federation__key(fields: "id") {
  id: ID!
}
```

在这里,我们链接 `federation` 以它的url 显示 spec。 此链接名称 `federation` 转到url `https://specs.apollo.dev/federation/v2.0`,指示核心意识处理器识别像 `federation__FieldSet` 财务报告和审定财务报表 `@federation__key` 定义由 [https://specs.apollo.dev/federation/v2.0. 互联网档案馆的存檔,存档日期2013-12-22](https://specs.apollo.dev/federation/v2.0)。 。 。 .

`@link` 推断名称 `federation` (以及版本) `2.0`从url. 也可以明确设置名称:

```graphql
extend schema
  @link(url: "https://specs.apollo.dev/federation/v2.0", as: fedv2)

type User @fedv2__key(fields: "id") {
  id: ID!
}
```

这些名字会让人讨厌 所以 `@link` 还提供 `import` 参数,将非前缀名称链接到远程定义:

```graphql
extend schema
  @link(url: "https://specs.apollo.dev/federation/v2.0",
        import: "@key")

type User @key(fields: "id") {
  id: ID!
}
```

让我们解决冲突 比如说我有这个计划:

```graphql
type User @key(column: "id") {
  id: ID!
}

directive @key(column: string) on OBJECT
```

现在说我想把这个计划 变成联邦的子图 联邦已经定义 `@key` 指令,它会和我自己的冲突 `@key` 指令,这是无关的.

与 `@link`我可以给联邦的 `@key` 命令任何我想要的名字, 避免冲突 :

```graphql
extend schema
  @link(url: "https://specs.apollo.dev/federation/v2.0",
        import: "@fedKey: @key")

type User @fedKey(fields: "id") @key(column: "id") {
  id: ID!
}

directive @key(column: string) on OBJECT
```

请注意,这也有利于难民署 `@link` 指令本身:

```graphql
extend schema
  @coreLink(url: "https://specs.apollo.dev/link/v1.0", as: coreLink)
  @coreLink(url: "https://specs.apollo.dev/federation/v2.0",
        import: "@fedKey: @key")
```

## 汇编

上面的例子不是有效的 GraphQL 计划,因为它们并不包含它们所命名的所有元素的定义。 具体地说,它们没有包含联邦指令的定义,也没有包含联邦指令的定义 `@link` 自己来 如果您把它们输入到一个需要有效的 GraphQL 方案的工具中, 这个工具将会被打破 .

看来我们应该能解决这个问题. `@link` 非常像一个 `import` 语句 - 它的存在似乎意味着某种汇编过程,可以某种方式查阅相关定义并插入到文件中.

这个库提供了这样的机制。 其间,它提供了一个框架,用以与 _全球图_ 定义——从中构建计划,从一个文件复制到另一个文件,等等.

### 编译器的问题

再来一次

```graphql
extend schema
  @link(url: "https://specs.apollo.dev/federation/v2.0",
        import: "@fedKey: @key")

type User @fedKey(fields: "id") {
  id: ID!
}
```

编译器必须查看此方案,并为文档中引用但未定义的任何元素插入定义。 说我们有一个地图集 里面有一个计划:

```graphql
extend schema
  # @id is @link's sister, specifying this schema's
  # position within the global graph
  @id(url: "https://specs.apollo.dev/federation/v2.0")

directive @key(fields: FieldSet!) on OBJECT
scalar FieldSet
```

编辑器需要复制定义 `@key` 输入文档。 然后它也需要复制定义 `FieldSet`,从 `@key` 参考文献 `FieldSet`. 当它将这些定义插入到文档中时,它需要更改它们的名称,以适应文档的名称空间。 核心计划可以转接 `@link` 其他核心计划,因此可能涉及增加 `@link`给其他计划.

这个图书馆揭露了一个编辑模型.

# 编辑模式

基本办法是:

1.  读取一个计划,并通过审查其范围来构建其范围 `@link` 指令。 。 。 范围管理命名空间——它能够查看文档中的任何定义或参考,并将其与全局图表位置(url,基本上是)联系起来。 范围与某一要素在文档中是否有定义完全无关——它的唯一工作是将名称与urls联系起来.
2.  当复制文档中的节点时,用其全局图位置来注释这些节点及其后人。 我们称之为这个过程 _隔离_ 或者说 _非正常化_ (因为该数据库携带的元数据) `@link` 指令被非正常化到整个树上.
3.  将定义按需要移动而不担心命名空间
4.  在发放完成的文件之前,收集所有参考文献,生成适当的 `@link` 信头,以及 _重新正常化_ 它的所有节点, 酌情设置它们的名字.

节点的去正态化和再正态化的过程大多是透明的.

## 在实践中

您可以构造一个 `Schema` 从类似 GraphQL 的文档中:

```typescript
import {Schema, gql} from '@apollo/core-schema'

const schema = Schema.from(gql `
  extend schema
    @id(url: "https://my/schema")
    @link(url: "https://specs.apollo.dev/link/v1.0")
    @link(url: "https://specs.apollo.dev/federation", import: "@key")
    @link(url: "https://myorg.internal/future")

  type User @key(fields: "id") @future
`)
```

`Schema`可执行性,产生文件中的每一项定义:

```typescript
const defs = [...schema]
```

`Schema`总是产生离子树。 分离子树中的定义和参考文献 `.gref` 属性,在全局图中查找节点:

```typescript
import {GRef} from '@apollo/core-schema'

expect(defs[defs.length - 1].gref).toBe(
  GRef.named('User', 'https://my/schema')
)
```

(一个"gref"是"g"raph"的"ref".

您可以使用任意机制在文档中插入已解开的节点:

```typescript
// helper to create a detached @tag directive
function $tag(name: string) {
  return {
    kind: Kind.DIRECTIVE,
    name: "tag",
    arguments: [{
      name: { kind: Kind.NAME, value: "name" },
      value: { kind: Kind.STRING, value: name }
    }],
    gref: GRef.rootDirective("https://specs.apollo.dev/tag/v0.1")
  }
])

// replace @future with @tag(name: "future")
const newSchema = schema.mapDoc(schema =>
  visit(schema.document, {
    Directive(node) {
      if (!hasRef(node)) return
      if (node.gref === GRef.rootDirective("https://myorg.internal/future")) {
        // replace @future with @tag(name: "future")
        return $tag("future")
      }
    }
  }))
```

终于可以打电话了 `compile` 重新规范一切并确保适当的 `@link` 有页眉:

```typescript
return newSchema.compile()
```

`schema.compile()` 使用可选参数, a `atlas` 委员会将从中设法填补文件中已提及但未列入的任何定义. `atlas` 它可以是任何可执行的 超越离散的定义。 例如,它可能是另一个 `Schema`数字 :

```typescript
const tagSchema = Schema.basic(gql`
  @id(url: "https://specs.apollo.dev/tag/v0.1")
  directive @tag(name: string) repeatable on OBJECT
`)
return newSchema.compile(tagSchema)
```

您可以使用 `Atlas` 将多个计划合并成地图集.

## 设计原则

### AST 重点

这个图书馆以AST为中心与计划合作.

这是很好的,因为AST可以代表许多无法代表的情况 `GraphQLSchema`例如,没有包含所有定义(本库的原则动机!)的图案不能在其中表示 `GraphQL*` 类结构。 因此,我们只是不尝试: 这个图书馆从来没有打电话 `buildSchema`我们也不接触注重执行的班级 `GraphQLSchema`。 。 。 .

此外,与AST合作也使我们有能力 _小数_ 修改文档而不彻底改变结构。 默认情况下,此处执行的操作试图对文档进行最小的修改,并尽可能保留其结构. alas, 图克解析器的局限性意味着我们目前无法保存注释 .

最后,AST节点被解析器赋予了源位并保留该位置,甚至跨越复杂的变换. 这样做有助于错误报告,也将使生成源图相对容易,尽管我们目前没有这样做.

### 纯正而不可改变

基本上整个库都是在不可移动的数据结构上作为纯函数执行的,从ASTNodes(我们视其为不可移动)开始. 昂贵的操作被纪念.

### 懒惰

纯/不可改变/记忆设计的一个后果是,我们一般不计算任何东西,直到我们需要它。 例如, `Schema.from` 甚至不扫描文档的 `@link`和构造一个范围,直到 `schema.scope` 已实际使用。 同样地,节点在被访问之前不会被非正常化.

### 分类值类型

少数类型,尤其是 `GRef`, (中文(简体) ), `LinkUrl`,以及 `Version`\- 已经是 _扫描_也就是说,它们只能通过记忆性函数来创建,这确保了两个等同的例子永远是同一个例子:

```typescript
expect(LinkUrl.from('https://specs/example/?extraneous&stuff&ignored'))
  .toBe(LinkUrl.from('https://specs/example'))
```

它们是有效的价值类型,它们可以(和)被使用,例如作为键在 `Map`编号.

## 常见问题

### @apollo/core-schema 是什么？

阿波罗核心Schema处理库

### 如何安装 @apollo/core-schema？

在项目目录运行 npm install @apollo/core-schema，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：graphql（^15 \|\| ^16）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @apollo/core-schema 支持 TypeScript 吗？

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

### @apollo/core-schema 支持 ESM 还是 CommonJS？

以 CommonJS 形式发布，可以直接 require\(\)；在 ES Module 项目中也可以用 import 引入（Node\.js 会把 module\.exports 作为默认导出）。

### @apollo/core-schema 需要什么版本的 Node\.js？

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

### @apollo/core-schema 可以商用吗？

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

### @apollo/core-schema 的下载量有多少？

根据 npm 官方下载统计，@apollo/core-schema 在 2026/10/07 – 2026/11/05 这 30 天内被下载 43,293 次，日均约 1,443 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @apollo/core-schema 还在维护吗？

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

