Skip to content

[codex] Upgrade ReScript Relay compiler to Relay 21#38

Draft
zth wants to merge 719 commits into
rescriptrelay-2.0from
codex/relay-21-redo-rescriptrelay-2.0
Draft

[codex] Upgrade ReScript Relay compiler to Relay 21#38
zth wants to merge 719 commits into
rescriptrelay-2.0from
codex/relay-21-redo-rescriptrelay-2.0

Conversation

@zth
Copy link
Copy Markdown
Owner

@zth zth commented Jun 2, 2026

What changed

  • Merged the upstream Relay 21 compiler/runtime source onto rescriptrelay-2.0.
  • Restored ReScript-specific extraction and compiler transforms on top of the Relay 21 pipeline.
  • Preserved nominal ReScript variants for enums/unions, including abstract selections that Relay 21 now models differently.
  • Added compatibility for Relay 21 artifact metadata references used by refetch operations and resolver modules.
  • Updated ReScript typegen/runtime conversion support for aliased fragments, nullable/null output, variables helpers, and generated input constructors.

Why

This branch explores bringing the ReScript Relay compiler up to the latest Relay major while keeping ReScript Relay's generated API shape intact.

Validation

Run from the parent checkout with this submodule commit:

  • cargo check -p common -p relay-typegen -p relay-compiler -p relay
  • cargo test -p extract-graphql
  • yarn build:test
  • yarn build
  • yarn test:ci

All passed locally.

generatedunixname2066905484085733 and others added 30 commits March 18, 2026 20:33
Reviewed By: dtolnay

Differential Revision: D97203424

fbshipit-source-id: 4fdacb77f86c951a90e51017356584eecad53413
…arallel

Reviewed By: ginfung

Differential Revision: D97312038

fbshipit-source-id: 5c5e3ae2c46cec473544fade02852097e1144f28
Reviewed By: Bellardia

Differential Revision: D97304082

fbshipit-source-id: 9566c971e03fa8c6b47450f878387f87249ddee6
…uteWithDefer-test

Summary:
Remove the `$FlowFixMe[missing-local-annot]` suppression at line 111 and fix the underlying type error by:

1. Adding a `Sink` type import from `RelayObservable`
2. Annotating the `sink` callback parameter as `Sink<GraphQLResponse>` and adding `<GraphQLResponse>` type parameter to `RelayObservable.create`
3. Adding `GraphQLResponse` type annotations to 9 payload variables that were exposed by the fix (these had `extensions` objects with invariant indexer type incompatibilities that were previously hidden by the suppression)

Reviewed By: jcperez-ch

Differential Revision: D96773458

fbshipit-source-id: 47fb7b1cfab63b532076d326251d05428f989015
Reviewed By: evanyeung

Differential Revision: D97396237

fbshipit-source-id: a810c53cc55e695df0677b3fdb108d9bb328f90e
Summary:
Automated changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action

Pull Request resolved: facebook#5213

Reviewed By: captbaritone

Differential Revision: D97403460

Pulled By: tyao1

fbshipit-source-id: 16195fb3f2a6a3c260bbe9d54d9e28bf8ad0f280
Reviewed By: marcoww6

Differential Revision: D97425290

fbshipit-source-id: 8118a167ab2c4e118214edbf6cdb5635d26c600f
… type changes

Differential Revision:
D97396237

Original commit changeset: a810c53cc55e

Original Phabricator Diff: D97396237

fbshipit-source-id: 66da642bbfc5d1c5edfca163bb9fd6f1e25c597c
Reviewed By: marcoww6, panagosg7

Differential Revision: D97534385

fbshipit-source-id: b76be68b58c891ce553f96b79c3fbf157085cf08
Reviewed By: diliop

Differential Revision: D97809993

fbshipit-source-id: 7ed7c09c13496688a6568067a1cae8db2dffc771
Reviewed By: evanyeung

Differential Revision: D96528622

fbshipit-source-id: 9732f3fc38c39a1d0026891ecff7dc8248453b67
Reviewed By: evanyeung

Differential Revision: D96528752

fbshipit-source-id: 3e730a1029709e9997072a6356e28455fecaa9d7
Summary:
Fix `catch` directive not working when `alias` directive is also present on inline fragments.

Previously, `_readAliasedInlineFragment` did not return its computed `fieldValue`, so when called from `_readCatchField` (which relies on the return value to determine error/success), the result was always `undefined`. This adds the missing return statement and return type annotation.

Also adds tests covering `catch(to: RESULT)` and `catch(to: NULL)` on aliased inline fragments with field errors, and `catch(to: RESULT)` on aliased inline fragments with no errors.

Reviewed By: captbaritone

Differential Revision: D97971003

fbshipit-source-id: 68a124f047ccf1b28e4a6d48e4bee8094a2176e8
…cache

Reviewed By: evanyeung

Differential Revision: D96632567

fbshipit-source-id: 7ec102d6f0f37379709362e68bbb85fc151dd14f
Reviewed By: tyao1

Differential Revision: D97331868

fbshipit-source-id: 50ff9134e401dbe1b88e94388733d65906651594
Reviewed By: marcoww6, gkz

Differential Revision: D97890708

fbshipit-source-id: 9547aca3b87c0cdfe5bf309cc964e3dd1712ca67
Reviewed By: tyao1

Differential Revision: D95419963

fbshipit-source-id: 911e175d3e03de0da5695fad8b690db8e2c56c68
Reviewed By: captbaritone

Differential Revision: D95419949

fbshipit-source-id: a72376ee8aaab8a180686ad72ff241d8219f6d49
Reviewed By: tyao1

Differential Revision: D97355483

fbshipit-source-id: abbff42fee562c285b56f13d8a0b1f6d8bb0dd63
Reviewed By: tyao1

Differential Revision: D97324210

fbshipit-source-id: f27e956f63c20848124a78339442359c9434128a
Reviewed By: tyao1

Differential Revision: D94594801

fbshipit-source-id: c0f7599e6c7af6ca442925239147e22282d0ab3f
…elay-schema-generation

Reviewed By: evanyeung

Differential Revision: D94138342

fbshipit-source-id: 38f196089c191e1e587d0b69b00c988c2d0f5007
Reviewed By: tyao1

Differential Revision: D97368959

fbshipit-source-id: 1a1dc064eb4c63de9ea6bb8f1bd65322db28478c
Reviewed By: evanyeung

Differential Revision: D97392769

fbshipit-source-id: 1072a34fa6a0eb58206cf99c3b906c9842538428
Reviewed By: jlwass

Differential Revision: D98158292

fbshipit-source-id: 0787183bd1487c7557ee50a22b47a06aa0b07af6
Reviewed By: dtolnay

Differential Revision: D98333053

fbshipit-source-id: 09f4bb6d43ea51b59d05cd8451bf798ea1a6769e
Reviewed By: thegreatercurve

Differential Revision: D98338132

fbshipit-source-id: 856dd5b96bfb7ab8398bdcbea3651435acbc891e
Differential Revision: D98240774

fbshipit-source-id: 640849e4d0449769ab7e851cd1b6d460f9612339
Summary:
Add a Rust binary that identifies all elements in a desired subset GraphQL
schema that are not properly included in a base schema.

Architecture:
- New `find_subset_violations` module in the `schema-set` crate that uses
  `SchemaSet::exclude_set()` to compute the remainder, then walks it to
  produce structured violation objects with Schema Coordinates format
- New lite executable at `graphql_build_infra/lite_executables/find_subset_violations/`
  following the exclude_schema/merge_sdl CLI patterns (structopt, read_file)
- CLI accepts `--base`, `--base-dir`, `--subset`, `--subset-dir`, `--output`

Violation types covered (all GraphQLSchemaBreakingChangeType values + extras):
TYPE_REMOVED, TYPE_CHANGED_KIND, FIELD_REMOVED, FIELD_CHANGED_KIND,
FIELD_ARG_ADDED, TYPE_REMOVED_FROM_UNION, VALUE_REMOVED_FROM_ENUM,
REQUIRED_INPUT_FIELD_ADDED, IMPLEMENTED_INTERFACE_REMOVED, REQUIRED_ARG_ADDED,
ARG_REMOVED, ARG_CHANGED_KIND, DIRECTIVE_REMOVED, DIRECTIVE_ARG_REMOVED,
REQUIRED_DIRECTIVE_ARG_ADDED, DIRECTIVE_LOCATION_REMOVED,
INCONSISTENT_TYPE_DIRECTIVE_USE

62 tests ported from PHP SandcastleValidateGraphQLAgainstAllowlistSchemaCommandTest
and Rust set_exclude tests covering nullability coercion, semantic non-null,
arg defaults, directive value equality, list coercion, and more.

One common use for SchemaSet is to quickly identify the schema that is *not* a subset, but should be, of a "base" schema. This is essentially a re-imagining of how Schema Breaking Changes should be detected, with a focus on the *set* rules that yield those violations.

Differential Revision: D98400289

fbshipit-source-id: cc9efdaa045f64dd91f70bdd5f6a035d8f766bd6
Summary:
Extract the core logic from locate_schema_coordinate into a reusable library
and use it to enrich subset violations with source file locations.

- Extract `locate_schema_coordinates()`, `FileLocation`, `build_text_sources()`,
  and span-resolution helpers into `locate-schema-coordinate-lib` library target
- Refactor existing locate_schema_coordinate binary to use the library
- Add `SchemaFileLocation` struct and `base_locations`/`subset_locations` fields
  to `SubsetViolation` (skip-serialized when empty)
- Update find_subset_violations binary to resolve locations post-hoc, only when
  violations exist (avoids building TextSource maps on clean schemas)

It's useful to be able to add in the source location of any violation. This sets us up to take all the source locations of the problematic extra-from-subset coordinates when explaining the violations.

Differential Revision: D98400723

fbshipit-source-id: ebe0dd2516ed348d8ee7cffc121aa613d1c18268
skrabe and others added 29 commits May 22, 2026 15:55
Summary:
Follow-up to facebook#4880.

The `fetchPolicy` option isn't mentioned in the fetchQuery docs, which is what caused the confusion in that issue. This adds it to the Arguments section with the two supported values (`network-only`, `store-or-network`) and an explicit note that `store-and-network` and `store-only` aren't supported, pointing people at `useLazyLoadQuery` instead.

The TypeScript types on DefinitelyTyped already match the Flow type (`FetchQueryFetchPolicy = "store-or-network" | "network-only"`), so nothing was needed on that side.

Pull Request resolved: facebook#5244

Reviewed By: tyao1

Differential Revision: D106046717

Pulled By: evanyeung

fbshipit-source-id: 23a3bfd3c9826a2a7f01e586eced52a4b1cec137
Summary:
GraphQL allows `deprecated` on enum values, but Relay wasn't warning when a deprecated enum value was used as a field or directive argument. This PR adds that validation alongside the existing deprecated field/argument checks.

```graphql
enum Status {
  ACTIVE
  LEGACY deprecated(reason: "Use ACTIVE instead.")
}

# Before: no warning
# After: The enum value `LEGACY` of type `Status` is deprecated. Deprecation reason: "Use ACTIVE instead."
fragment Foo on Query {
  user(status: LEGACY)
}

```

The warning message wording follows the existing patterns in the codebase. Open to suggestions if there's a better way to phrase it!

> [!NOTE]
> Variable values (`$status`) and deeply nested enum values inside constant objects/arrays are not yet covered. Left a TODO comment in the code.

Pull Request resolved: facebook#5277

Reviewed By: captbaritone

Differential Revision: D106030387

Pulled By: evanyeung

fbshipit-source-id: 16617aa66259c233780624767dfe457f93c9c9d3
Reviewed By: SamChou19815

Differential Revision: D106028091

fbshipit-source-id: 81c042b50f19eeb5d56c6128372a86e356ff8762
Reviewed By: dtolnay

Differential Revision: D106248758

fbshipit-source-id: 0b1e6369f55ee6b49912be4aa47d53ceddf717d1
Reviewed By: marcoww6

Differential Revision: D106303680

fbshipit-source-id: 593f5cff104e2abfa87f3a5b8adda92cb96848bd
Reviewed By: tyao1

Differential Revision: D106132555

fbshipit-source-id: a1c340cfc5d15eeded3fb35fc50f0f26c2740bf8
Summary:
Automated changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action

Pull Request resolved: facebook#5297

Reviewed By: evanyeung

Differential Revision: D106386358

Pulled By: captbaritone

fbshipit-source-id: 8f10f94d0b1a627f39ef65983410a5fdbe373f56
Reviewed By: evanyeung

Differential Revision: D106422899

fbshipit-source-id: 44d24f39099b79837a706519899b97b5ea2ae474
Reviewed By: jcperez-ch

Differential Revision: D106428675

fbshipit-source-id: c9c96183b3b377141e8eb60e7aa703d3341e0ab2
Reviewed By: jcperez-ch

Differential Revision: D106438092

fbshipit-source-id: 5b549202b5d121c88478104e6380586a2bf688de
Differential Revision: D105339725

fbshipit-source-id: d5e6f5da64d54f55b769de2ad92f9e7812c8f336
Differential Revision: D105339620

fbshipit-source-id: 0b2596f90af82bc646ab58733a40331feab0793c
Reviewed By: SamChou19815

Differential Revision: D106410842

fbshipit-source-id: 58982a572f941fa32aeeaa50857b1e3b8968665e
… to concrete types

Reviewed By: yczhu

Differential Revision: D103700821

fbshipit-source-id: 11e3ed8d23c438e83994d8fade7b8736c9b57ddc
Reviewed By: gkz

Differential Revision: D106557702

fbshipit-source-id: 9228e5f8f855a362f72249117770d33d97bd4191
Reviewed By: yczhu

Differential Revision: D106566723

fbshipit-source-id: 8da4cb1b08a7c01a84df00c2e7bb277a166f2b3a
Reviewed By: marcoww6

Differential Revision: D106733740

fbshipit-source-id: baf8a8ab52ca413aa3acfbd3e139675cc2f9d044
…refetch queries

Reviewed By: yczhu

Differential Revision: D104083544

fbshipit-source-id: 5e8b6ea542f29433f5975f7e6293e60fa1a7641d
…nterfaces

Reviewed By: yczhu

Differential Revision: D104106879

fbshipit-source-id: d22322d261bc21bbc6a683b69e192819372801c5
…calVariables

Reviewed By: yczhu

Differential Revision: D103424054

fbshipit-source-id: 06138709db7674126c20b2e71c21beebd766e7ad
Reviewed By: gkz

Differential Revision: D106807767

fbshipit-source-id: b60203de457a90e1c31fc8e49bd62f7e7c8fe2a6
…wup synthetic responses

Summary:
The exec-time NormalizationEngine's `_normalizeFollowup` constructs a synthetic followup response (`{data: followup.data}`) without any `extensions`. `OperationExecutor._normalizeFollowupPayload` (lines 864-870) stamps `extensions: {is_final: true}` on the synthetic response when it's processing a final outer payload — without this, nested defer/3D placeholders inside a module-loaded fragment never see is_final and never finalize on a non-streaming server.

Thread `parentIsFinal` through `_processFollowups` → `_processModuleImport` → `_normalizeFollowup`, and propagate it onto the synthetic response's `extensions.is_final`. The recursive `_processFollowups` call inside `_normalizeFollowup` also passes through `payload.isFinal` from the followup's own normalization so nested module followups inherit correctly.

Resolves another of the TODOs left in NormalizationEngine.js when the engine was extracted from OperationExecutor.

Propagate is_final from parent response to module followup synthetic responses in NormalizationEngine, matching OperationExecutor behavior for nested defer/3D finalization.

Reviewed By: yczhu

Differential Revision: D103424899

fbshipit-source-id: 79b6aec28605f3ce5ee654dbb4cbdadbfd79560d
…rejection

Summary:
The exec-time NormalizationEngine's `_processModuleImport` was wrapping the async `operationLoader.load(...)` chain with `.catch((_error) => emptyResult)`, silently swallowing load failures (e.g., the module fragment failing to load over the network). Callers had no way to observe the error — the resulting Promise just resolved to an empty payload, and the failed module would appear as missing data with no diagnostic.

Drop the `.catch` so load failures propagate naturally via Promise rejection through `pendingModules`. The caller (e.g., the S2C executor that drains `pendingModules`) is expected to surface the rejection — `OperationExecutor.js:1121` does this by forwarding `error: sink.error` on the load observable, and the engine's contract now matches.

Resolves the last of the TODOs left in NormalizationEngine.js when the engine was extracted from OperationExecutor for the exec-time-resolver path.

Surface async module load failures via Promise rejection instead of silently swallowing them in NormalizationEngine.

Reviewed By: yczhu

Differential Revision: D103443165

fbshipit-source-id: 8d5f6db4c54adc410ae1f204197414f6530d9fd9
…e replay

Summary:
Two TODOs in `NormalizationEngine.js` (`_processDefer` and `_processStream`) noted that the engine concatenates parent-replayed handle field payloads into the same payload as the deferred/streamed data, while `OperationExecutor._processDeferResponse` / `_processStreamResponse` emit them as a separate empty-source payload via a second `commitPayload`.

After analysis the two-payload split is structural, not semantic: within one `commitPayload` the source merges (and the stream `storeUpdater` runs) before `fieldPayloads` execute, so the parent handlers still see the updated parent record either way. Same end state. The only externally observable difference is the number of subscriber-notification rounds — and the single-commit version is strictly better there (one notification instead of two for the same logical update).

Replace the TODOs with a comment that records this analysis, so future readers understand the deliberate divergence from `OperationExecutor` rather than treating it as an oversight.

Document that NormalizationEngine's single-payload approach for defer/stream parent handle replay is intentionally different from OperationExecutor's two-payload split, with equivalent semantics.

Reviewed By: yczhu

Differential Revision: D103464607

fbshipit-source-id: e9f27ca2245369654a0e077226d92ec83073ba63
Reviewed By: marcoww6

Differential Revision: D106904599

fbshipit-source-id: 79b5cfadae59e09213e9ef69747c664bcba3724f
Reviewed By: SamChou19815

Differential Revision: D106964682

fbshipit-source-id: 4c87a48ef0a4f626ec603e065975525ccdcb2444
Reviewed By: panagosg7

Differential Revision: D107100695

fbshipit-source-id: 57e9deebb7a1bea8ce76164975f60adf1ff0a17f
Summary:
- The "Compiler output check" CI job has been failing on all recent commits since `045f228` ("Implement feature flag to gate rollout of flow modern syntax")
- That commit added a `flow_modern_syntax` feature flag and enabled it in the Rust test fixtures, but did not add it to `scripts/config.tests.json`
- When CI regenerates Flow artifacts using `config.tests.json`, it produces classic Flow syntax (`+` for readonly, `{||}` for exact objects) while the committed files use modern syntax (`readonly`, `{}`)
- This adds `"flow_modern_syntax": {"kind": "enabled"}` to the feature flags in `scripts/config.tests.json` to match

Pull Request resolved: facebook#5307

Test Plan: - CI should pass on this PR — the "Compiler output check" job should no longer show diffs in generated Flow files

Reviewed By: evanyeung

Differential Revision: D107158647

Pulled By: captbaritone

fbshipit-source-id: 57f2131be86c6206d76bdb446aa48022a70558db
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.