Skip to content

[graphql] Add @typespec/graphql emitter#11000

Open
FionaBronwen wants to merge 176 commits into
microsoft:mainfrom
pinterest:feature/graphql
Open

[graphql] Add @typespec/graphql emitter#11000
FionaBronwen wants to merge 176 commits into
microsoft:mainfrom
pinterest:feature/graphql

Conversation

@FionaBronwen

@FionaBronwen FionaBronwen commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR introduces @typespec/graphql, a new emitter that generates GraphQL SDL (Schema Definition Language) from TypeSpec definitions.

Features

  • Schema generation: Emit complete GraphQL schemas from TypeSpec models and operations
  • Operation types: Support for @query, @mutation, and @subscription decorators
  • Interface composition: Use @graphqlInterface and @compose for GraphQL interface inheritance
    patterns
  • Visibility filtering: Automatic input/output type generation based on @visibility decorators
  • Custom scalars: @specifiedBy decorator for custom scalar URL specifications
  • Schema customization: @schema decorator for multi-schema scenarios

Architecture

The emitter uses a two-phase approach:

  1. Mutation phase: Transforms TypeSpec types into GraphQL-compatible structures using the mutator framework, handling visibility filtering, naming conventions, and type deduplication
  2. Render phase: Uses @pinterest/alloy-graphql components to emit the final SDL output

Example

import "@typespec/graphql";

using TypeSpec.GraphQL;

@query
op getUser(id: string): User;

@mutation
op createUser(user: User): User;

model User {
  name: string;
  email: string;
}

Generates:

  type Query {
    getUser(id: String!): User!
  }

  type Mutation {
    createUser(user: UserInput!): User!
  }

  type User {
    name: String!
    email: String!
  }

  input UserInput {
    name: String!
    email: String!
  }

Test plan

  • Unit tests for all decorators and components
  • E2E tests covering schema generation scenarios
  • Mutation engine tests for type transformation logic

Notes

timotheeguerin and others added 30 commits November 5, 2024 07:59
Add CODEOWNERS for graphql pull request reviews

---------

Co-authored-by: swatikumar <swatikumar@pinterest.com>
…#5033)

### Description

This PR sets up the flow to use the GraphQL emitter by providing an
interface for the various options that the GraphQL emitter will use
eventually. It also sets up test-hosts to work with these options. The
actual schema emitter doesn't really do anything other than emit "Hello
World" as it did previously, but the options get pass through as
confirmed by the test case.

Going forward, we can change the code in schema-emitter.ts to setup it
up for GraphQL using `navigateProgram`. We need to add diagnostics in
the emitter lib definition, but that can be done in a separate PR. The
next PR will have the outer layer of the GraphQL emitter setup to deal
with multiple schemas similar to multiple services in the OAI emitter.

### Testing
Run the tests and see that they pass.

---------

Co-authored-by: swatikumar <swatikumar@pinterest.com>
These are just some basic updates to the metadata in the
`@typespec/graphql` `package.json`. This brings it in line with other
packages like `@typespec/openapi3`.
The `@compose` decorator is used to indicate that a GraphQL `type` or `interface` implements one or more interfaces.

As [defined by the GraphQL spec](https://spec.graphql.org/October2021/#sec-Interfaces), a `type` or `interface` implementing an interface must contain all the properties defined by that interface, and so we require that the TypeSpec model implement the interface's properties as well. There is no restriction on how this is accomplished (via spread, via composition, via manual copying of properties, etc).

To reduce confusion, we do not allow a TypeSpec model to define both a `type` and an `interface`. In order to define an `interface`, the model must be decorated with the `@Interface` decorator.
The `@operationFields` decorator is used to specify one or more operations that should be placed onto a GraphQL type as fields with arguments.

This is our solution for representing [GraphQL field arguments](https://spec.graphql.org/October2021/#sec-Field-Arguments) in TypeSpec, as TypeSpec does not support arguments on model properties.
Implement `@Interface` and `@compose` decorators
Implement `@operationFields` decorator
Import useStateMap from compiler utils (after merge)
A few updates to make the project buildable again:
- `implements` became a reserved keyword in 9a4463b, so we switch to `interfaces`
- `expectIdenticalTypes` was renamed to `expectTypeEquals` in 32ca22f
- `validateDecoratorTarget` was removed in 32ca22f, as the TypeSpec type system handles this
- `SyntaxKind` was moved to `compiler/ast` in 32ca22f
- we also bump version of `devDependencies` to match those in other projects
Add main.tsp and remove strict from tspconfig.yml
- Add @pinterest/alloy-graphql and graphql to pnpm-workspace catalog
- Convert all dependencies in graphql package to use catalog: protocol
- Add oxc: false to vitest config to fix JSX transform compatibility with vitest 4
@timotheeguerin

Copy link
Copy Markdown
Member

/azp run typespec - pr tools

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Introduces a new first-party TypeSpec emitter package, @typespec/graphql, that generates GraphQL SDL from TypeSpec programs, including a mutation-engine phase (naming, visibility filtering, input/output splitting) and an Alloy-based render phase. The PR also wires the emitter into the website documentation and the playground.

Changes:

  • Add packages/graphql implementing the GraphQL emitter, decorators, validation, mutation engine, and Alloy SDL rendering.
  • Add extensive unit/integration tests for decorators, mutation engine behavior, and component-level SDL rendering.
  • Add docs + playground integration, and register new workspace dependencies (@pinterest/alloy-graphql, graphql).

Reviewed changes

Copilot reviewed 113 out of 115 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
website/src/content/docs/docs/emitters/graphql/reference/index.mdx New GraphQL emitter reference landing page.
website/src/content/docs/docs/emitters/graphql/reference/emitter.md Documents CLI/config usage and emitter options.
website/src/content/docs/docs/emitters/graphql/reference/data-types.md Documents exported GraphQL-related TypeSpec types.
website/src/content/docs/docs/emitters/graphql/guide.md New end-to-end usage guide and mapping examples.
website/src/content/current-sidebar.ts Adds GraphQL docs entry to website sidebar.
pnpm-workspace.yaml Adds catalog deps for alloy-graphql and graphql; minReleaseAge exclusion.
pnpm-lock.yaml Locks new dependencies and adds packages/graphql importer.
packages/playground-website/tsconfig.json Adds project reference to packages/graphql.
packages/playground-website/src/config.ts Enables @typespec/graphql in playground libraries list.
packages/playground-website/samples/graphql.tsp Adds a GraphQL sample TypeSpec program.
packages/playground-website/samples/build.js Registers GraphQL sample in playground sample builder.
packages/playground-website/package.json Adds @typespec/graphql dependency for playground.
packages/graphql/vitest.config.ts Vitest config for JSX/alloy plugin + dependency dedupe.
packages/graphql/tsconfig.json TypeScript project config for the new package.
packages/graphql/test/test-host.ts Test harness for compiling/emitting GraphQL and parsing SDL.
packages/graphql/test/schema.test.ts Unit tests for @schema decorator behavior.
packages/graphql/test/operation-kind.test.ts Unit tests for @query/@mutation/@subscription operation kind.
packages/graphql/test/operation-fields.test.ts Tests for @operationFields behavior and conflict diagnostics.
packages/graphql/test/mutation-engine/type-graph.test.ts Tests for TypeGraph construction and navigation compatibility.
packages/graphql/test/mutation-engine/scalars.test.ts Scalar mapping/sanitization + @specifiedBy tests.
packages/graphql/test/mutation-engine/print-type.test.ts Tests GraphQL type string printing (nullability/list handling).
packages/graphql/test/mutation-engine/operations.test.ts Operation naming + return-type nullability propagation tests.
packages/graphql/test/mutation-engine/naming-integration.test.ts Integration tests for naming pipelines across kinds.
packages/graphql/test/mutation-engine/enums.test.ts Enum + enum member mutation behavior tests.
packages/graphql/test/mutation-engine/context.test.ts Tests for input/output context caching and propagation.
packages/graphql/test/main.tsp Sample library schema TypeSpec used for testing/manual runs.
packages/graphql/test/lib/type-utils.test.ts Unit tests for type/name utility helpers.
packages/graphql/test/lib/template-composition.test.ts Unit tests for template-instance naming composition.
packages/graphql/test/lib/naming.test.ts Unit tests for naming pipeline functions.
packages/graphql/test/interface.test.ts Tests for interface markers and @compose validation.
packages/graphql/test/emitter.test.ts E2E-ish tests for full SDL emission for common scenarios.
packages/graphql/test/e2e-manual/output/.gitignore Ignores manual E2E output artifacts.
packages/graphql/test/crash-repro.test.ts Regression tests for previously-crashing patterns (records, generics, unions).
packages/graphql/test/components/union-type.test.tsx Component-level SDL rendering tests for unions.
packages/graphql/test/components/test-utils.tsx Shared component test renderer to SDL string.
packages/graphql/test/components/scalar-type.test.tsx Component-level SDL rendering tests for scalars.
packages/graphql/test/components/object-type.test.tsx Component-level SDL rendering tests for object types.
packages/graphql/test/components/interface-type.test.tsx Component-level SDL rendering tests for interface types.
packages/graphql/test/components/input-type.test.tsx Component-level SDL rendering tests for input objects / @OneOf.
packages/graphql/test/components/enum-type.test.tsx Component-level SDL rendering tests for enums.
packages/graphql/src/validate.ts Adds GraphQL-specific validation hook for schemas/names/empties.
packages/graphql/src/type-usage.ts Tracks type usage (input/output/query/mutation) + reachability.
packages/graphql/src/tsp-index.ts Exposes decorators and validate hook for TypeSpec runtime.
packages/graphql/src/mutation-engine/type-graph.ts Builds a self-contained namespace of mutated types for rendering.
packages/graphql/src/mutation-engine/schema-mutator.ts Walks schema namespace, mutates types, builds TypeGraph, checks collisions.
packages/graphql/src/mutation-engine/print-type.ts Converts mutated types into GraphQL type strings (nullability/list rules).
packages/graphql/src/mutation-engine/options.ts Mutation options carrying GraphQL context, visibility, cache keys.
packages/graphql/src/mutation-engine/mutations/scalar.ts Scalar mutation: mapping, sanitization, builtin collision warnings, @specifiedBy.
packages/graphql/src/mutation-engine/mutations/operation.ts Operation mutation: naming + visibility + nullability propagation.
packages/graphql/src/mutation-engine/mutations/model.ts Model mutation: naming, visibility filtering, record→scalar replacement, decorator arg remutation.
packages/graphql/src/mutation-engine/mutations/model-property.ts Property mutation: naming + nullability/nullable-elements tagging.
packages/graphql/src/mutation-engine/mutations/index.ts Barrel exports for mutation classes.
packages/graphql/src/mutation-engine/mutations/enum.ts Enum mutation with member-edge handling + naming pipeline.
packages/graphql/src/mutation-engine/mutations/enum-member.ts Enum member naming pipeline mutation.
packages/graphql/src/mutation-engine/mutations/union.ts Union mutation: flattening/dedup, scalar wrapper models, input @oneOf conversion.
packages/graphql/src/mutation-engine/index.ts Mutation-engine public entrypoints.
packages/graphql/src/mutation-engine/engine.ts MutationEngine wiring + convenience mutation APIs.
packages/graphql/src/lib/visibility.ts Defines visibility filters for query/mutation/output contexts.
packages/graphql/src/lib/utils.ts Structural equality helpers for conflict detection (ops/models/props).
packages/graphql/src/lib/template-composition.ts Template-instance name composition logic.
packages/graphql/src/lib/specified-by.ts @specifiedBy decorator state + decorator implementation.
packages/graphql/src/lib/schema.ts @schema decorator state + schema list helpers.
packages/graphql/src/lib/operation-kind.ts @query/@mutation/@subscription decorator state + duplicate detection.
packages/graphql/src/lib/operation-fields.ts @operationFields implementation + conflict/duplicate diagnostics.
packages/graphql/src/lib/one-of.ts @oneOf marker decorator implementation/helpers.
packages/graphql/src/lib/nullable.ts @nullable/@nullableElements marker decorators + helpers.
packages/graphql/src/lib/naming.ts GraphQL naming pipelines (sanitize + casing + suffixes).
packages/graphql/src/lib/interface.ts @graphqlInterface and @compose state + validation.
packages/graphql/src/lib/input-type.ts Internal marker for identifying input types during render.
packages/graphql/src/lib/graphql-type-name.ts Maps std scalars to GraphQL builtins and resolves type names.
packages/graphql/src/lib.ts Library definition: diagnostics + emitter option schema.
packages/graphql/src/index.ts Package exports (emitter, lib, decorators, mutation engine).
packages/graphql/src/emitter.tsx Core emitter: schema selection, mutation, SDL render, emit files.
packages/graphql/src/context/index.ts Context barrel exports for renderer.
packages/graphql/src/context/graphql-schema-context.tsx Renderer context for passing TypeGraph into Alloy components.
packages/graphql/src/components/types/union-type.tsx Alloy component for GraphQL unions.
packages/graphql/src/components/types/scalar-type.tsx Alloy component for GraphQL scalars (+ specifiedBy).
packages/graphql/src/components/types/object-type.tsx Alloy component for object types (+ interfaces, operation fields).
packages/graphql/src/components/types/interface-type.tsx Alloy component for interface types.
packages/graphql/src/components/types/input-type.tsx Alloy component for input object types (+ @OneOf).
packages/graphql/src/components/types/index.ts Barrel exports for type components.
packages/graphql/src/components/types/enum-type.tsx Alloy component for enums (+ descriptions/deprecation).
packages/graphql/src/components/schema.tsx Top-level schema composition component (types + root ops).
packages/graphql/src/components/fields/operation-field.tsx Alloy component for operation-as-field rendering incl. args/nullability/lists.
packages/graphql/src/components/fields/index.ts Barrel exports for field components.
packages/graphql/src/components/fields/field.tsx Alloy component for model property fields (input/output).
packages/graphql/package.json New package manifest + scripts + deps/peers.
packages/graphql/lib/specified-by.tsp TypeSpec extern decorator declaration for @specifiedBy.
packages/graphql/lib/schema.tsp TypeSpec extern decorator declaration for @schema + SchemaOptions model.
packages/graphql/lib/scalars.tsp Declares TypeSpec.GraphQL.ID scalar.
packages/graphql/lib/operation-kind.tsp TypeSpec extern decorator declarations for query/mutation/subscription.
packages/graphql/lib/operation-fields.tsp TypeSpec extern decorator declaration for @operationFields.
packages/graphql/lib/one-of.tsp TypeSpec extern decorator declaration for @oneOf.
packages/graphql/lib/nullable.tsp TypeSpec extern decorator declarations for nullability markers.
packages/graphql/lib/main.tsp TypeSpec library entrypoint importing JS + decorator declarations.
packages/graphql/lib/interface.tsp TypeSpec extern decorator declarations for @graphqlInterface and @compose.
packages/graphql/CHANGELOG.md New changelog for initial release.
packages/graphql/api-extractor.json Enables API extractor config for the new package.
cspell.yaml Adds new words and ignores .claude/**.
.gitignore Ignores local Claude settings file.
.github/CODEOWNERS Adds CODEOWNERS entry for packages/graphql.
.chronus/changes/feature-graphql-2026-6-9-12-47-10.md Adds Chronus changelog entry for the new emitter.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

Comment thread packages/graphql/test/components/test-utils.tsx Outdated
Comment thread packages/graphql/src/validate.ts
Comment thread packages/graphql/src/mutation-engine/type-graph.ts
@azure-sdk-automation

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

- Remove unnecessary cast and outdated comment in test-utils.tsx (graphql types now match)
- Add operation name validation for reserved __ prefix in validate.ts
- Add transitive registration of union variant types in type-graph.ts
- Add test to verify variant types are registered when only union is passed
@timotheeguerin

Copy link
Copy Markdown
Member

test @typespec-graphql-reviewers

Comment thread packages/graphql/package.json
Consolidate scalar mappings into a single unified structure that covers
all 25 TypeSpec intrinsic scalars. When std scalars like int64 are used
directly without defining a custom scalar, they now map to the closest
GraphQL built-in type (e.g., int64 → String) instead of crashing.

- Unified SCALAR_MAPPINGS table with graphqlType for all scalars
- Filter std/library scalars from emission in schema-mutator
- Remove renaming of std scalars in scalar mutation
- Add comprehensive unit tests for all scalar mappings

Fixes crash: "Unknown GraphQL type Long" when using int64 directly.
When encountering types without a GraphQL equivalent (like numeric
literals `42` or string literals `"foo"`), emit a warning diagnostic
and fall back to String instead of crashing.

Adds `unsupported-type` diagnostic that reports which type kind has
no GraphQL equivalent.
@timotheeguerin

Copy link
Copy Markdown
Member

test1 @typespec-graphql-reviewers/core
test @typespec-graphql-reviewers

FionaBronwen and others added 8 commits July 13, 2026 12:19
The Azure/typespec-azure CI uses its own pnpm catalog which doesn't
include @pinterest/alloy-graphql. Using an explicit version bypasses
the catalog lookup and allows the downstream CI to pass.
- Fix CodeQL security alert: use iterative stripping for angle brackets
  in type names to handle nested cases
- Revert to catalog: for @pinterest/alloy-graphql (repo requires it)
Mark @nullable, @nullableElements, and @OneOf as internal since they
are applied automatically by the mutation engine and should not be
used directly by users (doing so crashes the emitter).
The tspd doc tool requires tsconfig.build.json to exist. Adding it
and regenerating the reference documentation to satisfy CI validation.
…ors (#105)

Convert the internal `@nullable`, `@nullableElements`, `@oneOf`, and
`@inputType` marker decorators from hand-written implementations (and the
`.decorators`-push hack) to compiler `internal auto dec` declarations.

- Adopt tspd `gen-extern-signature` generated readers/setters (isNullable,
  setNullable, isOneOf, setOneOf, isInputType, setInputType, ...) instead of
  hand-written state accessors; delete src/lib/{nullable,one-of,input-type}.ts.
- Type all decorator implementations with the generated `*Decorator`
  signatures; `$decorators` uses `satisfies TypeSpecGraphQLDecorators`.
- Wire up gen-extern-signature into the build; add generated-defs/ and
  tspconfig.yaml (auto-decorators experimental feature opt-in).
- Remove now-unused GraphQLKeys state entries for the migrated decorators.
Comment thread .chronus/changes/feature-graphql-2026-6-9-12-47-10.md Outdated
Comment thread .github/CODEOWNERS Outdated
FionaBronwen and others added 3 commits July 16, 2026 11:27
Co-authored-by: Timothee Guerin <timothee.guerin@outlook.com>
External contributors cannot be added as codeowners, so falling back
to the default catch-all for this package.
@timotheeguerin
timotheeguerin enabled auto-merge July 16, 2026 17:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:graphql Issues for @typespec/graphql emitter emitter-framework Issues for the emitter framework eng meta:website TypeSpec.io updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants