Skip to content

Support type extensions in DefinitionDocuments - #157

Open
swalkinshaw wants to merge 2 commits into
mainfrom
support-schema-type-extensions
Open

swalkinshaw wants to merge 2 commits into
mainfrom
support-schema-type-extensions

Conversation

@swalkinshaw

@swalkinshaw swalkinshaw commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Bluejay rejects extend type Foo { … } and type Foo with a parse error, but both are valid GraphQL (Type System Extensions, ObjectTypeDefinition). Bluejay now parses them, so that tools which read schema source see each extension as it is written.

  • TypeSystemExtension covers the seven extension kinds of the September 2025 spec. DefinitionDocument::type_system_extensions() returns them in source order. extend directive is in the draft spec only, and stays a parse error.
  • Bluejay does not apply extensions to the types they extend. SchemaDefinition::try_from returns one error for each extension. The spec allows this for tools that only build schemas, with "a descriptive error". Bluejay does not build a schema that differs from its document.
  • Type definitions without a body (type Foo, union Foo, …) now parse. try_from applies the "must define one or more fields / values / member types" rules from Type Validation.
  • Each definition and extension implements HasSpan, from its description (or keyword) to its end. Together with the public type_definitions(), schema_definitions(), name_token() and description_token() accessors, a tool can lower or edit schema source without scanning the text. Name and StringValue are exported, so callers can name these types.

Breaking: no public API is removed. A document with a bodyless type now fails in try_from instead of in parse.

Cost: no measurable change in the existing parse benchmarks. Each type and directive definition is 8 bytes larger. Fields, arguments and enum values do not change size. An extension parses 2–7% slower than a definition with the same body, because of the extra extend token.

Out of scope: applying extensions to the types they extend, and the version bump.

Benchmarks (criterion medians, two runs of each side)
Benchmark main main again this PR this PR again
parse GitHub schema 2.64 ms 2.62 ms 2.52 ms 2.39 ms
parse admin schema (3.4 MB) 8.54 ms 8.18 ms 8.42 ms 8.03 ms
build admin schema definition 1.41 ms 1.38 ms 1.33 ms 1.33 ms
parse kitchen sink executable 5.06 µs 4.32 µs 4.42 µs 4.32 µs
parse large executable 44.2 µs 43.8 µs 44.8 µs 43.4 µs
parse 2,000 object type definitions 2.00 ms 2.04 ms
parse 2,000 object type extensions 2.05 ms 2.18 ms

The two main runs differ by up to 10%, so the differences between main and this PR are noise.

@swalkinshaw swalkinshaw changed the title Parse type system extensions and type definitions without a body Support type extensions in DefinitionDocuments Oct 23, 2026
@swalkinshaw
swalkinshaw force-pushed the support-schema-type-extensions branch from f2112c3 to 2bc3d64 Compare October 23, 2026 20:05
Parse the seven type system extensions of the September 2025 spec
(`extend schema`, `scalar`, `type`, `interface`, `union`, `enum` and
`input`). The parser keeps each extension as its own node, in source
order, so that tools can read extensions as they are written.

- An extension must add at least one part, cannot have a description
  and takes only const directives. Directive extensions are draft-only
  and are rejected.
- Bluejay does not apply extensions to the types they extend.
  `SchemaDefinition::try_from` gives one descriptive error for each
  extension, as the spec allows for tools that only build schemas. It
  does not build a schema that differs from the document.
- Type definitions can omit their body (`type Foo`, `union Foo`, ...),
  as the grammar allows. `try_from` applies the spec rule that each type
  must define one or more members.
- Every definition and extension has a span from its description (or
  keyword) to its end. With the public `type_definitions()`,
  `schema_definitions()` and `type_system_extensions()` accessors and
  the `name_token()` and `description_token()` accessors, a tool can
  lower or edit schema source without scanning the text. `Name` and
  `StringValue` are exported so that callers can name these types.

Documents without extensions parse as before. The spans add 8 bytes to
each type and directive definition and nothing to fields, arguments or
enum values.
Add benchmarks that parse the 3.4 MB admin schema, build a schema
definition from it, and parse the same type bodies as definitions and as
extensions.
@swalkinshaw
swalkinshaw force-pushed the support-schema-type-extensions branch from 2bc3d64 to ad5d7d1 Compare October 26, 2026 17:36
@swalkinshaw
swalkinshaw marked this pull request as ready for review October 26, 2026 18:01

@szluzero szluzero left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know rust so just used an agent to review and found no blockers, and letting bluejay parse type extensions and bodyless types makes sense to me

@swalkinshaw
swalkinshaw requested a review from adampetro October 28, 2026 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants